Merge "Disallow prepare()-ing over an always on VPN app" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 9183771..fc9c319 100644
--- a/Android.mk
+++ b/Android.mk
@@ -42,7 +42,7 @@
 
 # EventLogTags files.
 LOCAL_SRC_FILES += \
-       core/java/android/auditing/SecurityLogTags.logtags \
+       core/java/android/app/admin/SecurityLogTags.logtags \
        core/java/android/content/EventLogTags.logtags \
        core/java/android/speech/tts/EventLogTags.logtags \
        core/java/android/webkit/EventLogTags.logtags \
@@ -117,6 +117,7 @@
 	core/java/android/bluetooth/IBluetoothManager.aidl \
 	core/java/android/bluetooth/IBluetoothManagerCallback.aidl \
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
+	core/java/android/bluetooth/IBluetoothPbapClient.aidl \
 	core/java/android/bluetooth/IBluetoothMap.aidl \
 	core/java/android/bluetooth/IBluetoothSap.aidl \
 	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
@@ -149,15 +150,16 @@
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
 	core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
+	core/java/android/content/pm/IShortcutService.aidl \
 	core/java/android/database/IContentObserver.aidl \
-	core/java/android/hardware/ICameraService.aidl \
-	core/java/android/hardware/ICameraServiceListener.aidl \
-	core/java/android/hardware/ICameraServiceProxy.aidl \
-	core/java/android/hardware/ICamera.aidl \
-	core/java/android/hardware/ICameraClient.aidl \
+	../av/camera/aidl/android/hardware/ICameraService.aidl \
+	../av/camera/aidl/android/hardware/ICameraServiceListener.aidl \
+	../av/camera/aidl/android/hardware/ICameraServiceProxy.aidl \
+	../av/camera/aidl/android/hardware/ICamera.aidl \
+	../av/camera/aidl/android/hardware/ICameraClient.aidl \
+	../av/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl \
+	../av/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
 	core/java/android/hardware/IConsumerIrService.aidl \
-	core/java/android/hardware/camera2/ICameraDeviceUser.aidl \
-	core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
 	core/java/android/hardware/ISerialManager.aidl \
 	core/java/android/hardware/display/IDisplayManager.aidl \
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
@@ -194,6 +196,7 @@
 	core/java/android/hardware/usb/IUsbManager.aidl \
 	core/java/android/net/ICaptivePortal.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
+	core/java/android/net/IConnectivityMetricsLogger.aidl \
 	core/java/android/net/IEthernetManager.aidl \
 	core/java/android/net/IEthernetServiceListener.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -222,7 +225,10 @@
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/IPermissionController.aidl \
 	core/java/android/os/IProcessInfoService.aidl \
+	core/java/android/os/IProgressListener.aidl \
 	core/java/android/os/IPowerManager.aidl \
+	core/java/android/os/IRecoverySystem.aidl \
+	core/java/android/os/IRecoverySystemProgressListener.aidl \
 	core/java/android/os/IRemoteCallback.aidl \
 	core/java/android/os/ISchedulingPolicyService.aidl \
 	core/java/android/os/IUpdateLock.aidl \
@@ -237,15 +243,20 @@
 	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
 	core/java/android/service/notification/IConditionProvider.aidl \
+	core/java/android/service/vr/IVrListener.aidl \
 	core/java/android/print/ILayoutResultCallback.aidl \
 	core/java/android/print/IPrinterDiscoveryObserver.aidl \
 	core/java/android/print/IPrintDocumentAdapter.aidl \
 	core/java/android/print/IPrintDocumentAdapterObserver.aidl \
 	core/java/android/print/IPrintJobStateChangeListener.aidl \
+	core/java/android/print/IPrintServicesChangeListener.aidl \
+	core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl \
 	core/java/android/print/IPrintManager.aidl \
 	core/java/android/print/IPrintSpooler.aidl \
 	core/java/android/print/IPrintSpoolerCallbacks.aidl \
 	core/java/android/print/IPrintSpoolerClient.aidl \
+	core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl \
+	core/java/android/printservice/recommendation/IRecommendationService.aidl \
 	core/java/android/print/IWriteResultCallback.aidl \
 	core/java/android/printservice/IPrintService.aidl \
 	core/java/android/printservice/IPrintServiceClient.aidl \
@@ -291,7 +302,6 @@
 	core/java/com/android/internal/app/IAssistScreenshotReceiver.aidl \
 	core/java/com/android/internal/app/IBatteryStats.aidl \
 	core/java/com/android/internal/app/IEphemeralResolver.aidl \
-	core/java/com/android/internal/app/IProcessStats.aidl \
 	core/java/com/android/internal/app/ISoundTriggerService.aidl \
 	core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
 	core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl \
@@ -299,6 +309,7 @@
 	core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
 	core/java/com/android/internal/app/IVoiceInteractorRequest.aidl \
 	core/java/com/android/internal/app/IMediaContainerService.aidl \
+	core/java/com/android/internal/app/procstats/IProcessStats.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
@@ -307,6 +318,7 @@
 	core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardService.aidl \
 	core/java/com/android/internal/policy/IKeyguardStateCallback.aidl \
+	core/java/com/android/internal/policy/IShortcutService.aidl \
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
 	core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
@@ -405,12 +417,20 @@
 	telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl \
 	telephony/java/com/android/ims/internal/IImsEcbm.aidl \
 	telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
+        telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
+        telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
 	telephony/java/com/android/ims/internal/IImsService.aidl \
 	telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl \
 	telephony/java/com/android/ims/internal/IImsUt.aidl \
 	telephony/java/com/android/ims/internal/IImsUtListener.aidl \
 	telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl \
 	telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl \
+        telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl \
+        telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl \
+        telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl \
+        telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl \
+        telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl \
+        telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl \
 	telephony/java/com/android/ims/ImsConfigListener.aidl \
 	telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl \
 	telephony/java/com/android/internal/telephony/IMms.aidl \
@@ -450,6 +470,10 @@
       $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
       frameworks/native/aidl/binder
 
+LOCAL_AIDL_INCLUDES += \
+	frameworks/av/camera/aidl \
+	frameworks/native/aidl/gui
+
 LOCAL_INTERMEDIATE_SOURCES := \
 			$(framework_res_source_path)/android/R.java \
 			$(framework_res_source_path)/android/Manifest.java \
@@ -543,6 +567,7 @@
 	frameworks/base/core/java/android/print/PrintJobInfo.aidl \
 	frameworks/base/core/java/android/print/PrinterInfo.aidl \
 	frameworks/base/core/java/android/print/PrintJobId.aidl \
+	frameworks/base/core/java/android/printservice/recommendation/RecommendationInfo.aidl \
 	frameworks/base/core/java/android/hardware/usb/UsbDevice.aidl \
 	frameworks/base/core/java/android/hardware/usb/UsbInterface.aidl \
 	frameworks/base/core/java/android/hardware/usb/UsbEndpoint.aidl \
@@ -572,7 +597,7 @@
 	frameworks/base/core/java/android/view/Display.aidl \
 	frameworks/base/core/java/android/view/InputDevice.aidl \
 	frameworks/base/core/java/android/view/InputEvent.aidl \
-	frameworks/base/core/java/android/view/Surface.aidl \
+	frameworks/native/aidl/gui/android/view/Surface.aidl \
 	frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \
 	frameworks/base/core/java/android/view/inputmethod/InputMethodSubtype.aidl \
 	frameworks/base/core/java/android/view/inputmethod/CursorAnchorInfo.aidl \
@@ -641,6 +666,7 @@
 	frameworks/base/core/java/android/content/pm/ProviderInfo.aidl \
 	frameworks/base/core/java/android/content/pm/PackageStats.aidl \
 	frameworks/base/core/java/android/content/pm/PermissionGroupInfo.aidl \
+	frameworks/base/core/java/android/content/pm/ShortcutInfo.aidl \
 	frameworks/base/core/java/android/content/pm/LabeledIntent.aidl \
 	frameworks/base/core/java/android/content/ComponentName.aidl \
 	frameworks/base/core/java/android/content/SyncStats.aidl \
@@ -814,6 +840,7 @@
     -since $(SRC_API_DIR)/21.txt 21 \
     -since $(SRC_API_DIR)/22.txt 22 \
     -since $(SRC_API_DIR)/23.txt 23 \
+    -since ./frameworks/base/api/current.txt N \
 		-werror -hide 111 -hide 113 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
@@ -857,9 +884,11 @@
 framework_docs_SDK_REL_ID:=1
 
 framework_docs_LOCAL_DROIDDOC_OPTIONS += \
+		-hdf sdk.codename N \
+		-hdf sdk.preview.version 2 \
 		-hdf sdk.version $(framework_docs_SDK_VERSION) \
 		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-		-hdf sdk.preview 0
+		-hdf sdk.preview 1
 
 # ====  the api stubs and current.xml ===========================
 include $(CLEAR_VARS)
@@ -1014,9 +1043,9 @@
 		-offlinemode \
 		-title "Android SDK" \
 		-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
-		-todo $(OUT_DOCS)/$(LOCAL_MODULE)-docs-todo.html \
 		-sdkvalues $(OUT_DOCS) \
-		-hdf android.whichdoc offline
+		-hdf android.whichdoc offline \
+		-referenceonly
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
@@ -1024,13 +1053,14 @@
 
 static_doc_index_redirect := $(out_dir)/index.html
 $(static_doc_index_redirect): \
-	$(LOCAL_PATH)/docs/docs-documentation-redirect.html | $(ACP)
+	$(LOCAL_PATH)/docs/docs-preview-index.html | $(ACP)
 	$(hide) mkdir -p $(dir $@)
 	$(hide) $(ACP) $< $@
 
 $(full_target): $(static_doc_index_redirect)
 $(full_target): $(framework_built)
 
+
 # ==== docs for the web (on the androiddevdocs app engine server) =======================
 include $(CLEAR_VARS)
 
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 2fe5cbe..cee8fdb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -240,6 +240,7 @@
 $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IRemoteControlDisplay.*)
 $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit1_intermediates/src/com/android/test/split/feature/R.java)
 $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit2_intermediates/src/com/android/test/split/feature/R.java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index abc9e9a..dfdff24 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38,6 +38,7 @@
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
     field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+    field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -70,6 +71,7 @@
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -101,7 +103,6 @@
     field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
     field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
     field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
-    field public static final java.lang.String READ_WRITE_CONTACT_METADATA = "android.permission.READ_WRITE_CONTACT_METADATA";
     field public static final java.lang.String REBOOT = "android.permission.REBOOT";
     field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
     field public static final java.lang.String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
@@ -115,6 +116,7 @@
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
+    field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
     field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
     field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
@@ -338,6 +340,7 @@
     field public static final int calendarViewStyle = 16843613; // 0x101035d
     field public static final int canControlMagnification = 16844040; // 0x1010508
     field public static final int canPerformGestures = 16844046; // 0x101050e
+    field public static final int canRecord = 16844061; // 0x101051d
     field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
     field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
     field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -414,15 +417,18 @@
     field public static final int contentAuthority = 16843408; // 0x1010290
     field public static final int contentDescription = 16843379; // 0x1010273
     field public static final int contentInsetEnd = 16843860; // 0x1010454
+    field public static final int contentInsetEndWithActions = 16844070; // 0x1010526
     field public static final int contentInsetLeft = 16843861; // 0x1010455
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
+    field public static final int contentInsetStartWithNavigation = 16844069; // 0x1010525
     field public static final int contextClickable = 16844007; // 0x10104e7
     field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
     field public static final int controlY2 = 16843775; // 0x10103ff
+    field public static final int countDown = 16844060; // 0x101051c
     field public static final int country = 16843962; // 0x10104ba
     field public static final int cropToPadding = 16843043; // 0x1010123
     field public static final int cursorVisible = 16843090; // 0x1010152
@@ -440,6 +446,7 @@
     field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
     field public static final int debuggable = 16842767; // 0x101000f
     field public static final int defaultHeight = 16844021; // 0x10104f5
+    field public static final int defaultToDeviceProtectedStorage = 16844037; // 0x1010505
     field public static final int defaultValue = 16843245; // 0x10101ed
     field public static final int defaultWidth = 16844020; // 0x10104f4
     field public static final int delay = 16843212; // 0x10101cc
@@ -459,6 +466,7 @@
     field public static final int dialogTheme = 16843528; // 0x1010308
     field public static final int dialogTitle = 16843250; // 0x10101f2
     field public static final int digits = 16843110; // 0x1010166
+    field public static final int directBootAware = 16844038; // 0x1010506
     field public static final int direction = 16843217; // 0x10101d1
     field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
     field public static final int directionPriority = 16843218; // 0x10101d2
@@ -507,7 +515,6 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
-    field public static final int encryptionAware = 16844038; // 0x1010506
     field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
     field public static final int endX = 16844051; // 0x1010513
@@ -556,6 +563,7 @@
     field public static final int fillBefore = 16843196; // 0x10101bc
     field public static final int fillColor = 16843780; // 0x1010404
     field public static final int fillEnabled = 16843343; // 0x101024f
+    field public static final int fillType = 16844064; // 0x1010520
     field public static final int fillViewport = 16843130; // 0x101017a
     field public static final int filter = 16843035; // 0x101011b
     field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -571,7 +579,7 @@
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
-    field public static final int forceDeviceEncrypted = 16844037; // 0x1010505
+    field public static final int forceHasOverlappingRendering = 16844068; // 0x1010524
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
     field public static final int foregroundTint = 16843885; // 0x101046d
@@ -855,7 +863,8 @@
     field public static final int minResizeWidth = 16843669; // 0x1010395
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
-    field public static final int minimalSize = 16844022; // 0x10104f6
+    field public static final int minimalHeight = 16844067; // 0x1010523
+    field public static final int minimalWidth = 16844022; // 0x10104f6
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
@@ -876,6 +885,7 @@
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
+    field public static final int nfcAntennaPositionDrawable = 16844063; // 0x101051f
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -939,6 +949,8 @@
     field public static final int popupBackground = 16843126; // 0x1010176
     field public static final int popupCharacters = 16843332; // 0x1010244
     field public static final int popupElevation = 16843916; // 0x101048c
+    field public static final int popupEnterTransition = 16844065; // 0x1010521
+    field public static final int popupExitTransition = 16844066; // 0x1010522
     field public static final int popupKeyboard = 16843331; // 0x1010243
     field public static final int popupLayout = 16843323; // 0x101023b
     field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -1358,6 +1370,7 @@
     field public static final int trimPathEnd = 16843785; // 0x1010409
     field public static final int trimPathOffset = 16843786; // 0x101040a
     field public static final int trimPathStart = 16843784; // 0x1010408
+    field public static final int tunerCount = 16844062; // 0x101051e
     field public static final int type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
@@ -2472,6 +2485,7 @@
     field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
     field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
     field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+    field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
     field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
     field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
     field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2506,6 +2520,7 @@
     field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
     field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
     field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+    field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
     field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
     field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
     field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -2663,8 +2678,11 @@
     field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
     field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
     field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+    field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+    field public static final int SHOW_MODE_AUTO = 0; // 0x0
+    field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
   }
 
   public static abstract class AccessibilityService.GestureResultCallback {
@@ -2745,14 +2763,10 @@
   }
 
   public final class GestureDescription {
-    method public static android.accessibilityservice.GestureDescription createClick(int, int);
-    method public static android.accessibilityservice.GestureDescription createLongClick(int, int);
-    method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long);
-    method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long);
+    method public static long getMaxGestureDuration();
+    method public static int getMaxStrokeCount();
     method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int);
     method public int getStrokeCount();
-    field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L
-    field public static final int MAX_STROKE_COUNT = 10; // 0xa
   }
 
   public static class GestureDescription.Builder {
@@ -3414,7 +3428,7 @@
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public void enterPictureInPicture();
+    method public void enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3434,7 +3448,7 @@
     method public android.view.View getCurrentFocus();
     method public android.app.FragmentManager getFragmentManager();
     method public android.content.Intent getIntent();
-    method public deprecated java.lang.Object getLastNonConfigurationInstance();
+    method public java.lang.Object getLastNonConfigurationInstance();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.LoaderManager getLoaderManager();
     method public java.lang.String getLocalClassName();
@@ -3454,15 +3468,16 @@
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
     method public boolean hasWindowFocus();
-    method public boolean inMultiWindow();
-    method public boolean inPictureInPicture();
     method public void invalidateOptionsMenu();
     method public boolean isChangingConfigurations();
     method public final boolean isChild();
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isInMultiWindowMode();
+    method public boolean isInPictureInPictureMode();
     method public boolean isLocalVoiceInteractionSupported();
+    method public boolean isOverlayWithDecorCaptionEnabled();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3509,7 +3524,7 @@
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onNavigateUp();
     method public boolean onNavigateUpFromChild(android.app.Activity);
     method protected void onNewIntent(android.content.Intent);
@@ -3517,7 +3532,7 @@
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method protected void onPostCreate(android.os.Bundle);
     method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
@@ -3528,14 +3543,13 @@
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
     method public void onProvideAssistContent(android.app.assist.AssistContent);
     method public void onProvideAssistData(android.os.Bundle);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public android.net.Uri onProvideReferrer();
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method protected void onRestart();
     method protected void onRestoreInstanceState(android.os.Bundle);
     method public void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method protected void onResume();
-    method public deprecated java.lang.Object onRetainNonConfigurationInstance();
+    method public java.lang.Object onRetainNonConfigurationInstance();
     method protected void onSaveInstanceState(android.os.Bundle);
     method public void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method public boolean onSearchRequested(android.view.SearchEvent);
@@ -3556,7 +3570,6 @@
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
-    method public void overlayWithDecorCaption(boolean);
     method public void overridePendingTransition(int, int);
     method public void postponeEnterTransition();
     method public void recreate();
@@ -3585,6 +3598,7 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
+    method public void setOverlayWithDecorCaptionEnabled(boolean);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3599,7 +3613,7 @@
     method public deprecated void setTitleColor(int);
     method public void setVisible(boolean);
     method public final void setVolumeControlStream(int);
-    method public void setVrMode(boolean);
+    method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean shouldShowRequestPermissionRationale(java.lang.String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
@@ -4123,13 +4137,12 @@
     field public java.lang.String serviceDetails;
   }
 
-  public class AutomaticZenRule implements android.os.Parcelable {
+  public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
     method public long getCreationTime();
-    method public java.lang.String getId();
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
@@ -4211,7 +4224,6 @@
     method public void onPanelClosed(int, android.view.Menu);
     method public boolean onPrepareOptionsMenu(android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public void onRestoreInstanceState(android.os.Bundle);
     method public android.os.Bundle onSaveInstanceState();
     method public boolean onSearchRequested(android.view.SearchEvent);
@@ -4429,11 +4441,11 @@
     method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
     method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method public void onPrepareOptionsMenu(android.view.Menu);
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method public void onResume();
@@ -4514,11 +4526,11 @@
     method public void dispatchDestroy();
     method public void dispatchDestroyView();
     method public void dispatchLowMemory();
-    method public void dispatchMultiWindowChanged(boolean);
+    method public void dispatchMultiWindowModeChanged(boolean);
     method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
     method public void dispatchOptionsMenuClosed(android.view.Menu);
     method public void dispatchPause();
-    method public void dispatchPictureInPictureChanged(boolean);
+    method public void dispatchPictureInPictureModeChanged(boolean);
     method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
     method public void dispatchResume();
     method public void dispatchStart();
@@ -4905,6 +4917,7 @@
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
     field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
     field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
@@ -5046,16 +5059,17 @@
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
+    method public android.widget.RemoteViews createBigContentView();
+    method public android.widget.RemoteViews createContentView();
+    method public android.widget.RemoteViews createHeadsUpContentView();
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
-    method public android.widget.RemoteViews makeBigContentView();
-    method public android.widget.RemoteViews makeContentView();
-    method public android.widget.RemoteViews makeHeadsUpContentView();
     method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setChronometerCountsDown(boolean);
     method public android.app.Notification.Builder setColor(int);
     method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
@@ -5224,14 +5238,14 @@
   }
 
   public class NotificationManager {
-    method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
-    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
+    method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5241,7 +5255,7 @@
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
-    method public boolean updateAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5253,7 +5267,7 @@
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
@@ -5605,8 +5619,6 @@
     method public void enableCarMode(int);
     method public int getCurrentModeType();
     method public int getNightMode();
-    method public boolean isNightModeLocked();
-    method public boolean isUiModeLocked();
     method public void setNightMode(int);
     field public static java.lang.String ACTION_ENTER_CAR_MODE;
     field public static java.lang.String ACTION_ENTER_DESK_MODE;
@@ -5708,6 +5720,7 @@
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clear(int) throws java.io.IOException;
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
     method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -5719,6 +5732,7 @@
     method public android.graphics.drawable.Drawable getFastDrawable();
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.os.ParcelFileDescriptor getWallpaperFile(int);
+    method public int getWallpaperId(int);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
     method public boolean isWallpaperSettingAllowed();
@@ -5744,8 +5758,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
-    field public static final int FLAG_SET_LOCK = 2; // 0x2
-    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+    field public static final int FLAG_LOCK = 2; // 0x2
+    field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5829,9 +5843,7 @@
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
-    method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
     method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
-    method public deprecated android.os.UserHandle createUser(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();
@@ -5847,8 +5859,7 @@
     method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
     method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
-    method public boolean getDeviceLoggingEnabled(android.content.ComponentName);
-    method public java.lang.String getDeviceOwnerLockScreenInfo();
+    method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public java.lang.String getLongSupportMessage(android.content.ComponentName);
@@ -5856,7 +5867,6 @@
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
     method public java.lang.String getOrganizationName(android.content.ComponentName);
-    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5881,20 +5891,24 @@
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
     method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
-    method public java.lang.String getWifiMacAddress();
+    method public java.lang.String getWifiMacAddress(android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
     method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
+    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
+    method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
+    method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
     method public void reboot(android.content.ComponentName);
@@ -5904,21 +5918,20 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
-    method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrieveDeviceLogs(android.content.ComponentName);
-    method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrievePreviousDeviceLogs(android.content.ComponentName);
+    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
+    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
-    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
+    method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
-    method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
+    method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
-    method public void setDeviceLoggingEnabled(android.content.ComponentName, boolean);
-    method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+    method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -5950,6 +5963,7 @@
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+    method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
     method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
@@ -5973,6 +5987,7 @@
     field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
     field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
     field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
+    field public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5; // 0x5
     field public static final int ENCRYPTION_STATUS_INACTIVE = 1; // 0x1
     field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
     field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
@@ -6034,6 +6049,27 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public class SecurityLog {
+    ctor public SecurityLog();
+    field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
+    field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
+    field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
+    field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
+    field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
+  }
+
+  public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.Object getData();
+    method public int getTag();
+    method public long getTimeNanos();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
+  }
+
   public class SystemUpdatePolicy implements android.os.Parcelable {
     method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -6238,6 +6274,8 @@
     method public long getIntervalMillis();
     method public long getMaxExecutionDelayMillis();
     method public long getMinLatencyMillis();
+    method public static final long getMinimumFlex();
+    method public static final long getMinimumPeriod();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
@@ -6251,8 +6289,6 @@
     field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
     field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
     field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
-    field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
-    field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
     field public static final int NETWORK_TYPE_ANY = 1; // 0x1
     field public static final int NETWORK_TYPE_NONE = 0; // 0x0
     field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6366,8 +6402,8 @@
     method public long getTxPackets();
     method public int getUid();
     field public static final int ROAMING_ALL = -1; // 0xffffffff
-    field public static final int ROAMING_DEFAULT = 1; // 0x1
-    field public static final int ROAMING_ROAMING = 2; // 0x2
+    field public static final int ROAMING_NO = 1; // 0x1
+    field public static final int ROAMING_YES = 2; // 0x2
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
@@ -6574,31 +6610,6 @@
 
 }
 
-package android.auditing {
-
-  public class SecurityLog {
-    ctor public SecurityLog();
-    field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
-    field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
-    field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
-    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
-    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
-    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
-    field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
-    field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
-  }
-
-  public static class SecurityLog.SecurityEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.lang.Object getData();
-    method public int getTag();
-    method public long getTimeNanos();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.auditing.SecurityLog.SecurityEvent> CREATOR;
-  }
-
-}
-
 package android.bluetooth {
 
   public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
@@ -7101,9 +7112,10 @@
     method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
   }
 
-  public class BluetoothGattCharacteristic {
+  public class BluetoothGattCharacteristic implements android.os.Parcelable {
     ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
     method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
     method public java.lang.Float getFloatValue(int, int);
@@ -7121,6 +7133,8 @@
     method public boolean setValue(int, int, int, int);
     method public boolean setValue(java.lang.String);
     method public void setWriteType(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
     field public static final int FORMAT_FLOAT = 52; // 0x34
     field public static final int FORMAT_SFLOAT = 50; // 0x32
     field public static final int FORMAT_SINT16 = 34; // 0x22
@@ -7151,13 +7165,16 @@
     field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors;
   }
 
-  public class BluetoothGattDescriptor {
+  public class BluetoothGattDescriptor implements android.os.Parcelable {
     ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
     method public int getPermissions();
     method public java.util.UUID getUuid();
     method public byte[] getValue();
     method public boolean setValue(byte[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
     field public static final byte[] DISABLE_NOTIFICATION_VALUE;
     field public static final byte[] ENABLE_INDICATION_VALUE;
     field public static final byte[] ENABLE_NOTIFICATION_VALUE;
@@ -7200,16 +7217,19 @@
     method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
   }
 
-  public class BluetoothGattService {
+  public class BluetoothGattService implements android.os.Parcelable {
     ctor public BluetoothGattService(java.util.UUID, int);
     method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
     method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
     method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
     method public int getInstanceId();
     method public int getType();
     method public java.util.UUID getUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattService> CREATOR;
     field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
     field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
     field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics;
@@ -7332,15 +7352,6 @@
     field public static final int TYPE_SCO = 2; // 0x2
   }
 
-  public class OobData implements android.os.Parcelable {
-    ctor public OobData();
-    method public int describeContents();
-    method public byte[] getSecurityManagerTk();
-    method public void setSecurityManagerTk(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
-  }
-
 }
 
 package android.bluetooth.le {
@@ -7981,7 +7992,7 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public abstract android.content.Context createDeviceEncryptedStorageContext();
+    method public abstract android.content.Context createDeviceProtectedStorageContext();
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -8026,8 +8037,6 @@
     method public abstract java.lang.String getPackageResourcePath();
     method public abstract android.content.res.Resources getResources();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -8039,10 +8048,10 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public abstract boolean isDeviceEncryptedStorage();
+    method public abstract boolean isDeviceProtectedStorage();
     method public boolean isRestricted();
-    method public abstract boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public abstract boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public abstract boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public abstract boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[]);
@@ -8116,7 +8125,7 @@
     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 HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
+    field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
     field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
@@ -8144,7 +8153,9 @@
     field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
+    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
@@ -8175,7 +8186,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createDeviceEncryptedStorageContext();
+    method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -8218,8 +8229,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -8227,9 +8236,9 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isDeviceEncryptedStorage();
-    method public boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public boolean isDeviceProtectedStorage();
+    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -8470,6 +8479,7 @@
     field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
     field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
     field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
+    field public static final java.lang.String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
     field public static final java.lang.String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
     field public static final java.lang.String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
     field public static final java.lang.String ACTION_ASSIST = "android.intent.action.ASSIST";
@@ -8513,8 +8523,9 @@
     field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
     field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
     field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
     field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -9254,7 +9265,6 @@
     field public int documentLaunchMode;
     field public int flags;
     field public int launchMode;
-    field public android.content.pm.ActivityInfo.Layout layout;
     field public int maxRecents;
     field public java.lang.String parentActivityName;
     field public java.lang.String permission;
@@ -9265,14 +9275,16 @@
     field public java.lang.String taskAffinity;
     field public int theme;
     field public int uiOptions;
+    field public android.content.pm.ActivityInfo.WindowLayout windowLayout;
   }
 
-  public static final class ActivityInfo.Layout {
-    ctor public ActivityInfo.Layout(int, float, int, float, int, int);
+  public static final class ActivityInfo.WindowLayout {
+    ctor public ActivityInfo.WindowLayout(int, float, int, float, int, int, int);
     field public final int gravity;
     field public final int height;
     field public final float heightFraction;
-    field public final int minimalSize;
+    field public final int minimalHeight;
+    field public final int minimalWidth;
     field public final int width;
     field public final float widthFraction;
   }
@@ -9319,14 +9331,14 @@
     field public java.lang.String backupAgentName;
     field public java.lang.String className;
     field public int compatibleWidthLimitDp;
-    field public java.lang.String credentialEncryptedDataDir;
     field public java.lang.String dataDir;
     field public int descriptionRes;
-    field public java.lang.String deviceEncryptedDataDir;
+    field public java.lang.String deviceProtectedDataDir;
     field public boolean enabled;
     field public int flags;
     field public int largestWidthLimitDp;
     field public java.lang.String manageSpaceActivityName;
+    field public java.lang.String minSdkVersion;
     field public java.lang.String nativeLibraryDir;
     field public java.lang.String permission;
     field public java.lang.String processName;
@@ -9358,8 +9370,8 @@
     method public boolean isEnabled();
     field public android.content.pm.ApplicationInfo applicationInfo;
     field public int descriptionRes;
+    field public boolean directBootAware;
     field public boolean enabled;
-    field public boolean encryptionAware;
     field public boolean exported;
     field public java.lang.String processName;
   }
@@ -9448,13 +9460,20 @@
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
+    method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+    method public boolean hasShortcutHostPermission();
     method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+    method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
   }
 
@@ -9467,6 +9486,18 @@
     method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
     method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+    method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
+  }
+
+  public static class LauncherApps.ShortcutQuery {
+    ctor public LauncherApps.ShortcutQuery();
+    method public void setActivity(android.content.ComponentName);
+    method public void setChangedSince(long);
+    method public void setPackage(java.lang.String);
+    method public void setQueryFlags(int);
+    field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_GET_PINNED = 2; // 0x2
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -9544,6 +9575,7 @@
     method public java.lang.String[] getNames() throws java.io.IOException;
     method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
     method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+    method public void removeSplit(java.lang.String) throws java.io.IOException;
     method public void setStagingProgress(float);
   }
 
@@ -9785,6 +9817,8 @@
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -9808,11 +9842,10 @@
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
+    field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
     field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
     field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
-    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
     field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
     field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
@@ -9887,6 +9920,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
     field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -9964,6 +9998,61 @@
     field public java.lang.String permission;
   }
 
+  public final class ShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivityComponent();
+    method public android.os.PersistableBundle getExtras();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public long getLastChangedTimestamp();
+    method public java.lang.String getPackageName();
+    method public java.lang.String getText();
+    method public java.lang.String getTitle();
+    method public int getWeight();
+    method public boolean hasIconFile();
+    method public boolean hasIconResource();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean isDynamic();
+    method public boolean isPinned();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
+    field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
+    field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int FLAG_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
+    field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+    field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
+    field public static final int FLAG_PINNED = 2; // 0x2
+  }
+
+  public static class ShortcutInfo.Builder {
+    ctor public ShortcutInfo.Builder(android.content.Context);
+    method public android.content.pm.ShortcutInfo build();
+    method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
+    method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setWeight(int);
+  }
+
+  public class ShortcutManager {
+    method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
+    method public void deleteAllDynamicShortcuts();
+    method public void deleteDynamicShortcut(java.lang.String);
+    method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+    method public int getIconMaxDimensions();
+    method public int getMaxDynamicShortcutCount();
+    method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public long getRateLimitResetTime();
+    method public int getRemainingCallCount();
+    method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+  }
+
   public class Signature implements android.os.Parcelable {
     ctor public Signature(byte[]);
     ctor public Signature(java.lang.String);
@@ -10035,7 +10124,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
+  public class ColorStateList implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -10044,18 +10133,13 @@
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
+    method public boolean isStateful();
     method public static android.content.res.ColorStateList valueOf(int);
     method public android.content.res.ColorStateList withAlpha(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
   }
 
-  public abstract class ComplexColor {
-    ctor public ComplexColor();
-    method public abstract int getDefaultColor();
-    method public boolean isStateful();
-  }
-
   public final class Configuration implements java.lang.Comparable android.os.Parcelable {
     ctor public Configuration();
     ctor public Configuration(android.content.res.Configuration);
@@ -10159,11 +10243,6 @@
     field public int uiMode;
   }
 
-  public class GradientColor extends android.content.res.ComplexColor {
-    method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public int getDefaultColor();
-  }
-
   public class ObbInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -10223,7 +10302,6 @@
     method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
     method public final android.content.res.Resources.Theme newTheme();
     method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
     method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10259,7 +10337,6 @@
     method public int getChangingConfigurations();
     method public int getColor(int, int);
     method public android.content.res.ColorStateList getColorStateList(int);
-    method public android.content.res.ComplexColor getComplexColor(int);
     method public float getDimension(int, float);
     method public int getDimensionPixelOffset(int, int);
     method public int getDimensionPixelSize(int, int);
@@ -10469,7 +10546,6 @@
     method public boolean hasNext();
     method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
     method public android.database.CursorJoiner.Result next();
-    method public void remove();
   }
 
   public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -11400,17 +11476,6 @@
 
 package android.graphics {
 
-  public deprecated class AvoidXfermode extends android.graphics.Xfermode {
-    ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
-  }
-
-  public static final class AvoidXfermode.Mode extends java.lang.Enum {
-    method public static android.graphics.AvoidXfermode.Mode valueOf(java.lang.String);
-    method public static final android.graphics.AvoidXfermode.Mode[] values();
-    enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
-    enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
-  }
-
   public final class Bitmap implements android.os.Parcelable {
     method public boolean compress(android.graphics.Bitmap.CompressFormat, int, java.io.OutputStream);
     method public android.graphics.Bitmap copy(android.graphics.Bitmap.Config, boolean);
@@ -11946,6 +12011,8 @@
     ctor public Outline(android.graphics.Outline);
     method public boolean canClip();
     method public float getAlpha();
+    method public float getRadius();
+    method public boolean getRect(android.graphics.Rect);
     method public boolean isEmpty();
     method public void offset(int, int);
     method public void set(android.graphics.Outline);
@@ -12275,10 +12342,6 @@
     field public int bytesPerPixel;
   }
 
-  public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
-    ctor public PixelXorXfermode(int);
-  }
-
   public class Point implements android.os.Parcelable {
     ctor public Point();
     ctor public Point(int, int);
@@ -12838,7 +12901,8 @@
     method public int getGradientType();
     method public int getOpacity();
     method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
-    method public boolean isUseLevel();
+    method public int getShape();
+    method public boolean getUseLevel();
     method public void setAlpha(int);
     method public void setColor(int);
     method public void setColor(android.content.res.ColorStateList);
@@ -12957,9 +13021,9 @@
     method public void setPaddingMode(int);
     method public void setPaddingRelative(int, int, int, int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    field public static final int INSET_UNDEFINED = -2147483648; // 0x80000000
     field public static final int PADDING_MODE_NEST = 0; // 0x0
     field public static final int PADDING_MODE_STACK = 1; // 0x1
-    field public static final int UNDEFINED_INSET = -2147483648; // 0x80000000
   }
 
   public class LevelListDrawable extends android.graphics.drawable.DrawableContainer {
@@ -12973,12 +13037,10 @@
     ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
     ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
     method public void draw(android.graphics.Canvas);
-    method public android.graphics.NinePatch getNinePatch();
     method public int getOpacity();
     method public android.graphics.Paint getPaint();
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setNinePatch(android.graphics.NinePatch);
     method public void setTargetDensity(android.graphics.Canvas);
     method public void setTargetDensity(android.util.DisplayMetrics);
     method public void setTargetDensity(int);
@@ -13201,8 +13263,8 @@
     method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
     method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
     method public final void unlock();
-    field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
-    field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+    field public static final deprecated java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
+    field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
     field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
     field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -13447,6 +13509,7 @@
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
+    method public int getId();
     method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
@@ -13456,9 +13519,10 @@
     method public float getResolution();
     method public java.lang.String getStringType();
     method public int getType();
-    method public java.util.UUID getUuid();
     method public java.lang.String getVendor();
     method public int getVersion();
+    method public boolean isAdditionalInfoSupported();
+    method public boolean isDynamicSensor();
     method public boolean isWakeUpSensor();
     field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
     field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13492,6 +13556,7 @@
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
+    field public static final int TYPE_DEVICE_PRIVATE_BASE = 65536; // 0x10000
     field public static final int TYPE_GAME_ROTATION_VECTOR = 15; // 0xf
     field public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; // 0x14
     field public static final int TYPE_GRAVITY = 9; // 0x9
@@ -13576,8 +13641,9 @@
     method public static void getRotationMatrixFromVector(float[], float[]);
     method public java.util.List<android.hardware.Sensor> getSensorList(int);
     method public deprecated int getSensors();
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+    method public boolean isDynamicSensorDiscoverySupported();
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13586,7 +13652,7 @@
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
-    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
     method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13651,8 +13717,8 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
-  public static abstract class SensorManager.DynamicSensorConnectionCallback {
-    ctor public SensorManager.DynamicSensorConnectionCallback();
+  public static abstract class SensorManager.DynamicSensorCallback {
+    ctor public SensorManager.DynamicSensorCallback();
     method public void onDynamicSensorConnected(android.hardware.Sensor);
     method public void onDynamicSensorDisconnected(android.hardware.Sensor);
   }
@@ -13702,6 +13768,7 @@
 
   public static abstract class CameraCaptureSession.CaptureCallback {
     ctor public CameraCaptureSession.CaptureCallback();
+    method public void onCaptureBufferLost(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.view.Surface, long);
     method public void onCaptureCompleted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult);
     method public void onCaptureFailed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure);
     method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
@@ -14776,7 +14843,6 @@
 
   public static abstract interface UCharacter.BidiPairedBracketType {
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int OPEN = 1; // 0x1
   }
@@ -14785,7 +14851,6 @@
     field public static final int CANONICAL = 1; // 0x1
     field public static final int CIRCLE = 3; // 0x3
     field public static final int COMPAT = 2; // 0x2
-    field public static final int COUNT = 18; // 0x12
     field public static final int FINAL = 4; // 0x4
     field public static final int FONT = 5; // 0x5
     field public static final int FRACTION = 6; // 0x6
@@ -14805,7 +14870,6 @@
 
   public static abstract interface UCharacter.EastAsianWidth {
     field public static final int AMBIGUOUS = 1; // 0x1
-    field public static final int COUNT = 6; // 0x6
     field public static final int FULLWIDTH = 3; // 0x3
     field public static final int HALFWIDTH = 2; // 0x2
     field public static final int NARROW = 4; // 0x4
@@ -14815,7 +14879,6 @@
 
   public static abstract interface UCharacter.GraphemeClusterBreak {
     field public static final int CONTROL = 1; // 0x1
-    field public static final int COUNT = 13; // 0xd
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
     field public static final int L = 4; // 0x4
@@ -14831,7 +14894,6 @@
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int LEADING_JAMO = 1; // 0x1
     field public static final int LVT_SYLLABLE = 5; // 0x5
     field public static final int LV_SYLLABLE = 4; // 0x4
@@ -14847,7 +14909,6 @@
     field public static final int BEH = 4; // 0x4
     field public static final int BETH = 5; // 0x5
     field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
-    field public static final int COUNT = 86; // 0x56
     field public static final int DAL = 6; // 0x6
     field public static final int DALATH_RISH = 7; // 0x7
     field public static final int E = 8; // 0x8
@@ -14932,7 +14993,6 @@
   }
 
   public static abstract interface UCharacter.JoiningType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int DUAL_JOINING = 2; // 0x2
     field public static final int JOIN_CAUSING = 1; // 0x1
     field public static final int LEFT_JOINING = 3; // 0x3
@@ -14955,7 +15015,6 @@
     field public static final int COMPLEX_CONTEXT = 24; // 0x18
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
-    field public static final int COUNT = 40; // 0x28
     field public static final int EXCLAMATION = 11; // 0xb
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
@@ -14987,7 +15046,6 @@
   }
 
   public static abstract interface UCharacter.NumericType {
-    field public static final int COUNT = 4; // 0x4
     field public static final int DECIMAL = 1; // 0x1
     field public static final int DIGIT = 2; // 0x2
     field public static final int NONE = 0; // 0x0
@@ -14997,7 +15055,6 @@
   public static abstract interface UCharacter.SentenceBreak {
     field public static final int ATERM = 1; // 0x1
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 15; // 0xf
     field public static final int CR = 11; // 0xb
     field public static final int EXTEND = 12; // 0xc
     field public static final int FORMAT = 3; // 0x3
@@ -15140,7 +15197,6 @@
     field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
     field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
     field public static final int COPTIC_ID = 132; // 0x84
-    field public static final int COUNT = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
     field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
     field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -15554,7 +15610,6 @@
 
   public static abstract interface UCharacter.WordBreak {
     field public static final int ALETTER = 1; // 0x1
-    field public static final int COUNT = 17; // 0x11
     field public static final int CR = 8; // 0x8
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
@@ -15585,7 +15640,6 @@
   }
 
   public static abstract interface UCharacterEnums.ECharacterCategory {
-    field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
     field public static final byte CONTROL = 15; // 0xf
@@ -15625,7 +15679,6 @@
     field public static final int ARABIC_NUMBER = 5; // 0x5
     field public static final int BLOCK_SEPARATOR = 7; // 0x7
     field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
-    field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
     field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
     field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
     field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -15678,7 +15731,6 @@
     field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
     field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
     field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
-    field public static final int BINARY_LIMIT = 57; // 0x39
     field public static final int BINARY_START = 0; // 0x0
     field public static final int BLOCK = 4097; // 0x1001
     field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -15697,7 +15749,6 @@
     field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
     field public static final int DEPRECATED = 6; // 0x6
     field public static final int DIACRITIC = 7; // 0x7
-    field public static final int DOUBLE_LIMIT = 12289; // 0x3001
     field public static final int DOUBLE_START = 12288; // 0x3000
     field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
     field public static final int EXTENDER = 8; // 0x8
@@ -15716,7 +15767,6 @@
     field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
     field public static final int ID_CONTINUE = 15; // 0xf
     field public static final int ID_START = 16; // 0x10
-    field public static final int INT_LIMIT = 4118; // 0x1016
     field public static final int INT_START = 4096; // 0x1000
     field public static final int JOINING_GROUP = 4102; // 0x1006
     field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -15726,7 +15776,6 @@
     field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
     field public static final int LOWERCASE = 22; // 0x16
     field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
-    field public static final int MASK_LIMIT = 8193; // 0x2001
     field public static final int MASK_START = 8192; // 0x2000
     field public static final int MATH = 23; // 0x17
     field public static final int NAME = 16389; // 0x4005
@@ -15741,7 +15790,6 @@
     field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
     field public static final int NUMERIC_TYPE = 4105; // 0x1009
     field public static final int NUMERIC_VALUE = 12288; // 0x3000
-    field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
     field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
     field public static final int PATTERN_SYNTAX = 42; // 0x2a
     field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -15761,7 +15809,6 @@
     field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
     field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
     field public static final int SOFT_DOTTED = 27; // 0x1b
-    field public static final int STRING_LIMIT = 16398; // 0x400e
     field public static final int STRING_START = 16384; // 0x4000
     field public static final int S_TERM = 35; // 0x23
     field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -15778,7 +15825,6 @@
   }
 
   public static abstract interface UProperty.NameChoice {
-    field public static final int COUNT = 2; // 0x2
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
   }
@@ -15823,7 +15869,6 @@
     field public static final int CHAM = 66; // 0x42
     field public static final int CHEROKEE = 6; // 0x6
     field public static final int CIRTH = 67; // 0x43
-    field public static final int CODE_LIMIT = 167; // 0xa7
     field public static final int COMMON = 0; // 0x0
     field public static final int COPTIC = 7; // 0x7
     field public static final int CUNEIFORM = 101; // 0x65
@@ -16218,7 +16263,6 @@
 
   public final class CollationKey implements java.lang.Comparable {
     ctor public CollationKey(java.lang.String, byte[]);
-    ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int compareTo(android.icu.text.CollationKey);
     method public boolean equals(android.icu.text.CollationKey);
     method public android.icu.text.CollationKey getBound(int, int);
@@ -16228,7 +16272,6 @@
   }
 
   public static final class CollationKey.BoundMode {
-    field public static final int COUNT = 3; // 0x3
     field public static final int LOWER = 0; // 0x0
     field public static final int UPPER = 1; // 0x1
     field public static final int UPPER_LONG = 2; // 0x2
@@ -16260,7 +16303,6 @@
     method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
     method public static final java.lang.String[] getKeywords();
     method public int getMaxVariable();
-    method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int[] getReorderCodes();
     method public int getStrength();
     method public android.icu.text.UnicodeSet getTailoredSet();
@@ -16300,7 +16342,6 @@
     field public static final int DEFAULT = -1; // 0xffffffff
     field public static final int DIGIT = 4100; // 0x1004
     field public static final int FIRST = 4096; // 0x1000
-    field public static final int LIMIT = 4101; // 0x1005
     field public static final int NONE = 103; // 0x67
     field public static final int OTHERS = 103; // 0x67
     field public static final int PUNCTUATION = 4097; // 0x1001
@@ -16413,7 +16454,6 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
-    field public static final int FIELD_COUNT = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16657,7 +16697,6 @@
     field public static final int MONTH = 3; // 0x3
     field public static final int QUARTER = 2; // 0x2
     field public static final int SECOND = 13; // 0xd
-    field public static final int TYPE_LIMIT = 16; // 0x10
     field public static final int WEEKDAY = 6; // 0x6
     field public static final int WEEK_OF_MONTH = 5; // 0x5
     field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -17288,14 +17327,6 @@
     enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
   }
 
-  public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
-    ctor public RawCollationKey();
-    ctor public RawCollationKey(int);
-    ctor public RawCollationKey(byte[]);
-    ctor public RawCollationKey(byte[], int);
-    method public int compareTo(android.icu.text.RawCollationKey);
-  }
-
   public final class RelativeDateTimeFormatter {
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -17379,7 +17410,6 @@
     method public android.icu.text.CollationKey getCollationKey(java.lang.String);
     method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
     method public boolean getNumericCollation();
-    method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public java.lang.String getRules();
     method public java.lang.String getRules(boolean);
     method public android.icu.util.VersionInfo getUCAVersion();
@@ -17710,9 +17740,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17726,10 +17753,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -17772,7 +17795,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -17787,7 +17809,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
@@ -17883,19 +17904,6 @@
     field public static final int BE = 0; // 0x0
   }
 
-  public class ByteArrayWrapper implements java.lang.Comparable {
-    ctor public ByteArrayWrapper();
-    ctor public ByteArrayWrapper(byte[], int);
-    ctor public ByteArrayWrapper(java.nio.ByteBuffer);
-    method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
-    method public int compareTo(android.icu.util.ByteArrayWrapper);
-    method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
-    method public final byte[] releaseBytes();
-    method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
-    field public byte[] bytes;
-    field public int size;
-  }
-
    abstract class CECalendar extends android.icu.util.Calendar {
     ctor protected CECalendar();
     ctor protected CECalendar(android.icu.util.TimeZone);
@@ -17906,11 +17914,8 @@
     ctor protected CECalendar(int, int, int);
     ctor protected CECalendar(java.util.Date);
     ctor protected CECalendar(int, int, int, int, int, int);
-    method public static int ceToJD(long, int, int, int);
-    method protected abstract int getJDEpochOffset();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetLimit(int, int);
-    method public static void jdToCE(int, int, int[]);
   }
 
   public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
@@ -18138,7 +18143,6 @@
     ctor public CopticCalendar(int, int, int);
     ctor public CopticCalendar(java.util.Date);
     ctor public CopticCalendar(int, int, int, int, int, int);
-    method protected deprecated int getJDEpochOffset();
     method protected deprecated int handleGetExtendedYear();
     field public static final int AMSHIR = 5; // 0x5
     field public static final int BABA = 1; // 0x1
@@ -18309,11 +18313,11 @@
     ctor public IslamicCalendar(java.util.Date);
     ctor public IslamicCalendar(int, int, int);
     ctor public IslamicCalendar(int, int, int, int, int, int);
+    method public android.icu.util.IslamicCalendar.CalculationType getCalculationType();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
-    method public boolean isCivil();
-    method public void setCivil(boolean);
+    method public void setCalculationType(android.icu.util.IslamicCalendar.CalculationType);
     field public static final int DHU_AL_HIJJAH = 11; // 0xb
     field public static final int DHU_AL_QIDAH = 10; // 0xa
     field public static final int JUMADA_1 = 4; // 0x4
@@ -18751,7 +18755,6 @@
     method public int getMicro();
     method public int getMilli();
     method public int getMinor();
-    method public static void main(java.lang.String[]);
     field public static final android.icu.util.VersionInfo ICU_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_BUILDER_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
@@ -19159,179 +19162,75 @@
 
   public final class GnssClock implements android.os.Parcelable {
     method public int describeContents();
-    method public double getBiasInNs();
-    method public double getBiasUncertaintyInNs();
-    method public double getDriftInNsPerSec();
-    method public double getDriftUncertaintyInNsPerSec();
-    method public long getFullBiasInNs();
+    method public double getBiasNanos();
+    method public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method public double getDriftUncertaintyNanosPerSecond();
+    method public long getFullBiasNanos();
     method public int getHardwareClockDiscontinuityCount();
-    method public short getLeapSecond();
-    method public long getTimeInNs();
-    method public double getTimeUncertaintyInNs();
-    method public byte getType();
-    method public boolean hasBiasInNs();
-    method public boolean hasBiasUncertaintyInNs();
-    method public boolean hasDriftInNsPerSec();
-    method public boolean hasDriftUncertaintyInNsPerSec();
-    method public boolean hasFullBiasInNs();
+    method public int getLeapSecond();
+    method public long getTimeNanos();
+    method public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasFullBiasNanos();
     method public boolean hasLeapSecond();
-    method public boolean hasTimeUncertaintyInNs();
-    method public void reset();
-    method public void resetBiasInNs();
-    method public void resetBiasUncertaintyInNs();
-    method public void resetDriftInNsPerSec();
-    method public void resetDriftUncertaintyInNsPerSec();
-    method public void resetFullBiasInNs();
-    method public void resetLeapSecond();
-    method public void resetTimeUncertaintyInNs();
-    method public void set(android.location.GnssClock);
-    method public void setBiasInNs(double);
-    method public void setBiasUncertaintyInNs(double);
-    method public void setDriftInNsPerSec(double);
-    method public void setDriftUncertaintyInNsPerSec(double);
-    method public void setFullBiasInNs(long);
-    method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(short);
-    method public void setTimeInNs(long);
-    method public void setTimeUncertaintyInNs(double);
-    method public void setType(byte);
+    method public boolean hasTimeUncertaintyNanos();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
-    field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
-    field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
   }
 
-  public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
-  }
-
   public final class GnssMeasurement implements android.os.Parcelable {
     method public int describeContents();
-    method public double getAccumulatedDeltaRangeInMeters();
-    method public short getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method public double getAzimuthInDeg();
-    method public double getAzimuthUncertaintyInDeg();
-    method public int getBitNumber();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public long getCarrierCycles();
-    method public float getCarrierFrequencyInHz();
+    method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
     method public double getCarrierPhaseUncertainty();
-    method public double getCn0InDbHz();
-    method public double getCodePhaseInChips();
-    method public double getCodePhaseUncertaintyInChips();
-    method public byte getConstellationType();
-    method public double getDopplerShiftInHz();
-    method public double getDopplerShiftUncertaintyInHz();
-    method public double getElevationInDeg();
-    method public double getElevationUncertaintyInDeg();
-    method public byte getLossOfLock();
-    method public byte getMultipathIndicator();
-    method public double getPseudorangeInMeters();
-    method public double getPseudorangeRateInMetersPerSec();
-    method public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method public double getPseudorangeUncertaintyInMeters();
-    method public long getReceivedSvTimeInNs();
-    method public long getReceivedSvTimeUncertaintyInNs();
+    method public double getCn0DbHz();
+    method public int getConstellationType();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
     method public double getSnrInDb();
-    method public short getState();
-    method public short getSvid();
-    method public short getTimeFromLastBitInMs();
-    method public double getTimeOffsetInNs();
-    method public boolean hasAzimuthInDeg();
-    method public boolean hasAzimuthUncertaintyInDeg();
-    method public boolean hasBitNumber();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
     method public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
     method public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodePhaseInChips();
-    method public boolean hasCodePhaseUncertaintyInChips();
-    method public boolean hasDopplerShiftInHz();
-    method public boolean hasDopplerShiftUncertaintyInHz();
-    method public boolean hasElevationInDeg();
-    method public boolean hasElevationUncertaintyInDeg();
-    method public boolean hasPseudorangeInMeters();
-    method public boolean hasPseudorangeUncertaintyInMeters();
     method public boolean hasSnrInDb();
-    method public boolean hasTimeFromLastBitInMs();
-    method public boolean isPseudorangeRateCorrected();
-    method public boolean isUsedInFix();
-    method public void reset();
-    method public void resetAzimuthInDeg();
-    method public void resetAzimuthUncertaintyInDeg();
-    method public void resetBitNumber();
-    method public void resetCarrierCycles();
-    method public void resetCarrierFrequencyInHz();
-    method public void resetCarrierPhase();
-    method public void resetCarrierPhaseUncertainty();
-    method public void resetCodePhaseInChips();
-    method public void resetCodePhaseUncertaintyInChips();
-    method public void resetDopplerShiftInHz();
-    method public void resetDopplerShiftUncertaintyInHz();
-    method public void resetElevationInDeg();
-    method public void resetElevationUncertaintyInDeg();
-    method public void resetPseudorangeInMeters();
-    method public void resetPseudorangeUncertaintyInMeters();
-    method public void resetSnrInDb();
-    method public void resetTimeFromLastBitInMs();
-    method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeInMeters(double);
-    method public void setAccumulatedDeltaRangeState(short);
-    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method public void setAzimuthInDeg(double);
-    method public void setAzimuthUncertaintyInDeg(double);
-    method public void setBitNumber(int);
-    method public void setCarrierCycles(long);
-    method public void setCarrierFrequencyInHz(float);
-    method public void setCarrierPhase(double);
-    method public void setCarrierPhaseUncertainty(double);
-    method public void setCn0InDbHz(double);
-    method public void setCodePhaseInChips(double);
-    method public void setCodePhaseUncertaintyInChips(double);
-    method public void setConstellationType(byte);
-    method public void setDopplerShiftInHz(double);
-    method public void setDopplerShiftUncertaintyInHz(double);
-    method public void setElevationInDeg(double);
-    method public void setElevationUncertaintyInDeg(double);
-    method public void setLossOfLock(byte);
-    method public void setMultipathIndicator(byte);
-    method public void setPseudorangeInMeters(double);
-    method public void setPseudorangeRateInMetersPerSec(double);
-    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method public void setPseudorangeUncertaintyInMeters(double);
-    method public void setReceivedSvTimeInNs(long);
-    method public void setReceivedSvTimeUncertaintyInNs(long);
-    method public void setSnrInDb(double);
-    method public void setState(short);
-    method public void setSvid(short);
-    method public void setTimeFromLastBitInMs(short);
-    method public void setTimeOffsetInNs(double);
-    method public void setUsedInFix(boolean);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final short ADR_STATE_RESET = 2; // 0x2
-    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final short ADR_STATE_VALID = 1; // 0x1
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final short STATE_BIT_SYNC = 2; // 0x2
-    field public static final short STATE_CODE_LOCK = 1; // 0x1
-    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final short STATE_TOW_DECODED = 8; // 0x8
-    field public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+    field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+    field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+    field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+    field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+    field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public final class GnssMeasurementsEvent implements android.os.Parcelable {
@@ -19341,7 +19240,7 @@
     method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19352,43 +19251,29 @@
     method public void onStatusChanged(int);
   }
 
-  public static abstract class GnssMeasurementsEvent.GnssMeasurementsStatus implements java.lang.annotation.Annotation {
-  }
-
   public final class GnssNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getData();
-    method public short getMessageId();
-    method public short getStatus();
-    method public short getSubmessageId();
-    method public short getSvid();
-    method public short getType();
-    method public void reset();
-    method public void set(android.location.GnssNavigationMessage);
-    method public void setData(byte[]);
-    method public void setMessageId(short);
-    method public void setStatus(short);
-    method public void setSubmessageId(short);
-    method public void setSvid(short);
-    method public void setType(short);
+    method public int getMessageId();
+    method public int getStatus();
+    method public int getSubmessageId();
+    method public int getSvid();
+    method public int getType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
-    field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
-    field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
-    field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
-    field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
-    field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
-    field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
-    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final short STATUS_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
   public final class GnssNavigationMessageEvent implements android.os.Parcelable {
@@ -19397,7 +19282,7 @@
     method public android.location.GnssNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19408,33 +19293,27 @@
     method public void onStatusChanged(int);
   }
 
-  public static abstract class GnssNavigationMessageEvent.GnssNavigationMessageStatus implements java.lang.annotation.Annotation {
-  }
-
   public abstract interface GnssNmeaListener {
     method public abstract void onNmeaReceived(long, java.lang.String);
   }
 
   public final class GnssStatus {
-    method public float getAzimuth(int);
-    method public byte getConstellationType(int);
-    method public float getElevation(int);
+    method public float getAzimuthDegrees(int);
+    method public float getCn0DbHz(int);
+    method public int getConstellationType(int);
+    method public float getElevationDegrees(int);
     method public int getNumSatellites();
-    method public float getSnr(int);
     method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
-    field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final byte CONSTELLATION_GPS = 1; // 0x1
-    field public static final byte CONSTELLATION_QZSS = 4; // 0x4
-    field public static final byte CONSTELLATION_SBAS = 2; // 0x2
-    field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
   public abstract class GnssStatusCallback {
@@ -19546,8 +19425,8 @@
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
     method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -19572,7 +19451,7 @@
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
-    method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -19692,6 +19571,7 @@
     field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
     field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
     field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+    field public static final int TYPE_BUS = 21; // 0x15
     field public static final int TYPE_DOCK = 13; // 0xd
     field public static final int TYPE_FM = 14; // 0xe
     field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -19709,12 +19589,14 @@
     field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
   }
 
-  public class AudioFormat {
+  public final class AudioFormat implements android.os.Parcelable {
+    method public int describeContents();
     method public int getChannelCount();
     method public int getChannelIndexMask();
     method public int getChannelMask();
     method public int getEncoding();
     method public int getSampleRate();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
     field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
     field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -19756,6 +19638,7 @@
     field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
     field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
     field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+    field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
     field public static final int ENCODING_AC3 = 5; // 0x5
     field public static final int ENCODING_DEFAULT = 1; // 0x1
     field public static final int ENCODING_DTS = 7; // 0x7
@@ -19766,6 +19649,7 @@
     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
+    field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
   }
 
   public static class AudioFormat.Builder {
@@ -19785,7 +19669,7 @@
     method public void adjustVolume(int, int);
     method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int generateAudioSessionId();
-    method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
+    method public android.media.AudioRecordingConfiguration[] getActiveRecordingConfigurations();
     method public android.media.AudioDeviceInfo[] getDevices(int);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
@@ -19931,7 +19815,7 @@
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged();
+    method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20005,7 +19889,7 @@
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
-  public class AudioRecordConfiguration implements android.os.Parcelable {
+  public final class AudioRecordingConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioDeviceInfo getAudioDevice();
     method public int getClientAudioSessionId();
@@ -20013,12 +19897,13 @@
     method public android.media.AudioFormat getClientFormat();
     method public android.media.AudioFormat getFormat();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
   }
 
   public abstract interface AudioRouting {
     method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public abstract android.media.AudioDeviceInfo getPreferredDevice();
+    method public abstract android.media.AudioDeviceInfo getRoutedDevice();
     method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
   }
@@ -20188,7 +20073,6 @@
   }
 
   public abstract class DrmInitData {
-    ctor public DrmInitData();
     method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
   }
 
@@ -20199,12 +20083,15 @@
 
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+    ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public java.lang.String getAttribute(java.lang.String);
     method public double getAttributeDouble(java.lang.String, double);
     method public int getAttributeInt(java.lang.String, int);
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
+    method public long[] getThumbnailRange();
     method public boolean hasThumbnail();
     method public void saveAttributes() throws java.io.IOException;
     method public void setAttribute(java.lang.String, java.lang.String);
@@ -20217,31 +20104,130 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
-    field public static final java.lang.String TAG_APERTURE = "FNumber";
+    field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
+    field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+    field public static final java.lang.String TAG_ARTIST = "Artist";
+    field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+    field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+    field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+    field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+    field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+    field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+    field public static final java.lang.String TAG_COMPRESSION = "Compression";
+    field public static final java.lang.String TAG_CONTRAST = "Contrast";
+    field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+    field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
     field public static final java.lang.String TAG_DATETIME = "DateTime";
     field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+    field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+    field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+    field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+    field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
+    field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+    field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
+    field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+    field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
     field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+    field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
     field public static final java.lang.String TAG_FLASH = "Flash";
+    field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+    field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
     field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+    field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+    field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+    field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+    field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+    field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+    field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
     field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
     field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+    field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
     field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+    field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+    field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
     field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
     field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
     field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
     field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+    field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
     field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+    field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+    field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+    field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+    field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
     field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+    field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+    field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+    field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
     field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+    field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
     field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
-    field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
+    field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+    field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
     field public static final java.lang.String TAG_MAKE = "Make";
+    field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+    field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+    field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
     field public static final java.lang.String TAG_MODEL = "Model";
+    field public static final java.lang.String TAG_OECF = "OECF";
     field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+    field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+    field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+    field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+    field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+    field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+    field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+    field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+    field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+    field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+    field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+    field public static final java.lang.String TAG_SATURATION = "Saturation";
+    field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+    field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+    field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+    field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+    field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+    field public static final java.lang.String TAG_SOFTWARE = "Software";
+    field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+    field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+    field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+    field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+    field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+    field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
     field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
     field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+    field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
     field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+    field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+    field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
     field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+    field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+    field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+    field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+    field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+    field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+    field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
     field public static final int WHITEBALANCE_AUTO = 0; // 0x0
     field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
   }
@@ -20341,8 +20327,8 @@
 
   public class MediaActionSound {
     ctor public MediaActionSound();
-    method public synchronized void load(int);
-    method public synchronized void play(int);
+    method public void load(int);
+    method public void play(int);
     method public void release();
     field public static final int FOCUS_COMPLETE = 1; // 0x1
     field public static final int SHUTTER_CLICK = 0; // 0x0
@@ -20439,6 +20425,7 @@
     field public static final int ERROR_NO_KEY = 1; // 0x1
     field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
     field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
+    field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6
   }
 
   public static final class MediaCodec.CryptoInfo {
@@ -20596,12 +20583,13 @@
     field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
     field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
     field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
-    field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
-    field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
-    field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
-    field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
-    field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
-    field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+    field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+    field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+    field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+    field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+    field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+    field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+    field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
     field public static final int H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -20647,6 +20635,7 @@
     field public static final int HEVCMainTierLevel62 = 16777216; // 0x1000000
     field public static final int HEVCProfileMain = 1; // 0x1
     field public static final int HEVCProfileMain10 = 2; // 0x2
+    field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
     field public static final int MPEG2LevelLL = 0; // 0x0
@@ -20904,6 +20893,7 @@
     method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String) throws java.io.IOException;
+    method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
     method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
     method public void unselectTrack(int);
@@ -20964,6 +20954,7 @@
     field public static final java.lang.String KEY_DURATION = "durationUs";
     field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
     field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
+    field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
     field public static final java.lang.String KEY_HEIGHT = "height";
     field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
     field public static final java.lang.String KEY_IS_ADTS = "is-adts";
@@ -20988,6 +20979,7 @@
     field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
     field public static final java.lang.String KEY_STRIDE = "stride";
     field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+    field public static final java.lang.String KEY_TRACK_ID = "track-id";
     field public static final java.lang.String KEY_WIDTH = "width";
     field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -21187,6 +21179,7 @@
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+    method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22263,7 +22256,7 @@
     method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(java.lang.String);
-    method public void unsubscribe(java.lang.String, android.os.Bundle);
+    method public void unsubscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
     field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
   }
@@ -22751,6 +22744,10 @@
     method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
     method public static final android.net.Uri buildRecordedProgramUri(long);
+    method public static final boolean isChannelUri(android.net.Uri);
+    method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+    method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+    method public static final boolean isProgramUri(android.net.Uri);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
@@ -22842,7 +22839,8 @@
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
     field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
     field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
@@ -22852,7 +22850,9 @@
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
     field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_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_THUMBNAIL_URI = "thumbnail_uri";
@@ -22895,7 +22895,7 @@
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
     field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
@@ -22910,7 +22910,8 @@
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
     field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_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_THUMBNAIL_URI = "thumbnail_uri";
@@ -22954,7 +22955,7 @@
   }
 
   public static final class TvInputInfo.Builder {
-    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
     method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
     method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -22971,6 +22972,7 @@
     field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
     field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
     field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
+    field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
     field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -23021,11 +23023,13 @@
     ctor public TvInputService.RecordingSession(android.content.Context);
     method public void notifyError(int);
     method public void notifyRecordingStopped(android.net.Uri);
-    method public void notifyTuned();
+    method public void notifyTuned(android.net.Uri);
+    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public abstract void onRelease();
     method public abstract void onStartRecording(android.net.Uri);
     method public abstract void onStopRecording();
     method public abstract void onTune(android.net.Uri);
+    method public void onTune(android.net.Uri, android.os.Bundle);
   }
 
   public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23039,6 +23043,7 @@
     method public void notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>);
     method public void notifyVideoAvailable();
     method public void notifyVideoUnavailable(int);
+    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public android.view.View onCreateOverlayView();
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
     method public boolean onKeyDown(int, android.view.KeyEvent);
@@ -23062,6 +23067,7 @@
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public abstract boolean onTune(android.net.Uri);
+    method public boolean onTune(android.net.Uri, android.os.Bundle);
     method public void onUnblockContent(android.media.tv.TvContentRating);
     method public void setOverlayViewEnabled(boolean);
   }
@@ -23069,9 +23075,11 @@
   public class TvRecordingClient {
     ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
     method public void release();
+    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public void startRecording(android.net.Uri);
     method public void stopRecording();
     method public void tune(java.lang.String, android.net.Uri);
+    method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
   }
 
   public static abstract class TvRecordingClient.RecordingCallback {
@@ -23080,7 +23088,7 @@
     method public void onDisconnected(java.lang.String);
     method public void onError(int);
     method public void onRecordingStopped(android.net.Uri);
-    method public void onTuned();
+    method public void onTuned(android.net.Uri);
   }
 
   public final class TvTrackInfo implements android.os.Parcelable {
@@ -23130,17 +23138,21 @@
     method public boolean onUnhandledInputEvent(android.view.InputEvent);
     method public void reset();
     method public void selectTrack(int, java.lang.String);
+    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public void setCallback(android.media.tv.TvView.TvInputCallback);
     method public void setCaptionEnabled(boolean);
     method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
     method public void setStreamVolume(float);
     method public void setTimeShiftPositionCallback(android.media.tv.TvView.TimeShiftPositionCallback);
+    method public void setZOrderMediaOverlay(boolean);
+    method public void setZOrderOnTop(boolean);
     method public void timeShiftPause();
     method public void timeShiftPlay(java.lang.String, android.net.Uri);
     method public void timeShiftResume();
     method public void timeShiftSeekTo(long);
     method public void timeShiftSetPlaybackParams(android.media.PlaybackParams);
     method public void tune(java.lang.String, android.net.Uri);
+    method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
   }
 
   public static abstract interface TvView.OnUnhandledInputEventListener {
@@ -23439,6 +23451,7 @@
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
+    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.app.PendingIntent);
     method public void releaseNetworkRequest(android.app.PendingIntent);
@@ -23507,7 +23520,7 @@
     method public int getUid();
   }
 
-  public class DataUsageRequest implements android.os.Parcelable {
+  public final class DataUsageRequest implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR;
@@ -26825,7 +26838,8 @@
     method public static void glGetSynciv(long, int, int, int[], int, int[], int);
     method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static deprecated void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static int glGetUniformBlockIndex(int, java.lang.String);
@@ -26851,6 +26865,7 @@
     method public static void glProgramBinary(int, int, java.nio.Buffer, int);
     method public static void glProgramParameteri(int, int, int);
     method public static void glReadBuffer(int);
+    method public static void glReadPixels(int, int, int, int, int, int, int);
     method public static void glRenderbufferStorageMultisample(int, int, int, int, int);
     method public static void glResumeTransformFeedback();
     method public static void glSamplerParameterf(int, int, float);
@@ -28436,6 +28451,10 @@
     ctor public DeadObjectException(java.lang.String);
   }
 
+  public class DeadSystemException extends android.os.DeadObjectException {
+    ctor public DeadSystemException();
+  }
+
   public final class Debug {
     method public static deprecated void changeDebugPort(int);
     method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
@@ -28689,14 +28708,17 @@
 
   public class HardwarePropertiesManager {
     method public android.os.CpuUsageInfo[] getCpuUsages();
-    method public float[] getDeviceTemperatures(int);
+    method public float[] getDeviceTemperatures(int, int);
     method public float[] getFanSpeeds();
     field public static final int DEVICE_TEMPERATURE_BATTERY = 2; // 0x2
     field public static final int DEVICE_TEMPERATURE_CPU = 0; // 0x0
     field public static final int DEVICE_TEMPERATURE_GPU = 1; // 0x1
-  }
-
-  public static abstract class HardwarePropertiesManager.DeviceTemperatureType implements java.lang.annotation.Annotation {
+    field public static final int DEVICE_TEMPERATURE_SKIN = 3; // 0x3
+    field public static final int TEMPERATURE_CURRENT = 0; // 0x0
+    field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
+    field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+    field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
+    field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
   }
 
   public abstract interface IBinder {
@@ -29055,6 +29077,7 @@
     method public boolean isInteractive();
     method public boolean isPowerSaveMode();
     method public deprecated boolean isScreenOn();
+    method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
@@ -29084,7 +29107,10 @@
   public class Process {
     ctor public Process();
     method public static final long getElapsedCpuTime();
+    method public static final int[] getExclusiveCores();
     method public static final int getGidForName(java.lang.String);
+    method public static final long getStartElapsedRealtime();
+    method public static final long getStartUptimeMillis();
     method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
     method public static final int getUidForName(java.lang.String);
     method public static final boolean is64Bit();
@@ -29292,10 +29318,6 @@
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
     method public boolean isUserRunning(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
     method public boolean isUserUnlocked();
     method public boolean isUserUnlocked(android.os.UserHandle);
@@ -29366,6 +29388,147 @@
 
 }
 
+package android.os.health {
+
+  public class HealthStats {
+    method public java.lang.String getDataType();
+    method public long getMeasurement(int);
+    method public int getMeasurementKeyAt(int);
+    method public int getMeasurementKeyCount();
+    method public java.util.Map<java.lang.String, java.lang.Long> getMeasurements(int);
+    method public int getMeasurementsKeyAt(int);
+    method public int getMeasurementsKeyCount();
+    method public java.util.Map<java.lang.String, android.os.health.HealthStats> getStats(int);
+    method public int getStatsKeyAt(int);
+    method public int getStatsKeyCount();
+    method public android.os.health.TimerStat getTimer(int);
+    method public int getTimerCount(int);
+    method public int getTimerKeyAt(int);
+    method public int getTimerKeyCount();
+    method public long getTimerTime(int);
+    method public java.util.Map<java.lang.String, android.os.health.TimerStat> getTimers(int);
+    method public int getTimersKeyAt(int);
+    method public int getTimersKeyCount();
+    method public boolean hasMeasurement(int);
+    method public boolean hasMeasurements(int);
+    method public boolean hasStats(int);
+    method public boolean hasTimer(int);
+    method public boolean hasTimers(int);
+  }
+
+  public final class PackageHealthStats {
+    field public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = 40002; // 0x9c42
+    field public static final int STATS_SERVICES = 40001; // 0x9c41
+  }
+
+  public final class PidHealthStats {
+    field public static final int MEASUREMENT_WAKE_NESTING_COUNT = 20001; // 0x4e21
+    field public static final int MEASUREMENT_WAKE_START_MS = 20003; // 0x4e23
+    field public static final int MEASUREMENT_WAKE_SUM_MS = 20002; // 0x4e22
+  }
+
+  public final class ProcessHealthStats {
+    field public static final int MEASUREMENT_ANR_COUNT = 30005; // 0x7535
+    field public static final int MEASUREMENT_CRASHES_COUNT = 30004; // 0x7534
+    field public static final int MEASUREMENT_FOREGROUND_MS = 30006; // 0x7536
+    field public static final int MEASUREMENT_STARTS_COUNT = 30003; // 0x7533
+    field public static final int MEASUREMENT_SYSTEM_TIME_MS = 30002; // 0x7532
+    field public static final int MEASUREMENT_USER_TIME_MS = 30001; // 0x7531
+  }
+
+  public final class ServiceHealthStats {
+    field public static final int MEASUREMENT_LAUNCH_COUNT = 50002; // 0xc352
+    field public static final int MEASUREMENT_START_SERVICE_COUNT = 50001; // 0xc351
+  }
+
+  public class SystemHealthManager {
+    method public static android.os.health.SystemHealthManager from(android.content.Context);
+    method public android.os.health.HealthStats takeMyUidSnapshot();
+    method public android.os.health.HealthStats takeUidSnapshot(int);
+    method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
+  }
+
+  public final class TimerStat implements android.os.Parcelable {
+    ctor public TimerStat();
+    ctor public TimerStat(int, long);
+    ctor public TimerStat(android.os.Parcel);
+    method public int describeContents();
+    method public int getCount();
+    method public long getTime();
+    method public void setCount(int);
+    method public void setTime(long);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.health.TimerStat> CREATOR;
+  }
+
+  public final class UidHealthStats {
+    field public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = 10020; // 0x2724
+    field public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = 10023; // 0x2727
+    field public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = 10052; // 0x2744
+    field public static final int MEASUREMENT_BLUETOOTH_RX_MS = 10021; // 0x2725
+    field public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = 10058; // 0x274a
+    field public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = 10053; // 0x2745
+    field public static final int MEASUREMENT_BLUETOOTH_TX_MS = 10022; // 0x2726
+    field public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = 10059; // 0x274b
+    field public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = 10046; // 0x273e
+    field public static final int MEASUREMENT_CPU_POWER_MAUS = 10064; // 0x2750
+    field public static final int MEASUREMENT_MOBILE_IDLE_MS = 10024; // 0x2728
+    field public static final int MEASUREMENT_MOBILE_POWER_MAMS = 10027; // 0x272b
+    field public static final int MEASUREMENT_MOBILE_RX_BYTES = 10048; // 0x2740
+    field public static final int MEASUREMENT_MOBILE_RX_MS = 10025; // 0x2729
+    field public static final int MEASUREMENT_MOBILE_RX_PACKETS = 10054; // 0x2746
+    field public static final int MEASUREMENT_MOBILE_TX_BYTES = 10049; // 0x2741
+    field public static final int MEASUREMENT_MOBILE_TX_MS = 10026; // 0x272a
+    field public static final int MEASUREMENT_MOBILE_TX_PACKETS = 10055; // 0x2747
+    field public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = 10045; // 0x273d
+    field public static final int MEASUREMENT_REALTIME_BATTERY_MS = 10001; // 0x2711
+    field public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = 10003; // 0x2713
+    field public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = 10063; // 0x274f
+    field public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = 10047; // 0x273f
+    field public static final int MEASUREMENT_UPTIME_BATTERY_MS = 10002; // 0x2712
+    field public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = 10004; // 0x2714
+    field public static final int MEASUREMENT_USER_CPU_TIME_US = 10062; // 0x274e
+    field public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = 10029; // 0x272d
+    field public static final int MEASUREMENT_WIFI_IDLE_MS = 10016; // 0x2720
+    field public static final int MEASUREMENT_WIFI_MULTICAST_MS = 10031; // 0x272f
+    field public static final int MEASUREMENT_WIFI_POWER_MAMS = 10019; // 0x2723
+    field public static final int MEASUREMENT_WIFI_RUNNING_MS = 10028; // 0x272c
+    field public static final int MEASUREMENT_WIFI_RX_BYTES = 10050; // 0x2742
+    field public static final int MEASUREMENT_WIFI_RX_MS = 10017; // 0x2721
+    field public static final int MEASUREMENT_WIFI_RX_PACKETS = 10056; // 0x2748
+    field public static final int MEASUREMENT_WIFI_TX_BYTES = 10051; // 0x2743
+    field public static final int MEASUREMENT_WIFI_TX_MS = 10018; // 0x2722
+    field public static final int MEASUREMENT_WIFI_TX_PACKETS = 10057; // 0x2749
+    field public static final int STATS_PACKAGES = 10015; // 0x271f
+    field public static final int STATS_PIDS = 10013; // 0x271d
+    field public static final int STATS_PROCESSES = 10014; // 0x271e
+    field public static final int TIMERS_JOBS = 10010; // 0x271a
+    field public static final int TIMERS_SENSORS = 10012; // 0x271c
+    field public static final int TIMERS_SYNCS = 10009; // 0x2719
+    field public static final int TIMERS_WAKELOCKS_DRAW = 10008; // 0x2718
+    field public static final int TIMERS_WAKELOCKS_FULL = 10005; // 0x2715
+    field public static final int TIMERS_WAKELOCKS_PARTIAL = 10006; // 0x2716
+    field public static final int TIMERS_WAKELOCKS_WINDOW = 10007; // 0x2717
+    field public static final int TIMER_AUDIO = 10032; // 0x2730
+    field public static final int TIMER_BLUETOOTH_SCAN = 10037; // 0x2735
+    field public static final int TIMER_CAMERA = 10035; // 0x2733
+    field public static final int TIMER_FLASHLIGHT = 10034; // 0x2732
+    field public static final int TIMER_FOREGROUND_ACTIVITY = 10036; // 0x2734
+    field public static final int TIMER_GPS_SENSOR = 10011; // 0x271b
+    field public static final int TIMER_MOBILE_RADIO_ACTIVE = 10061; // 0x274d
+    field public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = 10042; // 0x273a
+    field public static final int TIMER_PROCESS_STATE_CACHED_MS = 10043; // 0x273b
+    field public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = 10041; // 0x2739
+    field public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = 10039; // 0x2737
+    field public static final int TIMER_PROCESS_STATE_TOP_MS = 10038; // 0x2736
+    field public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = 10040; // 0x2738
+    field public static final int TIMER_VIBRATOR = 10044; // 0x273c
+    field public static final int TIMER_VIDEO = 10033; // 0x2731
+    field public static final int TIMER_WIFI_SCAN = 10030; // 0x272e
+  }
+
+}
+
 package android.os.storage {
 
   public abstract class OnObbStateChangeListener {
@@ -29383,14 +29546,15 @@
 
   public class StorageManager {
     method public java.lang.String getMountedObbPath(java.lang.String);
-    method public android.os.storage.StorageVolume getPrimaryVolume();
-    method public android.os.storage.StorageVolume[] getVolumeList();
+    method public android.os.storage.StorageVolume getPrimaryStorageVolume();
+    method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+    method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
   }
 
-  public class StorageVolume implements android.os.Parcelable {
+  public final class StorageVolume implements android.os.Parcelable {
     method public android.content.Intent createAccessIntent(java.lang.String);
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
@@ -29518,6 +29682,7 @@
     method protected int getPersistedInt(int);
     method protected long getPersistedLong(long);
     method protected java.lang.String getPersistedString(java.lang.String);
+    method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
     method public android.preference.PreferenceManager getPreferenceManager();
     method public android.content.SharedPreferences getSharedPreferences();
     method public boolean getShouldDisableView();
@@ -29539,7 +29704,6 @@
     method protected void onClick();
     method protected android.view.View onCreateView(android.view.ViewGroup);
     method public void onDependencyChanged(android.preference.Preference, boolean);
-    method protected void onDetachedFromActivity();
     method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
     method public void onParentChanged(android.preference.Preference, boolean);
     method protected void onPrepareForRemoval();
@@ -29552,6 +29716,7 @@
     method protected boolean persistInt(int);
     method protected boolean persistLong(long);
     method protected boolean persistString(java.lang.String);
+    method public boolean persistStringSet(java.util.Set<java.lang.String>);
     method public void restoreHierarchyState(android.os.Bundle);
     method public void saveHierarchyState(android.os.Bundle);
     method public void setDefaultValue(java.lang.Object);
@@ -29709,12 +29874,14 @@
     method public android.content.SharedPreferences getSharedPreferences();
     method public int getSharedPreferencesMode();
     method public java.lang.String getSharedPreferencesName();
+    method public boolean isStorageDefault();
+    method public boolean isStorageDeviceProtected();
     method public static void setDefaultValues(android.content.Context, int, boolean);
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
     method public void setStorageDefault();
-    method public void setStorageDeviceEncrypted();
+    method public void setStorageDeviceProtected();
     field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
     field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
   }
@@ -30084,7 +30251,7 @@
     method public android.print.PrinterInfo build();
     method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
     method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
-    method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+    method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon(boolean);
     method public android.print.PrinterInfo.Builder setIconResourceId(int);
     method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
     method public android.print.PrinterInfo.Builder setName(java.lang.String);
@@ -30136,6 +30303,7 @@
     method public boolean isStarted();
     method public void setProgress(float);
     method public void setStatus(java.lang.CharSequence);
+    method public void setStatus(int);
     method public boolean setTag(java.lang.String);
     method public boolean start();
   }
@@ -30166,7 +30334,7 @@
     method public final boolean isDestroyed();
     method public final boolean isPrinterDiscoveryStarted();
     method public abstract void onDestroy();
-    method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+    method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
     method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
     method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
     method public abstract void onStopPrinterDiscovery();
@@ -30212,6 +30380,7 @@
   public class BlockedNumberContract {
     method public static boolean canCurrentUserBlockNumbers(android.content.Context);
     method public static boolean isBlocked(android.content.Context, java.lang.String);
+    method public static int unblock(android.content.Context, java.lang.String);
     field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
     field public static final android.net.Uri AUTHORITY_URI;
   }
@@ -30221,7 +30390,7 @@
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
     field public static final android.net.Uri CONTENT_URI;
   }
 
@@ -30525,6 +30694,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -30547,6 +30717,7 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final java.lang.String FEATURES = "features";
+    field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
@@ -30569,6 +30740,7 @@
     field public static final int REJECTED_TYPE = 5; // 0x5
     field public static final java.lang.String TRANSCRIPTION = "transcription";
     field public static final java.lang.String TYPE = "type";
+    field public static final java.lang.String VIA_NUMBER = "via_number";
     field public static final int VOICEMAIL_TYPE = 4; // 0x4
     field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
   }
@@ -31719,6 +31891,7 @@
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
     field public static final java.lang.String EXTRA_LOADING = "loading";
+    field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
     field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
   }
@@ -31748,6 +31921,7 @@
 
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
     field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
     field public static final java.lang.String COLUMN_FLAGS = "flags";
     field public static final java.lang.String COLUMN_ICON = "icon";
@@ -32164,13 +32338,13 @@
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
+    field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
     field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
-    field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
     field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
     field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -32189,7 +32363,6 @@
     field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
     field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
     field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
-    field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
     field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
     field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -32202,6 +32375,8 @@
     field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
     field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
     field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+    field public static final java.lang.String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
+    field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
     field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
@@ -32239,6 +32414,7 @@
     field public static final java.lang.String AUTO_TIME = "auto_time";
     field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+    field public static final java.lang.String BOOT_COUNT = "boot_count";
     field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_ROAMING = "data_roaming";
@@ -34110,6 +34286,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34127,6 +34304,7 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
     method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
     method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -34153,6 +34331,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isInsideSecureHardware();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34216,6 +34395,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34227,6 +34407,7 @@
     method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -34265,7 +34446,8 @@
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -34276,6 +34458,9 @@
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+    field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
     field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -34380,7 +34565,6 @@
     method public boolean onMenuOpened(int, android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public boolean onSearchRequested(android.view.SearchEvent);
     method public boolean onSearchRequested();
     method public void onWakeUp();
@@ -34444,8 +34628,9 @@
 package android.service.notification {
 
   public class Condition implements android.os.Parcelable {
-    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int);
+    ctor public Condition(android.net.Uri, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
+    ctor public Condition(android.os.Parcel);
     method public android.service.notification.Condition copy();
     method public int describeContents();
     method public static boolean isValidId(android.net.Uri, java.lang.String);
@@ -34476,6 +34661,7 @@
     method public final void notifyConditions(android.service.notification.Condition...);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract void onConnected();
+    method public void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
@@ -34507,10 +34693,9 @@
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
-    method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
+    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
     method public final void requestUnbind() throws android.os.RemoteException;
     method public final void setNotificationsShown(java.lang.String[]);
-    field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
     field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
     field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -34531,10 +34716,11 @@
     method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
-    field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
-    field public static final int IMPORTANCE_HIGH = 3; // 0x3
-    field public static final int IMPORTANCE_LOW = 1; // 0x1
-    field public static final int IMPORTANCE_MAX = 4; // 0x4
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
     field public static final int IMPORTANCE_NONE = 0; // 0x0
     field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
   }
@@ -34804,6 +34990,18 @@
 
 }
 
+package android.service.vr {
+
+  public abstract class VrListenerService extends android.app.Service {
+    ctor public VrListenerService();
+    method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onCurrentVrActivityChanged(android.content.ComponentName);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+  }
+
+}
+
 package android.service.wallpaper {
 
   public abstract class WallpaperService extends android.app.Service {
@@ -35796,9 +35994,13 @@
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
+    method public final void putExtras(android.os.Bundle);
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public void sendCallEvent(java.lang.String, android.os.Bundle);
     method public void splitFromConference();
     method public void stopDtmfTone();
     method public void swapConference();
@@ -35812,6 +36014,7 @@
     field public static final int STATE_DISCONNECTING = 10; // 0xa
     field public static final int STATE_HOLDING = 3; // 0x3
     field public static final int STATE_NEW = 0; // 0x0
+    field public static final int STATE_PULLING_CALL = 11; // 0xb
     field public static final int STATE_RINGING = 2; // 0x2
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
   }
@@ -35822,6 +36025,7 @@
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -35852,6 +36056,7 @@
     method public static java.lang.String propertiesToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
     field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -35871,6 +36076,7 @@
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
     field public static final int PROPERTY_WIFI = 8; // 0x8
     field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
@@ -35922,6 +36128,7 @@
     method public final android.telecom.CallAudioState getCallAudioState();
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final long getConnectionTime();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -35934,6 +36141,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onConnectionAdded(android.telecom.Connection);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onMerge(android.telecom.Connection);
     method public void onMerge();
@@ -35942,14 +36150,17 @@
     method public void onStopDtmfTone();
     method public void onSwap();
     method public void onUnhold();
+    method public final void putExtras(android.os.Bundle);
     method public final void removeConnection(android.telecom.Connection);
+    method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void setActive();
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setConnectionTime(long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setOnHold();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -35975,6 +36186,7 @@
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public final int getState();
@@ -35985,15 +36197,23 @@
     method public void onAnswer(int);
     method public void onAnswer();
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+    method public void onCallEvent(java.lang.String, android.os.Bundle);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onPlayDtmfTone(char);
     method public void onPostDialContinue(boolean);
+    method public void onPullExternalCall();
     method public void onReject();
+    method public void onReject(java.lang.String);
     method public void onSeparate();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
+    method public static java.lang.String propertiesToString(int);
+    method public final void putExtras(android.os.Bundle);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
@@ -36001,9 +36221,10 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setNextPostDialChar(char);
@@ -36017,6 +36238,8 @@
     method public static java.lang.String stateToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
+    field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -36033,15 +36256,18 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
     field public static final int STATE_HOLDING = 5; // 0x5
     field public static final int STATE_INITIALIZING = 0; // 0x0
     field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_PULLING_CALL = 7; // 0x7
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
@@ -36096,6 +36322,7 @@
     method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
     method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public final java.util.Collection<android.telecom.Conference> getAllConferences();
     method public final java.util.Collection<android.telecom.Connection> getAllConnections();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
@@ -36118,7 +36345,9 @@
     method public java.lang.String getReason();
     method public int getTone();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
     field public static final int BUSY = 7; // 0x7
+    field public static final int CALL_PULLED = 12; // 0xc
     field public static final int CANCELED = 4; // 0x4
     field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
     field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR;
@@ -36154,6 +36383,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onSilenceRinger();
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
@@ -36253,6 +36483,7 @@
     method public void disconnect();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final java.util.List<android.telecom.RemoteConnection> getConnections();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
@@ -36275,6 +36506,7 @@
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
     method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onDestroyed(android.telecom.RemoteConference);
     method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36293,6 +36525,7 @@
     method public android.telecom.RemoteConference getConference();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public int getConnectionCapabilities();
+    method public int getConnectionProperties();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public int getState();
@@ -36304,6 +36537,7 @@
     method public boolean isVoipAudioMode();
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
     method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
@@ -36320,6 +36554,8 @@
     method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
     method public void onDestroyed(android.telecom.RemoteConnection);
     method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
     method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -36372,6 +36608,7 @@
   public class TelecomManager {
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void cancelMissedCallsNotification();
+    method public android.content.Intent createManageBlockedNumbersIntent();
     method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
     method public java.lang.String getDefaultDialerPackage();
@@ -36384,7 +36621,6 @@
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public void launchManageBlockedNumbersActivity();
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
@@ -36416,6 +36652,7 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+    field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -36464,15 +36701,16 @@
 package android.telephony {
 
   public class CarrierConfigManager {
+    method public android.os.PersistableBundle getConfig(int);
     method public android.os.PersistableBundle getConfig();
-    method public android.os.PersistableBundle getConfigForSubId(int);
-    method public void notifyConfigChangedForSubId(int);
+    method public deprecated android.os.PersistableBundle getConfigForSubId(int);
+    method public void notifyConfigChanged(int);
+    method public deprecated void notifyConfigChangedForSubId(int);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
-    field public static final java.lang.String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS = "bool_allow_emergency_video_calls";
-    field public static final java.lang.String BOOL_ALLOW_VIDEO_PAUSE = "bool_allow_video_pause";
     field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
     field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
     field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
+    field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
     field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
     field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
@@ -36494,6 +36732,7 @@
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
     field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+    field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -36555,6 +36794,7 @@
     field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+    field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
@@ -37069,7 +37309,8 @@
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
     method public java.lang.String getGroupIdLevel1(int);
-    method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+    method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+    method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
     method public java.lang.String getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
     method public java.lang.String getLine1Number(int);
@@ -37104,12 +37345,18 @@
     method public int getVoiceNetworkType(int);
     method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
     method public boolean hasCarrierPrivileges();
+    method public boolean hasCarrierPrivileges(int);
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
+    method public boolean iccCloseLogicalChannel(int, int);
     method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+    method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+    method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
     method public boolean isNetworkRoaming(int);
@@ -37120,15 +37367,25 @@
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
+    method public boolean setOperatorBrandOverride(int, java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
+    method public boolean setPreferredNetworkTypeToGlobal(int);
     method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
     method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
     field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+    field public static final int APPTYPE_CSIM = 4; // 0x4
+    field public static final int APPTYPE_ISIM = 5; // 0x5
+    field public static final int APPTYPE_RUIM = 3; // 0x3
+    field public static final int APPTYPE_SIM = 1; // 0x1
+    field public static final int APPTYPE_USIM = 2; // 0x2
+    field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+    field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -37630,7 +37887,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createDeviceEncryptedStorageContext();
+    method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -37672,8 +37929,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -37681,9 +37936,9 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isDeviceEncryptedStorage();
-    method public boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public boolean isDeviceProtectedStorage();
+    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -38488,7 +38743,6 @@
     method public boolean hasNext();
     method public java.util.Iterator<java.lang.String> iterator();
     method public java.lang.String next();
-    method public void remove();
     method public void setString(java.lang.String);
   }
 
@@ -39506,8 +39760,10 @@
     method public static final boolean addLinks(android.widget.TextView, int);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
     field public static final int ALL = 15; // 0xf
     field public static final int EMAIL_ADDRESSES = 2; // 0x2
     field public static final int MAP_ADDRESSES = 8; // 0x8
@@ -40100,6 +40356,7 @@
     method public int describeContents();
     method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getAdjustedDefault();
     method public static android.util.LocaleList getDefault();
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -41394,9 +41651,11 @@
   }
 
   public final class KeyboardShortcutInfo implements android.os.Parcelable {
+    ctor public KeyboardShortcutInfo(java.lang.CharSequence, int, int);
     ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
     method public int describeContents();
     method public char getBaseCharacter();
+    method public int getKeycode();
     method public java.lang.CharSequence getLabel();
     method public int getModifiers();
     method public void writeToParcel(android.os.Parcel, int);
@@ -42024,6 +42283,7 @@
     method public boolean dispatchDragEvent(android.view.DragEvent);
     method protected void dispatchDraw(android.graphics.Canvas);
     method public void dispatchDrawableHotspotChanged(float, float);
+    method public void dispatchFinishTemporaryDetach();
     method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -42043,6 +42303,7 @@
     method protected void dispatchSetActivated(boolean);
     method protected void dispatchSetPressed(boolean);
     method protected void dispatchSetSelected(boolean);
+    method public void dispatchStartTemporaryDetach();
     method public void dispatchSystemUiVisibilityChanged(int);
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -42060,6 +42321,7 @@
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
+    method public void forceHasOverlappingRendering(boolean);
     method public void forceLayout();
     method public static int generateViewId();
     method public java.lang.CharSequence getAccessibilityClassName();
@@ -42105,6 +42367,7 @@
     method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
     method public final boolean getGlobalVisibleRect(android.graphics.Rect);
     method public android.os.Handler getHandler();
+    method public final boolean getHasOverlappingRendering();
     method public final int getHeight();
     method public void getHitRect(android.graphics.Rect);
     method public int getHorizontalFadingEdgeLength();
@@ -42253,6 +42516,7 @@
     method public boolean isSelected();
     method public boolean isShown();
     method public boolean isSoundEffectsEnabled();
+    method public final boolean isTemporarilyDetached();
     method public boolean isTextAlignmentResolved();
     method public boolean isTextDirectionResolved();
     method public boolean isVerticalFadingEdgeEnabled();
@@ -42310,6 +42574,7 @@
     method public void onStartTemporaryDetach();
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
+    method public void onVisibilityAggregated(boolean);
     method protected void onVisibilityChanged(android.view.View, int);
     method public void onWindowFocusChanged(boolean);
     method public void onWindowSystemUiVisibilityChanged(int);
@@ -43406,7 +43671,7 @@
     method public abstract boolean onMenuOpened(int, android.view.Menu);
     method public abstract void onPanelClosed(int, android.view.Menu);
     method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+    method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
     method public abstract boolean onSearchRequested();
     method public abstract boolean onSearchRequested(android.view.SearchEvent);
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -43836,8 +44101,6 @@
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
     field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
@@ -44008,6 +44271,7 @@
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
     method public int getChildCount();
@@ -44015,6 +44279,7 @@
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+    method public java.lang.CharSequence getTitle();
     method public int getType();
     method public boolean isAccessibilityFocused();
     method public boolean isActive();
@@ -44027,6 +44292,7 @@
     field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
     field public static final int TYPE_APPLICATION = 1; // 0x1
     field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
     field public static final int TYPE_SYSTEM = 3; // 0x3
   }
 
@@ -44354,6 +44620,7 @@
     ctor public BaseInputConnection(android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -44521,6 +44788,7 @@
   public abstract interface InputConnection {
     method public abstract boolean beginBatchEdit();
     method public abstract boolean clearMetaKeyStates(int);
+    method public abstract void closeConnection();
     method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -44553,6 +44821,7 @@
     ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -46002,7 +46271,7 @@
     method public long getMinDate();
     method public deprecated android.graphics.drawable.Drawable getSelectedDateVerticalBar();
     method public deprecated int getSelectedWeekBackgroundColor();
-    method public boolean getShowWeekNumber();
+    method public deprecated boolean getShowWeekNumber();
     method public deprecated int getShownWeekCount();
     method public deprecated int getUnfocusedMonthDateColor();
     method public int getWeekDayTextAppearance();
@@ -46019,7 +46288,7 @@
     method public deprecated void setSelectedDateVerticalBar(int);
     method public deprecated void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
     method public deprecated void setSelectedWeekBackgroundColor(int);
-    method public void setShowWeekNumber(boolean);
+    method public deprecated void setShowWeekNumber(boolean);
     method public deprecated void setShownWeekCount(int);
     method public deprecated void setUnfocusedMonthDateColor(int);
     method public void setWeekDayTextAppearance(int);
@@ -46069,7 +46338,9 @@
     method public long getBase();
     method public java.lang.String getFormat();
     method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener();
+    method public boolean isCountDown();
     method public void setBase(long);
+    method public void setCountDown(boolean);
     method public void setFormat(java.lang.String);
     method public void setOnChronometerTickListener(android.widget.Chronometer.OnChronometerTickListener);
     method public void start();
@@ -46917,6 +47188,8 @@
     method public android.graphics.drawable.Drawable getBackground();
     method public android.view.View getContentView();
     method public float getElevation();
+    method public android.transition.Transition getEnterTransition();
+    method public android.transition.Transition getExitTransition();
     method public int getHeight();
     method public int getInputMethodMode();
     method public int getMaxAvailableHeight(android.view.View);
@@ -47161,6 +47434,7 @@
     method public void setChar(int, java.lang.String, char);
     method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
     method public void setChronometer(int, long, java.lang.String, boolean);
+    method public void setChronometerCountsDown(int, boolean);
     method public void setContentDescription(int, java.lang.CharSequence);
     method public void setDisplayedChild(int, int);
     method public void setDouble(int, java.lang.String, double);
@@ -47995,9 +48269,15 @@
     method public void collapseActionView();
     method public void dismissPopupMenus();
     method public int getContentInsetEnd();
+    method public int getContentInsetEndWithActions();
     method public int getContentInsetLeft();
     method public int getContentInsetRight();
     method public int getContentInsetStart();
+    method public int getContentInsetStartWithNavigation();
+    method public int getCurrentContentInsetEnd();
+    method public int getCurrentContentInsetLeft();
+    method public int getCurrentContentInsetRight();
+    method public int getCurrentContentInsetStart();
     method public android.graphics.drawable.Drawable getLogo();
     method public java.lang.CharSequence getLogoDescription();
     method public android.view.Menu getMenu();
@@ -48016,6 +48296,8 @@
     method public void inflateMenu(int);
     method public boolean isOverflowMenuShowing();
     method protected void onLayout(boolean, int, int, int, int);
+    method public void setContentInsetEndWithActions(int);
+    method public void setContentInsetStartWithNavigation(int);
     method public void setContentInsetsAbsolute(int, int);
     method public void setContentInsetsRelative(int, int);
     method public void setLogo(int);
@@ -49000,9 +49282,7 @@
 
   public final class FilePermission extends java.security.Permission implements java.io.Serializable {
     ctor public FilePermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -49741,6 +50021,7 @@
     method public static int compare(boolean, boolean);
     method public int compareTo(java.lang.Boolean);
     method public static boolean getBoolean(java.lang.String);
+    method public static int hashCode(boolean);
     method public static boolean parseBoolean(java.lang.String);
     method public static java.lang.String toString(boolean);
     method public static java.lang.Boolean valueOf(boolean);
@@ -49758,6 +50039,7 @@
     method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(byte);
     method public int intValue();
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -49766,6 +50048,7 @@
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+    field public static final int BYTES = 1; // 0x1
     field public static final byte MAX_VALUE = 127; // 0x7f
     field public static final byte MIN_VALUE = -128; // 0xffffff80
     field public static final int SIZE = 8; // 0x8
@@ -49803,6 +50086,7 @@
     method public static int getNumericValue(int);
     method public static int getType(char);
     method public static int getType(int);
+    method public static int hashCode(char);
     method public static char highSurrogate(int);
     method public static boolean isAlphabetic(int);
     method public static boolean isBmpCodePoint(int);
@@ -49863,6 +50147,7 @@
     method public static char toUpperCase(char);
     method public static int toUpperCase(int);
     method public static java.lang.Character valueOf(char);
+    field public static final int BYTES = 2; // 0x2
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
     field public static final byte CONTROL = 15; // 0xf
@@ -50407,18 +50692,24 @@
     method public static long doubleToRawLongBits(double);
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(double);
     method public int intValue();
+    method public static boolean isFinite(double);
     method public static boolean isInfinite(double);
     method public boolean isInfinite();
     method public static boolean isNaN(double);
     method public boolean isNaN();
     method public static double longBitsToDouble(long);
     method public long longValue();
+    method public static double max(double, double);
+    method public static double min(double, double);
     method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+    method public static double sum(double, double);
     method public static java.lang.String toHexString(double);
     method public static java.lang.String toString(double);
     method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Double valueOf(double);
+    field public static final int BYTES = 8; // 0x8
     field public static final int MAX_EXPONENT = 1023; // 0x3ff
     field public static final double MAX_VALUE = 1.7976931348623157E308;
     field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -50483,18 +50774,24 @@
     method public static int floatToIntBits(float);
     method public static int floatToRawIntBits(float);
     method public float floatValue();
+    method public static int hashCode(float);
     method public static float intBitsToFloat(int);
     method public int intValue();
+    method public static boolean isFinite(float);
     method public static boolean isInfinite(float);
     method public boolean isInfinite();
     method public static boolean isNaN(float);
     method public boolean isNaN();
     method public long longValue();
+    method public static float max(float, float);
+    method public static float min(float, float);
     method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+    method public static float sum(float, float);
     method public static java.lang.String toHexString(float);
     method public static java.lang.String toString(float);
     method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Float valueOf(float);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_EXPONENT = 127; // 0x7f
     field public static final float MAX_VALUE = 3.4028235E38f;
     field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -50581,10 +50878,13 @@
     method public static java.lang.Integer getInteger(java.lang.String);
     method public static java.lang.Integer getInteger(java.lang.String, int);
     method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+    method public static int hashCode(int);
     method public static int highestOneBit(int);
     method public int intValue();
     method public long longValue();
     method public static int lowestOneBit(int);
+    method public static int max(int, int);
+    method public static int min(int, int);
     method public static int numberOfLeadingZeros(int);
     method public static int numberOfTrailingZeros(int);
     method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50594,6 +50894,7 @@
     method public static int rotateLeft(int, int);
     method public static int rotateRight(int, int);
     method public static int signum(int);
+    method public static int sum(int, int);
     method public static java.lang.String toBinaryString(int);
     method public static java.lang.String toHexString(int);
     method public static java.lang.String toOctalString(int);
@@ -50602,6 +50903,7 @@
     method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(int);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
     field public static final int MIN_VALUE = -2147483648; // 0x80000000
     field public static final int SIZE = 32; // 0x20
@@ -50621,7 +50923,9 @@
   }
 
   public abstract interface Iterable {
+    method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
+    method public default java.util.Spliterator<T> spliterator();
   }
 
   public class LinkageError extends java.lang.Error {
@@ -50642,10 +50946,13 @@
     method public static java.lang.Long getLong(java.lang.String);
     method public static java.lang.Long getLong(java.lang.String, long);
     method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+    method public static int hashCode(long);
     method public static long highestOneBit(long);
     method public int intValue();
     method public long longValue();
     method public static long lowestOneBit(long);
+    method public static long max(long, long);
+    method public static long min(long, long);
     method public static int numberOfLeadingZeros(long);
     method public static int numberOfTrailingZeros(long);
     method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50655,6 +50962,7 @@
     method public static long rotateLeft(long, int);
     method public static long rotateRight(long, int);
     method public static int signum(long);
+    method public static long sum(long, long);
     method public static java.lang.String toBinaryString(long);
     method public static java.lang.String toHexString(long);
     method public static java.lang.String toOctalString(long);
@@ -50663,6 +50971,7 @@
     method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(long);
+    field public static final int BYTES = 8; // 0x8
     field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
     field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
     field public static final int SIZE = 64; // 0x40
@@ -50842,41 +51151,11 @@
     method public java.io.File directory();
     method public java.lang.ProcessBuilder directory(java.io.File);
     method public java.util.Map<java.lang.String, java.lang.String> environment();
-    method public java.lang.ProcessBuilder inheritIO();
-    method public java.lang.ProcessBuilder redirectError(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectError(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectError();
     method public boolean redirectErrorStream();
     method public java.lang.ProcessBuilder redirectErrorStream(boolean);
-    method public java.lang.ProcessBuilder redirectInput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectInput(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectInput();
-    method public java.lang.ProcessBuilder redirectOutput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectOutput(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectOutput();
     method public java.lang.Process start() throws java.io.IOException;
   }
 
-  public static abstract class ProcessBuilder.Redirect {
-    method public static java.lang.ProcessBuilder.Redirect appendTo(java.io.File);
-    method public java.io.File file();
-    method public static java.lang.ProcessBuilder.Redirect from(java.io.File);
-    method public static java.lang.ProcessBuilder.Redirect to(java.io.File);
-    method public abstract java.lang.ProcessBuilder.Redirect.Type type();
-    field public static final java.lang.ProcessBuilder.Redirect INHERIT;
-    field public static final java.lang.ProcessBuilder.Redirect PIPE;
-  }
-
-  public static final class ProcessBuilder.Redirect.Type extends java.lang.Enum {
-    method public static java.lang.ProcessBuilder.Redirect.Type valueOf(java.lang.String);
-    method public static final java.lang.ProcessBuilder.Redirect.Type[] values();
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type APPEND;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type INHERIT;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type PIPE;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type READ;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type WRITE;
-  }
-
   public abstract interface Readable {
     method public abstract int read(java.nio.CharBuffer) throws java.io.IOException;
   }
@@ -50996,6 +51275,7 @@
     method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(short);
     method public int intValue();
     method public long longValue();
     method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51005,6 +51285,7 @@
     method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(short);
+    field public static final int BYTES = 2; // 0x2
     field public static final short MAX_VALUE = 32767; // 0x7fff
     field public static final short MIN_VALUE = -32768; // 0xffff8000
     field public static final int SIZE = 16; // 0x10
@@ -52528,9 +52809,7 @@
 
   public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
     ctor public SocketPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53612,9 +53891,7 @@
   public final class AllPermission extends java.security.Permission {
     ctor public AllPermission();
     ctor public AllPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53628,9 +53905,7 @@
   public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
     ctor public BasicPermission(java.lang.String);
     ctor public BasicPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54008,10 +54283,8 @@
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
-    method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getActions();
     method public final java.lang.String getName();
-    method public abstract int hashCode();
     method public abstract boolean implies(java.security.Permission);
     method public java.security.PermissionCollection newPermissionCollection();
   }
@@ -54096,6 +54369,7 @@
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
@@ -54268,13 +54542,11 @@
 
   public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
     ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getUnresolvedActions();
     method public java.security.cert.Certificate[] getUnresolvedCerts();
     method public java.lang.String getUnresolvedName();
     method public java.lang.String getUnresolvedType();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54332,8 +54604,6 @@
   }
 
   public abstract interface Permission {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.lang.String toString();
   }
 
 }
@@ -57037,6 +57307,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
@@ -57045,8 +57316,13 @@
     ctor public ArrayList(java.util.Collection<? extends E>);
     method public java.lang.Object clone();
     method public void ensureCapacity(int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
+    method public boolean removeIf(java.util.function.Predicate<? super E>);
+    method public void replaceAll(java.util.function.UnaryOperator<E>);
     method public int size();
+    method public void sort(java.util.Comparator<? super E>);
+    method public java.util.Spliterator<E> spliterator();
     method public void trimToSize();
   }
 
@@ -57129,6 +57405,32 @@
     method public static int hashCode(float[]);
     method public static int hashCode(double[]);
     method public static int hashCode(java.lang.Object[]);
+    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
+    method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
+    method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
+    method public static void parallelSort(byte[]);
+    method public static void parallelSort(byte[], int, int);
+    method public static void parallelSort(char[]);
+    method public static void parallelSort(char[], int, int);
+    method public static void parallelSort(short[]);
+    method public static void parallelSort(short[], int, int);
+    method public static void parallelSort(int[]);
+    method public static void parallelSort(int[], int, int);
+    method public static void parallelSort(long[]);
+    method public static void parallelSort(long[], int, int);
+    method public static void parallelSort(float[]);
+    method public static void parallelSort(float[], int, int);
+    method public static void parallelSort(double[]);
+    method public static void parallelSort(double[], int, int);
+    method public static void parallelSort(T[]);
+    method public static void parallelSort(T[], int, int);
+    method public static void parallelSort(T[], java.util.Comparator<? super T>);
+    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static void setAll(int[], java.util.function.IntUnaryOperator);
+    method public static void setAll(long[], java.util.function.IntToLongFunction);
+    method public static void setAll(double[], java.util.function.IntToDoubleFunction);
     method public static void sort(int[]);
     method public static void sort(int[], int, int);
     method public static void sort(long[]);
@@ -57147,6 +57449,22 @@
     method public static void sort(java.lang.Object[], int, int);
     method public static void sort(T[], java.util.Comparator<? super T>);
     method public static void sort(T[], int, int, java.util.Comparator<? super T>);
+    method public static java.util.Spliterator<T> spliterator(T[]);
+    method public static java.util.Spliterator<T> spliterator(T[], int, int);
+    method public static java.util.Spliterator.OfInt spliterator(int[]);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
+    method public static java.util.Spliterator.OfLong spliterator(long[]);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[]);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
+    method public static java.util.stream.Stream<T> stream(T[]);
+    method public static java.util.stream.Stream<T> stream(T[], int, int);
+    method public static java.util.stream.IntStream stream(int[]);
+    method public static java.util.stream.IntStream stream(int[], int, int);
+    method public static java.util.stream.LongStream stream(long[]);
+    method public static java.util.stream.LongStream stream(long[], int, int);
+    method public static java.util.stream.DoubleStream stream(double[]);
+    method public static java.util.stream.DoubleStream stream(double[], int, int);
     method public static java.lang.String toString(long[]);
     method public static java.lang.String toString(int[]);
     method public static java.lang.String toString(short[]);
@@ -57306,10 +57624,13 @@
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
     method public abstract java.util.Iterator<E> iterator();
+    method public default java.util.stream.Stream<E> parallelStream();
     method public abstract boolean remove(java.lang.Object);
     method public abstract boolean removeAll(java.util.Collection<?>);
+    method public default boolean removeIf(java.util.function.Predicate<? super E>);
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
+    method public default java.util.stream.Stream<E> stream();
     method public abstract java.lang.Object[] toArray();
     method public abstract T[] toArray(T[]);
   }
@@ -57377,7 +57698,23 @@
 
   public abstract interface Comparator {
     method public abstract int compare(T, T);
+    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
     method public abstract boolean equals(java.lang.Object);
+    method public static java.util.Comparator<T> naturalOrder();
+    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
+    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
+    method public static java.util.Comparator<T> reverseOrder();
+    method public default java.util.Comparator<T> reversed();
+    method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
+    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
+    method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
+    method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
   }
 
   public class ConcurrentModificationException extends java.lang.RuntimeException {
@@ -57474,6 +57811,17 @@
     method public abstract int size();
   }
 
+  public class DoubleSummaryStatistics implements java.util.function.DoubleConsumer {
+    ctor public DoubleSummaryStatistics();
+    method public void accept(double);
+    method public void combine(java.util.DoubleSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final double getMax();
+    method public final double getMin();
+    method public final double getSum();
+  }
+
   public class DuplicateFormatFlagsException extends java.util.IllegalFormatException {
     ctor public DuplicateFormatFlagsException(java.lang.String);
     method public java.lang.String getFlags();
@@ -57608,6 +57956,8 @@
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public boolean replace(K, V, V);
   }
 
   public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -57618,6 +57968,7 @@
     method public java.lang.Object clone();
     method public java.util.Iterator<E> iterator();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
@@ -57627,19 +57978,29 @@
     ctor public Hashtable(java.util.Map<? extends K, ? extends V>);
     method public synchronized void clear();
     method public synchronized java.lang.Object clone();
+    method public synchronized V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public synchronized V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public synchronized V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public synchronized boolean contains(java.lang.Object);
     method public synchronized boolean containsKey(java.lang.Object);
     method public boolean containsValue(java.lang.Object);
     method public synchronized java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public synchronized V get(java.lang.Object);
+    method public synchronized V getOrDefault(java.lang.Object, V);
     method public synchronized boolean isEmpty();
     method public java.util.Set<K> keySet();
     method public synchronized java.util.Enumeration<K> keys();
+    method public synchronized V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public synchronized V put(K, V);
     method public synchronized void putAll(java.util.Map<? extends K, ? extends V>);
+    method public synchronized V putIfAbsent(K, V);
     method protected void rehash();
     method public synchronized V remove(java.lang.Object);
+    method public synchronized boolean remove(java.lang.Object, java.lang.Object);
+    method public synchronized boolean replace(K, V, V);
+    method public synchronized V replace(K, V);
     method public synchronized int size();
     method public java.util.Collection<V> values();
   }
@@ -57650,6 +58011,7 @@
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -57693,15 +58055,27 @@
     ctor public InputMismatchException(java.lang.String);
   }
 
+  public class IntSummaryStatistics implements java.util.function.IntConsumer {
+    ctor public IntSummaryStatistics();
+    method public void accept(int);
+    method public void combine(java.util.IntSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final int getMax();
+    method public final int getMin();
+    method public final long getSum();
+  }
+
   public class InvalidPropertiesFormatException extends java.io.IOException {
     ctor public InvalidPropertiesFormatException(java.lang.Throwable);
     ctor public InvalidPropertiesFormatException(java.lang.String);
   }
 
   public abstract interface Iterator {
+    method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
-    method public abstract void remove();
+    method public default void remove();
   }
 
   public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -57748,6 +58122,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public abstract interface List implements java.util.Collection {
@@ -57770,9 +58145,11 @@
     method public abstract boolean remove(java.lang.Object);
     method public abstract E remove(int);
     method public abstract boolean removeAll(java.util.Collection<?>);
+    method public default void replaceAll(java.util.function.UnaryOperator<E>);
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract E set(int, E);
     method public abstract int size();
+    method public default void sort(java.util.Comparator<? super E>);
     method public abstract java.util.List<E> subList(int, int);
     method public abstract java.lang.Object[] toArray();
     method public abstract T[] toArray(T[]);
@@ -57883,24 +58260,51 @@
     enum_constant public static final java.util.Locale.Category FORMAT;
   }
 
+  public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
+    ctor public LongSummaryStatistics();
+    method public void accept(int);
+    method public void accept(long);
+    method public void combine(java.util.LongSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final long getMax();
+    method public final long getMin();
+    method public final long getSum();
+  }
+
   public abstract interface Map {
     method public abstract void clear();
+    method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public default V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public abstract boolean containsKey(java.lang.Object);
     method public abstract boolean containsValue(java.lang.Object);
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract boolean equals(java.lang.Object);
+    method public default void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public abstract V get(java.lang.Object);
+    method public default V getOrDefault(java.lang.Object, V);
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
     method public abstract java.util.Set<K> keySet();
+    method public default V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public abstract V put(K, V);
     method public abstract void putAll(java.util.Map<? extends K, ? extends V>);
+    method public default V putIfAbsent(K, V);
     method public abstract V remove(java.lang.Object);
+    method public default boolean remove(java.lang.Object, java.lang.Object);
+    method public default boolean replace(K, V, V);
+    method public default V replace(K, V);
+    method public default void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public abstract int size();
     method public abstract java.util.Collection<V> values();
   }
 
   public static abstract interface Map.Entry {
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
     method public abstract boolean equals(java.lang.Object);
     method public abstract K getKey();
     method public abstract V getValue();
@@ -58003,9 +58407,83 @@
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
+  public final class Optional {
+    method public static java.util.Optional<T> empty();
+    method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public T get();
+    method public void ifPresent(java.util.function.Consumer<? super T>);
+    method public boolean isPresent();
+    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Optional<T> of(T);
+    method public static java.util.Optional<T> ofNullable(T);
+    method public T orElse(T);
+    method public T orElseGet(java.util.function.Supplier<? extends T>);
+    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalDouble {
+    method public static java.util.OptionalDouble empty();
+    method public double getAsDouble();
+    method public void ifPresent(java.util.function.DoubleConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalDouble of(double);
+    method public double orElse(double);
+    method public double orElseGet(java.util.function.DoubleSupplier);
+    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalInt {
+    method public static java.util.OptionalInt empty();
+    method public int getAsInt();
+    method public void ifPresent(java.util.function.IntConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalInt of(int);
+    method public int orElse(int);
+    method public int orElseGet(java.util.function.IntSupplier);
+    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalLong {
+    method public static java.util.OptionalLong empty();
+    method public long getAsLong();
+    method public void ifPresent(java.util.function.LongConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalLong of(long);
+    method public long orElse(long);
+    method public long orElseGet(java.util.function.LongSupplier);
+    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public abstract interface PrimitiveIterator implements java.util.Iterator {
+    method public abstract void forEachRemaining(T_CONS);
+  }
+
+  public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public default java.lang.Double next();
+    method public abstract double nextDouble();
+  }
+
+  public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public default java.lang.Integer next();
+    method public abstract int nextInt();
+  }
+
+  public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public default java.lang.Long next();
+    method public abstract long nextLong();
+  }
+
   public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
+    ctor public PriorityQueue(java.util.Comparator<? super E>);
     ctor public PriorityQueue(int, java.util.Comparator<? super E>);
     ctor public PriorityQueue(java.util.Collection<? extends E>);
     ctor public PriorityQueue(java.util.PriorityQueue<? extends E>);
@@ -58016,6 +58494,7 @@
     method public E peek();
     method public E poll();
     method public int size();
+    method public final java.util.Spliterator<E> spliterator();
   }
 
   public class Properties extends java.util.Hashtable {
@@ -58174,7 +58653,6 @@
     method public short nextShort();
     method public short nextShort(int);
     method public int radix();
-    method public void remove();
     method public java.util.Scanner reset();
     method public java.util.Scanner skip(java.util.regex.Pattern);
     method public java.util.Scanner skip(java.lang.String);
@@ -58259,6 +58737,139 @@
     method public abstract java.util.SortedSet<E> tailSet(E);
   }
 
+  public abstract interface Spliterator {
+    method public abstract int characteristics();
+    method public abstract long estimateSize();
+    method public default void forEachRemaining(java.util.function.Consumer<? super T>);
+    method public default java.util.Comparator<? super T> getComparator();
+    method public default long getExactSizeIfKnown();
+    method public default boolean hasCharacteristics(int);
+    method public abstract boolean tryAdvance(java.util.function.Consumer<? super T>);
+    method public abstract java.util.Spliterator<T> trySplit();
+    field public static final int CONCURRENT = 4096; // 0x1000
+    field public static final int DISTINCT = 1; // 0x1
+    field public static final int IMMUTABLE = 1024; // 0x400
+    field public static final int NONNULL = 256; // 0x100
+    field public static final int ORDERED = 16; // 0x10
+    field public static final int SIZED = 64; // 0x40
+    field public static final int SORTED = 4; // 0x4
+    field public static final int SUBSIZED = 16384; // 0x4000
+  }
+
+  public static abstract interface Spliterator.OfDouble implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public abstract boolean tryAdvance(java.util.function.DoubleConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Double>);
+    method public abstract java.util.Spliterator.OfDouble trySplit();
+  }
+
+  public static abstract interface Spliterator.OfInt implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public abstract boolean tryAdvance(java.util.function.IntConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Integer>);
+    method public abstract java.util.Spliterator.OfInt trySplit();
+  }
+
+  public static abstract interface Spliterator.OfLong implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public abstract boolean tryAdvance(java.util.function.LongConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Long>);
+    method public abstract java.util.Spliterator.OfLong trySplit();
+  }
+
+  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
+    method public default void forEachRemaining(T_CONS);
+    method public abstract boolean tryAdvance(T_CONS);
+    method public abstract T_SPLITR trySplit();
+  }
+
+  public final class Spliterators {
+    method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
+    method public static java.util.Spliterator.OfInt emptyIntSpliterator();
+    method public static java.util.Spliterator.OfLong emptyLongSpliterator();
+    method public static java.util.Spliterator<T> emptySpliterator();
+    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
+    method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
+    method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
+    method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
+    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
+    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
+    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
+    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
+    method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
+    method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
+    method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
+    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
+    method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
+    method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
+    method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
+  }
+
+  public static abstract class Spliterators.AbstractDoubleSpliterator implements java.util.Spliterator.OfDouble {
+    ctor protected Spliterators.AbstractDoubleSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfDouble trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractIntSpliterator implements java.util.Spliterator.OfInt {
+    ctor protected Spliterators.AbstractIntSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfInt trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractLongSpliterator implements java.util.Spliterator.OfLong {
+    ctor protected Spliterators.AbstractLongSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfLong trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
+    ctor protected Spliterators.AbstractSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator<T> trySplit();
+  }
+
+  public final class SplittableRandom {
+    ctor public SplittableRandom(long);
+    ctor public SplittableRandom();
+    method public java.util.stream.DoubleStream doubles(long);
+    method public java.util.stream.DoubleStream doubles();
+    method public java.util.stream.DoubleStream doubles(long, double, double);
+    method public java.util.stream.DoubleStream doubles(double, double);
+    method public java.util.stream.IntStream ints(long);
+    method public java.util.stream.IntStream ints();
+    method public java.util.stream.IntStream ints(long, int, int);
+    method public java.util.stream.IntStream ints(int, int);
+    method public java.util.stream.LongStream longs(long);
+    method public java.util.stream.LongStream longs();
+    method public java.util.stream.LongStream longs(long, long, long);
+    method public java.util.stream.LongStream longs(long, long);
+    method public boolean nextBoolean();
+    method public double nextDouble();
+    method public double nextDouble(double);
+    method public double nextDouble(double, double);
+    method public int nextInt();
+    method public int nextInt(int);
+    method public int nextInt(int, int);
+    method public long nextLong();
+    method public long nextLong(long);
+    method public long nextLong(long, long);
+    method public java.util.SplittableRandom split();
+  }
+
   public class Stack extends java.util.Vector {
     ctor public Stack();
     method public boolean empty();
@@ -58268,6 +58879,15 @@
     method public synchronized int search(java.lang.Object);
   }
 
+  public final class StringJoiner {
+    ctor public StringJoiner(java.lang.CharSequence);
+    ctor public StringJoiner(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
+    method public java.util.StringJoiner add(java.lang.CharSequence);
+    method public int length();
+    method public java.util.StringJoiner merge(java.util.StringJoiner);
+    method public java.util.StringJoiner setEmptyValue(java.lang.CharSequence);
+  }
+
   public class StringTokenizer implements java.util.Enumeration {
     ctor public StringTokenizer(java.lang.String, java.lang.String, boolean);
     ctor public StringTokenizer(java.lang.String, java.lang.String);
@@ -58350,6 +58970,7 @@
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public java.util.NavigableMap<K, V> headMap(K, boolean);
     method public java.util.SortedMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -58388,6 +59009,7 @@
     method public E pollFirst();
     method public E pollLast();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
     method public java.util.SortedSet<E> subSet(E, E);
     method public java.util.NavigableSet<E> tailSet(E, boolean);
@@ -58432,6 +59054,7 @@
     method public java.util.Enumeration<E> elements();
     method public synchronized void ensureCapacity(int);
     method public synchronized E firstElement();
+    method public synchronized void forEach(java.util.function.Consumer<? super E>);
     method public synchronized E get(int);
     method public synchronized int indexOf(java.lang.Object, int);
     method public synchronized void insertElementAt(E, int);
@@ -58440,9 +59063,13 @@
     method public synchronized void removeAllElements();
     method public synchronized boolean removeElement(java.lang.Object);
     method public synchronized void removeElementAt(int);
+    method public synchronized boolean removeIf(java.util.function.Predicate<? super E>);
+    method public synchronized void replaceAll(java.util.function.UnaryOperator<E>);
     method public synchronized void setElementAt(E, int);
     method public synchronized void setSize(int);
     method public synchronized int size();
+    method public synchronized void sort(java.util.Comparator<? super E>);
+    method public java.util.Spliterator<E> spliterator();
     method public synchronized void trimToSize();
     field protected int capacityIncrement;
     field protected int elementCount;
@@ -58455,6 +59082,7 @@
     ctor public WeakHashMap();
     ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
 }
@@ -58489,6 +59117,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -58552,6 +59181,78 @@
     ctor public CancellationException(java.lang.String);
   }
 
+  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
+    ctor public CompletableFuture();
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
+    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public boolean cancel(boolean);
+    method public boolean complete(T);
+    method public boolean completeExceptionally(java.lang.Throwable);
+    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
+    method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
+    method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public T getNow(T);
+    method public int getNumberOfDependents();
+    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public boolean isCancelled();
+    method public boolean isCompletedExceptionally();
+    method public boolean isDone();
+    method public T join();
+    method public void obtrudeException(java.lang.Throwable);
+    method public void obtrudeValue(T);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
+    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<T> toCompletableFuture();
+    method public java.util.concurrent.CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+  }
+
+  public static abstract interface CompletableFuture.AsynchronousCompletionTask {
+  }
+
+  public class CompletionException extends java.lang.RuntimeException {
+    ctor protected CompletionException();
+    ctor protected CompletionException(java.lang.String);
+    ctor public CompletionException(java.lang.String, java.lang.Throwable);
+    ctor public CompletionException(java.lang.Throwable);
+  }
+
   public abstract interface CompletionService {
     method public abstract java.util.concurrent.Future<V> poll();
     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
@@ -58560,20 +59261,130 @@
     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
+  public abstract interface CompletionStage {
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
+    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletableFuture<T> toCompletableFuture();
+    method public abstract java.util.concurrent.CompletionStage<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+  }
+
   public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
     ctor public ConcurrentHashMap();
     ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
     ctor public ConcurrentHashMap(int, float);
     ctor public ConcurrentHashMap(int, float, int);
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public boolean contains(java.lang.Object);
     method public java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
+    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
+    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachKey(long, java.util.function.Consumer<? super K>);
+    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachValue(long, java.util.function.Consumer<? super V>);
+    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public V getOrDefault(java.lang.Object, V);
+    method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
     method public java.util.Enumeration<K> keys();
+    method public long mappingCount();
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
+    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
     method public V putIfAbsent(K, V);
+    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
+    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
+    method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
+    method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
+    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
+    method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
+    method public double reduceToDouble(long, java.util.function.ToDoubleBiFunction<? super K, ? super V>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
+    method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
+    method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
+    method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
     method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
     method public V replace(K, V);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
+    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
+    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
+    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
+  }
+
+   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
+    method public final void clear();
+    method public abstract boolean contains(java.lang.Object);
+    method public final boolean containsAll(java.util.Collection<?>);
+    method public java.util.concurrent.ConcurrentHashMap<K, V> getMap();
+    method public final boolean isEmpty();
+    method public abstract java.util.Iterator<E> iterator();
+    method public abstract boolean remove(java.lang.Object);
+    method public final boolean removeAll(java.util.Collection<?>);
+    method public final boolean retainAll(java.util.Collection<?>);
+    method public final int size();
+    method public final java.lang.Object[] toArray();
+    method public final T[] toArray(T[]);
+    method public final java.lang.String toString();
+  }
+
+  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
+    method public boolean add(K);
+    method public boolean addAll(java.util.Collection<? extends K>);
+    method public boolean contains(java.lang.Object);
+    method public void forEach(java.util.function.Consumer<? super K>);
+    method public V getMappedValue();
+    method public java.util.Iterator<K> iterator();
+    method public boolean remove(java.lang.Object);
+    method public java.util.Spliterator<K> spliterator();
   }
 
   public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
@@ -58603,6 +59414,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
@@ -58613,6 +59425,7 @@
     method public E peek();
     method public E poll();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public abstract interface ConcurrentMap implements java.util.Map {
@@ -58644,6 +59457,9 @@
     method public K ceilingKey(K);
     method public java.util.concurrent.ConcurrentSkipListMap<K, V> clone();
     method public java.util.Comparator<? super K> comparator();
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableSet<K> descendingKeySet();
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
@@ -58651,6 +59467,8 @@
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public V getOrDefault(java.lang.Object, V);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -58659,6 +59477,7 @@
     method public K lastKey();
     method public java.util.Map.Entry<K, V> lowerEntry(K);
     method public K lowerKey(K);
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
@@ -58666,6 +59485,7 @@
     method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
     method public V replace(K, V);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, K);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K, boolean);
@@ -58693,6 +59513,7 @@
     method public E pollFirst();
     method public E pollLast();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
     method public java.util.NavigableSet<E> subSet(E, E);
     method public java.util.NavigableSet<E> tailSet(E, boolean);
@@ -58713,6 +59534,7 @@
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
     method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
@@ -58736,8 +59558,11 @@
   public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
     ctor public CopyOnWriteArraySet();
     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
+    method public boolean removeIf(java.util.function.Predicate<? super E>);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class CountDownLatch {
@@ -58748,6 +59573,32 @@
     method public long getCount();
   }
 
+  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
+    ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
+    ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
+    ctor protected CountedCompleter();
+    method public final void addToPendingCount(int);
+    method public final boolean compareAndSetPendingCount(int, int);
+    method public void complete(T);
+    method public abstract void compute();
+    method public final int decrementPendingCountUnlessZero();
+    method protected final boolean exec();
+    method public final java.util.concurrent.CountedCompleter<?> firstComplete();
+    method public final java.util.concurrent.CountedCompleter<?> getCompleter();
+    method public final int getPendingCount();
+    method public T getRawResult();
+    method public final java.util.concurrent.CountedCompleter<?> getRoot();
+    method public final void helpComplete(int);
+    method public final java.util.concurrent.CountedCompleter<?> nextComplete();
+    method public void onCompletion(java.util.concurrent.CountedCompleter<?>);
+    method public boolean onExceptionalCompletion(java.lang.Throwable, java.util.concurrent.CountedCompleter<?>);
+    method public final void propagateCompletion();
+    method public final void quietlyCompleteRoot();
+    method public final void setPendingCount(int);
+    method protected void setRawResult(T);
+    method public final void tryComplete();
+  }
+
   public class CyclicBarrier {
     ctor public CyclicBarrier(int, java.lang.Runnable);
     ctor public CyclicBarrier(int);
@@ -58838,6 +59689,8 @@
     method public static java.util.concurrent.ExecutorService newSingleThreadExecutor(java.util.concurrent.ThreadFactory);
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor();
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
+    method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
+    method public static java.util.concurrent.ExecutorService newWorkStealingPool();
     method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
@@ -58851,11 +59704,13 @@
     ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
     method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public static java.util.concurrent.ForkJoinPool commonPool();
     method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>);
     method public void execute(java.util.concurrent.ForkJoinTask<?>);
     method public void execute(java.lang.Runnable);
     method public int getActiveThreadCount();
     method public boolean getAsyncMode();
+    method public static int getCommonPoolParallelism();
     method public java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory getFactory();
     method public int getParallelism();
     method public int getPoolSize();
@@ -58893,6 +59748,7 @@
     method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
     method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
     method public boolean cancel(boolean);
+    method public final boolean compareAndSetForkJoinTaskTag(short, short);
     method public void complete(V);
     method public void completeExceptionally(java.lang.Throwable);
     method protected abstract boolean exec();
@@ -58900,6 +59756,7 @@
     method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public final java.lang.Throwable getException();
+    method public final short getForkJoinTaskTag();
     method public static java.util.concurrent.ForkJoinPool getPool();
     method public static int getQueuedTaskCount();
     method public abstract V getRawResult();
@@ -58918,9 +59775,11 @@
     method protected static java.util.concurrent.ForkJoinTask<?> peekNextLocalTask();
     method protected static java.util.concurrent.ForkJoinTask<?> pollNextLocalTask();
     method protected static java.util.concurrent.ForkJoinTask<?> pollTask();
+    method public final void quietlyComplete();
     method public final void quietlyInvoke();
     method public final void quietlyJoin();
     method public void reinitialize();
+    method public final short setForkJoinTaskTag(short);
     method protected abstract void setRawResult(V);
     method public boolean tryUnfork();
   }
@@ -58994,6 +59853,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
     method public E takeFirst() throws java.lang.InterruptedException;
     method public E takeLast() throws java.lang.InterruptedException;
@@ -59014,6 +59874,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -59033,6 +59894,7 @@
     method public void put(E);
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
     method public void transfer(E) throws java.lang.InterruptedException;
     method public boolean tryTransfer(E);
@@ -59080,6 +59942,7 @@
     method public void put(E);
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -59183,6 +60046,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -59192,6 +60056,18 @@
 
   public class ThreadLocalRandom extends java.util.Random {
     method public static java.util.concurrent.ThreadLocalRandom current();
+    method public java.util.stream.DoubleStream doubles(long);
+    method public java.util.stream.DoubleStream doubles();
+    method public java.util.stream.DoubleStream doubles(long, double, double);
+    method public java.util.stream.DoubleStream doubles(double, double);
+    method public java.util.stream.IntStream ints(long);
+    method public java.util.stream.IntStream ints();
+    method public java.util.stream.IntStream ints(long, int, int);
+    method public java.util.stream.IntStream ints(int, int);
+    method public java.util.stream.LongStream longs(long);
+    method public java.util.stream.LongStream longs();
+    method public java.util.stream.LongStream longs(long, long, long);
+    method public java.util.stream.LongStream longs(long, long);
     method public double nextDouble(double);
     method public double nextDouble(double, double);
     method public int nextInt(int, int);
@@ -59312,112 +60188,136 @@
   public class AtomicInteger extends java.lang.Number implements java.io.Serializable {
     ctor public AtomicInteger(int);
     ctor public AtomicInteger();
+    method public final int accumulateAndGet(int, java.util.function.IntBinaryOperator);
     method public final int addAndGet(int);
     method public final boolean compareAndSet(int, int);
     method public final int decrementAndGet();
     method public double doubleValue();
     method public float floatValue();
     method public final int get();
+    method public final int getAndAccumulate(int, java.util.function.IntBinaryOperator);
     method public final int getAndAdd(int);
     method public final int getAndDecrement();
     method public final int getAndIncrement();
     method public final int getAndSet(int);
+    method public final int getAndUpdate(java.util.function.IntUnaryOperator);
     method public final int incrementAndGet();
     method public int intValue();
     method public final void lazySet(int);
     method public long longValue();
     method public final void set(int);
+    method public final int updateAndGet(java.util.function.IntUnaryOperator);
     method public final boolean weakCompareAndSet(int, int);
   }
 
   public class AtomicIntegerArray implements java.io.Serializable {
     ctor public AtomicIntegerArray(int);
     ctor public AtomicIntegerArray(int[]);
+    method public final int accumulateAndGet(int, int, java.util.function.IntBinaryOperator);
     method public final int addAndGet(int, int);
     method public final boolean compareAndSet(int, int, int);
     method public final int decrementAndGet(int);
     method public final int get(int);
+    method public final int getAndAccumulate(int, int, java.util.function.IntBinaryOperator);
     method public final int getAndAdd(int, int);
     method public final int getAndDecrement(int);
     method public final int getAndIncrement(int);
     method public final int getAndSet(int, int);
+    method public final int getAndUpdate(int, java.util.function.IntUnaryOperator);
     method public final int incrementAndGet(int);
     method public final void lazySet(int, int);
     method public final int length();
     method public final void set(int, int);
+    method public final int updateAndGet(int, java.util.function.IntUnaryOperator);
     method public final boolean weakCompareAndSet(int, int, int);
   }
 
   public abstract class AtomicIntegerFieldUpdater {
     ctor protected AtomicIntegerFieldUpdater();
+    method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
     method public int addAndGet(T, int);
     method public abstract boolean compareAndSet(T, int, int);
     method public int decrementAndGet(T);
     method public abstract int get(T);
+    method public final int getAndAccumulate(T, int, java.util.function.IntBinaryOperator);
     method public int getAndAdd(T, int);
     method public int getAndDecrement(T);
     method public int getAndIncrement(T);
     method public int getAndSet(T, int);
+    method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
     method public int incrementAndGet(T);
     method public abstract void lazySet(T, int);
     method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, int);
+    method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, int, int);
   }
 
   public class AtomicLong extends java.lang.Number implements java.io.Serializable {
     ctor public AtomicLong(long);
     ctor public AtomicLong();
+    method public final long accumulateAndGet(long, java.util.function.LongBinaryOperator);
     method public final long addAndGet(long);
     method public final boolean compareAndSet(long, long);
     method public final long decrementAndGet();
     method public double doubleValue();
     method public float floatValue();
     method public final long get();
+    method public final long getAndAccumulate(long, java.util.function.LongBinaryOperator);
     method public final long getAndAdd(long);
     method public final long getAndDecrement();
     method public final long getAndIncrement();
     method public final long getAndSet(long);
+    method public final long getAndUpdate(java.util.function.LongUnaryOperator);
     method public final long incrementAndGet();
     method public int intValue();
     method public final void lazySet(long);
     method public long longValue();
     method public final void set(long);
+    method public final long updateAndGet(java.util.function.LongUnaryOperator);
     method public final boolean weakCompareAndSet(long, long);
   }
 
   public class AtomicLongArray implements java.io.Serializable {
     ctor public AtomicLongArray(int);
     ctor public AtomicLongArray(long[]);
+    method public final long accumulateAndGet(int, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(int, long);
     method public final boolean compareAndSet(int, long, long);
     method public final long decrementAndGet(int);
     method public final long get(int);
+    method public final long getAndAccumulate(int, long, java.util.function.LongBinaryOperator);
     method public final long getAndAdd(int, long);
     method public final long getAndDecrement(int);
     method public final long getAndIncrement(int);
     method public final long getAndSet(int, long);
+    method public final long getAndUpdate(int, java.util.function.LongUnaryOperator);
     method public final long incrementAndGet(int);
     method public final void lazySet(int, long);
     method public final int length();
     method public final void set(int, long);
+    method public final long updateAndGet(int, java.util.function.LongUnaryOperator);
     method public final boolean weakCompareAndSet(int, long, long);
   }
 
   public abstract class AtomicLongFieldUpdater {
     ctor protected AtomicLongFieldUpdater();
+    method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(T, long);
     method public abstract boolean compareAndSet(T, long, long);
     method public long decrementAndGet(T);
     method public abstract long get(T);
+    method public final long getAndAccumulate(T, long, java.util.function.LongBinaryOperator);
     method public long getAndAdd(T, long);
     method public long getAndDecrement(T);
     method public long getAndIncrement(T);
     method public long getAndSet(T, long);
+    method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
     method public long incrementAndGet(T);
     method public abstract void lazySet(T, long);
     method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, long);
+    method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, long, long);
   }
 
@@ -59435,34 +60335,46 @@
   public class AtomicReference implements java.io.Serializable {
     ctor public AtomicReference(V);
     ctor public AtomicReference();
+    method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
     method public final boolean compareAndSet(V, V);
     method public final V get();
+    method public final V getAndAccumulate(V, java.util.function.BinaryOperator<V>);
     method public final V getAndSet(V);
+    method public final V getAndUpdate(java.util.function.UnaryOperator<V>);
     method public final void lazySet(V);
     method public final void set(V);
+    method public final V updateAndGet(java.util.function.UnaryOperator<V>);
     method public final boolean weakCompareAndSet(V, V);
   }
 
   public class AtomicReferenceArray implements java.io.Serializable {
     ctor public AtomicReferenceArray(int);
     ctor public AtomicReferenceArray(E[]);
+    method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
     method public final boolean compareAndSet(int, E, E);
     method public final E get(int);
+    method public final E getAndAccumulate(int, E, java.util.function.BinaryOperator<E>);
     method public final E getAndSet(int, E);
+    method public final E getAndUpdate(int, java.util.function.UnaryOperator<E>);
     method public final void lazySet(int, E);
     method public final int length();
     method public final void set(int, E);
+    method public final E updateAndGet(int, java.util.function.UnaryOperator<E>);
     method public final boolean weakCompareAndSet(int, E, E);
   }
 
   public abstract class AtomicReferenceFieldUpdater {
     ctor protected AtomicReferenceFieldUpdater();
+    method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
     method public abstract boolean compareAndSet(T, V, V);
     method public abstract V get(T);
+    method public final V getAndAccumulate(T, V, java.util.function.BinaryOperator<V>);
     method public V getAndSet(T, V);
+    method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
     method public abstract void lazySet(T, V);
     method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
     method public abstract void set(T, V);
+    method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
     method public abstract boolean weakCompareAndSet(T, V, V);
   }
 
@@ -59477,6 +60389,59 @@
     method public boolean weakCompareAndSet(V, V, int, int);
   }
 
+  public class DoubleAccumulator extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public DoubleAccumulator(java.util.function.DoubleBinaryOperator, double);
+    method public void accumulate(double);
+    method public double doubleValue();
+    method public float floatValue();
+    method public double get();
+    method public double getThenReset();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+  }
+
+  public class DoubleAdder extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public DoubleAdder();
+    method public void add(double);
+    method public double doubleValue();
+    method public float floatValue();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+    method public double sum();
+    method public double sumThenReset();
+  }
+
+  public class LongAccumulator extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public LongAccumulator(java.util.function.LongBinaryOperator, long);
+    method public void accumulate(long);
+    method public double doubleValue();
+    method public float floatValue();
+    method public long get();
+    method public long getThenReset();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+  }
+
+  public class LongAdder extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public LongAdder();
+    method public void add(long);
+    method public void decrement();
+    method public double doubleValue();
+    method public float floatValue();
+    method public void increment();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+    method public long sum();
+    method public long sumThenReset();
+  }
+
+   abstract class Striped64 extends java.lang.Number {
+  }
+
 }
 
 package java.util.concurrent.locks {
@@ -59684,6 +60649,34 @@
     method public void unlock();
   }
 
+  public class StampedLock implements java.io.Serializable {
+    ctor public StampedLock();
+    method public java.util.concurrent.locks.Lock asReadLock();
+    method public java.util.concurrent.locks.ReadWriteLock asReadWriteLock();
+    method public java.util.concurrent.locks.Lock asWriteLock();
+    method public int getReadLockCount();
+    method public boolean isReadLocked();
+    method public boolean isWriteLocked();
+    method public long readLock();
+    method public long readLockInterruptibly() throws java.lang.InterruptedException;
+    method public long tryConvertToOptimisticRead(long);
+    method public long tryConvertToReadLock(long);
+    method public long tryConvertToWriteLock(long);
+    method public long tryOptimisticRead();
+    method public long tryReadLock();
+    method public long tryReadLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public boolean tryUnlockRead();
+    method public boolean tryUnlockWrite();
+    method public long tryWriteLock();
+    method public long tryWriteLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public void unlock(long);
+    method public void unlockRead(long);
+    method public void unlockWrite(long);
+    method public boolean validate(long);
+    method public long writeLock();
+    method public long writeLockInterruptibly() throws java.lang.InterruptedException;
+  }
+
 }
 
 package java.util.function {
@@ -60476,6 +61469,292 @@
 
 }
 
+package java.util.stream {
+
+  public abstract interface BaseStream implements java.lang.AutoCloseable {
+    method public abstract void close();
+    method public abstract boolean isParallel();
+    method public abstract java.util.Iterator<T> iterator();
+    method public abstract S onClose(java.lang.Runnable);
+    method public abstract S parallel();
+    method public abstract S sequential();
+    method public abstract java.util.Spliterator<T> spliterator();
+    method public abstract S unordered();
+  }
+
+  public abstract interface Collector {
+    method public abstract java.util.function.BiConsumer<A, T> accumulator();
+    method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
+    method public abstract java.util.function.BinaryOperator<A> combiner();
+    method public abstract java.util.function.Function<A, R> finisher();
+    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
+    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
+    method public abstract java.util.function.Supplier<A> supplier();
+  }
+
+  public static final class Collector.Characteristics extends java.lang.Enum {
+    method public static java.util.stream.Collector.Characteristics valueOf(java.lang.String);
+    method public static final java.util.stream.Collector.Characteristics[] values();
+    enum_constant public static final java.util.stream.Collector.Characteristics CONCURRENT;
+    enum_constant public static final java.util.stream.Collector.Characteristics IDENTITY_FINISH;
+    enum_constant public static final java.util.stream.Collector.Characteristics UNORDERED;
+  }
+
+  public final class Collectors {
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
+    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
+    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
+  }
+
+  public abstract interface DoubleStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.DoublePredicate);
+    method public abstract boolean anyMatch(java.util.function.DoublePredicate);
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Double> boxed();
+    method public static java.util.stream.DoubleStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
+    method public abstract long count();
+    method public abstract java.util.stream.DoubleStream distinct();
+    method public static java.util.stream.DoubleStream empty();
+    method public abstract java.util.stream.DoubleStream filter(java.util.function.DoublePredicate);
+    method public abstract java.util.OptionalDouble findAny();
+    method public abstract java.util.OptionalDouble findFirst();
+    method public abstract java.util.stream.DoubleStream flatMap(java.util.function.DoubleFunction<? extends java.util.stream.DoubleStream>);
+    method public abstract void forEach(java.util.function.DoubleConsumer);
+    method public abstract void forEachOrdered(java.util.function.DoubleConsumer);
+    method public static java.util.stream.DoubleStream generate(java.util.function.DoubleSupplier);
+    method public static java.util.stream.DoubleStream iterate(double, java.util.function.DoubleUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfDouble iterator();
+    method public abstract java.util.stream.DoubleStream limit(long);
+    method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
+    method public abstract java.util.OptionalDouble max();
+    method public abstract java.util.OptionalDouble min();
+    method public abstract boolean noneMatch(java.util.function.DoublePredicate);
+    method public static java.util.stream.DoubleStream of(double);
+    method public static java.util.stream.DoubleStream of(double...);
+    method public abstract java.util.stream.DoubleStream parallel();
+    method public abstract java.util.stream.DoubleStream peek(java.util.function.DoubleConsumer);
+    method public abstract double reduce(double, java.util.function.DoubleBinaryOperator);
+    method public abstract java.util.OptionalDouble reduce(java.util.function.DoubleBinaryOperator);
+    method public abstract java.util.stream.DoubleStream sequential();
+    method public abstract java.util.stream.DoubleStream skip(long);
+    method public abstract java.util.stream.DoubleStream sorted();
+    method public abstract java.util.Spliterator.OfDouble spliterator();
+    method public abstract double sum();
+    method public abstract java.util.DoubleSummaryStatistics summaryStatistics();
+    method public abstract double[] toArray();
+  }
+
+  public static abstract interface DoubleStream.Builder implements java.util.function.DoubleConsumer {
+    method public abstract void accept(double);
+    method public default java.util.stream.DoubleStream.Builder add(double);
+    method public abstract java.util.stream.DoubleStream build();
+  }
+
+  public abstract interface IntStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.IntPredicate);
+    method public abstract boolean anyMatch(java.util.function.IntPredicate);
+    method public abstract java.util.stream.DoubleStream asDoubleStream();
+    method public abstract java.util.stream.LongStream asLongStream();
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
+    method public static java.util.stream.IntStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
+    method public abstract long count();
+    method public abstract java.util.stream.IntStream distinct();
+    method public static java.util.stream.IntStream empty();
+    method public abstract java.util.stream.IntStream filter(java.util.function.IntPredicate);
+    method public abstract java.util.OptionalInt findAny();
+    method public abstract java.util.OptionalInt findFirst();
+    method public abstract java.util.stream.IntStream flatMap(java.util.function.IntFunction<? extends java.util.stream.IntStream>);
+    method public abstract void forEach(java.util.function.IntConsumer);
+    method public abstract void forEachOrdered(java.util.function.IntConsumer);
+    method public static java.util.stream.IntStream generate(java.util.function.IntSupplier);
+    method public static java.util.stream.IntStream iterate(int, java.util.function.IntUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfInt iterator();
+    method public abstract java.util.stream.IntStream limit(long);
+    method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
+    method public abstract java.util.OptionalInt max();
+    method public abstract java.util.OptionalInt min();
+    method public abstract boolean noneMatch(java.util.function.IntPredicate);
+    method public static java.util.stream.IntStream of(int);
+    method public static java.util.stream.IntStream of(int...);
+    method public abstract java.util.stream.IntStream parallel();
+    method public abstract java.util.stream.IntStream peek(java.util.function.IntConsumer);
+    method public static java.util.stream.IntStream range(int, int);
+    method public static java.util.stream.IntStream rangeClosed(int, int);
+    method public abstract int reduce(int, java.util.function.IntBinaryOperator);
+    method public abstract java.util.OptionalInt reduce(java.util.function.IntBinaryOperator);
+    method public abstract java.util.stream.IntStream sequential();
+    method public abstract java.util.stream.IntStream skip(long);
+    method public abstract java.util.stream.IntStream sorted();
+    method public abstract java.util.Spliterator.OfInt spliterator();
+    method public abstract int sum();
+    method public abstract java.util.IntSummaryStatistics summaryStatistics();
+    method public abstract int[] toArray();
+  }
+
+  public static abstract interface IntStream.Builder implements java.util.function.IntConsumer {
+    method public abstract void accept(int);
+    method public default java.util.stream.IntStream.Builder add(int);
+    method public abstract java.util.stream.IntStream build();
+  }
+
+  public abstract interface LongStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.LongPredicate);
+    method public abstract boolean anyMatch(java.util.function.LongPredicate);
+    method public abstract java.util.stream.DoubleStream asDoubleStream();
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Long> boxed();
+    method public static java.util.stream.LongStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
+    method public abstract long count();
+    method public abstract java.util.stream.LongStream distinct();
+    method public static java.util.stream.LongStream empty();
+    method public abstract java.util.stream.LongStream filter(java.util.function.LongPredicate);
+    method public abstract java.util.OptionalLong findAny();
+    method public abstract java.util.OptionalLong findFirst();
+    method public abstract java.util.stream.LongStream flatMap(java.util.function.LongFunction<? extends java.util.stream.LongStream>);
+    method public abstract void forEach(java.util.function.LongConsumer);
+    method public abstract void forEachOrdered(java.util.function.LongConsumer);
+    method public static java.util.stream.LongStream generate(java.util.function.LongSupplier);
+    method public static java.util.stream.LongStream iterate(long, java.util.function.LongUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfLong iterator();
+    method public abstract java.util.stream.LongStream limit(long);
+    method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
+    method public abstract java.util.OptionalLong max();
+    method public abstract java.util.OptionalLong min();
+    method public abstract boolean noneMatch(java.util.function.LongPredicate);
+    method public static java.util.stream.LongStream of(long);
+    method public static java.util.stream.LongStream of(long...);
+    method public abstract java.util.stream.LongStream parallel();
+    method public abstract java.util.stream.LongStream peek(java.util.function.LongConsumer);
+    method public static java.util.stream.LongStream range(long, long);
+    method public static java.util.stream.LongStream rangeClosed(long, long);
+    method public abstract long reduce(long, java.util.function.LongBinaryOperator);
+    method public abstract java.util.OptionalLong reduce(java.util.function.LongBinaryOperator);
+    method public abstract java.util.stream.LongStream sequential();
+    method public abstract java.util.stream.LongStream skip(long);
+    method public abstract java.util.stream.LongStream sorted();
+    method public abstract java.util.Spliterator.OfLong spliterator();
+    method public abstract long sum();
+    method public abstract java.util.LongSummaryStatistics summaryStatistics();
+    method public abstract long[] toArray();
+  }
+
+  public static abstract interface LongStream.Builder implements java.util.function.LongConsumer {
+    method public abstract void accept(long);
+    method public default java.util.stream.LongStream.Builder add(long);
+    method public abstract java.util.stream.LongStream build();
+  }
+
+  public abstract interface Stream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
+    method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Stream.Builder<T> builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
+    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
+    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
+    method public abstract long count();
+    method public abstract java.util.stream.Stream<T> distinct();
+    method public static java.util.stream.Stream<T> empty();
+    method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
+    method public abstract java.util.Optional<T> findAny();
+    method public abstract java.util.Optional<T> findFirst();
+    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
+    method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
+    method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
+    method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
+    method public abstract void forEach(java.util.function.Consumer<? super T>);
+    method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
+    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
+    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
+    method public abstract java.util.stream.Stream<T> limit(long);
+    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
+    method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
+    method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
+    method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Stream<T> of(T);
+    method public static java.util.stream.Stream<T> of(T...);
+    method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
+    method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
+    method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
+    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
+    method public abstract java.util.stream.Stream<T> skip(long);
+    method public abstract java.util.stream.Stream<T> sorted();
+    method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
+    method public abstract java.lang.Object[] toArray();
+    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
+  }
+
+  public static abstract interface Stream.Builder implements java.util.function.Consumer {
+    method public abstract void accept(T);
+    method public default java.util.stream.Stream.Builder<T> add(T);
+    method public abstract java.util.stream.Stream<T> build();
+  }
+
+  public final class StreamSupport {
+    method public static java.util.stream.DoubleStream doubleStream(java.util.Spliterator.OfDouble, boolean);
+    method public static java.util.stream.DoubleStream doubleStream(java.util.function.Supplier<? extends java.util.Spliterator.OfDouble>, int, boolean);
+    method public static java.util.stream.IntStream intStream(java.util.Spliterator.OfInt, boolean);
+    method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
+    method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
+    method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
+    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
+    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
+  }
+
+}
+
 package java.util.zip {
 
   public class Adler32 implements java.util.zip.Checksum {
@@ -62633,11 +63912,9 @@
 
   public final class PrivateCredentialPermission extends java.security.Permission {
     ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getCredentialClass();
     method public java.lang.String[][] getPrincipals();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
diff --git a/api/removed.txt b/api/removed.txt
index 0bf6594..3f16bca 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -9,18 +9,50 @@
 package android.app.admin {
 
   public class DevicePolicyManager {
+    method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+    method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
     method public deprecated java.lang.String getDeviceInitializerApp();
     method public deprecated android.content.ComponentName getDeviceInitializerComponent();
   }
 
 }
 
+package android.content {
+
+  public abstract class Context {
+    method public deprecated android.content.Context createCredentialEncryptedStorageContext();
+    method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+    method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+    method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
+    method public deprecated boolean isCredentialEncryptedStorage();
+    method public deprecated boolean isDeviceEncryptedStorage();
+    method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
+    method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+  }
+
+}
+
 package android.content.pm {
 
+  public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    field public deprecated java.lang.String credentialEncryptedDataDir;
+    field public deprecated java.lang.String deviceEncryptedDataDir;
+  }
+
+  public class ComponentInfo extends android.content.pm.PackageItemInfo {
+    field public deprecated boolean encryptionAware;
+  }
+
   public class PackageInfo implements android.os.Parcelable {
     field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
   }
 
+  public abstract class PackageManager {
+    field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
+    field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
+    field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+  }
+
 }
 
 package android.database {
@@ -33,14 +65,45 @@
 
 }
 
+package android.graphics {
+
+  public deprecated class AvoidXfermode extends android.graphics.Xfermode {
+    ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
+  }
+
+  public static final class AvoidXfermode.Mode extends java.lang.Enum {
+    method public static android.graphics.AvoidXfermode.Mode valueOf(java.lang.String);
+    method public static final android.graphics.AvoidXfermode.Mode[] values();
+    enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
+    enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
+  }
+
+  public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
+    ctor public PixelXorXfermode(int);
+  }
+
+}
+
 package android.media {
 
-  public class AudioFormat {
+  public final class AudioFormat implements android.os.Parcelable {
     ctor public AudioFormat();
   }
 
 }
 
+package android.media.tv {
+
+  public final class TvInputManager {
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+  }
+
+  public class TvView extends android.view.ViewGroup {
+    method public void requestUnblockContent(android.media.tv.TvContentRating);
+  }
+
+}
+
 package android.net {
 
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
@@ -69,6 +132,28 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndLocked();
+    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndUnlocked();
+    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
+  }
+
+}
+
+package android.os.storage {
+
+  public class StorageManager {
+    method public android.os.storage.StorageVolume getPrimaryVolume();
+    method public android.os.storage.StorageVolume[] getVolumeList();
+  }
+
+}
+
+package android.preference {
+
+  public class PreferenceManager {
+    method public deprecated void setStorageCredentialEncrypted();
+    method public deprecated void setStorageDeviceEncrypted();
   }
 
 }
@@ -199,14 +284,6 @@
 
 }
 
-package android.service.notification {
-
-  public abstract class ConditionProviderService extends android.app.Service {
-    method public void onRequestConditions(int);
-  }
-
-}
-
 package android.test.mock {
 
   public deprecated class MockPackageManager extends android.content.pm.PackageManager {
diff --git a/api/system-current.txt b/api/system-current.txt
index b36d7e8..96b1e28 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -42,6 +42,7 @@
     field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
+    field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
@@ -52,6 +53,7 @@
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
     field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+    field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -101,6 +103,7 @@
     field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
     field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
@@ -169,7 +172,6 @@
     field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
     field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
     field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
-    field public static final java.lang.String READ_WRITE_CONTACT_METADATA = "android.permission.READ_WRITE_CONTACT_METADATA";
     field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
     field public static final java.lang.String REBOOT = "android.permission.REBOOT";
     field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
@@ -194,6 +196,7 @@
     field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
+    field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
     field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT";
     field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -433,6 +436,7 @@
     field public static final int calendarViewStyle = 16843613; // 0x101035d
     field public static final int canControlMagnification = 16844040; // 0x1010508
     field public static final int canPerformGestures = 16844046; // 0x101050e
+    field public static final int canRecord = 16844061; // 0x101051d
     field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
     field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
     field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -509,15 +513,18 @@
     field public static final int contentAuthority = 16843408; // 0x1010290
     field public static final int contentDescription = 16843379; // 0x1010273
     field public static final int contentInsetEnd = 16843860; // 0x1010454
+    field public static final int contentInsetEndWithActions = 16844070; // 0x1010526
     field public static final int contentInsetLeft = 16843861; // 0x1010455
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
+    field public static final int contentInsetStartWithNavigation = 16844069; // 0x1010525
     field public static final int contextClickable = 16844007; // 0x10104e7
     field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
     field public static final int controlY2 = 16843775; // 0x10103ff
+    field public static final int countDown = 16844060; // 0x101051c
     field public static final int country = 16843962; // 0x10104ba
     field public static final int cropToPadding = 16843043; // 0x1010123
     field public static final int cursorVisible = 16843090; // 0x1010152
@@ -535,6 +542,7 @@
     field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
     field public static final int debuggable = 16842767; // 0x101000f
     field public static final int defaultHeight = 16844021; // 0x10104f5
+    field public static final int defaultToDeviceProtectedStorage = 16844037; // 0x1010505
     field public static final int defaultValue = 16843245; // 0x10101ed
     field public static final int defaultWidth = 16844020; // 0x10104f4
     field public static final int delay = 16843212; // 0x10101cc
@@ -554,6 +562,7 @@
     field public static final int dialogTheme = 16843528; // 0x1010308
     field public static final int dialogTitle = 16843250; // 0x10101f2
     field public static final int digits = 16843110; // 0x1010166
+    field public static final int directBootAware = 16844038; // 0x1010506
     field public static final int direction = 16843217; // 0x10101d1
     field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
     field public static final int directionPriority = 16843218; // 0x10101d2
@@ -602,7 +611,6 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
-    field public static final int encryptionAware = 16844038; // 0x1010506
     field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
     field public static final int endX = 16844051; // 0x1010513
@@ -651,6 +659,7 @@
     field public static final int fillBefore = 16843196; // 0x10101bc
     field public static final int fillColor = 16843780; // 0x1010404
     field public static final int fillEnabled = 16843343; // 0x101024f
+    field public static final int fillType = 16844064; // 0x1010520
     field public static final int fillViewport = 16843130; // 0x101017a
     field public static final int filter = 16843035; // 0x101011b
     field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -666,7 +675,7 @@
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
-    field public static final int forceDeviceEncrypted = 16844037; // 0x1010505
+    field public static final int forceHasOverlappingRendering = 16844068; // 0x1010524
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
     field public static final int foregroundTint = 16843885; // 0x101046d
@@ -950,7 +959,8 @@
     field public static final int minResizeWidth = 16843669; // 0x1010395
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
-    field public static final int minimalSize = 16844022; // 0x10104f6
+    field public static final int minimalHeight = 16844067; // 0x1010523
+    field public static final int minimalWidth = 16844022; // 0x10104f6
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
@@ -971,6 +981,7 @@
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
+    field public static final int nfcAntennaPositionDrawable = 16844063; // 0x101051f
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -1034,6 +1045,8 @@
     field public static final int popupBackground = 16843126; // 0x1010176
     field public static final int popupCharacters = 16843332; // 0x1010244
     field public static final int popupElevation = 16843916; // 0x101048c
+    field public static final int popupEnterTransition = 16844065; // 0x1010521
+    field public static final int popupExitTransition = 16844066; // 0x1010522
     field public static final int popupKeyboard = 16843331; // 0x1010243
     field public static final int popupLayout = 16843323; // 0x101023b
     field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -1457,6 +1470,7 @@
     field public static final int trimPathEnd = 16843785; // 0x1010409
     field public static final int trimPathOffset = 16843786; // 0x101040a
     field public static final int trimPathStart = 16843784; // 0x1010408
+    field public static final int tunerCount = 16844062; // 0x101051e
     field public static final int type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
@@ -2574,6 +2588,7 @@
     field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
     field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
     field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+    field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
     field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
     field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
     field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2608,6 +2623,7 @@
     field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
     field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
     field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+    field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
     field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
     field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
     field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -2765,8 +2781,11 @@
     field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
     field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
     field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+    field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+    field public static final int SHOW_MODE_AUTO = 0; // 0x0
+    field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
   }
 
   public static abstract class AccessibilityService.GestureResultCallback {
@@ -2847,14 +2866,10 @@
   }
 
   public final class GestureDescription {
-    method public static android.accessibilityservice.GestureDescription createClick(int, int);
-    method public static android.accessibilityservice.GestureDescription createLongClick(int, int);
-    method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long);
-    method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long);
+    method public static long getMaxGestureDuration();
+    method public static int getMaxStrokeCount();
     method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int);
     method public int getStrokeCount();
-    field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L
-    field public static final int MAX_STROKE_COUNT = 10; // 0xa
   }
 
   public static class GestureDescription.Builder {
@@ -3529,7 +3544,7 @@
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public void enterPictureInPicture();
+    method public void enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3549,7 +3564,7 @@
     method public android.view.View getCurrentFocus();
     method public android.app.FragmentManager getFragmentManager();
     method public android.content.Intent getIntent();
-    method public deprecated java.lang.Object getLastNonConfigurationInstance();
+    method public java.lang.Object getLastNonConfigurationInstance();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.LoaderManager getLoaderManager();
     method public java.lang.String getLocalClassName();
@@ -3569,8 +3584,6 @@
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
     method public boolean hasWindowFocus();
-    method public boolean inMultiWindow();
-    method public boolean inPictureInPicture();
     method public void invalidateOptionsMenu();
     method public boolean isBackgroundVisibleBehind();
     method public boolean isChangingConfigurations();
@@ -3578,7 +3591,10 @@
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isInMultiWindowMode();
+    method public boolean isInPictureInPictureMode();
     method public boolean isLocalVoiceInteractionSupported();
+    method public boolean isOverlayWithDecorCaptionEnabled();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3626,7 +3642,7 @@
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onNavigateUp();
     method public boolean onNavigateUpFromChild(android.app.Activity);
     method protected void onNewIntent(android.content.Intent);
@@ -3634,7 +3650,7 @@
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method protected void onPostCreate(android.os.Bundle);
     method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
@@ -3645,14 +3661,13 @@
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
     method public void onProvideAssistContent(android.app.assist.AssistContent);
     method public void onProvideAssistData(android.os.Bundle);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public android.net.Uri onProvideReferrer();
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method protected void onRestart();
     method protected void onRestoreInstanceState(android.os.Bundle);
     method public void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method protected void onResume();
-    method public deprecated java.lang.Object onRetainNonConfigurationInstance();
+    method public java.lang.Object onRetainNonConfigurationInstance();
     method protected void onSaveInstanceState(android.os.Bundle);
     method public void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method public boolean onSearchRequested(android.view.SearchEvent);
@@ -3673,7 +3688,6 @@
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
-    method public void overlayWithDecorCaption(boolean);
     method public void overridePendingTransition(int, int);
     method public void postponeEnterTransition();
     method public void recreate();
@@ -3702,6 +3716,7 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
+    method public void setOverlayWithDecorCaptionEnabled(boolean);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3716,7 +3731,7 @@
     method public deprecated void setTitleColor(int);
     method public void setVisible(boolean);
     method public final void setVolumeControlStream(int);
-    method public void setVrMode(boolean);
+    method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean shouldShowRequestPermissionRationale(java.lang.String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
@@ -4249,13 +4264,12 @@
     field public java.lang.String serviceDetails;
   }
 
-  public class AutomaticZenRule implements android.os.Parcelable {
+  public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
     method public long getCreationTime();
-    method public java.lang.String getId();
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
@@ -4343,7 +4357,6 @@
     method public void onPanelClosed(int, android.view.Menu);
     method public boolean onPrepareOptionsMenu(android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public void onRestoreInstanceState(android.os.Bundle);
     method public android.os.Bundle onSaveInstanceState();
     method public boolean onSearchRequested(android.view.SearchEvent);
@@ -4561,11 +4574,11 @@
     method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
     method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method public void onPrepareOptionsMenu(android.view.Menu);
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method public void onResume();
@@ -4646,11 +4659,11 @@
     method public void dispatchDestroy();
     method public void dispatchDestroyView();
     method public void dispatchLowMemory();
-    method public void dispatchMultiWindowChanged(boolean);
+    method public void dispatchMultiWindowModeChanged(boolean);
     method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
     method public void dispatchOptionsMenuClosed(android.view.Menu);
     method public void dispatchPause();
-    method public void dispatchPictureInPictureChanged(boolean);
+    method public void dispatchPictureInPictureModeChanged(boolean);
     method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
     method public void dispatchResume();
     method public void dispatchStart();
@@ -5037,6 +5050,7 @@
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
     field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
     field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
@@ -5178,16 +5192,17 @@
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
+    method public android.widget.RemoteViews createBigContentView();
+    method public android.widget.RemoteViews createContentView();
+    method public android.widget.RemoteViews createHeadsUpContentView();
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
-    method public android.widget.RemoteViews makeBigContentView();
-    method public android.widget.RemoteViews makeContentView();
-    method public android.widget.RemoteViews makeHeadsUpContentView();
     method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setChronometerCountsDown(boolean);
     method public android.app.Notification.Builder setColor(int);
     method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
@@ -5356,14 +5371,14 @@
   }
 
   public class NotificationManager {
-    method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
-    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
+    method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5373,7 +5388,7 @@
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
-    method public boolean updateAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5385,7 +5400,7 @@
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
@@ -5737,8 +5752,6 @@
     method public void enableCarMode(int);
     method public int getCurrentModeType();
     method public int getNightMode();
-    method public boolean isNightModeLocked();
-    method public boolean isUiModeLocked();
     method public void setNightMode(int);
     field public static java.lang.String ACTION_ENTER_CAR_MODE;
     field public static java.lang.String ACTION_ENTER_DESK_MODE;
@@ -5840,6 +5853,7 @@
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clear(int) throws java.io.IOException;
     method public void clearWallpaper();
     method public void clearWallpaper(int, int);
     method public void clearWallpaperOffsets(android.os.IBinder);
@@ -5853,6 +5867,7 @@
     method public android.graphics.drawable.Drawable getFastDrawable();
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.os.ParcelFileDescriptor getWallpaperFile(int);
+    method public int getWallpaperId(int);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
     method public boolean isWallpaperSettingAllowed();
@@ -5881,8 +5896,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
-    field public static final int FLAG_SET_LOCK = 2; // 0x2
-    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+    field public static final int FLAG_LOCK = 2; // 0x2
+    field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5966,9 +5981,7 @@
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
-    method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
     method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
-    method public deprecated android.os.UserHandle createUser(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();
@@ -5986,9 +5999,8 @@
     method public int getCurrentFailedPasswordAttempts();
     method public deprecated java.lang.String getDeviceInitializerApp();
     method public deprecated android.content.ComponentName getDeviceInitializerComponent();
-    method public boolean getDeviceLoggingEnabled(android.content.ComponentName);
     method public java.lang.String getDeviceOwner();
-    method public java.lang.String getDeviceOwnerLockScreenInfo();
+    method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
     method public java.lang.String getDeviceOwnerNameOnAnyUser();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -5997,7 +6009,6 @@
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
     method public java.lang.String getOrganizationName(android.content.ComponentName);
-    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -6025,21 +6036,26 @@
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
     method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
+    method public int getUserProvisioningState();
     method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
-    method public java.lang.String getWifiMacAddress();
+    method public java.lang.String getWifiMacAddress(android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
     method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
+    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
+    method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
+    method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
     method public void notifyPendingSystemUpdate(long);
@@ -6050,22 +6066,21 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
-    method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrieveDeviceLogs(android.content.ComponentName);
-    method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrievePreviousDeviceLogs(android.content.ComponentName);
+    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
+    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
     method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
-    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
+    method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
-    method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
+    method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
-    method public void setDeviceLoggingEnabled(android.content.ComponentName, boolean);
-    method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+    method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -6097,6 +6112,7 @@
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+    method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
     method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
@@ -6111,6 +6127,7 @@
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+    field public static final java.lang.String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
@@ -6122,6 +6139,7 @@
     field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
     field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
     field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
+    field public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5; // 0x5
     field public static final int ENCRYPTION_STATUS_INACTIVE = 1; // 0x1
     field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
     field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
@@ -6180,10 +6198,36 @@
     field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
+    field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
+    field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
+    field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
+    field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
+    field public static final int STATE_USER_UNMANAGED = 0; // 0x0
     field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public class SecurityLog {
+    ctor public SecurityLog();
+    field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
+    field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
+    field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
+    field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
+    field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
+  }
+
+  public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.Object getData();
+    method public int getTag();
+    method public long getTimeNanos();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
+  }
+
   public class SystemUpdatePolicy implements android.os.Parcelable {
     method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -6497,6 +6541,8 @@
     method public long getIntervalMillis();
     method public long getMaxExecutionDelayMillis();
     method public long getMinLatencyMillis();
+    method public static final long getMinimumFlex();
+    method public static final long getMinimumPeriod();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
@@ -6510,8 +6556,6 @@
     field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
     field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
     field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
-    field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
-    field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
     field public static final int NETWORK_TYPE_ANY = 1; // 0x1
     field public static final int NETWORK_TYPE_NONE = 0; // 0x0
     field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6625,8 +6669,8 @@
     method public long getTxPackets();
     method public int getUid();
     field public static final int ROAMING_ALL = -1; // 0xffffffff
-    field public static final int ROAMING_DEFAULT = 1; // 0x1
-    field public static final int ROAMING_ROAMING = 2; // 0x2
+    field public static final int ROAMING_NO = 1; // 0x1
+    field public static final int ROAMING_YES = 2; // 0x2
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
@@ -6834,31 +6878,6 @@
 
 }
 
-package android.auditing {
-
-  public class SecurityLog {
-    ctor public SecurityLog();
-    field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
-    field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
-    field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
-    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
-    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
-    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
-    field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
-    field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
-  }
-
-  public static class SecurityLog.SecurityEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.lang.Object getData();
-    method public int getTag();
-    method public long getTimeNanos();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.auditing.SecurityLog.SecurityEvent> CREATOR;
-  }
-
-}
-
 package android.bluetooth {
 
   public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
@@ -7369,9 +7388,10 @@
     method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
   }
 
-  public class BluetoothGattCharacteristic {
+  public class BluetoothGattCharacteristic implements android.os.Parcelable {
     ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
     method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
     method public java.lang.Float getFloatValue(int, int);
@@ -7389,6 +7409,8 @@
     method public boolean setValue(int, int, int, int);
     method public boolean setValue(java.lang.String);
     method public void setWriteType(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
     field public static final int FORMAT_FLOAT = 52; // 0x34
     field public static final int FORMAT_SFLOAT = 50; // 0x32
     field public static final int FORMAT_SINT16 = 34; // 0x22
@@ -7419,13 +7441,16 @@
     field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors;
   }
 
-  public class BluetoothGattDescriptor {
+  public class BluetoothGattDescriptor implements android.os.Parcelable {
     ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
     method public int getPermissions();
     method public java.util.UUID getUuid();
     method public byte[] getValue();
     method public boolean setValue(byte[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
     field public static final byte[] DISABLE_NOTIFICATION_VALUE;
     field public static final byte[] ENABLE_INDICATION_VALUE;
     field public static final byte[] ENABLE_NOTIFICATION_VALUE;
@@ -7468,16 +7493,19 @@
     method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
   }
 
-  public class BluetoothGattService {
+  public class BluetoothGattService implements android.os.Parcelable {
     ctor public BluetoothGattService(java.util.UUID, int);
     method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
     method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
     method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
     method public int getInstanceId();
     method public int getType();
     method public java.util.UUID getUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattService> CREATOR;
     field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
     field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
     field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics;
@@ -7600,15 +7628,6 @@
     field public static final int TYPE_SCO = 2; // 0x2
   }
 
-  public class OobData implements android.os.Parcelable {
-    ctor public OobData();
-    method public int describeContents();
-    method public byte[] getSecurityManagerTk();
-    method public void setSecurityManagerTk(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
-  }
-
 }
 
 package android.bluetooth.le {
@@ -8272,8 +8291,8 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public abstract android.content.Context createCredentialEncryptedStorageContext();
-    method public abstract android.content.Context createDeviceEncryptedStorageContext();
+    method public abstract android.content.Context createCredentialProtectedStorageContext();
+    method public abstract android.content.Context createDeviceProtectedStorageContext();
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -8318,8 +8337,6 @@
     method public abstract java.lang.String getPackageResourcePath();
     method public abstract android.content.res.Resources getResources();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -8331,11 +8348,11 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public abstract boolean isCredentialEncryptedStorage();
-    method public abstract boolean isDeviceEncryptedStorage();
+    method public abstract boolean isCredentialProtectedStorage();
+    method public abstract boolean isDeviceProtectedStorage();
     method public boolean isRestricted();
-    method public abstract boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public abstract boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public abstract boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public abstract boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[]);
@@ -8404,6 +8421,7 @@
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
+    field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
     field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
     field public static final int CONTEXT_RESTRICTED = 4; // 0x4
@@ -8412,7 +8430,7 @@
     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 HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
+    field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -8443,7 +8461,9 @@
     field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
+    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
@@ -8476,8 +8496,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedStorageContext();
-    method public android.content.Context createDeviceEncryptedStorageContext();
+    method public android.content.Context createCredentialProtectedStorageContext();
+    method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -8520,8 +8540,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -8529,10 +8547,10 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncryptedStorage();
-    method public boolean isDeviceEncryptedStorage();
-    method public boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public boolean isCredentialProtectedStorage();
+    method public boolean isDeviceProtectedStorage();
+    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -8775,6 +8793,7 @@
     field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
     field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
     field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
+    field public static final java.lang.String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
     field public static final java.lang.String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
     field public static final java.lang.String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
     field public static final java.lang.String ACTION_ASSIST = "android.intent.action.ASSIST";
@@ -8820,8 +8839,9 @@
     field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
     field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
     field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
     field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -9569,7 +9589,6 @@
     field public int documentLaunchMode;
     field public int flags;
     field public int launchMode;
-    field public android.content.pm.ActivityInfo.Layout layout;
     field public int maxRecents;
     field public java.lang.String parentActivityName;
     field public java.lang.String permission;
@@ -9580,14 +9599,16 @@
     field public java.lang.String taskAffinity;
     field public int theme;
     field public int uiOptions;
+    field public android.content.pm.ActivityInfo.WindowLayout windowLayout;
   }
 
-  public static final class ActivityInfo.Layout {
-    ctor public ActivityInfo.Layout(int, float, int, float, int, int);
+  public static final class ActivityInfo.WindowLayout {
+    ctor public ActivityInfo.WindowLayout(int, float, int, float, int, int, int);
     field public final int gravity;
     field public final int height;
     field public final float heightFraction;
-    field public final int minimalSize;
+    field public final int minimalHeight;
+    field public final int minimalWidth;
     field public final int width;
     field public final float widthFraction;
   }
@@ -9634,14 +9655,15 @@
     field public java.lang.String backupAgentName;
     field public java.lang.String className;
     field public int compatibleWidthLimitDp;
-    field public java.lang.String credentialEncryptedDataDir;
+    field public java.lang.String credentialProtectedDataDir;
     field public java.lang.String dataDir;
     field public int descriptionRes;
-    field public java.lang.String deviceEncryptedDataDir;
+    field public java.lang.String deviceProtectedDataDir;
     field public boolean enabled;
     field public int flags;
     field public int largestWidthLimitDp;
     field public java.lang.String manageSpaceActivityName;
+    field public java.lang.String minSdkVersion;
     field public java.lang.String nativeLibraryDir;
     field public java.lang.String permission;
     field public java.lang.String processName;
@@ -9673,8 +9695,8 @@
     method public boolean isEnabled();
     field public android.content.pm.ApplicationInfo applicationInfo;
     field public int descriptionRes;
+    field public boolean directBootAware;
     field public boolean enabled;
-    field public boolean encryptionAware;
     field public boolean exported;
     field public java.lang.String processName;
   }
@@ -9696,25 +9718,6 @@
     field public int reqTouchScreen;
   }
 
-  public deprecated class ContainerEncryptionParams implements android.os.Parcelable {
-    ctor public ContainerEncryptionParams(java.lang.String, java.security.spec.AlgorithmParameterSpec, javax.crypto.SecretKey) throws java.security.InvalidAlgorithmParameterException;
-    ctor public ContainerEncryptionParams(java.lang.String, java.security.spec.AlgorithmParameterSpec, javax.crypto.SecretKey, java.lang.String, java.security.spec.AlgorithmParameterSpec, javax.crypto.SecretKey, byte[], long, long, long) throws java.security.InvalidAlgorithmParameterException;
-    method public int describeContents();
-    method public long getAuthenticatedDataStart();
-    method public long getDataEnd();
-    method public long getEncryptedDataStart();
-    method public java.lang.String getEncryptionAlgorithm();
-    method public javax.crypto.SecretKey getEncryptionKey();
-    method public java.security.spec.AlgorithmParameterSpec getEncryptionSpec();
-    method public java.lang.String getMacAlgorithm();
-    method public javax.crypto.SecretKey getMacKey();
-    method public java.security.spec.AlgorithmParameterSpec getMacSpec();
-    method public byte[] getMacTag();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.pm.ContainerEncryptionParams> CREATOR;
-    field protected static final java.lang.String TAG = "ContainerEncryptionParams";
-  }
-
   public final class EphemeralResolveInfo implements android.os.Parcelable {
     ctor public EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>);
     method public int describeContents();
@@ -9794,13 +9797,20 @@
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
+    method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+    method public boolean hasShortcutHostPermission();
     method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+    method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
   }
 
@@ -9813,6 +9823,18 @@
     method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
     method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+    method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
+  }
+
+  public static class LauncherApps.ShortcutQuery {
+    ctor public LauncherApps.ShortcutQuery();
+    method public void setActivity(android.content.ComponentName);
+    method public void setChangedSince(long);
+    method public void setPackage(java.lang.String);
+    method public void setQueryFlags(int);
+    field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_GET_PINNED = 2; // 0x2
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -9890,6 +9912,7 @@
     method public java.lang.String[] getNames() throws java.io.IOException;
     method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
     method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+    method public void removeSplit(java.lang.String) throws java.io.IOException;
     method public void setStagingProgress(float);
   }
 
@@ -9919,9 +9942,11 @@
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
     ctor public PackageInstaller.SessionParams(int);
     method public int describeContents();
+    method public void setAllowDowngrade(boolean);
     method public void setAppIcon(android.graphics.Bitmap);
     method public void setAppLabel(java.lang.CharSequence);
     method public void setAppPackageName(java.lang.String);
+    method public void setDontKillApp(boolean);
     method public void setGrantedRuntimePermissions(java.lang.String[]);
     method public void setInstallLocation(int);
     method public void setOriginatingUid(int);
@@ -9944,6 +9969,7 @@
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager);
+    method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadUnbadgedIcon(android.content.pm.PackageManager);
     method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
@@ -10143,6 +10169,8 @@
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -10200,14 +10228,15 @@
     field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
     field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
     field public static final int INSTALL_SUCCEEDED = 1; // 0x1
+    field public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1; // 0xffffffff
+    field public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
     field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
+    field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
     field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
     field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
-    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
     field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
     field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
@@ -10282,6 +10311,7 @@
     field public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR;
     field public static final int FLAG_COSTS_MONEY = 1; // 0x1
     field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
+    field public static final int FLAG_REMOVED = 2; // 0x2
     field public static final int PROTECTION_DANGEROUS = 1; // 0x1
     field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
     field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20
@@ -10289,6 +10319,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
     field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -10366,6 +10397,61 @@
     field public java.lang.String permission;
   }
 
+  public final class ShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivityComponent();
+    method public android.os.PersistableBundle getExtras();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public long getLastChangedTimestamp();
+    method public java.lang.String getPackageName();
+    method public java.lang.String getText();
+    method public java.lang.String getTitle();
+    method public int getWeight();
+    method public boolean hasIconFile();
+    method public boolean hasIconResource();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean isDynamic();
+    method public boolean isPinned();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
+    field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
+    field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int FLAG_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
+    field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+    field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
+    field public static final int FLAG_PINNED = 2; // 0x2
+  }
+
+  public static class ShortcutInfo.Builder {
+    ctor public ShortcutInfo.Builder(android.content.Context);
+    method public android.content.pm.ShortcutInfo build();
+    method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
+    method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setWeight(int);
+  }
+
+  public class ShortcutManager {
+    method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
+    method public void deleteAllDynamicShortcuts();
+    method public void deleteDynamicShortcut(java.lang.String);
+    method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+    method public int getIconMaxDimensions();
+    method public int getMaxDynamicShortcutCount();
+    method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public long getRateLimitResetTime();
+    method public int getRemainingCallCount();
+    method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+  }
+
   public class Signature implements android.os.Parcelable {
     ctor public Signature(byte[]);
     ctor public Signature(java.lang.String);
@@ -10437,7 +10523,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
+  public class ColorStateList implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -10446,18 +10532,13 @@
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
+    method public boolean isStateful();
     method public static android.content.res.ColorStateList valueOf(int);
     method public android.content.res.ColorStateList withAlpha(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
   }
 
-  public abstract class ComplexColor {
-    ctor public ComplexColor();
-    method public abstract int getDefaultColor();
-    method public boolean isStateful();
-  }
-
   public final class Configuration implements java.lang.Comparable android.os.Parcelable {
     ctor public Configuration();
     ctor public Configuration(android.content.res.Configuration);
@@ -10561,11 +10642,6 @@
     field public int uiMode;
   }
 
-  public class GradientColor extends android.content.res.ComplexColor {
-    method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public int getDefaultColor();
-  }
-
   public class ObbInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -10625,7 +10701,6 @@
     method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
     method public final android.content.res.Resources.Theme newTheme();
     method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
     method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10661,7 +10736,6 @@
     method public int getChangingConfigurations();
     method public int getColor(int, int);
     method public android.content.res.ColorStateList getColorStateList(int);
-    method public android.content.res.ComplexColor getComplexColor(int);
     method public float getDimension(int, float);
     method public int getDimensionPixelOffset(int, int);
     method public int getDimensionPixelSize(int, int);
@@ -10871,7 +10945,6 @@
     method public boolean hasNext();
     method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
     method public android.database.CursorJoiner.Result next();
-    method public void remove();
   }
 
   public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -11802,17 +11875,6 @@
 
 package android.graphics {
 
-  public deprecated class AvoidXfermode extends android.graphics.Xfermode {
-    ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
-  }
-
-  public static final class AvoidXfermode.Mode extends java.lang.Enum {
-    method public static android.graphics.AvoidXfermode.Mode valueOf(java.lang.String);
-    method public static final android.graphics.AvoidXfermode.Mode[] values();
-    enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
-    enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
-  }
-
   public final class Bitmap implements android.os.Parcelable {
     method public boolean compress(android.graphics.Bitmap.CompressFormat, int, java.io.OutputStream);
     method public android.graphics.Bitmap copy(android.graphics.Bitmap.Config, boolean);
@@ -12348,6 +12410,8 @@
     ctor public Outline(android.graphics.Outline);
     method public boolean canClip();
     method public float getAlpha();
+    method public float getRadius();
+    method public boolean getRect(android.graphics.Rect);
     method public boolean isEmpty();
     method public void offset(int, int);
     method public void set(android.graphics.Outline);
@@ -12677,10 +12741,6 @@
     field public int bytesPerPixel;
   }
 
-  public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
-    ctor public PixelXorXfermode(int);
-  }
-
   public class Point implements android.os.Parcelable {
     ctor public Point();
     ctor public Point(int, int);
@@ -13240,7 +13300,8 @@
     method public int getGradientType();
     method public int getOpacity();
     method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
-    method public boolean isUseLevel();
+    method public int getShape();
+    method public boolean getUseLevel();
     method public void setAlpha(int);
     method public void setColor(int);
     method public void setColor(android.content.res.ColorStateList);
@@ -13359,9 +13420,9 @@
     method public void setPaddingMode(int);
     method public void setPaddingRelative(int, int, int, int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    field public static final int INSET_UNDEFINED = -2147483648; // 0x80000000
     field public static final int PADDING_MODE_NEST = 0; // 0x0
     field public static final int PADDING_MODE_STACK = 1; // 0x1
-    field public static final int UNDEFINED_INSET = -2147483648; // 0x80000000
   }
 
   public class LevelListDrawable extends android.graphics.drawable.DrawableContainer {
@@ -13375,12 +13436,10 @@
     ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
     ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
     method public void draw(android.graphics.Canvas);
-    method public android.graphics.NinePatch getNinePatch();
     method public int getOpacity();
     method public android.graphics.Paint getPaint();
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setNinePatch(android.graphics.NinePatch);
     method public void setTargetDensity(android.graphics.Canvas);
     method public void setTargetDensity(android.util.DisplayMetrics);
     method public void setTargetDensity(int);
@@ -13603,8 +13662,8 @@
     method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
     method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
     method public final void unlock();
-    field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
-    field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+    field public static final deprecated java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
+    field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
     field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
     field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -13849,6 +13908,7 @@
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
+    method public int getId();
     method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
@@ -13861,7 +13921,9 @@
     method public java.util.UUID getUuid();
     method public java.lang.String getVendor();
     method public int getVersion();
+    method public boolean isAdditionalInfoSupported();
     method public boolean isDataInjectionSupported();
+    method public boolean isDynamicSensor();
     method public boolean isWakeUpSensor();
     field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
     field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13897,6 +13959,7 @@
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
+    field public static final int TYPE_DEVICE_PRIVATE_BASE = 65536; // 0x10000
     field public static final int TYPE_DYNAMIC_SENSOR_META = 32; // 0x20
     field public static final int TYPE_GAME_ROTATION_VECTOR = 15; // 0xf
     field public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; // 0x14
@@ -13985,8 +14048,9 @@
     method public deprecated int getSensors();
     method public boolean initDataInjection(boolean);
     method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+    method public boolean isDynamicSensorDiscoverySupported();
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13995,7 +14059,7 @@
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
-    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
     method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -14060,8 +14124,8 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
-  public static abstract class SensorManager.DynamicSensorConnectionCallback {
-    ctor public SensorManager.DynamicSensorConnectionCallback();
+  public static abstract class SensorManager.DynamicSensorCallback {
+    ctor public SensorManager.DynamicSensorCallback();
     method public void onDynamicSensorConnected(android.hardware.Sensor);
     method public void onDynamicSensorDisconnected(android.hardware.Sensor);
   }
@@ -14111,6 +14175,7 @@
 
   public static abstract class CameraCaptureSession.CaptureCallback {
     ctor public CameraCaptureSession.CaptureCallback();
+    method public void onCaptureBufferLost(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.view.Surface, long);
     method public void onCaptureCompleted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult);
     method public void onCaptureFailed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure);
     method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
@@ -15209,6 +15274,7 @@
     ctor public ContextHubInfo();
     method public int describeContents();
     method public int getId();
+    method public int getMaxPacketLengthBytes();
     method public android.hardware.location.MemoryRegion[] getMemoryRegions();
     method public java.lang.String getName();
     method public float getPeakMips();
@@ -15221,35 +15287,26 @@
     method public java.lang.String getToolchain();
     method public int getToolchainVersion();
     method public java.lang.String getVendor();
-    method public void setId(int);
-    method public void setMemoryRegions(android.hardware.location.MemoryRegion[]);
-    method public void setName(java.lang.String);
-    method public void setPeakMips(float);
-    method public void setPeakPowerDrawMw(float);
-    method public void setPlatformVersion(int);
-    method public void setSleepPowerDrawMw(float);
-    method public void setStaticSwVersion(int);
-    method public void setStoppedPowerDrawMw(float);
-    method public void setSupportedSensors(int[]);
-    method public void setToolchain(java.lang.String);
-    method public void setToolchainVersion(int);
-    method public void setVendor(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR;
   }
 
   public final class ContextHubManager {
-    method public java.lang.Integer[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
-    method public int[] getContexthubHandles();
-    method public android.hardware.location.ContextHubInfo getContexthubInfo(int);
+    method public int[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
+    method public int[] getContextHubHandles();
+    method public android.hardware.location.ContextHubInfo getContextHubInfo(int);
     method public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
     method public int loadNanoApp(int, android.hardware.location.NanoApp);
+    method public int registerCallback(android.hardware.location.ContextHubManager.Callback);
+    method public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
     method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
     method public int unloadNanoApp(int);
-    field public static final int ANY_HUB = -1; // 0xffffffff
-    field public static final int MSG_DATA_SEND = 3; // 0x3
-    field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
-    field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
+    method public int unregisterCallback(android.hardware.location.ContextHubManager.Callback);
+  }
+
+  public static abstract class ContextHubManager.Callback {
+    ctor protected ContextHubManager.Callback();
+    method public abstract void onMessageReceipt(int, int, android.hardware.location.ContextHubMessage);
   }
 
   public class ContextHubMessage {
@@ -15438,7 +15495,7 @@
   public class NanoAppInstanceInfo {
     ctor public NanoAppInstanceInfo();
     method public int describeContents();
-    method public int getAppId();
+    method public long getAppId();
     method public int getAppVersion();
     method public int getContexthubId();
     method public int getHandle();
@@ -15449,17 +15506,6 @@
     method public int getNeededWriteMemBytes();
     method public int[] getOutputEvents();
     method public java.lang.String getPublisher();
-    method public void setAppId(int);
-    method public void setAppVersion(int);
-    method public void setContexthubId(int);
-    method public void setHandle(int);
-    method public void setName(java.lang.String);
-    method public void setNeededExecMemBytes(int);
-    method public void setNeededReadMemBytes(int);
-    method public void setNeededSensors(int[]);
-    method public void setNeededWriteMemBytes(int);
-    method public void setOutputEvents(int[]);
-    method public void setPublisher(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
   }
@@ -15957,7 +16003,6 @@
 
   public static abstract interface UCharacter.BidiPairedBracketType {
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int OPEN = 1; // 0x1
   }
@@ -15966,7 +16011,6 @@
     field public static final int CANONICAL = 1; // 0x1
     field public static final int CIRCLE = 3; // 0x3
     field public static final int COMPAT = 2; // 0x2
-    field public static final int COUNT = 18; // 0x12
     field public static final int FINAL = 4; // 0x4
     field public static final int FONT = 5; // 0x5
     field public static final int FRACTION = 6; // 0x6
@@ -15986,7 +16030,6 @@
 
   public static abstract interface UCharacter.EastAsianWidth {
     field public static final int AMBIGUOUS = 1; // 0x1
-    field public static final int COUNT = 6; // 0x6
     field public static final int FULLWIDTH = 3; // 0x3
     field public static final int HALFWIDTH = 2; // 0x2
     field public static final int NARROW = 4; // 0x4
@@ -15996,7 +16039,6 @@
 
   public static abstract interface UCharacter.GraphemeClusterBreak {
     field public static final int CONTROL = 1; // 0x1
-    field public static final int COUNT = 13; // 0xd
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
     field public static final int L = 4; // 0x4
@@ -16012,7 +16054,6 @@
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int LEADING_JAMO = 1; // 0x1
     field public static final int LVT_SYLLABLE = 5; // 0x5
     field public static final int LV_SYLLABLE = 4; // 0x4
@@ -16028,7 +16069,6 @@
     field public static final int BEH = 4; // 0x4
     field public static final int BETH = 5; // 0x5
     field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
-    field public static final int COUNT = 86; // 0x56
     field public static final int DAL = 6; // 0x6
     field public static final int DALATH_RISH = 7; // 0x7
     field public static final int E = 8; // 0x8
@@ -16113,7 +16153,6 @@
   }
 
   public static abstract interface UCharacter.JoiningType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int DUAL_JOINING = 2; // 0x2
     field public static final int JOIN_CAUSING = 1; // 0x1
     field public static final int LEFT_JOINING = 3; // 0x3
@@ -16136,7 +16175,6 @@
     field public static final int COMPLEX_CONTEXT = 24; // 0x18
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
-    field public static final int COUNT = 40; // 0x28
     field public static final int EXCLAMATION = 11; // 0xb
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
@@ -16168,7 +16206,6 @@
   }
 
   public static abstract interface UCharacter.NumericType {
-    field public static final int COUNT = 4; // 0x4
     field public static final int DECIMAL = 1; // 0x1
     field public static final int DIGIT = 2; // 0x2
     field public static final int NONE = 0; // 0x0
@@ -16178,7 +16215,6 @@
   public static abstract interface UCharacter.SentenceBreak {
     field public static final int ATERM = 1; // 0x1
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 15; // 0xf
     field public static final int CR = 11; // 0xb
     field public static final int EXTEND = 12; // 0xc
     field public static final int FORMAT = 3; // 0x3
@@ -16321,7 +16357,6 @@
     field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
     field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
     field public static final int COPTIC_ID = 132; // 0x84
-    field public static final int COUNT = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
     field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
     field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -16735,7 +16770,6 @@
 
   public static abstract interface UCharacter.WordBreak {
     field public static final int ALETTER = 1; // 0x1
-    field public static final int COUNT = 17; // 0x11
     field public static final int CR = 8; // 0x8
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
@@ -16766,7 +16800,6 @@
   }
 
   public static abstract interface UCharacterEnums.ECharacterCategory {
-    field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
     field public static final byte CONTROL = 15; // 0xf
@@ -16806,7 +16839,6 @@
     field public static final int ARABIC_NUMBER = 5; // 0x5
     field public static final int BLOCK_SEPARATOR = 7; // 0x7
     field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
-    field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
     field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
     field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
     field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -16859,7 +16891,6 @@
     field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
     field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
     field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
-    field public static final int BINARY_LIMIT = 57; // 0x39
     field public static final int BINARY_START = 0; // 0x0
     field public static final int BLOCK = 4097; // 0x1001
     field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -16878,7 +16909,6 @@
     field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
     field public static final int DEPRECATED = 6; // 0x6
     field public static final int DIACRITIC = 7; // 0x7
-    field public static final int DOUBLE_LIMIT = 12289; // 0x3001
     field public static final int DOUBLE_START = 12288; // 0x3000
     field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
     field public static final int EXTENDER = 8; // 0x8
@@ -16897,7 +16927,6 @@
     field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
     field public static final int ID_CONTINUE = 15; // 0xf
     field public static final int ID_START = 16; // 0x10
-    field public static final int INT_LIMIT = 4118; // 0x1016
     field public static final int INT_START = 4096; // 0x1000
     field public static final int JOINING_GROUP = 4102; // 0x1006
     field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -16907,7 +16936,6 @@
     field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
     field public static final int LOWERCASE = 22; // 0x16
     field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
-    field public static final int MASK_LIMIT = 8193; // 0x2001
     field public static final int MASK_START = 8192; // 0x2000
     field public static final int MATH = 23; // 0x17
     field public static final int NAME = 16389; // 0x4005
@@ -16922,7 +16950,6 @@
     field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
     field public static final int NUMERIC_TYPE = 4105; // 0x1009
     field public static final int NUMERIC_VALUE = 12288; // 0x3000
-    field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
     field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
     field public static final int PATTERN_SYNTAX = 42; // 0x2a
     field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -16942,7 +16969,6 @@
     field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
     field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
     field public static final int SOFT_DOTTED = 27; // 0x1b
-    field public static final int STRING_LIMIT = 16398; // 0x400e
     field public static final int STRING_START = 16384; // 0x4000
     field public static final int S_TERM = 35; // 0x23
     field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -16959,7 +16985,6 @@
   }
 
   public static abstract interface UProperty.NameChoice {
-    field public static final int COUNT = 2; // 0x2
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
   }
@@ -17004,7 +17029,6 @@
     field public static final int CHAM = 66; // 0x42
     field public static final int CHEROKEE = 6; // 0x6
     field public static final int CIRTH = 67; // 0x43
-    field public static final int CODE_LIMIT = 167; // 0xa7
     field public static final int COMMON = 0; // 0x0
     field public static final int COPTIC = 7; // 0x7
     field public static final int CUNEIFORM = 101; // 0x65
@@ -17399,7 +17423,6 @@
 
   public final class CollationKey implements java.lang.Comparable {
     ctor public CollationKey(java.lang.String, byte[]);
-    ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int compareTo(android.icu.text.CollationKey);
     method public boolean equals(android.icu.text.CollationKey);
     method public android.icu.text.CollationKey getBound(int, int);
@@ -17409,7 +17432,6 @@
   }
 
   public static final class CollationKey.BoundMode {
-    field public static final int COUNT = 3; // 0x3
     field public static final int LOWER = 0; // 0x0
     field public static final int UPPER = 1; // 0x1
     field public static final int UPPER_LONG = 2; // 0x2
@@ -17441,7 +17463,6 @@
     method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
     method public static final java.lang.String[] getKeywords();
     method public int getMaxVariable();
-    method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int[] getReorderCodes();
     method public int getStrength();
     method public android.icu.text.UnicodeSet getTailoredSet();
@@ -17481,7 +17502,6 @@
     field public static final int DEFAULT = -1; // 0xffffffff
     field public static final int DIGIT = 4100; // 0x1004
     field public static final int FIRST = 4096; // 0x1000
-    field public static final int LIMIT = 4101; // 0x1005
     field public static final int NONE = 103; // 0x67
     field public static final int OTHERS = 103; // 0x67
     field public static final int PUNCTUATION = 4097; // 0x1001
@@ -17594,7 +17614,6 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
-    field public static final int FIELD_COUNT = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -17838,7 +17857,6 @@
     field public static final int MONTH = 3; // 0x3
     field public static final int QUARTER = 2; // 0x2
     field public static final int SECOND = 13; // 0xd
-    field public static final int TYPE_LIMIT = 16; // 0x10
     field public static final int WEEKDAY = 6; // 0x6
     field public static final int WEEK_OF_MONTH = 5; // 0x5
     field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -18469,14 +18487,6 @@
     enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
   }
 
-  public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
-    ctor public RawCollationKey();
-    ctor public RawCollationKey(int);
-    ctor public RawCollationKey(byte[]);
-    ctor public RawCollationKey(byte[], int);
-    method public int compareTo(android.icu.text.RawCollationKey);
-  }
-
   public final class RelativeDateTimeFormatter {
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -18560,7 +18570,6 @@
     method public android.icu.text.CollationKey getCollationKey(java.lang.String);
     method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
     method public boolean getNumericCollation();
-    method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public java.lang.String getRules();
     method public java.lang.String getRules(boolean);
     method public android.icu.util.VersionInfo getUCAVersion();
@@ -18891,9 +18900,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -18907,10 +18913,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -18953,7 +18955,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -18968,7 +18969,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
@@ -19064,19 +19064,6 @@
     field public static final int BE = 0; // 0x0
   }
 
-  public class ByteArrayWrapper implements java.lang.Comparable {
-    ctor public ByteArrayWrapper();
-    ctor public ByteArrayWrapper(byte[], int);
-    ctor public ByteArrayWrapper(java.nio.ByteBuffer);
-    method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
-    method public int compareTo(android.icu.util.ByteArrayWrapper);
-    method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
-    method public final byte[] releaseBytes();
-    method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
-    field public byte[] bytes;
-    field public int size;
-  }
-
    abstract class CECalendar extends android.icu.util.Calendar {
     ctor protected CECalendar();
     ctor protected CECalendar(android.icu.util.TimeZone);
@@ -19087,11 +19074,8 @@
     ctor protected CECalendar(int, int, int);
     ctor protected CECalendar(java.util.Date);
     ctor protected CECalendar(int, int, int, int, int, int);
-    method public static int ceToJD(long, int, int, int);
-    method protected abstract int getJDEpochOffset();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetLimit(int, int);
-    method public static void jdToCE(int, int, int[]);
   }
 
   public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
@@ -19319,7 +19303,6 @@
     ctor public CopticCalendar(int, int, int);
     ctor public CopticCalendar(java.util.Date);
     ctor public CopticCalendar(int, int, int, int, int, int);
-    method protected deprecated int getJDEpochOffset();
     method protected deprecated int handleGetExtendedYear();
     field public static final int AMSHIR = 5; // 0x5
     field public static final int BABA = 1; // 0x1
@@ -19490,11 +19473,11 @@
     ctor public IslamicCalendar(java.util.Date);
     ctor public IslamicCalendar(int, int, int);
     ctor public IslamicCalendar(int, int, int, int, int, int);
+    method public android.icu.util.IslamicCalendar.CalculationType getCalculationType();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
-    method public boolean isCivil();
-    method public void setCivil(boolean);
+    method public void setCalculationType(android.icu.util.IslamicCalendar.CalculationType);
     field public static final int DHU_AL_HIJJAH = 11; // 0xb
     field public static final int DHU_AL_QIDAH = 10; // 0xa
     field public static final int JUMADA_1 = 4; // 0x4
@@ -19932,7 +19915,6 @@
     method public int getMicro();
     method public int getMilli();
     method public int getMinor();
-    method public static void main(java.lang.String[]);
     field public static final android.icu.util.VersionInfo ICU_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_BUILDER_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
@@ -20340,179 +20322,75 @@
 
   public final class GnssClock implements android.os.Parcelable {
     method public int describeContents();
-    method public double getBiasInNs();
-    method public double getBiasUncertaintyInNs();
-    method public double getDriftInNsPerSec();
-    method public double getDriftUncertaintyInNsPerSec();
-    method public long getFullBiasInNs();
+    method public double getBiasNanos();
+    method public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method public double getDriftUncertaintyNanosPerSecond();
+    method public long getFullBiasNanos();
     method public int getHardwareClockDiscontinuityCount();
-    method public short getLeapSecond();
-    method public long getTimeInNs();
-    method public double getTimeUncertaintyInNs();
-    method public byte getType();
-    method public boolean hasBiasInNs();
-    method public boolean hasBiasUncertaintyInNs();
-    method public boolean hasDriftInNsPerSec();
-    method public boolean hasDriftUncertaintyInNsPerSec();
-    method public boolean hasFullBiasInNs();
+    method public int getLeapSecond();
+    method public long getTimeNanos();
+    method public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasFullBiasNanos();
     method public boolean hasLeapSecond();
-    method public boolean hasTimeUncertaintyInNs();
-    method public void reset();
-    method public void resetBiasInNs();
-    method public void resetBiasUncertaintyInNs();
-    method public void resetDriftInNsPerSec();
-    method public void resetDriftUncertaintyInNsPerSec();
-    method public void resetFullBiasInNs();
-    method public void resetLeapSecond();
-    method public void resetTimeUncertaintyInNs();
-    method public void set(android.location.GnssClock);
-    method public void setBiasInNs(double);
-    method public void setBiasUncertaintyInNs(double);
-    method public void setDriftInNsPerSec(double);
-    method public void setDriftUncertaintyInNsPerSec(double);
-    method public void setFullBiasInNs(long);
-    method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(short);
-    method public void setTimeInNs(long);
-    method public void setTimeUncertaintyInNs(double);
-    method public void setType(byte);
+    method public boolean hasTimeUncertaintyNanos();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
-    field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
-    field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
   }
 
-  public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
-  }
-
   public final class GnssMeasurement implements android.os.Parcelable {
     method public int describeContents();
-    method public double getAccumulatedDeltaRangeInMeters();
-    method public short getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method public double getAzimuthInDeg();
-    method public double getAzimuthUncertaintyInDeg();
-    method public int getBitNumber();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public long getCarrierCycles();
-    method public float getCarrierFrequencyInHz();
+    method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
     method public double getCarrierPhaseUncertainty();
-    method public double getCn0InDbHz();
-    method public double getCodePhaseInChips();
-    method public double getCodePhaseUncertaintyInChips();
-    method public byte getConstellationType();
-    method public double getDopplerShiftInHz();
-    method public double getDopplerShiftUncertaintyInHz();
-    method public double getElevationInDeg();
-    method public double getElevationUncertaintyInDeg();
-    method public byte getLossOfLock();
-    method public byte getMultipathIndicator();
-    method public double getPseudorangeInMeters();
-    method public double getPseudorangeRateInMetersPerSec();
-    method public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method public double getPseudorangeUncertaintyInMeters();
-    method public long getReceivedSvTimeInNs();
-    method public long getReceivedSvTimeUncertaintyInNs();
+    method public double getCn0DbHz();
+    method public int getConstellationType();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
     method public double getSnrInDb();
-    method public short getState();
-    method public short getSvid();
-    method public short getTimeFromLastBitInMs();
-    method public double getTimeOffsetInNs();
-    method public boolean hasAzimuthInDeg();
-    method public boolean hasAzimuthUncertaintyInDeg();
-    method public boolean hasBitNumber();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
     method public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
     method public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodePhaseInChips();
-    method public boolean hasCodePhaseUncertaintyInChips();
-    method public boolean hasDopplerShiftInHz();
-    method public boolean hasDopplerShiftUncertaintyInHz();
-    method public boolean hasElevationInDeg();
-    method public boolean hasElevationUncertaintyInDeg();
-    method public boolean hasPseudorangeInMeters();
-    method public boolean hasPseudorangeUncertaintyInMeters();
     method public boolean hasSnrInDb();
-    method public boolean hasTimeFromLastBitInMs();
-    method public boolean isPseudorangeRateCorrected();
-    method public boolean isUsedInFix();
-    method public void reset();
-    method public void resetAzimuthInDeg();
-    method public void resetAzimuthUncertaintyInDeg();
-    method public void resetBitNumber();
-    method public void resetCarrierCycles();
-    method public void resetCarrierFrequencyInHz();
-    method public void resetCarrierPhase();
-    method public void resetCarrierPhaseUncertainty();
-    method public void resetCodePhaseInChips();
-    method public void resetCodePhaseUncertaintyInChips();
-    method public void resetDopplerShiftInHz();
-    method public void resetDopplerShiftUncertaintyInHz();
-    method public void resetElevationInDeg();
-    method public void resetElevationUncertaintyInDeg();
-    method public void resetPseudorangeInMeters();
-    method public void resetPseudorangeUncertaintyInMeters();
-    method public void resetSnrInDb();
-    method public void resetTimeFromLastBitInMs();
-    method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeInMeters(double);
-    method public void setAccumulatedDeltaRangeState(short);
-    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method public void setAzimuthInDeg(double);
-    method public void setAzimuthUncertaintyInDeg(double);
-    method public void setBitNumber(int);
-    method public void setCarrierCycles(long);
-    method public void setCarrierFrequencyInHz(float);
-    method public void setCarrierPhase(double);
-    method public void setCarrierPhaseUncertainty(double);
-    method public void setCn0InDbHz(double);
-    method public void setCodePhaseInChips(double);
-    method public void setCodePhaseUncertaintyInChips(double);
-    method public void setConstellationType(byte);
-    method public void setDopplerShiftInHz(double);
-    method public void setDopplerShiftUncertaintyInHz(double);
-    method public void setElevationInDeg(double);
-    method public void setElevationUncertaintyInDeg(double);
-    method public void setLossOfLock(byte);
-    method public void setMultipathIndicator(byte);
-    method public void setPseudorangeInMeters(double);
-    method public void setPseudorangeRateInMetersPerSec(double);
-    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method public void setPseudorangeUncertaintyInMeters(double);
-    method public void setReceivedSvTimeInNs(long);
-    method public void setReceivedSvTimeUncertaintyInNs(long);
-    method public void setSnrInDb(double);
-    method public void setState(short);
-    method public void setSvid(short);
-    method public void setTimeFromLastBitInMs(short);
-    method public void setTimeOffsetInNs(double);
-    method public void setUsedInFix(boolean);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final short ADR_STATE_RESET = 2; // 0x2
-    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final short ADR_STATE_VALID = 1; // 0x1
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final short STATE_BIT_SYNC = 2; // 0x2
-    field public static final short STATE_CODE_LOCK = 1; // 0x1
-    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final short STATE_TOW_DECODED = 8; // 0x8
-    field public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+    field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+    field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+    field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+    field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+    field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public final class GnssMeasurementsEvent implements android.os.Parcelable {
@@ -20522,7 +20400,7 @@
     method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -20533,43 +20411,29 @@
     method public void onStatusChanged(int);
   }
 
-  public static abstract class GnssMeasurementsEvent.GnssMeasurementsStatus implements java.lang.annotation.Annotation {
-  }
-
   public final class GnssNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getData();
-    method public short getMessageId();
-    method public short getStatus();
-    method public short getSubmessageId();
-    method public short getSvid();
-    method public short getType();
-    method public void reset();
-    method public void set(android.location.GnssNavigationMessage);
-    method public void setData(byte[]);
-    method public void setMessageId(short);
-    method public void setStatus(short);
-    method public void setSubmessageId(short);
-    method public void setSvid(short);
-    method public void setType(short);
+    method public int getMessageId();
+    method public int getStatus();
+    method public int getSubmessageId();
+    method public int getSvid();
+    method public int getType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
-    field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
-    field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
-    field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
-    field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
-    field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
-    field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
-    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final short STATUS_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
   public final class GnssNavigationMessageEvent implements android.os.Parcelable {
@@ -20578,7 +20442,7 @@
     method public android.location.GnssNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -20589,33 +20453,27 @@
     method public void onStatusChanged(int);
   }
 
-  public static abstract class GnssNavigationMessageEvent.GnssNavigationMessageStatus implements java.lang.annotation.Annotation {
-  }
-
   public abstract interface GnssNmeaListener {
     method public abstract void onNmeaReceived(long, java.lang.String);
   }
 
   public final class GnssStatus {
-    method public float getAzimuth(int);
-    method public byte getConstellationType(int);
-    method public float getElevation(int);
+    method public float getAzimuthDegrees(int);
+    method public float getCn0DbHz(int);
+    method public int getConstellationType(int);
+    method public float getElevationDegrees(int);
     method public int getNumSatellites();
-    method public float getSnr(int);
     method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
-    field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final byte CONSTELLATION_GPS = 1; // 0x1
-    field public static final byte CONSTELLATION_QZSS = 4; // 0x4
-    field public static final byte CONSTELLATION_SBAS = 2; // 0x2
-    field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
   public abstract class GnssStatusCallback {
@@ -20974,8 +20832,8 @@
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
     method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -21004,7 +20862,7 @@
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
-    method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -21168,6 +21026,7 @@
     field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
     field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
     field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+    field public static final int TYPE_BUS = 21; // 0x15
     field public static final int TYPE_DOCK = 13; // 0xd
     field public static final int TYPE_FM = 14; // 0xe
     field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -21197,12 +21056,14 @@
     field public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR;
   }
 
-  public class AudioFormat {
+  public final class AudioFormat implements android.os.Parcelable {
+    method public int describeContents();
     method public int getChannelCount();
     method public int getChannelIndexMask();
     method public int getChannelMask();
     method public int getEncoding();
     method public int getSampleRate();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
     field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
     field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -21244,6 +21105,7 @@
     field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
     field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
     field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+    field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
     field public static final int ENCODING_AC3 = 5; // 0x5
     field public static final int ENCODING_DEFAULT = 1; // 0x1
     field public static final int ENCODING_DTS = 7; // 0x7
@@ -21254,6 +21116,7 @@
     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
+    field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
   }
 
   public static class AudioFormat.Builder {
@@ -21274,7 +21137,7 @@
     method public void adjustVolume(int, int);
     method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int generateAudioSessionId();
-    method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
+    method public android.media.AudioRecordingConfiguration[] getActiveRecordingConfigurations();
     method public android.media.AudioDeviceInfo[] getDevices(int);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
@@ -21428,7 +21291,7 @@
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged();
+    method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -21505,7 +21368,7 @@
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
-  public class AudioRecordConfiguration implements android.os.Parcelable {
+  public final class AudioRecordingConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioDeviceInfo getAudioDevice();
     method public int getClientAudioSessionId();
@@ -21513,12 +21376,13 @@
     method public android.media.AudioFormat getClientFormat();
     method public android.media.AudioFormat getFormat();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
   }
 
   public abstract interface AudioRouting {
     method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public abstract android.media.AudioDeviceInfo getPreferredDevice();
+    method public abstract android.media.AudioDeviceInfo getRoutedDevice();
     method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
   }
@@ -21688,7 +21552,6 @@
   }
 
   public abstract class DrmInitData {
-    ctor public DrmInitData();
     method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
   }
 
@@ -21699,12 +21562,15 @@
 
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+    ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public java.lang.String getAttribute(java.lang.String);
     method public double getAttributeDouble(java.lang.String, double);
     method public int getAttributeInt(java.lang.String, int);
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
+    method public long[] getThumbnailRange();
     method public boolean hasThumbnail();
     method public void saveAttributes() throws java.io.IOException;
     method public void setAttribute(java.lang.String, java.lang.String);
@@ -21717,31 +21583,130 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
-    field public static final java.lang.String TAG_APERTURE = "FNumber";
+    field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
+    field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+    field public static final java.lang.String TAG_ARTIST = "Artist";
+    field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+    field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+    field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+    field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+    field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+    field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+    field public static final java.lang.String TAG_COMPRESSION = "Compression";
+    field public static final java.lang.String TAG_CONTRAST = "Contrast";
+    field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+    field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
     field public static final java.lang.String TAG_DATETIME = "DateTime";
     field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+    field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+    field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+    field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+    field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
+    field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+    field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
+    field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+    field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
     field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+    field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
     field public static final java.lang.String TAG_FLASH = "Flash";
+    field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+    field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
     field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+    field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+    field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+    field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+    field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+    field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+    field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
     field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
     field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+    field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
     field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+    field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+    field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
     field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
     field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
     field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
     field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+    field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
     field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+    field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+    field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+    field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+    field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
     field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+    field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+    field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+    field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
     field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+    field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
     field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
-    field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
+    field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+    field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
     field public static final java.lang.String TAG_MAKE = "Make";
+    field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+    field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+    field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
     field public static final java.lang.String TAG_MODEL = "Model";
+    field public static final java.lang.String TAG_OECF = "OECF";
     field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+    field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+    field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+    field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+    field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+    field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+    field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+    field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+    field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+    field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+    field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+    field public static final java.lang.String TAG_SATURATION = "Saturation";
+    field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+    field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+    field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+    field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+    field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+    field public static final java.lang.String TAG_SOFTWARE = "Software";
+    field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+    field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+    field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+    field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+    field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+    field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
     field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
     field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+    field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
     field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+    field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+    field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
     field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+    field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+    field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+    field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+    field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+    field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+    field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
     field public static final int WHITEBALANCE_AUTO = 0; // 0x0
     field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
   }
@@ -21841,8 +21806,8 @@
 
   public class MediaActionSound {
     ctor public MediaActionSound();
-    method public synchronized void load(int);
-    method public synchronized void play(int);
+    method public void load(int);
+    method public void play(int);
     method public void release();
     field public static final int FOCUS_COMPLETE = 1; // 0x1
     field public static final int SHUTTER_CLICK = 0; // 0x0
@@ -21939,6 +21904,7 @@
     field public static final int ERROR_NO_KEY = 1; // 0x1
     field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
     field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
+    field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6
   }
 
   public static final class MediaCodec.CryptoInfo {
@@ -22096,12 +22062,13 @@
     field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
     field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
     field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
-    field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
-    field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
-    field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
-    field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
-    field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
-    field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+    field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+    field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+    field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+    field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+    field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+    field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+    field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
     field public static final int H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -22147,6 +22114,7 @@
     field public static final int HEVCMainTierLevel62 = 16777216; // 0x1000000
     field public static final int HEVCProfileMain = 1; // 0x1
     field public static final int HEVCProfileMain10 = 2; // 0x2
+    field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
     field public static final int MPEG2LevelLL = 0; // 0x0
@@ -22404,6 +22372,7 @@
     method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String) throws java.io.IOException;
+    method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
     method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
     method public void unselectTrack(int);
@@ -22464,6 +22433,7 @@
     field public static final java.lang.String KEY_DURATION = "durationUs";
     field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
     field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
+    field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
     field public static final java.lang.String KEY_HEIGHT = "height";
     field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
     field public static final java.lang.String KEY_IS_ADTS = "is-adts";
@@ -22488,6 +22458,7 @@
     field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
     field public static final java.lang.String KEY_STRIDE = "stride";
     field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+    field public static final java.lang.String KEY_TRACK_ID = "track-id";
     field public static final java.lang.String KEY_WIDTH = "width";
     field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -22687,6 +22658,7 @@
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+    method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -23764,6 +23736,7 @@
   public static class AudioMix.Builder {
     ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
+    method public android.media.audiopolicy.AudioMix.Builder setDevice(android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
   }
@@ -23836,7 +23809,7 @@
     method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(java.lang.String);
-    method public void unsubscribe(java.lang.String, android.os.Bundle);
+    method public void unsubscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
     field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
   }
@@ -24373,7 +24346,10 @@
     method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
     method public static final android.net.Uri buildRecordedProgramUri(long);
+    method public static final boolean isChannelUri(android.net.Uri);
     method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+    method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+    method public static final boolean isProgramUri(android.net.Uri);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
@@ -24467,7 +24443,8 @@
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
     field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
     field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
@@ -24477,7 +24454,9 @@
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
     field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_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_THUMBNAIL_URI = "thumbnail_uri";
@@ -24520,7 +24499,7 @@
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
     field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
@@ -24535,7 +24514,8 @@
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
     field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_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_THUMBNAIL_URI = "thumbnail_uri";
@@ -24616,6 +24596,7 @@
     method public boolean isPassthroughInput();
     method public java.lang.CharSequence loadCustomLabel(android.content.Context);
     method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
+    method public android.graphics.drawable.Drawable loadIcon(android.content.Context, int);
     method public java.lang.CharSequence loadLabel(android.content.Context);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.tv.TvInputInfo> CREATOR;
@@ -24633,11 +24614,13 @@
   }
 
   public static final class TvInputInfo.Builder {
-    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
     method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
     method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
     method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
+    method public android.media.tv.TvInputInfo.Builder setLabel(java.lang.CharSequence);
     method public android.media.tv.TvInputInfo.Builder setLabel(int);
     method public android.media.tv.TvInputInfo.Builder setParentId(java.lang.String);
     method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -24652,11 +24635,9 @@
   }
 
   public final class TvInputManager {
-    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputInfo, android.media.tv.TvInputManager.HardwareCallback);
     method public void addBlockedRating(android.media.tv.TvContentRating);
     method public boolean captureFrame(java.lang.String, android.view.Surface, android.media.tv.TvStreamConfig);
-    method public void createRecordingSession(java.lang.String, android.media.tv.TvInputManager.SessionCallback, android.os.Handler);
-    method public void createSession(java.lang.String, android.media.tv.TvInputManager.SessionCallback, android.os.Handler);
     method public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(java.lang.String);
     method public java.util.List<android.media.tv.TvContentRating> getBlockedRatings();
     method public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
@@ -24675,6 +24656,7 @@
     field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
     field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
     field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
+    field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
     field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -24707,39 +24689,6 @@
     method public abstract void onStreamConfigChanged(android.media.tv.TvStreamConfig[]);
   }
 
-  public static final class TvInputManager.Session {
-    method public void dispatchSurfaceChanged(int, int, int);
-    method public java.lang.String getSelectedTrack(int);
-    method public java.util.List<android.media.tv.TvTrackInfo> getTracks(int);
-    method public void release();
-    method public void selectTrack(int, java.lang.String);
-    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
-    method public void setCaptionEnabled(boolean);
-    method public void setStreamVolume(float);
-    method public void setSurface(android.view.Surface);
-    method public void tune(android.net.Uri);
-    method public void tune(android.net.Uri, android.os.Bundle);
-  }
-
-  public static abstract class TvInputManager.SessionCallback {
-    ctor public TvInputManager.SessionCallback();
-    method public void onChannelRetuned(android.media.tv.TvInputManager.Session, android.net.Uri);
-    method public void onContentAllowed(android.media.tv.TvInputManager.Session);
-    method public void onContentBlocked(android.media.tv.TvInputManager.Session, android.media.tv.TvContentRating);
-    method public void onLayoutSurface(android.media.tv.TvInputManager.Session, int, int, int, int);
-    method public void onSessionCreated(android.media.tv.TvInputManager.Session);
-    method public void onSessionEvent(android.media.tv.TvInputManager.Session, java.lang.String, android.os.Bundle);
-    method public void onSessionReleased(android.media.tv.TvInputManager.Session);
-    method public void onTimeShiftCurrentPositionChanged(android.media.tv.TvInputManager.Session, long);
-    method public void onTimeShiftStartPositionChanged(android.media.tv.TvInputManager.Session, long);
-    method public void onTimeShiftStatusChanged(android.media.tv.TvInputManager.Session, int);
-    method public void onTrackSelected(android.media.tv.TvInputManager.Session, int, java.lang.String);
-    method public void onTracksChanged(android.media.tv.TvInputManager.Session, java.util.List<android.media.tv.TvTrackInfo>);
-    method public void onVideoAvailable(android.media.tv.TvInputManager.Session);
-    method public void onVideoSizeChanged(android.media.tv.TvInputManager.Session, int, int);
-    method public void onVideoUnavailable(android.media.tv.TvInputManager.Session, int);
-  }
-
   public static abstract class TvInputManager.TvInputCallback {
     ctor public TvInputManager.TvInputCallback();
     method public void onInputAdded(java.lang.String);
@@ -24776,7 +24725,7 @@
     method public void notifyError(int);
     method public void notifyRecordingStopped(android.net.Uri);
     method public void notifySessionEvent(java.lang.String, android.os.Bundle);
-    method public void notifyTuned();
+    method public void notifyTuned(android.net.Uri);
     method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public abstract void onRelease();
     method public abstract void onStartRecording(android.net.Uri);
@@ -24844,7 +24793,7 @@
     method public void onError(int);
     method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
     method public void onRecordingStopped(android.net.Uri);
-    method public void onTuned();
+    method public void onTuned(android.net.Uri);
   }
 
   public class TvStreamConfig implements android.os.Parcelable {
@@ -24918,7 +24867,6 @@
     method public java.util.List<android.media.tv.TvTrackInfo> getTracks(int);
     method protected void onLayout(boolean, int, int, int, int);
     method public boolean onUnhandledInputEvent(android.view.InputEvent);
-    method public deprecated void requestUnblockContent(android.media.tv.TvContentRating);
     method public void reset();
     method public void selectTrack(int, java.lang.String);
     method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
@@ -25239,6 +25187,7 @@
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
     method public boolean isTetheringSupported();
+    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.app.PendingIntent);
     method public void releaseNetworkRequest(android.app.PendingIntent);
@@ -25319,7 +25268,7 @@
     method public int getUid();
   }
 
-  public class DataUsageRequest implements android.os.Parcelable {
+  public final class DataUsageRequest implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR;
@@ -25667,9 +25616,11 @@
 
   public class ScoredNetwork implements android.os.Parcelable {
     ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve);
+    ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
+    field public final boolean meteredHint;
     field public final android.net.NetworkKey networkKey;
     field public final android.net.RssiCurve rssiCurve;
   }
@@ -26714,7 +26665,6 @@
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean saveConfiguration();
-    method public boolean setMetered(int, boolean);
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -26818,7 +26768,9 @@
     method public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
     method public boolean getScanResults();
     method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+    method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
     method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+    method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
     method public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
     method public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
     method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
@@ -26827,6 +26779,7 @@
     method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
     field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
     field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
+    field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
     field public static final int REASON_INVALID_LISTENER = -2; // 0xfffffffe
     field public static final int REASON_INVALID_REQUEST = -3; // 0xfffffffd
     field public static final int REASON_NOT_AUTHORIZED = -4; // 0xfffffffc
@@ -29117,7 +29070,8 @@
     method public static void glGetSynciv(long, int, int, int[], int, int[], int);
     method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static deprecated void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static int glGetUniformBlockIndex(int, java.lang.String);
@@ -29143,6 +29097,7 @@
     method public static void glProgramBinary(int, int, java.nio.Buffer, int);
     method public static void glProgramParameteri(int, int, int);
     method public static void glReadBuffer(int);
+    method public static void glReadPixels(int, int, int, int, int, int, int);
     method public static void glRenderbufferStorageMultisample(int, int, int, int, int);
     method public static void glResumeTransformFeedback();
     method public static void glSamplerParameterf(int, int, float);
@@ -30728,6 +30683,10 @@
     ctor public DeadObjectException(java.lang.String);
   }
 
+  public class DeadSystemException extends android.os.DeadObjectException {
+    ctor public DeadSystemException();
+  }
+
   public final class Debug {
     method public static deprecated void changeDebugPort(int);
     method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
@@ -30981,14 +30940,17 @@
 
   public class HardwarePropertiesManager {
     method public android.os.CpuUsageInfo[] getCpuUsages();
-    method public float[] getDeviceTemperatures(int);
+    method public float[] getDeviceTemperatures(int, int);
     method public float[] getFanSpeeds();
     field public static final int DEVICE_TEMPERATURE_BATTERY = 2; // 0x2
     field public static final int DEVICE_TEMPERATURE_CPU = 0; // 0x0
     field public static final int DEVICE_TEMPERATURE_GPU = 1; // 0x1
-  }
-
-  public static abstract class HardwarePropertiesManager.DeviceTemperatureType implements java.lang.annotation.Annotation {
+    field public static final int DEVICE_TEMPERATURE_SKIN = 3; // 0x3
+    field public static final int TEMPERATURE_CURRENT = 0; // 0x0
+    field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
+    field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+    field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
+    field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
   }
 
   public abstract interface IBinder {
@@ -31348,6 +31310,7 @@
     method public boolean isPowerSaveMode();
     method public boolean isScreenBrightnessBoosted();
     method public deprecated boolean isScreenOn();
+    method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
@@ -31364,6 +31327,7 @@
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
     field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
+    field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
     field public static final int USER_ACTIVITY_EVENT_TOUCH = 2; // 0x2
@@ -31384,7 +31348,10 @@
   public class Process {
     ctor public Process();
     method public static final long getElapsedCpuTime();
+    method public static final int[] getExclusiveCores();
     method public static final int getGidForName(java.lang.String);
+    method public static final long getStartElapsedRealtime();
+    method public static final long getStartUptimeMillis();
     method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
     method public static final int getUidForName(java.lang.String);
     method public static final boolean is64Bit();
@@ -31418,9 +31385,14 @@
   }
 
   public class RecoverySystem {
+    method public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
     method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
+    method public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
+    method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
+    method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
     method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
     method public static void rebootWipeUserData(android.content.Context) throws java.io.IOException;
+    method public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
     method public static void verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File) throws java.security.GeneralSecurityException, java.io.IOException;
   }
 
@@ -31568,12 +31540,13 @@
 
   public class UpdateEngine {
     ctor public UpdateEngine();
-    method public void applyPayload(java.lang.String, long, long, java.lang.String[]) throws android.os.RemoteException;
-    method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler) throws android.os.RemoteException;
-    method public boolean bind(android.os.UpdateEngineCallback) throws android.os.RemoteException;
-    method public void cancel() throws android.os.RemoteException;
-    method public void resume() throws android.os.RemoteException;
-    method public void suspend() throws android.os.RemoteException;
+    method public void applyPayload(java.lang.String, long, long, java.lang.String[]);
+    method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
+    method public boolean bind(android.os.UpdateEngineCallback);
+    method public void cancel();
+    method public void resetStatus();
+    method public void resume();
+    method public void suspend();
   }
 
   public static final class UpdateEngine.ErrorCodeConstants {
@@ -31644,14 +31617,11 @@
     method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(java.lang.String);
     method public boolean isManagedProfile();
+    method public boolean isManagedProfile(int);
     method public boolean isQuietModeEnabled(android.os.UserHandle);
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
     method public boolean isUserRunning(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
     method public boolean isUserUnlocked();
     method public boolean isUserUnlocked(android.os.UserHandle);
@@ -31722,6 +31692,147 @@
 
 }
 
+package android.os.health {
+
+  public class HealthStats {
+    method public java.lang.String getDataType();
+    method public long getMeasurement(int);
+    method public int getMeasurementKeyAt(int);
+    method public int getMeasurementKeyCount();
+    method public java.util.Map<java.lang.String, java.lang.Long> getMeasurements(int);
+    method public int getMeasurementsKeyAt(int);
+    method public int getMeasurementsKeyCount();
+    method public java.util.Map<java.lang.String, android.os.health.HealthStats> getStats(int);
+    method public int getStatsKeyAt(int);
+    method public int getStatsKeyCount();
+    method public android.os.health.TimerStat getTimer(int);
+    method public int getTimerCount(int);
+    method public int getTimerKeyAt(int);
+    method public int getTimerKeyCount();
+    method public long getTimerTime(int);
+    method public java.util.Map<java.lang.String, android.os.health.TimerStat> getTimers(int);
+    method public int getTimersKeyAt(int);
+    method public int getTimersKeyCount();
+    method public boolean hasMeasurement(int);
+    method public boolean hasMeasurements(int);
+    method public boolean hasStats(int);
+    method public boolean hasTimer(int);
+    method public boolean hasTimers(int);
+  }
+
+  public final class PackageHealthStats {
+    field public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = 40002; // 0x9c42
+    field public static final int STATS_SERVICES = 40001; // 0x9c41
+  }
+
+  public final class PidHealthStats {
+    field public static final int MEASUREMENT_WAKE_NESTING_COUNT = 20001; // 0x4e21
+    field public static final int MEASUREMENT_WAKE_START_MS = 20003; // 0x4e23
+    field public static final int MEASUREMENT_WAKE_SUM_MS = 20002; // 0x4e22
+  }
+
+  public final class ProcessHealthStats {
+    field public static final int MEASUREMENT_ANR_COUNT = 30005; // 0x7535
+    field public static final int MEASUREMENT_CRASHES_COUNT = 30004; // 0x7534
+    field public static final int MEASUREMENT_FOREGROUND_MS = 30006; // 0x7536
+    field public static final int MEASUREMENT_STARTS_COUNT = 30003; // 0x7533
+    field public static final int MEASUREMENT_SYSTEM_TIME_MS = 30002; // 0x7532
+    field public static final int MEASUREMENT_USER_TIME_MS = 30001; // 0x7531
+  }
+
+  public final class ServiceHealthStats {
+    field public static final int MEASUREMENT_LAUNCH_COUNT = 50002; // 0xc352
+    field public static final int MEASUREMENT_START_SERVICE_COUNT = 50001; // 0xc351
+  }
+
+  public class SystemHealthManager {
+    method public static android.os.health.SystemHealthManager from(android.content.Context);
+    method public android.os.health.HealthStats takeMyUidSnapshot();
+    method public android.os.health.HealthStats takeUidSnapshot(int);
+    method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
+  }
+
+  public final class TimerStat implements android.os.Parcelable {
+    ctor public TimerStat();
+    ctor public TimerStat(int, long);
+    ctor public TimerStat(android.os.Parcel);
+    method public int describeContents();
+    method public int getCount();
+    method public long getTime();
+    method public void setCount(int);
+    method public void setTime(long);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.health.TimerStat> CREATOR;
+  }
+
+  public final class UidHealthStats {
+    field public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = 10020; // 0x2724
+    field public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = 10023; // 0x2727
+    field public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = 10052; // 0x2744
+    field public static final int MEASUREMENT_BLUETOOTH_RX_MS = 10021; // 0x2725
+    field public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = 10058; // 0x274a
+    field public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = 10053; // 0x2745
+    field public static final int MEASUREMENT_BLUETOOTH_TX_MS = 10022; // 0x2726
+    field public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = 10059; // 0x274b
+    field public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = 10046; // 0x273e
+    field public static final int MEASUREMENT_CPU_POWER_MAUS = 10064; // 0x2750
+    field public static final int MEASUREMENT_MOBILE_IDLE_MS = 10024; // 0x2728
+    field public static final int MEASUREMENT_MOBILE_POWER_MAMS = 10027; // 0x272b
+    field public static final int MEASUREMENT_MOBILE_RX_BYTES = 10048; // 0x2740
+    field public static final int MEASUREMENT_MOBILE_RX_MS = 10025; // 0x2729
+    field public static final int MEASUREMENT_MOBILE_RX_PACKETS = 10054; // 0x2746
+    field public static final int MEASUREMENT_MOBILE_TX_BYTES = 10049; // 0x2741
+    field public static final int MEASUREMENT_MOBILE_TX_MS = 10026; // 0x272a
+    field public static final int MEASUREMENT_MOBILE_TX_PACKETS = 10055; // 0x2747
+    field public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = 10045; // 0x273d
+    field public static final int MEASUREMENT_REALTIME_BATTERY_MS = 10001; // 0x2711
+    field public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = 10003; // 0x2713
+    field public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = 10063; // 0x274f
+    field public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = 10047; // 0x273f
+    field public static final int MEASUREMENT_UPTIME_BATTERY_MS = 10002; // 0x2712
+    field public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = 10004; // 0x2714
+    field public static final int MEASUREMENT_USER_CPU_TIME_US = 10062; // 0x274e
+    field public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = 10029; // 0x272d
+    field public static final int MEASUREMENT_WIFI_IDLE_MS = 10016; // 0x2720
+    field public static final int MEASUREMENT_WIFI_MULTICAST_MS = 10031; // 0x272f
+    field public static final int MEASUREMENT_WIFI_POWER_MAMS = 10019; // 0x2723
+    field public static final int MEASUREMENT_WIFI_RUNNING_MS = 10028; // 0x272c
+    field public static final int MEASUREMENT_WIFI_RX_BYTES = 10050; // 0x2742
+    field public static final int MEASUREMENT_WIFI_RX_MS = 10017; // 0x2721
+    field public static final int MEASUREMENT_WIFI_RX_PACKETS = 10056; // 0x2748
+    field public static final int MEASUREMENT_WIFI_TX_BYTES = 10051; // 0x2743
+    field public static final int MEASUREMENT_WIFI_TX_MS = 10018; // 0x2722
+    field public static final int MEASUREMENT_WIFI_TX_PACKETS = 10057; // 0x2749
+    field public static final int STATS_PACKAGES = 10015; // 0x271f
+    field public static final int STATS_PIDS = 10013; // 0x271d
+    field public static final int STATS_PROCESSES = 10014; // 0x271e
+    field public static final int TIMERS_JOBS = 10010; // 0x271a
+    field public static final int TIMERS_SENSORS = 10012; // 0x271c
+    field public static final int TIMERS_SYNCS = 10009; // 0x2719
+    field public static final int TIMERS_WAKELOCKS_DRAW = 10008; // 0x2718
+    field public static final int TIMERS_WAKELOCKS_FULL = 10005; // 0x2715
+    field public static final int TIMERS_WAKELOCKS_PARTIAL = 10006; // 0x2716
+    field public static final int TIMERS_WAKELOCKS_WINDOW = 10007; // 0x2717
+    field public static final int TIMER_AUDIO = 10032; // 0x2730
+    field public static final int TIMER_BLUETOOTH_SCAN = 10037; // 0x2735
+    field public static final int TIMER_CAMERA = 10035; // 0x2733
+    field public static final int TIMER_FLASHLIGHT = 10034; // 0x2732
+    field public static final int TIMER_FOREGROUND_ACTIVITY = 10036; // 0x2734
+    field public static final int TIMER_GPS_SENSOR = 10011; // 0x271b
+    field public static final int TIMER_MOBILE_RADIO_ACTIVE = 10061; // 0x274d
+    field public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = 10042; // 0x273a
+    field public static final int TIMER_PROCESS_STATE_CACHED_MS = 10043; // 0x273b
+    field public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = 10041; // 0x2739
+    field public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = 10039; // 0x2737
+    field public static final int TIMER_PROCESS_STATE_TOP_MS = 10038; // 0x2736
+    field public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = 10040; // 0x2738
+    field public static final int TIMER_VIBRATOR = 10044; // 0x273c
+    field public static final int TIMER_VIDEO = 10033; // 0x2731
+    field public static final int TIMER_WIFI_SCAN = 10030; // 0x272e
+  }
+
+}
+
 package android.os.storage {
 
   public abstract class OnObbStateChangeListener {
@@ -31739,14 +31850,15 @@
 
   public class StorageManager {
     method public java.lang.String getMountedObbPath(java.lang.String);
-    method public android.os.storage.StorageVolume getPrimaryVolume();
-    method public android.os.storage.StorageVolume[] getVolumeList();
+    method public android.os.storage.StorageVolume getPrimaryStorageVolume();
+    method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+    method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
   }
 
-  public class StorageVolume implements android.os.Parcelable {
+  public final class StorageVolume implements android.os.Parcelable {
     method public android.content.Intent createAccessIntent(java.lang.String);
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
@@ -31874,6 +31986,7 @@
     method protected int getPersistedInt(int);
     method protected long getPersistedLong(long);
     method protected java.lang.String getPersistedString(java.lang.String);
+    method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
     method public android.preference.PreferenceManager getPreferenceManager();
     method public android.content.SharedPreferences getSharedPreferences();
     method public boolean getShouldDisableView();
@@ -31895,7 +32008,6 @@
     method protected void onClick();
     method protected android.view.View onCreateView(android.view.ViewGroup);
     method public void onDependencyChanged(android.preference.Preference, boolean);
-    method protected void onDetachedFromActivity();
     method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
     method public void onParentChanged(android.preference.Preference, boolean);
     method protected void onPrepareForRemoval();
@@ -31908,6 +32020,7 @@
     method protected boolean persistInt(int);
     method protected boolean persistLong(long);
     method protected boolean persistString(java.lang.String);
+    method public boolean persistStringSet(java.util.Set<java.lang.String>);
     method public void restoreHierarchyState(android.os.Bundle);
     method public void saveHierarchyState(android.os.Bundle);
     method public void setDefaultValue(java.lang.Object);
@@ -32065,13 +32178,16 @@
     method public android.content.SharedPreferences getSharedPreferences();
     method public int getSharedPreferencesMode();
     method public java.lang.String getSharedPreferencesName();
+    method public boolean isStorageCredentialProtected();
+    method public boolean isStorageDefault();
+    method public boolean isStorageDeviceProtected();
     method public static void setDefaultValues(android.content.Context, int, boolean);
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
-    method public void setStorageCredentialEncrypted();
+    method public void setStorageCredentialProtected();
     method public void setStorageDefault();
-    method public void setStorageDeviceEncrypted();
+    method public void setStorageDeviceProtected();
     field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
     field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
   }
@@ -32441,7 +32557,7 @@
     method public android.print.PrinterInfo build();
     method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
     method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
-    method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+    method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon(boolean);
     method public android.print.PrinterInfo.Builder setIconResourceId(int);
     method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
     method public android.print.PrinterInfo.Builder setName(java.lang.String);
@@ -32493,6 +32609,7 @@
     method public boolean isStarted();
     method public void setProgress(float);
     method public void setStatus(java.lang.CharSequence);
+    method public void setStatus(int);
     method public boolean setTag(java.lang.String);
     method public boolean start();
   }
@@ -32523,7 +32640,7 @@
     method public final boolean isDestroyed();
     method public final boolean isPrinterDiscoveryStarted();
     method public abstract void onDestroy();
-    method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+    method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
     method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
     method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
     method public abstract void onStopPrinterDiscovery();
@@ -32534,6 +32651,29 @@
 
 }
 
+package android.printservice.recommendation {
+
+  public final class RecommendationInfo implements android.os.Parcelable {
+    ctor public RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, int, boolean);
+    method public int describeContents();
+    method public java.lang.CharSequence getName();
+    method public int getNumDiscoveredPrinters();
+    method public java.lang.CharSequence getPackageName();
+    method public boolean recommendsMultiVendorService();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.printservice.recommendation.RecommendationInfo> CREATOR;
+  }
+
+  public abstract class RecommendationService extends android.app.Service {
+    ctor public RecommendationService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onConnected();
+    method public abstract void onDisconnected();
+    method public final void updateRecommendations(java.util.List<android.printservice.recommendation.RecommendationInfo>);
+  }
+
+}
+
 package android.provider {
 
   public final class AlarmClock {
@@ -32569,6 +32709,7 @@
   public class BlockedNumberContract {
     method public static boolean canCurrentUserBlockNumbers(android.content.Context);
     method public static boolean isBlocked(android.content.Context, java.lang.String);
+    method public static int unblock(android.content.Context, java.lang.String);
     field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
     field public static final android.net.Uri AUTHORITY_URI;
   }
@@ -32578,7 +32719,7 @@
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
     field public static final android.net.Uri CONTENT_URI;
   }
 
@@ -32882,6 +33023,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -32904,6 +33046,7 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final java.lang.String FEATURES = "features";
+    field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
@@ -32926,6 +33069,7 @@
     field public static final int REJECTED_TYPE = 5; // 0x5
     field public static final java.lang.String TRANSCRIPTION = "transcription";
     field public static final java.lang.String TYPE = "type";
+    field public static final java.lang.String VIA_NUMBER = "via_number";
     field public static final int VOICEMAIL_TYPE = 4; // 0x4
     field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
   }
@@ -34106,6 +34250,7 @@
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
     field public static final java.lang.String EXTRA_LOADING = "loading";
+    field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
     field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
   }
@@ -34135,6 +34280,7 @@
 
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
     field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
     field public static final java.lang.String COLUMN_FLAGS = "flags";
     field public static final java.lang.String COLUMN_ICON = "icon";
@@ -34653,13 +34799,13 @@
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
+    field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
     field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
-    field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
     field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
     field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -34678,7 +34824,6 @@
     field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
     field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
     field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
-    field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
     field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
     field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -34691,6 +34836,8 @@
     field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
     field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
     field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+    field public static final java.lang.String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
+    field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
     field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
@@ -34728,6 +34875,7 @@
     field public static final java.lang.String AUTO_TIME = "auto_time";
     field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+    field public static final java.lang.String BOOT_COUNT = "boot_count";
     field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_ROAMING = "data_roaming";
@@ -34751,6 +34899,7 @@
     field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
     field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+    field public static final java.lang.String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
     field public static final java.lang.String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN = "wifi_device_owner_configs_lockdown";
     field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
     field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
@@ -36601,6 +36750,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -36618,6 +36768,7 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
     method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
     method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -36644,6 +36795,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isInsideSecureHardware();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -36707,6 +36859,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -36718,6 +36871,7 @@
     method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -36756,7 +36910,8 @@
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -36767,6 +36922,9 @@
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+    field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
     field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -36871,7 +37029,6 @@
     method public boolean onMenuOpened(int, android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public boolean onSearchRequested(android.view.SearchEvent);
     method public boolean onSearchRequested();
     method public void onWakeUp();
@@ -36935,8 +37092,9 @@
 package android.service.notification {
 
   public class Condition implements android.os.Parcelable {
-    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int);
+    ctor public Condition(android.net.Uri, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
+    ctor public Condition(android.os.Parcel);
     method public android.service.notification.Condition copy();
     method public int describeContents();
     method public static boolean isValidId(android.net.Uri, java.lang.String);
@@ -36977,36 +37135,6 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
-  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
-    ctor public NotificationAssistantService();
-    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
-    method public void onNotificationActionClick(java.lang.String, long, int);
-    method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
-    method public void onNotificationRemoved(java.lang.String, long, int);
-    method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
-    field public static final int REASON_APP_CANCEL = 8; // 0x8
-    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
-    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
-    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
-    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
-    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
-    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
-    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
-    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
-    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
-    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
-    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
-    field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
-    field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
-    field public static final int REASON_USER_STOPPED = 6; // 0x6
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
-  }
-
-  public class NotificationAssistantService.Adjustment {
-    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
-  }
-
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -37032,12 +37160,11 @@
     method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
-    method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
+    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
     method public final void requestUnbind() throws android.os.RemoteException;
     method public final void setNotificationsShown(java.lang.String[]);
     method public final void setOnNotificationPostedTrim(int);
     method public void unregisterAsSystemService() throws android.os.RemoteException;
-    field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
     field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
     field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -37060,10 +37187,11 @@
     method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
-    field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
-    field public static final int IMPORTANCE_HIGH = 3; // 0x3
-    field public static final int IMPORTANCE_LOW = 1; // 0x1
-    field public static final int IMPORTANCE_MAX = 4; // 0x4
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
     field public static final int IMPORTANCE_NONE = 0; // 0x0
     field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
   }
@@ -37076,6 +37204,37 @@
     field public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR;
   }
 
+  public abstract class NotificationRankerService extends android.service.notification.NotificationListenerService {
+    ctor public NotificationRankerService();
+    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationRankerService.Adjustment);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onNotificationActionClick(java.lang.String, long, int);
+    method public void onNotificationClick(java.lang.String, long);
+    method public abstract android.service.notification.NotificationRankerService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public void onNotificationRemoved(java.lang.String, long, int);
+    method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
+    field public static final int REASON_APP_CANCEL = 8; // 0x8
+    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+    field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+    field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+    field public static final int REASON_USER_STOPPED = 6; // 0x6
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationRankerService";
+  }
+
+  public class NotificationRankerService.Adjustment {
+    ctor public NotificationRankerService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+  }
+
   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);
@@ -37102,6 +37261,7 @@
 
   public abstract interface IPersistentDataBlockService implements android.os.IInterface {
     method public abstract int getDataBlockSize() throws android.os.RemoteException;
+    method public abstract int getFlashLockState() throws android.os.RemoteException;
     method public abstract long getMaximumDataBlockSize() throws android.os.RemoteException;
     method public abstract boolean getOemUnlockEnabled() throws android.os.RemoteException;
     method public abstract byte[] read() throws android.os.RemoteException;
@@ -37113,12 +37273,19 @@
   public class PersistentDataBlockManager {
     ctor public PersistentDataBlockManager(android.service.persistentdata.IPersistentDataBlockService);
     method public int getDataBlockSize();
+    method public int getFlashLockState();
     method public long getMaximumDataBlockSize();
     method public boolean getOemUnlockEnabled();
     method public byte[] read();
     method public void setOemUnlockEnabled(boolean);
     method public void wipe();
     method public int write(byte[]);
+    field public static final int FLASH_LOCK_LOCKED = 1; // 0x1
+    field public static final int FLASH_LOCK_UNKNOWN = -1; // 0xffffffff
+    field public static final int FLASH_LOCK_UNLOCKED = 0; // 0x0
+  }
+
+  public static abstract class PersistentDataBlockManager.FlashLockState implements java.lang.annotation.Annotation {
   }
 
 }
@@ -37381,6 +37548,18 @@
 
 }
 
+package android.service.vr {
+
+  public abstract class VrListenerService extends android.app.Service {
+    ctor public VrListenerService();
+    method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onCurrentVrActivityChanged(android.content.ComponentName);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+  }
+
+}
+
 package android.service.wallpaper {
 
   public abstract class WallpaperService extends android.app.Service {
@@ -38392,10 +38571,14 @@
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
+    method public final void putExtras(android.os.Bundle);
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
+    method public final void removeExtras(java.util.List<java.lang.String>);
     method public deprecated void removeListener(android.telecom.Call.Listener);
+    method public void sendCallEvent(java.lang.String, android.os.Bundle);
     method public void splitFromConference();
     method public void stopDtmfTone();
     method public void swapConference();
@@ -38410,6 +38593,7 @@
     field public static final int STATE_HOLDING = 3; // 0x3
     field public static final int STATE_NEW = 0; // 0x0
     field public static final deprecated int STATE_PRE_DIAL_WAIT = 8; // 0x8
+    field public static final int STATE_PULLING_CALL = 11; // 0xb
     field public static final int STATE_RINGING = 2; // 0x2
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
   }
@@ -38420,6 +38604,7 @@
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -38450,6 +38635,7 @@
     method public static java.lang.String propertiesToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
     field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -38469,6 +38655,7 @@
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
     field public static final int PROPERTY_WIFI = 8; // 0x8
     field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
@@ -38526,6 +38713,7 @@
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final deprecated long getConnectTimeMillis();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final long getConnectionTime();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -38540,6 +38728,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onConnectionAdded(android.telecom.Connection);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onMerge(android.telecom.Connection);
     method public void onMerge();
@@ -38548,15 +38737,18 @@
     method public void onStopDtmfTone();
     method public void onSwap();
     method public void onUnhold();
+    method public final void putExtras(android.os.Bundle);
     method public final void removeConnection(android.telecom.Connection);
+    method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void setActive();
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final deprecated void setConnectTimeMillis(long);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setConnectionTime(long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setOnHold();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -38583,6 +38775,7 @@
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public final int getState();
@@ -38594,15 +38787,23 @@
     method public void onAnswer();
     method public deprecated void onAudioStateChanged(android.telecom.AudioState);
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+    method public void onCallEvent(java.lang.String, android.os.Bundle);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onPlayDtmfTone(char);
     method public void onPostDialContinue(boolean);
+    method public void onPullExternalCall();
     method public void onReject();
+    method public void onReject(java.lang.String);
     method public void onSeparate();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
+    method public static java.lang.String propertiesToString(int);
+    method public final void putExtras(android.os.Bundle);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
@@ -38610,9 +38811,10 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setNextPostDialChar(char);
@@ -38626,6 +38828,8 @@
     method public static java.lang.String stateToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
+    field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -38642,15 +38846,18 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
     field public static final int STATE_HOLDING = 5; // 0x5
     field public static final int STATE_INITIALIZING = 0; // 0x0
     field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_PULLING_CALL = 7; // 0x7
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
@@ -38705,6 +38912,7 @@
     method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
     method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public final java.util.Collection<android.telecom.Conference> getAllConferences();
     method public final java.util.Collection<android.telecom.Connection> getAllConnections();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
@@ -38727,7 +38935,9 @@
     method public java.lang.String getReason();
     method public int getTone();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
     field public static final int BUSY = 7; // 0x7
+    field public static final int CALL_PULLED = 12; // 0xc
     field public static final int CANCELED = 4; // 0x4
     field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
     field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR;
@@ -38764,6 +38974,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public deprecated void onPhoneCreated(android.telecom.Phone);
     method public deprecated void onPhoneDestroyed(android.telecom.Phone);
     method public void onSilenceRinger();
@@ -38917,6 +39128,7 @@
     method public void disconnect();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final java.util.List<android.telecom.RemoteConnection> getConnections();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
@@ -38940,6 +39152,7 @@
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
     method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onDestroyed(android.telecom.RemoteConference);
     method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -38958,6 +39171,7 @@
     method public android.telecom.RemoteConference getConference();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public int getConnectionCapabilities();
+    method public int getConnectionProperties();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public int getState();
@@ -38969,6 +39183,7 @@
     method public boolean isVoipAudioMode();
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
     method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
@@ -38986,6 +39201,8 @@
     method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
     method public void onDestroyed(android.telecom.RemoteConnection);
     method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
     method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -39047,6 +39264,7 @@
     method public void cancelMissedCallsNotification();
     method public deprecated void clearAccounts();
     method public void clearPhoneAccounts();
+    method public android.content.Intent createManageBlockedNumbersIntent();
     method public java.util.List<android.telecom.ParcelableCallAnalytics> dumpAnalytics();
     method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
     method public boolean endCall();
@@ -39072,7 +39290,6 @@
     method public boolean isRinging();
     method public boolean isTtySupported();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public void launchManageBlockedNumbersActivity();
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
@@ -39109,6 +39326,7 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+    field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -39157,17 +39375,18 @@
 package android.telephony {
 
   public class CarrierConfigManager {
+    method public android.os.PersistableBundle getConfig(int);
     method public android.os.PersistableBundle getConfig();
-    method public android.os.PersistableBundle getConfigForSubId(int);
+    method public deprecated android.os.PersistableBundle getConfigForSubId(int);
     method public static android.os.PersistableBundle getDefaultConfig();
-    method public void notifyConfigChangedForSubId(int);
+    method public void notifyConfigChanged(int);
+    method public deprecated void notifyConfigChangedForSubId(int);
     method public void updateConfigForPhoneId(int, java.lang.String);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
-    field public static final java.lang.String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS = "bool_allow_emergency_video_calls";
-    field public static final java.lang.String BOOL_ALLOW_VIDEO_PAUSE = "bool_allow_video_pause";
     field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
     field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
     field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
+    field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
     field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
     field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
@@ -39189,6 +39408,7 @@
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
     field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+    field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -39250,6 +39470,7 @@
     field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+    field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
@@ -39783,7 +40004,8 @@
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
     method public java.lang.String getGroupIdLevel1(int);
-    method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+    method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+    method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
     method public java.lang.String getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
     method public java.lang.String getLine1Number(int);
@@ -39820,12 +40042,18 @@
     method public boolean handlePinMmi(java.lang.String);
     method public boolean handlePinMmiForSubscriber(int, java.lang.String);
     method public boolean hasCarrierPrivileges();
+    method public boolean hasCarrierPrivileges(int);
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
+    method public boolean iccCloseLogicalChannel(int, int);
     method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+    method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+    method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
     method public boolean isDataConnectivityPossible();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isIdle();
@@ -39843,12 +40071,15 @@
     method public void listen(android.telephony.PhoneStateListener, int);
     method public boolean needsOtaServiceProvisioning();
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
     method public void setDataEnabled(boolean);
     method public void setDataEnabled(int, boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
+    method public boolean setOperatorBrandOverride(int, java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
+    method public boolean setPreferredNetworkTypeToGlobal(int);
     method public boolean setRadio(boolean);
     method public boolean setRadioPower(boolean);
     method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
@@ -39864,6 +40095,13 @@
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
+    field public static final int APPTYPE_CSIM = 4; // 0x4
+    field public static final int APPTYPE_ISIM = 5; // 0x5
+    field public static final int APPTYPE_RUIM = 3; // 0x3
+    field public static final int APPTYPE_SIM = 1; // 0x1
+    field public static final int APPTYPE_USIM = 2; // 0x2
+    field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+    field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -40378,8 +40616,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedStorageContext();
-    method public android.content.Context createDeviceEncryptedStorageContext();
+    method public android.content.Context createCredentialProtectedStorageContext();
+    method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -40421,8 +40659,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -40430,10 +40666,10 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncryptedStorage();
-    method public boolean isDeviceEncryptedStorage();
-    method public boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public boolean isCredentialProtectedStorage();
+    method public boolean isDeviceProtectedStorage();
+    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -41247,7 +41483,6 @@
     method public boolean hasNext();
     method public java.util.Iterator<java.lang.String> iterator();
     method public java.lang.String next();
-    method public void remove();
     method public void setString(java.lang.String);
   }
 
@@ -42265,8 +42500,10 @@
     method public static final boolean addLinks(android.widget.TextView, int);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
     field public static final int ALL = 15; // 0xf
     field public static final int EMAIL_ADDRESSES = 2; // 0x2
     field public static final int MAP_ADDRESSES = 8; // 0x8
@@ -42859,6 +43096,7 @@
     method public int describeContents();
     method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getAdjustedDefault();
     method public static android.util.LocaleList getDefault();
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -44153,9 +44391,11 @@
   }
 
   public final class KeyboardShortcutInfo implements android.os.Parcelable {
+    ctor public KeyboardShortcutInfo(java.lang.CharSequence, int, int);
     ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
     method public int describeContents();
     method public char getBaseCharacter();
+    method public int getKeycode();
     method public java.lang.CharSequence getLabel();
     method public int getModifiers();
     method public void writeToParcel(android.os.Parcel, int);
@@ -44783,6 +45023,7 @@
     method public boolean dispatchDragEvent(android.view.DragEvent);
     method protected void dispatchDraw(android.graphics.Canvas);
     method public void dispatchDrawableHotspotChanged(float, float);
+    method public void dispatchFinishTemporaryDetach();
     method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -44802,6 +45043,7 @@
     method protected void dispatchSetActivated(boolean);
     method protected void dispatchSetPressed(boolean);
     method protected void dispatchSetSelected(boolean);
+    method public void dispatchStartTemporaryDetach();
     method public void dispatchSystemUiVisibilityChanged(int);
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -44819,6 +45061,7 @@
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
+    method public void forceHasOverlappingRendering(boolean);
     method public void forceLayout();
     method public static int generateViewId();
     method public java.lang.CharSequence getAccessibilityClassName();
@@ -44864,6 +45107,7 @@
     method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
     method public final boolean getGlobalVisibleRect(android.graphics.Rect);
     method public android.os.Handler getHandler();
+    method public final boolean getHasOverlappingRendering();
     method public final int getHeight();
     method public void getHitRect(android.graphics.Rect);
     method public int getHorizontalFadingEdgeLength();
@@ -45012,6 +45256,7 @@
     method public boolean isSelected();
     method public boolean isShown();
     method public boolean isSoundEffectsEnabled();
+    method public final boolean isTemporarilyDetached();
     method public boolean isTextAlignmentResolved();
     method public boolean isTextDirectionResolved();
     method public boolean isVerticalFadingEdgeEnabled();
@@ -45069,6 +45314,7 @@
     method public void onStartTemporaryDetach();
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
+    method public void onVisibilityAggregated(boolean);
     method protected void onVisibilityChanged(android.view.View, int);
     method public void onWindowFocusChanged(boolean);
     method public void onWindowSystemUiVisibilityChanged(int);
@@ -46166,7 +46412,7 @@
     method public abstract boolean onMenuOpened(int, android.view.Menu);
     method public abstract void onPanelClosed(int, android.view.Menu);
     method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+    method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
     method public abstract boolean onSearchRequested();
     method public abstract boolean onSearchRequested(android.view.SearchEvent);
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -46598,8 +46844,6 @@
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
     field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
@@ -46770,6 +47014,7 @@
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
     method public int getChildCount();
@@ -46777,6 +47022,7 @@
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+    method public java.lang.CharSequence getTitle();
     method public int getType();
     method public boolean isAccessibilityFocused();
     method public boolean isActive();
@@ -46789,6 +47035,7 @@
     field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
     field public static final int TYPE_APPLICATION = 1; // 0x1
     field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
     field public static final int TYPE_SYSTEM = 3; // 0x3
   }
 
@@ -47116,6 +47363,7 @@
     ctor public BaseInputConnection(android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -47283,6 +47531,7 @@
   public abstract interface InputConnection {
     method public abstract boolean beginBatchEdit();
     method public abstract boolean clearMetaKeyStates(int);
+    method public abstract void closeConnection();
     method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -47315,6 +47564,7 @@
     ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -48408,6 +48658,7 @@
     method public int getPackageId(android.content.res.Resources, java.lang.String);
     method public void invokeDrawGlFunctor(android.view.View, long, boolean);
     method public boolean isTraceTagEnabled();
+    method public java.lang.Runnable setDrawGlFunctionDetachedCallback(android.view.View, java.lang.Runnable);
     method public void setOnTraceEnabledChangeListener(android.webkit.WebViewDelegate.OnTraceEnabledChangeListener);
   }
 
@@ -48418,19 +48669,18 @@
   public final class WebViewFactory {
     ctor public WebViewFactory();
     method public static android.content.pm.PackageInfo getLoadedPackageInfo();
-    method public static java.lang.String getWebViewPackageName();
-    method public static int loadWebViewNativeLibraryFromPackage(java.lang.String);
+    method public static int loadWebViewNativeLibraryFromPackage(java.lang.String, java.lang.ClassLoader);
     method public static void prepareWebViewInZygote();
     field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
     field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
     field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7
     field public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; // 0x4
+    field public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10; // 0xa
     field public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6; // 0x6
     field public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5; // 0x5
     field public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3; // 0x3
-    field public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9; // 0x9
+    field public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 8; // 0x8
     field public static final int LIBLOAD_SUCCESS = 0; // 0x0
-    field public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8; // 0x8
     field public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1; // 0x1
   }
 
@@ -48569,7 +48819,9 @@
 
   public static abstract interface WebViewProvider.ViewDelegate {
     method public abstract boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public abstract android.view.View findFocus(android.view.View);
     method public abstract android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
+    method public abstract android.os.Handler getHandler(android.os.Handler);
     method public abstract void onActivityResult(int, int, android.content.Intent);
     method public abstract void onAttachedToWindow();
     method public abstract void onConfigurationChanged(android.content.res.Configuration);
@@ -48612,6 +48864,24 @@
     method public abstract boolean shouldDelayChildPressedState();
   }
 
+  public final class WebViewProviderInfo implements android.os.Parcelable {
+    ctor public WebViewProviderInfo(java.lang.String, java.lang.String, boolean, boolean, java.lang.String[]);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.webkit.WebViewProviderInfo> CREATOR;
+    field public final boolean availableByDefault;
+    field public final java.lang.String description;
+    field public final boolean isFallback;
+    field public final java.lang.String packageName;
+    field public final java.lang.String[] signatures;
+  }
+
+  public final class WebViewUpdateService {
+    method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
+    method public static java.lang.String getCurrentWebViewPackageName();
+    method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+  }
+
 }
 
 package android.widget {
@@ -49098,7 +49368,7 @@
     method public long getMinDate();
     method public deprecated android.graphics.drawable.Drawable getSelectedDateVerticalBar();
     method public deprecated int getSelectedWeekBackgroundColor();
-    method public boolean getShowWeekNumber();
+    method public deprecated boolean getShowWeekNumber();
     method public deprecated int getShownWeekCount();
     method public deprecated int getUnfocusedMonthDateColor();
     method public int getWeekDayTextAppearance();
@@ -49115,7 +49385,7 @@
     method public deprecated void setSelectedDateVerticalBar(int);
     method public deprecated void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
     method public deprecated void setSelectedWeekBackgroundColor(int);
-    method public void setShowWeekNumber(boolean);
+    method public deprecated void setShowWeekNumber(boolean);
     method public deprecated void setShownWeekCount(int);
     method public deprecated void setUnfocusedMonthDateColor(int);
     method public void setWeekDayTextAppearance(int);
@@ -49165,7 +49435,9 @@
     method public long getBase();
     method public java.lang.String getFormat();
     method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener();
+    method public boolean isCountDown();
     method public void setBase(long);
+    method public void setCountDown(boolean);
     method public void setFormat(java.lang.String);
     method public void setOnChronometerTickListener(android.widget.Chronometer.OnChronometerTickListener);
     method public void start();
@@ -50013,6 +50285,8 @@
     method public android.graphics.drawable.Drawable getBackground();
     method public android.view.View getContentView();
     method public float getElevation();
+    method public android.transition.Transition getEnterTransition();
+    method public android.transition.Transition getExitTransition();
     method public int getHeight();
     method public int getInputMethodMode();
     method public int getMaxAvailableHeight(android.view.View);
@@ -50257,6 +50531,7 @@
     method public void setChar(int, java.lang.String, char);
     method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
     method public void setChronometer(int, long, java.lang.String, boolean);
+    method public void setChronometerCountsDown(int, boolean);
     method public void setContentDescription(int, java.lang.CharSequence);
     method public void setDisplayedChild(int, int);
     method public void setDouble(int, java.lang.String, double);
@@ -51091,9 +51366,15 @@
     method public void collapseActionView();
     method public void dismissPopupMenus();
     method public int getContentInsetEnd();
+    method public int getContentInsetEndWithActions();
     method public int getContentInsetLeft();
     method public int getContentInsetRight();
     method public int getContentInsetStart();
+    method public int getContentInsetStartWithNavigation();
+    method public int getCurrentContentInsetEnd();
+    method public int getCurrentContentInsetLeft();
+    method public int getCurrentContentInsetRight();
+    method public int getCurrentContentInsetStart();
     method public android.graphics.drawable.Drawable getLogo();
     method public java.lang.CharSequence getLogoDescription();
     method public android.view.Menu getMenu();
@@ -51112,6 +51393,8 @@
     method public void inflateMenu(int);
     method public boolean isOverflowMenuShowing();
     method protected void onLayout(boolean, int, int, int, int);
+    method public void setContentInsetEndWithActions(int);
+    method public void setContentInsetStartWithNavigation(int);
     method public void setContentInsetsAbsolute(int, int);
     method public void setContentInsetsRelative(int, int);
     method public void setLogo(int);
@@ -52096,9 +52379,7 @@
 
   public final class FilePermission extends java.security.Permission implements java.io.Serializable {
     ctor public FilePermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -52837,6 +53118,7 @@
     method public static int compare(boolean, boolean);
     method public int compareTo(java.lang.Boolean);
     method public static boolean getBoolean(java.lang.String);
+    method public static int hashCode(boolean);
     method public static boolean parseBoolean(java.lang.String);
     method public static java.lang.String toString(boolean);
     method public static java.lang.Boolean valueOf(boolean);
@@ -52854,6 +53136,7 @@
     method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(byte);
     method public int intValue();
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -52862,6 +53145,7 @@
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+    field public static final int BYTES = 1; // 0x1
     field public static final byte MAX_VALUE = 127; // 0x7f
     field public static final byte MIN_VALUE = -128; // 0xffffff80
     field public static final int SIZE = 8; // 0x8
@@ -52899,6 +53183,7 @@
     method public static int getNumericValue(int);
     method public static int getType(char);
     method public static int getType(int);
+    method public static int hashCode(char);
     method public static char highSurrogate(int);
     method public static boolean isAlphabetic(int);
     method public static boolean isBmpCodePoint(int);
@@ -52959,6 +53244,7 @@
     method public static char toUpperCase(char);
     method public static int toUpperCase(int);
     method public static java.lang.Character valueOf(char);
+    field public static final int BYTES = 2; // 0x2
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
     field public static final byte CONTROL = 15; // 0xf
@@ -53503,18 +53789,24 @@
     method public static long doubleToRawLongBits(double);
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(double);
     method public int intValue();
+    method public static boolean isFinite(double);
     method public static boolean isInfinite(double);
     method public boolean isInfinite();
     method public static boolean isNaN(double);
     method public boolean isNaN();
     method public static double longBitsToDouble(long);
     method public long longValue();
+    method public static double max(double, double);
+    method public static double min(double, double);
     method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+    method public static double sum(double, double);
     method public static java.lang.String toHexString(double);
     method public static java.lang.String toString(double);
     method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Double valueOf(double);
+    field public static final int BYTES = 8; // 0x8
     field public static final int MAX_EXPONENT = 1023; // 0x3ff
     field public static final double MAX_VALUE = 1.7976931348623157E308;
     field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -53579,18 +53871,24 @@
     method public static int floatToIntBits(float);
     method public static int floatToRawIntBits(float);
     method public float floatValue();
+    method public static int hashCode(float);
     method public static float intBitsToFloat(int);
     method public int intValue();
+    method public static boolean isFinite(float);
     method public static boolean isInfinite(float);
     method public boolean isInfinite();
     method public static boolean isNaN(float);
     method public boolean isNaN();
     method public long longValue();
+    method public static float max(float, float);
+    method public static float min(float, float);
     method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+    method public static float sum(float, float);
     method public static java.lang.String toHexString(float);
     method public static java.lang.String toString(float);
     method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Float valueOf(float);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_EXPONENT = 127; // 0x7f
     field public static final float MAX_VALUE = 3.4028235E38f;
     field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -53677,10 +53975,13 @@
     method public static java.lang.Integer getInteger(java.lang.String);
     method public static java.lang.Integer getInteger(java.lang.String, int);
     method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+    method public static int hashCode(int);
     method public static int highestOneBit(int);
     method public int intValue();
     method public long longValue();
     method public static int lowestOneBit(int);
+    method public static int max(int, int);
+    method public static int min(int, int);
     method public static int numberOfLeadingZeros(int);
     method public static int numberOfTrailingZeros(int);
     method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53690,6 +53991,7 @@
     method public static int rotateLeft(int, int);
     method public static int rotateRight(int, int);
     method public static int signum(int);
+    method public static int sum(int, int);
     method public static java.lang.String toBinaryString(int);
     method public static java.lang.String toHexString(int);
     method public static java.lang.String toOctalString(int);
@@ -53698,6 +54000,7 @@
     method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(int);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
     field public static final int MIN_VALUE = -2147483648; // 0x80000000
     field public static final int SIZE = 32; // 0x20
@@ -53717,7 +54020,9 @@
   }
 
   public abstract interface Iterable {
+    method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
+    method public default java.util.Spliterator<T> spliterator();
   }
 
   public class LinkageError extends java.lang.Error {
@@ -53738,10 +54043,13 @@
     method public static java.lang.Long getLong(java.lang.String);
     method public static java.lang.Long getLong(java.lang.String, long);
     method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+    method public static int hashCode(long);
     method public static long highestOneBit(long);
     method public int intValue();
     method public long longValue();
     method public static long lowestOneBit(long);
+    method public static long max(long, long);
+    method public static long min(long, long);
     method public static int numberOfLeadingZeros(long);
     method public static int numberOfTrailingZeros(long);
     method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53751,6 +54059,7 @@
     method public static long rotateLeft(long, int);
     method public static long rotateRight(long, int);
     method public static int signum(long);
+    method public static long sum(long, long);
     method public static java.lang.String toBinaryString(long);
     method public static java.lang.String toHexString(long);
     method public static java.lang.String toOctalString(long);
@@ -53759,6 +54068,7 @@
     method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(long);
+    field public static final int BYTES = 8; // 0x8
     field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
     field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
     field public static final int SIZE = 64; // 0x40
@@ -53938,41 +54248,11 @@
     method public java.io.File directory();
     method public java.lang.ProcessBuilder directory(java.io.File);
     method public java.util.Map<java.lang.String, java.lang.String> environment();
-    method public java.lang.ProcessBuilder inheritIO();
-    method public java.lang.ProcessBuilder redirectError(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectError(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectError();
     method public boolean redirectErrorStream();
     method public java.lang.ProcessBuilder redirectErrorStream(boolean);
-    method public java.lang.ProcessBuilder redirectInput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectInput(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectInput();
-    method public java.lang.ProcessBuilder redirectOutput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectOutput(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectOutput();
     method public java.lang.Process start() throws java.io.IOException;
   }
 
-  public static abstract class ProcessBuilder.Redirect {
-    method public static java.lang.ProcessBuilder.Redirect appendTo(java.io.File);
-    method public java.io.File file();
-    method public static java.lang.ProcessBuilder.Redirect from(java.io.File);
-    method public static java.lang.ProcessBuilder.Redirect to(java.io.File);
-    method public abstract java.lang.ProcessBuilder.Redirect.Type type();
-    field public static final java.lang.ProcessBuilder.Redirect INHERIT;
-    field public static final java.lang.ProcessBuilder.Redirect PIPE;
-  }
-
-  public static final class ProcessBuilder.Redirect.Type extends java.lang.Enum {
-    method public static java.lang.ProcessBuilder.Redirect.Type valueOf(java.lang.String);
-    method public static final java.lang.ProcessBuilder.Redirect.Type[] values();
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type APPEND;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type INHERIT;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type PIPE;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type READ;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type WRITE;
-  }
-
   public abstract interface Readable {
     method public abstract int read(java.nio.CharBuffer) throws java.io.IOException;
   }
@@ -54092,6 +54372,7 @@
     method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(short);
     method public int intValue();
     method public long longValue();
     method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -54101,6 +54382,7 @@
     method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(short);
+    field public static final int BYTES = 2; // 0x2
     field public static final short MAX_VALUE = 32767; // 0x7fff
     field public static final short MIN_VALUE = -32768; // 0xffff8000
     field public static final int SIZE = 16; // 0x10
@@ -55624,9 +55906,7 @@
 
   public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
     ctor public SocketPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -56708,9 +56988,7 @@
   public final class AllPermission extends java.security.Permission {
     ctor public AllPermission();
     ctor public AllPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -56724,9 +57002,7 @@
   public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
     ctor public BasicPermission(java.lang.String);
     ctor public BasicPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -57104,10 +57380,8 @@
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
-    method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getActions();
     method public final java.lang.String getName();
-    method public abstract int hashCode();
     method public abstract boolean implies(java.security.Permission);
     method public java.security.PermissionCollection newPermissionCollection();
   }
@@ -57192,6 +57466,7 @@
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
@@ -57364,13 +57639,11 @@
 
   public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
     ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getUnresolvedActions();
     method public java.security.cert.Certificate[] getUnresolvedCerts();
     method public java.lang.String getUnresolvedName();
     method public java.lang.String getUnresolvedType();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -57428,8 +57701,6 @@
   }
 
   public abstract interface Permission {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.lang.String toString();
   }
 
 }
@@ -60133,6 +60404,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
@@ -60141,8 +60413,13 @@
     ctor public ArrayList(java.util.Collection<? extends E>);
     method public java.lang.Object clone();
     method public void ensureCapacity(int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
+    method public boolean removeIf(java.util.function.Predicate<? super E>);
+    method public void replaceAll(java.util.function.UnaryOperator<E>);
     method public int size();
+    method public void sort(java.util.Comparator<? super E>);
+    method public java.util.Spliterator<E> spliterator();
     method public void trimToSize();
   }
 
@@ -60225,6 +60502,32 @@
     method public static int hashCode(float[]);
     method public static int hashCode(double[]);
     method public static int hashCode(java.lang.Object[]);
+    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
+    method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
+    method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
+    method public static void parallelSort(byte[]);
+    method public static void parallelSort(byte[], int, int);
+    method public static void parallelSort(char[]);
+    method public static void parallelSort(char[], int, int);
+    method public static void parallelSort(short[]);
+    method public static void parallelSort(short[], int, int);
+    method public static void parallelSort(int[]);
+    method public static void parallelSort(int[], int, int);
+    method public static void parallelSort(long[]);
+    method public static void parallelSort(long[], int, int);
+    method public static void parallelSort(float[]);
+    method public static void parallelSort(float[], int, int);
+    method public static void parallelSort(double[]);
+    method public static void parallelSort(double[], int, int);
+    method public static void parallelSort(T[]);
+    method public static void parallelSort(T[], int, int);
+    method public static void parallelSort(T[], java.util.Comparator<? super T>);
+    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static void setAll(int[], java.util.function.IntUnaryOperator);
+    method public static void setAll(long[], java.util.function.IntToLongFunction);
+    method public static void setAll(double[], java.util.function.IntToDoubleFunction);
     method public static void sort(int[]);
     method public static void sort(int[], int, int);
     method public static void sort(long[]);
@@ -60243,6 +60546,22 @@
     method public static void sort(java.lang.Object[], int, int);
     method public static void sort(T[], java.util.Comparator<? super T>);
     method public static void sort(T[], int, int, java.util.Comparator<? super T>);
+    method public static java.util.Spliterator<T> spliterator(T[]);
+    method public static java.util.Spliterator<T> spliterator(T[], int, int);
+    method public static java.util.Spliterator.OfInt spliterator(int[]);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
+    method public static java.util.Spliterator.OfLong spliterator(long[]);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[]);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
+    method public static java.util.stream.Stream<T> stream(T[]);
+    method public static java.util.stream.Stream<T> stream(T[], int, int);
+    method public static java.util.stream.IntStream stream(int[]);
+    method public static java.util.stream.IntStream stream(int[], int, int);
+    method public static java.util.stream.LongStream stream(long[]);
+    method public static java.util.stream.LongStream stream(long[], int, int);
+    method public static java.util.stream.DoubleStream stream(double[]);
+    method public static java.util.stream.DoubleStream stream(double[], int, int);
     method public static java.lang.String toString(long[]);
     method public static java.lang.String toString(int[]);
     method public static java.lang.String toString(short[]);
@@ -60402,10 +60721,13 @@
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
     method public abstract java.util.Iterator<E> iterator();
+    method public default java.util.stream.Stream<E> parallelStream();
     method public abstract boolean remove(java.lang.Object);
     method public abstract boolean removeAll(java.util.Collection<?>);
+    method public default boolean removeIf(java.util.function.Predicate<? super E>);
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
+    method public default java.util.stream.Stream<E> stream();
     method public abstract java.lang.Object[] toArray();
     method public abstract T[] toArray(T[]);
   }
@@ -60473,7 +60795,23 @@
 
   public abstract interface Comparator {
     method public abstract int compare(T, T);
+    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
     method public abstract boolean equals(java.lang.Object);
+    method public static java.util.Comparator<T> naturalOrder();
+    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
+    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
+    method public static java.util.Comparator<T> reverseOrder();
+    method public default java.util.Comparator<T> reversed();
+    method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
+    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
+    method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
+    method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
   }
 
   public class ConcurrentModificationException extends java.lang.RuntimeException {
@@ -60570,6 +60908,17 @@
     method public abstract int size();
   }
 
+  public class DoubleSummaryStatistics implements java.util.function.DoubleConsumer {
+    ctor public DoubleSummaryStatistics();
+    method public void accept(double);
+    method public void combine(java.util.DoubleSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final double getMax();
+    method public final double getMin();
+    method public final double getSum();
+  }
+
   public class DuplicateFormatFlagsException extends java.util.IllegalFormatException {
     ctor public DuplicateFormatFlagsException(java.lang.String);
     method public java.lang.String getFlags();
@@ -60704,6 +61053,8 @@
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public boolean replace(K, V, V);
   }
 
   public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -60714,6 +61065,7 @@
     method public java.lang.Object clone();
     method public java.util.Iterator<E> iterator();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
@@ -60723,19 +61075,29 @@
     ctor public Hashtable(java.util.Map<? extends K, ? extends V>);
     method public synchronized void clear();
     method public synchronized java.lang.Object clone();
+    method public synchronized V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public synchronized V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public synchronized V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public synchronized boolean contains(java.lang.Object);
     method public synchronized boolean containsKey(java.lang.Object);
     method public boolean containsValue(java.lang.Object);
     method public synchronized java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public synchronized V get(java.lang.Object);
+    method public synchronized V getOrDefault(java.lang.Object, V);
     method public synchronized boolean isEmpty();
     method public java.util.Set<K> keySet();
     method public synchronized java.util.Enumeration<K> keys();
+    method public synchronized V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public synchronized V put(K, V);
     method public synchronized void putAll(java.util.Map<? extends K, ? extends V>);
+    method public synchronized V putIfAbsent(K, V);
     method protected void rehash();
     method public synchronized V remove(java.lang.Object);
+    method public synchronized boolean remove(java.lang.Object, java.lang.Object);
+    method public synchronized boolean replace(K, V, V);
+    method public synchronized V replace(K, V);
     method public synchronized int size();
     method public java.util.Collection<V> values();
   }
@@ -60746,6 +61108,7 @@
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -60789,15 +61152,27 @@
     ctor public InputMismatchException(java.lang.String);
   }
 
+  public class IntSummaryStatistics implements java.util.function.IntConsumer {
+    ctor public IntSummaryStatistics();
+    method public void accept(int);
+    method public void combine(java.util.IntSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final int getMax();
+    method public final int getMin();
+    method public final long getSum();
+  }
+
   public class InvalidPropertiesFormatException extends java.io.IOException {
     ctor public InvalidPropertiesFormatException(java.lang.Throwable);
     ctor public InvalidPropertiesFormatException(java.lang.String);
   }
 
   public abstract interface Iterator {
+    method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
-    method public abstract void remove();
+    method public default void remove();
   }
 
   public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -60844,6 +61219,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public abstract interface List implements java.util.Collection {
@@ -60866,9 +61242,11 @@
     method public abstract boolean remove(java.lang.Object);
     method public abstract E remove(int);
     method public abstract boolean removeAll(java.util.Collection<?>);
+    method public default void replaceAll(java.util.function.UnaryOperator<E>);
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract E set(int, E);
     method public abstract int size();
+    method public default void sort(java.util.Comparator<? super E>);
     method public abstract java.util.List<E> subList(int, int);
     method public abstract java.lang.Object[] toArray();
     method public abstract T[] toArray(T[]);
@@ -60979,24 +61357,51 @@
     enum_constant public static final java.util.Locale.Category FORMAT;
   }
 
+  public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
+    ctor public LongSummaryStatistics();
+    method public void accept(int);
+    method public void accept(long);
+    method public void combine(java.util.LongSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final long getMax();
+    method public final long getMin();
+    method public final long getSum();
+  }
+
   public abstract interface Map {
     method public abstract void clear();
+    method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public default V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public abstract boolean containsKey(java.lang.Object);
     method public abstract boolean containsValue(java.lang.Object);
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract boolean equals(java.lang.Object);
+    method public default void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public abstract V get(java.lang.Object);
+    method public default V getOrDefault(java.lang.Object, V);
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
     method public abstract java.util.Set<K> keySet();
+    method public default V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public abstract V put(K, V);
     method public abstract void putAll(java.util.Map<? extends K, ? extends V>);
+    method public default V putIfAbsent(K, V);
     method public abstract V remove(java.lang.Object);
+    method public default boolean remove(java.lang.Object, java.lang.Object);
+    method public default boolean replace(K, V, V);
+    method public default V replace(K, V);
+    method public default void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public abstract int size();
     method public abstract java.util.Collection<V> values();
   }
 
   public static abstract interface Map.Entry {
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
     method public abstract boolean equals(java.lang.Object);
     method public abstract K getKey();
     method public abstract V getValue();
@@ -61099,9 +61504,83 @@
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
+  public final class Optional {
+    method public static java.util.Optional<T> empty();
+    method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public T get();
+    method public void ifPresent(java.util.function.Consumer<? super T>);
+    method public boolean isPresent();
+    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Optional<T> of(T);
+    method public static java.util.Optional<T> ofNullable(T);
+    method public T orElse(T);
+    method public T orElseGet(java.util.function.Supplier<? extends T>);
+    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalDouble {
+    method public static java.util.OptionalDouble empty();
+    method public double getAsDouble();
+    method public void ifPresent(java.util.function.DoubleConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalDouble of(double);
+    method public double orElse(double);
+    method public double orElseGet(java.util.function.DoubleSupplier);
+    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalInt {
+    method public static java.util.OptionalInt empty();
+    method public int getAsInt();
+    method public void ifPresent(java.util.function.IntConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalInt of(int);
+    method public int orElse(int);
+    method public int orElseGet(java.util.function.IntSupplier);
+    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalLong {
+    method public static java.util.OptionalLong empty();
+    method public long getAsLong();
+    method public void ifPresent(java.util.function.LongConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalLong of(long);
+    method public long orElse(long);
+    method public long orElseGet(java.util.function.LongSupplier);
+    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public abstract interface PrimitiveIterator implements java.util.Iterator {
+    method public abstract void forEachRemaining(T_CONS);
+  }
+
+  public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public default java.lang.Double next();
+    method public abstract double nextDouble();
+  }
+
+  public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public default java.lang.Integer next();
+    method public abstract int nextInt();
+  }
+
+  public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public default java.lang.Long next();
+    method public abstract long nextLong();
+  }
+
   public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
+    ctor public PriorityQueue(java.util.Comparator<? super E>);
     ctor public PriorityQueue(int, java.util.Comparator<? super E>);
     ctor public PriorityQueue(java.util.Collection<? extends E>);
     ctor public PriorityQueue(java.util.PriorityQueue<? extends E>);
@@ -61112,6 +61591,7 @@
     method public E peek();
     method public E poll();
     method public int size();
+    method public final java.util.Spliterator<E> spliterator();
   }
 
   public class Properties extends java.util.Hashtable {
@@ -61270,7 +61750,6 @@
     method public short nextShort();
     method public short nextShort(int);
     method public int radix();
-    method public void remove();
     method public java.util.Scanner reset();
     method public java.util.Scanner skip(java.util.regex.Pattern);
     method public java.util.Scanner skip(java.lang.String);
@@ -61355,6 +61834,139 @@
     method public abstract java.util.SortedSet<E> tailSet(E);
   }
 
+  public abstract interface Spliterator {
+    method public abstract int characteristics();
+    method public abstract long estimateSize();
+    method public default void forEachRemaining(java.util.function.Consumer<? super T>);
+    method public default java.util.Comparator<? super T> getComparator();
+    method public default long getExactSizeIfKnown();
+    method public default boolean hasCharacteristics(int);
+    method public abstract boolean tryAdvance(java.util.function.Consumer<? super T>);
+    method public abstract java.util.Spliterator<T> trySplit();
+    field public static final int CONCURRENT = 4096; // 0x1000
+    field public static final int DISTINCT = 1; // 0x1
+    field public static final int IMMUTABLE = 1024; // 0x400
+    field public static final int NONNULL = 256; // 0x100
+    field public static final int ORDERED = 16; // 0x10
+    field public static final int SIZED = 64; // 0x40
+    field public static final int SORTED = 4; // 0x4
+    field public static final int SUBSIZED = 16384; // 0x4000
+  }
+
+  public static abstract interface Spliterator.OfDouble implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public abstract boolean tryAdvance(java.util.function.DoubleConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Double>);
+    method public abstract java.util.Spliterator.OfDouble trySplit();
+  }
+
+  public static abstract interface Spliterator.OfInt implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public abstract boolean tryAdvance(java.util.function.IntConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Integer>);
+    method public abstract java.util.Spliterator.OfInt trySplit();
+  }
+
+  public static abstract interface Spliterator.OfLong implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public abstract boolean tryAdvance(java.util.function.LongConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Long>);
+    method public abstract java.util.Spliterator.OfLong trySplit();
+  }
+
+  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
+    method public default void forEachRemaining(T_CONS);
+    method public abstract boolean tryAdvance(T_CONS);
+    method public abstract T_SPLITR trySplit();
+  }
+
+  public final class Spliterators {
+    method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
+    method public static java.util.Spliterator.OfInt emptyIntSpliterator();
+    method public static java.util.Spliterator.OfLong emptyLongSpliterator();
+    method public static java.util.Spliterator<T> emptySpliterator();
+    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
+    method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
+    method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
+    method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
+    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
+    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
+    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
+    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
+    method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
+    method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
+    method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
+    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
+    method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
+    method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
+    method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
+  }
+
+  public static abstract class Spliterators.AbstractDoubleSpliterator implements java.util.Spliterator.OfDouble {
+    ctor protected Spliterators.AbstractDoubleSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfDouble trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractIntSpliterator implements java.util.Spliterator.OfInt {
+    ctor protected Spliterators.AbstractIntSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfInt trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractLongSpliterator implements java.util.Spliterator.OfLong {
+    ctor protected Spliterators.AbstractLongSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfLong trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
+    ctor protected Spliterators.AbstractSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator<T> trySplit();
+  }
+
+  public final class SplittableRandom {
+    ctor public SplittableRandom(long);
+    ctor public SplittableRandom();
+    method public java.util.stream.DoubleStream doubles(long);
+    method public java.util.stream.DoubleStream doubles();
+    method public java.util.stream.DoubleStream doubles(long, double, double);
+    method public java.util.stream.DoubleStream doubles(double, double);
+    method public java.util.stream.IntStream ints(long);
+    method public java.util.stream.IntStream ints();
+    method public java.util.stream.IntStream ints(long, int, int);
+    method public java.util.stream.IntStream ints(int, int);
+    method public java.util.stream.LongStream longs(long);
+    method public java.util.stream.LongStream longs();
+    method public java.util.stream.LongStream longs(long, long, long);
+    method public java.util.stream.LongStream longs(long, long);
+    method public boolean nextBoolean();
+    method public double nextDouble();
+    method public double nextDouble(double);
+    method public double nextDouble(double, double);
+    method public int nextInt();
+    method public int nextInt(int);
+    method public int nextInt(int, int);
+    method public long nextLong();
+    method public long nextLong(long);
+    method public long nextLong(long, long);
+    method public java.util.SplittableRandom split();
+  }
+
   public class Stack extends java.util.Vector {
     ctor public Stack();
     method public boolean empty();
@@ -61364,6 +61976,15 @@
     method public synchronized int search(java.lang.Object);
   }
 
+  public final class StringJoiner {
+    ctor public StringJoiner(java.lang.CharSequence);
+    ctor public StringJoiner(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
+    method public java.util.StringJoiner add(java.lang.CharSequence);
+    method public int length();
+    method public java.util.StringJoiner merge(java.util.StringJoiner);
+    method public java.util.StringJoiner setEmptyValue(java.lang.CharSequence);
+  }
+
   public class StringTokenizer implements java.util.Enumeration {
     ctor public StringTokenizer(java.lang.String, java.lang.String, boolean);
     ctor public StringTokenizer(java.lang.String, java.lang.String);
@@ -61446,6 +62067,7 @@
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public java.util.NavigableMap<K, V> headMap(K, boolean);
     method public java.util.SortedMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -61484,6 +62106,7 @@
     method public E pollFirst();
     method public E pollLast();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
     method public java.util.SortedSet<E> subSet(E, E);
     method public java.util.NavigableSet<E> tailSet(E, boolean);
@@ -61528,6 +62151,7 @@
     method public java.util.Enumeration<E> elements();
     method public synchronized void ensureCapacity(int);
     method public synchronized E firstElement();
+    method public synchronized void forEach(java.util.function.Consumer<? super E>);
     method public synchronized E get(int);
     method public synchronized int indexOf(java.lang.Object, int);
     method public synchronized void insertElementAt(E, int);
@@ -61536,9 +62160,13 @@
     method public synchronized void removeAllElements();
     method public synchronized boolean removeElement(java.lang.Object);
     method public synchronized void removeElementAt(int);
+    method public synchronized boolean removeIf(java.util.function.Predicate<? super E>);
+    method public synchronized void replaceAll(java.util.function.UnaryOperator<E>);
     method public synchronized void setElementAt(E, int);
     method public synchronized void setSize(int);
     method public synchronized int size();
+    method public synchronized void sort(java.util.Comparator<? super E>);
+    method public java.util.Spliterator<E> spliterator();
     method public synchronized void trimToSize();
     field protected int capacityIncrement;
     field protected int elementCount;
@@ -61551,6 +62179,7 @@
     ctor public WeakHashMap();
     ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
 }
@@ -61585,6 +62214,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -61648,6 +62278,78 @@
     ctor public CancellationException(java.lang.String);
   }
 
+  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
+    ctor public CompletableFuture();
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
+    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public boolean cancel(boolean);
+    method public boolean complete(T);
+    method public boolean completeExceptionally(java.lang.Throwable);
+    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
+    method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
+    method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public T getNow(T);
+    method public int getNumberOfDependents();
+    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public boolean isCancelled();
+    method public boolean isCompletedExceptionally();
+    method public boolean isDone();
+    method public T join();
+    method public void obtrudeException(java.lang.Throwable);
+    method public void obtrudeValue(T);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
+    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<T> toCompletableFuture();
+    method public java.util.concurrent.CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+  }
+
+  public static abstract interface CompletableFuture.AsynchronousCompletionTask {
+  }
+
+  public class CompletionException extends java.lang.RuntimeException {
+    ctor protected CompletionException();
+    ctor protected CompletionException(java.lang.String);
+    ctor public CompletionException(java.lang.String, java.lang.Throwable);
+    ctor public CompletionException(java.lang.Throwable);
+  }
+
   public abstract interface CompletionService {
     method public abstract java.util.concurrent.Future<V> poll();
     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
@@ -61656,20 +62358,130 @@
     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
+  public abstract interface CompletionStage {
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
+    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletableFuture<T> toCompletableFuture();
+    method public abstract java.util.concurrent.CompletionStage<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+  }
+
   public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
     ctor public ConcurrentHashMap();
     ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
     ctor public ConcurrentHashMap(int, float);
     ctor public ConcurrentHashMap(int, float, int);
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public boolean contains(java.lang.Object);
     method public java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
+    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
+    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachKey(long, java.util.function.Consumer<? super K>);
+    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachValue(long, java.util.function.Consumer<? super V>);
+    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public V getOrDefault(java.lang.Object, V);
+    method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
     method public java.util.Enumeration<K> keys();
+    method public long mappingCount();
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
+    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
     method public V putIfAbsent(K, V);
+    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
+    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
+    method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
+    method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
+    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
+    method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
+    method public double reduceToDouble(long, java.util.function.ToDoubleBiFunction<? super K, ? super V>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
+    method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
+    method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
+    method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
     method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
     method public V replace(K, V);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
+    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
+    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
+    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
+  }
+
+   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
+    method public final void clear();
+    method public abstract boolean contains(java.lang.Object);
+    method public final boolean containsAll(java.util.Collection<?>);
+    method public java.util.concurrent.ConcurrentHashMap<K, V> getMap();
+    method public final boolean isEmpty();
+    method public abstract java.util.Iterator<E> iterator();
+    method public abstract boolean remove(java.lang.Object);
+    method public final boolean removeAll(java.util.Collection<?>);
+    method public final boolean retainAll(java.util.Collection<?>);
+    method public final int size();
+    method public final java.lang.Object[] toArray();
+    method public final T[] toArray(T[]);
+    method public final java.lang.String toString();
+  }
+
+  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
+    method public boolean add(K);
+    method public boolean addAll(java.util.Collection<? extends K>);
+    method public boolean contains(java.lang.Object);
+    method public void forEach(java.util.function.Consumer<? super K>);
+    method public V getMappedValue();
+    method public java.util.Iterator<K> iterator();
+    method public boolean remove(java.lang.Object);
+    method public java.util.Spliterator<K> spliterator();
   }
 
   public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
@@ -61699,6 +62511,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
@@ -61709,6 +62522,7 @@
     method public E peek();
     method public E poll();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public abstract interface ConcurrentMap implements java.util.Map {
@@ -61740,6 +62554,9 @@
     method public K ceilingKey(K);
     method public java.util.concurrent.ConcurrentSkipListMap<K, V> clone();
     method public java.util.Comparator<? super K> comparator();
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableSet<K> descendingKeySet();
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
@@ -61747,6 +62564,8 @@
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public V getOrDefault(java.lang.Object, V);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -61755,6 +62574,7 @@
     method public K lastKey();
     method public java.util.Map.Entry<K, V> lowerEntry(K);
     method public K lowerKey(K);
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
@@ -61762,6 +62582,7 @@
     method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
     method public V replace(K, V);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, K);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K, boolean);
@@ -61789,6 +62610,7 @@
     method public E pollFirst();
     method public E pollLast();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
     method public java.util.NavigableSet<E> subSet(E, E);
     method public java.util.NavigableSet<E> tailSet(E, boolean);
@@ -61809,6 +62631,7 @@
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
     method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
@@ -61832,8 +62655,11 @@
   public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
     ctor public CopyOnWriteArraySet();
     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
+    method public boolean removeIf(java.util.function.Predicate<? super E>);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class CountDownLatch {
@@ -61844,6 +62670,32 @@
     method public long getCount();
   }
 
+  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
+    ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
+    ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
+    ctor protected CountedCompleter();
+    method public final void addToPendingCount(int);
+    method public final boolean compareAndSetPendingCount(int, int);
+    method public void complete(T);
+    method public abstract void compute();
+    method public final int decrementPendingCountUnlessZero();
+    method protected final boolean exec();
+    method public final java.util.concurrent.CountedCompleter<?> firstComplete();
+    method public final java.util.concurrent.CountedCompleter<?> getCompleter();
+    method public final int getPendingCount();
+    method public T getRawResult();
+    method public final java.util.concurrent.CountedCompleter<?> getRoot();
+    method public final void helpComplete(int);
+    method public final java.util.concurrent.CountedCompleter<?> nextComplete();
+    method public void onCompletion(java.util.concurrent.CountedCompleter<?>);
+    method public boolean onExceptionalCompletion(java.lang.Throwable, java.util.concurrent.CountedCompleter<?>);
+    method public final void propagateCompletion();
+    method public final void quietlyCompleteRoot();
+    method public final void setPendingCount(int);
+    method protected void setRawResult(T);
+    method public final void tryComplete();
+  }
+
   public class CyclicBarrier {
     ctor public CyclicBarrier(int, java.lang.Runnable);
     ctor public CyclicBarrier(int);
@@ -61934,6 +62786,8 @@
     method public static java.util.concurrent.ExecutorService newSingleThreadExecutor(java.util.concurrent.ThreadFactory);
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor();
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
+    method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
+    method public static java.util.concurrent.ExecutorService newWorkStealingPool();
     method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
@@ -61947,11 +62801,13 @@
     ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
     method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public static java.util.concurrent.ForkJoinPool commonPool();
     method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>);
     method public void execute(java.util.concurrent.ForkJoinTask<?>);
     method public void execute(java.lang.Runnable);
     method public int getActiveThreadCount();
     method public boolean getAsyncMode();
+    method public static int getCommonPoolParallelism();
     method public java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory getFactory();
     method public int getParallelism();
     method public int getPoolSize();
@@ -61989,6 +62845,7 @@
     method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
     method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
     method public boolean cancel(boolean);
+    method public final boolean compareAndSetForkJoinTaskTag(short, short);
     method public void complete(V);
     method public void completeExceptionally(java.lang.Throwable);
     method protected abstract boolean exec();
@@ -61996,6 +62853,7 @@
     method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public final java.lang.Throwable getException();
+    method public final short getForkJoinTaskTag();
     method public static java.util.concurrent.ForkJoinPool getPool();
     method public static int getQueuedTaskCount();
     method public abstract V getRawResult();
@@ -62014,9 +62872,11 @@
     method protected static java.util.concurrent.ForkJoinTask<?> peekNextLocalTask();
     method protected static java.util.concurrent.ForkJoinTask<?> pollNextLocalTask();
     method protected static java.util.concurrent.ForkJoinTask<?> pollTask();
+    method public final void quietlyComplete();
     method public final void quietlyInvoke();
     method public final void quietlyJoin();
     method public void reinitialize();
+    method public final short setForkJoinTaskTag(short);
     method protected abstract void setRawResult(V);
     method public boolean tryUnfork();
   }
@@ -62090,6 +62950,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
     method public E takeFirst() throws java.lang.InterruptedException;
     method public E takeLast() throws java.lang.InterruptedException;
@@ -62110,6 +62971,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -62129,6 +62991,7 @@
     method public void put(E);
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
     method public void transfer(E) throws java.lang.InterruptedException;
     method public boolean tryTransfer(E);
@@ -62176,6 +63039,7 @@
     method public void put(E);
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -62279,6 +63143,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -62288,6 +63153,18 @@
 
   public class ThreadLocalRandom extends java.util.Random {
     method public static java.util.concurrent.ThreadLocalRandom current();
+    method public java.util.stream.DoubleStream doubles(long);
+    method public java.util.stream.DoubleStream doubles();
+    method public java.util.stream.DoubleStream doubles(long, double, double);
+    method public java.util.stream.DoubleStream doubles(double, double);
+    method public java.util.stream.IntStream ints(long);
+    method public java.util.stream.IntStream ints();
+    method public java.util.stream.IntStream ints(long, int, int);
+    method public java.util.stream.IntStream ints(int, int);
+    method public java.util.stream.LongStream longs(long);
+    method public java.util.stream.LongStream longs();
+    method public java.util.stream.LongStream longs(long, long, long);
+    method public java.util.stream.LongStream longs(long, long);
     method public double nextDouble(double);
     method public double nextDouble(double, double);
     method public int nextInt(int, int);
@@ -62408,112 +63285,136 @@
   public class AtomicInteger extends java.lang.Number implements java.io.Serializable {
     ctor public AtomicInteger(int);
     ctor public AtomicInteger();
+    method public final int accumulateAndGet(int, java.util.function.IntBinaryOperator);
     method public final int addAndGet(int);
     method public final boolean compareAndSet(int, int);
     method public final int decrementAndGet();
     method public double doubleValue();
     method public float floatValue();
     method public final int get();
+    method public final int getAndAccumulate(int, java.util.function.IntBinaryOperator);
     method public final int getAndAdd(int);
     method public final int getAndDecrement();
     method public final int getAndIncrement();
     method public final int getAndSet(int);
+    method public final int getAndUpdate(java.util.function.IntUnaryOperator);
     method public final int incrementAndGet();
     method public int intValue();
     method public final void lazySet(int);
     method public long longValue();
     method public final void set(int);
+    method public final int updateAndGet(java.util.function.IntUnaryOperator);
     method public final boolean weakCompareAndSet(int, int);
   }
 
   public class AtomicIntegerArray implements java.io.Serializable {
     ctor public AtomicIntegerArray(int);
     ctor public AtomicIntegerArray(int[]);
+    method public final int accumulateAndGet(int, int, java.util.function.IntBinaryOperator);
     method public final int addAndGet(int, int);
     method public final boolean compareAndSet(int, int, int);
     method public final int decrementAndGet(int);
     method public final int get(int);
+    method public final int getAndAccumulate(int, int, java.util.function.IntBinaryOperator);
     method public final int getAndAdd(int, int);
     method public final int getAndDecrement(int);
     method public final int getAndIncrement(int);
     method public final int getAndSet(int, int);
+    method public final int getAndUpdate(int, java.util.function.IntUnaryOperator);
     method public final int incrementAndGet(int);
     method public final void lazySet(int, int);
     method public final int length();
     method public final void set(int, int);
+    method public final int updateAndGet(int, java.util.function.IntUnaryOperator);
     method public final boolean weakCompareAndSet(int, int, int);
   }
 
   public abstract class AtomicIntegerFieldUpdater {
     ctor protected AtomicIntegerFieldUpdater();
+    method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
     method public int addAndGet(T, int);
     method public abstract boolean compareAndSet(T, int, int);
     method public int decrementAndGet(T);
     method public abstract int get(T);
+    method public final int getAndAccumulate(T, int, java.util.function.IntBinaryOperator);
     method public int getAndAdd(T, int);
     method public int getAndDecrement(T);
     method public int getAndIncrement(T);
     method public int getAndSet(T, int);
+    method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
     method public int incrementAndGet(T);
     method public abstract void lazySet(T, int);
     method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, int);
+    method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, int, int);
   }
 
   public class AtomicLong extends java.lang.Number implements java.io.Serializable {
     ctor public AtomicLong(long);
     ctor public AtomicLong();
+    method public final long accumulateAndGet(long, java.util.function.LongBinaryOperator);
     method public final long addAndGet(long);
     method public final boolean compareAndSet(long, long);
     method public final long decrementAndGet();
     method public double doubleValue();
     method public float floatValue();
     method public final long get();
+    method public final long getAndAccumulate(long, java.util.function.LongBinaryOperator);
     method public final long getAndAdd(long);
     method public final long getAndDecrement();
     method public final long getAndIncrement();
     method public final long getAndSet(long);
+    method public final long getAndUpdate(java.util.function.LongUnaryOperator);
     method public final long incrementAndGet();
     method public int intValue();
     method public final void lazySet(long);
     method public long longValue();
     method public final void set(long);
+    method public final long updateAndGet(java.util.function.LongUnaryOperator);
     method public final boolean weakCompareAndSet(long, long);
   }
 
   public class AtomicLongArray implements java.io.Serializable {
     ctor public AtomicLongArray(int);
     ctor public AtomicLongArray(long[]);
+    method public final long accumulateAndGet(int, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(int, long);
     method public final boolean compareAndSet(int, long, long);
     method public final long decrementAndGet(int);
     method public final long get(int);
+    method public final long getAndAccumulate(int, long, java.util.function.LongBinaryOperator);
     method public final long getAndAdd(int, long);
     method public final long getAndDecrement(int);
     method public final long getAndIncrement(int);
     method public final long getAndSet(int, long);
+    method public final long getAndUpdate(int, java.util.function.LongUnaryOperator);
     method public final long incrementAndGet(int);
     method public final void lazySet(int, long);
     method public final int length();
     method public final void set(int, long);
+    method public final long updateAndGet(int, java.util.function.LongUnaryOperator);
     method public final boolean weakCompareAndSet(int, long, long);
   }
 
   public abstract class AtomicLongFieldUpdater {
     ctor protected AtomicLongFieldUpdater();
+    method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(T, long);
     method public abstract boolean compareAndSet(T, long, long);
     method public long decrementAndGet(T);
     method public abstract long get(T);
+    method public final long getAndAccumulate(T, long, java.util.function.LongBinaryOperator);
     method public long getAndAdd(T, long);
     method public long getAndDecrement(T);
     method public long getAndIncrement(T);
     method public long getAndSet(T, long);
+    method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
     method public long incrementAndGet(T);
     method public abstract void lazySet(T, long);
     method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, long);
+    method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, long, long);
   }
 
@@ -62531,34 +63432,46 @@
   public class AtomicReference implements java.io.Serializable {
     ctor public AtomicReference(V);
     ctor public AtomicReference();
+    method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
     method public final boolean compareAndSet(V, V);
     method public final V get();
+    method public final V getAndAccumulate(V, java.util.function.BinaryOperator<V>);
     method public final V getAndSet(V);
+    method public final V getAndUpdate(java.util.function.UnaryOperator<V>);
     method public final void lazySet(V);
     method public final void set(V);
+    method public final V updateAndGet(java.util.function.UnaryOperator<V>);
     method public final boolean weakCompareAndSet(V, V);
   }
 
   public class AtomicReferenceArray implements java.io.Serializable {
     ctor public AtomicReferenceArray(int);
     ctor public AtomicReferenceArray(E[]);
+    method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
     method public final boolean compareAndSet(int, E, E);
     method public final E get(int);
+    method public final E getAndAccumulate(int, E, java.util.function.BinaryOperator<E>);
     method public final E getAndSet(int, E);
+    method public final E getAndUpdate(int, java.util.function.UnaryOperator<E>);
     method public final void lazySet(int, E);
     method public final int length();
     method public final void set(int, E);
+    method public final E updateAndGet(int, java.util.function.UnaryOperator<E>);
     method public final boolean weakCompareAndSet(int, E, E);
   }
 
   public abstract class AtomicReferenceFieldUpdater {
     ctor protected AtomicReferenceFieldUpdater();
+    method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
     method public abstract boolean compareAndSet(T, V, V);
     method public abstract V get(T);
+    method public final V getAndAccumulate(T, V, java.util.function.BinaryOperator<V>);
     method public V getAndSet(T, V);
+    method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
     method public abstract void lazySet(T, V);
     method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
     method public abstract void set(T, V);
+    method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
     method public abstract boolean weakCompareAndSet(T, V, V);
   }
 
@@ -62573,6 +63486,59 @@
     method public boolean weakCompareAndSet(V, V, int, int);
   }
 
+  public class DoubleAccumulator extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public DoubleAccumulator(java.util.function.DoubleBinaryOperator, double);
+    method public void accumulate(double);
+    method public double doubleValue();
+    method public float floatValue();
+    method public double get();
+    method public double getThenReset();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+  }
+
+  public class DoubleAdder extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public DoubleAdder();
+    method public void add(double);
+    method public double doubleValue();
+    method public float floatValue();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+    method public double sum();
+    method public double sumThenReset();
+  }
+
+  public class LongAccumulator extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public LongAccumulator(java.util.function.LongBinaryOperator, long);
+    method public void accumulate(long);
+    method public double doubleValue();
+    method public float floatValue();
+    method public long get();
+    method public long getThenReset();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+  }
+
+  public class LongAdder extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public LongAdder();
+    method public void add(long);
+    method public void decrement();
+    method public double doubleValue();
+    method public float floatValue();
+    method public void increment();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+    method public long sum();
+    method public long sumThenReset();
+  }
+
+   abstract class Striped64 extends java.lang.Number {
+  }
+
 }
 
 package java.util.concurrent.locks {
@@ -62780,6 +63746,34 @@
     method public void unlock();
   }
 
+  public class StampedLock implements java.io.Serializable {
+    ctor public StampedLock();
+    method public java.util.concurrent.locks.Lock asReadLock();
+    method public java.util.concurrent.locks.ReadWriteLock asReadWriteLock();
+    method public java.util.concurrent.locks.Lock asWriteLock();
+    method public int getReadLockCount();
+    method public boolean isReadLocked();
+    method public boolean isWriteLocked();
+    method public long readLock();
+    method public long readLockInterruptibly() throws java.lang.InterruptedException;
+    method public long tryConvertToOptimisticRead(long);
+    method public long tryConvertToReadLock(long);
+    method public long tryConvertToWriteLock(long);
+    method public long tryOptimisticRead();
+    method public long tryReadLock();
+    method public long tryReadLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public boolean tryUnlockRead();
+    method public boolean tryUnlockWrite();
+    method public long tryWriteLock();
+    method public long tryWriteLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public void unlock(long);
+    method public void unlockRead(long);
+    method public void unlockWrite(long);
+    method public boolean validate(long);
+    method public long writeLock();
+    method public long writeLockInterruptibly() throws java.lang.InterruptedException;
+  }
+
 }
 
 package java.util.function {
@@ -63572,6 +64566,292 @@
 
 }
 
+package java.util.stream {
+
+  public abstract interface BaseStream implements java.lang.AutoCloseable {
+    method public abstract void close();
+    method public abstract boolean isParallel();
+    method public abstract java.util.Iterator<T> iterator();
+    method public abstract S onClose(java.lang.Runnable);
+    method public abstract S parallel();
+    method public abstract S sequential();
+    method public abstract java.util.Spliterator<T> spliterator();
+    method public abstract S unordered();
+  }
+
+  public abstract interface Collector {
+    method public abstract java.util.function.BiConsumer<A, T> accumulator();
+    method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
+    method public abstract java.util.function.BinaryOperator<A> combiner();
+    method public abstract java.util.function.Function<A, R> finisher();
+    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
+    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
+    method public abstract java.util.function.Supplier<A> supplier();
+  }
+
+  public static final class Collector.Characteristics extends java.lang.Enum {
+    method public static java.util.stream.Collector.Characteristics valueOf(java.lang.String);
+    method public static final java.util.stream.Collector.Characteristics[] values();
+    enum_constant public static final java.util.stream.Collector.Characteristics CONCURRENT;
+    enum_constant public static final java.util.stream.Collector.Characteristics IDENTITY_FINISH;
+    enum_constant public static final java.util.stream.Collector.Characteristics UNORDERED;
+  }
+
+  public final class Collectors {
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
+    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
+    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
+  }
+
+  public abstract interface DoubleStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.DoublePredicate);
+    method public abstract boolean anyMatch(java.util.function.DoublePredicate);
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Double> boxed();
+    method public static java.util.stream.DoubleStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
+    method public abstract long count();
+    method public abstract java.util.stream.DoubleStream distinct();
+    method public static java.util.stream.DoubleStream empty();
+    method public abstract java.util.stream.DoubleStream filter(java.util.function.DoublePredicate);
+    method public abstract java.util.OptionalDouble findAny();
+    method public abstract java.util.OptionalDouble findFirst();
+    method public abstract java.util.stream.DoubleStream flatMap(java.util.function.DoubleFunction<? extends java.util.stream.DoubleStream>);
+    method public abstract void forEach(java.util.function.DoubleConsumer);
+    method public abstract void forEachOrdered(java.util.function.DoubleConsumer);
+    method public static java.util.stream.DoubleStream generate(java.util.function.DoubleSupplier);
+    method public static java.util.stream.DoubleStream iterate(double, java.util.function.DoubleUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfDouble iterator();
+    method public abstract java.util.stream.DoubleStream limit(long);
+    method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
+    method public abstract java.util.OptionalDouble max();
+    method public abstract java.util.OptionalDouble min();
+    method public abstract boolean noneMatch(java.util.function.DoublePredicate);
+    method public static java.util.stream.DoubleStream of(double);
+    method public static java.util.stream.DoubleStream of(double...);
+    method public abstract java.util.stream.DoubleStream parallel();
+    method public abstract java.util.stream.DoubleStream peek(java.util.function.DoubleConsumer);
+    method public abstract double reduce(double, java.util.function.DoubleBinaryOperator);
+    method public abstract java.util.OptionalDouble reduce(java.util.function.DoubleBinaryOperator);
+    method public abstract java.util.stream.DoubleStream sequential();
+    method public abstract java.util.stream.DoubleStream skip(long);
+    method public abstract java.util.stream.DoubleStream sorted();
+    method public abstract java.util.Spliterator.OfDouble spliterator();
+    method public abstract double sum();
+    method public abstract java.util.DoubleSummaryStatistics summaryStatistics();
+    method public abstract double[] toArray();
+  }
+
+  public static abstract interface DoubleStream.Builder implements java.util.function.DoubleConsumer {
+    method public abstract void accept(double);
+    method public default java.util.stream.DoubleStream.Builder add(double);
+    method public abstract java.util.stream.DoubleStream build();
+  }
+
+  public abstract interface IntStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.IntPredicate);
+    method public abstract boolean anyMatch(java.util.function.IntPredicate);
+    method public abstract java.util.stream.DoubleStream asDoubleStream();
+    method public abstract java.util.stream.LongStream asLongStream();
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
+    method public static java.util.stream.IntStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
+    method public abstract long count();
+    method public abstract java.util.stream.IntStream distinct();
+    method public static java.util.stream.IntStream empty();
+    method public abstract java.util.stream.IntStream filter(java.util.function.IntPredicate);
+    method public abstract java.util.OptionalInt findAny();
+    method public abstract java.util.OptionalInt findFirst();
+    method public abstract java.util.stream.IntStream flatMap(java.util.function.IntFunction<? extends java.util.stream.IntStream>);
+    method public abstract void forEach(java.util.function.IntConsumer);
+    method public abstract void forEachOrdered(java.util.function.IntConsumer);
+    method public static java.util.stream.IntStream generate(java.util.function.IntSupplier);
+    method public static java.util.stream.IntStream iterate(int, java.util.function.IntUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfInt iterator();
+    method public abstract java.util.stream.IntStream limit(long);
+    method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
+    method public abstract java.util.OptionalInt max();
+    method public abstract java.util.OptionalInt min();
+    method public abstract boolean noneMatch(java.util.function.IntPredicate);
+    method public static java.util.stream.IntStream of(int);
+    method public static java.util.stream.IntStream of(int...);
+    method public abstract java.util.stream.IntStream parallel();
+    method public abstract java.util.stream.IntStream peek(java.util.function.IntConsumer);
+    method public static java.util.stream.IntStream range(int, int);
+    method public static java.util.stream.IntStream rangeClosed(int, int);
+    method public abstract int reduce(int, java.util.function.IntBinaryOperator);
+    method public abstract java.util.OptionalInt reduce(java.util.function.IntBinaryOperator);
+    method public abstract java.util.stream.IntStream sequential();
+    method public abstract java.util.stream.IntStream skip(long);
+    method public abstract java.util.stream.IntStream sorted();
+    method public abstract java.util.Spliterator.OfInt spliterator();
+    method public abstract int sum();
+    method public abstract java.util.IntSummaryStatistics summaryStatistics();
+    method public abstract int[] toArray();
+  }
+
+  public static abstract interface IntStream.Builder implements java.util.function.IntConsumer {
+    method public abstract void accept(int);
+    method public default java.util.stream.IntStream.Builder add(int);
+    method public abstract java.util.stream.IntStream build();
+  }
+
+  public abstract interface LongStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.LongPredicate);
+    method public abstract boolean anyMatch(java.util.function.LongPredicate);
+    method public abstract java.util.stream.DoubleStream asDoubleStream();
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Long> boxed();
+    method public static java.util.stream.LongStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
+    method public abstract long count();
+    method public abstract java.util.stream.LongStream distinct();
+    method public static java.util.stream.LongStream empty();
+    method public abstract java.util.stream.LongStream filter(java.util.function.LongPredicate);
+    method public abstract java.util.OptionalLong findAny();
+    method public abstract java.util.OptionalLong findFirst();
+    method public abstract java.util.stream.LongStream flatMap(java.util.function.LongFunction<? extends java.util.stream.LongStream>);
+    method public abstract void forEach(java.util.function.LongConsumer);
+    method public abstract void forEachOrdered(java.util.function.LongConsumer);
+    method public static java.util.stream.LongStream generate(java.util.function.LongSupplier);
+    method public static java.util.stream.LongStream iterate(long, java.util.function.LongUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfLong iterator();
+    method public abstract java.util.stream.LongStream limit(long);
+    method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
+    method public abstract java.util.OptionalLong max();
+    method public abstract java.util.OptionalLong min();
+    method public abstract boolean noneMatch(java.util.function.LongPredicate);
+    method public static java.util.stream.LongStream of(long);
+    method public static java.util.stream.LongStream of(long...);
+    method public abstract java.util.stream.LongStream parallel();
+    method public abstract java.util.stream.LongStream peek(java.util.function.LongConsumer);
+    method public static java.util.stream.LongStream range(long, long);
+    method public static java.util.stream.LongStream rangeClosed(long, long);
+    method public abstract long reduce(long, java.util.function.LongBinaryOperator);
+    method public abstract java.util.OptionalLong reduce(java.util.function.LongBinaryOperator);
+    method public abstract java.util.stream.LongStream sequential();
+    method public abstract java.util.stream.LongStream skip(long);
+    method public abstract java.util.stream.LongStream sorted();
+    method public abstract java.util.Spliterator.OfLong spliterator();
+    method public abstract long sum();
+    method public abstract java.util.LongSummaryStatistics summaryStatistics();
+    method public abstract long[] toArray();
+  }
+
+  public static abstract interface LongStream.Builder implements java.util.function.LongConsumer {
+    method public abstract void accept(long);
+    method public default java.util.stream.LongStream.Builder add(long);
+    method public abstract java.util.stream.LongStream build();
+  }
+
+  public abstract interface Stream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
+    method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Stream.Builder<T> builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
+    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
+    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
+    method public abstract long count();
+    method public abstract java.util.stream.Stream<T> distinct();
+    method public static java.util.stream.Stream<T> empty();
+    method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
+    method public abstract java.util.Optional<T> findAny();
+    method public abstract java.util.Optional<T> findFirst();
+    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
+    method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
+    method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
+    method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
+    method public abstract void forEach(java.util.function.Consumer<? super T>);
+    method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
+    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
+    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
+    method public abstract java.util.stream.Stream<T> limit(long);
+    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
+    method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
+    method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
+    method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Stream<T> of(T);
+    method public static java.util.stream.Stream<T> of(T...);
+    method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
+    method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
+    method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
+    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
+    method public abstract java.util.stream.Stream<T> skip(long);
+    method public abstract java.util.stream.Stream<T> sorted();
+    method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
+    method public abstract java.lang.Object[] toArray();
+    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
+  }
+
+  public static abstract interface Stream.Builder implements java.util.function.Consumer {
+    method public abstract void accept(T);
+    method public default java.util.stream.Stream.Builder<T> add(T);
+    method public abstract java.util.stream.Stream<T> build();
+  }
+
+  public final class StreamSupport {
+    method public static java.util.stream.DoubleStream doubleStream(java.util.Spliterator.OfDouble, boolean);
+    method public static java.util.stream.DoubleStream doubleStream(java.util.function.Supplier<? extends java.util.Spliterator.OfDouble>, int, boolean);
+    method public static java.util.stream.IntStream intStream(java.util.Spliterator.OfInt, boolean);
+    method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
+    method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
+    method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
+    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
+    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
+  }
+
+}
+
 package java.util.zip {
 
   public class Adler32 implements java.util.zip.Checksum {
@@ -65729,11 +67009,9 @@
 
   public final class PrivateCredentialPermission extends java.security.Permission {
     ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getCredentialClass();
     method public java.lang.String[][] getPrincipals();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 27de913..03cf8b0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -6,12 +6,51 @@
 
 }
 
+package android.app.admin {
+
+  public class DevicePolicyManager {
+    method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+    method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
+  }
+
+}
+
+package android.content {
+
+  public abstract class Context {
+    method public deprecated android.content.Context createCredentialEncryptedStorageContext();
+    method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+    method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+    method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
+    method public deprecated boolean isCredentialEncryptedStorage();
+    method public deprecated boolean isDeviceEncryptedStorage();
+    method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
+    method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+  }
+
+}
+
 package android.content.pm {
 
+  public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    field public deprecated java.lang.String credentialEncryptedDataDir;
+    field public deprecated java.lang.String deviceEncryptedDataDir;
+  }
+
+  public class ComponentInfo extends android.content.pm.PackageItemInfo {
+    field public deprecated boolean encryptionAware;
+  }
+
   public class PackageInfo implements android.os.Parcelable {
     field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
   }
 
+  public abstract class PackageManager {
+    field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
+    field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
+    field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+  }
+
 }
 
 package android.database {
@@ -24,14 +63,45 @@
 
 }
 
+package android.graphics {
+
+  public deprecated class AvoidXfermode extends android.graphics.Xfermode {
+    ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
+  }
+
+  public static final class AvoidXfermode.Mode extends java.lang.Enum {
+    method public static android.graphics.AvoidXfermode.Mode valueOf(java.lang.String);
+    method public static final android.graphics.AvoidXfermode.Mode[] values();
+    enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
+    enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
+  }
+
+  public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
+    ctor public PixelXorXfermode(int);
+  }
+
+}
+
 package android.media {
 
-  public class AudioFormat {
+  public final class AudioFormat implements android.os.Parcelable {
     ctor public AudioFormat();
   }
 
 }
 
+package android.media.tv {
+
+  public final class TvInputManager {
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+  }
+
+  public class TvView extends android.view.ViewGroup {
+    method public void requestUnblockContent(android.media.tv.TvContentRating);
+  }
+
+}
+
 package android.net {
 
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
@@ -60,6 +130,28 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndLocked();
+    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndUnlocked();
+    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
+  }
+
+}
+
+package android.os.storage {
+
+  public class StorageManager {
+    method public android.os.storage.StorageVolume getPrimaryVolume();
+    method public android.os.storage.StorageVolume[] getVolumeList();
+  }
+
+}
+
+package android.preference {
+
+  public class PreferenceManager {
+    method public deprecated void setStorageCredentialEncrypted();
+    method public deprecated void setStorageDeviceEncrypted();
   }
 
 }
diff --git a/api/test-current.txt b/api/test-current.txt
index 3878fbf..8a745bf 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -38,6 +38,7 @@
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
     field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+    field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -70,6 +71,7 @@
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -101,7 +103,6 @@
     field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
     field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
     field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
-    field public static final java.lang.String READ_WRITE_CONTACT_METADATA = "android.permission.READ_WRITE_CONTACT_METADATA";
     field public static final java.lang.String REBOOT = "android.permission.REBOOT";
     field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
     field public static final java.lang.String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
@@ -115,6 +116,7 @@
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
+    field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
     field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
     field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
@@ -338,6 +340,7 @@
     field public static final int calendarViewStyle = 16843613; // 0x101035d
     field public static final int canControlMagnification = 16844040; // 0x1010508
     field public static final int canPerformGestures = 16844046; // 0x101050e
+    field public static final int canRecord = 16844061; // 0x101051d
     field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
     field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
     field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -414,15 +417,18 @@
     field public static final int contentAuthority = 16843408; // 0x1010290
     field public static final int contentDescription = 16843379; // 0x1010273
     field public static final int contentInsetEnd = 16843860; // 0x1010454
+    field public static final int contentInsetEndWithActions = 16844070; // 0x1010526
     field public static final int contentInsetLeft = 16843861; // 0x1010455
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
+    field public static final int contentInsetStartWithNavigation = 16844069; // 0x1010525
     field public static final int contextClickable = 16844007; // 0x10104e7
     field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
     field public static final int controlY2 = 16843775; // 0x10103ff
+    field public static final int countDown = 16844060; // 0x101051c
     field public static final int country = 16843962; // 0x10104ba
     field public static final int cropToPadding = 16843043; // 0x1010123
     field public static final int cursorVisible = 16843090; // 0x1010152
@@ -440,6 +446,7 @@
     field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
     field public static final int debuggable = 16842767; // 0x101000f
     field public static final int defaultHeight = 16844021; // 0x10104f5
+    field public static final int defaultToDeviceProtectedStorage = 16844037; // 0x1010505
     field public static final int defaultValue = 16843245; // 0x10101ed
     field public static final int defaultWidth = 16844020; // 0x10104f4
     field public static final int delay = 16843212; // 0x10101cc
@@ -459,6 +466,7 @@
     field public static final int dialogTheme = 16843528; // 0x1010308
     field public static final int dialogTitle = 16843250; // 0x10101f2
     field public static final int digits = 16843110; // 0x1010166
+    field public static final int directBootAware = 16844038; // 0x1010506
     field public static final int direction = 16843217; // 0x10101d1
     field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
     field public static final int directionPriority = 16843218; // 0x10101d2
@@ -507,7 +515,6 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
-    field public static final int encryptionAware = 16844038; // 0x1010506
     field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
     field public static final int endX = 16844051; // 0x1010513
@@ -556,6 +563,7 @@
     field public static final int fillBefore = 16843196; // 0x10101bc
     field public static final int fillColor = 16843780; // 0x1010404
     field public static final int fillEnabled = 16843343; // 0x101024f
+    field public static final int fillType = 16844064; // 0x1010520
     field public static final int fillViewport = 16843130; // 0x101017a
     field public static final int filter = 16843035; // 0x101011b
     field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -571,7 +579,7 @@
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
-    field public static final int forceDeviceEncrypted = 16844037; // 0x1010505
+    field public static final int forceHasOverlappingRendering = 16844068; // 0x1010524
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
     field public static final int foregroundTint = 16843885; // 0x101046d
@@ -855,7 +863,8 @@
     field public static final int minResizeWidth = 16843669; // 0x1010395
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
-    field public static final int minimalSize = 16844022; // 0x10104f6
+    field public static final int minimalHeight = 16844067; // 0x1010523
+    field public static final int minimalWidth = 16844022; // 0x10104f6
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
@@ -876,6 +885,7 @@
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
+    field public static final int nfcAntennaPositionDrawable = 16844063; // 0x101051f
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -939,6 +949,8 @@
     field public static final int popupBackground = 16843126; // 0x1010176
     field public static final int popupCharacters = 16843332; // 0x1010244
     field public static final int popupElevation = 16843916; // 0x101048c
+    field public static final int popupEnterTransition = 16844065; // 0x1010521
+    field public static final int popupExitTransition = 16844066; // 0x1010522
     field public static final int popupKeyboard = 16843331; // 0x1010243
     field public static final int popupLayout = 16843323; // 0x101023b
     field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -1358,6 +1370,7 @@
     field public static final int trimPathEnd = 16843785; // 0x1010409
     field public static final int trimPathOffset = 16843786; // 0x101040a
     field public static final int trimPathStart = 16843784; // 0x1010408
+    field public static final int tunerCount = 16844062; // 0x101051e
     field public static final int type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
@@ -2472,6 +2485,7 @@
     field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
     field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
     field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+    field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
     field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
     field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
     field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2506,6 +2520,7 @@
     field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
     field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
     field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+    field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
     field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
     field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
     field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -2663,8 +2678,11 @@
     field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
     field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
     field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+    field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+    field public static final int SHOW_MODE_AUTO = 0; // 0x0
+    field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
   }
 
   public static abstract class AccessibilityService.GestureResultCallback {
@@ -2745,14 +2763,10 @@
   }
 
   public final class GestureDescription {
-    method public static android.accessibilityservice.GestureDescription createClick(int, int);
-    method public static android.accessibilityservice.GestureDescription createLongClick(int, int);
-    method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long);
-    method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long);
+    method public static long getMaxGestureDuration();
+    method public static int getMaxStrokeCount();
     method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int);
     method public int getStrokeCount();
-    field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L
-    field public static final int MAX_STROKE_COUNT = 10; // 0xa
   }
 
   public static class GestureDescription.Builder {
@@ -3414,7 +3428,7 @@
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public void enterPictureInPicture();
+    method public void enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3434,7 +3448,7 @@
     method public android.view.View getCurrentFocus();
     method public android.app.FragmentManager getFragmentManager();
     method public android.content.Intent getIntent();
-    method public deprecated java.lang.Object getLastNonConfigurationInstance();
+    method public java.lang.Object getLastNonConfigurationInstance();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.LoaderManager getLoaderManager();
     method public java.lang.String getLocalClassName();
@@ -3454,15 +3468,16 @@
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
     method public boolean hasWindowFocus();
-    method public boolean inMultiWindow();
-    method public boolean inPictureInPicture();
     method public void invalidateOptionsMenu();
     method public boolean isChangingConfigurations();
     method public final boolean isChild();
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isInMultiWindowMode();
+    method public boolean isInPictureInPictureMode();
     method public boolean isLocalVoiceInteractionSupported();
+    method public boolean isOverlayWithDecorCaptionEnabled();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3509,7 +3524,7 @@
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onNavigateUp();
     method public boolean onNavigateUpFromChild(android.app.Activity);
     method protected void onNewIntent(android.content.Intent);
@@ -3517,7 +3532,7 @@
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method protected void onPostCreate(android.os.Bundle);
     method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
@@ -3528,14 +3543,13 @@
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
     method public void onProvideAssistContent(android.app.assist.AssistContent);
     method public void onProvideAssistData(android.os.Bundle);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public android.net.Uri onProvideReferrer();
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method protected void onRestart();
     method protected void onRestoreInstanceState(android.os.Bundle);
     method public void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method protected void onResume();
-    method public deprecated java.lang.Object onRetainNonConfigurationInstance();
+    method public java.lang.Object onRetainNonConfigurationInstance();
     method protected void onSaveInstanceState(android.os.Bundle);
     method public void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method public boolean onSearchRequested(android.view.SearchEvent);
@@ -3556,7 +3570,6 @@
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
-    method public void overlayWithDecorCaption(boolean);
     method public void overridePendingTransition(int, int);
     method public void postponeEnterTransition();
     method public void recreate();
@@ -3585,6 +3598,7 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
+    method public void setOverlayWithDecorCaptionEnabled(boolean);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3599,7 +3613,7 @@
     method public deprecated void setTitleColor(int);
     method public void setVisible(boolean);
     method public final void setVolumeControlStream(int);
-    method public void setVrMode(boolean);
+    method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean shouldShowRequestPermissionRationale(java.lang.String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
@@ -4123,13 +4137,12 @@
     field public java.lang.String serviceDetails;
   }
 
-  public class AutomaticZenRule implements android.os.Parcelable {
+  public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
     method public long getCreationTime();
-    method public java.lang.String getId();
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
@@ -4211,7 +4224,6 @@
     method public void onPanelClosed(int, android.view.Menu);
     method public boolean onPrepareOptionsMenu(android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public void onRestoreInstanceState(android.os.Bundle);
     method public android.os.Bundle onSaveInstanceState();
     method public boolean onSearchRequested(android.view.SearchEvent);
@@ -4429,11 +4441,11 @@
     method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
     method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method public void onPrepareOptionsMenu(android.view.Menu);
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method public void onResume();
@@ -4514,11 +4526,11 @@
     method public void dispatchDestroy();
     method public void dispatchDestroyView();
     method public void dispatchLowMemory();
-    method public void dispatchMultiWindowChanged(boolean);
+    method public void dispatchMultiWindowModeChanged(boolean);
     method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
     method public void dispatchOptionsMenuClosed(android.view.Menu);
     method public void dispatchPause();
-    method public void dispatchPictureInPictureChanged(boolean);
+    method public void dispatchPictureInPictureModeChanged(boolean);
     method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
     method public void dispatchResume();
     method public void dispatchStart();
@@ -4905,6 +4917,7 @@
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
     field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
     field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
@@ -5046,16 +5059,17 @@
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
+    method public android.widget.RemoteViews createBigContentView();
+    method public android.widget.RemoteViews createContentView();
+    method public android.widget.RemoteViews createHeadsUpContentView();
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
-    method public android.widget.RemoteViews makeBigContentView();
-    method public android.widget.RemoteViews makeContentView();
-    method public android.widget.RemoteViews makeHeadsUpContentView();
     method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setChronometerCountsDown(boolean);
     method public android.app.Notification.Builder setColor(int);
     method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
@@ -5224,14 +5238,14 @@
   }
 
   public class NotificationManager {
-    method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
-    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
+    method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5241,7 +5255,7 @@
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
-    method public boolean updateAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5253,7 +5267,7 @@
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
@@ -5710,6 +5724,7 @@
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clear(int) throws java.io.IOException;
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
     method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -5721,6 +5736,7 @@
     method public android.graphics.drawable.Drawable getFastDrawable();
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.os.ParcelFileDescriptor getWallpaperFile(int);
+    method public int getWallpaperId(int);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
     method public boolean isWallpaperSettingAllowed();
@@ -5746,8 +5762,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
-    field public static final int FLAG_SET_LOCK = 2; // 0x2
-    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+    field public static final int FLAG_LOCK = 2; // 0x2
+    field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5831,9 +5847,7 @@
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
-    method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
     method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
-    method public deprecated android.os.UserHandle createUser(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();
@@ -5849,8 +5863,7 @@
     method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
     method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
-    method public boolean getDeviceLoggingEnabled(android.content.ComponentName);
-    method public java.lang.String getDeviceOwnerLockScreenInfo();
+    method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public java.lang.String getLongSupportMessage(android.content.ComponentName);
@@ -5858,7 +5871,6 @@
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
     method public java.lang.String getOrganizationName(android.content.ComponentName);
-    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5883,20 +5895,24 @@
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
     method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
-    method public java.lang.String getWifiMacAddress();
+    method public java.lang.String getWifiMacAddress(android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
     method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
+    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
+    method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
+    method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
     method public void reboot(android.content.ComponentName);
@@ -5906,21 +5922,20 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
-    method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrieveDeviceLogs(android.content.ComponentName);
-    method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrievePreviousDeviceLogs(android.content.ComponentName);
+    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
+    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
-    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
+    method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
-    method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
+    method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
-    method public void setDeviceLoggingEnabled(android.content.ComponentName, boolean);
-    method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+    method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -5952,6 +5967,7 @@
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+    method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
     method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
@@ -5975,6 +5991,7 @@
     field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
     field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
     field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
+    field public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5; // 0x5
     field public static final int ENCRYPTION_STATUS_INACTIVE = 1; // 0x1
     field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
     field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
@@ -6036,6 +6053,27 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public class SecurityLog {
+    ctor public SecurityLog();
+    field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
+    field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
+    field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
+    field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
+    field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
+  }
+
+  public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.Object getData();
+    method public int getTag();
+    method public long getTimeNanos();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
+  }
+
   public class SystemUpdatePolicy implements android.os.Parcelable {
     method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -6240,6 +6278,8 @@
     method public long getIntervalMillis();
     method public long getMaxExecutionDelayMillis();
     method public long getMinLatencyMillis();
+    method public static final long getMinimumFlex();
+    method public static final long getMinimumPeriod();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
@@ -6253,8 +6293,6 @@
     field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
     field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
     field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
-    field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
-    field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
     field public static final int NETWORK_TYPE_ANY = 1; // 0x1
     field public static final int NETWORK_TYPE_NONE = 0; // 0x0
     field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6368,8 +6406,8 @@
     method public long getTxPackets();
     method public int getUid();
     field public static final int ROAMING_ALL = -1; // 0xffffffff
-    field public static final int ROAMING_DEFAULT = 1; // 0x1
-    field public static final int ROAMING_ROAMING = 2; // 0x2
+    field public static final int ROAMING_NO = 1; // 0x1
+    field public static final int ROAMING_YES = 2; // 0x2
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
@@ -6576,31 +6614,6 @@
 
 }
 
-package android.auditing {
-
-  public class SecurityLog {
-    ctor public SecurityLog();
-    field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
-    field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
-    field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
-    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
-    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
-    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
-    field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
-    field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
-  }
-
-  public static class SecurityLog.SecurityEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.lang.Object getData();
-    method public int getTag();
-    method public long getTimeNanos();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.auditing.SecurityLog.SecurityEvent> CREATOR;
-  }
-
-}
-
 package android.bluetooth {
 
   public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
@@ -7103,9 +7116,10 @@
     method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
   }
 
-  public class BluetoothGattCharacteristic {
+  public class BluetoothGattCharacteristic implements android.os.Parcelable {
     ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
     method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
     method public java.lang.Float getFloatValue(int, int);
@@ -7123,6 +7137,8 @@
     method public boolean setValue(int, int, int, int);
     method public boolean setValue(java.lang.String);
     method public void setWriteType(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
     field public static final int FORMAT_FLOAT = 52; // 0x34
     field public static final int FORMAT_SFLOAT = 50; // 0x32
     field public static final int FORMAT_SINT16 = 34; // 0x22
@@ -7153,13 +7169,16 @@
     field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors;
   }
 
-  public class BluetoothGattDescriptor {
+  public class BluetoothGattDescriptor implements android.os.Parcelable {
     ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
     method public int getPermissions();
     method public java.util.UUID getUuid();
     method public byte[] getValue();
     method public boolean setValue(byte[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
     field public static final byte[] DISABLE_NOTIFICATION_VALUE;
     field public static final byte[] ENABLE_INDICATION_VALUE;
     field public static final byte[] ENABLE_NOTIFICATION_VALUE;
@@ -7202,16 +7221,19 @@
     method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
   }
 
-  public class BluetoothGattService {
+  public class BluetoothGattService implements android.os.Parcelable {
     ctor public BluetoothGattService(java.util.UUID, int);
     method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
     method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
     method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
     method public int getInstanceId();
     method public int getType();
     method public java.util.UUID getUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattService> CREATOR;
     field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
     field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
     field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics;
@@ -7334,15 +7356,6 @@
     field public static final int TYPE_SCO = 2; // 0x2
   }
 
-  public class OobData implements android.os.Parcelable {
-    ctor public OobData();
-    method public int describeContents();
-    method public byte[] getSecurityManagerTk();
-    method public void setSecurityManagerTk(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
-  }
-
 }
 
 package android.bluetooth.le {
@@ -7984,7 +7997,7 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public abstract android.content.Context createDeviceEncryptedStorageContext();
+    method public abstract android.content.Context createDeviceProtectedStorageContext();
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -8029,8 +8042,6 @@
     method public abstract java.lang.String getPackageResourcePath();
     method public abstract android.content.res.Resources getResources();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -8043,10 +8054,10 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public abstract boolean isDeviceEncryptedStorage();
+    method public abstract boolean isDeviceProtectedStorage();
     method public boolean isRestricted();
-    method public abstract boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public abstract boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public abstract boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public abstract boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[]);
@@ -8120,7 +8131,7 @@
     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 HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
+    field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
     field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
@@ -8148,7 +8159,9 @@
     field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
+    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
@@ -8179,7 +8192,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createDeviceEncryptedStorageContext();
+    method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -8222,8 +8235,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -8232,9 +8243,9 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isDeviceEncryptedStorage();
-    method public boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public boolean isDeviceProtectedStorage();
+    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -8475,6 +8486,7 @@
     field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
     field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
     field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
+    field public static final java.lang.String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
     field public static final java.lang.String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
     field public static final java.lang.String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
     field public static final java.lang.String ACTION_ASSIST = "android.intent.action.ASSIST";
@@ -8518,8 +8530,9 @@
     field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
     field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
     field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
     field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -9259,7 +9272,6 @@
     field public int documentLaunchMode;
     field public int flags;
     field public int launchMode;
-    field public android.content.pm.ActivityInfo.Layout layout;
     field public int maxRecents;
     field public java.lang.String parentActivityName;
     field public java.lang.String permission;
@@ -9270,14 +9282,16 @@
     field public java.lang.String taskAffinity;
     field public int theme;
     field public int uiOptions;
+    field public android.content.pm.ActivityInfo.WindowLayout windowLayout;
   }
 
-  public static final class ActivityInfo.Layout {
-    ctor public ActivityInfo.Layout(int, float, int, float, int, int);
+  public static final class ActivityInfo.WindowLayout {
+    ctor public ActivityInfo.WindowLayout(int, float, int, float, int, int, int);
     field public final int gravity;
     field public final int height;
     field public final float heightFraction;
-    field public final int minimalSize;
+    field public final int minimalHeight;
+    field public final int minimalWidth;
     field public final int width;
     field public final float widthFraction;
   }
@@ -9326,14 +9340,14 @@
     field public java.lang.String backupAgentName;
     field public java.lang.String className;
     field public int compatibleWidthLimitDp;
-    field public java.lang.String credentialEncryptedDataDir;
     field public java.lang.String dataDir;
     field public int descriptionRes;
-    field public java.lang.String deviceEncryptedDataDir;
+    field public java.lang.String deviceProtectedDataDir;
     field public boolean enabled;
     field public int flags;
     field public int largestWidthLimitDp;
     field public java.lang.String manageSpaceActivityName;
+    field public java.lang.String minSdkVersion;
     field public java.lang.String nativeLibraryDir;
     field public java.lang.String permission;
     field public java.lang.String processName;
@@ -9365,8 +9379,8 @@
     method public boolean isEnabled();
     field public android.content.pm.ApplicationInfo applicationInfo;
     field public int descriptionRes;
+    field public boolean directBootAware;
     field public boolean enabled;
-    field public boolean encryptionAware;
     field public boolean exported;
     field public java.lang.String processName;
   }
@@ -9455,13 +9469,20 @@
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
+    method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+    method public boolean hasShortcutHostPermission();
     method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+    method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
   }
 
@@ -9474,6 +9495,18 @@
     method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
     method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+    method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
+  }
+
+  public static class LauncherApps.ShortcutQuery {
+    ctor public LauncherApps.ShortcutQuery();
+    method public void setActivity(android.content.ComponentName);
+    method public void setChangedSince(long);
+    method public void setPackage(java.lang.String);
+    method public void setQueryFlags(int);
+    field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_GET_PINNED = 2; // 0x2
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -9551,6 +9584,7 @@
     method public java.lang.String[] getNames() throws java.io.IOException;
     method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
     method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+    method public void removeSplit(java.lang.String) throws java.io.IOException;
     method public void setStagingProgress(float);
   }
 
@@ -9793,6 +9827,8 @@
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -9816,11 +9852,10 @@
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
+    field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
     field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
     field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
-    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
     field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
     field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
@@ -9895,6 +9930,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
     field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -9972,6 +10008,61 @@
     field public java.lang.String permission;
   }
 
+  public final class ShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivityComponent();
+    method public android.os.PersistableBundle getExtras();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public long getLastChangedTimestamp();
+    method public java.lang.String getPackageName();
+    method public java.lang.String getText();
+    method public java.lang.String getTitle();
+    method public int getWeight();
+    method public boolean hasIconFile();
+    method public boolean hasIconResource();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean isDynamic();
+    method public boolean isPinned();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
+    field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
+    field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int FLAG_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
+    field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+    field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
+    field public static final int FLAG_PINNED = 2; // 0x2
+  }
+
+  public static class ShortcutInfo.Builder {
+    ctor public ShortcutInfo.Builder(android.content.Context);
+    method public android.content.pm.ShortcutInfo build();
+    method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
+    method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setWeight(int);
+  }
+
+  public class ShortcutManager {
+    method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
+    method public void deleteAllDynamicShortcuts();
+    method public void deleteDynamicShortcut(java.lang.String);
+    method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+    method public int getIconMaxDimensions();
+    method public int getMaxDynamicShortcutCount();
+    method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public long getRateLimitResetTime();
+    method public int getRemainingCallCount();
+    method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+  }
+
   public class Signature implements android.os.Parcelable {
     ctor public Signature(byte[]);
     ctor public Signature(java.lang.String);
@@ -10043,7 +10134,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
+  public class ColorStateList implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -10052,18 +10143,13 @@
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
+    method public boolean isStateful();
     method public static android.content.res.ColorStateList valueOf(int);
     method public android.content.res.ColorStateList withAlpha(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
   }
 
-  public abstract class ComplexColor {
-    ctor public ComplexColor();
-    method public abstract int getDefaultColor();
-    method public boolean isStateful();
-  }
-
   public final class Configuration implements java.lang.Comparable android.os.Parcelable {
     ctor public Configuration();
     ctor public Configuration(android.content.res.Configuration);
@@ -10167,11 +10253,6 @@
     field public int uiMode;
   }
 
-  public class GradientColor extends android.content.res.ComplexColor {
-    method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public int getDefaultColor();
-  }
-
   public class ObbInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -10231,7 +10312,6 @@
     method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
     method public final android.content.res.Resources.Theme newTheme();
     method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
     method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10267,7 +10347,6 @@
     method public int getChangingConfigurations();
     method public int getColor(int, int);
     method public android.content.res.ColorStateList getColorStateList(int);
-    method public android.content.res.ComplexColor getComplexColor(int);
     method public float getDimension(int, float);
     method public int getDimensionPixelOffset(int, int);
     method public int getDimensionPixelSize(int, int);
@@ -10477,7 +10556,6 @@
     method public boolean hasNext();
     method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
     method public android.database.CursorJoiner.Result next();
-    method public void remove();
   }
 
   public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -11408,17 +11486,6 @@
 
 package android.graphics {
 
-  public deprecated class AvoidXfermode extends android.graphics.Xfermode {
-    ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
-  }
-
-  public static final class AvoidXfermode.Mode extends java.lang.Enum {
-    method public static android.graphics.AvoidXfermode.Mode valueOf(java.lang.String);
-    method public static final android.graphics.AvoidXfermode.Mode[] values();
-    enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
-    enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
-  }
-
   public final class Bitmap implements android.os.Parcelable {
     method public boolean compress(android.graphics.Bitmap.CompressFormat, int, java.io.OutputStream);
     method public android.graphics.Bitmap copy(android.graphics.Bitmap.Config, boolean);
@@ -11954,6 +12021,8 @@
     ctor public Outline(android.graphics.Outline);
     method public boolean canClip();
     method public float getAlpha();
+    method public float getRadius();
+    method public boolean getRect(android.graphics.Rect);
     method public boolean isEmpty();
     method public void offset(int, int);
     method public void set(android.graphics.Outline);
@@ -12283,10 +12352,6 @@
     field public int bytesPerPixel;
   }
 
-  public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
-    ctor public PixelXorXfermode(int);
-  }
-
   public class Point implements android.os.Parcelable {
     ctor public Point();
     ctor public Point(int, int);
@@ -12846,7 +12911,8 @@
     method public int getGradientType();
     method public int getOpacity();
     method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
-    method public boolean isUseLevel();
+    method public int getShape();
+    method public boolean getUseLevel();
     method public void setAlpha(int);
     method public void setColor(int);
     method public void setColor(android.content.res.ColorStateList);
@@ -12965,9 +13031,9 @@
     method public void setPaddingMode(int);
     method public void setPaddingRelative(int, int, int, int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    field public static final int INSET_UNDEFINED = -2147483648; // 0x80000000
     field public static final int PADDING_MODE_NEST = 0; // 0x0
     field public static final int PADDING_MODE_STACK = 1; // 0x1
-    field public static final int UNDEFINED_INSET = -2147483648; // 0x80000000
   }
 
   public class LevelListDrawable extends android.graphics.drawable.DrawableContainer {
@@ -12981,12 +13047,10 @@
     ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
     ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
     method public void draw(android.graphics.Canvas);
-    method public android.graphics.NinePatch getNinePatch();
     method public int getOpacity();
     method public android.graphics.Paint getPaint();
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setNinePatch(android.graphics.NinePatch);
     method public void setTargetDensity(android.graphics.Canvas);
     method public void setTargetDensity(android.util.DisplayMetrics);
     method public void setTargetDensity(int);
@@ -13209,8 +13273,8 @@
     method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
     method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
     method public final void unlock();
-    field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
-    field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+    field public static final deprecated java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
+    field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
     field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
     field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -13455,6 +13519,7 @@
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
+    method public int getId();
     method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
@@ -13464,9 +13529,10 @@
     method public float getResolution();
     method public java.lang.String getStringType();
     method public int getType();
-    method public java.util.UUID getUuid();
     method public java.lang.String getVendor();
     method public int getVersion();
+    method public boolean isAdditionalInfoSupported();
+    method public boolean isDynamicSensor();
     method public boolean isWakeUpSensor();
     field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
     field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13500,6 +13566,7 @@
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
+    field public static final int TYPE_DEVICE_PRIVATE_BASE = 65536; // 0x10000
     field public static final int TYPE_GAME_ROTATION_VECTOR = 15; // 0xf
     field public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; // 0x14
     field public static final int TYPE_GRAVITY = 9; // 0x9
@@ -13584,8 +13651,9 @@
     method public static void getRotationMatrixFromVector(float[], float[]);
     method public java.util.List<android.hardware.Sensor> getSensorList(int);
     method public deprecated int getSensors();
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+    method public boolean isDynamicSensorDiscoverySupported();
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13594,7 +13662,7 @@
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
-    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
     method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13659,8 +13727,8 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
-  public static abstract class SensorManager.DynamicSensorConnectionCallback {
-    ctor public SensorManager.DynamicSensorConnectionCallback();
+  public static abstract class SensorManager.DynamicSensorCallback {
+    ctor public SensorManager.DynamicSensorCallback();
     method public void onDynamicSensorConnected(android.hardware.Sensor);
     method public void onDynamicSensorDisconnected(android.hardware.Sensor);
   }
@@ -13710,6 +13778,7 @@
 
   public static abstract class CameraCaptureSession.CaptureCallback {
     ctor public CameraCaptureSession.CaptureCallback();
+    method public void onCaptureBufferLost(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.view.Surface, long);
     method public void onCaptureCompleted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult);
     method public void onCaptureFailed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure);
     method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
@@ -14784,7 +14853,6 @@
 
   public static abstract interface UCharacter.BidiPairedBracketType {
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int OPEN = 1; // 0x1
   }
@@ -14793,7 +14861,6 @@
     field public static final int CANONICAL = 1; // 0x1
     field public static final int CIRCLE = 3; // 0x3
     field public static final int COMPAT = 2; // 0x2
-    field public static final int COUNT = 18; // 0x12
     field public static final int FINAL = 4; // 0x4
     field public static final int FONT = 5; // 0x5
     field public static final int FRACTION = 6; // 0x6
@@ -14813,7 +14880,6 @@
 
   public static abstract interface UCharacter.EastAsianWidth {
     field public static final int AMBIGUOUS = 1; // 0x1
-    field public static final int COUNT = 6; // 0x6
     field public static final int FULLWIDTH = 3; // 0x3
     field public static final int HALFWIDTH = 2; // 0x2
     field public static final int NARROW = 4; // 0x4
@@ -14823,7 +14889,6 @@
 
   public static abstract interface UCharacter.GraphemeClusterBreak {
     field public static final int CONTROL = 1; // 0x1
-    field public static final int COUNT = 13; // 0xd
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
     field public static final int L = 4; // 0x4
@@ -14839,7 +14904,6 @@
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int LEADING_JAMO = 1; // 0x1
     field public static final int LVT_SYLLABLE = 5; // 0x5
     field public static final int LV_SYLLABLE = 4; // 0x4
@@ -14855,7 +14919,6 @@
     field public static final int BEH = 4; // 0x4
     field public static final int BETH = 5; // 0x5
     field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
-    field public static final int COUNT = 86; // 0x56
     field public static final int DAL = 6; // 0x6
     field public static final int DALATH_RISH = 7; // 0x7
     field public static final int E = 8; // 0x8
@@ -14940,7 +15003,6 @@
   }
 
   public static abstract interface UCharacter.JoiningType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int DUAL_JOINING = 2; // 0x2
     field public static final int JOIN_CAUSING = 1; // 0x1
     field public static final int LEFT_JOINING = 3; // 0x3
@@ -14963,7 +15025,6 @@
     field public static final int COMPLEX_CONTEXT = 24; // 0x18
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
-    field public static final int COUNT = 40; // 0x28
     field public static final int EXCLAMATION = 11; // 0xb
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
@@ -14995,7 +15056,6 @@
   }
 
   public static abstract interface UCharacter.NumericType {
-    field public static final int COUNT = 4; // 0x4
     field public static final int DECIMAL = 1; // 0x1
     field public static final int DIGIT = 2; // 0x2
     field public static final int NONE = 0; // 0x0
@@ -15005,7 +15065,6 @@
   public static abstract interface UCharacter.SentenceBreak {
     field public static final int ATERM = 1; // 0x1
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 15; // 0xf
     field public static final int CR = 11; // 0xb
     field public static final int EXTEND = 12; // 0xc
     field public static final int FORMAT = 3; // 0x3
@@ -15148,7 +15207,6 @@
     field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
     field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
     field public static final int COPTIC_ID = 132; // 0x84
-    field public static final int COUNT = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
     field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
     field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -15562,7 +15620,6 @@
 
   public static abstract interface UCharacter.WordBreak {
     field public static final int ALETTER = 1; // 0x1
-    field public static final int COUNT = 17; // 0x11
     field public static final int CR = 8; // 0x8
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
@@ -15593,7 +15650,6 @@
   }
 
   public static abstract interface UCharacterEnums.ECharacterCategory {
-    field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
     field public static final byte CONTROL = 15; // 0xf
@@ -15633,7 +15689,6 @@
     field public static final int ARABIC_NUMBER = 5; // 0x5
     field public static final int BLOCK_SEPARATOR = 7; // 0x7
     field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
-    field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
     field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
     field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
     field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -15686,7 +15741,6 @@
     field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
     field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
     field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
-    field public static final int BINARY_LIMIT = 57; // 0x39
     field public static final int BINARY_START = 0; // 0x0
     field public static final int BLOCK = 4097; // 0x1001
     field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -15705,7 +15759,6 @@
     field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
     field public static final int DEPRECATED = 6; // 0x6
     field public static final int DIACRITIC = 7; // 0x7
-    field public static final int DOUBLE_LIMIT = 12289; // 0x3001
     field public static final int DOUBLE_START = 12288; // 0x3000
     field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
     field public static final int EXTENDER = 8; // 0x8
@@ -15724,7 +15777,6 @@
     field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
     field public static final int ID_CONTINUE = 15; // 0xf
     field public static final int ID_START = 16; // 0x10
-    field public static final int INT_LIMIT = 4118; // 0x1016
     field public static final int INT_START = 4096; // 0x1000
     field public static final int JOINING_GROUP = 4102; // 0x1006
     field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -15734,7 +15786,6 @@
     field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
     field public static final int LOWERCASE = 22; // 0x16
     field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
-    field public static final int MASK_LIMIT = 8193; // 0x2001
     field public static final int MASK_START = 8192; // 0x2000
     field public static final int MATH = 23; // 0x17
     field public static final int NAME = 16389; // 0x4005
@@ -15749,7 +15800,6 @@
     field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
     field public static final int NUMERIC_TYPE = 4105; // 0x1009
     field public static final int NUMERIC_VALUE = 12288; // 0x3000
-    field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
     field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
     field public static final int PATTERN_SYNTAX = 42; // 0x2a
     field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -15769,7 +15819,6 @@
     field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
     field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
     field public static final int SOFT_DOTTED = 27; // 0x1b
-    field public static final int STRING_LIMIT = 16398; // 0x400e
     field public static final int STRING_START = 16384; // 0x4000
     field public static final int S_TERM = 35; // 0x23
     field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -15786,7 +15835,6 @@
   }
 
   public static abstract interface UProperty.NameChoice {
-    field public static final int COUNT = 2; // 0x2
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
   }
@@ -15831,7 +15879,6 @@
     field public static final int CHAM = 66; // 0x42
     field public static final int CHEROKEE = 6; // 0x6
     field public static final int CIRTH = 67; // 0x43
-    field public static final int CODE_LIMIT = 167; // 0xa7
     field public static final int COMMON = 0; // 0x0
     field public static final int COPTIC = 7; // 0x7
     field public static final int CUNEIFORM = 101; // 0x65
@@ -16226,7 +16273,6 @@
 
   public final class CollationKey implements java.lang.Comparable {
     ctor public CollationKey(java.lang.String, byte[]);
-    ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int compareTo(android.icu.text.CollationKey);
     method public boolean equals(android.icu.text.CollationKey);
     method public android.icu.text.CollationKey getBound(int, int);
@@ -16236,7 +16282,6 @@
   }
 
   public static final class CollationKey.BoundMode {
-    field public static final int COUNT = 3; // 0x3
     field public static final int LOWER = 0; // 0x0
     field public static final int UPPER = 1; // 0x1
     field public static final int UPPER_LONG = 2; // 0x2
@@ -16268,7 +16313,6 @@
     method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
     method public static final java.lang.String[] getKeywords();
     method public int getMaxVariable();
-    method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int[] getReorderCodes();
     method public int getStrength();
     method public android.icu.text.UnicodeSet getTailoredSet();
@@ -16308,7 +16352,6 @@
     field public static final int DEFAULT = -1; // 0xffffffff
     field public static final int DIGIT = 4100; // 0x1004
     field public static final int FIRST = 4096; // 0x1000
-    field public static final int LIMIT = 4101; // 0x1005
     field public static final int NONE = 103; // 0x67
     field public static final int OTHERS = 103; // 0x67
     field public static final int PUNCTUATION = 4097; // 0x1001
@@ -16421,7 +16464,6 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
-    field public static final int FIELD_COUNT = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16665,7 +16707,6 @@
     field public static final int MONTH = 3; // 0x3
     field public static final int QUARTER = 2; // 0x2
     field public static final int SECOND = 13; // 0xd
-    field public static final int TYPE_LIMIT = 16; // 0x10
     field public static final int WEEKDAY = 6; // 0x6
     field public static final int WEEK_OF_MONTH = 5; // 0x5
     field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -17296,14 +17337,6 @@
     enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
   }
 
-  public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
-    ctor public RawCollationKey();
-    ctor public RawCollationKey(int);
-    ctor public RawCollationKey(byte[]);
-    ctor public RawCollationKey(byte[], int);
-    method public int compareTo(android.icu.text.RawCollationKey);
-  }
-
   public final class RelativeDateTimeFormatter {
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -17387,7 +17420,6 @@
     method public android.icu.text.CollationKey getCollationKey(java.lang.String);
     method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
     method public boolean getNumericCollation();
-    method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public java.lang.String getRules();
     method public java.lang.String getRules(boolean);
     method public android.icu.util.VersionInfo getUCAVersion();
@@ -17718,9 +17750,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17734,10 +17763,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -17780,7 +17805,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -17795,7 +17819,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
@@ -17891,19 +17914,6 @@
     field public static final int BE = 0; // 0x0
   }
 
-  public class ByteArrayWrapper implements java.lang.Comparable {
-    ctor public ByteArrayWrapper();
-    ctor public ByteArrayWrapper(byte[], int);
-    ctor public ByteArrayWrapper(java.nio.ByteBuffer);
-    method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
-    method public int compareTo(android.icu.util.ByteArrayWrapper);
-    method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
-    method public final byte[] releaseBytes();
-    method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
-    field public byte[] bytes;
-    field public int size;
-  }
-
    abstract class CECalendar extends android.icu.util.Calendar {
     ctor protected CECalendar();
     ctor protected CECalendar(android.icu.util.TimeZone);
@@ -17914,11 +17924,8 @@
     ctor protected CECalendar(int, int, int);
     ctor protected CECalendar(java.util.Date);
     ctor protected CECalendar(int, int, int, int, int, int);
-    method public static int ceToJD(long, int, int, int);
-    method protected abstract int getJDEpochOffset();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetLimit(int, int);
-    method public static void jdToCE(int, int, int[]);
   }
 
   public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
@@ -18146,7 +18153,6 @@
     ctor public CopticCalendar(int, int, int);
     ctor public CopticCalendar(java.util.Date);
     ctor public CopticCalendar(int, int, int, int, int, int);
-    method protected deprecated int getJDEpochOffset();
     method protected deprecated int handleGetExtendedYear();
     field public static final int AMSHIR = 5; // 0x5
     field public static final int BABA = 1; // 0x1
@@ -18317,11 +18323,11 @@
     ctor public IslamicCalendar(java.util.Date);
     ctor public IslamicCalendar(int, int, int);
     ctor public IslamicCalendar(int, int, int, int, int, int);
+    method public android.icu.util.IslamicCalendar.CalculationType getCalculationType();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
-    method public boolean isCivil();
-    method public void setCivil(boolean);
+    method public void setCalculationType(android.icu.util.IslamicCalendar.CalculationType);
     field public static final int DHU_AL_HIJJAH = 11; // 0xb
     field public static final int DHU_AL_QIDAH = 10; // 0xa
     field public static final int JUMADA_1 = 4; // 0x4
@@ -18759,7 +18765,6 @@
     method public int getMicro();
     method public int getMilli();
     method public int getMinor();
-    method public static void main(java.lang.String[]);
     field public static final android.icu.util.VersionInfo ICU_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_BUILDER_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
@@ -19166,180 +19171,121 @@
   }
 
   public final class GnssClock implements android.os.Parcelable {
+    ctor public GnssClock();
     method public int describeContents();
-    method public double getBiasInNs();
-    method public double getBiasUncertaintyInNs();
-    method public double getDriftInNsPerSec();
-    method public double getDriftUncertaintyInNsPerSec();
-    method public long getFullBiasInNs();
+    method public double getBiasNanos();
+    method public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method public double getDriftUncertaintyNanosPerSecond();
+    method public long getFullBiasNanos();
     method public int getHardwareClockDiscontinuityCount();
-    method public short getLeapSecond();
-    method public long getTimeInNs();
-    method public double getTimeUncertaintyInNs();
-    method public byte getType();
-    method public boolean hasBiasInNs();
-    method public boolean hasBiasUncertaintyInNs();
-    method public boolean hasDriftInNsPerSec();
-    method public boolean hasDriftUncertaintyInNsPerSec();
-    method public boolean hasFullBiasInNs();
+    method public int getLeapSecond();
+    method public long getTimeNanos();
+    method public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasFullBiasNanos();
     method public boolean hasLeapSecond();
-    method public boolean hasTimeUncertaintyInNs();
+    method public boolean hasTimeUncertaintyNanos();
     method public void reset();
-    method public void resetBiasInNs();
-    method public void resetBiasUncertaintyInNs();
-    method public void resetDriftInNsPerSec();
-    method public void resetDriftUncertaintyInNsPerSec();
-    method public void resetFullBiasInNs();
+    method public void resetBiasNanos();
+    method public void resetBiasUncertaintyNanos();
+    method public void resetDriftNanosPerSecond();
+    method public void resetDriftUncertaintyNanosPerSecond();
+    method public void resetFullBiasNanos();
     method public void resetLeapSecond();
-    method public void resetTimeUncertaintyInNs();
+    method public void resetTimeUncertaintyNanos();
     method public void set(android.location.GnssClock);
-    method public void setBiasInNs(double);
-    method public void setBiasUncertaintyInNs(double);
-    method public void setDriftInNsPerSec(double);
-    method public void setDriftUncertaintyInNsPerSec(double);
-    method public void setFullBiasInNs(long);
+    method public void setBiasNanos(double);
+    method public void setBiasUncertaintyNanos(double);
+    method public void setDriftNanosPerSecond(double);
+    method public void setDriftUncertaintyNanosPerSecond(double);
+    method public void setFullBiasNanos(long);
     method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(short);
-    method public void setTimeInNs(long);
-    method public void setTimeUncertaintyInNs(double);
-    method public void setType(byte);
+    method public void setLeapSecond(int);
+    method public void setTimeNanos(long);
+    method public void setTimeUncertaintyNanos(double);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
-    field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
-    field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
   }
 
-  public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
-  }
-
   public final class GnssMeasurement implements android.os.Parcelable {
+    ctor public GnssMeasurement();
     method public int describeContents();
-    method public double getAccumulatedDeltaRangeInMeters();
-    method public short getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method public double getAzimuthInDeg();
-    method public double getAzimuthUncertaintyInDeg();
-    method public int getBitNumber();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public long getCarrierCycles();
-    method public float getCarrierFrequencyInHz();
+    method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
     method public double getCarrierPhaseUncertainty();
-    method public double getCn0InDbHz();
-    method public double getCodePhaseInChips();
-    method public double getCodePhaseUncertaintyInChips();
-    method public byte getConstellationType();
-    method public double getDopplerShiftInHz();
-    method public double getDopplerShiftUncertaintyInHz();
-    method public double getElevationInDeg();
-    method public double getElevationUncertaintyInDeg();
-    method public byte getLossOfLock();
-    method public byte getMultipathIndicator();
-    method public double getPseudorangeInMeters();
-    method public double getPseudorangeRateInMetersPerSec();
-    method public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method public double getPseudorangeUncertaintyInMeters();
-    method public long getReceivedSvTimeInNs();
-    method public long getReceivedSvTimeUncertaintyInNs();
+    method public double getCn0DbHz();
+    method public int getConstellationType();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
     method public double getSnrInDb();
-    method public short getState();
-    method public short getSvid();
-    method public short getTimeFromLastBitInMs();
-    method public double getTimeOffsetInNs();
-    method public boolean hasAzimuthInDeg();
-    method public boolean hasAzimuthUncertaintyInDeg();
-    method public boolean hasBitNumber();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
     method public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
     method public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodePhaseInChips();
-    method public boolean hasCodePhaseUncertaintyInChips();
-    method public boolean hasDopplerShiftInHz();
-    method public boolean hasDopplerShiftUncertaintyInHz();
-    method public boolean hasElevationInDeg();
-    method public boolean hasElevationUncertaintyInDeg();
-    method public boolean hasPseudorangeInMeters();
-    method public boolean hasPseudorangeUncertaintyInMeters();
     method public boolean hasSnrInDb();
-    method public boolean hasTimeFromLastBitInMs();
-    method public boolean isPseudorangeRateCorrected();
-    method public boolean isUsedInFix();
     method public void reset();
-    method public void resetAzimuthInDeg();
-    method public void resetAzimuthUncertaintyInDeg();
-    method public void resetBitNumber();
     method public void resetCarrierCycles();
-    method public void resetCarrierFrequencyInHz();
+    method public void resetCarrierFrequencyHz();
     method public void resetCarrierPhase();
     method public void resetCarrierPhaseUncertainty();
-    method public void resetCodePhaseInChips();
-    method public void resetCodePhaseUncertaintyInChips();
-    method public void resetDopplerShiftInHz();
-    method public void resetDopplerShiftUncertaintyInHz();
-    method public void resetElevationInDeg();
-    method public void resetElevationUncertaintyInDeg();
-    method public void resetPseudorangeInMeters();
-    method public void resetPseudorangeUncertaintyInMeters();
     method public void resetSnrInDb();
-    method public void resetTimeFromLastBitInMs();
     method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeInMeters(double);
-    method public void setAccumulatedDeltaRangeState(short);
-    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method public void setAzimuthInDeg(double);
-    method public void setAzimuthUncertaintyInDeg(double);
-    method public void setBitNumber(int);
+    method public void setAccumulatedDeltaRangeMeters(double);
+    method public void setAccumulatedDeltaRangeState(int);
+    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
     method public void setCarrierCycles(long);
-    method public void setCarrierFrequencyInHz(float);
+    method public void setCarrierFrequencyHz(float);
     method public void setCarrierPhase(double);
     method public void setCarrierPhaseUncertainty(double);
-    method public void setCn0InDbHz(double);
-    method public void setCodePhaseInChips(double);
-    method public void setCodePhaseUncertaintyInChips(double);
-    method public void setConstellationType(byte);
-    method public void setDopplerShiftInHz(double);
-    method public void setDopplerShiftUncertaintyInHz(double);
-    method public void setElevationInDeg(double);
-    method public void setElevationUncertaintyInDeg(double);
-    method public void setLossOfLock(byte);
-    method public void setMultipathIndicator(byte);
-    method public void setPseudorangeInMeters(double);
-    method public void setPseudorangeRateInMetersPerSec(double);
-    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method public void setPseudorangeUncertaintyInMeters(double);
-    method public void setReceivedSvTimeInNs(long);
-    method public void setReceivedSvTimeUncertaintyInNs(long);
+    method public void setCn0DbHz(double);
+    method public void setConstellationType(int);
+    method public void setMultipathIndicator(int);
+    method public void setPseudorangeRateMetersPerSecond(double);
+    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+    method public void setReceivedSvTimeNanos(long);
+    method public void setReceivedSvTimeUncertaintyNanos(long);
     method public void setSnrInDb(double);
-    method public void setState(short);
-    method public void setSvid(short);
-    method public void setTimeFromLastBitInMs(short);
-    method public void setTimeOffsetInNs(double);
-    method public void setUsedInFix(boolean);
+    method public void setState(int);
+    method public void setSvid(int);
+    method public void setTimeOffsetNanos(double);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final short ADR_STATE_RESET = 2; // 0x2
-    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final short ADR_STATE_VALID = 1; // 0x1
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final short STATE_BIT_SYNC = 2; // 0x2
-    field public static final short STATE_CODE_LOCK = 1; // 0x1
-    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final short STATE_TOW_DECODED = 8; // 0x8
-    field public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+    field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+    field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+    field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+    field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+    field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public final class GnssMeasurementsEvent implements android.os.Parcelable {
@@ -19349,7 +19295,7 @@
     method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19360,43 +19306,38 @@
     method public void onStatusChanged(int);
   }
 
-  public static abstract class GnssMeasurementsEvent.GnssMeasurementsStatus implements java.lang.annotation.Annotation {
-  }
-
   public final class GnssNavigationMessage implements android.os.Parcelable {
+    ctor public GnssNavigationMessage();
     method public int describeContents();
     method public byte[] getData();
-    method public short getMessageId();
-    method public short getStatus();
-    method public short getSubmessageId();
-    method public short getSvid();
-    method public short getType();
+    method public int getMessageId();
+    method public int getStatus();
+    method public int getSubmessageId();
+    method public int getSvid();
+    method public int getType();
     method public void reset();
     method public void set(android.location.GnssNavigationMessage);
     method public void setData(byte[]);
-    method public void setMessageId(short);
-    method public void setStatus(short);
-    method public void setSubmessageId(short);
-    method public void setSvid(short);
-    method public void setType(short);
+    method public void setMessageId(int);
+    method public void setStatus(int);
+    method public void setSubmessageId(int);
+    method public void setSvid(int);
+    method public void setType(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
-    field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
-    field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
-    field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
-    field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
-    field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
-    field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
-    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final short STATUS_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
   public final class GnssNavigationMessageEvent implements android.os.Parcelable {
@@ -19405,7 +19346,7 @@
     method public android.location.GnssNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19416,33 +19357,27 @@
     method public void onStatusChanged(int);
   }
 
-  public static abstract class GnssNavigationMessageEvent.GnssNavigationMessageStatus implements java.lang.annotation.Annotation {
-  }
-
   public abstract interface GnssNmeaListener {
     method public abstract void onNmeaReceived(long, java.lang.String);
   }
 
   public final class GnssStatus {
-    method public float getAzimuth(int);
-    method public byte getConstellationType(int);
-    method public float getElevation(int);
+    method public float getAzimuthDegrees(int);
+    method public float getCn0DbHz(int);
+    method public int getConstellationType(int);
+    method public float getElevationDegrees(int);
     method public int getNumSatellites();
-    method public float getSnr(int);
     method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
-    field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final byte CONSTELLATION_GPS = 1; // 0x1
-    field public static final byte CONSTELLATION_QZSS = 4; // 0x4
-    field public static final byte CONSTELLATION_SBAS = 2; // 0x2
-    field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
   public abstract class GnssStatusCallback {
@@ -19555,8 +19490,8 @@
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
     method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -19581,7 +19516,7 @@
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
-    method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -19701,6 +19636,7 @@
     field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
     field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
     field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+    field public static final int TYPE_BUS = 21; // 0x15
     field public static final int TYPE_DOCK = 13; // 0xd
     field public static final int TYPE_FM = 14; // 0xe
     field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -19718,12 +19654,14 @@
     field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
   }
 
-  public class AudioFormat {
+  public final class AudioFormat implements android.os.Parcelable {
+    method public int describeContents();
     method public int getChannelCount();
     method public int getChannelIndexMask();
     method public int getChannelMask();
     method public int getEncoding();
     method public int getSampleRate();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
     field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
     field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -19765,6 +19703,7 @@
     field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
     field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
     field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+    field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
     field public static final int ENCODING_AC3 = 5; // 0x5
     field public static final int ENCODING_DEFAULT = 1; // 0x1
     field public static final int ENCODING_DTS = 7; // 0x7
@@ -19775,6 +19714,7 @@
     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
+    field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
   }
 
   public static class AudioFormat.Builder {
@@ -19794,7 +19734,7 @@
     method public void adjustVolume(int, int);
     method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int generateAudioSessionId();
-    method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
+    method public android.media.AudioRecordingConfiguration[] getActiveRecordingConfigurations();
     method public android.media.AudioDeviceInfo[] getDevices(int);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
@@ -19940,7 +19880,7 @@
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged();
+    method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20014,7 +19954,7 @@
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
-  public class AudioRecordConfiguration implements android.os.Parcelable {
+  public final class AudioRecordingConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioDeviceInfo getAudioDevice();
     method public int getClientAudioSessionId();
@@ -20022,12 +19962,13 @@
     method public android.media.AudioFormat getClientFormat();
     method public android.media.AudioFormat getFormat();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
   }
 
   public abstract interface AudioRouting {
     method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public abstract android.media.AudioDeviceInfo getPreferredDevice();
+    method public abstract android.media.AudioDeviceInfo getRoutedDevice();
     method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
   }
@@ -20197,7 +20138,6 @@
   }
 
   public abstract class DrmInitData {
-    ctor public DrmInitData();
     method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
   }
 
@@ -20208,12 +20148,15 @@
 
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+    ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public java.lang.String getAttribute(java.lang.String);
     method public double getAttributeDouble(java.lang.String, double);
     method public int getAttributeInt(java.lang.String, int);
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
+    method public long[] getThumbnailRange();
     method public boolean hasThumbnail();
     method public void saveAttributes() throws java.io.IOException;
     method public void setAttribute(java.lang.String, java.lang.String);
@@ -20226,31 +20169,130 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
-    field public static final java.lang.String TAG_APERTURE = "FNumber";
+    field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
+    field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+    field public static final java.lang.String TAG_ARTIST = "Artist";
+    field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+    field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+    field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+    field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+    field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+    field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+    field public static final java.lang.String TAG_COMPRESSION = "Compression";
+    field public static final java.lang.String TAG_CONTRAST = "Contrast";
+    field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+    field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
     field public static final java.lang.String TAG_DATETIME = "DateTime";
     field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+    field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+    field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+    field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+    field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
+    field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+    field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
+    field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+    field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
     field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+    field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
     field public static final java.lang.String TAG_FLASH = "Flash";
+    field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+    field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
     field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+    field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+    field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+    field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+    field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+    field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+    field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
     field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
     field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+    field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
     field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+    field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+    field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+    field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+    field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+    field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+    field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
     field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
     field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
     field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
     field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+    field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
     field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+    field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+    field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+    field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+    field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
     field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+    field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+    field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+    field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
     field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+    field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
     field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
-    field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
+    field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+    field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
     field public static final java.lang.String TAG_MAKE = "Make";
+    field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+    field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+    field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
     field public static final java.lang.String TAG_MODEL = "Model";
+    field public static final java.lang.String TAG_OECF = "OECF";
     field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+    field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+    field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+    field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+    field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+    field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+    field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+    field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+    field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+    field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+    field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+    field public static final java.lang.String TAG_SATURATION = "Saturation";
+    field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+    field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+    field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+    field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+    field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+    field public static final java.lang.String TAG_SOFTWARE = "Software";
+    field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+    field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+    field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+    field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+    field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+    field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+    field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
     field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
     field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+    field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
     field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+    field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+    field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
     field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+    field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+    field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+    field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+    field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+    field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+    field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
     field public static final int WHITEBALANCE_AUTO = 0; // 0x0
     field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
   }
@@ -20350,8 +20392,8 @@
 
   public class MediaActionSound {
     ctor public MediaActionSound();
-    method public synchronized void load(int);
-    method public synchronized void play(int);
+    method public void load(int);
+    method public void play(int);
     method public void release();
     field public static final int FOCUS_COMPLETE = 1; // 0x1
     field public static final int SHUTTER_CLICK = 0; // 0x0
@@ -20448,6 +20490,7 @@
     field public static final int ERROR_NO_KEY = 1; // 0x1
     field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
     field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
+    field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6
   }
 
   public static final class MediaCodec.CryptoInfo {
@@ -20605,12 +20648,13 @@
     field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
     field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
     field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
-    field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
-    field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
-    field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
-    field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
-    field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
-    field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+    field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+    field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+    field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+    field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+    field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+    field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+    field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
     field public static final int H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -20656,6 +20700,7 @@
     field public static final int HEVCMainTierLevel62 = 16777216; // 0x1000000
     field public static final int HEVCProfileMain = 1; // 0x1
     field public static final int HEVCProfileMain10 = 2; // 0x2
+    field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
     field public static final int MPEG2LevelLL = 0; // 0x0
@@ -20913,6 +20958,7 @@
     method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String) throws java.io.IOException;
+    method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
     method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
     method public void unselectTrack(int);
@@ -20973,6 +21019,7 @@
     field public static final java.lang.String KEY_DURATION = "durationUs";
     field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
     field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
+    field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
     field public static final java.lang.String KEY_HEIGHT = "height";
     field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
     field public static final java.lang.String KEY_IS_ADTS = "is-adts";
@@ -20997,6 +21044,7 @@
     field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
     field public static final java.lang.String KEY_STRIDE = "stride";
     field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+    field public static final java.lang.String KEY_TRACK_ID = "track-id";
     field public static final java.lang.String KEY_WIDTH = "width";
     field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -21196,6 +21244,7 @@
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+    method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22272,7 +22321,7 @@
     method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(java.lang.String);
-    method public void unsubscribe(java.lang.String, android.os.Bundle);
+    method public void unsubscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
     field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
     field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
   }
@@ -22760,6 +22809,10 @@
     method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
     method public static final android.net.Uri buildRecordedProgramUri(long);
+    method public static final boolean isChannelUri(android.net.Uri);
+    method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+    method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+    method public static final boolean isProgramUri(android.net.Uri);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
@@ -22851,7 +22904,8 @@
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
     field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
     field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
@@ -22861,7 +22915,9 @@
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
     field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_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_THUMBNAIL_URI = "thumbnail_uri";
@@ -22904,7 +22960,7 @@
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
     field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
@@ -22919,7 +22975,8 @@
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
     field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_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_THUMBNAIL_URI = "thumbnail_uri";
@@ -22963,7 +23020,7 @@
   }
 
   public static final class TvInputInfo.Builder {
-    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
     method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
     method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -22980,6 +23037,7 @@
     field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
     field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
     field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
+    field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
     field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -23030,11 +23088,13 @@
     ctor public TvInputService.RecordingSession(android.content.Context);
     method public void notifyError(int);
     method public void notifyRecordingStopped(android.net.Uri);
-    method public void notifyTuned();
+    method public void notifyTuned(android.net.Uri);
+    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public abstract void onRelease();
     method public abstract void onStartRecording(android.net.Uri);
     method public abstract void onStopRecording();
     method public abstract void onTune(android.net.Uri);
+    method public void onTune(android.net.Uri, android.os.Bundle);
   }
 
   public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23048,6 +23108,7 @@
     method public void notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>);
     method public void notifyVideoAvailable();
     method public void notifyVideoUnavailable(int);
+    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public android.view.View onCreateOverlayView();
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
     method public boolean onKeyDown(int, android.view.KeyEvent);
@@ -23071,6 +23132,7 @@
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public abstract boolean onTune(android.net.Uri);
+    method public boolean onTune(android.net.Uri, android.os.Bundle);
     method public void onUnblockContent(android.media.tv.TvContentRating);
     method public void setOverlayViewEnabled(boolean);
   }
@@ -23078,9 +23140,11 @@
   public class TvRecordingClient {
     ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
     method public void release();
+    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public void startRecording(android.net.Uri);
     method public void stopRecording();
     method public void tune(java.lang.String, android.net.Uri);
+    method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
   }
 
   public static abstract class TvRecordingClient.RecordingCallback {
@@ -23089,7 +23153,7 @@
     method public void onDisconnected(java.lang.String);
     method public void onError(int);
     method public void onRecordingStopped(android.net.Uri);
-    method public void onTuned();
+    method public void onTuned(android.net.Uri);
   }
 
   public final class TvTrackInfo implements android.os.Parcelable {
@@ -23139,17 +23203,21 @@
     method public boolean onUnhandledInputEvent(android.view.InputEvent);
     method public void reset();
     method public void selectTrack(int, java.lang.String);
+    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public void setCallback(android.media.tv.TvView.TvInputCallback);
     method public void setCaptionEnabled(boolean);
     method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
     method public void setStreamVolume(float);
     method public void setTimeShiftPositionCallback(android.media.tv.TvView.TimeShiftPositionCallback);
+    method public void setZOrderMediaOverlay(boolean);
+    method public void setZOrderOnTop(boolean);
     method public void timeShiftPause();
     method public void timeShiftPlay(java.lang.String, android.net.Uri);
     method public void timeShiftResume();
     method public void timeShiftSeekTo(long);
     method public void timeShiftSetPlaybackParams(android.media.PlaybackParams);
     method public void tune(java.lang.String, android.net.Uri);
+    method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
   }
 
   public static abstract interface TvView.OnUnhandledInputEventListener {
@@ -23448,6 +23516,7 @@
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
+    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.app.PendingIntent);
     method public void releaseNetworkRequest(android.app.PendingIntent);
@@ -23516,7 +23585,7 @@
     method public int getUid();
   }
 
-  public class DataUsageRequest implements android.os.Parcelable {
+  public final class DataUsageRequest implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR;
@@ -26834,7 +26903,8 @@
     method public static void glGetSynciv(long, int, int, int[], int, int[], int);
     method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static deprecated void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static int glGetUniformBlockIndex(int, java.lang.String);
@@ -26860,6 +26930,7 @@
     method public static void glProgramBinary(int, int, java.nio.Buffer, int);
     method public static void glProgramParameteri(int, int, int);
     method public static void glReadBuffer(int);
+    method public static void glReadPixels(int, int, int, int, int, int, int);
     method public static void glRenderbufferStorageMultisample(int, int, int, int, int);
     method public static void glResumeTransformFeedback();
     method public static void glSamplerParameterf(int, int, float);
@@ -28445,6 +28516,10 @@
     ctor public DeadObjectException(java.lang.String);
   }
 
+  public class DeadSystemException extends android.os.DeadObjectException {
+    ctor public DeadSystemException();
+  }
+
   public final class Debug {
     method public static deprecated void changeDebugPort(int);
     method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
@@ -28698,14 +28773,17 @@
 
   public class HardwarePropertiesManager {
     method public android.os.CpuUsageInfo[] getCpuUsages();
-    method public float[] getDeviceTemperatures(int);
+    method public float[] getDeviceTemperatures(int, int);
     method public float[] getFanSpeeds();
     field public static final int DEVICE_TEMPERATURE_BATTERY = 2; // 0x2
     field public static final int DEVICE_TEMPERATURE_CPU = 0; // 0x0
     field public static final int DEVICE_TEMPERATURE_GPU = 1; // 0x1
-  }
-
-  public static abstract class HardwarePropertiesManager.DeviceTemperatureType implements java.lang.annotation.Annotation {
+    field public static final int DEVICE_TEMPERATURE_SKIN = 3; // 0x3
+    field public static final int TEMPERATURE_CURRENT = 0; // 0x0
+    field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
+    field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+    field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
+    field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
   }
 
   public abstract interface IBinder {
@@ -29064,6 +29142,7 @@
     method public boolean isInteractive();
     method public boolean isPowerSaveMode();
     method public deprecated boolean isScreenOn();
+    method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
@@ -29093,7 +29172,10 @@
   public class Process {
     ctor public Process();
     method public static final long getElapsedCpuTime();
+    method public static final int[] getExclusiveCores();
     method public static final int getGidForName(java.lang.String);
+    method public static final long getStartElapsedRealtime();
+    method public static final long getStartUptimeMillis();
     method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
     method public static final int getUidForName(java.lang.String);
     method public static final boolean is64Bit();
@@ -29302,10 +29384,6 @@
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
     method public boolean isUserRunning(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
     method public boolean isUserUnlocked();
     method public boolean isUserUnlocked(android.os.UserHandle);
@@ -29376,6 +29454,147 @@
 
 }
 
+package android.os.health {
+
+  public class HealthStats {
+    method public java.lang.String getDataType();
+    method public long getMeasurement(int);
+    method public int getMeasurementKeyAt(int);
+    method public int getMeasurementKeyCount();
+    method public java.util.Map<java.lang.String, java.lang.Long> getMeasurements(int);
+    method public int getMeasurementsKeyAt(int);
+    method public int getMeasurementsKeyCount();
+    method public java.util.Map<java.lang.String, android.os.health.HealthStats> getStats(int);
+    method public int getStatsKeyAt(int);
+    method public int getStatsKeyCount();
+    method public android.os.health.TimerStat getTimer(int);
+    method public int getTimerCount(int);
+    method public int getTimerKeyAt(int);
+    method public int getTimerKeyCount();
+    method public long getTimerTime(int);
+    method public java.util.Map<java.lang.String, android.os.health.TimerStat> getTimers(int);
+    method public int getTimersKeyAt(int);
+    method public int getTimersKeyCount();
+    method public boolean hasMeasurement(int);
+    method public boolean hasMeasurements(int);
+    method public boolean hasStats(int);
+    method public boolean hasTimer(int);
+    method public boolean hasTimers(int);
+  }
+
+  public final class PackageHealthStats {
+    field public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = 40002; // 0x9c42
+    field public static final int STATS_SERVICES = 40001; // 0x9c41
+  }
+
+  public final class PidHealthStats {
+    field public static final int MEASUREMENT_WAKE_NESTING_COUNT = 20001; // 0x4e21
+    field public static final int MEASUREMENT_WAKE_START_MS = 20003; // 0x4e23
+    field public static final int MEASUREMENT_WAKE_SUM_MS = 20002; // 0x4e22
+  }
+
+  public final class ProcessHealthStats {
+    field public static final int MEASUREMENT_ANR_COUNT = 30005; // 0x7535
+    field public static final int MEASUREMENT_CRASHES_COUNT = 30004; // 0x7534
+    field public static final int MEASUREMENT_FOREGROUND_MS = 30006; // 0x7536
+    field public static final int MEASUREMENT_STARTS_COUNT = 30003; // 0x7533
+    field public static final int MEASUREMENT_SYSTEM_TIME_MS = 30002; // 0x7532
+    field public static final int MEASUREMENT_USER_TIME_MS = 30001; // 0x7531
+  }
+
+  public final class ServiceHealthStats {
+    field public static final int MEASUREMENT_LAUNCH_COUNT = 50002; // 0xc352
+    field public static final int MEASUREMENT_START_SERVICE_COUNT = 50001; // 0xc351
+  }
+
+  public class SystemHealthManager {
+    method public static android.os.health.SystemHealthManager from(android.content.Context);
+    method public android.os.health.HealthStats takeMyUidSnapshot();
+    method public android.os.health.HealthStats takeUidSnapshot(int);
+    method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
+  }
+
+  public final class TimerStat implements android.os.Parcelable {
+    ctor public TimerStat();
+    ctor public TimerStat(int, long);
+    ctor public TimerStat(android.os.Parcel);
+    method public int describeContents();
+    method public int getCount();
+    method public long getTime();
+    method public void setCount(int);
+    method public void setTime(long);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.health.TimerStat> CREATOR;
+  }
+
+  public final class UidHealthStats {
+    field public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = 10020; // 0x2724
+    field public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = 10023; // 0x2727
+    field public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = 10052; // 0x2744
+    field public static final int MEASUREMENT_BLUETOOTH_RX_MS = 10021; // 0x2725
+    field public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = 10058; // 0x274a
+    field public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = 10053; // 0x2745
+    field public static final int MEASUREMENT_BLUETOOTH_TX_MS = 10022; // 0x2726
+    field public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = 10059; // 0x274b
+    field public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = 10046; // 0x273e
+    field public static final int MEASUREMENT_CPU_POWER_MAUS = 10064; // 0x2750
+    field public static final int MEASUREMENT_MOBILE_IDLE_MS = 10024; // 0x2728
+    field public static final int MEASUREMENT_MOBILE_POWER_MAMS = 10027; // 0x272b
+    field public static final int MEASUREMENT_MOBILE_RX_BYTES = 10048; // 0x2740
+    field public static final int MEASUREMENT_MOBILE_RX_MS = 10025; // 0x2729
+    field public static final int MEASUREMENT_MOBILE_RX_PACKETS = 10054; // 0x2746
+    field public static final int MEASUREMENT_MOBILE_TX_BYTES = 10049; // 0x2741
+    field public static final int MEASUREMENT_MOBILE_TX_MS = 10026; // 0x272a
+    field public static final int MEASUREMENT_MOBILE_TX_PACKETS = 10055; // 0x2747
+    field public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = 10045; // 0x273d
+    field public static final int MEASUREMENT_REALTIME_BATTERY_MS = 10001; // 0x2711
+    field public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = 10003; // 0x2713
+    field public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = 10063; // 0x274f
+    field public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = 10047; // 0x273f
+    field public static final int MEASUREMENT_UPTIME_BATTERY_MS = 10002; // 0x2712
+    field public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = 10004; // 0x2714
+    field public static final int MEASUREMENT_USER_CPU_TIME_US = 10062; // 0x274e
+    field public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = 10029; // 0x272d
+    field public static final int MEASUREMENT_WIFI_IDLE_MS = 10016; // 0x2720
+    field public static final int MEASUREMENT_WIFI_MULTICAST_MS = 10031; // 0x272f
+    field public static final int MEASUREMENT_WIFI_POWER_MAMS = 10019; // 0x2723
+    field public static final int MEASUREMENT_WIFI_RUNNING_MS = 10028; // 0x272c
+    field public static final int MEASUREMENT_WIFI_RX_BYTES = 10050; // 0x2742
+    field public static final int MEASUREMENT_WIFI_RX_MS = 10017; // 0x2721
+    field public static final int MEASUREMENT_WIFI_RX_PACKETS = 10056; // 0x2748
+    field public static final int MEASUREMENT_WIFI_TX_BYTES = 10051; // 0x2743
+    field public static final int MEASUREMENT_WIFI_TX_MS = 10018; // 0x2722
+    field public static final int MEASUREMENT_WIFI_TX_PACKETS = 10057; // 0x2749
+    field public static final int STATS_PACKAGES = 10015; // 0x271f
+    field public static final int STATS_PIDS = 10013; // 0x271d
+    field public static final int STATS_PROCESSES = 10014; // 0x271e
+    field public static final int TIMERS_JOBS = 10010; // 0x271a
+    field public static final int TIMERS_SENSORS = 10012; // 0x271c
+    field public static final int TIMERS_SYNCS = 10009; // 0x2719
+    field public static final int TIMERS_WAKELOCKS_DRAW = 10008; // 0x2718
+    field public static final int TIMERS_WAKELOCKS_FULL = 10005; // 0x2715
+    field public static final int TIMERS_WAKELOCKS_PARTIAL = 10006; // 0x2716
+    field public static final int TIMERS_WAKELOCKS_WINDOW = 10007; // 0x2717
+    field public static final int TIMER_AUDIO = 10032; // 0x2730
+    field public static final int TIMER_BLUETOOTH_SCAN = 10037; // 0x2735
+    field public static final int TIMER_CAMERA = 10035; // 0x2733
+    field public static final int TIMER_FLASHLIGHT = 10034; // 0x2732
+    field public static final int TIMER_FOREGROUND_ACTIVITY = 10036; // 0x2734
+    field public static final int TIMER_GPS_SENSOR = 10011; // 0x271b
+    field public static final int TIMER_MOBILE_RADIO_ACTIVE = 10061; // 0x274d
+    field public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = 10042; // 0x273a
+    field public static final int TIMER_PROCESS_STATE_CACHED_MS = 10043; // 0x273b
+    field public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = 10041; // 0x2739
+    field public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = 10039; // 0x2737
+    field public static final int TIMER_PROCESS_STATE_TOP_MS = 10038; // 0x2736
+    field public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = 10040; // 0x2738
+    field public static final int TIMER_VIBRATOR = 10044; // 0x273c
+    field public static final int TIMER_VIDEO = 10033; // 0x2731
+    field public static final int TIMER_WIFI_SCAN = 10030; // 0x272e
+  }
+
+}
+
 package android.os.storage {
 
   public abstract class OnObbStateChangeListener {
@@ -29393,14 +29612,15 @@
 
   public class StorageManager {
     method public java.lang.String getMountedObbPath(java.lang.String);
-    method public android.os.storage.StorageVolume getPrimaryVolume();
-    method public android.os.storage.StorageVolume[] getVolumeList();
+    method public android.os.storage.StorageVolume getPrimaryStorageVolume();
+    method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+    method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
   }
 
-  public class StorageVolume implements android.os.Parcelable {
+  public final class StorageVolume implements android.os.Parcelable {
     method public android.content.Intent createAccessIntent(java.lang.String);
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
@@ -29528,6 +29748,7 @@
     method protected int getPersistedInt(int);
     method protected long getPersistedLong(long);
     method protected java.lang.String getPersistedString(java.lang.String);
+    method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
     method public android.preference.PreferenceManager getPreferenceManager();
     method public android.content.SharedPreferences getSharedPreferences();
     method public boolean getShouldDisableView();
@@ -29549,7 +29770,6 @@
     method protected void onClick();
     method protected android.view.View onCreateView(android.view.ViewGroup);
     method public void onDependencyChanged(android.preference.Preference, boolean);
-    method protected void onDetachedFromActivity();
     method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
     method public void onParentChanged(android.preference.Preference, boolean);
     method protected void onPrepareForRemoval();
@@ -29562,6 +29782,7 @@
     method protected boolean persistInt(int);
     method protected boolean persistLong(long);
     method protected boolean persistString(java.lang.String);
+    method public boolean persistStringSet(java.util.Set<java.lang.String>);
     method public void restoreHierarchyState(android.os.Bundle);
     method public void saveHierarchyState(android.os.Bundle);
     method public void setDefaultValue(java.lang.Object);
@@ -29719,12 +29940,14 @@
     method public android.content.SharedPreferences getSharedPreferences();
     method public int getSharedPreferencesMode();
     method public java.lang.String getSharedPreferencesName();
+    method public boolean isStorageDefault();
+    method public boolean isStorageDeviceProtected();
     method public static void setDefaultValues(android.content.Context, int, boolean);
     method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
     method public void setStorageDefault();
-    method public void setStorageDeviceEncrypted();
+    method public void setStorageDeviceProtected();
     field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
     field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
   }
@@ -30020,7 +30243,7 @@
     method public android.print.PrinterId getPrinterId();
     method public float getProgress();
     method public int getState();
-    method public java.lang.CharSequence getStatus();
+    method public java.lang.CharSequence getStatus(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
@@ -30097,7 +30320,7 @@
     method public android.print.PrinterInfo build();
     method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
     method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
-    method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+    method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon(boolean);
     method public android.print.PrinterInfo.Builder setIconResourceId(int);
     method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
     method public android.print.PrinterInfo.Builder setName(java.lang.String);
@@ -30149,6 +30372,7 @@
     method public boolean isStarted();
     method public void setProgress(float);
     method public void setStatus(java.lang.CharSequence);
+    method public void setStatus(int);
     method public boolean setTag(java.lang.String);
     method public boolean start();
   }
@@ -30179,7 +30403,7 @@
     method public final boolean isDestroyed();
     method public final boolean isPrinterDiscoveryStarted();
     method public abstract void onDestroy();
-    method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+    method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
     method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
     method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
     method public abstract void onStopPrinterDiscovery();
@@ -30225,6 +30449,7 @@
   public class BlockedNumberContract {
     method public static boolean canCurrentUserBlockNumbers(android.content.Context);
     method public static boolean isBlocked(android.content.Context, java.lang.String);
+    method public static int unblock(android.content.Context, java.lang.String);
     field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
     field public static final android.net.Uri AUTHORITY_URI;
   }
@@ -30234,7 +30459,7 @@
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
     field public static final android.net.Uri CONTENT_URI;
   }
 
@@ -30538,6 +30763,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -30560,6 +30786,7 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final java.lang.String FEATURES = "features";
+    field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
@@ -30582,6 +30809,7 @@
     field public static final int REJECTED_TYPE = 5; // 0x5
     field public static final java.lang.String TRANSCRIPTION = "transcription";
     field public static final java.lang.String TYPE = "type";
+    field public static final java.lang.String VIA_NUMBER = "via_number";
     field public static final int VOICEMAIL_TYPE = 4; // 0x4
     field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
   }
@@ -31732,6 +31960,7 @@
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
     field public static final java.lang.String EXTRA_LOADING = "loading";
+    field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
     field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
   }
@@ -31761,6 +31990,7 @@
 
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
     field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
     field public static final java.lang.String COLUMN_FLAGS = "flags";
     field public static final java.lang.String COLUMN_ICON = "icon";
@@ -32177,13 +32407,13 @@
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
+    field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
     field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
     field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
-    field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
     field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
     field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -32202,7 +32432,6 @@
     field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
     field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
     field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
-    field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
     field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
     field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -32215,6 +32444,8 @@
     field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
     field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
     field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+    field public static final java.lang.String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
+    field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
     field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
@@ -32252,6 +32483,7 @@
     field public static final java.lang.String AUTO_TIME = "auto_time";
     field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+    field public static final java.lang.String BOOT_COUNT = "boot_count";
     field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_ROAMING = "data_roaming";
@@ -34092,6 +34324,7 @@
 
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
+    method public void handleTrustStorageUpdate();
     method public boolean isCleartextTrafficPermitted();
     method public boolean isCleartextTrafficPermitted(java.lang.String);
   }
@@ -34125,6 +34358,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34142,6 +34376,7 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
     method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
     method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -34168,6 +34403,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isInsideSecureHardware();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34231,6 +34467,7 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
+    method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
@@ -34242,6 +34479,7 @@
     method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -34280,7 +34518,8 @@
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -34291,6 +34530,9 @@
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+    field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
     field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -34395,7 +34637,6 @@
     method public boolean onMenuOpened(int, android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
     method public boolean onSearchRequested(android.view.SearchEvent);
     method public boolean onSearchRequested();
     method public void onWakeUp();
@@ -34459,8 +34700,9 @@
 package android.service.notification {
 
   public class Condition implements android.os.Parcelable {
-    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int);
+    ctor public Condition(android.net.Uri, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
+    ctor public Condition(android.os.Parcel);
     method public android.service.notification.Condition copy();
     method public int describeContents();
     method public static boolean isValidId(android.net.Uri, java.lang.String);
@@ -34491,6 +34733,7 @@
     method public final void notifyConditions(android.service.notification.Condition...);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract void onConnected();
+    method public void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
@@ -34522,10 +34765,9 @@
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
-    method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
+    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
     method public final void requestUnbind() throws android.os.RemoteException;
     method public final void setNotificationsShown(java.lang.String[]);
-    field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
     field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
     field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -34546,10 +34788,11 @@
     method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
-    field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
-    field public static final int IMPORTANCE_HIGH = 3; // 0x3
-    field public static final int IMPORTANCE_LOW = 1; // 0x1
-    field public static final int IMPORTANCE_MAX = 4; // 0x4
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
     field public static final int IMPORTANCE_NONE = 0; // 0x0
     field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
   }
@@ -34819,6 +35062,18 @@
 
 }
 
+package android.service.vr {
+
+  public abstract class VrListenerService extends android.app.Service {
+    ctor public VrListenerService();
+    method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onCurrentVrActivityChanged(android.content.ComponentName);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+  }
+
+}
+
 package android.service.wallpaper {
 
   public abstract class WallpaperService extends android.app.Service {
@@ -35811,9 +36066,13 @@
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
+    method public final void putExtras(android.os.Bundle);
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public void sendCallEvent(java.lang.String, android.os.Bundle);
     method public void splitFromConference();
     method public void stopDtmfTone();
     method public void swapConference();
@@ -35827,6 +36086,7 @@
     field public static final int STATE_DISCONNECTING = 10; // 0xa
     field public static final int STATE_HOLDING = 3; // 0x3
     field public static final int STATE_NEW = 0; // 0x0
+    field public static final int STATE_PULLING_CALL = 11; // 0xb
     field public static final int STATE_RINGING = 2; // 0x2
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
   }
@@ -35837,6 +36097,7 @@
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -35867,6 +36128,7 @@
     method public static java.lang.String propertiesToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
     field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -35886,6 +36148,7 @@
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
     field public static final int PROPERTY_WIFI = 8; // 0x8
     field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
@@ -35937,6 +36200,7 @@
     method public final android.telecom.CallAudioState getCallAudioState();
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final long getConnectionTime();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -35949,6 +36213,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onConnectionAdded(android.telecom.Connection);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onMerge(android.telecom.Connection);
     method public void onMerge();
@@ -35957,14 +36222,17 @@
     method public void onStopDtmfTone();
     method public void onSwap();
     method public void onUnhold();
+    method public final void putExtras(android.os.Bundle);
     method public final void removeConnection(android.telecom.Connection);
+    method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void setActive();
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setConnectionTime(long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setOnHold();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -35990,6 +36258,7 @@
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public final int getState();
@@ -36000,15 +36269,23 @@
     method public void onAnswer(int);
     method public void onAnswer();
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+    method public void onCallEvent(java.lang.String, android.os.Bundle);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onPlayDtmfTone(char);
     method public void onPostDialContinue(boolean);
+    method public void onPullExternalCall();
     method public void onReject();
+    method public void onReject(java.lang.String);
     method public void onSeparate();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
+    method public static java.lang.String propertiesToString(int);
+    method public final void putExtras(android.os.Bundle);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
@@ -36016,9 +36293,10 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setNextPostDialChar(char);
@@ -36032,6 +36310,8 @@
     method public static java.lang.String stateToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
+    field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -36048,15 +36328,18 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
     field public static final int STATE_HOLDING = 5; // 0x5
     field public static final int STATE_INITIALIZING = 0; // 0x0
     field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_PULLING_CALL = 7; // 0x7
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
@@ -36111,6 +36394,7 @@
     method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
     method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public final java.util.Collection<android.telecom.Conference> getAllConferences();
     method public final java.util.Collection<android.telecom.Connection> getAllConnections();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
@@ -36133,7 +36417,9 @@
     method public java.lang.String getReason();
     method public int getTone();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
     field public static final int BUSY = 7; // 0x7
+    field public static final int CALL_PULLED = 12; // 0xc
     field public static final int CANCELED = 4; // 0x4
     field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
     field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR;
@@ -36169,6 +36455,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onSilenceRinger();
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
@@ -36268,6 +36555,7 @@
     method public void disconnect();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final java.util.List<android.telecom.RemoteConnection> getConnections();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
@@ -36290,6 +36578,7 @@
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
     method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onDestroyed(android.telecom.RemoteConference);
     method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36308,6 +36597,7 @@
     method public android.telecom.RemoteConference getConference();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public int getConnectionCapabilities();
+    method public int getConnectionProperties();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public int getState();
@@ -36319,6 +36609,7 @@
     method public boolean isVoipAudioMode();
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
     method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
@@ -36335,6 +36626,8 @@
     method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
     method public void onDestroyed(android.telecom.RemoteConnection);
     method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
     method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -36387,6 +36680,7 @@
   public class TelecomManager {
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void cancelMissedCallsNotification();
+    method public android.content.Intent createManageBlockedNumbersIntent();
     method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
     method public java.lang.String getDefaultDialerPackage();
@@ -36399,7 +36693,6 @@
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public void launchManageBlockedNumbersActivity();
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
@@ -36431,6 +36724,7 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+    field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -36479,15 +36773,16 @@
 package android.telephony {
 
   public class CarrierConfigManager {
+    method public android.os.PersistableBundle getConfig(int);
     method public android.os.PersistableBundle getConfig();
-    method public android.os.PersistableBundle getConfigForSubId(int);
-    method public void notifyConfigChangedForSubId(int);
+    method public deprecated android.os.PersistableBundle getConfigForSubId(int);
+    method public void notifyConfigChanged(int);
+    method public deprecated void notifyConfigChangedForSubId(int);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
-    field public static final java.lang.String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS = "bool_allow_emergency_video_calls";
-    field public static final java.lang.String BOOL_ALLOW_VIDEO_PAUSE = "bool_allow_video_pause";
     field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
     field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
     field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
+    field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
     field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
     field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
@@ -36509,6 +36804,7 @@
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
     field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+    field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -36570,6 +36866,7 @@
     field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+    field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
@@ -37084,7 +37381,8 @@
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
     method public java.lang.String getGroupIdLevel1(int);
-    method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+    method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+    method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
     method public java.lang.String getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
     method public java.lang.String getLine1Number(int);
@@ -37119,12 +37417,18 @@
     method public int getVoiceNetworkType(int);
     method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
     method public boolean hasCarrierPrivileges();
+    method public boolean hasCarrierPrivileges(int);
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
+    method public boolean iccCloseLogicalChannel(int, int);
     method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+    method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+    method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
     method public boolean isNetworkRoaming(int);
@@ -37135,15 +37439,25 @@
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
+    method public boolean setOperatorBrandOverride(int, java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
+    method public boolean setPreferredNetworkTypeToGlobal(int);
     method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
     method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
     field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+    field public static final int APPTYPE_CSIM = 4; // 0x4
+    field public static final int APPTYPE_ISIM = 5; // 0x5
+    field public static final int APPTYPE_RUIM = 3; // 0x3
+    field public static final int APPTYPE_SIM = 1; // 0x1
+    field public static final int APPTYPE_USIM = 2; // 0x2
+    field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+    field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -37645,7 +37959,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createDeviceEncryptedStorageContext();
+    method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -37687,8 +38001,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -37697,9 +38009,9 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isDeviceEncryptedStorage();
-    method public boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+    method public boolean isDeviceProtectedStorage();
+    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -38505,7 +38817,6 @@
     method public boolean hasNext();
     method public java.util.Iterator<java.lang.String> iterator();
     method public java.lang.String next();
-    method public void remove();
     method public void setString(java.lang.String);
   }
 
@@ -39523,8 +39834,10 @@
     method public static final boolean addLinks(android.widget.TextView, int);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
     field public static final int ALL = 15; // 0xf
     field public static final int EMAIL_ADDRESSES = 2; // 0x2
     field public static final int MAP_ADDRESSES = 8; // 0x8
@@ -40117,6 +40430,7 @@
     method public int describeContents();
     method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getAdjustedDefault();
     method public static android.util.LocaleList getDefault();
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -41411,9 +41725,11 @@
   }
 
   public final class KeyboardShortcutInfo implements android.os.Parcelable {
+    ctor public KeyboardShortcutInfo(java.lang.CharSequence, int, int);
     ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
     method public int describeContents();
     method public char getBaseCharacter();
+    method public int getKeycode();
     method public java.lang.CharSequence getLabel();
     method public int getModifiers();
     method public void writeToParcel(android.os.Parcel, int);
@@ -42041,6 +42357,7 @@
     method public boolean dispatchDragEvent(android.view.DragEvent);
     method protected void dispatchDraw(android.graphics.Canvas);
     method public void dispatchDrawableHotspotChanged(float, float);
+    method public void dispatchFinishTemporaryDetach();
     method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -42060,6 +42377,7 @@
     method protected void dispatchSetActivated(boolean);
     method protected void dispatchSetPressed(boolean);
     method protected void dispatchSetSelected(boolean);
+    method public void dispatchStartTemporaryDetach();
     method public void dispatchSystemUiVisibilityChanged(int);
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -42077,6 +42395,7 @@
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
+    method public void forceHasOverlappingRendering(boolean);
     method public void forceLayout();
     method public static int generateViewId();
     method public java.lang.CharSequence getAccessibilityClassName();
@@ -42122,6 +42441,7 @@
     method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
     method public final boolean getGlobalVisibleRect(android.graphics.Rect);
     method public android.os.Handler getHandler();
+    method public final boolean getHasOverlappingRendering();
     method public final int getHeight();
     method public void getHitRect(android.graphics.Rect);
     method public int getHorizontalFadingEdgeLength();
@@ -42270,6 +42590,7 @@
     method public boolean isSelected();
     method public boolean isShown();
     method public boolean isSoundEffectsEnabled();
+    method public final boolean isTemporarilyDetached();
     method public boolean isTextAlignmentResolved();
     method public boolean isTextDirectionResolved();
     method public boolean isVerticalFadingEdgeEnabled();
@@ -42327,6 +42648,7 @@
     method public void onStartTemporaryDetach();
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
+    method public void onVisibilityAggregated(boolean);
     method protected void onVisibilityChanged(android.view.View, int);
     method public void onWindowFocusChanged(boolean);
     method public void onWindowSystemUiVisibilityChanged(int);
@@ -43423,7 +43745,7 @@
     method public abstract boolean onMenuOpened(int, android.view.Menu);
     method public abstract void onPanelClosed(int, android.view.Menu);
     method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+    method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
     method public abstract boolean onSearchRequested();
     method public abstract boolean onSearchRequested(android.view.SearchEvent);
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -43853,8 +44175,6 @@
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
     field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
@@ -44025,6 +44345,7 @@
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
     method public int getChildCount();
@@ -44032,6 +44353,7 @@
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+    method public java.lang.CharSequence getTitle();
     method public int getType();
     method public boolean isAccessibilityFocused();
     method public boolean isActive();
@@ -44044,6 +44366,7 @@
     field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
     field public static final int TYPE_APPLICATION = 1; // 0x1
     field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
     field public static final int TYPE_SYSTEM = 3; // 0x3
   }
 
@@ -44371,6 +44694,7 @@
     ctor public BaseInputConnection(android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -44538,6 +44862,7 @@
   public abstract interface InputConnection {
     method public abstract boolean beginBatchEdit();
     method public abstract boolean clearMetaKeyStates(int);
+    method public abstract void closeConnection();
     method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -44570,6 +44895,7 @@
     ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -46019,7 +46345,7 @@
     method public long getMinDate();
     method public deprecated android.graphics.drawable.Drawable getSelectedDateVerticalBar();
     method public deprecated int getSelectedWeekBackgroundColor();
-    method public boolean getShowWeekNumber();
+    method public deprecated boolean getShowWeekNumber();
     method public deprecated int getShownWeekCount();
     method public deprecated int getUnfocusedMonthDateColor();
     method public int getWeekDayTextAppearance();
@@ -46036,7 +46362,7 @@
     method public deprecated void setSelectedDateVerticalBar(int);
     method public deprecated void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
     method public deprecated void setSelectedWeekBackgroundColor(int);
-    method public void setShowWeekNumber(boolean);
+    method public deprecated void setShowWeekNumber(boolean);
     method public deprecated void setShownWeekCount(int);
     method public deprecated void setUnfocusedMonthDateColor(int);
     method public void setWeekDayTextAppearance(int);
@@ -46086,7 +46412,9 @@
     method public long getBase();
     method public java.lang.String getFormat();
     method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener();
+    method public boolean isCountDown();
     method public void setBase(long);
+    method public void setCountDown(boolean);
     method public void setFormat(java.lang.String);
     method public void setOnChronometerTickListener(android.widget.Chronometer.OnChronometerTickListener);
     method public void start();
@@ -46934,6 +47262,8 @@
     method public android.graphics.drawable.Drawable getBackground();
     method public android.view.View getContentView();
     method public float getElevation();
+    method public android.transition.Transition getEnterTransition();
+    method public android.transition.Transition getExitTransition();
     method public int getHeight();
     method public int getInputMethodMode();
     method public int getMaxAvailableHeight(android.view.View);
@@ -47178,6 +47508,7 @@
     method public void setChar(int, java.lang.String, char);
     method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
     method public void setChronometer(int, long, java.lang.String, boolean);
+    method public void setChronometerCountsDown(int, boolean);
     method public void setContentDescription(int, java.lang.CharSequence);
     method public void setDisplayedChild(int, int);
     method public void setDouble(int, java.lang.String, double);
@@ -48012,14 +48343,21 @@
     method public void collapseActionView();
     method public void dismissPopupMenus();
     method public int getContentInsetEnd();
+    method public int getContentInsetEndWithActions();
     method public int getContentInsetLeft();
     method public int getContentInsetRight();
     method public int getContentInsetStart();
+    method public int getContentInsetStartWithNavigation();
+    method public int getCurrentContentInsetEnd();
+    method public int getCurrentContentInsetLeft();
+    method public int getCurrentContentInsetRight();
+    method public int getCurrentContentInsetStart();
     method public android.graphics.drawable.Drawable getLogo();
     method public java.lang.CharSequence getLogoDescription();
     method public android.view.Menu getMenu();
     method public java.lang.CharSequence getNavigationContentDescription();
     method public android.graphics.drawable.Drawable getNavigationIcon();
+    method public android.view.View getNavigationView();
     method public android.graphics.drawable.Drawable getOverflowIcon();
     method public int getPopupTheme();
     method public java.lang.CharSequence getSubtitle();
@@ -48033,6 +48371,8 @@
     method public void inflateMenu(int);
     method public boolean isOverflowMenuShowing();
     method protected void onLayout(boolean, int, int, int, int);
+    method public void setContentInsetEndWithActions(int);
+    method public void setContentInsetStartWithNavigation(int);
     method public void setContentInsetsAbsolute(int, int);
     method public void setContentInsetsRelative(int, int);
     method public void setLogo(int);
@@ -49017,9 +49357,7 @@
 
   public final class FilePermission extends java.security.Permission implements java.io.Serializable {
     ctor public FilePermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -49758,6 +50096,7 @@
     method public static int compare(boolean, boolean);
     method public int compareTo(java.lang.Boolean);
     method public static boolean getBoolean(java.lang.String);
+    method public static int hashCode(boolean);
     method public static boolean parseBoolean(java.lang.String);
     method public static java.lang.String toString(boolean);
     method public static java.lang.Boolean valueOf(boolean);
@@ -49775,6 +50114,7 @@
     method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(byte);
     method public int intValue();
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -49783,6 +50123,7 @@
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+    field public static final int BYTES = 1; // 0x1
     field public static final byte MAX_VALUE = 127; // 0x7f
     field public static final byte MIN_VALUE = -128; // 0xffffff80
     field public static final int SIZE = 8; // 0x8
@@ -49820,6 +50161,7 @@
     method public static int getNumericValue(int);
     method public static int getType(char);
     method public static int getType(int);
+    method public static int hashCode(char);
     method public static char highSurrogate(int);
     method public static boolean isAlphabetic(int);
     method public static boolean isBmpCodePoint(int);
@@ -49880,6 +50222,7 @@
     method public static char toUpperCase(char);
     method public static int toUpperCase(int);
     method public static java.lang.Character valueOf(char);
+    field public static final int BYTES = 2; // 0x2
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
     field public static final byte CONTROL = 15; // 0xf
@@ -50424,18 +50767,24 @@
     method public static long doubleToRawLongBits(double);
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(double);
     method public int intValue();
+    method public static boolean isFinite(double);
     method public static boolean isInfinite(double);
     method public boolean isInfinite();
     method public static boolean isNaN(double);
     method public boolean isNaN();
     method public static double longBitsToDouble(long);
     method public long longValue();
+    method public static double max(double, double);
+    method public static double min(double, double);
     method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+    method public static double sum(double, double);
     method public static java.lang.String toHexString(double);
     method public static java.lang.String toString(double);
     method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Double valueOf(double);
+    field public static final int BYTES = 8; // 0x8
     field public static final int MAX_EXPONENT = 1023; // 0x3ff
     field public static final double MAX_VALUE = 1.7976931348623157E308;
     field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -50500,18 +50849,24 @@
     method public static int floatToIntBits(float);
     method public static int floatToRawIntBits(float);
     method public float floatValue();
+    method public static int hashCode(float);
     method public static float intBitsToFloat(int);
     method public int intValue();
+    method public static boolean isFinite(float);
     method public static boolean isInfinite(float);
     method public boolean isInfinite();
     method public static boolean isNaN(float);
     method public boolean isNaN();
     method public long longValue();
+    method public static float max(float, float);
+    method public static float min(float, float);
     method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+    method public static float sum(float, float);
     method public static java.lang.String toHexString(float);
     method public static java.lang.String toString(float);
     method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Float valueOf(float);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_EXPONENT = 127; // 0x7f
     field public static final float MAX_VALUE = 3.4028235E38f;
     field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -50598,10 +50953,13 @@
     method public static java.lang.Integer getInteger(java.lang.String);
     method public static java.lang.Integer getInteger(java.lang.String, int);
     method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+    method public static int hashCode(int);
     method public static int highestOneBit(int);
     method public int intValue();
     method public long longValue();
     method public static int lowestOneBit(int);
+    method public static int max(int, int);
+    method public static int min(int, int);
     method public static int numberOfLeadingZeros(int);
     method public static int numberOfTrailingZeros(int);
     method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50611,6 +50969,7 @@
     method public static int rotateLeft(int, int);
     method public static int rotateRight(int, int);
     method public static int signum(int);
+    method public static int sum(int, int);
     method public static java.lang.String toBinaryString(int);
     method public static java.lang.String toHexString(int);
     method public static java.lang.String toOctalString(int);
@@ -50619,6 +50978,7 @@
     method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(int);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
     field public static final int MIN_VALUE = -2147483648; // 0x80000000
     field public static final int SIZE = 32; // 0x20
@@ -50638,7 +50998,9 @@
   }
 
   public abstract interface Iterable {
+    method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
+    method public default java.util.Spliterator<T> spliterator();
   }
 
   public class LinkageError extends java.lang.Error {
@@ -50659,10 +51021,13 @@
     method public static java.lang.Long getLong(java.lang.String);
     method public static java.lang.Long getLong(java.lang.String, long);
     method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+    method public static int hashCode(long);
     method public static long highestOneBit(long);
     method public int intValue();
     method public long longValue();
     method public static long lowestOneBit(long);
+    method public static long max(long, long);
+    method public static long min(long, long);
     method public static int numberOfLeadingZeros(long);
     method public static int numberOfTrailingZeros(long);
     method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50672,6 +51037,7 @@
     method public static long rotateLeft(long, int);
     method public static long rotateRight(long, int);
     method public static int signum(long);
+    method public static long sum(long, long);
     method public static java.lang.String toBinaryString(long);
     method public static java.lang.String toHexString(long);
     method public static java.lang.String toOctalString(long);
@@ -50680,6 +51046,7 @@
     method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(long);
+    field public static final int BYTES = 8; // 0x8
     field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
     field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
     field public static final int SIZE = 64; // 0x40
@@ -50859,41 +51226,11 @@
     method public java.io.File directory();
     method public java.lang.ProcessBuilder directory(java.io.File);
     method public java.util.Map<java.lang.String, java.lang.String> environment();
-    method public java.lang.ProcessBuilder inheritIO();
-    method public java.lang.ProcessBuilder redirectError(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectError(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectError();
     method public boolean redirectErrorStream();
     method public java.lang.ProcessBuilder redirectErrorStream(boolean);
-    method public java.lang.ProcessBuilder redirectInput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectInput(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectInput();
-    method public java.lang.ProcessBuilder redirectOutput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectOutput(java.io.File);
-    method public java.lang.ProcessBuilder.Redirect redirectOutput();
     method public java.lang.Process start() throws java.io.IOException;
   }
 
-  public static abstract class ProcessBuilder.Redirect {
-    method public static java.lang.ProcessBuilder.Redirect appendTo(java.io.File);
-    method public java.io.File file();
-    method public static java.lang.ProcessBuilder.Redirect from(java.io.File);
-    method public static java.lang.ProcessBuilder.Redirect to(java.io.File);
-    method public abstract java.lang.ProcessBuilder.Redirect.Type type();
-    field public static final java.lang.ProcessBuilder.Redirect INHERIT;
-    field public static final java.lang.ProcessBuilder.Redirect PIPE;
-  }
-
-  public static final class ProcessBuilder.Redirect.Type extends java.lang.Enum {
-    method public static java.lang.ProcessBuilder.Redirect.Type valueOf(java.lang.String);
-    method public static final java.lang.ProcessBuilder.Redirect.Type[] values();
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type APPEND;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type INHERIT;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type PIPE;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type READ;
-    enum_constant public static final java.lang.ProcessBuilder.Redirect.Type WRITE;
-  }
-
   public abstract interface Readable {
     method public abstract int read(java.nio.CharBuffer) throws java.io.IOException;
   }
@@ -51013,6 +51350,7 @@
     method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(short);
     method public int intValue();
     method public long longValue();
     method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51022,6 +51360,7 @@
     method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(short);
+    field public static final int BYTES = 2; // 0x2
     field public static final short MAX_VALUE = 32767; // 0x7fff
     field public static final short MIN_VALUE = -32768; // 0xffff8000
     field public static final int SIZE = 16; // 0x10
@@ -52545,9 +52884,7 @@
 
   public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
     ctor public SocketPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53629,9 +53966,7 @@
   public final class AllPermission extends java.security.Permission {
     ctor public AllPermission();
     ctor public AllPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53645,9 +53980,7 @@
   public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
     ctor public BasicPermission(java.lang.String);
     ctor public BasicPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54025,10 +54358,8 @@
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
-    method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getActions();
     method public final java.lang.String getName();
-    method public abstract int hashCode();
     method public abstract boolean implies(java.security.Permission);
     method public java.security.PermissionCollection newPermissionCollection();
   }
@@ -54113,6 +54444,7 @@
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
@@ -54285,13 +54617,11 @@
 
   public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
     ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getUnresolvedActions();
     method public java.security.cert.Certificate[] getUnresolvedCerts();
     method public java.lang.String getUnresolvedName();
     method public java.lang.String getUnresolvedType();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54349,8 +54679,6 @@
   }
 
   public abstract interface Permission {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.lang.String toString();
   }
 
 }
@@ -57054,6 +57382,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
@@ -57062,8 +57391,13 @@
     ctor public ArrayList(java.util.Collection<? extends E>);
     method public java.lang.Object clone();
     method public void ensureCapacity(int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
+    method public boolean removeIf(java.util.function.Predicate<? super E>);
+    method public void replaceAll(java.util.function.UnaryOperator<E>);
     method public int size();
+    method public void sort(java.util.Comparator<? super E>);
+    method public java.util.Spliterator<E> spliterator();
     method public void trimToSize();
   }
 
@@ -57146,6 +57480,32 @@
     method public static int hashCode(float[]);
     method public static int hashCode(double[]);
     method public static int hashCode(java.lang.Object[]);
+    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
+    method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
+    method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
+    method public static void parallelSort(byte[]);
+    method public static void parallelSort(byte[], int, int);
+    method public static void parallelSort(char[]);
+    method public static void parallelSort(char[], int, int);
+    method public static void parallelSort(short[]);
+    method public static void parallelSort(short[], int, int);
+    method public static void parallelSort(int[]);
+    method public static void parallelSort(int[], int, int);
+    method public static void parallelSort(long[]);
+    method public static void parallelSort(long[], int, int);
+    method public static void parallelSort(float[]);
+    method public static void parallelSort(float[], int, int);
+    method public static void parallelSort(double[]);
+    method public static void parallelSort(double[], int, int);
+    method public static void parallelSort(T[]);
+    method public static void parallelSort(T[], int, int);
+    method public static void parallelSort(T[], java.util.Comparator<? super T>);
+    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static void setAll(int[], java.util.function.IntUnaryOperator);
+    method public static void setAll(long[], java.util.function.IntToLongFunction);
+    method public static void setAll(double[], java.util.function.IntToDoubleFunction);
     method public static void sort(int[]);
     method public static void sort(int[], int, int);
     method public static void sort(long[]);
@@ -57164,6 +57524,22 @@
     method public static void sort(java.lang.Object[], int, int);
     method public static void sort(T[], java.util.Comparator<? super T>);
     method public static void sort(T[], int, int, java.util.Comparator<? super T>);
+    method public static java.util.Spliterator<T> spliterator(T[]);
+    method public static java.util.Spliterator<T> spliterator(T[], int, int);
+    method public static java.util.Spliterator.OfInt spliterator(int[]);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
+    method public static java.util.Spliterator.OfLong spliterator(long[]);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[]);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
+    method public static java.util.stream.Stream<T> stream(T[]);
+    method public static java.util.stream.Stream<T> stream(T[], int, int);
+    method public static java.util.stream.IntStream stream(int[]);
+    method public static java.util.stream.IntStream stream(int[], int, int);
+    method public static java.util.stream.LongStream stream(long[]);
+    method public static java.util.stream.LongStream stream(long[], int, int);
+    method public static java.util.stream.DoubleStream stream(double[]);
+    method public static java.util.stream.DoubleStream stream(double[], int, int);
     method public static java.lang.String toString(long[]);
     method public static java.lang.String toString(int[]);
     method public static java.lang.String toString(short[]);
@@ -57323,10 +57699,13 @@
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
     method public abstract java.util.Iterator<E> iterator();
+    method public default java.util.stream.Stream<E> parallelStream();
     method public abstract boolean remove(java.lang.Object);
     method public abstract boolean removeAll(java.util.Collection<?>);
+    method public default boolean removeIf(java.util.function.Predicate<? super E>);
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
+    method public default java.util.stream.Stream<E> stream();
     method public abstract java.lang.Object[] toArray();
     method public abstract T[] toArray(T[]);
   }
@@ -57394,7 +57773,23 @@
 
   public abstract interface Comparator {
     method public abstract int compare(T, T);
+    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
     method public abstract boolean equals(java.lang.Object);
+    method public static java.util.Comparator<T> naturalOrder();
+    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
+    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
+    method public static java.util.Comparator<T> reverseOrder();
+    method public default java.util.Comparator<T> reversed();
+    method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
+    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
+    method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
+    method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
   }
 
   public class ConcurrentModificationException extends java.lang.RuntimeException {
@@ -57491,6 +57886,17 @@
     method public abstract int size();
   }
 
+  public class DoubleSummaryStatistics implements java.util.function.DoubleConsumer {
+    ctor public DoubleSummaryStatistics();
+    method public void accept(double);
+    method public void combine(java.util.DoubleSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final double getMax();
+    method public final double getMin();
+    method public final double getSum();
+  }
+
   public class DuplicateFormatFlagsException extends java.util.IllegalFormatException {
     ctor public DuplicateFormatFlagsException(java.lang.String);
     method public java.lang.String getFlags();
@@ -57625,6 +58031,8 @@
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public boolean replace(K, V, V);
   }
 
   public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -57635,6 +58043,7 @@
     method public java.lang.Object clone();
     method public java.util.Iterator<E> iterator();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
@@ -57644,19 +58053,29 @@
     ctor public Hashtable(java.util.Map<? extends K, ? extends V>);
     method public synchronized void clear();
     method public synchronized java.lang.Object clone();
+    method public synchronized V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public synchronized V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public synchronized V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public synchronized boolean contains(java.lang.Object);
     method public synchronized boolean containsKey(java.lang.Object);
     method public boolean containsValue(java.lang.Object);
     method public synchronized java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public synchronized V get(java.lang.Object);
+    method public synchronized V getOrDefault(java.lang.Object, V);
     method public synchronized boolean isEmpty();
     method public java.util.Set<K> keySet();
     method public synchronized java.util.Enumeration<K> keys();
+    method public synchronized V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public synchronized V put(K, V);
     method public synchronized void putAll(java.util.Map<? extends K, ? extends V>);
+    method public synchronized V putIfAbsent(K, V);
     method protected void rehash();
     method public synchronized V remove(java.lang.Object);
+    method public synchronized boolean remove(java.lang.Object, java.lang.Object);
+    method public synchronized boolean replace(K, V, V);
+    method public synchronized V replace(K, V);
     method public synchronized int size();
     method public java.util.Collection<V> values();
   }
@@ -57667,6 +58086,7 @@
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -57710,15 +58130,27 @@
     ctor public InputMismatchException(java.lang.String);
   }
 
+  public class IntSummaryStatistics implements java.util.function.IntConsumer {
+    ctor public IntSummaryStatistics();
+    method public void accept(int);
+    method public void combine(java.util.IntSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final int getMax();
+    method public final int getMin();
+    method public final long getSum();
+  }
+
   public class InvalidPropertiesFormatException extends java.io.IOException {
     ctor public InvalidPropertiesFormatException(java.lang.Throwable);
     ctor public InvalidPropertiesFormatException(java.lang.String);
   }
 
   public abstract interface Iterator {
+    method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
-    method public abstract void remove();
+    method public default void remove();
   }
 
   public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -57765,6 +58197,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public abstract interface List implements java.util.Collection {
@@ -57787,9 +58220,11 @@
     method public abstract boolean remove(java.lang.Object);
     method public abstract E remove(int);
     method public abstract boolean removeAll(java.util.Collection<?>);
+    method public default void replaceAll(java.util.function.UnaryOperator<E>);
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract E set(int, E);
     method public abstract int size();
+    method public default void sort(java.util.Comparator<? super E>);
     method public abstract java.util.List<E> subList(int, int);
     method public abstract java.lang.Object[] toArray();
     method public abstract T[] toArray(T[]);
@@ -57900,24 +58335,51 @@
     enum_constant public static final java.util.Locale.Category FORMAT;
   }
 
+  public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
+    ctor public LongSummaryStatistics();
+    method public void accept(int);
+    method public void accept(long);
+    method public void combine(java.util.LongSummaryStatistics);
+    method public final double getAverage();
+    method public final long getCount();
+    method public final long getMax();
+    method public final long getMin();
+    method public final long getSum();
+  }
+
   public abstract interface Map {
     method public abstract void clear();
+    method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public default V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public abstract boolean containsKey(java.lang.Object);
     method public abstract boolean containsValue(java.lang.Object);
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract boolean equals(java.lang.Object);
+    method public default void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public abstract V get(java.lang.Object);
+    method public default V getOrDefault(java.lang.Object, V);
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
     method public abstract java.util.Set<K> keySet();
+    method public default V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public abstract V put(K, V);
     method public abstract void putAll(java.util.Map<? extends K, ? extends V>);
+    method public default V putIfAbsent(K, V);
     method public abstract V remove(java.lang.Object);
+    method public default boolean remove(java.lang.Object, java.lang.Object);
+    method public default boolean replace(K, V, V);
+    method public default V replace(K, V);
+    method public default void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public abstract int size();
     method public abstract java.util.Collection<V> values();
   }
 
   public static abstract interface Map.Entry {
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
+    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
     method public abstract boolean equals(java.lang.Object);
     method public abstract K getKey();
     method public abstract V getValue();
@@ -58020,9 +58482,83 @@
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
+  public final class Optional {
+    method public static java.util.Optional<T> empty();
+    method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public T get();
+    method public void ifPresent(java.util.function.Consumer<? super T>);
+    method public boolean isPresent();
+    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Optional<T> of(T);
+    method public static java.util.Optional<T> ofNullable(T);
+    method public T orElse(T);
+    method public T orElseGet(java.util.function.Supplier<? extends T>);
+    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalDouble {
+    method public static java.util.OptionalDouble empty();
+    method public double getAsDouble();
+    method public void ifPresent(java.util.function.DoubleConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalDouble of(double);
+    method public double orElse(double);
+    method public double orElseGet(java.util.function.DoubleSupplier);
+    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalInt {
+    method public static java.util.OptionalInt empty();
+    method public int getAsInt();
+    method public void ifPresent(java.util.function.IntConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalInt of(int);
+    method public int orElse(int);
+    method public int orElseGet(java.util.function.IntSupplier);
+    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalLong {
+    method public static java.util.OptionalLong empty();
+    method public long getAsLong();
+    method public void ifPresent(java.util.function.LongConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalLong of(long);
+    method public long orElse(long);
+    method public long orElseGet(java.util.function.LongSupplier);
+    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public abstract interface PrimitiveIterator implements java.util.Iterator {
+    method public abstract void forEachRemaining(T_CONS);
+  }
+
+  public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public default java.lang.Double next();
+    method public abstract double nextDouble();
+  }
+
+  public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public default java.lang.Integer next();
+    method public abstract int nextInt();
+  }
+
+  public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public default java.lang.Long next();
+    method public abstract long nextLong();
+  }
+
   public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
+    ctor public PriorityQueue(java.util.Comparator<? super E>);
     ctor public PriorityQueue(int, java.util.Comparator<? super E>);
     ctor public PriorityQueue(java.util.Collection<? extends E>);
     ctor public PriorityQueue(java.util.PriorityQueue<? extends E>);
@@ -58033,6 +58569,7 @@
     method public E peek();
     method public E poll();
     method public int size();
+    method public final java.util.Spliterator<E> spliterator();
   }
 
   public class Properties extends java.util.Hashtable {
@@ -58191,7 +58728,6 @@
     method public short nextShort();
     method public short nextShort(int);
     method public int radix();
-    method public void remove();
     method public java.util.Scanner reset();
     method public java.util.Scanner skip(java.util.regex.Pattern);
     method public java.util.Scanner skip(java.lang.String);
@@ -58276,6 +58812,139 @@
     method public abstract java.util.SortedSet<E> tailSet(E);
   }
 
+  public abstract interface Spliterator {
+    method public abstract int characteristics();
+    method public abstract long estimateSize();
+    method public default void forEachRemaining(java.util.function.Consumer<? super T>);
+    method public default java.util.Comparator<? super T> getComparator();
+    method public default long getExactSizeIfKnown();
+    method public default boolean hasCharacteristics(int);
+    method public abstract boolean tryAdvance(java.util.function.Consumer<? super T>);
+    method public abstract java.util.Spliterator<T> trySplit();
+    field public static final int CONCURRENT = 4096; // 0x1000
+    field public static final int DISTINCT = 1; // 0x1
+    field public static final int IMMUTABLE = 1024; // 0x400
+    field public static final int NONNULL = 256; // 0x100
+    field public static final int ORDERED = 16; // 0x10
+    field public static final int SIZED = 64; // 0x40
+    field public static final int SORTED = 4; // 0x4
+    field public static final int SUBSIZED = 16384; // 0x4000
+  }
+
+  public static abstract interface Spliterator.OfDouble implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public abstract boolean tryAdvance(java.util.function.DoubleConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Double>);
+    method public abstract java.util.Spliterator.OfDouble trySplit();
+  }
+
+  public static abstract interface Spliterator.OfInt implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public abstract boolean tryAdvance(java.util.function.IntConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Integer>);
+    method public abstract java.util.Spliterator.OfInt trySplit();
+  }
+
+  public static abstract interface Spliterator.OfLong implements java.util.Spliterator.OfPrimitive {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public abstract boolean tryAdvance(java.util.function.LongConsumer);
+    method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Long>);
+    method public abstract java.util.Spliterator.OfLong trySplit();
+  }
+
+  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
+    method public default void forEachRemaining(T_CONS);
+    method public abstract boolean tryAdvance(T_CONS);
+    method public abstract T_SPLITR trySplit();
+  }
+
+  public final class Spliterators {
+    method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
+    method public static java.util.Spliterator.OfInt emptyIntSpliterator();
+    method public static java.util.Spliterator.OfLong emptyLongSpliterator();
+    method public static java.util.Spliterator<T> emptySpliterator();
+    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
+    method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
+    method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
+    method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
+    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
+    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int);
+    method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int);
+    method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int);
+    method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
+    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
+    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
+    method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
+    method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
+    method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
+    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
+    method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
+    method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
+    method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
+  }
+
+  public static abstract class Spliterators.AbstractDoubleSpliterator implements java.util.Spliterator.OfDouble {
+    ctor protected Spliterators.AbstractDoubleSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfDouble trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractIntSpliterator implements java.util.Spliterator.OfInt {
+    ctor protected Spliterators.AbstractIntSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfInt trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractLongSpliterator implements java.util.Spliterator.OfLong {
+    ctor protected Spliterators.AbstractLongSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator.OfLong trySplit();
+  }
+
+  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
+    ctor protected Spliterators.AbstractSpliterator(long, int);
+    method public int characteristics();
+    method public long estimateSize();
+    method public java.util.Spliterator<T> trySplit();
+  }
+
+  public final class SplittableRandom {
+    ctor public SplittableRandom(long);
+    ctor public SplittableRandom();
+    method public java.util.stream.DoubleStream doubles(long);
+    method public java.util.stream.DoubleStream doubles();
+    method public java.util.stream.DoubleStream doubles(long, double, double);
+    method public java.util.stream.DoubleStream doubles(double, double);
+    method public java.util.stream.IntStream ints(long);
+    method public java.util.stream.IntStream ints();
+    method public java.util.stream.IntStream ints(long, int, int);
+    method public java.util.stream.IntStream ints(int, int);
+    method public java.util.stream.LongStream longs(long);
+    method public java.util.stream.LongStream longs();
+    method public java.util.stream.LongStream longs(long, long, long);
+    method public java.util.stream.LongStream longs(long, long);
+    method public boolean nextBoolean();
+    method public double nextDouble();
+    method public double nextDouble(double);
+    method public double nextDouble(double, double);
+    method public int nextInt();
+    method public int nextInt(int);
+    method public int nextInt(int, int);
+    method public long nextLong();
+    method public long nextLong(long);
+    method public long nextLong(long, long);
+    method public java.util.SplittableRandom split();
+  }
+
   public class Stack extends java.util.Vector {
     ctor public Stack();
     method public boolean empty();
@@ -58285,6 +58954,15 @@
     method public synchronized int search(java.lang.Object);
   }
 
+  public final class StringJoiner {
+    ctor public StringJoiner(java.lang.CharSequence);
+    ctor public StringJoiner(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
+    method public java.util.StringJoiner add(java.lang.CharSequence);
+    method public int length();
+    method public java.util.StringJoiner merge(java.util.StringJoiner);
+    method public java.util.StringJoiner setEmptyValue(java.lang.CharSequence);
+  }
+
   public class StringTokenizer implements java.util.Enumeration {
     ctor public StringTokenizer(java.lang.String, java.lang.String, boolean);
     ctor public StringTokenizer(java.lang.String, java.lang.String);
@@ -58367,6 +59045,7 @@
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public java.util.NavigableMap<K, V> headMap(K, boolean);
     method public java.util.SortedMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -58405,6 +59084,7 @@
     method public E pollFirst();
     method public E pollLast();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
     method public java.util.SortedSet<E> subSet(E, E);
     method public java.util.NavigableSet<E> tailSet(E, boolean);
@@ -58449,6 +59129,7 @@
     method public java.util.Enumeration<E> elements();
     method public synchronized void ensureCapacity(int);
     method public synchronized E firstElement();
+    method public synchronized void forEach(java.util.function.Consumer<? super E>);
     method public synchronized E get(int);
     method public synchronized int indexOf(java.lang.Object, int);
     method public synchronized void insertElementAt(E, int);
@@ -58457,9 +59138,13 @@
     method public synchronized void removeAllElements();
     method public synchronized boolean removeElement(java.lang.Object);
     method public synchronized void removeElementAt(int);
+    method public synchronized boolean removeIf(java.util.function.Predicate<? super E>);
+    method public synchronized void replaceAll(java.util.function.UnaryOperator<E>);
     method public synchronized void setElementAt(E, int);
     method public synchronized void setSize(int);
     method public synchronized int size();
+    method public synchronized void sort(java.util.Comparator<? super E>);
+    method public java.util.Spliterator<E> spliterator();
     method public synchronized void trimToSize();
     field protected int capacityIncrement;
     field protected int elementCount;
@@ -58472,6 +59157,7 @@
     ctor public WeakHashMap();
     ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
 }
@@ -58506,6 +59192,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -58569,6 +59256,78 @@
     ctor public CancellationException(java.lang.String);
   }
 
+  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
+    ctor public CompletableFuture();
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
+    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public boolean cancel(boolean);
+    method public boolean complete(T);
+    method public boolean completeExceptionally(java.lang.Throwable);
+    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
+    method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
+    method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public T getNow(T);
+    method public int getNumberOfDependents();
+    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public boolean isCancelled();
+    method public boolean isCompletedExceptionally();
+    method public boolean isDone();
+    method public T join();
+    method public void obtrudeException(java.lang.Throwable);
+    method public void obtrudeValue(T);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
+    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<T> toCompletableFuture();
+    method public java.util.concurrent.CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+  }
+
+  public static abstract interface CompletableFuture.AsynchronousCompletionTask {
+  }
+
+  public class CompletionException extends java.lang.RuntimeException {
+    ctor protected CompletionException();
+    ctor protected CompletionException(java.lang.String);
+    ctor public CompletionException(java.lang.String, java.lang.Throwable);
+    ctor public CompletionException(java.lang.Throwable);
+  }
+
   public abstract interface CompletionService {
     method public abstract java.util.concurrent.Future<V> poll();
     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
@@ -58577,20 +59336,130 @@
     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
+  public abstract interface CompletionStage {
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
+    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
+    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public abstract java.util.concurrent.CompletableFuture<T> toCompletableFuture();
+    method public abstract java.util.concurrent.CompletionStage<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
+    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+  }
+
   public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
     ctor public ConcurrentHashMap();
     ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
     ctor public ConcurrentHashMap(int, float);
     ctor public ConcurrentHashMap(int, float, int);
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public boolean contains(java.lang.Object);
     method public java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
+    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
+    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachKey(long, java.util.function.Consumer<? super K>);
+    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
+    method public void forEachValue(long, java.util.function.Consumer<? super V>);
+    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public V getOrDefault(java.lang.Object, V);
+    method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
     method public java.util.Enumeration<K> keys();
+    method public long mappingCount();
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
+    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
     method public V putIfAbsent(K, V);
+    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
+    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
+    method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
+    method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
+    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
+    method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
+    method public double reduceToDouble(long, java.util.function.ToDoubleBiFunction<? super K, ? super V>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
+    method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
+    method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
+    method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
+    method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
     method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
     method public V replace(K, V);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
+    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
+    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
+    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
+  }
+
+   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
+    method public final void clear();
+    method public abstract boolean contains(java.lang.Object);
+    method public final boolean containsAll(java.util.Collection<?>);
+    method public java.util.concurrent.ConcurrentHashMap<K, V> getMap();
+    method public final boolean isEmpty();
+    method public abstract java.util.Iterator<E> iterator();
+    method public abstract boolean remove(java.lang.Object);
+    method public final boolean removeAll(java.util.Collection<?>);
+    method public final boolean retainAll(java.util.Collection<?>);
+    method public final int size();
+    method public final java.lang.Object[] toArray();
+    method public final T[] toArray(T[]);
+    method public final java.lang.String toString();
+  }
+
+  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
+    method public boolean add(K);
+    method public boolean addAll(java.util.Collection<? extends K>);
+    method public boolean contains(java.lang.Object);
+    method public void forEach(java.util.function.Consumer<? super K>);
+    method public V getMappedValue();
+    method public java.util.Iterator<K> iterator();
+    method public boolean remove(java.lang.Object);
+    method public java.util.Spliterator<K> spliterator();
   }
 
   public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
@@ -58620,6 +59489,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
@@ -58630,6 +59500,7 @@
     method public E peek();
     method public E poll();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public abstract interface ConcurrentMap implements java.util.Map {
@@ -58661,6 +59532,9 @@
     method public K ceilingKey(K);
     method public java.util.concurrent.ConcurrentSkipListMap<K, V> clone();
     method public java.util.Comparator<? super K> comparator();
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableSet<K> descendingKeySet();
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
@@ -58668,6 +59542,8 @@
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public V getOrDefault(java.lang.Object, V);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -58676,6 +59552,7 @@
     method public K lastKey();
     method public java.util.Map.Entry<K, V> lowerEntry(K);
     method public K lowerKey(K);
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
@@ -58683,6 +59560,7 @@
     method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
     method public V replace(K, V);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, K);
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K, boolean);
@@ -58710,6 +59588,7 @@
     method public E pollFirst();
     method public E pollLast();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
     method public java.util.NavigableSet<E> subSet(E, E);
     method public java.util.NavigableSet<E> tailSet(E, boolean);
@@ -58730,6 +59609,7 @@
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
     method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
@@ -58753,8 +59633,11 @@
   public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
     ctor public CopyOnWriteArraySet();
     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
+    method public boolean removeIf(java.util.function.Predicate<? super E>);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
   }
 
   public class CountDownLatch {
@@ -58765,6 +59648,32 @@
     method public long getCount();
   }
 
+  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
+    ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
+    ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
+    ctor protected CountedCompleter();
+    method public final void addToPendingCount(int);
+    method public final boolean compareAndSetPendingCount(int, int);
+    method public void complete(T);
+    method public abstract void compute();
+    method public final int decrementPendingCountUnlessZero();
+    method protected final boolean exec();
+    method public final java.util.concurrent.CountedCompleter<?> firstComplete();
+    method public final java.util.concurrent.CountedCompleter<?> getCompleter();
+    method public final int getPendingCount();
+    method public T getRawResult();
+    method public final java.util.concurrent.CountedCompleter<?> getRoot();
+    method public final void helpComplete(int);
+    method public final java.util.concurrent.CountedCompleter<?> nextComplete();
+    method public void onCompletion(java.util.concurrent.CountedCompleter<?>);
+    method public boolean onExceptionalCompletion(java.lang.Throwable, java.util.concurrent.CountedCompleter<?>);
+    method public final void propagateCompletion();
+    method public final void quietlyCompleteRoot();
+    method public final void setPendingCount(int);
+    method protected void setRawResult(T);
+    method public final void tryComplete();
+  }
+
   public class CyclicBarrier {
     ctor public CyclicBarrier(int, java.lang.Runnable);
     ctor public CyclicBarrier(int);
@@ -58855,6 +59764,8 @@
     method public static java.util.concurrent.ExecutorService newSingleThreadExecutor(java.util.concurrent.ThreadFactory);
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor();
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
+    method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
+    method public static java.util.concurrent.ExecutorService newWorkStealingPool();
     method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
@@ -58868,11 +59779,13 @@
     ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
     method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public static java.util.concurrent.ForkJoinPool commonPool();
     method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>);
     method public void execute(java.util.concurrent.ForkJoinTask<?>);
     method public void execute(java.lang.Runnable);
     method public int getActiveThreadCount();
     method public boolean getAsyncMode();
+    method public static int getCommonPoolParallelism();
     method public java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory getFactory();
     method public int getParallelism();
     method public int getPoolSize();
@@ -58910,6 +59823,7 @@
     method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
     method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
     method public boolean cancel(boolean);
+    method public final boolean compareAndSetForkJoinTaskTag(short, short);
     method public void complete(V);
     method public void completeExceptionally(java.lang.Throwable);
     method protected abstract boolean exec();
@@ -58917,6 +59831,7 @@
     method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public final java.lang.Throwable getException();
+    method public final short getForkJoinTaskTag();
     method public static java.util.concurrent.ForkJoinPool getPool();
     method public static int getQueuedTaskCount();
     method public abstract V getRawResult();
@@ -58935,9 +59850,11 @@
     method protected static java.util.concurrent.ForkJoinTask<?> peekNextLocalTask();
     method protected static java.util.concurrent.ForkJoinTask<?> pollNextLocalTask();
     method protected static java.util.concurrent.ForkJoinTask<?> pollTask();
+    method public final void quietlyComplete();
     method public final void quietlyInvoke();
     method public final void quietlyJoin();
     method public void reinitialize();
+    method public final short setForkJoinTaskTag(short);
     method protected abstract void setRawResult(V);
     method public boolean tryUnfork();
   }
@@ -59011,6 +59928,7 @@
     method public E removeLast();
     method public boolean removeLastOccurrence(java.lang.Object);
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
     method public E takeFirst() throws java.lang.InterruptedException;
     method public E takeLast() throws java.lang.InterruptedException;
@@ -59031,6 +59949,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -59050,6 +59969,7 @@
     method public void put(E);
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
     method public void transfer(E) throws java.lang.InterruptedException;
     method public boolean tryTransfer(E);
@@ -59097,6 +60017,7 @@
     method public void put(E);
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -59200,6 +60121,7 @@
     method public void put(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public int size();
+    method public java.util.Spliterator<E> spliterator();
     method public E take() throws java.lang.InterruptedException;
   }
 
@@ -59209,6 +60131,18 @@
 
   public class ThreadLocalRandom extends java.util.Random {
     method public static java.util.concurrent.ThreadLocalRandom current();
+    method public java.util.stream.DoubleStream doubles(long);
+    method public java.util.stream.DoubleStream doubles();
+    method public java.util.stream.DoubleStream doubles(long, double, double);
+    method public java.util.stream.DoubleStream doubles(double, double);
+    method public java.util.stream.IntStream ints(long);
+    method public java.util.stream.IntStream ints();
+    method public java.util.stream.IntStream ints(long, int, int);
+    method public java.util.stream.IntStream ints(int, int);
+    method public java.util.stream.LongStream longs(long);
+    method public java.util.stream.LongStream longs();
+    method public java.util.stream.LongStream longs(long, long, long);
+    method public java.util.stream.LongStream longs(long, long);
     method public double nextDouble(double);
     method public double nextDouble(double, double);
     method public int nextInt(int, int);
@@ -59329,112 +60263,136 @@
   public class AtomicInteger extends java.lang.Number implements java.io.Serializable {
     ctor public AtomicInteger(int);
     ctor public AtomicInteger();
+    method public final int accumulateAndGet(int, java.util.function.IntBinaryOperator);
     method public final int addAndGet(int);
     method public final boolean compareAndSet(int, int);
     method public final int decrementAndGet();
     method public double doubleValue();
     method public float floatValue();
     method public final int get();
+    method public final int getAndAccumulate(int, java.util.function.IntBinaryOperator);
     method public final int getAndAdd(int);
     method public final int getAndDecrement();
     method public final int getAndIncrement();
     method public final int getAndSet(int);
+    method public final int getAndUpdate(java.util.function.IntUnaryOperator);
     method public final int incrementAndGet();
     method public int intValue();
     method public final void lazySet(int);
     method public long longValue();
     method public final void set(int);
+    method public final int updateAndGet(java.util.function.IntUnaryOperator);
     method public final boolean weakCompareAndSet(int, int);
   }
 
   public class AtomicIntegerArray implements java.io.Serializable {
     ctor public AtomicIntegerArray(int);
     ctor public AtomicIntegerArray(int[]);
+    method public final int accumulateAndGet(int, int, java.util.function.IntBinaryOperator);
     method public final int addAndGet(int, int);
     method public final boolean compareAndSet(int, int, int);
     method public final int decrementAndGet(int);
     method public final int get(int);
+    method public final int getAndAccumulate(int, int, java.util.function.IntBinaryOperator);
     method public final int getAndAdd(int, int);
     method public final int getAndDecrement(int);
     method public final int getAndIncrement(int);
     method public final int getAndSet(int, int);
+    method public final int getAndUpdate(int, java.util.function.IntUnaryOperator);
     method public final int incrementAndGet(int);
     method public final void lazySet(int, int);
     method public final int length();
     method public final void set(int, int);
+    method public final int updateAndGet(int, java.util.function.IntUnaryOperator);
     method public final boolean weakCompareAndSet(int, int, int);
   }
 
   public abstract class AtomicIntegerFieldUpdater {
     ctor protected AtomicIntegerFieldUpdater();
+    method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
     method public int addAndGet(T, int);
     method public abstract boolean compareAndSet(T, int, int);
     method public int decrementAndGet(T);
     method public abstract int get(T);
+    method public final int getAndAccumulate(T, int, java.util.function.IntBinaryOperator);
     method public int getAndAdd(T, int);
     method public int getAndDecrement(T);
     method public int getAndIncrement(T);
     method public int getAndSet(T, int);
+    method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
     method public int incrementAndGet(T);
     method public abstract void lazySet(T, int);
     method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, int);
+    method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, int, int);
   }
 
   public class AtomicLong extends java.lang.Number implements java.io.Serializable {
     ctor public AtomicLong(long);
     ctor public AtomicLong();
+    method public final long accumulateAndGet(long, java.util.function.LongBinaryOperator);
     method public final long addAndGet(long);
     method public final boolean compareAndSet(long, long);
     method public final long decrementAndGet();
     method public double doubleValue();
     method public float floatValue();
     method public final long get();
+    method public final long getAndAccumulate(long, java.util.function.LongBinaryOperator);
     method public final long getAndAdd(long);
     method public final long getAndDecrement();
     method public final long getAndIncrement();
     method public final long getAndSet(long);
+    method public final long getAndUpdate(java.util.function.LongUnaryOperator);
     method public final long incrementAndGet();
     method public int intValue();
     method public final void lazySet(long);
     method public long longValue();
     method public final void set(long);
+    method public final long updateAndGet(java.util.function.LongUnaryOperator);
     method public final boolean weakCompareAndSet(long, long);
   }
 
   public class AtomicLongArray implements java.io.Serializable {
     ctor public AtomicLongArray(int);
     ctor public AtomicLongArray(long[]);
+    method public final long accumulateAndGet(int, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(int, long);
     method public final boolean compareAndSet(int, long, long);
     method public final long decrementAndGet(int);
     method public final long get(int);
+    method public final long getAndAccumulate(int, long, java.util.function.LongBinaryOperator);
     method public final long getAndAdd(int, long);
     method public final long getAndDecrement(int);
     method public final long getAndIncrement(int);
     method public final long getAndSet(int, long);
+    method public final long getAndUpdate(int, java.util.function.LongUnaryOperator);
     method public final long incrementAndGet(int);
     method public final void lazySet(int, long);
     method public final int length();
     method public final void set(int, long);
+    method public final long updateAndGet(int, java.util.function.LongUnaryOperator);
     method public final boolean weakCompareAndSet(int, long, long);
   }
 
   public abstract class AtomicLongFieldUpdater {
     ctor protected AtomicLongFieldUpdater();
+    method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(T, long);
     method public abstract boolean compareAndSet(T, long, long);
     method public long decrementAndGet(T);
     method public abstract long get(T);
+    method public final long getAndAccumulate(T, long, java.util.function.LongBinaryOperator);
     method public long getAndAdd(T, long);
     method public long getAndDecrement(T);
     method public long getAndIncrement(T);
     method public long getAndSet(T, long);
+    method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
     method public long incrementAndGet(T);
     method public abstract void lazySet(T, long);
     method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, long);
+    method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, long, long);
   }
 
@@ -59452,34 +60410,46 @@
   public class AtomicReference implements java.io.Serializable {
     ctor public AtomicReference(V);
     ctor public AtomicReference();
+    method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
     method public final boolean compareAndSet(V, V);
     method public final V get();
+    method public final V getAndAccumulate(V, java.util.function.BinaryOperator<V>);
     method public final V getAndSet(V);
+    method public final V getAndUpdate(java.util.function.UnaryOperator<V>);
     method public final void lazySet(V);
     method public final void set(V);
+    method public final V updateAndGet(java.util.function.UnaryOperator<V>);
     method public final boolean weakCompareAndSet(V, V);
   }
 
   public class AtomicReferenceArray implements java.io.Serializable {
     ctor public AtomicReferenceArray(int);
     ctor public AtomicReferenceArray(E[]);
+    method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
     method public final boolean compareAndSet(int, E, E);
     method public final E get(int);
+    method public final E getAndAccumulate(int, E, java.util.function.BinaryOperator<E>);
     method public final E getAndSet(int, E);
+    method public final E getAndUpdate(int, java.util.function.UnaryOperator<E>);
     method public final void lazySet(int, E);
     method public final int length();
     method public final void set(int, E);
+    method public final E updateAndGet(int, java.util.function.UnaryOperator<E>);
     method public final boolean weakCompareAndSet(int, E, E);
   }
 
   public abstract class AtomicReferenceFieldUpdater {
     ctor protected AtomicReferenceFieldUpdater();
+    method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
     method public abstract boolean compareAndSet(T, V, V);
     method public abstract V get(T);
+    method public final V getAndAccumulate(T, V, java.util.function.BinaryOperator<V>);
     method public V getAndSet(T, V);
+    method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
     method public abstract void lazySet(T, V);
     method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
     method public abstract void set(T, V);
+    method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
     method public abstract boolean weakCompareAndSet(T, V, V);
   }
 
@@ -59494,6 +60464,59 @@
     method public boolean weakCompareAndSet(V, V, int, int);
   }
 
+  public class DoubleAccumulator extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public DoubleAccumulator(java.util.function.DoubleBinaryOperator, double);
+    method public void accumulate(double);
+    method public double doubleValue();
+    method public float floatValue();
+    method public double get();
+    method public double getThenReset();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+  }
+
+  public class DoubleAdder extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public DoubleAdder();
+    method public void add(double);
+    method public double doubleValue();
+    method public float floatValue();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+    method public double sum();
+    method public double sumThenReset();
+  }
+
+  public class LongAccumulator extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public LongAccumulator(java.util.function.LongBinaryOperator, long);
+    method public void accumulate(long);
+    method public double doubleValue();
+    method public float floatValue();
+    method public long get();
+    method public long getThenReset();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+  }
+
+  public class LongAdder extends java.util.concurrent.atomic.Striped64 implements java.io.Serializable {
+    ctor public LongAdder();
+    method public void add(long);
+    method public void decrement();
+    method public double doubleValue();
+    method public float floatValue();
+    method public void increment();
+    method public int intValue();
+    method public long longValue();
+    method public void reset();
+    method public long sum();
+    method public long sumThenReset();
+  }
+
+   abstract class Striped64 extends java.lang.Number {
+  }
+
 }
 
 package java.util.concurrent.locks {
@@ -59701,6 +60724,34 @@
     method public void unlock();
   }
 
+  public class StampedLock implements java.io.Serializable {
+    ctor public StampedLock();
+    method public java.util.concurrent.locks.Lock asReadLock();
+    method public java.util.concurrent.locks.ReadWriteLock asReadWriteLock();
+    method public java.util.concurrent.locks.Lock asWriteLock();
+    method public int getReadLockCount();
+    method public boolean isReadLocked();
+    method public boolean isWriteLocked();
+    method public long readLock();
+    method public long readLockInterruptibly() throws java.lang.InterruptedException;
+    method public long tryConvertToOptimisticRead(long);
+    method public long tryConvertToReadLock(long);
+    method public long tryConvertToWriteLock(long);
+    method public long tryOptimisticRead();
+    method public long tryReadLock();
+    method public long tryReadLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public boolean tryUnlockRead();
+    method public boolean tryUnlockWrite();
+    method public long tryWriteLock();
+    method public long tryWriteLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public void unlock(long);
+    method public void unlockRead(long);
+    method public void unlockWrite(long);
+    method public boolean validate(long);
+    method public long writeLock();
+    method public long writeLockInterruptibly() throws java.lang.InterruptedException;
+  }
+
 }
 
 package java.util.function {
@@ -60493,6 +61544,292 @@
 
 }
 
+package java.util.stream {
+
+  public abstract interface BaseStream implements java.lang.AutoCloseable {
+    method public abstract void close();
+    method public abstract boolean isParallel();
+    method public abstract java.util.Iterator<T> iterator();
+    method public abstract S onClose(java.lang.Runnable);
+    method public abstract S parallel();
+    method public abstract S sequential();
+    method public abstract java.util.Spliterator<T> spliterator();
+    method public abstract S unordered();
+  }
+
+  public abstract interface Collector {
+    method public abstract java.util.function.BiConsumer<A, T> accumulator();
+    method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
+    method public abstract java.util.function.BinaryOperator<A> combiner();
+    method public abstract java.util.function.Function<A, R> finisher();
+    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
+    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
+    method public abstract java.util.function.Supplier<A> supplier();
+  }
+
+  public static final class Collector.Characteristics extends java.lang.Enum {
+    method public static java.util.stream.Collector.Characteristics valueOf(java.lang.String);
+    method public static final java.util.stream.Collector.Characteristics[] values();
+    enum_constant public static final java.util.stream.Collector.Characteristics CONCURRENT;
+    enum_constant public static final java.util.stream.Collector.Characteristics IDENTITY_FINISH;
+    enum_constant public static final java.util.stream.Collector.Characteristics UNORDERED;
+  }
+
+  public final class Collectors {
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
+    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
+    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
+    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
+    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
+    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
+    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
+  }
+
+  public abstract interface DoubleStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.DoublePredicate);
+    method public abstract boolean anyMatch(java.util.function.DoublePredicate);
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Double> boxed();
+    method public static java.util.stream.DoubleStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
+    method public abstract long count();
+    method public abstract java.util.stream.DoubleStream distinct();
+    method public static java.util.stream.DoubleStream empty();
+    method public abstract java.util.stream.DoubleStream filter(java.util.function.DoublePredicate);
+    method public abstract java.util.OptionalDouble findAny();
+    method public abstract java.util.OptionalDouble findFirst();
+    method public abstract java.util.stream.DoubleStream flatMap(java.util.function.DoubleFunction<? extends java.util.stream.DoubleStream>);
+    method public abstract void forEach(java.util.function.DoubleConsumer);
+    method public abstract void forEachOrdered(java.util.function.DoubleConsumer);
+    method public static java.util.stream.DoubleStream generate(java.util.function.DoubleSupplier);
+    method public static java.util.stream.DoubleStream iterate(double, java.util.function.DoubleUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfDouble iterator();
+    method public abstract java.util.stream.DoubleStream limit(long);
+    method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
+    method public abstract java.util.OptionalDouble max();
+    method public abstract java.util.OptionalDouble min();
+    method public abstract boolean noneMatch(java.util.function.DoublePredicate);
+    method public static java.util.stream.DoubleStream of(double);
+    method public static java.util.stream.DoubleStream of(double...);
+    method public abstract java.util.stream.DoubleStream parallel();
+    method public abstract java.util.stream.DoubleStream peek(java.util.function.DoubleConsumer);
+    method public abstract double reduce(double, java.util.function.DoubleBinaryOperator);
+    method public abstract java.util.OptionalDouble reduce(java.util.function.DoubleBinaryOperator);
+    method public abstract java.util.stream.DoubleStream sequential();
+    method public abstract java.util.stream.DoubleStream skip(long);
+    method public abstract java.util.stream.DoubleStream sorted();
+    method public abstract java.util.Spliterator.OfDouble spliterator();
+    method public abstract double sum();
+    method public abstract java.util.DoubleSummaryStatistics summaryStatistics();
+    method public abstract double[] toArray();
+  }
+
+  public static abstract interface DoubleStream.Builder implements java.util.function.DoubleConsumer {
+    method public abstract void accept(double);
+    method public default java.util.stream.DoubleStream.Builder add(double);
+    method public abstract java.util.stream.DoubleStream build();
+  }
+
+  public abstract interface IntStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.IntPredicate);
+    method public abstract boolean anyMatch(java.util.function.IntPredicate);
+    method public abstract java.util.stream.DoubleStream asDoubleStream();
+    method public abstract java.util.stream.LongStream asLongStream();
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
+    method public static java.util.stream.IntStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
+    method public abstract long count();
+    method public abstract java.util.stream.IntStream distinct();
+    method public static java.util.stream.IntStream empty();
+    method public abstract java.util.stream.IntStream filter(java.util.function.IntPredicate);
+    method public abstract java.util.OptionalInt findAny();
+    method public abstract java.util.OptionalInt findFirst();
+    method public abstract java.util.stream.IntStream flatMap(java.util.function.IntFunction<? extends java.util.stream.IntStream>);
+    method public abstract void forEach(java.util.function.IntConsumer);
+    method public abstract void forEachOrdered(java.util.function.IntConsumer);
+    method public static java.util.stream.IntStream generate(java.util.function.IntSupplier);
+    method public static java.util.stream.IntStream iterate(int, java.util.function.IntUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfInt iterator();
+    method public abstract java.util.stream.IntStream limit(long);
+    method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
+    method public abstract java.util.OptionalInt max();
+    method public abstract java.util.OptionalInt min();
+    method public abstract boolean noneMatch(java.util.function.IntPredicate);
+    method public static java.util.stream.IntStream of(int);
+    method public static java.util.stream.IntStream of(int...);
+    method public abstract java.util.stream.IntStream parallel();
+    method public abstract java.util.stream.IntStream peek(java.util.function.IntConsumer);
+    method public static java.util.stream.IntStream range(int, int);
+    method public static java.util.stream.IntStream rangeClosed(int, int);
+    method public abstract int reduce(int, java.util.function.IntBinaryOperator);
+    method public abstract java.util.OptionalInt reduce(java.util.function.IntBinaryOperator);
+    method public abstract java.util.stream.IntStream sequential();
+    method public abstract java.util.stream.IntStream skip(long);
+    method public abstract java.util.stream.IntStream sorted();
+    method public abstract java.util.Spliterator.OfInt spliterator();
+    method public abstract int sum();
+    method public abstract java.util.IntSummaryStatistics summaryStatistics();
+    method public abstract int[] toArray();
+  }
+
+  public static abstract interface IntStream.Builder implements java.util.function.IntConsumer {
+    method public abstract void accept(int);
+    method public default java.util.stream.IntStream.Builder add(int);
+    method public abstract java.util.stream.IntStream build();
+  }
+
+  public abstract interface LongStream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.LongPredicate);
+    method public abstract boolean anyMatch(java.util.function.LongPredicate);
+    method public abstract java.util.stream.DoubleStream asDoubleStream();
+    method public abstract java.util.OptionalDouble average();
+    method public abstract java.util.stream.Stream<java.lang.Long> boxed();
+    method public static java.util.stream.LongStream.Builder builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
+    method public abstract long count();
+    method public abstract java.util.stream.LongStream distinct();
+    method public static java.util.stream.LongStream empty();
+    method public abstract java.util.stream.LongStream filter(java.util.function.LongPredicate);
+    method public abstract java.util.OptionalLong findAny();
+    method public abstract java.util.OptionalLong findFirst();
+    method public abstract java.util.stream.LongStream flatMap(java.util.function.LongFunction<? extends java.util.stream.LongStream>);
+    method public abstract void forEach(java.util.function.LongConsumer);
+    method public abstract void forEachOrdered(java.util.function.LongConsumer);
+    method public static java.util.stream.LongStream generate(java.util.function.LongSupplier);
+    method public static java.util.stream.LongStream iterate(long, java.util.function.LongUnaryOperator);
+    method public abstract java.util.PrimitiveIterator.OfLong iterator();
+    method public abstract java.util.stream.LongStream limit(long);
+    method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
+    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
+    method public abstract java.util.OptionalLong max();
+    method public abstract java.util.OptionalLong min();
+    method public abstract boolean noneMatch(java.util.function.LongPredicate);
+    method public static java.util.stream.LongStream of(long);
+    method public static java.util.stream.LongStream of(long...);
+    method public abstract java.util.stream.LongStream parallel();
+    method public abstract java.util.stream.LongStream peek(java.util.function.LongConsumer);
+    method public static java.util.stream.LongStream range(long, long);
+    method public static java.util.stream.LongStream rangeClosed(long, long);
+    method public abstract long reduce(long, java.util.function.LongBinaryOperator);
+    method public abstract java.util.OptionalLong reduce(java.util.function.LongBinaryOperator);
+    method public abstract java.util.stream.LongStream sequential();
+    method public abstract java.util.stream.LongStream skip(long);
+    method public abstract java.util.stream.LongStream sorted();
+    method public abstract java.util.Spliterator.OfLong spliterator();
+    method public abstract long sum();
+    method public abstract java.util.LongSummaryStatistics summaryStatistics();
+    method public abstract long[] toArray();
+  }
+
+  public static abstract interface LongStream.Builder implements java.util.function.LongConsumer {
+    method public abstract void accept(long);
+    method public default java.util.stream.LongStream.Builder add(long);
+    method public abstract java.util.stream.LongStream build();
+  }
+
+  public abstract interface Stream implements java.util.stream.BaseStream {
+    method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
+    method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Stream.Builder<T> builder();
+    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
+    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
+    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
+    method public abstract long count();
+    method public abstract java.util.stream.Stream<T> distinct();
+    method public static java.util.stream.Stream<T> empty();
+    method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
+    method public abstract java.util.Optional<T> findAny();
+    method public abstract java.util.Optional<T> findFirst();
+    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
+    method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
+    method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
+    method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
+    method public abstract void forEach(java.util.function.Consumer<? super T>);
+    method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
+    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
+    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
+    method public abstract java.util.stream.Stream<T> limit(long);
+    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
+    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
+    method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
+    method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
+    method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
+    method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
+    method public static java.util.stream.Stream<T> of(T);
+    method public static java.util.stream.Stream<T> of(T...);
+    method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
+    method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
+    method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
+    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
+    method public abstract java.util.stream.Stream<T> skip(long);
+    method public abstract java.util.stream.Stream<T> sorted();
+    method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
+    method public abstract java.lang.Object[] toArray();
+    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
+  }
+
+  public static abstract interface Stream.Builder implements java.util.function.Consumer {
+    method public abstract void accept(T);
+    method public default java.util.stream.Stream.Builder<T> add(T);
+    method public abstract java.util.stream.Stream<T> build();
+  }
+
+  public final class StreamSupport {
+    method public static java.util.stream.DoubleStream doubleStream(java.util.Spliterator.OfDouble, boolean);
+    method public static java.util.stream.DoubleStream doubleStream(java.util.function.Supplier<? extends java.util.Spliterator.OfDouble>, int, boolean);
+    method public static java.util.stream.IntStream intStream(java.util.Spliterator.OfInt, boolean);
+    method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
+    method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
+    method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
+    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
+    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
+  }
+
+}
+
 package java.util.zip {
 
   public class Adler32 implements java.util.zip.Checksum {
@@ -62650,11 +63987,9 @@
 
   public final class PrivateCredentialPermission extends java.security.Permission {
     ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getCredentialClass();
     method public java.lang.String[][] getPrincipals();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 0bf6594..3f16bca 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -9,18 +9,50 @@
 package android.app.admin {
 
   public class DevicePolicyManager {
+    method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+    method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
     method public deprecated java.lang.String getDeviceInitializerApp();
     method public deprecated android.content.ComponentName getDeviceInitializerComponent();
   }
 
 }
 
+package android.content {
+
+  public abstract class Context {
+    method public deprecated android.content.Context createCredentialEncryptedStorageContext();
+    method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+    method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+    method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
+    method public deprecated boolean isCredentialEncryptedStorage();
+    method public deprecated boolean isDeviceEncryptedStorage();
+    method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
+    method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
+  }
+
+}
+
 package android.content.pm {
 
+  public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    field public deprecated java.lang.String credentialEncryptedDataDir;
+    field public deprecated java.lang.String deviceEncryptedDataDir;
+  }
+
+  public class ComponentInfo extends android.content.pm.PackageItemInfo {
+    field public deprecated boolean encryptionAware;
+  }
+
   public class PackageInfo implements android.os.Parcelable {
     field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
   }
 
+  public abstract class PackageManager {
+    field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
+    field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
+    field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+  }
+
 }
 
 package android.database {
@@ -33,14 +65,45 @@
 
 }
 
+package android.graphics {
+
+  public deprecated class AvoidXfermode extends android.graphics.Xfermode {
+    ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
+  }
+
+  public static final class AvoidXfermode.Mode extends java.lang.Enum {
+    method public static android.graphics.AvoidXfermode.Mode valueOf(java.lang.String);
+    method public static final android.graphics.AvoidXfermode.Mode[] values();
+    enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
+    enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
+  }
+
+  public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
+    ctor public PixelXorXfermode(int);
+  }
+
+}
+
 package android.media {
 
-  public class AudioFormat {
+  public final class AudioFormat implements android.os.Parcelable {
     ctor public AudioFormat();
   }
 
 }
 
+package android.media.tv {
+
+  public final class TvInputManager {
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+  }
+
+  public class TvView extends android.view.ViewGroup {
+    method public void requestUnblockContent(android.media.tv.TvContentRating);
+  }
+
+}
+
 package android.net {
 
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
@@ -69,6 +132,28 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndLocked();
+    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndUnlocked();
+    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
+  }
+
+}
+
+package android.os.storage {
+
+  public class StorageManager {
+    method public android.os.storage.StorageVolume getPrimaryVolume();
+    method public android.os.storage.StorageVolume[] getVolumeList();
+  }
+
+}
+
+package android.preference {
+
+  public class PreferenceManager {
+    method public deprecated void setStorageCredentialEncrypted();
+    method public deprecated void setStorageDeviceEncrypted();
   }
 
 }
@@ -199,14 +284,6 @@
 
 }
 
-package android.service.notification {
-
-  public abstract class ConditionProviderService extends android.app.Service {
-    method public void onRequestConditions(int);
-  }
-
-}
-
 package android.test.mock {
 
   public deprecated class MockPackageManager extends android.content.pm.PackageManager {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index eedb82b..456be02 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -44,6 +44,7 @@
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
+import android.content.pm.InstrumentationInfo;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
@@ -96,6 +97,7 @@
     private static final int STACK_BOUNDS_INSET = 10;
 
     private IActivityManager mAm;
+    private IPackageManager mPm;
 
     private int mStartFlags = 0;
     private boolean mWaitOption = false;
@@ -224,7 +226,8 @@
                 "    --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" +
                 "\n" +
                 "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
-                "  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:\n" +
+                "  is the form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there \n" +
+                "  is only one instrumentation.  Options are:\n" +
                 "    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with\n" +
                 "        [-e perf true] to generate raw output for performance measurements.\n" +
                 "    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a\n" +
@@ -373,6 +376,12 @@
             throw new AndroidException("Can't connect to activity manager; is the system running?");
         }
 
+        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+        if (mPm == null) {
+            System.err.println(NO_SYSTEM_ERROR_CODE);
+            throw new AndroidException("Can't connect to package manager; is the system running?");
+        }
+
         String op = nextArgRequired();
 
         if (op.equals("start")) {
@@ -570,14 +579,8 @@
                 if (intent.getComponent() != null) {
                     packageName = intent.getComponent().getPackageName();
                 } else {
-                    IPackageManager pm = IPackageManager.Stub.asInterface(
-                            ServiceManager.getService("package"));
-                    if (pm == null) {
-                        System.err.println("Error: Package manager not running; aborting");
-                        return;
-                    }
-                    List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0,
-                            mUserId);
+                    List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0,
+                            mUserId).getList();
                     if (activities == null || activities.size() <= 0) {
                         System.err.println("Error: Intent does not match any activities: "
                                 + intent);
@@ -606,7 +609,7 @@
                             new File(mProfileFile),
                             ParcelFileDescriptor.MODE_CREATE |
                             ParcelFileDescriptor.MODE_TRUNCATE |
-                            ParcelFileDescriptor.MODE_READ_WRITE);
+                            ParcelFileDescriptor.MODE_WRITE_ONLY);
                 } catch (FileNotFoundException e) {
                     System.err.println("Error: Unable to open file: " + mProfileFile);
                     System.err.println("Consider using a file under /data/local/tmp/");
@@ -813,8 +816,44 @@
         }
 
         String cnArg = nextArgRequired();
-        ComponentName cn = ComponentName.unflattenFromString(cnArg);
-        if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
+
+        ComponentName cn;
+        if (cnArg.contains("/")) {
+            cn = ComponentName.unflattenFromString(cnArg);
+            if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
+        } else {
+            List<InstrumentationInfo> infos = mPm.queryInstrumentation(null, 0).getList();
+
+            final int numInfos = infos == null ? 0: infos.size();
+            List<ComponentName> cns = new ArrayList<>();
+            for (int i = 0; i < numInfos; i++) {
+                InstrumentationInfo info = infos.get(i);
+
+                ComponentName c = new ComponentName(info.packageName, info.name);
+                if (cnArg.equals(info.packageName)) {
+                    cns.add(c);
+                }
+            }
+
+            if (cns.size() == 0) {
+                throw new IllegalArgumentException("No instrumentation found for: " + cnArg);
+            } else if (cns.size() == 1) {
+                cn = cns.get(0);
+            } else {
+                StringBuilder cnsStr = new StringBuilder();
+                final int numCns = cns.size();
+                for (int i = 0; i < numCns; i++) {
+                    cnsStr.append(cns.get(i).flattenToString());
+                    cnsStr.append(", ");
+                }
+
+                // Remove last ", "
+                cnsStr.setLength(cnsStr.length() - 2);
+
+                throw new IllegalArgumentException("Found multiple instrumentations: "
+                        + cnsStr.toString());
+            }
+        }
 
         InstrumentationWatcher watcher = null;
         UiAutomationConnection connection = null;
@@ -903,7 +942,7 @@
             fd = openForSystemServer(file,
                     ParcelFileDescriptor.MODE_CREATE |
                             ParcelFileDescriptor.MODE_TRUNCATE |
-                            ParcelFileDescriptor.MODE_READ_WRITE);
+                            ParcelFileDescriptor.MODE_WRITE_ONLY);
         } catch (FileNotFoundException e) {
             System.err.println("Error: Unable to open file: " + filename);
             System.err.println("Consider using a file under /data/local/tmp/");
@@ -992,7 +1031,7 @@
                         new File(profileFile),
                         ParcelFileDescriptor.MODE_CREATE |
                         ParcelFileDescriptor.MODE_TRUNCATE |
-                        ParcelFileDescriptor.MODE_READ_WRITE);
+                        ParcelFileDescriptor.MODE_WRITE_ONLY);
             } catch (FileNotFoundException e) {
                 System.err.println("Error: Unable to open file: " + profileFile);
                 System.err.println("Consider using a file under /data/local/tmp/");
@@ -1052,7 +1091,7 @@
             fd = openForSystemServer(file,
                     ParcelFileDescriptor.MODE_CREATE |
                     ParcelFileDescriptor.MODE_TRUNCATE |
-                    ParcelFileDescriptor.MODE_READ_WRITE);
+                    ParcelFileDescriptor.MODE_WRITE_ONLY);
         } catch (FileNotFoundException e) {
             System.err.println("Error: Unable to open file: " + heapFile);
             System.err.println("Consider using a file under /data/local/tmp/");
@@ -1141,7 +1180,7 @@
         int userId = Integer.parseInt(nextArgRequired());
         byte[] token = argToBytes(nextArgRequired());
         byte[] secret = argToBytes(nextArgRequired());
-        boolean success = mAm.unlockUser(userId, token, secret);
+        boolean success = mAm.unlockUser(userId, token, secret, null);
         if (success) {
             System.out.println("Success: user unlocked");
         } else {
@@ -1216,6 +1255,7 @@
 
     class MyActivityController extends IActivityController.Stub {
         final String mGdbPort;
+        final boolean mMonkey;
 
         static final int STATE_NORMAL = 0;
         static final int STATE_CRASHED = 1;
@@ -1242,8 +1282,9 @@
         Thread mGdbThread;
         boolean mGotGdbPrint;
 
-        MyActivityController(String gdbPort) {
+        MyActivityController(String gdbPort, boolean monkey) {
             mGdbPort = gdbPort;
+            mMonkey = monkey;
         }
 
         @Override
@@ -1443,7 +1484,7 @@
             try {
                 printMessageForState();
 
-                mAm.setActivityController(this);
+                mAm.setActivityController(this, mMonkey);
                 mState = STATE_NORMAL;
 
                 InputStreamReader converter = new InputStreamReader(System.in);
@@ -1498,7 +1539,7 @@
             } catch (IOException e) {
                 e.printStackTrace();
             } finally {
-                mAm.setActivityController(null);
+                mAm.setActivityController(null, mMonkey);
             }
         }
     }
@@ -1506,16 +1547,19 @@
     private void runMonitor() throws Exception {
         String opt;
         String gdbPort = null;
+        boolean monkey = false;
         while ((opt=nextOption()) != null) {
             if (opt.equals("--gdb")) {
                 gdbPort = nextArgRequired();
+            } else if (opt.equals("-m")) {
+                monkey = true;
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
             }
         }
 
-        MyActivityController controller = new MyActivityController(gdbPort);
+        MyActivityController controller = new MyActivityController(gdbPort, monkey);
         controller.run();
     }
 
@@ -1809,7 +1853,7 @@
 
     private void resizeStackUnchecked(int stackId, Rect bounds, int delayMs, boolean animate) {
         try {
-            mAm.resizeStack(stackId, bounds, false, false, animate);
+            mAm.resizeStack(stackId, bounds, false, false, animate, -1);
             Thread.sleep(delayMs);
         } catch (RemoteException e) {
             showError("Error: resizing stack " + e);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 51bbb81..3ae9e12 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -20,6 +20,7 @@
     libutils \
     liblog \
     libbinder \
+    libnativeloader \
     libandroid_runtime \
     $(app_process_common_shared_libs) \
 
@@ -52,6 +53,7 @@
     libutils \
     liblog \
     libbinder \
+    libnativeloader \
     libandroid_runtime \
     $(app_process_common_shared_libs) \
 
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 2e02382..7590325 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -21,6 +21,7 @@
 #include <cutils/properties.h>
 #include <cutils/trace.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <nativeloader/native_loader.h>
 #include <private/android_filesystem_config.h>  // for AID_SYSTEM
 
 namespace android {
@@ -304,6 +305,7 @@
     }
 
     if (zygote) {
+        InitializeNativeLoader();
         runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
     } else if (className) {
         runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 8f361ce..c597ed2 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -68,15 +68,11 @@
 
 // ---------------------------------------------------------------------------
 
-BootAnimation::BootAnimation() : Thread(false), mZip(NULL)
-{
+BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true) {
     mSession = new SurfaceComposerClient();
 }
 
 BootAnimation::~BootAnimation() {
-    if (mZip != NULL) {
-        delete mZip;
-    }
 }
 
 void BootAnimation::onFirstRef() {
@@ -289,19 +285,15 @@
 
     bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
 
-    ZipFileRO* zipFile = NULL;
-    if ((encryptedAnimation &&
-            (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
-            ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||
-
-            ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) &&
-            ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) ||
-
-            ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
-            ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
-        mZip = zipFile;
+    if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
+        mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
     }
-
+    else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {
+        mZipFileName = OEM_BOOTANIMATION_FILE;
+    }
+    else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
+        mZipFileName = SYSTEM_BOOTANIMATION_FILE;
+    }
     return NO_ERROR;
 }
 
@@ -310,7 +302,7 @@
     bool r;
     // We have no bootanimation file, so we use the stock android logo
     // animation.
-    if (mZip == NULL) {
+    if (mZipFileName.isEmpty()) {
         r = android();
     } else {
         r = movie();
@@ -430,16 +422,17 @@
     return true;
 }
 
-bool BootAnimation::readFile(const char* name, String8& outString)
+
+static bool readFile(ZipFileRO* zip, const char* name, String8& outString)
 {
-    ZipEntryRO entry = mZip->findEntryByName(name);
+    ZipEntryRO entry = zip->findEntryByName(name);
     ALOGE_IF(!entry, "couldn't find %s", name);
     if (!entry) {
         return false;
     }
 
-    FileMap* entryMap = mZip->createEntryFileMap(entry);
-    mZip->releaseEntry(entry);
+    FileMap* entryMap = zip->createEntryFileMap(entry);
+    zip->releaseEntry(entry);
     ALOGE_IF(!entryMap, "entryMap is null");
     if (!entryMap) {
         return false;
@@ -450,18 +443,81 @@
     return true;
 }
 
-bool BootAnimation::movie()
+// The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide,
+// and the colon character is half that at 20 pixels. The glyph order is '0123456789:'.
+// We render 24 hour time.
+void BootAnimation::drawTime(const Texture& clockTex, const int yPos) {
+    static constexpr char TIME_FORMAT[] = "%H:%M";
+    static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT);
+
+    static constexpr int DIGIT_HEIGHT = 64;
+    static constexpr int DIGIT_WIDTH = 40;
+    static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2;
+    static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH;
+
+    if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) {
+        ALOGE("Clock texture is too small; abandoning boot animation clock");
+        mClockEnabled = false;
+        return;
+    }
+
+    time_t rawtime;
+    time(&rawtime);
+    struct tm* timeInfo = localtime(&rawtime);
+
+    char timeBuff[TIME_LENGTH];
+    size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo);
+
+    if (length != TIME_LENGTH - 1) {
+        ALOGE("Couldn't format time; abandoning boot animation clock");
+        mClockEnabled = false;
+        return;
+    }
+
+    glEnable(GL_BLEND);  // Allow us to draw on top of the animation
+    glBindTexture(GL_TEXTURE_2D, clockTex.name);
+
+    int xPos = (mWidth - TIME_WIDTH) / 2;
+    int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT };
+
+    for (int i = 0; i < TIME_LENGTH - 1; i++) {
+        char c = timeBuff[i];
+        int width = DIGIT_WIDTH;
+        int pos = c - '0';  // Position in the character list
+        if (pos < 0 || pos > 10) {
+            continue;
+        }
+        if (c == ':') {
+            width = COLON_WIDTH;
+        }
+
+        // Crop the texture to only the pixels in the current glyph
+        int left = pos * DIGIT_WIDTH;
+        cropRect[0] = left;
+        cropRect[2] = width;
+        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+
+        glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT);
+
+        xPos += width;
+    }
+
+    glDisable(GL_BLEND);  // Return to the animation's default behaviour
+    glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+bool BootAnimation::parseAnimationDesc(Animation& animation)
 {
     String8 desString;
 
-    if (!readFile("desc.txt", desString)) {
+    if (!readFile(animation.zip, "desc.txt", desString)) {
         return false;
     }
     char const* s = desString.string();
 
     // Create and initialize an AudioPlayer if we have an audio_conf.txt file
     String8 audioConf;
-    if (readFile("audio_conf.txt", audioConf)) {
+    if (readFile(animation.zip, "audio_conf.txt", audioConf)) {
         mAudioPlayer = new AudioPlayer;
         if (!mAudioPlayer->init(audioConf.string())) {
             ALOGE("mAudioPlayer.init failed");
@@ -469,15 +525,18 @@
         }
     }
 
-    Animation animation;
-
     // Parse the description file
     for (;;) {
         const char* endl = strstr(s, "\n");
         if (endl == NULL) break;
         String8 line(s, endl - s);
         const char* l = line.string();
-        int fps, width, height, count, pause;
+        int fps = 0;
+        int width = 0;
+        int height = 0;
+        int count = 0;
+        int pause = 0;
+        int clockPosY = -1;
         char path[ANIM_ENTRY_NAME_MAX];
         char color[7] = "000000"; // default to black if unspecified
 
@@ -487,15 +546,17 @@
             animation.width = width;
             animation.height = height;
             animation.fps = fps;
-        }
-        else if (sscanf(l, " %c %d %d %s #%6s", &pathType, &count, &pause, path, color) >= 4) {
-            // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s", pathType, count, pause, path, color);
+        } else if (sscanf(l, " %c %d %d %s #%6s %d",
+                          &pathType, &count, &pause, path, color, &clockPosY) >= 4) {
+            // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY);
             Animation::Part part;
             part.playUntilComplete = pathType == 'c';
             part.count = count;
             part.pause = pause;
             part.path = path;
+            part.clockPosY = clockPosY;
             part.audioFile = NULL;
+            part.animation = NULL;
             if (!parseColor(color, part.backgroundColor)) {
                 ALOGE("> invalid color '#%s'", color);
                 part.backgroundColor[0] = 0.0f;
@@ -504,13 +565,29 @@
             }
             animation.parts.add(part);
         }
-
+        else if (strcmp(l, "$SYSTEM") == 0) {
+            // ALOGD("> SYSTEM");
+            Animation::Part part;
+            part.playUntilComplete = false;
+            part.count = 1;
+            part.pause = 0;
+            part.audioFile = NULL;
+            part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
+            if (part.animation != NULL)
+                animation.parts.add(part);
+        }
         s = ++endl;
     }
 
+    return true;
+}
+
+bool BootAnimation::preloadZip(Animation& animation)
+{
     // read all the data structures
     const size_t pcount = animation.parts.size();
     void *cookie = NULL;
+    ZipFileRO* mZip = animation.zip;
     if (!mZip->startIteration(&cookie)) {
         return false;
     }
@@ -556,6 +633,18 @@
 
     mZip->endIteration(cookie);
 
+    return true;
+}
+
+bool BootAnimation::movie()
+{
+
+    Animation* animation = loadAnimation(mZipFileName);
+    if (animation == NULL)
+        return false;
+
+    // Blend required to draw time on top of animation frames.
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glShadeModel(GL_FLAT);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
@@ -569,6 +658,25 @@
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
+    bool clockTextureInitialized = false;
+    if (mClockEnabled) {
+        clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR);
+        mClockEnabled = clockTextureInitialized;
+    }
+
+    playAnimation(*animation);
+    releaseAnimation(animation);
+
+    if (clockTextureInitialized) {
+        glDeleteTextures(1, &mClock.name);
+    }
+
+    return false;
+}
+
+bool BootAnimation::playAnimation(const Animation& animation)
+{
+    const size_t pcount = animation.parts.size();
     const int xc = (mWidth - animation.width) / 2;
     const int yc = ((mHeight - animation.height) / 2);
     nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -581,6 +689,14 @@
         const size_t fcount = part.frames.size();
         glBindTexture(GL_TEXTURE_2D, 0);
 
+        // Handle animation package
+        if (part.animation != NULL) {
+            playAnimation(*part.animation);
+            if (exitPending())
+                break;
+            continue; //to next part
+        }
+
         for (int r=0 ; !part.count || r<part.count ; r++) {
             // Exit any non playuntil complete parts immediately
             if(exitPending() && !part.playUntilComplete)
@@ -629,6 +745,10 @@
                 // which is equivalent to mHeight - (yc + animation.height)
                 glDrawTexiOES(xc, mHeight - (yc + animation.height),
                               0, animation.width, animation.height);
+                if (mClockEnabled && part.clockPosY >= 0) {
+                    drawTime(mClock, part.clockPosY);
+                }
+
                 eglSwapBuffers(mDisplay, mSurface);
 
                 nsecs_t now = systemTime();
@@ -664,10 +784,46 @@
             }
         }
     }
-
-    return false;
+    return true;
 }
 
+void BootAnimation::releaseAnimation(Animation* animation) const
+{
+    for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
+         e = animation->parts.end(); it != e; ++it) {
+        if (it->animation)
+            releaseAnimation(it->animation);
+    }
+    if (animation->zip)
+        delete animation->zip;
+    delete animation;
+}
+
+BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
+{
+    if (mLoadedFiles.indexOf(fn) >= 0) {
+        ALOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
+            fn.string());
+        return NULL;
+    }
+    ZipFileRO *zip = ZipFileRO::open(fn);
+    if (zip == NULL) {
+        ALOGE("Failed to open animation zip \"%s\": %s",
+            fn.string(), strerror(errno));
+        return NULL;
+    }
+
+    Animation *animation =  new Animation;
+    animation->fileName = fn;
+    animation->zip = zip;
+    mLoadedFiles.add(animation->fileName);
+
+    parseAnimationDesc(*animation);
+    preloadZip(*animation);
+
+    mLoadedFiles.remove(fn);
+    return animation;
+}
 // ---------------------------------------------------------------------------
 
 }
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f968b25..d49e1ec 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -67,25 +67,36 @@
             }
         };
         struct Part {
-            int count;
-            int pause;
+            int count;  // The number of times this part should repeat, 0 for infinite
+            int pause;  // The number of frames to pause for at the end of this part
+            int clockPosY;  // The y position of the clock, in pixels, from the bottom of the
+                            // display (the clock is centred horizontally). -1 to disable the clock
             String8 path;
             SortedVector<Frame> frames;
             bool playUntilComplete;
             float backgroundColor[3];
             FileMap* audioFile;
+            Animation* animation;
         };
         int fps;
         int width;
         int height;
         Vector<Part> parts;
+        String8 audioConf;
+        String8 fileName;
+        ZipFileRO* zip;
     };
 
     status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
     status_t initTexture(const Animation::Frame& frame);
     bool android();
-    bool readFile(const char* name, String8& outString);
     bool movie();
+    void drawTime(const Texture& clockTex, const int yPos);
+    Animation* loadAnimation(const String8&);
+    bool playAnimation(const Animation&);
+    void releaseAnimation(Animation*) const;
+    bool parseAnimationDesc(Animation&);
+    bool preloadZip(Animation &animation);
 
     void checkExit();
 
@@ -93,6 +104,7 @@
     sp<AudioPlayer>                 mAudioPlayer;
     AssetManager mAssets;
     Texture     mAndroid[2];
+    Texture     mClock;
     int         mWidth;
     int         mHeight;
     EGLDisplay  mDisplay;
@@ -100,7 +112,9 @@
     EGLDisplay  mSurface;
     sp<SurfaceControl> mFlingerSurfaceControl;
     sp<Surface> mFlingerSurface;
-    ZipFileRO   *mZip;
+    bool        mClockEnabled;
+    String8     mZipFileName;
+    SortedVector<String8> mLoadedFiles;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 24449d4..d44a1df 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -930,7 +930,7 @@
                 // In non-split user mode, userId can only be SYSTEM
                 int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
                 info = mUm.createRestrictedProfile(name, parentUserId);
-                mAm.addSharedAccountsFromParentUser(userId, parentUserId);
+                mAm.addSharedAccountsFromParentUser(parentUserId, userId);
             } else if (userId < 0) {
                 info = mUm.createUser(name, flags);
             } else {
@@ -1490,7 +1490,7 @@
         System.err.println("    -i: specify the installer package name");
         System.err.println("    -s: install application on sdcard");
         System.err.println("    -f: install application on internal flash");
-        System.err.println("    -d: allow version code downgrade");
+        System.err.println("    -d: allow version code downgrade (debuggable packages only)");
         System.err.println("    -p: partial application install");
         System.err.println("    -g: grant all runtime permissions");
         System.err.println("    -S: size in bytes of entire session");
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index c469ae4..7bf073b 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -67,30 +67,6 @@
     }
 }
 
-static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,
-        uint32_t* bytespp, uint32_t* f)
-{
-
-    switch (vinfo.bits_per_pixel) {
-        case 16:
-            *f = PIXEL_FORMAT_RGB_565;
-            *bytespp = 2;
-            break;
-        case 24:
-            *f = PIXEL_FORMAT_RGB_888;
-            *bytespp = 3;
-            break;
-        case 32:
-            // TODO: do better decoding of vinfo here
-            *f = PIXEL_FORMAT_RGBX_8888;
-            *bytespp = 4;
-            break;
-        default:
-            return BAD_VALUE;
-    }
-    return NO_ERROR;
-}
-
 static status_t notifyMediaScanner(const char* fileName) {
     String8 cmd("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
     String8 fileUrl("\"");
@@ -147,7 +123,7 @@
             png = true;
         }
     }
-    
+
     if (fd == -1) {
         usage(pname);
         return 1;
@@ -195,28 +171,6 @@
         s = screenshot.getStride();
         f = screenshot.getFormat();
         size = screenshot.getSize();
-    } else {
-        const char* fbpath = "/dev/graphics/fb0";
-        int fb = open(fbpath, O_RDONLY);
-        if (fb >= 0) {
-            struct fb_var_screeninfo vinfo;
-            if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {
-                uint32_t bytespp;
-                if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {
-                    size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;
-                    w = vinfo.xres;
-                    h = vinfo.yres;
-                    s = vinfo.xres;
-                    size = w*h*bytespp;
-                    mapsize = offset + size;
-                    mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
-                    if (mapbase != MAP_FAILED) {
-                        base = (void const *)((char const *)mapbase + offset);
-                    }
-                }
-            }
-            close(fb);
-        }
     }
 
     if (base != NULL) {
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index b208e43..0e674c8 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -88,6 +88,8 @@
             runForget();
         } else if ("set-emulate-fbe".equals(op)) {
             runSetEmulateFbe();
+        } else if ("get-fbe-mode".equals(op)) {
+            runGetFbeMode();
         } else {
             throw new IllegalArgumentException();
         }
@@ -145,6 +147,16 @@
                 StorageManager.DEBUG_EMULATE_FBE);
     }
 
+    public void runGetFbeMode() {
+        if (StorageManager.isFileEncryptedNativeOnly()) {
+            System.out.println("native");
+        } else if (StorageManager.isFileEncryptedEmulatedOnly()) {
+            System.out.println("emulated");
+        } else {
+            System.out.println("none");
+        }
+    }
+
     public void runPartition() throws RemoteException {
         final String diskId = nextArg();
         final String type = nextArg();
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index 1fa9bac..ddeb8e7 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -50,9 +50,9 @@
         }
         try {
             if (isSet) {
-                am.setActivityController(new DummyActivityController());
+                am.setActivityController(new DummyActivityController(), true);
             } else {
-                am.setActivityController(null);
+                am.setActivityController(null, true);
             }
         } catch (RemoteException e) {
             throw new RuntimeException(e);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4bc6b97..bf823f8 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -334,7 +334,7 @@
     public static final int GLOBAL_ACTION_HOME = 2;
 
     /**
-     * Action to open the recent apps.
+     * Action to toggle showing the overview of recent apps
      */
     public static final int GLOBAL_ACTION_RECENTS = 3;
 
@@ -353,6 +353,11 @@
      */
     public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
 
+    /**
+     * Action to toggle docking the current app's window
+     */
+    public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
+
     private static final String LOG_TAG = "AccessibilityService";
 
     /**
@@ -378,13 +383,7 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
     public @interface SoftKeyboardShowMode {};
-    /**
-     * @hide
-     */
     public static final int SHOW_MODE_AUTO = 0;
-    /**
-     * @hide
-     */
     public static final int SHOW_MODE_HIDDEN = 1;
 
     private int mConnectionId;
@@ -407,7 +406,9 @@
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
-     * @param event An event.
+     * @param event The new event. This event is owned by the caller and cannot be used after
+     * this method returns. Services wishing to use the event after this method returns should
+     * make a copy.
      */
     public abstract void onAccessibilityEvent(AccessibilityEvent event);
 
@@ -494,7 +495,9 @@
      * functionality.
      * <p>
      *
-     * @param event The event to be processed.
+     * @param event The event to be processed. This event is owned by the caller and cannot be used
+     * after this method returns. Services wishing to use the event after this method returns should
+     * make a copy.
      * @return If true then the event will be consumed and not delivered to
      *         applications, otherwise it will be delivered as usual.
      */
@@ -852,6 +855,7 @@
                     return connection.getMagnificationScale();
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain scale", re);
+                    re.rethrowFromSystemServer();
                 }
             }
             return 1.0f;
@@ -880,6 +884,7 @@
                     return connection.getMagnificationCenterX();
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain center X", re);
+                    re.rethrowFromSystemServer();
                 }
             }
             return 0.0f;
@@ -908,6 +913,7 @@
                     return connection.getMagnificationCenterY();
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain center Y", re);
+                    re.rethrowFromSystemServer();
                 }
             }
             return 0.0f;
@@ -934,6 +940,7 @@
                     return connection.getMagnifiedRegion();
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain magnified region", re);
+                    re.rethrowFromSystemServer();
                 }
             }
             return Region.obtain();
@@ -962,6 +969,7 @@
                     return connection.resetMagnification(animate);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to reset", re);
+                    re.rethrowFromSystemServer();
                 }
             }
             return false;
@@ -990,6 +998,7 @@
                             scale, Float.NaN, Float.NaN, animate);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to set scale", re);
+                    re.rethrowFromSystemServer();
                 }
             }
             return false;
@@ -1021,6 +1030,7 @@
                             Float.NaN, centerX, centerY, animate);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to set center", re);
+                    re.rethrowFromSystemServer();
                 }
             }
             return false;
@@ -1132,7 +1142,7 @@
         }
 
         /**
-         * Removes all instances of the specified change listener from teh list of magnification
+         * Removes all instances of the specified change listener from the list of magnification
          * change listeners.
          *
          * @param listener the listener to remove, must be non-null
@@ -1211,14 +1221,11 @@
 
         /**
          * Returns the show mode of the soft keyboard. The default show mode is
-         * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
-         * input field is focused. An AccessibilityService can also request the show mode
-         * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+         * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
+         * focused. An AccessibilityService can also request the show mode
+         * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
          *
          * @return the current soft keyboard show mode
-         *
-         * @see Settings#Secure#SHOW_MODE_AUTO
-         * @see Settings#Secure#SHOW_MODE_HIDDEN
          */
         @SoftKeyboardShowMode
         public int getShowMode() {
@@ -1234,9 +1241,9 @@
 
         /**
          * Sets the soft keyboard show mode. The default show mode is
-         * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
-         * input field is focused. An AccessibilityService can also request the show mode
-         * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
+         * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
+         * focused. An AccessibilityService can also request the show mode
+         * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
          * The lastto this method will be honored, regardless of any previous calls (including those
          * made by other AccessibilityServices).
          * <p>
@@ -1246,9 +1253,6 @@
          *
          * @param showMode the new show mode for the soft keyboard
          * @return {@code true} on success
-         *
-         * @see Settings#Secure#SHOW_MODE_AUTO
-         * @see Settings#Secure#SHOW_MODE_HIDDEN
          */
         public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
            final IAccessibilityServiceConnection connection =
@@ -1258,7 +1262,8 @@
                try {
                    return connection.setSoftKeyboardShowMode(showMode);
                } catch (RemoteException re) {
-                   Log.w(LOG_TAG, "Falied to set soft keyboard behavior", re);
+                   Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
+                   re.rethrowFromSystemServer();
                }
            }
            return false;
@@ -1270,9 +1275,9 @@
         public interface OnShowModeChangedListener {
            /**
             * Called when the soft keyboard behavior changes. The default show mode is
-            * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
-            * input field is focused. An AccessibilityService can also request the show mode
-            * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+            * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
+            * focused. An AccessibilityService can also request the show mode
+            * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
             *
             * @param controller the soft keyboard controller
             * @param showMode the current soft keyboard show mode
@@ -1304,6 +1309,7 @@
                 return connection.performGlobalAction(action);
             } catch (RemoteException re) {
                 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
+                re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1352,6 +1358,7 @@
                 return connection.getServiceInfo();
             } catch (RemoteException re) {
                 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
+                re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -1385,6 +1392,7 @@
                 AccessibilityInteractionClient.getInstance().clearCache();
             } catch (RemoteException re) {
                 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
+                re.rethrowFromSystemServer();
             }
         }
     }
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 079bdfc..ee03280 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -36,11 +36,11 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import com.android.internal.R;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -319,6 +319,9 @@
      */
     public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
 
+    /** {@hide} */
+    public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
+
     /**
      * The event types an {@link AccessibilityService} is interested in.
      * <p>
@@ -686,6 +689,12 @@
         return null;
     }
 
+    /** {@hide} */
+    public boolean isDirectBootAware() {
+        return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
+                || mResolveInfo.serviceInfo.directBootAware;
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 14aabcf..e18a34d 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -36,142 +36,38 @@
  * Accessibility services with the
  * {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch
  * gestures. This class describes those gestures. Gestures are made up of one or more strokes.
- * Gestures are immutable; use the {@code create} methods to get common gesture, or a
- * {@code Builder} to create a new one.
+ * Gestures are immutable once built.
  * <p>
  * Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds.
  */
 public final class GestureDescription {
     /** Gestures may contain no more than this many strokes */
-    public static final int MAX_STROKE_COUNT = 10;
+    private static final int MAX_STROKE_COUNT = 10;
 
     /**
      * Upper bound on total gesture duration. Nearly all gestures will be much shorter.
      */
-    public static final long MAX_GESTURE_DURATION_MS = 60 * 1000;
+    private static final long MAX_GESTURE_DURATION_MS = 60 * 1000;
 
     private final List<StrokeDescription> mStrokes = new ArrayList<>();
     private final float[] mTempPos = new float[2];
 
     /**
-     * Create a description of a click gesture
+     * Get the upper limit for the number of strokes a gesture may contain.
      *
-     * @param x The x coordinate to click. Must not be negative.
-     * @param y The y coordinate to click. Must not be negative.
-     *
-     * @return A description of a click at (x, y)
+     * @return The maximum number of strokes.
      */
-    public static GestureDescription createClick(@IntRange(from = 0) int x,
-            @IntRange(from = 0) int y) {
-        Path clickPath = new Path();
-        clickPath.moveTo(x, y);
-        clickPath.lineTo(x + 1, y);
-        return new GestureDescription(
-                new StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout()));
+    public static int getMaxStrokeCount() {
+        return MAX_STROKE_COUNT;
     }
 
     /**
-     * Create a description of a long click gesture
+     * Get the upper limit on a gesture's duration.
      *
-     * @param x The x coordinate to click. Must not be negative.
-     * @param y The y coordinate to click. Must not be negative.
-     *
-     * @return A description of a click at (x, y)
+     * @return The maximum duration in milliseconds.
      */
-    public static GestureDescription createLongClick(@IntRange(from = 0) int x,
-            @IntRange(from = 0) int y) {
-        Path clickPath = new Path();
-        clickPath.moveTo(x, y);
-        clickPath.lineTo(x + 1, y);
-        int longPressTime = ViewConfiguration.getLongPressTimeout();
-        return new GestureDescription(
-                new StrokeDescription(clickPath, 0, longPressTime + (longPressTime / 2)));
-    }
-
-    /**
-     * Create a description of a swipe gesture
-     *
-     * @param startX The x coordinate of the starting point. Must not be negative.
-     * @param startY The y coordinate of the starting point. Must not be negative.
-     * @param endX The x coordinate of the ending point. Must not be negative.
-     * @param endY The y coordinate of the ending point. Must not be negative.
-     * @param duration The time, in milliseconds, to complete the gesture. Must not be negative.
-     *
-     * @return A description of a swipe from ({@code startX}, {@code startY}) to
-     * ({@code endX}, {@code endY}) that takes {@code duration} milliseconds. Returns {@code null}
-     * if the path specified for the swipe is invalid.
-     */
-    public static GestureDescription createSwipe(@IntRange(from = 0) int startX,
-            @IntRange(from = 0) int startY,
-            @IntRange(from = 0) int endX,
-            @IntRange(from = 0) int endY,
-            @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) {
-        Path swipePath = new Path();
-        swipePath.moveTo(startX, startY);
-        swipePath.lineTo(endX, endY);
-        return new GestureDescription(new StrokeDescription(swipePath, 0, duration));
-    }
-
-    /**
-     * Create a description for a pinch (or zoom) gesture.
-     *
-     * @param centerX The x coordinate of the center of the pinch. Must not be negative.
-     * @param centerY The y coordinate of the center of the pinch. Must not be negative.
-     * @param startSpacing The spacing of the touch points at the beginning of the gesture. Must not
-     * be negative.
-     * @param endSpacing The spacing of the touch points at the end of the gesture. Must not be
-     * negative.
-     * @param orientation The angle, in degrees, of the gesture. 0 represents a horizontal pinch
-     * @param duration The time, in milliseconds, to complete the gesture. Must not be negative.
-     *
-     * @return A description of a pinch centered at ({code centerX}, {@code centerY}) that starts
-     * with the touch points spaced by {@code startSpacing} and ends with them spaced by
-     * {@code endSpacing} that lasts {@code duration} ms. Returns {@code null} if either path
-     * specified for the pinch is invalid.
-     */
-    public static GestureDescription createPinch(@IntRange(from = 0) int centerX,
-            @IntRange(from = 0) int centerY,
-            @IntRange(from = 0) int startSpacing,
-            @IntRange(from = 0) int endSpacing,
-            float orientation,
-            @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) {
-        if ((startSpacing < 0) || (endSpacing < 0)) {
-            throw new IllegalArgumentException("Pinch spacing cannot be negative");
-        }
-        float[] startPoint1 = new float[2];
-        float[] endPoint1 = new float[2];
-        float[] startPoint2 = new float[2];
-        float[] endPoint2 = new float[2];
-
-        /* Build points for a horizontal gesture centered at the origin */
-        startPoint1[0] = startSpacing / 2;
-        startPoint1[1] = 0;
-        endPoint1[0] = endSpacing / 2;
-        endPoint1[1] = 0;
-        startPoint2[0] = -startSpacing / 2;
-        startPoint2[1] = 0;
-        endPoint2[0] = -endSpacing / 2;
-        endPoint2[1] = 0;
-
-        /* Rotate and translate the points */
-        Matrix matrix = new Matrix();
-        matrix.setRotate(orientation);
-        matrix.postTranslate(centerX, centerY);
-        matrix.mapPoints(startPoint1);
-        matrix.mapPoints(endPoint1);
-        matrix.mapPoints(startPoint2);
-        matrix.mapPoints(endPoint2);
-
-        Path path1 = new Path();
-        path1.moveTo(startPoint1[0], startPoint1[1]);
-        path1.lineTo(endPoint1[0], endPoint1[1]);
-        Path path2 = new Path();
-        path2.moveTo(startPoint2[0], startPoint2[1]);
-        path2.lineTo(endPoint2[0], endPoint2[1]);
-
-        return new GestureDescription(Arrays.asList(
-                new StrokeDescription(path1, 0, duration),
-                new StrokeDescription(path2, 0, duration)));
+    public static long getMaxGestureDuration() {
+        return MAX_GESTURE_DURATION_MS;
     }
 
     private GestureDescription() {}
@@ -180,10 +76,6 @@
         mStrokes.addAll(strokes);
     }
 
-    private GestureDescription(StrokeDescription stroke) {
-        mStrokes.add(stroke);
-    }
-
     /**
      * Get the number of stroke in the gesture.
      *
@@ -278,21 +170,23 @@
          */
         public Builder addStroke(@NonNull StrokeDescription strokeDescription) {
             if (mStrokes.size() >= MAX_STROKE_COUNT) {
-                throw new RuntimeException("Attempting to add too many strokes to a gesture");
+                throw new IllegalStateException(
+                        "Attempting to add too many strokes to a gesture");
             }
 
             mStrokes.add(strokeDescription);
 
             if (getTotalDuration(mStrokes) > MAX_GESTURE_DURATION_MS) {
                 mStrokes.remove(strokeDescription);
-                throw new RuntimeException("Gesture would exceed maximum duration with new stroke");
+                throw new IllegalStateException(
+                        "Gesture would exceed maximum duration with new stroke");
             }
             return this;
         }
 
         public GestureDescription build() {
             if (mStrokes.size() == 0) {
-                throw new RuntimeException("Gestures must have at least one stroke");
+                throw new IllegalStateException("Gestures must have at least one stroke");
             }
             return new GestureDescription(mStrokes);
         }
@@ -317,8 +211,8 @@
          * Must not be negative.
          */
         public StrokeDescription(@NonNull Path path,
-                @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long startTime,
-                @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) {
+                @IntRange(from = 0) long startTime,
+                @IntRange(from = 0) long duration) {
             if (duration <= 0) {
                 throw new IllegalArgumentException("Duration must be positive");
             }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 1d9e3bb..7465ed9 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -353,8 +353,7 @@
         try {
             return mService.getPassword(account);
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -382,8 +381,7 @@
         try {
             return mService.getUserData(account, key);
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -402,8 +400,7 @@
         try {
             return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
         } catch (RemoteException e) {
-            // will never happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -424,8 +421,7 @@
         try {
             return mService.getAuthenticatorTypes(userId);
         } catch (RemoteException e) {
-            // will never happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -449,8 +445,7 @@
         try {
             return mService.getAccounts(null, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -475,8 +470,7 @@
         try {
             return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -493,8 +487,7 @@
         try {
             return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
         } catch (RemoteException re) {
-            // won't ever happen
-            throw new RuntimeException(re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -512,8 +505,7 @@
             return mService.getAccountsByTypeForPackage(type, packageName,
                     mContext.getOpPackageName());
         } catch (RemoteException re) {
-            // won't ever happen
-            throw new RuntimeException(re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -552,8 +544,7 @@
             return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -572,8 +563,7 @@
         try {
             mService.updateAppPermission(account, authTokenType, uid, value);
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -742,8 +732,7 @@
         try {
             return mService.addAccountExplicitly(account, password, userdata);
         } catch (RemoteException e) {
-            // Can happen if there was a SecurityException was thrown.
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -768,7 +757,7 @@
         try {
             return mService.accountAuthenticated(account);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -836,8 +825,7 @@
         try {
             return mService.getPreviousName(account);
         } catch (RemoteException e) {
-            // will never happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1008,8 +996,7 @@
         try {
             return mService.removeAccountExplicitly(account);
         } catch (RemoteException e) {
-            // May happen if the caller doesn't match the signature of the authenticator.
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1036,8 +1023,7 @@
                 mService.invalidateAuthToken(accountType, authToken);
             }
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1068,8 +1054,7 @@
         try {
             return mService.peekAuthToken(account, authTokenType);
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1098,8 +1083,7 @@
         try {
             mService.setPassword(account, password);
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1127,8 +1111,7 @@
         try {
             mService.clearPassword(account);
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1156,8 +1139,7 @@
         try {
             mService.setUserData(account, key, value);
         } catch (RemoteException e) {
-            // Will happen if there is not signature match.
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1186,8 +1168,7 @@
         try {
             mService.setAuthToken(account, authTokenType, authToken);
         } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1588,7 +1569,7 @@
             mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
                     user.getIdentifier());
         } catch (RemoteException re) {
-            throw new IllegalStateException(re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1641,8 +1622,7 @@
             boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier());
             return val;
         } catch (RemoteException re) {
-            // won't ever happen
-            throw new RuntimeException(re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1655,8 +1635,7 @@
         try {
             return mService.getSharedAccountsAsUser(user.getIdentifier());
         } catch (RemoteException re) {
-            // won't ever happen
-            throw new RuntimeException(re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1878,7 +1857,7 @@
         try {
             return mService.someUserHasAccount(account);
         } catch (RemoteException re) {
-            throw new RuntimeException(re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -2039,8 +2018,7 @@
                     try {
                         doWork();
                     } catch (RemoteException e) {
-                        // this will only happen if the system process is dead, which means
-                        // we will be dying ourselves
+                        throw e.rethrowFromSystemServer();
                     }
                 } else {
                     set(bundle);
@@ -2820,6 +2798,15 @@
         if (account == null) {
             throw new IllegalArgumentException("account is null");
         }
+
+        // Always include the calling package name. This just makes life easier
+        // down stream.
+        final Bundle optionsIn = new Bundle();
+        if (options != null) {
+            optionsIn.putAll(options);
+        }
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
         return new AmsTask(activity, handler, callback) {
             @Override
             public void doWork() throws RemoteException {
@@ -2828,7 +2815,7 @@
                         account,
                         authTokenType,
                         activity != null,
-                        options);
+                        optionsIn);
             }
         }.start();
     }
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 844063c..c51725a 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -16,6 +16,8 @@
 
 package android.animation;
 
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ConstantState;
 
 import java.util.ArrayList;
@@ -50,7 +52,7 @@
      * A set of flags which identify the type of configuration changes that can affect this
      * Animator. Used by the Animator cache.
      */
-    int mChangingConfigurations = 0;
+    @Config int mChangingConfigurations = 0;
 
     /**
      * If this animator is inflated from a constant state, keep a reference to it so that
@@ -344,7 +346,7 @@
      * @see android.content.pm.ActivityInfo
      * @hide
      */
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return mChangingConfigurations;
     }
 
@@ -358,7 +360,7 @@
      * @see android.content.pm.ActivityInfo
      * @hide
      */
-    public void setChangingConfigurations(int configs) {
+    public void setChangingConfigurations(@Config int configs) {
         mChangingConfigurations = configs;
     }
 
@@ -368,7 +370,7 @@
      * This method is called while loading the animator.
      * @hide
      */
-    public void appendChangingConfigurations(int configs) {
+    public void appendChangingConfigurations(@Config int configs) {
         mChangingConfigurations |= configs;
     }
 
@@ -435,10 +437,14 @@
      * operate on target objects (for example, {@link ValueAnimator}, but this method
      * is on the superclass for the convenience of dealing generically with those subclasses
      * that do handle targets.
+     * <p>
+     * <strong>Note:</strong> The target is stored as a weak reference internally to avoid leaking
+     * resources by having animators directly reference old targets. Therefore, you should
+     * ensure that animator targets always have a hard reference elsewhere.
      *
      * @param target The object being animated
      */
-    public void setTarget(Object target) {
+    public void setTarget(@Nullable Object target) {
     }
 
     // Hide reverse() and canReverse() for now since reverse() only work for simple
@@ -564,7 +570,7 @@
     private static class AnimatorConstantState extends ConstantState<Animator> {
 
         final Animator mAnimator;
-        int mChangingConf;
+        @Config int mChangingConf;
 
         public AnimatorConstantState(Animator animator) {
             mAnimator = animator;
@@ -574,7 +580,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConf;
         }
 
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 20d71a6..7d5931f 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -16,7 +16,10 @@
 package android.animation;
 
 import android.annotation.AnimatorRes;
+import android.annotation.AnyRes;
+import android.annotation.NonNull;
 import android.content.Context;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ConfigurationBoundResourceCache;
 import android.content.res.ConstantState;
 import android.content.res.Resources;
@@ -108,7 +111,7 @@
             float pathErrorScale) throws NotFoundException {
         final ConfigurationBoundResourceCache<Animator> animatorCache = resources
                 .getAnimatorCache();
-        Animator animator = animatorCache.getInstance(id, theme);
+        Animator animator = animatorCache.getInstance(id, resources, theme);
         if (animator != null) {
             if (DBG_ANIMATOR_INFLATER) {
                 Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
@@ -157,7 +160,7 @@
         final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
                 .getStateListAnimatorCache();
         final Theme theme = context.getTheme();
-        StateListAnimator animator = cache.getInstance(id, theme);
+        StateListAnimator animator = cache.getInstance(id, resources, theme);
         if (animator != null) {
             return animator;
         }
@@ -1062,7 +1065,7 @@
         return anim;
     }
 
-    private static int getChangingConfigs(Resources resources, int id) {
+    private static @Config int getChangingConfigs(@NonNull Resources resources, @AnyRes int id) {
         synchronized (sTmpTypedValue) {
             resources.getValue(id, sTmpTypedValue, true);
             return sTmpTypedValue.changingConfigurations;
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 32edd4d..77df151 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -29,8 +29,9 @@
  * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
  * values between those keyframes for a given animation. The class internal to the animation
  * package because it is an implementation detail of how Keyframes are stored and used.
+ * @hide
  */
-class KeyframeSet implements Keyframes {
+public class KeyframeSet implements Keyframes {
 
     int mNumKeyframes;
 
diff --git a/core/java/android/animation/Keyframes.java b/core/java/android/animation/Keyframes.java
index c149bed..e40a86c 100644
--- a/core/java/android/animation/Keyframes.java
+++ b/core/java/android/animation/Keyframes.java
@@ -20,8 +20,9 @@
 /**
  * This interface abstracts a collection of Keyframe objects and is called by
  * ValueAnimator to calculate values between those keyframes for a given animation.
+ * @hide
  */
-interface Keyframes extends Cloneable {
+public interface Keyframes extends Cloneable {
 
     /**
      * Sets the TypeEvaluator to be used when calculating animated values. This object
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 0b751b2..542ecf4 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -373,6 +373,7 @@
      * @param values A set of values that the animation will animate between over time.
      * @return An ObjectAnimator object that is set up to animate between the given values.
      */
+    @SafeVarargs
     public static <T> ObjectAnimator ofMultiInt(Object target, String propertyName,
             TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, T... values) {
         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, converter,
@@ -569,6 +570,7 @@
      * @param values A set of values that the animation will animate between over time.
      * @return An ObjectAnimator object that is set up to animate between the given values.
      */
+    @SafeVarargs
     public static <T> ObjectAnimator ofMultiFloat(Object target, String propertyName,
             TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, T... values) {
         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, converter,
@@ -642,6 +644,7 @@
      * @return An ObjectAnimator object that is set up to animate between the given values.
      */
     @NonNull
+    @SafeVarargs
     public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
             TypeEvaluator<V> evaluator, V... values) {
         ObjectAnimator anim = new ObjectAnimator(target, property);
@@ -670,6 +673,7 @@
      * @return An ObjectAnimator object that is set up to animate between the given values.
      */
     @NonNull
+    @SafeVarargs
     public static <T, V, P> ObjectAnimator ofObject(T target, Property<T, P> property,
             TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values) {
         PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, evaluator,
@@ -894,12 +898,6 @@
         return mTarget == null ? null : mTarget.get();
     }
 
-    /**
-     * Sets the target object whose property will be animated by this animation. If the
-     * animator has been started, it will be canceled.
-     *
-     * @param target The object being animated
-     */
     @Override
     public void setTarget(@Nullable Object target) {
         final Object oldTarget = getTarget();
diff --git a/core/java/android/animation/PathKeyframes.java b/core/java/android/animation/PathKeyframes.java
index 8230ac5..50a490e 100644
--- a/core/java/android/animation/PathKeyframes.java
+++ b/core/java/android/animation/PathKeyframes.java
@@ -34,8 +34,9 @@
  * Typically, the returned type is a PointF, but the individual components can be extracted
  * as either an IntKeyframes or FloatKeyframes.
  * </p>
+ * @hide
  */
-class PathKeyframes implements Keyframes {
+public class PathKeyframes implements Keyframes {
     private static final int FRACTION_OFFSET = 0;
     private static final int X_OFFSET = 1;
     private static final int Y_OFFSET = 2;
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 6ba5b96..ffea6f5 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -236,6 +236,7 @@
      * @see ObjectAnimator#ofMultiInt(Object, String, TypeConverter, TypeEvaluator, Object[])
      * @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...)
      */
+    @SafeVarargs
     public static <V> PropertyValuesHolder ofMultiInt(String propertyName,
             TypeConverter<V, int[]> converter, TypeEvaluator<V> evaluator, V... values) {
         return new MultiIntValuesHolder(propertyName, converter, evaluator, values);
@@ -353,6 +354,7 @@
      * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
      * @see ObjectAnimator#ofMultiFloat(Object, String, TypeConverter, TypeEvaluator, Object[])
      */
+    @SafeVarargs
     public static <V> PropertyValuesHolder ofMultiFloat(String propertyName,
             TypeConverter<V, float[]> converter, TypeEvaluator<V> evaluator, V... values) {
         return new MultiFloatValuesHolder(propertyName, converter, evaluator, values);
@@ -438,6 +440,7 @@
      * @param values The values that the property will animate between.
      * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
      */
+    @SafeVarargs
     public static <V> PropertyValuesHolder ofObject(Property property,
             TypeEvaluator<V> evaluator, V... values) {
         PropertyValuesHolder pvh = new PropertyValuesHolder(property);
@@ -465,6 +468,7 @@
      * @see #setConverter(TypeConverter)
      * @see TypeConverter
      */
+    @SafeVarargs
     public static <T, V> PropertyValuesHolder ofObject(Property<?, V> property,
             TypeConverter<T, V> converter, TypeEvaluator<T> evaluator, T... values) {
         PropertyValuesHolder pvh = new PropertyValuesHolder(property);
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
index d49e914..b6d6910 100644
--- a/core/java/android/animation/StateListAnimator.java
+++ b/core/java/android/animation/StateListAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ConstantState;
 import android.util.StateSet;
 import android.view.View;
@@ -53,7 +54,7 @@
     private WeakReference<View> mViewRef;
     private StateListAnimatorConstantState mConstantState;
     private AnimatorListenerAdapter mAnimatorListener;
-    private int mChangingConfigurations;
+    private @Config int mChangingConfigurations;
 
     public StateListAnimator() {
         initAnimatorListener();
@@ -223,7 +224,7 @@
      * @see android.content.pm.ActivityInfo
      * @hide
      */
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return mChangingConfigurations;
     }
 
@@ -237,7 +238,7 @@
      * @see android.content.pm.ActivityInfo
      * @hide
      */
-    public void setChangingConfigurations(int configs) {
+    public void setChangingConfigurations(@Config int configs) {
         mChangingConfigurations = configs;
     }
 
@@ -247,7 +248,7 @@
      * This method is called while loading the animator.
      * @hide
      */
-    public void appendChangingConfigurations(int configs) {
+    public void appendChangingConfigurations(@Config int configs) {
         mChangingConfigurations |= configs;
     }
 
@@ -309,7 +310,7 @@
 
         final StateListAnimator mAnimator;
 
-        int mChangingConf;
+        @Config int mChangingConf;
 
         public StateListAnimatorConstantState(StateListAnimator animator) {
             mAnimator = animator;
@@ -318,7 +319,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConf;
         }
 
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e721de9..c6a5152 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -967,12 +967,19 @@
         AnimationHandler animationHandler = AnimationHandler.getInstance();
         animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
 
-        if (mStartDelay == 0) {
+        if (mStartDelay == 0 || mSeekFraction >= 0) {
             // If there's no start delay, init the animation and notify start listeners right away
             // to be consistent with the previous behavior. Otherwise, postpone this until the first
             // frame after the start delay.
             startAnimation();
-            setCurrentFraction(mSeekFraction == -1 ? 0 : mSeekFraction);
+            if (mSeekFraction == -1) {
+                // No seek, start at play time 0. Note that the reason we are not using fraction 0
+                // is because for animations with 0 duration, we want to be consistent with pre-N
+                // behavior: skip to the final value immediately.
+                setCurrentPlayTime(0);
+            } else {
+                setCurrentFraction(mSeekFraction);
+            }
         }
     }
 
@@ -1029,8 +1036,16 @@
 
     @Override
     public void resume() {
-        if (mPaused) {
+        if (Looper.myLooper() == null) {
+            throw new AndroidRuntimeException("Animators may only be resumed from the same " +
+                    "thread that the animator was started on");
+        }
+        if (mPaused && !mResumed) {
             mResumed = true;
+            if (mPauseTime > 0) {
+                AnimationHandler handler = AnimationHandler.getInstance();
+                handler.addAnimationFrameCallback(this, 0);
+            }
         }
         super.resume();
     }
@@ -1235,9 +1250,8 @@
         }
         mLastFrameTime = frameTime;
         if (mPaused) {
-            if (mPauseTime < 0) {
-                mPauseTime = frameTime;
-            }
+            mPauseTime = frameTime;
+            handler.removeCallback(this);
             return;
         } else if (mResumed) {
             mResumed = false;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 332c739..0410a6e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -41,6 +41,7 @@
 import android.content.IntentSender;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
@@ -50,12 +51,8 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
+import android.hardware.input.InputManager;
 import android.media.AudioManager;
 import android.media.session.MediaController;
 import android.net.Uri;
@@ -68,6 +65,7 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
@@ -89,6 +87,8 @@
 import android.view.ContextThemeWrapper;
 import android.view.DragEvent;
 import android.view.DropPermissions;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
 import android.view.KeyboardShortcutInfo;
@@ -110,12 +110,12 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
+import android.widget.Toast;
 import android.widget.Toolbar;
 
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
 
 import java.io.FileDescriptor;
@@ -741,7 +741,7 @@
     Activity mParent;
     boolean mCalled;
     /*package*/ boolean mResumed;
-    private boolean mStopped;
+    /*package*/ boolean mStopped;
     boolean mFinished;
     boolean mStartedActivity;
     private boolean mDestroyed;
@@ -815,6 +815,9 @@
     private int mDefaultKeyMode = DEFAULT_KEYS_DISABLE;
     private SpannableStringBuilder mDefaultKeySsb = null;
 
+    private ActivityManager.TaskDescription mTaskDescription =
+            new ActivityManager.TaskDescription();
+
     protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
 
     @SuppressWarnings("unused")
@@ -829,6 +832,8 @@
     private boolean mHasCurrentPermissionsRequest;
     private boolean mEatKeyUpEvent;
 
+    private static native String getDlWarning();
+
     /** Return the intent that started this activity. */
     public Intent getIntent() {
         return mIntent;
@@ -1136,6 +1141,7 @@
             mTitleReady = true;
             onTitleChanged(getTitle(), getTitleColor());
         }
+
         mCalled = true;
     }
 
@@ -1237,7 +1243,7 @@
     protected void onResume() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
         getApplication().dispatchActivityResumed(this);
-        mActivityTransitionState.onResume();
+        mActivityTransitionState.onResume(this, isTopOfTask());
         mCalled = true;
     }
 
@@ -1670,10 +1676,16 @@
     }
 
     @Override
-    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+    public void onProvideKeyboardShortcuts(
+            List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
         if (menu == null) {
           return;
         }
+        final InputDevice inputDevice = InputManager.getInstance().getInputDevice(deviceId);
+        if (inputDevice == null) {
+            return;
+        }
+        final KeyCharacterMap keyCharacterMap = inputDevice.getKeyCharacterMap();
         KeyboardShortcutGroup group = null;
         int menuSize = menu.size();
         for (int i = 0; i < menuSize; ++i) {
@@ -1837,15 +1849,15 @@
      * visa-versa.
      * @see android.R.attr#resizeableActivity
      *
-     * @param inMultiWindow True if the activity is in multi-window mode.
+     * @param isInMultiWindowMode True if the activity is in multi-window mode.
      */
     @CallSuper
-    public void onMultiWindowChanged(boolean inMultiWindow) {
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG,
-                "onMultiWindowChanged " + this + ": " + inMultiWindow);
-        mFragments.dispatchMultiWindowChanged(inMultiWindow);
+                "onMultiWindowModeChanged " + this + ": " + isInMultiWindowMode);
+        mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode);
         if (mWindow != null) {
-            mWindow.onMultiWindowChanged();
+            mWindow.onMultiWindowModeChanged();
         }
     }
 
@@ -1855,9 +1867,9 @@
      *
      * @return True if the activity is in multi-window mode.
      */
-    public boolean inMultiWindow() {
+    public boolean isInMultiWindowMode() {
         try {
-            return ActivityManagerNative.getDefault().inMultiWindow(mToken);
+            return ActivityManagerNative.getDefault().isInMultiWindowMode(mToken);
         } catch (RemoteException e) {
         }
         return false;
@@ -1867,13 +1879,13 @@
      * Called by the system when the activity changes to and from picture-in-picture mode.
      * @see android.R.attr#supportsPictureInPicture
      *
-     * @param inPictureInPicture True if the activity is in picture-in-picture mode.
+     * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
      */
     @CallSuper
-    public void onPictureInPictureChanged(boolean inPictureInPicture) {
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG,
-                "onPictureInPictureChanged " + this + ": " + inPictureInPicture);
-        mFragments.dispatchPictureInPictureChanged(inPictureInPicture);
+                "onPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode);
+        mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
     }
 
     /**
@@ -1882,9 +1894,9 @@
      *
      * @return True if the activity is in picture-in-picture mode.
      */
-    public boolean inPictureInPicture() {
+    public boolean isInPictureInPictureMode() {
         try {
-            return ActivityManagerNative.getDefault().inPictureInPicture(mToken);
+            return ActivityManagerNative.getDefault().isInPictureInPictureMode(mToken);
         } catch (RemoteException e) {
         }
         return false;
@@ -1894,9 +1906,9 @@
      * Puts the activity in picture-in-picture mode.
      * @see android.R.attr#supportsPictureInPicture
      */
-    public void enterPictureInPicture() {
+    public void enterPictureInPictureMode() {
         try {
-            ActivityManagerNative.getDefault().enterPictureInPicture(mToken);
+            ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken);
         } catch (RemoteException e) {
         }
     }
@@ -1967,15 +1979,13 @@
      * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
      * function returns null.
      *
-     * @return Returns the object previously returned by
-     * {@link #onRetainNonConfigurationInstance()}.
-     *
-     * @deprecated Use the new {@link Fragment} API
+     * <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
      * {@link Fragment#setRetainInstance(boolean)} instead; this is also
-     * available on older platforms through the Android compatibility package.
+     * available on older platforms through the Android support libraries.
+     *
+     * @return the object previously returned by {@link #onRetainNonConfigurationInstance()}
      */
     @Nullable
-    @Deprecated
     public Object getLastNonConfigurationInstance() {
         return mLastNonConfigurationInstances != null
                 ? mLastNonConfigurationInstances.activity : null;
@@ -2026,12 +2036,12 @@
      * guarantee for {@link android.os.AsyncTask#doInBackground} since that is
      * running in a separate thread.)
      *
-     * @return Return any Object holding the desired state to propagate to the
-     * next activity instance.
-     *
-     * @deprecated Use the new {@link Fragment} API
+     * <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
      * {@link Fragment#setRetainInstance(boolean)} instead; this is also
-     * available on older platforms through the Android compatibility package.
+     * available on older platforms through the Android support libraries.
+     *
+     * @return any Object holding the desired state to propagate to the
+     *         next activity instance
      */
     public Object onRetainNonConfigurationInstance() {
         return null;
@@ -3977,55 +3987,25 @@
         }
 
         // Get the primary color and update the TaskDescription for this activity
-        if (theme != null) {
-            TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
-            int windowBgResourceId = a.getResourceId(
-                    com.android.internal.R.styleable.Window_windowBackground, 0);
-            int windowBgFallbackResourceId = a.getResourceId(
-                    com.android.internal.R.styleable.Window_windowBackgroundFallback, 0);
-            int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
-            int colorBg = tryExtractColorFromDrawable(DecorView.getResizingBackgroundDrawable(this,
-                    windowBgResourceId, windowBgFallbackResourceId));
-            a.recycle();
-            if (colorPrimary != 0) {
-                ActivityManager.TaskDescription td = new ActivityManager.TaskDescription();
-                if (Color.alpha(colorPrimary) == 0xFF) {
-                    td.setPrimaryColor(colorPrimary);
-                }
-                if (Color.alpha(colorBg) == 0xFF) {
-                    td.setBackgroundColor(colorBg);
-                }
-                setTaskDescription(td);
+        TypedArray a = theme.obtainStyledAttributes(
+                com.android.internal.R.styleable.ActivityTaskDescription);
+        if (mTaskDescription.getPrimaryColor() == 0) {
+            int colorPrimary = a.getColor(
+                    com.android.internal.R.styleable.ActivityTaskDescription_colorPrimary, 0);
+            if (colorPrimary != 0 && Color.alpha(colorPrimary) == 0xFF) {
+                mTaskDescription.setPrimaryColor(colorPrimary);
             }
         }
-    }
-
-    /**
-     * Attempts to extract the color from a given drawable.
-     *
-     * @return the extracted color or 0 if no color could be extracted.
-     */
-    private int tryExtractColorFromDrawable(Drawable drawable) {
-        if (drawable instanceof ColorDrawable) {
-            return ((ColorDrawable) drawable).getColor();
-        } else if (drawable instanceof InsetDrawable) {
-            return tryExtractColorFromDrawable(((InsetDrawable) drawable).getDrawable());
-        } else if (drawable instanceof ShapeDrawable) {
-            Paint p = ((ShapeDrawable) drawable).getPaint();
-            if (p != null) {
-                return p.getColor();
-            }
-        } else if (drawable instanceof LayerDrawable) {
-            LayerDrawable ld = (LayerDrawable) drawable;
-            int numLayers = ld.getNumberOfLayers();
-            for (int i = 0; i < numLayers; i++) {
-                int color = tryExtractColorFromDrawable(ld.getDrawable(i));
-                if (color != 0) {
-                    return color;
-                }
+        // For dev-preview only.
+        if (mTaskDescription.getBackgroundColor() == 0) {
+            int colorBackground = a.getColor(
+                    com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
+            if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
+                mTaskDescription.setBackgroundColor(colorBackground);
             }
         }
-        return 0;
+        a.recycle();
+        setTaskDescription(mTaskDescription);
     }
 
     /**
@@ -5651,18 +5631,18 @@
      * @param taskDescription The TaskDescription properties that describe the task with this activity
      */
     public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
-        ActivityManager.TaskDescription td;
-        // Scale the icon down to something reasonable if it is provided
-        if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
-            final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
-            final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true);
-            td = new ActivityManager.TaskDescription(taskDescription);
-            td.setIcon(icon);
-        } else {
-            td = taskDescription;
+        if (mTaskDescription != taskDescription) {
+            mTaskDescription.copyFrom(taskDescription);
+            // Scale the icon down to something reasonable if it is provided
+            if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
+                final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
+                final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size,
+                        true);
+                mTaskDescription.setIcon(icon);
+            }
         }
         try {
-            ActivityManagerNative.getDefault().setTaskDescription(mToken, td);
+            ActivityManagerNative.getDefault().setTaskDescription(mToken, mTaskDescription);
         } catch (RemoteException e) {
         }
     }
@@ -5934,6 +5914,9 @@
      * @return true if this is the topmost, non-finishing activity in its task.
      */
     private boolean isTopOfTask() {
+        if (mToken == null || mWindow == null || !mWindowAdded) {
+            return false;
+        }
         try {
             return ActivityManagerNative.getDefault().isTopOfTask(mToken);
         } catch (RemoteException e) {
@@ -6198,14 +6181,24 @@
     /**
      * Enable or disable virtual reality (VR) mode.
      *
-     * <p>VR mode is a hint to Android system services to switch to modes optimized for
-     * high-performance stereoscopic rendering.</p>
+     * <p>VR mode is a hint to Android system services to switch to a mode optimized for
+     * high-performance stereoscopic rendering.  This mode will be enabled while this Activity has
+     * focus.</p>
      *
      * @param enabled {@code true} to enable this mode.
+     * @param requestedComponent the name of the component to use as a
+     *        {@link android.service.vr.VrListenerService} while VR mode is enabled.
+     *
+     * @throws android.content.pm.PackageManager.NameNotFoundException;
      */
-    public void setVrMode(boolean enabled) {
+    public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent)
+          throws PackageManager.NameNotFoundException {
         try {
-            ActivityManagerNative.getDefault().setVrMode(mToken, enabled);
+            if (ActivityManagerNative.getDefault().setVrMode(mToken, enabled, requestedComponent)
+                    != 0) {
+                throw new PackageManager.NameNotFoundException(
+                        requestedComponent.flattenToString());
+            }
         } catch (RemoteException e) {
             // pass
         }
@@ -6611,6 +6604,32 @@
         }
         mFragments.dispatchStart();
         mFragments.reportLoaderStart();
+
+        // This property is set for all builds except final release
+        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
+        boolean isAppDebuggable =
+                (mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+        if (isAppDebuggable || isDlwarningEnabled) {
+            String dlwarning = getDlWarning();
+            if (dlwarning != null) {
+                String appName = getApplicationInfo().loadLabel(getPackageManager())
+                        .toString();
+                String warning = "Detected problems with app native libraries\n" +
+                                 "(please consult log for detail):\n" + dlwarning;
+                if (isAppDebuggable) {
+                      new AlertDialog.Builder(this).
+                          setTitle(appName).
+                          setMessage(warning).
+                          setPositiveButton(android.R.string.ok, null).
+                          setCancelable(false).
+                          show();
+                } else {
+                    Toast.makeText(this, appName + "\n" + warning, Toast.LENGTH_LONG).show();
+                }
+            }
+        }
+
         mActivityTransitionState.enterReady(this);
     }
 
@@ -6618,9 +6637,7 @@
         mFragments.noteStateNotSaved();
 
         if (mToken != null && mParent == null) {
-            // We might have view roots that were preserved during a relaunch, we need to start them
-            // again. We don't need to check mStopped, the roots will check if they were actually
-            // stopped.
+            // No need to check mStopped, the roots will check if they were actually stopped.
             WindowManagerGlobal.getInstance().setStoppedState(mToken, false /* stopped */);
         }
 
@@ -6718,7 +6735,7 @@
         onUserLeaveHint();
     }
 
-    final void performStop() {
+    final void performStop(boolean preserveWindow) {
         mDoReportFullyDrawn = false;
         mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
 
@@ -6727,7 +6744,10 @@
                 mWindow.closeAllPanels();
             }
 
-            if (mToken != null && mParent == null) {
+            // If we're preserving the window, don't setStoppedState to true, since we
+            // need the window started immediately again. Stopping the window will
+            // destroys hardware resources and causes flicker.
+            if (!preserveWindow && mToken != null && mParent == null) {
                 WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
             }
 
@@ -6889,14 +6909,25 @@
     }
 
     /**
+     * Check whether the caption on freeform windows is displayed directly on the content.
+     *
+     * @return True if caption is displayed on content, false if it pushes the content down.
+     *
+     * @see {@link #setOverlayWithDecorCaptionEnabled(boolean)}
+     */
+    public boolean isOverlayWithDecorCaptionEnabled() {
+        return mWindow.isOverlayWithDecorCaptionEnabled();
+    }
+
+    /**
      * Set whether the caption should displayed directly on the content rather than push it down.
      *
      * This affects only freeform windows since they display the caption and only the main
      * window of the activity. The caption is used to drag the window around and also shows
      * maximize and close action buttons.
      */
-    public void overlayWithDecorCaption(boolean overlay) {
-        mWindow.setOverlayDecorCaption(overlay);
+    public void setOverlayWithDecorCaptionEnabled(boolean enabled) {
+        mWindow.setOverlayWithDecorCaptionEnabled(enabled);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7771139..d1f5143 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Point;
@@ -30,7 +31,7 @@
 import android.os.ParcelFileDescriptor;
 
 import android.util.Log;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
 
@@ -376,6 +377,12 @@
     /** @hide Process is being cached for later use and is empty. */
     public static final int PROCESS_STATE_CACHED_EMPTY = 16;
 
+    /** @hide The lowest process state number */
+    public static final int MIN_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
+
+    /** @hide The highest process state number */
+    public static final int MAX_PROCESS_STATE = PROCESS_STATE_CACHED_EMPTY;
+
     /** @hide Should this process state be considered a background state? */
     public static final boolean isProcStateBackground(int procState) {
         return procState >= PROCESS_STATE_BACKUP;
@@ -577,6 +584,16 @@
         }
 
         /**
+         * Return whether a stackId is a stack containing floating windows. Floating windows
+         * are laid out differently as they are allowed to extend past the display bounds
+         * without overscan insets.
+         */
+        public static boolean tasksAreFloating(int stackId) {
+            return stackId == FREEFORM_WORKSPACE_STACK_ID
+                || stackId == PINNED_STACK_ID;
+        }
+
+        /**
          * Returns true if animation specs should be constructed for app transition that moves
          * the task to the specified stack.
          */
@@ -647,6 +664,16 @@
             return stackId != PINNED_STACK_ID && stackId != FREEFORM_WORKSPACE_STACK_ID
                     && stackId != DOCKED_STACK_ID;
         }
+
+        /**
+         * Returns true if the input stack id should only be present on a device that supports
+         * multi-window mode.
+         * @see android.app.ActivityManager#supportsMultiWindow
+         */
+        public static boolean isMultiWindowStack(int stackId) {
+            return isStaticStack(stackId) || stackId == PINNED_STACK_ID
+                    || stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
+        }
     }
 
     /**
@@ -716,8 +743,7 @@
         try {
             return ActivityManagerNative.getDefault().getFrontActivityScreenCompatMode();
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -726,7 +752,7 @@
         try {
             ActivityManagerNative.getDefault().setFrontActivityScreenCompatMode(mode);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -735,8 +761,7 @@
         try {
             return ActivityManagerNative.getDefault().getPackageScreenCompatMode(packageName);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -745,7 +770,7 @@
         try {
             ActivityManagerNative.getDefault().setPackageScreenCompatMode(packageName, mode);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -754,8 +779,7 @@
         try {
             return ActivityManagerNative.getDefault().getPackageAskScreenCompat(packageName);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -764,7 +788,7 @@
         try {
             ActivityManagerNative.getDefault().setPackageAskScreenCompat(packageName, ask);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -871,6 +895,17 @@
     }
 
     /**
+     * Returns true if the system supports at least one form of multi-window.
+     * E.g. freeform, split-screen, picture-in-picture.
+     * @hide
+     */
+    static public boolean supportsMultiWindow() {
+        return !isLowRamDeviceStatic()
+                && Resources.getSystem().getBoolean(
+                    com.android.internal.R.bool.config_supportsMultiWindow);
+    }
+
+    /**
      * Information you can set and retrieve about the current activity within the recent task list.
      */
     public static class TaskDescription implements Parcelable {
@@ -946,11 +981,19 @@
          * Creates a copy of another TaskDescription.
          */
         public TaskDescription(TaskDescription td) {
-            mLabel = td.mLabel;
-            mIcon = td.mIcon;
-            mIconFilename = td.mIconFilename;
-            mColorPrimary = td.mColorPrimary;
-            mColorBackground = td.mColorBackground;
+            copyFrom(td);
+        }
+
+        /**
+         * Copies this the values from another TaskDescription.
+         * @hide
+         */
+        public void copyFrom(TaskDescription other) {
+            mLabel = other.mLabel;
+            mIcon = other.mIcon;
+            mIconFilename = other.mIconFilename;
+            mColorPrimary = other.mColorPrimary;
+            mColorBackground = other.mColorBackground;
         }
 
         private TaskDescription(Parcel source) {
@@ -1041,6 +1084,7 @@
                     return ActivityManagerNative.getDefault().getTaskDescriptionIcon(iconFilename,
                             userId);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return null;
@@ -1372,10 +1416,10 @@
     public static final int RECENT_IGNORE_HOME_STACK_TASKS = 0x0008;
 
     /**
-     * Ignores all tasks that are on the docked stack.
+     * Ignores the top task in the docked stack.
      * @hide
      */
-    public static final int RECENT_INGORE_DOCKED_STACK_TASKS = 0x0010;
+    public static final int RECENT_INGORE_DOCKED_STACK_TOP_TASK = 0x0010;
 
     /**
      * Ignores all tasks that are on the pinned stack.
@@ -1421,8 +1465,7 @@
             return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
                     flags, UserHandle.myUserId());
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1447,8 +1490,7 @@
             return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
                     flags, userId);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1540,6 +1582,7 @@
                     Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
             dest.writeInt(numActivities);
             dest.writeInt(numRunning);
+            dest.writeInt(isDockable ? 1 : 0);
         }
 
         public void readFromParcel(Parcel source) {
@@ -1555,6 +1598,7 @@
             description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
             numActivities = source.readInt();
             numRunning = source.readInt();
+            isDockable = source.readInt() != 0;
         }
 
         public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() {
@@ -1583,8 +1627,7 @@
         try {
             appTasks = ActivityManagerNative.getDefault().getAppTasks(mContext.getPackageName());
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
         int numAppTasks = appTasks.size();
         for (int i = 0; i < numAppTasks; i++) {
@@ -1609,7 +1652,7 @@
             try {
                 mAppTaskThumbnailSize = ActivityManagerNative.getDefault().getAppTaskThumbnailSize();
             } catch (RemoteException e) {
-                throw new IllegalStateException("System dead?", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1675,7 +1718,7 @@
             return ActivityManagerNative.getDefault().addAppTask(activity.getActivityToken(),
                     intent, description, thumbnail);
         } catch (RemoteException e) {
-            throw new IllegalStateException("System dead?", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1717,8 +1760,7 @@
         try {
             return ActivityManagerNative.getDefault().getTasks(maxNum, 0);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1734,8 +1776,7 @@
         try {
             return ActivityManagerNative.getDefault().removeTask(taskId);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1756,7 +1797,7 @@
 
         public int taskWidth;
         public int taskHeight;
-        public int screenOrientation;
+        public int screenOrientation = Configuration.ORIENTATION_UNDEFINED;
 
         public TaskThumbnailInfo() {
             // Do nothing
@@ -1773,7 +1814,16 @@
         public void reset() {
             taskWidth = 0;
             taskHeight = 0;
-            screenOrientation = 0;
+            screenOrientation = Configuration.ORIENTATION_UNDEFINED;
+        }
+
+        /**
+         * Copies from another ThumbnailInfo.
+         */
+        public void copyFrom(TaskThumbnailInfo o) {
+            taskWidth = o.taskWidth;
+            taskHeight = o.taskHeight;
+            screenOrientation = o.screenOrientation;
         }
 
         /** @hide */
@@ -1894,8 +1944,7 @@
         try {
             return ActivityManagerNative.getDefault().getTaskThumbnail(id);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1904,8 +1953,7 @@
         try {
             return ActivityManagerNative.getDefault().isInHomeStack(taskId);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1954,7 +2002,7 @@
         try {
             ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags, options);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2140,8 +2188,7 @@
             return ActivityManagerNative.getDefault()
                     .getServices(maxNum, 0);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2156,8 +2203,7 @@
             return ActivityManagerNative.getDefault()
                     .getRunningServiceControlPanel(service);
         } catch (RemoteException e) {
-            // System dead, we will be dead too soon!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2261,6 +2307,7 @@
         try {
             ActivityManagerNative.getDefault().getMemoryInfo(outInfo);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2379,7 +2426,7 @@
             return ActivityManagerNative.getDefault().clearApplicationUserData(packageName,
                     observer, UserHandle.myUserId());
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2413,8 +2460,7 @@
             return ActivityManagerNative.getDefault().getGrantedUriPermissions(packageName,
                     UserHandle.myUserId());
         } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't get granted URI permissions for :" + packageName, e);
-            return ParceledListSlice.emptyList();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2432,7 +2478,7 @@
             ActivityManagerNative.getDefault().clearGrantedUriPermissions(packageName,
                     UserHandle.myUserId());
         } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't clear granted URI permissions for :" + packageName, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2552,7 +2598,7 @@
         try {
             return ActivityManagerNative.getDefault().getProcessesInErrorState();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2866,7 +2912,7 @@
         try {
             return ActivityManagerNative.getDefault().getRunningExternalApplications();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2883,7 +2929,7 @@
             return ActivityManagerNative.getDefault().setProcessMemoryTrimLevel(process, userId,
                     level);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2901,7 +2947,7 @@
         try {
             return ActivityManagerNative.getDefault().getRunningAppProcesses();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2920,7 +2966,7 @@
                     mContext.getOpPackageName());
             return RunningAppProcessInfo.procStateToImportance(procState);
         } catch (RemoteException e) {
-            return RunningAppProcessInfo.IMPORTANCE_GONE;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2939,6 +2985,7 @@
         try {
             ActivityManagerNative.getDefault().getMyMemoryState(outState);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2957,7 +3004,7 @@
         try {
             return ActivityManagerNative.getDefault().getProcessMemoryInfo(pids);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2991,6 +3038,7 @@
             ActivityManagerNative.getDefault().killBackgroundProcesses(packageName,
                     UserHandle.myUserId());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3007,7 +3055,7 @@
             ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
                     UserHandle.getUserId(uid), reason);
         } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't kill uid:" + uid, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3034,6 +3082,7 @@
         try {
             ActivityManagerNative.getDefault().forceStopPackage(packageName, userId);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3052,8 +3101,8 @@
         try {
             return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -3142,8 +3191,8 @@
         try {
             return ActivityManagerNative.getDefault().isUserAMonkey();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -3218,10 +3267,8 @@
             return AppGlobals.getPackageManager()
                     .checkUidPermission(permission, uid);
         } catch (RemoteException e) {
-            // Should never happen, but if it does... deny!
-            Slog.e(TAG, "PackageManager is dead?!?", e);
+            throw e.rethrowFromSystemServer();
         }
-        return PackageManager.PERMISSION_DENIED;
     }
 
     /** @hide */
@@ -3230,10 +3277,8 @@
             return AppGlobals.getPackageManager()
                     .checkUidPermission(permission, uid);
         } catch (RemoteException e) {
-            // Should never happen, but if it does... deny!
-            Slog.e(TAG, "PackageManager is dead?!?", e);
+            throw e.rethrowFromSystemServer();
         }
-        return PackageManager.PERMISSION_DENIED;
     }
 
     /**
@@ -3269,7 +3314,7 @@
             return ActivityManagerNative.getDefault().handleIncomingUser(callingPid,
                     callingUid, userId, allowAll, requireFull, name, callerPackage);
         } catch (RemoteException e) {
-            throw new SecurityException("Failed calling activity manager", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3284,7 +3329,7 @@
             ui = ActivityManagerNative.getDefault().getCurrentUser();
             return ui != null ? ui.id : 0;
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3296,7 +3341,24 @@
         try {
             return ActivityManagerNative.getDefault().switchUser(userid);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Logs out current current foreground user by switching to the system user and stopping the
+     * user being switched from.
+     * @hide
+     */
+    public static void logoutCurrentUser() {
+        int currentUser = ActivityManager.getCurrentUser();
+        if (currentUser != UserHandle.USER_SYSTEM) {
+            try {
+                ActivityManagerNative.getDefault().switchUser(UserHandle.USER_SYSTEM);
+                ActivityManagerNative.getDefault().stopUser(currentUser, /* force= */ false, null);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
         }
     }
 
@@ -3320,7 +3382,7 @@
         try {
             return ActivityManagerNative.getDefault().isUserRunning(userId, 0);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3330,7 +3392,7 @@
             return ActivityManagerNative.getDefault().isUserRunning(userId,
                     ActivityManager.FLAG_AND_LOCKED);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3340,7 +3402,16 @@
             return ActivityManagerNative.getDefault().isUserRunning(userId,
                     ActivityManager.FLAG_AND_UNLOCKED);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** {@hide} */
+    public boolean isVrModePackageEnabled(ComponentName component) {
+        try {
+            return ActivityManagerNative.getDefault().isVrModePackageEnabled(component);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3425,6 +3496,7 @@
             ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, pssSize,
                     mContext.getPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3443,6 +3515,7 @@
         try {
             ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, 0, null);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3453,6 +3526,7 @@
         try {
             ActivityManagerNative.getDefault().startLockTaskMode(taskId);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3463,6 +3537,7 @@
         try {
             ActivityManagerNative.getDefault().stopLockTaskMode();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3489,7 +3564,7 @@
         try {
             return ActivityManagerNative.getDefault().getLockTaskModeState();
         } catch (RemoteException e) {
-            return ActivityManager.LOCK_TASK_MODE_NONE;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3512,7 +3587,7 @@
             try {
                 mAppTaskImpl.finishAndRemoveTask();
             } catch (RemoteException e) {
-                Slog.e(TAG, "Invalid AppTask", e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -3525,8 +3600,7 @@
             try {
                 return mAppTaskImpl.getTaskInfo();
             } catch (RemoteException e) {
-                Slog.e(TAG, "Invalid AppTask", e);
-                return null;
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -3540,7 +3614,7 @@
             try {
                 mAppTaskImpl.moveToFront();
             } catch (RemoteException e) {
-                Slog.e(TAG, "Invalid AppTask", e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -3582,7 +3656,7 @@
             try {
                 mAppTaskImpl.setExcludeFromRecents(exclude);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Invalid AppTask", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 4fa654f..5116634 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -29,6 +29,31 @@
  * @hide Only for use within the system server.
  */
 public abstract class ActivityManagerInternal {
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because we had
+     * the surface saved.
+     */
+    public static final int APP_TRANSITION_SAVED_SURFACE = 0;
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because we drew
+     * the starting window.
+     */
+    public static final int APP_TRANSITION_STARTING_WINDOW = 1;
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because we all
+     * app windows were drawn
+     */
+    public static final int APP_TRANSITION_WINDOWS_DRAWN = 2;
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because of a
+     * timeout.
+     */
+    public static final int APP_TRANSITION_TIMEOUT = 3;
+
     // Called by the power manager.
     public abstract void onWakefulnessChanged(int wakefulness);
 
@@ -48,6 +73,7 @@
      * with underlying activities.
      */
     public static abstract class SleepToken {
+
         /**
          * Releases the sleep token.
          */
@@ -56,6 +82,7 @@
 
     /**
      * Returns home activity for the specified user.
+     *
      * @param userId ID of the user or {@link android.os.UserHandle#USER_ALL}
      */
     public abstract ComponentName getHomeActivityForUser(int userId);
@@ -72,4 +99,30 @@
     public abstract void onLocalVoiceInteractionStarted(IBinder callingActivity,
             IVoiceInteractionSession mSession,
             IVoiceInteractor mInteractor);
+
+    /**
+     * Callback for window manager to let activity manager know that the starting window has been
+     * drawn
+     */
+    public abstract void notifyStartingWindowDrawn();
+
+    /**
+     * Callback for window manager to let activity manager know that we are finally starting the
+     * app transition;
+     *
+     * @param reason The reason why the app transition started. Must be one of the APP_TRANSITION_*
+     *               values.
+     */
+    public abstract void notifyAppTransitionStarting(int reason);
+
+    /**
+     * Callback for window manager to let activity manager know that the app transition was
+     * cancelled.
+     */
+    public abstract void notifyAppTransitionCancelled();
+
+    /**
+     * Callback for window manager to let activity manager know that the app transition is finished.
+     */
+    public abstract void notifyAppTransitionFinished();
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index bb36a3e..65d48e6 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.UserIdInt;
 import android.app.ActivityManager.StackInfo;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
@@ -40,6 +41,7 @@
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
+import android.os.IProgressListener;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -93,7 +95,7 @@
         }
         return sSystemReady;
     }
-    static boolean sSystemReady = false;
+    static volatile boolean sSystemReady = false;
 
     static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
         broadcastStickyIntent(intent, permission, AppOpsManager.OP_NONE, userId);
@@ -792,8 +794,9 @@
             if (hasBounds) {
                 bounds = Rect.CREATOR.createFromParcel(data);
             }
-            moveTaskToDockedStack(taskId, createMode, toTop, animate, bounds);
+            boolean res = moveTaskToDockedStack(taskId, createMode, toTop, animate, bounds);
             reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
             return true;
         }
 
@@ -818,11 +821,33 @@
             final boolean allowResizeInDockedMode = data.readInt() == 1;
             final boolean preserveWindows = data.readInt() == 1;
             final boolean animate = data.readInt() == 1;
-            resizeStack(stackId, r, allowResizeInDockedMode, preserveWindows, animate);
+            final int animationDuration = data.readInt();
+            resizeStack(stackId,
+                    r, allowResizeInDockedMode, preserveWindows, animate, animationDuration);
             reply.writeNoException();
             return true;
         }
-
+        case RESIZE_PINNED_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final boolean hasBounds = data.readInt() != 0;
+            Rect bounds = null;
+            if (hasBounds) {
+                bounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempPinnedTaskBounds = data.readInt() != 0;
+            Rect tempPinnedTaskBounds = null;
+            if (hasTempPinnedTaskBounds) {
+                tempPinnedTaskBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            resizePinnedStack(bounds, tempPinnedTaskBounds);
+            return true;
+        }
+        case SWAP_DOCKED_AND_FULLSCREEN_STACK: {
+            data.enforceInterface(IActivityManager.descriptor);
+            swapDockedAndFullscreenStack();
+            reply.writeNoException();
+            return true;
+        }
         case RESIZE_DOCKED_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final boolean hasBounds = data.readInt() != 0;
@@ -1527,7 +1552,8 @@
             data.enforceInterface(IActivityManager.descriptor);
             IActivityController watcher = IActivityController.Stub.asInterface(
                     data.readStrongBinder());
-            setActivityController(watcher);
+            boolean imAMonkey = data.readInt() != 0;
+            setActivityController(watcher, imAMonkey);
             reply.writeNoException();
             return true;
         }
@@ -1540,6 +1566,14 @@
             return true;
         }
 
+        case GET_MEMORY_TRIM_LEVEL_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int level = getMemoryTrimLevel();
+            reply.writeNoException();
+            reply.writeInt(level);
+            return true;
+        }
+
         case ENTER_SAFE_MODE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             enterSafeMode();
@@ -2089,7 +2123,9 @@
             int userId = data.readInt();
             byte[] token = data.createByteArray();
             byte[] secret = data.createByteArray();
-            boolean result = unlockUser(userId, token, secret);
+            IProgressListener listener = IProgressListener.Stub
+                    .asInterface(data.readStrongBinder());
+            boolean result = unlockUser(userId, token, secret, listener);
             reply.writeNoException();
             reply.writeInt(result ? 1 : 0);
             return true;
@@ -2277,7 +2313,7 @@
 
         case KEYGUARD_GOING_AWAY_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            keyguardGoingAway(data.readInt() != 0, data.readInt() != 0);
+            keyguardGoingAway(data.readInt());
             reply.writeNoException();
             return true;
         }
@@ -2854,7 +2890,7 @@
         case IN_MULTI_WINDOW_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final IBinder token = data.readStrongBinder();
-            final boolean inMultiWindow = inMultiWindow(token);
+            final boolean inMultiWindow = isInMultiWindowMode(token);
             reply.writeNoException();
             reply.writeInt(inMultiWindow ? 1 : 0);
             return true;
@@ -2862,7 +2898,7 @@
         case IN_PICTURE_IN_PICTURE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final IBinder token = data.readStrongBinder();
-            final boolean inPip = inPictureInPicture(token);
+            final boolean inPip = isInPictureInPictureMode(token);
             reply.writeNoException();
             reply.writeInt(inPip ? 1 : 0);
             return true;
@@ -2870,7 +2906,7 @@
         case ENTER_PICTURE_IN_PICTURE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final IBinder token = data.readStrongBinder();
-            enterPictureInPicture(token);
+            enterPictureInPictureMode(token);
             reply.writeNoException();
             return true;
         }
@@ -2878,8 +2914,18 @@
             data.enforceInterface(IActivityManager.descriptor);
             final IBinder token = data.readStrongBinder();
             final boolean enable = data.readInt() == 1;
-            setVrMode(token, enable);
+            final ComponentName packageName = ComponentName.CREATOR.createFromParcel(data);
+            int res = setVrMode(token, enable, packageName);
             reply.writeNoException();
+            reply.writeInt(res);
+            return true;
+        }
+        case IS_VR_PACKAGE_ENABLED_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final ComponentName packageName = ComponentName.CREATOR.createFromParcel(data);
+            boolean res = isVrModePackageEnabled(packageName);
+            reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
             return true;
         }
         case IS_APP_FOREGROUND_TRANSACTION: {
@@ -2902,6 +2948,13 @@
             reply.writeNoException();
             return true;
         }
+        case NOTIFY_LOCKED_PROFILE: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final int userId = data.readInt();
+            notifyLockedProfile(userId);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3800,7 +3853,7 @@
         reply.recycle();
     }
     @Override
-    public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -3818,8 +3871,10 @@
         }
         mRemote.transact(MOVE_TASK_TO_DOCKED_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
+        boolean res = reply.readInt() > 0;
         data.recycle();
         reply.recycle();
+        return res;
     }
     @Override
     public boolean moveTopActivityToPinnedStack(int stackId, Rect r)
@@ -3839,7 +3894,8 @@
     }
     @Override
     public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode,
-            boolean preserveWindows, boolean animate) throws RemoteException {
+            boolean preserveWindows, boolean animate, int animationDuration)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3853,12 +3909,24 @@
         data.writeInt(allowResizeInDockedMode ? 1 : 0);
         data.writeInt(preserveWindows ? 1 : 0);
         data.writeInt(animate ? 1 : 0);
+        data.writeInt(animationDuration);
         mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
     @Override
+    public void swapDockedAndFullscreenStack() throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(SWAP_DOCKED_AND_FULLSCREEN_STACK, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    @Override
     public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
             Rect tempDockedTaskInsetBounds,
             Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds)
@@ -3902,6 +3970,31 @@
         data.recycle();
         reply.recycle();
     }
+
+    @Override
+    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        if (pinnedBounds != null) {
+            data.writeInt(1);
+            pinnedBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempPinnedTaskBounds != null) {
+            data.writeInt(1);
+            tempPinnedTaskBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        mRemote.transact(RESIZE_PINNED_STACK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     @Override
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
     {
@@ -4852,12 +4945,14 @@
         data.recycle();
         reply.recycle();
     }
-    public void setActivityController(IActivityController watcher) throws RemoteException
+    public void setActivityController(IActivityController watcher, boolean imAMonkey)
+            throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
+        data.writeInt(imAMonkey ? 1 : 0);
         mRemote.transact(SET_ACTIVITY_CONTROLLER_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -4874,6 +4969,18 @@
         data.recycle();
         reply.recycle();
     }
+    public int getMemoryTrimLevel() throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_MEMORY_TRIM_LEVEL_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int level = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return level;
+    }
     public void enterSafeMode() throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -5603,13 +5710,15 @@
         return result;
     }
 
-    public boolean unlockUser(int userId, byte[] token, byte[] secret) throws RemoteException {
+    public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(userId);
         data.writeByteArray(token);
         data.writeByteArray(secret);
+        data.writeStrongInterface(listener);
         mRemote.transact(IActivityManager.UNLOCK_USER_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean result = reply.readInt() != 0;
@@ -5832,13 +5941,12 @@
         reply.recycle();
     }
 
-    public void keyguardGoingAway(boolean disableWindowAnimations,
-            boolean keyguardGoingToNotificationShade) throws RemoteException {
+    public void keyguardGoingAway(int flags)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(disableWindowAnimations ? 1 : 0);
-        data.writeInt(keyguardGoingToNotificationShade ? 1 : 0);
+        data.writeInt(flags);
         mRemote.transact(KEYGUARD_GOING_AWAY_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -6182,16 +6290,34 @@
         return res;
     }
 
-    public void setVrMode(IBinder token, boolean enabled) throws RemoteException {
+    public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         data.writeInt(enabled ? 1 : 0);
+        packageName.writeToParcel(data, 0);
         mRemote.transact(SET_VR_MODE_TRANSACTION, data, reply, 0);
         reply.readException();
+        int res = reply.readInt();
         data.recycle();
         reply.recycle();
+        return res;
+    }
+
+    public boolean isVrModePackageEnabled(ComponentName packageName)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        packageName.writeToParcel(data, 0);
+        mRemote.transact(IS_VR_PACKAGE_ENABLED_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int res = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return res == 1;
     }
 
     @Override
@@ -6711,7 +6837,7 @@
     }
 
     @Override
-    public boolean inMultiWindow(IBinder token) throws RemoteException {
+    public boolean isInMultiWindowMode(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6725,7 +6851,7 @@
     }
 
     @Override
-    public boolean inPictureInPicture(IBinder token) throws RemoteException {
+    public boolean isInPictureInPictureMode(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6739,7 +6865,7 @@
     }
 
     @Override
-    public void enterPictureInPicture(IBinder token) throws RemoteException {
+    public void enterPictureInPictureMode(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6785,5 +6911,17 @@
         reply.recycle();
     }
 
+    public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(userId);
+        mRemote.transact(NOTIFY_LOCKED_PROFILE, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 094950b..2846798 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -154,6 +154,12 @@
     private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
 
     /**
+     * The task id the activity should be launched into.
+     * @hide
+     */
+    private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId";
+
+    /**
      * Where the docked stack should be positioned.
      * @hide
      */
@@ -224,6 +230,7 @@
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
     private int mLaunchStackId = INVALID_STACK_ID;
+    private int mLaunchTaskId = -1;
     private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
     private AppTransitionAnimationSpec mAnimSpecs[];
 
@@ -621,6 +628,7 @@
      * @see android.transition.Transition#setEpicenterCallback(
      *          android.transition.Transition.EpicenterCallback)
      */
+    @SafeVarargs
     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
             Pair<View, String>... sharedElements) {
         ActivityOptions opts = new ActivityOptions();
@@ -710,6 +718,10 @@
 
     /** @hide */
     public ActivityOptions(Bundle opts) {
+        // If the remote side sent us bad parcelables, they won't get the
+        // results they want, which is their loss.
+        opts.setDefusable(true);
+
         mPackageName = opts.getString(KEY_PACKAGE_NAME);
         try {
             mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT);
@@ -761,6 +773,7 @@
                 break;
         }
         mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
+        mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
         mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
         if (opts.containsKey(KEY_ANIM_SPECS)) {
             Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
@@ -777,15 +790,16 @@
 
     /**
      * Sets the bounds (window size) that the activity should be launched in.
+     * Rect position should be provided in pixels and in screen coordinates.
      * Set to null explicitly for fullscreen.
      * <p>
      * <strong>NOTE:<strong/> This value is ignored on devices that don't have
      * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
      * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
-     * @param launchBounds Launch bounds to use for the activity or null for fullscreen.
+     * @param screenSpacePixelRect Launch bounds to use for the activity or null for fullscreen.
      */
-    public ActivityOptions setLaunchBounds(@Nullable Rect launchBounds) {
-        mLaunchBounds = launchBounds != null ? new Rect(launchBounds) : null;
+    public ActivityOptions setLaunchBounds(@Nullable Rect screenSpacePixelRect) {
+        mLaunchBounds = screenSpacePixelRect != null ? new Rect(screenSpacePixelRect) : null;
         return this;
     }
 
@@ -921,6 +935,21 @@
         mLaunchStackId = launchStackId;
     }
 
+    /**
+     * Sets the task the activity will be launched in.
+     * @hide
+     */
+    public void setLaunchTaskId(int taskId) {
+        mLaunchTaskId = taskId;
+    }
+
+    /**
+     * @hide
+     */
+    public int getLaunchTaskId() {
+        return mLaunchTaskId;
+    }
+
     /** @hide */
     public int getDockCreateMode() {
         return mDockCreateMode;
@@ -1073,6 +1102,7 @@
                 break;
         }
         b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
+        b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
         b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
         if (mAnimSpecs != null) {
             b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 02b94de..14c4fc6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -75,6 +75,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.security.NetworkSecurityPolicy;
@@ -90,6 +91,7 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.SuperNotCalledException;
+import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.ThreadedRenderer;
 import android.view.View;
@@ -112,6 +114,7 @@
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.org.conscrypt.OpenSSLSocketImpl;
 import com.android.org.conscrypt.TrustedCertificateStore;
@@ -174,6 +177,7 @@
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
     private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
     private static final int LOG_AM_ON_RESUME_CALLED = 30022;
+    private static final int LOG_AM_ON_STOP_CALLED = 30049;
 
     /** Type for IActivityManager.serviceDoneExecuting: anonymous operation */
     public static final int SERVICE_DONE_EXECUTING_ANON = 0;
@@ -191,7 +195,7 @@
 
     private ContextImpl mSystemContext;
 
-    static IPackageManager sPackageManager;
+    static volatile IPackageManager sPackageManager;
 
     final ApplicationThread mAppThread = new ApplicationThread();
     final Looper mLooper = Looper.myLooper();
@@ -216,7 +220,7 @@
     // set of instantiated backup agents, keyed by package name
     final ArrayMap<String, BackupAgent> mBackupAgents = new ArrayMap<String, BackupAgent>();
     /** Reference to singleton {@link ActivityThread} */
-    private static ActivityThread sCurrentActivityThread;
+    private static volatile ActivityThread sCurrentActivityThread;
     Instrumentation mInstrumentation;
     String mInstrumentationPackageName = null;
     String mInstrumentationAppDir = null;
@@ -294,7 +298,7 @@
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
 
-    static Handler sMainThreadHandler;  // set once in main()
+    static volatile Handler sMainThreadHandler;  // set once in main()
 
     Bundle mCoreSettings = null;
 
@@ -376,6 +380,33 @@
                         ? "no component name" : componentName.toShortString())
                 + "}";
         }
+
+        public String getStateString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("ActivityClientRecord{");
+            sb.append("paused=").append(paused);
+            sb.append(", stopped=").append(stopped);
+            sb.append(", hideForNow=").append(hideForNow);
+            sb.append(", startsNotResumed=").append(startsNotResumed);
+            sb.append(", isForward=").append(isForward);
+            sb.append(", pendingConfigChanges=").append(pendingConfigChanges);
+            sb.append(", onlyLocalRequest=").append(onlyLocalRequest);
+            sb.append(", preserveWindow=").append(mPreserveWindow);
+            if (activity != null) {
+                sb.append(", Activity{");
+                sb.append("resumed=").append(activity.mResumed);
+                sb.append(", stopped=").append(activity.mStopped);
+                sb.append(", finished=").append(activity.isFinishing());
+                sb.append(", destroyed=").append(activity.isDestroyed());
+                sb.append(", startedActivity=").append(activity.mStartedActivity);
+                sb.append(", temporaryPause=").append(activity.mTemporaryPause);
+                sb.append(", changingConfigurations=").append(activity.mChangingConfigurations);
+                sb.append(", visibleBehind=").append(activity.mVisibleBehind);
+                sb.append("}");
+            }
+            sb.append("}");
+            return sb.toString();
+        }
     }
 
     final class ProviderClientRecord {
@@ -977,18 +1008,19 @@
 
         @Override
         public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
-                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) {
+                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
+                boolean dumpUnreachable, String[] args) {
             FileOutputStream fout = new FileOutputStream(fd);
             PrintWriter pw = new FastPrintWriter(fout);
             try {
-                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly);
+                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly, dumpUnreachable);
             } finally {
                 pw.flush();
             }
         }
 
         private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
-                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly) {
+                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
             long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
             long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -1102,6 +1134,16 @@
                 pw.println(" Asset Allocations");
                 pw.print(assetAlloc);
             }
+
+            // Unreachable native memory
+            if (dumpUnreachable) {
+                boolean showContents = ((mBoundApplication != null)
+                    && ((mBoundApplication.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0))
+                    || android.os.Build.IS_DEBUGGABLE;
+                pw.println(" ");
+                pw.println(" Unreachable memory");
+                pw.print(Debug.getUnreachableMemory(100, showContents));
+            }
         }
 
         @Override
@@ -1243,15 +1285,15 @@
         }
 
         @Override
-        public void scheduleMultiWindowChanged(IBinder token, boolean inMultiWindow)
+        public void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode)
                 throws RemoteException {
-            sendMessage(H.MULTI_WINDOW_CHANGED, token, inMultiWindow ? 1 : 0);
+            sendMessage(H.MULTI_WINDOW_MODE_CHANGED, token, isInMultiWindowMode ? 1 : 0);
         }
 
         @Override
-        public void schedulePictureInPictureChanged(IBinder token, boolean inPip)
+        public void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode)
                 throws RemoteException {
-            sendMessage(H.PICTURE_IN_PICTURE_CHANGED, token, inPip ? 1 : 0);
+            sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, token, isInPipMode ? 1 : 0);
         }
 
         @Override
@@ -1323,8 +1365,8 @@
         public static final int ENTER_ANIMATION_COMPLETE = 149;
         public static final int START_BINDER_TRACKING = 150;
         public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
-        public static final int MULTI_WINDOW_CHANGED = 152;
-        public static final int PICTURE_IN_PICTURE_CHANGED = 153;
+        public static final int MULTI_WINDOW_MODE_CHANGED = 152;
+        public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
         public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
 
         String codeToString(int code) {
@@ -1379,8 +1421,8 @@
                     case CANCEL_VISIBLE_BEHIND: return "CANCEL_VISIBLE_BEHIND";
                     case BACKGROUND_VISIBLE_BEHIND_CHANGED: return "BACKGROUND_VISIBLE_BEHIND_CHANGED";
                     case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
-                    case MULTI_WINDOW_CHANGED: return "MULTI_WINDOW_CHANGED";
-                    case PICTURE_IN_PICTURE_CHANGED: return "PICTURE_IN_PICTURE_CHANGED";
+                    case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
+                    case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
                     case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
                 }
             }
@@ -1395,7 +1437,7 @@
 
                     r.packageInfo = getPackageInfoNoCheck(
                             r.activityInfo.applicationInfo, r.compatInfo);
-                    handleLaunchActivity(r, null);
+                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                 } break;
                 case RELAUNCH_ACTIVITY: {
@@ -1446,7 +1488,7 @@
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
                     SomeArgs args = (SomeArgs) msg.obj;
                     handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true,
-                            args.argi3);
+                            args.argi3, "RESUME_ACTIVITY");
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case SEND_RESULT:
@@ -1625,11 +1667,11 @@
                 case STOP_BINDER_TRACKING_AND_DUMP:
                     handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
                     break;
-                case MULTI_WINDOW_CHANGED:
-                    handleMultiWindowChanged((IBinder) msg.obj, msg.arg1 == 1);
+                case MULTI_WINDOW_MODE_CHANGED:
+                    handleMultiWindowModeChanged((IBinder) msg.obj, msg.arg1 == 1);
                     break;
-                case PICTURE_IN_PICTURE_CHANGED:
-                    handlePictureInPictureChanged((IBinder) msg.obj, msg.arg1 == 1);
+                case PICTURE_IN_PICTURE_MODE_CHANGED:
+                    handlePictureInPictureModeChanged((IBinder) msg.obj, msg.arg1 == 1);
                     break;
                 case LOCAL_VOICE_INTERACTION_STARTED:
                     handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
@@ -1693,7 +1735,7 @@
                             am.activityIdle(a.token, a.createdConfig, stopProfiling);
                             a.createdConfig = null;
                         } catch (RemoteException ex) {
-                            // Ignore
+                            throw ex.rethrowFromSystemServer();
                         }
                     }
                     prev = a;
@@ -1775,14 +1817,13 @@
     }
 
     /**
-     * Creates the top level resources for the given package.
+     * Creates the top level resources for the given package. Will return an existing
+     * Resources if one has already been created.
      */
     Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
-            String[] libDirs, int displayId, Configuration overrideConfiguration,
-            LoadedApk pkgInfo) {
-        return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
-                displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo(),
-                pkgInfo.getClassLoader());
+            String[] libDirs, int displayId, LoadedApk pkgInfo) {
+        return mResourcesManager.getResources(null, resDir, splitResDirs, overlayDirs, libDirs,
+                displayId, null, pkgInfo.getCompatibilityInfo(), pkgInfo.getClassLoader());
     }
 
     final Handler getHandler() {
@@ -1833,7 +1874,7 @@
                             | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                     userId);
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
 
         if (ai != null) {
@@ -2241,8 +2282,8 @@
                         memInfo.getTotalSwappablePss(),
                         memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
                         memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
-                        memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOut() :
-                        memInfo.getTotalSwappedOutPss(),
+                        memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() :
+                        memInfo.getTotalSwappedOut(),
                         nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
                         nativeFree+dalvikFree);
             } else {
@@ -2592,10 +2633,11 @@
         try {
             displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
 
         ContextImpl appContext = ContextImpl.createActivityContext(
-                this, r.packageInfo, displayId, r.overrideConfig);
+                this, r.packageInfo, r.token, displayId, r.overrideConfig);
         appContext.setOuterContext(activity);
         Context baseContext = appContext;
 
@@ -2618,7 +2660,7 @@
         return baseContext;
     }
 
-    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
+    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
         unscheduleGcIdler();
@@ -2645,7 +2687,7 @@
             reportSizeConfigurations(r);
             Bundle oldState = r.state;
             handleResumeActivity(r.token, false, r.isForward,
-                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq);
+                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
 
             if (!r.activity.mFinished && r.startsNotResumed) {
                 // The activity manager actually wants this one to start out
@@ -2660,6 +2702,8 @@
                 try {
                     r.activity.mCalled = false;
                     mInstrumentation.callActivityOnPause(r.activity);
+                    EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
+                            r.activity.getComponentName().getClassName(), reason);
                     // We need to keep around the original state, in case
                     // we need to be created again.  But we only do this
                     // for pre-Honeycomb apps, which always save their state
@@ -2697,7 +2741,7 @@
                     .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                             Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
             } catch (RemoteException ex) {
-                // Ignore
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -2726,6 +2770,7 @@
             ActivityManagerNative.getDefault().reportSizeConfigurations(r.token,
                     horizontal.copyKeys(), vertical.copyKeys(), smallest.copyKeys());
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
 
     }
@@ -2802,6 +2847,7 @@
         try {
             mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content, referrer);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2838,6 +2884,7 @@
         try {
             ActivityManagerNative.getDefault().backgroundResourcesReleased(token);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2878,17 +2925,17 @@
         }
     }
 
-    private void handleMultiWindowChanged(IBinder token, boolean inMultiWindow) {
+    private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) {
         final ActivityClientRecord r = mActivities.get(token);
         if (r != null) {
-            r.activity.onMultiWindowChanged(inMultiWindow);
+            r.activity.onMultiWindowModeChanged(isInMultiWindowMode);
         }
     }
 
-    private void handlePictureInPictureChanged(IBinder token, boolean inPip) {
+    private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode) {
         final ActivityClientRecord r = mActivities.get(token);
         if (r != null) {
-            r.activity.onPictureInPictureChanged(inPip);
+            r.activity.onPictureInPictureModeChanged(isInPipMode);
         }
     }
 
@@ -2992,8 +3039,7 @@
                 return;
             }
         } catch (RemoteException e) {
-            Slog.e(TAG, "Can't reach package manager", e);
-            return;
+            throw e.rethrowFromSystemServer();
         }
 
         // no longer idle; we have backup work to do
@@ -3054,7 +3100,7 @@
             try {
                 ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder);
             } catch (RemoteException e) {
-                // nothing to do.
+                throw e.rethrowFromSystemServer();
             }
         } catch (Exception e) {
             throw new RuntimeException("Unable to create BackupAgent "
@@ -3116,7 +3162,7 @@
                 ActivityManagerNative.getDefault().serviceDoneExecuting(
                         data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
             } catch (RemoteException e) {
-                // nothing to do.
+                throw e.rethrowFromSystemServer();
             }
         } catch (Exception e) {
             if (!mInstrumentation.onException(service, e)) {
@@ -3147,6 +3193,7 @@
                     }
                     ensureJitEnabled();
                 } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
                 }
             } catch (Exception e) {
                 if (!mInstrumentation.onException(s, e)) {
@@ -3174,6 +3221,7 @@
                                 data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                     }
                 } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
                 }
             } catch (Exception e) {
                 if (!mInstrumentation.onException(s, e)) {
@@ -3255,7 +3303,7 @@
                     ActivityManagerNative.getDefault().serviceDoneExecuting(
                             data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                 } catch (RemoteException e) {
-                    // nothing to do.
+                    throw e.rethrowFromSystemServer();
                 }
                 ensureJitEnabled();
             } catch (Exception e) {
@@ -3286,9 +3334,7 @@
                     ActivityManagerNative.getDefault().serviceDoneExecuting(
                             token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
                 } catch (RemoteException e) {
-                    // nothing to do.
-                    Slog.i(TAG, "handleStopService: unable to execute serviceDoneExecuting for "
-                            + token, e);
+                    throw e.rethrowFromSystemServer();
                 }
             } catch (Exception e) {
                 if (!mInstrumentation.onException(s, e)) {
@@ -3305,7 +3351,7 @@
     }
 
     public final ActivityClientRecord performResumeActivity(IBinder token,
-            boolean clearHide) {
+            boolean clearHide, String reason) {
         ActivityClientRecord r = mActivities.get(token);
         if (localLOGV) Slog.v(TAG, "Performing resume of " + r
                 + " finished=" + r.activity.mFinished);
@@ -3327,8 +3373,20 @@
                 }
                 r.activity.performResume();
 
-                EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED,
-                        UserHandle.myUserId(), r.activity.getComponentName().getClassName());
+                // If there is a pending local relaunch that was requested when the activity was
+                // paused, it will put the activity into paused state when it finally happens.
+                // Since the activity resumed before being relaunched, we don't want that to happen,
+                // so we need to clear the request to relaunch paused.
+                for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
+                    final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
+                    if (relaunching.token == r.token
+                            && relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
+                        relaunching.startsNotResumed = false;
+                    }
+                }
+
+                EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), reason);
 
                 r.paused = false;
                 r.stopped = false;
@@ -3364,7 +3422,7 @@
     }
 
     final void handleResumeActivity(IBinder token,
-            boolean clearHide, boolean isForward, boolean reallyResume, int seq) {
+            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
         ActivityClientRecord r = mActivities.get(token);
         if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
             return;
@@ -3376,7 +3434,7 @@
         mSomeActivitiesChanged = true;
 
         // TODO Push resumeArgs into the activity for consideration
-        r = performResumeActivity(token, clearHide);
+        r = performResumeActivity(token, clearHide, reason);
 
         if (r != null) {
             final Activity a = r.activity;
@@ -3398,6 +3456,7 @@
                     willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                             a.getActivityToken());
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
             if (r.window == null && !a.mFinished && willBeVisible) {
@@ -3435,14 +3494,9 @@
             if (!r.activity.mFinished && willBeVisible
                     && r.activity.mDecor != null && !r.hideForNow) {
                 if (r.newConfig != null) {
-                    r.tmpConfig.setTo(r.newConfig);
-                    if (r.overrideConfig != null) {
-                        r.tmpConfig.updateFrom(r.overrideConfig);
-                    }
+                    performConfigurationChangedForActivity(r, r.newConfig, REPORT_TO_ACTIVITY);
                     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
-                            + r.activityInfo.name + " with newConfig " + r.tmpConfig);
-                    performConfigurationChanged(r.activity, r.tmpConfig, REPORT_TO_ACTIVITY);
-                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
+                            + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig);
                     r.newConfig = null;
                 }
                 if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
@@ -3481,6 +3535,7 @@
                 try {
                     ActivityManagerNative.getDefault().activityResumed(token);
                 } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
                 }
             }
 
@@ -3492,6 +3547,7 @@
                     .finishActivity(token, Activity.RESULT_CANCELED, null,
                             Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
             } catch (RemoteException ex) {
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -3555,6 +3611,7 @@
     private void handlePauseActivity(IBinder token, boolean finished,
             boolean userLeaving, int configChanges, boolean dontReport, int seq) {
         ActivityClientRecord r = mActivities.get(token);
+        if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
         if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
             return;
         }
@@ -3565,7 +3622,7 @@
             }
 
             r.activity.mConfigChangeFlags |= configChanges;
-            performPauseActivity(token, finished, r.isPreHoneycomb());
+            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
 
             // Make sure any pending writes are now committed.
             if (r.isPreHoneycomb()) {
@@ -3577,6 +3634,7 @@
                 try {
                     ActivityManagerNative.getDefault().activityPaused(token);
                 } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
                 }
             }
             mSomeActivitiesChanged = true;
@@ -3588,13 +3646,13 @@
     }
 
     final Bundle performPauseActivity(IBinder token, boolean finished,
-            boolean saveState) {
+            boolean saveState, String reason) {
         ActivityClientRecord r = mActivities.get(token);
-        return r != null ? performPauseActivity(r, finished, saveState) : null;
+        return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
     }
 
     final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
-            boolean saveState) {
+            boolean saveState, String reason) {
         if (r.paused) {
             if (r.activity.mFinished) {
                 // If we are finishing, we won't call onResume() in certain cases.
@@ -3619,7 +3677,7 @@
             r.activity.mCalled = false;
             mInstrumentation.callActivityOnPause(r.activity);
             EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
-                    r.activity.getComponentName().getClassName());
+                    r.activity.getComponentName().getClassName(), reason);
             if (!r.activity.mCalled) {
                 throw new SuperNotCalledException(
                     "Activity " + r.intent.getComponent().toShortString() +
@@ -3652,9 +3710,9 @@
         return !r.activity.mFinished && saveState ? r.state : null;
     }
 
-    final void performStopActivity(IBinder token, boolean saveState) {
+    final void performStopActivity(IBinder token, boolean saveState, String reason) {
         ActivityClientRecord r = mActivities.get(token);
-        performStopActivityInner(r, null, false, saveState);
+        performStopActivityInner(r, null, false, saveState, reason);
     }
 
     private static class StopInfo implements Runnable {
@@ -3670,6 +3728,12 @@
                 ActivityManagerNative.getDefault().activityStopped(
                     activity.token, state, persistentState, description);
             } catch (RemoteException ex) {
+                if (ex instanceof TransactionTooLargeException
+                        && activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
+                    Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
+                    return;
+                }
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -3705,7 +3769,7 @@
      * the activity's UI visibillity changes.
      */
     private void performStopActivityInner(ActivityClientRecord r,
-            StopInfo info, boolean keepShown, boolean saveState) {
+            StopInfo info, boolean keepShown, boolean saveState, String reason) {
         if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
         if (r != null) {
             if (!keepShown && r.stopped) {
@@ -3716,9 +3780,10 @@
                     return;
                 }
                 RuntimeException e = new RuntimeException(
-                        "Performing stop of activity that is not resumed: "
+                        "Performing stop of activity that is already stopped: "
                         + r.intent.getComponent().toShortString());
                 Slog.e(TAG, e.getMessage(), e);
+                Slog.e(TAG, r.getStateString());
             }
 
             if (info != null) {
@@ -3747,7 +3812,7 @@
             if (!keepShown) {
                 try {
                     // Now we are idle.
-                    r.activity.performStop();
+                    r.activity.performStop(false /*preserveWindow*/);
                 } catch (Exception e) {
                     if (!mInstrumentation.onException(r.activity, e)) {
                         throw new RuntimeException(
@@ -3757,6 +3822,8 @@
                     }
                 }
                 r.stopped = true;
+                EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), reason);
             }
 
             r.paused = true;
@@ -3775,14 +3842,10 @@
                     }
                 }
                 if (r.newConfig != null) {
-                    r.tmpConfig.setTo(r.newConfig);
-                    if (r.overrideConfig != null) {
-                        r.tmpConfig.updateFrom(r.overrideConfig);
-                    }
+                    performConfigurationChangedForActivity(r, r.newConfig, REPORT_TO_ACTIVITY);
                     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Updating activity vis "
-                            + r.activityInfo.name + " with new config " + r.tmpConfig);
-                    performConfigurationChanged(r.activity, r.tmpConfig, REPORT_TO_ACTIVITY);
-                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
+                            + r.activityInfo.name + " with new config "
+                            + r.activity.mCurrentConfig);
                     r.newConfig = null;
                 }
             } else {
@@ -3803,7 +3866,7 @@
         r.activity.mConfigChangeFlags |= configChanges;
 
         StopInfo info = new StopInfo();
-        performStopActivityInner(r, info, show, true);
+        performStopActivityInner(r, info, show, true, "handleStopActivity");
 
         if (localLOGV) Slog.v(
             TAG, "Finishing stop of " + r + ": show=" + show
@@ -3859,7 +3922,7 @@
         }
 
         if (!show && !r.stopped) {
-            performStopActivityInner(r, null, show, false);
+            performStopActivityInner(r, null, show, false, "handleWindowVisibility");
         } else if (show && r.stopped) {
             // If we are getting ready to gc after going to the background, well
             // we are back active so skip it.
@@ -3888,7 +3951,7 @@
             if (!r.stopped && !r.isPreHoneycomb()) {
                 try {
                     // Now we are idle.
-                    r.activity.performStop();
+                    r.activity.performStop(false /*preserveWindow*/);
                 } catch (Exception e) {
                     if (!mInstrumentation.onException(r.activity, e)) {
                         throw new RuntimeException(
@@ -3898,6 +3961,8 @@
                     }
                 }
                 r.stopped = true;
+                EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), "sleeping");
             }
 
             // Make sure any pending writes are now committed.
@@ -3909,6 +3974,7 @@
             try {
                 ActivityManagerNative.getDefault().activitySlept(r.token);
             } catch (RemoteException ex) {
+                throw ex.rethrowFromSystemServer();
             }
         } else {
             if (r.stopped && r.activity.mVisibleFromServer) {
@@ -4038,7 +4104,7 @@
                     r.activity.mCalled = false;
                     mInstrumentation.callActivityOnPause(r.activity);
                     EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
-                            r.activity.getComponentName().getClassName());
+                            r.activity.getComponentName().getClassName(), "destroy");
                     if (!r.activity.mCalled) {
                         throw new SuperNotCalledException(
                             "Activity " + safeToComponentShortString(r.intent)
@@ -4058,7 +4124,7 @@
             }
             if (!r.stopped) {
                 try {
-                    r.activity.performStop();
+                    r.activity.performStop(r.mPreserveWindow);
                 } catch (SuperNotCalledException e) {
                     throw e;
                 } catch (Exception e) {
@@ -4070,6 +4136,8 @@
                     }
                 }
                 r.stopped = true;
+                EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), "destroy");
             }
             if (getNonConfigInstance) {
                 try {
@@ -4175,7 +4243,7 @@
             try {
                 ActivityManagerNative.getDefault().activityDestroyed(token);
             } catch (RemoteException ex) {
-                // If the system process has died, it's game over for everyone.
+                throw ex.rethrowFromSystemServer();
             }
         }
         mSomeActivitiesChanged = true;
@@ -4194,6 +4262,7 @@
         synchronized (mResourcesManager) {
             for (int i=0; i<mRelaunchingActivities.size(); i++) {
                 ActivityClientRecord r = mRelaunchingActivities.get(i);
+                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + this + ", trying: " + r);
                 if (r.token == token) {
                     target = r;
                     if (pendingResults != null) {
@@ -4216,7 +4285,7 @@
                         try {
                             ActivityManagerNative.getDefault().activityRelaunched(token);
                         } catch (RemoteException e) {
-                            e.printStackTrace();
+                            throw e.rethrowFromSystemServer();
                         }
                     }
                     break;
@@ -4224,14 +4293,19 @@
             }
 
             if (target == null) {
+                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null, fromServer:"
+                        + fromServer);
                 target = new ActivityClientRecord();
                 target.token = token;
                 target.pendingResults = pendingResults;
                 target.pendingIntents = pendingNewIntents;
                 target.mPreserveWindow = preserveWindow;
                 if (!fromServer) {
-                    ActivityClientRecord existing = mActivities.get(token);
+                    final ActivityClientRecord existing = mActivities.get(token);
+                    if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + existing);
                     if (existing != null) {
+                        if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: paused= "
+                                + existing.paused);;
                         target.startsNotResumed = existing.paused;
                         target.overrideConfig = existing.overrideConfig;
                     }
@@ -4254,8 +4328,8 @@
             target.pendingConfigChanges |= configChanges;
             target.relaunchSeq = getLifecycleSeq();
         }
-        if (DEBUG_ORDER) Slog.d(TAG, "relaunchActivity " + ActivityThread.this
-                + " operation received seq: " + target.relaunchSeq);
+        if (DEBUG_ORDER) Slog.d(TAG, "relaunchActivity " + ActivityThread.this + ", target "
+                + target + " operation received seq: " + target.relaunchSeq);
     }
 
     private void handleRelaunchActivity(ActivityClientRecord tmp) {
@@ -4337,7 +4411,7 @@
                 try {
                     ActivityManagerNative.getDefault().activityRelaunched(tmp.token);
                 } catch (RemoteException e) {
-                    // If the system process has died, it's game over for everyone.
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return;
@@ -4363,13 +4437,13 @@
                 WindowManagerGlobal.getWindowSession().prepareToReplaceChildren(r.token);
             }
         } catch (RemoteException e) {
-            // If the system process has died, it's game over for everyone.
+            throw e.rethrowFromSystemServer();
         }
 
 
         // Need to ensure state is saved.
         if (!r.paused) {
-            performPauseActivity(r.token, false, r.isPreHoneycomb());
+            performPauseActivity(r.token, false, r.isPreHoneycomb(), "handleRelaunchActivity");
         }
         if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
             callCallActivityOnSaveInstanceState(r);
@@ -4399,7 +4473,7 @@
         r.startsNotResumed = tmp.startsNotResumed;
         r.overrideConfig = tmp.overrideConfig;
 
-        handleLaunchActivity(r, currentIntent);
+        handleLaunchActivity(r, currentIntent, "handleRelaunchActivity");
 
         if (!tmp.onlyLocalRequest) {
             try {
@@ -4408,7 +4482,7 @@
                     r.window.reportActivityRelaunched();
                 }
             } catch (RemoteException e) {
-                // If the system process has died, it's game over for everyone.
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4476,8 +4550,44 @@
         return callbacks;
     }
 
-    private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config,
-            boolean reportToActivity) {
+    /**
+     * Updates the configuration for an Activity. The ActivityClientRecord's
+     * {@link ActivityClientRecord#overrideConfig} is used to compute the final Configuration for
+     * that Activity. {@link ActivityClientRecord#tmpConfig} is used as a temporary for delivering
+     * the updated Configuration.
+     * @param r ActivityClientRecord representing the Activity.
+     * @param newBaseConfig The new configuration to use. This may be augmented with
+     *                      {@link ActivityClientRecord#overrideConfig}.
+     * @param reportToActivity true if the change should be reported to the Activity's callback.
+     */
+    private void performConfigurationChangedForActivity(ActivityClientRecord r,
+                                                        Configuration newBaseConfig,
+                                                        boolean reportToActivity) {
+        r.tmpConfig.setTo(newBaseConfig);
+        if (r.overrideConfig != null) {
+            r.tmpConfig.updateFrom(r.overrideConfig);
+        }
+        performConfigurationChanged(r.activity, r.token, r.tmpConfig, r.overrideConfig,
+                reportToActivity);
+        freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
+    }
+
+    /**
+     * Decides whether to update an Activity's configuration and whether to tell the
+     * Activity/Component about it.
+     * @param cb The component callback to notify of configuration change.
+     * @param activityToken The Activity binder token for which this configuration change happened.
+     *                      If the change is global, this is null.
+     * @param newConfig The new configuration.
+     * @param overrideConfig The override config that differentiates the Activity's configuration
+     *                       from the base global configuration.
+     * @param reportToActivity Notify the Activity of the change.
+     */
+    private void performConfigurationChanged(ComponentCallbacks2 cb,
+                                             IBinder activityToken,
+                                             Configuration newConfig,
+                                             Configuration overrideConfig,
+                                             boolean reportToActivity) {
         // Only for Activity objects, check that they actually call up to their
         // superclass implementation.  ComponentCallbacks2 is an interface, so
         // we check the runtime type and act accordingly.
@@ -4494,7 +4604,7 @@
             // If the new config is the same as the config this Activity
             // is already running with then don't bother calling
             // onConfigurationChanged
-            int diff = activity.mCurrentConfig.diff(config);
+            int diff = activity.mCurrentConfig.diff(newConfig);
             if (diff != 0) {
                 // If this activity doesn't handle any of the config changes then don't bother
                 // calling onConfigurationChanged as we're going to destroy it.
@@ -4509,21 +4619,45 @@
             }
         }
 
-        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Config callback " + cb
-                + ": shouldChangeConfig=" + shouldChangeConfig);
+        if (DEBUG_CONFIGURATION) {
+            Slog.v(TAG, "Config callback " + cb + ": shouldChangeConfig=" + shouldChangeConfig);
+        }
+
         if (shouldChangeConfig) {
+            if (activityToken != null) {
+                // We only update an Activity's configuration if this is not a global
+                // configuration change. This must also be done before the callback,
+                // or else we violate the contract that the new resources are available
+                // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
+                mResourcesManager.updateResourcesForActivity(activityToken, overrideConfig);
+            }
+
             if (reportToActivity) {
-                cb.onConfigurationChanged(config);
+                Configuration configToReport = newConfig;
+
+                if (cb instanceof ContextThemeWrapper) {
+                    // ContextThemeWrappers may override the configuration for that context.
+                    // We must check and apply any overrides defined.
+                    ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+                    final Configuration localOverrideConfig =
+                            contextThemeWrapper.getOverrideConfiguration();
+                    if (localOverrideConfig != null) {
+                        configToReport = new Configuration(newConfig);
+                        configToReport.updateFrom(localOverrideConfig);
+                    }
+                }
+
+                cb.onConfigurationChanged(configToReport);
             }
 
             if (activity != null) {
                 if (reportToActivity && !activity.mCalled) {
                     throw new SuperNotCalledException(
                             "Activity " + activity.getLocalClassName() +
-                        " did not call through to super.onConfigurationChanged()");
+                            " did not call through to super.onConfigurationChanged()");
                 }
                 activity.mConfigChangeFlags = 0;
-                activity.mCurrentConfig = new Configuration(config);
+                activity.mCurrentConfig = new Configuration(newConfig);
             }
         }
     }
@@ -4540,7 +4674,8 @@
             mCompatConfiguration = new Configuration();
         }
         mCompatConfiguration.setTo(mConfiguration);
-        if (mResourcesManager.applyCompatConfiguration(displayDensity, mCompatConfiguration)) {
+        if (mResourcesManager.applyCompatConfigurationLocked(displayDensity,
+                mCompatConfiguration)) {
             config = mCompatConfiguration;
         }
         return config;
@@ -4592,7 +4727,8 @@
         if (callbacks != null) {
             final int N = callbacks.size();
             for (int i=0; i<N; i++) {
-                performConfigurationChanged(callbacks.get(i), config, REPORT_TO_ACTIVITY);
+                performConfigurationChanged(callbacks.get(i), null, config, null,
+                        REPORT_TO_ACTIVITY);
             }
         }
     }
@@ -4618,15 +4754,8 @@
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
                 + r.activityInfo.name + ", with callback=" + reportToActivity);
 
-        r.tmpConfig.setTo(mCompatConfiguration);
-        if (data.overrideConfig != null) {
-            r.overrideConfig = data.overrideConfig;
-            r.tmpConfig.updateFrom(data.overrideConfig);
-        }
-        performConfigurationChanged(r.activity, r.tmpConfig, reportToActivity);
-
-        freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration));
-
+        r.overrideConfig = data.overrideConfig;
+        performConfigurationChangedForActivity(r, mCompatConfiguration, reportToActivity);
         mSomeActivitiesChanged = true;
     }
 
@@ -4688,34 +4817,93 @@
         try {
             ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
     final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
         boolean hasPkgInfo = false;
-        if (packages != null) {
-            synchronized (mResourcesManager) {
-                for (int i=packages.length-1; i>=0; i--) {
-                    //Slog.i(TAG, "Cleaning old package: " + packages[i]);
-                    if (!hasPkgInfo) {
-                        WeakReference<LoadedApk> ref;
-                        ref = mPackages.get(packages[i]);
-                        if (ref != null && ref.get() != null) {
+        switch (cmd) {
+            case IApplicationThread.PACKAGE_REMOVED:
+            case IApplicationThread.PACKAGE_REMOVED_DONT_KILL:
+            {
+                final boolean killApp = cmd == IApplicationThread.PACKAGE_REMOVED;
+                if (packages == null) {
+                    break;
+                }
+                synchronized (mResourcesManager) {
+                    for (int i = packages.length - 1; i >= 0; i--) {
+                        if (!hasPkgInfo) {
+                            WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
+                            if (ref != null && ref.get() != null) {
+                                hasPkgInfo = true;
+                            } else {
+                                ref = mResourcePackages.get(packages[i]);
+                                if (ref != null && ref.get() != null) {
+                                    hasPkgInfo = true;
+                                }
+                            }
+                        }
+                        if (killApp) {
+                            mPackages.remove(packages[i]);
+                            mResourcePackages.remove(packages[i]);
+                        }
+                    }
+                }
+                break;
+            }
+            case IApplicationThread.PACKAGE_REPLACED:
+            {
+                if (packages == null) {
+                    break;
+                }
+                synchronized (mResourcesManager) {
+                    for (int i = packages.length - 1; i >= 0; i--) {
+                        WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
+                        LoadedApk pkgInfo = ref != null ? ref.get() : null;
+                        if (pkgInfo != null) {
                             hasPkgInfo = true;
                         } else {
                             ref = mResourcePackages.get(packages[i]);
-                            if (ref != null && ref.get() != null) {
+                            pkgInfo = ref != null ? ref.get() : null;
+                            if (pkgInfo != null) {
                                 hasPkgInfo = true;
                             }
                         }
+                        // If the package is being replaced, yet it still has a valid
+                        // LoadedApk object, the package was updated with _DONT_KILL.
+                        // Adjust it's internal references to the application info and
+                        // resources.
+                        if (pkgInfo != null) {
+                            try {
+                                final String packageName = packages[i];
+                                final ApplicationInfo aInfo =
+                                        sPackageManager.getApplicationInfo(
+                                                packageName,
+                                                0 /*flags*/,
+                                                UserHandle.myUserId());
+
+                                if (mActivities.size() > 0) {
+                                    for (ActivityClientRecord ar : mActivities.values()) {
+                                        if (ar.activityInfo.applicationInfo.packageName
+                                                .equals(packageName)) {
+                                            ar.activityInfo.applicationInfo = aInfo;
+                                            ar.packageInfo = pkgInfo;
+                                        }
+                                    }
+                                }
+                                final List<String> oldPaths =
+                                        sPackageManager.getPreviousCodePaths(packageName);
+                                pkgInfo.updateApplicationInfo(aInfo, oldPaths);
+                            } catch (RemoteException e) {
+                            }
+                        }
                     }
-                    mPackages.remove(packages[i]);
-                    mResourcePackages.remove(packages[i]);
                 }
+                break;
             }
         }
-        ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
-                hasPkgInfo);
+        ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasPkgInfo);
     }
 
     final void handleLowMemory() {
@@ -4770,14 +4958,15 @@
                 RenderScriptCacheDir.setupDiskCache(cacheDir);
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
     }
 
     // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp).
     private static File getPrimaryProfileFile(String packageName) {
-         return new File("/data/misc/profiles/cur/" + UserHandle.myUserId() +
-              "/" + packageName + "/primary.prof");
+        File profileDir = Environment.getDataProfilesDePackageDirectory(
+                UserHandle.myUserId(), packageName);
+        return new File(profileDir, "primary.prof");
     }
 
     private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) {
@@ -4808,11 +4997,15 @@
                 Os.fchmod(fd, permissions);
                 Os.fchown(fd, appInfo.uid, appInfo.uid);
             } catch (ErrnoException e) {
-                Log.v(TAG, "Unable to create jit profile file " + profileFile, e);
+                Log.v(TAG, "Unable to create jit profile file "
+                        + profileFile + ": " + e.getMessage());
                 try {
                     Os.unlink(profileFile.getAbsolutePath());
                 } catch (ErrnoException unlinkErr) {
-                    Log.v(TAG, "Unable to unlink jit profile file " + profileFile, unlinkErr);
+                    if (unlinkErr.errno != OsConstants.ENOENT) {
+                        Log.v(TAG, "Unable to unlink jit profile file "
+                                + profileFile + ": " + unlinkErr.getMessage());
+                    }
                 }
                 return;
             } finally {
@@ -4820,8 +5013,17 @@
             }
         }
 
+        final File foreignDexProfilesFile =
+                Environment.getDataProfilesDeForeignDexDirectory(UserHandle.myUserId());
+        String foreignDexProfilesPath = null;
+        if (!foreignDexProfilesFile.exists()) {
+            Log.v(TAG, "ForeignDexProfilesPath does not exists:" +
+                    foreignDexProfilesFile.getPath());
+        } else {
+            foreignDexProfilesPath = foreignDexProfilesFile.getAbsolutePath();
+        }
         VMRuntime.registerAppInfo(profileFile.getAbsolutePath(), appInfo.dataDir,
-                codePaths.toArray(new String[codePaths.size()]));
+                codePaths.toArray(new String[codePaths.size()]), foreignDexProfilesPath);
     }
 
     private void updateDefaultDensity() {
@@ -4839,6 +5041,9 @@
             DdmVmInternal.enableRecentAllocations(true);
         }
 
+        // Note when this process has started.
+        Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+
         mBoundApplication = data;
         mConfiguration = new Configuration(data.config);
         mCompatConfiguration = new Configuration(data.config);
@@ -4887,22 +5092,6 @@
          */
         TimeZone.setDefault(null);
 
-        /*
-         * Initialize the default locales in this process for the reasons we set the time zone.
-         *
-         * We do this through ResourcesManager, since we need to do locale negotiation.
-         */
-        mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
-
-        /*
-         * Update the system configuration since its preloaded and might not
-         * reflect configuration changes. The configuration object passed
-         * in AppBindData can be safely assumed to be up to date
-         */
-        mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
-        mCurDefaultDisplayDpi = data.config.densityDpi;
-        applyCompatConfiguration(mCurDefaultDisplayDpi);
-
         data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
 
         /**
@@ -4962,6 +5151,7 @@
                 try {
                     mgr.showWaitingForDebugger(mAppThread, true);
                 } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
                 }
 
                 Debug.waitForDebugger();
@@ -4969,6 +5159,7 @@
                 try {
                     mgr.showWaitingForDebugger(mAppThread, false);
                 } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
                 }
 
             } else {
@@ -4996,7 +5187,9 @@
             try {
                 final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
                 Proxy.setHttpProxySystemProperty(proxyInfo);
-            } catch (RemoteException e) {}
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
 
         // Instrumentation info affects the class loader, so load it before
@@ -5023,6 +5216,26 @@
         }
 
         final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
+        synchronized (mResourcesManager) {
+            /*
+             * Initialize the default locales in this process for the reasons we set the time zone.
+             *
+             * We do this through ResourcesManager, since we need to do locale negotiation.
+             */
+            mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
+
+            /*
+             * Update the system configuration since its preloaded and might not
+             * reflect configuration changes. The configuration object passed
+             * in AppBindData can be safely assumed to be up to date
+             */
+            mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
+            mCurDefaultDisplayDpi = data.config.densityDpi;
+
+            // This calls mResourcesManager so keep it within the synchronized block.
+            applyCompatConfiguration(mCurDefaultDisplayDpi);
+        }
+
         if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
             // This cache location probably points at credential-encrypted
             // storage which may not be accessible yet; assign it anyway instead
@@ -5038,9 +5251,9 @@
 
             // Setup a location to store generated/compiled graphics code and
             // JIT profiling data. Note that this data is stored in a
-            // device-encrypted storage area, so these caches must never contain
+            // device-protected storage area, so these caches must never contain
             // user sensitive user data.
-            final Context deviceContext = appContext.createDeviceEncryptedStorageContext();
+            final Context deviceContext = appContext.createDeviceProtectedStorageContext();
             final File codeCacheDir = deviceContext.getCodeCacheDir();
             if (codeCacheDir != null) {
                 setupGraphicsSupport(data.info, codeCacheDir);
@@ -5115,9 +5328,8 @@
             // don't bring up providers in restricted mode; they may depend on the
             // app's custom Application class
             if (!data.restrictedBackupMode) {
-                List<ProviderInfo> providers = data.providers;
-                if (providers != null) {
-                    installContentProviders(app, providers);
+                if (!ArrayUtils.isEmpty(data.providers)) {
+                    installContentProviders(app, data.providers);
                     // For process that contains content providers, we want to
                     // ensure that the JIT is enabled "at some point".
                     mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
@@ -5160,6 +5372,7 @@
         try {
             am.finishInstrumentation(mAppThread, resultCode, results);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -5189,6 +5402,7 @@
             ActivityManagerNative.getDefault().publishContentProviders(
                 getApplicationThread(), results);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -5210,6 +5424,7 @@
             holder = ActivityManagerNative.getDefault().getContentProvider(
                     getApplicationThread(), auth, userId, stable);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
         if (holder == null) {
             Slog.e(TAG, "Failed to find provider info for " + auth);
@@ -5497,6 +5712,7 @@
                     ActivityManagerNative.getDefault()
                             .appNotRespondingViaProvider(prc.holder.connection);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
         }
@@ -5676,7 +5892,7 @@
             try {
                 mgr.attachApplication(mAppThread);
             } catch (RemoteException ex) {
-                // Ignore
+                throw ex.rethrowFromSystemServer();
             }
             // Watch for getting close to heap limit.
             BinderInternal.addGcWatcher(new Runnable() {
@@ -5695,6 +5911,7 @@
                         try {
                             mgr.releaseSomeActivities(mAppThread);
                         } catch (RemoteException e) {
+                            throw e.rethrowFromSystemServer();
                         }
                     }
                 }
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 198bfb0a..e589e7c 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -25,6 +25,7 @@
 import android.os.ResultReceiver;
 import android.transition.Transition;
 import android.transition.TransitionSet;
+import android.transition.Visibility;
 import android.util.ArrayMap;
 import android.view.GhostView;
 import android.view.View;
@@ -378,6 +379,7 @@
             transition.setEpicenterCallback(mEpicenterCallback);
             transition = setTargets(transition, includeTransitioningViews);
         }
+        noLayoutSuppressionForVisibilityTransitions(transition);
         return transition;
     }
 
@@ -944,6 +946,24 @@
         }
     }
 
+    /**
+     * Blocks suppressLayout from Visibility transitions. It is ok to suppress the layout,
+     * but we don't want to force the layout when suppressLayout becomes false. This leads
+     * to visual glitches.
+     */
+    private static void noLayoutSuppressionForVisibilityTransitions(Transition transition) {
+        if (transition instanceof Visibility) {
+            final Visibility visibility = (Visibility) transition;
+            visibility.setSuppressLayout(false);
+        } else if (transition instanceof TransitionSet) {
+            final TransitionSet set = (TransitionSet) transition;
+            final int count = set.getTransitionCount();
+            for (int i = 0; i < count; i++) {
+                noLayoutSuppressionForVisibilityTransitions(set.getTransitionAt(i));
+            }
+        }
+    }
+
     private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
         private Rect mEpicenter;
 
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index bf0bd79..4a1aff7 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -236,9 +236,24 @@
         }
     }
 
-    public void onResume() {
-        restoreExitedViews();
-        restoreReenteringViews();
+    public void onResume(Activity activity, boolean isTopOfTask) {
+        // After orientation change, the onResume can come in before the top Activity has
+        // left, so if the Activity is not top, wait a second for the top Activity to exit.
+        if (isTopOfTask || mEnterTransitionCoordinator == null) {
+            restoreExitedViews();
+            restoreReenteringViews();
+        } else {
+            activity.mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    if (mEnterTransitionCoordinator == null ||
+                            mEnterTransitionCoordinator.isWaitingForRemoteExit()) {
+                        restoreExitedViews();
+                        restoreReenteringViews();
+                    }
+                }
+            }, 1000);
+        }
     }
 
     public void clear() {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index b569416..e4fff9d 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -201,6 +201,7 @@
             try {
                 mService.remove(null, this);
             } catch (RemoteException ex) {
+                throw ex.rethrowFromSystemServer();
             }
 
             synchronized (AlarmManager.class) {
@@ -558,9 +559,10 @@
      * the given time.
      * @hide
      */
-    public void setIdleUntil(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_IDLE_UNTIL, operation,
-                null, null, null, null, null);
+    public void setIdleUntil(int type, long triggerAtMillis, String tag, OnAlarmListener listener,
+            Handler targetHandler) {
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_IDLE_UNTIL, null,
+                listener, tag, targetHandler, null, null);
     }
 
     /**
@@ -656,6 +658,7 @@
             mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
                     operation, recipientWrapper, listenerTag, workSource, alarmClock);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -886,6 +889,7 @@
         try {
             mService.remove(operation, null);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -901,10 +905,12 @@
 
         ListenerWrapper wrapper = null;
         synchronized (AlarmManager.class) {
-            final WeakReference<ListenerWrapper> wrapperRef;
-            wrapperRef = sWrappers.get(listener);
-            if (wrapperRef != null) {
-                wrapper = wrapperRef.get();
+            if (sWrappers != null) {
+                final WeakReference<ListenerWrapper> wrapperRef;
+                wrapperRef = sWrappers.get(listener);
+                if (wrapperRef != null) {
+                    wrapper = wrapperRef.get();
+                }
             }
         }
 
@@ -926,6 +932,7 @@
         try {
             mService.setTime(millis);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -965,6 +972,7 @@
         try {
             mService.setTimeZone(timeZone);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -973,18 +981,23 @@
         try {
             return mService.getNextWakeFromIdleTime();
         } catch (RemoteException ex) {
-            return Long.MAX_VALUE;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
     /**
      * Gets information about the next alarm clock currently scheduled.
      *
-     * The alarm clocks considered are those scheduled by {@link #setAlarmClock}
-     * from any package of the calling user.
+     * The alarm clocks considered are those scheduled by any application
+     * using the {@link #setAlarmClock} method.
+     *
+     * @return An {@link AlarmClockInfo} object describing the next upcoming alarm
+     *   clock event that will occur.  If there are no alarm clock events currently
+     *   scheduled, this method will return {@code null}.
      *
      * @see #setAlarmClock
      * @see AlarmClockInfo
+     * @see #ACTION_NEXT_ALARM_CLOCK_CHANGED
      */
     public AlarmClockInfo getNextAlarmClock() {
         return getNextAlarmClock(UserHandle.myUserId());
@@ -993,11 +1006,16 @@
     /**
      * Gets information about the next alarm clock currently scheduled.
      *
-     * The alarm clocks considered are those scheduled by {@link #setAlarmClock}
-     * from any package of the given {@parm userId}.
+     * The alarm clocks considered are those scheduled by any application
+     * using the {@link #setAlarmClock} method within the given user.
+     *
+     * @return An {@link AlarmClockInfo} object describing the next upcoming alarm
+     *   clock event that will occur within the given user.  If there are no alarm clock
+     *   events currently scheduled in that user, this method will return {@code null}.
      *
      * @see #setAlarmClock
      * @see AlarmClockInfo
+     * @see #ACTION_NEXT_ALARM_CLOCK_CHANGED
      *
      * @hide
      */
@@ -1005,12 +1023,12 @@
         try {
             return mService.getNextAlarmClock(userId);
         } catch (RemoteException ex) {
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
     /**
-     * An immutable description of an alarm clock.
+     * An immutable description of a scheduled "alarm clock" event.
      *
      * @see AlarmManager#setAlarmClock
      * @see AlarmManager#getNextAlarmClock
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 93452fd..64586a6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -704,8 +704,8 @@
      * (and system ui) to bypass the user restriction when active.
      */
     private static boolean[] sOpAllowSystemRestrictionBypass = new boolean[] {
-            false, //COARSE_LOCATION
-            false, //FINE_LOCATION
+            true, //COARSE_LOCATION
+            true, //FINE_LOCATION
             false, //GPS
             false, //VIBRATE
             false, //READ_CONTACTS
@@ -1236,8 +1236,8 @@
         try {
             return mService.getPackagesForOps(ops);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -1252,8 +1252,8 @@
         try {
             return mService.getOpsForPackage(uid, packageName, ops);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /** @hide */
@@ -1261,14 +1261,23 @@
         try {
             mService.setUidMode(code, uid, mode);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /** @hide */
     public void setUserRestriction(int code, boolean restricted, IBinder token) {
+        setUserRestriction(code, restricted, token, /*exceptionPackages*/null);
+    }
+
+    /** @hide */
+    public void setUserRestriction(int code, boolean restricted, IBinder token,
+            String[] exceptionPackages) {
         try {
-            mService.setUserRestriction(code, restricted, token, mContext.getUserId());
+            mService.setUserRestriction(code, restricted, token, mContext.getUserId(),
+                  exceptionPackages);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1277,6 +1286,7 @@
         try {
             mService.setMode(code, uid, packageName, mode);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1297,6 +1307,7 @@
             final int uid = Binder.getCallingUid();
             mService.setAudioRestriction(code, usage, uid, mode, exceptionPackages);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1305,6 +1316,7 @@
         try {
             mService.resetAllModes(UserHandle.myUserId(), null);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1361,6 +1373,7 @@
             try {
                 mService.startWatchingMode(op, packageName, cb);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1376,6 +1389,7 @@
                 try {
                     mService.stopWatchingMode(cb);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
         }
@@ -1540,8 +1554,8 @@
             }
             return mode;
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_IGNORED;
     }
 
     /**
@@ -1553,8 +1567,8 @@
         try {
             return mService.checkOperation(op, uid, packageName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_ERRORED;
     }
 
     /**
@@ -1570,7 +1584,7 @@
                         "Package " + packageName + " does not belong to " + uid);
             }
         } catch (RemoteException e) {
-            throw new SecurityException("Unable to verify package ownership", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1586,8 +1600,8 @@
             }
             return mode;
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_IGNORED;
     }
 
     /**
@@ -1599,8 +1613,8 @@
         try {
             return mService.checkAudioOperation(op, stream, uid, packageName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_ERRORED;
     }
 
     /**
@@ -1626,8 +1640,8 @@
             }
             return mode;
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_IGNORED;
     }
 
     /**
@@ -1669,8 +1683,8 @@
             return mService.noteProxyOperation(op, mContext.getOpPackageName(),
                     Binder.getCallingUid(), proxiedPackageName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_ERRORED;
     }
 
     /**
@@ -1682,8 +1696,8 @@
         try {
             return mService.noteOperation(op, uid, packageName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_ERRORED;
     }
 
     /** @hide */
@@ -1700,7 +1714,7 @@
             try {
                 sToken = service.getToken(new Binder());
             } catch (RemoteException e) {
-                // System is dead, whatevs.
+                throw e.rethrowFromSystemServer();
             }
             return sToken;
         }
@@ -1731,8 +1745,8 @@
             }
             return mode;
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_IGNORED;
     }
 
     /**
@@ -1744,8 +1758,8 @@
         try {
             return mService.startOperation(getToken(mService), op, uid, packageName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return MODE_ERRORED;
     }
 
     /** @hide */
@@ -1764,6 +1778,7 @@
         try {
             mService.finishOperation(getToken(mService), op, uid, packageName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 7d0d1b4..0fc097e 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -20,16 +20,14 @@
 import android.util.ArrayMap;
 import dalvik.system.PathClassLoader;
 
-class ApplicationLoaders
-{
-    public static ApplicationLoaders getDefault()
-    {
+class ApplicationLoaders {
+    public static ApplicationLoaders getDefault() {
         return gApplicationLoaders;
     }
 
-    public ClassLoader getClassLoader(String zip, boolean isBundled, String librarySearchPath,
-                                      String libraryPermittedPath, ClassLoader parent)
-    {
+    public ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
+                                      String librarySearchPath, String libraryPermittedPath,
+                                      ClassLoader parent) {
         /*
          * This is the parent we use if they pass "null" in.  In theory
          * this should be the "system" class loader; in practice we
@@ -55,11 +53,22 @@
                 }
     
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
+
                 PathClassLoader pathClassloader =
-                    new PathClassLoader(zip, isBundled, librarySearchPath,
-                                        libraryPermittedPath, parent);
+                    new PathClassLoader(zip, librarySearchPath, parent);
+
+                String errorMessage = createClassloaderNamespace(pathClassloader,
+                                                                 targetSdkVersion,
+                                                                 librarySearchPath,
+                                                                 libraryPermittedPath,
+                                                                 isBundled);
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
+                if (errorMessage != null) {
+                    throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " +
+                                                   pathClassloader + ": " + errorMessage);
+                }
+
                 mLoaders.put(zip, pathClassloader);
                 return pathClassloader;
             }
@@ -71,6 +80,24 @@
         }
     }
 
+    private static native String createClassloaderNamespace(ClassLoader classLoader,
+                                                            int targetSdkVersion,
+                                                            String librarySearchPath,
+                                                            String libraryPermittedPath,
+                                                            boolean isShared);
+
+    /**
+     * Adds a new path the classpath of the given loader.
+     * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}.
+     */
+    void addPath(ClassLoader classLoader, String dexPath) {
+        if (!(classLoader instanceof PathClassLoader)) {
+            throw new IllegalStateException("class loader is not a PathClassLoader");
+        }
+        final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
+        baseDexClassLoader.addDexPath(dexPath);
+    }
+
     private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<String, ClassLoader>();
 
     private static final ApplicationLoaders gApplicationLoaders
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 91eabcc..ed590e6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -30,7 +30,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
-import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IOnPermissionsChangeListener;
@@ -54,7 +53,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -143,7 +141,7 @@
                 return pi;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(packageName);
@@ -154,7 +152,7 @@
         try {
             return mPM.currentToCanonicalPackageNames(names);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -163,7 +161,7 @@
         try {
             return mPM.canonicalToCurrentPackageNames(names);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -227,7 +225,7 @@
                 return gids;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(packageName);
@@ -252,7 +250,7 @@
                 return uid;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(packageName);
@@ -267,22 +265,27 @@
                 return pi;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(name);
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
             throws NameNotFoundException {
         try {
-            List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
-            if (pi != null) {
-                return pi;
+            ParceledListSlice<PermissionInfo> parceledList =
+                    mPM.queryPermissionsByGroup(group, flags);
+            if (parceledList != null) {
+                List<PermissionInfo> pi = parceledList.getList();
+                if (pi != null) {
+                    return pi;
+                }
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(group);
@@ -290,25 +293,31 @@
 
     @Override
     public PermissionGroupInfo getPermissionGroupInfo(String name,
-                                                      int flags) throws NameNotFoundException {
+            int flags) throws NameNotFoundException {
         try {
             PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
             if (pgi != null) {
                 return pgi;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(name);
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
         try {
-            return mPM.getAllPermissionGroups(flags);
+            ParceledListSlice<PermissionGroupInfo> parceledList =
+                    mPM.getAllPermissionGroups(flags);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -330,7 +339,7 @@
                 return maybeAdjustApplicationInfo(ai);
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(packageName);
@@ -370,7 +379,7 @@
                 return ai;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(className.toString());
@@ -385,7 +394,7 @@
                 return ai;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(className.toString());
@@ -400,7 +409,7 @@
                 return si;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(className.toString());
@@ -415,7 +424,7 @@
                 return pi;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(className.toString());
@@ -426,7 +435,7 @@
         try {
             return mPM.getSystemSharedLibraryNames();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -436,16 +445,27 @@
         try {
             return mPM.getServicesSystemSharedLibraryPackageName();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public FeatureInfo[] getSystemAvailableFeatures() {
         try {
-            return mPM.getSystemAvailableFeatures();
+            ParceledListSlice<FeatureInfo> parceledList =
+                    mPM.getSystemAvailableFeatures();
+            if (parceledList == null) {
+                return new FeatureInfo[0];
+            }
+            final List<FeatureInfo> list = parceledList.getList();
+            final FeatureInfo[] res = new FeatureInfo[list.size()];
+            for (int i = 0; i < res.length; i++) {
+                res[i] = list.get(i);
+            }
+            return res;
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -459,7 +479,7 @@
         try {
             return mPM.hasSystemFeature(name, version);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -468,7 +488,7 @@
         try {
             return mPM.checkPermission(permName, pkgName, mContext.getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -477,7 +497,7 @@
         try {
             return mPM.isPermissionRevokedByPolicy(permName, pkgName, mContext.getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -491,7 +511,7 @@
                 try {
                     mPermissionsControllerPackageName = mPM.getPermissionControllerPackageName();
                 } catch (RemoteException e) {
-                    throw new RuntimeException("Package manager has died", e);
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return mPermissionsControllerPackageName;
@@ -503,7 +523,7 @@
         try {
             return mPM.addPermission(info);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -512,7 +532,7 @@
         try {
             return mPM.addPermissionAsync(info);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -521,7 +541,7 @@
         try {
             mPM.removePermission(name);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -531,7 +551,7 @@
         try {
             mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -541,7 +561,7 @@
         try {
             mPM.revokeRuntimePermission(packageName, permissionName, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -550,7 +570,7 @@
         try {
             return mPM.getPermissionFlags(permissionName, packageName, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -561,7 +581,7 @@
             mPM.updatePermissionFlags(permissionName, packageName, flagMask,
                     flagValues, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -571,7 +591,7 @@
             return mPM.shouldShowRequestPermissionRationale(permission,
                     mContext.getPackageName(), mContext.getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -580,7 +600,7 @@
         try {
             return mPM.checkSignatures(pkg1, pkg2);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -589,7 +609,7 @@
         try {
             return mPM.checkUidSignatures(uid1, uid2);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -598,7 +618,7 @@
         try {
             return mPM.getPackagesForUid(uid);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -607,7 +627,7 @@
         try {
             return mPM.getNameForUid(uid);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -620,7 +640,7 @@
                 return uid;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
         throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
     }
@@ -633,12 +653,17 @@
 
     /** @hide */
     @Override
+    @SuppressWarnings("unchecked")
     public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
         try {
-            ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId);
-            return slice.getList();
+            ParceledListSlice<PackageInfo> parceledList =
+                    mPM.getInstalledPackages(flags, userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -648,11 +673,14 @@
             String[] permissions, int flags) {
         final int userId = mContext.getUserId();
         try {
-            ParceledListSlice<PackageInfo> slice = mPM.getPackagesHoldingPermissions(
-                    permissions, flags, userId);
-            return slice.getList();
+            ParceledListSlice<PackageInfo> parceledList =
+                    mPM.getPackagesHoldingPermissions(permissions, flags, userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -661,10 +689,14 @@
     public List<ApplicationInfo> getInstalledApplications(int flags) {
         final int userId = mContext.getUserId();
         try {
-            ParceledListSlice<ApplicationInfo> slice = mPM.getInstalledApplications(flags, userId);
-            return slice.getList();
+            ParceledListSlice<ApplicationInfo> parceledList =
+                    mPM.getInstalledApplications(flags, userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -680,7 +712,7 @@
             }
             return Collections.emptyList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -695,7 +727,7 @@
             }
             return null;
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -705,9 +737,8 @@
             return mPM.isEphemeralApplication(
                     mContext.getPackageName(), mContext.getUserId());
         } catch (RemoteException e) {
-            Log.e(TAG, "System server is dead", e);
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     @Override
@@ -724,11 +755,12 @@
                     mContext.getPackageName(), mContext.getUserId());
             if (cookie != null) {
                 return cookie;
+            } else {
+                return EmptyArray.BYTE;
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "System server is dead", e);
+            throw e.rethrowFromSystemServer();
         }
-        return EmptyArray.BYTE;
     }
 
     @Override
@@ -737,9 +769,8 @@
             return mPM.setEphemeralApplicationCookie(
                     mContext.getPackageName(), cookie, mContext.getUserId());
         } catch (RemoteException e) {
-            Log.e(TAG, "System server is dead", e);
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     @Override
@@ -756,7 +787,7 @@
                 flags,
                 userId);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -768,20 +799,25 @@
 
     /** @hide Same as above but for a specific user */
     @Override
+    @SuppressWarnings("unchecked")
     public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
-                                                   int flags, int userId) {
+            int flags, int userId) {
         try {
-            return mPM.queryIntentActivities(
-                intent,
-                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags,
-                userId);
+            ParceledListSlice<ResolveInfo> parceledList =
+                    mPM.queryIntentActivities(intent,
+                            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                            flags, userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<ResolveInfo> queryIntentActivityOptions(
         ComponentName caller, Intent[] specifics, Intent intent,
         int flags) {
@@ -805,11 +841,15 @@
         }
 
         try {
-            return mPM.queryIntentActivityOptions(caller, specifics,
-                                                  specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
-                                                  flags, mContext.getUserId());
+            ParceledListSlice<ResolveInfo> parceledList =
+                    mPM.queryIntentActivityOptions(caller, specifics, specificTypes, intent,
+                    intent.resolveTypeIfNeeded(resolver), flags, mContext.getUserId());
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -817,15 +857,19 @@
      * @hide
      */
     @Override
+    @SuppressWarnings("unchecked")
     public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
         try {
-            return mPM.queryIntentReceivers(
-                intent,
-                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags,
-                userId);
+            ParceledListSlice<ResolveInfo> parceledList =
+                    mPM.queryIntentReceivers(intent,
+                            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                            flags,  userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -843,20 +887,24 @@
                 flags,
                 mContext.getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
         try {
-            return mPM.queryIntentServices(
-                intent,
-                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags,
-                userId);
+            ParceledListSlice<ResolveInfo> parceledList =
+                    mPM.queryIntentServices(intent,
+                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                    flags, userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -866,13 +914,20 @@
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<ResolveInfo> queryIntentContentProvidersAsUser(
             Intent intent, int flags, int userId) {
         try {
-            return mPM.queryIntentContentProviders(intent,
-                    intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, userId);
+            ParceledListSlice<ResolveInfo> parceledList =
+                    mPM.queryIntentContentProviders(intent,
+                            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                            flags, userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -892,19 +947,20 @@
         try {
             return mPM.resolveContentProvider(name, flags, userId);
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<ProviderInfo> queryContentProviders(String processName,
-                                                    int uid, int flags) {
+            int uid, int flags) {
         try {
-            ParceledListSlice<ProviderInfo> slice
-                    = mPM.queryContentProviders(processName, uid, flags);
-            return slice != null ? slice.getList() : null;
+            ParceledListSlice<ProviderInfo> slice =
+                    mPM.queryContentProviders(processName, uid, flags);
+            return slice != null ? slice.getList() : Collections.<ProviderInfo>emptyList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -919,19 +975,25 @@
                 return ii;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         throw new NameNotFoundException(className.toString());
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<InstrumentationInfo> queryInstrumentation(
         String targetPackage, int flags) {
         try {
-            return mPM.queryInstrumentation(targetPackage, flags);
+            ParceledListSlice<InstrumentationInfo> parceledList =
+                    mPM.queryInstrumentation(targetPackage, flags);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1096,6 +1158,14 @@
     }
 
     @Override
+    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+            int badgeDensity) {
+        Drawable badgeDrawable = getDrawableForDensity(
+            com.android.internal.R.drawable.ic_corp_badge, badgeDensity);
+        return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
+    }
+
+    @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         final int badgeResId = getBadgeResIdForUser(user.getIdentifier());
         if (badgeResId == 0) {
@@ -1117,32 +1187,33 @@
 
     @Override
     public Drawable getUserBadgeForDensity(UserHandle user, int density) {
-        return getManagedProfileIconForDensity(user, density,
-                com.android.internal.R.drawable.ic_corp_badge);
+        return getManagedProfileIconForDensity(user, com.android.internal.R.drawable.ic_corp_badge,
+                density);
     }
 
     @Override
     public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
-        return getManagedProfileIconForDensity(user, density,
-                com.android.internal.R.drawable.ic_corp_badge_no_background);
+        return getManagedProfileIconForDensity(user,
+                com.android.internal.R.drawable.ic_corp_badge_no_background, density);
     }
 
-    private Drawable getManagedProfileIconForDensity(UserHandle user, int density,
-            int drawableId) {
-        UserInfo userInfo = getUserIfProfile(user.getIdentifier());
-        if (userInfo != null && userInfo.isManagedProfile()) {
-            if (density <= 0) {
-                density = mContext.getResources().getDisplayMetrics().densityDpi;
-            }
-            return Resources.getSystem().getDrawableForDensity(drawableId, density);
+    private Drawable getDrawableForDensity(int drawableId, int density) {
+        if (density <= 0) {
+            density = mContext.getResources().getDisplayMetrics().densityDpi;
+        }
+        return Resources.getSystem().getDrawableForDensity(drawableId, density);
+    }
+
+    private Drawable getManagedProfileIconForDensity(UserHandle user, int drawableId, int density) {
+        if (isManagedProfile(user.getIdentifier())) {
+            return getDrawableForDensity(drawableId, density);
         }
         return null;
     }
 
     @Override
     public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
-        UserInfo userInfo = getUserIfProfile(user.getIdentifier());
-        if (userInfo != null && userInfo.isManagedProfile()) {
+        if (isManagedProfile(user.getIdentifier())) {
             return Resources.getSystem().getString(
                     com.android.internal.R.string.managed_profile_label_badge, label);
         }
@@ -1167,7 +1238,7 @@
                 sameUid ? app.sourceDir : app.publicSourceDir,
                 sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
                 app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
-                null, mContext.mPackageInfo);
+                mContext.mPackageInfo);
         if (r != null) {
             return r;
         }
@@ -1198,7 +1269,7 @@
                 return getResourcesForApplication(ai);
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
         throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
     }
@@ -1213,7 +1284,7 @@
             }
             return mCachedSafeMode != 0;
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1229,7 +1300,7 @@
                 mPM.addOnPermissionsChangeListener(delegate);
                 mPermissionListeners.put(listener, delegate);
             } catch (RemoteException e) {
-                throw new RuntimeException("Package manager has died", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1243,7 +1314,7 @@
                     mPM.removeOnPermissionsChangeListener(delegate);
                     mPermissionListeners.remove(listener);
                 } catch (RemoteException e) {
-                    throw new RuntimeException("Package manager has died", e);
+                    throw e.rethrowFromSystemServer();
                 }
             }
         }
@@ -1470,81 +1541,29 @@
     @Override
     public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                                String installerPackageName) {
-        final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID);
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, null, mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID);
-        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
+                installerPackageName, mContext.getUserId());
     }
 
     @Override
     public void installPackage(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName) {
-        installPackageAsUser(packageURI, observer, flags, installerPackageName,
-                mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
-               String installerPackageName, int userId) {
-        final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID);
-        installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
-                userId);
-    }
-
-    @Override
-    public void installPackageWithVerification(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID);
-        installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
-                encryptionParams, mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-        installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
-                encryptionParams, mContext.getUserId());
+        installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
     }
 
     private void installCommon(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams,
             int userId) {
         if (!"file".equals(packageURI.getScheme())) {
             throw new UnsupportedOperationException("Only file:// URIs are supported");
         }
-        if (encryptionParams != null) {
-            throw new UnsupportedOperationException("ContainerEncryptionParams not supported");
-        }
 
         final String originPath = packageURI.getPath();
         try {
             mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
-                    verificationParams, null, userId);
-        } catch (RemoteException ignored) {
+                    userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1563,8 +1582,7 @@
             }
             return res;
         } catch (RemoteException e) {
-            // Should never happen!
-            throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1573,7 +1591,7 @@
         try {
             mPM.verifyPendingInstall(id, response);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1583,16 +1601,16 @@
         try {
             mPM.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
-    public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains) {
+    public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
         try {
-            mPM.verifyIntentFilter(id, verificationCode, outFailedDomains);
+            mPM.verifyIntentFilter(id, verificationCode, failedDomains);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1601,8 +1619,7 @@
         try {
             return mPM.getIntentVerificationStatus(packageName, userId);
         } catch (RemoteException e) {
-            // Should never happen!
-            return PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1611,28 +1628,37 @@
         try {
             return mPM.updateIntentVerificationStatus(packageName, status, userId);
         } catch (RemoteException e) {
-            // Should never happen!
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
         try {
-            return mPM.getIntentFilterVerifications(packageName);
+            ParceledListSlice<IntentFilterVerificationInfo> parceledList =
+                    mPM.getIntentFilterVerifications(packageName);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            // Should never happen!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public List<IntentFilter> getAllIntentFilters(String packageName) {
         try {
-            return mPM.getAllIntentFilters(packageName);
+            ParceledListSlice<IntentFilter> parceledList =
+                    mPM.getAllIntentFilters(packageName);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
         } catch (RemoteException e) {
-            // Should never happen!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1641,8 +1667,7 @@
         try {
             return mPM.getDefaultBrowserPackageName(userId);
         } catch (RemoteException e) {
-            // Should never happen!
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1651,8 +1676,7 @@
         try {
             return mPM.setDefaultBrowserPackageName(packageName, userId);
         } catch (RemoteException e) {
-            // Should never happen!
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1662,7 +1686,7 @@
         try {
             mPM.setInstallerPackageName(targetPackage, installerPackageName);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1671,9 +1695,8 @@
         try {
             return mPM.getInstallerPackageName(packageName);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     @Override
@@ -1681,7 +1704,7 @@
         try {
             return mPM.getMoveStatus(moveId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1693,7 +1716,7 @@
             try {
                 mPM.registerMoveCallback(delegate);
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
             mDelegates.add(delegate);
         }
@@ -1708,7 +1731,7 @@
                     try {
                         mPM.unregisterMoveCallback(delegate);
                     } catch (RemoteException e) {
-                        throw e.rethrowAsRuntimeException();
+                        throw e.rethrowFromSystemServer();
                     }
                     i.remove();
                 }
@@ -1730,7 +1753,7 @@
 
             return mPM.movePackage(packageName, volumeUuid);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1796,7 +1819,7 @@
                 return false;
             }
         } catch (RemoteException e) {
-            throw new RuntimeException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
 
         // Otherwise we can move to any private volume
@@ -1817,7 +1840,7 @@
 
             return mPM.movePrimaryStorage(volumeUuid);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1874,7 +1897,7 @@
         try {
             mPM.deletePackageAsUser(packageName, observer, userId, flags);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1884,7 +1907,7 @@
         try {
             mPM.clearApplicationUserData(packageName, observer, mContext.getUserId());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
     @Override
@@ -1893,7 +1916,7 @@
         try {
             mPM.deleteApplicationCacheFiles(packageName, observer);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1903,7 +1926,7 @@
         try {
             mPM.freeStorageAndNotify(volumeUuid, idealStorageSize, observer);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1912,7 +1935,7 @@
         try {
             mPM.freeStorage(volumeUuid, freeStorageSize, pi);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1922,9 +1945,8 @@
         try {
             return mPM.setPackagesSuspendedAsUser(packageNames, suspended, userId);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return packageNames;
     }
 
     @Override
@@ -1932,9 +1954,8 @@
         try {
             return mPM.isPackageSuspendedForUser(packageName, userId);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     @Override
@@ -1943,35 +1964,24 @@
         try {
             mPM.getPackageSizeInfo(packageName, userHandle, observer);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
+
     @Override
     public void addPackageToPreferred(String packageName) {
-        try {
-            mPM.addPackageToPreferred(packageName);
-        } catch (RemoteException e) {
-            // Should never happen!
-        }
+        Log.w(TAG, "addPackageToPreferred() is a no-op");
     }
 
     @Override
     public void removePackageFromPreferred(String packageName) {
-        try {
-            mPM.removePackageFromPreferred(packageName);
-        } catch (RemoteException e) {
-            // Should never happen!
-        }
+        Log.w(TAG, "removePackageFromPreferred() is a no-op");
     }
 
     @Override
     public List<PackageInfo> getPreferredPackages(int flags) {
-        try {
-            return mPM.getPreferredPackages(flags);
-        } catch (RemoteException e) {
-            // Should never happen!
-        }
-        return new ArrayList<PackageInfo>();
+        Log.w(TAG, "getPreferredPackages() is a no-op");
+        return Collections.emptyList();
     }
 
     @Override
@@ -1980,7 +1990,7 @@
         try {
             mPM.addPreferredActivity(filter, match, set, activity, mContext.getUserId());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1990,7 +2000,7 @@
         try {
             mPM.addPreferredActivity(filter, match, set, activity, userId);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2000,7 +2010,7 @@
         try {
             mPM.replacePreferredActivity(filter, match, set, activity, mContext.getUserId());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2011,7 +2021,7 @@
         try {
             mPM.replacePreferredActivity(filter, match, set, activity, userId);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2020,7 +2030,7 @@
         try {
             mPM.clearPackagePreferredActivities(packageName);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2030,9 +2040,8 @@
         try {
             return mPM.getPreferredActivities(outFilters, outActivities, packageName);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return 0;
     }
 
     @Override
@@ -2040,9 +2049,8 @@
         try {
             return mPM.getHomeActivities(outActivities);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     @Override
@@ -2051,7 +2059,7 @@
         try {
             mPM.setComponentEnabledSetting(componentName, newState, flags, mContext.getUserId());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2060,9 +2068,8 @@
         try {
             return mPM.getComponentEnabledSetting(componentName, mContext.getUserId());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
     }
 
     @Override
@@ -2072,7 +2079,7 @@
             mPM.setApplicationEnabledSetting(packageName, newState, flags,
                     mContext.getUserId(), mContext.getOpPackageName());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2081,9 +2088,17 @@
         try {
             return mPM.getApplicationEnabledSetting(packageName, mContext.getUserId());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+    }
+
+    @Override
+    public void flushPackageRestrictionsAsUser(int userId) {
+        try {
+            mPM.flushPackageRestrictionsAsUser(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @Override
@@ -2092,20 +2107,18 @@
         try {
             return mPM.setApplicationHiddenSettingAsUser(packageName, hidden,
                     user.getIdentifier());
-        } catch (RemoteException re) {
-            // Should never happen!
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     @Override
     public boolean getApplicationHiddenSettingAsUser(String packageName, UserHandle user) {
         try {
             return mPM.getApplicationHiddenSettingAsUser(packageName, user.getIdentifier());
-        } catch (RemoteException re) {
-            // Should never happen!
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /** @hide */
@@ -2113,26 +2126,22 @@
     public KeySet getKeySetByAlias(String packageName, String alias) {
         Preconditions.checkNotNull(packageName);
         Preconditions.checkNotNull(alias);
-        KeySet ks;
         try {
-            ks = mPM.getKeySetByAlias(packageName, alias);
+            return mPM.getKeySetByAlias(packageName, alias);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
-        return ks;
     }
 
     /** @hide */
     @Override
     public KeySet getSigningKeySet(String packageName) {
         Preconditions.checkNotNull(packageName);
-        KeySet ks;
         try {
-            ks = mPM.getSigningKeySet(packageName);
+            return mPM.getSigningKeySet(packageName);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
-        return ks;
     }
 
     /** @hide */
@@ -2143,7 +2152,7 @@
         try {
             return mPM.isPackageSignedByKeySet(packageName, ks);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2155,7 +2164,7 @@
         try {
             return mPM.isPackageSignedByKeySetExactly(packageName, ks);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2167,9 +2176,8 @@
         try {
             return mPM.getVerifierDeviceIdentity();
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -2180,7 +2188,7 @@
         try {
             return mPM.isUpgrade();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2192,7 +2200,7 @@
                     mInstaller = new PackageInstaller(mContext, this, mPM.getPackageInstaller(),
                             mContext.getPackageName(), mContext.getUserId());
                 } catch (RemoteException e) {
-                    throw e.rethrowAsRuntimeException();
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return mInstaller;
@@ -2204,7 +2212,7 @@
         try {
             return mPM.isPackageAvailable(packageName, mContext.getUserId());
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2218,7 +2226,7 @@
             mPM.addCrossProfileIntentFilter(filter, mContext.getOpPackageName(),
                     sourceUserId, targetUserId, flags);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2230,7 +2238,7 @@
         try {
             mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2319,23 +2327,16 @@
         return drawable;
     }
 
-    private int getBadgeResIdForUser(int userHandle) {
+    private int getBadgeResIdForUser(int userId) {
         // Return the framework-provided badge.
-        UserInfo userInfo = getUserIfProfile(userHandle);
-        if (userInfo != null && userInfo.isManagedProfile()) {
+        if (isManagedProfile(userId)) {
             return com.android.internal.R.drawable.ic_corp_icon_badge;
         }
         return 0;
     }
 
-    private UserInfo getUserIfProfile(int userHandle) {
-        List<UserInfo> userProfiles = getUserManager().getProfiles(mContext.getUserId());
-        for (UserInfo user : userProfiles) {
-            if (user.id == userHandle) {
-                return user;
-            }
-        }
-        return null;
+    private boolean isManagedProfile(int userId) {
+        return getUserManager().isManagedProfile(userId);
     }
 
     /** {@hide} */
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 59ecc03..ea86dd0 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -548,11 +548,12 @@
             boolean dumpInfo = data.readInt() != 0;
             boolean dumpDalvik = data.readInt() != 0;
             boolean dumpSummaryOnly = data.readInt() != 0;
+            boolean dumpUnreachable = data.readInt() != 0;
             String[] args = data.readStringArray();
             if (fd != null) {
                 try {
                     dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo,
-                            dumpDalvik, dumpSummaryOnly, args);
+                            dumpDalvik, dumpSummaryOnly, dumpUnreachable, args);
                 } finally {
                     try {
                         fd.close();
@@ -735,7 +736,7 @@
             data.enforceInterface(IApplicationThread.descriptor);
             final IBinder b = data.readStrongBinder();
             final boolean inMultiWindow = data.readInt() != 0;
-            scheduleMultiWindowChanged(b, inMultiWindow);
+            scheduleMultiWindowModeChanged(b, inMultiWindow);
             return true;
         }
 
@@ -744,7 +745,7 @@
             data.enforceInterface(IApplicationThread.descriptor);
             final IBinder b = data.readStrongBinder();
             final boolean inPip = data.readInt() != 0;
-            schedulePictureInPictureChanged(b, inPip);
+            schedulePictureInPictureModeChanged(b, inPip);
             return true;
         }
 
@@ -1328,7 +1329,8 @@
     }
 
     public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
-            boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException {
+            boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
+            boolean dumpUnreachable, String[] args) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1338,6 +1340,7 @@
         data.writeInt(dumpInfo ? 1 : 0);
         data.writeInt(dumpDalvik ? 1 : 0);
         data.writeInt(dumpSummaryOnly ? 1 : 0);
+        data.writeInt(dumpUnreachable ? 1 : 0);
         data.writeStringArray(args);
         mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
         reply.readException();
@@ -1495,24 +1498,24 @@
     }
 
     @Override
-    public final void scheduleMultiWindowChanged(
-            IBinder token, boolean inMultiWindow) throws RemoteException {
+    public final void scheduleMultiWindowModeChanged(
+            IBinder token, boolean isInMultiWindowMode) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
-        data.writeInt(inMultiWindow ? 1 : 0);
+        data.writeInt(isInMultiWindowMode ? 1 : 0);
         mRemote.transact(SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
     }
 
     @Override
-    public final void schedulePictureInPictureChanged(IBinder token, boolean inPip)
+    public final void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
-        data.writeInt(inPip ? 1 : 0);
+        data.writeInt(isInPipMode ? 1 : 0);
         mRemote.transact(SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index e5fa02b..cd4ace6 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.app.NotificationManager.InterruptionFilter;
 import android.content.ComponentName;
 import android.net.Uri;
 import android.os.Parcel;
@@ -26,14 +27,13 @@
 /**
  * Rule instance information for zen mode.
  */
-public class AutomaticZenRule implements Parcelable {
+public final class AutomaticZenRule implements Parcelable {
 
     private boolean enabled = false;
     private String name;
-    private int interruptionFilter;
+    private @InterruptionFilter int interruptionFilter;
     private Uri conditionId;
     private ComponentName owner;
-    private String id;
     private long creationTime;
 
     /**
@@ -42,7 +42,7 @@
      * @param name The name of the rule.
      * @param owner The Condition Provider service that owns this rule.
      * @param conditionId A representation of the state that should cause the Condition Provider
-     *                    service to apply the interruption filter.
+     *                    service to apply the given interruption filter.
      * @param interruptionFilter The interruption filter defines which notifications are allowed to
      *                           interrupt the user (e.g. via sound &amp; vibration) while this rule
      *                           is active.
@@ -62,9 +62,8 @@
      * @hide
      */
     public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
-            int interruptionFilter, boolean enabled, String id, long creationTime) {
+            int interruptionFilter, boolean enabled, long creationTime) {
         this(name, owner, conditionId, interruptionFilter, enabled);
-        this.id = id;
         this.creationTime = creationTime;
     }
 
@@ -76,9 +75,6 @@
         interruptionFilter = source.readInt();
         conditionId = source.readParcelable(null);
         owner = source.readParcelable(null);
-        if (source.readInt() == 1) {
-            id = source.readString();
-        }
         creationTime = source.readLong();
     }
 
@@ -118,20 +114,13 @@
     }
 
     /**
-     * Returns the wall time in milliseconds when this rule was created, if known.
+     * Returns the time this rule was created, represented as milliseconds since the epoch.
      */
     public long getCreationTime() {
       return creationTime;
     }
 
     /**
-     * Returns the unique identifier for this rule.
-     */
-    public String getId() {
-      return id;
-    }
-
-    /**
      * Sets the representation of the state that causes this rule to become active.
      */
     public void setConditionId(Uri conditionId) {
@@ -140,9 +129,9 @@
 
     /**
      * Sets the interruption filter that is applied when this rule is active.
-     * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants in NotificationManager.
+     * @param interruptionFilter The do not disturb mode to enter when this rule is active.
      */
-    public void setInterruptionFilter(int interruptionFilter) {
+    public void setInterruptionFilter(@InterruptionFilter int interruptionFilter) {
         this.interruptionFilter = interruptionFilter;
     }
 
@@ -177,12 +166,6 @@
         dest.writeInt(interruptionFilter);
         dest.writeParcelable(conditionId, 0);
         dest.writeParcelable(owner, 0);
-        if (id != null) {
-            dest.writeInt(1);
-            dest.writeString(id);
-        } else {
-            dest.writeInt(0);
-        }
         dest.writeLong(creationTime);
     }
 
@@ -194,7 +177,6 @@
                 .append(",interruptionFilter=").append(interruptionFilter)
                 .append(",conditionId=").append(conditionId)
                 .append(",owner=").append(owner)
-                .append(",id=").append(id)
                 .append(",creationTime=").append(creationTime)
                 .append(']').toString();
     }
@@ -209,13 +191,12 @@
                 && other.interruptionFilter == interruptionFilter
                 && Objects.equals(other.conditionId, conditionId)
                 && Objects.equals(other.owner, owner)
-                && Objects.equals(other.id, id)
                 && other.creationTime == creationTime;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, id, creationTime);
+        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime);
     }
 
     public static final Parcelable.Creator<AutomaticZenRule> CREATOR
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index eb4b13e..1e2cc26 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -16,8 +16,6 @@
 
 package android.app;
 
-import com.android.internal.util.FastPrintWriter;
-
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,6 +31,8 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 
+import com.android.internal.util.FastPrintWriter;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -146,6 +146,10 @@
                     op.removed.add(r);
                 }
             }
+            bse.mEnterAnim = op.enterAnim;
+            bse.mExitAnim = op.exitAnim;
+            bse.mPopEnterAnim = op.popEnterAnim;
+            bse.mPopExitAnim = op.popExitAnim;
             bse.addOp(op);
             num++;
         }
@@ -470,6 +474,10 @@
         }
 
         if (containerViewId != 0) {
+            if (containerViewId == View.NO_ID) {
+                throw new IllegalArgumentException("Can't add fragment "
+                        + fragment + " with tag " + tag + " to container view with no id");
+            }
             if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
                 throw new IllegalStateException("Can't change container ID of fragment "
                         + fragment + ": was " + fragment.mFragmentId
@@ -713,10 +721,12 @@
 
         bumpBackStackNesting(1);
 
-        SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
-        SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-        calculateFragments(firstOutFragments, lastInFragments);
-        beginTransition(firstOutFragments, lastInFragments, false);
+        if (mManager.mCurState >= Fragment.CREATED) {
+            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
+            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
+            calculateFragments(firstOutFragments, lastInFragments);
+            beginTransition(firstOutFragments, lastInFragments, false);
+        }
 
         Op op = mHead;
         while (op != null) {
@@ -838,6 +848,14 @@
                     firstOutFragments.remove(containerId);
                 }
             }
+            /**
+             * Ensure that fragments that are entering are at least at the CREATED state
+             * so that they may load Transitions using TransitionInflater.
+             */
+            if (fragment.mState < Fragment.CREATED && mManager.mCurState >= Fragment.CREATED) {
+                mManager.makeActive(fragment);
+                mManager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
+            }
         }
     }
 
@@ -982,7 +1000,6 @@
      */
     private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments,
             SparseArray<Fragment> lastInFragments, boolean isBack) {
-        ensureFragmentsAreInitialized(lastInFragments);
         TransitionState state = new TransitionState();
 
         // Adding a non-existent target view makes sure that the transitions don't target
@@ -1008,21 +1025,6 @@
         return state;
     }
 
-    /**
-     * Ensure that fragments that are entering are at least at the CREATED state
-     * so that they may load Transitions using TransitionInflater.
-     */
-    private void ensureFragmentsAreInitialized(SparseArray<Fragment> lastInFragments) {
-        final int count = lastInFragments.size();
-        for (int i = 0; i < count; i++) {
-            final Fragment fragment = lastInFragments.valueAt(i);
-            if (fragment.mState < Fragment.CREATED) {
-                mManager.makeActive(fragment);
-                mManager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
-            }
-        }
-    }
-
     private static Transition cloneTransition(Transition transition) {
         if (transition != null) {
             transition = transition.clone();
@@ -1659,12 +1661,14 @@
             pw.flush();
         }
 
-        if (state == null) {
-            if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
-                state = beginTransition(firstOutFragments, lastInFragments, true);
+        if (mManager.mCurState >= Fragment.CREATED) {
+            if (state == null) {
+                if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
+                    state = beginTransition(firstOutFragments, lastInFragments, true);
+                }
+            } else if (!doStateMove) {
+                setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
             }
-        } else if (!doStateMove) {
-            setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
         }
 
         bumpBackStackNesting(-1);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8884949..6bb853a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -396,9 +396,11 @@
 
     /**
      * Try our best to migrate all files from source to target that match
-     * requested prefix. Return false if we have any trouble migrating.
+     * requested prefix.
+     *
+     * @return the number of files moved, or -1 if there was trouble.
      */
-    private static boolean migrateFiles(File sourceDir, File targetDir, final String prefix) {
+    private static int moveFiles(File sourceDir, File targetDir, final String prefix) {
         final File[] sourceFiles = FileUtils.listFilesOrEmpty(sourceDir, new FilenameFilter() {
             @Override
             public boolean accept(File dir, String name) {
@@ -406,7 +408,7 @@
             }
         });
 
-        boolean res = true;
+        int res = 0;
         for (File sourceFile : sourceFiles) {
             final File targetFile = new File(targetDir, sourceFile.getName());
             Log.d(TAG, "Migrating " + sourceFile + " to " + targetFile);
@@ -416,26 +418,34 @@
                 if (!sourceFile.delete()) {
                     throw new IOException("Failed to clean up " + sourceFile);
                 }
+                if (res != -1) {
+                    res++;
+                }
             } catch (IOException e) {
                 Log.w(TAG, "Failed to migrate " + sourceFile + ": " + e);
-                res = false;
+                res = -1;
             }
         }
         return res;
     }
 
     @Override
-    public boolean migrateSharedPreferencesFrom(Context sourceContext, String name) {
+    public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
         synchronized (ContextImpl.class) {
             final File source = sourceContext.getSharedPreferencesPath(name);
             final File target = getSharedPreferencesPath(name);
 
-            // Evict any in-memory caches for either location
-            final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
-            cache.remove(source);
-            cache.remove(target);
-
-            return migrateFiles(source.getParentFile(), target.getParentFile(), source.getName());
+            final int res = moveFiles(source.getParentFile(), target.getParentFile(),
+                    source.getName());
+            if (res > 0) {
+                // We moved at least one file, so evict any in-memory caches for
+                // either location
+                final ArrayMap<File, SharedPreferencesImpl> cache =
+                        getSharedPreferencesCacheLocked();
+                cache.remove(source);
+                cache.remove(target);
+            }
+            return res != -1;
         }
     }
 
@@ -671,11 +681,12 @@
     }
 
     @Override
-    public boolean migrateDatabaseFrom(Context sourceContext, String name) {
+    public boolean moveDatabaseFrom(Context sourceContext, String name) {
         synchronized (ContextImpl.class) {
             final File source = sourceContext.getDatabasePath(name);
             final File target = getDatabasePath(name);
-            return migrateFiles(source.getParentFile(), target.getParentFile(), source.getName());
+            return moveFiles(source.getParentFile(), target.getParentFile(),
+                    source.getName()) != -1;
         }
     }
 
@@ -792,7 +803,12 @@
     @Override
     public void startActivity(Intent intent, Bundle options) {
         warnIfCallingFromSystemProcess();
-        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
+
+        // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
+        // generally not allowed, except if the caller specifies the task id the activity should
+        // be launched in.
+        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
+                && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
             throw new AndroidRuntimeException(
                     "Calling startActivity() from outside of an Activity "
                     + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
@@ -813,7 +829,7 @@
                 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
                 user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -878,7 +894,7 @@
             }
             Instrumentation.checkStartActivityResult(result, null);
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -893,7 +909,7 @@
                     Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                     getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -910,7 +926,7 @@
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                     null, false, false, getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -925,7 +941,7 @@
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                     null, false, false, getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -942,7 +958,7 @@
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                     options, false, false, getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -959,7 +975,7 @@
                     Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
                     getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -976,7 +992,7 @@
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                     null, true, false, getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1039,7 +1055,7 @@
                 initialCode, initialData, initialExtras, receiverPermissions, appOp,
                     options, true, false, getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1052,7 +1068,7 @@
                     intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
                     AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1075,7 +1091,7 @@
                     Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
                     user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1126,7 +1142,7 @@
                 initialCode, initialData, initialExtras, receiverPermissions,
                     appOp, options, true, false, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1142,7 +1158,7 @@
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
                 getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1178,7 +1194,7 @@
                 initialCode, initialData, initialExtras, null,
                     AppOpsManager.OP_NONE, null, true, true, getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1195,7 +1211,7 @@
             ActivityManagerNative.getDefault().unbroadcastIntent(
                     mMainThread.getApplicationThread(), intent, getUserId());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1210,7 +1226,7 @@
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
                     user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1225,7 +1241,7 @@
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
                 user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1260,7 +1276,7 @@
                 initialCode, initialData, initialExtras, null,
                     AppOpsManager.OP_NONE, null, true, true, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1277,7 +1293,7 @@
             ActivityManagerNative.getDefault().unbroadcastIntent(
                     mMainThread.getApplicationThread(), intent, user.getIdentifier());
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1321,11 +1337,16 @@
             }
         }
         try {
-            return ActivityManagerNative.getDefault().registerReceiver(
+            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                     mMainThread.getApplicationThread(), mBasePackageName,
                     rd, filter, broadcastPermission, userId);
+            if (intent != null) {
+                intent.setExtrasClassLoader(getClassLoader());
+                intent.prepareToEnterProcess();
+            }
+            return intent;
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1337,6 +1358,7 @@
             try {
                 ActivityManagerNative.getDefault().unregisterReceiver(rd);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         } else {
             throw new RuntimeException("Not supported in system context");
@@ -1393,7 +1415,7 @@
             }
             return cn;
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1415,7 +1437,7 @@
             }
             return res != 0;
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1474,7 +1496,7 @@
             }
             return res != 0;
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1489,6 +1511,7 @@
             try {
                 ActivityManagerNative.getDefault().unbindService(sd);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         } else {
             throw new RuntimeException("Not supported in system context");
@@ -1506,7 +1529,7 @@
                     className, profileFile, 0, arguments, null, null, getUserId(),
                     null /* ABI override */);
         } catch (RemoteException e) {
-            throw new RuntimeException("Failure from system", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1530,7 +1553,7 @@
             return ActivityManagerNative.getDefault().checkPermission(
                     permission, pid, uid);
         } catch (RemoteException e) {
-            return PackageManager.PERMISSION_DENIED;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1545,7 +1568,7 @@
             return ActivityManagerNative.getDefault().checkPermissionWithToken(
                     permission, pid, uid, callerToken);
         } catch (RemoteException e) {
-            return PackageManager.PERMISSION_DENIED;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1631,6 +1654,7 @@
                     mMainThread.getApplicationThread(), toPackage,
                     ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1641,6 +1665,7 @@
                     mMainThread.getApplicationThread(),
                     ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1651,7 +1676,7 @@
                     ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
                     resolveUserId(uri), null);
         } catch (RemoteException e) {
-            return PackageManager.PERMISSION_DENIED;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1663,7 +1688,7 @@
                     ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
                     resolveUserId(uri), callerToken);
         } catch (RemoteException e) {
-            return PackageManager.PERMISSION_DENIED;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1885,17 +1910,17 @@
     }
 
     @Override
-    public Context createDeviceEncryptedStorageContext() {
-        final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE)
-                | Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE;
+    public Context createDeviceProtectedStorageContext() {
+        final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
+                | Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
                 mUser, flags, mDisplay, null, Display.INVALID_DISPLAY);
     }
 
     @Override
-    public Context createCredentialEncryptedStorageContext() {
-        final int flags = (mFlags & ~Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE)
-                | Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE;
+    public Context createCredentialProtectedStorageContext() {
+        final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
+                | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
                 mUser, flags, mDisplay, null, Display.INVALID_DISPLAY);
     }
@@ -1906,13 +1931,13 @@
     }
 
     @Override
-    public boolean isDeviceEncryptedStorage() {
-        return (mFlags & Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE) != 0;
+    public boolean isDeviceProtectedStorage() {
+        return (mFlags & Context.CONTEXT_DEVICE_PROTECTED_STORAGE) != 0;
     }
 
     @Override
-    public boolean isCredentialEncryptedStorage() {
-        return (mFlags & Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE) != 0;
+    public boolean isCredentialProtectedStorage() {
+        return (mFlags & Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) != 0;
     }
 
     @Override
@@ -1924,10 +1949,10 @@
     public File getDataDir() {
         if (mPackageInfo != null) {
             File res = null;
-            if (isCredentialEncryptedStorage()) {
-                res = mPackageInfo.getCredentialEncryptedDataDirFile();
-            } else if (isDeviceEncryptedStorage()) {
-                res = mPackageInfo.getDeviceEncryptedDataDirFile();
+            if (isCredentialProtectedStorage()) {
+                res = mPackageInfo.getCredentialProtectedDataDirFile();
+            } else if (isDeviceProtectedStorage()) {
+                res = mPackageInfo.getDeviceProtectedDataDirFile();
             } else {
                 res = mPackageInfo.getDataDirFile();
             }
@@ -1968,7 +1993,7 @@
         ContextImpl context = new ContextImpl(null, mainThread,
                 packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
-                context.mResourcesManager.getDisplayMetricsLocked());
+                context.mResourcesManager.getDisplayMetrics());
         return context;
     }
 
@@ -1979,9 +2004,10 @@
     }
 
     static ContextImpl createActivityContext(ActivityThread mainThread,
-            LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
+            LoadedApk packageInfo, IBinder activityToken, int displayId,
+            Configuration overrideConfiguration) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
-        return new ContextImpl(null, mainThread, packageInfo, null, null, 0,
+        return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
                 null, overrideConfiguration, displayId);
     }
 
@@ -1992,13 +2018,13 @@
 
         // If creator didn't specify which storage to use, use the default
         // location for application.
-        if ((flags & (Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE
-                | Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE)) == 0) {
+        if ((flags & (Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE
+                | Context.CONTEXT_DEVICE_PROTECTED_STORAGE)) == 0) {
             final File dataDir = packageInfo.getDataDirFile();
-            if (Objects.equals(dataDir, packageInfo.getCredentialEncryptedDataDirFile())) {
-                flags |= Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE;
-            } else if (Objects.equals(dataDir, packageInfo.getDeviceEncryptedDataDirFile())) {
-                flags |= Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE;
+            if (Objects.equals(dataDir, packageInfo.getCredentialProtectedDataDirFile())) {
+                flags |= Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
+            } else if (Objects.equals(dataDir, packageInfo.getDeviceProtectedDataDirFile())) {
+                flags |= Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
             }
         }
 
@@ -2039,10 +2065,34 @@
                     || overrideConfiguration != null
                     || (compatInfo != null && compatInfo.applicationScale
                             != resources.getCompatibilityInfo().applicationScale)) {
-                resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
-                        packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
-                        packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
-                        overrideConfiguration, compatInfo, packageInfo.getClassLoader());
+
+                if (container != null) {
+                    // This is a nested Context, so it can't be a base Activity context.
+                    // Just create a regular Resources object associated with the Activity.
+                    resources = mResourcesManager.getResources(
+                            activityToken,
+                            packageInfo.getResDir(),
+                            packageInfo.getSplitResDirs(),
+                            packageInfo.getOverlayDirs(),
+                            packageInfo.getApplicationInfo().sharedLibraryFiles,
+                            displayId,
+                            overrideConfiguration,
+                            compatInfo,
+                            packageInfo.getClassLoader());
+                } else {
+                    // This is not a nested Context, so it must be the root Activity context.
+                    // All other nested Contexts will inherit the configuration set here.
+                    resources = mResourcesManager.createBaseActivityResources(
+                            activityToken,
+                            packageInfo.getResDir(),
+                            packageInfo.getSplitResDirs(),
+                            packageInfo.getOverlayDirs(),
+                            packageInfo.getApplicationInfo().sharedLibraryFiles,
+                            displayId,
+                            overrideConfiguration,
+                            compatInfo,
+                            packageInfo.getClassLoader());
+                }
             }
         }
         mResources = resources;
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index bbf1607..bd55a06 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -58,7 +58,7 @@
      * @param context the parent context
      */
     public DatePickerDialog(@NonNull Context context) {
-        this(context, 0);
+        this(context, 0, null, Calendar.getInstance(), -1, -1, -1);
     }
 
     /**
@@ -70,24 +70,7 @@
      *                   {@code context}'s default alert dialog theme
      */
     public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId) {
-        super(context, resolveDialogTheme(context, themeResId));
-
-        final Context themeContext = getContext();
-        final LayoutInflater inflater = LayoutInflater.from(themeContext);
-        final View view = inflater.inflate(R.layout.date_picker_dialog, null);
-        setView(view);
-
-        setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
-        setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
-        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
-
-        final Calendar calendar = Calendar.getInstance();
-        final int year = calendar.get(Calendar.YEAR);
-        final int monthOfYear = calendar.get(Calendar.MONTH);
-        final int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
-        mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
-        mDatePicker.init(year, monthOfYear, dayOfMonth, this);
-        mDatePicker.setValidationCallback(mValidationCallback);
+        this(context, themeResId, null, Calendar.getInstance(), -1, -1, -1);
     }
 
     /**
@@ -104,7 +87,7 @@
      */
     public DatePickerDialog(@NonNull Context context, @Nullable OnDateSetListener listener,
             int year, int month, int dayOfMonth) {
-        this(context, 0, listener, year, month, dayOfMonth);
+        this(context, 0, listener, null, year, month, dayOfMonth);
     }
 
     /**
@@ -116,18 +99,41 @@
      *                   {@code context}'s default alert dialog theme
      * @param listener the listener to call when the user sets the date
      * @param year the initially selected year
-     * @param month the initially selected month (0-11 for compatibility with
-     *              {@link Calendar#MONTH})
+     * @param monthOfYear the initially selected month of the year (0-11 for
+     *                    compatibility with {@link Calendar#MONTH})
      * @param dayOfMonth the initially selected day of month (1-31, depending
      *                   on month)
      */
     public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
-            @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
-        this(context, themeResId);
+            @Nullable OnDateSetListener listener, int year, int monthOfYear, int dayOfMonth) {
+        this(context, themeResId, listener, null, year, monthOfYear, dayOfMonth);
+    }
+
+    private DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
+            @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year,
+            int monthOfYear, int dayOfMonth) {
+        super(context, resolveDialogTheme(context, themeResId));
+
+        final Context themeContext = getContext();
+        final LayoutInflater inflater = LayoutInflater.from(themeContext);
+        final View view = inflater.inflate(R.layout.date_picker_dialog, null);
+        setView(view);
+
+        setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
+        setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
+        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
+
+        if (calendar != null) {
+            year = calendar.get(Calendar.YEAR);
+            monthOfYear = calendar.get(Calendar.MONTH);
+            dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+        }
+
+        mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
+        mDatePicker.init(year, monthOfYear, dayOfMonth, this);
+        mDatePicker.setValidationCallback(mValidationCallback);
 
         mDateSetListener = listener;
-
-        mDatePicker.updateDate(year, month, dayOfMonth);
     }
 
     static @StyleRes int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 79461b4..85a0403 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,6 +16,10 @@
 
 package android.app;
 
+import com.android.internal.R;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.PhoneWindow;
+
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
@@ -43,7 +47,6 @@
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -57,12 +60,7 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.internal.R;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.PhoneWindow;
-
 import java.lang.ref.WeakReference;
-import java.util.List;
 
 /**
  * Base class for Dialogs.
@@ -94,11 +92,14 @@
         KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
     private static final String TAG = "Dialog";
     private Activity mOwnerActivity;
-    
+
+    private final WindowManager mWindowManager;
+
     final Context mContext;
-    final WindowManager mWindowManager;
-    Window mWindow;
+    final Window mWindow;
+
     View mDecor;
+
     private ActionBar mActionBar;
     /**
      * This field should be made private, so it is hidden from the SDK.
@@ -123,7 +124,7 @@
     private static final int CANCEL = 0x44;
     private static final int SHOW = 0x45;
 
-    private Handler mListenersHandler;
+    private final Handler mListenersHandler;
 
     private SearchEvent mSearchEvent;
 
@@ -131,11 +132,7 @@
 
     private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
 
-    private final Runnable mDismissAction = new Runnable() {
-        public void run() {
-            dismissDialog();
-        }
-    };
+    private final Runnable mDismissAction = this::dismissDialog;
 
     /**
      * Creates a dialog window that uses the default dialog theme.
@@ -198,14 +195,15 @@
      * @hide
      */
     @Deprecated
-    protected Dialog(@NonNull Context context, boolean cancelable, Message cancelCallback) {
+    protected Dialog(@NonNull Context context, boolean cancelable,
+            @Nullable Message cancelCallback) {
         this(context);
         mCancelable = cancelable;
         mCancelMessage = cancelCallback;
     }
 
     protected Dialog(@NonNull Context context, boolean cancelable,
-            OnCancelListener cancelListener) {
+            @Nullable OnCancelListener cancelListener) {
         this(context);
         mCancelable = cancelable;
         setOnCancelListener(cancelListener);
@@ -216,8 +214,7 @@
      * 
      * @return Context The Context used by the Dialog.
      */
-    @NonNull
-    public final Context getContext() {
+    public final @NonNull Context getContext() {
         return mContext;
     }
 
@@ -226,7 +223,7 @@
      *
      * @return The ActionBar attached to the dialog or null if no ActionBar is present.
      */
-    public ActionBar getActionBar() {
+    public @Nullable ActionBar getActionBar() {
         return mActionBar;
     }
 
@@ -236,7 +233,7 @@
      * 
      * @param activity The Activity that owns this dialog.
      */
-    public final void setOwnerActivity(Activity activity) {
+    public final void setOwnerActivity(@NonNull Activity activity) {
         mOwnerActivity = activity;
         
         getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream());
@@ -250,7 +247,7 @@
      * 
      * @return The Activity that owns this Dialog.
      */
-    public final Activity getOwnerActivity() {
+    public final @Nullable Activity getOwnerActivity() {
         return mOwnerActivity;
     }
     
@@ -316,13 +313,10 @@
             l = nl;
         }
 
-        try {
-            mWindowManager.addView(mDecor, l);
-            mShowing = true;
-    
-            sendShowMessage();
-        } finally {
-        }
+        mWindowManager.addView(mDecor, l);
+        mShowing = true;
+
+        sendShowMessage();
     }
     
     /**
@@ -388,7 +382,7 @@
         }
     }
 
-    // internal method to make sure mcreated is set properly without requiring
+    // internal method to make sure mCreated is set properly without requiring
     // users to call through to super in onCreate
     void dispatchOnCreate(Bundle savedInstanceState) {
         if (!mCreated) {
@@ -400,7 +394,7 @@
     /**
      * Similar to {@link Activity#onCreate}, you should initialize your dialog
      * in this method, including calling {@link #setContentView}.
-     * @param savedInstanceState If this dialog is being reinitalized after a
+     * @param savedInstanceState If this dialog is being reinitialized after a
      *     the hosting activity was previously shut down, holds the result from
      *     the most recent call to {@link #onSaveInstanceState}, or null if this
      *     is the first time.
@@ -433,7 +427,7 @@
      * state.
      * @return A bundle with the state of the dialog.
      */
-    public Bundle onSaveInstanceState() {
+    public @NonNull Bundle onSaveInstanceState() {
         Bundle bundle = new Bundle();
         bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);
         if (mCreated) {
@@ -452,7 +446,7 @@
      * @param savedInstanceState The state of the dialog previously saved by
      *     {@link #onSaveInstanceState()}.
      */
-    public void onRestoreInstanceState(Bundle savedInstanceState) {
+    public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
         final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);
         if (dialogHierarchyState == null) {
             // dialog has never been shown, or onCreated, nothing to restore.
@@ -473,7 +467,7 @@
      * @return Window The current window, or null if the activity is not
      *         visual.
      */
-    public Window getWindow() {
+    public @Nullable Window getWindow() {
         return mWindow;
     }
 
@@ -486,7 +480,7 @@
      * @see #getWindow
      * @see android.view.Window#getCurrentFocus
      */
-    public View getCurrentFocus() {
+    public @Nullable View getCurrentFocus() {
         return mWindow != null ? mWindow.getCurrentFocus() : null;
     }
 
@@ -498,8 +492,7 @@
      * @param id the identifier of the view to find
      * @return The view with the given id or null.
      */
-    @Nullable
-    public View findViewById(@IdRes int id) {
+    public @Nullable View findViewById(@IdRes int id) {
         return mWindow.findViewById(id);
     }
 
@@ -520,19 +513,19 @@
      * 
      * @param view The desired content to display.
      */
-    public void setContentView(View view) {
+    public void setContentView(@NonNull View view) {
         mWindow.setContentView(view);
     }
 
     /**
      * Set the screen content to an explicit view.  This view is placed
      * directly into the screen's view hierarchy.  It can itself be a complex
-     * view hierarhcy.
+     * view hierarchy.
      * 
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
      */
-    public void setContentView(View view, ViewGroup.LayoutParams params) {
+    public void setContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
         mWindow.setContentView(view, params);
     }
 
@@ -543,7 +536,7 @@
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
      */
-    public void addContentView(View view, ViewGroup.LayoutParams params) {
+    public void addContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
         mWindow.addContentView(view, params);
     }
 
@@ -552,7 +545,7 @@
      * 
      * @param title The new text to display in the title.
      */
-    public void setTitle(CharSequence title) {
+    public void setTitle(@Nullable CharSequence title) {
         mWindow.setTitle(title);
         mWindow.getAttributes().setTitle(title);
     }
@@ -578,7 +571,8 @@
      * @see #onKeyUp
      * @see android.view.KeyEvent
      */
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
+    @Override
+    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK) {
             event.startTracking();
             return true;
@@ -592,7 +586,8 @@
      * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
      * the event).
      */
-    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+    @Override
+    public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) {
         return false;
     }
 
@@ -605,7 +600,8 @@
      * @see #onKeyDown
      * @see KeyEvent
      */
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
+    @Override
+    public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
                 && !event.isCanceled()) {
             onBackPressed();
@@ -619,7 +615,8 @@
      * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
      * the event).
      */
-    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+    @Override
+    public boolean onKeyMultiple(int keyCode, int repeatCount, @NonNull KeyEvent event) {
         return false;
     }
     
@@ -644,7 +641,7 @@
      * @param event Description of the key event.
      * @return True if the key shortcut was handled.
      */
-    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+    public boolean onKeyShortcut(int keyCode, @NonNull KeyEvent event) {
         return false;
     }
 
@@ -658,7 +655,7 @@
      *         The default implementation will cancel the dialog when a touch
      *         happens outside of the window bounds.
      */
-    public boolean onTouchEvent(MotionEvent event) {
+    public boolean onTouchEvent(@NonNull MotionEvent event) {
         if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
             cancel();
             return true;
@@ -681,7 +678,7 @@
      * @return Return true if you have consumed the event, false if you haven't.
      * The default implementation always returns false.
      */
-    public boolean onTrackballEvent(MotionEvent event) {
+    public boolean onTrackballEvent(@NonNull MotionEvent event) {
         return false;
     }
 
@@ -710,25 +707,30 @@
      * @return Return true if you have consumed the event, false if you haven't.
      * The default implementation always returns false.
      */
-    public boolean onGenericMotionEvent(MotionEvent event) {
+    public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
         return false;
     }
 
+    @Override
     public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
         if (mDecor != null) {
             mWindowManager.updateViewLayout(mDecor, params);
         }
     }
 
+    @Override
     public void onContentChanged() {
     }
 
+    @Override
     public void onWindowFocusChanged(boolean hasFocus) {
     }
 
+    @Override
     public void onAttachedToWindow() {
     }
 
+    @Override
     public void onDetachedFromWindow() {
     }
 
@@ -747,7 +749,8 @@
      *
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchKeyEvent(KeyEvent event) {
+    @Override
+    public boolean dispatchKeyEvent(@NonNull KeyEvent event) {
         if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) {
             return true;
         }
@@ -767,7 +770,8 @@
      * @param event The key shortcut event.
      * @return True if this event was consumed.
      */
-    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+    @Override
+    public boolean dispatchKeyShortcutEvent(@NonNull KeyEvent event) {
         if (mWindow.superDispatchKeyShortcutEvent(event)) {
             return true;
         }
@@ -784,7 +788,8 @@
      * 
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchTouchEvent(MotionEvent ev) {
+    @Override
+    public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
         if (mWindow.superDispatchTouchEvent(ev)) {
             return true;
         }
@@ -801,7 +806,8 @@
      * 
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchTrackballEvent(MotionEvent ev) {
+    @Override
+    public boolean dispatchTrackballEvent(@NonNull MotionEvent ev) {
         if (mWindow.superDispatchTrackballEvent(ev)) {
             return true;
         }
@@ -818,14 +824,16 @@
      *
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+    @Override
+    public boolean dispatchGenericMotionEvent(@NonNull MotionEvent ev) {
         if (mWindow.superDispatchGenericMotionEvent(ev)) {
             return true;
         }
         return onGenericMotionEvent(ev);
     }
 
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
         event.setClassName(getClass().getName());
         event.setPackageName(mContext.getPackageName());
 
@@ -840,6 +848,7 @@
     /**
      * @see Activity#onCreatePanelView(int)
      */
+    @Override
     public View onCreatePanelView(int featureId) {
         return null;
     }
@@ -847,7 +856,8 @@
     /**
      * @see Activity#onCreatePanelMenu(int, Menu)
      */
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+    @Override
+    public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             return onCreateOptionsMenu(menu);
         }
@@ -858,10 +868,10 @@
     /**
      * @see Activity#onPreparePanel(int, View, Menu)
      */
+    @Override
     public boolean onPreparePanel(int featureId, View view, Menu menu) {
         if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
-            boolean goforit = onPrepareOptionsMenu(menu);
-            return goforit && menu.hasVisibleItems();
+            return onPrepareOptionsMenu(menu) && menu.hasVisibleItems();
         }
         return true;
     }
@@ -869,6 +879,7 @@
     /**
      * @see Activity#onMenuOpened(int, Menu)
      */
+    @Override
     public boolean onMenuOpened(int featureId, Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(true);
@@ -879,6 +890,7 @@
     /**
      * @see Activity#onMenuItemSelected(int, MenuItem)
      */
+    @Override
     public boolean onMenuItemSelected(int featureId, MenuItem item) {
         return false;
     }
@@ -886,6 +898,7 @@
     /**
      * @see Activity#onPanelClosed(int, Menu)
      */
+    @Override
     public void onPanelClosed(int featureId, Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(false);
@@ -900,7 +913,7 @@
      * @see Activity#onCreateOptionsMenu(Menu)
      * @see #getOwnerActivity()
      */
-    public boolean onCreateOptionsMenu(Menu menu) {
+    public boolean onCreateOptionsMenu(@NonNull Menu menu) {
         return true;
     }
 
@@ -912,21 +925,21 @@
      * @see Activity#onPrepareOptionsMenu(Menu)
      * @see #getOwnerActivity()
      */
-    public boolean onPrepareOptionsMenu(Menu menu) {
+    public boolean onPrepareOptionsMenu(@NonNull Menu menu) {
         return true;
     }
 
     /**
      * @see Activity#onOptionsItemSelected(MenuItem)
      */
-    public boolean onOptionsItemSelected(MenuItem item) {
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
         return false;
     }
 
     /**
      * @see Activity#onOptionsMenuClosed(Menu)
      */
-    public void onOptionsMenuClosed(Menu menu) {
+    public void onOptionsMenuClosed(@NonNull Menu menu) {
     }
 
     /**
@@ -959,47 +972,49 @@
     /**
      * @see Activity#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)
      */
+    @Override
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
     }
 
     /**
      * @see Activity#registerForContextMenu(View)
      */
-    public void registerForContextMenu(View view) {
+    public void registerForContextMenu(@NonNull View view) {
         view.setOnCreateContextMenuListener(this);
     }
     
     /**
      * @see Activity#unregisterForContextMenu(View)
      */
-    public void unregisterForContextMenu(View view) {
+    public void unregisterForContextMenu(@NonNull View view) {
         view.setOnCreateContextMenuListener(null);
     }
     
     /**
      * @see Activity#openContextMenu(View)
      */
-    public void openContextMenu(View view) {
+    public void openContextMenu(@NonNull View view) {
         view.showContextMenu();
     }
 
     /**
      * @see Activity#onContextItemSelected(MenuItem)
      */
-    public boolean onContextItemSelected(MenuItem item) {
+    public boolean onContextItemSelected(@NonNull MenuItem item) {
         return false;
     }
 
     /**
      * @see Activity#onContextMenuClosed(Menu)
      */
-    public void onContextMenuClosed(Menu menu) {
+    public void onContextMenuClosed(@NonNull Menu menu) {
     }
 
     /**
      * This hook is called when the user signals the desire to start a search.
      */
-    public boolean onSearchRequested(SearchEvent searchEvent) {
+    @Override
+    public boolean onSearchRequested(@NonNull SearchEvent searchEvent) {
         mSearchEvent = searchEvent;
         return onSearchRequested();
     }
@@ -1007,6 +1022,7 @@
     /**
      * This hook is called when the user signals the desire to start a search.
      */
+    @Override
     public boolean onSearchRequested() {
         final SearchManager searchManager = (SearchManager) mContext
                 .getSystemService(Context.SEARCH_SERVICE);
@@ -1029,13 +1045,10 @@
      * @return SearchEvent The SearchEvent that triggered the {@link
      *                    #onSearchRequested} callback.
      */
-    public final SearchEvent getSearchEvent() {
+    public final @Nullable SearchEvent getSearchEvent() {
         return mSearchEvent;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         if (mActionBar != null && mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) {
@@ -1044,9 +1057,6 @@
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
         try {
@@ -1063,6 +1073,7 @@
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeStarted(mode).
      */
+    @Override
     @CallSuper
     public void onActionModeStarted(ActionMode mode) {
         mActionMode = mode;
@@ -1074,6 +1085,7 @@
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeFinished(mode).
      */
+    @Override
     @CallSuper
     public void onActionModeFinished(ActionMode mode) {
         if (mode == mActionMode) {
@@ -1082,13 +1094,6 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
-    }
-
-    /**
      * @return The activity associated with this dialog, or null if there is no associated activity.
      */
     private ComponentName getAssociatedActivity() {
@@ -1146,7 +1151,7 @@
      * Convenience for calling
      * {@link android.view.Window#setFeatureDrawableUri}.
      */
-    public final void setFeatureDrawableUri(int featureId, Uri uri) {
+    public final void setFeatureDrawableUri(int featureId, @Nullable Uri uri) {
         getWindow().setFeatureDrawableUri(featureId, uri);
     }
 
@@ -1154,7 +1159,7 @@
      * Convenience for calling
      * {@link android.view.Window#setFeatureDrawable(int, Drawable)}.
      */
-    public final void setFeatureDrawable(int featureId, Drawable drawable) {
+    public final void setFeatureDrawable(int featureId, @Nullable Drawable drawable) {
         getWindow().setFeatureDrawable(featureId, drawable);
     }
 
@@ -1166,7 +1171,7 @@
         getWindow().setFeatureDrawableAlpha(featureId, alpha);
     }
 
-    public LayoutInflater getLayoutInflater() {
+    public @NonNull LayoutInflater getLayoutInflater() {
         return getWindow().getLayoutInflater();
     }
 
@@ -1198,6 +1203,7 @@
      * Cancel the dialog.  This is essentially the same as calling {@link #dismiss()}, but it will
      * also call your {@link DialogInterface.OnCancelListener} (if registered).
      */
+    @Override
     public void cancel() {
         if (!mCanceled && mCancelMessage != null) {
             mCanceled = true;
@@ -1218,7 +1224,7 @@
      * 
      * @param listener The {@link DialogInterface.OnCancelListener} to use.
      */
-    public void setOnCancelListener(final OnCancelListener listener) {
+    public void setOnCancelListener(@Nullable OnCancelListener listener) {
         if (mCancelAndDismissTaken != null) {
             throw new IllegalStateException(
                     "OnCancelListener is already taken by "
@@ -1236,7 +1242,7 @@
      * @param msg The msg to send when the dialog is canceled.
      * @see #setOnCancelListener(android.content.DialogInterface.OnCancelListener)
      */
-    public void setCancelMessage(final Message msg) {
+    public void setCancelMessage(@Nullable Message msg) {
         mCancelMessage = msg;
     }
 
@@ -1244,7 +1250,7 @@
      * Set a listener to be invoked when the dialog is dismissed.
      * @param listener The {@link DialogInterface.OnDismissListener} to use.
      */
-    public void setOnDismissListener(final OnDismissListener listener) {
+    public void setOnDismissListener(@Nullable OnDismissListener listener) {
         if (mCancelAndDismissTaken != null) {
             throw new IllegalStateException(
                     "OnDismissListener is already taken by "
@@ -1261,7 +1267,7 @@
      * Sets a listener to be invoked when the dialog is shown.
      * @param listener The {@link DialogInterface.OnShowListener} to use.
      */
-    public void setOnShowListener(OnShowListener listener) {
+    public void setOnShowListener(@Nullable OnShowListener listener) {
         if (listener != null) {
             mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
         } else {
@@ -1273,13 +1279,13 @@
      * Set a message to be sent when the dialog is dismissed.
      * @param msg The msg to send when the dialog is dismissed.
      */
-    public void setDismissMessage(final Message msg) {
+    public void setDismissMessage(@Nullable Message msg) {
         mDismissMessage = msg;
     }
 
     /** @hide */
-    public boolean takeCancelAndDismissListeners(String msg, final OnCancelListener cancel,
-            final OnDismissListener dismiss) {
+    public boolean takeCancelAndDismissListeners(@Nullable String msg,
+            @Nullable OnCancelListener cancel, @Nullable OnDismissListener dismiss) {
         if (mCancelAndDismissTaken != null) {
             mCancelAndDismissTaken = null;
         } else if (mCancelMessage != null || mDismissMessage != null) {
@@ -1313,15 +1319,15 @@
     /**
      * Sets the callback that will be called if a key is dispatched to the dialog.
      */
-    public void setOnKeyListener(final OnKeyListener onKeyListener) {
+    public void setOnKeyListener(@Nullable OnKeyListener onKeyListener) {
         mOnKeyListener = onKeyListener;
     }
 
     private static final class ListenersHandler extends Handler {
-        private WeakReference<DialogInterface> mDialog;
+        private final WeakReference<DialogInterface> mDialog;
 
         public ListenersHandler(Dialog dialog) {
-            mDialog = new WeakReference<DialogInterface>(dialog);
+            mDialog = new WeakReference<>(dialog);
         }
 
         @Override
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 1e5f007..e681d47 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1366,7 +1366,7 @@
                     return getLocalUri();
                 case COLUMN_LOCAL_FILENAME:
                     if (!mAccessFilename) {
-                        throw new IllegalArgumentException(
+                        throw new SecurityException(
                                 "COLUMN_LOCAL_FILENAME is deprecated;"
                                         + " use ContentResolver.openFileDescriptor() instead");
                     }
@@ -1380,7 +1380,7 @@
             if (destinationType == Downloads.Impl.DESTINATION_FILE_URI ||
                     destinationType == Downloads.Impl.DESTINATION_EXTERNAL ||
                     destinationType == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) {
-                String localPath = getString(getColumnIndex(COLUMN_LOCAL_FILENAME));
+                String localPath = super.getString(getColumnIndex(COLUMN_LOCAL_FILENAME));
                 if (localPath == null) {
                     return null;
                 }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index ddd0ae9..a599584 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -244,6 +244,10 @@
         }
     }
 
+    public boolean isWaitingForRemoteExit() {
+        return mIsReturning && mResultReceiver != null;
+    }
+
     /**
      * This is called onResume. If an Activity is resuming and the transitions
      * haven't started yet, force the views to appear. This is likely to be
@@ -288,6 +292,10 @@
             cancelPendingTransitions();
         }
         mAreViewsReady = true;
+        if (mResultReceiver != null) {
+            mResultReceiver.send(MSG_CANCEL, null);
+            mResultReceiver = null;
+        }
     }
 
     private void cancel() {
@@ -537,12 +545,10 @@
                 setTransitioningViewsVisiblity(View.INVISIBLE, false);
             }
             TransitionManager.beginDelayedTransition(decorView, transition);
-            if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
-                mSharedElements.get(0).invalidate();
-            }
             if (startEnterTransition) {
-                setTransitioningViewsVisiblity(View.VISIBLE, true);
+                setTransitioningViewsVisiblity(View.VISIBLE, false);
             }
+            decorView.invalidate();
         } else {
             transitionStarted();
         }
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index d54ffa0..0404288 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -100,6 +100,10 @@
                 mExitSharedElementBundle = resultData;
                 sharedElementExitBack();
                 break;
+            case MSG_CANCEL:
+                mIsCanceled = true;
+                finish();
+                break;
         }
     }
 
@@ -268,7 +272,8 @@
         if (transition != null && decorView != null && mTransitioningViews != null) {
             setTransitioningViewsVisiblity(View.VISIBLE, false);
             TransitionManager.beginDelayedTransition(decorView, transition);
-            setTransitioningViewsVisiblity(View.INVISIBLE, true);
+            setTransitioningViewsVisiblity(View.INVISIBLE, false);
+            decorView.invalidate();
         } else {
             transitionStarted();
         }
@@ -367,7 +372,7 @@
             scheduleGhostVisibilityChange(View.VISIBLE);
             setGhostVisibility(View.VISIBLE);
             if (viewsTransition != null) {
-                setTransitioningViewsVisiblity(View.INVISIBLE, true);
+                setTransitioningViewsVisiblity(View.INVISIBLE, false);
             }
             decorView.invalidate();
         } else {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index aafb3c6..2a04c39 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1033,11 +1033,12 @@
      *                        false if it is not.
      */
     public void setUserVisibleHint(boolean isVisibleToUser) {
-        if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null) {
+        if (!mUserVisibleHint && isVisibleToUser && mState < STARTED
+                && mFragmentManager != null && isAdded()) {
             mFragmentManager.performPendingDeferredStart(this);
         }
         mUserVisibleHint = isVisibleToUser;
-        mDeferStart = !isVisibleToUser;
+        mDeferStart = mState < STARTED && !isVisibleToUser;
     }
 
     /**
@@ -1429,16 +1430,20 @@
         final Context context = getContext();
         final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0;
         if (version >= Build.VERSION_CODES.N) {
-            if (savedInstanceState != null) {
-                Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
-                if (p != null) {
-                    if (mChildFragmentManager == null) {
-                        instantiateChildFragmentManager();
-                    }
-                    mChildFragmentManager.restoreAllState(p, mChildNonConfig);
-                    mChildNonConfig = null;
-                    mChildFragmentManager.dispatchCreate();
+            restoreChildFragmentState(savedInstanceState, true);
+        }
+    }
+
+    void restoreChildFragmentState(@Nullable Bundle savedInstanceState, boolean provideNonConfig) {
+        if (savedInstanceState != null) {
+            Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
+            if (p != null) {
+                if (mChildFragmentManager == null) {
+                    instantiateChildFragmentManager();
                 }
+                mChildFragmentManager.restoreAllState(p, provideNonConfig ? mChildNonConfig : null);
+                mChildNonConfig = null;
+                mChildFragmentManager.dispatchCreate();
             }
         }
     }
@@ -1578,21 +1583,21 @@
 
     /**
      * Called when the Fragment's activity changes from fullscreen mode to multi-window mode and
-     * visa-versa. This is generally tied to {@link Activity#onMultiWindowChanged} of the containing
-     * Activity.
+     * visa-versa. This is generally tied to {@link Activity#onMultiWindowModeChanged} of the
+     * containing Activity.
      *
-     * @param inMultiWindow True if the activity is in multi-window mode.
+     * @param isInMultiWindowMode True if the activity is in multi-window mode.
      */
-    public void onMultiWindowChanged(boolean inMultiWindow) {
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
     }
 
     /**
      * Called by the system when the activity changes to and from picture-in-picture mode. This is
-     * generally tied to {@link Activity#onPictureInPictureChanged} of the containing Activity.
+     * generally tied to {@link Activity#onPictureInPictureModeChanged} of the containing Activity.
      *
-     * @param inPictureInPicture True if the activity is in picture-in-picture mode.
+     * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
      */
-    public void onPictureInPictureChanged(boolean inPictureInPicture) {
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
     }
 
     public void onConfigurationChanged(Configuration newConfig) {
@@ -1692,6 +1697,18 @@
      */
     public void onDetach() {
         mCalled = true;
+
+        // Destroy the child FragmentManager if we still have it here.
+        // We won't unless we're retaining our instance and if we do,
+        // our child FragmentManager instance state will have already been saved.
+        if (mChildFragmentManager != null) {
+            if (!mRetaining) {
+                throw new IllegalStateException("Child FragmentManager of " + this + " was not "
+                        + " destroyed and this fragment is not retaining instance");
+            }
+            mChildFragmentManager.dispatchDestroy();
+            mChildFragmentManager = null;
+        }
     }
 
     /**
@@ -2252,16 +2269,7 @@
         final Context context = getContext();
         final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0;
         if (version < Build.VERSION_CODES.N) {
-            if (savedInstanceState != null) {
-                Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
-                if (p != null) {
-                    if (mChildFragmentManager == null) {
-                        instantiateChildFragmentManager();
-                    }
-                    mChildFragmentManager.restoreAllState(p, null);
-                    mChildFragmentManager.dispatchCreate();
-                }
-            }
+            restoreChildFragmentState(savedInstanceState, false);
         }
     }
 
@@ -2327,17 +2335,17 @@
         }
     }
 
-    void performMultiWindowChanged(boolean inMultiWindow) {
-        onMultiWindowChanged(inMultiWindow);
+    void performMultiWindowModeChanged(boolean isInMultiWindowMode) {
+        onMultiWindowModeChanged(isInMultiWindowMode);
         if (mChildFragmentManager != null) {
-            mChildFragmentManager.dispatchMultiWindowChanged(inMultiWindow);
+            mChildFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode);
         }
     }
 
-    void performPictureInPictureChanged(boolean inPictureInPicture) {
-        onPictureInPictureChanged(inPictureInPicture);
+    void performPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        onPictureInPictureModeChanged(isInPictureInPictureMode);
         if (mChildFragmentManager != null) {
-            mChildFragmentManager.dispatchPictureInPictureChanged(inPictureInPicture);
+            mChildFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
         }
     }
 
@@ -2509,6 +2517,7 @@
             throw new SuperNotCalledException("Fragment " + this
                     + " did not call through to super.onDestroy()");
         }
+        mChildFragmentManager = null;
     }
 
     private static Transition loadTransition(Context context, TypedArray typedArray,
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index 57b0ff1..b3d2df5 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -247,10 +247,10 @@
      * the activity changed.
      * <p>Call when the multi-window mode of the activity changed.
      *
-     * @see Fragment#onMultiWindowChanged
+     * @see Fragment#onMultiWindowModeChanged
      */
-    public void dispatchMultiWindowChanged(boolean inMultiWindow) {
-        mHost.mFragmentManager.dispatchMultiWindowChanged(inMultiWindow);
+    public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
+        mHost.mFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode);
     }
 
     /**
@@ -258,10 +258,10 @@
      * mode of the activity changed.
      * <p>Call when the picture-in-picture mode of the activity changed.
      *
-     * @see Fragment#onPictureInPictureChanged
+     * @see Fragment#onPictureInPictureModeChanged
      */
-    public void dispatchPictureInPictureChanged(boolean inPictureInPicture) {
-        mHost.mFragmentManager.dispatchPictureInPictureChanged(inPictureInPicture);
+    public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        mHost.mFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
     }
 
     /**
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 4c8761c..8369f17 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -24,6 +24,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.os.Debug;
@@ -940,6 +941,9 @@
 
                     if (!f.mRetaining) {
                         f.performCreate(f.mSavedFragmentState);
+                    } else {
+                        f.restoreChildFragmentState(f.mSavedFragmentState, true);
+                        f.mState = Fragment.CREATED;
                     }
                     f.mRetaining = false;
                     if (f.mFromLayout) {
@@ -960,12 +964,24 @@
                         if (!f.mFromLayout) {
                             ViewGroup container = null;
                             if (f.mContainerId != 0) {
-                                container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
+                                if (f.mContainerId == View.NO_ID) {
+                                    throwException(new IllegalArgumentException(
+                                            "Cannot create fragment "
+                                                    + f
+                                                    + " for a container view with no id"));
+                                }
+                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                 if (container == null && !f.mRestored) {
+                                    String resName;
+                                    try {
+                                        resName = f.getResources().getResourceName(f.mContainerId);
+                                    } catch (NotFoundException e) {
+                                        resName = "unknown";
+                                    }
                                     throwException(new IllegalArgumentException(
                                             "No view found for id 0x"
                                             + Integer.toHexString(f.mContainerId) + " ("
-                                            + f.getResources().getResourceName(f.mContainerId)
+                                            + resName
                                             + ") for fragment " + f));
                                 }
                             }
@@ -996,6 +1012,9 @@
                         f.mSavedFragmentState = null;
                     }
                 case Fragment.ACTIVITY_CREATED:
+                    if (newState > Fragment.ACTIVITY_CREATED) {
+                        f.mState = Fragment.STOPPED;
+                    }
                 case Fragment.STOPPED:
                     if (newState > Fragment.STOPPED) {
                         if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
@@ -1095,7 +1114,7 @@
                             if (!f.mRetaining) {
                                 f.performDestroy();
                             } else {
-                                f.mState = Fragment.INITIALIZING;
+                                f.mState = Fragment.CREATED;
                             }
 
                             f.mCalled = false;
@@ -1111,7 +1130,6 @@
                                     f.mHost = null;
                                     f.mParentFragment = null;
                                     f.mFragmentManager = null;
-                                    f.mChildFragmentManager = null;
                                 }
                             }
                         }
@@ -1512,7 +1530,7 @@
             throw new IllegalStateException("Must be called from main thread of fragment host");
         }
 
-        if (allowStateLoss) {
+        if (!allowStateLoss) {
             checkStateLoss();
         }
 
@@ -1612,7 +1630,9 @@
             final BackStackRecord bss = mBackStack.remove(last);
             SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
             SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-            bss.calculateBackFragments(firstOutFragments, lastInFragments);
+            if (mCurState >= Fragment.CREATED) {
+                bss.calculateBackFragments(firstOutFragments, lastInFragments);
+            }
             bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
             reportBackStackChanged();
         } else {
@@ -1659,8 +1679,10 @@
             final int LAST = states.size()-1;
             SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
             SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-            for (int i=0; i<=LAST; i++) {
-                states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
+            if (mCurState >= Fragment.CREATED) {
+                for (int i = 0; i <= LAST; i++) {
+                    states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
+                }
             }
             BackStackRecord.TransitionState state = null;
             for (int i=0; i<=LAST; i++) {
@@ -2047,26 +2069,26 @@
         mParent = null;
     }
 
-    public void dispatchMultiWindowChanged(boolean inMultiWindow) {
+    public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
         if (mAdded == null) {
             return;
         }
         for (int i = mAdded.size() - 1; i >= 0; --i) {
             final Fragment f = mAdded.get(i);
             if (f != null) {
-                f.performMultiWindowChanged(inMultiWindow);
+                f.performMultiWindowModeChanged(isInMultiWindowMode);
             }
         }
     }
 
-    public void dispatchPictureInPictureChanged(boolean inPictureInPicture) {
+    public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         if (mAdded == null) {
             return;
         }
         for (int i = mAdded.size() - 1; i >= 0; --i) {
             final Fragment f = mAdded.get(i);
             if (f != null) {
-                f.performPictureInPictureChanged(inPictureInPicture);
+                f.performPictureInPictureModeChanged(isInPictureInPictureMode);
             }
         }
     }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index e4d6835..8ee6fd0 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.UserIdInt;
 import android.app.ActivityManager.RunningServiceInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
@@ -33,6 +34,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ProviderInfo;
 import android.content.pm.UserInfo;
@@ -45,6 +47,7 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.IInterface;
+import android.os.IProgressListener;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -143,11 +146,32 @@
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
     public void moveTaskBackwards(int task) throws RemoteException;
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
-    public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) throws RemoteException;
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
+
+    /**
+     * Resizes the input stack id to the given bounds.
+     *
+     * @param stackId Id of the stack to resize.
+     * @param bounds Bounds to resize the stack to or {@code null} for fullscreen.
+     * @param allowResizeInDockedMode True if the resize should be allowed when the docked stack is
+     *                                active.
+     * @param preserveWindows True if the windows of activities contained in the stack should be
+     *                        preserved.
+     * @param animate True if the stack resize should be animated.
+     * @param animationDuration The duration of the resize animation in milliseconds or -1 if the
+     *                          default animation duration should be used.
+     * @throws RemoteException
+     */
     public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
-            boolean preserveWindows, boolean animate) throws RemoteException;
+            boolean preserveWindows, boolean animate, int animationDuration) throws RemoteException;
+
+    /**
+     * Moves all tasks from the docked stack in the fullscreen stack and puts the top task of the
+     * fullscreen stack into the docked stack.
+     */
+    public void swapDockedAndFullscreenStack() throws RemoteException;
 
     /**
      * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
@@ -171,6 +195,16 @@
     public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
             Rect tempDockedTaskInsetBounds,
             Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) throws RemoteException;
+    /**
+     * Resizes the pinned stack.
+     *
+     * @param pinnedBounds The bounds for the pinned stack.
+     * @param tempPinnedTaskBounds The temporary bounds for the tasks in the pinned stack, which
+     *                             might be different from the stack bounds to allow more
+     *                             flexibility while resizing, or {@code null} if they should be the
+     *                             same as the stack bounds.
+     */
+    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException;
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
     public List<StackInfo> getAllStackInfos() throws RemoteException;
     public StackInfo getStackInfo(int stackId) throws RemoteException;
@@ -305,9 +339,10 @@
         String packageName, boolean waitForDebugger, boolean persistent)
         throws RemoteException;
     public void setAlwaysFinish(boolean enabled) throws RemoteException;
-    public void setActivityController(IActivityController watcher)
+    public void setActivityController(IActivityController watcher, boolean imAMonkey)
         throws RemoteException;
     public void setLenientBackgroundCheck(boolean enabled) throws RemoteException;
+    public int getMemoryTrimLevel() throws RemoteException;
 
     public void enterSafeMode() throws RemoteException;
 
@@ -427,7 +462,8 @@
     // Multi-user APIs
     public boolean switchUser(int userid) throws RemoteException;
     public boolean startUserInBackground(int userid) throws RemoteException;
-    public boolean unlockUser(int userid, byte[] token, byte[] secret) throws RemoteException;
+    public boolean unlockUser(int userid, byte[] token, byte[] secret, IProgressListener listener)
+            throws RemoteException;
     public int stopUser(int userid, boolean force, IStopUserCallback callback) throws RemoteException;
     public UserInfo getCurrentUser() throws RemoteException;
     public boolean isUserRunning(int userid, int flags) throws RemoteException;
@@ -457,8 +493,13 @@
 
     public void keyguardWaitingForActivityDrawn() throws RemoteException;
 
-    public void keyguardGoingAway(boolean disableWindowAnimations,
-            boolean keyguardGoingToNotificationShade) throws RemoteException;
+    /**
+     * Notify the system that the keyguard is going away.
+     *
+     * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
+     *              etc.
+     */
+    public void keyguardGoingAway(int flags) throws RemoteException;
 
     public boolean shouldUpRecreateTask(IBinder token, String destAffinity)
             throws RemoteException;
@@ -582,13 +623,16 @@
 
     public int getAppStartMode(int uid, String packageName) throws RemoteException;
 
-    public boolean inMultiWindow(IBinder token) throws RemoteException;
+    public boolean isInMultiWindowMode(IBinder token) throws RemoteException;
 
-    public boolean inPictureInPicture(IBinder token) throws RemoteException;
+    public boolean isInPictureInPictureMode(IBinder token) throws RemoteException;
 
-    public void enterPictureInPicture(IBinder token) throws RemoteException;
+    public void enterPictureInPictureMode(IBinder token) throws RemoteException;
 
-    public void setVrMode(IBinder token, boolean enabled) throws RemoteException;
+    public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
+            throws RemoteException;
+
+    public boolean isVrModePackageEnabled(ComponentName packageName) throws RemoteException;
 
     public boolean isAppForeground(int uid) throws RemoteException;
 
@@ -602,6 +646,8 @@
 
     public void removeStack(int stackId) throws RemoteException;
 
+    public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -980,4 +1026,9 @@
     int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366;
     int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367;
     int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368;
+    int GET_MEMORY_TRIM_LEVEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+369;
+    int RESIZE_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 370;
+    int IS_VR_PACKAGE_ENABLED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 371;
+    int SWAP_DOCKED_AND_FULLSCREEN_STACK = IBinder.FIRST_CALL_TRANSACTION + 372;
+    int NOTIFY_LOCKED_PROFILE = IBinder.FIRST_CALL_TRANSACTION + 373;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index b55da88..a3b2638 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -123,8 +123,13 @@
     void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
             throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
+    // the package has been removed, clean up internal references
     static final int PACKAGE_REMOVED = 0;
     static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
+    // the package is being modified in-place, don't kill it and retain references to it
+    static final int PACKAGE_REMOVED_DONT_KILL = 2;
+    // a previously removed package was replaced with a new version [eg. upgrade, split added, ...]
+    static final int PACKAGE_REPLACED = 3;
     void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
     void scheduleCrash(String msg) throws RemoteException;
     void dumpActivity(FileDescriptor fd, IBinder servicetoken, String prefix, String[] args)
@@ -133,7 +138,8 @@
     void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
     void scheduleTrimMemory(int level) throws RemoteException;
     void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo,
-            boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException;
+            boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable,
+            String[] args) throws RemoteException;
     void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void unstableProviderDied(IBinder provider) throws RemoteException;
@@ -152,8 +158,8 @@
     void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException;
     void startBinderTracking() throws RemoteException;
     void stopBinderTrackingAndDump(FileDescriptor fd) throws RemoteException;
-    void scheduleMultiWindowChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
-    void schedulePictureInPictureChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
+    void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) throws RemoteException;
+    void schedulePictureInPictureModeChanged(IBinder token, boolean isInPictureInPictureMode) throws RemoteException;
     void scheduleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor voiceInteractor) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 8be00aa..7a69c62 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -80,7 +80,7 @@
     void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
     void setInterruptionFilter(String pkg, int interruptionFilter);
 
-    void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
+    void setImportanceFromRankerService(in INotificationListener token, String key, int importance, CharSequence explanation);
 
     ComponentName getEffectsSuppressor();
     boolean matchesCallFilter(in Bundle extras);
@@ -97,9 +97,9 @@
     boolean isNotificationPolicyAccessGrantedForPackage(String pkg);
     void setNotificationPolicyAccessGranted(String pkg, boolean granted);
     AutomaticZenRule getAutomaticZenRule(String id);
-    List<AutomaticZenRule> getAutomaticZenRules();
-    AutomaticZenRule addAutomaticZenRule(in AutomaticZenRule automaticZenRule);
-    boolean updateAutomaticZenRule(in AutomaticZenRule automaticZenRule);
+    List<ZenModeConfig.ZenRule> getZenRules();
+    String addAutomaticZenRule(in AutomaticZenRule automaticZenRule);
+    boolean updateAutomaticZenRule(String id, in AutomaticZenRule automaticZenRule);
     boolean removeAutomaticZenRule(String id);
     boolean removeAutomaticZenRules(String packageName);
     int getRuleInstanceCount(in ComponentName owner);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 6432558..fa67529 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -35,4 +35,9 @@
      * Called whenever the pinned stack is done animating a resize.
      */
     void onPinnedStackAnimationEnded();
+
+    /**
+     * Called when we launched an activity that we forced to be resizable.
+     */
+    void onActivityForcedResizable(String packageName, int taskId);
 }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 1143c6a..2fc6533 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -62,6 +62,11 @@
             out Bundle outParams, int userId);
 
     /**
+     * Retrieve the given user's current wallpaper ID of the given kind.
+     */
+    int getWallpaperIdForUser(int which, int userId);
+
+    /**
      * If the current system wallpaper is a live wallpaper component, return the
      * information about that wallpaper.  Otherwise, if it is a static image,
      * simply return null.
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 33fd1db..13e8e75 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -49,6 +50,8 @@
 import com.android.internal.content.ReferrerIntent;
 
 import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -78,7 +81,15 @@
     public static final String REPORT_KEY_STREAMRESULT = "stream";
 
     private static final String TAG = "Instrumentation";
-    
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({0, UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES})
+    public @interface UiAutomationFlags {};
+
+
     private final Object mSync = new Object();
     private ActivityThread mThread = null;
     private MessageQueue mMessageQueue = null;
@@ -1876,7 +1887,7 @@
      *
      * @see UiAutomation
      */
-    public UiAutomation getUiAutomation(int flags) {
+    public UiAutomation getUiAutomation(@UiAutomationFlags int flags) {
         if (mUiAutomationConnection != null) {
             if ((mUiAutomation == null) || (mUiAutomation.isDestroyed())) {
                 mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(),
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index dacf4ea..b3a486f 100644
--- a/core/java/android/app/JobSchedulerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -46,9 +46,9 @@
     }
 
     @Override
-    public int scheduleAsPackage(JobInfo job, String packageName, int userId) {
+    public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag) {
         try {
-            return mBinder.scheduleAsPackage(job, packageName, userId);
+            return mBinder.scheduleAsPackage(job, packageName, userId, tag);
         } catch (RemoteException e) {
             return JobScheduler.RESULT_FAILURE;
         }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 8717353..e090aa4 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -16,8 +16,6 @@
 
 package android.app;
 
-import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -37,15 +35,17 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.view.DisplayAdjustments;
 import android.view.Display;
-import android.os.SystemProperties;
+import android.view.DisplayAdjustments;
 
 import dalvik.system.VMRuntime;
 
@@ -56,10 +56,10 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.URL;
-import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.List;
 import java.util.Objects;
 
 final class IntentReceiverLeaked extends AndroidRuntimeException {
@@ -83,24 +83,25 @@
     private static final String TAG = "LoadedApk";
 
     private final ActivityThread mActivityThread;
-    private ApplicationInfo mApplicationInfo;
     final String mPackageName;
-    private final String mAppDir;
-    private final String mResDir;
-    private final String[] mSplitAppDirs;
-    private final String[] mSplitResDirs;
-    private final String[] mOverlayDirs;
-    private final String[] mSharedLibraries;
-    private final String mDataDir;
-    private final String mLibDir;
-    private final File mDataDirFile;
-    private final File mDeviceEncryptedDataDirFile;
-    private final File mCredentialEncryptedDataDirFile;
+    private ApplicationInfo mApplicationInfo;
+    private String mAppDir;
+    private String mResDir;
+    private String[] mSplitAppDirs;
+    private String[] mSplitResDirs;
+    private String[] mOverlayDirs;
+    private String[] mSharedLibraries;
+    private String mDataDir;
+    private String mLibDir;
+    private File mDataDirFile;
+    private File mDeviceProtectedDataDirFile;
+    private File mCredentialProtectedDataDirFile;
     private final ClassLoader mBaseClassLoader;
     private final boolean mSecurityViolation;
     private final boolean mIncludeCode;
     private final boolean mRegisterPackage;
     private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
+    /** WARNING: This may change. Don't hold external references to it. */
     Resources mResources;
     private ClassLoader mClassLoader;
     private Application mApplication;
@@ -129,23 +130,10 @@
     public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
             CompatibilityInfo compatInfo, ClassLoader baseLoader,
             boolean securityViolation, boolean includeCode, boolean registerPackage) {
-        final int myUid = Process.myUid();
-        aInfo = adjustNativeLibraryPaths(aInfo);
 
         mActivityThread = activityThread;
-        mApplicationInfo = aInfo;
+        setApplicationInfo(aInfo);
         mPackageName = aInfo.packageName;
-        mAppDir = aInfo.sourceDir;
-        mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
-        mSplitAppDirs = aInfo.splitSourceDirs;
-        mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
-        mOverlayDirs = aInfo.resourceDirs;
-        mSharedLibraries = aInfo.sharedLibraryFiles;
-        mDataDir = aInfo.dataDir;
-        mDataDirFile = FileUtils.newFileOrNull(mDataDir);
-        mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir);
-        mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir);
-        mLibDir = aInfo.nativeLibraryDir;
         mBaseClassLoader = baseLoader;
         mSecurityViolation = securityViolation;
         mIncludeCode = includeCode;
@@ -197,8 +185,8 @@
         mSharedLibraries = null;
         mDataDir = null;
         mDataDirFile = null;
-        mDeviceEncryptedDataDirFile = null;
-        mCredentialEncryptedDataDirFile = null;
+        mDeviceProtectedDataDirFile = null;
+        mCredentialProtectedDataDirFile = null;
         mLibDir = null;
         mBaseClassLoader = null;
         mSecurityViolation = false;
@@ -225,6 +213,10 @@
         return mApplicationInfo;
     }
 
+    public int getTargetSdkVersion() {
+        return mApplicationInfo.targetSdkVersion;
+    }
+
     public boolean isSecurityViolation() {
         return mSecurityViolation;
     }
@@ -252,7 +244,7 @@
             ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
                     PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
         } catch (RemoteException e) {
-            throw new AssertionError(e);
+            throw e.rethrowFromSystemServer();
         }
 
         if (ai == null) {
@@ -262,159 +254,246 @@
         return ai.sharedLibraryFiles;
     }
 
-    public ClassLoader getClassLoader() {
+    public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) {
+        setApplicationInfo(aInfo);
+
+        final List<String> newPaths = new ArrayList<>();
+        makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
+        final List<String> addedPaths = new ArrayList<>(newPaths.size());
+
+        if (oldPaths != null) {
+            for (String path : newPaths) {
+                final String apkName = path.substring(path.lastIndexOf(File.separator));
+                boolean match = false;
+                for (String oldPath : oldPaths) {
+                    final String oldApkName = oldPath.substring(path.lastIndexOf(File.separator));
+                    if (apkName.equals(oldApkName)) {
+                        match = true;
+                        break;
+                    }
+                }
+                if (!match) {
+                    addedPaths.add(path);
+                }
+            }
+        } else {
+            addedPaths.addAll(newPaths);
+        }
         synchronized (this) {
-            if (mClassLoader != null) {
-                return mClassLoader;
+            createOrUpdateClassLoaderLocked(addedPaths);
+            if (mResources != null) {
+                mResources = mActivityThread.getTopLevelResources(mResDir, mSplitResDirs,
+                        mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
+                        this);
+            }
+        }
+    }
+
+    private void setApplicationInfo(ApplicationInfo aInfo) {
+        final int myUid = Process.myUid();
+        aInfo = adjustNativeLibraryPaths(aInfo);
+        mApplicationInfo = aInfo;
+        mAppDir = aInfo.sourceDir;
+        mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
+        mSplitAppDirs = aInfo.splitSourceDirs;
+        mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
+        mOverlayDirs = aInfo.resourceDirs;
+        mSharedLibraries = aInfo.sharedLibraryFiles;
+        mDataDir = aInfo.dataDir;
+        mLibDir = aInfo.nativeLibraryDir;
+        mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
+        mDeviceProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceProtectedDataDir);
+        mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir);
+    }
+
+    public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
+            List<String> outZipPaths, List<String> outLibPaths) {
+        final String appDir = aInfo.sourceDir;
+        final String[] splitAppDirs = aInfo.splitSourceDirs;
+        final String libDir = aInfo.nativeLibraryDir;
+        final String[] sharedLibraries = aInfo.sharedLibraryFiles;
+
+        outZipPaths.clear();
+        outZipPaths.add(appDir);
+        if (splitAppDirs != null) {
+            Collections.addAll(outZipPaths, splitAppDirs);
+        }
+
+        if (outLibPaths != null) {
+            outLibPaths.clear();
+        }
+
+        /*
+         * The following is a bit of a hack to inject
+         * instrumentation into the system: If the app
+         * being started matches one of the instrumentation names,
+         * then we combine both the "instrumentation" and
+         * "instrumented" app into the path, along with the
+         * concatenation of both apps' shared library lists.
+         */
+
+        String instrumentationPackageName = activityThread.mInstrumentationPackageName;
+        String instrumentationAppDir = activityThread.mInstrumentationAppDir;
+        String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
+        String instrumentationLibDir = activityThread.mInstrumentationLibDir;
+
+        String instrumentedAppDir = activityThread.mInstrumentedAppDir;
+        String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
+        String instrumentedLibDir = activityThread.mInstrumentedLibDir;
+        String[] instrumentationLibs = null;
+
+        if (appDir.equals(instrumentationAppDir)
+                || appDir.equals(instrumentedAppDir)) {
+            outZipPaths.clear();
+            outZipPaths.add(instrumentationAppDir);
+            if (instrumentationSplitAppDirs != null) {
+                Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
+            }
+            outZipPaths.add(instrumentedAppDir);
+            if (instrumentedSplitAppDirs != null) {
+                Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
             }
 
-            if (mIncludeCode && !mPackageName.equals("android")) {
-                // Avoid the binder call when the package is the current application package.
-                // The activity manager will perform ensure that dexopt is performed before
-                // spinning up the process.
-                if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
-                    final String isa = VMRuntime.getRuntime().vmInstructionSet();
-                    try {
-                        ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
-                    } catch (RemoteException re) {
-                        // Ignored.
-                    }
+            if (outLibPaths != null) {
+                outLibPaths.add(instrumentationLibDir);
+                outLibPaths.add(instrumentedLibDir);
+            }
+
+            if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+                instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+            }
+        }
+
+        if (outLibPaths != null) {
+            if (outLibPaths.isEmpty()) {
+                outLibPaths.add(libDir);
+            }
+
+            // Add path to libraries in apk for current abi. Do this now because more entries
+            // will be added to zipPaths that shouldn't be part of the library path.
+            if (aInfo.primaryCpuAbi != null) {
+                for (String apk : outZipPaths) {
+                    outLibPaths.add(apk + "!/lib/" + aInfo.primaryCpuAbi);
                 }
+            }
 
-                final List<String> zipPaths = new ArrayList<>();
-                final List<String> apkPaths = new ArrayList<>();
-                final List<String> libPaths = new ArrayList<>();
+            if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
+                // Add path to system libraries to libPaths;
+                // Access to system libs should be limited
+                // to bundled applications; this is why updated
+                // system apps are not included.
+                outLibPaths.add(System.getProperty("java.library.path"));
+            }
+        }
 
-                if (mRegisterPackage) {
-                    try {
-                        ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
-                    } catch (RemoteException e) {
-                    }
+        if (sharedLibraries != null) {
+            for (String lib : sharedLibraries) {
+                if (!outZipPaths.contains(lib)) {
+                    outZipPaths.add(0, lib);
                 }
+            }
+        }
 
-                zipPaths.add(mAppDir);
-                if (mSplitAppDirs != null) {
-                    Collections.addAll(zipPaths, mSplitAppDirs);
+        if (instrumentationLibs != null) {
+            for (String lib : instrumentationLibs) {
+                if (!outZipPaths.contains(lib)) {
+                    outZipPaths.add(0, lib);
                 }
+            }
+        }
+    }
 
-                libPaths.add(mLibDir);
+    private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
+        if (mPackageName.equals("android")) {
+            if (mClassLoader != null) {
+                // nothing to update
+                return;
+            }
 
-                /*
-                 * The following is a bit of a hack to inject
-                 * instrumentation into the system: If the app
-                 * being started matches one of the instrumentation names,
-                 * then we combine both the "instrumentation" and
-                 * "instrumented" app into the path, along with the
-                 * concatenation of both apps' shared library lists.
-                 */
-
-                String instrumentationPackageName = mActivityThread.mInstrumentationPackageName;
-                String instrumentationAppDir = mActivityThread.mInstrumentationAppDir;
-                String[] instrumentationSplitAppDirs = mActivityThread.mInstrumentationSplitAppDirs;
-                String instrumentationLibDir = mActivityThread.mInstrumentationLibDir;
-
-                String instrumentedAppDir = mActivityThread.mInstrumentedAppDir;
-                String[] instrumentedSplitAppDirs = mActivityThread.mInstrumentedSplitAppDirs;
-                String instrumentedLibDir = mActivityThread.mInstrumentedLibDir;
-                String[] instrumentationLibs = null;
-
-                if (mAppDir.equals(instrumentationAppDir)
-                        || mAppDir.equals(instrumentedAppDir)) {
-                    zipPaths.clear();
-                    zipPaths.add(instrumentationAppDir);
-                    if (instrumentationSplitAppDirs != null) {
-                        Collections.addAll(zipPaths, instrumentationSplitAppDirs);
-                    }
-                    zipPaths.add(instrumentedAppDir);
-                    if (instrumentedSplitAppDirs != null) {
-                        Collections.addAll(zipPaths, instrumentedSplitAppDirs);
-                    }
-
-                    libPaths.clear();
-                    libPaths.add(instrumentationLibDir);
-                    libPaths.add(instrumentedLibDir);
-
-                    if (!instrumentedAppDir.equals(instrumentationAppDir)) {
-                        instrumentationLibs = getLibrariesFor(instrumentationPackageName);
-                    }
-                }
-
-                apkPaths.addAll(zipPaths);
-
-                if (mSharedLibraries != null) {
-                    for (String lib : mSharedLibraries) {
-                        if (!zipPaths.contains(lib)) {
-                            zipPaths.add(0, lib);
-                        }
-                    }
-                }
-
-                if (instrumentationLibs != null) {
-                    for (String lib : instrumentationLibs) {
-                        if (!zipPaths.contains(lib)) {
-                            zipPaths.add(0, lib);
-                        }
-                    }
-                }
-
-                final String zip = TextUtils.join(File.pathSeparator, zipPaths);
-
-                // Add path to libraries in apk for current abi
-                if (mApplicationInfo.primaryCpuAbi != null) {
-                    for (String apk : apkPaths) {
-                      libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);
-                    }
-                }
-
-                String libraryPermittedPath = mDataDir;
-                boolean isBundledApp = false;
-
-                if (mApplicationInfo.isSystemApp()) {
-                    isBundledApp = true;
-                    // Add path to system libraries to libPaths;
-                    // Access to system libs should be limited
-                    // to bundled applications; this is why updated
-                    // system apps are not included.
-                    libPaths.add(System.getProperty("java.library.path"));
-
-                    // This is necessary to grant bundled apps access to
-                    // libraries located in subdirectories of /system/lib
-                    libraryPermittedPath += File.pathSeparator +
-                                            System.getProperty("java.library.path");
-                }
-                // DO NOT SHIP: this is a workaround for apps loading native libraries
-                // provided by 3rd party apps using absolute path instead of corresponding
-                // classloader; see http://b/26954419 for example.
-                if (mApplicationInfo.targetSdkVersion <= 23) {
-                    libraryPermittedPath += File.pathSeparator + "/data/app";
-                }
-                // -----------------------------------------------------------------------------
-
-                final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
-
-                /*
-                 * With all the combination done (if necessary, actually
-                 * create the class loader.
-                 */
-
-                if (ActivityThread.localLOGV)
-                    Slog.v(ActivityThread.TAG, "Class path: " + zip +
-                            ", JNI path: " + librarySearchPath);
-
-                // Temporarily disable logging of disk reads on the Looper thread
-                // as this is early and necessary.
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-
-                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, isBundledApp,
-                        librarySearchPath, libraryPermittedPath, mBaseClassLoader);
-
-                StrictMode.setThreadPolicy(oldPolicy);
+            if (mBaseClassLoader != null) {
+                mClassLoader = mBaseClassLoader;
             } else {
-                if (mBaseClassLoader == null) {
-                    mClassLoader = ClassLoader.getSystemClassLoader();
-                } else {
-                    mClassLoader = mBaseClassLoader;
-                }
+                mClassLoader = ClassLoader.getSystemClassLoader();
+            }
+
+            return;
+        }
+
+        // Avoid the binder call when the package is the current application package.
+        // The activity manager will perform ensure that dexopt is performed before
+        // spinning up the process.
+        if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
+            VMRuntime.getRuntime().vmInstructionSet();
+            try {
+                ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+
+        final List<String> zipPaths = new ArrayList<>();
+        final List<String> libPaths = new ArrayList<>();
+
+        if (mRegisterPackage) {
+            try {
+                ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
+        final String zip = mIncludeCode ? TextUtils.join(File.pathSeparator, zipPaths) : "";
+        final boolean isBundledApp = mApplicationInfo.isSystemApp()
+                && !mApplicationInfo.isUpdatedSystemApp();
+        String libraryPermittedPath = mDataDir;
+        if (isBundledApp) {
+            // This is necessary to grant bundled apps access to
+            // libraries located in subdirectories of /system/lib
+            libraryPermittedPath += File.pathSeparator +
+                                    System.getProperty("java.library.path");
+        }
+        // DO NOT SHIP: this is a workaround for apps loading native libraries
+        // provided by 3rd party apps using absolute path instead of corresponding
+        // classloader; see http://b/26954419 for example.
+        if (mApplicationInfo.targetSdkVersion <= 23) {
+            libraryPermittedPath += File.pathSeparator + "/data/app";
+        }
+        // -----------------------------------------------------------------------------
+
+        final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
+
+        /*
+         * With all the combination done (if necessary, actually
+         * create the class loader.
+         */
+
+        if (ActivityThread.localLOGV)
+            Slog.v(ActivityThread.TAG, "Class path: " + zip +
+                    ", JNI path: " + librarySearchPath);
+
+        if (mClassLoader == null) {
+            // Temporarily disable logging of disk reads on the Looper thread
+            // as this is early and necessary.
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+
+            mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
+                    mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+                    libraryPermittedPath, mBaseClassLoader);
+
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+
+        if (addedPaths != null && addedPaths.size() > 0) {
+            final String add = TextUtils.join(File.pathSeparator, addedPaths);
+            ApplicationLoaders.getDefault().addPath(mClassLoader, add);
+        }
+    }
+
+    public ClassLoader getClassLoader() {
+        synchronized (this) {
+            if (mClassLoader == null) {
+                createOrUpdateClassLoaderLocked(null /*addedPaths*/);
             }
             return mClassLoader;
         }
@@ -450,8 +529,7 @@
             pi = pm.getPackageInfo(mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                     UserHandle.myUserId());
         } catch (RemoteException e) {
-            throw new IllegalStateException("Unable to get package info for "
-                    + mPackageName + "; is system dying?", e);
+            throw e.rethrowFromSystemServer();
         }
         if (pi == null) {
             throw new IllegalStateException("Unable to get package info for "
@@ -572,12 +650,12 @@
         return mDataDirFile;
     }
 
-    public File getDeviceEncryptedDataDirFile() {
-        return mDeviceEncryptedDataDirFile;
+    public File getDeviceProtectedDataDirFile() {
+        return mDeviceProtectedDataDirFile;
     }
 
-    public File getCredentialEncryptedDataDirFile() {
-        return mCredentialEncryptedDataDirFile;
+    public File getCredentialProtectedDataDirFile() {
+        return mCredentialProtectedDataDirFile;
     }
 
     public AssetManager getAssets(ActivityThread mainThread) {
@@ -587,7 +665,7 @@
     public Resources getResources(ActivityThread mainThread) {
         if (mResources == null) {
             mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
-                    mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
+                    mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, this);
         }
         return mResources;
     }
@@ -708,7 +786,7 @@
                         ActivityManagerNative.getDefault().unregisterReceiver(
                                 rd.getIIntentReceiver());
                     } catch (RemoteException e) {
-                        // system crashed, nothing we can do
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -734,7 +812,7 @@
                         ActivityManagerNative.getDefault().unbindService(
                                 sd.getIServiceConnection());
                     } catch (RemoteException e) {
-                        // system crashed, nothing we can do
+                        throw e.rethrowFromSystemServer();
                     }
                     sd.doForget();
                 }
@@ -834,6 +912,8 @@
                 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                 mStrongRef = strong ? rd : null;
             }
+
+            @Override
             public void performReceive(Intent intent, int resultCode, String data,
                     Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
@@ -859,7 +939,7 @@
                         }
                         mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                     } catch (RemoteException e) {
-                        Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -917,6 +997,7 @@
                 try {
                     ClassLoader cl =  mReceiver.getClass().getClassLoader();
                     intent.setExtrasClassLoader(cl);
+                    intent.prepareToEnterProcess();
                     setExtrasClassLoader(cl);
                     receiver.setPendingResult(this);
                     receiver.onReceive(mContext, intent);
@@ -1097,7 +1178,6 @@
 
         private RuntimeException mUnbindLocation;
 
-        private boolean mDied;
         private boolean mForgotten;
 
         private static class ConnectionInfo {
@@ -1196,7 +1276,6 @@
             ServiceDispatcher.ConnectionInfo old;
 
             synchronized (this) {
-                mDied = true;
                 old = mActiveConnections.remove(name);
                 if (old == null || old.binder != service) {
                     // Death for someone different than who we last
@@ -1231,7 +1310,6 @@
 
                 if (service != null) {
                     // A new service is being connected... set it all up.
-                    mDied = false;
                     info = new ConnectionInfo();
                     info.binder = service;
                     info.deathMonitor = new DeathMonitor(name, service);
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 873e337..2a1e3c2 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -144,7 +144,7 @@
             
             if (desiredState == RESUMED) {
                 if (localLOGV) Log.v(TAG, r.id + ": resuming");
-                mActivityThread.performResumeActivity(r, true);
+                mActivityThread.performResumeActivity(r, true, "moveToState-INITIALIZING");
                 r.curState = RESUMED;
             }
             
@@ -167,7 +167,7 @@
                 if (desiredState == RESUMED) {
                     if (localLOGV) Log.v(TAG, r.id + ": restarting and resuming");
                     mActivityThread.performRestartActivity(r);
-                    mActivityThread.performResumeActivity(r, true);
+                    mActivityThread.performResumeActivity(r, true, "moveToState-CREATED");
                     r.curState = RESUMED;
                 }
                 return;
@@ -176,13 +176,13 @@
                 if (desiredState == RESUMED) {
                     // Need to resume it...
                     if (localLOGV) Log.v(TAG, r.id + ": resuming");
-                    mActivityThread.performResumeActivity(r, true);
+                    mActivityThread.performResumeActivity(r, true, "moveToState-STARTED");
                     r.instanceState = null;
                     r.curState = RESUMED;
                 }
                 if (desiredState == CREATED) {
                     if (localLOGV) Log.v(TAG, r.id + ": stopping");
-                    mActivityThread.performStopActivity(r, false);
+                    mActivityThread.performStopActivity(r, false, "moveToState-STARTED");
                     r.curState = CREATED;
                 }
                 return;
@@ -197,7 +197,7 @@
                     if (localLOGV) Log.v(TAG, r.id + ": pausing");
                     performPause(r, mFinishing);
                     if (localLOGV) Log.v(TAG, r.id + ": stopping");
-                    mActivityThread.performStopActivity(r, false);
+                    mActivityThread.performStopActivity(r, false, "moveToState-RESUMED");
                     r.curState = CREATED;
                 }
                 return;
@@ -205,9 +205,9 @@
     }
     
     private void performPause(LocalActivityRecord r, boolean finishing) {
-        boolean needState = r.instanceState == null;
-        Bundle instanceState = mActivityThread.performPauseActivity(r,
-                finishing, needState);
+        final boolean needState = r.instanceState == null;
+        final Bundle instanceState = mActivityThread.performPauseActivity(
+                r, finishing, needState, "performPause");
         if (needState) {
             r.instanceState = instanceState;
         }
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index 181c907..70a5e15 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 import com.android.internal.app.MediaRouteDialogPresenter;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.res.TypedArray;
@@ -279,7 +280,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return super.verifyDrawable(who) || who == mRemoteIndicator;
     }
 
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index aa14cb5..b6e0467 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -95,8 +95,7 @@
     
     private native long loadNativeCode(String path, String funcname, MessageQueue queue,
             String internalDataPath, String obbPath, String externalDataPath, int sdkVersion,
-            AssetManager assetMgr, byte[] savedState, ClassLoader classLoader, String libraryPath,
-            String isolationPath);
+            AssetManager assetMgr, byte[] savedState, ClassLoader classLoader, String libraryPath);
     private native String getDlError();
     private native void unloadNativeCode(long handle);
     private native void onStartNative(long handle);
@@ -166,7 +165,8 @@
         String path = classLoader.findLibrary(libname);
 
         if (path == null) {
-            throw new IllegalArgumentException("Unable to find native library: " + libname);
+            throw new IllegalArgumentException("Unable to find native library " + libname +
+                                               " using classloader: " + classLoader.toString());
         }
         
         byte[] nativeSavedState = savedInstanceState != null
@@ -176,8 +176,7 @@
                 getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
                 getAbsolutePath(getExternalFilesDir(null)),
                 Build.VERSION.SDK_INT, getAssets(), nativeSavedState,
-                classLoader, classLoader.getLdLibraryPath(),
-                classLoader.getLibraryPermittedPath());
+                classLoader, classLoader.getLdLibraryPath());
 
         if (mNativeHandle == 0) {
             throw new UnsatisfiedLinkError(
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 402c112..8423de8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -21,11 +21,9 @@
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
@@ -44,7 +42,13 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
 import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.CharacterStyle;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.TextAppearanceSpan;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedValue;
@@ -65,7 +69,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -564,6 +567,12 @@
     public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
 
     /**
+     * Special value of {@link #color} used as a place holder for an invalid color.
+     */
+    @ColorInt
+    private static final int COLOR_INVALID = 1;
+
+    /**
      * Sphere of visibility of this notification, which affects how and when the SystemUI reveals 
      * the notification's presence and contents in untrusted situations (namely, on the secure 
      * lockscreen).
@@ -823,6 +832,12 @@
     public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
 
     /**
+     * {@link #extras} key: whether the chronometer set on the notification should count down
+     * instead of counting up. Is only relevant if key {@link #EXTRA_SHOW_CHRONOMETER} is present.
+     */
+    public static final String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
+
+    /**
      * {@link #extras} key: whether {@link #when} should be shown,
      * as supplied to {@link Builder#setShowWhen(boolean)}.
      */
@@ -947,7 +962,7 @@
             if (in.readInt() == 1) {
                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
             }
-            mExtras = in.readBundle();
+            mExtras = Bundle.setDefusable(in.readBundle(), true);
             mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR);
         }
 
@@ -1477,7 +1492,7 @@
 
         mSortKey = parcel.readString();
 
-        extras = parcel.readBundle(); // may be null
+        extras = Bundle.setDefusable(parcel.readBundle(), true); // may be null
 
         actions = parcel.createTypedArray(Action.CREATOR); // may be null
 
@@ -1645,8 +1660,39 @@
                     + " instance is a custom Parcelable and not allowed in Notification");
             return cs.toString();
         }
+        return removeTextSizeSpans(cs);
+    }
 
-        return cs;
+    private static CharSequence removeTextSizeSpans(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 (resultSpan instanceof CharacterStyle) {
+                    resultSpan = ((CharacterStyle) span).getUnderlying();
+                }
+                if (resultSpan instanceof TextAppearanceSpan) {
+                    TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
+                    resultSpan = new TextAppearanceSpan(
+                            originalSpan.getFamily(),
+                            originalSpan.getTextStyle(),
+                            -1,
+                            originalSpan.getTextColor(),
+                            originalSpan.getLinkTextColor());
+                } else if (resultSpan instanceof RelativeSizeSpan
+                        || resultSpan instanceof AbsoluteSizeSpan) {
+                    continue;
+                } else {
+                    resultSpan = span;
+                }
+                builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
+                        ss.getSpanFlags(span));
+            }
+            return builder;
+        }
+        return charSequence;
     }
 
     public int describeContents() {
@@ -2051,6 +2097,12 @@
         private boolean mColorUtilInited = false;
 
         /**
+         * Caches a contrast-enhanced version of {@link #mCachedContrastColorIsFor}.
+         */
+        private int mCachedContrastColor = COLOR_INVALID;
+        private int mCachedContrastColorIsFor = COLOR_INVALID;
+
+        /**
          * Constructs a new Builder with the defaults:
          *
 
@@ -2158,8 +2210,12 @@
          *
          * Useful when showing an elapsed time (like an ongoing phone call).
          *
+         * The counter can also be set to count down to <code>when</code> when using
+         * {@link #setChronometerCountsDown(boolean)}.
+         *
          * @see android.widget.Chronometer
          * @see Notification#when
+         * @see #setChronometerCountsDown(boolean)
          */
         public Builder setUsesChronometer(boolean b) {
             mN.extras.putBoolean(EXTRA_SHOW_CHRONOMETER, b);
@@ -2167,6 +2223,19 @@
         }
 
         /**
+         * Sets the Chronometer to count down instead of counting up.
+         *
+         * <p>This is only relevant if {@link #setUsesChronometer(boolean)} has been set to true.
+         * If it isn't set the chronometer will count up.
+         *
+         * @see #setUsesChronometer(boolean)
+         */
+        public Builder setChronometerCountsDown(boolean countsDown) {
+            mN.extras.putBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN, countsDown);
+            return this;
+        }
+
+        /**
          * Set the small icon resource, which will be used to represent the notification in the
          * status bar.
          *
@@ -2942,7 +3011,6 @@
             contentView.setViewVisibility(R.id.chronometer, View.GONE);
             contentView.setViewVisibility(R.id.header_sub_text, View.GONE);
             contentView.setViewVisibility(R.id.header_content_info, View.GONE);
-            contentView.setViewVisibility(R.id.number_of_children, View.GONE);
             contentView.setViewVisibility(R.id.sub_text_divider, View.GONE);
             contentView.setViewVisibility(R.id.content_info_divider, View.GONE);
             contentView.setViewVisibility(R.id.time_divider, View.GONE);
@@ -3017,7 +3085,7 @@
                         R.id.progress, ColorStateList.valueOf(mContext.getColor(
                                 R.color.notification_progress_background_color)));
                 if (mN.color != COLOR_DEFAULT) {
-                    ColorStateList colorStateList = ColorStateList.valueOf(mN.color);
+                    ColorStateList colorStateList = ColorStateList.valueOf(resolveContrastColor());
                     contentView.setProgressTintList(R.id.progress, colorStateList);
                     contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
                 }
@@ -3043,7 +3111,6 @@
 
         private void bindNotificationHeader(RemoteViews contentView) {
             bindSmallIcon(contentView);
-            bindChildCountColor(contentView);
             bindHeaderAppName(contentView);
             bindHeaderSubText(contentView);
             bindContentInfo(contentView);
@@ -3052,10 +3119,6 @@
             bindProfileBadge(contentView);
         }
 
-        private void bindChildCountColor(RemoteViews contentView) {
-            contentView.setTextColor(R.id.number_of_children, resolveColor());
-        }
-
         private void bindContentInfo(RemoteViews contentView) {
             boolean visible = false;
             if (mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
@@ -3083,10 +3146,10 @@
         }
 
         private void bindExpandButton(RemoteViews contentView) {
-            contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveColor(),
+            contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveContrastColor(),
                     PorterDuff.Mode.SRC_ATOP, -1);
             contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
-                    resolveColor());
+                    resolveContrastColor());
         }
 
         private void bindHeaderChronometerAndTime(RemoteViews contentView) {
@@ -3097,6 +3160,8 @@
                     contentView.setLong(R.id.chronometer, "setBase",
                             mN.when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
                     contentView.setBoolean(R.id.chronometer, "setStarted", true);
+                    boolean countsDown = mN.extras.getBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN);
+                    contentView.setChronometerCountsDown(R.id.chronometer, countsDown);
                 } else {
                     contentView.setViewVisibility(R.id.time, View.VISIBLE);
                     contentView.setLong(R.id.time, "setTime", mN.when);
@@ -3119,21 +3184,14 @@
         }
 
         private void bindHeaderAppName(RemoteViews contentView) {
-            PackageManager packageManager = mContext.getPackageManager();
-            ApplicationInfo info = null;
-            try {
-                info = packageManager.getApplicationInfo(mContext.getApplicationInfo().packageName,
-                        0);
-            } catch (final NameNotFoundException e) {
-                return;
-            }
-            CharSequence appName = info != null ? packageManager.getApplicationLabel(info)
-                    : null;
+            CharSequence appName = mContext.getPackageManager()
+                    .getApplicationLabel(mContext.getApplicationInfo());
+
             if (TextUtils.isEmpty(appName)) {
                 return;
             }
             contentView.setTextViewText(R.id.app_name_text, appName);
-            contentView.setTextColor(R.id.app_name_text, resolveColor());
+            contentView.setTextColor(R.id.app_name_text, resolveContrastColor());
         }
 
         private void bindSmallIcon(RemoteViews contentView) {
@@ -3150,6 +3208,7 @@
         }
 
         private void resetStandardTemplateWithActions(RemoteViews big) {
+            big.setViewVisibility(R.id.actions_container, View.GONE);
             big.setViewVisibility(R.id.actions, View.GONE);
             big.removeAllViews(R.id.actions);
 
@@ -3171,6 +3230,7 @@
 
             int N = mActions.size();
             if (N > 0) {
+                big.setViewVisibility(R.id.actions_container, View.VISIBLE);
                 big.setViewVisibility(R.id.actions, View.VISIBLE);
                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
                 for (int i=0; i<N; i++) {
@@ -3233,7 +3293,7 @@
          *   2. Style's proposed content view
          *   3. Standard template view
          */
-        public RemoteViews makeContentView() {
+        public RemoteViews createContentView() {
             if (mN.contentView != null && (mStyle == null || !mStyle.displayCustomViewInline())) {
                 return mN.contentView;
             } else if (mStyle != null) {
@@ -3248,7 +3308,7 @@
         /**
          * Construct a RemoteViews for the final big notification layout.
          */
-        public RemoteViews makeBigContentView() {
+        public RemoteViews createBigContentView() {
             RemoteViews result = null;
             if (mN.bigContentView != null
                     && (mStyle == null || !mStyle.displayCustomViewInline())) {
@@ -3291,7 +3351,7 @@
         /**
          * Construct a RemoteViews for the final heads-up notification layout.
          */
-        public RemoteViews makeHeadsUpContentView() {
+        public RemoteViews createHeadsUpContentView() {
             if (mN.headsUpContentView != null
                     && (mStyle == null ||  !mStyle.displayCustomViewInline())) {
                 return mN.headsUpContentView;
@@ -3304,7 +3364,6 @@
                 return null;
             }
 
-
             return applyStandardTemplateWithActions(getBigBaseLayoutResource());
         }
 
@@ -3316,7 +3375,7 @@
         public RemoteViews makePublicContentView() {
             if (mN.publicVersion != null) {
                 final Builder builder = recoverBuilder(mContext, mN.publicVersion);
-                return builder.makeContentView();
+                return builder.createContentView();
             }
             Bundle savedBundle = mN.extras;
             Style style = mStyle;
@@ -3328,6 +3387,8 @@
                     savedBundle.getBoolean(EXTRA_SHOW_WHEN));
             publicExtras.putBoolean(EXTRA_SHOW_CHRONOMETER,
                     savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER));
+            publicExtras.putBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN,
+                    savedBundle.getBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN));
             publicExtras.putCharSequence(EXTRA_TITLE,
                     mContext.getString(R.string.notification_hidden_text));
             mN.extras = publicExtras;
@@ -3355,7 +3416,7 @@
                 button.setRemoteInputs(R.id.action0, action.mRemoteInputs);
             }
             if (mN.color != COLOR_DEFAULT) {
-                button.setTextColor(R.id.action0, mN.color);
+                button.setTextColor(R.id.action0, resolveContrastColor());
             }
             return button;
         }
@@ -3382,12 +3443,12 @@
         private void processSmallIconColor(Icon smallIcon, RemoteViews contentView) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
             if (colorable) {
-                contentView.setDrawableParameters(R.id.icon, false, -1, resolveColor(),
+                contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(),
                         PorterDuff.Mode.SRC_ATOP, -1);
 
             }
             contentView.setInt(R.id.notification_header, "setOriginalIconColor",
-                    colorable ? resolveColor() : NotificationHeaderView.NO_COLOR);
+                    colorable ? resolveContrastColor() : NotificationHeaderView.NO_COLOR);
         }
 
         /**
@@ -3399,7 +3460,7 @@
             if (largeIcon != null && isLegacy()
                     && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
                 // resolve color will fall back to the default when legacy
-                contentView.setDrawableParameters(R.id.icon, false, -1, resolveColor(),
+                contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(),
                         PorterDuff.Mode.SRC_ATOP, -1);
             }
         }
@@ -3410,11 +3471,14 @@
             }
         }
 
-        int resolveColor() {
-            if (mN.color == COLOR_DEFAULT) {
-                return mContext.getColor(R.color.notification_icon_default_color);
+        int resolveContrastColor() {
+            if (mCachedContrastColorIsFor == mN.color && mCachedContrastColor != COLOR_INVALID) {
+                return mCachedContrastColor;
             }
-            return mN.color;
+            final int contrasted = NotificationColorUtil.resolveContrastColor(mContext, mN.color);
+
+            mCachedContrastColorIsFor = mN.color;
+            return mCachedContrastColor = contrasted;
         }
 
         /**
@@ -3437,6 +3501,11 @@
             return mN;
         }
 
+        /**
+         * Creates a Builder from an existing notification so further changes can be made.
+         * @param context The context for your application / activity.
+         * @param n The notification to create a Builder from.
+         */
         public static Notification.Builder recoverBuilder(Context context, Notification n) {
             // Re-create notification context so we can access app resources.
             ApplicationInfo applicationInfo = n.extras.getParcelable(
@@ -3496,21 +3565,22 @@
                 mStyle.buildStyled(mN);
             }
 
-            if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+            if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
+                    && (mStyle == null || !mStyle.displayCustomViewInline())) {
                 if (mN.contentView == null) {
-                    mN.contentView = makeContentView();
+                    mN.contentView = createContentView();
                     mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
                             mN.contentView.getSequenceNumber());
                 }
                 if (mN.bigContentView == null) {
-                    mN.bigContentView = makeBigContentView();
+                    mN.bigContentView = createBigContentView();
                     if (mN.bigContentView != null) {
                         mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
                                 mN.bigContentView.getSequenceNumber());
                     }
                 }
                 if (mN.headsUpContentView == null) {
-                    mN.headsUpContentView = makeHeadsUpContentView();
+                    mN.headsUpContentView = createHeadsUpContentView();
                     if (mN.headsUpContentView != null) {
                         mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
                                 mN.headsUpContentView.getSequenceNumber());
@@ -3536,37 +3606,53 @@
         }
 
         /**
+         * Removes RemoteViews that were created for compatibility from {@param n}, if they did not
+         * change.
+         *
+         * @return {@param n}, if no stripping is needed, otherwise a stripped clone of {@param n}.
+         *
          * @hide
          */
-        public static void stripForDelivery(Notification n) {
+        public static Notification maybeCloneStrippedForDelivery(Notification n) {
             String templateClass = n.extras.getString(EXTRA_TEMPLATE);
-            if (TextUtils.isEmpty(templateClass)) {
-                return;
-            }
+
             // Only strip views for known Styles because we won't know how to
             // re-create them otherwise.
-            if (getNotificationStyleClass(templateClass) == null) {
-                return;
+            if (!TextUtils.isEmpty(templateClass)
+                    && getNotificationStyleClass(templateClass) == null) {
+                return n;
             }
-            // Get rid of unmodified BuilderRemoteViews.
-            if (n.contentView instanceof BuilderRemoteViews &&
+
+            // Only strip unmodified BuilderRemoteViews.
+            boolean stripContentView = n.contentView instanceof BuilderRemoteViews &&
                     n.extras.getInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, -1) ==
-                            n.contentView.getSequenceNumber()) {
-                n.contentView = null;
-                n.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT);
-            }
-            if (n.bigContentView instanceof BuilderRemoteViews &&
+                            n.contentView.getSequenceNumber();
+            boolean stripBigContentView = n.bigContentView instanceof BuilderRemoteViews &&
                     n.extras.getInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, -1) ==
-                            n.bigContentView.getSequenceNumber()) {
-                n.bigContentView = null;
-                n.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT);
-            }
-            if (n.headsUpContentView instanceof BuilderRemoteViews &&
+                            n.bigContentView.getSequenceNumber();
+            boolean stripHeadsUpContentView = n.headsUpContentView instanceof BuilderRemoteViews &&
                     n.extras.getInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, -1) ==
-                            n.headsUpContentView.getSequenceNumber()) {
-                n.headsUpContentView = null;
-                n.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT);
+                            n.headsUpContentView.getSequenceNumber();
+
+            // Nothing to do here, no need to clone.
+            if (!stripContentView && !stripBigContentView && !stripHeadsUpContentView) {
+                return n;
             }
+
+            Notification clone = n.clone();
+            if (stripContentView) {
+                clone.contentView = null;
+                clone.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT);
+            }
+            if (stripBigContentView) {
+                clone.bigContentView = null;
+                clone.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT);
+            }
+            if (stripHeadsUpContentView) {
+                clone.headsUpContentView = null;
+                clone.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT);
+            }
+            return clone;
         }
 
         private int getBaseLayoutResource() {
@@ -4145,7 +4231,8 @@
             int i=0;
             final float density = mBuilder.mContext.getResources().getDisplayMetrics().density;
             int topPadding = (int) (5 * density);
-            int bottomPadding = (int) (13 * density);
+            int bottomPadding = mBuilder.mContext.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.notification_content_margin_bottom);
             boolean first = true;
             while (i < mTexts.size() && i < rowIds.length) {
                 CharSequence str = mTexts.get(i);
@@ -4354,7 +4441,7 @@
 
                     final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
                     final RemoteViews button = generateMediaActionButton(action,
-                            mBuilder.resolveColor());
+                            mBuilder.resolveContrastColor());
                     view.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
@@ -4387,7 +4474,7 @@
                 big.removeAllViews(com.android.internal.R.id.media_actions);
                 for (int i = 0; i < actionCount; i++) {
                     final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i),
-                            mBuilder.resolveColor());
+                            mBuilder.resolveContrastColor());
                     big.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
@@ -4509,8 +4596,13 @@
 
         private void buildIntoRemoteViewContent(RemoteViews remoteViews,
                 RemoteViews customContent) {
-            remoteViews.removeAllViews(R.id.notification_main_column);
-            remoteViews.addView(R.id.notification_main_column, customContent);
+            if (customContent != null) {
+                // Need to clone customContent before adding, because otherwise it can no longer be
+                // parceled independently of remoteViews.
+                customContent = customContent.clone();
+                remoteViews.removeAllViews(R.id.notification_main_column);
+                remoteViews.addView(R.id.notification_main_column, customContent);
+            }
             // also update the end margin if there is an image
             int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
                     R.dimen.notification_content_margin_end);
@@ -4613,8 +4705,13 @@
 
         private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
                 RemoteViews customContent) {
-            remoteViews.removeAllViews(id);
-            remoteViews.addView(id, customContent);
+            if (customContent != null) {
+                // Need to clone customContent before adding, because otherwise it can no longer be
+                // parceled independently of remoteViews.
+                customContent = customContent.clone();
+                remoteViews.removeAllViews(id);
+                remoteViews.addView(id, customContent);
+            }
             return remoteViews;
         }
     }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 324a0ab..47bff64 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.util.Preconditions;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -45,8 +46,14 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Class to notify the user of events that happen.  This is how you tell
@@ -138,27 +145,39 @@
     public static final String ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL
             = "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL";
 
+    /** @hide */
+    @IntDef({INTERRUPTION_FILTER_NONE, INTERRUPTION_FILTER_PRIORITY, INTERRUPTION_FILTER_ALARMS,
+            INTERRUPTION_FILTER_ALL, INTERRUPTION_FILTER_UNKNOWN})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InterruptionFilter {}
+
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     Normal interruption filter.
+     *     Normal interruption filter - no notifications are suppressed.
      */
     public static final int INTERRUPTION_FILTER_ALL = 1;
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     Priority interruption filter.
+     *     Priority interruption filter - all notifications are suppressed except those that match
+     *     the priority criteria. Some audio streams are muted. See
+     *     {@link Policy#priorityCallSenders}, {@link Policy#priorityCategories},
+     *     {@link Policy#priorityMessageSenders} to define or query this criteria. Users can
+     *     additionally specify packages that can bypass this interruption filter.
      */
     public static final int INTERRUPTION_FILTER_PRIORITY = 2;
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     No interruptions filter.
+     *     No interruptions filter - all notifications are suppressed and all audio streams (except
+     *     those used for phone calls) and vibrations are muted.
      */
     public static final int INTERRUPTION_FILTER_NONE = 3;
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     Alarms only interruption filter.
+     *     Alarms only interruption filter - all notifications except those of category
+     *     {@link Notification#CATEGORY_ALARM} are suppressed. Some audio streams are muted.
      */
     public static final int INTERRUPTION_FILTER_ALARMS = 4;
 
@@ -245,8 +264,7 @@
             }
         }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
-        final Notification copy = notification.clone();
-        Builder.stripForDelivery(copy);
+        final Notification copy = Builder.maybeCloneStrippedForDelivery(notification);
         try {
             service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                     copy, idOut, user.getIdentifier());
@@ -254,6 +272,7 @@
                 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
             }
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -294,6 +313,7 @@
         try {
             service.cancelNotificationWithTag(pkg, tag, id, user.getIdentifier());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -309,6 +329,7 @@
         try {
             service.cancelAllNotifications(pkg, UserHandle.myUserId());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -320,7 +341,7 @@
         try {
             return service.getEffectsSuppressor();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -332,7 +353,7 @@
         try {
             return service.matchesCallFilter(extras);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -344,7 +365,7 @@
         try {
             return service.isSystemConditionProviderEnabled(path);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -356,6 +377,7 @@
         try {
             service.setZenMode(mode, conditionId, reason);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -367,8 +389,8 @@
         try {
             return service.getZenMode();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return Global.ZEN_MODE_OFF;
     }
 
     /**
@@ -379,8 +401,8 @@
         try {
             return service.getZenModeConfig();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -391,31 +413,38 @@
         try {
             return service.getRuleInstanceCount(owner);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return 0;
     }
 
     /**
      * Returns AutomaticZenRules owned by the caller.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      */
-    public List<AutomaticZenRule> getAutomaticZenRules() {
+    public Map<String, AutomaticZenRule> getAutomaticZenRules() {
         INotificationManager service = getService();
         try {
-            return service.getAutomaticZenRules();
+            List<ZenModeConfig.ZenRule> rules = service.getZenRules();
+            Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
+            for (ZenModeConfig.ZenRule rule : rules) {
+                ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+                        rule.conditionId, zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
+                        rule.creationTime));
+            }
+            return ruleMap;
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
      * Returns the AutomaticZenRule with the given id, if it exists and the caller has access.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * <p>
@@ -427,56 +456,56 @@
         try {
             return service.getAutomaticZenRule(id);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
      * Creates the given zen rule.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * @param automaticZenRule the rule to create.
-     * @return A fully populated {@link AutomaticZenRule} if the rule was persisted successfully,
-     * null otherwise.
+     * @return The id of the newly created rule; null if the rule could not be created.
      */
-    public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
+    public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
         INotificationManager service = getService();
         try {
             return service.addAutomaticZenRule(automaticZenRule);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
      * Updates the given zen rule.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * <p>
      * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
+     * @param id The id of the rule to update
      * @param automaticZenRule the rule to update. 
      * @return Whether the rule was successfully updated.
      */
-    public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule) {
+    public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) {
         INotificationManager service = getService();
         try {
-            return service.updateAutomaticZenRule(automaticZenRule);
+            return service.updateAutomaticZenRule(id, automaticZenRule);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
      * Deletes the automatic zen rule with the given id.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * <p>
@@ -489,8 +518,8 @@
         try {
             return service.removeAutomaticZenRule(id);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -503,26 +532,32 @@
         try {
             return service.removeAutomaticZenRules(packageName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
-    public int getImportance() {
+    /**
+     * Returns the user specified importance for notifications from the calling package.
+     */
+    public @NotificationListenerService.Ranking.Importance int getImportance() {
         INotificationManager service = getService();
         try {
             return service.getPackageImportance(mContext.getPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
     }
 
+    /**
+     * Returns whether notifications from the calling package are blocked.
+     */
     public boolean areNotificationsEnabled() {
         INotificationManager service = getService();
         try {
             return service.areNotificationsEnabled(mContext.getPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -544,8 +579,8 @@
         try {
             return service.isNotificationPolicyAccessGranted(mContext.getOpPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /** @hide */
@@ -554,8 +589,8 @@
         try {
             return service.isNotificationPolicyAccessGrantedForPackage(pkg);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -570,8 +605,8 @@
         try {
             return service.getNotificationPolicy(mContext.getOpPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -589,6 +624,7 @@
         try {
             service.setNotificationPolicy(mContext.getOpPackageName(), policy);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -598,6 +634,7 @@
         try {
             service.setNotificationPolicyAccessGranted(pkg, granted);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -614,8 +651,9 @@
                 return rt;
             }
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return new ArraySet<String>();
+        return new ArraySet<>();
     }
 
     private Context mContext;
@@ -628,7 +666,7 @@
 
     /**
      * Notification policy configuration.  Represents user-preferences for notification
-     * filtering and prioritization.
+     * filtering.
      */
     public static class Policy implements android.os.Parcelable {
         /** Reminder notifications are prioritized. */
@@ -673,13 +711,13 @@
          */
         public static final int SUPPRESSED_EFFECTS_UNSET = -1;
         /**
-         * Whether notification suppressed by DND should not interruption visually when the screen
-         * is off.
+         * Whether notifications suppressed by DND should not interrupt visually (e.g. with
+         * notification lights or by turning the screen on) when the screen is off.
          */
         public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1 << 0;
         /**
-         * Whether notification suppressed by DND should not interruption visually when the screen
-         * is on.
+         * Whether notifications suppressed by DND should not interrupt visually when the screen
+         * is on (e.g. by peeking onto the screen).
          */
         public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 1;
 
@@ -694,13 +732,27 @@
          */
         public final int suppressedVisualEffects;
 
-
-        @Deprecated
+        /**
+         * Constructs a policy for Do Not Disturb priority mode behavior.
+         *
+         * @param priorityCategories bitmask of categories of notifications that can bypass DND.
+         * @param priorityCallSenders which callers can bypass DND.
+         * @param priorityMessageSenders which message senders can bypass DND.
+         */
         public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) {
             this(priorityCategories, priorityCallSenders, priorityMessageSenders,
                     SUPPRESSED_EFFECTS_UNSET);
         }
 
+        /**
+         * Constructs a policy for Do Not Disturb priority mode behavior.
+         *
+         * @param priorityCategories bitmask of categories of notifications that can bypass DND.
+         * @param priorityCallSenders which callers can bypass DND.
+         * @param priorityMessageSenders which message senders can bypass DND.
+         * @param suppressedVisualEffects which visual interruptions should be suppressed from
+         *                                notifications that are filtered by DND.
+         */
         public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders,
                 int suppressedVisualEffects) {
             this.priorityCategories = priorityCategories;
@@ -831,7 +883,6 @@
                 return new Policy[size];
             }
         };
-
     }
 
     /**
@@ -856,9 +907,8 @@
             final List<StatusBarNotification> list = parceledList.getList();
             return list.toArray(new StatusBarNotification[list.size()]);
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+            throw e.rethrowFromSystemServer();
         }
-        return new StatusBarNotification[0];
     }
 
     /**
@@ -869,19 +919,14 @@
      * (e.g. via sound &amp; vibration) and is applied globally.
      * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
      * unavailable.
-     *
-     * <p>
-     * Only available if policy access is granted to this package.
-     * See {@link #isNotificationPolicyAccessGranted}.
      */
-    public final int getCurrentInterruptionFilter() {
+    public final @InterruptionFilter int getCurrentInterruptionFilter() {
         final INotificationManager service = getService();
         try {
             return zenModeToInterruptionFilter(service.getZenMode());
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+            throw e.rethrowFromSystemServer();
         }
-        return INTERRUPTION_FILTER_UNKNOWN;
     }
 
     /**
@@ -902,7 +947,7 @@
         try {
             service.setInterruptionFilter(mContext.getOpPackageName(), interruptionFilter);
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 94e584e..4c4f128 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -18,13 +18,17 @@
 
 import static android.app.ActivityThread.DEBUG_CONFIGURATION;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
 import android.content.res.AssetManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.ResourcesImpl;
 import android.content.res.ResourcesKey;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.LocaleList;
@@ -33,11 +37,16 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayAdjustments;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
-import java.util.List;
+import java.util.Objects;
+import java.util.WeakHashMap;
+import java.util.function.Predicate;
 
 /** @hide */
 public class ResourcesManager {
@@ -45,18 +54,65 @@
     private static final boolean DEBUG = false;
 
     private static ResourcesManager sResourcesManager;
-    private final ArrayMap<ResourcesKey, WeakReference<Resources>> mActiveResources =
-            new ArrayMap<>();
-    private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>> mDisplays =
-            new ArrayMap<>();
 
-    private String[] mSystemLocales = {};
-    private final HashSet<String> mNonSystemLocales = new HashSet<String>();
+    /**
+     * Predicate that returns true if a WeakReference is gc'ed.
+     */
+    private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate =
+            new Predicate<WeakReference<Resources>>() {
+                @Override
+                public boolean test(WeakReference<Resources> weakRef) {
+                    return weakRef == null || weakRef.get() == null;
+                }
+            };
+
+    private String[] mSystemLocales = null;
+    private final HashSet<String> mNonSystemLocales = new HashSet<>();
     private boolean mHasNonSystemLocales = false;
 
-    CompatibilityInfo mResCompatibilityInfo;
+    /**
+     * The global compatibility settings.
+     */
+    private CompatibilityInfo mResCompatibilityInfo;
 
-    Configuration mResConfiguration;
+    /**
+     * The global configuration upon which all Resources are based. Multi-window Resources
+     * apply their overrides to this configuration.
+     */
+    private final Configuration mResConfiguration = new Configuration();
+
+    /**
+     * A mapping of ResourceImpls and their configurations. These are heavy weight objects
+     * which should be reused as much as possible.
+     */
+    private final ArrayMap<ResourcesKey, WeakReference<ResourcesImpl>> mResourceImpls =
+            new ArrayMap<>();
+
+    /**
+     * A list of Resource references that can be reused.
+     */
+    private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
+
+    /**
+     * Resources and base configuration override associated with an Activity.
+     */
+    private static class ActivityResources {
+        public final Configuration overrideConfig = new Configuration();
+        public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
+    }
+
+    /**
+     * Each Activity may has a base override configuration that is applied to each Resources object,
+     * which in turn may have their own override configuration specified.
+     */
+    private final WeakHashMap<IBinder, ActivityResources> mActivityResourceReferences =
+            new WeakHashMap<>();
+
+    /**
+     * A cache of DisplayId to DisplayAdjustments.
+     */
+    private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>> mDisplays =
+            new ArrayMap<>();
 
     public static ResourcesManager getInstance() {
         synchronized (ResourcesManager.class) {
@@ -68,14 +124,20 @@
     }
 
     public Configuration getConfiguration() {
-        return mResConfiguration;
+        synchronized (this) {
+            return mResConfiguration;
+        }
     }
 
-    DisplayMetrics getDisplayMetricsLocked() {
-        return getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
+    DisplayMetrics getDisplayMetrics() {
+        return getDisplayMetrics(Display.DEFAULT_DISPLAY);
     }
 
-    DisplayMetrics getDisplayMetricsLocked(int displayId) {
+    /**
+     * Protected so that tests can override and returns something a fixed value.
+     */
+    @VisibleForTesting
+    protected DisplayMetrics getDisplayMetrics(int displayId) {
         DisplayMetrics dm = new DisplayMetrics();
         final Display display =
                 getAdjustedDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
@@ -87,12 +149,12 @@
         return dm;
     }
 
-    final void applyNonDefaultDisplayMetricsToConfigurationLocked(
-            DisplayMetrics dm, Configuration config) {
+    private static void applyNonDefaultDisplayMetricsToConfiguration(
+            @NonNull DisplayMetrics dm, @NonNull Configuration config) {
         config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
         config.densityDpi = dm.densityDpi;
-        config.screenWidthDp = (int)(dm.widthPixels / dm.density);
-        config.screenHeightDp = (int)(dm.heightPixels / dm.density);
+        config.screenWidthDp = (int) (dm.widthPixels / dm.density);
+        config.screenHeightDp = (int) (dm.heightPixels / dm.density);
         int sl = Configuration.resetScreenLayout(config.screenLayout);
         if (dm.widthPixels > dm.heightPixels) {
             config.orientation = Configuration.ORIENTATION_LANDSCAPE;
@@ -109,8 +171,8 @@
         config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp;
     }
 
-    public boolean applyCompatConfiguration(int displayDensity,
-            Configuration compatConfiguration) {
+    public boolean applyCompatConfigurationLocked(int displayDensity,
+            @NonNull Configuration compatConfiguration) {
         if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) {
             mResCompatibilityInfo.applyToConfiguration(displayDensity, compatConfiguration);
             return true;
@@ -125,7 +187,8 @@
      * @param displayId display Id.
      * @param displayAdjustments display adjustments.
      */
-    public Display getAdjustedDisplay(final int displayId, DisplayAdjustments displayAdjustments) {
+    public Display getAdjustedDisplay(final int displayId,
+            @Nullable DisplayAdjustments displayAdjustments) {
         final DisplayAdjustments displayAdjustmentsCopy = (displayAdjustments != null)
                 ? new DisplayAdjustments(displayAdjustments) : new DisplayAdjustments();
         final Pair<Integer, DisplayAdjustments> key =
@@ -152,76 +215,42 @@
     }
 
     /**
-     * Creates the top level Resources for applications with the given compatibility info.
+     * Creates an AssetManager from the paths within the ResourcesKey.
      *
-     * @param resDir the resource directory.
-     * @param splitResDirs split resource directories.
-     * @param overlayDirs the resource overlay directories.
-     * @param libDirs the shared library resource dirs this app references.
-     * @param displayId display Id.
-     * @param overrideConfiguration override configurations.
-     * @param compatInfo the compatibility info. Must not be null.
-     * @param classLoader the class loader for the resource package
-     */
-    Resources getTopLevelResources(String resDir, String[] splitResDirs,
-            String[] overlayDirs, String[] libDirs, int displayId,
-            Configuration overrideConfiguration, CompatibilityInfo compatInfo,
-            ClassLoader classLoader) {
-        final float scale = compatInfo.applicationScale;
-        Configuration overrideConfigCopy = (overrideConfiguration != null)
-                ? new Configuration(overrideConfiguration) : null;
-        ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
-        Resources r;
-        final boolean findSystemLocales;
-        final boolean hasNonSystemLocales;
-        synchronized (this) {
-            // Resources is app scale dependent.
-            if (DEBUG) Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
-
-            WeakReference<Resources> wr = mActiveResources.get(key);
-            r = wr != null ? wr.get() : null;
-            //if (r != null) Log.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
-            if (r != null && r.getAssets().isUpToDate()) {
-                if (DEBUG) Slog.w(TAG, "Returning cached resources " + r + " " + resDir
-                        + ": appScale=" + r.getCompatibilityInfo().applicationScale
-                        + " key=" + key + " overrideConfig=" + overrideConfiguration);
-                return r;
-            }
-            findSystemLocales = (mSystemLocales.length == 0);
-            hasNonSystemLocales = mHasNonSystemLocales;
-        }
-
-        //if (r != null) {
-        //    Log.w(TAG, "Throwing away out-of-date resources!!!! "
-        //            + r + " " + resDir);
-        //}
-
+     * This can be overridden in tests so as to avoid creating a real AssetManager with
+     * real APK paths.
+     * @param key The key containing the resource paths to add to the AssetManager.
+     * @return a new AssetManager.
+    */
+    @VisibleForTesting
+    protected AssetManager createAssetManager(@NonNull final ResourcesKey key) {
         AssetManager assets = new AssetManager();
+
         // resDir can be null if the 'android' package is creating a new Resources object.
         // This is fine, since each AssetManager automatically loads the 'android' package
         // already.
-        if (resDir != null) {
-            if (assets.addAssetPath(resDir) == 0) {
+        if (key.mResDir != null) {
+            if (assets.addAssetPath(key.mResDir) == 0) {
                 return null;
             }
         }
 
-        if (splitResDirs != null) {
-            for (String splitResDir : splitResDirs) {
+        if (key.mSplitResDirs != null) {
+            for (final String splitResDir : key.mSplitResDirs) {
                 if (assets.addAssetPath(splitResDir) == 0) {
                     return null;
                 }
             }
         }
 
-        if (overlayDirs != null) {
-            for (String idmapPath : overlayDirs) {
+        if (key.mOverlayDirs != null) {
+            for (final String idmapPath : key.mOverlayDirs) {
                 assets.addOverlayPath(idmapPath);
             }
         }
 
-        if (libDirs != null) {
-            for (String libDir : libDirs) {
+        if (key.mLibDirs != null) {
+            for (final String libDir : key.mLibDirs) {
                 if (libDir.endsWith(".apk")) {
                     // Avoid opening files we know do not have resources,
                     // like code-only .jar files.
@@ -232,16 +261,17 @@
                 }
             }
         }
+        return assets;
+    }
 
-        //Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
-        DisplayMetrics dm = getDisplayMetricsLocked(displayId);
+    private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
         Configuration config;
-        final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+        final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY);
         final boolean hasOverrideConfig = key.hasOverrideConfiguration();
         if (!isDefaultDisplay || hasOverrideConfig) {
             config = new Configuration(getConfiguration());
             if (!isDefaultDisplay) {
-                applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
+                applyNonDefaultDisplayMetricsToConfiguration(dm, config);
             }
             if (hasOverrideConfig) {
                 config.updateFrom(key.mOverrideConfiguration);
@@ -250,15 +280,265 @@
         } else {
             config = getConfiguration();
         }
-        r = new Resources(assets, dm, config, compatInfo, classLoader);
-        if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
-                + r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
+        return config;
+    }
 
-        final String[] systemLocales = (
-                findSystemLocales ?
-                AssetManager.getSystem().getLocales() :
-                null);
-        final String[] nonSystemLocales = assets.getNonSystemLocales();
+    private ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
+        AssetManager assets = createAssetManager(key);
+        DisplayMetrics dm = getDisplayMetrics(key.mDisplayId);
+        Configuration config = generateConfig(key, dm);
+        ResourcesImpl impl = new ResourcesImpl(assets, dm, config, key.mCompatInfo);
+        if (DEBUG) {
+            Slog.d(TAG, "- creating impl=" + impl + " with key: " + key);
+        }
+        return impl;
+    }
+
+    /**
+     * Finds a cached ResourcesImpl object that matches the given ResourcesKey.
+     *
+     * @param key The key to match.
+     * @return a ResourcesImpl if the key matches a cache entry, null otherwise.
+     */
+    private ResourcesImpl findResourcesImplForKeyLocked(@NonNull ResourcesKey key) {
+        WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.get(key);
+        ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
+        if (impl != null && impl.getAssets().isUpToDate()) {
+            return impl;
+        }
+        return null;
+    }
+
+    /**
+     * Find the ResourcesKey that this ResourcesImpl object is associated with.
+     * @return the ResourcesKey or null if none was found.
+     */
+    private ResourcesKey findKeyForResourceImplLocked(@NonNull ResourcesImpl resourceImpl) {
+        final int refCount = mResourceImpls.size();
+        for (int i = 0; i < refCount; i++) {
+            WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
+            ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
+            if (impl != null && resourceImpl == impl) {
+                return mResourceImpls.keyAt(i);
+            }
+        }
+        return null;
+    }
+
+    private ActivityResources getOrCreateActivityResourcesStructLocked(
+            @NonNull IBinder activityToken) {
+        ActivityResources activityResources = mActivityResourceReferences.get(activityToken);
+        if (activityResources == null) {
+            activityResources = new ActivityResources();
+            mActivityResourceReferences.put(activityToken, activityResources);
+        }
+        return activityResources;
+    }
+
+    /**
+     * Gets an existing Resources object tied to this Activity, or creates one if it doesn't exist
+     * or the class loader is different.
+     */
+    private Resources getOrCreateResourcesForActivityLocked(@NonNull IBinder activityToken,
+            @NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl) {
+        final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                activityToken);
+
+        final int refCount = activityResources.activityResources.size();
+        for (int i = 0; i < refCount; i++) {
+            WeakReference<Resources> weakResourceRef = activityResources.activityResources.get(i);
+            Resources resources = weakResourceRef.get();
+
+            if (resources != null
+                    && Objects.equals(resources.getClassLoader(), classLoader)
+                    && resources.getImpl() == impl) {
+                if (DEBUG) {
+                    Slog.d(TAG, "- using existing ref=" + resources);
+                }
+                return resources;
+            }
+        }
+
+        Resources resources = new Resources(classLoader);
+        resources.setImpl(impl);
+        activityResources.activityResources.add(new WeakReference<>(resources));
+        if (DEBUG) {
+            Slog.d(TAG, "- creating new ref=" + resources);
+            Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
+        }
+        return resources;
+    }
+
+    /**
+     * Gets an existing Resources object if the class loader and ResourcesImpl are the same,
+     * otherwise creates a new Resources object.
+     */
+    private Resources getOrCreateResourcesLocked(@NonNull ClassLoader classLoader,
+            @NonNull ResourcesImpl impl) {
+        // Find an existing Resources that has this ResourcesImpl set.
+        final int refCount = mResourceReferences.size();
+        for (int i = 0; i < refCount; i++) {
+            WeakReference<Resources> weakResourceRef = mResourceReferences.get(i);
+            Resources resources = weakResourceRef.get();
+            if (resources != null &&
+                    Objects.equals(resources.getClassLoader(), classLoader) &&
+                    resources.getImpl() == impl) {
+                if (DEBUG) {
+                    Slog.d(TAG, "- using existing ref=" + resources);
+                }
+                return resources;
+            }
+        }
+
+        // Create a new Resources reference and use the existing ResourcesImpl object.
+        Resources resources = new Resources(classLoader);
+        resources.setImpl(impl);
+        mResourceReferences.add(new WeakReference<>(resources));
+        if (DEBUG) {
+            Slog.d(TAG, "- creating new ref=" + resources);
+            Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
+        }
+        return resources;
+    }
+
+    /**
+     * Creates base resources for an Activity. Calls to
+     * {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
+     * CompatibilityInfo, ClassLoader)} with the same activityToken will have their override
+     * configurations merged with the one specified here.
+     *
+     * @param activityToken Represents an Activity.
+     * @param resDir The base resource path. Can be null (only framework resources will be loaded).
+     * @param splitResDirs An array of split resource paths. Can be null.
+     * @param overlayDirs An array of overlay paths. Can be null.
+     * @param libDirs An array of resource library paths. Can be null.
+     * @param displayId The ID of the display for which to create the resources.
+     * @param overrideConfig The configuration to apply on top of the base configuration. Can be
+     *                       null. This provides the base override for this Activity.
+     * @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
+     *                   {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
+     * @param classLoader The class loader to use when inflating Resources. If null, the
+     *                    {@link ClassLoader#getSystemClassLoader()} is used.
+     * @return a Resources object from which to access resources.
+     */
+    public Resources createBaseActivityResources(@NonNull IBinder activityToken,
+            @Nullable String resDir,
+            @Nullable String[] splitResDirs,
+            @Nullable String[] overlayDirs,
+            @Nullable String[] libDirs,
+            int displayId,
+            @Nullable Configuration overrideConfig,
+            @NonNull CompatibilityInfo compatInfo,
+            @Nullable ClassLoader classLoader) {
+        final ResourcesKey key = new ResourcesKey(
+                resDir,
+                splitResDirs,
+                overlayDirs,
+                libDirs,
+                displayId,
+                overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+                compatInfo);
+        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+
+        if (DEBUG) {
+            Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+                    + " with key=" + key);
+        }
+
+        synchronized (this) {
+            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                    activityToken);
+
+            if (overrideConfig != null) {
+                activityResources.overrideConfig.setTo(overrideConfig);
+            } else {
+                activityResources.overrideConfig.setToDefaults();
+            }
+        }
+
+        // Update any existing Activity Resources references.
+        updateResourcesForActivity(activityToken, overrideConfig);
+
+        // Now request an actual Resources object.
+        return getOrCreateResources(activityToken, key, classLoader);
+    }
+
+    /**
+     * Gets an existing Resources object set with a ResourcesImpl object matching the given key,
+     * or creates one if it doesn't exist.
+     *
+     * @param activityToken The Activity this Resources object should be associated with.
+     * @param key The key describing the parameters of the ResourcesImpl object.
+     * @param classLoader The classloader to use for the Resources object.
+     *                    If null, {@link ClassLoader#getSystemClassLoader()} is used.
+     * @return A Resources object that gets updated when
+     *         {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
+     *         is called.
+     */
+    private Resources getOrCreateResources(@Nullable IBinder activityToken,
+            @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
+        final boolean findSystemLocales;
+        final boolean hasNonSystemLocales;
+        synchronized (this) {
+            findSystemLocales = (mSystemLocales == null || mSystemLocales.length == 0);
+            hasNonSystemLocales = mHasNonSystemLocales;
+
+            if (DEBUG) {
+                Throwable here = new Throwable();
+                here.fillInStackTrace();
+                Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
+            }
+
+            if (activityToken != null) {
+                final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                        activityToken);
+
+                // Clean up any dead references so they don't pile up.
+                ArrayUtils.unstableRemoveIf(activityResources.activityResources,
+                        sEmptyReferencePredicate);
+
+                // Rebase the key's override config on top of the Activity's base override.
+                if (key.hasOverrideConfiguration()
+                        && !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
+                    final Configuration temp = new Configuration(activityResources.overrideConfig);
+                    temp.updateFrom(key.mOverrideConfiguration);
+                    key.mOverrideConfiguration.setTo(temp);
+                }
+
+                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
+                if (resourcesImpl != null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "- using existing impl=" + resourcesImpl);
+                    }
+                    return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
+                            resourcesImpl);
+                }
+
+                // We will create the ResourcesImpl object outside of holding this lock.
+
+            } else {
+                // Clean up any dead references so they don't pile up.
+                ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
+
+                // Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
+                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
+                if (resourcesImpl != null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "- using existing impl=" + resourcesImpl);
+                    }
+                    return getOrCreateResourcesLocked(classLoader, resourcesImpl);
+                }
+
+                // We will create the ResourcesImpl object outside of holding this lock.
+            }
+        }
+
+        // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+        ResourcesImpl resourcesImpl = createResourcesImpl(key);
+
+        final String[] systemLocales = findSystemLocales
+                ? AssetManager.getSystem().getLocales() : null;
+        final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
         // Avoid checking for non-pseudo-locales if we already know there were some from a previous
         // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
         // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
@@ -267,28 +547,189 @@
                 LocaleList.isPseudoLocalesOnly(nonSystemLocales);
 
         synchronized (this) {
-            WeakReference<Resources> wr = mActiveResources.get(key);
-            Resources existing = wr != null ? wr.get() : null;
-            if (existing != null && existing.getAssets().isUpToDate()) {
-                // Someone else already created the resources while we were
-                // unlocked; go ahead and use theirs.
-                r.getAssets().close();
-                return existing;
-            }
-
-            // XXX need to remove entries when weak references go away
-            mActiveResources.put(key, new WeakReference<>(r));
-            if (mSystemLocales.length == 0) {
+            if (mSystemLocales == null || mSystemLocales.length == 0) {
                 mSystemLocales = systemLocales;
             }
             mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
             mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
-            if (DEBUG) Slog.v(TAG, "mActiveResources.size()=" + mActiveResources.size());
-            return r;
+
+            ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
+            if (existingResourcesImpl != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
+                            + " new impl=" + resourcesImpl);
+                }
+                resourcesImpl.getAssets().close();
+                resourcesImpl = existingResourcesImpl;
+            } else {
+                // Add this ResourcesImpl to the cache.
+                mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
+            }
+
+            final Resources resources;
+            if (activityToken != null) {
+                resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
+                        resourcesImpl);
+            } else {
+                resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
+            }
+            return resources;
         }
     }
 
-    /* package */ void setDefaultLocalesLocked(LocaleList locales) {
+    /**
+     * Gets or creates a new Resources object associated with the IBinder token. References returned
+     * by this method live as long as the Activity, meaning they can be cached and used by the
+     * Activity even after a configuration change. If any other parameter is changed
+     * (resDir, splitResDirs, overrideConfig) for a given Activity, the same Resources object
+     * is updated and handed back to the caller. However, changing the class loader will result in a
+     * new Resources object.
+     * <p/>
+     * If activityToken is null, a cached Resources object will be returned if it matches the
+     * input parameters. Otherwise a new Resources object that satisfies these parameters is
+     * returned.
+     *
+     * @param activityToken Represents an Activity. If null, global resources are assumed.
+     * @param resDir The base resource path. Can be null (only framework resources will be loaded).
+     * @param splitResDirs An array of split resource paths. Can be null.
+     * @param overlayDirs An array of overlay paths. Can be null.
+     * @param libDirs An array of resource library paths. Can be null.
+     * @param displayId The ID of the display for which to create the resources.
+     * @param overrideConfig The configuration to apply on top of the base configuration. Can be
+     * null. Mostly used with Activities that are in multi-window which may override width and
+     * height properties from the base config.
+     * @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
+     * {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
+     * @param classLoader The class loader to use when inflating Resources. If null, the
+     * {@link ClassLoader#getSystemClassLoader()} is used.
+     * @return a Resources object from which to access resources.
+     */
+    public Resources getResources(@Nullable IBinder activityToken,
+            @Nullable String resDir,
+            @Nullable String[] splitResDirs,
+            @Nullable String[] overlayDirs,
+            @Nullable String[] libDirs,
+            int displayId,
+            @Nullable Configuration overrideConfig,
+            @NonNull CompatibilityInfo compatInfo,
+            @Nullable ClassLoader classLoader) {
+        final ResourcesKey key = new ResourcesKey(
+                resDir,
+                splitResDirs,
+                overlayDirs,
+                libDirs,
+                displayId,
+                overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+                compatInfo);
+        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+        return getOrCreateResources(activityToken, key, classLoader);
+    }
+
+    /**
+     * Updates an Activity's Resources object with overrideConfig. The Resources object
+     * that was previously returned by
+     * {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
+     * CompatibilityInfo, ClassLoader)} is
+     * still valid and will have the updated configuration.
+     * @param activityToken The Activity token.
+     * @param overrideConfig The configuration override to update.
+     */
+    public void updateResourcesForActivity(@NonNull IBinder activityToken,
+            @Nullable Configuration overrideConfig) {
+        synchronized (this) {
+            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                    activityToken);
+
+            if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+                // They are the same, no work to do.
+                return;
+            }
+
+            // Grab a copy of the old configuration so we can create the delta's of each
+            // Resources object associated with this Activity.
+            final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
+
+            // Update the Activity's base override.
+            if (overrideConfig != null) {
+                activityResources.overrideConfig.setTo(overrideConfig);
+            } else {
+                activityResources.overrideConfig.setToDefaults();
+            }
+
+            if (DEBUG) {
+                Throwable here = new Throwable();
+                here.fillInStackTrace();
+                Slog.d(TAG, "updating resources override for activity=" + activityToken
+                        + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
+                        + " to newConfig="
+                        + Configuration.resourceQualifierString(activityResources.overrideConfig),
+                        here);
+            }
+
+            final boolean activityHasOverrideConfig =
+                    !activityResources.overrideConfig.equals(Configuration.EMPTY);
+
+            // Rebase each Resources associated with this Activity.
+            final int refCount = activityResources.activityResources.size();
+            for (int i = 0; i < refCount; i++) {
+                WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
+                Resources resources = weakResRef.get();
+                if (resources == null) {
+                    continue;
+                }
+
+                // Extract the ResourcesKey that was last used to create the Resources for this
+                // activity.
+                final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+                if (oldKey == null) {
+                    Slog.e(TAG, "can't find ResourcesKey for resources impl="
+                            + resources.getImpl());
+                    continue;
+                }
+
+                // Build the new override configuration for this ResourcesKey.
+                final Configuration rebasedOverrideConfig = new Configuration();
+                if (overrideConfig != null) {
+                    rebasedOverrideConfig.setTo(overrideConfig);
+                }
+
+                if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+                    // Generate a delta between the old base Activity override configuration and
+                    // the actual final override configuration that was used to figure out the real
+                    // delta this Resources object wanted.
+                    Configuration overrideOverrideConfig = Configuration.generateDelta(
+                            oldConfig, oldKey.mOverrideConfiguration);
+                    rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+                }
+
+                // Create the new ResourcesKey with the rebased override config.
+                final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
+                        oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+                        rebasedOverrideConfig, oldKey.mCompatInfo);
+
+                if (DEBUG) {
+                    Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+                            + " to newKey=" + newKey);
+                }
+
+                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+                if (resourcesImpl == null) {
+                    resourcesImpl = createResourcesImpl(newKey);
+                    mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+                }
+
+                if (resourcesImpl != resources.getImpl()) {
+                    // Set the ResourcesImpl, updating it for all users of this Resources object.
+                    resources.setImpl(resourcesImpl);
+                }
+            }
+        }
+    }
+
+    /* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) {
+        if (mSystemLocales == null) {
+            throw new RuntimeException("ResourcesManager is not ready to negotiate locales.");
+        }
         final int bestLocale;
         if (mHasNonSystemLocales) {
             bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mNonSystemLocales);
@@ -302,11 +743,8 @@
         LocaleList.setDefault(locales, bestLocale);
     }
 
-    final boolean applyConfigurationToResourcesLocked(Configuration config,
-            CompatibilityInfo compat) {
-        if (mResConfiguration == null) {
-            mResConfiguration = new Configuration();
-        }
+    public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
+                                                             @Nullable CompatibilityInfo compat) {
         if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
             if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
                     + mResConfiguration.seq + ", newSeq=" + config.seq);
@@ -315,7 +753,7 @@
         int changes = mResConfiguration.updateFrom(config);
         // Things might have changed in display manager, so clear the cached displays.
         mDisplays.clear();
-        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked();
+        DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
 
         if (compat != null && (mResCompatibilityInfo == null ||
                 !mResCompatibilityInfo.equals(compat))) {
@@ -353,9 +791,9 @@
 
         Configuration tmpConfig = null;
 
-        for (int i = mActiveResources.size() - 1; i >= 0; i--) {
-            ResourcesKey key = mActiveResources.keyAt(i);
-            Resources r = mActiveResources.valueAt(i).get();
+        for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
+            ResourcesKey key = mResourceImpls.keyAt(i);
+            ResourcesImpl r = mResourceImpls.valueAt(i).get();
             if (r != null) {
                 if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
                         + r + " config to: " + localeAdjustedConfig);
@@ -369,8 +807,8 @@
                     }
                     tmpConfig.setTo(localeAdjustedConfig);
                     if (!isDefaultDisplay) {
-                        dm = getDisplayMetricsLocked(displayId);
-                        applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
+                        dm = getDisplayMetrics(displayId);
+                        applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
                     }
                     if (hasOverrideConfiguration) {
                         tmpConfig.updateFrom(key.mOverrideConfiguration);
@@ -383,11 +821,10 @@
                 //        + " " + r + ": " + r.getConfiguration());
             } else {
                 //Slog.i(TAG, "Removing old resources " + v.getKey());
-                mActiveResources.removeAt(i);
+                mResourceImpls.removeAt(i);
             }
         }
 
         return changes != 0;
     }
-
 }
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 9e32164..ac4abf5 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -686,8 +686,7 @@
         try {
             return mService.getGlobalSearchActivities();
         } catch (RemoteException ex) {
-            Log.e(TAG, "getGlobalSearchActivities() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -698,8 +697,7 @@
         try {
             return mService.getGlobalSearchActivity();
         } catch (RemoteException ex) {
-            Log.e(TAG, "getGlobalSearchActivity() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -716,8 +714,7 @@
         try {
             return mService.getWebSearchActivity();
         } catch (RemoteException ex) {
-            Log.e(TAG, "getWebSearchActivity() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -850,8 +847,7 @@
         try {
             return mService.getSearchableInfo(componentName);
         } catch (RemoteException ex) {
-            Log.e(TAG, "getSearchableInfo() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -935,8 +931,7 @@
         try {
             return mService.getSearchablesInGlobalSearch();
         } catch (RemoteException e) {
-            Log.e(TAG, "getSearchablesInGlobalSearch() failed: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -958,8 +953,7 @@
             }
             return intent;
         } catch (RemoteException re) {
-            Log.e(TAG, "getAssistIntent() failed: " + re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -977,7 +971,7 @@
             }
             mService.launchAssist(args);
         } catch (RemoteException re) {
-            Log.e(TAG, "launchAssist() failed: " + re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -995,8 +989,7 @@
             }
             return mService.launchLegacyAssist(hint, userHandle, args);
         } catch (RemoteException re) {
-            Log.e(TAG, "launchAssist() failed: " + re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index b899116..e57a9b5 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -123,8 +123,7 @@
                 svc.disable(what, mToken, mContext.getPackageName());
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -141,8 +140,7 @@
                 svc.disable2(what, mToken, mContext.getPackageName());
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -156,8 +154,7 @@
                 svc.expandNotificationsPanel();
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
     
@@ -171,8 +168,7 @@
                 svc.collapsePanels();
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -193,8 +189,7 @@
                 svc.expandSettingsPanel(subPanel);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -206,8 +201,7 @@
                     contentDescription);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -218,8 +212,7 @@
                 svc.removeIcon(slot);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -230,8 +223,7 @@
                 svc.setIconVisibility(slot, visible);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 52fba3b..bdc4404 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -37,7 +37,9 @@
 import android.content.IRestrictionsManager;
 import android.content.RestrictionsManager;
 import android.content.pm.ILauncherApps;
+import android.content.pm.IShortcutService;
 import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutManager;
 import android.content.res.Resources;
 import android.hardware.ConsumerIrManager;
 import android.hardware.ISerialManager;
@@ -49,6 +51,7 @@
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlService;
 import android.hardware.input.InputManager;
+import android.hardware.location.ContextHubManager;
 import android.hardware.usb.IUsbManager;
 import android.hardware.usb.UsbManager;
 import android.hardware.radio.RadioManager;
@@ -66,6 +69,7 @@
 import android.media.tv.ITvInputManager;
 import android.media.tv.TvInputManager;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityThread;
 import android.net.EthernetManager;
 import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
@@ -91,14 +95,17 @@
 import android.os.IBinder;
 import android.os.IHardwarePropertiesManager;
 import android.os.IPowerManager;
+import android.os.IRecoverySystem;
 import android.os.IUserManager;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RecoverySystem;
 import android.os.ServiceManager;
 import android.os.SystemVibrator;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
+import android.os.health.SystemHealthManager;
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
@@ -224,7 +231,7 @@
         SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
 
         registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
-                new StaticOuterContextServiceFetcher<ConnectivityManager>() {
+                new StaticApplicationContextServiceFetcher<ConnectivityManager>() {
             @Override
             public ConnectivityManager createService(Context context) {
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
@@ -269,9 +276,9 @@
             }});
 
         registerService(Context.DROPBOX_SERVICE, DropBoxManager.class,
-                new StaticServiceFetcher<DropBoxManager>() {
+                new CachedServiceFetcher<DropBoxManager>() {
             @Override
-            public DropBoxManager createService() {
+            public DropBoxManager createService(ContextImpl ctx) {
                 IBinder b = ServiceManager.getService(Context.DROPBOX_SERVICE);
                 IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
                 if (service == null) {
@@ -281,7 +288,7 @@
                     // DROPBOX_SERVICE is registered.
                     return null;
                 }
-                return new DropBoxManager(service);
+                return new DropBoxManager(ctx, service);
             }});
 
         registerService(Context.INPUT_SERVICE, InputManager.class,
@@ -380,6 +387,18 @@
                         service, ctx.mMainThread.getHandler());
             }});
 
+        registerService(Context.RECOVERY_SERVICE, RecoverySystem.class,
+                new CachedServiceFetcher<RecoverySystem>() {
+            @Override
+            public RecoverySystem createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.RECOVERY_SERVICE);
+                IRecoverySystem service = IRecoverySystem.Stub.asInterface(b);
+                if (service == null) {
+                    Log.wtf(TAG, "Failed to get recovery service.");
+                }
+                return new RecoverySystem(service);
+            }});
+
         registerService(Context.SEARCH_SERVICE, SearchManager.class,
                 new CachedServiceFetcher<SearchManager>() {
             @Override
@@ -482,7 +501,8 @@
             public WifiManager createService(ContextImpl ctx) {
                 IBinder b = ServiceManager.getService(Context.WIFI_SERVICE);
                 IWifiManager service = IWifiManager.Stub.asInterface(b);
-                return new WifiManager(ctx.getOuterContext(), service);
+                return new WifiManager(ctx.getOuterContext(), service,
+                        ConnectivityThread.getInstanceLooper());
             }});
 
         registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class,
@@ -731,9 +751,31 @@
             @Override
             public SoundTriggerManager createService(ContextImpl ctx) {
                 IBinder b = ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE);
-                Log.i(TAG, "Creating new instance of SoundTriggerManager object.");
                 return new SoundTriggerManager(ctx, ISoundTriggerService.Stub.asInterface(b));
             }});
+
+        registerService(Context.SHORTCUT_SERVICE, ShortcutManager.class,
+                new CachedServiceFetcher<ShortcutManager>() {
+            @Override
+            public ShortcutManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.SHORTCUT_SERVICE);
+                return new ShortcutManager(ctx, IShortcutService.Stub.asInterface(b));
+            }});
+
+        registerService(Context.SYSTEM_HEALTH_SERVICE, SystemHealthManager.class,
+                new CachedServiceFetcher<SystemHealthManager>() {
+            @Override
+            public SystemHealthManager createService(ContextImpl ctx) {
+                return new SystemHealthManager();
+            }});
+
+        registerService(Context.CONTEXTHUB_SERVICE, ContextHubManager.class,
+                new CachedServiceFetcher<ContextHubManager>() {
+            @Override
+            public ContextHubManager createService(ContextImpl ctx) {
+                return new ContextHubManager(ctx.getOuterContext(),
+                  ctx.mMainThread.getHandler().getLooper());
+            }});
     }
 
     /**
@@ -826,22 +868,26 @@
     }
 
     /**
-     * Like StaticServiceFetcher, creates only one instance of the service per process, but when
-     * creating the service for the first time, passes it the outer context of the creating
-     * component.
+     * Like StaticServiceFetcher, creates only one instance of the service per application, but when
+     * creating the service for the first time, passes it the application context of the creating
+     * application.
      *
-     * TODO: Is this safe in the case where multiple applications share the same process?
      * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
      * case where multiple application components each have their own ConnectivityManager object.
      */
-    static abstract class StaticOuterContextServiceFetcher<T> implements ServiceFetcher<T> {
+    static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
         private T mCachedInstance;
 
         @Override
         public final T getService(ContextImpl ctx) {
-            synchronized (StaticOuterContextServiceFetcher.this) {
+            synchronized (StaticApplicationContextServiceFetcher.this) {
                 if (mCachedInstance == null) {
-                    mCachedInstance = createService(ctx.getOuterContext());
+                    Context appContext = ctx.getApplicationContext();
+                    // If the application context is null, we're either in the system process or
+                    // it's the application context very early in app initialization. In both these
+                    // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it
+                    // to the service. http://b/27532714 .
+                    mCachedInstance = createService(appContext != null ? appContext : ctx);
                 }
                 return mCachedInstance;
             }
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 276f774..2c1ee8e 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -36,6 +36,7 @@
 import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
+
 import libcore.io.IoUtils;
 
 import java.io.FileOutputStream;
@@ -77,6 +78,7 @@
 
     private int mOwningUid;
 
+    @Override
     public void connect(IAccessibilityServiceClient client, int flags) {
         if (client == null) {
             throw new IllegalArgumentException("Client cannot be null!");
@@ -326,11 +328,12 @@
             int flags) {
         IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
                 ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
-        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+        final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
         info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
         info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
         info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
-                | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
+                | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
+                | AccessibilityServiceInfo.FLAG_FORCE_DIRECT_BOOT_AWARE;
         info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
                 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
                 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 56b4249..69e8df8 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.RemoteException;
@@ -158,7 +159,7 @@
             try {
                 mService.enableCarMode(flags);
             } catch (RemoteException e) {
-                Log.e(TAG, "disableCarMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -181,7 +182,7 @@
             try {
                 mService.disableCarMode(flags);
             } catch (RemoteException e) {
-                Log.e(TAG, "disableCarMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -200,7 +201,7 @@
             try {
                 return mService.getCurrentModeType();
             } catch (RemoteException e) {
-                Log.e(TAG, "getCurrentModeType: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return Configuration.UI_MODE_TYPE_NORMAL;
@@ -233,7 +234,7 @@
             try {
                 mService.setNightMode(mode);
             } catch (RemoteException e) {
-                Log.e(TAG, "setNightMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -257,7 +258,7 @@
             try {
                 return mService.getNightMode();
             } catch (RemoteException e) {
-                Log.e(TAG, "getNightMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return -1;
@@ -266,13 +267,15 @@
     /**
      * @return If UI mode is locked or not. When UI mode is locked, calls to change UI mode
      *         like {@link #enableCarMode(int)} will silently fail.
+     * @hide
      */
+    @TestApi
     public boolean isUiModeLocked() {
         if (mService != null) {
             try {
                 return mService.isUiModeLocked();
             } catch (RemoteException e) {
-                Log.e(TAG, "isUiModeLocked: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
@@ -286,13 +289,15 @@
      * mode will fail silently.
      *
      * @return {@code true} if night mode is locked or {@code false} otherwise
+     * @hide
      */
+    @TestApi
     public boolean isNightModeLocked() {
         if (mService != null) {
             try {
                 return mService.isNightModeLocked();
             } catch (RemoteException e) {
-                Log.e(TAG, "isNightModeLocked: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c3512ec..72b9318 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -49,7 +49,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.WindowManagerGlobal;
@@ -162,8 +161,8 @@
 
     /** @hide */
     @IntDef(flag = true, value = {
-            FLAG_SET_SYSTEM,
-            FLAG_SET_LOCK
+            FLAG_SYSTEM,
+            FLAG_LOCK
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SetWallpaperFlags {}
@@ -171,12 +170,12 @@
     /**
      * Flag: use the supplied imagery as the general system wallpaper.
      */
-    public static final int FLAG_SET_SYSTEM = 1 << 0;
+    public static final int FLAG_SYSTEM = 1 << 0;
 
     /**
      * Flag: use the supplied imagery as the lock-screen wallpaper.
      */
-    public static final int FLAG_SET_LOCK = 1 << 1;
+    public static final int FLAG_LOCK = 1 << 1;
 
     private final Context mContext;
 
@@ -263,7 +262,8 @@
 
     static class Globals extends IWallpaperManagerCallback.Stub {
         private IWallpaperManager mService;
-        private Bitmap mWallpaper;
+        private Bitmap mCachedWallpaper;
+        private int mCachedWallpaperUserId;
         private Bitmap mDefaultWallpaper;
 
         Globals(Looper looper) {
@@ -293,36 +293,37 @@
                             return null;
                         }
                     } catch (RemoteException e) {
-                        // Ignore
+                        throw e.rethrowFromSystemServer();
                     }
                 }
-                if (mWallpaper != null) {
-                    return mWallpaper;
+                if (mCachedWallpaper != null && mCachedWallpaperUserId == userId) {
+                    return mCachedWallpaper;
                 }
-                if (mDefaultWallpaper != null) {
-                    return mDefaultWallpaper;
-                }
-                mWallpaper = null;
+                mCachedWallpaper = null;
+                mCachedWallpaperUserId = 0;
                 try {
-                    mWallpaper = getCurrentWallpaperLocked(userId);
+                    mCachedWallpaper = getCurrentWallpaperLocked(userId);
+                    mCachedWallpaperUserId = userId;
                 } catch (OutOfMemoryError e) {
                     Log.w(TAG, "No memory load current wallpaper", e);
                 }
-                if (returnDefault) {
-                    if (mWallpaper == null) {
-                        mDefaultWallpaper = getDefaultWallpaperLocked(context);
-                        return mDefaultWallpaper;
-                    } else {
-                        mDefaultWallpaper = null;
-                    }
+                if (mCachedWallpaper != null) {
+                    return mCachedWallpaper;
                 }
-                return mWallpaper;
+                if (returnDefault) {
+                    if (mDefaultWallpaper == null) {
+                        mDefaultWallpaper = getDefaultWallpaperLocked(context);
+                    }
+                    return mDefaultWallpaper;
+                }
+                return null;
             }
         }
 
         public void forgetLoadedWallpaper() {
             synchronized (this) {
-                mWallpaper = null;
+                mCachedWallpaper = null;
+                mCachedWallpaperUserId = 0;
                 mDefaultWallpaper = null;
             }
         }
@@ -335,7 +336,7 @@
 
             try {
                 Bundle params = new Bundle();
-                ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SET_SYSTEM,
+                ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SYSTEM,
                         params, userId);
                 if (fd != null) {
                     try {
@@ -349,7 +350,7 @@
                     }
                 }
             } catch (RemoteException e) {
-                // Ignore
+                throw e.rethrowFromSystemServer();
             }
             return null;
         }
@@ -662,11 +663,18 @@
 
     /**
      * Get an open, readable file descriptor to the given wallpaper image file.
-     * The callee is resopnsible for closing the fd when done ingesting the file.
+     * The caller is responsible for closing the file descriptor when done ingesting the file.
      *
      * <p>If no lock-specific wallpaper has been configured for the given user, then
-     * this method will return {@code null} when requesting {@link #FLAG_SET_LOCK} rather than
+     * this method will return {@code null} when requesting {@link #FLAG_LOCK} rather than
      * returning the system wallpaper's image file.
+     *
+     * @param which The wallpaper whose image file is to be retrieved.  Must be a single
+     *     defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
+     *
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      */
     public ParcelFileDescriptor getWallpaperFile(int which) {
         return getWallpaperFile(which, mContext.getUserId());
@@ -676,10 +684,19 @@
      * Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
      * for a given user.  The caller must hold the INTERACT_ACROSS_USERS_FULL
      * permission to access another user's wallpaper data.
+     *
+     * @param which The wallpaper whose image file is to be retrieved.  Must be a single
+     *     defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
+     * @param userId The user or profile whose imagery is to be retrieved
+     *
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
+     *
      * @hide
      */
     public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
-        if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
         }
 
@@ -691,7 +708,7 @@
                 Bundle outParams = new Bundle();
                 return sGlobals.mService.getWallpaper(null, which, outParams, userId);
             } catch (RemoteException e) {
-                return null;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -720,7 +737,39 @@
                 return sGlobals.mService.getWallpaperInfo();
             }
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the ID of the current wallpaper of the given kind.  If there is no
+     * such wallpaper configured, returns a negative number.
+     *
+     * @param which The wallpaper whose ID is to be returned.  Must be a single
+     *     defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
+     * @return The positive numeric ID of the current wallpaper of the given kind,
+     *     or a negative value if no such wallpaper is configured.
+     */
+    public int getWallpaperId(int which) {
+        return getWallpaperIdForUser(which, mContext.getUserId());
+    }
+
+    /**
+     * Get the ID of the given user's current wallpaper of the given kind.  If there
+     * is no such wallpaper configured, returns a negative number.
+     * @hide
+     */
+    public int getWallpaperIdForUser(int which, int userId) {
+        try {
+            if (sGlobals.mService == null) {
+                Log.w(TAG, "WallpaperService not running");
+                return -1;
+            } else {
+                return sGlobals.mService.getWallpaperIdForUser(which, userId);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -767,7 +816,9 @@
         }
 
         // fallback crop activity
-        cropAndSetWallpaperIntent.setPackage("com.android.wallpapercropper");
+        final String cropperPackage = mContext.getString(
+                com.android.internal.R.string.config_wallpaperCropperPackage);
+        cropAndSetWallpaperIntent.setPackage(cropperPackage);
         List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
                 cropAndSetWallpaperIntent, 0);
         if (cropAppList.size() > 0) {
@@ -788,24 +839,24 @@
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#SET_WALLPAPER}.
      *
-     * @param resid The bitmap to save.
+     * @param resid The resource ID of the bitmap to be used as the wallpaper image
      *
      * @throws IOException If an error occurs reverting to the built-in
      * wallpaper.
      */
     public void setResource(@RawRes int resid) throws IOException {
-        setResource(resid, FLAG_SET_SYSTEM);
+        setResource(resid, FLAG_SYSTEM);
     }
 
     /**
-     * Version of {@link #setResource(int)} that takes an optional Bundle for returning
-     * metadata about the operation to the caller.
+     * Version of {@link #setResource(int)} that allows the caller to specify which
+     * of the supported wallpaper categories to set.
      *
-     * @param resid
-     * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+     * @param resid The resource ID of the bitmap to be used as the wallpaper image
+     * @param which Flags indicating which wallpaper(s) to configure with the new imagery
      *
-     * @see #FLAG_SET_LOCK
-     * @see #FLAG_SET_SYSTEM
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      *
      * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
      *
@@ -842,7 +893,7 @@
                 }
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
         return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
@@ -899,11 +950,10 @@
      */
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
-        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM);
     }
 
     /**
-    /**
      * Version of {@link #setBitmap(Bitmap, Rect, boolean)} that allows the caller
      * to specify which of the supported wallpaper categories to set.
      *
@@ -916,8 +966,8 @@
      *     image for restore to a future device; {@code false} otherwise.
      * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
      *
-     * @see #FLAG_SET_LOCK_WALLPAPER
-     * @see #FLAG_SET_SYSTEM_WALLPAPER
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      *
      * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
      *
@@ -948,7 +998,7 @@
                 }
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
         return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
@@ -1019,7 +1069,7 @@
      */
     public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
-        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM);
     }
 
     /**
@@ -1035,8 +1085,8 @@
      *     image for restore to a future device; {@code false} otherwise.
      * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
      *
-     * @see #FLAG_SET_LOCK_WALLPAPER
-     * @see #FLAG_SET_SYSTEM_WALLPAPER
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      *
      * @throws IOException
      */
@@ -1065,7 +1115,7 @@
                 }
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
 
         return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
@@ -1086,7 +1136,7 @@
             String name = "res:" + resources.getResourceName(resid);
             return sGlobals.mService.hasNamedWallpaper(name);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1112,8 +1162,7 @@
         try {
             return sGlobals.mService.getWidthHint();
         } catch (RemoteException e) {
-            // Shouldn't happen!
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1139,8 +1188,7 @@
         try {
             return sGlobals.mService.getHeightHint();
         } catch (RemoteException e) {
-            // Shouldn't happen!
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1201,7 +1249,7 @@
                         mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1222,7 +1270,7 @@
                 sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1243,7 +1291,7 @@
                     windowToken, x, y);
             //Log.v(TAG, "...app returning after sending display offset!");
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1254,7 +1302,7 @@
      */
     @SystemApi
     public void clearWallpaper() {
-        clearWallpaper(FLAG_SET_SYSTEM, mContext.getUserId());
+        clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
     }
 
     /**
@@ -1272,7 +1320,7 @@
         try {
             sGlobals.mService.clearWallpaper(mContext.getOpPackageName(), which, userId);
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1294,9 +1342,8 @@
             sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
             return true;
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -1319,7 +1366,7 @@
                     windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1357,7 +1404,7 @@
                     windowToken, action, x, y, z, extras, false);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1373,7 +1420,7 @@
             try {
                 return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName());
             } catch (RemoteException e) {
-                // Ignore
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1393,7 +1440,7 @@
             try {
                 return sGlobals.mService.isWallpaperSettingAllowed(mContext.getOpPackageName());
             } catch (RemoteException e) {
-                // Ignore
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1414,7 +1461,7 @@
             WindowManagerGlobal.getWindowSession().setWallpaperPosition(
                     windowToken, -1, -1, -1, -1);
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1434,6 +1481,25 @@
     }
 
     /**
+     * Remove one or more currently set wallpapers, reverting to the system default
+     * display for each one.  If {@link #FLAG_SYSTEM} is set in the {@code which}
+     * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
+     * upon success.
+     *
+     * @param which A bitwise combination of {@link #FLAG_SYSTEM} or
+     *   {@link #FLAG_LOCK}
+     * @throws IOException If an error occurs reverting to the built-in wallpaper.
+     */
+    public void clear(int which) throws IOException {
+        if ((which & FLAG_SYSTEM) != 0) {
+            clear();
+        }
+        if ((which & FLAG_LOCK) != 0) {
+            clearWallpaper(FLAG_LOCK, mContext.getUserId());
+        }
+    }
+
+    /**
      * Open stream representing the default static image wallpaper.
      *
      * @hide
@@ -1495,9 +1561,8 @@
         try {
             return sGlobals.mService.setLockWallpaperCallback(callback);
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to contact wallpaper service");
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     // Private completion callback for setWallpaper() synchronization
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 4e9adf0..1de1d2f 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -240,7 +240,7 @@
     /**
      * The BroadcastReceiver that implements this device admin component.
      */
-    final ResolveInfo mReceiver;
+    final ActivityInfo mActivityInfo;
 
     /**
      * Whether this should be visible to the user.
@@ -252,29 +252,42 @@
      */
     int mUsesPolicies;
 
+
     /**
      * Constructor.
      *
      * @param context The Context in which we are parsing the device admin.
-     * @param receiver The ResolveInfo returned from the package manager about
+     * @param resolveInfo The ResolveInfo returned from the package manager about
      * this device admin's component.
      */
-    public DeviceAdminInfo(Context context, ResolveInfo receiver)
+    public DeviceAdminInfo(Context context, ResolveInfo resolveInfo)
             throws XmlPullParserException, IOException {
-        mReceiver = receiver;
-        ActivityInfo ai = receiver.activityInfo;
+        this(context, resolveInfo.activityInfo);
+    }
+    /**
+     * Constructor.
+     *
+     * @param context The Context in which we are parsing the device admin.
+     * @param activityInfo The ActivityInfo returned from the package manager about
+     * this device admin's component.
+     *
+     * @hide
+     */
+    public DeviceAdminInfo(Context context, ActivityInfo activityInfo)
+            throws XmlPullParserException, IOException {
+        mActivityInfo = activityInfo;
 
         PackageManager pm = context.getPackageManager();
 
         XmlResourceParser parser = null;
         try {
-            parser = ai.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
+            parser = mActivityInfo.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
             if (parser == null) {
                 throw new XmlPullParserException("No "
                         + DeviceAdminReceiver.DEVICE_ADMIN_META_DATA + " meta-data");
             }
 
-            Resources res = pm.getResourcesForApplication(ai.applicationInfo);
+            Resources res = pm.getResourcesForApplication(mActivityInfo.applicationInfo);
 
             AttributeSet attrs = Xml.asAttributeSet(parser);
 
@@ -324,14 +337,14 @@
             }
         } catch (NameNotFoundException e) {
             throw new XmlPullParserException(
-                    "Unable to create context for: " + ai.packageName);
+                    "Unable to create context for: " + mActivityInfo.packageName);
         } finally {
             if (parser != null) parser.close();
         }
     }
 
     DeviceAdminInfo(Parcel source) {
-        mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
+        mActivityInfo = ActivityInfo.CREATOR.createFromParcel(source);
         mUsesPolicies = source.readInt();
     }
 
@@ -339,7 +352,7 @@
      * Return the .apk package that implements this device admin.
      */
     public String getPackageName() {
-        return mReceiver.activityInfo.packageName;
+        return mActivityInfo.packageName;
     }
 
     /**
@@ -347,7 +360,7 @@
      * this device admin.
      */
     public String getReceiverName() {
-        return mReceiver.activityInfo.name;
+        return mActivityInfo.name;
     }
 
     /**
@@ -355,7 +368,7 @@
      * device admin.  Do not modify the returned object.
      */
     public ActivityInfo getActivityInfo() {
-        return mReceiver.activityInfo;
+        return mActivityInfo;
     }
 
     /**
@@ -363,8 +376,8 @@
      */
     @NonNull
     public ComponentName getComponent() {
-        return new ComponentName(mReceiver.activityInfo.packageName,
-                mReceiver.activityInfo.name);
+        return new ComponentName(mActivityInfo.packageName,
+                mActivityInfo.name);
     }
 
     /**
@@ -374,7 +387,7 @@
      * resources.
      */
     public CharSequence loadLabel(PackageManager pm) {
-        return mReceiver.loadLabel(pm);
+        return mActivityInfo.loadLabel(pm);
     }
 
     /**
@@ -384,15 +397,9 @@
      * resources.
      */
     public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
-        if (mReceiver.activityInfo.descriptionRes != 0) {
-            String packageName = mReceiver.resolvePackageName;
-            ApplicationInfo applicationInfo = null;
-            if (packageName == null) {
-                packageName = mReceiver.activityInfo.packageName;
-                applicationInfo = mReceiver.activityInfo.applicationInfo;
-            }
-            return pm.getText(packageName,
-                    mReceiver.activityInfo.descriptionRes, applicationInfo);
+        if (mActivityInfo.descriptionRes != 0) {
+            return pm.getText(mActivityInfo.packageName,
+                    mActivityInfo.descriptionRes, mActivityInfo.applicationInfo);
         }
         throw new NotFoundException();
     }
@@ -404,7 +411,7 @@
      * resources.
      */
     public Drawable loadIcon(PackageManager pm) {
-        return mReceiver.loadIcon(pm);
+        return mActivityInfo.loadIcon(pm);
     }
 
     /**
@@ -464,12 +471,12 @@
 
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "Receiver:");
-        mReceiver.dump(pw, prefix + "  ");
+        mActivityInfo.dump(pw, prefix + "  ");
     }
 
     @Override
     public String toString() {
-        return "DeviceAdminInfo{" + mReceiver.activityInfo.name + "}";
+        return "DeviceAdminInfo{" + mActivityInfo.name + "}";
     }
 
     /**
@@ -479,7 +486,7 @@
      * @param flags The flags used for parceling.
      */
     public void writeToParcel(Parcel dest, int flags) {
-        mReceiver.writeToParcel(dest, flags);
+        mActivityInfo.writeToParcel(dest, flags);
         dest.writeInt(mUsesPolicies);
     }
 
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index d5ca0e9..dd70b5d 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -268,7 +268,7 @@
             "android.app.action.BUGREPORT_SHARE";
 
     /**
-     * Broadcast action: notify that a new batch of device logs is ready to be collected.
+     * Broadcast action: notify that a new batch of security logs is ready to be collected.
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -284,10 +284,11 @@
     public static final String EXTRA_BUGREPORT_HASH = "android.app.extra.BUGREPORT_HASH";
 
     /**
-     * An {@code int} failure code representing the reason of the bugreport failure.
+     * An {@code int} failure code representing the reason of the bugreport failure. One of
+     * {@link #BUGREPORT_FAILURE_FAILED_COMPLETING}
+     * or {@link #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE}
      *
      * @see #ACTION_BUGREPORT_FAILED
-     * @see #BUGREPORT_FAILURE_FAILED_COMPLETING, #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
      * @hide
      */
     public static final String EXTRA_BUGREPORT_FAILURE_REASON =
@@ -305,9 +306,24 @@
         BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
     })
     public @interface BugreportFailureCode {}
-    /** Bugreport completion process failed. */
+
+    /**
+     * Bugreport completion process failed.
+     *
+     * <p>If this error code is received, the requesting of bugreport can be retried.
+     * @see DevicePolicyManager#requestBugreport
+     */
     public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0;
-    /** Bugreport is no longer available for collection. */
+
+    /**
+     * Bugreport has been created, but is no longer available for collection.
+     *
+     * <p>This error likely occurs because the user of the device hasn't consented to share
+     * the bugreport for a long period after its creation.
+     *
+     * <p>If this error code is received, the requesting of bugreport can be retried.
+     * @see DevicePolicyManager#requestBugreport
+     */
     public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1;
 
     /** @hide */
@@ -383,8 +399,8 @@
      *
      * <p> If the admin is activated by a device owner, then the intent
      * may contain private extras that are relevant to user setup.
-     * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
-     *      ComponentName, Intent)}
+     * {@see DevicePolicyManager#createAndManageUser(ComponentName, String, ComponentName,
+     *      PersistableBundle, int)}
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
@@ -598,7 +614,8 @@
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
      * @param failureCode int containing failure code. One of
-     * #BUGREPORT_FAILURE_FAILED_COMPLETING or #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
+     * {@link #BUGREPORT_FAILURE_FAILED_COMPLETING}
+     * or {@link #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE}
      * @see DevicePolicyManager#requestBugreport
      */
     public void onBugreportFailed(Context context, Intent intent,
@@ -606,13 +623,13 @@
     }
 
     /**
-     * Called when a new batch of device logs can be retrieved.
+     * Called when a new batch of security logs can be retrieved.
      *
      * <p>This callback is only applicable to device owners.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
-     * @see DevicePolicyManager#retrieveDeviceLogs(ComponentName)
+     * @see DevicePolicyManager#retrieveSecurityLogs(ComponentName)
      */
     public void onSecurityLogsAvailable(Context context, Intent intent) {
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ae63a2f..f15b8fe 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -25,16 +25,14 @@
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
 import android.app.Activity;
-import android.auditing.SecurityLog;
-import android.auditing.SecurityLog.SecurityEvent;
+import android.app.admin.SecurityLog.SecurityEvent;
 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;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
-import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.net.ProxyInfo;
@@ -51,13 +49,12 @@
 import android.provider.Settings;
 import android.security.Credentials;
 import android.service.restrictions.RestrictionsReceiver;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.org.conscrypt.TrustedCertificateStore;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -74,24 +71,25 @@
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
 /**
  * Public interface for managing policies enforced on a device. Most clients of this class must be
- * registered with the system as a
- * <a href="{@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
- * a device administrator may be registered as either a profile or device owner. A given method is
- * accessible to all device administrators unless the documentation for that method specifies that
- * it is restricted to either device or profile owners.
- *
+ * registered with the system as a <a href="{@docRoot}guide/topics/admin/device-admin.html">device
+ * administrator</a>. Additionally, a device administrator may be registered as either a profile or
+ * device owner. A given method is accessible to all device administrators unless the documentation
+ * for that method specifies that it is restricted to either device or profile owners. Any
+ * application calling an api may only pass as an argument a device administrator component it
+ * owns. Otherwise, a {@link SecurityException} will be thrown.
  * <div class="special reference">
  * <h3>Developer Guides</h3>
- * <p>For more information about managing policies for device administration, read the
- * <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
- * developer guide.
- * </div>
+ * <p>
+ * For more information about managing policies for device administration, read the <a href=
+ * "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a> developer
+ * guide. </div>
  */
 public class DevicePolicyManager {
     private static String TAG = "DevicePolicyManager";
@@ -100,9 +98,6 @@
     private final IDevicePolicyManager mService;
     private final boolean mParentInstance;
 
-    private static final String REMOTE_EXCEPTION_MESSAGE =
-            "Failed to talk with device policy manager service";
-
     private DevicePolicyManager(Context context, boolean parentInstance) {
         this(context,
                 IDevicePolicyManager.Stub.asInterface(
@@ -151,19 +146,23 @@
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported.
      *
-     * <p> The intent may also contain the following extras:
+     * <p>The intent may also contain the following extras:
      * <ul>
-     * <li> {@link #EXTRA_PROVISIONING_LOGO_URI}, optional </li>
-     * <li> {@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional </li>
+     * <li>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}, optional </li>
+     * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional, supported from
+     * {@link android.os.Build.VERSION_CODES#N}</li>
+     * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
      * </ul>
      *
-     * <p> When managed provisioning has completed, broadcasts are sent to the application specified
+     * <p>When managed provisioning has completed, broadcasts are sent to the application specified
      * in the provisioning intent. The
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} broadcast is sent in the
      * managed profile and the {@link #ACTION_MANAGED_PROFILE_PROVISIONED} broadcast is sent in
      * the primary profile.
      *
-     * <p> If provisioning fails, the managedProfile is removed so the device returns to its
+     * <p>If provisioning fails, the managedProfile is removed so the device returns to its
      * previous state.
      *
      * <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a
@@ -177,7 +176,6 @@
         = "android.app.action.PROVISION_MANAGED_PROFILE";
 
     /**
-     * @hide
      * Activity action: Starts the provisioning flow which sets up a managed user.
      *
      * <p>This intent will typically be sent by a mobile device management application (MDM).
@@ -186,16 +184,24 @@
      * been completed. Use {@link #isProvisioningAllowed(String)} to check if provisioning is
      * allowed.
      *
-     * <p>This intent should contain the extra
-     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}.
+     * <p>The intent contains the following extras:
+     * <ul>
+     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li>
+     * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
+     * </ul>
      *
-     * <p> If provisioning fails, the device returns to its previous state.
+     * <p>If provisioning fails, the device returns to its previous state.
      *
      * <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a
      * result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part of
      * the provisioning flow was successful, although this doesn't guarantee the full flow will
      * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies
      * that the user backed-out of provisioning, or some precondition for provisioning wasn't met.
+     *
+     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_USER
@@ -226,11 +232,11 @@
      * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
      * </ul>
      *
-     * <p> When device owner provisioning has completed, an intent of the type
+     * <p>When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcast to the
      * device owner.
      *
-     * <p> If provisioning fails, the device is factory reset.
+     * <p>If provisioning fails, the device is factory reset.
      *
      * <p>A result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part
      * of the provisioning flow was successful, although this doesn't guarantee the full flow will
@@ -294,14 +300,14 @@
      * The primary benefit is that multiple non-system users are supported when provisioning using
      * this form of device management.
      *
-     * <p> During device owner provisioning a device admin app is set as the owner of the device.
+     * <p>During device owner provisioning a device admin app is set as the owner of the device.
      * A device owner has full control over the device. The device owner can not be modified by the
      * user.
      *
-     * <p> A typical use case would be a device that is owned by a company, but used by either an
+     * <p>A typical use case would be a device that is owned by a company, but used by either an
      * employee or client.
      *
-     * <p> An intent with this action can be sent only on an unprovisioned device.
+     * <p>An intent with this action can be sent only on an unprovisioned device.
      * It is possible to check if provisioning is allowed or not by querying the method
      * {@link #isProvisioningAllowed(String)}.
      *
@@ -311,13 +317,15 @@
      * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
      * </ul>
      *
-     * <p> When device owner provisioning has completed, an intent of the type
+     * <p>When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcast to the
      * device owner.
      *
-     * <p> If provisioning fails, the device is factory reset.
+     * <p>If provisioning fails, the device is factory reset.
      *
      * <p>A result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part
      * of the provisioning flow was successful, although this doesn't guarantee the full flow will
@@ -341,11 +349,74 @@
      *
      * @hide
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_FINALIZATION
             = "android.app.action.PROVISION_FINALIZATION";
 
     /**
+     * Action: Bugreport sharing with device owner has been accepted by the user.
+     *
+     * @hide
+     */
+    public static final String ACTION_BUGREPORT_SHARING_ACCEPTED =
+            "com.android.server.action.BUGREPORT_SHARING_ACCEPTED";
+
+    /**
+     * Action: Bugreport sharing with device owner has been declined by the user.
+     *
+     * @hide
+     */
+    public static final String ACTION_BUGREPORT_SHARING_DECLINED =
+            "com.android.server.action.BUGREPORT_SHARING_DECLINED";
+
+    /**
+     * Action: Bugreport has been collected and is dispatched to {@link DevicePolicyManagerService}.
+     *
+     * @hide
+     */
+    public static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
+            "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
+
+    /**
+     * Extra for shared bugreport's SHA-256 hash.
+     *
+     * @hide
+     */
+    public static final String EXTRA_REMOTE_BUGREPORT_HASH =
+            "android.intent.extra.REMOTE_BUGREPORT_HASH";
+
+    /**
+     * Extra for remote bugreport notification shown type.
+     *
+     * @hide
+     */
+    public static final String EXTRA_BUGREPORT_NOTIFICATION_TYPE =
+            "android.app.extra.bugreport_notification_type";
+
+    /**
+     * Notification type for a started remote bugreport flow.
+     *
+     * @hide
+     */
+    public static final int NOTIFICATION_BUGREPORT_STARTED = 1;
+
+    /**
+     * Notification type for a bugreport that has already been accepted to be shared, but is still
+     * being taken.
+     *
+     * @hide
+     */
+    public static final int NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED = 2;
+
+    /**
+     * Notification type for a bugreport that has been taken and can be shared or declined.
+     *
+     * @hide
+     */
+    public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
+
+    /**
      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
      * allows a mobile device management application or NFC programmer application which starts
      * managed provisioning to pass data to the management application instance after provisioning.
@@ -382,7 +453,7 @@
      *
      * <p> When this extra is set, the application must have exactly one device admin receiver.
      * This receiver will be set as the profile or device owner and active admin.
-
+     *
      * @see DeviceAdminReceiver
      * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
      * supported, but only if there is only one device admin receiver in the package that requires
@@ -404,7 +475,7 @@
      * <p>This component is set as device owner and active admin when device owner provisioning is
      * started by an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE} or by an NFC
      * message containing an NFC record with MIME type
-     * {@link #MIME_TYPE_PROVISIONING_NFC}. For the NFC record, the component name should be
+     * {@link #MIME_TYPE_PROVISIONING_NFC}. For the NFC record, the component name must be
      * flattened to a string, via {@link ComponentName#flattenToShortString()}.
      *
      * @see DeviceAdminReceiver
@@ -607,8 +678,8 @@
      * the file at download location specified in
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
      *
-     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} should be
-     * present. The provided checksum should match the checksum of the file at the download
+     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} must be
+     * present. The provided checksum must match the checksum of the file at the download
      * location. If the checksum doesn't match an error will be shown to the user and the user will
      * be asked to factory reset the device.
      *
@@ -632,8 +703,8 @@
      * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
      * {@link android.content.pm.PackageManager#GET_SIGNATURES}.
      *
-     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} should be
-     * present. The provided checksum should match the checksum of any signature of the file at
+     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} must be
+     * present. The provided checksum must match the checksum of any signature of the file at
      * the download location. If the checksum does not match an error will be shown to the user and
      * the user will be asked to factory reset the device.
      *
@@ -658,11 +729,14 @@
         = "android.app.action.MANAGED_PROFILE_PROVISIONED";
 
     /**
-     * A boolean extra indicating whether device encryption can be skipped as part of Device Owner
-     * provisioning.
+     * A boolean extra indicating whether device encryption can be skipped as part of device owner
+     * or managed profile provisioning.
      *
      * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action
      * {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning.
+     *
+     * <p>From {@link android.os.Build.VERSION_CODES#N} onwards, this is also supported for an
+     * intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}.
      */
     public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
              "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
@@ -705,7 +779,7 @@
             "android.app.extra.PROVISIONING_SKIP_USER_SETUP";
 
     /**
-     * This MIME type is used for starting the Device Owner provisioning.
+     * This MIME type is used for starting the device owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
      * A device owner has full control over the device. The device owner can not be modified by the
@@ -715,7 +789,7 @@
      * <p> A typical use case would be a device that is owned by a company, but used by either an
      * employee or client.
      *
-     * <p> The NFC message should be send to an unprovisioned device.
+     * <p> The NFC message must be sent to an unprovisioned device.
      *
      * <p>The NFC record must contain a serialized {@link java.util.Properties} object which
      * contains the following properties:
@@ -932,30 +1006,35 @@
      * No management for current user in-effect. This is the default.
      * @hide
      */
+    @SystemApi
     public static final int STATE_USER_UNMANAGED = 0;
 
     /**
      * Management partially setup, user setup needs to be completed.
      * @hide
      */
+    @SystemApi
     public static final int STATE_USER_SETUP_INCOMPLETE = 1;
 
     /**
      * Management partially setup, user setup completed.
      * @hide
      */
+    @SystemApi
     public static final int STATE_USER_SETUP_COMPLETE = 2;
 
     /**
      * Management setup and active on current user.
      * @hide
      */
+    @SystemApi
     public static final int STATE_USER_SETUP_FINALIZED = 3;
 
     /**
      * Management partially setup on a managed profile.
      * @hide
      */
+    @SystemApi
     public static final int STATE_USER_PROFILE_COMPLETE = 4;
 
     /**
@@ -967,8 +1046,11 @@
     public @interface UserProvisioningState {}
 
     /**
-     * Return true if the given administrator component is currently
-     * active (enabled) in the system.
+     * Return true if the given administrator component is currently active (enabled) in the system.
+     *
+     * @param admin The administrator component to check for.
+     * @return {@code true} if {@code admin} is currently enabled in the system, {@code false}
+     *         otherwise
      */
     public boolean isAdminActive(@NonNull ComponentName admin) {
         return isAdminActiveAsUser(admin, myUserId());
@@ -983,7 +1065,7 @@
             try {
                 return mService.isAdminActive(admin, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -998,7 +1080,7 @@
             try {
                 return mService.isRemovingAdmin(admin, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1023,7 +1105,7 @@
             try {
                 return mService.getActiveAdmins(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -1048,7 +1130,7 @@
             try {
                 return mService.packageHasActiveAdmins(packageName, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1059,32 +1141,39 @@
      * by the application that owns the administration component; if you
      * try to remove someone else's component, a security exception will be
      * thrown.
+     *
+     * <p>Note that the operation is not synchronous and the admin might still be active (as
+     * indicated by {@link #getActiveAdmins()}) by the time this method returns.
+     *
+     * @param admin The administration compononent to remove.
+     * @throws SecurityException if the caller is not in the owner application of {@code admin}.
      */
     public void removeActiveAdmin(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 mService.removeActiveAdmin(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Returns true if an administrator has been granted a particular device policy.  This can
-     * be used to check whether the administrator was activated under an earlier set of policies,
-     * but requires additional policies after an upgrade.
+     * Returns true if an administrator has been granted a particular device policy. This can be
+     * used to check whether the administrator was activated under an earlier set of policies, but
+     * requires additional policies after an upgrade.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.  Must be
-     * an active administrator, or an exception will be thrown.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Must be an
+     *            active administrator, or an exception will be thrown.
      * @param usesPolicy Which uses-policy to check, as defined in {@link DeviceAdminInfo}.
+     * @throws SecurityException if {@code admin} is not an active administrator.
      */
     public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) {
         if (mService != null) {
             try {
                 return mService.hasGrantedPolicy(admin, usesPolicy, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1100,7 +1189,7 @@
             try {
                 return mService.isSeparateProfileChallengeAllowed(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1184,41 +1273,39 @@
     public static final int PASSWORD_QUALITY_MANAGED = 0x80000;
 
     /**
-     * Called by an application that is administering the device to set the
-     * password restrictions it is imposing.  After setting this, the user
-     * will not be able to enter a new password that is not at least as
-     * restrictive as what has been set.  Note that the current password
-     * will remain until the user has set a new one, so the change does not
-     * take place immediately.  To prompt the user for a new password, use
-     * {@link #ACTION_SET_NEW_PASSWORD} or
+     * Called by an application that is administering the device to set the password restrictions it
+     * is imposing. After setting this, the user will not be able to enter a new password that is
+     * not at least as restrictive as what has been set. Note that the current password will remain
+     * until the user has set a new one, so the change does not take place immediately. To prompt
+     * the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
      * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after calling this method.
-     *
-     * <p>Quality constants are ordered so that higher values are more restrictive;
-     * thus the highest requested quality constant (between the policy set here,
-     * the user's preference, and any other considerations) is the one that
-     * is in effect.
-     *
-     * <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.
-     *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
+     * <p>
+     * Quality constants are ordered so that higher values are more restrictive; thus the highest
+     * requested quality constant (between the policy set here, the user's preference, and any other
+     * considerations) is the one that is in effect.
+     * <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.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param quality The new desired quality.  One of
-     * {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING},
-     * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX},
-     * {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC}
-     * or {@link #PASSWORD_QUALITY_COMPLEX}.
+     * @param quality The new desired quality. One of {@link #PASSWORD_QUALITY_UNSPECIFIED},
+     *            {@link #PASSWORD_QUALITY_SOMETHING}, {@link #PASSWORD_QUALITY_NUMERIC},
+     *            {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX}, {@link #PASSWORD_QUALITY_ALPHABETIC},
+     *            {@link #PASSWORD_QUALITY_ALPHANUMERIC} or {@link #PASSWORD_QUALITY_COMPLEX}.
+     * @throws SecurityException if {@code admin} is not an active administrator or if {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordQuality(@NonNull ComponentName admin, int quality) {
         if (mService != null) {
             try {
                 mService.setPasswordQuality(admin, quality, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1245,44 +1332,44 @@
             try {
                 return mService.getPasswordQuality(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return PASSWORD_QUALITY_UNSPECIFIED;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * minimum allowed password length.  After setting this, the user
-     * will not be able to enter a new password that is not at least as
-     * restrictive as what has been set.  Note that the current password
-     * will remain until the user has set a new one, so the change does not
-     * take place immediately.  To prompt the user for a new password, use
-     * {@link #ACTION_SET_NEW_PASSWORD}  or
-     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value.  This
-     * constraint is only imposed if the administrator has also requested either
-     * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX},
-     * {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC},
-     * or {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}.
-     *
-     * <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.
-     *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
+     * Called by an application that is administering the device to set the minimum allowed password
+     * length. After setting this, the user will not be able to enter a new password that is not at
+     * least as restrictive as what has been set. Note that the current password will remain until
+     * the user has set a new one, so the change does not take place immediately. To prompt the user
+     * for a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
+     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This constraint is
+     * only imposed if the administrator has also requested either {@link #PASSWORD_QUALITY_NUMERIC}
+     * , {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX}, {@link #PASSWORD_QUALITY_ALPHABETIC},
+     * {@link #PASSWORD_QUALITY_ALPHANUMERIC}, or {@link #PASSWORD_QUALITY_COMPLEX} with
+     * {@link #setPasswordQuality}.
+     * <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.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param length The new desired minimum password length.  A value of 0
-     * means there is no restriction.
+     * @param length The new desired minimum password length. A value of 0 means there is no
+     *            restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordMinimumLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1310,45 +1397,42 @@
             try {
                 return mService.getPasswordMinimumLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * minimum number of upper case letters required in the password. After
-     * setting this, the user will not be able to enter a new password that is
-     * not at least as restrictive as what has been set. Note that the current
-     * password will remain until the user has set a new one, so the change does
-     * not take place immediately. To prompt the user for a new password, use
-     * {@link #ACTION_SET_NEW_PASSWORD}  or
-     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
-     * constraint is only imposed if the administrator has also requested
-     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
-     * default value is 0.
+     * Called by an application that is administering the device to set the minimum number of upper
+     * case letters required in the password. After setting this, the user will not be able to enter
+     * a new password that is not at least as restrictive as what has been set. Note that the
+     * current password will remain until the user has set a new one, so the change does not take
+     * place immediately. To prompt the user for a new password, use
+     * {@link #ACTION_SET_NEW_PASSWORD} or {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after
+     * setting this value. This constraint is only imposed if the administrator has also requested
+     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 0.
      * <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.
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param length The new desired minimum number of upper case letters
-     *            required in the password. A value of 0 means there is no
-     *            restriction.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired minimum number of upper case letters required in the password.
+     *            A value of 0 means there is no restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordMinimumUpperCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumUpperCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1382,45 +1466,42 @@
             try {
                 return mService.getPasswordMinimumUpperCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * minimum number of lower case letters required in the password. After
-     * setting this, the user will not be able to enter a new password that is
-     * not at least as restrictive as what has been set. Note that the current
-     * password will remain until the user has set a new one, so the change does
-     * not take place immediately. To prompt the user for a new password, use
-     * {@link #ACTION_SET_NEW_PASSWORD} or
-     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
-     * constraint is only imposed if the administrator has also requested
-     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
-     * default value is 0.
+     * Called by an application that is administering the device to set the minimum number of lower
+     * case letters required in the password. After setting this, the user will not be able to enter
+     * a new password that is not at least as restrictive as what has been set. Note that the
+     * current password will remain until the user has set a new one, so the change does not take
+     * place immediately. To prompt the user for a new password, use
+     * {@link #ACTION_SET_NEW_PASSWORD} or {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after
+     * setting this value. This constraint is only imposed if the administrator has also requested
+     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 0.
      * <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.
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param length The new desired minimum number of lower case letters
-     *            required in the password. A value of 0 means there is no
-     *            restriction.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired minimum number of lower case letters required in the password.
+     *            A value of 0 means there is no restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordMinimumLowerCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumLowerCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1454,44 +1535,42 @@
             try {
                 return mService.getPasswordMinimumLowerCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * minimum number of letters required in the password. After setting this,
-     * the user will not be able to enter a new password that is not at least as
-     * restrictive as what has been set. Note that the current password will
-     * remain until the user has set a new one, so the change does not take
-     * place immediately. To prompt the user for a new password, use
-     * {@link #ACTION_SET_NEW_PASSWORD} or
-     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
-     * constraint is only imposed if the administrator has also requested
-     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
-     * default value is 1.
+     * Called by an application that is administering the device to set the minimum number of
+     * letters required in the password. After setting this, the user will not be able to enter a
+     * new password that is not at least as restrictive as what has been set. Note that the current
+     * password will remain until the user has set a new one, so the change does not take place
+     * immediately. To prompt the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
+     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This constraint is
+     * only imposed if the administrator has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
+     * {@link #setPasswordQuality}. The default value is 1.
      * <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.
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param length The new desired minimum number of letters required in the
-     *            password. A value of 0 means there is no restriction.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired minimum number of letters required in the password. A value of
+     *            0 means there is no restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordMinimumLetters(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumLetters(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1524,44 +1603,42 @@
             try {
                 return mService.getPasswordMinimumLetters(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * minimum number of numerical digits required in the password. After
-     * setting this, the user will not be able to enter a new password that is
-     * not at least as restrictive as what has been set. Note that the current
-     * password will remain until the user has set a new one, so the change does
-     * not take place immediately. To prompt the user for a new password, use
-     * {@link #ACTION_SET_NEW_PASSWORD} or
-     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
-     * constraint is only imposed if the administrator has also requested
-     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
-     * default value is 1.
+     * Called by an application that is administering the device to set the minimum number of
+     * numerical digits required in the password. After setting this, the user will not be able to
+     * enter a new password that is not at least as restrictive as what has been set. Note that the
+     * current password will remain until the user has set a new one, so the change does not take
+     * place immediately. To prompt the user for a new password, use
+     * {@link #ACTION_SET_NEW_PASSWORD} or {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after
+     * setting this value. This constraint is only imposed if the administrator has also requested
+     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 1.
      * <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.
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param length The new desired minimum number of numerical digits required
-     *            in the password. A value of 0 means there is no restriction.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired minimum number of numerical digits required in the password. A
+     *            value of 0 means there is no restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordMinimumNumeric(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumNumeric(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1594,44 +1671,42 @@
             try {
                 return mService.getPasswordMinimumNumeric(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * minimum number of symbols required in the password. After setting this,
-     * the user will not be able to enter a new password that is not at least as
-     * restrictive as what has been set. Note that the current password will
-     * remain until the user has set a new one, so the change does not take
-     * place immediately. To prompt the user for a new password, use
-     * {@link #ACTION_SET_NEW_PASSWORD} or
-     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
-     * constraint is only imposed if the administrator has also requested
-     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
-     * default value is 1.
+     * Called by an application that is administering the device to set the minimum number of
+     * symbols required in the password. After setting this, the user will not be able to enter a
+     * new password that is not at least as restrictive as what has been set. Note that the current
+     * password will remain until the user has set a new one, so the change does not take place
+     * immediately. To prompt the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
+     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This constraint is
+     * only imposed if the administrator has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
+     * {@link #setPasswordQuality}. The default value is 1.
      * <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.
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param length The new desired minimum number of symbols required in the
-     *            password. A value of 0 means there is no restriction.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired minimum number of symbols required in the password. A value of
+     *            0 means there is no restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordMinimumSymbols(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumSymbols(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1663,44 +1738,42 @@
             try {
                 return mService.getPasswordMinimumSymbols(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * minimum number of non-letter characters (numerical digits or symbols)
-     * required in the password. After setting this, the user will not be able
-     * to enter a new password that is not at least as restrictive as what has
-     * been set. Note that the current password will remain until the user has
-     * set a new one, so the change does not take place immediately. To prompt
-     * the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
-     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after
-     * setting this value. This constraint is only imposed if the administrator
-     * has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
-     * {@link #setPasswordQuality}. The default value is 0.
+     * Called by an application that is administering the device to set the minimum number of
+     * non-letter characters (numerical digits or symbols) required in the password. After setting
+     * this, the user will not be able to enter a new password that is not at least as restrictive
+     * as what has been set. Note that the current password will remain until the user has set a new
+     * one, so the change does not take place immediately. To prompt the user for a new password,
+     * use {@link #ACTION_SET_NEW_PASSWORD} or {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after
+     * setting this value. This constraint is only imposed if the administrator has also requested
+     * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 0.
      * <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.
+     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param length The new desired minimum number of letters required in the
-     *            password. A value of 0 means there is no restriction.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired minimum number of letters required in the password. A value of
+     *            0 means there is no restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public void setPasswordMinimumNonLetter(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumNonLetter(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1733,81 +1806,81 @@
             try {
                 return mService.getPasswordMinimumNonLetter(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
-  /**
-   * Called by an application that is administering the device to set the length
-   * of the password history. After setting this, the user will not be able to
-   * enter a new password that is the same as any password in the history. Note
-   * that the current password will remain until the user has set a new one, so
-   * the change does not take place immediately. To prompt the user for a new
-   * password, use {@link #ACTION_SET_NEW_PASSWORD} or
-   * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value.
-   * This constraint is only imposed if the administrator has also requested
-   * either {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX}
-   * {@link #PASSWORD_QUALITY_ALPHABETIC}, or {@link #PASSWORD_QUALITY_ALPHANUMERIC}
-   * with {@link #setPasswordQuality}.
-   *
-   * <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.
-   *
-   * <p>This method can be called on the {@link DevicePolicyManager} instance
-   * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-   * restrictions on the parent profile.
-   *
-   * @param admin Which {@link DeviceAdminReceiver} this request is associated
-   *        with.
-   * @param length The new desired length of password history. A value of 0
-   *        means there is no restriction.
-   */
+    /**
+     * Called by an application that is administering the device to set the length of the password
+     * history. After setting this, the user will not be able to enter a new password that is the
+     * same as any password in the history. Note that the current password will remain until the
+     * user has set a new one, so the change does not take place immediately. To prompt the user for
+     * a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
+     * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This constraint is
+     * only imposed if the administrator has also requested either {@link #PASSWORD_QUALITY_NUMERIC}
+     * , {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX} {@link #PASSWORD_QUALITY_ALPHABETIC}, or
+     * {@link #PASSWORD_QUALITY_ALPHANUMERIC} with {@link #setPasswordQuality}.
+     * <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.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param length The new desired length of password history. A value of 0 means there is no
+     *            restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
+     */
     public void setPasswordHistoryLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordHistoryLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Called by a device admin to set the password expiration timeout. Calling this method
-     * will restart the countdown for password expiration for the given admin, as will changing
-     * the device password (for all admins).
-     *
-     * <p>The provided timeout is the time delta in ms and will be added to the current time.
-     * For example, to have the password expire 5 days from now, timeout would be
-     * 5 * 86400 * 1000 = 432000000 ms for timeout.
-     *
-     * <p>To disable password expiration, a value of 0 may be used for timeout.
-     *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to be able to call this
-     * method; if it has not, a security exception will be thrown.
-     *
-     * <p> Note that setting the password will automatically reset the expiration time for all
-     * active admins. Active admins do not need to explicitly call this method in that case.
-     *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
+     * Called by a device admin to set the password expiration timeout. Calling this method will
+     * restart the countdown for password expiration for the given admin, as will changing the
+     * device password (for all admins).
+     * <p>
+     * The provided timeout is the time delta in ms and will be added to the current time. For
+     * example, to have the password expire 5 days from now, timeout would be 5 * 86400 * 1000 =
+     * 432000000 ms for timeout.
+     * <p>
+     * To disable password expiration, a value of 0 may be used for timeout.
+     * <p>
+     * The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
+     * <p>
+     * Note that setting the password will automatically reset the expiration time for all active
+     * admins. Active admins do not need to explicitly call this method in that case.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param timeout The limit (in ms) that a password can remain in effect. A value of 0
-     *        means there is no restriction (unlimited).
+     * @param timeout The limit (in ms) that a password can remain in effect. A value of 0 means
+     *            there is no restriction (unlimited).
+     * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
+     *             does not use {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD}
      */
     public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) {
         if (mService != null) {
             try {
                 mService.setPasswordExpirationTimeout(admin, timeout, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1831,7 +1904,7 @@
             try {
                 return mService.getPasswordExpirationTimeout(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1855,7 +1928,7 @@
             try {
                 return mService.getPasswordExpiration(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1884,7 +1957,7 @@
             try {
                 return mService.getPasswordHistoryLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1902,27 +1975,29 @@
     }
 
     /**
-     * Determine whether the current password the user has set is sufficient
-     * to meet the policy requirements (e.g. quality, minimum length) that have been
-     * requested by the admins of this user and its participating profiles.
-     * Restrictions on profiles that have a separate challenge are not taken into account.
-     *
-     * <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.
-     *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to determine
-     * if the password set on the parent profile is sufficient.
+     * Determine whether the current password the user has set is sufficient to meet the policy
+     * requirements (e.g. quality, minimum length) that have been requested by the admins of this
+     * user and its participating profiles. Restrictions on profiles that have a separate challenge
+     * are not taken into account.
+     * <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.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to determine if the password set on
+     * the parent profile is sufficient.
      *
      * @return Returns true if the password meets the current requirements, else false.
+     * @throws SecurityException if the calling application does not own an active administrator
+     *             that uses {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD}
      */
     public boolean isActivePasswordSufficient() {
         if (mService != null) {
             try {
                 return mService.isActivePasswordSufficient(myUserId(), mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1935,6 +2010,7 @@
      *
      * @param userHandle the userId of the profile to check the password for.
      * @return Returns true if the password would meet the current requirements, else false.
+     * @throws SecurityException if {@code userHandle} is not a managed profile.
      * @hide
      */
     public boolean isProfileActivePasswordSufficientForParent(int userHandle) {
@@ -1942,23 +2018,27 @@
             try {
                 return mService.isProfileActivePasswordSufficientForParent(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Retrieve the number of times the user has failed at entering a
-     * password since that last successful password entry.
+     * Retrieve the number of times the user has failed at entering a password since that last
+     * successful password entry.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to retrieve the number of failed
+     * password attemts for the parent user.
+     * <p>
+     * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN}
+     * to be able to call this method; if it has not, a security exception will be thrown.
      *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
-     * the number of failed password attemts for the parent user.
-     *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call
-     * this method; if it has not, a security exception will be thrown.
+     * @return The number of times user has entered an incorrect password since the last correct
+     *         password entry.
+     * @throws SecurityException if the calling application does not own an active administrator
+     *             that uses {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN}
      */
     public int getCurrentFailedPasswordAttempts() {
         return getCurrentFailedPasswordAttempts(myUserId());
@@ -1979,7 +2059,7 @@
             try {
                 return mService.getCurrentFailedPasswordAttempts(userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return -1;
@@ -1996,41 +2076,42 @@
             try {
                 return mService.getDoNotAskCredentialsOnBoot();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Setting this to a value greater than zero enables a built-in policy
-     * that will perform a device or profile wipe after too many incorrect
-     * device-unlock passwords have been entered.  This built-in policy combines
-     * watching for failed passwords and wiping the device, and requires
-     * that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
+     * Setting this to a value greater than zero enables a built-in policy that will perform a
+     * device or profile wipe after too many incorrect device-unlock passwords have been entered.
+     * This built-in policy combines watching for failed passwords and wiping the device, and
+     * requires that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
      * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}}.
-     *
-     * <p>To implement any other policy (e.g. wiping data for a particular
-     * application only, erasing or revoking credentials, or reporting the
-     * failure to a server), you should implement
-     * {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)}
-     * instead.  Do not use this API, because if the maximum count is reached,
-     * the device or profile will be wiped immediately, and your callback will not be invoked.
-     *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * a value on the parent profile.
+     * <p>
+     * To implement any other policy (e.g. wiping data for a particular application only, erasing or
+     * revoking credentials, or reporting the failure to a server), you should implement
+     * {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)} instead. Do not
+     * use this API, because if the maximum count is reached, the device or profile will be wiped
+     * immediately, and your callback will not be invoked.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set a value on the parent
+     * profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param num The number of failed password attempts at which point the
-     * device or profile will be wiped.
+     * @param num The number of failed password attempts at which point the device or profile will
+     *            be wiped.
+     * @throws SecurityException if {@code admin} is not an active administrator or does not use
+     *             both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
+     *             {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}.
      */
     public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) {
         if (mService != null) {
             try {
                 mService.setMaximumFailedPasswordsForWipe(admin, num, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2059,7 +2140,7 @@
                 return mService.getMaximumFailedPasswordsForWipe(
                         admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -2078,7 +2159,7 @@
                 return mService.getProfileWithMinimumFailedPasswordsForWipe(
                         userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return UserHandle.USER_NULL;
@@ -2101,42 +2182,38 @@
     public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 0x0002;
 
     /**
-     * Force a new device unlock password (the password needed to access the
-     * entire device, not for individual accounts) on the user.  This takes
-     * effect immediately.
-     *
-     * <p>Calling this from a managed profile that shares the password with the owner profile
-     * will throw a security exception.
-     *
-     * <p><em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for
+     * Force a new device unlock password (the password needed to access the entire device, not for
+     * individual accounts) on the user. This takes effect immediately.
+     * <p>
+     * <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for
      * device admins that are not device owner and not profile owner.
      * The password can now only be changed if there is currently no password set.  Device owner
      * and profile owner can still do this.</em>
-     *
-     * <p>The given password must be sufficient for the
-     * current password quality and length constraints as returned by
-     * {@link #getPasswordQuality(ComponentName)} and
-     * {@link #getPasswordMinimumLength(ComponentName)}; if it does not meet
-     * these constraints, then it will be rejected and false returned.  Note
-     * that the password may be a stronger quality (containing alphanumeric
-     * characters when the requested quality is only numeric), in which case
-     * the currently active quality will be increased to match.
-     *
-     * <p>Calling with a null or empty password will clear any existing PIN,
-     * pattern or password if the current password constraints allow it. <em>Note: This will not
-     * work in {@link android.os.Build.VERSION_CODES#N} and later for device admins that are not
-     * device owner and not profile owner.  Once set, the password cannot be changed to null or
-     * empty, except by device owner or profile owner.</em>
-     *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call
-     * this method; if it has not, a security exception will be thrown.
+     * <p>
+     * The given password must be sufficient for the current password quality and length constraints
+     * as returned by {@link #getPasswordQuality(ComponentName)} and
+     * {@link #getPasswordMinimumLength(ComponentName)}; if it does not meet these constraints, then
+     * it will be rejected and false returned. Note that the password may be a stronger quality
+     * (containing alphanumeric characters when the requested quality is only numeric), in which
+     * case the currently active quality will be increased to match.
+     * <p>
+     * Calling with a null or empty password will clear any existing PIN, pattern or password if the
+     * current password constraints allow it. <em>Note: This will not work in
+     * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins
+     * that are not device owner or profile owner.  Once set, the password cannot be changed to null
+     * or empty except by these admins.</em>
+     * <p>
+     * The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call this method; if it has
+     * not, a security exception will be thrown.
      *
      * @param password The new password for the user. Null or empty clears the password.
      * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and
-     *              {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}.
-     * @return Returns true if the password was applied, or false if it is
-     * not acceptable for the current constraints or if the user has not been decrypted yet.
+     *            {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}.
+     * @return Returns true if the password was applied, or false if it is not acceptable for the
+     *         current constraints or if the user has not been decrypted yet.
+     * @throws SecurityException if the calling application does not own an active administrator
+     *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
      */
     public boolean resetPassword(String password, int flags) {
         if (mParentInstance) {
@@ -2146,35 +2223,36 @@
             try {
                 return mService.resetPassword(password, flags);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Called by an application that is administering the device to set the
-     * maximum time for user activity until the device will lock.  This limits
-     * the length that the user can set.  It takes effect immediately.
-     *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
-     * this method; if it has not, a security exception will be thrown.
-     *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
-     * restrictions on the parent profile.
+     * Called by an application that is administering the device to set the maximum time for user
+     * activity until the device will lock. This limits the length that the user can set. It takes
+     * effect immediately.
+     * <p>
+     * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK}
+     * to be able to call this method; if it has not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param timeMs The new desired maximum time to lock in milliseconds.
-     * A value of 0 means there is no restriction.
+     * @param timeMs The new desired maximum time to lock in milliseconds. A value of 0 means there
+     *            is no restriction.
+     * @throws SecurityException if {@code admin} is not an active administrator or it does not use
+     *             {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK}
      */
     public void setMaximumTimeToLock(@NonNull ComponentName admin, long timeMs) {
         if (mService != null) {
             try {
                 mService.setMaximumTimeToLock(admin, timeMs, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2203,30 +2281,31 @@
             try {
                 return mService.getMaximumTimeToLock(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
     }
 
     /**
-     * Make the device lock immediately, as if the lock screen timeout has
-     * expired at the point of this call.
+     * Make the device lock immediately, as if the lock screen timeout has expired at the point of
+     * this call.
+     * <p>
+     * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK}
+     * to be able to call this method; if it has not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to lock the parent profile.
      *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
-     * this method; if it has not, a security exception will be thrown.
-     *
-     * <p>This method can be called on the {@link DevicePolicyManager} instance
-     * returned by {@link #getParentProfileInstance(ComponentName)} in order to lock
-     * the parent profile.
+     * @throws SecurityException if the calling application does not own an active administrator
+     *             that uses {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK}
      */
     public void lockNow() {
         if (mService != null) {
             try {
                 mService.lockNow(mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2247,23 +2326,23 @@
     public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;
 
     /**
-     * Ask the user data be wiped.  Wiping the primary user will cause the
-     * device to reboot, erasing all user data while next booting up.
+     * Ask the user data be wiped. Wiping the primary user will cause the device to reboot, erasing
+     * all user data while next booting up.
+     * <p>
+     * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to
+     * be able to call this method; if it has not, a security exception will be thrown.
      *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
-     * this method; if it has not, a security exception will be thrown.
-     *
-     * @param flags Bit mask of additional options: currently supported flags
-     * are {@link #WIPE_EXTERNAL_STORAGE} and
-     * {@link #WIPE_RESET_PROTECTION_DATA}.
+     * @param flags Bit mask of additional options: currently supported flags are
+     *            {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
+     * @throws SecurityException if the calling application does not own an active administrator
+     *             that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
      */
     public void wipeData(int flags) {
         if (mService != null) {
             try {
                 mService.wipeData(flags);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2333,27 +2412,27 @@
                 }
                 return mService.setGlobalProxy(admin, hostSpec, exclSpec);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
     }
 
     /**
-     * Set a network-independent global HTTP proxy.  This is not normally what you want
-     * for typical HTTP proxies - they are generally 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.
+     * Set a network-independent global HTTP proxy. This is not normally what you want for typical
+     * HTTP proxies - they are generally 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.
+     * <p>
+     * This method requires the caller to be the device owner.
+     * <p>
+     * This proxy is only a recommendation and it is possible that some apps will ignore it.
      *
-     * <p>This method requires the caller to be the device owner.
-     *
-     * <p>This proxy is only a recommendation and it is possible that some apps will ignore it.
      * @see ProxyInfo
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param proxyInfo The a {@link ProxyInfo} object defining the new global
-     *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param proxyInfo The a {@link ProxyInfo} object defining the new global HTTP proxy. A
+     *            {@code null} value will clear the global HTTP proxy.
+     * @throws SecurityException if {@code admin} is not the device owner.
      */
     public void setRecommendedGlobalProxy(@NonNull ComponentName admin, @Nullable ProxyInfo
             proxyInfo) {
@@ -2361,7 +2440,7 @@
             try {
                 mService.setRecommendedGlobalProxy(admin, proxyInfo);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2377,7 +2456,7 @@
             try {
                 return mService.getGlobalProxyAdmin(myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -2419,6 +2498,12 @@
     public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4;
 
     /**
+     * Result code for {@link #getStorageEncryptionStatus}:
+     * indicating that encryption is active and the encryption key is tied to the user.
+     */
+    public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5;
+
+    /**
      * Activity action: begin the process of encrypting data on the device.  This activity should
      * be launched after using {@link #setStorageEncryption} to request encryption be activated.
      * After resuming from this activity, use {@link #getStorageEncryption}
@@ -2470,43 +2555,42 @@
     public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
 
     /**
-     * Called by an application that is administering the device to
-     * request that the storage system be encrypted.
-     *
-     * <p>When multiple device administrators attempt to control device
-     * encryption, the most secure, supported setting will always be
-     * used.  If any device administrator requests device encryption,
-     * it will be enabled;  Conversely, if a device administrator
-     * attempts to disable device encryption while another
-     * device administrator has enabled it, the call to disable will
+     * Called by an application that is administering the device to request that the storage system
+     * be encrypted.
+     * <p>
+     * When multiple device administrators attempt to control device encryption, the most secure,
+     * supported setting will always be used. If any device administrator requests device
+     * encryption, it will be enabled; Conversely, if a device administrator attempts to disable
+     * device encryption while another device administrator has enabled it, the call to disable will
      * fail (most commonly returning {@link #ENCRYPTION_STATUS_ACTIVE}).
-     *
-     * <p>This policy controls encryption of the secure (application data) storage area.  Data
-     * written to other storage areas may or may not be encrypted, and this policy does not require
-     * or control the encryption of any other storage areas.
-     * There is one exception:  If {@link android.os.Environment#isExternalStorageEmulated()} is
-     * {@code true}, then the directory returned by
-     * {@link android.os.Environment#getExternalStorageDirectory()} must be written to disk
-     * within the encrypted storage area.
-     *
-     * <p>Important Note:  On some devices, it is possible to encrypt storage without requiring
-     * the user to create a device PIN or Password.  In this case, the storage is encrypted, but
-     * the encryption key may not be fully secured.  For maximum security, the administrator should
-     * also require (and check for) a pattern, PIN, or password.
+     * <p>
+     * This policy controls encryption of the secure (application data) storage area. Data written
+     * to other storage areas may or may not be encrypted, and this policy does not require or
+     * control the encryption of any other storage areas. There is one exception: If
+     * {@link android.os.Environment#isExternalStorageEmulated()} is {@code true}, then the
+     * directory returned by {@link android.os.Environment#getExternalStorageDirectory()} must be
+     * written to disk within the encrypted storage area.
+     * <p>
+     * Important Note: On some devices, it is possible to encrypt storage without requiring the user
+     * to create a device PIN or Password. In this case, the storage is encrypted, but the
+     * encryption key may not be fully secured. For maximum security, the administrator should also
+     * require (and check for) a pattern, PIN, or password.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param encrypt true to request encryption, false to release any previous request
      * @return the new request status (for all active admins) - will be one of
-     * {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE}, or
-     * {@link #ENCRYPTION_STATUS_ACTIVE}.  This is the value of the requests;  Use
-     * {@link #getStorageEncryptionStatus()} to query the actual device state.
+     *         {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE}, or
+     *         {@link #ENCRYPTION_STATUS_ACTIVE}. This is the value of the requests; Use
+     *         {@link #getStorageEncryptionStatus()} to query the actual device state.
+     * @throws SecurityException if {@code admin} is not an active administrator or does not use
+     *             {@link DeviceAdminInfo#USES_ENCRYPTED_STORAGE}
      */
     public int setStorageEncryption(@NonNull ComponentName admin, boolean encrypt) {
         if (mService != null) {
             try {
                 return mService.setStorageEncryption(admin, encrypt);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return ENCRYPTION_STATUS_UNSUPPORTED;
@@ -2526,7 +2610,7 @@
             try {
                 return mService.getStorageEncryption(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2559,15 +2643,52 @@
     public int getStorageEncryptionStatus(int userHandle) {
         if (mService != null) {
             try {
-                return mService.getStorageEncryptionStatus(userHandle);
+                return mService.getStorageEncryptionStatus(mContext.getPackageName(), userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return ENCRYPTION_STATUS_UNSUPPORTED;
     }
 
     /**
+     * Mark a CA certificate as approved by the device user. This means that they have been notified
+     * of the installation, were made aware of the risks, viewed the certificate and still wanted to
+     * keep the certificate on the device.
+     *
+     * Calling with {@param approval} as {@code true} will cancel any ongoing warnings related to
+     * this certificate.
+     *
+     * @hide
+     */
+    public boolean approveCaCert(String alias, int userHandle, boolean approval) {
+        if (mService != null) {
+            try {
+                return mService.approveCaCert(alias, userHandle, approval);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check whether a CA certificate has been approved by the device user.
+     *
+     * @hide
+     */
+    public boolean isCaCertApproved(String alias, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isCaCertApproved(alias, userHandle);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Installs the given certificate as a user CA.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
@@ -2576,13 +2697,15 @@
      *
      * @return false if the certBuffer cannot be parsed or installation is
      *         interrupted, true otherwise.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
      */
     public boolean installCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
         if (mService != null) {
             try {
                 return mService.installCaCert(admin, certBuffer);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2594,6 +2717,8 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *              {@code null} if calling from a delegated certificate installer.
      * @param certBuffer encoded form of the certificate to remove.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
      */
     public void uninstallCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
         if (mService != null) {
@@ -2603,7 +2728,7 @@
             } catch (CertificateException e) {
                 Log.w(TAG, "Unable to parse certificate", e);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2616,6 +2741,8 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *              {@code null} if calling from a delegated certificate installer.
      * @return a List of byte[] arrays, each encoding one user CA certificate.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
      */
     public List<byte[]> getInstalledCaCerts(@Nullable ComponentName admin) {
         List<byte[]> certs = new ArrayList<byte[]>();
@@ -2631,7 +2758,7 @@
                     }
                 }
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return certs;
@@ -2643,6 +2770,8 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *              {@code null} if calling from a delegated certificate installer.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
      */
     public void uninstallAllUserCaCerts(@Nullable ComponentName admin) {
         if (mService != null) {
@@ -2650,7 +2779,7 @@
                 mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases()
                         .toArray(new String[0]));
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -2661,6 +2790,8 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *              {@code null} if calling from a delegated certificate installer.
      * @param certBuffer encoded form of the certificate to look up.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
      */
     public boolean hasCaCertInstalled(@Nullable ComponentName admin, byte[] certBuffer) {
         if (mService != null) {
@@ -2668,7 +2799,7 @@
                 mService.enforceCanManageCaCerts(admin);
                 return getCaCertAlias(certBuffer) != null;
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             } catch (CertificateException ce) {
                 Log.w(TAG, "Could not parse certificate", ce);
             }
@@ -2677,8 +2808,16 @@
     }
 
     /**
-     * Called by a device or profile owner to install a certificate and private key pair. The
-     * keypair will be visible to all apps within the profile.
+     * Called by a device or profile owner, or delegated certificate installer, to install a
+     * certificate and corresponding private key. All apps within the profile will be able to access
+     * the certificate and use the private key, given direct user approval.
+     *
+     * <p>Access to the installed credentials will not be granted to the caller of this API without
+     * direct user approval. This is for security - should a certificate installer become
+     * compromised, certificates it had already installed will be protected.
+     *
+     * <p>If the installer must have access to the credentials, call
+     * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, boolean)} instead.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *            {@code null} if calling from a delegated certificate installer.
@@ -2687,16 +2826,54 @@
      * @param alias The private key alias under which to install the certificate. If a certificate
      * with that alias already exists, it will be overwritten.
      * @return {@code true} if the keys were installed, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
      */
     public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
             @NonNull Certificate cert, @NonNull String alias) {
+        return installKeyPair(admin, privKey, new Certificate[] {cert}, alias, false);
+    }
+
+    /**
+     * Called by a device or profile owner, or delegated certificate installer, to install a
+     * certificate chain and corresponding private key for the leaf certificate. All apps within the
+     * profile will be able to access the certificate chain and use the private key, given direct
+     * user approval.
+     *
+     * <p>The caller of this API may grant itself access to the certificate and private key
+     * immediately, without user approval. It is a best practice not to request this unless strictly
+     * necessary since it opens up additional security vulnerabilities.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *        {@code null} if calling from a delegated certificate installer.
+     * @param privKey The private key to install.
+     * @param certs The certificate chain to install. The chain should start with the leaf
+     *        certificate and include the chain of trust in order. This will be returned by
+     *        {@link android.security.KeyChain#getCertificateChain}.
+     * @param alias The private key alias under which to install the certificate. If a certificate
+     *        with that alias already exists, it will be overwritten.
+     * @param requestAccess {@code true} to request that the calling app be granted access to the
+     *        credentials immediately. Otherwise, access to the credentials will be gated by user
+     *        approval.
+     * @return {@code true} if the keys were installed, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
+     * @see android.security.KeyChain#getCertificateChain
+     */
+    public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
+            @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) {
         try {
-            final byte[] pemCert = Credentials.convertToPem(cert);
+            final byte[] pemCert = Credentials.convertToPem(certs[0]);
+            byte[] pemChain = null;
+            if (certs.length > 1) {
+                pemChain = Credentials.convertToPem(Arrays.copyOfRange(certs, 1, certs.length));
+            }
             final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
                     .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
-            return mService.installKeyPair(admin, pkcs8Key, pemCert, alias);
+            return mService.installKeyPair(admin, pkcs8Key, pemCert, pemChain, alias,
+                    requestAccess);
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            throw e.rethrowFromSystemServer();
         } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
             Log.w(TAG, "Failed to obtain private key material", e);
         } catch (CertificateException | IOException e) {
@@ -2706,21 +2883,22 @@
     }
 
     /**
-     * Called by a device or profile owner to remove all user credentials installed under a given
-     * alias.
+     * Called by a device or profile owner, or delegated certificate installer, to remove a
+     * certificate and private key pair installed under a given alias.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
-     *            {@code null} if calling from a delegated certificate installer.
+     *        {@code null} if calling from a delegated certificate installer.
      * @param alias The private key alias under which the certificate is installed.
-     * @return {@code true} if the keys were both removed, {@code false} otherwise.
+     * @return {@code true} if the private key alias no longer exists, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
+     *         owner.
      */
     public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) {
         try {
             return mService.removeKeyPair(admin, alias);
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -2743,15 +2921,16 @@
      * Delegated certificate installer is a per-user state. The delegated access is persistent until
      * it is later cleared by calling this method with a null value or uninstallling the certificate
      * installer.
-     *<p>
+     * <p>
      * <b>Note:</b>Starting from {@link android.os.Build.VERSION_CODES#N}, if the caller
      * application's target SDK version is {@link android.os.Build.VERSION_CODES#N} or newer, the
-     * supplied certificate installer package must be installed when calling this API,
-     * otherwise an {@link IllegalArgumentException} will be thrown.
+     * supplied certificate installer package must be installed when calling this API, otherwise an
+     * {@link IllegalArgumentException} will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param installerPackage The package name of the certificate installer which will be given
-     * access. If {@code null} is given the current package will be cleared.
+     *            access. If {@code null} is given the current package will be cleared.
+     * @throws SecurityException if {@code admin} is not a device or a profile owner.
      */
     public void setCertInstallerPackage(@NonNull ComponentName admin, @Nullable String
             installerPackage) throws SecurityException {
@@ -2759,25 +2938,26 @@
             try {
                 mService.setCertInstallerPackage(admin, installerPackage);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Called by a profile owner or device owner to retrieve the certificate installer for the
-     * user. null if none is set.
+     * Called by a profile owner or device owner to retrieve the certificate installer for the user.
+     * null if none is set.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The package name of the current delegated certificate installer, or {@code null}
-     * if none is set.
+     * @return The package name of the current delegated certificate installer, or {@code null} if
+     *         none is set.
+     * @throws SecurityException if {@code admin} is not a device or a profile owner.
      */
     public String getCertInstallerPackage(@NonNull ComponentName admin) throws SecurityException {
         if (mService != null) {
             try {
                 return mService.getCertInstallerPackage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -2785,71 +2965,77 @@
 
     /**
      * Called by a device or profile owner to configure an always-on VPN connection through a
-     * specific application for the current user.
-     * This connection is automatically granted and persisted after a reboot.
+     * specific application for the current user. This connection is automatically granted and
+     * persisted after a reboot.
+     * <p>
+     * The designated package should declare a {@link android.net.VpnService} in its manifest
+     * guarded by {@link android.Manifest.permission#BIND_VPN_SERVICE}, otherwise the call will
+     * fail.
      *
-     * <p>The designated package should declare a {@link android.net.VpnService} in its
-     *    manifest guarded by {@link android.Manifest.permission#BIND_VPN_SERVICE},
-     *    otherwise the call will fail.
-     *
-     * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
-     *                   to remove an existing always-on VPN configuration.
-     *
-     * @return {@code true} if the package is set as always-on VPN controller;
-     *         {@code false} otherwise.
+     * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
+     *            remove an existing always-on VPN configuration.
+     * @return {@code true} if the package is set as always-on VPN controller; {@code false}
+     *         otherwise.
+     * @throws SecurityException if {@code admin} is not a device or a profile owner.
+     * @throws NameNotFoundException if {@code vpnPackage} is not installed.
+     * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
+     *         set as always-on, or if always-on VPN is not available.
      */
-    public boolean setAlwaysOnVpnPackage(@NonNull ComponentName admin,
-            @Nullable String vpnPackage) {
+    public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage)
+            throws NameNotFoundException, UnsupportedOperationException {
         if (mService != null) {
             try {
-                return mService.setAlwaysOnVpnPackage(admin, vpnPackage);
+                if (!mService.setAlwaysOnVpnPackage(admin, vpnPackage)) {
+                    throw new NameNotFoundException(vpnPackage);
+                }
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
-        return false;
     }
 
     /**
      * Called by a device or profile owner to read the name of the package administering an
-     * always-on VPN connection for the current user.
-     * If there is no such package, or the always-on VPN is provided by the system instead
-     * of by an application, {@code null} will be returned.
+     * always-on VPN connection for the current user. If there is no such package, or the always-on
+     * VPN is provided by the system instead of by an application, {@code null} will be returned.
      *
-     * @return Package name of VPN controller responsible for always-on VPN,
-     *         or {@code null} if none is set.
+     * @return Package name of VPN controller responsible for always-on VPN, or {@code null} if none
+     *         is set.
+     * @throws SecurityException if {@code admin} is not a device or a profile owner.
      */
     public String getAlwaysOnVpnPackage(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getAlwaysOnVpnPackage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
     }
 
     /**
-     * Called by an application that is administering the device to disable all cameras
-     * on the device, for this user. After setting this, no applications running as this user
-     * will be able to access any cameras on the device.
-     *
-     * <p>If the caller is device owner, then the restriction will be applied to all users.
-     *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call
-     * this method; if it has not, a security exception will be thrown.
+     * Called by an application that is administering the device to disable all cameras on the
+     * device, for this user. After setting this, no applications running as this user will be able
+     * to access any cameras on the device.
+     * <p>
+     * If the caller is device owner, then the restriction will be applied to all users.
+     * <p>
+     * The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call this method; if it has
+     * not, a security exception will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled Whether or not the camera should be disabled.
+     * @throws SecurityException if {@code admin} is not an active administrator or does not use
+     *             {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
      */
     public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
                 mService.setCameraDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2870,7 +3056,7 @@
             try {
                 return mService.getCameraDisabled(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2878,21 +3064,23 @@
 
     /**
      * Called by a device owner to request a bugreport.
-     *
-     * <p>There must be only one user on the device, managed by the device owner.
-     * Otherwise a security exception will be thrown.
+     * <p>
+     * There must be only one user on the device, managed by the device owner. Otherwise a
+     * {@link SecurityException} will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return {@code true} if the bugreport collection started successfully, or {@code false}
-     * if it wasn't triggered because a previous bugreport operation is still active
-     * (either the bugreport is still running or waiting for the user to share or decline)
+     * @return {@code true} if the bugreport collection started successfully, or {@code false} if it
+     *         wasn't triggered because a previous bugreport operation is still active (either the
+     *         bugreport is still running or waiting for the user to share or decline)
+     * @throws SecurityException if {@code admin} is not a device owner, or if there are users other
+     *             than the one managed by the device owner.
      */
     public boolean requestBugreport(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.requestBugreport(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2914,22 +3102,23 @@
      * screen capture also prevents the content from being shown on display devices that do not have
      * a secure video output. See {@link android.view.Display#FLAG_SECURE} for more details about
      * secure surfaces and secure displays.
-     *
-     * <p>The calling device admin must be a device or profile owner. If it is not, a
-     * security exception will be thrown.
-     *
-     * <p>From version {@link android.os.Build.VERSION_CODES#M} disabling screen capture also
-     * blocks assist requests for all activities of the relevant user.
+     * <p>
+     * The calling device admin must be a device or profile owner. If it is not, a security
+     * exception will be thrown.
+     * <p>
+     * From version {@link android.os.Build.VERSION_CODES#M} disabling screen capture also blocks
+     * assist requests for all activities of the relevant user.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled Whether screen capture is disabled or not.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setScreenCaptureDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
                 mService.setScreenCaptureDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2950,30 +3139,31 @@
             try {
                 return mService.getScreenCaptureDisabled(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Called by a device owner to set whether auto time is required. If auto time is
-     * required the user cannot set the date and time, but has to use network date and time.
-     *
-     * <p>Note: if auto time is required the user can still manually set the time zone.
-     *
-     * <p>The calling device admin must be a device owner. If it is not, a security exception will
-     * be thrown.
+     * Called by a device owner to set whether auto time is required. If auto time is required the
+     * user cannot set the date and time, but has to use network date and time.
+     * <p>
+     * Note: if auto time is required the user can still manually set the time zone.
+     * <p>
+     * The calling device admin must be a device owner. If it is not, a security exception will be
+     * thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param required Whether auto time is set required or not.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
     public void setAutoTimeRequired(@NonNull ComponentName admin, boolean required) {
         if (mService != null) {
             try {
                 mService.setAutoTimeRequired(admin, required);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2986,7 +3176,7 @@
             try {
                 return mService.getAutoTimeRequired();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2994,15 +3184,16 @@
 
     /**
      * Called by a device owner to set whether all users created on the device should be ephemeral.
-     *
-     * <p>The system user is exempt from this policy - it is never ephemeral.
-     *
-     * <p>The calling device admin must be the device owner. If it is not, a security exception will
-     * be thrown.
+     * <p>
+     * The system user is exempt from this policy - it is never ephemeral.
+     * <p>
+     * The calling device admin must be the device owner. If it is not, a security exception will be
+     * thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param forceEphemeralUsers If true, all the existing users will be deleted and all
-     *         subsequently created users will be ephemeral.
+     *            subsequently created users will be ephemeral.
+     * @throws SecurityException if {@code admin} is not a device owner.
      * @hide
      */
     public void setForceEphemeralUsers(
@@ -3011,13 +3202,14 @@
             try {
                 mService.setForceEphemeralUsers(admin, forceEphemeralUsers);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
      * @return true if all users are created ephemeral.
+     * @throws SecurityException if {@code admin} is not a device owner.
      * @hide
      */
     public boolean getForceEphemeralUsers(@NonNull ComponentName admin) {
@@ -3025,7 +3217,7 @@
             try {
                 return mService.getForceEphemeralUsers(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3035,46 +3227,48 @@
      * Called by an application that is administering the device to disable keyguard customizations,
      * such as widgets. After setting this, keyguard features will be disabled according to the
      * provided feature list.
-     *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES} to be able to call
-     * this method; if it has not, a security exception will be thrown.
-     *
-     * <p>Calling this from a managed profile before version
-     * {@link android.os.Build.VERSION_CODES#M} will throw a security exception. From version
-     * {@link android.os.Build.VERSION_CODES#M} the profile owner of a managed profile can set:
+     * <p>
+     * The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES} to be able to call this method;
+     * if it has not, a security exception will be thrown.
+     * <p>
+     * Calling this from a managed profile before version {@link android.os.Build.VERSION_CODES#M}
+     * will throw a security exception. From version {@link android.os.Build.VERSION_CODES#M} the
+     * profile owner of a managed profile can set:
      * <ul>
      * <li>{@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which affects the parent user, but only if there
-     *      is no separate challenge set on the managed profile.
+     * is no separate challenge set on the managed profile.
      * <li>{@link #KEYGUARD_DISABLE_FINGERPRINT} which affects the managed profile challenge if
-     *      there is one, or the parent user otherwise.
-     * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} which affects notifications
-     *      generated by applications in the managed profile.
+     * there is one, or the parent user otherwise.
+     * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} which affects notifications generated
+     * by applications in the managed profile.
      * </ul>
-     *
      * {@link #KEYGUARD_DISABLE_TRUST_AGENTS} and {@link #KEYGUARD_DISABLE_FINGERPRINT} can also be
      * set on the {@link DevicePolicyManager} instance returned by
-     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the
-     * parent profile.
-     *
-     * <p>Requests to disable other features on a managed profile will be ignored.
-     *
-     * <p>The admin can check which features have been disabled by calling
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
+     * <p>
+     * Requests to disable other features on a managed profile will be ignored.
+     * <p>
+     * The admin can check which features have been disabled by calling
      * {@link #getKeyguardDisabledFeatures(ComponentName)}
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param which {@link #KEYGUARD_DISABLE_FEATURES_NONE} (default),
-     * {@link #KEYGUARD_DISABLE_WIDGETS_ALL}, {@link #KEYGUARD_DISABLE_SECURE_CAMERA},
-     * {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_TRUST_AGENTS},
-     * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FINGERPRINT},
-     * {@link #KEYGUARD_DISABLE_FEATURES_ALL}
+     *            {@link #KEYGUARD_DISABLE_WIDGETS_ALL}, {@link #KEYGUARD_DISABLE_SECURE_CAMERA},
+     *            {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS},
+     *            {@link #KEYGUARD_DISABLE_TRUST_AGENTS},
+     *            {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS},
+     *            {@link #KEYGUARD_DISABLE_FINGERPRINT}, {@link #KEYGUARD_DISABLE_FEATURES_ALL}
+     * @throws SecurityException if {@code admin} is not an active administrator or does not user
+     *             {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES}
      */
     public void setKeyguardDisabledFeatures(@NonNull ComponentName admin, int which) {
         if (mService != null) {
             try {
                 mService.setKeyguardDisabledFeatures(admin, which, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3103,7 +3297,7 @@
             try {
                 return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return KEYGUARD_DISABLE_FEATURES_NONE;
@@ -3118,7 +3312,7 @@
             try {
                 mService.setActiveAdmin(policyReceiver, refreshing, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3131,31 +3325,6 @@
     }
 
     /**
-     * Returns the DeviceAdminInfo as defined by the administrator's package info &amp; meta-data
-     * @hide
-     */
-    public DeviceAdminInfo getAdminInfo(@NonNull ComponentName cn) {
-        ActivityInfo ai;
-        try {
-            ai = mContext.getPackageManager().getReceiverInfo(cn,
-                    PackageManager.GET_META_DATA);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Unable to retrieve device policy " + cn, e);
-            return null;
-        }
-
-        ResolveInfo ri = new ResolveInfo();
-        ri.activityInfo = ai;
-
-        try {
-            return new DeviceAdminInfo(mContext, ri);
-        } catch (XmlPullParserException | IOException e) {
-            Log.w(TAG, "Unable to parse device policy " + cn, e);
-            return null;
-        }
-    }
-
-    /**
      * @hide
      */
     public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) {
@@ -3163,7 +3332,7 @@
             try {
                 mService.getRemoveWarning(admin, result, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3178,7 +3347,7 @@
                 mService.setActivePasswordState(quality, length, letters, uppercase, lowercase,
                         numbers, symbols, nonletter, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3191,7 +3360,7 @@
             try {
                 mService.reportFailedPasswordAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3204,7 +3373,7 @@
             try {
                 mService.reportSuccessfulPasswordAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3217,7 +3386,7 @@
             try {
                 mService.reportFailedFingerprintAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3230,7 +3399,7 @@
             try {
                 mService.reportSuccessfulFingerprintAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3244,7 +3413,7 @@
             try {
                 mService.reportKeyguardDismissed(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3258,7 +3427,7 @@
             try {
                 mService.reportKeyguardSecured(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3311,7 +3480,7 @@
             try {
                 return mService.setDeviceOwner(who, ownerName, userId);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3393,7 +3562,7 @@
             try {
                 return mService.getDeviceOwnerComponent(callingUserOnly);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3412,27 +3581,27 @@
             try {
                 return mService.getDeviceOwnerUserId();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return UserHandle.USER_NULL;
     }
 
     /**
-     * Clears the current device owner.  The caller must be the device owner.
-     *
-     * This function should be used cautiously as once it is called it cannot
-     * be undone.  The device owner can only be set as a part of device setup
-     * before setup completes.
+     * Clears the current device owner. The caller must be the device owner. This function should be
+     * used cautiously as once it is called it cannot be undone. The device owner can only be set as
+     * a part of device setup before setup completes.
      *
      * @param packageName The package name of the device owner.
+     * @throws SecurityException if the caller is not in {@code packageName} or {@code packageName}
+     *             does not own the current device owner component.
      */
     public void clearDeviceOwnerApp(String packageName) {
         if (mService != null) {
             try {
                 mService.clearDeviceOwner(packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -3475,7 +3644,7 @@
             try {
                 return mService.getDeviceOwnerName();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3528,27 +3697,28 @@
                 mService.setActiveAdmin(admin, false, myUserId);
                 return mService.setProfileOwner(admin, ownerName, myUserId);
             } catch (RemoteException re) {
-                throw new IllegalArgumentException("Couldn't set profile owner.", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Clears the active profile owner and removes all user restrictions. The caller must
-     * be from the same package as the active profile owner for this user, otherwise a
-     * SecurityException will be thrown.
-     *
-     * <p>This doesn't work for managed profile owners.
+     * Clears the active profile owner and removes all user restrictions. The caller must be from
+     * the same package as the active profile owner for this user, otherwise a SecurityException
+     * will be thrown.
+     * <p>
+     * This doesn't work for managed profile owners.
      *
      * @param admin The component to remove as the profile owner.
+     * @throws SecurityException if {@code admin} is not an active profile owner.
      */
     public void clearProfileOwner(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 mService.clearProfileOwner(admin);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -3562,7 +3732,7 @@
             try {
                 return mService.hasUserSetupCompleted();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return true;
@@ -3593,8 +3763,7 @@
                 }
                 return mService.setProfileOwner(admin, ownerName, userHandle);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException("Couldn't set profile owner.", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3602,41 +3771,40 @@
 
     /**
      * Sets the device owner information to be shown on the lock screen.
-     *
-     * <p>If the device owner information is {@code null} or empty then the device owner info is
+     * <p>
+     * If the device owner information is {@code null} or empty then the device owner info is
      * cleared and the user owner info is shown on the lock screen if it is set.
-     * <p>If the device owner information contains only whitespaces then the message on the lock
-     * screen will be blank and the user will not be allowed to change it.
-     *
-     * <p>If the device owner information needs to be localized, it is the responsibility of the
+     * <p>
+     * If the device owner information contains only whitespaces then the message on the lock screen
+     * will be blank and the user will not be allowed to change it.
+     * <p>
+     * If the device owner information needs to be localized, it is the responsibility of the
      * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
      * and set a new version of this string accordingly.
      *
      * @param admin The name of the admin component to check.
-     * @param info Device owner information which will be displayed instead of the user
-     * owner info.
-     * @return Whether the device owner information has been set.
+     * @param info Device owner information which will be displayed instead of the user owner info.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public boolean setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, String info) {
+    public void setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, CharSequence info) {
         if (mService != null) {
             try {
-                return mService.setDeviceOwnerLockScreenInfo(admin, info);
+                mService.setDeviceOwnerLockScreenInfo(admin, info);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
-        return false;
     }
 
     /**
      * @return The device owner information. If it is not set returns {@code null}.
      */
-    public String getDeviceOwnerLockScreenInfo() {
+    public CharSequence getDeviceOwnerLockScreenInfo() {
         if (mService != null) {
             try {
                 return mService.getDeviceOwnerLockScreenInfo();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3644,19 +3812,22 @@
 
     /**
      * Called by device or profile owners to suspend packages for this user.
-     *
-     * <p>A suspended package will not be able to start activities. Its notifications will
-     * be hidden, it will not show up in recents, will not be able to show toasts or dialogs
-     * or ring the device.
-     *
-     * <p>The package must already be installed.
+     * <p>
+     * A suspended package will not be able to start activities. Its notifications will be hidden,
+     * it will not show up in recents, will not be able to show toasts or dialogs or ring the
+     * device.
+     * <p>
+     * The package must already be installed. If the package is uninstalled while suspended the
+     * package will no longer be suspended. The admin can block this by using
+     * {@link #setUninstallBlocked}.
      *
      * @param admin The name of the admin component to check.
      * @param packageNames The package names to suspend or unsuspend.
      * @param suspended If set to {@code true} than the packages will be suspended, if set to
-     * {@code false} the packages will be unsuspended.
+     *            {@code false} the packages will be unsuspended.
      * @return an array of package names for which the suspended status is not set as requested in
-     * this method.
+     *         this method.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public String[] setPackagesSuspended(@NonNull ComponentName admin, String[] packageNames,
             boolean suspended) {
@@ -3664,7 +3835,7 @@
             try {
                 return mService.setPackagesSuspended(admin, packageNames, suspended);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return packageNames;
@@ -3676,14 +3847,19 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package to retrieve the suspended status of.
      * @return {@code true} if the package is suspended or {@code false} if the package is not
-     * suspended, could not be found or an error occurred.
+     *         suspended, could not be found or an error occurred.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
+     * @throws NameNotFoundException if the package could not be found.
      */
-    public boolean getPackageSuspended(@NonNull ComponentName admin, String packageName) {
+    public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName)
+            throws NameNotFoundException {
         if (mService != null) {
             try {
-                return mService.getPackageSuspended(admin, packageName);
+                return mService.isPackageSuspended(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
+            } catch (IllegalArgumentException ex) {
+                throw new NameNotFoundException(packageName);
             }
         }
         return false;
@@ -3694,36 +3870,36 @@
      * be used. Only the profile owner can call this.
      *
      * @see #isProfileOwnerApp
-     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public void setProfileEnabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 mService.setProfileEnabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Sets the name of the profile. In the device owner case it sets the name of the user
-     * which it is called from. Only a profile owner or device owner can call this. If this is
-     * never called by the profile or device owner, the name will be set to default values.
+     * Sets the name of the profile. In the device owner case it sets the name of the user which it
+     * is called from. Only a profile owner or device owner can call this. If this is never called
+     * by the profile or device owner, the name will be set to default values.
      *
      * @see #isProfileOwnerApp
      * @see #isDeviceOwnerApp
-     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associate with.
      * @param profileName The name of the profile.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setProfileName(@NonNull ComponentName admin, String profileName) {
         if (mService != null) {
             try {
                 mService.setProfileName(admin, profileName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3743,7 +3919,7 @@
                 return profileOwner != null
                         && profileOwner.getPackageName().equals(packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3769,9 +3945,7 @@
             try {
                 return mService.getProfileOwner(userId);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException(
-                        "Requested profile owner for invalid userId", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3788,9 +3962,7 @@
             try {
                 return mService.getProfileOwnerName(Process.myUserHandle().getIdentifier());
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException(
-                        "Requested profile owner for invalid userId", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3809,9 +3981,7 @@
             try {
                 return mService.getProfileOwnerName(userId);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException(
-                        "Requested profile owner for invalid userId", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3820,19 +3990,20 @@
     /**
      * Called by a profile owner or device owner to add a default intent handler activity for
      * intents that match a certain intent filter. This activity will remain the default intent
-     * handler even if the set of potential event handlers for the intent filter changes and if
-     * the intent preferences are reset.
-     *
-     * <p>The default disambiguation mechanism takes over if the activity is not installed
-     * (anymore). When the activity is (re)installed, it is automatically reset as default
-     * intent handler for the filter.
-     *
-     * <p>The calling device admin must be a profile owner or device owner. If it is not, a
-     * security exception will be thrown.
+     * handler even if the set of potential event handlers for the intent filter changes and if the
+     * intent preferences are reset.
+     * <p>
+     * The default disambiguation mechanism takes over if the activity is not installed (anymore).
+     * When the activity is (re)installed, it is automatically reset as default intent handler for
+     * the filter.
+     * <p>
+     * The calling device admin must be a profile owner or device owner. If it is not, a security
+     * exception will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param filter The IntentFilter for which a default handler is added.
      * @param activity The Activity that is added as default intent handler.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void addPersistentPreferredActivity(@NonNull ComponentName admin, IntentFilter filter,
             @NonNull ComponentName activity) {
@@ -3840,7 +4011,7 @@
             try {
                 mService.addPersistentPreferredActivity(admin, filter, activity);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3848,12 +4019,13 @@
     /**
      * Called by a profile owner or device owner to remove all persistent intent handler preferences
      * associated with the given package that were set by {@link #addPersistentPreferredActivity}.
-     *
-     * <p>The calling device admin must be a profile owner. If it is not, a security
-     * exception will be thrown.
+     * <p>
+     * The calling device admin must be a profile owner. If it is not, a security exception will be
+     * thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package for which preferences are removed.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void clearPackagePersistentPreferredActivities(@NonNull ComponentName admin,
             String packageName) {
@@ -3861,7 +4033,7 @@
             try {
                 mService.clearPackagePersistentPreferredActivities(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3875,19 +4047,23 @@
      * {@code null} value or uninstalling the managing package.
      * <p>
      * The supplied application restriction managing package must be installed when calling this
-     * API, otherwise an {@link IllegalArgumentException} will be thrown.
+     * API, otherwise an {@link NameNotFoundException} will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The package name which will be given access to application restrictions
-     * APIs. If {@code null} is given the current package will be cleared.
+     *            APIs. If {@code null} is given the current package will be cleared.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
+     * @throws NameNotFoundException if {@code packageName} is not found
      */
     public void setApplicationRestrictionsManagingPackage(@NonNull ComponentName admin,
-            @Nullable String packageName) {
+            @Nullable String packageName) throws NameNotFoundException {
         if (mService != null) {
             try {
-                mService.setApplicationRestrictionsManagingPackage(admin, packageName);
+                if (!mService.setApplicationRestrictionsManagingPackage(admin, packageName)) {
+                    throw new NameNotFoundException(packageName);
+                }
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3898,30 +4074,34 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return The package name allowed to manage application restrictions on the current user, or
-     * {@code null} if none is set.
+     *         {@code null} if none is set.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public String getApplicationRestrictionsManagingPackage(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getApplicationRestrictionsManagingPackage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
     }
 
     /**
-     * Returns {@code true} if the calling package has been granted permission via
-     * {@link #setApplicationRestrictionsManagingPackage} to manage application
-     * restrictions for the calling user.
+     * Called by any application to find out whether it has been granted permission via
+     * {@link #setApplicationRestrictionsManagingPackage} to manage application restrictions
+     * for the calling user.
+     *
+     * <p>This is done by comparing the calling Linux uid with the uid of the package specified by
+     * that method.
      */
     public boolean isCallerApplicationRestrictionsManagingPackage() {
         if (mService != null) {
             try {
                 return mService.isCallerApplicationRestrictionsManagingPackage();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3929,34 +4109,34 @@
 
     /**
      * Sets the application restrictions for a given target application running in the calling user.
-     *
-     * <p>The caller must be a profile or device owner on that user, or the package allowed to
-     * manage application restrictions via {@link #setApplicationRestrictionsManagingPackage};
-     * otherwise a security exception will be thrown.
-     *
-     * <p>The provided {@link Bundle} consists of key-value pairs, where the types of values may be:
+     * <p>
+     * The caller must be a profile or device owner on that user, or the package allowed to manage
+     * application restrictions via {@link #setApplicationRestrictionsManagingPackage}; otherwise a
+     * security exception will be thrown.
+     * <p>
+     * The provided {@link Bundle} consists of key-value pairs, where the types of values may be:
      * <ul>
      * <li>{@code boolean}
      * <li>{@code int}
      * <li>{@code String} or {@code String[]}
      * <li>From {@link android.os.Build.VERSION_CODES#M}, {@code Bundle} or {@code Bundle[]}
      * </ul>
-     *
-     * <p>If the restrictions are not available yet, but may be applied in the near future,
-     * the caller can notify the target application of that by adding
+     * <p>
+     * If the restrictions are not available yet, but may be applied in the near future, the caller
+     * can notify the target application of that by adding
      * {@link UserManager#KEY_RESTRICTIONS_PENDING} to the settings parameter.
-     *
-     * <p>The application restrictions are only made visible to the target application via
-     * {@link UserManager#getApplicationRestrictions(String)}, in addition to the profile or
-     * device owner, and the application restrictions managing package via
+     * <p>
+     * The application restrictions are only made visible to the target application via
+     * {@link UserManager#getApplicationRestrictions(String)}, in addition to the profile or device
+     * owner, and the application restrictions managing package via
      * {@link #getApplicationRestrictions}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
-     * {@code null} if called by the application restrictions managing package.
+     *            {@code null} if called by the application restrictions managing package.
      * @param packageName The name of the package to update restricted settings for.
      * @param settings A {@link Bundle} to be parsed by the receiving application, conveying a new
-     * set of active restrictions.
-     *
+     *            set of active restrictions.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      * @see #setApplicationRestrictionsManagingPackage
      * @see UserManager#KEY_RESTRICTIONS_PENDING
      */
@@ -3966,37 +4146,47 @@
             try {
                 mService.setApplicationRestrictions(admin, packageName, settings);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Sets a list of configuration features to enable for a TrustAgent component. This is meant
-     * to be used in conjunction with {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which disables all
-     * trust agents but those enabled by this function call. If flag
+     * Sets a list of configuration features to enable for a TrustAgent component. This is meant to
+     * be used in conjunction with {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which disables all trust
+     * agents but those enabled by this function call. If flag
      * {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is not set, then this call has no effect.
-     *
-     * <p>The calling device admin must have requested
-     * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES} to be able to call
-     * this method; if not, a security exception will be thrown.
+     * <p>
+     * The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES} to be able to call this method;
+     * if not, a security exception will be thrown.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set the configuration for
+     * the parent profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param target Component name of the agent to be enabled.
-     * @param configuration TrustAgent-specific feature bundle. If null for any admin, agent
-     * will be strictly disabled according to the state of the
-     *  {@link #KEYGUARD_DISABLE_TRUST_AGENTS} flag.
-     * <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
-     * then it's up to the TrustAgent itself to aggregate the values from all device admins.
-     * <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
+     * @param configuration TrustAgent-specific feature bundle. If null for any admin, agent will be
+     *            strictly disabled according to the state of the
+     *            {@link #KEYGUARD_DISABLE_TRUST_AGENTS} flag.
+     *            <p>
+     *            If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all
+     *            admins, then it's up to the TrustAgent itself to aggregate the values from all
+     *            device admins.
+     *            <p>
+     *            Consult documentation for the specific TrustAgent to determine legal options
+     *            parameters.
+     * @throws SecurityException if {@code admin} is not an active administrator or does not use
+     *             {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES}
      */
     public void setTrustAgentConfiguration(@NonNull ComponentName admin,
             @NonNull ComponentName target, PersistableBundle configuration) {
         if (mService != null) {
             try {
-                mService.setTrustAgentConfiguration(admin, target, configuration);
+                mService.setTrustAgentConfiguration(admin, target, configuration, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4005,6 +4195,10 @@
      * Gets configuration for the given trust agent based on aggregating all calls to
      * {@link #setTrustAgentConfiguration(ComponentName, ComponentName, PersistableBundle)} for
      * all device admins.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to retrieve the configuration set
+     * on the parent profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with. If null,
      * this function returns a list of configurations for all admins that declare
@@ -4025,30 +4219,32 @@
             @NonNull ComponentName agent, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getTrustAgentConfiguration(admin, agent, userHandle);
+                return mService.getTrustAgentConfiguration(admin, agent, userHandle,
+                        mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return new ArrayList<PersistableBundle>(); // empty list
     }
 
     /**
-     * Called by a profile owner of a managed profile to set whether caller-Id information from
-     * the managed profile will be shown in the parent profile, for incoming calls.
-     *
-     * <p>The calling device admin must be a profile owner. If it is not, a
-     * security exception will be thrown.
+     * Called by a profile owner of a managed profile to set whether caller-Id information from the
+     * managed profile will be shown in the parent profile, for incoming calls.
+     * <p>
+     * The calling device admin must be a profile owner. If it is not, a security exception will be
+     * thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled If true caller-Id information in the managed profile is not displayed.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setCrossProfileCallerIdDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
                 mService.setCrossProfileCallerIdDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4056,18 +4252,19 @@
     /**
      * Called by a profile owner of a managed profile to determine whether or not caller-Id
      * information has been disabled.
-     *
-     * <p>The calling device admin must be a profile owner. If it is not, a
-     * security exception will be thrown.
+     * <p>
+     * The calling device admin must be a profile owner. If it is not, a security exception will be
+     * thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean getCrossProfileCallerIdDisabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getCrossProfileCallerIdDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4084,21 +4281,22 @@
             try {
                 return mService.getCrossProfileCallerIdDisabledForUser(userHandle.getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Called by a profile owner of a managed profile to set whether contacts search from
-     * the managed profile will be shown in the parent profile, for incoming calls.
-     *
-     * <p>The calling device admin must be a profile owner. If it is not, a
-     * security exception will be thrown.
+     * Called by a profile owner of a managed profile to set whether contacts search from the
+     * managed profile will be shown in the parent profile, for incoming calls.
+     * <p>
+     * The calling device admin must be a profile owner. If it is not, a security exception will be
+     * thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled If true contacts search in the managed profile is not displayed.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setCrossProfileContactsSearchDisabled(@NonNull ComponentName admin,
             boolean disabled) {
@@ -4106,7 +4304,7 @@
             try {
                 mService.setCrossProfileContactsSearchDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4114,18 +4312,19 @@
     /**
      * Called by a profile owner of a managed profile to determine whether or not contacts search
      * has been disabled.
-     *
-     * <p>The calling device admin must be a profile owner. If it is not, a
-     * security exception will be thrown.
+     * <p>
+     * The calling device admin must be a profile owner. If it is not, a security exception will be
+     * thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean getCrossProfileContactsSearchDisabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getCrossProfileContactsSearchDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4144,7 +4343,7 @@
                 return mService
                         .getCrossProfileContactsSearchDisabledForUser(userHandle.getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4162,7 +4361,7 @@
                 mService.startManagedQuickContact(actualLookupKey, actualContactId,
                         isContactIdIgnored, directoryId, originalIntent);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4178,47 +4377,46 @@
     }
 
     /**
-     * Called by a profile owner of a managed profile to set whether bluetooth
-     * devices can access enterprise contacts.
+     * Called by a profile owner of a managed profile to set whether bluetooth devices can access
+     * enterprise contacts.
      * <p>
-     * The calling device admin must be a profile owner. If it is not, a
-     * security exception will be thrown.
+     * The calling device admin must be a profile owner. If it is not, a security exception will be
+     * thrown.
      * <p>
      * This API works on managed profile only.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param disabled If true, bluetooth devices cannot access enterprise
-     *            contacts.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param disabled If true, bluetooth devices cannot access enterprise contacts.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setBluetoothContactSharingDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
                 mService.setBluetoothContactSharingDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Called by a profile owner of a managed profile to determine whether or
-     * not Bluetooth devices cannot access enterprise contacts.
+     * Called by a profile owner of a managed profile to determine whether or not Bluetooth devices
+     * cannot access enterprise contacts.
      * <p>
-     * The calling device admin must be a profile owner. If it is not, a
-     * security exception will be thrown.
+     * The calling device admin must be a profile owner. If it is not, a security exception will be
+     * thrown.
      * <p>
      * This API works on managed profile only.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean getBluetoothContactSharingDisabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getBluetoothContactSharingDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
@@ -4238,7 +4436,7 @@
                 return mService.getBluetoothContactSharingDisabledForUser(userHandle
                         .getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
@@ -4246,21 +4444,22 @@
 
     /**
      * Called by the profile owner of a managed profile so that some intents sent in the managed
-     * profile can also be resolved in the parent, or vice versa.
-     * Only activity intents are supported.
+     * profile can also be resolved in the parent, or vice versa. Only activity intents are
+     * supported.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param filter The {@link IntentFilter} the intent has to match to be also resolved in the
-     * other profile
+     *            other profile
      * @param flags {@link DevicePolicyManager#FLAG_MANAGED_CAN_ACCESS_PARENT} and
-     * {@link DevicePolicyManager#FLAG_PARENT_CAN_ACCESS_MANAGED} are supported.
+     *            {@link DevicePolicyManager#FLAG_PARENT_CAN_ACCESS_MANAGED} are supported.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void addCrossProfileIntentFilter(@NonNull ComponentName admin, IntentFilter filter, int flags) {
         if (mService != null) {
             try {
                 mService.addCrossProfileIntentFilter(admin, filter, flags);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4269,38 +4468,37 @@
      * Called by a profile owner of a managed profile to remove the cross-profile intent filters
      * that go from the managed profile to the parent, or from the parent to the managed profile.
      * Only removes those that have been set by the profile owner.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void clearCrossProfileIntentFilters(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 mService.clearCrossProfileIntentFilters(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Called by a profile or device owner to set the permitted accessibility services. When
-     * set by a device owner or profile owner the restriction applies to all profiles of the
-     * user the device owner or profile owner is an admin for.
-     *
-     * By default the user can use any accessiblity service. When zero or more packages have
-     * been added, accessiblity services that are not in the list and not part of the system
-     * can not be enabled by the user.
-     *
-     * <p> Calling with a null value for the list disables the restriction so that all services
-     * can be used, calling with an empty list only allows the builtin system's services.
-     *
-     * <p> System accesibility services are always available to the user the list can't modify
-     * this.
+     * Called by a profile or device owner to set the permitted accessibility services. When set by
+     * a device owner or profile owner the restriction applies to all profiles of the user the
+     * device owner or profile owner is an admin for. By default the user can use any accessiblity
+     * service. When zero or more packages have been added, accessiblity services that are not in
+     * the list and not part of the system can not be enabled by the user.
+     * <p>
+     * Calling with a null value for the list disables the restriction so that all services can be
+     * used, calling with an empty list only allows the builtin system's services.
+     * <p>
+     * System accesibility services are always available to the user the list can't modify this.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageNames List of accessibility service package names.
-     *
-     * @return true if setting the restriction succeeded. It fail if there is
-     * one or more non-system accessibility services enabled, that are not in the list.
+     * @return true if setting the restriction succeeded. It fail if there is one or more non-system
+     *         accessibility services enabled, that are not in the list.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean setPermittedAccessibilityServices(@NonNull ComponentName admin,
             List<String> packageNames) {
@@ -4308,7 +4506,7 @@
             try {
                 return mService.setPermittedAccessibilityServices(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4316,19 +4514,20 @@
 
     /**
      * Returns the list of permitted accessibility services set by this device or profile owner.
-     *
-     * <p>An empty list means no accessibility services except system services are allowed.
-     * Null means all accessibility services are allowed.
+     * <p>
+     * An empty list means no accessibility services except system services are allowed. Null means
+     * all accessibility services are allowed.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return List of accessiblity service package names.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public List<String> getPermittedAccessibilityServices(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getPermittedAccessibilityServices(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4351,7 +4550,7 @@
                 return mService.isAccessibilityServicePermittedByAdmin(admin, packageName,
                         userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4375,41 +4574,37 @@
             try {
                 return mService.getPermittedAccessibilityServicesForUser(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
      }
 
     /**
-     * Called by a profile or device owner to set the permitted input methods services. When
-     * set by a device owner or profile owner the restriction applies to all profiles of the
-     * user the device owner or profile owner is an admin for.
-     *
-     * By default the user can use any input method. When zero or more packages have
-     * been added, input method that are not in the list and not part of the system
-     * can not be enabled by the user.
-     *
-     * This method will fail if it is called for a admin that is not for the foreground user
-     * or a profile of the foreground user.
-     *
-     * <p> Calling with a null value for the list disables the restriction so that all input methods
-     * can be used, calling with an empty list disables all but the system's own input methods.
-     *
-     * <p> System input methods are always available to the user this method can't modify this.
+     * Called by a profile or device owner to set the permitted input methods services. When set by
+     * a device owner or profile owner the restriction applies to all profiles of the user the
+     * device owner or profile owner is an admin for. By default the user can use any input method.
+     * When zero or more packages have been added, input method that are not in the list and not
+     * part of the system can not be enabled by the user. This method will fail if it is called for
+     * a admin that is not for the foreground user or a profile of the foreground user.
+     * <p>
+     * Calling with a null value for the list disables the restriction so that all input methods can
+     * be used, calling with an empty list disables all but the system's own input methods.
+     * <p>
+     * System input methods are always available to the user this method can't modify this.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageNames List of input method package names.
-     * @return true if setting the restriction succeeded. It will fail if there are
-     *     one or more non-system input methods currently enabled that are not in
-     *     the packageNames list.
+     * @return true if setting the restriction succeeded. It will fail if there are one or more
+     *         non-system input methods currently enabled that are not in the packageNames list.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean setPermittedInputMethods(@NonNull ComponentName admin, List<String> packageNames) {
         if (mService != null) {
             try {
                 return mService.setPermittedInputMethods(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4418,19 +4613,20 @@
 
     /**
      * Returns the list of permitted input methods set by this device or profile owner.
-     *
-     * <p>An empty list means no input methods except system input methods are allowed.
-     * Null means all input methods are allowed.
+     * <p>
+     * An empty list means no input methods except system input methods are allowed. Null means all
+     * input methods are allowed.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return List of input method package names.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public List<String> getPermittedInputMethods(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getPermittedInputMethods(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4452,7 +4648,7 @@
             try {
                 return mService.isInputMethodPermittedByAdmin(admin, packageName, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4475,7 +4671,7 @@
             try {
                 return mService.getPermittedInputMethodsForCurrentUser();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4495,7 +4691,7 @@
             try {
                 return mService.getKeepUninstalledPackages(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4510,6 +4706,7 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageNames List of package names to keep cached.
+     * @throws SecurityException if {@code admin} is not a device owner.
      * @hide
      */
     public void setKeepUninstalledPackages(@NonNull ComponentName admin,
@@ -4518,7 +4715,7 @@
             try {
                 mService.setKeepUninstalledPackages(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4536,14 +4733,10 @@
      *         user could not be created.
      *
      * @deprecated From {@link android.os.Build.VERSION_CODES#M}
+     * @removed From {@link android.os.Build.VERSION_CODES#N}
      */
     @Deprecated
     public UserHandle createUser(@NonNull ComponentName admin, String name) {
-        try {
-            return mService.createUser(admin, name);
-        } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-        }
         return null;
     }
 
@@ -4573,16 +4766,11 @@
      *         user could not be created.
      *
      * @deprecated From {@link android.os.Build.VERSION_CODES#M}
+     * @removed From {@link android.os.Build.VERSION_CODES#N}
      */
     @Deprecated
     public UserHandle createAndInitializeUser(@NonNull ComponentName admin, String name,
             String ownerName, @NonNull ComponentName profileOwnerComponent, Bundle adminExtras) {
-        try {
-            return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
-                    adminExtras);
-        } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-        }
         return null;
     }
 
@@ -4604,27 +4792,27 @@
      * persisted as user handles are recycled as users are removed and created. If you need to
      * persist an identifier for this user, use {@link UserManager#getSerialNumberForUser}. The new
      * user will not be started in the background.
-     *
-     * <p>admin is the {@link DeviceAdminReceiver} which is the device owner. profileOwner is also
-     * a DeviceAdminReceiver in the same package as admin, and will become the profile owner and
-     * will be registered as an active admin on the new user. The profile owner package will be
-     * installed on the new user.
-     *
-     * <p>If the adminExtras are not null, they will be stored on the device until the user is
-     * started for the first time. Then the extras will be passed to the admin when
-     * onEnable is called.
+     * <p>
+     * admin is the {@link DeviceAdminReceiver} which is the device owner. profileOwner is also a
+     * DeviceAdminReceiver in the same package as admin, and will become the profile owner and will
+     * be registered as an active admin on the new user. The profile owner package will be installed
+     * on the new user.
+     * <p>
+     * If the adminExtras are not null, they will be stored on the device until the user is started
+     * for the first time. Then the extras will be passed to the admin when onEnable is called.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param name The user's name.
      * @param profileOwner Which {@link DeviceAdminReceiver} will be profile owner. Has to be in the
-     *      same package as admin, otherwise no user is created and an IllegalArgumentException is
-     *      thrown.
+     *            same package as admin, otherwise no user is created and an
+     *            IllegalArgumentException is thrown.
      * @param adminExtras Extras that will be passed to onEnable of the admin receiver on the new
-     *      user.
+     *            user.
      * @param flags {@link #SKIP_SETUP_WIZARD} is supported.
      * @see UserHandle
      * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the
      *         user could not be created.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
     public UserHandle createAndManageUser(@NonNull ComponentName admin, @NonNull String name,
             @NonNull ComponentName profileOwner, @Nullable PersistableBundle adminExtras,
@@ -4632,25 +4820,24 @@
         try {
             return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
-     * Called by a device owner to remove a user and all associated data. The primary user can
-     * not be removed.
+     * Called by a device owner to remove a user and all associated data. The primary user can not
+     * be removed.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param userHandle the user to remove.
      * @return {@code true} if the user was removed, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
     public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) {
         try {
             return mService.removeUser(admin, userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -4660,33 +4847,32 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param userHandle the user to switch to; null will switch to primary.
      * @return {@code true} if the switch was successful, {@code false} otherwise.
-     *
+     * @throws SecurityException if {@code admin} is not a device owner.
      * @see Intent#ACTION_USER_FOREGROUND
      */
     public boolean switchUser(@NonNull ComponentName admin, @Nullable UserHandle userHandle) {
         try {
             return mService.switchUser(admin, userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
      * Retrieves the application restrictions for a given target application running in the calling
      * user.
-     *
-     * <p>The caller must be a profile or device owner on that user, or the package allowed to
-     * manage application restrictions via {@link #setApplicationRestrictionsManagingPackage};
-     * otherwise a security exception will be thrown.
+     * <p>
+     * The caller must be a profile or device owner on that user, or the package allowed to manage
+     * application restrictions via {@link #setApplicationRestrictionsManagingPackage}; otherwise a
+     * security exception will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
-     * {@code null} if called by the application restrictions managing package.
+     *            {@code null} if called by the application restrictions managing package.
      * @param packageName The name of the package to fetch restricted settings of.
      * @return {@link Bundle} of settings corresponding to what was set last time
-     * {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty {@link Bundle}
-     * if no restrictions have been set.
-     *
+     *         {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty
+     *         {@link Bundle} if no restrictions have been set.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      * @see {@link #setApplicationRestrictionsManagingPackage}
      */
     public Bundle getApplicationRestrictions(@Nullable ComponentName admin, String packageName) {
@@ -4694,7 +4880,7 @@
             try {
                 return mService.getApplicationRestrictions(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4703,20 +4889,20 @@
     /**
      * Called by a profile or device owner to set a user restriction specified by the key.
      * <p>
-     * The calling device admin must be a profile or device owner; if it is not,
-     * a security exception will be thrown.
+     * The calling device admin must be a profile or device owner; if it is not, a security
+     * exception will be thrown.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param key The key of the restriction. See the constants in
-     *            {@link android.os.UserManager} for the list of keys.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param key The key of the restriction. See the constants in {@link android.os.UserManager}
+     *            for the list of keys.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void addUserRestriction(@NonNull ComponentName admin, String key) {
         if (mService != null) {
             try {
                 mService.setUserRestriction(admin, key, true);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4724,20 +4910,20 @@
     /**
      * Called by a profile or device owner to clear a user restriction specified by the key.
      * <p>
-     * The calling device admin must be a profile or device owner; if it is not,
-     * a security exception will be thrown.
+     * The calling device admin must be a profile or device owner; if it is not, a security
+     * exception will be thrown.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
-     * @param key The key of the restriction. See the constants in
-     *            {@link android.os.UserManager} for the list of keys.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param key The key of the restriction. See the constants in {@link android.os.UserManager}
+     *            for the list of keys.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void clearUserRestriction(@NonNull ComponentName admin, String key) {
         if (mService != null) {
             try {
                 mService.setUserRestriction(admin, key, false);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4747,38 +4933,54 @@
      * {@link #addUserRestriction(ComponentName, String)}.
      * <p>
      * The target user may have more restrictions set by the system or other device owner / profile
-     * owner.  To get all the user restrictions currently set, use
+     * owner. To get all the user restrictions currently set, use
      * {@link UserManager#getUserRestrictions()}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @throws SecurityException if the {@code admin} is not an active admin.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public Bundle getUserRestrictions(@NonNull ComponentName admin) {
-        return getUserRestrictions(admin, myUserId());
-    }
-
-    /** @hide per-user version */
-    public Bundle getUserRestrictions(@NonNull ComponentName admin, int userHandle) {
         Bundle ret = null;
         if (mService != null) {
             try {
-                ret = mService.getUserRestrictions(admin, userHandle);
+                ret = mService.getUserRestrictions(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return ret == null ? new Bundle() : ret;
     }
 
     /**
-     * Called by profile or device owners to hide or unhide packages. When a package is hidden it
-     * is unavailable for use, but the data and actual package file remain.
+     * Called by the system to get the user restrictions for a user.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param userHandle user id the admin is running as.
+     *
+     * @hide
+     */
+    public Bundle getUserRestrictionsForUser(@NonNull ComponentName admin, int userHandle) {
+        Bundle ret = null;
+        if (mService != null) {
+            try {
+                ret = mService.getUserRestrictionsForUser(admin, userHandle);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return ret == null ? new Bundle() : ret;
+    }
+
+    /**
+     * Called by profile or device owners to hide or unhide packages. When a package is hidden it is
+     * unavailable for use, but the data and actual package file remain.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package to hide or unhide.
      * @param hidden {@code true} if the package should be hidden, {@code false} if it should be
-     *                 unhidden.
+     *            unhidden.
      * @return boolean Whether the hidden setting of the package was successfully updated.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName,
             boolean hidden) {
@@ -4786,7 +4988,7 @@
             try {
                 return mService.setApplicationHidden(admin, packageName, hidden);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4798,13 +5000,14 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package to retrieve the hidden status of.
      * @return boolean {@code true} if the package is hidden, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.isApplicationHidden(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4816,32 +5019,34 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The package to be re-enabled in the calling profile.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void enableSystemApp(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 mService.enableSystemApp(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Called by profile or device owners to re-enable system apps by intent that were disabled
-     * by default when the user was initialized.
+     * Called by profile or device owners to re-enable system apps by intent that were disabled by
+     * default when the user was initialized.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param intent An intent matching the app(s) to be installed. All apps that resolve for this
-     *               intent will be re-enabled in the calling profile.
+     *            intent will be re-enabled in the calling profile.
      * @return int The number of activities that matched the intent and were installed.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public int enableSystemApp(@NonNull ComponentName admin, Intent intent) {
         if (mService != null) {
             try {
                 return mService.enableSystemAppWithIntent(admin, intent);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -4850,21 +5055,22 @@
     /**
      * Called by a device owner or profile owner to disable account management for a specific type
      * of account.
-     *
-     * <p>The calling device admin must be a device owner or 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.
-     *
-     * <p>From {@link android.os.Build.VERSION_CODES#N} the profile or device owner can still use
+     * <p>
+     * The calling device admin must be a device owner or 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.
+     * <p>
+     * From {@link android.os.Build.VERSION_CODES#N} the profile or device owner can still use
      * {@link android.accounts.AccountManager} APIs to add or remove accounts when account
      * management for a specific type is disabled.
      *
      * @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).
+     *            enabled (false).
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setAccountManagementDisabled(@NonNull ComponentName admin, String accountType,
             boolean disabled) {
@@ -4872,7 +5078,7 @@
             try {
                 mService.setAccountManagementDisabled(admin, accountType, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4900,7 +5106,7 @@
             try {
                 return mService.getAccountTypesWithManagementDisabledAsUser(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -4909,17 +5115,15 @@
 
     /**
      * Sets which packages may enter lock task mode.
+     * <p>
+     * Any packages that shares uid with an allowed package will also be allowed to activate lock
+     * task. From {@link android.os.Build.VERSION_CODES#M} removing packages from the lock task
+     * package list results in locked tasks belonging to those packages to be finished. This
+     * function can only be called by the device owner.
      *
-     * <p>Any packages that shares uid with an allowed package will also be allowed
-     * to activate lock task.
-     *
-     * From {@link android.os.Build.VERSION_CODES#M} removing packages from the lock task
-     * package list results in locked tasks belonging to those packages to be finished.
-     *
-     * This function can only be called by the device owner.
      * @param packages The list of packages allowed to enter lock task mode
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     *
+     * @throws SecurityException if {@code admin} is not a device owner.
      * @see Activity#startLockTask()
      * @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
      * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
@@ -4931,7 +5135,7 @@
             try {
                 mService.setLockTaskPackages(admin, packages);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4947,7 +5151,7 @@
             try {
                 return mService.getLockTaskPackages(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4963,7 +5167,7 @@
             try {
                 return mService.isLockTaskPermitted(pkg);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4972,7 +5176,8 @@
     /**
      * Called by device owners to update {@link Settings.Global} settings. Validation that the value
      * of the setting is in the correct form for the setting type should be performed by the caller.
-     * <p>The settings that can be updated with this method are:
+     * <p>
+     * The settings that can be updated with this method are:
      * <ul>
      * <li>{@link Settings.Global#ADB_ENABLED}</li>
      * <li>{@link Settings.Global#AUTO_TIME}</li>
@@ -4980,37 +5185,37 @@
      * <li>{@link Settings.Global#DATA_ROAMING}</li>
      * <li>{@link Settings.Global#USB_MASS_STORAGE_ENABLED}</li>
      * <li>{@link Settings.Global#WIFI_SLEEP_POLICY}</li>
-     * <li>{@link Settings.Global#STAY_ON_WHILE_PLUGGED_IN}
-     *   This setting is only available from {@link android.os.Build.VERSION_CODES#M} onwards
-     *   and can only be set if {@link #setMaximumTimeToLock} is not used to set a timeout.</li>
-     * <li>{@link Settings.Global#WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN}</li>
-     *   This setting is only available from {@link android.os.Build.VERSION_CODES#M} onwards.
-     *   </li>
+     * <li>{@link Settings.Global#STAY_ON_WHILE_PLUGGED_IN} This setting is only available from
+     * {@link android.os.Build.VERSION_CODES#M} onwards and can only be set if
+     * {@link #setMaximumTimeToLock} is not used to set a timeout.</li>
+     * <li>{@link Settings.Global#WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN}</li> This setting is only
+     * available from {@link android.os.Build.VERSION_CODES#M} onwards.</li>
      * </ul>
-     * <p>Changing the following settings has no effect as of
-     * {@link android.os.Build.VERSION_CODES#M}:
+     * <p>
+     * Changing the following settings has no effect as of {@link android.os.Build.VERSION_CODES#M}:
      * <ul>
-     * <li>{@link Settings.Global#BLUETOOTH_ON}.
-     *   Use {@link android.bluetooth.BluetoothAdapter#enable()} and
-     *   {@link android.bluetooth.BluetoothAdapter#disable()} instead.</li>
+     * <li>{@link Settings.Global#BLUETOOTH_ON}. Use
+     * {@link android.bluetooth.BluetoothAdapter#enable()} and
+     * {@link android.bluetooth.BluetoothAdapter#disable()} instead.</li>
      * <li>{@link Settings.Global#DEVELOPMENT_SETTINGS_ENABLED}</li>
-     * <li>{@link Settings.Global#MODE_RINGER}.
-     *   Use {@link android.media.AudioManager#setRingerMode(int)} instead.</li>
+     * <li>{@link Settings.Global#MODE_RINGER}. Use
+     * {@link android.media.AudioManager#setRingerMode(int)} instead.</li>
      * <li>{@link Settings.Global#NETWORK_PREFERENCE}</li>
-     * <li>{@link Settings.Global#WIFI_ON}.
-     *   Use {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} instead.</li>
+     * <li>{@link Settings.Global#WIFI_ON}. Use
+     * {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} instead.</li>
      * </ul>
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param setting The name of the setting to update.
      * @param value The value to update the setting to.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
     public void setGlobalSetting(@NonNull ComponentName admin, String setting, String value) {
         if (mService != null) {
             try {
                 mService.setGlobalSetting(admin, setting, value);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5019,39 +5224,45 @@
      * Called by profile or device owners to update {@link Settings.Secure} settings. Validation
      * that the value of the setting is in the correct form for the setting type should be performed
      * by the caller.
-     * <p>The settings that can be updated by a profile or device owner with this method are:
+     * <p>
+     * The settings that can be updated by a profile or device owner with this method are:
      * <ul>
      * <li>{@link Settings.Secure#DEFAULT_INPUT_METHOD}</li>
      * <li>{@link Settings.Secure#INSTALL_NON_MARKET_APPS}</li>
      * <li>{@link Settings.Secure#SKIP_FIRST_USE_HINTS}</li>
      * </ul>
-     * <p>A device owner can additionally update the following settings:
+     * <p>
+     * A device owner can additionally update the following settings:
      * <ul>
      * <li>{@link Settings.Secure#LOCATION_MODE}</li>
      * </ul>
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param setting The name of the setting to update.
      * @param value The value to update the setting to.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setSecureSetting(@NonNull ComponentName admin, String setting, String value) {
         if (mService != null) {
             try {
                 mService.setSecureSetting(admin, setting, value);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
     /**
-     * Designates a specific service component as the provider for
-     * making permission requests of a local or remote administrator of the user.
+     * Designates a specific service component as the provider for making permission requests of a
+     * local or remote administrator of the user.
      * <p/>
      * Only a profile owner can designate the restrictions provider.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param provider The component name of the service that implements
-     * {@link RestrictionsReceiver}. If this param is null,
-     * it removes the restrictions provider previously assigned.
+     *            {@link RestrictionsReceiver}. If this param is null, it removes the restrictions
+     *            provider previously assigned.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setRestrictionsProvider(@NonNull ComponentName admin,
             @Nullable ComponentName provider) {
@@ -5059,7 +5270,7 @@
             try {
                 mService.setRestrictionsProvider(admin, provider);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5069,13 +5280,14 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param on {@code true} to mute master volume, {@code false} to turn mute off.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setMasterVolumeMuted(@NonNull ComponentName admin, boolean on) {
         if (mService != null) {
             try {
                 mService.setMasterVolumeMuted(admin, on);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5085,25 +5297,26 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return {@code true} if master volume is muted, {@code false} if it's not.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean isMasterVolumeMuted(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.isMasterVolumeMuted(admin);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Called by profile or device owners to change whether a user can uninstall
-     * a package.
+     * Called by profile or device owners to change whether a user can uninstall a package.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName package to change.
      * @param uninstallBlocked true if the user shouldn't be able to uninstall the package.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setUninstallBlocked(@NonNull ComponentName admin, String packageName,
             boolean uninstallBlocked) {
@@ -5111,7 +5324,7 @@
             try {
                 mService.setUninstallBlocked(admin, packageName, uninstallBlocked);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5121,40 +5334,40 @@
      * Requires the caller to be the profile owner if checking a specific admin's policy.
      * <p>
      * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the
-     * behavior of this API is changed such that passing {@code null} as the {@code admin}
-     * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing
-     * {@code null} will cause a NullPointerException to be raised.
+     * behavior of this API is changed such that passing {@code null} as the {@code admin} parameter
+     * will return if any admin has blocked the uninstallation. Before L MR1, passing {@code null}
+     * will cause a NullPointerException to be raised.
      *
      * @param admin The name of the admin component whose blocking policy will be checked, or
-     *              {@code null} to check whether any admin has blocked the uninstallation.
+     *            {@code null} to check whether any admin has blocked the uninstallation.
      * @param packageName package to check.
      * @return true if uninstallation is blocked.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.isUninstallBlocked(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
     }
 
     /**
-     * Called by the profile owner of a managed profile to enable widget providers from a
-     * given package to be available in the parent profile. As a result the user will be able to
-     * add widgets from the white-listed package running under the profile to a widget
-     * host which runs under the parent profile, for example the home screen. Note that
-     * a package may have zero or more provider components, where each component
-     * provides a different widget type.
+     * Called by the profile owner of a managed profile to enable widget providers from a given
+     * package to be available in the parent profile. As a result the user will be able to add
+     * widgets from the white-listed package running under the profile to a widget host which runs
+     * under the parent profile, for example the home screen. Note that a package may have zero or
+     * more provider components, where each component provides a different widget type.
      * <p>
      * <strong>Note:</strong> By default no widget provider package is white-listed.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The package from which widget providers are white-listed.
      * @return Whether the package was added.
-     *
+     * @throws SecurityException if {@code admin} is not a profile owner.
      * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #getCrossProfileWidgetProviders(android.content.ComponentName)
      */
@@ -5163,7 +5376,7 @@
             try {
                 return mService.addCrossProfileWidgetProvider(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -5171,17 +5384,16 @@
 
     /**
      * Called by the profile owner of a managed profile to disable widget providers from a given
-     * package to be available in the parent profile. For this method to take effect the
-     * package should have been added via {@link #addCrossProfileWidgetProvider(
-     * android.content.ComponentName, String)}.
+     * package to be available in the parent profile. For this method to take effect the package
+     * should have been added via
+     * {@link #addCrossProfileWidgetProvider( android.content.ComponentName, String)}.
      * <p>
      * <strong>Note:</strong> By default no widget provider package is white-listed.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param packageName The package from which widget providers are no longer
-     *     white-listed.
+     * @param packageName The package from which widget providers are no longer white-listed.
      * @return Whether the package was removed.
-     *
+     * @throws SecurityException if {@code admin} is not a profile owner.
      * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #getCrossProfileWidgetProviders(android.content.ComponentName)
      */
@@ -5191,7 +5403,7 @@
             try {
                 return mService.removeCrossProfileWidgetProvider(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -5203,9 +5415,9 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return The white-listed package list.
-     *
      * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String)
+     * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public List<String> getCrossProfileWidgetProviders(@NonNull ComponentName admin) {
         if (mService != null) {
@@ -5215,7 +5427,7 @@
                     return providers;
                 }
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return Collections.emptyList();
@@ -5226,12 +5438,13 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param icon the bitmap to set as the photo.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void setUserIcon(@NonNull ComponentName admin, Bitmap icon) {
         try {
             mService.setUserIcon(admin, icon);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5240,10 +5453,10 @@
      * {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with. All
-     *              components in the device owner package can set system update policies and the
-     *              most recent policy takes
-     * effect.
+     *            components in the device owner package can set system update policies and the most
+     *            recent policy takes effect.
      * @param policy the new policy, or {@code null} to clear the current policy.
+     * @throws SecurityException if {@code admin} is not a device owner.
      * @see SystemUpdatePolicy
      */
     public void setSystemUpdatePolicy(@NonNull ComponentName admin, SystemUpdatePolicy policy) {
@@ -5251,7 +5464,7 @@
             try {
                 mService.setSystemUpdatePolicy(admin, policy);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5266,7 +5479,7 @@
             try {
                 return mService.getSystemUpdatePolicy();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5274,44 +5487,41 @@
 
     /**
      * Called by a device owner to disable the keyguard altogether.
-     *
-     * <p>Setting the keyguard to disabled has the same effect as choosing "None" as the screen
-     * lock type. However, this call has no effect if a password, pin or pattern is currently set.
-     * If a password, pin or pattern is set after the keyguard was disabled, the keyguard stops
-     * being disabled.
+     * <p>
+     * Setting the keyguard to disabled has the same effect as choosing "None" as the screen lock
+     * type. However, this call has no effect if a password, pin or pattern is currently set. If a
+     * password, pin or pattern is set after the keyguard was disabled, the keyguard stops being
+     * disabled.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled {@code true} disables the keyguard, {@code false} reenables it.
-     *
      * @return {@code false} if attempting to disable the keyguard while a lock password was in
-     * place. {@code true} otherwise.
+     *         place. {@code true} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
     public boolean setKeyguardDisabled(@NonNull ComponentName admin, boolean disabled) {
         try {
             return mService.setKeyguardDisabled(admin, disabled);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
      * Called by device owner to disable the status bar. Disabling the status bar blocks
-     * notifications, quick settings and other screen overlays that allow escaping from
-     * a single use device.
+     * notifications, quick settings and other screen overlays that allow escaping from a single use
+     * device.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled {@code true} disables the status bar, {@code false} reenables it.
-     *
-     * @return {@code false} if attempting to disable the status bar failed.
-     * {@code true} otherwise.
+     * @return {@code false} if attempting to disable the status bar failed. {@code true} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
     public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) {
         try {
             return mService.setStatusBarDisabled(admin, disabled);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5330,33 +5540,33 @@
             try {
                 mService.notifyPendingSystemUpdate(updateReceivedTime);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
 
     /**
      * Called by profile or device owners to set the default response for future runtime permission
-     * requests by applications. The policy can allow for normal operation which prompts the
-     * user to grant a permission, or can allow automatic granting or denying of runtime
-     * permission requests by an application. This also applies to new permissions declared by app
-     * updates. When a permission is denied or granted this way, the effect is equivalent to setting
-     * the permission grant state via {@link #setPermissionGrantState}.
-     *
-     * <p/>As this policy only acts on runtime permission requests, it only applies to applications
+     * requests by applications. The policy can allow for normal operation which prompts the user to
+     * grant a permission, or can allow automatic granting or denying of runtime permission requests
+     * by an application. This also applies to new permissions declared by app updates. When a
+     * permission is denied or granted this way, the effect is equivalent to setting the permission
+     * grant state via {@link #setPermissionGrantState}.
+     * <p/>
+     * As this policy only acts on runtime permission requests, it only applies to applications
      * built with a {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#M} or later.
      *
      * @param admin Which profile or device owner this request is associated with.
      * @param policy One of the policy constants {@link #PERMISSION_POLICY_PROMPT},
-     * {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}.
-     *
+     *            {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      * @see #setPermissionGrantState
      */
     public void setPermissionPolicy(@NonNull ComponentName admin, int policy) {
         try {
             mService.setPermissionPolicy(admin, policy);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5370,34 +5580,33 @@
         try {
             return mService.getPermissionPolicy(admin);
         } catch (RemoteException re) {
-            return PERMISSION_POLICY_PROMPT;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Sets the grant state of a runtime permission for a specific application. The state
-     * can be {@link #PERMISSION_GRANT_STATE_DEFAULT default} in which a user can manage it
-     * through the UI, {@link #PERMISSION_GRANT_STATE_DENIED denied}, in which the permission
-     * is denied and the user cannot manage it through the UI, and {@link
-     * #PERMISSION_GRANT_STATE_GRANTED granted} in which the permission is granted and the
-     * user cannot manage it through the UI. This might affect all permissions in a
-     * group that the runtime permission belongs to. This method can only be called
+     * Sets the grant state of a runtime permission for a specific application. The state can be
+     * {@link #PERMISSION_GRANT_STATE_DEFAULT default} in which a user can manage it through the UI,
+     * {@link #PERMISSION_GRANT_STATE_DENIED denied}, in which the permission is denied and the user
+     * cannot manage it through the UI, and {@link #PERMISSION_GRANT_STATE_GRANTED granted} in which
+     * the permission is granted and the user cannot manage it through the UI. This might affect all
+     * permissions in a group that the runtime permission belongs to. This method can only be called
      * by a profile or device owner.
-     *
-     * <p/>Setting the grant state to {@link #PERMISSION_GRANT_STATE_DEFAULT default} does not
-     * revoke the permission. It retains the previous grant, if any.
-     *
-     * <p/>Permissions can be granted or revoked only for applications built with a
+     * <p/>
+     * Setting the grant state to {@link #PERMISSION_GRANT_STATE_DEFAULT default} does not revoke
+     * the permission. It retains the previous grant, if any.
+     * <p/>
+     * Permissions can be granted or revoked only for applications built with a
      * {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#M} or later.
      *
      * @param admin Which profile or device owner this request is associated with.
      * @param packageName The application to grant or revoke a permission to.
      * @param permission The permission to grant or revoke.
-     * @param grantState The permission grant state which is one of {@link
-     *         #PERMISSION_GRANT_STATE_DENIED}, {@link #PERMISSION_GRANT_STATE_DEFAULT},
-     *         {@link #PERMISSION_GRANT_STATE_GRANTED},
+     * @param grantState The permission grant state which is one of
+     *            {@link #PERMISSION_GRANT_STATE_DENIED}, {@link #PERMISSION_GRANT_STATE_DEFAULT},
+     *            {@link #PERMISSION_GRANT_STATE_GRANTED},
      * @return whether the permission was successfully granted or revoked.
-     *
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      * @see #PERMISSION_GRANT_STATE_DENIED
      * @see #PERMISSION_GRANT_STATE_DEFAULT
      * @see #PERMISSION_GRANT_STATE_GRANTED
@@ -5407,8 +5616,7 @@
         try {
             return mService.setPermissionGrantState(admin, packageName, permission, grantState);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5419,13 +5627,15 @@
      * @param packageName The application to check the grant state for.
      * @param permission The permission to check for.
      * @return the current grant state specified by device policy. If the profile or device owner
-     * has not set a grant state, the return value is {@link #PERMISSION_GRANT_STATE_DEFAULT}.
-     * This does not indicate whether or not the permission is currently granted for the package.
-     *
-     * <p/>If a grant state was set by the profile or device owner, then the return value will
-     * be one of {@link #PERMISSION_GRANT_STATE_DENIED} or {@link #PERMISSION_GRANT_STATE_GRANTED},
-     * which indicates if the permission is currently denied or granted.
-     *
+     *         has not set a grant state, the return value is
+     *         {@link #PERMISSION_GRANT_STATE_DEFAULT}. This does not indicate whether or not the
+     *         permission is currently granted for the package.
+     *         <p/>
+     *         If a grant state was set by the profile or device owner, then the return value will
+     *         be one of {@link #PERMISSION_GRANT_STATE_DENIED} or
+     *         {@link #PERMISSION_GRANT_STATE_GRANTED}, which indicates if the permission is
+     *         currently denied or granted.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
      * @see #setPermissionGrantState(ComponentName, String, String, int)
      * @see PackageManager#checkPermission(String, String)
      */
@@ -5434,8 +5644,7 @@
         try {
             return mService.getPermissionGrantState(admin, packageName, permission);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return PERMISSION_GRANT_STATE_DEFAULT;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5443,9 +5652,6 @@
      * Returns if provisioning a managed profile or device is possible or not.
      * @param action One of {@link #ACTION_PROVISION_MANAGED_DEVICE},
      * {@link #ACTION_PROVISION_MANAGED_PROFILE}.
-     * Note that even if this method returns true, there is a slight possibility that the
-     * provisioning will not be allowed when it is actually initiated because some event has
-     * happened in between.
      * @return if provisioning a managed profile or device is possible or not.
      * @throws IllegalArgumentException if the supplied action is not valid.
      */
@@ -5453,16 +5659,14 @@
         try {
             return mService.isProvisioningAllowed(action);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * @hide
      * Return if this user is a managed profile of another user. An admin can become the profile
      * owner of a managed profile with {@link #ACTION_PROVISION_MANAGED_PROFILE} and of a managed
-     * user with {@link #ACTION_PROVISION_MANAGED_USER}.
+     * user with {@link #createAndManageUser}
      * @param admin Which profile owner this request is associated with.
      * @return if this user is a managed profile of another user.
      */
@@ -5470,8 +5674,7 @@
         try {
             return mService.isManagedProfile(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5486,58 +5689,60 @@
         try {
             return mService.isSystemOnlyUser(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
      * Called by device owner to get the MAC address of the Wi-Fi device.
      *
-     * @return the MAC address of the Wi-Fi device, or null when the information is not
-     * available. (For example, Wi-Fi hasn't been enabled, or the device doesn't support Wi-Fi.)
-     *
-     * <p>The address will be in the {@code XX:XX:XX:XX:XX:XX} format.
+     * @param admin Which device owner this request is associated with.
+     * @return the MAC address of the Wi-Fi device, or null when the information is not available.
+     *         (For example, Wi-Fi hasn't been enabled, or the device doesn't support Wi-Fi.)
+     *         <p>
+     *         The address will be in the {@code XX:XX:XX:XX:XX:XX} format.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public String getWifiMacAddress() {
+    public String getWifiMacAddress(@NonNull ComponentName admin) {
         try {
-            return mService.getWifiMacAddress();
+            return mService.getWifiMacAddress(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Called by device owner to reboot the device.
+     * Called by device owner to reboot the device. If there is an ongoing call on the device,
+     * throws an {@link IllegalStateException}.
+     * @param admin Which device owner the request is associated with.
+     * @throws IllegalStateException if device has an ongoing call.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     * @see TelephonyManager#CALL_STATE_IDLE
      */
     public void reboot(@NonNull ComponentName admin) {
         try {
             mService.reboot(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Called by a device admin to set the short support message. This will
-     * be displayed to the user in settings screens where funtionality has
-     * been disabled by the admin.
-     *
-     * The message should be limited to a short statement such as
-     * "This setting is disabled by your administrator. Contact someone@example.com
-     *  for support."
-     * If the message is longer than 200 characters it may be truncated.
-     *
-     * <p>If the short support message needs to be localized, it is the responsibility of the
+     * Called by a device admin to set the short support message. This will be displayed to the user
+     * in settings screens where funtionality has been disabled by the admin. The message should be
+     * limited to a short statement such as "This setting is disabled by your administrator. Contact
+     * someone@example.com for support." If the message is longer than 200 characters it may be
+     * truncated.
+     * <p>
+     * If the short support message needs to be localized, it is the responsibility of the
      * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
      * and set a new version of this string accordingly.
      *
      * @see #setLongSupportMessage
-     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param message Short message to be displayed to the user in settings or null to
-     *        clear the existing message.
+     * @param message Short message to be displayed to the user in settings or null to clear the
+     *            existing message.
+     * @throws SecurityException if {@code admin} is not an active administrator.
      */
     public void setShortSupportMessage(@NonNull ComponentName admin,
             @Nullable String message) {
@@ -5545,7 +5750,7 @@
             try {
                 mService.setShortSupportMessage(admin, message);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5554,33 +5759,34 @@
      * Called by a device admin to get the short support message.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
-     *         or null if no message has been set.
+     * @return The message set by {@link #setShortSupportMessage(ComponentName, String)} or null if
+     *         no message has been set.
+     * @throws SecurityException if {@code admin} is not an active administrator.
      */
     public String getShortSupportMessage(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getShortSupportMessage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
     }
 
     /**
-     * Called by a device admin to set the long support message. This will
-     * be displayed to the user in the device administators settings screen.
-     *
-     * <p>If the long support message needs to be localized, it is the responsibility of the
+     * Called by a device admin to set the long support message. This will be displayed to the user
+     * in the device administators settings screen.
+     * <p>
+     * If the long support message needs to be localized, it is the responsibility of the
      * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
      * and set a new version of this string accordingly.
      *
      * @see #setShortSupportMessage
-     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param message Long message to be displayed to the user in settings or null to
-     *        clear the existing message.
+     * @param message Long message to be displayed to the user in settings or null to clear the
+     *            existing message.
+     * @throws SecurityException if {@code admin} is not an active administrator.
      */
     public void setLongSupportMessage(@NonNull ComponentName admin,
             @Nullable String message) {
@@ -5588,7 +5794,7 @@
             try {
                 mService.setLongSupportMessage(admin, message);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5597,15 +5803,16 @@
      * Called by a device admin to get the long support message.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
-     *         or null if no message has been set.
+     * @return The message set by {@link #setLongSupportMessage(ComponentName, String)} or null if
+     *         no message has been set.
+     * @throws SecurityException if {@code admin} is not an active administrator.
      */
     public String getLongSupportMessage(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getLongSupportMessage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5625,7 +5832,7 @@
             try {
                 return mService.getShortSupportMessageForUser(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5646,7 +5853,7 @@
             try {
                 return mService.getLongSupportMessageForUser(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5656,9 +5863,45 @@
      * Called by the profile owner of a managed profile to obtain a {@link DevicePolicyManager}
      * whose calls act on the parent profile.
      *
-     * <p> Note only some methods will work on the parent Manager.
+     * <p>The following methods are supported for the parent instance, all other methods will
+     * throw a SecurityException when called on the parent instance:
+     * <ul>
+     * <li>{@link #getPasswordQuality}</li>
+     * <li>{@link #setPasswordQuality}</li>
+     * <li>{@link #getPasswordMinimumLength}</li>
+     * <li>{@link #setPasswordMinimumLength}</li>
+     * <li>{@link #getPasswordMinimumUpperCase}</li>
+     * <li>{@link #setPasswordMinimumUpperCase}</li>
+     * <li>{@link #getPasswordMinimumLowerCase}</li>
+     * <li>{@link #setPasswordMinimumLowerCase}</li>
+     * <li>{@link #getPasswordMinimumLetters}</li>
+     * <li>{@link #setPasswordMinimumLetters}</li>
+     * <li>{@link #getPasswordMinimumNumeric}</li>
+     * <li>{@link #setPasswordMinimumNumeric}</li>
+     * <li>{@link #getPasswordMinimumSymbols}</li>
+     * <li>{@link #setPasswordMinimumSymbols}</li>
+     * <li>{@link #getPasswordMinimumNonLetter}</li>
+     * <li>{@link #setPasswordMinimumNonLetter}</li>
+     * <li>{@link #getPasswordHistoryLength}</li>
+     * <li>{@link #setPasswordHistoryLength}</li>
+     * <li>{@link #getPasswordExpirationTimeout}</li>
+     * <li>{@link #setPasswordExpirationTimeout}</li>
+     * <li>{@link #getPasswordExpiration}</li>
+     * <li>{@link #isActivePasswordSufficient}</li>
+     * <li>{@link #getCurrentFailedPasswordAttempts}</li>
+     * <li>{@link #getMaximumFailedPasswordsForWipe}</li>
+     * <li>{@link #setMaximumFailedPasswordsForWipe}</li>
+     * <li>{@link #getMaximumTimeToLock}</li>
+     * <li>{@link #setMaximumTimeToLock}</li>
+     * <li>{@link #lockNow}</li>
+     * <li>{@link #getKeyguardDisabledFeatures}</li>
+     * <li>{@link #setKeyguardDisabledFeatures}</li>
+     * <li>{@link #getTrustAgentConfiguration}</li>
+     * <li>{@link #setTrustAgentConfiguration}</li>
+     * </ul>
      *
      * @return a new instance of {@link DevicePolicyManager} that acts on the parent profile.
+     * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) {
         try {
@@ -5667,59 +5910,69 @@
             }
             return new DevicePolicyManager(mContext, true);
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Called by device owner to control the device logging feature. Logging can only be
+     * Called by device owner to control the security logging feature. Logging can only be
      * enabled on single user devices where the sole user is managed by the device owner.
      *
-     * <p> Device logs contain various information intended for security auditing purposes.
+     * <p> Security logs contain various information intended for security auditing purposes.
      * See {@link SecurityEvent} for details.
      *
-     * @param admin Which device owner this request is associated with.
-     * @param enabled whether device logging should be enabled or not.
-     * @see #retrieveDeviceLogs
-     */
-    public void setDeviceLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
-        try {
-            mService.setDeviceLoggingEnabled(admin, enabled);
-        } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-        }
-    }
-
-    /**
-     * Return whether device logging is enabled or not by the device owner.
+     * <p>There must be only one user on the device, managed by the device owner.
+     * Otherwise a {@link SecurityException} will be thrown.
      *
      * @param admin Which device owner this request is associated with.
-     * @return {@code true} if device logging is enabled by device owner, {@code false} otherwise.
+     * @param enabled whether security logging should be enabled or not.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     * @see #retrieveSecurityLogs
      */
-    public boolean getDeviceLoggingEnabled(@NonNull ComponentName admin) {
+    public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
         try {
-            return mService.getDeviceLoggingEnabled(admin);
+            mService.setSecurityLoggingEnabled(admin, enabled);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Called by device owner to retrieve all new device logging entries since the last call to
+     * Return whether security logging is enabled or not by the device owner.
+     *
+     * <p>Can only be called by the device owner, otherwise a {@link SecurityException} will be
+     * thrown.
+     *
+     * @param admin Which device owner this request is associated with.
+     * @return {@code true} if security logging is enabled by device owner, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     */
+    public boolean isSecurityLoggingEnabled(@NonNull ComponentName admin) {
+        try {
+            return mService.isSecurityLoggingEnabled(admin);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Called by device owner to retrieve all new security logging entries since the last call to
      * this API after device boots.
      *
      * <p> Access to the logs is rate limited and it will only return new logs after the device
      * owner has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}.
      *
+     * <p>There must be only one user on the device, managed by the device owner.
+     * Otherwise a {@link SecurityException} will be thrown.
+     *
      * @param admin Which device owner this request is associated with.
-     * @return the new batch of device logs which is a list of {@link SecurityEvent},
+     * @return the new batch of security logs which is a list of {@link SecurityEvent},
      * or {@code null} if rate limitation is exceeded or if logging is currently disabled.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public List<SecurityEvent> retrieveDeviceLogs(@NonNull ComponentName admin) {
+    public List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) {
         try {
-            ParceledListSlice<SecurityEvent> list = mService.retrieveDeviceLogs(admin);
+            ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(admin);
             if (list != null) {
                 return list.getList();
             } else {
@@ -5727,8 +5980,7 @@
                 return null;
             }
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5750,42 +6002,45 @@
 
     /**
      * Called by device owners to retrieve device logs from before the device's last reboot.
-     *
      * <p>
      * <strong> The device logs are retrieved from a RAM region which is not guaranteed to be
-     * corruption-free during power cycles, due to hardware variations and limitations. As a
-     * result, this API is provided as best-effort and the returned logs may contain corrupted data.
-     * </strong>
+     * corruption-free during power cycles, due to hardware variations and limitations. As a result,
+     * this API is provided as best-effort and the returned logs may be empty or contain corrupted
+     * data. </strong>
+     * <p>
+     * There must be only one user on the device, managed by the device owner. Otherwise a
+     * {@link SecurityException} will be thrown.
      *
      * @param admin Which device owner this request is associated with.
      * @return Device logs from before the latest reboot of the system.
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public List<SecurityEvent> retrievePreviousDeviceLogs(@NonNull ComponentName admin) {
+    public List<SecurityEvent> retrievePreRebootSecurityLogs(@NonNull ComponentName admin) {
         try {
-            ParceledListSlice<SecurityEvent> list = mService.retrievePreviousDeviceLogs(admin);
+            ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(admin);
             return list.getList();
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return Collections.<SecurityEvent>emptyList();
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Called by a profile owner of a managed profile to set the color used for customization.
-     * This color is used as background color of the confirm credentials screen for that user.
-     * The default color is {@link android.graphics.Color#GRAY}.
-     *
-     * <p>The confirm credentials screen can be created using
+     * Called by a profile owner of a managed profile to set the color used for customization. This
+     * color is used as background color of the confirm credentials screen for that user. The
+     * default color is teal (#00796B).
+     * <p>
+     * The confirm credentials screen can be created using
      * {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param color The 32bit representation of the color to be used.
+     * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public void setOrganizationColor(@NonNull ComponentName admin, int color) {
         try {
             mService.setOrganizationColor(admin, color);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5804,7 +6059,7 @@
         try {
             mService.setOrganizationColorForUser(color, userId);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5814,13 +6069,13 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return The 32bit representation of the color to be used.
+     * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public int getOrganizationColor(@NonNull ComponentName admin) {
         try {
             return mService.getOrganizationColor(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return 0;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5835,43 +6090,43 @@
         try {
             return mService.getOrganizationColorForUser(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return 0;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
      * Called by a profile owner of a managed profile to set the name of the organization under
      * management.
-     *
-     * <p>If the organization name needs to be localized, it is the responsibility of the
+     * <p>
+     * If the organization name needs to be localized, it is the responsibility of the
      * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
      * and set a new version of this string accordingly.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param title The organization name or {@code null} to clear a previously set name.
+     * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
         try {
             mService.setOrganizationName(admin, title);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Called by a profile owner of a managed profile to retrieve the name of the organization
-     * under management.
+     * Called by a profile owner of a managed profile to retrieve the name of the organization under
+     * management.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return The organization name or {@code null} if none is set.
+     * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public String getOrganizationName(@NonNull ComponentName admin) {
         try {
             return mService.getOrganizationName(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5887,8 +6142,7 @@
         try {
             return mService.getOrganizationNameForUser(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5897,13 +6151,14 @@
      *         return {@link #STATE_USER_UNMANAGED}
      * @hide
      */
+    @SystemApi
     @UserProvisioningState
     public int getUserProvisioningState() {
         if (mService != null) {
             try {
                 return mService.getUserProvisioningState();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return STATE_USER_UNMANAGED;
@@ -5921,7 +6176,7 @@
             try {
                 mService.setUserProvisioningState(state, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5948,7 +6203,7 @@
         try {
             mService.setAffiliationIds(admin, new ArrayList<String>(ids));
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -5963,8 +6218,7 @@
         try {
             return mService != null && mService.isAffiliatedUser();
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -5979,8 +6233,7 @@
         try {
             return mService.isUninstallInQueue(packageName);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5992,7 +6245,7 @@
         try {
             mService.uninstallPackageWithActiveAdmins(packageName);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 0a0d77d..54a2f7a 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -16,6 +16,9 @@
 
 package android.app.admin;
 
+import android.content.Intent;
+import android.os.UserHandle;
+
 import java.util.List;
 
 /**
@@ -69,4 +72,26 @@
      * @return true if the uid is an active admin with the given policy.
      */
     public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
+
+    /**
+     * Checks if a given package has a device or a profile owner for the given user.
+     * <p>
+     * <em>Note: does <b>not</b> support negative userIds like {@link UserHandle#USER_ALL}</em>
+     *
+     * @param packageName The package to check
+     * @param userId the userId to check for.
+     * @return true if package has a device or profile owner, false otherwise.
+     */
+    public abstract boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId);
+
+    /**
+     * Creates an intent to show the admin support dialog to let the user know that the package is
+     * suspended by the admin. This assumes that {@param packageName} is suspended by the
+     * device/profile owner. The caller should check if the package is suspended or not.
+     *
+     * @param packageName The package that is suspended
+     * @param userId The user having the suspended package.
+     * @return The intent to trigger the admin support dialog.
+     */
+    public abstract Intent createPackageSuspendedDialogIntent(String packageName, int userId);
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e9af872..1fb2283 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -91,7 +91,7 @@
 
     int setStorageEncryption(in ComponentName who, boolean encrypt);
     boolean getStorageEncryption(in ComponentName who, int userHandle);
-    int getStorageEncryptionStatus(int userHandle);
+    int getStorageEncryptionStatus(in String callerPackage, int userHandle);
 
     boolean requestBugreport(in ComponentName who);
 
@@ -135,17 +135,20 @@
     void clearProfileOwner(in ComponentName who);
     boolean hasUserSetupCompleted();
 
-    boolean setDeviceOwnerLockScreenInfo(in ComponentName who, String deviceOwnerInfo);
-    String getDeviceOwnerLockScreenInfo();
+    void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
+    CharSequence getDeviceOwnerLockScreenInfo();
 
     String[] setPackagesSuspended(in ComponentName admin, in String[] packageNames, boolean suspended);
-    boolean getPackageSuspended(in ComponentName admin, String packageName);
+    boolean isPackageSuspended(in ComponentName admin, String packageName);
 
     boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
     void uninstallCaCerts(in ComponentName admin, in String[] aliases);
     void enforceCanManageCaCerts(in ComponentName admin);
+    boolean approveCaCert(in String alias, int userHandle, boolean approval);
+    boolean isCaCertApproved(in String alias, int userHandle);
 
-    boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias);
+    boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer,
+            in byte[] certChainBuffer, String alias, boolean requestAccess);
     boolean removeKeyPair(in ComponentName who, String alias);
     void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
 
@@ -160,7 +163,7 @@
 
     void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings);
     Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
-    void setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName);
+    boolean setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName);
     String getApplicationRestrictionsManagingPackage(in ComponentName admin);
     boolean isCallerApplicationRestrictionsManagingPackage();
 
@@ -168,7 +171,8 @@
     ComponentName getRestrictionsProvider(int userHandle);
 
     void setUserRestriction(in ComponentName who, in String key, boolean enable);
-    Bundle getUserRestrictions(in ComponentName who, int userId);
+    Bundle getUserRestrictions(in ComponentName who);
+    Bundle getUserRestrictionsForUser(in ComponentName who, int userId);
     void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
     void clearCrossProfileIntentFilters(in ComponentName admin);
 
@@ -185,8 +189,6 @@
     boolean setApplicationHidden(in ComponentName admin, in String packageName, boolean hidden);
     boolean isApplicationHidden(in ComponentName admin, in String packageName);
 
-    UserHandle createUser(in ComponentName who, in String name);
-    UserHandle createAndInitializeUser(in ComponentName who, in String name, in String profileOwnerName, in ComponentName profileOwnerComponent, in Bundle adminExtras);
     UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
     boolean removeUser(in ComponentName who, in UserHandle userHandle);
     boolean switchUser(in ComponentName who, in UserHandle userHandle);
@@ -226,9 +228,9 @@
     boolean getBluetoothContactSharingDisabledForUser(int userId);
 
     void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent,
-            in PersistableBundle args);
+            in PersistableBundle args, boolean parent);
     List<PersistableBundle> getTrustAgentConfiguration(in ComponentName admin,
-            in ComponentName agent, int userId);
+            in ComponentName agent, int userId, boolean parent);
 
     boolean addCrossProfileWidgetProvider(in ComponentName admin, String packageName);
     boolean removeCrossProfileWidgetProvider(in ComponentName admin, String packageName);
@@ -263,7 +265,7 @@
     List<String> getKeepUninstalledPackages(in ComponentName admin);
     boolean isManagedProfile(in ComponentName admin);
     boolean isSystemOnlyUser(in ComponentName admin);
-    String getWifiMacAddress();
+    String getWifiMacAddress(in ComponentName admin);
     void reboot(in ComponentName admin);
 
     void setShortSupportMessage(in ComponentName admin, in String message);
@@ -291,10 +293,10 @@
     void setAffiliationIds(in ComponentName admin, in List<String> ids);
     boolean isAffiliatedUser();
 
-    void setDeviceLoggingEnabled(in ComponentName admin, boolean enabled);
-    boolean getDeviceLoggingEnabled(in ComponentName admin);
-    ParceledListSlice retrieveDeviceLogs(in ComponentName admin);
-    ParceledListSlice retrievePreviousDeviceLogs(in ComponentName admin);
+    void setSecurityLoggingEnabled(in ComponentName admin, boolean enabled);
+    boolean isSecurityLoggingEnabled(in ComponentName admin);
+    ParceledListSlice retrieveSecurityLogs(in ComponentName admin);
+    ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin);
 
     boolean isUninstallInQueue(String packageName);
     void uninstallPackageWithActiveAdmins(String packageName);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
new file mode 100644
index 0000000..2858991
--- /dev/null
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.admin;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemProperties;
+import android.util.EventLog.Event;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+
+public class SecurityLog {
+
+    private static final String PROPERTY_LOGGING_ENABLED = "persist.logd.security";
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE,
+        TAG_APP_PROCESS_START, TAG_KEYGUARD_DISMISSED, TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
+        TAG_KEYGUARD_SECURED})
+    public @interface SECURITY_LOG_TAG {}
+
+    /**
+     * Indicate that an ADB interactive shell was opened via "adb shell".
+     * There is no extra payload in the log event.
+     */
+    public static final int TAG_ADB_SHELL_INTERACTIVE =
+            SecurityLogTags.SECURITY_ADB_SHELL_INTERACTIVE;
+    /**
+     * Indicate that an shell command was issued over ADB via "adb shell command"
+     * The log entry contains a string data of the shell command, accessible via
+     * {@link SecurityEvent#getData()}
+     */
+    public static final int TAG_ADB_SHELL_CMD = SecurityLogTags.SECURITY_ADB_SHELL_COMMAND;
+    /**
+     * Indicate that a file was pulled from the device via the adb daemon, for example via
+     * "adb pull". The log entry contains a string data of the path of the pulled file,
+     * accessible via {@link SecurityEvent#getData()}
+     */
+    public static final int TAG_SYNC_RECV_FILE = SecurityLogTags.SECURITY_ADB_SYNC_RECV;
+    /**
+     * Indicate that a file was pushed to the device via the adb daemon, for example via
+     * "adb push". The log entry contains a string data of the destination path of the
+     * pushed file, accessible via {@link SecurityEvent#getData()}
+     */
+    public static final int TAG_SYNC_SEND_FILE = SecurityLogTags.SECURITY_ADB_SYNC_SEND;
+    /**
+     * Indicate that an app process was started. The log entry contains the following
+     * information about the process encapsulated in an {@link Object} array, accessible via
+     * {@link SecurityEvent#getData()}:
+     * process name (String), exact start time (long), app Uid (integer), app Pid (integer),
+     * seinfo tag (String), SHA-256 hash of the base APK in hexadecimal (String)
+     */
+    public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
+    /**
+     * Indicate that keyguard is being dismissed.
+     * There is no extra payload in the log event.
+     */
+    public static final int TAG_KEYGUARD_DISMISSED =
+            SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
+    /**
+     * Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
+     * contains the following information about the attempt encapsulated in an {@link Object} array,
+     * accessible via {@link SecurityEvent#getData()}:
+     * attempt result (integer, 1 for successful, 0 for unsuccessful), strength of auth method
+     * (integer, 1 if strong auth method was used, 0 otherwise)
+     */
+    public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
+            SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
+    /**
+     * Indicate that the device has been locked, either by user or by timeout.
+     * There is no extra payload in the log event.
+     */
+    public static final int TAG_KEYGUARD_SECURED = SecurityLogTags.SECURITY_KEYGUARD_SECURED;
+
+    /**
+     * Returns if security logging is enabled. Log producers should only write new logs if this is
+     * true. Under the hood this is the logical AND of whether device owner exists and whether
+     * it enables logging by setting the system property {@link #PROPERTY_LOGGING_ENABLED}.
+     * @hide
+     */
+    public static native boolean isLoggingEnabled();
+
+    /**
+     * @hide
+     */
+    public static void setLoggingEnabledProperty(boolean enabled) {
+        SystemProperties.set(PROPERTY_LOGGING_ENABLED, enabled ? "true" : "false");
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean getLoggingEnabledProperty() {
+        return SystemProperties.getBoolean(PROPERTY_LOGGING_ENABLED, false);
+    }
+
+    /**
+     * A class representing a security event log entry.
+     */
+    public static final class SecurityEvent implements Parcelable {
+        private Event mEvent;
+
+        /** @hide */
+        /*package*/ SecurityEvent(byte[] data) {
+            mEvent = Event.fromBytes(data);
+        }
+
+        /**
+         * Returns the timestamp in nano seconds when this event was logged.
+         */
+        public long getTimeNanos() {
+            return mEvent.getTimeNanos();
+        }
+
+        /**
+         * Returns the tag of this log entry, which specifies entry's semantics.
+         * Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE},
+         * {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD},
+         * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START},
+         * {@link SecurityLog#TAG_KEYGUARD_DISMISSED}, {@link SecurityLog#TAG_KEYGUARD_SECURED},
+         * {@link SecurityLog#TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT}.
+         */
+        public @SECURITY_LOG_TAG int getTag() {
+            return mEvent.getTag();
+        }
+
+        /**
+         * Returns the payload contained in this log. Each call to this method will
+         * retrieve the next payload item. If no more payload exists, it returns {@code null}.
+         */
+        public Object getData() {
+            return mEvent.getData();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeByteArray(mEvent.getBytes());
+        }
+
+        public static final Parcelable.Creator<SecurityEvent> CREATOR =
+                new Parcelable.Creator<SecurityEvent>() {
+            @Override
+            public SecurityEvent createFromParcel(Parcel source) {
+                return new SecurityEvent(source.createByteArray());
+            }
+
+            @Override
+            public SecurityEvent[] newArray(int size) {
+                return new SecurityEvent[size];
+            }
+        };
+    }
+    /**
+     * Retrieve all security logs and return immediately.
+     * @hide
+     */
+    public static native void readEvents(Collection<SecurityEvent> output) throws IOException;
+
+    /**
+     * Retrieve all security logs since the given timestamp in nanoseconds and return immediately.
+     * @hide
+     */
+    public static native void readEventsSince(long timestamp, Collection<SecurityEvent> output)
+            throws IOException;
+
+    /**
+     * Retrieve all security logs before the last reboot. May return corrupted data due to
+     * unreliable pstore.
+     * @hide
+     */
+    public static native void readPreviousEvents(Collection<SecurityEvent> output)
+            throws IOException;
+
+    /**
+     * Retrieve all security logs whose timestamp (in nanosceonds) is equal to or greater than the
+     * given timestamp. This method will block until either the last log earlier than the given
+     * timestamp is about to be pruned, or after a 2-hour timeout has passed.
+     * @hide
+     */
+    public static native void readEventsOnWrapping(long timestamp, Collection<SecurityEvent> output)
+            throws IOException;
+
+    /**
+     * Write a log entry to the underlying storage, with a string payload.
+     * @hide
+     */
+    public static native int writeEvent(int tag, String str);
+
+    /**
+     * Write a log entry to the underlying storage, with several payloads.
+     * Supported types of payload are: integer, long, float, string plus array of supported types.
+     * @hide
+     */
+    public static native int writeEvent(int tag, Object... payloads);
+}
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
new file mode 100644
index 0000000..39371c7
--- /dev/null
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -0,0 +1,12 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.app.admin
+
+210001 security_adb_shell_interactive
+210002 security_adb_shell_command               (command|3)
+210003 security_adb_sync_recv                   (path|3)
+210004 security_adb_sync_send                   (path|3)
+210005 security_app_process_start               (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
+210006 security_keyguard_dismissed
+210007 security_keyguard_dismiss_auth_attempt   (success|1),(method_strength|1)
+210008 security_keyguard_secured
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index aeb3156..8e515e2 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -18,7 +18,6 @@
 
 import android.app.IBackupAgent;
 import android.app.QueuedWork;
-import android.app.backup.IBackupManager;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.ApplicationInfo;
@@ -36,18 +35,17 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 /**
  * Provides the central interface between an
  * application and Android's data backup infrastructure.  An application that wishes
@@ -310,7 +308,7 @@
 
         // System apps have control over where their default storage context
         // is pointed, so we're always explicit when building paths.
-        final Context ceContext = createCredentialEncryptedStorageContext();
+        final Context ceContext = createCredentialProtectedStorageContext();
         final String rootDir = ceContext.getDataDir().getCanonicalPath();
         final String filesDir = ceContext.getFilesDir().getCanonicalPath();
         final String noBackupDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
@@ -321,7 +319,7 @@
         final String cacheDir = ceContext.getCacheDir().getCanonicalPath();
         final String codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
 
-        final Context deContext = createDeviceEncryptedStorageContext();
+        final Context deContext = createDeviceProtectedStorageContext();
         final String deviceRootDir = deContext.getDataDir().getCanonicalPath();
         final String deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
         final String deviceNoBackupDir = deContext.getNoBackupFilesDir().getCanonicalPath();
@@ -429,23 +427,31 @@
     }
 
     /**
-     * Tells the application agent that the backup data size exceeded current transport quota.
-     * Later calls to {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
-     * and {@link #onFullBackup(FullBackupDataOutput)} could use this information
-     * to reduce backup size under the limit.
-     * However, the quota can change, so do not assume that the value passed in here is absolute,
-     * similarly all subsequent backups should not be restricted to this size.
-     * This callback will be invoked before data has been put onto the wire in a preflight check,
-     * so it is relatively inexpensive to hit your quota.
-     * Apps that hit quota repeatedly without dealing with it can be subject to having their backup
-     * schedule reduced.
-     * The {@code quotaBytes} is a loose guideline b/c of metadata added by the backupmanager
-     * so apps should be more aggressive in trimming their backup set.
+     * Notification that the application's current backup operation causes it to exceed
+     * the maximum size permitted by the transport.  The ongoing backup operation is
+     * halted and rolled back: any data that had been stored by a previous backup operation
+     * is still intact.  Typically the quota-exceeded state will be detected before any data
+     * is actually transmitted over the network.
      *
-     * @param backupDataBytes Expected or already processed amount of data.
-     *                        Could be less than total backup size if backup process was interrupted
-     *                        before finish of processing all backup data.
-     * @param quotaBytes Current amount of backup data that is allowed for the app.
+     * <p>The {@code quotaBytes} value is the total data size currently permitted for this
+     * application.  If desired, the application can use this as a hint for determining
+     * how much data to store.  For example, a messaging application might choose to
+     * store only the newest messages, dropping enough older content to stay under
+     * the quota.
+     *
+     * <p class="note">Note that the maximum quota for the application can change over
+     * time.  In particular, in the future the quota may grow.  Applications that adapt
+     * to the quota when deciding what data to store should be aware of this and implement
+     * their data storage mechanisms in a way that can take advantage of additional
+     * quota.
+     *
+     * @param backupDataBytes The amount of data measured while initializing the backup
+     *    operation, if the total exceeds the app's alloted quota.  If initial measurement
+     *    suggested that the data would fit but then too much data was actually submitted
+     *    as part of the operation, then this value is the amount of data that had been
+     *    streamed into the transport at the time the quota was reached.
+     * @param quotaBytes The maximum data size that the transport currently permits
+     *    this application to store as a backup.
      */
     public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
     }
@@ -516,7 +522,7 @@
         try {
             // System apps have control over where their default storage context
             // is pointed, so we're always explicit when building paths.
-            final Context ceContext = createCredentialEncryptedStorageContext();
+            final Context ceContext = createCredentialProtectedStorageContext();
             rootDir = ceContext.getDataDir().getCanonicalPath();
             filesDir = ceContext.getFilesDir().getCanonicalPath();
             nbFilesDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
@@ -525,7 +531,7 @@
             cacheDir = ceContext.getCacheDir().getCanonicalPath();
             codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
 
-            final Context deContext = createDeviceEncryptedStorageContext();
+            final Context deContext = createDeviceProtectedStorageContext();
             deviceRootDir = deContext.getDataDir().getCanonicalPath();
             deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
             deviceNbFilesDir = deContext.getNoBackupFilesDir().getCanonicalPath();
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 2268400..7fcca09 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -468,7 +468,7 @@
      *
      * @param packages List of package names to backup.
      * @param observer The {@link BackupObserver} to receive callbacks during the backup
-     * operation.
+     * operation. Could be {@code null}.
      * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
      * @exception  IllegalArgumentException on null or empty {@code packages} param.
      *
@@ -479,8 +479,9 @@
         checkServiceBinder();
         if (sService != null) {
             try {
-                BackupObserverWrapper observerWrapper =
-                    new BackupObserverWrapper(mContext, observer);
+                BackupObserverWrapper observerWrapper = observer == null
+                        ? null
+                        : new BackupObserverWrapper(mContext, observer);
                 return sService.requestBackup(packages, observerWrapper);
             } catch (RemoteException e) {
                 Log.e(TAG, "requestBackup() couldn't connect");
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index cdc80e3..478024d 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.XmlResourceParser;
-import android.os.*;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -31,16 +31,15 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.xmlpull.v1.XmlPullParserException;
 /**
  * Global constant definitions et cetera related to the full-backup-to-fd
  * binary format.  Nothing in this namespace is part of any API; it's all
@@ -289,7 +288,7 @@
 
             // System apps have control over where their default storage context
             // is pointed, so we're always explicit when building paths.
-            final Context ceContext = context.createCredentialEncryptedStorageContext();
+            final Context ceContext = context.createCredentialProtectedStorageContext();
             FILES_DIR = ceContext.getFilesDir();
             DATABASE_DIR = ceContext.getDatabasePath("foo").getParentFile();
             ROOT_DIR = ceContext.getDataDir();
@@ -297,7 +296,7 @@
             CACHE_DIR = ceContext.getCacheDir();
             NOBACKUP_DIR = ceContext.getNoBackupFilesDir();
 
-            final Context deContext = context.createDeviceEncryptedStorageContext();
+            final Context deContext = context.createDeviceProtectedStorageContext();
             DEVICE_FILES_DIR = deContext.getFilesDir();
             DEVICE_DATABASE_DIR = deContext.getDatabasePath("foo").getParentFile();
             DEVICE_ROOT_DIR = deContext.getDataDir();
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 30c11ef..f256a95 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -120,6 +120,7 @@
      * need to be backed up, write them to the data stream, and fill in newState with the
      * state as it exists now.
      */
+    @Override
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) {
         performBackup_checked(oldState, data, newState, mFiles, mKeys);
@@ -130,6 +131,7 @@
      * magic wallpaper file, take specific action to determine whether it is suitable for
      * the current device.
      */
+    @Override
     public void restoreEntity(BackupDataInputStream data) {
         final String key = data.getKey();
         if (isKeyInList(key, mKeys)) {
@@ -174,12 +176,8 @@
                     }
 
                     // We passed the acceptable-dimensions test (if any), so we're going to
-                    // use the restored image.
-                    // TODO: spin a service to copy the restored image to sd/usb storage,
-                    // since it does not exist anywhere other than the private wallpaper
-                    // file.
-                    Slog.d(TAG, "Applying restored wallpaper image.");
-                    f.renameTo(new File(WALLPAPER_IMAGE));
+                    // use the restored image.  That comes last, when we are done restoring
+                    // both the pixels and the metadata.
                 }
             } else if (key.equals(WALLPAPER_INFO_KEY)) {
                 // XML file containing wallpaper info
@@ -188,4 +186,20 @@
             }
         }
     }
+
+    /**
+     * Hook for the agent to call this helper upon completion of the restore.  We do this
+     * upon completion so that we know both the imagery and the wallpaper info have
+     * been emplaced without requiring either or relying on ordering.
+     */
+    public void onRestoreFinished() {
+        final File f = new File(STAGE_FILE);
+        if (f.exists()) {
+            // TODO: spin a service to copy the restored image to sd/usb storage,
+            // since it does not exist anywhere other than the private wallpaper
+            // file.
+            Slog.d(TAG, "Applying restored wallpaper image.");
+            f.renameTo(new File(WALLPAPER_IMAGE));
+        }
+    }
 }
diff --git a/core/java/android/app/job/IJobScheduler.aidl b/core/java/android/app/job/IJobScheduler.aidl
index f0c3302..3379f2e 100644
--- a/core/java/android/app/job/IJobScheduler.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -24,7 +24,7 @@
   */
 interface IJobScheduler {
     int schedule(in JobInfo job);
-    int scheduleAsPackage(in JobInfo job, String packageName, int userId);
+    int scheduleAsPackage(in JobInfo job, String packageName, int userId, String tag);
     void cancel(int jobId);
     void cancelAll();
     List<JobInfo> getAllPendingJobs();
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 5398e7f..828ac38 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -73,9 +73,32 @@
     public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
 
     /* Minimum interval for a periodic job, in milliseconds. */
-    public static final long MIN_PERIOD_MILLIS = 60 * 60 * 1000L;   // 60 minutes
+    private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L;   // 15 minutes
+
     /* Minimum flex for a periodic job, in milliseconds. */
-    public static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
+    private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
+
+    /**
+     * Query the minimum interval allowed for periodic scheduled jobs.  Attempting
+     * to declare a smaller period that this when scheduling a job will result in a
+     * job that is still periodic, but will run with this effective period.
+     *
+     * @return The minimum available interval for scheduling periodic jobs, in milliseconds.
+     */
+    public static final long getMinimumPeriod() {
+        return MIN_PERIOD_MILLIS;
+    }
+
+    /**
+     * Query the minimum flex time allowed for periodic scheduled jobs.  Attempting
+     * to declare a shorter flex time than this when scheduling such a job will
+     * result in this amount as the effective flex time for the job.
+     *
+     * @return The minimum available flex time for scheduling periodic jobs, in milliseconds.
+     */
+    public static final long getMinimumFlex() {
+        return MIN_FLEX_MILLIS;
+    }
 
     /**
      * Default type of backoff.
@@ -83,6 +106,38 @@
      */
     public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
 
+    /**
+     * Default of {@link #getPriority}.
+     * @hide
+     */
+    public static final int PRIORITY_DEFAULT = 0;
+
+    /**
+     * Value of {@link #getPriority} for expedited syncs.
+     * @hide
+     */
+    public static final int PRIORITY_SYNC_EXPEDITED = 10;
+
+    /**
+     * Value of {@link #getPriority} for first time initialization syncs.
+     * @hide
+     */
+    public static final int PRIORITY_SYNC_INITIALIZATION = 20;
+
+    /**
+     * Value of {@link #getPriority} for a foreground app (overrides the supplied
+     * JobInfo priority if it is smaller).
+     * @hide
+     */
+    public static final int PRIORITY_FOREGROUND_APP = 30;
+
+    /**
+     * Value of {@link #getPriority} for the current top app (overrides the supplied
+     * JobInfo priority if it is smaller).
+     * @hide
+     */
+    public static final int PRIORITY_TOP_APP = 40;
+
     private final int jobId;
     private final PersistableBundle extras;
     private final ComponentName service;
@@ -195,7 +250,7 @@
      * job does not recur periodically.
      */
     public long getIntervalMillis() {
-        return intervalMillis >= MIN_PERIOD_MILLIS ? intervalMillis : MIN_PERIOD_MILLIS;
+        return intervalMillis >= getMinimumPeriod() ? intervalMillis : getMinimumPeriod();
     }
 
     /**
@@ -204,7 +259,7 @@
     public long getFlexMillis() {
         long interval = getIntervalMillis();
         long percentClamp = 5 * interval / 100;
-        long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, MIN_FLEX_MILLIS));
+        long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, getMinimumFlex()));
         return clampedFlex <= interval ? clampedFlex : interval;
     }
 
@@ -406,7 +461,7 @@
         private int mJobId;
         private PersistableBundle mExtras = PersistableBundle.EMPTY;
         private ComponentName mJobService;
-        private int mPriority;
+        private int mPriority = PRIORITY_DEFAULT;
         // Requirements.
         private boolean mRequiresCharging;
         private boolean mRequiresDeviceIdle;
@@ -504,6 +559,9 @@
          * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}.  To continually monitor
          * for content changes, you need to schedule a new JobInfo observing the same URIs
          * before you finish execution of the JobService handling the most recent changes.</p>
+         * <p>Because because setting this property is not compatible with periodic or
+         * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
+         * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
          * @param uri The content: URI to monitor.
          */
         public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
@@ -530,9 +588,9 @@
          * Specify that this job should recur with the provided interval and flex. The job can
          * execute at any time in a window of flex length at the end of the period.
          * @param intervalMillis Millisecond interval for which this job will repeat. A minimum
-         *                       value of {@link #MIN_PERIOD_MILLIS} is enforced.
+         *                       value of {@link #getMinimumPeriod()} is enforced.
          * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
-         *                   {@link #MIN_FLEX_MILLIS} or 5 percent of the period, whichever is
+         *                   {@link #getMinimumFlex()} or 5 percent of the period, whichever is
          *                   higher.
          */
         public Builder setPeriodic(long intervalMillis, long flexMillis) {
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 5e1a4256..d1e563f 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -68,10 +68,11 @@
      * @param packageName The package on behalf of which the job is to be scheduled. This will be
      *                    used to track battery usage and appIdleState.
      * @param userId    User on behalf of whom this job is to be scheduled.
+     * @param tag Debugging tag for dumps associated with this job (instead of the service class)
      * @return {@link #RESULT_SUCCESS} or {@link #RESULT_FAILURE}
      * @hide
      */
-    public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId);
+    public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag);
 
     /**
      * Cancel a job that is pending in the JobScheduler.
diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java
index 940a530..95a8ccf 100644
--- a/core/java/android/app/job/JobService.java
+++ b/core/java/android/app/job/JobService.java
@@ -46,10 +46,10 @@
      * Job services must be protected with this permission:
      *
      * <pre class="prettyprint">
-     *     <service android:name="MyJobService"
-     *              android:permission="android.permission.BIND_JOB_SERVICE" >
+     *     &#60;service android:name="MyJobService"
+     *              android:permission="android.permission.BIND_JOB_SERVICE" &#62;
      *         ...
-     *     </service>
+     *     &#60;/service&#62;
      * </pre>
      *
      * <p>If a job service is declared in the manifest but not protected with this
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 999d826..0f5cb6f 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -16,8 +16,6 @@
 
 package android.app.trust;
 
-import com.android.internal.widget.LockPatternUtils;
-
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.os.Handler;
@@ -26,7 +24,8 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.ArrayMap;
-import android.util.Log;
+
+import com.android.internal.widget.LockPatternUtils;
 
 /**
  * See {@link com.android.server.trust.TrustManagerService}
@@ -62,7 +61,7 @@
         try {
             mService.setDeviceLockedForUser(userId, locked);
         } catch (RemoteException e) {
-            onError(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -77,7 +76,7 @@
         try {
             mService.reportUnlockAttempt(successful, userId);
         } catch (RemoteException e) {
-            onError(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -90,7 +89,7 @@
         try {
             mService.reportEnabledTrustAgentsChanged(userId);
         } catch (RemoteException e) {
-            onError(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -103,7 +102,7 @@
         try {
             mService.reportKeyguardShowingChanged();
         } catch (RemoteException e) {
-            onError(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -134,7 +133,7 @@
             mService.registerTrustListener(iTrustListener);
             mTrustListeners.put(trustListener, iTrustListener);
         } catch (RemoteException e) {
-            onError(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -149,7 +148,7 @@
             try {
                 mService.unregisterTrustListener(iTrustListener);
             } catch (RemoteException e) {
-                onError(e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -163,16 +162,10 @@
         try {
             return mService.isTrustUsuallyManaged(userId);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
-
-
-    private void onError(Exception e) {
-        Log.e(TAG, "Error while calling TrustManagerService", e);
-    }
-
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index a9328bc..342c285 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -33,4 +33,5 @@
     void setAppInactive(String packageName, boolean inactive, int userId);
     boolean isAppInactive(String packageName, int userId);
     void whitelistAppTemporarily(String packageName, long duration, int userId);
+    void onCarrierPrivilegedAppsChanged();
 }
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 9f1a9cf0..6d5c81b 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -16,6 +16,7 @@
 
 package android.app.usage;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.net.INetworkStatsService;
 import android.net.INetworkStatsSession;
@@ -29,6 +30,9 @@
 
 import dalvik.system.CloseGuard;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects
  * are returned as results to various queries in {@link NetworkStatsManager}.
@@ -119,6 +123,11 @@
      * aggregated (e.g. time or state) some values may be equal across all buckets.
      */
     public static class Bucket {
+        /** @hide */
+        @IntDef({STATE_ALL, STATE_DEFAULT, STATE_FOREGROUND})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface State {}
+
         /**
          * Combined usage across all states.
          */
@@ -149,20 +158,34 @@
          */
         public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
 
+        /** @hide */
+        @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Roaming {}
+
         /**
-         * Combined usage across all roaming states.
+         * Combined usage across all roaming states. Covers both roaming and non-roaming usage.
          */
         public static final int ROAMING_ALL = -1;
 
         /**
-         * Usage not accounted for in any other roaming state.
+         * Usage that occurs on a home, non-roaming network.
+         *
+         * <p>Any cellular usage in this bucket was incurred while the device was connected to a
+         * tower owned or operated by the user's wireless carrier, or a tower that the user's
+         * wireless carrier has indicated should be treated as a home network regardless.
+         *
+         * <p>This is also the default value for network types that do not support roaming.
          */
-        public static final int ROAMING_DEFAULT = 0x1;
+        public static final int ROAMING_NO = 0x1;
 
         /**
-         * Roaming usage.
+         * Usage that occurs on a roaming network.
+         *
+         * <p>Any cellular usage in this bucket as incurred while the device was roaming on another
+         * carrier's network, for which additional charges may apply.
          */
-        public static final int ROAMING_ROAMING = 0x2;
+        public static final int ROAMING_YES = 0x2;
 
         /**
          * Special TAG value matching any tag.
@@ -185,7 +208,7 @@
         private long mTxBytes;
         private long mTxPackets;
 
-        private static int convertState(int networkStatsSet) {
+        private static @State int convertState(int networkStatsSet) {
             switch (networkStatsSet) {
                 case android.net.NetworkStats.SET_ALL : return STATE_ALL;
                 case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT;
@@ -210,11 +233,11 @@
             return tag;
         }
 
-        private static int convertRoaming(int roaming) {
+        private static @Roaming int convertRoaming(int roaming) {
             switch (roaming) {
                 case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL;
-                case android.net.NetworkStats.ROAMING_DEFAULT : return ROAMING_DEFAULT;
-                case android.net.NetworkStats.ROAMING_ROAMING : return ROAMING_ROAMING;
+                case android.net.NetworkStats.ROAMING_NO: return ROAMING_NO;
+                case android.net.NetworkStats.ROAMING_YES: return ROAMING_YES;
             }
             return 0;
         }
@@ -252,7 +275,7 @@
          * </ul>
          * @return Usage state.
          */
-        public int getState() {
+        public @State int getState() {
             return mState;
         }
 
@@ -260,11 +283,11 @@
          * Roaming state. One of the following values:<p/>
          * <ul>
          * <li>{@link #ROAMING_ALL}</li>
-         * <li>{@link #ROAMING_DEFAULT}</li>
-         * <li>{@link #ROAMING_ROAMING}</li>
+         * <li>{@link #ROAMING_NO}</li>
+         * <li>{@link #ROAMING_YES}</li>
          * </ul>
          */
-        public int getRoaming() {
+        public @Roaming int getRoaming() {
             return mRoaming;
         }
 
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index c74b0f2..2aeecfa 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -267,4 +267,15 @@
         } catch (RemoteException re) {
         }
     }
+
+    /**
+     * Inform usage stats that the carrier privileged apps access rules have changed.
+     * @hide
+     */
+    public void onCarrierPrivilegedAppsChanged() {
+        try {
+            mService.onCarrierPrivilegedAppsChanged();
+        } catch (RemoteException re) {
+        }
+    }
 }
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 1af4953..2d9f4a7 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -17,8 +17,7 @@
 package android.appwidget;
 
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.List;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -35,7 +34,9 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.util.DisplayMetrics;
+import android.util.SparseArray;
 import android.util.TypedValue;
 import android.widget.RemoteViews;
 import android.widget.RemoteViews.OnClickHandler;
@@ -62,7 +63,7 @@
     private final Handler mHandler;
     private final int mHostId;
     private final Callbacks mCallbacks;
-    private final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<>();
+    private final SparseArray<AppWidgetHostView> mViews = new SparseArray<>();
     private OnClickHandler mOnClickHandler;
 
     static class Callbacks extends IAppWidgetHost.Stub {
@@ -164,7 +165,6 @@
         bindService();
     }
 
-
     private static void bindService() {
         synchronized (sServiceLock) {
             if (sService == null) {
@@ -179,17 +179,25 @@
      * becomes visible, i.e. from onStart() in your Activity.
      */
     public void startListening() {
-        int[] updatedIds;
-        ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
+        final int[] idsToUpdate;
+        synchronized (mViews) {
+            int N = mViews.size();
+            idsToUpdate = new int[N];
+            for (int i = 0; i < N; i++) {
+                idsToUpdate[i] = mViews.keyAt(i);
+            }
+        }
+        List<RemoteViews> updatedViews;
+        int[] updatedIds = new int[idsToUpdate.length];
         try {
-            updatedIds = sService.startListening(mCallbacks, mContextOpPackageName, mHostId,
-                    updatedViews);
+            updatedViews = sService.startListening(
+                    mCallbacks, mContextOpPackageName, mHostId, idsToUpdate, updatedIds).getList();
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
 
-        final int N = updatedIds.length;
+        int N = updatedViews.size();
         for (int i = 0; i < N; i++) {
             updateAppWidgetView(updatedIds[i], updatedViews.get(i));
         }
@@ -206,10 +214,6 @@
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
-
-        // This is here because keyguard needs it since it'll be switching users after this call.
-        // If it turns out other apps need to call this often, we should re-think how this works.
-        clearViews();
     }
 
     /**
@@ -418,7 +422,9 @@
      * Clear the list of Views that have been created by this AppWidgetHost.
      */
     protected void clearViews() {
-        mViews.clear();
+        synchronized (mViews) {
+            mViews.clear();
+        }
     }
 }
 
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 278c9d6..9f654c2 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -472,9 +472,8 @@
         }
         try {
             mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -495,9 +494,8 @@
         }
         try {
             mService.updateAppWidgetOptions(mPackageName, appWidgetId, options);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -518,9 +516,8 @@
         }
         try {
             return mService.getAppWidgetOptions(mPackageName, appWidgetId);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -581,7 +578,7 @@
         try {
             mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views);
         } catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -635,9 +632,8 @@
         }
         try {
             mService.updateAppWidgetProvider(provider, views);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -654,9 +650,8 @@
         }
         try {
             mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -764,9 +759,8 @@
                 convertSizesToPixels(info);
             }
             return providers.getList();
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -787,9 +781,8 @@
                 convertSizesToPixels(info);
             }
             return info;
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -918,9 +911,8 @@
         }
         try {
             return mService.hasBindAppWidgetPermission(packageName, userId);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -939,9 +931,8 @@
         }
         try {
             return mService.hasBindAppWidgetPermission(packageName, UserHandle.myUserId());
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -979,9 +970,8 @@
         }
         try {
             mService.setBindAppWidgetPermission(packageName, userId, permission);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1005,9 +995,8 @@
         }
         try {
             mService.bindRemoteViewsService(packageName, appWidgetId, intent, connection);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1029,9 +1018,8 @@
         }
         try {
             mService.unbindRemoteViewsService(packageName, appWidgetId, intent);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1048,9 +1036,8 @@
         }
         try {
             return mService.getAppWidgetIds(provider);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1063,8 +1050,8 @@
         }
         try {
             return mService.isBoundWidgetPackage(packageName, userId);
-        } catch (RemoteException re) {
-            throw new RuntimeException("system server dead?", re);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1076,9 +1063,8 @@
         try {
             return mService.bindAppWidgetId(mPackageName, appWidgetId,
                     profileId, provider, options);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java
deleted file mode 100644
index f1703d6..0000000
--- a/core/java/android/auditing/SecurityLog.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.auditing;
-
-import android.annotation.IntDef;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemProperties;
-import android.util.EventLog.Event;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
-
-public class SecurityLog {
-
-    private static final String PROPERTY_LOGGING_ENABLED = "persist.logd.security";
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE,
-        TAG_APP_PROCESS_START, TAG_KEYGUARD_DISMISSED, TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
-        TAG_KEYGUARD_SECURED})
-    public @interface SECURITY_LOG_TAG {}
-
-    /**
-     * Indicate that an ADB interactive shell was opened via "adb shell".
-     * There is no extra payload in the log event.
-     */
-    public static final int TAG_ADB_SHELL_INTERACTIVE =
-            SecurityLogTags.SECURITY_ADB_SHELL_INTERACTIVE;
-    /**
-     * Indicate that an shell command was issued over ADB via "adb shell command"
-     * The log entry contains a string data of the shell command, accessible via
-     * {@link SecurityEvent#getData()}
-     */
-    public static final int TAG_ADB_SHELL_CMD = SecurityLogTags.SECURITY_ADB_SHELL_COMMAND;
-    /**
-     * Indicate that a file was pulled from the device via the adb daemon, for example via
-     * "adb pull". The log entry contains a string data of the path of the pulled file,
-     * accessible via {@link SecurityEvent#getData()}
-     */
-    public static final int TAG_SYNC_RECV_FILE = SecurityLogTags.SECURITY_ADB_SYNC_RECV;
-    /**
-     * Indicate that a file was pushed to the device via the adb daemon, for example via
-     * "adb push". The log entry contains a string data of the destination path of the
-     * pushed file, accessible via {@link SecurityEvent#getData()}
-     */
-    public static final int TAG_SYNC_SEND_FILE = SecurityLogTags.SECURITY_ADB_SYNC_SEND;
-    /**
-     * Indicate that an app process was started. The log entry contains the following
-     * information about the process in order, accessible via {@link SecurityEvent#getData()}}:
-     * process name (String), exact start time (long), app Uid (integer), app Pid (integer),
-     * seinfo tag (String), SHA-256 hash of the APK in hexadecimal (String)
-     */
-    public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
-    /**
-     * Indicate that keyguard is being dismissed.
-     * There is no extra payload in the log event.
-     */
-    public static final int TAG_KEYGUARD_DISMISSED =
-            SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
-    /**
-     * Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
-     * contains the following information about the attempt in order, accessible via
-     * {@link SecurityEvent#getData()}}: attempt result (integer, 1 for successful, 0 for
-     * unsuccessful), strength of auth method (integer, 1 if strong auth method was used,
-     * 0 otherwise)
-     */
-    public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
-            SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
-    /**
-     * Indicate that the device has been locked, either by user or by timeout.
-     * There is no extra payload in the log event.
-     */
-    public static final int TAG_KEYGUARD_SECURED = SecurityLogTags.SECURITY_KEYGUARD_SECURED;
-
-    /**
-     * Returns if device logging is enabled. Log producers should only write new logs if this is
-     * true. Under the hood this is the logical AND of whether device owner exists and whether
-     * it enables logging by setting the system property {@link #PROPERTY_LOGGING_ENABLED}.
-     * @hide
-     */
-    public static native boolean isLoggingEnabled();
-
-    /**
-     * @hide
-     */
-    public static void setLoggingEnabledProperty(boolean enabled) {
-        SystemProperties.set(PROPERTY_LOGGING_ENABLED, enabled ? "true" : "false");
-    }
-
-    /**
-     * @hide
-     */
-    public static boolean getLoggingEnabledProperty() {
-        return SystemProperties.getBoolean(PROPERTY_LOGGING_ENABLED, false);
-    }
-
-    /**
-     * A class representing a security event log entry.
-     */
-    public static class SecurityEvent implements Parcelable {
-        private Event mEvent;
-
-        /** @hide */
-        /*package*/ SecurityEvent(byte[] data) {
-            mEvent = Event.fromBytes(data);
-        }
-
-        /**
-         * Returns the timestamp in nano seconds when this event was logged.
-         */
-        public long getTimeNanos() {
-            return mEvent.getTimeNanos();
-        }
-
-        /**
-         * Returns the tag of this log entry, which specifies entry's semantics.
-         * Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE},
-         * {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD},
-         * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START},
-         * {@link SecurityLog#TAG_KEYGUARD_DISMISSED}, {@link SecurityLog#TAG_KEYGUARD_SECURED},
-         * {@link SecurityLog#TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT}.
-         */
-        public @SECURITY_LOG_TAG int getTag() {
-            return mEvent.getTag();
-        }
-
-        /**
-         * Returns the payload contained in this log. Each call to this method will
-         * retrieve the next payload item. If no more payload exists, it returns {@code null}.
-         */
-        public Object getData() {
-            return mEvent.getData();
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeByteArray(mEvent.getBytes());
-        }
-
-        public static final Parcelable.Creator<SecurityEvent> CREATOR =
-                new Parcelable.Creator<SecurityEvent>() {
-            @Override
-            public SecurityEvent createFromParcel(Parcel source) {
-                return new SecurityEvent(source.createByteArray());
-            }
-
-            @Override
-            public SecurityEvent[] newArray(int size) {
-                return new SecurityEvent[size];
-            }
-        };
-    }
-    /**
-     * Retrieve all security logs and return immediately.
-     * @hide
-     */
-    public static native void readEvents(Collection<SecurityEvent> output) throws IOException;
-
-    /**
-     * Retrieve all security logs since the given timestamp in nanoseconds and return immediately.
-     * @hide
-     */
-    public static native void readEventsSince(long timestamp, Collection<SecurityEvent> output)
-            throws IOException;
-
-    /**
-     * Retrieve all security logs before the last reboot. May return corrupted data due to
-     * unreliable pstore.
-     * @hide
-     */
-    public static native void readPreviousEvents(Collection<SecurityEvent> output)
-            throws IOException;
-
-    /**
-     * Retrieve all security logs whose timestamp (in nanosceonds) is equal to or greater than the
-     * given timestamp. This method will block until either the last log earlier than the given
-     * timestamp is about to be pruned, or after a 2-hour timeout has passed.
-     * @hide
-     */
-    public static native void readEventsOnWrapping(long timestamp, Collection<SecurityEvent> output)
-            throws IOException;
-
-    /**
-     * Write a log entry to the underlying storage, with a string payload.
-     * @hide
-     */
-    public static native int writeEvent(int tag, String str);
-
-    /**
-     * Write a log entry to the underlying storage, with several payloads.
-     * Supported types of payload are: integer, long, float, string plus array of supported types.
-     * @hide
-     */
-    public static native int writeEvent(int tag, Object... payloads);
-}
diff --git a/core/java/android/auditing/SecurityLogTags.logtags b/core/java/android/auditing/SecurityLogTags.logtags
deleted file mode 100644
index ccc3799..0000000
--- a/core/java/android/auditing/SecurityLogTags.logtags
+++ /dev/null
@@ -1,12 +0,0 @@
-# See system/core/logcat/event.logtags for a description of the format of this file.
-
-option java_package android.auditing
-
-210001 security_adb_shell_interactive
-210002 security_adb_shell_command               (command|3)
-210003 security_adb_sync_recv                   (path|3)
-210004 security_adb_sync_send                   (path|3)
-210005 security_app_process_start               (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
-210006 security_keyguard_dismissed
-210007 security_keyguard_dismiss_auth_attempt   (success|1),(method_strength|1)
-210008 security_keyguard_secured
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index eb4cb91..2a7eff8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2015 The Android Open Source Project
+ * Copyright (C) 2009-2016 The Android Open Source Project
  * Copyright (C) 2015 Samsung LSI
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,6 +36,7 @@
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Pair;
 
@@ -1015,6 +1016,8 @@
         try {
             if (mService != null) {
                 return mService.factoryReset();
+            } else {
+                SystemProperties.set("persist.bluetooth.factoryreset", "true");
             }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
@@ -1837,6 +1840,9 @@
         } else if (profile == BluetoothProfile.SAP) {
             BluetoothSap sap = new BluetoothSap(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.PBAP_CLIENT) {
+            BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener);
+            return true;
         } else {
             return false;
         }
@@ -1905,6 +1911,10 @@
                 BluetoothSap sap = (BluetoothSap)proxy;
                 sap.close();
                 break;
+            case BluetoothProfile.PBAP_CLIENT:
+                BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy;
+                pbapClient.close();
+                break;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ea2dca0..b8a40dc 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -197,109 +197,43 @@
             }
 
             /**
-             * A new GATT service has been discovered.
-             * The service is added to the internal list and the search
-             * continues.
-             * @hide
-             */
-            public void onGetService(String address, int srvcType,
-                                     int srvcInstId, ParcelUuid srvcUuid) {
-                if (VDBG) Log.d(TAG, "onGetService() - Device=" + address + " UUID=" + srvcUuid);
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                mServices.add(new BluetoothGattService(mDevice, srvcUuid.getUuid(),
-                                                       srvcInstId, srvcType));
-            }
-
-            /**
-             * An included service has been found durig GATT discovery.
-             * The included service is added to the respective parent.
-             * @hide
-             */
-            public void onGetIncludedService(String address, int srvcType,
-                                             int srvcInstId, ParcelUuid srvcUuid,
-                                             int inclSrvcType, int inclSrvcInstId,
-                                             ParcelUuid inclSrvcUuid) {
-                if (VDBG) Log.d(TAG, "onGetIncludedService() - Device=" + address
-                    + " UUID=" + srvcUuid + " Included=" + inclSrvcUuid);
-
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                BluetoothGattService service = getService(mDevice,
-                        srvcUuid.getUuid(), srvcInstId, srvcType);
-                BluetoothGattService includedService = getService(mDevice,
-                        inclSrvcUuid.getUuid(), inclSrvcInstId, inclSrvcType);
-
-                if (service != null && includedService != null) {
-                    service.addIncludedService(includedService);
-                }
-            }
-
-            /**
-             * A new GATT characteristic has been discovered.
-             * Add the new characteristic to the relevant service and continue
-             * the remote device inspection.
-             * @hide
-             */
-            public void onGetCharacteristic(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int charProps) {
-                if (VDBG) Log.d(TAG, "onGetCharacteristic() - Device=" + address + " UUID=" +
-                               charUuid);
-
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service != null) {
-                    service.addCharacteristic(new BluetoothGattCharacteristic(
-                           service, charUuid.getUuid(), charInstId, charProps, 0));
-                }
-            }
-
-            /**
-             * A new GATT descriptor has been discovered.
-             * Finally, add the descriptor to the related characteristic.
-             * This should conclude the remote device update.
-             * @hide
-             */
-            public void onGetDescriptor(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int descrInstId, ParcelUuid descUuid) {
-                if (VDBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid);
-
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                    charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
-
-                characteristic.addDescriptor(new BluetoothGattDescriptor(
-                    characteristic, descUuid.getUuid(), descrInstId, 0));
-            }
-
-            /**
              * Remote search has been completed.
              * The internal object structure should now reflect the state
              * of the remote device database. Let the application know that
              * we are done at this point.
              * @hide
              */
-            public void onSearchComplete(String address, int status) {
+            public void onSearchComplete(String address, List<BluetoothGattService> services,
+                                         int status) {
                 if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status);
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                for (BluetoothGattService s : services) {
+                    //services we receive don't have device set properly.
+                    s.setDevice(mDevice);
+                }
+
+                mServices.addAll(services);
+
+                // Fix references to included services, as they doesn't point to right objects.
+                for (BluetoothGattService fixedService : mServices) {
+                    ArrayList<BluetoothGattService> includedServices =
+                        new ArrayList(fixedService.getIncludedServices());
+                    fixedService.getIncludedServices().clear();
+
+                    for(BluetoothGattService brokenRef : includedServices) {
+                        BluetoothGattService includedService = getService(mDevice,
+                            brokenRef.getUuid(), brokenRef.getInstanceId(), brokenRef.getType());
+                        if (includedService != null) {
+                            fixedService.addIncludedService(includedService);
+                        } else {
+                            Log.e(TAG, "Broken GATT database: can't find included service.");
+                        }
+                    }
+                }
+
                 try {
                     mCallback.onServicesDiscovered(BluetoothGatt.this, status);
                 } catch (Exception ex) {
@@ -312,11 +246,12 @@
              * Updates the internal value.
              * @hide
              */
-            public void onCharacteristicRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid, byte[] value) {
+            public void onCharacteristicRead(String address, int status, int handle, byte[] value) {
                 if (VDBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address
-                            + " UUID=" + charUuid + " Status=" + status);
+                            + " handle=" + handle + " Status=" + status);
+
+                 Log.w(TAG, "onCharacteristicRead() - Device=" + address
+                            + " handle=" + handle + " Status=" + status);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -331,9 +266,7 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.readCharacteristic(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid,
-                            charInstId, charUuid, AUTHENTICATION_MITM);
+                        mService.readCharacteristic(mClientIf, address, handle, AUTHENTICATION_MITM);
                         return;
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
@@ -342,13 +275,11 @@
 
                 mAuthRetry = false;
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
+                BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
+                if (characteristic == null) {
+                    Log.w(TAG, "onCharacteristicRead() failed to find characteristic!");
+                    return;
+                }
 
                 if (status == 0) characteristic.setValue(value);
 
@@ -364,11 +295,9 @@
              * Let the app know how we did...
              * @hide
              */
-            public void onCharacteristicWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid) {
+            public void onCharacteristicWrite(String address, int status, int handle) {
                 if (VDBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address
-                            + " UUID=" + charUuid + " Status=" + status);
+                            + " handle=" + handle + " Status=" + status);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -378,12 +307,7 @@
                     mDeviceBusy = false;
                 }
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
+                BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
                 if (characteristic == null) return;
 
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
@@ -391,8 +315,7 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.writeCharacteristic(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
+                        mService.writeCharacteristic(mClientIf, address, handle,
                             characteristic.getWriteType(), AUTHENTICATION_MITM,
                             characteristic.getValue());
                         return;
@@ -415,21 +338,14 @@
              * Updates the internal value.
              * @hide
              */
-            public void onNotify(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             byte[] value) {
-                if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " UUID=" + charUuid);
+            public void onNotify(String address, int handle, byte[] value) {
+                if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " handle=" + handle);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
 
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
+                BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
                 if (characteristic == null) return;
 
                 characteristic.setValue(value);
@@ -445,12 +361,8 @@
              * Descriptor has been read.
              * @hide
              */
-            public void onDescriptorRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int descrInstId, ParcelUuid descrUuid,
-                             byte[] value) {
-                if (VDBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid);
+            public void onDescriptorRead(String address, int status, int handle, byte[] value) {
+                if (VDBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " handle=" + handle);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -460,16 +372,7 @@
                     mDeviceBusy = false;
                 }
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
-
-                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
-                        descrUuid.getUuid(), descrInstId);
+                BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
                 if (descriptor == null) return;
 
                 if (status == 0) descriptor.setValue(value);
@@ -479,9 +382,7 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.readDescriptor(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
-                            descrInstId, descrUuid, AUTHENTICATION_MITM);
+                        mService.readDescriptor(mClientIf, address, handle, AUTHENTICATION_MITM);
                         return;
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
@@ -501,11 +402,8 @@
              * Descriptor write operation complete.
              * @hide
              */
-            public void onDescriptorWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int descrInstId, ParcelUuid descrUuid) {
-                if (VDBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid);
+            public void onDescriptorWrite(String address, int status, int handle) {
+                if (VDBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " handle=" + handle);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -515,16 +413,7 @@
                     mDeviceBusy = false;
                 }
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
-
-                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
-                        descrUuid.getUuid(), descrInstId);
+                BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
                 if (descriptor == null) return;
 
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
@@ -532,9 +421,8 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.writeDescriptor(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
-                            descrInstId, descrUuid, characteristic.getWriteType(),
+                        mService.writeDescriptor(mClientIf, address, handle,
+                            BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT,
                             AUTHENTICATION_MITM, descriptor.getValue());
                         return;
                     } catch (RemoteException e) {
@@ -651,6 +539,36 @@
 
 
     /**
+     * Returns a characteristic with id equal to instanceId.
+     * @hide
+     */
+    /*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device, int instanceId) {
+        for(BluetoothGattService svc : mServices) {
+            for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
+                if (charac.getInstanceId() == instanceId)
+                    return charac;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a descriptor with id equal to instanceId.
+     * @hide
+     */
+    /*package*/ BluetoothGattDescriptor getDescriptorById(BluetoothDevice device, int instanceId) {
+        for(BluetoothGattService svc : mServices) {
+            for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
+                for(BluetoothGattDescriptor desc : charac.getDescriptors()) {
+                    if (desc.getInstanceId() == instanceId)
+                        return desc;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Register an application callback to start using GATT.
      *
      * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
@@ -898,9 +816,7 @@
 
         try {
             mService.readCharacteristic(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()), AUTHENTICATION_NONE);
+                characteristic.getInstanceId(), AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             mDeviceBusy = false;
@@ -943,11 +859,8 @@
 
         try {
             mService.writeCharacteristic(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()),
-                characteristic.getWriteType(), AUTHENTICATION_NONE,
-                characteristic.getValue());
+                characteristic.getInstanceId(), characteristic.getWriteType(),
+                AUTHENTICATION_NONE, characteristic.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             mDeviceBusy = false;
@@ -988,11 +901,8 @@
         }
 
         try {
-            mService.readDescriptor(mClientIf, device.getAddress(), service.getType(),
-                service.getInstanceId(), new ParcelUuid(service.getUuid()),
-                characteristic.getInstanceId(), new ParcelUuid(characteristic.getUuid()),
-                descriptor.getInstanceId(), new ParcelUuid(descriptor.getUuid()),
-                AUTHENTICATION_NONE);
+            mService.readDescriptor(mClientIf, device.getAddress(),
+                descriptor.getInstanceId(), AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             mDeviceBusy = false;
@@ -1032,11 +942,8 @@
         }
 
         try {
-            mService.writeDescriptor(mClientIf, device.getAddress(), service.getType(),
-                service.getInstanceId(), new ParcelUuid(service.getUuid()),
-                characteristic.getInstanceId(), new ParcelUuid(characteristic.getUuid()),
-                descriptor.getInstanceId(), new ParcelUuid(descriptor.getUuid()),
-                characteristic.getWriteType(), AUTHENTICATION_NONE,
+            mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
+                BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, AUTHENTICATION_NONE,
                 descriptor.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
@@ -1168,10 +1075,7 @@
 
         try {
             mService.registerForNotification(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()),
-                enable);
+                characteristic.getInstanceId(), enable);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
index 01778b3..17e533a 100644
--- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
+++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.le.AdvertiseSettings;
 import android.bluetooth.le.ScanResult;
+import android.bluetooth.BluetoothGattService;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 
@@ -48,41 +49,17 @@
     }
 
     @Override
-    public void onGetService(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid)
+    public void onSearchComplete(String address, List<BluetoothGattService> services,
+            int status) throws RemoteException {
+    }
+
+    @Override
+    public void onCharacteristicRead(String address, int status, int handle, byte[] value)
             throws RemoteException {
     }
 
     @Override
-    public void onGetIncludedService(String address, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int inclSrvcType, int inclSrvcInstId, ParcelUuid inclSrvcUuid)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onGetCharacteristic(String address, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int charProps)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onGetDescriptor(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid,
-            int charInstId, ParcelUuid charUuid, int descrInstId, ParcelUuid descrUuid)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onSearchComplete(String address, int status) throws RemoteException {
-    }
-
-    @Override
-    public void onCharacteristicRead(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onCharacteristicWrite(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid) throws RemoteException {
+    public void onCharacteristicWrite(String address, int status, int handle) throws RemoteException {
     }
 
     @Override
@@ -90,20 +67,15 @@
     }
 
     @Override
-    public void onDescriptorRead(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int descrInstId,
-            ParcelUuid descrUuid, byte[] value) throws RemoteException {
+    public void onDescriptorRead(String address, int status, int handle, byte[] value) throws RemoteException {
     }
 
     @Override
-    public void onDescriptorWrite(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int descrInstId,
-            ParcelUuid descrUuid) throws RemoteException {
+    public void onDescriptorWrite(String address, int status, int handle) throws RemoteException {
     }
 
     @Override
-    public void onNotify(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid,
-            int charInstId, ParcelUuid charUuid, byte[] value) throws RemoteException {
+    public void onNotify(String address, int handle, byte[] value) throws RemoteException {
     }
 
     @Override
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.aidl b/core/java/android/bluetooth/BluetoothGattCharacteristic.aidl
new file mode 100644
index 0000000..bbb8623
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+parcelable BluetoothGattCharacteristic;
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 7cdcc2c..01f82e6 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -15,6 +15,9 @@
  */
 package android.bluetooth;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -26,7 +29,7 @@
  * {@link BluetoothGattService}. The characteristic contains a value as well as
  * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}.
  */
-public class BluetoothGattCharacteristic {
+public class BluetoothGattCharacteristic implements Parcelable {
 
     /**
      * Characteristic proprty: Characteristic is broadcastable.
@@ -242,6 +245,15 @@
         initCharacteristic(service, uuid, instanceId, properties, permissions);
     }
 
+    /**
+     * Create a new BluetoothGattCharacteristic
+     * @hide
+     */
+    public BluetoothGattCharacteristic(UUID uuid, int instanceId,
+                                       int properties, int permissions) {
+        initCharacteristic(null, uuid, instanceId, properties, permissions);
+    }
+
     private void initCharacteristic(BluetoothGattService service,
                                     UUID uuid, int instanceId,
                                     int properties, int permissions) {
@@ -261,6 +273,54 @@
     }
 
     /**
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstance);
+        out.writeInt(mProperties);
+        out.writeInt(mPermissions);
+        out.writeInt(mKeySize);
+        out.writeInt(mWriteType);
+        out.writeTypedList(mDescriptors);
+    }
+
+    public static final Parcelable.Creator<BluetoothGattCharacteristic> CREATOR
+            = new Parcelable.Creator<BluetoothGattCharacteristic>() {
+        public BluetoothGattCharacteristic createFromParcel(Parcel in) {
+            return new BluetoothGattCharacteristic(in);
+        }
+
+        public BluetoothGattCharacteristic[] newArray(int size) {
+            return new BluetoothGattCharacteristic[size];
+        }
+    };
+
+    private BluetoothGattCharacteristic(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstance = in.readInt();
+        mProperties = in.readInt();
+        mPermissions = in.readInt();
+        mKeySize = in.readInt();
+        mWriteType = in.readInt();
+
+        mDescriptors = new ArrayList<BluetoothGattDescriptor>();
+
+        ArrayList<BluetoothGattDescriptor> descs =
+                in.createTypedArrayList(BluetoothGattDescriptor.CREATOR);
+        if (descs != null) {
+            for (BluetoothGattDescriptor desc: descs) {
+                desc.setCharacteristic(this);
+                mDescriptors.add(desc);
+            }
+        }
+    }
+
+    /**
      * Returns the deisred key size.
      * @hide
      */
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.aidl b/core/java/android/bluetooth/BluetoothGattDescriptor.aidl
new file mode 100644
index 0000000..4393273
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+parcelable BluetoothGattDescriptor;
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index 5f525dc..28317c4 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
 import java.util.UUID;
 
 /**
@@ -25,7 +28,7 @@
  * characteristic, {@link BluetoothGattCharacteristic}. They can be used to describe
  * the characteristic's features or to control certain behaviours of the characteristic.
  */
-public class BluetoothGattDescriptor {
+public class BluetoothGattDescriptor implements Parcelable {
 
     /**
      * Value used to enable notification for a client configuration descriptor
@@ -138,6 +141,13 @@
         initDescriptor(characteristic, uuid, instance, permissions);
     }
 
+    /**
+     * @hide
+     */
+    public BluetoothGattDescriptor(UUID uuid, int instance, int permissions) {
+        initDescriptor(null, uuid, instance, permissions);
+    }
+
     private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
                                 int instance, int permissions) {
         mCharacteristic = characteristic;
@@ -147,6 +157,36 @@
     }
 
     /**
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstance);
+        out.writeInt(mPermissions);
+    }
+
+    public static final Parcelable.Creator<BluetoothGattDescriptor> CREATOR
+            = new Parcelable.Creator<BluetoothGattDescriptor>() {
+        public BluetoothGattDescriptor createFromParcel(Parcel in) {
+            return new BluetoothGattDescriptor(in);
+        }
+
+        public BluetoothGattDescriptor[] newArray(int size) {
+            return new BluetoothGattDescriptor[size];
+        }
+    };
+
+    private BluetoothGattDescriptor(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstance = in.readInt();
+        mPermissions = in.readInt();
+    }
+
+    /**
      * Returns the characteristic this descriptor belongs to.
      * @return The characteristic.
      */
diff --git a/core/java/android/bluetooth/BluetoothGattIncludedService.aidl b/core/java/android/bluetooth/BluetoothGattIncludedService.aidl
new file mode 100644
index 0000000..1ef427e
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattIncludedService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+parcelable BluetoothGattIncludedService;
diff --git a/core/java/android/bluetooth/BluetoothGattIncludedService.java b/core/java/android/bluetooth/BluetoothGattIncludedService.java
new file mode 100644
index 0000000..155dc57
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattIncludedService.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Represents a Bluetooth GATT Included Service
+ * @hide
+ */
+public class BluetoothGattIncludedService implements Parcelable {
+
+    /**
+     * The UUID of this service.
+     */
+    protected UUID mUuid;
+
+    /**
+     * Instance ID for this service.
+     */
+    protected int mInstanceId;
+
+    /**
+     * Service type (Primary/Secondary).
+     */
+    protected int mServiceType;
+
+    /**
+     * Create a new BluetoothGattIncludedService
+     */
+    public BluetoothGattIncludedService(UUID uuid, int instanceId, int serviceType) {
+        mUuid = uuid;
+        mInstanceId = instanceId;
+        mServiceType = serviceType;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstanceId);
+        out.writeInt(mServiceType);
+     }
+
+    public static final Parcelable.Creator<BluetoothGattIncludedService> CREATOR
+            = new Parcelable.Creator<BluetoothGattIncludedService>() {
+        public BluetoothGattIncludedService createFromParcel(Parcel in) {
+            return new BluetoothGattIncludedService(in);
+        }
+
+        public BluetoothGattIncludedService[] newArray(int size) {
+            return new BluetoothGattIncludedService[size];
+        }
+    };
+
+    private BluetoothGattIncludedService(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstanceId = in.readInt();
+        mServiceType = in.readInt();
+    }
+
+    /**
+     * Returns the UUID of this service
+     *
+     * @return UUID of this service
+     */
+    public UUID getUuid() {
+        return mUuid;
+    }
+
+    /**
+     * Returns the instance ID for this service
+     *
+     * <p>If a remote device offers multiple services with the same UUID
+     * (ex. multiple battery services for different batteries), the instance
+     * ID is used to distuinguish services.
+     *
+     * @return Instance ID of this service
+     */
+    public int getInstanceId() {
+        return mInstanceId;
+    }
+
+    /**
+     * Get the type of this service (primary/secondary)
+     */
+    public int getType() {
+        return mServiceType;
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothGattService.aidl b/core/java/android/bluetooth/BluetoothGattService.aidl
new file mode 100644
index 0000000..84314d2
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+parcelable BluetoothGattService;
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 52bc0f7..a4e1dc0 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -15,6 +15,9 @@
  */
 package android.bluetooth;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -25,7 +28,7 @@
  * <p> Gatt Service contains a collection of {@link BluetoothGattCharacteristic},
  * as well as referenced services.
  */
-public class BluetoothGattService {
+public class BluetoothGattService implements Parcelable {
 
     /**
      * Primary service
@@ -117,6 +120,81 @@
     }
 
     /**
+     * Create a new BluetoothGattService
+     * @hide
+     */
+    public BluetoothGattService(UUID uuid, int instanceId, int serviceType) {
+        mDevice = null;
+        mUuid = uuid;
+        mInstanceId = instanceId;
+        mServiceType = serviceType;
+        mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
+        mIncludedServices = new ArrayList<BluetoothGattService>();
+    }
+
+    /**
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstanceId);
+        out.writeInt(mServiceType);
+        out.writeTypedList(mCharacteristics);
+
+        ArrayList<BluetoothGattIncludedService> includedServices =
+                new ArrayList<BluetoothGattIncludedService>(mIncludedServices.size());
+        for(BluetoothGattService s : mIncludedServices) {
+            includedServices.add(new BluetoothGattIncludedService(s.getUuid(),
+                                                                  s.getInstanceId(), s.getType()));
+        }
+        out.writeTypedList(includedServices);
+     }
+
+    public static final Parcelable.Creator<BluetoothGattService> CREATOR
+            = new Parcelable.Creator<BluetoothGattService>() {
+        public BluetoothGattService createFromParcel(Parcel in) {
+            return new BluetoothGattService(in);
+        }
+
+        public BluetoothGattService[] newArray(int size) {
+            return new BluetoothGattService[size];
+        }
+    };
+
+    private BluetoothGattService(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstanceId = in.readInt();
+        mServiceType = in.readInt();
+
+        mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
+
+        ArrayList<BluetoothGattCharacteristic> chrcs =
+                in.createTypedArrayList(BluetoothGattCharacteristic.CREATOR);
+        if (chrcs != null) {
+            for (BluetoothGattCharacteristic chrc : chrcs) {
+                chrc.setService(this);
+                mCharacteristics.add(chrc);
+            }
+        }
+
+        mIncludedServices = new ArrayList<BluetoothGattService>();
+
+        ArrayList<BluetoothGattIncludedService> inclSvcs =
+                in.createTypedArrayList(BluetoothGattIncludedService.CREATOR);
+        if (chrcs != null) {
+            for (BluetoothGattIncludedService isvc : inclSvcs) {
+                mIncludedServices.add(new BluetoothGattService(null, isvc.getUuid(),
+                                                            isvc.getInstanceId(), isvc.getType()));
+            }
+        }
+    }
+
+    /**
      * Returns the device associated with this service.
      * @hide
      */
@@ -125,6 +203,14 @@
     }
 
     /**
+     * Returns the device associated with this service.
+     * @hide
+     */
+    /*package*/ void setDevice(BluetoothDevice device) {
+        this.mDevice = device;
+    }
+
+    /**
      * Add an included service to this service.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
@@ -192,7 +278,7 @@
      * Add an included service to the internal map.
      * @hide
      */
-    /*package*/ void addIncludedService(BluetoothGattService includedService) {
+    public void addIncludedService(BluetoothGattService includedService) {
         mIncludedServices.add(includedService);
     }
 
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index e355a1c..35437a1 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -144,7 +144,7 @@
     }
 
     /**
-     * 
+     *
      * Get a list of devices that match any of the given connection
      * states.
      *
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
new file mode 100644
index 0000000..eab4c6f
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 java.util.List;
+import java.util.ArrayList;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * This class provides the APIs to control the Bluetooth PBAP Client Profile.
+ *@hide
+ */
+public final class BluetoothPbapClient implements BluetoothProfile {
+
+    private static final String TAG = "BluetoothPbapClient";
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
+
+    private IBluetoothPbapClient mService;
+    private final Context mContext;
+    private ServiceListener mServiceListener;
+    private BluetoothAdapter mAdapter;
+
+    /** There was an error trying to obtain the state */
+    public static final int STATE_ERROR        = -1;
+
+    public static final int RESULT_FAILURE = 0;
+    public static final int RESULT_SUCCESS = 1;
+    /** Connection canceled before completion. */
+    public static final int RESULT_CANCELED = 2;
+
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) {
+                        Log.d(TAG, "onBluetoothStateChange: PBAP CLIENT up=" + up);
+                    }
+                    if (!up) {
+                        if (VDBG) {
+                            Log.d(TAG,"Unbinding service...");
+                        }
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (VDBG) {
+                                        Log.d(TAG,"Binding service...");
+                                    }
+                                    doBind();
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+
+    /**
+     * Create a BluetoothPbapClient proxy object.
+     */
+    BluetoothPbapClient(Context context, ServiceListener l) {
+        if (DBG) {
+            Log.d(TAG, "Create BluetoothPbapClient proxy object");
+        }
+        mContext = context;
+        mServiceListener = l;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+        doBind();
+    }
+
+    private boolean doBind() {
+        Intent intent = new Intent(IBluetoothPbapClient.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+                android.os.Process.myUserHandle())) {
+            Log.e(TAG, "Could not bind to Bluetooth PBAP Client Service with " + intent);
+            return false;
+        }
+        return true;
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Close the connection to the backing service.
+     * Other public functions of BluetoothPbapClient will return default error
+     * results once close() has been called. Multiple invocations of close()
+     * are ok.
+     */
+    public synchronized void close() {
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
+        }
+        mServiceListener = null;
+    }
+
+    /**
+     * Initiate connection.
+     * Upon successful connection to remote PBAP server the Client will
+     * attempt to automatically download the users phonebook and call log.
+     *
+     * @param device    a remote device we want connect to
+     * @return <code>true</code> if command has been issued successfully;
+     *         <code>false</code> otherwise;
+     */
+    public boolean connect(BluetoothDevice device) {
+        if (DBG) {
+            log("connect(" + device + ") for PBAP Client.");
+        }
+        if (mService != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return mService.connect(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return false;
+    }
+
+    /**
+     * Initiate disconnect.
+     *
+     * @param device Remote Bluetooth Device
+     * @return false on error,
+     *               true otherwise
+     */
+    public boolean disconnect(BluetoothDevice device) {
+        if (DBG) {
+            log("disconnect(" + device + ")" + new Exception() );
+        }
+        if (mService != null && isEnabled() && isValidDevice(device)) {
+            try {
+                mService.disconnect(device);
+                return true;
+            } catch (RemoteException e) {
+              Log.e(TAG, Log.getStackTraceString(new Throwable()));
+              return false;
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return false;
+    }
+
+    /**
+     * Get the list of connected devices.
+     * Currently at most one.
+     *
+     * @return list of connected devices
+     */
+    @Override
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (DBG) {
+            log("getConnectedDevices()");
+        }
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get the list of devices matching specified states. Currently at most one.
+     *
+     * @return list of matching devices
+     */
+    @Override
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (DBG) {
+            log("getDevicesMatchingStates()");
+        }
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get connection state of device
+     *
+     * @return device connection state
+     */
+    @Override
+    public int getConnectionState(BluetoothDevice device) {
+        if (DBG) {
+            log("getConnectionState(" + device + ")");
+        }
+        if (mService != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return mService.getConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) {
+                log("Proxy object connected");
+            }
+            mService = IBluetoothPbapClient.Stub.asInterface(service);
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, BluetoothPbapClient.this);
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) {
+                log("Proxy object disconnected");
+            }
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP_CLIENT);
+            }
+        }
+    };
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+
+    private boolean isEnabled() {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
+            return true;
+        }
+        log("Bluetooth is Not enabled");
+        return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) {
+           return false;
+       }
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
+           return true;
+       }
+       return false;
+    }
+
+    /**
+     * Set priority of the profile
+     *
+     * <p> The device should already be paired.
+     *  Priority can be one of {@link #PRIORITY_ON} or
+     * {@link #PRIORITY_OFF},
+     *
+     * @param device Paired bluetooth device
+     * @param priority
+     * @return true if priority is set, false on error
+     */
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) {
+            log("setPriority(" + device + ", " + priority + ")");
+        }
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            if (priority != BluetoothProfile.PRIORITY_OFF &&
+                priority != BluetoothProfile.PRIORITY_ON) {
+              return false;
+            }
+            try {
+                return mService.setPriority(device, priority);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return false;
+    }
+
+    /**
+     * Get the priority of the profile.
+     *
+     * <p> The priority can be any of:
+     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     *
+     * @param device Bluetooth device
+     * @return priority of the device
+     */
+    public int getPriority(BluetoothDevice device) {
+        if (VDBG) {
+            log("getPriority(" + device + ")");
+        }
+        if (mService != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return mService.getPriority(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return PRIORITY_OFF;
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return PRIORITY_OFF;
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index cbce22c..eee66d1 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -131,6 +131,12 @@
     public static final int HEADSET_CLIENT = 16;
 
     /**
+     * PBAP Client
+     * @hide
+     */
+    public static final int PBAP_CLIENT = 17;
+
+    /**
      * Default priority for devices that we try to auto-connect to and
      * and allow incoming connections for the profile
      * @hide
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 6b5f77f..adb07df 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -51,28 +51,13 @@
     void clientDisconnect(in int clientIf, in String address);
     void refreshDevice(in int clientIf, in String address);
     void discoverServices(in int clientIf, in String address);
-    void readCharacteristic(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in int authReq);
-    void writeCharacteristic(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
+    void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
+    void writeCharacteristic(in int clientIf, in String address, in int handle,
                             in int writeType, in int authReq, in byte[] value);
-    void readDescriptor(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in int descrInstanceId, in ParcelUuid descrUuid,
-                            in int authReq);
-    void writeDescriptor(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in int descrInstanceId, in ParcelUuid descrId,
+    void readDescriptor(in int clientIf, in String address, in int handle, in int authReq);
+    void writeDescriptor(in int clientIf, in String address, in int handle,
                             in int writeType, in int authReq, in byte[] value);
-    void registerForNotification(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in boolean enable);
+    void registerForNotification(in int clientIf, in String address, in int handle, in boolean enable);
     void beginReliableWrite(in int clientIf, in String address);
     void endReliableWrite(in int clientIf, in String address, in boolean execute);
     void readRemoteRssi(in int clientIf, in String address);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index cbba9f0..7163c37 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -16,6 +16,7 @@
 package android.bluetooth;
 
 import android.os.ParcelUuid;
+import android.bluetooth.BluetoothGattService;
 import android.bluetooth.le.AdvertiseSettings;
 import android.bluetooth.le.ScanResult;
 
@@ -29,41 +30,13 @@
                                  in boolean connected, in String address);
     void onScanResult(in ScanResult scanResult);
     void onBatchScanResults(in List<ScanResult> batchResults);
-    void onGetService(in String address, in int srvcType, in int srvcInstId,
-                      in ParcelUuid srvcUuid);
-    void onGetIncludedService(in String address, in int srvcType, in int srvcInstId,
-                              in ParcelUuid srvcUuid, in int inclSrvcType,
-                              in int inclSrvcInstId, in ParcelUuid inclSrvcUuid);
-    void onGetCharacteristic(in String address, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int charProps);
-    void onGetDescriptor(in String address, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int descrInstId, in ParcelUuid descrUuid);
-    void onSearchComplete(in String address, in int status);
-    void onCharacteristicRead(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in byte[] value);
-    void onCharacteristicWrite(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid);
+    void onSearchComplete(in String address, in List<BluetoothGattService> services, in int status);
+    void onCharacteristicRead(in String address, in int status, in int handle, in byte[] value);
+    void onCharacteristicWrite(in String address, in int status, in int handle);
     void onExecuteWrite(in String address, in int status);
-    void onDescriptorRead(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int descrInstId, in ParcelUuid descrUuid,
-                             in byte[] value);
-    void onDescriptorWrite(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int descrInstId, in ParcelUuid descrUuid);
-    void onNotify(in String address, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in byte[] value);
+    void onDescriptorRead(in String address, in int status, in int handle, in byte[] value);
+    void onDescriptorWrite(in String address, in int status, in int handle);
+    void onNotify(in String address, in int handle, in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
     void onMultiAdvertiseCallback(in int status, boolean isStart,
                                   in AdvertiseSettings advertiseSettings);
diff --git a/core/java/android/bluetooth/IBluetoothManagerCallback.aidl b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
index 1385daf..8104d21 100644
--- a/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
@@ -23,7 +23,7 @@
  *
  * {@hide}
  */
-interface IBluetoothManagerCallback {
+oneway interface IBluetoothManagerCallback {
     void onBluetoothServiceUp(in IBluetooth bluetoothService);
     void onBluetoothServiceDown();
     void onBrEdrDown();
diff --git a/core/java/android/bluetooth/IBluetoothPbapClient.aidl b/core/java/android/bluetooth/IBluetoothPbapClient.aidl
new file mode 100644
index 0000000..6d4c5a6
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothPbapClient.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Phone Book Access Provile Client Side
+ *
+ * {@hide}
+ */
+interface IBluetoothPbapClient {
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+}
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index 01f72ef..70d47ee 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -23,6 +23,7 @@
 
 /**
  * Out Of Band Data for Bluetooth device.
+ * @hide
  */
 public class OobData implements Parcelable {
     private byte[] securityManagerTk;
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 0ec58ea..58630b0 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -836,6 +836,17 @@
         }
     }
 
+    /** {@hide} */
+    public void prepareToEnterProcess() {
+        final int size = mItems.size();
+        for (int i = 0; i < size; i++) {
+            final Item item = mItems.get(i);
+            if (item.mIntent != null) {
+                item.mIntent.prepareToEnterProcess();
+            }
+        }
+    }
+
     /** @hide */
     public void fixUris(int contentUserHint) {
         final int size = mItems.size();
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index e67da2b..1266f73 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -122,6 +122,7 @@
             }
             getService().setPrimaryClip(clip, mContext.getOpPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -132,7 +133,7 @@
         try {
             return getService().getPrimaryClip(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -144,7 +145,7 @@
         try {
             return getService().getPrimaryClipDescription(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -155,7 +156,7 @@
         try {
             return getService().hasPrimaryClip(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -166,6 +167,7 @@
                     getService().addPrimaryClipChangedListener(
                             mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
             mPrimaryClipChangedListeners.add(what);
@@ -180,6 +182,7 @@
                     getService().removePrimaryClipChangedListener(
                             mPrimaryClipChangedServiceListener);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
         }
@@ -213,7 +216,7 @@
         try {
             return getService().hasClipboardText(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 1c3f45c..bc2d788 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -394,6 +394,7 @@
         @Override
         public Bundle call(
                 String callingPkg, String method, @Nullable String arg, @Nullable Bundle extras) {
+            Bundle.setDefusable(extras, true);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.call(method, arg, extras);
@@ -412,6 +413,7 @@
         @Override
         public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
                 Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
+            Bundle.setDefusable(opts, true);
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
             enforceFilePermission(callingPkg, uri, "r", null);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 4e1b6e0..cd67b3e 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1412,7 +1412,9 @@
             throw new IllegalArgumentException("Unknown URI " + uri);
         }
         try {
-            return provider.call(mPackageName, method, arg, extras);
+            final Bundle res = provider.call(mPackageName, method, arg, extras);
+            Bundle.setDefusable(res, true);
+            return res;
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -2440,6 +2442,28 @@
         }
     }
 
+    /** {@hide} */
+    public void putCache(Uri key, Bundle value) {
+        try {
+            getContentService().putCache(mContext.getPackageName(), key, value,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** {@hide} */
+    public Bundle getCache(Uri key) {
+        try {
+            final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
+                    mContext.getUserId());
+            if (bundle != null) bundle.setClassLoader(mContext.getClassLoader());
+            return bundle;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Returns sampling percentage for a given duration.
      *
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0cdbef0..15cc17d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -691,24 +691,31 @@
      *
      * @see #getSharedPreferencesPath(String)
      * @see #MODE_PRIVATE
+     * @removed
      */
     public abstract SharedPreferences getSharedPreferences(File file, int mode);
 
     /**
-     * Migrate an existing shared preferences file from the given source storage
+     * Move an existing shared preferences file from the given source storage
      * context to this context. This is typically used to migrate data between
-     * storage locations after an upgrade, such as migrating from credential
-     * encrypted to device encrypted storage.
+     * storage locations after an upgrade, such as moving to device protected
+     * storage.
      *
      * @param sourceContext The source context which contains the existing
-     *            shared preferences to migrate.
+     *            shared preferences to move.
      * @param name The name of the shared preferences file.
-     * @return {@code true} if the migration was successful or if the shared
+     * @return {@code true} if the move was successful or if the shared
      *         preferences didn't exist in the source context, otherwise
      *         {@code false}.
-     * @see #createDeviceEncryptedStorageContext()
+     * @see #createDeviceProtectedStorageContext()
      */
-    public abstract boolean migrateSharedPreferencesFrom(Context sourceContext, String name);
+    public abstract boolean moveSharedPreferencesFrom(Context sourceContext, String name);
+
+    /** @removed */
+    @Deprecated
+    public boolean migrateSharedPreferencesFrom(Context sourceContext, String name) {
+        return moveSharedPreferencesFrom(sourceContext, name);
+    }
 
     /**
      * Delete an existing shared preferences file.
@@ -807,17 +814,16 @@
      *            to get a path.
      * @return An absolute path to the given file.
      * @see #getSharedPreferences(String, int)
+     * @removed
      */
     public abstract File getSharedPreferencesPath(String name);
 
     /**
      * Returns the absolute path to the directory on the filesystem where all
-     * private files belonging to this app are stored. This is the top-level
-     * directory under which {@link #getFilesDir()}, {@link #getCacheDir()}, etc
-     * are contained. Apps should <em>not</em> create any files or directories
-     * as direct children of this directory, since it's a reserved namespace
-     * belonging to the platform. Instead, use {@link #getDir(String, int)} or
-     * other storage APIs.
+     * private files belonging to this app are stored. Apps should not use this
+     * path directly; they should instead use {@link #getFilesDir()},
+     * {@link #getCacheDir()}, {@link #getDir(String, int)}, or other storage
+     * APIs on this class.
      * <p>
      * The returned path may change over time if the calling app is moved to an
      * adopted storage device, so only relative paths should be persisted.
@@ -825,7 +831,7 @@
      * No additional permissions are required for the calling app to read or
      * write files under the returned path.
      *
-     * @see #getDir(String, int)
+     * @see ApplicationInfo#dataDir
      */
     public abstract File getDataDir();
 
@@ -1397,19 +1403,25 @@
             @Nullable DatabaseErrorHandler errorHandler);
 
     /**
-     * Migrate an existing database file from the given source storage context
-     * to this context. This is typically used to migrate data between storage
-     * locations after an upgrade, such as migrating from credential encrypted
-     * to device encrypted storage.
+     * Move an existing database file from the given source storage context to
+     * this context. This is typically used to migrate data between storage
+     * locations after an upgrade, such as migrating to device protected
+     * storage.
      *
      * @param sourceContext The source context which contains the existing
-     *            database to migrate.
+     *            database to move.
      * @param name The name of the database file.
-     * @return {@code true} if the migration was successful or if the database
-     *         didn't exist in the source context, otherwise {@code false}.
-     * @see #createDeviceEncryptedStorageContext()
+     * @return {@code true} if the move was successful or if the database didn't
+     *         exist in the source context, otherwise {@code false}.
+     * @see #createDeviceProtectedStorageContext()
      */
-    public abstract boolean migrateDatabaseFrom(Context sourceContext, String name);
+    public abstract boolean moveDatabaseFrom(Context sourceContext, String name);
+
+    /** @removed */
+    @Deprecated
+    public boolean migrateDatabaseFrom(Context sourceContext, String name) {
+        return moveDatabaseFrom(sourceContext, name);
+    }
 
     /**
      * Delete an existing private SQLiteDatabase associated with this Context's
@@ -2680,6 +2692,8 @@
             RADIO_SERVICE,
             HARDWARE_PROPERTIES_SERVICE,
             //@hide: SOUND_TRIGGER_SERVICE,
+            SHORTCUT_SERVICE,
+            //@hide: CONTEXTHUB_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2741,7 +2755,7 @@
      * <dt> {@link #NETWORK_STATS_SERVICE} ("netstats")
      * <dd> A {@link android.app.usage.NetworkStatsManager NetworkStatsManager} for querying network
      * usage statistics.
-     * <dt> {@link #HARDWARE_PROPERTIES_SERVICE} ("hardwareproperties")
+     * <dt> {@link #HARDWARE_PROPERTIES_SERVICE} ("hardware_properties")
      * <dd> A {@link android.os.HardwarePropertiesManager} for accessing hardware properties.
      * </dl>
      *
@@ -2863,6 +2877,16 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.os.RecoverySystem} for accessing the recovery system
+     * service.
+     *
+     * @see #getSystemService
+     * @hide
+     */
+    public static final String RECOVERY_SERVICE = "recovery";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.view.WindowManager} for accessing the system's window
      * manager.
      *
@@ -3563,7 +3587,36 @@
      *
      * @see #getSystemService
      */
-    public static final String HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
+    public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
+
+    /**
+     * TODO Javadoc
+     *
+     * @see #getSystemService
+     * @see android.content.pm.ShortcutManager
+     */
+    public static final String SHORTCUT_SERVICE = "shortcut";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.hardware.location.ContextHubManager} for accessing context hubs.
+     *
+     * @see #getSystemService
+     * @see android.hardware.location.ContextHubManager
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String CONTEXTHUB_SERVICE = "contexthub";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.os.health.SystemHealthManager} for accessing system health (battery, power,
+     * memory, etc) metrics.
+     *
+     * @see #getSystemService
+     */
+    public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
 
     /**
      * Determine whether the given permission is allowed for a particular
@@ -3997,19 +4050,19 @@
 
     /**
      * Flag for use with {@link #createPackageContext}: point all file APIs at
-     * device-encrypted storage.
+     * device-protected storage.
      *
      * @hide
      */
-    public static final int CONTEXT_DEVICE_ENCRYPTED_STORAGE = 0x00000008;
+    public static final int CONTEXT_DEVICE_PROTECTED_STORAGE = 0x00000008;
 
     /**
      * Flag for use with {@link #createPackageContext}: point all file APIs at
-     * credential-encrypted storage.
+     * credential-protected storage.
      *
      * @hide
      */
-    public static final int CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE = 0x00000010;
+    public static final int CONTEXT_CREDENTIAL_PROTECTED_STORAGE = 0x00000010;
 
     /**
      * @hide Used to indicate we should tell the activity manager about the process
@@ -4113,53 +4166,73 @@
 
     /**
      * Return a new Context object for the current Context but whose storage
-     * APIs are backed by device-encrypted storage.
+     * APIs are backed by device-protected storage.
      * <p>
-     * Data stored in device-encrypted storage is typically encrypted with a key
-     * tied to the physical device, and it can be accessed when the device has
-     * booted successfully, both <em>before and after</em> the user has
-     * authenticated with their credentials (such as a lock pattern or PIN).
-     * Because device-encrypted data is available before user authentication,
-     * you should carefully consider what data you store using this Context.
+     * On devices with direct boot, data stored in this location is encrypted
+     * with a key tied to the physical device, and it can be accessed
+     * immediately after the device has booted successfully, both
+     * <em>before and after</em> the user has authenticated with their
+     * credentials (such as a lock pattern or PIN).
+     * <p>
+     * Because device-protected data is available without user authentication,
+     * you should carefully limit the data you store using this Context. For
+     * example, storing sensitive authentication tokens or passwords in the
+     * device-protected area is strongly discouraged.
      * <p>
      * If the underlying device does not have the ability to store
-     * device-encrypted and credential-encrypted data using different keys, then
-     * both storage areas will become available at the same time. They remain
-     * two distinct storage areas, and only the window of availability changes.
+     * device-protected and credential-protected data using different keys, then
+     * both storage areas will become available at the same time. They remain as
+     * two distinct storage locations on disk, and only the window of
+     * availability changes.
      * <p>
      * Each call to this method returns a new instance of a Context object;
      * Context objects are not shared, however common state (ClassLoader, other
      * Resources for the same configuration) may be so the Context itself can be
      * fairly lightweight.
      *
-     * @see #isDeviceEncryptedStorage()
+     * @see #isDeviceProtectedStorage()
      */
-    public abstract Context createDeviceEncryptedStorageContext();
+    public abstract Context createDeviceProtectedStorageContext();
+
+    /** @removed */
+    @Deprecated
+    public Context createDeviceEncryptedStorageContext() {
+        return createDeviceProtectedStorageContext();
+    }
 
     /**
      * Return a new Context object for the current Context but whose storage
-     * APIs are backed by credential-encrypted storage.
+     * APIs are backed by credential-protected storage. This is the default
+     * storage area for apps unless
+     * {@link android.R.attr#defaultToDeviceProtectedStorage} was requested.
      * <p>
-     * Data stored in credential-encrypted storage is typically encrypted with a
-     * key tied to user credentials, and they can be accessed
+     * On devices with direct boot, data stored in this location is encrypted
+     * with a key tied to user credentials, which can be accessed
      * <em>only after</em> the user has entered their credentials (such as a
      * lock pattern or PIN).
      * <p>
      * If the underlying device does not have the ability to store
-     * device-encrypted and credential-encrypted data using different keys, then
-     * both storage areas will become available at the same time. They remain
-     * two distinct storage areas, and only the window of availability changes.
+     * device-protected and credential-protected data using different keys, then
+     * both storage areas will become available at the same time. They remain as
+     * two distinct storage locations on disk, and only the window of
+     * availability changes.
      * <p>
      * Each call to this method returns a new instance of a Context object;
      * Context objects are not shared, however common state (ClassLoader, other
      * Resources for the same configuration) may be so the Context itself can be
      * fairly lightweight.
      *
-     * @see #isCredentialEncryptedStorage()
+     * @see #isCredentialProtectedStorage()
      * @hide
      */
     @SystemApi
-    public abstract Context createCredentialEncryptedStorageContext();
+    public abstract Context createCredentialProtectedStorageContext();
+
+    /** @removed */
+    @Deprecated
+    public Context createCredentialEncryptedStorageContext() {
+        return createCredentialProtectedStorageContext();
+    }
 
     /**
      * Gets the display adjustments holder for this context.  This information
@@ -4185,19 +4258,31 @@
 
     /**
      * Indicates if the storage APIs of this Context are backed by
-     * device-encrypted storage.
+     * device-protected storage.
      *
-     * @see #createDeviceEncryptedStorageContext()
+     * @see #createDeviceProtectedStorageContext()
      */
-    public abstract boolean isDeviceEncryptedStorage();
+    public abstract boolean isDeviceProtectedStorage();
+
+    /** @removed */
+    @Deprecated
+    public boolean isDeviceEncryptedStorage() {
+        return isDeviceProtectedStorage();
+    }
 
     /**
      * Indicates if the storage APIs of this Context are backed by
-     * credential-encrypted storage.
+     * credential-protected storage.
      *
-     * @see #createCredentialEncryptedStorageContext()
+     * @see #createCredentialProtectedStorageContext()
      * @hide
      */
     @SystemApi
-    public abstract boolean isCredentialEncryptedStorage();
+    public abstract boolean isCredentialProtectedStorage();
+
+    /** @removed */
+    @Deprecated
+    public boolean isCredentialEncryptedStorage() {
+        return isCredentialProtectedStorage();
+    }
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 323c9bf..087ac47 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -33,8 +33,8 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.UserHandle;
-import android.view.DisplayAdjustments;
 import android.view.Display;
+import android.view.DisplayAdjustments;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -164,14 +164,15 @@
         return mBase.getSharedPreferences(name, mode);
     }
 
+    /** @removed */
     @Override
     public SharedPreferences getSharedPreferences(File file, int mode) {
         return mBase.getSharedPreferences(file, mode);
     }
 
     @Override
-    public boolean migrateSharedPreferencesFrom(Context sourceContext, String name) {
-        return mBase.migrateSharedPreferencesFrom(sourceContext, name);
+    public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
+        return mBase.moveSharedPreferencesFrom(sourceContext, name);
     }
 
     @Override
@@ -201,6 +202,7 @@
         return mBase.getFileStreamPath(name);
     }
 
+    /** @removed */
     @Override
     public File getSharedPreferencesPath(String name) {
         return mBase.getSharedPreferencesPath(name);
@@ -288,8 +290,8 @@
     }
 
     @Override
-    public boolean migrateDatabaseFrom(Context sourceContext, String name) {
-        return mBase.migrateDatabaseFrom(sourceContext, name);
+    public boolean moveDatabaseFrom(Context sourceContext, String name) {
+        return mBase.moveDatabaseFrom(sourceContext, name);
     }
 
     @Override
@@ -818,26 +820,26 @@
     }
 
     @Override
-    public Context createDeviceEncryptedStorageContext() {
-        return mBase.createDeviceEncryptedStorageContext();
+    public Context createDeviceProtectedStorageContext() {
+        return mBase.createDeviceProtectedStorageContext();
     }
 
     /** {@hide} */
     @SystemApi
     @Override
-    public Context createCredentialEncryptedStorageContext() {
-        return mBase.createCredentialEncryptedStorageContext();
+    public Context createCredentialProtectedStorageContext() {
+        return mBase.createCredentialProtectedStorageContext();
     }
 
     @Override
-    public boolean isDeviceEncryptedStorage() {
-        return mBase.isDeviceEncryptedStorage();
+    public boolean isDeviceProtectedStorage() {
+        return mBase.isDeviceProtectedStorage();
     }
 
     /** {@hide} */
     @SystemApi
     @Override
-    public boolean isCredentialEncryptedStorage() {
-        return mBase.isCredentialEncryptedStorage();
+    public boolean isCredentialProtectedStorage() {
+        return mBase.isCredentialProtectedStorage();
     }
 }
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 8b471a0..d47e780 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -179,6 +179,8 @@
             int userId);
 
     void addStatusChangeListener(int mask, ISyncStatusObserver callback);
-
     void removeStatusChangeListener(ISyncStatusObserver callback);
+
+    void putCache(in String packageName, in Uri key, in Bundle value, int userId);
+    Bundle getCache(in String packageName, in Uri key, int userId);
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8f2b9c8..30f2c94 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -16,46 +16,40 @@
 
 package android.content;
 
-import android.content.pm.ApplicationInfo;
-import android.os.ResultReceiver;
-import android.os.ShellCommand;
-import android.provider.MediaStore;
-import android.util.ArraySet;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.AnyRes;
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.content.pm.ActivityInfo;
-
-import static android.content.ContentProvider.maybeAddUserId;
-
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.ResultReceiver;
+import android.os.ShellCommand;
 import android.os.StrictMode;
 import android.os.UserHandle;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
+import android.provider.MediaStore;
 import android.provider.OpenableColumns;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
-
 import com.android.internal.util.XmlUtils;
-
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
@@ -71,6 +65,8 @@
 import java.util.Objects;
 import java.util.Set;
 
+import static android.content.ContentProvider.maybeAddUserId;
+
 /**
  * An intent is an abstract description of an operation to be performed.  It
  * can be used with {@link Context#startActivity(Intent) startActivity} to
@@ -666,6 +662,8 @@
     /**
      * Activity Action: Quick view the data. Launches a quick viewer for
      * a URI or a list of URIs.
+     * <p>Activities handling this intent action should handle the vast majority of
+     * MIME types rather than only specific ones.
      * <p>Input: {@link #getData} is a mandatory content URI of the item to
      * preview. {@link #getClipData} contains an optional list of content URIs
      * if there is more than one item to preview. {@link #EXTRA_INDEX} is an
@@ -759,6 +757,14 @@
             "android.intent.extra.shortcut.ICON_RESOURCE";
 
     /**
+     * An activity that provides a user interface for adjusting application preferences.
+     * Optional but recommended settings for all applications which have settings.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APPLICATION_PREFERENCES
+            = "android.intent.action.APPLICATION_PREFERENCES";
+
+    /**
      * Represents a shortcut/live folder icon resource.
      *
      * @see Intent#ACTION_CREATE_SHORTCUT
@@ -1575,14 +1581,6 @@
             = "android.intent.extra.UNINSTALL_ALL_USERS";
 
     /**
-     * Specified when the uninstall confirmation dialog is not required to be shown.
-     * Use with {@link #ACTION_UNINSTALL_PACKAGE}
-     * @hide
-     */
-    public static final String EXTRA_SKIP_UNINSTALL_CONFIRMATION =
-            "android.intent.extra.SKIP_UNINSTALL_CONFIRMATION";
-
-    /**
      * A string associated with a {@link #ACTION_UPGRADE_SETUP} activity
      * describing the last run version of the platform that was setup.
      * @hide
@@ -1942,31 +1940,48 @@
     public static final String ACTION_ALARM_CHANGED = "android.intent.action.ALARM_CHANGED";
 
     /**
-     * Broadcast Action: This is broadcast once, after the system has finished
-     * booting and the user is in a "locked" state. A user is locked when their
-     * credential-encrypted private app data storage is unavailable. Once the
-     * user has entered their credentials (such as a lock pattern or PIN) for
-     * the first time, the {@link #ACTION_BOOT_COMPLETED} broadcast will be
-     * sent.
+     * Broadcast Action: This is broadcast once, after the user has finished
+     * booting, but while still in the "locked" state. It can be used to perform
+     * application-specific initialization, such as installing alarms. You must
+     * hold the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}
+     * permission in order to receive this broadcast.
      * <p>
-     * You must hold the
-     * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in
-     * order to receive this broadcast.
+     * This broadcast is sent immediately at boot by all devices (regardless of
+     * direct boot support) running {@link android.os.Build.VERSION_CODES#N} or
+     * higher. Upon receipt of this broadcast, the user is still locked and only
+     * device-protected storage can be accessed safely. If you want to access
+     * credential-protected storage, you need to wait for the user to be
+     * unlocked (typically by entering their lock pattern or PIN for the first
+     * time), after which the {@link #ACTION_USER_UNLOCKED} and
+     * {@link #ACTION_BOOT_COMPLETED} broadcasts are sent.
+     * <p>
+     * To receive this broadcast, your receiver component must be marked as
+     * being {@link ComponentInfo#directBootAware}.
      * <p class="note">
      * This is a protected intent that can only be sent by the system.
+     *
+     * @see Context#createDeviceProtectedStorageContext()
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
 
     /**
-     * Broadcast Action: This is broadcast once, after the system has finished
-     * booting.  It can be used to perform application-specific initialization,
-     * such as installing alarms.  You must hold the
-     * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission
-     * in order to receive this broadcast.
-     *
-     * <p class="note">This is a protected intent that can only be sent
-     * by the system.
+     * Broadcast Action: This is broadcast once, after the user has finished
+     * booting. It can be used to perform application-specific initialization,
+     * such as installing alarms. You must hold the
+     * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in
+     * order to receive this broadcast.
+     * <p>
+     * This broadcast is sent at boot by all devices (both with and without
+     * direct boot support). Upon receipt of this broadcast, the user is
+     * unlocked and both device-protected and credential-protected storage can
+     * accessed safely.
+     * <p>
+     * If you need to run while the user is still locked (before they've entered
+     * their lock pattern or PIN for the first time), you can listen for the
+     * {@link #ACTION_LOCKED_BOOT_COMPLETED} broadcast.
+     * <p class="note">
+     * This is a protected intent that can only be sent by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
@@ -2833,12 +2848,15 @@
             "com.google.android.c2dm.intent.RECEIVE";
 
     /**
-     * Broadcast Action: hook for permforming cleanup after a system update.
+     * Broadcast Action: This is broadcast once when the user is booting after a
+     * system update. It can be used to perform cleanup or upgrades after a
+     * system update.
+     * <p>
+     * This broadcast is sent after the {@link #ACTION_LOCKED_BOOT_COMPLETED}
+     * broadcast but before the {@link #ACTION_BOOT_COMPLETED} broadcast. It's
+     * only sent when the {@link Build#FINGERPRINT} has changed, and it's only
+     * sent to receivers in the system image.
      *
-     * The broadcast is sent when the system is booting, before the
-     * BOOT_COMPLETED broadcast.  It is only sent to receivers in the system
-     * image.  A receiver for this should do its work and then disable itself
-     * so that it does not get run again at the next boot.
      * @hide
      */
     public static final String ACTION_PRE_BOOT_COMPLETED =
@@ -3038,15 +3056,29 @@
     public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
             "android.intent.action.MANAGED_PROFILE_UNLOCKED";
 
+    /** @hide */
+    public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
+            "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+
     /**
-     * Broadcast sent to the primary user when an associated managed profile's availability has
-     * changed. This includes when the user toggles the profile's quiet mode. Carries an extra
+     * Broadcast sent to the primary user when an associated managed profile has become available.
+     * Currently this includes when the user disables quiet mode for the profile. Carries an extra
      * {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
      * this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
      * of quiet mode. This is only sent to registered receivers, not manifest receivers.
      */
-    public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
-            "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+    public static final String ACTION_MANAGED_PROFILE_AVAILABLE =
+            "android.intent.action.MANAGED_PROFILE_AVAILABLE";
+
+    /**
+     * Broadcast sent to the primary user when an associated managed profile has become unavailable.
+     * Currently this includes when the user enables quiet mode for the profile. Carries an extra
+     * {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
+     * this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
+     * of quiet mode. This is only sent to registered receivers, not manifest receivers.
+     */
+    public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE =
+            "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
 
     /**
      * Sent when the user taps on the clock widget in the system's "quick settings" area.
@@ -4140,12 +4172,16 @@
 
     /**
      * Optional index with semantics depending on the intent action.
-     * @see #ACTION_QUICK_VIEW
+     *
+     * <p>The value must be an integer greater or equal to 0.
      */
     public static final String EXTRA_INDEX = "android.intent.extra.INDEX";
 
     /**
      * Optional boolean extra indicating whether quiet mode has been switched on or off.
+     * When a profile goes into quiet mode, all apps in the profile are killed and the
+     * profile user is stopped. Widgets originating from the profile are masked, and app
+     * launcher icons are grayed out.
      */
     public static final String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
 
@@ -4558,7 +4594,8 @@
     /**
      * This flag is only used in split-screen multi-window mode. The new activity will be displayed
      * adjacent to the one launching it. This can only be used in conjunction with
-     * {@link #FLAG_ACTIVITY_NEW_TASK}.
+     * {@link #FLAG_ACTIVITY_NEW_TASK}. Also, setting {@link #FLAG_ACTIVITY_MULTIPLE_TASK} is
+     * required if you want a new instance of an existing activity to be created.
      */
     public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT = 0x00001000;
 
@@ -6031,13 +6068,20 @@
         return mExtras != null && mExtras.hasFileDescriptors();
     }
 
-    /** @hide */
+    /** {@hide} */
     public void setAllowFds(boolean allowFds) {
         if (mExtras != null) {
             mExtras.setAllowFds(allowFds);
         }
     }
 
+    /** {@hide} */
+    public void setDefusable(boolean defusable) {
+        if (mExtras != null) {
+            mExtras.setDefusable(defusable);
+        }
+    }
+
     /**
      * Retrieve extended data from the intent.
      *
@@ -8932,6 +8976,17 @@
      * @hide
      */
     public void prepareToEnterProcess() {
+        // We just entered destination process, so we should be able to read all
+        // parcelables inside.
+        setDefusable(true);
+
+        if (mSelector != null) {
+            mSelector.prepareToEnterProcess();
+        }
+        if (mClipData != null) {
+            mClipData.prepareToEnterProcess();
+        }
+
         if (mContentUserHint != UserHandle.USER_CURRENT) {
             if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
                 fixUris(mContentUserHint);
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 3a17e23..ed5dfa5 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -883,6 +883,15 @@
             return true;
         }
 
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof AuthorityEntry) {
+                final AuthorityEntry other = (AuthorityEntry)obj;
+                return match(other);
+            }
+            return false;
+        }
+
         /**
          * Determine whether this AuthorityEntry matches the given data Uri.
          * <em>Note that this comparison is case-sensitive, unlike formal
@@ -917,7 +926,7 @@
             }
             return MATCH_CATEGORY_HOST;
         }
-    };
+    }
 
     /**
      * Add a new Intent data "scheme specific part" to match against.  The filter must
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index a7744e7..6893067 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -422,7 +422,7 @@
                 return mService.getApplicationRestrictions(mContext.getPackageName());
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Couldn't reach service");
+            throw re.rethrowFromSystemServer();
         }
         return null;
     }
@@ -439,7 +439,7 @@
                 return mService.hasRestrictionsProvider();
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Couldn't reach service");
+            throw re.rethrowFromSystemServer();
         }
         return false;
     }
@@ -477,7 +477,7 @@
                         request);
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Couldn't reach service");
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -487,7 +487,7 @@
                 return mService.createLocalApprovalIntent();
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Couldn't reach service");
+            throw re.rethrowFromSystemServer();
         }
         return null;
     }
@@ -519,7 +519,7 @@
                 mService.notifyPermissionResponse(packageName, response);
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Couldn't reach service");
+            throw re.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index f793d76..541ebbd 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -147,7 +147,7 @@
     }
 
     private SyncRequest(Parcel in) {
-        mExtras = in.readBundle();
+        mExtras = Bundle.setDefusable(in.readBundle(), true);
         mSyncFlexTimeSecs = in.readLong();
         mSyncRunTimeSecs = in.readLong();
         mIsPeriodic = (in.readInt() != 0);
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 14ef61c..0f4cbbb 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.content.res.Configuration;
+import android.content.res.Configuration.NativeConfig;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Printer;
@@ -495,6 +496,28 @@
     @ScreenOrientation
     public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
+    /** @hide */
+    @IntDef(flag = true,
+            value = {
+                    CONFIG_MCC,
+                    CONFIG_MNC,
+                    CONFIG_LOCALE,
+                    CONFIG_TOUCHSCREEN,
+                    CONFIG_KEYBOARD,
+                    CONFIG_KEYBOARD_HIDDEN,
+                    CONFIG_NAVIGATION,
+                    CONFIG_ORIENTATION,
+                    CONFIG_SCREEN_LAYOUT,
+                    CONFIG_UI_MODE,
+                    CONFIG_SCREEN_SIZE,
+                    CONFIG_SMALLEST_SCREEN_SIZE,
+                    CONFIG_DENSITY,
+                    CONFIG_LAYOUT_DIRECTION,
+                    CONFIG_FONT_SCALE,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Config {}
+
     /**
      * Bit in {@link #configChanges} that indicates that the activity
      * can itself handle changes to the IMSI MCC.  Set from the
@@ -629,7 +652,7 @@
      *
      * @hide
      */
-    public static int activityInfoConfigToNative(int input) {
+    public static @NativeConfig int activityInfoConfigJavaToNative(@Config int input) {
         int output = 0;
         for (int i = 0; i < CONFIG_NATIVE_BITS.length; i++) {
             if ((input & (1 << i)) != 0) {
@@ -644,7 +667,7 @@
      *
      * @hide
      */
-    public static int activityInfoConfigNativeToJava(int input) {
+    public static @Config int activityInfoConfigNativeToJava(@NativeConfig int input) {
         int output = 0;
         for (int i = 0; i < CONFIG_NATIVE_BITS.length; i++) {
             if ((input & CONFIG_NATIVE_BITS[i]) != 0) {
@@ -744,7 +767,11 @@
      */
     public int lockTaskLaunchMode;
 
-    public Layout layout;
+    /**
+     * Information about desired position and size of activity on the display when
+     * it is first started.
+     */
+    public WindowLayout windowLayout;
 
     public ActivityInfo() {
     }
@@ -765,7 +792,7 @@
         parentActivityName = orig.parentActivityName;
         maxRecents = orig.maxRecents;
         lockTaskLaunchMode = orig.lockTaskLaunchMode;
-        layout = orig.layout;
+        windowLayout = orig.windowLayout;
         resizeMode = orig.resizeMode;
     }
 
@@ -863,10 +890,10 @@
             pw.println(prefix + "lockTaskLaunchMode="
                     + lockTaskLaunchModeToString(lockTaskLaunchMode));
         }
-        if (layout != null) {
-            pw.println(prefix + "defaultLayout=" + layout.width + "|"
-                    + layout.widthFraction + ", " + layout.height + "|"
-                    + layout.heightFraction + ", " + layout.gravity);
+        if (windowLayout != null) {
+            pw.println(prefix + "windowLayout=" + windowLayout.width + "|"
+                    + windowLayout.widthFraction + ", " + windowLayout.height + "|"
+                    + windowLayout.heightFraction + ", " + windowLayout.gravity);
         }
         pw.println(prefix + "resizeMode=" + resizeModeToString(resizeMode));
         super.dumpBack(pw, prefix, flags);
@@ -899,14 +926,15 @@
         dest.writeInt(persistableMode);
         dest.writeInt(maxRecents);
         dest.writeInt(lockTaskLaunchMode);
-        if (layout != null) {
+        if (windowLayout != null) {
             dest.writeInt(1);
-            dest.writeInt(layout.width);
-            dest.writeFloat(layout.widthFraction);
-            dest.writeInt(layout.height);
-            dest.writeFloat(layout.heightFraction);
-            dest.writeInt(layout.gravity);
-            dest.writeInt(layout.minimalSize);
+            dest.writeInt(windowLayout.width);
+            dest.writeFloat(windowLayout.widthFraction);
+            dest.writeInt(windowLayout.height);
+            dest.writeFloat(windowLayout.heightFraction);
+            dest.writeInt(windowLayout.gravity);
+            dest.writeInt(windowLayout.minimalWidth);
+            dest.writeInt(windowLayout.minimalHeight);
         } else {
             dest.writeInt(0);
         }
@@ -941,36 +969,107 @@
         maxRecents = source.readInt();
         lockTaskLaunchMode = source.readInt();
         if (source.readInt() == 1) {
-            layout = new Layout(source);
+            windowLayout = new WindowLayout(source);
         }
         resizeMode = source.readInt();
     }
 
-    public static final class Layout {
-        public Layout(int width, float widthFraction, int height, float heightFraction, int gravity,
-                int minimalSize) {
+    /**
+     * Contains information about position and size of the activity on the display.
+     *
+     * Used in freeform mode to set desired position when activity is first launched.
+     * It describes how big the activity wants to be in both width and height,
+     * the minimal allowed size, and the gravity to be applied.
+     *
+     * @attr ref android.R.styleable#AndroidManifestLayout_defaultWidth
+     * @attr ref android.R.styleable#AndroidManifestLayout_defaultHeight
+     * @attr ref android.R.styleable#AndroidManifestLayout_gravity
+     * @attr ref android.R.styleable#AndroidManifestLayout_minimalWidth
+     * @attr ref android.R.styleable#AndroidManifestLayout_minimalHeight
+     */
+    public static final class WindowLayout {
+        public WindowLayout(int width, float widthFraction, int height, float heightFraction, int gravity,
+                int minimalWidth, int minimalHeight) {
             this.width = width;
             this.widthFraction = widthFraction;
             this.height = height;
             this.heightFraction = heightFraction;
             this.gravity = gravity;
-            this.minimalSize = minimalSize;
+            this.minimalWidth = minimalWidth;
+            this.minimalHeight = minimalHeight;
         }
 
-        Layout(Parcel source) {
+        WindowLayout(Parcel source) {
             width = source.readInt();
             widthFraction = source.readFloat();
             height = source.readInt();
             heightFraction = source.readFloat();
             gravity = source.readInt();
-            minimalSize = source.readInt();
+            minimalWidth = source.readInt();
+            minimalHeight = source.readInt();
         }
 
+        /**
+         * Width of activity in pixels.
+         *
+         * @attr ref android.R.styleable#AndroidManifestLayout_defaultWidth
+         */
         public final int width;
+
+        /**
+         * Width of activity as a fraction of available display width.
+         * If both {@link #width} and this value are set this one will be preferred.
+         *
+         * @attr ref android.R.styleable#AndroidManifestLayout_defaultWidth
+         */
         public final float widthFraction;
+
+        /**
+         * Height of activity in pixels.
+         *
+         * @attr ref android.R.styleable#AndroidManifestLayout_defaultHeight
+         */
         public final int height;
+
+        /**
+         * Height of activity as a fraction of available display height.
+         * If both {@link #height} and this value are set this one will be preferred.
+         *
+         * @attr ref android.R.styleable#AndroidManifestLayout_defaultHeight
+         */
         public final float heightFraction;
+
+        /**
+         * Gravity of activity.
+         * Currently {@link android.view.Gravity#TOP}, {@link android.view.Gravity#BOTTOM},
+         * {@link android.view.Gravity#LEFT} and {@link android.view.Gravity#RIGHT} are supported.
+         *
+         * @attr ref android.R.styleable#AndroidManifestLayout_gravity
+         */
         public final int gravity;
-        public final int minimalSize;
+
+        /**
+         * Minimal width of activity in pixels to be able to display its content.
+         *
+         * <p><strong>NOTE:</strong> A task's root activity value is applied to all additional
+         * activities launched in the task. That is if the root activity of a task set minimal
+         * width, then the system will set the same minimal width on all other activities in the
+         * task. It will also ignore any other minimal width attributes of non-root activities.
+         *
+         * @attr ref android.R.styleable#AndroidManifestLayout_minimalWidth
+         */
+        public final int minimalWidth;
+
+        /**
+         * Minimal height of activity in pixels to be able to display its content.
+         *
+         * <p><strong>NOTE:</strong> A task's root activity value is applied to all additional
+         * activities launched in the task. That is if the root activity of a task set minimal
+         * height, then the system will set the same minimal height on all other activities in the
+         * task. It will also ignore any other minimal height attributes of non-root activities.
+         *
+         * @attr ref android.R.styleable#AndroidManifestLayout_minimalHeight
+         */
+        public final int minimalHeight;
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ad174f6..104feb5 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -16,7 +16,9 @@
 
 package android.content.pm;
 
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -24,7 +26,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
-import android.os.storage.StorageManager;
 import android.text.TextUtils;
 import android.util.Printer;
 
@@ -109,8 +110,8 @@
      * include/exclude criteria.
      * <p>If android:allowBackup is set to false, this attribute is ignored.
      *
-     * @see {@link android.content.Context#getNoBackupFilesDir}
-     * @see {@link #FLAG_ALLOW_BACKUP}
+     * @see android.content.Context#getNoBackupFilesDir()
+     * @see #FLAG_ALLOW_BACKUP
      *
      * @hide
      */
@@ -469,20 +470,20 @@
     public static final int PRIVATE_FLAG_HAS_DOMAIN_URLS = 1<<4;
 
     /**
-     * When set, default data storage directory for given app is pointed at
-     * device-encrypted location.
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
      *
      * @hide
      */
-    public static final int PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED = 1 << 5;
+    public static final int PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1 << 5;
 
     /**
-     * When set, assume that all components under the given app are encryption
+     * When set, assume that all components under the given app are direct boot
      * aware, unless otherwise specified.
      *
      * @hide
      */
-    public static final int PRIVATE_FLAG_ENCRYPTION_AWARE = 1 << 6;
+    public static final int PRIVATE_FLAG_DIRECT_BOOT_AWARE = 1 << 6;
 
     /**
      * Value for {@link #privateFlags}: set to {@code true} if the application
@@ -493,11 +494,12 @@
     public static final int PRIVATE_FLAG_AUTOPLAY = 1 << 7;
 
     /**
-     * When set, at least one component inside this application is encryption aware.
+     * When set, at least one component inside this application is direct boot
+     * aware.
      *
      * @hide
      */
-    public static final int PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE = 1 << 8;
+    public static final int PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE = 1 << 8;
 
     /**
      * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
@@ -627,15 +629,28 @@
     public String dataDir;
 
     /**
-     * Full path to the device-encrypted directory assigned to the package for
+     * Full path to the device-protected directory assigned to the package for
      * its persistent data.
+     *
+     * @see Context#createDeviceProtectedStorageContext()
      */
+    public String deviceProtectedDataDir;
+
+    /** @removed */
+    @Deprecated
     public String deviceEncryptedDataDir;
 
     /**
-     * Full path to the credential-encrypted directory assigned to the package
+     * Full path to the credential-protected directory assigned to the package
      * for its persistent data.
+     *
+     * @hide
      */
+    @SystemApi
+    public String credentialProtectedDataDir;
+
+    /** @removed */
+    @Deprecated
     public String credentialEncryptedDataDir;
 
     /**
@@ -707,6 +722,12 @@
     public int uid;
     
     /**
+     * The minimum SDK version this application can run on. It will not run
+     * on earlier versions.
+     */
+    public String minSdkVersion;
+
+    /**
      * The minimum SDK version this application targets.  It may run on earlier
      * versions, but it knows how to work with any new behavior added at this
      * version.  Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
@@ -784,13 +805,15 @@
         }
         pw.println(prefix + "dataDir=" + dataDir);
         if ((flags&DUMP_FLAG_DETAILS) != 0) {
-            pw.println(prefix + "deviceEncryptedDataDir=" + deviceEncryptedDataDir);
-            pw.println(prefix + "credentialEncryptedDataDir=" + credentialEncryptedDataDir);
+            pw.println(prefix + "deviceProtectedDataDir=" + deviceProtectedDataDir);
+            pw.println(prefix + "credentialProtectedDataDir=" + credentialProtectedDataDir);
             if (sharedLibraryFiles != null) {
                 pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles));
             }
         }
-        pw.println(prefix + "enabled=" + enabled + " targetSdkVersion=" + targetSdkVersion
+        pw.println(prefix + "enabled=" + enabled
+                + " minSdkVersion=" + minSdkVersion
+                + " targetSdkVersion=" + targetSdkVersion
                 + " versionCode=" + versionCode);
         if ((flags&DUMP_FLAG_DETAILS) != 0) {
             if (manageSpaceActivityName != null) {
@@ -881,9 +904,10 @@
         seinfo = orig.seinfo;
         sharedLibraryFiles = orig.sharedLibraryFiles;
         dataDir = orig.dataDir;
-        deviceEncryptedDataDir = orig.deviceEncryptedDataDir;
-        credentialEncryptedDataDir = orig.credentialEncryptedDataDir;
+        deviceEncryptedDataDir = deviceProtectedDataDir = orig.deviceProtectedDataDir;
+        credentialEncryptedDataDir = credentialProtectedDataDir = orig.credentialProtectedDataDir;
         uid = orig.uid;
+        minSdkVersion = orig.minSdkVersion;
         targetSdkVersion = orig.targetSdkVersion;
         versionCode = orig.versionCode;
         enabled = orig.enabled;
@@ -935,9 +959,10 @@
         dest.writeString(seinfo);
         dest.writeStringArray(sharedLibraryFiles);
         dest.writeString(dataDir);
-        dest.writeString(deviceEncryptedDataDir);
-        dest.writeString(credentialEncryptedDataDir);
+        dest.writeString(deviceProtectedDataDir);
+        dest.writeString(credentialProtectedDataDir);
         dest.writeInt(uid);
+        dest.writeString(minSdkVersion);
         dest.writeInt(targetSdkVersion);
         dest.writeInt(versionCode);
         dest.writeInt(enabled ? 1 : 0);
@@ -989,9 +1014,10 @@
         seinfo = source.readString();
         sharedLibraryFiles = source.readStringArray();
         dataDir = source.readString();
-        deviceEncryptedDataDir = source.readString();
-        credentialEncryptedDataDir = source.readString();
+        deviceEncryptedDataDir = deviceProtectedDataDir = source.readString();
+        credentialEncryptedDataDir = credentialProtectedDataDir = source.readString();
         uid = source.readInt();
+        minSdkVersion = source.readString();
         targetSdkVersion = source.readInt();
         versionCode = source.readInt();
         enabled = source.readInt() != 0;
@@ -1045,18 +1071,18 @@
             return;
         }
 
-        deviceEncryptedDataDir = Environment
+        deviceEncryptedDataDir = deviceProtectedDataDir = Environment
                 .getDataUserDePackageDirectory(volumeUuid, userId, packageName)
                 .getAbsolutePath();
-        credentialEncryptedDataDir = Environment
+        credentialEncryptedDataDir = credentialProtectedDataDir = Environment
                 .getDataUserCePackageDirectory(volumeUuid, userId, packageName)
                 .getAbsolutePath();
 
-        if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0
-                && PackageManager.APPLY_FORCE_DEVICE_ENCRYPTED) {
-            dataDir = deviceEncryptedDataDir;
+        if ((privateFlags & PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            dataDir = deviceProtectedDataDir;
         } else {
-            dataDir = credentialEncryptedDataDir;
+            dataDir = credentialProtectedDataDir;
         }
     }
 
@@ -1123,18 +1149,19 @@
     }
 
     /** @hide */
-    public boolean isForceDeviceEncrypted() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0;
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return (privateFlags
+                & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0;
     }
 
     /** @hide */
-    public boolean isEncryptionAware() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE) != 0;
+    public boolean isDirectBootAware() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
     }
 
     /** @hide */
-    public boolean isPartiallyEncryptionAware() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE) != 0;
+    public boolean isPartiallyDirectBootAware() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
     }
 
     /**
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
index e542589..4c01b27 100644
--- a/core/java/android/content/pm/AppsQueryHelper.java
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -171,7 +171,7 @@
             return mPackageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
                     | PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
         } catch (RemoteException e) {
-            throw new IllegalStateException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -181,9 +181,9 @@
             return mPackageManager.queryIntentActivities(intent, null,
                     PackageManager.GET_DISABLED_COMPONENTS
                             | PackageManager.GET_UNINSTALLED_PACKAGES,
-                    userId);
+                    userId).getList();
         } catch (RemoteException e) {
-            throw new IllegalStateException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -192,9 +192,9 @@
         try {
             return mPackageManager.queryIntentServices(intent, null,
                     PackageManager.GET_META_DATA
-                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
+                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId).getList();
         } catch (RemoteException e) {
-            throw new IllegalStateException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -205,8 +205,7 @@
             return mPackageManager.getPackagesHoldingPermissions(new String[]{perm}, 0,
                     userId).getList();
         } catch (RemoteException e) {
-            throw new IllegalStateException("Package manager has died", e);
+            throw e.rethrowFromSystemServer();
         }
     }
-
 }
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 63a163d..5cd15dd 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -66,10 +66,14 @@
     public boolean exported = false;
 
     /**
-     * Indicate if this component is aware of encryption lifecycle, and can be
+     * Indicates if this component is aware of direct boot lifecycle, and can be
      * safely run before the user has entered their credentials (such as a lock
      * pattern or PIN).
      */
+    public boolean directBootAware = false;
+
+    /** @removed */
+    @Deprecated
     public boolean encryptionAware = false;
 
     public ComponentInfo() {
@@ -82,7 +86,7 @@
         descriptionRes = orig.descriptionRes;
         enabled = orig.enabled;
         exported = orig.exported;
-        encryptionAware = orig.encryptionAware;
+        encryptionAware = directBootAware = orig.directBootAware;
     }
 
     @Override public CharSequence loadLabel(PackageManager pm) {
@@ -160,7 +164,7 @@
             pw.println(prefix + "processName=" + processName);
         }
         pw.println(prefix + "enabled=" + enabled + " exported=" + exported
-                + " encryptionAware=" + encryptionAware);
+                + " directBootAware=" + directBootAware);
         if (descriptionRes != 0) {
             pw.println(prefix + "description=" + descriptionRes);
         }
@@ -194,7 +198,7 @@
         dest.writeInt(descriptionRes);
         dest.writeInt(enabled ? 1 : 0);
         dest.writeInt(exported ? 1 : 0);
-        dest.writeInt(encryptionAware ? 1 : 0);
+        dest.writeInt(directBootAware ? 1 : 0);
     }
     
     protected ComponentInfo(Parcel source) {
@@ -207,9 +211,9 @@
         descriptionRes = source.readInt();
         enabled = (source.readInt() != 0);
         exported = (source.readInt() != 0);
-        encryptionAware = (source.readInt() != 0);
+        encryptionAware = directBootAware = (source.readInt() != 0);
     }
-    
+
     /**
      * @hide
      */
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java
deleted file mode 100644
index ab3aa27..0000000
--- a/core/java/android/content/pm/ContainerEncryptionParams.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Slog;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Represents encryption parameters used to read a container.
- *
- * @deprecated encrypted containers are legacy.
- * @hide
- */
-@SystemApi
-@Deprecated
-public class ContainerEncryptionParams implements Parcelable {
-    protected static final String TAG = "ContainerEncryptionParams";
-
-    /** What we print out first when toString() is called. */
-    private static final String TO_STRING_PREFIX = "ContainerEncryptionParams{";
-
-    /**
-     * Parameter type for parceling that indicates the next parameters are
-     * IvParameters.
-     */
-    private static final int ENC_PARAMS_IV_PARAMETERS = 1;
-
-    /** Parameter type for paceling that indicates there are no MAC parameters. */
-    private static final int MAC_PARAMS_NONE = 1;
-
-    /** The encryption algorithm used. */
-    private final String mEncryptionAlgorithm;
-
-    /** The parameter spec to be used for encryption. */
-    private final IvParameterSpec mEncryptionSpec;
-
-    /** Secret key to be used for decryption. */
-    private final SecretKey mEncryptionKey;
-
-    /** Algorithm name for the MAC to be used. */
-    private final String mMacAlgorithm;
-
-    /** The parameter spec to be used for the MAC tag authentication. */
-    private final AlgorithmParameterSpec mMacSpec;
-
-    /** Secret key to be used for MAC tag authentication. */
-    private final SecretKey mMacKey;
-
-    /** MAC tag authenticating the data in the container. */
-    private final byte[] mMacTag;
-
-    /** Offset into file where authenticated (e.g., MAC protected) data begins. */
-    private final long mAuthenticatedDataStart;
-
-    /** Offset into file where encrypted data begins. */
-    private final long mEncryptedDataStart;
-
-    /**
-     * Offset into file for the end of encrypted data (and, by extension,
-     * authenticated data) in file.
-     */
-    private final long mDataEnd;
-
-    public ContainerEncryptionParams(String encryptionAlgorithm,
-            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey)
-            throws InvalidAlgorithmParameterException {
-        this(encryptionAlgorithm, encryptionSpec, encryptionKey, null, null, null, null, -1, -1,
-                -1);
-    }
-
-    /**
-     * Creates container encryption specifications for installing from encrypted
-     * containers.
-     *
-     * @param encryptionAlgorithm encryption algorithm to use; format matches
-     *            JCE
-     * @param encryptionSpec algorithm parameter specification
-     * @param encryptionKey key used for decryption
-     * @param macAlgorithm MAC algorithm to use; format matches JCE
-     * @param macSpec algorithm parameters specification, may be {@code null}
-     * @param macKey key used for authentication (i.e., for the MAC tag)
-     * @param macTag message authentication code (MAC) tag for the authenticated
-     *            data
-     * @param authenticatedDataStart offset of start of authenticated data in
-     *            stream
-     * @param encryptedDataStart offset of start of encrypted data in stream
-     * @param dataEnd offset of the end of both the authenticated and encrypted
-     *            data
-     * @throws InvalidAlgorithmParameterException
-     */
-    public ContainerEncryptionParams(String encryptionAlgorithm,
-            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm,
-            AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag,
-            long authenticatedDataStart, long encryptedDataStart, long dataEnd)
-            throws InvalidAlgorithmParameterException {
-        if (TextUtils.isEmpty(encryptionAlgorithm)) {
-            throw new NullPointerException("algorithm == null");
-        } else if (encryptionSpec == null) {
-            throw new NullPointerException("encryptionSpec == null");
-        } else if (encryptionKey == null) {
-            throw new NullPointerException("encryptionKey == null");
-        }
-
-        if (!TextUtils.isEmpty(macAlgorithm)) {
-            if (macKey == null) {
-                throw new NullPointerException("macKey == null");
-            }
-        }
-
-        if (!(encryptionSpec instanceof IvParameterSpec)) {
-            throw new InvalidAlgorithmParameterException(
-                    "Unknown parameter spec class; must be IvParameters");
-        }
-
-        mEncryptionAlgorithm = encryptionAlgorithm;
-        mEncryptionSpec = (IvParameterSpec) encryptionSpec;
-        mEncryptionKey = encryptionKey;
-
-        mMacAlgorithm = macAlgorithm;
-        mMacSpec = macSpec;
-        mMacKey = macKey;
-        mMacTag = macTag;
-
-        mAuthenticatedDataStart = authenticatedDataStart;
-        mEncryptedDataStart = encryptedDataStart;
-        mDataEnd = dataEnd;
-    }
-
-    public String getEncryptionAlgorithm() {
-        return mEncryptionAlgorithm;
-    }
-
-    public AlgorithmParameterSpec getEncryptionSpec() {
-        return mEncryptionSpec;
-    }
-
-    public SecretKey getEncryptionKey() {
-        return mEncryptionKey;
-    }
-
-    public String getMacAlgorithm() {
-        return mMacAlgorithm;
-    }
-
-    public AlgorithmParameterSpec getMacSpec() {
-        return mMacSpec;
-    }
-
-    public SecretKey getMacKey() {
-        return mMacKey;
-    }
-
-    public byte[] getMacTag() {
-        return mMacTag;
-    }
-
-    public long getAuthenticatedDataStart() {
-        return mAuthenticatedDataStart;
-    }
-
-    public long getEncryptedDataStart() {
-        return mEncryptedDataStart;
-    }
-
-    public long getDataEnd() {
-        return mDataEnd;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-
-        if (!(o instanceof ContainerEncryptionParams)) {
-            return false;
-        }
-
-        final ContainerEncryptionParams other = (ContainerEncryptionParams) o;
-
-        // Primitive comparison
-        if ((mAuthenticatedDataStart != other.mAuthenticatedDataStart)
-                || (mEncryptedDataStart != other.mEncryptedDataStart)
-                || (mDataEnd != other.mDataEnd)) {
-            return false;
-        }
-
-        // String comparison
-        if (!mEncryptionAlgorithm.equals(other.mEncryptionAlgorithm)
-                || !mMacAlgorithm.equals(other.mMacAlgorithm)) {
-            return false;
-        }
-
-        // Object comparison
-        if (!isSecretKeyEqual(mEncryptionKey, other.mEncryptionKey)
-                || !isSecretKeyEqual(mMacKey, other.mMacKey)) {
-            return false;
-        }
-
-        if (!Arrays.equals(mEncryptionSpec.getIV(), other.mEncryptionSpec.getIV())
-                || !Arrays.equals(mMacTag, other.mMacTag) || (mMacSpec != other.mMacSpec)) {
-            return false;
-        }
-
-        return true;
-    }
-
-    private static final boolean isSecretKeyEqual(SecretKey key1, SecretKey key2) {
-        final String keyFormat = key1.getFormat();
-        final String otherKeyFormat = key2.getFormat();
-
-        if (keyFormat == null) {
-            if (keyFormat != otherKeyFormat) {
-                return false;
-            }
-
-            if (key1.getEncoded() != key2.getEncoded()) {
-                return false;
-            }
-        } else {
-            if (!keyFormat.equals(key2.getFormat())) {
-                return false;
-            }
-
-            if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 3;
-
-        hash += 5 * mEncryptionAlgorithm.hashCode();
-        hash += 7 * Arrays.hashCode(mEncryptionSpec.getIV());
-        hash += 11 * mEncryptionKey.hashCode();
-        hash += 13 * mMacAlgorithm.hashCode();
-        hash += 17 * mMacKey.hashCode();
-        hash += 19 * Arrays.hashCode(mMacTag);
-        hash += 23 * mAuthenticatedDataStart;
-        hash += 29 * mEncryptedDataStart;
-        hash += 31 * mDataEnd;
-
-        return hash;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX);
-
-        sb.append("mEncryptionAlgorithm=\"");
-        sb.append(mEncryptionAlgorithm);
-        sb.append("\",");
-        sb.append("mEncryptionSpec=");
-        sb.append(mEncryptionSpec.toString());
-        sb.append("mEncryptionKey=");
-        sb.append(mEncryptionKey.toString());
-
-        sb.append("mMacAlgorithm=\"");
-        sb.append(mMacAlgorithm);
-        sb.append("\",");
-        sb.append("mMacSpec=");
-        sb.append(mMacSpec.toString());
-        sb.append("mMacKey=");
-        sb.append(mMacKey.toString());
-
-        sb.append(",mAuthenticatedDataStart=");
-        sb.append(mAuthenticatedDataStart);
-        sb.append(",mEncryptedDataStart=");
-        sb.append(mEncryptedDataStart);
-        sb.append(",mDataEnd=");
-        sb.append(mDataEnd);
-        sb.append('}');
-
-        return sb.toString();
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mEncryptionAlgorithm);
-        dest.writeInt(ENC_PARAMS_IV_PARAMETERS);
-        dest.writeByteArray(mEncryptionSpec.getIV());
-        dest.writeSerializable(mEncryptionKey);
-
-        dest.writeString(mMacAlgorithm);
-        dest.writeInt(MAC_PARAMS_NONE);
-        dest.writeByteArray(new byte[0]);
-        dest.writeSerializable(mMacKey);
-
-        dest.writeByteArray(mMacTag);
-
-        dest.writeLong(mAuthenticatedDataStart);
-        dest.writeLong(mEncryptedDataStart);
-        dest.writeLong(mDataEnd);
-    }
-
-    private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException {
-        mEncryptionAlgorithm = source.readString();
-        final int encParamType = source.readInt();
-        final byte[] encParamsEncoded = source.createByteArray();
-        mEncryptionKey = (SecretKey) source.readSerializable();
-
-        mMacAlgorithm = source.readString();
-        final int macParamType = source.readInt();
-        source.createByteArray(); // byte[] macParamsEncoded
-        mMacKey = (SecretKey) source.readSerializable();
-
-        mMacTag = source.createByteArray();
-
-        mAuthenticatedDataStart = source.readLong();
-        mEncryptedDataStart = source.readLong();
-        mDataEnd = source.readLong();
-
-        switch (encParamType) {
-            case ENC_PARAMS_IV_PARAMETERS:
-                mEncryptionSpec = new IvParameterSpec(encParamsEncoded);
-                break;
-            default:
-                throw new InvalidAlgorithmParameterException("Unknown parameter type "
-                        + encParamType);
-        }
-
-        switch (macParamType) {
-            case MAC_PARAMS_NONE:
-                mMacSpec = null;
-                break;
-            default:
-                throw new InvalidAlgorithmParameterException("Unknown parameter type "
-                        + macParamType);
-        }
-
-        if (mEncryptionKey == null) {
-            throw new NullPointerException("encryptionKey == null");
-        }
-    }
-
-    public static final Parcelable.Creator<ContainerEncryptionParams> CREATOR =
-            new Parcelable.Creator<ContainerEncryptionParams>() {
-        public ContainerEncryptionParams createFromParcel(Parcel source) {
-            try {
-                return new ContainerEncryptionParams(source);
-            } catch (InvalidAlgorithmParameterException e) {
-                Slog.e(TAG, "Invalid algorithm parameters specified", e);
-                return null;
-            }
-        }
-
-        public ContainerEncryptionParams[] newArray(int size) {
-            return new ContainerEncryptionParams[size];
-        }
-    };
-}
\ No newline at end of file
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index cc266c5..6b3d4f1 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -22,16 +22,19 @@
 import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.os.ParcelFileDescriptor;
+
 import java.util.List;
 
 /**
  * {@hide}
  */
 interface ILauncherApps {
-    void addOnAppsChangedListener(in IOnAppsChangedListener listener);
+    void addOnAppsChangedListener(String callingPackage, in IOnAppsChangedListener listener);
     void removeOnAppsChangedListener(in IOnAppsChangedListener listener);
     ParceledListSlice getLauncherActivities(String packageName, in UserHandle user);
     ResolveInfo resolveActivity(in Intent intent, in UserHandle user);
@@ -42,4 +45,19 @@
     boolean isPackageEnabled(String packageName, in UserHandle user);
     boolean isActivityEnabled(in ComponentName component, in UserHandle user);
     ApplicationInfo getApplicationInfo(String packageName, int flags, in UserHandle user);
+
+    ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
+            in ComponentName componentName, int flags, in UserHandle user);
+    ParceledListSlice getShortcutInfo(String callingPackage, String packageName, in List<String> ids,
+            in UserHandle user);
+    void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
+            in UserHandle user);
+    boolean startShortcut(String callingPackage, String packageName, String id,
+            in Rect sourceBounds, in Bundle startActivityOptions, in UserHandle user);
+
+    int getShortcutIconResId(String callingPackage, in ShortcutInfo shortcut, in UserHandle user);
+    ParcelFileDescriptor getShortcutIconFd(String callingPackage, in ShortcutInfo shortcut,
+            in UserHandle user);
+
+    boolean hasShortcutHostPermission(String callingPackage);
 }
diff --git a/core/java/android/content/pm/IOnAppsChangedListener.aidl b/core/java/android/content/pm/IOnAppsChangedListener.aidl
index 1303696..e6525af 100644
--- a/core/java/android/content/pm/IOnAppsChangedListener.aidl
+++ b/core/java/android/content/pm/IOnAppsChangedListener.aidl
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.content.pm.ParceledListSlice;
 import android.os.UserHandle;
 
 /**
@@ -29,4 +30,5 @@
     void onPackagesUnavailable(in UserHandle user, in String[] packageNames, boolean replacing);
     void onPackagesSuspended(in UserHandle user, in String[] packageNames);
     void onPackagesUnsuspended(in UserHandle user, in String[] packageNames);
+    void onShortcutChanged(in UserHandle user, String packageName, in ParceledListSlice shortcuts);
 }
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index aee3ba7..2a3fac3 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -29,6 +29,8 @@
     ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
     ParcelFileDescriptor openRead(String name);
 
+    void removeSplit(String splitName);
+
     void close();
     void commit(in IntentSender statusReceiver);
     void abandon();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d6b674c..6fce36b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -46,7 +46,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -72,11 +71,11 @@
 
     PermissionInfo getPermissionInfo(String name, int flags);
 
-    List<PermissionInfo> queryPermissionsByGroup(String group, int flags);
+    ParceledListSlice queryPermissionsByGroup(String group, int flags);
 
     PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
 
-    List<PermissionGroupInfo> getAllPermissionGroups(int flags);
+    ParceledListSlice getAllPermissionGroups(int flags);
 
     ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
 
@@ -121,6 +120,8 @@
 
     int checkUidSignatures(int uid1, int uid2);
 
+    List<String> getAllPackages();
+
     String[] getPackagesForUid(int uid);
 
     String getNameForUid(int uid);
@@ -139,24 +140,24 @@
 
     boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
 
-    List<ResolveInfo> queryIntentActivities(in Intent intent,
+    ParceledListSlice queryIntentActivities(in Intent intent,
             String resolvedType, int flags, int userId);
 
-    List<ResolveInfo> queryIntentActivityOptions(
+    ParceledListSlice queryIntentActivityOptions(
             in ComponentName caller, in Intent[] specifics,
             in String[] specificTypes, in Intent intent,
             String resolvedType, int flags, int userId);
 
-    List<ResolveInfo> queryIntentReceivers(in Intent intent,
+    ParceledListSlice queryIntentReceivers(in Intent intent,
             String resolvedType, int flags, int userId);
 
     ResolveInfo resolveService(in Intent intent,
             String resolvedType, int flags, int userId);
 
-    List<ResolveInfo> queryIntentServices(in Intent intent,
+    ParceledListSlice queryIntentServices(in Intent intent,
             String resolvedType, int flags, int userId);
 
-    List<ResolveInfo> queryIntentContentProviders(in Intent intent,
+    ParceledListSlice queryIntentContentProviders(in Intent intent,
             String resolvedType, int flags, int userId);
 
     /**
@@ -190,7 +191,7 @@
      * @return A List&lt;applicationInfo> containing one entry for each persistent
      *         application.
      */
-    List<ApplicationInfo> getPersistentApplications(int flags);
+    ParceledListSlice getPersistentApplications(int flags);
 
     ProviderInfo resolveContentProvider(String name, int flags, int userId);
 
@@ -211,22 +212,14 @@
     InstrumentationInfo getInstrumentationInfo(
             in ComponentName className, int flags);
 
-    List<InstrumentationInfo> queryInstrumentation(
+    ParceledListSlice queryInstrumentation(
             String targetPackage, int flags);
 
-    void installPackage(in String originPath,
-            in IPackageInstallObserver2 observer,
-            int flags,
-            in String installerPackageName,
-            in VerificationParams verificationParams,
-            in String packageAbiOverride);
-
+    /** @deprecated Use PackageInstaller instead */
     void installPackageAsUser(in String originPath,
             in IPackageInstallObserver2 observer,
             int flags,
             in String installerPackageName,
-            in VerificationParams verificationParams,
-            in String packageAbiOverride,
             int userId);
 
     void finishPackageInstall(int token);
@@ -249,12 +242,6 @@
 
     String getInstallerPackageName(in String packageName);
 
-    void addPackageToPreferred(String packageName);
-
-    void removePackageFromPreferred(String packageName);
-
-    List<PackageInfo> getPreferredPackages(int flags);
-
     void resetApplicationPreferences(int userId);
 
     ResolveInfo getLastChosenActivity(in Intent intent,
@@ -304,6 +291,8 @@
      */
      ComponentName getHomeActivities(out List<ResolveInfo> outHomeCandidates);
 
+    void setHomeActivity(in ComponentName className, int userId);
+
     /**
      * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
      */
@@ -327,6 +316,17 @@
     int getApplicationEnabledSetting(in String packageName, int userId);
 
     /**
+     * Logs process start information (including APK hash) to the security log.
+     */
+    void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile,
+            int pid);
+
+    /**
+     * As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}.
+     */
+    void flushPackageRestrictionsAsUser(in int userId);
+
+    /**
      * Set whether the given package should be considered stopped, making
      * it not visible to implicit intents that filter out stopped packages.
      */
@@ -395,6 +395,13 @@
      */
     void clearApplicationUserData(in String packageName, IPackageDataObserver observer, int userId);
 
+    /**
+     * Clear the profile data of an application.
+     * @param packageName The package name of the application whose profile data
+     * need to be deleted
+     */
+    void clearApplicationProfileData(in String packageName);
+
    /**
      * Get package statistics including the code, data and cache size for
      * an already installed package
@@ -415,7 +422,7 @@
      * Get a list of features that are available on the
      * system.
      */
-    FeatureInfo[] getSystemAvailableFeatures();
+    ParceledListSlice getSystemAvailableFeatures();
 
     boolean hasSystemFeature(String name, int version);
 
@@ -430,10 +437,9 @@
     void performFstrimIfNeeded();
 
     /**
-     * Ask the package manager to extract packages if needed, to save
-     * the VM unzipping the APK in memory during launch.
+     * Ask the package manager to update packages if needed.
      */
-    void extractPackagesIfNeeded();
+    void updatePackagesIfNeeded();
 
     /**
      * Notify the package manager that a package is going to be used.
@@ -453,8 +459,21 @@
      */
     boolean performDexOptIfNeeded(String packageName, String instructionSet);
 
-    boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
-            boolean extractOnly, boolean force);
+    /**
+     * Ask the package manager to perform a dex-opt for the given reason. The package
+     * manager will map the reason to a compiler filter according to the current system
+     * configuration.
+     */
+    boolean performDexOpt(String packageName, String instructionSet, boolean checkProfiles,
+            int compileReason, boolean force);
+    /**
+     * Ask the package manager to perform a dex-opt with the given compiler filter.
+     *
+     * Note: exposed only for the shell command to allow moving packages explicitly to a
+     *       definite state.
+     */
+    boolean performDexOptMode(String packageName, String instructionSet, boolean checkProfiles,
+            String targetCompilerFilter, boolean force);
 
     void forceDexOpt(String packageName);
 
@@ -489,8 +508,8 @@
     void verifyIntentFilter(int id, int verificationCode, in List<String> failedDomains);
     int getIntentVerificationStatus(String packageName, int userId);
     boolean updateIntentVerificationStatus(String packageName, int status, int userId);
-    List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName);
-    List<IntentFilter> getAllIntentFilters(String packageName);
+    ParceledListSlice getIntentFilterVerifications(String packageName);
+    ParceledListSlice getAllIntentFilters(String packageName);
 
     boolean setDefaultBrowserPackageName(String packageName, int userId);
     String getDefaultBrowserPackageName(int userId);
@@ -539,4 +558,6 @@
     String getServicesSystemSharedLibraryPackageName();
 
     boolean isPackageDeviceAdminOnAnyUser(String packageName);
+
+    List<String> getPreviousCodePaths(in String packageName);
 }
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
new file mode 100644
index 0000000..31d377b
--- /dev/null
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.ParceledListSlice;
+import android.content.pm.ShortcutInfo;
+
+/**
+ * {@hide}
+ */
+interface IShortcutService {
+
+    boolean setDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
+            int userId);
+
+    ParceledListSlice getDynamicShortcuts(String packageName, int userId);
+
+    boolean addDynamicShortcut(String packageName, in ShortcutInfo shortcutInfo, int userId);
+
+    void deleteDynamicShortcut(String packageName, in String shortcutId, int userId);
+
+    void deleteAllDynamicShortcuts(String packageName, int userId);
+
+    ParceledListSlice getPinnedShortcuts(String packageName, int userId);
+
+    boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId);
+
+    int getMaxDynamicShortcutCount(String packageName, int userId);
+
+    int getRemainingCallCount(String packageName, int userId);
+
+    long getRateLimitResetTime(String packageName, int userId);
+
+    int getIconMaxDimensions(String packageName, int userId);
+
+    void resetThrottling(); // system only API for developer opsions
+
+    byte[] getBackupPayload(int user);
+
+    void applyRestore(in byte[] payload, int user);
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index 44bdf4e..cbeed35 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -62,9 +62,9 @@
     public String dataDir;
 
     /** {@hide} */
-    public String deviceEncryptedDataDir;
+    public String deviceProtectedDataDir;
     /** {@hide} */
-    public String credentialEncryptedDataDir;
+    public String credentialProtectedDataDir;
 
     /**
      * Full path to the directory where the native JNI libraries are stored.
@@ -92,8 +92,8 @@
         splitSourceDirs = orig.splitSourceDirs;
         splitPublicSourceDirs = orig.splitPublicSourceDirs;
         dataDir = orig.dataDir;
-        deviceEncryptedDataDir = orig.deviceEncryptedDataDir;
-        credentialEncryptedDataDir = orig.credentialEncryptedDataDir;
+        deviceProtectedDataDir = orig.deviceProtectedDataDir;
+        credentialProtectedDataDir = orig.credentialProtectedDataDir;
         nativeLibraryDir = orig.nativeLibraryDir;
         handleProfiling = orig.handleProfiling;
         functionalTest = orig.functionalTest;
@@ -117,8 +117,8 @@
         dest.writeStringArray(splitSourceDirs);
         dest.writeStringArray(splitPublicSourceDirs);
         dest.writeString(dataDir);
-        dest.writeString(deviceEncryptedDataDir);
-        dest.writeString(credentialEncryptedDataDir);
+        dest.writeString(deviceProtectedDataDir);
+        dest.writeString(credentialProtectedDataDir);
         dest.writeString(nativeLibraryDir);
         dest.writeInt((handleProfiling == false) ? 0 : 1);
         dest.writeInt((functionalTest == false) ? 0 : 1);
@@ -142,8 +142,8 @@
         splitSourceDirs = source.readStringArray();
         splitPublicSourceDirs = source.readStringArray();
         dataDir = source.readString();
-        deviceEncryptedDataDir = source.readString();
-        credentialEncryptedDataDir = source.readString();
+        deviceProtectedDataDir = source.readString();
+        credentialProtectedDataDir = source.readString();
         nativeLibraryDir = source.readString();
         handleProfiling = source.readInt() != 0;
         functionalTest = source.readInt() != 0;
@@ -157,8 +157,8 @@
         ai.splitSourceDirs = splitSourceDirs;
         ai.splitPublicSourceDirs = splitPublicSourceDirs;
         ai.dataDir = dataDir;
-        ai.deviceEncryptedDataDir = deviceEncryptedDataDir;
-        ai.credentialEncryptedDataDir = credentialEncryptedDataDir;
+        ai.deviceProtectedDataDir = deviceProtectedDataDir;
+        ai.credentialProtectedDataDir = credentialProtectedDataDir;
         ai.nativeLibraryDir = nativeLibraryDir;
     }
 }
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index a5617b4..40e1a9f 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -103,53 +103,22 @@
      * @return The drawable associated with the activity.
      */
     public Drawable getIcon(int density) {
-        final int iconRes = mResolveInfo.getIconResource();
-        Drawable icon = getDrawableForDensity(iconRes, density);
-        // Get the default density icon
-        if (icon == null) {
-            icon = mResolveInfo.loadIcon(mPm);
-        }
-        return icon;
-    }
-
-    /**
-     * Returns the icon for this activity, without any badging for the profile.
-     * This function can get the icon no matter the icon needs to be badged or not.
-     * @param density The preferred density of the icon, zero for default density. Use
-     * density DPI values from {@link DisplayMetrics}.
-     * @see #getBadgedIcon(int)
-     * @see DisplayMetrics
-     * @return The drawable associated with the activity.
-     */
-    private Drawable getOriginalIcon(int density) {
         final int iconRes = mResolveInfo.getIconResourceInternal();
-        Drawable icon = getDrawableForDensity(iconRes, density);
-        // Get the default density icon
-        if (icon == null) {
-            icon = mResolveInfo.loadIcon(mPm);
-        }
-        return icon;
-    }
-
-    /**
-     * Returns the drawable for this activity, without any badging for the profile.
-     * @param iconRes id of the drawable.
-     * @param density The preferred density of the icon, zero for default density. Use
-     * density DPI values from {@link DisplayMetrics}.
-     * @see DisplayMetrics
-     * @return The drawable associated with the resource id.
-     */
-    private Drawable getDrawableForDensity(int iconRes, int density) {
+        Drawable icon = null;
         // Get the preferred density icon from the app's resources
         if (density != 0 && iconRes != 0) {
             try {
                 final Resources resources
                         = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
-                return resources.getDrawableForDensity(iconRes, density);
+                icon = resources.getDrawableForDensity(iconRes, density);
             } catch (NameNotFoundException | Resources.NotFoundException exc) {
             }
         }
-        return null;
+        // Get the default density icon
+        if (icon == null) {
+            icon = mResolveInfo.loadIcon(mPm);
+        }
+        return icon;
     }
 
     /**
@@ -201,7 +170,7 @@
      * @return A badged icon for the activity.
      */
     public Drawable getBadgedIcon(int density) {
-        Drawable originalIcon = getOriginalIcon(density);
+        Drawable originalIcon = getIcon(density);
 
         if (originalIcon instanceof BitmapDrawable) {
             return mPm.getUserBadgedIcon(originalIcon, mUser);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8c7d327..d865f34 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -16,23 +16,26 @@
 
 package android.content.pm;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ILauncherApps;
-import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -148,6 +151,96 @@
          */
         public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
         }
+
+        /**
+         * Indicates that one or more shortcuts (which may be dynamic and/or pinned)
+         * have been added, updated or removed.
+         *
+         * <p>Only the applications that are allowed to access the shortcut information,
+         * as defined in {@link #hasShortcutHostPermission()}, will receive it.
+         *
+         * @param packageName The name of the package that has the shortcuts.
+         * @param shortcuts all shortcuts from the package (dynamic and/or pinned).  Only "key"
+         *    information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
+         * @param user The UserHandle of the profile that generated the change.
+         */
+        public void onShortcutsChanged(@NonNull String packageName,
+                @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+        }
+    }
+
+    /**
+     * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
+     */
+    public static class ShortcutQuery {
+        /**
+         * Include dynamic shortcuts in the result.
+         */
+        public static final int FLAG_GET_DYNAMIC = 1 << 0;
+
+        /**
+         * Include pinned shortcuts in the result.
+         */
+        public static final int FLAG_GET_PINNED = 1 << 1;
+
+        /**
+         * Requests "key" fields only.  See {@link ShortcutInfo#hasKeyFieldsOnly()} for which
+         * fields are available.
+         */
+        public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
+
+        /** @hide */
+        @IntDef(flag = true,
+                value = {
+                        FLAG_GET_DYNAMIC,
+                        FLAG_GET_PINNED,
+                        FLAG_GET_KEY_FIELDS_ONLY,
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface QueryFlags {}
+
+        long mChangedSince;
+
+        @Nullable
+        String mPackage;
+
+        @Nullable
+        ComponentName mActivity;
+
+        @QueryFlags
+        int mQueryFlags;
+
+        public ShortcutQuery() {
+        }
+
+        /**
+         * If non-zero, returns only shortcuts that have been added or updated since the timestamp,
+         * which is a milliseconds since the Epoch.
+         */
+        public void setChangedSince(long changedSince) {
+            mChangedSince = changedSince;
+        }
+
+        /**
+         * If non-null, returns only shortcuts from the package.
+         */
+        public void setPackage(@Nullable String packageName) {
+            mPackage = packageName;
+        }
+
+        /**
+         * If non-null, returns only shortcuts associated with the activity.
+         */
+        public void setActivity(@Nullable ComponentName activity) {
+            mActivity = activity;
+        }
+
+        /**
+         * Set query options.
+         */
+        public void setQueryFlags(@QueryFlags int queryFlags) {
+            mQueryFlags = queryFlags;
+        }
     }
 
     /** @hide */
@@ -171,7 +264,7 @@
         try {
             activities = mService.getLauncherActivities(packageName, user);
         } catch (RemoteException re) {
-            throw new RuntimeException("Failed to call LauncherAppsService", re);
+            throw re.rethrowFromSystemServer();
         }
         if (activities == null) {
             return Collections.EMPTY_LIST;
@@ -208,7 +301,7 @@
                 return info;
             }
         } catch (RemoteException re) {
-            throw new RuntimeException("Failed to call LauncherAppsService", re);
+            throw re.rethrowFromSystemServer();
         }
         return null;
     }
@@ -229,7 +322,7 @@
         try {
             mService.startActivityAsUser(component, sourceBounds, opts, user);
         } catch (RemoteException re) {
-            // Oops!
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -247,7 +340,7 @@
         try {
             mService.showAppDetailsAsUser(component, sourceBounds, opts, user);
         } catch (RemoteException re) {
-            // Oops!
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -263,7 +356,7 @@
         try {
             return mService.isPackageEnabled(packageName, user);
         } catch (RemoteException re) {
-            throw new RuntimeException("Failed to call LauncherAppsService", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -282,7 +375,7 @@
         try {
             return mService.getApplicationInfo(packageName, flags, user);
         } catch (RemoteException re) {
-            throw new RuntimeException("Failed to call LauncherAppsService", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -298,10 +391,158 @@
         try {
             return mService.isActivityEnabled(component, user);
         } catch (RemoteException re) {
-            throw new RuntimeException("Failed to call LauncherAppsService", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
+    /**
+     * Returns whether the caller can access the shortcut information.
+     *
+     * <p>Only the default launcher can access the shortcut information.
+     *
+     * <p>Note when this method returns {@code false}, that may be a temporary situation because
+     * the user is trying a new launcher application.  The user may decide to change the default
+     * launcher to the calling application again, so even if a launcher application loses
+     * this permission, it does <b>not</b> have to purge pinned shortcut information.
+     */
+    public boolean hasShortcutHostPermission() {
+        try {
+            return mService.hasShortcutHostPermission(mContext.getPackageName());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the IDs of {@link ShortcutInfo}s that match {@code query}.
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param query result includes shortcuts matching this query.
+     * @param user The UserHandle of the profile.
+     *
+     * @return the IDs of {@link ShortcutInfo}s that match the query.
+     */
+    @Nullable
+    public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
+            @NonNull UserHandle user) {
+        try {
+            return mService.getShortcuts(mContext.getPackageName(),
+                    query.mChangedSince, query.mPackage, query.mActivity, query.mQueryFlags, user)
+                    .getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns {@link ShortcutInfo}s with the given IDs from a package.
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param packageName The target package.
+     * @param ids IDs of the shortcuts to retrieve.
+     * @param user The UserHandle of the profile.
+     *
+     * @return list of {@link ShortcutInfo} associated with the package.
+     */
+    @Nullable
+    public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
+            @NonNull List<String> ids, @NonNull UserHandle user) {
+        try {
+            return mService.getShortcutInfo(mContext.getPackageName(), packageName, ids, user)
+                    .getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+
+    /**
+     * Pin shortcuts on a package.
+     *
+     * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
+     * However, different launchers may have different set of pinned shortcuts.
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param packageName The target package name.
+     * @param shortcutIds The IDs of the shortcut to be pinned.
+     * @param user The UserHandle of the profile.
+     */
+    public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
+            @NonNull UserHandle user) {
+        try {
+            mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the icon resource ID, if {@code shortcut} has one
+     * (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}).
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param shortcut The target shortcut.
+     * @param user The UserHandle of the profile.
+     */
+    public int getShortcutIconResId(@NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
+        try {
+            return mService.getShortcutIconResId(mContext.getPackageName(), shortcut, user);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the icon as {@link ParcelFileDescriptor}, when it's stored as a file
+     * (i.e. when {@link ShortcutInfo#hasIconFile()} returns {@code true}).
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param shortcut The target shortcut.
+     * @param user The UserHandle of the profile.
+     */
+    public ParcelFileDescriptor getShortcutIconFd(
+            @NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
+        try {
+            return mService.getShortcutIconFd(mContext.getPackageName(), shortcut, user);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Launches a shortcut.
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param packageName The target shortcut package name.
+     * @param shortcutId The target shortcut ID.
+     * @param sourceBounds The Rect containing the source bounds of the clicked icon.
+     * @param startActivityOptions Options to pass to startActivity.
+     * @param user The UserHandle of the profile.
+     * @return {@code false} when the shortcut is no longer valid (e.g. the creator application
+     *   has been uninstalled). {@code true} when the shortcut is still valid.
+     */
+    public boolean startShortcut(@NonNull String packageName, @NonNull String shortcutId,
+            @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
+            @NonNull UserHandle user) {
+        try {
+            return mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
+                    sourceBounds, startActivityOptions, user);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
     /**
      * Registers a callback for changes to packages in current and managed profiles.
@@ -325,8 +566,10 @@
                 addCallbackLocked(callback, handler);
                 if (addedFirstCallback) {
                     try {
-                        mService.addOnAppsChangedListener(mAppsChangedListener);
+                        mService.addOnAppsChangedListener(mContext.getPackageName(),
+                                mAppsChangedListener);
                     } catch (RemoteException re) {
+                        throw re.rethrowFromSystemServer();
                     }
                 }
             }
@@ -346,6 +589,7 @@
                 try {
                     mService.removeOnAppsChangedListener(mAppsChangedListener);
                 } catch (RemoteException re) {
+                    throw re.rethrowFromSystemServer();
                 }
             }
         }
@@ -472,6 +716,20 @@
                 }
             }
         }
+
+        @Override
+        public void onShortcutChanged(UserHandle user, String packageName,
+                ParceledListSlice shortcuts) {
+            if (DEBUG) {
+                Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
+            }
+            final List<ShortcutInfo> list = shortcuts.getList();
+            synchronized (LauncherApps.this) {
+                for (CallbackMessageHandler callback : mCallbacks) {
+                    callback.postOnShortcutChanged(packageName, user, list);
+                }
+            }
+        }
     };
 
     private static class CallbackMessageHandler extends Handler {
@@ -482,6 +740,7 @@
         private static final int MSG_UNAVAILABLE = 5;
         private static final int MSG_SUSPENDED = 6;
         private static final int MSG_UNSUSPENDED = 7;
+        private static final int MSG_SHORTCUT_CHANGED = 8;
 
         private LauncherApps.Callback mCallback;
 
@@ -490,6 +749,7 @@
             String packageName;
             boolean replacing;
             UserHandle user;
+            List<ShortcutInfo> shortcuts;
         }
 
         public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
@@ -525,6 +785,9 @@
                 case MSG_UNSUSPENDED:
                     mCallback.onPackagesUnsuspended(info.packageNames, info.user);
                     break;
+                case MSG_SHORTCUT_CHANGED:
+                    mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
+                    break;
             }
         }
 
@@ -580,5 +843,14 @@
             info.user = user;
             obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
         }
+
+        public void postOnShortcutChanged(String packageName, UserHandle user,
+                List<ShortcutInfo> shortcuts) {
+            CallbackInfo info = new CallbackInfo();
+            info.packageName = packageName;
+            info.user = user;
+            info.shortcuts = shortcuts;
+            obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
+        }
     }
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3283005..ed8143e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -37,7 +37,6 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.util.ExceptionUtils;
-import android.util.Log;
 
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -47,7 +46,6 @@
 import java.io.OutputStream;
 import java.security.MessageDigest;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
@@ -301,7 +299,7 @@
             ExceptionUtils.maybeUnwrapIOException(e);
             throw e;
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -321,7 +319,7 @@
             ExceptionUtils.maybeUnwrapIOException(e);
             throw e;
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -337,7 +335,7 @@
         try {
             mInstaller.updateSessionAppIcon(sessionId, appIcon);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -353,7 +351,7 @@
             final String val = (appLabel != null) ? appLabel.toString() : null;
             mInstaller.updateSessionAppLabel(sessionId, val);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -370,7 +368,7 @@
         try {
             mInstaller.abandonSession(sessionId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -385,7 +383,7 @@
         try {
             return mInstaller.getSessionInfo(sessionId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -393,17 +391,10 @@
      * Return list of all known install sessions, regardless of the installer.
      */
     public @NonNull List<SessionInfo> getAllSessions() {
-        final ApplicationInfo info = mContext.getApplicationInfo();
-        if ("com.google.android.googlequicksearchbox".equals(info.packageName)
-                && info.versionCode <= 300400110) {
-            Log.d(TAG, "Ignoring callback request from old prebuilt");
-            return Collections.EMPTY_LIST;
-        }
-
         try {
             return mInstaller.getAllSessions(mUserId).getList();
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -414,7 +405,7 @@
         try {
             return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -427,7 +418,7 @@
         try {
             mInstaller.uninstall(packageName, mInstallerPackageName, 0, statusReceiver, mUserId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -436,7 +427,7 @@
         try {
             mInstaller.setPermissionsResult(sessionId, accepted);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -597,21 +588,13 @@
      *            calling thread.
      */
     public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
-        // TODO: remove this temporary guard once we have new prebuilts
-        final ApplicationInfo info = mContext.getApplicationInfo();
-        if ("com.google.android.googlequicksearchbox".equals(info.packageName)
-                && info.versionCode <= 300400110) {
-            Log.d(TAG, "Ignoring callback request from old prebuilt");
-            return;
-        }
-
         synchronized (mDelegates) {
             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
                     handler.getLooper());
             try {
                 mInstaller.registerCallback(delegate, mUserId);
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
             mDelegates.add(delegate);
         }
@@ -634,7 +617,7 @@
                     try {
                         mInstaller.unregisterCallback(delegate);
                     } catch (RemoteException e) {
-                        throw e.rethrowAsRuntimeException();
+                        throw e.rethrowFromSystemServer();
                     }
                     i.remove();
                 }
@@ -681,7 +664,7 @@
             try {
                 mSession.setClientProgress(progress);
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -690,7 +673,7 @@
             try {
                 mSession.addClientProgress(progress);
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -734,7 +717,7 @@
                 ExceptionUtils.maybeUnwrapIOException(e);
                 throw e;
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -767,7 +750,7 @@
                 ExceptionUtils.maybeUnwrapIOException(e);
                 throw e;
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -790,7 +773,28 @@
                 ExceptionUtils.maybeUnwrapIOException(e);
                 throw e;
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Removes a split.
+         * <p>
+         * Split removals occur prior to adding new APKs. If upgrading a feature
+         * split, it is not expected nor desirable to remove the split prior to
+         * upgrading.
+         * <p>
+         * When split removal is bundled with new APKs, the packageName must be
+         * identical.
+         */
+        public void removeSplit(@NonNull String splitName) throws IOException {
+            try {
+                mSession.removeSplit(splitName);
+            } catch (RuntimeException e) {
+                ExceptionUtils.maybeUnwrapIOException(e);
+                throw e;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -810,7 +814,7 @@
             try {
                 mSession.commit(statusReceiver);
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -823,7 +827,7 @@
             try {
                 mSession.close();
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -837,7 +841,7 @@
             try {
                 mSession.abandon();
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -979,8 +983,8 @@
         }
 
         /**
-         * Optionally set the URI where this package was downloaded from. Used for
-         * verification purposes.
+         * Optionally set the URI where this package was downloaded from. This is
+         * informational and may be used as a signal for anti-malware purposes.
          *
          * @see Intent#EXTRA_ORIGINATING_URI
          */
@@ -989,7 +993,8 @@
         }
 
         /**
-         * Sets the UID that initiated package installation. Used for verification purposes.
+         * Sets the UID that initiated package installation. This is informational
+         * and may be used as a signal for anti-malware purposes.
          *
          * @see PackageManager#EXTRA_VERIFICATION_INSTALLER_UID
          */
@@ -998,8 +1003,8 @@
         }
 
         /**
-         * Optionally set the URI that referred you to install this package. Used
-         * for verification purposes.
+         * Optionally set the URI that referred you to install this package. This is
+         * informational and may be used as a signal for anti-malware purposes.
          *
          * @see Intent#EXTRA_REFERRER
          */
@@ -1031,6 +1036,16 @@
         }
 
         /** {@hide} */
+        @SystemApi
+        public void setAllowDowngrade(boolean allowDowngrade) {
+            if (allowDowngrade) {
+                installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
+            } else {
+                installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
+            }
+        }
+
+        /** {@hide} */
         public void setInstallFlagsExternal() {
             installFlags |= PackageManager.INSTALL_EXTERNAL;
             installFlags &= ~PackageManager.INSTALL_INTERNAL;
@@ -1042,6 +1057,16 @@
         }
 
         /** {@hide} */
+        @SystemApi
+        public void setDontKillApp(boolean dontKillApp) {
+            if (dontKillApp) {
+                installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
+            } else {
+                installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
+            }
+        }
+
+        /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
             pw.printHexPair("installFlags", installFlags);
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 4df83036..edd888b 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -16,12 +16,16 @@
 
 package android.content.pm;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.content.res.XmlResourceParser;
 
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.UserHandle;
+import android.text.BidiFormatter;
+import android.text.TextPaint;
 import android.text.TextUtils;
 import android.util.Printer;
 
@@ -38,6 +42,8 @@
  * in the implementation of Parcelable in subclasses.
  */
 public class PackageItemInfo {
+    private static final float MAX_LABEL_SIZE_PX = 500f;
+
     /**
      * Public name of this item. From the "android:name" attribute.
      */
@@ -140,6 +146,56 @@
     }
 
     /**
+     * Same as {@link #loadLabel(PackageManager)} with the addition that
+     * the returned label is safe for being presented in the UI since it
+     * will not contain new lines and the length will be limited to a
+     * reasonable amount. This prevents a malicious party to influence UI
+     * layout via the app label misleading the user into performing a
+     * detrimental for them action. If the label is too long it will be
+     * truncated and ellipsized at the end.
+     *
+     * @param pm A PackageManager from which the label can be loaded; usually
+     * the PackageManager from which you originally retrieved this item
+     * @return Returns a CharSequence containing the item's label. If the
+     * item does not have a label, its name is returned.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
+        // loadLabel() always returns non-null
+        CharSequence label = loadLabel(pm);
+
+        // If the label contains new line characters it may push the UI
+        // down to hide a part of it. Labels shouldn't have new line
+        // characters, so just truncate at the first time one is seen.
+        String labelStr = label.toString();
+        final int labelLength = labelStr.length();
+        int offset = 0;
+        while (offset < labelLength) {
+            final int codePoint = labelStr.codePointAt(offset);
+            final int type = Character.getType(codePoint);
+            if (type == Character.LINE_SEPARATOR
+                    || type == Character.CONTROL
+                    || type == Character.PARAGRAPH_SEPARATOR) {
+                labelStr = labelStr.substring(0, offset);
+                break;
+            }
+            offset += Character.charCount(codePoint);
+        }
+
+        if (labelStr.isEmpty()) {
+            return labelStr;
+        }
+
+        TextPaint paint = new TextPaint();
+        paint.setTextSize(42);
+
+        return TextUtils.ellipsize(labelStr, paint, MAX_LABEL_SIZE_PX,
+                TextUtils.TruncateAt.END);
+    }
+
+    /**
      * Retrieve the current graphical icon associated with this item.  This
      * will call back on the given PackageManager to load the icon from
      * the application.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 188e1d7..39bc783 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -48,6 +48,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.storage.VolumeInfo;
 import android.util.AndroidException;
 import android.util.Log;
@@ -69,7 +70,7 @@
     private static final String TAG = "PackageManager";
 
     /** {@hide} */
-    public static final boolean APPLY_FORCE_DEVICE_ENCRYPTED = true;
+    public static final boolean APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = true;
 
     /**
      * This exception is thrown when a given package, application, or component
@@ -129,6 +130,7 @@
             MATCH_DISABLED_COMPONENTS,
             MATCH_DISABLED_UNTIL_USED_COMPONENTS,
             MATCH_SYSTEM_ONLY,
+            MATCH_FACTORY_ONLY,
             MATCH_DEBUG_TRIAGED_MISSING,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -154,9 +156,8 @@
             MATCH_DEFAULT_ONLY,
             MATCH_DISABLED_COMPONENTS,
             MATCH_DISABLED_UNTIL_USED_COMPONENTS,
-            MATCH_ENCRYPTION_AWARE,
-            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
-            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_DIRECT_BOOT_AWARE,
+            MATCH_DIRECT_BOOT_UNAWARE,
             MATCH_SYSTEM_ONLY,
             MATCH_UNINSTALLED_PACKAGES,
     })
@@ -173,9 +174,8 @@
             MATCH_DISABLED_COMPONENTS,
             MATCH_DISABLED_UNTIL_USED_COMPONENTS,
             MATCH_DEFAULT_ONLY,
-            MATCH_ENCRYPTION_AWARE,
-            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
-            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_DIRECT_BOOT_AWARE,
+            MATCH_DIRECT_BOOT_UNAWARE,
             MATCH_SYSTEM_ONLY,
             MATCH_UNINSTALLED_PACKAGES,
     })
@@ -365,21 +365,47 @@
     public static final int MATCH_ALL = 0x00020000;
 
     /**
-     * Querying flag: include only components which are encryption unaware in
+     * Querying flag: match components which are direct boot <em>unaware</em> in
      * the returned info, regardless of the current user state.
+     * <p>
+     * When neither {@link #MATCH_DIRECT_BOOT_AWARE} nor
+     * {@link #MATCH_DIRECT_BOOT_UNAWARE} are specified, the default behavior is
+     * to match only runnable components based on the user state. For example,
+     * when a user is started but credentials have not been presented yet, the
+     * user is running "locked" and only {@link #MATCH_DIRECT_BOOT_AWARE}
+     * components are returned. Once the user credentials have been presented,
+     * the user is running "unlocked" and both {@link #MATCH_DIRECT_BOOT_AWARE}
+     * and {@link #MATCH_DIRECT_BOOT_UNAWARE} components are returned.
+     *
+     * @see UserManager#isUserUnlocked()
      */
+    public static final int MATCH_DIRECT_BOOT_UNAWARE = 0x00040000;
+
+    /**
+     * Querying flag: match components which are direct boot <em>aware</em> in
+     * the returned info, regardless of the current user state.
+     * <p>
+     * When neither {@link #MATCH_DIRECT_BOOT_AWARE} nor
+     * {@link #MATCH_DIRECT_BOOT_UNAWARE} are specified, the default behavior is
+     * to match only runnable components based on the user state. For example,
+     * when a user is started but credentials have not been presented yet, the
+     * user is running "locked" and only {@link #MATCH_DIRECT_BOOT_AWARE}
+     * components are returned. Once the user credentials have been presented,
+     * the user is running "unlocked" and both {@link #MATCH_DIRECT_BOOT_AWARE}
+     * and {@link #MATCH_DIRECT_BOOT_UNAWARE} components are returned.
+     *
+     * @see UserManager#isUserUnlocked()
+     */
+    public static final int MATCH_DIRECT_BOOT_AWARE = 0x00080000;
+
+    /** @removed */
+    @Deprecated
     public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
-
-    /**
-     * Querying flag: include only components which are encryption aware in the
-     * returned info, regardless of the current user state.
-     */
+    /** @removed */
+    @Deprecated
     public static final int MATCH_ENCRYPTION_AWARE = 0x00080000;
-
-    /**
-     * Querying flag: include both encryption aware and unaware components in
-     * the returned info, regardless of the current user state.
-     */
+    /** @removed */
+    @Deprecated
     public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
             | MATCH_ENCRYPTION_UNAWARE;
 
@@ -390,6 +416,13 @@
     public static final int MATCH_SYSTEM_ONLY = 0x00100000;
 
     /**
+     * Internal {@link PackageInfo} flag: include only components on the system image.
+     * This will not return information on any unbundled update to system components.
+     * @hide
+     */
+    public static final int MATCH_FACTORY_ONLY = 0x00200000;
+
+    /**
      * Internal flag used to indicate that a system component has done their
      * homework and verified that they correctly handle packages and components
      * that come and go over time. In particular:
@@ -401,7 +434,8 @@
      * </ul>
      *
      * @see #MATCH_UNINSTALLED_PACKAGES
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @hide
      */
     public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
@@ -538,6 +572,7 @@
             INSTALL_FORCE_VOLUME_UUID,
             INSTALL_FORCE_PERMISSION_PROMPT,
             INSTALL_EPHEMERAL,
+            INSTALL_DONT_KILL_APP,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface InstallFlags {}
@@ -602,7 +637,8 @@
     /**
      * Flag parameter for {@link #installPackage} to indicate that it is okay
      * to install an update to an app where the newly installed app has a lower
-     * version code than the currently installed app.
+     * version code than the currently installed app. This is permitted only if
+     * the currently installed app is marked debuggable.
      *
      * @hide
      */
@@ -639,6 +675,15 @@
     public static final int INSTALL_EPHEMERAL = 0x00000800;
 
     /**
+     * Flag parameter for {@link #installPackage} to indicate that this package contains
+     * a feature split to an existing application and the existing application should not
+     * be killed during the installation process.
+     *
+     * @hide
+     */
+    public static final int INSTALL_DONT_KILL_APP = 0x00001000;
+
+    /**
      * Flag parameter for
      * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
      * that you don't want to kill the app containing the component.  Be careful when you set this
@@ -1087,6 +1132,7 @@
             DELETE_KEEP_DATA,
             DELETE_ALL_USERS,
             DELETE_SYSTEM_APP,
+            DELETE_DONT_KILL_APP,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface DeleteFlags {}
@@ -1119,6 +1165,15 @@
     public static final int DELETE_SYSTEM_APP = 0x00000004;
 
     /**
+     * Flag parameter for {@link #deletePackage} to indicate that, if you are calling
+     * uninstall on a package that is replaced to provide new feature splits, the
+     * existing application should not be killed during the removal process.
+     *
+     * @hide
+     */
+    public static final int DELETE_DONT_KILL_APP = 0x00000008;
+
+    /**
      * Return code for when package deletion succeeds. This is passed to the
      * {@link IPackageDeleteObserver} if the system succeeded in deleting the
      * package.
@@ -1291,6 +1346,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1;
 
     /**
@@ -1300,6 +1356,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1;
 
     /**
@@ -1573,6 +1630,48 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan native API
+     * will enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate
+     * what level of optional hardware features limits it supports.
+     * <p>
+     * Level 0 includes the base Vulkan requirements as well as:
+     * <ul><li>{@code VkPhysicalDeviceFeatures::textureCompressionETC2}</li></ul>
+     * <p>
+     * Level 1 additionally includes:
+     * <ul>
+     * <li>{@code VkPhysicalDeviceFeatures::fullDrawIndexUint32}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::imageCubeArray}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::independentBlend}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::geometryShader}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::tessellationShader}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::sampleRateShading}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::textureCompressionASTC_LDR}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::fragmentStoresAndAtomics}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::shaderImageGatherExtended}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::shaderUniformBufferArrayDynamicIndexing}</li>
+     * <li>{@code VkPhysicalDeviceFeatures::shaderSampledImageArrayDynamicIndexing}</li>
+     * </ul>
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature(String, int)}: The version of this feature indicates the highest
+     * {@code VkPhysicalDeviceProperties::apiVersion} supported by the physical devices that support
+     * the hardware level indicated by {@link #FEATURE_VULKAN_HARDWARE_LEVEL}. The feature version
+     * uses the same encoding as Vulkan version numbers:
+     * <ul>
+     * <li>Major version number in bits 31-22</li>
+     * <li>Minor version number in bits 21-12</li>
+     * <li>Patch version number in bits 11-0</li>
+     * </ul>
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device includes an accelerometer.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -2502,12 +2601,15 @@
     public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
 
     /**
-     * Return an array of all of the secondary group-ids that have been assigned
-     * to a package.
+     * Return an array of all of the POSIX secondary group IDs that have been
+     * assigned to the given package.
+     * <p>
+     * Note that the same package may have different GIDs under different
+     * {@link UserHandle} on the same device.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *         desired package.
-     * @return Returns an int array of the assigned gids, or null if there are
+     *            desired package.
+     * @return Returns an int array of the assigned GIDs, or null if there are
      *         none.
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
@@ -2516,8 +2618,11 @@
             throws NameNotFoundException;
 
     /**
-     * Return an array of all of the secondary group-ids that have been assigned
-     * to a package.
+     * Return an array of all of the POSIX secondary group IDs that have been
+     * assigned to the given package.
+     * <p>
+     * Note that the same package may have different GIDs under different
+     * {@link UserHandle} on the same device.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *            desired package.
@@ -2531,6 +2636,9 @@
 
     /**
      * Return the UID associated with the given package name.
+     * <p>
+     * Note that the same package will have different UIDs under different
+     * {@link UserHandle} on the same device.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *            desired package.
@@ -2543,6 +2651,9 @@
 
     /**
      * Return the UID associated with the given package name.
+     * <p>
+     * Note that the same package will have different UIDs under different
+     * {@link UserHandle} on the same device.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *            desired package.
@@ -2557,6 +2668,9 @@
 
     /**
      * Return the UID associated with the given package name.
+     * <p>
+     * Note that the same package will have different UIDs under different
+     * {@link UserHandle} on the same device.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *            desired package.
@@ -2677,21 +2791,21 @@
      * class.
      *
      * @param component The full component name (i.e.
-     * com.google.apps.contacts/com.google.apps.contacts.ContactsList) of an Activity
-     * class.
+     *            com.google.apps.contacts/com.google.apps.contacts.
+     *            ContactsList) of an Activity class.
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     *         {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
-     *         {@link #MATCH_DISABLED_COMPONENTS},  {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE},
-     *         {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
-     *         {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return An {@link ActivityInfo} containing information about the activity.
+     *            {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *            {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return An {@link ActivityInfo} containing information about the
+     *         activity.
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
-     *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #MATCH_ALL
@@ -2699,9 +2813,8 @@
      * @see #MATCH_DEFAULT_ONLY
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -2713,21 +2826,21 @@
      * class.
      *
      * @param component The full component name (i.e.
-     * com.google.apps.calendar/com.google.apps.calendar.CalendarAlarm) of a Receiver
-     * class.
+     *            com.google.apps.calendar/com.google.apps.calendar.
+     *            CalendarAlarm) of a Receiver class.
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     *         {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
-     *         {@link #MATCH_DISABLED_COMPONENTS},  {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE},
-     *         {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
-     *         {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return An {@link ActivityInfo} containing information about the receiver.
+     *            {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *            {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return An {@link ActivityInfo} containing information about the
+     *         receiver.
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
-     *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #MATCH_ALL
@@ -2735,9 +2848,8 @@
      * @see #MATCH_DEFAULT_ONLY
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -2745,25 +2857,24 @@
             @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
-     * Retrieve all of the information we know about a particular service
-     * class.
+     * Retrieve all of the information we know about a particular service class.
      *
      * @param component The full component name (i.e.
-     * com.google.apps.media/com.google.apps.media.BackgroundPlayback) of a Service
-     * class.
+     *            com.google.apps.media/com.google.apps.media.
+     *            BackgroundPlayback) of a Service class.
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     *         {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
-     *         {@link #MATCH_DISABLED_COMPONENTS},  {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE},
-     *         {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
-     *         {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return A {@link ServiceInfo} object containing information about the service.
+     *            {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *            {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return A {@link ServiceInfo} object containing information about the
+     *         service.
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
-     *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #MATCH_ALL
@@ -2771,9 +2882,8 @@
      * @see #MATCH_DEFAULT_ONLY
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -2785,21 +2895,21 @@
      * provider class.
      *
      * @param component The full component name (i.e.
-     * com.google.providers.media/com.google.providers.media.MediaProvider) of a
-     * ContentProvider class.
+     *            com.google.providers.media/com.google.providers.media.
+     *            MediaProvider) of a ContentProvider class.
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     *         {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
-     *         {@link #MATCH_DISABLED_COMPONENTS},  {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE},
-     *         {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
-     *         {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return A {@link ProviderInfo} object containing information about the provider.
+     *            {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *            {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return A {@link ProviderInfo} object containing information about the
+     *         provider.
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
-     *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #MATCH_ALL
@@ -2807,9 +2917,8 @@
      * @see #MATCH_DEFAULT_ONLY
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3434,36 +3543,37 @@
     public abstract boolean hasSystemFeature(String name, int version);
 
     /**
-     * Determine the best action to perform for a given Intent.  This is how
-     * {@link Intent#resolveActivity} finds an activity if a class has not
-     * been explicitly specified.
-     *
-     * <p><em>Note:</em> if using an implicit Intent (without an explicit ComponentName
-     * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
-     * only flag.  You need to do so to resolve the activity in the same way
-     * that {@link android.content.Context#startActivity(Intent)} and
+     * Determine the best action to perform for a given Intent. This is how
+     * {@link Intent#resolveActivity} finds an activity if a class has not been
+     * explicitly specified.
+     * <p>
+     * <em>Note:</em> if using an implicit Intent (without an explicit
+     * ComponentName specified), be sure to consider whether to set the
+     * {@link #MATCH_DEFAULT_ONLY} only flag. You need to do so to resolve the
+     * activity in the same way that
+     * {@link android.content.Context#startActivity(Intent)} and
      * {@link android.content.Intent#resolveActivity(PackageManager)
-     * Intent.resolveActivity(PackageManager)} do.</p>
+     * Intent.resolveActivity(PackageManager)} do.
+     * </p>
      *
      * @param intent An intent containing all of the desired specification
-     *               (action, data, type, category, and/or component).
+     *            (action, data, type, category, and/or component).
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned. The most important is
-     *         {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
-     *         those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned. The most important is {@link #MATCH_DEFAULT_ONLY},
+     *            to limit the resolution to only those activities that support
+     *            the {@link android.content.Intent#CATEGORY_DEFAULT}.
      * @return Returns a ResolveInfo object containing the final activity intent
-     *         that was determined to be the best action.  Returns null if no
+     *         that was determined to be the best action. Returns null if no
      *         matching activity was found. If multiple matching activities are
      *         found and there is no default set, returns a ResolveInfo object
      *         containing something else, such as the activity resolver.
-     *
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3471,46 +3581,46 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
 
     /**
-     * Determine the best action to perform for a given Intent for a given user. This
-     * is how {@link Intent#resolveActivity} finds an activity if a class has not
-     * been explicitly specified.
-     *
-     * <p><em>Note:</em> if using an implicit Intent (without an explicit ComponentName
-     * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
-     * only flag.  You need to do so to resolve the activity in the same way
-     * that {@link android.content.Context#startActivity(Intent)} and
+     * Determine the best action to perform for a given Intent for a given user.
+     * This is how {@link Intent#resolveActivity} finds an activity if a class
+     * has not been explicitly specified.
+     * <p>
+     * <em>Note:</em> if using an implicit Intent (without an explicit
+     * ComponentName specified), be sure to consider whether to set the
+     * {@link #MATCH_DEFAULT_ONLY} only flag. You need to do so to resolve the
+     * activity in the same way that
+     * {@link android.content.Context#startActivity(Intent)} and
      * {@link android.content.Intent#resolveActivity(PackageManager)
-     * Intent.resolveActivity(PackageManager)} do.</p>
+     * Intent.resolveActivity(PackageManager)} do.
+     * </p>
      *
      * @param intent An intent containing all of the desired specification
-     *               (action, data, type, category, and/or component).
+     *            (action, data, type, category, and/or component).
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned. The most important is
-     *         {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
-     *         those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned. The most important is {@link #MATCH_DEFAULT_ONLY},
+     *            to limit the resolution to only those activities that support
+     *            the {@link android.content.Intent#CATEGORY_DEFAULT}.
      * @param userId The user id.
-     *
      * @return Returns a ResolveInfo object containing the final activity intent
-     *         that was determined to be the best action.  Returns null if no
+     *         that was determined to be the best action. Returns null if no
      *         matching activity was found. If multiple matching activities are
      *         found and there is no default set, returns a ResolveInfo object
      *         containing something else, such as the activity resolver.
-     *
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3518,12 +3628,10 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
-     *
      * @hide
      */
     public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
@@ -3534,22 +3642,22 @@
      *
      * @param intent The desired intent as per resolveActivity().
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned. The most important is
-     *         {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
-     *         those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
-     *         Or, set {@link #MATCH_ALL} to prevent any filtering of the results.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching activity, ordered from best to worst. In other words, the
-     *         first item is what would be returned by {@link #resolveActivity}.
-     *         If there are no matching activities, an empty list is returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned. The most important is {@link #MATCH_DEFAULT_ONLY},
+     *            to limit the resolution to only those activities that support
+     *            the {@link android.content.Intent#CATEGORY_DEFAULT}. Or, set
+     *            {@link #MATCH_ALL} to prevent any filtering of the results.
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching activity, ordered from best to worst. In other
+     *         words, the first item is what would be returned by
+     *         {@link #resolveActivity}. If there are no matching activities, an
+     *         empty list is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3557,9 +3665,8 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3567,26 +3674,27 @@
             @ResolveInfoFlags int flags);
 
     /**
-     * Retrieve all activities that can be performed for the given intent, for a specific user.
+     * Retrieve all activities that can be performed for the given intent, for a
+     * specific user.
      *
      * @param intent The desired intent as per resolveActivity().
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned. The most important is
-     *         {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
-     *         those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
-     *         Or, set {@link #MATCH_ALL} to prevent any filtering of the results.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching activity, ordered from best to worst. In other words, the
-     *         first item is what would be returned by {@link #resolveActivity}.
-     *         If there are no matching activities, an empty list is returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned. The most important is {@link #MATCH_DEFAULT_ONLY},
+     *            to limit the resolution to only those activities that support
+     *            the {@link android.content.Intent#CATEGORY_DEFAULT}. Or, set
+     *            {@link #MATCH_ALL} to prevent any filtering of the results.
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching activity, ordered from best to worst. In other
+     *         words, the first item is what would be returned by
+     *         {@link #resolveActivity}. If there are no matching activities, an
+     *         empty list is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3594,12 +3702,10 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
-     *
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
@@ -3607,36 +3713,35 @@
 
     /**
      * Retrieve a set of activities that should be presented to the user as
-     * similar options.  This is like {@link #queryIntentActivities}, except it
+     * similar options. This is like {@link #queryIntentActivities}, except it
      * also allows you to supply a list of more explicit Intents that you would
      * like to resolve to particular options, and takes care of returning the
      * final ResolveInfo list in a reasonable order, with no duplicates, based
      * on those inputs.
      *
-     * @param caller The class name of the activity that is making the
-     *               request.  This activity will never appear in the output
-     *               list.  Can be null.
-     * @param specifics An array of Intents that should be resolved to the
-     *                  first specific results.  Can be null.
+     * @param caller The class name of the activity that is making the request.
+     *            This activity will never appear in the output list. Can be
+     *            null.
+     * @param specifics An array of Intents that should be resolved to the first
+     *            specific results. Can be null.
      * @param intent The desired intent as per resolveActivity().
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned. The most important is
-     *         {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
-     *         those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching activity. The list is ordered first by all of the intents resolved
-     *         in <var>specifics</var> and then any additional activities that
-     *         can handle <var>intent</var> but did not get included by one of
-     *         the <var>specifics</var> intents.  If there are no matching
-     *         activities, an empty list is returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned. The most important is {@link #MATCH_DEFAULT_ONLY},
+     *            to limit the resolution to only those activities that support
+     *            the {@link android.content.Intent#CATEGORY_DEFAULT}.
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching activity. The list is ordered first by all of the
+     *         intents resolved in <var>specifics</var> and then any additional
+     *         activities that can handle <var>intent</var> but did not get
+     *         included by one of the <var>specifics</var> intents. If there are
+     *         no matching activities, an empty list is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3644,9 +3749,8 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3658,18 +3762,17 @@
      *
      * @param intent The desired intent as per resolveActivity().
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching receiver, ordered from best to worst. If there are no matching
-     *         receivers, an empty list or null is returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching receiver, ordered from best to worst. If there are
+     *         no matching receivers, an empty list or null is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3677,9 +3780,8 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3687,24 +3789,23 @@
             @ResolveInfoFlags int flags);
 
     /**
-     * Retrieve all receivers that can handle a broadcast of the given intent, for a specific
-     * user.
+     * Retrieve all receivers that can handle a broadcast of the given intent,
+     * for a specific user.
      *
      * @param intent The desired intent as per resolveActivity().
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
      * @param userHandle UserHandle of the user being queried.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching receiver, ordered from best to worst. If there are no matching
-     *         receivers, an empty list or null is returned.
-     *
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching receiver, ordered from best to worst. If there are
+     *         no matching receivers, an empty list or null is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3712,12 +3813,10 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
-     *
      * @hide
      */
     @SystemApi
@@ -3745,20 +3844,19 @@
      * Determine the best service to handle for a given Intent.
      *
      * @param intent An intent containing all of the desired specification
-     *               (action, data, type, category, and/or component).
+     *            (action, data, type, category, and/or component).
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
      * @return Returns a ResolveInfo object containing the final service intent
-     *         that was determined to be the best action.  Returns null if no
+     *         that was determined to be the best action. Returns null if no
      *         matching service was found.
-     *
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3766,9 +3864,8 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3779,19 +3876,19 @@
      *
      * @param intent The desired intent as per resolveService().
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching service, ordered from best to worst. In other words, the first
-     *         item is what would be returned by {@link #resolveService}. If there are
-     *         no matching services, an empty list or null is returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching service, ordered from best to worst. In other
+     *         words, the first item is what would be returned by
+     *         {@link #resolveService}. If there are no matching services, an
+     *         empty list or null is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3799,9 +3896,8 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3813,20 +3909,20 @@
      *
      * @param intent The desired intent as per resolveService().
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
      * @param userId The user id.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching service, ordered from best to worst. In other words, the first
-     *         item is what would be returned by {@link #resolveService}. If there are
-     *         no matching services, an empty list or null is returned.
-     *
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching service, ordered from best to worst. In other
+     *         words, the first item is what would be returned by
+     *         {@link #resolveService}. If there are no matching services, an
+     *         empty list or null is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3834,12 +3930,10 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
-     *
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
@@ -3851,19 +3945,18 @@
      * @param intent An intent containing all of the desired specification
      *            (action, data, type, category, and/or component).
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
      * @param userId The user id.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching provider, ordered from best to worst. If there are no
-     *         matching services, an empty list or null is returned.
-     *
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching provider, ordered from best to worst. If there are
+     *         no matching services, an empty list or null is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3871,12 +3964,10 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
-     *
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
@@ -3888,18 +3979,17 @@
      * @param intent An intent containing all of the desired specification
      *            (action, data, type, category, and/or component).
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
-     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
-     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE},
-     *         {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
-     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return Returns a List of ResolveInfo objects containing one entry for each
-     *         matching provider, ordered from best to worst. If there are no
-     *         matching services, an empty list or null is returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER},
+     *            {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return Returns a List of ResolveInfo objects containing one entry for
+     *         each matching provider, ordered from best to worst. If there are
+     *         no matching services, an empty list or null is returned.
      * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
      * @see #GET_SHARED_LIBRARY_FILES
@@ -3907,9 +3997,8 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_DEFAULT_ONLY
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3921,17 +4010,16 @@
      *
      * @param name The name of the provider to find.
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     *         {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
-     *         {@link #MATCH_DISABLED_COMPONENTS},  {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE},
-     *         {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
-     *         {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
-     * @return A {@link ProviderInfo} object containing information about the provider.
-     *         If a provider was not found, returns null.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *            {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
+     * @return A {@link ProviderInfo} object containing information about the
+     *         provider. If a provider was not found, returns null.
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #MATCH_ALL
@@ -3939,9 +4027,8 @@
      * @see #MATCH_DEFAULT_ONLY
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -3953,18 +4040,17 @@
      *
      * @param name The name of the provider to find.
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     *         {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
-     *         {@link #MATCH_DISABLED_COMPONENTS},  {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE},
-     *         {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
-     *         {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
+     *            {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *            {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
      * @param userId The user id.
-     *
-     * @return A {@link ProviderInfo} object containing information about the provider.
-     *         If a provider was not found, returns null.
-     *
+     * @return A {@link ProviderInfo} object containing information about the
+     *         provider. If a provider was not found, returns null.
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #MATCH_ALL
@@ -3972,12 +4058,10 @@
      * @see #MATCH_DEFAULT_ONLY
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
-     *
      * @hide
      */
     public abstract ProviderInfo resolveContentProviderAsUser(String name,
@@ -3985,29 +4069,28 @@
 
     /**
      * Retrieve content provider information.
-     *
-     * <p><em>Note: unlike most other methods, an empty result set is indicated
+     * <p>
+     * <em>Note: unlike most other methods, an empty result set is indicated
      * by a null return instead of an empty list.</em>
      *
      * @param processName If non-null, limits the returned providers to only
-     *                    those that are hosted by the given process.  If null,
-     *                    all content providers are returned.
+     *            those that are hosted by the given process. If null, all
+     *            content providers are returned.
      * @param uid If <var>processName</var> is non-null, this is the required
-     *        uid owning the requested content providers.
+     *            uid owning the requested content providers.
      * @param flags Additional option flags. Use any combination of
-     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     *         {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
-     *         {@link #MATCH_DISABLED_COMPONENTS},  {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
-     *         {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE},
-     *         {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
-     *         {@link #MATCH_UNINSTALLED_PACKAGES}
-     *         to modify the data returned.
-     *
+     *            {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *            {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY},
+     *            {@link #MATCH_DISABLED_COMPONENTS},
+     *            {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *            {@link #MATCH_DIRECT_BOOT_AWARE},
+     *            {@link #MATCH_DIRECT_BOOT_UNAWARE}, {@link #MATCH_SYSTEM_ONLY}
+     *            or {@link #MATCH_UNINSTALLED_PACKAGES} to modify the data
+     *            returned.
      * @return A list of {@link ProviderInfo} objects containing one entry for
      *         each provider either matching <var>processName</var> or, if
      *         <var>processName</var> is null, all known content providers.
      *         <em>If there are no matching providers, null is returned.</em>
-     *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #MATCH_ALL
@@ -4015,9 +4098,8 @@
      * @see #MATCH_DEFAULT_ONLY
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
-     * @see #MATCH_ENCRYPTION_AWARE
-     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
-     * @see #MATCH_ENCRYPTION_UNAWARE
+     * @see #MATCH_DIRECT_BOOT_AWARE
+     * @see #MATCH_DIRECT_BOOT_UNAWARE
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
      */
@@ -4059,7 +4141,7 @@
      *
      * @return A list of {@link InstrumentationInfo} objects containing one
      *         entry for each matching instrumentation. If there are no
-     *         instrumentation available, returns and empty list. 
+     *         instrumentation available, returns an empty list.
      *
      * @see #GET_META_DATA
      */
@@ -4296,10 +4378,34 @@
             throws NameNotFoundException;
 
     /**
-     * If the target user is a managed profile of the calling user or if the
-     * target user is the caller and 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. For badging an arbitrary drawable use
+     * Returns a managed-user-style badged copy of the given drawable allowing the user to
+     * distinguish it from the original drawable.
+     * The caller can specify the location in the bounds of the drawable to be
+     * badged where the badge should be applied as well as the density of the
+     * badge to be used.
+     * <p>
+     * If the original drawable is a BitmapDrawable and the backing bitmap is
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
+     * is performed in place and the original drawable is returned.
+     * </p>
+     *
+     * @param drawable The drawable to badge.
+     * @param badgeLocation Where in the bounds of the badged drawable to place
+     *         the badge. If it's {@code null}, the badge is applied on top of the entire
+     *         drawable being badged.
+     * @param badgeDensity The optional desired density for the badge as per
+     *         {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
+     *         the density of the display is used.
+     * @return A drawable that combines the original drawable and a badge as
+     *         determined by the system.
+     * @hide
+     */
+    public abstract Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+        int badgeDensity);
+
+    /**
+     * If the target user is a managed profile, then this returns a badged copy of the given icon
+     * to be able to distinguish it from the original icon. For badging an arbitrary drawable use
      * {@link #getUserBadgedDrawableForDensity(
      * android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}.
      * <p>
@@ -4324,17 +4430,17 @@
      * badge to be used.
      * <p>
      * If the original drawable is a BitmapDrawable and the backing bitmap is
-     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
      * is performed in place and the original drawable is returned.
      * </p>
      *
      * @param drawable The drawable to badge.
      * @param user The target user.
      * @param badgeLocation Where in the bounds of the badged drawable to place
-     *         the badge. If not provided, the badge is applied on top of the entire
+     *         the badge. If it's {@code null}, the badge is applied on top of the entire
      *         drawable being badged.
      * @param badgeDensity The optional desired density for the badge as per
-     *         {@link android.util.DisplayMetrics#densityDpi}. If not provided,
+     *         {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
      *         the density of the display is used.
      * @return A drawable that combines the original drawable and a badge as
      *         determined by the system.
@@ -4529,13 +4635,13 @@
         final PackageParser parser = new PackageParser();
         final File apkFile = new File(archiveFilePath);
         try {
-            if ((flags & (MATCH_ENCRYPTION_UNAWARE | MATCH_ENCRYPTION_AWARE)) != 0) {
+            if ((flags & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
                 // Caller expressed an explicit opinion about what encryption
                 // aware/unaware components they want to see, so fall through and
                 // give them what they want
             } else {
                 // Caller expressed no opinion, so match everything
-                flags |= MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+                flags |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
             }
 
             PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
@@ -4555,60 +4661,20 @@
      */
     @Deprecated
     public abstract void installPackage(
-            Uri packageURI, IPackageInstallObserver observer, @InstallFlags int flags,
+            Uri packageURI,
+            IPackageInstallObserver observer,
+            @InstallFlags int flags,
             String installerPackageName);
-
     /**
      * @deprecated replaced by {@link PackageInstaller}
      * @hide
      */
     @Deprecated
-    public abstract void installPackageWithVerification(Uri packageURI,
-            IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            Uri verificationURI, ContainerEncryptionParams encryptionParams);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackage(Uri packageURI, PackageInstallObserver observer,
-            @InstallFlags int flags, String installerPackageName);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,
-            @InstallFlags int flags, String installerPackageName, @UserIdInt int userId);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageWithVerification(Uri packageURI,
-            PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            Uri verificationURI, ContainerEncryptionParams encryptionParams);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
+    public abstract void installPackage(
+            Uri packageURI,
+            PackageInstallObserver observer,
+            @InstallFlags int flags,
+            String installerPackageName);
 
     /**
      * If there is already an application with the given package name installed
@@ -4682,8 +4748,8 @@
 
     /**
      * Allows a package listening to the
-     * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION intent filter verification
-     * broadcast} to respond to the package manager. The response must include
+     * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION} intent filter verification
+     * broadcast to respond to the package manager. The response must include
      * the {@code verificationCode} which is one of
      * {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS} or
      * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
@@ -4692,7 +4758,7 @@
      *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
      * @param verificationCode either {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS}
      *            or {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
-     * @param outFailedDomains a list of failed domains if the verificationCode is
+     * @param failedDomains a list of failed domains if the verificationCode is
      *            {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}, otherwise null;
      * @throws SecurityException if the caller does not have the
      *            INTENT_FILTER_VERIFICATION_AGENT permission.
@@ -4701,7 +4767,7 @@
      */
     @SystemApi
     public abstract void verifyIntentFilter(int verificationId, int verificationCode,
-            List<String> outFailedDomains);
+            List<String> failedDomains);
 
     /**
      * Get the status of a Domain Verification Result for an IntentFilter. This is
@@ -5176,7 +5242,6 @@
     public abstract void setComponentEnabledSetting(ComponentName componentName,
             int newState, int flags);
 
-
     /**
      * Return the enabled setting for a package component (activity,
      * receiver, service, provider).  This returns the last value set by
@@ -5234,6 +5299,16 @@
     public abstract int getApplicationEnabledSetting(String packageName);
 
     /**
+     * Flush the package restrictions for a given user to disk. This forces the package restrictions
+     * like component and package enabled settings to be written to disk and avoids the delay that
+     * is otherwise present when changing those settings.
+     *
+     * @param userId Ther userId of the user whose restrictions are to be flushed.
+     * @hide
+     */
+    public abstract void flushPackageRestrictionsAsUser(int userId);
+
+    /**
      * Puts the package in a hidden state, which is almost like an uninstalled state,
      * making the package unavailable, but it doesn't remove the data or the actual
      * package file. Application can be unhidden by either resetting the hidden state
@@ -5316,6 +5391,9 @@
      * will be hidden, the application will not show up in recents, will not be able to show
      * toasts or dialogs or ring the device.
      *
+     * <p>The package must already be installed. If the package is uninstalled while suspended
+     * the package will no longer be suspended.
+     *
      * @param packageNames The names of the packages to set the suspended status.
      * @param suspended If set to {@code true} than the packages will be suspended, if set to
      * {@code false} the packages will be unsuspended.
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 7fe7f84..13ebb82 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -16,6 +16,9 @@
 
 package android.content.pm;
 
+import android.content.ComponentName;
+import android.content.pm.PackageManager.NameNotFoundException;
+
 import java.util.List;
 
 /**
@@ -125,4 +128,23 @@
      * @return True a permissions review is required.
      */
     public abstract boolean isPermissionsReviewRequired(String packageName, int userId);
+
+    /**
+     * Gets all of the information we know about a particular package.
+     *
+     * @param packageName The package name to find.
+     * @param userId The user under which to check.
+     *
+     * @return An {@link ApplicationInfo} containing information about the
+     *         package.
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
+     */
+    public abstract ApplicationInfo getApplicationInfo(String packageName, int userId);
+
+    /**
+     * Interface to {@link com.android.server.pm.PackageManagerService#getHomeActivitiesAsUser}.
+     */
+    public abstract ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+            int userId);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ce6ddfd..fe8db9f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -121,6 +121,10 @@
 
     private static final int MAX_PACKAGES_PER_APK = 5;
 
+    public static final int APK_SIGNING_UNKNOWN = 0;
+    public static final int APK_SIGNING_V1 = 1;
+    public static final int APK_SIGNING_V2 = 2;
+
     // TODO: switch outError users to PackageParserException
     // TODO: refactor "codePath" to "apkPath"
 
@@ -1058,12 +1062,24 @@
         return pkg;
     }
 
+    public static int getApkSigningVersion(Package pkg) {
+        try {
+            if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
+                return APK_SIGNING_V2;
+            }
+            return APK_SIGNING_V1;
+        } catch (IOException e) {
+        }
+        return APK_SIGNING_UNKNOWN;
+    }
+
     /**
      * Collect certificates from all the APKs described in the given package,
      * populating {@link Package#mSignatures}. Also asserts that all APK
      * contents are signed correctly and consistently.
      */
-    public static void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
+    public static void collectCertificates(Package pkg, int parseFlags)
+            throws PackageParserException {
         collectCertificatesInternal(pkg, parseFlags);
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
@@ -1074,18 +1090,25 @@
         }
     }
 
-    private static void collectCertificatesInternal(Package pkg, int parseFlags) throws PackageParserException {
+    private static void collectCertificatesInternal(Package pkg, int parseFlags)
+            throws PackageParserException {
         pkg.mCertificates = null;
         pkg.mSignatures = null;
         pkg.mSigningKeys = null;
 
-        collectCertificates(pkg, new File(pkg.baseCodePath), pkg.applicationInfo.flags, parseFlags);
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+        try {
+            collectCertificates(
+                    pkg, new File(pkg.baseCodePath), pkg.applicationInfo.flags, parseFlags);
 
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                collectCertificates(pkg, new File(pkg.splitCodePaths[i]), pkg.splitFlags[i],
-                        parseFlags);
+            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+                for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+                    collectCertificates(
+                            pkg, new File(pkg.splitCodePaths[i]), pkg.splitFlags[i], parseFlags);
+                }
             }
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
@@ -1101,6 +1124,7 @@
             Certificate[][] allSignersCerts = null;
             Signature[] signatures = null;
             try {
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
                 allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
                 signatures = convertToSignatures(allSignersCerts);
                 // APK verified using APK Signature Scheme v2.
@@ -1113,6 +1137,8 @@
                         "Failed to collect certificates from " + apkPath
                                 + " using APK Signature Scheme v2",
                         e);
+            } finally {
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
 
             if (verified) {
@@ -1141,10 +1167,15 @@
         StrictJarFile jarFile = null;
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
+            // Ignore signature stripping protections when verifying APKs from system partition.
+            // For those APKs we only care about extracting signer certificates, and don't care
+            // about verifying integrity.
+            boolean signatureSchemeRollbackProtectionsEnforced =
+                    (parseFlags & PARSE_IS_SYSTEM) == 0;
             jarFile = new StrictJarFile(
                     apkPath,
-                    !verified // whether to verify JAR signature
-                    );
+                    !verified, // whether to verify JAR signature
+                    signatureSchemeRollbackProtectionsEnforced);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
             // Always verify manifest, regardless of source
@@ -1164,7 +1195,7 @@
             }
 
             // APK's integrity needs to be verified using JAR signature scheme.
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "buildVerifyList");
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1");
             final List<ZipEntry> toVerify = new ArrayList<>();
             toVerify.add(manifestEntry);
 
@@ -1186,7 +1217,6 @@
                     toVerify.add(entry);
                 }
             }
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
             if (!codeFound && requireCode) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
@@ -1196,7 +1226,6 @@
             // Verify that entries are signed consistently with the first entry
             // we encountered. Note that for splits, certificates may have
             // already been populated during an earlier parse of a base APK.
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyEntries");
             for (ZipEntry entry : toVerify) {
                 final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
                 if (ArrayUtils.isEmpty(entryCerts)) {
@@ -1278,7 +1307,12 @@
             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
                 // TODO: factor signature related items out of Package object
                 final Package tempPkg = new Package(null);
-                collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/, 0 /*flags*/);
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+                try {
+                    collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/, 0 /*flags*/);
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
                 signatures = tempPkg.mSignatures;
             } else {
                 signatures = null;
@@ -1507,6 +1541,7 @@
         childPkg.baseRevisionCode = parentPkg.baseRevisionCode;
         childPkg.mVersionName = parentPkg.mVersionName;
         childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion;
+        childPkg.applicationInfo.minSdkVersion = parentPkg.applicationInfo.minSdkVersion;
 
         childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError);
         if (childPkg == null) {
@@ -1837,10 +1872,16 @@
                             com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
                     if (val != null) {
                         if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                            targetCode = minCode = val.string.toString();
+                            targetCode = val.string.toString();
+                            if (minCode == null) {
+                                minCode = targetCode;
+                            }
                         } else {
                             // If it's not a string, it's an integer.
                             targetVers = val.data;
+                            if (minVers == 0) {
+                                minVers = targetVers;
+                            }
                         }
                     }
 
@@ -1866,11 +1907,14 @@
                             mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                             return null;
                         }
+                        pkg.applicationInfo.minSdkVersion = minCode;
                     } else if (minVers > SDK_VERSION) {
                         outError[0] = "Requires newer sdk version #" + minVers
                                 + " (current version is #" + SDK_VERSION + ")";
                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                         return null;
+                    } else {
+                        pkg.applicationInfo.minSdkVersion = Integer.toString(minVers);
                     }
 
                     if (targetCode != null) {
@@ -2838,13 +2882,13 @@
             ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
         }
 
-        if (sa.getBoolean(R.styleable.AndroidManifestApplication_forceDeviceEncrypted, false)
-                && (flags & PARSE_IS_SYSTEM) != 0) {
-            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED;
+        if (sa.getBoolean(R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
+                false) && (flags & PARSE_IS_SYSTEM) != 0) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
         }
-        if (sa.getBoolean(R.styleable.AndroidManifestApplication_encryptionAware, false)
+        if (sa.getBoolean(R.styleable.AndroidManifestApplication_directBootAware, false)
                 && (flags & PARSE_IS_SYSTEM) != 0) {
-            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE;
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
         }
 
         if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity,
@@ -3466,9 +3510,9 @@
             a.info.lockTaskLaunchMode =
                     sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
 
-            a.info.encryptionAware = sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_encryptionAware,
-                    owner.applicationInfo.isEncryptionAware());
+            a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_directBootAware,
+                    owner.applicationInfo.isDirectBootAware());
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
@@ -3484,14 +3528,14 @@
                 }
             }
 
-            a.info.encryptionAware = sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_encryptionAware,
-                    owner.applicationInfo.isEncryptionAware());
+            a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_directBootAware,
+                    owner.applicationInfo.isDirectBootAware());
         }
 
-        if (a.info.encryptionAware) {
+        if (a.info.directBootAware) {
             owner.applicationInfo.privateFlags |=
-                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
+                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
         }
 
         sa.recycle();
@@ -3616,12 +3660,15 @@
         int gravity = sw.getInt(
                 com.android.internal.R.styleable.AndroidManifestLayout_gravity,
                 Gravity.CENTER);
-        int minimalSize = sw.getDimensionPixelSize(
-                com.android.internal.R.styleable.AndroidManifestLayout_minimalSize,
+        int minimalWidth = sw.getDimensionPixelSize(
+                com.android.internal.R.styleable.AndroidManifestLayout_minimalWidth,
+                -1);
+        int minimalHeight = sw.getDimensionPixelSize(
+                com.android.internal.R.styleable.AndroidManifestLayout_minimalHeight,
                 -1);
         sw.recycle();
-        a.info.layout = new ActivityInfo.Layout(width, widthFraction,
-                height, heightFraction, gravity, minimalSize);
+        a.info.windowLayout = new ActivityInfo.WindowLayout(width, widthFraction,
+                height, heightFraction, gravity, minimalWidth, minimalHeight);
     }
 
     private Activity parseActivityAlias(Package owner, Resources res,
@@ -3703,9 +3750,9 @@
         info.uiOptions = target.info.uiOptions;
         info.parentActivityName = target.info.parentActivityName;
         info.maxRecents = target.info.maxRecents;
-        info.layout = target.info.layout;
+        info.windowLayout = target.info.windowLayout;
         info.resizeMode = target.info.resizeMode;
-        info.encryptionAware = target.info.encryptionAware;
+        info.encryptionAware = info.directBootAware = target.info.directBootAware;
 
         Activity a = new Activity(mParseActivityAliasArgs, info);
         if (outError[0] != null) {
@@ -3894,12 +3941,12 @@
             }
         }
 
-        p.info.encryptionAware = sa.getBoolean(
-                R.styleable.AndroidManifestProvider_encryptionAware,
-                owner.applicationInfo.isEncryptionAware());
-        if (p.info.encryptionAware) {
+        p.info.encryptionAware = p.info.directBootAware = sa.getBoolean(
+                R.styleable.AndroidManifestProvider_directBootAware,
+                owner.applicationInfo.isDirectBootAware());
+        if (p.info.directBootAware) {
             owner.applicationInfo.privateFlags |=
-                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
+                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
         }
 
         sa.recycle();
@@ -4186,12 +4233,12 @@
             }
         }
 
-        s.info.encryptionAware = sa.getBoolean(
-                R.styleable.AndroidManifestService_encryptionAware,
-                owner.applicationInfo.isEncryptionAware());
-        if (s.info.encryptionAware) {
+        s.info.encryptionAware = s.info.directBootAware = sa.getBoolean(
+                R.styleable.AndroidManifestService_directBootAware,
+                owner.applicationInfo.isDirectBootAware());
+        if (s.info.directBootAware) {
             owner.applicationInfo.privateFlags |=
-                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
+                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
         }
 
         sa.recycle();
@@ -4690,9 +4737,6 @@
         // preferred up order.
         public int mPreferredOrder = 0;
 
-        // For use by package manager to keep track of where it needs to do dexopt.
-        public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
-
         // For use by package manager to keep track of when a package was last used.
         public long mLastPackageUsageTimeInMills;
 
@@ -5499,7 +5543,7 @@
         return pi;
     }
 
-    public final static class Instrumentation extends Component {
+    public final static class Instrumentation extends Component<IntentInfo> {
         public final InstrumentationInfo info;
 
         public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 38e0044..e85311d 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -23,8 +23,8 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
 import android.util.ArraySet;
@@ -98,10 +98,10 @@
             }
         }
 
-        final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0)
-                && !componentInfo.encryptionAware;
-        final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0)
-                && componentInfo.encryptionAware;
+        final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
+                && !componentInfo.directBootAware;
+        final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
+                && componentInfo.directBootAware;
         return matchesUnaware || matchesAware;
     }
 
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 9da2ba9..65e0b92 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -112,6 +113,13 @@
     public static final int PROTECTION_FLAG_PREINSTALLED = 0x400;
 
     /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>setup</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     */
+    public static final int PROTECTION_FLAG_SETUP = 0x800;
+
+    /**
      * Mask for {@link #protectionLevel}: the basic protection type.
      */
     public static final int PROTECTION_MASK_BASE = 0xf;
@@ -145,11 +153,12 @@
     public static final int FLAG_COSTS_MONEY = 1<<0;
 
     /**
-     * Flag for {@link #flags}, corresponding to <code>hidden</code>
+     * Flag for {@link #flags}, corresponding to <code>removed</code>
      * value of {@link android.R.attr#permissionFlags}.
      * @hide
      */
-    public static final int FLAG_HIDDEN = 1<<1;
+    @SystemApi
+    public static final int FLAG_REMOVED = 1<<1;
 
     /**
      * Flag for {@link #flags}, indicating that this permission has been
@@ -224,6 +233,9 @@
         if ((level&PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) {
             protLevel += "|preinstalled";
         }
+        if ((level&PermissionInfo.PROTECTION_FLAG_SETUP) != 0) {
+            protLevel += "|setup";
+        }
         return protLevel;
     }
 
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index bb28bde..6162d1a 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -365,7 +365,8 @@
     protected List<ResolveInfo> queryIntentServices(int userId) {
         final PackageManager pm = mContext.getPackageManager();
         return pm.queryIntentServicesAsUser(new Intent(mInterfaceName),
-                PackageManager.GET_META_DATA | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+                PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
     }
 
diff --git a/core/java/android/content/pm/ShortcutInfo.aidl b/core/java/android/content/pm/ShortcutInfo.aidl
new file mode 100644
index 0000000..08e1873
--- /dev/null
+++ b/core/java/android/content/pm/ShortcutInfo.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 ShortcutInfo;
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
new file mode 100644
index 0000000..1812575a
--- /dev/null
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+// TODO Enhance javadoc
+/**
+ *
+ * Represents a shortcut from an application.
+ *
+ * <p>Notes about icons:
+ * <ul>
+ *     <li>If an {@link Icon} is a resource, the system keeps the package name and the resource ID.
+ *     Otherwise, the bitmap is fetched when it's registered to ShortcutManager,
+ *     then shrunk if necessary, and persisted.
+ *     <li>The system disallows byte[] icons, because they can easily go over the binder size limit.
+ * </ul>
+ *
+ * @see {@link ShortcutManager}.
+ */
+public final class ShortcutInfo implements Parcelable {
+    /* @hide */
+    public static final int FLAG_DYNAMIC = 1 << 0;
+
+    /* @hide */
+    public static final int FLAG_PINNED = 1 << 1;
+
+    /* @hide */
+    public static final int FLAG_HAS_ICON_RES = 1 << 2;
+
+    /* @hide */
+    public static final int FLAG_HAS_ICON_FILE = 1 << 3;
+
+    /* @hide */
+    public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
+
+    /** @hide */
+    @IntDef(flag = true,
+            value = {
+            FLAG_DYNAMIC,
+            FLAG_PINNED,
+            FLAG_HAS_ICON_RES,
+            FLAG_HAS_ICON_FILE,
+            FLAG_KEY_FIELDS_ONLY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ShortcutFlags {}
+
+    // Cloning options.
+
+    /* @hide */
+    private static final int CLONE_REMOVE_ICON = 1 << 0;
+
+    /* @hide */
+    private static final int CLONE_REMOVE_INTENT = 1 << 1;
+
+    /* @hide */
+    public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
+
+    /* @hide */
+    public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON;
+
+    /* @hide */
+    public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT;
+
+    /** @hide */
+    @IntDef(flag = true,
+            value = {
+                    CLONE_REMOVE_ICON,
+                    CLONE_REMOVE_INTENT,
+                    CLONE_REMOVE_NON_KEY_INFO,
+                    CLONE_REMOVE_FOR_CREATOR,
+                    CLONE_REMOVE_FOR_LAUNCHER
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CloneFlags {}
+
+    private final String mId;
+
+    @NonNull
+    private final String mPackageName;
+
+    @Nullable
+    private ComponentName mActivityComponent;
+
+    @Nullable
+    private Icon mIcon;
+
+    @NonNull
+    private String mTitle;
+
+    @Nullable
+    private String mText;
+
+    /**
+     * Intent *with extras removed*.
+     */
+    @NonNull
+    private Intent mIntent;
+
+    /**
+     * Extras for the intent.
+     */
+    @NonNull
+    private PersistableBundle mIntentPersistableExtras;
+
+    private int mWeight;
+
+    @Nullable
+    private PersistableBundle mExtras;
+
+    private long mLastChangedTimestamp;
+
+    // Internal use only.
+    @ShortcutFlags
+    private int mFlags;
+
+    // Internal use only.
+    private int mIconResourceId;
+
+    // Internal use only.
+    @Nullable
+    private String mBitmapPath;
+
+    private ShortcutInfo(Builder b) {
+        mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
+
+        // Note we can't do other null checks here because SM.updateShortcuts() takes partial
+        // information.
+        mPackageName = b.mContext.getPackageName();
+        mActivityComponent = b.mActivityComponent;
+        mIcon = b.mIcon;
+        mTitle = b.mTitle;
+        mText = b.mText;
+        mIntent = b.mIntent;
+        if (mIntent != null) {
+            final Bundle intentExtras = mIntent.getExtras();
+            if (intentExtras != null) {
+                mIntent.replaceExtras((Bundle) null);
+                mIntentPersistableExtras = new PersistableBundle(intentExtras);
+            }
+        }
+        mWeight = b.mWeight;
+        mExtras = b.mExtras;
+        updateTimestamp();
+    }
+
+    /**
+     * Throws if any of the mandatory fields is not set.
+     *
+     * @hide
+     */
+    public void enforceMandatoryFields() {
+        Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
+        Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
+        Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
+    }
+
+    /**
+     * Copy constructor.
+     */
+    private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
+        mId = source.mId;
+        mPackageName = source.mPackageName;
+        mFlags = source.mFlags;
+        mLastChangedTimestamp = source.mLastChangedTimestamp;
+
+        if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
+            mActivityComponent = source.mActivityComponent;
+
+            if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
+                mIcon = source.mIcon;
+                mBitmapPath = source.mBitmapPath;
+                mIconResourceId = source.mIconResourceId;
+            }
+
+            mTitle = source.mTitle;
+            mText = source.mText;
+            if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
+                mIntent = source.mIntent;
+                mIntentPersistableExtras = source.mIntentPersistableExtras;
+            }
+            mWeight = source.mWeight;
+            mExtras = source.mExtras;
+        } else {
+            // Set this bit.
+            mFlags |= FLAG_KEY_FIELDS_ONLY;
+        }
+    }
+
+    /**
+     * Copy a {@link ShortcutInfo}, optionally removing fields.
+     * @hide
+     */
+    public ShortcutInfo clone(@CloneFlags int cloneFlags) {
+        return new ShortcutInfo(this, cloneFlags);
+    }
+
+    /**
+     * Copy non-null/zero fields from another {@link ShortcutInfo}.  Only "public" information
+     * will be overwritten.  The timestamp will be updated.
+     *
+     * - Flags will not change
+     * - mBitmapPath will not change
+     * - Current time will be set to timestamp
+     *
+     * @hide
+     */
+    public void copyNonNullFieldsFrom(ShortcutInfo source) {
+        Preconditions.checkState(mId.equals(source.mId), "ID must match");
+        Preconditions.checkState(mPackageName.equals(source.mPackageName),
+                "Package name must match");
+
+        if (source.mActivityComponent != null) {
+            mActivityComponent = source.mActivityComponent;
+        }
+
+        if (source.mIcon != null) {
+            mIcon = source.mIcon;
+        }
+        if (source.mTitle != null) {
+            mTitle = source.mTitle;
+        }
+        if (source.mText != null) {
+            mText = source.mText;
+        }
+        if (source.mIntent != null) {
+            mIntent = source.mIntent;
+            mIntentPersistableExtras = source.mIntentPersistableExtras;
+        }
+        if (source.mWeight != 0) {
+            mWeight = source.mWeight;
+        }
+        if (source.mExtras != null) {
+            mExtras = source.mExtras;
+        }
+
+        updateTimestamp();
+    }
+
+    /**
+     * @hide
+     */
+    public static Icon validateIcon(Icon icon) {
+        switch (icon.getType()) {
+            case Icon.TYPE_RESOURCE:
+            case Icon.TYPE_BITMAP:
+                break; // OK
+            case Icon.TYPE_URI:
+                if (ContentResolver.SCHEME_CONTENT.equals(icon.getUri().getScheme())) {
+                    break;
+                }
+                // Note "file:" is not supported, because depending on the path, system server
+                // cannot access it. // TODO Revisit "file:" icon support
+
+                // fall through
+            default:
+                throw getInvalidIconException();
+        }
+        if (icon.hasTint()) {
+            // TODO support it
+            throw new IllegalArgumentException("Icons with tints are not supported");
+        }
+
+        return icon;
+    }
+
+    /** @hide */
+    public static IllegalArgumentException getInvalidIconException() {
+        return new IllegalArgumentException("Unsupported icon type:"
+                +" only bitmap, resource and content URI are supported");
+    }
+
+    /**
+     * Builder class for {@link ShortcutInfo} objects.
+     */
+    public static class Builder {
+        private final Context mContext;
+
+        private String mId;
+
+        private ComponentName mActivityComponent;
+
+        private Icon mIcon;
+
+        private String mTitle;
+
+        private String mText;
+
+        private Intent mIntent;
+
+        private int mWeight;
+
+        private PersistableBundle mExtras;
+
+        /** Constructor. */
+        public Builder(Context context) {
+            mContext = context;
+        }
+
+        /**
+         * Sets the ID of the shortcut.  This is a mandatory field.
+         */
+        @NonNull
+        public Builder setId(@NonNull String id) {
+            mId = Preconditions.checkStringNotEmpty(id, "id");
+            return this;
+        }
+
+        /**
+         * Optionally sets the target activity.  If it's not set, and if the caller application
+         * has multiple launcher icons, this shortcut will be shown on all those icons.
+         * If it's set, this shortcut will be only shown on this activity.
+         */
+        @NonNull
+        public Builder setActivityComponent(@NonNull ComponentName activityComponent) {
+            mActivityComponent = Preconditions.checkNotNull(activityComponent, "activityComponent");
+            return this;
+        }
+
+        /**
+         * Optionally sets an icon.
+         *
+         * <ul>
+         *     <li>Tints are not supported.
+         *     <li>Bitmaps, resources and "content:" URIs are supported.
+         *     <li>"content:" URI will be fetched when a shortcut is registered to
+         *         {@link ShortcutManager}.  Changing the content from the same URI later will
+         *         not be reflected to launcher icons.
+         * </ul>
+         *
+         * <p>For performance reasons, icons will <b>NOT</b> be available on instances
+         * returned by {@link ShortcutManager} or {@link LauncherApps}.  Launcher applications
+         * need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)}
+         * and {@link LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)}.
+         */
+        @NonNull
+        public Builder setIcon(Icon icon) {
+            mIcon = validateIcon(icon);
+            return this;
+        }
+
+        /**
+         * Sets the title of a shortcut.  This is a mandatory field.
+         *
+         * <p>This field is intended for a concise description of a shortcut displayed under
+         * an icon.  The recommend max length is 10 characters.
+         */
+        @NonNull
+        public Builder setTitle(@NonNull String title) {
+            mTitle = Preconditions.checkStringNotEmpty(title, "title");
+            return this;
+        }
+
+        /**
+         * Sets the text of a shortcut.  This is an optional field.
+         *
+         * <p>This field is intended to be more descriptive than the shortcut title.
+         * The recommend max length is 25 characters.
+         */
+        @NonNull
+        public Builder setText(@NonNull String text) {
+            mText = Preconditions.checkStringNotEmpty(text, "text");
+            return this;
+        }
+
+        /**
+         * Sets the intent of a shortcut.  This is a mandatory field.  The extras must only contain
+         * persistable information.  (See {@link PersistableBundle}).
+         */
+        @NonNull
+        public Builder setIntent(@NonNull Intent intent) {
+            mIntent = Preconditions.checkNotNull(intent, "intent");
+            return this;
+        }
+
+        /**
+         * Optionally sets the weight of a shortcut, which will be used by the launcher for sorting.
+         * The larger the weight, the more "important" a shortcut is.
+         */
+        @NonNull
+        public Builder setWeight(int weight) {
+            mWeight = weight;
+            return this;
+        }
+
+        /**
+         * Optional values that applications can set.  Applications can store any meta-data of
+         * shortcuts in this, and retrieve later from {@link ShortcutInfo#getExtras()}.
+         */
+        @NonNull
+        public Builder setExtras(@NonNull PersistableBundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Creates a {@link ShortcutInfo} instance.
+         */
+        @NonNull
+        public ShortcutInfo build() {
+            return new ShortcutInfo(this);
+        }
+    }
+
+    /**
+     * Return the ID of the shortcut.
+     */
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
+    /**
+     * Return the package name of the creator application.
+     */
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Return the target activity, which may be null, in which case the shortcut is not associated
+     * with a specific activity.
+     */
+    @Nullable
+    public ComponentName getActivityComponent() {
+        return mActivityComponent;
+    }
+
+    /**
+     * Icon.
+     *
+     * For performance reasons, this will <b>NOT</b> be available when an instance is returned
+     * by {@link ShortcutManager} or {@link LauncherApps}.  A launcher application needs to use
+     * other APIs in LauncherApps to fetch the bitmap.
+     *
+     * @hide
+     */
+    @Nullable
+    public Icon getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Return the shortcut title.
+     *
+     * <p>All shortcuts must have a non-empty title, but this method will return null when
+     * {@link #hasKeyFieldsOnly()} is true.
+     */
+    @Nullable
+    public String getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Return the shortcut text.
+     */
+    @Nullable
+    public String getText() {
+        return mText;
+    }
+
+    /**
+     * Return the intent.
+     *
+     * <p>All shortcuts must have an intent, but this method will return null when
+     * {@link #hasKeyFieldsOnly()} is true.
+     */
+    @Nullable
+    public Intent getIntent() {
+        if (mIntent == null) {
+            return null;
+        }
+        final Intent intent = new Intent(mIntent);
+        intent.replaceExtras(
+                mIntentPersistableExtras != null ? new Bundle(mIntentPersistableExtras) : null);
+        return intent;
+    }
+
+    /**
+     * Return "raw" intent, which is the original intent without the extras.
+     * @hide
+     */
+    @Nullable
+    public Intent getIntentNoExtras() {
+        return mIntent;
+    }
+
+    /**
+     * The extras in the intent.  We convert extras into {@link PersistableBundle} so we can
+     * persist them.
+     * @hide
+     */
+    @Nullable
+    public PersistableBundle getIntentPersistableExtras() {
+        return mIntentPersistableExtras;
+    }
+
+    /**
+     * Return the weight of a shortcut, which will be used by Launcher for sorting.
+     * The larger the weight, the more "important" a shortcut is.
+     */
+    public int getWeight() {
+        return mWeight;
+    }
+
+    /**
+     * Optional values that application can set.
+     */
+    @Nullable
+    public PersistableBundle getExtras() {
+        return mExtras;
+    }
+
+    /**
+     * Last time when any of the fields was updated.
+     */
+    public long getLastChangedTimestamp() {
+        return mLastChangedTimestamp;
+    }
+
+    /** @hide */
+    @ShortcutFlags
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /** @hide*/
+    public void replaceFlags(@ShortcutFlags int flags) {
+        mFlags = flags;
+    }
+
+    /** @hide*/
+    public void addFlags(@ShortcutFlags int flags) {
+        mFlags |= flags;
+    }
+
+    /** @hide*/
+    public void clearFlags(@ShortcutFlags int flags) {
+        mFlags &= ~flags;
+    }
+
+    /** @hide*/
+    public boolean hasFlags(@ShortcutFlags int flags) {
+        return (mFlags & flags) == flags;
+    }
+
+    /** Return whether a shortcut is dynamic. */
+    public boolean isDynamic() {
+        return hasFlags(FLAG_DYNAMIC);
+    }
+
+    /** Return whether a shortcut is pinned. */
+    public boolean isPinned() {
+        return hasFlags(FLAG_PINNED);
+    }
+
+    /**
+     * Return whether a shortcut's icon is a resource in the owning package.
+     *
+     * @see LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)
+     */
+    public boolean hasIconResource() {
+        return hasFlags(FLAG_HAS_ICON_RES);
+    }
+
+    /**
+     * Return whether a shortcut's icon is stored as a file.
+     *
+     * @see LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)
+     */
+    public boolean hasIconFile() {
+        return hasFlags(FLAG_HAS_ICON_FILE);
+    }
+
+    /**
+     * Return whether a shortcut only contains "key" information only or not.  If true, only the
+     * following fields are available.
+     * <ul>
+     *     <li>{@link #getId()}
+     *     <li>{@link #getPackageName()}
+     *     <li>{@link #getLastChangedTimestamp()}
+     *     <li>{@link #isDynamic()}
+     *     <li>{@link #isPinned()}
+     *     <li>{@link #hasIconResource()}
+     *     <li>{@link #hasIconFile()}
+     * </ul>
+     */
+    public boolean hasKeyFieldsOnly() {
+        return hasFlags(FLAG_KEY_FIELDS_ONLY);
+    }
+
+    /** @hide */
+    public void updateTimestamp() {
+        mLastChangedTimestamp = System.currentTimeMillis();
+    }
+
+    /** @hide */
+    // VisibleForTesting
+    public void setTimestamp(long value) {
+        mLastChangedTimestamp = value;
+    }
+
+    /** @hide */
+    public void clearIcon() {
+        mIcon = null;
+    }
+
+    /** @hide */
+    public void setIconResourceId(int iconResourceId) {
+        mIconResourceId = iconResourceId;
+    }
+
+    /** @hide */
+    public int getIconResourceId() {
+        return mIconResourceId;
+    }
+
+    /** @hide */
+    public String getBitmapPath() {
+        return mBitmapPath;
+    }
+
+    /** @hide */
+    public void setBitmapPath(String bitmapPath) {
+        mBitmapPath = bitmapPath;
+    }
+
+    private ShortcutInfo(Parcel source) {
+        final ClassLoader cl = getClass().getClassLoader();
+
+        mId = source.readString();
+        mPackageName = source.readString();
+        mActivityComponent = source.readParcelable(cl);
+        mIcon = source.readParcelable(cl);
+        mTitle = source.readString();
+        mText = source.readString();
+        mIntent = source.readParcelable(cl);
+        mIntentPersistableExtras = source.readParcelable(cl);
+        mWeight = source.readInt();
+        mExtras = source.readParcelable(cl);
+        mLastChangedTimestamp = source.readLong();
+        mFlags = source.readInt();
+        mIconResourceId = source.readInt();
+        mBitmapPath = source.readString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+        dest.writeString(mPackageName);
+        dest.writeParcelable(mActivityComponent, flags);
+        dest.writeParcelable(mIcon, flags);
+        dest.writeString(mTitle);
+        dest.writeString(mText);
+        dest.writeParcelable(mIntent, flags);
+        dest.writeParcelable(mIntentPersistableExtras, flags);
+        dest.writeInt(mWeight);
+        dest.writeParcelable(mExtras, flags);
+        dest.writeLong(mLastChangedTimestamp);
+        dest.writeInt(mFlags);
+        dest.writeInt(mIconResourceId);
+        dest.writeString(mBitmapPath);
+    }
+
+    public static final Creator<ShortcutInfo> CREATOR =
+            new Creator<ShortcutInfo>() {
+                public ShortcutInfo createFromParcel(Parcel source) {
+                    return new ShortcutInfo(source);
+                }
+                public ShortcutInfo[] newArray(int size) {
+                    return new ShortcutInfo[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Return a string representation, intended for logging.  Some fields will be retracted.
+     */
+    @Override
+    public String toString() {
+        return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false);
+    }
+
+    /** @hide */
+    public String toInsecureString() {
+        return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true);
+    }
+
+    private String toStringInner(boolean secure, boolean includeInternalData) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("ShortcutInfo {");
+
+        sb.append("id=");
+        sb.append(secure ? "***" : mId);
+
+        sb.append(", packageName=");
+        sb.append(mPackageName);
+
+        if (isDynamic()) {
+            sb.append(", dynamic");
+        }
+        if (isPinned()) {
+            sb.append(", pinned");
+        }
+
+        sb.append(", activity=");
+        sb.append(mActivityComponent);
+
+        sb.append(", title=");
+        sb.append(secure ? "***" : mTitle);
+
+        sb.append(", text=");
+        sb.append(secure ? "***" : mText);
+
+        sb.append(", icon=");
+        sb.append(mIcon);
+
+        sb.append(", weight=");
+        sb.append(mWeight);
+
+        sb.append(", timestamp=");
+        sb.append(mLastChangedTimestamp);
+
+        sb.append(", intent=");
+        sb.append(mIntent);
+
+        sb.append(", intentExtras=");
+        sb.append(secure ? "***" : mIntentPersistableExtras);
+
+        sb.append(", extras=");
+        sb.append(mExtras);
+
+        sb.append(", flags=");
+        sb.append(mFlags);
+
+        if (includeInternalData) {
+
+            sb.append(", iconRes=");
+            sb.append(mIconResourceId);
+
+            sb.append(", bitmapPath=");
+            sb.append(mBitmapPath);
+        }
+
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /** @hide */
+    public ShortcutInfo(String id, String packageName, ComponentName activityComponent,
+            Icon icon, String title, String text, Intent intent,
+            PersistableBundle intentPersistableExtras,
+            int weight, PersistableBundle extras, long lastChangedTimestamp,
+            int flags, int iconResId, String bitmapPath) {
+        mId = id;
+        mPackageName = packageName;
+        mActivityComponent = activityComponent;
+        mIcon = icon;
+        mTitle = title;
+        mText = text;
+        mIntent = intent;
+        mIntentPersistableExtras = intentPersistableExtras;
+        mWeight = weight;
+        mExtras = extras;
+        mLastChangedTimestamp = lastChangedTimestamp;
+        mFlags = flags;
+        mIconResourceId = iconResId;
+        mBitmapPath = bitmapPath;
+    }
+}
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
new file mode 100644
index 0000000..e4a98b5
--- /dev/null
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.annotation.NonNull;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+// TODO Enhance javadoc
+/**
+ * {@link ShortcutManager} manages shortcuts created by applications.
+ *
+ * <h3>Dynamic shortcuts and pinned shortcuts</h3>
+ *
+ * An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and
+ * {@link #addDynamicShortcut(ShortcutInfo)}.  There can be at most
+ * {@link #getMaxDynamicShortcutCount()} number of dynamic shortcuts at a time from the same
+ * application.
+ * A dynamic shortcut can be deleted with {@link #deleteDynamicShortcut(String)}, and apps
+ * can also use {@link #deleteAllDynamicShortcuts()} to delete all dynamic shortcuts.
+ *
+ * <p>The shortcuts that are currently published by the above APIs are called "dynamic", because
+ * they can be removed by the creator application at any time.  The user may "pin" dynamic shortcuts
+ * on Launcher to make "pinned" shortcuts.  Pinned shortcuts <b>cannot</b> be removed by the creator
+ * app.  An application can obtain all pinned shortcuts from itself with
+ * {@link #getPinnedShortcuts()}.  Applications should keep the pinned shortcut information
+ * up-to-date using {@link #updateShortcuts(List)}.
+ *
+ * <p>The number of pinned shortcuts does not affect the number of dynamic shortcuts that can be
+ * published by an application at a time.
+ * No matter how many pinned shortcuts that Launcher has for an application, the
+ * application can still always publish {@link #getMaxDynamicShortcutCount()} number of dynamic
+ * shortcuts.
+ *
+ * <h3>Shortcut IDs</h3>
+ *
+ * Each shortcut must have an ID, which must be unique within each application.  When a shortcut is
+ * published, existing shortcuts with the same ID will be updated.  Note this may include a
+ * pinned shortcut.
+ *
+ * <h3>Rate limiting</h3>
+ *
+ * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcut(ShortcutInfo)},
+ * and {@link #updateShortcuts(List)} will be
+ * rate-limited.  An application can call these methods at most
+ * {@link #getRemainingCallCount()} times until the rate-limiting counter is reset,
+ * which happens at a certain time every day.
+ *
+ * <p>An application can use {@link #getRateLimitResetTime()} to get the next reset time.
+ *
+ * <p>For testing purposes, use "Developer Options" (found in the Settings menu) to reset the
+ * internal rate-limiting counter.  Automated tests can use the following ADB shell command to
+ * achieve the same effect:</p>
+ * <pre>adb shell cmd shortcut reset-throttling</pre>
+ *
+ * <h3>Backup and Restore</h3>
+ *
+ * Shortcuts will be backed up and restored across devices.  This means all information, including
+ * IDs, must be meaningful on a different device.
+ *
+ * <h3>APIs for launcher</h3>
+ *
+ * Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
+ * applications.  Launcher applications can also pin shortcuts with
+ * {@link LauncherApps#pinShortcuts(String, List, UserHandle)}.
+ */
+public class ShortcutManager {
+    private static final String TAG = "ShortcutManager";
+
+    private final Context mContext;
+    private final IShortcutService mService;
+
+    /**
+     * @hide
+     */
+    public ShortcutManager(Context context, IShortcutService service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Publish a list of shortcuts.  All existing dynamic shortcuts from the caller application
+     * will be replaced.
+     *
+     * <p>This API will be rate-limited.
+     *
+     * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
+     *
+     * @throws IllegalArgumentException if {@code shortcutInfoList} contains more than
+     * {@link #getMaxDynamicShortcutCount()} shortcuts.
+     */
+    public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
+        try {
+            return mService.setDynamicShortcuts(mContext.getPackageName(),
+                    new ParceledListSlice(shortcutInfoList), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return all dynamic shortcuts from the caller application.  The number of result items
+     * will not exceed the value returned by {@link #getMaxDynamicShortcutCount()}.
+     */
+    @NonNull
+    public List<ShortcutInfo> getDynamicShortcuts() {
+        try {
+            return mService.getDynamicShortcuts(mContext.getPackageName(), injectMyUserId())
+                    .getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Publish a single dynamic shortcut.  If there's already dynamic or pinned shortcuts with
+     * the same ID, they will all be updated.
+     *
+     * <p>This API will be rate-limited.
+     *
+     * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
+     *
+     * @throws IllegalArgumentException if the caller application has already published the
+     * max number of dynamic shortcuts.
+     */
+    public boolean addDynamicShortcut(@NonNull ShortcutInfo shortcutInfo) {
+        try {
+            return mService.addDynamicShortcut(
+                    mContext.getPackageName(), shortcutInfo, injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Delete a single dynamic shortcut by ID.
+     */
+    public void deleteDynamicShortcut(@NonNull String shortcutId) {
+        try {
+            mService.deleteDynamicShortcut(mContext.getPackageName(), shortcutId, injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Delete all dynamic shortcuts from the caller application.
+     */
+    public void deleteAllDynamicShortcuts() {
+        try {
+            mService.deleteAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return all pinned shortcuts from the caller application.
+     */
+    @NonNull
+    public List<ShortcutInfo> getPinnedShortcuts() {
+        try {
+            return mService.getPinnedShortcuts(mContext.getPackageName(), injectMyUserId())
+                    .getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Update all existing shortcuts with the same IDs.  Shortcuts may be pinned and/or dynamic.
+     *
+     * <p>This API will be rate-limited.
+     *
+     * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
+     */
+    public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
+        try {
+            return mService.updateShortcuts(mContext.getPackageName(),
+                    new ParceledListSlice(shortcutInfoList), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the max number of dynamic shortcuts that each application can have at a time.
+     */
+    public int getMaxDynamicShortcutCount() {
+        try {
+            return mService.getMaxDynamicShortcutCount(mContext.getPackageName(), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the number of times the caller application can call the rate-limited APIs
+     * before the rate limit counter is reset.
+     *
+     * @see #getRateLimitResetTime()
+     */
+    public int getRemainingCallCount() {
+        try {
+            return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return when the rate limit count will be reset next time, in milliseconds since the epoch.
+     *
+     * @see #getRemainingCallCount()
+     * @see System#currentTimeMillis()
+     */
+    public long getRateLimitResetTime() {
+        try {
+            return mService.getRateLimitResetTime(mContext.getPackageName(), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the max width and height for icons, in pixels.
+     */
+    public int getIconMaxDimensions() {
+        try {
+            return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide injection point */
+    @VisibleForTesting
+    protected int injectMyUserId() {
+        return UserHandle.myUserId();
+    }
+}
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
new file mode 100644
index 0000000..d57f2e6e
--- /dev/null
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+
+import java.util.List;
+
+/**
+ * Entry points used by {@link LauncherApps}.
+ *
+ * <p>No permission / argument checks will be performed inside.
+ * Callers must check the calling app permission and the calling package name.
+ * @hide
+ */
+public abstract class ShortcutServiceInternal {
+    public interface ShortcutChangeListener {
+        void onShortcutChanged(@NonNull String packageName, @UserIdInt int userId);
+    }
+
+    public abstract List<ShortcutInfo>
+            getShortcuts(int launcherUserId,
+            @NonNull String callingPackage, long changedSince,
+            @Nullable String packageName, @Nullable ComponentName componentName,
+            @ShortcutQuery.QueryFlags int flags,
+            int userId);
+
+    public abstract List<ShortcutInfo>
+            getShortcutInfo(int launcherUserId, @NonNull String callingPackage,
+            @NonNull String packageName, @Nullable List<String> ids, int userId);
+
+
+    public abstract boolean
+            isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
+            @NonNull String packageName, @NonNull String id, int userId);
+
+    public abstract void pinShortcuts(int launcherUserId,
+            @NonNull String callingPackage, @NonNull String packageName,
+            @NonNull List<String> shortcutIds, int userId);
+
+    public abstract Intent createShortcutIntent(int launcherUserId, @NonNull String callingPackage,
+            @NonNull String packageName, @NonNull String shortcutId, int userId);
+
+    public abstract void addListener(@NonNull ShortcutChangeListener listener);
+
+    public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
+            @NonNull ShortcutInfo shortcut, int userId);
+
+    public abstract ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
+            @NonNull String callingPackage,
+            @NonNull ShortcutInfo shortcut, int userId);
+
+    public abstract boolean hasShortcutHostPermission(int launcherUserId,
+            @NonNull String callingPackage);
+}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 9cf4675..dd3a36c 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -73,6 +73,9 @@
 
     /**
      * Indicates that this user is disabled.
+     *
+     * <p>Note: If an ephemeral user is disabled, it shouldn't be later re-enabled. Ephemeral users
+     * are disabled as their removal is in progress to indicate that they shouldn't be re-entered.
      */
     public static final int FLAG_DISABLED = 0x00000040;
 
@@ -93,6 +96,7 @@
     public int flags;
     public long creationTime;
     public long lastLoggedInTime;
+    public String lastLoggedInFingerprint;
     public int profileGroupId;
     public int restrictedProfileParentId;
 
@@ -171,6 +175,10 @@
      * @return true if this user can be switched to.
      **/
     public boolean supportsSwitchTo() {
+        if (isEphemeral() && !isEnabled()) {
+            // Don't support switching to an ephemeral user with removal in progress.
+            return false;
+        }
         // TODO remove fw.show_hidden_users when we have finished developing managed profiles.
         return !isManagedProfile() || SystemProperties.getBoolean("fw.show_hidden_users", false);
     }
@@ -207,8 +215,10 @@
         serialNumber = orig.serialNumber;
         creationTime = orig.creationTime;
         lastLoggedInTime = orig.lastLoggedInTime;
+        lastLoggedInFingerprint = orig.lastLoggedInFingerprint;
         partial = orig.partial;
         profileGroupId = orig.profileGroupId;
+        restrictedProfileParentId = orig.restrictedProfileParentId;
         guestToRemove = orig.guestToRemove;
     }
 
@@ -233,6 +243,7 @@
         dest.writeInt(serialNumber);
         dest.writeLong(creationTime);
         dest.writeLong(lastLoggedInTime);
+        dest.writeString(lastLoggedInFingerprint);
         dest.writeInt(partial ? 1 : 0);
         dest.writeInt(profileGroupId);
         dest.writeInt(guestToRemove ? 1 : 0);
@@ -257,6 +268,7 @@
         serialNumber = source.readInt();
         creationTime = source.readLong();
         lastLoggedInTime = source.readLong();
+        lastLoggedInFingerprint = source.readString();
         partial = source.readInt() != 0;
         profileGroupId = source.readInt();
         guestToRemove = source.readInt() != 0;
diff --git a/core/java/android/content/pm/VerificationParams.aidl b/core/java/android/content/pm/VerificationParams.aidl
deleted file mode 100644
index 5bb7f6962..0000000
--- a/core/java/android/content/pm/VerificationParams.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-parcelable VerificationParams;
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7b0b98d..4ad86f7 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
+import android.content.res.Configuration.NativeConfig;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 import android.util.SparseArray;
@@ -796,7 +797,10 @@
     /*package*/ static final int STYLE_DATA = 1;
     /*package*/ static final int STYLE_ASSET_COOKIE = 2;
     /*package*/ static final int STYLE_RESOURCE_ID = 3;
-    /*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
+
+    /* Offset within typed data array for native changingConfigurations. */
+    static final int STYLE_CHANGING_CONFIGURATIONS = 4;
+
     /*package*/ static final int STYLE_DENSITY = 5;
     /*package*/ native static final boolean applyStyle(long theme,
             int defStyleAttr, int defStyleRes, long xmlParser,
@@ -845,7 +849,7 @@
                                                                 TypedValue outValue,
                                                                 boolean resolve);
     /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
-    /*package*/ native static final int getThemeChangingConfigurations(long theme);
+    /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
 
     private native final long openXmlAssetNative(int cookie, String fileName);
 
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 9e1b312..fb5bfd3 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -19,6 +19,7 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources.Theme;
 import android.graphics.Color;
 
@@ -82,7 +83,7 @@
     private ColorStateListFactory mFactory;
 
     private int[][] mThemeAttrs;
-    private int mChangingConfigurations;
+    private @Config int mChangingConfigurations;
 
     private int[][] mStateSpecs;
     private int[] mColors;
@@ -251,7 +252,7 @@
         int depth;
         int type;
 
-        int changingConfigurations = 0;
+        @Config int changingConfigurations = 0;
         int defaultColor = DEFAULT_COLOR;
 
         boolean hasUnresolvedAttrs = false;
@@ -440,8 +441,8 @@
      *
      * @see android.content.pm.ActivityInfo
      */
-    public int getChangingConfigurations() {
-        return mChangingConfigurations;
+    public @Config int getChangingConfigurations() {
+        return super.getChangingConfigurations() | mChangingConfigurations;
     }
 
     private int modulateColorAlpha(int baseColor, float alphaMod) {
@@ -620,7 +621,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mSrc.mChangingConfigurations;
         }
 
diff --git a/core/java/android/content/res/ComplexColor.java b/core/java/android/content/res/ComplexColor.java
index d96ec62..58c6fc5 100644
--- a/core/java/android/content/res/ComplexColor.java
+++ b/core/java/android/content/res/ComplexColor.java
@@ -23,8 +23,11 @@
 /**
  * Defines an abstract class for the complex color information, like
  * {@link android.content.res.ColorStateList} or {@link android.content.res.GradientColor}
+ * @hide
  */
 public abstract class ComplexColor {
+    private int mChangingConfigurations;
+
     /**
      * @return {@code true}  if this ComplexColor changes color based on state, {@code false}
      * otherwise.
@@ -52,4 +55,24 @@
      * @hide only for resource preloading
      */
     public abstract ComplexColor obtainForTheme(Theme t);
+
+    /**
+     * @hide only for resource preloading
+     */
+    final void setBaseChangingConfigurations(int changingConfigurations) {
+        mChangingConfigurations = changingConfigurations;
+    }
+
+    /**
+     * Returns a mask of the configuration parameters for which this color
+     * may change, requiring that it be re-created.
+     *
+     * @return a mask of the changing configuration parameters, as defined by
+     *         {@link android.content.pm.ActivityInfo}
+     *
+     * @see android.content.pm.ActivityInfo
+     */
+    public int getChangingConfigurations() {
+        return mChangingConfigurations;
+    }
 }
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index be4f895..9b1d462 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -22,8 +22,11 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.Config;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,6 +35,8 @@
 import android.view.View;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Locale;
 
@@ -663,6 +668,28 @@
      */
     public int seq;
 
+    /** @hide */
+    @IntDef(flag = true,
+            value = {
+                    NATIVE_CONFIG_MCC,
+                    NATIVE_CONFIG_MNC,
+                    NATIVE_CONFIG_LOCALE,
+                    NATIVE_CONFIG_TOUCHSCREEN,
+                    NATIVE_CONFIG_KEYBOARD,
+                    NATIVE_CONFIG_KEYBOARD_HIDDEN,
+                    NATIVE_CONFIG_NAVIGATION,
+                    NATIVE_CONFIG_ORIENTATION,
+                    NATIVE_CONFIG_DENSITY,
+                    NATIVE_CONFIG_SCREEN_SIZE,
+                    NATIVE_CONFIG_VERSION,
+                    NATIVE_CONFIG_SCREEN_LAYOUT,
+                    NATIVE_CONFIG_UI_MODE,
+                    NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
+                    NATIVE_CONFIG_LAYOUTDIR,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NativeConfig {}
+
     /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */
     public static final int NATIVE_CONFIG_MCC = 0x0001;
     /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */
@@ -917,14 +944,13 @@
     }
 
     /**
-     * Copy the fields from delta into this Configuration object, keeping
-     * track of which ones have changed.  Any undefined fields in
-     * <var>delta</var> are ignored and not copied in to the current
-     * Configuration.
-     * @return Returns a bit mask of the changed fields, as per
-     * {@link #diff}.
+     * Copies the fields from delta into this Configuration object, keeping
+     * track of which ones have changed. Any undefined fields in {@code delta}
+     * are ignored and not copied in to the current Configuration.
+     *
+     * @return a bit mask of the changed fields, as per {@link #diff}
      */
-    public int updateFrom(Configuration delta) {
+    public @Config int updateFrom(@NonNull Configuration delta) {
         int changed = 0;
         if (delta.fontScale > 0 && fontScale != delta.fontScale) {
             changed |= ActivityInfo.CONFIG_FONT_SCALE;
@@ -1171,17 +1197,19 @@
     }
 
     /**
-     * Determine if a new resource needs to be loaded from the bit set of
+     * Determines if a new resource needs to be loaded from the bit set of
      * configuration changes returned by {@link #updateFrom(Configuration)}.
      *
-     * @param configChanges The mask of changes configurations as returned by
-     * {@link #updateFrom(Configuration)}.
-     * @param interestingChanges The configuration changes that the resource
-     * can handled, as given in {@link android.util.TypedValue#changingConfigurations}.
-     *
-     * @return Return true if the resource needs to be loaded, else false.
+     * @param configChanges the mask of changes configurations as returned by
+     *                      {@link #updateFrom(Configuration)}
+     * @param interestingChanges the configuration changes that the resource
+     *                           can handle as given in
+     *                           {@link android.util.TypedValue#changingConfigurations}
+     * @return {@code true} if the resource needs to be loaded, {@code false}
+     *         otherwise
      */
-    public static boolean needNewResources(int configChanges, int interestingChanges) {
+    public static boolean needNewResources(@Config int configChanges,
+            @Config int interestingChanges) {
         return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
     }
 
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
index fecda87..70290c4 100644
--- a/core/java/android/content/res/ConfigurationBoundResourceCache.java
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -16,6 +16,8 @@
 
 package android.content.res;
 
+import android.content.pm.ActivityInfo.Config;
+
 /**
  * A Cache class which can be used to cache resource objects that are easy to clone but more
  * expensive to inflate.
@@ -23,36 +25,26 @@
  * @hide For internal use only.
  */
 public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<ConstantState<T>> {
-    private final Resources mResources;
-
-    /**
-     * Creates a cache for the given Resources instance.
-     *
-     * @param resources the resources to use when creating new instances
-     */
-    public ConfigurationBoundResourceCache(Resources resources) {
-        mResources = resources;
-    }
-
     /**
      * If the resource is cached, creates and returns a new instance of it.
      *
      * @param key a key that uniquely identifies the drawable resource
+     * @param resources a Resources object from which to create new instances.
      * @param theme the theme where the resource will be used
      * @return a new instance of the resource, or {@code null} if not in
      *         the cache
      */
-    public T getInstance(long key, Resources.Theme theme) {
+    public T getInstance(long key, Resources resources, Resources.Theme theme) {
         final ConstantState<T> entry = get(key, theme);
         if (entry != null) {
-            return entry.newInstance(mResources, theme);
+            return entry.newInstance(resources, theme);
         }
 
         return null;
     }
 
     @Override
-    public boolean shouldInvalidateEntry(ConstantState<T> entry, int configChanges) {
+    public boolean shouldInvalidateEntry(ConstantState<T> entry, @Config int configChanges) {
         return Configuration.needNewResources(configChanges, entry.getChangingConfigurations());
     }
 }
diff --git a/core/java/android/content/res/ConstantState.java b/core/java/android/content/res/ConstantState.java
index ee609df..09d4a59 100644
--- a/core/java/android/content/res/ConstantState.java
+++ b/core/java/android/content/res/ConstantState.java
@@ -15,6 +15,8 @@
 */
 package android.content.res;
 
+import android.content.pm.ActivityInfo.Config;
+
 /**
  * A cache class that can provide new instances of a particular resource which may change
  * depending on the current {@link Resources.Theme} or {@link Configuration}.
@@ -33,7 +35,7 @@
      * Return a bit mask of configuration changes that will impact
      * this resource (and thus require completely reloading it).
      */
-    abstract public int getChangingConfigurations();
+    abstract public @Config int getChangingConfigurations();
 
     /**
      * Create a new instance without supplying resources the caller
diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java
index ba00134..7b27fac 100644
--- a/core/java/android/content/res/DrawableCache.java
+++ b/core/java/android/content/res/DrawableCache.java
@@ -22,29 +22,19 @@
  * Class which can be used to cache Drawable resources against a theme.
  */
 class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> {
-    private final Resources mResources;
-
-    /**
-     * Creates a cache for the given Resources instance.
-     *
-     * @param resources the resources to use when creating new instances
-     */
-    public DrawableCache(Resources resources) {
-        mResources = resources;
-    }
-
     /**
      * If the resource is cached, creates and returns a new instance of it.
      *
      * @param key a key that uniquely identifies the drawable resource
+     * @param resources a Resources object from which to create new instances.
      * @param theme the theme where the resource will be used
      * @return a new instance of the resource, or {@code null} if not in
      *         the cache
      */
-    public Drawable getInstance(long key, Resources.Theme theme) {
+    public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
         final Drawable.ConstantState entry = get(key, theme);
         if (entry != null) {
-            return entry.newDrawable(mResources, theme);
+            return entry.newDrawable(resources, theme);
         }
 
         return null;
diff --git a/core/java/android/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
index 98ef2ea..c49c4b2 100644
--- a/core/java/android/content/res/GradientColor.java
+++ b/core/java/android/content/res/GradientColor.java
@@ -17,8 +17,10 @@
 package android.content.res;
 
 import android.annotation.ColorInt;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources.Theme;
 
 import com.android.internal.R;
@@ -37,24 +39,61 @@
 import android.util.Xml;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
-
+/**
+ * Lets you define a gradient color, which is used inside
+ * {@link android.graphics.drawable.VectorDrawable}.
+ *
+ * {@link android.content.res.GradientColor}s are created from XML resource files defined in the
+ * "color" subdirectory directory of an application's resource directory.  The XML file contains
+ * a single "gradient" element with a number of attributes and elements inside.  For example:
+ * <pre>
+ * &lt;gradient xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+ *   &lt;android:startColor="?android:attr/colorPrimary"/&gt;
+ *   &lt;android:endColor="?android:attr/colorControlActivated"/&gt;
+ *   &lt;.../&gt;
+ *   &lt;android:type="linear"/&gt;
+ * &lt;/gradient&gt;
+ * </pre>
+ *
+ * This can describe either a {@link android.graphics.LinearGradient},
+ * {@link android.graphics.RadialGradient}, or {@link android.graphics.SweepGradient}.
+ *
+ * Note that different attributes are relevant for different types of gradient.
+ * For example, android:gradientRadius is only applied to RadialGradient.
+ * androd:centerX and android:centerY are only applied to SweepGradient or RadialGradient.
+ * android:startX, android:startY, android:endX and android:endY are only applied to LinearGradient.
+ *
+ * Also note if any color "item" element is defined, then startColor, centerColor and endColor will
+ * be ignored.
+ * @hide
+ */
 public class GradientColor extends ComplexColor {
     private static final String TAG = "GradientColor";
 
     private static final boolean DBG_GRADIENT = false;
 
+    @IntDef({TILE_MODE_CLAMP, TILE_MODE_REPEAT, TILE_MODE_MIRROR})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface GradientTileMode {}
+    private static final int TILE_MODE_CLAMP = 0;
+    private static final int TILE_MODE_REPEAT = 1;
+    private static final int TILE_MODE_MIRROR = 2;
+
     /** Lazily-created factory for this GradientColor. */
     private GradientColorFactory mFactory;
 
-    private int mChangingConfigurations;
+    private @Config int mChangingConfigurations;
     private int mDefaultColor;
 
     // After parsing all the attributes from XML, this shader is the ultimate result containing
     // all the XML information.
     private Shader mShader = null;
 
-    // Below are the attributes at the root element <gradient>
+    // Below are the attributes at the root element <gradient>.
+    // NOTE: they need to be copied in the copy constructor!
     private int mGradientType = GradientDrawable.LINEAR_GRADIENT;
 
     private float mCenterX = 0f;
@@ -70,6 +109,8 @@
     private int mEndColor = 0;
     private boolean mHasCenterColor = false;
 
+    private int mTileMode = 0; // Clamp mode.
+
     private float mGradientRadius = 0f;
 
     // Below are the attributes for the <item> element.
@@ -100,6 +141,7 @@
             mEndColor = copy.mEndColor;
             mHasCenterColor = copy.mHasCenterColor;
             mGradientRadius = copy.mGradientRadius;
+            mTileMode = copy.mTileMode;
 
             if (copy.mItemColors != null) {
                 mItemColors = copy.mItemColors.clone();
@@ -117,6 +159,20 @@
         }
     }
 
+    // Set the default to clamp mode.
+    private static Shader.TileMode parseTileMode(@GradientTileMode int tileMode) {
+        switch (tileMode) {
+            case TILE_MODE_CLAMP:
+                return Shader.TileMode.CLAMP;
+            case TILE_MODE_REPEAT:
+                return Shader.TileMode.REPEAT;
+            case TILE_MODE_MIRROR:
+                return Shader.TileMode.MIRROR;
+            default:
+                return Shader.TileMode.CLAMP;
+        }
+    }
+
     /**
      * Update the root level's attributes, either for inflate or applyTheme.
      */
@@ -150,6 +206,9 @@
         mEndColor = a.getColor(
                 R.styleable.GradientColor_endColor, mEndColor);
 
+        mTileMode = a.getInt(
+                R.styleable.GradientColor_tileMode, mTileMode);
+
         if (DBG_GRADIENT) {
             Log.v(TAG, "hasCenterColor is " + mHasCenterColor);
             if (mHasCenterColor) {
@@ -157,6 +216,7 @@
             }
             Log.v(TAG, "startColor: " + mStartColor);
             Log.v(TAG, "endColor: " + mEndColor);
+            Log.v(TAG, "tileMode: " + mTileMode);
         }
 
         mGradientRadius = a.getFloat(R.styleable.GradientColor_gradientRadius,
@@ -406,11 +466,11 @@
 
         if (mGradientType == GradientDrawable.LINEAR_GRADIENT) {
             mShader = new LinearGradient(mStartX, mStartY, mEndX, mEndY, tempColors, tempOffsets,
-                    Shader.TileMode.CLAMP);
+                    parseTileMode(mTileMode));
         } else {
             if (mGradientType == GradientDrawable.RADIAL_GRADIENT) {
                 mShader = new RadialGradient(mCenterX, mCenterY, mGradientRadius, tempColors,
-                        tempOffsets, Shader.TileMode.CLAMP);
+                        tempOffsets, parseTileMode(mTileMode));
             } else {
                 mShader = new SweepGradient(mCenterX, mCenterY, tempColors, tempOffsets);
             }
@@ -448,7 +508,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mSrc.mChangingConfigurations;
         }
 
@@ -483,6 +543,19 @@
         return clone;
     }
 
+    /**
+     * Returns a mask of the configuration parameters for which this gradient
+     * may change, requiring that it be re-created.
+     *
+     * @return a mask of the changing configuration parameters, as defined by
+     *         {@link android.content.pm.ActivityInfo}
+     *
+     * @see android.content.pm.ActivityInfo
+     */
+    public int getChangingConfigurations() {
+        return super.getChangingConfigurations() | mChangingConfigurations;
+    }
+
     private void applyTheme(Theme t) {
         if (mThemeAttrs != null) {
             applyRootAttrsTheme(t);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 915fae0..93fe73b 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -40,26 +40,21 @@
 import android.annotation.XmlRes;
 import android.content.pm.ActivityInfo;
 import android.graphics.Movie;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.DrawableInflater;
-import android.icu.text.PluralRules;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.LocaleList;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Pools.SynchronizedPool;
-import android.util.Slog;
 import android.util.TypedValue;
-import android.util.Xml;
 import android.view.ViewDebug;
 import android.view.ViewHierarchyEncoder;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.GrowingArrayUtils;
 import com.android.internal.util.XmlUtils;
 
@@ -68,7 +63,8 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Locale;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * Class for accessing an application's resources.  This sits on top of the
@@ -98,48 +94,15 @@
 public class Resources {
     static final String TAG = "Resources";
 
-    private static final boolean DEBUG_LOAD = false;
-    private static final boolean DEBUG_CONFIG = false;
-    private static final boolean TRACE_FOR_PRELOAD = false;
-    private static final boolean TRACE_FOR_MISS_PRELOAD = false;
-
-    private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
-            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
-
-    private static final int ID_OTHER = 0x01000004;
-
     private static final Object sSync = new Object();
 
-    // Information about preloaded resources.  Note that they are not
-    // protected by a lock, because while preloading in zygote we are all
-    // single-threaded, and after that these are immutable.
-    private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
-    private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
-            = new LongSparseArray<>();
-    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
-            sPreloadedComplexColors = new LongSparseArray<>();
-
-    // Pool of TypedArrays targeted to this Resources object.
-    final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
-
     // Used by BridgeResources in layoutlib
     static Resources mSystem = null;
 
-    private static boolean sPreloaded;
+    private ResourcesImpl mResourcesImpl;
 
-    /** Lock object used to protect access to caches and configuration. */
-    private final Object mAccessLock = new Object();
-
-    // These are protected by mAccessLock.
-    private final Configuration mTmpConfig = new Configuration();
-    private final DrawableCache mDrawableCache = new DrawableCache(this);
-    private final DrawableCache mColorDrawableCache = new DrawableCache(this);
-    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
-            new ConfigurationBoundResourceCache<>(this);
-    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
-            new ConfigurationBoundResourceCache<>(this);
-    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
-            new ConfigurationBoundResourceCache<>(this);
+    // Pool of TypedArrays targeted to this Resources object.
+    final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
 
     /** Used to inflate drawable objects from XML. */
     private DrawableInflater mDrawableInflater;
@@ -150,28 +113,14 @@
     /** Single-item pool used to minimize TypedValue allocations. */
     private TypedValue mTmpValue = new TypedValue();
 
-    private boolean mPreloading;
-
-    // Cyclical cache used for recently-accessed XML files.
-    private int mLastCachedXmlBlockIndex = -1;
-    private final String[] mCachedXmlBlockFiles = new String[4];
-    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
-
-    final AssetManager mAssets;
     final ClassLoader mClassLoader;
-    final DisplayMetrics mMetrics = new DisplayMetrics();
 
-    private final Configuration mConfiguration = new Configuration();
-
-    private PluralRules mPluralRule;
-
-    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-
-    static {
-        sPreloadedDrawables = new LongSparseArray[2];
-        sPreloadedDrawables[0] = new LongSparseArray<>();
-        sPreloadedDrawables[1] = new LongSparseArray<>();
-    }
+    /**
+     * WeakReferences to Themes that were constructed from this Resources object.
+     * We keep track of these in case our underlying implementation is changed, in which case
+     * the Themes must also get updated ThemeImpls.
+     */
+    private final ArrayList<WeakReference<Theme>> mThemeRefs = new ArrayList<>();
 
     /**
      * Returns the most appropriate default theme for the specified target SDK version.
@@ -214,32 +163,20 @@
     }
 
     /**
-     * @return the inflater used to create drawable objects
-     * @hide Pending API finalization.
+     * Return a global shared Resources object that provides access to only
+     * system resources (no application resources), and is not configured for
+     * the current screen (can not use dimension units, does not change based
+     * on orientation, etc).
      */
-    public final DrawableInflater getDrawableInflater() {
-        if (mDrawableInflater == null) {
-            mDrawableInflater = new DrawableInflater(this, mClassLoader);
+    public static Resources getSystem() {
+        synchronized (sSync) {
+            Resources ret = mSystem;
+            if (ret == null) {
+                ret = new Resources();
+                mSystem = ret;
+            }
+            return ret;
         }
-        return mDrawableInflater;
-    }
-
-    /**
-     * Used by AnimatorInflater.
-     *
-     * @hide
-     */
-    public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
-        return mAnimatorCache;
-    }
-
-    /**
-     * Used by AnimatorInflater.
-     *
-     * @hide
-     */
-    public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
-        return mStateListAnimatorCache;
     }
 
     /**
@@ -270,51 +207,105 @@
      *               selecting/computing resource values (optional).
      */
     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
-        this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        this(null);
+        mResourcesImpl = new ResourcesImpl(assets, metrics, config,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
     }
 
     /**
      * Creates a new Resources object with CompatibilityInfo.
      *
-     * @param assets Previously created AssetManager.
-     * @param metrics Current display metrics to consider when
-     *                selecting/computing resource values.
-     * @param config Desired device configuration to consider when
-     *               selecting/computing resource values (optional).
-     * @param compatInfo this resource's compatibility info. Must not be null.
      * @param classLoader class loader for the package used to load custom
      *                    resource classes, may be {@code null} to use system
      *                    class loader
      * @hide
      */
-    public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
-            CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) {
-        mAssets = assets;
+    public Resources(@Nullable ClassLoader classLoader) {
         mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
-        mMetrics.setToDefaults();
-        if (compatInfo != null) {
-            mCompatibilityInfo = compatInfo;
-        }
-        updateConfiguration(config, metrics);
-        assets.ensureStringBlocks();
     }
 
     /**
-     * Return a global shared Resources object that provides access to only
-     * system resources (no application resources), and is not configured for
-     * the current screen (can not use dimension units, does not change based
-     * on orientation, etc).
+     * Only for creating the System resources.
      */
-    public static Resources getSystem() {
-        synchronized (sSync) {
-            Resources ret = mSystem;
-            if (ret == null) {
-                ret = new Resources();
-                mSystem = ret;
-            }
+    private Resources() {
+        this(null);
 
-            return ret;
+        final DisplayMetrics metrics = new DisplayMetrics();
+        metrics.setToDefaults();
+
+        final Configuration config = new Configuration();
+        config.setToDefaults();
+
+        mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
+    }
+
+    /**
+     * Set the underlying implementation (containing all the resources and caches)
+     * and updates all Theme references to new implementations as well.
+     * @hide
+     */
+    public void setImpl(ResourcesImpl impl) {
+        if (impl == mResourcesImpl) {
+            return;
         }
+
+        mResourcesImpl = impl;
+
+        // Create new ThemeImpls that are identical to the ones we have.
+        synchronized (mThemeRefs) {
+            final int count = mThemeRefs.size();
+            for (int i = 0; i < count; i++) {
+                WeakReference<Theme> weakThemeRef = mThemeRefs.get(i);
+                Theme theme = weakThemeRef != null ? weakThemeRef.get() : null;
+                if (theme != null) {
+                    theme.setImpl(mResourcesImpl.newThemeImpl(theme.getKey()));
+                }
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public ResourcesImpl getImpl() {
+        return mResourcesImpl;
+    }
+
+    /**
+     * @hide
+     */
+    public ClassLoader getClassLoader() {
+        return mClassLoader;
+    }
+
+    /**
+     * @return the inflater used to create drawable objects
+     * @hide Pending API finalization.
+     */
+    public final DrawableInflater getDrawableInflater() {
+        if (mDrawableInflater == null) {
+            mDrawableInflater = new DrawableInflater(this, mClassLoader);
+        }
+        return mDrawableInflater;
+    }
+
+    /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+        return mResourcesImpl.getAnimatorCache();
+    }
+
+    /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+        return mResourcesImpl.getStateListAnimatorCache();
     }
 
     /**
@@ -332,8 +323,8 @@
      * @return CharSequence The string data associated with the resource, plus
      *         possibly styled text information.
      */
-    public CharSequence getText(@StringRes int id) throws NotFoundException {
-        CharSequence res = mAssets.getResourceText(id);
+    @NonNull public CharSequence getText(@StringRes int id) throws NotFoundException {
+        CharSequence res = mResourcesImpl.getAssets().getResourceText(id);
         if (res != null) {
             return res;
         }
@@ -361,41 +352,10 @@
      * @return CharSequence The string data associated with the resource, plus
      *         possibly styled text information.
      */
+    @NonNull
     public CharSequence getQuantityText(@PluralsRes int id, int quantity)
             throws NotFoundException {
-        PluralRules rule = getPluralRule();
-        CharSequence res = mAssets.getResourceBagText(id,
-                attrForQuantityCode(rule.select(quantity)));
-        if (res != null) {
-            return res;
-        }
-        res = mAssets.getResourceBagText(id, ID_OTHER);
-        if (res != null) {
-            return res;
-        }
-        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
-                + " quantity=" + quantity
-                + " item=" + rule.select(quantity));
-    }
-
-    private PluralRules getPluralRule() {
-        synchronized (sSync) {
-            if (mPluralRule == null) {
-                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
-            }
-            return mPluralRule;
-        }
-    }
-
-    private static int attrForQuantityCode(String quantityCode) {
-        switch (quantityCode) {
-            case PluralRules.KEYWORD_ZERO: return 0x01000005;
-            case PluralRules.KEYWORD_ONE:  return 0x01000006;
-            case PluralRules.KEYWORD_TWO:  return 0x01000007;
-            case PluralRules.KEYWORD_FEW:  return 0x01000008;
-            case PluralRules.KEYWORD_MANY: return 0x01000009;
-            default:                     return ID_OTHER;
-        }
+        return mResourcesImpl.getQuantityText(id, quantity);
     }
 
     /**
@@ -414,12 +374,7 @@
      */
     @NonNull
     public String getString(@StringRes int id) throws NotFoundException {
-        final CharSequence res = getText(id);
-        if (res != null) {
-            return res.toString();
-        }
-        throw new NotFoundException("String resource ID #0x"
-                                    + Integer.toHexString(id));
+        return getText(id).toString();
     }
 
 
@@ -444,7 +399,8 @@
     @NonNull
     public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
         final String raw = getString(id);
-        return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
+        return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
+                formatArgs);
     }
 
     /**
@@ -472,10 +428,12 @@
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
+    @NonNull
     public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
             throws NotFoundException {
         String raw = getQuantityText(id, quantity).toString();
-        return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
+        return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
+                formatArgs);
     }
 
     /**
@@ -498,8 +456,8 @@
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
-    public String getQuantityString(@PluralsRes int id, int quantity)
-            throws NotFoundException {
+    @NonNull
+    public String getQuantityString(@PluralsRes int id, int quantity) throws NotFoundException {
         return getQuantityText(id, quantity).toString();
     }
 
@@ -518,7 +476,7 @@
      *         possibly styled text information, or def if id is 0 or not found.
      */
     public CharSequence getText(@StringRes int id, CharSequence def) {
-        CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
+        CharSequence res = id != 0 ? mResourcesImpl.getAssets().getResourceText(id) : null;
         return res != null ? res : def;
     }
 
@@ -533,13 +491,13 @@
      *
      * @return The styled text array associated with the resource.
      */
+    @NonNull
     public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException {
-        CharSequence[] res = mAssets.getResourceTextArray(id);
+        CharSequence[] res = mResourcesImpl.getAssets().getResourceTextArray(id);
         if (res != null) {
             return res;
         }
-        throw new NotFoundException("Text array resource ID #0x"
-                                    + Integer.toHexString(id));
+        throw new NotFoundException("Text array resource ID #0x" + Integer.toHexString(id));
     }
 
     /**
@@ -553,14 +511,14 @@
      *
      * @return The string array associated with the resource.
      */
+    @NonNull
     public String[] getStringArray(@ArrayRes int id)
             throws NotFoundException {
-        String[] res = mAssets.getResourceStringArray(id);
+        String[] res = mResourcesImpl.getAssets().getResourceStringArray(id);
         if (res != null) {
             return res;
         }
-        throw new NotFoundException("String array resource ID #0x"
-                                    + Integer.toHexString(id));
+        throw new NotFoundException("String array resource ID #0x" + Integer.toHexString(id));
     }
 
     /**
@@ -574,13 +532,13 @@
      *
      * @return The int array associated with the resource.
      */
+    @NonNull
     public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
-        int[] res = mAssets.getArrayIntResource(id);
+        int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
         if (res != null) {
             return res;
         }
-        throw new NotFoundException("Int array resource ID #0x"
-                                    + Integer.toHexString(id));
+        throw new NotFoundException("Int array resource ID #0x" + Integer.toHexString(id));
     }
 
     /**
@@ -596,16 +554,16 @@
      * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
      * when done with it.
      */
-    public TypedArray obtainTypedArray(@ArrayRes int id)
-            throws NotFoundException {
-        int len = mAssets.getArraySize(id);
+    @NonNull
+    public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
+        final ResourcesImpl impl = mResourcesImpl;
+        int len = impl.getAssets().getArraySize(id);
         if (len < 0) {
-            throw new NotFoundException("Array resource ID #0x"
-                                        + Integer.toHexString(id));
+            throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
         }
         
         TypedArray array = TypedArray.obtain(this, len);
-        array.mLength = mAssets.retrieveArray(id, array.mData);
+        array.mLength = impl.getAssets().retrieveArray(id, array.mData);
         array.mIndices[0] = 0;
         
         return array;
@@ -629,10 +587,12 @@
      * @see #getDimensionPixelSize
      */
     public float getDimension(@DimenRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_DIMENSION) {
-                return TypedValue.complexToDimension(value.data, mMetrics);
+                return TypedValue.complexToDimension(value.data, impl.getDisplayMetrics());
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -661,10 +621,13 @@
      * @see #getDimensionPixelSize
      */
     public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_DIMENSION) {
-                return TypedValue.complexToDimensionPixelOffset(value.data, mMetrics);
+                return TypedValue.complexToDimensionPixelOffset(value.data,
+                        impl.getDisplayMetrics());
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -694,10 +657,12 @@
      * @see #getDimensionPixelOffset
      */
     public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_DIMENSION) {
-                return TypedValue.complexToDimensionPixelSize(value.data, mMetrics);
+                return TypedValue.complexToDimensionPixelSize(value.data, impl.getDisplayMetrics());
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -724,8 +689,9 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      */
     public float getFraction(@FractionRes int id, int base, int pbase) {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_FRACTION) {
                 return TypedValue.complexToFraction(value.data, base, pbase);
             }
@@ -748,12 +714,11 @@
      * the resource ID passed here is an alias to another Drawable resource.
      * This means that if the density configuration of the alias resource
      * is different than the actual resource, the density of the returned
-     * Drawable would be incorrect, resulting in bad scaling.  To work
-     * around this, you can instead retrieve the Drawable through
-     * {@link TypedArray#getDrawable TypedArray.getDrawable}.  Use
-     * {@link android.content.Context#obtainStyledAttributes(int[])
-     * Context.obtainStyledAttributes} with
-     * an array containing the resource ID of interest to create the TypedArray.</p>
+     * Drawable would be incorrect, resulting in bad scaling. To work
+     * around this, you can instead manually resolve the aliased reference
+     * by using {@link #getValue(int, TypedValue, boolean)} and passing
+     * {@code true} for {@code resolveRefs}. The resulting
+     * {@link TypedValue#resourceId} value may be passed to this method.</p>
      *
      * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
      * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
@@ -769,7 +734,6 @@
      * @deprecated Use {@link #getDrawable(int, Theme)} instead.
      */
     @Deprecated
-    @Nullable
     public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
         final Drawable d = getDrawable(id, null);
         if (d != null && d.canApplyTheme()) {
@@ -794,12 +758,13 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *         not exist.
      */
-    @Nullable
     public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            return loadDrawable(value, id, theme);
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
+            return impl.loadDrawable(this, value, id, theme, true);
         } finally {
             releaseTempTypedValue(value);
         }
@@ -832,7 +797,6 @@
      * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
      */
     @Deprecated
-    @Nullable
     public Drawable getDrawableForDensity(@DrawableRes int id, int density)
             throws NotFoundException {
         return getDrawableForDensity(id, density, null);
@@ -852,16 +816,17 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *             not exist.
      */
-    @Nullable
     public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            getValueForDensity(id, density, value, true);
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValueForDensity(id, density, value, true);
 
             // If the drawable's XML lives in our current density qualifier,
             // it's okay to use a scaled version from the cache. Otherwise, we
             // need to actually load the drawable from XML.
-            final boolean useCache = value.density == mMetrics.densityDpi;
+            final DisplayMetrics metrics = impl.getDisplayMetrics();
+            final boolean useCache = value.density == metrics.densityDpi;
 
             /*
              * Pretend the requested density is actually the display density. If
@@ -872,18 +837,23 @@
              */
             if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
                 if (value.density == density) {
-                    value.density = mMetrics.densityDpi;
+                    value.density = metrics.densityDpi;
                 } else {
-                    value.density = (value.density * mMetrics.densityDpi) / density;
+                    value.density = (value.density * metrics.densityDpi) / density;
                 }
             }
-
-            return loadDrawable(value, id, theme, useCache);
+            return impl.loadDrawable(this, value, id, theme, useCache);
         } finally {
             releaseTempTypedValue(value);
         }
     }
 
+    @NonNull
+    Drawable loadDrawable(@NonNull TypedValue value, int id, @Nullable Theme theme)
+            throws NotFoundException {
+        return mResourcesImpl.loadDrawable(this, value, id, theme, true);
+    }
+
     /**
      * Return a movie object associated with the particular resource ID.
      * @param id The desired resource identifier, as generated by the aapt
@@ -893,13 +863,12 @@
      * 
      */
     public Movie getMovie(@RawRes int id) throws NotFoundException {
-        InputStream is = openRawResource(id);
-        Movie movie = Movie.decodeStream(is);
+        final InputStream is = openRawResource(id);
+        final Movie movie = Movie.decodeStream(is);
         try {
             is.close();
-        }
-        catch (java.io.IOException e) {
-            // don't care, since the return value is valid
+        } catch (IOException e) {
+            // No one cares.
         }
         return movie;
     }
@@ -943,8 +912,10 @@
      */
     @ColorInt
     public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type >= TypedValue.TYPE_FIRST_INT
                     && value.type <= TypedValue.TYPE_LAST_INT) {
                 return value.data;
@@ -953,7 +924,7 @@
                         + " type #0x" + Integer.toHexString(value.type) + " is not valid");
             }
 
-            final ColorStateList csl = loadColorStateList(value, id, theme);
+            final ColorStateList csl = impl.loadColorStateList(this, value, id, theme);
             return csl.getDefaultColor();
         } finally {
             releaseTempTypedValue(value);
@@ -1011,14 +982,30 @@
     @Nullable
     public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            return loadColorStateList(value, id, theme);
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
+            return impl.loadColorStateList(this, value, id, theme);
         } finally {
             releaseTempTypedValue(value);
         }
     }
 
+    @Nullable
+    ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme)
+            throws NotFoundException {
+        return mResourcesImpl.loadColorStateList(this, value, id, theme);
+    }
+
+    /**
+     * @hide
+     */
+    @Nullable
+    public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
+        return mResourcesImpl.loadComplexColor(this, value, id, theme);
+    }
+
     /**
      * Return a boolean associated with a particular resource ID.  This can be
      * used with any integral resource value, and will return true if it is
@@ -1033,8 +1020,9 @@
      * @return Returns the boolean value contained in the resource.
      */
     public boolean getBoolean(@BoolRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type >= TypedValue.TYPE_FIRST_INT
                     && value.type <= TypedValue.TYPE_LAST_INT) {
                 return value.data != 0;
@@ -1058,8 +1046,9 @@
      * @return Returns the integer value contained in the resource.
      */
     public int getInteger(@IntegerRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type >= TypedValue.TYPE_FIRST_INT
                     && value.type <= TypedValue.TYPE_LAST_INT) {
                 return value.data;
@@ -1085,8 +1074,9 @@
      * @hide Pending API council approval.
      */
     public float getFloat(int id) {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_FLOAT) {
                 return value.getFloat();
             }
@@ -1194,20 +1184,6 @@
     }
 
     /**
-     * Returns a TypedValue populated with data for the specified resource ID
-     * that's suitable for temporary use. The obtained TypedValue should be
-     * released using {@link #releaseTempTypedValue(TypedValue)}.
-     *
-     * @param id the resource ID for which data should be obtained
-     * @return a populated typed value suitable for temporary use
-     */
-    private TypedValue obtainTempTypedValue(@AnyRes int id) {
-        final TypedValue value = obtainTempTypedValue();
-        getValue(id, value, true);
-        return value;
-    }
-
-    /**
      * Returns a TypedValue suitable for temporary use. The obtained TypedValue
      * should be released using {@link #releaseTempTypedValue(TypedValue)}.
      *
@@ -1256,17 +1232,7 @@
      */
     public InputStream openRawResource(@RawRes int id, TypedValue value)
             throws NotFoundException {
-        getValue(id, value, true);
-
-        try {
-            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
-                    AssetManager.ACCESS_STREAMING);
-        } catch (Exception e) {
-            NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
-                    " from drawable resource ID #0x" + Integer.toHexString(id));
-            rnf.initCause(e);
-            throw rnf;
-        }
+        return mResourcesImpl.openRawResource(id, value);
     }
 
     /**
@@ -1292,12 +1258,9 @@
      */
     public AssetFileDescriptor openRawResourceFd(@RawRes int id)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            return mAssets.openNonAssetFd(value.assetCookie, value.string.toString());
-        } catch (Exception e) {
-            throw new NotFoundException("File " + value.string.toString() + " from drawable "
-                    + "resource ID #0x" + Integer.toHexString(id), e);
+            return mResourcesImpl.openRawResourceFd(id, value);
         } finally {
             releaseTempTypedValue(value);
         }
@@ -1320,12 +1283,7 @@
      */
     public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
-        if (found) {
-            return;
-        }
-        throw new NotFoundException("Resource ID #0x"
-                                    + Integer.toHexString(id));
+        mResourcesImpl.getValue(id, outValue, resolveRefs);
     }
 
     /**
@@ -1343,11 +1301,7 @@
      */
     public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
             boolean resolveRefs) throws NotFoundException {
-        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
-        if (found) {
-            return;
-        }
-        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+        mResourcesImpl.getValueForDensity(id, density, outValue, resolveRefs);
     }
 
     /**
@@ -1372,12 +1326,7 @@
      */
     public void getValue(String name, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        int id = getIdentifier(name, "string", null);
-        if (id != 0) {
-            getValue(id, outValue, resolveRefs);
-            return;
-        }
-        throw new NotFoundException("String resource name " + name);
+        mResourcesImpl.getValue(name, outValue, resolveRefs);
     }
 
     /**
@@ -1396,6 +1345,15 @@
      * retrieve XML attributes with style and theme information applied.
      */
     public final class Theme {
+        private ResourcesImpl.ThemeImpl mThemeImpl;
+
+        private Theme() {
+        }
+
+        void setImpl(ResourcesImpl.ThemeImpl impl) {
+            mThemeImpl = impl;
+        }
+
         /**
          * Place new attribute values into the theme.  The style resource
          * specified by <var>resid</var> will be retrieved from this Theme's
@@ -1414,12 +1372,7 @@
          *              if not already defined in the theme.
          */
         public void applyStyle(int resId, boolean force) {
-            synchronized (mKey) {
-                AssetManager.applyThemeStyle(mTheme, resId, force);
-
-                mThemeResId = resId;
-                mKey.append(resId, force);
-            }
+            mThemeImpl.applyStyle(resId, force);
         }
 
         /**
@@ -1432,14 +1385,7 @@
          * @param other The existing Theme to copy from.
          */
         public void setTo(Theme other) {
-            synchronized (mKey) {
-                synchronized (other.mKey) {
-                    AssetManager.copyTheme(mTheme, other.mTheme);
-
-                    mThemeResId = other.mThemeResId;
-                    mKey.setTo(other.getKey());
-                }
-            }
+            mThemeImpl.setTo(other.mThemeImpl);
         }
 
         /**
@@ -1462,13 +1408,7 @@
          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
          */
         public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-                array.mTheme = this;
-                AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
-                return array;
-            }
+            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
         }
 
         /**
@@ -1493,13 +1433,7 @@
          */
         public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
                 throws NotFoundException {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-                array.mTheme = this;
-                AssetManager.applyStyle(mTheme, 0, resId, 0, attrs, array.mData, array.mIndices);
-                return array;
-            }
+            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
         }
 
         /**
@@ -1552,23 +1486,7 @@
          */
         public TypedArray obtainStyledAttributes(AttributeSet set,
                 @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-
-                // XXX note that for now we only work with compiled XML files.
-                // To support generic XML files we will need to manually parse
-                // out the attributes from the XML file (applying type information
-                // contained in the resources and such).
-                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
-                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
-                        parser != null ? parser.mParseState : 0,
-                        attrs, array.mData, array.mIndices);
-                array.mTheme = this;
-                array.mXml = parser;
-
-                return array;
-            }
+            return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
         }
 
         /**
@@ -1587,20 +1505,7 @@
          */
         @NonNull
         public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                if (values == null || len != values.length) {
-                    throw new IllegalArgumentException(
-                            "Base attribute values must the same length as attrs");
-                }
-
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
-                array.mTheme = this;
-                array.mXml = null;
-
-                return array;
-            }
+            return mThemeImpl.resolveAttributes(this, values, attrs);
         }
 
         /**
@@ -1621,9 +1526,7 @@
          *         <var>outValue</var> is valid, else false.
          */
         public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
-            synchronized (mKey) {
-                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
-            }
+            return mThemeImpl.resolveAttribute(resid, outValue, resolveRefs);
         }
 
         /**
@@ -1633,7 +1536,7 @@
          * @hide
          */
         public int[] getAllAttributes() {
-            return mAssets.getStyleAttributes(getAppliedStyleResId());
+            return mThemeImpl.getAllAttributes();
         }
 
         /**
@@ -1669,11 +1572,7 @@
          * @see ActivityInfo
          */
         public int getChangingConfigurations() {
-            synchronized (mKey) {
-                final int nativeChangingConfig =
-                        AssetManager.getThemeChangingConfigurations(mTheme);
-                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
-            }
+            return mThemeImpl.getChangingConfigurations();
         }
 
         /**
@@ -1684,43 +1583,23 @@
          * @param prefix Text to prefix each line printed.
          */
         public void dump(int priority, String tag, String prefix) {
-            synchronized (mKey) {
-                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
-            }
+            mThemeImpl.dump(priority, tag, prefix);
         }
 
-        @Override
-        protected void finalize() throws Throwable {
-            super.finalize();
-            mAssets.releaseTheme(mTheme);
-        }
-
-        /*package*/ Theme() {
-            mAssets = Resources.this.mAssets;
-            mTheme = mAssets.createTheme();
-        }
-
-        /** Unique key for the series of styles applied to this theme. */
-        private final ThemeKey mKey = new ThemeKey();
-
-        @SuppressWarnings("hiding")
-        private final AssetManager mAssets;
-        private final long mTheme;
-
-        /** Resource identifier for the theme. */
-        private int mThemeResId = 0;
-
         // Needed by layoutlib.
         /*package*/ long getNativeTheme() {
-            return mTheme;
+            return mThemeImpl.getNativeTheme();
         }
 
         /*package*/ int getAppliedStyleResId() {
-            return mThemeResId;
+            return mThemeImpl.getAppliedStyleResId();
         }
 
-        /*package*/ ThemeKey getKey() {
-            return mKey;
+        /**
+         * @hide
+         */
+        public ThemeKey getKey() {
+            return mThemeImpl.getKey();
         }
 
         private String getResourceNameFromHexString(String hexString) {
@@ -1728,7 +1607,7 @@
         }
 
         /**
-         * Parses {@link #mKey} and returns a String array that holds pairs of
+         * Parses {@link #getKey()} and returns a String array that holds pairs of
          * adjacent Theme data: resource name followed by whether or not it was
          * forced, as specified by {@link #applyStyle(int, boolean)}.
          *
@@ -1736,21 +1615,7 @@
          */
         @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
         public String[] getTheme() {
-            synchronized (mKey) {
-                final int N = mKey.mCount;
-                final String[] themes = new String[N * 2];
-                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
-                    final int resId = mKey.mResId[j];
-                    final boolean forced = mKey.mForce[j];
-                    try {
-                        themes[i] = getResourceName(resId);
-                    } catch (NotFoundException e) {
-                        themes[i] = Integer.toHexString(i);
-                    }
-                    themes[i + 1] = forced ? "forced" : "not forced";
-                }
-                return themes;
-            }
+            return mThemeImpl.getTheme();
         }
 
         /** @hide */
@@ -1771,16 +1636,7 @@
          * @hide
          */
         public void rebase() {
-            synchronized (mKey) {
-                AssetManager.clearTheme(mTheme);
-
-                // Reapply the same styles in the same order.
-                for (int i = 0; i < mKey.mCount; i++) {
-                    final int resId = mKey.mResId[i];
-                    final boolean force = mKey.mForce[i];
-                    AssetManager.applyThemeStyle(mTheme, resId, force);
-                }
-            }
+            mThemeImpl.rebase();
         }
     }
 
@@ -1869,7 +1725,10 @@
      * @return Theme The newly created Theme container.
      */
     public final Theme newTheme() {
-        return new Theme();
+        Theme theme = new Theme();
+        theme.setImpl(mResourcesImpl.newThemeImpl());
+        mThemeRefs.add(new WeakReference<>(theme));
+        return theme;
     }
 
     /**
@@ -1893,7 +1752,7 @@
         // out the attributes from the XML file (applying type information
         // contained in the resources and such).
         XmlBlock.Parser parser = (XmlBlock.Parser)set;
-        mAssets.retrieveAttributes(parser.mParseState, attrs,
+        mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
                 array.mData, array.mIndices);
 
         array.mXml = parser;
@@ -1904,151 +1763,16 @@
     /**
      * Store the newly updated configuration.
      */
-    public void updateConfiguration(Configuration config,
-            DisplayMetrics metrics) {
+    public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
         updateConfiguration(config, metrics, null);
     }
 
     /**
      * @hide
      */
-    public void updateConfiguration(Configuration config,
-            DisplayMetrics metrics, CompatibilityInfo compat) {
-        synchronized (mAccessLock) {
-            if (false) {
-                Slog.i(TAG, "**** Updating config of " + this + ": old config is "
-                        + mConfiguration + " old compat is " + mCompatibilityInfo);
-                Slog.i(TAG, "**** Updating config of " + this + ": new config is "
-                        + config + " new compat is " + compat);
-            }
-            if (compat != null) {
-                mCompatibilityInfo = compat;
-            }
-            if (metrics != null) {
-                mMetrics.setTo(metrics);
-            }
-            // NOTE: We should re-arrange this code to create a Display
-            // with the CompatibilityInfo that is used everywhere we deal
-            // with the display in relation to this app, rather than
-            // doing the conversion here.  This impl should be okay because
-            // we make sure to return a compatible display in the places
-            // where there are public APIs to retrieve the display...  but
-            // it would be cleaner and more maintainble to just be
-            // consistently dealing with a compatible display everywhere in
-            // the framework.
-            mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
-
-            final int configChanges = calcConfigChanges(config);
-
-            LocaleList locales = mConfiguration.getLocales();
-            if (locales.isEmpty()) {
-                locales = LocaleList.getAdjustedDefault();
-                mConfiguration.setLocales(locales);
-            }
-            if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
-                mMetrics.densityDpi = mConfiguration.densityDpi;
-                mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
-            }
-            mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
-
-            final int width, height;
-            if (mMetrics.widthPixels >= mMetrics.heightPixels) {
-                width = mMetrics.widthPixels;
-                height = mMetrics.heightPixels;
-            } else {
-                //noinspection SuspiciousNameCombination
-                width = mMetrics.heightPixels;
-                //noinspection SuspiciousNameCombination
-                height = mMetrics.widthPixels;
-            }
-
-            final int keyboardHidden;
-            if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
-                    && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
-                keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
-            } else {
-                keyboardHidden = mConfiguration.keyboardHidden;
-            }
-
-            mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
-                    adjustLanguageTag(locales.get(0).toLanguageTag()),
-                    mConfiguration.orientation,
-                    mConfiguration.touchscreen,
-                    mConfiguration.densityDpi, mConfiguration.keyboard,
-                    keyboardHidden, mConfiguration.navigation, width, height,
-                    mConfiguration.smallestScreenWidthDp,
-                    mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
-                    mConfiguration.screenLayout, mConfiguration.uiMode,
-                    Build.VERSION.RESOURCES_SDK_INT);
-
-            if (DEBUG_CONFIG) {
-                Slog.i(TAG, "**** Updating config of " + this + ": final config is "
-                        + mConfiguration + " final compat is " + mCompatibilityInfo);
-            }
-
-            mDrawableCache.onConfigurationChange(configChanges);
-            mColorDrawableCache.onConfigurationChange(configChanges);
-            mComplexColorCache.onConfigurationChange(configChanges);
-            mAnimatorCache.onConfigurationChange(configChanges);
-            mStateListAnimatorCache.onConfigurationChange(configChanges);
-
-            flushLayoutCache();
-        }
-        synchronized (sSync) {
-            if (mPluralRule != null) {
-                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
-            }
-        }
-    }
-
-    /**
-     * Called by ConfigurationBoundResourceCacheTest via reflection.
-     */
-    private int calcConfigChanges(Configuration config) {
-        int configChanges = 0xfffffff;
-        if (config != null) {
-            mTmpConfig.setTo(config);
-            int density = config.densityDpi;
-            if (density == Configuration.DENSITY_DPI_UNDEFINED) {
-                density = mMetrics.noncompatDensityDpi;
-            }
-
-            mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
-
-            if (mTmpConfig.getLocales().isEmpty()) {
-                mTmpConfig.setLocales(LocaleList.getDefault());
-            }
-            configChanges = mConfiguration.updateFrom(mTmpConfig);
-            configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
-        }
-        return configChanges;
-    }
-
-    /**
-     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
-     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
-     *
-     * All released versions of android prior to "L" used the deprecated language
-     * tags, so we will need to support them for backwards compatibility.
-     *
-     * Note that this conversion needs to take place *after* the call to
-     * {@code toLanguageTag} because that will convert all the deprecated codes to
-     * the new ones, even if they're set manually.
-     */
-    private static String adjustLanguageTag(String languageTag) {
-        final int separator = languageTag.indexOf('-');
-        final String language;
-        final String remainder;
-
-        if (separator == -1) {
-            language = languageTag;
-            remainder = "";
-        } else {
-            language = languageTag.substring(0, separator);
-            remainder = languageTag.substring(separator);
-        }
-
-        return Locale.adjustLanguageCode(language) + remainder;
+    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
+                                    CompatibilityInfo compat) {
+        mResourcesImpl.updateConfiguration(config, metrics, compat);
     }
 
     /**
@@ -2073,9 +1797,7 @@
      * @return The resource's current display metrics. 
      */
     public DisplayMetrics getDisplayMetrics() {
-        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
-                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
-        return mMetrics;
+        return mResourcesImpl.getDisplayMetrics();
     }
 
     /**
@@ -2085,13 +1807,13 @@
      * @return The resource's current configuration. 
      */
     public Configuration getConfiguration() {
-        return mConfiguration;
+        return mResourcesImpl.getConfiguration();
     }
 
     /** @hide */
     public Configuration[] getSizeConfigurations() {
-        return mAssets.getSizeConfigurations();
-    };
+        return mResourcesImpl.getSizeConfigurations();
+    }
 
     /**
      * Return the compatibility mode information for the application.
@@ -2101,17 +1823,17 @@
      * @hide
      */
     public CompatibilityInfo getCompatibilityInfo() {
-        return mCompatibilityInfo;
+        return mResourcesImpl.getCompatibilityInfo();
     }
 
     /**
      * This is just for testing.
      * @hide
      */
+    @VisibleForTesting
     public void setCompatibilityInfo(CompatibilityInfo ci) {
         if (ci != null) {
-            mCompatibilityInfo = ci;
-            updateConfiguration(mConfiguration, mMetrics);
+            mResourcesImpl.updateConfiguration(null, null, ci);
         }
     }
     
@@ -2136,15 +1858,7 @@
      *         resource was found.  (0 is not a valid resource ID.)
      */
     public int getIdentifier(String name, String defType, String defPackage) {
-        if (name == null) {
-            throw new NullPointerException("name is null");
-        }
-        try {
-            return Integer.parseInt(name);
-        } catch (Exception e) {
-            // Ignore
-        }
-        return mAssets.getResourceIdentifier(name, defType, defPackage);
+        return mResourcesImpl.getIdentifier(name, defType, defPackage);
     }
 
     /**
@@ -2171,10 +1885,7 @@
      * @see #getResourceEntryName
      */
     public String getResourceName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourceName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourceName(resid);
     }
     
     /**
@@ -2190,10 +1901,7 @@
      * @see #getResourceName
      */
     public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourcePackageName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourcePackageName(resid);
     }
     
     /**
@@ -2209,10 +1917,7 @@
      * @see #getResourceName
      */
     public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourceTypeName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourceTypeName(resid);
     }
     
     /**
@@ -2228,10 +1933,7 @@
      * @see #getResourceName
      */
     public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourceEntryName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourceEntryName(resid);
     }
     
     /**
@@ -2334,7 +2036,7 @@
      * Retrieve underlying AssetManager storage for these resources.
      */
     public final AssetManager getAssets() {
-        return mAssets;
+        return mResourcesImpl.getAssets();
     }
 
     /**
@@ -2343,19 +2045,7 @@
      * tools.
      */
     public final void flushLayoutCache() {
-        final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
-        final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
-        synchronized (cachedXmlBlockFiles) {
-            final int num = cachedXmlBlockFiles.length;
-            for (int i = 0; i < num; i++) {
-                final XmlBlock oldBlock = cachedXmlBlocks[i];
-                if (oldBlock != null) {
-                    oldBlock.close();
-                }
-                cachedXmlBlockFiles[i] = null;
-                cachedXmlBlocks[i] = null;
-            }
-        }
+        mResourcesImpl.flushLayoutCache();
     }
 
     /**
@@ -2364,15 +2054,7 @@
      * {@hide}
      */
     public final void startPreloading() {
-        synchronized (sSync) {
-            if (sPreloaded) {
-                throw new IllegalStateException("Resources already preloaded");
-            }
-            sPreloaded = true;
-            mPreloading = true;
-            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
-            updateConfiguration(null, null);
-        }
+        mResourcesImpl.startPreloading();
     }
     
     /**
@@ -2380,441 +2062,14 @@
      * to normal Resources operation.
      */
     public final void finishPreloading() {
-        if (mPreloading) {
-            mPreloading = false;
-            flushLayoutCache();
-        }
+        mResourcesImpl.finishPreloading();
     }
 
     /**
      * @hide
      */
     public LongSparseArray<ConstantState> getPreloadedDrawables() {
-        return sPreloadedDrawables[0];
-    }
-
-    private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
-            int resourceId, String name) {
-        // We allow preloading of resources even if they vary by font scale (which
-        // doesn't impact resource selection) or density (which we handle specially by
-        // simply turning off all preloading), as well as any other configs specified
-        // by the caller.
-        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
-                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
-            String resName;
-            try {
-                resName = getResourceName(resourceId);
-            } catch (NotFoundException e) {
-                resName = "?";
-            }
-            // This should never happen in production, so we should log a
-            // warning even if we're not debugging.
-            Log.w(TAG, "Preloaded " + name + " resource #0x"
-                    + Integer.toHexString(resourceId)
-                    + " (" + resName + ") that varies with configuration!!");
-            return false;
-        }
-        if (TRACE_FOR_PRELOAD) {
-            String resName;
-            try {
-                resName = getResourceName(resourceId);
-            } catch (NotFoundException e) {
-                resName = "?";
-            }
-            Log.w(TAG, "Preloading " + name + " resource #0x"
-                    + Integer.toHexString(resourceId)
-                    + " (" + resName + ")");
-        }
-        return true;
-    }
-
-    @Nullable
-    Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
-        return loadDrawable(value, id, theme, true);
-    }
-
-    @Nullable
-    Drawable loadDrawable(TypedValue value, int id, Theme theme, boolean useCache)
-            throws NotFoundException {
-        try {
-            if (TRACE_FOR_PRELOAD) {
-                // Log only framework resources
-                if ((id >>> 24) == 0x1) {
-                    final String name = getResourceName(id);
-                    if (name != null) {
-                        Log.d("PreloadDrawable", name);
-                    }
-                }
-            }
-
-            final boolean isColorDrawable;
-            final DrawableCache caches;
-            final long key;
-            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
-                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-                isColorDrawable = true;
-                caches = mColorDrawableCache;
-                key = value.data;
-            } else {
-                isColorDrawable = false;
-                caches = mDrawableCache;
-                key = (((long) value.assetCookie) << 32) | value.data;
-            }
-
-            // First, check whether we have a cached version of this drawable
-            // that was inflated against the specified theme. Skip the cache if
-            // we're currently preloading or we're not using the cache.
-            if (!mPreloading && useCache) {
-                final Drawable cachedDrawable = caches.getInstance(key, theme);
-                if (cachedDrawable != null) {
-                    return cachedDrawable;
-                }
-            }
-
-            // Next, check preloaded drawables. Preloaded drawables may contain
-            // unresolved theme attributes.
-            final ConstantState cs;
-            if (isColorDrawable) {
-                cs = sPreloadedColorDrawables.get(key);
-            } else {
-                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
-            }
-
-            Drawable dr;
-            if (cs != null) {
-                dr = cs.newDrawable(this);
-            } else if (isColorDrawable) {
-                dr = new ColorDrawable(value.data);
-            } else {
-                dr = loadDrawableForCookie(value, id, null);
-            }
-
-            // Determine if the drawable has unresolved theme attributes. If it
-            // does, we'll need to apply a theme and store it in a theme-specific
-            // cache.
-            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
-            if (canApplyTheme && theme != null) {
-                dr = dr.mutate();
-                dr.applyTheme(theme);
-                dr.clearMutated();
-            }
-
-            // If we were able to obtain a drawable, store it in the appropriate
-            // cache: preload, not themed, null theme, or theme-specific. Don't
-            // pollute the cache with drawables loaded from a foreign density.
-            if (dr != null && useCache) {
-                dr.setChangingConfigurations(value.changingConfigurations);
-                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
-            }
-
-            return dr;
-        } catch (Exception e) {
-            String name;
-            try {
-                name = getResourceName(id);
-            } catch (NotFoundException e2) {
-                name = "(missing name)";
-            }
-
-            // The target drawable might fail to load for any number of
-            // reasons, but we always want to include the resource name.
-            // Since the client already expects this method to throw a
-            // NotFoundException, just throw one of those.
-            final NotFoundException nfe = new NotFoundException("Drawable " + name
-                    + " with resource ID #0x" + Integer.toHexString(id), e);
-            nfe.setStackTrace(new StackTraceElement[0]);
-            throw nfe;
-        }
-    }
-
-    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
-            Theme theme, boolean usesTheme, long key, Drawable dr) {
-        final ConstantState cs = dr.getConstantState();
-        if (cs == null) {
-            return;
-        }
-
-        if (mPreloading) {
-            final int changingConfigs = cs.getChangingConfigurations();
-            if (isColorDrawable) {
-                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
-                    sPreloadedColorDrawables.put(key, cs);
-                }
-            } else {
-                if (verifyPreloadConfig(
-                        changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
-                    if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
-                        // If this resource does not vary based on layout direction,
-                        // we can put it in all of the preload maps.
-                        sPreloadedDrawables[0].put(key, cs);
-                        sPreloadedDrawables[1].put(key, cs);
-                    } else {
-                        // Otherwise, only in the layout dir we loaded it for.
-                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
-                    }
-                }
-            }
-        } else {
-            synchronized (mAccessLock) {
-                caches.put(key, theme, cs, usesTheme);
-            }
-        }
-    }
-
-    /**
-     * Loads a drawable from XML or resources stream.
-     */
-    private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
-        if (value.string == null) {
-            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
-                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
-        }
-
-        final String file = value.string.toString();
-
-        if (TRACE_FOR_MISS_PRELOAD) {
-            // Log only framework resources
-            if ((id >>> 24) == 0x1) {
-                final String name = getResourceName(id);
-                if (name != null) {
-                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
-                            + ": " + name + " at " + file);
-                }
-            }
-        }
-
-        if (DEBUG_LOAD) {
-            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
-        }
-
-        final Drawable dr;
-
-        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
-        try {
-            if (file.endsWith(".xml")) {
-                final XmlResourceParser rp = loadXmlResourceParser(
-                        file, id, value.assetCookie, "drawable");
-                dr = Drawable.createFromXml(this, rp, theme);
-                rp.close();
-            } else {
-                final InputStream is = mAssets.openNonAsset(
-                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
-                dr = Drawable.createFromResourceStream(this, value, is, file, null);
-                is.close();
-            }
-        } catch (Exception e) {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-            final NotFoundException rnf = new NotFoundException(
-                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
-            rnf.initCause(e);
-            throw rnf;
-        }
-        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-
-        return dr;
-    }
-
-    /**
-     * Given the value and id, we can get the XML filename as in value.data, based on that, we
-     * first try to load CSL from the cache. If not found, try to get from the constant state.
-     * Last, parse the XML and generate the CSL.
-     */
-    private ComplexColor loadComplexColorFromName(Theme theme, TypedValue value, int id) {
-        final long key = (((long) value.assetCookie) << 32) | value.data;
-        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
-        ComplexColor complexColor = cache.getInstance(key, theme);
-        if (complexColor != null) {
-            return complexColor;
-        }
-
-        final android.content.res.ConstantState<ComplexColor> factory =
-                sPreloadedComplexColors.get(key);
-
-        if (factory != null) {
-            complexColor = factory.newInstance(this, theme);
-        }
-        if (complexColor == null) {
-            complexColor = loadComplexColorForCookie(value, id, theme);
-        }
-
-        if (complexColor != null) {
-            if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                        "color")) {
-                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
-                }
-            } else {
-                cache.put(key, theme, complexColor.getConstantState());
-            }
-        }
-        return complexColor;
-    }
-
-    @Nullable
-    public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, Theme theme) {
-        if (TRACE_FOR_PRELOAD) {
-            // Log only framework resources
-            if ((id >>> 24) == 0x1) {
-                final String name = getResourceName(id);
-                if (name != null) android.util.Log.d("loadComplexColor", name);
-            }
-        }
-
-        final long key = (((long) value.assetCookie) << 32) | value.data;
-
-        // Handle inline color definitions.
-        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
-                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            return getColorStateListFromInt(value, key);
-        }
-
-        final String file = value.string.toString();
-
-        ComplexColor complexColor;
-        if (file.endsWith(".xml")) {
-            try {
-                complexColor = loadComplexColorFromName(theme, value, id);
-            } catch (Exception e) {
-                final NotFoundException rnf = new NotFoundException(
-                        "File " + file + " from complex color resource ID #0x"
-                                + Integer.toHexString(id));
-                rnf.initCause(e);
-                throw rnf;
-            }
-        } else {
-            throw new NotFoundException(
-                    "File " + file + " from drawable resource ID #0x"
-                            + Integer.toHexString(id) + ": .xml extension required");
-        }
-
-        return complexColor;
-    }
-
-    @Nullable
-    ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
-            throws NotFoundException {
-        if (TRACE_FOR_PRELOAD) {
-            // Log only framework resources
-            if ((id >>> 24) == 0x1) {
-                final String name = getResourceName(id);
-                if (name != null) android.util.Log.d("PreloadColorStateList", name);
-            }
-        }
-
-        final long key = (((long) value.assetCookie) << 32) | value.data;
-
-        // Handle inline color definitions.
-        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
-                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            return getColorStateListFromInt(value, key);
-        }
-
-        ComplexColor complexColor = loadComplexColorFromName(theme, value, id);
-        if (complexColor != null && complexColor instanceof ColorStateList) {
-            return (ColorStateList) complexColor;
-        }
-
-        throw new NotFoundException(
-                "Can't find ColorStateList from drawable resource ID #0x"
-                        + Integer.toHexString(id));
-    }
-
-    @NonNull
-    private ColorStateList getColorStateListFromInt(@NonNull  TypedValue value, long key) {
-        ColorStateList csl;
-        final android.content.res.ConstantState<ComplexColor> factory =
-                sPreloadedComplexColors.get(key);
-        if (factory != null) {
-            return (ColorStateList) factory.newInstance();
-        }
-
-        csl = ColorStateList.valueOf(value.data);
-
-        if (mPreloading) {
-            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                    "color")) {
-                sPreloadedComplexColors.put(key, csl.getConstantState());
-            }
-        }
-
-        return csl;
-    }
-
-    /**
-     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
-     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
-     *
-     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
-     * and selector tag.
-     *
-     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
-     */
-    @Nullable
-    private ComplexColor loadComplexColorForCookie(TypedValue value, int id, Theme theme) {
-        if (value.string == null) {
-            throw new UnsupportedOperationException(
-                    "Can't convert to ComplexColor: type=0x" + value.type);
-        }
-
-        final String file = value.string.toString();
-
-        if (TRACE_FOR_MISS_PRELOAD) {
-            // Log only framework resources
-            if ((id >>> 24) == 0x1) {
-                final String name = getResourceName(id);
-                if (name != null) {
-                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
-                            + ": " + name + " at " + file);
-                }
-            }
-        }
-
-        if (DEBUG_LOAD) {
-            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
-        }
-
-        ComplexColor complexColor = null;
-
-        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
-        if (file.endsWith(".xml")) {
-            try {
-                final XmlResourceParser parser = loadXmlResourceParser(
-                        file, id, value.assetCookie, "ComplexColor");
-
-                final AttributeSet attrs = Xml.asAttributeSet(parser);
-                int type;
-                while ((type = parser.next()) != XmlPullParser.START_TAG
-                        && type != XmlPullParser.END_DOCUMENT) {
-                    // Seek parser to start tag.
-                }
-                if (type != XmlPullParser.START_TAG) {
-                    throw new XmlPullParserException("No start tag found");
-                }
-
-                final String name = parser.getName();
-                if (name.equals("gradient")) {
-                    complexColor = GradientColor.createFromXmlInner(this, parser, attrs, theme);
-                } else if (name.equals("selector")) {
-                    complexColor = ColorStateList.createFromXmlInner(this, parser, attrs, theme);
-                }
-                parser.close();
-            } catch (Exception e) {
-                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-                final NotFoundException rnf = new NotFoundException(
-                        "File " + file + " from ComplexColor resource ID #0x"
-                                + Integer.toHexString(id));
-                rnf.initCause(e);
-                throw rnf;
-            }
-        } else {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-            throw new NotFoundException(
-                    "File " + file + " from drawable resource ID #0x"
-                            + Integer.toHexString(id) + ": .xml extension required");
-        }
-        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-
-        return complexColor;
+        return mResourcesImpl.getPreloadedDrawables();
     }
 
     /**
@@ -2828,10 +2083,12 @@
     @NonNull
     XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_STRING) {
-                return loadXmlResourceParser(value.string.toString(), id,
+                return impl.loadXmlResourceParser(value.string.toString(), id,
                         value.assetCookie, type);
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
@@ -2852,47 +2109,18 @@
      * @throws NotFoundException if the file could not be loaded
      */
     @NonNull
-    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
-            int assetCookie, @NonNull String type) throws NotFoundException {
-        if (id != 0) {
-            try {
-                final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
-                final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
-                synchronized (cachedXmlBlockFiles) {
-                    // First see if this block is in our cache.
-                    final int num = cachedXmlBlockFiles.length;
-                    for (int i = 0; i < num; i++) {
-                        if (cachedXmlBlockFiles[i] != null
-                                && cachedXmlBlockFiles[i].equals(file)) {
-                            return cachedXmlBlocks[i].newParser();
-                        }
-                    }
+    XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie,
+                                            String type) throws NotFoundException {
+        return mResourcesImpl.loadXmlResourceParser(file, id, assetCookie, type);
+    }
 
-                    // Not in the cache, create a new block and put it at
-                    // the next slot in the cache.
-                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
-                    if (block != null) {
-                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
-                        mLastCachedXmlBlockIndex = pos;
-                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
-                        if (oldBlock != null) {
-                            oldBlock.close();
-                        }
-                        cachedXmlBlockFiles[pos] = file;
-                        cachedXmlBlocks[pos] = block;
-                        return block.newParser();
-                    }
-                }
-            } catch (Exception e) {
-                final NotFoundException rnf = new NotFoundException("File " + file
-                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
-                rnf.initCause(e);
-                throw rnf;
-            }
-        }
-
-        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
-                + Integer.toHexString(id));
+    /**
+     * Called by ConfigurationBoundResourceCacheTest.
+     * @hide
+     */
+    @VisibleForTesting
+    public int calcConfigChanges(Configuration config) {
+        return mResourcesImpl.calcConfigChanges(config);
     }
 
     /**
@@ -2908,16 +2136,4 @@
         }
         return theme.obtainStyledAttributes(set, attrs, 0, 0);
     }
-
-    private Resources() {
-        mAssets = AssetManager.getSystem();
-        mClassLoader = ClassLoader.getSystemClassLoader();
-        // NOTE: Intentionally leaving this uninitialized (all values set
-        // to zero), so that anyone who tries to do something that requires
-        // metrics will get a very wrong value.
-        mConfiguration.setToDefaults();
-        mMetrics.setToDefaults();
-        updateConfiguration(null, null);
-        mAssets.ensureStringBlocks();
-    }
 }
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
new file mode 100644
index 0000000..a364010
--- /dev/null
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR 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.res;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.animation.Animator;
+import android.animation.StateListAnimator;
+import android.annotation.AnyRes;
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.PluralsRes;
+import android.annotation.RawRes;
+import android.annotation.StyleRes;
+import android.annotation.StyleableRes;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.Config;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.icu.text.PluralRules;
+import android.os.Build;
+import android.os.Trace;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.util.Xml;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * The implementation of Resource access. This class contains the AssetManager and all caches
+ * associated with it.
+ *
+ * {@link Resources} is just a thing wrapper around this class. When a configuration change
+ * occurs, clients can retain the same {@link Resources} reference because the underlying
+ * {@link ResourcesImpl} object will be updated or re-created.
+ *
+ * @hide
+ */
+public class ResourcesImpl {
+    static final String TAG = "Resources";
+
+    private static final boolean DEBUG_LOAD = false;
+    private static final boolean DEBUG_CONFIG = false;
+    private static final boolean TRACE_FOR_PRELOAD = false;
+    private static final boolean TRACE_FOR_MISS_PRELOAD = false;
+
+    private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigJavaToNative(
+            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
+
+    private static final int ID_OTHER = 0x01000004;
+
+    private static final Object sSync = new Object();
+
+    private static boolean sPreloaded;
+    private boolean mPreloading;
+
+    // Information about preloaded resources.  Note that they are not
+    // protected by a lock, because while preloading in zygote we are all
+    // single-threaded, and after that these are immutable.
+    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
+    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
+            = new LongSparseArray<>();
+    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
+            sPreloadedComplexColors = new LongSparseArray<>();
+
+    /** Lock object used to protect access to caches and configuration. */
+    private final Object mAccessLock = new Object();
+
+    // These are protected by mAccessLock.
+    private final Configuration mTmpConfig = new Configuration();
+    private final DrawableCache mDrawableCache = new DrawableCache();
+    private final DrawableCache mColorDrawableCache = new DrawableCache();
+    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
+            new ConfigurationBoundResourceCache<>();
+    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
+            new ConfigurationBoundResourceCache<>();
+    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
+            new ConfigurationBoundResourceCache<>();
+
+    /** Size of the cyclical cache used to map XML files to blocks. */
+    private static final int XML_BLOCK_CACHE_SIZE = 4;
+
+    // Cyclical cache used for recently-accessed XML files.
+    private int mLastCachedXmlBlockIndex = -1;
+    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
+    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
+    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
+
+
+    final AssetManager mAssets;
+    final DisplayMetrics mMetrics = new DisplayMetrics();
+
+    private PluralRules mPluralRule;
+
+    private final Configuration mConfiguration = new Configuration();
+    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+
+    static {
+        sPreloadedDrawables = new LongSparseArray[2];
+        sPreloadedDrawables[0] = new LongSparseArray<>();
+        sPreloadedDrawables[1] = new LongSparseArray<>();
+    }
+
+    /**
+     * Creates a new ResourcesImpl object with CompatibilityInfo.
+     *
+     * @param assets Previously created AssetManager.
+     * @param metrics Current display metrics to consider when
+     *                selecting/computing resource values.
+     * @param config Desired device configuration to consider when
+     *               selecting/computing resource values (optional).
+     * @param compatInfo this resource's compatibility info. Must not be null.
+     */
+    public ResourcesImpl(AssetManager assets, DisplayMetrics metrics, Configuration config,
+            CompatibilityInfo compatInfo) {
+        mAssets = assets;
+        mMetrics.setToDefaults();
+        updateConfiguration(config, metrics, compatInfo);
+        mAssets.ensureStringBlocks();
+    }
+
+    public AssetManager getAssets() {
+        return mAssets;
+    }
+
+    DisplayMetrics getDisplayMetrics() {
+        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
+                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
+        return mMetrics;
+    }
+
+    Configuration getConfiguration() {
+        return mConfiguration;
+    }
+
+    Configuration[] getSizeConfigurations() {
+        return mAssets.getSizeConfigurations();
+    }
+
+    CompatibilityInfo getCompatibilityInfo() {
+        return mCompatibilityInfo;
+    }
+
+    private PluralRules getPluralRule() {
+        synchronized (sSync) {
+            if (mPluralRule == null) {
+                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
+            }
+            return mPluralRule;
+        }
+    }
+
+    void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
+        if (found) {
+            return;
+        }
+        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+    }
+
+    void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
+            boolean resolveRefs) throws NotFoundException {
+        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
+        if (found) {
+            return;
+        }
+        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+    }
+
+    void getValue(String name, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        int id = getIdentifier(name, "string", null);
+        if (id != 0) {
+            getValue(id, outValue, resolveRefs);
+            return;
+        }
+        throw new NotFoundException("String resource name " + name);
+    }
+
+    int getIdentifier(String name, String defType, String defPackage) {
+        if (name == null) {
+            throw new NullPointerException("name is null");
+        }
+        try {
+            return Integer.parseInt(name);
+        } catch (Exception e) {
+            // Ignore
+        }
+        return mAssets.getResourceIdentifier(name, defType, defPackage);
+    }
+
+    @NonNull
+    String getResourceName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourceName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourcePackageName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourceTypeName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourceEntryName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
+        PluralRules rule = getPluralRule();
+        CharSequence res = mAssets.getResourceBagText(id,
+                attrForQuantityCode(rule.select(quantity)));
+        if (res != null) {
+            return res;
+        }
+        res = mAssets.getResourceBagText(id, ID_OTHER);
+        if (res != null) {
+            return res;
+        }
+        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
+                + " quantity=" + quantity
+                + " item=" + rule.select(quantity));
+    }
+
+    private static int attrForQuantityCode(String quantityCode) {
+        switch (quantityCode) {
+            case PluralRules.KEYWORD_ZERO: return 0x01000005;
+            case PluralRules.KEYWORD_ONE:  return 0x01000006;
+            case PluralRules.KEYWORD_TWO:  return 0x01000007;
+            case PluralRules.KEYWORD_FEW:  return 0x01000008;
+            case PluralRules.KEYWORD_MANY: return 0x01000009;
+            default:                       return ID_OTHER;
+        }
+    }
+
+    @NonNull
+    AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
+            throws NotFoundException {
+        getValue(id, tempValue, true);
+        try {
+            return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
+        } catch (Exception e) {
+            throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
+                    + "resource ID #0x" + Integer.toHexString(id), e);
+        }
+    }
+
+    @NonNull
+    InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
+        getValue(id, value, true);
+        try {
+            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
+                    AssetManager.ACCESS_STREAMING);
+        } catch (Exception e) {
+            NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
+                    " from drawable resource ID #0x" + Integer.toHexString(id));
+            rnf.initCause(e);
+            throw rnf;
+        }
+    }
+
+    ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+        return mAnimatorCache;
+    }
+
+    ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+        return mStateListAnimatorCache;
+    }
+
+    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
+                                    CompatibilityInfo compat) {
+        synchronized (mAccessLock) {
+            if (false) {
+                Slog.i(TAG, "**** Updating config of " + this + ": old config is "
+                        + mConfiguration + " old compat is " + mCompatibilityInfo);
+                Slog.i(TAG, "**** Updating config of " + this + ": new config is "
+                        + config + " new compat is " + compat);
+            }
+            if (compat != null) {
+                mCompatibilityInfo = compat;
+            }
+            if (metrics != null) {
+                mMetrics.setTo(metrics);
+            }
+            // NOTE: We should re-arrange this code to create a Display
+            // with the CompatibilityInfo that is used everywhere we deal
+            // with the display in relation to this app, rather than
+            // doing the conversion here.  This impl should be okay because
+            // we make sure to return a compatible display in the places
+            // where there are public APIs to retrieve the display...  but
+            // it would be cleaner and more maintainble to just be
+            // consistently dealing with a compatible display everywhere in
+            // the framework.
+            mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
+
+            final @Config int configChanges = calcConfigChanges(config);
+
+            LocaleList locales = mConfiguration.getLocales();
+            if (locales.isEmpty()) {
+                locales = LocaleList.getAdjustedDefault();
+                mConfiguration.setLocales(locales);
+            }
+            if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
+                mMetrics.densityDpi = mConfiguration.densityDpi;
+                mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+            }
+            mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
+
+            final int width, height;
+            if (mMetrics.widthPixels >= mMetrics.heightPixels) {
+                width = mMetrics.widthPixels;
+                height = mMetrics.heightPixels;
+            } else {
+                //noinspection SuspiciousNameCombination
+                width = mMetrics.heightPixels;
+                //noinspection SuspiciousNameCombination
+                height = mMetrics.widthPixels;
+            }
+
+            final int keyboardHidden;
+            if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
+                    && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
+                keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
+            } else {
+                keyboardHidden = mConfiguration.keyboardHidden;
+            }
+
+            mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
+                    adjustLanguageTag(locales.get(0).toLanguageTag()),
+                    mConfiguration.orientation,
+                    mConfiguration.touchscreen,
+                    mConfiguration.densityDpi, mConfiguration.keyboard,
+                    keyboardHidden, mConfiguration.navigation, width, height,
+                    mConfiguration.smallestScreenWidthDp,
+                    mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
+                    mConfiguration.screenLayout, mConfiguration.uiMode,
+                    Build.VERSION.RESOURCES_SDK_INT);
+
+            if (DEBUG_CONFIG) {
+                Slog.i(TAG, "**** Updating config of " + this + ": final config is "
+                        + mConfiguration + " final compat is " + mCompatibilityInfo);
+            }
+
+            mDrawableCache.onConfigurationChange(configChanges);
+            mColorDrawableCache.onConfigurationChange(configChanges);
+            mComplexColorCache.onConfigurationChange(configChanges);
+            mAnimatorCache.onConfigurationChange(configChanges);
+            mStateListAnimatorCache.onConfigurationChange(configChanges);
+
+            flushLayoutCache();
+        }
+        synchronized (sSync) {
+            if (mPluralRule != null) {
+                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
+            }
+        }
+    }
+
+    /**
+     * Applies the new configuration, returning a bitmask of the changes
+     * between the old and new configurations.
+     *
+     * @param config the new configuration
+     * @return bitmask of config changes
+     */
+    public @Config int calcConfigChanges(@Nullable Configuration config) {
+        if (config == null) {
+            // If there is no configuration, assume all flags have changed.
+            return 0xFFFFFFFF;
+        }
+
+        mTmpConfig.setTo(config);
+        int density = config.densityDpi;
+        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+            density = mMetrics.noncompatDensityDpi;
+        }
+
+        mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
+
+        if (mTmpConfig.getLocales().isEmpty()) {
+            mTmpConfig.setLocales(LocaleList.getDefault());
+        }
+        return mConfiguration.updateFrom(mTmpConfig);
+    }
+
+    /**
+     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
+     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
+     *
+     * All released versions of android prior to "L" used the deprecated language
+     * tags, so we will need to support them for backwards compatibility.
+     *
+     * Note that this conversion needs to take place *after* the call to
+     * {@code toLanguageTag} because that will convert all the deprecated codes to
+     * the new ones, even if they're set manually.
+     */
+    private static String adjustLanguageTag(String languageTag) {
+        final int separator = languageTag.indexOf('-');
+        final String language;
+        final String remainder;
+
+        if (separator == -1) {
+            language = languageTag;
+            remainder = "";
+        } else {
+            language = languageTag.substring(0, separator);
+            remainder = languageTag.substring(separator);
+        }
+
+        return Locale.adjustLanguageCode(language) + remainder;
+    }
+
+    /**
+     * Call this to remove all cached loaded layout resources from the
+     * Resources object.  Only intended for use with performance testing
+     * tools.
+     */
+    public void flushLayoutCache() {
+        synchronized (mCachedXmlBlocks) {
+            Arrays.fill(mCachedXmlBlockCookies, 0);
+            Arrays.fill(mCachedXmlBlockFiles, null);
+
+            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
+                final XmlBlock oldBlock = cachedXmlBlocks[i];
+                if (oldBlock != null) {
+                    oldBlock.close();
+                }
+            }
+            Arrays.fill(cachedXmlBlocks, null);
+        }
+    }
+
+    @Nullable
+    Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme,
+            boolean useCache) throws NotFoundException {
+        try {
+            if (TRACE_FOR_PRELOAD) {
+                // Log only framework resources
+                if ((id >>> 24) == 0x1) {
+                    final String name = getResourceName(id);
+                    if (name != null) {
+                        Log.d("PreloadDrawable", name);
+                    }
+                }
+            }
+
+            final boolean isColorDrawable;
+            final DrawableCache caches;
+            final long key;
+            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+                isColorDrawable = true;
+                caches = mColorDrawableCache;
+                key = value.data;
+            } else {
+                isColorDrawable = false;
+                caches = mDrawableCache;
+                key = (((long) value.assetCookie) << 32) | value.data;
+            }
+
+            // First, check whether we have a cached version of this drawable
+            // that was inflated against the specified theme. Skip the cache if
+            // we're currently preloading or we're not using the cache.
+            if (!mPreloading && useCache) {
+                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
+                if (cachedDrawable != null) {
+                    return cachedDrawable;
+                }
+            }
+
+            // Next, check preloaded drawables. Preloaded drawables may contain
+            // unresolved theme attributes.
+            final Drawable.ConstantState cs;
+            if (isColorDrawable) {
+                cs = sPreloadedColorDrawables.get(key);
+            } else {
+                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
+            }
+
+            Drawable dr;
+            if (cs != null) {
+                dr = cs.newDrawable(wrapper);
+            } else if (isColorDrawable) {
+                dr = new ColorDrawable(value.data);
+            } else {
+                dr = loadDrawableForCookie(wrapper, value, id, null);
+            }
+
+            // Determine if the drawable has unresolved theme attributes. If it
+            // does, we'll need to apply a theme and store it in a theme-specific
+            // cache.
+            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
+            if (canApplyTheme && theme != null) {
+                dr = dr.mutate();
+                dr.applyTheme(theme);
+                dr.clearMutated();
+            }
+
+            // If we were able to obtain a drawable, store it in the appropriate
+            // cache: preload, not themed, null theme, or theme-specific. Don't
+            // pollute the cache with drawables loaded from a foreign density.
+            if (dr != null && useCache) {
+                dr.setChangingConfigurations(value.changingConfigurations);
+                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
+            }
+
+            return dr;
+        } catch (Exception e) {
+            String name;
+            try {
+                name = getResourceName(id);
+            } catch (NotFoundException e2) {
+                name = "(missing name)";
+            }
+
+            // The target drawable might fail to load for any number of
+            // reasons, but we always want to include the resource name.
+            // Since the client already expects this method to throw a
+            // NotFoundException, just throw one of those.
+            final NotFoundException nfe = new NotFoundException("Drawable " + name
+                    + " with resource ID #0x" + Integer.toHexString(id), e);
+            nfe.setStackTrace(new StackTraceElement[0]);
+            throw nfe;
+        }
+    }
+
+    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
+            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
+        final Drawable.ConstantState cs = dr.getConstantState();
+        if (cs == null) {
+            return;
+        }
+
+        if (mPreloading) {
+            final int changingConfigs = cs.getChangingConfigurations();
+            if (isColorDrawable) {
+                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
+                    sPreloadedColorDrawables.put(key, cs);
+                }
+            } else {
+                if (verifyPreloadConfig(
+                        changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
+                    if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
+                        // If this resource does not vary based on layout direction,
+                        // we can put it in all of the preload maps.
+                        sPreloadedDrawables[0].put(key, cs);
+                        sPreloadedDrawables[1].put(key, cs);
+                    } else {
+                        // Otherwise, only in the layout dir we loaded it for.
+                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
+                    }
+                }
+            }
+        } else {
+            synchronized (mAccessLock) {
+                caches.put(key, theme, cs, usesTheme);
+            }
+        }
+    }
+
+    private boolean verifyPreloadConfig(@Config int changingConfigurations,
+            @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) {
+        // We allow preloading of resources even if they vary by font scale (which
+        // doesn't impact resource selection) or density (which we handle specially by
+        // simply turning off all preloading), as well as any other configs specified
+        // by the caller.
+        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
+                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
+            String resName;
+            try {
+                resName = getResourceName(resourceId);
+            } catch (NotFoundException e) {
+                resName = "?";
+            }
+            // This should never happen in production, so we should log a
+            // warning even if we're not debugging.
+            Log.w(TAG, "Preloaded " + name + " resource #0x"
+                    + Integer.toHexString(resourceId)
+                    + " (" + resName + ") that varies with configuration!!");
+            return false;
+        }
+        if (TRACE_FOR_PRELOAD) {
+            String resName;
+            try {
+                resName = getResourceName(resourceId);
+            } catch (NotFoundException e) {
+                resName = "?";
+            }
+            Log.w(TAG, "Preloading " + name + " resource #0x"
+                    + Integer.toHexString(resourceId)
+                    + " (" + resName + ")");
+        }
+        return true;
+    }
+
+    /**
+     * Loads a drawable from XML or resources stream.
+     */
+    private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,
+            Resources.Theme theme) {
+        if (value.string == null) {
+            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
+        }
+
+        final String file = value.string.toString();
+
+        if (TRACE_FOR_MISS_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) {
+                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
+                            + ": " + name + " at " + file);
+                }
+            }
+        }
+
+        if (DEBUG_LOAD) {
+            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
+        }
+
+        final Drawable dr;
+
+        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+        try {
+            if (file.endsWith(".xml")) {
+                final XmlResourceParser rp = loadXmlResourceParser(
+                        file, id, value.assetCookie, "drawable");
+                dr = Drawable.createFromXml(wrapper, rp, theme);
+                rp.close();
+            } else {
+                final InputStream is = mAssets.openNonAsset(
+                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
+                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
+                is.close();
+            }
+        } catch (Exception e) {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+            final NotFoundException rnf = new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
+            rnf.initCause(e);
+            throw rnf;
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+
+        return dr;
+    }
+
+    /**
+     * Given the value and id, we can get the XML filename as in value.data, based on that, we
+     * first try to load CSL from the cache. If not found, try to get from the constant state.
+     * Last, parse the XML and generate the CSL.
+     */
+    private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
+            TypedValue value, int id) {
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
+        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
+        if (complexColor != null) {
+            return complexColor;
+        }
+
+        final android.content.res.ConstantState<ComplexColor> factory =
+                sPreloadedComplexColors.get(key);
+
+        if (factory != null) {
+            complexColor = factory.newInstance(wrapper, theme);
+        }
+        if (complexColor == null) {
+            complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
+        }
+
+        if (complexColor != null) {
+            complexColor.setBaseChangingConfigurations(value.changingConfigurations);
+
+            if (mPreloading) {
+                if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
+                        0, value.resourceId, "color")) {
+                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
+                }
+            } else {
+                cache.put(key, theme, complexColor.getConstantState());
+            }
+        }
+        return complexColor;
+    }
+
+    @Nullable
+    ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
+            Resources.Theme theme) {
+        if (TRACE_FOR_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) android.util.Log.d("loadComplexColor", name);
+            }
+        }
+
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+
+        // Handle inline color definitions.
+        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+            return getColorStateListFromInt(value, key);
+        }
+
+        final String file = value.string.toString();
+
+        ComplexColor complexColor;
+        if (file.endsWith(".xml")) {
+            try {
+                complexColor = loadComplexColorFromName(wrapper, theme, value, id);
+            } catch (Exception e) {
+                final NotFoundException rnf = new NotFoundException(
+                        "File " + file + " from complex color resource ID #0x"
+                                + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        } else {
+            throw new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x"
+                            + Integer.toHexString(id) + ": .xml extension required");
+        }
+
+        return complexColor;
+    }
+
+    @Nullable
+    ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
+            Resources.Theme theme)
+            throws NotFoundException {
+        if (TRACE_FOR_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) android.util.Log.d("PreloadColorStateList", name);
+            }
+        }
+
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+
+        // Handle inline color definitions.
+        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+            return getColorStateListFromInt(value, key);
+        }
+
+        ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
+        if (complexColor != null && complexColor instanceof ColorStateList) {
+            return (ColorStateList) complexColor;
+        }
+
+        throw new NotFoundException(
+                "Can't find ColorStateList from drawable resource ID #0x"
+                        + Integer.toHexString(id));
+    }
+
+    @NonNull
+    private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
+        ColorStateList csl;
+        final android.content.res.ConstantState<ComplexColor> factory =
+                sPreloadedComplexColors.get(key);
+        if (factory != null) {
+            return (ColorStateList) factory.newInstance();
+        }
+
+        csl = ColorStateList.valueOf(value.data);
+
+        if (mPreloading) {
+            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                    "color")) {
+                sPreloadedComplexColors.put(key, csl.getConstantState());
+            }
+        }
+
+        return csl;
+    }
+
+    /**
+     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
+     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
+     *
+     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
+     * and selector tag.
+     *
+     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+     */
+    @Nullable
+    private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
+            Resources.Theme theme) {
+        if (value.string == null) {
+            throw new UnsupportedOperationException(
+                    "Can't convert to ComplexColor: type=0x" + value.type);
+        }
+
+        final String file = value.string.toString();
+
+        if (TRACE_FOR_MISS_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) {
+                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
+                            + ": " + name + " at " + file);
+                }
+            }
+        }
+
+        if (DEBUG_LOAD) {
+            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
+        }
+
+        ComplexColor complexColor = null;
+
+        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+        if (file.endsWith(".xml")) {
+            try {
+                final XmlResourceParser parser = loadXmlResourceParser(
+                        file, id, value.assetCookie, "ComplexColor");
+
+                final AttributeSet attrs = Xml.asAttributeSet(parser);
+                int type;
+                while ((type = parser.next()) != XmlPullParser.START_TAG
+                        && type != XmlPullParser.END_DOCUMENT) {
+                    // Seek parser to start tag.
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new XmlPullParserException("No start tag found");
+                }
+
+                final String name = parser.getName();
+                if (name.equals("gradient")) {
+                    complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
+                } else if (name.equals("selector")) {
+                    complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
+                }
+                parser.close();
+            } catch (Exception e) {
+                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+                final NotFoundException rnf = new NotFoundException(
+                        "File " + file + " from ComplexColor resource ID #0x"
+                                + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        } else {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+            throw new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x"
+                            + Integer.toHexString(id) + ": .xml extension required");
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+
+        return complexColor;
+    }
+
+    /**
+     * Loads an XML parser for the specified file.
+     *
+     * @param file the path for the XML file to parse
+     * @param id the resource identifier for the file
+     * @param assetCookie the asset cookie for the file
+     * @param type the type of resource (used for logging)
+     * @return a parser for the specified XML file
+     * @throws NotFoundException if the file could not be loaded
+     */
+    @NonNull
+    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie,
+            @NonNull String type)
+            throws NotFoundException {
+        if (id != 0) {
+            try {
+                synchronized (mCachedXmlBlocks) {
+                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
+                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+                    // First see if this block is in our cache.
+                    final int num = cachedXmlBlockFiles.length;
+                    for (int i = 0; i < num; i++) {
+                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
+                                && cachedXmlBlockFiles[i].equals(file)) {
+                            return cachedXmlBlocks[i].newParser();
+                        }
+                    }
+
+                    // Not in the cache, create a new block and put it at
+                    // the next slot in the cache.
+                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
+                    if (block != null) {
+                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
+                        mLastCachedXmlBlockIndex = pos;
+                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
+                        if (oldBlock != null) {
+                            oldBlock.close();
+                        }
+                        cachedXmlBlockCookies[pos] = assetCookie;
+                        cachedXmlBlockFiles[pos] = file;
+                        cachedXmlBlocks[pos] = block;
+                        return block.newParser();
+                    }
+                }
+            } catch (Exception e) {
+                final NotFoundException rnf = new NotFoundException("File " + file
+                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        }
+
+        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
+                + Integer.toHexString(id));
+    }
+
+    /**
+     * Start preloading of resource data using this Resources object.  Only
+     * for use by the zygote process for loading common system resources.
+     * {@hide}
+     */
+    public final void startPreloading() {
+        synchronized (sSync) {
+            if (sPreloaded) {
+                throw new IllegalStateException("Resources already preloaded");
+            }
+            sPreloaded = true;
+            mPreloading = true;
+            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
+            updateConfiguration(null, null, null);
+        }
+    }
+
+    /**
+     * Called by zygote when it is done preloading resources, to change back
+     * to normal Resources operation.
+     */
+    void finishPreloading() {
+        if (mPreloading) {
+            mPreloading = false;
+            flushLayoutCache();
+        }
+    }
+
+    LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
+        return sPreloadedDrawables[0];
+    }
+
+    ThemeImpl newThemeImpl() {
+        return new ThemeImpl();
+    }
+
+    /**
+     * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey.
+     */
+    ThemeImpl newThemeImpl(Resources.ThemeKey key) {
+        ThemeImpl impl = new ThemeImpl();
+        impl.mKey.setTo(key);
+        impl.rebase();
+        return impl;
+    }
+
+    public class ThemeImpl {
+        /**
+         * Unique key for the series of styles applied to this theme.
+         */
+        private final Resources.ThemeKey mKey = new Resources.ThemeKey();
+
+        @SuppressWarnings("hiding")
+        private final AssetManager mAssets;
+        private final long mTheme;
+
+        /**
+         * Resource identifier for the theme.
+         */
+        private int mThemeResId = 0;
+
+        /*package*/ ThemeImpl() {
+            mAssets = ResourcesImpl.this.mAssets;
+            mTheme = mAssets.createTheme();
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            super.finalize();
+            mAssets.releaseTheme(mTheme);
+        }
+
+        /*package*/ Resources.ThemeKey getKey() {
+            return mKey;
+        }
+
+        /*package*/ long getNativeTheme() {
+            return mTheme;
+        }
+
+        /*package*/ int getAppliedStyleResId() {
+            return mThemeResId;
+        }
+
+        void applyStyle(int resId, boolean force) {
+            synchronized (mKey) {
+                AssetManager.applyThemeStyle(mTheme, resId, force);
+
+                mThemeResId = resId;
+                mKey.append(resId, force);
+            }
+        }
+
+        void setTo(ThemeImpl other) {
+            synchronized (mKey) {
+                synchronized (other.mKey) {
+                    AssetManager.copyTheme(mTheme, other.mTheme);
+
+                    mThemeResId = other.mThemeResId;
+                    mKey.setTo(other.getKey());
+                }
+            }
+        }
+
+        @NonNull
+        TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
+                AttributeSet set,
+                @StyleableRes int[] attrs,
+                @AttrRes int defStyleAttr,
+                @StyleRes int defStyleRes) {
+            synchronized (mKey) {
+                final int len = attrs.length;
+                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
+
+                // XXX note that for now we only work with compiled XML files.
+                // To support generic XML files we will need to manually parse
+                // out the attributes from the XML file (applying type information
+                // contained in the resources and such).
+                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
+                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+                        parser != null ? parser.mParseState : 0,
+                        attrs, array.mData, array.mIndices);
+                array.mTheme = wrapper;
+                array.mXml = parser;
+
+                return array;
+            }
+        }
+
+        @NonNull
+        TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
+                @NonNull int[] values,
+                @NonNull int[] attrs) {
+            synchronized (mKey) {
+                final int len = attrs.length;
+                if (values == null || len != values.length) {
+                    throw new IllegalArgumentException(
+                            "Base attribute values must the same length as attrs");
+                }
+
+                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
+                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+                array.mTheme = wrapper;
+                array.mXml = null;
+                return array;
+            }
+        }
+
+        boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
+            synchronized (mKey) {
+                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
+            }
+        }
+
+        int[] getAllAttributes() {
+            return mAssets.getStyleAttributes(getAppliedStyleResId());
+        }
+
+        @Config int getChangingConfigurations() {
+            synchronized (mKey) {
+                final int nativeChangingConfig =
+                        AssetManager.getThemeChangingConfigurations(mTheme);
+                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
+            }
+        }
+
+        public void dump(int priority, String tag, String prefix) {
+            synchronized (mKey) {
+                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+            }
+        }
+
+        String[] getTheme() {
+            synchronized (mKey) {
+                final int N = mKey.mCount;
+                final String[] themes = new String[N * 2];
+                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
+                    final int resId = mKey.mResId[j];
+                    final boolean forced = mKey.mForce[j];
+                    try {
+                        themes[i] = getResourceName(resId);
+                    } catch (NotFoundException e) {
+                        themes[i] = Integer.toHexString(i);
+                    }
+                    themes[i + 1] = forced ? "forced" : "not forced";
+                }
+                return themes;
+            }
+        }
+
+        /**
+         * Rebases the theme against the parent Resource object's current
+         * configuration by re-applying the styles passed to
+         * {@link #applyStyle(int, boolean)}.
+         */
+        void rebase() {
+            synchronized (mKey) {
+                AssetManager.clearTheme(mTheme);
+
+                // Reapply the same styles in the same order.
+                for (int i = 0; i < mKey.mCount; i++) {
+                    final int resId = mKey.mResId[i];
+                    final boolean force = mKey.mForce[i];
+                    AssetManager.applyThemeStyle(mTheme, resId, force);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 2620571..e894492 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -17,32 +17,59 @@
 package android.content.res;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 /** @hide */
 public final class ResourcesKey {
-    private final String mResDir;
-    private final float mScale;
-    private final int mHash;
+    @Nullable
+    public final String mResDir;
+
+    @Nullable
+    public final String[] mSplitResDirs;
+
+    @Nullable
+    public final String[] mOverlayDirs;
+
+    @Nullable
+    public final String[] mLibDirs;
 
     public final int mDisplayId;
+
     @NonNull
     public final Configuration mOverrideConfiguration;
 
-    public ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
-            float scale) {
+    @NonNull
+    public final CompatibilityInfo mCompatInfo;
+
+    private final int mHash;
+
+    public ResourcesKey(@Nullable String resDir,
+                        @Nullable String[] splitResDirs,
+                        @Nullable String[] overlayDirs,
+                        @Nullable String[] libDirs,
+                        int displayId,
+                        @Nullable Configuration overrideConfig,
+                        @Nullable CompatibilityInfo compatInfo) {
         mResDir = resDir;
+        mSplitResDirs = splitResDirs;
+        mOverlayDirs = overlayDirs;
+        mLibDirs = libDirs;
         mDisplayId = displayId;
-        mOverrideConfiguration = overrideConfiguration != null
-                ? overrideConfiguration : Configuration.EMPTY;
-        mScale = scale;
+        mOverrideConfiguration = overrideConfig != null ? overrideConfig : Configuration.EMPTY;
+        mCompatInfo = compatInfo != null ? compatInfo : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
 
         int hash = 17;
-        hash = 31 * hash + (mResDir == null ? 0 : mResDir.hashCode());
+        hash = 31 * hash + Objects.hashCode(mResDir);
+        hash = 31 * hash + Arrays.hashCode(mSplitResDirs);
+        hash = 31 * hash + Arrays.hashCode(mOverlayDirs);
+        hash = 31 * hash + Arrays.hashCode(mLibDirs);
         hash = 31 * hash + mDisplayId;
-        hash = 31 * hash + mOverrideConfiguration.hashCode();
-        hash = 31 * hash + Float.floatToIntBits(mScale);
+        hash = 31 * hash + Objects.hashCode(mOverrideConfiguration);
+        hash = 31 * hash + Objects.hashCode(mCompatInfo);
         mHash = hash;
     }
 
@@ -60,18 +87,32 @@
         if (!(obj instanceof ResourcesKey)) {
             return false;
         }
+
         ResourcesKey peer = (ResourcesKey) obj;
+        if (mHash != peer.mHash) {
+            // If the hashes don't match, the objects can't match.
+            return false;
+        }
 
         if (!Objects.equals(mResDir, peer.mResDir)) {
             return false;
         }
+        if (!Arrays.equals(mSplitResDirs, peer.mSplitResDirs)) {
+            return false;
+        }
+        if (!Arrays.equals(mOverlayDirs, peer.mOverlayDirs)) {
+            return false;
+        }
+        if (!Arrays.equals(mLibDirs, peer.mLibDirs)) {
+            return false;
+        }
         if (mDisplayId != peer.mDisplayId) {
             return false;
         }
-        if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
+        if (!Objects.equals(mOverrideConfiguration, peer.mOverrideConfiguration)) {
             return false;
         }
-        if (mScale != peer.mScale) {
+        if (!Objects.equals(mCompatInfo, peer.mCompatInfo)) {
             return false;
         }
         return true;
@@ -79,6 +120,29 @@
 
     @Override
     public String toString() {
-        return Integer.toHexString(mHash);
+        StringBuilder builder = new StringBuilder().append("ResourcesKey{");
+        builder.append(" mHash=").append(Integer.toHexString(mHash));
+        builder.append(" mResDir=").append(mResDir);
+        builder.append(" mSplitDirs=[");
+        if (mSplitResDirs != null) {
+            builder.append(TextUtils.join(",", mSplitResDirs));
+        }
+        builder.append("]");
+        builder.append(" mOverlayDirs=[");
+        if (mOverlayDirs != null) {
+            builder.append(TextUtils.join(",", mOverlayDirs));
+        }
+        builder.append("]");
+        builder.append(" mLibDirs=[");
+        if (mLibDirs != null) {
+            builder.append(TextUtils.join(",", mLibDirs));
+        }
+        builder.append("]");
+        builder.append(" mDisplayId=").append(mDisplayId);
+        builder.append(" mOverrideConfig=").append(Configuration.resourceQualifierString(
+                mOverrideConfiguration));
+        builder.append(" mCompatInfo=").append(mCompatInfo);
+        builder.append("}");
+        return builder.toString();
     }
 }
diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java
index 9a2d06147..f1b1e74 100644
--- a/core/java/android/content/res/ThemedResourceCache.java
+++ b/core/java/android/content/res/ThemedResourceCache.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources.Theme;
 import android.content.res.Resources.ThemeKey;
 import android.util.LongSparseArray;
@@ -115,7 +116,7 @@
      *
      * @param configChanges a bitmask of configuration changes
      */
-    public void onConfigurationChange(int configChanges) {
+    public void onConfigurationChange(@Config int configChanges) {
         prune(configChanges);
     }
 
@@ -192,7 +193,7 @@
      *                      simply prune missing weak references
      * @return {@code true} if the cache is completely empty after pruning
      */
-    private boolean prune(int configChanges) {
+    private boolean prune(@Config int configChanges) {
         synchronized (this) {
             if (mThemedEntries != null) {
                 for (int i = mThemedEntries.size() - 1; i >= 0; i--) {
@@ -211,7 +212,7 @@
     }
 
     private boolean pruneEntriesLocked(@Nullable LongSparseArray<WeakReference<T>> entries,
-            int configChanges) {
+            @Config int configChanges) {
         if (entries == null) {
             return true;
         }
@@ -226,7 +227,7 @@
         return entries.size() == 0;
     }
 
-    private boolean pruneEntryLocked(@Nullable T entry, int configChanges) {
+    private boolean pruneEntryLocked(@Nullable T entry, @Config int configChanges) {
         return entry == null || (configChanges != 0
                 && shouldInvalidateEntry(entry, configChanges));
     }
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 6067577..92134ee 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -20,6 +20,8 @@
 import android.annotation.ColorInt;
 import android.annotation.Nullable;
 import android.annotation.StyleableRes;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.Config;
 import android.graphics.drawable.Drawable;
 import android.os.StrictMode;
 import android.util.AttributeSet;
@@ -252,7 +254,8 @@
      * @throws RuntimeException if the TypedArray has already been recycled.
      * @hide
      */
-    public String getNonConfigurationString(@StyleableRes int index, int allowedChangingConfigs) {
+    public String getNonConfigurationString(@StyleableRes int index,
+            @Config int allowedChangingConfigs) {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
@@ -260,7 +263,9 @@
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
-        if ((data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS]&~allowedChangingConfigs) != 0) {
+        final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
+                data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
+        if ((changingConfigs & ~allowedChangingConfigs) != 0) {
             return null;
         }
         if (type == TypedValue.TYPE_NULL) {
@@ -426,7 +431,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
+        final int attrIndex = index;
         index *= AssetManager.STYLE_NUM_ENTRIES;
+
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
@@ -444,13 +451,13 @@
             return defValue;
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
-            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            getValueAt(index, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index + ": " + value);
+                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
         }
 
-        throw new UnsupportedOperationException("Can't convert to color: type=0x"
-                + Integer.toHexString(type));
+        throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+                + " to color: type=0x" + Integer.toHexString(type));
     }
 
     /**
@@ -468,6 +475,7 @@
      *         been recycled.
      * @throws UnsupportedOperationException if the attribute is defined but is
      *         not an integer color, color state list or GradientColor.
+     * @hide
      */
     @Nullable
     public ComplexColor getComplexColor(@StyleableRes int index) {
@@ -541,7 +549,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
+        final int attrIndex = index;
         index *= AssetManager.STYLE_NUM_ENTRIES;
+
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
@@ -551,13 +561,13 @@
             return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
-            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            getValueAt(index, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index + ": " + value);
+                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
         }
 
-        throw new UnsupportedOperationException("Can't convert to integer: type=0x"
-                + Integer.toHexString(type));
+        throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+                + " to integer: type=0x" + Integer.toHexString(type));
     }
 
     /**
@@ -587,7 +597,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
+        final int attrIndex = index;
         index *= AssetManager.STYLE_NUM_ENTRIES;
+
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
@@ -597,13 +609,13 @@
                     data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
-            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            getValueAt(index, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index + ": " + value);
+                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
         }
 
-        throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
-                + Integer.toHexString(type));
+        throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+                + " to dimension: type=0x" + Integer.toHexString(type));
     }
 
     /**
@@ -634,7 +646,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
+        final int attrIndex = index;
         index *= AssetManager.STYLE_NUM_ENTRIES;
+
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
@@ -644,13 +658,13 @@
                     data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
-            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            getValueAt(index, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index + ": " + value);
+                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
         }
 
-        throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
-                + Integer.toHexString(type));
+        throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+                + " to dimension: type=0x" + Integer.toHexString(type));
     }
 
     /**
@@ -682,7 +696,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
+        final int attrIndex = index;
         index *= AssetManager.STYLE_NUM_ENTRIES;
+
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
@@ -692,13 +708,13 @@
                 data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
-            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            getValueAt(index, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index + ": " + value);
+                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
         }
 
-        throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
-                + Integer.toHexString(type));
+        throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+                + " to dimension: type=0x" + Integer.toHexString(type));
     }
 
     /**
@@ -724,7 +740,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
+        final int attrIndex = index;
         index *= AssetManager.STYLE_NUM_ENTRIES;
+
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         if (type >= TypedValue.TYPE_FIRST_INT
@@ -735,9 +753,9 @@
                 data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
-            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            getValueAt(index, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index + ": " + value);
+                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
         }
 
         throw new UnsupportedOperationException(getPositionDescription()
@@ -800,7 +818,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
+        final int attrIndex = index;
         index *= AssetManager.STYLE_NUM_ENTRIES;
+
         final int[] data = mData;
         final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
@@ -810,13 +830,13 @@
                 data[index+AssetManager.STYLE_DATA], base, pbase);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
-            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            getValueAt(index, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index + ": " + value);
+                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
         }
 
-        throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
-                + Integer.toHexString(type));
+        throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+                + " to fraction: type=0x" + Integer.toHexString(type));
     }
 
     /**
@@ -1141,12 +1161,12 @@
      * @throws RuntimeException if the TypedArray has already been recycled.
      * @see android.content.pm.ActivityInfo
      */
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        int changingConfig = 0;
+        @Config int changingConfig = 0;
 
         final int[] data = mData;
         final int N = length();
@@ -1156,7 +1176,8 @@
             if (type == TypedValue.TYPE_NULL) {
                 continue;
             }
-            changingConfig |= data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS];
+            changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
+                    data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
         }
         return changingConfig;
     }
@@ -1171,7 +1192,8 @@
         outValue.data = data[index+AssetManager.STYLE_DATA];
         outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
         outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
-        outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS];
+        outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+                data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
         outValue.density = data[index+AssetManager.STYLE_DENSITY];
         outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
         return true;
@@ -1192,8 +1214,8 @@
 
     /*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {
         mResources = resources;
-        mMetrics = mResources.mMetrics;
-        mAssets = mResources.mAssets;
+        mMetrics = mResources.getDisplayMetrics();
+        mAssets = mResources.getAssets();
         mData = data;
         mIndices = indices;
         mLength = len;
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 2dce425..b2288fc 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -136,12 +136,14 @@
         }
         String vmFlags = "CheckJNI="
             + (vmRuntime.isCheckJniEnabled() ? "true" : "false");
+        boolean isNativeDebuggable = vmRuntime.isNativeDebuggable();
 
         ByteBuffer out = ByteBuffer.allocate(28
                             + vmIdent.length() * 2
                             + appName.length() * 2
                             + instructionSetDescription.length() * 2
-                            + vmFlags.length() * 2);
+                            + vmFlags.length() * 2
+                            + 1);
         out.order(ChunkHandler.CHUNK_ORDER);
         out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
         out.putInt(android.os.Process.myPid());
@@ -154,6 +156,7 @@
         putString(out, instructionSetDescription);
         out.putInt(vmFlags.length());
         putString(out, vmFlags);
+        out.put((byte)(isNativeDebuggable ? 1 : 0));
 
         Chunk reply = new Chunk(CHUNK_HELO, out);
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 02d4e59..acf0677 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -19,6 +19,7 @@
 import android.app.ActivityThread;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.job.JobInfo;
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.Point;
@@ -75,7 +76,7 @@
  * <li>If necessary, modify the returned {@link Camera.Parameters} object and call
  * {@link #setParameters(Camera.Parameters)}.
  *
- * <li>If desired, call {@link #setDisplayOrientation(int)}.
+ * <li>Call {@link #setDisplayOrientation(int)} to ensure correct orientation of preview.
  *
  * <li><b>Important</b>: Pass a fully initialized {@link SurfaceHolder} to
  * {@link #setPreviewDisplay(SurfaceHolder)}.  Without a surface, the camera
@@ -177,19 +178,27 @@
     private static final int NO_ERROR = 0;
 
     /**
+     * @deprecated This broadcast is no longer delivered by the system; use
+     * {@link android.app.job.JobInfo.Builder JobInfo.Builder}.{@link android.app.job.JobInfo.Builder#addTriggerContentUri}
+     * instead.
      * Broadcast Action:  A new picture is taken by the camera, and the entry of
      * the picture has been added to the media store.
      * {@link android.content.Intent#getData} is URI of the picture.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @Deprecated
     public static final String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
 
     /**
+     * @deprecated This broadcast is no longer delivered by the system; use
+     * {@link android.app.job.JobInfo.Builder JobInfo.Builder}.{@link android.app.job.JobInfo.Builder#addTriggerContentUri}
+     * instead.
      * Broadcast Action:  A new video is recorded by the camera, and the entry
      * of the video has been added to the media store.
      * {@link android.content.Intent#getData} is URI of the video.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @Deprecated
     public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
 
     /**
@@ -1502,9 +1511,15 @@
      * <p>Starting from API level 14, this method can be called when preview is
      * active.
      *
+     * <p><b>Note: </b>Before API level 24, the default value for orientation is 0. Starting in
+     * API level 24, the default orientation will be such that applications in forced-landscape mode
+     * will have correct preview orientation, which may be either a default of 0 or
+     * 180. Applications that operate in portrait mode or allow for changing orientation must still
+     * call this method after each orientation change to ensure correct preview display in all
+     * cases.</p>
+     *
      * @param degrees the angle that the picture will be rotated clockwise.
-     *                Valid values are 0, 90, 180, and 270. The starting
-     *                position is 0 (landscape).
+     *                Valid values are 0, 90, 180, and 270.
      * @see #setPreviewDisplay(SurfaceHolder)
      */
     public native final void setDisplayOrientation(int degrees);
diff --git a/core/java/android/hardware/CameraInfo.aidl b/core/java/android/hardware/CameraInfo.aidl
deleted file mode 100644
index e21e694..0000000
--- a/core/java/android/hardware/CameraInfo.aidl
+++ /dev/null
@@ -1,20 +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;
-
-/** @hide */
-parcelable CameraInfo;
diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java
index 6d29212..9fa1c3f 100644
--- a/core/java/android/hardware/ConsumerIrManager.java
+++ b/core/java/android/hardware/ConsumerIrManager.java
@@ -60,8 +60,8 @@
         try {
             return mService.hasIrEmitter();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -84,7 +84,7 @@
         try {
             mService.transmit(mPackageName, carrierFrequency, pattern);
         } catch (RemoteException e) {
-            Log.w(TAG, "failed to transmit.", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -149,8 +149,7 @@
             }
             return range;
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
-
 }
diff --git a/core/java/android/hardware/ICamera.aidl b/core/java/android/hardware/ICamera.aidl
deleted file mode 100644
index d4f64f8..0000000
--- a/core/java/android/hardware/ICamera.aidl
+++ /dev/null
@@ -1,26 +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;
-
-/** @hide */
-interface ICamera
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICamera.h
-     */
-    void disconnect();
-}
diff --git a/core/java/android/hardware/ICameraClient.aidl b/core/java/android/hardware/ICameraClient.aidl
deleted file mode 100644
index d7877b4..0000000
--- a/core/java/android/hardware/ICameraClient.aidl
+++ /dev/null
@@ -1,26 +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;
-
-/** @hide */
-interface ICameraClient
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICameraClient.h
-     */
-    // TODO: consider implementing this.
-}
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
deleted file mode 100644
index 0b165cd..0000000
--- a/core/java/android/hardware/ICameraService.aidl
+++ /dev/null
@@ -1,89 +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;
-
-import android.hardware.ICamera;
-import android.hardware.ICameraClient;
-import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.ICameraDeviceCallbacks;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.utils.BinderHolder;
-import android.hardware.ICameraServiceListener;
-import android.hardware.CameraInfo;
-
-/**
- * Binder interface for the native camera service running in mediaserver.
- *
- * @hide
- */
-interface ICameraService
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICameraService.h
-     */
-    int getNumberOfCameras(int type);
-
-    // rest of 'int' return values in this file are actually status_t
-
-    int getCameraInfo(int cameraId, out CameraInfo info);
-
-    int connect(ICameraClient client, int cameraId,
-                    String opPackageName,
-                    int clientUid,
-                    // Container for an ICamera object
-                    out BinderHolder device);
-
-    int connectDevice(ICameraDeviceCallbacks callbacks, int cameraId,
-                              String opPackageName,
-                              int clientUid,
-                              // Container for an ICameraDeviceUser object
-                              out BinderHolder device);
-
-    int addListener(ICameraServiceListener listener);
-    int removeListener(ICameraServiceListener listener);
-
-    int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
-
-    /**
-     * The java stubs for this method are not intended to be used.  Please use
-     * the native stub in frameworks/av/include/camera/ICameraService.h instead.
-     * The BinderHolder output is being used as a placeholder, and will not be
-     * well-formatted in the generated java method.
-     */
-    int getCameraVendorTagDescriptor(out BinderHolder desc);
-
-    // Writes the camera1 parameters into a single-element array.
-    int getLegacyParameters(int cameraId, out String[] parameters);
-    // Determines if a particular API version is supported; see ICameraService.h for version defines
-    int supportsCameraApi(int cameraId, int apiVersion);
-
-    int connectLegacy(ICameraClient client, int cameraId,
-                    int halVersion,
-                    String opPackageName,
-                    int clientUid,
-                    // Container for an ICamera object
-                    out BinderHolder device);
-
-    int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
-
-    /**
-     * Notify the camera service of a system event.  Should only be called from system_server.
-     *
-     * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
-     */
-    oneway void notifySystemEvent(int eventId, in int[] args);
-}
diff --git a/core/java/android/hardware/ICameraServiceListener.aidl b/core/java/android/hardware/ICameraServiceListener.aidl
deleted file mode 100644
index 49278b6..0000000
--- a/core/java/android/hardware/ICameraServiceListener.aidl
+++ /dev/null
@@ -1,28 +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;
-
-/** @hide */
-interface ICameraServiceListener
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICameraServiceListener.h
-     */
-    void onStatusChanged(int status, int cameraId);
-
-    void onTorchStatusChanged(int status, String cameraId);
-}
diff --git a/core/java/android/hardware/ICameraServiceProxy.aidl b/core/java/android/hardware/ICameraServiceProxy.aidl
deleted file mode 100644
index 0e654d5..0000000
--- a/core/java/android/hardware/ICameraServiceProxy.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-/**
- * Binder interface for the camera service proxy running in system_server.
- *
- * Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h
- *
- * @hide
- */
-interface ICameraServiceProxy
-{
-    /**
-     * Ping the service proxy to update the valid users for the camera service.
-     */
-    oneway void pingForUserUpdate();
-
-    /**
-     * Update the status of a camera device
-     */
-     oneway void notifyCameraState(String cameraId, int newCameraState);
-}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 841e5b0..cc82eb6 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -186,7 +186,7 @@
      * @see #TYPE_LINEAR_ACCELERATION
      */
     public static final String STRING_TYPE_LINEAR_ACCELERATION =
-        "android.sensor.linear_acceleration";
+            "android.sensor.linear_acceleration";
 
     /**
      * A constant describing a rotation vector sensor type.
@@ -229,7 +229,7 @@
      * @see #TYPE_AMBIENT_TEMPERATURE
      */
     public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
-        "android.sensor.ambient_temperature";
+            "android.sensor.ambient_temperature";
 
     /**
      * A constant describing an uncalibrated magnetic field sensor type.
@@ -254,7 +254,7 @@
      * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
      */
     public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
-        "android.sensor.magnetic_field_uncalibrated";
+            "android.sensor.magnetic_field_uncalibrated";
 
     /**
      * A constant describing an uncalibrated rotation vector sensor type.
@@ -280,7 +280,7 @@
      * @see #TYPE_GAME_ROTATION_VECTOR
      */
     public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
-        "android.sensor.game_rotation_vector";
+            "android.sensor.game_rotation_vector";
 
     /**
      * A constant describing an uncalibrated gyroscope sensor type.
@@ -302,7 +302,7 @@
      * @see #TYPE_GYROSCOPE_UNCALIBRATED
      */
     public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
-        "android.sensor.gyroscope_uncalibrated";
+            "android.sensor.gyroscope_uncalibrated";
 
     /**
      * A constant describing a significant motion trigger sensor.
@@ -324,7 +324,7 @@
      * @see #TYPE_SIGNIFICANT_MOTION
      */
     public static final String STRING_TYPE_SIGNIFICANT_MOTION =
-        "android.sensor.significant_motion";
+            "android.sensor.significant_motion";
 
     /**
      * A constant describing a step detector sensor.
@@ -391,7 +391,7 @@
      * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
      */
     public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
-        "android.sensor.geomagnetic_rotation_vector";
+            "android.sensor.geomagnetic_rotation_vector";
 
     /**
      * A constant describing a heart rate monitor.
@@ -431,7 +431,7 @@
      * A constant string describing a wake up tilt detector sensor type.
      *
      * @hide
-     * @see #TYPE_WAKE_UP_TILT_DETECTOR
+     * @see #TYPE_TILT_DETECTOR
      */
     public static final String SENSOR_STRING_TYPE_TILT_DETECTOR =
             "android.sensor.tilt_detector";
@@ -495,7 +495,7 @@
      */
     public static final String STRING_TYPE_GLANCE_GESTURE = "android.sensor.glance_gesture";
 
-     /**
+    /**
      * A constant describing a pick up sensor.
      *
      * A sensor of this type triggers when the device is picked up regardless of wherever it was
@@ -514,7 +514,7 @@
      */
     public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
 
-     /**
+    /**
      * A constant describing a wrist tilt gesture sensor.
      *
      * A sensor of this type triggers when the device face is tilted towards the user.
@@ -553,7 +553,7 @@
      */
     public static final String STRING_TYPE_DEVICE_ORIENTATION = "android.sensor.device_orientation";
 
-     /**
+    /**
      * A constant describing a pose sensor with 6 degrees of freedom.
      *
      * Similar to {@link #TYPE_ROTATION_VECTOR}, with additional delta
@@ -578,7 +578,7 @@
      */
     public static final String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
 
-     /**
+    /**
      * A constant describing a stationary detect sensor.
      *
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -593,7 +593,7 @@
      */
     public static final String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
 
-     /**
+    /**
      * A constant describing a motion detect sensor.
      *
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -608,7 +608,7 @@
      */
     public static final String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
 
-     /**
+    /**
      * A constant describing a motion detect sensor.
      *
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -652,6 +652,14 @@
 
     public static final int TYPE_ALL = -1;
 
+    /**
+     * The lowest sensor type vendor defined sensors can use.
+     *
+     * All vendor sensor types are greater than or equal to this constant.
+     *
+     */
+    public static final int TYPE_DEVICE_PRIVATE_BASE = 0x10000;
+
     // If this flag is set, the sensor defined as a wake up sensor. This field and REPORTING_MODE_*
     // constants are defined as flags in sensors.h. Modify at both places if needed.
     private static final int SENSOR_FLAG_WAKE_UP_SENSOR = 1;
@@ -698,6 +706,14 @@
     private static final int DATA_INJECTION_MASK = 0x10;
     private static final int DATA_INJECTION_SHIFT = 4;
 
+    // MASK for dynamic sensor (sensor that added during runtime), bit 6.
+    private static final int DYNAMIC_SENSOR_MASK = 0x20;
+    private static final int DYNAMIC_SENSOR_SHIFT = 5;
+
+    // MASK for indication bit of sensor additional information support (bit 7).
+    private static final int ADDITIONAL_INFO_MASK = 0x40;
+    private static final int ADDITIONAL_INFO_SHIFT = 6;
+
     // TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
 
     // Note: This needs to be updated, whenever a new sensor is added.
@@ -879,13 +895,37 @@
     }
 
     /**
-     * @return The type of this sensor as a string.
+     * @return The UUID of the sensor. If the sensor does not support UUID, the returned value will
+     * be an all zero UUID; if the sensor's combination of type and name is guaranteed to be unique
+     * in system, the return value will be an all "F" UUID.
+     *
+     * @hide
      */
+    @SystemApi
     public UUID getUuid() {
         return mUuid;
     }
 
     /**
+     * @return The unique id of sensor. Return value of 0 means this sensor does not support UUID;
+     * return value of -1 means this sensor can be uniquely identified in system by combination of
+     * its type and name.
+     */
+    public int getId() {
+        if (mUuid == ALL_0_UUID) {
+            return 0;
+        } else if (mUuid == ALL_F_UUID) {
+            return -1;
+        } else {
+            int id = Math.abs(mUuid.hashCode()) + 1;
+            if (id <= 0) { // catch corner case when hash is Integer.MIN_VALUE and Integer.MAX_VALUE
+                id = 1;
+            }
+            return id;
+        }
+    }
+
+    /**
      * @hide
      * @return The permission required to access this sensor. If empty, no permission is required.
      */
@@ -953,6 +993,26 @@
     }
 
     /**
+     * Returns true if the sensor is a dynamic sensor.
+     *
+     * @return <code>true</code> if the sensor is a dynamic sensor (sensor added at runtime).
+     * @see SensorManager.DynamicSensorCallback
+     */
+    public boolean isDynamicSensor() {
+        return (mFlags & DYNAMIC_SENSOR_MASK) != 0;
+    }
+
+    /**
+     * Returns true if the sensor supports sensor additional information API
+     *
+     * @return <code>true</code> if the sensor supports sensor additional information API
+     * @see SensorAdditionalInfo
+     */
+    public boolean isAdditionalInfoSupported() {
+        return (mFlags & ADDITIONAL_INFO_MASK) != 0;
+    }
+
+    /**
      * Returns true if the sensor supports data injection when the
      * HAL is set to data injection mode.
      *
@@ -978,6 +1038,10 @@
                 + ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
     }
 
+    //special UUID hash constant
+    private final static UUID ALL_0_UUID = new UUID(0,0);
+    private final static UUID ALL_F_UUID = new UUID(~0L, ~0L);
+
     /**
      * Sets the Type associated with the sensor.
      * NOTE: to be used only by native bindings in SensorManager.
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 8e5b8a3..572a287 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -27,7 +27,7 @@
  * android.hardware.SensorEventCallback#onSensorAdditionalInfo onSensorAdditionalInfo}.
  *
  * @see SensorManager
- * @see SensorEventListener3
+ * @see SensorEventCallback
  * @see Sensor
  *
  */
@@ -106,7 +106,7 @@
      * such as accelerometer, gyro, etc.
      *
      * Payload:
-     *     floatValues[0..11]: First 3 rows of a homogenous matrix in row major order that captures
+     *     floatValues[0..11]: First 3 rows of a homogeneous matrix in row major order that captures
      *     any linear transformation, including rotation, scaling, shear, shift.
      */
     public static final int TYPE_VEC3_CALIBRATION = 0x10002;
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 35c96f7..0d96b8e 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -18,7 +18,7 @@
 
 /**
  * This class represents a {@link android.hardware.Sensor Sensor} event and
- * holds informations such as the sensor's type, the time-stamp, accuracy and of
+ * holds information such as the sensor's type, the time-stamp, accuracy and of
  * course the sensor's {@link SensorEvent#values data}.
  *
  * <p>
@@ -163,7 +163,7 @@
      * </ul>
      * <p>
      * Typically the output of the gyroscope is integrated over time to
-     * calculate a rotation describing the change of angles over the timestep,
+     * calculate a rotation describing the change of angles over the time step,
      * for example:
      * </p>
      *
@@ -173,7 +173,7 @@
      *     private float timestamp;
      *
      *     public void onSensorChanged(SensorEvent event) {
-     *          // This timestep's delta rotation to be multiplied by the current rotation
+     *          // This time step's delta rotation to be multiplied by the current rotation
      *          // after computing it from the gyro sample data.
      *          if (timestamp != 0) {
      *              final float dT = (event.timestamp - timestamp) * NS2S;
@@ -192,8 +192,8 @@
      *                  axisZ /= omegaMagnitude;
      *              }
      *
-     *              // Integrate around this axis with the angular speed by the timestep
-     *              // in order to get a delta rotation from this sample over the timestep
+     *              // Integrate around this axis with the angular speed by the time step
+     *              // in order to get a delta rotation from this sample over the time step
      *              // We will convert this axis-angle representation of the delta rotation
      *              // into a quaternion before turning it into the rotation matrix.
      *              float thetaOverTwo = omegaMagnitude * dT / 2.0f;
@@ -433,9 +433,9 @@
      * Each field is a component of the estimated hard iron calibration.
      * The values are in micro-Tesla (uT).
      * </p>
-     * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanenet
+     * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanent
      * magnets on the device.
-     * Soft iron - These distortions arise due to the interaction with the earth's magentic
+     * Soft iron - These distortions arise due to the interaction with the earth's magnetic
      * field.
      * </p>
      * <h4> {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR}:</h4>
@@ -508,14 +508,14 @@
      *
      *
      * <ul>
-     *  <li> values[0]: x*sin(&#952/2) </li>
-     *  <li> values[1]: y*sin(&#952/2) </li>
-     *  <li> values[2]: z*sin(&#952/2) </li>
-     *  <li> values[3]: cos(&#952/2)   </li>
+     * <li> values[0]: x*sin(&#952/2) </li>
+     * <li> values[1]: y*sin(&#952/2) </li>
+     * <li> values[2]: z*sin(&#952/2) </li>
+     * <li> values[3]: cos(&#952/2)   </li>
      *
      *
      * <li> values[4]: Translation along x axis from an arbitrary origin. </li>
-     * li> values[5]: Translation along y axis from an arbitrary origin. </li>
+     * <li> values[5]: Translation along y axis from an arbitrary origin. </li>
      * <li> values[6]: Translation along z axis from an arbitrary origin. </li>
      *
      * <li> values[7]:  Delta quaternion rotation x*sin(&#952/2) </li>
diff --git a/core/java/android/hardware/SensorEventListener.java b/core/java/android/hardware/SensorEventListener.java
index 0d859fb..0c059ba 100644
--- a/core/java/android/hardware/SensorEventListener.java
+++ b/core/java/android/hardware/SensorEventListener.java
@@ -18,28 +18,33 @@
 
 /**
  * Used for receiving notifications from the SensorManager when
- * sensor values have changed.
+ * there is new sensor data.
  */
 public interface SensorEventListener {
 
     /**
-     * Called when sensor values have changed.
+     * Called when there is a new sensor event.  Note that "on changed"
+     * is somewhat of a misnomer, as this will also be called if we have a
+     * new reading from a sensor with the exact same sensor values (but a
+     * newer timestamp).
+     *
      * <p>See {@link android.hardware.SensorManager SensorManager}
      * for details on possible sensor types.
      * <p>See also {@link android.hardware.SensorEvent SensorEvent}.
-     * 
+     *
      * <p><b>NOTE:</b> The application doesn't own the
      * {@link android.hardware.SensorEvent event}
      * object passed as a parameter and therefore cannot hold on to it.
      * The object may be part of an internal pool and may be reused by
      * the framework.
      *
-     * @param event the {@link android.hardware.SensorEvent SensorEvent}. 
+     * @param event the {@link android.hardware.SensorEvent SensorEvent}.
      */
     public void onSensorChanged(SensorEvent event);
 
     /**
-     * Called when the accuracy of the registered sensor has changed.
+     * Called when the accuracy of the registered sensor has changed.  Unlike
+     * onSensorChanged(), this is only called when this accuracy value changes.
      *
      * <p>See the SENSOR_STATUS_* constants in
      * {@link android.hardware.SensorManager SensorManager} for details.
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index f0b17c30..a20307a 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -46,7 +46,7 @@
  * is an example of a trigger sensor.
  * </p>
  * <pre class="prettyprint">
- * public class SensorActivity extends Activity, implements SensorEventListener {
+ * public class SensorActivity extends Activity implements SensorEventListener {
  *     private final SensorManager mSensorManager;
  *     private final Sensor mAccelerometer;
  *
@@ -884,7 +884,7 @@
      * Used for receiving notifications from the SensorManager when dynamic sensors are connected or
      * disconnected.
      */
-    public static abstract class DynamicSensorConnectionCallback {
+    public static abstract class DynamicSensorCallback {
         /**
          * Called when there is a dynamic sensor being connected to the system.
          *
@@ -902,62 +902,73 @@
 
 
     /**
-     * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+     * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+     * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
      * registration with the already registered callback object will have no additional effect.
      *
      * @param callback An object that implements the
-     *        {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     *        DynamicSensorConnectionCallback}
+     *        {@link android.hardware.SensorManager.DynamicSensorCallback
+     *        DynamicSensorCallback}
      *        interface for receiving callbacks.
-     * @see #addDynamicSensorCallback(DynamicSensorConnectionCallback, Handler)
+     * @see #addDynamicSensorCallback(DynamicSensorCallback, Handler)
      *
      * @throws IllegalArgumentException when callback is null.
      */
-    public void registerDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+    public void registerDynamicSensorCallback(DynamicSensorCallback callback) {
         registerDynamicSensorCallback(callback, null);
     }
 
     /**
-     * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+     * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+     * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
      * registration with the already registered callback object will have no additional effect.
      *
      * @param callback An object that implements the
-     *        {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     *        DynamicSensorConnectionCallback} interface for receiving callbacks.
+     *        {@link android.hardware.SensorManager.DynamicSensorCallback
+     *        DynamicSensorCallback} interface for receiving callbacks.
      * @param handler The {@link android.os.Handler Handler} the {@link
-     *        android.hardware.SensorManager.DynamicSensorConnectionCallback
+     *        android.hardware.SensorManager.DynamicSensorCallback
      *        sensor connection events} will be delivered to.
      *
      * @throws IllegalArgumentException when callback is null.
      */
     public void registerDynamicSensorCallback(
-            DynamicSensorConnectionCallback callback, Handler handler) {
+            DynamicSensorCallback callback, Handler handler) {
         registerDynamicSensorCallbackImpl(callback, handler);
     }
 
     /**
-     * Remove a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     * DynamicSensorConnectionCallback} to stop sending dynamic sensor connection events to that
+     * Remove a {@link android.hardware.SensorManager.DynamicSensorCallback
+     * DynamicSensorCallback} to stop sending dynamic sensor connection events to that
      * callback.
      *
      * @param callback An object that implements the
-     *        {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     *        DynamicSensorConnectionCallback}
+     *        {@link android.hardware.SensorManager.DynamicSensorCallback
+     *        DynamicSensorCallback}
      *        interface for receiving callbacks.
      */
-    public void unregisterDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+    public void unregisterDynamicSensorCallback(DynamicSensorCallback callback) {
         unregisterDynamicSensorCallbackImpl(callback);
     }
 
+    /**
+     * Tell if dynamic sensor discovery feature is supported by system.
+     *
+     * @return <code>true</code> if dynamic sensor discovery is supported, <code>false</code>
+     * otherwise.
+     */
+    public boolean isDynamicSensorDiscoverySupported() {
+        List<Sensor> sensors = getSensorList(Sensor.TYPE_DYNAMIC_SENSOR_META);
+        return sensors.size() > 0;
+    }
+
     /** @hide */
     protected abstract void registerDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback, Handler handler);
+            DynamicSensorCallback callback, Handler handler);
 
     /** @hide */
     protected abstract void unregisterDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback);
+            DynamicSensorCallback callback);
 
     /**
      * <p>
diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java
index e0680bf22..83f7649 100644
--- a/core/java/android/hardware/SerialManager.java
+++ b/core/java/android/hardware/SerialManager.java
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-
 package android.hardware;
 
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.util.Log;
 
 import java.io.IOException;
 
@@ -50,8 +48,7 @@
         try {
             return mService.getSerialPorts();
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getSerialPorts", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -77,8 +74,7 @@
                 throw new IOException("Could not open serial port " + name);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "exception in UsbManager.openDevice", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 }
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index c4afbfb..259ca03 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -1,4 +1,4 @@
-    /*
+/*
  * Copyright (C) 2012 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,12 +31,15 @@
 import android.util.SparseIntArray;
 import dalvik.system.CloseGuard;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+
 /**
  * Sensor manager implementation that communicates with the built-in
  * system sensors.
@@ -54,10 +57,11 @@
     private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
     private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
 
-    private static boolean sSensorModuleInitialized = false;
-    private static InjectEventQueue mInjectEventQueue = null;
-
-    private final Object mLock = new Object();
+    private static final Object sLock = new Object();
+    @GuardedBy("sLock")
+    private static boolean sNativeClassInited = false;
+    @GuardedBy("sLock")
+    private static InjectEventQueue sInjectEventQueue = null;
 
     private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
     private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
@@ -72,7 +76,7 @@
             new HashMap<TriggerEventListener, TriggerEventQueue>();
 
     // Dynamic Sensor callbacks
-    private HashMap<DynamicSensorConnectionCallback, Handler>
+    private HashMap<DynamicSensorCallback, Handler>
             mDynamicSensorCallbacks = new HashMap<>();
     private BroadcastReceiver mDynamicSensorBroadcastReceiver;
 
@@ -84,24 +88,24 @@
 
     /** {@hide} */
     public SystemSensorManager(Context context, Looper mainLooper) {
+        synchronized(sLock) {
+            if (!sNativeClassInited) {
+                sNativeClassInited = true;
+                nativeClassInit();
+            }
+        }
+
         mMainLooper = mainLooper;
         mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
         mContext = context;
         mNativeInstance = nativeCreate(context.getOpPackageName());
 
-        synchronized(mLock) {
-            if (!sSensorModuleInitialized) {
-                sSensorModuleInitialized = true;
-                nativeClassInit();
-            }
-
-            // initialize the sensor list
-            for (int index = 0;;++index) {
-                Sensor sensor = new Sensor();
-                if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
-                mFullSensorsList.add(sensor);
-                mHandleToSensor.put(sensor.getHandle(), sensor);
-            }
+        // initialize the sensor list
+        for (int index = 0;;++index) {
+            Sensor sensor = new Sensor();
+            if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
+            mFullSensorsList.add(sensor);
+            mHandleToSensor.put(sensor.getHandle(), sensor);
         }
     }
 
@@ -116,7 +120,7 @@
     @Override
     protected List<Sensor> getFullDynamicSensorList() {
         // only set up broadcast receiver if the application tries to find dynamic sensors or
-        // explicitly register a DynamicSensorConnectionCallback
+        // explicitly register a DynamicSensorCallback
         setupDynamicSensorBroadcastReceiver();
         updateDynamicSensorList();
         return mFullDynamicSensorsList;
@@ -257,7 +261,7 @@
     }
 
     protected boolean initDataInjectionImpl(boolean enable) {
-        synchronized (mLock) {
+        synchronized (sLock) {
             if (enable) {
                 boolean isDataInjectionModeEnabled = nativeIsDataInjectionEnabled(mNativeInstance);
                 // The HAL does not support injection OR SensorService hasn't been set in DI mode.
@@ -266,15 +270,15 @@
                     return false;
                 }
                 // Initialize a client for data_injection.
-                if (mInjectEventQueue == null) {
-                    mInjectEventQueue = new InjectEventQueue(mMainLooper, this,
+                if (sInjectEventQueue == null) {
+                    sInjectEventQueue = new InjectEventQueue(mMainLooper, this,
                             mContext.getPackageName());
                 }
             } else {
                 // If data injection is being disabled clean up the native resources.
-                if (mInjectEventQueue != null) {
-                    mInjectEventQueue.dispose();
-                    mInjectEventQueue = null;
+                if (sInjectEventQueue != null) {
+                    sInjectEventQueue.dispose();
+                    sInjectEventQueue = null;
                 }
             }
             return true;
@@ -283,17 +287,17 @@
 
     protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
             long timestamp) {
-        synchronized (mLock) {
-            if (mInjectEventQueue == null) {
+        synchronized (sLock) {
+            if (sInjectEventQueue == null) {
                 Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
                 return false;
             }
-            int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
+            int ret = sInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
                                                          timestamp);
             // If there are any errors in data injection clean up the native resources.
             if (ret != 0) {
-                mInjectEventQueue.dispose();
-                mInjectEventQueue = null;
+                sInjectEventQueue.dispose();
+                sInjectEventQueue = null;
             }
             return ret == 0;
         }
@@ -350,9 +354,9 @@
 
                     Handler mainHandler = new Handler(mContext.getMainLooper());
 
-                    for (Map.Entry<DynamicSensorConnectionCallback, Handler> entry :
+                    for (Map.Entry<DynamicSensorCallback, Handler> entry :
                             mDynamicSensorCallbacks.entrySet()) {
-                        final DynamicSensorConnectionCallback callback = entry.getKey();
+                        final DynamicSensorCallback callback = entry.getKey();
                         Handler handler =
                                 entry.getValue() == null ? mainHandler : entry.getValue();
 
@@ -409,7 +413,7 @@
 
     /** @hide */
     protected void registerDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback, Handler handler) {
+            DynamicSensorCallback callback, Handler handler) {
         if (DEBUG_DYNAMIC_SENSOR) {
             Log.i(TAG, "DYNS Register dynamic sensor callback");
         }
@@ -428,7 +432,7 @@
 
     /** @hide */
     protected void unregisterDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback) {
+            DynamicSensorCallback callback) {
         if (DEBUG_DYNAMIC_SENSOR) {
             Log.i(TAG, "Removing dynamic sensor listerner");
         }
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
index 933ce0d..f9b659c 100644
--- a/core/java/android/hardware/camera2/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -114,12 +114,12 @@
     }
 
     public CameraAccessException(@AccessError int problem, String message) {
-        super(message);
+        super(getCombinedMessage(problem, message));
         mReason = problem;
     }
 
     public CameraAccessException(@AccessError int problem, String message, Throwable cause) {
-        super(message, cause);
+        super(getCombinedMessage(problem, message), cause);
         mReason = problem;
     }
 
@@ -151,4 +151,37 @@
         }
         return null;
     }
+
+    private static String getCombinedMessage(@AccessError int problem, String message) {
+        String problemString = getProblemString(problem);
+        return String.format("%s (%d): %s", problemString, problem, message);
+    }
+
+    private static String getProblemString(int problem) {
+        String problemString;
+        switch (problem) {
+            case CAMERA_IN_USE:
+                problemString = "CAMERA_IN_USE";
+                break;
+            case MAX_CAMERAS_IN_USE:
+                problemString = "MAX_CAMERAS_IN_USE";
+                break;
+            case CAMERA_DISCONNECTED:
+                problemString = "CAMERA_DISCONNECTED";
+                break;
+            case CAMERA_DISABLED:
+                problemString = "CAMERA_DISABLED";
+                break;
+            case CAMERA_ERROR:
+                problemString = "CAMERA_ERROR";
+                break;
+            case CAMERA_DEPRECATED_HAL:
+                problemString = "CAMERA_DEPRECATED_HAL";
+                break;
+            default:
+                problemString = "<UNKNOWN ERROR>";
+        }
+        return problemString;
+    }
+
 }
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 8724a96..38279a4 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -990,6 +990,30 @@
                 int sequenceId) {
             // default empty implementation
         }
+
+        /**
+         * <p>This method is called if a single buffer for a capture could not be sent to its
+         * destination surface.</p>
+         *
+         * <p>If the whole capture failed, then {@link #onCaptureFailed} will be called instead. If
+         * some but not all buffers were captured but the result metadata will not be available,
+         * then onCaptureFailed will be invoked with {@link CaptureFailure#wasImageCaptured}
+         * returning true, along with one or more calls to {@link #onCaptureBufferLost} for the
+         * failed outputs.</p>
+         *
+         * @param session
+         *            The session returned by {@link CameraDevice#createCaptureSession}
+         * @param request
+         *            The request that was given to the CameraDevice
+         * @param target
+         *            The target Surface that the buffer will not be produced for
+         * @param frameNumber
+         *            The frame number for the request
+         */
+        public void onCaptureBufferLost(@NonNull CameraCaptureSession session,
+                @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) {
+            // default empty implementation
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 51796eb..ffd9d89 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -26,15 +26,14 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.legacy.CameraDeviceUserShim;
 import android.hardware.camera2.legacy.LegacyMetadataMapper;
-import android.hardware.camera2.utils.CameraServiceBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.BinderHolder;
 import android.os.IBinder;
 import android.os.Binder;
+import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.ArrayMap;
 
@@ -240,25 +239,19 @@
                 if (!supportsCamera2ApiLocked(cameraId)) {
                     // Legacy backwards compatibility path; build static info from the camera
                     // parameters
-                    String[] outParameters = new String[1];
+                    String parameters = cameraService.getLegacyParameters(id);
 
-                    cameraService.getLegacyParameters(id, /*out*/outParameters);
-                    String parameters = outParameters[0];
-
-                    CameraInfo info = new CameraInfo();
-                    cameraService.getCameraInfo(id, /*out*/info);
+                    CameraInfo info = cameraService.getCameraInfo(id);
 
                     characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
                 } else {
                     // Normal path: Get the camera characteristics directly from the camera service
-                    CameraMetadataNative info = new CameraMetadataNative();
-
-                    cameraService.getCameraCharacteristics(id, info);
+                    CameraMetadataNative info = cameraService.getCameraCharacteristics(id);
 
                     characteristics = new CameraCharacteristics(info);
                 }
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
+            } catch (ServiceSpecificException e) {
+                throwAsPublicException(e);
             } catch (RemoteException e) {
                 // Camera service died - act as if the camera was disconnected
                 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -292,85 +285,85 @@
             throws CameraAccessException {
         CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
         CameraDevice device = null;
-        try {
 
-            synchronized (mLock) {
+        synchronized (mLock) {
 
-                ICameraDeviceUser cameraUser = null;
+            ICameraDeviceUser cameraUser = null;
 
-                android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
-                        new android.hardware.camera2.impl.CameraDeviceImpl(
-                                cameraId,
-                                callback,
-                                handler,
-                                characteristics);
+            android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
+                    new android.hardware.camera2.impl.CameraDeviceImpl(
+                        cameraId,
+                        callback,
+                        handler,
+                        characteristics);
 
-                BinderHolder holder = new BinderHolder();
+            ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
 
-                ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
-                int id = Integer.parseInt(cameraId);
-                try {
-                    if (supportsCamera2ApiLocked(cameraId)) {
-                        // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
-                        ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
-                        if (cameraService == null) {
-                            throw new CameraRuntimeException(
-                                CameraAccessException.CAMERA_DISCONNECTED,
-                                "Camera service is currently unavailable");
-                        }
-                        cameraService.connectDevice(callbacks, id,
-                                mContext.getOpPackageName(), USE_CALLING_UID, holder);
-                        cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
-                    } else {
-                        // Use legacy camera implementation for HAL1 devices
-                        Log.i(TAG, "Using legacy camera HAL.");
-                        cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
-                    }
-                } catch (CameraRuntimeException e) {
-                    if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
-                        throw new AssertionError("Should've gone down the shim path");
-                    } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
-                            e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
-                            e.getReason() == CameraAccessException.CAMERA_DISABLED ||
-                            e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
-                            e.getReason() == CameraAccessException.CAMERA_ERROR) {
-                        // Received one of the known connection errors
-                        // The remote camera device cannot be connected to, so
-                        // set the local camera to the startup error state
-                        deviceImpl.setRemoteFailure(e);
-
-                        if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
-                                e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
-                                e.getReason() == CameraAccessException.CAMERA_IN_USE) {
-                            // Per API docs, these failures call onError and throw
-                            throw e.asChecked();
-                        }
-                    } else {
-                        // Unexpected failure - rethrow
-                        throw e;
-                    }
-                } catch (RemoteException e) {
-                    // Camera service died - act as if it's a CAMERA_DISCONNECTED case
-                    CameraRuntimeException ce = new CameraRuntimeException(
-                        CameraAccessException.CAMERA_DISCONNECTED,
-                        "Camera service is currently unavailable", e);
-                    deviceImpl.setRemoteFailure(ce);
-                    throw ce.asChecked();
-                }
-
-                // TODO: factor out callback to be non-nested, then move setter to constructor
-                // For now, calling setRemoteDevice will fire initial
-                // onOpened/onUnconfigured callbacks.
-                deviceImpl.setRemoteDevice(cameraUser);
-                device = deviceImpl;
+            int id;
+            try {
+                id = Integer.parseInt(cameraId);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+                        + cameraId);
             }
 
-        } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
-                    + cameraId);
-        } catch (CameraRuntimeException e) {
-            throw e.asChecked();
+            try {
+                if (supportsCamera2ApiLocked(cameraId)) {
+                    // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
+                    ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+                    if (cameraService == null) {
+                        throw new ServiceSpecificException(
+                            ICameraService.ERROR_DISCONNECTED,
+                            "Camera service is currently unavailable");
+                    }
+                    cameraUser = cameraService.connectDevice(callbacks, id,
+                            mContext.getOpPackageName(), USE_CALLING_UID);
+                } else {
+                    // Use legacy camera implementation for HAL1 devices
+                    Log.i(TAG, "Using legacy camera HAL.");
+                    cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
+                }
+            } catch (ServiceSpecificException e) {
+                if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
+                    throw new AssertionError("Should've gone down the shim path");
+                } else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
+                        e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
+                        e.errorCode == ICameraService.ERROR_DISABLED ||
+                        e.errorCode == ICameraService.ERROR_DISCONNECTED ||
+                        e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
+                    // Received one of the known connection errors
+                    // The remote camera device cannot be connected to, so
+                    // set the local camera to the startup error state
+                    deviceImpl.setRemoteFailure(e);
+
+                    if (e.errorCode == ICameraService.ERROR_DISABLED ||
+                            e.errorCode == ICameraService.ERROR_DISCONNECTED ||
+                            e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
+                        // Per API docs, these failures call onError and throw
+                        throwAsPublicException(e);
+                    }
+                } else {
+                    // Unexpected failure - rethrow
+                    throwAsPublicException(e);
+                }
+            } catch (RemoteException e) {
+                // Camera service died - act as if it's a CAMERA_DISCONNECTED case
+                ServiceSpecificException sse = new ServiceSpecificException(
+                    ICameraService.ERROR_DISCONNECTED,
+                    "Camera service is currently unavailable");
+                deviceImpl.setRemoteFailure(sse);
+                throwAsPublicException(sse);
+            }
+
+            // TODO: factor out callback to be non-nested, then move setter to constructor
+            // For now, calling setRemoteDevice will fire initial
+            // onOpened/onUnconfigured callbacks.
+            // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
+            // cameraUser dies during setup.
+            deviceImpl.setRemoteDevice(cameraUser);
+            device = deviceImpl;
         }
+
         return device;
     }
 
@@ -602,6 +595,56 @@
     }
 
     /**
+     * Convert ServiceSpecificExceptions and Binder RemoteExceptions from camera binder interfaces
+     * into the correct public exceptions.
+     *
+     * @hide
+     */
+    public static void throwAsPublicException(Throwable t) throws CameraAccessException {
+        if (t instanceof ServiceSpecificException) {
+            ServiceSpecificException e = (ServiceSpecificException) t;
+            int reason = CameraAccessException.CAMERA_ERROR;
+            switch(e.errorCode) {
+                case ICameraService.ERROR_DISCONNECTED:
+                    reason = CameraAccessException.CAMERA_DISCONNECTED;
+                    break;
+                case ICameraService.ERROR_DISABLED:
+                    reason = CameraAccessException.CAMERA_DISABLED;
+                    break;
+                case ICameraService.ERROR_CAMERA_IN_USE:
+                    reason = CameraAccessException.CAMERA_IN_USE;
+                    break;
+                case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
+                    reason = CameraAccessException.MAX_CAMERAS_IN_USE;
+                    break;
+                case ICameraService.ERROR_DEPRECATED_HAL:
+                    reason = CameraAccessException.CAMERA_DEPRECATED_HAL;
+                    break;
+                case ICameraService.ERROR_ILLEGAL_ARGUMENT:
+                case ICameraService.ERROR_ALREADY_EXISTS:
+                    throw new IllegalArgumentException(e.getMessage(), e);
+                case ICameraService.ERROR_PERMISSION_DENIED:
+                    throw new SecurityException(e.getMessage(), e);
+                case ICameraService.ERROR_TIMED_OUT:
+                case ICameraService.ERROR_INVALID_OPERATION:
+                default:
+                    reason = CameraAccessException.CAMERA_ERROR;
+            }
+            throw new CameraAccessException(reason, e.getMessage(), e);
+        } else if (t instanceof DeadObjectException) {
+            throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                    "Camera service has died unexpectedly",
+                    t);
+        } else if (t instanceof RemoteException) {
+            throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
+                    " which should never happen.", t);
+        } else if (t instanceof RuntimeException) {
+            RuntimeException e = (RuntimeException) t;
+            throw e;
+        }
+    }
+
+    /**
      * Return or create the list of currently connected camera devices.
      *
      * <p>In case of errors connecting to the camera service, will return an empty list.</p>
@@ -619,34 +662,32 @@
 
             try {
                 numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
-            } catch(CameraRuntimeException e) {
-                throw e.asChecked();
+            } catch(ServiceSpecificException e) {
+                throwAsPublicException(e);
             } catch (RemoteException e) {
                 // camera service just died - if no camera service, then no devices
                 return deviceIdList;
             }
 
-            CameraMetadataNative info = new CameraMetadataNative();
             for (int i = 0; i < numCameras; ++i) {
                 // Non-removable cameras use integers starting at 0 for their
                 // identifiers
                 boolean isDeviceSupported = false;
                 try {
-                    cameraService.getCameraCharacteristics(i, info);
+                    CameraMetadataNative info = cameraService.getCameraCharacteristics(i);
                     if (!info.isEmpty()) {
                         isDeviceSupported = true;
                     } else {
                         throw new AssertionError("Expected to get non-empty characteristics");
                     }
-                } catch(IllegalArgumentException  e) {
-                    // Got a BAD_VALUE from service, meaning that this
-                    // device is not supported.
-                } catch(CameraRuntimeException e) {
+                } catch(ServiceSpecificException e) {
                     // DISCONNECTED means that the HAL reported an low-level error getting the
-                    // device info; skip listing the device.  Other errors,
+                    // device info; ILLEGAL_ARGUMENT means that this devices is not supported.
+                    // Skip listing the device.  Other errors,
                     // propagate exception onward
-                    if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
-                        throw e.asChecked();
+                    if (e.errorCode != ICameraService.ERROR_DISCONNECTED ||
+                            e.errorCode != ICameraService.ERROR_ILLEGAL_ARGUMENT) {
+                        throwAsPublicException(e);
                     }
                 } catch(RemoteException e) {
                     // Camera service died - no devices to list
@@ -699,17 +740,7 @@
             // If no camera service, no support
             if (cameraService == null) return false;
 
-            int res = cameraService.supportsCameraApi(id, apiVersion);
-
-            if (res != CameraServiceBinderDecorator.NO_ERROR) {
-                throw new AssertionError("Unexpected value " + res);
-            }
-            return true;
-        } catch (CameraRuntimeException e) {
-            if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) {
-                throw e;
-            }
-            // API level is not supported
+            return cameraService.supportsCameraApi(id, apiVersion);
         } catch (RemoteException e) {
             // Camera service is now down, no support for any API level
         }
@@ -737,21 +768,6 @@
          */
         private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
 
-        // Keep up-to-date with ICameraServiceListener.h
-
-        // Device physically unplugged
-        public static final int STATUS_NOT_PRESENT = 0;
-        // Device physically has been plugged in
-        // and the camera can be used exclusively
-        public static final int STATUS_PRESENT = 1;
-        // Device physically has been plugged in
-        // but it will not be connect-able until enumeration is complete
-        public static final int STATUS_ENUMERATING = 2;
-        // Camera is in use by another app and cannot be used exclusively
-        public static final int STATUS_NOT_AVAILABLE = 0x80000000;
-
-        // End enums shared with ICameraServiceListener.h
-
         // Camera ID -> Status map
         private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
 
@@ -759,17 +775,6 @@
         private final ArrayMap<AvailabilityCallback, Handler> mCallbackMap =
             new ArrayMap<AvailabilityCallback, Handler>();
 
-        // Keep up-to-date with ICameraServiceListener.h
-
-        // torch mode has become not available to set via setTorchMode().
-        public static final int TORCH_STATUS_NOT_AVAILABLE = 0;
-        // torch mode is off and available to be turned on via setTorchMode().
-        public static final int TORCH_STATUS_AVAILABLE_OFF = 1;
-        // torch mode is on and available to be turned off via setTorchMode().
-        public static final int TORCH_STATUS_AVAILABLE_ON = 2;
-
-        // End enums shared with ICameraServiceListener.h
-
         // torch client binder to set the torch mode with.
         private Binder mTorchClientBinder = new Binder();
 
@@ -839,29 +844,20 @@
                 return;
             }
 
-            ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
-
-            /**
-             * Wrap the camera service in a decorator which automatically translates return codes
-             * into exceptions.
-             */
-            ICameraService cameraService =
-                CameraServiceBinderDecorator.newInstance(cameraServiceRaw);
+            ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);
 
             try {
-                CameraServiceBinderDecorator.throwOnError(
-                        CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
-            } catch (CameraRuntimeException e) {
-                handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
+                CameraMetadataNative.setupGlobalVendorTagDescriptor();
+            } catch (ServiceSpecificException e) {
+                handleRecoverableSetupErrors(e);
             }
 
             try {
                 cameraService.addListener(this);
                 mCameraService = cameraService;
-            } catch(CameraRuntimeException e) {
+            } catch(ServiceSpecificException e) {
                 // Unexpected failure
-                throw new IllegalStateException("Failed to register a camera service listener",
-                        e.asChecked());
+                throw new IllegalStateException("Failed to register a camera service listener", e);
             } catch (RemoteException e) {
                 // Camera service is now down, leave mCameraService as null
             }
@@ -881,16 +877,9 @@
                 }
 
                 try {
-                    int status = cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
-                } catch(CameraRuntimeException e) {
-                    int problem = e.getReason();
-                    switch (problem) {
-                        case CameraAccessException.CAMERA_ERROR:
-                            throw new IllegalArgumentException(
-                                    "the camera device doesn't have a flash unit.");
-                        default:
-                            throw e.asChecked();
-                    }
+                    cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
+                } catch(ServiceSpecificException e) {
+                    throwAsPublicException(e);
                 } catch (RemoteException e) {
                     throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                             "Camera service is currently unavailable");
@@ -898,21 +887,19 @@
             }
         }
 
-        private void handleRecoverableSetupErrors(CameraRuntimeException e, String msg) {
-            int problem = e.getReason();
-            switch (problem) {
-                case CameraAccessException.CAMERA_DISCONNECTED:
-                    String errorMsg = CameraAccessException.getDefaultMessage(problem);
-                    Log.w(TAG, msg + ": " + errorMsg);
+        private void handleRecoverableSetupErrors(ServiceSpecificException e) {
+            switch (e.errorCode) {
+                case ICameraService.ERROR_DISCONNECTED:
+                    Log.w(TAG, e.getMessage());
                     break;
                 default:
-                    throw new IllegalStateException(msg, e.asChecked());
+                    throw new IllegalStateException(e);
             }
         }
 
         private boolean isAvailable(int status) {
             switch (status) {
-                case STATUS_PRESENT:
+                case ICameraServiceListener.STATUS_PRESENT:
                     return true;
                 default:
                     return false;
@@ -921,10 +908,10 @@
 
         private boolean validStatus(int status) {
             switch (status) {
-                case STATUS_NOT_PRESENT:
-                case STATUS_PRESENT:
-                case STATUS_ENUMERATING:
-                case STATUS_NOT_AVAILABLE:
+                case ICameraServiceListener.STATUS_NOT_PRESENT:
+                case ICameraServiceListener.STATUS_PRESENT:
+                case ICameraServiceListener.STATUS_ENUMERATING:
+                case ICameraServiceListener.STATUS_NOT_AVAILABLE:
                     return true;
                 default:
                     return false;
@@ -933,9 +920,9 @@
 
         private boolean validTorchStatus(int status) {
             switch (status) {
-                case TORCH_STATUS_NOT_AVAILABLE:
-                case TORCH_STATUS_AVAILABLE_ON:
-                case TORCH_STATUS_AVAILABLE_OFF:
+                case ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
                     return true;
                 default:
                     return false;
@@ -966,14 +953,14 @@
         private void postSingleTorchUpdate(final TorchCallback callback, final Handler handler,
                 final String id, final int status) {
             switch(status) {
-                case TORCH_STATUS_AVAILABLE_ON:
-                case TORCH_STATUS_AVAILABLE_OFF:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
                     handler.post(
                             new Runnable() {
                                 @Override
                                 public void run() {
                                     callback.onTorchModeChanged(id, status ==
-                                            TORCH_STATUS_AVAILABLE_ON);
+                                            ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON);
                                 }
                             });
                     break;
@@ -1112,6 +1099,11 @@
                 if (oldHandler == null) {
                     updateCallbackLocked(callback, handler);
                 }
+
+                // If not connected to camera service, schedule a reconnect to camera service.
+                if (mCameraService == null) {
+                    scheduleCameraServiceReconnectionLocked();
+                }
             }
         }
 
@@ -1136,6 +1128,11 @@
                 if (oldHandler == null) {
                     updateTorchCallbackLocked(callback, handler);
                 }
+
+                // If not connected to camera service, schedule a reconnect to camera service.
+                if (mCameraService == null) {
+                    scheduleCameraServiceReconnectionLocked();
+                }
             }
         }
 
@@ -1220,11 +1217,12 @@
                 // and torch statuses will be updated.
                 for (int i = 0; i < mDeviceStatus.size(); i++) {
                     String cameraId = mDeviceStatus.keyAt(i);
-                    onStatusChangedLocked(STATUS_NOT_PRESENT, cameraId);
+                    onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);
                 }
                 for (int i = 0; i < mTorchStatus.size(); i++) {
                     String cameraId = mTorchStatus.keyAt(i);
-                    onTorchStatusChangedLocked(TORCH_STATUS_NOT_AVAILABLE, cameraId);
+                    onTorchStatusChangedLocked(ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE,
+                            cameraId);
                 }
 
                 scheduleCameraServiceReconnectionLocked();
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index d58ad22..d06e08b 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2025,11 +2025,20 @@
      * produced in response to a capture request submitted
      * while in HDR mode.</p>
      * <p>Since substantial post-processing is generally needed to
-     * produce an HDR image, only YUV and JPEG outputs are
-     * supported for LIMITED/FULL device HDR captures, and only
-     * JPEG outputs are supported for LEGACY HDR
-     * captures. Using a RAW output for HDR capture is not
+     * produce an HDR image, only YUV, PRIVATE, and JPEG
+     * outputs are supported for LIMITED/FULL device HDR
+     * captures, and only JPEG outputs are supported for LEGACY
+     * HDR captures. Using a RAW output for HDR capture is not
      * supported.</p>
+     * <p>Some devices may also support always-on HDR, which
+     * applies HDR processing at full frame rate.  For these
+     * devices, intents other than STILL_CAPTURE will also
+     * produce an HDR output with no frame rate impact compared
+     * to normal operation, though the quality may be lower
+     * than for STILL_CAPTURE intents.</p>
+     * <p>If SCENE_MODE_HDR is used with unsupported output types
+     * or capture intents, the images captured will be as if
+     * the SCENE_MODE was not enabled at all.</p>
      *
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      * @see CaptureRequest#CONTROL_SCENE_MODE
@@ -2070,6 +2079,24 @@
      */
     public static final int CONTROL_SCENE_MODE_FACE_PRIORITY_LOW_LIGHT = 19;
 
+    /**
+     * <p>Scene mode values within the range of
+     * <code>[DEVICE_CUSTOM_START, DEVICE_CUSTOM_END]</code> are reserved for device specific
+     * customized scene modes.</p>
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     * @hide
+     */
+    public static final int CONTROL_SCENE_MODE_DEVICE_CUSTOM_START = 100;
+
+    /**
+     * <p>Scene mode values within the range of
+     * <code>[DEVICE_CUSTOM_START, DEVICE_CUSTOM_END]</code> are reserved for device specific
+     * customized scene modes.</p>
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     * @hide
+     */
+    public static final int CONTROL_SCENE_MODE_DEVICE_CUSTOM_END = 127;
+
     //
     // Enumeration values for CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
     //
diff --git a/core/java/android/hardware/camera2/CaptureRequest.aidl b/core/java/android/hardware/camera2/CaptureRequest.aidl
deleted file mode 100644
index 0b7d5ba..0000000
--- a/core/java/android/hardware/camera2/CaptureRequest.aidl
+++ /dev/null
@@ -1,20 +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;
-
-/** @hide */
-parcelable CaptureRequest;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 5748726..4f41e1c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3373,7 +3373,7 @@
 
     /**
      * <p>Maximum raw value output by sensor for this frame.</p>
-     * <p>Since the android.sensor.blackLevel may change for different
+     * <p>Since the {@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern} may change for different
      * capture settings (e.g., {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}), the white
      * level will change accordingly. This key is similar to
      * {@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}, but specifies the camera device
@@ -3385,6 +3385,7 @@
      * &gt;= 0</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
      * @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
      * @see CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS
      * @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
index 57a080b..9478dc0 100644
--- a/core/java/android/hardware/camera2/DngCreator.java
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -137,6 +137,11 @@
             throw new IllegalArgumentException("Orientation " + orientation +
                     " is not a valid EXIF orientation value");
         }
+        // ExifInterface and TIFF/EP spec differ on definition of
+        // "Unknown" orientation; other values map directly
+        if (orientation == ExifInterface.ORIENTATION_UNDEFINED) {
+            orientation = TAG_ORIENTATION_UNKNOWN;
+        }
         nativeSetOrientation(orientation);
         return this;
     }
@@ -443,7 +448,7 @@
     private static final String GPS_LONG_REF_WEST = "W";
 
     private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
-    private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd kk:mm:ss";
+    private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss";
     private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
     private static final DateFormat sDateTimeStampFormat =
             new SimpleDateFormat(TIFF_DATETIME_FORMAT);
@@ -458,6 +463,9 @@
     private static final int DEFAULT_PIXEL_STRIDE = 2; // bytes per sample
     private static final int BYTES_PER_RGB_PIX = 3; // byts per pixel
 
+    // TIFF tag values needed to map between public API and TIFF spec
+    private static final int TAG_ORIENTATION_UNKNOWN = 9;
+
     /**
      * Offset, rowStride, and pixelStride are given in bytes.  Height and width are given in pixels.
      */
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
deleted file mode 100644
index 151c918..0000000
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ /dev/null
@@ -1,35 +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;
-
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.impl.CaptureResultExtras;
-
-/** @hide */
-interface ICameraDeviceCallbacks
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
-     */
-
-    oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
-    oneway void onDeviceIdle();
-    oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
-    oneway void onResultReceived(in CameraMetadataNative result,
-                                 in CaptureResultExtras resultExtras);
-    oneway void onPrepared(int streamId);
-}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
deleted file mode 100644
index c9c9abc..0000000
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ /dev/null
@@ -1,107 +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;
-
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.LongParcelable;
-import android.view.Surface;
-
-/** @hide */
-interface ICameraDeviceUser
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceUser.h and
-     * frameworks/base/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
-     */
-    void disconnect();
-
-    // ints here are status_t
-
-    // non-negative value is the requestId. negative value is status_t
-    int submitRequest(in CaptureRequest request, boolean streaming,
-                      out LongParcelable lastFrameNumber);
-
-    int submitRequestList(in List<CaptureRequest> requestList, boolean streaming,
-                          out LongParcelable lastFrameNumber);
-
-    int cancelRequest(int requestId, out LongParcelable lastFrameNumber);
-
-    /**
-     * Begin the device configuration.
-     *
-     * <p>
-     * beginConfigure must be called before any call to deleteStream, createStream,
-     * or endConfigure.  It is not valid to call this when the device is not idle.
-     * <p>
-     */
-    int beginConfigure();
-
-    /**
-     * End the device configuration.
-     *
-     * <p>
-     * endConfigure must be called after stream configuration is complete (i.e. after
-     * a call to beginConfigure and subsequent createStream/deleteStream calls).  This
-     * must be called before any requests can be submitted.
-     * <p>
-     */
-    int endConfigure(boolean isConstrainedHighSpeed);
-
-    int deleteStream(int streamId);
-
-    // non-negative value is the stream ID. negative value is status_t
-    int createStream(in OutputConfiguration outputConfiguration);
-
-    /**
-     * Create an input stream
-     *
-     * <p>Create an input stream of width, height, and format</p>
-     *
-     * @param width Width of the input buffers
-     * @param height Height of the input buffers
-     * @param format Format of the input buffers. One of HAL_PIXEL_FORMAT_*.
-     *
-     * @return stream ID if it's a non-negative value. status_t if it's a negative value.
-     */
-    int createInputStream(int width, int height, int format);
-
-    /**
-     * Get the surface of the input stream.
-     *
-     * <p>It's valid to call this method only after a stream configuration is completed
-     * successfully and the stream configuration includes a input stream.</p>
-     *
-     * @param surface An output argument for the surface of the input stream buffer queue.
-     */
-    int getInputSurface(out Surface surface);
-
-    int createDefaultRequest(int templateId, out CameraMetadataNative request);
-
-    int getCameraInfo(out CameraMetadataNative info);
-
-    int waitUntilIdle();
-
-    int flush(out LongParcelable lastFrameNumber);
-
-    int prepare(int streamId);
-
-    int tearDown(int streamId);
-
-    int prepare2(int maxCount, int streamId);
-}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 3aba0d1..d2e820e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -33,14 +33,14 @@
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.ReprocessFormatsMap;
 import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.utils.SurfaceUtils;
+import android.hardware.ICameraService;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.Range;
 import android.util.Size;
@@ -63,14 +63,15 @@
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
  */
-public class CameraDeviceImpl extends CameraDevice {
+public class CameraDeviceImpl extends CameraDevice
+        implements IBinder.DeathRecipient {
     private final String TAG;
     private final boolean DEBUG = false;
 
     private static final int REQUEST_ID_NONE = -1;
 
     // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
-    private ICameraDeviceUser mRemoteDevice;
+    private ICameraDeviceUserWrapper mRemoteDevice;
 
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock = new Object(); // access from this class and Session only!
@@ -261,13 +262,34 @@
         return mCallbacks;
     }
 
-    public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
+    /**
+     * Set remote device, which triggers initial onOpened/onUnconfigured callbacks
+     *
+     * <p>This function may post onDisconnected and throw CAMERA_DISCONNECTED if remoteDevice dies
+     * during setup.</p>
+     *
+     */
+    public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
         synchronized(mInterfaceLock) {
             // TODO: Move from decorator to direct binder-mediated exceptions
             // If setRemoteFailure already called, do nothing
             if (mInError) return;
 
-            mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
+            mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
+
+            IBinder remoteDeviceBinder = remoteDevice.asBinder();
+            // For legacy camera device, remoteDevice is in the same process, and
+            // asBinder returns NULL.
+            if (remoteDeviceBinder != null) {
+                try {
+                    remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
+                } catch (RemoteException e) {
+                    CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
+
+                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                            "The camera device has encountered a serious error");
+                }
+            }
 
             mDeviceHandler.post(mCallOnOpened);
             mDeviceHandler.post(mCallOnUnconfigured);
@@ -280,28 +302,29 @@
      * <p>This places the camera device in the error state and informs the callback.
      * Use in place of setRemoteDevice() when startup fails.</p>
      */
-    public void setRemoteFailure(final CameraRuntimeException failure) {
+    public void setRemoteFailure(final ServiceSpecificException failure) {
         int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
         boolean failureIsError = true;
 
-        switch (failure.getReason()) {
-            case CameraAccessException.CAMERA_IN_USE:
+        switch (failure.errorCode) {
+            case ICameraService.ERROR_CAMERA_IN_USE:
                 failureCode = StateCallback.ERROR_CAMERA_IN_USE;
                 break;
-            case CameraAccessException.MAX_CAMERAS_IN_USE:
+            case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
                 failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
                 break;
-            case CameraAccessException.CAMERA_DISABLED:
+            case ICameraService.ERROR_DISABLED:
                 failureCode = StateCallback.ERROR_CAMERA_DISABLED;
                 break;
-            case CameraAccessException.CAMERA_DISCONNECTED:
+            case ICameraService.ERROR_DISCONNECTED:
                 failureIsError = false;
                 break;
-            case CameraAccessException.CAMERA_ERROR:
+            case ICameraService.ERROR_INVALID_OPERATION:
                 failureCode = StateCallback.ERROR_CAMERA_DEVICE;
                 break;
             default:
-                Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
+                Log.e(TAG, "Unexpected failure in opening camera device: " + failure.errorCode +
+                        failure.getMessage());
                 break;
         }
         final int code = failureCode;
@@ -430,27 +453,20 @@
                     }
                 }
 
-                try {
-                    mRemoteDevice.endConfigure(isConstrainedHighSpeed);
-                }
-                catch (IllegalArgumentException e) {
-                    // OK. camera service can reject stream config if it's not supported by HAL
-                    // This is only the result of a programmer misusing the camera2 api.
-                    Log.w(TAG, "Stream configuration failed");
-                    return false;
-                }
+                mRemoteDevice.endConfigure(isConstrainedHighSpeed);
 
                 success = true;
-            } catch (CameraRuntimeException e) {
-                if (e.getReason() == CAMERA_IN_USE) {
-                    throw new IllegalStateException("The camera is currently busy." +
-                            " You must wait until the previous operation completes.");
-                }
-
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
+            } catch (IllegalArgumentException e) {
+                // OK. camera service can reject stream config if it's not supported by HAL
+                // This is only the result of a programmer misusing the camera2 api.
+                Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
                 return false;
+            } catch (CameraAccessException e) {
+                if (e.getReason() == CameraAccessException.CAMERA_IN_USE) {
+                    throw new IllegalStateException("The camera is currently busy." +
+                            " You must wait until the previous operation completes.", e);
+                }
+                throw e;
             } finally {
                 if (success && outputs.size() > 0) {
                     mDeviceHandler.post(mCallOnIdle);
@@ -594,12 +610,7 @@
                 configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
                         isConstrainedHighSpeed);
                 if (configureSuccess == true && inputConfig != null) {
-                    input = new Surface();
-                    try {
-                        mRemoteDevice.getInputSurface(/*out*/input);
-                    } catch (CameraRuntimeException e) {
-                        e.asChecked();
-                    }
+                    input = mRemoteDevice.getInputSurface();
                 }
             } catch (CameraAccessException e) {
                 configureSuccess = false;
@@ -608,9 +619,6 @@
                 if (DEBUG) {
                     Log.v(TAG, "createCaptureSession - failed with exception ", e);
                 }
-            } catch (RemoteException e) {
-                // impossible
-                return;
             }
 
             List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
@@ -655,16 +663,9 @@
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
 
-            CameraMetadataNative templatedRequest = new CameraMetadataNative();
+            CameraMetadataNative templatedRequest = null;
 
-            try {
-                mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return null;
-            }
+            templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
 
             CaptureRequest.Builder builder = new CaptureRequest.Builder(
                     templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
@@ -701,14 +702,8 @@
             if (streamId == -1) {
                 throw new IllegalArgumentException("Surface is not part of this session");
             }
-            try {
-                mRemoteDevice.prepare(streamId);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.prepare(streamId);
         }
     }
 
@@ -728,14 +723,8 @@
             if (streamId == -1) {
                 throw new IllegalArgumentException("Surface is not part of this session");
             }
-            try {
-                mRemoteDevice.prepare2(maxCount, streamId);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.prepare2(maxCount, streamId);
         }
     }
 
@@ -753,14 +742,8 @@
             if (streamId == -1) {
                 throw new IllegalArgumentException("Surface is not part of this session");
             }
-            try {
-                mRemoteDevice.tearDown(streamId);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.tearDown(streamId);
         }
     }
 
@@ -875,45 +858,37 @@
 
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
-            int requestId;
-
             if (repeating) {
                 stopRepeating();
             }
 
-            LongParcelable lastFrameNumberRef = new LongParcelable();
-            try {
-                requestId = mRemoteDevice.submitRequestList(requestList, repeating,
-                        /*out*/lastFrameNumberRef);
-                if (DEBUG) {
-                    Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
-                }
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return -1;
+            SubmitInfo requestInfo;
+
+            CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
+            requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
+            if (DEBUG) {
+                Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
             }
 
             if (callback != null) {
-                mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback,
-                        requestList, handler, repeating, mNextSessionId - 1));
+                mCaptureCallbackMap.put(requestInfo.getRequestId(),
+                        new CaptureCallbackHolder(
+                            callback, requestList, handler, repeating, mNextSessionId - 1));
             } else {
                 if (DEBUG) {
-                    Log.d(TAG, "Listen for request " + requestId + " is null");
+                    Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
                 }
             }
 
-            long lastFrameNumber = lastFrameNumberRef.getNumber();
-
             if (repeating) {
                 if (mRepeatingRequestId != REQUEST_ID_NONE) {
-                    checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
+                    checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
+                            requestInfo.getLastFrameNumber());
                 }
-                mRepeatingRequestId = requestId;
+                mRepeatingRequestId = requestInfo.getRequestId();
             } else {
-                mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestList,
-                        requestId, lastFrameNumber));
+                mRequestLastFrameNumbersList.add(
+                    new RequestLastFrameNumbersHolder(requestList, requestInfo));
             }
 
             if (mIdle) {
@@ -921,7 +896,7 @@
             }
             mIdle = false;
 
-            return requestId;
+            return requestInfo.getRequestId();
         }
     }
 
@@ -949,19 +924,9 @@
                 int requestId = mRepeatingRequestId;
                 mRepeatingRequestId = REQUEST_ID_NONE;
 
-                try {
-                    LongParcelable lastFrameNumberRef = new LongParcelable();
-                    mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
-                    long lastFrameNumber = lastFrameNumberRef.getNumber();
+                long lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
 
-                    checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
-
-                } catch (CameraRuntimeException e) {
-                    throw e.asChecked();
-                } catch (RemoteException e) {
-                    // impossible
-                    return;
-                }
+                checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
             }
         }
     }
@@ -974,14 +939,8 @@
             if (mRepeatingRequestId != REQUEST_ID_NONE) {
                 throw new IllegalStateException("Active repeating request ongoing");
             }
-            try {
-                mRemoteDevice.waitUntilIdle();
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.waitUntilIdle();
         }
     }
 
@@ -997,19 +956,11 @@
                 mDeviceHandler.post(mCallOnIdle);
                 return;
             }
-            try {
-                LongParcelable lastFrameNumberRef = new LongParcelable();
-                mRemoteDevice.flush(/*out*/lastFrameNumberRef);
-                if (mRepeatingRequestId != REQUEST_ID_NONE) {
-                    long lastFrameNumber = lastFrameNumberRef.getNumber();
-                    checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
-                    mRepeatingRequestId = REQUEST_ID_NONE;
-                }
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
+
+            long lastFrameNumber = mRemoteDevice.flush();
+            if (mRepeatingRequestId != REQUEST_ID_NONE) {
+                checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
+                mRepeatingRequestId = REQUEST_ID_NONE;
             }
         }
     }
@@ -1021,14 +972,9 @@
                 return;
             }
 
-            try {
-                if (mRemoteDevice != null) {
-                    mRemoteDevice.disconnect();
-                }
-            } catch (CameraRuntimeException e) {
-                Log.e(TAG, "Exception while closing: ", e.asChecked());
-            } catch (RemoteException e) {
-                // impossible
+            if (mRemoteDevice != null) {
+                mRemoteDevice.disconnect();
+                mRemoteDevice.unlinkToDeath(this, /*flags*/0);
             }
 
             // Only want to fire the onClosed callback once;
@@ -1171,6 +1117,11 @@
                 int sequenceId) {
             // default empty implementation
         }
+
+        public void onCaptureBufferLost(CameraDevice camera,
+                CaptureRequest request, Surface target, long frameNumber) {
+            // default empty implementation
+        }
     }
 
     /**
@@ -1297,14 +1248,14 @@
          * Create a request-last-frame-numbers holder with a list of requests, request ID, and
          * the last frame number returned by camera service.
          */
-        public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, int requestId,
-                long lastFrameNumber) {
+        public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, SubmitInfo requestInfo) {
             long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
             long lastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
-            long frameNumber = lastFrameNumber;
+            long frameNumber = requestInfo.getLastFrameNumber();
 
-            if (lastFrameNumber < requestList.size() - 1) {
-                throw new IllegalArgumentException("lastFrameNumber: " + lastFrameNumber +
+            if (requestInfo.getLastFrameNumber() < requestList.size() - 1) {
+                throw new IllegalArgumentException(
+                        "lastFrameNumber: " + requestInfo.getLastFrameNumber() +
                         " should be at least " + (requestList.size() - 1) + " for the number of " +
                         " requests in the list: " + requestList.size());
             }
@@ -1330,7 +1281,7 @@
 
             mLastRegularFrameNumber = lastRegularFrameNumber;
             mLastReprocessFrameNumber = lastReprocessFrameNumber;
-            mRequestId = requestId;
+            mRequestId = requestInfo.getRequestId();
         }
 
         /**
@@ -1942,48 +1893,66 @@
 
             final CaptureRequest request = holder.getRequest(subsequenceId);
 
-            // No way to report buffer errors right now
+            Runnable failureDispatch = null;
             if (errorCode == ERROR_CAMERA_BUFFER) {
-                Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
-                return;
-            }
-
-            boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
-
-            // This is only approximate - exact handling needs the camera service and HAL to
-            // disambiguate between request failures to due abort and due to real errors.
-            // For now, assume that if the session believes we're mid-abort, then the error
-            // is due to abort.
-            int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
-                    CaptureFailure.REASON_FLUSHED :
-                    CaptureFailure.REASON_ERROR;
-
-            final CaptureFailure failure = new CaptureFailure(
-                request,
-                reason,
-                /*dropped*/ mayHaveBuffers,
-                requestId,
-                frameNumber);
-
-            Runnable failureDispatch = new Runnable() {
-                @Override
-                public void run() {
-                    if (!CameraDeviceImpl.this.isClosed()){
-                        holder.getCallback().onCaptureFailed(
-                            CameraDeviceImpl.this,
-                            request,
-                            failure);
-                    }
+                final Surface outputSurface =
+                        mConfiguredOutputs.get(resultExtras.getErrorStreamId()).getSurface();
+                if (DEBUG) {
+                    Log.v(TAG, String.format("Lost output buffer reported for frame %d, target %s",
+                            frameNumber, outputSurface));
                 }
-            };
-            holder.getHandler().post(failureDispatch);
+                failureDispatch = new Runnable() {
+                    @Override
+                    public void run() {
+                        if (!CameraDeviceImpl.this.isClosed()){
+                            holder.getCallback().onCaptureBufferLost(
+                                CameraDeviceImpl.this,
+                                request,
+                                outputSurface,
+                                frameNumber);
+                        }
+                    }
+                };
+            } else {
+                boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
 
-            // Fire onCaptureSequenceCompleted if appropriate
-            if (DEBUG) {
-                Log.v(TAG, String.format("got error frame %d", frameNumber));
+                // This is only approximate - exact handling needs the camera service and HAL to
+                // disambiguate between request failures to due abort and due to real errors.  For
+                // now, assume that if the session believes we're mid-abort, then the error is due
+                // to abort.
+                int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
+                        CaptureFailure.REASON_FLUSHED :
+                        CaptureFailure.REASON_ERROR;
+
+                final CaptureFailure failure = new CaptureFailure(
+                    request,
+                    reason,
+                    /*dropped*/ mayHaveBuffers,
+                    requestId,
+                    frameNumber);
+
+                failureDispatch = new Runnable() {
+                    @Override
+                    public void run() {
+                        if (!CameraDeviceImpl.this.isClosed()){
+                            holder.getCallback().onCaptureFailed(
+                                CameraDeviceImpl.this,
+                                request,
+                                failure);
+                        }
+                    }
+                };
+
+                // Fire onCaptureSequenceCompleted if appropriate
+                if (DEBUG) {
+                    Log.v(TAG, String.format("got error frame %d", frameNumber));
+                }
+                mFrameNumberTracker.updateTracker(frameNumber, /*error*/true, request.isReprocess());
+                checkAndFireSequenceComplete();
             }
-            mFrameNumberTracker.updateTracker(frameNumber, /*error*/true, request.isReprocess());
-            checkAndFireSequenceComplete();
+
+            // Dispatch the failure callback
+            holder.getHandler().post(failureDispatch);
         }
 
     } // public class CameraDeviceCallbacks
@@ -2039,4 +2008,28 @@
         return mCharacteristics;
     }
 
+    /**
+     * Listener for binder death.
+     *
+     * <p> Handle binder death for ICameraDeviceUser. Trigger onError.</p>
+     */
+    public void binderDied() {
+        Log.w(TAG, "CameraDevice " + mCameraId + " died unexpectedly");
+
+        if (mRemoteDevice == null) {
+            return; // Camera already closed
+        }
+
+        mInError = true;
+        Runnable r = new Runnable() {
+            @Override
+            public void run() {
+                if (!isClosed()) {
+                    mDeviceCallback.onError(CameraDeviceImpl.this,
+                            CameraDeviceCallbacks.ERROR_CAMERA_SERVICE);
+                }
+            }
+        };
+        CameraDeviceImpl.this.mDeviceHandler.post(r);
+    }
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
deleted file mode 100644
index 4a89129..0000000
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
+++ /dev/null
@@ -1,20 +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;
-
-/** @hide */
-parcelable CameraMetadataNative;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 12a2910..79eac26 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -58,6 +58,7 @@
 import android.location.LocationManager;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.Size;
 
@@ -363,13 +364,24 @@
      * Set the global client-side vendor tag descriptor to allow use of vendor
      * tags in camera applications.
      *
-     * @return int A native status_t value corresponding to one of the
-     * {@link CameraBinderDecorator} integer constants.
-     * @see CameraBinderDecorator#throwOnError
-     *
+     * @throws ServiceSpecificException
      * @hide
      */
-    public static native int nativeSetupGlobalVendorTagDescriptor();
+    public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException {
+        int err = nativeSetupGlobalVendorTagDescriptor();
+        if (err != 0) {
+            throw new ServiceSpecificException(err, "Failure to set up global vendor tags");
+        }
+    }
+
+    /**
+     * Set the global client-side vendor tag descriptor to allow use of vendor
+     * tags in camera applications.
+     *
+     * @return int An error code corresponding to one of the
+     * {@link ICameraService} error constants, or 0 on success.
+     */
+    private static native int nativeSetupGlobalVendorTagDescriptor();
 
     /**
      * Set a camera metadata field to a value. The field definitions can be
diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
deleted file mode 100644
index ebc812a..0000000
--- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.impl;
-
-/** @hide */
-parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
index d859da7..40535e2 100644
--- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
@@ -28,6 +28,7 @@
     private int precaptureTriggerId;
     private long frameNumber;
     private int partialResultCount;
+    private int errorStreamId;
 
     public static final Parcelable.Creator<CaptureResultExtras> CREATOR =
             new Parcelable.Creator<CaptureResultExtras>() {
@@ -48,13 +49,14 @@
 
     public CaptureResultExtras(int requestId, int subsequenceId, int afTriggerId,
                                int precaptureTriggerId, long frameNumber,
-                               int partialResultCount) {
+                               int partialResultCount, int errorStreamId) {
         this.requestId = requestId;
         this.subsequenceId = subsequenceId;
         this.afTriggerId = afTriggerId;
         this.precaptureTriggerId = precaptureTriggerId;
         this.frameNumber = frameNumber;
         this.partialResultCount = partialResultCount;
+        this.errorStreamId = errorStreamId;
     }
 
     @Override
@@ -70,6 +72,7 @@
         dest.writeInt(precaptureTriggerId);
         dest.writeLong(frameNumber);
         dest.writeInt(partialResultCount);
+        dest.writeInt(errorStreamId);
     }
 
     public void readFromParcel(Parcel in) {
@@ -79,6 +82,7 @@
         precaptureTriggerId = in.readInt();
         frameNumber = in.readLong();
         partialResultCount = in.readInt();
+        errorStreamId = in.readInt();
     }
 
     public int getRequestId() {
@@ -104,4 +108,8 @@
     public int getPartialResultCount() {
         return partialResultCount;
     }
+
+    public int getErrorStreamId() {
+        return errorStreamId;
+    }
 }
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
new file mode 100644
index 0000000..ef5f6d7
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
+import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
+
+import android.hardware.ICameraService;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.utils.SubmitInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.Surface;
+
+/**
+ * A wrapper around ICameraDeviceUser.
+ *
+ * Mainly used to convert ServiceSpecificExceptions to the correct
+ * checked / unchecked exception.
+ *
+ * @hide
+ */
+public class ICameraDeviceUserWrapper {
+
+    private final ICameraDeviceUser mRemoteDevice;
+
+    public ICameraDeviceUserWrapper(ICameraDeviceUser remoteDevice) {
+        if (remoteDevice == null) {
+            throw new NullPointerException("Remote device may not be null");
+        }
+        mRemoteDevice = remoteDevice;
+    }
+
+    public void unlinkToDeath(IBinder.DeathRecipient recipient, int flags) {
+        if (mRemoteDevice.asBinder() != null) {
+            mRemoteDevice.asBinder().unlinkToDeath(recipient, flags);
+        }
+    }
+
+    public void disconnect()  {
+        try {
+            mRemoteDevice.disconnect();
+        } catch (RemoteException t) {
+            // ignore binder errors for disconnect
+        }
+    }
+
+    public SubmitInfo submitRequest(CaptureRequest request, boolean streaming)
+            throws CameraAccessException  {
+        try {
+            return mRemoteDevice.submitRequest(request, streaming);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean streaming)
+            throws CameraAccessException {
+        try {
+            return mRemoteDevice.submitRequestList(requestList, streaming);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public long cancelRequest(int requestId) throws CameraAccessException {
+        try {
+            return mRemoteDevice.cancelRequest(requestId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void beginConfigure() throws CameraAccessException {
+        try {
+            mRemoteDevice.beginConfigure();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void endConfigure(boolean isConstrainedHighSpeed) throws CameraAccessException {
+        try {
+            mRemoteDevice.endConfigure(isConstrainedHighSpeed);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void deleteStream(int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.deleteStream(streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public int createStream(OutputConfiguration outputConfiguration)
+            throws CameraAccessException {
+        try {
+            return mRemoteDevice.createStream(outputConfiguration);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public int createInputStream(int width, int height, int format) throws CameraAccessException {
+        try {
+            return mRemoteDevice.createInputStream(width, height, format);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public Surface getInputSurface() throws CameraAccessException {
+        try {
+            return mRemoteDevice.getInputSurface();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public CameraMetadataNative createDefaultRequest(int templateId) throws CameraAccessException {
+        try {
+            return mRemoteDevice.createDefaultRequest(templateId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public CameraMetadataNative getCameraInfo() throws CameraAccessException {
+        try {
+            return mRemoteDevice.getCameraInfo();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void waitUntilIdle() throws CameraAccessException {
+        try {
+            mRemoteDevice.waitUntilIdle();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public long flush() throws CameraAccessException {
+        try {
+            return mRemoteDevice.flush();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void prepare(int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.prepare(streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void tearDown(int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.tearDown(streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void prepare2(int maxCount, int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.prepare2(maxCount, streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+
+}
diff --git a/core/java/android/hardware/camera2/legacy/BurstHolder.java b/core/java/android/hardware/camera2/legacy/BurstHolder.java
index e7b3682..23efe15 100644
--- a/core/java/android/hardware/camera2/legacy/BurstHolder.java
+++ b/core/java/android/hardware/camera2/legacy/BurstHolder.java
@@ -35,10 +35,10 @@
      *
      * @param requestId id of the burst request.
      * @param repeating true if this burst is repeating.
-     * @param requests a {@link List} of {@link CaptureRequest}s in this burst.
+     * @param requests the array of {@link CaptureRequest}s for this burst.
      * @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs.
      */
-    public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests,
+    public BurstHolder(int requestId, boolean repeating, CaptureRequest[] requests,
                        Collection<Long> jpegSurfaceIds) {
         mRequestBuilders = new ArrayList<>();
         int i = 0;
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index 2c2ad1c..b0b94e3 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -70,7 +70,7 @@
      * CameraDeviceStateListener callbacks to be called after state transitions.
      */
     public interface CameraDeviceStateListener {
-        void onError(int errorCode, RequestHolder holder);
+        void onError(int errorCode, Object errorArg, RequestHolder holder);
         void onConfiguring();
         void onIdle();
         void onBusy();
@@ -162,11 +162,12 @@
      * @param captureError Report a recoverable error for a single buffer or result using a valid
      *                     error code for {@code ICameraDeviceCallbacks}, or
      *                     {@link #NO_CAPTURE_ERROR}.
+     * @param captureErrorArg An argument for some error captureError codes.
      * @return {@code false} if an error has occurred.
      */
     public synchronized boolean setCaptureResult(final RequestHolder request,
-                                             final CameraMetadataNative result,
-                                             final int captureError) {
+            final CameraMetadataNative result,
+            final int captureError, final Object captureErrorArg) {
         if (mCurrentState != STATE_CAPTURING) {
             Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
             mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
@@ -179,7 +180,7 @@
                 mCurrentHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        mCurrentListener.onError(captureError, request);
+                        mCurrentListener.onError(captureError, captureErrorArg, request);
                     }
                 });
             } else {
@@ -194,6 +195,11 @@
         return mCurrentError == NO_CAPTURE_ERROR;
     }
 
+    public synchronized boolean setCaptureResult(final RequestHolder request,
+            final CameraMetadataNative result) {
+        return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
+    }
+
     /**
      * Set the listener for state transition callbacks.
      *
@@ -239,7 +245,7 @@
                     mCurrentHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            mCurrentListener.onError(mCurrentError, mCurrentRequest);
+                            mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest);
                         }
                     });
                 }
@@ -299,7 +305,7 @@
                         mCurrentHandler.post(new Runnable() {
                             @Override
                             public void run() {
-                                mCurrentListener.onError(error, mCurrentRequest);
+                                mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest);
                             }
                         });
                     } else {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 798c941..f99928a 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2.legacy;
 
+import android.hardware.ICameraService;
 import android.hardware.Camera;
 import android.hardware.Camera.CameraInfo;
 import android.hardware.camera2.CameraAccessException;
@@ -23,12 +24,10 @@
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.utils.LongParcelable;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.os.ConditionVariable;
 import android.os.IBinder;
 import android.os.Looper;
@@ -36,6 +35,7 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Surface;
@@ -93,7 +93,7 @@
 
     private static int translateErrorsFromCamera1(int errorCode) {
         if (errorCode == -EACCES) {
-            return CameraBinderDecorator.PERMISSION_DENIED;
+            return ICameraService.ERROR_PERMISSION_DENIED;
         }
 
         return errorCode;
@@ -173,7 +173,7 @@
          *
          * @return int error code
          *
-         * @throws CameraRuntimeException if the camera open times out with ({@code CAMERA_ERROR})
+         * @throws ServiceSpecificException if the camera open times out with ({@code CAMERA_ERROR})
          */
         public int waitForOpen(int timeoutMs) {
             // Block until the camera is open asynchronously
@@ -186,7 +186,7 @@
                     Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
                 }
 
-                throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION);
             }
 
             return mInitErrors;
@@ -344,7 +344,7 @@
         Camera legacyCamera = init.getCamera();
 
         // Check errors old HAL initialization
-        CameraBinderDecorator.throwOnError(initErrors);
+        LegacyExceptionUtils.throwOnServiceError(initErrors);
 
         // Disable shutter sounds (this will work unconditionally) for api2 clients
         legacyCamera.disableShutterSound();
@@ -356,8 +356,8 @@
         try {
             legacyParameters = legacyCamera.getParameters();
         } catch (RuntimeException e) {
-            throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR,
-                    "Unable to get initial parameters", e);
+            throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
+                    "Unable to get initial parameters: " + e.getMessage());
         }
 
         CameraCharacteristics characteristics =
@@ -386,137 +386,140 @@
     }
 
     @Override
-    public int submitRequest(CaptureRequest request, boolean streaming,
-                             /*out*/LongParcelable lastFrameNumber) {
+    public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
         if (DEBUG) {
             Log.d(TAG, "submitRequest called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot submit request, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot submit request, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot submit request, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot submit request, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        return mLegacyDevice.submitRequest(request, streaming, lastFrameNumber);
+        return mLegacyDevice.submitRequest(request, streaming);
     }
 
     @Override
-    public int submitRequestList(List<CaptureRequest> request, boolean streaming,
-                                 /*out*/LongParcelable lastFrameNumber) {
+    public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
         if (DEBUG) {
             Log.d(TAG, "submitRequestList called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot submit request list, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot submit request list, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot submit request, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot submit request, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        return mLegacyDevice.submitRequestList(request, streaming, lastFrameNumber);
+        return mLegacyDevice.submitRequestList(request, streaming);
     }
 
     @Override
-    public int cancelRequest(int requestId, /*out*/LongParcelable lastFrameNumber) {
+    public long cancelRequest(int requestId) {
         if (DEBUG) {
             Log.d(TAG, "cancelRequest called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot cancel request, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot cancel request, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot cancel request, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot cancel request, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        long lastFrame = mLegacyDevice.cancelRequest(requestId);
-        lastFrameNumber.setNumber(lastFrame);
-        return CameraBinderDecorator.NO_ERROR;
+        return mLegacyDevice.cancelRequest(requestId);
     }
 
     @Override
-    public int beginConfigure() {
+    public void beginConfigure() {
         if (DEBUG) {
             Log.d(TAG, "beginConfigure called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot begin configure, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot begin configure, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot begin configure, configuration change already in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot begin configure, configuration change already in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
             mConfiguring = true;
         }
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
-    public int endConfigure(boolean isConstrainedHighSpeed) {
+    public void endConfigure(boolean isConstrainedHighSpeed) {
         if (DEBUG) {
             Log.d(TAG, "endConfigure called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot end configure, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot end configure, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
-        ArrayList<Surface> surfaces = null;
+        SparseArray<Surface> surfaces = null;
         synchronized(mConfigureLock) {
             if (!mConfiguring) {
-                Log.e(TAG, "Cannot end configure, no configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot end configure, no configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
-            int numSurfaces = mSurfaces.size();
-            if (numSurfaces > 0) {
-                surfaces = new ArrayList<>();
-                for (int i = 0; i < numSurfaces; ++i) {
-                    surfaces.add(mSurfaces.valueAt(i));
-                }
+            if (mSurfaces != null) {
+                surfaces = mSurfaces.clone();
             }
             mConfiguring = false;
         }
-        return mLegacyDevice.configureOutputs(surfaces);
+        mLegacyDevice.configureOutputs(surfaces);
     }
 
     @Override
-    public int deleteStream(int streamId) {
+    public void deleteStream(int streamId) {
         if (DEBUG) {
             Log.d(TAG, "deleteStream called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot delete stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot delete stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (!mConfiguring) {
-                Log.e(TAG, "Cannot delete stream, beginConfigure hasn't been called yet.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot delete stream, no configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
             int index = mSurfaces.indexOfKey(streamId);
             if (index < 0) {
-                Log.e(TAG, "Cannot delete stream, stream id " + streamId + " doesn't exist.");
-                return CameraBinderDecorator.BAD_VALUE;
+                String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
             }
             mSurfaces.removeAt(index);
         }
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
@@ -525,18 +528,21 @@
             Log.d(TAG, "createStream called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot create stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot create stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (!mConfiguring) {
-                Log.e(TAG, "Cannot create stream, beginConfigure hasn't been called yet.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot create stream, beginConfigure hasn't been called yet.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
             if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
-                Log.e(TAG, "Cannot create stream, stream rotation is not supported.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot create stream, stream rotation is not supported.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
             }
             int id = ++mSurfaceIdCounter;
             mSurfaces.put(id, outputConfiguration.getSurface());
@@ -546,24 +552,27 @@
 
     @Override
     public int createInputStream(int width, int height, int format) {
-        Log.e(TAG, "creating input stream is not supported on legacy devices");
-        return CameraBinderDecorator.INVALID_OPERATION;
+        String err = "Creating input stream is not supported on legacy devices";
+        Log.e(TAG, err);
+        throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
     }
 
     @Override
-    public int getInputSurface(/*out*/ Surface surface) {
-        Log.e(TAG, "getting input surface is not supported on legacy devices");
-        return CameraBinderDecorator.INVALID_OPERATION;
+    public Surface getInputSurface() {
+        String err = "Getting input surface is not supported on legacy devices";
+        Log.e(TAG, err);
+        throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
     }
 
     @Override
-    public int createDefaultRequest(int templateId, /*out*/CameraMetadataNative request) {
+    public CameraMetadataNative createDefaultRequest(int templateId) {
         if (DEBUG) {
             Log.d(TAG, "createDefaultRequest called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot create default request, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot create default request, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         CameraMetadataNative template;
@@ -571,99 +580,96 @@
             template =
                     LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "createDefaultRequest - invalid templateId specified");
-            return CameraBinderDecorator.BAD_VALUE;
+            String err = "createDefaultRequest - invalid templateId specified";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
         }
 
-        request.swap(template);
-        return CameraBinderDecorator.NO_ERROR;
+        return template;
     }
 
     @Override
-    public int getCameraInfo(/*out*/CameraMetadataNative info) {
+    public CameraMetadataNative getCameraInfo() {
         if (DEBUG) {
             Log.d(TAG, "getCameraInfo called.");
         }
         // TODO: implement getCameraInfo.
         Log.e(TAG, "getCameraInfo unimplemented.");
-        return CameraBinderDecorator.NO_ERROR;
+        return null;
     }
 
     @Override
-    public int waitUntilIdle() throws RemoteException {
+    public void waitUntilIdle() throws RemoteException {
         if (DEBUG) {
             Log.d(TAG, "waitUntilIdle called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot wait until idle, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot wait until idle, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot wait until idle, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot wait until idle, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
         mLegacyDevice.waitUntilIdle();
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
-    public int flush(/*out*/LongParcelable lastFrameNumber) {
+    public long flush() {
         if (DEBUG) {
             Log.d(TAG, "flush called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot flush, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot flush, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot flush, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot flush, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        long lastFrame = mLegacyDevice.flush();
-        if (lastFrameNumber != null) {
-            lastFrameNumber.setNumber(lastFrame);
-        }
-        return CameraBinderDecorator.NO_ERROR;
+        return mLegacyDevice.flush();
     }
 
-    public int prepare(int streamId) {
+    public void prepare(int streamId) {
         if (DEBUG) {
             Log.d(TAG, "prepare called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot prepare stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot prepare stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         // LEGACY doesn't support actual prepare, just signal success right away
         mCameraCallbacks.onPrepared(streamId);
-
-        return CameraBinderDecorator.NO_ERROR;
     }
 
-    public int prepare2(int maxCount, int streamId) {
+    public void prepare2(int maxCount, int streamId) {
         // We don't support this in LEGACY mode.
-        return prepare(streamId);
+        prepare(streamId);
     }
 
-    public int tearDown(int streamId) {
+    public void tearDown(int streamId) {
         if (DEBUG) {
             Log.d(TAG, "tearDown called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot tear down stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot tear down stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         // LEGACY doesn't support actual teardown, so just a no-op
-
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
index eb48a01..113927c 100644
--- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java
+++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
@@ -19,7 +19,7 @@
 import android.util.Log;
 import android.util.MutableLong;
 import android.util.Pair;
-
+import android.view.Surface;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.TreeSet;
@@ -95,22 +95,28 @@
                     } else {
                         // Send buffer dropped errors for each pending buffer if the request has
                         // started.
-                        if (mFailedPreview) {
-                            Log.w(TAG, "Preview buffers dropped for request: " +
-                                    mRequest.getRequestId());
-                            for (int i = 0; i < mRequest.numPreviewTargets(); i++) {
-                                CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
-                                    /*result*/null,
-                                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
-                            }
-                        }
-                        if (mFailedJpeg) {
-                            Log.w(TAG, "Jpeg buffers dropped for request: " +
-                                    mRequest.getRequestId());
-                            for (int i = 0; i < mRequest.numJpegTargets(); i++) {
-                                CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
-                                    /*result*/null,
-                                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
+                        for (Surface targetSurface : mRequest.getRequest().getTargets() ) {
+                            try {
+                                if (mRequest.jpegType(targetSurface)) {
+                                    if (mFailedJpeg) {
+                                        CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+                                                /*result*/null,
+                                                CameraDeviceImpl.CameraDeviceCallbacks.
+                                                        ERROR_CAMERA_BUFFER,
+                                                targetSurface);
+                                    }
+                                } else {
+                                    // preview buffer
+                                    if (mFailedPreview) {
+                                        CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+                                                /*result*/null,
+                                                CameraDeviceImpl.CameraDeviceCallbacks.
+                                                        ERROR_CAMERA_BUFFER,
+                                                targetSurface);
+                                    }
+                                }
+                            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                                Log.e(TAG, "Unexpected exception when querying Surface: " + e);
                             }
                         }
                     }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index fddfbde..6c95869 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -26,17 +26,17 @@
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.ArrayUtils;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.utils.CameraRuntimeException;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Size;
+import android.util.SparseArray;
 import android.view.Surface;
 
 import java.util.ArrayList;
@@ -45,7 +45,6 @@
 import java.util.List;
 
 import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
-import static android.hardware.camera2.utils.CameraBinderDecorator.*;
 import static com.android.internal.util.Preconditions.*;
 
 /**
@@ -66,7 +65,7 @@
     private final CameraCharacteristics mStaticCharacteristics;
     private final ICameraDeviceCallbacks mDeviceCallbacks;
     private final CameraDeviceState mDeviceState = new CameraDeviceState();
-    private List<Surface> mConfiguredSurfaces;
+    private SparseArray<Surface> mConfiguredSurfaces;
     private boolean mClosed = false;
 
     private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
@@ -91,13 +90,29 @@
     public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
 
     private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
+        return getExtrasFromRequest(holder,
+                /*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
+    }
+
+    private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
+            int errorCode, Object errorArg) {
+        int errorStreamId = -1;
+        if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
+            Surface errorTarget = (Surface) errorArg;
+            int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
+            if (indexOfTarget < 0) {
+                Log.e(TAG, "Buffer drop error reported for unknown Surface");
+            } else {
+                errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
+            }
+        }
         if (holder == null) {
             return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
-                    ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
+                    ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
         }
         return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
                 /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
-                /*partialResultCount*/1);
+                /*partialResultCount*/1, errorStreamId);
     }
 
     /**
@@ -107,9 +122,9 @@
     private final CameraDeviceState.CameraDeviceStateListener mStateListener =
             new CameraDeviceState.CameraDeviceStateListener() {
         @Override
-        public void onError(final int errorCode, final RequestHolder holder) {
+        public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
             if (DEBUG) {
-                Log.d(TAG, "onError called, errorCode = " + errorCode);
+                Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
             }
             switch (errorCode) {
                 /*
@@ -127,7 +142,7 @@
                 }
             }
 
-            final CaptureResultExtras extras = getExtrasFromRequest(holder);
+            final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
             mResultHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -283,14 +298,17 @@
      *
      * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
      *
-     * @param outputs a list of surfaces to set.
+     * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
+     *          list; it must not be modified by the caller once it's passed in.
      * @return an error code for this binder operation, or {@link NO_ERROR}
      *          on success.
      */
-    public int configureOutputs(List<Surface> outputs) {
+    public int configureOutputs(SparseArray<Surface> outputs) {
         List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
         if (outputs != null) {
-            for (Surface output : outputs) {
+            int count = outputs.size();
+            for (int i = 0; i < count; i++)  {
+                Surface output = outputs.valueAt(i);
                 if (output == null) {
                     Log.e(TAG, "configureOutputs - null outputs are not allowed");
                     return BAD_VALUE;
@@ -355,11 +373,11 @@
         }
 
         if (success) {
-            mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
+            mConfiguredSurfaces = outputs;
         } else {
-            return CameraBinderDecorator.INVALID_OPERATION;
+            return LegacyExceptionUtils.INVALID_OPERATION;
         }
-        return CameraBinderDecorator.NO_ERROR;
+        return LegacyExceptionUtils.NO_ERROR;
     }
 
     /**
@@ -367,17 +385,16 @@
      *
      * @param requestList a list of capture requests to execute.
      * @param repeating {@code true} if this burst is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    burst is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public int submitRequestList(List<CaptureRequest> requestList, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
-        if (requestList == null || requestList.isEmpty()) {
+    public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) {
+        if (requestList == null || requestList.length == 0) {
             Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
-            return BAD_VALUE;
+            throw new ServiceSpecificException(BAD_VALUE,
+                    "submitRequestList - Empty/null requests are not allowed");
         }
 
         List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
@@ -388,28 +405,33 @@
             if (request.getTargets().isEmpty()) {
                 Log.e(TAG, "submitRequestList - "
                         + "Each request must have at least one Surface target");
-                return BAD_VALUE;
+                throw new ServiceSpecificException(BAD_VALUE,
+                        "submitRequestList - "
+                        + "Each request must have at least one Surface target");
             }
 
             for (Surface surface : request.getTargets()) {
                 if (surface == null) {
                     Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
-                    return BAD_VALUE;
+                    throw new ServiceSpecificException(BAD_VALUE,
+                            "submitRequestList - Null Surface targets are not allowed");
                 } else if (mConfiguredSurfaces == null) {
                     Log.e(TAG, "submitRequestList - must configure " +
                             " device with valid surfaces before submitting requests");
-                    return INVALID_OPERATION;
+                    throw new ServiceSpecificException(INVALID_OPERATION,
+                            "submitRequestList - must configure " +
+                            " device with valid surfaces before submitting requests");
                 } else if (!containsSurfaceId(surface, surfaceIds)) {
                     Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
-                    return BAD_VALUE;
+                    throw new ServiceSpecificException(BAD_VALUE,
+                            "submitRequestList - cannot use a surface that wasn't configured");
                 }
             }
         }
 
         // TODO: further validation of request here
         mIdle.close();
-        return mRequestThreadManager.submitCaptureRequests(requestList, repeating,
-                frameNumber);
+        return mRequestThreadManager.submitCaptureRequests(requestList, repeating);
     }
 
     /**
@@ -417,17 +439,14 @@
      *
      * @param request the capture request to execute.
      * @param repeating {@code true} if this request is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    request is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public int submitRequest(CaptureRequest request, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
-        ArrayList<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
-        requestList.add(request);
-        return submitRequestList(requestList, repeating, frameNumber);
+    public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) {
+        CaptureRequest[] requestList = { request };
+        return submitRequestList(requestList, repeating);
     }
 
     /**
@@ -493,7 +512,7 @@
     protected void finalize() throws Throwable {
         try {
             close();
-        } catch (CameraRuntimeException e) {
+        } catch (ServiceSpecificException e) {
             Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
         } finally {
             super.finalize();
@@ -615,14 +634,16 @@
         return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
     }
 
-    static void configureSurface(Surface surface, int width, int height,
-                                 int pixelFormat) throws BufferQueueAbandonedException {
+    static void connectSurface(Surface surface) throws BufferQueueAbandonedException {
         checkNotNull(surface);
-        checkArgumentPositive(width, "width must be positive.");
-        checkArgumentPositive(height, "height must be positive.");
 
-        LegacyExceptionUtils.throwOnError(nativeConfigureSurface(surface, width, height,
-                pixelFormat));
+        LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface));
+    }
+
+    static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException {
+        if (surface == null) return;
+
+        LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface));
     }
 
     static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
@@ -658,6 +679,23 @@
         return nativeGetSurfaceId(surface);
     }
 
+    static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) {
+        if (surfaces == null) {
+            throw new NullPointerException("Null argument surfaces");
+        }
+        List<Long> surfaceIds = new ArrayList<>();
+        int count = surfaces.size();
+        for (int i = 0; i < count; i++) {
+            long id = getSurfaceId(surfaces.valueAt(i));
+            if (id == 0) {
+                throw new IllegalStateException(
+                        "Configured surface had null native GraphicBufferProducer pointer!");
+            }
+            surfaceIds.add(id);
+        }
+        return surfaceIds;
+    }
+
     static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
         if (surfaces == null) {
             throw new NullPointerException("Null argument surfaces");
@@ -717,8 +755,7 @@
     private static native int nativeDetectSurfaceDimens(Surface surface,
             /*out*/int[/*2*/] dimens);
 
-    private static native int nativeConfigureSurface(Surface surface, int width, int height,
-                                                        int pixelFormat);
+    private static native int nativeConnectSurface(Surface surface);
 
     private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
                                                     int height, int pixelFormat);
@@ -741,5 +778,7 @@
 
     private static native int nativeSetScalingMode(Surface surface, int scalingMode);
 
+    private static native int nativeDisconnectSurface(Surface surface);
+
     static native int nativeGetJpegFooterSize();
 }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
index 4501e81..93d6001 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
@@ -16,10 +16,11 @@
 
 package android.hardware.camera2.legacy;
 
-import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.ICameraService;
+import android.os.ServiceSpecificException;
 import android.util.AndroidException;
 
-import static android.system.OsConstants.ENODEV;
+import static android.system.OsConstants.*;
 
 /**
  * Utility class containing exception handling used solely by the compatibility mode shim.
@@ -27,6 +28,14 @@
 public class LegacyExceptionUtils {
     private static final String TAG = "LegacyExceptionUtils";
 
+    public static final int NO_ERROR = 0;
+    public static final int PERMISSION_DENIED = -EPERM;
+    public static final int ALREADY_EXISTS = -EEXIST;
+    public static final int BAD_VALUE = -EINVAL;
+    public static final int DEAD_OBJECT = -ENOSYS;
+    public static final int INVALID_OPERATION = -EPIPE;
+    public static final int TIMED_OUT = -ETIMEDOUT;
+
     /**
      * Checked exception thrown when a BufferQueue has been abandoned by its consumer.
      */
@@ -58,8 +67,8 @@
      * @return {@code errorFlag} if the value was non-negative, throws otherwise.
      */
     public static int throwOnError(int errorFlag) throws BufferQueueAbandonedException {
-        if (errorFlag == CameraBinderDecorator.NO_ERROR) {
-            return CameraBinderDecorator.NO_ERROR;
+        if (errorFlag == NO_ERROR) {
+            return NO_ERROR;
         } else if (errorFlag == -ENODEV) {
             throw new BufferQueueAbandonedException();
         }
@@ -70,6 +79,59 @@
         return errorFlag;
     }
 
+    /**
+     * Throw error codes returned by the camera service as exceptions.
+     *
+     * @param errorFlag error to throw as an exception.
+     */
+    public static void throwOnServiceError(int errorFlag) {
+        int errorCode = ICameraService.ERROR_INVALID_OPERATION;
+        String errorMsg;
+
+        if (errorFlag >= NO_ERROR) {
+            return;
+        } else if (errorFlag == PERMISSION_DENIED) {
+            errorCode = ICameraService.ERROR_PERMISSION_DENIED;
+            errorMsg = "Lacking privileges to access camera service";
+        } else if (errorFlag == ALREADY_EXISTS) {
+            // This should be handled at the call site. Typically this isn't bad,
+            // just means we tried to do an operation that already completed.
+            return;
+        } else if (errorFlag == BAD_VALUE) {
+            errorCode = ICameraService.ERROR_ILLEGAL_ARGUMENT;
+            errorMsg = "Bad argument passed to camera service";
+        } else if (errorFlag == DEAD_OBJECT) {
+            errorCode = ICameraService.ERROR_DISCONNECTED;
+            errorMsg = "Camera service not available";
+        } else if (errorFlag == TIMED_OUT) {
+            errorCode = ICameraService.ERROR_INVALID_OPERATION;
+            errorMsg = "Operation timed out in camera service";
+        } else if (errorFlag == -EACCES) {
+            errorCode = ICameraService.ERROR_DISABLED;
+            errorMsg = "Camera disabled by policy";
+        } else if (errorFlag == -EBUSY) {
+            errorCode = ICameraService.ERROR_CAMERA_IN_USE;
+            errorMsg = "Camera already in use";
+        } else if (errorFlag == -EUSERS) {
+            errorCode = ICameraService.ERROR_MAX_CAMERAS_IN_USE;
+            errorMsg = "Maximum number of cameras in use";
+        } else if (errorFlag == -ENODEV) {
+            errorCode = ICameraService.ERROR_DISCONNECTED;
+            errorMsg = "Camera device not available";
+        } else if (errorFlag == -EOPNOTSUPP) {
+            errorCode = ICameraService.ERROR_DEPRECATED_HAL;
+            errorMsg = "Deprecated camera HAL does not support this";
+        } else if (errorFlag == INVALID_OPERATION) {
+            errorCode = ICameraService.ERROR_INVALID_OPERATION;
+            errorMsg = "Illegal state encountered in camera service.";
+        } else {
+            errorCode = ICameraService.ERROR_INVALID_OPERATION;
+            errorMsg = "Unknown camera device error " + errorFlag;
+        }
+
+        throw new ServiceSpecificException(errorCode, errorMsg);
+    }
+
     private LegacyExceptionUtils() {
         throw new AssertionError();
     }
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
index 9b628fb..476c3de 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java
@@ -41,6 +41,8 @@
     private final int mNumPreviewTargets;
     private volatile boolean mFailed = false;
 
+    private final Collection<Long> mJpegSurfaceIds;
+
     /**
      * A builder class for {@link RequestHolder} objects.
      *
@@ -150,13 +152,13 @@
          */
         public RequestHolder build(long frameNumber) {
             return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
-                    mNumJpegTargets, mNumPreviewTargets);
+                    mNumJpegTargets, mNumPreviewTargets, mJpegSurfaceIds);
         }
     }
 
     private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
                           boolean repeating, long frameNumber, int numJpegTargets,
-                          int numPreviewTargets) {
+                          int numPreviewTargets, Collection<Long> jpegSurfaceIds) {
         mRepeating = repeating;
         mRequest = request;
         mRequestId = requestId;
@@ -164,6 +166,7 @@
         mFrameNumber = frameNumber;
         mNumJpegTargets = numJpegTargets;
         mNumPreviewTargets = numPreviewTargets;
+        mJpegSurfaceIds = jpegSurfaceIds;
     }
 
     /**
@@ -238,6 +241,17 @@
     }
 
     /**
+     * Returns true if the given surface requires jpeg buffers.
+     *
+     * @param s a {@link android.view.Surface} to check.
+     * @return true if the surface requires a jpeg buffer.
+     */
+    public boolean jpegType(Surface s)
+            throws LegacyExceptionUtils.BufferQueueAbandonedException {
+        return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
+    }
+
+    /**
      * Mark this request as failed.
      */
     public void failRequest() {
diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java
index c995029..8f252a1 100644
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java
@@ -16,7 +16,7 @@
 package android.hardware.camera2.legacy;
 
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.util.Log;
 import android.util.Pair;
 
@@ -111,31 +111,29 @@
      *
      * @param requests the burst of requests to add to the queue.
      * @param repeating true if the burst is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    burst is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
+    public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) {
         int requestId = mCurrentRequestId++;
         BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
-        long ret = INVALID_FRAME;
+        long lastFrame = INVALID_FRAME;
         if (burst.isRepeating()) {
             Log.i(TAG, "Repeating capture request set.");
             if (mRepeatingRequest != null) {
-                ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
+                lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
                         mCurrentRepeatingFrameNumber - 1;
             }
             mCurrentRepeatingFrameNumber = INVALID_FRAME;
             mRepeatingRequest = burst;
         } else {
             mRequestQueue.offer(burst);
-            ret = calculateLastFrame(burst.getRequestId());
+            lastFrame = calculateLastFrame(burst.getRequestId());
         }
-        frameNumber.setNumber(ret);
-        return requestId;
+        SubmitInfo info = new SubmitInfo(requestId, lastFrame);
+        return info;
     }
 
     private long calculateLastFrame(int requestId) {
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 4866598..a3fdd56 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -21,7 +21,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.utils.SizeAreaComparator;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.os.ConditionVariable;
@@ -365,6 +365,14 @@
             mGLThreadManager.waitUntilIdle();
         }
         resetJpegSurfaceFormats(mCallbackOutputs);
+
+        for (Surface s : mCallbackOutputs) {
+            try {
+                LegacyCameraDevice.disconnectSurface(s);
+            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                Log.w(TAG, "Surface abandoned, skipping...", e);
+            }
+        }
         mPreviewOutputs.clear();
         mCallbackOutputs.clear();
         mJpegSurfaceIds.clear();
@@ -392,6 +400,10 @@
                             mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s));
                             mCallbackOutputs.add(s);
                             callbackOutputSizes.add(outSize);
+
+                            // LegacyCameraDevice is the producer of JPEG output surfaces
+                            // so LegacyCameraDevice needs to connect to the surfaces.
+                            LegacyCameraDevice.connectSurface(s);
                             break;
                         default:
                             LegacyCameraDevice.setScalingMode(s, LegacyCameraDevice.
@@ -896,8 +908,7 @@
                         mFaceDetectMapper.mapResultFaces(result, mLastRequest);
 
                         if (!holder.requestFailed()) {
-                            mDeviceState.setCaptureResult(holder, result,
-                                    CameraDeviceState.NO_CAPTURE_ERROR);
+                            mDeviceState.setCaptureResult(holder, result);
                         }
                     }
                     if (DEBUG) {
@@ -1008,21 +1019,19 @@
      *
      * @param requests the burst of requests to add to the queue.
      * @param repeating true if the burst is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    burst is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public int submitCaptureRequests(List<CaptureRequest> requests, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
+    public SubmitInfo submitCaptureRequests(CaptureRequest[] requests, boolean repeating) {
         Handler handler = mRequestThread.waitAndGetHandler();
-        int ret;
+        SubmitInfo info;
         synchronized (mIdleLock) {
-            ret = mRequestQueue.submit(requests, repeating, frameNumber);
+            info = mRequestQueue.submit(requests, repeating);
             handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
         }
-        return ret;
+        return info;
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index bc80fc1..70bc2fd 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -401,6 +401,13 @@
 
     private void clearState() {
         mSurfaces.clear();
+        for (EGLSurfaceHolder holder : mConversionSurfaces) {
+            try {
+                LegacyCameraDevice.disconnectSurface(holder.surface);
+            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                Log.w(TAG, "Surface abandoned, skipping...", e);
+            }
+        }
         mConversionSurfaces.clear();
         mPBufferPixels = null;
         if (mSurfaceTexture != null) {
@@ -631,6 +638,9 @@
                 holder.height = surfaceSize.getHeight();
                 if (LegacyCameraDevice.needsConversion(s)) {
                     mConversionSurfaces.add(holder);
+                    // LegacyCameraDevice is the producer of surfaces if it's not handled by EGL,
+                    // so LegacyCameraDevice needs to connect to the surfaces.
+                    LegacyCameraDevice.connectSurface(s);
                 } else {
                     mSurfaces.add(holder);
                 }
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.aidl b/core/java/android/hardware/camera2/params/OutputConfiguration.aidl
deleted file mode 100644
index 0921cd8..0000000
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.params;
-
-/** @hide */
-parcelable OutputConfiguration;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 4407e55..cd0c474 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -21,11 +21,11 @@
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.utils.HashCodeHelpers;
 import android.hardware.camera2.utils.SurfaceUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.Log;
 import android.util.Size;
 import android.view.Surface;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 import static com.android.internal.util.Preconditions.*;
 
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 8be49e8..dfa19b0 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1196,7 +1196,7 @@
      *
      * <p>In particular these formats are converted:
      * <ul>
-     * <li>ImageFormat.JPEG => HAL_DATASPACE_JFIF
+     * <li>ImageFormat.JPEG => HAL_DATASPACE_V0_JFIF
      * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_DATASPACE_DEPTH
      * <li>ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH
      * <li>others => HAL_DATASPACE_UNKNOWN
@@ -1223,7 +1223,7 @@
     static int imageFormatToDataspace(int format) {
         switch (format) {
             case ImageFormat.JPEG:
-                return HAL_DATASPACE_JFIF;
+                return HAL_DATASPACE_V0_JFIF;
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.DEPTH16:
                 return HAL_DATASPACE_DEPTH;
@@ -1269,6 +1269,11 @@
 
     private Size[] getInternalFormatSizes(int format, int dataspace,
             boolean output, boolean highRes) {
+        // All depth formats are non-high-res.
+        if (dataspace == HAL_DATASPACE_DEPTH && highRes) {
+            return new Size[0];
+        }
+
         SparseIntArray formatsMap =
                 !output ? mInputFormats :
                 dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
@@ -1287,6 +1292,8 @@
 
         StreamConfiguration[] configurations =
                 (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+        StreamConfigurationDuration[] minFrameDurations =
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations : mMinFrameDurations;
 
         for (StreamConfiguration config : configurations) {
             int fmt = config.getFormat();
@@ -1295,8 +1302,8 @@
                     // Filter slow high-res output formats; include for
                     // highRes, remove for !highRes
                     long duration = 0;
-                    for (int i = 0; i < mMinFrameDurations.length; i++) {
-                        StreamConfigurationDuration d = mMinFrameDurations[i];
+                    for (int i = 0; i < minFrameDurations.length; i++) {
+                        StreamConfigurationDuration d = minFrameDurations[i];
                         if (d.getFormat() == fmt &&
                                 d.getWidth() == config.getSize().getWidth() &&
                                 d.getHeight() == config.getSize().getHeight()) {
@@ -1304,7 +1311,8 @@
                             break;
                         }
                     }
-                    if (highRes != (duration > DURATION_20FPS_NS)) {
+                    if (dataspace != HAL_DATASPACE_DEPTH &&
+                            highRes != (duration > DURATION_20FPS_NS)) {
                         continue;
                     }
                 }
@@ -1625,8 +1633,16 @@
     private static final int HAL_PIXEL_FORMAT_Y16 = 0x20363159;
 
 
+    private static final int HAL_DATASPACE_STANDARD_SHIFT = 16;
+    private static final int HAL_DATASPACE_TRANSFER_SHIFT = 22;
+    private static final int HAL_DATASPACE_RANGE_SHIFT = 27;
+
     private static final int HAL_DATASPACE_UNKNOWN = 0x0;
-    private static final int HAL_DATASPACE_JFIF = 0x101;
+    private static final int HAL_DATASPACE_V0_JFIF =
+            (2 << HAL_DATASPACE_STANDARD_SHIFT) |
+            (3 << HAL_DATASPACE_TRANSFER_SHIFT) |
+            (1 << HAL_DATASPACE_RANGE_SHIFT);
+
     private static final int HAL_DATASPACE_DEPTH = 0x1000;
 
     private static final long DURATION_20FPS_NS = 50000000L;
diff --git a/core/java/android/hardware/camera2/params/VendorTagDescriptor.java b/core/java/android/hardware/camera2/params/VendorTagDescriptor.java
new file mode 100644
index 0000000..ea424e5
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/VendorTagDescriptor.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class for describing the vendor tags declared by a camera HAL module.
+ * Generally only used by the native side of
+ * android.hardware.camera2.impl.CameraMetadataNative
+ *
+ * @hide
+ */
+public final class VendorTagDescriptor implements Parcelable {
+
+    private VendorTagDescriptor(Parcel source) {
+    }
+
+    public static final Parcelable.Creator<VendorTagDescriptor> CREATOR =
+            new Parcelable.Creator<VendorTagDescriptor>() {
+        @Override
+        public VendorTagDescriptor createFromParcel(Parcel source) {
+            try {
+                VendorTagDescriptor vendorDescriptor = new VendorTagDescriptor(source);
+                return vendorDescriptor;
+            } catch (Exception e) {
+                Log.e(TAG, "Exception creating VendorTagDescriptor from parcel", e);
+                return null;
+            }
+        }
+
+        @Override
+        public VendorTagDescriptor[] newArray(int size) {
+            return new VendorTagDescriptor[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (dest == null) {
+            throw new IllegalArgumentException("dest must not be null");
+        }
+    }
+
+    private static final String TAG = "VendorTagDescriptor";
+}
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.aidl b/core/java/android/hardware/camera2/utils/BinderHolder.aidl
deleted file mode 100644
index f39d645..0000000
--- a/core/java/android/hardware/camera2/utils/BinderHolder.aidl
+++ /dev/null
@@ -1,20 +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.utils;
-
-/** @hide */
-parcelable BinderHolder;
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.java b/core/java/android/hardware/camera2/utils/BinderHolder.java
deleted file mode 100644
index 9eea390..0000000
--- a/core/java/android/hardware/camera2/utils/BinderHolder.java
+++ /dev/null
@@ -1,74 +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.utils;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.IBinder;
-
-/**
- * @hide
- */
-public class BinderHolder implements Parcelable {
-    private IBinder mBinder = null;
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mBinder);
-    }
-
-    public void readFromParcel(Parcel src) {
-        mBinder = src.readStrongBinder();
-    }
-
-    public static final Parcelable.Creator<BinderHolder> CREATOR =
-             new Parcelable.Creator<BinderHolder>() {
-         @Override
-         public BinderHolder createFromParcel(Parcel in) {
-             return new BinderHolder(in);
-         }
-
-         @Override
-         public BinderHolder[] newArray(int size) {
-             return new BinderHolder[size];
-         }
-    };
-
-    public IBinder getBinder() {
-        return mBinder;
-    }
-
-    public void setBinder(IBinder binder) {
-        mBinder = binder;
-    }
-
-    public BinderHolder() {}
-
-    public BinderHolder(IBinder binder) {
-        mBinder = binder;
-    }
-
-    private BinderHolder(Parcel in) {
-        mBinder = in.readStrongBinder();
-    }
-}
-
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
deleted file mode 100644
index 162edc9..0000000
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ /dev/null
@@ -1,162 +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.utils;
-
-import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
-import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
-import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
-import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
-import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
-import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
-import static android.system.OsConstants.*;
-
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-
-import java.lang.reflect.Method;
-
-/**
- * Translate camera device status_t return values into exceptions.
- *
- * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
- * @hide
- */
-public class CameraBinderDecorator {
-
-    public static final int NO_ERROR = 0;
-    public static final int PERMISSION_DENIED = -EPERM;
-    public static final int ALREADY_EXISTS = -EEXIST;
-    public static final int BAD_VALUE = -EINVAL;
-    public static final int DEAD_OBJECT = -ENOSYS;
-    public static final int INVALID_OPERATION = -EPIPE;
-    public static final int TIMED_OUT = -ETIMEDOUT;
-
-    /**
-     * TODO: add as error codes in Errors.h
-     * - POLICY_PROHIBITS
-     * - RESOURCE_BUSY
-     * - NO_SUCH_DEVICE
-     * - NOT_SUPPORTED
-     * - TOO_MANY_USERS
-     */
-
-    static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
-
-        @Override
-        public void onBeforeInvocation(Method m, Object[] args) {
-        }
-
-        @Override
-        public void onAfterInvocation(Method m, Object[] args, Object result) {
-            // int return type => status_t => convert to exception
-            if (m.getReturnType() == Integer.TYPE) {
-                int returnValue = (Integer) result;
-                throwOnError(returnValue);
-            }
-        }
-
-        @Override
-        public boolean onCatchException(Method m, Object[] args, Throwable t) {
-
-            if (t instanceof DeadObjectException) {
-                throw new CameraRuntimeException(CAMERA_DISCONNECTED,
-                        "Process hosting the camera service has died unexpectedly",
-                        t);
-            } else if (t instanceof RemoteException) {
-                throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
-                        " which should never happen.", t);
-            }
-
-            return false;
-        }
-
-        @Override
-        public void onFinally(Method m, Object[] args) {
-        }
-
-    }
-
-    /**
-     * Throw error codes returned by the camera service as exceptions.
-     *
-     * @param errorFlag error to throw as an exception.
-     */
-    public static void throwOnError(int errorFlag) {
-        if (errorFlag == NO_ERROR) {
-            return;
-        } else if (errorFlag == PERMISSION_DENIED) {
-            throw new SecurityException("Lacking privileges to access camera service");
-        } else if (errorFlag == ALREADY_EXISTS) {
-            // This should be handled at the call site. Typically this isn't bad,
-            // just means we tried to do an operation that already completed.
-            return;
-        } else if (errorFlag == BAD_VALUE) {
-            throw new IllegalArgumentException("Bad argument passed to camera service");
-        } else if (errorFlag == DEAD_OBJECT) {
-            throw new CameraRuntimeException(CAMERA_DISCONNECTED);
-        } else if (errorFlag == TIMED_OUT) {
-            throw new CameraRuntimeException(CAMERA_ERROR,
-                    "Operation timed out in camera service");
-        } else if (errorFlag == -EACCES) {
-            throw new CameraRuntimeException(CAMERA_DISABLED);
-        } else if (errorFlag == -EBUSY) {
-            throw new CameraRuntimeException(CAMERA_IN_USE);
-        } else if (errorFlag == -EUSERS) {
-            throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
-        } else if (errorFlag == -ENODEV) {
-            throw new CameraRuntimeException(CAMERA_DISCONNECTED);
-        } else if (errorFlag == -EOPNOTSUPP) {
-            throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
-        } else if (errorFlag == INVALID_OPERATION) {
-            throw new CameraRuntimeException(CAMERA_ERROR,
-                    "Illegal state encountered in camera service.");
-        }
-
-        /**
-         * Trap the rest of the negative return values. If we have known
-         * error codes i.e. ALREADY_EXISTS that aren't really runtime
-         * errors, then add them to the top switch statement
-         */
-        if (errorFlag < 0) {
-            throw new CameraRuntimeException(CAMERA_ERROR,
-                    String.format("Unknown camera device error %d", errorFlag));
-        }
-    }
-
-    /**
-     * <p>
-     * Wraps the type T with a proxy that will check 'status_t' return codes
-     * from the native side of the camera service, and throw Java exceptions
-     * automatically based on the code.
-     * </p>
-     * <p>
-     * In addition it also rewrites binder's RemoteException into either a
-     * CameraAccessException or an UnsupportedOperationException.
-     * </p>
-     * <p>
-     * As a result of calling any method on the proxy, RemoteException is
-     * guaranteed never to be thrown.
-     * </p>
-     *
-     * @param obj object that will serve as the target for all method calls
-     * @param <T> the type of the element you want to wrap. This must be an interface.
-     * @return a proxy that will intercept all invocations to obj
-     */
-    public static <T> T newInstance(T obj) {
-        return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/CameraRuntimeException.java b/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
deleted file mode 100644
index 9ed88a9..0000000
--- a/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package android.hardware.camera2.utils;
-
-import android.hardware.camera2.CameraAccessException;
-
-/**
- * @hide
- */
-public class CameraRuntimeException extends RuntimeException {
-
-    private final int mReason;
-    private String mMessage;
-    private Throwable mCause;
-
-    public final int getReason() {
-        return mReason;
-    }
-
-    public CameraRuntimeException(int problem) {
-        super();
-        mReason = problem;
-    }
-
-    public CameraRuntimeException(int problem, String message) {
-        super(message);
-        mReason = problem;
-        mMessage = message;
-    }
-
-    public CameraRuntimeException(int problem, String message, Throwable cause) {
-        super(message, cause);
-        mReason = problem;
-        mMessage = message;
-        mCause = cause;
-    }
-
-    public CameraRuntimeException(int problem, Throwable cause) {
-        super(cause);
-        mReason = problem;
-        mCause = cause;
-    }
-
-    /**
-     * Recreate this exception as the CameraAccessException equivalent.
-     * @return CameraAccessException
-     */
-    public CameraAccessException asChecked() {
-        CameraAccessException e;
-
-        if (mMessage != null && mCause != null) {
-            e = new CameraAccessException(mReason, mMessage, mCause);
-        } else if (mMessage != null) {
-            e = new CameraAccessException(mReason, mMessage);
-        } else if (mCause != null) {
-            e = new CameraAccessException(mReason, mCause);
-        } else {
-            e = new CameraAccessException(mReason);
-        }
-        // throw and catch, so java has a chance to fill out the stack trace
-        e.setStackTrace(this.getStackTrace());
-
-        return e;
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java
deleted file mode 100644
index c1fb6b1..0000000
--- a/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-
-/**
- * Translate camera service status_t return values into exceptions.
- *
- * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
- * @hide
- */
-public class CameraServiceBinderDecorator extends CameraBinderDecorator {
-
-    private static final String TAG = "CameraServiceBinderDecorator";
-
-    static class CameraServiceBinderDecoratorListener
-            extends CameraBinderDecorator.CameraBinderDecoratorListener {
-
-        // Pass through remote exceptions, unlike CameraBinderDecorator
-        @Override
-        public boolean onCatchException(Method m, Object[] args, Throwable t) {
-
-            if (t instanceof DeadObjectException) {
-                // Can sometimes happen (camera service died)
-                // Pass on silently
-            } else if (t instanceof RemoteException) {
-                // Some other kind of remote exception - this is not normal, so let's at least
-                // note it before moving on
-                Log.e(TAG, "Unexpected RemoteException from camera service call.", t);
-            }
-            // All other exceptions also get sent onward
-            return false;
-        }
-
-    }
-
-    /**
-     * <p>
-     * Wraps the type T with a proxy that will check 'status_t' return codes
-     * from the native side of the camera service, and throw Java exceptions
-     * automatically based on the code.
-     * </p>
-     *
-     * @param obj object that will serve as the target for all method calls
-     * @param <T> the type of the element you want to wrap. This must be an interface.
-     * @return a proxy that will intercept all invocations to obj
-     */
-    public static <T> T newInstance(T obj) {
-        return Decorator.<T> newInstance(obj, new CameraServiceBinderDecoratorListener());
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/Decorator.java b/core/java/android/hardware/camera2/utils/Decorator.java
deleted file mode 100644
index 5826497..0000000
--- a/core/java/android/hardware/camera2/utils/Decorator.java
+++ /dev/null
@@ -1,92 +0,0 @@
-
-package android.hardware.camera2.utils;
-
-import java.lang.reflect.*;
-
-/**
- * This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
- *
- * @see android.hardware.camera2.utils.Decorator#newInstance
- *
- * @hide
- */
-public class Decorator<T> implements InvocationHandler {
-
-    public interface DecoratorListener {
-        /**
-         * This method is called before the target method is invoked
-         * @param args arguments to target method
-         * @param m Method being called
-         */
-        void onBeforeInvocation(Method m, Object[] args);
-        /**
-         * This function is called after the target method is invoked
-         * if there were no uncaught exceptions
-         * @param args arguments to target method
-         * @param m Method being called
-         * @param result return value of target method
-         */
-        void onAfterInvocation(Method m, Object[] args, Object result);
-        /**
-         * This method is called only if there was an exception thrown by the target method
-         * during its invocation.
-         *
-         * @param args arguments to target method
-         * @param m Method being called
-         * @param t Throwable that was thrown
-         * @return false to rethrow exception, true if the exception was handled
-         */
-        boolean onCatchException(Method m, Object[] args, Throwable t);
-        /**
-         * This is called after the target method is invoked, regardless of whether or not
-         * there were any exceptions.
-         * @param args arguments to target method
-         * @param m Method being called
-         */
-        void onFinally(Method m, Object[] args);
-    }
-
-    private final T mObject;
-    private final DecoratorListener mListener;
-
-    /**
-     * Create a decorator wrapping the specified object's method calls.
-     *
-     * @param obj the object whose method calls you want to intercept
-     * @param listener the decorator handler for intercepted method calls
-     * @param <T> the type of the element you want to wrap. This must be an interface.
-     * @return a wrapped interface-compatible T
-     */
-    @SuppressWarnings("unchecked")
-    public static<T> T newInstance(T obj, DecoratorListener listener) {
-        return (T)java.lang.reflect.Proxy.newProxyInstance(
-                obj.getClass().getClassLoader(),
-                obj.getClass().getInterfaces(),
-                new Decorator<T>(obj, listener));
-    }
-
-    private Decorator(T obj, DecoratorListener listener) {
-        this.mObject = obj;
-        this.mListener = listener;
-    }
-
-    @Override
-    public Object invoke(Object proxy, Method m, Object[] args)
-            throws Throwable
-    {
-        Object result = null;
-        try {
-            mListener.onBeforeInvocation(m, args);
-            result = m.invoke(mObject, args);
-            mListener.onAfterInvocation(m, args, result);
-        } catch (InvocationTargetException e) {
-            Throwable t = e.getTargetException();
-            if (!mListener.onCatchException(m, args, t)) {
-                throw t;
-            }
-        } finally {
-            mListener.onFinally(m, args);
-        }
-        return result;
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.aidl b/core/java/android/hardware/camera2/utils/LongParcelable.aidl
deleted file mode 100644
index 98ad1b2..0000000
--- a/core/java/android/hardware/camera2/utils/LongParcelable.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-/** @hide */
-parcelable LongParcelable;
diff --git a/core/java/android/hardware/camera2/utils/SubmitInfo.java b/core/java/android/hardware/camera2/utils/SubmitInfo.java
new file mode 100644
index 0000000..d1692b5
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/SubmitInfo.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.utils;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.hardware.camera2.ICameraDeviceUser;
+
+/**
+ * The status information returned for a successful capture request submission.
+ *
+ * Includes the request ID for the newly submitted capture request, and the
+ * last frame number of either the previous repeating request (for repeating
+ * requests), or of the request(s) just submitted (for single-shot capture).
+ *
+ * @hide
+ */
+public class SubmitInfo implements Parcelable {
+
+    private int mRequestId;
+    private long mLastFrameNumber;
+
+    public SubmitInfo() {
+        mRequestId = -1;
+        mLastFrameNumber = ICameraDeviceUser.NO_IN_FLIGHT_REPEATING_FRAMES;
+    }
+
+    public SubmitInfo(int requestId, long lastFrameNumber) {
+        mRequestId = requestId;
+        mLastFrameNumber = lastFrameNumber;
+    }
+
+    public static final Parcelable.Creator<SubmitInfo> CREATOR =
+            new Parcelable.Creator<SubmitInfo>() {
+        @Override
+        public SubmitInfo createFromParcel(Parcel in) {
+            return new SubmitInfo(in);
+        }
+
+        @Override
+        public SubmitInfo[] newArray(int size) {
+            return new SubmitInfo[size];
+        }
+    };
+
+    private SubmitInfo(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRequestId);
+        dest.writeLong(mLastFrameNumber);
+    }
+
+    public void readFromParcel(Parcel in) {
+        mRequestId = in.readInt();
+        mLastFrameNumber = in.readLong();
+    }
+
+    /**
+     * Return the request ID for the submitted capture request/burst.
+     *
+     * This is used to track the completion status of the requested captures,
+     * and to cancel repeating requests.
+     */
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * Return the last frame number for the submitted capture request/burst.
+     *
+     * For a repeating request, this is the last frame number of the _prior_
+     * repeating request, to indicate when to fire the sequence completion callback
+     * for the prior repeating request.
+     *
+     * For a single-shot capture, this is the last frame number of _this_
+     * burst, to indicate when to fire the sequence completion callback for the request itself.
+     *
+     * For a repeating request, may be NO_IN_FLIGHT_REPEATING_FRAMES, if no
+     * instances of a prior repeating request were actually issued to the camera device.
+     */
+    public long getLastFrameNumber() {
+        return mLastFrameNumber;
+    }
+
+}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 121a187..93da3e5 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -132,8 +132,7 @@
                 return info;
             }
         } catch (RemoteException ex) {
-            Log.e(TAG, "Could not get display information from display manager.", ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -159,8 +158,7 @@
                 return displayIds;
             }
         } catch (RemoteException ex) {
-            Log.e(TAG, "Could not get display ids from display manager.", ex);
-            return new int[] { Display.DEFAULT_DISPLAY };
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -237,8 +235,7 @@
             try {
                 mDm.registerCallback(mCallback);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Failed to register callback with display manager service.", ex);
-                mCallback = null;
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
@@ -267,7 +264,7 @@
                 try {
                     mDm.startWifiDisplayScan();
                 } catch (RemoteException ex) {
-                    Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+                    throw ex.rethrowFromSystemServer();
                 }
             }
         }
@@ -279,7 +276,7 @@
                 try {
                     mDm.stopWifiDisplayScan();
                 } catch (RemoteException ex) {
-                    Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+                    throw ex.rethrowFromSystemServer();
                 }
             } else if (mWifiDisplayScanNestCount < 0) {
                 Log.wtf(TAG, "Wifi display scan nest count became negative: "
@@ -297,7 +294,7 @@
         try {
             mDm.connectWifiDisplay(deviceAddress);
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -305,7 +302,7 @@
         try {
             mDm.pauseWifiDisplay();
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to pause Wifi display.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -313,7 +310,7 @@
         try {
             mDm.resumeWifiDisplay();
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to resume Wifi display.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -321,7 +318,7 @@
         try {
             mDm.disconnectWifiDisplay();
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -333,8 +330,7 @@
         try {
             mDm.renameWifiDisplay(deviceAddress, alias);
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to rename Wifi display " + deviceAddress
-                    + " with alias " + alias + ".", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -346,7 +342,7 @@
         try {
             mDm.forgetWifiDisplay(deviceAddress);
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to forget Wifi display.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -354,8 +350,7 @@
         try {
             return mDm.getWifiDisplayStatus();
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to get Wifi display status.", ex);
-            return new WifiDisplayStatus();
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -363,7 +358,7 @@
         try {
             mDm.requestColorTransform(displayId, colorTransformId);
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to request color transform.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -385,8 +380,7 @@
             displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
                     context.getPackageName(), name, width, height, densityDpi, surface, flags);
         } catch (RemoteException ex) {
-            Log.e(TAG, "Could not create virtual display: " + name, ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
         if (displayId < 0) {
             Log.e(TAG, "Could not create virtual display: " + name);
@@ -399,6 +393,7 @@
             try {
                 mDm.releaseVirtualDisplay(callbackWrapper);
             } catch (RemoteException ex) {
+                throw ex.rethrowFromSystemServer();
             }
             return null;
         }
@@ -409,7 +404,7 @@
         try {
             mDm.setVirtualDisplaySurface(token, surface);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to set virtual display surface.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -418,7 +413,7 @@
         try {
             mDm.resizeVirtualDisplay(token, width, height, densityDpi);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to resize virtual display.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -426,7 +421,7 @@
         try {
             mDm.releaseVirtualDisplay(token);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to release virtual display.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 9f8c28e..b8088f3 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -40,6 +40,7 @@
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.USE_FINGERPRINT;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 
@@ -539,7 +540,7 @@
         if (mService != null) try {
             result = mService.preEnroll(mToken);
         } catch (RemoteException e) {
-            Log.w(TAG, "Remote exception in enroll: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return result;
     }
@@ -554,7 +555,7 @@
         if (mService != null) try {
             result = mService.postEnroll(mToken);
         } catch (RemoteException e) {
-            Log.w(TAG, "Remote exception in post enroll: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return result;
     }
@@ -570,7 +571,7 @@
         if (mService != null) try {
             mService.setActiveUser(userId);
         } catch (RemoteException e) {
-            Log.w(TAG, "Remote exception in setActiveUser: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -613,7 +614,7 @@
             try {
                 mService.rename(fpId, userId, newName);
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in rename(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "rename(): Service not connected!");
@@ -631,7 +632,7 @@
         if (mService != null) try {
             return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return null;
     }
@@ -655,10 +656,25 @@
     @RequiresPermission(USE_FINGERPRINT)
     public boolean hasEnrolledFingerprints() {
         if (mService != null) try {
-            return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
-                    mContext.getOpPackageName());
+            return mService.hasEnrolledFingerprints(
+                    UserHandle.myUserId(), mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+            throw e.rethrowFromSystemServer();
+        }
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            USE_FINGERPRINT,
+            INTERACT_ACROSS_USERS})
+    public boolean hasEnrolledFingerprints(int userId) {
+        if (mService != null) try {
+            return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
         return false;
     }
@@ -675,7 +691,7 @@
                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
                 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
@@ -694,7 +710,7 @@
             try {
                 return mService.getAuthenticatorId(mContext.getOpPackageName());
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "getAuthenticatorId(): Service not connected!");
@@ -714,7 +730,7 @@
             try {
                 mService.resetTimeout(token);
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in resetTimeout(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "resetTimeout(): Service not connected!");
@@ -749,7 +765,7 @@
                     }
                 });
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
@@ -865,8 +881,7 @@
         try {
             return ActivityManagerNative.getDefault().getCurrentUser().id;
         } catch (RemoteException e) {
-            Log.w(TAG, "Failed to get current user id\n");
-            return UserHandle.USER_NULL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -874,7 +889,7 @@
         if (mService != null) try {
             mService.cancelEnrollment(mToken);
         } catch (RemoteException e) {
-            if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -882,7 +897,7 @@
         if (mService != null) try {
             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 6effc0d..ff87b67 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -267,7 +267,7 @@
             try {
                 types = mService.getSupportedTypes();
             } catch (RemoteException e) {
-                // Do nothing.
+                throw e.rethrowFromSystemServer();
             }
         }
         mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
@@ -403,7 +403,7 @@
         try {
             mService.addHotplugEventListener(wrappedListener);
         } catch (RemoteException e) {
-            Log.e(TAG, "failed to add hotplug event listener: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -425,7 +425,7 @@
         try {
             mService.removeHotplugEventListener(wrappedListener);
         } catch (RemoteException e) {
-            Log.e(TAG, "failed to remove hotplug event listener: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index cbe3412..fbac58c 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -252,7 +252,7 @@
                 try {
                     inputDevice = mIm.getInputDevice(id);
                 } catch (RemoteException ex) {
-                    throw new RuntimeException("Could not get input device information.", ex);
+                    throw ex.rethrowFromSystemServer();
                 }
                 if (inputDevice != null) {
                     mInputDevices.setValueAt(index, inputDevice);
@@ -284,7 +284,7 @@
                     try {
                         inputDevice = mIm.getInputDevice(id);
                     } catch (RemoteException ex) {
-                        // Ignore the problem for the purposes of this method.
+                        throw ex.rethrowFromSystemServer();
                     }
                     if (inputDevice == null) {
                         continue;
@@ -384,8 +384,7 @@
         try {
             return mIm.isInTabletMode();
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get tablet mode state", ex);
-            return SWITCH_STATE_UNKNOWN;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -439,7 +438,7 @@
         try {
             mIm.registerTabletModeChangedListener(listener);
         } catch (RemoteException ex) {
-            throw new RuntimeException("Could not register tablet mode changed listener", ex);
+            throw ex.rethrowFromSystemServer();
         }
         mTabletModeChangedListener = listener;
         mOnTabletModeChangedListeners = new ArrayList<>();
@@ -471,8 +470,7 @@
         try {
             return mIm.getKeyboardLayouts();
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get list of keyboard layout informations.", ex);
-            return new KeyboardLayout[0];
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -494,8 +492,7 @@
         try {
             return mIm.getKeyboardLayoutsForInputDevice(identifier);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get list of keyboard layouts for input device.", ex);
-            return new KeyboardLayout[0];
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -516,8 +513,7 @@
         try {
             return mIm.getKeyboardLayout(keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get keyboard layout information.", ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -534,8 +530,7 @@
         try {
             return mIm.getCurrentKeyboardLayoutForInputDevice(identifier);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get current keyboard layout for input device.", ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -565,7 +560,7 @@
             mIm.setCurrentKeyboardLayoutForInputDevice(identifier,
                     keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set current keyboard layout for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -585,8 +580,7 @@
         try {
             return mIm.getEnabledKeyboardLayoutsForInputDevice(identifier);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get keyboard layouts for input device.", ex);
-            return ArrayUtils.emptyArray(String.class);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -614,7 +608,7 @@
         try {
             mIm.addKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not add keyboard layout for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -642,7 +636,7 @@
         try {
             mIm.removeKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not remove keyboard layout for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -664,8 +658,7 @@
             return mIm.getKeyboardLayoutForInputDevice(
                     identifier, inputMethodInfo, inputMethodSubtype);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set keyboard layout.", ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -687,7 +680,7 @@
             mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
                     inputMethodSubtype, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set keyboard layout.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -704,8 +697,7 @@
         try {
             return mIm.getTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get calibration matrix for input device.", ex);
-            return TouchCalibration.IDENTITY;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -726,7 +718,7 @@
         try {
             mIm.setTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation, calibration);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set calibration matrix for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -793,7 +785,7 @@
         try {
             mIm.tryPointerSpeed(speed);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set temporary pointer speed.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -831,7 +823,7 @@
         try {
             mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret);
         } catch (RemoteException e) {
-            // no fallback; just return the empty array
+            throw e.rethrowFromSystemServer();
         }
         return ret;
     }
@@ -871,7 +863,7 @@
         try {
             return mIm.injectInputEvent(event, mode);
         } catch (RemoteException ex) {
-            return false;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -887,7 +879,7 @@
         try {
             mIm.setPointerIconShape(iconId);
         } catch (RemoteException ex) {
-            // Do nothing.
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -896,7 +888,7 @@
         try {
             mIm.setCustomPointerIcon(icon);
         } catch (RemoteException ex) {
-            // Do nothing.
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -914,7 +906,7 @@
         try {
             mIm.setPointerIconDetached(detached);
         } catch (RemoteException ex) {
-            // Do nothing.
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -924,8 +916,7 @@
             try {
                 mIm.registerInputDevicesChangedListener(listener);
             } catch (RemoteException ex) {
-                throw new RuntimeException(
-                        "Could not get register input device changed listener", ex);
+                throw ex.rethrowFromSystemServer();
             }
             mInputDevicesChangedListener = listener;
         }
@@ -935,7 +926,7 @@
             try {
                 ids = mIm.getInputDeviceIds();
             } catch (RemoteException ex) {
-                throw new RuntimeException("Could not get input device ids.", ex);
+                throw ex.rethrowFromSystemServer();
             }
 
             mInputDevices = new SparseArray<InputDevice>();
@@ -1175,7 +1166,7 @@
             try {
                 mIm.vibrate(mDeviceId, pattern, repeat, mToken);
             } catch (RemoteException ex) {
-                Log.w(TAG, "Failed to vibrate.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
 
@@ -1184,7 +1175,7 @@
             try {
                 mIm.cancelVibrate(mDeviceId, mToken);
             } catch (RemoteException ex) {
-                Log.w(TAG, "Failed to cancel vibration.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
diff --git a/core/java/android/hardware/location/ContextHubInfo.aidl b/core/java/android/hardware/location/ContextHubInfo.aidl
index 1a9221a..8de03da 100644
--- a/core/java/android/hardware/location/ContextHubInfo.aidl
+++ b/core/java/android/hardware/location/ContextHubInfo.aidl
@@ -15,7 +15,7 @@
  */
 
 package android.hardware.location;
-/*
-@hide
-*/
+/**
+ * @hide
+ */
 parcelable ContextHubInfo;
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index e47c541..ae44f1d 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -23,7 +23,7 @@
 
 /**
  * @hide
-  */
+ */
 @SystemApi
 public class ContextHubInfo {
     private int mId;
@@ -37,6 +37,7 @@
     private float mStoppedPowerDrawMw;
     private float mSleepPowerDrawMw;
     private float mPeakPowerDrawMw;
+    private int mMaxPacketLengthBytes;
 
     private int[] mSupportedSensors;
 
@@ -46,6 +47,27 @@
     }
 
     /**
+     * returns the maximum number of bytes that can be sent per message to the hub
+     *
+     * @return int - maximum bytes that can be transmitted in a
+     *         single packet
+     */
+    public int getMaxPacketLengthBytes() {
+        return mMaxPacketLengthBytes;
+    }
+
+    /**
+     * set the context hub unique identifer
+     *
+     * @param bytes - Maximum number of bytes per message
+     *
+     * @hide
+     */
+    public void setMaxPacketLenBytes(int bytes) {
+        mMaxPacketLengthBytes = bytes;
+    }
+
+    /**
      * get the context hub unique identifer
      *
      * @return int - unique system wide identifier
@@ -58,6 +80,8 @@
      * set the context hub unique identifer
      *
      * @param id - unique system wide identifier for the hub
+     *
+     * @hide
      */
     public void setId(int id) {
         mId = id;
@@ -75,7 +99,9 @@
     /**
      * set a string as the hub name
      *
-     * @param String - the name for the hub
+     * @param name - the name for the hub
+     *
+     * @hide
      */
     public void setName(String name) {
         mName = name;
@@ -93,7 +119,9 @@
     /**
      * set a string as the vendor name
      *
-     * @param String - a name for the vendor
+     * @param vendor - a name for the vendor
+     *
+     * @hide
      */
     public void setVendor(String vendor) {
         mVendor = vendor;
@@ -111,7 +139,9 @@
     /**
      * set tool chain string
      *
-     * @param String - description of the tool chain
+     * @param toolchain - description of the tool chain
+     *
+     * @hide
      */
     public void setToolchain(String toolchain) {
         mToolchain = toolchain;
@@ -130,6 +160,8 @@
      * set platform version
      *
      * @param platformVersion - platform version number
+     *
+     * @hide
      */
     public void setPlatformVersion(int platformVersion) {
         mPlatformVersion = platformVersion;
@@ -148,6 +180,8 @@
      * set platform software version
      *
      * @param staticSwVersion - platform static s/w version number
+     *
+     * @hide
      */
     public void setStaticSwVersion(int staticSwVersion) {
         mStaticSwVersion = staticSwVersion;
@@ -166,6 +200,8 @@
      * set the tool chain version number
      *
      * @param toolchainVersion - tool chain version number
+     *
+     * @hide
      */
     public void setToolchainVersion(int toolchainVersion) {
         mToolchainVersion = toolchainVersion;
@@ -184,6 +220,8 @@
      * set the peak mips that this hub can support
      *
      * @param peakMips - peak mips this hub can deliver
+     *
+     * @hide
      */
     public void setPeakMips(float peakMips) {
         mPeakMips = peakMips;
@@ -206,6 +244,8 @@
      * Set the power consumed by the hub in stopped state
      *
      * @param stoppedPowerDrawMw - stopped power in milli watts
+     *
+     * @hide
      */
     public void setStoppedPowerDrawMw(float stoppedPowerDrawMw) {
         mStoppedPowerDrawMw = stoppedPowerDrawMw;
@@ -230,6 +270,8 @@
      * Set the sleep power draw in milliwatts
      *
      * @param sleepPowerDrawMw - sleep power draw in milliwatts.
+     *
+     * @hide
      */
     public void setSleepPowerDrawMw(float sleepPowerDrawMw) {
         mSleepPowerDrawMw = sleepPowerDrawMw;
@@ -250,6 +292,8 @@
      *
      * @param peakPowerDrawMw - peak power draw of the hub in
      *                        milliwatts.
+     *
+     * @hide
      */
     public void setPeakPowerDrawMw(float peakPowerDrawMw) {
         mPeakPowerDrawMw = peakPowerDrawMw;
@@ -281,6 +325,8 @@
      * set the supported sensors on this hub
      *
      * @param supportedSensors - supported sensors on this hub
+     *
+     * @hide
      */
     public void setSupportedSensors(int[] supportedSensors) {
         mSupportedSensors = Arrays.copyOf(supportedSensors, supportedSensors.length);
@@ -292,6 +338,8 @@
      * @param memoryRegions - memory regions information
      *
      * @see MemoryRegion
+     *
+     * @hide
      */
     public void setMemoryRegions(MemoryRegion[] memoryRegions) {
         mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
@@ -348,4 +396,4 @@
             return new ContextHubInfo[size];
         }
     };
-}
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 301b2e4..89edaa9 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -16,26 +16,19 @@
 package android.hardware.location;
 
 import android.annotation.SystemApi;
-import android.hardware.location.NanoAppInstanceInfo;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.ServiceConnection;
-import android.Manifest;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-
 /**
- * A class that exposes the Context hubs on a device to
- * applicaions.
+ * A class that exposes the Context hubs on a device to applications.
  *
- * Please not that this class is not expected to be used by
- * unbundled applications. Also, calling applications are
- * expected to have LOCTION_HARDWARE premissions to use this
- * class.
+ * Please note that this class is not expected to be used by unbundled applications. Also, calling
+ * applications are expected to have LOCATION_HARDWARE permissions to use this class.
  *
  * @hide
  */
@@ -43,46 +36,43 @@
 public final class ContextHubManager {
 
     private static final String TAG = "ContextHubManager";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
-    private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
-            + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
 
-    private Context mContext;
+    private final Looper mMainLooper;
     private IContextHubService mContextHubService;
-    private boolean mContextHubConnected;
+    private Callback mCallback;
+    private Handler mCallbackHandler;
 
     /**
-     * A special context hub identifer meaning any possible hub on
-     * the system.
+     * An interface to receive asynchronous communication from the context hub.
      */
-    public static final int ANY_HUB       = -1;
-    /**
-     * A constant denoting a message to load a a Nano App
-     */
-    public static final int MSG_LOAD_NANO_APP   = 1;
-    /**
-     * A constant denoting a message to unload a a Nano App
-     */
-    public static final int MSG_UNLOAD_NANO_APP = 2;
-    /**
-     * A constant denoting a message to send a message
-     */
-    public static final int MSG_DATA_SEND       = 3;
+    public abstract static class Callback {
+        protected Callback() {}
 
+        /**
+         * Callback function called on message receipt from context hub.
+         *
+         * @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
+         * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
+         * @param message The context hub message.
+         *
+         * @see ContextHubMessage
+         */
+        public abstract void onMessageReceipt(
+                int hubHandle,
+                int nanoAppHandle,
+                ContextHubMessage message);
+    }
 
     /**
      * Get a handle to all the context hubs in the system
      * @return array of context hub handles
      */
-    public int[] getContexthubHandles() {
+    public int[] getContextHubHandles() {
         int[] retVal = null;
-        if(mContextHubConnected) {
-            try {
-                retVal = mContextHubService.getContextHubHandles();
-            }catch (RemoteException e) {
-                Log.e (TAG, "Could not fetch context hub handles :" + e.toString());
-            }
+        try {
+            retVal = getBinder().getContextHubHandles();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not fetch context hub handles : " + e);
         }
         return retVal;
     }
@@ -90,27 +80,24 @@
     /**
      * Get more information about a specific hub.
      *
-     * @param contexthubHandle Handle of context hub
-     *
-     * @return ContextHubInfo  returned information about the hub
+     * @param hubHandle Handle (system-wide unique identifier) of a context hub.
+     * @return ContextHubInfo Information about the requested context hub.
      *
      * @see ContextHubInfo
      */
-    public ContextHubInfo getContexthubInfo(int contexthubHandle) {
+    public ContextHubInfo getContextHubInfo(int hubHandle) {
         ContextHubInfo retVal = null;
-        if(mContextHubConnected) {
-            try {
-                retVal = mContextHubService.getContextHubInfo(contexthubHandle);
-            }catch (RemoteException e) {
-                Log.e (TAG, "Could not fetch context hub info :" + e.toString());
-            }
+        try {
+            retVal = getBinder().getContextHubInfo(hubHandle);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not fetch context hub info :" + e);
         }
 
-        return(retVal);
+        return retVal;
     }
 
     /**
-     * Load a nanoapp on a specified context hub
+     * Load a nano app on a specified context hub.
      *
      * @param hubHandle handle of context hub to load the app on.
      * @param app the nanoApp to load on the hub
@@ -123,12 +110,14 @@
     public int loadNanoApp(int hubHandle, NanoApp app) {
         int retVal = -1;
 
-        if(mContextHubConnected) {
-            try {
-                retVal = mContextHubService.loadNanoApp(hubHandle, app);
-            }catch (RemoteException e) {
-                Log.e (TAG, "Could not fetch load nanoApp :" + e.toString());
-            }
+        if (app == null) {
+            return retVal;
+        }
+
+        try {
+            retVal = getBinder().loadNanoApp(hubHandle, app);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not load nanoApp :" + e);
         }
 
         return retVal;
@@ -137,19 +126,17 @@
     /**
      * Unload a specified nanoApp
      *
-     * @param nanoAppInstanceHandle handle of the nanoApp to load
+     * @param nanoAppHandle handle of the nanoApp to load
      *
-     * @return int  0 on success, -1 otherewise
+     * @return int  0 on success, -1 otherwise
      */
-    public int unloadNanoApp(int nanoAppInstanceHandle) {
+    public int unloadNanoApp(int nanoAppHandle) {
         int retVal = -1;
 
-        if(mContextHubConnected) {
-            try {
-                retVal = mContextHubService.unloadNanoApp(nanoAppInstanceHandle);
-            }catch (RemoteException e) {
-                Log.e (TAG, "Could not fetch unload nanoApp :" + e.toString());
-            }
+        try {
+            retVal = getBinder().unloadNanoApp(nanoAppHandle);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not fetch unload nanoApp :" + e);
         }
 
         return retVal;
@@ -158,22 +145,18 @@
     /**
      * get information about the nano app instance
      *
-     * @param nanoAppInstanceHandle handle of the nanoAppInstance
-     *
-     * @return NanoAppInstanceInfo Inforamtion about the nano app
-     *         instance.
+     * @param nanoAppHandle handle of the nanoAppInstance
+     * @return NanoAppInstanceInfo Information about the nano app instance.
      *
      * @see NanoAppInstanceInfo
      */
-    public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) {
+    public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
         NanoAppInstanceInfo retVal = null;
 
-        if(mContextHubConnected) {
-            try {
-                retVal = mContextHubService.getNanoAppInstanceInfo(nanoAppInstanceHandle);
-            }catch (RemoteException e) {
-                Log.e (TAG, "Could not fetch nanoApp info :" + e.toString());
-            }
+        try {
+            retVal = getBinder().getNanoAppInstanceInfo(nanoAppHandle);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not fetch nanoApp info :" + e);
         }
 
         return retVal;
@@ -187,92 +170,147 @@
      *
      * @see NanoAppFilter
      *
-     * @return Integer[] Array of handles to any found nano apps
+     * @return int[] Array of handles to any found nano apps
      */
-    public Integer[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
-        int[] temp;
-        Integer[] retVal = null;
+    public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+        int[] retVal = null;
+        try {
+            retVal = getBinder().findNanoAppOnHub(hubHandle, filter);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not query nanoApp instance :" + e);
+        }
+        return retVal;
+    }
 
-        if(mContextHubConnected) {
-            try {
-                temp = mContextHubService.findNanoAppOnHub(hubHandle, filter);
-                retVal = new Integer[temp.length];
-                for (int i = 0; i < temp.length; i++) {
-                    retVal[i] = temp[i];
-                }
-            }catch (RemoteException e) {
-                Log.e (TAG, "Could not query nanoApp instance :" + e.toString());
-            }
+    /**
+     * Send a message to a specific nano app instance on a context hub.
+     *
+     * @param hubHandle handle of the hub to send the message to
+     * @param nanoAppHandle  handle of the nano app to send to
+     * @param message Message to be sent
+     *
+     * @see ContextHubMessage
+     *
+     * @return int 0 on success, -1 otherwise
+     */
+    public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) {
+        int retVal = -1;
+
+        if (message == null || message.getData() == null) {
+            Log.w(TAG, "null ptr");
+            return retVal;
+        }
+        try {
+            retVal = getBinder().sendMessage(hubHandle, nanoAppHandle, message);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not send message :" + e.toString());
         }
 
         return retVal;
     }
 
     /**
-     * Send a message to a spcific nano app instance on a context
-     * hub
+     * Set a callback to receive messages from the context hub
      *
+     * @param callback Callback object
      *
-     * @param hubHandle handle of the hub to send the message to
-     * @param nanoAppHandle  handle of the nano app to send to
-     * @param msg Message to be sent
-     *
-     * @see ContextHubMessage
+     * @see Callback
      *
      * @return int 0 on success, -1 otherwise
      */
-    public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) {
-        int retVal = -1;
-
-        if(mContextHubConnected) {
-            try {
-                retVal = mContextHubService.sendMessage(hubHandle, nanoAppHandle, msg);
-            }catch (RemoteException e) {
-                Log.e (TAG, "Could not fetch send message :" + e.toString());
-            }
-        }
-
-        return retVal;
+    public int registerCallback(Callback callback) {
+        return registerCallback(callback, null);
     }
 
-    private void checkPermissions() {
-        mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+    /**
+     * Set a callback to receive messages from the context hub
+     *
+     * @param callback Callback object
+     * @param handler Handler object
+     *
+     * @see Callback
+     *
+     * @return int 0 on success, -1 otherwise
+     */
+    public int registerCallback(Callback callback, Handler handler) {
+        synchronized(this) {
+            if (mCallback != null) {
+                Log.w(TAG, "Max number of callbacks reached!");
+                return -1;
+            }
+            mCallback = callback;
+            mCallbackHandler = handler;
+        }
+        return 0;
+    }
+
+    /**
+     * Unregister a callback for receive messages from the context hub.
+     *
+     * @see Callback
+     *
+     * @param callback method to deregister
+     *
+     * @return int 0 on success, -1 otherwise
+     */
+    public int unregisterCallback(Callback callback) {
+      synchronized(this) {
+          if (callback != mCallback) {
+              Log.w(TAG, "Cannot recognize callback!");
+              return -1;
+          }
+
+          mCallback = null;
+          mCallbackHandler = null;
+      }
+      return 0;
     }
 
     private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
         @Override
-        public void onMessageReceipt(int hubId, int nanoAppId, ContextHubMessage msg) throws RemoteException {
-
+        public void onMessageReceipt(final int hubId, final int nanoAppId,
+                final ContextHubMessage message) {
+            if (mCallback != null) {
+                synchronized(this) {
+                    final Callback callback = mCallback;
+                    Handler handler = mCallbackHandler == null ?
+                            new Handler(mMainLooper) : mCallbackHandler;
+                    handler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            callback.onMessageReceipt(hubId, nanoAppId, message);
+                        }
+                    });
+                }
+            } else {
+                Log.d(TAG, "Context hub manager client callback is NULL");
+            }
         }
     };
 
-    private ContextHubManager(Context context) {
-        checkPermissions();
-        mContext = context;
-        mContextHubConnected = false;
+    /** @hide */
+    public ContextHubManager(Context context, Looper mainLooper) {
+        mMainLooper = mainLooper;
+
+        IBinder b = ServiceManager.getService(ContextHubService.CONTEXTHUB_SERVICE);
+        if (b != null) {
+            mContextHubService = IContextHubService.Stub.asInterface(b);
+
+            try {
+                getBinder().registerCallback(mClientCallback);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Could not register callback:" + e);
+            }
+
+        } else {
+            Log.w(TAG, "failed to getService");
+        }
     }
 
-    private ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mContextHubService = IContextHubService.Stub.asInterface(service);
-            mContextHubConnected = true;
-
-            // Register our Callback
-            try {
-                mContextHubService.registerCallBack(mClientCallback);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Could not register callback with context hub service :" + e.toString());
-            }
-            Log.d(TAG, "contexthub manager connected to " + name.toString());
+    private IContextHubService getBinder() throws RemoteException {
+        if (mContextHubService == null) {
+            throw new RemoteException("Service not connected.");
         }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            mContextHubService = null;
-            mContextHubConnected = false;
-            Log.d(TAG, "contexthub manager disconnected from " + name.toString());
-        }
-    };
-
+        return mContextHubService;
+    }
 }
diff --git a/core/java/android/hardware/location/ContextHubMessage.aidl b/core/java/android/hardware/location/ContextHubMessage.aidl
index 915f1ec..56704e7 100644
--- a/core/java/android/hardware/location/ContextHubMessage.aidl
+++ b/core/java/android/hardware/location/ContextHubMessage.aidl
@@ -15,8 +15,8 @@
  */
 
 package android.hardware.location;
-/*
-@hide
-*/
+/**
+ * @hide
+ */
 parcelable ContextHubMessage;
 
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index 954e97d..bca2ae6 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -16,10 +16,10 @@
 
 package android.hardware.location;
 
-
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 import java.util.Arrays;
 
@@ -32,6 +32,9 @@
     private int mVersion;
     private byte[]mData;
 
+    private static final String TAG = "ContextHubMessage";
+
+
     /**
      * Get the message type
      *
@@ -106,9 +109,11 @@
     private ContextHubMessage(Parcel in) {
         mType = in.readInt();
         mVersion = in.readInt();
-        byte[] byteBuffer = new byte[in.readInt()];
-        in.readByteArray(byteBuffer);
+        int bufferLength = in.readInt();
+        mData = new byte[bufferLength];
+        in.readByteArray(mData);
     }
+
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mType);
         out.writeInt(mVersion);
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index a2a13c6..3e6cb63 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -16,10 +16,8 @@
 
 package android.hardware.location;
 
-import android.app.Service;
+import android.Manifest;
 import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -29,175 +27,231 @@
 /**
  * @hide
  */
-public class ContextHubService extends Service {
+public class ContextHubService extends IContextHubService.Stub {
+
+    public static final String CONTEXTHUB_SERVICE = "contexthub_service";
 
     private static final String TAG = "ContextHubService";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+    private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+            + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
 
-    private static ContextHubService sSingletonInstance;
-    private static final Object sSingletonInstanceLock = new Object();
 
-    private HashMap<Integer, ContextHubInfo> mHubHash;
+    public static final int ANY_HUB             = -1;
+    public static final int MSG_LOAD_NANO_APP   = 3;
+    public static final int MSG_UNLOAD_NANO_APP = 4;
+
+    private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
+    private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
+    private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
+    private static final int PRE_LOADED_APP_MEM_REQ = 0;
+
+    private static final int MSG_HEADER_SIZE = 4;
+    private static final int MSG_FIELD_TYPE = 0;
+    private static final int MSG_FIELD_VERSION = 1;
+    private static final int MSG_FIELD_HUB_HANDLE = 2;
+    private static final int MSG_FIELD_APP_INSTANCE = 3;
+
+    private static final int OS_APP_INSTANCE = -1;
+
+    private final Context mContext;
+
     private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
-    private ContextHubInfo[] mContexthubInfo;
-
+    private ContextHubInfo[] mContextHubInfo;
+    private IContextHubCallback mCallback;
 
     private native int nativeSendMessage(int[] header, byte[] data);
     private native ContextHubInfo[] nativeInitialize();
 
-    private int onMessageReceipt(int[] header, byte[] data) {
+
+    public ContextHubService(Context context) {
+        mContext = context;
+        mContextHubInfo = nativeInitialize();
+        mNanoAppHash = new HashMap<Integer, NanoAppInstanceInfo>();
+
+        for (int i = 0; i < mContextHubInfo.length; i++) {
+            Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+                  + ", name:  " + mContextHubInfo[i].getName());
+        }
+    }
+
+    @Override
+    public int registerCallback(IContextHubCallback callback) throws RemoteException {
+        checkPermissions();
+        synchronized(this) {
+          mCallback = callback;
+        }
         return 0;
     }
-    private void initialize() {
-        mContexthubInfo = nativeInitialize();
 
-        mHubHash = new HashMap<Integer, ContextHubInfo>();
+    @Override
+    public int[] getContextHubHandles() throws RemoteException {
+        checkPermissions();
+        int [] returnArray = new int[mContextHubInfo.length];
 
-        for (int i = 0; i < mContexthubInfo.length; i++) {
-            mHubHash.put(i + 1, mContexthubInfo[i]); // Avoiding zero
+        for (int i = 0; i < returnArray.length; ++i) {
+            returnArray[i] = i + 1; //valid handles from 1...n
+            Log.d(TAG, String.format("Hub %s is mapped to %d",
+                                     mContextHubInfo[i].getName(), returnArray[i]));
         }
+
+        return returnArray;
     }
 
-    private ContextHubService(Context context) {
-        initialize();
-        Log.d(TAG, "Created from " + context.toString());
+    @Override
+    public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
+        checkPermissions();
+        contextHubHandle -= 1;
+        if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
+            return null; // null means fail
+        }
+
+        return mContextHubInfo[contextHubHandle];
     }
 
-    public static ContextHubService getInstance(Context context) {
-        synchronized (sSingletonInstanceLock) {
-            if (sSingletonInstance == null) {
-                sSingletonInstance = new ContextHubService(context);
-            }
-            return sSingletonInstance;
+    @Override
+    public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
+        checkPermissions();
+        contextHubHandle -= 1;
+
+        if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
+            return -1; // negative handle are invalid, means failed
+        }
+
+        // Call Native interface here
+        int[] msgHeader = new int[MSG_HEADER_SIZE];
+        msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
+        msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+        msgHeader[MSG_FIELD_VERSION] = 0;
+        msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
+
+        if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
+            return -1;
+        }
+        // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+        return 0;
+    }
+
+    @Override
+    public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+        checkPermissions();
+        NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
+        if (info == null) {
+            return -1; //means failed
+        }
+
+        // Call Native interface here
+        int[] msgHeader = new int[MSG_HEADER_SIZE];
+        msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
+        msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+        msgHeader[MSG_FIELD_VERSION] = 0;
+        msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
+
+        if(nativeSendMessage(msgHeader, null) != 0) {
+            return -1;
+        }
+
+        // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+        return 0;
+    }
+
+    @Override
+    public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
+            throws RemoteException {
+        checkPermissions();
+        // This assumes that all the nanoAppInfo is current. This is reasonable
+        // for the use cases for tightly controlled nanoApps.
+        if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+            return mNanoAppHash.get(nanoAppInstanceHandle);
+        } else {
+            return null;
         }
     }
 
     @Override
-    public void onCreate() {
-        super.onCreate();
+    public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+        checkPermissions();
+        ArrayList<Integer> foundInstances = new ArrayList<Integer>();
+
+        for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
+            NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
+
+            if (filter.testMatch(info)){
+                foundInstances.add(nanoAppInstance);
+            }
+        }
+
+        int[] retArray = new int[foundInstances.size()];
+        for (int i = 0; i < foundInstances.size(); i++) {
+            retArray[i] = foundInstances.get(i).intValue();
+        }
+
+        return retArray;
     }
 
     @Override
-    public IBinder onBind(Intent intent) {
-        return null;
+    public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
+            throws RemoteException {
+        checkPermissions();
+
+        int[] msgHeader = new int[MSG_HEADER_SIZE];
+        msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
+        msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
+        msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
+        msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
+
+        return nativeSendMessage(msgHeader, msg.getData());
     }
 
-    private final IContextHubService.Stub mBinder = new IContextHubService.Stub() {
+    private void checkPermissions() {
+        mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+    }
 
-        private  IContextHubCallback callback;
-
-        @Override
-        public int registerCallBack(IContextHubCallback callback) throws RemoteException{
-            this.callback = callback;
-            return 0;
+    private int onMessageReceipt(int[] header, byte[] data) {
+        if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
+            return  -1;
         }
 
-        @Override
-        public int[] getContextHubHandles() throws RemoteException {
-            int [] returnArray = new int[mHubHash.size()];
-            int i = 0;
-            for (int key : mHubHash.keySet()) {
-                // Add any filtering here
-                returnArray[i] = key;
-                i++;
-            }
-            return returnArray;
-        }
+        synchronized(this) {
+            if (mCallback != null) {
+                ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE],
+                        header[MSG_FIELD_VERSION],
+                        data);
 
-        @Override
-        public ContextHubInfo getContextHubInfo(int contexthubHandle) throws RemoteException {
-            return mHubHash.get(contexthubHandle);
-        }
-
-        @Override
-        public int loadNanoApp(int hubHandle, NanoApp app) throws RemoteException {
-            if (!mHubHash.containsKey(hubHandle)) {
-                return -1;
-            } else {
-                // Call Native interface here
-                int[] msgHeader = new int[8];
-                msgHeader[0] = ContextHubManager.MSG_LOAD_NANO_APP;
-                msgHeader[1] = app.getAppId();
-                msgHeader[2] = app.getAppVersion();
-                msgHeader[3] = 0; // LOADING_HINTS
-                msgHeader[4] = hubHandle;
-
-                int handle = nativeSendMessage(msgHeader, app.getAppBinary());
-
-                // if successful, add an entry to mNanoAppHash
-
-                if(handle > 0) {
-                    return 0;
-                } else {
-
+                try {
+                    mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE],
+                            header[MSG_FIELD_APP_INSTANCE],
+                            msg);
+                } catch (Exception e) {
+                    Log.w(TAG, "Exception " + e + " when calling remote callback");
                     return -1;
                 }
-            }
-        }
-
-        @Override
-        public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
-            if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
-                return -1;
             } else {
-                NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
-                // Call Native interface here
-                int[] msgHeader = new int[8];
-                msgHeader[0] = ContextHubManager.MSG_UNLOAD_NANO_APP;
-                msgHeader[1] = info.getContexthubId();
-                msgHeader[2] = info.getHandle();
-
-                int result = nativeSendMessage(msgHeader, null);
-                // if successful, remove the entry in mNanoAppHash
-                if(result == 0) {
-                    mNanoAppHash.remove(nanoAppInstanceHandle);
-                }
-                return(result);
+                Log.d(TAG, "Message Callback is NULL");
             }
         }
 
-        @Override
-        public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
-            // This assumes that all the nanoAppInfo is current. This is reasonable
-            // for the use cases for tightly controlled nanoApps.
-            //
-            if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
-                return(mNanoAppHash.get(nanoAppInstanceHandle));
-            } else {
-                return null;
-            }
-        }
+        return 0;
+    }
 
-        @Override
-        public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
-            ArrayList<Integer> foundInstances = new ArrayList<Integer>();
+    private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
+        // App Id encodes vendor & version
+        NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
 
-            for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
-                NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
+        appInfo.setAppId(appId);
+        appInfo.setAppVersion(appVersion);
+        appInfo.setName(PRE_LOADED_APP_NAME);
+        appInfo.setContexthubId(hubHandle);
+        appInfo.setHandle(appInstanceHandle);
+        appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
+        appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
+        appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
+        appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
 
-                if(filter.testMatch(info)){
-                    foundInstances.add(nanoAppInstance);
-                }
-            }
+        mNanoAppHash.put(appInstanceHandle, appInfo);
+        Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
+              + " version " + appVersion);
 
-            int[] retArray = new int[foundInstances.size()];
-            for (int i = 0; i < foundInstances.size(); i++) {
-                retArray[i] = foundInstances.get(i).intValue();
-            }
-
-            return retArray;
-        }
-
-        @Override
-        public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
-            int[] msgHeader = new int[8];
-            msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
-            msgHeader[1] = hubHandle;
-            msgHeader[2] = nanoAppHandle;
-            msgHeader[3] = msg.getMsgType();
-            msgHeader[4] = msg.getVersion();
-
-            return (nativeSendMessage(msgHeader, msg.getData()));
-        }
-    };
+        return 0;
+    }
 }
diff --git a/core/java/android/hardware/location/IContextHubCallback.aidl b/core/java/android/hardware/location/IContextHubCallback.aidl
index 45b1ef4..141fcf6 100644
--- a/core/java/android/hardware/location/IContextHubCallback.aidl
+++ b/core/java/android/hardware/location/IContextHubCallback.aidl
@@ -18,7 +18,9 @@
 
 import android.hardware.location.ContextHubMessage;
 
-/** @hide */
+/**
+ * @hide
+ */
 oneway interface IContextHubCallback {
     void onMessageReceipt(int hubId, int nanoAppId, in ContextHubMessage msg);
 }
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index b2db0b2..ff8c1d0 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -24,11 +24,13 @@
 import android.hardware.location.NanoAppFilter;
 import android.hardware.location.IContextHubCallback;
 
-/** @hide */
+/**
+ * @hide
+ */
 interface IContextHubService {
 
     // register a callback to receive messages
-    int registerCallBack(in IContextHubCallback callback);
+    int registerCallback(in IContextHubCallback callback);
 
     // Gets a list of available context hub handles
     int[] getContextHubHandles();
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
index e8c7615..d100de2 100644
--- a/core/java/android/hardware/location/MemoryRegion.java
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -23,7 +23,6 @@
 /**
  * @hide
  */
-
 @SystemApi
 public class MemoryRegion implements Parcelable{
 
diff --git a/core/java/android/hardware/location/NanoApp.aidl b/core/java/android/hardware/location/NanoApp.aidl
index d32c44a..9df9a08 100644
--- a/core/java/android/hardware/location/NanoApp.aidl
+++ b/core/java/android/hardware/location/NanoApp.aidl
@@ -15,7 +15,7 @@
  */
 
 package android.hardware.location;
-/*
-@hide
-*/
+/**
+ * @hide
+ */
 parcelable NanoApp;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
index 36d181f..b447b62 100644
--- a/core/java/android/hardware/location/NanoApp.java
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -13,16 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.hardware.location;
 
-
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-/**
- * A class describing nano apps.
+/** A class describing nano apps.
  * A nano app is a piece of executable code that can be
  * downloaded onto a specific architecture. These are targtted
  * for low power compute domains on a device.
diff --git a/core/java/android/hardware/location/NanoAppFilter.aidl b/core/java/android/hardware/location/NanoAppFilter.aidl
index cc6d475..5f10201 100644
--- a/core/java/android/hardware/location/NanoAppFilter.aidl
+++ b/core/java/android/hardware/location/NanoAppFilter.aidl
@@ -15,7 +15,7 @@
  */
 
 package android.hardware.location;
-/*
-@hide
-*/
+/**
+ * @hide
+ */
 parcelable NanoAppFilter;
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index ac341e4..8db70e9 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 /**
  * @hide
@@ -27,6 +28,8 @@
 @SystemApi
 public class NanoAppFilter {
 
+    private static final String TAG = "NanoAppFilter";
+
     // The appId, can be set to APP_ID_ANY
     private long mAppId;
 
@@ -54,6 +57,10 @@
      * If this flag is set, only versions strictly less than the version specified shall match.
      */
     public static final int FLAGS_VERSION_LESS_THAN   = 4;
+    /**
+     * If this flag is set, only versions strictly equal to the
+     * version specified shall match.
+     */
     public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
 
     /**
@@ -110,20 +117,16 @@
         return true;
     }
     /**
+     * Test match method.
      *
-     * @param nano app instance info
+     * @param info nano app instance info
      *
      * @return true if this is a match, false otherwise
      */
     public boolean testMatch(NanoAppInstanceInfo info) {
-        if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+        return (mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
                 (mAppId == APP_ANY || info.getAppId() == mAppId) &&
-               // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
-                (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
-            return true;
-        } else {
-            return false;
-        }
+                (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()));
     }
 
     public static final Parcelable.Creator<NanoAppFilter> CREATOR
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.aidl b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
index c8c40d7..2db5566 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
@@ -15,7 +15,7 @@
  */
 
 package android.hardware.location;
-/*
-@hide
-*/
-parcelable NanoAppInstanceInfo;
\ No newline at end of file
+/**
+ * @hide
+ */
+parcelable NanoAppInstanceInfo;
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index ac62919..977f645 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -29,7 +29,7 @@
     private String mPublisher;
     private String mName;
 
-    private int mAppId;
+    private long mAppId;
     private int mAppVersion;
 
     private int mNeededReadMemBytes;
@@ -59,6 +59,8 @@
      * set the publisher name for the app
      *
      * @param publisher - name of the publisher
+     *
+     * @hide
      */
     public void setPublisher(String publisher) {
         mPublisher = publisher;
@@ -77,6 +79,8 @@
      * set the name of the app
      *
      * @param name - name of the app
+     *
+     * @hide
      */
     public void setName(String name) {
         mName = name;
@@ -87,7 +91,7 @@
      *
      * @return int - application identifier
      */
-    public int getAppId() {
+    public long getAppId() {
         return mAppId;
     }
 
@@ -95,8 +99,10 @@
      * Set the application identifier
      *
      * @param appId - application identifier
+     *
+     * @hide
      */
-    public void setAppId(int appId) {
+    public void setAppId(long appId) {
         mAppId = appId;
     }
 
@@ -113,6 +119,8 @@
      * Set the application version
      *
      * @param appVersion - version of the app
+     *
+     * @hide
      */
     public void setAppVersion(int appVersion) {
         mAppVersion = appVersion;
@@ -131,6 +139,8 @@
      * Set the read memory needed by the app
      *
      * @param neededReadMemBytes - readable Memory needed in bytes
+     *
+     * @hide
      */
     public void setNeededReadMemBytes(int neededReadMemBytes) {
         mNeededReadMemBytes = neededReadMemBytes;
@@ -150,6 +160,8 @@
      *
      * @param neededWriteMemBytes - writable memory needed by the
      *                            app
+     *
+     * @hide
      */
     public void setNeededWriteMemBytes(int neededWriteMemBytes) {
         mNeededWriteMemBytes = neededWriteMemBytes;
@@ -169,6 +181,8 @@
      *
      * @param neededExecMemBytes - executable memory needed by the
      *                           app
+     *
+     * @hide
      */
     public void setNeededExecMemBytes(int neededExecMemBytes) {
         mNeededExecMemBytes = neededExecMemBytes;
@@ -187,6 +201,8 @@
      * set the sensors needed by this app
      *
      * @param neededSensors - all the sensors needed by this app
+     *
+     * @hide
      */
     public void setNeededSensors(int[] neededSensors) {
         mNeededSensors = neededSensors;
@@ -206,6 +222,8 @@
      *
      * @param outputEvents - the events that may be generated by
      *                     this app
+     *
+     * @hide
      */
     public void setOutputEvents(int[] outputEvents) {
         mOutputEvents = outputEvents;
@@ -224,6 +242,8 @@
      * set the context hub identifier
      *
      * @param contexthubId - system wide unique identifier
+     *
+     * @hide
      */
     public void setContexthubId(int contexthubId) {
         mContexthubId = contexthubId;
@@ -242,6 +262,8 @@
      * set the handle for an app instance
      *
      * @param handle - handle to this instance
+     *
+     * @hide
      */
     public void setHandle(int handle) {
         mHandle = handle;
@@ -252,7 +274,7 @@
         mPublisher = in.readString();
         mName = in.readString();
 
-        mAppId = in.readInt();
+        mAppId = in.readLong();
         mAppVersion = in.readInt();
         mNeededReadMemBytes = in.readInt();
         mNeededWriteMemBytes = in.readInt();
@@ -274,7 +296,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mPublisher);
         out.writeString(mName);
-        out.writeInt(mAppId);
+        out.writeLong(mAppId);
         out.writeInt(mAppVersion);
         out.writeInt(mContexthubId);
         out.writeInt(mNeededReadMemBytes);
@@ -286,7 +308,6 @@
 
         out.writeInt(mOutputEvents.length);
         out.writeIntArray(mOutputEvents);
-
     }
 
     public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index 597efa5..dcc3369 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -26,10 +26,20 @@
      * Called when the keyphrase is spoken.
      *
      * @param recognitionEvent Object containing data relating to the
-     *                         recognition event such as trigger audio data, if it was requested
-     *                         and is available.
+     *                         keyphrase recognition event such as keyphrase
+     *                         extras.
      */
-    void onDetected(in SoundTrigger.RecognitionEvent recognitionEvent);
+    void onKeyphraseDetected(in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent);
+
+   /**
+     * Called when a generic sound trigger event is witnessed.
+     *
+     * @param recognitionEvent Object containing data relating to the
+     *                         recognition event such as trigger audio data (if
+     *                         requested).
+     */
+
+    void onGenericSoundTriggerDetected(in SoundTrigger.GenericRecognitionEvent recognitionEvent);
 
     /**
      * Called when the detection fails due to an error.
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index fec64ea..325a9ad 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -20,7 +20,7 @@
 parcelable SoundTrigger.Keyphrase;
 parcelable SoundTrigger.RecognitionEvent;
 parcelable SoundTrigger.KeyphraseRecognitionEvent;
-parcelable SoundTrigger.GenericSoundRecognitionEvent;
+parcelable SoundTrigger.GenericRecognitionEvent;
 parcelable SoundTrigger.KeyphraseRecognitionExtra;
 parcelable SoundTrigger.KeyphraseSoundModel;
 parcelable SoundTrigger.GenericSoundModel;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 882908a..b635088 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -595,7 +595,7 @@
             }
         };
 
-        private static RecognitionEvent fromParcel(Parcel in) {
+        protected static RecognitionEvent fromParcel(Parcel in) {
             int status = in.readInt();
             int soundModelHandle = in.readInt();
             boolean captureAvailable = in.readByte() == 1;
@@ -689,12 +689,19 @@
                 return false;
             if (triggerInData != other.triggerInData)
                 return false;
-            if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
-                return false;
-            if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
-                return false;
-            if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
-                return false;
+            if (captureFormat == null) {
+                if (other.captureFormat != null)
+                    return false;
+            } else {
+                if (other.captureFormat == null)
+                    return false;
+                if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
+                    return false;
+                if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
+                    return false;
+                if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
+                    return false;
+            }
             return true;
         }
 
@@ -980,7 +987,7 @@
         public static final Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
                 = new Parcelable.Creator<KeyphraseRecognitionEvent>() {
             public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
-                return KeyphraseRecognitionEvent.fromParcel(in);
+                return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
             }
 
             public KeyphraseRecognitionEvent[] newArray(int size) {
@@ -988,7 +995,7 @@
             }
         };
 
-        private static KeyphraseRecognitionEvent fromParcel(Parcel in) {
+        private static KeyphraseRecognitionEvent fromParcelForKeyphrase(Parcel in) {
             int status = in.readInt();
             int soundModelHandle = in.readInt();
             boolean captureAvailable = in.readByte() == 1;
@@ -1002,10 +1009,10 @@
                 int encoding = in.readInt();
                 int channelMask = in.readInt();
                 captureFormat = (new AudioFormat.Builder())
-                        .setChannelMask(channelMask)
-                        .setEncoding(encoding)
-                        .setSampleRate(sampleRate)
-                        .build();
+                    .setChannelMask(channelMask)
+                    .setEncoding(encoding)
+                    .setSampleRate(sampleRate)
+                    .build();
             }
             byte[] data = in.readBlob();
             KeyphraseRecognitionExtra[] keyphraseExtras =
@@ -1094,6 +1101,40 @@
                     captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
                     data);
         }
+
+        public static final Parcelable.Creator<GenericRecognitionEvent> CREATOR
+                = new Parcelable.Creator<GenericRecognitionEvent>() {
+            public GenericRecognitionEvent createFromParcel(Parcel in) {
+                return GenericRecognitionEvent.fromParcelForGeneric(in);
+            }
+
+            public GenericRecognitionEvent[] newArray(int size) {
+                return new GenericRecognitionEvent[size];
+            }
+        };
+
+        private static GenericRecognitionEvent fromParcelForGeneric(Parcel in) {
+            RecognitionEvent event = RecognitionEvent.fromParcel(in);
+            return new GenericRecognitionEvent(event.status, event.soundModelHandle,
+                    event.captureAvailable, event.captureSession, event.captureDelayMs,
+                    event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass()) return false;
+            RecognitionEvent other = (RecognitionEvent) obj;
+            return super.equals(obj);
+        }
+
+        @Override
+        public String toString() {
+            return "GenericRecognitionEvent ::" + super.toString();
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 1e3bcd0..f9a7d19 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -54,6 +54,8 @@
      * This is a sticky broadcast for clients that includes USB connected/disconnected state,
      * <ul>
      * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.
+     * <li> {@link #USB_HOST_CONNECTED} boolean indicating whether USB is connected or
+     *     disconnected as host.
      * <li> {@link #USB_CONFIGURED} boolean indicating whether USB is configured.
      * currently zero if not configured, one for configured.
      * <li> {@link #USB_FUNCTION_ADB} boolean extra indicating whether the
@@ -152,6 +154,14 @@
     public static final String USB_CONNECTED = "connected";
 
     /**
+     * Boolean extra indicating whether USB is connected or disconnected as host.
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+     *
+     * {@hide}
+     */
+    public static final String USB_HOST_CONNECTED = "host_connected";
+
+    /**
      * Boolean extra indicating whether USB is configured.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
@@ -302,8 +312,7 @@
             }
             return result;
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getDeviceList", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -347,8 +356,7 @@
                 return new UsbAccessory[] { accessory };
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getAccessoryList", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -362,8 +370,7 @@
         try {
             return mService.openAccessory(accessory);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in openAccessory", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -380,8 +387,7 @@
         try {
             return mService.hasDevicePermission(device);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in hasPermission", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -398,8 +404,7 @@
         try {
             return mService.hasAccessoryPermission(accessory);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in hasPermission", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -425,7 +430,7 @@
         try {
             mService.requestDevicePermission(device, mContext.getPackageName(), pi);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in requestPermission", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -451,7 +456,7 @@
         try {
             mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in requestPermission", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -466,7 +471,7 @@
         try {
             mService.grantDevicePermission(device, Process.myUid());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in grantPermission", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -486,8 +491,7 @@
         try {
             return mService.isFunctionEnabled(function);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setCurrentFunction", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -517,7 +521,7 @@
         try {
             mService.setCurrentFunction(function);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setCurrentFunction", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -533,7 +537,7 @@
         try {
             mService.setUsbDataUnlocked(unlocked);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setUsbDataUnlocked", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -554,9 +558,8 @@
         try {
             return mService.getPorts();
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getPorts", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -573,9 +576,8 @@
         try {
             return mService.getPortStatus(port.getId());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getPortStatus", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -604,7 +606,7 @@
         try {
             mService.setPortRoles(port.getId(), powerRole, dataRole);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setPortRole", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 857e335..cc71a9c 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -36,6 +36,7 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionInspector;
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodSession;
 import android.view.inputmethod.InputMethodSubtype;
@@ -164,9 +165,10 @@
                 return;
             case DO_START_INPUT: {
                 SomeArgs args = (SomeArgs)msg.obj;
+                int missingMethods = msg.arg1;
                 IInputContext inputContext = (IInputContext)args.arg1;
                 InputConnection ic = inputContext != null
-                        ? new InputConnectionWrapper(inputContext) : null;
+                        ? new InputConnectionWrapper(inputContext, missingMethods) : null;
                 EditorInfo info = (EditorInfo)args.arg2;
                 info.makeCompatible(mTargetSdkVersion);
                 inputMethod.startInput(ic, info);
@@ -175,9 +177,10 @@
             }
             case DO_RESTART_INPUT: {
                 SomeArgs args = (SomeArgs)msg.obj;
+                int missingMethods = msg.arg1;
                 IInputContext inputContext = (IInputContext)args.arg1;
                 InputConnection ic = inputContext != null
-                        ? new InputConnectionWrapper(inputContext) : null;
+                        ? new InputConnectionWrapper(inputContext, missingMethods) : null;
                 EditorInfo info = (EditorInfo)args.arg2;
                 info.makeCompatible(mTargetSdkVersion);
                 inputMethod.restartInput(ic, info);
@@ -246,8 +249,10 @@
 
     @Override
     public void bindInput(InputBinding binding) {
+        // This IInputContext is guaranteed to implement all the methods.
+        final int missingMethodFlags = 0;
         InputConnection ic = new InputConnectionWrapper(
-                IInputContext.Stub.asInterface(binding.getConnectionToken()));
+                IInputContext.Stub.asInterface(binding.getConnectionToken()), missingMethodFlags);
         InputBinding nu = new InputBinding(ic, binding);
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
     }
@@ -258,15 +263,19 @@
     }
 
     @Override
-    public void startInput(IInputContext inputContext, EditorInfo attribute) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_START_INPUT,
-                inputContext, attribute));
+    public void startInput(IInputContext inputContext,
+            @InputConnectionInspector.MissingMethodFlags final int missingMethods,
+            EditorInfo attribute) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_START_INPUT,
+                missingMethods, inputContext, attribute));
     }
 
     @Override
-    public void restartInput(IInputContext inputContext, EditorInfo attribute) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_RESTART_INPUT,
-                inputContext, attribute));
+    public void restartInput(IInputContext inputContext,
+            @InputConnectionInspector.MissingMethodFlags final int missingMethods,
+            EditorInfo attribute) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_RESTART_INPUT,
+                missingMethods, inputContext, attribute));
     }
 
     @Override
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 2826882..cc201bc 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -295,9 +295,7 @@
     boolean mLastShowInputRequested;
     int mCandidatesVisibility;
     CompletionInfo[] mCurCompletions;
-    
-    boolean mShowInputForced;
-    
+
     boolean mFullscreenApplied;
     boolean mIsFullscreen;
     View mExtractView;
@@ -422,7 +420,6 @@
             boolean wasVis = isInputViewShown();
             mShowInputFlags = 0;
             mShowInputRequested = false;
-            mShowInputForced = false;
             doHideWindow();
             clearInsetOfPreviousIme();
             if (resultReceiver != null) {
@@ -439,8 +436,7 @@
         public void showSoftInput(int flags, ResultReceiver resultReceiver) {
             if (DEBUG) Log.v(TAG, "showSoftInput()");
             boolean wasVis = isInputViewShown();
-            mShowInputFlags = 0;
-            if (onShowInputRequested(flags, false)) {
+            if (dispatchOnShowInputRequested(flags, false)) {
                 try {
                     showWindow(true);
                 } catch (BadTokenException e) {
@@ -721,7 +717,11 @@
                 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
                         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
                         ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
-                mService.updateInputViewShown();
+                // In Android M and prior, state change of
+                // Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD has triggered
+                // #onConfigurationChanged().  For compatibility reasons, we reset the internal
+                // state as if configuration was changed.
+                mService.resetStateForNewConfiguration();
             }
         }
 
@@ -817,8 +817,8 @@
         mInitialized = false;
         mWindowCreated = false;
         mShowInputRequested = false;
-        mShowInputForced = false;
-        
+        mShowInputFlags = 0;
+
         mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
         mRootView = mInflater.inflate(
                 com.android.internal.R.layout.input_method, null);
@@ -888,7 +888,10 @@
      */
     @Override public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        
+        resetStateForNewConfiguration();
+    }
+
+    private void resetStateForNewConfiguration() {
         boolean visible = mWindowVisible;
         int showFlags = mShowInputFlags;
         boolean showingInput = mShowInputRequested;
@@ -903,7 +906,7 @@
         if (visible) {
             if (showingInput) {
                 // If we were last showing the soft keyboard, try to do so again.
-                if (onShowInputRequested(showFlags, true)) {
+                if (dispatchOnShowInputRequested(showFlags, true)) {
                     showWindow(true);
                     if (completions != null) {
                         mCurCompletions = completions;
@@ -1540,20 +1543,41 @@
                 return false;
             }
         }
-        if ((flags&InputMethod.SHOW_FORCED) != 0) {
-            mShowInputForced = true;
-        }
         return true;
     }
-    
+
+    /**
+     * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
+     * states depending on its result.  Since {@link #onShowInputRequested(int, boolean)} is
+     * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
+     * to have this method to ensure that those internal states are always updated no matter how
+     * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
+     * @param flags Provides additional information about the show request,
+     * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
+     * @param configChange This is true if we are re-showing due to a
+     * configuration change.
+     * @return Returns true to indicate that the window should be shown.
+     * @see #onShowInputRequested(int, boolean)
+     */
+    private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
+        final boolean result = onShowInputRequested(flags, configChange);
+        if (result) {
+            mShowInputFlags = flags;
+        } else {
+            mShowInputFlags = 0;
+        }
+        return result;
+    }
+
     public void showWindow(boolean showInput) {
         if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
                 + " mShowInputRequested=" + mShowInputRequested
                 + " mWindowAdded=" + mWindowAdded
                 + " mWindowCreated=" + mWindowCreated
                 + " mWindowVisible=" + mWindowVisible
-                + " mInputStarted=" + mInputStarted);
-        
+                + " mInputStarted=" + mInputStarted
+                + " mShowInputFlags=" + mShowInputFlags);
+
         if (mInShowWindow) {
             Log.w(TAG, "Re-entrance in to showWindow");
             return;
@@ -2269,8 +2293,9 @@
     public void onExtractedDeleteText(int start, int end) {
         InputConnection conn = getCurrentInputConnection();
         if (conn != null) {
+            conn.finishComposingText();
             conn.setSelection(start, start);
-            conn.deleteSurroundingText(0, end-start);
+            conn.deleteSurroundingText(0, end - start);
         }
     }
 
@@ -2572,7 +2597,6 @@
         
         p.println("  mShowInputRequested=" + mShowInputRequested
                 + " mLastShowInputRequested=" + mLastShowInputRequested
-                + " mShowInputForced=" + mShowInputForced
                 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
         p.println("  mCandidatesVisibility=" + mCandidatesVisibility
                 + " mFullscreenApplied=" + mFullscreenApplied
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7004e97..b452341 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -45,10 +45,12 @@
 import android.telephony.SubscriptionManager;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.Protocol;
+import com.android.internal.util.MessageUtils;
 
 import libcore.net.event.NetworkEventDispatcher;
 
@@ -79,6 +81,13 @@
 public class ConnectivityManager {
     private static final String TAG = "ConnectivityManager";
 
+    private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
+            new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
+
+    private static final String whatToString(int what) {
+        return sMagicDecoderRing.get(what, Integer.toString(what));
+    }
+
     /**
      * A change in network connectivity has occurred. A default connection has either
      * been established or lost. The NetworkInfo for the affected network is
@@ -733,7 +742,7 @@
         try {
             return mService.getActiveNetworkInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -753,7 +762,7 @@
         try {
             return mService.getActiveNetwork();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -777,7 +786,7 @@
         try {
             return mService.setAlwaysOnVpnPackage(userId, vpnPackage);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -794,7 +803,7 @@
         try {
             return mService.getAlwaysOnVpnPackage(userId);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -815,7 +824,7 @@
         try {
             return mService.getActiveNetworkInfoForUid(uid);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -839,7 +848,7 @@
         try {
             return mService.getNetworkInfo(networkType);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -859,7 +868,7 @@
         try {
             return mService.getNetworkInfoForNetwork(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -880,7 +889,7 @@
         try {
             return mService.getAllNetworkInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -900,7 +909,7 @@
         try {
             return mService.getNetworkForType(networkType);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -916,7 +925,7 @@
         try {
             return mService.getAllNetworks();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -929,7 +938,7 @@
         try {
             return mService.getDefaultNetworkCapabilitiesForUser(userId);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -948,7 +957,7 @@
         try {
             return mService.getActiveLinkProperties();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -972,7 +981,7 @@
         try {
             return mService.getLinkPropertiesForType(networkType);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -989,7 +998,7 @@
         try {
             return mService.getLinkProperties(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1006,7 +1015,7 @@
         try {
             return mService.getNetworkCapabilities(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1024,7 +1033,7 @@
         try {
             return mService.getCaptivePortalServerUrl();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1324,7 +1333,9 @@
         int type = legacyTypeForNetworkCapabilities(netCap);
         try {
             delay = mService.getRestoreDefaultNetworkDelay(type);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
         LegacyRequest l = new LegacyRequest();
         l.networkCapabilities = netCap;
         l.delay = delay;
@@ -1542,7 +1553,7 @@
         try {
             return mService.requestRouteToHostAddress(networkType, hostAddress.getAddress());
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1598,7 +1609,7 @@
         try {
             return mService.getActiveNetworkQuotaInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1617,7 +1628,9 @@
                 Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
                         + " retVal=" + retVal);
                 return retVal;
-            } catch (RemoteException e) { }
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
         Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
         return false;
@@ -1678,6 +1691,7 @@
             getNetworkManagementService().registerNetworkActivityListener(rl);
             mNetworkActivityListeners.put(l, rl);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1695,6 +1709,7 @@
         try {
             getNetworkManagementService().unregisterNetworkActivityListener(rl);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1710,8 +1725,8 @@
         try {
             return getNetworkManagementService().isNetworkActive();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -1785,7 +1800,7 @@
         try {
             return mService.getTetherableIfaces();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1802,7 +1817,7 @@
         try {
             return mService.getTetheredIfaces();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1825,7 +1840,7 @@
         try {
             return mService.getTetheringErroredIfaces();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1839,7 +1854,7 @@
         try {
             return mService.getTetheredDhcpRanges();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1871,7 +1886,7 @@
         try {
             return mService.tether(iface);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1897,7 +1912,7 @@
         try {
             return mService.untether(iface);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1917,7 +1932,7 @@
         try {
             return mService.isTetheringSupported();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2005,7 +2020,7 @@
         try {
             mService.stopTethering(type);
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception trying to stop tethering.", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2025,7 +2040,7 @@
         try {
             return mService.getTetherableUsbRegexs();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2045,7 +2060,7 @@
         try {
             return mService.getTetherableWifiRegexs();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2065,7 +2080,7 @@
         try {
             return mService.getTetherableBluetoothRegexs();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2090,7 +2105,7 @@
         try {
             return mService.setUsbTethering(enable);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2135,7 +2150,7 @@
         try {
             return mService.getLastTetherError(iface);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2153,6 +2168,7 @@
         try {
             mService.reportInetCondition(networkType, percentage);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2174,6 +2190,7 @@
             mService.reportNetworkConnectivity(network, true);
             mService.reportNetworkConnectivity(network, false);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2192,6 +2209,7 @@
         try {
             mService.reportNetworkConnectivity(network, hasConnectivity);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2211,6 +2229,7 @@
         try {
             mService.setGlobalProxy(p);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2225,7 +2244,7 @@
         try {
             return mService.getGlobalProxy();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2247,7 +2266,7 @@
         try {
             return mService.getProxyForNetwork(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2282,8 +2301,9 @@
     public boolean isNetworkSupported(int networkType) {
         try {
             return mService.isNetworkSupported(networkType);
-        } catch (RemoteException e) {}
-        return false;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -2303,7 +2323,7 @@
         try {
             return mService.isActiveNetworkMetered();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2320,7 +2340,7 @@
         try {
             return mService.updateLockdownVpn();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2339,6 +2359,7 @@
         try {
             timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
         return timeOutMs;
     }
@@ -2351,8 +2372,8 @@
         try {
             return mService.getMobileProvisioningUrl();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -2369,6 +2390,7 @@
         try {
             mService.setProvisioningNotificationVisible(visible, networkType, action);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2385,6 +2407,7 @@
         try {
             mService.setAirplaneMode(enable);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2392,14 +2415,18 @@
     public void registerNetworkFactory(Messenger messenger, String name) {
         try {
             mService.registerNetworkFactory(messenger, name);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /** {@hide} */
     public void unregisterNetworkFactory(Messenger messenger) {
         try {
             mService.unregisterNetworkFactory(messenger);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -2412,7 +2439,7 @@
         try {
             return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
         } catch (RemoteException e) {
-            return NETID_UNSET;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2563,9 +2590,11 @@
 
         @Override
         public void handleMessage(Message message) {
-            if (DBG) Log.d(TAG, "CM callback handler got msg " + message.what);
             NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class);
             Network network = (Network) getObject(message, Network.class);
+            if (DBG) {
+                Log.d(TAG, whatToString(message.what) + " for network " + network);
+            }
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
                     NetworkCallback callback = getCallback(request, "PRECHECK");
@@ -2715,7 +2744,9 @@
         if (networkCallback == null) {
             throw new IllegalArgumentException("null NetworkCallback");
         }
-        if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
+        if (need == null && action != REQUEST) {
+            throw new IllegalArgumentException("null NetworkCapabilities");
+        }
         try {
             incCallbackHandlerRefCount();
             synchronized(sNetworkCallback) {
@@ -2730,13 +2761,15 @@
                     sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
                 }
             }
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
         if (networkCallback.networkRequest == null) decCallbackHandlerRefCount();
         return networkCallback.networkRequest;
     }
 
     /**
-     * Helper function to requests a network with a particular legacy type.
+     * Helper function to request a network with a particular legacy type.
      *
      * This is temporarily public @hide so it can be called by system code that uses the
      * NetworkRequest API to request networks but relies on CONNECTIVITY_ACTION broadcasts for
@@ -2893,7 +2926,9 @@
         checkPendingIntent(operation);
         try {
             mService.pendingRequestForNetwork(request.networkCapabilities, operation);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -2911,7 +2946,9 @@
         checkPendingIntent(operation);
         try {
             mService.releasePendingNetworkRequest(operation);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     private void checkPendingIntent(PendingIntent intent) {
@@ -2970,7 +3007,30 @@
         checkPendingIntent(operation);
         try {
             mService.pendingListenForNetwork(request.networkCapabilities, operation);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers to receive notifications about whichever network currently satisfies the
+     * system default {@link NetworkRequest}.  The callbacks will continue to be called until
+     * either the application exits or {@link #unregisterNetworkCallback} is called
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @param networkCallback The {@link NetworkCallback} that the system will call as the
+     *                        system default network changes.
+     */
+    public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
+        // This works because if the NetworkCapabilities are null,
+        // ConnectivityService takes them from the default request.
+        //
+        // Since the capabilities are exactly the same as the default request's
+        // capabilities, this request is guaranteed, at all times, to be
+        // satisfied by the same network, if any, that satisfies the default
+        // request, i.e., the system default network.
+        sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE);
     }
 
     /**
@@ -2988,7 +3048,7 @@
         try {
             return mService.requestBandwidthUpdate(network);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3008,7 +3068,9 @@
         }
         try {
             mService.releaseNetworkRequest(networkCallback.networkRequest);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -3044,7 +3106,9 @@
     public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
         try {
             mService.setAcceptUnvalidated(network, accept, always);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -3055,6 +3119,7 @@
         try {
             mService.factoryReset();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3262,7 +3327,7 @@
         try {
             return getNetworkPolicyManager().getRestrictBackgroundByCaller();
         } catch (RemoteException e) {
-            return RESTRICT_BACKGROUND_STATUS_DISABLED;
+            throw e.rethrowFromSystemServer();
         }
     }
 }
diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
new file mode 100644
index 0000000..a027d7c
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 ConnectivityMetricsEvent;
+parcelable ConnectivityMetricsEvent.Reference;
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
new file mode 100644
index 0000000..b5d67d3
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+/** {@hide} */
+public final class ConnectivityMetricsEvent implements Parcelable {
+
+    /**  The time when this event was collected, as returned by System.currentTimeMillis(). */
+    final public long timestamp;
+
+    /** The subsystem that generated the event. One of the COMPONENT_TAG_xxx constants. */
+    final public int componentTag;
+
+    /** The subsystem-specific event ID. */
+    final public int eventTag;
+
+    /** Opaque event-specific data. */
+    final public Parcelable data;
+
+    public ConnectivityMetricsEvent(long timestamp, int componentTag,
+                                    int eventTag, Parcelable data) {
+        this.timestamp = timestamp;
+        this.componentTag = componentTag;
+        this.eventTag = eventTag;
+        this.data = data;
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Parcelable.Creator<ConnectivityMetricsEvent> CREATOR
+            = new Parcelable.Creator<ConnectivityMetricsEvent> (){
+        public ConnectivityMetricsEvent createFromParcel(Parcel source) {
+            final long timestamp = source.readLong();
+            final int componentTag = source.readInt();
+            final int eventTag = source.readInt();
+            final Parcelable data = source.readParcelable(null);
+            return new ConnectivityMetricsEvent(timestamp, componentTag,
+                    eventTag, data);
+        }
+
+        public ConnectivityMetricsEvent[] newArray(int size) {
+            return new ConnectivityMetricsEvent[size];
+        }
+    };
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(timestamp);
+        dest.writeInt(componentTag);
+        dest.writeInt(eventTag);
+        dest.writeParcelable(data, 0);
+    }
+
+    public String toString() {
+        return String.format("ConnectivityMetricsEvent(%d, %d, %d)", timestamp,
+                componentTag, eventTag);
+    }
+
+    /** {@hide} */
+    public static class Reference implements Parcelable {
+
+        public long value;
+
+        public Reference(long ref) {
+            this.value = ref;
+        }
+
+        /** Implement the Parcelable interface */
+        public static final Parcelable.Creator<Reference> CREATOR
+                = new Parcelable.Creator<Reference> (){
+            public Reference createFromParcel(Parcel source) {
+                return new Reference(source.readLong());
+            }
+
+            public Reference[] newArray(int size) {
+                return new Reference[size];
+            }
+        };
+
+        /** Implement the Parcelable interface */
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface */
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeLong(value);
+        }
+
+        public void readFromParcel(Parcel in) {
+            value = in.readLong();
+        }
+    }
+}
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
new file mode 100644
index 0000000..eafb8ac
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/** {@hide} */
+public class ConnectivityMetricsLogger {
+    private static String TAG = "ConnectivityMetricsLogger";
+    private static final boolean DBG = true;
+
+    public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
+
+    // Component Tags
+    public static final int COMPONENT_TAG_CONNECTIVITY = 0;
+    public static final int COMPONENT_TAG_BLUETOOTH = 1;
+    public static final int COMPONENT_TAG_WIFI = 2;
+    public static final int COMPONENT_TAG_TELECOM = 3;
+    public static final int COMPONENT_TAG_TELEPHONY = 4;
+
+    public static final int NUMBER_OF_COMPONENTS = 5;
+
+    // Event Tag
+    public static final int TAG_SKIPPED_EVENTS = -1;
+
+    public static final String DATA_KEY_EVENTS_COUNT = "count";
+
+    private IConnectivityMetricsLogger mService;
+
+    private long mServiceUnblockedTimestampMillis = 0;
+    private int mNumSkippedEvents = 0;
+
+    public ConnectivityMetricsLogger() {
+        mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
+                CONNECTIVITY_METRICS_LOGGER_SERVICE));
+    }
+
+    public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
+        if (mService == null) {
+            if (DBG) {
+                Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
+            }
+            return;
+        }
+
+        if (mServiceUnblockedTimestampMillis > 0) {
+            if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
+                // Service is throttling events.
+                // Don't send new events because they will be dropped.
+                mNumSkippedEvents++;
+                return;
+            }
+        }
+
+        ConnectivityMetricsEvent skippedEventsEvent = null;
+        if (mNumSkippedEvents > 0) {
+            // Log number of skipped events
+            Bundle b = new Bundle();
+            b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
+            skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
+                    componentTag, TAG_SKIPPED_EVENTS, b);
+
+            mServiceUnblockedTimestampMillis = 0;
+        }
+
+        ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag,
+                eventTag, data);
+
+        try {
+            long result;
+            if (skippedEventsEvent == null) {
+                result = mService.logEvent(event);
+            } else {
+                result = mService.logEvents(new ConnectivityMetricsEvent[]
+                        {skippedEventsEvent, event});
+            }
+
+            if (result == 0) {
+                mNumSkippedEvents = 0;
+            } else {
+                mNumSkippedEvents++;
+                if (result > 0) { // events are throttled
+                    mServiceUnblockedTimestampMillis = result;
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error logging event " + e.getMessage());
+        }
+    }
+}
diff --git a/core/java/android/net/ConnectivityThread.java b/core/java/android/net/ConnectivityThread.java
new file mode 100644
index 0000000..55c3402
--- /dev/null
+++ b/core/java/android/net/ConnectivityThread.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.HandlerThread;
+import android.os.Looper;
+
+/**
+ * Shared singleton connectivity thread for the system.  This is a thread for
+ * connectivity operations such as AsyncChannel connections to system services.
+ * Various connectivity manager objects can use this singleton as a common
+ * resource for their handlers instead of creating separate threads of their own.
+ * @hide
+ */
+public final class ConnectivityThread extends HandlerThread {
+    private static ConnectivityThread sInstance;
+
+    private ConnectivityThread() {
+        super("ConnectivityThread");
+    }
+
+    private static synchronized ConnectivityThread getInstance() {
+        if (sInstance == null) {
+            sInstance = new ConnectivityThread();
+            sInstance.start();
+        }
+        return sInstance;
+    }
+
+    public static ConnectivityThread get() {
+        return getInstance();
+    }
+
+    public static Looper getInstanceLooper() {
+        return getInstance().getLooper();
+    }
+}
diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java
index 5e96cc1..8526584 100644
--- a/core/java/android/net/DataUsageRequest.java
+++ b/core/java/android/net/DataUsageRequest.java
@@ -29,7 +29,7 @@
  * If no {@code uid}s are set, callbacks are restricted to device-owners,
  * carrier-privileged apps, or system apps.
  */
-public class DataUsageRequest implements Parcelable {
+public final class DataUsageRequest implements Parcelable {
 
     /**
      * @hide
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 97bd5d2..8c5f603 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -40,6 +40,9 @@
 
     public int leaseDuration;
 
+    /** Link MTU option. 0 means unset. */
+    public int mtu;
+
     public DhcpResults() {
         super();
     }
@@ -57,19 +60,7 @@
             serverAddress = source.serverAddress;
             vendorInfo = source.vendorInfo;
             leaseDuration = source.leaseDuration;
-        }
-    }
-
-    /**
-     * Updates the DHCP fields that need to be retained from
-     * original DHCP request if the current renewal shows them
-     * being empty.
-     */
-    public void updateFromDhcpRequest(DhcpResults orig) {
-        if (orig == null) return;
-        if (gateway == null) gateway = orig.gateway;
-        if (dnsServers.size() == 0) {
-            dnsServers.addAll(orig.dnsServers);
+            mtu = source.mtu;
         }
     }
 
@@ -89,6 +80,7 @@
         super.clear();
         vendorInfo = null;
         leaseDuration = 0;
+        mtu = 0;
     }
 
     @Override
@@ -98,6 +90,7 @@
         str.append(" DHCP server ").append(serverAddress);
         str.append(" Vendor info ").append(vendorInfo);
         str.append(" lease ").append(leaseDuration).append(" seconds");
+        if (mtu != 0) str.append(" MTU ").append(mtu);
 
         return str.toString();
     }
@@ -113,7 +106,8 @@
         return super.equals((StaticIpConfiguration) obj) &&
                 Objects.equals(serverAddress, target.serverAddress) &&
                 Objects.equals(vendorInfo, target.vendorInfo) &&
-                leaseDuration == target.leaseDuration;
+                leaseDuration == target.leaseDuration &&
+                mtu == target.mtu;
     }
 
     /** Implement the Parcelable interface */
@@ -134,6 +128,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeInt(leaseDuration);
+        dest.writeInt(mtu);
         NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
         dest.writeString(vendorInfo);
     }
@@ -141,6 +136,7 @@
     private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
         StaticIpConfiguration.readFromParcel(dhcpResults, in);
         dhcpResults.leaseDuration = in.readInt();
+        dhcpResults.mtu = in.readInt();
         dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
         dhcpResults.vendorInfo = in.readString();
     }
diff --git a/core/java/android/net/DnsPinger.java b/core/java/android/net/DnsPinger.java
deleted file mode 100644
index 7acf3f5..0000000
--- a/core/java/android/net/DnsPinger.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.util.Protocol;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketTimeoutException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Performs a simple DNS "ping" by sending a "server status" query packet to the
- * DNS server. As long as the server replies, we consider it a success.
- * <p>
- * We do not use a simple hostname lookup because that could be cached and the
- * API may not differentiate between a time out and a failure lookup (which we
- * really care about).
- * <p>
- *
- * @hide
- */
-public final class DnsPinger extends Handler {
-    private static final boolean DBG = false;
-
-    private static final int RECEIVE_POLL_INTERVAL_MS = 200;
-    private static final int DNS_PORT = 53;
-
-    /** Short socket timeout so we don't block one any 'receive' call */
-    private static final int SOCKET_TIMEOUT_MS = 1;
-
-    /** Used to generate IDs */
-    private static final Random sRandom = new Random();
-    private static final AtomicInteger sCounter = new AtomicInteger();
-
-    private ConnectivityManager mConnectivityManager = null;
-    private final Context mContext;
-    private final int mConnectionType;
-    private final Handler mTarget;
-    private final ArrayList<InetAddress> mDefaultDns;
-    private String TAG;
-
-    //Invalidates old dns requests upon a cancel
-    private AtomicInteger mCurrentToken = new AtomicInteger();
-
-    private static final int BASE = Protocol.BASE_DNS_PINGER;
-
-    /**
-     * Async response packet for dns pings.
-     * arg1 is the ID of the ping, also returned by {@link #pingDnsAsync(InetAddress, int, int)}
-     * arg2 is the delay, or is negative on error.
-     */
-    public static final int DNS_PING_RESULT = BASE;
-    /** An error code for a {@link #DNS_PING_RESULT} packet */
-    public static final int TIMEOUT = -1;
-    /** An error code for a {@link #DNS_PING_RESULT} packet */
-    public static final int SOCKET_EXCEPTION = -2;
-
-    /**
-     * Send a new ping via a socket.  arg1 is ID, arg2 is timeout, obj is InetAddress to ping
-     */
-    private static final int ACTION_PING_DNS = BASE + 1;
-    private static final int ACTION_LISTEN_FOR_RESPONSE = BASE + 2;
-    private static final int ACTION_CANCEL_ALL_PINGS = BASE + 3;
-
-    private List<ActivePing> mActivePings = new ArrayList<ActivePing>();
-    private int mEventCounter;
-
-    private class ActivePing {
-        DatagramSocket socket;
-        int internalId;
-        short packetId;
-        int timeout;
-        Integer result;
-        long start = SystemClock.elapsedRealtime();
-    }
-
-    /* Message argument for ACTION_PING_DNS */
-    private class DnsArg {
-        InetAddress dns;
-        int seq;
-
-        DnsArg(InetAddress d, int s) {
-            dns = d;
-            seq = s;
-        }
-    }
-
-    public DnsPinger(Context context, String TAG, Looper looper,
-            Handler target, int connectionType) {
-        super(looper);
-        this.TAG = TAG;
-        mContext = context;
-        mTarget = target;
-        mConnectionType = connectionType;
-        if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
-            throw new IllegalArgumentException("Invalid connectionType in constructor: "
-                    + connectionType);
-        }
-        mDefaultDns = new ArrayList<InetAddress>();
-        mDefaultDns.add(getDefaultDns());
-        mEventCounter = 0;
-    }
-
-    @Override
-    public void handleMessage(Message msg) {
-        switch (msg.what) {
-            case ACTION_PING_DNS:
-                DnsArg dnsArg = (DnsArg) msg.obj;
-                if (dnsArg.seq != mCurrentToken.get()) {
-                    break;
-                }
-                try {
-                    ActivePing newActivePing = new ActivePing();
-                    InetAddress dnsAddress = dnsArg.dns;
-                    newActivePing.internalId = msg.arg1;
-                    newActivePing.timeout = msg.arg2;
-                    newActivePing.socket = new DatagramSocket();
-                    // Set some socket properties
-                    newActivePing.socket.setSoTimeout(SOCKET_TIMEOUT_MS);
-
-                    // Try to bind but continue ping if bind fails
-                    try {
-                        newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
-                                getCurrentLinkProperties().getInterfaceName()));
-                    } catch (Exception e) {
-                        loge("sendDnsPing::Error binding to socket " + e);
-                    }
-
-                    newActivePing.packetId = (short) sRandom.nextInt();
-                    byte[] buf = mDnsQuery.clone();
-                    buf[0] = (byte) (newActivePing.packetId >> 8);
-                    buf[1] = (byte) newActivePing.packetId;
-
-                    // Send the DNS query
-                    DatagramPacket packet = new DatagramPacket(buf,
-                            buf.length, dnsAddress, DNS_PORT);
-                    if (DBG) {
-                        log("Sending a ping " + newActivePing.internalId +
-                                " to " + dnsAddress.getHostAddress()
-                                + " with packetId " + newActivePing.packetId + ".");
-                    }
-
-                    newActivePing.socket.send(packet);
-                    mActivePings.add(newActivePing);
-                    mEventCounter++;
-                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
-                            RECEIVE_POLL_INTERVAL_MS);
-                } catch (IOException e) {
-                    sendResponse(msg.arg1, -9999, SOCKET_EXCEPTION);
-                }
-                break;
-            case ACTION_LISTEN_FOR_RESPONSE:
-                if (msg.arg1 != mEventCounter) {
-                    break;
-                }
-                for (ActivePing curPing : mActivePings) {
-                    try {
-                        /** Each socket will block for {@link #SOCKET_TIMEOUT_MS} in receive() */
-                        byte[] responseBuf = new byte[2];
-                        DatagramPacket replyPacket = new DatagramPacket(responseBuf, 2);
-                        curPing.socket.receive(replyPacket);
-                        // Check that ID field matches (we're throwing out the rest of the packet)
-                        if (responseBuf[0] == (byte) (curPing.packetId >> 8) &&
-                                responseBuf[1] == (byte) curPing.packetId) {
-                            curPing.result =
-                                    (int) (SystemClock.elapsedRealtime() - curPing.start);
-                        } else {
-                            if (DBG) {
-                                log("response ID didn't match, ignoring packet");
-                            }
-                        }
-                    } catch (SocketTimeoutException e) {
-                        // A timeout here doesn't mean anything - squelsh this exception
-                    } catch (Exception e) {
-                        if (DBG) {
-                            log("DnsPinger.pingDns got socket exception: " + e);
-                        }
-                        curPing.result = SOCKET_EXCEPTION;
-                    }
-                }
-                Iterator<ActivePing> iter = mActivePings.iterator();
-                while (iter.hasNext()) {
-                   ActivePing curPing = iter.next();
-                   if (curPing.result != null) {
-                       sendResponse(curPing.internalId, curPing.packetId, curPing.result);
-                       curPing.socket.close();
-                       iter.remove();
-                   } else if (SystemClock.elapsedRealtime() >
-                                  curPing.start + curPing.timeout) {
-                       sendResponse(curPing.internalId, curPing.packetId, TIMEOUT);
-                       curPing.socket.close();
-                       iter.remove();
-                   }
-                }
-                if (!mActivePings.isEmpty()) {
-                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
-                            RECEIVE_POLL_INTERVAL_MS);
-                }
-                break;
-            case ACTION_CANCEL_ALL_PINGS:
-                for (ActivePing activePing : mActivePings)
-                    activePing.socket.close();
-                mActivePings.clear();
-                break;
-        }
-    }
-
-    /**
-     * Returns a list of DNS addresses, coming from either the link properties of the
-     * specified connection or the default system DNS if the link properties has no dnses.
-     * @return a non-empty non-null list
-     */
-    public List<InetAddress> getDnsList() {
-        LinkProperties curLinkProps = getCurrentLinkProperties();
-        if (curLinkProps == null) {
-            loge("getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
-            return mDefaultDns;
-        }
-
-        Collection<InetAddress> dnses = curLinkProps.getDnsServers();
-        if (dnses == null || dnses.size() == 0) {
-            loge("getDns::LinkProps has null dns - returning default");
-            return mDefaultDns;
-        }
-
-        return new ArrayList<InetAddress>(dnses);
-    }
-
-    /**
-     * Send a ping.  The response will come via a {@link #DNS_PING_RESULT} to the handler
-     * specified at creation.
-     * @param dns address of dns server to ping
-     * @param timeout timeout for ping
-     * @return an ID field, which will also be included in the {@link #DNS_PING_RESULT} message.
-     */
-    public int pingDnsAsync(InetAddress dns, int timeout, int delay) {
-        int id = sCounter.incrementAndGet();
-        sendMessageDelayed(obtainMessage(ACTION_PING_DNS, id, timeout,
-                new DnsArg(dns, mCurrentToken.get())), delay);
-        return id;
-    }
-
-    public void cancelPings() {
-        mCurrentToken.incrementAndGet();
-        obtainMessage(ACTION_CANCEL_ALL_PINGS).sendToTarget();
-    }
-
-    private void sendResponse(int internalId, int externalId, int responseVal) {
-        if(DBG) {
-            log("Responding to packet " + internalId +
-                    " externalId " + externalId +
-                    " and val " + responseVal);
-        }
-        mTarget.sendMessage(obtainMessage(DNS_PING_RESULT, internalId, responseVal));
-    }
-
-    private LinkProperties getCurrentLinkProperties() {
-        if (mConnectivityManager == null) {
-            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
-                    Context.CONNECTIVITY_SERVICE);
-        }
-
-        return mConnectivityManager.getLinkProperties(mConnectionType);
-    }
-
-    private InetAddress getDefaultDns() {
-        String dns = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.DEFAULT_DNS_SERVER);
-        if (dns == null || dns.length() == 0) {
-            dns = mContext.getResources().getString(
-                    com.android.internal.R.string.config_default_dns_server);
-        }
-        try {
-            return NetworkUtils.numericToInetAddress(dns);
-        } catch (IllegalArgumentException e) {
-            loge("getDefaultDns::malformed default dns address");
-            return null;
-        }
-    }
-
-    private static final byte[] mDnsQuery = new byte[] {
-        0, 0, // [0-1] is for ID (will set each time)
-        1, 0, // [2-3] are flags.  Set byte[2] = 1 for recursion desired (RD) on.  Currently on.
-        0, 1, // [4-5] bytes are for number of queries (QCOUNT)
-        0, 0, // [6-7] unused count field for dns response packets
-        0, 0, // [8-9] unused count field for dns response packets
-        0, 0, // [10-11] unused count field for dns response packets
-        3, 'w', 'w', 'w',
-        6, 'g', 'o', 'o', 'g', 'l', 'e',
-        3, 'c', 'o', 'm',
-        0,    // null terminator of address (also called empty TLD)
-        0, 1, // QTYPE, set to 1 = A (host address)
-        0, 1  // QCLASS, set to 1 = IN (internet)
-    };
-
-    private void log(String s) {
-        Log.d(TAG, s);
-    }
-
-    private void loge(String s) {
-        Log.e(TAG, s);
-    }
-}
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index f45737a..664b7b4 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -87,8 +87,8 @@
     public IpConfiguration getConfiguration() {
         try {
             return mService.getConfiguration();
-        } catch (NullPointerException | RemoteException e) {
-            return new IpConfiguration();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -98,7 +98,8 @@
     public void setConfiguration(IpConfiguration config) {
         try {
             mService.setConfiguration(config);
-        } catch (NullPointerException | RemoteException e) {
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -109,8 +110,8 @@
     public boolean isAvailable() {
         try {
             return mService.isAvailable();
-        } catch (NullPointerException | RemoteException e) {
-            return false;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -127,7 +128,8 @@
         if (mListeners.size() == 1) {
             try {
                 mService.addListener(mServiceListener);
-            } catch (NullPointerException | RemoteException e) {
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -145,7 +147,8 @@
         if (mListeners.isEmpty()) {
             try {
                 mService.removeListener(mServiceListener);
-            } catch (NullPointerException | RemoteException e) {
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
diff --git a/core/java/android/net/IConnectivityMetricsLogger.aidl b/core/java/android/net/IConnectivityMetricsLogger.aidl
new file mode 100644
index 0000000..a83a019
--- /dev/null
+++ b/core/java/android/net/IConnectivityMetricsLogger.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.app.PendingIntent;
+import android.net.ConnectivityMetricsEvent;
+
+/** {@hide} */
+interface IConnectivityMetricsLogger {
+
+    /**
+     * @return 0 on success
+     *        <0 if error happened
+     *        >0 timestamp after which new events will be accepted
+     */
+    long logEvent(in ConnectivityMetricsEvent event);
+    long logEvents(in ConnectivityMetricsEvent[] events);
+
+    /**
+     * @param reference of the last event previously returned. The function will return
+     *                  events following it.
+     *                  If 0 then all events will be returned.
+     *                  After the function call it will contain reference of the last event.
+     */
+    ConnectivityMetricsEvent[] getEvents(inout ConnectivityMetricsEvent.Reference reference);
+
+    boolean register(in PendingIntent newEventsIntent);
+    void unregister(in PendingIntent newEventsIntent);
+}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index e27c0fb..64186145 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -248,7 +248,7 @@
      * for a network to satisfy a request, all capabilities requested must be satisfied.
      *
      * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
-     * @return This NetworkCapability to facilitate chaining.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
     public NetworkCapabilities addCapability(int capability) {
@@ -263,7 +263,7 @@
      * Removes (if found) the given capability from this {@code NetworkCapability} instance.
      *
      * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
-     * @return This NetworkCapability to facilitate chaining.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
     public NetworkCapabilities removeCapability(int capability) {
@@ -418,7 +418,7 @@
      * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
      *
      * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
-     * @return This NetworkCapability to facilitate chaining.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
     public NetworkCapabilities addTransportType(int transportType) {
@@ -434,7 +434,7 @@
      * Removes (if found) the given transport from this {@code NetworkCapability} instance.
      *
      * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
-     * @return This NetworkCapability to facilitate chaining.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
     public NetworkCapabilities removeTransportType(int transportType) {
@@ -578,14 +578,16 @@
      * @param networkSpecifier An {@code String} of opaque format used to specify the bearer
      *                         specific network specifier where the bearer has a choice of
      *                         networks.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
-    public void setNetworkSpecifier(String networkSpecifier) {
+    public NetworkCapabilities setNetworkSpecifier(String networkSpecifier) {
         if (TextUtils.isEmpty(networkSpecifier) == false && Long.bitCount(mTransportTypes) != 1) {
             throw new IllegalStateException("Must have a single transport specified to use " +
                     "setNetworkSpecifier");
         }
         mNetworkSpecifier = networkSpecifier;
+        return this;
     }
 
     /**
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a83e722..e464a4a 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -57,6 +57,10 @@
     public static final int RULE_REJECT_METERED = 1;
     /** Reject traffic on all networks. */
     public static final int RULE_REJECT_ALL = 2;
+    /** Allow traffic on metered networks. */
+    public static final int RULE_ALLOW_METERED = 3;
+    /** Temporarily allow traffic on metered networks because app is on foreground. */
+    public static final int RULE_TEMPORARY_ALLOW_METERED = 4;
 
     public static final int FIREWALL_RULE_DEFAULT = 0;
     public static final int FIREWALL_RULE_ALLOW = 1;
@@ -68,10 +72,12 @@
     public static final int FIREWALL_CHAIN_NONE = 0;
     public static final int FIREWALL_CHAIN_DOZABLE = 1;
     public static final int FIREWALL_CHAIN_STANDBY = 2;
+    public static final int FIREWALL_CHAIN_POWERSAVE = 3;
 
     public static final String FIREWALL_CHAIN_NAME_NONE = "none";
     public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable";
     public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
+    public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave";
 
     private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
 
@@ -106,6 +112,7 @@
         try {
             mService.setUidPolicy(uid, policy);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -118,6 +125,7 @@
         try {
             mService.addUidPolicy(uid, policy);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -130,6 +138,7 @@
         try {
             mService.removeUidPolicy(uid, policy);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -137,7 +146,7 @@
         try {
             return mService.getUidPolicy(uid);
         } catch (RemoteException e) {
-            return POLICY_NONE;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -145,7 +154,7 @@
         try {
             return mService.getUidsWithPolicy(policy);
         } catch (RemoteException e) {
-            return new int[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -153,6 +162,7 @@
         try {
             mService.registerListener(listener);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -160,6 +170,7 @@
         try {
             mService.unregisterListener(listener);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -167,6 +178,7 @@
         try {
             mService.setNetworkPolicies(policies);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -174,7 +186,7 @@
         try {
             return mService.getNetworkPolicies(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -182,6 +194,7 @@
         try {
             mService.setRestrictBackground(restrictBackground);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -189,7 +202,7 @@
         try {
             return mService.getRestrictBackground();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -202,6 +215,7 @@
         try {
             mService.factoryReset(subscriber);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index b6fe68a..01c160f 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -166,7 +166,7 @@
         try {
             return mService.updateScores(networks);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -186,7 +186,7 @@
         try {
             return mService.clearScores();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -206,7 +206,7 @@
         try {
             return mService.setActiveScorer(packageName);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -221,6 +221,7 @@
         try {
             mService.disableScoring();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -265,6 +266,7 @@
         try {
             mService.registerNetworkScoreCache(networkType, scoreCache);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 }
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index e555fa4..29291ca 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -19,11 +19,9 @@
 import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.Nullable;
-import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.UserHandle;
@@ -69,12 +67,32 @@
          */
         public final String mConfigurationActivityClassName;
 
+        /**
+         * Optional class name of the scoring service we can bind to. Null if none is set.
+         */
+        public final String mScoringServiceClassName;
+
         public NetworkScorerAppData(String packageName, int packageUid, CharSequence scorerName,
-                @Nullable String configurationActivityClassName) {
+                @Nullable String configurationActivityClassName,
+                @Nullable String scoringServiceClassName) {
             mScorerName = scorerName;
             mPackageName = packageName;
             mPackageUid = packageUid;
             mConfigurationActivityClassName = configurationActivityClassName;
+            mScoringServiceClassName = scoringServiceClassName;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("NetworkScorerAppData{");
+            sb.append("mPackageName='").append(mPackageName).append('\'');
+            sb.append(", mPackageUid=").append(mPackageUid);
+            sb.append(", mScorerName=").append(mScorerName);
+            sb.append(", mConfigurationActivityClassName='").append(mConfigurationActivityClassName)
+                    .append('\'');
+            sb.append(", mScoringServiceClassName='").append(mScoringServiceClassName).append('\'');
+            sb.append('}');
+            return sb.toString();
         }
     }
 
@@ -128,18 +146,27 @@
             Intent intent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE);
             intent.setPackage(receiverInfo.packageName);
             List<ResolveInfo> configActivities = pm.queryIntentActivities(intent, 0 /* flags */);
-            if (!configActivities.isEmpty()) {
+            if (configActivities != null && !configActivities.isEmpty()) {
                 ActivityInfo activityInfo = configActivities.get(0).activityInfo;
                 if (activityInfo != null) {
                     configurationActivityClassName = activityInfo.name;
                 }
             }
 
+            // Find the scoring service class we can bind to, if any.
+            String scoringServiceClassName = null;
+            Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_SCORE_NETWORKS);
+            serviceIntent.setPackage(receiverInfo.packageName);
+            ResolveInfo resolveServiceInfo = pm.resolveService(serviceIntent, 0 /* flags */);
+            if (resolveServiceInfo != null && resolveServiceInfo.serviceInfo != null) {
+                scoringServiceClassName = resolveServiceInfo.serviceInfo.name;
+            }
+
             // NOTE: loadLabel will attempt to load the receiver's label and fall back to the
             // app label if none is present.
             scorers.add(new NetworkScorerAppData(receiverInfo.packageName,
                     receiverInfo.applicationInfo.uid, receiverInfo.loadLabel(pm),
-                    configurationActivityClassName));
+                    configurationActivityClassName, scoringServiceClassName));
         }
 
         return scorers;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 3d8b091..25806fa 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -71,9 +71,9 @@
     /** {@link #set} value for all roaming values. */
     public static final int ROAMING_ALL = -1;
     /** {@link #set} value where native, non-roaming data is accounted. */
-    public static final int ROAMING_DEFAULT = 0;
+    public static final int ROAMING_NO = 0;
     /** {@link #set} value where roaming data is accounted. */
-    public static final int ROAMING_ROAMING = 1;
+    public static final int ROAMING_YES = 1;
 
     // TODO: move fields to "mVariable" notation
 
@@ -123,7 +123,7 @@
 
         public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
                 long txBytes, long txPackets, long operations) {
-            this(iface, uid, set, tag, ROAMING_DEFAULT, rxBytes, rxPackets, txBytes, txPackets,
+            this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets,
                     operations);
         }
 
@@ -836,10 +836,10 @@
         switch (roaming) {
             case ROAMING_ALL:
                 return "ALL";
-            case ROAMING_DEFAULT:
-                return "DEFAULT";
-            case ROAMING_ROAMING:
-                return "ROAMING";
+            case ROAMING_NO:
+                return "NO";
+            case ROAMING_YES:
+                return "YES";
             default:
                 return "UNKNOWN";
         }
@@ -1019,18 +1019,18 @@
         // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
         // the TAG_NONE traffic.
         //
-        // Relies on the fact that the underlying traffic only has state ROAMING_DEFAULT, which
+        // Relies on the fact that the underlying traffic only has state ROAMING_NO, which
         // should be the case as it comes directly from the /proc file. We only blend in the
         // roaming data after applying these adjustments, by checking the NetworkIdentity of the
         // underlying iface.
         int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
-                ROAMING_DEFAULT);
+                ROAMING_NO);
         if (idxVpnBackground != -1) {
             tunSubtract(idxVpnBackground, this, moved);
         }
 
         int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
-                ROAMING_DEFAULT);
+                ROAMING_NO);
         if (idxVpnForeground != -1) {
             tunSubtract(idxVpnForeground, this, moved);
         }
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 5761d66..b32b2cc 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -18,6 +18,7 @@
 
 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
 import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static android.net.ConnectivityManager.TYPE_PROXY;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
@@ -68,6 +69,7 @@
     public static final int MATCH_MOBILE_WILDCARD = 6;
     public static final int MATCH_WIFI_WILDCARD = 7;
     public static final int MATCH_BLUETOOTH = 8;
+    public static final int MATCH_PROXY = 9;
 
     /**
      * Set of {@link NetworkInfo#getType()} that reflect data usage.
@@ -157,6 +159,14 @@
         return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
     }
 
+    /**
+     * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style
+     * networks together.
+     */
+    public static NetworkTemplate buildTemplateProxy() {
+        return new NetworkTemplate(MATCH_PROXY, null, null);
+    }
+
     private final int mMatchRule;
     private final String mSubscriberId;
 
@@ -250,6 +260,16 @@
         }
     }
 
+    public boolean isPersistable() {
+        switch (mMatchRule) {
+            case MATCH_MOBILE_WILDCARD:
+            case MATCH_WIFI_WILDCARD:
+                return false;
+            default:
+                return true;
+        }
+    }
+
     public int getMatchRule() {
         return mMatchRule;
     }
@@ -283,6 +303,8 @@
                 return matchesWifiWildcard(ident);
             case MATCH_BLUETOOTH:
                 return matchesBluetooth(ident);
+            case MATCH_PROXY:
+                return matchesProxy(ident);
             default:
                 throw new IllegalArgumentException("unknown network template");
         }
@@ -391,6 +413,13 @@
         return false;
     }
 
+    /**
+     * Check if matches Proxy network template.
+     */
+    private boolean matchesProxy(NetworkIdentity ident) {
+        return ident.mType == TYPE_PROXY;
+    }
+
     private static String getMatchRuleName(int matchRule) {
         switch (matchRule) {
             case MATCH_MOBILE_3G_LOWER:
@@ -409,6 +438,8 @@
                 return "WIFI_WILDCARD";
             case MATCH_BLUETOOTH:
                 return "BLUETOOTH";
+            case MATCH_PROXY:
+                return "PROXY";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index c6d919f..141af3d 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -39,29 +39,19 @@
 
     private static final String TAG = "NetworkUtils";
 
-    /** Setting bit 0 indicates reseting of IPv4 addresses required */
-    public static final int RESET_IPV4_ADDRESSES = 0x01;
-
-    /** Setting bit 1 indicates reseting of IPv4 addresses required */
-    public static final int RESET_IPV6_ADDRESSES = 0x02;
-
-    /** Reset all addresses */
-    public static final int RESET_ALL_ADDRESSES = RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES;
-
-    /**
-     * Reset IPv6 or IPv4 sockets that are connected via the named interface.
-     *
-     * @param interfaceName is the interface to reset
-     * @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES}
-     */
-    public native static int resetConnections(String interfaceName, int mask);
-
     /**
      * Attaches a socket filter that accepts DHCP packets to the given socket.
      */
     public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
 
     /**
+     * Attaches a socket filter that accepts ICMP6 router advertisement packets to the given socket.
+     * @param fd the socket's {@link FileDescriptor}.
+     * @param packetType the hardware address type, one of ARPHRD_*.
+     */
+    public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
+
+    /**
      * Binds the current process to the network designated by {@code netId}.  All sockets created
      * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
      * {@link Network#getSocketFactory}) will be bound to this network.  Note that if this
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index 2dfb061..8582150 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -43,6 +43,16 @@
     public final RssiCurve rssiCurve;
 
     /**
+     * A boolean value that indicates whether or not the network is believed to be metered.
+     *
+     * <p>A network can be classified as metered if the user would be
+     * sensitive to heavy data usage on that connection due to monetary costs,
+     * data limitations or battery/performance issues. A typical example would
+     * be a wifi connection where the user would be charged for usage.
+     */
+    public final boolean meteredHint;
+
+    /**
      * Construct a new {@link ScoredNetwork}.
      *
      * @param networkKey the {@link NetworkKey} uniquely identifying this network.
@@ -54,8 +64,26 @@
      *     the scorer may choose to issue an out-of-band update at any time.
      */
     public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve) {
+        this(networkKey, rssiCurve, false /* meteredHint */);
+    }
+
+    /**
+     * Construct a new {@link ScoredNetwork}.
+     *
+     * @param networkKey the {@link NetworkKey} uniquely identifying this network.
+     * @param rssiCurve the {@link RssiCurve} representing the scores for this network based on the
+     *     RSSI. This field is optional, and may be skipped to represent a network which the scorer
+     *     has opted not to score at this time. Passing a null value here is strongly preferred to
+     *     not returning any {@link ScoredNetwork} for a given {@link NetworkKey} because it
+     *     indicates to the system not to request scores for this network in the future, although
+     *     the scorer may choose to issue an out-of-band update at any time.
+     * @param meteredHint A boolean value indicating whether or not the network is believed to be
+     *     metered.
+     */
+    public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint) {
         this.networkKey = networkKey;
         this.rssiCurve = rssiCurve;
+        this.meteredHint = meteredHint;
     }
 
     private ScoredNetwork(Parcel in) {
@@ -65,6 +93,7 @@
         } else {
             rssiCurve = null;
         }
+        meteredHint = in.readByte() != 0;
     }
 
     @Override
@@ -81,6 +110,7 @@
         } else {
             out.writeByte((byte) 0);
         }
+        out.writeByte((byte) (meteredHint ? 1 : 0));
     }
 
     @Override
@@ -90,18 +120,20 @@
 
         ScoredNetwork that = (ScoredNetwork) o;
 
-        return Objects.equals(networkKey, that.networkKey) &&
-                Objects.equals(rssiCurve, that.rssiCurve);
+        return Objects.equals(networkKey, that.networkKey)
+            && Objects.equals(rssiCurve, that.rssiCurve)
+            && Objects.equals(meteredHint, that.meteredHint);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(networkKey, rssiCurve);
+        return Objects.hash(networkKey, rssiCurve, meteredHint);
     }
 
     @Override
     public String toString() {
-        return "ScoredNetwork[key=" + networkKey + ",score=" + rssiCurve + "]";
+        return "ScoredNetwork[key=" + networkKey + ",score=" + rssiCurve
+            + ",meteredHint=" + meteredHint + "]";
     }
 
     public static final Parcelable.Creator<ScoredNetwork> CREATOR =
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index e82485d..cfd0468 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.app.DownloadManager;
 import android.app.backup.BackupManager;
+import android.app.usage.NetworkStatsManager;
 import android.content.Context;
 import android.media.MediaPlayer;
 import android.os.RemoteException;
@@ -33,12 +34,16 @@
 import java.net.SocketException;
 
 /**
- * Class that provides network traffic statistics.  These statistics include
+ * Class that provides network traffic statistics. These statistics include
  * bytes transmitted and received and network packets transmitted and received,
  * over all interfaces, over the mobile interface, and on a per-UID basis.
  * <p>
- * These statistics may not be available on all platforms.  If the statistics
- * are not supported by this device, {@link #UNSUPPORTED} will be returned.
+ * These statistics may not be available on all platforms. If the statistics are
+ * not supported by this device, {@link #UNSUPPORTED} will be returned.
+ * <p>
+ * Note that the statistics returned by this class reset and start from zero
+ * after every reboot. To access more robust historical network statistics data,
+ * use {@link NetworkStatsManager} instead.
  */
 public class TrafficStats {
     /**
@@ -142,8 +147,10 @@
     }
 
     /**
-     * System API for backup-related support components to tag network traffic
-     * appropriately.
+     * Set active tag to use when accounting {@link Socket} traffic originating
+     * from the current thread. The tag used internally is well-defined to
+     * distinguish all backup-related traffic.
+     *
      * @hide
      */
     @SystemApi
@@ -152,8 +159,10 @@
     }
 
     /**
-     * System API for restore-related support components to tag network traffic
-     * appropriately.
+     * Set active tag to use when accounting {@link Socket} traffic originating
+     * from the current thread. The tag used internally is well-defined to
+     * distinguish all restore-related traffic.
+     *
      * @hide
      */
     @SystemApi
@@ -200,7 +209,13 @@
         NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
     }
 
-    /** {@hide} */
+    /**
+     * Clear any active UID set to account {@link Socket} traffic originating
+     * from the current thread.
+     *
+     * @see #setThreadStatsUid(int)
+     * @hide
+     */
     @SystemApi
     public static void clearThreadStatsUid() {
         NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
@@ -310,7 +325,7 @@
         try {
             getStatsService().incrementOperationCount(uid, tag, operationCount);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -497,14 +512,27 @@
      * monotonically since device boot. Statistics are measured at the network
      * layer, so they include both TCP and UDP usage.
      * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
-     * {@link #UNSUPPORTED} on devices where statistics aren't available.
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+     * report traffic statistics for the calling UID. It will return
+     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+     * historical network statistics belonging to other UIDs, use
+     * {@link NetworkStatsManager}.
      *
      * @see android.os.Process#myUid()
      * @see android.content.pm.ApplicationInfo#uid
      */
     public static long getUidTxBytes(int uid) {
-        return nativeGetUidStat(uid, TYPE_TX_BYTES);
+        // This isn't actually enforcing any security; it just returns the
+        // unsupported value. The real filtering is done at the kernel level.
+        final int callingUid = android.os.Process.myUid();
+        if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+            return nativeGetUidStat(uid, TYPE_TX_BYTES);
+        } else {
+            return UNSUPPORTED;
+        }
     }
 
     /**
@@ -515,12 +543,25 @@
      * <p>
      * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
      * {@link #UNSUPPORTED} on devices where statistics aren't available.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+     * report traffic statistics for the calling UID. It will return
+     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+     * historical network statistics belonging to other UIDs, use
+     * {@link NetworkStatsManager}.
      *
      * @see android.os.Process#myUid()
      * @see android.content.pm.ApplicationInfo#uid
      */
     public static long getUidRxBytes(int uid) {
-        return nativeGetUidStat(uid, TYPE_RX_BYTES);
+        // This isn't actually enforcing any security; it just returns the
+        // unsupported value. The real filtering is done at the kernel level.
+        final int callingUid = android.os.Process.myUid();
+        if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+            return nativeGetUidStat(uid, TYPE_RX_BYTES);
+        } else {
+            return UNSUPPORTED;
+        }
     }
 
     /**
@@ -531,12 +572,25 @@
      * <p>
      * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
      * {@link #UNSUPPORTED} on devices where statistics aren't available.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+     * report traffic statistics for the calling UID. It will return
+     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+     * historical network statistics belonging to other UIDs, use
+     * {@link NetworkStatsManager}.
      *
      * @see android.os.Process#myUid()
      * @see android.content.pm.ApplicationInfo#uid
      */
     public static long getUidTxPackets(int uid) {
-        return nativeGetUidStat(uid, TYPE_TX_PACKETS);
+        // This isn't actually enforcing any security; it just returns the
+        // unsupported value. The real filtering is done at the kernel level.
+        final int callingUid = android.os.Process.myUid();
+        if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+            return nativeGetUidStat(uid, TYPE_TX_PACKETS);
+        } else {
+            return UNSUPPORTED;
+        }
     }
 
     /**
@@ -547,12 +601,25 @@
      * <p>
      * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
      * {@link #UNSUPPORTED} on devices where statistics aren't available.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+     * report traffic statistics for the calling UID. It will return
+     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+     * historical network statistics belonging to other UIDs, use
+     * {@link NetworkStatsManager}.
      *
      * @see android.os.Process#myUid()
      * @see android.content.pm.ApplicationInfo#uid
      */
     public static long getUidRxPackets(int uid) {
-        return nativeGetUidStat(uid, TYPE_RX_PACKETS);
+        // This isn't actually enforcing any security; it just returns the
+        // unsupported value. The real filtering is done at the kernel level.
+        final int callingUid = android.os.Process.myUid();
+        if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+            return nativeGetUidStat(uid, TYPE_RX_PACKETS);
+        } else {
+            return UNSUPPORTED;
+        }
     }
 
     /**
@@ -653,7 +720,7 @@
         try {
             return getStatsService().getDataLayerSnapshotForUid(uid);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -666,7 +733,7 @@
         try {
             return getStatsService().getMobileIfaces();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java b/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java
new file mode 100644
index 0000000..2239a25
--- /dev/null
+++ b/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class CaptivePortalCheckResultEvent extends IpConnectivityEvent implements Parcelable {
+    public static final String TAG = "CaptivePortalCheckResultEvent";
+
+    private int mNetId;
+    private int mResult;
+
+    public CaptivePortalCheckResultEvent(int netId, int result) {
+        mNetId = netId;
+        mResult = result;
+    }
+
+    public CaptivePortalCheckResultEvent(Parcel in) {
+        mNetId = in.readInt();
+        mResult = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mNetId);
+        out.writeInt(mResult);
+    }
+
+    public static final Parcelable.Creator<CaptivePortalCheckResultEvent> CREATOR
+        = new Parcelable.Creator<CaptivePortalCheckResultEvent>() {
+            public CaptivePortalCheckResultEvent createFromParcel(Parcel in) {
+                return new CaptivePortalCheckResultEvent(in);
+            }
+
+            public CaptivePortalCheckResultEvent[] newArray(int size) {
+                return new CaptivePortalCheckResultEvent[size];
+            }
+        };
+
+    public static void logEvent(int netId, int result) {
+        IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_NETMON_CHECK_RESULT,
+                new CaptivePortalCheckResultEvent(netId, result));
+    }
+};
diff --git a/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
new file mode 100644
index 0000000..00808c1
--- /dev/null
+++ b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class CaptivePortalStateChangeEvent extends IpConnectivityEvent implements Parcelable {
+    public static final String TAG = "CaptivePortalStateChangeEvent";
+
+    public static final int NETWORK_MONITOR_CONNECTED = 0;
+    public static final int NETWORK_MONITOR_DISCONNECTED = 1;
+    public static final int NETWORK_MONITOR_VALIDATED = 2;
+    private int mState;
+
+    public CaptivePortalStateChangeEvent(int state) {
+        mState = state;
+    }
+
+    public CaptivePortalStateChangeEvent(Parcel in) {
+        mState = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mState);
+    }
+
+    public static final Parcelable.Creator<CaptivePortalStateChangeEvent> CREATOR
+        = new Parcelable.Creator<CaptivePortalStateChangeEvent>() {
+        public CaptivePortalStateChangeEvent createFromParcel(Parcel in) {
+            return new CaptivePortalStateChangeEvent(in);
+        }
+
+        public CaptivePortalStateChangeEvent[] newArray(int size) {
+            return new CaptivePortalStateChangeEvent[size];
+        }
+    };
+
+    public static void logEvent(int state) {
+        IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_NETMON_STATE_CHANGE,
+                new CaptivePortalStateChangeEvent(state));
+    }
+};
diff --git a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
new file mode 100644
index 0000000..c6fcb2d
--- /dev/null
+++ b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class ConnectivityServiceChangeEvent extends IpConnectivityEvent implements Parcelable {
+    public static final String TAG = "ConnectivityServiceChangeEvent";
+
+    private int mNetId;
+
+    public ConnectivityServiceChangeEvent(int netId) {
+        mNetId = netId;
+    }
+
+    public ConnectivityServiceChangeEvent(Parcel in) {
+        mNetId = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mNetId);
+    }
+
+    public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
+        = new Parcelable.Creator<ConnectivityServiceChangeEvent>() {
+        public ConnectivityServiceChangeEvent createFromParcel(Parcel in) {
+            return new ConnectivityServiceChangeEvent(in);
+        }
+
+        public ConnectivityServiceChangeEvent[] newArray(int size) {
+            return new ConnectivityServiceChangeEvent[size];
+        }
+    };
+
+    public static void logEvent(int netId) {
+        IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_CONSRV_DEFAULT_NET_CHANGE,
+                new ConnectivityServiceChangeEvent(netId));
+    }
+};
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
new file mode 100644
index 0000000..7b44664
--- /dev/null
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class DhcpClientEvent extends IpConnectivityEvent implements Parcelable {
+    public static final String TAG = "DhcpClientEvent";
+
+    private String mIfName;
+    private String mMsg;
+
+    public DhcpClientEvent(String ifName, String msg) {
+        mIfName = ifName;
+        mMsg = msg;
+    }
+
+    public DhcpClientEvent(Parcel in) {
+        mIfName = in.readString();
+        mMsg = in.readString();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mIfName);
+        out.writeString(mMsg);
+    }
+
+    public static final Parcelable.Creator<DhcpClientEvent> CREATOR
+        = new Parcelable.Creator<DhcpClientEvent>() {
+        public DhcpClientEvent createFromParcel(Parcel in) {
+            return new DhcpClientEvent(in);
+        }
+
+        public DhcpClientEvent[] newArray(int size) {
+            return new DhcpClientEvent[size];
+        }
+    };
+
+    public static void logEvent(int eventType, String ifName, String msg) {
+        IpConnectivityEvent.logEvent(eventType, new DhcpClientEvent(ifName, msg));
+    }
+};
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
new file mode 100644
index 0000000..ec42890
--- /dev/null
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.metrics;
+
+import android.net.ConnectivityMetricsLogger;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpConnectivityEvent implements Parcelable {
+    // IPRM = IpReachabilityMonitor
+    // DHCP = DhcpClient
+    // NETMON = NetworkMonitorEvent
+    // CONSRV = ConnectivityServiceEvent
+    public static final String TAG = "IpConnectivityEvent";
+    public static final int IPCE_IPRM_BASE = 0*1024;
+    public static final int IPCE_DHCP_BASE = 1*1024;
+    public static final int IPCE_NETMON_BASE = 2*1024;
+    public static final int IPCE_CONSRV_BASE = 3*1024;
+
+    public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
+    public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
+    public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
+    public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
+    public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2;
+    public static final int IPCE_DHCP_STATE_CHANGE = IPCE_DHCP_BASE + 3;
+    public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0;
+    public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1;
+    public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
+
+    private static ConnectivityMetricsLogger mMetricsLogger = new ConnectivityMetricsLogger();
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+    }
+
+    public static void logEvent(int tag, IpConnectivityEvent event) {
+        long timestamp = System.currentTimeMillis();
+        mMetricsLogger.logEvent(timestamp, ConnectivityMetricsLogger.COMPONENT_TAG_CONNECTIVITY,
+                tag, event);
+    }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
new file mode 100644
index 0000000..e71b0be
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpReachabilityMonitorMessageEvent extends IpConnectivityEvent
+    implements Parcelable {
+    public static final String TAG = "IpReachabilityMonitorMessageEvent";
+
+    private String mIfName;
+    private String mDestination;
+    private int mMsgType;
+    private int mNudState;
+
+    public IpReachabilityMonitorMessageEvent(String ifName, String destination, int msgType,
+            int nudState) {
+        mIfName = ifName;
+        mDestination = destination;
+        mMsgType = msgType;
+        mNudState = nudState;
+    }
+
+    public IpReachabilityMonitorMessageEvent(Parcel in) {
+        mIfName = in.readString();
+        mDestination = in.readString();
+        mMsgType = in.readInt();
+        mNudState = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mIfName);
+        out.writeString(mDestination);
+        out.writeInt(mMsgType);
+        out.writeInt(mNudState);
+    }
+
+    public static final Parcelable.Creator<IpReachabilityMonitorMessageEvent> CREATOR
+        = new Parcelable.Creator<IpReachabilityMonitorMessageEvent>() {
+        public IpReachabilityMonitorMessageEvent createFromParcel(Parcel in) {
+            return new IpReachabilityMonitorMessageEvent(in);
+        }
+
+        public IpReachabilityMonitorMessageEvent[] newArray(int size) {
+            return new IpReachabilityMonitorMessageEvent[size];
+        }
+    };
+
+    public static void logEvent(String ifName, String destination, int msgType, int nudState) {
+        IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_IPRM_MESSAGE_RECEIVED,
+                new IpReachabilityMonitorMessageEvent(ifName, destination, msgType, nudState));
+    }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
new file mode 100644
index 0000000..182b778
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpReachabilityMonitorProbeEvent extends IpConnectivityEvent
+    implements Parcelable {
+    public static final String TAG = "IpReachabilityMonitorProbeEvent";
+
+    private String mIfName;
+    private String mDestination;
+    private boolean mSuccess;
+
+    public IpReachabilityMonitorProbeEvent(String ifName, String destination, boolean success) {
+        mIfName = ifName;
+        mDestination = destination;
+        mSuccess = success;
+    }
+
+    public IpReachabilityMonitorProbeEvent(Parcel in) {
+        mIfName = in.readString();
+        mDestination = in.readString();
+        mSuccess = in.readByte() > 0 ? true : false;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mIfName);
+        out.writeString(mDestination);
+        out.writeByte((byte)(mSuccess ? 1 : 0));
+    }
+
+    public static final Parcelable.Creator<IpReachabilityMonitorProbeEvent> CREATOR
+        = new Parcelable.Creator<IpReachabilityMonitorProbeEvent>() {
+        public IpReachabilityMonitorProbeEvent createFromParcel(Parcel in) {
+            return new IpReachabilityMonitorProbeEvent(in);
+        }
+
+        public IpReachabilityMonitorProbeEvent[] newArray(int size) {
+            return new IpReachabilityMonitorProbeEvent[size];
+        }
+    };
+
+    public static void logEvent(String ifName, String destination, boolean success) {
+        IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_IPRM_PROBE_RESULT,
+                new IpReachabilityMonitorProbeEvent(ifName, destination, success));
+    }
+};
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 377ed88..86bd502 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -619,7 +619,9 @@
     public void setEnabled(boolean enabled) {
         try {
             mService.setEnabled(enabled);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -632,7 +634,7 @@
         try {
             return mService.getMessenger();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 }
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 6fdb0d0..4a06fb1 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -16,8 +16,11 @@
 
 package android.net.nsd;
 
+import android.annotation.NonNull;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.text.TextUtils;
+import android.util.Base64;
 import android.util.Log;
 import android.util.ArrayMap;
 
@@ -95,8 +98,99 @@
         mPort = p;
     }
 
+    /**
+     * Unpack txt information from a base-64 encoded byte array.
+     *
+     * @param rawRecords The raw base64 encoded records string read from netd.
+     *
+     * @hide
+     */
+    public void setTxtRecords(@NonNull String rawRecords) {
+        byte[] txtRecordsRawBytes = Base64.decode(rawRecords, Base64.DEFAULT);
+
+        // There can be multiple TXT records after each other. Each record has to following format:
+        //
+        // byte                  type                  required   meaning
+        // -------------------   -------------------   --------   ----------------------------------
+        // 0                     unsigned 8 bit        yes        size of record excluding this byte
+        // 1 - n                 ASCII but not '='     yes        key
+        // n + 1                 '='                   optional   separator of key and value
+        // n + 2 - record size   uninterpreted bytes   optional   value
+        //
+        // Example legal records:
+        // [11, 'm', 'y', 'k', 'e', 'y', '=', 0x0, 0x4, 0x65, 0x7, 0xff]
+        // [17, 'm', 'y', 'K', 'e', 'y', 'W', 'i', 't', 'h', 'N', 'o', 'V', 'a', 'l', 'u', 'e', '=']
+        // [12, 'm', 'y', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'K', 'e', 'y']
+        //
+        // Example corrupted records
+        // [3, =, 1, 2]    <- key is empty
+        // [3, 0, =, 2]    <- key contains non-ASCII character. We handle this by replacing the
+        //                    invalid characters instead of skipping the record.
+        // [30, 'a', =, 2] <- length exceeds total left over bytes in the TXT records array, we
+        //                    handle this by reducing the length of the record as needed.
+        int pos = 0;
+        while (pos < txtRecordsRawBytes.length) {
+            // recordLen is an unsigned 8 bit value
+            int recordLen = txtRecordsRawBytes[pos] & 0xff;
+            pos += 1;
+
+            try {
+                if (recordLen == 0) {
+                    throw new IllegalArgumentException("Zero sized txt record");
+                } else if (pos + recordLen > txtRecordsRawBytes.length) {
+                    Log.w(TAG, "Corrupt record length (pos = " + pos + "): " + recordLen);
+                    recordLen = txtRecordsRawBytes.length - pos;
+                }
+
+                // Decode key-value records
+                String key = null;
+                byte[] value = null;
+                int valueLen = 0;
+                for (int i = pos; i < pos + recordLen; i++) {
+                    if (key == null) {
+                        if (txtRecordsRawBytes[i] == '=') {
+                            key = new String(txtRecordsRawBytes, pos, i - pos,
+                                    StandardCharsets.US_ASCII);
+                        }
+                    } else {
+                        if (value == null) {
+                            value = new byte[recordLen - key.length() - 1];
+                        }
+                        value[valueLen] = txtRecordsRawBytes[i];
+                        valueLen++;
+                    }
+                }
+
+                // If '=' was not found we have a boolean record
+                if (key == null) {
+                    key = new String(txtRecordsRawBytes, pos, recordLen, StandardCharsets.US_ASCII);
+                }
+
+                if (TextUtils.isEmpty(key)) {
+                    // Empty keys are not allowed (RFC6763 6.4)
+                    throw new IllegalArgumentException("Invalid txt record (key is empty)");
+                }
+
+                if (getAttributes().containsKey(key)) {
+                    // When we have a duplicate record, the later ones are ignored (RFC6763 6.4)
+                    throw new IllegalArgumentException("Invalid txt record (duplicate key \"" + key + "\")");
+                }
+
+                setAttribute(key, value);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "While parsing txt records (pos = " + pos + "): " + e.getMessage());
+            }
+
+            pos += recordLen;
+        }
+    }
+
     /** @hide */
     public void setAttribute(String key, byte[] value) {
+        if (TextUtils.isEmpty(key)) {
+            throw new IllegalArgumentException("Key cannot be empty");
+        }
+
         // Key must be printable US-ASCII, excluding =.
         for (int i = 0; i < key.length(); ++i) {
             char character = key.charAt(i);
@@ -177,10 +271,10 @@
     }
 
     /** @hide */
-    public byte[] getTxtRecord() {
+    public @NonNull byte[] getTxtRecord() {
         int txtRecordSize = getTxtRecordSize();
         if (txtRecordSize == 0) {
-            return null;
+            return new byte[]{};
         }
 
         byte[] txtRecord = new byte[txtRecordSize];
diff --git a/core/java/android/os/BadParcelableException.java b/core/java/android/os/BadParcelableException.java
index a1c5bb2..7e0b1a5 100644
--- a/core/java/android/os/BadParcelableException.java
+++ b/core/java/android/os/BadParcelableException.java
@@ -15,11 +15,15 @@
  */
 
 package android.os;
+
 import android.util.AndroidRuntimeException;
 
 /**
- * The object you are calling has died, because its hosting process
- * no longer exists.
+ * Exception thrown when a {@link Parcelable} is malformed or otherwise invalid.
+ * <p>
+ * This is typically encountered when a custom {@link Parcelable} object is
+ * passed to another process that doesn't have the same {@link Parcelable} class
+ * in its {@link ClassLoader}.
  */
 public class BadParcelableException extends AndroidRuntimeException {
     public BadParcelableException(String msg) {
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index ee7bd9a..b6c919e 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -20,13 +20,16 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.MathUtils;
+import android.util.Slog;
 
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Set;
 
 /**
- * A mapping from String values to various types.
+ * A mapping from String keys to values of various types. In most cases, you
+ * should work directly with either the {@link Bundle} or
+ * {@link PersistableBundle} subclass.
  */
 public class BaseBundle {
     private static final String TAG = "Bundle";
@@ -35,6 +38,32 @@
     // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
     static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
 
+    /**
+     * Flag indicating that this Bundle is okay to "defuse." That is, it's okay
+     * for system processes to ignore any {@link BadParcelableException}
+     * encountered when unparceling it, leaving an empty bundle in its place.
+     * <p>
+     * This should <em>only</em> be set when the Bundle reaches its final
+     * destination, otherwise a system process may clobber contents that were
+     * destined for an app that could have unparceled them.
+     */
+    static final int FLAG_DEFUSABLE = 1 << 0;
+
+    private static volatile boolean sShouldDefuse = false;
+
+    /**
+     * Set global variable indicating that any Bundles parsed in this process
+     * should be "defused." That is, any {@link BadParcelableException}
+     * encountered will be suppressed and logged, leaving an empty Bundle
+     * instead of crashing.
+     *
+     * @hide
+     */
+    public static void setShouldDefuse(boolean shouldDefuse) {
+        sShouldDefuse = shouldDefuse;
+    }
+
+    /** {@hide} */
     static final Parcel EMPTY_PARCEL;
 
     static {
@@ -58,6 +87,9 @@
      */
     private ClassLoader mClassLoader;
 
+    /** {@hide} */
+    int mFlags;
+
     /**
      * Constructs a new, empty Bundle that uses a specific ClassLoader for
      * instantiating Parcelable and Serializable objects.
@@ -197,6 +229,11 @@
             return;
         }
 
+        if (sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
+            Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
+                    + "clobber all data inside!", new Throwable());
+        }
+
         if (mParcelledData == EMPTY_PARCEL) {
             if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
                     + ": empty");
@@ -221,9 +258,19 @@
             mMap.erase();
             mMap.ensureCapacity(N);
         }
-        mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
-        mParcelledData.recycle();
-        mParcelledData = null;
+        try {
+            mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
+        } catch (BadParcelableException e) {
+            if (sShouldDefuse) {
+                Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
+                mMap.erase();
+            } else {
+                throw e;
+            }
+        } finally {
+            mParcelledData.recycle();
+            mParcelledData = null;
+        }
         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
                 + " final map: " + mMap);
     }
@@ -235,6 +282,12 @@
         return mParcelledData != null;
     }
 
+    /** @hide */
+    ArrayMap<String, Object> getMap() {
+        unparcel();
+        return mMap;
+    }
+
     /**
      * Returns the number of mappings contained in this Bundle.
      *
@@ -1365,9 +1418,8 @@
             return;
         }
 
-        int magic = parcel.readInt();
+        final int magic = parcel.readInt();
         if (magic != BUNDLE_MAGIC) {
-            //noinspection ThrowableInstanceNeverThrown
             throw new IllegalStateException("Bad magic number for Bundle: 0x"
                     + Integer.toHexString(magic));
         }
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 56cb250..e40ebf7 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -221,7 +221,7 @@
         try {
             return mBatteryStats.isCharging();
         } catch (RemoteException e) {
-            return true;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -246,7 +246,7 @@
             else
                 ret = Long.MIN_VALUE;
         } catch (RemoteException e) {
-            ret = Long.MIN_VALUE;
+            throw e.rethrowFromSystemServer();
         }
 
         return ret;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a738b2e..c452837 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,8 @@
 import android.telephony.SignalStrength;
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
+import android.util.MutableBoolean;
+import android.util.Pair;
 import android.util.Printer;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -210,6 +212,7 @@
     private static final String WIFI_CONTROLLER_DATA = "wfcd";
     private static final String GLOBAL_BLUETOOTH_CONTROLLER_DATA = "gble";
     private static final String BLUETOOTH_CONTROLLER_DATA = "ble";
+    private static final String BLUETOOTH_MISC_DATA = "blem";
     private static final String MISC_DATA = "m";
     private static final String GLOBAL_NETWORK_DATA = "gn";
     private static final String GLOBAL_MODEM_CONTROLLER_DATA = "gmcd";
@@ -445,19 +448,41 @@
         public abstract Timer getForegroundActivityTimer();
         public abstract Timer getBluetoothScanTimer();
 
-        // Time this uid has any processes in the top state.
+        // Note: the following times are disjoint.  They can be added together to find the
+        // total time a uid has had any processes running at all.
+
+        /**
+         * Time this uid has any processes in the top state (or above such as persistent).
+         */
         public static final int PROCESS_STATE_TOP = 0;
-        // Time this uid has any process with a started out bound foreground service.
+        /**
+         * Time this uid has any process with a started out bound foreground service, but
+         * none in the "top" state.
+         */
         public static final int PROCESS_STATE_FOREGROUND_SERVICE = 1;
-        // Time this uid has any process that is top while the device is sleeping.
+        /**
+         * Time this uid has any process that is top while the device is sleeping, but none
+         * in the "foreground service" or better state.
+         */
         public static final int PROCESS_STATE_TOP_SLEEPING = 2;
-        // Time this uid has any process in an active foreground state.
+        /**
+         * Time this uid has any process in an active foreground state, but none in the
+         * "top sleeping" or better state.
+         */
         public static final int PROCESS_STATE_FOREGROUND = 3;
-        // Time this uid has any process in an active background state.
+        /**
+         * Time this uid has any process in an active background state, but none in the
+         * "foreground" or better state.
+         */
         public static final int PROCESS_STATE_BACKGROUND = 4;
-        // Time this uid has any processes running at all.
+        /**
+         * Time this uid has any processes that are sitting around cached, not in one of the
+         * other active states.
+         */
         public static final int PROCESS_STATE_CACHED = 5;
-        // Total number of process states we track.
+        /**
+         * Total number of process states we track.
+         */
         public static final int NUM_PROCESS_STATE = 6;
 
         static final String[] PROCESS_STATE_NAMES = {
@@ -465,6 +490,7 @@
         };
 
         public abstract long getProcessStateTime(int state, long elapsedRealtimeUs, int which);
+        public abstract Timer getProcessStateTimer(int state);
 
         public abstract Timer getVibratorOnTimer();
 
@@ -476,10 +502,10 @@
          * also be bumped.
          */
         static final String[] USER_ACTIVITY_TYPES = {
-            "other", "button", "touch"
+            "other", "button", "touch", "accessibility"
         };
         
-        public static final int NUM_USER_ACTIVITY_TYPES = 3;
+        public static final int NUM_USER_ACTIVITY_TYPES = 4;
 
         public abstract void noteUserActivityLocked(int type);
         public abstract boolean hasUserActivity();
@@ -623,7 +649,7 @@
             /**
              * The statistics associated with a particular service.
              */
-            public abstract class Serv {
+            public static abstract class Serv {
 
                 /**
                  * Returns the amount of time spent started.
@@ -1678,7 +1704,7 @@
     /**
      * Constant for device idle mode: active in full mode.
      */
-    public static final int DEVICE_IDLE_MODE_FULL = 2;
+    public static final int DEVICE_IDLE_MODE_DEEP = 2;
 
     /**
      * Returns the time in microseconds that device has been in idle mode while
@@ -2753,11 +2779,11 @@
         final long powerSaveModeEnabledTime = getPowerSaveModeEnabledTime(rawRealtime, which);
         final long deviceIdleModeLightTime = getDeviceIdleModeTime(DEVICE_IDLE_MODE_LIGHT,
                 rawRealtime, which);
-        final long deviceIdleModeFullTime = getDeviceIdleModeTime(DEVICE_IDLE_MODE_FULL,
+        final long deviceIdleModeFullTime = getDeviceIdleModeTime(DEVICE_IDLE_MODE_DEEP,
                 rawRealtime, which);
         final long deviceLightIdlingTime = getDeviceIdlingTime(DEVICE_IDLE_MODE_LIGHT,
                 rawRealtime, which);
-        final long deviceIdlingTime = getDeviceIdlingTime(DEVICE_IDLE_MODE_FULL,
+        final long deviceIdlingTime = getDeviceIdlingTime(DEVICE_IDLE_MODE_DEEP,
                 rawRealtime, which);
         final int connChanges = getNumConnectivityChange(which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
@@ -2843,14 +2869,14 @@
                 getMobileRadioActiveTime(rawRealtime, which) / 1000,
                 getMobileRadioActiveAdjustedTime(which) / 1000, interactiveTime / 1000,
                 powerSaveModeEnabledTime / 1000, connChanges, deviceIdleModeFullTime / 1000,
-                getDeviceIdleModeCount(DEVICE_IDLE_MODE_FULL, which), deviceIdlingTime / 1000,
-                getDeviceIdlingCount(DEVICE_IDLE_MODE_FULL, which),
+                getDeviceIdleModeCount(DEVICE_IDLE_MODE_DEEP, which), deviceIdlingTime / 1000,
+                getDeviceIdlingCount(DEVICE_IDLE_MODE_DEEP, which),
                 getMobileRadioActiveCount(which),
                 getMobileRadioActiveUnknownTime(which) / 1000, deviceIdleModeLightTime / 1000,
                 getDeviceIdleModeCount(DEVICE_IDLE_MODE_LIGHT, which), deviceLightIdlingTime / 1000,
                 getDeviceIdlingCount(DEVICE_IDLE_MODE_LIGHT, which),
                 getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_LIGHT),
-                getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_FULL));
+                getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_DEEP));
         
         // Dump screen brightness stats
         Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -3068,6 +3094,15 @@
             dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
                     u.getWifiControllerActivity(), which);
 
+            // Dump Bluetooth scan data, per UID.
+            final long bleScanTimeUs = u.getBluetoothScanTimer().getTotalTimeLocked(
+                    rawRealtime, which);
+            final int bleScanCount = u.getBluetoothScanTimer().getCountLocked(which);
+            if (bleScanTimeUs != 0 || bleScanCount != 0) {
+                dumpLine(pw, uid, category, BLUETOOTH_MISC_DATA,
+                        bleScanTimeUs / 1000, bleScanCount);
+            }
+
             dumpControllerActivityLine(pw, uid, category, BLUETOOTH_CONTROLLER_DATA,
                     u.getBluetoothControllerActivity(), which);
 
@@ -3329,11 +3364,11 @@
         final long powerSaveModeEnabledTime = getPowerSaveModeEnabledTime(rawRealtime, which);
         final long deviceIdleModeLightTime = getDeviceIdleModeTime(DEVICE_IDLE_MODE_LIGHT,
                 rawRealtime, which);
-        final long deviceIdleModeFullTime = getDeviceIdleModeTime(DEVICE_IDLE_MODE_FULL,
+        final long deviceIdleModeFullTime = getDeviceIdleModeTime(DEVICE_IDLE_MODE_DEEP,
                 rawRealtime, which);
         final long deviceLightIdlingTime = getDeviceIdlingTime(DEVICE_IDLE_MODE_LIGHT,
                 rawRealtime, which);
-        final long deviceIdlingTime = getDeviceIdlingTime(DEVICE_IDLE_MODE_FULL,
+        final long deviceIdlingTime = getDeviceIdlingTime(DEVICE_IDLE_MODE_DEEP,
                 rawRealtime, which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
@@ -3410,7 +3445,7 @@
                     formatTimeMs(sb, deviceIdlingTime / 1000);
                     sb.append("(");
                     sb.append(formatRatioLocked(deviceIdlingTime, whichBatteryRealtime));
-                    sb.append(") "); sb.append(getDeviceIdlingCount(DEVICE_IDLE_MODE_FULL, which));
+                    sb.append(") "); sb.append(getDeviceIdlingCount(DEVICE_IDLE_MODE_DEEP, which));
                     sb.append("x");
             pw.println(sb.toString());
         }
@@ -3422,10 +3457,10 @@
                     sb.append("(");
                     sb.append(formatRatioLocked(deviceIdleModeFullTime, whichBatteryRealtime));
                     sb.append(") ");
-                    sb.append(getDeviceIdleModeCount(DEVICE_IDLE_MODE_FULL, which));
+                    sb.append(getDeviceIdleModeCount(DEVICE_IDLE_MODE_DEEP, which));
                     sb.append("x");
                     sb.append(" -- longest ");
-                    formatTimeMs(sb, getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_FULL));
+                    formatTimeMs(sb, getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_DEEP));
             pw.println(sb.toString());
         }
         if (phoneOnTime != 0) {
@@ -5316,26 +5351,28 @@
         }
 
         if (apps != null) {
-            SparseArray<ArrayList<String>> uids = new SparseArray<ArrayList<String>>();
+            SparseArray<Pair<ArrayList<String>, MutableBoolean>> uids = new SparseArray<>();
             for (int i=0; i<apps.size(); i++) {
                 ApplicationInfo ai = apps.get(i);
-                ArrayList<String> pkgs = uids.get(ai.uid);
+                Pair<ArrayList<String>, MutableBoolean> pkgs = uids.get(
+                        UserHandle.getAppId(ai.uid));
                 if (pkgs == null) {
-                    pkgs = new ArrayList<String>();
-                    uids.put(ai.uid, pkgs);
+                    pkgs = new Pair<>(new ArrayList<String>(), new MutableBoolean(false));
+                    uids.put(UserHandle.getAppId(ai.uid), pkgs);
                 }
-                pkgs.add(ai.packageName);
+                pkgs.first.add(ai.packageName);
             }
             SparseArray<? extends Uid> uidStats = getUidStats();
             final int NU = uidStats.size();
             String[] lineArgs = new String[2];
             for (int i=0; i<NU; i++) {
-                int uid = uidStats.keyAt(i);
-                ArrayList<String> pkgs = uids.get(uid);
-                if (pkgs != null) {
-                    for (int j=0; j<pkgs.size(); j++) {
+                int uid = UserHandle.getAppId(uidStats.keyAt(i));
+                Pair<ArrayList<String>, MutableBoolean> pkgs = uids.get(uid);
+                if (pkgs != null && !pkgs.second.value) {
+                    pkgs.second.value = true;
+                    for (int j=0; j<pkgs.first.size(); j++) {
                         lineArgs[0] = Integer.toString(uid);
-                        lineArgs[1] = pkgs.get(j);
+                        lineArgs[1] = pkgs.first.get(j);
                         dumpLine(pw, 0 /* uid */, "i" /* category */, UID_DATA,
                                 (Object[])lineArgs);
                     }
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index d73deb6..ea8ba2f 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -70,6 +70,9 @@
     private static final boolean CHECK_PARCEL_SIZE = false;
     static final String TAG = "Binder";
 
+    /** @hide */
+    public static boolean LOG_RUNTIME_EXCEPTION = false; // DO NOT SUBMIT WITH TRUE
+
     /**
      * Control whether dump() calls are allowed.
      */
@@ -560,17 +563,16 @@
         // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
         try {
             res = onTransact(code, data, reply, flags);
-        } catch (RemoteException e) {
-            if ((flags & FLAG_ONEWAY) != 0) {
-                Log.w(TAG, "Binder call failed.", e);
-            } else {
-                reply.setDataPosition(0);
-                reply.writeException(e);
-            }
-            res = true;
-        } catch (RuntimeException e) {
-            if ((flags & FLAG_ONEWAY) != 0) {
+        } catch (RemoteException|RuntimeException e) {
+            if (LOG_RUNTIME_EXCEPTION) {
                 Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
+            }
+            if ((flags & FLAG_ONEWAY) != 0) {
+                if (e instanceof RemoteException) {
+                    Log.w(TAG, "Binder call failed.", e);
+                } else {
+                    Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
+                }
             } else {
                 reply.setDataPosition(0);
                 reply.writeException(e);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index de8b690..d0029e1 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -91,6 +91,12 @@
     /** The name of the hardware (from the kernel command line or /proc). */
     public static final String HARDWARE = getString("ro.hardware");
 
+    /**
+     * Whether this build was for an emulator device.
+     * @hide
+     */
+    public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
+
     /** A hardware serial number, if available.  Alphanumeric only, case-insensitive. */
     public static final String SERIAL = getString("ro.serialno");
 
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 74699fd..1128074 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -27,11 +27,17 @@
 import java.util.List;
 
 /**
- * A mapping from String values to various Parcelable types.
+ * A mapping from String keys to various {@link Parcelable} values.
  *
+ * @see PersistableBundle
  */
 public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
+    private static final int FLAG_HAS_FDS = 1 << 8;
+    private static final int FLAG_HAS_FDS_KNOWN = 1 << 9;
+    private static final int FLAG_ALLOW_FDS = 1 << 10;
+
     public static final Bundle EMPTY;
+
     static final Parcel EMPTY_PARCEL;
 
     static {
@@ -40,15 +46,12 @@
         EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL;
     }
 
-    private boolean mHasFds = false;
-    private boolean mFdsKnown = true;
-    private boolean mAllowFds = true;
-
     /**
      * Constructs a new, empty Bundle.
      */
     public Bundle() {
         super();
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
     }
 
     /**
@@ -59,16 +62,18 @@
      */
     Bundle(Parcel parcelledData) {
         super(parcelledData);
-
-        mHasFds = mParcelledData.hasFileDescriptors();
-        mFdsKnown = true;
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+        if (mParcelledData.hasFileDescriptors()) {
+            mFlags |= FLAG_HAS_FDS;
+        }
     }
 
     /* package */ Bundle(Parcel parcelledData, int length) {
         super(parcelledData, length);
-
-        mHasFds = mParcelledData.hasFileDescriptors();
-        mFdsKnown = true;
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+        if (mParcelledData.hasFileDescriptors()) {
+            mFlags |= FLAG_HAS_FDS;
+        }
     }
 
     /**
@@ -80,6 +85,7 @@
      */
     public Bundle(ClassLoader loader) {
         super(loader);
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
     }
 
     /**
@@ -90,6 +96,7 @@
      */
     public Bundle(int capacity) {
         super(capacity);
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
     }
 
     /**
@@ -100,9 +107,7 @@
      */
     public Bundle(Bundle b) {
         super(b);
-
-        mHasFds = b.mHasFds;
-        mFdsKnown = b.mFdsKnown;
+        mFlags = b.mFlags;
     }
 
     /**
@@ -113,6 +118,7 @@
      */
     public Bundle(PersistableBundle b) {
         super(b);
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
     }
 
     /**
@@ -145,14 +151,45 @@
         return super.getClassLoader();
     }
 
-    /** @hide */
+    /** {@hide} */
     public boolean setAllowFds(boolean allowFds) {
-        boolean orig = mAllowFds;
-        mAllowFds = allowFds;
+        final boolean orig = (mFlags & FLAG_ALLOW_FDS) != 0;
+        if (allowFds) {
+            mFlags |= FLAG_ALLOW_FDS;
+        } else {
+            mFlags &= ~FLAG_ALLOW_FDS;
+        }
         return orig;
     }
 
     /**
+     * Mark if this Bundle is okay to "defuse." That is, it's okay for system
+     * processes to ignore any {@link BadParcelableException} encountered when
+     * unparceling it, leaving an empty bundle in its place.
+     * <p>
+     * This should <em>only</em> be set when the Bundle reaches its final
+     * destination, otherwise a system process may clobber contents that were
+     * destined for an app that could have unparceled them.
+     *
+     * @hide
+     */
+    public void setDefusable(boolean defusable) {
+        if (defusable) {
+            mFlags |= FLAG_DEFUSABLE;
+        } else {
+            mFlags &= ~FLAG_DEFUSABLE;
+        }
+    }
+
+    /** {@hide} */
+    public static Bundle setDefusable(Bundle bundle, boolean defusable) {
+        if (bundle != null) {
+            bundle.setDefusable(defusable);
+        }
+        return bundle;
+    }
+
+    /**
      * Clones the current Bundle. The internal map is cloned, but the keys and
      * values to which it refers are copied by reference.
      */
@@ -167,9 +204,19 @@
     @Override
     public void clear() {
         super.clear();
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+    }
 
-        mHasFds = false;
-        mFdsKnown = true;
+    /**
+     * Removes any entry with the given key from the mapping of this Bundle.
+     *
+     * @param key a String key
+     */
+    public void remove(String key) {
+        super.remove(key);
+        if ((mFlags & FLAG_HAS_FDS) != 0) {
+            mFlags &= ~FLAG_HAS_FDS_KNOWN;
+        }
     }
 
     /**
@@ -182,16 +229,20 @@
         bundle.unparcel();
         mMap.putAll(bundle.mMap);
 
-        // fd state is now known if and only if both bundles already knew
-        mHasFds |= bundle.mHasFds;
-        mFdsKnown = mFdsKnown && bundle.mFdsKnown;
+        // FD state is now known if and only if both bundles already knew
+        if ((bundle.mFlags & FLAG_HAS_FDS) != 0) {
+            mFlags |= FLAG_HAS_FDS;
+        }
+        if ((bundle.mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
+            mFlags &= ~FLAG_HAS_FDS_KNOWN;
+        }
     }
 
     /**
      * Reports whether the bundle contains any parcelled file descriptors.
      */
     public boolean hasFileDescriptors() {
-        if (!mFdsKnown) {
+        if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
             boolean fdFound = false;    // keep going until we find one or run out of data
 
             if (mParcelledData != null) {
@@ -247,10 +298,14 @@
                 }
             }
 
-            mHasFds = fdFound;
-            mFdsKnown = true;
+            if (fdFound) {
+                mFlags |= FLAG_HAS_FDS;
+            } else {
+                mFlags &= ~FLAG_HAS_FDS;
+            }
+            mFlags |= FLAG_HAS_FDS_KNOWN;
         }
-        return mHasFds;
+        return (mFlags & FLAG_HAS_FDS) != 0;
     }
 
     /**
@@ -274,6 +329,8 @@
                 mMap.removeAt(i);
             }
         }
+        mFlags |= FLAG_HAS_FDS_KNOWN;
+        mFlags &= ~FLAG_HAS_FDS;
     }
 
     /**
@@ -346,7 +403,7 @@
     public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
         unparcel();
         mMap.put(key, value);
-        mFdsKnown = false;
+        mFlags &= ~FLAG_HAS_FDS_KNOWN;
     }
 
     /**
@@ -384,7 +441,7 @@
     public void putParcelableArray(@Nullable String key, @Nullable Parcelable[] value) {
         unparcel();
         mMap.put(key, value);
-        mFdsKnown = false;
+        mFlags &= ~FLAG_HAS_FDS_KNOWN;
     }
 
     /**
@@ -399,14 +456,14 @@
             @Nullable ArrayList<? extends Parcelable> value) {
         unparcel();
         mMap.put(key, value);
-        mFdsKnown = false;
+        mFlags &= ~FLAG_HAS_FDS_KNOWN;
     }
 
     /** {@hide} */
     public void putParcelableList(String key, List<? extends Parcelable> value) {
         unparcel();
         mMap.put(key, value);
-        mFdsKnown = false;
+        mFlags &= ~FLAG_HAS_FDS_KNOWN;
     }
 
     /**
@@ -421,7 +478,7 @@
             @Nullable SparseArray<? extends Parcelable> value) {
         unparcel();
         mMap.put(key, value);
-        mFdsKnown = false;
+        mFlags &= ~FLAG_HAS_FDS_KNOWN;
     }
 
     /**
@@ -1074,7 +1131,7 @@
      */
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
+        final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
         try {
             super.writeToParcelInner(parcel, flags);
         } finally {
@@ -1089,8 +1146,10 @@
      */
     public void readFromParcel(Parcel parcel) {
         super.readFromParcelInner(parcel);
-        mHasFds = mParcelledData.hasFileDescriptors();
-        mFdsKnown = true;
+        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+        if (mParcelledData.hasFileDescriptors()) {
+            mFlags |= FLAG_HAS_FDS;
+        }
     }
 
     @Override
@@ -1105,5 +1164,4 @@
         }
         return "Bundle[" + mMap.toString() + "]";
     }
-
 }
diff --git a/core/java/android/os/DeadSystemException.java b/core/java/android/os/DeadSystemException.java
new file mode 100644
index 0000000..8fb53e2
--- /dev/null
+++ b/core/java/android/os/DeadSystemException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+/**
+ * The core Android system has died and is going through a runtime restart. All
+ * running apps will be promptly killed.
+ */
+public class DeadSystemException extends DeadObjectException {
+    public DeadSystemException() {
+        super();
+    }
+}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index e58744b..55b107a 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -19,8 +19,11 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.TypedProperties;
 
+import android.app.AppGlobals;
+import android.content.Context;
 import android.util.Log;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -98,14 +101,8 @@
     /**
      * Default trace file path and file
      */
-    private static final String DEFAULT_TRACE_PATH_PREFIX =
-        Environment.getLegacyExternalStorageDirectory().getPath() + "/";
     private static final String DEFAULT_TRACE_BODY = "dmtrace";
     private static final String DEFAULT_TRACE_EXTENSION = ".trace";
-    private static final String DEFAULT_TRACE_FILE_PATH =
-        DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
-        + DEFAULT_TRACE_EXTENSION;
-
 
     /**
      * This class is used to retrieved various statistics about the memory mappings for this
@@ -936,109 +933,171 @@
     }
 
     /**
-     * Start method tracing with default log name and buffer size. See <a
-href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading these files. Call stopMethodTracing() to stop
-     * tracing.
+     * Start method tracing with default log name and buffer size.
+     * <p>
+     * By default, the trace file is called "dmtrace.trace" and it's placed
+     * under your package-specific directory on primary shared/external storage,
+     * as returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
+     * </p>
      */
     public static void startMethodTracing() {
-        VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0, false, 0);
+        VMDebug.startMethodTracing(fixTracePath(null), 0, 0, false, 0);
     }
 
     /**
-     * Start method tracing, specifying the trace log file name.  The trace
-     * file will be put under "/sdcard" unless an absolute path is given.
-     * See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading trace files.
-     *
-     * @param traceName Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     */
-    public static void startMethodTracing(String traceName) {
-        startMethodTracing(traceName, 0, 0);
-    }
-
-    /**
-     * Start method tracing, specifying the trace log file name and the
-     * buffer size. The trace files will be put under "/sdcard" unless an
-     * absolute path is given. See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading trace files.
-     * @param traceName    Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     *
-     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
-     */
-    public static void startMethodTracing(String traceName, int bufferSize) {
-        startMethodTracing(traceName, bufferSize, 0);
-    }
-
-    /**
-     * Start method tracing, specifying the trace log file name and the
-     * buffer size. The trace files will be put under "/sdcard" unless an
-     * absolute path is given. See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading trace files.
-     *
+     * Start method tracing, specifying the trace log file path.
      * <p>
-     * When method tracing is enabled, the VM will run more slowly than
-     * usual, so the timings from the trace files should only be considered
-     * in relative terms (e.g. was run #1 faster than run #2).  The times
-     * for native methods will not change, so don't try to use this to
-     * compare the performance of interpreted and native implementations of the
-     * same method.  As an alternative, consider using sampling-based method
-     * tracing via {@link #startMethodTracingSampling(String, int, int)} or
-     * "native" tracing in the emulator via {@link #startNativeTracing()}.
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
      * </p>
      *
-     * @param traceName    Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
-     * @param flags    Flags to control method tracing. The only one that is currently defined is {@link #TRACE_COUNT_ALLOCS}.
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
      */
-    public static void startMethodTracing(String traceName, int bufferSize,
-        int flags) {
-        VMDebug.startMethodTracing(fixTraceName(traceName), bufferSize, flags, false, 0);
+    public static void startMethodTracing(String tracePath) {
+        startMethodTracing(tracePath, 0, 0);
+    }
+
+    /**
+     * Start method tracing, specifying the trace log file name and the buffer
+     * size.
+     * <p>
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
+     * </p>
+     *
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
+     * @param bufferSize The maximum amount of trace data we gather. If not
+     *            given, it defaults to 8MB.
+     */
+    public static void startMethodTracing(String tracePath, int bufferSize) {
+        startMethodTracing(tracePath, bufferSize, 0);
+    }
+
+    /**
+     * Start method tracing, specifying the trace log file name, the buffer
+     * size, and flags.
+     * <p>
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
+     * </p>
+     *
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
+     * @param bufferSize The maximum amount of trace data we gather. If not
+     *            given, it defaults to 8MB.
+     * @param flags Flags to control method tracing. The only one that is
+     *            currently defined is {@link #TRACE_COUNT_ALLOCS}.
+     */
+    public static void startMethodTracing(String tracePath, int bufferSize, int flags) {
+        VMDebug.startMethodTracing(fixTracePath(tracePath), bufferSize, flags, false, 0);
     }
 
     /**
      * Start sampling-based method tracing, specifying the trace log file name,
-     * the buffer size, and the sampling interval. The trace files will be put
-     * under "/sdcard" unless an absolute path is given. See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a>
-     * for information about reading trace files.
+     * the buffer size, and the sampling interval.
+     * <p>
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
      *
-     * @param traceName    Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
-     * @param intervalUs    The amount of time between each sample in microseconds.
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
+     * @param bufferSize The maximum amount of trace data we gather. If not
+     *            given, it defaults to 8MB.
+     * @param intervalUs The amount of time between each sample in microseconds.
      */
-    public static void startMethodTracingSampling(String traceName,
-        int bufferSize, int intervalUs) {
-        VMDebug.startMethodTracing(fixTraceName(traceName), bufferSize, 0, true, intervalUs);
+    public static void startMethodTracingSampling(String tracePath, int bufferSize,
+            int intervalUs) {
+        VMDebug.startMethodTracing(fixTracePath(tracePath), bufferSize, 0, true, intervalUs);
     }
-
+    
     /**
      * Formats name of trace log file for method tracing.
      */
-    private static String fixTraceName(String traceName) {
-        if (traceName == null)
-            traceName = DEFAULT_TRACE_FILE_PATH;
-        if (traceName.charAt(0) != '/')
-            traceName = DEFAULT_TRACE_PATH_PREFIX + traceName;
-        if (!traceName.endsWith(DEFAULT_TRACE_EXTENSION))
-            traceName = traceName + DEFAULT_TRACE_EXTENSION;
+    private static String fixTracePath(String tracePath) {
+        if (tracePath == null || tracePath.charAt(0) != '/') {
+            final Context context = AppGlobals.getInitialApplication();
+            final File dir;
+            if (context != null) {
+                dir = context.getExternalFilesDir(null);
+            } else {
+                dir = Environment.getExternalStorageDirectory();
+            }
 
-        return traceName;
+            if (tracePath == null) {
+                tracePath = new File(dir, DEFAULT_TRACE_BODY).getAbsolutePath();
+            } else {
+                tracePath = new File(dir, tracePath).getAbsolutePath();
+            }
+        }
+        if (!tracePath.endsWith(DEFAULT_TRACE_EXTENSION)) {
+            tracePath += DEFAULT_TRACE_EXTENSION;
+        }
+        return tracePath;
     }
 
     /**
@@ -2158,6 +2217,14 @@
     public static native void dumpNativeBacktraceToFile(int pid, String file);
 
     /**
+     * Get description of unreachable native memory.
+     * @param limit the number of leaks to provide info on, 0 to only get a summary.
+     * @param contents true to include a hex dump of the contents of unreachable memory.
+     * @return the String containing a description of unreachable memory.
+     * @hide */
+    public static native String getUnreachableMemory(int limit, boolean contents);
+
+    /**
      * Return a String describing the calling method and location at a particular stack depth.
      * @param callStack the Thread stack
      * @param depth the depth of stack to return information for.
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 2b14468..cb85eef 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -16,6 +16,9 @@
 
 package android.os;
 
+import android.content.Context;
+import android.util.Log;
+
 import com.android.internal.os.IDropBoxManagerService;
 
 import java.io.ByteArrayInputStream;
@@ -40,6 +43,8 @@
  */
 public class DropBoxManager {
     private static final String TAG = "DropBoxManager";
+
+    private final Context mContext;
     private final IDropBoxManagerService mService;
 
     /** Flag value: Entry's content was deleted to save space. */
@@ -249,14 +254,20 @@
     }
 
     /** {@hide} */
-    public DropBoxManager(IDropBoxManagerService service) { mService = service; }
+    public DropBoxManager(Context context, IDropBoxManagerService service) {
+        mContext = context;
+        mService = service;
+    }
 
     /**
      * Create a dummy instance for testing.  All methods will fail unless
      * overridden with an appropriate mock implementation.  To obtain a
      * functional instance, use {@link android.content.Context#getSystemService}.
      */
-    protected DropBoxManager() { mService = null; }
+    protected DropBoxManager() {
+        mContext = null;
+        mService = null;
+    }
 
     /**
      * Stores human-readable text.  The data may be discarded eventually (or even
@@ -267,7 +278,16 @@
      * @param data value to store
      */
     public void addText(String tag, String data) {
-        try { mService.add(new Entry(tag, 0, data)); } catch (RemoteException e) {}
+        try {
+            mService.add(new Entry(tag, 0, data));
+        } catch (RemoteException e) {
+            if (e instanceof TransactionTooLargeException
+                    && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+                Log.e(TAG, "App sent too much data, so it was ignored", e);
+                return;
+            }
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -279,7 +299,16 @@
      */
     public void addData(String tag, byte[] data, int flags) {
         if (data == null) throw new NullPointerException("data == null");
-        try { mService.add(new Entry(tag, 0, data, flags)); } catch (RemoteException e) {}
+        try {
+            mService.add(new Entry(tag, 0, data, flags));
+        } catch (RemoteException e) {
+            if (e instanceof TransactionTooLargeException
+                    && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+                Log.e(TAG, "App sent too much data, so it was ignored", e);
+                return;
+            }
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -297,7 +326,7 @@
         try {
             mService.add(entry);
         } catch (RemoteException e) {
-            // ignore
+            throw e.rethrowFromSystemServer();
         } finally {
             entry.close();
         }
@@ -312,7 +341,11 @@
      * @return whether events with that tag would be accepted
      */
     public boolean isTagEnabled(String tag) {
-        try { return mService.isTagEnabled(tag); } catch (RemoteException e) { return false; }
+        try {
+            return mService.isTagEnabled(tag);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -325,7 +358,11 @@
      * @return the next entry, or null if there are no more entries
      */
     public Entry getNextEntry(String tag, long msec) {
-        try { return mService.getNextEntry(tag, msec); } catch (RemoteException e) { return null; }
+        try {
+            return mService.getNextEntry(tag, msec);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     // TODO: It may be useful to have some sort of notification mechanism
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 1085b1e..f6e8940 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -34,6 +34,7 @@
     private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
     private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
     private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
+    private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
     private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
     private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
     private static final String ENV_OEM_ROOT = "OEM_ROOT";
@@ -54,6 +55,7 @@
 
     private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
     private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
+    private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
     private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
     private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
     private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
@@ -229,6 +231,11 @@
     }
 
     /** {@hide} */
+    public static File getExpandDirectory() {
+        return DIR_ANDROID_EXPAND;
+    }
+
+    /** {@hide} */
     public static File getDataSystemDirectory() {
         return new File(getDataDirectory(), "system");
     }
@@ -258,6 +265,20 @@
         return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
     }
 
+    private static File getDataProfilesDeDirectory(int userId) {
+        return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
+    }
+
+    /** {@hide} */
+    public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
+        return buildPath(getDataProfilesDeDirectory(userId), packageName);
+    }
+
+    /** {@hide} */
+    public static File getDataProfilesDeForeignDexDirectory(int userId) {
+        return buildPath(getDataProfilesDeDirectory(userId), "foreign-dex");
+    }
+
     /** {@hide} */
     public static File getDataAppDirectory(String volumeUuid) {
         return new File(getDataDirectory(volumeUuid), "app");
@@ -493,7 +514,7 @@
      * </ul>
      * @hide
      */
-    private static final String[] STANDARD_DIRECTORIES = {
+    public static final String[] STANDARD_DIRECTORIES = {
             DIRECTORY_MUSIC,
             DIRECTORY_PODCASTS,
             DIRECTORY_RINGTONES,
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1b79497..dd73e53 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -605,6 +605,30 @@
      */
     public static File buildUniqueFile(File parent, String mimeType, String displayName)
             throws FileNotFoundException {
+        final String[] parts = splitFileName(mimeType, displayName);
+        final String name = parts[0];
+        final String ext = parts[1];
+        File file = buildFile(parent, name, ext);
+
+        // If conflicting file, try adding counter suffix
+        int n = 0;
+        while (file.exists()) {
+            if (n++ >= 32) {
+                throw new FileNotFoundException("Failed to create unique file");
+            }
+            file = buildFile(parent, name + " (" + n + ")", ext);
+        }
+
+        return file;
+    }
+
+    /**
+     * Splits file name into base name and extension.
+     * If the display name doesn't have an extension that matches the requested MIME type, the
+     * extension is regarded as a part of filename and default extension for that MIME type is
+     * appended.
+     */
+    public static String[] splitFileName(String mimeType, String displayName) {
         String name;
         String ext;
 
@@ -642,18 +666,11 @@
             }
         }
 
-        File file = buildFile(parent, name, ext);
-
-        // If conflicting file, try adding counter suffix
-        int n = 0;
-        while (file.exists()) {
-            if (n++ >= 32) {
-                throw new FileNotFoundException("Failed to create unique file");
-            }
-            file = buildFile(parent, name + " (" + n + ")", ext);
+        if (ext == null) {
+            ext = "";
         }
 
-        return file;
+        return new String[] { name, ext };
     }
 
     private static File buildFile(File parent, String name, String ext) {
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index c72a6481..9d362d6 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -33,13 +33,27 @@
 
     private final IHardwarePropertiesManager mService;
 
+    /**
+     * @hide
+     */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
-        DEVICE_TEMPERATURE_CPU, DEVICE_TEMPERATURE_GPU, DEVICE_TEMPERATURE_BATTERY
+        DEVICE_TEMPERATURE_CPU, DEVICE_TEMPERATURE_GPU, DEVICE_TEMPERATURE_BATTERY,
+                DEVICE_TEMPERATURE_SKIN
     })
     public @interface DeviceTemperatureType {}
 
     /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN,
+                TEMPERATURE_THROTTLING_BELOW_VR_MIN
+    })
+    public @interface TemperatureSource {}
+
+    /**
      * Device temperature types. These must match the values in
      * frameworks/native/include/hardwareproperties/HardwarePropertiesManager.h
      */
@@ -52,6 +66,27 @@
     /** Temperature of battery in Celsius. */
     public static final int DEVICE_TEMPERATURE_BATTERY = 2;
 
+    /** Temperature of device skin in Celsius. */
+    public static final int DEVICE_TEMPERATURE_SKIN = 3;
+
+    /** Get current temperature. */
+    public static final int TEMPERATURE_CURRENT = 0;
+
+    /** Get throttling temperature threshold. */
+    public static final int TEMPERATURE_THROTTLING = 1;
+
+    /** Get shutdown temperature threshold. */
+    public static final int TEMPERATURE_SHUTDOWN = 2;
+
+    /**
+     * Get throttling temperature threshold above which minimum clockrates for VR mode will not be
+     * met.
+     */
+    public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3;
+
+    /** Undefined temperature constant. */
+    public static final float UNDEFINED_TEMPERATURE = -Float.MAX_VALUE;
+
     /** Calling app context. */
     private final Context mContext;
 
@@ -65,43 +100,61 @@
      * Return an array of device temperatures in Celsius.
      *
      * @param type type of requested device temperature, one of {@link #DEVICE_TEMPERATURE_CPU},
-     * {@link #DEVICE_TEMPERATURE_GPU} or {@link #DEVICE_TEMPERATURE_BATTERY}.
-     * @return an array of requested float device temperatures.
+     * {@link #DEVICE_TEMPERATURE_GPU}, {@link #DEVICE_TEMPERATURE_BATTERY} or {@link
+     * #DEVICE_TEMPERATURE_SKIN}.
+     * @param source source of requested device temperature, one of {@link #TEMPERATURE_CURRENT},
+     * {@link #TEMPERATURE_THROTTLING}, {@link #TEMPERATURE_THROTTLING_BELOW_VR_MIN} or
+     * {@link #TEMPERATURE_SHUTDOWN}.
+     * @return an array of requested float device temperatures. Temperature equals to
+     *         {@link #UNDEFINED_TEMPERATURE} if undefined.
      *         Empty if platform doesn't provide the queried temperature.
      *
-     * @throws IllegalArgumentException if an incorrect temperature type is queried.
-     * @throws SecurityException if a non profile or device owner tries to call this method.
+     * @throws SecurityException if something other than the profile or device owner, or the
+     *        current VR service tries to retrieve information provided by this service.
     */
-    public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type) {
+    public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type,
+            @TemperatureSource int source) {
         switch (type) {
-        case DEVICE_TEMPERATURE_CPU:
-        case DEVICE_TEMPERATURE_GPU:
-        case DEVICE_TEMPERATURE_BATTERY:
-            try {
-                return mService.getDeviceTemperatures(mContext.getOpPackageName(), type);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Could not get device temperatures", e);
+            case DEVICE_TEMPERATURE_CPU:
+            case DEVICE_TEMPERATURE_GPU:
+            case DEVICE_TEMPERATURE_BATTERY:
+            case DEVICE_TEMPERATURE_SKIN:
+                switch (source) {
+                    case TEMPERATURE_CURRENT:
+                    case TEMPERATURE_THROTTLING:
+                    case TEMPERATURE_SHUTDOWN:
+                    case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
+                        try {
+                            return mService.getDeviceTemperatures(mContext.getOpPackageName(), type,
+                                    source);
+                        } catch (RemoteException e) {
+                            throw e.rethrowFromSystemServer();
+                        }
+                    default:
+                        Log.w(TAG, "Unknown device temperature source.");
+                        return new float[0];
+                }
+            default:
+                Log.w(TAG, "Unknown device temperature type.");
                 return new float[0];
-            }
-        default:
-            throw new IllegalArgumentException();
         }
     }
 
     /**
      * Return an array of CPU usage info for each core.
      *
-     * @return an array of {@link android.os.CpuUsageInfo} for each core.
+     * @return an array of {@link android.os.CpuUsageInfo} for each core. Return {@code null} for
+     *         each unplugged core.
      *         Empty if CPU usage is not supported on this system.
      *
-     * @throws SecurityException if a non profile or device owner tries to call this method.
+     * @throws SecurityException if something other than the profile or device owner, or the
+     *        current VR service tries to retrieve information provided by this service.
      */
     public @NonNull CpuUsageInfo[] getCpuUsages() {
         try {
             return mService.getCpuUsages(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.w(TAG, "Could not get CPU usages", e);
-            return new CpuUsageInfo[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -111,14 +164,14 @@
      * @return an array of float fan speeds in RPM. Empty if there are no fans or fan speed is not
      * supported on this system.
      *
-     * @throws SecurityException if a non profile or device owner tries to call this method.
+     * @throws SecurityException if something other than the profile or device owner, or the
+     *        current VR service tries to retrieve information provided by this service.
      */
     public @NonNull float[] getFanSpeeds() {
         try {
             return mService.getFanSpeeds(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.w(TAG, "Could not get fan speeds", e);
-            return new float[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 }
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index 838279b..082194b 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -25,10 +25,12 @@
     void removePowerSaveWhitelistApp(String name);
     String[] getSystemPowerWhitelistExceptIdle();
     String[] getSystemPowerWhitelist();
+    String[] getUserPowerWhitelist();
     String[] getFullPowerWhitelistExceptIdle();
     String[] getFullPowerWhitelist();
     int[] getAppIdWhitelistExceptIdle();
     int[] getAppIdWhitelist();
+    int[] getAppIdUserWhitelist();
     int[] getAppIdTempWhitelist();
     boolean isPowerSaveWhitelistExceptIdleApp(String name);
     boolean isPowerSaveWhitelistApp(String name);
diff --git a/core/java/android/os/IHardwarePropertiesManager.aidl b/core/java/android/os/IHardwarePropertiesManager.aidl
index bcf0dc8..1c86bd0 100644
--- a/core/java/android/os/IHardwarePropertiesManager.aidl
+++ b/core/java/android/os/IHardwarePropertiesManager.aidl
@@ -22,7 +22,7 @@
 /** @hide */
 
 interface IHardwarePropertiesManager {
-    float[] getDeviceTemperatures(String callingPackage, int type);
+    float[] getDeviceTemperatures(String callingPackage, int type, int source);
     CpuUsageInfo[] getCpuUsages(String callingPackage);
     float[] getFanSpeeds(String callingPackage);
 }
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index cd84c8f..68b0a9f 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -97,12 +97,6 @@
     void setInterfaceIpv6NdOffload(String iface, boolean enable);
 
     /**
-     * Retrieves the network routes currently configured on the specified
-     * interface
-     */
-    RouteInfo[] getRoutes(String iface);
-
-    /**
      * Add the specified route to the interface.
      */
     void addRoute(int netId, in RouteInfo route);
@@ -299,7 +293,9 @@
     /**
      * Control network activity of a UID over interfaces with a quota limit.
      */
-    void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
+    void setUidMeteredNetworkBlacklist(int uid, boolean enable);
+    void setUidMeteredNetworkWhitelist(int uid, boolean enable);
+    boolean setDataSaverModeEnabled(boolean enable);
 
     void setUidCleartextNetworkPolicy(int uid, int policy);
 
@@ -332,11 +328,6 @@
      */
     void setDnsServersForNetwork(int netId, in String[] servers, String domains);
 
-    /**
-     * Flush the DNS cache associated with the specified network.
-     */
-    void flushNetworkDnsCache(int netId);
-
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index dd10df3..1d464c0 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -50,6 +50,7 @@
     boolean isLightDeviceIdleMode();
 
     void reboot(boolean confirm, String reason, boolean wait);
+    void rebootSafeMode(boolean confirm, boolean wait);
     void shutdown(boolean confirm, String reason, boolean wait);
     void crash(String message);
 
diff --git a/core/java/android/os/IProgressListener.aidl b/core/java/android/os/IProgressListener.aidl
new file mode 100644
index 0000000..ad58a7c
--- /dev/null
+++ b/core/java/android/os/IProgressListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.os.Bundle;
+
+/** @hide */
+oneway interface IProgressListener {
+    void onStarted(int id, in Bundle extras);
+    void onProgress(int id, int progress, in Bundle extras);
+    void onFinished(int id, in Bundle extras);
+}
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
new file mode 100644
index 0000000..12830a4
--- /dev/null
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -0,0 +1,28 @@
+/* //device/java/android/android/os/IRecoverySystem.aidl
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR 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.os.IRecoverySystemProgressListener;
+
+/** @hide */
+
+interface IRecoverySystem {
+    boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
+    boolean setupBcb(in String command);
+    boolean clearBcb();
+}
diff --git a/core/java/android/os/IRecoverySystemProgressListener.aidl b/core/java/android/os/IRecoverySystemProgressListener.aidl
new file mode 100644
index 0000000..d6f712e
--- /dev/null
+++ b/core/java/android/os/IRecoverySystemProgressListener.aidl
@@ -0,0 +1,24 @@
+/* //device/java/android/android/os/IRecoverySystemProgressListener.aidl
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+/** @hide */
+
+oneway interface IRecoverySystemProgressListener {
+    void onProgress(int progress);
+}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index bc2566b..c38bf3c 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -76,4 +76,5 @@
     PersistableBundle getSeedAccountOptions();
     void clearSeedAccountData();
     boolean someUserHasSeedAccount(in String accountName, in String accountType);
+    boolean isManagedProfile(int userId);
 }
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index ea180b2..b947c97 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -18,20 +18,21 @@
 
 import android.annotation.Nullable;
 import android.util.ArrayMap;
+
 import com.android.internal.util.XmlUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
 
 /**
- * A mapping from String values to various types that can be saved to persistent and later
- * restored.
+ * A mapping from String keys to values of various types. The set of types
+ * supported by this class is purposefully restricted to simple objects that can
+ * safely be persisted to and restored from disk.
  *
+ * @see Bundle
  */
 public final class PersistableBundle extends BaseBundle implements Cloneable, Parcelable,
         XmlUtils.WriteMapCallback {
@@ -60,6 +61,7 @@
      */
     public PersistableBundle() {
         super();
+        mFlags = FLAG_DEFUSABLE;
     }
 
     /**
@@ -70,6 +72,7 @@
      */
     public PersistableBundle(int capacity) {
         super(capacity);
+        mFlags = FLAG_DEFUSABLE;
     }
 
     /**
@@ -80,6 +83,21 @@
      */
     public PersistableBundle(PersistableBundle b) {
         super(b);
+        mFlags = b.mFlags;
+    }
+
+
+    /**
+     * Constructs a PersistableBundle from a Bundle.
+     *
+     * @param b a Bundle to be copied.
+     *
+     * @throws IllegalArgumentException if any element of {@code b} cannot be persisted.
+     *
+     * @hide
+     */
+    public PersistableBundle(Bundle b) {
+        this(b.getMap());
     }
 
     /**
@@ -90,6 +108,7 @@
      */
     private PersistableBundle(ArrayMap<String, Object> map) {
         super();
+        mFlags = FLAG_DEFUSABLE;
 
         // First stuff everything in.
         putAll(map);
@@ -101,6 +120,8 @@
             if (value instanceof ArrayMap) {
                 // Fix up any Maps by replacing them with PersistableBundles.
                 mMap.setValueAt(i, new PersistableBundle((ArrayMap<String, Object>) value));
+            } else if (value instanceof Bundle) {
+                mMap.setValueAt(i, new PersistableBundle(((Bundle) value)));
             } else if (!isValidType(value)) {
                 throw new IllegalArgumentException("Bad value in PersistableBundle key="
                         + mMap.keyAt(i) + " value=" + value);
@@ -110,6 +131,7 @@
 
     /* package */ PersistableBundle(Parcel parcelledData, int length) {
         super(parcelledData, length);
+        mFlags = FLAG_DEFUSABLE;
     }
 
     /**
@@ -265,5 +287,4 @@
         }
         return "PersistableBundle[" + mMap.toString() + "]";
     }
-
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 314b7d5..92edc62 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -221,7 +221,7 @@
     /**
      * Wake lock level: Enables Sustained Performance Mode.
      * <p>
-     * This is used by Gaming and VR applications to ensure the device provides
+     * This is used by Gaming and VR applications to ensure the device
      * will provide consistent performance over a large amount of time.
      * </p>
      */
@@ -316,6 +316,13 @@
     public static final int USER_ACTIVITY_EVENT_TOUCH = 2;
 
     /**
+     * User activity event type: Accessibility taking action on behalf of user.
+     * @hide
+     */
+    @SystemApi
+    public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3;
+
+    /**
      * User activity flag: If already dimmed, extend the dim timeout
      * but do not brighten.  This flag is useful for keeping the screen on
      * a little longer without causing a visible change such as when
@@ -385,9 +392,9 @@
     public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
 
     /**
-     * The value to pass as the 'reason' argument to reboot() to
-     * reboot into recovery mode (for applying system updates, doing
-     * factory resets, etc.).
+     * The value to pass as the 'reason' argument to reboot() to reboot into
+     * recovery mode for tasks other than applying system updates, such as
+     * doing factory resets.
      * <p>
      * Requires the {@link android.Manifest.permission#RECOVERY}
      * permission (in addition to
@@ -398,6 +405,18 @@
     public static final String REBOOT_RECOVERY = "recovery";
 
     /**
+     * The value to pass as the 'reason' argument to reboot() to reboot into
+     * recovery mode for applying system updates.
+     * <p>
+     * Requires the {@link android.Manifest.permission#RECOVERY}
+     * permission (in addition to
+     * {@link android.Manifest.permission#REBOOT}).
+     * </p>
+     * @hide
+     */
+    public static final String REBOOT_RECOVERY_UPDATE = "recovery-update";
+
+    /**
      * The value to pass as the 'reason' argument to reboot() when device owner requests a reboot on
      * the device.
      * @hide
@@ -405,6 +424,12 @@
     public static final String REBOOT_REQUESTED_BY_DEVICE_OWNER = "deviceowner";
 
     /**
+     * The 'reason' value used when rebooting in safe mode
+     * @hide
+     */
+    public static final String REBOOT_SAFE_MODE = "safemode";
+
+    /**
      * The value to pass as the 'reason' argument to android_reboot().
      * @hide
      */
@@ -606,6 +631,7 @@
         try {
             mService.userActivity(when, event, flags);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -657,6 +683,7 @@
         try {
             mService.goToSleep(time, reason, flags);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -683,6 +710,7 @@
         try {
             mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -693,6 +721,7 @@
         try {
             mService.wakeUp(time, reason, mContext.getOpPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -721,6 +750,7 @@
         try {
             mService.nap(time);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -743,6 +773,7 @@
         try {
             mService.boostScreenBrightness(time);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -758,7 +789,7 @@
         try {
             return mService.isScreenBrightnessBoosted();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -776,6 +807,7 @@
         try {
             mService.setTemporaryScreenBrightnessSettingOverride(brightness);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -789,7 +821,7 @@
         try {
             return mService.isWakeLockLevelSupported(level);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -853,7 +885,7 @@
         try {
             return mService.isInteractive();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -870,6 +902,22 @@
         try {
             mService.reboot(false, reason, true);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Reboot the device. Will not return if the reboot is successful.
+     * <p>
+     * Requires the {@link android.Manifest.permission#REBOOT} permission.
+     * </p>
+     * @hide
+     */
+    public void rebootSafeMode() {
+        try {
+            mService.rebootSafeMode(false, true);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -885,7 +933,7 @@
         try {
             return mService.isPowerSaveMode();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -902,7 +950,7 @@
         try {
             return mService.setPowerSaveMode(mode);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -922,7 +970,7 @@
         try {
             return mService.isDeviceIdleMode();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -942,7 +990,7 @@
         try {
             return mService.isLightDeviceIdleMode();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -961,7 +1009,7 @@
         try {
             return mIDeviceIdleController.isPowerSaveWhitelistApp(packageName);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -978,10 +1026,21 @@
         try {
             mService.shutdown(confirm, reason, wait);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
+     * Returns True if the device supports Sustained Performance Mode.
+     * Applications Should check if the device supports this mode, before
+     * using {@link #SUSTAINED_PERFORMANCE_WAKE_LOCK}.
+     */
+    public boolean isSustainedPerformanceModeSupported() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_sustainedPerformanceModeSupported);
+    }
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
      * This broadcast is only sent to registered receivers.
      */
@@ -1104,6 +1163,7 @@
                     try {
                         mService.releaseWakeLock(mToken, 0);
                     } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -1172,6 +1232,7 @@
                     mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
                             mHistoryTag);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
                 mHeld = true;
             }
@@ -1210,6 +1271,7 @@
                         try {
                             mService.releaseWakeLock(mToken, flags);
                         } catch (RemoteException e) {
+                            throw e.rethrowFromSystemServer();
                         }
                         mHeld = false;
                     }
@@ -1266,6 +1328,7 @@
                     try {
                         mService.updateWakeLockWorkSource(mToken, mWorkSource, mHistoryTag);
                     } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9984755..4506f51 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -383,6 +383,9 @@
     public static final int SIGNAL_KILL = 9;
     public static final int SIGNAL_USR1 = 10;
 
+    private static long sStartElapsedRealtime;
+    private static long sStartUptimeMillis;
+
     /**
      * State for communicating with the zygote process.
      *
@@ -772,6 +775,26 @@
     public static final native long getElapsedCpuTime();
 
     /**
+     * Return the {@link SystemClock#elapsedRealtime()} at which this process was started.
+     */
+    public static final long getStartElapsedRealtime() {
+        return sStartElapsedRealtime;
+    }
+
+    /**
+     * Return the {@link SystemClock#uptimeMillis()} at which this process was started.
+     */
+    public static final long getStartUptimeMillis() {
+        return sStartUptimeMillis;
+    }
+
+    /** @hide */
+    public static final void setStartTimes(long elapsedRealtime, long uptimeMillis) {
+        sStartElapsedRealtime = elapsedRealtime;
+        sStartUptimeMillis = uptimeMillis;
+    }
+
+    /**
      * Returns true if the current process is a 64-bit runtime.
      */
     public static final boolean is64Bit() {
@@ -975,6 +998,31 @@
             throws IllegalArgumentException, SecurityException;
 
     /**
+     * On some devices, the foreground process may have one or more CPU
+     * cores exclusively reserved for it. This method can be used to
+     * retrieve which cores that are (if any), so the calling process
+     * can then use sched_setaffinity() to lock a thread to these cores.
+     * Note that the calling process must currently be running in the
+     * foreground for this method to return any cores.
+     *
+     * The CPU core(s) exclusively reserved for the foreground process will
+     * stay reserved for as long as the process stays in the foreground.
+     *
+     * As soon as a process leaves the foreground, those CPU cores will
+     * no longer be reserved for it, and will most likely be reserved for
+     * the new foreground process. It's not necessary to change the affinity
+     * of your process when it leaves the foreground (if you had previously
+     * set it to use a reserved core); the OS will automatically take care
+     * of resetting the affinity at that point.
+     *
+     * @return an array of integers, indicating the CPU cores exclusively
+     * reserved for this process. The array will have length zero if no
+     * CPU cores are exclusively reserved for this process at this point
+     * in time.
+     */
+    public static final native int[] getExclusiveCores();
+
+    /**
      * Set the priority of the calling thread, based on Linux priorities.  See
      * {@link #setThreadPriority(int, int)} for more information.
      * 
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 154c9bb..b25b33d 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.SystemApi;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -66,15 +67,34 @@
     private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
 
     /** Used to communicate with recovery.  See bootable/recovery/recovery.cpp. */
-    private static File RECOVERY_DIR = new File("/cache/recovery");
-    private static File BLOCK_MAP_FILE = new File(RECOVERY_DIR, "block.map");
-    private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
-    private static File UNCRYPT_FILE = new File(RECOVERY_DIR, "uncrypt_file");
-    private static File LOG_FILE = new File(RECOVERY_DIR, "log");
-    private static String LAST_PREFIX = "last_";
+    private static final File RECOVERY_DIR = new File("/cache/recovery");
+    private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
+    private static final String LAST_PREFIX = "last_";
+
+    /**
+     * The recovery image uses this file to identify the location (i.e. blocks)
+     * of an OTA package on the /data partition. The block map file is
+     * generated by uncrypt.
+     *
+     * @hide
+     */
+    public static final File BLOCK_MAP_FILE = new File(RECOVERY_DIR, "block.map");
+
+    /**
+     * UNCRYPT_PACKAGE_FILE stores the filename to be uncrypt'd, which will be
+     * read by uncrypt.
+     *
+     * @hide
+     */
+    public static final File UNCRYPT_PACKAGE_FILE = new File(RECOVERY_DIR, "uncrypt_file");
 
     // Length limits for reading files.
-    private static int LOG_FILE_MAX_LENGTH = 64 * 1024;
+    private static final int LOG_FILE_MAX_LENGTH = 64 * 1024;
+
+    // Prevent concurrent execution of requests.
+    private static final Object sRequestLock = new Object();
+
+    private final IRecoverySystem mService;
 
     /**
      * Interface definition for a callback to be invoked regularly as
@@ -287,6 +307,89 @@
     }
 
     /**
+     * Process a given package with uncrypt. No-op if the package is not on the
+     * /data partition.
+     *
+     * @param Context      the Context to use
+     * @param packageFile  the package to be processed
+     * @param listener     an object to receive periodic progress updates as
+     *                     processing proceeds.  May be null.
+     * @param handler      the Handler upon which the callbacks will be
+     *                     executed.
+     *
+     * @throws IOException if there were any errors processing the package file.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static void processPackage(Context context,
+                                      File packageFile,
+                                      final ProgressListener listener,
+                                      final Handler handler)
+            throws IOException {
+        String filename = packageFile.getCanonicalPath();
+        if (!filename.startsWith("/data/")) {
+            return;
+        }
+
+        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+        IRecoverySystemProgressListener progressListener = null;
+        if (listener != null) {
+            final Handler progressHandler;
+            if (handler != null) {
+                progressHandler = handler;
+            } else {
+                progressHandler = new Handler(context.getMainLooper());
+            }
+            progressListener = new IRecoverySystemProgressListener.Stub() {
+                int lastProgress = 0;
+                long lastPublishTime = System.currentTimeMillis();
+
+                @Override
+                public void onProgress(final int progress) {
+                    final long now = System.currentTimeMillis();
+                    progressHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (progress > lastProgress &&
+                                    now - lastPublishTime > PUBLISH_PROGRESS_INTERVAL_MS) {
+                                lastProgress = progress;
+                                lastPublishTime = now;
+                                listener.onProgress(progress);
+                            }
+                        }
+                    });
+                }
+            };
+        }
+
+        if (!rs.uncrypt(filename, progressListener)) {
+            throw new IOException("process package failed");
+        }
+    }
+
+    /**
+     * Process a given package with uncrypt. No-op if the package is not on the
+     * /data partition.
+     *
+     * @param Context      the Context to use
+     * @param packageFile  the package to be processed
+     * @param listener     an object to receive periodic progress updates as
+     *                     processing proceeds.  May be null.
+     *
+     * @throws IOException if there were any errors processing the package file.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static void processPackage(Context context,
+                                      File packageFile,
+                                      final ProgressListener listener)
+            throws IOException {
+        processPackage(context, packageFile, listener, null);
+    }
+
+    /**
      * Reboots the device in order to install the given update
      * package.
      * Requires the {@link android.Manifest.permission#REBOOT} permission.
@@ -301,30 +404,137 @@
      * fails, or if the reboot itself fails.
      */
     public static void installPackage(Context context, File packageFile)
-        throws IOException {
+            throws IOException {
+        installPackage(context, packageFile, false);
+    }
+
+    /**
+     * If the package hasn't been processed (i.e. uncrypt'd), set up
+     * UNCRYPT_PACKAGE_FILE and delete BLOCK_MAP_FILE to trigger uncrypt during the
+     * reboot.
+     *
+     * @param context      the Context to use
+     * @param packageFile  the update package to install.  Must be on a
+     * partition mountable by recovery.
+     * @param processed    if the package has been processed (uncrypt'd).
+     *
+     * @throws IOException if writing the recovery command file fails, or if
+     * the reboot itself fails.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static void installPackage(Context context, File packageFile, boolean processed)
+            throws IOException {
+        synchronized (sRequestLock) {
+            LOG_FILE.delete();
+            // Must delete the file in case it was created by system server.
+            UNCRYPT_PACKAGE_FILE.delete();
+
+            String filename = packageFile.getCanonicalPath();
+            Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+
+            // If the package is on the /data partition, the package needs to
+            // be processed (i.e. uncrypt'd). The caller specifies if that has
+            // been done in 'processed' parameter.
+            if (filename.startsWith("/data/")) {
+                if (processed) {
+                    if (!BLOCK_MAP_FILE.exists()) {
+                        Log.e(TAG, "Package claimed to have been processed but failed to find "
+                                + "the block map file.");
+                        throw new IOException("Failed to find block map file");
+                    }
+                } else {
+                    FileWriter uncryptFile = new FileWriter(UNCRYPT_PACKAGE_FILE);
+                    try {
+                        uncryptFile.write(filename + "\n");
+                    } finally {
+                        uncryptFile.close();
+                    }
+                    // UNCRYPT_PACKAGE_FILE needs to be readable and writable
+                    // by system server.
+                    if (!UNCRYPT_PACKAGE_FILE.setReadable(true, false)
+                            || !UNCRYPT_PACKAGE_FILE.setWritable(true, false)) {
+                        Log.e(TAG, "Error setting permission for " + UNCRYPT_PACKAGE_FILE);
+                    }
+
+                    BLOCK_MAP_FILE.delete();
+                }
+
+                // If the package is on the /data partition, use the block map
+                // file as the package name instead.
+                filename = "@/cache/recovery/block.map";
+            }
+
+            final String filenameArg = "--update_package=" + filename + "\n";
+            final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+            final String command = filenameArg + localeArg;
+
+            RecoverySystem rs = (RecoverySystem) context.getSystemService(
+                    Context.RECOVERY_SERVICE);
+            if (!rs.setupBcb(command)) {
+                throw new IOException("Setup BCB failed");
+            }
+
+            // Having set up the BCB (bootloader control block), go ahead and reboot
+            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+            pm.reboot(PowerManager.REBOOT_RECOVERY_UPDATE);
+
+            throw new IOException("Reboot failed (no permissions?)");
+        }
+    }
+
+    /**
+     * Schedule to install the given package on next boot. The caller needs to
+     * ensure that the package must have been processed (uncrypt'd) if needed.
+     * It sets up the command in BCB (bootloader control block), which will
+     * be read by the bootloader and the recovery image.
+     *
+     * @param Context      the Context to use.
+     * @param packageFile  the package to be installed.
+     *
+     * @throws IOException if there were any errors setting up the BCB.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static void scheduleUpdateOnBoot(Context context, File packageFile)
+            throws IOException {
         String filename = packageFile.getCanonicalPath();
 
-        FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE);
-        try {
-            uncryptFile.write(filename + "\n");
-        } finally {
-            uncryptFile.close();
-        }
-        // UNCRYPT_FILE needs to be readable by system server on bootup.
-        if (!UNCRYPT_FILE.setReadable(true, false)) {
-            Log.e(TAG, "Error setting readable for " + UNCRYPT_FILE.getCanonicalPath());
-        }
-        Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
-
-        // If the package is on the /data partition, write the block map file
-        // into COMMAND_FILE instead.
+        // If the package is on the /data partition, use the block map file as
+        // the package name instead.
         if (filename.startsWith("/data/")) {
             filename = "@/cache/recovery/block.map";
         }
 
-        final String filenameArg = "--update_package=" + filename;
-        final String localeArg = "--locale=" + Locale.getDefault().toString();
-        bootCommand(context, filenameArg, localeArg);
+        final String filenameArg = "--update_package=" + filename + "\n";
+        final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+        final String command = filenameArg + localeArg;
+
+        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+        if (!rs.setupBcb(command)) {
+            throw new IOException("schedule update on boot failed");
+        }
+    }
+
+    /**
+     * Cancel any scheduled update by clearing up the BCB (bootloader control
+     * block).
+     *
+     * @param Context      the Context to use.
+     *
+     * @throws IOException if there were any errors clearing up the BCB.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static void cancelScheduledUpdate(Context context)
+            throws IOException {
+        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+        if (!rs.clearBcb()) {
+            throw new IOException("cancel scheduled update failed");
+        }
     }
 
     /**
@@ -434,27 +644,28 @@
      * @throws IOException if something goes wrong.
      */
     private static void bootCommand(Context context, String... args) throws IOException {
-        RECOVERY_DIR.mkdirs();  // In case we need it
-        COMMAND_FILE.delete();  // In case it's not writable
-        LOG_FILE.delete();
+        synchronized (sRequestLock) {
+            LOG_FILE.delete();
 
-        FileWriter command = new FileWriter(COMMAND_FILE);
-        try {
+            StringBuilder command = new StringBuilder();
             for (String arg : args) {
                 if (!TextUtils.isEmpty(arg)) {
-                    command.write(arg);
-                    command.write("\n");
+                    command.append(arg);
+                    command.append("\n");
                 }
             }
-        } finally {
-            command.close();
+
+            // Write the command into BCB (bootloader control block).
+            RecoverySystem rs = (RecoverySystem) context.getSystemService(
+                    Context.RECOVERY_SERVICE);
+            rs.setupBcb(command.toString());
+
+            // Having set up the BCB, go ahead and reboot.
+            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+            pm.reboot(PowerManager.REBOOT_RECOVERY);
+
+            throw new IOException("Reboot failed (no permissions?)");
         }
-
-        // Having written the command file, go ahead and reboot
-        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        pm.reboot(PowerManager.REBOOT_RECOVERY);
-
-        throw new IOException("Reboot failed (no permissions?)");
     }
 
     /**
@@ -476,10 +687,10 @@
 
         // Only remove the OTA package if it's partially processed (uncrypt'd).
         boolean reservePackage = BLOCK_MAP_FILE.exists();
-        if (!reservePackage && UNCRYPT_FILE.exists()) {
+        if (!reservePackage && UNCRYPT_PACKAGE_FILE.exists()) {
             String filename = null;
             try {
-                filename = FileUtils.readTextFile(UNCRYPT_FILE, 0, null);
+                filename = FileUtils.readTextFile(UNCRYPT_PACKAGE_FILE, 0, null);
             } catch (IOException e) {
                 Log.e(TAG, "Error reading uncrypt file", e);
             }
@@ -487,7 +698,7 @@
             // Remove the OTA package on /data that has been (possibly
             // partially) processed. (Bug: 24973532)
             if (filename != null && filename.startsWith("/data")) {
-                if (UNCRYPT_FILE.delete()) {
+                if (UNCRYPT_PACKAGE_FILE.delete()) {
                     Log.i(TAG, "Deleted: " + filename);
                 } else {
                     Log.e(TAG, "Can't delete: " + filename);
@@ -499,13 +710,13 @@
         // the block map file (BLOCK_MAP_FILE) for a package. BLOCK_MAP_FILE
         // will be created at the end of a successful uncrypt. If seeing this
         // file, we keep the block map file and the file that contains the
-        // package name (UNCRYPT_FILE). This is to reduce the work for GmsCore
-        // to avoid re-downloading everything again.
+        // package name (UNCRYPT_PACKAGE_FILE). This is to reduce the work for
+        // GmsCore to avoid re-downloading everything again.
         String[] names = RECOVERY_DIR.list();
         for (int i = 0; names != null && i < names.length; i++) {
             if (names[i].startsWith(LAST_PREFIX)) continue;
             if (reservePackage && names[i].equals(BLOCK_MAP_FILE.getName())) continue;
-            if (reservePackage && names[i].equals(UNCRYPT_FILE.getName())) continue;
+            if (reservePackage && names[i].equals(UNCRYPT_PACKAGE_FILE.getName())) continue;
 
             recursiveDelete(new File(RECOVERY_DIR, names[i]));
         }
@@ -533,6 +744,39 @@
     }
 
     /**
+     * Talks to RecoverySystemService via Binder to trigger uncrypt.
+     */
+    private boolean uncrypt(String packageFile, IRecoverySystemProgressListener listener) {
+        try {
+            return mService.uncrypt(packageFile, listener);
+        } catch (RemoteException unused) {
+        }
+        return false;
+    }
+
+    /**
+     * Talks to RecoverySystemService via Binder to set up the BCB.
+     */
+    private boolean setupBcb(String command) {
+        try {
+            return mService.setupBcb(command);
+        } catch (RemoteException unused) {
+        }
+        return false;
+    }
+
+    /**
+     * Talks to RecoverySystemService via Binder to clear up the BCB.
+     */
+    private boolean clearBcb() {
+        try {
+            return mService.clearBcb();
+        } catch (RemoteException unused) {
+        }
+        return false;
+    }
+
+    /**
      * Internally, recovery treats each line of the command file as a separate
      * argv, so we only need to protect against newlines and nulls.
      */
@@ -546,5 +790,14 @@
     /**
      * @removed Was previously made visible by accident.
      */
-    public RecoverySystem() { }
+    public RecoverySystem() {
+        mService = null;
+    }
+
+    /**
+     * @hide
+     */
+    public RecoverySystem(IRecoverySystem service) {
+        mService = service;
+    }
 }
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
index 98d7523..6d25fc1 100644
--- a/core/java/android/os/RemoteException.java
+++ b/core/java/android/os/RemoteException.java
@@ -15,6 +15,7 @@
  */
 
 package android.os;
+
 import android.util.AndroidException;
 
 /**
@@ -33,4 +34,25 @@
     public RuntimeException rethrowAsRuntimeException() {
         throw new RuntimeException(this);
     }
+
+    /**
+     * Rethrow this exception when we know it came from the system server. This
+     * gives us an opportunity to throw a nice clean
+     * {@link DeadSystemException} signal to avoid spamming logs with
+     * misleading stack traces.
+     * <p>
+     * Apps making calls into the system server may end up persisting internal
+     * state or making security decisions based on the perceived success or
+     * failure of a call, or any default values returned. For this reason, we
+     * want to strongly throw when there was trouble with the transaction.
+     *
+     * @hide
+     */
+    public RuntimeException rethrowFromSystemServer() {
+        if (this instanceof DeadObjectException) {
+            throw new RuntimeException(new DeadSystemException());
+        } else {
+            throw new RuntimeException(this);
+        }
+    }
 }
diff --git a/core/java/android/os/ServiceSpecificException.java b/core/java/android/os/ServiceSpecificException.java
index 20f237a5..04fca19 100644
--- a/core/java/android/os/ServiceSpecificException.java
+++ b/core/java/android/os/ServiceSpecificException.java
@@ -20,20 +20,23 @@
  *
  * <p>This exception includes an error code specific to the throwing
  * service.  This is mostly used by system services to indicate
- * domain specific error conditions.
+ * domain specific error conditions.</p>
+ *
+ * <p>Since these exceptions are designed to be passed through Binder
+ * interfaces, and to be generated by native-code Binder services,
+ * they do not support exception chaining.</p>
  *
  * @hide
  */
 public class ServiceSpecificException extends RuntimeException {
     public final int errorCode;
 
-    ServiceSpecificException(int errorCode, String message) {
+    public ServiceSpecificException(int errorCode, String message) {
         super(message);
         this.errorCode = errorCode;
     }
 
-    ServiceSpecificException(int errorCode) {
+    public ServiceSpecificException(int errorCode) {
         this.errorCode = errorCode;
     }
 }
-
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 91d88da..e4a76db 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1517,7 +1517,11 @@
                         violationMaskSubset,
                         info);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+                    if (e instanceof DeadObjectException) {
+                        // System process is dead; ignore
+                    } else {
+                        Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+                    }
                 } finally {
                     // Restore the policy.
                     setThreadPolicyMask(savedPolicyMask);
@@ -1569,7 +1573,11 @@
                             info);
                     }
                 } catch (RemoteException e) {
-                    Log.e(TAG, "RemoteException handling StrictMode violation", e);
+                    if (e instanceof DeadObjectException) {
+                        // System process is dead; ignore
+                    } else {
+                        Log.e(TAG, "RemoteException handling StrictMode violation", e);
+                    }
                 }
                 int outstanding = sDropboxCallsInFlight.decrementAndGet();
                 if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding);
@@ -1897,7 +1905,11 @@
                     violationMaskSubset,
                     info);
             } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+                if (e instanceof DeadObjectException) {
+                    // System process is dead; ignore
+                } else {
+                    Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+                }
             } finally {
                 // Restore the policy.
                 setThreadPolicyMask(savedPolicyMask);
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 80e6146..bf03cce 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -87,7 +87,7 @@
     }
 
     @SystemApi
-    public boolean bind(final UpdateEngineCallback callback, final Handler handler) throws RemoteException {
+    public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
         IUpdateEngineCallback updateEngineCallback = new IUpdateEngineCallback.Stub() {
             @Override
             public void onStatusUpdate(final int status, final float percent) {
@@ -118,31 +118,60 @@
             }
         };
 
-        return mUpdateEngine.bind(updateEngineCallback);
+        try {
+            return mUpdateEngine.bind(updateEngineCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @SystemApi
-    public boolean bind(final UpdateEngineCallback callback) throws RemoteException {
+    public boolean bind(final UpdateEngineCallback callback) {
         return bind(callback, null);
     }
 
     @SystemApi
-    public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) throws RemoteException {
-        mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
+    public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
+        try {
+            mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @SystemApi
-    public void cancel() throws RemoteException {
-        mUpdateEngine.cancel();
+    public void cancel() {
+        try {
+            mUpdateEngine.cancel();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @SystemApi
-    public void suspend() throws RemoteException {
-        mUpdateEngine.suspend();
+    public void suspend() {
+        try {
+            mUpdateEngine.suspend();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @SystemApi
-    public void resume() throws RemoteException {
-        mUpdateEngine.resume();
+    public void resume() {
+        try {
+            mUpdateEngine.resume();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @SystemApi
+    public void resetStatus() {
+        try {
+            mUpdateEngine.resetStatus();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 69d564f..707d5f5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.os;
 
 import android.Manifest;
@@ -36,7 +37,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
-import android.util.Log;
+import android.telephony.TelephonyManager;
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.R;
@@ -379,8 +380,7 @@
      * Specifies that the user is not allowed to make outgoing
      * phone calls. Emergency calls are still permitted.
      * The default value is <code>false</code>.
-     * <p>This restriction has no effect on managed profiles since call intents are normally
-     * forwarded to the primary user.
+     * <p>This restriction has no effect on managed profiles.
      *
      * <p>Key for user restrictions.
      * <p>Type: Boolean
@@ -682,6 +682,22 @@
     }
 
     /**
+     * Returns whether switching users is currently allowed.
+     * <p>For instance switching users is not allowed if the current user is in a phone call,
+     * or system user hasn't been unlocked yet
+     * @hide
+     */
+    public boolean canSwitchUsers() {
+        boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
+        boolean isSystemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
+        boolean inCall = TelephonyManager.getDefault().getCallState()
+                != TelephonyManager.CALL_STATE_IDLE;
+        return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall;
+    }
+
+    /**
      * Returns the user handle for the user that this process is running under.
      *
      * @return the user handle of this process.
@@ -701,8 +717,7 @@
         try {
             return mService.getUserInfo(getUserHandle()).name;
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user name", re);
-            return "";
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -772,8 +787,7 @@
         try {
             return mService.isRestricted();
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not check if user is limited ", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -785,8 +799,7 @@
         try {
             return mService.canHaveRestrictedProfile(userId);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not check if user can have restricted profile", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -809,8 +822,28 @@
      */
     @SystemApi
     public boolean isManagedProfile() {
-        UserInfo user = getUserInfo(UserHandle.myUserId());
-        return user != null ? user.isManagedProfile() : false;
+        try {
+            return mService.isManagedProfile(UserHandle.myUserId());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Checks if the specified user is a managed profile.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission, otherwise the caller
+     * must be in the same profile group of specified user.
+     *
+     * @return whether the specified user is a managed profile.
+     * @hide
+     */
+    @SystemApi
+    public boolean isManagedProfile(@UserIdInt int userId) {
+        try {
+            return mService.isManagedProfile(userId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -848,8 +881,8 @@
     public boolean isUserRunning(int userId) {
         try {
             return ActivityManagerNative.getDefault().isUserRunning(userId, 0);
-        } catch (RemoteException e) {
-            return false;
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -865,86 +898,77 @@
             // TODO: reconcile stopped vs stopping?
             return ActivityManagerNative.getDefault().isUserRunning(
                     user.getIdentifier(), ActivityManager.FLAG_OR_STOPPED);
-        } catch (RemoteException e) {
-            return false;
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * Return whether the calling user is running in a "locked" state. A user is
-     * unlocked only after they've entered their credentials (such as a lock
-     * pattern or PIN), and credential-encrypted private app data storage is
-     * available.
-     */
+    /** @removed */
     @Deprecated
     public boolean isUserRunningAndLocked() {
         return isUserRunningAndLocked(Process.myUserHandle());
     }
 
-    /**
-     * Return whether the given user is running in a "locked" state. A user
-     * is unlocked only after they've entered their credentials (such as a lock
-     * pattern or PIN), and credential-encrypted private app data storage is
-     * available.
-     *
-     * @param user to retrieve the unlocked state for.
-     */
+    /** @removed */
     @Deprecated
     public boolean isUserRunningAndLocked(UserHandle user) {
         try {
             return ActivityManagerNative.getDefault().isUserRunning(
                     user.getIdentifier(), ActivityManager.FLAG_AND_LOCKED);
-        } catch (RemoteException e) {
-            return false;
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * Return whether the calling user is running in an "unlocked" state. A user
-     * is unlocked only after they've entered their credentials (such as a lock
-     * pattern or PIN), and credential-encrypted private app data storage is
-     * available.
-     */
+    /** @removed */
     @Deprecated
     public boolean isUserRunningAndUnlocked() {
         return isUserRunningAndUnlocked(Process.myUserHandle());
     }
 
-    /**
-     * Return whether the given user is running in an "unlocked" state. A user
-     * is unlocked only after they've entered their credentials (such as a lock
-     * pattern or PIN), and credential-encrypted private app data storage is
-     * available.
-     *
-     * @param user to retrieve the unlocked state for.
-     */
+    /** @removed */
     @Deprecated
     public boolean isUserRunningAndUnlocked(UserHandle user) {
         try {
             return ActivityManagerNative.getDefault().isUserRunning(
                     user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
-        } catch (RemoteException e) {
-            return false;
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Return whether the calling user is running in an "unlocked" state. A user
-     * is unlocked only after they've entered their credentials (such as a lock
-     * pattern or PIN), and credential-encrypted private app data storage is
-     * available.
+     * Return whether the calling user is running in an "unlocked" state.
+     * <p>
+     * On devices with direct boot, a user is unlocked only after they've
+     * entered their credentials (such as a lock pattern or PIN). On devices
+     * without direct boot, a user is unlocked as soon as it starts.
+     * <p>
+     * When a user is locked, only device-protected data storage is available.
+     * When a user is unlocked, both device-protected and credential-protected
+     * private app data storage is available.
+     *
+     * @see Intent#ACTION_USER_UNLOCKED
+     * @see Context#createDeviceProtectedStorageContext()
      */
     public boolean isUserUnlocked() {
         return isUserUnlocked(Process.myUserHandle());
     }
 
     /**
-     * Return whether the given user is running in an "unlocked" state. A user
-     * is unlocked only after they've entered their credentials (such as a lock
-     * pattern or PIN), and credential-encrypted private app data storage is
-     * available.
+     * Return whether the given user is running in an "unlocked" state.
+     * <p>
+     * On devices with direct boot, a user is unlocked only after they've
+     * entered their credentials (such as a lock pattern or PIN). On devices
+     * without direct boot, a user is unlocked as soon as it starts.
+     * <p>
+     * When a user is locked, only device-protected data storage is available.
+     * When a user is unlocked, both device-protected and credential-protected
+     * private app data storage is available.
      *
      * @param user to retrieve the unlocked state for.
+     * @see Intent#ACTION_USER_UNLOCKED
+     * @see Context#createDeviceProtectedStorageContext()
      */
     public boolean isUserUnlocked(UserHandle user) {
         return isUserUnlocked(user.getIdentifier());
@@ -969,8 +993,7 @@
         try {
             return mService.getUserInfo(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user info", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -991,8 +1014,7 @@
         try {
             return mService.getUserRestrictions(userHandle.getIdentifier());
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user restrictions", re);
-            return Bundle.EMPTY;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1008,9 +1030,7 @@
         try {
             return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier());
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get base user restrictions for user " +
-                    userHandle.getIdentifier(), re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1066,7 +1086,7 @@
         try {
             mService.setUserRestriction(key, value, userHandle.getIdentifier());
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set user restriction", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1093,8 +1113,7 @@
             return mService.hasUserRestriction(restrictionKey,
                     userHandle.getIdentifier());
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not check user restrictions", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1148,7 +1167,7 @@
                 mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not create a user", re);
+            throw re.rethrowFromSystemServer();
         }
         return user;
     }
@@ -1168,7 +1187,7 @@
                         Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not create a user", re);
+            throw re.rethrowFromSystemServer();
         }
         return guest;
     }
@@ -1189,8 +1208,7 @@
         try {
             return mService.createProfileForUser(name, flags, userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not create a user", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1212,10 +1230,9 @@
                         UserHandle.of(user.id));
             }
             return user;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Could not create a restricted profile", e);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -1283,8 +1300,7 @@
         try {
             return mService.getSeedAccountName();
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get the seed account name", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1298,8 +1314,7 @@
         try {
             return mService.getSeedAccountType();
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get the seed account type", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1315,8 +1330,7 @@
         try {
             return mService.getSeedAccountOptions();
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get the seed account options", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1337,7 +1351,7 @@
             mService.setSeedAccountData(userId, accountName, accountType, accountOptions,
                     /* persist= */ true);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set the seed account data", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1350,7 +1364,7 @@
         try {
             mService.clearSeedAccountData();
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not clear the seed account data", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1365,15 +1379,18 @@
         try {
             return mService.markGuestForDeletion(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not mark guest for deletion", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
      * 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.
+     *
+     * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * <p>Note that the default is true, it's only that managed profiles might not be enabled.
+     * Also ephemeral users can be disabled to indicate that their removal is in progress and they
+     * shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled.
      *
      * @param userHandle the id of the profile to enable
      * @hide
@@ -1381,8 +1398,8 @@
     public void setUserEnabled(@UserIdInt int userHandle) {
         try {
             mService.setUserEnabled(userHandle);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Could not enable the profile", e);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1404,8 +1421,7 @@
         try {
             return mService.getUsers(false);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user list", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1427,8 +1443,7 @@
             }
             return result;
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get users list", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1444,8 +1459,7 @@
         try {
             return mService.getUserAccount(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user account", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1461,7 +1475,7 @@
         try {
             mService.setUserAccount(userHandle, accountName);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set user account", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1476,8 +1490,7 @@
         try {
             return mService.getPrimaryUser();
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get Primary user", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1514,8 +1527,7 @@
         try {
             return mService.canAddMoreManagedProfiles(userId, allowedToRemoveOne);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not check if we can add more managed profiles", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1534,8 +1546,7 @@
         try {
             return mService.getProfiles(userHandle, false /* enabledOnly */);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user list", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1550,8 +1561,7 @@
         try {
             return mService.isSameProfileGroup(userId, otherUserId);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user list", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1569,8 +1579,7 @@
         try {
             return mService.getProfiles(userHandle, true /* enabledOnly */);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user list", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1586,8 +1595,7 @@
         try {
             users = mService.getProfiles(UserHandle.myUserId(), true /* enabledOnly */);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user list", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
         for (UserInfo info : users) {
             UserHandle userHandle = new UserHandle(info.id);
@@ -1607,8 +1615,7 @@
         try {
             return mService.getCredentialOwnerProfile(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get credential owner", re);
-            return -1;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1622,8 +1629,7 @@
         try {
             return mService.getProfileParent(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get profile parent", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1637,8 +1643,8 @@
     public void setQuietModeEnabled(@UserIdInt int userHandle, boolean enableQuietMode) {
         try {
             mService.setQuietModeEnabled(userHandle, enableQuietMode);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Could not change the profile's quiet mode", e);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1651,10 +1657,9 @@
     public boolean isQuietModeEnabled(UserHandle userHandle) {
         try {
             return mService.isQuietModeEnabled(userHandle.getIdentifier());
-        } catch (RemoteException e) {
-            Log.w(TAG, "Could not query the profile's quiet mode", e);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -1665,7 +1670,7 @@
      * android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}.
      * <p>
      * If the original drawable is a BitmapDrawable and the backing bitmap is
-     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
      * is performed in place and the original drawable is returned.
      * </p>
      *
@@ -1688,17 +1693,17 @@
      * badge to be used.
      * <p>
      * If the original drawable is a BitmapDrawable and the backing bitmap is
-     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
      * is performed in place and the original drawable is returned.
      * </p>
      *
      * @param badgedDrawable The drawable to badge.
      * @param user The target user.
      * @param badgeLocation Where in the bounds of the badged drawable to place
-     *         the badge. If not provided, the badge is applied on top of the entire
+     *         the badge. If it's {@code null}, the badge is applied on top of the entire
      *         drawable being badged.
      * @param badgeDensity The optional desired density for the badge as per
-     *         {@link android.util.DisplayMetrics#densityDpi}. If not provided,
+     *         {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
      *         the density of the display is used.
      * @return A drawable that combines the original drawable and a badge as
      *         determined by the system.
@@ -1739,8 +1744,7 @@
         try {
             return mService.getUsers(excludeDying);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user list", re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1754,8 +1758,7 @@
         try {
             return mService.removeUser(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not remove user ", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1771,7 +1774,7 @@
         try {
             mService.setUserName(userHandle, name);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set the user name ", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1785,7 +1788,7 @@
         try {
             mService.setUserIcon(userHandle, icon);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set the user icon ", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1810,7 +1813,7 @@
                 }
             }
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get the user icon ", re);
+            throw re.rethrowFromSystemServer();
         }
         return null;
     }
@@ -1866,9 +1869,8 @@
         try {
             return mService.getUserSerialNumber(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get serial number for user " + userHandle);
+            throw re.rethrowFromSystemServer();
         }
-        return -1;
     }
 
     /**
@@ -1884,9 +1886,8 @@
         try {
             return mService.getUserHandle(userSerialNumber);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get userHandle for user " + userSerialNumber);
+            throw re.rethrowFromSystemServer();
         }
-        return -1;
     }
 
     /**
@@ -1912,9 +1913,8 @@
         try {
             return mService.getApplicationRestrictions(packageName);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get application restrictions for package " + packageName);
+            throw re.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -1924,9 +1924,8 @@
         try {
             return mService.getApplicationRestrictionsForUser(packageName, user.getIdentifier());
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get application restrictions for user " + user.getIdentifier());
+            throw re.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -1937,7 +1936,7 @@
         try {
             mService.setApplicationRestrictions(packageName, restrictions, user.getIdentifier());
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier());
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1961,7 +1960,7 @@
         try {
             mService.setDefaultGuestRestrictions(restrictions);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set guest restrictions");
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -1973,9 +1972,8 @@
         try {
             return mService.getDefaultGuestRestrictions();
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set guest restrictions");
+            throw re.rethrowFromSystemServer();
         }
-        return new Bundle();
     }
 
     /**
@@ -1988,8 +1986,7 @@
         try {
             return mService.getUserCreationTime(userHandle.getIdentifier());
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not get user creation time", re);
-            return 0;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -2005,8 +2002,7 @@
         try {
             return mService.someUserHasSeedAccount(accountName, accountType);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not check seed accounts", re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 }
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index d2ece8b..f399719 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -109,6 +109,17 @@
     public abstract void removeAllUsers();
 
     /**
+     * Called by the activity manager when the ephemeral user goes to background and its removal
+     * starts as a result.
+     *
+     * <p>It marks the ephemeral user as disabled in order to prevent it from being re-entered
+     * before its removal finishes.
+     *
+     * @param userId the ID of the ephemeral user.
+     */
+    public abstract void onEphemeralUserStop(int userId);
+
+    /**
      * Same as UserManager.createUser(), but bypasses the check for DISALLOW_ADD_USER.
      *
      * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
diff --git a/core/java/android/os/health/HealthKeys.java b/core/java/android/os/health/HealthKeys.java
new file mode 100644
index 0000000..842def3
--- /dev/null
+++ b/core/java/android/os/health/HealthKeys.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+/**
+ * Constants and stuff for the android.os.health package.
+ *
+ * @hide
+ */
+public class HealthKeys {
+
+    /**
+     * No valid key will ever be 0.
+     */
+    public static final int UNKNOWN_KEY = 0;
+
+    /*
+     * Base key for each of the different classes. There is
+     * nothing intrinsic to the operation of the value of the
+     * keys. It's just segmented for better debugging. The
+     * classes don't mix them anway.
+     */
+    public static final int BASE_UID = 10000;
+    public static final int BASE_PID = 20000;
+    public static final int BASE_PROCESS = 30000;
+    public static final int BASE_PACKAGE = 40000;
+    public static final int BASE_SERVICE = 50000;
+
+    /*
+     * The types of values supported by HealthStats.
+     */
+    public static final int TYPE_TIMER = 0;
+    public static final int TYPE_MEASUREMENT = 1;
+    public static final int TYPE_STATS = 2;
+    public static final int TYPE_TIMERS = 3;
+    public static final int TYPE_MEASUREMENTS = 4;
+
+    public static final int TYPE_COUNT = 5;
+
+    /**
+     * Annotation to mark public static final int fields that are to be used
+     * as field keys in HealthStats.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.FIELD})
+    public @interface Constant {
+        /**
+         * One of the TYPE_* constants above.
+         */
+        int type();
+    }
+
+    /**
+     * Class to gather the constants defined in a class full of constants and
+     * build the key indices used by HealthStatsWriter and HealthStats.
+     *
+     * @hide
+     */
+    public static class Constants {
+        private final String mDataType;
+        private final int[][] mKeys = new int[TYPE_COUNT][];
+
+        /**
+         * Pass in a class to gather the public static final int fields that are
+         * tagged with the @Constant annotation.
+         */
+        public Constants(Class clazz) {
+            // Save the class name for debugging
+            mDataType = clazz.getSimpleName();
+
+            // Iterate through the list of fields on this class, and build the
+            // constant arrays for these fields.
+            final Field[] fields = clazz.getDeclaredFields();
+            final Class<Constant> annotationClass = Constant.class;
+
+            final int N = fields.length;
+
+            final SortedIntArray[] keys = new SortedIntArray[mKeys.length];
+            for (int i=0; i<keys.length; i++) {
+                keys[i] = new SortedIntArray(N);
+            }
+
+            for (int i=0; i<N; i++) {
+                final Field field = fields[i];
+                final Constant constant = field.getAnnotation(annotationClass);
+                if (constant != null) {
+                    final int type = constant.type();
+                    if (type >= keys.length) {
+                        throw new RuntimeException("Unknown Constant type " + type
+                                + " on " + field);
+                    }
+                    try {
+                        keys[type].addValue(field.getInt(null));
+                    } catch (IllegalAccessException ex) {
+                        throw new RuntimeException("Can't read constant value type=" + type
+                                + " field=" + field, ex);
+                    }
+                }
+            }
+
+            for (int i=0; i<keys.length; i++) {
+                mKeys[i] = keys[i].getArray();
+            }
+        }
+
+        /**
+         * Get a string representation of this class. Useful for debugging. It will be the
+         * simple name of the class passed in the constructor.
+         */
+        public String getDataType() {
+            return mDataType;
+        }
+
+        /**
+         * Return how many keys there are for the given field type.
+         *
+         * @see TYPE_TIMER
+         * @see TYPE_MEASUREMENT
+         * @see TYPE_TIMERS
+         * @see TYPE_MEASUREMENTS
+         * @see TYPE_STATS
+         */
+        public int getSize(int type) {
+            return mKeys[type].length;
+        }
+
+        /**
+         * Return the index for the given type and key combination in the array of field
+         * keys or values.
+         *
+         * @see TYPE_TIMER
+         * @see TYPE_MEASUREMENT
+         * @see TYPE_TIMERS
+         * @see TYPE_MEASUREMENTS
+         * @see TYPE_STATS
+         */
+        public int getIndex(int type, int key) {
+            final int index = Arrays.binarySearch(mKeys[type], key);
+            if (index >= 0) {
+                return index;
+            } else {
+                throw new RuntimeException("Unknown Constant " + key + " (of type "
+                        + type + " )");
+            }
+        }
+
+        /**
+         * Get the array of keys for the given field type.
+         */
+        public int[] getKeys(int type) {
+            return mKeys[type];
+        }
+    }
+
+    /**
+     * An array of fixed size that will be sorted.
+     */
+    private static class SortedIntArray {
+        int mCount;
+        int[] mArray;
+
+        /**
+         * Construct with the maximum number of values.
+         */
+        SortedIntArray(int maxCount) {
+            mArray = new int[maxCount];
+        }
+
+        /**
+         * Add a value.
+         */
+        void addValue(int value) {
+            mArray[mCount++] = value;
+        }
+
+        /**
+         * Get the array of values that have been added, with the values in
+         * numerically increasing order.
+         */
+        int[] getArray() {
+            if (mCount == mArray.length) {
+                Arrays.sort(mArray);
+                return mArray;
+            } else {
+                final int[] result = new int[mCount];
+                System.arraycopy(mArray, 0, result, 0, mCount);
+                Arrays.sort(result);
+                return result;
+            }
+        }
+    }
+}
+
+
diff --git a/core/java/android/os/health/HealthStats.java b/core/java/android/os/health/HealthStats.java
new file mode 100644
index 0000000..f0489e2
--- /dev/null
+++ b/core/java/android/os/health/HealthStats.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * A HealthStats object contains system health data about an application.
+ *
+ * <p>
+ * <b>Data Types</b><br>
+ * Each of the keys references data in one of five data types:
+ *
+ * <p>
+ * A <b>measurement</b> metric contains a sinlge {@code long} value. That value may
+ * be a count, a time, or some other type of value. The unit for a measurement
+ * (COUNT, MS, etc) will always be in the name of the constant for the key to
+ * retrieve it. For example, the
+ * {@link android.os.health.UidHealthStats#MEASUREMENT_WIFI_TX_MS UidHealthStats.MEASUREMENT_WIFI_TX_MS}
+ * value is the number of milliseconds (ms) that were spent transmitting on wifi by an
+ * application.  The
+ * {@link android.os.health.UidHealthStats#MEASUREMENT_MOBILE_RX_PACKETS UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS}
+ * measurement is the number of packets received on behalf of an application.
+ * The {@link android.os.health.UidHealthStats#MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
+ *     UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT}
+ * measurement is the number of times the user touched the screen, causing the
+ * screen to stay awake.
+ *
+ *
+ * <p>
+ * A <b>timer</b> metric contains an {@code int} count and a {@code long} time,
+ * measured in milliseconds. Timers track how many times a resource was used, and
+ * the total duration for that usage. For example, the
+ * {@link android.os.health.UidHealthStats#TIMER_FLASHLIGHT}
+ * timer tracks how many times the application turned on the flashlight, and for
+ * how many milliseconds total it kept it on.
+ *
+ * <p>
+ * A <b>measurement map</b> metric is a mapping of {@link java.lang.String} names to
+ * {@link java.lang.Long} values.  The names typically are application provided names. For
+ * example, the
+ * {@link android.os.health.PackageHealthStats#MEASUREMENTS_WAKEUP_ALARMS_COUNT
+ *         PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT}
+ * measurement map is a mapping of the tag provided to the
+ * {@link android.app.AlarmManager} when the alarm is scheduled.
+ *
+ * <p>
+ * A <b>timer map</b> metric is a mapping of {@link java.lang.String} names to
+ * {@link android.os.health.TimerStat} objects. The names are typically application
+ * provided names.  For example, the
+ * {@link android.os.health.UidHealthStats#TIMERS_WAKELOCKS_PARTIAL UidHealthStats.TIMERS_WAKELOCKS_PARTIAL}
+ * is a mapping of tag provided to the {@link android.os.PowerManager} when the
+ * wakelock is created to the number of times and for how long each wakelock was
+ * active.
+ *
+ * <p>
+ * Lastly, a <b>health stats</b> metric is a mapping of {@link java.lang.String}
+ * names to a recursive {@link android.os.health.HealthStats} object containing
+ * more detailed information. For example, the
+ * {@link android.os.health.UidHealthStats#STATS_PACKAGES UidHealthStats.STATS_PACKAGES}
+ * metric is a mapping of the package names for each of the APKs sharing a uid to
+ * the information recorded for that apk.  The returned HealthStats objects will
+ * each be associated with a different set of constants.  For the HealthStats
+ * returned for UidHealthStats.STATS_PACKAGES, the keys come from the
+ * {@link android.os.health.PackageHealthStats}  class.
+ *
+ */
+public class HealthStats {
+    // Header fields
+    private String mDataType;
+
+    // TimerStat fields
+    private int[] mTimerKeys;
+    private int[] mTimerCounts;
+    private long[] mTimerTimes;
+
+    // Measurement fields
+    private int[] mMeasurementKeys;
+    private long[] mMeasurementValues;
+
+    // Stats fields
+    private int[] mStatsKeys;
+    private ArrayMap<String,HealthStats>[] mStatsValues;
+
+    // Timers fields
+    private int[] mTimersKeys;
+    private ArrayMap<String,TimerStat>[] mTimersValues;
+
+    // Measurements fields
+    private int[] mMeasurementsKeys;
+    private ArrayMap<String,Long>[] mMeasurementsValues;
+
+    /**
+     * HealthStats empty constructor not implemented because this
+     * class is read-only.
+     */
+    private HealthStats() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /**
+     * Construct a health stats object from a parcel.
+     *
+     * @hide
+     */
+    public HealthStats(Parcel in) {
+        int count;
+
+        // Header fields
+        mDataType = in.readString();
+
+        // TimerStat fields
+        count = in.readInt();
+        mTimerKeys = new int[count];
+        mTimerCounts = new int[count];
+        mTimerTimes = new long[count];
+        for (int i=0; i<count; i++) {
+            mTimerKeys[i] = in.readInt();
+            mTimerCounts[i] = in.readInt();
+            mTimerTimes[i] = in.readLong();
+        }
+
+        // Measurement fields
+        count = in.readInt();
+        mMeasurementKeys = new int[count];
+        mMeasurementValues = new long[count];
+        for (int i=0; i<count; i++) {
+            mMeasurementKeys[i] = in.readInt();
+            mMeasurementValues[i] = in.readLong();
+        }
+
+        // Stats fields
+        count = in.readInt();
+        mStatsKeys = new int[count];
+        mStatsValues = new ArrayMap[count];
+        for (int i=0; i<count; i++) {
+            mStatsKeys[i] = in.readInt();
+            mStatsValues[i] = createHealthStatsMap(in);
+        }
+
+        // Timers fields
+        count = in.readInt();
+        mTimersKeys = new int[count];
+        mTimersValues = new ArrayMap[count];
+        for (int i=0; i<count; i++) {
+            mTimersKeys[i] = in.readInt();
+            mTimersValues[i] = createParcelableMap(in, TimerStat.CREATOR);
+        }
+
+        // Measurements fields
+        count = in.readInt();
+        mMeasurementsKeys = new int[count];
+        mMeasurementsValues = new ArrayMap[count];
+        for (int i=0; i<count; i++) {
+            mMeasurementsKeys[i] = in.readInt();
+            mMeasurementsValues[i] = createLongsMap(in);
+        }
+    }
+
+    /**
+     * Get a name representing the contents of this object.
+     *
+     * @see UidHealthStats
+     * @see PackageHealthStats
+     * @see PidHealthStats
+     * @see ProcessHealthStats
+     * @see ServiceHealthStats
+     */
+    public String getDataType() {
+        return mDataType;
+    }
+
+    /**
+     * Return whether this object contains a TimerStat for the supplied key.
+     */
+    public boolean hasTimer(int key) {
+        return getIndex(mTimerKeys, key) >= 0;
+    }
+
+    /**
+     * Return a TimerStat object for the given key.
+     *
+     * This will allocate a new {@link TimerStat} object, which may be wasteful. Instead, use
+     * {@link #getTimerCount} and {@link #getTimerTime}.
+     *
+     * @throws IndexOutOfBoundsException When the key is not present in this object.
+     * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
+     */
+    public TimerStat getTimer(int key) {
+        final int index = getIndex(mTimerKeys, key);
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
+                    + " key=" + key);
+        }
+        return new TimerStat(mTimerCounts[index], mTimerTimes[index]);
+    }
+
+    /**
+     * Get the count for the timer for the given key.
+     *
+     * @throws IndexOutOfBoundsException When the key is not present in this object.
+     * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
+     */
+    public int getTimerCount(int key) {
+        final int index = getIndex(mTimerKeys, key);
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
+                    + " key=" + key);
+        }
+        return mTimerCounts[index];
+    }
+
+    /**
+     * Get the time for the timer for the given key, in milliseconds.
+     *
+     * @throws IndexOutOfBoundsException When the key is not present in this object.
+     * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
+     */
+    public long getTimerTime(int key) {
+        final int index = getIndex(mTimerKeys, key);
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
+                    + " key=" + key);
+        }
+        return mTimerTimes[index];
+    }
+
+    /**
+     * Get the number of timer values in this object. Can be used to iterate through
+     * the available timers.
+     *
+     * @see #getTimerKeyAt
+     */
+    public int getTimerKeyCount() {
+        return mTimerKeys.length;
+    }
+
+    /**
+     * Get the key for the timer at the given index.  Index must be between 0 and the result
+     * of {@link #getTimerKeyCount getTimerKeyCount()}.
+     *
+     * @see #getTimerKeyCount
+     */
+    public int getTimerKeyAt(int index) {
+        return mTimerKeys[index];
+    }
+
+    /**
+     * Return whether this object contains a measurement for the supplied key.
+     */
+    public boolean hasMeasurement(int key) {
+        return getIndex(mMeasurementKeys, key) >= 0;
+    }
+
+    /**
+     * Get the measurement for the given key.
+     *
+     * @throws IndexOutOfBoundsException When the key is not present in this object.
+     * @see #hasMeasurement hasMeasurement(int) To check if a value for the given key is present.
+     */
+    public long getMeasurement(int key) {
+        final int index = getIndex(mMeasurementKeys, key);
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Bad measurement key dataType=" + mDataType
+                    + " key=" + key);
+        }
+        return mMeasurementValues[index];
+    }
+
+    /**
+     * Get the number of measurement values in this object. Can be used to iterate through
+     * the available measurements.
+     *
+     * @see #getMeasurementKeyAt
+     */
+    public int getMeasurementKeyCount() {
+        return mMeasurementKeys.length;
+    }
+
+    /**
+     * Get the key for the measurement at the given index.  Index must be between 0 and the result
+     * of {@link #getMeasurementKeyCount getMeasurementKeyCount()}.
+     *
+     * @see #getMeasurementKeyCount
+     */
+    public int getMeasurementKeyAt(int index) {
+        return mMeasurementKeys[index];
+    }
+
+    /**
+     * Return whether this object contains a HealthStats map for the supplied key.
+     */
+    public boolean hasStats(int key) {
+        return getIndex(mStatsKeys, key) >= 0;
+    }
+
+    /**
+     * Get the HealthStats map for the given key.
+     *
+     * @throws IndexOutOfBoundsException When the key is not present in this object.
+     * @see #hasStats hasStats(int) To check if a value for the given key is present.
+     */
+    public Map<String,HealthStats> getStats(int key) {
+        final int index = getIndex(mStatsKeys, key);
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Bad stats key dataType=" + mDataType
+                    + " key=" + key);
+        }
+        return mStatsValues[index];
+    }
+
+    /**
+     * Get the number of HealthStat map values in this object. Can be used to iterate through
+     * the available measurements.
+     *
+     * @see #getMeasurementKeyAt
+     */
+    public int getStatsKeyCount() {
+        return mStatsKeys.length;
+    }
+
+    /**
+     * Get the key for the timer at the given index.  Index must be between 0 and the result
+     * of {@link #getStatsKeyCount getStatsKeyCount()}.
+     *
+     * @see #getStatsKeyCount
+     */
+    public int getStatsKeyAt(int index) {
+        return mStatsKeys[index];
+    }
+
+    /**
+     * Return whether this object contains a timers map for the supplied key.
+     */
+    public boolean hasTimers(int key) {
+        return getIndex(mTimersKeys, key) >= 0;
+    }
+
+    /**
+     * Get the TimerStat map for the given key.
+     *
+     * @throws IndexOutOfBoundsException When the key is not present in this object.
+     * @see #hasTimers hasTimers(int) To check if a value for the given key is present.
+     */
+    public Map<String,TimerStat> getTimers(int key) {
+        final int index = getIndex(mTimersKeys, key);
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Bad timers key dataType=" + mDataType
+                    + " key=" + key);
+        }
+        return mTimersValues[index];
+    }
+
+    /**
+     * Get the number of timer map values in this object. Can be used to iterate through
+     * the available timer maps.
+     *
+     * @see #getTimersKeyAt
+     */
+    public int getTimersKeyCount() {
+        return mTimersKeys.length;
+    }
+
+    /**
+     * Get the key for the timer map at the given index.  Index must be between 0 and the result
+     * of {@link #getTimersKeyCount getTimersKeyCount()}.
+     *
+     * @see #getTimersKeyCount
+     */
+    public int getTimersKeyAt(int index) {
+        return mTimersKeys[index];
+    }
+
+    /**
+     * Return whether this object contains a measurements map for the supplied key.
+     */
+    public boolean hasMeasurements(int key) {
+        return getIndex(mMeasurementsKeys, key) >= 0;
+    }
+
+    /**
+     * Get the measurements map for the given key.
+     *
+     * @throws IndexOutOfBoundsException When the key is not present in this object.
+     * @see #hasMeasurements To check if a value for the given key is present.
+     */
+    public Map<String,Long> getMeasurements(int key) {
+        final int index = getIndex(mMeasurementsKeys, key);
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Bad measurements key dataType=" + mDataType
+                    + " key=" + key);
+        }
+        return mMeasurementsValues[index];
+    }
+
+    /**
+     * Get the number of measurement map values in this object. Can be used to iterate through
+     * the available measurement maps.
+     *
+     * @see #getMeasurementsKeyAt
+     */
+    public int getMeasurementsKeyCount() {
+        return mMeasurementsKeys.length;
+    }
+
+    /**
+     * Get the key for the measurement map at the given index.
+     * Index must be between 0 and the result
+     * of {@link #getMeasurementsKeyCount getMeasurementsKeyCount()}.
+     *
+     * @see #getMeasurementsKeyCount
+     */
+    public int getMeasurementsKeyAt(int index) {
+        return mMeasurementsKeys[index];
+    }
+
+    /**
+     * Get the index in keys of key.
+     */
+    private static int getIndex(int[] keys, int key) {
+        return Arrays.binarySearch(keys, key);
+    }
+
+    /**
+     * Create an ArrayMap<String,HealthStats> from the given Parcel.
+     */
+    private static ArrayMap<String,HealthStats> createHealthStatsMap(Parcel in) {
+        final int count = in.readInt();
+        final ArrayMap<String,HealthStats> result = new ArrayMap<String,HealthStats>(count);
+        for (int i=0; i<count; i++) {
+            result.put(in.readString(), new HealthStats(in));
+        }
+        return result;
+    }
+
+    /**
+     * Create an ArrayMap<String,T extends Parcelable> from the given Parcel using
+     * the given Parcelable.Creator.
+     */
+    private static <T extends Parcelable> ArrayMap<String,T> createParcelableMap(Parcel in,
+            Parcelable.Creator<T> creator) {
+        final int count = in.readInt();
+        final ArrayMap<String,T> result = new ArrayMap<String,T>(count);
+        for (int i=0; i<count; i++) {
+            result.put(in.readString(), creator.createFromParcel(in));
+        }
+        return result;
+    }
+
+    /**
+     * Create an ArrayMap<String,Long> from the given Parcel.
+     */
+    private static ArrayMap<String,Long> createLongsMap(Parcel in) {
+        final int count = in.readInt();
+        final ArrayMap<String,Long> result = new ArrayMap<String,Long>(count);
+        for (int i=0; i<count; i++) {
+            result.put(in.readString(), in.readLong());
+        }
+        return result;
+    }
+}
+
diff --git a/core/java/android/os/health/HealthStatsParceler.aidl b/core/java/android/os/health/HealthStatsParceler.aidl
new file mode 100644
index 0000000..68c348b
--- /dev/null
+++ b/core/java/android/os/health/HealthStatsParceler.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+parcelable HealthStatsParceler;
diff --git a/core/java/android/os/health/HealthStatsParceler.java b/core/java/android/os/health/HealthStatsParceler.java
new file mode 100644
index 0000000..28b3694
--- /dev/null
+++ b/core/java/android/os/health/HealthStatsParceler.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Class to allow sending the HealthStats through aidl generated glue.
+ *
+ * The alternative would be to send a HealthStats object, which would
+ * require constructing one, and then immediately flattening it. This
+ * saves that step at the cost of doing the extra flattening when
+ * accessed in the same process as the writer.
+ *
+ * The HealthStatsWriter passed in the constructor is retained, so don't
+ * reuse them.
+ * @hide
+ */
+public class HealthStatsParceler implements Parcelable {
+    private HealthStatsWriter mWriter;
+    private HealthStats mHealthStats;
+
+    public static final Parcelable.Creator<HealthStatsParceler> CREATOR
+            = new Parcelable.Creator<HealthStatsParceler>() {
+        public HealthStatsParceler createFromParcel(Parcel in) {
+            return new HealthStatsParceler(in);
+        }
+
+        public HealthStatsParceler[] newArray(int size) {
+            return new HealthStatsParceler[size];
+        }
+    };
+
+    public HealthStatsParceler(HealthStatsWriter writer) {
+        mWriter = writer;
+    }
+
+    public HealthStatsParceler(Parcel in) {
+        mHealthStats = new HealthStats(in);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        // See comment on mWriter declaration above.
+        if (mWriter != null) {
+            mWriter.flattenToParcel(out);
+        } else {
+            throw new RuntimeException("Can not re-parcel HealthStatsParceler that was"
+                    + " constructed from a Parcel");
+        }
+    }
+
+    public HealthStats getHealthStats() {
+        if (mWriter != null) {
+            final Parcel parcel = Parcel.obtain();
+            mWriter.flattenToParcel(parcel);
+            parcel.setDataPosition(0);
+            mHealthStats = new HealthStats(parcel);
+            parcel.recycle();
+        }
+
+        return mHealthStats;
+    }
+}
+
diff --git a/core/java/android/os/health/HealthStatsWriter.java b/core/java/android/os/health/HealthStatsWriter.java
new file mode 100644
index 0000000..351836b
--- /dev/null
+++ b/core/java/android/os/health/HealthStatsWriter.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Class to write the health stats data into a parcel, so it can then be
+ * retrieved via a {@link HealthStats} object.
+ *
+ * There is an attempt to keep this class as low overhead as possible, for
+ * example storing an int[] and a long[] instead of a TimerStat[].
+ *
+ * @hide
+ */
+public class HealthStatsWriter {
+    private final HealthKeys.Constants mConstants;
+
+    // TimerStat fields
+    private final boolean[] mTimerFields;
+    private final int[] mTimerCounts;
+    private final long[] mTimerTimes;
+
+    // Measurement fields
+    private final boolean[] mMeasurementFields;
+    private final long[] mMeasurementValues;
+
+    // Stats fields
+    private final ArrayMap<String,HealthStatsWriter>[] mStatsValues;
+
+    // Timers fields
+    private final ArrayMap<String,TimerStat>[] mTimersValues;
+
+    // Measurements fields
+    private final ArrayMap<String,Long>[] mMeasurementsValues;
+
+    /**
+     * Construct a HealthStatsWriter object with the given constants.
+     *
+     * The "getDataType()" of the resulting HealthStats object will be the
+     * short name of the java class that the Constants object was initalized
+     * with.
+     */
+    public HealthStatsWriter(HealthKeys.Constants constants) {
+        mConstants = constants;
+
+        // TimerStat
+        final int timerCount = constants.getSize(HealthKeys.TYPE_TIMER);
+        mTimerFields = new boolean[timerCount];
+        mTimerCounts = new int[timerCount];
+        mTimerTimes = new long[timerCount];
+
+        // Measurement
+        final int measurementCount = constants.getSize(HealthKeys.TYPE_MEASUREMENT);
+        mMeasurementFields = new boolean[measurementCount];
+        mMeasurementValues = new long[measurementCount];
+
+        // Stats
+        final int statsCount = constants.getSize(HealthKeys.TYPE_STATS);
+        mStatsValues = new ArrayMap[statsCount];
+
+        // Timers
+        final int timersCount = constants.getSize(HealthKeys.TYPE_TIMERS);
+        mTimersValues = new ArrayMap[timersCount];
+
+        // Measurements
+        final int measurementsCount = constants.getSize(HealthKeys.TYPE_MEASUREMENTS);
+        mMeasurementsValues = new ArrayMap[measurementsCount];
+    }
+
+    /**
+     * Add a timer for the given key.
+     */
+    public void addTimer(int timerId, int count, long time) {
+        final int index = mConstants.getIndex(HealthKeys.TYPE_TIMER, timerId);
+
+        mTimerFields[index] = true;
+        mTimerCounts[index] = count;
+        mTimerTimes[index] = time;
+    }
+
+    /**
+     * Add a measurement for the given key.
+     */
+    public void addMeasurement(int measurementId, long value) {
+        final int index = mConstants.getIndex(HealthKeys.TYPE_MEASUREMENT, measurementId);
+
+        mMeasurementFields[index] = true;
+        mMeasurementValues[index] = value;
+    }
+
+    /**
+     * Add a recursive HealthStats object for the given key and string name. The value
+     * is stored as a HealthStatsWriter until this object is written to a parcel, so
+     * don't attempt to reuse the HealthStatsWriter.
+     *
+     * The value field should not be null.
+     */
+    public void addStats(int key, String name, HealthStatsWriter value) {
+        final int index = mConstants.getIndex(HealthKeys.TYPE_STATS, key);
+
+        ArrayMap<String,HealthStatsWriter> map = mStatsValues[index];
+        if (map == null) {
+            map = mStatsValues[index] = new ArrayMap<String,HealthStatsWriter>(1);
+        }
+        map.put(name, value);
+    }
+
+    /**
+     * Add a TimerStat for the given key and string name.
+     *
+     * The value field should not be null.
+     */
+    public void addTimers(int key, String name, TimerStat value) {
+        final int index = mConstants.getIndex(HealthKeys.TYPE_TIMERS, key);
+
+        ArrayMap<String,TimerStat> map = mTimersValues[index];
+        if (map == null) {
+            map = mTimersValues[index] = new ArrayMap<String,TimerStat>(1);
+        }
+        map.put(name, value);
+    }
+
+    /**
+     * Add a measurement for the given key and string name.
+     */
+    public void addMeasurements(int key, String name, long value) {
+        final int index = mConstants.getIndex(HealthKeys.TYPE_MEASUREMENTS, key);
+
+        ArrayMap<String,Long> map = mMeasurementsValues[index];
+        if (map == null) {
+            map = mMeasurementsValues[index] = new ArrayMap<String,Long>(1);
+        }
+        map.put(name, value);
+    }
+
+    /**
+     * Flattens the data in this HealthStatsWriter to the Parcel format
+     * that can be unparceled into a HealthStat.
+     * @more
+     * (Called flattenToParcel because this HealthStatsWriter itself is
+     * not parcelable and we don't flatten all the business about the
+     * HealthKeys.Constants, only the values that were actually supplied)
+     */
+    public void flattenToParcel(Parcel out) {
+        int[] keys;
+
+        // Header fields
+        out.writeString(mConstants.getDataType());
+
+        // TimerStat fields
+        out.writeInt(countBooleanArray(mTimerFields));
+        keys = mConstants.getKeys(HealthKeys.TYPE_TIMER);
+        for (int i=0; i<keys.length; i++) {
+            if (mTimerFields[i]) {
+                out.writeInt(keys[i]);
+                out.writeInt(mTimerCounts[i]);
+                out.writeLong(mTimerTimes[i]);
+            }
+        }
+
+        // Measurement fields
+        out.writeInt(countBooleanArray(mMeasurementFields));
+        keys = mConstants.getKeys(HealthKeys.TYPE_MEASUREMENT);
+        for (int i=0; i<keys.length; i++) {
+            if (mMeasurementFields[i]) {
+                out.writeInt(keys[i]);
+                out.writeLong(mMeasurementValues[i]);
+            }
+        }
+
+        // Stats
+        out.writeInt(countObjectArray(mStatsValues));
+        keys = mConstants.getKeys(HealthKeys.TYPE_STATS);
+        for (int i=0; i<keys.length; i++) {
+            if (mStatsValues[i] != null) {
+                out.writeInt(keys[i]);
+                writeHealthStatsWriterMap(out, mStatsValues[i]);
+            }
+        }
+
+        // Timers
+        out.writeInt(countObjectArray(mTimersValues));
+        keys = mConstants.getKeys(HealthKeys.TYPE_TIMERS);
+        for (int i=0; i<keys.length; i++) {
+            if (mTimersValues[i] != null) {
+                out.writeInt(keys[i]);
+                writeParcelableMap(out, mTimersValues[i]);
+            }
+        }
+
+        // Measurements
+        out.writeInt(countObjectArray(mMeasurementsValues));
+        keys = mConstants.getKeys(HealthKeys.TYPE_MEASUREMENTS);
+        for (int i=0; i<keys.length; i++) {
+            if (mMeasurementsValues[i] != null) {
+                out.writeInt(keys[i]);
+                writeLongsMap(out, mMeasurementsValues[i]);
+            }
+        }
+    }
+
+    /**
+     * Count how many of the fields have been set.
+     */
+    private static int countBooleanArray(boolean[] fields) {
+        int count = 0;
+        final int N = fields.length;
+        for (int i=0; i<N; i++) {
+            if (fields[i]) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Count how many of the fields have been set.
+     */
+    private static <T extends Object> int countObjectArray(T[] fields) {
+        int count = 0;
+        final int N = fields.length;
+        for (int i=0; i<N; i++) {
+            if (fields[i] != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Write a map of String to HealthStatsWriter to the Parcel.
+     */
+    private static void writeHealthStatsWriterMap(Parcel out,
+            ArrayMap<String,HealthStatsWriter> map) {
+        final int N = map.size();
+        out.writeInt(N);
+        for (int i=0; i<N; i++) {
+            out.writeString(map.keyAt(i));
+            map.valueAt(i).flattenToParcel(out);
+        }
+    }
+
+    /**
+     * Write a map of String to Parcelables to the Parcel.
+     */
+    private static <T extends Parcelable> void writeParcelableMap(Parcel out,
+            ArrayMap<String,T> map) {
+        final int N = map.size();
+        out.writeInt(N);
+        for (int i=0; i<N; i++) {
+            out.writeString(map.keyAt(i));
+            map.valueAt(i).writeToParcel(out, 0);
+        }
+    }
+
+    /**
+     * Write a map of String to Longs to the Parcel.
+     */
+    private static void writeLongsMap(Parcel out, ArrayMap<String,Long> map) {
+        final int N = map.size();
+        out.writeInt(N);
+        for (int i=0; i<N; i++) {
+            out.writeString(map.keyAt(i));
+            out.writeLong(map.valueAt(i));
+        }
+    }
+}
+
+
diff --git a/core/java/android/os/health/PackageHealthStats.java b/core/java/android/os/health/PackageHealthStats.java
new file mode 100644
index 0000000..2c30d5f
--- /dev/null
+++ b/core/java/android/os/health/PackageHealthStats.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link UidHealthStats#STATS_PACKAGES UidHealthStats.STATS_PACKAGES} key.
+ */
+public final class PackageHealthStats {
+
+    private PackageHealthStats() {
+    }
+
+    /**
+     * Key for a HealthStats with {@link ServiceHealthStats} keys for each of the
+     * services defined in this apk.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+    public static final int STATS_SERVICES = HealthKeys.BASE_PACKAGE + 1;
+
+    /**
+     * Key for a map of the number of times that a package's wakeup alarms have fired
+     * while the device was on battery.
+     *
+     * @see android.app.AlarmManager.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENTS)
+    public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = HealthKeys.BASE_PACKAGE + 2;
+
+    /**
+     * @hide
+     */
+    public static final HealthKeys.Constants CONSTANTS
+            = new HealthKeys.Constants(PackageHealthStats.class);
+}
diff --git a/core/java/android/os/health/PidHealthStats.java b/core/java/android/os/health/PidHealthStats.java
new file mode 100644
index 0000000..fe3c02c
--- /dev/null
+++ b/core/java/android/os/health/PidHealthStats.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link UidHealthStats#STATS_PIDS UidHealthStats.STATS_PIDS} key.
+ */
+public final class PidHealthStats {
+
+    private PidHealthStats() {
+    }
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WAKE_NESTING_COUNT = HealthKeys.BASE_PID + 1;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WAKE_SUM_MS = HealthKeys.BASE_PID + 2;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WAKE_START_MS = HealthKeys.BASE_PID + 3;
+
+    /**
+     * @hide
+     */
+    public static final HealthKeys.Constants CONSTANTS = new HealthKeys.Constants(PidHealthStats.class);
+}
diff --git a/core/java/android/os/health/ProcessHealthStats.java b/core/java/android/os/health/ProcessHealthStats.java
new file mode 100644
index 0000000..e004ecb
--- /dev/null
+++ b/core/java/android/os/health/ProcessHealthStats.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link UidHealthStats#STATS_PROCESSES UidHealthStats.STATS_PROCESSES} key.
+ */
+public final class ProcessHealthStats {
+
+    private ProcessHealthStats() {
+    }
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_USER_TIME_MS = HealthKeys.BASE_PROCESS + 1;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_SYSTEM_TIME_MS = HealthKeys.BASE_PROCESS + 2;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_STARTS_COUNT = HealthKeys.BASE_PROCESS + 3;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_CRASHES_COUNT = HealthKeys.BASE_PROCESS + 4;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_ANR_COUNT = HealthKeys.BASE_PROCESS + 5;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_FOREGROUND_MS = HealthKeys.BASE_PROCESS + 6;
+
+    /**
+     * @hide
+     */
+    public static final HealthKeys.Constants CONSTANTS = new HealthKeys.Constants(ProcessHealthStats.class);
+}
diff --git a/core/java/android/os/health/ServiceHealthStats.java b/core/java/android/os/health/ServiceHealthStats.java
new file mode 100644
index 0000000..802ad31
--- /dev/null
+++ b/core/java/android/os/health/ServiceHealthStats.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link PackageHealthStats#STATS_SERVICES PackageHealthStats.STATS_SERVICES} key.
+ */
+public final class ServiceHealthStats {
+
+    private ServiceHealthStats() {
+    }
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_START_SERVICE_COUNT = HealthKeys.BASE_SERVICE + 1;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_LAUNCH_COUNT = HealthKeys.BASE_SERVICE + 2;
+
+    /**
+     * @hide
+     */
+    public static final HealthKeys.Constants CONSTANTS
+            = new HealthKeys.Constants(ServiceHealthStats.class);
+}
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
new file mode 100644
index 0000000..520e84e
--- /dev/null
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.app.IBatteryStats;
+
+/**
+ * Provides access to data about how various system resources are used by applications.
+ * @more
+ * <b>Battery Usage</b><br>
+ * The statistics related to power (battery) usage are recorded since the device
+ * was last unplugged. It is expected that applications schedule more work to do
+ * while the device is plugged in (e.g. using {@link android.app.job.JobScheduler
+ * JobScheduler}), and while that can affect charging rates, it is still preferable
+ * to actually draining the battery.
+ */
+public class SystemHealthManager {
+    private final IBatteryStats mBatteryStats;
+
+    /**
+     * Construct a new SystemHealthManager object.
+     * @hide
+     */
+    public SystemHealthManager() {
+        mBatteryStats = IBatteryStats.Stub.asInterface(
+            ServiceManager.getService(BatteryStats.SERVICE_NAME));
+    }
+
+    /**
+     * Obtain a SystemHealthManager object for the supplied context.
+     */
+    public static SystemHealthManager from(Context context) {
+        return (SystemHealthManager)context.getSystemService(Context.SYSTEM_HEALTH_SERVICE);
+    }
+
+    /**
+     * Return a {@link HealthStats} object containing a snapshot of system health
+     * metrics for the given uid (user-id, which in usually corresponds to application).
+     * @more
+     *
+     * An application must hold the {@link android.Manifest.permission#BATTERY_STATS
+     * android.permission.BATTERY_STATS} permission in order to retrieve any HealthStats
+     * other than its own.
+     *
+     * @param uid User ID for a given application.
+     * @return A {@link HealthStats} object containing the metrics for the requested
+     * application. The keys for this HealthStats object will be from the {@link UidHealthStats}
+     * class.
+     * @see Process#myUid()
+     */
+    public HealthStats takeUidSnapshot(int uid) {
+        try {
+            final HealthStatsParceler parceler = mBatteryStats.takeUidSnapshot(uid);
+            return parceler.getHealthStats();
+        } catch (RemoteException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Return a {@link HealthStats} object containing a snapshot of system health
+     * metrics for the application calling this API. This method is the same as calling
+     * {@code takeUidSnapshot(Process.myUid())}.
+     *
+     * @return A {@link HealthStats} object containing the metrics for this application. The keys
+     * for this HealthStats object will be from the {@link UidHealthStats} class.
+     */
+    public HealthStats takeMyUidSnapshot() {
+        return takeUidSnapshot(Process.myUid());
+    }
+
+    /**
+     * Return a {@link HealthStats} object containing a snapshot of system health
+     * metrics for the given uids (user-id, which in usually corresponds to application).
+     * @more
+     *
+     * An application must hold the {@link android.Manifest.permission#BATTERY_STATS
+     * android.permission.BATTERY_STATS} permission in order to retrieve any HealthStats
+     * other than its own.
+     *
+     * @param uids An array of User IDs to retrieve.
+     * @return An array of {@link HealthStats} objects containing the metrics for each of
+     * the requested uids. The keys for this HealthStats object will be from the
+     * {@link UidHealthStats} class.
+     */
+    public HealthStats[] takeUidSnapshots(int[] uids) {
+        try {
+            final HealthStatsParceler[] parcelers = mBatteryStats.takeUidSnapshots(uids);
+            final HealthStats[] results = new HealthStats[uids.length];
+            final int N = uids.length;
+            for (int i=0; i<N; i++) {
+                results[i] = parcelers[i].getHealthStats();
+            }
+            return results;
+        } catch (RemoteException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+}
+
diff --git a/core/java/android/os/health/TimerStat.java b/core/java/android/os/health/TimerStat.java
new file mode 100644
index 0000000..b9d8874
--- /dev/null
+++ b/core/java/android/os/health/TimerStat.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A TimerStat object stores a count and a time.
+ *
+ * @more
+ * When possible, the other APIs in this package avoid requiring a TimerStat
+ * object to be constructed, even internally, but the getTimers method on
+ * {@link android.os.health.HealthStats} does require TimerStat objects.
+ */
+public final class TimerStat implements Parcelable {
+    private int mCount;
+    private long mTime;
+
+    /**
+     * The CREATOR instance for use by aidl Binder interfaces.
+     */
+    public static final Parcelable.Creator<TimerStat> CREATOR
+            = new Parcelable.Creator<TimerStat>() {
+        public TimerStat createFromParcel(Parcel in) {
+            return new TimerStat(in);
+        }
+
+        public TimerStat[] newArray(int size) {
+            return new TimerStat[size];
+        }
+    };
+
+    /**
+     * Construct an empty TimerStat object with the count and time set to 0.
+     */
+    public TimerStat() {
+    }
+
+    /**
+     * Construct a TimerStat object with the supplied count and time fields.
+     *
+     * @param count The count
+     * @param time The time
+     */
+    public TimerStat(int count, long time) {
+        mCount = count;
+        mTime = time;
+    }
+
+    /**
+     * Construct a TimerStat object reading the values from a {@link android.os.Parcel Parcel}
+     * object.
+     */
+    public TimerStat(Parcel in) {
+        mCount = in.readInt();
+        mTime = in.readLong();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Write this TimerStat object to a parcel.
+     */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mCount);
+        out.writeLong(mTime);
+    }
+
+    /**
+     * Set the count for this timer.
+     */
+    public void setCount(int count) {
+        mCount = count;
+    }
+
+    /**
+     * Get the count for this timer.
+     */
+    public int getCount() {
+        return mCount;
+    }
+
+    /**
+     * Set the time for this timer.
+     */
+    public void setTime(long time) {
+        mTime = time;
+    }
+
+    /**
+     * Get the time for this timer.
+     */
+    public long getTime() {
+        return mTime;
+    }
+}
diff --git a/core/java/android/os/health/UidHealthStats.java b/core/java/android/os/health/UidHealthStats.java
new file mode 100644
index 0000000..c7d257f
--- /dev/null
+++ b/core/java/android/os/health/UidHealthStats.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link SystemHealthManager#takeUidSnapshot(int) SystemHealthManager.takeUidSnapshot(int)},
+ * {@link SystemHealthManager#takeMyUidSnapshot() SystemHealthManager.takeMyUidSnapshot()}, and
+ * {@link SystemHealthManager#takeUidSnapshots(int[]) SystemHealthManager.takeUidSnapshots(int[])}.
+ */
+public final class UidHealthStats {
+
+    private UidHealthStats() {
+    }
+
+    /**
+     * How many milliseconds this statistics report covers in wall-clock time while the
+     * device was on battery including both screen-on and screen-off time.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_REALTIME_BATTERY_MS = HealthKeys.BASE_UID + 1;
+
+    /**
+     * How many milliseconds this statistics report covers that the CPU was running while the
+     * device was on battery including both screen-on and screen-off time.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_UPTIME_BATTERY_MS = HealthKeys.BASE_UID + 2;
+
+    /**
+     * How many milliseconds this statistics report covers in wall-clock time while the
+     * device was on battery including both screen-on and screen-off time.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 3;
+
+    /**
+     * How many milliseconds this statistics report covers that the CPU was running while the
+     * device was on battery including both screen-on and screen-off time.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 4;
+
+    /**
+     * Key for a TimerStat for the times a
+     * {@link android.os.PowerManager#FULL_WAKE_LOCK full wake lock}
+     * was acquired for this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+    public static final int TIMERS_WAKELOCKS_FULL = HealthKeys.BASE_UID + 5;
+
+    /**
+     * Key for a TimerStat for the times a
+     * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK full wake lock}
+     * was acquired for this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+    public static final int TIMERS_WAKELOCKS_PARTIAL = HealthKeys.BASE_UID + 6;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+    public static final int TIMERS_WAKELOCKS_WINDOW = HealthKeys.BASE_UID + 7;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+    public static final int TIMERS_WAKELOCKS_DRAW = HealthKeys.BASE_UID + 8;
+
+    /**
+     * Key for a map of Timers for the sync adapter syncs that were done for
+     * this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+    public static final int TIMERS_SYNCS = HealthKeys.BASE_UID + 9;
+
+    /**
+     * Key for a map of Timers for the {@link android.app.job.JobScheduler} jobs for
+     * this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+    public static final int TIMERS_JOBS = HealthKeys.BASE_UID + 10;
+
+    /**
+     * Key for a timer for the applications use of the GPS sensor.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_GPS_SENSOR = HealthKeys.BASE_UID + 11;
+
+    /**
+     * Key for a map of the sensor usage for this uid. The keys are a
+     * string representation of the handle for the sensor.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+    public static final int TIMERS_SENSORS = HealthKeys.BASE_UID + 12;
+
+    /**
+     * Key for a HealthStats with {@link PidHealthStats} keys for each of the
+     * currently running processes for this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+    public static final int STATS_PIDS = HealthKeys.BASE_UID + 13;
+
+    /**
+     * Key for a HealthStats with {@link ProcessHealthStats} keys for each of the
+     * named processes for this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+    public static final int STATS_PROCESSES = HealthKeys.BASE_UID + 14;
+
+    /**
+     * Key for a HealthStats with {@link PackageHealthStats} keys for each of the
+     * APKs that share this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+    public static final int STATS_PACKAGES = HealthKeys.BASE_UID + 15;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_IDLE_MS = HealthKeys.BASE_UID + 16;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_RX_MS = HealthKeys.BASE_UID + 17;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_TX_MS = HealthKeys.BASE_UID + 18;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_POWER_MAMS = HealthKeys.BASE_UID + 19;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = HealthKeys.BASE_UID + 20;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_RX_MS = HealthKeys.BASE_UID + 21;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_TX_MS = HealthKeys.BASE_UID + 22;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = HealthKeys.BASE_UID + 23;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_IDLE_MS = HealthKeys.BASE_UID + 24;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_RX_MS = HealthKeys.BASE_UID + 25;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_TX_MS = HealthKeys.BASE_UID + 26;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_POWER_MAMS = HealthKeys.BASE_UID + 27;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_RUNNING_MS = HealthKeys.BASE_UID + 28;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = HealthKeys.BASE_UID + 29;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_WIFI_SCAN = HealthKeys.BASE_UID + 30;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_MULTICAST_MS = HealthKeys.BASE_UID + 31;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_AUDIO = HealthKeys.BASE_UID + 32;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_VIDEO = HealthKeys.BASE_UID + 33;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_FLASHLIGHT = HealthKeys.BASE_UID + 34;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_CAMERA = HealthKeys.BASE_UID + 35;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_FOREGROUND_ACTIVITY = HealthKeys.BASE_UID + 36;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_BLUETOOTH_SCAN = HealthKeys.BASE_UID + 37;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_PROCESS_STATE_TOP_MS = HealthKeys.BASE_UID + 38;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = HealthKeys.BASE_UID + 39;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = HealthKeys.BASE_UID + 40;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = HealthKeys.BASE_UID + 41;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = HealthKeys.BASE_UID + 42;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_PROCESS_STATE_CACHED_MS = HealthKeys.BASE_UID + 43;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_VIBRATOR = HealthKeys.BASE_UID + 44;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = HealthKeys.BASE_UID + 45;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = HealthKeys.BASE_UID + 46;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = HealthKeys.BASE_UID + 47;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_RX_BYTES = HealthKeys.BASE_UID + 48;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_TX_BYTES = HealthKeys.BASE_UID + 49;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_RX_BYTES = HealthKeys.BASE_UID + 50;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_TX_BYTES = HealthKeys.BASE_UID + 51;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = HealthKeys.BASE_UID + 52;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = HealthKeys.BASE_UID + 53;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_RX_PACKETS = HealthKeys.BASE_UID + 54;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_MOBILE_TX_PACKETS = HealthKeys.BASE_UID + 55;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_RX_PACKETS = HealthKeys.BASE_UID + 56;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_WIFI_TX_PACKETS = HealthKeys.BASE_UID + 57;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = HealthKeys.BASE_UID + 58;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = HealthKeys.BASE_UID + 59;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+    public static final int TIMER_MOBILE_RADIO_ACTIVE = HealthKeys.BASE_UID + 61;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_USER_CPU_TIME_US = HealthKeys.BASE_UID + 62;
+
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = HealthKeys.BASE_UID + 63;
+
+    /**
+     * An estimate of the number of milliamp-microsends used by this uid.
+     */
+    @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+    public static final int MEASUREMENT_CPU_POWER_MAUS = HealthKeys.BASE_UID + 64;
+
+    /**
+     * @hide
+     */
+    public static final HealthKeys.Constants CONSTANTS = new HealthKeys.Constants(UidHealthStats.class);
+}
+
diff --git a/core/java/android/os/health/package.html b/core/java/android/os/health/package.html
new file mode 100644
index 0000000..3a46a5b
--- /dev/null
+++ b/core/java/android/os/health/package.html
@@ -0,0 +1,39 @@
+<html>
+<body>
+
+The android.os.health package contains a set of classes to provide data
+to track the system resources of applications.
+<p>
+Applications running in the background are responsible for a significant amount 
+of battery usage on a typical android device. There are several things that 
+applications can do in order to reduce their impact. For example, by using 
+{@link android.app.job.JobScheduler JobScheduler}, an application does not need 
+to independently monitor whether the network is available, whether the device is 
+plugged in, etc.  In addition to being simpler to use, the application's 
+services are only started when the required conditions have been met.  But even 
+when using the appropriate helper APIs, applications still can reduce their 
+footprint. This package provides more insight into what is going on behind the 
+scenes when an application is running.
+<p>
+Application data is tracked by which user id (uid) is using particular 
+resources. A snapshot of an application's measurements can be taken with the
+{@link android.os.health.SystemHealthManager#takeMyUidSnapshot() SystemHealth.takeMyUidSnapshot()} 
+method. The {@link android.os.health.HealthStats} object returned contains the 
+statistics.
+<p>
+<b>HealthStats</b><br>
+In order to be returned efficiently, the {@link android.os.health.HealthStats} 
+class uses a set of int keys to identify the data returned. The
+{@link android.os.health.UidHealthStats}, {@link android.os.health.PidHealthStats},
+{@link android.os.health.PackageHealthStats} , {@link android.os.health.ProcessHealthStats},
+and {@link android.os.health.ServiceHealthStats} classes provide those constants.
+Each {@link android.os.health.HealthStats} object will be associated with
+exactly one of those classes. The object returned from
+{@link android.os.health.SystemHealthManager#takeMyUidSnapshot() SystemHealth.takeMyUidSnapshot()}
+will be using the {@link android.os.health.UidHealthStats} keys, as it contains all
+of the data available for that uid.
+
+
+</body>
+</html>
+
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index fc440d2..c21c65a 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -2286,7 +2286,12 @@
 
     /**
      * Determines the encryption state of the volume.
-     * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible values.
+     * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
+     * values.
+     * Note that this has been replaced in most cases by the APIs in
+     * StorageManager (see isEncryptable and below)
+     * This is still useful to get the error state when encryption has failed
+     * and CryptKeeper needs to throw up a screen advising the user what to do
      */
     public int getEncryptionState() throws RemoteException;
 
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 97ee90d..720d3f7 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -34,6 +34,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
@@ -48,6 +49,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -100,6 +102,10 @@
 
     /** {@hide} */
     public static final int FLAG_FOR_WRITE = 1 << 8;
+    /** {@hide} */
+    public static final int FLAG_REAL_STATE = 1 << 9;
+    /** {@hide} */
+    public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
 
     private final Context mContext;
     private final ContentResolver mResolver;
@@ -332,7 +338,7 @@
             try {
                 mMountService.registerListener(delegate);
             } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
+                throw e.rethrowFromSystemServer();
             }
             mDelegates.add(delegate);
         }
@@ -353,7 +359,7 @@
                     try {
                         mMountService.unregisterListener(delegate);
                     } catch (RemoteException e) {
-                        throw e.rethrowAsRuntimeException();
+                        throw e.rethrowFromSystemServer();
                     }
                     i.remove();
                 }
@@ -434,10 +440,8 @@
         } catch (IOException e) {
             throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to mount OBB", e);
+            throw e.rethrowFromSystemServer();
         }
-
-        return false;
     }
 
     /**
@@ -469,10 +473,8 @@
             mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
             return true;
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to mount OBB", e);
+            throw e.rethrowFromSystemServer();
         }
-
-        return false;
     }
 
     /**
@@ -487,10 +489,8 @@
         try {
             return mMountService.isObbMounted(rawPath);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to check if OBB is mounted", e);
+            throw e.rethrowFromSystemServer();
         }
-
-        return false;
     }
 
     /**
@@ -508,10 +508,8 @@
         try {
             return mMountService.getMountedObbPath(rawPath);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to find mounted path for OBB", e);
+            throw e.rethrowFromSystemServer();
         }
-
-        return null;
     }
 
     /** {@hide} */
@@ -519,7 +517,7 @@
         try {
             return Arrays.asList(mMountService.getDisks());
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -605,7 +603,7 @@
         try {
             return Arrays.asList(mMountService.getVolumes(0));
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -620,7 +618,7 @@
             }
             return res;
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -629,7 +627,7 @@
         try {
             return Arrays.asList(mMountService.getVolumeRecords(0));
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -672,7 +670,7 @@
         try {
             mMountService.mount(volId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -681,7 +679,7 @@
         try {
             mMountService.unmount(volId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -690,7 +688,7 @@
         try {
             mMountService.format(volId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -699,7 +697,7 @@
         try {
             return mMountService.benchmark(volId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -708,7 +706,7 @@
         try {
             mMountService.partitionPublic(diskId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -717,7 +715,7 @@
         try {
             mMountService.partitionPrivate(diskId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -726,7 +724,7 @@
         try {
             mMountService.partitionMixed(diskId, ratio);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -759,7 +757,7 @@
         try {
             mMountService.setVolumeNickname(fsUuid, nickname);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -769,7 +767,7 @@
             mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
                     VolumeRecord.USER_FLAG_INITED);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -779,7 +777,7 @@
             mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
                     VolumeRecord.USER_FLAG_SNOOZED);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -788,7 +786,7 @@
         try {
             mMountService.forgetVolume(fsUuid);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -802,7 +800,7 @@
         try {
             return mMountService.getPrimaryStorageUuid();
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -816,7 +814,7 @@
         try {
             mMountService.setPrimaryStorageUuid(volumeUuid, callback);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -866,11 +864,31 @@
     }
 
     /**
-     * Gets the list of shared/external storage volumes available to the current user.
+     * Return the list of shared/external storage volumes available to the
+     * current user. This includes both the primary shared storage device and
+     * any attached external volumes including SD cards and USB drives.
      *
-     * <p>It always contains the primary storage volume, plus any additional external volume(s)
-     * available in the device, such as SD cards or attached USB drives.
+     * @see Environment#getExternalStorageDirectory()
+     * @see StorageVolume#createAccessIntent(String)
      */
+    public @NonNull List<StorageVolume> getStorageVolumes() {
+        final ArrayList<StorageVolume> res = new ArrayList<>();
+        Collections.addAll(res,
+                getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
+        return res;
+    }
+
+    /**
+     * Return the primary shared/external storage volume available to the
+     * current user. This volume is the same storage device returned by
+     * {@link Environment#getExternalStorageDirectory()} and
+     * {@link Context#getExternalFilesDir(String)}.
+     */
+    public @NonNull StorageVolume getPrimaryStorageVolume() {
+        return getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
+    }
+
+    /** @removed */
     public @NonNull StorageVolume[] getVolumeList() {
         return getVolumeList(mContext.getUserId(), 0);
     }
@@ -900,7 +918,7 @@
             }
             return mountService.getVolumeList(uid, packageName, flags);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -919,9 +937,7 @@
         return paths;
     }
 
-    /**
-     * Gets the primary shared/external storage volume available to the current user.
-     */
+    /** @removed */
     public @NonNull StorageVolume getPrimaryVolume() {
         return getPrimaryVolume(getVolumeList());
     }
@@ -984,7 +1000,7 @@
         try {
             mMountService.createUserKey(userId, serialNumber, ephemeral);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -993,7 +1009,7 @@
         try {
             mMountService.destroyUserKey(userId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1002,7 +1018,7 @@
         try {
             mMountService.unlockUserKey(userId, serialNumber, token, secret);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1011,7 +1027,7 @@
         try {
             mMountService.lockUserKey(userId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1020,7 +1036,7 @@
         try {
             mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1029,25 +1045,137 @@
         try {
             return mMountService.isUserKeyUnlocked(userId);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /** {@hide} */
-    public static boolean isFileBasedEncryptionEnabled() {
-        return isNativeFileBasedEncryptionEnabled() || isEmulatedFileBasedEncryptionEnabled();
+    /**
+     * Return if data stored at the given path will be encrypted while at rest.
+     * This can help apps avoid the overhead of double-encrypting data.
+     */
+    public boolean isEncrypted(File file) {
+        if (FileUtils.contains(Environment.getDataDirectory(), file)) {
+            return isEncrypted();
+        } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
+            return true;
+        }
+        // TODO: extend to support shared storage
+        return false;
+    }
+
+    /** {@hide}
+     * Is this device encryptable or already encrypted?
+     * @return true for encryptable or encrypted
+     *         false not encrypted and not encryptable
+     */
+    public static boolean isEncryptable() {
+        final String state = SystemProperties.get("ro.crypto.state", "unsupported");
+        return !"unsupported".equalsIgnoreCase(state);
+    }
+
+    /** {@hide}
+     * Is this device already encrypted?
+     * @return true for encrypted. (Implies isEncryptable() == true)
+     *         false not encrypted
+     */
+    public static boolean isEncrypted() {
+        final String state = SystemProperties.get("ro.crypto.state", "");
+        return "encrypted".equalsIgnoreCase(state);
+    }
+
+    /** {@hide}
+     * Is this device file encrypted?
+     * @return true for file encrypted. (Implies isEncrypted() == true)
+     *         false not encrypted or block encrypted
+     */
+    public static boolean isFileEncryptedNativeOnly() {
+        if (!isEncrypted()) {
+            return false;
+        }
+
+        final String status = SystemProperties.get("ro.crypto.type", "");
+        return "file".equalsIgnoreCase(status);
+    }
+
+    /** {@hide}
+     * Is this device block encrypted?
+     * @return true for block encrypted. (Implies isEncrypted() == true)
+     *         false not encrypted or file encrypted
+     */
+    public static boolean isBlockEncrypted() {
+        if (!isEncrypted()) {
+            return false;
+        }
+        final String status = SystemProperties.get("ro.crypto.type", "");
+        return "block".equalsIgnoreCase(status);
+    }
+
+    /** {@hide}
+     * Is this device block encrypted with credentials?
+     * @return true for crediential block encrypted.
+     *         (Implies isBlockEncrypted() == true)
+     *         false not encrypted, file encrypted or default block encrypted
+     */
+    public static boolean isNonDefaultBlockEncrypted() {
+        if (!isBlockEncrypted()) {
+            return false;
+        }
+
+        try {
+            IMountService mountService = IMountService.Stub.asInterface(
+                    ServiceManager.getService("mount"));
+            return mountService.getPasswordType() != CRYPT_TYPE_DEFAULT;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error getting encryption type");
+            return false;
+        }
+    }
+
+    /** {@hide}
+     * Is this device in the process of being block encrypted?
+     * @return true for encrypting.
+     *         false otherwise
+     * Whether device isEncrypted at this point is undefined
+     * Note that only system services and CryptKeeper will ever see this return
+     * true - no app will ever be launched in this state.
+     * Also note that this state will not change without a teardown of the
+     * framework, so no service needs to check for changes during their lifespan
+     */
+    public static boolean isBlockEncrypting() {
+        final String state = SystemProperties.get("vold.encrypt_progress", "");
+        return !"".equalsIgnoreCase(state);
+    }
+
+    /** {@hide}
+     * Is this device non default block encrypted and in the process of
+     * prompting for credentials?
+     * @return true for prompting for credentials.
+     *         (Implies isNonDefaultBlockEncrypted() == true)
+     *         false otherwise
+     * Note that only system services and CryptKeeper will ever see this return
+     * true - no app will ever be launched in this state.
+     * Also note that this state will not change without a teardown of the
+     * framework, so no service needs to check for changes during their lifespan
+     */
+    public static boolean inCryptKeeperBounce() {
+        final String status = SystemProperties.get("vold.decrypt");
+        return "trigger_restart_min_framework".equals(status);
     }
 
     /** {@hide} */
-    public static boolean isNativeFileBasedEncryptionEnabled() {
-        return "file".equals(SystemProperties.get("ro.crypto.type", "none"));
-    }
-
-    /** {@hide} */
-    public static boolean isEmulatedFileBasedEncryptionEnabled() {
+    public static boolean isFileEncryptedEmulatedOnly() {
         return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
     }
 
+    /** {@hide}
+     * Is this device running in a file encrypted mode, either native or emulated?
+     * @return true for file encrypted, false otherwise
+     */
+    public static boolean isFileEncryptedNativeOrEmulated() {
+        return isFileEncryptedNativeOnly()
+               || isFileEncryptedEmulatedOnly();
+    }
+
     /** {@hide} */
     public static File maybeTranslateEmulatedPathToInternal(File path) {
         final IMountService mountService = IMountService.Stub.asInterface(
@@ -1064,7 +1192,8 @@
                     }
                 }
             }
-        } catch (RemoteException ignored) {
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
         return path;
     }
@@ -1074,7 +1203,7 @@
         try {
             return mMountService.mountAppFuse(name);
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index d860c7d..7b0d2a4 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -16,7 +16,6 @@
 
 package android.os.storage;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
@@ -66,8 +65,8 @@
  * broad access to all files contained on a storage device.
  * </ul>
  *
- * <p>It can be obtained through {@link StorageManager#getVolumeList()} and
- * {@link StorageManager#getPrimaryVolume()} and also as an extra in some broadcasts
+ * <p>It can be obtained through {@link StorageManager#getStorageVolumes()} and
+ * {@link StorageManager#getPrimaryStorageVolume()} and also as an extra in some broadcasts
  * (see {@link #EXTRA_STORAGE_VOLUME}).
  *
  * <p>
@@ -76,7 +75,7 @@
  */
 // NOTE: This is a legacy specialization of VolumeInfo which describes the volume for a specific
 // user, but is now part of the public API.
-public class StorageVolume implements Parcelable {
+public final class StorageVolume implements Parcelable {
 
     private final String mId;
     private final int mStorageId;
@@ -306,8 +305,8 @@
     }
 
     /**
-     * Builds an intent to give access to a standard storage directory after obtaining the user's
-     * approval.
+     * Builds an intent to give access to a standard storage directory or entire volume after
+     * obtaining the user's approval.
      * <p>
      * When invoked, the system will ask the user to grant access to the requested directory (and
      * its descendants). The result of the request will be returned to the activity through the
@@ -316,22 +315,34 @@
      * To gain access to descendants (child, grandchild, etc) documents, use
      * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)}, or
      * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
-     *
-     * <b>If your application only needs to store internal data, consider using
+     * <p>
+     * If your application only needs to store internal data, consider using
      * {@link Context#getExternalFilesDirs(String) Context.getExternalFilesDirs},
-     * {@link Context#getExternalCacheDirs()}, or
-     * {@link Context#getExternalMediaDirs()}, which require no permissions to read or write.
+     * {@link Context#getExternalCacheDirs()}, or {@link Context#getExternalMediaDirs()}, which
+     * require no permissions to read or write.
+     * <p>
+     * Access to the entire volume is only available for non-primary volumes (for the primary
+     * volume, apps can use the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} and
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions) and should be used
+     * with caution, since users are more likely to deny access when asked for entire volume access
+     * rather than specific directories.
      *
-     * @param directoryName must be one of
-     * {@link Environment#DIRECTORY_MUSIC}, {@link Environment#DIRECTORY_PODCASTS},
-     * {@link Environment#DIRECTORY_RINGTONES}, {@link Environment#DIRECTORY_ALARMS},
-     * {@link Environment#DIRECTORY_NOTIFICATIONS}, {@link Environment#DIRECTORY_PICTURES},
-     * {@link Environment#DIRECTORY_MOVIES}, {@link Environment#DIRECTORY_DOWNLOADS},
-     * {@link Environment#DIRECTORY_DCIM}, or {@link Environment#DIRECTORY_DOCUMENTS}
-     *
+     * @param directoryName must be one of {@link Environment#DIRECTORY_MUSIC},
+     *            {@link Environment#DIRECTORY_PODCASTS}, {@link Environment#DIRECTORY_RINGTONES},
+     *            {@link Environment#DIRECTORY_ALARMS}, {@link Environment#DIRECTORY_NOTIFICATIONS},
+     *            {@link Environment#DIRECTORY_PICTURES}, {@link Environment#DIRECTORY_MOVIES},
+     *            {@link Environment#DIRECTORY_DOWNLOADS}, {@link Environment#DIRECTORY_DCIM}, or
+     *            {@link Environment#DIRECTORY_DOCUMENTS}, or {code null} to request access to the
+     *            entire volume.
+     * @return intent to request access, or {@code null} if the requested directory is invalid for
+     *         that volume.
      * @see DocumentsContract
      */
-    public Intent createAccessIntent(@NonNull String directoryName) {
+    public @Nullable Intent createAccessIntent(String directoryName) {
+        if ((isPrimary() && directoryName == null) ||
+                (directoryName != null && !Environment.isStandardDirectory(directoryName))) {
+            return null;
+        }
         final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY);
         intent.putExtra(EXTRA_STORAGE_VOLUME, this);
         intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName);
diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java
index ff37042..9467c22 100644
--- a/core/java/android/preference/EditTextPreference.java
+++ b/core/java/android/preference/EditTextPreference.java
@@ -49,6 +49,7 @@
     private EditText mEditText;
     
     private String mText;
+    private boolean mTextSet;
 
     public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
@@ -85,15 +86,16 @@
      * @param text The text to save
      */
     public void setText(String text) {
-        final boolean wasBlocking = shouldDisableDependents();
-        
-        mText = text;
-        
-        persistString(text);
-        
-        final boolean isBlocking = shouldDisableDependents(); 
-        if (isBlocking != wasBlocking) {
-            notifyDependencyChange(isBlocking);
+        // Always persist/notify the first time.
+        final boolean changed = !TextUtils.equals(mText, text);
+        if (changed || !mTextSet) {
+            mText = text;
+            mTextSet = true;
+            persistString(text);
+            if(changed) {
+                notifyDependencyChange(shouldDisableDependents());
+                notifyChanged();
+            }
         }
     }
     
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 5d64af5..b1cad05 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1184,10 +1184,9 @@
     
     /**
      * Called when the Preference hierarchy has been attached to the
-     * {@link PreferenceActivity} or {@link PreferenceFragment}. This can
-     * also be called when this Preference has been attached to a group
-     * that was already attached to the {@link PreferenceActivity} or
-     * {@link PreferenceFragment}.
+     * {@link PreferenceActivity}. This can also be called when this
+     * Preference has been attached to a group that was already attached
+     * to the {@link PreferenceActivity}.
      */
     protected void onAttachedToActivity() {
         // At this point, the hierarchy that this preference is in is connected
@@ -1195,16 +1194,6 @@
         registerDependency();
     }
 
-    /**
-     * Called when the Preference hierarchy has been detached from the
-     * {@link PreferenceActivity} or {@link PreferenceFragment}. This can
-     * also be called when this Preference has been removed from a group
-     * that was already attached to the {@link PreferenceActivity} or
-     * {@link PreferenceFragment}.
-     */
-    protected void onDetachedFromActivity() {
-    }
-
     private void registerDependency() {
         
         if (TextUtils.isEmpty(mDependencyKey)) return;
@@ -1494,11 +1483,9 @@
      * @return True if the Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
-     * @see #getPersistedString(Set)
-     * 
-     * @hide Pending API approval
+     * @see #getPersistedStringSet(Set)
      */
-    protected boolean persistStringSet(Set<String> values) {
+    public boolean persistStringSet(Set<String> values) {
         if (shouldPersist()) {
             // Shouldn't store null
             if (values.equals(getPersistedStringSet(null))) {
@@ -1527,10 +1514,8 @@
      * @return The value from the SharedPreferences or the default return
      *         value.
      * @see #persistStringSet(Set)
-     * 
-     * @hide Pending API approval
      */
-    protected Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
+    public Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
         if (!shouldPersist()) {
             return defaultReturnValue;
         }
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 13c3661..f17506b 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -186,11 +186,7 @@
     private boolean removePreferenceInt(Preference preference) {
         synchronized(this) {
             preference.onPrepareForRemoval();
-            boolean success = mPreferenceList.remove(preference);
-            if (mAttachedToActivity) {
-                preference.onDetachedFromActivity();
-            }
-            return success;
+            return mPreferenceList.remove(preference);
         }
     }
     
@@ -266,7 +262,7 @@
     protected boolean isOnSameScreenAsChildren() {
         return true;
     }
-
+    
     @Override
     protected void onAttachedToActivity() {
         super.onAttachedToActivity();
@@ -283,17 +279,11 @@
     }
 
     @Override
-    protected void onDetachedFromActivity() {
-        super.onDetachedFromActivity();
-
+    protected void onPrepareForRemoval() {
+        super.onPrepareForRemoval();
+        
         // We won't be attached to the activity anymore
         mAttachedToActivity = false;
-
-        // Dispatch to all contained preferences
-        final int preferenceCount = getPreferenceCount();
-        for (int i = 0; i < preferenceCount; i++) {
-            getPreference(i).onDetachedFromActivity();
-        }
     }
 
     @Override
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index ebb12fd..1a6b06f 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -113,8 +113,8 @@
     private int mSharedPreferencesMode;
 
     private static final int STORAGE_DEFAULT = 0;
-    private static final int STORAGE_DEVICE_ENCRYPTED = 1;
-    private static final int STORAGE_CREDENTIAL_ENCRYPTED = 2;
+    private static final int STORAGE_DEVICE_PROTECTED = 1;
+    private static final int STORAGE_CREDENTIAL_PROTECTED = 2;
 
     private int mStorage = STORAGE_DEFAULT;
 
@@ -360,35 +360,92 @@
 
     /**
      * Explicitly set the storage location used internally by this class to be
-     * device-encrypted storage.
+     * device-protected storage.
      * <p>
-     * Data stored in device-encrypted storage is typically encrypted with a key
-     * tied to the physical device, and it can be accessed when the device has
-     * booted successfully, both <em>before and after</em> the user has
-     * authenticated with their credentials (such as a lock pattern or PIN).
-     * Because device-encrypted data is available before user authentication,
-     * you should carefully consider what data you store using this mode.
+     * On devices with direct boot, data stored in this location is encrypted
+     * with a key tied to the physical device, and it can be accessed
+     * immediately after the device has booted successfully, both
+     * <em>before and after</em> the user has authenticated with their
+     * credentials (such as a lock pattern or PIN).
+     * <p>
+     * Because device-protected data is available without user authentication,
+     * you should carefully limit the data you store using this Context. For
+     * example, storing sensitive authentication tokens or passwords in the
+     * device-protected area is strongly discouraged.
      *
-     * @see Context#createDeviceEncryptedStorageContext()
+     * @see Context#createDeviceProtectedStorageContext()
      */
-    public void setStorageDeviceEncrypted() {
-        mStorage = STORAGE_DEVICE_ENCRYPTED;
+    public void setStorageDeviceProtected() {
+        mStorage = STORAGE_DEVICE_PROTECTED;
         mSharedPreferences = null;
     }
 
+    /** @removed */
+    @Deprecated
+    public void setStorageDeviceEncrypted() {
+        setStorageDeviceProtected();
+    }
+
     /**
      * Explicitly set the storage location used internally by this class to be
-     * credential-encrypted storage.
+     * credential-protected storage. This is the default storage area for apps
+     * unless {@code forceDeviceProtectedStorage} was requested.
+     * <p>
+     * On devices with direct boot, data stored in this location is encrypted
+     * with a key tied to user credentials, which can be accessed
+     * <em>only after</em> the user has entered their credentials (such as a
+     * lock pattern or PIN).
      *
-     * @see Context#createCredentialEncryptedStorageContext()
+     * @see Context#createCredentialProtectedStorageContext()
      * @hide
      */
     @SystemApi
-    public void setStorageCredentialEncrypted() {
-        mStorage = STORAGE_CREDENTIAL_ENCRYPTED;
+    public void setStorageCredentialProtected() {
+        mStorage = STORAGE_CREDENTIAL_PROTECTED;
         mSharedPreferences = null;
     }
 
+    /** @removed */
+    @Deprecated
+    public void setStorageCredentialEncrypted() {
+        setStorageCredentialProtected();
+    }
+
+    /**
+     * Indicates if the storage location used internally by this class is the
+     * default provided by the hosting {@link Context}.
+     *
+     * @see #setStorageDefault()
+     * @see #setStorageDeviceProtected()
+     */
+    public boolean isStorageDefault() {
+        return mStorage == STORAGE_DEFAULT;
+    }
+
+    /**
+     * Indicates if the storage location used internally by this class is backed
+     * by device-protected storage.
+     *
+     * @see #setStorageDefault()
+     * @see #setStorageDeviceProtected()
+     */
+    public boolean isStorageDeviceProtected() {
+        return mStorage == STORAGE_DEVICE_PROTECTED;
+    }
+
+    /**
+     * Indicates if the storage location used internally by this class is backed
+     * by credential-protected storage.
+     *
+     * @see #setStorageDefault()
+     * @see #setStorageDeviceProtected()
+     * @hide
+     */
+    @SystemApi
+    public boolean isStorageCredentialProtected() {
+        return mStorage == STORAGE_CREDENTIAL_PROTECTED;
+    }
+
     /**
      * Gets a SharedPreferences instance that preferences managed by this will
      * use.
@@ -400,11 +457,11 @@
         if (mSharedPreferences == null) {
             final Context storageContext;
             switch (mStorage) {
-                case STORAGE_DEVICE_ENCRYPTED:
-                    storageContext = mContext.createDeviceEncryptedStorageContext();
+                case STORAGE_DEVICE_PROTECTED:
+                    storageContext = mContext.createDeviceProtectedStorageContext();
                     break;
-                case STORAGE_CREDENTIAL_ENCRYPTED:
-                    storageContext = mContext.createCredentialEncryptedStorageContext();
+                case STORAGE_CREDENTIAL_PROTECTED:
+                    storageContext = mContext.createCredentialProtectedStorageContext();
                     break;
                 default:
                     storageContext = mContext;
@@ -462,9 +519,6 @@
      */
     boolean setPreferences(PreferenceScreen preferenceScreen) {
         if (preferenceScreen != mPreferenceScreen) {
-            if (mPreferenceScreen != null) {
-                mPreferenceScreen.onDetachedFromActivity();
-            }
             mPreferenceScreen = preferenceScreen;
             return true;
         }
@@ -773,11 +827,7 @@
      */
     void dispatchActivityDestroy() {
         List<OnActivityDestroyListener> list = null;
-
-        if (mPreferenceScreen != null) {
-            mPreferenceScreen.onDetachedFromActivity();
-            mPreferenceScreen = null;
-        }
+        
         synchronized (this) {
             if (mActivityDestroyListeners != null) {
                 list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 2445bc2..1ec00db 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -38,6 +38,8 @@
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
+import com.android.internal.annotations.GuardedBy;
+
 /**
  * Turns a {@link SeekBar} into a volume control.
  * @hide
@@ -67,6 +69,10 @@
     private Observer mVolumeObserver;
     private int mOriginalStreamVolume;
     private int mLastAudibleStreamVolume;
+    // When the old handler is destroyed and a new one is created, there could be a situation where
+    // this is accessed at the same time in different handlers. So, access to this field needs to be
+    // synchronized.
+    @GuardedBy("this")
     private Ringtone mRingtone;
     private int mLastProgress = -1;
     private boolean mMuted;
@@ -174,9 +180,11 @@
     }
 
     private void onInitSample() {
-        mRingtone = RingtoneManager.getRingtone(mContext, mDefaultUri);
-        if (mRingtone != null) {
-            mRingtone.setStreamType(mStreamType);
+        synchronized (this) {
+            mRingtone = RingtoneManager.getRingtone(mContext, mDefaultUri);
+            if (mRingtone != null) {
+                mRingtone.setStreamType(mStreamType);
+            }
         }
     }
 
@@ -192,16 +200,19 @@
             if (mCallback != null) {
                 mCallback.onSampleStarting(this);
             }
-            if (mRingtone != null) {
-                try {
-                    mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone
-                            .getAudioAttributes())
-                            .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
-                                    AudioAttributes.FLAG_BYPASS_MUTE)
-                            .build());
-                    mRingtone.play();
-                } catch (Throwable e) {
-                    Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);
+
+            synchronized (this) {
+                if (mRingtone != null) {
+                    try {
+                        mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone
+                                .getAudioAttributes())
+                                .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
+                                        AudioAttributes.FLAG_BYPASS_MUTE)
+                                .build());
+                        mRingtone.play();
+                    } catch (Throwable e) {
+                        Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);
+                    }
                 }
             }
         }
@@ -216,8 +227,10 @@
     }
 
     private void onStopSample() {
-        if (mRingtone != null) {
-            mRingtone.stop();
+        synchronized (this) {
+            if (mRingtone != null) {
+                mRingtone.stop();
+            }
         }
     }
 
@@ -274,7 +287,9 @@
     }
 
     public boolean isSamplePlaying() {
-        return mRingtone != null && mRingtone.isPlaying();
+        synchronized (this) {
+            return mRingtone != null && mRingtone.isPlaying();
+        }
     }
 
     public void startSample() {
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 9a80e37..d7c267b 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -16,15 +16,19 @@
 
 package android.print;
 
+import android.content.ComponentName;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.IPrintDocumentAdapter;
 import android.print.PrintJobId;
 import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintServicesChangeListener;
+import android.printservice.recommendation.IRecommendationsChangeListener;
 import android.print.PrinterId;
 import android.print.PrintJobInfo;
 import android.print.PrintAttributes;
+import android.printservice.recommendation.RecommendationInfo;
 import android.printservice.PrintServiceInfo;
 
 /**
@@ -45,8 +49,77 @@
     void removePrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
             int userId);
 
-    List<PrintServiceInfo> getInstalledPrintServices(int userId);
-    List<PrintServiceInfo> getEnabledPrintServices(int userId);
+    /**
+     * Listen for changes to the installed and enabled print services.
+     *
+     * @param listener the listener to add
+     * @param userId the id of the user listening
+     *
+     * @see android.print.PrintManager#getPrintServices(int, String)
+     */
+    void addPrintServicesChangeListener(in IPrintServicesChangeListener listener,
+            int userId);
+
+    /**
+     * Stop listening for changes to the installed and enabled print services.
+     *
+     * @param listener the listener to remove
+     * @param userId the id of the user requesting the removal
+     *
+     * @see android.print.PrintManager#getPrintServices(int, String)
+     */
+    void removePrintServicesChangeListener(in IPrintServicesChangeListener listener,
+            int userId);
+
+    /**
+     * Get the print services.
+     *
+     * @param selectionFlags flags selecting which services to get
+     * @param userId the id of the user requesting the services
+     *
+     * @return the list of selected print services.
+     */
+    List<PrintServiceInfo> getPrintServices(int selectionFlags, int userId);
+
+    /**
+     * Enable or disable a print service.
+     *
+     * @param service The service to enabled or disable
+     * @param isEnabled whether the service should be enabled or disabled
+     * @param userId the id of the user requesting the services
+     */
+    void setPrintServiceEnabled(in ComponentName service, boolean isEnabled, int userId);
+
+    /**
+     * Listen for changes to the print service recommendations.
+     *
+     * @param listener the listener to add
+     * @param userId the id of the user listening
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
+     */
+    void addPrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+            int userId);
+
+    /**
+     * Stop listening for changes to the print service recommendations.
+     *
+     * @param listener the listener to remove
+     * @param userId the id of the user requesting the removal
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
+     */
+    void removePrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+            int userId);
+
+    /**
+     * Get the print service recommendations.
+     *
+     * @param userId the id of the user requesting the recommendations
+     *
+     * @return the list of selected print services.
+     */
+    List<RecommendationInfo> getPrintServiceRecommendations(int userId);
 
     void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
     void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
diff --git a/core/java/android/print/IPrintServicesChangeListener.aidl b/core/java/android/print/IPrintServicesChangeListener.aidl
new file mode 100644
index 0000000..2a7ce89
--- /dev/null
+++ b/core/java/android/print/IPrintServicesChangeListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+/**
+ * Interface for observing print services changes.
+ *
+ * @hide
+ */
+oneway interface IPrintServicesChangeListener {
+    void onPrintServicesChanged();
+}
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index 469a4ea..63bf885 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -61,6 +61,15 @@
     void setStatus(in PrintJobId printJobId, in CharSequence status);
 
     /**
+     * Set the status of this print job
+     *
+     * @param printJobId The print job to update
+     * @param status The new status as a string resource
+     * @param appPackageName App package name the resource belongs to
+     */
+    void setStatusRes(in PrintJobId printJobId, int status, in CharSequence appPackageName);
+
+    /**
      * Handle that a custom icon for a printer was loaded.
      *
      * @param printerId the id of the printer the icon belongs to
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 57c7718..2941283 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -32,6 +32,9 @@
      */
     public static final PageRange ALL_PAGES = new PageRange(0, Integer.MAX_VALUE);
 
+    /** @hide */
+    public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES};
+
     private final int mStart;
     private final int mEnd;
 
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index e9c196d..721c94e 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -20,6 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources.NotFoundException;
@@ -31,6 +32,7 @@
 import android.util.Log;
 
 import com.android.internal.R;
+import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -49,7 +51,7 @@
     @IntDef(flag = true, value = {
             COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
     })
-    public @interface ColorMode {
+    @interface ColorMode {
     }
     /** Color mode: Monochrome color scheme, for example one color is used. */
     public static final int COLOR_MODE_MONOCHROME = 1 << 0;
@@ -64,7 +66,7 @@
     @IntDef(flag = true, value = {
             DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
     })
-    public @interface DuplexMode {
+    @interface DuplexMode {
     }
     /** Duplex mode: No duplexing. */
     public static final int DUPLEX_MODE_NONE = 1 << 0;
@@ -76,23 +78,29 @@
     private static final int VALID_DUPLEX_MODES =
             DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
 
-    private MediaSize mMediaSize;
-    private Resolution mResolution;
-    private Margins mMinMargins;
+    private @Nullable MediaSize mMediaSize;
+    private @Nullable Resolution mResolution;
+    private @Nullable Margins mMinMargins;
 
-    private int mColorMode;
-    private int mDuplexMode;
+    private @IntRange(from = 0) int mColorMode;
+    private @IntRange(from = 0) int mDuplexMode;
 
     PrintAttributes() {
         /* hide constructor */
     }
 
     private PrintAttributes(@NonNull Parcel parcel) {
-        mMediaSize = (parcel.readInt() ==  1) ? MediaSize.createFromParcel(parcel) : null;
-        mResolution = (parcel.readInt() ==  1) ? Resolution.createFromParcel(parcel) : null;
-        mMinMargins = (parcel.readInt() ==  1) ? Margins.createFromParcel(parcel) : null;
+        mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
+        mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
+        mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
         mColorMode = parcel.readInt();
+        if (mColorMode != 0) {
+            enforceValidColorMode(mColorMode);
+        }
         mDuplexMode = parcel.readInt();
+        if (mDuplexMode != 0) {
+            enforceValidDuplexMode(mDuplexMode);
+        }
     }
 
     /**
@@ -179,7 +187,7 @@
      * @see #COLOR_MODE_COLOR
      * @see #COLOR_MODE_MONOCHROME
      */
-    public @ColorMode int getColorMode() {
+    public @IntRange(from = 0) int getColorMode() {
         return mColorMode;
     }
 
@@ -214,13 +222,13 @@
     /**
      * Gets the duplex mode.
      *
-     * @return The duplex mode.
+     * @return The duplex mode or zero if not set.
      *
      * @see #DUPLEX_MODE_NONE
      * @see #DUPLEX_MODE_LONG_EDGE
      * @see #DUPLEX_MODE_SHORT_EDGE
      */
-    public @DuplexMode int getDuplexMode() {
+    public @IntRange(from = 0) int getDuplexMode() {
         return mDuplexMode;
     }
 
@@ -448,7 +456,7 @@
         private static final String LOG_TAG = "MediaSize";
 
         private static final Map<String, MediaSize> sIdToMediaSizeMap =
-                new ArrayMap<String, MediaSize>();
+                new ArrayMap<>();
 
         /**
          * Unknown media size in portrait mode.
@@ -781,15 +789,15 @@
                 new MediaSize("JPN_YOU4", "android",
                         R.string.mediasize_japanese_you4, 4134, 9252);
 
-        private final String mId;
+        private final @NonNull String mId;
         /**@hide */
-        public final String mLabel;
+        public final @NonNull String mLabel;
         /**@hide */
-        public final String mPackageName;
+        public final @Nullable String mPackageName;
         /**@hide */
-        public final int mLabelResId;
-        private final int mWidthMils;
-        private final int mHeightMils;
+        public final @StringRes int mLabelResId;
+        private final @IntRange(from = 1) int mWidthMils;
+        private final @IntRange(from = 1) int mHeightMils;
 
         /**
          * Creates a new instance.
@@ -808,29 +816,7 @@
          */
         public MediaSize(String id, String packageName, int labelResId,
                 int widthMils, int heightMils) {
-            if (TextUtils.isEmpty(id)) {
-                throw new IllegalArgumentException("id cannot be empty.");
-            }
-            if (TextUtils.isEmpty(packageName)) {
-                throw new IllegalArgumentException("packageName cannot be empty.");
-            }
-            if (labelResId <= 0) {
-                throw new IllegalArgumentException("labelResId must be greater than zero.");
-            }
-            if (widthMils <= 0) {
-                throw new IllegalArgumentException("widthMils "
-                        + "cannot be less than or equal to zero.");
-            }
-            if (heightMils <= 0) {
-                throw new IllegalArgumentException("heightMils "
-                       + "cannot be less than or euqual to zero.");
-            }
-            mPackageName = packageName;
-            mId = id;
-            mLabelResId = labelResId;
-            mWidthMils = widthMils;
-            mHeightMils = heightMils;
-            mLabel = null;
+            this(id, null, packageName, widthMils, heightMils, labelResId);
 
             // Build this mapping only for predefined media sizes.
             sIdToMediaSizeMap.put(mId, this);
@@ -851,26 +837,7 @@
          */
         public MediaSize(@NonNull String id, @NonNull String label,
                 @IntRange(from = 1) int widthMils, @IntRange(from = 1) int heightMils) {
-            if (TextUtils.isEmpty(id)) {
-                throw new IllegalArgumentException("id cannot be empty.");
-            }
-            if (TextUtils.isEmpty(label)) {
-                throw new IllegalArgumentException("label cannot be empty.");
-            }
-            if (widthMils <= 0) {
-                throw new IllegalArgumentException("widthMils "
-                        + "cannot be less than or equal to zero.");
-            }
-            if (heightMils <= 0) {
-                throw new IllegalArgumentException("heightMils "
-                       + "cannot be less than or euqual to zero.");
-            }
-            mId = id;
-            mLabel = label;
-            mWidthMils = widthMils;
-            mHeightMils = heightMils;
-            mLabelResId = 0;
-            mPackageName = null;
+            this(id, label, null, widthMils, heightMils, 0);
         }
 
         /**
@@ -890,15 +857,37 @@
             return definedMediaSizes;
         }
 
-        /** @hide */
-        public MediaSize(String id, String label, String packageName,
-                int widthMils, int heightMils, int labelResId) {
+        /**
+         * Creates a new instance.
+         *
+         * @param id The unique media size id. It is unique amongst other media sizes
+         *        supported by the printer.
+         * @param label The <strong>localized</strong> human readable label.
+         * @param packageName The name of the creating package.
+         * @param widthMils The width in mils (thousands of an inch).
+         * @param heightMils The height in mils (thousands of an inch).
+         * @param labelResId The resource if of a human readable label.
+         *
+         * @throws IllegalArgumentException If the id is empty or the label is unset
+         * or the widthMils is less than or equal to zero or the heightMils is less
+         * than or equal to zero.
+         *
+         * @hide
+         */
+        public MediaSize(String id, String label, String packageName, int widthMils, int heightMils,
+                int labelResId) {
             mPackageName = packageName;
-            mId = id;
+            mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty.");
             mLabelResId = labelResId;
-            mWidthMils = widthMils;
-            mHeightMils = heightMils;
+            mWidthMils = Preconditions.checkArgumentPositive(widthMils, "widthMils cannot be " +
+                    "less than or equal to zero.");
+            mHeightMils = Preconditions.checkArgumentPositive(heightMils, "heightMils cannot be " +
+                    "less than or equal to zero.");
             mLabel = label;
+
+            // The label has to be either a string ot a StringRes
+            Preconditions.checkArgument(!TextUtils.isEmpty(label) !=
+                    (!TextUtils.isEmpty(packageName) && labelResId != 0), "label cannot be empty.");
         }
 
         /**
@@ -926,10 +915,7 @@
                 try {
                     return packageManager.getResourcesForApplication(
                             mPackageName).getString(mLabelResId);
-                } catch (NotFoundException nfe) {
-                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
-                            + " from package " + mPackageName);
-                } catch (NameNotFoundException nnfee) {
+                } catch (NotFoundException | NameNotFoundException e) {
                     Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
                             + " from package " + mPackageName);
                 }
@@ -1084,10 +1070,10 @@
      * the one with 300 DPI resolution.
      */
     public static final class Resolution {
-        private final String mId;
-        private final String mLabel;
-        private final int mHorizontalDpi;
-        private final int mVerticalDpi;
+        private final @NonNull String mId;
+        private final @NonNull String mLabel;
+        private final @IntRange(from = 1) int mHorizontalDpi;
+        private final @IntRange(from = 1) int mVerticalDpi;
 
         /**
          * Creates a new instance.
@@ -1244,8 +1230,7 @@
          * @param rightMils The right margin in mils (thousands of an inch).
          * @param bottomMils The bottom margin in mils (thousands of an inch).
          */
-        public Margins(@IntRange(from = 0) int leftMils, @IntRange(from = 0) int topMils,
-                @IntRange(from = 0) int rightMils, @IntRange(from = 0) int bottomMils) {
+        public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
             mTopMils = topMils;
             mLeftMils = leftMils;
             mRightMils = rightMils;
@@ -1257,7 +1242,7 @@
          *
          * @return The left margin.
          */
-        public @IntRange(from = 0) int getLeftMils() {
+        public int getLeftMils() {
             return mLeftMils;
         }
 
@@ -1266,7 +1251,7 @@
          *
          * @return The top margin.
          */
-        public @IntRange(from = 0) int getTopMils() {
+        public int getTopMils() {
             return mTopMils;
         }
 
@@ -1275,7 +1260,7 @@
          *
          * @return The right margin.
          */
-        public @IntRange(from = 0) int getRightMils() {
+        public int getRightMils() {
             return mRightMils;
         }
 
@@ -1284,7 +1269,7 @@
          *
          * @return The bottom margin.
          */
-        public @IntRange(from = 0) int getBottomMils() {
+        public int getBottomMils() {
             return mBottomMils;
         }
 
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index db3b6f4..bec6f29 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -22,6 +22,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -114,8 +115,8 @@
      */
     public static final int CONTENT_TYPE_PHOTO = 1;
 
-    private String mName;
-    private int mPageCount;
+    private @NonNull String mName;
+    private @IntRange(from = -1) int mPageCount;
     private int mContentType;
     private long mDataSize;
 
@@ -144,10 +145,11 @@
      * @param parcel Data from which to initialize.
      */
     private PrintDocumentInfo(Parcel parcel) {
-        mName = parcel.readString();
+        mName = Preconditions.checkStringNotEmpty(parcel.readString());
         mPageCount = parcel.readInt();
+        Preconditions.checkArgument(mPageCount == PAGE_COUNT_UNKNOWN || mPageCount > 0);
         mContentType = parcel.readInt();
-        mDataSize = parcel.readLong();
+        mDataSize = Preconditions.checkArgumentNonnegative(parcel.readLong());
     }
 
     /**
@@ -180,7 +182,7 @@
      * @see #CONTENT_TYPE_DOCUMENT
      * @see #CONTENT_TYPE_PHOTO
      */
-    public @ContentType int getContentType() {
+    public int getContentType() {
         return mContentType;
     }
 
@@ -262,13 +264,13 @@
         builder.append("PrintDocumentInfo{");
         builder.append("name=").append(mName);
         builder.append(", pageCount=").append(mPageCount);
-        builder.append(", contentType=").append(contentTyepToString(mContentType));
+        builder.append(", contentType=").append(contentTypeToString(mContentType));
         builder.append(", dataSize=").append(mDataSize);
         builder.append("}");
         return builder.toString();
     }
 
-    private String contentTyepToString(int contentType) {
+    private String contentTypeToString(int contentType) {
         switch (contentType) {
             case CONTENT_TYPE_DOCUMENT: {
                 return "CONTENT_TYPE_DOCUMENT";
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 7e3a72f..f134943 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -21,7 +21,10 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.annotation.TestApi;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -181,7 +184,11 @@
     private float mProgress;
 
     /** A short string describing the status of this job. */
-    private CharSequence mStatus;
+    private @Nullable CharSequence mStatus;
+
+    /** A string resource describing the status of this job. */
+    private @StringRes int mStatusRes;
+    private @Nullable CharSequence mStatusResAppPackageName;
 
     /** Advanced printer specific options. */
     private Bundle mAdvancedOptions;
@@ -210,6 +217,8 @@
         mDocumentInfo = other.mDocumentInfo;
         mProgress = other.mProgress;
         mStatus = other.mStatus;
+        mStatusRes = other.mStatusRes;
+        mStatusResAppPackageName = other.mStatusResAppPackageName;
         mCanceling = other.mCanceling;
         mAdvancedOptions = other.mAdvancedOptions;
     }
@@ -235,8 +244,14 @@
         mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null);
         mProgress = parcel.readFloat();
         mStatus = parcel.readCharSequence();
+        mStatusRes = parcel.readInt();
+        mStatusResAppPackageName = parcel.readCharSequence();
         mCanceling = (parcel.readInt() == 1);
         mAdvancedOptions = parcel.readBundle();
+
+        if (mAdvancedOptions != null) {
+            Preconditions.checkArgument(!mAdvancedOptions.containsKey(null));
+        }
     }
 
     /**
@@ -370,10 +385,28 @@
      * @hide
      */
     public void setStatus(@Nullable CharSequence status) {
+        mStatusRes = 0;
+        mStatusResAppPackageName = null;
+
         mStatus = status;
     }
 
     /**
+     * Sets the status of the print job.
+     *
+     * @param status The new status as a string resource
+     * @param appPackageName App package name the resource belongs to
+     *
+     * @hide
+     */
+    public void setStatus(@StringRes int status, @NonNull CharSequence appPackageName) {
+        mStatus = null;
+
+        mStatusRes = status;
+        mStatusResAppPackageName = appPackageName;
+    }
+
+    /**
      * Sets the owning application id.
      *
      * @return The owning app id.
@@ -633,6 +666,8 @@
         parcel.writeParcelable(mDocumentInfo, 0);
         parcel.writeFloat(mProgress);
         parcel.writeCharSequence(mStatus);
+        parcel.writeInt(mStatusRes);
+        parcel.writeCharSequence(mStatusResAppPackageName);
         parcel.writeInt(mCanceling ? 1 : 0);
         parcel.writeBundle(mAdvancedOptions);
     }
@@ -659,6 +694,9 @@
         builder.append(", progress: " + mProgress);
         builder.append(", status: " + (mStatus != null
                 ? mStatus.toString() : null));
+        builder.append(", statusRes: " + mStatusRes);
+        builder.append(", statusResAppPackageName: " + (mStatusResAppPackageName != null
+                ? mStatusResAppPackageName.toString() : null));
         builder.append("}");
         return builder.toString();
     }
@@ -707,12 +745,23 @@
     /**
      * Get the status of this job.
      *
+     * @param pm Package manager used to resolve the string
+     *
      * @return the status of this job or null if not set
      * @hide
      */
     @TestApi
-    public @Nullable CharSequence getStatus() {
-        return mStatus;
+    public @Nullable CharSequence getStatus(@NonNull PackageManager pm) {
+        if (mStatusRes == 0) {
+            return mStatus;
+        } else {
+            try {
+                return pm.getResourcesForApplication(mStatusResAppPackageName.toString())
+                        .getString(mStatusRes);
+            } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
+                return null;
+            }
+        }
     }
 
     /**
@@ -789,6 +838,8 @@
          * @param value The option value.
          */
         public void putAdvancedOption(@NonNull String key, @Nullable String value) {
+            Preconditions.checkNotNull(key, "key cannot be null");
+
             if (mPrototype.mAdvancedOptions == null) {
                 mPrototype.mAdvancedOptions = new Bundle();
             }
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 58f260c..71f0bd6 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
@@ -35,12 +36,15 @@
 import android.print.PrintDocumentAdapter.LayoutResultCallback;
 import android.print.PrintDocumentAdapter.WriteResultCallback;
 import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
+import android.printservice.recommendation.RecommendationInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.internal.os.SomeArgs;
 
+import com.android.internal.util.Preconditions;
 import libcore.io.IoUtils;
 
 import java.lang.ref.WeakReference;
@@ -111,6 +115,39 @@
     private static final boolean DEBUG = false;
 
     private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
+    private static final int MSG_NOTIFY_PRINT_SERVICES_CHANGED = 2;
+    private static final int MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED = 3;
+
+    /**
+     * Package name of print spooler.
+     *
+     * @hide
+     */
+    public static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
+
+    /**
+     * Select enabled services.
+     * </p>
+     * @see #getPrintServices
+     * @hide
+     */
+    public static final int ENABLED_SERVICES = 1 << 0;
+
+    /**
+     * Select disabled services.
+     * </p>
+     * @see #getPrintServices
+     * @hide
+     */
+    public static final int DISABLED_SERVICES = 1 << 1;
+
+    /**
+     * Select all services.
+     * </p>
+     * @see #getPrintServices
+     * @hide
+     */
+    public static final int ALL_SERVICES = ENABLED_SERVICES | DISABLED_SERVICES;
 
     /**
      * The action for launching the print dialog activity.
@@ -165,7 +202,13 @@
 
     private final Handler mHandler;
 
-    private Map<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper> mPrintJobStateChangeListeners;
+    private Map<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper>
+            mPrintJobStateChangeListeners;
+    private Map<PrintServicesChangeListener, PrintServicesChangeListenerWrapper>
+            mPrintServicesChangeListeners;
+    private Map<PrintServiceRecommendationsChangeListener,
+            PrintServiceRecommendationsChangeListenerWrapper>
+            mPrintServiceRecommendationsChangeListeners;
 
     /** @hide */
     public interface PrintJobStateChangeListener {
@@ -178,6 +221,24 @@
         public void onPrintJobStateChanged(PrintJobId printJobId);
     }
 
+    /** @hide */
+    public interface PrintServicesChangeListener {
+
+        /**
+         * Callback notifying that the print services changed.
+         */
+        public void onPrintServicesChanged();
+    }
+
+    /** @hide */
+    public interface PrintServiceRecommendationsChangeListener {
+
+        /**
+         * Callback notifying that the print service recommendations changed.
+         */
+        void onPrintServiceRecommendationsChanged();
+    }
+
     /**
      * Creates a new instance.
      *
@@ -207,6 +268,22 @@
                         }
                         args.recycle();
                     } break;
+                    case MSG_NOTIFY_PRINT_SERVICES_CHANGED: {
+                        PrintServicesChangeListenerWrapper wrapper =
+                                (PrintServicesChangeListenerWrapper) message.obj;
+                        PrintServicesChangeListener listener = wrapper.getListener();
+                        if (listener != null) {
+                            listener.onPrintServicesChanged();
+                        }
+                    } break;
+                    case MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED: {
+                        PrintServiceRecommendationsChangeListenerWrapper wrapper =
+                                (PrintServiceRecommendationsChangeListenerWrapper) message.obj;
+                        PrintServiceRecommendationsChangeListener listener = wrapper.getListener();
+                        if (listener != null) {
+                            listener.onPrintServiceRecommendationsChanged();
+                        }
+                    } break;
                 }
             }
         };
@@ -232,9 +309,8 @@
         try {
             return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error getting a print job info:" + printJobId, re);
+            throw re.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -258,7 +334,7 @@
             mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId);
             mPrintJobStateChangeListeners.put(listener, wrappedListener);
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error adding print job state change listener", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -288,7 +364,7 @@
         try {
             mService.removePrintJobStateChangeListener(wrappedListener, mUserId);
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error removing print job state change listener", re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -311,7 +387,7 @@
                 return new PrintJob(printJob, this);
             }
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error getting print job", re);
+            throw re.rethrowFromSystemServer();
         }
         return null;
     }
@@ -334,9 +410,8 @@
         try {
             return mService.getCustomPrinterIcon(printerId, mUserId);
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error getting custom printer icon", re);
+            throw re.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -362,9 +437,8 @@
             }
             return printJobs;
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error getting print jobs", re);
+            throw re.rethrowFromSystemServer();
         }
-        return Collections.emptyList();
     }
 
     void cancelPrintJob(PrintJobId printJobId) {
@@ -375,7 +449,7 @@
         try {
             mService.cancelPrintJob(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error canceling a print job: " + printJobId, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -387,7 +461,7 @@
         try {
             mService.restartPrintJob(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error restarting a print job: " + printJobId, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -475,51 +549,181 @@
                 }
             }
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error creating a print job", re);
+            throw re.rethrowFromSystemServer();
         }
         return null;
     }
 
     /**
-     * Gets the list of enabled print services.
+     * Listen for changes to the installed and enabled print services.
      *
-     * @return The enabled service list or an empty list.
-     * @hide
+     * @param listener the listener to add
+     *
+     * @see android.print.PrintManager#getPrintServices
      */
-    public List<PrintServiceInfo> getEnabledPrintServices() {
+    void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
-            return Collections.emptyList();
+            return;
         }
+        if (mPrintServicesChangeListeners == null) {
+            mPrintServicesChangeListeners = new ArrayMap<>();
+        }
+        PrintServicesChangeListenerWrapper wrappedListener =
+                new PrintServicesChangeListenerWrapper(listener, mHandler);
         try {
-            List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
-            if (enabledServices != null) {
-                return enabledServices;
+            mService.addPrintServicesChangeListener(wrappedListener, mUserId);
+            mPrintServicesChangeListeners.put(listener, wrappedListener);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stop listening for changes to the installed and enabled print services.
+     *
+     * @param listener the listener to remove
+     *
+     * @see android.print.PrintManager#getPrintServices
+     */
+    void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
+        if (mPrintServicesChangeListeners == null) {
+            return;
+        }
+        PrintServicesChangeListenerWrapper wrappedListener =
+                mPrintServicesChangeListeners.remove(listener);
+        if (wrappedListener == null) {
+            return;
+        }
+        if (mPrintServicesChangeListeners.isEmpty()) {
+            mPrintServicesChangeListeners = null;
+        }
+        wrappedListener.destroy();
+        try {
+            mService.removePrintServicesChangeListener(wrappedListener, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error removing print services change listener", re);
+        }
+    }
+
+    /**
+     * Gets the list of print services, but does not register for updates. The user has to register
+     * for updates by itself, or use {@link PrintServicesLoader}.
+     *
+     * @param selectionFlags flags selecting which services to get. Either
+     *                       {@link #ENABLED_SERVICES},{@link #DISABLED_SERVICES}, or both.
+     *
+     * @return The print service list or an empty list.
+     *
+     * @see #addPrintServicesChangeListener(PrintServicesChangeListener)
+     * @see #removePrintServicesChangeListener(PrintServicesChangeListener)
+     *
+     * @hide
+     */
+    public @NonNull List<PrintServiceInfo> getPrintServices(int selectionFlags) {
+        Preconditions.checkFlagsArgument(selectionFlags, ALL_SERVICES);
+
+        try {
+            List<PrintServiceInfo> services = mService.getPrintServices(selectionFlags, mUserId);
+            if (services != null) {
+                return services;
             }
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error getting the enabled print services", re);
+            throw re.rethrowFromSystemServer();
         }
         return Collections.emptyList();
     }
 
     /**
-     * Gets the list of installed print services.
+     * Listen for changes to the print service recommendations.
      *
-     * @return The installed service list or an empty list.
-     * @hide
+     * @param listener the listener to add
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
      */
-    public List<PrintServiceInfo> getInstalledPrintServices() {
+    void addPrintServiceRecommendationsChangeListener(
+            @NonNull PrintServiceRecommendationsChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
-            return Collections.emptyList();
+            return;
         }
+        if (mPrintServiceRecommendationsChangeListeners == null) {
+            mPrintServiceRecommendationsChangeListeners = new ArrayMap<>();
+        }
+        PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+                new PrintServiceRecommendationsChangeListenerWrapper(listener, mHandler);
         try {
-            List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId);
-            if (installedServices != null) {
-                return installedServices;
+            mService.addPrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+            mPrintServiceRecommendationsChangeListeners.put(listener, wrappedListener);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stop listening for changes to the print service recommendations.
+     *
+     * @param listener the listener to remove
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
+     */
+    void removePrintServiceRecommendationsChangeListener(
+            @NonNull PrintServiceRecommendationsChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
+        if (mPrintServiceRecommendationsChangeListeners == null) {
+            return;
+        }
+        PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+                mPrintServiceRecommendationsChangeListeners.remove(listener);
+        if (wrappedListener == null) {
+            return;
+        }
+        if (mPrintServiceRecommendationsChangeListeners.isEmpty()) {
+            mPrintServiceRecommendationsChangeListeners = null;
+        }
+        wrappedListener.destroy();
+        try {
+            mService.removePrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets the list of print service recommendations, but does not register for updates. The user
+     * has to register for updates by itself, or use {@link PrintServiceRecommendationsLoader}.
+     *
+     * @return The print service recommendations list or an empty list.
+     *
+     * @see #addPrintServiceRecommendationsChangeListener
+     * @see #removePrintServiceRecommendationsChangeListener
+     *
+     * @hide
+     */
+    public @NonNull List<RecommendationInfo> getPrintServiceRecommendations() {
+        try {
+            List<RecommendationInfo> recommendations =
+                    mService.getPrintServiceRecommendations(mUserId);
+            if (recommendations != null) {
+                return recommendations;
             }
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error getting the installed print services", re);
+            throw re.rethrowFromSystemServer();
         }
         return Collections.emptyList();
     }
@@ -536,6 +740,26 @@
     }
 
     /**
+     * Enable or disable a print service.
+     *
+     * @param service The service to enabled or disable
+     * @param isEnabled whether the service should be enabled or disabled
+     *
+     * @hide
+     */
+    public void setPrintServiceEnabled(@NonNull ComponentName service, boolean isEnabled) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
+        try {
+            mService.setPrintServiceEnabled(service, isEnabled, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error enabling or disabling " + service, re);
+        }
+    }
+
+    /**
      * @hide
      */
     public static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
@@ -1099,4 +1323,69 @@
             return mWeakListener.get();
         }
     }
+
+    /**
+     * @hide
+     */
+    public static final class PrintServicesChangeListenerWrapper extends
+            IPrintServicesChangeListener.Stub {
+        private final WeakReference<PrintServicesChangeListener> mWeakListener;
+        private final WeakReference<Handler> mWeakHandler;
+
+        public PrintServicesChangeListenerWrapper(PrintServicesChangeListener listener,
+                Handler handler) {
+            mWeakListener = new WeakReference<>(listener);
+            mWeakHandler = new WeakReference<>(handler);
+        }
+
+        @Override
+        public void onPrintServicesChanged() {
+            Handler handler = mWeakHandler.get();
+            PrintServicesChangeListener listener = mWeakListener.get();
+            if (handler != null && listener != null) {
+                handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICES_CHANGED, this).sendToTarget();
+            }
+        }
+
+        public void destroy() {
+            mWeakListener.clear();
+        }
+
+        public PrintServicesChangeListener getListener() {
+            return mWeakListener.get();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static final class PrintServiceRecommendationsChangeListenerWrapper extends
+            IRecommendationsChangeListener.Stub {
+        private final WeakReference<PrintServiceRecommendationsChangeListener> mWeakListener;
+        private final WeakReference<Handler> mWeakHandler;
+
+        public PrintServiceRecommendationsChangeListenerWrapper(
+                PrintServiceRecommendationsChangeListener listener, Handler handler) {
+            mWeakListener = new WeakReference<>(listener);
+            mWeakHandler = new WeakReference<>(handler);
+        }
+
+        @Override
+        public void onRecommendationsChanged() {
+            Handler handler = mWeakHandler.get();
+            PrintServiceRecommendationsChangeListener listener = mWeakListener.get();
+            if (handler != null && listener != null) {
+                handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED,
+                        this).sendToTarget();
+            }
+        }
+
+        public void destroy() {
+            mWeakListener.clear();
+        }
+
+        public PrintServiceRecommendationsChangeListener getListener() {
+            return mWeakListener.get();
+        }
+    }
 }
diff --git a/core/java/android/print/PrintServiceRecommendationsLoader.java b/core/java/android/print/PrintServiceRecommendationsLoader.java
new file mode 100644
index 0000000..bb5d065
--- /dev/null
+++ b/core/java/android/print/PrintServiceRecommendationsLoader.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Handler;
+import android.os.Message;
+import android.printservice.recommendation.RecommendationInfo;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Loader for the list of print service recommendations.
+ *
+ * @hide
+ */
+public class PrintServiceRecommendationsLoader extends Loader<List<RecommendationInfo>> {
+    /** The print manager to be used by this object */
+    private final @NonNull PrintManager mPrintManager;
+
+    /** Handler to sequentialize the delivery of the results to the main thread */
+    private final Handler mHandler;
+
+    /** Listens for updates to the data from the platform */
+    private PrintManager.PrintServiceRecommendationsChangeListener mListener;
+
+    /**
+     * Create a new PrintServicesLoader.
+     *
+     * @param printManager The print manager supplying the data
+     * @param context      Context of the using object
+     */
+    public PrintServiceRecommendationsLoader(@NonNull PrintManager printManager,
+            @NonNull Context context) {
+        super(Preconditions.checkNotNull(context));
+        mHandler = new MyHandler();
+        mPrintManager = Preconditions.checkNotNull(printManager);
+    }
+
+    @Override
+    protected void onForceLoad() {
+        queueNewResult();
+    }
+
+    /**
+     * Read the print service recommendations and queue it to be delivered on the main thread.
+     */
+    private void queueNewResult() {
+        Message m = mHandler.obtainMessage(0);
+        m.obj = mPrintManager.getPrintServiceRecommendations();
+        mHandler.sendMessage(m);
+    }
+
+    @Override
+    protected void onStartLoading() {
+        mListener = new PrintManager.PrintServiceRecommendationsChangeListener() {
+            @Override
+            public void onPrintServiceRecommendationsChanged() {
+                queueNewResult();
+            }
+        };
+
+        mPrintManager.addPrintServiceRecommendationsChangeListener(mListener);
+
+        // Immediately deliver a result
+        deliverResult(mPrintManager.getPrintServiceRecommendations());
+    }
+
+    @Override
+    protected void onStopLoading() {
+        if (mListener != null) {
+            mPrintManager.removePrintServiceRecommendationsChangeListener(mListener);
+            mListener = null;
+        }
+
+        if (mHandler != null) {
+            mHandler.removeMessages(0);
+        }
+    }
+
+    @Override
+    protected void onReset() {
+        onStopLoading();
+    }
+
+    /**
+     * Handler to sequentialize all the updates to the main thread.
+     */
+    private class MyHandler extends Handler {
+        /**
+         * Create a new handler on the main thread.
+         */
+        public MyHandler() {
+            super(getContext().getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (isStarted()) {
+                deliverResult((List<RecommendationInfo>) msg.obj);
+            }
+        }
+    }
+}
diff --git a/core/java/android/print/PrintServicesLoader.java b/core/java/android/print/PrintServicesLoader.java
new file mode 100644
index 0000000..60d7d66
--- /dev/null
+++ b/core/java/android/print/PrintServicesLoader.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Handler;
+import android.os.Message;
+import android.printservice.PrintServiceInfo;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Loader for the list of print services. Can be parametrized to select a subset.
+ *
+ * @hide
+ */
+public class PrintServicesLoader extends Loader<List<PrintServiceInfo>> {
+    /** What type of services to load. */
+    private final int mSelectionFlags;
+
+    /** The print manager to be used by this object */
+    private final @NonNull PrintManager mPrintManager;
+
+    /** Handler to sequentialize the delivery of the results to the main thread */
+    private Handler mHandler;
+
+    /** Listens for updates to the data from the platform */
+    private PrintManager.PrintServicesChangeListener mListener;
+
+    /**
+     * Create a new PrintServicesLoader.
+     *
+     * @param printManager   The print manager supplying the data
+     * @param context        Context of the using object
+     * @param selectionFlags What type of services to load.
+     */
+    public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
+            int selectionFlags) {
+        super(Preconditions.checkNotNull(context));
+        mPrintManager = Preconditions.checkNotNull(printManager);
+        mSelectionFlags = Preconditions.checkFlagsArgument(selectionFlags,
+                PrintManager.ALL_SERVICES);
+    }
+
+    @Override
+    protected void onForceLoad() {
+        queueNewResult();
+    }
+
+    /**
+     * Read the print services and queue it to be delivered on the main thread.
+     */
+    private void queueNewResult() {
+        Message m = mHandler.obtainMessage(0);
+        m.obj = mPrintManager.getPrintServices(mSelectionFlags);
+        mHandler.sendMessage(m);
+    }
+
+    @Override
+    protected void onStartLoading() {
+        mHandler = new MyHandler();
+        mListener = new PrintManager.PrintServicesChangeListener() {
+            @Override public void onPrintServicesChanged() {
+                queueNewResult();
+            }
+        };
+
+        mPrintManager.addPrintServicesChangeListener(mListener);
+
+        // Immediately deliver a result
+        deliverResult(mPrintManager.getPrintServices(mSelectionFlags));
+    }
+
+    @Override
+    protected void onStopLoading() {
+        if (mListener != null) {
+            mPrintManager.removePrintServicesChangeListener(mListener);
+            mListener = null;
+        }
+
+        if (mHandler != null) {
+            mHandler.removeMessages(0);
+            mHandler = null;
+        }
+    }
+
+    @Override
+    protected void onReset() {
+        onStopLoading();
+    }
+
+    /**
+     * Handler to sequentialize all the updates to the main thread.
+     */
+    private class MyHandler extends Handler {
+        /**
+         * Create a new handler on the main thread.
+         */
+        public MyHandler() {
+            super(getContext().getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+
+            if (isStarted()) {
+                deliverResult((List<PrintServiceInfo>) msg.obj);
+            }
+        }
+    }
+}
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index d13879b..01c23f6 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -24,11 +24,13 @@
 import android.print.PrintAttributes.Margins;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Resolution;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.IntConsumer;
 
 /**
  * This class represents the capabilities of a printer. Instances
@@ -55,9 +57,9 @@
 
     private static final Margins DEFAULT_MARGINS = new Margins(0,  0,  0,  0);
 
-    private Margins mMinMargins = DEFAULT_MARGINS;
-    private List<MediaSize> mMediaSizes;
-    private List<Resolution> mResolutions;
+    private @NonNull Margins mMinMargins = DEFAULT_MARGINS;
+    private @NonNull List<MediaSize> mMediaSizes;
+    private @NonNull List<Resolution> mResolutions;
 
     private int mColorModes;
     private int mDuplexModes;
@@ -205,15 +207,37 @@
         return builder.build();
     }
 
+    /**
+     * Call enforceSingle for each bit in the mask.
+     *
+     * @param mask The mask
+     * @param enforceSingle The function to call
+     */
+    private static void enforceValidMask(int mask, IntConsumer enforceSingle) {
+        int current = mask;
+        while (current > 0) {
+            final int currentMode = (1 << Integer.numberOfTrailingZeros(current));
+            current &= ~currentMode;
+            enforceSingle.accept(currentMode);
+        }
+    }
+
     private PrinterCapabilitiesInfo(Parcel parcel) {
-        mMinMargins = readMargins(parcel);
+        mMinMargins = Preconditions.checkNotNull(readMargins(parcel));
         readMediaSizes(parcel);
         readResolutions(parcel);
 
         mColorModes = parcel.readInt();
+        enforceValidMask(mColorModes,
+                (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
+
         mDuplexModes = parcel.readInt();
+        enforceValidMask(mDuplexModes,
+                (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
 
         readDefaults(parcel);
+        Preconditions.checkArgument(mMediaSizes.size() > mDefaults[PROPERTY_MEDIA_SIZE]);
+        Preconditions.checkArgument(mResolutions.size() > mDefaults[PROPERTY_RESOLUTION]);
     }
 
     @Override
@@ -537,12 +561,8 @@
          */
         public @NonNull Builder setColorModes(@ColorMode int colorModes,
                 @ColorMode int defaultColorMode) {
-            int currentModes = colorModes;
-            while (currentModes > 0) {
-                final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
-                currentModes &= ~currentMode;
-                PrintAttributes.enforceValidColorMode(currentMode);
-            }
+            enforceValidMask(colorModes,
+                    (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
             PrintAttributes.enforceValidColorMode(defaultColorMode);
             mPrototype.mColorModes = colorModes;
             mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
@@ -568,12 +588,8 @@
          */
         public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
                 @DuplexMode int defaultDuplexMode) {
-            int currentModes = duplexModes;
-            while (currentModes > 0) {
-                final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
-                currentModes &= ~currentMode;
-                PrintAttributes.enforceValidDuplexMode(currentMode);
-            }
+            enforceValidMask(duplexModes,
+                    (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
             PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
             mPrototype.mDuplexModes = duplexModes;
             mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 0d2d9f4..1ee6389 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -467,10 +467,12 @@
          * {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon}.
          * </p>
          *
+         * @param hasCustomPrinterIcon If the printer has a custom icon or not.
+         *
          * @return This builder.
          */
-        public @NonNull Builder setHasCustomPrinterIcon() {
-            mHasCustomPrinterIcon = true;
+        public @NonNull Builder setHasCustomPrinterIcon(boolean hasCustomPrinterIcon) {
+            mHasCustomPrinterIcon = hasCustomPrinterIcon;
             return this;
         }
 
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index 0ae1e18..f0ea6ae 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -52,6 +52,15 @@
      */
     void setStatus(in PrintJobId printJobId, in CharSequence status);
 
+    /**
+     * Set the status of this print job
+     *
+     * @param printJobId The print job to update
+     * @param status The new status as a string resource
+     * @param appPackageName The app package name the string belongs to
+     */
+    void setStatusRes(in PrintJobId printJobId, int status, in CharSequence appPackageName);
+
     void onPrintersAdded(in ParceledListSlice printers);
     void onPrintersRemoved(in ParceledListSlice printerIds);
 
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 6414b6a..7a7ca23 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -20,11 +20,14 @@
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.content.Context;
 import android.os.RemoteException;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
 import android.text.TextUtils;
 import android.util.Log;
+import com.android.internal.util.Preconditions;
 
 /**
  * This class represents a print job from the perspective of a print
@@ -45,7 +48,12 @@
 
     private PrintJobInfo mCachedInfo;
 
-    PrintJob(@NonNull PrintJobInfo jobInfo, @NonNull IPrintServiceClient client) {
+    /** Context that created the object */
+    private final Context mContext;
+
+    PrintJob(@NonNull Context context, @NonNull PrintJobInfo jobInfo,
+            @NonNull IPrintServiceClient client) {
+        mContext = context;
         mCachedInfo = jobInfo;
         mPrintServiceClient = client;
         mDocument = new PrintDocument(mCachedInfo.getId(), client,
@@ -216,11 +224,10 @@
     }
 
     /**
-     * Blocks the print job. You should call this method if {@link
-     * #isStarted()} or {@link #isBlocked()} returns true and you need
-     * to block the print job. For example, the user has to add some
-     * paper to continue printing. To resume the print job call {@link
-     * #start()}.
+     * Blocks the print job. You should call this method if {@link #isStarted()} returns true and
+     * you need to block the print job. For example, the user has to add some paper to continue
+     * printing. To resume the print job call {@link #start()}. To change the reason call
+     * {@link #setStatus(CharSequence)}.
      *
      * @param reason The human readable, short, and translated reason why the print job is blocked.
      * @return Whether the job was blocked.
@@ -233,9 +240,7 @@
         PrintService.throwIfNotCalledOnMainThread();
         PrintJobInfo info = getInfo();
         final int state = info.getState();
-        if (state == PrintJobInfo.STATE_STARTED
-                || (state == PrintJobInfo.STATE_BLOCKED
-                        && !TextUtils.equals(info.getStatus(), reason))) {
+        if (state == PrintJobInfo.STATE_STARTED || state == PrintJobInfo.STATE_BLOCKED) {
             return setState(PrintJobInfo.STATE_BLOCKED, reason);
         }
         return false;
@@ -320,6 +325,9 @@
     /**
      * Sets the status of this print job. This should be a human readable, short, and translated
      * description of the current state of the print job.
+     * <p />
+     * This overrides any previously set status set via {@link #setStatus(CharSequence)},
+     * {@link #setStatus(int)}, {@link #block(String)}, or {@link #fail(String)},
      *
      * @param status The new status. If null the status will be empty.
      */
@@ -335,6 +343,29 @@
     }
 
     /**
+     * Sets the status of this print job as a string resource.
+     * <p />
+     * This overrides any previously set status set via {@link #setStatus(CharSequence)},
+     * {@link #setStatus(int)}, {@link #block(String)}, or {@link #fail(String)},
+     * <p />
+     * To clear the status use {@link #setStatus(CharSequence) <code>setStatus(null)</code>}
+     *
+     * @param status  The new status as a String resource.
+     */
+    @MainThread
+    public void setStatus(@StringRes int status) {
+        PrintService.throwIfNotCalledOnMainThread();
+        Preconditions.checkArgument(status != 0, "status has to be != 0");
+
+        try {
+            mPrintServiceClient.setStatusRes(mCachedInfo.getId(), status,
+                    mContext.getPackageName());
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error setting status for job: " + mCachedInfo.getId(), re);
+        }
+    }
+
+    /**
      * Sets a tag that is valid in the context of a {@link PrintService}
      * and is not interpreted by the system. For example, a print service
      * may set as a tag the key of the print job returned by a remote
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 62d214e..8f73518 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -329,7 +329,7 @@
                 final int printJobInfoCount = printJobInfos.size();
                 printJobs = new ArrayList<PrintJob>(printJobInfoCount);
                 for (int i = 0; i < printJobInfoCount; i++) {
-                    printJobs.add(new PrintJob(printJobInfos.get(i), mClient));
+                    printJobs.add(new PrintJob(this, printJobInfos.get(i), mClient));
                 }
             }
             if (printJobs != null) {
@@ -549,7 +549,7 @@
                                 + getPackageName());
                     }
                     PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
-                    onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient));
+                    onRequestCancelPrintJob(new PrintJob(PrintService.this, printJobInfo, mClient));
                 } break;
 
                 case MSG_ON_PRINTJOB_QUEUED: {
@@ -561,7 +561,7 @@
                     if (DEBUG) {
                         Log.i(LOG_TAG, "Queued: " + printJobInfo);
                     }
-                    onPrintJobQueued(new PrintJob(printJobInfo, mClient));
+                    onPrintJobQueued(new PrintJob(PrintService.this, printJobInfo, mClient));
                 } break;
 
                 case MSG_SET_CLIENT: {
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 91e01f2..45e3d47 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -55,6 +55,8 @@
 
     private final String mId;
 
+    private boolean mIsEnabled;
+
     private final ResolveInfo mResolveInfo;
 
     private final String mSettingsActivityName;
@@ -70,6 +72,7 @@
      */
     public PrintServiceInfo(Parcel parcel) {
         mId = parcel.readString();
+        mIsEnabled = parcel.readByte() != 0;
         mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
         mAddPrintersActivityName = parcel.readString();
@@ -180,6 +183,24 @@
     }
 
     /**
+     * If the service was enabled when it was read from the system.
+     *
+     * @return The id.
+     */
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    /**
+     * Mark a service as enabled or not
+     *
+     * @param isEnabled If the service should be marked as enabled.
+     */
+    public void setIsEnabled(boolean isEnabled) {
+        mIsEnabled = isEnabled;
+    }
+
+    /**
      * The service {@link ResolveInfo}.
      *
      * @return The info.
@@ -238,6 +259,7 @@
     @Override
     public void writeToParcel(Parcel parcel, int flagz) {
         parcel.writeString(mId);
+        parcel.writeByte((byte)(mIsEnabled ? 1 : 0));
         parcel.writeParcelable(mResolveInfo, 0);
         parcel.writeString(mSettingsActivityName);
         parcel.writeString(mAddPrintersActivityName);
@@ -276,6 +298,7 @@
         StringBuilder builder = new StringBuilder();
         builder.append("PrintServiceInfo{");
         builder.append("id=").append(mId);
+        builder.append("isEnabled=").append(mIsEnabled);
         builder.append(", resolveInfo=").append(mResolveInfo);
         builder.append(", settingsActivityName=").append(mSettingsActivityName);
         builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index cd5a903..7b9533d 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.content.pm.ParceledListSlice;
+import android.os.CancellationSignal;
 import android.os.RemoteException;
 import android.print.PrinterCapabilitiesInfo;
 import android.print.PrinterId;
@@ -412,11 +413,13 @@
      * service.
      *
      * @param printerId The printer to icon belongs to.
+     * @param cancellationSignal Signal used to cancel the request
      * @param callback Callback for returning the icon to the print spooler.
      *
      * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
      */
     public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+            @NonNull CancellationSignal cancellationSignal,
             @NonNull CustomPrinterIconCallback callback) {
     }
 
@@ -533,7 +536,7 @@
         if (!mIsDestroyed && mObserver != null) {
             CustomPrinterIconCallback callback = new CustomPrinterIconCallback(printerId,
                     mObserver);
-            onRequestCustomPrinterIcon(printerId, callback);
+            onRequestCustomPrinterIcon(printerId, new CancellationSignal(), callback);
         }
     }
 
diff --git a/core/java/android/printservice/recommendation/IRecommendationService.aidl b/core/java/android/printservice/recommendation/IRecommendationService.aidl
new file mode 100644
index 0000000..ce9ea6f
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationService.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+import android.printservice.recommendation.IRecommendationServiceCallbacks;
+
+/**
+ * Interface for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationServiceCallbacks
+ *
+ * @hide
+ */
+oneway interface IRecommendationService {
+    void registerCallbacks(in IRecommendationServiceCallbacks callbacks);
+}
diff --git a/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
new file mode 100644
index 0000000..9528654
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+import android.printservice.recommendation.RecommendationInfo;
+
+/**
+ * Callbacks for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationService
+ *
+ * @hide
+ */
+oneway interface IRecommendationServiceCallbacks {
+    /**
+     * Update the print service recommendations.
+     *
+     * @param recommendations the new print service recommendations
+     */
+    void onRecommendationsUpdated(in List<RecommendationInfo> recommendations);
+}
diff --git a/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
new file mode 100644
index 0000000..8ca5c69
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+/**
+ * Interface for observing changes of the print service recommendations.
+ *
+ * @hide
+ */
+oneway interface IRecommendationsChangeListener {
+    void onRecommendationsChanged();
+}
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.aidl b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
new file mode 100644
index 0000000..f21d0bf
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+/**
+ * @hide
+ */
+parcelable RecommendationInfo;
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.java b/core/java/android/printservice/recommendation/RecommendationInfo.java
new file mode 100644
index 0000000..65d534e
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.printservice.PrintService;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A recommendation to install a {@link PrintService print service}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RecommendationInfo implements Parcelable {
+    /** Package name of the print service. */
+    private @NonNull final CharSequence mPackageName;
+
+    /** Display name of the print service. */
+    private @NonNull final CharSequence mName;
+
+    /** Number of printers the print service would discover if installed. */
+    private @IntRange(from = 0) final int mNumDiscoveredPrinters;
+
+    /** If the service detects printer from multiple vendors. */
+    private final boolean mRecommendsMultiVendorService;
+
+    /**
+     * Create a new recommendation.
+     *
+     * @param packageName                  Package name of the print service
+     * @param name                         Display name of the print service
+     * @param numDiscoveredPrinters        Number of printers the print service would discover if
+     *                                     installed
+     * @param recommendsMultiVendorService If the service detects printer from multiple vendor
+     */
+    public RecommendationInfo(@NonNull CharSequence packageName, @NonNull CharSequence name,
+            @IntRange(from = 0) int numDiscoveredPrinters, boolean recommendsMultiVendorService) {
+        mPackageName = Preconditions.checkStringNotEmpty(packageName);
+        mName = Preconditions.checkStringNotEmpty(name);
+        mNumDiscoveredPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters);
+        mRecommendsMultiVendorService = recommendsMultiVendorService;
+    }
+
+    /**
+     * Create a new recommendation from a parcel.
+     *
+     * @param parcel The parcel containing the data
+     *
+     * @see #CREATOR
+     */
+    private RecommendationInfo(@NonNull Parcel parcel) {
+        this(parcel.readCharSequence(), parcel.readCharSequence(), parcel.readInt(),
+                parcel.readByte() != 0);
+    }
+
+    /**
+     * @return The package name the recommendations recommends.
+     */
+    public CharSequence getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * @return Whether the recommended print service detects printers of more than one vendor.
+     */
+    public boolean recommendsMultiVendorService() {
+        return mRecommendsMultiVendorService;
+    }
+
+    /**
+     * @return The number of printer the print service would detect.
+     */
+    public int getNumDiscoveredPrinters() {
+        return mNumDiscoveredPrinters;
+    }
+
+    /**
+     * @return The name of the recommended print service.
+     */
+    public CharSequence getName() {
+        return mName;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeCharSequence(mPackageName);
+        dest.writeCharSequence(mName);
+        dest.writeInt(mNumDiscoveredPrinters);
+        dest.writeByte((byte) (mRecommendsMultiVendorService ? 1 : 0));
+    }
+
+    /**
+     * Utility class used to create new print service recommendation objects from parcels.
+     *
+     * @see #RecommendationInfo(Parcel)
+     */
+    public static final Creator<RecommendationInfo> CREATOR =
+            new Creator<RecommendationInfo>() {
+                @Override
+                public RecommendationInfo createFromParcel(Parcel in) {
+                    return new RecommendationInfo(in);
+                }
+
+                @Override
+                public RecommendationInfo[] newArray(int size) {
+                    return new RecommendationInfo[size];
+                }
+    };
+}
diff --git a/core/java/android/printservice/recommendation/RecommendationService.java b/core/java/android/printservice/recommendation/RecommendationService.java
new file mode 100644
index 0000000..b7ea512
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationService.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.List;
+
+/**
+ * Base class for the print service recommendation services.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class RecommendationService extends Service {
+    private static final String LOG_TAG = "PrintServiceRecS";
+
+    /** Used to push onConnect and onDisconnect on the main thread */
+    private Handler mHandler;
+
+    /**
+     * The {@link Intent} action that must be declared as handled by a service in its manifest for
+     * the system to recognize it as a print service recommendation service.
+     *
+     * @hide
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.printservice.recommendation.RecommendationService";
+
+    /** Registered callbacks, only modified on main thread */
+    private IRecommendationServiceCallbacks mCallbacks;
+
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+
+        mHandler = new MyHandler();
+    }
+
+    /**
+     * Update the print service recommendations.
+     *
+     * @param recommendations The new set of recommendations
+     */
+    public final void updateRecommendations(@Nullable List<RecommendationInfo> recommendations) {
+        mHandler.obtainMessage(MyHandler.MSG_UPDATE, recommendations).sendToTarget();
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return new IRecommendationService.Stub() {
+            @Override
+            public void registerCallbacks(IRecommendationServiceCallbacks callbacks) {
+                // The callbacks come in order of the caller on oneway calls. Hence while the caller
+                // cannot know at what time the connection is made, he can know the ordering of
+                // connection and disconnection.
+                //
+                // Similar he cannot know when the disconnection is processed, hence he has to
+                // handle callbacks after calling disconnect.
+                if (callbacks != null) {
+                    mHandler.obtainMessage(MyHandler.MSG_CONNECT, callbacks).sendToTarget();
+                } else {
+                    mHandler.obtainMessage(MyHandler.MSG_DISCONNECT).sendToTarget();
+                }
+            }
+        };
+    }
+
+    /**
+     * Called when the client connects to the recommendation service.
+     */
+    public abstract void onConnected();
+
+    /**
+     * Called when the client disconnects from the recommendation service.
+     */
+    public abstract void onDisconnected();
+
+    private class MyHandler extends Handler {
+        static final int MSG_CONNECT = 1;
+        static final int MSG_DISCONNECT = 2;
+        static final int MSG_UPDATE = 3;
+
+        MyHandler() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_CONNECT:
+                    mCallbacks = (IRecommendationServiceCallbacks) msg.obj;
+                    onConnected();
+                    break;
+                case MSG_DISCONNECT:
+                    onDisconnected();
+                    mCallbacks = null;
+                    break;
+                case MSG_UPDATE:
+                    // Note that there might be a connection change in progress. In this case the
+                    // message is handled as before the change. This is acceptable as the caller of
+                    // the connection change has not guarantee when the connection change binder
+                    // transaction is actually processed.
+                    try {
+                        mCallbacks.onRecommendationsUpdated((List<RecommendationInfo>) msg.obj);
+                    } catch (RemoteException | NullPointerException e) {
+                        Log.e(LOG_TAG, "Could not update recommended services", e);
+                    }
+                    break;
+            }
+        }
+    }
+}
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index ed7c7c5..e90dc9c 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -15,6 +15,7 @@
  */
 package android.provider;
 
+import android.annotation.WorkerThread;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Bundle;
@@ -32,13 +33,20 @@
  * blocked numbers are discarded by the platform. Notifications upon provider changes can be
  * received using a {@link android.database.ContentObserver}.
  * </p>
+ * <p>
+ * The platform will not block messages, and calls from emergency numbers as defined by
+ * {@link android.telephony.PhoneNumberUtils#isEmergencyNumber(String)}. If the user contacts
+ * emergency services, number blocking is disabled by the platform for a duration defined by
+ * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}.
+ * </p>
  *
  * <h3> Permissions </h3>
  * <p>
  * Only the system, the default SMS application, and the default phone app
  * (See {@link android.telecom.TelecomManager#getDefaultDialerPackage()}), and carrier apps
  * (See {@link android.service.carrier.CarrierService}) can read, and write to the blockednumber
- * provider.
+ * provider. However, {@link #canCurrentUserBlockNumbers(Context)} can be accessed by any
+ * application.
  * </p>
  *
  * <h3> Data </h3>
@@ -61,7 +69,12 @@
  * Apps can optionally provide the {@link BlockedNumbers#COLUMN_E164_NUMBER} which is the phone
  * number's E164 representation. The provider automatically populates this column if the app does
  * not provide it. Note that this column is not populated if normalization fails or if the address
- * is not a phone number (eg: email). The provider enforces uniqueness constraint on this column.
+ * is not a phone number (eg: email).
+ * <p>
+ * Attempting to insert an existing blocked number (same
+ * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column) will result in replacing the existing
+ * blocked number.
+ * <p>
  * Examples:
  * <pre>
  * ContentValues values = new ContentValues();
@@ -97,6 +110,8 @@
  * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
  * getContentResolver().delete(uri, null, null);
  * </pre>
+ * To check if a particular number is blocked, use the method
+ * {@link #isBlocked(Context, String)}.
  * </p>
  * </dd>
  * <dt><b>Query</b></dt>
@@ -108,8 +123,12 @@
  *          new String[]{BlockedNumbers.COLUMN_ID, BlockedNumbers.COLUMN_ORIGINAL_NUMBER,
  *          BlockedNumbers.COLUMN_E164_NUMBER}, null, null, null);
  * </pre>
- * To check if a particular number is blocked, use the method
- * {@link #isBlocked(Context, String)}.
+ * </p>
+ * </dd>
+ * <dt><b>Unblock</b></dt>
+ * <dd>
+ * <p>
+ * Use the method {@link #unblock(Context, String)} to unblock numbers.
  * </p>
  * </dd>
  *
@@ -141,25 +160,26 @@
 
         /**
          * Content URI for the blocked numbers.
-         *
-         * Supported operations
-         * blocked
-         * - query
-         * - delete
-         * - insert
-         *
-         * blocked/ID
-         * - query (selection is not supported)
-         * - delete (selection is not supported)
+         * <h3> Supported operations </h3>
+         * <p> blocked
+         * <ul>
+         * <li> query
+         * <li> delete
+         * <li> insert
+         * </ul>
+         * <p> blocked/ID
+         * <ul>
+         * <li> query (selection is not supported)
+         * <li> delete (selection is not supported)
+         * </ul>
          */
-        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
-                "blocked");
+        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "blocked");
 
         /**
          * The MIME type of {@link #CONTENT_URI} itself providing a directory of blocked phone
          * numbers.
          */
-        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
 
         /**
          * The MIME type of a blocked phone number under {@link #CONTENT_URI}.
@@ -193,9 +213,15 @@
     public static final String METHOD_IS_BLOCKED = "is_blocked";
 
     /** @hide */
+    public static final String METHOD_UNBLOCK= "unblock";
+
+    /** @hide */
     public static final String RES_NUMBER_IS_BLOCKED = "blocked";
 
     /** @hide */
+    public static final String RES_NUM_ROWS_DELETED = "num_deleted";
+
+    /** @hide */
     public static final String METHOD_CAN_CURRENT_USER_BLOCK_NUMBERS =
             "can_current_user_block_numbers";
 
@@ -204,9 +230,15 @@
 
     /**
      * Returns whether a given number is in the blocked list.
+     *
+     * <p> This matches the {@code phoneNumber} against the
+     * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column, and the E164 representation of the
+     * {@code phoneNumber} with the {@link BlockedNumbers#COLUMN_E164_NUMBER} column.
+     *
      * <p> Note that if the {@link #canCurrentUserBlockNumbers} is {@code false} for the user
      * context {@code context}, this method will throw an {@link UnsupportedOperationException}.
      */
+    @WorkerThread
     public static boolean isBlocked(Context context, String phoneNumber) {
         final Bundle res = context.getContentResolver().call(
                 AUTHORITY_URI, METHOD_IS_BLOCKED, phoneNumber, null);
@@ -214,8 +246,32 @@
     }
 
     /**
+     * Unblocks the {@code phoneNumber} if it is blocked.
+     *
+     * <p> Returns the number of rows deleted in the blocked number provider as a result of unblock.
+     *
+     * <p> This deletes all rows where the {@code phoneNumber} matches the
+     * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column or the E164 representation of the
+     * {@code phoneNumber} matches the {@link BlockedNumbers#COLUMN_E164_NUMBER} column.
+     *
+     * <p>To delete rows based on exact match with specific columns such as
+     * {@link BlockedNumbers#COLUMN_ID} use
+     * {@link android.content.ContentProvider#delete(Uri, String, String[])} with
+     * {@link BlockedNumbers#CONTENT_URI} URI.
+     *
+     * <p> Note that if the {@link #canCurrentUserBlockNumbers} is {@code false} for the user
+     * context {@code context}, this method will throw an {@link UnsupportedOperationException}.
+     */
+    @WorkerThread
+    public static int unblock(Context context, String phoneNumber) {
+        final Bundle res = context.getContentResolver().call(
+                AUTHORITY_URI, METHOD_UNBLOCK, phoneNumber, null);
+        return res.getInt(RES_NUM_ROWS_DELETED, 0);
+    }
+
+    /**
      * Returns {@code true} if blocking numbers is supported for the current user.
-     * <p> Typically, blocking numbers is only supported for the primary user.
+     * <p> Typically, blocking numbers is only supported for one user at a time.
      */
     public static boolean canCurrentUserBlockNumbers(Context context) {
         final Bundle res = context.getContentResolver().call(
@@ -239,20 +295,20 @@
     public static class SystemContract {
         /**
          * A protected broadcast intent action for letting components with
-         * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} know that the block suppressal
-         * status as returned by {@link #getBlockSuppressalStatus(Context)} has been updated.
+         * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} know that the block suppression
+         * status as returned by {@link #getBlockSuppressionStatus(Context)} has been updated.
          */
-        public static final String ACTION_BLOCK_SUPPRESSAL_STATE_CHANGED =
-                "android.provider.action.BLOCK_SUPPRESSAL_STATE_CHANGED";
+        public static final String ACTION_BLOCK_SUPPRESSION_STATE_CHANGED =
+                "android.provider.action.BLOCK_SUPPRESSION_STATE_CHANGED";
 
         public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
 
-        public static final String METHOD_END_BLOCK_SUPPRESSAL = "end_block_suppressal";
+        public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression";
 
         public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
 
-        public static final String METHOD_GET_BLOCK_SUPPRESSAL_STATUS =
-                "get_block_suppresal_status";
+        public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
+                "get_block_suppression_status";
 
         public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
 
@@ -264,7 +320,7 @@
          * <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent
          * of the contents of the provider for a duration defined by
          * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}
-         * the provider unless {@link #endBlockSuppressal(Context)} is called.
+         * the provider unless {@link #endBlockSuppression(Context)} is called.
          */
         public static void notifyEmergencyContact(Context context) {
             context.getContentResolver().call(
@@ -275,9 +331,9 @@
          * Notifies the provider to disable suppressing blocking. If emergency services were not
          * contacted recently at all, calling this method is a no-op.
          */
-        public static void endBlockSuppressal(Context context) {
+        public static void endBlockSuppression(Context context) {
             context.getContentResolver().call(
-                    AUTHORITY_URI, METHOD_END_BLOCK_SUPPRESSAL, null, null);
+                    AUTHORITY_URI, METHOD_END_BLOCK_SUPPRESSION, null, null);
         }
 
         /**
@@ -292,26 +348,29 @@
             return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
         }
 
-        public static BlockSuppressalStatus getBlockSuppressalStatus(Context context) {
+        /**
+         * Returns the current status of block suppression.
+         */
+        public static BlockSuppressionStatus getBlockSuppressionStatus(Context context) {
             final Bundle res = context.getContentResolver().call(
-                    AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSAL_STATUS, null, null);
-            return new BlockSuppressalStatus(res.getBoolean(RES_IS_BLOCKING_SUPPRESSED, false),
+                    AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSION_STATUS, null, null);
+            return new BlockSuppressionStatus(res.getBoolean(RES_IS_BLOCKING_SUPPRESSED, false),
                     res.getLong(RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP, 0));
         }
 
         /**
          * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If
          * emergency services have been contacted recently, {@link #isSuppressed} is {@code true},
-         *  and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
+         * and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
          */
-        public static class BlockSuppressalStatus {
+        public static class BlockSuppressionStatus {
             public final boolean isSuppressed;
             /**
              * Timestamp in milliseconds from epoch.
              */
             public final long untilTimestampMillis;
 
-            public BlockSuppressalStatus(boolean isSuppressed, long untilTimestampMillis) {
+            public BlockSuppressionStatus(boolean isSuppressed, long untilTimestampMillis) {
                 this.isSuppressed = isSuppressed;
                 this.untilTimestampMillis = untilTimestampMillis;
             }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index e7c4a07..8ac185a 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -179,6 +179,7 @@
          * <li>{@link #VOICEMAIL_TYPE}</li>
          * <li>{@link #REJECTED_TYPE}</li>
          * <li>{@link #BLOCKED_TYPE}</li>
+         * <li>{@link #ANSWERED_EXTERNALLY_TYPE}</li>
          * </ul>
          * </p>
          */
@@ -196,6 +197,12 @@
         public static final int REJECTED_TYPE = 5;
         /** Call log type for calls blocked automatically. */
         public static final int BLOCKED_TYPE = 6;
+        /**
+         * Call log type for a call which was answered on another device.  Used in situations where
+         * a call rings on multiple devices simultaneously and it ended up being answered on a
+         * device other than the current one.
+         */
+        public static final int ANSWERED_EXTERNALLY_TYPE = 7;
 
         /**
          * Bit-mask describing features of the call (e.g. video).
@@ -207,6 +214,9 @@
         /** Call had video. */
         public static final int FEATURES_VIDEO = 0x1;
 
+        /** Call was pulled externally. */
+        public static final int FEATURES_PULLED_EXTERNALLY = 0x2;
+
         /**
          * The phone number as the user entered it.
          * <P>Type: TEXT</P>
@@ -430,6 +440,13 @@
         public static final String POST_DIAL_DIGITS = "post_dial_digits";
 
         /**
+         * For an incoming call, the secondary line number the call was received via.
+         * When a SIM card has multiple phone numbers associated with it, the via number indicates
+         * which of the numbers associated with the SIM was called.
+         */
+        public static final String VIA_NUMBER = "via_number";
+
+        /**
          * Indicates that the entry will be copied from primary user to other users.
          * <P>Type: INTEGER</P>
          *
@@ -475,10 +492,10 @@
         public static Uri addCall(CallerInfo ci, Context context, String number,
                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
                 long start, int duration, Long dataUsage) {
-            return addCall(ci, context, number, /* postDialDigits =*/ "", presentation,
-                    callType, features, accountHandle,
-                    start, duration, dataUsage, /* addForAllUsers =*/ false,
-                    /* userToBeInsertedTo =*/ null, /* is_read =*/ false);
+            return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "",
+                    presentation, callType, features, accountHandle, start, duration,
+                    dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null,
+                    /* is_read =*/ false);
         }
 
 
@@ -489,6 +506,8 @@
          * if the contact is unknown.
          * @param context the context used to get the ContentResolver
          * @param number the phone number to be added to the calls db
+         * @param viaNumber the secondary number that the incoming call received with. If the
+         *       call was received with the SIM assigned number, then this field must be ''.
          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
          *        is set by the network and denotes the number presenting rules for
          *        "allowed", "payphone", "restricted" or "unknown"
@@ -509,12 +528,12 @@
          * {@hide}
          */
         public static Uri addCall(CallerInfo ci, Context context, String number,
-                String postDialDigits, int presentation, int callType, int features,
-                PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage,
-                boolean addForAllUsers, UserHandle userToBeInsertedTo) {
-            return addCall(ci, context, number, postDialDigits, presentation, callType, features,
-                    accountHandle, start, duration, dataUsage, addForAllUsers, userToBeInsertedTo,
-                    /* is_read =*/ false);
+                String postDialDigits, String viaNumber, int presentation, int callType,
+                int features, PhoneAccountHandle accountHandle, long start, int duration,
+                Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
+            return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
+                    features, accountHandle, start, duration, dataUsage, addForAllUsers,
+                    userToBeInsertedTo, /* is_read =*/ false);
         }
 
         /**
@@ -526,6 +545,8 @@
          * @param number the phone number to be added to the calls db
          * @param postDialDigits the post-dial digits that were dialed after the number,
          *        if it was outgoing. Otherwise it is ''.
+         * @param viaNumber the secondary number that the incoming call received with. If the
+         *        call was received with the SIM assigned number, then this field must be ''.
          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
          *        is set by the network and denotes the number presenting rules for
          *        "allowed", "payphone", "restricted" or "unknown"
@@ -550,9 +571,10 @@
          * {@hide}
          */
         public static Uri addCall(CallerInfo ci, Context context, String number,
-                String postDialDigits, int presentation, int callType, int features,
-                PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage,
-                boolean addForAllUsers, UserHandle userToBeInsertedTo, boolean is_read) {
+                String postDialDigits, String viaNumber, int presentation, int callType,
+                int features, PhoneAccountHandle accountHandle, long start, int duration,
+                Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
+                boolean is_read) {
             if (VERBOSE_LOG) {
                 Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
                         number, userToBeInsertedTo, addForAllUsers));
@@ -608,6 +630,7 @@
 
             values.put(NUMBER, number);
             values.put(POST_DIAL_DIGITS, postDialDigits);
+            values.put(VIA_NUMBER, viaNumber);
             values.put(NUMBER_PRESENTATION, Integer.valueOf(numberPresentation));
             values.put(TYPE, Integer.valueOf(callType));
             values.put(FEATURES, features);
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 904b393..3658df9 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -5185,6 +5185,10 @@
          *     <li>
          *     Corp contacts will get artificial {@link #LOOKUP_KEY}s too.
          *     </li>
+         *     <li>
+         *     Returned work contact IDs and lookup keys are not accepted in places that not
+         *     explicitly say to accept them.
+         *     </li>
          * </ul>
          * <p>
          * A contact lookup URL built by
@@ -6194,6 +6198,10 @@
              *     <li>
              *     Corp contacts will get artificial {@link #LOOKUP_KEY}s too.
              *     </li>
+             *     <li>
+             *     Returned work contact IDs and lookup keys are not accepted in places that not
+             *     explicitly say to accept them.
+             *     </li>
              * </ul>
              * <p>
              * A contact lookup URL built by
@@ -8466,7 +8474,9 @@
          *            around this {@link View}.
          * @param lookupUri A {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
          *            {@link Uri} that describes a specific contact to feature
-         *            in this dialog.
+         *            in this dialog. A work lookup uri is supported here,
+         *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+         *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
          * @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
          *            {@link #MODE_LARGE}, indicating the desired dialog size,
          *            when supported.
@@ -8500,7 +8510,9 @@
          * @param lookupUri A
          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
          *            {@link Uri} that describes a specific contact to feature
-         *            in this dialog.
+         *            in this dialog. A work lookup uri is supported here,
+         *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+         *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
          * @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
          *            {@link #MODE_LARGE}, indicating the desired dialog size,
          *            when supported.
@@ -8531,7 +8543,9 @@
          * @param lookupUri A
          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
          *            {@link Uri} that describes a specific contact to feature
-         *            in this dialog.
+         *            in this dialog. A work lookup uri is supported here,
+         *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+         *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
          *            to exclude when showing this dialog. For example, when
          *            already viewing the contact details card, this can be used
@@ -8569,7 +8583,9 @@
          * @param lookupUri A
          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
          *            {@link Uri} that describes a specific contact to feature
-         *            in this dialog.
+         *            in this dialog. A work lookup uri is supported here,
+         *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+         *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
          *            to exclude when showing this dialog. For example, when
          *            already viewing the contact details card, this can be used
@@ -8763,6 +8779,15 @@
          * <li><em>Note: Some apps may choose to use phone number as the unique contact ID in DATA1.
          * If this applies to you and you’d like phone number to be shown below the Contact Name by
          * the Voice Assistant, then you may choose to leave DATA3 empty.</em></li>
+         * <li><em>Note: If your app also uses DATA3 to display contact details in the Contacts App,
+         * make sure it does not include prefix text such as "Message +<phone>" or "Free Message
+         * +<phone>", etc. If you must show the prefix text in the Contacts App, please use a
+         * different DATA# column, and update your contacts.xml to point to this new column. </em>
+         * </li>
+         * <li>Everytime the user sends a message to a contact, your app may choose to update the
+         * {@link ContactOptionsColumns#TIMES_CONTACTED} entry through DataUsageFeedback class.
+         * Doing this will allow Voice Assistant to bias speech recognition to contacts frequently
+         * contacted, this is particularly useful for contact names that are hard to pronounce.</li>
          * </ul>
          * <p>
          * Input: {@link android.content.Intent#getType} is the MIME type of the data being sent.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 3700098..aba3972 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -112,9 +112,8 @@
      * thumbnail should be rotated.
      *
      * @see MediaStore.Images.ImageColumns#ORIENTATION
-     * @hide
      */
-    public static final String EXTRA_ORIENTATION = "android.content.extra.ORIENTATION";
+    public static final String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
 
     /**
      * Overrides the default prompt text in DocumentsUI when set in an intent.
@@ -122,8 +121,6 @@
     public static final String EXTRA_PROMPT = "android.provider.extra.PROMPT";
 
     /** {@hide} */
-    public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
-    /** {@hide} */
     public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
 
     /** {@hide} */
@@ -384,20 +381,18 @@
          * @see DocumentsProvider#queryChildDocuments(String, String[], String)
          * @hide
          */
-
         public static final int FLAG_ARCHIVE = 1 << 15;
+
         /**
-         * Flag indicating that document titles should be hidden when viewing
-         * this directory in a larger format grid. For example, a directory
-         * containing only images may want the image thumbnails to speak for
-         * themselves. Only valid when {@link #COLUMN_MIME_TYPE} is
-         * {@link #MIME_TYPE_DIR}.
+         * Flag indicating that a document is not complete, likely its
+         * contents are being downloaded. Partial files cannot be opened,
+         * copied, moved in the UI. But they can be deleted and retried
+         * if they represent a failed download.
          *
          * @see #COLUMN_FLAGS
-         * @see #FLAG_DIR_PREFERS_GRID
          * @hide
          */
-        public static final int FLAG_DIR_HIDE_GRID_TITLES = 1 << 16;
+        public static final int FLAG_PARTIAL = 1 << 16;
     }
 
     /**
@@ -481,7 +476,6 @@
         /**
          * Capacity of a root in bytes. This column is optional, and may be
          * {@code null} if unknown or unbounded.
-         * {@hide}
          * <p>
          * Type: INTEGER (long)
          */
@@ -580,6 +574,22 @@
          * @hide
          */
         public static final int FLAG_HAS_SETTINGS = 1 << 18;
+
+        /**
+         * Flag indicating that this root is on removable SD card storage.
+         *
+         * @see #COLUMN_FLAGS
+         * @hide
+         */
+        public static final int FLAG_REMOVABLE_SD = 1 << 19;
+
+        /**
+         * Flag indicating that this root is on removable USB storage.
+         *
+         * @see #COLUMN_FLAGS
+         * @hide
+         */
+        public static final int FLAG_REMOVABLE_USB = 1 << 20;
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 770cde7..2a3c3fe 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -58,6 +58,7 @@
 import android.util.AndroidException;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.LocaleList;
 import android.util.Log;
 
 import com.android.internal.util.ArrayUtils;
@@ -216,21 +217,6 @@
             "android.settings.ACCESSIBILITY_SETTINGS";
 
     /**
-     * Activity Action: Launch the screen reader tutorial.
-     * <p>
-     * In some cases, a matching Activity may not exist, so ensure you
-     * safeguard against this.
-     * <p>
-     * Input: Nothing.
-     * <p>
-     * Output: Nothing.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_SCREEN_READER_TUTORIAL =
-            "android.settings.SCREEN_READER_TUTORIAL";
-
-
-    /**
      * Activity Action: Show settings to control access to usage information.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -336,6 +322,20 @@
             "android.settings.PRIVACY_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of VPN.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VPN_SETTINGS =
+            "android.settings.VPN_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of Wi-Fi.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -531,21 +531,18 @@
             "android.settings.USER_DICTIONARY_SETTINGS";
 
     /**
-     * Activity Action: Show settings to configure the hardware keyboard layout.
+     * Activity Action: Show settings to configure the hardware keyboard.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
      * <p>
-     *
-     * @see android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS
-     * <p>
      * Input: Nothing.
      * <p>
      * Output: Nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_KEYBOARD_LAYOUT_SETTINGS =
-            "android.settings.KEYBOARD_LAYOUT_SETTINGS";
+    public static final String ACTION_HARD_KEYBOARD_SETTINGS =
+            "android.settings.HARD_KEYBOARD_SETTINGS";
 
     /**
      * Activity Action: Adds a word to the user dictionary.
@@ -1240,6 +1237,32 @@
     public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
             = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
 
+    /**
+     * Activity Action: Show a dialog for remote bugreport flow.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SHOW_REMOTE_BUGREPORT_DIALOG
+            = "android.settings.SHOW_REMOTE_BUGREPORT_DIALOG";
+
+    /**
+     * Activity Action: Show VR listener settings.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     *
+     * @see android.service.vr.VrListenerService
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VR_LISTENER_SETTINGS
+            = "android.settings.VR_LISTENER_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -1546,9 +1569,8 @@
      * @return true if the calling app can draw on top of other apps, false otherwise.
      */
     public static boolean canDrawOverlays(Context context) {
-        int uid = Binder.getCallingUid();
-        return Settings.isCallingPackageAllowedToDrawOverlays(context, uid, Settings
-                .getPackageNameForUid(context, uid), false);
+        return Settings.isCallingPackageAllowedToDrawOverlays(context, Process.myUid(),
+                context.getOpPackageName(), false);
     }
 
     /**
@@ -2071,6 +2093,8 @@
             if (outConfig.fontScale < 0) {
                 outConfig.fontScale = 1;
             }
+            outConfig.setLocales(LocaleList.forLanguageTags(
+                    Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle)));
         }
 
         /**
@@ -2079,6 +2103,9 @@
          */
         public static void clearConfiguration(Configuration inoutConfig) {
             inoutConfig.fontScale = 0;
+            if (!inoutConfig.userSetLocale && !inoutConfig.getLocales().isEmpty()) {
+                inoutConfig.setLocales(LocaleList.getEmptyLocaleList());
+            }
         }
 
         /**
@@ -2096,12 +2123,15 @@
         /** @hide */
         public static boolean putConfigurationForUser(ContentResolver cr, Configuration config,
                 int userHandle) {
-            return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle);
+            return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle) &&
+                    Settings.System.putStringForUser(
+                            cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle);
         }
 
         /** @hide */
         public static boolean hasInterestingConfigurationChanges(int changes) {
-            return (changes&ActivityInfo.CONFIG_FONT_SCALE) != 0;
+            return (changes & ActivityInfo.CONFIG_FONT_SCALE) != 0 ||
+                    (changes & ActivityInfo.CONFIG_LOCALE) != 0;
         }
 
         /** @deprecated - Do not use */
@@ -2480,6 +2510,18 @@
         };
 
         /**
+         * The serialized system locale value.
+         *
+         * Do not use this value directory.
+         * To get system locale, use {@link android.util.LocaleList#getDefault} instead.
+         * To update system locale, use {@link com.android.internal.app.LocalePicker#updateLocales}
+         * instead.
+         * @hide
+         */
+        public static final String SYSTEM_LOCALES = "system_locales";
+
+
+        /**
          * Name of an application package to be debugged.
          *
          * @deprecated Use {@link Global#DEBUG_APP} instead
@@ -2676,24 +2718,6 @@
         public static final String VOLUME_MASTER = "volume_master";
 
         /**
-         * Master volume mute (int 1 = mute, 0 = not muted).
-         *
-         * @hide
-         */
-        public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
-
-        private static final Validator VOLUME_MASTER_MUTE_VALIDATOR = sBooleanValidator;
-
-        /**
-         * Microphone mute (int 1 = mute, 0 = not muted).
-         *
-         * @hide
-         */
-        public static final String MICROPHONE_MUTE = "microphone_mute";
-
-        private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
-
-        /**
          * Master mono (int 1 = mono, 0 = normal).
          *
          * @hide
@@ -2780,6 +2804,11 @@
          */
         public static final Uri DEFAULT_RINGTONE_URI = getUriFor(RINGTONE);
 
+        /** {@hide} */
+        public static final String RINGTONE_CACHE = "ringtone_cache";
+        /** {@hide} */
+        public static final Uri RINGTONE_CACHE_URI = getUriFor(RINGTONE_CACHE);
+
         /**
          * Persistent store for the system-wide default notification sound.
          *
@@ -2798,6 +2827,11 @@
          */
         public static final Uri DEFAULT_NOTIFICATION_URI = getUriFor(NOTIFICATION_SOUND);
 
+        /** {@hide} */
+        public static final String NOTIFICATION_SOUND_CACHE = "notification_sound_cache";
+        /** {@hide} */
+        public static final Uri NOTIFICATION_SOUND_CACHE_URI = getUriFor(NOTIFICATION_SOUND_CACHE);
+
         /**
          * Persistent store for the system-wide default alarm alert.
          *
@@ -2816,6 +2850,11 @@
          */
         public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
 
+        /** {@hide} */
+        public static final String ALARM_ALERT_CACHE = "alarm_alert_cache";
+        /** {@hide} */
+        public static final Uri ALARM_ALERT_CACHE_URI = getUriFor(ALARM_ALERT_CACHE);
+
         /**
          * Persistent store for the system default media button event receiver.
          *
@@ -3468,8 +3507,6 @@
             PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
             PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
             PRIVATE_SETTINGS.add(VOLUME_MASTER);
-            PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE);
-            PRIVATE_SETTINGS.add(MICROPHONE_MUTE);
             PRIVATE_SETTINGS.add(MASTER_MONO);
             PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME);
             PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
@@ -3547,8 +3584,6 @@
             VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
             VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
             VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
-            VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
-            VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
             VALIDATORS.put(MASTER_MONO, MASTER_MONO_VALIDATOR);
             VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
             VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
@@ -3849,9 +3884,8 @@
          * @return true if the calling app can write to system settings, false otherwise
          */
         public static boolean canWrite(Context context) {
-            int uid = Binder.getCallingUid();
-            return isCallingPackageAllowedToWriteSettings(context, uid, getPackageNameForUid(
-                    context, uid), false);
+            return isCallingPackageAllowedToWriteSettings(context, Process.myUid(),
+                    context.getOpPackageName(), false);
         }
     }
 
@@ -3955,6 +3989,7 @@
             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_VERBOSE_LOGGING_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);
@@ -4486,6 +4521,13 @@
         public static final String USER_SETUP_COMPLETE = "user_setup_complete";
 
         /**
+         * Prefix for category name that marks whether a suggested action from that category was
+         * completed.
+         * @hide
+         */
+        public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
+
+        /**
          * List of input methods that are currently enabled.  This is a string
          * containing the IDs of all enabled input methods, each ID separated
          * by ':'.
@@ -5798,15 +5840,6 @@
         public static final String ASSIST_SCREENSHOT_ENABLED = "assist_screenshot_enabled";
 
         /**
-         * Names of the service component that the current user has explicitly allowed to
-         * see and change the importance of all of the user's notifications.
-         *
-         * @hide
-         */
-        public static final String ENABLED_NOTIFICATION_ASSISTANT
-                = "enabled_notification_assistant";
-
-        /**
          * Names of the service components that the current user has explicitly allowed to
          * see all of the user's notifications, separated by ':'.
          *
@@ -5985,6 +6018,14 @@
         public static final String BRIGHTNESS_USE_TWILIGHT = "brightness_use_twilight";
 
         /**
+         * Names of the service components that the current user has explicitly allowed to
+         * be a VR mode listener, separated by ':'.
+         *
+         * @hide
+         */
+        public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -6011,6 +6052,7 @@
             BACKUP_AUTO_RESTORE,
             ENABLED_ACCESSIBILITY_SERVICES,
             ENABLED_NOTIFICATION_LISTENERS,
+            ENABLED_VR_LISTENERS,
             ENABLED_INPUT_METHODS,
             TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
             TOUCH_EXPLORATION_ENABLED,
@@ -6046,7 +6088,6 @@
             MOUNT_UMS_AUTOSTART,
             MOUNT_UMS_PROMPT,
             MOUNT_UMS_NOTIFY_ENABLED,
-            UI_NIGHT_MODE,
             SLEEP_TIMEOUT,
             DOUBLE_TAP_TO_WAKE,
             WAKE_GESTURE_ENABLED,
@@ -7033,6 +7074,14 @@
                 "webview_data_reduction_proxy_key";
 
         /**
+         * Whether or not the WebView fallback mechanism should be enabled.
+         * 0=disabled, 1=enabled.
+         * @hide
+         */
+        public static final String WEBVIEW_FALLBACK_LOGIC_ENABLED =
+                "webview_fallback_logic_enabled";
+
+        /**
          * Name of the package used as WebView provider (if unset the provider is instead determined
          * by the system).
          * @hide
@@ -7043,6 +7092,7 @@
          * Developer setting to enable WebView multiprocess rendering.
          * @hide
          */
+        @SystemApi
         public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
 
        /**
@@ -7207,6 +7257,14 @@
                "wifi_suspend_optimizations_enabled";
 
        /**
+        * Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1
+        * will enable it. In the future, additional values may be supported.
+        * @hide
+        */
+       public static final String WIFI_VERBOSE_LOGGING_ENABLED =
+               "wifi_verbose_logging_enabled";
+
+       /**
         * The maximum number of times we will retry a connection to an access
         * point for which we have failed in acquiring an IP address from DHCP.
         * A value of N means that we will make N+1 connection attempts in all.
@@ -7628,6 +7686,9 @@
                 BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
         /** {@hide} */
         public static final String
+                BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX = "bluetooth_pbap_client_priority_";
+        /** {@hide} */
+        public static final String
                 BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
 
         /**
@@ -7661,6 +7722,16 @@
         public static final String DEVICE_IDLE_CONSTANTS = "device_idle_constants";
 
         /**
+         * Device Idle (Doze) specific settings for watches. See {@code #DEVICE_IDLE_CONSTANTS}
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * @see com.android.server.DeviceIdleController.Constants
+         */
+        public static final String DEVICE_IDLE_CONSTANTS_WATCH = "device_idle_constants_watch";
+
+        /**
          * App standby (app idle) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
@@ -7708,6 +7779,31 @@
         public static final String ALARM_MANAGER_CONSTANTS = "alarm_manager_constants";
 
         /**
+         * ShortcutManager specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "reset_interval_sec=86400,max_daily_updates=5"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * reset_interval_sec              (long)
+         * max_daily_updates               (int)
+         * max_icon_dimension_dp           (int, DP)
+         * max_icon_dimension_dp_lowram    (int, DP)
+         * max_shortcuts                   (int)
+         * icon_quality                    (int, 0-100)
+         * icon_format                     (String)
+         * </pre>
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * @see com.android.server.pm.ShortcutService.ConfigConstants
+         */
+        public static final String SHORTCUT_MANAGER_CONSTANTS = "shortcut_manager_constants";
+
+        /**
          * Get the key that retrieves a bluetooth headset's priority.
          * @hide
          */
@@ -7748,6 +7844,14 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth pbap client priority.
+         * @hide
+         */
+        public static final String getBluetoothPbapClientPriorityKey(String address) {
+            return BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+
+        /**
          * Get the key that retrieves a bluetooth map priority.
          * @hide
          */
@@ -7866,6 +7970,52 @@
         public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
 
         /**
+         * The surround sound formats AC3, DTS or IEC61937 are
+         * available for use if they are detected.
+         * This is the default mode.
+         *
+         * Note that AUTO is equivalent to ALWAYS for Android TVs and other
+         * devices that have an S/PDIF output. This is because S/PDIF
+         * is unidirectional and the TV cannot know if a decoder is
+         * connected. So it assumes they are always available.
+         * @hide
+         */
+         public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
+
+        /**
+         * AC3, DTS or IEC61937 are NEVER available, even if they
+         * are detected by the hardware. Those formats will not be
+         * reported.
+         *
+         * An example use case would be an AVR reports that it is capable of
+         * surround sound decoding but is broken. If NEVER is chosen
+         * then apps must use PCM output instead of encoded output.
+         * @hide
+         */
+         public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
+
+        /**
+         * AC3, DTS or IEC61937 are ALWAYS available, even if they
+         * are not detected by the hardware. Those formats will be
+         * reported as part of the HDMI output capability. Applications
+         * are then free to use either PCM or encoded output.
+         *
+         * An example use case would be a when TV was connected over
+         * TOS-link to an AVR. But the TV could not see it because TOS-link
+         * is unidirectional.
+         * @hide
+         */
+         public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
+
+        /**
+         * Set to ENCODED_SURROUND_OUTPUT_AUTO,
+         * ENCODED_SURROUND_OUTPUT_NEVER or
+         * ENCODED_SURROUND_OUTPUT_ALWAYS
+         * @hide
+         */
+        public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
+
+        /**
          * Persisted safe headphone volume management state by AudioService
          * @hide
          */
@@ -8140,6 +8290,32 @@
                 "uninstalled_ephemeral_app_cache_duration_millis";
 
         /**
+         * Allows switching users when system user is locked.
+         * <p>
+         * Type: int
+         * @hide
+         */
+        public static final String ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED =
+                "allow_user_switching_when_system_user_locked";
+
+        /**
+         * Boot count since the device starts running APK level 24.
+         * <p>
+         * Type: int
+         */
+        public static final String BOOT_COUNT = "boot_count";
+
+        /**
+         * Whether the safe boot is disallowed.
+         *
+         * <p>This setting should have the identical value as the corresponding user restriction.
+         * The purpose of the setting is to make the restriction available in early boot stages
+         * before the user restrictions are loaded.
+         * @hide
+         */
+        public static final String SAFE_BOOT_DISALLOWED = "safe_boot_disallowed";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
@@ -8172,6 +8348,7 @@
             EMERGENCY_TONE,
             CALL_AUTO_RETRY,
             DOCK_AUDIO_MEDIA_ENABLED,
+            ENCODED_SURROUND_OUTPUT,
             LOW_POWER_MODE_TRIGGER_LEVEL
         };
 
diff --git a/core/java/android/provider/UserDictionary.java b/core/java/android/provider/UserDictionary.java
index a9b106a..c6e58cb 100644
--- a/core/java/android/provider/UserDictionary.java
+++ b/core/java/android/provider/UserDictionary.java
@@ -28,6 +28,9 @@
  * A provider of user defined words for input methods to use for predictive text input.
  * Applications and input methods may add words into the dictionary. Words can have associated
  * frequency information and locale information.
+ *
+ * <p><strong>NOTE: </strong>Starting on API 23, the user dictionary is only accessible through
+ * IME and spellchecker.
  */
 public class UserDictionary {
 
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 733a092..9530aca 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -16,6 +16,7 @@
 
 package android.security;
 
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.security.net.config.ApplicationConfig;
@@ -104,4 +105,13 @@
         ManifestConfigSource source = new ManifestConfigSource(appContext);
         return new ApplicationConfig(source);
     }
+
+    /**
+     * Handle an update to the system or user certificate stores.
+     * @hide
+     */
+    @TestApi
+    public void handleTrustStorageUpdate() {
+        ApplicationConfig.getDefaultInstance().handleTrustStorageUpdate();
+    }
 }
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 4de36cd..fadea56 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -17,6 +17,7 @@
 package android.security.net.config;
 
 import android.util.Pair;
+import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
 import javax.net.ssl.X509TrustManager;
@@ -146,6 +147,20 @@
         return getConfigForHostname(hostname).isCleartextTrafficPermitted();
     }
 
+    public void handleTrustStorageUpdate() {
+        ensureInitialized();
+        mDefaultConfig.handleTrustStorageUpdate();
+        if (mConfigs != null) {
+            Set<NetworkSecurityConfig> updatedConfigs =
+                    new HashSet<NetworkSecurityConfig>(mConfigs.size());
+            for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) {
+                if (updatedConfigs.add(entry.second)) {
+                    entry.second.handleTrustStorageUpdate();
+                }
+            }
+        }
+    }
+
     private void ensureInitialized() {
         synchronized(mLock) {
             if (mInitialized) {
diff --git a/core/java/android/security/net/config/CertificateSource.java b/core/java/android/security/net/config/CertificateSource.java
index f3272e4..4bcc405 100644
--- a/core/java/android/security/net/config/CertificateSource.java
+++ b/core/java/android/security/net/config/CertificateSource.java
@@ -25,4 +25,5 @@
     X509Certificate findBySubjectAndPublicKey(X509Certificate cert);
     X509Certificate findByIssuerAndSignature(X509Certificate cert);
     Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert);
+    void handleTrustStorageUpdate();
 }
diff --git a/core/java/android/security/net/config/CertificatesEntryRef.java b/core/java/android/security/net/config/CertificatesEntryRef.java
index 742d430..45cd0f0 100644
--- a/core/java/android/security/net/config/CertificatesEntryRef.java
+++ b/core/java/android/security/net/config/CertificatesEntryRef.java
@@ -64,4 +64,8 @@
     public Set<X509Certificate> findAllCertificatesByIssuerAndSignature(X509Certificate cert) {
         return mSource.findAllByIssuerAndSignature(cert);
     }
+
+    public void handleTrustStorageUpdate() {
+        mSource.handleTrustStorageUpdate();
+    }
 }
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index b2c068c..e3c9d65 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -126,6 +126,13 @@
         });
     }
 
+    @Override
+    public void handleTrustStorageUpdate() {
+        synchronized (mLock) {
+            mCertificates = null;
+        }
+    }
+
     private static interface CertSelector {
         boolean match(X509Certificate cert);
     }
diff --git a/core/java/android/security/net/config/KeyStoreCertificateSource.java b/core/java/android/security/net/config/KeyStoreCertificateSource.java
index ba5dd83..c68f385 100644
--- a/core/java/android/security/net/config/KeyStoreCertificateSource.java
+++ b/core/java/android/security/net/config/KeyStoreCertificateSource.java
@@ -105,4 +105,9 @@
         }
         return certs;
     }
+
+    @Override
+    public void handleTrustStorageUpdate() {
+        // Nothing to do.
+    }
 }
diff --git a/core/java/android/security/net/config/ManifestConfigSource.java b/core/java/android/security/net/config/ManifestConfigSource.java
index 0e137cd..be0821c 100644
--- a/core/java/android/security/net/config/ManifestConfigSource.java
+++ b/core/java/android/security/net/config/ManifestConfigSource.java
@@ -61,6 +61,7 @@
             } catch (PackageManager.NameNotFoundException e) {
                 throw new RuntimeException("Failed to look up ApplicationInfo", e);
             }
+            int targetSdkVersion = info.targetSdkVersion;
             int configResourceId = 0;
             if (info != null && info.metaData != null) {
                 configResourceId = info.metaData.getInt(META_DATA_NETWORK_SECURITY_CONFIG);
@@ -74,14 +75,15 @@
                             + mContext.getResources().getResourceEntryName(configResourceId)
                             + " debugBuild: " + debugBuild);
                 }
-                source = new XmlConfigSource(mContext, configResourceId, debugBuild);
+                source = new XmlConfigSource(mContext, configResourceId, debugBuild,
+                        targetSdkVersion);
             } else {
                 if (DBG) {
                     Log.d(LOG_TAG, "No Network Security Config specified, using platform default");
                 }
                 boolean usesCleartextTraffic =
                         (info.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0;
-                source = new DefaultConfigSource(usesCleartextTraffic);
+                source = new DefaultConfigSource(usesCleartextTraffic, targetSdkVersion);
             }
             mConfigSource = source;
             return mConfigSource;
@@ -92,11 +94,11 @@
 
         private final NetworkSecurityConfig mDefaultConfig;
 
-        public DefaultConfigSource(boolean usesCleartextTraffic) {
-            mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder()
+        public DefaultConfigSource(boolean usesCleartextTraffic, int targetSdkVersion) {
+            mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(targetSdkVersion)
                     .setCleartextTrafficPermitted(usesCleartextTraffic)
                     .build();
-       }
+        }
 
         @Override
         public NetworkSecurityConfig getDefaultConfig() {
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index ebe14691..b3a37d0 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -16,6 +16,7 @@
 
 package android.security.net.config;
 
+import android.os.Build;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import java.security.cert.X509Certificate;
@@ -37,7 +38,6 @@
     public static final boolean DEFAULT_CLEARTEXT_TRAFFIC_PERMITTED = true;
     /** @hide */
     public static final boolean DEFAULT_HSTS_ENFORCED = false;
-    public static final NetworkSecurityConfig DEFAULT = getDefaultBuilder().build();
 
     private final boolean mCleartextTrafficPermitted;
     private final boolean mHstsEnforced;
@@ -117,12 +117,6 @@
         }
     }
 
-    void onTrustStoreChange() {
-        synchronized (mAnchorsLock) {
-            mAnchors = null;
-        }
-    }
-
     /** @hide */
     public TrustAnchor findTrustAnchorBySubjectAndPublicKey(X509Certificate cert) {
         for (CertificatesEntryRef ref : mCertificatesEntryRefs) {
@@ -154,6 +148,16 @@
         return certs;
     }
 
+    public void handleTrustStorageUpdate() {
+        synchronized (mAnchorsLock) {
+            mAnchors = null;
+            for (CertificatesEntryRef ref : mCertificatesEntryRefs) {
+                ref.handleTrustStorageUpdate();
+            }
+        }
+        getTrustManager().handleTrustStorageUpdate();
+    }
+
     /**
      * Return a {@link Builder} for the default {@code NetworkSecurityConfig}.
      *
@@ -163,21 +167,28 @@
      * <li>Cleartext traffic is permitted.</li>
      * <li>HSTS is not enforced.</li>
      * <li>No certificate pinning is used.</li>
-     * <li>The system and user added trusted certificate stores are trusted for connections.</li>
+     * <li>The system certificate store is trusted for connections.</li>
+     * <li>If the application targets API level 23 (Android M) or lower then the user certificate
+     * store is trusted by default as well.</li>
      * </ol>
      *
      * @hide
      */
-    public static final Builder getDefaultBuilder() {
-        return new Builder()
+    public static final Builder getDefaultBuilder(int targetSdkVersion) {
+        Builder builder = new Builder()
                 .setCleartextTrafficPermitted(DEFAULT_CLEARTEXT_TRAFFIC_PERMITTED)
                 .setHstsEnforced(DEFAULT_HSTS_ENFORCED)
                 // System certificate store, does not bypass static pins.
                 .addCertificatesEntryRef(
-                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false))
-                // User certificate store, does not bypass static pins.
-                .addCertificatesEntryRef(
-                        new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
+                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
+        // Applications targeting N and above must opt in into trusting the user added certificate
+        // store.
+        if (targetSdkVersion <= Build.VERSION_CODES.M) {
+            // User certificate store, does not bypass static pins.
+            builder.addCertificatesEntryRef(
+                    new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
+        }
+        return builder;
     }
 
     /**
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index 81cad79..3c292ca 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -20,6 +20,7 @@
 
 import android.util.ArrayMap;
 import java.io.IOException;
+import java.net.Socket;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.security.GeneralSecurityException;
@@ -29,14 +30,15 @@
 import java.util.Map;
 import java.util.Set;
 
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedTrustManager;
 
 /**
- * {@link X509TrustManager} that implements the trust anchor and pinning for a
+ * {@link X509ExtendedTrustManager} that implements the trust anchor and pinning for a
  * given {@link NetworkSecurityConfig}.
  * @hide
  */
-public class NetworkSecurityTrustManager implements X509TrustManager {
+public class NetworkSecurityTrustManager extends X509ExtendedTrustManager {
     // TODO: Replace this with a general X509TrustManager and use duck-typing.
     private final TrustManagerImpl mDelegate;
     private final NetworkSecurityConfig mNetworkSecurityConfig;
@@ -68,9 +70,37 @@
     }
 
     @Override
+    public void checkClientTrusted(X509Certificate[] certs, String authType, Socket socket)
+            throws CertificateException {
+        mDelegate.checkClientTrusted(certs, authType, socket);
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+            throws CertificateException {
+        mDelegate.checkClientTrusted(certs, authType, engine);
+    }
+
+    @Override
     public void checkServerTrusted(X509Certificate[] certs, String authType)
             throws CertificateException {
-        checkServerTrusted(certs, authType, null);
+        checkServerTrusted(certs, authType, (String) null);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] certs, String authType, Socket socket)
+            throws CertificateException {
+        List<X509Certificate> trustedChain =
+                mDelegate.getTrustedChainForServer(certs, authType, socket);
+        checkPins(trustedChain);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+            throws CertificateException {
+        List<X509Certificate> trustedChain =
+                mDelegate.getTrustedChainForServer(certs, authType, engine);
+        checkPins(trustedChain);
     }
 
     /**
@@ -157,4 +187,11 @@
             return mIssuers.clone();
         }
     }
+
+    public void handleTrustStorageUpdate() {
+        synchronized (mIssuersLock) {
+            mIssuers = null;
+            mDelegate.handleTrustStorageUpdate();
+        }
+    }
 }
diff --git a/core/java/android/security/net/config/ResourceCertificateSource.java b/core/java/android/security/net/config/ResourceCertificateSource.java
index 8803c4b..78669c5 100644
--- a/core/java/android/security/net/config/ResourceCertificateSource.java
+++ b/core/java/android/security/net/config/ResourceCertificateSource.java
@@ -44,7 +44,7 @@
 
     public ResourceCertificateSource(int resourceId, Context context) {
         mResourceId = resourceId;
-        mContext = context.getApplicationContext();
+        mContext = context;
     }
 
     private void ensureInitialized() {
@@ -115,4 +115,9 @@
         }
         return certs;
     }
+
+    @Override
+    public void handleTrustStorageUpdate() {
+        // Nothing to do, resource sources never change.
+    }
 }
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index b4e58e6..19f6887 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -16,24 +16,28 @@
 
 package android.security.net.config;
 
+import java.net.Socket;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.List;
 
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedTrustManager;
 
 /**
- * {@link X509TrustManager} based on an {@link ApplicationConfig}.
+ * {@link X509ExtendedTrustManager} based on an {@link ApplicationConfig}.
  *
- * <p>This {@code X509TrustManager} delegates to the specific trust manager for the hostname
- * being used for the connection (See {@link ApplicationConfig#getConfigForHostname(String)} and
+ * <p>This trust manager delegates to the specific trust manager for the hostname being used for
+ * the connection (See {@link ApplicationConfig#getConfigForHostname(String)} and
  * {@link NetworkSecurityTrustManager}).</p>
  *
  * Note that if the {@code ApplicationConfig} has per-domain configurations the hostname aware
  * {@link #checkServerTrusted(X509Certificate[], String String)} must be used instead of the normal
  * non-aware call.
  * @hide */
-public class RootTrustManager implements X509TrustManager {
+public class RootTrustManager extends X509ExtendedTrustManager {
     private final ApplicationConfig mConfig;
 
     public RootTrustManager(ApplicationConfig config) {
@@ -53,6 +57,54 @@
     }
 
     @Override
+    public void checkClientTrusted(X509Certificate[] certs, String authType, Socket socket)
+            throws CertificateException {
+        // Use the default configuration for all client authentication. Domain specific configs are
+        // only for use in checking server trust not client trust.
+        NetworkSecurityConfig config = mConfig.getConfigForHostname("");
+        config.getTrustManager().checkClientTrusted(certs, authType, socket);
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+            throws CertificateException {
+        // Use the default configuration for all client authentication. Domain specific configs are
+        // only for use in checking server trust not client trust.
+        NetworkSecurityConfig config = mConfig.getConfigForHostname("");
+        config.getTrustManager().checkClientTrusted(certs, authType, engine);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] certs, String authType, Socket socket)
+            throws CertificateException {
+        if (socket instanceof SSLSocket) {
+            SSLSocket sslSocket = (SSLSocket) socket;
+            SSLSession session = sslSocket.getHandshakeSession();
+            if (session == null) {
+                throw new CertificateException("Not in handshake; no session available");
+            }
+            String host = session.getPeerHost();
+            NetworkSecurityConfig config = mConfig.getConfigForHostname(host);
+            config.getTrustManager().checkServerTrusted(certs, authType, socket);
+        } else {
+            // Not an SSLSocket, use the hostname unaware checkServerTrusted.
+            checkServerTrusted(certs, authType);
+        }
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+            throws CertificateException {
+        SSLSession session = engine.getHandshakeSession();
+        if (session == null) {
+            throw new CertificateException("Not in handshake; no session available");
+        }
+        String host = session.getPeerHost();
+        NetworkSecurityConfig config = mConfig.getConfigForHostname(host);
+        config.getTrustManager().checkServerTrusted(certs, authType, engine);
+    }
+
+    @Override
     public void checkServerTrusted(X509Certificate[] certs, String authType)
             throws CertificateException {
         if (mConfig.hasPerDomainConfigs()) {
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index 1706e95..4a5f827 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -3,9 +3,11 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.util.ArraySet;
 import android.util.Base64;
 import android.util.Pair;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -34,20 +36,29 @@
     private final Object mLock = new Object();
     private final int mResourceId;
     private final boolean mDebugBuild;
+    private final int mTargetSdkVersion;
 
     private boolean mInitialized;
     private NetworkSecurityConfig mDefaultConfig;
     private Set<Pair<Domain, NetworkSecurityConfig>> mDomainMap;
     private Context mContext;
 
+    @VisibleForTesting
     public XmlConfigSource(Context context, int resourceId) {
         this(context, resourceId, false);
     }
 
+    @VisibleForTesting
     public XmlConfigSource(Context context, int resourceId, boolean debugBuild) {
+        this(context, resourceId, debugBuild, Build.VERSION_CODES.CUR_DEVELOPMENT);
+    }
+
+    public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
+            int targetSdkVersion) {
         mResourceId = resourceId;
         mContext = context;
         mDebugBuild = debugBuild;
+        mTargetSdkVersion = targetSdkVersion;
     }
 
     public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() {
@@ -100,7 +111,7 @@
         if (parser.next() != XmlPullParser.TEXT) {
             throw new ParserException(parser, "Missing pin digest");
         }
-        String digest = parser.getText();
+        String digest = parser.getText().trim();
         byte[] decodedDigest = null;
         try {
             decodedDigest = Base64.decode(digest, 0);
@@ -157,7 +168,7 @@
         if (parser.next() != XmlPullParser.TEXT) {
             throw new ParserException(parser, "Domain name missing");
         }
-        String domain = parser.getText().toLowerCase(Locale.US);
+        String domain = parser.getText().trim().toLowerCase(Locale.US);
         if (parser.next() != XmlPullParser.END_TAG) {
             throw new ParserException(parser, "domain contains additional elements");
         }
@@ -328,7 +339,7 @@
                 }
                 if (mDebugBuild) {
                     debugConfigBuilder =
-                            parseConfigEntry(parser, seenDomains, null, CONFIG_DEBUG).get(0).first;
+                            parseConfigEntry(parser, null, null, CONFIG_DEBUG).get(0).first;
                 } else {
                     XmlUtils.skipCurrentTag(parser);
                 }
@@ -337,11 +348,16 @@
                 XmlUtils.skipCurrentTag(parser);
             }
         }
+        // If debug is true and there was no debug-overrides in the file check for an extra
+        // _debug resource.
+        if (mDebugBuild && debugConfigBuilder == null) {
+            debugConfigBuilder = parseDebugOverridesResource();
+        }
 
         // Use the platform default as the parent of the base config for any values not provided
         // there. If there is no base config use the platform default.
         NetworkSecurityConfig.Builder platformDefaultBuilder =
-                NetworkSecurityConfig.getDefaultBuilder();
+                NetworkSecurityConfig.getDefaultBuilder(mTargetSdkVersion);
         addDebugAnchorsIfNeeded(debugConfigBuilder, platformDefaultBuilder);
         if (baseConfigBuilder != null) {
             baseConfigBuilder.setParent(platformDefaultBuilder);
@@ -374,6 +390,43 @@
         mDomainMap = configs;
     }
 
+    private NetworkSecurityConfig.Builder parseDebugOverridesResource()
+            throws IOException, XmlPullParserException, ParserException {
+        Resources resources = mContext.getResources();
+        String packageName = resources.getResourcePackageName(mResourceId);
+        String entryName = resources.getResourceEntryName(mResourceId);
+        int resId = resources.getIdentifier(entryName + "_debug", "xml", packageName);
+        // No debug-overrides resource was found, nothing to parse.
+        if (resId == 0) {
+            return null;
+        }
+        NetworkSecurityConfig.Builder debugConfigBuilder = null;
+        // Parse debug-overrides out of the _debug resource.
+        try (XmlResourceParser parser = resources.getXml(resId)) {
+            XmlUtils.beginDocument(parser, "network-security-config");
+            int outerDepth = parser.getDepth();
+            boolean seenDebugOverrides = false;
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                if ("debug-overrides".equals(parser.getName())) {
+                    if (seenDebugOverrides) {
+                        throw new ParserException(parser, "Only one debug-overrides allowed");
+                    }
+                    if (mDebugBuild) {
+                        debugConfigBuilder =
+                                parseConfigEntry(parser, null, null, CONFIG_DEBUG).get(0).first;
+                    } else {
+                        XmlUtils.skipCurrentTag(parser);
+                    }
+                    seenDebugOverrides = true;
+                } else {
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+        }
+
+        return debugConfigBuilder;
+    }
+
     public static class ParserException extends Exception {
 
         public ParserException(XmlPullParser parser, String message, Throwable cause) {
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index f5396a3..140341c 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -51,6 +51,30 @@
             = "android.service.carrier.CarrierMessagingService";
 
     /**
+     * The default bitmask value passed to the callback of {@link #onReceiveTextSms} with all
+     * {@code RECEIVE_OPTIONS_x} flags cleared to indicate that the message should be kept and a
+     * new message notification should be shown.
+     *
+     * @see #RECEIVE_OPTIONS_DROP
+     * @see #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE
+     */
+    public static final int RECEIVE_OPTIONS_DEFAULT = 0;
+
+    /**
+     * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
+     * indicate that the inbound SMS should be dropped.
+     */
+    public static final int RECEIVE_OPTIONS_DROP = 0x1;
+
+    /**
+     * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
+     * indicate that a new message notification should not be shown to the user when the
+     * credential-encrypted storage of the device is not available before the user unlocks the
+     * phone. It is only applicable to devices that support file-based encryption.
+     */
+    public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 0x2;
+
+    /**
      * Indicates that an SMS or MMS message was successfully sent.
      */
     public static final int SEND_STATUS_OK = 0;
@@ -96,7 +120,9 @@
      * @param subId SMS subscription ID of the SIM
      * @param callback result callback. Call with {@code true} to keep an inbound SMS message and
      *        deliver to SMS apps, and {@code false} to drop the message.
+     * @deprecated Use {@link #onReceiveTextSms} instead.
      */
+    @Deprecated
     public void onFilterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
             int subId, @NonNull ResultCallback<Boolean> callback) {
         // optional
@@ -107,6 +133,36 @@
     }
 
     /**
+     * Override this method to filter inbound SMS messages.
+     *
+     * <p>This method will be called once for every incoming text SMS. You can invoke the callback
+     * with a bitmask to tell the platform how to handle the SMS. For a SMS received on a
+     * file-based encryption capable device while the credential-encrypted storage is not available,
+     * this method will be called for the second time when the credential-encrypted storage becomes
+     * available after the user unlocks the phone, if the bit {@link #RECEIVE_OPTIONS_DROP} is not
+     * set when invoking the callback.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
+     * @param subId SMS subscription ID of the SIM
+     * @param callback result callback. Call with a bitmask integer to indicate how the incoming
+     *        text SMS should be handled by the platform. Use {@link #RECEIVE_OPTIONS_DROP} and
+     *        {@link #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE}
+     *        to set the flags in the bitmask.
+     */
+    public void onReceiveTextSms(@NonNull MessagePdu pdu, @NonNull String format,
+            int destPort, int subId, @NonNull final ResultCallback<Integer> callback) {
+        onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() {
+            @Override
+            public void onReceiveResult(Boolean result) throws RemoteException {
+                callback.onReceiveResult(result ? RECEIVE_OPTIONS_DEFAULT : RECEIVE_OPTIONS_DROP
+                    | RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE);
+            }
+        });
+    }
+
+    /**
      * Override this method to intercept text SMSs sent from the device.
      * @deprecated Override {@link #onSendTextSms} below instead.
      *
@@ -408,10 +464,11 @@
         @Override
         public void filterSms(MessagePdu pdu, String format, int destPort,
                               int subId, final ICarrierMessagingCallback callback) {
-            onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() {
+            onReceiveTextSms(pdu, format, destPort, subId,
+                new ResultCallback<Integer>() {
                     @Override
-                    public void onReceiveResult(final Boolean result) throws RemoteException {
-                        callback.onFilterComplete(result);
+                    public void onReceiveResult(Integer options) throws RemoteException {
+                        callback.onFilterComplete(options);
                     }
                 });
         }
diff --git a/core/java/android/service/carrier/ICarrierMessagingCallback.aidl b/core/java/android/service/carrier/ICarrierMessagingCallback.aidl
index 6118a20..2753669 100644
--- a/core/java/android/service/carrier/ICarrierMessagingCallback.aidl
+++ b/core/java/android/service/carrier/ICarrierMessagingCallback.aidl
@@ -22,7 +22,7 @@
  * @hide
  */
 oneway interface ICarrierMessagingCallback {
-    void onFilterComplete(boolean keepMessage);
+    void onFilterComplete(int result);
     void onSendSmsComplete(int result, int messageRef);
     void onSendMultipartSmsComplete(int result, in int[] messageRefs);
     void onSendMmsComplete(int result, in byte[] sendConfPdu);
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 816ecde..0557d13 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -35,7 +35,6 @@
 import android.view.ActionMode;
 import android.view.Display;
 import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
@@ -367,11 +366,6 @@
     @Override
     public void onActionModeFinished(ActionMode mode) {
     }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
-    }
     // end Window.Callback methods
 
     // begin public api
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 11737c6..0163b47 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -16,32 +16,56 @@
 
 package android.service.notification;
 
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.app.AutomaticZenRule;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
- * Condition information from condition providers. Used to tell the system to enter Do Not Disturb
- * mode and request that the system exit Do Not Disturb mode.
+ * The current condition of an {@link android.app.AutomaticZenRule}, provided by the
+ * {@link ConditionProviderService} that owns the rule. Used to tell the system to enter Do Not
+ * Disturb mode and request that the system exit Do Not Disturb mode.
  */
 public class Condition implements Parcelable {
 
+    @SystemApi
     public static final String SCHEME = "condition";
 
+    /** @hide */
+    @IntDef({STATE_FALSE, STATE_TRUE, STATE_TRUE, STATE_ERROR})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    /**
+     * Indicates that Do Not Disturb should be turned off. Note that all Conditions from all
+     * {@link ConditionProviderService} providers must be off for Do Not Disturb to be turned off on
+     * the device.
+     */
     public static final int STATE_FALSE = 0;
+    /**
+     * Indicates that Do Not Disturb should be turned on.
+     */
     public static final int STATE_TRUE = 1;
+
+    @SystemApi
     public static final int STATE_UNKNOWN = 2;
+    @SystemApi
     public static final int STATE_ERROR = 3;
 
+    @SystemApi
     public static final int FLAG_RELEVANT_NOW = 1 << 0;
+    @SystemApi
     public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
 
     /**
-     * The URI representing the condition being updated.
+     * The URI representing the rule being updated.
      * See {@link android.app.AutomaticZenRule#getConditionId()}.
      */
     public final Uri id;
@@ -52,23 +76,17 @@
      */
     public final String summary;
 
-    /**
-     * Additional information about what the rule encoded in {@link #id} means when it is enabled.
-     * User visible if the state of the condition is {@link #STATE_TRUE}.
-     */
+    @SystemApi
     public final String line1;
-
-    /**
-     * Additional information about what the rule encoded in {@link #id} means when it is enabled.
-     * User visible if the state of the condition is {@link #STATE_TRUE}.
-     */
+    @SystemApi
     public final String line2;
 
     /**
-     * The state of this condition. {@link #STATE_TRUE} will enable Do Not Disturb mode. Any other
-     * state will turn Do Not Disturb off for this rule. Note that Do Not Disturb might still be
-     * enabled globally if other conditions are in a {@link #STATE_TRUE} state.
+     * The state of this condition. {@link #STATE_TRUE} will enable Do Not Disturb mode.
+     * {@link #STATE_FALSE} will turn Do Not Disturb off for this rule. Note that Do Not Disturb
+     * might still be enabled globally if other conditions are in a {@link #STATE_TRUE} state.
      */
+    @State
     public final int state;
 
     @SystemApi
@@ -76,8 +94,13 @@
     @SystemApi
     public final int icon;
 
-    public Condition(Uri id, String summary, String line1, String line2, int state) {
-        this(id, summary, line1, line2, -1, state, FLAG_RELEVANT_ALWAYS);
+    /**
+     * An object representing the current state of a {@link android.app.AutomaticZenRule}.
+     * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule
+     * @param summary a user visible description of the rule state.
+     */
+    public Condition(Uri id, String summary, int state) {
+        this(id, summary, "", "", -1, state, FLAG_RELEVANT_ALWAYS);
     }
 
     @SystemApi
@@ -85,8 +108,6 @@
             int state, int flags) {
         if (id == null) throw new IllegalArgumentException("id 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.summary = summary;
@@ -97,7 +118,7 @@
         this.flags = flags;
     }
 
-    private Condition(Parcel source) {
+    public Condition(Parcel source) {
         this((Uri)source.readParcelable(Condition.class.getClassLoader()),
                 source.readString(),
                 source.readString(),
@@ -135,6 +156,7 @@
             .append(']').toString();
     }
 
+    @SystemApi
     public static String stateToString(int state) {
         if (state == STATE_FALSE) return "STATE_FALSE";
         if (state == STATE_TRUE) return "STATE_TRUE";
@@ -143,6 +165,7 @@
         throw new IllegalArgumentException("state is invalid: " + state);
     }
 
+    @SystemApi
     public static String relevanceToString(int flags) {
         final boolean now = (flags & FLAG_RELEVANT_NOW) != 0;
         final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0;
@@ -175,6 +198,7 @@
         return 0;
     }
 
+    @SystemApi
     public Condition copy() {
         final Parcel parcel = Parcel.obtain();
         try {
@@ -186,10 +210,14 @@
         }
     }
 
+    @SystemApi
     public static Uri.Builder newId(Context context) {
-        return new Uri.Builder().scheme(SCHEME).authority(context.getPackageName());
+        return new Uri.Builder()
+                .scheme(Condition.SCHEME)
+                .authority(context.getPackageName());
     }
 
+    @SystemApi
     public static boolean isValidId(Uri id, String pkg) {
         return id != null && SCHEME.equals(id.getScheme()) && pkg.equals(id.getAuthority());
     }
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index adcc9d6..44c3887 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -102,9 +102,6 @@
      */
     abstract public void onConnected();
 
-    /**
-     * @removed
-     */
     @SystemApi
     public void onRequestConditions(int relevance) {}
 
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index a0de17f..8c35901 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -23,7 +23,7 @@
 /** @hide */
 oneway interface INotificationListener
 {
-    // listeners and assistants
+    // listeners and rankers
     void onListenerConnected(in NotificationRankingUpdate update);
     void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
@@ -33,7 +33,7 @@
     void onListenerHintsChanged(int hints);
     void onInterruptionFilterChanged(int interruptionFilter);
 
-    // assistants only
+    // rankers only
     void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
     void onNotificationVisibilityChanged(String key, long time, boolean visible);
     void onNotificationClick(String key, long time);
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
deleted file mode 100644
index b5387f1..0000000
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.notification;
-
-import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
-import android.app.INotificationManager;
-import android.app.Notification;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-/**
- * A service that helps the user manage notifications by modifying the
- * relative importance of notifications.
- * <p>To extend this class, you must declare the service in your manifest file with
- * the {@link android.Manifest.permission#BIND_NOTIFICATION_ASSISTANT_SERVICE} permission
- * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
- * <pre>
- * &lt;service android:name=".NotificationAssistant"
- *          android:label="&#64;string/service_name"
- *          android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE">
- *     &lt;intent-filter>
- *         &lt;action android:name="android.service.notification.NotificationAssistantService" />
- *     &lt;/intent-filter>
- * &lt;/service></pre>
- * @hide
- */
-@SystemApi
-public abstract class NotificationAssistantService extends NotificationListenerService {
-    private static final String TAG = "NotificationAssistant";
-
-    /**
-     * The {@link Intent} that must be declared as handled by the service.
-     */
-    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE
-            = "android.service.notification.NotificationAssistantService";
-
-    /** Notification was canceled by the status bar reporting a click. */
-    public static final int REASON_DELEGATE_CLICK = 1;
-
-    /** Notification was canceled by the status bar reporting a user dismissal. */
-    public static final int REASON_DELEGATE_CANCEL = 2;
-
-    /** Notification was canceled by the status bar reporting a user dismiss all. */
-    public static final int REASON_DELEGATE_CANCEL_ALL = 3;
-
-    /** Notification was canceled by the status bar reporting an inflation error. */
-    public static final int REASON_DELEGATE_ERROR = 4;
-
-    /** Notification was canceled by the package manager modifying the package. */
-    public static final int REASON_PACKAGE_CHANGED = 5;
-
-    /** Notification was canceled by the owning user context being stopped. */
-    public static final int REASON_USER_STOPPED = 6;
-
-    /** Notification was canceled by the user banning the package. */
-    public static final int REASON_PACKAGE_BANNED = 7;
-
-    /** Notification was canceled by the app canceling this specific notification. */
-    public static final int REASON_APP_CANCEL = 8;
-
-    /** Notification was canceled by the app cancelling all its notifications. */
-    public static final int REASON_APP_CANCEL_ALL = 9;
-
-    /** Notification was canceled by a listener reporting a user dismissal. */
-    public static final int REASON_LISTENER_CANCEL = 10;
-
-    /** Notification was canceled by a listener reporting a user dismiss all. */
-    public static final int REASON_LISTENER_CANCEL_ALL = 11;
-
-    /** Notification was canceled because it was a member of a canceled group. */
-    public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
-
-    /** Notification was canceled because it was an invisible member of a group. */
-    public static final int REASON_GROUP_OPTIMIZATION = 13;
-
-    /** Notification was canceled by the device administrator suspending the package. */
-    public static final int REASON_PACKAGE_SUSPENDED = 14;
-
-    /** Notification was canceled by the owning managed profile being turned off. */
-    public static final int REASON_PROFILE_TURNED_OFF = 15;
-
-    public class Adjustment {
-        int mImportance;
-        CharSequence mExplanation;
-        Uri mReference;
-
-        /**
-         * Create a notification importance adjustment.
-         *
-         * @param importance The final importance of the notification.
-         * @param explanation A human-readable justification for the adjustment.
-         * @param reference A reference to an external object that augments the
-         *                  explanation, such as a
-         *                  {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
-         *                  or null.
-         */
-        public Adjustment(int importance, CharSequence explanation, Uri reference) {
-            mImportance = importance;
-            mExplanation = explanation;
-            mReference = reference;
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        if (mWrapper == null) {
-            mWrapper = new NotificationAssistantWrapper();
-        }
-        return mWrapper;
-    }
-
-    /**
-     * A notification was posted by an app. Called before alert.
-     *
-     * @param sbn the new notification
-     * @param importance the initial importance of the notification.
-     * @param user true if the initial importance reflects an explicit user preference.
-     * @return an adjustment or null to take no action, within 100ms.
-     */
-    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
-          int importance, boolean user);
-
-    /**
-     * The visibility of a notification has changed.
-     *
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     * @param visible true if the notification became visible, false if hidden.
-     */
-    public void onNotificationVisibilityChanged(String key, long time, boolean visible)
-    {
-        // Do nothing, Override this to collect visibility statistics.
-    }
-
-    /**
-     * The user clicked on a notification.
-     *
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     */
-    public void onNotificationClick(String key, long time)
-    {
-        // Do nothing, Override this to collect click statistics
-    }
-
-    /**
-     * The user clicked on a notification action.
-     *
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     * @param actionIndex the index of the action button that was pressed.
-     */
-    public void onNotificationActionClick(String key, long time, int actionIndex)
-    {
-        // Do nothing, Override this to collect action button click statistics
-    }
-
-    /**
-     * A notification was removed.
-
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
-     */
-    public void onNotificationRemoved(String key, long time, int reason) {
-        // Do nothing, Override this to collect dismissal statistics
-    }
-
-    /**
-     * Change the importance of an existing notification.  N.B. this won’t cause
-     * an existing notification to alert, but might allow a future update to
-     * this notification to alert.
-     *
-     * @param key the notification key
-     * @param adjustment the new importance with an explanation
-     */
-    public final void adjustImportance(String key, Adjustment adjustment)
-    {
-        if (!isBound()) return;
-        try {
-            getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
-                    adjustment.mImportance, adjustment.mExplanation);
-        } catch (android.os.RemoteException ex) {
-            Log.v(TAG, "Unable to contact notification manager", ex);
-        }
-    }
-
-    private class NotificationAssistantWrapper extends NotificationListenerWrapper {
-        @Override
-        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
-                                           int importance, boolean user) throws RemoteException {
-            StatusBarNotification sbn;
-            try {
-                sbn = sbnHolder.get();
-            } catch (RemoteException e) {
-                Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
-                return;
-            }
-
-            try {
-                Adjustment adjustment =
-                    NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
-                if (adjustment != null) {
-                    adjustImportance(sbn.getKey(), adjustment);
-                }
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationEnqueued", t);
-            }
-        }
-
-        @Override
-        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
-                throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
-                        visible);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
-            }
-        }
-
-        @Override
-        public void onNotificationClick(String key, long time) throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationClick(key, time);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationClick", t);
-            }
-        }
-
-        @Override
-        public void onNotificationActionClick(String key, long time, int actionIndex)
-                throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationActionClick", t);
-            }
-        }
-
-        @Override
-        public void onNotificationRemovedReason(String key, long time, int reason)
-                throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationRemoved", t);
-            }
-        }
-    }
-}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 7b461b1..afdd1d4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -15,8 +15,12 @@
  */
 
 package android.service.notification;
-import android.service.notification.IStatusBarNotificationHolder;
 
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
 import android.app.INotificationManager;
@@ -42,7 +46,11 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
-
+import android.widget.RemoteViews;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.SomeArgs;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -61,16 +69,6 @@
  *         &lt;action android:name="android.service.notification.NotificationListenerService" />
  *     &lt;/intent-filter>
  * &lt;/service></pre>
- * <p> Typically, while enabled in user settings, this service will be bound on boot or when a
- * settings change occurs that could affect whether this service should run.  However, for some
- * system usage modes, the you may instead specify that this service is instead bound and unbound
- * in response to mode changes by including a category in the intent filter.  Currently
- * supported categories are:
- * <ul>
- *   <li>{@link #CATEGORY_VR_NOTIFICATIONS} - this service is bound when an Activity has enabled
- *   VR mode. {@see android.app.Activity#setVrMode(boolean)}.</li>
- * </ul>
- * </p>
  */
 public abstract class NotificationListenerService extends Service {
     // TAG = "NotificationListenerService[MySubclass]"
@@ -160,19 +158,30 @@
     @SystemApi
     public static final int TRIM_LIGHT = 1;
 
+    private final Object mLock = new Object();
+
+    private Handler mHandler;
+
     /** @hide */
     protected NotificationListenerWrapper mWrapper = null;
+
+    @GuardedBy("mLock")
     private RankingMap mRankingMap;
 
     private INotificationManager mNoMan;
 
-    /** Only valid after a successful call to (@link registerAsService}. */
-    private int mCurrentUser;
+    /**
+     * Only valid after a successful call to (@link registerAsService}.
+     * @hide
+     */
+    protected int mCurrentUser;
 
-
-    // This context is required for system services since NotificationListenerService isn't
-    // started as a real Service and hence no context is available.
-    private Context mSystemContext;
+    /**
+     * This context is required for system services since NotificationListenerService isn't
+     * started as a real Service and hence no context is available..
+     * @hide
+     */
+    protected Context mSystemContext;
 
     /**
      * The {@link Intent} that must be declared as handled by the service.
@@ -181,16 +190,11 @@
     public static final String SERVICE_INTERFACE
             = "android.service.notification.NotificationListenerService";
 
-    /**
-     * If this category is declared in the application manifest for a service of this type, this
-     * service will be bound when VR mode is enabled, and unbound when VR mode is disabled rather
-     * than the normal lifecycle for a notification service.
-     *
-     * {@see android.app.Activity#setVrMode(boolean)}
-     */
-    @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
-    public static final String CATEGORY_VR_NOTIFICATIONS =
-        "android.intent.category.vr.notifications";
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new MyHandler(getMainLooper());
+    }
 
     /**
      * Implement this method to learn about new notifications as they are posted by apps.
@@ -639,7 +643,9 @@
      * @return A {@link RankingMap} object providing access to ranking information
      */
     public RankingMap getCurrentRanking() {
-        return mRankingMap;
+        synchronized (mLock) {
+            return mRankingMap;
+        }
     }
 
     @Override
@@ -674,13 +680,14 @@
     @SystemApi
     public void registerAsSystemService(Context context, ComponentName componentName,
             int currentUser) throws RemoteException {
-        mSystemContext = context;
         if (mWrapper == null) {
             mWrapper = new NotificationListenerWrapper();
         }
+        mSystemContext = context;
         INotificationManager noMan = getNotificationInterface();
         noMan.registerListener(mWrapper, componentName, currentUser);
         mCurrentUser = currentUser;
+        mHandler = new MyHandler(context.getMainLooper());
     }
 
     /**
@@ -707,7 +714,7 @@
      * <P>The service should wait for the {@link #onListenerConnected()} event
      * before performing any operations.
      */
-    public static final void requestRebind(ComponentName componentName)
+    public static void requestRebind(ComponentName componentName)
             throws RemoteException {
         INotificationManager noMan = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -752,9 +759,16 @@
     private void maybePopulateRemoteViews(Notification notification) {
         if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
             Builder builder = Builder.recoverBuilder(getContext(), notification);
-            notification.contentView = builder.makeContentView();
-            notification.bigContentView = builder.makeBigContentView();
-            notification.headsUpContentView = builder.makeHeadsUpContentView();
+
+            // Some styles wrap Notification's contentView, bigContentView and headsUpContentView.
+            // First inflate them all, only then set them to avoid recursive wrapping.
+            RemoteViews content = builder.createContentView();
+            RemoteViews big = builder.createBigContentView();
+            RemoteViews headsUp = builder.createHeadsUpContentView();
+
+            notification.contentView = content;
+            notification.bigContentView = big;
+            notification.headsUpContentView = headsUp;
         }
     }
 
@@ -772,7 +786,6 @@
             }
 
             try {
-                Notification notification = sbn.getNotification();
                 // convert icon metadata to legacy format for older clients
                 createLegacyIconExtras(sbn.getNotification());
                 maybePopulateRemoteViews(sbn.getNotification());
@@ -784,20 +797,23 @@
             }
 
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    if (sbn != null) {
-                        NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
-                    } else {
-                        // still pass along the ranking map, it may contain other information
-                        NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
-                    }
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onNotificationPosted", t);
+            synchronized (mLock) {
+                applyUpdateLocked(update);
+                if (sbn != null) {
+                    SomeArgs args = SomeArgs.obtain();
+                    args.arg1 = sbn;
+                    args.arg2 = mRankingMap;
+                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
+                            args).sendToTarget();
+                } else {
+                    // still pass along the ranking map, it may contain other information
+                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
+                            mRankingMap).sendToTarget();
                 }
             }
+
         }
+
         @Override
         public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
                 NotificationRankingUpdate update) {
@@ -809,56 +825,48 @@
                 return;
             }
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    NotificationListenerService.this.onNotificationRemoved(sbn, mRankingMap);
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onNotificationRemoved", t);
-                }
+            synchronized (mLock) {
+                applyUpdateLocked(update);
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = sbn;
+                args.arg2 = mRankingMap;
+                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED,
+                        args).sendToTarget();
             }
+
         }
+
         @Override
         public void onListenerConnected(NotificationRankingUpdate update) {
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    NotificationListenerService.this.onListenerConnected();
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onListenerConnected", t);
-                }
+            synchronized (mLock) {
+                applyUpdateLocked(update);
             }
+            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_CONNECTED).sendToTarget();
         }
+
         @Override
         public void onNotificationRankingUpdate(NotificationRankingUpdate update)
                 throws RemoteException {
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onNotificationRankingUpdate", t);
-                }
+            synchronized (mLock) {
+                applyUpdateLocked(update);
+                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
+                        mRankingMap).sendToTarget();
             }
+
         }
+
         @Override
         public void onListenerHintsChanged(int hints) throws RemoteException {
-            try {
-                NotificationListenerService.this.onListenerHintsChanged(hints);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onListenerHintsChanged", t);
-            }
+            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_HINTS_CHANGED,
+                    hints, 0).sendToTarget();
         }
 
         @Override
         public void onInterruptionFilterChanged(int interruptionFilter) throws RemoteException {
-            try {
-                NotificationListenerService.this.onInterruptionFilterChanged(interruptionFilter);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onInterruptionFilterChanged", t);
-            }
+            mHandler.obtainMessage(MyHandler.MSG_ON_INTERRUPTION_FILTER_CHANGED,
+                    interruptionFilter, 0).sendToTarget();
         }
 
         @Override
@@ -891,11 +899,12 @@
         }
     }
 
-    private void applyUpdate(NotificationRankingUpdate update) {
+    private void applyUpdateLocked(NotificationRankingUpdate update) {
         mRankingMap = new RankingMap(update);
     }
 
-    private Context getContext() {
+    /** @hide */
+    protected Context getContext() {
         if (mSystemContext != null) {
             return mSystemContext;
         }
@@ -911,6 +920,14 @@
      * current {@link RankingMap}.
      */
     public static class Ranking {
+
+        /** @hide */
+        @IntDef({VISIBILITY_NO_OVERRIDE, IMPORTANCE_UNSPECIFIED, IMPORTANCE_NONE,
+                IMPORTANCE_MIN, IMPORTANCE_LOW, IMPORTANCE_DEFAULT, IMPORTANCE_HIGH,
+                IMPORTANCE_MAX})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Importance {}
+
         /** Value signifying that the user has not expressed a per-app visibility override value.
          * @hide */
         public static final int VISIBILITY_NO_OVERRIDE = -1000;
@@ -929,26 +946,31 @@
         public static final int IMPORTANCE_NONE = 0;
 
         /**
-         * Low notification importance: only shows in the shade, below the fold.
+         * Min notification importance: only shows in the shade, below the fold.
          */
-        public static final int IMPORTANCE_LOW = 1;
+        public static final int IMPORTANCE_MIN = 1;
 
         /**
-         * Default notification importance: shows everywhere, but is not intrusive.
+         * Low notification importance: shows everywhere, but is not intrusive.
          */
-        public static final int IMPORTANCE_DEFAULT = 2;
+        public static final int IMPORTANCE_LOW = 2;
 
         /**
-         * Higher notification importance: shows everywhere, makes noise,
+         * Default notification importance: shows everywhere, allowed to makes noise,
          * but does not visually intrude.
          */
-        public static final int IMPORTANCE_HIGH = 3;
+        public static final int IMPORTANCE_DEFAULT = 3;
 
         /**
-         * Highest notification importance: shows everywhere, makes noise,
-         * and also visually intrudes.
+         * Higher notification importance: shows everywhere, allowed to makes noise and peek.
          */
-        public static final int IMPORTANCE_MAX = 4;
+        public static final int IMPORTANCE_HIGH = 4;
+
+        /**
+         * Highest notification importance: shows everywhere, allowed to makes noise, peek, and
+         * use full screen intents.
+         */
+        public static final int IMPORTANCE_MAX = 5;
 
         private String mKey;
         private int mRank = -1;
@@ -956,7 +978,7 @@
         private boolean mMatchesInterruptionFilter;
         private int mVisibilityOverride;
         private int mSuppressedVisualEffects;
-        private int mImportance;
+        private @Importance int mImportance;
         private CharSequence mImportanceExplanation;
 
         public Ranking() {}
@@ -1022,7 +1044,7 @@
          *
          * @return the rank of the notification
          */
-        public int getImportance() {
+        public @Importance int getImportance() {
             return mImportance;
         }
 
@@ -1041,7 +1063,7 @@
                 CharSequence explanation) {
             mKey = key;
             mRank = rank;
-            mIsAmbient = importance < IMPORTANCE_DEFAULT;
+            mIsAmbient = importance < IMPORTANCE_LOW;
             mMatchesInterruptionFilter = matchesInterruptionFilter;
             mVisibilityOverride = visibilityOverride;
             mSuppressedVisualEffects = suppressedVisualEffects;
@@ -1058,6 +1080,8 @@
                     return "UNSPECIFIED";
                 case IMPORTANCE_NONE:
                     return "NONE";
+                case IMPORTANCE_MIN:
+                    return "MIN";
                 case IMPORTANCE_LOW:
                     return "LOW";
                 case IMPORTANCE_DEFAULT:
@@ -1264,4 +1288,57 @@
             }
         };
     }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_ON_NOTIFICATION_POSTED = 1;
+        public static final int MSG_ON_NOTIFICATION_REMOVED = 2;
+        public static final int MSG_ON_LISTENER_CONNECTED = 3;
+        public static final int MSG_ON_NOTIFICATION_RANKING_UPDATE = 4;
+        public static final int MSG_ON_LISTENER_HINTS_CHANGED = 5;
+        public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_NOTIFICATION_POSTED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    RankingMap rankingMap = (RankingMap) args.arg2;
+                    args.recycle();
+                    onNotificationPosted(sbn, rankingMap);
+                } break;
+
+                case MSG_ON_NOTIFICATION_REMOVED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    RankingMap rankingMap = (RankingMap) args.arg2;
+                    args.recycle();
+                    onNotificationRemoved(sbn, rankingMap);
+                } break;
+
+                case MSG_ON_LISTENER_CONNECTED: {
+                    onListenerConnected();
+                } break;
+
+                case MSG_ON_NOTIFICATION_RANKING_UPDATE: {
+                    RankingMap rankingMap = (RankingMap) msg.obj;
+                    onNotificationRankingUpdate(rankingMap);
+                } break;
+
+                case MSG_ON_LISTENER_HINTS_CHANGED: {
+                    final int hints = msg.arg1;
+                    onListenerHintsChanged(hints);
+                } break;
+
+                case MSG_ON_INTERRUPTION_FILTER_CHANGED: {
+                    final int interruptionFilter = msg.arg1;
+                    onInterruptionFilterChanged(interruptionFilter);
+                } break;
+            }
+        }
+    }
 }
diff --git a/core/java/android/service/notification/NotificationRankerService.java b/core/java/android/service/notification/NotificationRankerService.java
new file mode 100644
index 0000000..47fdac6
--- /dev/null
+++ b/core/java/android/service/notification/NotificationRankerService.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+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.os.SomeArgs;
+
+/**
+ * A service that helps the user manage notifications. This class is only used to
+ * extend the framework service and may not be implemented by non-framework components.
+ * @hide
+ */
+@SystemApi
+public abstract class NotificationRankerService extends NotificationListenerService {
+    private static final String TAG = "NotificationRankers";
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE
+            = "android.service.notification.NotificationRankerService";
+
+    /** Notification was canceled by the status bar reporting a click. */
+    public static final int REASON_DELEGATE_CLICK = 1;
+
+    /** Notification was canceled by the status bar reporting a user dismissal. */
+    public static final int REASON_DELEGATE_CANCEL = 2;
+
+    /** Notification was canceled by the status bar reporting a user dismiss all. */
+    public static final int REASON_DELEGATE_CANCEL_ALL = 3;
+
+    /** Notification was canceled by the status bar reporting an inflation error. */
+    public static final int REASON_DELEGATE_ERROR = 4;
+
+    /** Notification was canceled by the package manager modifying the package. */
+    public static final int REASON_PACKAGE_CHANGED = 5;
+
+    /** Notification was canceled by the owning user context being stopped. */
+    public static final int REASON_USER_STOPPED = 6;
+
+    /** Notification was canceled by the user banning the package. */
+    public static final int REASON_PACKAGE_BANNED = 7;
+
+    /** Notification was canceled by the app canceling this specific notification. */
+    public static final int REASON_APP_CANCEL = 8;
+
+    /** Notification was canceled by the app cancelling all its notifications. */
+    public static final int REASON_APP_CANCEL_ALL = 9;
+
+    /** Notification was canceled by a listener reporting a user dismissal. */
+    public static final int REASON_LISTENER_CANCEL = 10;
+
+    /** Notification was canceled by a listener reporting a user dismiss all. */
+    public static final int REASON_LISTENER_CANCEL_ALL = 11;
+
+    /** Notification was canceled because it was a member of a canceled group. */
+    public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
+
+    /** Notification was canceled because it was an invisible member of a group. */
+    public static final int REASON_GROUP_OPTIMIZATION = 13;
+
+    /** Notification was canceled by the device administrator suspending the package. */
+    public static final int REASON_PACKAGE_SUSPENDED = 14;
+
+    /** Notification was canceled by the owning managed profile being turned off. */
+    public static final int REASON_PROFILE_TURNED_OFF = 15;
+
+    public class Adjustment {
+        int mImportance;
+        CharSequence mExplanation;
+        Uri mReference;
+
+        /**
+         * Create a notification importance adjustment.
+         *
+         * @param importance The final importance of the notification.
+         * @param explanation A human-readable justification for the adjustment.
+         * @param reference A reference to an external object that augments the
+         *                  explanation, such as a
+         *                  {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
+         *                  or null.
+         */
+        public Adjustment(int importance, CharSequence explanation, Uri reference) {
+            mImportance = importance;
+            mExplanation = explanation;
+            mReference = reference;
+        }
+    }
+
+    private Handler mHandler;
+
+    /** @hide */
+    @Override
+    public void registerAsSystemService(Context context, ComponentName componentName,
+            int currentUser)  {
+        throw new UnsupportedOperationException("the ranker lifecycle is managed by the system.");
+    }
+
+    /** @hide */
+    @Override
+    public void unregisterAsSystemService()  {
+        throw new UnsupportedOperationException("the ranker lifecycle is managed by the system.");
+    }
+
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new MyHandler(getContext().getMainLooper());
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (mWrapper == null) {
+            mWrapper = new NotificationRankingServiceWrapper();
+        }
+        return mWrapper;
+    }
+
+    /**
+     * A notification was posted by an app. Called before alert.
+     *
+     * @param sbn the new notification
+     * @param importance the initial importance of the notification.
+     * @param user true if the initial importance reflects an explicit user preference.
+     * @return an adjustment or null to take no action, within 100ms.
+     */
+    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
+          int importance, boolean user);
+
+    /**
+     * The visibility of a notification has changed.
+     *
+     * @param key the notification key
+     * @param time milliseconds since midnight, January 1, 1970 UTC.
+     * @param visible true if the notification became visible, false if hidden.
+     */
+    public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+    {
+        // Do nothing, Override this to collect visibility statistics.
+    }
+
+    /**
+     * The user clicked on a notification.
+     *
+     * @param key the notification key
+     * @param time milliseconds since midnight, January 1, 1970 UTC.
+     */
+    public void onNotificationClick(String key, long time)
+    {
+        // Do nothing, Override this to collect click statistics
+    }
+
+    /**
+     * The user clicked on a notification action.
+     *
+     * @param key the notification key
+     * @param time milliseconds since midnight, January 1, 1970 UTC.
+     * @param actionIndex the index of the action button that was pressed.
+     */
+    public void onNotificationActionClick(String key, long time, int actionIndex)
+    {
+        // Do nothing, Override this to collect action button click statistics
+    }
+
+    /**
+     * A notification was removed.
+
+     * @param key the notification key
+     * @param time milliseconds since midnight, January 1, 1970 UTC.
+     * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
+     */
+    public void onNotificationRemoved(String key, long time, int reason) {
+        // Do nothing, Override this to collect dismissal statistics
+    }
+
+    /**
+     * Change the importance of an existing notification.  N.B. this won’t cause
+     * an existing notification to alert, but might allow a future update to
+     * this notification to alert.
+     *
+     * @param key the notification key
+     * @param adjustment the new importance with an explanation
+     */
+    public final void adjustImportance(String key, Adjustment adjustment) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().setImportanceFromRankerService(mWrapper, key,
+                    adjustment.mImportance, adjustment.mExplanation);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    private class NotificationRankingServiceWrapper extends NotificationListenerWrapper {
+        @Override
+        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
+                int importance, boolean user) {
+            StatusBarNotification sbn;
+            try {
+                sbn = sbnHolder.get();
+            } catch (RemoteException e) {
+                Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
+                return;
+            }
+
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = sbn;
+            args.argi1 = importance;
+            args.argi2 = user ? 1 : 0;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
+                    args).sendToTarget();
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(String key, long time, boolean visible) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            args.argi1 = visible ? 1 : 0;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_VISIBILITY_CHANGED,
+                    args).sendToTarget();
+        }
+
+        @Override
+        public void onNotificationClick(String key, long time) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_CLICK,
+                    args).sendToTarget();
+        }
+
+        @Override
+        public void onNotificationActionClick(String key, long time, int actionIndex) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            args.argi1 = actionIndex;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ACTION_CLICK,
+                    args).sendToTarget();
+        }
+
+        @Override
+        public void onNotificationRemovedReason(String key, long time, int reason) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            args.argi1 = reason;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED_REASON,
+                    args).sendToTarget();
+        }
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
+        public static final int MSG_ON_NOTIFICATION_VISIBILITY_CHANGED = 2;
+        public static final int MSG_ON_NOTIFICATION_CLICK = 3;
+        public static final int MSG_ON_NOTIFICATION_ACTION_CLICK = 4;
+        public static final int MSG_ON_NOTIFICATION_REMOVED_REASON = 5;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_NOTIFICATION_ENQUEUED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    final int importance = args.argi1;
+                    final boolean user = args.argi2 == 1;
+                    args.recycle();
+                    Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
+                    if (adjustment != null) {
+                        adjustImportance(sbn.getKey(), adjustment);
+                    }
+                } break;
+
+                case MSG_ON_NOTIFICATION_VISIBILITY_CHANGED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    final boolean visible = args.argi1 == 1;
+                    args.recycle();
+                    onNotificationVisibilityChanged(key, time, visible);
+                } break;
+
+                case MSG_ON_NOTIFICATION_CLICK: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    args.recycle();
+                    onNotificationClick(key, time);
+                } break;
+
+                case MSG_ON_NOTIFICATION_ACTION_CLICK: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    final int actionIndex = args.argi1;
+                    args.recycle();
+                    onNotificationActionClick(key, time, actionIndex);
+                } break;
+
+                case MSG_ON_NOTIFICATION_REMOVED_REASON: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    final int reason = args.argi1;
+                    args.recycle();
+                    onNotificationRemoved(key, time, reason);
+                } break;
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/notification/ZenModeConfig.aidl b/core/java/android/service/notification/ZenModeConfig.aidl
index c73b75e..4644103 100644
--- a/core/java/android/service/notification/ZenModeConfig.aidl
+++ b/core/java/android/service/notification/ZenModeConfig.aidl
@@ -17,4 +17,5 @@
 package android.service.notification;
 
 parcelable ZenModeConfig;
+parcelable ZenModeConfig.ZenRule;
 
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 97939a9..27315ee 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1017,7 +1017,7 @@
     public static class ZenRule implements Parcelable {
         public boolean enabled;
         public boolean snoozing;         // user manually disabled this instance
-        public String name;              // required for automatic (unique)
+        public String name;              // required for automatic
         public int zenMode;
         public Uri conditionId;          // required for automatic
         public Condition condition;      // optional
diff --git a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
index 52db223..626b408 100644
--- a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
+++ b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
@@ -35,4 +35,6 @@
 
     void setOemUnlockEnabled(boolean enabled);
     boolean getOemUnlockEnabled();
+    int getFlashLockState();
 }
+
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 0ffdf68..cfeed51 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -17,9 +17,13 @@
 package android.service.persistentdata;
 
 import android.annotation.SystemApi;
+import android.annotation.IntDef;
 import android.os.RemoteException;
 import android.util.Slog;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Interface for reading and writing data blocks to a persistent partition.
  *
@@ -43,6 +47,27 @@
     private static final String TAG = PersistentDataBlockManager.class.getSimpleName();
     private IPersistentDataBlockService sService;
 
+    /**
+     * Indicates that the device's bootloader lock state is UNKNOWN.
+     */
+    public static final int FLASH_LOCK_UNKNOWN = -1;
+    /**
+     * Indicates that the device's bootloader is UNLOCKED.
+     */
+    public static final int FLASH_LOCK_UNLOCKED = 0;
+    /**
+     * Indicates that the device's bootloader is LOCKED.
+     */
+    public static final int FLASH_LOCK_LOCKED = 1;
+
+    @IntDef({
+        FLASH_LOCK_UNKNOWN,
+        FLASH_LOCK_LOCKED,
+        FLASH_LOCK_UNLOCKED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FlashLockState {}
+
     public PersistentDataBlockManager(IPersistentDataBlockService service) {
         sService = service;
     }
@@ -60,8 +85,7 @@
         try {
             return sService.write(data);
         } catch (RemoteException e) {
-            onError("writing data");
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -72,8 +96,7 @@
         try {
             return sService.read();
         } catch (RemoteException e) {
-            onError("reading data");
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -86,8 +109,7 @@
         try {
             return sService.getDataBlockSize();
         } catch (RemoteException e) {
-            onError("getting data block size");
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -100,8 +122,7 @@
         try {
             return sService.getMaximumDataBlockSize();
         } catch (RemoteException e) {
-            onError("getting maximum data block size");
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -113,7 +134,7 @@
         try {
             sService.wipe();
         } catch (RemoteException e) {
-            onError("wiping persistent partition");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -124,7 +145,7 @@
         try {
             sService.setOemUnlockEnabled(enabled);
         } catch (RemoteException e) {
-            onError("setting OEM unlock enabled to " + enabled);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -135,12 +156,24 @@
         try {
             return sService.getOemUnlockEnabled();
         } catch (RemoteException e) {
-            onError("getting OEM unlock enabled bit");
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    private void onError(String msg) {
-        Slog.v(TAG, "Remote exception while " + msg);
+    /**
+     * Retrieves available information about this device's flash lock state.
+     *
+     * @return FLASH_LOCK_STATE_LOCKED if device bootloader is locked,
+     * FLASH_LOCK_STATE_UNLOCKED if device bootloader is unlocked,
+     * or FLASH_LOCK_STATE unknown if this information cannot be ascertained
+     * on this device.
+     */
+    @FlashLockState
+    public int getFlashLockState() {
+        try {
+            return sService.getFlashLockState();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 }
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 1d90505..5434e2e 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -34,4 +34,5 @@
     void startUnlockAndRun(in Tile tile);
 
     void onDialogHidden(in Tile tile);
+    void onStartSuccessful(in Tile tile);
 }
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index 85f1955..3d7d53e 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -37,8 +37,6 @@
     private static final String TAG = "Tile";
 
     /**
-     * This is the default state of any tile, until updated by the {@link TileService}.
-     * <p>
      * An unavailable state indicates that for some reason this tile is not currently
      * available to the user for some reason, and will have no click action.  The tile's
      * icon will be tinted differently to reflect this state.
@@ -57,7 +55,7 @@
 
     /**
      * This represents a tile that is currently active. (e.g. wifi is connected, bluetooth is on,
-     * cast is casting).
+     * cast is casting).  This is the default state.
      */
     public static final int STATE_ACTIVE = 2;
 
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 76a401d..9464a87 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -617,11 +617,7 @@
         }
 
         @Override
-        public void onDetected(RecognitionEvent event) {
-            if (! (event instanceof KeyphraseRecognitionEvent)) {
-                Slog.e(TAG, "onDetected() called for a soundtrigger event.");
-                return;
-            }
+        public void onKeyphraseDetected(KeyphraseRecognitionEvent event) {
             if (DBG) {
                 Slog.d(TAG, "onDetected(" + event + ")");
             } else {
@@ -632,6 +628,10 @@
                             event.captureFormat, event.captureSession, event.data))
                     .sendToTarget();
         }
+        @Override
+        public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
+            Slog.w(TAG, "Generic sound trigger event detected at AOHD: " + event);
+        }
 
         @Override
         public void onError(int status) {
diff --git a/core/java/android/service/vr/IVrListener.aidl b/core/java/android/service/vr/IVrListener.aidl
new file mode 100644
index 0000000..afb13d3
--- /dev/null
+++ b/core/java/android/service/vr/IVrListener.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.vr;
+
+import android.content.ComponentName;
+
+/** @hide */
+oneway interface IVrListener {
+    void focusedActivityChanged(in ComponentName component);
+}
diff --git a/core/java/android/service/vr/VrListenerService.java b/core/java/android/service/vr/VrListenerService.java
new file mode 100644
index 0000000..9a5e95d
--- /dev/null
+++ b/core/java/android/service/vr/VrListenerService.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.vr;
+
+import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.app.ActivityManager;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * A service that is bound from the system while running in virtual reality (VR) mode.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_VR_LISTENER_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * &lt;service android:name=".VrListener"
+ *          android:label="&#64;string/service_name"
+ *          android:permission="android.permission.BIND_VR_LISTENER_SERVICE">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.service.vr.VrListenerService" />
+ *     &lt;/intent-filter>
+ * &lt;/service>
+ * </pre>
+ *
+ * <p>
+ * This service is bound when the system enters VR mode and is unbound when the system leaves VR
+ * mode.
+ * {@see android.app.Activity#setVrMode(boolean)}
+ * </p>
+ */
+public abstract class VrListenerService extends Service {
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+
+    private final Handler mHandler;
+
+    private static final int MSG_ON_CURRENT_VR_ACTIVITY_CHANGED = 1;
+
+    private final IVrListener.Stub mBinder = new IVrListener.Stub() {
+        @Override
+        public void focusedActivityChanged(ComponentName component) {
+            mHandler.obtainMessage(MSG_ON_CURRENT_VR_ACTIVITY_CHANGED, component).sendToTarget();
+        }
+    };
+
+    private final class VrListenerHandler extends Handler {
+        public VrListenerHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_CURRENT_VR_ACTIVITY_CHANGED: {
+                    VrListenerService.this.onCurrentVrActivityChanged((ComponentName) msg.obj);
+                } break;
+            }
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    public VrListenerService() {
+        mHandler = new VrListenerHandler(Looper.getMainLooper());
+    }
+
+    /**
+     * Called when the current activity using VR mode is changed.
+     * <p/>
+     * This will be called immediately when this service is initially bound, but is
+     * not guaranteed to be called before onUnbind.
+     *
+     * @param component the {@link ComponentName} of the new current VR activity.
+     */
+    public void onCurrentVrActivityChanged(ComponentName component) {
+        // Override to implement
+    }
+
+    /**
+     * Check if the given package is available to be enabled/disabled in VR mode settings.
+     *
+     * @param context the {@link Context} to use for looking up the requested component.
+     * @param requestedComponent the name of the component that implements
+     * {@link android.service.vr.VrListenerService} to check.
+     *
+     * @return {@code true} if this package is enabled in settings.
+     */
+    public static final boolean isVrModePackageEnabled(@NonNull Context context,
+            @NonNull ComponentName requestedComponent) {
+        ActivityManager am = context.getSystemService(ActivityManager.class);
+        if (am == null) {
+            return false;
+        }
+        return am.isVrModePackageEnabled(requestedComponent);
+    }
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a985517..de8133b 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -271,7 +271,8 @@
             @Override
             public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                     Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                    Configuration newConfig, Rect backDropRect, boolean forceLayout) {
+                    Configuration newConfig, Rect backDropRect, boolean forceLayout,
+                    boolean alwaysConsumeNavBar) {
                 Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0, outsets);
                 mCaller.sendMessage(msg);
@@ -790,7 +791,7 @@
                             mFinalStableInsets.set(mDispatchedStableInsets);
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
                                     null, mFinalStableInsets,
-                                    getResources().getConfiguration().isScreenRound());
+                                    getResources().getConfiguration().isScreenRound(), false);
                             if (DEBUG) {
                                 Log.v(TAG, "dispatching insets=" + insets);
                             }
diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
index d4fea53..ed7534d 100644
--- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
@@ -16,7 +16,7 @@
 package android.speech.tts;
 
 import android.content.Context;
-import android.media.AudioSystem;
+import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.ConditionVariable;
@@ -57,7 +57,7 @@
         int sessionId = mAudioParams.mSessionId;
         mPlayer = MediaPlayer.create(
                 mContext, mUri, null, mAudioParams.mAudioAttributes,
-                sessionId > 0 ? sessionId : AudioSystem.AUDIO_SESSION_ALLOCATE);
+                sessionId > 0 ? sessionId : AudioManager.AUDIO_SESSION_ID_GENERATE);
         if (mPlayer == null) {
             dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT);
             return;
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index fc075de..1eaa7cf 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -19,7 +19,7 @@
 import android.app.Service;
 import android.content.Intent;
 import android.media.AudioAttributes;
-import android.media.AudioSystem;
+import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -659,7 +659,7 @@
         /**
          * Audio session identifier. May be used to associate audio playback with one of the
          * {@link android.media.audiofx.AudioEffect} objects. If not specified by client,
-         * it should be equal to {@link AudioSystem#AUDIO_SESSION_ALLOCATE}.
+         * it should be equal to {@link AudioManager#AUDIO_SESSION_ID_GENERATE}.
          */
         public final int mSessionId;
 
@@ -684,7 +684,7 @@
 
         /** Create AudioOutputParams with default values */
         AudioOutputParams() {
-            mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+            mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
             mVolume = Engine.DEFAULT_VOLUME;
             mPan = Engine.DEFAULT_PAN;
             mAudioAttributes = null;
@@ -722,7 +722,7 @@
             return new AudioOutputParams(
                     paramsBundle.getInt(
                             Engine.KEY_PARAM_SESSION_ID,
-                            AudioSystem.AUDIO_SESSION_ALLOCATE),
+                            AudioManager.AUDIO_SESSION_ID_GENERATE),
                     paramsBundle.getFloat(
                             Engine.KEY_PARAM_VOLUME,
                             Engine.DEFAULT_VOLUME),
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 0f65f80..7f0021d 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -183,8 +183,10 @@
 
         if (includepad) {
             spacing = metrics.bottom - metrics.top;
+            mDesc = metrics.bottom;
         } else {
             spacing = metrics.descent - metrics.ascent;
+            mDesc = metrics.descent;
         }
 
         mBottom = spacing;
@@ -208,8 +210,6 @@
             mTopPadding = metrics.top - metrics.ascent;
             mBottomPadding = metrics.bottom - metrics.descent;
         }
-
-        mDesc = spacing + mBottomPadding + (includepad ? metrics.top : metrics.ascent);
     }
 
     /**
@@ -247,23 +247,22 @@
      */
     public static Metrics isBoring(CharSequence text, TextPaint paint,
             TextDirectionHeuristic textDir, Metrics metrics) {
-        char[] temp = TextUtils.obtain(500);
-        int length = text.length();
+        final int MAX_BUF_LEN = 500;
+        final char[] buffer = TextUtils.obtain(MAX_BUF_LEN);
+        final int textLength = text.length();
         boolean boring = true;
 
         outer:
-        for (int i = 0; i < length; i += 500) {
-            int j = i + 500;
+        for (int start = 0; start < textLength; start += MAX_BUF_LEN) {
+            final int end = Math.min(start + MAX_BUF_LEN, textLength);
 
-            if (j > length)
-                j = length;
+            // No need to worry about getting half codepoints, since we reject surrogate code units
+            // as non-boring as soon we see one.
+            TextUtils.getChars(text, start, end, buffer, 0);
 
-            TextUtils.getChars(text, i, j, temp, 0);
-
-            int n = j - i;
-
-            for (int a = 0; a < n; a++) {
-                char c = temp[a];
+            final int len = end - start;
+            for (int i = 0; i < len; i++) {
+                final char c = buffer[i];
 
                 if (c == '\n' || c == '\t' ||
                         (c >= 0x0590 && c <= 0x08FF) ||  // RTL scripts
@@ -279,17 +278,19 @@
                 }
             }
 
-            if (textDir != null && textDir.isRtl(temp, 0, n)) {
+            // TODO: This looks a little suspicious, and in some cases can result in O(n^2)
+            // run time. Consider moving outside the loop.
+            if (textDir != null && textDir.isRtl(buffer, 0, len)) {
                boring = false;
                break outer;
             }
         }
 
-        TextUtils.recycle(temp);
+        TextUtils.recycle(buffer);
 
         if (boring && text instanceof Spanned) {
             Spanned sp = (Spanned) text;
-            Object[] styles = sp.getSpans(0, length, ParagraphStyle.class);
+            Object[] styles = sp.getSpans(0, textLength, ParagraphStyle.class);
             if (styles.length > 0) {
                 boring = false;
             }
@@ -299,10 +300,12 @@
             Metrics fm = metrics;
             if (fm == null) {
                 fm = new Metrics();
+            } else {
+                fm.reset();
             }
 
             TextLine line = TextLine.obtain();
-            line.set(paint, text, 0, length, Layout.DIR_LEFT_TO_RIGHT,
+            line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
                     Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
             fm.width = (int) Math.ceil(line.metrics(fm));
             TextLine.recycle(line);
@@ -413,8 +416,6 @@
         mEllipsizedCount = end - start;
     }
 
-    private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
-
     private String mDirect;
     private Paint mPaint;
 
@@ -423,14 +424,20 @@
     private float mMax;
     private int mEllipsizedWidth, mEllipsizedStart, mEllipsizedCount;
 
-    private static final TextPaint sTemp =
-                                new TextPaint();
-
     public static class Metrics extends Paint.FontMetricsInt {
         public int width;
 
         @Override public String toString() {
             return super.toString() + " width=" + width;
         }
+
+        private void reset() {
+            top = 0;
+            bottom = 0;
+            ascent = 0;
+            descent = 0;
+            width = 0;
+            leading = 0;
+        }
     }
 }
diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java
index b437f48..c0f0663 100644
--- a/core/java/android/text/Emoji.java
+++ b/core/java/android/text/Emoji.java
@@ -23,15 +23,17 @@
  * @hide
  */
 public class Emoji {
-    // See http://www.unicode.org/Public/emoji/2.0//emoji-data.txt
+    // See http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
     private static int[] EMOJI_MODIFIER_BASE = {
         0x261D, 0x26F9, 0x270A, 0x270B, 0x270C, 0x270D, 0x1F385, 0x1F3C3, 0x1F3C4, 0x1F3CA,
         0x1F3CB, 0x1F442, 0x1F443, 0x1F446, 0x1F447, 0x1F448, 0x1F449, 0x1F44A, 0x1F44B, 0x1F44C,
         0x1F44D, 0x1F44E, 0x1F44F, 0x1F450, 0x1F466, 0x1F467, 0x1F468, 0x1F469, 0x1F46E, 0x1F470,
-        0x1F471, 0x1F472, 0x1F473, 0x1F474, 0x1F475, 0x1F476, 0x1F474, 0x1F478, 0x1F47C, 0x1F481,
-        0x1F482, 0x1F483, 0x1F485, 0x1F486, 0x1F487, 0x1F4AA, 0x1F575, 0x1F590, 0x1F595, 0x1F596,
-        0x1F645, 0x1F646, 0x1F647, 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F6A3, 0x1F6B4,
-        0x1F6B5, 0x1F6B6, 0x1F6C0, 0x1F918
+        0x1F471, 0x1F472, 0x1F473, 0x1F474, 0x1F475, 0x1F476, 0x1F477, 0x1F478, 0x1F47C, 0x1F481,
+        0x1F482, 0x1F483, 0x1F485, 0x1F486, 0x1F487, 0x1F4AA, 0x1F575, 0x1F57A, 0x1F590, 0x1F595,
+        0x1F596, 0x1F645, 0x1F646, 0x1F647, 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F6A3,
+        0x1F6B4, 0x1F6B5, 0x1F6B6, 0x1F6C0, 0x1F918, 0x1F919, 0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D,
+        0x1F91E, 0x1F926, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938, 0x1F939,
+        0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E
     };
 
     // See http://www.unicode.org/emoji/charts/emoji-zwj-sequences.html
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 568b267..356804e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -152,6 +152,9 @@
         {"en-UM", "en-US"}, // English (United States Minor Outlying Islands)
         {"en-VI", "en-US"}, // English (Virgin Islands)
 
+        // All English locales other than those falling back to en-US are mapped to en-GB.
+        {"en", "en-GB"},
+
         // For German, we're assuming the 1996 (and later) orthography by default.
         {"de", "de-1996"},
         // Liechtenstein uses the Swiss hyphenation rules for the 1901 orthography.
@@ -160,6 +163,9 @@
         // Norwegian is very probably Norwegian Bokmål.
         {"no", "nb"},
 
+        // Use mn-Cyrl. According to CLDR's likelySubtags.xml, mn is most likely to be mn-Cyrl.
+        {"mn", "mn-Cyrl"}, // Mongolian
+
         // Fall back to Ethiopic script for languages likely to be written in Ethiopic.
         // Data is from CLDR's likelySubtags.xml.
         // TODO: Convert this to a mechanism using ICU4J's ULocale#addLikelySubtags().
@@ -182,16 +188,36 @@
 
         // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
         String[] availableLanguages = {
+            "as",
+            "bn",
+            "cy",
+            "da",
             "de-1901", "de-1996", "de-CH-1901",
-            "en-US",
+            "en-GB", "en-US",
             "es",
+            "et",
             "eu",
+            "fr",
+            "ga",
+            "gu",
+            "hi",
+            "hr",
             "hu",
             "hy",
+            "kn",
+            "ml",
+            "mn-Cyrl",
+            "mr",
             "nb",
             "nn",
+            "or",
+            "pa",
             "pt",
-            "und-Ethi"
+            "sl",
+            "ta",
+            "te",
+            "tk",
+            "und-Ethi",
         };
         for (int i = 0; i < availableLanguages.length; i++) {
             String languageTag = availableLanguages[i];
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 692d848..0bd5071 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -799,6 +799,31 @@
         return false;
     }
 
+    /**
+     * Returns the range of the run that the character at offset belongs to.
+     * @param offset the offset
+     * @return The range of the run
+     * @hide
+     */
+    public long getRunRange(int offset) {
+        int line = getLineForOffset(offset);
+        Directions dirs = getLineDirections(line);
+        if (dirs == DIRS_ALL_LEFT_TO_RIGHT || dirs == DIRS_ALL_RIGHT_TO_LEFT) {
+            return TextUtils.packRangeInLong(0, getLineEnd(line));
+        }
+        int[] runs = dirs.mDirections;
+        int lineStart = getLineStart(line);
+        for (int i = 0; i < runs.length; i += 2) {
+            int start = lineStart + runs[i];
+            int limit = start + (runs[i+1] & RUN_LENGTH_MASK);
+            if (offset >= start && offset < limit) {
+                return TextUtils.packRangeInLong(start, limit);
+            }
+        }
+        // Should happen only if the offset is "out of bounds"
+        return TextUtils.packRangeInLong(0, getLineEnd(line));
+    }
+
     private boolean primaryIsTrailingPrevious(int offset) {
         int line = getLineForOffset(offset);
         int lineStart = getLineStart(line);
@@ -886,6 +911,10 @@
         return getHorizontal(offset, !trailing, clamped);
     }
 
+    private float getHorizontal(int offset, boolean primary) {
+        return primary ? getPrimaryHorizontal(offset) : getSecondaryHorizontal(offset);
+    }
+
     private float getHorizontal(int offset, boolean trailing, boolean clamped) {
         int line = getLineForOffset(offset);
 
@@ -1114,6 +1143,20 @@
      * closest to the specified horizontal position.
      */
     public int getOffsetForHorizontal(int line, float horiz) {
+        return getOffsetForHorizontal(line, horiz, true);
+    }
+
+    /**
+     * Get the character offset on the specified line whose position is
+     * closest to the specified horizontal position.
+     *
+     * @param line the line used to find the closest offset
+     * @param horiz the horizontal position used to find the closest offset
+     * @param primary whether to use the primary position or secondary position to find the offset
+     *
+     * @hide
+     */
+    public int getOffsetForHorizontal(int line, float horiz, boolean primary) {
         // TODO: use Paint.getOffsetForAdvance to avoid binary search
         final int lineEndOffset = getLineEnd(line);
         final int lineStartOffset = getLineStart(line);
@@ -1133,7 +1176,7 @@
                     !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
         }
         int best = lineStartOffset;
-        float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
+        float bestdist = Math.abs(getHorizontal(best, primary) - horiz);
 
         for (int i = 0; i < dirs.mDirections.length; i += 2) {
             int here = lineStartOffset + dirs.mDirections[i];
@@ -1149,7 +1192,7 @@
                 guess = (high + low) / 2;
                 int adguess = getOffsetAtStartOf(guess);
 
-                if (getPrimaryHorizontal(adguess) * swap >= horiz * swap)
+                if (getHorizontal(adguess, primary) * swap >= horiz * swap)
                     high = guess;
                 else
                     low = guess;
@@ -1162,9 +1205,9 @@
                 int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset;
                 low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset;
                 if (low >= here && low < there) {
-                    float dist = Math.abs(getPrimaryHorizontal(low) - horiz);
+                    float dist = Math.abs(getHorizontal(low, primary) - horiz);
                     if (aft < there) {
-                        float other = Math.abs(getPrimaryHorizontal(aft) - horiz);
+                        float other = Math.abs(getHorizontal(aft, primary) - horiz);
 
                         if (other < dist) {
                             dist = other;
@@ -1179,7 +1222,7 @@
                 }
             }
 
-            float dist = Math.abs(getPrimaryHorizontal(here) - horiz);
+            float dist = Math.abs(getHorizontal(here, primary) - horiz);
 
             if (dist < bestdist) {
                 bestdist = dist;
@@ -1187,7 +1230,7 @@
             }
         }
 
-        float dist = Math.abs(getPrimaryHorizontal(max) - horiz);
+        float dist = Math.abs(getHorizontal(max, primary) - horiz);
 
         if (dist <= bestdist) {
             bestdist = dist;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 6a33579..94ce57a 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -1132,22 +1132,12 @@
 
     @Override
     public int getLineTop(int line) {
-        int top = mLines[mColumns * line + TOP];
-        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount &&
-                line != mLineCount) {
-            top += getBottomPadding();
-        }
-        return top;
+        return mLines[mColumns * line + TOP];
     }
 
     @Override
     public int getLineDescent(int line) {
-        int descent = mLines[mColumns * line + DESCENT];
-        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended
-                line != mLineCount) {
-            descent += getBottomPadding();
-        }
-        return descent;
+        return mLines[mColumns * line + DESCENT];
     }
 
     @Override
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 367c9fb..3564e11 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -16,6 +16,7 @@
 
 package android.text.method;
 
+import android.graphics.Paint;
 import android.icu.lang.UCharacter;
 import android.icu.lang.UProperty;
 import android.view.KeyEvent;
@@ -25,6 +26,8 @@
 import android.text.style.ReplacementSpan;
 import android.widget.TextView;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.text.BreakIterator;
 import java.util.Arrays;
 import java.util.Collections;
@@ -45,6 +48,11 @@
         implements KeyListener {
     /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    static Paint sCachedPaint = null;
+
     /**
      * Performs the action that happens when you press the {@link KeyEvent#KEYCODE_DEL} key in
      * a {@link TextView}.  If there is a selection, deletes the selection; otherwise,
@@ -258,20 +266,15 @@
     }
 
     // Returns the end offset to be deleted by a forward delete key from the given offset.
-    private static int getOffsetForForwardDeleteKey(CharSequence text, int offset) {
+    private static int getOffsetForForwardDeleteKey(CharSequence text, int offset, Paint paint) {
         final int len = text.length();
 
         if (offset >= len - 1) {
             return len;
         }
 
-        int codePoint = Character.codePointAt(text, offset);
-        offset += Character.charCount(codePoint);
-        if (offset == len) {
-            return len;
-        }
-
-        // TODO: Handle emoji, combining chars, etc.
+        offset = paint.getTextRunCursor(text, offset, len, Paint.DIRECTION_LTR /* not used */,
+                offset, Paint.CURSOR_AFTER);
 
         return adjustReplacementSpan(text, offset, false /* move to the end */);
     }
@@ -311,7 +314,18 @@
         final int start = Selection.getSelectionEnd(content);
         final int end;
         if (isForwardDelete) {
-            end = getOffsetForForwardDeleteKey(content, start);
+            final Paint paint;
+            if (view instanceof TextView) {
+                paint = ((TextView)view).getPaint();
+            } else {
+                synchronized (mLock) {
+                    if (sCachedPaint == null) {
+                        sCachedPaint = new Paint();
+                    }
+                    paint = sCachedPaint;
+                }
+            }
+            end = getOffsetForForwardDeleteKey(content, start, paint);
         } else {
             end = getOffsetForBackspaceKey(content, start);
         }
@@ -437,6 +451,7 @@
 
         if (handled) {
             adjustMetaAfterKeypress(content);
+            return true;
         }
 
         return super.onKeyDown(view, content, keyCode, event);
@@ -470,4 +485,3 @@
         return true;
     }
 }
-
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index 93a156b..e9153dd 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -1013,7 +1013,7 @@
          * @return This instance.
          */
         public MeasureBuilder setIntegerPart(long integerPart) {
-            return setNumber(String.valueOf(integerPart));
+            return setIntegerPart(String.valueOf(integerPart));
         }
 
         /**
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index fbd9924..ca037a2 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -16,6 +16,9 @@
 
 package android.text.util;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.telephony.PhoneNumberUtils;
 import android.text.method.LinkMovementMethod;
 import android.text.method.MovementMethod;
@@ -29,6 +32,8 @@
 
 
 import java.io.UnsupportedEncodingException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -41,19 +46,21 @@
 import com.android.i18n.phonenumbers.PhoneNumberUtil;
 import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
 
+import libcore.util.EmptyArray;
+
 /**
  *  Linkify take a piece of text and a regular expression and turns all of the
  *  regex matches in the text into clickable links.  This is particularly
- *  useful for matching things like email addresses, web urls, etc. and making
+ *  useful for matching things like email addresses, web URLs, etc. and making
  *  them actionable.
  *
- *  Alone with the pattern that is to be matched, a url scheme prefix is also
+ *  Alone with the pattern that is to be matched, a URL scheme prefix is also
  *  required.  Any pattern match that does not begin with the supplied scheme
- *  will have the scheme prepended to the matched text when the clickable url
- *  is created.  For instance, if you are matching web urls you would supply
- *  the scheme <code>http://</code>.  If the pattern matches example.com, which
- *  does not have a url scheme prefix, the supplied scheme will be prepended to
- *  create <code>http://example.com</code> when the clickable url link is
+ *  will have the scheme prepended to the matched text when the clickable URL
+ *  is created.  For instance, if you are matching web URLs you would supply
+ *  the scheme <code>http://</code>. If the pattern matches example.com, which
+ *  does not have a URL scheme prefix, the supplied scheme will be prepended to
+ *  create <code>http://example.com</code> when the clickable URL link is
  *  created.
  */
 
@@ -97,6 +104,11 @@
      */
     private static final int PHONE_NUMBER_MINIMUM_DIGITS = 5;
 
+    /** @hide */
+    @IntDef(flag = true, value = { WEB_URLS, EMAIL_ADDRESSES, PHONE_NUMBERS, MAP_ADDRESSES, ALL })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LinkifyMask {}
+
     /**
      *  Filters out web URL matches that occur after an at-sign (@).  This is
      *  to prevent turning the domain name in an email address into a web link.
@@ -152,10 +164,10 @@
      *  MatchFilter enables client code to have more control over
      *  what is allowed to match and become a link, and what is not.
      *
-     *  For example:  when matching web urls you would like things like
+     *  For example:  when matching web URLs you would like things like
      *  http://www.example.com to match, as well as just example.com itelf.
      *  However, you would not want to match against the domain in
-     *  support@example.com.  So, when matching against a web url pattern you
+     *  support@example.com.  So, when matching against a web URL pattern you
      *  might also include a MatchFilter that disallows the match if it is
      *  immediately preceded by an at-sign (@).
      */
@@ -203,8 +215,13 @@
      *  If the mask is nonzero, it also removes any existing URLSpans
      *  attached to the Spannable, to avoid problems if you call it
      *  repeatedly on the same text.
+     *
+     *  @param text Spannable whose text is to be marked-up with links
+     *  @param mask Mask to define which kinds of links will be searched.
+     *
+     *  @return True if at least one link is found and applied.
      */
-    public static final boolean addLinks(Spannable text, int mask) {
+    public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
         if (mask == 0) {
             return false;
         }
@@ -224,7 +241,7 @@
         }
 
         if ((mask & EMAIL_ADDRESSES) != 0) {
-            gatherLinks(links, text, Patterns.EMAIL_ADDRESS,
+            gatherLinks(links, text, Patterns.AUTOLINK_EMAIL_ADDRESS,
                 new String[] { "mailto:" },
                 null, null);
         }
@@ -255,8 +272,13 @@
      *  the link types indicated in the mask into clickable links.  If matches
      *  are found the movement method for the TextView is set to
      *  LinkMovementMethod.
+     *
+     *  @param text TextView whose text is to be marked-up with links
+     *  @param mask Mask to define which kinds of links will be searched.
+     *
+     *  @return True if at least one link is found and applied.
      */
-    public static final boolean addLinks(TextView text, int mask) {
+    public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
         if (mask == 0) {
             return false;
         }
@@ -284,7 +306,7 @@
         }
     }
 
-    private static final void addLinkMovementMethod(TextView t) {
+    private static final void addLinkMovementMethod(@NonNull TextView t) {
         MovementMethod m = t.getMovementMethod();
 
         if ((m == null) || !(m instanceof LinkMovementMethod)) {
@@ -302,12 +324,12 @@
      *
      *  @param text         TextView whose text is to be marked-up with links
      *  @param pattern      Regex pattern to be used for finding links
-     *  @param scheme       Url scheme string (eg <code>http://</code> to be
-     *                      prepended to the url of links that do not have
-     *                      a scheme specified in the link text
+     *  @param scheme       URL scheme string (eg <code>http://</code>) to be
+     *                      prepended to the links that do not start with this scheme.
      */
-    public static final void addLinks(TextView text, Pattern pattern, String scheme) {
-        addLinks(text, pattern, scheme, null, null);
+    public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
+            @Nullable String scheme) {
+        addLinks(text, pattern, scheme, null, null, null);
     }
 
     /**
@@ -317,20 +339,45 @@
      *  to LinkMovementMethod.
      *
      *  @param text         TextView whose text is to be marked-up with links
-     *  @param p            Regex pattern to be used for finding links
-     *  @param scheme       Url scheme string (eg <code>http://</code> to be
-     *                      prepended to the url of links that do not have
-     *                      a scheme specified in the link text
+     *  @param pattern      Regex pattern to be used for finding links
+     *  @param scheme       URL scheme string (eg <code>http://</code>) to be
+     *                      prepended to the links that do not start with this scheme.
      *  @param matchFilter  The filter that is used to allow the client code
      *                      additional control over which pattern matches are
      *                      to be converted into links.
      */
-    public static final void addLinks(TextView text, Pattern p, String scheme,
-            MatchFilter matchFilter, TransformFilter transformFilter) {
-        SpannableString s = SpannableString.valueOf(text.getText());
+    public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
+            @Nullable String scheme, @Nullable MatchFilter matchFilter,
+            @Nullable TransformFilter transformFilter) {
+        addLinks(text, pattern, scheme, null, matchFilter, transformFilter);
+    }
 
-        if (addLinks(s, p, scheme, matchFilter, transformFilter)) {
-            text.setText(s);
+    /**
+     *  Applies a regex to the text of a TextView turning the matches into
+     *  links.  If links are found then UrlSpans are applied to the link
+     *  text match areas, and the movement method for the text is changed
+     *  to LinkMovementMethod.
+     *
+     *  @param text TextView whose text is to be marked-up with links.
+     *  @param pattern Regex pattern to be used for finding links.
+     *  @param defaultScheme The default scheme to be prepended to links if the link does not
+     *                       start with one of the <code>schemes</code> given.
+     *  @param schemes Array of schemes (eg <code>http://</code>) to check if the link found
+     *                 contains a scheme. Passing a null or empty value means prepend defaultScheme
+     *                 to all links.
+     *  @param matchFilter  The filter that is used to allow the client code additional control
+     *                      over which pattern matches are to be converted into links.
+     *  @param transformFilter Filter to allow the client code to update the link found.
+     */
+    public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
+             @Nullable  String defaultScheme, @Nullable String[] schemes,
+             @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
+        SpannableString spannable = SpannableString.valueOf(text.getText());
+
+        boolean linksAdded = addLinks(spannable, pattern, defaultScheme, schemes, matchFilter,
+                transformFilter);
+        if (linksAdded) {
+            text.setText(spannable);
             addLinkMovementMethod(text);
         }
     }
@@ -339,37 +386,72 @@
      *  Applies a regex to a Spannable turning the matches into
      *  links.
      *
-     *  @param text         Spannable whose text is to be marked-up with
-     *                      links
+     *  @param text         Spannable whose text is to be marked-up with links
      *  @param pattern      Regex pattern to be used for finding links
-     *  @param scheme       Url scheme string (eg <code>http://</code> to be
-     *                      prepended to the url of links that do not have
-     *                      a scheme specified in the link text
+     *  @param scheme       URL scheme string (eg <code>http://</code>) to be
+     *                      prepended to the links that do not start with this scheme.
      */
-    public static final boolean addLinks(Spannable text, Pattern pattern, String scheme) {
-        return addLinks(text, pattern, scheme, null, null);
+    public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
+            @Nullable String scheme) {
+        return addLinks(text, pattern, scheme, null, null, null);
     }
 
     /**
-     *  Applies a regex to a Spannable turning the matches into
-     *  links.
+     * Applies a regex to a Spannable turning the matches into
+     * links.
      *
-     *  @param s            Spannable whose text is to be marked-up with
-     *                      links
-     *  @param p            Regex pattern to be used for finding links
-     *  @param scheme       Url scheme string (eg <code>http://</code> to be
-     *                      prepended to the url of links that do not have
-     *                      a scheme specified in the link text
-     *  @param matchFilter  The filter that is used to allow the client code
-     *                      additional control over which pattern matches are
-     *                      to be converted into links.
+     * @param spannable    Spannable whose text is to be marked-up with links
+     * @param pattern      Regex pattern to be used for finding links
+     * @param scheme       URL scheme string (eg <code>http://</code>) to be
+     *                     prepended to the links that do not start with this scheme.
+     * @param matchFilter  The filter that is used to allow the client code
+     *                     additional control over which pattern matches are
+     *                     to be converted into links.
+     * @param transformFilter Filter to allow the client code to update the link found.
+     *
+     * @return True if at least one link is found and applied.
      */
-    public static final boolean addLinks(Spannable s, Pattern p,
-            String scheme, MatchFilter matchFilter,
-            TransformFilter transformFilter) {
+    public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
+            @Nullable String scheme, @Nullable MatchFilter matchFilter,
+            @Nullable TransformFilter transformFilter) {
+        return addLinks(spannable, pattern, scheme, null, matchFilter,
+                transformFilter);
+    }
+
+    /**
+     * Applies a regex to a Spannable turning the matches into links.
+     *
+     * @param spannable Spannable whose text is to be marked-up with links.
+     * @param pattern Regex pattern to be used for finding links.
+     * @param defaultScheme The default scheme to be prepended to links if the link does not
+     *                      start with one of the <code>schemes</code> given.
+     * @param schemes Array of schemes (eg <code>http://</code>) to check if the link found
+     *                contains a scheme. Passing a null or empty value means prepend defaultScheme
+     *                to all links.
+     * @param matchFilter  The filter that is used to allow the client code additional control
+     *                     over which pattern matches are to be converted into links.
+     * @param transformFilter Filter to allow the client code to update the link found.
+     *
+     * @return True if at least one link is found and applied.
+     */
+    public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
+            @Nullable  String defaultScheme, @Nullable String[] schemes,
+            @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
+        final String[] schemesCopy;
+        if (defaultScheme == null) defaultScheme = "";
+        if (schemes == null || schemes.length < 1) {
+            schemes = EmptyArray.STRING;
+        }
+
+        schemesCopy = new String[schemes.length + 1];
+        schemesCopy[0] = defaultScheme.toLowerCase(Locale.ROOT);
+        for (int index = 0; index < schemes.length; index++) {
+            String scheme = schemes[index];
+            schemesCopy[index + 1] = (scheme == null) ? "" : scheme.toLowerCase(Locale.ROOT);
+        }
+
         boolean hasMatches = false;
-        String prefix = (scheme == null) ? "" : scheme.toLowerCase(Locale.ROOT);
-        Matcher m = p.matcher(s);
+        Matcher m = pattern.matcher(spannable);
 
         while (m.find()) {
             int start = m.start();
@@ -377,14 +459,13 @@
             boolean allowed = true;
 
             if (matchFilter != null) {
-                allowed = matchFilter.acceptMatch(s, start, end);
+                allowed = matchFilter.acceptMatch(spannable, start, end);
             }
 
             if (allowed) {
-                String url = makeUrl(m.group(0), new String[] { prefix },
-                                     m, transformFilter);
+                String url = makeUrl(m.group(0), schemesCopy, m, transformFilter);
 
-                applyLink(url, start, end, s);
+                applyLink(url, start, end, spannable);
                 hasMatches = true;
             }
         }
@@ -398,22 +479,20 @@
         text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
-    private static final String makeUrl(String url, String[] prefixes,
-            Matcher m, TransformFilter filter) {
+    private static final String makeUrl(@NonNull String url, @NonNull String[] prefixes,
+            Matcher matcher, @Nullable TransformFilter filter) {
         if (filter != null) {
-            url = filter.transformUrl(m, url);
+            url = filter.transformUrl(matcher, url);
         }
 
         boolean hasPrefix = false;
-        
+
         for (int i = 0; i < prefixes.length; i++) {
-            if (url.regionMatches(true, 0, prefixes[i], 0,
-                                  prefixes[i].length())) {
+            if (url.regionMatches(true, 0, prefixes[i], 0, prefixes[i].length())) {
                 hasPrefix = true;
 
                 // Fix capitalization if necessary
-                if (!url.regionMatches(false, 0, prefixes[i], 0,
-                                       prefixes[i].length())) {
+                if (!url.regionMatches(false, 0, prefixes[i], 0, prefixes[i].length())) {
                     url = prefixes[i] + url.substring(prefixes[i].length());
                 }
 
@@ -421,7 +500,7 @@
             }
         }
 
-        if (!hasPrefix) {
+        if (!hasPrefix && prefixes.length > 0) {
             url = prefixes[0] + url;
         }
 
diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java
index fa4c8d2..70443ba 100644
--- a/core/java/android/transition/ArcMotion.java
+++ b/core/java/android/transition/ArcMotion.java
@@ -15,13 +15,13 @@
  */
 package android.transition;
 
-import com.android.internal.R;
-
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Path;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
+
 /**
  * A PathMotion that generates a curved path along an arc on an imaginary circle containing
  * the two points. If the horizontal distance between the points is less than the vertical
@@ -207,7 +207,7 @@
             ey = (startY + endY) / 2;
         } else {
             float deltaX = endX - startX;
-            float deltaY = startY - endY; // Y is inverted compared to diagram above.
+            float deltaY = endY - startY;
             // hypotenuse squared.
             float h2 = deltaX * deltaX + deltaY * deltaY;
 
@@ -219,24 +219,35 @@
             float midDist2 = h2 * 0.25f;
 
             float minimumArcDist2 = 0;
+            boolean isQuadrant1Or3 = (deltaX * deltaY) > 0;
 
-            if (Math.abs(deltaX) < Math.abs(deltaY)) {
+            if ((Math.abs(deltaX) < Math.abs(deltaY))) {
                 // Similar triangles bfa and bde mean that (ab/fb = eb/bd)
                 // Therefore, eb = ab * bd / fb
                 // ab = hypotenuse
                 // bd = hypotenuse/2
                 // fb = deltaY
                 float eDistY = h2 / (2 * deltaY);
-                ey = endY + eDistY;
-                ex = endX;
+                if (isQuadrant1Or3) {
+                    ey = startY + eDistY;
+                    ex = startX;
+                } else {
+                    ey = endY - eDistY;
+                    ex = endX;
+                }
 
                 minimumArcDist2 = midDist2 * mMinimumVerticalTangent
                         * mMinimumVerticalTangent;
             } else {
                 // Same as above, but flip X & Y
                 float eDistX = h2 / (2 * deltaX);
-                ex = endX + eDistX;
-                ey = endY;
+                if (isQuadrant1Or3) {
+                    ex = endX - eDistX;
+                    ey = endY;
+                } else {
+                    ex = startX + eDistX;
+                    ey = startY;
+                }
 
                 minimumArcDist2 = midDist2 * mMinimumHorizontalTangent
                         * mMinimumHorizontalTangent;
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java
index 9af65e4..2645f86 100644
--- a/core/java/android/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -47,6 +47,7 @@
     private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
     private CalculateSlide mSlideCalculator = sCalculateBottom;
     private @GravityFlag int mSlideEdge = Gravity.BOTTOM;
+    private float mSlideFraction = 1;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -56,16 +57,16 @@
     private interface CalculateSlide {
 
         /** Returns the translation value for view when it goes out of the scene */
-        float getGoneX(ViewGroup sceneRoot, View view);
+        float getGoneX(ViewGroup sceneRoot, View view, float fraction);
 
         /** Returns the translation value for view when it goes out of the scene */
-        float getGoneY(ViewGroup sceneRoot, View view);
+        float getGoneY(ViewGroup sceneRoot, View view, float fraction);
     }
 
     private static abstract class CalculateSlideHorizontal implements CalculateSlide {
 
         @Override
-        public float getGoneY(ViewGroup sceneRoot, View view) {
+        public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
             return view.getTranslationY();
         }
     }
@@ -73,27 +74,27 @@
     private static abstract class CalculateSlideVertical implements CalculateSlide {
 
         @Override
-        public float getGoneX(ViewGroup sceneRoot, View view) {
+        public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
             return view.getTranslationX();
         }
     }
 
     private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() {
         @Override
-        public float getGoneX(ViewGroup sceneRoot, View view) {
-            return view.getTranslationX() - sceneRoot.getWidth();
+        public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
+            return view.getTranslationX() - sceneRoot.getWidth() * fraction;
         }
     };
 
     private static final CalculateSlide sCalculateStart = new CalculateSlideHorizontal() {
         @Override
-        public float getGoneX(ViewGroup sceneRoot, View view) {
+        public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
             final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
             final float x;
             if (isRtl) {
-                x = view.getTranslationX() + sceneRoot.getWidth();
+                x = view.getTranslationX() + sceneRoot.getWidth() * fraction;
             } else {
-                x = view.getTranslationX() - sceneRoot.getWidth();
+                x = view.getTranslationX() - sceneRoot.getWidth() * fraction;
             }
             return x;
         }
@@ -101,27 +102,27 @@
 
     private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
         @Override
-        public float getGoneY(ViewGroup sceneRoot, View view) {
-            return view.getTranslationY() - sceneRoot.getHeight();
+        public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
+            return view.getTranslationY() - sceneRoot.getHeight() * fraction;
         }
     };
 
     private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() {
         @Override
-        public float getGoneX(ViewGroup sceneRoot, View view) {
-            return view.getTranslationX() + sceneRoot.getWidth();
+        public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
+            return view.getTranslationX() + sceneRoot.getWidth() * fraction;
         }
     };
 
     private static final CalculateSlide sCalculateEnd = new CalculateSlideHorizontal() {
         @Override
-        public float getGoneX(ViewGroup sceneRoot, View view) {
+        public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
             final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
             final float x;
             if (isRtl) {
-                x = view.getTranslationX() - sceneRoot.getWidth();
+                x = view.getTranslationX() - sceneRoot.getWidth() * fraction;
             } else {
-                x = view.getTranslationX() + sceneRoot.getWidth();
+                x = view.getTranslationX() + sceneRoot.getWidth() * fraction;
             }
             return x;
         }
@@ -129,8 +130,8 @@
 
     private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
         @Override
-        public float getGoneY(ViewGroup sceneRoot, View view) {
-            return view.getTranslationY() + sceneRoot.getHeight();
+        public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
+            return view.getTranslationY() + sceneRoot.getHeight() * fraction;
         }
     };
 
@@ -237,8 +238,8 @@
         int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
         float endX = view.getTranslationX();
         float endY = view.getTranslationY();
-        float startX = mSlideCalculator.getGoneX(sceneRoot, view);
-        float startY = mSlideCalculator.getGoneY(sceneRoot, view);
+        float startX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction);
+        float startY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction);
         return TranslationAnimationCreator
                 .createAnimation(view, endValues, position[0], position[1],
                         startX, startY, endX, endY, sDecelerate, this);
@@ -253,10 +254,15 @@
         int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
         float startX = view.getTranslationX();
         float startY = view.getTranslationY();
-        float endX = mSlideCalculator.getGoneX(sceneRoot, view);
-        float endY = mSlideCalculator.getGoneY(sceneRoot, view);
+        float endX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction);
+        float endY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction);
         return TranslationAnimationCreator
                 .createAnimation(view, startValues, position[0], position[1],
                         startX, startY, endX, endY, sAccelerate, this);
     }
+
+    /** @hide */
+    public void setSlideFraction(float slideFraction) {
+        mSlideFraction = slideFraction;
+    }
 }
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 4afa9fe..316c7e3 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -41,12 +41,12 @@
 import android.widget.ListView;
 import android.widget.Spinner;
 
+import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.StringTokenizer;
 
-import com.android.internal.R;
-
 /**
  * A Transition holds information about animations that will be run on its
  * targets during a scene change. Subclasses of this abstract class may
@@ -192,7 +192,7 @@
     private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
     private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
     TransitionSet mParent = null;
-    private int[] mMatchOrder = DEFAULT_MATCH_ORDER;
+    int[] mMatchOrder = DEFAULT_MATCH_ORDER;
     ArrayList<TransitionValues> mStartValuesList; // only valid after playTransition starts
     ArrayList<TransitionValues> mEndValuesList; // only valid after playTransitions starts
 
@@ -246,7 +246,7 @@
 
     // The function used to interpolate along two-dimensional points. Typically used
     // for adding curves to x/y View motion.
-    private PathMotion mPathMotion = STRAIGHT_PATH_MOTION;
+    PathMotion mPathMotion = STRAIGHT_PATH_MOTION;
 
     /**
      * Constructs a Transition object with no target objects. A transition with
@@ -780,7 +780,7 @@
                 }
             }
         }
-        if (minStartDelay != 0) {
+        if (startDelays.size() != 0) {
             for (int i = 0; i < startDelays.size(); i++) {
                 int index = startDelays.keyAt(i);
                 Animator animator = mAnimators.get(index);
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 4eaab37..6579212 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -84,6 +84,7 @@
     }
 
     private int mMode = MODE_IN | MODE_OUT;
+    private boolean mSuppressLayout = true;
 
     public Visibility() {}
 
@@ -98,6 +99,15 @@
     }
 
     /**
+     * This tells the Visibility transition to suppress layout during the transition and release
+     * the suppression after the transition.
+     * @hide
+     */
+    public void setSuppressLayout(boolean suppress) {
+        this.mSuppressLayout = suppress;
+    }
+
+    /**
      * Changes the transition to support appearing and/or disappearing Views, depending
      * on <code>mode</code>.
      *
@@ -428,7 +438,7 @@
             Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
             if (animator != null) {
                 DisappearListener disappearListener = new DisappearListener(viewToKeep,
-                        finalVisibility);
+                        finalVisibility, mSuppressLayout);
                 animator.addListener(disappearListener);
                 animator.addPauseListener(disappearListener);
                 addListener(disappearListener);
@@ -483,14 +493,16 @@
         private final View mView;
         private final int mFinalVisibility;
         private final ViewGroup mParent;
+        private final boolean mSuppressLayout;
 
         private boolean mLayoutSuppressed;
         boolean mCanceled = false;
 
-        public DisappearListener(View view, int finalVisibility) {
+        public DisappearListener(View view, int finalVisibility, boolean suppressLayout) {
             this.mView = view;
             this.mFinalVisibility = finalVisibility;
             this.mParent = (ViewGroup) view.getParent();
+            this.mSuppressLayout = suppressLayout;
             // Prevent a layout from including mView in its calculation.
             suppressLayout(true);
         }
@@ -555,7 +567,7 @@
         }
 
         private void suppressLayout(boolean suppress) {
-            if (mLayoutSuppressed != suppress && mParent != null) {
+            if (mSuppressLayout && mLayoutSuppressed != suppress && mParent != null) {
                 mLayoutSuppressed = suppress;
                 mParent.suppressLayout(suppress);
             }
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index bdb1fdc..92a5803 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -67,7 +67,7 @@
     /**
      * @hide Special immutable empty ArrayMap.
      */
-    public static final ArrayMap EMPTY = new ArrayMap(true);
+    public static final ArrayMap EMPTY = new ArrayMap<>(-1);
 
     /**
      * Caches of small array objects to avoid spamming garbage.  The cache
@@ -80,6 +80,7 @@
     static Object[] mTwiceBaseCache;
     static int mTwiceBaseCacheSize;
 
+    final boolean mIdentityHashCode;
     int[] mHashes;
     Object[] mArray;
     int mSize;
@@ -236,16 +237,27 @@
      * will grow once items are added to it.
      */
     public ArrayMap() {
-        mHashes = EmptyArray.INT;
-        mArray = EmptyArray.OBJECT;
-        mSize = 0;
+        this(0, false);
     }
 
     /**
      * Create a new ArrayMap with a given initial capacity.
      */
     public ArrayMap(int capacity) {
-        if (capacity == 0) {
+        this(capacity, false);
+    }
+
+    /** {@hide} */
+    public ArrayMap(int capacity, boolean identityHashCode) {
+        mIdentityHashCode = identityHashCode;
+
+        // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
+        // instance instead of the usual EmptyArray.INT. The reference
+        // is checked later to see if the array is allowed to grow.
+        if (capacity < 0) {
+            mHashes = EMPTY_IMMUTABLE_INTS;
+            mArray = EmptyArray.OBJECT;
+        } else if (capacity == 0) {
             mHashes = EmptyArray.INT;
             mArray = EmptyArray.OBJECT;
         } else {
@@ -254,15 +266,6 @@
         mSize = 0;
     }
 
-    private ArrayMap(boolean immutable) {
-        // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
-        // instance instead of the usual EmptyArray.INT. The reference
-        // is checked later to see if the array is allowed to grow.
-        mHashes = immutable ? EMPTY_IMMUTABLE_INTS : EmptyArray.INT;
-        mArray = EmptyArray.OBJECT;
-        mSize = 0;
-    }
-
     /**
      * Create a new ArrayMap with the mappings from the given ArrayMap.
      */
@@ -336,7 +339,8 @@
      * @return Returns the index of the key if it exists, else a negative integer.
      */
     public int indexOfKey(Object key) {
-        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+        return key == null ? indexOfNull()
+                : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
     }
 
     int indexOfValue(Object value) {
@@ -437,7 +441,7 @@
             hash = 0;
             index = indexOfNull();
         } else {
-            hash = key.hashCode();
+            hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
             index = indexOf(key, hash);
         }
         if (index >= 0) {
@@ -488,7 +492,8 @@
      */
     public void append(K key, V value) {
         int index = mSize;
-        final int hash = key == null ? 0 : key.hashCode();
+        final int hash = key == null ? 0
+                : (mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
         if (index >= mHashes.length) {
             throw new IllegalStateException("Array is full");
         }
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index b7a3c42..9e9314f 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -69,6 +69,7 @@
     static Object[] mTwiceBaseCache;
     static int mTwiceBaseCacheSize;
 
+    final boolean mIdentityHashCode;
     int[] mHashes;
     Object[] mArray;
     int mSize;
@@ -222,15 +223,19 @@
      * will grow once items are added to it.
      */
     public ArraySet() {
-        mHashes = EmptyArray.INT;
-        mArray = EmptyArray.OBJECT;
-        mSize = 0;
+        this(0, false);
     }
 
     /**
      * Create a new ArraySet with a given initial capacity.
      */
     public ArraySet(int capacity) {
+        this(capacity, false);
+    }
+
+    /** {@hide} */
+    public ArraySet(int capacity, boolean identityHashCode) {
+        mIdentityHashCode = identityHashCode;
         if (capacity == 0) {
             mHashes = EmptyArray.INT;
             mArray = EmptyArray.OBJECT;
@@ -306,7 +311,8 @@
      * @return Returns the index of the value if it exists, else a negative integer.
      */
     public int indexOf(Object key) {
-        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+        return key == null ? indexOfNull()
+                : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
     }
 
     /**
@@ -343,7 +349,7 @@
             hash = 0;
             index = indexOfNull();
         } else {
-            hash = value.hashCode();
+            hash = mIdentityHashCode ? System.identityHashCode(value) : value.hashCode();
             index = indexOf(value, hash);
         }
         if (index >= 0) {
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index a747f16..d201ade 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -154,11 +154,11 @@
     public static final int DENSITY_DEVICE_STABLE = getDeviceDensity();
 
     /**
-     * The absolute width of the display in pixels.
+     * The absolute width of the available display size in pixels.
      */
     public int widthPixels;
     /**
-     * The absolute height of the display in pixels.
+     * The absolute height of the available display size in pixels.
      */
     public int heightPixels;
     /**
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index fc39004..fa3921c 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -478,8 +478,6 @@
     /**
      * Returns the default locale list, adjusted by moving the default locale to its first
      * position.
-     *
-     * {@hide}
      */
     @NonNull @Size(min=1)
     public static LocaleList getAdjustedDefault() {
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 3d7cb49..5bc6c94 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import android.os.DeadSystemException;
+
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.LineBreakBufferedWriter;
@@ -405,6 +407,11 @@
                 if (t instanceof UnknownHostException) {
                     break;
                 }
+                if (t instanceof DeadSystemException) {
+                    lbbw.println("DeadSystemException: The system died; "
+                            + "earlier logs will point to the root cause");
+                    break;
+                }
                 t = t.getCause();
             }
             if (t == null) {
diff --git a/core/java/android/util/Pair.java b/core/java/android/util/Pair.java
index 6027d08..f96da72 100644
--- a/core/java/android/util/Pair.java
+++ b/core/java/android/util/Pair.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import libcore.util.Objects;
+import java.util.Objects;
 
 /**
  * Container to ease passing around a tuple of two objects. This object provides a sensible
@@ -52,7 +52,7 @@
             return false;
         }
         Pair<?, ?> p = (Pair<?, ?>) o;
-        return Objects.equal(p.first, first) && Objects.equal(p.second, second);
+        return Objects.equals(p.first, first) && Objects.equals(p.second, second);
     }
 
     /**
@@ -65,6 +65,11 @@
         return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
     }
 
+    @Override
+    public String toString() {
+        return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
+    }
+
     /**
      * Convenience method for creating an appropriately typed pair.
      * @param a the first object in the Pair
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 9f2bcfd..9ed4850 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -394,6 +394,36 @@
     public static final Pattern AUTOLINK_WEB_URL = Pattern.compile(
             "(" + WEB_URL_WITH_PROTOCOL + "|" + WEB_URL_WITHOUT_PROTOCOL + ")");
 
+    /**
+     * Regular expression for valid email characters. Does not include some of the valid characters
+     * defined in RFC5321: #&~!^`{}/=$*?|
+     */
+    private static final String EMAIL_CHAR = LABEL_CHAR + "\\+\\-_%'";
+
+    /**
+     * Regular expression for local part of an email address. RFC5321 section 4.5.3.1.1 limits
+     * the local part to be at most 64 octets.
+     */
+    private static final String EMAIL_ADDRESS_LOCAL_PART =
+            "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{1,62}[" + EMAIL_CHAR + "])?";
+
+    /**
+     * Regular expression for the domain part of an email address. RFC5321 section 4.5.3.1.2 limits
+     * the domain to be at most 255 octets.
+     */
+    private static final String EMAIL_ADDRESS_DOMAIN =
+            "(?=.{1,255}(?:\\s|$|^))" + HOST_NAME;
+
+    /**
+     * Regular expression pattern to match email addresses. It excludes double quoted local parts
+     * and the special characters #&~!^`{}/=$*?| that are included in RFC5321.
+     * @hide
+     */
+    public static final Pattern AUTOLINK_EMAIL_ADDRESS = Pattern.compile("(" + WORD_BOUNDARY +
+            "(?:" + EMAIL_ADDRESS_LOCAL_PART + "@" + EMAIL_ADDRESS_DOMAIN + ")" +
+            WORD_BOUNDARY + ")"
+    );
+
     public static final Pattern EMAIL_ADDRESS
         = Pattern.compile(
             "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 98aaa81..bd00aba 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -17,6 +17,7 @@
 package android.util;
 
 import android.annotation.AnyRes;
+import android.content.pm.ActivityInfo.Config;
 
 /**
  * Container for a dynamically typed data value.  Primarily used with
@@ -183,9 +184,11 @@
     @AnyRes
     public int resourceId;
 
-    /** If Value came from a resource, these are the configurations for which
-     *  its contents can change. */
-    public int changingConfigurations = -1;
+    /**
+     * If the value came from a resource, these are the configurations for
+     * which its contents can change.
+     */
+    public @Config int changingConfigurations = -1;
 
     /**
      * If the Value came from a resource, this holds the corresponding pixel density.
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 728f723..78d3b7b 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -16,17 +16,20 @@
 
 package android.util.apk;
 
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.util.ArrayMap;
 import android.util.Pair;
 
 import java.io.ByteArrayInputStream;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.math.BigInteger;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
+import java.nio.DirectByteBuffer;
 import java.security.DigestException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -52,11 +55,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import libcore.io.Libcore;
+import libcore.io.Os;
+
 /**
  * APK Signature Scheme v2 verifier.
  *
@@ -75,6 +80,20 @@
     public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 2;
 
     /**
+     * Returns {@code true} if the provided APK contains an APK Signature Scheme V2 signature.
+     *
+     * <p><b>NOTE: This method does not verify the signature.</b>
+     */
+    public static boolean hasSignature(String apkFile) throws IOException {
+        try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
+            findSignature(apk);
+            return true;
+        } catch (SignatureNotFoundException e) {
+            return false;
+        }
+    }
+
+    /**
      * Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
      * associated with each signer.
      *
@@ -94,98 +113,97 @@
      * associated with each signer.
      *
      * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v2.
-     * @throws SecurityException if a APK Signature Scheme v2 signature of this APK does not verify.
+     * @throws SecurityException if an APK Signature Scheme v2 signature of this APK does not
+     *         verify.
      * @throws IOException if an I/O error occurs while reading the APK file.
      */
-    public static X509Certificate[][] verify(RandomAccessFile apk)
+    private static X509Certificate[][] verify(RandomAccessFile apk)
             throws SignatureNotFoundException, SecurityException, IOException {
-
-        long fileSize = apk.length();
-        if (fileSize > Integer.MAX_VALUE) {
-            throw new IOException("File too large: " + apk.length() + " bytes");
-        }
-        MappedByteBuffer apkContents =
-                apk.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
-        // Attempt to preload the contents into memory for faster overall verification (v2 and
-        // older) at the expense of somewhat increased latency for rejecting malformed APKs.
-        apkContents.load();
-        return verify(apkContents);
+        SignatureInfo signatureInfo = findSignature(apk);
+        return verify(apk.getFD(), signatureInfo);
     }
 
     /**
-     * Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
-     * associated with each signer.
-     *
-     * @param apkContents contents of the APK. The contents start at the current position and end
-     *        at the limit of the buffer.
+     * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
+     * contained in the block against the file.
+     */
+    private static class SignatureInfo {
+        /** Contents of APK Signature Scheme v2 block. */
+        private final ByteBuffer signatureBlock;
+
+        /** Position of the APK Signing Block in the file. */
+        private final long apkSigningBlockOffset;
+
+        /** Position of the ZIP Central Directory in the file. */
+        private final long centralDirOffset;
+
+        /** Position of the ZIP End of Central Directory (EoCD) in the file. */
+        private final long eocdOffset;
+
+        /** Contents of ZIP End of Central Directory (EoCD) of the file. */
+        private final ByteBuffer eocd;
+
+        private SignatureInfo(
+                ByteBuffer signatureBlock,
+                long apkSigningBlockOffset,
+                long centralDirOffset,
+                long eocdOffset,
+                ByteBuffer eocd) {
+            this.signatureBlock = signatureBlock;
+            this.apkSigningBlockOffset = apkSigningBlockOffset;
+            this.centralDirOffset = centralDirOffset;
+            this.eocdOffset = eocdOffset;
+            this.eocd = eocd;
+        }
+    }
+
+    /**
+     * Returns the APK Signature Scheme v2 block contained in the provided APK file and the
+     * additional information relevant for verifying the block against the file.
      *
      * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v2.
-     * @throws SecurityException if a APK Signature Scheme v2 signature of this APK does not verify.
+     * @throws IOException if an I/O error occurs while reading the APK file.
      */
-    public static X509Certificate[][] verify(ByteBuffer apkContents)
-            throws SignatureNotFoundException, SecurityException {
-        // Avoid modifying byte order, position, limit, and mark of the original apkContents.
-        apkContents = apkContents.slice();
-
-        // ZipUtils and APK Signature Scheme v2 verifier expect little-endian byte order.
-        apkContents.order(ByteOrder.LITTLE_ENDIAN);
-
-        // Find the offset of ZIP End of Central Directory (EoCD)
-        int eocdOffset = ZipUtils.findZipEndOfCentralDirectoryRecord(apkContents);
-        if (eocdOffset == -1) {
-            throw new SignatureNotFoundException(
-                    "Not an APK file: ZIP End of Central Directory record not found");
-        }
-        if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apkContents, eocdOffset)) {
+    private static SignatureInfo findSignature(RandomAccessFile apk)
+            throws IOException, SignatureNotFoundException {
+        // Find the ZIP End of Central Directory (EoCD) record.
+        Pair<ByteBuffer, Long> eocdAndOffsetInFile = getEocd(apk);
+        ByteBuffer eocd = eocdAndOffsetInFile.first;
+        long eocdOffset = eocdAndOffsetInFile.second;
+        if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apk, eocdOffset)) {
             throw new SignatureNotFoundException("ZIP64 APK not supported");
         }
-        ByteBuffer eocd = sliceFromTo(apkContents, eocdOffset, apkContents.capacity());
 
-        // Look up the offset of ZIP Central Directory.
-        long centralDirOffsetLong = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
-        if (centralDirOffsetLong >= eocdOffset) {
-            throw new SignatureNotFoundException(
-                    "ZIP Central Directory offset out of range: " + centralDirOffsetLong
-                    + ". ZIP End of Central Directory offset: " + eocdOffset);
-        }
-        long centralDirSizeLong = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
-        if (centralDirOffsetLong + centralDirSizeLong != eocdOffset) {
-            throw new SignatureNotFoundException(
-                    "ZIP Central Directory is not immediately followed by End of Central"
-                    + " Directory");
-        }
-        int centralDirOffset = (int) centralDirOffsetLong;
-
-        // Find the APK Signing Block.
-        int apkSigningBlockOffset = findApkSigningBlock(apkContents, centralDirOffset);
-        ByteBuffer apkSigningBlock =
-                sliceFromTo(apkContents, apkSigningBlockOffset, centralDirOffset);
+        // Find the APK Signing Block. The block immediately precedes the Central Directory.
+        long centralDirOffset = getCentralDirOffset(eocd, eocdOffset);
+        Pair<ByteBuffer, Long> apkSigningBlockAndOffsetInFile =
+                findApkSigningBlock(apk, centralDirOffset);
+        ByteBuffer apkSigningBlock = apkSigningBlockAndOffsetInFile.first;
+        long apkSigningBlockOffset = apkSigningBlockAndOffsetInFile.second;
 
         // Find the APK Signature Scheme v2 Block inside the APK Signing Block.
         ByteBuffer apkSignatureSchemeV2Block = findApkSignatureSchemeV2Block(apkSigningBlock);
 
-        // Verify the contents of the APK outside of the APK Signing Block using the APK Signature
-        // Scheme v2 Block.
-        return verify(
-                apkContents,
+        return new SignatureInfo(
                 apkSignatureSchemeV2Block,
                 apkSigningBlockOffset,
                 centralDirOffset,
-                eocdOffset);
+                eocdOffset,
+                eocd);
     }
 
     /**
-     * Verifies the contents outside of the APK Signing Block using the provided APK Signature
-     * Scheme v2 Block.
+     * Verifies the contents of the provided APK file against the provided APK Signature Scheme v2
+     * Block.
+     *
+     * @param signatureInfo APK Signature Scheme v2 Block and information relevant for verifying it
+     *        against the APK file.
      */
     private static X509Certificate[][] verify(
-            ByteBuffer apkContents,
-            ByteBuffer v2Block,
-            int apkSigningBlockOffset,
-            int centralDirOffset,
-            int eocdOffset) throws SecurityException {
+            FileDescriptor apkFileDescriptor,
+            SignatureInfo signatureInfo) throws SecurityException {
         int signerCount = 0;
-        Map<Integer, byte[]> contentDigests = new HashMap<>();
+        Map<Integer, byte[]> contentDigests = new ArrayMap<>();
         List<X509Certificate[]> signerCerts = new ArrayList<>();
         CertificateFactory certFactory;
         try {
@@ -195,7 +213,7 @@
         }
         ByteBuffer signers;
         try {
-            signers = getLengthPrefixedSlice(v2Block);
+            signers = getLengthPrefixedSlice(signatureInfo.signatureBlock);
         } catch (IOException e) {
             throw new SecurityException("Failed to read list of signers", e);
         }
@@ -222,10 +240,11 @@
 
         verifyIntegrity(
                 contentDigests,
-                apkContents,
-                apkSigningBlockOffset,
-                centralDirOffset,
-                eocdOffset);
+                apkFileDescriptor,
+                signatureInfo.apkSigningBlockOffset,
+                signatureInfo.centralDirOffset,
+                signatureInfo.eocdOffset,
+                signatureInfo.eocd);
 
         return signerCerts.toArray(new X509Certificate[signerCerts.size()][]);
     }
@@ -368,25 +387,38 @@
 
     private static void verifyIntegrity(
             Map<Integer, byte[]> expectedDigests,
-            ByteBuffer apkContents,
-            int apkSigningBlockOffset,
-            int centralDirOffset,
-            int eocdOffset) throws SecurityException {
+            FileDescriptor apkFileDescriptor,
+            long apkSigningBlockOffset,
+            long centralDirOffset,
+            long eocdOffset,
+            ByteBuffer eocdBuf) throws SecurityException {
 
         if (expectedDigests.isEmpty()) {
             throw new SecurityException("No digests provided");
         }
 
-        ByteBuffer beforeApkSigningBlock = sliceFromTo(apkContents, 0, apkSigningBlockOffset);
-        ByteBuffer centralDir = sliceFromTo(apkContents, centralDirOffset, eocdOffset);
+        // We need to verify the integrity of the following three sections of the file:
+        // 1. Everything up to the start of the APK Signing Block.
+        // 2. ZIP Central Directory.
+        // 3. ZIP End of Central Directory (EoCD).
+        // Each of these sections is represented as a separate DataSource instance below.
+
+        // To handle large APKs, these sections are read in 1 MB chunks using memory-mapped I/O to
+        // avoid wasting physical memory. In most APK verification scenarios, the contents of the
+        // APK are already there in the OS's page cache and thus mmap does not use additional
+        // physical memory.
+        DataSource beforeApkSigningBlock =
+                new MemoryMappedFileDataSource(apkFileDescriptor, 0, apkSigningBlockOffset);
+        DataSource centralDir =
+                new MemoryMappedFileDataSource(
+                        apkFileDescriptor, centralDirOffset, eocdOffset - centralDirOffset);
+
         // For the purposes of integrity verification, ZIP End of Central Directory's field Start of
         // Central Directory must be considered to point to the offset of the APK Signing Block.
-        byte[] eocdBytes = new byte[apkContents.capacity() - eocdOffset];
-        apkContents.position(eocdOffset);
-        apkContents.get(eocdBytes);
-        ByteBuffer eocd = ByteBuffer.wrap(eocdBytes);
-        eocd.order(apkContents.order());
-        ZipUtils.setZipEocdCentralDirectoryOffset(eocd, apkSigningBlockOffset);
+        eocdBuf = eocdBuf.duplicate();
+        eocdBuf.order(ByteOrder.LITTLE_ENDIAN);
+        ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, apkSigningBlockOffset);
+        DataSource eocd = new ByteBufferDataSource(eocdBuf);
 
         int[] digestAlgorithms = new int[expectedDigests.size()];
         int digestAlgorithmCount = 0;
@@ -394,30 +426,30 @@
             digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
             digestAlgorithmCount++;
         }
-        Map<Integer, byte[]> actualDigests;
+        byte[][] actualDigests;
         try {
             actualDigests =
                     computeContentDigests(
                             digestAlgorithms,
-                            new ByteBuffer[] {beforeApkSigningBlock, centralDir, eocd});
+                            new DataSource[] {beforeApkSigningBlock, centralDir, eocd});
         } catch (DigestException e) {
             throw new SecurityException("Failed to compute digest(s) of contents", e);
         }
-        for (Map.Entry<Integer, byte[]> entry : expectedDigests.entrySet()) {
-            int digestAlgorithm = entry.getKey();
-            byte[] expectedDigest = entry.getValue();
-            byte[] actualDigest = actualDigests.get(digestAlgorithm);
+        for (int i = 0; i < digestAlgorithms.length; i++) {
+            int digestAlgorithm = digestAlgorithms[i];
+            byte[] expectedDigest = expectedDigests.get(digestAlgorithm);
+            byte[] actualDigest = actualDigests[i];
             if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
                 throw new SecurityException(
                         getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
-                        + " digest of contents did not verify");
+                                + " digest of contents did not verify");
             }
         }
     }
 
-    private static Map<Integer, byte[]> computeContentDigests(
+    private static byte[][] computeContentDigests(
             int[] digestAlgorithms,
-            ByteBuffer[] contents) throws DigestException {
+            DataSource[] contents) throws DigestException {
         // For each digest algorithm the result is computed as follows:
         // 1. Each segment of contents is split into consecutive chunks of 1 MB in size.
         //    The final chunk will be shorter iff the length of segment is not a multiple of 1 MB.
@@ -428,13 +460,18 @@
         //    chunks (uint32 little-endian) and the concatenation of digests of chunks of all
         //    segments in-order.
 
-        int totalChunkCount = 0;
-        for (ByteBuffer input : contents) {
-            totalChunkCount += getChunkCount(input.remaining());
+        long totalChunkCountLong = 0;
+        for (DataSource input : contents) {
+            totalChunkCountLong += getChunkCount(input.size());
         }
+        if (totalChunkCountLong >= Integer.MAX_VALUE / 1024) {
+            throw new DigestException("Too many chunks: " + totalChunkCountLong);
+        }
+        int totalChunkCount = (int) totalChunkCountLong;
 
-        Map<Integer, byte[]> digestsOfChunks = new HashMap<>(totalChunkCount);
-        for (int digestAlgorithm : digestAlgorithms) {
+        byte[][] digestsOfChunks = new byte[digestAlgorithms.length][];
+        for (int i = 0; i < digestAlgorithms.length; i++) {
+            int digestAlgorithm = digestAlgorithms[i];
             int digestOutputSizeBytes = getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
             byte[] concatenationOfChunkCountAndChunkDigests =
                     new byte[5 + totalChunkCount * digestOutputSizeBytes];
@@ -443,49 +480,71 @@
                     totalChunkCount,
                     concatenationOfChunkCountAndChunkDigests,
                     1);
-            digestsOfChunks.put(digestAlgorithm, concatenationOfChunkCountAndChunkDigests);
+            digestsOfChunks[i] = concatenationOfChunkCountAndChunkDigests;
         }
 
         byte[] chunkContentPrefix = new byte[5];
         chunkContentPrefix[0] = (byte) 0xa5;
         int chunkIndex = 0;
-        for (ByteBuffer input : contents) {
-            while (input.hasRemaining()) {
-                int chunkSize = Math.min(input.remaining(), CHUNK_SIZE_BYTES);
-                ByteBuffer chunk = getByteBuffer(input, chunkSize);
-                for (int digestAlgorithm : digestAlgorithms) {
-                    String jcaAlgorithmName =
-                            getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm);
-                    MessageDigest md;
-                    try {
-                        md = MessageDigest.getInstance(jcaAlgorithmName);
-                    } catch (NoSuchAlgorithmException e) {
-                        throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
-                    }
-                    chunk.clear();
-                    setUnsignedInt32LittleEndian(chunk.remaining(), chunkContentPrefix, 1);
-                    md.update(chunkContentPrefix);
-                    md.update(chunk);
-                    byte[] concatenationOfChunkCountAndChunkDigests =
-                            digestsOfChunks.get(digestAlgorithm);
+        MessageDigest[] mds = new MessageDigest[digestAlgorithms.length];
+        for (int i = 0; i < digestAlgorithms.length; i++) {
+            String jcaAlgorithmName =
+                    getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithms[i]);
+            try {
+                mds[i] = MessageDigest.getInstance(jcaAlgorithmName);
+            } catch (NoSuchAlgorithmException e) {
+                throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
+            }
+        }
+        // TODO: Compute digests of chunks in parallel when beneficial. This requires some research
+        // into how to parallelize (if at all) based on the capabilities of the hardware on which
+        // this code is running and based on the size of input.
+        int dataSourceIndex = 0;
+        for (DataSource input : contents) {
+            long inputOffset = 0;
+            long inputRemaining = input.size();
+            while (inputRemaining > 0) {
+                int chunkSize = (int) Math.min(inputRemaining, CHUNK_SIZE_BYTES);
+                setUnsignedInt32LittleEndian(chunkSize, chunkContentPrefix, 1);
+                for (int i = 0; i < mds.length; i++) {
+                    mds[i].update(chunkContentPrefix);
+                }
+                try {
+                    input.feedIntoMessageDigests(mds, inputOffset, chunkSize);
+                } catch (IOException e) {
+                    throw new DigestException(
+                            "Failed to digest chunk #" + chunkIndex + " of section #"
+                                    + dataSourceIndex,
+                            e);
+                }
+                for (int i = 0; i < digestAlgorithms.length; i++) {
+                    int digestAlgorithm = digestAlgorithms[i];
+                    byte[] concatenationOfChunkCountAndChunkDigests = digestsOfChunks[i];
                     int expectedDigestSizeBytes =
                             getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
-                    int actualDigestSizeBytes = md.digest(concatenationOfChunkCountAndChunkDigests,
-                            5 + chunkIndex * expectedDigestSizeBytes, expectedDigestSizeBytes);
+                    MessageDigest md = mds[i];
+                    int actualDigestSizeBytes =
+                            md.digest(
+                                    concatenationOfChunkCountAndChunkDigests,
+                                    5 + chunkIndex * expectedDigestSizeBytes,
+                                    expectedDigestSizeBytes);
                     if (actualDigestSizeBytes != expectedDigestSizeBytes) {
                         throw new RuntimeException(
                                 "Unexpected output size of " + md.getAlgorithm() + " digest: "
                                         + actualDigestSizeBytes);
                     }
                 }
+                inputOffset += chunkSize;
+                inputRemaining -= chunkSize;
                 chunkIndex++;
             }
+            dataSourceIndex++;
         }
 
-        Map<Integer, byte[]> result = new HashMap<>(digestAlgorithms.length);
-        for (Map.Entry<Integer, byte[]> entry : digestsOfChunks.entrySet()) {
-            int digestAlgorithm = entry.getKey();
-            byte[] input = entry.getValue();
+        byte[][] result = new byte[digestAlgorithms.length][];
+        for (int i = 0; i < digestAlgorithms.length; i++) {
+            int digestAlgorithm = digestAlgorithms[i];
+            byte[] input = digestsOfChunks[i];
             String jcaAlgorithmName = getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm);
             MessageDigest md;
             try {
@@ -494,12 +553,47 @@
                 throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
             }
             byte[] output = md.digest(input);
-            result.put(digestAlgorithm, output);
+            result[i] = output;
         }
         return result;
     }
 
-    private static final int getChunkCount(int inputSizeBytes) {
+    /**
+     * Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
+     *
+     * @throws IOException if an I/O error occurs while reading the file.
+     * @throws SignatureNotFoundException if the EoCD could not be found.
+     */
+    private static Pair<ByteBuffer, Long> getEocd(RandomAccessFile apk)
+            throws IOException, SignatureNotFoundException {
+        Pair<ByteBuffer, Long> eocdAndOffsetInFile =
+                ZipUtils.findZipEndOfCentralDirectoryRecord(apk);
+        if (eocdAndOffsetInFile == null) {
+            throw new SignatureNotFoundException(
+                    "Not an APK file: ZIP End of Central Directory record not found");
+        }
+        return eocdAndOffsetInFile;
+    }
+
+    private static long getCentralDirOffset(ByteBuffer eocd, long eocdOffset)
+            throws SignatureNotFoundException {
+        // Look up the offset of ZIP Central Directory.
+        long centralDirOffset = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
+        if (centralDirOffset >= eocdOffset) {
+            throw new SignatureNotFoundException(
+                    "ZIP Central Directory offset out of range: " + centralDirOffset
+                    + ". ZIP End of Central Directory offset: " + eocdOffset);
+        }
+        long centralDirSize = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
+        if (centralDirOffset + centralDirSize != eocdOffset) {
+            throw new SignatureNotFoundException(
+                    "ZIP Central Directory is not immediately followed by End of Central"
+                    + " Directory");
+        }
+        return centralDirOffset;
+    }
+
+    private static final long getChunkCount(long inputSizeBytes) {
         return (inputSizeBytes + CHUNK_SIZE_BYTES - 1) / CHUNK_SIZE_BYTES;
     }
 
@@ -512,7 +606,6 @@
     private static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
     private static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
     private static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
-    private static final int SIGNATURE_DSA_WITH_SHA512 = 0x0302;
 
     private static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
     private static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
@@ -526,7 +619,6 @@
             case SIGNATURE_ECDSA_WITH_SHA256:
             case SIGNATURE_ECDSA_WITH_SHA512:
             case SIGNATURE_DSA_WITH_SHA256:
-            case SIGNATURE_DSA_WITH_SHA512:
                 return true;
             default:
                 return false;
@@ -576,7 +668,6 @@
             case SIGNATURE_RSA_PSS_WITH_SHA512:
             case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
             case SIGNATURE_ECDSA_WITH_SHA512:
-            case SIGNATURE_DSA_WITH_SHA512:
                 return CONTENT_DIGEST_CHUNKED_SHA512;
             default:
                 throw new IllegalArgumentException(
@@ -620,7 +711,6 @@
             case SIGNATURE_ECDSA_WITH_SHA512:
                 return "EC";
             case SIGNATURE_DSA_WITH_SHA256:
-            case SIGNATURE_DSA_WITH_SHA512:
                 return "DSA";
             default:
                 throw new IllegalArgumentException(
@@ -652,8 +742,6 @@
                 return Pair.create("SHA512withECDSA", null);
             case SIGNATURE_DSA_WITH_SHA256:
                 return Pair.create("SHA256withDSA", null);
-            case SIGNATURE_DSA_WITH_SHA512:
-                return Pair.create("SHA512withDSA", null);
             default:
                 throw new IllegalArgumentException(
                         "Unknown signature algorithm: 0x"
@@ -767,10 +855,9 @@
 
     private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
 
-    private static int findApkSigningBlock(ByteBuffer apkContents, int centralDirOffset)
-            throws SignatureNotFoundException {
-        checkByteOrderLittleEndian(apkContents);
-
+    private static Pair<ByteBuffer, Long> findApkSigningBlock(
+            RandomAccessFile apk, long centralDirOffset)
+                    throws IOException, SignatureNotFoundException {
         // FORMAT:
         // OFFSET       DATA TYPE  DESCRIPTION
         // * @+0  bytes uint64:    size in bytes (excluding this field)
@@ -783,32 +870,42 @@
                     "APK too small for APK Signing Block. ZIP Central Directory offset: "
                             + centralDirOffset);
         }
-        // Check magic field present
-        if ((apkContents.getLong(centralDirOffset - 16) != APK_SIG_BLOCK_MAGIC_LO)
-                || (apkContents.getLong(centralDirOffset - 8) != APK_SIG_BLOCK_MAGIC_HI)) {
+        // Read the magic and offset in file from the footer section of the block:
+        // * uint64:   size of block
+        // * 16 bytes: magic
+        ByteBuffer footer = ByteBuffer.allocate(24);
+        footer.order(ByteOrder.LITTLE_ENDIAN);
+        apk.seek(centralDirOffset - footer.capacity());
+        apk.readFully(footer.array(), footer.arrayOffset(), footer.capacity());
+        if ((footer.getLong(8) != APK_SIG_BLOCK_MAGIC_LO)
+                || (footer.getLong(16) != APK_SIG_BLOCK_MAGIC_HI)) {
             throw new SignatureNotFoundException(
                     "No APK Signing Block before ZIP Central Directory");
         }
         // Read and compare size fields
-        long apkSigBlockSizeLong = apkContents.getLong(centralDirOffset - 24);
-        if ((apkSigBlockSizeLong < 24) || (apkSigBlockSizeLong > Integer.MAX_VALUE - 8)) {
+        long apkSigBlockSizeInFooter = footer.getLong(0);
+        if ((apkSigBlockSizeInFooter < footer.capacity())
+                || (apkSigBlockSizeInFooter > Integer.MAX_VALUE - 8)) {
             throw new SignatureNotFoundException(
-                    "APK Signing Block size out of range: " + apkSigBlockSizeLong);
+                    "APK Signing Block size out of range: " + apkSigBlockSizeInFooter);
         }
-        int apkSigBlockSizeFromFooter = (int) apkSigBlockSizeLong;
-        int totalSize = apkSigBlockSizeFromFooter + 8;
-        int apkSigBlockOffset = centralDirOffset - totalSize;
+        int totalSize = (int) (apkSigBlockSizeInFooter + 8);
+        long apkSigBlockOffset = centralDirOffset - totalSize;
         if (apkSigBlockOffset < 0) {
             throw new SignatureNotFoundException(
                     "APK Signing Block offset out of range: " + apkSigBlockOffset);
         }
-        long apkSigBlockSizeFromHeader = apkContents.getLong(apkSigBlockOffset);
-        if (apkSigBlockSizeFromHeader != apkSigBlockSizeFromFooter) {
+        ByteBuffer apkSigBlock = ByteBuffer.allocate(totalSize);
+        apkSigBlock.order(ByteOrder.LITTLE_ENDIAN);
+        apk.seek(apkSigBlockOffset);
+        apk.readFully(apkSigBlock.array(), apkSigBlock.arrayOffset(), apkSigBlock.capacity());
+        long apkSigBlockSizeInHeader = apkSigBlock.getLong(0);
+        if (apkSigBlockSizeInHeader != apkSigBlockSizeInFooter) {
             throw new SignatureNotFoundException(
                     "APK Signing Block sizes in header and footer do not match: "
-                            + apkSigBlockSizeFromHeader + " vs " + apkSigBlockSizeFromFooter);
+                            + apkSigBlockSizeInHeader + " vs " + apkSigBlockSizeInFooter);
         }
-        return apkSigBlockOffset;
+        return Pair.create(apkSigBlock, apkSigBlockOffset);
     }
 
     private static ByteBuffer findApkSignatureSchemeV2Block(ByteBuffer apkSigningBlock)
@@ -860,6 +957,8 @@
     }
 
     public static class SignatureNotFoundException extends Exception {
+        private static final long serialVersionUID = 1L;
+
         public SignatureNotFoundException(String message) {
             super(message);
         }
@@ -870,6 +969,159 @@
     }
 
     /**
+     * Source of data to be digested.
+     */
+    private static interface DataSource {
+
+        /**
+         * Returns the size (in bytes) of the data offered by this source.
+         */
+        long size();
+
+        /**
+         * Feeds the specified region of this source's data into the provided digests. Each digest
+         * instance gets the same data.
+         *
+         * @param offset offset of the region inside this data source.
+         * @param size size (in bytes) of the region.
+         */
+        void feedIntoMessageDigests(MessageDigest[] mds, long offset, int size) throws IOException;
+    }
+
+    /**
+     * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
+     * of the file requested by
+     * {@link DataSource#feedIntoMessageDigests(MessageDigest[], long, int) feedIntoMessageDigests}.
+     */
+    private static final class MemoryMappedFileDataSource implements DataSource {
+        private static final Os OS = Libcore.os;
+        private static final long MEMORY_PAGE_SIZE_BYTES = OS.sysconf(OsConstants._SC_PAGESIZE);
+
+        private final FileDescriptor mFd;
+        private final long mFilePosition;
+        private final long mSize;
+
+        /**
+         * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
+         *
+         * @param position start position of the region in the file.
+         * @param size size (in bytes) of the region.
+         */
+        public MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
+            mFd = fd;
+            mFilePosition = position;
+            mSize = size;
+        }
+
+        @Override
+        public long size() {
+            return mSize;
+        }
+
+        @Override
+        public void feedIntoMessageDigests(
+                MessageDigest[] mds, long offset, int size) throws IOException {
+            // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
+            // method was settled on a straightforward mmap with prefaulting.
+            //
+            // This method is not using FileChannel.map API because that API does not offset a way
+            // to "prefault" the resulting memory pages. Without prefaulting, performance is about
+            // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
+            // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
+            // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
+            // time, which is not compensated for by faster reads.
+
+            // We mmap the smallest region of the file containing the requested data. mmap requires
+            // that the start offset in the file must be a multiple of memory page size. We thus may
+            // need to mmap from an offset less than the requested offset.
+            long filePosition = mFilePosition + offset;
+            long mmapFilePosition =
+                    (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
+            int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
+            long mmapRegionSize = size + dataStartOffsetInMmapRegion;
+            long mmapPtr = 0;
+            try {
+                mmapPtr = OS.mmap(
+                        0, // let the OS choose the start address of the region in memory
+                        mmapRegionSize,
+                        OsConstants.PROT_READ,
+                        OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
+                        mFd,
+                        mmapFilePosition);
+                // Feeding a memory region into MessageDigest requires the region to be represented
+                // as a direct ByteBuffer.
+                ByteBuffer buf = new DirectByteBuffer(
+                        size,
+                        mmapPtr + dataStartOffsetInMmapRegion,
+                        mFd,  // not really needed, but just in case
+                        null, // no need to clean up -- it's taken care of by the finally block
+                        true  // read only buffer
+                        );
+                for (MessageDigest md : mds) {
+                    buf.position(0);
+                    md.update(buf);
+                }
+            } catch (ErrnoException e) {
+                throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
+            } finally {
+                if (mmapPtr != 0) {
+                    try {
+                        OS.munmap(mmapPtr, mmapRegionSize);
+                    } catch (ErrnoException ignored) {}
+                }
+            }
+        }
+    }
+
+    /**
+     * {@link DataSource} which provides data from a {@link ByteBuffer}.
+     */
+    private static final class ByteBufferDataSource implements DataSource {
+        /**
+         * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
+         * The buffer's position is 0 and limit is equal to capacity.
+         */
+        private final ByteBuffer mBuf;
+
+        public ByteBufferDataSource(ByteBuffer buf) {
+            // Defensive copy, to avoid changes to mBuf being visible in buf.
+            mBuf = buf.slice();
+        }
+
+        @Override
+        public long size() {
+            return mBuf.capacity();
+        }
+
+        @Override
+        public void feedIntoMessageDigests(
+                MessageDigest[] mds, long offset, int size) throws IOException {
+            // There's no way to tell MessageDigest to read data from ByteBuffer from a position
+            // other than the buffer's current position. We thus need to change the buffer's
+            // position to match the requested offset.
+            //
+            // In the future, it may be necessary to compute digests of multiple regions in
+            // parallel. Given that digest computation is a slow operation, we enable multiple
+            // such requests to be fulfilled by this instance. This is achieved by serially
+            // creating a new ByteBuffer corresponding to the requested data range and then,
+            // potentially concurrently, feeding these buffers into MessageDigest instances.
+            ByteBuffer region;
+            synchronized (mBuf) {
+                mBuf.position((int) offset);
+                mBuf.limit((int) offset + size);
+                region = mBuf.slice();
+            }
+
+            for (MessageDigest md : mds) {
+                // Need to reset position to 0 at the start of each iteration because
+                // MessageDigest.update below sets it to the buffer's limit.
+                region.position(0);
+                md.update(region);
+            }
+        }
+    }
+
+    /**
      * For legacy reasons we need to return exactly the original encoded certificate bytes, instead
      * of letting the underlying implementation have a shot at re-encoding the data.
      */
diff --git a/core/java/android/util/apk/ZipUtils.java b/core/java/android/util/apk/ZipUtils.java
index a383d5c..cdbac18 100644
--- a/core/java/android/util/apk/ZipUtils.java
+++ b/core/java/android/util/apk/ZipUtils.java
@@ -16,13 +16,17 @@
 
 package android.util.apk;
 
+import android.util.Pair;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
 /**
  * Assorted ZIP format helpers.
  *
- * <p>NOTE: Most helper methods operating on {@code ByteBuffer} instances except that the byte
+ * <p>NOTE: Most helper methods operating on {@code ByteBuffer} instances expect that the byte
  * order of these buffers is little-endian.
  */
 abstract class ZipUtils {
@@ -35,9 +39,101 @@
     private static final int ZIP_EOCD_COMMENT_LENGTH_FIELD_OFFSET = 20;
 
     private static final int ZIP64_EOCD_LOCATOR_SIZE = 20;
-    private static final int ZIP64_EOCD_LOCATOR_SIG = 0x07064b50;
+    private static final int ZIP64_EOCD_LOCATOR_SIG_REVERSE_BYTE_ORDER = 0x504b0607;
 
-    private static final int UINT32_MAX_VALUE = 0xffff;
+    private static final int UINT16_MAX_VALUE = 0xffff;
+
+    /**
+     * Returns the ZIP End of Central Directory record of the provided ZIP file.
+     *
+     * @return contents of the ZIP End of Central Directory record and the record's offset in the
+     *         file or {@code null} if the file does not contain the record.
+     *
+     * @throws IOException if an I/O error occurs while reading the file.
+     */
+    static Pair<ByteBuffer, Long> findZipEndOfCentralDirectoryRecord(RandomAccessFile zip)
+            throws IOException {
+        // ZIP End of Central Directory (EOCD) record is located at the very end of the ZIP archive.
+        // The record can be identified by its 4-byte signature/magic which is located at the very
+        // beginning of the record. A complication is that the record is variable-length because of
+        // the comment field.
+        // The algorithm for locating the ZIP EOCD record is as follows. We search backwards from
+        // end of the buffer for the EOCD record signature. Whenever we find a signature, we check
+        // the candidate record's comment length is such that the remainder of the record takes up
+        // exactly the remaining bytes in the buffer. The search is bounded because the maximum
+        // size of the comment field is 65535 bytes because the field is an unsigned 16-bit number.
+
+        long fileSize = zip.length();
+        if (fileSize < ZIP_EOCD_REC_MIN_SIZE) {
+            return null;
+        }
+
+        // Optimization: 99.99% of APKs have a zero-length comment field in the EoCD record and thus
+        // the EoCD record offset is known in advance. Try that offset first to avoid unnecessarily
+        // reading more data.
+        Pair<ByteBuffer, Long> result = findZipEndOfCentralDirectoryRecord(zip, 0);
+        if (result != null) {
+            return result;
+        }
+
+        // EoCD does not start where we expected it to. Perhaps it contains a non-empty comment
+        // field. Expand the search. The maximum size of the comment field in EoCD is 65535 because
+        // the comment length field is an unsigned 16-bit number.
+        return findZipEndOfCentralDirectoryRecord(zip, UINT16_MAX_VALUE);
+    }
+
+    /**
+     * Returns the ZIP End of Central Directory record of the provided ZIP file.
+     *
+     * @param maxCommentSize maximum accepted size (in bytes) of EoCD comment field. The permitted
+     *        value is from 0 to 65535 inclusive. The smaller the value, the faster this method
+     *        locates the record, provided its comment field is no longer than this value.
+     *
+     * @return contents of the ZIP End of Central Directory record and the record's offset in the
+     *         file or {@code null} if the file does not contain the record.
+     *
+     * @throws IOException if an I/O error occurs while reading the file.
+     */
+    private static Pair<ByteBuffer, Long> findZipEndOfCentralDirectoryRecord(
+            RandomAccessFile zip, int maxCommentSize) throws IOException {
+        // ZIP End of Central Directory (EOCD) record is located at the very end of the ZIP archive.
+        // The record can be identified by its 4-byte signature/magic which is located at the very
+        // beginning of the record. A complication is that the record is variable-length because of
+        // the comment field.
+        // The algorithm for locating the ZIP EOCD record is as follows. We search backwards from
+        // end of the buffer for the EOCD record signature. Whenever we find a signature, we check
+        // the candidate record's comment length is such that the remainder of the record takes up
+        // exactly the remaining bytes in the buffer. The search is bounded because the maximum
+        // size of the comment field is 65535 bytes because the field is an unsigned 16-bit number.
+
+        if ((maxCommentSize < 0) || (maxCommentSize > UINT16_MAX_VALUE)) {
+            throw new IllegalArgumentException("maxCommentSize: " + maxCommentSize);
+        }
+
+        long fileSize = zip.length();
+        if (fileSize < ZIP_EOCD_REC_MIN_SIZE) {
+            // No space for EoCD record in the file.
+            return null;
+        }
+        // Lower maxCommentSize if the file is too small.
+        maxCommentSize = (int) Math.min(maxCommentSize, fileSize - ZIP_EOCD_REC_MIN_SIZE);
+
+        ByteBuffer buf = ByteBuffer.allocate(ZIP_EOCD_REC_MIN_SIZE + maxCommentSize);
+        buf.order(ByteOrder.LITTLE_ENDIAN);
+        long bufOffsetInFile = fileSize - buf.capacity();
+        zip.seek(bufOffsetInFile);
+        zip.readFully(buf.array(), buf.arrayOffset(), buf.capacity());
+        int eocdOffsetInBuf = findZipEndOfCentralDirectoryRecord(buf);
+        if (eocdOffsetInBuf == -1) {
+            // No EoCD record found in the buffer
+            return null;
+        }
+        // EoCD found
+        buf.position(eocdOffsetInBuf);
+        ByteBuffer eocd = buf.slice();
+        eocd.order(ByteOrder.LITTLE_ENDIAN);
+        return Pair.create(eocd, bufOffsetInFile + eocdOffsetInBuf);
+    }
 
     /**
      * Returns the position at which ZIP End of Central Directory record starts in the provided
@@ -45,7 +141,7 @@
      *
      * <p>NOTE: Byte order of {@code zipContents} must be little-endian.
      */
-    public static int findZipEndOfCentralDirectoryRecord(ByteBuffer zipContents) {
+    private static int findZipEndOfCentralDirectoryRecord(ByteBuffer zipContents) {
         assertByteOrderLittleEndian(zipContents);
 
         // ZIP End of Central Directory (EOCD) record is located at the very end of the ZIP archive.
@@ -56,14 +152,13 @@
         // end of the buffer for the EOCD record signature. Whenever we find a signature, we check
         // the candidate record's comment length is such that the remainder of the record takes up
         // exactly the remaining bytes in the buffer. The search is bounded because the maximum
-        // size of the comment field is 65535 bytes because the field is an unsigned 32-bit number.
+        // size of the comment field is 65535 bytes because the field is an unsigned 16-bit number.
 
         int archiveSize = zipContents.capacity();
         if (archiveSize < ZIP_EOCD_REC_MIN_SIZE) {
-            System.out.println("File size smaller than EOCD min size");
             return -1;
         }
-        int maxCommentLength = Math.min(archiveSize - ZIP_EOCD_REC_MIN_SIZE, UINT32_MAX_VALUE);
+        int maxCommentLength = Math.min(archiveSize - ZIP_EOCD_REC_MIN_SIZE, UINT16_MAX_VALUE);
         int eocdWithEmptyCommentStartPosition = archiveSize - ZIP_EOCD_REC_MIN_SIZE;
         for (int expectedCommentLength = 0; expectedCommentLength < maxCommentLength;
                 expectedCommentLength++) {
@@ -82,24 +177,28 @@
     }
 
     /**
-     * Returns {@code true} if the provided buffer contains a ZIP64 End of Central Directory
+     * Returns {@code true} if the provided file contains a ZIP64 End of Central Directory
      * Locator.
      *
-     * <p>NOTE: Byte order of {@code zipContents} must be little-endian.
+     * @param zipEndOfCentralDirectoryPosition offset of the ZIP End of Central Directory record
+     *        in the file.
+     *
+     * @throws IOException if an I/O error occurs while reading the file.
      */
     public static final boolean isZip64EndOfCentralDirectoryLocatorPresent(
-            ByteBuffer zipContents, int zipEndOfCentralDirectoryPosition) {
-        assertByteOrderLittleEndian(zipContents);
+            RandomAccessFile zip, long zipEndOfCentralDirectoryPosition) throws IOException {
 
         // ZIP64 End of Central Directory Locator immediately precedes the ZIP End of Central
         // Directory Record.
-
-        int locatorPosition = zipEndOfCentralDirectoryPosition - ZIP64_EOCD_LOCATOR_SIZE;
+        long locatorPosition = zipEndOfCentralDirectoryPosition - ZIP64_EOCD_LOCATOR_SIZE;
         if (locatorPosition < 0) {
             return false;
         }
 
-        return zipContents.getInt(locatorPosition) == ZIP64_EOCD_LOCATOR_SIG;
+        zip.seek(locatorPosition);
+        // RandomAccessFile.readInt assumes big-endian byte order, but ZIP format uses
+        // little-endian.
+        return zip.readInt() == ZIP64_EOCD_LOCATOR_SIG_REVERSE_BYTE_ORDER;
     }
 
     /**
diff --git a/core/java/android/util/jar/StrictJarFile.java b/core/java/android/util/jar/StrictJarFile.java
index 302a08d..5d94b06 100644
--- a/core/java/android/util/jar/StrictJarFile.java
+++ b/core/java/android/util/jar/StrictJarFile.java
@@ -58,11 +58,22 @@
 
     public StrictJarFile(String fileName)
             throws IOException, SecurityException {
-        this(fileName, true);
+        this(fileName, true, true);
     }
 
-    public StrictJarFile(String fileName, boolean verify)
-            throws IOException, SecurityException {
+    /**
+     *
+     * @param verify whether to verify the file's JAR signatures and collect the corresponding
+     *        signer certificates.
+     * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against
+     *        stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or
+     *        {@code false} to ignore any such protections. This parameter is ignored when
+     *        {@code verify} is {@code false}.
+     */
+    public StrictJarFile(String fileName,
+            boolean verify,
+            boolean signatureSchemeRollbackProtectionsEnforced)
+                    throws IOException, SecurityException {
         this.nativeHandle = nativeOpenJarFile(fileName);
         this.raf = new RandomAccessFile(fileName, "r");
 
@@ -73,7 +84,12 @@
             if (verify) {
                 HashMap<String, byte[]> metaEntries = getMetaEntries();
                 this.manifest = new StrictJarManifest(metaEntries.get(JarFile.MANIFEST_NAME), true);
-                this.verifier = new StrictJarVerifier(fileName, manifest, metaEntries);
+                this.verifier =
+                        new StrictJarVerifier(
+                                fileName,
+                                manifest,
+                                metaEntries,
+                                signatureSchemeRollbackProtectionsEnforced);
                 Set<String> files = manifest.getEntries().keySet();
                 for (String file : files) {
                     if (findEntry(file) == null) {
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index 0546a5f..6da50ba 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -72,6 +72,7 @@
     private final StrictJarManifest manifest;
     private final HashMap<String, byte[]> metaEntries;
     private final int mainAttributesEnd;
+    private final boolean signatureSchemeRollbackProtectionsEnforced;
 
     private final Hashtable<String, HashMap<String, Attributes>> signatures =
             new Hashtable<String, HashMap<String, Attributes>>(5);
@@ -164,13 +165,19 @@
      *
      * @param name
      *            the name of the JAR file being verified.
+     *
+     * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against
+     *        stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or
+     *        {@code false} to ignore any such protections.
      */
     StrictJarVerifier(String name, StrictJarManifest manifest,
-        HashMap<String, byte[]> metaEntries) {
+        HashMap<String, byte[]> metaEntries, boolean signatureSchemeRollbackProtectionsEnforced) {
         jarName = name;
         this.manifest = manifest;
         this.metaEntries = metaEntries;
         this.mainAttributesEnd = manifest.getMainAttributesEnd();
+        this.signatureSchemeRollbackProtectionsEnforced =
+                signatureSchemeRollbackProtectionsEnforced;
     }
 
     /**
@@ -357,40 +364,42 @@
             return;
         }
 
-        // Check whether APK Signature Scheme v2 signature was stripped.
-        String apkSignatureSchemeIdList =
-                attributes.getValue(
-                        ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME);
-        if (apkSignatureSchemeIdList != null) {
-            // This field contains a comma-separated list of APK signature scheme IDs which were
-            // used to sign this APK. If an ID is known to us, it means signatures of that scheme
-            // were stripped from the APK because otherwise we wouldn't have fallen back to
-            // verifying the APK using the JAR signature scheme.
-            boolean v2SignatureGenerated = false;
-            StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
-            while (tokenizer.hasMoreTokens()) {
-                String idText = tokenizer.nextToken().trim();
-                if (idText.isEmpty()) {
-                    continue;
+        // If requested, check whether APK Signature Scheme v2 signature was stripped.
+        if (signatureSchemeRollbackProtectionsEnforced) {
+            String apkSignatureSchemeIdList =
+                    attributes.getValue(
+                            ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME);
+            if (apkSignatureSchemeIdList != null) {
+                // This field contains a comma-separated list of APK signature scheme IDs which
+                // were used to sign this APK. If an ID is known to us, it means signatures of that
+                // scheme were stripped from the APK because otherwise we wouldn't have fallen back
+                // to verifying the APK using the JAR signature scheme.
+                boolean v2SignatureGenerated = false;
+                StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
+                while (tokenizer.hasMoreTokens()) {
+                    String idText = tokenizer.nextToken().trim();
+                    if (idText.isEmpty()) {
+                        continue;
+                    }
+                    int id;
+                    try {
+                        id = Integer.parseInt(idText);
+                    } catch (Exception ignored) {
+                        continue;
+                    }
+                    if (id == ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) {
+                        // This APK was supposed to be signed with APK Signature Scheme v2 but no
+                        // such signature was found.
+                        v2SignatureGenerated = true;
+                        break;
+                    }
                 }
-                int id;
-                try {
-                    id = Integer.parseInt(idText);
-                } catch (Exception ignored) {
-                    continue;
-                }
-                if (id == ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) {
-                    // This APK was supposed to be signed with APK Signature Scheme v2 but no such
-                    // signature was found.
-                    v2SignatureGenerated = true;
-                    break;
-                }
-            }
 
-            if (v2SignatureGenerated) {
-                throw new SecurityException(signatureFile + " indicates " + jarName + " is signed"
-                        + " using APK Signature Scheme v2, but no such signature was found."
-                        + " Signature stripped?");
+                if (v2SignatureGenerated) {
+                    throw new SecurityException(signatureFile + " indicates " + jarName
+                            + " is signed using APK Signature Scheme v2, but no such signature was"
+                            + " found. Signature stripped?");
+                }
             }
         }
 
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index 4888877..86318e9 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -101,6 +101,15 @@
         mOverrideConfiguration = new Configuration(overrideConfiguration);
     }
 
+    /**
+     * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
+     * callbacks.
+     * @hide
+     */
+    public Configuration getOverrideConfiguration() {
+        return mOverrideConfiguration;
+    }
+
     @Override
     public AssetManager getAssets() {
         // Ensure we're returning assets with the correct configuration.
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 1269ad9..22d5ed8 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
@@ -31,6 +32,8 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 
 import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM;
@@ -715,6 +718,14 @@
     }
 
     /**
+     * Returns the display's HDR capabilities.
+     * @hide
+     */
+    public HdrCapabilities getHdrCapabilities() {
+        return new HdrCapabilities();
+    }
+
+    /**
      * Gets the supported color transforms of this device.
      * @hide
      */
@@ -762,14 +773,23 @@
 
     /**
      * Gets display metrics that describe the size and density of this display.
-     * <p>
-     * The size is adjusted based on the current rotation of the display.
-     * </p><p>
      * The size returned by this method does not necessarily represent the
-     * actual raw size (native resolution) of the display.  The returned size may
-     * be adjusted to exclude certain system decor elements that are always visible.
-     * It may also be scaled to provide compatibility with older applications that
+     * actual raw size (native resolution) of the display.
+     * <p>
+     * 1. The returned size may be adjusted to exclude certain system decor elements
+     * that are always visible.
+     * </p><p>
+     * 2. It may be scaled to provide compatibility with older applications that
      * were originally designed for smaller displays.
+     * </p><p>
+     * 3. It can be different depending on the WindowManager to which the display belongs.
+     * <pre>
+     * - If requested from non-Activity context (e.g. Application context via
+     * {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)})
+     * metrics will report real size of the display based on current rotation.
+     * - If requested from activity resulting metrics will correspond to current window metrics.
+     * In this case the size can be smaller than physical size in multi-window mode.
+     * </pre>
      * </p>
      *
      * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
@@ -807,7 +827,7 @@
      * The size is adjusted based on the current rotation of the display.
      * </p><p>
      * The real size may be smaller than the physical size of the screen when the
-     * window manager is emulating a smaller display (using adb shell am display-size).
+     * window manager is emulating a smaller display (using adb shell wm size).
      * </p>
      *
      * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
@@ -816,8 +836,7 @@
         synchronized (this) {
             updateDisplayInfoLocked();
             mDisplayInfo.getLogicalMetrics(outMetrics,
-                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,
-                    mDisplayAdjustments.getConfiguration());
+                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
         }
     }
 
@@ -1104,6 +1123,117 @@
     }
 
     /**
+     * Encapsulates the HDR capabilities of a given display.
+     * For example, what HDR types it supports and details about the desired luminance data.
+     * <p>You can get an instance for a given {@link Display} object with
+     * {@link Display#getHdrCapabilities getHdrCapabilities()}.
+     * @hide
+     */
+    public static final class HdrCapabilities implements Parcelable {
+        /**
+         * Invalid luminance value.
+         */
+        public static final float INVALID_LUMINANCE = -1;
+        /**
+         * Dolby Vision high dynamic range (HDR) display.
+         */
+        public static final int HDR_TYPE_DOLBY_VISION = 1;
+        /**
+         * HDR10 display.
+         */
+        public static final int HDR_TYPE_HDR10 = 2;
+        /**
+         * Hybrid Log-Gamma HDR display.
+         */
+        public static final int HDR_TYPE_HLG = 3;
+
+        @IntDef({
+            HDR_TYPE_DOLBY_VISION,
+            HDR_TYPE_HDR10,
+            HDR_TYPE_HLG,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface HdrType {}
+
+        private @HdrType int[] mSupportedHdrTypes = new int[0];
+        private float mMaxLuminance = INVALID_LUMINANCE;
+        private float mMaxAverageLuminance = INVALID_LUMINANCE;
+        private float mMinLuminance = INVALID_LUMINANCE;
+
+        public HdrCapabilities() {
+        }
+
+        /**
+         * Gets the supported HDR types of this display.
+         * Returns empty array if HDR is not supported by the display.
+         */
+        public @HdrType int[] getSupportedHdrTypes() {
+            return mSupportedHdrTypes;
+        }
+        /**
+         * Returns the desired content max luminance data in cd/m2 for this display.
+         */
+        public float getDesiredMaxLuminance() {
+            return mMaxLuminance;
+        }
+        /**
+         * Returns the desired content max frame-average luminance data in cd/m2 for this display.
+         */
+        public float getDesiredMaxAverageLuminance() {
+            return mMaxAverageLuminance;
+        }
+        /**
+         * Returns the desired content min luminance data in cd/m2 for this display.
+         */
+        public float getDesiredMinLuminance() {
+            return mMinLuminance;
+        }
+
+        public static final Creator<HdrCapabilities> CREATOR = new Creator<HdrCapabilities>() {
+            @Override
+            public HdrCapabilities createFromParcel(Parcel source) {
+                return new HdrCapabilities(source);
+            }
+
+            @Override
+            public HdrCapabilities[] newArray(int size) {
+                return new HdrCapabilities[size];
+            }
+        };
+
+        private HdrCapabilities(Parcel source) {
+            readFromParcel(source);
+        }
+
+        public void readFromParcel(Parcel source) {
+            int types = source.readInt();
+            mSupportedHdrTypes = new int[types];
+            for (int i = 0; i < types; ++i) {
+                mSupportedHdrTypes[i] = source.readInt();
+            }
+            mMaxLuminance = source.readFloat();
+            mMaxAverageLuminance = source.readFloat();
+            mMinLuminance = source.readFloat();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mSupportedHdrTypes.length);
+            for (int i = 0; i < mSupportedHdrTypes.length; ++i) {
+                dest.writeInt(mSupportedHdrTypes[i]);
+            }
+            dest.writeFloat(mMaxLuminance);
+            dest.writeFloat(mMaxAverageLuminance);
+            dest.writeFloat(mMinLuminance);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+    }
+
+    /**
      * A color transform supported by a given display.
      *
      * @see Display#getSupportedColorTransforms()
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index a12434c..41c44f1 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.Nullable;
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
 import android.graphics.Paint;
@@ -51,8 +52,8 @@
      * @param paint The paint used when the layer is drawn into the destination canvas.
      * @see View#setLayerPaint(android.graphics.Paint)
      */
-    public void setLayerPaint(Paint paint) {
-        nSetLayerPaint(mFinalizer.get(), paint.getNativeInstance());
+    public void setLayerPaint(@Nullable Paint paint) {
+        nSetLayerPaint(mFinalizer.get(), paint != null ? paint.getNativeInstance() : 0);
         mRenderer.pushLayerUpdate(this);
     }
 
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3688d50..707300f 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -49,7 +49,8 @@
 
     void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
             in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
-            in Configuration newConfig, in Rect backDropFrame, boolean forceLayout);
+            in Configuration newConfig, in Rect backDropFrame, boolean forceLayout,
+            boolean alwaysConsumeNavBar);
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
@@ -94,5 +95,5 @@
     /**
      * Called when Keyboard Shortcuts are requested for the window.
      */
-    void requestAppKeyboardShortcuts(IResultReceiver receiver);
+    void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5b9930b..4ba97d5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -20,6 +20,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
+import com.android.internal.policy.IShortcutService;
 
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -166,7 +167,7 @@
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
     void setAppVisibility(IBinder token, boolean visible);
-    void notifyAppStopped(IBinder token);
+    void notifyAppStopped(IBinder token, boolean stopped);
     void startAppFreezingScreen(IBinder token, int configChanges);
     void stopAppFreezingScreen(IBinder token, boolean force);
     void removeAppToken(IBinder token);
@@ -179,7 +180,12 @@
     // caller must call setNewConfiguration() sometime later.
     Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
             IBinder freezeThisOneIfNeeded);
-    void setNewConfiguration(in Configuration config);
+    // Notify window manager of the new configuration. Returns an array of stack ids that's
+    // affected by the update, ActivityManager should resize these stacks.
+    int[] setNewConfiguration(in Configuration config);
+
+    // Retrieves the new bounds after the configuration update evaluated by window manager.
+    Rect getBoundsForNewConfiguration(int stackId);
 
     void startFreezingScreen(int exitAnim, int enterAnim);
     void stopFreezingScreen();
@@ -192,8 +198,7 @@
     boolean isKeyguardSecure();
     boolean inKeyguardRestrictedInputMode();
     void dismissKeyguard();
-    void keyguardGoingAway(boolean disableWindowAnimations,
-            boolean keyguardGoingToNotificationShade);
+    void keyguardGoingAway(int flags);
 
     void closeSystemDialogs(String reason);
 
@@ -362,6 +367,12 @@
     void setDockedStackResizing(boolean resizing);
 
     /**
+     * Sets the region the user can touch the divider. This region will be excluded from the region
+     * which is used to cause a focus switch when dispatching touch.
+     */
+    void setDockedStackDividerTouchRegion(in Rect touchableRegion);
+
+    /**
      * Registers a listener that will be called when the dock divider changes its visibility or when
      * the docked stack gets added/removed.
      */
@@ -381,10 +392,27 @@
      *
      * @param receiver The receiver to deliver the results to.
      */
-    void requestAppKeyboardShortcuts(IResultReceiver receiver);
+    void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
 
     /**
      * Retrieves the current stable insets from the primary display.
      */
     void getStableInsets(out Rect outInsets);
+
+    /**
+     * Register shortcut key. Shortcut code is packed as:
+     * (MetaState << Integer.SIZE) | KeyCode
+     * @hide
+     */
+    void registerShortcutKey(in long shortcutCode, IShortcutService keySubscriber);
+
+    /**
+     * Create the input consumer for wallpaper events.
+     */
+    void createWallpaperInputConsumer(out InputChannel inputChannel);
+
+    /**
+     * Remove the input consumer for wallpaper events.
+     */
+    void removeWallpaperInputConsumer();
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 6a2cc80..8e1609c 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -112,10 +112,10 @@
      *
      *  @param window The window being modified. Must be attached to a parent window
      *  or this call will fail.
-     *  @param x The new x position
-     *  @param y The new y position
-     *  @param width The new width
-     *  @param height The new height
+     *  @param left The new left position
+     *  @param top The new top position
+     *  @param right The new right position
+     *  @param bottom The new bottom position
      *  @param deferTransactionUntilFrame Frame number from our parent (attached) to
      *  defer this action until.
      *  @param outFrame Rect in which is placed the new position/size on screen.
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 51e1f4b..e0c6770 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1780,6 +1780,7 @@
             case KeyEvent.KEYCODE_DPAD_CENTER:
             case KeyEvent.KEYCODE_ENTER:
             case KeyEvent.KEYCODE_SPACE:
+            case KeyEvent.KEYCODE_NUMPAD_ENTER:
                 return true;
             default:
                 return false;
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index 2c9006d..eee925d 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -30,31 +30,46 @@
     private final CharSequence mLabel;
     private final Icon mIcon;
     private final char mBaseCharacter;
+    private final int mKeycode;
     private final int mModifiers;
 
     /**
      * @param label The label that identifies the action performed by this shortcut.
      * @param icon An icon that identifies the action performed by this shortcut.
-     * @param baseCharacter The character that triggers the shortcut.
+     * @param keycode The keycode that triggers the shortcut. This should be a valid constant
+     *     defined in {@link KeyEvent}.
      * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
      *     These should be a combination of {@link KeyEvent#META_CTRL_ON},
-     *     {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and
-     *     {@link KeyEvent#META_ALT_ON}.
+     *     {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON},
+     *     {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_FUNCTION_ON} and
+     *     {@link KeyEvent#META_SYM_ON}.
      *
      * @hide
      */
     public KeyboardShortcutInfo(
-            @Nullable CharSequence label, @Nullable Icon icon, char baseCharacter, int modifiers) {
+            @Nullable CharSequence label, @Nullable Icon icon, int keycode, int modifiers) {
         mLabel = label;
         mIcon = icon;
-        checkArgument(baseCharacter != MIN_VALUE);
-        mBaseCharacter = baseCharacter;
+        mBaseCharacter = MIN_VALUE;
+        checkArgument(keycode >= KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
+        mKeycode = keycode;
         mModifiers = modifiers;
     }
 
     /**
-     * Convenience constructor for shortcuts with a label and no icon.
-     *
+     * @param label The label that identifies the action performed by this shortcut.
+     * @param keycode The keycode that triggers the shortcut. This should be a valid constant
+     *     defined in {@link KeyEvent}.
+     * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
+     *     These should be a combination of {@link KeyEvent#META_CTRL_ON},
+     *     {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and
+     *     {@link KeyEvent#META_ALT_ON}.
+     */
+    public KeyboardShortcutInfo(CharSequence label, int keycode, int modifiers) {
+        this(label, null, keycode, modifiers);
+    }
+
+    /**
      * @param label The label that identifies the action performed by this shortcut.
      * @param baseCharacter The character that triggers the shortcut.
      * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
@@ -66,14 +81,16 @@
         mLabel = label;
         checkArgument(baseCharacter != MIN_VALUE);
         mBaseCharacter = baseCharacter;
+        mKeycode = KeyEvent.KEYCODE_UNKNOWN;
         mModifiers = modifiers;
         mIcon = null;
     }
 
     private KeyboardShortcutInfo(Parcel source) {
         mLabel = source.readCharSequence();
-        mIcon = (Icon) source.readParcelable(null);
+        mIcon = source.readParcelable(null);
         mBaseCharacter = (char) source.readInt();
+        mKeycode = source.readInt();
         mModifiers = source.readInt();
     }
 
@@ -96,7 +113,16 @@
     }
 
     /**
-     * Returns the base character that, combined with the modifiers, triggers this shortcut.
+     * Returns the base keycode that, combined with the modifiers, triggers this shortcut. If the
+     * base character was set instead, returns {@link KeyEvent#KEYCODE_UNKNOWN}.
+     */
+    public int getKeycode() {
+        return mKeycode;
+    }
+
+    /**
+     * Returns the base character that, combined with the modifiers, triggers this shortcut. If the
+     * keycode was set instead, returns {@link Character#MIN_VALUE}.
      */
     public char getBaseCharacter() {
         return mBaseCharacter;
@@ -119,6 +145,7 @@
         dest.writeCharSequence(mLabel);
         dest.writeParcelable(mIcon, 0);
         dest.writeInt(mBaseCharacter);
+        dest.writeInt(mKeycode);
         dest.writeInt(mModifiers);
     }
 
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index b9a7421..cff9d8e 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -35,7 +35,6 @@
 public class NotificationHeaderView extends ViewGroup {
     public static final int NO_COLOR = -1;
     private final int mChildMinWidth;
-    private final int mExpandTopPadding;
     private final int mContentEndMargin;
     private View mAppName;
     private View mSubTextView;
@@ -43,12 +42,10 @@
     private HeaderTouchListener mTouchListener = new HeaderTouchListener();
     private ImageView mExpandButton;
     private View mIcon;
-    private TextView mChildCount;
     private View mProfileBadge;
     private View mInfo;
     private int mIconColor;
     private int mOriginalNotificationColor;
-    private boolean mGroupHeader;
     private boolean mExpanded;
     private boolean mShowWorkBadgeAtEnd;
 
@@ -70,7 +67,6 @@
                 com.android.internal.R.dimen.notification_header_shrink_min_width);
         mContentEndMargin = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_end);
-        mExpandTopPadding = (int) (1 * getResources().getDisplayMetrics().density);
     }
 
     @Override
@@ -80,7 +76,6 @@
         mSubTextView = findViewById(com.android.internal.R.id.header_sub_text);
         mExpandButton = (ImageView) findViewById(com.android.internal.R.id.expand_button);
         mIcon = findViewById(com.android.internal.R.id.icon);
-        mChildCount = (TextView) findViewById(com.android.internal.R.id.number_of_children);
         mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
         mInfo = findViewById(com.android.internal.R.id.header_content_info);
     }
@@ -193,17 +188,6 @@
         updateTouchListener();
     }
 
-    public void setChildCount(int childCount) {
-        if (childCount > 0) {
-            mChildCount.setText(getContext().getString(
-                    com.android.internal.R.string.notification_children_count_bracketed,
-                    childCount));
-            mChildCount.setVisibility(VISIBLE);
-        } else {
-            mChildCount.setVisibility(GONE);
-        }
-    }
-
     @RemotableViewMethod
     public void setOriginalIconColor(int color) {
         mIconColor = color;
@@ -222,11 +206,6 @@
         return mOriginalNotificationColor;
     }
 
-    public void setIsGroupHeader(boolean isGroupHeader) {
-        mGroupHeader = isGroupHeader;
-        updateExpandButton();
-    }
-
     @RemotableViewMethod
     public void setExpanded(boolean expanded) {
         mExpanded = expanded;
@@ -235,24 +214,13 @@
 
     private void updateExpandButton() {
         int drawableId;
-        int paddingTop = 0;
-        if (mGroupHeader) {
-            if (mExpanded) {
-                drawableId = com.android.internal.R.drawable.ic_collapse_bundle;
-            } else {
-                drawableId =com.android.internal.R.drawable.ic_expand_bundle;
-            }
+        if (mExpanded) {
+            drawableId = com.android.internal.R.drawable.ic_collapse_notification;
         } else {
-            if (mExpanded) {
-                drawableId = com.android.internal.R.drawable.ic_collapse_notification;
-            } else {
-                drawableId = com.android.internal.R.drawable.ic_expand_notification;
-            }
-            paddingTop = mExpandTopPadding;
+            drawableId = com.android.internal.R.drawable.ic_expand_notification;
         }
         mExpandButton.setImageDrawable(getContext().getDrawable(drawableId));
         mExpandButton.setColorFilter(mOriginalNotificationColor);
-        mExpandButton.setPadding(0, paddingTop, 0, 0);
     }
 
     public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a4cb703..ab4cbcf 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -259,7 +259,7 @@
         return nSetLayerType(mNativeRenderNode, layerType);
     }
 
-    public boolean setLayerPaint(Paint paint) {
+    public boolean setLayerPaint(@Nullable Paint paint) {
         return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
     }
 
@@ -307,18 +307,22 @@
      *
      * Deep copies the data into native to simplify reference ownership.
      */
-    public boolean setOutline(Outline outline) {
+    public boolean setOutline(@Nullable Outline outline) {
         if (outline == null) {
             return nSetOutlineNone(mNativeRenderNode);
-        } else if (outline.isEmpty()) {
-            return nSetOutlineEmpty(mNativeRenderNode);
-        } else if (outline.mRect != null) {
-            return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
-                    outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
-        } else if (outline.mPath != null) {
-            return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
-                    outline.mAlpha);
         }
+
+        switch(outline.mMode) {
+            case Outline.MODE_EMPTY:
+                return nSetOutlineEmpty(mNativeRenderNode);
+            case Outline.MODE_ROUND_RECT:
+                return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
+                        outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
+            case Outline.MODE_CONVEX_PATH:
+                return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
+                        outline.mAlpha);
+        }
+
         throw new IllegalArgumentException("Unrecognized outline?");
     }
 
@@ -763,6 +767,16 @@
         return nGetDebugSize(mNativeRenderNode);
     }
 
+    /**
+     * Called by native when the passed displaylist is removed from the draw tree
+     */
+    void onRenderNodeDetached() {
+        discardDisplayList();
+        if (mOwningView != null) {
+            mOwningView.onRenderNodeDetached(this);
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Animations
     ///////////////////////////////////////////////////////////////////////////
@@ -779,7 +793,7 @@
         return mOwningView != null && mOwningView.mAttachInfo != null;
     }
 
-    public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimator animatorSet) {
+    public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
         if (mOwningView == null || mOwningView.mAttachInfo == null) {
             throw new IllegalStateException("Cannot start this animator on a detached view!");
         }
@@ -795,7 +809,9 @@
     // Native methods
     ///////////////////////////////////////////////////////////////////////////
 
-    private static native long nCreate(String name);
+    // Intentionally not static because it acquires a reference to 'this'
+    private native long nCreate(String name);
+
     private static native void nDestroyRenderNode(long renderNode);
     private static native void nSetDisplayList(long renderNode, long newData);
 
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 37e4000..7cd161c 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -145,13 +145,6 @@
     private int mSpanSlop;
     private int mMinSpan;
 
-    // Bounds for recently seen values
-    private float mTouchUpper;
-    private float mTouchLower;
-    private float mTouchHistoryLastAccepted;
-    private int mTouchHistoryDirection;
-    private long mTouchHistoryLastAcceptedTime;
-    private int mTouchMinMajor;
     private final Handler mHandler;
 
     private float mAnchoredScaleStartX;
@@ -207,8 +200,6 @@
         mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
 
         final Resources res = context.getResources();
-        mTouchMinMajor = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_minScalingTouchMajor);
         mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
         mHandler = handler;
         // Quick scale is enabled by default after JB_MR2
@@ -223,77 +214,6 @@
     }
 
     /**
-     * The touchMajor/touchMinor elements of a MotionEvent can flutter/jitter on
-     * some hardware/driver combos. Smooth it out to get kinder, gentler behavior.
-     * @param ev MotionEvent to add to the ongoing history
-     */
-    private void addTouchHistory(MotionEvent ev) {
-        final long currentTime = SystemClock.uptimeMillis();
-        final int count = ev.getPointerCount();
-        boolean accept = currentTime - mTouchHistoryLastAcceptedTime >= TOUCH_STABILIZE_TIME;
-        float total = 0;
-        int sampleCount = 0;
-        for (int i = 0; i < count; i++) {
-            final boolean hasLastAccepted = !Float.isNaN(mTouchHistoryLastAccepted);
-            final int historySize = ev.getHistorySize();
-            final int pointerSampleCount = historySize + 1;
-            for (int h = 0; h < pointerSampleCount; h++) {
-                float major;
-                if (h < historySize) {
-                    major = ev.getHistoricalTouchMajor(i, h);
-                } else {
-                    major = ev.getTouchMajor(i);
-                }
-                if (major < mTouchMinMajor) major = mTouchMinMajor;
-                total += major;
-
-                if (Float.isNaN(mTouchUpper) || major > mTouchUpper) {
-                    mTouchUpper = major;
-                }
-                if (Float.isNaN(mTouchLower) || major < mTouchLower) {
-                    mTouchLower = major;
-                }
-
-                if (hasLastAccepted) {
-                    final int directionSig = (int) Math.signum(major - mTouchHistoryLastAccepted);
-                    if (directionSig != mTouchHistoryDirection ||
-                            (directionSig == 0 && mTouchHistoryDirection == 0)) {
-                        mTouchHistoryDirection = directionSig;
-                        final long time = h < historySize ? ev.getHistoricalEventTime(h)
-                                : ev.getEventTime();
-                        mTouchHistoryLastAcceptedTime = time;
-                        accept = false;
-                    }
-                }
-            }
-            sampleCount += pointerSampleCount;
-        }
-
-        final float avg = total / sampleCount;
-
-        if (accept) {
-            float newAccepted = (mTouchUpper + mTouchLower + avg) / 3;
-            mTouchUpper = (mTouchUpper + newAccepted) / 2;
-            mTouchLower = (mTouchLower + newAccepted) / 2;
-            mTouchHistoryLastAccepted = newAccepted;
-            mTouchHistoryDirection = 0;
-            mTouchHistoryLastAcceptedTime = ev.getEventTime();
-        }
-    }
-
-    /**
-     * Clear all touch history tracking. Useful in ACTION_CANCEL or ACTION_UP.
-     * @see #addTouchHistory(MotionEvent)
-     */
-    private void clearTouchHistory() {
-        mTouchUpper = Float.NaN;
-        mTouchLower = Float.NaN;
-        mTouchHistoryLastAccepted = Float.NaN;
-        mTouchHistoryDirection = 0;
-        mTouchHistoryLastAcceptedTime = 0;
-    }
-
-    /**
      * Accepts MotionEvents and dispatches events to a {@link OnScaleGestureListener}
      * when appropriate.
      *
@@ -344,7 +264,6 @@
             }
 
             if (streamComplete) {
-                clearTouchHistory();
                 return true;
             }
         }
@@ -391,17 +310,14 @@
             focusY = sumY / div;
         }
 
-        addTouchHistory(event);
-
         // Determine average deviation from focal point
         float devSumX = 0, devSumY = 0;
         for (int i = 0; i < count; i++) {
             if (skipIndex == i) continue;
 
             // Convert the resulting diameter into a radius.
-            final float touchSize = mTouchHistoryLastAccepted / 2;
-            devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
-            devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
+            devSumX += Math.abs(event.getX(i) - focusX);
+            devSumY += Math.abs(event.getY(i) - focusY);
         }
         final float devX = devSumX / div;
         final float devY = devSumY / div;
diff --git a/core/java/android/view/Surface.aidl b/core/java/android/view/Surface.aidl
deleted file mode 100644
index 90bf37a..0000000
--- a/core/java/android/view/Surface.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* //device/java/android/android/view/Surface.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 android.view;
-
-parcelable Surface;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b58c68f..c30ede3 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -36,6 +36,7 @@
             throws OutOfResourcesException;
     private static native void nativeRelease(long nativeObject);
     private static native void nativeDestroy(long nativeObject);
+    private static native void nativeDisconnect(long nativeObject);
 
     private static native Bitmap nativeScreenshot(IBinder displayToken,
             Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
@@ -56,6 +57,7 @@
     private static native void nativeSetMatrix(long nativeObject, float dsdx, float dtdx, float dsdy, float dtdy);
     private static native void nativeSetFlags(long nativeObject, int flags, int mask);
     private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
+    private static native void nativeSetFinalCrop(long nativeObject, int l, int t, int r, int b);
     private static native void nativeSetLayerStack(long nativeObject, int layerStack);
 
     private static native boolean nativeClearContentFrameStats(long nativeObject);
@@ -341,6 +343,15 @@
         mCloseGuard.close();
     }
 
+    /**
+     * Disconnect any client still connected to the surface.
+     */
+    public void disconnect() {
+        if (mNativeObject != 0) {
+            nativeDisconnect(mNativeObject);
+        }
+    }
+
     private void checkNotReleased() {
         if (mNativeObject == 0) throw new NullPointerException(
                 "mNativeObject is null. Have you called release() already?");
@@ -446,6 +457,16 @@
         }
     }
 
+    public void setFinalCrop(Rect crop) {
+        checkNotReleased();
+        if (crop != null) {
+            nativeSetFinalCrop(mNativeObject,
+                crop.left, crop.top, crop.right, crop.bottom);
+        } else {
+            nativeSetFinalCrop(mNativeObject, 0, 0, 0, 0);
+        }
+    }
+
     public void setLayerStack(int layerStack) {
         checkNotReleased();
         nativeSetLayerStack(mNativeObject, layerStack);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 152dd66..8a8fb43 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -490,7 +490,7 @@
                               | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                               | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                               ;
-                if (!creating && !force && !mUpdateWindowNeeded) {
+                if (!creating && !force && !mUpdateWindowNeeded && !sizeChanged) {
                     mLayout.privateFlags |=
                             WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
                 } else {
@@ -584,18 +584,6 @@
 
                     mSurface.transferFrom(mNewSurface);
                     if (visible && mSurface.isValid()) {
-                        // We set SCALING_MODE_NO_SCALE_CROP to allow the WindowManager
-                        // to update our Surface crop without requiring a new buffer from
-                        // us. In the default mode of SCALING_MODE_FREEZE, surface geometry
-                        // state (which includes crop) is only applied when a buffer
-                        // with appropriate geometry is available. During drag resize
-                        // it is quite frequent that a matching buffer will not be available
-                        // (because we are constantly being resized and have fallen behind).
-                        // However in such situations the WindowManager still needs to be able
-                        // to update our crop to ensure we stay within the bounds of the containing
-                        // window.
-                        mSurface.setScalingMode(Surface.SCALING_MODE_NO_SCALE_CROP);
-
                         if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
                             mSurfaceCreated = true;
                             mIsCreating = true;
@@ -665,7 +653,8 @@
                             "postion = [%d, %d, %d, %d]", mWindowSpaceLeft, mWindowSpaceTop,
                             mLocation[0], mLocation[1]));
                     mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop,
-                            mLocation[0], mLocation[1], -1, mWinFrame);
+                            mLocation[0], mLocation[1],
+                            -1, mWinFrame);
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Exception from relayout", ex);
                 }
@@ -700,7 +689,8 @@
                         right, bottom));
             }
             // Just using mRTLastReportedPosition as a dummy rect here
-            session.repositionChild(window, left, top, right, bottom, frameNumber,
+            session.repositionChild(window, left, top, right, bottom,
+                    frameNumber,
                     mRTLastReportedPosition);
             // Now overwrite mRTLastReportedPosition with our values
             mRTLastReportedPosition.set(left, top, right, bottom);
@@ -743,7 +733,8 @@
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                Configuration newConfig, Rect backDropRect, boolean forceLayout) {
+                Configuration newConfig, Rect backDropRect, boolean forceLayout,
+                boolean alwaysConsumeNavBar) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
                 if (DEBUG) Log.v(
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 1be4810..1a712c3 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -133,7 +134,6 @@
      */
     public TextureView(Context context) {
         super(context);
-        init();
     }
 
     /**
@@ -144,7 +144,6 @@
      */
     public TextureView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        init();
     }
 
     /**
@@ -158,7 +157,6 @@
      */
     public TextureView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        init();
     }
 
     /**
@@ -176,11 +174,6 @@
      */
     public TextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        init();
-    }
-
-    private void init() {
-        mLayerPaint = new Paint();
     }
 
     /**
@@ -260,7 +253,7 @@
      * method will however be taken into account when rendering the content of
      * this TextureView.
      *
-     * @param layerType The ype of layer to use with this view, must be one of
+     * @param layerType The type of layer to use with this view, must be one of
      *        {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
      *        {@link #LAYER_TYPE_HARDWARE}
      * @param paint The paint used to compose the layer. This argument is optional
@@ -268,16 +261,16 @@
      *        {@link #LAYER_TYPE_NONE}
      */
     @Override
-    public void setLayerType(int layerType, Paint paint) {
-        if (paint != mLayerPaint) {
-            mLayerPaint = paint == null ? new Paint() : paint;
-            invalidate();
-        }
+    public void setLayerType(int layerType, @Nullable Paint paint) {
+        setLayerPaint(paint);
     }
 
     @Override
-    public void setLayerPaint(Paint paint) {
-        setLayerType(/* ignored */ 0, paint);
+    public void setLayerPaint(@Nullable Paint paint) {
+        if (paint != mLayerPaint) {
+            mLayerPaint = paint;
+            invalidate();
+        }
     }
 
     /**
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c972476..df774b4 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -794,7 +794,8 @@
         }
 
         final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
-        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
+        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length,
+                mRootNode.mNativeRenderNode);
         if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
             setEnabled(false);
             attachInfo.mViewRootImpl.mSurface.release();
@@ -993,7 +994,8 @@
     private static native void nSetLightCenter(long nativeProxy,
             float lightX, float lightY, float lightZ);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
-    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
+    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size,
+            long rootRenderNode);
     private static native void nDestroy(long nativeProxy, long rootRenderNode);
     private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 70a0e01..b95d830 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -84,7 +84,6 @@
 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator;
 import android.view.AccessibilityIterators.TextSegmentIterator;
 import android.view.AccessibilityIterators.WordTextSegmentIterator;
-import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
@@ -2430,7 +2429,12 @@
      *                     1             PFLAG3_SCROLL_INDICATOR_START
      *                    1              PFLAG3_SCROLL_INDICATOR_END
      *                   1               PFLAG3_ASSIST_BLOCKED
-     *            1111111                PFLAG3_POINTER_ICON_MASK
+     *                  1                PFLAG3_POINTER_ICON_NULL
+     *                 1                 PFLAG3_POINTER_ICON_VALUE_START
+     *           11111111                PFLAG3_POINTER_ICON_MASK
+     *          1                        PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
+     *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
+     *        1                          PFLAG3_TEMPORARY_DETACH
      * |-------|-------|-------|-------|
      */
 
@@ -2519,8 +2523,6 @@
      */
     static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
 
-    /* End of masks for mPrivateFlags3 */
-
     static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
 
     static final int SCROLL_INDICATORS_NONE = 0x0000;
@@ -2652,6 +2654,31 @@
     private static final int PFLAG3_POINTER_ICON_VALUE_START = 2 << PFLAG3_POINTER_ICON_LSHIFT;
 
     /**
+     * Whether this view has rendered elements that overlap (see {@link
+     * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and
+     * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when
+     * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is
+     * determined by whatever {@link #hasOverlappingRendering()} returns.
+     */
+    private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000;
+
+    /**
+     * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value
+     * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid.
+     */
+    private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000;
+
+    /**
+     * Flag indicating that the view is temporarily detached from the parent view.
+     *
+     * @see #onStartTemporaryDetach()
+     * @see #onFinishTemporaryDetach()
+     */
+    static final int PFLAG3_TEMPORARY_DETACH = 0x2000000;
+
+    /* End of masks for mPrivateFlags3 */
+
+    /**
      * Always allow a user to over-scroll this view, provided it is a
      * view that can scroll.
      *
@@ -3872,6 +3899,7 @@
      * cleanup.
      */
     final RenderNode mRenderNode;
+    private Runnable mRenderNodeDetachedCallback;
 
     /**
      * Set to true when the view is sending hover accessibility events because it
@@ -4517,6 +4545,12 @@
                         }
                     }
                     break;
+                case R.styleable.View_forceHasOverlappingRendering:
+                    if (a.peekValue(attr) != null) {
+                        forceHasOverlappingRendering(a.getBoolean(attr, true));
+                    }
+                    break;
+
             }
         }
 
@@ -5021,8 +5055,8 @@
 
         if (scrollabilityCache.scrollBar == null) {
             scrollabilityCache.scrollBar = new ScrollBarDrawable();
-            scrollabilityCache.scrollBar.setCallback(this);
             scrollabilityCache.scrollBar.setState(getDrawableState());
+            scrollabilityCache.scrollBar.setCallback(this);
         }
 
         final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true);
@@ -9711,9 +9745,20 @@
     }
 
     /**
-     * @hide
+     * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()}
+     * and {@link #onFinishTemporaryDetach()}.
      */
+    public final boolean isTemporarilyDetached() {
+        return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0;
+    }
+
+    /**
+     * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is
+     * a container View.
+     */
+    @CallSuper
     public void dispatchStartTemporaryDetach() {
+        mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH;
         onStartTemporaryDetach();
     }
 
@@ -9729,10 +9774,13 @@
     }
 
     /**
-     * @hide
+     * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is
+     * a container View.
      */
+    @CallSuper
     public void dispatchFinishTemporaryDetach() {
         onFinishTemporaryDetach();
+        mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
     }
 
     /**
@@ -10151,19 +10199,6 @@
      *                   {@link #INVISIBLE} or {@link #GONE}.
      */
     protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {
-        final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;
-        if (visible && mAttachInfo != null) {
-            initialAwakenScrollBars();
-        }
-
-        final Drawable dr = mBackground;
-        if (dr != null && visible != dr.isVisible()) {
-            dr.setVisible(visible, false);
-        }
-        final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
-        if (fg != null && visible != fg.isVisible()) {
-            fg.setVisible(visible, false);
-        }
     }
 
     /**
@@ -10220,6 +10255,46 @@
     }
 
     /**
+     * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by
+     * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()},
+     * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}.
+     *
+     * @param isVisible true if this view's visibility to the user is uninterrupted by its
+     *                  ancestors or by window visibility
+     * @return true if this view is visible to the user, not counting clipping or overlapping
+     */
+    @Visibility boolean dispatchVisibilityAggregated(boolean isVisible) {
+        final boolean thisVisible = getVisibility() == VISIBLE;
+        if (thisVisible) {
+            onVisibilityAggregated(isVisible);
+        }
+        return thisVisible && isVisible;
+    }
+
+    /**
+     * Called when the user-visibility of this View is potentially affected by a change
+     * to this view itself, an ancestor view or the window this view is attached to.
+     *
+     * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE}
+     *                  and this view's window is also visible
+     */
+    @CallSuper
+    public void onVisibilityAggregated(boolean isVisible) {
+        if (isVisible && mAttachInfo != null) {
+            initialAwakenScrollBars();
+        }
+
+        final Drawable dr = mBackground;
+        if (dr != null && isVisible != dr.isVisible()) {
+            dr.setVisible(isVisible, false);
+        }
+        final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
+        if (fg != null && isVisible != fg.isVisible()) {
+            fg.setVisible(isVisible, false);
+        }
+    }
+
+    /**
      * Returns the current visibility of the window this view is attached to
      * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}).
      *
@@ -10270,6 +10345,27 @@
     }
 
     /**
+     * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window
+     * is currently in without any insets.
+     *
+     * @hide
+     */
+    public void getWindowDisplayFrame(Rect outRect) {
+        if (mAttachInfo != null) {
+            try {
+                mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
+            } catch (RemoteException e) {
+                return;
+            }
+            return;
+        }
+        // The view is not attached to a display so we don't have a context.
+        // Make a best guess about the display size.
+        Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+        d.getRectSize(outRect);
+    }
+
+    /**
      * Dispatch a notification about a resource configuration change down
      * the view hierarchy.
      * ViewGroups should override to route to their children.
@@ -11315,6 +11411,16 @@
 
             if (mAttachInfo != null) {
                 dispatchVisibilityChanged(this, newVisibility);
+
+                // Aggregated visibility changes are dispatched to attached views
+                // in visible windows where the parent is currently shown/drawn
+                // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot),
+                // discounting clipping or overlapping. This makes it a good place
+                // to change animation states.
+                if (mParent != null && getWindowVisibility() == VISIBLE &&
+                        ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) {
+                    dispatchVisibilityAggregated(newVisibility == VISIBLE);
+                }
                 notifySubtreeAccessibilityStateChangedIfNeeded();
             }
         }
@@ -11684,7 +11790,7 @@
         }
     }
 
-   /**
+    /**
      * Utility method to retrieve the inverse of the current mMatrix property.
      * We cache the matrix to avoid recalculating it when transform properties
      * have not changed.
@@ -12059,6 +12165,42 @@
     }
 
     /**
+     * Sets the behavior for overlapping rendering for this view (see {@link
+     * #hasOverlappingRendering()} for more details on this behavior). Calling this method
+     * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass,
+     * providing the value which is then used internally. That is, when {@link
+     * #forceHasOverlappingRendering(boolean)} is called, the value of {@link
+     * #hasOverlappingRendering()} is ignored and the value passed into this method is used
+     * instead.
+     *
+     * @param hasOverlappingRendering The value for overlapping rendering to be used internally
+     * instead of that returned by {@link #hasOverlappingRendering()}.
+     *
+     * @attr ref android.R.styleable#View_forceHasOverlappingRendering
+     */
+    public void forceHasOverlappingRendering(boolean hasOverlappingRendering) {
+        mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED;
+        if (hasOverlappingRendering) {
+            mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE;
+        } else {
+            mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE;
+        }
+    }
+
+    /**
+     * Returns the value for overlapping rendering that is used internally. This is either
+     * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or
+     * the return value of {@link #hasOverlappingRendering()}, otherwise.
+     *
+     * @return The value for overlapping rendering being used internally.
+     */
+    public final boolean getHasOverlappingRendering() {
+        return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ?
+                (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 :
+                hasOverlappingRendering();
+    }
+
+    /**
      * Returns whether this View has content which overlaps.
      *
      * <p>This function, intended to be overridden by specific View types, is an optimization when
@@ -12074,6 +12216,9 @@
      * necessitates that a View return true if it uses the methods internally without passing the
      * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p>
      *
+     * <p><strong>Note:</strong> The return value of this method is ignored if {@link
+     * #forceHasOverlappingRendering(boolean)} has been called on this view.</p>
+     *
      * @return true if the content in this view might overlap, false otherwise.
      */
     @ViewDebug.ExportedProperty(category = "drawing")
@@ -13238,8 +13383,8 @@
 
         if (scrollCache.scrollBar == null) {
             scrollCache.scrollBar = new ScrollBarDrawable();
-            scrollCache.scrollBar.setCallback(this);
             scrollCache.scrollBar.setState(getDrawableState());
+            scrollCache.scrollBar.setCallback(this);
         }
 
         if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) {
@@ -15066,6 +15211,7 @@
     protected void onDetachedFromWindowInternal() {
         mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
         mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
+        mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
 
         removeUnsetPressCallback();
         removeLongPressCallback();
@@ -15225,6 +15371,11 @@
         int vis = info.mWindowVisibility;
         if (vis != GONE) {
             onWindowVisibilityChanged(vis);
+            if (isShown()) {
+                // Calling onVisibilityChanged directly here since the subtree will also
+                // receive dispatchAttachedToWindow and this same call
+                onVisibilityAggregated(vis == VISIBLE);
+            }
         }
 
         // Send onVisibilityChanged directly instead of dispatchVisibilityChanged.
@@ -15245,6 +15396,11 @@
             int vis = info.mWindowVisibility;
             if (vis != GONE) {
                 onWindowVisibilityChanged(GONE);
+                if (isShown()) {
+                    // Invoking onVisibilityAggregated directly here since the subtree
+                    // will also receive detached from window
+                    onVisibilityAggregated(false);
+                }
             }
         }
 
@@ -15559,7 +15715,7 @@
      *
      * @attr ref android.R.styleable#View_layerType
      */
-    public void setLayerType(int layerType, Paint paint) {
+    public void setLayerType(int layerType, @Nullable Paint paint) {
         if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
             throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
                     + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
@@ -15578,8 +15734,7 @@
         }
 
         mLayerType = layerType;
-        final boolean layerDisabled = (mLayerType == LAYER_TYPE_NONE);
-        mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
+        mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint;
         mRenderNode.setLayerPaint(mLayerPaint);
 
         // draw() behaves differently if we are on a layer, so we need to
@@ -15613,12 +15768,12 @@
      *
      * @see #setLayerType(int, android.graphics.Paint)
      */
-    public void setLayerPaint(Paint paint) {
+    public void setLayerPaint(@Nullable Paint paint) {
         int layerType = getLayerType();
         if (layerType != LAYER_TYPE_NONE) {
-            mLayerPaint = paint == null ? new Paint() : paint;
+            mLayerPaint = paint;
             if (layerType == LAYER_TYPE_HARDWARE) {
-                if (mRenderNode.setLayerPaint(mLayerPaint)) {
+                if (mRenderNode.setLayerPaint(paint)) {
                     invalidateViewProperty(false, false);
                 }
             } else {
@@ -15879,6 +16034,27 @@
     }
 
     /**
+     * Called when the passed RenderNode is removed from the draw tree
+     * @hide
+     */
+    public void onRenderNodeDetached(RenderNode renderNode) {
+        if (renderNode == mRenderNode && mRenderNodeDetachedCallback != null) {
+            mRenderNodeDetachedCallback.run();
+        }
+    }
+
+    /**
+     * Set callback for functor detach. Exposed to WebView through WebViewDelegate.
+     * Should not be used otherwise.
+     * @hide
+     */
+    public final Runnable setRenderNodeDetachedCallback(@Nullable Runnable callback) {
+        Runnable oldCallback = mRenderNodeDetachedCallback;
+        mRenderNodeDetachedCallback = callback;
+        return oldCallback;
+    }
+
+    /**
      * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
      *
      * @return A non-scaled bitmap representing this view or null if cache is disabled.
@@ -16169,8 +16345,10 @@
     /**
      * Create a snapshot of the view into a bitmap.  We should probably make
      * some form of this public, but should think about the API.
+     *
+     * @hide
      */
-    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
+    public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
         int width = mRight - mLeft;
         int height = mBottom - mTop;
 
@@ -16500,7 +16678,7 @@
      */
     void setDisplayListProperties(RenderNode renderNode) {
         if (renderNode != null) {
-            renderNode.setHasOverlappingRendering(hasOverlappingRendering());
+            renderNode.setHasOverlappingRendering(getHasOverlappingRendering());
             renderNode.setClipToBounds(mParent instanceof ViewGroup
                     && ((ViewGroup) mParent).getClipChildren());
 
@@ -16776,7 +16954,7 @@
             }
         } else if (cache != null) {
             mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-            if (layerType == LAYER_TYPE_NONE) {
+            if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) {
                 // no layer paint, use temporary paint to draw bitmap
                 Paint cachePaint = parent.mCachePaint;
                 if (cachePaint == null) {
@@ -16789,9 +16967,13 @@
             } else {
                 // use layer paint to draw the bitmap, merging the two alphas, but also restore
                 int layerPaintAlpha = mLayerPaint.getAlpha();
-                mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
+                if (alpha < 1) {
+                    mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
+                }
                 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);
-                mLayerPaint.setAlpha(layerPaintAlpha);
+                if (alpha < 1) {
+                    mLayerPaint.setAlpha(layerPaintAlpha);
+                }
             }
         }
 
@@ -17484,7 +17666,7 @@
      *        {@link SystemClock#uptimeMillis} timebase.
      */
     @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+    public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
         if (verifyDrawable(who) && what != null) {
             final long delay = when - SystemClock.uptimeMillis();
             if (mAttachInfo != null) {
@@ -17506,7 +17688,7 @@
      * @param what the action to cancel
      */
     @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
+    public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
         if (verifyDrawable(who) && what != null) {
             if (mAttachInfo != null) {
                 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
@@ -17616,7 +17798,7 @@
      * @see #drawableStateChanged()
      */
     @CallSuper
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         // Avoid verifying the scroll bar drawable so that we don't end up in
         // an invalidation loop. This effectively prevents the scroll bar
         // drawable from triggering invalidations and scheduling runnables.
@@ -17932,9 +18114,12 @@
 
         /*
          * Regardless of whether we're setting a new background or not, we want
-         * to clear the previous drawable.
+         * to clear the previous drawable. setVisible first while we still have the callback set.
          */
         if (mBackground != null) {
+            if (isAttachedToWindow()) {
+                mBackground.setVisible(false, false);
+            }
             mBackground.setCallback(null);
             unscheduleDrawable(mBackground);
         }
@@ -17973,15 +18158,24 @@
                 requestLayout = true;
             }
 
-            background.setCallback(this);
+            // Set mBackground before we set this as the callback and start making other
+            // background drawable state change calls. In particular, the setVisible call below
+            // can result in drawables attempting to start animations or otherwise invalidate,
+            // which requires the view set as the callback (us) to recognize the drawable as
+            // belonging to it as per verifyDrawable.
+            mBackground = background;
             if (background.isStateful()) {
                 background.setState(getDrawableState());
             }
-            background.setVisible(getVisibility() == VISIBLE, false);
-            mBackground = background;
+            if (isAttachedToWindow()) {
+                background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
+            }
 
             applyBackgroundTint();
 
+            // Set callback last, since the view may still be initializing.
+            background.setCallback(this);
+
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
                 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
                 requestLayout = true;
@@ -18014,6 +18208,7 @@
 
         mBackgroundSizeChanged = true;
         invalidate(true);
+        invalidateOutline();
     }
 
     /**
@@ -18157,6 +18352,9 @@
         }
 
         if (mForegroundInfo.mDrawable != null) {
+            if (isAttachedToWindow()) {
+                mForegroundInfo.mDrawable.setVisible(false, false);
+            }
             mForegroundInfo.mDrawable.setCallback(null);
             unscheduleDrawable(mForegroundInfo.mDrawable);
         }
@@ -18167,12 +18365,16 @@
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
                 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
             }
-            foreground.setCallback(this);
             foreground.setLayoutDirection(getLayoutDirection());
             if (foreground.isStateful()) {
                 foreground.setState(getDrawableState());
             }
             applyForegroundTint();
+            if (isAttachedToWindow()) {
+                foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
+            }
+            // Set callback last, since the view may still be initializing.
+            foreground.setCallback(this);
         } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) {
             mPrivateFlags |= PFLAG_SKIP_DRAW;
         }
@@ -18916,7 +19118,8 @@
         transformFromViewToWindowSpace(outLocation);
     }
 
-    void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) {
+    /** @hide */
+    public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) {
         if (inOutLocation == null || inOutLocation.length < 2) {
             throw new IllegalArgumentException("inOutLocation must be an array of two integers");
         }
@@ -22087,7 +22290,7 @@
     /**
      * @hide
      */
-    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data) {
+    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) {
         // Do nothing.
     }
 
@@ -22517,6 +22720,13 @@
         final Rect mOutsets = new Rect();
 
         /**
+         * In multi-window we force show the navigation bar. Because we don't want that the surface
+         * size changes in this mode, we instead have a flag whether the navigation bar size should
+         * always be consumed, so the app is treated like there is no virtual navigation bar at all.
+         */
+        boolean mAlwaysConsumeNavBar;
+
+        /**
          * The internal insets given by this window.  This value is
          * supplied by the client (through
          * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c54ce80..3f7bbdf 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1291,6 +1291,22 @@
     }
 
     @Override
+    boolean dispatchVisibilityAggregated(boolean isVisible) {
+        isVisible = super.dispatchVisibilityAggregated(isVisible);
+        final int count = mChildrenCount;
+        final View[] children = mChildren;
+        for (int i = 0; i < count; i++) {
+            // Only dispatch to visible children. Not visible children and their subtrees already
+            // know that they aren't visible and that's not going to change as a result of
+            // whatever triggered this dispatch.
+            if (children[i].getVisibility() == VISIBLE) {
+                children[i].dispatchVisibilityAggregated(isVisible);
+            }
+        }
+        return isVisible;
+    }
+
+    @Override
     public void dispatchConfigurationChanged(Configuration newConfig) {
         super.dispatchConfigurationChanged(newConfig);
         final int count = mChildrenCount;
@@ -1382,6 +1398,13 @@
             if (mIsInterestedInDrag) {
                 retval = true;
             }
+
+            if (!retval) {
+                // Neither us nor any of our children are interested in this drag, so stop tracking
+                // the current drag event.
+                mCurrentDragStartEvent.recycle();
+                mCurrentDragStartEvent = null;
+            }
         } break;
 
         case DragEvent.ACTION_DRAG_ENDED: {
@@ -3228,8 +3251,11 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
-    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
+    public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
         int count = mChildrenCount;
         int[] visibilities = null;
 
@@ -3239,7 +3265,8 @@
                 View child = getChildAt(i);
                 visibilities[i] = child.getVisibility();
                 if (visibilities[i] == View.VISIBLE) {
-                    child.setVisibility(INVISIBLE);
+                    child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
+                            | (View.INVISIBLE & View.VISIBILITY_MASK);
                 }
             }
         }
@@ -3248,7 +3275,9 @@
 
         if (skipChildren) {
             for (int i = 0; i < count; i++) {
-                getChildAt(i).setVisibility(visibilities[i]);
+                View child = getChildAt(i);
+                child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
+                        | (visibilities[i] & View.VISIBILITY_MASK);
             }
         }
 
@@ -4971,6 +5000,8 @@
         if (child.hasFocus()) {
             requestChildFocus(child, child.findFocus());
         }
+        dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
+                && isShown());
     }
 
     /**
@@ -5357,9 +5388,6 @@
     void offsetRectBetweenParentAndChild(View descendant, Rect rect,
             boolean offsetFromChildToParent, boolean clipToBounds) {
 
-        final RectF rectF = mAttachInfo != null ? mAttachInfo.mTmpTransformRect1 : new RectF();
-        final Matrix inverse = mAttachInfo != null ? mAttachInfo.mTmpMatrix : new Matrix();
-
         // already in the same coord system :)
         if (descendant == this) {
             return;
@@ -5373,16 +5401,8 @@
                 && (theParent != this)) {
 
             if (offsetFromChildToParent) {
-                rect.offset(-descendant.mScrollX, -descendant.mScrollY);
-
-                if (!descendant.hasIdentityMatrix()) {
-                    rectF.set(rect);
-                    descendant.getMatrix().mapRect(rectF);
-                    rectF.roundOut(rect);
-                }
-
-                rect.offset(descendant.mLeft, descendant.mTop);
-
+                rect.offset(descendant.mLeft - descendant.mScrollX,
+                        descendant.mTop - descendant.mScrollY);
                 if (clipToBounds) {
                     View p = (View) theParent;
                     boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
@@ -5400,16 +5420,8 @@
                         rect.setEmpty();
                     }
                 }
-                rect.offset(-descendant.mLeft, -descendant.mTop);
-
-                if (!descendant.hasIdentityMatrix()) {
-                    descendant.getMatrix().invert(inverse);
-                    rectF.set(rect);
-                    inverse.mapRect(rectF);
-                    rectF.roundOut(rect);
-                }
-
-                rect.offset(descendant.mScrollX, descendant.mScrollY);
+                rect.offset(descendant.mScrollX - descendant.mLeft,
+                        descendant.mScrollY - descendant.mTop);
             }
 
             descendant = (View) theParent;
@@ -5420,26 +5432,11 @@
         // to get into our coordinate space
         if (theParent == this) {
             if (offsetFromChildToParent) {
-                rect.offset(-descendant.mScrollX, -descendant.mScrollY);
-
-                if (!descendant.hasIdentityMatrix()) {
-                    rectF.set(rect);
-                    descendant.getMatrix().mapRect(rectF);
-                    rectF.roundOut(rect);
-                }
-
-                rect.offset(descendant.mLeft, descendant.mTop);
+                rect.offset(descendant.mLeft - descendant.mScrollX,
+                        descendant.mTop - descendant.mScrollY);
             } else {
-                rect.offset(-descendant.mLeft, -descendant.mTop);
-
-                if (!descendant.hasIdentityMatrix()) {
-                    descendant.getMatrix().invert(inverse);
-                    rectF.set(rect);
-                    inverse.mapRect(rectF);
-                    rectF.roundOut(rect);
-                }
-
-                rect.offset(descendant.mScrollX, descendant.mScrollY);
+                rect.offset(descendant.mScrollX - descendant.mLeft,
+                        descendant.mScrollY - descendant.mTop);
             }
         } else {
             throw new IllegalArgumentException("parameter must be a descendant of this view");
@@ -6758,7 +6755,8 @@
     @Override
     public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
             int dxUnconsumed, int dyUnconsumed) {
-        // Do nothing
+        // Re-dispatch up the tree by default
+        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
     }
 
     /**
@@ -6766,7 +6764,8 @@
      */
     @Override
     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
-        // Do nothing
+        // Re-dispatch up the tree by default
+        dispatchNestedPreScroll(dx, dy, consumed, null);
     }
 
     /**
@@ -6774,7 +6773,8 @@
      */
     @Override
     public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
-        return false;
+        // Re-dispatch up the tree by default
+        return dispatchNestedFling(velocityX, velocityY, consumed);
     }
 
     /**
@@ -6782,7 +6782,8 @@
      */
     @Override
     public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
-        return false;
+        // Re-dispatch up the tree by default
+        return dispatchNestedPreFling(velocityX, velocityY);
     }
 
     /**
diff --git a/core/java/android/view/ViewGroupOverlay.java b/core/java/android/view/ViewGroupOverlay.java
index 16afc5d..c2807ba 100644
--- a/core/java/android/view/ViewGroupOverlay.java
+++ b/core/java/android/view/ViewGroupOverlay.java
@@ -15,6 +15,7 @@
  */
 package android.view;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 
@@ -37,7 +38,7 @@
     }
 
     /**
-     * Adds a View to the overlay. The bounds of the added view should be
+     * Adds a {@code View} to the overlay. The bounds of the added view should be
      * relative to the host view. Any view added to the overlay should be
      * removed when it is no longer needed or no longer visible.
      *
@@ -54,23 +55,32 @@
      * and 200 pixels down from the origin of the overlay's
      * host view, then the view will be offset by (100, 200).</p>
      *
-     * @param view The View to be added to the overlay. The added view will be
+     * <p>{@code View}s added with this API will be drawn in the order they were
+     * added. Drawing of the overlay views will happen before drawing of any of the
+     * {@code Drawable}s added with {@link #add(Drawable)} API even if a call to
+     * this API happened after the call to {@link #add(Drawable)}.</p>
+     *
+     * <p>Passing <code>null</code> parameter will result in an
+     * {@link IllegalArgumentException} being thrown.</p>
+     *
+     * @param view The {@code View} to be added to the overlay. The added view will be
      * drawn when the overlay is drawn.
      * @see #remove(View)
      * @see ViewOverlay#add(Drawable)
      */
-    public void add(View view) {
+    public void add(@NonNull View view) {
         mOverlayViewGroup.add(view);
     }
 
     /**
-     * Removes the specified View from the overlay.
+     * Removes the specified {@code View} from the overlay. Passing <code>null</code> parameter
+     * will result in an {@link IllegalArgumentException} being thrown.
      *
-     * @param view The View to be removed from the overlay.
+     * @param view The {@code View} to be removed from the overlay.
      * @see #add(View)
      * @see ViewOverlay#remove(Drawable)
      */
-    public void remove(View view) {
+    public void remove(@NonNull View view) {
         mOverlayViewGroup.remove(view);
     }
 }
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 5e5ef29..b770bd5 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -16,6 +16,7 @@
 package android.view;
 
 import android.animation.LayoutTransition;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -59,25 +60,30 @@
     }
 
     /**
-     * Adds a Drawable to the overlay. The bounds of the drawable should be relative to
+     * Adds a {@link Drawable} to the overlay. The bounds of the drawable should be relative to
      * the host view. Any drawable added to the overlay should be removed when it is no longer
-     * needed or no longer visible.
+     * needed or no longer visible. Adding an already existing {@link Drawable}
+     * is a no-op. Passing <code>null</code> parameter will result in an
+     * {@link IllegalArgumentException} being thrown.
      *
-     * @param drawable The Drawable to be added to the overlay. This drawable will be
-     * drawn when the view redraws its overlay.
+     * @param drawable The {@link Drawable} to be added to the overlay. This drawable will be
+     * drawn when the view redraws its overlay. {@link Drawable}s will be drawn in the order that
+     * they were added.
      * @see #remove(Drawable)
      */
-    public void add(Drawable drawable) {
+    public void add(@NonNull Drawable drawable) {
         mOverlayViewGroup.add(drawable);
     }
 
     /**
-     * Removes the specified Drawable from the overlay.
+     * Removes the specified {@link Drawable} from the overlay. Removing a {@link Drawable} that was
+     * not added with {@link #add(Drawable)} is a no-op. Passing <code>null</code> parameter will
+     * result in an {@link IllegalArgumentException} being thrown.
      *
-     * @param drawable The Drawable to be removed from the overlay.
+     * @param drawable The {@link Drawable} to be removed from the overlay.
      * @see #add(Drawable)
      */
-    public void remove(Drawable drawable) {
+    public void remove(@NonNull Drawable drawable) {
         mOverlayViewGroup.remove(drawable);
     }
 
@@ -119,7 +125,7 @@
          * The View for which this is an overlay. Invalidations of the overlay are redirected to
          * this host view.
          */
-        View mHostView;
+        final View mHostView;
 
         /**
          * The set of drawables to draw when the overlay is rendered.
@@ -137,10 +143,12 @@
             mRenderNode.setLeftTopRightBottom(0, 0, mRight, mBottom);
         }
 
-        public void add(Drawable drawable) {
+        public void add(@NonNull Drawable drawable) {
+            if (drawable == null) {
+                throw new IllegalArgumentException("drawable must be non-null");
+            }
             if (mDrawables == null) {
-
-                mDrawables = new ArrayList<Drawable>();
+                mDrawables = new ArrayList<>();
             }
             if (!mDrawables.contains(drawable)) {
                 // Make each drawable unique in the overlay; can't add it more than once
@@ -150,7 +158,10 @@
             }
         }
 
-        public void remove(Drawable drawable) {
+        public void remove(@NonNull Drawable drawable) {
+            if (drawable == null) {
+                throw new IllegalArgumentException("drawable must be non-null");
+            }
             if (mDrawables != null) {
                 mDrawables.remove(drawable);
                 invalidate(drawable.getBounds());
@@ -159,11 +170,15 @@
         }
 
         @Override
-        protected boolean verifyDrawable(Drawable who) {
+        protected boolean verifyDrawable(@NonNull Drawable who) {
             return super.verifyDrawable(who) || (mDrawables != null && mDrawables.contains(who));
         }
 
-        public void add(View child) {
+        public void add(@NonNull View child) {
+            if (child == null) {
+                throw new IllegalArgumentException("view must be non-null");
+            }
+
             if (child.getParent() instanceof ViewGroup) {
                 ViewGroup parent = (ViewGroup) child.getParent();
                 if (parent != mHostView && parent.getParent() != null &&
@@ -190,13 +205,20 @@
             super.addView(child);
         }
 
-        public void remove(View view) {
+        public void remove(@NonNull View view) {
+            if (view == null) {
+                throw new IllegalArgumentException("view must be non-null");
+            }
+
             super.removeView(view);
         }
 
         public void clear() {
             removeAllViews();
             if (mDrawables != null) {
+                for (Drawable drawable : mDrawables) {
+                    drawable.setCallback(null);
+                }
                 mDrawables.clear();
             }
         }
@@ -210,7 +232,7 @@
         }
 
         @Override
-        public void invalidateDrawable(Drawable drawable) {
+        public void invalidateDrawable(@NonNull Drawable drawable) {
             invalidate(drawable.getBounds());
         }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index f18b7ac..c604234 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -1110,6 +1110,13 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             mView.setHasTransientState(false);
+            if (mAnimatorCleanupMap != null) {
+                Runnable r = mAnimatorCleanupMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorCleanupMap.remove(animation);
+            }
             if (mListener != null) {
                 mListener.onAnimationEnd(animation);
             }
@@ -1120,13 +1127,6 @@
                 }
                 mAnimatorOnEndMap.remove(animation);
             }
-            if (mAnimatorCleanupMap != null) {
-                Runnable r = mAnimatorCleanupMap.get(animation);
-                if (r != null) {
-                    r.run();
-                }
-                mAnimatorCleanupMap.remove(animation);
-            }
             mAnimatorMap.remove(animation);
         }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0517788..5b2877f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,7 +16,8 @@
 
 package android.view;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
+import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -84,6 +85,7 @@
 import android.widget.Scroller;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.PhoneFallbackEventHandler;
@@ -96,8 +98,8 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
 import java.util.HashSet;
+import java.util.concurrent.CountDownLatch;
 
 /**
  * The top of a view hierarchy, implementing the needed protocol between View
@@ -146,9 +148,6 @@
      */
     static final int MAX_TRACKBALL_DELAY = 250;
 
-    private static final int RESIZE_MODE_FREEFORM = 0;
-    private static final int RESIZE_MODE_DOCKED_DIVIDER = 1;
-
     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
 
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
@@ -156,7 +155,12 @@
 
     static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
 
-    final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList();
+    /**
+     * This list must only be modified by the main thread, so a lock is only needed when changing
+     * the list or when accessing the list from a non-main thread.
+     */
+    @GuardedBy("mWindowCallbacks")
+    final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
     final Context mContext;
     final IWindowSession mWindowSession;
     final Display mDisplay;
@@ -233,6 +237,7 @@
     boolean mIsAnimating;
 
     private boolean mDragResizing;
+    private boolean mInvalidateRootRequested;
     private int mResizeMode;
     private int mCanvasOffsetX;
     private int mCanvasOffsetY;
@@ -313,6 +318,7 @@
     final Rect mPendingContentInsets = new Rect();
     final Rect mPendingOutsets = new Rect();
     final Rect mPendingBackDropFrame = new Rect();
+    boolean mPendingAlwaysConsumeNavBar;
     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
             = new ViewTreeObserver.InternalInsetsInfo();
 
@@ -623,6 +629,9 @@
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingStableInsets.set(mAttachInfo.mStableInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
+                mAttachInfo.mAlwaysConsumeNavBar =
+                        (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
+                mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                 if (res < WindowManagerGlobal.ADD_OKAY) {
                     mAttachInfo.mRootView = null;
@@ -765,7 +774,7 @@
      *                          has invoked. If false, the functor may be invoked
      *                          asynchronously.
      */
-    public void invokeFunctor(long functor, boolean waitForCompletion) {
+    public static void invokeFunctor(long functor, boolean waitForCompletion) {
         ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
     }
 
@@ -1072,6 +1081,12 @@
             mStopped = stopped;
             if (!mStopped) {
                 scheduleTraversals();
+            } else {
+                if (mAttachInfo.mHardwareRenderer != null) {
+                    if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle());
+                    mAttachInfo.mHardwareRenderer.updateSurface(null);
+                    mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
+                }
             }
         }
     }
@@ -1343,7 +1358,8 @@
             }
             mLastWindowInsets = new WindowInsets(contentInsets,
                     null /* windowDecorInsets */, stableInsets,
-                    mContext.getResources().getConfiguration().isScreenRound());
+                    mContext.getResources().getConfiguration().isScreenRound(),
+                    mAttachInfo.mAlwaysConsumeNavBar);
         }
         return mLastWindowInsets;
     }
@@ -1461,6 +1477,7 @@
         if (viewVisibilityChanged) {
             mAttachInfo.mWindowVisibility = viewVisibility;
             host.dispatchWindowVisibilityChanged(viewVisibility);
+            host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
                 endDragResizing();
                 destroyHardwareResources();
@@ -1510,6 +1527,9 @@
                 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
                     insetsChanged = true;
                 }
+                if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
+                    insetsChanged = true;
+                }
                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     windowSizeMayChange = true;
@@ -1694,6 +1714,8 @@
                 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
                 final boolean surfaceSizeChanged = (relayoutResult
                         & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
+                final boolean alwaysConsumeNavBarChanged =
+                        mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
                 if (contentInsetsChanged) {
                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
                     if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
@@ -1713,6 +1735,10 @@
                     // Need to relayout with content insets.
                     contentInsetsChanged = true;
                 }
+                if (alwaysConsumeNavBarChanged) {
+                    mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
+                    contentInsetsChanged = true;
+                }
                 if (contentInsetsChanged || mLastSystemUiVisibility !=
                         mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
                         || mLastOverscanRequested != mAttachInfo.mOverscanRequested
@@ -1807,12 +1833,12 @@
                 final boolean dragResizing = freeformResizing || dockedResizing;
                 if (mDragResizing != dragResizing) {
                     if (dragResizing) {
-                        startDragResizing(mPendingBackDropFrame,
-                                mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
-                                mPendingStableInsets);
                         mResizeMode = freeformResizing
                                 ? RESIZE_MODE_FREEFORM
                                 : RESIZE_MODE_DOCKED_DIVIDER;
+                        startDragResizing(mPendingBackDropFrame,
+                                mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
+                                mPendingStableInsets, mResizeMode);
                     } else {
                         // We shouldn't come here, but if we come we should end the resize.
                         endDragResizing();
@@ -1966,7 +1992,7 @@
         boolean triggerGlobalLayoutListener = didLayout
                 || mAttachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
-            performLayout(lp, desiredWindowWidth, desiredWindowHeight);
+            performLayout(lp, mWidth, mHeight);
 
             // By this point all views have been sized and positioned
             // We can compute the transparent area
@@ -2100,7 +2126,7 @@
 
         boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
 
-        if (!cancelDraw) {
+        if (!cancelDraw && !newSurface) {
             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
                     mPendingTransitions.get(i).startChangingAnimations();
@@ -2149,7 +2175,6 @@
             }
         }
     }
-
     private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
         Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
         try {
@@ -2417,6 +2442,9 @@
     @Override
     public void onHardwarePostDraw(DisplayListCanvas canvas) {
         drawAccessibilityFocusedDrawableIfNeeded(canvas);
+        for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+            mWindowCallbacks.get(i).onPostDraw(canvas);
+        }
     }
 
     /**
@@ -2654,7 +2682,8 @@
         if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
             if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
                 // If accessibility focus moved, always invalidate the root.
-                boolean invalidateRoot = accessibilityFocusDirty;
+                boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
+                mInvalidateRootRequested = false;
 
                 // Draw with hardware renderer.
                 mIsAnimating = false;
@@ -2887,6 +2916,14 @@
         return mAttachInfo.mAccessibilityFocusDrawable;
     }
 
+    /**
+     * Requests that the root render node is invalidated next time we perform a draw, such that
+     * {@link WindowCallbacks#onPostDraw} gets called.
+     */
+    public void requestInvalidateRootRenderNode() {
+        mInvalidateRootRequested = true;
+    }
+
     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
         final Rect ci = mAttachInfo.mContentInsets;
         final Rect vi = mAttachInfo.mVisibleInsets;
@@ -3266,7 +3303,6 @@
     private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
     private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
     private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
-    private final static int MSG_FINISH_INPUT_CONNECTION = 12;
     private final static int MSG_CHECK_FOCUS = 13;
     private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
     private final static int MSG_DISPATCH_DRAG_EVENT = 15;
@@ -3306,8 +3342,6 @@
                     return "MSG_DISPATCH_GET_NEW_SURFACE";
                 case MSG_DISPATCH_KEY_FROM_IME:
                     return "MSG_DISPATCH_KEY_FROM_IME";
-                case MSG_FINISH_INPUT_CONNECTION:
-                    return "MSG_FINISH_INPUT_CONNECTION";
                 case MSG_CHECK_FOCUS:
                     return "MSG_CHECK_FOCUS";
                 case MSG_CLOSE_SYSTEM_DIALOGS:
@@ -3381,6 +3415,13 @@
                         updateConfiguration(config, false);
                     }
 
+                    final boolean framesChanged = !mWinFrame.equals(args.arg1)
+                            || !mPendingOverscanInsets.equals(args.arg5)
+                            || !mPendingContentInsets.equals(args.arg2)
+                            || !mPendingStableInsets.equals(args.arg6)
+                            || !mPendingVisibleInsets.equals(args.arg3)
+                            || !mPendingOutsets.equals(args.arg7);
+
                     mWinFrame.set((Rect) args.arg1);
                     mPendingOverscanInsets.set((Rect) args.arg5);
                     mPendingContentInsets.set((Rect) args.arg2);
@@ -3389,6 +3430,7 @@
                     mPendingOutsets.set((Rect) args.arg7);
                     mPendingBackDropFrame.set((Rect) args.arg8);
                     mForceNextWindowRelayout = args.argi1 != 0;
+                    mPendingAlwaysConsumeNavBar = args.argi2 != 0;
 
                     args.recycle();
 
@@ -3396,7 +3438,7 @@
                         mReportNextDraw = true;
                     }
 
-                    if (mView != null) {
+                    if (mView != null && framesChanged) {
                         forceLayout(mView);
                     }
 
@@ -3527,12 +3569,6 @@
                 }
                 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
             } break;
-            case MSG_FINISH_INPUT_CONNECTION: {
-                InputMethodManager imm = InputMethodManager.peekInstance();
-                if (imm != null) {
-                    imm.reportFinishInputConnection((InputConnection)msg.obj);
-                }
-            } break;
             case MSG_CHECK_FOCUS: {
                 InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null) {
@@ -3572,8 +3608,9 @@
                 handleDispatchWindowShown();
             } break;
             case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
-                IResultReceiver receiver = (IResultReceiver) msg.obj;
-                handleRequestKeyboardShortcuts(receiver);
+                final IResultReceiver receiver = (IResultReceiver) msg.obj;
+                final int deviceId = msg.arg1;
+                handleRequestKeyboardShortcuts(receiver, deviceId);
             } break;
             case MSG_UPDATE_POINTER_ICON: {
                 MotionEvent event = (MotionEvent) msg.obj;
@@ -3797,7 +3834,8 @@
                 return true;
             } else if ((!mAttachInfo.mHasWindowFocus
                     && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
-                    || mIsAmbientMode || (mPausedForTransition && !isBack(q.mEvent))) {
+                    || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
+                    || (mPausedForTransition && !isBack(q.mEvent))) {
                 // This is a focus event and the window doesn't currently have input focus or
                 // has stopped. This could be an event that came back from the previous stage
                 // but the window has lost focus or stopped in the meantime.
@@ -4375,8 +4413,14 @@
     private boolean updatePointerIcon(MotionEvent event) {
         final float x = event.getX();
         final float y = event.getY();
+        if (mView == null) {
+            // E.g. click outside a popup to dismiss it
+            Slog.d(mTag, "updatePointerIcon called after view was removed");
+            return false;
+        }
         if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
-            Slog.e(mTag, "updatePointerIcon called with position out of bounds");
+            // E.g. when moving window divider with mouse
+            Slog.d(mTag, "updatePointerIcon called with position out of bounds");
             return false;
         }
         final PointerIcon pointerIcon = mView.getPointerIcon(event, x, y);
@@ -5487,11 +5531,11 @@
         mAttachInfo.mTreeObserver.dispatchOnWindowShown();
     }
 
-    public void handleRequestKeyboardShortcuts(IResultReceiver receiver) {
+    public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
         Bundle data = new Bundle();
         ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
         if (mView != null) {
-            mView.requestKeyboardShortcuts(list);
+            mView.requestKeyboardShortcuts(list, deviceId);
         }
         data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
         try {
@@ -5567,6 +5611,10 @@
                 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
                 mSurface);
+
+        mPendingAlwaysConsumeNavBar =
+                (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
+
         //Log.d(mTag, "<<<<<< BACK FROM relayout");
         if (restore) {
             params.restore();
@@ -5831,14 +5879,10 @@
         }
     }
 
-    public void dispatchFinishInputConnection(InputConnection connection) {
-        Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
-        mHandler.sendMessage(msg);
-    }
-
     public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-            Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
+            Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+            boolean alwaysConsumeNavBar) {
         if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
                 + " contentInsets=" + contentInsets.toShortString()
                 + " visibleInsets=" + visibleInsets.toShortString()
@@ -5875,6 +5919,7 @@
         args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
         args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
         args.argi1 = forceLayout ? 1 : 0;
+        args.argi2 = alwaysConsumeNavBar ? 1 : 0;
         msg.obj = args;
         mHandler.sendMessage(msg);
     }
@@ -6447,8 +6492,9 @@
         }
     }
 
-    public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver) {
-        mHandler.obtainMessage(MSG_REQUEST_KEYBOARD_SHORTCUTS, receiver).sendToTarget();
+    public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
+        mHandler.obtainMessage(
+                MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
     }
 
     /**
@@ -6876,12 +6922,13 @@
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
+                Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+                boolean alwaysConsumeNavBar) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
                         visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
-                        forceLayout);
+                        forceLayout, alwaysConsumeNavBar);
             }
         }
 
@@ -7024,11 +7071,11 @@
         }
 
         @Override
-        public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
-          ViewRootImpl viewAncestor = mViewAncestor.get();
-          if (viewAncestor != null) {
-            viewAncestor.dispatchRequestKeyboardShortcuts(receiver);
-          }
+        public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
+            ViewRootImpl viewAncestor = mViewAncestor.get();
+            if (viewAncestor != null) {
+                viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
+            }
         }
     }
 
@@ -7052,14 +7099,12 @@
      * Start a drag resizing which will inform all listeners that a window resize is taking place.
      */
     private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
-            Rect stableInsets) {
+            Rect stableInsets, int resizeMode) {
         if (!mDragResizing) {
             mDragResizing = true;
-            synchronized (mWindowCallbacks) {
-                for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
-                    mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
-                            systemInsets, stableInsets);
-                }
+            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+                mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
+                        systemInsets, stableInsets, resizeMode);
             }
             mFullRedrawNeeded = true;
         }
@@ -7071,10 +7116,8 @@
     private void endDragResizing() {
         if (mDragResizing) {
             mDragResizing = false;
-            synchronized (mWindowCallbacks) {
-                for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
-                    mWindowCallbacks.get(i).onWindowDragResizeEnd();
-                }
+            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+                mWindowCallbacks.get(i).onWindowDragResizeEnd();
             }
             mFullRedrawNeeded = true;
         }
@@ -7082,13 +7125,11 @@
 
     private boolean updateContentDrawBounds() {
         boolean updated = false;
-        synchronized (mWindowCallbacks) {
-            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
-                updated |= mWindowCallbacks.get(i).onContentDrawn(
-                        mWindowAttributes.surfaceInsets.left,
-                        mWindowAttributes.surfaceInsets.top,
-                        mWidth, mHeight);
-            }
+        for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+            updated |= mWindowCallbacks.get(i).onContentDrawn(
+                    mWindowAttributes.surfaceInsets.left,
+                    mWindowAttributes.surfaceInsets.top,
+                    mWidth, mHeight);
         }
         return updated | (mDragResizing && mReportNextDraw);
     }
@@ -7097,10 +7138,8 @@
         if (mReportNextDraw) {
             mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
         }
-        synchronized (mWindowCallbacks) {
-            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
-                mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
-            }
+        for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+            mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
         }
     }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9f05990..2f3f0bf 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -298,7 +298,7 @@
 
     private boolean mDestroyed;
 
-    private boolean mOverlayWithDecorCaption = false;
+    private boolean mOverlayWithDecorCaptionEnabled = false;
 
     // The current window attributes.
     private final WindowManager.LayoutParams mWindowAttributes =
@@ -565,9 +565,10 @@
          *
          * @param data The data list to populate with shortcuts.
          * @param menu The current menu, which may be null.
+         * @param deviceId The id for the connected device the shortcuts should be provided for.
          */
-        public void onProvideKeyboardShortcuts(
-                List<KeyboardShortcutGroup> data, @Nullable Menu menu);
+        default public void onProvideKeyboardShortcuts(
+                List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) { };
     }
 
     /** @hide */
@@ -2138,13 +2139,13 @@
      * down. This affects only freeform windows since they display the caption.
      * @hide
      */
-    public void setOverlayDecorCaption(boolean overlayCaption) {
-        mOverlayWithDecorCaption = overlayCaption;
+    public void setOverlayWithDecorCaptionEnabled(boolean enabled) {
+        mOverlayWithDecorCaptionEnabled = enabled;
     }
 
     /** @hide */
-    public boolean getOverlayDecorCaption() {
-        return mOverlayWithDecorCaption;
+    public boolean isOverlayWithDecorCaptionEnabled() {
+        return mOverlayWithDecorCaptionEnabled;
     }
 
     /** @hide */
@@ -2180,7 +2181,7 @@
      * Called when the activity changes from fullscreen mode to multi-window mode and visa-versa.
      * @hide
      */
-    public abstract void onMultiWindowChanged();
+    public abstract void onMultiWindowModeChanged();
 
     /**
      * Called when the activity just relaunched.
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index bed74e9..8f2d2e1 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -154,8 +154,9 @@
     }
 
     @Override
-    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
-        mWrapped.onProvideKeyboardShortcuts(data, menu);
+    public void onProvideKeyboardShortcuts(
+            List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
+        mWrapped.onProvideKeyboardShortcuts(data, menu, deviceId);
     }
 }
 
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
index d2bfca7..b2dc1e9 100644
--- a/core/java/android/view/WindowCallbacks.java
+++ b/core/java/android/view/WindowCallbacks.java
@@ -26,6 +26,11 @@
  * @hide
  */
 public interface WindowCallbacks {
+
+    public static final int RESIZE_MODE_INVALID = -1;
+    public static final int RESIZE_MODE_FREEFORM = 0;
+    public static final int RESIZE_MODE_DOCKED_DIVIDER = 1;
+
     /**
      * Called by the system when the window got changed by the user, before the layouter got called.
      * It also gets called when the insets changed, or when the window switched between a fullscreen
@@ -51,7 +56,7 @@
      * @param stableInsets The stable insets for the window.
      */
     void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
-            Rect stableInsets);
+            Rect stableInsets, int resizeMode);
 
     /**
      * Called when a drag resize ends.
@@ -69,4 +74,13 @@
      * @param reportNextDraw Whether it should report when the requested draw finishes.
      */
     void onRequestDraw(boolean reportNextDraw);
+
+    /**
+     * Called after all the content has drawn and the callback now has the ability to draw something
+     * on top of everything. Call {@link ViewRootImpl#requestInvalidateRootRenderNode} when this
+     * content needs to be redrawn.
+     *
+     * @param canvas The canvas to draw on.
+     */
+    void onPostDraw(DisplayListCanvas canvas);
 }
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index b721074..737e4607 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -44,6 +44,8 @@
     public boolean focused;
     public final Rect boundsInScreen = new Rect();
     public List<IBinder> childTokens;
+    public CharSequence title;
+    public int accessibilityIdOfAnchor = View.NO_ID;
 
     private WindowInfo() {
         /* do nothing - hide constructor */
@@ -65,6 +67,8 @@
         window.parentToken = other.parentToken;
         window.focused = other.focused;
         window.boundsInScreen.set(other.boundsInScreen);
+        window.title = other.title;
+        window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
 
         if (other.childTokens != null && !other.childTokens.isEmpty()) {
             if (window.childTokens == null) {
@@ -95,6 +99,8 @@
         parcel.writeStrongBinder(parentToken);
         parcel.writeInt(focused ? 1 : 0);
         boundsInScreen.writeToParcel(parcel, flags);
+        parcel.writeCharSequence(title);
+        parcel.writeInt(accessibilityIdOfAnchor);
 
         if (childTokens != null && !childTokens.isEmpty()) {
             parcel.writeInt(1);
@@ -108,13 +114,15 @@
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("WindowInfo[");
-        builder.append("type=").append(type);
+        builder.append("title=").append(title);
+        builder.append(", type=").append(type);
         builder.append(", layer=").append(layer);
         builder.append(", token=").append(token);
         builder.append(", bounds=").append(boundsInScreen);
         builder.append(", parent=").append(parentToken);
         builder.append(", focused=").append(focused);
         builder.append(", children=").append(childTokens);
+        builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor);
         builder.append(']');
         return builder.toString();
     }
@@ -126,6 +134,8 @@
         parentToken = parcel.readStrongBinder();
         focused = (parcel.readInt() == 1);
         boundsInScreen.readFromParcel(parcel);
+        title = parcel.readCharSequence();
+        accessibilityIdOfAnchor = parcel.readInt();
 
         final boolean hasChildren = (parcel.readInt() == 1);
         if (hasChildren) {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 997e7e8..750931a 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -37,6 +37,13 @@
     private Rect mTempRect;
     private boolean mIsRound;
 
+    /**
+     * In multi-window we force show the navigation bar. Because we don't want that the surface size
+     * changes in this mode, we instead have a flag whether the navigation bar size should always
+     * be consumed, so the app is treated like there is no virtual navigation bar at all.
+     */
+    private boolean mAlwaysConsumeNavBar;
+
     private boolean mSystemWindowInsetsConsumed = false;
     private boolean mWindowDecorInsetsConsumed = false;
     private boolean mStableInsetsConsumed = false;
@@ -52,12 +59,12 @@
     public static final WindowInsets CONSUMED;
 
     static {
-        CONSUMED = new WindowInsets(null, null, null, false);
+        CONSUMED = new WindowInsets(null, null, null, false, false);
     }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
-            boolean isRound) {
+            boolean isRound, boolean alwaysConsumeNavBar) {
         mSystemWindowInsetsConsumed = systemWindowInsets == null;
         mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
 
@@ -68,6 +75,7 @@
         mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : stableInsets;
 
         mIsRound = isRound;
+        mAlwaysConsumeNavBar = alwaysConsumeNavBar;
     }
 
     /**
@@ -83,11 +91,12 @@
         mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
         mStableInsetsConsumed = src.mStableInsetsConsumed;
         mIsRound = src.mIsRound;
+        mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
     }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets) {
-        this(systemWindowInsets, null, null, false);
+        this(systemWindowInsets, null, null, false, false);
     }
 
     /**
@@ -475,6 +484,13 @@
         return result;
     }
 
+    /**
+     * @hide
+     */
+    public boolean shouldAlwaysConsumeNavBar() {
+        return mAlwaysConsumeNavBar;
+    }
+
     @Override
     public String toString() {
         return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 18dfdfd..c372c30 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -30,7 +30,7 @@
 import android.util.Log;
 
 import java.util.List;
-
+import java.util.Objects;
 
 /**
  * The interface that apps use to talk to the window manager.
@@ -135,6 +135,18 @@
     }
 
     /**
+     * Message for taking fullscreen screenshot
+     * @hide
+     */
+    final int TAKE_SCREENSHOT_FULLSCREEN = 1;
+
+    /**
+     * Message for taking screenshot of selected region.
+     * @hide
+     */
+    final int TAKE_SCREENSHOT_SELECTED_REGION = 2;
+
+    /**
      * @hide
      */
     public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
@@ -146,7 +158,7 @@
      *
      * @hide
      */
-    public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver);
+    public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver, int deviceId);
 
     public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
         /**
@@ -269,6 +281,7 @@
             @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
             @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, to = "TYPE_DOCK_DIVIDER"),
             @ViewDebug.IntToString(from = TYPE_QS_DIALOG, to = "TYPE_QS_DIALOG"),
+            @ViewDebug.IntToString(from = TYPE_SCREENSHOT, to = "TYPE_SCREENSHOT")
         })
         public int type;
 
@@ -622,6 +635,13 @@
         public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;
 
         /**
+         * Window type: shares similar characteristics with {@link #TYPE_DREAM}. The layer is
+         * reserved for screenshot region selection.
+         * @hide
+         */
+        public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
@@ -1673,6 +1693,14 @@
          */
         public long userActivityTimeout = -1;
 
+        /**
+         * For windows with an anchor (e.g. PopupWindow), keeps track of the View that anchors the
+         * window.
+         *
+         * @hide
+         */
+        public int accessibilityIdOfAnchor = -1;
+
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = TYPE_APPLICATION;
@@ -1779,6 +1807,7 @@
             out.writeInt(surfaceInsets.bottom);
             out.writeInt(hasManualSurfaceInsets ? 1 : 0);
             out.writeInt(needsMenuKey);
+            out.writeInt(accessibilityIdOfAnchor);
         }
 
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1829,6 +1858,7 @@
             surfaceInsets.bottom = in.readInt();
             hasManualSurfaceInsets = in.readInt() != 0;
             needsMenuKey = in.readInt();
+            accessibilityIdOfAnchor = in.readInt();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1868,6 +1898,8 @@
         /** {@hide} */
         public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
         /** {@hide} */
+        public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
+        /** {@hide} */
         public static final int EVERYTHING_CHANGED = 0xffffffff;
 
         // internal buffer to backup/restore parameters under compatibility mode.
@@ -1950,7 +1982,7 @@
                 // already have one.
                 packageName = o.packageName;
             }
-            if (o.mTitle != null) {
+            if (!Objects.equals(mTitle, o.mTitle) && o.mTitle != null) {
                 // NOTE: mTitle only copied if the originator set one.
                 mTitle = o.mTitle;
                 changes |= TITLE_CHANGED;
@@ -2028,6 +2060,11 @@
                 changes |= NEEDS_MENU_KEY_CHANGED;
             }
 
+            if (accessibilityIdOfAnchor != o.accessibilityIdOfAnchor) {
+                accessibilityIdOfAnchor = o.accessibilityIdOfAnchor;
+                changes |= ACCESSIBILITY_ANCHOR_CHANGED;
+            }
+
             return changes;
         }
 
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 1530b47..887cc3a 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -90,6 +90,13 @@
     public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
 
     /**
+     * In multi-window we force show the navigation bar. Because we don't want that the surface size
+     * changes in this mode, we instead have a flag whether the navigation bar size should always be
+     * consumed, so the app is treated like there is no virtual navigation bar at all.
+     */
+    public static final int RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR = 0x40;
+
+    /**
      * Flag for relayout: the client will be later giving
      * internal insets; as a result, the window will not impact other window
      * layouts until the insets are given.
@@ -107,6 +114,11 @@
     public static final int ADD_FLAG_APP_VISIBLE = 0x2;
     public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE;
 
+    /**
+     * Like {@link #RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR}, but as a "hint" when adding the window.
+     */
+    public static final int ADD_FLAG_ALWAYS_CONSUME_NAV_BAR = 0x4;
+
     public static final int ADD_OKAY = 0;
     public static final int ADD_BAD_APP_TOKEN = -1;
     public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
@@ -158,7 +170,7 @@
                     sWindowManagerService = getWindowManagerService();
                     ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return sWindowManagerService;
@@ -180,7 +192,7 @@
                             },
                             imm.getClient(), imm.getInputContext());
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Failed to open window session", e);
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return sWindowSession;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6e11671..f8c7d68 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -125,7 +125,8 @@
     }
 
     @Override
-    public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver) {
+    public void requestAppKeyboardShortcuts(
+            final KeyboardShortcutsReceiver receiver, int deviceId) {
         IResultReceiver resultReceiver = new IResultReceiver.Stub() {
             @Override
             public void send(int resultCode, Bundle resultData) throws RemoteException {
@@ -136,7 +137,7 @@
         };
         try {
             WindowManagerGlobal.getWindowManagerService()
-                .requestAppKeyboardShortcuts(resultReceiver);
+                .requestAppKeyboardShortcuts(resultReceiver, deviceId);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index c22d60d..3ad730b 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -157,6 +158,15 @@
     public abstract void setMagnificationSpec(MagnificationSpec spec);
 
     /**
+     * Obtains the magnified and available regions.
+     *
+     * @param outMagnified the currently magnified region
+     * @param outAvailable the region available for magnification
+     */
+    public abstract void getMagnificationRegions(@NonNull Region outMagnified,
+            @NonNull Region outAvailable);
+
+    /**
      * Gets the magnification and translation applied to a window given its token.
      * Not all windows are magnified and the window manager policy determines which
      * windows are magnified. The returned result also takes into account the compat
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index a8b7a7b..23b0df2 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -29,7 +29,9 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.view.animation.Animation;
+import com.android.internal.policy.IShortcutService;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -89,6 +91,11 @@
     public final static int FLAG_INTERACTIVE = 0x20000000;
     public final static int FLAG_PASS_TO_USER = 0x40000000;
 
+    // Flags for IActivityManager.keyguardGoingAway()
+    public final static int KEYGUARD_GOING_AWAY_FLAG_TO_SHADE = 1 << 0;
+    public final static int KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS = 1 << 1;
+    public final static int KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER = 1 << 2;
+
     // Flags used for indicating whether the internal and/or external input devices
     // of some type are available.
     public final static int PRESENCE_INTERNAL = 1 << 0;
@@ -121,6 +128,14 @@
     public final static int ACTION_PASS_TO_USER = 0x00000001;
 
     /**
+     * Register shortcuts for window manager to dispatch.
+     * Shortcut code is packed as (metaState << Integer.SIZE) | keyCode
+     * @hide
+     */
+    void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
+            throws RemoteException;
+
+    /**
      * Interface to the Window Manager state associated with a particular
      * window.  You can hold on to an instance of this interface from the call
      * to prepareAddWindow() until removeWindow().
@@ -395,6 +410,12 @@
          *         not attached to any stack.
          */
         int getStackId();
+
+        /**
+         * Returns true if the window is current in multi-windowing mode. i.e. it shares the
+         * screen with other application windows.
+         */
+        public boolean isInMultiWindowMode();
     }
 
     /**
@@ -920,9 +941,10 @@
      * @param outStableInsets The areas covered by stable system windows irrespective of their
      *                        current visibility. Expressed as positive insets.
      * @param outOutsets The areas that are not real display, but we would like to treat as such.
-     *
+     * @return Whether to always consume the navigation bar.
+     *         See {@link #isNavBarForcedShownLw(WindowState)}.
      */
-    public void getInsetHintLw(WindowManager.LayoutParams attrs, int rotation,
+    public boolean getInsetHintLw(WindowManager.LayoutParams attrs, int rotation,
             Rect outContentInsets, Rect outStableInsets, Rect outOutsets);
 
     /**
@@ -1351,6 +1373,12 @@
     public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
             Rect outInsets);
 
+
+    /**
+     * @return true if the navigation bar is forced to stay visible
+     */
+    public boolean isNavBarForcedShownLw(WindowState win);
+
     /**
      * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
      * bar or button bar. See {@link #getNonDecorDisplayWidth}.
@@ -1362,4 +1390,11 @@
      */
     public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
             Rect outInsets);
+
+    /**
+     * @return True if a specified {@param dockSide} is allowed on the current device, or false
+     *         otherwise. It is guaranteed that at least one dock side for a particular orientation
+     *         is allowed, so for example, if DOCKED_RIGHT is not allowed, DOCKED_LEFT is allowed.
+     */
+    public boolean isDockSideAllowed(int dockSide);
 }
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 2cde03d..f8a13a3 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -240,10 +240,12 @@
  *   <li>{@link #getMovementGranularity()} - Sets the granularity at which a view's text
  *       was traversed.</li>
  *   <li>{@link #getText()} -  The text of the source's sub-tree.</li>
- *   <li>{@link #getFromIndex()} - The start of the next/previous text at the specified granularity
- *           - inclusive.</li>
- *   <li>{@link #getToIndex()} - The end of the next/previous text at the specified granularity
- *           - exclusive.</li>
+ *   <li>{@link #getFromIndex()} - The start the text that was skipped over in this movement.
+ *       This is the starting point when moving forward through the text, but not when moving
+ *       back.</li>
+ *   <li>{@link #getToIndex()} - The end of the text that was skipped over in this movement.
+ *       This is the ending point when moving forward through the text, but not when moving
+ *       back.</li>
  *   <li>{@link #isPassword()} - Whether the source is password.</li>
  *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index bdaf291..02d2a8b 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -328,36 +328,6 @@
     // Action arguments
 
     /**
-     * Argument for specifying index of {@link android.text.style.ClickableSpan} the click action is
-     * related to.
-     * <p>
-     * <strong>Type:</strong> int<br>
-     * <strong>Actions:</strong>
-     * {@link AccessibilityAction#ACTION_CLICK}
-     * </p>
-     *
-     * @see AccessibilityAction#ACTION_CLICK
-     */
-    public static final String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT =
-            "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
-
-    /**
-     * Argument for specifying index of character in the text which contains
-     * {@link android.text.style.ClickableSpan} the click action is
-     * related to. If there is more than one {@link android.text.style.ClickableSpan} assigned for
-     * the range the character is in only the first span would be clicked.
-     * <p>
-     * <strong>Type:</strong> int<br>
-     * <strong>Actions:</strong>
-     * {@link AccessibilityAction#ACTION_CLICK}
-     * </p>
-     *
-     * @see AccessibilityAction#ACTION_CLICK
-     */
-    public static final String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT =
-            "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-
-    /**
      * Argument for which movement granularity to be used when traversing the node text.
      * <p>
      * <strong>Type:</strong> int<br>
@@ -2926,8 +2896,10 @@
         mInputType = other.mInputType;
         mLiveRegion = other.mLiveRegion;
         mDrawingOrderInParent = other.mDrawingOrderInParent;
-        if (other.mExtras != null && !other.mExtras.isEmpty()) {
-            getExtras().putAll(other.mExtras);
+        if (other.mExtras != null) {
+            mExtras = new Bundle(other.mExtras);
+        } else {
+            mExtras = null;
         }
         mRangeInfo = (other.mRangeInfo != null)
                 ? RangeInfo.obtain(other.mRangeInfo) : null;
@@ -3006,7 +2978,9 @@
         mDrawingOrderInParent = parcel.readInt();
 
         if (parcel.readInt() == 1) {
-            getExtras().putAll(parcel.readBundle());
+            mExtras = parcel.readBundle();
+        } else {
+            mExtras = null;
         }
 
         if (parcel.readInt() == 1) {
@@ -3073,9 +3047,7 @@
         mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
         mInputType = InputType.TYPE_NULL;
         mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
-        if (mExtras != null) {
-            mExtras.clear();
-        }
+        mExtras = null;
         if (mRangeInfo != null) {
             mRangeInfo.recycle();
             mRangeInfo = null;
@@ -3389,33 +3361,6 @@
 
         /**
          * Action that clicks on the node info.
-         *
-         * <p>
-         * If a specific {@link android.text.style.ClickableSpan} within node's text content is
-         * supposed to be clicked, then one of {@link #ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT} or
-         * {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT} arguments should be specified.
-         * If both arguments are set {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT} would
-         * be ignored.<br>
-         *
-         * {@link #ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT} specifies index of corresponding
-         * {@link android.text.style.ClickableSpan} in {@link android.text.SpannableString}.<br>
-         *
-         * {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT} specifies index of character
-         * that could contain one or more spans.
-         * </p>
-         *
-         * <p>
-         * <strong>Optional arguments:</strong>
-         * {@link #ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT},
-         * {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT}<br>
-         * <strong>Example:</strong> Perform click on 3rd {@link android.text.style.ClickableSpan}
-         * inside {@link android.text.SpannableString} in node's text.
-         * <code><pre><p>
-         *   Bundle arguments = new Bundle();
-         *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT, 3);
-         *   info.performAction(AccessibilityAction.ACTION_CLICK.getId(), arguments);
-         * </code></pre></p>
-         * </p>
          */
         public static final AccessibilityAction ACTION_CLICK =
                 new AccessibilityAction(
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index a75e8a7..d0d4507 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -64,6 +64,12 @@
      */
     public static final int TYPE_ACCESSIBILITY_OVERLAY = 4;
 
+    /**
+     * Window type: A system window used to divide the screen in split-screen mode.
+     * This type of window is present only in split-screen mode.
+     */
+    public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5;
+
     private static final int UNDEFINED = -1;
 
     private static final int BOOLEAN_PROPERTY_ACTIVE = 1 << 0;
@@ -83,6 +89,8 @@
     private int mParentId = UNDEFINED;
     private final Rect mBoundsInScreen = new Rect();
     private LongArray mChildIds;
+    private CharSequence mTitle;
+    private int mAnchorId = UNDEFINED;
 
     private int mConnectionId = UNDEFINED;
 
@@ -91,6 +99,26 @@
     }
 
     /**
+     * Gets the title of the window.
+     *
+     * @return The title.
+     */
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Sets the title of the window.
+     *
+     * @param title The title.
+     *
+     * @hide
+     */
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+    }
+
+    /**
      * Gets the type of the window.
      *
      * @return The type.
@@ -153,9 +181,35 @@
     }
 
     /**
-     * Gets the parent window if such.
+     * Sets the anchor node's ID.
      *
-     * @return The parent window.
+     * @param anchorId The anchor's accessibility id in its window.
+     *
+     * @hide
+     */
+    public void setAnchorId(int anchorId) {
+        mAnchorId = anchorId;
+    }
+
+    /**
+     * Gets the node that anchors this window to another.
+     *
+     * @return The anchor node, or {@code null} if none exists.
+     */
+    public AccessibilityNodeInfo getAnchor() {
+        if ((mConnectionId == UNDEFINED) || (mAnchorId == UNDEFINED) || (mParentId == UNDEFINED)) {
+            return null;
+        }
+
+        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+                mParentId, mAnchorId, true, 0);
+    }
+
+    /**
+     * Gets the parent window.
+     *
+     * @return The parent window, or {@code null} if none exists.
      */
     public AccessibilityWindowInfo getParent() {
         if (mConnectionId == UNDEFINED || mParentId == UNDEFINED) {
@@ -364,6 +418,8 @@
         infoClone.mId = info.mId;
         infoClone.mParentId = info.mParentId;
         infoClone.mBoundsInScreen.set(info.mBoundsInScreen);
+        infoClone.mTitle = info.mTitle;
+        infoClone.mAnchorId = info.mAnchorId;
 
         if (info.mChildIds != null && info.mChildIds.size() > 0) {
             if (infoClone.mChildIds == null) {
@@ -404,6 +460,8 @@
         parcel.writeInt(mId);
         parcel.writeInt(mParentId);
         mBoundsInScreen.writeToParcel(parcel, flags);
+        parcel.writeCharSequence(mTitle);
+        parcel.writeInt(mAnchorId);
 
         final LongArray childIds = mChildIds;
         if (childIds == null) {
@@ -426,6 +484,8 @@
         mId = parcel.readInt();
         mParentId = parcel.readInt();
         mBoundsInScreen.readFromParcel(parcel);
+        mTitle = parcel.readCharSequence();
+        mAnchorId = parcel.readInt();
 
         final int childCount = parcel.readInt();
         if (childCount > 0) {
@@ -465,6 +525,7 @@
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("AccessibilityWindowInfo[");
+        builder.append("title=").append(mTitle);
         builder.append("id=").append(mId);
         builder.append(", type=").append(typeToString(mType));
         builder.append(", layer=").append(mLayer);
@@ -488,6 +549,7 @@
             builder.append(']');
         } else {
             builder.append(", hasParent=").append(mParentId != UNDEFINED);
+            builder.append(", isAnchored=").append(mAnchorId != UNDEFINED);
             builder.append(", hasChildren=").append(mChildIds != null
                     && mChildIds.size() > 0);
         }
@@ -509,6 +571,8 @@
             mChildIds.clear();
         }
         mConnectionId = UNDEFINED;
+        mAnchorId = UNDEFINED;
+        mTitle = null;
     }
 
     /**
@@ -551,6 +615,9 @@
             case TYPE_ACCESSIBILITY_OVERLAY: {
                 return "TYPE_ACCESSIBILITY_OVERLAY";
             }
+            case TYPE_SPLIT_SCREEN_DIVIDER: {
+                return "TYPE_SPLIT_SCREEN_DIVIDER";
+            }
             default:
                 return "<UNKNOWN>";
         }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 655c9b3..7f44bac 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -59,4 +59,8 @@
             boolean touchExplorationEnabled);
 
     IBinder getWindowToken(int windowId, int userId);
+
+    void enableAccessibilityService(in ComponentName service, int userId);
+
+    void disableAccessibilityService(in ComponentName service, int userId);
 }
diff --git a/core/java/android/view/animation/BaseInterpolator.java b/core/java/android/view/animation/BaseInterpolator.java
index 9c0014c..a78fa1e 100644
--- a/core/java/android/view/animation/BaseInterpolator.java
+++ b/core/java/android/view/animation/BaseInterpolator.java
@@ -16,22 +16,24 @@
 
 package android.view.animation;
 
+import android.content.pm.ActivityInfo.Config;
+
 /**
  * An abstract class which is extended by default interpolators.
  */
 abstract public class BaseInterpolator implements Interpolator {
-    private int mChangingConfiguration;
+    private @Config int mChangingConfiguration;
     /**
      * @hide
      */
-    public int getChangingConfiguration() {
+    public @Config int getChangingConfiguration() {
         return mChangingConfiguration;
     }
 
     /**
      * @hide
      */
-    void setChangingConfiguration(int changingConfiguration) {
+    void setChangingConfiguration(@Config int changingConfiguration) {
         mChangingConfiguration = changingConfiguration;
     }
 }
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 6a830f8..89dec2d 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,6 +16,7 @@
 
 package android.view.inputmethod;
 
+import android.annotation.CallSuper;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Bundle;
@@ -154,12 +155,11 @@
     }
 
     /**
-     * Called when this InputConnection is no longer used by the InputMethodManager.
-     *
-     * @hide
+     * Default implementation calls {@link #finishComposingText()}.
      */
-    protected void reportFinish() {
-        // Intentionaly empty
+    @CallSuper
+    public void closeConnection() {
+        finishComposingText();
     }
 
     /**
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 2a9706d..9f66429 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -28,10 +28,26 @@
  * cursor, committing text to the text box, and sending raw key events
  * to the application.
  *
- * <p>Applications should never directly implement this interface, but
- * instead subclass from {@link BaseInputConnection}. This will ensure
- * that the application does not break when new methods are added to
- * the interface.</p>
+ * <p>Starting from API Level {@link android.os.Build.VERSION_CODES#N},
+ * the system can deal with the situation where the application directly
+ * implements this class but one or more of the following methods are
+ * not implemented.</p>
+ * <ul>
+ *     <li>{@link #getSelectedText(int)}, which was introduced in
+ *     {@link android.os.Build.VERSION_CODES#GINGERBREAD}.</li>
+ *     <li>{@link #setComposingRegion(int, int)}, which was introduced
+ *     in {@link android.os.Build.VERSION_CODES#GINGERBREAD}.</li>
+ *     <li>{@link #commitCorrection(CorrectionInfo)}, which was introduced
+ *     in {@link android.os.Build.VERSION_CODES#HONEYCOMB}.</li>
+ *     <li>{@link #requestCursorUpdates(int)}, which was introduced in
+ *     {@link android.os.Build.VERSION_CODES#LOLLIPOP}.</li>
+ *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}}, which
+ *     was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
+ *     <li>{@link #getHandler()}}, which was introduced in
+ *     {@link android.os.Build.VERSION_CODES#N}.</li>
+ *     <li>{@link #closeConnection()}}, which was introduced in
+ *     {@link android.os.Build.VERSION_CODES#N}.</li>
+ * </ul>
  *
  * <h3>Implementing an IME or an editor</h3>
  * <p>Text input is the result of the synergy of two essential components:
@@ -224,7 +240,9 @@
      * @param flags Supplies additional options controlling how the text is
      * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}.
      * @return the text that is currently selected, if any, or null if
-     * no text is selected.
+     * no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
+     * later, returns false when the target application does not implement
+     * this method.
      */
     public CharSequence getSelectedText(int flags);
 
@@ -371,7 +389,8 @@
      *        If this is greater than the number of existing characters between the cursor and
      *        the end of the text, then this method does not fail but deletes all the characters in
      *        that range.
-     * @return true on success, false if the input connection is no longer valid.
+     * @return true on success, false if the input connection is no longer valid.  Returns
+     * {@code false} when the target application does not implement this method.
      */
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
 
@@ -461,7 +480,8 @@
      * @param start the position in the text at which the composing region begins
      * @param end the position in the text at which the composing region ends
      * @return true on success, false if the input connection is no longer
-     * valid.
+     * valid. In {@link android.os.Build.VERSION_CODES#N} and later, false is returned when the
+     * target application does not implement this method.
      */
     public boolean setComposingRegion(int start, int end);
 
@@ -573,6 +593,8 @@
      *
      * @param correctionInfo Detailed information about the correction.
      * @return true on success, false if the input connection is no longer valid.
+     * In {@link android.os.Build.VERSION_CODES#N} and later, returns false
+     * when the target application does not implement this method.
      */
     public boolean commitCorrection(CorrectionInfo correctionInfo);
 
@@ -785,6 +807,8 @@
      * @return {@code true} if the request is scheduled. {@code false} to indicate that when the
      * application will not call
      * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}.
+     * In {@link android.os.Build.VERSION_CODES#N} and later, returns {@code false} also when the
+     * target application does not implement this method.
      */
     public boolean requestCursorUpdates(int cursorUpdateMode);
 
@@ -798,4 +822,18 @@
      * @return {@code null} to use the default {@link Handler}.
      */
     public Handler getHandler();
+
+    /**
+     * Called by the system up to only once to notify that the system is about to invalidate
+     * connection between the input method and the application.
+     *
+     * <p><strong>Editor authors</strong>: You can clear all the nested batch edit right now and
+     * you no longer need to handle subsequent callbacks on this connection, including
+     * {@link #beginBatchEdit()}}.  Note that although the system tries to call this method whenever
+     * possible, there may be a chance that this method is not called in some exceptional
+     * situations.</p>
+     *
+     * <p>Note: This does nothing when called from input methods.</p>
+     */
+    public void closeConnection();
 }
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
new file mode 100644
index 0000000..118a61f
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputConnectionInspector.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * @hide
+ */
+public final class InputConnectionInspector {
+
+    @Retention(SOURCE)
+    @IntDef({MissingMethodFlags.GET_SELECTED_TEXT,
+            MissingMethodFlags.SET_COMPOSING_REGION,
+            MissingMethodFlags.COMMIT_CORRECTION,
+            MissingMethodFlags.REQUEST_CURSOR_UPDATES,
+            MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
+            MissingMethodFlags.GET_HANDLER,
+    })
+    public @interface MissingMethodFlags {
+        /**
+         * {@link InputConnection#getSelectedText(int)} is available in
+         * {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
+         */
+        int GET_SELECTED_TEXT = 1 << 0;
+        /**
+         * {@link InputConnection#setComposingRegion(int, int)} is available in
+         * {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
+         */
+        int SET_COMPOSING_REGION = 1 << 1;
+        /**
+         * {@link InputConnection#commitCorrection(CorrectionInfo)} is available in
+         * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and later.
+         */
+        int COMMIT_CORRECTION = 1 << 2;
+        /**
+         * {@link InputConnection#requestCursorUpdates(int)} is available in
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later.
+         */
+        int REQUEST_CURSOR_UPDATES = 1 << 3;
+        /**
+         * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
+         * {@link android.os.Build.VERSION_CODES#N} and later.
+         */
+        int DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 1 << 4;
+        /**
+         * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
+         * {@link android.os.Build.VERSION_CODES#N} and later.
+         */
+        int GET_HANDLER = 1 << 5;
+        /**
+         * {@link InputConnection#closeConnection()}} is available in
+         * {@link android.os.Build.VERSION_CODES#N} and later.
+         */
+        int CLOSE_CONNECTION = 1 << 6;
+    }
+
+    private static final Map<Class, Integer> sMissingMethodsMap = Collections.synchronizedMap(
+            new WeakHashMap<>());
+
+    @MissingMethodFlags
+    public static int getMissingMethodFlags(@Nullable final InputConnection ic) {
+        if (ic == null) {
+            return 0;
+        }
+        // Optimization for a known class.
+        if (ic instanceof BaseInputConnection) {
+            return 0;
+        }
+        // Optimization for a known class.
+        if (ic instanceof InputConnectionWrapper) {
+            return ((InputConnectionWrapper) ic).getMissingMethodFlags();
+        }
+        return getMissingMethodFlagsInternal(ic.getClass());
+    }
+
+    @MissingMethodFlags
+    public static int getMissingMethodFlagsInternal(@NonNull final Class clazz) {
+        final Integer cachedFlags = sMissingMethodsMap.get(clazz);
+        if (cachedFlags != null) {
+            return cachedFlags;
+        }
+        int flags = 0;
+        if (!hasGetSelectedText(clazz)) {
+            flags |= MissingMethodFlags.GET_SELECTED_TEXT;
+        }
+        if (!hasSetComposingRegion(clazz)) {
+            flags |= MissingMethodFlags.SET_COMPOSING_REGION;
+        }
+        if (!hasCommitCorrection(clazz)) {
+            flags |= MissingMethodFlags.COMMIT_CORRECTION;
+        }
+        if (!hasRequestCursorUpdate(clazz)) {
+            flags |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
+        }
+        if (!hasDeleteSurroundingTextInCodePoints(clazz)) {
+            flags |= MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS;
+        }
+        if (!hasGetHandler(clazz)) {
+            flags |= MissingMethodFlags.GET_HANDLER;
+        }
+        if (!hasCloseConnection(clazz)) {
+            flags |= MissingMethodFlags.CLOSE_CONNECTION;
+        }
+        sMissingMethodsMap.put(clazz, flags);
+        return flags;
+    }
+
+    private static boolean hasGetSelectedText(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("getSelectedText", int.class);
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    private static boolean hasSetComposingRegion(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("setComposingRegion", int.class, int.class);
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    private static boolean hasCommitCorrection(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("commitCorrection", CorrectionInfo.class);
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    private static boolean hasRequestCursorUpdate(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("requestCursorUpdates", int.class);
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    private static boolean hasDeleteSurroundingTextInCodePoints(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("deleteSurroundingTextInCodePoints", int.class,
+                    int.class);
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    private static boolean hasGetHandler(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("getHandler");
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    private static boolean hasCloseConnection(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("closeConnection");
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
+    public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
+        final StringBuilder sb = new StringBuilder();
+        boolean isEmpty = true;
+        if ((flags & MissingMethodFlags.GET_SELECTED_TEXT) != 0) {
+            sb.append("getSelectedText(int)");
+            isEmpty = false;
+        }
+        if ((flags & MissingMethodFlags.SET_COMPOSING_REGION) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("setComposingRegion(int, int)");
+            isEmpty = false;
+        }
+        if ((flags & MissingMethodFlags.COMMIT_CORRECTION) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("commitCorrection(CorrectionInfo)");
+            isEmpty = false;
+        }
+        if ((flags & MissingMethodFlags.REQUEST_CURSOR_UPDATES) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("requestCursorUpdate(int)");
+            isEmpty = false;
+        }
+        if ((flags & MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("deleteSurroundingTextInCodePoints(int, int)");
+            isEmpty = false;
+        }
+        if ((flags & MissingMethodFlags.GET_HANDLER) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("getHandler()");
+        }
+        if ((flags & MissingMethodFlags.CLOSE_CONNECTION) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("closeConnection()");
+        }
+        return sb.toString();
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 65c7654..e743f62 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -21,121 +21,252 @@
 import android.view.KeyEvent;
 
 /**
- * <p>Wrapper class for proxying calls to another InputConnection.  Subclass
- * and have fun!
+ * <p>Wrapper class for proxying calls to another InputConnection.  Subclass and have fun!
  */
 public class InputConnectionWrapper implements InputConnection {
     private InputConnection mTarget;
     final boolean mMutable;
-    
+    @InputConnectionInspector.MissingMethodFlags
+    private int mMissingMethodFlags;
+
+    /**
+     * Initializes a wrapper.
+     *
+     * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
+     * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
+     * has {@code null} in {@code target}.</p>
+     * @param target the {@link InputConnection} to be proxied.
+     * @param mutable set {@code true} to protect this object from being reconfigured to target
+     * another {@link InputConnection}.  Note that this is ignored while the target is {@code null}.
+     */
     public InputConnectionWrapper(InputConnection target, boolean mutable) {
         mMutable = mutable;
         mTarget = target;
+        mMissingMethodFlags = InputConnectionInspector.getMissingMethodFlags(target);
     }
 
     /**
      * Change the target of the input connection.
+     *
+     * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
+     * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
+     * has {@code null} in {@code target}.</p>
+     * @param target the {@link InputConnection} to be proxied.
+     * @throws SecurityException when this wrapper has non-null target and is immutable.
      */
     public void setTarget(InputConnection target) {
         if (mTarget != null && !mMutable) {
             throw new SecurityException("not mutable");
         }
         mTarget = target;
+        mMissingMethodFlags = InputConnectionInspector.getMissingMethodFlags(target);
     }
-    
+
+    /**
+     * @hide
+     */
+    @InputConnectionInspector.MissingMethodFlags
+    public int getMissingMethodFlags() {
+        return mMissingMethodFlags;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public CharSequence getTextBeforeCursor(int n, int flags) {
         return mTarget.getTextBeforeCursor(n, flags);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public CharSequence getTextAfterCursor(int n, int flags) {
         return mTarget.getTextAfterCursor(n, flags);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public CharSequence getSelectedText(int flags) {
         return mTarget.getSelectedText(flags);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public int getCursorCapsMode(int reqModes) {
         return mTarget.getCursorCapsMode(reqModes);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
         return mTarget.getExtractedText(request, flags);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
         return mTarget.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         return mTarget.deleteSurroundingText(beforeLength, afterLength);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
         return mTarget.setComposingText(text, newCursorPosition);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean setComposingRegion(int start, int end) {
         return mTarget.setComposingRegion(start, end);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean finishComposingText() {
         return mTarget.finishComposingText();
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean commitText(CharSequence text, int newCursorPosition) {
         return mTarget.commitText(text, newCursorPosition);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean commitCompletion(CompletionInfo text) {
         return mTarget.commitCompletion(text);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean commitCorrection(CorrectionInfo correctionInfo) {
         return mTarget.commitCorrection(correctionInfo);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean setSelection(int start, int end) {
         return mTarget.setSelection(start, end);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean performEditorAction(int editorAction) {
         return mTarget.performEditorAction(editorAction);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean performContextMenuAction(int id) {
         return mTarget.performContextMenuAction(id);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean beginBatchEdit() {
         return mTarget.beginBatchEdit();
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean endBatchEdit() {
         return mTarget.endBatchEdit();
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean sendKeyEvent(KeyEvent event) {
         return mTarget.sendKeyEvent(event);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean clearMetaKeyStates(int states) {
         return mTarget.clearMetaKeyStates(states);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean reportFullscreenMode(boolean enabled) {
         return mTarget.reportFullscreenMode(enabled);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean performPrivateCommand(String action, Bundle data) {
         return mTarget.performPrivateCommand(action, data);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean requestCursorUpdates(int cursorUpdateMode) {
         return mTarget.requestCursorUpdates(cursorUpdateMode);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public Handler getHandler() {
         return mTarget.getHandler();
     }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
+    public void closeConnection() {
+        mTarget.closeConnection();
+    }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2de9897..1ce80434 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -317,7 +317,6 @@
     /**
      * The InputConnection that was last retrieved from the served view.
      */
-    InputConnection mServedInputConnection;
     ControlledInputConnectionWrapper mServedInputConnectionWrapper;
     /**
      * The completions that were last provided by the served view.
@@ -494,12 +493,7 @@
                         // Check focus again in case that "onWindowFocus" is called before
                         // handling this message.
                         if (mServedView != null && mServedView.hasWindowFocus()) {
-                            // Please note that this handler thread could be different
-                            // from a thread that created mServedView. That could happen
-                            // the current activity is running in the system process.
-                            // In that case, we really should not call
-                            // mServedInputConnection.finishComposingText.
-                            if (checkFocusNoStartInput(mHasBeenInactive, false)) {
+                            if (checkFocusNoStartInput(mHasBeenInactive)) {
                                 final int reason = active ?
                                         InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS :
                                         InputMethodClient.START_INPUT_REASON_DEACTIVATED_BY_IMMS;
@@ -532,22 +526,25 @@
 
     private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
         private final InputMethodManager mParentInputMethodManager;
-        private boolean mActive;
 
         public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
                 final InputMethodManager inputMethodManager) {
             super(mainLooper, conn);
             mParentInputMethodManager = inputMethodManager;
-            mActive = true;
         }
 
         @Override
         public boolean isActive() {
-            return mParentInputMethodManager.mActive && mActive;
+            return mParentInputMethodManager.mActive && !isFinished();
         }
 
         void deactivate() {
-            mActive = false;
+            if (isFinished()) {
+                // This is a small performance optimization.  Still only the 1st call of
+                // reportFinish() will take effect.
+                return;
+            }
+            closeConnection();
         }
 
         @Override
@@ -562,7 +559,9 @@
 
         @Override
         public String toString() {
-            return "ControlledInputConnectionWrapper{mActive=" + mActive
+            return "ControlledInputConnectionWrapper{"
+                    + "connection=" + getInputConnection()
+                    + " finished=" + isFinished()
                     + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
                     + "}";
         }
@@ -664,7 +663,7 @@
         try {
             return mService.getInputMethodList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -672,7 +671,7 @@
         try {
             return mService.getEnabledInputMethodList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -689,7 +688,7 @@
             return mService.getEnabledInputMethodSubtypeList(
                     imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -697,7 +696,7 @@
         try {
             mService.updateStatusIcon(imeToken, packageName, iconId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -705,7 +704,7 @@
         try {
             mService.updateStatusIcon(imeToken, null, 0);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -714,7 +713,7 @@
         try {
             mService.setImeWindowStatus(imeToken, vis, backDisposition);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -728,7 +727,7 @@
         try {
             mService.registerSuggestionSpansForNotification(spans);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -737,7 +736,7 @@
         try {
             mService.notifySuggestionPicked(span, originalString, index);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -780,7 +779,8 @@
      */
     public boolean isAcceptingText() {
         checkFocus();
-        return mServedInputConnection != null;
+        return mServedInputConnectionWrapper != null &&
+                mServedInputConnectionWrapper.getInputConnection() != null;
     }
 
     /**
@@ -815,7 +815,6 @@
      */
     void clearConnectionLocked() {
         mCurrentTextBoxAttribute = null;
-        mServedInputConnection = null;
         if (mServedInputConnectionWrapper != null) {
             mServedInputConnectionWrapper.deactivate();
             mServedInputConnectionWrapper = null;
@@ -828,14 +827,14 @@
     void finishInputLocked() {
         mNextServedView = null;
         if (mServedView != null) {
-            if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
+            if (DEBUG) Log.v(TAG, "FINISH INPUT: mServedView=" + dumpViewInfo(mServedView));
             if (mCurrentTextBoxAttribute != null) {
                 try {
                     mService.finishInput(mClient);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
-            notifyInputConnectionFinished();
             mServedView = null;
             mCompletions = null;
             mServedConnecting = false;
@@ -843,37 +842,6 @@
         }
     }
 
-    /**
-     * Notifies the served view that the current InputConnection will no longer be used.
-     */
-    private void notifyInputConnectionFinished() {
-        if (mServedView != null && mServedInputConnection != null) {
-            // We need to tell the previously served view that it is no
-            // longer the input target, so it can reset its state.  Schedule
-            // this call on its window's Handler so it will be on the correct
-            // thread and outside of our lock.
-            ViewRootImpl viewRootImpl = mServedView.getViewRootImpl();
-            if (viewRootImpl != null) {
-                // This will result in a call to reportFinishInputConnection() below.
-                viewRootImpl.dispatchFinishInputConnection(mServedInputConnection);
-            }
-        }
-    }
-
-    /**
-     * Called from the FINISH_INPUT_CONNECTION message above.
-     * @hide
-     */
-    public void reportFinishInputConnection(InputConnection ic) {
-        if (mServedInputConnection != ic) {
-            ic.finishComposingText();
-            // To avoid modifying the public InputConnection interface
-            if (ic instanceof BaseInputConnection) {
-                ((BaseInputConnection) ic).reportFinish();
-            }
-        }
-    }
-
     public void displayCompletions(View view, CompletionInfo[] completions) {
         checkFocus();
         synchronized (mH) {
@@ -974,7 +942,17 @@
      * shown to the user, if needed.  Call this if the user interacts with
      * your view in such a way that they have expressed they would like to
      * start performing input into it.
-     * 
+     *
+     * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
+     * this method can be a long-lived object, because it may not be
+     * garbage-collected until all the corresponding {@link ResultReceiver}
+     * objects transferred to different processes get garbage-collected.
+     * Follow the general patterns to avoid memory leaks in Android.
+     * Consider to use {@link java.lang.ref.WeakReference} so that application
+     * logic objects such as {@link android.app.Activity} and {@link Context}
+     * can be garbage collected regardless of the lifetime of
+     * {@link ResultReceiver}.
+     *
      * @param view The currently focused view, which would like to receive
      * soft keyboard input.
      * @param flags Provides additional operating flags.  Currently may be
@@ -996,9 +974,8 @@
             try {
                 return mService.showSoftInput(mClient, flags, resultReceiver);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
-            
-            return false;
         }
     }
     
@@ -1007,6 +984,7 @@
         try {
             mService.showSoftInput(mClient, flags, resultReceiver);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
     
@@ -1043,7 +1021,17 @@
      * that is currently accepting input.  This should be called as a result
      * of the user doing some actually than fairly explicitly requests to
      * have the input window hidden.
-     * 
+     *
+     * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
+     * this method can be a long-lived object, because it may not be
+     * garbage-collected until all the corresponding {@link ResultReceiver}
+     * objects transferred to different processes get garbage-collected.
+     * Follow the general patterns to avoid memory leaks in Android.
+     * Consider to use {@link java.lang.ref.WeakReference} so that application
+     * logic objects such as {@link android.app.Activity} and {@link Context}
+     * can be garbage collected regardless of the lifetime of
+     * {@link ResultReceiver}.
+     *
      * @param windowToken The token of the window that is making the request,
      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
      * @param flags Provides additional operating flags.  Currently may be
@@ -1065,8 +1053,8 @@
             try {
                 return mService.hideSoftInput(mClient, flags, resultReceiver);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
-            return false;
         }
     }
     
@@ -1148,10 +1136,10 @@
         final View view;
         synchronized (mH) {
             view = mServedView;
-            
+
             // Make sure we have a window token for the served view.
             if (DEBUG) {
-                Log.v(TAG, "Starting input: view=" + view +
+                Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) +
                         " reason=" + InputMethodClient.getStartInputReason(startInputReason));
             }
             if (view == null) {
@@ -1159,7 +1147,7 @@
                 return false;
             }
         }
-        
+
         // Now we need to get an input connection from the served view.
         // This is complicated in a couple ways: we can't be holding our lock
         // when calling out to the view, and we need to make sure we call into
@@ -1204,9 +1192,10 @@
             // changed.
             if (mServedView != view || !mServedConnecting) {
                 // Something else happened, so abort.
-                if (DEBUG) Log.v(TAG, 
-                        "Starting input: finished by someone else (view="
-                        + mServedView + " conn=" + mServedConnecting + ")");
+                if (DEBUG) Log.v(TAG,
+                        "Starting input: finished by someone else. view=" + dumpViewInfo(view)
+                        + " mServedView=" + dumpViewInfo(mServedView)
+                        + " mServedConnecting=" + mServedConnecting);
                 return false;
             }
 
@@ -1219,10 +1208,12 @@
             // Hook 'em up and let 'er rip.
             mCurrentTextBoxAttribute = tba;
             mServedConnecting = false;
-            // Notify the served view that its previous input connection is finished
-            notifyInputConnectionFinished();
-            mServedInputConnection = ic;
+            if (mServedInputConnectionWrapper != null) {
+                mServedInputConnectionWrapper.deactivate();
+                mServedInputConnectionWrapper = null;
+            }
             ControlledInputConnectionWrapper servedContext;
+            final int missingMethodFlags;
             if (ic != null) {
                 mCursorSelStart = tba.initialSelStart;
                 mCursorSelEnd = tba.initialSelEnd;
@@ -1230,30 +1221,30 @@
                 mCursorCandEnd = -1;
                 mCursorRect.setEmpty();
                 mCursorAnchorInfo = null;
-                final Handler icHandler = ic.getHandler();
+                final Handler icHandler;
+                missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
+                if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)
+                        != 0) {
+                    // InputConnection#getHandler() is not implemented.
+                    icHandler = null;
+                } else {
+                    icHandler = ic.getHandler();
+                }
                 servedContext = new ControlledInputConnectionWrapper(
                         icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
             } else {
                 servedContext = null;
-            }
-            if (mServedInputConnectionWrapper != null) {
-                mServedInputConnectionWrapper.deactivate();
+                missingMethodFlags = 0;
             }
             mServedInputConnectionWrapper = servedContext;
 
             try {
-                if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
+                if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
                         + ic + " tba=" + tba + " controlFlags=#"
                         + Integer.toHexString(controlFlags));
-                InputBindResult res;
-                if (windowGainingFocus != null) {
-                    res = mService.windowGainedFocus(startInputReason, mClient, windowGainingFocus,
-                            controlFlags, softInputMode, windowFlags,
-                            tba, servedContext);
-                } else {
-                    res = mService.startInput(startInputReason, mClient,
-                            servedContext, tba, controlFlags);
-                }
+                final InputBindResult res = mService.startInputOrWindowGainedFocus(
+                        startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
+                        windowFlags, tba, servedContext, missingMethodFlags);
                 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
                 if (res != null) {
                     if (res.id != null) {
@@ -1314,7 +1305,13 @@
     }
 
     void focusInLocked(View view) {
-        if (DEBUG) Log.v(TAG, "focusIn: " + view);
+        if (DEBUG) Log.v(TAG, "focusIn: " + dumpViewInfo(view));
+
+        if (view != null && view.isTemporarilyDetached()) {
+            // This is a request from a view that is temporarily detached from a window.
+            if (DEBUG) Log.v(TAG, "Temporarily detached view, ignoring");
+            return;
+        }
 
         if (mCurRootView != view.getRootView()) {
             // This is a request from a window that isn't in the window with
@@ -1333,15 +1330,15 @@
      */
     public void focusOut(View view) {
         synchronized (mH) {
-            if (DEBUG) Log.v(TAG, "focusOut: " + view
-                    + " mServedView=" + mServedView
-                    + " winFocus=" + view.hasWindowFocus());
+            if (DEBUG) Log.v(TAG, "focusOut: view=" + dumpViewInfo(view)
+                    + " mServedView=" + dumpViewInfo(mServedView));
             if (mServedView != view) {
                 // The following code would auto-hide the IME if we end up
                 // with no more views with focus.  This can happen, however,
                 // whenever we go into touch mode, so it ends up hiding
                 // at times when we don't really want it to.  For now it
                 // seems better to just turn it all off.
+                // TODO: Check view.isTemporarilyDetached() when re-enable the following code.
                 if (false && view.hasWindowFocus()) {
                     mNextServedView = null;
                     scheduleCheckFocusLocked(view);
@@ -1356,10 +1353,9 @@
      */
     public void onViewDetachedFromWindow(View view) {
         synchronized (mH) {
-            if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: " + view
-                    + " mServedView=" + mServedView
-                    + " hasWindowFocus=" + view.hasWindowFocus());
-            if (mServedView == view && view.hasWindowFocus()) {
+            if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: view=" + dumpViewInfo(view)
+                    + " mServedView=" + dumpViewInfo(mServedView));
+            if (mServedView == view) {
                 mNextServedView = null;
                 scheduleCheckFocusLocked(view);
             }
@@ -1377,18 +1373,18 @@
      * @hide
      */
     public void checkFocus() {
-        if (checkFocusNoStartInput(false, true)) {
+        if (checkFocusNoStartInput(false)) {
             startInputInner(InputMethodClient.START_INPUT_REASON_CHECK_FOCUS, null, 0, 0, 0);
         }
     }
 
-    private boolean checkFocusNoStartInput(boolean forceNewFocus, boolean finishComposingText) {
+    private boolean checkFocusNoStartInput(boolean forceNewFocus) {
         // This is called a lot, so short-circuit before locking.
         if (mServedView == mNextServedView && !forceNewFocus) {
             return false;
         }
 
-        InputConnection ic = null;
+        final ControlledInputConnectionWrapper ic;
         synchronized (mH) {
             if (mServedView == mNextServedView && !forceNewFocus) {
                 return false;
@@ -1408,7 +1404,7 @@
                 return false;
             }
 
-            ic = mServedInputConnection;
+            ic = mServedInputConnectionWrapper;
 
             mServedView = mNextServedView;
             mCurrentTextBoxAttribute = null;
@@ -1416,7 +1412,7 @@
             mServedConnecting = true;
         }
 
-        if (finishComposingText && ic != null) {
+        if (ic != null) {
             ic.finishComposingText();
         }
 
@@ -1427,6 +1423,7 @@
         try {
             mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1461,7 +1458,7 @@
             controlFlags |= CONTROL_WINDOW_FIRST;
         }
         
-        if (checkFocusNoStartInput(forceNewFocus, true)) {
+        if (checkFocusNoStartInput(forceNewFocus)) {
             // We need to restart input on the current focus view.  This
             // should be done in conjunction with telling the system service
             // about the window gaining focus, to help make the transition
@@ -1471,17 +1468,18 @@
                 return;
             }
         }
-        
+
         // For some reason we didn't do a startInput + windowFocusGain, so
         // we'll just do a window focus gain and call it a day.
         synchronized (mH) {
             try {
                 if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
-                mService.windowGainedFocus(
+                mService.startInputOrWindowGainedFocus(
                         InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
                         rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
-                        null);
+                        null, 0 /* missingMethodFlags */);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1722,7 +1720,7 @@
         try {
             mService.setInputMethod(token, id);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1739,7 +1737,7 @@
         try {
             mService.setInputMethodAndSubtype(token, id, subtype);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1759,7 +1757,7 @@
         try {
             mService.hideMySoftInput(token, flags);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
     
@@ -1780,7 +1778,7 @@
         try {
             mService.showMySoftInput(token, flags);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1986,7 +1984,7 @@
                         SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
                 mService.showInputMethodPickerFromClient(mClient, mode);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1995,7 +1993,7 @@
         try {
             mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
         } catch (RemoteException e) {
-            Log.w(TAG, "IME died: " + mCurId, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2009,7 +2007,7 @@
             try {
                 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2024,8 +2022,7 @@
             try {
                 return mService.getCurrentInputMethodSubtype();
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return null;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2042,8 +2039,7 @@
             try {
                 return mService.setCurrentInputMethodSubtype(subtype);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2077,7 +2073,7 @@
                 mLastSentUserActionNotificationSequenceNumber =
                         mNextUserActionNotificationSequenceNumber;
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2110,7 +2106,7 @@
                     }
                 }
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
             return ret;
         }
@@ -2125,8 +2121,7 @@
             try {
                 return mService.getInputMethodWindowVisibleHeight();
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return 0;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2145,8 +2140,7 @@
             try {
                 return mService.switchToLastInputMethod(imeToken);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2166,8 +2160,7 @@
             try {
                 return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2188,8 +2181,7 @@
             try {
                 return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2224,7 +2216,7 @@
             try {
                 mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2234,8 +2226,7 @@
             try {
                 return mService.getLastInputMethodSubtype();
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return null;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2262,7 +2253,7 @@
         } else {
             p.println("  mCurrentTextBoxAttribute: null");
         }
-        p.println("  mServedInputConnection=" + mServedInputConnection);
+        p.println("  mServedInputConnectionWrapper=" + mServedInputConnectionWrapper);
         p.println("  mCompletions=" + Arrays.toString(mCompletions));
         p.println("  mCursorRect=" + mCursorRect);
         p.println("  mCursorSelStart=" + mCursorSelStart
@@ -2321,4 +2312,17 @@
             }
         }
     }
+
+    private static String dumpViewInfo(@Nullable final View view) {
+        if (view == null) {
+            return "null";
+        }
+        final StringBuilder sb = new StringBuilder();
+        sb.append(view);
+        sb.append(",focus=" + view.hasFocus());
+        sb.append(",windowFocus=" + view.hasWindowFocus());
+        sb.append(",window=" + view.getWindowToken());
+        sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
+        return sb.toString();
+    }
 }
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index 471b6d4..fc17f7a 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -31,10 +31,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.Xml;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -55,7 +57,7 @@
     /**
      * The array of subtypes.
      */
-    private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<SpellCheckerSubtype>();
+    private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<>();
 
     /**
      * Constructor.
@@ -267,4 +269,22 @@
     public int describeContents() {
         return 0;
     }
+
+    /**
+     * @hide
+     */
+    public void dump(final PrintWriter pw, final String prefix) {
+        pw.println(prefix + "mId=" + mId);
+        pw.println(prefix + "mSettingsActivityName=" + mSettingsActivityName);
+        pw.println(prefix + "Service:");
+        mService.dump(new PrintWriterPrinter(pw), prefix + "  ");
+        final int N = getSubtypeCount();
+        for (int i = 0; i < N; i++) {
+            final SpellCheckerSubtype st = getSubtypeAt(i);
+            pw.println(prefix + "  " + "Subtype #" + i + ":");
+            pw.println(prefix + "    " + "locale=" + st.getLocale()
+                    + " languageTag=" + st.getLanguageTag());
+            pw.println(prefix + "    " + "extraValue=" + st.getExtraValue());
+        }
+    }
 }
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index df33698..35d3bf9 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -50,7 +50,10 @@
     private static final String TAG = SpellCheckerSubtype.class.getSimpleName();
     private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
     private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "=";
-    private static final int SUBTYPE_ID_NONE = 0;
+    /**
+     * @hide
+     */
+    public static final int SUBTYPE_ID_NONE = 0;
     private static final String SUBTYPE_LANGUAGE_TAG_NONE = "";
 
     private final int mSubtypeId;
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index 89d5d69..9434f0c 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -38,10 +38,14 @@
     WebViewProviderResponse waitForAndGetProvider();
 
     /**
-     * DevelopmentSettings uses this to notify WebViewUpdateService that a
-     * new provider has been selected by the user.
+     * DevelopmentSettings uses this to notify WebViewUpdateService that a new provider has been
+     * selected by the user. Returns the provider we end up switching to, this could be different to
+     * the one passed as argument to this method since the Dev Setting calling this method could be
+     * stale. I.e. the Dev setting could be letting the user choose uninstalled/disabled packages,
+     * it would then try to update the provider to such a package while in reality the update
+     * service would switch to another one.
      */
-    void changeProviderAndSetting(String newProvider);
+    String changeProviderAndSetting(String newProvider);
 
     /**
      * DevelopmentSettings uses this to get the current available WebView
@@ -50,7 +54,23 @@
     WebViewProviderInfo[] getValidWebViewPackages();
 
     /**
+     * Fetch all packages that could potentially implement WebView.
+     */
+    WebViewProviderInfo[] getAllWebViewPackages();
+
+    /**
      * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
      */
     String getCurrentWebViewPackageName();
+
+    /**
+     * Used by Settings to determine whether a certain package can be enabled/disabled by the user -
+     * the package should not be modifiable in this way if it is a fallback package.
+     */
+    boolean isFallbackPackage(String packageName);
+
+    /**
+     * Enable or disable the WebView package fallback mechanism.
+     */
+    void enableFallbackLogic(boolean enable);
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 647d4dc..b16508e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -32,6 +32,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.StrictMode;
@@ -288,11 +289,11 @@
  * helps Google improve WebView. Data is collected on a per-app basis for each app which has
  * instantiated a WebView. An individual app can opt out of this feature by putting the following
  * tag in its manifest:
- * </p>
  * <pre>
- * <meta-data android:name="android.webkit.WebView.MetricsOptOut"
- *            android:value="true" />
+ * &lt;meta-data android:name="android.webkit.WebView.MetricsOptOut"
+ *            android:value="true" /&gt;
  * </pre>
+ * </p>
  * <p>
  * Data will only be uploaded for a given app if the user has consented AND the app has not opted
  * out.
@@ -2622,6 +2623,16 @@
         mProvider.getViewDelegate().onFinishTemporaryDetach();
     }
 
+    @Override
+    public Handler getHandler() {
+        return mProvider.getViewDelegate().getHandler(super.getHandler());
+    }
+
+    @Override
+    public View findFocus() {
+        return mProvider.getViewDelegate().findFocus(super.findFocus());
+    }
+
     /**
      * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}.
      *
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 23af384..b6516c8 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -16,6 +16,8 @@
 
 package android.webkit;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -86,8 +88,7 @@
      */
     public void invokeDrawGlFunctor(View containerView, long nativeDrawGLFunctor,
             boolean waitForCompletion) {
-        ViewRootImpl viewRootImpl = containerView.getViewRootImpl();
-        viewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
+        ViewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
     }
 
     /**
@@ -110,6 +111,24 @@
     }
 
     /**
+     * Set the Runnable callback the DrawGlFunction functor is detached and free to be destroyed.
+     * This will replace the previous callback, if any.
+     *
+     * @param view The view to set the callback. Should be the view where onDraw inserted
+     *        DrawGLFunctor.
+     * @param callback The new callback to set on the view.
+     * @throws IllegalArgumentException if view is null.
+     * @return The previous callback on this view.
+     */
+    public Runnable setDrawGlFunctionDetachedCallback(
+        @NonNull View view, @Nullable Runnable callback) {
+        if (view == null) {
+            throw new IllegalArgumentException("View cannot be null");
+        }
+        return view.setRenderNodeDetachedCallback(callback);
+    }
+
+    /**
      * Detaches the draw GL functor.
      *
      * @param nativeDrawGLFunctor the pointer to the native functor that implements
@@ -156,7 +175,7 @@
      * Adds the WebView asset path to {@link android.content.res.AssetManager}.
      */
     public void addWebViewAssetPath(Context context) {
-        context.getAssets().addAssetPath(
+        context.getAssets().addAssetPathAsSharedLibrary(
                 WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir);
     }
 }
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index b04b4c0..0ac5731 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -102,8 +102,10 @@
     public static final int LIBLOAD_FAILED_JNI_CALL = 7;
 
     // more error codes for waiting for WebView preparation
-    public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8;
-    public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9;
+    public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 8;
+
+    // error for namespace lookup
+    public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10;
 
     private static String getWebViewPreparationErrorReason(int error) {
         switch (error) {
@@ -111,8 +113,6 @@
                 return "Time out waiting for Relro files being created";
             case LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES:
                 return "No WebView installed";
-            case LIBLOAD_WEBVIEW_BEING_REPLACED:
-                return "Time out waiting for WebView to be replaced";
             case LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN:
                 return "Crashed for unknown reason";
         }
@@ -127,90 +127,6 @@
         public MissingWebViewPackageException(Exception e) { super(e); }
     }
 
-    private static String TAG_START = "webviewproviders";
-    private static String TAG_WEBVIEW_PROVIDER = "webviewprovider";
-    private static String TAG_PACKAGE_NAME = "packageName";
-    private static String TAG_DESCRIPTION = "description";
-    // Whether or not the provider must be explicitly chosen by the user to be used.
-    private static String TAG_AVAILABILITY = "availableByDefault";
-    private static String TAG_SIGNATURE = "signature";
-
-    /**
-     * Reads all signatures at the current depth (within the current provider) from the XML parser.
-     */
-    private static String[] readSignatures(XmlResourceParser parser) throws IOException,
-            XmlPullParserException {
-        List<String> signatures = new ArrayList<String>();
-        int outerDepth = parser.getDepth();
-        while(XmlUtils.nextElementWithin(parser, outerDepth)) {
-            if (parser.getName().equals(TAG_SIGNATURE)) {
-                // Parse the value within the signature tag
-                String signature = parser.nextText();
-                signatures.add(signature);
-            } else {
-                Log.e(LOGTAG, "Found an element in a webview provider that is not a signature");
-            }
-        }
-        return signatures.toArray(new String[signatures.size()]);
-    }
-
-    /**
-     * Returns all packages declared in the framework resources as potential WebView providers.
-     * @hide
-     * */
-    public static WebViewProviderInfo[] getWebViewPackages() {
-        XmlResourceParser parser = null;
-        List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
-        try {
-            parser = AppGlobals.getInitialApplication().getResources().getXml(
-                    com.android.internal.R.xml.config_webview_packages);
-            XmlUtils.beginDocument(parser, TAG_START);
-            while(true) {
-                XmlUtils.nextElement(parser);
-                String element = parser.getName();
-                if (element == null) {
-                    break;
-                }
-                if (element.equals(TAG_WEBVIEW_PROVIDER)) {
-                    String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
-                    if (packageName == null) {
-                        throw new MissingWebViewPackageException(
-                                "WebView provider in framework resources missing package name");
-                    }
-                    String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
-                    if (description == null) {
-                        throw new MissingWebViewPackageException(
-                                "WebView provider in framework resources missing description");
-                    }
-                    String availableByDefault = parser.getAttributeValue(null, TAG_AVAILABILITY);
-                    if (availableByDefault == null) {
-                        availableByDefault = "false";
-                    }
-                    webViewProviders.add(
-                            new WebViewProviderInfo(packageName, description, availableByDefault,
-                                readSignatures(parser)));
-                }
-                else {
-                    Log.e(LOGTAG, "Found an element that is not a webview provider");
-                }
-            }
-        } catch(XmlPullParserException e) {
-            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
-        } catch(IOException e) {
-            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
-        } finally {
-            if (parser != null) parser.close();
-        }
-        return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
-    }
-
-
-    // TODO (gsennton) remove when committing webview xts test change
-    public static String getWebViewPackageName() {
-        WebViewProviderInfo[] providers = getWebViewPackages();
-        return providers[0].packageName;
-    }
-
     /**
      * @hide
      */
@@ -228,7 +144,8 @@
      * Load the native library for the given package name iff that package
      * name is the same as the one providing the webview.
      */
-    public static int loadWebViewNativeLibraryFromPackage(String packageName) {
+    public static int loadWebViewNativeLibraryFromPackage(String packageName,
+                                                          ClassLoader clazzLoader) {
         int ret = waitForProviderAndSetPackageInfo();
         if (ret != LIBLOAD_SUCCESS) {
             return ret;
@@ -236,7 +153,7 @@
         if (!sPackageInfo.packageName.equals(packageName))
             return LIBLOAD_WRONG_PACKAGE_NAME;
 
-        return loadNativeLibrary();
+        return loadNativeLibrary(clazzLoader);
     }
 
     static WebViewFactoryProvider getProvider() {
@@ -251,11 +168,11 @@
                         "For security reasons, WebView is not allowed in privileged processes");
             }
 
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
             try {
                 Class<WebViewFactoryProvider> providerClass = getProviderClass();
 
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
                 try {
                     sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
@@ -267,10 +184,10 @@
                     throw new AndroidRuntimeException(e);
                 } finally {
                     Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-                    StrictMode.setThreadPolicy(oldPolicy);
                 }
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+                StrictMode.setThreadPolicy(oldPolicy);
             }
         }
     }
@@ -322,15 +239,16 @@
                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
             }
 
-            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
-            loadNativeLibrary();
-            Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
                 initialApplication.getAssets().addAssetPathAsSharedLibrary(
                         webViewContext.getApplicationInfo().sourceDir);
                 ClassLoader clazzLoader = webViewContext.getClassLoader();
+
+                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
+                loadNativeLibrary(clazzLoader);
+                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
                 try {
                     return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
@@ -622,7 +540,7 @@
     }
 
     // Assumes that we have waited for relro creation and set sPackageInfo
-    private static int loadNativeLibrary() {
+    private static int loadNativeLibrary(ClassLoader clazzLoader) {
         if (!sAddressSpaceReserved) {
             Log.e(LOGTAG, "can't load with relro file; address space not reserved");
             return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
@@ -630,9 +548,10 @@
 
         String[] args = getWebViewNativeLibraryPaths(sPackageInfo);
         int result = nativeLoadWithRelroFile(args[0] /* path32 */,
-                                                 args[1] /* path64 */,
-                                                 CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
-                                                 CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+                                             args[1] /* path64 */,
+                                             CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+                                             CHROMIUM_WEBVIEW_NATIVE_RELRO_64,
+                                             clazzLoader);
         if (result != LIBLOAD_SUCCESS) {
             Log.w(LOGTAG, "failed to load with relro file, proceeding without");
         } else if (DEBUG) {
@@ -641,13 +560,18 @@
         return result;
     }
 
-    private static IWebViewUpdateService getUpdateService() {
-        return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
+    private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
+
+    /** @hide */
+    public static IWebViewUpdateService getUpdateService() {
+        return IWebViewUpdateService.Stub.asInterface(
+                ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
     }
 
     private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
     private static native boolean nativeCreateRelroFile(String lib32, String lib64,
                                                         String relro32, String relro64);
     private static native int nativeLoadWithRelroFile(String lib32, String lib64,
-                                                          String relro32, String relro64);
+                                                      String relro32, String relro64,
+                                                      ClassLoader clazzLoader);
 }
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 94d231c..e5b65e7 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -28,6 +28,7 @@
 import android.net.http.SslCertificate;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Message;
 import android.print.PrintDocumentAdapter;
 import android.view.DragEvent;
@@ -386,6 +387,10 @@
         public void onFinishTemporaryDetach();
 
         public void onActivityResult(int requestCode, int resultCode, Intent data);
+
+        public Handler getHandler(Handler originalHandler);
+
+        public View findFocus(View originalFocusedView);
     }
 
     interface ScrollDelegate {
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 94e8b70..5d091c9 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -16,120 +16,27 @@
 
 package android.webkit;
 
-import android.app.AppGlobals;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.os.Build;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.AndroidRuntimeException;
-import android.util.Base64;
 
 import java.util.Arrays;
 
-/** @hide */
-public class WebViewProviderInfo implements Parcelable {
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewProviderInfo implements Parcelable {
 
-    /**
-     * @hide
-     */
-    public static class WebViewPackageNotFoundException extends AndroidRuntimeException {
-        public WebViewPackageNotFoundException(String message) { super(message); }
-        public WebViewPackageNotFoundException(Exception e) { super(e); }
-    }
-
-    public WebViewProviderInfo(String packageName, String description, String availableByDefault,
-            String[] signatures) {
+    public WebViewProviderInfo(String packageName, String description,
+            boolean availableByDefault, boolean isFallback, String[] signatures) {
         this.packageName = packageName;
         this.description = description;
-        this.availableByDefault = availableByDefault.equals("true");
+        this.availableByDefault = availableByDefault;
+        this.isFallback = isFallback;
         this.signatures = signatures;
     }
 
-    private boolean hasValidSignature() {
-        if (Build.IS_DEBUGGABLE)
-            return true;
-        Signature[] packageSignatures;
-        try {
-            // If no signature is declared, instead check whether the package is included in the
-            // system.
-            if (signatures == null || signatures.length == 0)
-                return getPackageInfo().applicationInfo.isSystemApp();
-
-            packageSignatures = getPackageInfo().signatures;
-        } catch (WebViewPackageNotFoundException e) {
-            return false;
-        }
-        if (packageSignatures.length != 1)
-            return false;
-
-        final byte[] packageSignature = packageSignatures[0].toByteArray();
-        // Return whether the package signature matches any of the valid signatures
-        for (String signature : signatures) {
-            final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
-            if (Arrays.equals(packageSignature, validSignature))
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns whether this provider is valid for use as a WebView provider.
-     */
-    public boolean isValidProvider() {
-        ApplicationInfo applicationInfo;
-        try {
-            applicationInfo = getPackageInfo().applicationInfo;
-        } catch (WebViewPackageNotFoundException e) {
-            return false;
-        }
-        if (hasValidSignature() && WebViewFactory.getWebViewLibrary(applicationInfo) != null) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns whether this package is enabled.
-     * This state can be changed by the user from Settings->Apps
-     */
-    public boolean isEnabled() {
-        try {
-            // Explicitly fetch up-to-date package info here since the enabled-state of the package
-            // might have changed since we last fetched its package info.
-            updatePackageInfo();
-            return getPackageInfo().applicationInfo.enabled;
-        } catch (WebViewPackageNotFoundException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Returns whether the provider is always available as long as it is valid.
-     * If this returns false, the provider will only be used if the user chose this provider.
-     */
-    public boolean isAvailableByDefault() {
-        return availableByDefault;
-    }
-
-    private void updatePackageInfo() {
-        try {
-            PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-            packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new WebViewPackageNotFoundException(e);
-        }
-    }
-
-    public PackageInfo getPackageInfo() {
-        if (packageInfo == null) {
-            updatePackageInfo();
-        }
-        return packageInfo;
-    }
-
     // aidl stuff
     public static final Parcelable.Creator<WebViewProviderInfo> CREATOR =
         new Parcelable.Creator<WebViewProviderInfo>() {
@@ -145,8 +52,9 @@
     private WebViewProviderInfo(Parcel in) {
         packageName = in.readString();
         description = in.readString();
+        availableByDefault = (in.readInt() > 0);
+        isFallback = (in.readInt() > 0);
         signatures = in.createStringArray();
-        packageInfo = null;
     }
 
     @Override
@@ -158,19 +66,15 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(packageName);
         out.writeString(description);
+        out.writeInt(availableByDefault ? 1 : 0);
+        out.writeInt(isFallback ? 1 : 0);
         out.writeStringArray(signatures);
     }
 
     // fields read from framework resource
-    public String packageName;
-    public String description;
-    private boolean availableByDefault;
-
-    private String[] signatures;
-
-    private PackageInfo packageInfo;
-
-    // flags declaring we want extra info from the package manager
-    private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
-            | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+    public final String packageName;
+    public final String description;
+    public final boolean availableByDefault;
+    public final boolean isFallback;
+    public final String[] signatures;
 }
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
new file mode 100644
index 0000000..4e83d88
--- /dev/null
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewUpdateService {
+
+    private WebViewUpdateService () {}
+
+    /**
+     * Fetch all packages that could potentially implement WebView.
+     */
+    public static WebViewProviderInfo[] getAllWebViewPackages() {
+        try {
+            return getUpdateService().getAllWebViewPackages();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Fetch all packages that could potentially implement WebView and are currently valid.
+     */
+    public static WebViewProviderInfo[] getValidWebViewPackages() {
+        try {
+            return getUpdateService().getValidWebViewPackages();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
+     */
+    public static String getCurrentWebViewPackageName() {
+        try {
+            return getUpdateService().getCurrentWebViewPackageName();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static IWebViewUpdateService getUpdateService() {
+        return WebViewFactory.getUpdateService();
+    }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 496f7ee..6e1dff9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2864,7 +2864,7 @@
     }
 
     @Override
-    public boolean verifyDrawable(Drawable dr) {
+    public boolean verifyDrawable(@NonNull Drawable dr) {
         return mSelector == dr || super.verifyDrawable(dr);
     }
 
@@ -3078,7 +3078,8 @@
             final int motionPosition = mClickMotionPosition;
             if (adapter != null && mItemCount > 0 &&
                     motionPosition != INVALID_POSITION &&
-                    motionPosition < adapter.getCount() && sameWindow()) {
+                    motionPosition < adapter.getCount() && sameWindow() &&
+                    adapter.isEnabled(motionPosition)) {
                 final View view = getChildAt(motionPosition - mFirstPosition);
                 // If there is no view, something bad happened (the view scrolled off the
                 // screen, etc.) and we should cancel the click
@@ -5936,6 +5937,11 @@
         public Handler getHandler() {
             return getTarget().getHandler();
         }
+
+        @Override
+        public void closeConnection() {
+            getTarget().closeConnection();
+        }
     }
 
     /**
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 9a68593..878a9eb 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -485,7 +486,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return who == mThumb || who == mTickMark || super.verifyDrawable(who);
     }
 
@@ -694,7 +695,7 @@
                 final int halfH = h >= 0 ? h / 2 : 1;
                 mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
 
-                final int spacing = (getWidth() - mPaddingLeft - mPaddingRight) / count;
+                final float spacing = (getWidth() - mPaddingLeft - mPaddingRight) / (float) count;
                 final int saveCount = canvas.save();
                 canvas.translate(mPaddingLeft, getHeight() / 2);
                 for (int i = 0; i <= count; i++) {
diff --git a/core/java/android/widget/AccessibilityIterators.java b/core/java/android/widget/AccessibilityIterators.java
index a3d58a4..442ffa1 100644
--- a/core/java/android/widget/AccessibilityIterators.java
+++ b/core/java/android/widget/AccessibilityIterators.java
@@ -134,8 +134,8 @@
 
         @Override
         public int[] following(int offset) {
-            final int textLegth = mText.length();
-            if (textLegth <= 0) {
+            final int textLength = mText.length();
+            if (textLength <= 0) {
                 return null;
             }
             if (offset >= mText.length()) {
@@ -163,8 +163,8 @@
 
         @Override
         public int[] preceding(int offset) {
-            final int textLegth = mText.length();
-            if (textLegth <= 0) {
+            final int textLength = mText.length();
+            if (textLength <= 0) {
                 return null;
             }
             if (offset <= 0) {
@@ -181,8 +181,13 @@
             final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
                     - mView.getTotalPaddingBottom();
             final int previousPageEndY = currentLineTop - pageHeight;
-            final int currentPageStartLine = (previousPageEndY > 0) ?
-                     mLayout.getLineForVertical(previousPageEndY) + 1 : 0;
+            int currentPageStartLine = (previousPageEndY > 0) ?
+                     mLayout.getLineForVertical(previousPageEndY) : 0;
+            // If we're at the end of text, we're at the end of the current line rather than the
+            // start of the next line, so we should move up one fewer lines than we would otherwise.
+            if (end == mText.length() && (currentPageStartLine < currentLine)) {
+                currentPageStartLine += 1;
+            }
 
             final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START);
 
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 027f6d6..9d228cf 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -20,6 +20,7 @@
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.Log;
@@ -61,17 +62,13 @@
 
     private final LayoutInflater mInflater;
 
-    /**
-     * Contains the list of objects that represent the data of this ArrayAdapter.
-     * The content of this list is referred to as "the array" in the documentation.
-     */
-    private List<T> mObjects;
+    private final Context mContext;
 
     /**
      * The resource indicating what views to inflate to display the content of this
      * array adapter.
      */
-    private int mResource;
+    private final int mResource;
 
     /**
      * The resource indicating what views to inflate to display the content of this
@@ -80,7 +77,13 @@
     private int mDropDownResource;
 
     /**
-     * If the inflated resource is not a TextView, {@link #mFieldId} is used to find
+     * Contains the list of objects that represent the data of this ArrayAdapter.
+     * The content of this list is referred to as "the array" in the documentation.
+     */
+    private List<T> mObjects;
+
+    /**
+     * If the inflated resource is not a TextView, {@code mFieldId} is used to find
      * a TextView inside the inflated views hierarchy. This field must contain the
      * identifier that matches the one defined in the resource file.
      */
@@ -92,8 +95,6 @@
      */
     private boolean mNotifyOnChange = true;
 
-    private Context mContext;
-
     // A copy of the original mObjects array, initialized from and then used instead as soon as
     // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
     private ArrayList<T> mOriginalValues;
@@ -109,8 +110,8 @@
      * @param resource The resource ID for a layout file containing a TextView to use when
      *                 instantiating views.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource) {
-        this(context, resource, 0, new ArrayList<T>());
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource) {
+        this(context, resource, 0, new ArrayList<>());
     }
 
     /**
@@ -121,8 +122,9 @@
      *                 instantiating views.
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {
-        this(context, resource, textViewResourceId, new ArrayList<T>());
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @IdRes int textViewResourceId) {
+        this(context, resource, textViewResourceId, new ArrayList<>());
     }
 
     /**
@@ -133,7 +135,7 @@
      *                 instantiating views.
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull T[] objects) {
         this(context, resource, 0, Arrays.asList(objects));
     }
 
@@ -146,8 +148,8 @@
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
-            @NonNull T[] objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @IdRes int textViewResourceId, @NonNull T[] objects) {
         this(context, resource, textViewResourceId, Arrays.asList(objects));
     }
 
@@ -159,7 +161,8 @@
      *                 instantiating views.
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @NonNull List<T> objects) {
         this(context, resource, 0, objects);
     }
 
@@ -172,8 +175,8 @@
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
-            @NonNull List<T> objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @IdRes int textViewResourceId, @NonNull List<T> objects) {
         mContext = context;
         mInflater = LayoutInflater.from(context);
         mResource = mDropDownResource = resource;
@@ -186,7 +189,7 @@
      *
      * @param object The object to add at the end of the array.
      */
-    public void add(T object) {
+    public void add(@Nullable T object) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.add(object);
@@ -201,8 +204,17 @@
      * Adds the specified Collection at the end of the array.
      *
      * @param collection The Collection to add at the end of the array.
+     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
      */
-    public void addAll(Collection<? extends T> collection) {
+    public void addAll(@NonNull Collection<? extends T> collection) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.addAll(collection);
@@ -235,7 +247,7 @@
      * @param object The object to insert into the array.
      * @param index The index at which the object must be inserted.
      */
-    public void insert(T object, int index) {
+    public void insert(@Nullable T object, int index) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.add(index, object);
@@ -251,7 +263,7 @@
      *
      * @param object The object to remove.
      */
-    public void remove(T object) {
+    public void remove(@Nullable T object) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.remove(object);
@@ -282,7 +294,7 @@
      * @param comparator The comparator used to sort the objects contained
      *        in this adapter.
      */
-    public void sort(Comparator<? super T> comparator) {
+    public void sort(@NonNull Comparator<? super T> comparator) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 Collections.sort(mOriginalValues, comparator);
@@ -293,9 +305,6 @@
         if (mNotifyOnChange) notifyDataSetChanged();
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void notifyDataSetChanged() {
         super.notifyDataSetChanged();
@@ -326,21 +335,17 @@
      *
      * @return The Context associated with this adapter.
      */
-    public Context getContext() {
+    public @NonNull Context getContext() {
         return mContext;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public int getCount() {
         return mObjects.size();
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public T getItem(int position) {
+    @Override
+    public @Nullable T getItem(int position) {
         return mObjects.get(position);
     }
 
@@ -351,28 +356,25 @@
      *
      * @return The position of the specified item.
      */
-    public int getPosition(T item) {
+    public int getPosition(@Nullable T item) {
         return mObjects.indexOf(item);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public long getItemId(int position) {
         return position;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public View getView(int position, View convertView, ViewGroup parent) {
+    @Override
+    public @NonNull View getView(int position, @Nullable View convertView,
+            @NonNull ViewGroup parent) {
         return createViewFromResource(mInflater, position, convertView, parent, mResource);
     }
 
-    private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
-            ViewGroup parent, int resource) {
-        View view;
-        TextView text;
+    private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,
+            @Nullable View convertView, @NonNull ViewGroup parent, int resource) {
+        final View view;
+        final TextView text;
 
         if (convertView == null) {
             view = inflater.inflate(resource, parent, false);
@@ -387,6 +389,12 @@
             } else {
                 //  Otherwise, find the TextView field within the layout
                 text = (TextView) view.findViewById(mFieldId);
+
+                if (text == null) {
+                    throw new RuntimeException("Failed to find view with ID "
+                            + mContext.getResources().getResourceName(mFieldId)
+                            + " in item layout");
+                }
             }
         } catch (ClassCastException e) {
             Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
@@ -394,9 +402,9 @@
                     "ArrayAdapter requires the resource ID to be a TextView", e);
         }
 
-        T item = getItem(position);
+        final T item = getItem(position);
         if (item instanceof CharSequence) {
-            text.setText((CharSequence)item);
+            text.setText((CharSequence) item);
         } else {
             text.setText(item.toString());
         }
@@ -426,7 +434,7 @@
      * @see #getDropDownView(int, View, ViewGroup)
      */
     @Override
-    public void setDropDownViewTheme(Resources.Theme theme) {
+    public void setDropDownViewTheme(@Nullable Resources.Theme theme) {
         if (theme == null) {
             mDropDownInflater = null;
         } else if (theme == mInflater.getContext().getTheme()) {
@@ -438,12 +446,13 @@
     }
 
     @Override
-    public Resources.Theme getDropDownViewTheme() {
+    public @Nullable Resources.Theme getDropDownViewTheme() {
         return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
     }
 
     @Override
-    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+    public View getDropDownView(int position, @Nullable View convertView,
+            @NonNull ViewGroup parent) {
         final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
         return createViewFromResource(inflater, position, convertView, parent, mDropDownResource);
     }
@@ -458,16 +467,14 @@
      *
      * @return An ArrayAdapter<CharSequence>.
      */
-    public static ArrayAdapter<CharSequence> createFromResource(Context context,
+    public static @NonNull ArrayAdapter<CharSequence> createFromResource(@NonNull Context context,
             @ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
-        CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
-        return new ArrayAdapter<CharSequence>(context, textViewResId, strings);
+        final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
+        return new ArrayAdapter<>(context, textViewResId, strings);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public Filter getFilter() {
+    @Override
+    public @NonNull Filter getFilter() {
         if (mFilter == null) {
             mFilter = new ArrayFilter();
         }
@@ -482,31 +489,31 @@
     private class ArrayFilter extends Filter {
         @Override
         protected FilterResults performFiltering(CharSequence prefix) {
-            FilterResults results = new FilterResults();
+            final FilterResults results = new FilterResults();
 
             if (mOriginalValues == null) {
                 synchronized (mLock) {
-                    mOriginalValues = new ArrayList<T>(mObjects);
+                    mOriginalValues = new ArrayList<>(mObjects);
                 }
             }
 
             if (prefix == null || prefix.length() == 0) {
-                ArrayList<T> list;
+                final ArrayList<T> list;
                 synchronized (mLock) {
-                    list = new ArrayList<T>(mOriginalValues);
+                    list = new ArrayList<>(mOriginalValues);
                 }
                 results.values = list;
                 results.count = list.size();
             } else {
-                String prefixString = prefix.toString().toLowerCase();
+                final String prefixString = prefix.toString().toLowerCase();
 
-                ArrayList<T> values;
+                final ArrayList<T> values;
                 synchronized (mLock) {
-                    values = new ArrayList<T>(mOriginalValues);
+                    values = new ArrayList<>(mOriginalValues);
                 }
 
                 final int count = values.size();
-                final ArrayList<T> newValues = new ArrayList<T>();
+                final ArrayList<T> newValues = new ArrayList<>();
 
                 for (int i = 0; i < count; i++) {
                     final T value = values.get(i);
@@ -517,11 +524,8 @@
                         newValues.add(value);
                     } else {
                         final String[] words = valueText.split(" ");
-                        final int wordCount = words.length;
-
-                        // Start at index 0, in case valueText starts with space(s)
-                        for (int k = 0; k < wordCount; k++) {
-                            if (words[k].startsWith(prefixString)) {
+                        for (String word : words) {
+                            if (word.startsWith(prefixString)) {
                                 newValues.add(value);
                                 break;
                             }
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 7d57cb8..6a4e36a 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1116,7 +1116,7 @@
     protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(focused, direction, previouslyFocusedRect);
 
-        if (mTemporaryDetach) {
+        if (isTemporarilyDetached()) {
             // If we are temporarily in the detach state, then do nothing.
             return;
         }
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index cde7604..66896ab 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -430,9 +430,11 @@
      * Sets whether to show the week number.
      *
      * @param showWeekNumber True to show the week number.
+     * @deprecated No longer used by Material-style CalendarView.
      *
      * @attr ref android.R.styleable#CalendarView_showWeekNumber
      */
+    @Deprecated
     public void setShowWeekNumber(boolean showWeekNumber) {
         mDelegate.setShowWeekNumber(showWeekNumber);
     }
@@ -441,9 +443,11 @@
      * Gets whether to show the week number.
      *
      * @return True if showing the week number.
+     * @deprecated No longer used by Material-style CalendarView.
      *
      * @attr ref android.R.styleable#CalendarView_showWeekNumber
      */
+    @Deprecated
     public boolean getShowWeekNumber() {
         return mDelegate.getShowWeekNumber();
     }
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
index 442fb33..f540479 100644
--- a/core/java/android/widget/CalendarViewLegacyDelegate.java
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -404,7 +404,7 @@
 
     @Override
     public int getUnfocusedMonthDateColor() {
-        return mFocusedMonthDateColor;
+        return mUnfocusedMonthDateColor;
     }
 
     @Override
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 9f94005..df506ca 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -308,7 +308,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return who == mCheckMarkDrawable || super.verifyDrawable(who);
     }
 
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 4d707e3..3421790 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -19,15 +19,14 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.os.Handler;
-import android.os.Message;
 import android.os.SystemClock;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.R;
+
 import java.util.Formatter;
 import java.util.IllegalFormatException;
 import java.util.Locale;
@@ -37,11 +36,17 @@
  * <p>
  * You can give it a start time in the {@link SystemClock#elapsedRealtime} timebase,
  * and it counts up from that, or if you don't give it a base time, it will use the
- * time at which you call {@link #start}.  By default it will display the current
+ * time at which you call {@link #start}.
+ *
+ * <p>The timer can also count downward towards the base time by
+ * setting {@link #setCountDown(boolean)} to true.
+ *
+ *  <p>By default it will display the current
  * timer value in the form "MM:SS" or "H:MM:SS", or you can use {@link #setFormat}
  * to format the timer value into an arbitrary string.
  *
  * @attr ref android.R.styleable#Chronometer_format
+ * @attr ref android.R.styleable#Chronometer_countDown
  */
 @RemoteView
 public class Chronometer extends TextView {
@@ -72,6 +77,7 @@
     private StringBuilder mFormatBuilder;
     private OnChronometerTickListener mOnChronometerTickListener;
     private StringBuilder mRecycle = new StringBuilder(8);
+    private boolean mCountDown;
     
     /**
      * Initialize this Chronometer object.
@@ -102,7 +108,8 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.Chronometer, defStyleAttr, defStyleRes);
-        setFormat(a.getString(com.android.internal.R.styleable.Chronometer_format));
+        setFormat(a.getString(R.styleable.Chronometer_format));
+        setCountDown(a.getBoolean(R.styleable.Chronometer_countDown, false));
         a.recycle();
 
         init();
@@ -114,6 +121,27 @@
     }
 
     /**
+     * Set this view to count down to the base instead of counting up from it.
+     *
+     * @param countDown whether this view should count down
+     *
+     * @see #setBase(long)
+     */
+    @android.view.RemotableViewMethod
+    public void setCountDown(boolean countDown) {
+        mCountDown = countDown;
+    }
+
+    /**
+     * @return whether this view counts down
+     *
+     * @see #setCountDown(boolean)
+     */
+    public boolean isCountDown() {
+        return mCountDown;
+    }
+
+    /**
      * Set the time that the count-up timer is in reference to.
      *
      * @param base Use the {@link SystemClock#elapsedRealtime} time base.
@@ -226,9 +254,17 @@
 
     private synchronized void updateText(long now) {
         mNow = now;
-        long seconds = now - mBase;
+        long seconds = mCountDown ? mBase - now : now - mBase;
         seconds /= 1000;
+        boolean negative = false;
+        if (seconds < 0) {
+            seconds = -seconds;
+            negative = true;
+        }
         String text = DateUtils.formatElapsedTime(mRecycle, seconds);
+        if (negative) {
+            text = getResources().getString(R.string.negative_duration, text);
+        }
 
         if (mFormat != null) {
             Locale loc = Locale.getDefault();
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index b19fe17..5d7585f 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -474,7 +474,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return super.verifyDrawable(who) || who == mButtonDrawable;
     }
 
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 87bee44..e3357a7 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -23,32 +23,17 @@
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
-import android.text.InputType;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.SparseArray;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.NumberPicker.OnValueChangeListener;
 
 import com.android.internal.R;
 
-import java.text.DateFormatSymbols;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Locale;
 import java.util.TimeZone;
 
-import libcore.icu.ICU;
-
 /**
  * Provides a widget for selecting a date.
  * <p>
@@ -90,8 +75,6 @@
  */
 @Widget
 public class DatePicker extends FrameLayout {
-    private static final String LOG_TAG = DatePicker.class.getSimpleName();
-
     private static final int MODE_SPINNER = 1;
     private static final int MODE_CALENDAR = 2;
 
@@ -527,6 +510,114 @@
         protected void onLocaleChanged(Locale locale) {
             // Stub.
         }
+
+        /**
+         * Class for managing state storing/restoring.
+         */
+        static class SavedState extends View.BaseSavedState {
+            private final int mSelectedYear;
+            private final int mSelectedMonth;
+            private final int mSelectedDay;
+            private final long mMinDate;
+            private final long mMaxDate;
+            private final int mCurrentView;
+            private final int mListPosition;
+            private final int mListPositionOffset;
+
+            public SavedState(Parcelable superState, int year, int month, int day, long minDate,
+                    long maxDate) {
+                this(superState, year, month, day, minDate, maxDate, 0, 0, 0);
+            }
+
+            /**
+             * Constructor called from {@link DatePicker#onSaveInstanceState()}
+             */
+            public SavedState(Parcelable superState, int year, int month, int day, long minDate,
+                    long maxDate, int currentView, int listPosition, int listPositionOffset) {
+                super(superState);
+                mSelectedYear = year;
+                mSelectedMonth = month;
+                mSelectedDay = day;
+                mMinDate = minDate;
+                mMaxDate = maxDate;
+                mCurrentView = currentView;
+                mListPosition = listPosition;
+                mListPositionOffset = listPositionOffset;
+            }
+
+            /**
+             * Constructor called from {@link #CREATOR}
+             */
+            private SavedState(Parcel in) {
+                super(in);
+                mSelectedYear = in.readInt();
+                mSelectedMonth = in.readInt();
+                mSelectedDay = in.readInt();
+                mMinDate = in.readLong();
+                mMaxDate = in.readLong();
+                mCurrentView = in.readInt();
+                mListPosition = in.readInt();
+                mListPositionOffset = in.readInt();
+            }
+
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {
+                super.writeToParcel(dest, flags);
+                dest.writeInt(mSelectedYear);
+                dest.writeInt(mSelectedMonth);
+                dest.writeInt(mSelectedDay);
+                dest.writeLong(mMinDate);
+                dest.writeLong(mMaxDate);
+                dest.writeInt(mCurrentView);
+                dest.writeInt(mListPosition);
+                dest.writeInt(mListPositionOffset);
+            }
+
+            public int getSelectedDay() {
+                return mSelectedDay;
+            }
+
+            public int getSelectedMonth() {
+                return mSelectedMonth;
+            }
+
+            public int getSelectedYear() {
+                return mSelectedYear;
+            }
+
+            public long getMinDate() {
+                return mMinDate;
+            }
+
+            public long getMaxDate() {
+                return mMaxDate;
+            }
+
+            public int getCurrentView() {
+                return mCurrentView;
+            }
+
+            public int getListPosition() {
+                return mListPosition;
+            }
+
+            public int getListPositionOffset() {
+                return mListPositionOffset;
+            }
+
+            @SuppressWarnings("all")
+            // suppress unused and hiding
+            public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
+
+                public SavedState createFromParcel(Parcel in) {
+                    return new SavedState(in);
+                }
+
+                public SavedState[] newArray(int size) {
+                    return new SavedState[size];
+                }
+            };
+        }
     }
 
     /**
@@ -535,666 +626,7 @@
      *
      * @hide
      */
-    public static interface ValidationCallback {
+    public interface ValidationCallback {
         void onValidationChanged(boolean valid);
     }
-
-    /**
-     * A delegate implementing the basic DatePicker
-     */
-    private static class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
-
-        private static final String DATE_FORMAT = "MM/dd/yyyy";
-
-        private static final int DEFAULT_START_YEAR = 1900;
-
-        private static final int DEFAULT_END_YEAR = 2100;
-
-        private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
-
-        private static final boolean DEFAULT_SPINNERS_SHOWN = true;
-
-        private static final boolean DEFAULT_ENABLED_STATE = true;
-
-        private final LinearLayout mSpinners;
-
-        private final NumberPicker mDaySpinner;
-
-        private final NumberPicker mMonthSpinner;
-
-        private final NumberPicker mYearSpinner;
-
-        private final EditText mDaySpinnerInput;
-
-        private final EditText mMonthSpinnerInput;
-
-        private final EditText mYearSpinnerInput;
-
-        private final CalendarView mCalendarView;
-
-        private String[] mShortMonths;
-
-        private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
-
-        private int mNumberOfMonths;
-
-        private Calendar mTempDate;
-
-        private Calendar mMinDate;
-
-        private Calendar mMaxDate;
-
-        private Calendar mCurrentDate;
-
-        private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
-
-        DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
-                int defStyleAttr, int defStyleRes) {
-            super(delegator, context);
-
-            mDelegator = delegator;
-            mContext = context;
-
-            // initialization based on locale
-            setCurrentLocale(Locale.getDefault());
-
-            final TypedArray attributesArray = context.obtainStyledAttributes(attrs,
-                    R.styleable.DatePicker, defStyleAttr, defStyleRes);
-            boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
-                    DEFAULT_SPINNERS_SHOWN);
-            boolean calendarViewShown = attributesArray.getBoolean(
-                    R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
-            int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear,
-                    DEFAULT_START_YEAR);
-            int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
-            String minDate = attributesArray.getString(R.styleable.DatePicker_minDate);
-            String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate);
-            int layoutResourceId = attributesArray.getResourceId(
-                    R.styleable.DatePicker_legacyLayout, R.layout.date_picker_legacy);
-            attributesArray.recycle();
-
-            LayoutInflater inflater = (LayoutInflater) context
-                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            inflater.inflate(layoutResourceId, mDelegator, true);
-
-            OnValueChangeListener onChangeListener = new OnValueChangeListener() {
-                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
-                    updateInputState();
-                    mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
-                    // take care of wrapping of days and months to update greater fields
-                    if (picker == mDaySpinner) {
-                        int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
-                        if (oldVal == maxDayOfMonth && newVal == 1) {
-                            mTempDate.add(Calendar.DAY_OF_MONTH, 1);
-                        } else if (oldVal == 1 && newVal == maxDayOfMonth) {
-                            mTempDate.add(Calendar.DAY_OF_MONTH, -1);
-                        } else {
-                            mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
-                        }
-                    } else if (picker == mMonthSpinner) {
-                        if (oldVal == 11 && newVal == 0) {
-                            mTempDate.add(Calendar.MONTH, 1);
-                        } else if (oldVal == 0 && newVal == 11) {
-                            mTempDate.add(Calendar.MONTH, -1);
-                        } else {
-                            mTempDate.add(Calendar.MONTH, newVal - oldVal);
-                        }
-                    } else if (picker == mYearSpinner) {
-                        mTempDate.set(Calendar.YEAR, newVal);
-                    } else {
-                        throw new IllegalArgumentException();
-                    }
-                    // now set the date to the adjusted one
-                    setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
-                            mTempDate.get(Calendar.DAY_OF_MONTH));
-                    updateSpinners();
-                    updateCalendarView();
-                    notifyDateChanged();
-                }
-            };
-
-            mSpinners = (LinearLayout) mDelegator.findViewById(R.id.pickers);
-
-            // calendar view day-picker
-            mCalendarView = (CalendarView) mDelegator.findViewById(R.id.calendar_view);
-            mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
-                public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
-                    setDate(year, month, monthDay);
-                    updateSpinners();
-                    notifyDateChanged();
-                }
-            });
-
-            // day
-            mDaySpinner = (NumberPicker) mDelegator.findViewById(R.id.day);
-            mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
-            mDaySpinner.setOnLongPressUpdateInterval(100);
-            mDaySpinner.setOnValueChangedListener(onChangeListener);
-            mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input);
-
-            // month
-            mMonthSpinner = (NumberPicker) mDelegator.findViewById(R.id.month);
-            mMonthSpinner.setMinValue(0);
-            mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
-            mMonthSpinner.setDisplayedValues(mShortMonths);
-            mMonthSpinner.setOnLongPressUpdateInterval(200);
-            mMonthSpinner.setOnValueChangedListener(onChangeListener);
-            mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(R.id.numberpicker_input);
-
-            // year
-            mYearSpinner = (NumberPicker) mDelegator.findViewById(R.id.year);
-            mYearSpinner.setOnLongPressUpdateInterval(100);
-            mYearSpinner.setOnValueChangedListener(onChangeListener);
-            mYearSpinnerInput = (EditText) mYearSpinner.findViewById(R.id.numberpicker_input);
-
-            // show only what the user required but make sure we
-            // show something and the spinners have higher priority
-            if (!spinnersShown && !calendarViewShown) {
-                setSpinnersShown(true);
-            } else {
-                setSpinnersShown(spinnersShown);
-                setCalendarViewShown(calendarViewShown);
-            }
-
-            // set the min date giving priority of the minDate over startYear
-            mTempDate.clear();
-            if (!TextUtils.isEmpty(minDate)) {
-                if (!parseDate(minDate, mTempDate)) {
-                    mTempDate.set(startYear, 0, 1);
-                }
-            } else {
-                mTempDate.set(startYear, 0, 1);
-            }
-            setMinDate(mTempDate.getTimeInMillis());
-
-            // set the max date giving priority of the maxDate over endYear
-            mTempDate.clear();
-            if (!TextUtils.isEmpty(maxDate)) {
-                if (!parseDate(maxDate, mTempDate)) {
-                    mTempDate.set(endYear, 11, 31);
-                }
-            } else {
-                mTempDate.set(endYear, 11, 31);
-            }
-            setMaxDate(mTempDate.getTimeInMillis());
-
-            // initialize to current date
-            mCurrentDate.setTimeInMillis(System.currentTimeMillis());
-            init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
-                    .get(Calendar.DAY_OF_MONTH), null);
-
-            // re-order the number spinners to match the current date format
-            reorderSpinners();
-
-            // accessibility
-            setContentDescriptions();
-
-            // If not explicitly specified this view is important for accessibility.
-            if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-                mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
-            }
-        }
-
-        @Override
-        public void init(int year, int monthOfYear, int dayOfMonth,
-                         OnDateChangedListener onDateChangedListener) {
-            setDate(year, monthOfYear, dayOfMonth);
-            updateSpinners();
-            updateCalendarView();
-            mOnDateChangedListener = onDateChangedListener;
-        }
-
-        @Override
-        public void updateDate(int year, int month, int dayOfMonth) {
-            if (!isNewDate(year, month, dayOfMonth)) {
-                return;
-            }
-            setDate(year, month, dayOfMonth);
-            updateSpinners();
-            updateCalendarView();
-            notifyDateChanged();
-        }
-
-        @Override
-        public int getYear() {
-            return mCurrentDate.get(Calendar.YEAR);
-        }
-
-        @Override
-        public int getMonth() {
-            return mCurrentDate.get(Calendar.MONTH);
-        }
-
-        @Override
-        public int getDayOfMonth() {
-            return mCurrentDate.get(Calendar.DAY_OF_MONTH);
-        }
-
-        @Override
-        public void setFirstDayOfWeek(int firstDayOfWeek) {
-            mCalendarView.setFirstDayOfWeek(firstDayOfWeek);
-        }
-
-        @Override
-        public int getFirstDayOfWeek() {
-            return mCalendarView.getFirstDayOfWeek();
-        }
-
-        @Override
-        public void setMinDate(long minDate) {
-            mTempDate.setTimeInMillis(minDate);
-            if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
-                    && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
-                return;
-            }
-            mMinDate.setTimeInMillis(minDate);
-            mCalendarView.setMinDate(minDate);
-            if (mCurrentDate.before(mMinDate)) {
-                mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
-                updateCalendarView();
-            }
-            updateSpinners();
-        }
-
-        @Override
-        public Calendar getMinDate() {
-            final Calendar minDate = Calendar.getInstance();
-            minDate.setTimeInMillis(mCalendarView.getMinDate());
-            return minDate;
-        }
-
-        @Override
-        public void setMaxDate(long maxDate) {
-            mTempDate.setTimeInMillis(maxDate);
-            if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
-                    && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
-                return;
-            }
-            mMaxDate.setTimeInMillis(maxDate);
-            mCalendarView.setMaxDate(maxDate);
-            if (mCurrentDate.after(mMaxDate)) {
-                mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
-                updateCalendarView();
-            }
-            updateSpinners();
-        }
-
-        @Override
-        public Calendar getMaxDate() {
-            final Calendar maxDate = Calendar.getInstance();
-            maxDate.setTimeInMillis(mCalendarView.getMaxDate());
-            return maxDate;
-        }
-
-        @Override
-        public void setEnabled(boolean enabled) {
-            mDaySpinner.setEnabled(enabled);
-            mMonthSpinner.setEnabled(enabled);
-            mYearSpinner.setEnabled(enabled);
-            mCalendarView.setEnabled(enabled);
-            mIsEnabled = enabled;
-        }
-
-        @Override
-        public boolean isEnabled() {
-            return mIsEnabled;
-        }
-
-        @Override
-        public CalendarView getCalendarView() {
-            return mCalendarView;
-        }
-
-        @Override
-        public void setCalendarViewShown(boolean shown) {
-            mCalendarView.setVisibility(shown ? VISIBLE : GONE);
-        }
-
-        @Override
-        public boolean getCalendarViewShown() {
-            return (mCalendarView.getVisibility() == View.VISIBLE);
-        }
-
-        @Override
-        public void setSpinnersShown(boolean shown) {
-            mSpinners.setVisibility(shown ? VISIBLE : GONE);
-        }
-
-        @Override
-        public boolean getSpinnersShown() {
-            return mSpinners.isShown();
-        }
-
-        @Override
-        public void onConfigurationChanged(Configuration newConfig) {
-            setCurrentLocale(newConfig.locale);
-        }
-
-        @Override
-        public Parcelable onSaveInstanceState(Parcelable superState) {
-            return new SavedState(superState, getYear(), getMonth(), getDayOfMonth());
-        }
-
-        @Override
-        public void onRestoreInstanceState(Parcelable state) {
-            SavedState ss = (SavedState) state;
-            setDate(ss.mYear, ss.mMonth, ss.mDay);
-            updateSpinners();
-            updateCalendarView();
-        }
-
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-            onPopulateAccessibilityEvent(event);
-            return true;
-        }
-
-        @Override
-        public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-            final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
-            String selectedDateUtterance = DateUtils.formatDateTime(mContext,
-                    mCurrentDate.getTimeInMillis(), flags);
-            event.getText().add(selectedDateUtterance);
-        }
-
-        /**
-         * Sets the current locale.
-         *
-         * @param locale The current locale.
-         */
-        @Override
-        protected void setCurrentLocale(Locale locale) {
-            super.setCurrentLocale(locale);
-
-            mTempDate = getCalendarForLocale(mTempDate, locale);
-            mMinDate = getCalendarForLocale(mMinDate, locale);
-            mMaxDate = getCalendarForLocale(mMaxDate, locale);
-            mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
-
-            mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
-            mShortMonths = new DateFormatSymbols().getShortMonths();
-
-            if (usingNumericMonths()) {
-                // We're in a locale where a date should either be all-numeric, or all-text.
-                // All-text would require custom NumberPicker formatters for day and year.
-                mShortMonths = new String[mNumberOfMonths];
-                for (int i = 0; i < mNumberOfMonths; ++i) {
-                    mShortMonths[i] = String.format("%d", i + 1);
-                }
-            }
-        }
-
-        /**
-         * Tests whether the current locale is one where there are no real month names,
-         * such as Chinese, Japanese, or Korean locales.
-         */
-        private boolean usingNumericMonths() {
-            return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0));
-        }
-
-        /**
-         * Gets a calendar for locale bootstrapped with the value of a given calendar.
-         *
-         * @param oldCalendar The old calendar.
-         * @param locale The locale.
-         */
-        private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
-            if (oldCalendar == null) {
-                return Calendar.getInstance(locale);
-            } else {
-                final long currentTimeMillis = oldCalendar.getTimeInMillis();
-                Calendar newCalendar = Calendar.getInstance(locale);
-                newCalendar.setTimeInMillis(currentTimeMillis);
-                return newCalendar;
-            }
-        }
-
-        /**
-         * Reorders the spinners according to the date format that is
-         * explicitly set by the user and if no such is set fall back
-         * to the current locale's default format.
-         */
-        private void reorderSpinners() {
-            mSpinners.removeAllViews();
-            // We use numeric spinners for year and day, but textual months. Ask icu4c what
-            // order the user's locale uses for that combination. http://b/7207103.
-            String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyyMMMdd");
-            char[] order = ICU.getDateFormatOrder(pattern);
-            final int spinnerCount = order.length;
-            for (int i = 0; i < spinnerCount; i++) {
-                switch (order[i]) {
-                    case 'd':
-                        mSpinners.addView(mDaySpinner);
-                        setImeOptions(mDaySpinner, spinnerCount, i);
-                        break;
-                    case 'M':
-                        mSpinners.addView(mMonthSpinner);
-                        setImeOptions(mMonthSpinner, spinnerCount, i);
-                        break;
-                    case 'y':
-                        mSpinners.addView(mYearSpinner);
-                        setImeOptions(mYearSpinner, spinnerCount, i);
-                        break;
-                    default:
-                        throw new IllegalArgumentException(Arrays.toString(order));
-                }
-            }
-        }
-
-        /**
-         * Parses the given <code>date</code> and in case of success sets the result
-         * to the <code>outDate</code>.
-         *
-         * @return True if the date was parsed.
-         */
-        private boolean parseDate(String date, Calendar outDate) {
-            try {
-                outDate.setTime(mDateFormat.parse(date));
-                return true;
-            } catch (ParseException e) {
-                Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
-                return false;
-            }
-        }
-
-        private boolean isNewDate(int year, int month, int dayOfMonth) {
-            return (mCurrentDate.get(Calendar.YEAR) != year
-                    || mCurrentDate.get(Calendar.MONTH) != month
-                    || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth);
-        }
-
-        private void setDate(int year, int month, int dayOfMonth) {
-            mCurrentDate.set(year, month, dayOfMonth);
-            if (mCurrentDate.before(mMinDate)) {
-                mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
-            } else if (mCurrentDate.after(mMaxDate)) {
-                mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
-            }
-        }
-
-        private void updateSpinners() {
-            // set the spinner ranges respecting the min and max dates
-            if (mCurrentDate.equals(mMinDate)) {
-                mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setWrapSelectorWheel(false);
-                mMonthSpinner.setDisplayedValues(null);
-                mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
-                mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
-                mMonthSpinner.setWrapSelectorWheel(false);
-            } else if (mCurrentDate.equals(mMaxDate)) {
-                mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setWrapSelectorWheel(false);
-                mMonthSpinner.setDisplayedValues(null);
-                mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
-                mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
-                mMonthSpinner.setWrapSelectorWheel(false);
-            } else {
-                mDaySpinner.setMinValue(1);
-                mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setWrapSelectorWheel(true);
-                mMonthSpinner.setDisplayedValues(null);
-                mMonthSpinner.setMinValue(0);
-                mMonthSpinner.setMaxValue(11);
-                mMonthSpinner.setWrapSelectorWheel(true);
-            }
-
-            // make sure the month names are a zero based array
-            // with the months in the month spinner
-            String[] displayedValues = Arrays.copyOfRange(mShortMonths,
-                    mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
-            mMonthSpinner.setDisplayedValues(displayedValues);
-
-            // year spinner range does not change based on the current date
-            mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
-            mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
-            mYearSpinner.setWrapSelectorWheel(false);
-
-            // set the spinner values
-            mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
-            mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
-            mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
-
-            if (usingNumericMonths()) {
-                mMonthSpinnerInput.setRawInputType(InputType.TYPE_CLASS_NUMBER);
-            }
-        }
-
-        /**
-         * Updates the calendar view with the current date.
-         */
-        private void updateCalendarView() {
-            mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
-        }
-
-
-        /**
-         * Notifies the listener, if such, for a change in the selected date.
-         */
-        private void notifyDateChanged() {
-            mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-            if (mOnDateChangedListener != null) {
-                mOnDateChangedListener.onDateChanged(mDelegator, getYear(), getMonth(),
-                        getDayOfMonth());
-            }
-        }
-
-        /**
-         * Sets the IME options for a spinner based on its ordering.
-         *
-         * @param spinner The spinner.
-         * @param spinnerCount The total spinner count.
-         * @param spinnerIndex The index of the given spinner.
-         */
-        private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
-            final int imeOptions;
-            if (spinnerIndex < spinnerCount - 1) {
-                imeOptions = EditorInfo.IME_ACTION_NEXT;
-            } else {
-                imeOptions = EditorInfo.IME_ACTION_DONE;
-            }
-            TextView input = (TextView) spinner.findViewById(R.id.numberpicker_input);
-            input.setImeOptions(imeOptions);
-        }
-
-        private void setContentDescriptions() {
-            // Day
-            trySetContentDescription(mDaySpinner, R.id.increment,
-                    R.string.date_picker_increment_day_button);
-            trySetContentDescription(mDaySpinner, R.id.decrement,
-                    R.string.date_picker_decrement_day_button);
-            // Month
-            trySetContentDescription(mMonthSpinner, R.id.increment,
-                    R.string.date_picker_increment_month_button);
-            trySetContentDescription(mMonthSpinner, R.id.decrement,
-                    R.string.date_picker_decrement_month_button);
-            // Year
-            trySetContentDescription(mYearSpinner, R.id.increment,
-                    R.string.date_picker_increment_year_button);
-            trySetContentDescription(mYearSpinner, R.id.decrement,
-                    R.string.date_picker_decrement_year_button);
-        }
-
-        private void trySetContentDescription(View root, int viewId, int contDescResId) {
-            View target = root.findViewById(viewId);
-            if (target != null) {
-                target.setContentDescription(mContext.getString(contDescResId));
-            }
-        }
-
-        private void updateInputState() {
-            // Make sure that if the user changes the value and the IME is active
-            // for one of the inputs if this widget, the IME is closed. If the user
-            // changed the value via the IME and there is a next input the IME will
-            // be shown, otherwise the user chose another means of changing the
-            // value and having the IME up makes no sense.
-            InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
-            if (inputMethodManager != null) {
-                if (inputMethodManager.isActive(mYearSpinnerInput)) {
-                    mYearSpinnerInput.clearFocus();
-                    inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-                } else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
-                    mMonthSpinnerInput.clearFocus();
-                    inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-                } else if (inputMethodManager.isActive(mDaySpinnerInput)) {
-                    mDaySpinnerInput.clearFocus();
-                    inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-                }
-            }
-        }
-    }
-
-    /**
-     * Class for managing state storing/restoring.
-     */
-    private static class SavedState extends BaseSavedState {
-
-        private final int mYear;
-
-        private final int mMonth;
-
-        private final int mDay;
-
-        /**
-         * Constructor called from {@link DatePicker#onSaveInstanceState()}
-         */
-        private SavedState(Parcelable superState, int year, int month, int day) {
-            super(superState);
-            mYear = year;
-            mMonth = month;
-            mDay = day;
-        }
-
-        /**
-         * Constructor called from {@link #CREATOR}
-         */
-        private SavedState(Parcel in) {
-            super(in);
-            mYear = in.readInt();
-            mMonth = in.readInt();
-            mDay = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mYear);
-            dest.writeInt(mMonth);
-            dest.writeInt(mDay);
-        }
-
-        @SuppressWarnings("all")
-        // suppress unused and hiding
-        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
-
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
 }
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index cbb6109..332e89c 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -16,13 +16,14 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
@@ -37,8 +38,6 @@
 import android.widget.DayPickerView.OnDaySelectedListener;
 import android.widget.YearPickerView.OnYearSelectedListener;
 
-import com.android.internal.R;
-
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Locale;
@@ -379,9 +378,9 @@
         mCurrentDate.set(Calendar.MONTH, monthOfYear);
         mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
 
-        mDateChangedListener = callBack;
-
         onDateChanged(false, false);
+
+        mDateChangedListener = callBack;
     }
 
     @Override
@@ -550,25 +549,27 @@
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        final SavedState ss = (SavedState) state;
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
 
-        // TODO: Move instance state into DayPickerView, YearPickerView.
-        mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
-        mMinDate.setTimeInMillis(ss.getMinDate());
-        mMaxDate.setTimeInMillis(ss.getMaxDate());
+            // TODO: Move instance state into DayPickerView, YearPickerView.
+            mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
+            mMinDate.setTimeInMillis(ss.getMinDate());
+            mMaxDate.setTimeInMillis(ss.getMaxDate());
 
-        onCurrentDateChanged(false);
+            onCurrentDateChanged(false);
 
-        final int currentView = ss.getCurrentView();
-        setCurrentView(currentView);
+            final int currentView = ss.getCurrentView();
+            setCurrentView(currentView);
 
-        final int listPosition = ss.getListPosition();
-        if (listPosition != -1) {
-            if (currentView == VIEW_MONTH_DAY) {
-                mDayPickerView.setPosition(listPosition);
-            } else if (currentView == VIEW_YEAR) {
-                final int listPositionOffset = ss.getListPositionOffset();
-                mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
+            final int listPosition = ss.getListPosition();
+            if (listPosition != -1) {
+                if (currentView == VIEW_MONTH_DAY) {
+                    mDayPickerView.setPosition(listPosition);
+                } else if (currentView == VIEW_YEAR) {
+                    final int listPositionOffset = ss.getListPositionOffset();
+                    mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
+                }
             }
         }
     }
@@ -613,108 +614,4 @@
     private void tryVibrate() {
         mDelegator.performHapticFeedback(HapticFeedbackConstants.CALENDAR_DATE);
     }
-
-    /**
-     * Class for managing state storing/restoring.
-     */
-    private static class SavedState extends View.BaseSavedState {
-        private final int mSelectedYear;
-        private final int mSelectedMonth;
-        private final int mSelectedDay;
-        private final long mMinDate;
-        private final long mMaxDate;
-        private final int mCurrentView;
-        private final int mListPosition;
-        private final int mListPositionOffset;
-
-        /**
-         * Constructor called from {@link DatePicker#onSaveInstanceState()}
-         */
-        private SavedState(Parcelable superState, int year, int month, int day,
-                long minDate, long maxDate, int currentView, int listPosition,
-                int listPositionOffset) {
-            super(superState);
-            mSelectedYear = year;
-            mSelectedMonth = month;
-            mSelectedDay = day;
-            mMinDate = minDate;
-            mMaxDate = maxDate;
-            mCurrentView = currentView;
-            mListPosition = listPosition;
-            mListPositionOffset = listPositionOffset;
-        }
-
-        /**
-         * Constructor called from {@link #CREATOR}
-         */
-        private SavedState(Parcel in) {
-            super(in);
-            mSelectedYear = in.readInt();
-            mSelectedMonth = in.readInt();
-            mSelectedDay = in.readInt();
-            mMinDate = in.readLong();
-            mMaxDate = in.readLong();
-            mCurrentView = in.readInt();
-            mListPosition = in.readInt();
-            mListPositionOffset = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mSelectedYear);
-            dest.writeInt(mSelectedMonth);
-            dest.writeInt(mSelectedDay);
-            dest.writeLong(mMinDate);
-            dest.writeLong(mMaxDate);
-            dest.writeInt(mCurrentView);
-            dest.writeInt(mListPosition);
-            dest.writeInt(mListPositionOffset);
-        }
-
-        public int getSelectedDay() {
-            return mSelectedDay;
-        }
-
-        public int getSelectedMonth() {
-            return mSelectedMonth;
-        }
-
-        public int getSelectedYear() {
-            return mSelectedYear;
-        }
-
-        public long getMinDate() {
-            return mMinDate;
-        }
-
-        public long getMaxDate() {
-            return mMaxDate;
-        }
-
-        public int getCurrentView() {
-            return mCurrentView;
-        }
-
-        public int getListPosition() {
-            return mListPosition;
-        }
-
-        public int getListPositionOffset() {
-            return mListPositionOffset;
-        }
-
-        @SuppressWarnings("all")
-        // suppress unused and hiding
-        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
-
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
 }
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
new file mode 100644
index 0000000..d8a3c56
--- /dev/null
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -0,0 +1,653 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.os.Parcelable;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.text.format.DateFormat;
+import android.text.format.DateUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.DatePicker.AbstractDatePickerDelegate;
+import android.widget.NumberPicker.OnValueChangeListener;
+
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Locale;
+
+import libcore.icu.ICU;
+
+/**
+ * A delegate implementing the basic DatePicker
+ */
+class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
+
+    private static final String DATE_FORMAT = "MM/dd/yyyy";
+
+    private static final int DEFAULT_START_YEAR = 1900;
+
+    private static final int DEFAULT_END_YEAR = 2100;
+
+    private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
+
+    private static final boolean DEFAULT_SPINNERS_SHOWN = true;
+
+    private static final boolean DEFAULT_ENABLED_STATE = true;
+
+    private final LinearLayout mSpinners;
+
+    private final NumberPicker mDaySpinner;
+
+    private final NumberPicker mMonthSpinner;
+
+    private final NumberPicker mYearSpinner;
+
+    private final EditText mDaySpinnerInput;
+
+    private final EditText mMonthSpinnerInput;
+
+    private final EditText mYearSpinnerInput;
+
+    private final CalendarView mCalendarView;
+
+    private String[] mShortMonths;
+
+    private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
+
+    private int mNumberOfMonths;
+
+    private Calendar mTempDate;
+
+    private Calendar mMinDate;
+
+    private Calendar mMaxDate;
+
+    private Calendar mCurrentDate;
+
+    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
+
+    DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(delegator, context);
+
+        mDelegator = delegator;
+        mContext = context;
+
+        // initialization based on locale
+        setCurrentLocale(Locale.getDefault());
+
+        final TypedArray attributesArray = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.DatePicker, defStyleAttr, defStyleRes);
+        boolean spinnersShown = attributesArray.getBoolean(com.android.internal.R.styleable.DatePicker_spinnersShown,
+                DEFAULT_SPINNERS_SHOWN);
+        boolean calendarViewShown = attributesArray.getBoolean(
+                com.android.internal.R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
+        int startYear = attributesArray.getInt(com.android.internal.R.styleable.DatePicker_startYear,
+                DEFAULT_START_YEAR);
+        int endYear = attributesArray.getInt(com.android.internal.R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
+        String minDate = attributesArray.getString(com.android.internal.R.styleable.DatePicker_minDate);
+        String maxDate = attributesArray.getString(com.android.internal.R.styleable.DatePicker_maxDate);
+        int layoutResourceId = attributesArray.getResourceId(
+                com.android.internal.R.styleable.DatePicker_legacyLayout, com.android.internal.R.layout.date_picker_legacy);
+        attributesArray.recycle();
+
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(layoutResourceId, mDelegator, true);
+
+        OnValueChangeListener onChangeListener = new OnValueChangeListener() {
+            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                updateInputState();
+                mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
+                // take care of wrapping of days and months to update greater fields
+                if (picker == mDaySpinner) {
+                    int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
+                    if (oldVal == maxDayOfMonth && newVal == 1) {
+                        mTempDate.add(Calendar.DAY_OF_MONTH, 1);
+                    } else if (oldVal == 1 && newVal == maxDayOfMonth) {
+                        mTempDate.add(Calendar.DAY_OF_MONTH, -1);
+                    } else {
+                        mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
+                    }
+                } else if (picker == mMonthSpinner) {
+                    if (oldVal == 11 && newVal == 0) {
+                        mTempDate.add(Calendar.MONTH, 1);
+                    } else if (oldVal == 0 && newVal == 11) {
+                        mTempDate.add(Calendar.MONTH, -1);
+                    } else {
+                        mTempDate.add(Calendar.MONTH, newVal - oldVal);
+                    }
+                } else if (picker == mYearSpinner) {
+                    mTempDate.set(Calendar.YEAR, newVal);
+                } else {
+                    throw new IllegalArgumentException();
+                }
+                // now set the date to the adjusted one
+                setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
+                        mTempDate.get(Calendar.DAY_OF_MONTH));
+                updateSpinners();
+                updateCalendarView();
+                notifyDateChanged();
+            }
+        };
+
+        mSpinners = (LinearLayout) mDelegator.findViewById(com.android.internal.R.id.pickers);
+
+        // calendar view day-picker
+        mCalendarView = (CalendarView) mDelegator.findViewById(com.android.internal.R.id.calendar_view);
+        mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
+            public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
+                setDate(year, month, monthDay);
+                updateSpinners();
+                notifyDateChanged();
+            }
+        });
+
+        // day
+        mDaySpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.day);
+        mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
+        mDaySpinner.setOnLongPressUpdateInterval(100);
+        mDaySpinner.setOnValueChangedListener(onChangeListener);
+        mDaySpinnerInput = (EditText) mDaySpinner.findViewById(com.android.internal.R.id.numberpicker_input);
+
+        // month
+        mMonthSpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.month);
+        mMonthSpinner.setMinValue(0);
+        mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
+        mMonthSpinner.setDisplayedValues(mShortMonths);
+        mMonthSpinner.setOnLongPressUpdateInterval(200);
+        mMonthSpinner.setOnValueChangedListener(onChangeListener);
+        mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(com.android.internal.R.id.numberpicker_input);
+
+        // year
+        mYearSpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.year);
+        mYearSpinner.setOnLongPressUpdateInterval(100);
+        mYearSpinner.setOnValueChangedListener(onChangeListener);
+        mYearSpinnerInput = (EditText) mYearSpinner.findViewById(com.android.internal.R.id.numberpicker_input);
+
+        // show only what the user required but make sure we
+        // show something and the spinners have higher priority
+        if (!spinnersShown && !calendarViewShown) {
+            setSpinnersShown(true);
+        } else {
+            setSpinnersShown(spinnersShown);
+            setCalendarViewShown(calendarViewShown);
+        }
+
+        // set the min date giving priority of the minDate over startYear
+        mTempDate.clear();
+        if (!TextUtils.isEmpty(minDate)) {
+            if (!parseDate(minDate, mTempDate)) {
+                mTempDate.set(startYear, 0, 1);
+            }
+        } else {
+            mTempDate.set(startYear, 0, 1);
+        }
+        setMinDate(mTempDate.getTimeInMillis());
+
+        // set the max date giving priority of the maxDate over endYear
+        mTempDate.clear();
+        if (!TextUtils.isEmpty(maxDate)) {
+            if (!parseDate(maxDate, mTempDate)) {
+                mTempDate.set(endYear, 11, 31);
+            }
+        } else {
+            mTempDate.set(endYear, 11, 31);
+        }
+        setMaxDate(mTempDate.getTimeInMillis());
+
+        // initialize to current date
+        mCurrentDate.setTimeInMillis(System.currentTimeMillis());
+        init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
+                .get(Calendar.DAY_OF_MONTH), null);
+
+        // re-order the number spinners to match the current date format
+        reorderSpinners();
+
+        // accessibility
+        setContentDescriptions();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (mDelegator.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            mDelegator.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    @Override
+    public void init(int year, int monthOfYear, int dayOfMonth,
+                     DatePicker.OnDateChangedListener onDateChangedListener) {
+        setDate(year, monthOfYear, dayOfMonth);
+        updateSpinners();
+        updateCalendarView();
+
+        mOnDateChangedListener = onDateChangedListener;
+    }
+
+    @Override
+    public void updateDate(int year, int month, int dayOfMonth) {
+        if (!isNewDate(year, month, dayOfMonth)) {
+            return;
+        }
+        setDate(year, month, dayOfMonth);
+        updateSpinners();
+        updateCalendarView();
+        notifyDateChanged();
+    }
+
+    @Override
+    public int getYear() {
+        return mCurrentDate.get(Calendar.YEAR);
+    }
+
+    @Override
+    public int getMonth() {
+        return mCurrentDate.get(Calendar.MONTH);
+    }
+
+    @Override
+    public int getDayOfMonth() {
+        return mCurrentDate.get(Calendar.DAY_OF_MONTH);
+    }
+
+    @Override
+    public void setFirstDayOfWeek(int firstDayOfWeek) {
+        mCalendarView.setFirstDayOfWeek(firstDayOfWeek);
+    }
+
+    @Override
+    public int getFirstDayOfWeek() {
+        return mCalendarView.getFirstDayOfWeek();
+    }
+
+    @Override
+    public void setMinDate(long minDate) {
+        mTempDate.setTimeInMillis(minDate);
+        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
+                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
+            return;
+        }
+        mMinDate.setTimeInMillis(minDate);
+        mCalendarView.setMinDate(minDate);
+        if (mCurrentDate.before(mMinDate)) {
+            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
+            updateCalendarView();
+        }
+        updateSpinners();
+    }
+
+    @Override
+    public Calendar getMinDate() {
+        final Calendar minDate = Calendar.getInstance();
+        minDate.setTimeInMillis(mCalendarView.getMinDate());
+        return minDate;
+    }
+
+    @Override
+    public void setMaxDate(long maxDate) {
+        mTempDate.setTimeInMillis(maxDate);
+        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
+                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
+            return;
+        }
+        mMaxDate.setTimeInMillis(maxDate);
+        mCalendarView.setMaxDate(maxDate);
+        if (mCurrentDate.after(mMaxDate)) {
+            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+            updateCalendarView();
+        }
+        updateSpinners();
+    }
+
+    @Override
+    public Calendar getMaxDate() {
+        final Calendar maxDate = Calendar.getInstance();
+        maxDate.setTimeInMillis(mCalendarView.getMaxDate());
+        return maxDate;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        mDaySpinner.setEnabled(enabled);
+        mMonthSpinner.setEnabled(enabled);
+        mYearSpinner.setEnabled(enabled);
+        mCalendarView.setEnabled(enabled);
+        mIsEnabled = enabled;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    @Override
+    public CalendarView getCalendarView() {
+        return mCalendarView;
+    }
+
+    @Override
+    public void setCalendarViewShown(boolean shown) {
+        mCalendarView.setVisibility(shown ? View.VISIBLE : View.GONE);
+    }
+
+    @Override
+    public boolean getCalendarViewShown() {
+        return (mCalendarView.getVisibility() == View.VISIBLE);
+    }
+
+    @Override
+    public void setSpinnersShown(boolean shown) {
+        mSpinners.setVisibility(shown ? View.VISIBLE : View.GONE);
+    }
+
+    @Override
+    public boolean getSpinnersShown() {
+        return mSpinners.isShown();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        setCurrentLocale(newConfig.locale);
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState(Parcelable superState) {
+        return new SavedState(superState, getYear(), getMonth(), getDayOfMonth(),
+                getMinDate().getTimeInMillis(), getMaxDate().getTimeInMillis());
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
+            setDate(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
+            updateSpinners();
+            updateCalendarView();
+        }
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        onPopulateAccessibilityEvent(event);
+        return true;
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
+        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
+                mCurrentDate.getTimeInMillis(), flags);
+        event.getText().add(selectedDateUtterance);
+    }
+
+    /**
+     * Sets the current locale.
+     *
+     * @param locale The current locale.
+     */
+    @Override
+    protected void setCurrentLocale(Locale locale) {
+        super.setCurrentLocale(locale);
+
+        mTempDate = getCalendarForLocale(mTempDate, locale);
+        mMinDate = getCalendarForLocale(mMinDate, locale);
+        mMaxDate = getCalendarForLocale(mMaxDate, locale);
+        mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
+
+        mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
+        mShortMonths = new DateFormatSymbols().getShortMonths();
+
+        if (usingNumericMonths()) {
+            // We're in a locale where a date should either be all-numeric, or all-text.
+            // All-text would require custom NumberPicker formatters for day and year.
+            mShortMonths = new String[mNumberOfMonths];
+            for (int i = 0; i < mNumberOfMonths; ++i) {
+                mShortMonths[i] = String.format("%d", i + 1);
+            }
+        }
+    }
+
+    /**
+     * Tests whether the current locale is one where there are no real month names,
+     * such as Chinese, Japanese, or Korean locales.
+     */
+    private boolean usingNumericMonths() {
+        return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0));
+    }
+
+    /**
+     * Gets a calendar for locale bootstrapped with the value of a given calendar.
+     *
+     * @param oldCalendar The old calendar.
+     * @param locale The locale.
+     */
+    private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
+        if (oldCalendar == null) {
+            return Calendar.getInstance(locale);
+        } else {
+            final long currentTimeMillis = oldCalendar.getTimeInMillis();
+            Calendar newCalendar = Calendar.getInstance(locale);
+            newCalendar.setTimeInMillis(currentTimeMillis);
+            return newCalendar;
+        }
+    }
+
+    /**
+     * Reorders the spinners according to the date format that is
+     * explicitly set by the user and if no such is set fall back
+     * to the current locale's default format.
+     */
+    private void reorderSpinners() {
+        mSpinners.removeAllViews();
+        // We use numeric spinners for year and day, but textual months. Ask icu4c what
+        // order the user's locale uses for that combination. http://b/7207103.
+        String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyyMMMdd");
+        char[] order = ICU.getDateFormatOrder(pattern);
+        final int spinnerCount = order.length;
+        for (int i = 0; i < spinnerCount; i++) {
+            switch (order[i]) {
+                case 'd':
+                    mSpinners.addView(mDaySpinner);
+                    setImeOptions(mDaySpinner, spinnerCount, i);
+                    break;
+                case 'M':
+                    mSpinners.addView(mMonthSpinner);
+                    setImeOptions(mMonthSpinner, spinnerCount, i);
+                    break;
+                case 'y':
+                    mSpinners.addView(mYearSpinner);
+                    setImeOptions(mYearSpinner, spinnerCount, i);
+                    break;
+                default:
+                    throw new IllegalArgumentException(Arrays.toString(order));
+            }
+        }
+    }
+
+    /**
+     * Parses the given <code>date</code> and in case of success sets the result
+     * to the <code>outDate</code>.
+     *
+     * @return True if the date was parsed.
+     */
+    private boolean parseDate(String date, Calendar outDate) {
+        try {
+            outDate.setTime(mDateFormat.parse(date));
+            return true;
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    private boolean isNewDate(int year, int month, int dayOfMonth) {
+        return (mCurrentDate.get(Calendar.YEAR) != year
+                || mCurrentDate.get(Calendar.MONTH) != month
+                || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth);
+    }
+
+    private void setDate(int year, int month, int dayOfMonth) {
+        mCurrentDate.set(year, month, dayOfMonth);
+        if (mCurrentDate.before(mMinDate)) {
+            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
+        } else if (mCurrentDate.after(mMaxDate)) {
+            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+        }
+    }
+
+    private void updateSpinners() {
+        // set the spinner ranges respecting the min and max dates
+        if (mCurrentDate.equals(mMinDate)) {
+            mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setWrapSelectorWheel(false);
+            mMonthSpinner.setDisplayedValues(null);
+            mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
+            mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
+            mMonthSpinner.setWrapSelectorWheel(false);
+        } else if (mCurrentDate.equals(mMaxDate)) {
+            mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setWrapSelectorWheel(false);
+            mMonthSpinner.setDisplayedValues(null);
+            mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
+            mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
+            mMonthSpinner.setWrapSelectorWheel(false);
+        } else {
+            mDaySpinner.setMinValue(1);
+            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setWrapSelectorWheel(true);
+            mMonthSpinner.setDisplayedValues(null);
+            mMonthSpinner.setMinValue(0);
+            mMonthSpinner.setMaxValue(11);
+            mMonthSpinner.setWrapSelectorWheel(true);
+        }
+
+        // make sure the month names are a zero based array
+        // with the months in the month spinner
+        String[] displayedValues = Arrays.copyOfRange(mShortMonths,
+                mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
+        mMonthSpinner.setDisplayedValues(displayedValues);
+
+        // year spinner range does not change based on the current date
+        mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
+        mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
+        mYearSpinner.setWrapSelectorWheel(false);
+
+        // set the spinner values
+        mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
+        mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
+        mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
+
+        if (usingNumericMonths()) {
+            mMonthSpinnerInput.setRawInputType(InputType.TYPE_CLASS_NUMBER);
+        }
+    }
+
+    /**
+     * Updates the calendar view with the current date.
+     */
+    private void updateCalendarView() {
+        mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
+    }
+
+
+    /**
+     * Notifies the listener, if such, for a change in the selected date.
+     */
+    private void notifyDateChanged() {
+        mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        if (mOnDateChangedListener != null) {
+            mOnDateChangedListener.onDateChanged(mDelegator, getYear(), getMonth(),
+                    getDayOfMonth());
+        }
+    }
+
+    /**
+     * Sets the IME options for a spinner based on its ordering.
+     *
+     * @param spinner The spinner.
+     * @param spinnerCount The total spinner count.
+     * @param spinnerIndex The index of the given spinner.
+     */
+    private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
+        final int imeOptions;
+        if (spinnerIndex < spinnerCount - 1) {
+            imeOptions = EditorInfo.IME_ACTION_NEXT;
+        } else {
+            imeOptions = EditorInfo.IME_ACTION_DONE;
+        }
+        TextView input = (TextView) spinner.findViewById(com.android.internal.R.id.numberpicker_input);
+        input.setImeOptions(imeOptions);
+    }
+
+    private void setContentDescriptions() {
+        // Day
+        trySetContentDescription(mDaySpinner, com.android.internal.R.id.increment,
+                com.android.internal.R.string.date_picker_increment_day_button);
+        trySetContentDescription(mDaySpinner, com.android.internal.R.id.decrement,
+                com.android.internal.R.string.date_picker_decrement_day_button);
+        // Month
+        trySetContentDescription(mMonthSpinner, com.android.internal.R.id.increment,
+                com.android.internal.R.string.date_picker_increment_month_button);
+        trySetContentDescription(mMonthSpinner, com.android.internal.R.id.decrement,
+                com.android.internal.R.string.date_picker_decrement_month_button);
+        // Year
+        trySetContentDescription(mYearSpinner, com.android.internal.R.id.increment,
+                com.android.internal.R.string.date_picker_increment_year_button);
+        trySetContentDescription(mYearSpinner, com.android.internal.R.id.decrement,
+                com.android.internal.R.string.date_picker_decrement_year_button);
+    }
+
+    private void trySetContentDescription(View root, int viewId, int contDescResId) {
+        View target = root.findViewById(viewId);
+        if (target != null) {
+            target.setContentDescription(mContext.getString(contDescResId));
+        }
+    }
+
+    private void updateInputState() {
+        // Make sure that if the user changes the value and the IME is active
+        // for one of the inputs if this widget, the IME is closed. If the user
+        // changed the value via the IME and there is a next input the IME will
+        // be shown, otherwise the user chose another means of changing the
+        // value and having the IME up makes no sense.
+        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        if (inputMethodManager != null) {
+            if (inputMethodManager.isActive(mYearSpinnerInput)) {
+                mYearSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
+                mMonthSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mDaySpinnerInput)) {
+                mDaySpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            }
+        }
+    }
+}
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index f5840dc..8ce2f9c 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -282,7 +282,7 @@
     public CharSequence getPageTitle(int position) {
         final SimpleMonthView v = mItems.get(position).calendar;
         if (v != null) {
-            return v.getTitle();
+            return v.getMonthYearLabel();
         }
         return null;
     }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 1d242d3..ad35550 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -117,6 +117,16 @@
         Selection.extendSelection(getText(), index);
     }
 
+    /**
+     * Causes words in the text that are longer than the view's width to be ellipsized instead of
+     * broken in the middle. {@link TextUtils.TruncateAt#MARQUEE
+     * TextUtils.TruncateAt#MARQUEE} is not supported.
+     *
+     * @param ellipsis Type of ellipsis to be applied.
+     * @throws IllegalArgumentException When the value of <code>ellipsis</code> parameter is
+     *      {@link TextUtils.TruncateAt#MARQUEE}.
+     * @see TextView#setEllipsize(TextUtils.TruncateAt)
+     */
     @Override
     public void setEllipsize(TextUtils.TruncateAt ellipsis) {
         if (ellipsis == TextUtils.TruncateAt.MARQUEE) {
@@ -145,6 +155,9 @@
     public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+                if (!isEnabled()) {
+                    return false;
+                }
                 CharSequence text = (arguments != null) ? arguments.getCharSequence(
                         AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
                 setText(text);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 1826dd8..7055f78 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -18,6 +18,7 @@
 
 import android.R;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
@@ -215,8 +216,8 @@
 
     boolean mInBatchEditControllers;
     boolean mShowSoftInputOnFocus = true;
-    boolean mPreserveDetachedSelection;
-    boolean mTemporaryDetach;
+    private boolean mPreserveSelection;
+    private boolean mRestartActionModeOnNextRefresh;
 
     boolean mIsBeingLongClicked;
 
@@ -290,7 +291,6 @@
     boolean mIsInsertionActionModeStartPending = false;
 
     private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
-    private SuggestionInfo[] mSuggestionInfosInContextMenu;
 
     Editor(TextView textView) {
         mTextView = textView;
@@ -351,10 +351,14 @@
     }
 
     void replace() {
+        if (mSuggestionsPopupWindow == null) {
+            mSuggestionsPopupWindow = new SuggestionsPopupWindow();
+        }
+        hideCursorAndSpanControllers();
+        mSuggestionsPopupWindow.show();
+
         int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
-        stopTextActionMode();
         Selection.setSelection((Spannable) mTextView.getText(), middle);
-        showSuggestions();
     }
 
     void onAttachedToWindow() {
@@ -362,7 +366,6 @@
             showError();
             mShowErrorAfterAttach = false;
         }
-        mTemporaryDetach = false;
 
         final ViewTreeObserver observer = mTextView.getViewTreeObserver();
         // No need to create the controller.
@@ -377,15 +380,8 @@
         updateSpellCheckSpans(0, mTextView.getText().length(),
                 true /* create the spell checker if needed */);
 
-        if (mTextView.hasTransientState() &&
-                mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
-            // Since transient state is reference counted make sure it stays matched
-            // with our own calls to it for managing selection.
-            // The action mode callback will set this back again when/if the action mode starts.
-            mTextView.setHasTransientState(false);
-
-            // We had an active selection from before, start the selection mode.
-            startSelectionActionMode();
+        if (mTextView.hasSelection()) {
+            refreshTextActionMode();
         }
 
         getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true);
@@ -429,11 +425,8 @@
             mSpellChecker = null;
         }
 
-        mPreserveDetachedSelection = true;
         hideCursorAndSpanControllers();
-        stopTextActionMode();
-        mPreserveDetachedSelection = false;
-        mTemporaryDetach = false;
+        stopTextActionModeWithPreservingSelection();
     }
 
     private void discardTextDisplayLists() {
@@ -930,7 +923,8 @@
     }
 
     void onLocaleChanged() {
-        // Will be re-created on demand in getWordIterator with the proper new locale
+        // Will be re-created on demand in getWordIterator and getWordIteratorWithText with the
+        // proper new locale
         mWordIterator = null;
         mWordIteratorWithText = null;
     }
@@ -965,20 +959,21 @@
     private int getNextCursorOffset(int offset, boolean findAfterGivenOffset) {
         final Layout layout = mTextView.getLayout();
         if (layout == null) return offset;
-        final CharSequence text = mTextView.getText();
-        final int nextOffset = layout.getPaint().getTextRunCursor(text, 0, text.length(),
-                layout.isRtlCharAt(offset) ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR,
-                offset, findAfterGivenOffset ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE);
-        return nextOffset == -1 ? offset : nextOffset;
+        return findAfterGivenOffset == layout.isRtlCharAt(offset) ?
+                layout.getOffsetToLeftOf(offset) : layout.getOffsetToRightOf(offset);
     }
 
     private long getCharClusterRange(int offset) {
         final int textLength = mTextView.getText().length();
         if (offset < textLength) {
-            return TextUtils.packRangeInLong(offset, getNextCursorOffset(offset, true));
+            final int clusterEndOffset = getNextCursorOffset(offset, true);
+            return TextUtils.packRangeInLong(
+                    getNextCursorOffset(clusterEndOffset, false), clusterEndOffset);
         }
         if (offset - 1 >= 0) {
-            return TextUtils.packRangeInLong(getNextCursorOffset(offset, false), offset);
+            final int clusterStartOffset = getNextCursorOffset(offset, false);
+            return TextUtils.packRangeInLong(clusterStartOffset,
+                    getNextCursorOffset(clusterStartOffset, true));
         }
         return TextUtils.packRangeInLong(offset, offset);
     }
@@ -1084,12 +1079,16 @@
     }
 
     private void startDragAndDrop() {
+        // TODO: Fix drag and drop in full screen extracted mode.
+        if (mTextView.isInExtractedMode()) {
+            return;
+        }
         final int start = mTextView.getSelectionStart();
         final int end = mTextView.getSelectionEnd();
         CharSequence selectedText = mTextView.getTransformedText(start, end);
         ClipData data = ClipData.newPlainText(null, selectedText);
         DragLocalState localState = new DragLocalState(mTextView, start, end);
-        mTextView.startDragAndDrop(data, getTextThumbnailBuilder(selectedText), localState,
+        mTextView.startDragAndDrop(data, getTextThumbnailBuilder(start, end), localState,
                 View.DRAG_FLAG_GLOBAL);
         stopTextActionMode();
         if (hasSelectionController()) {
@@ -1103,7 +1102,6 @@
                 mInsertionControllerEnabled) {
             final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
                     mLastDownPositionY);
-            stopTextActionMode();
             Selection.setSelection((Spannable) mTextView.getText(), offset);
             getInsertionController().show();
             mIsInsertionActionModeStartPending = true;
@@ -1207,18 +1205,15 @@
             mTextView.onEndBatchEdit();
 
             if (mTextView.isInExtractedMode()) {
-                // terminateTextSelectionMode removes selection, which we want to keep when
-                // ExtractEditText goes out of focus.
-                final int selStart = mTextView.getSelectionStart();
-                final int selEnd = mTextView.getSelectionEnd();
                 hideCursorAndSpanControllers();
-                stopTextActionMode();
-                Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
+                stopTextActionModeWithPreservingSelection();
             } else {
-                if (mTemporaryDetach) mPreserveDetachedSelection = true;
                 hideCursorAndSpanControllers();
-                stopTextActionMode();
-                if (mTemporaryDetach) mPreserveDetachedSelection = false;
+                if (mTextView.isTemporarilyDetached()) {
+                    stopTextActionModeWithPreservingSelection();
+                } else {
+                    stopTextActionMode();
+                }
                 downgradeEasyCorrectionSpans();
             }
             // No need to create the controller
@@ -1289,10 +1284,8 @@
                 makeBlink();
             }
             final InputMethodManager imm = InputMethodManager.peekInstance();
-            final boolean immFullScreen = (imm != null && imm.isFullscreenMode());
-            if (mSelectionModifierCursorController != null && mTextView.hasSelection()
-                    && !immFullScreen && mTextActionMode != null) {
-                mSelectionModifierCursorController.show();
+            if (mTextView.hasSelection() && !extractedTextModeWillBeStarted()) {
+                refreshTextActionMode();
             }
         } else {
             if (mBlink != null) {
@@ -1303,9 +1296,7 @@
             }
             // Order matters! Must be done before onParentLostFocus to rely on isShowingUp
             hideCursorAndSpanControllers();
-            if (mSelectionModifierCursorController != null) {
-                mSelectionModifierCursorController.hide();
-            }
+            stopTextActionModeWithPreservingSelection();
             if (mSuggestionsPopupWindow != null) {
                 mSuggestionsPopupWindow.onParentLostFocus();
             }
@@ -1833,7 +1824,7 @@
             return;
         }
 
-        Layout layout = getActiveLayout();
+        Layout layout = mTextView.getLayout();
         final int offset = mTextView.getSelectionStart();
         final int line = layout.getLineForOffset(offset);
         final int top = layout.getLineTop(line);
@@ -1855,6 +1846,47 @@
         }
     }
 
+    void refreshTextActionMode() {
+        if (extractedTextModeWillBeStarted()) {
+            mRestartActionModeOnNextRefresh = false;
+            return;
+        }
+        final boolean hasSelection = mTextView.hasSelection();
+        final SelectionModifierCursorController selectionController = getSelectionController();
+        final InsertionPointCursorController insertionController = getInsertionController();
+        if ((selectionController != null && selectionController.isCursorBeingModified())
+                || (insertionController != null && insertionController.isCursorBeingModified())) {
+            // ActionMode should be managed by the currently active cursor controller.
+            mRestartActionModeOnNextRefresh = false;
+            return;
+        }
+        if (hasSelection) {
+            hideInsertionPointCursorController();
+            if (mTextActionMode == null) {
+                if (mRestartActionModeOnNextRefresh) {
+                    // To avoid distraction, newly start action mode only when selection action
+                    // mode is being restarted.
+                    startSelectionActionMode();
+                }
+            } else if (selectionController == null || !selectionController.isActive()) {
+                // Insertion action mode is active. Avoid dismissing the selection.
+                stopTextActionModeWithPreservingSelection();
+                startSelectionActionMode();
+            } else {
+                mTextActionMode.invalidateContentRect();
+            }
+        } else {
+            // Insertion action mode is started only when insertion controller is explicitly
+            // activated.
+            if (insertionController == null || !insertionController.isActive()) {
+                stopTextActionMode();
+            } else if (mTextActionMode != null) {
+                mTextActionMode.invalidateContentRect();
+            }
+        }
+        mRestartActionModeOnNextRefresh = false;
+    }
+
     /**
      * Start an Insertion action mode.
      */
@@ -1878,8 +1910,8 @@
 
     /**
      * Starts a Selection Action Mode with the current selection and ensures the selection handles
-     * are shown if there is a selection, otherwise the insertion handle is shown. This should be
-     * used when the mode is started from a non-touch event.
+     * are shown if there is a selection. This should be used when the mode is started from a
+     * non-touch event.
      *
      * @return true if the selection mode was actually started.
      */
@@ -1887,9 +1919,8 @@
         boolean selectionStarted = startSelectionActionModeInternal();
         if (selectionStarted) {
             getSelectionController().show();
-        } else if (getInsertionController() != null) {
-            getInsertionController().show();
         }
+        mRestartActionModeOnNextRefresh = false;
         return selectionStarted;
     }
 
@@ -1906,66 +1937,52 @@
         if (extractedTextModeWillBeStarted()) {
             return false;
         }
-        if (mTextActionMode != null) {
-            mTextActionMode.finish();
-        }
-        if (!checkFieldAndSelectCurrentWord()) {
+        if (!checkField()) {
             return false;
         }
-
-        // Avoid dismissing the selection if it exists.
-        mPreserveDetachedSelection = true;
-        stopTextActionMode();
-        mPreserveDetachedSelection = false;
-
+        if (!mTextView.hasSelection() && !selectCurrentWord()) {
+            // No selection and cannot select a word.
+            return false;
+        }
+        stopTextActionModeWithPreservingSelection();
         getSelectionController().enterDrag(
                 SelectionModifierCursorController.DRAG_ACCELERATOR_MODE_WORD);
         return true;
     }
 
     /**
-     * Checks whether a selection can be performed on the current TextView and if so selects
-     * the current word.
+     * Checks whether a selection can be performed on the current TextView.
      *
-     * @return true if there already was a selection or if the current word was selected.
+     * @return true if a selection can be performed
      */
-    boolean checkFieldAndSelectCurrentWord() {
+    boolean checkField() {
         if (!mTextView.canSelectText() || !mTextView.requestFocus()) {
             Log.w(TextView.LOG_TAG,
                     "TextView does not support text selection. Selection cancelled.");
             return false;
         }
-
-        if (!mTextView.hasSelection()) {
-            // There may already be a selection on device rotation
-            return selectCurrentWord();
-        }
         return true;
     }
 
     private boolean startSelectionActionModeInternal() {
+        if (extractedTextModeWillBeStarted()) {
+            return false;
+        }
         if (mTextActionMode != null) {
             // Text action mode is already started
             mTextActionMode.invalidate();
             return false;
         }
 
-        if (!checkFieldAndSelectCurrentWord()) {
+        if (!checkField() || !mTextView.hasSelection()) {
             return false;
         }
 
-        boolean willExtract = extractedTextModeWillBeStarted();
+        ActionMode.Callback actionModeCallback =
+                new TextActionModeCallback(true /* hasSelection */);
+        mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
 
-        // Do not start the action mode when extracted text will show up full screen, which would
-        // immediately hide the newly created action bar and would be visually distracting.
-        if (!willExtract) {
-            ActionMode.Callback actionModeCallback =
-                    new TextActionModeCallback(true /* hasSelection */);
-            mTextActionMode = mTextView.startActionMode(
-                    actionModeCallback, ActionMode.TYPE_FLOATING);
-        }
-
-        final boolean selectionStarted = mTextActionMode != null || willExtract;
+        final boolean selectionStarted = mTextActionMode != null;
         if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) {
             // Show the IME to be able to replace text, except when selecting non editable text.
             final InputMethodManager imm = InputMethodManager.peekInstance();
@@ -2086,7 +2103,7 @@
 
                     mShowSuggestionRunnable = new Runnable() {
                         public void run() {
-                            showSuggestions();
+                            replace();
                         }
                     };
                     // removeCallbacks is performed on every touch
@@ -2106,6 +2123,15 @@
         }
     }
 
+    private void stopTextActionModeWithPreservingSelection() {
+        if (mTextActionMode != null) {
+            mRestartActionModeOnNextRefresh = true;
+        }
+        mPreserveSelection = true;
+        stopTextActionMode();
+        mPreserveSelection = false;
+    }
+
     /**
      * @return True if this view supports insertion handles.
      */
@@ -2163,27 +2189,35 @@
             mCursorDrawable[cursorIndex] = mTextView.getContext().getDrawable(
                     mTextView.mCursorDrawableRes);
         final Drawable drawable = mCursorDrawable[cursorIndex];
-        final int left = clampCursorHorizontalPosition(drawable, horizontal);
+        final int left = clampHorizontalPosition(drawable, horizontal);
         final int width = drawable.getIntrinsicWidth();
         drawable.setBounds(left, top - mTempRect.top, left + width,
                 bottom + mTempRect.bottom);
     }
 
     /**
-     * Return clamped position for the cursor. If the cursor is within the boundaries of the view,
-     * then it is offset with the left padding of the cursor drawable. If the cursor is at
+     * Return clamped position for the drawable. If the drawable is within the boundaries of the
+     * view, then it is offset with the left padding of the cursor drawable. If the drawable is at
      * the beginning or the end of the text then its drawable edge is aligned with left or right of
-     * the view boundary.
+     * the view boundary. If the drawable is null, horizontal parameter is aligned to left or right
+     * of the view.
      *
-     * @param drawable   Cursor drawable.
-     * @param horizontal Horizontal position for the cursor.
-     * @return The clamped horizontal position for the cursor.
+     * @param drawable Drawable. Can be null.
+     * @param horizontal Horizontal position for the drawable.
+     * @return The clamped horizontal position for the drawable.
      */
-    private final int clampCursorHorizontalPosition(final Drawable drawable, float
-            horizontal) {
+    private int clampHorizontalPosition(@Nullable final Drawable drawable, float horizontal) {
         horizontal = Math.max(0.5f, horizontal - 0.5f);
         if (mTempRect == null) mTempRect = new Rect();
-        drawable.getPadding(mTempRect);
+
+        int drawableWidth = 0;
+        if (drawable != null) {
+            drawable.getPadding(mTempRect);
+            drawableWidth = drawable.getIntrinsicWidth();
+        } else {
+            mTempRect.setEmpty();
+        }
+
         int scrollX = mTextView.getScrollX();
         float horizontalDiff = horizontal - scrollX;
         int viewClippedWidth = mTextView.getWidth() - mTextView.getCompoundPaddingLeft()
@@ -2192,9 +2226,11 @@
         final int left;
         if (horizontalDiff >= (viewClippedWidth - 1f)) {
             // at the rightmost position
-            final int cursorWidth = drawable.getIntrinsicWidth();
-            left = viewClippedWidth + scrollX - (cursorWidth - mTempRect.right);
-        } else if (Math.abs(horizontalDiff) <= 1f) {
+            left = viewClippedWidth + scrollX - (drawableWidth - mTempRect.right);
+        } else if (Math.abs(horizontalDiff) <= 1f ||
+                (TextUtils.isEmpty(mTextView.getText())
+                        && (TextView.VERY_WIDE - scrollX) <= (viewClippedWidth + 1f)
+                        && horizontal <= 1f)) {
             // at the leftmost position
             left = scrollX - mTempRect.left;
         } else {
@@ -2221,15 +2257,6 @@
         mCorrectionHighlighter.highlight(info);
     }
 
-    void showSuggestions() {
-        if (mSuggestionsPopupWindow == null) {
-            mSuggestionsPopupWindow = new SuggestionsPopupWindow();
-        }
-        hideCursorAndSpanControllers();
-        stopTextActionMode();
-        mSuggestionsPopupWindow.show();
-    }
-
     void onScrollChanged() {
         if (mPositionListener != null) {
             mPositionListener.onScrollChanged();
@@ -2296,7 +2323,7 @@
         }
     }
 
-    private DragShadowBuilder getTextThumbnailBuilder(CharSequence text) {
+    private DragShadowBuilder getTextThumbnailBuilder(int start, int end) {
         TextView shadowView = (TextView) View.inflate(mTextView.getContext(),
                 com.android.internal.R.layout.text_drag_thumbnail, null);
 
@@ -2304,9 +2331,11 @@
             throw new IllegalArgumentException("Unable to inflate text drag thumbnail");
         }
 
-        if (text.length() > DRAG_SHADOW_MAX_TEXT_LENGTH) {
-            text = text.subSequence(0, DRAG_SHADOW_MAX_TEXT_LENGTH);
+        if (end - start > DRAG_SHADOW_MAX_TEXT_LENGTH) {
+            final long range = getCharClusterRange(start + DRAG_SHADOW_MAX_TEXT_LENGTH);
+            end = TextUtils.unpackRangeEndFromLong(range);
         }
+        final CharSequence text = mTextView.getTransformedText(start, end);
         shadowView.setText(text);
         shadowView.setTextColor(mTextView.getTextColors());
 
@@ -2391,17 +2420,22 @@
                 dragSourceEnd += shift;
             }
 
-            // Delete original selection
-            mTextView.deleteText_internal(dragSourceStart, dragSourceEnd);
+            mUndoInputFilter.setForceMerge(true);
+            try {
+                // Delete original selection
+                mTextView.deleteText_internal(dragSourceStart, dragSourceEnd);
 
-            // Make sure we do not leave two adjacent spaces.
-            final int prevCharIdx = Math.max(0,  dragSourceStart - 1);
-            final int nextCharIdx = Math.min(mTextView.getText().length(), dragSourceStart + 1);
-            if (nextCharIdx > prevCharIdx + 1) {
-                CharSequence t = mTextView.getTransformedText(prevCharIdx, nextCharIdx);
-                if (Character.isSpaceChar(t.charAt(0)) && Character.isSpaceChar(t.charAt(1))) {
-                    mTextView.deleteText_internal(prevCharIdx, prevCharIdx + 1);
+                // Make sure we do not leave two adjacent spaces.
+                final int prevCharIdx = Math.max(0,  dragSourceStart - 1);
+                final int nextCharIdx = Math.min(mTextView.getText().length(), dragSourceStart + 1);
+                if (nextCharIdx > prevCharIdx + 1) {
+                    CharSequence t = mTextView.getTransformedText(prevCharIdx, nextCharIdx);
+                    if (Character.isSpaceChar(t.charAt(0)) && Character.isSpaceChar(t.charAt(1))) {
+                        mTextView.deleteText_internal(prevCharIdx, prevCharIdx + 1);
+                    }
                 }
+            } finally {
+                mUndoInputFilter.setForceMerge(false);
             }
         }
     }
@@ -2433,34 +2467,35 @@
         if (offset == -1) {
             return;
         }
-        mPreserveDetachedSelection = true;
-        stopTextActionMode();
-        mPreserveDetachedSelection = false;
+        stopTextActionModeWithPreservingSelection();
         final boolean isOnSelection = mTextView.hasSelection()
                 && offset >= mTextView.getSelectionStart() && offset <= mTextView.getSelectionEnd();
         if (!isOnSelection) {
             // Right clicked position is not on the selection. Remove the selection and move the
             // cursor to the right clicked position.
-            stopTextActionMode();
             Selection.setSelection((Spannable) mTextView.getText(), offset);
+            stopTextActionMode();
         }
 
         if (shouldOfferToShowSuggestions()) {
-            if (mSuggestionInfosInContextMenu == null) {
-                mSuggestionInfosInContextMenu =
-                        new SuggestionInfo[SuggestionSpan.SUGGESTIONS_MAX_SIZE];
-                for (int i = 0; i < mSuggestionInfosInContextMenu.length; i++) {
-                    mSuggestionInfosInContextMenu[i] = new SuggestionInfo();
-                }
+            final SuggestionInfo[] suggestionInfoArray =
+                    new SuggestionInfo[SuggestionSpan.SUGGESTIONS_MAX_SIZE];
+            for (int i = 0; i < suggestionInfoArray.length; i++) {
+                suggestionInfoArray[i] = new SuggestionInfo();
             }
             final SubMenu subMenu = menu.addSubMenu(Menu.NONE, Menu.NONE, MENU_ITEM_ORDER_REPLACE,
                     com.android.internal.R.string.replace);
-            mSuggestionHelper.getSuggestionInfo(mSuggestionInfosInContextMenu);
-            int i = 0;
-            for (final SuggestionInfo info : mSuggestionInfosInContextMenu) {
-                info.mSuggestionEnd = info.mText.length();
-                subMenu.add(Menu.NONE, Menu.NONE, i++, info.mText)
-                        .setOnMenuItemClickListener(mOnContextMenuReplaceItemClickListener);
+            final int numItems = mSuggestionHelper.getSuggestionInfo(suggestionInfoArray, null);
+            for (int i = 0; i < numItems; i++) {
+                final SuggestionInfo info = suggestionInfoArray[i];
+                subMenu.add(Menu.NONE, Menu.NONE, i, info.mText)
+                        .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                            @Override
+                            public boolean onMenuItemClick(MenuItem item) {
+                                replaceWithSuggestion(info);
+                                return true;
+                            }
+                        });
             }
         }
 
@@ -2503,11 +2538,52 @@
                 .setEnabled(mTextView.canSelectAllText())
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
 
-        mPreserveDetachedSelection = true;
+        mPreserveSelection = true;
     }
 
-    private void replaceWithSuggestion(SuggestionInfo suggestionInfo, int spanStart, int spanEnd) {
+    @Nullable
+    private SuggestionSpan findEquivalentSuggestionSpan(
+            @NonNull SuggestionSpanInfo suggestionSpanInfo) {
         final Editable editable = (Editable) mTextView.getText();
+        if (editable.getSpanStart(suggestionSpanInfo.mSuggestionSpan) >= 0) {
+            // Exactly same span is found.
+            return suggestionSpanInfo.mSuggestionSpan;
+        }
+        // Suggestion span couldn't be found. Try to find a suggestion span that has the same
+        // contents.
+        final SuggestionSpan[] suggestionSpans = editable.getSpans(suggestionSpanInfo.mSpanStart,
+                suggestionSpanInfo.mSpanEnd, SuggestionSpan.class);
+        for (final SuggestionSpan suggestionSpan : suggestionSpans) {
+            final int start = editable.getSpanStart(suggestionSpan);
+            if (start != suggestionSpanInfo.mSpanStart) {
+                continue;
+            }
+            final int end = editable.getSpanEnd(suggestionSpan);
+            if (end != suggestionSpanInfo.mSpanEnd) {
+                continue;
+            }
+            if (suggestionSpan.equals(suggestionSpanInfo.mSuggestionSpan)) {
+                return suggestionSpan;
+            }
+        }
+        return null;
+    }
+
+    private void replaceWithSuggestion(@NonNull final SuggestionInfo suggestionInfo) {
+        final SuggestionSpan targetSuggestionSpan = findEquivalentSuggestionSpan(
+                suggestionInfo.mSuggestionSpanInfo);
+        if (targetSuggestionSpan == null) {
+            // Span has been removed
+            return;
+        }
+        final Editable editable = (Editable) mTextView.getText();
+        final int spanStart = editable.getSpanStart(targetSuggestionSpan);
+        final int spanEnd = editable.getSpanEnd(targetSuggestionSpan);
+        if (spanStart < 0 || spanEnd <= spanStart) {
+            // Span has been removed
+            return;
+        }
+
         final String originalText = TextUtils.substring(editable, spanStart, spanEnd);
         // SuggestionSpans are removed by replace: save them before
         SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
@@ -2532,7 +2608,7 @@
         }
 
         // Notify source IME of the suggestion pick. Do this before swapping texts.
-        suggestionInfo.mSuggestionSpan.notifySelection(
+        targetSuggestionSpan.notifySelection(
                 mTextView.getContext(), originalText, suggestionInfo.mSuggestionIndex);
 
         // Swap text content between actual text and Suggestion span
@@ -2542,7 +2618,7 @@
                 suggestionStart, suggestionEnd).toString();
         mTextView.replaceText_internal(spanStart, spanEnd, suggestion);
 
-        String[] suggestions = suggestionInfo.mSuggestionSpan.getSuggestions();
+        String[] suggestions = targetSuggestionSpan.getSuggestions();
         suggestions[suggestionInfo.mSuggestionIndex] = originalText;
 
         // Restore previous SuggestionSpans
@@ -2572,31 +2648,6 @@
         }
     };
 
-    private final MenuItem.OnMenuItemClickListener mOnContextMenuReplaceItemClickListener =
-            new MenuItem.OnMenuItemClickListener() {
-        @Override
-        public boolean onMenuItemClick(MenuItem item) {
-            int index = item.getOrder();
-            if (index < 0 || index >= mSuggestionInfosInContextMenu.length) {
-                clear();
-                return false;
-            }
-            final Spannable spannable = (Spannable) mTextView.getText();
-            final SuggestionSpan suggestionSpan =
-                    mSuggestionInfosInContextMenu[index].mSuggestionSpan;
-            replaceWithSuggestion(mSuggestionInfosInContextMenu[index],
-                    spannable.getSpanStart(suggestionSpan), spannable.getSpanEnd(suggestionSpan));
-            clear();
-            return true;
-        }
-
-        private void clear() {
-            for (final SuggestionInfo info : mSuggestionInfosInContextMenu) {
-                info.clear();
-            }
-        }
-    };
-
     /**
      * Controls the {@link EasyEditSpan} monitoring when it is added, and when the related
      * pop-up should be displayed.
@@ -3015,13 +3066,12 @@
         }
     }
 
-    private static class SuggestionInfo {
-        // Range of actual suggestion within text
+    private static final class SuggestionInfo {
+        // Range of actual suggestion within mText
         int mSuggestionStart, mSuggestionEnd;
 
         // The SuggestionSpan that this TextView represents
-        @Nullable
-        SuggestionSpan mSuggestionSpan;
+        final SuggestionSpanInfo mSuggestionSpanInfo = new SuggestionSpanInfo();
 
         // The index of this suggestion inside suggestionSpan
         int mSuggestionIndex;
@@ -3029,9 +3079,32 @@
         final SpannableStringBuilder mText = new SpannableStringBuilder();
 
         void clear() {
-            mSuggestionSpan = null;
+            mSuggestionSpanInfo.clear();
             mText.clear();
         }
+
+        // Utility method to set attributes about a SuggestionSpan.
+        void setSpanInfo(SuggestionSpan span, int spanStart, int spanEnd) {
+            mSuggestionSpanInfo.mSuggestionSpan = span;
+            mSuggestionSpanInfo.mSpanStart = spanStart;
+            mSuggestionSpanInfo.mSpanEnd = spanEnd;
+        }
+    }
+
+    private static final class SuggestionSpanInfo {
+        // The SuggestionSpan;
+        @Nullable
+        SuggestionSpan mSuggestionSpan;
+
+        // The SuggestionSpan start position
+        int mSpanStart;
+
+        // The SuggestionSpan end position
+        int mSpanEnd;
+
+        void clear() {
+            mSuggestionSpan = null;
+        }
     }
 
     private class SuggestionHelper {
@@ -3089,43 +3162,48 @@
          * position.
          *
          * @param suggestionInfos SuggestionInfo array the results will be set.
+         * @param misspelledSpanInfo a struct the misspelled SuggestionSpan info will be set.
          * @return the number of suggestions actually fetched.
          */
-        public int getSuggestionInfo(SuggestionInfo[] suggestionInfos) {
+        public int getSuggestionInfo(SuggestionInfo[] suggestionInfos,
+                @Nullable SuggestionSpanInfo misspelledSpanInfo) {
             final Spannable spannable = (Spannable) mTextView.getText();
             final SuggestionSpan[] suggestionSpans = getSortedSuggestionSpans();
             final int nbSpans = suggestionSpans.length;
             if (nbSpans == 0) return 0;
 
             int numberOfSuggestions = 0;
-            for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) {
-                final SuggestionSpan suggestionSpan = suggestionSpans[spanIndex];
+            for (final SuggestionSpan suggestionSpan : suggestionSpans) {
                 final int spanStart = spannable.getSpanStart(suggestionSpan);
                 final int spanEnd = spannable.getSpanEnd(suggestionSpan);
 
+                if (misspelledSpanInfo != null
+                        && (suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+                    misspelledSpanInfo.mSuggestionSpan = suggestionSpan;
+                    misspelledSpanInfo.mSpanStart = spanStart;
+                    misspelledSpanInfo.mSpanEnd = spanEnd;
+                }
+
                 final String[] suggestions = suggestionSpan.getSuggestions();
                 final int nbSuggestions = suggestions.length;
+                suggestionLoop:
                 for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
                     final String suggestion = suggestions[suggestionIndex];
-                    boolean suggestionIsDuplicate = false;
                     for (int i = 0; i < numberOfSuggestions; i++) {
-                        if (suggestionInfos[i].mText.toString().equals(suggestion)) {
-                            final SuggestionSpan otherSuggestionSpan =
-                                    suggestionInfos[i].mSuggestionSpan;
-                            final int otherSpanStart = spannable.getSpanStart(otherSuggestionSpan);
-                            final int otherSpanEnd = spannable.getSpanEnd(otherSuggestionSpan);
+                        final SuggestionInfo otherSuggestionInfo = suggestionInfos[i];
+                        if (otherSuggestionInfo.mText.toString().equals(suggestion)) {
+                            final int otherSpanStart =
+                                    otherSuggestionInfo.mSuggestionSpanInfo.mSpanStart;
+                            final int otherSpanEnd =
+                                    otherSuggestionInfo.mSuggestionSpanInfo.mSpanEnd;
                             if (spanStart == otherSpanStart && spanEnd == otherSpanEnd) {
-                                suggestionIsDuplicate = true;
-                                break;
+                                continue suggestionLoop;
                             }
                         }
                     }
 
-                    if (suggestionIsDuplicate) {
-                        continue;
-                    }
                     SuggestionInfo suggestionInfo = suggestionInfos[numberOfSuggestions];
-                    suggestionInfo.mSuggestionSpan = suggestionSpan;
+                    suggestionInfo.setSpanInfo(suggestionSpan, spanStart, spanEnd);
                     suggestionInfo.mSuggestionIndex = suggestionIndex;
                     suggestionInfo.mSuggestionStart = 0;
                     suggestionInfo.mSuggestionEnd = suggestion.length();
@@ -3157,7 +3235,8 @@
                 mTextView.getContext(), mTextView.mTextEditSuggestionHighlightStyle);
         private TextView mAddToDictionaryButton;
         private TextView mDeleteButton;
-        private SuggestionSpan mMisspelledSpan;
+        private ListView mSuggestionListView;
+        private final SuggestionSpanInfo mMisspelledSpanInfo = new SuggestionSpanInfo();
         private int mContainerMarginWidth;
         private int mContainerMarginTop;
 
@@ -3174,7 +3253,7 @@
                 ((Spannable) mTextView.getText()).removeSpan(mSuggestionRangeSpan);
 
                 mTextView.setCursorVisible(mCursorWasVisibleBeforeSuggestions);
-                if (hasInsertionController()) {
+                if (hasInsertionController() && !extractedTextModeWillBeStarted()) {
                     getInsertionController().show();
                 }
             }
@@ -3210,12 +3289,12 @@
             mClippingLimitLeft = lp.leftMargin;
             mClippingLimitRight = lp.rightMargin;
 
-            final ListView suggestionListView = (ListView) relativeLayout.findViewById(
+            mSuggestionListView = (ListView) relativeLayout.findViewById(
                     com.android.internal.R.id.suggestionContainer);
 
             mSuggestionsAdapter = new SuggestionAdapter();
-            suggestionListView.setAdapter(mSuggestionsAdapter);
-            suggestionListView.setOnItemClickListener(this);
+            mSuggestionListView.setAdapter(mSuggestionsAdapter);
+            mSuggestionListView.setOnItemClickListener(this);
 
             // Inflate the suggestion items once and for all.
             mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
@@ -3229,9 +3308,18 @@
                     com.android.internal.R.id.addToDictionaryButton);
             mAddToDictionaryButton.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
+                    final SuggestionSpan misspelledSpan =
+                            findEquivalentSuggestionSpan(mMisspelledSpanInfo);
+                    if (misspelledSpan == null) {
+                        // Span has been removed.
+                        return;
+                    }
                     final Editable editable = (Editable) mTextView.getText();
-                    final int spanStart = editable.getSpanStart(mMisspelledSpan);
-                    final int spanEnd = editable.getSpanEnd(mMisspelledSpan);
+                    final int spanStart = editable.getSpanStart(misspelledSpan);
+                    final int spanEnd = editable.getSpanEnd(misspelledSpan);
+                    if (spanStart < 0 || spanEnd <= spanStart) {
+                        return;
+                    }
                     final String originalText = TextUtils.substring(editable, spanStart, spanEnd);
 
                     final Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
@@ -3242,7 +3330,7 @@
                     mTextView.getContext().startActivity(intent);
                     // There is no way to know if the word was indeed added. Re-check.
                     // TODO The ExtractEditText should remove the span in the original text instead
-                    editable.removeSpan(mMisspelledSpan);
+                    editable.removeSpan(mMisspelledSpanInfo.mSuggestionSpan);
                     Selection.setSelection(editable, spanEnd);
                     updateSpellCheckSpans(spanStart, spanEnd, false);
                     hideWithCleanUp();
@@ -3324,6 +3412,9 @@
         @Override
         public void show() {
             if (!(mTextView.getText() instanceof Editable)) return;
+            if (extractedTextModeWillBeStarted()) {
+                return;
+            }
 
             if (updateSuggestions()) {
                 mCursorWasVisibleBeforeSuggestions = mCursorVisible;
@@ -3371,12 +3462,13 @@
                 popupBackground.getPadding(mTempRect);
                 width += mTempRect.left + mTempRect.right;
             }
+            mSuggestionListView.getLayoutParams().width = width;
             mPopupWindow.setWidth(width);
         }
 
         @Override
         protected int getTextOffset() {
-            return mTextView.getSelectionStart();
+            return (mTextView.getSelectionStart() + mTextView.getSelectionStart()) / 2;
         }
 
         @Override
@@ -3395,32 +3487,29 @@
             for (final SuggestionInfo info : mSuggestionInfos) {
                 info.clear();
             }
-            mMisspelledSpan = null;
+            mMisspelledSpanInfo.clear();
             hide();
         }
 
         private boolean updateSuggestions() {
             Spannable spannable = (Spannable) mTextView.getText();
             mNumberOfSuggestions =
-                    mSuggestionHelper.getSuggestionInfo(mSuggestionInfos);
-            if (mNumberOfSuggestions == 0) {
+                    mSuggestionHelper.getSuggestionInfo(mSuggestionInfos, mMisspelledSpanInfo);
+            if (mNumberOfSuggestions == 0 && mMisspelledSpanInfo.mSuggestionSpan == null) {
                 return false;
             }
 
             int spanUnionStart = mTextView.getText().length();
             int spanUnionEnd = 0;
 
-            mMisspelledSpan = null;
             for (int i = 0; i < mNumberOfSuggestions; i++) {
-                final SuggestionInfo suggestionInfo = mSuggestionInfos[i];
-                final SuggestionSpan suggestionSpan = suggestionInfo.mSuggestionSpan;
-                if ((suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) {
-                    mMisspelledSpan = suggestionSpan;
-                }
-                final int spanStart = spannable.getSpanStart(suggestionSpan);
-                final int spanEnd = spannable.getSpanEnd(suggestionSpan);
-                spanUnionStart = Math.min(spanUnionStart, spanStart);
-                spanUnionEnd = Math.max(spanUnionEnd, spanEnd);
+                final SuggestionSpanInfo spanInfo = mSuggestionInfos[i].mSuggestionSpanInfo;
+                spanUnionStart = Math.min(spanUnionStart, spanInfo.mSpanStart);
+                spanUnionEnd = Math.max(spanUnionEnd, spanInfo.mSpanEnd);
+            }
+            if (mMisspelledSpanInfo.mSuggestionSpan != null) {
+                spanUnionStart = Math.min(spanUnionStart, mMisspelledSpanInfo.mSpanStart);
+                spanUnionEnd = Math.max(spanUnionEnd, mMisspelledSpanInfo.mSpanEnd);
             }
 
             for (int i = 0; i < mNumberOfSuggestions; i++) {
@@ -3429,17 +3518,23 @@
 
             // Make "Add to dictionary" item visible if there is a span with the misspelled flag
             int addToDictionaryButtonVisibility = View.GONE;
-            if (mMisspelledSpan != null) {
-                final int misspelledStart = spannable.getSpanStart(mMisspelledSpan);
-                final int misspelledEnd = spannable.getSpanEnd(mMisspelledSpan);
-                if (misspelledStart >= 0 && misspelledEnd > misspelledStart) {
+            if (mMisspelledSpanInfo.mSuggestionSpan != null) {
+                if (mMisspelledSpanInfo.mSpanStart >= 0
+                        && mMisspelledSpanInfo.mSpanEnd > mMisspelledSpanInfo.mSpanStart) {
                     addToDictionaryButtonVisibility = View.VISIBLE;
                 }
             }
             mAddToDictionaryButton.setVisibility(addToDictionaryButtonVisibility);
 
             if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
-            final int underlineColor = mSuggestionInfos[0].mSuggestionSpan.getUnderlineColor();
+            final int underlineColor;
+            if (mNumberOfSuggestions != 0) {
+                underlineColor =
+                        mSuggestionInfos[0].mSuggestionSpanInfo.mSuggestionSpan.getUnderlineColor();
+            } else {
+                underlineColor = mMisspelledSpanInfo.mSuggestionSpan.getUnderlineColor();
+            }
+
             if (underlineColor == 0) {
                 // Fallback on the default highlight color when the first span does not provide one
                 mSuggestionRangeSpan.setBackgroundColor(mTextView.mHighlightColor);
@@ -3459,8 +3554,8 @@
         private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
                 int unionEnd) {
             final Spannable text = (Spannable) mTextView.getText();
-            final int spanStart = text.getSpanStart(suggestionInfo.mSuggestionSpan);
-            final int spanEnd = text.getSpanEnd(suggestionInfo.mSuggestionSpan);
+            final int spanStart = suggestionInfo.mSuggestionSpanInfo.mSpanStart;
+            final int spanEnd = suggestionInfo.mSuggestionSpanInfo.mSpanEnd;
 
             // Adjust the start/end of the suggestion span
             suggestionInfo.mSuggestionStart = spanStart - unionStart;
@@ -3478,17 +3573,8 @@
 
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            Editable editable = (Editable) mTextView.getText();
             SuggestionInfo suggestionInfo = mSuggestionInfos[position];
-
-            final int spanStart = editable.getSpanStart(suggestionInfo.mSuggestionSpan);
-            final int spanEnd = editable.getSpanEnd(suggestionInfo.mSuggestionSpan);
-            if (spanStart < 0 || spanEnd <= spanStart) {
-                // Span has been removed
-                hideWithCleanUp();
-                return;
-            }
-            replaceWithSuggestion(suggestionInfo, spanStart, spanEnd);
+            replaceWithSuggestion(suggestionInfo);
             hideWithCleanUp();
         }
     }
@@ -3551,7 +3637,9 @@
             }
 
             if (menu.hasVisibleItems() || mode.getCustomView() != null) {
-                mTextView.setHasTransientState(true);
+                if (mHasSelection && !mTextView.hasTransientState()) {
+                    mTextView.setHasTransientState(true);
+                }
                 return true;
             } else {
                 return false;
@@ -3621,8 +3709,7 @@
         }
 
         private void updateReplaceItem(Menu menu) {
-            boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions()
-                    && !(mTextView.isInExtractedMode() && mTextView.hasSelection());
+            boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions();
             boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null;
             if (canReplace && !replaceItemExists) {
                 menu.add(Menu.NONE, TextView.ID_REPLACE, MENU_ITEM_ORDER_REPLACE,
@@ -3647,27 +3734,26 @@
 
         @Override
         public void onDestroyActionMode(ActionMode mode) {
+            // Clear mTextActionMode not to recursively destroy action mode by clearing selection.
+            mTextActionMode = null;
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
                 customCallback.onDestroyActionMode(mode);
             }
 
-            /*
-             * If we're ending this mode because we're detaching from a window,
-             * we still have selection state to preserve. Don't clear it, we'll
-             * bring back the selection mode when (if) we get reattached.
-             */
-            if (!mPreserveDetachedSelection) {
+            if (!mPreserveSelection) {
+                /*
+                 * Leave current selection when we tentatively destroy action mode for the
+                 * selection. If we're detaching from a window, we'll bring back the selection
+                 * mode when (if) we get reattached.
+                 */
                 Selection.setSelection((Spannable) mTextView.getText(),
                         mTextView.getSelectionEnd());
-                mTextView.setHasTransientState(false);
             }
 
             if (mSelectionModifierCursorController != null) {
                 mSelectionModifierCursorController.hide();
             }
-
-            mTextActionMode = null;
         }
 
         @Override
@@ -3696,10 +3782,10 @@
                                 + mHandleHeight);
             } else {
                 // We have a single cursor.
-                Layout layout = getActiveLayout();
+                Layout layout = mTextView.getLayout();
                 int line = layout.getLineForOffset(mTextView.getSelectionStart());
-                float primaryHorizontal =
-                        layout.getPrimaryHorizontal(mTextView.getSelectionStart());
+                float primaryHorizontal = clampHorizontalPosition(null,
+                        layout.getPrimaryHorizontal(mTextView.getSelectionStart()));
                 mSelectionBounds.set(
                         primaryHorizontal,
                         layout.getLineTop(line),
@@ -3948,14 +4034,17 @@
                 // Don't update drawable during dragging.
                 return;
             }
+            final Layout layout = mTextView.getLayout();
+            if (layout == null) {
+                return;
+            }
             final int offset = getCurrentCursorOffset();
-            final boolean isRtlCharAtOffset = mTextView.getLayout().isRtlCharAt(offset);
+            final boolean isRtlCharAtOffset = isAtRtlRun(layout, offset);
             final Drawable oldDrawable = mDrawable;
             mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
             mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset);
             mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset);
-            final Layout layout = mTextView.getLayout();
-            if (layout != null && oldDrawable != mDrawable && isShowing()) {
+            if (oldDrawable != mDrawable && isShowing()) {
                 // Update popup window position.
                 mPositionX = getCursorHorizontalPosition(layout, offset) - mHotspotX -
                         getHorizontalOffset() + getCursorOffset();
@@ -4068,6 +4157,19 @@
 
         public abstract void updatePosition(float x, float y);
 
+        protected boolean isAtRtlRun(@NonNull Layout layout, int offset) {
+            return layout.isRtlCharAt(offset);
+        }
+
+        @VisibleForTesting
+        public float getHorizontal(@NonNull Layout layout, int offset) {
+            return layout.getPrimaryHorizontal(offset);
+        }
+
+        protected int getOffsetAtCoordinate(@NonNull Layout layout, int line, float x) {
+            return mTextView.getOffsetAtCoordinate(line, x);
+        }
+
         protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
             // A HandleView relies on the layout, which may be nulled by external methods
             Layout layout = mTextView.getLayout();
@@ -4076,7 +4178,7 @@
                 prepareCursorControllers();
                 return;
             }
-            layout = getActiveLayout();
+            layout = mTextView.getLayout();
 
             boolean offsetChanged = offset != mPreviousOffset;
             if (offsetChanged || parentScrolled) {
@@ -4108,7 +4210,7 @@
          * @return The clamped horizontal position for the cursor.
          */
         int getCursorHorizontalPosition(Layout layout, int offset) {
-            return (int) (layout.getPrimaryHorizontal(offset) - 0.5f);
+            return (int) (getHorizontal(layout, offset) - 0.5f);
         }
 
         public void updatePosition(int parentPositionX, int parentPositionY,
@@ -4128,13 +4230,15 @@
                 }
 
                 if (isVisible()) {
-                    final int positionX = parentPositionX + mPositionX;
-                    final int positionY = parentPositionY + mPositionY;
+                    // Transform to the window coordinates to follow the view tranformation.
+                    final int[] pts = { mPositionX + mHotspotX + getHorizontalOffset(), mPositionY};
+                    mTextView.transformFromViewToWindowSpace(pts);
+                    pts[0] -= mHotspotX + getHorizontalOffset();
+
                     if (isShowing()) {
-                        mContainer.update(positionX, positionY, -1, -1);
+                        mContainer.update(pts[0], pts[1], -1, -1);
                     } else {
-                        mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY,
-                                positionX, positionY);
+                        mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY, pts[0], pts[1]);
                     }
                 } else {
                     if (isShowing()) {
@@ -4244,19 +4348,6 @@
         public void onDetached() {}
     }
 
-    /**
-     * Returns the active layout (hint or text layout). Note that the text layout can be null.
-     */
-    private Layout getActiveLayout() {
-        Layout layout = mTextView.getLayout();
-        Layout hintLayout = mTextView.getHintLayout();
-        if (TextUtils.isEmpty(layout.getText()) && hintLayout != null &&
-                !TextUtils.isEmpty(hintLayout.getText())) {
-            layout = hintLayout;
-        }
-        return layout;
-    }
-
     private class InsertionHandleView extends HandleView {
         private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000;
         private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds
@@ -4352,8 +4443,8 @@
         int getCursorHorizontalPosition(Layout layout, int offset) {
             final Drawable drawable = mCursorCount > 0 ? mCursorDrawable[0] : null;
             if (drawable != null) {
-                final float horizontal = layout.getPrimaryHorizontal(offset);
-                return clampCursorHorizontalPosition(drawable, horizontal) + mTempRect.left;
+                final float horizontal = getHorizontal(layout, offset);
+                return clampHorizontalPosition(drawable, horizontal) + mTempRect.left;
             }
             return super.getCursorHorizontalPosition(layout, offset);
         }
@@ -4381,7 +4472,7 @@
                         if (distanceSquared < touchSlop * touchSlop) {
                             // Tapping on the handle toggles the insertion action mode.
                             if (mTextActionMode != null) {
-                                mTextActionMode.finish();
+                                stopTextActionMode();
                             } else {
                                 startInsertionActionMode();
                             }
@@ -4424,10 +4515,10 @@
                     mPreviousLineTouched = mTextView.getLineAtCoordinate(y);
                 }
                 int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y);
-                offset = mTextView.getOffsetAtCoordinate(currLine, x);
+                offset = getOffsetAtCoordinate(layout, currLine, x);
                 mPreviousLineTouched = currLine;
             } else {
-                offset = mTextView.getOffsetForPosition(x, y);
+                offset = -1;
             }
             positionAtCursorOffset(offset, false);
             if (mTextActionMode != null) {
@@ -4537,14 +4628,14 @@
             final int anotherHandleOffset =
                     isStartHandle() ? mTextView.getSelectionEnd() : mTextView.getSelectionStart();
             int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y);
-            int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x);
+            int initialOffset = getOffsetAtCoordinate(layout, currLine, x);
 
             if (isStartHandle() && initialOffset >= anotherHandleOffset
                     || !isStartHandle() && initialOffset <= anotherHandleOffset) {
                 // Handles have crossed, bound it to the first selected line and
                 // adjust by word / char as normal.
                 currLine = layout.getLineForOffset(anotherHandleOffset);
-                initialOffset = mTextView.getOffsetAtCoordinate(currLine, x);
+                initialOffset = getOffsetAtCoordinate(layout, currLine, x);
             }
 
             int offset = initialOffset;
@@ -4556,8 +4647,8 @@
             }
 
             final int currentOffset = getCurrentCursorOffset();
-            final boolean rtlAtCurrentOffset = layout.isRtlCharAt(currentOffset);
-            final boolean atRtl = layout.isRtlCharAt(offset);
+            final boolean rtlAtCurrentOffset = isAtRtlRun(layout, currentOffset);
+            final boolean atRtl = isAtRtlRun(layout, offset);
             final boolean isLvlBoundary = layout.isLevelBoundary(offset);
 
             // We can't determine if the user is expanding or shrinking the selection if they're
@@ -4614,14 +4705,15 @@
 
             if (isExpanding) {
                 // User is increasing the selection.
-                final boolean snapToWord = !mInWord
-                        || (isStartHandle() ? currLine < mPrevLine : currLine > mPrevLine);
+                int wordBoundary = isStartHandle() ? wordStart : wordEnd;
+                final boolean snapToWord = (!mInWord
+                        || (isStartHandle() ? currLine < mPrevLine : currLine > mPrevLine))
+                                && atRtl == isAtRtlRun(layout, wordBoundary);
                 if (snapToWord) {
                     // Sometimes words can be broken across lines (Chinese, hyphenation).
                     // We still snap to the word boundary but we only use the letters on the
                     // current line to determine if the user is far enough into the word to snap.
-                    int wordBoundary = isStartHandle() ? wordStart : wordEnd;
-                    if (layout != null && layout.getLineForOffset(wordBoundary) != currLine) {
+                    if (layout.getLineForOffset(wordBoundary) != currLine) {
                         wordBoundary = isStartHandle() ?
                                 layout.getLineStart(currLine) : layout.getLineEnd(currLine);
                     }
@@ -4642,9 +4734,9 @@
                         offset = mPreviousOffset;
                     }
                 }
-                if (layout != null && (isStartHandle() && offset < initialOffset)
+                if ((isStartHandle() && offset < initialOffset)
                         || (!isStartHandle() && offset > initialOffset)) {
-                    final float adjustedX = layout.getPrimaryHorizontal(offset);
+                    final float adjustedX = getHorizontal(layout, offset);
                     mTouchWordDelta =
                             mTextView.convertToLocalHorizontalCoordinate(x) - adjustedX;
                 } else {
@@ -4653,7 +4745,7 @@
                 positionCursor = true;
             } else {
                 final int adjustedOffset =
-                        mTextView.getOffsetAtCoordinate(currLine, x - mTouchWordDelta);
+                        getOffsetAtCoordinate(layout, currLine, x - mTouchWordDelta);
                 final boolean shrinking = isStartHandle()
                         ? adjustedOffset > mPreviousOffset || currLine > mPrevLine
                         : adjustedOffset < mPreviousOffset || currLine < mPrevLine;
@@ -4662,9 +4754,9 @@
                     if (currLine != mPrevLine) {
                         // We're on a different line, so we'll snap to word boundaries.
                         offset = isStartHandle() ? wordStart : wordEnd;
-                        if (layout != null && (isStartHandle() && offset < initialOffset)
+                        if ((isStartHandle() && offset < initialOffset)
                                 || (!isStartHandle() && offset > initialOffset)) {
-                            final float adjustedX = layout.getPrimaryHorizontal(offset);
+                            final float adjustedX = getHorizontal(layout, offset);
                             mTouchWordDelta =
                                     mTextView.convertToLocalHorizontalCoordinate(x) - adjustedX;
                         } else {
@@ -4679,7 +4771,7 @@
                     // Handle has jumped to the word boundary, and the user is moving
                     // their finger towards the handle, the delta should be updated.
                     mTouchWordDelta = mTextView.convertToLocalHorizontalCoordinate(x) -
-                            layout.getPrimaryHorizontal(mPreviousOffset);
+                            getHorizontal(layout, mPreviousOffset);
                 }
             }
 
@@ -4717,9 +4809,32 @@
                     isStartHandle() ? mTextView.getSelectionEnd() : mTextView.getSelectionStart();
             if ((isStartHandle() && offset >= anotherHandleOffset)
                     || (!isStartHandle() && offset <= anotherHandleOffset)) {
+                mTouchWordDelta = 0.0f;
+                final Layout layout = mTextView.getLayout();
+                if (layout != null && offset != anotherHandleOffset) {
+                    final float horiz = getHorizontal(layout, offset);
+                    final float anotherHandleHoriz = getHorizontal(layout, anotherHandleOffset,
+                            !isStartHandle());
+                    final float currentHoriz = getHorizontal(layout, mPreviousOffset);
+                    if (currentHoriz < anotherHandleHoriz && horiz < anotherHandleHoriz
+                            || currentHoriz > anotherHandleHoriz && horiz > anotherHandleHoriz) {
+                        // This handle passes another one as it crossed a direction boundary.
+                        // Don't minimize the selection, but keep the handle at the run boundary.
+                        final int currentOffset = getCurrentCursorOffset();
+                        final int offsetToGetRunRange = isStartHandle() ?
+                                currentOffset : Math.max(currentOffset - 1, 0);
+                        final long range = layout.getRunRange(offsetToGetRunRange);
+                        if (isStartHandle()) {
+                            offset = TextUtils.unpackRangeStartFromLong(range);
+                        } else {
+                            offset = TextUtils.unpackRangeEndFromLong(range);
+                        }
+                        positionAtCursorOffset(offset, false);
+                        return;
+                    }
+                }
                 // Handles can not cross and selection is at least one character.
                 offset = getNextCursorOffset(anotherHandleOffset, !isStartHandle());
-                mTouchWordDelta = 0.0f;
             }
             positionAtCursorOffset(offset, false);
         }
@@ -4737,6 +4852,50 @@
             }
             return nearEdge;
         }
+
+        @Override
+        protected boolean isAtRtlRun(@NonNull Layout layout, int offset) {
+            final int offsetToCheck = isStartHandle() ? offset : Math.max(offset - 1, 0);
+            return layout.isRtlCharAt(offsetToCheck);
+        }
+
+        @Override
+        public float getHorizontal(@NonNull Layout layout, int offset) {
+            return getHorizontal(layout, offset, isStartHandle());
+        }
+
+        private float getHorizontal(@NonNull Layout layout, int offset, boolean startHandle) {
+            final int line = layout.getLineForOffset(offset);
+            final int offsetToCheck = startHandle ? offset : Math.max(offset - 1, 0);
+            final boolean isRtlChar = layout.isRtlCharAt(offsetToCheck);
+            final boolean isRtlParagraph = layout.getParagraphDirection(line) == -1;
+            return (isRtlChar == isRtlParagraph) ?
+                    layout.getPrimaryHorizontal(offset) : layout.getSecondaryHorizontal(offset);
+        }
+
+        @Override
+        protected int getOffsetAtCoordinate(@NonNull Layout layout, int line, float x) {
+            final float localX = mTextView.convertToLocalHorizontalCoordinate(x);
+            final int primaryOffset = layout.getOffsetForHorizontal(line, localX, true);
+            if (!layout.isLevelBoundary(primaryOffset)) {
+                return primaryOffset;
+            }
+            final int secondaryOffset = layout.getOffsetForHorizontal(line, localX, false);
+            final int currentOffset = getCurrentCursorOffset();
+            final int primaryDiff = Math.abs(primaryOffset - currentOffset);
+            final int secondaryDiff = Math.abs(secondaryOffset - currentOffset);
+            if (primaryDiff < secondaryDiff) {
+                return primaryOffset;
+            } else if (primaryDiff > secondaryDiff) {
+                return secondaryOffset;
+            } else {
+                final int offsetToCheck = isStartHandle() ?
+                        currentOffset : Math.max(currentOffset - 1, 0);
+                final boolean isRtlChar = layout.isRtlCharAt(offsetToCheck);
+                final boolean isRtlParagraph = layout.getParagraphDirection(line) == -1;
+                return isRtlChar == isRtlParagraph ? primaryOffset : secondaryOffset;
+            }
+        }
     }
 
     private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) {
@@ -4798,6 +4957,10 @@
          * preventing the activity from being recycled.
          */
         public void onDetached();
+
+        public boolean isCursorBeingModified();
+
+        public boolean isActive();
     }
 
     private class InsertionPointCursorController implements CursorController {
@@ -4841,6 +5004,16 @@
 
             if (mHandle != null) mHandle.onDetached();
         }
+
+        @Override
+        public boolean isCursorBeingModified() {
+            return mHandle != null && mHandle.isDragging();
+        }
+
+        @Override
+        public boolean isActive() {
+            return mHandle != null && mHandle.isShowing();
+        }
     }
 
     class SelectionModifierCursorController implements CursorController {
@@ -5030,9 +5203,7 @@
 
                         if (mStartOffset != offset) {
                             // Start character based drag accelerator.
-                            if (mTextActionMode != null) {
-                                mTextActionMode.finish();
-                            }
+                            stopTextActionMode();
                             enterDrag(DRAG_ACCELERATOR_MODE_CHARACTER);
                             mDiscardNextActionUp = true;
                             mHaventMovedEnoughToStartDrag = false;
@@ -5056,27 +5227,12 @@
                     // No longer dragging to select text, let the parent intercept events.
                     mTextView.getParent().requestDisallowInterceptTouchEvent(false);
 
-                    int startOffset = mTextView.getSelectionStart();
-                    int endOffset = mTextView.getSelectionEnd();
-
-                    // Since we don't let drag handles pass once they're visible, we need to
-                    // make sure the start / end locations are correct because the user *can*
-                    // switch directions during the initial drag.
-                    if (endOffset < startOffset) {
-                        int tmp = endOffset;
-                        endOffset = startOffset;
-                        startOffset = tmp;
-
-                        // Also update the selection with the right offsets in this case.
-                        Selection.setSelection((Spannable) mTextView.getText(),
-                                startOffset, endOffset);
-                    }
-                    if (startOffset != endOffset) {
-                        startSelectionActionMode();
-                    }
-
                     // No longer the first dragging motion, reset.
                     resetDragAcceleratorState();
+
+                    if (mTextView.hasSelection()) {
+                        startSelectionActionMode();
+                    }
                     break;
             }
         }
@@ -5106,9 +5262,7 @@
             if (mInsertionActionModeRunnable != null) {
                 mTextView.removeCallbacks(mInsertionActionModeRunnable);
             }
-            if (mTextActionMode != null) {
-                mTextActionMode.finish();
-            }
+            stopTextActionMode();
             if (!selectCurrentParagraph()) {
                 return false;
             }
@@ -5217,6 +5371,12 @@
             mStartOffset = -1;
             mDragAcceleratorMode = DRAG_ACCELERATOR_MODE_INACTIVE;
             mSwitchedLines = false;
+            final int selectionStart = mTextView.getSelectionStart();
+            final int selectionEnd = mTextView.getSelectionEnd();
+            if (selectionStart > selectionEnd) {
+                Selection.setSelection((Spannable) mTextView.getText(),
+                        selectionEnd, selectionStart);
+            }
         }
 
         /**
@@ -5226,6 +5386,12 @@
             return mStartHandle != null && mStartHandle.isDragging();
         }
 
+        @Override
+        public boolean isCursorBeingModified() {
+            return isDragAcceleratorActive() || isSelectionStartDragged()
+                    || (mEndHandle != null && mEndHandle.isDragging());
+        }
+
         /**
          * @return true if the user is selecting text using the drag accelerator.
          */
@@ -5247,6 +5413,11 @@
             if (mStartHandle != null) mStartHandle.onDetached();
             if (mEndHandle != null) mEndHandle.onDetached();
         }
+
+        @Override
+        public boolean isActive() {
+            return mStartHandle != null && mStartHandle.isShowing();
+        }
     }
 
     private class CorrectionHighlighter {
@@ -5442,6 +5613,9 @@
         // rotates the screen during composition.
         private boolean mHasComposition;
 
+        // Whether to merge events into one operation.
+        private boolean mForceMerge;
+
         public UndoInputFilter(Editor editor) {
             mEditor = editor;
         }
@@ -5456,6 +5630,10 @@
             mHasComposition = parcel.readInt() != 0;
         }
 
+        public void setForceMerge(boolean forceMerge) {
+            mForceMerge = forceMerge;
+        }
+
         /**
          * Signals that a user-triggered edit is starting.
          */
@@ -5515,7 +5693,7 @@
                 // Otherwise the user inserted the composition.
                 String newText = TextUtils.substring(source, start, end);
                 EditOperation edit = new EditOperation(mEditor, "", dstart, newText);
-                recordEdit(edit, false /* forceMerge */);
+                recordEdit(edit, mForceMerge);
                 return true;
             }
 
@@ -5529,7 +5707,7 @@
             // the initial input filters run (e.g. a credit card formatter that adds spaces to a
             // string). This results in multiple filter() calls for what the user considers to be
             // a single operation. Always undo the whole set of changes in one step.
-            final boolean forceMerge = isInTextWatcher();
+            final boolean forceMerge = mForceMerge || isInTextWatcher();
 
             // Build a new operation with all the information from this edit.
             String newText = TextUtils.substring(source, start, end);
@@ -5970,7 +6148,7 @@
         private boolean fireIntent(Intent intent) {
             if (intent != null && Intent.ACTION_PROCESS_TEXT.equals(intent.getAction())) {
                 intent.putExtra(Intent.EXTRA_PROCESS_TEXT, mTextView.getSelectedText());
-                mEditor.mPreserveDetachedSelection = true;
+                mEditor.mPreserveSelection = true;
                 mTextView.startActivityForResult(intent, TextView.PROCESS_TEXT_REQUEST_CODE);
                 return true;
             }
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 280ff15..9ac4917 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -16,17 +16,15 @@
 
 package android.widget;
 
-import java.util.ArrayList;
+import com.android.internal.R;
 
+import android.annotation.AttrRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.Gravity;
@@ -36,8 +34,7 @@
 import android.view.ViewHierarchyEncoder;
 import android.widget.RemoteViews.RemoteView;
 
-import com.android.internal.R;
-
+import java.util.ArrayList;
 
 /**
  * FrameLayout is designed to block out an area on the screen to display
@@ -75,31 +72,29 @@
     @ViewDebug.ExportedProperty(category = "padding")
     private int mForegroundPaddingBottom = 0;
 
-    private final Rect mSelfBounds = new Rect();
-    private final Rect mOverlayBounds = new Rect();
-    
-    private final ArrayList<View> mMatchParentChildren = new ArrayList<View>(1);
-    
-    public FrameLayout(Context context) {
+    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+    public FrameLayout(@NonNull Context context) {
         super(context);
     }
-    
-    public FrameLayout(Context context, @Nullable AttributeSet attrs) {
+
+    public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+    public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public FrameLayout(
-            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.FrameLayout, defStyleAttr, defStyleRes);
-        
-        if (a.getBoolean(com.android.internal.R.styleable.FrameLayout_measureAllChildren, false)) {
+                attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes);
+
+        if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) {
             setMeasureAllChildren(true);
         }
 
@@ -171,10 +166,6 @@
             mPaddingBottom + mForegroundPaddingBottom;
     }
 
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int count = getChildCount();
@@ -264,17 +255,13 @@
             }
         }
     }
- 
-    /**
-     * {@inheritDoc}
-     */
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         layoutChildren(left, top, right, bottom, false /* no force left gravity */);
     }
 
-    void layoutChildren(int left, int top, int right, int bottom,
-                                  boolean forceLeftGravity) {
+    void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
         final int count = getChildCount();
 
         final int parentLeft = getPaddingLeftWithForeground();
@@ -378,12 +365,9 @@
         return mMeasureAllChildren;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new FrameLayout.LayoutParams(getContext(), attrs);        
+        return new FrameLayout.LayoutParams(getContext(), attrs);
     }
 
     @Override
@@ -391,17 +375,20 @@
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
         return p instanceof LayoutParams;
     }
 
     @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new LayoutParams(p);
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) lp);
+        } else if (lp instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) lp);
+        } else {
+            return new LayoutParams(lp);
+        }
     }
 
     @Override
@@ -425,34 +412,30 @@
      * Per-child layout information for layouts that support margins.
      * See {@link android.R.styleable#FrameLayout_Layout FrameLayout Layout Attributes}
      * for a list of all child view attributes that this class supports.
-     * 
+     *
      * @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
      */
     public static class LayoutParams extends MarginLayoutParams {
         /**
          * The gravity to apply with the View to which these layout parameters
          * are associated.
+         * <p>
+         * The default value is {@code Gravity.TOP | Gravity.START}
          *
          * @see android.view.Gravity
-         * 
          * @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
          */
-        public int gravity = -1;
+        public int gravity = DEFAULT_CHILD_GRAVITY;
 
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(Context c, AttributeSet attrs) {
+        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
             super(c, attrs);
 
-            TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout_Layout);
-            gravity = a.getInt(com.android.internal.R.styleable.FrameLayout_Layout_layout_gravity, -1);
+            final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FrameLayout_Layout);
+            gravity = a.getInt(R.styleable.FrameLayout_Layout_layout_gravity,
+                    DEFAULT_CHILD_GRAVITY);
             a.recycle();
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public LayoutParams(int width, int height) {
             super(width, height);
         }
@@ -462,9 +445,9 @@
          * and weight.
          *
          * @param width the width, either {@link #MATCH_PARENT},
-         *        {@link #WRAP_CONTENT} or a fixed size in pixels
+         *              {@link #WRAP_CONTENT} or a fixed size in pixels
          * @param height the height, either {@link #MATCH_PARENT},
-         *        {@link #WRAP_CONTENT} or a fixed size in pixels
+         *               {@link #WRAP_CONTENT} or a fixed size in pixels
          * @param gravity the gravity
          *
          * @see android.view.Gravity
@@ -474,17 +457,11 @@
             this.gravity = gravity;
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(ViewGroup.LayoutParams source) {
+        public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
             super(source);
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(ViewGroup.MarginLayoutParams source) {
+        public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
             super(source);
         }
 
@@ -494,7 +471,7 @@
          *
          * @param source The layout params to copy from.
          */
-        public LayoutParams(LayoutParams source) {
+        public LayoutParams(@NonNull LayoutParams source) {
             super(source);
 
             this.gravity = source.gravity;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index ef6628a..726586e 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -867,8 +867,14 @@
     }
 
     @Override
-    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new LayoutParams(p);
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) lp);
+        } else if (lp instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) lp);
+        } else {
+            return new LayoutParams(lp);
+        }
     }
 
     // Draw grid
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 1321221..6d7313d 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1644,7 +1644,7 @@
         boolean handled = false;
         int action = event.getAction();
         if (KeyEvent.isConfirmKey(keyCode)
-                && event.hasNoModifiers() && action == KeyEvent.ACTION_UP) {
+                && event.hasNoModifiers() && action != KeyEvent.ACTION_UP) {
             handled = resurrectSelectionIfNeeded();
             if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
                 keyPressed();
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index f16fdd6..00f368e 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -325,16 +325,24 @@
 
         if (getChildCount() > 0) {
             final View child = getChildAt(0);
-            int width = getMeasuredWidth();
-            if (child.getMeasuredWidth() < width) {
-                final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final int widthPadding;
+            final int heightPadding;
+            final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+            if (targetSdkVersion >= Build.VERSION_CODES.M) {
+                widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
+                heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
+            } else {
+                widthPadding = mPaddingLeft + mPaddingRight;
+                heightPadding = mPaddingTop + mPaddingBottom;
+            }
 
-                int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, mPaddingTop
-                        + mPaddingBottom, lp.height);
-                width -= mPaddingLeft;
-                width -= mPaddingRight;
-                int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
-
+            int desiredWidth = getMeasuredWidth() - widthPadding;
+            if (child.getMeasuredWidth() < desiredWidth) {
+                final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        desiredWidth, MeasureSpec.EXACTLY);
+                final int childHeightMeasureSpec = getChildMeasureSpec(
+                        heightMeasureSpec, heightPadding, lp.height);
                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
             }
         }
@@ -1235,17 +1243,17 @@
     }
 
     @Override
-    protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
+    protected void measureChild(View child, int parentWidthMeasureSpec,
+            int parentHeightMeasureSpec) {
         ViewGroup.LayoutParams lp = child.getLayoutParams();
 
-        int childWidthMeasureSpec;
-        int childHeightMeasureSpec;
+        final int horizontalPadding = mPaddingLeft + mPaddingRight;
+        final int childWidthMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
+                Math.max(0, MeasureSpec.getSize(parentWidthMeasureSpec) - horizontalPadding),
+                MeasureSpec.UNSPECIFIED);
 
-        childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop
-                + mPaddingBottom, lp.height);
-
-        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
+        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
+                mPaddingTop + mPaddingBottom, lp.height);
         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     }
 
@@ -1257,8 +1265,11 @@
         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                         + heightUsed, lp.height);
-        final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);
+        final int usedTotal = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin +
+                widthUsed;
+        final int childWidthMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
+                Math.max(0, MeasureSpec.getSize(parentWidthMeasureSpec) - usedTotal),
+                MeasureSpec.UNSPECIFIED);
 
         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index f601f7d..222a040 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -212,7 +212,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable dr) {
+    protected boolean verifyDrawable(@NonNull Drawable dr) {
         return mDrawable == dr || super.verifyDrawable(dr);
     }
 
@@ -223,7 +223,7 @@
     }
 
     @Override
-    public void invalidateDrawable(Drawable dr) {
+    public void invalidateDrawable(@NonNull Drawable dr) {
         if (dr == mDrawable) {
             if (dr != null) {
                 // update cached drawable dimensions if they've changed
@@ -913,6 +913,9 @@
         if (mDrawable != null) {
             mDrawable.setCallback(null);
             unscheduleDrawable(mDrawable);
+            if (isAttachedToWindow()) {
+                mDrawable.setVisible(false, false);
+            }
         }
 
         mDrawable = d;
@@ -923,7 +926,9 @@
             if (d.isStateful()) {
                 d.setState(getDrawableState());
             }
-            d.setVisible(getVisibility() == VISIBLE, true);
+            if (isAttachedToWindow()) {
+                d.setVisible(getWindowVisibility() == VISIBLE && isShown(), true);
+            }
             d.setLevel(mLevel);
             mDrawableWidth = d.getIntrinsicWidth();
             mDrawableHeight = d.getIntrinsicHeight();
@@ -1498,28 +1503,11 @@
         }
     }
 
-    @RemotableViewMethod
     @Override
-    public void setVisibility(int visibility) {
-        super.setVisibility(visibility);
+    public void onVisibilityAggregated(boolean isVisible) {
+        super.onVisibilityAggregated(isVisible);
         if (mDrawable != null) {
-            mDrawable.setVisible(visibility == VISIBLE, false);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mDrawable != null) {
-            mDrawable.setVisible(getVisibility() == VISIBLE, false);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mDrawable != null) {
-            mDrawable.setVisible(false, false);
+            mDrawable.setVisible(isVisible, false);
         }
     }
 
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index e0ef86c..f75b74b 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -869,10 +869,10 @@
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds. If we skipped
         // measurement on any children, we need to measure them now.
-        final int delta = heightSize - mTotalLength
+        int remainingExcess = heightSize - mTotalLength
                 + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
-        if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
-            final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+        if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
+            float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
 
             mTotalLength = 0;
 
@@ -883,9 +883,12 @@
                 }
 
                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                final float childExtra = lp.weight;
-                if (childExtra > 0) {
-                    final int share = (int) (childExtra * delta / weightSum);
+                final float childWeight = lp.weight;
+                if (childWeight > 0) {
+                    final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
+                    remainingExcess -= share;
+                    remainingWeightSum -= childWeight;
+
                     final int childHeight;
                     if (lp.height == 0 && (!mAllowInconsistentMeasurement
                             || heightMode == MeasureSpec.EXACTLY)) {
@@ -1244,10 +1247,10 @@
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds. If we skipped
         // measurement on any children, we need to measure them now.
-        final int delta = widthSize - mTotalLength
+        int remainingExcess = widthSize - mTotalLength
                 + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
-        if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
-            final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+        if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
+            float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
 
             maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
             maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
@@ -1262,9 +1265,12 @@
                 }
 
                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                final float childExtra = lp.weight;
-                if (childExtra > 0) {
-                    final int share = (int) (childExtra * delta / weightSum);
+                final float childWeight = lp.weight;
+                if (childWeight > 0) {
+                    final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
+                    remainingExcess -= share;
+                    remainingWeightSum -= childWeight;
+
                     final int childWidth;
                     if (lp.width == 0 && (!mAllowInconsistentMeasurement
                             || widthMode == MeasureSpec.EXACTLY)) {
@@ -1833,8 +1839,14 @@
     }
 
     @Override
-    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new LayoutParams(p);
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) lp);
+        } else if (lp instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) lp);
+        } else {
+            return new LayoutParams(lp);
+        }
     }
 
 
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index dcadb6a..6a10743 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -879,12 +879,13 @@
     /**
      * Filter key down events. By forwarding key down events to this function,
      * views using non-modal ListPopupWindow can have it handle key selection of items.
-     *  
+     *
      * @param keyCode keyCode param passed to the host view's onKeyDown
      * @param event event param passed to the host view's onKeyDown
      * @return true if the event was handled, false if it was ignored.
-     * 
+     *
      * @see #setModal(boolean)
+     * @see #onKeyUp(int, KeyEvent)
      */
     public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
         // when the drop down is shown, we drive it directly
@@ -972,14 +973,15 @@
     }
 
     /**
-     * Filter key down events. By forwarding key up events to this function,
+     * Filter key up events. By forwarding key up events to this function,
      * views using non-modal ListPopupWindow can have it handle key selection of items.
-     *  
+     *
      * @param keyCode keyCode param passed to the host view's onKeyUp
      * @param event event param passed to the host view's onKeyUp
      * @return true if the event was handled, false if it was ignored.
-     * 
+     *
      * @see #setModal(boolean)
+     * @see #onKeyDown(int, KeyEvent)
      */
     public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
         if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
@@ -998,11 +1000,11 @@
      * Filter pre-IME key events. By forwarding {@link View#onKeyPreIme(int, KeyEvent)}
      * events to this function, views using ListPopupWindow can have it dismiss the popup
      * when the back key is pressed.
-     *  
+     *
      * @param keyCode keyCode param passed to the host view's onKeyPreIme
      * @param event event param passed to the host view's onKeyPreIme
      * @return true if the event was handled, false if it was ignored.
-     * 
+     *
      * @see #setModal(boolean)
      */
     public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
@@ -1181,28 +1183,28 @@
         }
 
         // getMaxAvailableHeight() subtracts the padding, so we put it back
-        // to get the available height for the whole window
-        int padding = 0;
-        Drawable background = mPopup.getBackground();
+        // to get the available height for the whole window.
+        final int padding;
+        final Drawable background = mPopup.getBackground();
         if (background != null) {
             background.getPadding(mTempRect);
             padding = mTempRect.top + mTempRect.bottom;
 
-            // If we don't have an explicit vertical offset, determine one from the window
-            // background so that content will line up.
+            // If we don't have an explicit vertical offset, determine one from
+            // the window background so that content will line up.
             if (!mDropDownVerticalOffsetSet) {
                 mDropDownVerticalOffset = -mTempRect.top;
             }
         } else {
             mTempRect.setEmpty();
+            padding = 0;
         }
 
         // Max height available on the screen for a popup.
-        boolean ignoreBottomDecorations =
+        final boolean ignoreBottomDecorations =
                 mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
         final int maxHeight = mPopup.getMaxAvailableHeight(
                 getAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
-
         if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
             return maxHeight + padding;
         }
@@ -1211,25 +1213,30 @@
         switch (mDropDownWidth) {
             case ViewGroup.LayoutParams.WRAP_CONTENT:
                 childWidthSpec = MeasureSpec.makeMeasureSpec(
-                        mContext.getResources().getDisplayMetrics().widthPixels -
-                        (mTempRect.left + mTempRect.right),
+                        mContext.getResources().getDisplayMetrics().widthPixels
+                                - (mTempRect.left + mTempRect.right),
                         MeasureSpec.AT_MOST);
                 break;
             case ViewGroup.LayoutParams.MATCH_PARENT:
                 childWidthSpec = MeasureSpec.makeMeasureSpec(
-                        mContext.getResources().getDisplayMetrics().widthPixels -
-                        (mTempRect.left + mTempRect.right),
+                        mContext.getResources().getDisplayMetrics().widthPixels
+                                - (mTempRect.left + mTempRect.right),
                         MeasureSpec.EXACTLY);
                 break;
             default:
                 childWidthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.EXACTLY);
                 break;
         }
+
+        // Add padding only if the list has items in it, that way we don't show
+        // the popup if it is not needed.
         final int listContent = mDropDownList.measureHeightOfChildren(childWidthSpec,
-                0, ListView.NO_POSITION, maxHeight - otherHeights, -1);
-        // add padding only if the list has items in it, that way we don't show
-        // the popup if it is not needed
-        if (listContent > 0) otherHeights += padding;
+                0, DropDownListView.NO_POSITION, maxHeight - otherHeights, -1);
+        if (listContent > 0) {
+            final int listPadding = mDropDownList.getPaddingTop()
+                    + mDropDownList.getPaddingBottom();
+            otherHeights += padding + listPadding;
+        }
 
         return listContent + otherHeights;
     }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5b4a368..bfc87f2 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -16,15 +16,14 @@
 
 package android.widget;
 
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Trace;
+import com.google.android.collect.Lists;
+
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
-import com.google.android.collect.Lists;
 
 import android.annotation.IdRes;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
@@ -33,6 +32,8 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.MathUtils;
 import android.util.SparseBooleanArray;
@@ -1106,20 +1107,63 @@
     }
 
     private class FocusSelector implements Runnable {
+        // the selector is waiting to set selection on the list view
+        private static final int STATE_SET_SELECTION = 1;
+        // the selector set the selection on the list view, waiting for a layoutChildren pass
+        private static final int STATE_WAIT_FOR_LAYOUT = 2;
+        // the selector's selection has been honored and it is waiting to request focus on the
+        // target child.
+        private static final int STATE_REQUEST_FOCUS = 3;
+
+        private int mAction;
         private int mPosition;
         private int mPositionTop;
-        
-        public FocusSelector setup(int position, int top) {
+
+        FocusSelector setupForSetSelection(int position, int top) {
             mPosition = position;
             mPositionTop = top;
+            mAction = STATE_SET_SELECTION;
             return this;
         }
-        
+
         public void run() {
-            setSelectionFromTop(mPosition, mPositionTop);
+            if (mAction == STATE_SET_SELECTION) {
+                setSelectionFromTop(mPosition, mPositionTop);
+                mAction = STATE_WAIT_FOR_LAYOUT;
+            } else if (mAction == STATE_REQUEST_FOCUS) {
+                final int childIndex = mPosition - mFirstPosition;
+                final View child = getChildAt(childIndex);
+                if (child != null) {
+                    child.requestFocus();
+                }
+                mAction = -1;
+            }
+        }
+
+        @Nullable Runnable setupFocusIfValid(int position) {
+            if (mAction != STATE_WAIT_FOR_LAYOUT || position != mPosition) {
+                return null;
+            }
+            mAction = STATE_REQUEST_FOCUS;
+            return this;
+        }
+
+        void onLayoutComplete() {
+            if (mAction == STATE_WAIT_FOR_LAYOUT) {
+                mAction = -1;
+            }
         }
     }
-    
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if (mFocusSelector != null) {
+            removeCallbacks(mFocusSelector);
+            mFocusSelector = null;
+        }
+        super.onDetachedFromWindow();
+    }
+
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         if (getChildCount() > 0) {
@@ -1132,7 +1176,7 @@
                 if (mFocusSelector == null) {
                     mFocusSelector = new FocusSelector();
                 }
-                post(mFocusSelector.setup(childPosition, top));
+                post(mFocusSelector.setupForSetSelection(childPosition, top));
             }
         }
         super.onSizeChanged(w, h, oldw, oldh);
@@ -1629,7 +1673,7 @@
                     focusLayoutRestoreView = findFocus();
                     if (focusLayoutRestoreView != null) {
                         // Tell it we are going to mess with it.
-                        focusLayoutRestoreView.onStartTemporaryDetach();
+                        focusLayoutRestoreView.dispatchStartTemporaryDetach();
                     }
                 }
                 requestFocus();
@@ -1672,7 +1716,21 @@
                 adjustViewsUpOrDown();
                 break;
             case LAYOUT_SPECIFIC:
-                sel = fillSpecific(reconcileSelectedPosition(), mSpecificTop);
+                final int selectedPosition = reconcileSelectedPosition();
+                sel = fillSpecific(selectedPosition, mSpecificTop);
+                /**
+                 * When ListView is resized, FocusSelector requests an async selection for the
+                 * previously focused item to make sure it is still visible. If the item is not
+                 * selectable, it won't regain focus so instead we call FocusSelector
+                 * to directly request focus on the view after it is visible.
+                 */
+                if (sel == null && mFocusSelector != null) {
+                    final Runnable focusRunnable = mFocusSelector
+                            .setupFocusIfValid(selectedPosition);
+                    if (focusRunnable != null) {
+                        post(focusRunnable);
+                    }
+                }
                 break;
             case LAYOUT_MOVE_SELECTION:
                 sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom);
@@ -1792,7 +1850,7 @@
             // our view hierarchy.
             if (focusLayoutRestoreView != null
                     && focusLayoutRestoreView.getWindowToken() != null) {
-                focusLayoutRestoreView.onFinishTemporaryDetach();
+                focusLayoutRestoreView.dispatchFinishTemporaryDetach();
             }
             
             mLayoutMode = LAYOUT_NORMAL;
@@ -1812,6 +1870,9 @@
 
             invokeOnItemScrollListener();
         } finally {
+            if (mFocusSelector != null) {
+                mFocusSelector.onLayoutComplete();
+            }
             if (!blockLayoutRequests) {
                 mBlockLayoutRequests = false;
             }
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 8fa71a2..0d8d8ed 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -16,14 +16,11 @@
 
 package android.widget;
 
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
-
 import com.android.internal.R;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -55,10 +52,46 @@
 
 import java.lang.ref.WeakReference;
 
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+
 /**
- * <p>A popup window that can be used to display an arbitrary view. The popup
- * window is a floating container that appears on top of the current
- * activity.</p>
+ * <p>
+ * This class represents a popup window that can be used to display an
+ * arbitrary view. The popup window is a floating container that appears on top
+ * of the current activity.
+ * </p>
+ * <a name="Animation"></a>
+ * <h3>Animation</h3>
+ * <p>
+ * On all versions of Android, popup window enter and exit animations may be
+ * specified by calling {@link #setAnimationStyle(int)} and passing the
+ * resource ID for an animation style that defines {@code windowEnterAnimation}
+ * and {@code windowExitAnimation}. For example, passing
+ * {@link android.R.style#Animation_Dialog} will give a scale and alpha
+ * animation.
+ * </br>
+ * A window animation style may also be specified in the popup window's style
+ * XML via the {@link android.R.styleable#PopupWindow_popupAnimationStyle popupAnimationStyle}
+ * attribute.
+ * </p>
+ * <p>
+ * Starting with API 23, more complex popup window enter and exit transitions
+ * may be specified by calling either {@link #setEnterTransition(Transition)}
+ * or {@link #setExitTransition(Transition)} and passing a  {@link Transition}.
+ * </br>
+ * Popup enter and exit transitions may also be specified in the popup window's
+ * style XML via the {@link android.R.styleable#PopupWindow_popupEnterTransition popupEnterTransition}
+ * and {@link android.R.styleable#PopupWindow_popupExitTransition popupExitTransition}
+ * attributes, respectively.
+ * </p>
+ *
+ * @attr ref android.R.styleable#PopupWindow_overlapAnchor
+ * @attr ref android.R.styleable#PopupWindow_popupAnimationStyle
+ * @attr ref android.R.styleable#PopupWindow_popupBackground
+ * @attr ref android.R.styleable#PopupWindow_popupElevation
+ * @attr ref android.R.styleable#PopupWindow_popupEnterTransition
+ * @attr ref android.R.styleable#PopupWindow_popupExitTransition
  *
  * @see android.widget.AutoCompleteTextView
  * @see android.widget.Spinner
@@ -96,8 +129,8 @@
      */
     private static final int ANIMATION_STYLE_DEFAULT = -1;
 
-    private final int[] mDrawingLocation = new int[2];
-    private final int[] mScreenLocation = new int[2];
+    private final int[] mTmpDrawingLocation = new int[2];
+    private final int[] mTmpScreenLocation = new int[2];
     private final Rect mTempRect = new Rect();
 
     private Context mContext;
@@ -140,9 +173,6 @@
     private int mHeight = LayoutParams.WRAP_CONTENT;
     private int mLastHeight;
 
-    private int mPopupWidth;
-    private int mPopupHeight;
-
     private float mElevation;
 
     private Drawable mBackground;
@@ -189,7 +219,7 @@
                         mDecorView.getLayoutParams();
 
                 updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
-                        mAnchoredGravity));
+                        p.width, p.height, mAnchoredGravity));
                 update(p.x, p.y, -1, -1, true);
             }
         }
@@ -352,15 +382,54 @@
         setFocusable(focusable);
     }
 
-    public void setEnterTransition(Transition enterTransition) {
+    /**
+     * Sets the enter transition to be used when the popup window is shown.
+     *
+     * @param enterTransition the enter transition, or {@code null} to clear
+     * @see #getEnterTransition()
+     * @attr ref android.R.styleable#PopupWindow_popupEnterTransition
+     */
+    public void setEnterTransition(@Nullable Transition enterTransition) {
         mEnterTransition = enterTransition;
     }
 
-    public void setExitTransition(Transition exitTransition) {
+    /**
+     * Returns the enter transition to be used when the popup window is shown.
+     *
+     * @return the enter transition, or {@code null} if not set
+     * @see #setEnterTransition(Transition)
+     * @attr ref android.R.styleable#PopupWindow_popupEnterTransition
+     */
+    @Nullable
+    public Transition getEnterTransition() {
+        return mEnterTransition;
+    }
+
+    /**
+     * Sets the exit transition to be used when the popup window is dismissed.
+     *
+     * @param exitTransition the exit transition, or {@code null} to clear
+     * @see #getExitTransition()
+     * @attr ref android.R.styleable#PopupWindow_popupExitTransition
+     */
+    public void setExitTransition(@Nullable Transition exitTransition) {
         mExitTransition = exitTransition;
     }
 
     /**
+     * Returns the exit transition to be used when the popup window is
+     * dismissed.
+     *
+     * @return the exit transition, or {@code null} if not set
+     * @see #setExitTransition(Transition)
+     * @attr ref android.R.styleable#PopupWindow_popupExitTransition
+     */
+    @Nullable
+    public Transition getExitTransition() {
+        return mExitTransition;
+    }
+
+    /**
      * Sets the bounds used as the epicenter of the enter and exit transitions.
      * <p>
      * Transitions use a point or Rect, referred to as the epicenter, to orient
@@ -1051,7 +1120,7 @@
 
         TransitionManager.endTransitions(mDecorView);
 
-        unregisterForViewTreeChanges();
+        detachFromAnchor();
 
         mIsShowing = true;
         mIsDropdown = false;
@@ -1134,7 +1203,7 @@
 
         TransitionManager.endTransitions(mDecorView);
 
-        registerForViewTreeChanges(anchor, xoff, yoff, gravity);
+        attachToAnchor(anchor, xoff, yoff, gravity);
 
         mIsShowing = true;
         mIsDropdown = true;
@@ -1142,8 +1211,10 @@
         final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
         preparePopup(p);
 
-        final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, gravity);
+        final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
+                p.width, p.height, gravity);
         updateAboveAnchor(aboveAnchor);
+        p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
 
         invokePopup(p);
     }
@@ -1225,8 +1296,6 @@
 
         mPopupViewInitialLayoutDirectionInherited =
                 (mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
-        mPopupWidth = p.width;
-        mPopupHeight = p.height;
     }
 
     /**
@@ -1422,122 +1491,196 @@
      * 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.
+     * The results of positioning are placed in {@code outParams}.
      *
      * @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 outParams the layout parameters used to display the drop down
+     * @param xOffset absolute horizontal offset from the left of the anchor
+     * @param yOffset absolute vertical offset from the top of the anchor
      * @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 outParams,
+            int xOffset, int yOffset, int width, int height, int gravity) {
         final int anchorHeight = anchor.getHeight();
         final int anchorWidth = anchor.getWidth();
         if (mOverlapAnchor) {
-            yoff -= anchorHeight;
+            yOffset -= anchorHeight;
         }
 
-        anchor.getLocationInWindow(mDrawingLocation);
-        p.x = mDrawingLocation[0] + xoff;
-        p.y = mDrawingLocation[1] + anchorHeight + yoff;
+        // Initially, align to the bottom-left corner of the anchor plus offsets.
+        final int[] drawingLocation = mTmpDrawingLocation;
+        anchor.getLocationInWindow(drawingLocation);
+        outParams.x = drawingLocation[0] + xOffset;
+        outParams.y = drawingLocation[1] + anchorHeight + yOffset;
 
+        // If we need to adjust for gravity RIGHT, align to the bottom-right
+        // corner of the anchor (still accounting for offsets).
         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 - anchorWidth;
+            outParams.x -= width - anchorWidth;
         }
 
-        boolean onTop = false;
+        // Let the window manager know to align the top to y.
+        outParams.gravity = Gravity.LEFT | Gravity.TOP;
+        outParams.width = width;
+        outParams.height = height;
 
-        p.gravity = Gravity.LEFT | Gravity.TOP;
+        final int[] screenLocation = mTmpScreenLocation;
+        anchor.getLocationOnScreen(screenLocation);
 
-        anchor.getLocationOnScreen(mScreenLocation);
         final Rect displayFrame = new Rect();
         anchor.getWindowVisibleDisplayFrame(displayFrame);
 
-        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 (mAllowScrollingAnchorParent) {
-                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);
-            }
+        // First, attempt to fit the popup vertically without resizing.
+        final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
+                anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
+                displayFrame.bottom, false);
 
-            // 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] + anchorHeight + yoff;
+        // Next, attempt to fit the popup horizontally without resizing.
+        final boolean fitsHorizontal = tryFitHorizontal(outParams, xOffset, width,
+                anchorWidth, drawingLocation[0], screenLocation[0], displayFrame.left,
+                displayFrame.right, false);
 
-            // Preserve the gravity adjustment.
-            if (hgrav == Gravity.RIGHT) {
-                p.x -= mPopupWidth - anchorWidth;
-            }
+        // If the popup still doesn't fit, attempt to scroll the parent.
+        if (!fitsVertical || !fitsHorizontal) {
+            final int scrollX = anchor.getScrollX();
+            final int scrollY = anchor.getScrollY();
+            final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
+                    scrollY + height + anchorHeight + yOffset);
+            if (mAllowScrollingAnchorParent && anchor.requestRectangleOnScreen(r, true)) {
+                // Reset for the new anchor position.
+                anchor.getLocationInWindow(drawingLocation);
+                outParams.x = drawingLocation[0] + xOffset;
+                outParams.y = drawingLocation[1] + anchorHeight + yOffset;
 
-            // Determine whether there is more space above or below the anchor.
-            anchor.getLocationOnScreen(mScreenLocation);
-            onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
-                    (mScreenLocation[1] - yoff - displayFrame.top);
-            if (!mOverlapAnchor) {
-                if (onTop) {
-                    p.gravity = Gravity.LEFT | Gravity.BOTTOM;
-                    p.y = root.getHeight() - mDrawingLocation[1] + yoff;
-                } else {
-                    p.y = mDrawingLocation[1] + anchorHeight + yoff;
+                // Preserve the gravity adjustment.
+                if (hgrav == Gravity.RIGHT) {
+                    outParams.x -= width - anchorWidth;
                 }
             }
+
+            // Try to fit the popup again and allowing resizing.
+            tryFitVertical(outParams, yOffset, height, anchorHeight, drawingLocation[1],
+                    screenLocation[1], displayFrame.top, displayFrame.bottom, mClipToScreen);
+            tryFitHorizontal(outParams, xOffset, width, anchorWidth, drawingLocation[0],
+                    screenLocation[0], displayFrame.left, displayFrame.right, mClipToScreen);
         }
 
-        if (mClipToScreen) {
-            final int winOffsetX = mScreenLocation[0] - mDrawingLocation[0];
-            final int winOffsetY = mScreenLocation[1] - mDrawingLocation[1];
-            p.x += winOffsetX;
-            p.y += winOffsetY;
-            final int displayFrameWidth = displayFrame.right - displayFrame.left;
-            final int right = p.x + p.width;
-            if (right > displayFrame.right) {
-                p.x -= right - displayFrame.right;
-            }
+        // Return whether the popup's top edge is above the anchor's top edge.
+        return outParams.y < drawingLocation[1];
+    }
 
-            if (p.x < displayFrame.left) {
-                p.x = displayFrame.left;
-                p.width = Math.min(p.width, displayFrameWidth);
-            }
+    private boolean tryFitVertical(@NonNull LayoutParams outParams, int yOffset, int height,
+            int anchorHeight, int drawingLocationY, int screenLocationY, int displayFrameTop,
+            int displayFrameBottom, boolean allowResize) {
+        final int anchorTopInScreen = screenLocationY + anchorHeight + yOffset;
+        final int spaceBelow = displayFrameBottom - anchorTopInScreen;
+        if (height <= spaceBelow) {
+            return true;
+        }
 
+        final int spaceAbove = displayFrameTop + anchorTopInScreen - anchorHeight;
+        if (height <= spaceAbove) {
+            // Move everything up.
             if (mOverlapAnchor) {
-                final int bottom = p.y + p.height;
-                if (bottom > displayFrame.bottom) {
-                    p.y -= bottom - displayFrame.bottom;
-                }
-            } else {
-                if (onTop) {
-                    final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
-                    if (popupTop < 0) {
-                        p.y += popupTop;
-                    }
-                } else {
-                    p.y = Math.max(p.y, displayFrame.top);
-                }
+                yOffset += anchorHeight;
             }
-            p.x -= winOffsetX;
-            p.y -= winOffsetY;
+            outParams.y = drawingLocationY - height + yOffset;
+
+            return true;
         }
 
-        p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
+        if (positionInDisplayVertical(outParams, height, drawingLocationY, screenLocationY,
+                displayFrameTop, displayFrameBottom, allowResize)) {
+            return true;
+        }
 
-        return onTop;
+        return false;
+    }
+
+    private boolean positionInDisplayVertical(@NonNull LayoutParams outParams, int height,
+            int drawingLocationY, int screenLocationY, int displayFrameTop, int displayFrameBottom,
+            boolean canResize) {
+        boolean fitsInDisplay = true;
+
+        final int winOffsetY = screenLocationY - drawingLocationY;
+        outParams.y += winOffsetY;
+        outParams.height = height;
+
+        final int bottom = outParams.y + height;
+        if (bottom > displayFrameBottom) {
+            // The popup is too far down, move it back in.
+            outParams.y -= bottom - displayFrameBottom;
+        }
+
+        if (outParams.y < displayFrameTop) {
+            // The popup is too far up, move it back in and clip if
+            // it's still too large.
+            outParams.y = displayFrameTop;
+
+            final int displayFrameHeight = displayFrameBottom - displayFrameTop;
+            if (canResize && height > displayFrameHeight) {
+                outParams.height = displayFrameHeight;
+            } else {
+                fitsInDisplay = false;
+            }
+        }
+
+        outParams.y -= winOffsetY;
+
+        return fitsInDisplay;
+    }
+
+    private boolean tryFitHorizontal(@NonNull LayoutParams outParams, int xOffset, int width,
+            int anchorWidth, int drawingLocationX, int screenLocationX, int displayFrameLeft,
+            int displayFrameRight, boolean allowResize) {
+        final int anchorLeftInScreen = screenLocationX + xOffset;
+        final int spaceRight = displayFrameRight - anchorLeftInScreen;
+        if (width <= spaceRight) {
+            return true;
+        }
+
+        if (positionInDisplayHorizontal(outParams, width, drawingLocationX, screenLocationX,
+                displayFrameLeft, displayFrameRight, allowResize)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean positionInDisplayHorizontal(@NonNull LayoutParams outParams, int width,
+            int drawingLocationX, int screenLocationX, int displayFrameLeft, int displayFrameRight,
+            boolean canResize) {
+        boolean fitsInDisplay = true;
+
+        // Use screen coordinates for comparison against display frame.
+        final int winOffsetX = screenLocationX - drawingLocationX;
+        outParams.x += winOffsetX;
+
+        final int right = outParams.x + width;
+        if (right > displayFrameRight) {
+            // The popup is too far right, move it back in.
+            outParams.x -= right - displayFrameRight;
+        }
+
+        if (outParams.x < displayFrameLeft) {
+            // The popup is too far left, move it back in and clip if it's
+            // still too large.
+            outParams.x = displayFrameLeft;
+
+            final int displayFrameWidth = displayFrameRight - displayFrameLeft;
+            if (canResize && width > displayFrameWidth) {
+                outParams.width = displayFrameWidth;
+            } else {
+                fitsInDisplay = false;
+            }
+        }
+
+        outParams.x -= winOffsetX;
+
+        return fitsInDisplay;
     }
 
     /**
@@ -1587,18 +1730,16 @@
     public int getMaxAvailableHeight(
             @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) {
         final Rect displayFrame = new Rect();
-        anchor.getWindowVisibleDisplayFrame(displayFrame);
+        if (ignoreBottomDecorations) {
+            anchor.getWindowDisplayFrame(displayFrame);
+        } else {
+            anchor.getWindowVisibleDisplayFrame(displayFrame);
+        }
 
-        final int[] anchorPos = mDrawingLocation;
+        final int[] anchorPos = mTmpDrawingLocation;
         anchor.getLocationOnScreen(anchorPos);
 
-        final int bottomEdge;
-        if (ignoreBottomDecorations) {
-            final Resources res = anchor.getContext().getResources();
-            bottomEdge = res.getDisplayMetrics().heightPixels;
-        } else {
-            bottomEdge = displayFrame.bottom;
-        }
+        final int bottomEdge = displayFrame.bottom;
 
         final int distanceToBottom;
         if (mOverlapAnchor) {
@@ -1653,11 +1794,12 @@
         // can expect the OnAttachStateChangeListener to have been called prior
         // to executing this method, so we can rely on that instead.
         final Transition exitTransition = mExitTransition;
-        if (!mIsAnchorRootAttached && exitTransition != null && decorView.isLaidOut()) {
-            // The decor view is non-interactive during exit transitions.
+        if (mIsAnchorRootAttached && exitTransition != null && decorView.isLaidOut()) {
+            // The decor view is non-interactive and non-IME-focusable during exit transitions.
             final LayoutParams p = (LayoutParams) decorView.getLayoutParams();
             p.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
             p.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
+            p.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
             mWindowManager.updateViewLayout(decorView, p);
 
             // Once we start dismissing the decor view, all state (including
@@ -1683,7 +1825,7 @@
         }
 
         // Clears the anchor view.
-        unregisterForViewTreeChanges();
+        detachFromAnchor();
 
         if (mOnDismissListener != null) {
             mOnDismissListener.onDismiss();
@@ -1899,6 +2041,13 @@
             update = true;
         }
 
+        int newAccessibilityIdOfAnchor =
+                (mAnchor != null) ? mAnchor.get().getAccessibilityViewId() : -1;
+        if (newAccessibilityIdOfAnchor != p.accessibilityIdOfAnchor) {
+            p.accessibilityIdOfAnchor = newAccessibilityIdOfAnchor;
+            update = true;
+        }
+
         if (update) {
             setLayoutDirectionFromAnchor();
             mWindowManager.updateViewLayout(mDecorView, p);
@@ -1916,7 +2065,7 @@
      * @param height the new height, must be >= 0 or -1 to ignore
      */
     public void update(View anchor, int width, int height) {
-        update(anchor, false, 0, 0, true, width, height);
+        update(anchor, false, 0, 0, width, height);
     }
 
     /**
@@ -1936,51 +2085,51 @@
      * @param height the new height, must be >= 0 or -1 to ignore
      */
     public void update(View anchor, int xoff, int yoff, int width, int height) {
-        update(anchor, true, xoff, yoff, true, width, height);
+        update(anchor, true, xoff, yoff, width, height);
     }
 
     private void update(View anchor, boolean updateLocation, int xoff, int yoff,
-            boolean updateDimension, int width, int height) {
+            int width, int height) {
 
         if (!isShowing() || mContentView == null) {
             return;
         }
 
         final WeakReference<View> oldAnchor = mAnchor;
+        final int gravity = mAnchoredGravity;
+
         final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
         if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
-            registerForViewTreeChanges(anchor, xoff, yoff, mAnchoredGravity);
+            attachToAnchor(anchor, xoff, yoff, gravity);
         } else if (needsUpdate) {
             // No need to register again if this is a DropDown, showAsDropDown already did.
             mAnchorXoff = xoff;
             mAnchorYoff = yoff;
         }
 
-        if (updateDimension) {
-            if (width == -1) {
-                width = mPopupWidth;
-            } else {
-                mPopupWidth = width;
-            }
-            if (height == -1) {
-                height = mPopupHeight;
-            } else {
-                mPopupHeight = height;
-            }
+        final LayoutParams p = (LayoutParams) mDecorView.getLayoutParams();
+        final int oldGravity = p.gravity;
+        final int oldWidth = p.width;
+        final int oldHeight = p.height;
+        final int oldX = p.x;
+        final int oldY = p.y;
+
+        // If an explicit width/height has not specified, use the most recent
+        // explicitly specified value (either from setWidth/Height or update).
+        if (width == -1) {
+            width = mWidth;
+        }
+        if (height == -1) {
+            height = mHeight;
         }
 
-        final WindowManager.LayoutParams p =
-                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
-        final int x = p.x;
-        final int y = p.y;
-        if (updateLocation) {
-            updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, mAnchoredGravity));
-        } else {
-            updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
-                    mAnchoredGravity));
-        }
+        final boolean aboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+                width, height, gravity);
+        updateAboveAnchor(aboveAnchor);
 
-        update(p.x, p.y, width, height, x != p.x || y != p.y);
+        final boolean paramsChanged = oldGravity != p.gravity || oldX != p.x || oldY != p.y
+                || oldWidth != p.width || oldHeight != p.height;
+        update(p.x, p.y, p.width, p.height, paramsChanged);
     }
 
     /**
@@ -1993,7 +2142,7 @@
         public void onDismiss();
     }
 
-    private void unregisterForViewTreeChanges() {
+    private void detachFromAnchor() {
         final View anchor = mAnchor != null ? mAnchor.get() : null;
         if (anchor != null) {
             final ViewTreeObserver vto = anchor.getViewTreeObserver();
@@ -2010,8 +2159,8 @@
         mIsAnchorRootAttached = false;
     }
 
-    private void registerForViewTreeChanges(View anchor, int xoff, int yoff, int gravity) {
-        unregisterForViewTreeChanges();
+    private void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
+        detachFromAnchor();
 
         final ViewTreeObserver vto = anchor.getViewTreeObserver();
         if (vto != null) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 2099b04..e9fa26c 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -17,21 +17,15 @@
 package android.widget;
 
 import android.animation.ObjectAnimator;
+import android.annotation.InterpolatorRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.graphics.PorterDuff;
-
-import android.util.FloatProperty;
-import android.util.IntProperty;
-import android.view.accessibility.AccessibilityNodeInfo;
-import com.android.internal.R;
-
-import android.annotation.InterpolatorRes;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.drawable.Animatable;
@@ -46,6 +40,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.util.MathUtils;
 import android.util.Pools.SynchronizedPool;
 import android.view.Gravity;
@@ -55,6 +50,7 @@
 import android.view.ViewHierarchyEncoder;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -63,6 +59,7 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
 import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
 
 import java.util.ArrayList;
 
@@ -249,6 +246,8 @@
 
     boolean mMirrorForRtl = false;
 
+    private boolean mAggregatedIsVisible;
+
     private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
 
     private AccessibilityEventSender mAccessibilityEventSender;
@@ -606,15 +605,29 @@
 
             if (indeterminate) {
                 // swap between indeterminate and regular backgrounds
-                mCurrentDrawable = mIndeterminateDrawable;
+                swapCurrentDrawable(mIndeterminateDrawable);
                 startAnimation();
             } else {
-                mCurrentDrawable = mProgressDrawable;
+                swapCurrentDrawable(mProgressDrawable);
                 stopAnimation();
             }
         }
     }
 
+    private void swapCurrentDrawable(Drawable newDrawable) {
+        final Drawable oldDrawable = mCurrentDrawable;
+        mCurrentDrawable = newDrawable;
+
+        if (oldDrawable != mCurrentDrawable) {
+            if (oldDrawable != null) {
+                oldDrawable.setVisible(false, false);
+            }
+            if (mCurrentDrawable != null) {
+                mCurrentDrawable.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
+            }
+        }
+    }
+
     /**
      * <p>Get the drawable used to draw the progress bar in
      * indeterminate mode.</p>
@@ -654,7 +667,7 @@
             }
 
             if (mIndeterminate) {
-                mCurrentDrawable = d;
+                swapCurrentDrawable(d);
                 postInvalidate();
             }
         }
@@ -820,7 +833,7 @@
             }
 
             if (!mIndeterminate) {
-                mCurrentDrawable = d;
+                swapCurrentDrawable(d);
                 postInvalidate();
             }
 
@@ -1217,7 +1230,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return who == mProgressDrawable || who == mIndeterminateDrawable
                 || super.verifyDrawable(who);
     }
@@ -1555,7 +1568,7 @@
      * <p>Start the indeterminate progress animation.</p>
      */
     void startAnimation() {
-        if (getVisibility() != VISIBLE) {
+        if (getVisibility() != VISIBLE || getWindowVisibility() != VISIBLE) {
             return;
         }
 
@@ -1633,38 +1646,29 @@
     }
 
     @Override
-    @RemotableViewMethod
-    public void setVisibility(int v) {
-        if (getVisibility() != v) {
-            super.setVisibility(v);
+    public void onVisibilityAggregated(boolean isVisible) {
+        super.onVisibilityAggregated(isVisible);
+
+        if (isVisible != mAggregatedIsVisible) {
+            mAggregatedIsVisible = isVisible;
 
             if (mIndeterminate) {
                 // let's be nice with the UI thread
-                if (v == GONE || v == INVISIBLE) {
-                    stopAnimation();
-                } else {
+                if (isVisible) {
                     startAnimation();
+                } else {
+                    stopAnimation();
                 }
             }
-        }
-    }
 
-    @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
-        super.onVisibilityChanged(changedView, visibility);
-
-        if (mIndeterminate) {
-            // let's be nice with the UI thread
-            if (visibility == GONE || visibility == INVISIBLE) {
-                stopAnimation();
-            } else {
-                startAnimation();
+            if (mCurrentDrawable != null) {
+                mCurrentDrawable.setVisible(isVisible, false);
             }
         }
     }
 
     @Override
-    public void invalidateDrawable(Drawable dr) {
+    public void invalidateDrawable(@NonNull Drawable dr) {
         if (!mInDrawing) {
             if (verifyDrawable(dr)) {
                 final Rect dirty = dr.getBounds();
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index df01fc1..0136542 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1103,8 +1103,14 @@
     }
 
     @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new LayoutParams(p);
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) lp);
+        } else if (lp instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) lp);
+        } else {
+            return new LayoutParams(lp);
+        }
     }
 
     /** @hide */
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 4ed175d..6d2cea6 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.ColorInt;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -60,6 +61,7 @@
 import libcore.util.Objects;
 
 import com.android.internal.R;
+import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -227,6 +229,11 @@
 
         public boolean onClickHandler(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
+            return onClickHandler(view, pendingIntent, fillInIntent, StackId.INVALID_STACK_ID);
+        }
+
+        public boolean onClickHandler(View view, PendingIntent pendingIntent,
+                Intent fillInIntent, int launchStackId) {
             try {
                 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
                 Context context = view.getContext();
@@ -238,6 +245,10 @@
                             0, 0,
                             view.getMeasuredWidth(), view.getMeasuredHeight());
                 }
+
+                if (launchStackId != StackId.INVALID_STACK_ID) {
+                    opts.setLaunchStackId(launchStackId);
+                }
                 context.startIntentSender(
                         pendingIntent.getIntentSender(), fillInIntent,
                         Intent.FLAG_ACTIVITY_NEW_TASK,
@@ -454,12 +465,19 @@
                     public void onClick(View v) {
                         // Insure that this view is a child of an AdapterView
                         View parent = (View) v.getParent();
+                        // Break the for loop on the first encounter of:
+                        //    1) an AdapterView,
+                        //    2) an AppWidgetHostView that is not a RemoteViewsFrameLayout, or
+                        //    3) a null parent.
+                        // 2) and 3) are unexpected and catch the case where a child is not
+                        // correctly parented in an AdapterView.
                         while (parent != null && !(parent instanceof AdapterView<?>)
-                                && !(parent instanceof AppWidgetHostView)) {
+                                && !((parent instanceof AppWidgetHostView) &&
+                                    !(parent instanceof RemoteViewsAdapter.RemoteViewsFrameLayout))) {
                             parent = (View) parent.getParent();
                         }
 
-                        if (parent instanceof AppWidgetHostView || parent == null) {
+                        if (!(parent instanceof AdapterView<?>)) {
                             // Somehow they've managed to get this far without having
                             // and AdapterView as a parent.
                             Log.e(LOG_TAG, "Collection item doesn't have AdapterView parent");
@@ -1089,6 +1107,13 @@
                 memoryCounter.addBitmapMemory(mBitmaps.get(i));
             }
         }
+
+        @Override
+        protected BitmapCache clone() {
+            BitmapCache bitmapCache = new BitmapCache();
+            bitmapCache.mBitmaps.addAll(mBitmaps);
+            return bitmapCache;
+        }
     }
 
     private class BitmapReflectionAction extends Action {
@@ -1973,13 +1998,13 @@
 
         public SetRemoteInputsAction(Parcel parcel) {
             viewId = parcel.readInt();
-            remoteInputs = parcel.readParcelableArray(RemoteInput.class.getClassLoader());
+            remoteInputs = parcel.createTypedArray(RemoteInput.CREATOR);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(TAG);
             dest.writeInt(viewId);
-            dest.writeParcelableArray(remoteInputs, flags);
+            dest.writeTypedArray(remoteInputs, flags);
         }
 
         @Override
@@ -2220,10 +2245,21 @@
 
 
     public RemoteViews clone() {
+        Preconditions.checkState(mIsRoot, "RemoteView has been attached to another RemoteView. "
+                + "May only clone the root of a RemoteView hierarchy.");
+
         Parcel p = Parcel.obtain();
+
+        // Do not parcel the Bitmap cache - doing so creates an expensive copy of all bitmaps.
+        // Instead pretend we're not owning the cache while parceling.
+        mIsRoot = false;
         writeToParcel(p, 0);
         p.setDataPosition(0);
-        RemoteViews rv = new RemoteViews(p);
+        mIsRoot = true;
+
+        RemoteViews rv = new RemoteViews(p, mBitmapCache.clone());
+        rv.mIsRoot = true;
+
         p.recycle();
         return rv;
     }
@@ -2233,7 +2269,7 @@
     }
 
     /**
-     * Reutrns the layout id of the root layout associated with this RemoteViews. In the case
+     * Returns the layout id of the root layout associated with this RemoteViews. In the case
      * that the RemoteViews has both a landscape and portrait root, this will return the layout
      * id associated with the portrait layout.
      *
@@ -2556,6 +2592,8 @@
      * @param format The Chronometer format string, or null to
      *               simply display the timer value.
      * @param started True if you want the clock to be started, false if not.
+     *
+     * @see #setChronometerCountsDown(int, boolean)
      */
     public void setChronometer(int viewId, long base, String format, boolean started) {
         setLong(viewId, "setBase", base);
@@ -2564,6 +2602,18 @@
     }
 
     /**
+     * Equivalent to calling {@link Chronometer#setCountDown(boolean) Chronometer.setCountDown} on
+     * the chronometer with the given viewId.
+     *
+     * @param viewId The id of the {@link Chronometer} to change
+     * @param isCountDown True if you want the chronometer to count down to base instead of
+     *                    counting up.
+     */
+    public void setChronometerCountsDown(int viewId, boolean isCountDown) {
+        setBoolean(viewId, "setCountDown", isCountDown);
+    }
+
+    /**
      * Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax},
      * {@link ProgressBar#setProgress ProgressBar.setProgress}, and
      * {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 8278c5a..10abbab 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -288,7 +288,7 @@
      * A FrameLayout which contains a loading view, and manages the re/applying of RemoteViews when
      * they are loaded.
      */
-    private static class RemoteViewsFrameLayout extends AppWidgetHostView {
+    static class RemoteViewsFrameLayout extends AppWidgetHostView {
         private final FixedSizeRemoteViewsCache mCache;
 
         public RemoteViewsFrameLayout(Context context, FixedSizeRemoteViewsCache cache) {
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index 8880217..11eab2a 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.widget.ScrollBarUtils;
 
+import android.annotation.NonNull;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
@@ -362,17 +363,17 @@
     }
 
     @Override
-    public void invalidateDrawable(Drawable who) {
+    public void invalidateDrawable(@NonNull Drawable who) {
         invalidateSelf();
     }
 
     @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+    public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
         scheduleSelf(what, when);
     }
 
     @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
+    public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
         unscheduleSelf(what);
     }
 
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 3f7a07b..0555cd4 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -350,24 +350,24 @@
 
         if (getChildCount() > 0) {
             final View child = getChildAt(0);
-            final int height = getMeasuredHeight();
-            if (child.getMeasuredHeight() < height) {
-                final int widthPadding;
-                final int heightPadding;
-                final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
-                if (targetSdkVersion >= VERSION_CODES.M) {
-                    widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
-                    heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
-                } else {
-                    widthPadding = mPaddingLeft + mPaddingRight;
-                    heightPadding = mPaddingTop + mPaddingBottom;
-                }
+            final int widthPadding;
+            final int heightPadding;
+            final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+            final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (targetSdkVersion >= VERSION_CODES.M) {
+                widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
+                heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
+            } else {
+                widthPadding = mPaddingLeft + mPaddingRight;
+                heightPadding = mPaddingTop + mPaddingBottom;
+            }
 
+            final int desiredHeight = getMeasuredHeight() - heightPadding;
+            if (child.getMeasuredHeight() < desiredHeight) {
                 final int childWidthMeasureSpec = getChildMeasureSpec(
                         widthMeasureSpec, widthPadding, lp.width);
                 final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        height - heightPadding, MeasureSpec.EXACTLY);
+                        desiredHeight, MeasureSpec.EXACTLY);
                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
             }
         }
@@ -1268,9 +1268,10 @@
 
         childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft
                 + mPaddingRight, lp.width);
-
+        final int verticalPadding = mPaddingTop + mPaddingBottom;
         childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
-                MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
+                Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - verticalPadding),
+                MeasureSpec.UNSPECIFIED);
 
         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     }
@@ -1283,8 +1284,11 @@
         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                         + widthUsed, lp.width);
+        final int usedTotal = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin +
+                heightUsed;
         final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
-                MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
+                Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
+                MeasureSpec.UNSPECIFIED);
 
         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     }
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 3796df7..9a4d69f 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1358,6 +1358,17 @@
                     + Integer.toHexString(System.identityHashCode(this))
                     + " isIconified=" + isIconified + "}";
         }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+                    public SavedState createFromParcel(Parcel in) {
+                        return new SavedState(in);
+                    }
+
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
     }
 
     @Override
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 6edce91..ee716df 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -16,6 +16,9 @@
 
 package android.widget;
 
+import com.android.internal.R;
+import com.android.internal.widget.ExploreByTouchHelper;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -33,6 +36,7 @@
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.util.IntArray;
+import android.util.Log;
 import android.util.MathUtils;
 import android.util.StateSet;
 import android.view.KeyEvent;
@@ -43,29 +47,33 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
-import com.android.internal.R;
-import com.android.internal.widget.ExploreByTouchHelper;
-
 import java.text.NumberFormat;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Locale;
 
+import libcore.icu.LocaleData;
+
 /**
  * A calendar-like view displaying a specified month and the appropriate selectable day numbers
  * within the specified month.
  */
 class SimpleMonthView extends View {
+    private static final String LOG_TAG = "SimpleMonthView";
+
     private static final int DAYS_IN_WEEK = 7;
     private static final int MAX_WEEKS_IN_MONTH = 6;
 
     private static final int DEFAULT_SELECTED_DAY = -1;
     private static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
 
-    private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
-    private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
+    private static final String MONTH_YEAR_FORMAT = "MMMMy";
 
     private static final int SELECTED_HIGHLIGHT_ALPHA = 0xB0;
 
+    /** Temporary until we figure out why the date gets messed up. */
+    private static final boolean DEBUG_WRONG_DATE = true;
+
     private final TextPaint mMonthPaint = new TextPaint();
     private final TextPaint mDayOfWeekPaint = new TextPaint();
     private final TextPaint mDayPaint = new TextPaint();
@@ -73,13 +81,14 @@
     private final Paint mDayHighlightPaint = new Paint();
     private final Paint mDayHighlightSelectorPaint = new Paint();
 
-    private final Calendar mCalendar = Calendar.getInstance();
-    private final Calendar mDayOfWeekLabelCalendar = Calendar.getInstance();
+    /** Array of single-character weekday labels ordered by column index. */
+    private final String[] mDayOfWeekLabels = new String[7];
+
+    private final Calendar mCalendar;
+    private final Locale mLocale;
 
     private final MonthViewTouchHelper mTouchHelper;
 
-    private final SimpleDateFormat mTitleFormatter;
-    private final SimpleDateFormat mDayOfWeekFormatter;
     private final NumberFormat mDayFormatter;
 
     // Desired dimensions.
@@ -89,7 +98,7 @@
     private final int mDesiredCellWidth;
     private final int mDesiredDaySelectorRadius;
 
-    private CharSequence mTitle;
+    private String mMonthYearLabel;
 
     private int mMonth;
     private int mYear;
@@ -113,7 +122,7 @@
      */
     private int mToday = DEFAULT_SELECTED_DAY;
 
-    /** The first day of the week (ex. Calendar.SUNDAY). */
+    /** The first day of the week (ex. Calendar.SUNDAY) indexed from one. */
     private int mWeekStart = DEFAULT_WEEK_START;
 
     /** The number of days (ex. 28) in the current month. */
@@ -168,15 +177,42 @@
         setAccessibilityDelegate(mTouchHelper);
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
 
-        final Locale locale = res.getConfiguration().locale;
-        final String titleFormat = DateFormat.getBestDateTimePattern(locale, DEFAULT_TITLE_FORMAT);
-        mTitleFormatter = new SimpleDateFormat(titleFormat, locale);
-        mDayOfWeekFormatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, locale);
-        mDayFormatter = NumberFormat.getIntegerInstance(locale);
+        mLocale = res.getConfiguration().locale;
+        mCalendar = Calendar.getInstance(mLocale);
+
+        mDayFormatter = NumberFormat.getIntegerInstance(mLocale);
+
+        updateMonthYearLabel();
+        updateDayOfWeekLabels();
 
         initPaints(res);
     }
 
+    private void updateMonthYearLabel() {
+        final String format = DateFormat.getBestDateTimePattern(mLocale, MONTH_YEAR_FORMAT);
+        final SimpleDateFormat formatter = new SimpleDateFormat(format, mLocale);
+        mMonthYearLabel = formatter.format(mCalendar.getTime());
+    }
+
+    private void updateDayOfWeekLabels() {
+        if (DEBUG_WRONG_DATE) {
+            Log.d(LOG_TAG, "enter updateDayOfWeekLabels()", new Exception());
+            Log.d(LOG_TAG, "mLocale => " + mLocale);
+            Log.d(LOG_TAG, "mWeekStart => " + mWeekStart);
+        }
+
+        // Use tiny (e.g. single-character) weekday names from ICU. The indices
+        // for this list correspond to Calendar days, e.g. SUNDAY is index 1.
+        final String[] tinyWeekdayNames = LocaleData.get(mLocale).tinyWeekdayNames;
+        for (int i = 0; i < DAYS_IN_WEEK; i++) {
+            mDayOfWeekLabels[i] = tinyWeekdayNames[(mWeekStart + i - 1) % DAYS_IN_WEEK + 1];
+        }
+
+        if (DEBUG_WRONG_DATE) {
+            Log.d(LOG_TAG, "mDayOfWeekLabels <= " + Arrays.toString(mDayOfWeekLabels));
+        }
+    }
+
     /**
      * Applies the specified text appearance resource to a paint, returning the
      * text color if one is set in the text appearance.
@@ -236,13 +272,6 @@
         invalidate();
     }
 
-    public CharSequence getTitle() {
-        if (mTitle == null) {
-            mTitle = mTitleFormatter.format(mCalendar.getTime());
-        }
-        return mTitle;
-    }
-
     /**
      * Sets up the text and style properties for painting.
      */
@@ -607,7 +636,11 @@
         final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent();
         final float y = (mMonthHeight - lineHeight) / 2f;
 
-        canvas.drawText(getTitle().toString(), x, y, mMonthPaint);
+        canvas.drawText(mMonthYearLabel, x, y, mMonthPaint);
+    }
+
+    public String getMonthYearLabel() {
+        return mMonthYearLabel;
     }
 
     private void drawDaysOfWeek(Canvas canvas) {
@@ -629,17 +662,11 @@
                 colCenterRtl = colCenter;
             }
 
-            final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK;
-            final String label = getDayOfWeekLabel(dayOfWeek);
+            final String label = mDayOfWeekLabels[col];
             canvas.drawText(label, colCenterRtl, rowCenter - halfLineHeight, p);
         }
     }
 
-    private String getDayOfWeekLabel(int dayOfWeek) {
-        mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
-        return mDayOfWeekFormatter.format(mDayOfWeekLabelCalendar.getTime());
-    }
-
     /**
      * Draws the month days.
      */
@@ -746,12 +773,22 @@
      *                  {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY}
      */
     public void setFirstDayOfWeek(int weekStart) {
+        if (DEBUG_WRONG_DATE) {
+            Log.d(LOG_TAG, "enter setFirstDayOfWeek(" + weekStart + ")", new Exception());
+        }
+
         if (isValidDayOfWeek(weekStart)) {
             mWeekStart = weekStart;
         } else {
             mWeekStart = mCalendar.getFirstDayOfWeek();
         }
 
+        if (DEBUG_WRONG_DATE) {
+            Log.d(LOG_TAG, "mWeekStart <=" + mWeekStart);
+        }
+
+        updateDayOfWeekLabels();
+
         // Invalidate cached accessibility information.
         mTouchHelper.invalidateRoot();
         invalidate();
@@ -775,6 +812,11 @@
      */
     void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart,
             int enabledDayEnd) {
+        if (DEBUG_WRONG_DATE) {
+            Log.d(LOG_TAG, "setMonthParams(" + selectedDay + ", " + month + ", " + year + ", "
+                    + weekStart + ", " + enabledDayStart + ", " + enabledDayEnd + ")");
+        }
+
         mActivatedDay = selectedDay;
 
         if (isValidMonth(month)) {
@@ -807,11 +849,18 @@
         mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth);
         mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth);
 
-        // Invalidate the old title.
-        mTitle = null;
-
         // Invalidate cached accessibility information.
         mTouchHelper.invalidateRoot();
+
+        updateMonthYearLabel();
+
+        if (DEBUG_WRONG_DATE) {
+            Log.d(LOG_TAG, "mMonth = " + mMonth);
+            Log.d(LOG_TAG, "mDayOfWeekStart = " + mDayOfWeekStart);
+            Log.d(LOG_TAG, "mWeekStart = " + mWeekStart);
+            Log.d(LOG_TAG, "mDaysInMonth = " + mDaysInMonth);
+            Log.d(LOG_TAG, "mToday = " + mToday);
+        }
     }
 
     private static int getDaysInMonth(int month, int year) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 434516d..c4a1771 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -18,6 +18,7 @@
 
 import android.animation.ObjectAnimator;
 import android.annotation.DrawableRes;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.content.Context;
@@ -1371,7 +1372,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 95fcdc1..4483b7ba 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,9 +17,11 @@
 package android.widget;
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
 import android.R;
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
@@ -284,8 +286,8 @@
 
     private static final RectF TEMP_RECTF = new RectF();
 
-    // XXX should be much larger
-    private static final int VERY_WIDE = 1024*1024;
+    /** @hide */
+    static final int VERY_WIDE = 1024 * 1024; // XXX should be much larger
     private static final int ANIMATED_SCROLL_GAP = 250;
 
     private static final InputFilter[] NO_FILTERS = new InputFilter[0];
@@ -328,10 +330,6 @@
     private int mCurTextColor;
     private int mCurHintTextColor;
     private boolean mFreezesText;
-    private boolean mDispatchTemporaryDetach;
-
-    /** Whether this view is temporarily detached from the parent view. */
-    boolean mTemporaryDetach;
 
     private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
     private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
@@ -662,11 +660,12 @@
      */
     private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN;
 
-    /*
+    /**
      * Kick-start the font cache for the zygote process (to pay the cost of
      * initializing freetype for our default font only once).
+     * @hide
      */
-    static {
+    public static void preloadFontCache() {
         Paint p = new Paint();
         p.setAntiAlias(true);
         // We don't care about the result, just the side-effect of measuring.
@@ -1509,6 +1508,9 @@
                 if (result != null) {
                     if (isTextEditable()) {
                         replaceSelectionWithText(result);
+                        if (mEditor != null) {
+                            mEditor.refreshTextActionMode();
+                        }
                     } else {
                         if (result.length() > 0) {
                             Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG)
@@ -1518,12 +1520,7 @@
                 }
             } else if (mText instanceof Spannable) {
                 // Reset the selection.
-                stopTextActionMode();
-                Selection.setSelection((Spannable) mText, getSelectionStart(), getSelectionEnd());
-            }
-
-            if (mEditor.hasSelectionController()) {
-                mEditor.startSelectionActionMode();
+                Selection.setSelection((Spannable) mText, getSelectionEnd());
             }
         }
     }
@@ -2892,6 +2889,11 @@
     public void setTextLocale(@NonNull Locale locale) {
         mLocalesChanged = true;
         mTextPaint.setTextLocale(locale);
+        if (mLayout != null) {
+            nullLayouts();
+            requestLayout();
+            invalidate();
+        }
     }
 
     /**
@@ -2908,6 +2910,11 @@
     public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
         mLocalesChanged = true;
         mTextPaint.setTextLocales(locales);
+        if (mLayout != null) {
+            nullLayouts();
+            requestLayout();
+            invalidate();
+        }
     }
 
     @Override
@@ -2915,6 +2922,11 @@
         super.onConfigurationChanged(newConfig);
         if (!mLocalesChanged) {
             mTextPaint.setTextLocales(LocaleList.getDefault());
+            if (mLayout != null) {
+                nullLayouts();
+                requestLayout();
+                invalidate();
+            }
         }
     }
 
@@ -3071,7 +3083,14 @@
      * @attr ref android.R.styleable#TextView_elegantTextHeight
      */
     public void setElegantTextHeight(boolean elegant) {
-        mTextPaint.setElegantTextHeight(elegant);
+        if (elegant != mTextPaint.isElegantTextHeight()) {
+            mTextPaint.setElegantTextHeight(elegant);
+            if (mLayout != null) {
+                nullLayouts();
+                requestLayout();
+                invalidate();
+            }
+        }
     }
 
     /**
@@ -3108,10 +3127,15 @@
     }
 
     /**
+     * Returns the font feature settings. The format is the same as the CSS
+     * font-feature-settings attribute:
+     * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+     *     http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
+     *
      * @return the currently set font feature settings.  Default is null.
      *
      * @see #setFontFeatureSettings(String)
-     * @see Paint#setFontFeatureSettings
+     * @see Paint#setFontFeatureSettings(String) Paint.setFontFeatureSettings(String)
      */
     @Nullable
     public String getFontFeatureSettings() {
@@ -3175,13 +3199,15 @@
     }
 
     /**
-     * Sets font feature settings.  The format is the same as the CSS
+     * Sets font feature settings. The format is the same as the CSS
      * font-feature-settings attribute:
-     * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
+     * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+     *     http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
      *
      * @param fontFeatureSettings font feature settings represented as CSS compatible string
+     *
      * @see #getFontFeatureSettings()
-     * @see Paint#getFontFeatureSettings
+     * @see Paint#getFontFeatureSettings() Paint.getFontFeatureSettings()
      *
      * @attr ref android.R.styleable#TextView_fontFeatureSettings
      */
@@ -3396,17 +3422,10 @@
     }
 
     /**
-     * Sets whether the movement method will automatically be set to {@link LinkMovementMethod}
-     * after {@link #setText} or {@link #append} is called. The movement method is set if one of the
-     * following is true:
-     * <ul>
-     * <li>{@link #setAutoLinkMask} has been set to nonzero and links are detected in
-     * {@link #setText} or {@link #append}.
-     * <li>The input for {@link #setText} or {@link #append} contains a {@link ClickableSpan}.
-     * </ul>
-     *
-     * <p>This function does not have an immediate effect, movement method will be set only after a
-     * call to {@link #setText} or {@link #append}. The default is true.</p>
+     * Sets whether the movement method will automatically be set to
+     * {@link LinkMovementMethod} if {@link #setAutoLinkMask} has been
+     * set to nonzero and links are detected in {@link #setText}.
+     * The default is true.
      *
      * @attr ref android.R.styleable#TextView_linksClickable
      */
@@ -3416,14 +3435,10 @@
     }
 
     /**
-     * Returns whether the movement method will automatically be set to {@link LinkMovementMethod}
-     * after {@link #setText} or {@link #append} is called.
-     *
-     * See {@link #setLinksClickable} for details.
-     *
-     * <p>The default is true.</p>
-     *
-     * @see #setLinksClickable
+     * Returns whether the movement method will automatically be set to
+     * {@link LinkMovementMethod} if {@link #setAutoLinkMask} has been
+     * set to nonzero and links are detected in {@link #setText}.
+     * The default is true.
      *
      * @attr ref android.R.styleable#TextView_linksClickable
      */
@@ -4017,19 +4032,13 @@
 
         ((Editable) mText).append(text, start, end);
 
-        boolean hasClickableSpans = false;
         if (mAutoLinkMask != 0) {
-            hasClickableSpans = Linkify.addLinks((Spannable) mText, mAutoLinkMask);
-        } else if (mLinksClickable && text instanceof Spanned) {
-            ClickableSpan[] clickableSpans =
-                    ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
-            hasClickableSpans = clickableSpans != null && clickableSpans.length > 0;
-        }
-
-        // Do not change the movement method for text that supports text selection as it
-        // would prevent an arbitrary cursor displacement.
-        if (hasClickableSpans && mLinksClickable && !textCanBeSelected()) {
-            setMovementMethod(LinkMovementMethod.getInstance());
+            boolean linksWereAdded = Linkify.addLinks((Spannable) mText, mAutoLinkMask);
+            // Do not change the movement method for text that support text selection as it
+            // would prevent an arbitrary cursor displacement.
+            if (linksWereAdded && mLinksClickable && !textCanBeSelected()) {
+                setMovementMethod(LinkMovementMethod.getInstance());
+            }
         }
     }
 
@@ -4382,7 +4391,6 @@
             text = TextUtils.stringOrSpannedString(text);
         }
 
-        boolean hasClickableSpans = false;
         if (mAutoLinkMask != 0) {
             Spannable s2;
 
@@ -4392,32 +4400,22 @@
                 s2 = mSpannableFactory.newSpannable(text);
             }
 
-            hasClickableSpans = Linkify.addLinks(s2, mAutoLinkMask);
-            if (hasClickableSpans) {
+            if (Linkify.addLinks(s2, mAutoLinkMask)) {
                 text = s2;
-            }
-        } else if (mLinksClickable && text instanceof Spanned) {
-            ClickableSpan[] clickableSpans =
-                    ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
-            hasClickableSpans = clickableSpans != null && clickableSpans.length > 0;
-            if (hasClickableSpans && !(text instanceof Spannable)) {
-                text = mSpannableFactory.newSpannable(text);
-            }
-        }
+                type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;
 
-        if (hasClickableSpans) {
-            type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;
-            /*
-             * We must go ahead and set the text before changing the
-             * movement method, because setMovementMethod() may call
-             * setText() again to try to upgrade the buffer type.
-             */
-            mText = text;
+                /*
+                 * We must go ahead and set the text before changing the
+                 * movement method, because setMovementMethod() may call
+                 * setText() again to try to upgrade the buffer type.
+                 */
+                mText = text;
 
-            // Do not change the movement method for text that supports text selection as it
-            // would prevent an arbitrary cursor displacement.
-            if (mLinksClickable && !textCanBeSelected()) {
-                setMovementMethod(LinkMovementMethod.getInstance());
+                // Do not change the movement method for text that support text selection as it
+                // would prevent an arbitrary cursor displacement.
+                if (mLinksClickable && !textCanBeSelected()) {
+                    setMovementMethod(LinkMovementMethod.getInstance());
+                }
             }
         }
 
@@ -5391,11 +5389,7 @@
         // - onFocusChanged cannot start it when focus is given to a view with selected text (after
         //   a screen rotation) since layout is not yet initialized at that point.
         if (mEditor != null && mEditor.mCreatedWithASelection) {
-            if (mEditor.extractedTextModeWillBeStarted()) {
-                mEditor.checkFieldAndSelectCurrentWord();
-            } else {
-                mEditor.startSelectionActionMode();
-            }
+            mEditor.refreshTextActionMode();
             mEditor.mCreatedWithASelection = false;
         }
 
@@ -5408,8 +5402,6 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
-        mTemporaryDetach = false;
-
         if (mEditor != null) mEditor.onAttachedToWindow();
 
         if (mPreDrawListenerDetached) {
@@ -5467,7 +5459,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         final boolean verified = super.verifyDrawable(who);
         if (!verified && mDrawables != null) {
             for (Drawable dr : mDrawables.mShowing) {
@@ -5492,7 +5484,7 @@
     }
 
     @Override
-    public void invalidateDrawable(Drawable drawable) {
+    public void invalidateDrawable(@NonNull Drawable drawable) {
         boolean handled = false;
 
         if (verifyDrawable(drawable)) {
@@ -5834,8 +5826,7 @@
 
         final int layoutDirection = getLayoutDirection();
         final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-        if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
-                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
+        if (isMarqueeFadeEnabled()) {
             if (!mSingleLine && getLineCount() == 1 && canMarquee() &&
                     (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
                 final int width = mRight - mLeft;
@@ -6550,7 +6541,7 @@
                 if (TextUtils.equals(content.subSequence(start, end), text.text)) {
                     if (text.text instanceof Spanned) {
                         // OK to copy spans only.
-                        TextUtils.copySpansFrom((Spanned) text.text, start, end,
+                        TextUtils.copySpansFrom((Spanned) text.text, 0, end - start,
                                 Object.class, content, start);
                     }
                 } else {
@@ -6593,6 +6584,9 @@
         // in the extracted view.
         mEditor.hideCursorAndSpanControllers();
         stopTextActionMode();
+        if (mEditor.mSelectionModifierCursorController != null) {
+            mEditor.mSelectionModifierCursorController.resetTouchOffsets();
+        }
     }
 
     /**
@@ -7887,7 +7881,7 @@
     }
 
     /**
-     * Causes words in the text that are longer than the view is wide
+     * Causes words in the text that are longer than the view's width
      * to be ellipsized instead of broken in the middle.  You may also
      * want to {@link #setSingleLine} or {@link #setHorizontallyScrolling}
      * to constrain the text to a single line.  Use <code>null</code>
@@ -8288,6 +8282,14 @@
                 if (newSelEnd < 0) {
                     newSelEnd = Selection.getSelectionEnd(buf);
                 }
+
+                if (mEditor != null) {
+                    mEditor.refreshTextActionMode();
+                    if (!hasSelection() && mEditor.mTextActionMode == null && hasTransientState()) {
+                        // User generated selection has been removed.
+                        setHasTransientState(false);
+                    }
+                }
                 onSelectionChanged(newSelStart, newSelEnd);
             }
         }
@@ -8358,40 +8360,9 @@
         }
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public void dispatchFinishTemporaryDetach() {
-        mDispatchTemporaryDetach = true;
-        super.dispatchFinishTemporaryDetach();
-        mDispatchTemporaryDetach = false;
-    }
-
-    @Override
-    public void onStartTemporaryDetach() {
-        super.onStartTemporaryDetach();
-        // Only track when onStartTemporaryDetach() is called directly,
-        // usually because this instance is an editable field in a list
-        if (!mDispatchTemporaryDetach) mTemporaryDetach = true;
-
-        // Tell the editor that we are temporarily detached. It can use this to preserve
-        // selection state as needed.
-        if (mEditor != null) mEditor.mTemporaryDetach = true;
-    }
-
-    @Override
-    public void onFinishTemporaryDetach() {
-        super.onFinishTemporaryDetach();
-        // Only track when onStartTemporaryDetach() is called directly,
-        // usually because this instance is an editable field in a list
-        if (!mDispatchTemporaryDetach) mTemporaryDetach = false;
-        if (mEditor != null) mEditor.mTemporaryDetach = false;
-    }
-
     @Override
     protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
-        if (mTemporaryDetach) {
+        if (isTemporarilyDetached()) {
             // If we are temporarily in the detach state, then do nothing.
             super.onFocusChanged(focused, direction, previouslyFocusedRect);
             return;
@@ -8615,78 +8586,59 @@
 
     @Override
     protected float getLeftFadingEdgeStrength() {
-        if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
-                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
-            if (mMarquee != null && !mMarquee.isStopped()) {
-                final Marquee marquee = mMarquee;
-                if (marquee.shouldDrawLeftFade()) {
-                    final float scroll = marquee.getScroll();
-                    return scroll / getHorizontalFadingEdgeLength();
-                } else {
-                    return 0.0f;
-                }
-            } else if (getLineCount() == 1) {
-                final int layoutDirection = getLayoutDirection();
-                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-                    case Gravity.LEFT:
-                        return 0.0f;
-                    case Gravity.RIGHT:
-                        return (mLayout.getLineRight(0) - (mRight - mLeft) -
-                                getCompoundPaddingLeft() - getCompoundPaddingRight() -
-                                mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
-                    case Gravity.CENTER_HORIZONTAL:
-                    case Gravity.FILL_HORIZONTAL:
-                        final int textDirection = mLayout.getParagraphDirection(0);
-                        if (textDirection == Layout.DIR_LEFT_TO_RIGHT) {
-                            return 0.0f;
-                        } else {
-                            return (mLayout.getLineRight(0) - (mRight - mLeft) -
-                                getCompoundPaddingLeft() - getCompoundPaddingRight() -
-                                mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
-                        }
-                }
+        if (isMarqueeFadeEnabled() && mMarquee != null && !mMarquee.isStopped()) {
+            final Marquee marquee = mMarquee;
+            if (marquee.shouldDrawLeftFade()) {
+                return getHorizontalFadingEdgeStrength(marquee.getScroll(), 0.0f);
+            } else {
+                return 0.0f;
             }
+        } else if (getLineCount() == 1) {
+            final float lineLeft = getLayout().getLineLeft(0);
+            if(lineLeft > mScrollX) return 0.0f;
+            return getHorizontalFadingEdgeStrength(mScrollX, lineLeft);
         }
         return super.getLeftFadingEdgeStrength();
     }
 
     @Override
     protected float getRightFadingEdgeStrength() {
-        if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
-                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
-            if (mMarquee != null && !mMarquee.isStopped()) {
-                final Marquee marquee = mMarquee;
-                final float maxFadeScroll = marquee.getMaxFadeScroll();
-                final float scroll = marquee.getScroll();
-                return (maxFadeScroll - scroll) / getHorizontalFadingEdgeLength();
-            } else if (getLineCount() == 1) {
-                final int layoutDirection = getLayoutDirection();
-                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-                    case Gravity.LEFT:
-                        final int textWidth = (mRight - mLeft) - getCompoundPaddingLeft() -
-                                getCompoundPaddingRight();
-                        final float lineWidth = mLayout.getLineWidth(0);
-                        return (lineWidth - textWidth) / getHorizontalFadingEdgeLength();
-                    case Gravity.RIGHT:
-                        return 0.0f;
-                    case Gravity.CENTER_HORIZONTAL:
-                    case Gravity.FILL_HORIZONTAL:
-                        final int textDirection = mLayout.getParagraphDirection(0);
-                        if (textDirection == Layout.DIR_RIGHT_TO_LEFT) {
-                            return 0.0f;
-                        } else {
-                            return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
-                                getCompoundPaddingLeft() - getCompoundPaddingRight())) /
-                                getHorizontalFadingEdgeLength();
-                        }
-                }
-            }
+        if (isMarqueeFadeEnabled() && mMarquee != null && !mMarquee.isStopped()) {
+            final Marquee marquee = mMarquee;
+            return getHorizontalFadingEdgeStrength(marquee.getMaxFadeScroll(), marquee.getScroll());
+        } else if (getLineCount() == 1) {
+            final float rightEdge = mScrollX + (getWidth() - getCompoundPaddingLeft() -
+                    getCompoundPaddingRight());
+            final float lineRight = getLayout().getLineRight(0);
+            if(lineRight < rightEdge) return 0.0f;
+            return getHorizontalFadingEdgeStrength(rightEdge, lineRight);
         }
         return super.getRightFadingEdgeStrength();
     }
 
+    /**
+     * Calculates the fading edge strength as the ratio of the distance between two
+     * horizontal positions to {@link View#getHorizontalFadingEdgeLength()}. Uses the absolute
+     * value for the distance calculation.
+     *
+     * @param position1 A horizontal position.
+     * @param position2 A horizontal position.
+     * @return Fading edge strength between [0.0f, 1.0f].
+     */
+    @FloatRange(from=0.0, to=1.0)
+    private final float getHorizontalFadingEdgeStrength(float position1, float position2) {
+        final int horizontalFadingEdgeLength = getHorizontalFadingEdgeLength();
+        if(horizontalFadingEdgeLength == 0) return 0.0f;
+        final float diff = Math.abs(position1 - position2);
+        if(diff > horizontalFadingEdgeLength) return 1.0f;
+        return diff / horizontalFadingEdgeLength;
+    }
+
+    private final boolean isMarqueeFadeEnabled() {
+        return mEllipsize == TextUtils.TruncateAt.MARQUEE &&
+                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
+    }
+
     @Override
     protected int computeHorizontalScrollRange() {
         if (mLayout != null) {
@@ -8927,8 +8879,7 @@
     }
 
     void onLocaleChanged() {
-        // Will be re-created on demand in getWordIterator with the proper new locale
-        mEditor.mWordIterator = null;
+        mEditor.onLocaleChanged();
     }
 
     /**
@@ -9106,6 +9057,9 @@
 
         if (mBufferType == BufferType.EDITABLE) {
             info.setEditable(true);
+            if (isEnabled()) {
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
+            }
         }
 
         if (mEditor != null) {
@@ -9237,6 +9191,17 @@
                     }
                 }
             } return false;
+            case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+                if (!isEnabled() || (mBufferType != BufferType.EDITABLE)) {
+                    return false;
+                }
+                CharSequence text = (arguments != null) ? arguments.getCharSequence(
+                        AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
+                setText(text);
+                if (text != null && text.length() > 0) {
+                    Selection.setSelection((Spannable) mText, text.length());
+                }
+            } return true;
             default: {
                 return super.performAccessibilityActionInternal(action, arguments);
             }
@@ -9245,52 +9210,12 @@
 
     private boolean performAccessibilityActionClick(Bundle arguments) {
         boolean handled = false;
-        boolean processed = false;
 
         if (!isEnabled()) {
             return false;
         }
 
-        if (arguments != null && arguments.containsKey(
-                AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT)) {
-            int spanIndex = arguments.getInt(
-                    AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT, -1);
-            if (spanIndex >= 0 && hasSpannableText()) {
-                ClickableSpan[] spans = ((Spannable) mText).getSpans(0,
-                        mText.length(), ClickableSpan.class);
-                if (spans != null && spans.length > spanIndex && spans[spanIndex] != null) {
-                    // Simulate View.onTouchEvent for an ACTION_UP event
-                    if (isFocusable() && !isFocused()) {
-                        requestFocus();
-                    }
-                    spans[spanIndex].onClick(this);
-                    handled = true;
-                }
-            }
-            processed = true;
-        }
-
-        if (!processed && arguments != null &&  arguments.containsKey(
-                AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT)) {
-            int characterIndex = arguments.getInt(
-                    AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT, -1);
-            if (characterIndex >= 0 && hasSpannableText()) {
-                ClickableSpan[] spans = ((Spannable) mText).getSpans(characterIndex,
-                        characterIndex, ClickableSpan.class);
-                // click only on the first span to keep parity with onTouch() implementation
-                if (spans != null && spans.length > 0 && spans[0] != null) {
-                    // Simulate View.onTouchEvent for an ACTION_UP event
-                    if (isFocusable() && !isFocused()) {
-                        requestFocus();
-                    }
-                    spans[0].onClick(this);
-                    handled = true;
-                }
-            }
-            processed = true;
-        }
-
-        if (!processed && (isClickable() || isLongClickable())) {
+        if (isClickable() || isLongClickable()) {
             // Simulate View.onTouchEvent for an ACTION_UP event
             if (isFocusable() && !isFocused()) {
                 requestFocus();
@@ -9411,16 +9336,7 @@
 
         switch (id) {
             case ID_SELECT_ALL:
-                // This starts an action mode if triggered from another action mode. Text is
-                // highlighted, so that it can be bulk edited, like selectAllOnFocus does. Returns
-                // true even if text is empty.
-                boolean shouldRestartActionMode =
-                        mEditor != null && mEditor.mTextActionMode != null;
-                stopTextActionMode();
                 selectAllText();
-                if (shouldRestartActionMode) {
-                    mEditor.startSelectionActionMode();
-                }
                 return true;
 
             case ID_UNDO:
@@ -9446,7 +9362,6 @@
             case ID_CUT:
                 setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
                 deleteText_internal(min, max);
-                stopTextActionMode();
                 return true;
 
             case ID_COPY:
@@ -9661,7 +9576,10 @@
     }
 
     boolean canShare() {
-        return canCopy() && isDeviceProvisioned();
+        if (!getContext().canStartActivityForResult() || !isDeviceProvisioned()) {
+            return false;
+        }
+        return canCopy();
     }
 
     boolean isDeviceProvisioned() {
@@ -9684,16 +9602,10 @@
     }
 
     boolean canProcessText() {
-        if (!getContext().canStartActivityForResult() || getId() == View.NO_ID
-                || hasPasswordTransformationMethod()) {
+        if (getId() == View.NO_ID) {
             return false;
         }
-
-        if (mText.length() > 0 && hasSelection() && mEditor != null) {
-            return true;
-        }
-
-        return false;
+        return canShare();
     }
 
     boolean canSelectAllText() {
@@ -9702,12 +9614,6 @@
     }
 
     boolean selectAllText() {
-        // Need to hide insert point cursor controller before settings selection, otherwise insert
-        // point cursor controller obtains cursor update event and update cursor with cancelling
-        // selection.
-        if (mEditor != null) {
-            mEditor.hideInsertionPointCursorController();
-        }
         final int length = mText.length();
         Selection.setSelection((Spannable) mText, 0, length);
         return length > 0;
@@ -9746,7 +9652,6 @@
                     }
                 }
             }
-            stopTextActionMode();
             sLastCutCopyOrTextChangedTime = 0;
         }
     }
@@ -9759,7 +9664,7 @@
             sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT);
             sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText);
             getContext().startActivity(Intent.createChooser(sharingIntent, null));
-            stopTextActionMode();
+            Selection.setSelection((Spannable) mText, getSelectionEnd());
         }
     }
 
@@ -10077,6 +9982,12 @@
                 && getAccessibilitySelectionEnd() == end) {
             return;
         }
+        CharSequence text = getIterableTextForAccessibility();
+        if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
+            Selection.setSelection((Spannable) text, start, end);
+        } else {
+            Selection.removeSelection((Spannable) text);
+        }
         // Hide all selection controllers used for adjusting selection
         // since we are doing so explicitlty by other means and these
         // controllers interact with how selection behaves.
@@ -10084,12 +9995,6 @@
             mEditor.hideCursorAndSpanControllers();
             mEditor.stopTextActionMode();
         }
-        CharSequence text = getIterableTextForAccessibility();
-        if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
-            Selection.setSelection((Spannable) text, start, end);
-        } else {
-            Selection.removeSelection((Spannable) text);
-        }
     }
 
     /** @hide */
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index a24d37f..f2fc617 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -22,8 +22,11 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Parcelable.Creator;
 import android.util.AttributeSet;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import com.android.internal.R;
 
@@ -301,5 +304,69 @@
             mContext = context;
             mLocale = context.getResources().getConfiguration().locale;
         }
+
+        protected static class SavedState extends View.BaseSavedState {
+            private final int mHour;
+            private final int mMinute;
+            private final boolean mIs24HourMode;
+            private final int mCurrentItemShowing;
+
+            public SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode) {
+                this(superState, hour, minute, is24HourMode, 0);
+            }
+
+            public SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
+                    int currentItemShowing) {
+                super(superState);
+                mHour = hour;
+                mMinute = minute;
+                mIs24HourMode = is24HourMode;
+                mCurrentItemShowing = currentItemShowing;
+            }
+
+            private SavedState(Parcel in) {
+                super(in);
+                mHour = in.readInt();
+                mMinute = in.readInt();
+                mIs24HourMode = (in.readInt() == 1);
+                mCurrentItemShowing = in.readInt();
+            }
+
+            public int getHour() {
+                return mHour;
+            }
+
+            public int getMinute() {
+                return mMinute;
+            }
+
+            public boolean is24HourMode() {
+                return mIs24HourMode;
+            }
+
+            public int getCurrentItemShowing() {
+                return mCurrentItemShowing;
+            }
+
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {
+                super.writeToParcel(dest, flags);
+                dest.writeInt(mHour);
+                dest.writeInt(mMinute);
+                dest.writeInt(mIs24HourMode ? 1 : 0);
+                dest.writeInt(mCurrentItemShowing);
+            }
+
+            @SuppressWarnings({"unused", "hiding"})
+            public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+                public SavedState createFromParcel(Parcel in) {
+                    return new SavedState(in);
+                }
+
+                public SavedState[] newArray(int size) {
+                    return new SavedState[size];
+                }
+            };
+        }
     }
 }
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 05fd4c8..4a24e26 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -21,7 +21,6 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.SpannableStringBuilder;
 import android.text.format.DateFormat;
@@ -45,7 +44,6 @@
 import com.android.internal.widget.NumericTextView.OnValueChangedListener;
 
 import java.util.Calendar;
-import java.util.Locale;
 
 /**
  * A delegate implementing the radial clock-based TimePicker.
@@ -501,9 +499,11 @@
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        final SavedState ss = (SavedState) state;
-        initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
-        mRadialTimePickerView.invalidate();
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
+            initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
+            mRadialTimePickerView.invalidate();
+        }
     }
 
     @Override
@@ -544,70 +544,6 @@
         }
     }
 
-    /**
-     * Used to save / restore state of time picker
-     */
-    private static class SavedState extends View.BaseSavedState {
-
-        private final int mHour;
-        private final int mMinute;
-        private final boolean mIs24HourMode;
-        private final int mCurrentItemShowing;
-
-        private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
-                int currentItemShowing) {
-            super(superState);
-            mHour = hour;
-            mMinute = minute;
-            mIs24HourMode = is24HourMode;
-            mCurrentItemShowing = currentItemShowing;
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            mHour = in.readInt();
-            mMinute = in.readInt();
-            mIs24HourMode = (in.readInt() == 1);
-            mCurrentItemShowing = in.readInt();
-        }
-
-        public int getHour() {
-            return mHour;
-        }
-
-        public int getMinute() {
-            return mMinute;
-        }
-
-        public boolean is24HourMode() {
-            return mIs24HourMode;
-        }
-
-        public int getCurrentItemShowing() {
-            return mCurrentItemShowing;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mHour);
-            dest.writeInt(mMinute);
-            dest.writeInt(mIs24HourMode ? 1 : 0);
-            dest.writeInt(mCurrentItemShowing);
-        }
-
-        @SuppressWarnings({"unused", "hiding"})
-        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
     private void tryVibrate() {
         mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
     }
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 863d409..b113fd9 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
@@ -32,7 +31,6 @@
 import com.android.internal.R;
 
 import java.util.Calendar;
-import java.util.Locale;
 
 import libcore.icu.LocaleData;
 
@@ -387,14 +385,16 @@
 
     @Override
     public Parcelable onSaveInstanceState(Parcelable superState) {
-        return new SavedState(superState, getHour(), getMinute());
+        return new SavedState(superState, getHour(), getMinute(), is24Hour());
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        SavedState ss = (SavedState) state;
-        setHour(ss.getHour());
-        setMinute(ss.getMinute());
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
+            setHour(ss.getHour());
+            setMinute(ss.getMinute());
+        }
     }
 
     @Override
@@ -525,52 +525,6 @@
         }
     }
 
-    /**
-     * Used to save / restore state of time picker
-     */
-    private static class SavedState extends View.BaseSavedState {
-        private final int mHour;
-        private final int mMinute;
-
-        private SavedState(Parcelable superState, int hour, int minute) {
-            super(superState);
-            mHour = hour;
-            mMinute = minute;
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            mHour = in.readInt();
-            mMinute = in.readInt();
-        }
-
-        public int getHour() {
-            return mHour;
-        }
-
-        public int getMinute() {
-            return mMinute;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mHour);
-            dest.writeInt(mMinute);
-        }
-
-        @SuppressWarnings({"unused", "hiding"})
-        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
     public static String[] getAmPmStrings(Context context) {
         String[] result = new String[2];
         LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 06daf61..9cdb73a 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
+import android.annotation.TestApi;
 import android.app.ActionBar;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -106,6 +107,8 @@
  * @attr ref android.R.styleable#Toolbar_contentInsetLeft
  * @attr ref android.R.styleable#Toolbar_contentInsetRight
  * @attr ref android.R.styleable#Toolbar_contentInsetStart
+ * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
+ * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
  * @attr ref android.R.styleable#Toolbar_gravity
  * @attr ref android.R.styleable#Toolbar_logo
  * @attr ref android.R.styleable#Toolbar_logoDescription
@@ -159,6 +162,8 @@
     private int mTitleMarginBottom;
 
     private final RtlSpacingHelper mContentInsets = new RtlSpacingHelper();
+    private int mContentInsetStartWithNavigation;
+    private int mContentInsetEndWithActions;
 
     private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;
 
@@ -272,6 +277,11 @@
             mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
         }
 
+        mContentInsetStartWithNavigation = a.getDimensionPixelOffset(
+                R.styleable.Toolbar_contentInsetStartWithNavigation, RtlSpacingHelper.UNDEFINED);
+        mContentInsetEndWithActions = a.getDimensionPixelOffset(
+                R.styleable.Toolbar_contentInsetEndWithActions, RtlSpacingHelper.UNDEFINED);
+
         mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
         mCollapseDescription = a.getText(R.styleable.Toolbar_collapseContentDescription);
 
@@ -967,6 +977,15 @@
     }
 
     /**
+     * @hide
+     */
+    @Nullable
+    @TestApi
+    public View getNavigationView() {
+        return mNavButtonView;
+    }
+
+    /**
      * Return the Menu shown in the toolbar.
      *
      * <p>Applications that wish to populate the toolbar's menu can do so from here. To use
@@ -1055,7 +1074,7 @@
     }
 
     /**
-     * Set the content insets for this toolbar relative to layout direction.
+     * Sets the content insets for this toolbar relative to layout direction.
      *
      * <p>The content inset affects the valid area for Toolbar content other than
      * the navigation button and menu. Insets define the minimum margin for these components
@@ -1069,13 +1088,15 @@
      * @see #getContentInsetEnd()
      * @see #getContentInsetLeft()
      * @see #getContentInsetRight()
+     * @attr ref android.R.styleable#Toolbar_contentInsetEnd
+     * @attr ref android.R.styleable#Toolbar_contentInsetStart
      */
     public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
         mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
     }
 
     /**
-     * Get the starting content inset for this toolbar.
+     * Gets the starting content inset for this toolbar.
      *
      * <p>The content inset affects the valid area for Toolbar content other than
      * the navigation button and menu. Insets define the minimum margin for these components
@@ -1088,13 +1109,14 @@
      * @see #getContentInsetEnd()
      * @see #getContentInsetLeft()
      * @see #getContentInsetRight()
+     * @attr ref android.R.styleable#Toolbar_contentInsetStart
      */
     public int getContentInsetStart() {
         return mContentInsets.getStart();
     }
 
     /**
-     * Get the ending content inset for this toolbar.
+     * Gets the ending content inset for this toolbar.
      *
      * <p>The content inset affects the valid area for Toolbar content other than
      * the navigation button and menu. Insets define the minimum margin for these components
@@ -1107,13 +1129,14 @@
      * @see #getContentInsetStart()
      * @see #getContentInsetLeft()
      * @see #getContentInsetRight()
+     * @attr ref android.R.styleable#Toolbar_contentInsetEnd
      */
     public int getContentInsetEnd() {
         return mContentInsets.getEnd();
     }
 
     /**
-     * Set the content insets for this toolbar.
+     * Sets the content insets for this toolbar.
      *
      * <p>The content inset affects the valid area for Toolbar content other than
      * the navigation button and menu. Insets define the minimum margin for these components
@@ -1127,13 +1150,15 @@
      * @see #getContentInsetEnd()
      * @see #getContentInsetLeft()
      * @see #getContentInsetRight()
+     * @attr ref android.R.styleable#Toolbar_contentInsetLeft
+     * @attr ref android.R.styleable#Toolbar_contentInsetRight
      */
     public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
         mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
     }
 
     /**
-     * Get the left content inset for this toolbar.
+     * Gets the left content inset for this toolbar.
      *
      * <p>The content inset affects the valid area for Toolbar content other than
      * the navigation button and menu. Insets define the minimum margin for these components
@@ -1146,13 +1171,14 @@
      * @see #getContentInsetStart()
      * @see #getContentInsetEnd()
      * @see #getContentInsetRight()
+     * @attr ref android.R.styleable#Toolbar_contentInsetLeft
      */
     public int getContentInsetLeft() {
         return mContentInsets.getLeft();
     }
 
     /**
-     * Get the right content inset for this toolbar.
+     * Gets the right content inset for this toolbar.
      *
      * <p>The content inset affects the valid area for Toolbar content other than
      * the navigation button and menu. Insets define the minimum margin for these components
@@ -1165,11 +1191,160 @@
      * @see #getContentInsetStart()
      * @see #getContentInsetEnd()
      * @see #getContentInsetLeft()
+     * @attr ref android.R.styleable#Toolbar_contentInsetRight
      */
     public int getContentInsetRight() {
         return mContentInsets.getRight();
     }
 
+    /**
+     * Gets the start content inset to use when a navigation button is present.
+     *
+     * <p>Different content insets are often called for when additional buttons are present
+     * in the toolbar, as well as at different toolbar sizes. The larger value of
+     * {@link #getContentInsetStart()} and this value will be used during layout.</p>
+     *
+     * @return the start content inset used when a navigation icon has been set in pixels
+     *
+     * @see #setContentInsetStartWithNavigation(int)
+     * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
+     */
+    public int getContentInsetStartWithNavigation() {
+        return mContentInsetStartWithNavigation != RtlSpacingHelper.UNDEFINED
+                ? mContentInsetStartWithNavigation
+                : getContentInsetStart();
+    }
+
+    /**
+     * Sets the start content inset to use when a navigation button is present.
+     *
+     * <p>Different content insets are often called for when additional buttons are present
+     * in the toolbar, as well as at different toolbar sizes. The larger value of
+     * {@link #getContentInsetStart()} and this value will be used during layout.</p>
+     *
+     * @param insetStartWithNavigation the inset to use when a navigation icon has been set
+     *                                 in pixels
+     *
+     * @see #getContentInsetStartWithNavigation()
+     * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
+     */
+    public void setContentInsetStartWithNavigation(int insetStartWithNavigation) {
+        if (insetStartWithNavigation < 0) {
+            insetStartWithNavigation = RtlSpacingHelper.UNDEFINED;
+        }
+        if (insetStartWithNavigation != mContentInsetStartWithNavigation) {
+            mContentInsetStartWithNavigation = insetStartWithNavigation;
+            if (getNavigationIcon() != null) {
+                requestLayout();
+            }
+        }
+    }
+
+    /**
+     * Gets the end content inset to use when action buttons are present.
+     *
+     * <p>Different content insets are often called for when additional buttons are present
+     * in the toolbar, as well as at different toolbar sizes. The larger value of
+     * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
+     *
+     * @return the end content inset used when a menu has been set in pixels
+     *
+     * @see #setContentInsetEndWithActions(int)
+     * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
+     */
+    public int getContentInsetEndWithActions() {
+        return mContentInsetEndWithActions != RtlSpacingHelper.UNDEFINED
+                ? mContentInsetEndWithActions
+                : getContentInsetEnd();
+    }
+
+    /**
+     * Sets the start content inset to use when action buttons are present.
+     *
+     * <p>Different content insets are often called for when additional buttons are present
+     * in the toolbar, as well as at different toolbar sizes. The larger value of
+     * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
+     *
+     * @param insetEndWithActions the inset to use when a menu has been set in pixels
+     *
+     * @see #setContentInsetEndWithActions(int)
+     * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
+     */
+    public void setContentInsetEndWithActions(int insetEndWithActions) {
+        if (insetEndWithActions < 0) {
+            insetEndWithActions = RtlSpacingHelper.UNDEFINED;
+        }
+        if (insetEndWithActions != mContentInsetEndWithActions) {
+            mContentInsetEndWithActions = insetEndWithActions;
+            if (getNavigationIcon() != null) {
+                requestLayout();
+            }
+        }
+    }
+
+    /**
+     * Gets the content inset that will be used on the starting side of the bar in the current
+     * toolbar configuration.
+     *
+     * @return the current content inset start in pixels
+     *
+     * @see #getContentInsetStartWithNavigation()
+     */
+    public int getCurrentContentInsetStart() {
+        return getNavigationIcon() != null
+                ? Math.max(getContentInsetStart(), Math.max(mContentInsetStartWithNavigation, 0))
+                : getContentInsetStart();
+    }
+
+    /**
+     * Gets the content inset that will be used on the ending side of the bar in the current
+     * toolbar configuration.
+     *
+     * @return the current content inset end in pixels
+     *
+     * @see #getContentInsetEndWithActions()
+     */
+    public int getCurrentContentInsetEnd() {
+        boolean hasActions = false;
+        if (mMenuView != null) {
+            final MenuBuilder mb = mMenuView.peekMenu();
+            hasActions = mb != null && mb.hasVisibleItems();
+        }
+        return hasActions
+                ? Math.max(getContentInsetEnd(), Math.max(mContentInsetEndWithActions, 0))
+                : getContentInsetEnd();
+    }
+
+    /**
+     * Gets the content inset that will be used on the left side of the bar in the current
+     * toolbar configuration.
+     *
+     * @return the current content inset left in pixels
+     *
+     * @see #getContentInsetStartWithNavigation()
+     * @see #getContentInsetEndWithActions()
+     */
+    public int getCurrentContentInsetLeft() {
+        return isLayoutRtl()
+                ? getCurrentContentInsetEnd()
+                : getCurrentContentInsetStart();
+    }
+
+    /**
+     * Gets the content inset that will be used on the right side of the bar in the current
+     * toolbar configuration.
+     *
+     * @return the current content inset right in pixels
+     *
+     * @see #getContentInsetStartWithNavigation()
+     * @see #getContentInsetEndWithActions()
+     */
+    public int getCurrentContentInsetRight() {
+        return isLayoutRtl()
+                ? getCurrentContentInsetStart()
+                : getCurrentContentInsetEnd();
+    }
+
     private void ensureNavButtonView() {
         if (mNavButtonView == null) {
             mNavButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
@@ -1406,7 +1581,7 @@
             childState = combineMeasuredStates(childState, mCollapseButtonView.getMeasuredState());
         }
 
-        final int contentInsetStart = getContentInsetStart();
+        final int contentInsetStart = getCurrentContentInsetStart();
         width += Math.max(contentInsetStart, navWidth);
         collapsingMargins[marginStartIndex] = Math.max(0, contentInsetStart - navWidth);
 
@@ -1420,7 +1595,7 @@
             childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
         }
 
-        final int contentInsetEnd = getContentInsetEnd();
+        final int contentInsetEnd = getCurrentContentInsetEnd();
         width += Math.max(contentInsetEnd, menuWidth);
         collapsingMargins[marginEndIndex] = Math.max(0, contentInsetEnd - menuWidth);
 
@@ -1543,10 +1718,12 @@
             }
         }
 
-        collapsingMargins[0] = Math.max(0, getContentInsetLeft() - left);
-        collapsingMargins[1] = Math.max(0, getContentInsetRight() - (width - paddingRight - right));
-        left = Math.max(left, getContentInsetLeft());
-        right = Math.min(right, width - paddingRight - getContentInsetRight());
+        final int contentInsetLeft = getCurrentContentInsetLeft();
+        final int contentInsetRight = getCurrentContentInsetRight();
+        collapsingMargins[0] = Math.max(0, contentInsetLeft - left);
+        collapsingMargins[1] = Math.max(0, contentInsetRight - (width - paddingRight - right));
+        left = Math.max(left, contentInsetLeft);
+        right = Math.min(right, width - paddingRight - contentInsetRight);
 
         if (shouldLayout(mExpandedActionView)) {
             if (isRtl) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index aac7bc3..b7ac600 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -204,6 +204,9 @@
         mShowTitle = a.getBoolean(R.styleable.AlertDialog_showTitle, true);
 
         a.recycle();
+
+        /* We use a custom title so never request a window title */
+        window.requestFeature(Window.FEATURE_NO_TITLE);
     }
 
     static boolean canTextInput(View v) {
@@ -229,8 +232,6 @@
     }
 
     public void installContent() {
-        /* We use a custom title so never request a window title */
-        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         int contentView = selectContentView();
         mWindow.setContentView(contentView);
         setupView();
@@ -515,9 +516,15 @@
             }
 
             // Only show the divider if we have a title.
-            final View divider;
+            View divider = null;
             if (mMessage != null || mListView != null || hasCustomPanel) {
-                divider = topPanel.findViewById(R.id.titleDivider);
+                if (!hasCustomPanel) {
+                    divider = topPanel.findViewById(R.id.titleDividerNoCustom);
+                }
+                if (divider == null) {
+                    divider = topPanel.findViewById(R.id.titleDivider);
+                }
+
             } else {
                 divider = topPanel.findViewById(R.id.titleDividerTop);
             }
@@ -525,6 +532,17 @@
             if (divider != null) {
                 divider.setVisibility(View.VISIBLE);
             }
+        } else {
+            if (contentPanel != null) {
+                final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
+                if (spacer != null) {
+                    spacer.setVisibility(View.VISIBLE);
+                }
+            }
+        }
+
+        if (mListView instanceof RecycleListView) {
+            ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
         }
 
         // Update scroll indicators as needed.
@@ -860,23 +878,34 @@
     }
 
     public static class RecycleListView extends ListView {
+        private final int mPaddingTopNoTitle;
+        private final int mPaddingBottomNoButtons;
+
         boolean mRecycleOnMeasure = true;
 
         public RecycleListView(Context context) {
-            super(context);
+            this(context, null);
         }
 
         public RecycleListView(Context context, AttributeSet attrs) {
             super(context, attrs);
+
+            final TypedArray ta = context.obtainStyledAttributes(
+                    attrs, R.styleable.RecycleListView);
+            mPaddingBottomNoButtons = ta.getDimensionPixelOffset(
+                    R.styleable.RecycleListView_paddingBottomNoButtons, -1);
+            mPaddingTopNoTitle = ta.getDimensionPixelOffset(
+                    R.styleable.RecycleListView_paddingTopNoTitle, -1);
         }
 
-        public RecycleListView(Context context, AttributeSet attrs, int defStyleAttr) {
-            super(context, attrs, defStyleAttr);
-        }
-
-        public RecycleListView(
-                Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-            super(context, attrs, defStyleAttr, defStyleRes);
+        public void setHasDecor(boolean hasTitle, boolean hasButtons) {
+            if (!hasButtons || !hasTitle) {
+                final int paddingLeft = getPaddingLeft();
+                final int paddingTop = hasTitle ? getPaddingTop() : mPaddingTopNoTitle;
+                final int paddingRight = getPaddingRight();
+                final int paddingBottom = hasButtons ? getPaddingBottom() : mPaddingBottomNoButtons;
+                setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+            }
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 6085164..a4e489c 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -433,8 +433,7 @@
 
                 final ChooserTargetServiceConnection conn =
                         new ChooserTargetServiceConnection(this, dri);
-                if (bindServiceAsUser(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND,
-                        UserHandle.CURRENT)) {
+                if (bindService(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND)) {
                     if (DEBUG) {
                         Log.d(TAG, "Binding service connection for target " + dri
                                 + " intent " + serviceIntent);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index b13be97..3a31b37 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -45,6 +45,6 @@
     void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
 
     void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
-    void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle);
+    void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages);
     void removeUser(int userHandle);
 }
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 74fe94f..8e38c5a 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -20,6 +20,7 @@
 
 import android.os.ParcelFileDescriptor;
 import android.os.WorkSource;
+import android.os.health.HealthStatsParceler;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.SignalStrength;
 
@@ -125,4 +126,7 @@
     void noteBleScanStarted(in WorkSource ws);
     void noteBleScanStopped(in WorkSource ws);
     void noteResetBleScan();
+
+    HealthStatsParceler takeUidSnapshot(int uid);
+    HealthStatsParceler[] takeUidSnapshots(in int[] uid);
 }
diff --git a/core/java/com/android/internal/app/IProcessStats.aidl b/core/java/com/android/internal/app/IProcessStats.aidl
deleted file mode 100644
index 6fadf2f..0000000
--- a/core/java/com/android/internal/app/IProcessStats.aidl
+++ /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.app;
-
-import android.content.ComponentName;
-import android.os.ParcelFileDescriptor;
-import com.android.internal.app.ProcessStats;
-
-interface IProcessStats {
-    byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
-    ParcelFileDescriptor getStatsOverTime(long minTime);
-    int getCurrentMemoryState();
-}
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index c7459d7..a9d5113 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -16,8 +16,8 @@
 
 package com.android.internal.app;
 
-import android.icu.util.ULocale;
 import android.icu.text.ListFormatter;
+import android.icu.util.ULocale;
 import android.util.LocaleList;
 
 import java.text.Collator;
@@ -99,7 +99,7 @@
      * @return the localized name of the locale.
      */
     public static String getDisplayName(Locale locale, Locale displayLocale, boolean sentenceCase) {
-        String result = ULocale.getDisplayName(locale.toLanguageTag(),
+        String result = ULocale.getDisplayNameWithDialect(locale.toLanguageTag(),
                 ULocale.forLocale(displayLocale));
         return sentenceCase ? toSentenceCase(result, displayLocale) : result;
     }
@@ -112,7 +112,8 @@
      * @return the localized name of the locale.
      */
     public static String getDisplayName(Locale locale, boolean sentenceCase) {
-        String result = ULocale.getDisplayName(locale.toLanguageTag(), ULocale.getDefault());
+        String result = ULocale.getDisplayNameWithDialect(locale.toLanguageTag(),
+                ULocale.getDefault());
         return sentenceCase ? toSentenceCase(result, Locale.getDefault()) : result;
     }
 
@@ -155,7 +156,7 @@
         }
 
         ListFormatter lfn = ListFormatter.getInstance(dispLocale);
-        return lfn.format(localeNames);
+        return lfn.format((Object[]) localeNames);
     }
 
     /**
@@ -179,14 +180,31 @@
      */
     public static final class LocaleInfoComparator implements Comparator<LocaleStore.LocaleInfo> {
         private final Collator mCollator;
+        private final boolean mCountryMode;
+        private static final String PREFIX_ARABIC = "\u0627\u0644"; // ALEF-LAM, ال
 
         /**
          * Constructor.
          *
          * @param sortLocale the locale to be used for sorting.
          */
-        public LocaleInfoComparator(Locale sortLocale) {
+        public LocaleInfoComparator(Locale sortLocale, boolean countryMode) {
             mCollator = Collator.getInstance(sortLocale);
+            mCountryMode = countryMode;
+        }
+
+        /*
+         * The Arabic collation should ignore Alef-Lam at the beginning (b/26277596)
+         *
+         * We look at the label's locale, not the current system locale.
+         * This is because the name of the Arabic language itself is in Arabic,
+         * and starts with Alef-Lam, no matter what the system locale is.
+         */
+        private String removePrefixForCompare(Locale locale, String str) {
+            if ("ar".equals(locale.getLanguage()) && str.startsWith(PREFIX_ARABIC)) {
+                return str.substring(PREFIX_ARABIC.length());
+            }
+            return str;
         }
 
         /**
@@ -203,7 +221,9 @@
             // and "all others" (== 0)
             if (lhs.isSuggested() == rhs.isSuggested()) {
                 // They are in the same "bucket" (suggested / others), so we compare the text
-                return mCollator.compare(lhs.getLabel(), rhs.getLabel());
+                return mCollator.compare(
+                        removePrefixForCompare(lhs.getLocale(), lhs.getLabel(mCountryMode)),
+                        removePrefixForCompare(rhs.getLocale(), rhs.getLabel(mCountryMode)));
             } else {
                 // One locale is suggested and one is not, so we put them in different "buckets"
                 return lhs.isSuggested() ? -1 : 1;
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 6a365e0..b1b019c 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -275,7 +275,7 @@
             config.setLocales(locales);
             config.userSetLocale = true;
 
-            am.updateConfiguration(config);
+            am.updatePersistentConfiguration(config);
             // Trigger the dirty bit for the Settings Provider.
             BackupManager.dataChanged("com.android.providers.settings");
         } catch (RemoteException e) {
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index 956ee8c..ea62899 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -21,6 +21,7 @@
 import android.app.ListFragment;
 import android.content.Context;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.LocaleList;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -50,7 +51,11 @@
     private Set<LocaleStore.LocaleInfo> mLocaleList;
     private LocaleStore.LocaleInfo mParentLocale;
     private boolean mTranslatedOnly = false;
-    private boolean mCountryMode = false;
+    private SearchView mSearchView = null;
+    private CharSequence mPreviousSearch = null;
+    private boolean mPreviousSearchHadFocus = false;
+    private int mFirstVisiblePosition = 0;
+    private int mTopDistance = 0;
 
     /**
      * Other classes can register to be notified when a locale was selected.
@@ -70,15 +75,14 @@
             boolean translatedOnly) {
         LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
         boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
-                true /* country mode */, translatedOnly);
+                translatedOnly);
         return shouldShowTheList ? localePicker : null;
     }
 
     public static LocalePickerWithRegion createLanguagePicker(Context context,
             LocaleSelectedListener listener, boolean translatedOnly) {
         LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
-        localePicker.setListener(context, listener, null,
-                false /* language mode */, translatedOnly);
+        localePicker.setListener(context, listener, /* parent */ null, translatedOnly);
         return localePicker;
     }
 
@@ -96,14 +100,7 @@
      * "pretending" it was selected, and return false.</p>
      */
     private boolean setListener(Context context, LocaleSelectedListener listener,
-            LocaleStore.LocaleInfo parent, boolean countryMode, boolean translatedOnly) {
-        if (countryMode && (parent == null || parent.getLocale() == null)) {
-            // The list of countries is determined as all the countries where the parent language
-            // is used.
-            throw new IllegalArgumentException("The country selection list needs a parent.");
-        }
-
-        this.mCountryMode = countryMode;
+            LocaleStore.LocaleInfo parent, boolean translatedOnly) {
         this.mParentLocale = parent;
         this.mListener = listener;
         this.mTranslatedOnly = translatedOnly;
@@ -116,7 +113,7 @@
             Collections.addAll(langTagsToIgnore, langTags);
         }
 
-        if (countryMode) {
+        if (parent != null) {
             mLocaleList = LocaleStore.getLevelLocales(context,
                     langTagsToIgnore, parent, translatedOnly);
             if (mLocaleList.size() <= 1) {
@@ -138,13 +135,11 @@
         super.onCreate(savedInstanceState);
         setHasOptionsMenu(true);
 
-        final Locale sortingLocale = (mCountryMode && mParentLocale != null)
-                ? mParentLocale.getLocale()
-                : Locale.getDefault();
-
-        mAdapter = new SuggestedLocaleAdapter(mLocaleList, mCountryMode);
+        final boolean countryMode = mParentLocale != null;
+        final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
+        mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
         final LocaleHelper.LocaleInfoComparator comp =
-                new LocaleHelper.LocaleInfoComparator(sortingLocale);
+                new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
         mAdapter.sort(comp);
         setListAdapter(mAdapter);
     }
@@ -164,25 +159,41 @@
     public void onResume() {
         super.onResume();
 
-        if (mCountryMode) {
-            if (mParentLocale == null) {
-                this.getActivity().setTitle(R.string.country_selection_title);
-            } else {
-                this.getActivity().setTitle(mParentLocale.getFullNameNative());
-            }
+        if (mParentLocale != null) {
+            getActivity().setTitle(mParentLocale.getFullNameNative());
         } else {
-            this.getActivity().setTitle(R.string.language_selection_title);
+            getActivity().setTitle(R.string.language_selection_title);
         }
 
         getListView().requestFocus();
     }
 
     @Override
+    public void onPause() {
+        super.onPause();
+
+        // Save search status
+        if (mSearchView != null) {
+            mPreviousSearchHadFocus = mSearchView.hasFocus();
+            mPreviousSearch = mSearchView.getQuery();
+        } else {
+            mPreviousSearchHadFocus = false;
+            mPreviousSearch = null;
+        }
+
+        // Save scroll position
+        final ListView list = getListView();
+        final View firstChild = list.getChildAt(0);
+        mFirstVisiblePosition = list.getFirstVisiblePosition();
+        mTopDistance = (firstChild == null) ? 0 : (firstChild.getTop() - list.getPaddingTop());
+    }
+
+    @Override
     public void onListItemClick(ListView l, View v, int position, long id) {
         final LocaleStore.LocaleInfo locale =
                 (LocaleStore.LocaleInfo) getListAdapter().getItem(position);
 
-        if (mCountryMode || locale.getParent() != null) {
+        if (locale.getParent() != null) {
             if (mListener != null) {
                 mListener.onLocaleSelected(locale);
             }
@@ -205,15 +216,30 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        if (!mCountryMode) {
+        if (mParentLocale == null) {
             inflater.inflate(R.menu.language_selection_list, menu);
 
-            MenuItem mSearchMenuItem = menu.findItem(R.id.locale_search_menu);
-            SearchView mSearchView = (SearchView) mSearchMenuItem.getActionView();
+            final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_menu);
+            mSearchView = (SearchView) searchMenuItem.getActionView();
 
             mSearchView.setQueryHint(getText(R.string.search_language_hint));
             mSearchView.setOnQueryTextListener(this);
-            mSearchView.setQuery("", false /* submit */);
+
+            // Restore previous search status
+            if (!TextUtils.isEmpty(mPreviousSearch)) {
+                searchMenuItem.expandActionView();
+                mSearchView.setIconified(false);
+                mSearchView.setActivated(true);
+                if (mPreviousSearchHadFocus) {
+                    mSearchView.requestFocus();
+                }
+                mSearchView.setQuery(mPreviousSearch, true /* submit */);
+            } else {
+                mSearchView.setQuery(null, false /* submit */);
+            }
+
+            // Restore previous scroll position
+            getListView().setSelectionFromTop(mFirstVisiblePosition, mTopDistance);
         }
     }
 
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 465c4d8..7803e52 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -31,8 +31,9 @@
     private static boolean sFullyInitialized = false;
 
     public static class LocaleInfo {
-        private static final int SUGGESTION_TYPE_NONE = 0x00;
-        private static final int SUGGESTION_TYPE_SIM = 0x01;
+        private static final int SUGGESTION_TYPE_NONE = 0;
+        private static final int SUGGESTION_TYPE_SIM = 1 << 0;
+        private static final int SUGGESTION_TYPE_CFG = 1 << 1;
 
         private final Locale mLocale;
         private final Locale mParent;
@@ -145,11 +146,11 @@
             return mLangScriptKey;
         }
 
-        String getLabel() {
-            if (getParent() == null || this.isSuggestionOfType(SUGGESTION_TYPE_SIM)) {
-                return getFullNameNative();
-            } else {
+        String getLabel(boolean countryMode) {
+            if (countryMode) {
                 return getFullCountryNameNative();
+            } else {
+                return getFullNameNative();
             }
         }
 
@@ -273,6 +274,22 @@
         final HashSet<String> localizedLocales = new HashSet<>();
         for (String localeId : LocalePicker.getSystemAssetLocales()) {
             LocaleInfo li = new LocaleInfo(localeId);
+            final String country = li.getLocale().getCountry();
+            // All this is to figure out if we should suggest a country
+            if (!country.isEmpty()) {
+                LocaleInfo cachedLocale = null;
+                if (sLocaleCache.containsKey(li.getId())) { // the simple case, e.g. fr-CH
+                    cachedLocale = sLocaleCache.get(li.getId());
+                } else { // e.g. zh-TW localized, zh-Hant-TW in cache
+                    final String langScriptCtry = li.getLangScriptKey() + "-" + country;
+                    if (sLocaleCache.containsKey(langScriptCtry)) {
+                        cachedLocale = sLocaleCache.get(langScriptCtry);
+                    }
+                }
+                if (cachedLocale != null) {
+                    cachedLocale.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_CFG;
+                }
+            }
             localizedLocales.add(li.getLangScriptKey());
         }
 
@@ -311,9 +328,7 @@
             if (level == 2) {
                 if (parent != null) { // region selection
                     if (parentId.equals(li.getParent().toLanguageTag())) {
-                        if (!li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
-                            result.add(li);
-                        }
+                        result.add(li);
                     }
                 } else { // language selection
                     if (li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 0964dcf..5944568 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -73,62 +73,28 @@
         final int size = (int)
                 (Math.min(Math.min(dm.widthPixels, dm.heightPixels), 600*dp) - 100*dp);
 
-        final View im = new View(this);
+        final ImageView im = new ImageView(this);
+        final int pad = (int)(40*dp);
+        im.setPadding(pad, pad, pad, pad);
         im.setTranslationZ(20);
         im.setScaleX(0.5f);
         im.setScaleY(0.5f);
         im.setAlpha(0f);
-        im.setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                final int pad = (int) (8 * dp);
-                outline.setOval(pad, pad, view.getWidth() - pad, view.getHeight() - pad);
-            }
-        });
-        final float hue = (float) Math.random();
-        final Paint bgPaint = new Paint();
-        bgPaint.setColor(HSBtoColor(hue, 0.4f, 1f));
-        final Paint fgPaint = new Paint();
-        fgPaint.setColor(HSBtoColor(hue, 0.5f, 1f));
-        final Drawable M = getDrawable(com.android.internal.R.drawable.platlogo_m);
-        final Drawable platlogo = new Drawable() {
-            @Override
-            public void setAlpha(int alpha) { }
 
-            @Override
-            public void setColorFilter(@Nullable ColorFilter colorFilter) { }
-
-            @Override
-            public int getOpacity() {
-                return PixelFormat.TRANSLUCENT;
-            }
-
-            @Override
-            public void draw(Canvas c) {
-                final float r = c.getWidth() / 2f;
-                c.drawCircle(r, r, r, bgPaint);
-                c.drawArc(0, 0, 2 * r, 2 * r, 135, 180, false, fgPaint);
-                M.setBounds(0, 0, c.getWidth(), c.getHeight());
-                M.draw(c);
-            }
-        };
         im.setBackground(new RippleDrawable(
                 ColorStateList.valueOf(0xFFFFFFFF),
-                platlogo,
+                getDrawable(com.android.internal.R.drawable.platlogo),
                 null));
-        im.setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setOval(0, 0, view.getWidth(), view.getHeight());
-            }
-        });
+//        im.setOutlineProvider(new ViewOutlineProvider() {
+//            @Override
+//            public void getOutline(View view, Outline outline) {
+//                outline.setOval(0, 0, view.getWidth(), view.getHeight());
+//            }
+//        });
         im.setClickable(true);
         im.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                if (mTapCount == 0) {
-                    showMarshmallow(im);
-                }
                 im.setOnLongClickListener(new View.OnLongClickListener() {
                     @Override
                     public boolean onLongClick(View v) {
@@ -175,9 +141,6 @@
             @Override
             public boolean onKey(View v, int keyCode, KeyEvent event) {
                 if (keyCode != KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
-                    if (mKeyCount == 0) {
-                        showMarshmallow(im);
-                    }
                     ++mKeyCount;
                     if (mKeyCount > 2) {
                         if (mTapCount > 5) {
@@ -201,81 +164,4 @@
                 .setStartDelay(800)
                 .start();
     }
-
-    public void showMarshmallow(View im) {
-        final Drawable fg = getDrawable(com.android.internal.R.drawable.platlogo);
-        fg.setBounds(0, 0, im.getWidth(), im.getHeight());
-        fg.setAlpha(0);
-        im.getOverlay().add(fg);
-
-        final Animator fadeIn = ObjectAnimator.ofInt(fg, "alpha", 255);
-        fadeIn.setInterpolator(mInterpolator);
-        fadeIn.setDuration(300);
-        fadeIn.start();
-    }
-
-    /**
-     * Convert HSB components to an ARGB color. Alpha set to 0xFF.
-     *     hsv[0] is Hue [0 .. 1)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
-     * If hsv values are out of range, they are pinned.
-     * @param h Hue component
-     * @param s Saturation component
-     * @param b Brightness component
-     * @return the resulting argb color
-     */
-    private static int HSBtoColor(float h, float s, float b) {
-        h = MathUtils.constrain(h, 0.0f, 1.0f);
-        s = MathUtils.constrain(s, 0.0f, 1.0f);
-        b = MathUtils.constrain(b, 0.0f, 1.0f);
-
-        float red = 0.0f;
-        float green = 0.0f;
-        float blue = 0.0f;
-
-        final float hf = (h - (int) h) * 6.0f;
-        final int ihf = (int) hf;
-        final float f = hf - ihf;
-        final float pv = b * (1.0f - s);
-        final float qv = b * (1.0f - s * f);
-        final float tv = b * (1.0f - s * (1.0f - f));
-
-        switch (ihf) {
-            case 0:         // Red is the dominant color
-                red = b;
-                green = tv;
-                blue = pv;
-                break;
-            case 1:         // Green is the dominant color
-                red = qv;
-                green = b;
-                blue = pv;
-                break;
-            case 2:
-                red = pv;
-                green = b;
-                blue = tv;
-                break;
-            case 3:         // Blue is the dominant color
-                red = pv;
-                green = qv;
-                blue = b;
-                break;
-            case 4:
-                red = tv;
-                green = pv;
-                blue = b;
-                break;
-            case 5:         // Red is the dominant color
-                red = b;
-                green = pv;
-                blue = qv;
-                break;
-        }
-
-        return 0xFF000000 | (((int) (red * 255.0f)) << 16) |
-                (((int) (green * 255.0f)) << 8) | ((int) (blue * 255.0f));
-    }
-
 }
diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java
index 23a8bd7..81036f7 100644
--- a/core/java/com/android/internal/app/ProcessMap.java
+++ b/core/java/com/android/internal/app/ProcessMap.java
@@ -54,4 +54,8 @@
     public ArrayMap<String, SparseArray<E>> getMap() {
         return mMap;
     }
+
+    public int size() {
+        return mMap.size();
+    }
 }
diff --git a/core/java/com/android/internal/app/ProcessStats.aidl b/core/java/com/android/internal/app/ProcessStats.aidl
deleted file mode 100644
index 48b1f85..0000000
--- a/core/java/com/android/internal/app/ProcessStats.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-** 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.app;
-
-parcelable ProcessStats;
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
deleted file mode 100644
index 17ca904d..0000000
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ /dev/null
@@ -1,3794 +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.app;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.text.format.DateFormat;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.DebugUtils;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.TimeUtils;
-
-import com.android.internal.util.GrowingArrayUtils;
-
-import dalvik.system.VMRuntime;
-import libcore.util.EmptyArray;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Objects;
-
-public final class ProcessStats implements Parcelable {
-    static final String TAG = "ProcessStats";
-    static final boolean DEBUG = false;
-    static final boolean DEBUG_PARCEL = false;
-
-    public static final String SERVICE_NAME = "procstats";
-
-    // How often the service commits its data, giving the minimum batching
-    // that is done.
-    public static long COMMIT_PERIOD = 3*60*60*1000;  // Commit current stats every 3 hours
-
-    // Minimum uptime period before committing.  If the COMMIT_PERIOD has elapsed but
-    // the total uptime has not exceeded this amount, then the commit will be held until
-    // it is reached.
-    public static long COMMIT_UPTIME_PERIOD = 60*60*1000;  // Must have at least 1 hour elapsed
-
-    public static final int STATE_NOTHING = -1;
-    public static final int STATE_PERSISTENT = 0;
-    public static final int STATE_TOP = 1;
-    public static final int STATE_IMPORTANT_FOREGROUND = 2;
-    public static final int STATE_IMPORTANT_BACKGROUND = 3;
-    public static final int STATE_BACKUP = 4;
-    public static final int STATE_HEAVY_WEIGHT = 5;
-    public static final int STATE_SERVICE = 6;
-    public static final int STATE_SERVICE_RESTARTING = 7;
-    public static final int STATE_RECEIVER = 8;
-    public static final int STATE_HOME = 9;
-    public static final int STATE_LAST_ACTIVITY = 10;
-    public static final int STATE_CACHED_ACTIVITY = 11;
-    public static final int STATE_CACHED_ACTIVITY_CLIENT = 12;
-    public static final int STATE_CACHED_EMPTY = 13;
-    public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
-
-    public static final int PSS_SAMPLE_COUNT = 0;
-    public static final int PSS_MINIMUM = 1;
-    public static final int PSS_AVERAGE = 2;
-    public static final int PSS_MAXIMUM = 3;
-    public static final int PSS_USS_MINIMUM = 4;
-    public static final int PSS_USS_AVERAGE = 5;
-    public static final int PSS_USS_MAXIMUM = 6;
-    public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
-
-    public static final int SYS_MEM_USAGE_SAMPLE_COUNT = 0;
-    public static final int SYS_MEM_USAGE_CACHED_MINIMUM = 1;
-    public static final int SYS_MEM_USAGE_CACHED_AVERAGE = 2;
-    public static final int SYS_MEM_USAGE_CACHED_MAXIMUM = 3;
-    public static final int SYS_MEM_USAGE_FREE_MINIMUM = 4;
-    public static final int SYS_MEM_USAGE_FREE_AVERAGE = 5;
-    public static final int SYS_MEM_USAGE_FREE_MAXIMUM = 6;
-    public static final int SYS_MEM_USAGE_ZRAM_MINIMUM = 7;
-    public static final int SYS_MEM_USAGE_ZRAM_AVERAGE = 8;
-    public static final int SYS_MEM_USAGE_ZRAM_MAXIMUM = 9;
-    public static final int SYS_MEM_USAGE_KERNEL_MINIMUM = 10;
-    public static final int SYS_MEM_USAGE_KERNEL_AVERAGE = 11;
-    public static final int SYS_MEM_USAGE_KERNEL_MAXIMUM = 12;
-    public static final int SYS_MEM_USAGE_NATIVE_MINIMUM = 13;
-    public static final int SYS_MEM_USAGE_NATIVE_AVERAGE = 14;
-    public static final int SYS_MEM_USAGE_NATIVE_MAXIMUM = 15;
-    public static final int SYS_MEM_USAGE_COUNT = SYS_MEM_USAGE_NATIVE_MAXIMUM+1;
-
-    public static final int ADJ_NOTHING = -1;
-    public static final int ADJ_MEM_FACTOR_NORMAL = 0;
-    public static final int ADJ_MEM_FACTOR_MODERATE = 1;
-    public static final int ADJ_MEM_FACTOR_LOW = 2;
-    public static final int ADJ_MEM_FACTOR_CRITICAL = 3;
-    public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1;
-    public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT;
-    public static final int ADJ_SCREEN_OFF = 0;
-    public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD;
-    public static final int ADJ_COUNT = ADJ_SCREEN_ON*2;
-
-    public static final int FLAG_COMPLETE = 1<<0;
-    public static final int FLAG_SHUTDOWN = 1<<1;
-    public static final int FLAG_SYSPROPS = 1<<2;
-
-    public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL,
-            ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
-
-    public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
-
-    public static final int[] NON_CACHED_PROC_STATES = new int[] {
-            STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
-            STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
-            STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
-    };
-
-    public static final int[] BACKGROUND_PROC_STATES = new int[] {
-            STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
-            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
-    };
-
-    // Map from process states to the states we track.
-    static final int[] PROCESS_STATE_TO_STATE = new int[] {
-            STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
-            STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
-            STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
-            STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
-            STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
-            STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
-            STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
-            STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
-            STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
-            STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
-            STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
-            STATE_RECEIVER,                 // ActivityManager.PROCESS_STATE_RECEIVER
-            STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
-            STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
-            STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
-            STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
-            STATE_CACHED_EMPTY,             // ActivityManager.PROCESS_STATE_CACHED_EMPTY
-    };
-
-    public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
-            STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
-            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
-            STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
-            STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
-    };
-
-    static final String[] STATE_NAMES = new String[] {
-            "Persist", "Top    ", "ImpFg  ", "ImpBg  ",
-            "Backup ", "HeavyWt", "Service", "ServRst",
-            "Receivr", "Home   ",
-            "LastAct", "CchAct ", "CchCAct", "CchEmty"
-    };
-
-    public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
-            "off", "on"
-    };
-
-    public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
-            "norm", "mod",  "low", "crit"
-    };
-
-    public static final String[] STATE_NAMES_CSV = new String[] {
-            "pers", "top", "impfg", "impbg", "backup", "heavy",
-            "service", "service-rs", "receiver", "home", "lastact",
-            "cch-activity", "cch-aclient", "cch-empty"
-    };
-
-    static final String[] ADJ_SCREEN_TAGS = new String[] {
-            "0", "1"
-    };
-
-    static final String[] ADJ_MEM_TAGS = new String[] {
-            "n", "m",  "l", "c"
-    };
-
-    static final String[] STATE_TAGS = new String[] {
-            "p", "t", "f", "b", "u", "w",
-            "s", "x", "r", "h", "l", "a", "c", "e"
-    };
-
-    static final String CSV_SEP = "\t";
-
-    // Current version of the parcel format.
-    private static final int PARCEL_VERSION = 18;
-    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
-    private static final int MAGIC = 0x50535453;
-
-    // Where the "type"/"state" part of the data appears in an offset integer.
-    static int OFFSET_TYPE_SHIFT = 0;
-    static int OFFSET_TYPE_MASK = 0xff;
-    // Where the "which array" part of the data appears in an offset integer.
-    static int OFFSET_ARRAY_SHIFT = 8;
-    static int OFFSET_ARRAY_MASK = 0xff;
-    // Where the "index into array" part of the data appears in an offset integer.
-    static int OFFSET_INDEX_SHIFT = 16;
-    static int OFFSET_INDEX_MASK = 0xffff;
-
-    public String mReadError;
-    public String mTimePeriodStartClockStr;
-    public int mFlags;
-
-    public final ProcessMap<SparseArray<PackageState>> mPackages
-            = new ProcessMap<SparseArray<PackageState>>();
-    public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
-
-    public final long[] mMemFactorDurations = new long[ADJ_COUNT];
-    public int mMemFactor = STATE_NOTHING;
-    public long mStartTime;
-
-    public int[] mSysMemUsageTable = null;
-    public int mSysMemUsageTableSize = 0;
-    public final long[] mSysMemUsageArgs = new long[SYS_MEM_USAGE_COUNT];
-
-    public long mTimePeriodStartClock;
-    public long mTimePeriodStartRealtime;
-    public long mTimePeriodEndRealtime;
-    public long mTimePeriodStartUptime;
-    public long mTimePeriodEndUptime;
-    String mRuntime;
-    boolean mRunning;
-
-    static final int LONGS_SIZE = 4096;
-    final ArrayList<long[]> mLongs = new ArrayList<long[]>();
-    int mNextLong;
-
-    int[] mAddLongTable;
-    int mAddLongTableSize;
-
-    // For writing parcels.
-    ArrayMap<String, Integer> mCommonStringToIndex;
-
-    // For reading parcels.
-    ArrayList<String> mIndexToCommonString;
-
-    public ProcessStats(boolean running) {
-        mRunning = running;
-        reset();
-    }
-
-    public ProcessStats(Parcel in) {
-        reset();
-        readFromParcel(in);
-    }
-
-    public void add(ProcessStats other) {
-        ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = other.mPackages.getMap();
-        for (int ip=0; ip<pkgMap.size(); ip++) {
-            final String pkgName = pkgMap.keyAt(ip);
-            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final int uid = uids.keyAt(iu);
-                final SparseArray<PackageState> versions = uids.valueAt(iu);
-                for (int iv=0; iv<versions.size(); iv++) {
-                    final int vers = versions.keyAt(iv);
-                    final PackageState otherState = versions.valueAt(iv);
-                    final int NPROCS = otherState.mProcesses.size();
-                    final int NSRVS = otherState.mServices.size();
-                    for (int iproc=0; iproc<NPROCS; iproc++) {
-                        ProcessState otherProc = otherState.mProcesses.valueAt(iproc);
-                        if (otherProc.mCommonProcess != otherProc) {
-                            if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
-                                    + " vers " + vers + " proc " + otherProc.mName);
-                            ProcessState thisProc = getProcessStateLocked(pkgName, uid, vers,
-                                    otherProc.mName);
-                            if (thisProc.mCommonProcess == thisProc) {
-                                if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting");
-                                thisProc.mMultiPackage = true;
-                                long now = SystemClock.uptimeMillis();
-                                final PackageState pkgState = getPackageStateLocked(pkgName, uid,
-                                        vers);
-                                thisProc = thisProc.clone(thisProc.mPackage, now);
-                                pkgState.mProcesses.put(thisProc.mName, thisProc);
-                            }
-                            thisProc.add(otherProc);
-                        }
-                    }
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        ServiceState otherSvc = otherState.mServices.valueAt(isvc);
-                        if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
-                                + " service " + otherSvc.mName);
-                        ServiceState thisSvc = getServiceStateLocked(pkgName, uid, vers,
-                                otherSvc.mProcessName, otherSvc.mName);
-                        thisSvc.add(otherSvc);
-                    }
-                }
-            }
-        }
-
-        ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap();
-        for (int ip=0; ip<procMap.size(); ip++) {
-            SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                int uid = uids.keyAt(iu);
-                ProcessState otherProc = uids.valueAt(iu);
-                ProcessState thisProc = mProcesses.get(otherProc.mName, uid);
-                if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + otherProc.mName);
-                if (thisProc == null) {
-                    if (DEBUG) Slog.d(TAG, "Creating new process!");
-                    thisProc = new ProcessState(this, otherProc.mPackage, uid, otherProc.mVersion,
-                            otherProc.mName);
-                    mProcesses.put(otherProc.mName, uid, thisProc);
-                    PackageState thisState = getPackageStateLocked(otherProc.mPackage, uid,
-                            otherProc.mVersion);
-                    if (!thisState.mProcesses.containsKey(otherProc.mName)) {
-                        thisState.mProcesses.put(otherProc.mName, thisProc);
-                    }
-                }
-                thisProc.add(otherProc);
-            }
-        }
-
-        for (int i=0; i<ADJ_COUNT; i++) {
-            if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by "
-                    + other.mMemFactorDurations[i] + " from "
-                    + mMemFactorDurations[i]);
-            mMemFactorDurations[i] += other.mMemFactorDurations[i];
-        }
-
-        for (int i=0; i<other.mSysMemUsageTableSize; i++) {
-            int ent = other.mSysMemUsageTable[i];
-            int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-            long[] longs = other.mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-            addSysMemUsage(state, longs, ((ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK));
-        }
-
-        if (other.mTimePeriodStartClock < mTimePeriodStartClock) {
-            mTimePeriodStartClock = other.mTimePeriodStartClock;
-            mTimePeriodStartClockStr = other.mTimePeriodStartClockStr;
-        }
-        mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime;
-        mTimePeriodEndUptime += other.mTimePeriodEndUptime - other.mTimePeriodStartUptime;
-    }
-
-    public void addSysMemUsage(long cachedMem, long freeMem, long zramMem, long kernelMem,
-            long nativeMem) {
-        if (mMemFactor != STATE_NOTHING) {
-            int state = mMemFactor * STATE_COUNT;
-            mSysMemUsageArgs[SYS_MEM_USAGE_SAMPLE_COUNT] = 1;
-            for (int i=0; i<3; i++) {
-                mSysMemUsageArgs[SYS_MEM_USAGE_CACHED_MINIMUM + i] = cachedMem;
-                mSysMemUsageArgs[SYS_MEM_USAGE_FREE_MINIMUM + i] = freeMem;
-                mSysMemUsageArgs[SYS_MEM_USAGE_ZRAM_MINIMUM + i] = zramMem;
-                mSysMemUsageArgs[SYS_MEM_USAGE_KERNEL_MINIMUM + i] = kernelMem;
-                mSysMemUsageArgs[SYS_MEM_USAGE_NATIVE_MINIMUM + i] = nativeMem;
-            }
-            addSysMemUsage(state, mSysMemUsageArgs, 0);
-        }
-    }
-
-    void addSysMemUsage(int state, long[] data, int dataOff) {
-        int idx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, state);
-        int off;
-        if (idx >= 0) {
-            off = mSysMemUsageTable[idx];
-        } else {
-            mAddLongTable = mSysMemUsageTable;
-            mAddLongTableSize = mSysMemUsageTableSize;
-            off = addLongData(~idx, state, SYS_MEM_USAGE_COUNT);
-            mSysMemUsageTable = mAddLongTable;
-            mSysMemUsageTableSize = mAddLongTableSize;
-        }
-        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-        idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
-        addSysMemUsage(longs, idx, data, dataOff);
-    }
-
-    static void addSysMemUsage(long[] dstData, int dstOff, long[] addData, int addOff) {
-        final long dstCount = dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT];
-        final long addCount = addData[addOff+SYS_MEM_USAGE_SAMPLE_COUNT];
-        if (dstCount == 0) {
-            dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = addCount;
-            for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i++) {
-                dstData[dstOff+i] = addData[addOff+i];
-            }
-        } else if (addCount > 0) {
-            dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = dstCount + addCount;
-            for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i+=3) {
-                if (dstData[dstOff+i] > addData[addOff+i]) {
-                    dstData[dstOff+i] = addData[addOff+i];
-                }
-                dstData[dstOff+i+1] = (long)(
-                        ((dstData[dstOff+i+1]*(double)dstCount)
-                                + (addData[addOff+i+1]*(double)addCount))
-                                / (dstCount+addCount) );
-                if (dstData[dstOff+i+2] < addData[addOff+i+2]) {
-                    dstData[dstOff+i+2] = addData[addOff+i+2];
-                }
-            }
-        }
-    }
-
-    public static final Parcelable.Creator<ProcessStats> CREATOR
-            = new Parcelable.Creator<ProcessStats>() {
-        public ProcessStats createFromParcel(Parcel in) {
-            return new ProcessStats(in);
-        }
-
-        public ProcessStats[] newArray(int size) {
-            return new ProcessStats[size];
-        }
-    };
-
-    private static void printScreenLabel(PrintWriter pw, int offset) {
-        switch (offset) {
-            case ADJ_NOTHING:
-                pw.print("     ");
-                break;
-            case ADJ_SCREEN_OFF:
-                pw.print("SOff/");
-                break;
-            case ADJ_SCREEN_ON:
-                pw.print("SOn /");
-                break;
-            default:
-                pw.print("????/");
-                break;
-        }
-    }
-
-    public static void printScreenLabelCsv(PrintWriter pw, int offset) {
-        switch (offset) {
-            case ADJ_NOTHING:
-                break;
-            case ADJ_SCREEN_OFF:
-                pw.print(ADJ_SCREEN_NAMES_CSV[0]);
-                break;
-            case ADJ_SCREEN_ON:
-                pw.print(ADJ_SCREEN_NAMES_CSV[1]);
-                break;
-            default:
-                pw.print("???");
-                break;
-        }
-    }
-
-    private static void printMemLabel(PrintWriter pw, int offset, char sep) {
-        switch (offset) {
-            case ADJ_NOTHING:
-                pw.print("    ");
-                if (sep != 0) pw.print(' ');
-                break;
-            case ADJ_MEM_FACTOR_NORMAL:
-                pw.print("Norm");
-                if (sep != 0) pw.print(sep);
-                break;
-            case ADJ_MEM_FACTOR_MODERATE:
-                pw.print("Mod ");
-                if (sep != 0) pw.print(sep);
-                break;
-            case ADJ_MEM_FACTOR_LOW:
-                pw.print("Low ");
-                if (sep != 0) pw.print(sep);
-                break;
-            case ADJ_MEM_FACTOR_CRITICAL:
-                pw.print("Crit");
-                if (sep != 0) pw.print(sep);
-                break;
-            default:
-                pw.print("????");
-                if (sep != 0) pw.print(sep);
-                break;
-        }
-    }
-
-    public static void printMemLabelCsv(PrintWriter pw, int offset) {
-        if (offset >= ADJ_MEM_FACTOR_NORMAL) {
-            if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
-                pw.print(ADJ_MEM_NAMES_CSV[offset]);
-            } else {
-                pw.print("???");
-            }
-        }
-    }
-
-    public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
-            int curState, long curStartTime, long now) {
-        long totalTime = 0;
-        int printedScreen = -1;
-        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
-            int printedMem = -1;
-            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
-                int state = imem+iscreen;
-                long time = durations[state];
-                String running = "";
-                if (curState == state) {
-                    time += now - curStartTime;
-                    if (pw != null) {
-                        running = " (running)";
-                    }
-                }
-                if (time != 0) {
-                    if (pw != null) {
-                        pw.print(prefix);
-                        printScreenLabel(pw, printedScreen != iscreen
-                                ? iscreen : STATE_NOTHING);
-                        printedScreen = iscreen;
-                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
-                        printedMem = imem;
-                        pw.print(": ");
-                        TimeUtils.formatDuration(time, pw); pw.println(running);
-                    }
-                    totalTime += time;
-                }
-            }
-        }
-        if (totalTime != 0 && pw != null) {
-            pw.print(prefix);
-            pw.print("    TOTAL: ");
-            TimeUtils.formatDuration(totalTime, pw);
-            pw.println();
-        }
-        return totalTime;
-    }
-
-    static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
-            int curState, long curStartTime, long now) {
-        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
-            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
-                int state = imem+iscreen;
-                long time = durations[state];
-                if (curState == state) {
-                    time += now - curStartTime;
-                }
-                if (time != 0) {
-                    printAdjTagAndValue(pw, state, time);
-                }
-            }
-        }
-    }
-
-    static void dumpServiceTimeCheckin(PrintWriter pw, String label, String packageName,
-            int uid, int vers, String serviceName, ServiceState svc, int serviceType, int opCount,
-            int curState, long curStartTime, long now) {
-        if (opCount <= 0) {
-            return;
-        }
-        pw.print(label);
-        pw.print(",");
-        pw.print(packageName);
-        pw.print(",");
-        pw.print(uid);
-        pw.print(",");
-        pw.print(vers);
-        pw.print(",");
-        pw.print(serviceName);
-        pw.print(",");
-        pw.print(opCount);
-        boolean didCurState = false;
-        for (int i=0; i<svc.mDurationsTableSize; i++) {
-            int off = svc.mDurationsTable[i];
-            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-            int memFactor = type / ServiceState.SERVICE_COUNT;
-            type %= ServiceState.SERVICE_COUNT;
-            if (type != serviceType) {
-                continue;
-            }
-            long time = svc.mStats.getLong(off, 0);
-            if (curState == memFactor) {
-                didCurState = true;
-                time += now - curStartTime;
-            }
-            printAdjTagAndValue(pw, memFactor, time);
-        }
-        if (!didCurState && curState != STATE_NOTHING) {
-            printAdjTagAndValue(pw, curState, now - curStartTime);
-        }
-        pw.println();
-    }
-
-    public static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
-        data.totalTime = 0;
-        data.numPss = data.minPss = data.avgPss = data.maxPss =
-                data.minUss = data.avgUss = data.maxUss = 0;
-        for (int is=0; is<data.screenStates.length; is++) {
-            for (int im=0; im<data.memStates.length; im++) {
-                for (int ip=0; ip<data.procStates.length; ip++) {
-                    int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
-                            + data.procStates[ip];
-                    data.totalTime += proc.getDuration(bucket, now);
-                    long samples = proc.getPssSampleCount(bucket);
-                    if (samples > 0) {
-                        long minPss = proc.getPssMinimum(bucket);
-                        long avgPss = proc.getPssAverage(bucket);
-                        long maxPss = proc.getPssMaximum(bucket);
-                        long minUss = proc.getPssUssMinimum(bucket);
-                        long avgUss = proc.getPssUssAverage(bucket);
-                        long maxUss = proc.getPssUssMaximum(bucket);
-                        if (data.numPss == 0) {
-                            data.minPss = minPss;
-                            data.avgPss = avgPss;
-                            data.maxPss = maxPss;
-                            data.minUss = minUss;
-                            data.avgUss = avgUss;
-                            data.maxUss = maxUss;
-                        } else {
-                            if (minPss < data.minPss) {
-                                data.minPss = minPss;
-                            }
-                            data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
-                                    + (avgPss*(double)samples)) / (data.numPss+samples) );
-                            if (maxPss > data.maxPss) {
-                                data.maxPss = maxPss;
-                            }
-                            if (minUss < data.minUss) {
-                                data.minUss = minUss;
-                            }
-                            data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
-                                    + (avgUss*(double)samples)) / (data.numPss+samples) );
-                            if (maxUss > data.maxUss) {
-                                data.maxUss = maxUss;
-                            }
-                        }
-                        data.numPss += samples;
-                    }
-                }
-            }
-        }
-    }
-
-    static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
-                int[] procStates, long now) {
-        long totalTime = 0;
-        /*
-        for (int i=0; i<proc.mDurationsTableSize; i++) {
-            int val = proc.mDurationsTable[i];
-            totalTime += proc.mState.getLong(val, 0);
-            if ((val&0xff) == proc.mCurState) {
-                totalTime += now - proc.mStartTime;
-            }
-        }
-        */
-        for (int is=0; is<screenStates.length; is++) {
-            for (int im=0; im<memStates.length; im++) {
-                for (int ip=0; ip<procStates.length; ip++) {
-                    int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
-                            + procStates[ip];
-                    totalTime += proc.getDuration(bucket, now);
-                }
-            }
-        }
-        proc.mTmpTotalTime = totalTime;
-        return totalTime;
-    }
-
-    static class PssAggr {
-        long pss = 0;
-        long samples = 0;
-
-        void add(long newPss, long newSamples) {
-            pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
-                    / (samples+newSamples);
-            samples += newSamples;
-        }
-    }
-
-    public void computeTotalMemoryUse(TotalMemoryUseCollection data, long now) {
-        data.totalTime = 0;
-        for (int i=0; i<STATE_COUNT; i++) {
-            data.processStateWeight[i] = 0;
-            data.processStatePss[i] = 0;
-            data.processStateTime[i] = 0;
-            data.processStateSamples[i] = 0;
-        }
-        for (int i=0; i<SYS_MEM_USAGE_COUNT; i++) {
-            data.sysMemUsage[i] = 0;
-        }
-        data.sysMemCachedWeight = 0;
-        data.sysMemFreeWeight = 0;
-        data.sysMemZRamWeight = 0;
-        data.sysMemKernelWeight = 0;
-        data.sysMemNativeWeight = 0;
-        data.sysMemSamples = 0;
-        long[] totalMemUsage = new long[SYS_MEM_USAGE_COUNT];
-        for (int i=0; i<mSysMemUsageTableSize; i++) {
-            int ent = mSysMemUsageTable[i];
-            long[] longs = mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-            int idx = (ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK;
-            addSysMemUsage(totalMemUsage, 0, longs, idx);
-        }
-        for (int is=0; is<data.screenStates.length; is++) {
-            for (int im=0; im<data.memStates.length; im++) {
-                int memBucket = data.screenStates[is] + data.memStates[im];
-                int stateBucket = memBucket * STATE_COUNT;
-                long memTime = mMemFactorDurations[memBucket];
-                if (mMemFactor == memBucket) {
-                    memTime += now - mStartTime;
-                }
-                data.totalTime += memTime;
-                int sysIdx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, stateBucket);
-                long[] longs = totalMemUsage;
-                int idx = 0;
-                if (sysIdx >= 0) {
-                    int ent = mSysMemUsageTable[sysIdx];
-                    long[] tmpLongs = mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-                    int tmpIdx = (ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK;
-                    if (tmpLongs[tmpIdx+SYS_MEM_USAGE_SAMPLE_COUNT] >= 3) {
-                        addSysMemUsage(data.sysMemUsage, 0, longs, idx);
-                        longs = tmpLongs;
-                        idx = tmpIdx;
-                    }
-                }
-                data.sysMemCachedWeight += longs[idx+SYS_MEM_USAGE_CACHED_AVERAGE]
-                        * (double)memTime;
-                data.sysMemFreeWeight += longs[idx+SYS_MEM_USAGE_FREE_AVERAGE]
-                        * (double)memTime;
-                data.sysMemZRamWeight += longs[idx+SYS_MEM_USAGE_ZRAM_AVERAGE]
-                        * (double)memTime;
-                data.sysMemKernelWeight += longs[idx+SYS_MEM_USAGE_KERNEL_AVERAGE]
-                        * (double)memTime;
-                data.sysMemNativeWeight += longs[idx+SYS_MEM_USAGE_NATIVE_AVERAGE]
-                        * (double)memTime;
-                data.sysMemSamples += longs[idx+SYS_MEM_USAGE_SAMPLE_COUNT];
-             }
-        }
-        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        for (int iproc=0; iproc<procMap.size(); iproc++) {
-            SparseArray<ProcessState> uids = procMap.valueAt(iproc);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final ProcessState proc = uids.valueAt(iu);
-                final PssAggr fgPss = new PssAggr();
-                final PssAggr bgPss = new PssAggr();
-                final PssAggr cachedPss = new PssAggr();
-                boolean havePss = false;
-                for (int i=0; i<proc.mDurationsTableSize; i++) {
-                    int off = proc.mDurationsTable[i];
-                    int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                    int procState = type % STATE_COUNT;
-                    long samples = proc.getPssSampleCount(type);
-                    if (samples > 0) {
-                        long avg = proc.getPssAverage(type);
-                        havePss = true;
-                        if (procState <= STATE_IMPORTANT_FOREGROUND) {
-                            fgPss.add(avg, samples);
-                        } else if (procState <= STATE_RECEIVER) {
-                            bgPss.add(avg, samples);
-                        } else {
-                            cachedPss.add(avg, samples);
-                        }
-                    }
-                }
-                if (!havePss) {
-                    continue;
-                }
-                boolean fgHasBg = false;
-                boolean fgHasCached = false;
-                boolean bgHasCached = false;
-                if (fgPss.samples < 3 && bgPss.samples > 0) {
-                    fgHasBg = true;
-                    fgPss.add(bgPss.pss, bgPss.samples);
-                }
-                if (fgPss.samples < 3 && cachedPss.samples > 0) {
-                    fgHasCached = true;
-                    fgPss.add(cachedPss.pss, cachedPss.samples);
-                }
-                if (bgPss.samples < 3 && cachedPss.samples > 0) {
-                    bgHasCached = true;
-                    bgPss.add(cachedPss.pss, cachedPss.samples);
-                }
-                if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
-                    bgPss.add(fgPss.pss, fgPss.samples);
-                }
-                if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
-                    cachedPss.add(bgPss.pss, bgPss.samples);
-                }
-                if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
-                    cachedPss.add(fgPss.pss, fgPss.samples);
-                }
-                for (int i=0; i<proc.mDurationsTableSize; i++) {
-                    final int off = proc.mDurationsTable[i];
-                    final int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                    long time = getLong(off, 0);
-                    if (proc.mCurState == type) {
-                        time += now - proc.mStartTime;
-                    }
-                    final int procState = type % STATE_COUNT;
-                    data.processStateTime[procState] += time;
-                    long samples = proc.getPssSampleCount(type);
-                    long avg;
-                    if (samples > 0) {
-                        avg = proc.getPssAverage(type);
-                    } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
-                        samples = fgPss.samples;
-                        avg = fgPss.pss;
-                    } else if (procState <= STATE_RECEIVER) {
-                        samples = bgPss.samples;
-                        avg = bgPss.pss;
-                    } else {
-                        samples = cachedPss.samples;
-                        avg = cachedPss.pss;
-                    }
-                    double newAvg = ( (data.processStatePss[procState]
-                            * (double)data.processStateSamples[procState])
-                                + (avg*(double)samples)
-                            ) / (data.processStateSamples[procState]+samples);
-                    data.processStatePss[procState] = (long)newAvg;
-                    data.processStateSamples[procState] += samples;
-                    data.processStateWeight[procState] += avg * (double)time;
-                }
-            }
-        }
-    }
-
-    static void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc,
-            int[] screenStates, int[] memStates, int[] procStates, long now) {
-        long totalTime = 0;
-        int printedScreen = -1;
-        for (int is=0; is<screenStates.length; is++) {
-            int printedMem = -1;
-            for (int im=0; im<memStates.length; im++) {
-                for (int ip=0; ip<procStates.length; ip++) {
-                    final int iscreen = screenStates[is];
-                    final int imem = memStates[im];
-                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
-                    long time = proc.getDuration(bucket, now);
-                    String running = "";
-                    if (proc.mCurState == bucket) {
-                        running = " (running)";
-                    }
-                    if (time != 0) {
-                        pw.print(prefix);
-                        if (screenStates.length > 1) {
-                            printScreenLabel(pw, printedScreen != iscreen
-                                    ? iscreen : STATE_NOTHING);
-                            printedScreen = iscreen;
-                        }
-                        if (memStates.length > 1) {
-                            printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, '/');
-                            printedMem = imem;
-                        }
-                        pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
-                        TimeUtils.formatDuration(time, pw); pw.println(running);
-                        totalTime += time;
-                    }
-                }
-            }
-        }
-        if (totalTime != 0) {
-            pw.print(prefix);
-            if (screenStates.length > 1) {
-                printScreenLabel(pw, STATE_NOTHING);
-            }
-            if (memStates.length > 1) {
-                printMemLabel(pw, STATE_NOTHING, '/');
-            }
-            pw.print("TOTAL  : ");
-            TimeUtils.formatDuration(totalTime, pw);
-            pw.println();
-        }
-    }
-
-    static void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
-            int[] memStates, int[] procStates) {
-        boolean printedHeader = false;
-        int printedScreen = -1;
-        for (int is=0; is<screenStates.length; is++) {
-            int printedMem = -1;
-            for (int im=0; im<memStates.length; im++) {
-                for (int ip=0; ip<procStates.length; ip++) {
-                    final int iscreen = screenStates[is];
-                    final int imem = memStates[im];
-                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
-                    long count = proc.getPssSampleCount(bucket);
-                    if (count > 0) {
-                        if (!printedHeader) {
-                            pw.print(prefix);
-                            pw.print("PSS/USS (");
-                            pw.print(proc.mPssTableSize);
-                            pw.println(" entries):");
-                            printedHeader = true;
-                        }
-                        pw.print(prefix);
-                        pw.print("  ");
-                        if (screenStates.length > 1) {
-                            printScreenLabel(pw, printedScreen != iscreen
-                                    ? iscreen : STATE_NOTHING);
-                            printedScreen = iscreen;
-                        }
-                        if (memStates.length > 1) {
-                            printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, '/');
-                            printedMem = imem;
-                        }
-                        pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
-                        pw.print(count);
-                        pw.print(" samples ");
-                        DebugUtils.printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
-                        pw.print(" ");
-                        DebugUtils.printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
-                        pw.print(" ");
-                        DebugUtils.printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
-                        pw.print(" / ");
-                        DebugUtils.printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
-                        pw.print(" ");
-                        DebugUtils.printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
-                        pw.print(" ");
-                        DebugUtils.printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
-                        pw.println();
-                    }
-                }
-            }
-        }
-        if (proc.mNumExcessiveWake != 0) {
-            pw.print(prefix); pw.print("Killed for excessive wake locks: ");
-                    pw.print(proc.mNumExcessiveWake); pw.println(" times");
-        }
-        if (proc.mNumExcessiveCpu != 0) {
-            pw.print(prefix); pw.print("Killed for excessive CPU use: ");
-                    pw.print(proc.mNumExcessiveCpu); pw.println(" times");
-        }
-        if (proc.mNumCachedKill != 0) {
-            pw.print(prefix); pw.print("Killed from cached state: ");
-                    pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
-                    DebugUtils.printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
-                    DebugUtils.printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
-                    DebugUtils.printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
-        }
-    }
-
-    long getSysMemUsageValue(int state, int index) {
-        int idx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, state);
-        return idx >= 0 ? getLong(mSysMemUsageTable[idx], index) : 0;
-    }
-
-    void dumpSysMemUsageCategory(PrintWriter pw, String prefix, String label,
-            int bucket, int index) {
-        pw.print(prefix); pw.print(label);
-        pw.print(": ");
-        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
-        pw.print(" min, ");
-        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
-        pw.print(" avg, ");
-        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
-        pw.println(" max");
-    }
-
-    void dumpSysMemUsage(PrintWriter pw, String prefix, int[] screenStates,
-            int[] memStates) {
-        int printedScreen = -1;
-        for (int is=0; is<screenStates.length; is++) {
-            int printedMem = -1;
-            for (int im=0; im<memStates.length; im++) {
-                final int iscreen = screenStates[is];
-                final int imem = memStates[im];
-                final int bucket = ((iscreen + imem) * STATE_COUNT);
-                long count = getSysMemUsageValue(bucket, SYS_MEM_USAGE_SAMPLE_COUNT);
-                if (count > 0) {
-                    pw.print(prefix);
-                    if (screenStates.length > 1) {
-                        printScreenLabel(pw, printedScreen != iscreen
-                                ? iscreen : STATE_NOTHING);
-                        printedScreen = iscreen;
-                    }
-                    if (memStates.length > 1) {
-                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, '\0');
-                        printedMem = imem;
-                    }
-                    pw.print(": ");
-                    pw.print(count);
-                    pw.println(" samples:");
-                    dumpSysMemUsageCategory(pw, prefix, "  Cached", bucket,
-                            SYS_MEM_USAGE_CACHED_MINIMUM);
-                    dumpSysMemUsageCategory(pw, prefix, "  Free", bucket,
-                            SYS_MEM_USAGE_FREE_MINIMUM);
-                    dumpSysMemUsageCategory(pw, prefix, "  ZRam", bucket,
-                            SYS_MEM_USAGE_ZRAM_MINIMUM);
-                    dumpSysMemUsageCategory(pw, prefix, "  Kernel", bucket,
-                            SYS_MEM_USAGE_KERNEL_MINIMUM);
-                    dumpSysMemUsageCategory(pw, prefix, "  Native", bucket,
-                            SYS_MEM_USAGE_NATIVE_MINIMUM);
-                }
-            }
-        }
-    }
-
-    static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
-            int[] memStates, int[] procStates) {
-        final int NS = screenStates != null ? screenStates.length : 1;
-        final int NM = memStates != null ? memStates.length : 1;
-        final int NP = procStates != null ? procStates.length : 1;
-        for (int is=0; is<NS; is++) {
-            for (int im=0; im<NM; im++) {
-                for (int ip=0; ip<NP; ip++) {
-                    pw.print(sep);
-                    boolean printed = false;
-                    if (screenStates != null && screenStates.length > 1) {
-                        printScreenLabelCsv(pw, screenStates[is]);
-                        printed = true;
-                    }
-                    if (memStates != null && memStates.length > 1) {
-                        if (printed) {
-                            pw.print("-");
-                        }
-                        printMemLabelCsv(pw, memStates[im]);
-                        printed = true;
-                    }
-                    if (procStates != null && procStates.length > 1) {
-                        if (printed) {
-                            pw.print("-");
-                        }
-                        pw.print(STATE_NAMES_CSV[procStates[ip]]);
-                    }
-                }
-            }
-        }
-    }
-
-    static void dumpProcessStateCsv(PrintWriter pw, ProcessState proc,
-            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
-            boolean sepProcStates, int[] procStates, long now) {
-        final int NSS = sepScreenStates ? screenStates.length : 1;
-        final int NMS = sepMemStates ? memStates.length : 1;
-        final int NPS = sepProcStates ? procStates.length : 1;
-        for (int iss=0; iss<NSS; iss++) {
-            for (int ims=0; ims<NMS; ims++) {
-                for (int ips=0; ips<NPS; ips++) {
-                    final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
-                    final int vsmem = sepMemStates ? memStates[ims] : 0;
-                    final int vsproc = sepProcStates ? procStates[ips] : 0;
-                    final int NSA = sepScreenStates ? 1 : screenStates.length;
-                    final int NMA = sepMemStates ? 1 : memStates.length;
-                    final int NPA = sepProcStates ? 1 : procStates.length;
-                    long totalTime = 0;
-                    for (int isa=0; isa<NSA; isa++) {
-                        for (int ima=0; ima<NMA; ima++) {
-                            for (int ipa=0; ipa<NPA; ipa++) {
-                                final int vascreen = sepScreenStates ? 0 : screenStates[isa];
-                                final int vamem = sepMemStates ? 0 : memStates[ima];
-                                final int vaproc = sepProcStates ? 0 : procStates[ipa];
-                                final int bucket = ((vsscreen + vascreen + vsmem + vamem)
-                                        * STATE_COUNT) + vsproc + vaproc;
-                                totalTime += proc.getDuration(bucket, now);
-                            }
-                        }
-                    }
-                    pw.print(CSV_SEP);
-                    pw.print(totalTime);
-                }
-            }
-        }
-    }
-
-    static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
-            int[] screenStates, int[] memStates, int[] procStates, long now) {
-        String innerPrefix = prefix + "  ";
-        for (int i=procs.size()-1; i>=0; i--) {
-            ProcessState proc = procs.get(i);
-            pw.print(prefix);
-            pw.print(proc.mName);
-            pw.print(" / ");
-            UserHandle.formatUid(pw, proc.mUid);
-            pw.print(" (");
-            pw.print(proc.mDurationsTableSize);
-            pw.print(" entries)");
-            pw.println(":");
-            dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now);
-            if (proc.mPssTableSize > 0) {
-                dumpProcessPss(pw, innerPrefix, proc, screenStates, memStates, procStates);
-            }
-        }
-    }
-
-    static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
-            String label, int[] screenStates, int[] memStates, int[] procStates,
-            long now, long totalTime, boolean full) {
-        ProcessDataCollection totals = new ProcessDataCollection(screenStates,
-                memStates, procStates);
-        computeProcessData(proc, totals, now);
-        double percentage = (double) totals.totalTime / (double) totalTime * 100;
-        // We don't print percentages < .01, so just drop those.
-        if (percentage >= 0.005 || totals.numPss != 0) {
-            if (prefix != null) {
-                pw.print(prefix);
-            }
-            if (label != null) {
-                pw.print(label);
-            }
-            totals.print(pw, totalTime, full);
-            if (prefix != null) {
-                pw.println();
-            }
-        }
-    }
-
-    static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
-            ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
-            boolean inclUidVers, long now, long totalTime) {
-        for (int i=procs.size()-1; i>=0; i--) {
-            ProcessState proc = procs.get(i);
-            pw.print(prefix);
-            pw.print("* ");
-            pw.print(proc.mName);
-            pw.print(" / ");
-            UserHandle.formatUid(pw, proc.mUid);
-            pw.print(" / v");
-            pw.print(proc.mVersion);
-            pw.println(":");
-            dumpProcessSummaryDetails(pw, proc, prefix, "         TOTAL: ", screenStates, memStates,
-                    procStates, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "    Persistent: ", screenStates, memStates,
-                    new int[] { STATE_PERSISTENT }, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "           Top: ", screenStates, memStates,
-                    new int[] {STATE_TOP}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Fg: ", screenStates, memStates,
-                    new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Bg: ", screenStates, memStates,
-                    new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "        Backup: ", screenStates, memStates,
-                    new int[] {STATE_BACKUP}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "     Heavy Wgt: ", screenStates, memStates,
-                    new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "       Service: ", screenStates, memStates,
-                    new int[] {STATE_SERVICE}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "    Service Rs: ", screenStates, memStates,
-                    new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "      Receiver: ", screenStates, memStates,
-                    new int[] {STATE_RECEIVER}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "        (Home): ", screenStates, memStates,
-                    new int[] {STATE_HOME}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "    (Last Act): ", screenStates, memStates,
-                    new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "      (Cached): ", screenStates, memStates,
-                    new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
-                            STATE_CACHED_EMPTY}, now, totalTime, true);
-        }
-    }
-
-    static void printPercent(PrintWriter pw, double fraction) {
-        fraction *= 100;
-        if (fraction < 1) {
-            pw.print(String.format("%.2f", fraction));
-        } else if (fraction < 10) {
-            pw.print(String.format("%.1f", fraction));
-        } else {
-            pw.print(String.format("%.0f", fraction));
-        }
-        pw.print("%");
-    }
-
-    public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
-            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
-            boolean sepProcStates, int[] procStates, long now) {
-        pw.print("process");
-        pw.print(CSV_SEP);
-        pw.print("uid");
-        pw.print(CSV_SEP);
-        pw.print("vers");
-        dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
-                sepMemStates ? memStates : null,
-                sepProcStates ? procStates : null);
-        pw.println();
-        for (int i=procs.size()-1; i>=0; i--) {
-            ProcessState proc = procs.get(i);
-            pw.print(proc.mName);
-            pw.print(CSV_SEP);
-            UserHandle.formatUid(pw, proc.mUid);
-            pw.print(CSV_SEP);
-            pw.print(proc.mVersion);
-            dumpProcessStateCsv(pw, proc, sepScreenStates, screenStates,
-                    sepMemStates, memStates, sepProcStates, procStates, now);
-            pw.println();
-        }
-    }
-
-    static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
-        int index = value/mod;
-        if (index >= 0 && index < array.length) {
-            pw.print(array[index]);
-        } else {
-            pw.print('?');
-        }
-        return value - index*mod;
-    }
-
-    static void printProcStateTag(PrintWriter pw, int state) {
-        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
-        state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
-        printArrayEntry(pw, STATE_TAGS,  state, 1);
-    }
-
-    static void printAdjTag(PrintWriter pw, int state) {
-        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
-        printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
-    }
-
-    static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
-        pw.print(',');
-        printProcStateTag(pw, state);
-        pw.print(':');
-        pw.print(value);
-    }
-
-    static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
-        pw.print(',');
-        printAdjTag(pw, state);
-        pw.print(':');
-        pw.print(value);
-    }
-
-    static void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
-        boolean didCurState = false;
-        for (int i=0; i<proc.mDurationsTableSize; i++) {
-            int off = proc.mDurationsTable[i];
-            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-            long time = proc.mStats.getLong(off, 0);
-            if (proc.mCurState == type) {
-                didCurState = true;
-                time += now - proc.mStartTime;
-            }
-            printProcStateTagAndValue(pw, type, time);
-        }
-        if (!didCurState && proc.mCurState != STATE_NOTHING) {
-            printProcStateTagAndValue(pw, proc.mCurState, now - proc.mStartTime);
-        }
-    }
-
-    static void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc) {
-        for (int i=0; i<proc.mPssTableSize; i++) {
-            int off = proc.mPssTable[i];
-            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-            long count = proc.mStats.getLong(off, PSS_SAMPLE_COUNT);
-            long min = proc.mStats.getLong(off, PSS_MINIMUM);
-            long avg = proc.mStats.getLong(off, PSS_AVERAGE);
-            long max = proc.mStats.getLong(off, PSS_MAXIMUM);
-            long umin = proc.mStats.getLong(off, PSS_USS_MINIMUM);
-            long uavg = proc.mStats.getLong(off, PSS_USS_AVERAGE);
-            long umax = proc.mStats.getLong(off, PSS_USS_MAXIMUM);
-            pw.print(',');
-            printProcStateTag(pw, type);
-            pw.print(':');
-            pw.print(count);
-            pw.print(':');
-            pw.print(min);
-            pw.print(':');
-            pw.print(avg);
-            pw.print(':');
-            pw.print(max);
-            pw.print(':');
-            pw.print(umin);
-            pw.print(':');
-            pw.print(uavg);
-            pw.print(':');
-            pw.print(umax);
-        }
-    }
-
-    public void reset() {
-        if (DEBUG) Slog.d(TAG, "Resetting state of " + mTimePeriodStartClockStr);
-        resetCommon();
-        mPackages.getMap().clear();
-        mProcesses.getMap().clear();
-        mMemFactor = STATE_NOTHING;
-        mStartTime = 0;
-        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
-    }
-
-    public void resetSafely() {
-        if (DEBUG) Slog.d(TAG, "Safely resetting state of " + mTimePeriodStartClockStr);
-        resetCommon();
-
-        // First initialize use count of all common processes.
-        final long now = SystemClock.uptimeMillis();
-        final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        for (int ip=procMap.size()-1; ip>=0; ip--) {
-            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=uids.size()-1; iu>=0; iu--) {
-                uids.valueAt(iu).mTmpNumInUse = 0;
-           }
-        }
-
-        // Next reset or prune all per-package processes, and for the ones that are reset
-        // track this back to the common processes.
-        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
-        for (int ip=pkgMap.size()-1; ip>=0; ip--) {
-            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            for (int iu=uids.size()-1; iu>=0; iu--) {
-                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
-                for (int iv=vpkgs.size()-1; iv>=0; iv--) {
-                    final PackageState pkgState = vpkgs.valueAt(iv);
-                    for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
-                        final ProcessState ps = pkgState.mProcesses.valueAt(iproc);
-                        if (ps.isInUse()) {
-                            ps.resetSafely(now);
-                            ps.mCommonProcess.mTmpNumInUse++;
-                            ps.mCommonProcess.mTmpFoundSubProc = ps;
-                        } else {
-                            pkgState.mProcesses.valueAt(iproc).makeDead();
-                            pkgState.mProcesses.removeAt(iproc);
-                        }
-                    }
-                    for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
-                        final ServiceState ss = pkgState.mServices.valueAt(isvc);
-                        if (ss.isInUse()) {
-                            ss.resetSafely(now);
-                        } else {
-                            pkgState.mServices.removeAt(isvc);
-                        }
-                    }
-                    if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) {
-                        vpkgs.removeAt(iv);
-                    }
-                }
-                if (vpkgs.size() <= 0) {
-                    uids.removeAt(iu);
-                }
-            }
-            if (uids.size() <= 0) {
-                pkgMap.removeAt(ip);
-            }
-        }
-
-        // Finally prune out any common processes that are no longer in use.
-        for (int ip=procMap.size()-1; ip>=0; ip--) {
-            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=uids.size()-1; iu>=0; iu--) {
-                ProcessState ps = uids.valueAt(iu);
-                if (ps.isInUse() || ps.mTmpNumInUse > 0) {
-                    // If this is a process for multiple packages, we could at this point
-                    // be back down to one package.  In that case, we want to revert back
-                    // to a single shared ProcessState.  We can do this by converting the
-                    // current package-specific ProcessState up to the shared ProcessState,
-                    // throwing away the current one we have here (because nobody else is
-                    // using it).
-                    if (!ps.mActive && ps.mMultiPackage && ps.mTmpNumInUse == 1) {
-                        // Here we go...
-                        ps = ps.mTmpFoundSubProc;
-                        ps.mCommonProcess = ps;
-                        uids.setValueAt(iu, ps);
-                    } else {
-                        ps.resetSafely(now);
-                    }
-                } else {
-                    ps.makeDead();
-                    uids.removeAt(iu);
-                }
-            }
-            if (uids.size() <= 0) {
-                procMap.removeAt(ip);
-            }
-        }
-
-        mStartTime = now;
-        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
-    }
-
-    private void resetCommon() {
-        mTimePeriodStartClock = System.currentTimeMillis();
-        buildTimePeriodStartClockStr();
-        mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
-        mTimePeriodStartUptime = mTimePeriodEndUptime = SystemClock.uptimeMillis();
-        mLongs.clear();
-        mLongs.add(new long[LONGS_SIZE]);
-        mNextLong = 0;
-        Arrays.fill(mMemFactorDurations, 0);
-        mSysMemUsageTable = null;
-        mSysMemUsageTableSize = 0;
-        mStartTime = 0;
-        mReadError = null;
-        mFlags = 0;
-        evaluateSystemProperties(true);
-    }
-
-    public boolean evaluateSystemProperties(boolean update) {
-        boolean changed = false;
-        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2",
-                VMRuntime.getRuntime().vmLibrary());
-        if (!Objects.equals(runtime, mRuntime)) {
-            changed = true;
-            if (update) {
-                mRuntime = runtime;
-            }
-        }
-        return changed;
-    }
-
-    private void buildTimePeriodStartClockStr() {
-        mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
-                mTimePeriodStartClock).toString();
-    }
-
-    static final int[] BAD_TABLE = new int[0];
-
-    private int[] readTableFromParcel(Parcel in, String name, String what) {
-        final int size = in.readInt();
-        if (size < 0) {
-            Slog.w(TAG, "Ignoring existing stats; bad " + what + " table size: " + size);
-            return BAD_TABLE;
-        }
-        if (size == 0) {
-            return null;
-        }
-        final int[] table = new int[size];
-        for (int i=0; i<size; i++) {
-            table[i] = in.readInt();
-            if (DEBUG_PARCEL) Slog.i(TAG, "Reading in " + name + " table #" + i + ": "
-                    + ProcessStats.printLongOffset(table[i]));
-            if (!validateLongOffset(table[i])) {
-                Slog.w(TAG, "Ignoring existing stats; bad " + what + " table entry: "
-                        + ProcessStats.printLongOffset(table[i]));
-                return null;
-            }
-        }
-        return table;
-    }
-
-    private void writeCompactedLongArray(Parcel out, long[] array, int num) {
-        for (int i=0; i<num; i++) {
-            long val = array[i];
-            if (val < 0) {
-                Slog.w(TAG, "Time val negative: " + val);
-                val = 0;
-            }
-            if (val <= Integer.MAX_VALUE) {
-                out.writeInt((int)val);
-            } else {
-                int top = ~((int)((val>>32)&0x7fffffff));
-                int bottom = (int)(val&0xfffffff);
-                out.writeInt(top);
-                out.writeInt(bottom);
-            }
-        }
-    }
-
-    private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
-        if (version <= 10) {
-            in.readLongArray(array);
-            return;
-        }
-        final int alen = array.length;
-        if (num > alen) {
-            throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
-        }
-        int i;
-        for (i=0; i<num; i++) {
-            int val = in.readInt();
-            if (val >= 0) {
-                array[i] = val;
-            } else {
-                int bottom = in.readInt();
-                array[i] = (((long)~val)<<32) | bottom;
-            }
-        }
-        while (i < alen) {
-            array[i] = 0;
-            i++;
-        }
-    }
-
-    private void writeCommonString(Parcel out, String name) {
-        Integer index = mCommonStringToIndex.get(name);
-        if (index != null) {
-            out.writeInt(index);
-            return;
-        }
-        index = mCommonStringToIndex.size();
-        mCommonStringToIndex.put(name, index);
-        out.writeInt(~index);
-        out.writeString(name);
-    }
-
-    private String readCommonString(Parcel in, int version) {
-        if (version <= 9) {
-            return in.readString();
-        }
-        int index = in.readInt();
-        if (index >= 0) {
-            return mIndexToCommonString.get(index);
-        }
-        index = ~index;
-        String name = in.readString();
-        while (mIndexToCommonString.size() <= index) {
-            mIndexToCommonString.add(null);
-        }
-        mIndexToCommonString.set(index, name);
-        return name;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        writeToParcel(out, SystemClock.uptimeMillis(), flags);
-    }
-
-    /** @hide */
-    public void writeToParcel(Parcel out, long now, int flags) {
-        out.writeInt(MAGIC);
-        out.writeInt(PARCEL_VERSION);
-        out.writeInt(STATE_COUNT);
-        out.writeInt(ADJ_COUNT);
-        out.writeInt(PSS_COUNT);
-        out.writeInt(SYS_MEM_USAGE_COUNT);
-        out.writeInt(LONGS_SIZE);
-
-        mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.mMap.size());
-
-        // First commit all running times.
-        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        final int NPROC = procMap.size();
-        for (int ip=0; ip<NPROC; ip++) {
-            SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            final int NUID = uids.size();
-            for (int iu=0; iu<NUID; iu++) {
-                uids.valueAt(iu).commitStateTime(now);
-            }
-        }
-        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
-        final int NPKG = pkgMap.size();
-        for (int ip=0; ip<NPKG; ip++) {
-            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            final int NUID = uids.size();
-            for (int iu=0; iu<NUID; iu++) {
-                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
-                final int NVERS = vpkgs.size();
-                for (int iv=0; iv<NVERS; iv++) {
-                    PackageState pkgState = vpkgs.valueAt(iv);
-                    final int NPROCS = pkgState.mProcesses.size();
-                    for (int iproc=0; iproc<NPROCS; iproc++) {
-                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                        if (proc.mCommonProcess != proc) {
-                            proc.commitStateTime(now);
-                        }
-                    }
-                    final int NSRVS = pkgState.mServices.size();
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        pkgState.mServices.valueAt(isvc).commitStateTime(now);
-                    }
-                }
-            }
-        }
-
-        out.writeLong(mTimePeriodStartClock);
-        out.writeLong(mTimePeriodStartRealtime);
-        out.writeLong(mTimePeriodEndRealtime);
-        out.writeLong(mTimePeriodStartUptime);
-        out.writeLong(mTimePeriodEndUptime);
-        out.writeString(mRuntime);
-        out.writeInt(mFlags);
-
-        out.writeInt(mLongs.size());
-        out.writeInt(mNextLong);
-        for (int i=0; i<(mLongs.size()-1); i++) {
-            long[] array = mLongs.get(i);
-            writeCompactedLongArray(out, array, array.length);
-        }
-        long[] lastLongs = mLongs.get(mLongs.size() - 1);
-        writeCompactedLongArray(out, lastLongs, mNextLong);
-
-        if (mMemFactor != STATE_NOTHING) {
-            mMemFactorDurations[mMemFactor] += now - mStartTime;
-            mStartTime = now;
-        }
-        writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
-
-        out.writeInt(mSysMemUsageTableSize);
-        for (int i=0; i<mSysMemUsageTableSize; i++) {
-            if (DEBUG_PARCEL) Slog.i(TAG, "Writing sys mem usage #" + i + ": "
-                    + printLongOffset(mSysMemUsageTable[i]));
-            out.writeInt(mSysMemUsageTable[i]);
-        }
-
-        out.writeInt(NPROC);
-        for (int ip=0; ip<NPROC; ip++) {
-            writeCommonString(out, procMap.keyAt(ip));
-            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            final int NUID = uids.size();
-            out.writeInt(NUID);
-            for (int iu=0; iu<NUID; iu++) {
-                out.writeInt(uids.keyAt(iu));
-                final ProcessState proc = uids.valueAt(iu);
-                writeCommonString(out, proc.mPackage);
-                out.writeInt(proc.mVersion);
-                proc.writeToParcel(out, now);
-            }
-        }
-        out.writeInt(NPKG);
-        for (int ip=0; ip<NPKG; ip++) {
-            writeCommonString(out, pkgMap.keyAt(ip));
-            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            final int NUID = uids.size();
-            out.writeInt(NUID);
-            for (int iu=0; iu<NUID; iu++) {
-                out.writeInt(uids.keyAt(iu));
-                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
-                final int NVERS = vpkgs.size();
-                out.writeInt(NVERS);
-                for (int iv=0; iv<NVERS; iv++) {
-                    out.writeInt(vpkgs.keyAt(iv));
-                    final PackageState pkgState = vpkgs.valueAt(iv);
-                    final int NPROCS = pkgState.mProcesses.size();
-                    out.writeInt(NPROCS);
-                    for (int iproc=0; iproc<NPROCS; iproc++) {
-                        writeCommonString(out, pkgState.mProcesses.keyAt(iproc));
-                        final ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                        if (proc.mCommonProcess == proc) {
-                            // This is the same as the common process we wrote above.
-                            out.writeInt(0);
-                        } else {
-                            // There is separate data for this package's process.
-                            out.writeInt(1);
-                            proc.writeToParcel(out, now);
-                        }
-                    }
-                    final int NSRVS = pkgState.mServices.size();
-                    out.writeInt(NSRVS);
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        out.writeString(pkgState.mServices.keyAt(isvc));
-                        final ServiceState svc = pkgState.mServices.valueAt(isvc);
-                        writeCommonString(out, svc.mProcessName);
-                        svc.writeToParcel(out, now);
-                    }
-                }
-            }
-        }
-
-        mCommonStringToIndex = null;
-    }
-
-    private boolean readCheckedInt(Parcel in, int val, String what) {
-        int got;
-        if ((got=in.readInt()) != val) {
-            mReadError = "bad " + what + ": " + got;
-            return false;
-        }
-        return true;
-    }
-
-    static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
-        int pos = 0;
-        final int initialAvail = stream.available();
-        byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
-        while (true) {
-            int amt = stream.read(data, pos, data.length-pos);
-            if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos
-                    + " of avail " + data.length);
-            if (amt < 0) {
-                if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos
-                        + " len=" + data.length);
-                outLen[0] = pos;
-                return data;
-            }
-            pos += amt;
-            if (pos >= data.length) {
-                byte[] newData = new byte[pos+16384];
-                if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
-                        + newData.length);
-                System.arraycopy(data, 0, newData, 0, pos);
-                data = newData;
-            }
-        }
-    }
-
-    public void read(InputStream stream) {
-        try {
-            int[] len = new int[1];
-            byte[] raw = readFully(stream, len);
-            Parcel in = Parcel.obtain();
-            in.unmarshall(raw, 0, len[0]);
-            in.setDataPosition(0);
-            stream.close();
-
-            readFromParcel(in);
-        } catch (IOException e) {
-            mReadError = "caught exception: " + e;
-        }
-    }
-
-    public void readFromParcel(Parcel in) {
-        final boolean hadData = mPackages.getMap().size() > 0
-                || mProcesses.getMap().size() > 0;
-        if (hadData) {
-            resetSafely();
-        }
-
-        if (!readCheckedInt(in, MAGIC, "magic number")) {
-            return;
-        }
-        int version = in.readInt();
-        if (version != PARCEL_VERSION) {
-            mReadError = "bad version: " + version;
-            return;
-        }
-        if (!readCheckedInt(in, STATE_COUNT, "state count")) {
-            return;
-        }
-        if (!readCheckedInt(in, ADJ_COUNT, "adj count")) {
-            return;
-        }
-        if (!readCheckedInt(in, PSS_COUNT, "pss count")) {
-            return;
-        }
-        if (!readCheckedInt(in, SYS_MEM_USAGE_COUNT, "sys mem usage count")) {
-            return;
-        }
-        if (!readCheckedInt(in, LONGS_SIZE, "longs size")) {
-            return;
-        }
-
-        mIndexToCommonString = new ArrayList<String>();
-
-        mTimePeriodStartClock = in.readLong();
-        buildTimePeriodStartClockStr();
-        mTimePeriodStartRealtime = in.readLong();
-        mTimePeriodEndRealtime = in.readLong();
-        mTimePeriodStartUptime = in.readLong();
-        mTimePeriodEndUptime = in.readLong();
-        mRuntime = in.readString();
-        mFlags = in.readInt();
-
-        final int NLONGS = in.readInt();
-        final int NEXTLONG = in.readInt();
-        mLongs.clear();
-        for (int i=0; i<(NLONGS-1); i++) {
-            while (i >= mLongs.size()) {
-                mLongs.add(new long[LONGS_SIZE]);
-            }
-            readCompactedLongArray(in, version, mLongs.get(i), LONGS_SIZE);
-        }
-        long[] longs = new long[LONGS_SIZE];
-        mNextLong = NEXTLONG;
-        readCompactedLongArray(in, version, longs, NEXTLONG);
-        mLongs.add(longs);
-
-        readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
-
-        mSysMemUsageTable = readTableFromParcel(in, TAG, "sys mem usage");
-        if (mSysMemUsageTable == BAD_TABLE) {
-            return;
-        }
-        mSysMemUsageTableSize = mSysMemUsageTable != null ? mSysMemUsageTable.length : 0;
-
-        int NPROC = in.readInt();
-        if (NPROC < 0) {
-            mReadError = "bad process count: " + NPROC;
-            return;
-        }
-        while (NPROC > 0) {
-            NPROC--;
-            final String procName = readCommonString(in, version);
-            if (procName == null) {
-                mReadError = "bad process name";
-                return;
-            }
-            int NUID = in.readInt();
-            if (NUID < 0) {
-                mReadError = "bad uid count: " + NUID;
-                return;
-            }
-            while (NUID > 0) {
-                NUID--;
-                final int uid = in.readInt();
-                if (uid < 0) {
-                    mReadError = "bad uid: " + uid;
-                    return;
-                }
-                final String pkgName = readCommonString(in, version);
-                if (pkgName == null) {
-                    mReadError = "bad process package name";
-                    return;
-                }
-                final int vers = in.readInt();
-                ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
-                if (proc != null) {
-                    if (!proc.readFromParcel(in, false)) {
-                        return;
-                    }
-                } else {
-                    proc = new ProcessState(this, pkgName, uid, vers, procName);
-                    if (!proc.readFromParcel(in, true)) {
-                        return;
-                    }
-                }
-                if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid
-                        + " " + proc);
-                mProcesses.put(procName, uid, proc);
-            }
-        }
-
-        if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes");
-
-        int NPKG = in.readInt();
-        if (NPKG < 0) {
-            mReadError = "bad package count: " + NPKG;
-            return;
-        }
-        while (NPKG > 0) {
-            NPKG--;
-            final String pkgName = readCommonString(in, version);
-            if (pkgName == null) {
-                mReadError = "bad package name";
-                return;
-            }
-            int NUID = in.readInt();
-            if (NUID < 0) {
-                mReadError = "bad uid count: " + NUID;
-                return;
-            }
-            while (NUID > 0) {
-                NUID--;
-                final int uid = in.readInt();
-                if (uid < 0) {
-                    mReadError = "bad uid: " + uid;
-                    return;
-                }
-                int NVERS = in.readInt();
-                if (NVERS < 0) {
-                    mReadError = "bad versions count: " + NVERS;
-                    return;
-                }
-                while (NVERS > 0) {
-                    NVERS--;
-                    final int vers = in.readInt();
-                    PackageState pkgState = new PackageState(pkgName, uid);
-                    SparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
-                    if (vpkg == null) {
-                        vpkg = new SparseArray<PackageState>();
-                        mPackages.put(pkgName, uid, vpkg);
-                    }
-                    vpkg.put(vers, pkgState);
-                    int NPROCS = in.readInt();
-                    if (NPROCS < 0) {
-                        mReadError = "bad package process count: " + NPROCS;
-                        return;
-                    }
-                    while (NPROCS > 0) {
-                        NPROCS--;
-                        String procName = readCommonString(in, version);
-                        if (procName == null) {
-                            mReadError = "bad package process name";
-                            return;
-                        }
-                        int hasProc = in.readInt();
-                        if (DEBUG_PARCEL) Slog.d(TAG, "Reading package " + pkgName + " " + uid
-                                + " process " + procName + " hasProc=" + hasProc);
-                        ProcessState commonProc = mProcesses.get(procName, uid);
-                        if (DEBUG_PARCEL) Slog.d(TAG, "Got common proc " + procName + " " + uid
-                                + ": " + commonProc);
-                        if (commonProc == null) {
-                            mReadError = "no common proc: " + procName;
-                            return;
-                        }
-                        if (hasProc != 0) {
-                            // The process for this package is unique to the package; we
-                            // need to load it.  We don't need to do anything about it if
-                            // it is not unique because if someone later looks for it
-                            // they will find and use it from the global procs.
-                            ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
-                            if (proc != null) {
-                                if (!proc.readFromParcel(in, false)) {
-                                    return;
-                                }
-                            } else {
-                                proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
-                                        0);
-                                if (!proc.readFromParcel(in, true)) {
-                                    return;
-                                }
-                            }
-                            if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
-                                    + procName + " " + uid + " " + proc);
-                            pkgState.mProcesses.put(procName, proc);
-                        } else {
-                            if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
-                                    + procName + " " + uid + " " + commonProc);
-                            pkgState.mProcesses.put(procName, commonProc);
-                        }
-                    }
-                    int NSRVS = in.readInt();
-                    if (NSRVS < 0) {
-                        mReadError = "bad package service count: " + NSRVS;
-                        return;
-                    }
-                    while (NSRVS > 0) {
-                        NSRVS--;
-                        String serviceName = in.readString();
-                        if (serviceName == null) {
-                            mReadError = "bad package service name";
-                            return;
-                        }
-                        String processName = version > 9 ? readCommonString(in, version) : null;
-                        ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
-                        if (serv == null) {
-                            serv = new ServiceState(this, pkgName, serviceName, processName, null);
-                        }
-                        if (!serv.readFromParcel(in)) {
-                            return;
-                        }
-                        if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " service: "
-                                + serviceName + " " + uid + " " + serv);
-                        pkgState.mServices.put(serviceName, serv);
-                    }
-                }
-            }
-        }
-
-        mIndexToCommonString = null;
-
-        if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!");
-    }
-
-    int addLongData(int index, int type, int num) {
-        int off = allocLongData(num);
-        mAddLongTable = GrowingArrayUtils.insert(
-                mAddLongTable != null ? mAddLongTable : EmptyArray.INT,
-                mAddLongTableSize, index, type | off);
-        mAddLongTableSize++;
-        return off;
-    }
-
-    int allocLongData(int num) {
-        int whichLongs = mLongs.size()-1;
-        long[] longs = mLongs.get(whichLongs);
-        if (mNextLong + num > longs.length) {
-            longs = new long[LONGS_SIZE];
-            mLongs.add(longs);
-            whichLongs++;
-            mNextLong = 0;
-        }
-        int off = (whichLongs<<OFFSET_ARRAY_SHIFT) | (mNextLong<<OFFSET_INDEX_SHIFT);
-        mNextLong += num;
-        return off;
-    }
-
-    boolean validateLongOffset(int off) {
-        int arr = (off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK;
-        if (arr >= mLongs.size()) {
-            return false;
-        }
-        int idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
-        if (idx >= LONGS_SIZE) {
-            return false;
-        }
-        if (DEBUG_PARCEL) Slog.d(TAG, "Validated long " + printLongOffset(off)
-                + ": " + getLong(off, 0));
-        return true;
-    }
-
-    static String printLongOffset(int off) {
-        StringBuilder sb = new StringBuilder(16);
-        sb.append("a"); sb.append((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-        sb.append("i"); sb.append((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK);
-        sb.append("t"); sb.append((off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK);
-        return sb.toString();
-    }
-
-    void setLong(int off, int index, long value) {
-        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-        longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)] = value;
-    }
-
-    long getLong(int off, int index) {
-        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-        return longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)];
-    }
-
-    static int binarySearch(int[] array, int size, int value) {
-        int lo = 0;
-        int hi = size - 1;
-
-        while (lo <= hi) {
-            int mid = (lo + hi) >>> 1;
-            int midVal = (array[mid] >> OFFSET_TYPE_SHIFT) & OFFSET_TYPE_MASK;
-
-            if (midVal < value) {
-                lo = mid + 1;
-            } else if (midVal > value) {
-                hi = mid - 1;
-            } else {
-                return mid;  // value found
-            }
-        }
-        return ~lo;  // value not present
-    }
-
-    public PackageState getPackageStateLocked(String packageName, int uid, int vers) {
-        SparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
-        if (vpkg == null) {
-            vpkg = new SparseArray<PackageState>();
-            mPackages.put(packageName, uid, vpkg);
-        }
-        PackageState as = vpkg.get(vers);
-        if (as != null) {
-            return as;
-        }
-        as = new PackageState(packageName, uid);
-        vpkg.put(vers, as);
-        return as;
-    }
-
-    public ProcessState getProcessStateLocked(String packageName, int uid, int vers,
-            String processName) {
-        final PackageState pkgState = getPackageStateLocked(packageName, uid, vers);
-        ProcessState ps = pkgState.mProcesses.get(processName);
-        if (ps != null) {
-            return ps;
-        }
-        ProcessState commonProc = mProcesses.get(processName, uid);
-        if (commonProc == null) {
-            commonProc = new ProcessState(this, packageName, uid, vers, processName);
-            mProcesses.put(processName, uid, commonProc);
-            if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc);
-        }
-        if (!commonProc.mMultiPackage) {
-            if (packageName.equals(commonProc.mPackage) && vers == commonProc.mVersion) {
-                // This common process is not in use by multiple packages, and
-                // is for the calling package, so we can just use it directly.
-                ps = commonProc;
-                if (DEBUG) Slog.d(TAG, "GETPROC also using for pkg " + commonProc);
-            } else {
-                if (DEBUG) Slog.d(TAG, "GETPROC need to split common proc!");
-                // This common process has not been in use by multiple packages,
-                // but it was created for a different package than the caller.
-                // We need to convert it to a multi-package process.
-                commonProc.mMultiPackage = true;
-                // To do this, we need to make two new process states, one a copy
-                // of the current state for the process under the original package
-                // name, and the second a free new process state for it as the
-                // new package name.
-                long now = SystemClock.uptimeMillis();
-                // First let's make a copy of the current process state and put
-                // that under the now unique state for its original package name.
-                final PackageState commonPkgState = getPackageStateLocked(commonProc.mPackage,
-                        uid, commonProc.mVersion);
-                if (commonPkgState != null) {
-                    ProcessState cloned = commonProc.clone(commonProc.mPackage, now);
-                    if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.mPackage
-                            + ": " + cloned);
-                    commonPkgState.mProcesses.put(commonProc.mName, cloned);
-                    // If this has active services, we need to update their process pointer
-                    // to point to the new package-specific process state.
-                    for (int i=commonPkgState.mServices.size()-1; i>=0; i--) {
-                        ServiceState ss = commonPkgState.mServices.valueAt(i);
-                        if (ss.mProc == commonProc) {
-                            if (DEBUG) Slog.d(TAG, "GETPROC switching service to cloned: "
-                                    + ss);
-                            ss.mProc = cloned;
-                        } else if (DEBUG) {
-                            Slog.d(TAG, "GETPROC leaving proc of " + ss);
-                        }
-                    }
-                } else {
-                    Slog.w(TAG, "Cloning proc state: no package state " + commonProc.mPackage
-                            + "/" + uid + " for proc " + commonProc.mName);
-                }
-                // And now make a fresh new process state for the new package name.
-                ps = new ProcessState(commonProc, packageName, uid, vers, processName, now);
-                if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
-            }
-        } else {
-            // The common process is for multiple packages, we need to create a
-            // separate object for the per-package data.
-            ps = new ProcessState(commonProc, packageName, uid, vers, processName,
-                    SystemClock.uptimeMillis());
-            if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
-        }
-        pkgState.mProcesses.put(processName, ps);
-        if (DEBUG) Slog.d(TAG, "GETPROC adding new pkg " + ps);
-        return ps;
-    }
-
-    public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid, int vers,
-            String processName, String className) {
-        final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid, vers);
-        ProcessStats.ServiceState ss = as.mServices.get(className);
-        if (ss != null) {
-            if (DEBUG) Slog.d(TAG, "GETSVC: returning existing " + ss);
-            return ss;
-        }
-        final ProcessStats.ProcessState ps = processName != null
-                ? getProcessStateLocked(packageName, uid, vers, processName) : null;
-        ss = new ProcessStats.ServiceState(this, packageName, className, processName, ps);
-        as.mServices.put(className, ss);
-        if (DEBUG) Slog.d(TAG, "GETSVC: creating " + ss + " in " + ps);
-        return ss;
-    }
-
-    private void dumpProcessInternalLocked(PrintWriter pw, String prefix, ProcessState proc,
-            boolean dumpAll) {
-        if (dumpAll) {
-            pw.print(prefix); pw.print("myID=");
-                    pw.print(Integer.toHexString(System.identityHashCode(proc)));
-                    pw.print(" mCommonProcess=");
-                    pw.print(Integer.toHexString(System.identityHashCode(proc.mCommonProcess)));
-                    pw.print(" mPackage="); pw.println(proc.mPackage);
-            if (proc.mMultiPackage) {
-                pw.print(prefix); pw.print("mMultiPackage="); pw.println(proc.mMultiPackage);
-            }
-            if (proc != proc.mCommonProcess) {
-                pw.print(prefix); pw.print("Common Proc: "); pw.print(proc.mCommonProcess.mName);
-                        pw.print("/"); pw.print(proc.mCommonProcess.mUid);
-                        pw.print(" pkg="); pw.println(proc.mCommonProcess.mPackage);
-            }
-        }
-        if (proc.mActive) {
-            pw.print(prefix); pw.print("mActive="); pw.println(proc.mActive);
-        }
-        if (proc.mDead) {
-            pw.print(prefix); pw.print("mDead="); pw.println(proc.mDead);
-        }
-        if (proc.mNumActiveServices != 0 || proc.mNumStartedServices != 0) {
-            pw.print(prefix); pw.print("mNumActiveServices="); pw.print(proc.mNumActiveServices);
-                    pw.print(" mNumStartedServices=");
-                    pw.println(proc.mNumStartedServices);
-        }
-    }
-
-    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
-            boolean dumpAll, boolean activeOnly) {
-        long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
-                mStartTime, now);
-        boolean sepNeeded = false;
-        if (mSysMemUsageTable != null) {
-            pw.println("System memory usage:");
-            dumpSysMemUsage(pw, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
-            sepNeeded = true;
-        }
-        ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
-        boolean printedHeader = false;
-        for (int ip=0; ip<pkgMap.size(); ip++) {
-            final String pkgName = pkgMap.keyAt(ip);
-            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final int uid = uids.keyAt(iu);
-                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
-                for (int iv=0; iv<vpkgs.size(); iv++) {
-                    final int vers = vpkgs.keyAt(iv);
-                    final PackageState pkgState = vpkgs.valueAt(iv);
-                    final int NPROCS = pkgState.mProcesses.size();
-                    final int NSRVS = pkgState.mServices.size();
-                    final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
-                    if (!pkgMatch) {
-                        boolean procMatch = false;
-                        for (int iproc=0; iproc<NPROCS; iproc++) {
-                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                            if (reqPackage.equals(proc.mName)) {
-                                procMatch = true;
-                                break;
-                            }
-                        }
-                        if (!procMatch) {
-                            continue;
-                        }
-                    }
-                    if (NPROCS > 0 || NSRVS > 0) {
-                        if (!printedHeader) {
-                            if (sepNeeded) pw.println();
-                            pw.println("Per-Package Stats:");
-                            printedHeader = true;
-                            sepNeeded = true;
-                        }
-                        pw.print("  * "); pw.print(pkgName); pw.print(" / ");
-                                UserHandle.formatUid(pw, uid); pw.print(" / v");
-                                pw.print(vers); pw.println(":");
-                    }
-                    if (!dumpSummary || dumpAll) {
-                        for (int iproc=0; iproc<NPROCS; iproc++) {
-                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                            if (!pkgMatch && !reqPackage.equals(proc.mName)) {
-                                continue;
-                            }
-                            if (activeOnly && !proc.isInUse()) {
-                                pw.print("      (Not active: ");
-                                        pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
-                                continue;
-                            }
-                            pw.print("      Process ");
-                            pw.print(pkgState.mProcesses.keyAt(iproc));
-                            if (proc.mCommonProcess.mMultiPackage) {
-                                pw.print(" (multi, ");
-                            } else {
-                                pw.print(" (unique, ");
-                            }
-                            pw.print(proc.mDurationsTableSize);
-                            pw.print(" entries)");
-                            pw.println(":");
-                            dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                                    ALL_PROC_STATES, now);
-                            dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                                    ALL_PROC_STATES);
-                            dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
-                        }
-                    } else {
-                        ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
-                        for (int iproc=0; iproc<NPROCS; iproc++) {
-                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                            if (!pkgMatch && !reqPackage.equals(proc.mName)) {
-                                continue;
-                            }
-                            if (activeOnly && !proc.isInUse()) {
-                                continue;
-                            }
-                            procs.add(proc);
-                        }
-                        dumpProcessSummaryLocked(pw, "      ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                                NON_CACHED_PROC_STATES, false, now, totalTime);
-                    }
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        ServiceState svc = pkgState.mServices.valueAt(isvc);
-                        if (!pkgMatch && !reqPackage.equals(svc.mProcessName)) {
-                            continue;
-                        }
-                        if (activeOnly && !svc.isInUse()) {
-                            pw.print("      (Not active: ");
-                                    pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
-                            continue;
-                        }
-                        if (dumpAll) {
-                            pw.print("      Service ");
-                        } else {
-                            pw.print("      * ");
-                        }
-                        pw.print(pkgState.mServices.keyAt(isvc));
-                        pw.println(":");
-                        pw.print("        Process: "); pw.println(svc.mProcessName);
-                        dumpServiceStats(pw, "        ", "          ", "    ", "Running", svc,
-                                svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
-                                svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
-                        dumpServiceStats(pw, "        ", "          ", "    ", "Started", svc,
-                                svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
-                                svc.mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
-                        dumpServiceStats(pw, "        ", "          ", "      ", "Bound", svc,
-                                svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
-                                svc.mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
-                        dumpServiceStats(pw, "        ", "          ", "  ", "Executing", svc,
-                                svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
-                                svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
-                        if (dumpAll) {
-                            if (svc.mOwner != null) {
-                                pw.print("        mOwner="); pw.println(svc.mOwner);
-                            }
-                            if (svc.mStarted || svc.mRestarting) {
-                                pw.print("        mStarted="); pw.print(svc.mStarted);
-                                pw.print(" mRestarting="); pw.println(svc.mRestarting);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        printedHeader = false;
-        int numShownProcs = 0, numTotalProcs = 0;
-        for (int ip=0; ip<procMap.size(); ip++) {
-            String procName = procMap.keyAt(ip);
-            SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                int uid = uids.keyAt(iu);
-                numTotalProcs++;
-                ProcessState proc = uids.valueAt(iu);
-                if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
-                        && proc.mPssTableSize == 0) {
-                    continue;
-                }
-                if (!proc.mMultiPackage) {
-                    continue;
-                }
-                if (reqPackage != null && !reqPackage.equals(procName)
-                        && !reqPackage.equals(proc.mPackage)) {
-                    continue;
-                }
-                numShownProcs++;
-                if (sepNeeded) {
-                    pw.println();
-                }
-                sepNeeded = true;
-                if (!printedHeader) {
-                    pw.println("Multi-Package Common Processes:");
-                    printedHeader = true;
-                }
-                if (activeOnly && !proc.isInUse()) {
-                    pw.print("      (Not active: "); pw.print(procName); pw.println(")");
-                    continue;
-                }
-                pw.print("  * "); pw.print(procName); pw.print(" / ");
-                        UserHandle.formatUid(pw, uid);
-                        pw.print(" ("); pw.print(proc.mDurationsTableSize);
-                        pw.print(" entries)"); pw.println(":");
-                dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                        ALL_PROC_STATES, now);
-                dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                        ALL_PROC_STATES);
-                dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
-            }
-        }
-        if (dumpAll) {
-            pw.println();
-            pw.print("  Total procs: "); pw.print(numShownProcs);
-                    pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
-        }
-
-        if (sepNeeded) {
-            pw.println();
-        }
-        if (dumpSummary) {
-            pw.println("Summary:");
-            dumpSummaryLocked(pw, reqPackage, now, activeOnly);
-        } else {
-            dumpTotalsLocked(pw, now);
-        }
-
-        if (dumpAll) {
-            pw.println();
-            pw.println("Internal state:");
-            pw.print("  Num long arrays: "); pw.println(mLongs.size());
-            pw.print("  Next long entry: "); pw.println(mNextLong);
-            pw.print("  mRunning="); pw.println(mRunning);
-        }
-    }
-
-    public static long dumpSingleServiceTime(PrintWriter pw, String prefix, ServiceState service,
-            int serviceType, int curState, long curStartTime, long now) {
-        long totalTime = 0;
-        int printedScreen = -1;
-        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
-            int printedMem = -1;
-            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
-                int state = imem+iscreen;
-                long time = service.getDuration(serviceType, curState, curStartTime,
-                        state, now);
-                String running = "";
-                if (curState == state && pw != null) {
-                    running = " (running)";
-                }
-                if (time != 0) {
-                    if (pw != null) {
-                        pw.print(prefix);
-                        printScreenLabel(pw, printedScreen != iscreen
-                                ? iscreen : STATE_NOTHING);
-                        printedScreen = iscreen;
-                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
-                        printedMem = imem;
-                        pw.print(": ");
-                        TimeUtils.formatDuration(time, pw); pw.println(running);
-                    }
-                    totalTime += time;
-                }
-            }
-        }
-        if (totalTime != 0 && pw != null) {
-            pw.print(prefix);
-            pw.print("    TOTAL: ");
-            TimeUtils.formatDuration(totalTime, pw);
-            pw.println();
-        }
-        return totalTime;
-    }
-
-    void dumpServiceStats(PrintWriter pw, String prefix, String prefixInner,
-            String headerPrefix, String header, ServiceState service,
-            int count, int serviceType, int state, long startTime, long now, long totalTime,
-            boolean dumpAll) {
-        if (count != 0) {
-            if (dumpAll) {
-                pw.print(prefix); pw.print(header);
-                pw.print(" op count "); pw.print(count); pw.println(":");
-                dumpSingleServiceTime(pw, prefixInner, service, serviceType, state, startTime,
-                        now);
-            } else {
-                long myTime = dumpSingleServiceTime(null, null, service, serviceType, state,
-                        startTime, now);
-                pw.print(prefix); pw.print(headerPrefix); pw.print(header);
-                pw.print(" count "); pw.print(count);
-                pw.print(" / time ");
-                printPercent(pw, (double)myTime/(double)totalTime);
-                pw.println();
-            }
-        }
-    }
-
-    public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) {
-        long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
-                mStartTime, now);
-        dumpFilteredSummaryLocked(pw, null, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly);
-        pw.println();
-        dumpTotalsLocked(pw, now);
-    }
-
-    long printMemoryCategory(PrintWriter pw, String prefix, String label, double memWeight,
-            long totalTime, long curTotalMem, int samples) {
-        if (memWeight != 0) {
-            long mem = (long)(memWeight * 1024 / totalTime);
-            pw.print(prefix);
-            pw.print(label);
-            pw.print(": ");
-            DebugUtils.printSizeValue(pw, mem);
-            pw.print(" (");
-            pw.print(samples);
-            pw.print(" samples)");
-            pw.println();
-            return curTotalMem + mem;
-        }
-        return curTotalMem;
-    }
-
-    void dumpTotalsLocked(PrintWriter pw, long now) {
-        pw.println("Run time Stats:");
-        dumpSingleTime(pw, "  ", mMemFactorDurations, mMemFactor, mStartTime, now);
-        pw.println();
-        pw.println("Memory usage:");
-        TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
-                ALL_MEM_ADJ);
-        computeTotalMemoryUse(totalMem, now);
-        long totalPss = 0;
-        totalPss = printMemoryCategory(pw, "  ", "Kernel ", totalMem.sysMemKernelWeight,
-                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
-        totalPss = printMemoryCategory(pw, "  ", "Native ", totalMem.sysMemNativeWeight,
-                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
-        for (int i=0; i<STATE_COUNT; i++) {
-            // Skip restarting service state -- that is not actually a running process.
-            if (i != STATE_SERVICE_RESTARTING) {
-                totalPss = printMemoryCategory(pw, "  ", STATE_NAMES[i],
-                        totalMem.processStateWeight[i], totalMem.totalTime, totalPss,
-                        totalMem.processStateSamples[i]);
-            }
-        }
-        totalPss = printMemoryCategory(pw, "  ", "Cached ", totalMem.sysMemCachedWeight,
-                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
-        totalPss = printMemoryCategory(pw, "  ", "Free   ", totalMem.sysMemFreeWeight,
-                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
-        totalPss = printMemoryCategory(pw, "  ", "Z-Ram  ", totalMem.sysMemZRamWeight,
-                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
-        pw.print("  TOTAL  : ");
-        DebugUtils.printSizeValue(pw, totalPss);
-        pw.println();
-        printMemoryCategory(pw, "  ", STATE_NAMES[STATE_SERVICE_RESTARTING],
-                totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
-                totalMem.processStateSamples[STATE_SERVICE_RESTARTING]);
-        pw.println();
-        pw.print("          Start time: ");
-        pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
-        pw.println();
-        pw.print("  Total elapsed time: ");
-        TimeUtils.formatDuration(
-                (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
-                        - mTimePeriodStartRealtime, pw);
-        boolean partial = true;
-        if ((mFlags&FLAG_SHUTDOWN) != 0) {
-            pw.print(" (shutdown)");
-            partial = false;
-        }
-        if ((mFlags&FLAG_SYSPROPS) != 0) {
-            pw.print(" (sysprops)");
-            partial = false;
-        }
-        if ((mFlags&FLAG_COMPLETE) != 0) {
-            pw.print(" (complete)");
-            partial = false;
-        }
-        if (partial) {
-            pw.print(" (partial)");
-        }
-        pw.print(' ');
-        pw.print(mRuntime);
-        pw.println();
-    }
-
-    void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
-            int[] screenStates, int[] memStates, int[] procStates,
-            int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) {
-        ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
-                procStates, sortProcStates, now, reqPackage, activeOnly);
-        if (procs.size() > 0) {
-            if (header != null) {
-                pw.println();
-                pw.println(header);
-            }
-            dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
-                    sortProcStates, true, now, totalTime);
-        }
-    }
-
-    public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
-            int[] procStates, int sortProcStates[], long now, String reqPackage,
-            boolean activeOnly) {
-        final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
-        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
-        for (int ip=0; ip<pkgMap.size(); ip++) {
-            final String pkgName = pkgMap.keyAt(ip);
-            final SparseArray<SparseArray<PackageState>> procs = pkgMap.valueAt(ip);
-            for (int iu=0; iu<procs.size(); iu++) {
-                final SparseArray<PackageState> vpkgs = procs.valueAt(iu);
-                final int NVERS = vpkgs.size();
-                for (int iv=0; iv<NVERS; iv++) {
-                    final PackageState state = vpkgs.valueAt(iv);
-                    final int NPROCS = state.mProcesses.size();
-                    final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
-                    for (int iproc=0; iproc<NPROCS; iproc++) {
-                        final ProcessState proc = state.mProcesses.valueAt(iproc);
-                        if (!pkgMatch && !reqPackage.equals(proc.mName)) {
-                            continue;
-                        }
-                        if (activeOnly && !proc.isInUse()) {
-                            continue;
-                        }
-                        foundProcs.add(proc.mCommonProcess);
-                    }
-                }
-            }
-        }
-        ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size());
-        for (int i=0; i<foundProcs.size(); i++) {
-            ProcessState proc = foundProcs.valueAt(i);
-            if (computeProcessTimeLocked(proc, screenStates, memStates, procStates, now) > 0) {
-                outProcs.add(proc);
-                if (procStates != sortProcStates) {
-                    computeProcessTimeLocked(proc, screenStates, memStates, sortProcStates, now);
-                }
-            }
-        }
-        Collections.sort(outProcs, new Comparator<ProcessState>() {
-            @Override
-            public int compare(ProcessState lhs, ProcessState rhs) {
-                if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
-                    return -1;
-                } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
-                    return 1;
-                }
-                return 0;
-            }
-        });
-        return outProcs;
-    }
-
-    String collapseString(String pkgName, String itemName) {
-        if (itemName.startsWith(pkgName)) {
-            final int ITEMLEN = itemName.length();
-            final int PKGLEN = pkgName.length();
-            if (ITEMLEN == PKGLEN) {
-                return "";
-            } else if (ITEMLEN >= PKGLEN) {
-                if (itemName.charAt(PKGLEN) == '.') {
-                    return itemName.substring(PKGLEN);
-                }
-            }
-        }
-        return itemName;
-    }
-
-    public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
-        final long now = SystemClock.uptimeMillis();
-        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
-        pw.println("vers,5");
-        pw.print("period,"); pw.print(mTimePeriodStartClockStr);
-        pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
-        pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
-        boolean partial = true;
-        if ((mFlags&FLAG_SHUTDOWN) != 0) {
-            pw.print(",shutdown");
-            partial = false;
-        }
-        if ((mFlags&FLAG_SYSPROPS) != 0) {
-            pw.print(",sysprops");
-            partial = false;
-        }
-        if ((mFlags&FLAG_COMPLETE) != 0) {
-            pw.print(",complete");
-            partial = false;
-        }
-        if (partial) {
-            pw.print(",partial");
-        }
-        pw.println();
-        pw.print("config,"); pw.println(mRuntime);
-        for (int ip=0; ip<pkgMap.size(); ip++) {
-            final String pkgName = pkgMap.keyAt(ip);
-            if (reqPackage != null && !reqPackage.equals(pkgName)) {
-                continue;
-            }
-            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final int uid = uids.keyAt(iu);
-                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
-                for (int iv=0; iv<vpkgs.size(); iv++) {
-                    final int vers = vpkgs.keyAt(iv);
-                    final PackageState pkgState = vpkgs.valueAt(iv);
-                    final int NPROCS = pkgState.mProcesses.size();
-                    final int NSRVS = pkgState.mServices.size();
-                    for (int iproc=0; iproc<NPROCS; iproc++) {
-                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                        pw.print("pkgproc,");
-                        pw.print(pkgName);
-                        pw.print(",");
-                        pw.print(uid);
-                        pw.print(",");
-                        pw.print(vers);
-                        pw.print(",");
-                        pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
-                        dumpAllProcessStateCheckin(pw, proc, now);
-                        pw.println();
-                        if (proc.mPssTableSize > 0) {
-                            pw.print("pkgpss,");
-                            pw.print(pkgName);
-                            pw.print(",");
-                            pw.print(uid);
-                            pw.print(",");
-                            pw.print(vers);
-                            pw.print(",");
-                            pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
-                            dumpAllProcessPssCheckin(pw, proc);
-                            pw.println();
-                        }
-                        if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0
-                                || proc.mNumCachedKill > 0) {
-                            pw.print("pkgkills,");
-                            pw.print(pkgName);
-                            pw.print(",");
-                            pw.print(uid);
-                            pw.print(",");
-                            pw.print(vers);
-                            pw.print(",");
-                            pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
-                            pw.print(",");
-                            pw.print(proc.mNumExcessiveWake);
-                            pw.print(",");
-                            pw.print(proc.mNumExcessiveCpu);
-                            pw.print(",");
-                            pw.print(proc.mNumCachedKill);
-                            pw.print(",");
-                            pw.print(proc.mMinCachedKillPss);
-                            pw.print(":");
-                            pw.print(proc.mAvgCachedKillPss);
-                            pw.print(":");
-                            pw.print(proc.mMaxCachedKillPss);
-                            pw.println();
-                        }
-                    }
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        String serviceName = collapseString(pkgName,
-                                pkgState.mServices.keyAt(isvc));
-                        ServiceState svc = pkgState.mServices.valueAt(isvc);
-                        dumpServiceTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName,
-                                svc, ServiceState.SERVICE_RUN, svc.mRunCount,
-                                svc.mRunState, svc.mRunStartTime, now);
-                        dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName,
-                                svc, ServiceState.SERVICE_STARTED, svc.mStartedCount,
-                                svc.mStartedState, svc.mStartedStartTime, now);
-                        dumpServiceTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName,
-                                svc, ServiceState.SERVICE_BOUND, svc.mBoundCount,
-                                svc.mBoundState, svc.mBoundStartTime, now);
-                        dumpServiceTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName,
-                                svc, ServiceState.SERVICE_EXEC, svc.mExecCount,
-                                svc.mExecState, svc.mExecStartTime, now);
-                    }
-                }
-            }
-        }
-
-        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        for (int ip=0; ip<procMap.size(); ip++) {
-            String procName = procMap.keyAt(ip);
-            SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                int uid = uids.keyAt(iu);
-                ProcessState procState = uids.valueAt(iu);
-                if (procState.mDurationsTableSize > 0) {
-                    pw.print("proc,");
-                    pw.print(procName);
-                    pw.print(",");
-                    pw.print(uid);
-                    dumpAllProcessStateCheckin(pw, procState, now);
-                    pw.println();
-                }
-                if (procState.mPssTableSize > 0) {
-                    pw.print("pss,");
-                    pw.print(procName);
-                    pw.print(",");
-                    pw.print(uid);
-                    dumpAllProcessPssCheckin(pw, procState);
-                    pw.println();
-                }
-                if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0
-                        || procState.mNumCachedKill > 0) {
-                    pw.print("kills,");
-                    pw.print(procName);
-                    pw.print(",");
-                    pw.print(uid);
-                    pw.print(",");
-                    pw.print(procState.mNumExcessiveWake);
-                    pw.print(",");
-                    pw.print(procState.mNumExcessiveCpu);
-                    pw.print(",");
-                    pw.print(procState.mNumCachedKill);
-                    pw.print(",");
-                    pw.print(procState.mMinCachedKillPss);
-                    pw.print(":");
-                    pw.print(procState.mAvgCachedKillPss);
-                    pw.print(":");
-                    pw.print(procState.mMaxCachedKillPss);
-                    pw.println();
-                }
-            }
-        }
-        pw.print("total");
-        dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
-                mStartTime, now);
-        pw.println();
-        if (mSysMemUsageTable != null) {
-            pw.print("sysmemusage");
-            for (int i=0; i<mSysMemUsageTableSize; i++) {
-                int off = mSysMemUsageTable[i];
-                int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                pw.print(",");
-                printProcStateTag(pw, type);
-                for (int j=SYS_MEM_USAGE_SAMPLE_COUNT; j<SYS_MEM_USAGE_COUNT; j++) {
-                    if (j > SYS_MEM_USAGE_CACHED_MINIMUM) {
-                        pw.print(":");
-                    }
-                    pw.print(getLong(off, j));
-                }
-            }
-        }
-        pw.println();
-        TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
-                ALL_MEM_ADJ);
-        computeTotalMemoryUse(totalMem, now);
-        pw.print("weights,");
-        pw.print(totalMem.totalTime);
-        pw.print(",");
-        pw.print(totalMem.sysMemCachedWeight);
-        pw.print(":");
-        pw.print(totalMem.sysMemSamples);
-        pw.print(",");
-        pw.print(totalMem.sysMemFreeWeight);
-        pw.print(":");
-        pw.print(totalMem.sysMemSamples);
-        pw.print(",");
-        pw.print(totalMem.sysMemZRamWeight);
-        pw.print(":");
-        pw.print(totalMem.sysMemSamples);
-        pw.print(",");
-        pw.print(totalMem.sysMemKernelWeight);
-        pw.print(":");
-        pw.print(totalMem.sysMemSamples);
-        pw.print(",");
-        pw.print(totalMem.sysMemNativeWeight);
-        pw.print(":");
-        pw.print(totalMem.sysMemSamples);
-        for (int i=0; i<STATE_COUNT; i++) {
-            pw.print(",");
-            pw.print(totalMem.processStateWeight[i]);
-            pw.print(":");
-            pw.print(totalMem.processStateSamples[i]);
-        }
-        pw.println();
-    }
-
-    public static class DurationsTable {
-        public final ProcessStats mStats;
-        public final String mName;
-        public int[] mDurationsTable;
-        public int mDurationsTableSize;
-
-        public DurationsTable(ProcessStats stats, String name) {
-            mStats = stats;
-            mName = name;
-        }
-
-        void copyDurationsTo(DurationsTable other) {
-            if (mDurationsTable != null) {
-                mStats.mAddLongTable = new int[mDurationsTable.length];
-                mStats.mAddLongTableSize = 0;
-                for (int i=0; i<mDurationsTableSize; i++) {
-                    int origEnt = mDurationsTable[i];
-                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                    int newOff = mStats.addLongData(i, type, 1);
-                    mStats.mAddLongTable[i] = newOff | type;
-                    mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
-                }
-                other.mDurationsTable = mStats.mAddLongTable;
-                other.mDurationsTableSize = mStats.mAddLongTableSize;
-            } else {
-                other.mDurationsTable = null;
-                other.mDurationsTableSize = 0;
-            }
-        }
-
-        void addDurations(DurationsTable other) {
-            for (int i=0; i<other.mDurationsTableSize; i++) {
-                int ent = other.mDurationsTable[i];
-                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
-                        + other.mStats.getLong(ent, 0));
-                addDuration(state, other.mStats.getLong(ent, 0));
-            }
-        }
-
-        void resetDurationsSafely() {
-            mDurationsTable = null;
-            mDurationsTableSize = 0;
-        }
-
-        void writeDurationsToParcel(Parcel out) {
-            out.writeInt(mDurationsTableSize);
-            for (int i=0; i<mDurationsTableSize; i++) {
-                if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
-                        + printLongOffset(mDurationsTable[i]));
-                out.writeInt(mDurationsTable[i]);
-            }
-        }
-
-        boolean readDurationsFromParcel(Parcel in) {
-            mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
-            if (mDurationsTable == BAD_TABLE) {
-                return false;
-            }
-            mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
-            return true;
-        }
-
-        void addDuration(int state, long dur) {
-            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
-            int off;
-            if (idx >= 0) {
-                off = mDurationsTable[idx];
-            } else {
-                mStats.mAddLongTable = mDurationsTable;
-                mStats.mAddLongTableSize = mDurationsTableSize;
-                off = mStats.addLongData(~idx, state, 1);
-                mDurationsTable = mStats.mAddLongTable;
-                mDurationsTableSize = mStats.mAddLongTableSize;
-            }
-            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-            if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
-                    + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
-            longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
-        }
-
-        long getDuration(int state, long now) {
-            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
-            return idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
-        }
-    }
-
-    final public static class ProcessStateHolder {
-        public final int appVersion;
-        public ProcessStats.ProcessState state;
-
-        public ProcessStateHolder(int _appVersion) {
-            appVersion = _appVersion;
-        }
-    }
-
-    public static final class ProcessState extends DurationsTable {
-        public ProcessState mCommonProcess;
-        public final String mPackage;
-        public final int mUid;
-        public final int mVersion;
-
-        //final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
-        int mCurState = STATE_NOTHING;
-        long mStartTime;
-
-        int mLastPssState = STATE_NOTHING;
-        long mLastPssTime;
-        int[] mPssTable;
-        int mPssTableSize;
-
-        boolean mActive;
-        int mNumActiveServices;
-        int mNumStartedServices;
-
-        int mNumExcessiveWake;
-        int mNumExcessiveCpu;
-
-        int mNumCachedKill;
-        long mMinCachedKillPss;
-        long mAvgCachedKillPss;
-        long mMaxCachedKillPss;
-
-        boolean mMultiPackage;
-        boolean mDead;
-
-        public long mTmpTotalTime;
-        int mTmpNumInUse;
-        ProcessState mTmpFoundSubProc;
-
-        /**
-         * Create a new top-level process state, for the initial case where there is only
-         * a single package running in a process.  The initial state is not running.
-         */
-        public ProcessState(ProcessStats processStats, String pkg, int uid, int vers, String name) {
-            super(processStats, name);
-            mCommonProcess = this;
-            mPackage = pkg;
-            mUid = uid;
-            mVersion = vers;
-        }
-
-        /**
-         * Create a new per-package process state for an existing top-level process
-         * state.  The current running state of the top-level process is also copied,
-         * marked as started running at 'now'.
-         */
-        public ProcessState(ProcessState commonProcess, String pkg, int uid, int vers, String name,
-                long now) {
-            super(commonProcess.mStats, name);
-            mCommonProcess = commonProcess;
-            mPackage = pkg;
-            mUid = uid;
-            mVersion = vers;
-            mCurState = commonProcess.mCurState;
-            mStartTime = now;
-        }
-
-        ProcessState clone(String pkg, long now) {
-            ProcessState pnew = new ProcessState(this, pkg, mUid, mVersion, mName, now);
-            copyDurationsTo(pnew);
-            if (mPssTable != null) {
-                mStats.mAddLongTable = new int[mPssTable.length];
-                mStats.mAddLongTableSize = 0;
-                for (int i=0; i<mPssTableSize; i++) {
-                    int origEnt = mPssTable[i];
-                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                    int newOff = mStats.addLongData(i, type, PSS_COUNT);
-                    mStats.mAddLongTable[i] = newOff | type;
-                    for (int j=0; j<PSS_COUNT; j++) {
-                        mStats.setLong(newOff, j, mStats.getLong(origEnt, j));
-                    }
-                }
-                pnew.mPssTable = mStats.mAddLongTable;
-                pnew.mPssTableSize = mStats.mAddLongTableSize;
-            }
-            pnew.mNumExcessiveWake = mNumExcessiveWake;
-            pnew.mNumExcessiveCpu = mNumExcessiveCpu;
-            pnew.mNumCachedKill = mNumCachedKill;
-            pnew.mMinCachedKillPss = mMinCachedKillPss;
-            pnew.mAvgCachedKillPss = mAvgCachedKillPss;
-            pnew.mMaxCachedKillPss = mMaxCachedKillPss;
-            pnew.mActive = mActive;
-            pnew.mNumActiveServices = mNumActiveServices;
-            pnew.mNumStartedServices = mNumStartedServices;
-            return pnew;
-        }
-
-        void add(ProcessState other) {
-            addDurations(other);
-            for (int i=0; i<other.mPssTableSize; i++) {
-                int ent = other.mPssTable[i];
-                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                addPss(state, (int) other.mStats.getLong(ent, PSS_SAMPLE_COUNT),
-                        other.mStats.getLong(ent, PSS_MINIMUM),
-                        other.mStats.getLong(ent, PSS_AVERAGE),
-                        other.mStats.getLong(ent, PSS_MAXIMUM),
-                        other.mStats.getLong(ent, PSS_USS_MINIMUM),
-                        other.mStats.getLong(ent, PSS_USS_AVERAGE),
-                        other.mStats.getLong(ent, PSS_USS_MAXIMUM));
-            }
-            mNumExcessiveWake += other.mNumExcessiveWake;
-            mNumExcessiveCpu += other.mNumExcessiveCpu;
-            if (other.mNumCachedKill > 0) {
-                addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
-                        other.mAvgCachedKillPss, other.mMaxCachedKillPss);
-            }
-        }
-
-        void resetSafely(long now) {
-            resetDurationsSafely();
-            mStartTime = now;
-            mLastPssState = STATE_NOTHING;
-            mLastPssTime = 0;
-            mPssTable = null;
-            mPssTableSize = 0;
-            mNumExcessiveWake = 0;
-            mNumExcessiveCpu = 0;
-            mNumCachedKill = 0;
-            mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
-        }
-
-        void makeDead() {
-            mDead = true;
-        }
-
-        private void ensureNotDead() {
-            if (!mDead) {
-                return;
-            }
-            Slog.wtfStack(TAG, "ProcessState dead: name=" + mName
-                    + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
-        }
-
-        void writeToParcel(Parcel out, long now) {
-            out.writeInt(mMultiPackage ? 1 : 0);
-            writeDurationsToParcel(out);
-            out.writeInt(mPssTableSize);
-            for (int i=0; i<mPssTableSize; i++) {
-                if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
-                        + printLongOffset(mPssTable[i]));
-                out.writeInt(mPssTable[i]);
-            }
-            out.writeInt(mNumExcessiveWake);
-            out.writeInt(mNumExcessiveCpu);
-            out.writeInt(mNumCachedKill);
-            if (mNumCachedKill > 0) {
-                out.writeLong(mMinCachedKillPss);
-                out.writeLong(mAvgCachedKillPss);
-                out.writeLong(mMaxCachedKillPss);
-            }
-        }
-
-        boolean readFromParcel(Parcel in, boolean fully) {
-            boolean multiPackage = in.readInt() != 0;
-            if (fully) {
-                mMultiPackage = multiPackage;
-            }
-            if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
-            if (!readDurationsFromParcel(in)) {
-                return false;
-            }
-            if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
-            mPssTable = mStats.readTableFromParcel(in, mName, "pss");
-            if (mPssTable == BAD_TABLE) {
-                return false;
-            }
-            mPssTableSize = mPssTable != null ? mPssTable.length : 0;
-            mNumExcessiveWake = in.readInt();
-            mNumExcessiveCpu = in.readInt();
-            mNumCachedKill = in.readInt();
-            if (mNumCachedKill > 0) {
-                mMinCachedKillPss = in.readLong();
-                mAvgCachedKillPss = in.readLong();
-                mMaxCachedKillPss = in.readLong();
-            } else {
-                mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
-            }
-            return true;
-        }
-
-        public void makeActive() {
-            ensureNotDead();
-            mActive = true;
-        }
-
-        public void makeInactive() {
-            mActive = false;
-        }
-
-        public boolean isInUse() {
-            return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
-                    || mCurState != STATE_NOTHING;
-        }
-
-        /**
-         * Update the current state of the given list of processes.
-         *
-         * @param state Current ActivityManager.PROCESS_STATE_*
-         * @param memFactor Current mem factor constant.
-         * @param now Current time.
-         * @param pkgList Processes to update.
-         */
-        public void setState(int state, int memFactor, long now,
-                ArrayMap<String, ProcessStateHolder> pkgList) {
-            if (state < 0) {
-                state = mNumStartedServices > 0
-                        ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
-            } else {
-                state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
-            }
-
-            // First update the common process.
-            mCommonProcess.setState(state, now);
-
-            // If the common process is not multi-package, there is nothing else to do.
-            if (!mCommonProcess.mMultiPackage) {
-                return;
-            }
-
-            if (pkgList != null) {
-                for (int ip=pkgList.size()-1; ip>=0; ip--) {
-                    pullFixedProc(pkgList, ip).setState(state, now);
-                }
-            }
-        }
-
-        void setState(int state, long now) {
-            ensureNotDead();
-            if (mCurState != state) {
-                //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
-                commitStateTime(now);
-                mCurState = state;
-            }
-        }
-
-        void commitStateTime(long now) {
-            if (mCurState != STATE_NOTHING) {
-                long dur = now - mStartTime;
-                if (dur > 0) {
-                    addDuration(mCurState, dur);
-                }
-            }
-            mStartTime = now;
-        }
-
-        void incActiveServices(String serviceName) {
-            if (DEBUG && "".equals(mName)) {
-                RuntimeException here = new RuntimeException("here");
-                here.fillInStackTrace();
-                Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
-                        + " to " + (mNumActiveServices+1), here);
-            }
-            if (mCommonProcess != this) {
-                mCommonProcess.incActiveServices(serviceName);
-            }
-            mNumActiveServices++;
-        }
-
-        void decActiveServices(String serviceName) {
-            if (DEBUG && "".equals(mName)) {
-                RuntimeException here = new RuntimeException("here");
-                here.fillInStackTrace();
-                Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
-                        + " to " + (mNumActiveServices-1), here);
-            }
-            if (mCommonProcess != this) {
-                mCommonProcess.decActiveServices(serviceName);
-            }
-            mNumActiveServices--;
-            if (mNumActiveServices < 0) {
-                Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
-                        + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
-                mNumActiveServices = 0;
-            }
-        }
-
-        void incStartedServices(int memFactor, long now, String serviceName) {
-            if (false) {
-                RuntimeException here = new RuntimeException("here");
-                here.fillInStackTrace();
-                Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
-                        + " to " + (mNumStartedServices+1), here);
-            }
-            if (mCommonProcess != this) {
-                mCommonProcess.incStartedServices(memFactor, now, serviceName);
-            }
-            mNumStartedServices++;
-            if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
-                setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
-            }
-        }
-
-        void decStartedServices(int memFactor, long now, String serviceName) {
-            if (false) {
-                RuntimeException here = new RuntimeException("here");
-                here.fillInStackTrace();
-                Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
-                        + " to " + (mNumStartedServices-1), here);
-            }
-            if (mCommonProcess != this) {
-                mCommonProcess.decStartedServices(memFactor, now, serviceName);
-            }
-            mNumStartedServices--;
-            if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
-                setState(STATE_NOTHING, now);
-            } else if (mNumStartedServices < 0) {
-                Slog.wtfStack(TAG, "Proc started services underrun: pkg="
-                        + mPackage + " uid=" + mUid + " name=" + mName);
-                mNumStartedServices = 0;
-            }
-        }
-
-        public void addPss(long pss, long uss, boolean always,
-                ArrayMap<String, ProcessStateHolder> pkgList) {
-            ensureNotDead();
-            if (!always) {
-                if (mLastPssState == mCurState && SystemClock.uptimeMillis()
-                        < (mLastPssTime+(30*1000))) {
-                    return;
-                }
-            }
-            mLastPssState = mCurState;
-            mLastPssTime = SystemClock.uptimeMillis();
-            if (mCurState != STATE_NOTHING) {
-                // First update the common process.
-                mCommonProcess.addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
-
-                // If the common process is not multi-package, there is nothing else to do.
-                if (!mCommonProcess.mMultiPackage) {
-                    return;
-                }
-
-                if (pkgList != null) {
-                    for (int ip=pkgList.size()-1; ip>=0; ip--) {
-                        pullFixedProc(pkgList, ip).addPss(mCurState, 1,
-                                pss, pss, pss, uss, uss, uss);
-                    }
-                }
-            }
-        }
-
-        void addPss(int state, int inCount, long minPss, long avgPss, long maxPss, long minUss,
-                long avgUss, long maxUss) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            int off;
-            if (idx >= 0) {
-                off = mPssTable[idx];
-            } else {
-                mStats.mAddLongTable = mPssTable;
-                mStats.mAddLongTableSize = mPssTableSize;
-                off = mStats.addLongData(~idx, state, PSS_COUNT);
-                mPssTable = mStats.mAddLongTable;
-                mPssTableSize = mStats.mAddLongTableSize;
-            }
-            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-            idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
-            long count = longs[idx+PSS_SAMPLE_COUNT];
-            if (count == 0) {
-                longs[idx+PSS_SAMPLE_COUNT] = inCount;
-                longs[idx+PSS_MINIMUM] = minPss;
-                longs[idx+PSS_AVERAGE] = avgPss;
-                longs[idx+PSS_MAXIMUM] = maxPss;
-                longs[idx+PSS_USS_MINIMUM] = minUss;
-                longs[idx+PSS_USS_AVERAGE] = avgUss;
-                longs[idx+PSS_USS_MAXIMUM] = maxUss;
-            } else {
-                longs[idx+PSS_SAMPLE_COUNT] = count+inCount;
-                if (longs[idx+PSS_MINIMUM] > minPss) {
-                    longs[idx+PSS_MINIMUM] = minPss;
-                }
-                longs[idx+PSS_AVERAGE] = (long)(
-                        ((longs[idx+PSS_AVERAGE]*(double)count)+(avgPss*(double)inCount))
-                                / (count+inCount) );
-                if (longs[idx+PSS_MAXIMUM] < maxPss) {
-                    longs[idx+PSS_MAXIMUM] = maxPss;
-                }
-                if (longs[idx+PSS_USS_MINIMUM] > minUss) {
-                    longs[idx+PSS_USS_MINIMUM] = minUss;
-                }
-                longs[idx+PSS_USS_AVERAGE] = (long)(
-                        ((longs[idx+PSS_USS_AVERAGE]*(double)count)+(avgUss*(double)inCount))
-                                / (count+inCount) );
-                if (longs[idx+PSS_USS_MAXIMUM] < maxUss) {
-                    longs[idx+PSS_USS_MAXIMUM] = maxUss;
-                }
-            }
-        }
-
-        public void reportExcessiveWake(ArrayMap<String, ProcessStateHolder> pkgList) {
-            ensureNotDead();
-            mCommonProcess.mNumExcessiveWake++;
-            if (!mCommonProcess.mMultiPackage) {
-                return;
-            }
-
-            for (int ip=pkgList.size()-1; ip>=0; ip--) {
-                pullFixedProc(pkgList, ip).mNumExcessiveWake++;
-            }
-        }
-
-        public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
-            ensureNotDead();
-            mCommonProcess.mNumExcessiveCpu++;
-            if (!mCommonProcess.mMultiPackage) {
-                return;
-            }
-
-            for (int ip=pkgList.size()-1; ip>=0; ip--) {
-                pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
-            }
-        }
-
-        private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
-            if (mNumCachedKill <= 0) {
-                mNumCachedKill = num;
-                mMinCachedKillPss = minPss;
-                mAvgCachedKillPss = avgPss;
-                mMaxCachedKillPss = maxPss;
-            } else {
-                if (minPss < mMinCachedKillPss) {
-                    mMinCachedKillPss = minPss;
-                }
-                if (maxPss > mMaxCachedKillPss) {
-                    mMaxCachedKillPss = maxPss;
-                }
-                mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
-                        / (mNumCachedKill+num) );
-                mNumCachedKill += num;
-            }
-        }
-
-        public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
-            ensureNotDead();
-            mCommonProcess.addCachedKill(1, pss, pss, pss);
-            if (!mCommonProcess.mMultiPackage) {
-                return;
-            }
-
-            for (int ip=pkgList.size()-1; ip>=0; ip--) {
-                pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
-            }
-        }
-
-        ProcessState pullFixedProc(String pkgName) {
-            if (mMultiPackage) {
-                // The array map is still pointing to a common process state
-                // that is now shared across packages.  Update it to point to
-                // the new per-package state.
-                SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
-                if (vpkg == null) {
-                    throw new IllegalStateException("Didn't find package " + pkgName
-                            + " / " + mUid);
-                }
-                PackageState pkg = vpkg.get(mVersion);
-                if (pkg == null) {
-                    throw new IllegalStateException("Didn't find package " + pkgName
-                            + " / " + mUid + " vers " + mVersion);
-                }
-                ProcessState proc = pkg.mProcesses.get(mName);
-                if (proc == null) {
-                    throw new IllegalStateException("Didn't create per-package process "
-                            + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
-                }
-                return proc;
-            }
-            return this;
-        }
-
-        private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
-                int index) {
-            ProcessStateHolder holder = pkgList.valueAt(index);
-            ProcessState proc = holder.state;
-            if (mDead && proc.mCommonProcess != proc) {
-                // Somehow we are contining to use a process state that is dead, because
-                // it was not being told it was active during the last commit.  We can recover
-                // from this by generating a fresh new state, but this is bad because we
-                // are losing whatever data we had in the old process state.
-                Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
-                        + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
-                proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
-                        proc.mName);
-            }
-            if (proc.mMultiPackage) {
-                // The array map is still pointing to a common process state
-                // that is now shared across packages.  Update it to point to
-                // the new per-package state.
-                SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
-                        proc.mUid);
-                if (vpkg == null) {
-                    throw new IllegalStateException("No existing package "
-                            + pkgList.keyAt(index) + "/" + proc.mUid
-                            + " for multi-proc " + proc.mName);
-                }
-                PackageState pkg = vpkg.get(proc.mVersion);
-                if (pkg == null) {
-                    throw new IllegalStateException("No existing package "
-                            + pkgList.keyAt(index) + "/" + proc.mUid
-                            + " for multi-proc " + proc.mName + " version " + proc.mVersion);
-                }
-                String savedName = proc.mName;
-                proc = pkg.mProcesses.get(proc.mName);
-                if (proc == null) {
-                    throw new IllegalStateException("Didn't create per-package process "
-                            + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
-                }
-                holder.state = proc;
-            }
-            return proc;
-        }
-
-        long getDuration(int state, long now) {
-            long time = super.getDuration(state, now);
-            if (mCurState == state) {
-                time += now - mStartTime;
-            }
-            return time;
-        }
-
-        long getPssSampleCount(int state) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
-        }
-
-        long getPssMinimum(int state) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
-        }
-
-        long getPssAverage(int state) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
-        }
-
-        long getPssMaximum(int state) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
-        }
-
-        long getPssUssMinimum(int state) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
-        }
-
-        long getPssUssAverage(int state) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
-        }
-
-        long getPssUssMaximum(int state) {
-            int idx = binarySearch(mPssTable, mPssTableSize, state);
-            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
-        }
-
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
-                    .append(" ").append(mName).append("/").append(mUid)
-                    .append(" pkg=").append(mPackage);
-            if (mMultiPackage) sb.append(" (multi)");
-            if (mCommonProcess != this) sb.append(" (sub)");
-            sb.append("}");
-            return sb.toString();
-        }
-    }
-
-    public static final class ServiceState extends DurationsTable {
-        public final String mPackage;
-        public final String mProcessName;
-        ProcessState mProc;
-
-        Object mOwner;
-
-        public static final int SERVICE_RUN = 0;
-        public static final int SERVICE_STARTED = 1;
-        public static final int SERVICE_BOUND = 2;
-        public static final int SERVICE_EXEC = 3;
-        static final int SERVICE_COUNT = 4;
-
-        int mRunCount;
-        public int mRunState = STATE_NOTHING;
-        long mRunStartTime;
-
-        boolean mStarted;
-        boolean mRestarting;
-        int mStartedCount;
-        public int mStartedState = STATE_NOTHING;
-        long mStartedStartTime;
-
-        int mBoundCount;
-        public int mBoundState = STATE_NOTHING;
-        long mBoundStartTime;
-
-        int mExecCount;
-        public int mExecState = STATE_NOTHING;
-        long mExecStartTime;
-
-        public ServiceState(ProcessStats processStats, String pkg, String name,
-                String processName, ProcessState proc) {
-            super(processStats, name);
-            mPackage = pkg;
-            mProcessName = processName;
-            mProc = proc;
-        }
-
-        public void applyNewOwner(Object newOwner) {
-            if (mOwner != newOwner) {
-                if (mOwner == null) {
-                    mOwner = newOwner;
-                    mProc.incActiveServices(mName);
-                } else {
-                    // There was already an old owner, reset this object for its
-                    // new owner.
-                    mOwner = newOwner;
-                    if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
-                        long now = SystemClock.uptimeMillis();
-                        if (mStarted) {
-                            if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
-                                    + " from " + mOwner + " while started: pkg="
-                                    + mPackage + " service=" + mName + " proc=" + mProc);
-                            setStarted(false, 0, now);
-                        }
-                        if (mBoundState != STATE_NOTHING) {
-                            if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
-                                    + " from " + mOwner + " while bound: pkg="
-                                    + mPackage + " service=" + mName + " proc=" + mProc);
-                            setBound(false, 0, now);
-                        }
-                        if (mExecState != STATE_NOTHING) {
-                            if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
-                                    + " from " + mOwner + " while executing: pkg="
-                                    + mPackage + " service=" + mName + " proc=" + mProc);
-                            setExecuting(false, 0, now);
-                        }
-                    }
-                }
-            }
-        }
-
-        public void clearCurrentOwner(Object owner, boolean silently) {
-            if (mOwner == owner) {
-                mProc.decActiveServices(mName);
-                if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
-                    long now = SystemClock.uptimeMillis();
-                    if (mStarted) {
-                        if (!silently) {
-                            Slog.wtfStack(TAG, "Service owner " + owner
-                                    + " cleared while started: pkg=" + mPackage + " service="
-                                    + mName + " proc=" + mProc);
-                        }
-                        setStarted(false, 0, now);
-                    }
-                    if (mBoundState != STATE_NOTHING) {
-                        if (!silently) {
-                            Slog.wtfStack(TAG, "Service owner " + owner
-                                    + " cleared while bound: pkg=" + mPackage + " service="
-                                    + mName + " proc=" + mProc);
-                        }
-                        setBound(false, 0, now);
-                    }
-                    if (mExecState != STATE_NOTHING) {
-                        if (!silently) {
-                            Slog.wtfStack(TAG, "Service owner " + owner
-                                    + " cleared while exec: pkg=" + mPackage + " service="
-                                    + mName + " proc=" + mProc);
-                        }
-                        setExecuting(false, 0, now);
-                    }
-                }
-                mOwner = null;
-            }
-        }
-
-        public boolean isInUse() {
-            return mOwner != null || mRestarting;
-        }
-
-        public boolean isRestarting() {
-            return mRestarting;
-        }
-
-        void add(ServiceState other) {
-            addDurations(other);
-            mRunCount += other.mRunCount;
-            mStartedCount += other.mStartedCount;
-            mBoundCount += other.mBoundCount;
-            mExecCount += other.mExecCount;
-        }
-
-        void resetSafely(long now) {
-            resetDurationsSafely();
-            mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
-            mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
-            mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
-            mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
-            mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
-        }
-
-        void writeToParcel(Parcel out, long now) {
-            writeDurationsToParcel(out);
-            out.writeInt(mRunCount);
-            out.writeInt(mStartedCount);
-            out.writeInt(mBoundCount);
-            out.writeInt(mExecCount);
-        }
-
-        boolean readFromParcel(Parcel in) {
-            if (!readDurationsFromParcel(in)) {
-                return false;
-            }
-            mRunCount = in.readInt();
-            mStartedCount = in.readInt();
-            mBoundCount = in.readInt();
-            mExecCount = in.readInt();
-            return true;
-        }
-
-        void commitStateTime(long now) {
-            if (mRunState != STATE_NOTHING) {
-                addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
-                mRunStartTime = now;
-            }
-            if (mStartedState != STATE_NOTHING) {
-                addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
-                        now - mStartedStartTime);
-                mStartedStartTime = now;
-            }
-            if (mBoundState != STATE_NOTHING) {
-                addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
-                mBoundStartTime = now;
-            }
-            if (mExecState != STATE_NOTHING) {
-                addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
-                mExecStartTime = now;
-            }
-        }
-
-        private void updateRunning(int memFactor, long now) {
-            final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
-                    || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
-            if (mRunState != state) {
-                if (mRunState != STATE_NOTHING) {
-                    addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
-                            now - mRunStartTime);
-                } else if (state != STATE_NOTHING) {
-                    mRunCount++;
-                }
-                mRunState = state;
-                mRunStartTime = now;
-            }
-        }
-
-        public void setStarted(boolean started, int memFactor, long now) {
-            if (mOwner == null) {
-                Slog.wtf(TAG, "Starting service " + this + " without owner");
-            }
-            mStarted = started;
-            updateStartedState(memFactor, now);
-        }
-
-        public void setRestarting(boolean restarting, int memFactor, long now) {
-            mRestarting = restarting;
-            updateStartedState(memFactor, now);
-        }
-
-        void updateStartedState(int memFactor, long now) {
-            final boolean wasStarted = mStartedState != STATE_NOTHING;
-            final boolean started = mStarted || mRestarting;
-            final int state = started ? memFactor : STATE_NOTHING;
-            if (mStartedState != state) {
-                if (mStartedState != STATE_NOTHING) {
-                    addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
-                            now - mStartedStartTime);
-                } else if (started) {
-                    mStartedCount++;
-                }
-                mStartedState = state;
-                mStartedStartTime = now;
-                mProc = mProc.pullFixedProc(mPackage);
-                if (wasStarted != started) {
-                    if (started) {
-                        mProc.incStartedServices(memFactor, now, mName);
-                    } else {
-                        mProc.decStartedServices(memFactor, now, mName);
-                    }
-                }
-                updateRunning(memFactor, now);
-            }
-        }
-
-        public void setBound(boolean bound, int memFactor, long now) {
-            if (mOwner == null) {
-                Slog.wtf(TAG, "Binding service " + this + " without owner");
-            }
-            final int state = bound ? memFactor : STATE_NOTHING;
-            if (mBoundState != state) {
-                if (mBoundState != STATE_NOTHING) {
-                    addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
-                            now - mBoundStartTime);
-                } else if (bound) {
-                    mBoundCount++;
-                }
-                mBoundState = state;
-                mBoundStartTime = now;
-                updateRunning(memFactor, now);
-            }
-        }
-
-        public void setExecuting(boolean executing, int memFactor, long now) {
-            if (mOwner == null) {
-                Slog.wtf(TAG, "Executing service " + this + " without owner");
-            }
-            final int state = executing ? memFactor : STATE_NOTHING;
-            if (mExecState != state) {
-                if (mExecState != STATE_NOTHING) {
-                    addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
-                } else if (executing) {
-                    mExecCount++;
-                }
-                mExecState = state;
-                mExecStartTime = now;
-                updateRunning(memFactor, now);
-            }
-        }
-
-        private long getDuration(int opType, int curState, long startTime, int memFactor,
-                long now) {
-            int state = opType + (memFactor*SERVICE_COUNT);
-            long time = getDuration(state, now);
-            if (curState == memFactor) {
-                time += now - startTime;
-            }
-            return time;
-        }
-
-        public String toString() {
-            return "ServiceState{" + Integer.toHexString(System.identityHashCode(this))
-                    + " " + mName + " pkg=" + mPackage + " proc="
-                    + Integer.toHexString(System.identityHashCode(this)) + "}";
-        }
-    }
-
-    public static final class PackageState {
-        public final ArrayMap<String, ProcessState> mProcesses
-                = new ArrayMap<String, ProcessState>();
-        public final ArrayMap<String, ServiceState> mServices
-                = new ArrayMap<String, ServiceState>();
-        public final String mPackageName;
-        public final int mUid;
-
-        public PackageState(String packageName, int uid) {
-            mUid = uid;
-            mPackageName = packageName;
-        }
-    }
-
-    public static final class ProcessDataCollection {
-        final int[] screenStates;
-        final int[] memStates;
-        final int[] procStates;
-
-        public long totalTime;
-        public long numPss;
-        public long minPss;
-        public long avgPss;
-        public long maxPss;
-        public long minUss;
-        public long avgUss;
-        public long maxUss;
-
-        public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
-            screenStates = _screenStates;
-            memStates = _memStates;
-            procStates = _procStates;
-        }
-
-        void print(PrintWriter pw, long overallTime, boolean full) {
-            if (totalTime > overallTime) {
-                pw.print("*");
-            }
-            printPercent(pw, (double) totalTime / (double) overallTime);
-            if (numPss > 0) {
-                pw.print(" (");
-                DebugUtils.printSizeValue(pw, minPss * 1024);
-                pw.print("-");
-                DebugUtils.printSizeValue(pw, avgPss * 1024);
-                pw.print("-");
-                DebugUtils.printSizeValue(pw, maxPss * 1024);
-                pw.print("/");
-                DebugUtils.printSizeValue(pw, minUss * 1024);
-                pw.print("-");
-                DebugUtils.printSizeValue(pw, avgUss * 1024);
-                pw.print("-");
-                DebugUtils.printSizeValue(pw, maxUss * 1024);
-                if (full) {
-                    pw.print(" over ");
-                    pw.print(numPss);
-                }
-                pw.print(")");
-            }
-        }
-    }
-
-    public static class TotalMemoryUseCollection {
-        final int[] screenStates;
-        final int[] memStates;
-
-        public TotalMemoryUseCollection(int[] _screenStates, int[] _memStates) {
-            screenStates = _screenStates;
-            memStates = _memStates;
-        }
-
-        public long totalTime;
-        public long[] processStatePss = new long[STATE_COUNT];
-        public double[] processStateWeight = new double[STATE_COUNT];
-        public long[] processStateTime = new long[STATE_COUNT];
-        public int[] processStateSamples = new int[STATE_COUNT];
-        public long[] sysMemUsage = new long[SYS_MEM_USAGE_COUNT];
-        public double sysMemCachedWeight;
-        public double sysMemFreeWeight;
-        public double sysMemZRamWeight;
-        public double sysMemKernelWeight;
-        public double sysMemNativeWeight;
-        public int sysMemSamples;
-    }
-}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9897b12..ff680e2 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -76,6 +76,7 @@
 import java.util.Objects;
 import java.util.Set;
 
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 
@@ -128,8 +129,8 @@
                 com.android.internal.R.string.whichSendApplication,
                 com.android.internal.R.string.whichSendApplicationNamed),
         SENDTO(Intent.ACTION_SENDTO,
-                com.android.internal.R.string.whichSendApplication,
-                com.android.internal.R.string.whichSendApplicationNamed),
+                com.android.internal.R.string.whichSendToApplication,
+                com.android.internal.R.string.whichSendToApplicationNamed),
         SEND_MULTIPLE(Intent.ACTION_SEND_MULTIPLE,
                 com.android.internal.R.string.whichSendApplication,
                 com.android.internal.R.string.whichSendApplicationNamed),
@@ -242,10 +243,6 @@
             return;
         }
 
-        // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
-        // control of the system bars.
-        getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
-
         final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
         if (rdl != null) {
             rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
@@ -392,12 +389,7 @@
         final DisplayResolveInfo dri = mAdapter.getOtherProfile();
         if (dri != null) {
             mProfileView.setVisibility(View.VISIBLE);
-            final ImageView icon = (ImageView) mProfileView.findViewById(R.id.icon);
-            final TextView text = (TextView) mProfileView.findViewById(R.id.text1);
-            if (!dri.hasDisplayIcon()) {
-                new LoadIconIntoViewTask(dri, icon).execute();
-            }
-            icon.setImageDrawable(dri.getDisplayIcon());
+            final TextView text = (TextView) mProfileView.findViewById(R.id.profile_button);
             text.setText(dri.getDisplayLabel());
         } else {
             mProfileView.setVisibility(View.GONE);
@@ -507,7 +499,9 @@
             mPackageMonitor.unregister();
             mRegistered = false;
         }
-        if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()) {
+        final Intent intent = getIntent();
+        if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
+                && !mResolvingHome) {
             // This resolver is in the unusual situation where it has been
             // launched at the top of a new task.  We don't let it be added
             // to the recent tasks shown to the user, and we need to make sure
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 478a56d..e2d29e3 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -23,7 +23,6 @@
 import android.widget.BaseAdapter;
 import android.widget.Filter;
 import android.widget.Filterable;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.internal.R;
@@ -50,6 +49,7 @@
     private static final int TYPE_HEADER_SUGGESTED = 0;
     private static final int TYPE_HEADER_ALL_OTHERS = 1;
     private static final int TYPE_LOCALE = 2;
+    private static final int MIN_REGIONS_FOR_SUGGESTIONS = 6;
 
     private ArrayList<LocaleStore.LocaleInfo> mLocaleOptions;
     private ArrayList<LocaleStore.LocaleInfo> mOriginalLocaleOptions;
@@ -156,16 +156,9 @@
                 }
 
                 TextView text = (TextView) convertView.findViewById(R.id.locale);
-                ImageView localized = (ImageView) convertView.findViewById(R.id.l10nWarn);
                 LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
-                text.setText(item.getLabel());
-                if (item.isTranslated() || mCountryMode) {
-                    localized.setVisibility(View.GONE);
-                    text.setTextLocale(item.getLocale());
-                } else {
-                    localized.setVisibility(View.VISIBLE);
-                    text.setTextLocale(Locale.getDefault());
-                }
+                text.setText(item.getLabel(mCountryMode));
+                text.setTextLocale(item.getLocale());
                 if (mCountryMode) {
                     int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
                     //noinspection ResourceType
@@ -179,6 +172,17 @@
     }
 
     private boolean showHeaders() {
+        // We don't want to show suggestions for locales with very few regions
+        // (e.g. Romanian, with 2 regions)
+        // So we put a (somewhat) arbitrary limit.
+        //
+        // The initial idea was to make that limit dependent on the screen height.
+        // But that would mean rotating the screen could make the suggestions disappear,
+        // as the number of countries that fits on the screen would be different in portrait
+        // and landscape mode.
+        if (mCountryMode && mLocaleOptions.size() < MIN_REGIONS_FOR_SUGGESTIONS) {
+            return false;
+        }
         return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
     }
 
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 29190f9..f6fbaab 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -42,15 +42,13 @@
 
 /**
  * A dialog shown to the user when they try to launch an app from a quiet profile
- * ({@link UserManager#isQuietModeEnabled(UserHandle)}, or when the app is suspended by the
- * profile owner or device owner.
+ * ({@link UserManager#isQuietModeEnabled(UserHandle)}.
  */
 public class UnlaunchableAppActivity extends Activity
         implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
     private static final String TAG = "UnlaunchableAppActivity";
 
     private static final int UNLAUNCHABLE_REASON_QUIET_MODE = 1;
-    private static final int UNLAUNCHABLE_REASON_SUSPENDED_PACKAGE = 2;
     private static final String EXTRA_UNLAUNCHABLE_REASON = "unlaunchable_reason";
 
     private int mUserId;
@@ -74,37 +72,6 @@
         if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
             dialogTitle = getResources().getString(R.string.work_mode_off_title);
             dialogMessage = getResources().getString(R.string.work_mode_off_message);
-        } else if (mReason == UNLAUNCHABLE_REASON_SUSPENDED_PACKAGE) {
-            DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
-                    Context.DEVICE_POLICY_SERVICE);
-            String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
-            String packageLabel = packageName;
-            try {
-                Context userContext = createPackageContextAsUser(packageName, 0,
-                        UserHandle.of(mUserId));
-                ApplicationInfo appInfo = userContext.getApplicationInfo();
-                if (appInfo != null) {
-                    packageLabel = userContext.getPackageManager().getApplicationLabel(appInfo)
-                            .toString();
-                }
-            } catch (NameNotFoundException e) {
-            }
-            dialogTitle = String.format(getResources().getString(R.string.suspended_package_title),
-                    packageLabel);
-            ComponentName profileOwner = dpm.getProfileOwnerAsUser(mUserId);
-            String profileOwnerName = null;
-            if (profileOwner != null) {
-                dialogMessage = dpm.getShortSupportMessageForUser(profileOwner, mUserId);
-                profileOwnerName = dpm.getProfileOwnerNameAsUser(mUserId);
-            }
-            // Fall back to standard message if profile owner hasn't set something specific.
-            if (TextUtils.isEmpty(dialogMessage)) {
-                if (TextUtils.isEmpty(profileOwnerName)) {
-                    profileOwnerName = getResources().getString(R.string.unknownName);
-                }
-                dialogMessage = getResources().getString(R.string.suspended_package_message,
-                        profileOwnerName);
-            }
         } else {
             Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
             finish();
@@ -154,12 +121,4 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
         return intent;
     }
-
-    public static Intent createPackageSuspendedDialogIntent(String packageName, int userId) {
-        Intent intent = createBaseIntent();
-        intent.putExtra(EXTRA_UNLAUNCHABLE_REASON, UNLAUNCHABLE_REASON_SUSPENDED_PACKAGE);
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
-        return intent;
-    }
 }
diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java
new file mode 100644
index 0000000..ebedc89
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/DumpUtils.java
@@ -0,0 +1,369 @@
+/*
+ * 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.app.procstats;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import static com.android.internal.app.procstats.ProcessStats.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * Utilities for dumping.
+ */
+public final class DumpUtils {
+    public static final String[] STATE_NAMES = new String[] {
+            "Persist", "Top    ", "ImpFg  ", "ImpBg  ",
+            "Backup ", "HeavyWt", "Service", "ServRst",
+            "Receivr", "Home   ",
+            "LastAct", "CchAct ", "CchCAct", "CchEmty"
+    };
+
+    public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
+            "off", "on"
+    };
+
+    public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
+            "norm", "mod",  "low", "crit"
+    };
+
+    public static final String[] STATE_NAMES_CSV = new String[] {
+            "pers", "top", "impfg", "impbg", "backup", "heavy",
+            "service", "service-rs", "receiver", "home", "lastact",
+            "cch-activity", "cch-aclient", "cch-empty"
+    };
+
+    static final String[] ADJ_SCREEN_TAGS = new String[] {
+            "0", "1"
+    };
+
+    static final String[] ADJ_MEM_TAGS = new String[] {
+            "n", "m",  "l", "c"
+    };
+
+    static final String[] STATE_TAGS = new String[] {
+            "p", "t", "f", "b", "u", "w",
+            "s", "x", "r", "h", "l", "a", "c", "e"
+    };
+
+    static final String CSV_SEP = "\t";
+
+    /**
+     * No instantiate
+     */
+    private DumpUtils() {
+    }
+
+    public static void printScreenLabel(PrintWriter pw, int offset) {
+        switch (offset) {
+            case ADJ_NOTHING:
+                pw.print("     ");
+                break;
+            case ADJ_SCREEN_OFF:
+                pw.print("SOff/");
+                break;
+            case ADJ_SCREEN_ON:
+                pw.print("SOn /");
+                break;
+            default:
+                pw.print("????/");
+                break;
+        }
+    }
+
+    public static void printScreenLabelCsv(PrintWriter pw, int offset) {
+        switch (offset) {
+            case ADJ_NOTHING:
+                break;
+            case ADJ_SCREEN_OFF:
+                pw.print(ADJ_SCREEN_NAMES_CSV[0]);
+                break;
+            case ADJ_SCREEN_ON:
+                pw.print(ADJ_SCREEN_NAMES_CSV[1]);
+                break;
+            default:
+                pw.print("???");
+                break;
+        }
+    }
+
+    public static void printMemLabel(PrintWriter pw, int offset, char sep) {
+        switch (offset) {
+            case ADJ_NOTHING:
+                pw.print("    ");
+                if (sep != 0) pw.print(' ');
+                break;
+            case ADJ_MEM_FACTOR_NORMAL:
+                pw.print("Norm");
+                if (sep != 0) pw.print(sep);
+                break;
+            case ADJ_MEM_FACTOR_MODERATE:
+                pw.print("Mod ");
+                if (sep != 0) pw.print(sep);
+                break;
+            case ADJ_MEM_FACTOR_LOW:
+                pw.print("Low ");
+                if (sep != 0) pw.print(sep);
+                break;
+            case ADJ_MEM_FACTOR_CRITICAL:
+                pw.print("Crit");
+                if (sep != 0) pw.print(sep);
+                break;
+            default:
+                pw.print("????");
+                if (sep != 0) pw.print(sep);
+                break;
+        }
+    }
+
+    public static void printMemLabelCsv(PrintWriter pw, int offset) {
+        if (offset >= ADJ_MEM_FACTOR_NORMAL) {
+            if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
+                pw.print(ADJ_MEM_NAMES_CSV[offset]);
+            } else {
+                pw.print("???");
+            }
+        }
+    }
+
+    public static void printPercent(PrintWriter pw, double fraction) {
+        fraction *= 100;
+        if (fraction < 1) {
+            pw.print(String.format("%.2f", fraction));
+        } else if (fraction < 10) {
+            pw.print(String.format("%.1f", fraction));
+        } else {
+            pw.print(String.format("%.0f", fraction));
+        }
+        pw.print("%");
+    }
+
+    public static void printProcStateTag(PrintWriter pw, int state) {
+        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
+        state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
+        printArrayEntry(pw, STATE_TAGS,  state, 1);
+    }
+
+    public static void printAdjTag(PrintWriter pw, int state) {
+        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
+        printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
+    }
+
+    public static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
+        pw.print(',');
+        printProcStateTag(pw, state);
+        pw.print(':');
+        pw.print(value);
+    }
+
+    public static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
+        pw.print(',');
+        printAdjTag(pw, state);
+        pw.print(':');
+        pw.print(value);
+    }
+
+    public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
+            int curState, long curStartTime, long now) {
+        long totalTime = 0;
+        int printedScreen = -1;
+        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
+            int printedMem = -1;
+            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
+                int state = imem+iscreen;
+                long time = durations[state];
+                String running = "";
+                if (curState == state) {
+                    time += now - curStartTime;
+                    if (pw != null) {
+                        running = " (running)";
+                    }
+                }
+                if (time != 0) {
+                    if (pw != null) {
+                        pw.print(prefix);
+                        printScreenLabel(pw, printedScreen != iscreen
+                                ? iscreen : STATE_NOTHING);
+                        printedScreen = iscreen;
+                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
+                        printedMem = imem;
+                        pw.print(": ");
+                        TimeUtils.formatDuration(time, pw); pw.println(running);
+                    }
+                    totalTime += time;
+                }
+            }
+        }
+        if (totalTime != 0 && pw != null) {
+            pw.print(prefix);
+            pw.print("    TOTAL: ");
+            TimeUtils.formatDuration(totalTime, pw);
+            pw.println();
+        }
+        return totalTime;
+    }
+
+    public static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
+            int curState, long curStartTime, long now) {
+        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
+            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
+                int state = imem+iscreen;
+                long time = durations[state];
+                if (curState == state) {
+                    time += now - curStartTime;
+                }
+                if (time != 0) {
+                    printAdjTagAndValue(pw, state, time);
+                }
+            }
+        }
+    }
+
+    private static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
+            int[] memStates, int[] procStates) {
+        final int NS = screenStates != null ? screenStates.length : 1;
+        final int NM = memStates != null ? memStates.length : 1;
+        final int NP = procStates != null ? procStates.length : 1;
+        for (int is=0; is<NS; is++) {
+            for (int im=0; im<NM; im++) {
+                for (int ip=0; ip<NP; ip++) {
+                    pw.print(sep);
+                    boolean printed = false;
+                    if (screenStates != null && screenStates.length > 1) {
+                        printScreenLabelCsv(pw, screenStates[is]);
+                        printed = true;
+                    }
+                    if (memStates != null && memStates.length > 1) {
+                        if (printed) {
+                            pw.print("-");
+                        }
+                        printMemLabelCsv(pw, memStates[im]);
+                        printed = true;
+                    }
+                    if (procStates != null && procStates.length > 1) {
+                        if (printed) {
+                            pw.print("-");
+                        }
+                        pw.print(STATE_NAMES_CSV[procStates[ip]]);
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * Doesn't seem to be used.
+     *
+    public static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
+            int[] screenStates, int[] memStates, int[] procStates, long now) {
+        String innerPrefix = prefix + "  ";
+        for (int i=procs.size()-1; i>=0; i--) {
+            ProcessState proc = procs.get(i);
+            pw.print(prefix);
+            pw.print(proc.mName);
+            pw.print(" / ");
+            UserHandle.formatUid(pw, proc.mUid);
+            pw.print(" (");
+            pw.print(proc.durations.getKeyCount());
+            pw.print(" entries)");
+            pw.println(":");
+            proc.dumpProcessState(pw, innerPrefix, screenStates, memStates, procStates, now);
+            if (proc.pssTable.getKeyCount() > 0) {
+                proc.dumpPss(pw, innerPrefix, screenStates, memStates, procStates);
+            }
+        }
+    }
+    */
+
+    public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
+            ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
+            long now, long totalTime) {
+        for (int i=procs.size()-1; i>=0; i--) {
+            final ProcessState proc = procs.get(i);
+            proc.dumpSummary(pw, prefix, screenStates, memStates, procStates, now, totalTime);
+        }
+    }
+
+    public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
+            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
+            boolean sepProcStates, int[] procStates, long now) {
+        pw.print("process");
+        pw.print(CSV_SEP);
+        pw.print("uid");
+        pw.print(CSV_SEP);
+        pw.print("vers");
+        dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
+                sepMemStates ? memStates : null,
+                sepProcStates ? procStates : null);
+        pw.println();
+        for (int i=procs.size()-1; i>=0; i--) {
+            ProcessState proc = procs.get(i);
+            pw.print(proc.getName());
+            pw.print(CSV_SEP);
+            UserHandle.formatUid(pw, proc.getUid());
+            pw.print(CSV_SEP);
+            pw.print(proc.getVersion());
+            proc.dumpCsv(pw, sepScreenStates, screenStates, sepMemStates,
+                    memStates, sepProcStates, procStates, now);
+            pw.println();
+        }
+    }
+
+    public static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
+        int index = value/mod;
+        if (index >= 0 && index < array.length) {
+            pw.print(array[index]);
+        } else {
+            pw.print('?');
+        }
+        return value - index*mod;
+    }
+
+    public static String collapseString(String pkgName, String itemName) {
+        if (itemName.startsWith(pkgName)) {
+            final int ITEMLEN = itemName.length();
+            final int PKGLEN = pkgName.length();
+            if (ITEMLEN == PKGLEN) {
+                return "";
+            } else if (ITEMLEN >= PKGLEN) {
+                if (itemName.charAt(PKGLEN) == '.') {
+                    return itemName.substring(PKGLEN);
+                }
+            }
+        }
+        return itemName;
+    }
+}
diff --git a/core/java/com/android/internal/app/procstats/DurationsTable.java b/core/java/com/android/internal/app/procstats/DurationsTable.java
new file mode 100644
index 0000000..b711ca1
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/DurationsTable.java
@@ -0,0 +1,64 @@
+/*
+ * 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.app.procstats;
+
+/**
+ * Sparse mapping table to store durations of processes, etc running in different
+ * states.
+ */
+public class DurationsTable extends SparseMappingTable.Table {
+    public DurationsTable(SparseMappingTable tableData) {
+        super(tableData);
+    }
+
+    /**
+     * Add all of the durations from the other table into this one.
+     * Resultant durations will be the sum of what is currently in the table
+     * and the new value.
+     */
+    public void addDurations(DurationsTable from) {
+        final int N = from.getKeyCount();
+        for (int i=0; i<N; i++) {
+            final int key = from.getKeyAt(i);
+            this.addDuration(SparseMappingTable.getIdFromKey(key), from.getValue(key));
+        }
+    }
+
+    /**
+     * Add the value into the value stored for the state.
+     *
+     * Resultant duration will be the sum of what is currently in the table
+     * and the new value.
+     */
+    public void addDuration(int state, long value) {
+        final int key = getOrAddKey((byte)state, 1);
+        setValue(key, getValue(key) + value);
+    }
+
+    /*
+    public long getDuration(int state, long now) {
+        final int key = getKey((byte)state);
+        if (key != SparseMappingTable.INVALID_KEY) {
+            return getValue(key);
+        } else {
+            return 0;
+        }
+    }
+    */
+}
+
+
diff --git a/core/java/com/android/internal/app/procstats/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
new file mode 100644
index 0000000..44867c7
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/IProcessStats.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.app.procstats;
+
+import android.content.ComponentName;
+import android.os.ParcelFileDescriptor;
+import com.android.internal.app.procstats.ProcessStats;
+
+interface IProcessStats {
+    byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
+    ParcelFileDescriptor getStatsOverTime(long minTime);
+    int getCurrentMemoryState();
+}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
new file mode 100644
index 0000000..80d6070
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -0,0 +1,1188 @@
+/*
+ * 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.app.procstats;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats.PackageState;
+import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
+import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
+import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
+import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
+import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
+import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
+import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
+import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
+import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
+import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
+import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
+import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
+
+import dalvik.system.VMRuntime;
+import libcore.util.EmptyArray;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+public final class ProcessState {
+    private static final String TAG = "ProcessStats";
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_PARCEL = false;
+
+    // Map from process states to the states we track.
+    private static final int[] PROCESS_STATE_TO_STATE = new int[] {
+        STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
+        STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+        STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
+        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
+        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
+        STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+        STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
+        STATE_RECEIVER,                 // ActivityManager.PROCESS_STATE_RECEIVER
+        STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
+        STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+        STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        STATE_CACHED_EMPTY,             // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+    };
+
+    public static final Comparator<ProcessState> COMPARATOR = new Comparator<ProcessState>() {
+            @Override
+            public int compare(ProcessState lhs, ProcessState rhs) {
+                if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
+                    return -1;
+                } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
+                    return 1;
+                }
+                return 0;
+            }
+        };
+
+    static class PssAggr {
+        long pss = 0;
+        long samples = 0;
+
+        void add(long newPss, long newSamples) {
+            pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
+                    / (samples+newSamples);
+            samples += newSamples;
+        }
+    }
+
+    // Used by reset to count rather than storing extra maps. Be careful.
+    public int tmpNumInUse;
+    public ProcessState tmpFoundSubProc;
+
+    private final ProcessStats mStats;
+    private final String mName;
+    private final String mPackage;
+    private final int mUid;
+    private final int mVersion;
+    private final DurationsTable mDurations;
+    private final PssTable mPssTable;
+
+    private ProcessState mCommonProcess;
+    private int mCurState = STATE_NOTHING;
+    private long mStartTime;
+
+    private int mLastPssState = STATE_NOTHING;
+    private long mLastPssTime;
+
+    private boolean mActive;
+    private int mNumActiveServices;
+    private int mNumStartedServices;
+
+    private int mNumExcessiveWake;
+    private int mNumExcessiveCpu;
+
+    private int mNumCachedKill;
+    private long mMinCachedKillPss;
+    private long mAvgCachedKillPss;
+    private long mMaxCachedKillPss;
+
+    private boolean mMultiPackage;
+    private boolean mDead;
+
+    // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
+    private long mTmpTotalTime;
+
+    /**
+     * Create a new top-level process state, for the initial case where there is only
+     * a single package running in a process.  The initial state is not running.
+     */
+    public ProcessState(ProcessStats processStats, String pkg, int uid, int vers, String name) {
+        mStats = processStats;
+        mName = name;
+        mCommonProcess = this;
+        mPackage = pkg;
+        mUid = uid;
+        mVersion = vers;
+        mDurations = new DurationsTable(processStats.mTableData);
+        mPssTable = new PssTable(processStats.mTableData);
+    }
+
+    /**
+     * Create a new per-package process state for an existing top-level process
+     * state.  The current running state of the top-level process is also copied,
+     * marked as started running at 'now'.
+     */
+    public ProcessState(ProcessState commonProcess, String pkg, int uid, int vers, String name,
+            long now) {
+        mStats = commonProcess.mStats;
+        mName = name;
+        mCommonProcess = commonProcess;
+        mPackage = pkg;
+        mUid = uid;
+        mVersion = vers;
+        mCurState = commonProcess.mCurState;
+        mStartTime = now;
+        mDurations = new DurationsTable(commonProcess.mStats.mTableData);
+        mPssTable = new PssTable(commonProcess.mStats.mTableData);
+    }
+
+    public ProcessState clone(long now) {
+        ProcessState pnew = new ProcessState(this, mPackage, mUid, mVersion, mName, now);
+        pnew.mDurations.addDurations(mDurations);
+        pnew.mPssTable.copyFrom(mPssTable, PSS_COUNT);
+        pnew.mNumExcessiveWake = mNumExcessiveWake;
+        pnew.mNumExcessiveCpu = mNumExcessiveCpu;
+        pnew.mNumCachedKill = mNumCachedKill;
+        pnew.mMinCachedKillPss = mMinCachedKillPss;
+        pnew.mAvgCachedKillPss = mAvgCachedKillPss;
+        pnew.mMaxCachedKillPss = mMaxCachedKillPss;
+        pnew.mActive = mActive;
+        pnew.mNumActiveServices = mNumActiveServices;
+        pnew.mNumStartedServices = mNumStartedServices;
+        return pnew;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public ProcessState getCommonProcess() {
+        return mCommonProcess;
+    }
+
+    /**
+     * Say that we are not part of a shared process, so mCommonProcess = this.
+     */
+    public void makeStandalone() {
+        mCommonProcess = this;
+    }
+
+    public String getPackage() {
+        return mPackage;
+    }
+
+    public int getUid() {
+        return mUid;
+    }
+
+    public int getVersion() {
+        return mVersion;
+    }
+
+    public boolean isMultiPackage() {
+        return mMultiPackage;
+    }
+
+    public void setMultiPackage(boolean val) {
+        mMultiPackage = val;
+    }
+    
+    public int getDurationsBucketCount() {
+        return mDurations.getKeyCount();
+    }
+
+    public void add(ProcessState other) {
+        mDurations.addDurations(other.mDurations);
+        mPssTable.mergeStats(other.mPssTable);
+        mNumExcessiveWake += other.mNumExcessiveWake;
+        mNumExcessiveCpu += other.mNumExcessiveCpu;
+        if (other.mNumCachedKill > 0) {
+            addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
+                    other.mAvgCachedKillPss, other.mMaxCachedKillPss);
+        }
+    }
+
+    public void resetSafely(long now) {
+        mDurations.resetTable();
+        mPssTable.resetTable();
+        mStartTime = now;
+        mLastPssState = STATE_NOTHING;
+        mLastPssTime = 0;
+        mNumExcessiveWake = 0;
+        mNumExcessiveCpu = 0;
+        mNumCachedKill = 0;
+        mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
+    }
+
+    public void makeDead() {
+        mDead = true;
+    }
+
+    private void ensureNotDead() {
+        if (!mDead) {
+            return;
+        }
+        Slog.wtfStack(TAG, "ProcessState dead: name=" + mName
+                + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+    }
+
+    public void writeToParcel(Parcel out, long now) {
+        out.writeInt(mMultiPackage ? 1 : 0);
+        mDurations.writeToParcel(out);
+        mPssTable.writeToParcel(out);
+        out.writeInt(mNumExcessiveWake);
+        out.writeInt(mNumExcessiveCpu);
+        out.writeInt(mNumCachedKill);
+        if (mNumCachedKill > 0) {
+            out.writeLong(mMinCachedKillPss);
+            out.writeLong(mAvgCachedKillPss);
+            out.writeLong(mMaxCachedKillPss);
+        }
+    }
+
+    public boolean readFromParcel(Parcel in, boolean fully) {
+        boolean multiPackage = in.readInt() != 0;
+        if (fully) {
+            mMultiPackage = multiPackage;
+        }
+        if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
+        if (!mDurations.readFromParcel(in)) {
+            return false;
+        }
+        if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
+        if (!mPssTable.readFromParcel(in)) {
+            return false;
+        }
+        mNumExcessiveWake = in.readInt();
+        mNumExcessiveCpu = in.readInt();
+        mNumCachedKill = in.readInt();
+        if (mNumCachedKill > 0) {
+            mMinCachedKillPss = in.readLong();
+            mAvgCachedKillPss = in.readLong();
+            mMaxCachedKillPss = in.readLong();
+        } else {
+            mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
+        }
+        return true;
+    }
+
+    public void makeActive() {
+        ensureNotDead();
+        mActive = true;
+    }
+
+    public void makeInactive() {
+        mActive = false;
+    }
+
+    public boolean isInUse() {
+        return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
+                || mCurState != STATE_NOTHING;
+    }
+
+    public boolean isActive() {
+        return mActive;
+    }
+
+    public boolean hasAnyData() {
+        return !(mDurations.getKeyCount() == 0
+                && mCurState == STATE_NOTHING
+                && mPssTable.getKeyCount() == 0);
+    }
+
+    /**
+     * Update the current state of the given list of processes.
+     *
+     * @param state Current ActivityManager.PROCESS_STATE_*
+     * @param memFactor Current mem factor constant.
+     * @param now Current time.
+     * @param pkgList Processes to update.
+     */
+    public void setState(int state, int memFactor, long now,
+            ArrayMap<String, ProcessStateHolder> pkgList) {
+        if (state < 0) {
+            state = mNumStartedServices > 0
+                    ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
+        } else {
+            state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
+        }
+
+        // First update the common process.
+        mCommonProcess.setState(state, now);
+
+        // If the common process is not multi-package, there is nothing else to do.
+        if (!mCommonProcess.mMultiPackage) {
+            return;
+        }
+
+        if (pkgList != null) {
+            for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                pullFixedProc(pkgList, ip).setState(state, now);
+            }
+        }
+    }
+
+    public void setState(int state, long now) {
+        ensureNotDead();
+        if (mCurState != state) {
+            //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
+            commitStateTime(now);
+            mCurState = state;
+        }
+    }
+
+    public void commitStateTime(long now) {
+        if (mCurState != STATE_NOTHING) {
+            long dur = now - mStartTime;
+            if (dur > 0) {
+                mDurations.addDuration(mCurState, dur);
+            }
+        }
+        mStartTime = now;
+    }
+
+    public void incActiveServices(String serviceName) {
+        if (DEBUG && "".equals(mName)) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
+                    + " to " + (mNumActiveServices+1), here);
+        }
+        if (mCommonProcess != this) {
+            mCommonProcess.incActiveServices(serviceName);
+        }
+        mNumActiveServices++;
+    }
+
+    public void decActiveServices(String serviceName) {
+        if (DEBUG && "".equals(mName)) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+                    + " to " + (mNumActiveServices-1), here);
+        }
+        if (mCommonProcess != this) {
+            mCommonProcess.decActiveServices(serviceName);
+        }
+        mNumActiveServices--;
+        if (mNumActiveServices < 0) {
+            Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
+                    + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
+            mNumActiveServices = 0;
+        }
+    }
+
+    public void incStartedServices(int memFactor, long now, String serviceName) {
+        if (false) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
+                    + " to " + (mNumStartedServices+1), here);
+        }
+        if (mCommonProcess != this) {
+            mCommonProcess.incStartedServices(memFactor, now, serviceName);
+        }
+        mNumStartedServices++;
+        if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
+            setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
+        }
+    }
+
+    public void decStartedServices(int memFactor, long now, String serviceName) {
+        if (false) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+                    + " to " + (mNumStartedServices-1), here);
+        }
+        if (mCommonProcess != this) {
+            mCommonProcess.decStartedServices(memFactor, now, serviceName);
+        }
+        mNumStartedServices--;
+        if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
+            setState(STATE_NOTHING, now);
+        } else if (mNumStartedServices < 0) {
+            Slog.wtfStack(TAG, "Proc started services underrun: pkg="
+                    + mPackage + " uid=" + mUid + " name=" + mName);
+            mNumStartedServices = 0;
+        }
+    }
+
+    public void addPss(long pss, long uss, boolean always,
+            ArrayMap<String, ProcessStateHolder> pkgList) {
+        ensureNotDead();
+        if (!always) {
+            if (mLastPssState == mCurState && SystemClock.uptimeMillis()
+                    < (mLastPssTime+(30*1000))) {
+                return;
+            }
+        }
+        mLastPssState = mCurState;
+        mLastPssTime = SystemClock.uptimeMillis();
+        if (mCurState != STATE_NOTHING) {
+            // First update the common process.
+            mCommonProcess.mPssTable.mergeStats(mCurState, 1, pss, pss, pss, uss, uss, uss);
+
+            // If the common process is not multi-package, there is nothing else to do.
+            if (!mCommonProcess.mMultiPackage) {
+                return;
+            }
+
+            if (pkgList != null) {
+                for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                    pullFixedProc(pkgList, ip).mPssTable.mergeStats(mCurState, 1,
+                            pss, pss, pss, uss, uss, uss);
+                }
+            }
+        }
+    }
+
+    public void reportExcessiveWake(ArrayMap<String, ProcessStateHolder> pkgList) {
+        ensureNotDead();
+        mCommonProcess.mNumExcessiveWake++;
+        if (!mCommonProcess.mMultiPackage) {
+            return;
+        }
+
+        for (int ip=pkgList.size()-1; ip>=0; ip--) {
+            pullFixedProc(pkgList, ip).mNumExcessiveWake++;
+        }
+    }
+
+    public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
+        ensureNotDead();
+        mCommonProcess.mNumExcessiveCpu++;
+        if (!mCommonProcess.mMultiPackage) {
+            return;
+        }
+
+        for (int ip=pkgList.size()-1; ip>=0; ip--) {
+            pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
+        }
+    }
+
+    private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
+        if (mNumCachedKill <= 0) {
+            mNumCachedKill = num;
+            mMinCachedKillPss = minPss;
+            mAvgCachedKillPss = avgPss;
+            mMaxCachedKillPss = maxPss;
+        } else {
+            if (minPss < mMinCachedKillPss) {
+                mMinCachedKillPss = minPss;
+            }
+            if (maxPss > mMaxCachedKillPss) {
+                mMaxCachedKillPss = maxPss;
+            }
+            mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
+                    / (mNumCachedKill+num) );
+            mNumCachedKill += num;
+        }
+    }
+
+    public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
+        ensureNotDead();
+        mCommonProcess.addCachedKill(1, pss, pss, pss);
+        if (!mCommonProcess.mMultiPackage) {
+            return;
+        }
+
+        for (int ip=pkgList.size()-1; ip>=0; ip--) {
+            pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
+        }
+    }
+
+    public ProcessState pullFixedProc(String pkgName) {
+        if (mMultiPackage) {
+            // The array map is still pointing to a common process state
+            // that is now shared across packages.  Update it to point to
+            // the new per-package state.
+            SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
+            if (vpkg == null) {
+                throw new IllegalStateException("Didn't find package " + pkgName
+                        + " / " + mUid);
+            }
+            PackageState pkg = vpkg.get(mVersion);
+            if (pkg == null) {
+                throw new IllegalStateException("Didn't find package " + pkgName
+                        + " / " + mUid + " vers " + mVersion);
+            }
+            ProcessState proc = pkg.mProcesses.get(mName);
+            if (proc == null) {
+                throw new IllegalStateException("Didn't create per-package process "
+                        + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
+            }
+            return proc;
+        }
+        return this;
+    }
+
+    private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
+            int index) {
+        ProcessStateHolder holder = pkgList.valueAt(index);
+        ProcessState proc = holder.state;
+        if (mDead && proc.mCommonProcess != proc) {
+            // Somehow we are contining to use a process state that is dead, because
+            // it was not being told it was active during the last commit.  We can recover
+            // from this by generating a fresh new state, but this is bad because we
+            // are losing whatever data we had in the old process state.
+            Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
+                    + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+            proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
+                    proc.mName);
+        }
+        if (proc.mMultiPackage) {
+            // The array map is still pointing to a common process state
+            // that is now shared across packages.  Update it to point to
+            // the new per-package state.
+            SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
+                    proc.mUid);
+            if (vpkg == null) {
+                throw new IllegalStateException("No existing package "
+                        + pkgList.keyAt(index) + "/" + proc.mUid
+                        + " for multi-proc " + proc.mName);
+            }
+            PackageState pkg = vpkg.get(proc.mVersion);
+            if (pkg == null) {
+                throw new IllegalStateException("No existing package "
+                        + pkgList.keyAt(index) + "/" + proc.mUid
+                        + " for multi-proc " + proc.mName + " version " + proc.mVersion);
+            }
+            String savedName = proc.mName;
+            proc = pkg.mProcesses.get(proc.mName);
+            if (proc == null) {
+                throw new IllegalStateException("Didn't create per-package process "
+                        + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
+            }
+            holder.state = proc;
+        }
+        return proc;
+    }
+
+    public long getDuration(int state, long now) {
+        long time = mDurations.getValueForId((byte)state);
+        if (mCurState == state) {
+            time += now - mStartTime;
+        }
+        return time;
+    }
+
+    public long getPssSampleCount(int state) {
+        return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
+    }
+
+    public long getPssMinimum(int state) {
+        return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
+    }
+
+    public long getPssAverage(int state) {
+        return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
+    }
+
+    public long getPssMaximum(int state) {
+        return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
+    }
+
+    public long getPssUssMinimum(int state) {
+        return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
+    }
+
+    public long getPssUssAverage(int state) {
+        return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
+    }
+
+    public long getPssUssMaximum(int state) {
+        return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
+    }
+
+    /**
+     * Sums up the PSS data and adds it to 'data'.
+     * 
+     * @param data The aggregate data is added here.
+     * @param now SystemClock.uptimeMillis()
+     */
+    public void aggregatePss(TotalMemoryUseCollection data, long now) {
+        final PssAggr fgPss = new PssAggr();
+        final PssAggr bgPss = new PssAggr();
+        final PssAggr cachedPss = new PssAggr();
+        boolean havePss = false;
+        for (int i=0; i<mDurations.getKeyCount(); i++) {
+            final int key = mDurations.getKeyAt(i);
+            int type = SparseMappingTable.getIdFromKey(key);
+            int procState = type % STATE_COUNT;
+            long samples = getPssSampleCount(type);
+            if (samples > 0) {
+                long avg = getPssAverage(type);
+                havePss = true;
+                if (procState <= STATE_IMPORTANT_FOREGROUND) {
+                    fgPss.add(avg, samples);
+                } else if (procState <= STATE_RECEIVER) {
+                    bgPss.add(avg, samples);
+                } else {
+                    cachedPss.add(avg, samples);
+                }
+            }
+        }
+        if (!havePss) {
+            return;
+        }
+        boolean fgHasBg = false;
+        boolean fgHasCached = false;
+        boolean bgHasCached = false;
+        if (fgPss.samples < 3 && bgPss.samples > 0) {
+            fgHasBg = true;
+            fgPss.add(bgPss.pss, bgPss.samples);
+        }
+        if (fgPss.samples < 3 && cachedPss.samples > 0) {
+            fgHasCached = true;
+            fgPss.add(cachedPss.pss, cachedPss.samples);
+        }
+        if (bgPss.samples < 3 && cachedPss.samples > 0) {
+            bgHasCached = true;
+            bgPss.add(cachedPss.pss, cachedPss.samples);
+        }
+        if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
+            bgPss.add(fgPss.pss, fgPss.samples);
+        }
+        if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
+            cachedPss.add(bgPss.pss, bgPss.samples);
+        }
+        if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
+            cachedPss.add(fgPss.pss, fgPss.samples);
+        }
+        for (int i=0; i<mDurations.getKeyCount(); i++) {
+            final int key = mDurations.getKeyAt(i);
+            final int type = SparseMappingTable.getIdFromKey(key);
+            long time = mDurations.getValue(key);
+            if (mCurState == type) {
+                time += now - mStartTime;
+            }
+            final int procState = type % STATE_COUNT;
+            data.processStateTime[procState] += time;
+            long samples = getPssSampleCount(type);
+            long avg;
+            if (samples > 0) {
+                avg = getPssAverage(type);
+            } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
+                samples = fgPss.samples;
+                avg = fgPss.pss;
+            } else if (procState <= STATE_RECEIVER) {
+                samples = bgPss.samples;
+                avg = bgPss.pss;
+            } else {
+                samples = cachedPss.samples;
+                avg = cachedPss.pss;
+            }
+            double newAvg = ( (data.processStatePss[procState]
+                    * (double)data.processStateSamples[procState])
+                        + (avg*(double)samples)
+                    ) / (data.processStateSamples[procState]+samples);
+            data.processStatePss[procState] = (long)newAvg;
+            data.processStateSamples[procState] += samples;
+            data.processStateWeight[procState] += avg * (double)time;
+        }
+    }
+
+    public long computeProcessTimeLocked(int[] screenStates, int[] memStates,
+                int[] procStates, long now) {
+        long totalTime = 0;
+        for (int is=0; is<screenStates.length; is++) {
+            for (int im=0; im<memStates.length; im++) {
+                for (int ip=0; ip<procStates.length; ip++) {
+                    int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
+                            + procStates[ip];
+                    totalTime += getDuration(bucket, now);
+                }
+            }
+        }
+        mTmpTotalTime = totalTime;
+        return totalTime;
+    }
+
+    public void dumpSummary(PrintWriter pw, String prefix,
+            int[] screenStates, int[] memStates, int[] procStates,
+            long now, long totalTime) {
+        pw.print(prefix);
+        pw.print("* ");
+        pw.print(mName);
+        pw.print(" / ");
+        UserHandle.formatUid(pw, mUid);
+        pw.print(" / v");
+        pw.print(mVersion);
+        pw.println(":");
+        dumpProcessSummaryDetails(pw, prefix, "         TOTAL: ", screenStates, memStates,
+                procStates, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "    Persistent: ", screenStates, memStates,
+                new int[] { STATE_PERSISTENT }, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "           Top: ", screenStates, memStates,
+                new int[] {STATE_TOP}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "        Imp Fg: ", screenStates, memStates,
+                new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "        Imp Bg: ", screenStates, memStates,
+                new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "        Backup: ", screenStates, memStates,
+                new int[] {STATE_BACKUP}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "     Heavy Wgt: ", screenStates, memStates,
+                new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "       Service: ", screenStates, memStates,
+                new int[] {STATE_SERVICE}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "    Service Rs: ", screenStates, memStates,
+                new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "      Receiver: ", screenStates, memStates,
+                new int[] {STATE_RECEIVER}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "        (Home): ", screenStates, memStates,
+                new int[] {STATE_HOME}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "    (Last Act): ", screenStates, memStates,
+                new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
+        dumpProcessSummaryDetails(pw, prefix, "      (Cached): ", screenStates, memStates,
+                new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
+                        STATE_CACHED_EMPTY}, now, totalTime, true);
+    }
+
+    public void dumpProcessState(PrintWriter pw, String prefix,
+            int[] screenStates, int[] memStates, int[] procStates, long now) {
+        long totalTime = 0;
+        int printedScreen = -1;
+        for (int is=0; is<screenStates.length; is++) {
+            int printedMem = -1;
+            for (int im=0; im<memStates.length; im++) {
+                for (int ip=0; ip<procStates.length; ip++) {
+                    final int iscreen = screenStates[is];
+                    final int imem = memStates[im];
+                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+                    long time = mDurations.getValueForId((byte)bucket);
+                    String running = "";
+                    if (mCurState == bucket) {
+                        running = " (running)";
+                    }
+                    if (time != 0) {
+                        pw.print(prefix);
+                        if (screenStates.length > 1) {
+                            DumpUtils.printScreenLabel(pw, printedScreen != iscreen
+                                    ? iscreen : STATE_NOTHING);
+                            printedScreen = iscreen;
+                        }
+                        if (memStates.length > 1) {
+                            DumpUtils.printMemLabel(pw,
+                                    printedMem != imem ? imem : STATE_NOTHING, '/');
+                            printedMem = imem;
+                        }
+                        pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
+                        TimeUtils.formatDuration(time, pw); pw.println(running);
+                        totalTime += time;
+                    }
+                }
+            }
+        }
+        if (totalTime != 0) {
+            pw.print(prefix);
+            if (screenStates.length > 1) {
+                DumpUtils.printScreenLabel(pw, STATE_NOTHING);
+            }
+            if (memStates.length > 1) {
+                DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
+            }
+            pw.print("TOTAL  : ");
+            TimeUtils.formatDuration(totalTime, pw);
+            pw.println();
+        }
+    }
+
+    public void dumpPss(PrintWriter pw, String prefix,
+            int[] screenStates, int[] memStates, int[] procStates) {
+        boolean printedHeader = false;
+        int printedScreen = -1;
+        for (int is=0; is<screenStates.length; is++) {
+            int printedMem = -1;
+            for (int im=0; im<memStates.length; im++) {
+                for (int ip=0; ip<procStates.length; ip++) {
+                    final int iscreen = screenStates[is];
+                    final int imem = memStates[im];
+                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+                    long count = getPssSampleCount(bucket);
+                    if (count > 0) {
+                        if (!printedHeader) {
+                            pw.print(prefix);
+                            pw.print("PSS/USS (");
+                            pw.print(mPssTable.getKeyCount());
+                            pw.println(" entries):");
+                            printedHeader = true;
+                        }
+                        pw.print(prefix);
+                        pw.print("  ");
+                        if (screenStates.length > 1) {
+                            DumpUtils.printScreenLabel(pw,
+                                    printedScreen != iscreen ? iscreen : STATE_NOTHING);
+                            printedScreen = iscreen;
+                        }
+                        if (memStates.length > 1) {
+                            DumpUtils.printMemLabel(pw,
+                                    printedMem != imem ? imem : STATE_NOTHING, '/');
+                            printedMem = imem;
+                        }
+                        pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
+                        pw.print(count);
+                        pw.print(" samples ");
+                        DebugUtils.printSizeValue(pw, getPssMinimum(bucket) * 1024);
+                        pw.print(" ");
+                        DebugUtils.printSizeValue(pw, getPssAverage(bucket) * 1024);
+                        pw.print(" ");
+                        DebugUtils.printSizeValue(pw, getPssMaximum(bucket) * 1024);
+                        pw.print(" / ");
+                        DebugUtils.printSizeValue(pw, getPssUssMinimum(bucket) * 1024);
+                        pw.print(" ");
+                        DebugUtils.printSizeValue(pw, getPssUssAverage(bucket) * 1024);
+                        pw.print(" ");
+                        DebugUtils.printSizeValue(pw, getPssUssMaximum(bucket) * 1024);
+                        pw.println();
+                    }
+                }
+            }
+        }
+        if (mNumExcessiveWake != 0) {
+            pw.print(prefix); pw.print("Killed for excessive wake locks: ");
+                    pw.print(mNumExcessiveWake); pw.println(" times");
+        }
+        if (mNumExcessiveCpu != 0) {
+            pw.print(prefix); pw.print("Killed for excessive CPU use: ");
+                    pw.print(mNumExcessiveCpu); pw.println(" times");
+        }
+        if (mNumCachedKill != 0) {
+            pw.print(prefix); pw.print("Killed from cached state: ");
+                    pw.print(mNumCachedKill); pw.print(" times from pss ");
+                    DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-");
+                    DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-");
+                    DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println();
+        }
+    }
+
+    private void dumpProcessSummaryDetails(PrintWriter pw, String prefix,
+            String label, int[] screenStates, int[] memStates, int[] procStates,
+            long now, long totalTime, boolean full) {
+        ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
+                screenStates, memStates, procStates);
+        computeProcessData(totals, now);
+        final double percentage = (double) totals.totalTime / (double) totalTime * 100;
+        // We don't print percentages < .01, so just drop those.
+        if (percentage >= 0.005 || totals.numPss != 0) {
+            if (prefix != null) {
+                pw.print(prefix);
+            }
+            if (label != null) {
+                pw.print(label);
+            }
+            totals.print(pw, totalTime, full);
+            if (prefix != null) {
+                pw.println();
+            }
+        }
+    }
+
+    public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) {
+        if (dumpAll) {
+            pw.print(prefix); pw.print("myID=");
+                    pw.print(Integer.toHexString(System.identityHashCode(this)));
+                    pw.print(" mCommonProcess=");
+                    pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess)));
+                    pw.print(" mPackage="); pw.println(mPackage);
+            if (mMultiPackage) {
+                pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage);
+            }
+            if (this != mCommonProcess) {
+                pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName);
+                        pw.print("/"); pw.print(mCommonProcess.mUid);
+                        pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
+            }
+        }
+        if (mActive) {
+            pw.print(prefix); pw.print("mActive="); pw.println(mActive);
+        }
+        if (mDead) {
+            pw.print(prefix); pw.print("mDead="); pw.println(mDead);
+        }
+        if (mNumActiveServices != 0 || mNumStartedServices != 0) {
+            pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices);
+                    pw.print(" mNumStartedServices=");
+                    pw.println(mNumStartedServices);
+        }
+    }
+
+    public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) {
+        data.totalTime = 0;
+        data.numPss = data.minPss = data.avgPss = data.maxPss =
+                data.minUss = data.avgUss = data.maxUss = 0;
+        for (int is=0; is<data.screenStates.length; is++) {
+            for (int im=0; im<data.memStates.length; im++) {
+                for (int ip=0; ip<data.procStates.length; ip++) {
+                    int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
+                            + data.procStates[ip];
+                    data.totalTime += getDuration(bucket, now);
+                    long samples = getPssSampleCount(bucket);
+                    if (samples > 0) {
+                        long minPss = getPssMinimum(bucket);
+                        long avgPss = getPssAverage(bucket);
+                        long maxPss = getPssMaximum(bucket);
+                        long minUss = getPssUssMinimum(bucket);
+                        long avgUss = getPssUssAverage(bucket);
+                        long maxUss = getPssUssMaximum(bucket);
+                        if (data.numPss == 0) {
+                            data.minPss = minPss;
+                            data.avgPss = avgPss;
+                            data.maxPss = maxPss;
+                            data.minUss = minUss;
+                            data.avgUss = avgUss;
+                            data.maxUss = maxUss;
+                        } else {
+                            if (minPss < data.minPss) {
+                                data.minPss = minPss;
+                            }
+                            data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
+                                    + (avgPss*(double)samples)) / (data.numPss+samples) );
+                            if (maxPss > data.maxPss) {
+                                data.maxPss = maxPss;
+                            }
+                            if (minUss < data.minUss) {
+                                data.minUss = minUss;
+                            }
+                            data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
+                                    + (avgUss*(double)samples)) / (data.numPss+samples) );
+                            if (maxUss > data.maxUss) {
+                                data.maxUss = maxUss;
+                            }
+                        }
+                        data.numPss += samples;
+                    }
+                }
+            }
+        }
+    }
+
+    public void dumpCsv(PrintWriter pw,
+            boolean sepScreenStates, int[] screenStates, boolean sepMemStates,
+            int[] memStates, boolean sepProcStates, int[] procStates, long now) {
+        final int NSS = sepScreenStates ? screenStates.length : 1;
+        final int NMS = sepMemStates ? memStates.length : 1;
+        final int NPS = sepProcStates ? procStates.length : 1;
+        for (int iss=0; iss<NSS; iss++) {
+            for (int ims=0; ims<NMS; ims++) {
+                for (int ips=0; ips<NPS; ips++) {
+                    final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
+                    final int vsmem = sepMemStates ? memStates[ims] : 0;
+                    final int vsproc = sepProcStates ? procStates[ips] : 0;
+                    final int NSA = sepScreenStates ? 1 : screenStates.length;
+                    final int NMA = sepMemStates ? 1 : memStates.length;
+                    final int NPA = sepProcStates ? 1 : procStates.length;
+                    long totalTime = 0;
+                    for (int isa=0; isa<NSA; isa++) {
+                        for (int ima=0; ima<NMA; ima++) {
+                            for (int ipa=0; ipa<NPA; ipa++) {
+                                final int vascreen = sepScreenStates ? 0 : screenStates[isa];
+                                final int vamem = sepMemStates ? 0 : memStates[ima];
+                                final int vaproc = sepProcStates ? 0 : procStates[ipa];
+                                final int bucket = ((vsscreen + vascreen + vsmem + vamem)
+                                        * STATE_COUNT) + vsproc + vaproc;
+                                totalTime += getDuration(bucket, now);
+                            }
+                        }
+                    }
+                    pw.print(DumpUtils.CSV_SEP);
+                    pw.print(totalTime);
+                }
+            }
+        }
+    }
+
+    public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+            String itemName, long now) {
+        pw.print("pkgproc,");
+        pw.print(pkgName);
+        pw.print(",");
+        pw.print(uid);
+        pw.print(",");
+        pw.print(vers);
+        pw.print(",");
+        pw.print(DumpUtils.collapseString(pkgName, itemName));
+        dumpAllStateCheckin(pw, now);
+        pw.println();
+        if (mPssTable.getKeyCount() > 0) {
+            pw.print("pkgpss,");
+            pw.print(pkgName);
+            pw.print(",");
+            pw.print(uid);
+            pw.print(",");
+            pw.print(vers);
+            pw.print(",");
+            pw.print(DumpUtils.collapseString(pkgName, itemName));
+            dumpAllPssCheckin(pw);
+            pw.println();
+        }
+        if (mNumExcessiveWake > 0 || mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
+            pw.print("pkgkills,");
+            pw.print(pkgName);
+            pw.print(",");
+            pw.print(uid);
+            pw.print(",");
+            pw.print(vers);
+            pw.print(",");
+            pw.print(DumpUtils.collapseString(pkgName, itemName));
+            pw.print(",");
+            pw.print(mNumExcessiveWake);
+            pw.print(",");
+            pw.print(mNumExcessiveCpu);
+            pw.print(",");
+            pw.print(mNumCachedKill);
+            pw.print(",");
+            pw.print(mMinCachedKillPss);
+            pw.print(":");
+            pw.print(mAvgCachedKillPss);
+            pw.print(":");
+            pw.print(mMaxCachedKillPss);
+            pw.println();
+        }
+    }
+
+    public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) {
+        if (mDurations.getKeyCount() > 0) {
+            pw.print("proc,");
+            pw.print(procName);
+            pw.print(",");
+            pw.print(uid);
+            dumpAllStateCheckin(pw, now);
+            pw.println();
+        }
+        if (mPssTable.getKeyCount() > 0) {
+            pw.print("pss,");
+            pw.print(procName);
+            pw.print(",");
+            pw.print(uid);
+            dumpAllPssCheckin(pw);
+            pw.println();
+        }
+        if (mNumExcessiveWake > 0 || mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
+            pw.print("kills,");
+            pw.print(procName);
+            pw.print(",");
+            pw.print(uid);
+            pw.print(",");
+            pw.print(mNumExcessiveWake);
+            pw.print(",");
+            pw.print(mNumExcessiveCpu);
+            pw.print(",");
+            pw.print(mNumCachedKill);
+            pw.print(",");
+            pw.print(mMinCachedKillPss);
+            pw.print(":");
+            pw.print(mAvgCachedKillPss);
+            pw.print(":");
+            pw.print(mMaxCachedKillPss);
+            pw.println();
+        }
+    }
+
+    public void dumpAllStateCheckin(PrintWriter pw, long now) {
+        boolean didCurState = false;
+        for (int i=0; i<mDurations.getKeyCount(); i++) {
+            final int key = mDurations.getKeyAt(i);
+            final int type = SparseMappingTable.getIdFromKey(key);
+            long time = mDurations.getValue(key);
+            if (mCurState == type) {
+                didCurState = true;
+                time += now - mStartTime;
+            }
+            DumpUtils.printProcStateTagAndValue(pw, type, time);
+        }
+        if (!didCurState && mCurState != STATE_NOTHING) {
+            DumpUtils.printProcStateTagAndValue(pw, mCurState, now - mStartTime);
+        }
+    }
+
+    public void dumpAllPssCheckin(PrintWriter pw) {
+        final int N = mPssTable.getKeyCount();
+        for (int i=0; i<N; i++) {
+            final int key = mPssTable.getKeyAt(i);
+            final int type = SparseMappingTable.getIdFromKey(key);
+            pw.print(',');
+            DumpUtils.printProcStateTag(pw, type);
+            pw.print(':');
+            pw.print(mPssTable.getValue(key, PSS_SAMPLE_COUNT));
+            pw.print(':');
+            pw.print(mPssTable.getValue(key, PSS_MINIMUM));
+            pw.print(':');
+            pw.print(mPssTable.getValue(key, PSS_AVERAGE));
+            pw.print(':');
+            pw.print(mPssTable.getValue(key, PSS_MAXIMUM));
+            pw.print(':');
+            pw.print(mPssTable.getValue(key, PSS_USS_MINIMUM));
+            pw.print(':');
+            pw.print(mPssTable.getValue(key, PSS_USS_AVERAGE));
+            pw.print(':');
+            pw.print(mPssTable.getValue(key, PSS_USS_MAXIMUM));
+        }
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
+                .append(" ").append(mName).append("/").append(mUid)
+                .append(" pkg=").append(mPackage);
+        if (mMultiPackage) sb.append(" (multi)");
+        if (mCommonProcess != this) sb.append(" (sub)");
+        sb.append("}");
+        return sb.toString();
+    }
+}
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.aidl b/core/java/com/android/internal/app/procstats/ProcessStats.aidl
new file mode 100644
index 0000000..33639a0
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.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.app.procstats;
+
+parcelable ProcessStats;
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
new file mode 100644
index 0000000..06542f7
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -0,0 +1,1621 @@
+/*
+ * 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.app.procstats;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.app.ProcessMap;
+import com.android.internal.app.procstats.DurationsTable;
+import com.android.internal.app.procstats.ProcessState;
+import com.android.internal.app.procstats.PssTable;
+import com.android.internal.app.procstats.ServiceState;
+import com.android.internal.app.procstats.SparseMappingTable;
+import com.android.internal.app.procstats.SysMemUsageTable;
+import com.android.internal.app.procstats.DumpUtils.*;
+
+import dalvik.system.VMRuntime;
+import libcore.util.EmptyArray;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+public final class ProcessStats implements Parcelable {
+    public static final String TAG = "ProcessStats";
+    static final boolean DEBUG = false;
+    static final boolean DEBUG_PARCEL = false;
+
+    public static final String SERVICE_NAME = "procstats";
+
+    // How often the service commits its data, giving the minimum batching
+    // that is done.
+    public static long COMMIT_PERIOD = 3*60*60*1000;  // Commit current stats every 3 hours
+
+    // Minimum uptime period before committing.  If the COMMIT_PERIOD has elapsed but
+    // the total uptime has not exceeded this amount, then the commit will be held until
+    // it is reached.
+    public static long COMMIT_UPTIME_PERIOD = 60*60*1000;  // Must have at least 1 hour elapsed
+
+    public static final int STATE_NOTHING = -1;
+    public static final int STATE_PERSISTENT = 0;
+    public static final int STATE_TOP = 1;
+    public static final int STATE_IMPORTANT_FOREGROUND = 2;
+    public static final int STATE_IMPORTANT_BACKGROUND = 3;
+    public static final int STATE_BACKUP = 4;
+    public static final int STATE_HEAVY_WEIGHT = 5;
+    public static final int STATE_SERVICE = 6;
+    public static final int STATE_SERVICE_RESTARTING = 7;
+    public static final int STATE_RECEIVER = 8;
+    public static final int STATE_HOME = 9;
+    public static final int STATE_LAST_ACTIVITY = 10;
+    public static final int STATE_CACHED_ACTIVITY = 11;
+    public static final int STATE_CACHED_ACTIVITY_CLIENT = 12;
+    public static final int STATE_CACHED_EMPTY = 13;
+    public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
+
+    public static final int PSS_SAMPLE_COUNT = 0;
+    public static final int PSS_MINIMUM = 1;
+    public static final int PSS_AVERAGE = 2;
+    public static final int PSS_MAXIMUM = 3;
+    public static final int PSS_USS_MINIMUM = 4;
+    public static final int PSS_USS_AVERAGE = 5;
+    public static final int PSS_USS_MAXIMUM = 6;
+    public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
+
+    public static final int SYS_MEM_USAGE_SAMPLE_COUNT = 0;
+    public static final int SYS_MEM_USAGE_CACHED_MINIMUM = 1;
+    public static final int SYS_MEM_USAGE_CACHED_AVERAGE = 2;
+    public static final int SYS_MEM_USAGE_CACHED_MAXIMUM = 3;
+    public static final int SYS_MEM_USAGE_FREE_MINIMUM = 4;
+    public static final int SYS_MEM_USAGE_FREE_AVERAGE = 5;
+    public static final int SYS_MEM_USAGE_FREE_MAXIMUM = 6;
+    public static final int SYS_MEM_USAGE_ZRAM_MINIMUM = 7;
+    public static final int SYS_MEM_USAGE_ZRAM_AVERAGE = 8;
+    public static final int SYS_MEM_USAGE_ZRAM_MAXIMUM = 9;
+    public static final int SYS_MEM_USAGE_KERNEL_MINIMUM = 10;
+    public static final int SYS_MEM_USAGE_KERNEL_AVERAGE = 11;
+    public static final int SYS_MEM_USAGE_KERNEL_MAXIMUM = 12;
+    public static final int SYS_MEM_USAGE_NATIVE_MINIMUM = 13;
+    public static final int SYS_MEM_USAGE_NATIVE_AVERAGE = 14;
+    public static final int SYS_MEM_USAGE_NATIVE_MAXIMUM = 15;
+    public static final int SYS_MEM_USAGE_COUNT = SYS_MEM_USAGE_NATIVE_MAXIMUM+1;
+
+    public static final int ADJ_NOTHING = -1;
+    public static final int ADJ_MEM_FACTOR_NORMAL = 0;
+    public static final int ADJ_MEM_FACTOR_MODERATE = 1;
+    public static final int ADJ_MEM_FACTOR_LOW = 2;
+    public static final int ADJ_MEM_FACTOR_CRITICAL = 3;
+    public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1;
+    public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT;
+    public static final int ADJ_SCREEN_OFF = 0;
+    public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD;
+    public static final int ADJ_COUNT = ADJ_SCREEN_ON*2;
+
+    public static final int FLAG_COMPLETE = 1<<0;
+    public static final int FLAG_SHUTDOWN = 1<<1;
+    public static final int FLAG_SYSPROPS = 1<<2;
+
+    public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL,
+            ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
+
+    public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
+
+    public static final int[] NON_CACHED_PROC_STATES = new int[] {
+            STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+            STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
+            STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
+    };
+
+    public static final int[] BACKGROUND_PROC_STATES = new int[] {
+            STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
+    };
+
+    public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
+            STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
+            STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
+            STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
+    };
+
+    // Current version of the parcel format.
+    private static final int PARCEL_VERSION = 19;
+    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
+    private static final int MAGIC = 0x50535454;
+
+    public String mReadError;
+    public String mTimePeriodStartClockStr;
+    public int mFlags;
+
+    public final ProcessMap<SparseArray<PackageState>> mPackages
+            = new ProcessMap<SparseArray<PackageState>>();
+    public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
+
+    public final long[] mMemFactorDurations = new long[ADJ_COUNT];
+    public int mMemFactor = STATE_NOTHING;
+    public long mStartTime;
+
+    public long mTimePeriodStartClock;
+    public long mTimePeriodStartRealtime;
+    public long mTimePeriodEndRealtime;
+    public long mTimePeriodStartUptime;
+    public long mTimePeriodEndUptime;
+    String mRuntime;
+    boolean mRunning;
+
+    public final SparseMappingTable mTableData = new SparseMappingTable();
+
+    int[] mAddLongTable;
+    int mAddLongTableSize;
+
+    public final long[] mSysMemUsageArgs = new long[SYS_MEM_USAGE_COUNT];
+    public final SysMemUsageTable mSysMemUsage = new SysMemUsageTable(mTableData);
+
+    // For writing parcels.
+    ArrayMap<String, Integer> mCommonStringToIndex;
+
+    // For reading parcels.
+    ArrayList<String> mIndexToCommonString;
+
+    public ProcessStats(boolean running) {
+        mRunning = running;
+        reset();
+    }
+
+    public ProcessStats(Parcel in) {
+        reset();
+        readFromParcel(in);
+    }
+
+    public void add(ProcessStats other) {
+        ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = other.mPackages.getMap();
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            final String pkgName = pkgMap.keyAt(ip);
+            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                final int uid = uids.keyAt(iu);
+                final SparseArray<PackageState> versions = uids.valueAt(iu);
+                for (int iv=0; iv<versions.size(); iv++) {
+                    final int vers = versions.keyAt(iv);
+                    final PackageState otherState = versions.valueAt(iv);
+                    final int NPROCS = otherState.mProcesses.size();
+                    final int NSRVS = otherState.mServices.size();
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        ProcessState otherProc = otherState.mProcesses.valueAt(iproc);
+                        if (otherProc.getCommonProcess() != otherProc) {
+                            if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
+                                    + " vers " + vers + " proc " + otherProc.getName());
+                            ProcessState thisProc = getProcessStateLocked(pkgName, uid, vers,
+                                    otherProc.getName());
+                            if (thisProc.getCommonProcess() == thisProc) {
+                                if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting");
+                                thisProc.setMultiPackage(true);
+                                long now = SystemClock.uptimeMillis();
+                                final PackageState pkgState = getPackageStateLocked(pkgName, uid,
+                                        vers);
+                                thisProc = thisProc.clone(now);
+                                pkgState.mProcesses.put(thisProc.getName(), thisProc);
+                            }
+                            thisProc.add(otherProc);
+                        }
+                    }
+                    for (int isvc=0; isvc<NSRVS; isvc++) {
+                        ServiceState otherSvc = otherState.mServices.valueAt(isvc);
+                        if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
+                                + " service " + otherSvc.getName());
+                        ServiceState thisSvc = getServiceStateLocked(pkgName, uid, vers,
+                                otherSvc.getProcessName(), otherSvc.getName());
+                        thisSvc.add(otherSvc);
+                    }
+                }
+            }
+        }
+
+        ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap();
+        for (int ip=0; ip<procMap.size(); ip++) {
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                ProcessState otherProc = uids.valueAt(iu);
+                final String name = otherProc.getName();
+                final String pkg = otherProc.getPackage();
+                final int vers = otherProc.getVersion();
+                ProcessState thisProc = mProcesses.get(name, uid);
+                if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + name);
+                if (thisProc == null) {
+                    if (DEBUG) Slog.d(TAG, "Creating new process!");
+                    thisProc = new ProcessState(this, pkg, uid, vers, name);
+                    mProcesses.put(name, uid, thisProc);
+                    PackageState thisState = getPackageStateLocked(pkg, uid, vers);
+                    if (!thisState.mProcesses.containsKey(name)) {
+                        thisState.mProcesses.put(name, thisProc);
+                    }
+                }
+                thisProc.add(otherProc);
+            }
+        }
+
+        for (int i=0; i<ADJ_COUNT; i++) {
+            if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by "
+                    + other.mMemFactorDurations[i] + " from "
+                    + mMemFactorDurations[i]);
+            mMemFactorDurations[i] += other.mMemFactorDurations[i];
+        }
+
+        mSysMemUsage.mergeStats(other.mSysMemUsage);
+
+        if (other.mTimePeriodStartClock < mTimePeriodStartClock) {
+            mTimePeriodStartClock = other.mTimePeriodStartClock;
+            mTimePeriodStartClockStr = other.mTimePeriodStartClockStr;
+        }
+        mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime;
+        mTimePeriodEndUptime += other.mTimePeriodEndUptime - other.mTimePeriodStartUptime;
+    }
+
+    public void addSysMemUsage(long cachedMem, long freeMem, long zramMem, long kernelMem,
+            long nativeMem) {
+        if (mMemFactor != STATE_NOTHING) {
+            int state = mMemFactor * STATE_COUNT;
+            mSysMemUsageArgs[SYS_MEM_USAGE_SAMPLE_COUNT] = 1;
+            for (int i=0; i<3; i++) {
+                mSysMemUsageArgs[SYS_MEM_USAGE_CACHED_MINIMUM + i] = cachedMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_FREE_MINIMUM + i] = freeMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_ZRAM_MINIMUM + i] = zramMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_KERNEL_MINIMUM + i] = kernelMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_NATIVE_MINIMUM + i] = nativeMem;
+            }
+            mSysMemUsage.mergeStats(state, mSysMemUsageArgs, 0);
+        }
+    }
+
+    public static final Parcelable.Creator<ProcessStats> CREATOR
+            = new Parcelable.Creator<ProcessStats>() {
+        public ProcessStats createFromParcel(Parcel in) {
+            return new ProcessStats(in);
+        }
+
+        public ProcessStats[] newArray(int size) {
+            return new ProcessStats[size];
+        }
+    };
+
+    public void computeTotalMemoryUse(TotalMemoryUseCollection data, long now) {
+        data.totalTime = 0;
+        for (int i=0; i<STATE_COUNT; i++) {
+            data.processStateWeight[i] = 0;
+            data.processStatePss[i] = 0;
+            data.processStateTime[i] = 0;
+            data.processStateSamples[i] = 0;
+        }
+        for (int i=0; i<SYS_MEM_USAGE_COUNT; i++) {
+            data.sysMemUsage[i] = 0;
+        }
+        data.sysMemCachedWeight = 0;
+        data.sysMemFreeWeight = 0;
+        data.sysMemZRamWeight = 0;
+        data.sysMemKernelWeight = 0;
+        data.sysMemNativeWeight = 0;
+        data.sysMemSamples = 0;
+        final long[] totalMemUsage = mSysMemUsage.getTotalMemUsage();
+        for (int is=0; is<data.screenStates.length; is++) {
+            for (int im=0; im<data.memStates.length; im++) {
+                int memBucket = data.screenStates[is] + data.memStates[im];
+                int stateBucket = memBucket * STATE_COUNT;
+                long memTime = mMemFactorDurations[memBucket];
+                if (mMemFactor == memBucket) {
+                    memTime += now - mStartTime;
+                }
+                data.totalTime += memTime;
+                final int sysKey = mSysMemUsage.getKey((byte)stateBucket);
+                long[] longs = totalMemUsage;
+                int idx = 0;
+                if (sysKey != SparseMappingTable.INVALID_KEY) {
+                    final long[] tmpLongs = mSysMemUsage.getArrayForKey(sysKey);
+                    final int tmpIndex = SparseMappingTable.getIndexFromKey(sysKey);
+                    if (tmpLongs[tmpIndex+SYS_MEM_USAGE_SAMPLE_COUNT] >= 3) {
+                        SysMemUsageTable.mergeSysMemUsage(data.sysMemUsage, 0, longs, idx);
+                        longs = tmpLongs;
+                        idx = tmpIndex;
+                    }
+                }
+                data.sysMemCachedWeight += longs[idx+SYS_MEM_USAGE_CACHED_AVERAGE]
+                        * (double)memTime;
+                data.sysMemFreeWeight += longs[idx+SYS_MEM_USAGE_FREE_AVERAGE]
+                        * (double)memTime;
+                data.sysMemZRamWeight += longs[idx+SYS_MEM_USAGE_ZRAM_AVERAGE]
+                        * (double)memTime;
+                data.sysMemKernelWeight += longs[idx+SYS_MEM_USAGE_KERNEL_AVERAGE]
+                        * (double)memTime;
+                data.sysMemNativeWeight += longs[idx+SYS_MEM_USAGE_NATIVE_AVERAGE]
+                        * (double)memTime;
+                data.sysMemSamples += longs[idx+SYS_MEM_USAGE_SAMPLE_COUNT];
+             }
+        }
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        for (int iproc=0; iproc<procMap.size(); iproc++) {
+            SparseArray<ProcessState> uids = procMap.valueAt(iproc);
+            for (int iu=0; iu<uids.size(); iu++) {
+                final ProcessState proc = uids.valueAt(iu);
+                proc.aggregatePss(data, now);
+            }
+        }
+    }
+
+    public void reset() {
+        if (DEBUG) Slog.d(TAG, "Resetting state of " + mTimePeriodStartClockStr);
+        resetCommon();
+        mPackages.getMap().clear();
+        mProcesses.getMap().clear();
+        mMemFactor = STATE_NOTHING;
+        mStartTime = 0;
+        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
+    }
+
+    public void resetSafely() {
+        if (DEBUG) Slog.d(TAG, "Safely resetting state of " + mTimePeriodStartClockStr);
+        resetCommon();
+
+        // First initialize use count of all common processes.
+        final long now = SystemClock.uptimeMillis();
+        final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        for (int ip=procMap.size()-1; ip>=0; ip--) {
+            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=uids.size()-1; iu>=0; iu--) {
+                uids.valueAt(iu).tmpNumInUse = 0;
+           }
+        }
+
+        // Next reset or prune all per-package processes, and for the ones that are reset
+        // track this back to the common processes.
+        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+        for (int ip=pkgMap.size()-1; ip>=0; ip--) {
+            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+            for (int iu=uids.size()-1; iu>=0; iu--) {
+                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+                for (int iv=vpkgs.size()-1; iv>=0; iv--) {
+                    final PackageState pkgState = vpkgs.valueAt(iv);
+                    for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
+                        final ProcessState ps = pkgState.mProcesses.valueAt(iproc);
+                        if (ps.isInUse()) {
+                            ps.resetSafely(now);
+                            ps.getCommonProcess().tmpNumInUse++;
+                            ps.getCommonProcess().tmpFoundSubProc = ps;
+                        } else {
+                            pkgState.mProcesses.valueAt(iproc).makeDead();
+                            pkgState.mProcesses.removeAt(iproc);
+                        }
+                    }
+                    for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
+                        final ServiceState ss = pkgState.mServices.valueAt(isvc);
+                        if (ss.isInUse()) {
+                            ss.resetSafely(now);
+                        } else {
+                            pkgState.mServices.removeAt(isvc);
+                        }
+                    }
+                    if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) {
+                        vpkgs.removeAt(iv);
+                    }
+                }
+                if (vpkgs.size() <= 0) {
+                    uids.removeAt(iu);
+                }
+            }
+            if (uids.size() <= 0) {
+                pkgMap.removeAt(ip);
+            }
+        }
+
+        // Finally prune out any common processes that are no longer in use.
+        for (int ip=procMap.size()-1; ip>=0; ip--) {
+            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=uids.size()-1; iu>=0; iu--) {
+                ProcessState ps = uids.valueAt(iu);
+                if (ps.isInUse() || ps.tmpNumInUse > 0) {
+                    // If this is a process for multiple packages, we could at this point
+                    // be back down to one package.  In that case, we want to revert back
+                    // to a single shared ProcessState.  We can do this by converting the
+                    // current package-specific ProcessState up to the shared ProcessState,
+                    // throwing away the current one we have here (because nobody else is
+                    // using it).
+                    if (!ps.isActive() && ps.isMultiPackage() && ps.tmpNumInUse == 1) {
+                        // Here we go...
+                        ps = ps.tmpFoundSubProc;
+                        ps.makeStandalone();
+                        uids.setValueAt(iu, ps);
+                    } else {
+                        ps.resetSafely(now);
+                    }
+                } else {
+                    ps.makeDead();
+                    uids.removeAt(iu);
+                }
+            }
+            if (uids.size() <= 0) {
+                procMap.removeAt(ip);
+            }
+        }
+
+        mStartTime = now;
+        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
+    }
+
+    private void resetCommon() {
+        mTimePeriodStartClock = System.currentTimeMillis();
+        buildTimePeriodStartClockStr();
+        mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+        mTimePeriodStartUptime = mTimePeriodEndUptime = SystemClock.uptimeMillis();
+        mTableData.reset();
+        Arrays.fill(mMemFactorDurations, 0);
+        mSysMemUsage.resetTable();
+        mStartTime = 0;
+        mReadError = null;
+        mFlags = 0;
+        evaluateSystemProperties(true);
+    }
+
+    public boolean evaluateSystemProperties(boolean update) {
+        boolean changed = false;
+        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2",
+                VMRuntime.getRuntime().vmLibrary());
+        if (!Objects.equals(runtime, mRuntime)) {
+            changed = true;
+            if (update) {
+                mRuntime = runtime;
+            }
+        }
+        return changed;
+    }
+
+    private void buildTimePeriodStartClockStr() {
+        mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                mTimePeriodStartClock).toString();
+    }
+
+    static final int[] BAD_TABLE = new int[0];
+
+    private void writeCompactedLongArray(Parcel out, long[] array, int num) {
+        for (int i=0; i<num; i++) {
+            long val = array[i];
+            if (val < 0) {
+                Slog.w(TAG, "Time val negative: " + val);
+                val = 0;
+            }
+            if (val <= Integer.MAX_VALUE) {
+                out.writeInt((int)val);
+            } else {
+                int top = ~((int)((val>>32)&0x7fffffff));
+                int bottom = (int)(val&0xfffffff);
+                out.writeInt(top);
+                out.writeInt(bottom);
+            }
+        }
+    }
+
+    private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
+        if (version <= 10) {
+            in.readLongArray(array);
+            return;
+        }
+        final int alen = array.length;
+        if (num > alen) {
+            throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
+        }
+        int i;
+        for (i=0; i<num; i++) {
+            int val = in.readInt();
+            if (val >= 0) {
+                array[i] = val;
+            } else {
+                int bottom = in.readInt();
+                array[i] = (((long)~val)<<32) | bottom;
+            }
+        }
+        while (i < alen) {
+            array[i] = 0;
+            i++;
+        }
+    }
+
+    private void writeCommonString(Parcel out, String name) {
+        Integer index = mCommonStringToIndex.get(name);
+        if (index != null) {
+            out.writeInt(index);
+            return;
+        }
+        index = mCommonStringToIndex.size();
+        mCommonStringToIndex.put(name, index);
+        out.writeInt(~index);
+        out.writeString(name);
+    }
+
+    private String readCommonString(Parcel in, int version) {
+        if (version <= 9) {
+            return in.readString();
+        }
+        int index = in.readInt();
+        if (index >= 0) {
+            return mIndexToCommonString.get(index);
+        }
+        index = ~index;
+        String name = in.readString();
+        while (mIndexToCommonString.size() <= index) {
+            mIndexToCommonString.add(null);
+        }
+        mIndexToCommonString.set(index, name);
+        return name;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        writeToParcel(out, SystemClock.uptimeMillis(), flags);
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel out, long now, int flags) {
+        out.writeInt(MAGIC);
+        out.writeInt(PARCEL_VERSION);
+        out.writeInt(STATE_COUNT);
+        out.writeInt(ADJ_COUNT);
+        out.writeInt(PSS_COUNT);
+        out.writeInt(SYS_MEM_USAGE_COUNT);
+        out.writeInt(SparseMappingTable.ARRAY_SIZE);
+
+        mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.size());
+
+        // First commit all running times.
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        final int NPROC = procMap.size();
+        for (int ip=0; ip<NPROC; ip++) {
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            final int NUID = uids.size();
+            for (int iu=0; iu<NUID; iu++) {
+                uids.valueAt(iu).commitStateTime(now);
+            }
+        }
+        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+        final int NPKG = pkgMap.size();
+        for (int ip=0; ip<NPKG; ip++) {
+            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+            final int NUID = uids.size();
+            for (int iu=0; iu<NUID; iu++) {
+                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+                final int NVERS = vpkgs.size();
+                for (int iv=0; iv<NVERS; iv++) {
+                    PackageState pkgState = vpkgs.valueAt(iv);
+                    final int NPROCS = pkgState.mProcesses.size();
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (proc.getCommonProcess() != proc) {
+                            proc.commitStateTime(now);
+                        }
+                    }
+                    final int NSRVS = pkgState.mServices.size();
+                    for (int isvc=0; isvc<NSRVS; isvc++) {
+                        pkgState.mServices.valueAt(isvc).commitStateTime(now);
+                    }
+                }
+            }
+        }
+
+        out.writeLong(mTimePeriodStartClock);
+        out.writeLong(mTimePeriodStartRealtime);
+        out.writeLong(mTimePeriodEndRealtime);
+        out.writeLong(mTimePeriodStartUptime);
+        out.writeLong(mTimePeriodEndUptime);
+        out.writeString(mRuntime);
+        out.writeInt(mFlags);
+
+        mTableData.writeToParcel(out);
+
+        if (mMemFactor != STATE_NOTHING) {
+            mMemFactorDurations[mMemFactor] += now - mStartTime;
+            mStartTime = now;
+        }
+        writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
+
+        mSysMemUsage.writeToParcel(out);
+
+        out.writeInt(NPROC);
+        for (int ip=0; ip<NPROC; ip++) {
+            writeCommonString(out, procMap.keyAt(ip));
+            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            final int NUID = uids.size();
+            out.writeInt(NUID);
+            for (int iu=0; iu<NUID; iu++) {
+                out.writeInt(uids.keyAt(iu));
+                final ProcessState proc = uids.valueAt(iu);
+                writeCommonString(out, proc.getPackage());
+                out.writeInt(proc.getVersion());
+                proc.writeToParcel(out, now);
+            }
+        }
+        out.writeInt(NPKG);
+        for (int ip=0; ip<NPKG; ip++) {
+            writeCommonString(out, pkgMap.keyAt(ip));
+            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+            final int NUID = uids.size();
+            out.writeInt(NUID);
+            for (int iu=0; iu<NUID; iu++) {
+                out.writeInt(uids.keyAt(iu));
+                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+                final int NVERS = vpkgs.size();
+                out.writeInt(NVERS);
+                for (int iv=0; iv<NVERS; iv++) {
+                    out.writeInt(vpkgs.keyAt(iv));
+                    final PackageState pkgState = vpkgs.valueAt(iv);
+                    final int NPROCS = pkgState.mProcesses.size();
+                    out.writeInt(NPROCS);
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        writeCommonString(out, pkgState.mProcesses.keyAt(iproc));
+                        final ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (proc.getCommonProcess() == proc) {
+                            // This is the same as the common process we wrote above.
+                            out.writeInt(0);
+                        } else {
+                            // There is separate data for this package's process.
+                            out.writeInt(1);
+                            proc.writeToParcel(out, now);
+                        }
+                    }
+                    final int NSRVS = pkgState.mServices.size();
+                    out.writeInt(NSRVS);
+                    for (int isvc=0; isvc<NSRVS; isvc++) {
+                        out.writeString(pkgState.mServices.keyAt(isvc));
+                        final ServiceState svc = pkgState.mServices.valueAt(isvc);
+                        writeCommonString(out, svc.getProcessName());
+                        svc.writeToParcel(out, now);
+                    }
+                }
+            }
+        }
+
+        mCommonStringToIndex = null;
+    }
+
+    private boolean readCheckedInt(Parcel in, int val, String what) {
+        int got;
+        if ((got=in.readInt()) != val) {
+            mReadError = "bad " + what + ": " + got;
+            return false;
+        }
+        return true;
+    }
+
+    static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
+        int pos = 0;
+        final int initialAvail = stream.available();
+        byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
+        while (true) {
+            int amt = stream.read(data, pos, data.length-pos);
+            if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos
+                    + " of avail " + data.length);
+            if (amt < 0) {
+                if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos
+                        + " len=" + data.length);
+                outLen[0] = pos;
+                return data;
+            }
+            pos += amt;
+            if (pos >= data.length) {
+                byte[] newData = new byte[pos+16384];
+                if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
+                        + newData.length);
+                System.arraycopy(data, 0, newData, 0, pos);
+                data = newData;
+            }
+        }
+    }
+
+    public void read(InputStream stream) {
+        try {
+            int[] len = new int[1];
+            byte[] raw = readFully(stream, len);
+            Parcel in = Parcel.obtain();
+            in.unmarshall(raw, 0, len[0]);
+            in.setDataPosition(0);
+            stream.close();
+
+            readFromParcel(in);
+        } catch (IOException e) {
+            mReadError = "caught exception: " + e;
+        }
+    }
+
+    public void readFromParcel(Parcel in) {
+        final boolean hadData = mPackages.getMap().size() > 0
+                || mProcesses.getMap().size() > 0;
+        if (hadData) {
+            resetSafely();
+        }
+
+        if (!readCheckedInt(in, MAGIC, "magic number")) {
+            return;
+        }
+        int version = in.readInt();
+        if (version != PARCEL_VERSION) {
+            mReadError = "bad version: " + version;
+            return;
+        }
+        if (!readCheckedInt(in, STATE_COUNT, "state count")) {
+            return;
+        }
+        if (!readCheckedInt(in, ADJ_COUNT, "adj count")) {
+            return;
+        }
+        if (!readCheckedInt(in, PSS_COUNT, "pss count")) {
+            return;
+        }
+        if (!readCheckedInt(in, SYS_MEM_USAGE_COUNT, "sys mem usage count")) {
+            return;
+        }
+        if (!readCheckedInt(in, SparseMappingTable.ARRAY_SIZE, "longs size")) {
+            return;
+        }
+
+        mIndexToCommonString = new ArrayList<String>();
+
+        mTimePeriodStartClock = in.readLong();
+        buildTimePeriodStartClockStr();
+        mTimePeriodStartRealtime = in.readLong();
+        mTimePeriodEndRealtime = in.readLong();
+        mTimePeriodStartUptime = in.readLong();
+        mTimePeriodEndUptime = in.readLong();
+        mRuntime = in.readString();
+        mFlags = in.readInt();
+        mTableData.readFromParcel(in);
+        readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
+        if (!mSysMemUsage.readFromParcel(in)) {
+            return;
+        }
+
+        int NPROC = in.readInt();
+        if (NPROC < 0) {
+            mReadError = "bad process count: " + NPROC;
+            return;
+        }
+        while (NPROC > 0) {
+            NPROC--;
+            final String procName = readCommonString(in, version);
+            if (procName == null) {
+                mReadError = "bad process name";
+                return;
+            }
+            int NUID = in.readInt();
+            if (NUID < 0) {
+                mReadError = "bad uid count: " + NUID;
+                return;
+            }
+            while (NUID > 0) {
+                NUID--;
+                final int uid = in.readInt();
+                if (uid < 0) {
+                    mReadError = "bad uid: " + uid;
+                    return;
+                }
+                final String pkgName = readCommonString(in, version);
+                if (pkgName == null) {
+                    mReadError = "bad process package name";
+                    return;
+                }
+                final int vers = in.readInt();
+                ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
+                if (proc != null) {
+                    if (!proc.readFromParcel(in, false)) {
+                        return;
+                    }
+                } else {
+                    proc = new ProcessState(this, pkgName, uid, vers, procName);
+                    if (!proc.readFromParcel(in, true)) {
+                        return;
+                    }
+                }
+                if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid
+                        + " " + proc);
+                mProcesses.put(procName, uid, proc);
+            }
+        }
+
+        if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes");
+
+        int NPKG = in.readInt();
+        if (NPKG < 0) {
+            mReadError = "bad package count: " + NPKG;
+            return;
+        }
+        while (NPKG > 0) {
+            NPKG--;
+            final String pkgName = readCommonString(in, version);
+            if (pkgName == null) {
+                mReadError = "bad package name";
+                return;
+            }
+            int NUID = in.readInt();
+            if (NUID < 0) {
+                mReadError = "bad uid count: " + NUID;
+                return;
+            }
+            while (NUID > 0) {
+                NUID--;
+                final int uid = in.readInt();
+                if (uid < 0) {
+                    mReadError = "bad uid: " + uid;
+                    return;
+                }
+                int NVERS = in.readInt();
+                if (NVERS < 0) {
+                    mReadError = "bad versions count: " + NVERS;
+                    return;
+                }
+                while (NVERS > 0) {
+                    NVERS--;
+                    final int vers = in.readInt();
+                    PackageState pkgState = new PackageState(pkgName, uid);
+                    SparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
+                    if (vpkg == null) {
+                        vpkg = new SparseArray<PackageState>();
+                        mPackages.put(pkgName, uid, vpkg);
+                    }
+                    vpkg.put(vers, pkgState);
+                    int NPROCS = in.readInt();
+                    if (NPROCS < 0) {
+                        mReadError = "bad package process count: " + NPROCS;
+                        return;
+                    }
+                    while (NPROCS > 0) {
+                        NPROCS--;
+                        String procName = readCommonString(in, version);
+                        if (procName == null) {
+                            mReadError = "bad package process name";
+                            return;
+                        }
+                        int hasProc = in.readInt();
+                        if (DEBUG_PARCEL) Slog.d(TAG, "Reading package " + pkgName + " " + uid
+                                + " process " + procName + " hasProc=" + hasProc);
+                        ProcessState commonProc = mProcesses.get(procName, uid);
+                        if (DEBUG_PARCEL) Slog.d(TAG, "Got common proc " + procName + " " + uid
+                                + ": " + commonProc);
+                        if (commonProc == null) {
+                            mReadError = "no common proc: " + procName;
+                            return;
+                        }
+                        if (hasProc != 0) {
+                            // The process for this package is unique to the package; we
+                            // need to load it.  We don't need to do anything about it if
+                            // it is not unique because if someone later looks for it
+                            // they will find and use it from the global procs.
+                            ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
+                            if (proc != null) {
+                                if (!proc.readFromParcel(in, false)) {
+                                    return;
+                                }
+                            } else {
+                                proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
+                                        0);
+                                if (!proc.readFromParcel(in, true)) {
+                                    return;
+                                }
+                            }
+                            if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
+                                    + procName + " " + uid + " " + proc);
+                            pkgState.mProcesses.put(procName, proc);
+                        } else {
+                            if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
+                                    + procName + " " + uid + " " + commonProc);
+                            pkgState.mProcesses.put(procName, commonProc);
+                        }
+                    }
+                    int NSRVS = in.readInt();
+                    if (NSRVS < 0) {
+                        mReadError = "bad package service count: " + NSRVS;
+                        return;
+                    }
+                    while (NSRVS > 0) {
+                        NSRVS--;
+                        String serviceName = in.readString();
+                        if (serviceName == null) {
+                            mReadError = "bad package service name";
+                            return;
+                        }
+                        String processName = version > 9 ? readCommonString(in, version) : null;
+                        ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
+                        if (serv == null) {
+                            serv = new ServiceState(this, pkgName, serviceName, processName, null);
+                        }
+                        if (!serv.readFromParcel(in)) {
+                            return;
+                        }
+                        if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " service: "
+                                + serviceName + " " + uid + " " + serv);
+                        pkgState.mServices.put(serviceName, serv);
+                    }
+                }
+            }
+        }
+
+        mIndexToCommonString = null;
+
+        if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!");
+    }
+
+    public PackageState getPackageStateLocked(String packageName, int uid, int vers) {
+        SparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
+        if (vpkg == null) {
+            vpkg = new SparseArray<PackageState>();
+            mPackages.put(packageName, uid, vpkg);
+        }
+        PackageState as = vpkg.get(vers);
+        if (as != null) {
+            return as;
+        }
+        as = new PackageState(packageName, uid);
+        vpkg.put(vers, as);
+        return as;
+    }
+
+    public ProcessState getProcessStateLocked(String packageName, int uid, int vers,
+            String processName) {
+        final PackageState pkgState = getPackageStateLocked(packageName, uid, vers);
+        ProcessState ps = pkgState.mProcesses.get(processName);
+        if (ps != null) {
+            return ps;
+        }
+        ProcessState commonProc = mProcesses.get(processName, uid);
+        if (commonProc == null) {
+            commonProc = new ProcessState(this, packageName, uid, vers, processName);
+            mProcesses.put(processName, uid, commonProc);
+            if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc);
+        }
+        if (!commonProc.isMultiPackage()) {
+            if (packageName.equals(commonProc.getPackage()) && vers == commonProc.getVersion()) {
+                // This common process is not in use by multiple packages, and
+                // is for the calling package, so we can just use it directly.
+                ps = commonProc;
+                if (DEBUG) Slog.d(TAG, "GETPROC also using for pkg " + commonProc);
+            } else {
+                if (DEBUG) Slog.d(TAG, "GETPROC need to split common proc!");
+                // This common process has not been in use by multiple packages,
+                // but it was created for a different package than the caller.
+                // We need to convert it to a multi-package process.
+                commonProc.setMultiPackage(true);
+                // To do this, we need to make two new process states, one a copy
+                // of the current state for the process under the original package
+                // name, and the second a free new process state for it as the
+                // new package name.
+                long now = SystemClock.uptimeMillis();
+                // First let's make a copy of the current process state and put
+                // that under the now unique state for its original package name.
+                final PackageState commonPkgState = getPackageStateLocked(commonProc.getPackage(),
+                        uid, commonProc.getVersion());
+                if (commonPkgState != null) {
+                    ProcessState cloned = commonProc.clone(now);
+                    if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.getPackage()
+                            + ": " + cloned);
+                    commonPkgState.mProcesses.put(commonProc.getName(), cloned);
+                    // If this has active services, we need to update their process pointer
+                    // to point to the new package-specific process state.
+                    for (int i=commonPkgState.mServices.size()-1; i>=0; i--) {
+                        ServiceState ss = commonPkgState.mServices.valueAt(i);
+                        if (ss.getProcess() == commonProc) {
+                            if (DEBUG) Slog.d(TAG, "GETPROC switching service to cloned: " + ss);
+                            ss.setProcess(cloned);
+                        } else if (DEBUG) {
+                            Slog.d(TAG, "GETPROC leaving proc of " + ss);
+                        }
+                    }
+                } else {
+                    Slog.w(TAG, "Cloning proc state: no package state " + commonProc.getPackage()
+                            + "/" + uid + " for proc " + commonProc.getName());
+                }
+                // And now make a fresh new process state for the new package name.
+                ps = new ProcessState(commonProc, packageName, uid, vers, processName, now);
+                if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
+            }
+        } else {
+            // The common process is for multiple packages, we need to create a
+            // separate object for the per-package data.
+            ps = new ProcessState(commonProc, packageName, uid, vers, processName,
+                    SystemClock.uptimeMillis());
+            if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
+        }
+        pkgState.mProcesses.put(processName, ps);
+        if (DEBUG) Slog.d(TAG, "GETPROC adding new pkg " + ps);
+        return ps;
+    }
+
+    public ServiceState getServiceStateLocked(String packageName, int uid, int vers,
+            String processName, String className) {
+        final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid, vers);
+        ServiceState ss = as.mServices.get(className);
+        if (ss != null) {
+            if (DEBUG) Slog.d(TAG, "GETSVC: returning existing " + ss);
+            return ss;
+        }
+        final ProcessState ps = processName != null
+                ? getProcessStateLocked(packageName, uid, vers, processName) : null;
+        ss = new ServiceState(this, packageName, className, processName, ps);
+        as.mServices.put(className, ss);
+        if (DEBUG) Slog.d(TAG, "GETSVC: creating " + ss + " in " + ps);
+        return ss;
+    }
+
+    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
+            boolean dumpAll, boolean activeOnly) {
+        long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+                mStartTime, now);
+        boolean sepNeeded = false;
+        if (mSysMemUsage.getKeyCount() > 0) {
+            pw.println("System memory usage:");
+            mSysMemUsage.dump(pw, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
+            sepNeeded = true;
+        }
+        ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+        boolean printedHeader = false;
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            final String pkgName = pkgMap.keyAt(ip);
+            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                final int uid = uids.keyAt(iu);
+                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+                for (int iv=0; iv<vpkgs.size(); iv++) {
+                    final int vers = vpkgs.keyAt(iv);
+                    final PackageState pkgState = vpkgs.valueAt(iv);
+                    final int NPROCS = pkgState.mProcesses.size();
+                    final int NSRVS = pkgState.mServices.size();
+                    final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+                    if (!pkgMatch) {
+                        boolean procMatch = false;
+                        for (int iproc=0; iproc<NPROCS; iproc++) {
+                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                            if (reqPackage.equals(proc.getName())) {
+                                procMatch = true;
+                                break;
+                            }
+                        }
+                        if (!procMatch) {
+                            continue;
+                        }
+                    }
+                    if (NPROCS > 0 || NSRVS > 0) {
+                        if (!printedHeader) {
+                            if (sepNeeded) pw.println();
+                            pw.println("Per-Package Stats:");
+                            printedHeader = true;
+                            sepNeeded = true;
+                        }
+                        pw.print("  * "); pw.print(pkgName); pw.print(" / ");
+                                UserHandle.formatUid(pw, uid); pw.print(" / v");
+                                pw.print(vers); pw.println(":");
+                    }
+                    if (!dumpSummary || dumpAll) {
+                        for (int iproc=0; iproc<NPROCS; iproc++) {
+                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                            if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+                                continue;
+                            }
+                            if (activeOnly && !proc.isInUse()) {
+                                pw.print("      (Not active: ");
+                                        pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
+                                continue;
+                            }
+                            pw.print("      Process ");
+                            pw.print(pkgState.mProcesses.keyAt(iproc));
+                            if (proc.getCommonProcess().isMultiPackage()) {
+                                pw.print(" (multi, ");
+                            } else {
+                                pw.print(" (unique, ");
+                            }
+                            pw.print(proc.getDurationsBucketCount());
+                            pw.print(" entries)");
+                            pw.println(":");
+                            proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                                    ALL_PROC_STATES, now);
+                            proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                                    ALL_PROC_STATES);
+                            proc.dumpInternalLocked(pw, "        ", dumpAll);
+                        }
+                    } else {
+                        ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
+                        for (int iproc=0; iproc<NPROCS; iproc++) {
+                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                            if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+                                continue;
+                            }
+                            if (activeOnly && !proc.isInUse()) {
+                                continue;
+                            }
+                            procs.add(proc);
+                        }
+                        DumpUtils.dumpProcessSummaryLocked(pw, "      ", procs,
+                                ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
+                                now, totalTime);
+                    }
+                    for (int isvc=0; isvc<NSRVS; isvc++) {
+                        ServiceState svc = pkgState.mServices.valueAt(isvc);
+                        if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
+                            continue;
+                        }
+                        if (activeOnly && !svc.isInUse()) {
+                            pw.print("      (Not active: ");
+                                    pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
+                            continue;
+                        }
+                        if (dumpAll) {
+                            pw.print("      Service ");
+                        } else {
+                            pw.print("      * ");
+                        }
+                        pw.print(pkgState.mServices.keyAt(isvc));
+                        pw.println(":");
+                        pw.print("        Process: "); pw.println(svc.getProcessName());
+                        svc.dumpStats(pw, "        ", "          ", "    ",
+                                now, totalTime, dumpSummary, dumpAll);
+                    }
+                }
+            }
+        }
+
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        printedHeader = false;
+        int numShownProcs = 0, numTotalProcs = 0;
+        for (int ip=0; ip<procMap.size(); ip++) {
+            String procName = procMap.keyAt(ip);
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                numTotalProcs++;
+                final ProcessState proc = uids.valueAt(iu);
+                if (proc.hasAnyData()) {
+                    continue;
+                }
+                if (!proc.isMultiPackage()) {
+                    continue;
+                }
+                if (reqPackage != null && !reqPackage.equals(procName)
+                        && !reqPackage.equals(proc.getPackage())) {
+                    continue;
+                }
+                numShownProcs++;
+                if (sepNeeded) {
+                    pw.println();
+                }
+                sepNeeded = true;
+                if (!printedHeader) {
+                    pw.println("Multi-Package Common Processes:");
+                    printedHeader = true;
+                }
+                if (activeOnly && !proc.isInUse()) {
+                    pw.print("      (Not active: "); pw.print(procName); pw.println(")");
+                    continue;
+                }
+                pw.print("  * "); pw.print(procName); pw.print(" / ");
+                        UserHandle.formatUid(pw, uid);
+                        pw.print(" ("); pw.print(proc.getDurationsBucketCount());
+                        pw.print(" entries)"); pw.println(":");
+                proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                        ALL_PROC_STATES, now);
+                proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES);
+                proc.dumpInternalLocked(pw, "        ", dumpAll);
+            }
+        }
+        if (dumpAll) {
+            pw.println();
+            pw.print("  Total procs: "); pw.print(numShownProcs);
+                    pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+        }
+
+        if (sepNeeded) {
+            pw.println();
+        }
+        if (dumpSummary) {
+            pw.println("Summary:");
+            dumpSummaryLocked(pw, reqPackage, now, activeOnly);
+        } else {
+            dumpTotalsLocked(pw, now);
+        }
+
+        if (dumpAll) {
+            pw.println();
+            pw.println("Internal state:");
+            /*
+            pw.print("  Num long arrays: "); pw.println(mLongs.size());
+            pw.print("  Next long entry: "); pw.println(mNextLong);
+            */
+            pw.print("  mRunning="); pw.println(mRunning);
+        }
+    }
+
+    public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) {
+        long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+                mStartTime, now);
+        dumpFilteredSummaryLocked(pw, null, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly);
+        pw.println();
+        dumpTotalsLocked(pw, now);
+    }
+
+    long printMemoryCategory(PrintWriter pw, String prefix, String label, double memWeight,
+            long totalTime, long curTotalMem, int samples) {
+        if (memWeight != 0) {
+            long mem = (long)(memWeight * 1024 / totalTime);
+            pw.print(prefix);
+            pw.print(label);
+            pw.print(": ");
+            DebugUtils.printSizeValue(pw, mem);
+            pw.print(" (");
+            pw.print(samples);
+            pw.print(" samples)");
+            pw.println();
+            return curTotalMem + mem;
+        }
+        return curTotalMem;
+    }
+
+    void dumpTotalsLocked(PrintWriter pw, long now) {
+        pw.println("Run time Stats:");
+        DumpUtils.dumpSingleTime(pw, "  ", mMemFactorDurations, mMemFactor, mStartTime, now);
+        pw.println();
+        pw.println("Memory usage:");
+        TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
+                ALL_MEM_ADJ);
+        computeTotalMemoryUse(totalMem, now);
+        long totalPss = 0;
+        totalPss = printMemoryCategory(pw, "  ", "Kernel ", totalMem.sysMemKernelWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        totalPss = printMemoryCategory(pw, "  ", "Native ", totalMem.sysMemNativeWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        for (int i=0; i<STATE_COUNT; i++) {
+            // Skip restarting service state -- that is not actually a running process.
+            if (i != STATE_SERVICE_RESTARTING) {
+                totalPss = printMemoryCategory(pw, "  ", DumpUtils.STATE_NAMES[i],
+                        totalMem.processStateWeight[i], totalMem.totalTime, totalPss,
+                        totalMem.processStateSamples[i]);
+            }
+        }
+        totalPss = printMemoryCategory(pw, "  ", "Cached ", totalMem.sysMemCachedWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        totalPss = printMemoryCategory(pw, "  ", "Free   ", totalMem.sysMemFreeWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        totalPss = printMemoryCategory(pw, "  ", "Z-Ram  ", totalMem.sysMemZRamWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        pw.print("  TOTAL  : ");
+        DebugUtils.printSizeValue(pw, totalPss);
+        pw.println();
+        printMemoryCategory(pw, "  ", DumpUtils.STATE_NAMES[STATE_SERVICE_RESTARTING],
+                totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
+                totalMem.processStateSamples[STATE_SERVICE_RESTARTING]);
+        pw.println();
+        pw.print("          Start time: ");
+        pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
+        pw.println();
+        pw.print("  Total elapsed time: ");
+        TimeUtils.formatDuration(
+                (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
+                        - mTimePeriodStartRealtime, pw);
+        boolean partial = true;
+        if ((mFlags&FLAG_SHUTDOWN) != 0) {
+            pw.print(" (shutdown)");
+            partial = false;
+        }
+        if ((mFlags&FLAG_SYSPROPS) != 0) {
+            pw.print(" (sysprops)");
+            partial = false;
+        }
+        if ((mFlags&FLAG_COMPLETE) != 0) {
+            pw.print(" (complete)");
+            partial = false;
+        }
+        if (partial) {
+            pw.print(" (partial)");
+        }
+        pw.print(' ');
+        pw.print(mRuntime);
+        pw.println();
+    }
+
+    void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
+            int[] screenStates, int[] memStates, int[] procStates,
+            int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) {
+        ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
+                procStates, sortProcStates, now, reqPackage, activeOnly);
+        if (procs.size() > 0) {
+            if (header != null) {
+                pw.println();
+                pw.println(header);
+            }
+            DumpUtils.dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
+                    sortProcStates, now, totalTime);
+        }
+    }
+
+    public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
+            int[] procStates, int sortProcStates[], long now, String reqPackage,
+            boolean activeOnly) {
+        final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
+        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            final String pkgName = pkgMap.keyAt(ip);
+            final SparseArray<SparseArray<PackageState>> procs = pkgMap.valueAt(ip);
+            for (int iu=0; iu<procs.size(); iu++) {
+                final SparseArray<PackageState> vpkgs = procs.valueAt(iu);
+                final int NVERS = vpkgs.size();
+                for (int iv=0; iv<NVERS; iv++) {
+                    final PackageState state = vpkgs.valueAt(iv);
+                    final int NPROCS = state.mProcesses.size();
+                    final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        final ProcessState proc = state.mProcesses.valueAt(iproc);
+                        if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+                            continue;
+                        }
+                        if (activeOnly && !proc.isInUse()) {
+                            continue;
+                        }
+                        foundProcs.add(proc.getCommonProcess());
+                    }
+                }
+            }
+        }
+        ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size());
+        for (int i=0; i<foundProcs.size(); i++) {
+            ProcessState proc = foundProcs.valueAt(i);
+            if (proc.computeProcessTimeLocked(screenStates, memStates, procStates, now) > 0) {
+                outProcs.add(proc);
+                if (procStates != sortProcStates) {
+                    proc.computeProcessTimeLocked(screenStates, memStates, sortProcStates, now);
+                }
+            }
+        }
+        Collections.sort(outProcs, ProcessState.COMPARATOR);
+        return outProcs;
+    }
+
+    public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
+        final long now = SystemClock.uptimeMillis();
+        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+        pw.println("vers,5");
+        pw.print("period,"); pw.print(mTimePeriodStartClockStr);
+        pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
+        pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
+        boolean partial = true;
+        if ((mFlags&FLAG_SHUTDOWN) != 0) {
+            pw.print(",shutdown");
+            partial = false;
+        }
+        if ((mFlags&FLAG_SYSPROPS) != 0) {
+            pw.print(",sysprops");
+            partial = false;
+        }
+        if ((mFlags&FLAG_COMPLETE) != 0) {
+            pw.print(",complete");
+            partial = false;
+        }
+        if (partial) {
+            pw.print(",partial");
+        }
+        pw.println();
+        pw.print("config,"); pw.println(mRuntime);
+        for (int ip=0; ip<pkgMap.size(); ip++) {
+            final String pkgName = pkgMap.keyAt(ip);
+            if (reqPackage != null && !reqPackage.equals(pkgName)) {
+                continue;
+            }
+            final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                final int uid = uids.keyAt(iu);
+                final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+                for (int iv=0; iv<vpkgs.size(); iv++) {
+                    final int vers = vpkgs.keyAt(iv);
+                    final PackageState pkgState = vpkgs.valueAt(iv);
+                    final int NPROCS = pkgState.mProcesses.size();
+                    final int NSRVS = pkgState.mServices.size();
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
+                                pkgState.mProcesses.keyAt(iproc), now);
+                    }
+                    for (int isvc=0; isvc<NSRVS; isvc++) {
+                        final String serviceName = DumpUtils.collapseString(pkgName,
+                                pkgState.mServices.keyAt(isvc));
+                        final ServiceState svc = pkgState.mServices.valueAt(isvc);
+                        svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
+                    }
+                }
+            }
+        }
+
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        for (int ip=0; ip<procMap.size(); ip++) {
+            String procName = procMap.keyAt(ip);
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                final int uid = uids.keyAt(iu);
+                final ProcessState procState = uids.valueAt(iu);
+                procState.dumpProcCheckin(pw, procName, uid, now);
+            }
+        }
+        pw.print("total");
+        DumpUtils.dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor, mStartTime, now);
+        pw.println();
+        final int sysMemUsageCount = mSysMemUsage.getKeyCount();
+        if (sysMemUsageCount > 0) {
+            pw.print("sysmemusage");
+            for (int i=0; i<sysMemUsageCount; i++) {
+                final int key = mSysMemUsage.getKeyAt(i);
+                final int type = SparseMappingTable.getIdFromKey(key);
+                pw.print(",");
+                DumpUtils.printProcStateTag(pw, type);
+                for (int j=SYS_MEM_USAGE_SAMPLE_COUNT; j<SYS_MEM_USAGE_COUNT; j++) {
+                    if (j > SYS_MEM_USAGE_CACHED_MINIMUM) {
+                        pw.print(":");
+                    }
+                    pw.print(mSysMemUsage.getValue(key, j));
+                }
+            }
+        }
+        pw.println();
+        TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
+                ALL_MEM_ADJ);
+        computeTotalMemoryUse(totalMem, now);
+        pw.print("weights,");
+        pw.print(totalMem.totalTime);
+        pw.print(",");
+        pw.print(totalMem.sysMemCachedWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemFreeWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemZRamWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemKernelWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemNativeWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        for (int i=0; i<STATE_COUNT; i++) {
+            pw.print(",");
+            pw.print(totalMem.processStateWeight[i]);
+            pw.print(":");
+            pw.print(totalMem.processStateSamples[i]);
+        }
+        pw.println();
+    }
+
+
+    final public static class ProcessStateHolder {
+        public final int appVersion;
+        public ProcessState state;
+
+        public ProcessStateHolder(int _appVersion) {
+            appVersion = _appVersion;
+        }
+    }
+
+    public static final class PackageState {
+        public final ArrayMap<String, ProcessState> mProcesses
+                = new ArrayMap<String, ProcessState>();
+        public final ArrayMap<String, ServiceState> mServices
+                = new ArrayMap<String, ServiceState>();
+        public final String mPackageName;
+        public final int mUid;
+
+        public PackageState(String packageName, int uid) {
+            mUid = uid;
+            mPackageName = packageName;
+        }
+    }
+
+    public static final class ProcessDataCollection {
+        final int[] screenStates;
+        final int[] memStates;
+        final int[] procStates;
+
+        public long totalTime;
+        public long numPss;
+        public long minPss;
+        public long avgPss;
+        public long maxPss;
+        public long minUss;
+        public long avgUss;
+        public long maxUss;
+
+        public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
+            screenStates = _screenStates;
+            memStates = _memStates;
+            procStates = _procStates;
+        }
+
+        void print(PrintWriter pw, long overallTime, boolean full) {
+            if (totalTime > overallTime) {
+                pw.print("*");
+            }
+            DumpUtils.printPercent(pw, (double) totalTime / (double) overallTime);
+            if (numPss > 0) {
+                pw.print(" (");
+                DebugUtils.printSizeValue(pw, minPss * 1024);
+                pw.print("-");
+                DebugUtils.printSizeValue(pw, avgPss * 1024);
+                pw.print("-");
+                DebugUtils.printSizeValue(pw, maxPss * 1024);
+                pw.print("/");
+                DebugUtils.printSizeValue(pw, minUss * 1024);
+                pw.print("-");
+                DebugUtils.printSizeValue(pw, avgUss * 1024);
+                pw.print("-");
+                DebugUtils.printSizeValue(pw, maxUss * 1024);
+                if (full) {
+                    pw.print(" over ");
+                    pw.print(numPss);
+                }
+                pw.print(")");
+            }
+        }
+    }
+
+    public static class TotalMemoryUseCollection {
+        final int[] screenStates;
+        final int[] memStates;
+
+        public TotalMemoryUseCollection(int[] _screenStates, int[] _memStates) {
+            screenStates = _screenStates;
+            memStates = _memStates;
+        }
+
+        public long totalTime;
+        public long[] processStatePss = new long[STATE_COUNT];
+        public double[] processStateWeight = new double[STATE_COUNT];
+        public long[] processStateTime = new long[STATE_COUNT];
+        public int[] processStateSamples = new int[STATE_COUNT];
+        public long[] sysMemUsage = new long[SYS_MEM_USAGE_COUNT];
+        public double sysMemCachedWeight;
+        public double sysMemFreeWeight;
+        public double sysMemZRamWeight;
+        public double sysMemKernelWeight;
+        public double sysMemNativeWeight;
+        public int sysMemSamples;
+    }
+
+}
diff --git a/core/java/com/android/internal/app/procstats/PssTable.java b/core/java/com/android/internal/app/procstats/PssTable.java
new file mode 100644
index 0000000..b6df983
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/PssTable.java
@@ -0,0 +1,108 @@
+/*
+ * 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.app.procstats;
+
+import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
+
+/**
+ * Class to accumulate PSS data.
+ */
+public class PssTable extends SparseMappingTable.Table {
+    /**
+     * Construct the PssTable with 'tableData' as backing store
+     * for the longs data.
+     */
+    public PssTable(SparseMappingTable tableData) {
+        super(tableData);
+    }
+
+    /**
+     * Merge the the values from the other table into this one.
+     */
+    public void mergeStats(PssTable that) {
+        final int N = that.getKeyCount();
+        for (int i=0; i<N; i++) {
+            final int key = that.getKeyAt(i);
+            final int state = SparseMappingTable.getIdFromKey(key);
+            mergeStats(state, (int)that.getValue(key, PSS_SAMPLE_COUNT),
+                    that.getValue(key, PSS_MINIMUM),
+                    that.getValue(key, PSS_AVERAGE),
+                    that.getValue(key, PSS_MAXIMUM),
+                    that.getValue(key, PSS_USS_MINIMUM),
+                    that.getValue(key, PSS_USS_AVERAGE),
+                    that.getValue(key, PSS_USS_MAXIMUM));
+        }
+    }
+
+    /**
+     * Merge the supplied PSS data in.  The new min pss will be the minimum of the existing
+     * one and the new one, the average will now incorporate the new average, etc.
+     */
+    public void mergeStats(int state, int inCount, long minPss, long avgPss, long maxPss,
+            long minUss, long avgUss, long maxUss) {
+        final int key = getOrAddKey((byte)state, PSS_COUNT);
+        final long count = getValue(key, PSS_SAMPLE_COUNT);
+        if (count == 0) {
+            setValue(key, PSS_SAMPLE_COUNT, inCount);
+            setValue(key, PSS_MINIMUM, minPss);
+            setValue(key, PSS_AVERAGE, avgPss);
+            setValue(key, PSS_MAXIMUM, maxPss);
+            setValue(key, PSS_USS_MINIMUM, minUss);
+            setValue(key, PSS_USS_AVERAGE, avgUss);
+            setValue(key, PSS_USS_MAXIMUM, maxUss);
+        } else {
+            setValue(key, PSS_SAMPLE_COUNT, count + inCount);
+
+            long val;
+
+            val = getValue(key, PSS_MINIMUM);
+            if (val > minPss) {
+                setValue(key, PSS_MINIMUM, minPss);
+            }
+
+            val = getValue(key, PSS_AVERAGE);
+            setValue(key, PSS_AVERAGE,
+                    (long)(((val*(double)count)+(avgPss*(double)inCount)) / (count+inCount)));
+
+            val = getValue(key, PSS_MAXIMUM);
+            if (val < maxPss) {
+                setValue(key, PSS_MAXIMUM, maxPss);
+            }
+
+            val = getValue(key, PSS_USS_MINIMUM);
+            if (val > minUss) {
+                setValue(key, PSS_USS_MINIMUM, minUss);
+            }
+
+            val = getValue(key, PSS_USS_AVERAGE);
+            setValue(key, PSS_AVERAGE,
+                    (long)(((val*(double)count)+(avgUss*(double)inCount)) / (count+inCount)));
+
+            val = getValue(key, PSS_USS_MAXIMUM);
+            if (val < maxUss) {
+                setValue(key, PSS_USS_MAXIMUM, maxUss);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java
new file mode 100644
index 0000000..2e11c43
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/ServiceState.java
@@ -0,0 +1,502 @@
+/*
+ * 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.app.procstats;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.app.procstats.ProcessStats;
+import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+public final class ServiceState {
+    private static final String TAG = "ProcessStats";
+    private static final boolean DEBUG = false;
+
+    public static final int SERVICE_RUN = 0;
+    public static final int SERVICE_STARTED = 1;
+    public static final int SERVICE_BOUND = 2;
+    public static final int SERVICE_EXEC = 3;
+    public static final int SERVICE_COUNT = 4;
+
+    private final String mPackage;
+    private final String mProcessName;
+    private final String mName;
+    private final DurationsTable mDurations;
+
+    private ProcessState mProc;
+    private Object mOwner;
+
+    private int mRunCount;
+    private int mRunState = STATE_NOTHING;
+    private long mRunStartTime;
+
+    private boolean mStarted;
+    private boolean mRestarting;
+    private int mStartedCount;
+    private int mStartedState = STATE_NOTHING;
+    private long mStartedStartTime;
+
+    private int mBoundCount;
+    private int mBoundState = STATE_NOTHING;
+    private long mBoundStartTime;
+
+    private int mExecCount;
+    private int mExecState = STATE_NOTHING;
+    private long mExecStartTime;
+
+    public ServiceState(ProcessStats processStats, String pkg, String name,
+            String processName, ProcessState proc) {
+        mPackage = pkg;
+        mName = name;
+        mProcessName = processName;
+        mProc = proc;
+        mDurations = new DurationsTable(processStats.mTableData);
+    }
+
+    public String getPackage() {
+        return mPackage;
+    }
+    
+    public String getProcessName() {
+        return mProcessName;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public ProcessState getProcess() {
+        return mProc;
+    }
+
+    public void setProcess(ProcessState proc) {
+        mProc = proc;
+    }
+
+    public void setMemFactor(int memFactor, long now) {
+        if (isRestarting()) {
+            setRestarting(true, memFactor, now);
+        } else if (isInUse()) {
+            if (mStartedState != ProcessStats.STATE_NOTHING) {
+                setStarted(true, memFactor, now);
+            }
+            if (mBoundState != ProcessStats.STATE_NOTHING) {
+                setBound(true, memFactor, now);
+            }
+            if (mExecState != ProcessStats.STATE_NOTHING) {
+                setExecuting(true, memFactor, now);
+            }
+        }
+    }
+
+    public void applyNewOwner(Object newOwner) {
+        if (mOwner != newOwner) {
+            if (mOwner == null) {
+                mOwner = newOwner;
+                mProc.incActiveServices(mName);
+            } else {
+                // There was already an old owner, reset this object for its
+                // new owner.
+                mOwner = newOwner;
+                if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
+                    long now = SystemClock.uptimeMillis();
+                    if (mStarted) {
+                        if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+                                + " from " + mOwner + " while started: pkg="
+                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        setStarted(false, 0, now);
+                    }
+                    if (mBoundState != STATE_NOTHING) {
+                        if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+                                + " from " + mOwner + " while bound: pkg="
+                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        setBound(false, 0, now);
+                    }
+                    if (mExecState != STATE_NOTHING) {
+                        if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+                                + " from " + mOwner + " while executing: pkg="
+                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        setExecuting(false, 0, now);
+                    }
+                }
+            }
+        }
+    }
+
+    public void clearCurrentOwner(Object owner, boolean silently) {
+        if (mOwner == owner) {
+            mProc.decActiveServices(mName);
+            if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
+                long now = SystemClock.uptimeMillis();
+                if (mStarted) {
+                    if (!silently) {
+                        Slog.wtfStack(TAG, "Service owner " + owner
+                                + " cleared while started: pkg=" + mPackage + " service="
+                                + mName + " proc=" + mProc);
+                    }
+                    setStarted(false, 0, now);
+                }
+                if (mBoundState != STATE_NOTHING) {
+                    if (!silently) {
+                        Slog.wtfStack(TAG, "Service owner " + owner
+                                + " cleared while bound: pkg=" + mPackage + " service="
+                                + mName + " proc=" + mProc);
+                    }
+                    setBound(false, 0, now);
+                }
+                if (mExecState != STATE_NOTHING) {
+                    if (!silently) {
+                        Slog.wtfStack(TAG, "Service owner " + owner
+                                + " cleared while exec: pkg=" + mPackage + " service="
+                                + mName + " proc=" + mProc);
+                    }
+                    setExecuting(false, 0, now);
+                }
+            }
+            mOwner = null;
+        }
+    }
+
+    public boolean isInUse() {
+        return mOwner != null || mRestarting;
+    }
+
+    public boolean isRestarting() {
+        return mRestarting;
+    }
+
+    public void add(ServiceState other) {
+        mDurations.addDurations(other.mDurations);
+        mRunCount += other.mRunCount;
+        mStartedCount += other.mStartedCount;
+        mBoundCount += other.mBoundCount;
+        mExecCount += other.mExecCount;
+    }
+
+    public void resetSafely(long now) {
+        mDurations.resetTable();
+        mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
+        mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
+        mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
+        mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
+        mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
+    }
+
+    public void writeToParcel(Parcel out, long now) {
+        mDurations.writeToParcel(out);
+        out.writeInt(mRunCount);
+        out.writeInt(mStartedCount);
+        out.writeInt(mBoundCount);
+        out.writeInt(mExecCount);
+    }
+
+    public boolean readFromParcel(Parcel in) {
+        if (!mDurations.readFromParcel(in)) {
+            return false;
+        }
+        mRunCount = in.readInt();
+        mStartedCount = in.readInt();
+        mBoundCount = in.readInt();
+        mExecCount = in.readInt();
+        return true;
+    }
+
+    public void commitStateTime(long now) {
+        if (mRunState != STATE_NOTHING) {
+            mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+                    now - mRunStartTime);
+            mRunStartTime = now;
+        }
+        if (mStartedState != STATE_NOTHING) {
+            mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+                    now - mStartedStartTime);
+            mStartedStartTime = now;
+        }
+        if (mBoundState != STATE_NOTHING) {
+            mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
+                    now - mBoundStartTime);
+            mBoundStartTime = now;
+        }
+        if (mExecState != STATE_NOTHING) {
+            mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT),
+                    now - mExecStartTime);
+            mExecStartTime = now;
+        }
+    }
+
+    private void updateRunning(int memFactor, long now) {
+        final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
+                || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
+        if (mRunState != state) {
+            if (mRunState != STATE_NOTHING) {
+                mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+                        now - mRunStartTime);
+            } else if (state != STATE_NOTHING) {
+                mRunCount++;
+            }
+            mRunState = state;
+            mRunStartTime = now;
+        }
+    }
+
+    public void setStarted(boolean started, int memFactor, long now) {
+        if (mOwner == null) {
+            Slog.wtf(TAG, "Starting service " + this + " without owner");
+        }
+        mStarted = started;
+        updateStartedState(memFactor, now);
+    }
+
+    public void setRestarting(boolean restarting, int memFactor, long now) {
+        mRestarting = restarting;
+        updateStartedState(memFactor, now);
+    }
+
+    public void updateStartedState(int memFactor, long now) {
+        final boolean wasStarted = mStartedState != STATE_NOTHING;
+        final boolean started = mStarted || mRestarting;
+        final int state = started ? memFactor : STATE_NOTHING;
+        if (mStartedState != state) {
+            if (mStartedState != STATE_NOTHING) {
+                mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+                        now - mStartedStartTime);
+            } else if (started) {
+                mStartedCount++;
+            }
+            mStartedState = state;
+            mStartedStartTime = now;
+            mProc = mProc.pullFixedProc(mPackage);
+            if (wasStarted != started) {
+                if (started) {
+                    mProc.incStartedServices(memFactor, now, mName);
+                } else {
+                    mProc.decStartedServices(memFactor, now, mName);
+                }
+            }
+            updateRunning(memFactor, now);
+        }
+    }
+
+    public void setBound(boolean bound, int memFactor, long now) {
+        if (mOwner == null) {
+            Slog.wtf(TAG, "Binding service " + this + " without owner");
+        }
+        final int state = bound ? memFactor : STATE_NOTHING;
+        if (mBoundState != state) {
+            if (mBoundState != STATE_NOTHING) {
+                mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
+                        now - mBoundStartTime);
+            } else if (bound) {
+                mBoundCount++;
+            }
+            mBoundState = state;
+            mBoundStartTime = now;
+            updateRunning(memFactor, now);
+        }
+    }
+
+    public void setExecuting(boolean executing, int memFactor, long now) {
+        if (mOwner == null) {
+            Slog.wtf(TAG, "Executing service " + this + " without owner");
+        }
+        final int state = executing ? memFactor : STATE_NOTHING;
+        if (mExecState != state) {
+            if (mExecState != STATE_NOTHING) {
+                mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT),
+                        now - mExecStartTime);
+            } else if (executing) {
+                mExecCount++;
+            }
+            mExecState = state;
+            mExecStartTime = now;
+            updateRunning(memFactor, now);
+        }
+    }
+
+    public long getDuration(int opType, int curState, long startTime, int memFactor,
+            long now) {
+        int state = opType + (memFactor*SERVICE_COUNT);
+        long time = mDurations.getValueForId((byte)state);
+        if (curState == memFactor) {
+            time += now - startTime;
+        }
+        return time;
+    }
+
+    public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix,
+            long now, long totalTime, boolean dumpSummary, boolean dumpAll) {
+        dumpStats(pw, prefix, prefixInner, headerPrefix, "Running",
+                mRunCount, ServiceState.SERVICE_RUN, mRunState,
+                mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
+        dumpStats(pw, prefix, prefixInner, headerPrefix, "Started",
+                mStartedCount, ServiceState.SERVICE_STARTED, mStartedState,
+                mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
+        dumpStats(pw, prefix, prefixInner, headerPrefix, "Bound",
+                mBoundCount, ServiceState.SERVICE_BOUND, mBoundState,
+                mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
+        dumpStats(pw, prefix, prefixInner, headerPrefix, "Executing",
+                mExecCount, ServiceState.SERVICE_EXEC, mExecState,
+                mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
+        if (dumpAll) {
+            if (mOwner != null) {
+                pw.print("        mOwner="); pw.println(mOwner);
+            }
+            if (mStarted || mRestarting) {
+                pw.print("        mStarted="); pw.print(mStarted);
+                pw.print(" mRestarting="); pw.println(mRestarting);
+            }
+        }
+    }
+
+    private void dumpStats(PrintWriter pw, String prefix, String prefixInner,
+            String headerPrefix, String header,
+            int count, int serviceType, int state, long startTime, long now, long totalTime,
+            boolean dumpAll) {
+        if (count != 0) {
+            if (dumpAll) {
+                pw.print(prefix); pw.print(header);
+                pw.print(" op count "); pw.print(count); pw.println(":");
+                dumpTime(pw, prefixInner, serviceType, state, startTime, now);
+            } else {
+                long myTime = dumpTime(null, null, serviceType, state, startTime, now);
+                pw.print(prefix); pw.print(headerPrefix); pw.print(header);
+                pw.print(" count "); pw.print(count);
+                pw.print(" / time ");
+                DumpUtils.printPercent(pw, (double)myTime/(double)totalTime);
+                pw.println();
+            }
+        }
+    }
+
+    public long dumpTime(PrintWriter pw, String prefix,
+            int serviceType, int curState, long curStartTime, long now) {
+        long totalTime = 0;
+        int printedScreen = -1;
+        for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) {
+            int printedMem = -1;
+            for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) {
+                int state = imem+iscreen;
+                long time = getDuration(serviceType, curState, curStartTime, state, now);
+                String running = "";
+                if (curState == state && pw != null) {
+                    running = " (running)";
+                }
+                if (time != 0) {
+                    if (pw != null) {
+                        pw.print(prefix);
+                        DumpUtils.printScreenLabel(pw, printedScreen != iscreen
+                                ? iscreen : STATE_NOTHING);
+                        printedScreen = iscreen;
+                        DumpUtils.printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING,
+                                (char)0);
+                        printedMem = imem;
+                        pw.print(": ");
+                        TimeUtils.formatDuration(time, pw); pw.println(running);
+                    }
+                    totalTime += time;
+                }
+            }
+        }
+        if (totalTime != 0 && pw != null) {
+            pw.print(prefix);
+            pw.print("    TOTAL: ");
+            TimeUtils.formatDuration(totalTime, pw);
+            pw.println();
+        }
+        return totalTime;
+    }
+
+    public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+            String serviceName, long now) {
+        dumpTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName,
+                ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now);
+        dumpTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName,
+                ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now);
+        dumpTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName,
+                ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now);
+        dumpTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName,
+                ServiceState.SERVICE_EXEC, mExecCount, mExecState, mExecStartTime, now);
+    }
+
+    private void dumpTimeCheckin(PrintWriter pw, String label, String packageName,
+            int uid, int vers, String serviceName, int serviceType, int opCount,
+            int curState, long curStartTime, long now) {
+        if (opCount <= 0) {
+            return;
+        }
+        pw.print(label);
+        pw.print(",");
+        pw.print(packageName);
+        pw.print(",");
+        pw.print(uid);
+        pw.print(",");
+        pw.print(vers);
+        pw.print(",");
+        pw.print(serviceName);
+        pw.print(",");
+        pw.print(opCount);
+        boolean didCurState = false;
+        final int N = mDurations.getKeyCount();
+        for (int i=0; i<N; i++) {
+            final int key = mDurations.getKeyAt(i);
+            long time = mDurations.getValue(key);
+            int type = SparseMappingTable.getIdFromKey(key);
+            int memFactor = type / ServiceState.SERVICE_COUNT;
+            type %= ServiceState.SERVICE_COUNT;
+            if (type != serviceType) {
+                continue;
+            }
+            if (curState == memFactor) {
+                didCurState = true;
+                time += now - curStartTime;
+            }
+            DumpUtils.printAdjTagAndValue(pw, memFactor, time);
+        }
+        if (!didCurState && curState != STATE_NOTHING) {
+            DumpUtils.printAdjTagAndValue(pw, curState, now - curStartTime);
+        }
+        pw.println();
+    }
+
+
+    public String toString() {
+        return "ServiceState{" + Integer.toHexString(System.identityHashCode(this))
+                + " " + mName + " pkg=" + mPackage + " proc="
+                + Integer.toHexString(System.identityHashCode(this)) + "}";
+    }
+}
diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
new file mode 100644
index 0000000..7252276
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
@@ -0,0 +1,631 @@
+/*
+ * 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.app.procstats;
+
+import android.os.Build;
+import android.os.Parcel;
+import android.util.Slog;
+import libcore.util.EmptyArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import com.android.internal.util.GrowingArrayUtils;
+
+/**
+ * Class that contains a set of tables mapping byte ids to long values.
+ *
+ * This class is used to store the ProcessStats data.  This data happens to be
+ * a set of very sparse tables, that is mostly append or overwrite, with infrequent
+ * resets of the data.
+ *
+ * Data is stored as a list of large long[] arrays containing the actual values.  There are a
+ * set of Table objects that each contain a small array mapping the byte IDs to a position
+ * in the larger arrays.
+ *
+ * The data itself is either a single long value or a range of long values which are always
+ * stored continguously in one of the long arrays. When the caller allocates a slot with
+ * getOrAddKey, an int key is returned.  That key can be re-retreived with getKey without
+ * allocating the value.  The data can then be set or retrieved with that key.
+ */
+public class SparseMappingTable {
+    private static final String TAG = "SparseMappingTable";
+
+    // How big each array is.
+    public static final int ARRAY_SIZE = 4096;
+
+    public static final int INVALID_KEY = 0xffffffff;
+
+    // Where the "type"/"state" part of the data appears in an offset integer.
+    private static final int ID_SHIFT = 0;
+    private static final int ID_MASK = 0xff;
+    // Where the "which array" part of the data appears in an offset integer.
+    private static final int ARRAY_SHIFT = 8;
+    private static final int ARRAY_MASK = 0xff;
+    // Where the "index into array" part of the data appears in an offset integer.
+    private static final int INDEX_SHIFT = 16;
+    private static final int INDEX_MASK = 0xffff;
+
+    private int mSequence;
+    private int mNextIndex;
+    private final ArrayList<long[]> mLongs = new ArrayList<long[]>();
+
+    /**
+     * A table of data as stored in a SparseMappingTable.
+     */
+    public static class Table {
+        // When mSequence is this this our data better be empty
+        private static final int UNINITIALIZED_SEQUENCE = -1;
+
+        private SparseMappingTable mParent;
+        private int mSequence = UNINITIALIZED_SEQUENCE;
+        private int[] mTable;
+        private int mSize;
+
+        public Table(SparseMappingTable parent) {
+            mParent = parent;
+            mSequence = parent.mSequence;
+        }
+
+        /**
+         * Pulls the data from 'copyFrom' and stores it in our own longs table.
+         *
+         * @param copyFrom   The Table to copy from
+         * @param valueCount The number of values to copy for each key
+         */
+        public void copyFrom(Table copyFrom, int valueCount) {
+            mTable = null;
+            mSize = 0;
+
+            final int N = copyFrom.getKeyCount();
+            for (int i=0; i<N; i++) {
+                final int theirKey = copyFrom.getKeyAt(i);
+                final long[] theirLongs = copyFrom.mParent.mLongs.get(getArrayFromKey(theirKey));
+
+                final byte id = SparseMappingTable.getIdFromKey(theirKey);
+
+                final int myKey = this.getOrAddKey((byte)id, valueCount);
+                final long[] myLongs = mParent.mLongs.get(getArrayFromKey(myKey));
+
+                System.arraycopy(theirLongs, getIndexFromKey(theirKey),
+                        myLongs, getIndexFromKey(myKey), valueCount);
+            }
+        }
+
+        /**
+         * Allocates data in the buffer, and stores that key in the mapping for this
+         * table.
+         *
+         * @param id    The id of the item (will be used in making the key)
+         * @param count The number of bytes to allocate.  Must be less than
+         *              SparseMappingTable.ARRAY_SIZE.
+         *
+         * @return The 'key' for this data value, which contains both the id itself
+         *         and the location in the long arrays that the data is actually stored
+         *         but should be considered opaque to the caller.
+         */
+        public int getOrAddKey(byte id, int count) {
+            // This is the only place we add data to mParent.mLongs, so this is the time
+            // to update our sequence to match there.
+            if (mSequence == UNINITIALIZED_SEQUENCE) {
+                mSequence = mParent.mSequence;
+            }
+
+            assertConsistency();
+
+            final int idx = binarySearch(id);
+            if (idx >= 0) {
+                // Found
+                return mTable[idx];
+            } else {
+                // Not found. Need to allocate it.
+
+                // Get an array with enough space to store 'count' values.
+                final ArrayList<long[]> list = mParent.mLongs;
+                int whichArray = list.size()-1;
+                long[] array = list.get(whichArray);
+                if (mParent.mNextIndex + count > array.length) {
+                    // if it won't fit then make a new array.
+                    array = new long[ARRAY_SIZE];
+                    list.add(array);
+                    whichArray++;
+                    mParent.mNextIndex = 0;
+                }
+
+                // The key is a combination of whichArray, which index in that array, and
+                // the table value itself, which will be used for lookup
+                final int key = (whichArray << ARRAY_SHIFT)
+                        | (mParent.mNextIndex << INDEX_SHIFT)
+                        | (((int)id) << ID_SHIFT);
+
+                mParent.mNextIndex += count;
+
+                // Store the key in the sparse lookup table for this Table object.
+                mTable = GrowingArrayUtils.insert(mTable != null ? mTable : EmptyArray.INT,
+                        mSize, ~idx, key);
+                mSize++;
+
+                return key;
+            }
+        }
+
+        /**
+         * Looks up a key in the table.
+         *
+         * @return The key from this table or INVALID_KEY if the id is not found.
+         */
+        public int getKey(byte id) {
+            assertConsistency();
+
+            final int idx = binarySearch(id);
+            if (idx >= 0) {
+                return mTable[idx];
+            } else {
+                return INVALID_KEY;
+            }
+        }
+
+        /**
+         * Get the value for the given key and offset from that key.
+         *
+         * @param key   A key as obtained from getKey or getOrAddKey.
+         * @param value The value to set.
+         */
+        public long getValue(int key) {
+            return getValue(key, 0);
+        }
+
+        /**
+         * Get the value for the given key and offset from that key.
+         *
+         * @param key   A key as obtained from getKey or getOrAddKey.
+         * @param index The offset from that key.  Must be less than the count
+         *              provided to getOrAddKey when the space was allocated.
+         * @param value The value to set.
+         *
+         * @return the value, or 0 in case of an error
+         */
+        public long getValue(int key, int index) {
+            assertConsistency();
+
+            try {
+                final long[] array = mParent.mLongs.get(getArrayFromKey(key));
+                return array[getIndexFromKey(key) + index];
+            } catch (IndexOutOfBoundsException ex) {
+                logOrThrow("key=0x" + Integer.toHexString(key)
+                        + " index=" + index + " -- " + dumpInternalState(), ex);
+                return 0;
+            }
+        }
+
+        /**
+         * Set the value for the given id at offset 0 from that id.
+         * If the id is not found, return 0 instead.
+         *
+         * @param id    The id of the item.
+         */
+        public long getValueForId(byte id) {
+            return getValueForId(id, 0);
+        }
+
+        /**
+         * Set the value for the given id and index offset from that id.
+         * If the id is not found, return 0 instead.
+         *
+         * @param id    The id of the item.
+         * @param index The offset from that key.  Must be less than the count
+         *              provided to getOrAddKey when the space was allocated.
+         */
+        public long getValueForId(byte id, int index) {
+            assertConsistency();
+
+            final int idx = binarySearch(id);
+            if (idx >= 0) {
+                final int key = mTable[idx];
+                try {
+                    final long[] array = mParent.mLongs.get(getArrayFromKey(key));
+                    return array[getIndexFromKey(key) + index];
+                } catch (IndexOutOfBoundsException ex) {
+                    logOrThrow("id=0x" + Integer.toHexString(id) + " idx=" + idx
+                            + " key=0x" + Integer.toHexString(key) + " index=" + index
+                            + " -- " + dumpInternalState(), ex);
+                    return 0;
+                }
+            } else {
+                return 0;
+            }
+        }
+
+        /**
+         * Return the raw storage long[] for the given key.
+         */
+        public long[] getArrayForKey(int key) {
+            assertConsistency();
+
+            return mParent.mLongs.get(getArrayFromKey(key));
+        }
+
+        /**
+         * Set the value for the given key and offset from that key.
+         *
+         * @param key   A key as obtained from getKey or getOrAddKey.
+         * @param value The value to set.
+         */
+        public void setValue(int key, long value) {
+            setValue(key, 0, value);
+        }
+
+        /**
+         * Set the value for the given key and offset from that key.
+         *
+         * @param key   A key as obtained from getKey or getOrAddKey.
+         * @param index The offset from that key.  Must be less than the count
+         *              provided to getOrAddKey when the space was allocated.
+         * @param value The value to set.
+         */
+        public void setValue(int key, int index, long value) {
+            assertConsistency();
+
+            if (value < 0) {
+                logOrThrow("can't store negative values"
+                        + " key=0x" + Integer.toHexString(key)
+                        + " index=" + index + " value=" + value
+                        + " -- " + dumpInternalState());
+                return;
+            }
+
+            try {
+                final long[] array = mParent.mLongs.get(getArrayFromKey(key));
+                array[getIndexFromKey(key) + index] = value;
+            } catch (IndexOutOfBoundsException ex) {
+                logOrThrow("key=0x" + Integer.toHexString(key)
+                        + " index=" + index + " value=" + value
+                        + " -- " + dumpInternalState(), ex);
+                return;
+            }
+        }
+
+        /**
+         * Clear out the table, and reset the sequence numbers so future writes
+         * without allocations will assert.
+         */
+        public void resetTable() {
+            // Clear out our table.
+            mTable = null;
+            mSize = 0;
+
+            // Reset our sequence number.  This will make all read/write calls
+            // start to fail, and then when we re-allocate it will be re-synced
+            // to that of mParent.
+            mSequence = UNINITIALIZED_SEQUENCE;
+        }
+
+        /**
+         * Write the keys stored in the table to the parcel. The parent must
+         * be separately written. Does not save the actual data.
+         */
+        public void writeToParcel(Parcel out) {
+            out.writeInt(mSequence);
+            out.writeInt(mSize);
+            for (int i=0; i<mSize; i++) {
+                out.writeInt(mTable[i]);
+            }
+        }
+
+        /**
+         * Read the keys from the parcel. The parent (with its long array) must
+         * have been previously initialized.
+         */
+        public boolean readFromParcel(Parcel in) {
+            // Read the state
+            mSequence = in.readInt();
+            mSize = in.readInt();
+            if (mSize != 0) {
+                mTable = new int[mSize];
+                for (int i=0; i<mSize; i++) {
+                    mTable[i] = in.readInt();
+                }
+            } else {
+                mTable = null;
+            }
+
+            // Make sure we're all healthy
+            if (validateKeys(true)) {
+                return true;
+            } else {
+                // Clear it out
+                mSize = 0;
+                mTable = null;
+                return false;
+            }
+        }
+
+        /**
+         * Return the number of keys that have been added to this Table.
+         */
+        public int getKeyCount() {
+            return mSize;
+        }
+
+        /**
+         * Get the key at the given index in our table.
+         */
+        public int getKeyAt(int i) {
+            return mTable[i];
+        }
+
+        /**
+         * Throw an exception if one of a variety of internal consistency checks fails.
+         */
+        private void assertConsistency() {
+            // Assert that our sequewnce number has been initialized. If it hasn't
+            // that means someone tried to read or write data without allocating it
+            // since we were created or reset.
+            if (mSequence == UNINITIALIZED_SEQUENCE) {
+                logOrThrow("mSequence == UNINITIALIZED_SEQUENCE in"
+                        + " SparseMappingTable.Table.  -- "
+                        + dumpInternalState());
+                return;
+            }
+
+            // Assert that our sequence number matches mParent's.  If it isn't that means
+            // we have been reset and our
+            if (mSequence != mParent.mSequence) {
+                if (mSequence < mParent.mSequence) {
+                    logOrThrow("Sequence mismatch. SparseMappingTable.resetTable()"
+                            + " called but not Table.resetTable() -- "
+                            + dumpInternalState());
+                    return;
+                } else if (mSequence > mParent.mSequence) {
+                    logOrThrow("Sequence mismatch. Table.resetTable()"
+                            + " called but not SparseMappingTable.resetTable() -- "
+                            + dumpInternalState());
+                    return;
+                }
+            }
+        }
+
+        /**
+         * Finds the 'id' inside the array of length size (physical size of the array
+         * is not used).
+         *
+         * @return The index of the array, or the bitwise not (~index) of where it
+         * would go if you wanted to insert 'id' into the array.
+         */
+        private int binarySearch(byte id) {
+            int lo = 0;
+            int hi = mSize - 1;
+
+            while (lo <= hi) {
+                int mid = (lo + hi) >>> 1;
+                byte midId = (byte)((mTable[mid] >> ID_SHIFT) & ID_MASK);
+
+                if (midId < id) {
+                    lo = mid + 1;
+                } else if (midId > id) {
+                    hi = mid - 1;
+                } else {
+                    return mid;  // id found
+                }
+            }
+            return ~lo;  // id not present
+        }
+
+        /**
+         * Check that all the keys are valid locations in the long arrays.
+         *
+         * If any aren't, log it and return false. Else return true.
+         */
+        private boolean validateKeys(boolean log) {
+            ArrayList<long[]> longs = mParent.mLongs;
+            final int longsSize = longs.size();
+
+            final int N = mSize;
+            for (int i=0; i<N; i++) {
+                final int key = mTable[i];
+                final int arrayIndex = getArrayFromKey(key);
+                final int index = getIndexFromKey(key);
+                if (arrayIndex >= longsSize || index >= longs.get(arrayIndex).length) {
+                    if (log) {
+                        Slog.w(TAG, "Invalid stats at index " + i + " -- " + dumpInternalState());
+                    }
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public String dumpInternalState() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("SparseMappingTable.Table{mSequence=");
+            sb.append(mSequence);
+            sb.append(" mParent.mSequence=");
+            sb.append(mParent.mSequence);
+            sb.append(" mParent.mLongs.size()=");
+            sb.append(mParent.mLongs.size());
+            sb.append(" mSize=");
+            sb.append(mSize);
+            sb.append(" mTable=");
+            if (mTable == null) {
+                sb.append("null");
+            } else {
+                final int N = mTable.length;
+                sb.append('[');
+                for (int i=0; i<N; i++) {
+                    final int key = mTable[i];
+                    sb.append("0x");
+                    sb.append(Integer.toHexString((key >> ID_SHIFT) & ID_MASK));
+                    sb.append("/0x");
+                    sb.append(Integer.toHexString((key >> ARRAY_SHIFT) & ARRAY_MASK));
+                    sb.append("/0x");
+                    sb.append(Integer.toHexString((key >> INDEX_SHIFT) & INDEX_MASK));
+                    if (i != N-1) {
+                        sb.append(", ");
+                    }
+                }
+                sb.append(']');
+            }
+            sb.append(" clazz=");
+            sb.append(getClass().getName());
+            sb.append('}');
+
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Wipe out all the data.
+     */
+    public void reset() {
+        // Clear out mLongs, and prime it with a new array of data
+        mLongs.clear();
+        mLongs.add(new long[ARRAY_SIZE]);
+        mNextIndex = 0;
+
+        // Increment out sequence counter, because all of the tables will
+        // now be out of sync with the data.
+        mSequence++;
+    }
+
+    /**
+     * Write the data arrays to the parcel.
+     */
+    public void writeToParcel(Parcel out) {
+        out.writeInt(mSequence);
+        out.writeInt(mNextIndex);
+        final int N = mLongs.size();
+        out.writeInt(N);
+        for (int i=0; i<N-1; i++) {
+            final long[] array = mLongs.get(i);
+            out.writeInt(array.length);
+            writeCompactedLongArray(out, array, array.length);
+        }
+        // save less for the last one. upon re-loading they'll just start a new array.
+        final long[] lastLongs = mLongs.get(N-1);
+        out.writeInt(mNextIndex);
+        writeCompactedLongArray(out, lastLongs, mNextIndex);
+    }
+
+    /**
+     * Read the data arrays from the parcel.
+     */
+    public void readFromParcel(Parcel in) {
+        mSequence = in.readInt();
+        mNextIndex = in.readInt();
+
+        mLongs.clear();
+        final int N = in.readInt();
+        for (int i=0; i<N; i++) {
+            final int size = in.readInt();
+            final long[] array = new long[size];
+            readCompactedLongArray(in, array, size);
+            mLongs.add(array);
+        }
+    }
+
+    /**
+     * Write the long array to the parcel in a compacted form.  Does not allow negative
+     * values in the array.
+     */
+    private static void writeCompactedLongArray(Parcel out, long[] array, int num) {
+        for (int i=0; i<num; i++) {
+            long val = array[i];
+            if (val < 0) {
+                Slog.w(TAG, "Time val negative: " + val);
+                val = 0;
+            }
+            if (val <= Integer.MAX_VALUE) {
+                out.writeInt((int)val);
+            } else {
+                int top = ~((int)((val>>32)&0x7fffffff));
+                int bottom = (int)(val&0xfffffff);
+                out.writeInt(top);
+                out.writeInt(bottom);
+            }
+        }
+    }
+
+    /**
+     * Read the compacted array into the long[].
+     */
+    private static void readCompactedLongArray(Parcel in, long[] array, int num) {
+        final int alen = array.length;
+        if (num > alen) {
+            logOrThrow("bad array lengths: got " + num + " array is " + alen);
+            return;
+        }
+        int i;
+        for (i=0; i<num; i++) {
+            int val = in.readInt();
+            if (val >= 0) {
+                array[i] = val;
+            } else {
+                int bottom = in.readInt();
+                array[i] = (((long)~val)<<32) | bottom;
+            }
+        }
+        while (i < alen) {
+            array[i] = 0;
+            i++;
+        }
+    }
+
+    /**
+     * Extract the id from a key.
+     */
+    public static byte getIdFromKey(int key) {
+        return (byte)((key >> ID_SHIFT) & ID_MASK);
+    }
+
+    /**
+     * Gets the index of the array in the list of arrays.
+     *
+     * Not to be confused with getIndexFromKey.
+     */
+    public static int getArrayFromKey(int key) {
+        return (key >> ARRAY_SHIFT) & ARRAY_MASK;
+    }
+
+    /**
+     * Gets the index of a value in a long[].
+     *
+     * Not to be confused with getArrayFromKey.
+     */
+    public static int getIndexFromKey(int key) {
+        return (key >> INDEX_SHIFT) & INDEX_MASK;
+    }
+
+    /**
+     * Do a Slog.wtf or throw an exception (thereby crashing the system process if
+     * this is a debug build.)
+     */
+    private static void logOrThrow(String message) {
+        logOrThrow(message, new RuntimeException("Stack trace"));
+    }
+
+    /**
+     * Do a Slog.wtf or throw an exception (thereby crashing the system process if
+     * this is an eng build.)
+     */
+    private static void logOrThrow(String message, Throwable th) {
+        Slog.wtf(TAG, message, th);
+        if (Build.TYPE.equals("eng")) {
+            throw new RuntimeException(message, th);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/procstats/SysMemUsageTable.java b/core/java/com/android/internal/app/procstats/SysMemUsageTable.java
new file mode 100644
index 0000000..e71bc55
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/SysMemUsageTable.java
@@ -0,0 +1,189 @@
+/*
+ * 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.app.procstats;
+
+import android.util.DebugUtils;
+
+import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_SAMPLE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_COUNT;
+
+import java.io.PrintWriter;
+
+
+/**
+ * Class to accumulate system mem usage data.
+ */
+public class SysMemUsageTable extends SparseMappingTable.Table {
+    /**
+     * Construct the SysMemUsageTable with 'tableData' as backing store
+     * for the longs data.
+     */
+    public SysMemUsageTable(SparseMappingTable tableData) {
+        super(tableData);
+    }
+
+    /**
+     * Merge the stats given into our own values.
+     *
+     * @param that  SysMemUsageTable to copy from.
+     */
+    public void mergeStats(SysMemUsageTable that) {
+        final int N = that.getKeyCount();
+        for (int i=0; i<N; i++) {
+            final int key = that.getKeyAt(i);
+
+            final int state = SparseMappingTable.getIdFromKey(key);
+            final long[] addData = that.getArrayForKey(key);
+            final int addOff = SparseMappingTable.getIndexFromKey(key);
+
+            mergeStats(state, addData, addOff);
+        }
+    }
+
+    /**
+     * Merge the stats given into our own values.
+     *
+     * @param state     The state
+     * @param addData   The data array to copy
+     * @param addOff    The index in addOff to start copying from
+     */
+    public void mergeStats(int state, long[] addData, int addOff) {
+        final int key = getOrAddKey((byte)state, SYS_MEM_USAGE_COUNT);
+        
+        final long[] dstData = getArrayForKey(key);
+        final int dstOff = SparseMappingTable.getIndexFromKey(key);
+
+        SysMemUsageTable.mergeSysMemUsage(dstData, dstOff, addData, addOff);
+    }
+
+    /**
+     * Return a long[] containing the merge of all of the usage in this table.
+     */
+    public long[] getTotalMemUsage() {
+        long[] total = new long[SYS_MEM_USAGE_COUNT];
+        final int N = getKeyCount();
+        for (int i=0; i<N; i++) {
+            final int key = getKeyAt(i);
+
+            final long[] addData = getArrayForKey(key);
+            final int addOff = SparseMappingTable.getIndexFromKey(key);
+
+            SysMemUsageTable.mergeSysMemUsage(total, 0, addData, addOff);
+        }
+        return total;
+    }
+
+    /**
+     * Merge the stats from one raw long[] into another.
+     *
+     * @param dstData The destination array
+     * @param dstOff  The index in the destination array to start from
+     * @param addData The source array
+     * @param addOff  The index in the source array to start from
+     */
+    public static void mergeSysMemUsage(long[] dstData, int dstOff,
+            long[] addData, int addOff) {
+        final long dstCount = dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT];
+        final long addCount = addData[addOff+SYS_MEM_USAGE_SAMPLE_COUNT];
+        if (dstCount == 0) {
+            dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = addCount;
+            for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i++) {
+                dstData[dstOff+i] = addData[addOff+i];
+            }
+        } else if (addCount > 0) {
+            dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = dstCount + addCount;
+            for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i+=3) {
+                if (dstData[dstOff+i] > addData[addOff+i]) {
+                    dstData[dstOff+i] = addData[addOff+i];
+                }
+                dstData[dstOff+i+1] = (long)(
+                        ((dstData[dstOff+i+1]*(double)dstCount)
+                                + (addData[addOff+i+1]*(double)addCount))
+                                / (dstCount+addCount) );
+                if (dstData[dstOff+i+2] < addData[addOff+i+2]) {
+                    dstData[dstOff+i+2] = addData[addOff+i+2];
+                }
+            }
+        }
+    }
+
+
+    public void dump(PrintWriter pw, String prefix, int[] screenStates, int[] memStates) {
+        int printedScreen = -1;
+        for (int is=0; is<screenStates.length; is++) {
+            int printedMem = -1;
+            for (int im=0; im<memStates.length; im++) {
+                final int iscreen = screenStates[is];
+                final int imem = memStates[im];
+                final int bucket = ((iscreen + imem) * STATE_COUNT);
+                long count = getValueForId((byte)bucket, SYS_MEM_USAGE_SAMPLE_COUNT);
+                if (count > 0) {
+                    pw.print(prefix);
+                    if (screenStates.length > 1) {
+                        DumpUtils.printScreenLabel(pw, printedScreen != iscreen
+                                ? iscreen : STATE_NOTHING);
+                        printedScreen = iscreen;
+                    }
+                    if (memStates.length > 1) {
+                        DumpUtils.printMemLabel(pw,
+                                printedMem != imem ? imem : STATE_NOTHING, '\0');
+                        printedMem = imem;
+                    }
+                    pw.print(": ");
+                    pw.print(count);
+                    pw.println(" samples:");
+                    dumpCategory(pw, prefix, "  Cached", bucket, SYS_MEM_USAGE_CACHED_MINIMUM);
+                    dumpCategory(pw, prefix, "  Free", bucket, SYS_MEM_USAGE_FREE_MINIMUM);
+                    dumpCategory(pw, prefix, "  ZRam", bucket, SYS_MEM_USAGE_ZRAM_MINIMUM);
+                    dumpCategory(pw, prefix, "  Kernel", bucket, SYS_MEM_USAGE_KERNEL_MINIMUM);
+                    dumpCategory(pw, prefix, "  Native", bucket, SYS_MEM_USAGE_NATIVE_MINIMUM);
+                }
+            }
+        }
+    }
+
+    private void dumpCategory(PrintWriter pw, String prefix, String label, int bucket, int index) {
+        pw.print(prefix); pw.print(label);
+        pw.print(": ");
+        DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index) * 1024);
+        pw.print(" min, ");
+        DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index + 1) * 1024);
+        pw.print(" avg, ");
+        DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index+2) * 1024);
+        pw.println(" max");
+    }
+    
+}
+
+
diff --git a/core/java/com/android/internal/app/procstats/package.html b/core/java/com/android/internal/app/procstats/package.html
new file mode 100644
index 0000000..db6f78b
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
\ No newline at end of file
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 5a195cb..4260e50 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -33,8 +33,8 @@
     //
     // for AppWidgetHost
     //
-    int[] startListening(IAppWidgetHost host, String callingPackage, int hostId,
-            out List<RemoteViews> updatedViews);
+    ParceledListSlice startListening(IAppWidgetHost host, String callingPackage, int hostId,
+            in int[] appWidgetIds, out int[] updatedIds);
     void stopListening(String callingPackage, int hostId);
     int allocateAppWidgetId(String callingPackage, int hostId);
     void deleteAppWidgetId(String callingPackage, int appWidgetId);
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 10027b6..5e8f4a2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -27,7 +27,6 @@
 import android.content.pm.PackageInfo;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.os.SELinux;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructStat;
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index c0dce22..7bd64e5 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -26,6 +26,7 @@
 import android.os.UserHandle;
 import android.util.Slog;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
 
 import java.util.HashSet;
 
@@ -72,15 +73,17 @@
 
     public void register(Context context, Looper thread, UserHandle user,
             boolean externalStorage) {
+        register(context, user, externalStorage,
+                (thread == null) ? BackgroundThread.getHandler() : new Handler(thread));
+    }
+
+    public void register(Context context, UserHandle user,
+        boolean externalStorage, Handler handler) {
         if (mRegisteredContext != null) {
             throw new IllegalStateException("Already registered");
         }
         mRegisteredContext = context;
-        if (thread == null) {
-            mRegisteredHandler = BackgroundThread.getHandler();
-        } else {
-            mRegisteredHandler = new Handler(thread);
-        }
+        mRegisteredHandler = Preconditions.checkNotNull(handler);
         if (user != null) {
             context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
             context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 62e149a..f3ae688 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -32,6 +32,7 @@
 import android.text.TextUtils.SimpleStringSplitter;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.LocaleList;
 import android.util.Pair;
 import android.util.Printer;
 import android.util.Slog;
@@ -486,18 +487,28 @@
         return NOT_A_SUBTYPE_ID;
     }
 
+    private static final LocaleUtils.LocaleExtractor<InputMethodSubtype> sSubtypeToLocale =
+            new LocaleUtils.LocaleExtractor<InputMethodSubtype>() {
+                @Override
+                public Locale get(InputMethodSubtype source) {
+                    return source != null ? source.getLocaleObject() : null;
+                }
+            };
+
     @VisibleForTesting
     public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
             Resources res, InputMethodInfo imi) {
         final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
-        final String systemLocale = res.getConfiguration().locale.toString();
+        final LocaleList systemLocales = res.getConfiguration().getLocales();
+        final String systemLocale = systemLocales.get(0).toString();
         if (TextUtils.isEmpty(systemLocale)) return new ArrayList<>();
-        final String systemLanguage = res.getConfiguration().locale.getLanguage();
+        final int numSubtypes = subtypes.size();
+
+        // Handle overridesImplicitlyEnabledSubtype mechanism.
         final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new HashMap<>();
-        final int N = subtypes.size();
-        for (int i = 0; i < N; ++i) {
+        for (int i = 0; i < numSubtypes; ++i) {
             // scan overriding implicitly enabled subtypes.
-            InputMethodSubtype subtype = subtypes.get(i);
+            final InputMethodSubtype subtype = subtypes.get(i);
             if (subtype.overridesImplicitlyEnabledSubtype()) {
                 final String mode = subtype.getMode();
                 if (!applicableModeAndSubtypesMap.containsKey(mode)) {
@@ -508,56 +519,65 @@
         if (applicableModeAndSubtypesMap.size() > 0) {
             return new ArrayList<>(applicableModeAndSubtypesMap.values());
         }
-        for (int i = 0; i < N; ++i) {
+
+        final HashMap<String, ArrayList<InputMethodSubtype>> nonKeyboardSubtypesMap =
+                new HashMap<>();
+        final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>();
+
+        for (int i = 0; i < numSubtypes; ++i) {
             final InputMethodSubtype subtype = subtypes.get(i);
-            final String locale = subtype.getLocale();
             final String mode = subtype.getMode();
-            final String language = getLanguageFromLocaleString(locale);
-            // When system locale starts with subtype's locale, that subtype will be applicable
-            // for system locale. We need to make sure the languages are the same, to prevent
-            // locales like "fil" (Filipino) being matched by "fi" (Finnish).
-            //
-            // For instance, it's clearly applicable for cases like system locale = en_US and
-            // subtype = en, but it is not necessarily considered applicable for cases like system
-            // locale = en and subtype = en_US.
-            //
-            // We just call systemLocale.startsWith(locale) in this function because there is no
-            // need to find applicable subtypes aggressively unlike
-            // findLastResortApplicableSubtypeLocked.
-            //
-            // TODO: This check is broken. It won't take scripts into account and doesn't
-            // account for the mandatory conversions performed by Locale#toString.
-            if (language.equals(systemLanguage) && systemLocale.startsWith(locale)) {
-                final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode);
-                // If more applicable subtypes are contained, skip.
-                if (applicableSubtype != null) {
-                    if (systemLocale.equals(applicableSubtype.getLocale())) continue;
-                    if (!systemLocale.equals(locale)) continue;
+            if (SUBTYPE_MODE_KEYBOARD.equals(mode)) {
+                keyboardSubtypes.add(subtype);
+            } else {
+                if (!nonKeyboardSubtypesMap.containsKey(mode)) {
+                    nonKeyboardSubtypesMap.put(mode, new ArrayList<>());
                 }
-                applicableModeAndSubtypesMap.put(mode, subtype);
+                nonKeyboardSubtypesMap.get(mode).add(subtype);
             }
         }
-        final InputMethodSubtype keyboardSubtype
-                = applicableModeAndSubtypesMap.get(SUBTYPE_MODE_KEYBOARD);
-        final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>(
-                applicableModeAndSubtypesMap.values());
-        if (keyboardSubtype != null && !keyboardSubtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
-            for (int i = 0; i < N; ++i) {
-                final InputMethodSubtype subtype = subtypes.get(i);
-                final String mode = subtype.getMode();
-                if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
-                        TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
-                    applicableSubtypes.add(subtype);
+
+        final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>();
+        LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales,
+                applicableSubtypes);
+
+        if (!applicableSubtypes.isEmpty()) {
+            boolean hasAsciiCapableKeyboard = false;
+            final int numApplicationSubtypes = applicableSubtypes.size();
+            for (int i = 0; i < numApplicationSubtypes; ++i) {
+                final InputMethodSubtype subtype = applicableSubtypes.get(i);
+                if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
+                    hasAsciiCapableKeyboard = true;
+                    break;
+                }
+            }
+            if (!hasAsciiCapableKeyboard) {
+                final int numKeyboardSubtypes = keyboardSubtypes.size();
+                for (int i = 0; i < numKeyboardSubtypes; ++i) {
+                    final InputMethodSubtype subtype = keyboardSubtypes.get(i);
+                    final String mode = subtype.getMode();
+                    if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
+                            TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
+                        applicableSubtypes.add(subtype);
+                    }
                 }
             }
         }
-        if (keyboardSubtype == null) {
+
+        if (applicableSubtypes.isEmpty()) {
             InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
                     res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
             if (lastResortKeyboardSubtype != null) {
                 applicableSubtypes.add(lastResortKeyboardSubtype);
             }
         }
+
+        // For each non-keyboard mode, extract subtypes with system locales.
+        for (final ArrayList<InputMethodSubtype> subtypeList : nonKeyboardSubtypesMap.values()) {
+            LocaleUtils.filterByLanguage(subtypeList, sSubtypeToLocale, systemLocales,
+                    applicableSubtypes);
+        }
+
         return applicableSubtypes;
     }
 
@@ -834,7 +854,8 @@
         private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>();
 
         private boolean mCopyOnWrite = false;
-        private String mEnabledInputMethodsStrCache;
+        @NonNull
+        private String mEnabledInputMethodsStrCache = "";
         @UserIdInt
         private int mCurrentUserId;
         private int[] mCurrentProfileIds = new int[0];
@@ -888,14 +909,6 @@
             return imsList;
         }
 
-        @Deprecated
-        public InputMethodSettings(
-                Resources res, ContentResolver resolver,
-                HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
-                @UserIdInt int userId) {
-            this(res, resolver, methodMap, methodList, userId, false /* copyOnWrite */);
-        }
-
         public InputMethodSettings(
                 Resources res, ContentResolver resolver,
                 HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
@@ -929,7 +942,7 @@
             // TODO: mCurrentProfileIds should be updated here.
         }
 
-        private void putString(final String key, final String str) {
+        private void putString(@NonNull final String key, @Nullable final String str) {
             if (mCopyOnWrite) {
                 mCopyOnWriteDataStore.put(key, str);
             } else {
@@ -937,12 +950,15 @@
             }
         }
 
-        private String getString(final String key) {
+        @Nullable
+        private String getString(@NonNull final String key, @Nullable final String defaultValue) {
+            final String result;
             if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
-                final String result = mCopyOnWriteDataStore.get(key);
-                return result != null ? result : "";
+                result = mCopyOnWriteDataStore.get(key);
+            } else {
+                result = Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
             }
-            return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
+            return result != null ? result : defaultValue;
         }
 
         private void putInt(final String key, final int value) {
@@ -1104,16 +1120,24 @@
             return res;
         }
 
-        private void putEnabledInputMethodsStr(String str) {
+        private void putEnabledInputMethodsStr(@Nullable String str) {
             if (DEBUG) {
                 Slog.d(TAG, "putEnabledInputMethodStr: " + str);
             }
-            putString(Settings.Secure.ENABLED_INPUT_METHODS, str);
-            mEnabledInputMethodsStrCache = str;
+            if (TextUtils.isEmpty(str)) {
+                // OK to coalesce to null, since getEnabledInputMethodsStr() can take care of the
+                // empty data scenario.
+                putString(Settings.Secure.ENABLED_INPUT_METHODS, null);
+            } else {
+                putString(Settings.Secure.ENABLED_INPUT_METHODS, str);
+            }
+            // TODO: Update callers of putEnabledInputMethodsStr to make str @NonNull.
+            mEnabledInputMethodsStrCache = (str != null ? str : "");
         }
 
+        @NonNull
         public String getEnabledInputMethodsStr() {
-            mEnabledInputMethodsStrCache = getString(Settings.Secure.ENABLED_INPUT_METHODS);
+            mEnabledInputMethodsStrCache = getString(Settings.Secure.ENABLED_INPUT_METHODS, "");
             if (DEBUG) {
                 Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache
                         + ", " + mCurrentUserId);
@@ -1167,11 +1191,17 @@
             saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
         }
 
-        private void putSubtypeHistoryStr(String str) {
+        private void putSubtypeHistoryStr(@NonNull String str) {
             if (DEBUG) {
                 Slog.d(TAG, "putSubtypeHistoryStr: " + str);
             }
-            putString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
+            if (TextUtils.isEmpty(str)) {
+                // OK to coalesce to null, since getSubtypeHistoryStr() can take care of the empty
+                // data scenario.
+                putString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, null);
+            } else {
+                putString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
+            }
         }
 
         public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
@@ -1288,8 +1318,9 @@
             return imsList;
         }
 
+        @NonNull
         private String getSubtypeHistoryStr() {
-            final String history = getString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY);
+            final String history = getString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, "");
             if (DEBUG) {
                 Slog.d(TAG, "getSubtypeHistoryStr: " + history);
             }
@@ -1312,8 +1343,9 @@
             putInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, subtypeId);
         }
 
+        @Nullable
         public String getSelectedInputMethod() {
-            final String imi = getString(Settings.Secure.DEFAULT_INPUT_METHOD);
+            final String imi = getString(Settings.Secure.DEFAULT_INPUT_METHOD, null);
             if (DEBUG) {
                 Slog.d(TAG, "getSelectedInputMethodStr: " + imi);
             }
diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/core/java/com/android/internal/inputmethod/LocaleUtils.java
new file mode 100644
index 0000000..2aa660e
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/LocaleUtils.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.inputmethod;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.icu.util.ULocale;
+import android.util.LocaleList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+public final class LocaleUtils {
+
+    @VisibleForTesting
+    public interface LocaleExtractor<T> {
+        @Nullable
+        Locale get(@Nullable T source);
+    }
+
+    /**
+     * Calculates a matching score for the single desired locale.
+     *
+     * @see LocaleUtils#calculateMatchingScore(ULocale, LocaleList, byte[])
+     *
+     * @param supported The locale supported by IME subtype.
+     * @param desired The locale preferred by user.
+     * @return A score based on the locale matching for the default subtype enabling.
+     */
+    @IntRange(from=1, to=3)
+    private static byte calculateMatchingSubScore(@NonNull final ULocale supported,
+            @NonNull final ULocale desired) {
+        // Assuming supported/desired is fully expanded.
+        if (supported.equals(desired)) {
+            return 3;  // Exact match.
+        }
+
+        // Skip language matching since it was already done in calculateMatchingScore.
+
+        final String supportedScript = supported.getScript();
+        if (supportedScript.isEmpty() || !supportedScript.equals(desired.getScript())) {
+            // TODO: Need subscript matching. For example, Hanb should match with Bopo.
+            return 1;
+        }
+
+        final String supportedCountry = supported.getCountry();
+        if (supportedCountry.isEmpty() || !supportedCountry.equals(desired.getCountry())) {
+            return 2;
+        }
+
+        // Ignore others e.g. variants, extensions.
+        return 3;
+    }
+
+    /**
+     * Calculates a matching score for the desired locale list.
+     *
+     * <p>The supported locale gets a matching score of 3 if all language, script and country of the
+     * supported locale matches with the desired locale.  The supported locale gets a matching
+     * score of 2 if the language and script of the supported locale matches with the desired
+     * locale. The supported locale gets a matching score of 1 if only language of the supported
+     * locale matches with the desired locale.  The supported locale gets a matching score of 0 if
+     * the language of the supported locale doesn't match with the desired locale.</p>
+     *
+     * @param supported The locale supported by IME subtyle.
+     * @param desired The locale list preferred by user. Typically system locale list.
+     * @param out The output buffer to be stored the individual score for the desired language list.
+     * The length of {@code out} must be same as the length of {@code desired} language list.
+     * @return {@code false} if supported locale doesn't match with any desired locale list.
+     * Otherwise {@code true}.
+     */
+    private static boolean calculateMatchingScore(@NonNull final ULocale supported,
+            @NonNull final LocaleList desired, @NonNull byte[] out) {
+        if (desired.isEmpty()) {
+            return false;
+        }
+
+        boolean allZeros = true;
+        final int N = desired.size();
+        for (int i = 0; i < N; ++i) {
+            final Locale locale = desired.get(i);
+
+            if (!locale.getLanguage().equals(supported.getLanguage())) {
+                // TODO: cache the result of addLikelySubtags if it is slow.
+                out[i] = 0;
+            } else {
+                out[i] = calculateMatchingSubScore(
+                        supported, ULocale.addLikelySubtags(ULocale.forLocale(locale)));
+                if (allZeros && out[i] != 0) {
+                    allZeros = false;
+                }
+            }
+        }
+        return !allZeros;
+    }
+
+    private static final class ScoreEntry implements Comparable<ScoreEntry> {
+        public int mIndex = -1;
+        @NonNull public final byte[] mScore;  // matching score of the i-th system languages.
+
+        ScoreEntry(@NonNull byte[] score, int index) {
+            mScore = new byte[score.length];
+            set(score, index);
+        }
+
+        private void set(@NonNull byte[] score, int index) {
+            for (int i = 0; i < mScore.length; ++i) {
+                mScore[i] = score[i];
+            }
+            mIndex = index;
+        }
+
+        /**
+         * Update score and index if the given score is better than this.
+         */
+        public void updateIfBetter(@NonNull byte[] score, int index) {
+            if (compare(mScore, score) == -1) {  // mScore < score
+                set(score, index);
+            }
+        }
+
+        /**
+         * Provides comaprison for bytes[].
+         *
+         * <p> Comparison does as follows. If the first value of {@code left} is larger than the
+         * first value of {@code right}, {@code left} is large than {@code right}.  If the first
+         * value of {@code left} is less than the first value of {@code right}, {@code left} is less
+         * than {@code right}. If the first value of {@code left} and the first value of
+         * {@code right} is equal, do the same comparison to the next value. Finally if all values
+         * in {@code left} and {@code right} are equal, {@code left} and {@code right} is equal.</p>
+         *
+         * @param left The length must be equal to {@code right}.
+         * @param right The length must be equal to {@code left}.
+         * @return 1 if {@code left} is larger than {@code right}. -1 if {@code left} is less than
+         * {@code right}. 0 if {@code left} and {@code right} is equal.
+         */
+        @IntRange(from=-1, to=1)
+        private static int compare(@NonNull byte[] left, @NonNull byte[] right) {
+            for (int i = 0; i < left.length; ++i) {
+                if (left[i] > right[i]) {
+                    return 1;
+                } else if (left[i] < right[i]) {
+                    return -1;
+                }
+            }
+            return 0;
+        }
+
+        @Override
+        public int compareTo(final ScoreEntry other) {
+            return -1 * compare(mScore, other.mScore);  // Order by descending order.
+        }
+    }
+
+    /**
+     * Filters the given items based on language preferences.
+     *
+     * <p>For each language found in {@code preferredLanguages}, this method tries to copy at most
+     * one best-match item from {@code source} to {@code dest}.  For example, if
+     * {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLanguages},
+     * this method tries to copy at most one English locale, at most one Japanese, and at most one
+     * French locale from {@code source} to {@code dest}.  Here the best matching English locale
+     * will be searched from {@code source} based on matching score. For the score design, see
+     * {@link LocaleUtils#calculateMatchingScore(ULocale, LocaleList, byte[])}</p>
+     *
+     * @param sources Source items to be filtered.
+     * @param extractor Type converter from the source items to {@link Locale} object.
+     * @param preferredLanguages Ordered list of locales with which the input items will be
+     * filtered.
+     * @param dest Destination into which the filtered items will be added.
+     * @param <T> Type of the data items.
+     */
+    @VisibleForTesting
+    public static <T> void filterByLanguage(
+            @NonNull List<T> sources,
+            @NonNull LocaleExtractor<T> extractor,
+            @NonNull LocaleList preferredLanguages,
+            @NonNull ArrayList<T> dest) {
+        final HashMap<String, ScoreEntry> scoreboard = new HashMap<>();
+        final byte[] score = new byte[preferredLanguages.size()];
+
+        final int sourceSize = sources.size();
+        for (int i = 0; i < sourceSize; ++i) {
+            final Locale locale = extractor.get(sources.get(i));
+            if (locale == null ||
+                    !calculateMatchingScore(ULocale.addLikelySubtags(ULocale.forLocale(locale)),
+                            preferredLanguages, score)) {
+                continue;
+            }
+
+            final String lang = locale.getLanguage();
+            final ScoreEntry bestScore = scoreboard.get(lang);
+            if (bestScore == null) {
+                scoreboard.put(lang, new ScoreEntry(score, i));
+            } else {
+                bestScore.updateIfBetter(score, i);
+            }
+        }
+
+        final ScoreEntry[] result = scoreboard.values().toArray(new ScoreEntry[scoreboard.size()]);
+        Arrays.sort(result);
+        for (final ScoreEntry entry : result) {
+            dest.add(sources.get(entry.mIndex));
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f178c8c..1b52146 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -754,8 +754,7 @@
         try {
             ParcelFileDescriptor pfd = service.getStatisticsStream();
             if (pfd != null) {
-                FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-                try {
+                try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
                     byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
                     Parcel parcel = Parcel.obtain();
                     parcel.unmarshall(data, 0, data.length);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 648b1a5..bbefcb5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -93,7 +93,7 @@
  * battery life.  All times are represented in microseconds except where indicated
  * otherwise.
  */
-public final class BatteryStatsImpl extends BatteryStats {
+public class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
     private static final boolean DEBUG = false;
     public static final boolean DEBUG_ENERGY = false;
@@ -107,7 +107,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 141 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 142 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -126,6 +126,8 @@
     // Number of transmit power states the Bluetooth controller can be in.
     private static final int NUM_BT_TX_LEVELS = 1;
 
+    protected Clocks mClocks;
+
     private final JournaledFile mFile;
     public final AtomicFile mCheckinFile;
     public final AtomicFile mDailyFile;
@@ -185,6 +187,21 @@
         }
     }
 
+    public interface Clocks {
+        public long elapsedRealtime();
+        public long uptimeMillis();
+    }
+
+    public static class SystemClocks implements Clocks {
+        public long elapsedRealtime() {
+            return SystemClock.elapsedRealtime();
+        }
+
+        public long uptimeMillis() {
+            return SystemClock.uptimeMillis();
+        }
+    }
+
     public interface ExternalStatsSync {
         public static final int UPDATE_CPU = 0x01;
         public static final int UPDATE_WIFI = 0x02;
@@ -236,7 +253,7 @@
 
     // These are the objects that will want to do something when the device
     // is unplugged from power.
-    final TimeBase mOnBatteryTimeBase = new TimeBase();
+    protected final TimeBase mOnBatteryTimeBase = new TimeBase();
 
     // These are the objects that will want to do something when the device
     // is unplugged from power *and* the screen is off.
@@ -541,6 +558,11 @@
     }
 
     public BatteryStatsImpl() {
+        this(new SystemClocks());
+    }
+
+    public BatteryStatsImpl(Clocks clocks) {
+        init(clocks);
         mFile = null;
         mCheckinFile = null;
         mDailyFile = null;
@@ -549,25 +571,40 @@
         clearHistoryLocked();
     }
 
+    private void init(Clocks clocks) {
+        mClocks = clocks;
+        mMobileNetworkStats = new NetworkStats[] {
+                new NetworkStats(mClocks.elapsedRealtime(), 50),
+                new NetworkStats(mClocks.elapsedRealtime(), 50),
+                new NetworkStats(mClocks.elapsedRealtime(), 50)
+        };
+        mWifiNetworkStats = new NetworkStats[] {
+                new NetworkStats(mClocks.elapsedRealtime(), 50),
+                new NetworkStats(mClocks.elapsedRealtime(), 50),
+                new NetworkStats(mClocks.elapsedRealtime(), 50)
+            };
+    }
+
     public static interface TimeBaseObs {
         void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime);
         void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime);
     }
 
-    static class TimeBase {
-        private final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
+    // methods are protected not private to be VisibleForTesting
+    public static class TimeBase {
+        protected final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
 
-        private long mUptime;
-        private long mRealtime;
+        protected long mUptime;
+        protected long mRealtime;
 
-        private boolean mRunning;
+        protected boolean mRunning;
 
-        private long mPastUptime;
-        private long mUptimeStart;
-        private long mPastRealtime;
-        private long mRealtimeStart;
-        private long mUnpluggedUptime;
-        private long mUnpluggedRealtime;
+        protected long mPastUptime;
+        protected long mUptimeStart;
+        protected long mPastRealtime;
+        protected long mRealtimeStart;
+        protected long mUnpluggedUptime;
+        protected long mUnpluggedRealtime;
 
         public void dump(PrintWriter pw, String prefix) {
             StringBuilder sb = new StringBuilder(128);
@@ -608,6 +645,10 @@
             }
         }
 
+        public boolean hasObserver(TimeBaseObs observer) {
+            return mObservers.contains(observer);
+        }
+
         public void init(long uptime, long realtime) {
             mRealtime = 0;
             mUptime = 0;
@@ -626,7 +667,10 @@
             } else {
                 mUptimeStart = uptime;
                 mRealtimeStart = realtime;
+                // TODO: Since mUptimeStart was just reset and we are running, getUptime will
+                // just return mPastUptime. Also, are we sure we don't want to reset that?
                 mUnpluggedUptime = getUptime(uptime);
+                // TODO: likewise.
                 mUnpluggedRealtime = getRealtime(realtime);
             }
         }
@@ -949,13 +993,14 @@
      * State for keeping track of timing information.
      */
     public static abstract class Timer extends BatteryStats.Timer implements TimeBaseObs {
-        final int mType;
-        final TimeBase mTimeBase;
+        protected final Clocks mClocks;
+        protected final int mType;
+        protected final TimeBase mTimeBase;
 
-        int mCount;
-        int mLoadedCount;
-        int mLastCount;
-        int mUnpluggedCount;
+        protected int mCount;
+        protected int mLoadedCount;
+        protected int mLastCount;
+        protected int mUnpluggedCount;
 
         // Times are in microseconds for better accuracy when dividing by the
         // lock count, and are in "battery realtime" units.
@@ -965,32 +1010,32 @@
          * boot, to the last time something interesting happened in the
          * current run.
          */
-        long mTotalTime;
+        protected long mTotalTime;
 
         /**
          * The total time we loaded for the previous runs.  Subtract this from
          * mTotalTime to find the time for the current run of the system.
          */
-        long mLoadedTime;
+        protected long mLoadedTime;
 
         /**
          * The run time of the last run of the system, as loaded from the
          * saved data.
          */
-        long mLastTime;
+        protected long mLastTime;
 
         /**
          * The value of mTotalTime when unplug() was last called.  Subtract
          * this from mTotalTime to find the time since the last unplug from
          * power.
          */
-        long mUnpluggedTime;
+        protected long mUnpluggedTime;
 
         /**
          * The total time this timer has been running until the latest mark has been set.
          * Subtract this from mTotalTime to get the time spent running since the mark was set.
          */
-        long mTimeBeforeMark;
+        protected long mTimeBeforeMark;
 
         /**
          * Constructs from a parcel.
@@ -998,7 +1043,8 @@
          * @param timeBase
          * @param in
          */
-        Timer(int type, TimeBase timeBase, Parcel in) {
+        public Timer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
+            mClocks = clocks;
             mType = type;
             mTimeBase = timeBase;
 
@@ -1015,7 +1061,8 @@
             if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
         }
 
-        Timer(int type, TimeBase timeBase) {
+        public Timer(Clocks clocks, int type, TimeBase timeBase) {
+            mClocks = clocks;
             mType = type;
             mTimeBase = timeBase;
             timeBase.add(this);
@@ -1029,7 +1076,7 @@
          * Clear state of this timer.  Returns true if the timer is inactive
          * so can be completely dropped.
          */
-        boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset) {
             mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0;
             mCount = mLoadedCount = mLastCount = 0;
             if (detachIfReset) {
@@ -1038,7 +1085,7 @@
             return true;
         }
 
-        void detach() {
+        public void detach() {
             mTimeBase.remove(this);
         }
 
@@ -1142,13 +1189,13 @@
         }
 
 
-        void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
+        public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
             long runTime = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
             out.writeLong(runTime);
             out.writeInt(mCount);
         }
 
-        void readSummaryFromParcelLocked(Parcel in) {
+        public void readSummaryFromParcelLocked(Parcel in) {
             // Multiply by 1000 for backwards compatibility
             mTotalTime = mLoadedTime = in.readLong();
             mLastTime = 0;
@@ -1162,7 +1209,7 @@
         }
     }
 
-    public static final class SamplingTimer extends Timer {
+    public static class SamplingTimer extends Timer {
 
         /**
          * The most recent reported count from /proc/wakelocks.
@@ -1202,8 +1249,8 @@
          */
         int mUpdateVersion;
 
-        SamplingTimer(TimeBase timeBase, Parcel in) {
-            super(0, timeBase, in);
+        SamplingTimer(Clocks clocks, TimeBase timeBase, Parcel in) {
+            super(clocks, 0, timeBase, in);
             mCurrentReportedCount = in.readInt();
             mUnpluggedReportedCount = in.readInt();
             mCurrentReportedTotalTime = in.readLong();
@@ -1212,8 +1259,8 @@
             mTimeBaseRunning = timeBase.isRunning();
         }
 
-        SamplingTimer(TimeBase timeBase, boolean trackReportedValues) {
-            super(0, timeBase);
+        SamplingTimer(Clocks clocks, TimeBase timeBase, boolean trackReportedValues) {
+            super(clocks, 0, timeBase);
             mTrackingReportedValues = trackReportedValues;
             mTimeBaseRunning = timeBase.isRunning();
         }
@@ -1301,20 +1348,20 @@
             out.writeInt(mTrackingReportedValues ? 1 : 0);
         }
 
-        boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset) {
             super.reset(detachIfReset);
             setStale();
             return true;
         }
 
-        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
+        public void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
             super.writeSummaryFromParcelLocked(out, batteryRealtime);
             out.writeLong(mCurrentReportedTotalTime);
             out.writeInt(mCurrentReportedCount);
             out.writeInt(mTrackingReportedValues ? 1 : 0);
         }
 
-        void readSummaryFromParcelLocked(Parcel in) {
+        public void readSummaryFromParcelLocked(Parcel in) {
             super.readSummaryFromParcelLocked(in);
             mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
             mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
@@ -1326,7 +1373,7 @@
      * A timer that increments in batches.  It does not run for durations, but just jumps
      * for a pre-determined amount.
      */
-    public static final class BatchTimer extends Timer {
+    public static class BatchTimer extends Timer {
         final Uid mUid;
 
         /**
@@ -1344,16 +1391,16 @@
          */
         boolean mInDischarge;
 
-        BatchTimer(Uid uid, int type, TimeBase timeBase, Parcel in) {
-            super(type, timeBase, in);
+        BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase, Parcel in) {
+            super(clocks, type, timeBase, in);
             mUid = uid;
             mLastAddedTime = in.readLong();
             mLastAddedDuration = in.readLong();
             mInDischarge = timeBase.isRunning();
         }
 
-        BatchTimer(Uid uid, int type, TimeBase timeBase) {
-            super(type, timeBase);
+        BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase) {
+            super(clocks, type, timeBase);
             mUid = uid;
             mInDischarge = timeBase.isRunning();
         }
@@ -1367,7 +1414,7 @@
 
         @Override
         public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            recomputeLastDuration(SystemClock.elapsedRealtime() * 1000, false);
+            recomputeLastDuration(mClocks.elapsedRealtime() * 1000, false);
             mInDischarge = false;
             super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
         }
@@ -1416,7 +1463,7 @@
         }
 
         public void addDuration(BatteryStatsImpl stats, long durationMillis) {
-            final long now = SystemClock.elapsedRealtime() * 1000;
+            final long now = mClocks.elapsedRealtime() * 1000;
             recomputeLastDuration(now, true);
             mLastAddedTime = now;
             mLastAddedDuration = durationMillis * 1000;
@@ -1427,7 +1474,7 @@
         }
 
         public void abortLastDuration(BatteryStatsImpl stats) {
-            final long now = SystemClock.elapsedRealtime() * 1000;
+            final long now = mClocks.elapsedRealtime() * 1000;
             recomputeLastDuration(now, true);
         }
 
@@ -1438,7 +1485,7 @@
 
         @Override
         protected long computeRunTimeLocked(long curBatteryRealtime) {
-            final long overage = computeOverage(SystemClock.elapsedRealtime() * 1000);
+            final long overage = computeOverage(mClocks.elapsedRealtime() * 1000);
             if (overage > 0) {
                 return mTotalTime = overage;
             }
@@ -1446,8 +1493,8 @@
         }
 
         @Override
-        boolean reset(boolean detachIfReset) {
-            final long now = SystemClock.elapsedRealtime() * 1000;
+        public boolean reset(boolean detachIfReset) {
+            final long now = mClocks.elapsedRealtime() * 1000;
             recomputeLastDuration(now, true);
             boolean stillActive = mLastAddedTime == now;
             super.reset(!stillActive && detachIfReset);
@@ -1458,7 +1505,7 @@
     /**
      * State for keeping track of timing information.
      */
-    public static final class StopwatchTimer extends Timer {
+    public static class StopwatchTimer extends Timer {
         final Uid mUid;
         final ArrayList<StopwatchTimer> mTimerPool;
 
@@ -1485,22 +1532,22 @@
          */
         boolean mInList;
 
-        StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+        public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
                 TimeBase timeBase, Parcel in) {
-            super(type, timeBase, in);
+            super(clocks, type, timeBase, in);
             mUid = uid;
             mTimerPool = timerPool;
             mUpdateTime = in.readLong();
         }
 
-        StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+        public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
                 TimeBase timeBase) {
-            super(type, timeBase);
+            super(clocks, type, timeBase);
             mUid = uid;
             mTimerPool = timerPool;
         }
 
-        void setTimeout(long timeout) {
+        public void setTimeout(long timeout) {
             mTimeout = timeout;
         }
 
@@ -1528,7 +1575,7 @@
                     + " mAcquireTime=" + mAcquireTime);
         }
 
-        void startRunningLocked(long elapsedRealtimeMs) {
+        public void startRunningLocked(long elapsedRealtimeMs) {
             if (mNesting++ == 0) {
                 final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
                 mUpdateTime = batteryRealtime;
@@ -1550,11 +1597,11 @@
             }
         }
 
-        boolean isRunningLocked() {
+        public boolean isRunningLocked() {
             return mNesting > 0;
         }
 
-        void stopRunningLocked(long elapsedRealtimeMs) {
+        public void stopRunningLocked(long elapsedRealtimeMs) {
             // Ignore attempt to stop a timer that isn't running
             if (mNesting == 0) {
                 return;
@@ -1587,7 +1634,7 @@
             }
         }
 
-        void stopAllRunningLocked(long elapsedRealtimeMs) {
+        public void stopAllRunningLocked(long elapsedRealtimeMs) {
             if (mNesting > 0) {
                 mNesting = 1;
                 stopRunningLocked(elapsedRealtimeMs);
@@ -1632,18 +1679,18 @@
         }
 
         @Override
-        boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset) {
             boolean canDetach = mNesting <= 0;
             super.reset(canDetach && detachIfReset);
             if (mNesting > 0) {
-                mUpdateTime = mTimeBase.getRealtime(SystemClock.elapsedRealtime() * 1000);
+                mUpdateTime = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000);
             }
             mAcquireTime = mTotalTime;
             return canDetach;
         }
 
         @Override
-        void detach() {
+        public void detach() {
             super.detach();
             if (mTimerPool != null) {
                 mTimerPool.remove(this);
@@ -1651,7 +1698,7 @@
         }
 
         @Override
-        void readSummaryFromParcelLocked(Parcel in) {
+        public void readSummaryFromParcelLocked(Parcel in) {
             super.readSummaryFromParcelLocked(in);
             mNesting = 0;
         }
@@ -1906,7 +1953,7 @@
          */
         @Override
         public LongSamplingCounter getIdleTimeCounter() {
-            return mRxTimeMillis;
+            return mIdleTimeMillis;
         }
 
         /**
@@ -1943,7 +1990,7 @@
     public SamplingTimer getWakeupReasonTimerLocked(String name) {
         SamplingTimer timer = mWakeupReasonStats.get(name);
         if (timer == null) {
-            timer = new SamplingTimer(mOnBatteryTimeBase, true);
+            timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, true);
             mWakeupReasonStats.put(name, timer);
         }
         return timer;
@@ -1956,7 +2003,8 @@
     public SamplingTimer getKernelWakelockTimerLocked(String name) {
         SamplingTimer kwlt = mKernelWakelockStats.get(name);
         if (kwlt == null) {
-            kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, true /* track reported values */);
+            kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
+                    true /* track reported values */);
             mKernelWakelockStats.put(name, kwlt);
         }
         return kwlt;
@@ -2729,8 +2777,8 @@
         if (!mActiveEvents.updateState(code, name, uid, 0)) {
             return;
         }
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
     }
 
@@ -2740,7 +2788,7 @@
             // If the start clock time has changed by more than a year, then presumably
             // the previous time was completely bogus.  So we are going to figure out a
             // new time based on how much time has elapsed since we started counting.
-            mStartClockTime = currentTime - (SystemClock.elapsedRealtime()-(mRealtimeStart/1000));
+            mStartClockTime = currentTime - (mClocks.elapsedRealtime()-(mRealtimeStart/1000));
             return true;
         }
         return false;
@@ -2748,8 +2796,8 @@
 
     public void noteCurrentTimeChangedLocked() {
         final long currentTime = System.currentTimeMillis();
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
         ensureStartClockTime(currentTime);
     }
@@ -2766,8 +2814,8 @@
         if (!mRecordAllHistory) {
             return;
         }
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
     }
 
@@ -2800,15 +2848,15 @@
         if (!mRecordAllHistory) {
             return;
         }
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
     }
 
     public void noteSyncStartLocked(String name, int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         getUidStatsLocked(uid).noteStartSyncLocked(name, elapsedRealtime);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) {
             return;
@@ -2818,8 +2866,8 @@
 
     public void noteSyncFinishLocked(String name, int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         getUidStatsLocked(uid).noteStopSyncLocked(name, elapsedRealtime);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) {
             return;
@@ -2829,8 +2877,8 @@
 
     public void noteJobStartLocked(String name, int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         getUidStatsLocked(uid).noteStartJobLocked(name, elapsedRealtime);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) {
             return;
@@ -2840,8 +2888,8 @@
 
     public void noteJobFinishLocked(String name, int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         getUidStatsLocked(uid).noteStopJobLocked(name, elapsedRealtime);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) {
             return;
@@ -2854,8 +2902,8 @@
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_START, name, uid, 0)) {
             return;
         }
@@ -2867,8 +2915,8 @@
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_FINISH, name, uid, 0)) {
             return;
         }
@@ -2898,8 +2946,8 @@
             HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
                     HistoryItem.EVENT_PROC);
             if (active != null) {
-                long mSecRealtime = SystemClock.elapsedRealtime();
-                final long mSecUptime = SystemClock.uptimeMillis();
+                long mSecRealtime = mClocks.elapsedRealtime();
+                final long mSecUptime = mClocks.uptimeMillis();
                 for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
                     SparseIntArray uids = ent.getValue();
                     for (int j=0; j<uids.size(); j++) {
@@ -2913,8 +2961,8 @@
             HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
                     HistoryItem.EVENT_PROC);
             if (active != null) {
-                long mSecRealtime = SystemClock.elapsedRealtime();
-                final long mSecUptime = SystemClock.uptimeMillis();
+                long mSecRealtime = mClocks.elapsedRealtime();
+                final long mSecUptime = mClocks.uptimeMillis();
                 for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
                     SparseIntArray uids = ent.getValue();
                     for (int j=0; j<uids.size(); j++) {
@@ -3023,8 +3071,8 @@
 
     public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
             String historyName, int type, boolean unimportantForLogging) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         final int N = ws.size();
         for (int i=0; i<N; i++) {
             noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging,
@@ -3035,8 +3083,8 @@
     public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
             String historyName, int type, WorkSource newWs, int newPid, String newName,
             String newHistoryName, int newType, boolean newUnimportantForLogging) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         // For correct semantics, we start the need worksources first, so that we won't
         // make inappropriate history items as if all wake locks went away and new ones
         // appeared.  This is okay because tracking of wake locks allows nesting.
@@ -3053,8 +3101,8 @@
 
     public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
             String historyName, int type) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         final int N = ws.size();
         for (int i=0; i<N; i++) {
             noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
@@ -3072,8 +3120,8 @@
     }
 
     public void noteWakeupReasonLocked(String reason) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (DEBUG_HISTORY) Slog.v(TAG, "Wakeup reason \"" + reason +"\": "
                 + Integer.toHexString(mHistoryCur.states));
         aggregateLastWakeupUptimeLocked(uptime);
@@ -3147,8 +3195,8 @@
 
     public void noteStartSensorLocked(int uid, int sensor) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mSensorNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
@@ -3161,8 +3209,8 @@
 
     public void noteStopSensorLocked(int uid, int sensor) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         mSensorNesting--;
         if (mSensorNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
@@ -3177,8 +3225,8 @@
 
     public void noteStartGpsLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mGpsNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -3191,8 +3239,8 @@
 
     public void noteStopGpsLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         mGpsNesting--;
         if (mGpsNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -3223,8 +3271,8 @@
 
             if (state == Display.STATE_ON) {
                 // Screen turning on.
-                final long elapsedRealtime = SystemClock.elapsedRealtime();
-                final long uptime = SystemClock.uptimeMillis();
+                final long elapsedRealtime = mClocks.elapsedRealtime();
+                final long uptime = mClocks.uptimeMillis();
                 mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
                         + Integer.toHexString(mHistoryCur.states));
@@ -3235,7 +3283,7 @@
                 }
 
                 updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
-                        SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+                        mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
 
                 // Fake a wake lock, so we consider the device waked as long
                 // as the screen is on.
@@ -3248,8 +3296,8 @@
                 }
             } else if (oldState == Display.STATE_ON) {
                 // Screen turning off or dozing.
-                final long elapsedRealtime = SystemClock.elapsedRealtime();
-                final long uptime = SystemClock.uptimeMillis();
+                final long elapsedRealtime = mClocks.elapsedRealtime();
+                final long uptime = mClocks.uptimeMillis();
                 mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
                         + Integer.toHexString(mHistoryCur.states));
@@ -3263,7 +3311,7 @@
                         elapsedRealtime, uptime);
 
                 updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
-                        SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+                        mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
 
                 // Update discharge amounts.
                 if (mOnBatteryInternal) {
@@ -3279,8 +3327,8 @@
         if (bin < 0) bin = 0;
         else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
         if (mScreenBrightnessBin != bin) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
                     | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
@@ -3304,15 +3352,15 @@
     }
 
     public void noteWakeUpLocked(String reason, int reasonUid) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SCREEN_WAKE_UP,
                 reason, reasonUid);
     }
 
     public void noteInteractiveLocked(boolean interactive) {
         if (mInteractive != interactive) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
             mInteractive = interactive;
             if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
             if (interactive) {
@@ -3324,16 +3372,16 @@
     }
 
     public void noteConnectivityChangedLocked(int type, String extra) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
                 extra, type);
         mNumConnectivityChange++;
     }
 
     public void noteMobileRadioPowerState(int powerState, long timestampNs) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mMobileRadioPowerState != powerState) {
             long realElapsedRealtimeMs;
             final boolean active =
@@ -3375,8 +3423,8 @@
             int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
             mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
             mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mPowerSaveModeEnabled = enabled;
             if (enabled) {
                 mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG;
@@ -3394,9 +3442,9 @@
     }
 
     public void noteDeviceIdleModeLocked(int mode, String activeReason, int activeUid) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
-        boolean nowIdling = mode == DEVICE_IDLE_MODE_FULL;
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
+        boolean nowIdling = mode == DEVICE_IDLE_MODE_DEEP;
         if (mDeviceIdling && !nowIdling && activeReason == null) {
             // We don't go out of general idling mode until explicitly taken out of
             // device idle through going active or significant motion.
@@ -3444,7 +3492,7 @@
                     mLongestLightIdleTime = lastDuration;
                 }
                 mDeviceIdleModeLightTimer.stopRunningLocked(elapsedRealtime);
-            } else if (mDeviceIdleMode == DEVICE_IDLE_MODE_FULL) {
+            } else if (mDeviceIdleMode == DEVICE_IDLE_MODE_DEEP) {
                 if (lastDuration > mLongestFullIdleTime) {
                     mLongestFullIdleTime = lastDuration;
                 }
@@ -3452,7 +3500,7 @@
             }
             if (mode == DEVICE_IDLE_MODE_LIGHT) {
                 mDeviceIdleModeLightTimer.startRunningLocked(elapsedRealtime);
-            } else if (mode == DEVICE_IDLE_MODE_FULL) {
+            } else if (mode == DEVICE_IDLE_MODE_DEEP) {
                 mDeviceIdleModeFullTimer.startRunningLocked(elapsedRealtime);
             }
             mDeviceIdleMode = mode;
@@ -3460,8 +3508,8 @@
     }
 
     public void notePackageInstalledLocked(String pkgName, int versionCode) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
                 pkgName, versionCode);
         PackageChange pc = new PackageChange();
@@ -3472,8 +3520,8 @@
     }
 
     public void notePackageUninstalledLocked(String pkgName) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_UNINSTALLED,
                 pkgName, 0);
         PackageChange pc = new PackageChange();
@@ -3491,8 +3539,8 @@
 
     public void notePhoneOnLocked() {
         if (!mPhoneOn) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
                     + Integer.toHexString(mHistoryCur.states));
@@ -3504,8 +3552,8 @@
 
     public void notePhoneOffLocked() {
         if (mPhoneOn) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
                     + Integer.toHexString(mHistoryCur.states));
@@ -3516,7 +3564,7 @@
     }
 
     void stopAllPhoneSignalStrengthTimersLocked(int except) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
         for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             if (i == except) {
                 continue;
@@ -3548,8 +3596,8 @@
         mPhoneSimStateRaw = simState;
         mPhoneSignalStrengthBinRaw = strengthBin;
 
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
 
         if (simState == TelephonyManager.SIM_STATE_ABSENT) {
             // In this case we will always be STATE_OUT_OF_SERVICE, so need
@@ -3697,8 +3745,8 @@
         }
         if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
         if (mPhoneDataConnectionType != bin) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
                     | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
@@ -3715,8 +3763,8 @@
 
     public void noteWifiOnLocked() {
         if (!mWifiOn) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
                     + Integer.toHexString(mHistoryCur.states));
@@ -3728,8 +3776,8 @@
     }
 
     public void noteWifiOffLocked() {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mWifiOn) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
@@ -3743,8 +3791,8 @@
 
     public void noteAudioOnLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mAudioOnNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
@@ -3761,8 +3809,8 @@
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (--mAudioOnNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
@@ -3775,8 +3823,8 @@
 
     public void noteVideoOnLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mVideoOnNesting == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
@@ -3793,8 +3841,8 @@
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (--mVideoOnNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
@@ -3807,8 +3855,8 @@
 
     public void noteResetAudioLocked() {
         if (mAudioOnNesting > 0) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mAudioOnNesting = 0;
             mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
@@ -3824,8 +3872,8 @@
 
     public void noteResetVideoLocked() {
         if (mVideoOnNesting > 0) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mAudioOnNesting = 0;
             mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
@@ -3841,12 +3889,12 @@
 
     public void noteActivityResumedLocked(int uid) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteActivityResumedLocked(SystemClock.elapsedRealtime());
+        getUidStatsLocked(uid).noteActivityResumedLocked(mClocks.elapsedRealtime());
     }
 
     public void noteActivityPausedLocked(int uid) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteActivityPausedLocked(SystemClock.elapsedRealtime());
+        getUidStatsLocked(uid).noteActivityPausedLocked(mClocks.elapsedRealtime());
     }
 
     public void noteVibratorOnLocked(int uid, long durationMillis) {
@@ -3861,8 +3909,8 @@
 
     public void noteFlashlightOnLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mFlashlightOnNesting++ == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: "
@@ -3878,8 +3926,8 @@
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (--mFlashlightOnNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
@@ -3892,8 +3940,8 @@
 
     public void noteCameraOnLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mCameraOnNesting++ == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: "
@@ -3909,8 +3957,8 @@
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (--mCameraOnNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
@@ -3923,8 +3971,8 @@
 
     public void noteResetCameraLocked() {
         if (mCameraOnNesting > 0) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mCameraOnNesting = 0;
             mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
@@ -3940,8 +3988,8 @@
 
     public void noteResetFlashlightLocked() {
         if (mFlashlightOnNesting > 0) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mFlashlightOnNesting = 0;
             mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
@@ -3964,6 +4012,7 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
                     + Integer.toHexString(mHistoryCur.states2));
             addHistoryRecordLocked(elapsedRealtime, uptime);
+            mBluetoothScanTimer.startRunningLocked(elapsedRealtime);
         }
         mBluetoothScanNesting++;
         getUidStatsLocked(uid).noteBluetoothScanStartedLocked(elapsedRealtime);
@@ -3986,6 +4035,7 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: "
                     + Integer.toHexString(mHistoryCur.states2));
             addHistoryRecordLocked(elapsedRealtime, uptime);
+            mBluetoothScanTimer.stopRunningLocked(elapsedRealtime);
         }
         getUidStatsLocked(uid).noteBluetoothScanStoppedLocked(elapsedRealtime);
     }
@@ -4015,8 +4065,8 @@
     }
 
     public void noteWifiRadioPowerState(int powerState, long timestampNs) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mWifiRadioPowerState != powerState) {
             final boolean active =
                     powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
@@ -4035,8 +4085,8 @@
 
     public void noteWifiRunningLocked(WorkSource ws) {
         if (!mGlobalWifiRunning) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
                     + Integer.toHexString(mHistoryCur.states));
@@ -4056,7 +4106,7 @@
 
     public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
         if (mGlobalWifiRunning) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
             int N = oldWs.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(oldWs.get(i));
@@ -4074,8 +4124,8 @@
 
     public void noteWifiStoppedLocked(WorkSource ws) {
         if (mGlobalWifiRunning) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
                     + Integer.toHexString(mHistoryCur.states));
@@ -4096,7 +4146,7 @@
     public void noteWifiStateLocked(int wifiState, String accessPoint) {
         if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
         if (mWifiState != wifiState) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
             if (mWifiState >= 0) {
                 mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
             }
@@ -4109,8 +4159,8 @@
     public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
         if (DEBUG) Log.i(TAG, "WiFi suppl state -> " + supplState);
         if (mWifiSupplState != supplState) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             if (mWifiSupplState >= 0) {
                 mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtime);
             }
@@ -4126,7 +4176,7 @@
     }
 
     void stopAllWifiSignalStrengthTimersLocked(int except) {
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
         for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             if (i == except) {
                 continue;
@@ -4141,8 +4191,8 @@
         int strengthBin = WifiManager.calculateSignalLevel(newRssi, NUM_WIFI_SIGNAL_STRENGTH_BINS);
         if (DEBUG) Log.i(TAG, "WiFi rssi -> " + newRssi + " bin=" + strengthBin);
         if (mWifiSignalStrengthBin != strengthBin) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             if (mWifiSignalStrengthBin >= 0) {
                 mWifiSignalStrengthsTimer[mWifiSignalStrengthBin].stopRunningLocked(
                         elapsedRealtime);
@@ -4168,8 +4218,8 @@
 
     public void noteFullWifiLockAcquiredLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
@@ -4182,8 +4232,8 @@
 
     public void noteFullWifiLockReleasedLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         mWifiFullLockNesting--;
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
@@ -4198,8 +4248,8 @@
 
     public void noteWifiScanStartedLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mWifiScanNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
@@ -4212,8 +4262,8 @@
 
     public void noteWifiScanStoppedLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         mWifiScanNesting--;
         if (mWifiScanNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
@@ -4226,13 +4276,13 @@
 
     public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
         getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
     }
 
     public void noteWifiBatchedScanStoppedLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
         getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
     }
 
@@ -4240,8 +4290,8 @@
 
     public void noteWifiMulticastEnabledLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
@@ -4254,8 +4304,8 @@
 
     public void noteWifiMulticastDisabledLocked(int uid) {
         uid = mapUid(uid);
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
         mWifiMulticastNesting--;
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
@@ -4369,7 +4419,7 @@
         // During device boot, qtaguid isn't enabled until after the inital
         // loading of battery stats. Now that they're enabled, take our initial
         // snapshot for future delta calculation.
-        updateMobileRadioStateLocked(SystemClock.elapsedRealtime(), null);
+        updateMobileRadioStateLocked(mClocks.elapsedRealtime(), null);
         updateWifiStateLocked(null);
     }
 
@@ -4404,7 +4454,7 @@
         switch (mode) {
             case DEVICE_IDLE_MODE_LIGHT:
                 return mDeviceIdleModeLightTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
-            case DEVICE_IDLE_MODE_FULL:
+            case DEVICE_IDLE_MODE_DEEP:
                 return mDeviceIdleModeFullTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
         return 0;
@@ -4414,7 +4464,7 @@
         switch (mode) {
             case DEVICE_IDLE_MODE_LIGHT:
                 return mDeviceIdleModeLightTimer.getCountLocked(which);
-            case DEVICE_IDLE_MODE_FULL:
+            case DEVICE_IDLE_MODE_DEEP:
                 return mDeviceIdleModeFullTimer.getCountLocked(which);
         }
         return 0;
@@ -4424,7 +4474,7 @@
         switch (mode) {
             case DEVICE_IDLE_MODE_LIGHT:
                 return mLongestLightIdleTime;
-            case DEVICE_IDLE_MODE_FULL:
+            case DEVICE_IDLE_MODE_DEEP:
                 return mLongestFullIdleTime;
         }
         return 0;
@@ -4434,7 +4484,7 @@
         switch (mode) {
             case DEVICE_IDLE_MODE_LIGHT:
                 return mDeviceLightIdlingTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
-            case DEVICE_IDLE_MODE_FULL:
+            case DEVICE_IDLE_MODE_DEEP:
                 return mDeviceIdlingTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
         return 0;
@@ -4444,7 +4494,7 @@
         switch (mode) {
             case DEVICE_IDLE_MODE_LIGHT:
                 return mDeviceLightIdlingTimer.getCountLocked(which);
-            case DEVICE_IDLE_MODE_FULL:
+            case DEVICE_IDLE_MODE_DEEP:
                 return mDeviceIdlingTimer.getCountLocked(which);
         }
         return 0;
@@ -4623,8 +4673,8 @@
     @Override public long getStartClockTime() {
         final long currentTime = System.currentTimeMillis();
         if (ensureStartClockTime(currentTime)) {
-            recordCurrentTimeChangeLocked(currentTime, SystemClock.elapsedRealtime(),
-                    SystemClock.uptimeMillis());
+            recordCurrentTimeChangeLocked(currentTime, mClocks.elapsedRealtime(),
+                    mClocks.uptimeMillis());
         }
         return mStartClockTime;
     }
@@ -4652,7 +4702,11 @@
     /**
      * The statistics associated with a particular uid.
      */
-    public final class Uid extends BatteryStats.Uid {
+    public static class Uid extends BatteryStats.Uid {
+        /**
+         * BatteryStatsImpl that we are associated with.
+         */
+        protected BatteryStatsImpl mBsi;
 
         final int mUid;
 
@@ -4717,35 +4771,25 @@
         long mCurStepUserTime;
         long mCurStepSystemTime;
 
-        LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
-        LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
-        LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase);
+        LongSamplingCounter mUserCpuTime;
+        LongSamplingCounter mSystemCpuTime;
+        LongSamplingCounter mCpuPower;
         LongSamplingCounter[][] mCpuClusterSpeed;
 
         /**
          * The statistics we have collected for this uid's wake locks.
          */
-        final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
-            @Override public Wakelock instantiateObject() { return new Wakelock(); }
-        };
+        final OverflowArrayMap<Wakelock> mWakelockStats;
 
         /**
          * The statistics we have collected for this uid's syncs.
          */
-        final OverflowArrayMap<StopwatchTimer> mSyncStats = new OverflowArrayMap<StopwatchTimer>() {
-            @Override public StopwatchTimer instantiateObject() {
-                return new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase);
-            }
-        };
+        final OverflowArrayMap<StopwatchTimer> mSyncStats;
 
         /**
          * The statistics we have collected for this uid's jobs.
          */
-        final OverflowArrayMap<StopwatchTimer> mJobStats = new OverflowArrayMap<StopwatchTimer>() {
-            @Override public StopwatchTimer instantiateObject() {
-                return new StopwatchTimer(Uid.this, JOB, null, mOnBatteryTimeBase);
-            }
-        };
+        final OverflowArrayMap<StopwatchTimer> mJobStats;
 
         /**
          * The statistics we have collected for this uid's sensor activations.
@@ -4767,17 +4811,41 @@
          */
         final SparseArray<Pid> mPids = new SparseArray<>();
 
-        public Uid(int uid) {
+        public Uid(BatteryStatsImpl bsi, int uid) {
+            mBsi = bsi;
             mUid = uid;
-            mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
-                    mWifiRunningTimers, mOnBatteryTimeBase);
-            mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                    mFullWifiLockTimers, mOnBatteryTimeBase);
-            mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
-                    mWifiScanTimers, mOnBatteryTimeBase);
+
+            mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+            mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+            mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+
+            mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>() {
+                @Override public Wakelock instantiateObject() {
+                    return new Wakelock(mBsi, Uid.this);
+                }
+            };
+            mSyncStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+                @Override public StopwatchTimer instantiateObject() {
+                    return new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null,
+                            mBsi.mOnBatteryTimeBase);
+                }
+            };
+            mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+                @Override public StopwatchTimer instantiateObject() {
+                    return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
+                            mBsi.mOnBatteryTimeBase);
+                }
+            };
+
+            mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_RUNNING,
+                    mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
+            mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, this, FULL_WIFI_LOCK,
+                    mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
+            mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_SCAN,
+                    mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
             mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
-            mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                    mWifiMulticastTimers, mOnBatteryTimeBase);
+            mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_MULTICAST_ENABLED,
+                    mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
             mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
         }
 
@@ -4821,8 +4889,8 @@
             if (!mWifiRunning) {
                 mWifiRunning = true;
                 if (mWifiRunningTimer == null) {
-                    mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
-                            mWifiRunningTimers, mOnBatteryTimeBase);
+                    mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+                            mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
                 }
                 mWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
             }
@@ -4841,8 +4909,8 @@
             if (!mFullWifiLockOut) {
                 mFullWifiLockOut = true;
                 if (mFullWifiLockTimer == null) {
-                    mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                            mFullWifiLockTimers, mOnBatteryTimeBase);
+                    mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+                            mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
                 }
                 mFullWifiLockTimer.startRunningLocked(elapsedRealtimeMs);
             }
@@ -4861,8 +4929,8 @@
             if (!mWifiScanStarted) {
                 mWifiScanStarted = true;
                 if (mWifiScanTimer == null) {
-                    mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
-                            mWifiScanTimers, mOnBatteryTimeBase);
+                    mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+                            mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
                 }
                 mWifiScanTimer.startRunningLocked(elapsedRealtimeMs);
             }
@@ -4911,8 +4979,8 @@
             if (!mWifiMulticastEnabled) {
                 mWifiMulticastEnabled = true;
                 if (mWifiMulticastTimer == null) {
-                    mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                            mWifiMulticastTimers, mOnBatteryTimeBase);
+                    mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+                            WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
                 }
                 mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs);
             }
@@ -4943,7 +5011,7 @@
 
         public ControllerActivityCounterImpl getOrCreateWifiControllerActivityLocked() {
             if (mWifiControllerActivity == null) {
-                mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
                         NUM_BT_TX_LEVELS);
             }
             return mWifiControllerActivity;
@@ -4951,7 +5019,7 @@
 
         public ControllerActivityCounterImpl getOrCreateBluetoothControllerActivityLocked() {
             if (mBluetoothControllerActivity == null) {
-                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
                         NUM_BT_TX_LEVELS);
             }
             return mBluetoothControllerActivity;
@@ -4959,7 +5027,7 @@
 
         public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
             if (mModemControllerActivity == null) {
-                mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
                         ModemActivityInfo.TX_POWER_LEVELS);
             }
             return mModemControllerActivity;
@@ -4967,8 +5035,8 @@
 
         public StopwatchTimer createAudioTurnedOnTimerLocked() {
             if (mAudioTurnedOnTimer == null) {
-                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
-                        mAudioTurnedOnTimers, mOnBatteryTimeBase);
+                mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+                        mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase);
             }
             return mAudioTurnedOnTimer;
         }
@@ -4991,8 +5059,8 @@
 
         public StopwatchTimer createVideoTurnedOnTimerLocked() {
             if (mVideoTurnedOnTimer == null) {
-                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
-                        mVideoTurnedOnTimers, mOnBatteryTimeBase);
+                mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+                        mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase);
             }
             return mVideoTurnedOnTimer;
         }
@@ -5015,8 +5083,8 @@
 
         public StopwatchTimer createFlashlightTurnedOnTimerLocked() {
             if (mFlashlightTurnedOnTimer == null) {
-                mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
-                        mFlashlightTurnedOnTimers, mOnBatteryTimeBase);
+                mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+                        FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase);
             }
             return mFlashlightTurnedOnTimer;
         }
@@ -5039,8 +5107,8 @@
 
         public StopwatchTimer createCameraTurnedOnTimerLocked() {
             if (mCameraTurnedOnTimer == null) {
-                mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
-                        mCameraTurnedOnTimers, mOnBatteryTimeBase);
+                mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+                        mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase);
             }
             return mCameraTurnedOnTimer;
         }
@@ -5063,16 +5131,16 @@
 
         public StopwatchTimer createForegroundActivityTimerLocked() {
             if (mForegroundActivityTimer == null) {
-                mForegroundActivityTimer = new StopwatchTimer(
-                        Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase);
+                mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+                        FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase);
             }
             return mForegroundActivityTimer;
         }
 
         public StopwatchTimer createBluetoothScanTimerLocked() {
             if (mBluetoothScanTimer == null) {
-                mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
-                        mBluetoothScanOnTimers, mOnBatteryTimeBase);
+                mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+                        mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase);
             }
             return mBluetoothScanTimer;
         }
@@ -5108,18 +5176,19 @@
 
         public BatchTimer createVibratorOnTimerLocked() {
             if (mVibratorOnTimer == null) {
-                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase);
+                mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+                        mBsi.mOnBatteryTimeBase);
             }
             return mVibratorOnTimer;
         }
 
         public void noteVibratorOnLocked(long durationMillis) {
-            createVibratorOnTimerLocked().addDuration(BatteryStatsImpl.this, durationMillis);
+            createVibratorOnTimerLocked().addDuration(mBsi, durationMillis);
         }
 
         public void noteVibratorOffLocked() {
             if (mVibratorOnTimer != null) {
-                mVibratorOnTimer.abortLastDuration(BatteryStatsImpl.this);
+                mVibratorOnTimer.abortLastDuration(mBsi);
             }
         }
 
@@ -5215,11 +5284,11 @@
             if (i < 0 || i >= NUM_PROCESS_STATE) return;
 
             if (in == null) {
-                mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
-                        mOnBatteryTimeBase);
+                mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+                        mBsi.mOnBatteryTimeBase);
             } else {
-                mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
-                        mOnBatteryTimeBase, in);
+                mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+                        mBsi.mOnBatteryTimeBase, in);
             }
         }
 
@@ -5233,6 +5302,12 @@
         }
 
         @Override
+        public Timer getProcessStateTimer(int state) {
+            if (state < 0 || state >= NUM_PROCESS_STATE) return null;
+            return mProcessStateTimer[state];
+        }
+
+        @Override
         public Timer getVibratorOnTimer() {
             return mVibratorOnTimer;
         }
@@ -5266,17 +5341,17 @@
         void makeWifiBatchedScanBin(int i, Parcel in) {
             if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
 
-            ArrayList<StopwatchTimer> collected = mWifiBatchedScanTimers.get(i);
+            ArrayList<StopwatchTimer> collected = mBsi.mWifiBatchedScanTimers.get(i);
             if (collected == null) {
                 collected = new ArrayList<StopwatchTimer>();
-                mWifiBatchedScanTimers.put(i, collected);
+                mBsi.mWifiBatchedScanTimers.put(i, collected);
             }
             if (in == null) {
-                mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
-                        mOnBatteryTimeBase);
+                mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+                        collected, mBsi.mOnBatteryTimeBase);
             } else {
-                mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
-                        mOnBatteryTimeBase, in);
+                mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+                        collected, mBsi.mOnBatteryTimeBase, in);
             }
         }
 
@@ -5284,7 +5359,7 @@
         void initUserActivityLocked() {
             mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
             for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
-                mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase);
+                mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase);
             }
         }
 
@@ -5383,11 +5458,11 @@
             mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
             mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
             for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
-                mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
-                mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+                mNetworkByteActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+                mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
             }
-            mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase);
-            mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase);
+            mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+            mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
         }
 
         /**
@@ -5475,12 +5550,12 @@
                 mWifiControllerActivity.reset(false);
             }
 
-            if (mBluetoothActivity != null) {
-                mBluetoothActivity.reset(false);
+            if (mBsi.mBluetoothActivity != null) {
+                mBsi.mBluetoothActivity.reset(false);
             }
 
-            if (mModemActivity != null) {
-                mModemActivity.reset(false);
+            if (mBsi.mModemActivity != null) {
+                mBsi.mModemActivity.reset(false);
             }
 
             mUserCpuTime.reset(false);
@@ -5871,7 +5946,7 @@
             mWakelockStats.clear();
             for (int j = 0; j < numWakelocks; j++) {
                 String wakelockName = in.readString();
-                Uid.Wakelock wakelock = new Wakelock();
+                Uid.Wakelock wakelock = new Wakelock(mBsi, this);
                 wakelock.readFromParcelLocked(timeBase, screenOffTimeBase, in);
                 mWakelockStats.add(wakelockName, wakelock);
             }
@@ -5882,7 +5957,7 @@
                 String syncName = in.readString();
                 if (in.readInt() != 0) {
                     mSyncStats.add(syncName,
-                            new StopwatchTimer(Uid.this, SYNC, null, timeBase, in));
+                            new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null, timeBase, in));
                 }
             }
 
@@ -5891,7 +5966,8 @@
             for (int j = 0; j < numJobs; j++) {
                 String jobName = in.readString();
                 if (in.readInt() != 0) {
-                    mJobStats.add(jobName, new StopwatchTimer(Uid.this, JOB, null, timeBase, in));
+                    mJobStats.add(jobName, new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
+                                timeBase, in));
                 }
             }
 
@@ -5899,8 +5975,8 @@
             mSensorStats.clear();
             for (int k = 0; k < numSensors; k++) {
                 int sensorNumber = in.readInt();
-                Uid.Sensor sensor = new Sensor(sensorNumber);
-                sensor.readFromParcelLocked(mOnBatteryTimeBase, in);
+                Uid.Sensor sensor = new Sensor(mBsi, this, sensorNumber);
+                sensor.readFromParcelLocked(mBsi.mOnBatteryTimeBase, in);
                 mSensorStats.put(sensorNumber, sensor);
             }
 
@@ -5908,7 +5984,7 @@
             mProcessStats.clear();
             for (int k = 0; k < numProcs; k++) {
                 String processName = in.readString();
-                Uid.Proc proc = new Proc(processName);
+                Uid.Proc proc = new Proc(mBsi, processName);
                 proc.readFromParcelLocked(in);
                 mProcessStats.put(processName, proc);
             }
@@ -5917,29 +5993,29 @@
             mPackageStats.clear();
             for (int l = 0; l < numPkgs; l++) {
                 String packageName = in.readString();
-                Uid.Pkg pkg = new Pkg();
+                Uid.Pkg pkg = new Pkg(mBsi);
                 pkg.readFromParcelLocked(in);
                 mPackageStats.put(packageName, pkg);
             }
 
             mWifiRunning = false;
             if (in.readInt() != 0) {
-                mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
-                        mWifiRunningTimers, mOnBatteryTimeBase, in);
+                mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+                        mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mWifiRunningTimer = null;
             }
             mFullWifiLockOut = false;
             if (in.readInt() != 0) {
-                mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                        mFullWifiLockTimers, mOnBatteryTimeBase, in);
+                mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+                        mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mFullWifiLockTimer = null;
             }
             mWifiScanStarted = false;
             if (in.readInt() != 0) {
-                mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
-                        mWifiScanTimers, mOnBatteryTimeBase, in);
+                mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+                        mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mWifiScanTimer = null;
             }
@@ -5953,44 +6029,44 @@
             }
             mWifiMulticastEnabled = false;
             if (in.readInt() != 0) {
-                mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                        mWifiMulticastTimers, mOnBatteryTimeBase, in);
+                mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_MULTICAST_ENABLED,
+                        mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mWifiMulticastTimer = null;
             }
             if (in.readInt() != 0) {
-                mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
-                        mAudioTurnedOnTimers, mOnBatteryTimeBase, in);
+                mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+                        mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mAudioTurnedOnTimer = null;
             }
             if (in.readInt() != 0) {
-                mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
-                        mVideoTurnedOnTimers, mOnBatteryTimeBase, in);
+                mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+                        mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mVideoTurnedOnTimer = null;
             }
             if (in.readInt() != 0) {
-                mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
-                        mFlashlightTurnedOnTimers, mOnBatteryTimeBase, in);
+                mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+                        FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mFlashlightTurnedOnTimer = null;
             }
             if (in.readInt() != 0) {
-                mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
-                        mCameraTurnedOnTimers, mOnBatteryTimeBase, in);
+                mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+                        mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mCameraTurnedOnTimer = null;
             }
             if (in.readInt() != 0) {
-                mForegroundActivityTimer = new StopwatchTimer(
-                        Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase, in);
+                mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+                        FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mForegroundActivityTimer = null;
             }
             if (in.readInt() != 0) {
-                mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
-                        mBluetoothScanOnTimers, mOnBatteryTimeBase, in);
+                mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+                        mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase, in);
             } else {
                 mBluetoothScanTimer = null;
             }
@@ -6003,14 +6079,15 @@
                 }
             }
             if (in.readInt() != 0) {
-                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase, in);
+                mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+                        mBsi.mOnBatteryTimeBase, in);
             } else {
                 mVibratorOnTimer = null;
             }
             if (in.readInt() != 0) {
                 mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
                 for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
-                    mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase, in);
+                    mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase, in);
                 }
             } else {
                 mUserActivityCounters = null;
@@ -6021,45 +6098,45 @@
                         = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
                 for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
                     mNetworkByteActivityCounters[i]
-                            = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                            = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
                     mNetworkPacketActivityCounters[i]
-                            = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                            = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
                 }
-                mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
-                mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+                mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
             } else {
                 mNetworkByteActivityCounters = null;
                 mNetworkPacketActivityCounters = null;
             }
 
             if (in.readInt() != 0) {
-                mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
                         NUM_WIFI_TX_LEVELS, in);
             } else {
                 mWifiControllerActivity = null;
             }
 
             if (in.readInt() != 0) {
-                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
                         NUM_BT_TX_LEVELS, in);
             } else {
                 mBluetoothControllerActivity = null;
             }
 
             if (in.readInt() != 0) {
-                mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
                         ModemActivityInfo.TX_POWER_LEVELS, in);
             } else {
                 mModemControllerActivity = null;
             }
 
-            mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
-            mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
-            mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase, in);
+            mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+            mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+            mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
 
             if (in.readInt() != 0) {
                 int numCpuClusters = in.readInt();
-                if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+                if (mBsi.mPowerProfile != null && mBsi.mPowerProfile.getNumCpuClusters() != numCpuClusters) {
                     throw new ParcelFormatException("Incompatible number of cpu clusters");
                 }
 
@@ -6067,8 +6144,8 @@
                 for (int cluster = 0; cluster < numCpuClusters; cluster++) {
                     if (in.readInt() != 0) {
                         int numSpeeds = in.readInt();
-                        if (mPowerProfile != null &&
-                                mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+                        if (mBsi.mPowerProfile != null &&
+                                mBsi.mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
                             throw new ParcelFormatException("Incompatible number of cpu speeds");
                         }
 
@@ -6076,7 +6153,7 @@
                         mCpuClusterSpeed[cluster] = cpuSpeeds;
                         for (int speed = 0; speed < numSpeeds; speed++) {
                             if (in.readInt() != 0) {
-                                cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                                cpuSpeeds[speed] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
                             }
                         }
                     } else {
@@ -6091,7 +6168,17 @@
         /**
          * The statistics associated with a particular wake lock.
          */
-        public final class Wakelock extends BatteryStats.Uid.Wakelock {
+        public static class Wakelock extends BatteryStats.Uid.Wakelock {
+            /**
+             * BatteryStatsImpl that we are associated with.
+             */
+            protected BatteryStatsImpl mBsi;
+
+            /**
+             * BatteryStatsImpl that we are associated with.
+             */
+            protected Uid mUid;
+
             /**
              * How long (in ms) this uid has been keeping the device partially awake.
              */
@@ -6112,6 +6199,11 @@
              */
             StopwatchTimer mTimerDraw;
 
+            public Wakelock(BatteryStatsImpl bsi, Uid uid) {
+                mBsi = bsi;
+                mUid = uid;
+            }
+
             /**
              * Reads a possibly null Timer from a Parcel.  The timer is associated with the
              * proper timer pool from the given BatteryStatsImpl object.
@@ -6125,7 +6217,7 @@
                     return null;
                 }
 
-                return new StopwatchTimer(Uid.this, type, pool, timeBase, in);
+                return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
             }
 
             boolean reset() {
@@ -6165,10 +6257,10 @@
 
             void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
                 mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
-                        mPartialTimers, screenOffTimeBase, in);
-                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mFullTimers, timeBase, in);
-                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mWindowTimers, timeBase, in);
-                mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mDrawTimers, timeBase, in);
+                        mBsi.mPartialTimers, screenOffTimeBase, in);
+                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
+                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
+                mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
             }
 
             void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
@@ -6195,32 +6287,32 @@
                     case WAKE_TYPE_PARTIAL:
                         t = mTimerPartial;
                         if (t == null) {
-                            t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
-                                    mPartialTimers, mOnBatteryScreenOffTimeBase);
+                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
+                                    mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase);
                             mTimerPartial = t;
                         }
                         return t;
                     case WAKE_TYPE_FULL:
                         t = mTimerFull;
                         if (t == null) {
-                            t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
-                                    mFullTimers, mOnBatteryTimeBase);
+                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
+                                    mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
                             mTimerFull = t;
                         }
                         return t;
                     case WAKE_TYPE_WINDOW:
                         t = mTimerWindow;
                         if (t == null) {
-                            t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
-                                    mWindowTimers, mOnBatteryTimeBase);
+                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
+                                    mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
                             mTimerWindow = t;
                         }
                         return t;
                     case WAKE_TYPE_DRAW:
                         t = mTimerDraw;
                         if (t == null) {
-                            t = new StopwatchTimer(Uid.this, WAKE_TYPE_DRAW,
-                                    mDrawTimers, mOnBatteryTimeBase);
+                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
+                                    mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
                             mTimerDraw = t;
                         }
                         return t;
@@ -6230,11 +6322,23 @@
             }
         }
 
-        public final class Sensor extends BatteryStats.Uid.Sensor {
+        public static class Sensor extends BatteryStats.Uid.Sensor {
+            /**
+             * BatteryStatsImpl that we are associated with.
+             */
+            protected BatteryStatsImpl mBsi;
+
+            /**
+             * BatteryStatsImpl that we are associated with.
+             */
+            protected Uid mUid;
+
             final int mHandle;
             StopwatchTimer mTimer;
 
-            public Sensor(int handle) {
+            public Sensor(BatteryStatsImpl bsi, Uid uid, int handle) {
+                mBsi = bsi;
+                mUid = uid;
                 mHandle = handle;
             }
 
@@ -6243,12 +6347,12 @@
                     return null;
                 }
 
-                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
+                ArrayList<StopwatchTimer> pool = mBsi.mSensorTimers.get(mHandle);
                 if (pool == null) {
                     pool = new ArrayList<StopwatchTimer>();
-                    mSensorTimers.put(mHandle, pool);
+                    mBsi.mSensorTimers.put(mHandle, pool);
                 }
-                return new StopwatchTimer(Uid.this, 0, pool, timeBase, in);
+                return new StopwatchTimer(mBsi.mClocks, mUid, 0, pool, timeBase, in);
             }
 
             boolean reset() {
@@ -6281,7 +6385,12 @@
         /**
          * The statistics associated with a particular process.
          */
-        public final class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
+        public static class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
+            /**
+             * BatteryStatsImpl that we are associated with.
+             */
+            protected BatteryStatsImpl mBsi;
+
             /**
              * The name of this process.
              */
@@ -6384,9 +6493,10 @@
 
             ArrayList<ExcessivePower> mExcessivePower;
 
-            Proc(String name) {
+            public Proc(BatteryStatsImpl bsi, String name) {
+                mBsi = bsi;
                 mName = name;
-                mOnBatteryTimeBase.add(this);
+                mBsi.mOnBatteryTimeBase.add(this);
             }
 
             public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6403,7 +6513,7 @@
 
             void detach() {
                 mActive = false;
-                mOnBatteryTimeBase.remove(this);
+                mBsi.mOnBatteryTimeBase.remove(this);
             }
 
             public int countExcessivePowers() {
@@ -6617,7 +6727,12 @@
         /**
          * The statistics associated with a particular package.
          */
-        public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
+        public static class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
+            /**
+             * BatteryStatsImpl that we are associated with.
+             */
+            protected BatteryStatsImpl mBsi;
+
             /**
              * Number of times wakeup alarms have occurred for this app.
              */
@@ -6628,8 +6743,9 @@
              */
             final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
 
-            Pkg() {
-                mOnBatteryScreenOffTimeBase.add(this);
+            public Pkg(BatteryStatsImpl bsi) {
+                mBsi = bsi;
+                mBsi.mOnBatteryScreenOffTimeBase.add(this);
             }
 
             public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6639,7 +6755,7 @@
             }
 
             void detach() {
-                mOnBatteryScreenOffTimeBase.remove(this);
+                mBsi.mOnBatteryScreenOffTimeBase.remove(this);
             }
 
             void readFromParcelLocked(Parcel in) {
@@ -6647,14 +6763,14 @@
                 mWakeupAlarms.clear();
                 for (int i=0; i<numWA; i++) {
                     String tag = in.readString();
-                    mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in));
+                    mWakeupAlarms.put(tag, new Counter(mBsi.mOnBatteryTimeBase, in));
                 }
 
                 int numServs = in.readInt();
                 mServiceStats.clear();
                 for (int m = 0; m < numServs; m++) {
                     String serviceName = in.readString();
-                    Uid.Pkg.Serv serv = new Serv();
+                    Uid.Pkg.Serv serv = new Serv(mBsi);
                     mServiceStats.put(serviceName, serv);
 
                     serv.readFromParcelLocked(in);
@@ -6686,7 +6802,7 @@
             public void noteWakeupAlarmLocked(String tag) {
                 Counter c = mWakeupAlarms.get(tag);
                 if (c == null) {
-                    c = new Counter(mOnBatteryTimeBase);
+                    c = new Counter(mBsi.mOnBatteryTimeBase);
                     mWakeupAlarms.put(tag, c);
                 }
                 c.stepAtomic();
@@ -6700,99 +6816,113 @@
             /**
              * The statistics associated with a particular service.
              */
-            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
+            public static class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
+                /**
+                 * BatteryStatsImpl that we are associated with.
+                 */
+                protected BatteryStatsImpl mBsi;
+
+                /**
+                 * The android package in which this service resides.
+                 */
+                protected Pkg mPkg;
+
                 /**
                  * Total time (ms in battery uptime) the service has been left started.
                  */
-                long mStartTime;
+                protected long mStartTime;
 
                 /**
                  * If service has been started and not yet stopped, this is
                  * when it was started.
                  */
-                long mRunningSince;
+                protected long mRunningSince;
 
                 /**
                  * True if we are currently running.
                  */
-                boolean mRunning;
+                protected boolean mRunning;
 
                 /**
                  * Total number of times startService() has been called.
                  */
-                int mStarts;
+                protected int mStarts;
 
                 /**
                  * Total time (ms in battery uptime) the service has been left launched.
                  */
-                long mLaunchedTime;
+                protected long mLaunchedTime;
 
                 /**
                  * If service has been launched and not yet exited, this is
                  * when it was launched (ms in battery uptime).
                  */
-                long mLaunchedSince;
+                protected long mLaunchedSince;
 
                 /**
                  * True if we are currently launched.
                  */
-                boolean mLaunched;
+                protected boolean mLaunched;
 
                 /**
                  * Total number times the service has been launched.
                  */
-                int mLaunches;
+                protected int mLaunches;
 
                 /**
                  * The amount of time spent started loaded from a previous save
                  * (ms in battery uptime).
                  */
-                long mLoadedStartTime;
+                protected long mLoadedStartTime;
 
                 /**
                  * The number of starts loaded from a previous save.
                  */
-                int mLoadedStarts;
+                protected int mLoadedStarts;
 
                 /**
                  * The number of launches loaded from a previous save.
                  */
-                int mLoadedLaunches;
+                protected int mLoadedLaunches;
 
                 /**
                  * The amount of time spent started as of the last run (ms
                  * in battery uptime).
                  */
-                long mLastStartTime;
+                protected long mLastStartTime;
 
                 /**
                  * The number of starts as of the last run.
                  */
-                int mLastStarts;
+                protected int mLastStarts;
 
                 /**
                  * The number of launches as of the last run.
                  */
-                int mLastLaunches;
+                protected int mLastLaunches;
 
                 /**
                  * The amount of time spent started when last unplugged (ms
                  * in battery uptime).
                  */
-                long mUnpluggedStartTime;
+                protected long mUnpluggedStartTime;
 
                 /**
                  * The number of starts when last unplugged.
                  */
-                int mUnpluggedStarts;
+                protected int mUnpluggedStarts;
 
                 /**
                  * The number of launches when last unplugged.
                  */
-                int mUnpluggedLaunches;
+                protected int mUnpluggedLaunches;
 
-                Serv() {
-                    mOnBatteryTimeBase.add(this);
+                /**
+                 * Construct a Serv. Also adds it to the on-battery time base as a listener.
+                 */
+                public Serv(BatteryStatsImpl bsi) {
+                    mBsi = bsi;
+                    mBsi.mOnBatteryTimeBase.add(this);
                 }
 
                 public void onTimeStarted(long elapsedRealtime, long baseUptime,
@@ -6806,11 +6936,14 @@
                         long baseRealtime) {
                 }
 
-                void detach() {
-                    mOnBatteryTimeBase.remove(this);
+                /**
+                 * Remove this Serv as a listener from the time base.
+                 */
+                public void detach() {
+                    mBsi.mOnBatteryTimeBase.remove(this);
                 }
 
-                void readFromParcelLocked(Parcel in) {
+                public void readFromParcelLocked(Parcel in) {
                     mStartTime = in.readLong();
                     mRunningSince = in.readLong();
                     mRunning = in.readInt() != 0;
@@ -6830,7 +6963,7 @@
                     mUnpluggedLaunches = in.readInt();
                 }
 
-                void writeToParcelLocked(Parcel out) {
+                public void writeToParcelLocked(Parcel out) {
                     out.writeLong(mStartTime);
                     out.writeLong(mRunningSince);
                     out.writeInt(mRunning ? 1 : 0);
@@ -6847,12 +6980,12 @@
                     out.writeInt(mUnpluggedLaunches);
                 }
 
-                long getLaunchTimeToNowLocked(long batteryUptime) {
+                public long getLaunchTimeToNowLocked(long batteryUptime) {
                     if (!mLaunched) return mLaunchedTime;
                     return mLaunchedTime + batteryUptime - mLaunchedSince;
                 }
 
-                long getStartTimeToNowLocked(long batteryUptime) {
+                public long getStartTimeToNowLocked(long batteryUptime) {
                     if (!mRunning) return mStartTime;
                     return mStartTime + batteryUptime - mRunningSince;
                 }
@@ -6860,14 +6993,14 @@
                 public void startLaunchedLocked() {
                     if (!mLaunched) {
                         mLaunches++;
-                        mLaunchedSince = getBatteryUptimeLocked();
+                        mLaunchedSince = mBsi.getBatteryUptimeLocked();
                         mLaunched = true;
                     }
                 }
 
                 public void stopLaunchedLocked() {
                     if (mLaunched) {
-                        long time = getBatteryUptimeLocked() - mLaunchedSince;
+                        long time = mBsi.getBatteryUptimeLocked() - mLaunchedSince;
                         if (time > 0) {
                             mLaunchedTime += time;
                         } else {
@@ -6880,14 +7013,14 @@
                 public void startRunningLocked() {
                     if (!mRunning) {
                         mStarts++;
-                        mRunningSince = getBatteryUptimeLocked();
+                        mRunningSince = mBsi.getBatteryUptimeLocked();
                         mRunning = true;
                     }
                 }
 
                 public void stopRunningLocked() {
                     if (mRunning) {
-                        long time = getBatteryUptimeLocked() - mRunningSince;
+                        long time = mBsi.getBatteryUptimeLocked() - mRunningSince;
                         if (time > 0) {
                             mStartTime += time;
                         } else {
@@ -6898,7 +7031,7 @@
                 }
 
                 public BatteryStatsImpl getBatteryStats() {
-                    return BatteryStatsImpl.this;
+                    return mBsi;
                 }
 
                 @Override
@@ -6937,7 +7070,7 @@
             }
 
             final Serv newServiceStatsLocked() {
-                return new Serv();
+                return new Serv(mBsi);
             }
         }
 
@@ -6948,7 +7081,7 @@
         public Proc getProcessStatsLocked(String name) {
             Proc ps = mProcessStats.get(name);
             if (ps == null) {
-                ps = new Proc(name);
+                ps = new Proc(mBsi, name);
                 mProcessStats.put(name, ps);
             }
 
@@ -6977,7 +7110,7 @@
 
             if (mProcessState == uidRunningState) return;
 
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long elapsedRealtime = mBsi.mClocks.elapsedRealtime();
 
             if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
                 mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtime);
@@ -7011,7 +7144,7 @@
         public Pkg getPackageStatsLocked(String name) {
             Pkg ps = mPackageStats.get(name);
             if (ps == null) {
-                ps = new Pkg();
+                ps = new Pkg(mBsi);
                 mPackageStats.put(name, ps);
             }
 
@@ -7046,7 +7179,7 @@
         }
 
         public void readWakeSummaryFromParcelLocked(String wlName, Parcel in) {
-            Wakelock wl = new Wakelock();
+            Wakelock wl = new Wakelock(mBsi, this);
             mWakelockStats.add(wlName, wl);
             if (in.readInt() != 0) {
                 wl.getStopwatchTimer(WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
@@ -7068,19 +7201,20 @@
                 if (!create) {
                     return null;
                 }
-                se = new Sensor(sensor);
+                se = new Sensor(mBsi, this, sensor);
                 mSensorStats.put(sensor, se);
             }
             StopwatchTimer t = se.mTimer;
             if (t != null) {
                 return t;
             }
-            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
+            ArrayList<StopwatchTimer> timers = mBsi.mSensorTimers.get(sensor);
             if (timers == null) {
                 timers = new ArrayList<StopwatchTimer>();
-                mSensorTimers.put(sensor, timers);
+                mBsi.mSensorTimers.put(sensor, timers);
             }
-            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mOnBatteryTimeBase);
+            t = new StopwatchTimer(mBsi.mClocks, this, BatteryStats.SENSOR, timers,
+                    mBsi.mOnBatteryTimeBase);
             se.mTimer = t;
             return t;
         }
@@ -7186,11 +7320,18 @@
         }
 
         public BatteryStatsImpl getBatteryStats() {
-            return BatteryStatsImpl.this;
+            return mBsi;
         }
     }
 
     public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
+        this(new SystemClocks(), systemDir, handler, externalSync);
+    }
+
+    public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
+            ExternalStatsSync externalSync) {
+        init(clocks);
+
         if (systemDir != null) {
             mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
                     new File(systemDir, "batterystats.bin.tmp"));
@@ -7202,24 +7343,28 @@
         mExternalSync = externalSync;
         mHandler = new MyHandler(handler.getLooper());
         mStartCount++;
-        mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
+        mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
-        }
-        mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase);
-        mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
-        mDeviceIdleModeLightTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase);
-        mDeviceIdleModeFullTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase);
-        mDeviceLightIdlingTimer = new StopwatchTimer(null, -15, null, mOnBatteryTimeBase);
-        mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase);
-        mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
+            mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
                     mOnBatteryTimeBase);
         }
-        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase);
+        mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase);
+        mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+                mOnBatteryTimeBase);
+        mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -11, null,
+                mOnBatteryTimeBase);
+        mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+        mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null, mOnBatteryTimeBase);
+        mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase);
+        mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase);
+        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i, null,
+                    mOnBatteryTimeBase);
+        }
+        mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+                mOnBatteryTimeBase);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null,
+            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i, null,
                     mOnBatteryTimeBase);
         }
         for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -7232,31 +7377,34 @@
         mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
                 ModemActivityInfo.TX_POWER_LEVELS);
 
-        mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
-        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
+        mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
+        mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
+                mOnBatteryTimeBase);
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
         mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
         mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
-        mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
+        mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
+        mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
-        }
-        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
-            mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i, null, mOnBatteryTimeBase);
-        }
-        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
-            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i, null,
+            mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i, null,
                     mOnBatteryTimeBase);
         }
-        mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
-        mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
-        mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
-        mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase);
-        mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase);
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i, null,
+                    mOnBatteryTimeBase);
+        }
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
+                    mOnBatteryTimeBase);
+        }
+        mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
+        mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
+        mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
+        mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
+        mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
-        long uptime = SystemClock.uptimeMillis() * 1000;
-        long realtime = SystemClock.elapsedRealtime() * 1000;
+        long uptime = mClocks.uptimeMillis() * 1000;
+        long realtime = mClocks.elapsedRealtime() * 1000;
         initTimes(uptime, realtime);
         mStartPlatformVersion = mEndPlatformVersion = Build.ID;
         mDischargeStartLevel = 0;
@@ -7270,6 +7418,11 @@
     }
 
     public BatteryStatsImpl(Parcel p) {
+        this(new SystemClocks(), p);
+    }
+
+    public BatteryStatsImpl(Clocks clocks, Parcel p) {
+        init(clocks);
         mFile = null;
         mCheckinFile = null;
         mDailyFile = null;
@@ -7808,9 +7961,9 @@
 
     public void resetAllStatsCmdLocked() {
         resetAllStatsLocked();
-        final long mSecUptime = SystemClock.uptimeMillis();
+        final long mSecUptime = mClocks.uptimeMillis();
         long uptime = mSecUptime * 1000;
-        long mSecRealtime = SystemClock.elapsedRealtime();
+        long mSecRealtime = mClocks.elapsedRealtime();
         long realtime = mSecRealtime * 1000;
         mDischargeStartLevel = mHistoryCur.batteryLevel;
         pullPendingStateUpdatesLocked();
@@ -7835,7 +7988,7 @@
 
     private void resetAllStatsLocked() {
         mStartCount = 0;
-        initTimes(SystemClock.uptimeMillis() * 1000, SystemClock.elapsedRealtime() * 1000);
+        initTimes(mClocks.uptimeMillis() * 1000, mClocks.elapsedRealtime() * 1000);
         mScreenOnTimer.reset(false);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].reset(false);
@@ -7983,17 +8136,8 @@
     private static final int NETWORK_STATS_NEXT = 1;
     private static final int NETWORK_STATS_DELTA = 2;
 
-    private final NetworkStats[] mMobileNetworkStats = new NetworkStats[] {
-            new NetworkStats(SystemClock.elapsedRealtime(), 50),
-            new NetworkStats(SystemClock.elapsedRealtime(), 50),
-            new NetworkStats(SystemClock.elapsedRealtime(), 50)
-    };
-
-    private final NetworkStats[] mWifiNetworkStats = new NetworkStats[] {
-            new NetworkStats(SystemClock.elapsedRealtime(), 50),
-            new NetworkStats(SystemClock.elapsedRealtime(), 50),
-            new NetworkStats(SystemClock.elapsedRealtime(), 50)
-    };
+    private NetworkStats[] mMobileNetworkStats;
+    private NetworkStats[] mWifiNetworkStats;
 
     /**
      * Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer
@@ -8026,7 +8170,7 @@
             Slog.d(TAG, "Updating wifi stats");
         }
 
-        final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
         NetworkStats delta = null;
         try {
             if (!ArrayUtils.isEmpty(mWifiIfaces)) {
@@ -8056,7 +8200,8 @@
                             + " txPackets=" + entry.txPackets);
                 }
 
-                if (entry.rxBytes == 0 || entry.txBytes == 0) {
+                if (entry.rxBytes == 0 && entry.txBytes == 0) {
+                    // Skip the lookup below since there is no work to do.
                     continue;
                 }
 
@@ -8570,7 +8715,7 @@
 
             SamplingTimer kwlt = mKernelWakelockStats.get(name);
             if (kwlt == null) {
-                kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
+                kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
                         true /* track reported val */);
                 mKernelWakelockStats.put(name, kwlt);
             }
@@ -8663,7 +8808,7 @@
         // Read the CPU data for each UID. This will internally generate a snapshot so next time
         // we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise
         // we just ignore the data.
-        final long startTimeMs = SystemClock.elapsedRealtime();
+        final long startTimeMs = mClocks.elapsedRealtime();
         mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null :
                 new KernelUidCpuTimeReader.Callback() {
                     @Override
@@ -8735,7 +8880,7 @@
                 });
 
         if (DEBUG_ENERGY_CPU) {
-            Slog.d(TAG, "Reading cpu stats took " + (SystemClock.elapsedRealtime() - startTimeMs) +
+            Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
                     " ms");
         }
 
@@ -9000,8 +9145,8 @@
     public void setBatteryStateLocked(int status, int health, int plugType, int level,
             int temp, int volt) {
         final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
-        final long uptime = SystemClock.uptimeMillis();
-        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
+        final long elapsedRealtime = mClocks.elapsedRealtime();
         if (!mHaveBatteryLevel) {
             mHaveBatteryLevel = true;
             // We start out assuming that the device is plugged in (not
@@ -9147,7 +9292,7 @@
     }
 
     public long getAwakeTimePlugged() {
-        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
+        return (mClocks.uptimeMillis() * 1000) - getAwakeTimeBattery();
     }
 
     @Override
@@ -9310,8 +9455,8 @@
         return mDailyPackageChanges;
     }
 
-    long getBatteryUptimeLocked() {
-        return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
+    protected long getBatteryUptimeLocked() {
+        return mOnBatteryTimeBase.getUptime(mClocks.uptimeMillis() * 1000);
     }
 
     @Override
@@ -9429,7 +9574,7 @@
     public Uid getUidStatsLocked(int uid) {
         Uid u = mUidStats.get(uid);
         if (u == null) {
-            u = new Uid(uid);
+            u = new Uid(this, uid);
             mUidStats.put(uid, u);
         }
         return u;
@@ -9474,7 +9619,7 @@
     }
 
     public void shutdownLocked() {
-        recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+        recordShutdownLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
         writeSyncLocked();
         mShuttingDown = true;
     }
@@ -9502,7 +9647,7 @@
 
         Parcel out = Parcel.obtain();
         writeSummaryToParcel(out, true);
-        mLastWriteTime = SystemClock.elapsedRealtime();
+        mLastWriteTime = mClocks.elapsedRealtime();
 
         if (mPendingWrite != null) {
             mPendingWrite.recycle();
@@ -9583,8 +9728,8 @@
 
         if (mHistoryBuffer.dataPosition() > 0) {
             mRecordingHistory = true;
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
+            final long elapsedRealtime = mClocks.elapsedRealtime();
+            final long uptime = mClocks.uptimeMillis();
             if (USE_OLD_HISTORY) {
                 addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
             }
@@ -9663,7 +9808,7 @@
         // We are just arbitrarily going to insert 1 minute from the sample of
         // the last run until samples in this run.
         if (mHistoryBaseTime > 0) {
-            long oldnow = SystemClock.elapsedRealtime();
+            long oldnow = mClocks.elapsedRealtime();
             mHistoryBaseTime = mHistoryBaseTime - oldnow + 1;
             if (DEBUG_HISTORY) {
                 StringBuilder sb = new StringBuilder(128);
@@ -9870,7 +10015,7 @@
         }
         for (int iu = 0; iu < NU; iu++) {
             int uid = in.readInt();
-            Uid u = new Uid(uid);
+            Uid u = new Uid(this, uid);
             mUidStats.put(uid, u);
 
             u.mWifiRunning = false;
@@ -10083,8 +10228,8 @@
         // if we had originally pulled a time before the RTC was set.
         long startClockTime = getStartClockTime();
 
-        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
-        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
+        final long NOW_SYS = mClocks.uptimeMillis() * 1000;
+        final long NOWREAL_SYS = mClocks.elapsedRealtime() * 1000;
 
         out.writeInt(VERSION);
 
@@ -10469,29 +10614,34 @@
         mOnBatteryScreenOffTimeBase.readFromParcel(in);
 
         mScreenState = Display.STATE_UNKNOWN;
-        mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase, in);
+        mScreenOnTimer = new StopwatchTimer(mClocks, 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);
+            mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
+                    mOnBatteryTimeBase, in);
         }
         mInteractive = false;
-        mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase, in);
+        mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase, in);
         mPhoneOn = false;
-        mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+                mOnBatteryTimeBase, in);
         mLongestLightIdleTime = in.readLong();
         mLongestFullIdleTime = in.readLong();
-        mDeviceIdleModeLightTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase, in);
-        mDeviceIdleModeFullTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase, in);
-        mDeviceLightIdlingTimer = new StopwatchTimer(null, -15, null, mOnBatteryTimeBase, in);
-        mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase, in);
-        mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
+        mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -14, null,
+                mOnBatteryTimeBase, in);
+        mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -11, null,
+                mOnBatteryTimeBase, in);
+        mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null,
+                mOnBatteryTimeBase, in);
+        mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase, in);
+        mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase, in);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
+            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i,
                     null, mOnBatteryTimeBase, in);
         }
-        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase, in);
+        mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+                mOnBatteryTimeBase, in);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
+            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i,
                     null, mOnBatteryTimeBase, in);
         }
         for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -10499,27 +10649,29 @@
             mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
         }
         mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-        mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
-        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
-                in);
+        mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null,
+                mOnBatteryTimeBase, in);
+        mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null, 
+                mOnBatteryTimeBase, in);
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
         mWifiOn = false;
-        mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
+        mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
         mGlobalWifiRunning = false;
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
+        mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null,
+                mOnBatteryTimeBase, in);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
+            mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i,
                     null, mOnBatteryTimeBase, in);
         }
         for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
-            mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i,
+            mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i,
                     null, mOnBatteryTimeBase, in);
         }
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
-            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
+            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
                     null, mOnBatteryTimeBase, in);
         }
 
@@ -10537,15 +10689,15 @@
         mLoadedNumConnectivityChange = in.readInt();
         mUnpluggedNumConnectivityChange = in.readInt();
         mAudioOnNesting = 0;
-        mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+        mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
         mVideoOnNesting = 0;
-        mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+        mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
         mFlashlightOnNesting = 0;
-        mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
+        mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase, in);
         mCameraOnNesting = 0;
-        mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase, in);
+        mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase, in);
         mBluetoothScanNesting = 0;
-        mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase, in);
+        mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase, in);
         mDischargeUnplugLevel = in.readInt();
         mDischargePlugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
@@ -10565,7 +10717,7 @@
         for (int ikw = 0; ikw < NKW; ikw++) {
             if (in.readInt() != 0) {
                 String wakelockName = in.readString();
-                SamplingTimer kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, in);
+                SamplingTimer kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase, in);
                 mKernelWakelockStats.put(wakelockName, kwlt);
             }
         }
@@ -10575,7 +10727,7 @@
         for (int iwr = 0; iwr < NWR; iwr++) {
             if (in.readInt() != 0) {
                 String reasonName = in.readString();
-                SamplingTimer timer = new SamplingTimer(mOnBatteryTimeBase, in);
+                SamplingTimer timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
                 mWakeupReasonStats.put(reasonName, timer);
             }
         }
@@ -10597,7 +10749,7 @@
         mUidStats.clear();
         for (int i = 0; i < numUids; i++) {
             int uid = in.readInt();
-            Uid u = new Uid(uid);
+            Uid u = new Uid(this, uid);
             u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
             mUidStats.append(uid, u);
         }
@@ -10620,8 +10772,8 @@
         // if we had originally pulled a time before the RTC was set.
         long startClockTime = getStartClockTime();
 
-        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
-        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
+        final long uSecUptime = mClocks.uptimeMillis() * 1000;
+        final long uSecRealtime = mClocks.elapsedRealtime() * 1000;
         final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
         final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
 
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index ed4722d..2a9264d 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -21,7 +21,6 @@
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Slog;
-import android.text.TextUtils;
 
 import com.android.internal.util.Preconditions;
 
@@ -140,14 +139,14 @@
     }
 
     public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
-            int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
+            int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
         dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
-                null /*outputPath*/, dexFlags, volumeUuid, useProfiles);
+                null /*outputPath*/, dexFlags, compilerFilter, volumeUuid);
     }
 
     public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
-            int dexoptNeeded, String outputPath, int dexFlags, String volumeUuid,
-            boolean useProfiles) throws InstallerException {
+            int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter,
+            String volumeUuid) throws InstallerException {
         execute("dexopt",
                 apkPath,
                 uid,
@@ -156,8 +155,27 @@
                 dexoptNeeded,
                 outputPath,
                 dexFlags,
-                volumeUuid,
-                useProfiles ? '1' : '0');
+                compilerFilter,
+                volumeUuid);
+    }
+
+    public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
+        String rawReply = executeForResult("merge_profiles", uid, pkgName);
+        if (rawReply == null) {
+            throw new IllegalStateException("Unexpected null reply");
+        }
+        final String res[] = rawReply.split(" ");
+
+        if ((res == null) || (res.length != 2)) {
+            throw new InstallerException("Invalid size result: " + rawReply);
+        }
+
+        // Just as a sanity check. Anything != "true" will be interpreted as false by parseBoolean.
+        if (!res[1].equals("true") && !res[1].equals("false")) {
+            throw new InstallerException("Invalid boolean result: " + rawReply);
+        }
+
+        return Boolean.parseBoolean(res[1]);
     }
 
     private boolean connect() {
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 14ebe22..79138b7 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -85,6 +85,7 @@
     public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
     public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
     public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
+    public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels";
     public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
 
     public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
@@ -287,9 +288,15 @@
         };
 
         for (int i = 0; i < configResIds.length; i++) {
+            String key = configResIdKeys[i];
+            // if we already have some of these parameters in power_profile.xml, ignore the
+            // value in config.xml
+            if ((sPowerMap.containsKey(key) && (Double) sPowerMap.get(key) > 0)) {
+                continue;
+            }
             int value = resources.getInteger(configResIds[i]);
             if (value > 0) {
-                sPowerMap.put(configResIdKeys[i], (double) value);
+                sPowerMap.put(key, (double) value);
             }
         }
     }
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index e298201..fff9d7c 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -20,6 +20,7 @@
 import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
 import android.os.Build;
+import android.os.DeadObjectException;
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.Process;
@@ -96,10 +97,14 @@
                 ActivityManagerNative.getDefault().handleApplicationCrash(
                         mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
             } catch (Throwable t2) {
-                try {
-                    Clog_e(TAG, "Error reporting crash", t2);
-                } catch (Throwable t3) {
-                    // Even Clog_e() fails!  Oh well.
+                if (t2 instanceof DeadObjectException) {
+                    // System process is dead; ignore
+                } else {
+                    try {
+                        Clog_e(TAG, "Error reporting crash", t2);
+                    } catch (Throwable t3) {
+                        // Even Clog_e() fails!  Oh well.
+                    }
                 }
             } finally {
                 // Try everything to make sure this process goes away.
@@ -358,8 +363,12 @@
                 System.exit(10);
             }
         } catch (Throwable t2) {
-            Slog.e(TAG, "Error reporting WTF", t2);
-            Slog.e(TAG, "Original WTF:", t);
+            if (t2 instanceof DeadObjectException) {
+                // System process is dead; ignore
+            } else {
+                Slog.e(TAG, "Error reporting WTF", t2);
+                Slog.e(TAG, "Original WTF:", t);
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 919254a..66cc975 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -149,6 +149,12 @@
     native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
 
+    /**
+     * Zygote unmount storage space on initializing.
+     * This method is called once.
+     */
+    native protected static void nativeUnmountStorageOnInit();
+
     private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
             String instructionSet) {
         VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 6ad9e20..5980ab6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -36,6 +36,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.webkit.WebViewFactory;
+import android.widget.TextView;
 
 import com.android.internal.os.InstallerConnection.InstallerException;
 
@@ -214,6 +215,7 @@
 
     private static void preloadTextResources() {
         Hyphenator.init();
+        TextView.preloadFontCache();
     }
 
     /**
@@ -497,14 +499,16 @@
 
         try {
             for (String classPathElement : classPathElements) {
+                // System server is fully AOTed and never profiled
+                // for profile guided compilation.
+                // TODO: Make this configurable between INTERPRET_ONLY, SPEED, SPACE and EVERYTHING?
                 final int dexoptNeeded = DexFile.getDexOptNeeded(
-                        classPathElement, "*", instructionSet, false /* defer */);
+                        classPathElement, instructionSet, "speed",
+                        false /* newProfile */);
                 if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                    // System server is fully AOTed and never profiled
-                    // for profile guided compilation.
                     installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
-                            dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/,
-                            false /*useProfiles*/);
+                            dexoptNeeded, 0 /*dexFlags*/, "speed",
+                            null /*volumeUuid*/);
                 }
             }
         } catch (IOException | InstallerException e) {
@@ -641,6 +645,9 @@
             // Zygote.
             Trace.setTracingEnabled(false);
 
+            // Zygote process unmounts root storage spaces.
+            Zygote.nativeUnmountStorageOnInit();
+
             if (startSystemServer) {
                 startSystemServer(abiList, socketName);
             }
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 6931193..738aaca 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.policy;
 
+import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -69,6 +71,7 @@
     private ColorDrawable mNavigationBarColor;
     private boolean mOldFullscreen;
     private boolean mFullscreen;
+    private final int mResizeMode;
     private final Rect mOldSystemInsets = new Rect();
     private final Rect mOldStableInsets = new Rect();
     private final Rect mSystemInsets = new Rect();
@@ -77,7 +80,7 @@
     public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
             Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
             Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor,
-            boolean fullscreen, Rect systemInsets, Rect stableInsets) {
+            boolean fullscreen, Rect systemInsets, Rect stableInsets, int resizeMode) {
         setName("ResizeFrame");
 
         mRenderer = renderer;
@@ -98,6 +101,7 @@
         mStableInsets.set(stableInsets);
         mOldSystemInsets.set(systemInsets);
         mOldStableInsets.set(stableInsets);
+        mResizeMode = resizeMode;
         synchronized (this) {
             redrawLocked(initialBounds, fullscreen, mSystemInsets, mStableInsets);
         }
@@ -266,11 +270,16 @@
             mLastXOffset = xOffset;
             mLastYOffset = yOffset;
 
-            mRenderer.setContentDrawBounds(
-                    mLastXOffset,
-                    mLastYOffset,
-                    mLastXOffset + mLastContentWidth,
-                    mLastYOffset + mLastCaptionHeight + mLastContentHeight);
+            // Only clip the content to the bounds if we are not fullscreen. In the other case, we
+            // actually need to draw outside these.
+            if (mResizeMode == RESIZE_MODE_FREEFORM) {
+                mRenderer.setContentDrawBounds(
+                        mLastXOffset,
+                        mLastYOffset,
+                        mLastXOffset + mLastContentWidth,
+                        mLastYOffset + mLastCaptionHeight + mLastContentHeight);
+            }
+
             // If this was the first call and redrawLocked got already called prior
             // to us, we should re-issue a redrawLocked now.
             return firstCall
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 3d60926..ea0fbda 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -39,8 +39,11 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.RemoteException;
@@ -49,6 +52,7 @@
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.ContextThemeWrapper;
+import android.view.DisplayListCanvas;
 import android.view.Gravity;
 import android.view.InputQueue;
 import android.view.KeyEvent;
@@ -88,6 +92,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -178,6 +183,7 @@
     private boolean mLastHasBottomStableInset = false;
     private boolean mLastHasRightStableInset = false;
     private int mLastWindowFlags = 0;
+    private boolean mLastShouldAlwaysConsumeNavBar = false;
 
     private int mRootScrollY = 0;
 
@@ -203,6 +209,7 @@
     private Drawable mResizingBackgroundDrawable;
     private Drawable mCaptionBackgroundDrawable;
     private Drawable mUserCaptionBackgroundDrawable;
+    private Drawable mOriginalBackgroundDrawable;
 
     private float mAvailableWidth;
 
@@ -211,6 +218,11 @@
     private boolean mApplyFloatingVerticalInsets = false;
     private boolean mApplyFloatingHorizontalInsets = false;
 
+    private int mResizeMode = RESIZE_MODE_INVALID;
+    private final int mResizeShadowSize;
+    private final Paint mVerticalResizeShadowPaint = new Paint();
+    private final Paint mHorizontalResizeShadowPaint = new Paint();
+
     DecorView(Context context, int featureId, PhoneWindow window,
             WindowManager.LayoutParams params) {
         super(context);
@@ -233,6 +245,10 @@
         setWindow(window);
 
         updateLogTag(params);
+
+        mResizeShadowSize = context.getResources().getDimensionPixelSize(
+                R.dimen.resize_shadow_size);
+        initResizingPaints();
     }
 
     void setBackgroundFallback(int resId) {
@@ -585,14 +601,14 @@
                     w = 0;
                 }
                 if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed width: " + w);
+                final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
                 if (w > 0) {
-                    final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
                     widthMeasureSpec = MeasureSpec.makeMeasureSpec(
                             Math.min(w, widthSize), EXACTLY);
                     fixedWidth = true;
                 } else {
                     widthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                            widthMeasureSpec - mFloatingInsets.left - mFloatingInsets.right,
+                            widthSize - mFloatingInsets.left - mFloatingInsets.right,
                             AT_MOST);
                     mApplyFloatingHorizontalInsets = true;
                 }
@@ -699,6 +715,10 @@
         // our shadow elevation.
         updateElevation();
         mAllowUpdateElevation = true;
+
+        if (changed && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER) {
+            getViewRootImpl().requestInvalidateRootRenderNode();
+        }
     }
 
     @Override
@@ -869,6 +889,11 @@
                 mBackgroundPadding.setEmpty();
             }
             drawableChanged();
+
+            // Make sure we don't reset to the old drawable when finishing resizing.
+            if (mResizeMode != RESIZE_MODE_INVALID) {
+                mOriginalBackgroundDrawable = null;
+            }
         }
     }
 
@@ -978,6 +1003,7 @@
                 boolean hasRightStableInset = insets.getStableInsetRight() != 0;
                 disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset);
                 mLastHasRightStableInset = hasRightStableInset;
+                mLastShouldAlwaysConsumeNavBar = insets.shouldAlwaysConsumeNavBar();
             }
 
             boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
@@ -998,11 +1024,11 @@
         // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need
         // to ensure that the rest of the view hierarchy doesn't notice it, unless they've
         // explicitly asked for it.
-
         boolean consumingNavBar =
                 (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                         && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
-                        && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+                        && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
+                || mLastShouldAlwaysConsumeNavBar;
 
         // If we didn't request fullscreen layout, but we still got it because of the
         // mForceWindowDrawsStatusBarBackground flag, also consume top inset.
@@ -1744,6 +1770,10 @@
             mCaptionBackgroundDrawable = getContext().getDrawable(
                     R.drawable.decor_caption_title_focused);
         }
+        if (mResizingBackgroundDrawable != null) {
+            mLastBackgroundDrawableCb = mResizingBackgroundDrawable.getCallback();
+            mResizingBackgroundDrawable.setCallback(null);
+        }
     }
 
     // Free floating overlapping windows require a caption.
@@ -1902,7 +1932,7 @@
 
     @Override
     public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
-            Rect stableInsets) {
+            Rect stableInsets, int resizeMode) {
         if (mWindow.isDestroyed()) {
             // If the owner's window is gone, we should not be able to come here anymore.
             releaseThreadedRenderer();
@@ -1914,16 +1944,11 @@
         final ThreadedRenderer renderer = getHardwareRenderer();
         if (renderer != null) {
             loadBackgroundDrawablesIfNeeded();
-            if (mResizingBackgroundDrawable != null) {
-                mLastBackgroundDrawableCb = mResizingBackgroundDrawable.getCallback();
-                mResizingBackgroundDrawable.setCallback(null);
-            }
-
             mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
                     initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                     mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
                     getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
-                    stableInsets);
+                    stableInsets, resizeMode);
 
             // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
             // If we want to get the shadow shown while resizing, we would need to elevate a new
@@ -1931,13 +1956,24 @@
             updateElevation();
 
             updateColorViews(null /* insets */, false);
+
+            mOriginalBackgroundDrawable = getBackground();
+            setBackgroundDrawable(null);
         }
+        mResizeMode = resizeMode;
+        getViewRootImpl().requestInvalidateRootRenderNode();
     }
 
     @Override
     public void onWindowDragResizeEnd() {
         releaseThreadedRenderer();
         updateColorViews(null /* insets */, false);
+        mResizeMode = RESIZE_MODE_INVALID;
+        getViewRootImpl().requestInvalidateRootRenderNode();
+        if (mOriginalBackgroundDrawable != null) {
+            setBackgroundDrawable(mOriginalBackgroundDrawable);
+            mOriginalBackgroundDrawable = null;
+        }
     }
 
     @Override
@@ -1960,6 +1996,41 @@
         }
     }
 
+    @Override
+    public void onPostDraw(DisplayListCanvas canvas) {
+        drawResizingShadowIfNeeded(canvas);
+    }
+
+    private void initResizingPaints() {
+        final int startColor = mContext.getResources().getColor(
+                R.color.resize_shadow_start_color, null);
+        final int endColor = mContext.getResources().getColor(
+                R.color.resize_shadow_end_color, null);
+        final int middleColor = (startColor + endColor) / 2;
+        mHorizontalResizeShadowPaint.setShader(new LinearGradient(
+                0, 0, 0, mResizeShadowSize, new int[] { startColor, middleColor, endColor },
+                new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
+        mVerticalResizeShadowPaint.setShader(new LinearGradient(
+                0, 0, mResizeShadowSize, 0, new int[] { startColor, middleColor, endColor },
+                new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
+    }
+
+    private void drawResizingShadowIfNeeded(DisplayListCanvas canvas) {
+        if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
+                || mWindow.isTranslucent()
+                || (mWindow.getAttributes().flags & FLAG_SHOW_WALLPAPER) != 0) {
+            return;
+        }
+        canvas.save();
+        canvas.translate(0, getHeight() - mFrameOffsets.bottom);
+        canvas.drawRect(0, 0, getWidth(), mResizeShadowSize, mHorizontalResizeShadowPaint);
+        canvas.restore();
+        canvas.save();
+        canvas.translate(getWidth() - mFrameOffsets.right, 0);
+        canvas.drawRect(0, 0, mResizeShadowSize, getHeight(), mVerticalResizeShadowPaint);
+        canvas.restore();
+    }
+
     /** Release the renderer thread which is usually done when the user stops resizing. */
     private void releaseThreadedRenderer() {
         if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
@@ -2070,14 +2141,10 @@
      * @hide
      */
     @Override
-    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list) {
+    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list, int deviceId) {
         final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
         if (!mWindow.isDestroyed() && st != null && mWindow.getCallback() != null) {
-            try {
-                mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu);
-            } catch (AbstractMethodError e) {
-                // We run into this if the app is using supportlib.
-            }
+            mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu, deviceId);
         }
     }
 
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 84d0fc7..9907ea9 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -279,6 +279,26 @@
     }
 
     /**
+     * Cycles through all non-dismiss targets with a stepping of {@param increment}. It moves left
+     * if {@param increment} is negative and moves right otherwise.
+     */
+    public SnapTarget cycleNonDismissTarget(SnapTarget snapTarget, int increment) {
+        int index = mTargets.indexOf(snapTarget);
+        if (index != -1) {
+            SnapTarget newTarget = mTargets.get((index + mTargets.size() + increment)
+                    % mTargets.size());
+            if (newTarget == mDismissStartTarget) {
+                return mLastSplitTarget;
+            } else if (newTarget == mDismissEndTarget) {
+                return mFirstSplitTarget;
+            } else {
+                return newTarget;
+            }
+        }
+        return snapTarget;
+    }
+
+    /**
      * Represents a snap target for the divider.
      */
     public static class SnapTarget {
diff --git a/core/java/com/android/internal/policy/IShortcutService.aidl b/core/java/com/android/internal/policy/IShortcutService.aidl
new file mode 100644
index 0000000..8550728
--- /dev/null
+++ b/core/java/com/android/internal/policy/IShortcutService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+/**
+ * An interface to notify the shortcut service that a shortcut key is pressed
+ * @hide
+ */
+oneway interface IShortcutService {
+    /**
+     * @param shortcutCode the keycode packed with meta information
+     */
+    void notifyShortcutKeyPressed(long shortcutCode);
+}
+
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 7637eec..0f257d7 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -24,6 +24,7 @@
 import android.app.SearchManager;
 import android.os.UserHandle;
 
+import android.text.TextUtils;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.IRotationWatcher.Stub;
@@ -157,6 +158,7 @@
     InputQueue.Callback mTakeInputQueueCallback;
 
     boolean mIsFloating;
+    private boolean mIsTranslucent;
 
     private LayoutInflater mLayoutInflater;
 
@@ -490,6 +492,10 @@
         return mIsFloating;
     }
 
+    public boolean isTranslucent() {
+        return mIsTranslucent;
+    }
+
     /**
      * Return a LayoutInflater instance that can be used to inflate XML view layout
      * resources for use in this Window.
@@ -509,6 +515,11 @@
             mDecorContentParent.setWindowTitle(title);
         }
         mTitle = title;
+        WindowManager.LayoutParams params = getAttributes();
+        if (!TextUtils.equals(title, params.getTitle())) {
+            params.setTitle(title);
+            dispatchWindowAttributesChanged(getAttributes());
+        }
     }
 
     @Override
@@ -675,7 +686,7 @@
     }
 
     @Override
-    public void onMultiWindowChanged() {
+    public void onMultiWindowModeChanged() {
         if (mDecor != null) {
             mDecor.onConfigurationChanged(getContext().getResources().getConfiguration());
         }
@@ -2400,6 +2411,8 @@
             requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
         }
 
+        mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);
+
         final Context context = getContext();
         final int targetSdk = context.getApplicationInfo().targetSdkVersion;
         final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 08d4fba..9e5c238 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -60,11 +60,12 @@
     void showRecentApps(boolean triggeredFromAltTab);
     void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
     void toggleRecentApps();
+    void toggleSplitScreen();
     void preloadRecentApps();
     void cancelPreloadRecentApps();
     void showScreenPinningRequest();
 
-    void toggleKeyboardShortcutsMenu();
+    void toggleKeyboardShortcutsMenu(int deviceId);
 
     /**
      * Notifies the status bar that an app transition is pending to delay applying some flags with
@@ -87,6 +88,11 @@
      */
     void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
 
+    /**
+     * Notifies the status bar that an app transition is done.
+     */
+    void appTransitionFinished();
+
     void showAssistDisclosure();
     void startAssist(in Bundle args);
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 8acf5d3..ee3f937 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -71,7 +71,7 @@
     void preloadRecentApps();
     void cancelPreloadRecentApps();
 
-    void toggleKeyboardShortcutsMenu();
+    void toggleKeyboardShortcutsMenu(int deviceId);
 
     /**
      * Notifies the status bar that an app transition is pending to delay applying some flags with
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 8026949..bed5a2e 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -27,6 +27,8 @@
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -126,6 +128,13 @@
     /**
      * Checks if given array is null or has zero elements.
      */
+    public static boolean isEmpty(@Nullable List<?> array) {
+        return array == null || array.isEmpty();
+    }
+
+    /**
+     * Checks if given array is null or has zero elements.
+     */
     public static <T> boolean isEmpty(@Nullable T[] array) {
         return array == null || array.length == 0;
     }
@@ -229,6 +238,14 @@
         return total;
     }
 
+    public static int[] convertToIntArray(List<Integer> list) {
+        int[] array = new int[list.size()];
+        for (int i = 0; i < list.size(); i++) {
+            array[i] = list.get(i);
+        }
+        return array;
+    }
+
     /**
      * Adds value to given array if not already present, providing set-like
      * behavior.
@@ -469,4 +486,48 @@
         }
         return !diff;
     }
+
+    /**
+     * Removes elements that match the predicate in an efficient way that alters the order of
+     * elements in the collection. This should only be used if order is not important.
+     * @param collection The ArrayList from which to remove elements.
+     * @param predicate The predicate that each element is tested against.
+     * @return the number of elements removed.
+     */
+    public static <T> int unstableRemoveIf(@Nullable ArrayList<T> collection,
+                                           @NonNull java.util.function.Predicate<T> predicate) {
+        if (collection == null) {
+            return 0;
+        }
+
+        final int size = collection.size();
+        int leftIdx = 0;
+        int rightIdx = size - 1;
+        while (leftIdx <= rightIdx) {
+            // Find the next element to remove moving left to right.
+            while (leftIdx < size && !predicate.test(collection.get(leftIdx))) {
+                leftIdx++;
+            }
+
+            // Find the next element to keep moving right to left.
+            while (rightIdx > leftIdx && predicate.test(collection.get(rightIdx))) {
+                rightIdx--;
+            }
+
+            if (leftIdx >= rightIdx) {
+                // Done.
+                break;
+            }
+
+            Collections.swap(collection, leftIdx, rightIdx);
+            leftIdx++;
+            rightIdx--;
+        }
+
+        // leftIdx is now at the end.
+        for (int i = size - 1; i >= leftIdx; i--) {
+            collection.remove(i);
+        }
+        return size - leftIdx;
+    }
 }
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index bd0e6ce..d8be9fd 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -402,7 +402,7 @@
 
         // Initialize destination fields
         mDstMessenger = dstMessenger;
-
+        linkToDeathMonitor();
         if (DBG) log("connected srcHandler to the dstMessenger X");
     }
 
@@ -844,22 +844,30 @@
         msg.arg1 = status;
         msg.obj = this;
         msg.replyTo = mDstMessenger;
+        if (!linkToDeathMonitor()) {
+            // Override status to indicate failure
+            msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+        }
 
-        /*
-         * Link to death only when bindService isn't used.
-         */
-        if (mConnection == null) {
+        mSrcHandler.sendMessage(msg);
+    }
+
+    /**
+     * Link to death monitor for destination messenger. Returns true if successfully binded to
+     * destination messenger; false otherwise.
+     */
+    private boolean linkToDeathMonitor() {
+        // Link to death only when bindService isn't used and not already linked.
+        if (mConnection == null && mDeathMonitor == null) {
             mDeathMonitor = new DeathMonitor();
             try {
                 mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
             } catch (RemoteException e) {
                 mDeathMonitor = null;
-                // Override status to indicate failure
-                msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+                return false;
             }
         }
-
-        mSrcHandler.sendMessage(msg);
+        return true;
     }
 
     /**
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
index 7a04080..3c1d2d6 100644
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ b/core/java/com/android/internal/util/FastXmlSerializer.java
@@ -28,6 +28,7 @@
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
 
@@ -38,14 +39,14 @@
  */
 public class FastXmlSerializer implements XmlSerializer {
     private static final String ESCAPE_TABLE[] = new String[] {
-        null,     null,     null,     null,     null,     null,     null,     null,  // 0-7
-        null,     null,     null,     null,     null,     null,     null,     null,  // 8-15
-        null,     null,     null,     null,     null,     null,     null,     null,  // 16-23
-        null,     null,     null,     null,     null,     null,     null,     null,  // 24-31
-        null,     null,     "&quot;", null,     null,     null,     "&amp;",  null,  // 32-39
-        null,     null,     null,     null,     null,     null,     null,     null,  // 40-47
-        null,     null,     null,     null,     null,     null,     null,     null,  // 48-55
-        null,     null,     null,     null,     "&lt;",   null,     "&gt;",   null,  // 56-63
+        "&#0;",   "&#1;",   "&#2;",   "&#3;",  "&#4;",    "&#5;",   "&#6;",  "&#7;",  // 0-7
+        "&#8;",   "&#9;",   "&#10;",  "&#11;", "&#12;",   "&#13;",  "&#14;", "&#15;", // 8-15
+        "&#16;",  "&#17;",  "&#18;",  "&#19;", "&#20;",   "&#21;",  "&#22;", "&#23;", // 16-23
+        "&#24;",  "&#25;",  "&#26;",  "&#27;", "&#28;",   "&#29;",  "&#30;", "&#31;", // 24-31
+        null,     null,     "&quot;", null,     null,     null,     "&amp;",  null,   // 32-39
+        null,     null,     null,     null,     null,     null,     null,     null,   // 40-47
+        null,     null,     null,     null,     null,     null,     null,     null,   // 48-55
+        null,     null,     null,     null,     "&lt;",   null,     "&gt;",   null,   // 56-63
     };
 
     private static final int BUFFER_LEN = 8192;
@@ -310,7 +311,9 @@
             throw new IllegalArgumentException();
         if (true) {
             try {
-                mCharset = Charset.forName(encoding).newEncoder();
+                mCharset = Charset.forName(encoding).newEncoder()
+                        .onMalformedInput(CodingErrorAction.REPLACE)
+                        .onUnmappableCharacter(CodingErrorAction.REPLACE);
             } catch (IllegalCharsetNameException e) {
                 throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
                         encoding).initCause(e));
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
index 1014bfd..184245e 100644
--- a/core/java/com/android/internal/util/MessageUtils.java
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -21,6 +21,7 @@
 import android.util.SparseArray;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 
 /**
  * Static utility class for dealing with {@link Message} objects.
@@ -62,8 +63,12 @@
             }
 
             for (Field field : fields) {
-                String name = field.getName();
+                int modifiers = field.getModifiers();
+                if (!Modifier.isStatic(modifiers) | !Modifier.isFinal(modifiers)) {
+                    continue;
+                }
 
+                String name = field.getName();
                 for (String prefix : prefixes) {
                     // Does this look like a constant?
                     if (!name.startsWith(prefix)) {
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 6076973..48bcc09 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -16,6 +16,11 @@
 
 package com.android.internal.util;
 
+import android.annotation.ColorInt;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.app.Notification;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -43,6 +48,7 @@
 public class NotificationColorUtil {
 
     private static final String TAG = "NotificationColorUtil";
+    private static final boolean DEBUG = false;
 
     private static final Object sLock = new Object();
     private static NotificationColorUtil sInstance;
@@ -222,4 +228,420 @@
                 255 - Color.green(color),
                 255 - Color.blue(color));
     }
+
+    /**
+     * Finds a suitable color such that there's enough contrast.
+     *
+     * @param color the color to start searching from.
+     * @param other the color to ensure contrast against. Assumed to be lighter than {@param color}
+     * @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
+     * @param minRatio the minimum contrast ratio required.
+     * @return a color with the same hue as {@param color}, potentially darkened to meet the
+     *          contrast ratio.
+     */
+    private static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
+        int fg = findFg ? color : other;
+        int bg = findFg ? other : color;
+        if (ColorUtilsFromCompat.calculateContrast(fg, bg) >= minRatio) {
+            return color;
+        }
+
+        double[] lab = new double[3];
+        ColorUtilsFromCompat.colorToLAB(findFg ? fg : bg, lab);
+
+        double low = 0, high = lab[0];
+        final double a = lab[1], b = lab[2];
+        for (int i = 0; i < 15 && high - low > 0.00001; i++) {
+            final double l = (low + high) / 2;
+            if (findFg) {
+                fg = ColorUtilsFromCompat.LABToColor(l, a, b);
+            } else {
+                bg = ColorUtilsFromCompat.LABToColor(l, a, b);
+            }
+            if (ColorUtilsFromCompat.calculateContrast(fg, bg) > minRatio) {
+                low = l;
+            } else {
+                high = l;
+            }
+        }
+        return ColorUtilsFromCompat.LABToColor(low, a, b);
+    }
+
+    /**
+     * Finds a text color with sufficient contrast over bg that has the same hue as the original
+     * color, assuming it is for large text.
+     */
+    private static int ensureLargeTextContrast(int color, int bg) {
+        return findContrastColor(color, bg, true, 3);
+    }
+
+    /**
+     * Finds a text color with sufficient contrast over bg that has the same hue as the original
+     * color.
+     */
+    private static int ensureTextContrast(int color, int bg) {
+        return findContrastColor(color, bg, true, 4.5);
+    }
+
+    /** Finds a background color for a text view with given text color and hint text color, that
+     * has the same hue as the original color.
+     */
+    public static int ensureTextBackgroundColor(int color, int textColor, int hintColor) {
+        color = findContrastColor(color, hintColor, false, 3.0);
+        return findContrastColor(color, textColor, false, 4.5);
+    }
+
+    private static String contrastChange(int colorOld, int colorNew, int bg) {
+        return String.format("from %.2f:1 to %.2f:1",
+                ColorUtilsFromCompat.calculateContrast(colorOld, bg),
+                ColorUtilsFromCompat.calculateContrast(colorNew, bg));
+    }
+
+    /**
+     * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
+     */
+    public static int resolveColor(Context context, int color) {
+        if (color == Notification.COLOR_DEFAULT) {
+            return context.getColor(com.android.internal.R.color.notification_icon_default_color);
+        }
+        return color;
+    }
+
+    /**
+     * Resolves a Notification's color such that it has enough contrast to be used as the
+     * color for the Notification's action and header text.
+     *
+     * @param notificationColor the color of the notification or {@link Notification#COLOR_DEFAULT}
+     * @return a color of the same hue with enough contrast against the backgrounds.
+     */
+    public static int resolveContrastColor(Context context, int notificationColor) {
+        final int resolvedColor = resolveColor(context, notificationColor);
+
+        final int actionBg = context.getColor(
+                com.android.internal.R.color.notification_action_list);
+        final int notiBg = context.getColor(
+                com.android.internal.R.color.notification_material_background_color);
+
+        int color = resolvedColor;
+        color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg);
+        color = NotificationColorUtil.ensureTextContrast(color, notiBg);
+
+        if (color != resolvedColor) {
+            if (DEBUG){
+                Log.w(TAG, String.format(
+                        "Enhanced contrast of notification for %s %s (over action)"
+                                + " and %s (over background) by changing #%s to %s",
+                        context.getPackageName(),
+                        NotificationColorUtil.contrastChange(resolvedColor, color, actionBg),
+                        NotificationColorUtil.contrastChange(resolvedColor, color, notiBg),
+                        Integer.toHexString(resolvedColor), Integer.toHexString(color)));
+            }
+        }
+        return color;
+    }
+
+    /**
+     * Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
+     */
+    private static class ColorUtilsFromCompat {
+        private static final double XYZ_WHITE_REFERENCE_X = 95.047;
+        private static final double XYZ_WHITE_REFERENCE_Y = 100;
+        private static final double XYZ_WHITE_REFERENCE_Z = 108.883;
+        private static final double XYZ_EPSILON = 0.008856;
+        private static final double XYZ_KAPPA = 903.3;
+
+        private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
+        private static final int MIN_ALPHA_SEARCH_PRECISION = 1;
+
+        private static final ThreadLocal<double[]> TEMP_ARRAY = new ThreadLocal<>();
+
+        private ColorUtilsFromCompat() {}
+
+        /**
+         * Composite two potentially translucent colors over each other and returns the result.
+         */
+        public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
+            int bgAlpha = Color.alpha(background);
+            int fgAlpha = Color.alpha(foreground);
+            int a = compositeAlpha(fgAlpha, bgAlpha);
+
+            int r = compositeComponent(Color.red(foreground), fgAlpha,
+                    Color.red(background), bgAlpha, a);
+            int g = compositeComponent(Color.green(foreground), fgAlpha,
+                    Color.green(background), bgAlpha, a);
+            int b = compositeComponent(Color.blue(foreground), fgAlpha,
+                    Color.blue(background), bgAlpha, a);
+
+            return Color.argb(a, r, g, b);
+        }
+
+        private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
+            return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
+        }
+
+        private static int compositeComponent(int fgC, int fgA, int bgC, int bgA, int a) {
+            if (a == 0) return 0;
+            return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
+        }
+
+        /**
+         * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}.
+         * <p>Defined as the Y component in the XYZ representation of {@code color}.</p>
+         */
+        @FloatRange(from = 0.0, to = 1.0)
+        public static double calculateLuminance(@ColorInt int color) {
+            final double[] result = getTempDouble3Array();
+            colorToXYZ(color, result);
+            // Luminance is the Y component
+            return result[1] / 100;
+        }
+
+        /**
+         * Returns the contrast ratio between {@code foreground} and {@code background}.
+         * {@code background} must be opaque.
+         * <p>
+         * Formula defined
+         * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef">here</a>.
+         */
+        public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) {
+            if (Color.alpha(background) != 255) {
+                throw new IllegalArgumentException("background can not be translucent: #"
+                        + Integer.toHexString(background));
+            }
+            if (Color.alpha(foreground) < 255) {
+                // If the foreground is translucent, composite the foreground over the background
+                foreground = compositeColors(foreground, background);
+            }
+
+            final double luminance1 = calculateLuminance(foreground) + 0.05;
+            final double luminance2 = calculateLuminance(background) + 0.05;
+
+            // Now return the lighter luminance divided by the darker luminance
+            return Math.max(luminance1, luminance2) / Math.min(luminance1, luminance2);
+        }
+
+        /**
+         * Convert the ARGB color to its CIE Lab representative components.
+         *
+         * @param color  the ARGB color to convert. The alpha component is ignored
+         * @param outLab 3-element array which holds the resulting LAB components
+         */
+        public static void colorToLAB(@ColorInt int color, @NonNull double[] outLab) {
+            RGBToLAB(Color.red(color), Color.green(color), Color.blue(color), outLab);
+        }
+
+        /**
+         * Convert RGB components to its CIE Lab representative components.
+         *
+         * <ul>
+         * <li>outLab[0] is L [0 ...1)</li>
+         * <li>outLab[1] is a [-128...127)</li>
+         * <li>outLab[2] is b [-128...127)</li>
+         * </ul>
+         *
+         * @param r      red component value [0..255]
+         * @param g      green component value [0..255]
+         * @param b      blue component value [0..255]
+         * @param outLab 3-element array which holds the resulting LAB components
+         */
+        public static void RGBToLAB(@IntRange(from = 0x0, to = 0xFF) int r,
+                @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+                @NonNull double[] outLab) {
+            // First we convert RGB to XYZ
+            RGBToXYZ(r, g, b, outLab);
+            // outLab now contains XYZ
+            XYZToLAB(outLab[0], outLab[1], outLab[2], outLab);
+            // outLab now contains LAB representation
+        }
+
+        /**
+         * Convert the ARGB color to it's CIE XYZ representative components.
+         *
+         * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+         * 2° Standard Observer (1931).</p>
+         *
+         * <ul>
+         * <li>outXyz[0] is X [0 ...95.047)</li>
+         * <li>outXyz[1] is Y [0...100)</li>
+         * <li>outXyz[2] is Z [0...108.883)</li>
+         * </ul>
+         *
+         * @param color  the ARGB color to convert. The alpha component is ignored
+         * @param outXyz 3-element array which holds the resulting LAB components
+         */
+        public static void colorToXYZ(@ColorInt int color, @NonNull double[] outXyz) {
+            RGBToXYZ(Color.red(color), Color.green(color), Color.blue(color), outXyz);
+        }
+
+        /**
+         * Convert RGB components to it's CIE XYZ representative components.
+         *
+         * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+         * 2° Standard Observer (1931).</p>
+         *
+         * <ul>
+         * <li>outXyz[0] is X [0 ...95.047)</li>
+         * <li>outXyz[1] is Y [0...100)</li>
+         * <li>outXyz[2] is Z [0...108.883)</li>
+         * </ul>
+         *
+         * @param r      red component value [0..255]
+         * @param g      green component value [0..255]
+         * @param b      blue component value [0..255]
+         * @param outXyz 3-element array which holds the resulting XYZ components
+         */
+        public static void RGBToXYZ(@IntRange(from = 0x0, to = 0xFF) int r,
+                @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+                @NonNull double[] outXyz) {
+            if (outXyz.length != 3) {
+                throw new IllegalArgumentException("outXyz must have a length of 3.");
+            }
+
+            double sr = r / 255.0;
+            sr = sr < 0.04045 ? sr / 12.92 : Math.pow((sr + 0.055) / 1.055, 2.4);
+            double sg = g / 255.0;
+            sg = sg < 0.04045 ? sg / 12.92 : Math.pow((sg + 0.055) / 1.055, 2.4);
+            double sb = b / 255.0;
+            sb = sb < 0.04045 ? sb / 12.92 : Math.pow((sb + 0.055) / 1.055, 2.4);
+
+            outXyz[0] = 100 * (sr * 0.4124 + sg * 0.3576 + sb * 0.1805);
+            outXyz[1] = 100 * (sr * 0.2126 + sg * 0.7152 + sb * 0.0722);
+            outXyz[2] = 100 * (sr * 0.0193 + sg * 0.1192 + sb * 0.9505);
+        }
+
+        /**
+         * Converts a color from CIE XYZ to CIE Lab representation.
+         *
+         * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
+         * 2° Standard Observer (1931).</p>
+         *
+         * <ul>
+         * <li>outLab[0] is L [0 ...1)</li>
+         * <li>outLab[1] is a [-128...127)</li>
+         * <li>outLab[2] is b [-128...127)</li>
+         * </ul>
+         *
+         * @param x      X component value [0...95.047)
+         * @param y      Y component value [0...100)
+         * @param z      Z component value [0...108.883)
+         * @param outLab 3-element array which holds the resulting Lab components
+         */
+        public static void XYZToLAB(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
+                @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
+                @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z,
+                @NonNull double[] outLab) {
+            if (outLab.length != 3) {
+                throw new IllegalArgumentException("outLab must have a length of 3.");
+            }
+            x = pivotXyzComponent(x / XYZ_WHITE_REFERENCE_X);
+            y = pivotXyzComponent(y / XYZ_WHITE_REFERENCE_Y);
+            z = pivotXyzComponent(z / XYZ_WHITE_REFERENCE_Z);
+            outLab[0] = Math.max(0, 116 * y - 16);
+            outLab[1] = 500 * (x - y);
+            outLab[2] = 200 * (y - z);
+        }
+
+        /**
+         * Converts a color from CIE Lab to CIE XYZ representation.
+         *
+         * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+         * 2° Standard Observer (1931).</p>
+         *
+         * <ul>
+         * <li>outXyz[0] is X [0 ...95.047)</li>
+         * <li>outXyz[1] is Y [0...100)</li>
+         * <li>outXyz[2] is Z [0...108.883)</li>
+         * </ul>
+         *
+         * @param l      L component value [0...100)
+         * @param a      A component value [-128...127)
+         * @param b      B component value [-128...127)
+         * @param outXyz 3-element array which holds the resulting XYZ components
+         */
+        public static void LABToXYZ(@FloatRange(from = 0f, to = 100) final double l,
+                @FloatRange(from = -128, to = 127) final double a,
+                @FloatRange(from = -128, to = 127) final double b,
+                @NonNull double[] outXyz) {
+            final double fy = (l + 16) / 116;
+            final double fx = a / 500 + fy;
+            final double fz = fy - b / 200;
+
+            double tmp = Math.pow(fx, 3);
+            final double xr = tmp > XYZ_EPSILON ? tmp : (116 * fx - 16) / XYZ_KAPPA;
+            final double yr = l > XYZ_KAPPA * XYZ_EPSILON ? Math.pow(fy, 3) : l / XYZ_KAPPA;
+
+            tmp = Math.pow(fz, 3);
+            final double zr = tmp > XYZ_EPSILON ? tmp : (116 * fz - 16) / XYZ_KAPPA;
+
+            outXyz[0] = xr * XYZ_WHITE_REFERENCE_X;
+            outXyz[1] = yr * XYZ_WHITE_REFERENCE_Y;
+            outXyz[2] = zr * XYZ_WHITE_REFERENCE_Z;
+        }
+
+        /**
+         * Converts a color from CIE XYZ to its RGB representation.
+         *
+         * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
+         * 2° Standard Observer (1931).</p>
+         *
+         * @param x X component value [0...95.047)
+         * @param y Y component value [0...100)
+         * @param z Z component value [0...108.883)
+         * @return int containing the RGB representation
+         */
+        @ColorInt
+        public static int XYZToColor(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
+                @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
+                @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z) {
+            double r = (x * 3.2406 + y * -1.5372 + z * -0.4986) / 100;
+            double g = (x * -0.9689 + y * 1.8758 + z * 0.0415) / 100;
+            double b = (x * 0.0557 + y * -0.2040 + z * 1.0570) / 100;
+
+            r = r > 0.0031308 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
+            g = g > 0.0031308 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
+            b = b > 0.0031308 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
+
+            return Color.rgb(
+                    constrain((int) Math.round(r * 255), 0, 255),
+                    constrain((int) Math.round(g * 255), 0, 255),
+                    constrain((int) Math.round(b * 255), 0, 255));
+        }
+
+        /**
+         * Converts a color from CIE Lab to its RGB representation.
+         *
+         * @param l L component value [0...100]
+         * @param a A component value [-128...127]
+         * @param b B component value [-128...127]
+         * @return int containing the RGB representation
+         */
+        @ColorInt
+        public static int LABToColor(@FloatRange(from = 0f, to = 100) final double l,
+                @FloatRange(from = -128, to = 127) final double a,
+                @FloatRange(from = -128, to = 127) final double b) {
+            final double[] result = getTempDouble3Array();
+            LABToXYZ(l, a, b, result);
+            return XYZToColor(result[0], result[1], result[2]);
+        }
+
+        private static int constrain(int amount, int low, int high) {
+            return amount < low ? low : (amount > high ? high : amount);
+        }
+
+        private static double pivotXyzComponent(double component) {
+            return component > XYZ_EPSILON
+                    ? Math.pow(component, 1 / 3.0)
+                    : (XYZ_KAPPA * component + 16) / 116;
+        }
+
+        private static double[] getTempDouble3Array() {
+            double[] result = TEMP_ARRAY.get();
+            if (result == null) {
+                result = new double[3];
+                TEMP_ARRAY.set(result);
+            }
+            return result;
+        }
+
+    }
 }
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 53cb56e..1ead5b3 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -35,6 +35,20 @@
     }
 
     /**
+     * Ensures that an expression checking an argument is true.
+     *
+     * @param expression the expression to check
+     * @param errorMessage the exception message to use if the check fails; will
+     *     be converted to a string using {@link String#valueOf(Object)}
+     * @throws IllegalArgumentException if {@code expression} is false
+     */
+    public static void checkArgument(boolean expression, final Object errorMessage) {
+        if (!expression) {
+            throw new IllegalArgumentException(String.valueOf(errorMessage));
+        }
+    }
+
+    /**
      * Ensures that an string reference passed as a parameter to the calling
      * method is not empty.
      *
@@ -42,7 +56,7 @@
      * @return the string reference that was validated
      * @throws IllegalArgumentException if {@code string} is empty
      */
-    public static @NonNull String checkStringNotEmpty(final String string) {
+    public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) {
         if (TextUtils.isEmpty(string)) {
             throw new IllegalArgumentException();
         }
@@ -59,7 +73,7 @@
      * @return the string reference that was validated
      * @throws IllegalArgumentException if {@code string} is empty
      */
-    public static @NonNull String checkStringNotEmpty(final String string,
+    public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string,
             final Object errorMessage) {
         if (TextUtils.isEmpty(string)) {
             throw new IllegalArgumentException(String.valueOf(errorMessage));
@@ -127,13 +141,17 @@
     /**
      * Check the requested flags, throwing if any requested flags are outside
      * the allowed set.
+     *
+     * @return the validated requested flags.
      */
-    public static void checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
+    public static int 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");
         }
+
+        return requestedFlags;
     }
 
     /**
@@ -156,6 +174,37 @@
     /**
      * Ensures that that the argument numeric value is non-negative.
      *
+     * @param value a numeric int value
+     *
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) {
+        if (value < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric long value
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static long checkArgumentNonnegative(final long value) {
+        if (value < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        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
diff --git a/core/java/com/android/internal/util/ProgressReporter.java b/core/java/com/android/internal/util/ProgressReporter.java
new file mode 100644
index 0000000..796f8ac
--- /dev/null
+++ b/core/java/com/android/internal/util/ProgressReporter.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.Nullable;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IProgressListener;
+import android.os.RemoteException;
+import android.util.MathUtils;
+
+/**
+ * Tracks and reports progress of a single task to a {@link IProgressListener}.
+ * The reported progress of a task ranges from 0-100, but the task can be
+ * segmented into smaller pieces using {@link #startSegment(int)} and
+ * {@link #endSegment(int[])}, and segments can be nested.
+ * <p>
+ * Here's an example in action; when finished the overall task progress will be
+ * at 60.
+ *
+ * <pre>
+ * prog.setProgress(20);
+ * {
+ *     final int restore = prog.startSegment(40);
+ *     for (int i = 0; i < N; i++) {
+ *         prog.setProgress(i, N);
+ *         ...
+ *     }
+ *     prog.endSegment(restore);
+ * }
+ * </pre>
+ *
+ * This class is not thread safe.
+ *
+ * @hide
+ */
+public class ProgressReporter {
+    public static final ProgressReporter NO_OP = new ProgressReporter(0, null);
+
+    private final int mId;
+    private final IProgressListener mListener;
+
+    private Bundle mExtras = new Bundle();
+
+    private int mProgress = 0;
+
+    /**
+     * Current segment range: first element is starting progress of this
+     * segment, second element is length of segment.
+     */
+    private int[] mSegmentRange = new int[] { 0, 100 };
+
+    /**
+     * Create a new task with the given identifier whose progress will be
+     * reported to the given listener.
+     */
+    public ProgressReporter(int id, @Nullable IProgressListener listener) {
+        mId = id;
+        mListener = listener;
+    }
+
+    /**
+     * Set the progress of the currently active segment.
+     *
+     * @param progress Segment progress between 0-100.
+     */
+    public void setProgress(int progress) {
+        setProgress(progress, 100, null);
+    }
+
+    /**
+     * Set the progress of the currently active segment.
+     *
+     * @param progress Segment progress between 0-100.
+     */
+    public void setProgress(int progress, @Nullable CharSequence title) {
+        setProgress(progress, 100, title);
+    }
+
+    /**
+     * Set the fractional progress of the currently active segment.
+     */
+    public void setProgress(int n, int m) {
+        setProgress(n, m, null);
+    }
+
+    /**
+     * Set the fractional progress of the currently active segment.
+     */
+    public void setProgress(int n, int m, @Nullable CharSequence title) {
+        mProgress = mSegmentRange[0]
+                + MathUtils.constrain((n * mSegmentRange[1]) / m, 0, mSegmentRange[1]);
+        if (title != null) {
+            mExtras.putCharSequence(Intent.EXTRA_TITLE, title);
+        }
+        notifyProgress(mId, mProgress, mExtras);
+    }
+
+    /**
+     * Start a new inner segment that will contribute the given range towards
+     * the currently active segment. You must pass the returned value to
+     * {@link #endSegment(int[])} when finished.
+     */
+    public int[] startSegment(int size) {
+        final int[] lastRange = mSegmentRange;
+        mSegmentRange = new int[] { mProgress, (size * mSegmentRange[1] / 100) };
+        return lastRange;
+    }
+
+    /**
+     * End the current segment.
+     */
+    public void endSegment(int[] lastRange) {
+        mProgress = mSegmentRange[0] + mSegmentRange[1];
+        mSegmentRange = lastRange;
+    }
+
+    int getProgress() {
+        return mProgress;
+    }
+
+    int[] getSegmentRange() {
+        return mSegmentRange;
+    }
+
+    /**
+     * Report this entire task as being finished.
+     */
+    public void finish() {
+        notifyFinished(mId, null);
+    }
+
+    private void notifyProgress(int id, int progress, Bundle extras) {
+        if (mListener != null) {
+            try {
+                mListener.onProgress(id, progress, extras);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    public void notifyFinished(int id, Bundle extras) {
+        if (mListener != null) {
+            try {
+                mListener.onFinished(id, extras);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
index 4a196f8..5f390be 100644
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ b/core/java/com/android/internal/util/ScreenShapeHelper.java
@@ -1,27 +1,20 @@
 package com.android.internal.util;
 
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.os.Build;
 import android.os.SystemProperties;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
 import android.view.ViewRootImpl;
 
-import com.android.internal.R;
-
 /**
  * @hide
  */
 public class ScreenShapeHelper {
-    private static final boolean IS_EMULATOR = Build.HARDWARE.contains("goldfish");
-
     /**
      * Return the bottom pixel window outset of a window given its style attributes.
      * @return An outset dimension in pixels or 0 if no outset should be applied.
      */
     public static int getWindowOutsetBottomPx(Resources resources) {
-        if (IS_EMULATOR) {
+        if (Build.IS_EMULATOR) {
             return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0);
         } else {
             return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom);
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 77859b8..2653745 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -21,6 +21,8 @@
 import android.os.Handler;
 import android.os.Message;
 
+import com.android.internal.annotations.VisibleForTesting;
+
  /**
  * An AlarmListener that sends the specified message to a Handler and keeps the system awake until
  * the message is processed.
@@ -33,19 +35,21 @@
  * the message, but does not guarantee that the system will be awake until the target object has
  * processed it. This is because as soon as the onAlarmListener sends the message and returns, the
  * AlarmManager releases its wakelock and the system is free to go to sleep again.
- *
  */
 public class WakeupMessage implements AlarmManager.OnAlarmListener {
-    private static AlarmManager sAlarmManager;
-    private final Handler mHandler;
-    private final String mCmdName;
-    private final int mCmd, mArg1, mArg2;
+    private final AlarmManager mAlarmManager;
+
+    @VisibleForTesting
+    protected final Handler mHandler;
+    @VisibleForTesting
+    protected final String mCmdName;
+    @VisibleForTesting
+    protected final int mCmd, mArg1, mArg2;
+    private boolean mScheduled;
 
     public WakeupMessage(Context context, Handler handler,
             String cmdName, int cmd, int arg1, int arg2) {
-        if (sAlarmManager == null) {
-            sAlarmManager = context.getSystemService(AlarmManager.class);
-        }
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mHandler = handler;
         mCmdName = cmdName;
         mCmd = cmd;
@@ -61,19 +65,43 @@
         this(context, handler, cmdName, cmd, 0, 0);
     }
 
-    public void schedule(long when) {
-        sAlarmManager.setExact(
+    /**
+     * Schedule the message to be delivered at the time in milliseconds of the
+     * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
+     * the device when it goes off. If schedule is called multiple times without the message being
+     * dispatched then the alarm is rescheduled to the new time.
+     */
+    public synchronized void schedule(long when) {
+        mAlarmManager.setExact(
                 AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler);
+        mScheduled = true;
     }
 
-    public void cancel() {
-        sAlarmManager.cancel(this);
+    /**
+     * Cancel all pending messages. This includes alarms that may have been fired, but have not been
+     * run on the handler yet.
+     */
+    public synchronized void cancel() {
+        if (mScheduled) {
+            mAlarmManager.cancel(this);
+            mScheduled = false;
+        }
     }
 
     @Override
     public void onAlarm() {
-        Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
-        mHandler.handleMessage(msg);
-        msg.recycle();
+        // Once this method is called the alarm has already been fired and removed from
+        // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now
+        // be marked as unscheduled so that it can be rescheduled in the message handler.
+        final boolean stillScheduled;
+        synchronized (this) {
+            stillScheduled = mScheduled;
+            mScheduled = false;
+        }
+        if (stillScheduled) {
+            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
+            mHandler.handleMessage(msg);
+            msg.recycle();
+        }
     }
 }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index bcc310f..530e00c 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -38,7 +38,7 @@
     @Override
     public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
             Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
-            Rect backDropFrame, boolean forceLayout) {
+            Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar) {
         if (reportDraw) {
             try {
                 mSession.finishDrawing(this);
@@ -111,6 +111,6 @@
     }
 
     @Override
-    public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+    public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
     }
 }
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 3be15f3..3a4afad 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.view;
 
+import com.android.internal.annotations.GuardedBy;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -27,8 +31,8 @@
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-
-import java.lang.ref.WeakReference;
+import android.view.inputmethod.InputConnectionInspector;
+import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
 
 public abstract class IInputConnectionWrapper extends IInputContext.Stub {
     static final String TAG = "IInputConnectionWrapper";
@@ -56,11 +60,17 @@
     private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
     private static final int DO_CLEAR_META_KEY_STATES = 130;
     private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
+    private static final int DO_CLOSE_CONNECTION = 150;
 
-    private WeakReference<InputConnection> mInputConnection;
+    @GuardedBy("mLock")
+    @Nullable
+    private InputConnection mInputConnection;
 
     private Looper mMainLooper;
     private Handler mH;
+    private Object mLock = new Object();
+    @GuardedBy("mLock")
+    private boolean mFinished = false;
 
     static class SomeArgs {
         Object arg1;
@@ -80,12 +90,25 @@
         }
     }
     
-    public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
-        mInputConnection = new WeakReference<>(conn);
+    public IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection) {
+        mInputConnection = inputConnection;
         mMainLooper = mainLooper;
         mH = new MyHandler(mMainLooper);
     }
 
+    @Nullable
+    public InputConnection getInputConnection() {
+        synchronized (mLock) {
+            return mInputConnection;
+        }
+    }
+
+    protected boolean isFinished() {
+        synchronized (mLock) {
+            return mFinished;
+        }
+    }
+
     abstract protected boolean isActive();
 
     /**
@@ -198,6 +221,10 @@
                 seq, callback));
     }
 
+    public void closeConnection() {
+        dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
+    }
+
     void dispatchMessage(Message msg) {
         // If we are calling this from the main thread, then we can call
         // right through.  Otherwise, we need to send the message to the
@@ -210,13 +237,13 @@
         
         mH.sendMessage(msg);
     }
-    
+
     void executeMessage(Message msg) {
         switch (msg.what) {
             case DO_GET_TEXT_AFTER_CURSOR: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 try {
-                    InputConnection ic = mInputConnection.get();
+                    InputConnection ic = getInputConnection();
                     if (ic == null || !isActive()) {
                         Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
                         args.callback.setTextAfterCursor(null, args.seq);
@@ -232,7 +259,7 @@
             case DO_GET_TEXT_BEFORE_CURSOR: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 try {
-                    InputConnection ic = mInputConnection.get();
+                    InputConnection ic = getInputConnection();
                     if (ic == null || !isActive()) {
                         Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
                         args.callback.setTextBeforeCursor(null, args.seq);
@@ -248,7 +275,7 @@
             case DO_GET_SELECTED_TEXT: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 try {
-                    InputConnection ic = mInputConnection.get();
+                    InputConnection ic = getInputConnection();
                     if (ic == null || !isActive()) {
                         Log.w(TAG, "getSelectedText on inactive InputConnection");
                         args.callback.setSelectedText(null, args.seq);
@@ -264,7 +291,7 @@
             case DO_GET_CURSOR_CAPS_MODE: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 try {
-                    InputConnection ic = mInputConnection.get();
+                    InputConnection ic = getInputConnection();
                     if (ic == null || !isActive()) {
                         Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
                         args.callback.setCursorCapsMode(0, args.seq);
@@ -280,7 +307,7 @@
             case DO_GET_EXTRACTED_TEXT: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 try {
-                    InputConnection ic = mInputConnection.get();
+                    InputConnection ic = getInputConnection();
                     if (ic == null || !isActive()) {
                         Log.w(TAG, "getExtractedText on inactive InputConnection");
                         args.callback.setExtractedText(null, args.seq);
@@ -294,7 +321,7 @@
                 return;
             }
             case DO_COMMIT_TEXT: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "commitText on inactive InputConnection");
                     return;
@@ -304,7 +331,7 @@
                 return;
             }
             case DO_SET_SELECTION: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "setSelection on inactive InputConnection");
                     return;
@@ -313,7 +340,7 @@
                 return;
             }
             case DO_PERFORM_EDITOR_ACTION: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "performEditorAction on inactive InputConnection");
                     return;
@@ -322,7 +349,7 @@
                 return;
             }
             case DO_PERFORM_CONTEXT_MENU_ACTION: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "performContextMenuAction on inactive InputConnection");
                     return;
@@ -331,7 +358,7 @@
                 return;
             }
             case DO_COMMIT_COMPLETION: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "commitCompletion on inactive InputConnection");
                     return;
@@ -340,7 +367,7 @@
                 return;
             }
             case DO_COMMIT_CORRECTION: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "commitCorrection on inactive InputConnection");
                     return;
@@ -349,7 +376,7 @@
                 return;
             }
             case DO_SET_COMPOSING_TEXT: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "setComposingText on inactive InputConnection");
                     return;
@@ -359,7 +386,7 @@
                 return;
             }
             case DO_SET_COMPOSING_REGION: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "setComposingRegion on inactive InputConnection");
                     return;
@@ -368,7 +395,7 @@
                 return;
             }
             case DO_FINISH_COMPOSING_TEXT: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 // Note we do NOT check isActive() here, because this is safe
                 // for an IME to call at any time, and we need to allow it
                 // through to clean up our state after the IME has switched to
@@ -381,7 +408,7 @@
                 return;
             }
             case DO_SEND_KEY_EVENT: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "sendKeyEvent on inactive InputConnection");
                     return;
@@ -391,7 +418,7 @@
                 return;
             }
             case DO_CLEAR_META_KEY_STATES: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
                     return;
@@ -400,7 +427,7 @@
                 return;
             }
             case DO_DELETE_SURROUNDING_TEXT: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
                     return;
@@ -409,7 +436,7 @@
                 return;
             }
             case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
                     return;
@@ -418,7 +445,7 @@
                 return;
             }
             case DO_BEGIN_BATCH_EDIT: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "beginBatchEdit on inactive InputConnection");
                     return;
@@ -427,7 +454,7 @@
                 return;
             }
             case DO_END_BATCH_EDIT: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "endBatchEdit on inactive InputConnection");
                     return;
@@ -436,7 +463,7 @@
                 return;
             }
             case DO_REPORT_FULLSCREEN_MODE: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null) {
                     Log.w(TAG, "reportFullscreenMode on inexistent InputConnection");
                     return;
@@ -447,7 +474,7 @@
                 return;
             }
             case DO_PERFORM_PRIVATE_COMMAND: {
-                InputConnection ic = mInputConnection.get();
+                InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "performPrivateCommand on inactive InputConnection");
                     return;
@@ -460,7 +487,7 @@
             case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 try {
-                    InputConnection ic = mInputConnection.get();
+                    InputConnection ic = getInputConnection();
                     if (ic == null || !isActive()) {
                         Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
                         args.callback.setRequestUpdateCursorAnchorInfoResult(false, args.seq);
@@ -473,6 +500,36 @@
                 }
                 return;
             }
+            case DO_CLOSE_CONNECTION: {
+                // Note that we do not need to worry about race condition here, because 1) mFinished
+                // is updated only inside this block, and 2) the code here is running on a Handler
+                // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
+                // same time.
+                if (isFinished()) {
+                    return;
+                }
+                try {
+                    InputConnection ic = getInputConnection();
+                    // Note we do NOT check isActive() here, because this is safe
+                    // for an IME to call at any time, and we need to allow it
+                    // through to clean up our state after the IME has switched to
+                    // another client.
+                    if (ic == null) {
+                        return;
+                    }
+                    @MissingMethodFlags
+                    final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
+                    if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
+                        ic.closeConnection();
+                    }
+                } finally {
+                    synchronized (mLock) {
+                        mInputConnection = null;
+                        mFinished = true;
+                    }
+                }
+                return;
+            }
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 77456da..6ab1ec7 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -38,9 +38,9 @@
 
     void unbindInput();
 
-    void startInput(in IInputContext inputContext, in EditorInfo attribute);
+    void startInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute);
 
-    void restartInput(in IInputContext inputContext, in EditorInfo attribute);
+    void restartInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute);
 
     void createSession(in InputChannel channel, IInputSessionCallback callback);
 
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index db3ecc6..94c94c1 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -46,21 +46,19 @@
             in IInputContext inputContext, int uid, int pid);
     void removeClient(in IInputMethodClient client);
 
-    InputBindResult startInput(/* @InputMethodClient.StartInputReason */ int startInputReason,
-            in IInputMethodClient client, IInputContext inputContext, in EditorInfo attribute,
-            int controlFlags);
     void finishInput(in IInputMethodClient client);
     boolean showSoftInput(in IInputMethodClient client, int flags,
             in ResultReceiver resultReceiver);
     boolean hideSoftInput(in IInputMethodClient client, int flags,
             in ResultReceiver resultReceiver);
-    // Report that a window has gained focus.  If 'attribute' is non-null,
-    // this will also do a startInput.
-    InputBindResult windowGainedFocus(
+    // If windowToken is null, this just does startInput().  Otherwise this reports that a window
+    // has gained focus, and if 'attribute' is non-null then also does startInput.
+    InputBindResult startInputOrWindowGainedFocus(
             /* @InputMethodClient.StartInputReason */ int startInputReason,
             in IInputMethodClient client, in IBinder windowToken, int controlFlags,
             int softInputMode, int windowFlags, in EditorInfo attribute,
-            IInputContext inputContext);
+            IInputContext inputContext,
+            /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags);
 
     void showInputMethodPickerFromClient(in IInputMethodClient client,
             int auxiliarySubtypeMode);
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index fc67245..f9884d8 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -27,11 +27,15 @@
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionInspector;
+import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
 
 public class InputConnectionWrapper implements InputConnection {
     private static final int MAX_WAIT_TIME_MILLIS = 2000;
     private final IInputContext mIInputContext;
-    
+    @MissingMethodFlags
+    private final int mMissingMethods;
+
     static class InputContextCallback extends IInputContextCallback.Stub {
         private static final String TAG = "InputConnectionWrapper.ICC";
         public int mSeq;
@@ -191,8 +195,10 @@
         }
     }
 
-    public InputConnectionWrapper(IInputContext inputContext) {
+    public InputConnectionWrapper(IInputContext inputContext,
+            @MissingMethodFlags final int missingMethods) {
         mIInputContext = inputContext;
+        mMissingMethods = missingMethods;
     }
 
     public CharSequence getTextAfterCursor(int length, int flags) {
@@ -230,8 +236,12 @@
         }
         return value;
     }
-    
+
     public CharSequence getSelectedText(int flags) {
+        if (isMethodMissing(MissingMethodFlags.GET_SELECTED_TEXT)) {
+            // This method is not implemented.
+            return null;
+        }
         CharSequence value = null;
         try {
             InputContextCallback callback = InputContextCallback.getInstance();
@@ -295,6 +305,10 @@
     }
 
     public boolean commitCompletion(CompletionInfo text) {
+        if (isMethodMissing(MissingMethodFlags.COMMIT_CORRECTION)) {
+            // This method is not implemented.
+            return false;
+        }
         try {
             mIInputContext.commitCompletion(text);
             return true;
@@ -340,6 +354,10 @@
     }
 
     public boolean setComposingRegion(int start, int end) {
+        if (isMethodMissing(MissingMethodFlags.SET_COMPOSING_REGION)) {
+            // This method is not implemented.
+            return false;
+        }
         try {
             mIInputContext.setComposingRegion(start, end);
             return true;
@@ -412,6 +430,10 @@
     }
 
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+        if (isMethodMissing(MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS)) {
+            // This method is not implemented.
+            return false;
+        }
         try {
             mIInputContext.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
             return true;
@@ -440,6 +462,10 @@
 
     public boolean requestCursorUpdates(int cursorUpdateMode) {
         boolean result = false;
+        if (isMethodMissing(MissingMethodFlags.REQUEST_CURSOR_UPDATES)) {
+            // This method is not implemented.
+            return false;
+        }
         try {
             InputContextCallback callback = InputContextCallback.getInstance();
             mIInputContext.requestUpdateCursorAnchorInfo(cursorUpdateMode, callback.mSeq, callback);
@@ -460,4 +486,20 @@
         // Nothing should happen when called from input method.
         return null;
     }
+
+    public void closeConnection() {
+        // Nothing should happen when called from input method.
+    }
+
+    private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
+        return (mMissingMethods & methodFlag) == methodFlag;
+    }
+
+    @Override
+    public String toString() {
+        return "InputConnectionWrapper{idHash=#"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " mMissingMethods="
+                + InputConnectionInspector.getMissingMethodFlagsAsString(mMissingMethods) + "}";
+    }
 }
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index 526e2ae..9e2cbdb 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -45,7 +45,8 @@
     private static float[] createLUT(TimeInterpolator interpolator, long duration) {
         long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
         int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
-        int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs);
+        // We need 2 frame values as the minimal.
+        int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
         float values[] = new float[numAnimFrames];
         float lastFrame = numAnimFrames - 1;
         for (int i = 0; i < numAnimFrames; i++) {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index bd97e5d..4738f5e 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -346,16 +346,6 @@
             }
             return false;
         }
-
-        @Override
-        protected boolean onForwardingStopped() {
-            final ShowableListMenu popup = getPopup();
-            if (popup != null) {
-                popup.dismiss();
-                return true;
-            }
-            return false;
-        }
     }
 
     public static abstract class PopupCallback {
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 31b2f96..df57639 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -65,7 +65,6 @@
 
     private final Context mContext;
     private final Resources mResources;
-    private final boolean mShowCascadingMenus;
 
     /**
      * Whether the shortcuts should be qwerty-accessible. Use isQwertyMode()
@@ -188,9 +187,6 @@
     public MenuBuilder(Context context) {
         mContext = context;
         mResources = context.getResources();
-        mShowCascadingMenus = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableCascadingSubmenus);
-        
         mItems = new ArrayList<MenuItemImpl>();
         
         mVisibleItems = new ArrayList<MenuItemImpl>();
@@ -915,10 +911,6 @@
                 close(true /* closeAllMenus */);
             }
         } else if (itemImpl.hasSubMenu() || providerHasSubMenu) {
-            if (!mShowCascadingMenus) {
-                close(false /* closeAllMenus */);
-            }
-
             if (!itemImpl.hasSubMenu()) {
                 itemImpl.setSubMenu(new SubMenuBuilder(getContext(), this, itemImpl));
             }
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 2cb224e..8ced36f 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -240,7 +240,10 @@
             mTreeObserver = null;
         }
         mShownAnchorView.removeOnAttachStateChangeListener(mAttachStateChangeListener);
-        mOnDismissListener.onDismiss();
+
+        if (mOnDismissListener != null) {
+            mOnDismissListener.onDismiss();
+        }
     }
 
     @Override
@@ -265,6 +268,13 @@
             subPopup.setPresenterCallback(mPresenterCallback);
             subPopup.setForceShowIcon(mAdapter.getForceShowIcon());
 
+            // Pass responsibility for handling onDismiss to the submenu.
+            subPopup.setOnDismissListener(mOnDismissListener);
+            mOnDismissListener = null;
+
+            // Close this menu popup to make room for the submenu popup.
+            dismiss();
+
             // Show the new sub-menu popup at the same location as this popup.
             if (subPopup.tryShow(mXOffset, mYOffset)) {
                 if (mPresenterCallback != null) {
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 398bbe7..baf3188 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -147,7 +147,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return (who == mBackground && !mIsSplit) || (who == mStackedBackground && mIsStacked) ||
                 (who == mSplitBackground && mIsSplit) || super.verifyDrawable(who);
     }
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index 409a17f..e59d7ba 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -136,7 +136,7 @@
     public void setPhoneWindow(PhoneWindow owner, boolean show) {
         mOwner = owner;
         mShow = show;
-        mOverlayWithAppContent = owner.getOverlayDecorCaption();
+        mOverlayWithAppContent = owner.isOverlayWithDecorCaptionEnabled();
         if (mOverlayWithAppContent) {
             // The caption is covering the content, so we make its background transparent to make
             // the content visible.
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index f211ff2..7f7528d 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -84,9 +84,8 @@
     }
 
     @Override
-    protected void reportFinish() {
-        super.reportFinish();
-
+    public void closeConnection() {
+        super.closeConnection();
         synchronized(this) {
             while (mBatchEditNesting > 0) {
                 endBatchEdit();
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index ce03bb8..1848fe8 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -41,6 +41,7 @@
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.View.OnLayoutChangeListener;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.Window;
@@ -308,9 +309,6 @@
         private static final int MIN_OVERFLOW_SIZE = 2;
         private static final int MAX_OVERFLOW_SIZE = 4;
 
-        /* The duration of the overflow button vector animation duration. */
-        private static final int OVERFLOW_BUTTON_ANIMATION_DELAY = 400;
-
         private final Context mContext;
         private final View mParent;  // Parent for the popup window.
         private final PopupWindow mPopupWindow;
@@ -377,18 +375,6 @@
             }
         };
 
-        /* Runnable to reset the overflow button's drawable after an overflow transition. */
-        private final Runnable mResetOverflowButtonDrawable = new Runnable() {
-            @Override
-            public void run() {
-                if (mIsOverflowOpen) {
-                    mOverflowButton.setImageDrawable(mArrow);
-                } else {
-                    mOverflowButton.setImageDrawable(mOverflow);
-                }
-            }
-        };
-
         private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing.
         private boolean mHidden; // tracks whether this popup is hidden or hiding.
 
@@ -893,6 +879,10 @@
                     .start();
         }
 
+        /**
+         * Defines the position of the floating toolbar popup panels when transition animation has
+         * stopped.
+         */
         private void setPanelsStatesAtRestingPosition() {
             mOverflowButton.setEnabled(true);
             mOverflowPanel.awakenScrollBars();
@@ -902,7 +892,9 @@
                 final Size containerSize = mOverflowPanelSize;
                 setSize(mContentContainer, containerSize);
                 mMainPanel.setAlpha(0);
+                mMainPanel.setVisibility(View.INVISIBLE);
                 mOverflowPanel.setAlpha(1);
+                mOverflowPanel.setVisibility(View.VISIBLE);
                 mOverflowButton.setImageDrawable(mArrow);
 
                 // Update x-coordinates depending on RTL state.
@@ -941,7 +933,9 @@
                 final Size containerSize = mMainPanelSize;
                 setSize(mContentContainer, containerSize);
                 mMainPanel.setAlpha(1);
+                mMainPanel.setVisibility(View.VISIBLE);
                 mOverflowPanel.setAlpha(0);
+                mOverflowPanel.setVisibility(View.INVISIBLE);
                 mOverflowButton.setImageDrawable(mOverflow);
 
                 if (hasOverflow()) {
@@ -1247,7 +1241,15 @@
                     Math.min(
                             Math.max(MIN_OVERFLOW_SIZE, maxItemSize),
                             mOverflowPanel.getCount()));
-            return actualSize * getLineHeight(mContext) + mOverflowButtonSize.getHeight();
+            int extension = 0;
+            if (actualSize < mOverflowPanel.getCount()) {
+                // The overflow will require scrolling to get to all the items.
+                // Extend the height so that part of the hidden items is displayed.
+                extension = (int) (getLineHeight(mContext) * 0.5f);
+            }
+            return actualSize * getLineHeight(mContext)
+                    + mOverflowButtonSize.getHeight()
+                    + extension;
         }
 
         private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) {
@@ -1327,8 +1329,6 @@
                         mToArrow.start();
                         openOverflow();
                     }
-                    overflowButton.postDelayed(
-                            mResetOverflowButtonDrawable, OVERFLOW_BUTTON_ANIMATION_DELAY);
                 }
             });
             return overflowButton;
@@ -1389,6 +1389,10 @@
                     // Disable the overflow button while it's animating.
                     // It will be re-enabled when the animation stops.
                     mOverflowButton.setEnabled(false);
+                    // Ensure both panels have visibility turned on when the overflow animation
+                    // starts.
+                    mMainPanel.setVisibility(View.VISIBLE);
+                    mOverflowPanel.setVisibility(View.VISIBLE);
                 }
 
                 @Override
@@ -1455,6 +1459,8 @@
             OverflowPanel(FloatingToolbarPopup popup) {
                 super(Preconditions.checkNotNull(popup).mContext);
                 this.mPopup = popup;
+                setScrollBarDefaultDelayBeforeFade(ViewConfiguration.getScrollDefaultDelay() * 3);
+                setScrollIndicators(View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
             }
 
             @Override
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index c4ed2e1..78c5e34 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -65,6 +65,8 @@
                 .setTextDirection(getTextDirectionHeuristic())
                 .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
                 .setIncludePad(getIncludeFontPadding())
+                .setEllipsize(shouldEllipsize ? effectiveEllipsize : null)
+                .setEllipsizedWidth(ellipsisWidth)
                 .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
                 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
         // we set the endmargin on the first 2 lines. this works just in our case but that's
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index cbc735f..3d892af 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -887,8 +887,7 @@
      * @return true if device encryption is enabled
      */
     public static boolean isDeviceEncryptionEnabled() {
-        final String status = SystemProperties.get("ro.crypto.state", "unsupported");
-        return "encrypted".equalsIgnoreCase(status);
+        return StorageManager.isEncrypted();
     }
 
     /**
@@ -896,8 +895,7 @@
      * @return true if device is file encrypted
      */
     public static boolean isFileEncryptionEnabled() {
-        final String status = SystemProperties.get("ro.crypto.type", "");
-        return "file".equalsIgnoreCase(status);
+        return StorageManager.isFileEncryptedNativeOrEmulated();
     }
 
     /**
@@ -1101,7 +1099,8 @@
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
+                || mode == DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
         return passwordEnabled && savedPasswordExists(userId);
     }
 
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index 6bba1b3..f63afad 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -89,36 +89,50 @@
         int topMargin = getMeasuredHeight() - mRightIcon.getMeasuredHeight()
                 - iconParams.bottomMargin;
         // If the topMargin is high enough we can also remove the header constraint!
+        boolean reMeasure = false;
         if (!hasIcon || topMargin >= mImageMinTopMargin) {
-            resetHeaderIndention();
+            reMeasure = resetHeaderIndention();
         } else {
             int paddingEnd = mNotificationContentImageMarginEnd;
             ViewGroup.MarginLayoutParams headerParams =
                     (MarginLayoutParams) mHeader.getLayoutParams();
-            headerParams.setMarginEnd(mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd());
-            if (mHeader.getPaddingEnd() != paddingEnd) {
-                mHeader.setPadding(
-                        isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
-                        mHeader.getPaddingTop(),
-                        isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
-                        mHeader.getPaddingBottom());
+            int newMarginEnd = mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd();
+            if (headerParams.getMarginEnd() != newMarginEnd) {
+                headerParams.setMarginEnd(newMarginEnd);
                 mHeader.setLayoutParams(headerParams);
+                reMeasure = true;
             }
+            if (mHeader.getPaddingEnd() != paddingEnd) {
+                mHeader.setPaddingRelative(mHeader.getPaddingStart(),
+                        mHeader.getPaddingTop(),
+                        paddingEnd,
+                        mHeader.getPaddingBottom());
+                reMeasure = true;
+            }
+        }
+        if (reMeasure) {
+            measureChildWithMargins(mHeader, widthMeasureSpec, 0, heightMeasureSpec, 0);
         }
     }
 
-    private void resetHeaderIndention() {
+    private boolean resetHeaderIndention() {
+        boolean remeasure = false;
         if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
-            ViewGroup.MarginLayoutParams headerParams =
-                    (MarginLayoutParams) mHeader.getLayoutParams();
-            headerParams.setMarginEnd(0);
-            mHeader.setPadding(
-                    isLayoutRtl() ? mNotificationContentMarginEnd : mHeader.getPaddingLeft(),
+            mHeader.setPaddingRelative(mHeader.getPaddingStart(),
                     mHeader.getPaddingTop(),
-                    isLayoutRtl() ? mHeader.getPaddingLeft() : mNotificationContentMarginEnd,
+                    mNotificationContentMarginEnd,
                     mHeader.getPaddingBottom());
-            mHeader.setLayoutParams(headerParams);
+            remeasure = true;
         }
+        ViewGroup.MarginLayoutParams headerParams =
+                (MarginLayoutParams) mHeader.getLayoutParams();
+        headerParams.setMarginEnd(0);
+        if (headerParams.getMarginEnd() != 0) {
+            headerParams.setMarginEnd(0);
+            mHeader.setLayoutParams(headerParams);
+            remeasure = true;
+        }
+        return remeasure;
     }
 
     public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c4347f8..25b487e 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -17,9 +17,14 @@
 
 package com.android.internal.widget;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -85,6 +90,10 @@
     private final float mMinFlingVelocity;
     private final OverScroller mScroller;
     private final VelocityTracker mVelocityTracker;
+    private final Drawable mScrollIndicatorDrawable;
+    private final Drawable mFakeForeground;
+
+    private View mButtonBar;
 
     private OnDismissedListener mOnDismissedListener;
     private RunOnDismissedListener mRunOnDismissedListener;
@@ -106,6 +115,8 @@
                 }
             };
 
+    private final int[] mTempOffset = new int[2];
+
     public ResolverDrawerLayout(Context context) {
         this(context, null);
     }
@@ -127,6 +138,9 @@
                 mMaxCollapsedHeight);
         a.recycle();
 
+        mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material);
+        mFakeForeground = new ColorDrawable(Color.TRANSPARENT);
+
         mScroller = new OverScroller(context, AnimationUtils.loadInterpolator(context,
                 android.R.interpolator.decelerate_quint));
         mVelocityTracker = VelocityTracker.obtain();
@@ -138,6 +152,13 @@
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
     }
 
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mButtonBar = findViewById(R.id.button_bar);
+    }
+
     public void setSmallCollapsed(boolean smallCollapsed) {
         mSmallCollapsed = smallCollapsed;
         requestLayout();
@@ -202,8 +223,7 @@
             }
             final boolean isCollapsedNew = mCollapseOffset != 0;
             if (isCollapsedOld != isCollapsedNew) {
-                notifyViewAccessibilityStateChangedIfNeeded(
-                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                onCollapsedChanged(isCollapsedNew);
             }
         } else {
             // Start out collapsed at first unless we restored state for otherwise
@@ -442,8 +462,7 @@
             mTopOffset += dy;
             final boolean isCollapsedNew = newPos != 0;
             if (isCollapsedOld != isCollapsedNew) {
-                notifyViewAccessibilityStateChangedIfNeeded(
-                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                onCollapsedChanged(isCollapsedNew);
             }
             postInvalidateOnAnimation();
             return dy;
@@ -451,6 +470,14 @@
         return 0;
     }
 
+    private void onCollapsedChanged(boolean isCollapsed) {
+        notifyViewAccessibilityStateChangedIfNeeded(
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+
+        // Set a fake foreground so that we receive onDrawForeground().
+        setForeground(isCollapsed ? mFakeForeground : null);
+    }
+
     void dispatchOnDismissed() {
         if (mOnDismissedListener != null) {
             mOnDismissedListener.onDismissed();
@@ -709,6 +736,23 @@
     }
 
     @Override
+    public void onDrawForeground(Canvas canvas) {
+        if (isCollapsed() && mButtonBar != null) {
+            // Draw the scroll indicator directly above the button bar.
+            final int height = mScrollIndicatorDrawable.getIntrinsicHeight();
+            mButtonBar.getLocationInWindow(mTempOffset);
+            final int barTop = mTempOffset[1];
+            getLocationInWindow(mTempOffset);
+            final int myTop = mTempOffset[1];
+            final int top = (barTop - myTop) - height;
+            mScrollIndicatorDrawable.setBounds(0, top, getWidth(), top + height);
+            mScrollIndicatorDrawable.draw(canvas);
+        }
+
+        super.onDrawForeground(canvas);
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int sourceWidth = MeasureSpec.getSize(widthMeasureSpec);
         int widthSize = sourceWidth;
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index 948a6bb..277fafd 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -17,6 +17,7 @@
 package com.android.internal.widget;
 
 import android.annotation.DrawableRes;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -746,7 +747,7 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
+    protected boolean verifyDrawable(@NonNull Drawable who) {
         return super.verifyDrawable(who) || who == mMarginDrawable;
     }
 
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index ab75b7c..6d6c162 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.storage.StorageManager;
 import android.provider.Downloads;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -143,8 +144,7 @@
         HashMap<String, Long> timestamps = readTimestamps();
 
         if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
-            if ("encrypted".equals(SystemProperties.get("ro.crypto.state"))
-                && "trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))) {
+            if (StorageManager.inCryptKeeperBounce()) {
                 // Encrypted, first boot to get PIN/pattern/password so data is tmpfs
                 // Don't set ro.runtime.firstboot so that we will do this again
                 // when data is properly mounted
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
new file mode 100644
index 0000000..07912cd
--- /dev/null
+++ b/core/java/com/android/server/SystemConfig.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static com.android.internal.util.ArrayUtils.appendInt;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Loads global system configuration info.
+ */
+public class SystemConfig {
+    static final String TAG = "SystemConfig";
+
+    static SystemConfig sInstance;
+
+    // permission flag, determines which types of configuration are allowed to be read
+    private static final int ALLOW_FEATURES = 0x01;
+    private static final int ALLOW_LIBS = 0x02;
+    private static final int ALLOW_PERMISSIONS = 0x04;
+    private static final int ALLOW_APP_CONFIGS = 0x08;
+    private static final int ALLOW_ALL = ~0;
+
+    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
+    int[] mGlobalGids;
+
+    // These are the built-in uid -> permission mappings that were read from the
+    // system configuration files.
+    final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
+
+    // These are the built-in shared libraries that were read from the
+    // system configuration files.  Keys are the library names; strings are the
+    // paths to the libraries.
+    final ArrayMap<String, String> mSharedLibraries  = new ArrayMap<>();
+
+    // These are the features this devices supports that were read from the
+    // system configuration files.
+    final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
+
+    // These are the features which this device doesn't support; the OEM
+    // partition uses these to opt-out of features from the system image.
+    final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
+
+    public static final class PermissionEntry {
+        public final String name;
+        public int[] gids;
+        public boolean perUser;
+
+        PermissionEntry(String name, boolean perUser) {
+            this.name = name;
+            this.perUser = perUser;
+        }
+    }
+
+    // These are the permission -> gid mappings that were read from the
+    // system configuration files.
+    final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
+
+    // These are the packages that are white-listed to be able to run in the
+    // background while in power save mode (but not whitelisted from device idle modes),
+    // as read from the configuration files.
+    final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>();
+
+    // These are the packages that are white-listed to be able to run in the
+    // background while in power save mode, as read from the configuration files.
+    final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
+
+    // These are the packages that are white-listed to be able to run in the
+    // background while in data-usage save mode, as read from the configuration files.
+    final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
+
+    // These are the package names of apps which should be in the 'always'
+    // URL-handling state upon factory reset.
+    final ArraySet<String> mLinkedApps = new ArraySet<>();
+
+    // These are the packages that are whitelisted to be able to run as system user
+    final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>();
+
+    // These are the packages that should not run under system user
+    final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
+
+    // These are the components that are enabled by default as VR mode listener services.
+    final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();
+
+    public static SystemConfig getInstance() {
+        synchronized (SystemConfig.class) {
+            if (sInstance == null) {
+                sInstance = new SystemConfig();
+            }
+            return sInstance;
+        }
+    }
+
+    public int[] getGlobalGids() {
+        return mGlobalGids;
+    }
+
+    public SparseArray<ArraySet<String>> getSystemPermissions() {
+        return mSystemPermissions;
+    }
+
+    public ArrayMap<String, String> getSharedLibraries() {
+        return mSharedLibraries;
+    }
+
+    public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
+        return mAvailableFeatures;
+    }
+
+    public ArrayMap<String, PermissionEntry> getPermissions() {
+        return mPermissions;
+    }
+
+    public ArraySet<String> getAllowInPowerSaveExceptIdle() {
+        return mAllowInPowerSaveExceptIdle;
+    }
+
+    public ArraySet<String> getAllowInPowerSave() {
+        return mAllowInPowerSave;
+    }
+
+    public ArraySet<String> getAllowInDataUsageSave() {
+        return mAllowInDataUsageSave;
+    }
+
+    public ArraySet<String> getLinkedApps() {
+        return mLinkedApps;
+    }
+
+    public ArraySet<String> getSystemUserWhitelistedApps() {
+        return mSystemUserWhitelistedApps;
+    }
+
+    public ArraySet<String> getSystemUserBlacklistedApps() {
+        return mSystemUserBlacklistedApps;
+    }
+
+    public ArraySet<ComponentName> getDefaultVrComponents() {
+        return mDefaultVrComponents;
+    }
+
+    SystemConfig() {
+        // Read configuration from system
+        readPermissions(Environment.buildPath(
+                Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
+        // Read configuration from the old permissions dir
+        readPermissions(Environment.buildPath(
+                Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
+        // Allow ODM to customize system configs around libs, features and apps
+        int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
+        readPermissions(Environment.buildPath(
+                Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
+        readPermissions(Environment.buildPath(
+                Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
+        // Only allow OEM to customize features
+        readPermissions(Environment.buildPath(
+                Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
+        readPermissions(Environment.buildPath(
+                Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
+    }
+
+    void readPermissions(File libraryDir, int permissionFlag) {
+        // Read permissions from given directory.
+        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
+            if (permissionFlag == ALLOW_ALL) {
+                Slog.w(TAG, "No directory " + libraryDir + ", skipping");
+            }
+            return;
+        }
+        if (!libraryDir.canRead()) {
+            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
+            return;
+        }
+
+        // Iterate over the files in the directory and scan .xml files
+        File platformFile = null;
+        for (File f : libraryDir.listFiles()) {
+            // We'll read platform.xml last
+            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
+                platformFile = f;
+                continue;
+            }
+
+            if (!f.getPath().endsWith(".xml")) {
+                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
+                continue;
+            }
+            if (!f.canRead()) {
+                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
+                continue;
+            }
+
+            readPermissionsFromXml(f, permissionFlag);
+        }
+
+        // Read platform permissions last so it will take precedence
+        if (platformFile != null) {
+            readPermissionsFromXml(platformFile, permissionFlag);
+        }
+    }
+
+    private void readPermissionsFromXml(File permFile, int permissionFlag) {
+        FileReader permReader = null;
+        try {
+            permReader = new FileReader(permFile);
+        } catch (FileNotFoundException e) {
+            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
+            return;
+        }
+
+        final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
+
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(permReader);
+
+            int type;
+            while ((type=parser.next()) != parser.START_TAG
+                       && type != parser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != parser.START_TAG) {
+                throw new XmlPullParserException("No start tag found");
+            }
+
+            if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
+                throw new XmlPullParserException("Unexpected start tag in " + permFile
+                        + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
+            }
+
+            boolean allowAll = permissionFlag == ALLOW_ALL;
+            boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
+            boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
+            boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
+            boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
+            while (true) {
+                XmlUtils.nextElement(parser);
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                String name = parser.getName();
+                if ("group".equals(name) && allowAll) {
+                    String gidStr = parser.getAttributeValue(null, "gid");
+                    if (gidStr != null) {
+                        int gid = android.os.Process.getGidForName(gidStr);
+                        mGlobalGids = appendInt(mGlobalGids, gid);
+                    } else {
+                        Slog.w(TAG, "<group> without gid in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else if ("permission".equals(name) && allowPermissions) {
+                    String perm = parser.getAttributeValue(null, "name");
+                    if (perm == null) {
+                        Slog.w(TAG, "<permission> without name in " + permFile + " at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    perm = perm.intern();
+                    readPermission(parser, perm);
+
+                } else if ("assign-permission".equals(name) && allowPermissions) {
+                    String perm = parser.getAttributeValue(null, "name");
+                    if (perm == null) {
+                        Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    String uidStr = parser.getAttributeValue(null, "uid");
+                    if (uidStr == null) {
+                        Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    int uid = Process.getUidForName(uidStr);
+                    if (uid < 0) {
+                        Slog.w(TAG, "<assign-permission> with unknown uid \""
+                                + uidStr + "  in " + permFile + " at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    perm = perm.intern();
+                    ArraySet<String> perms = mSystemPermissions.get(uid);
+                    if (perms == null) {
+                        perms = new ArraySet<String>();
+                        mSystemPermissions.put(uid, perms);
+                    }
+                    perms.add(perm);
+                    XmlUtils.skipCurrentTag(parser);
+
+                } else if ("library".equals(name) && allowLibs) {
+                    String lname = parser.getAttributeValue(null, "name");
+                    String lfile = parser.getAttributeValue(null, "file");
+                    if (lname == null) {
+                        Slog.w(TAG, "<library> without name in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    } else if (lfile == null) {
+                        Slog.w(TAG, "<library> without file in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    } else {
+                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
+                        mSharedLibraries.put(lname, lfile);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("feature".equals(name) && allowFeatures) {
+                    String fname = parser.getAttributeValue(null, "name");
+                    int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
+                    boolean allowed;
+                    if (!lowRam) {
+                        allowed = true;
+                    } else {
+                        String notLowRam = parser.getAttributeValue(null, "notLowRam");
+                        allowed = !"true".equals(notLowRam);
+                    }
+                    if (fname == null) {
+                        Slog.w(TAG, "<feature> without name in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    } else if (allowed) {
+                        addFeature(fname, fversion);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("unavailable-feature".equals(name) && allowFeatures) {
+                    String fname = parser.getAttributeValue(null, "name");
+                    if (fname == null) {
+                        Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    } else {
+                        mUnavailableFeatures.add(fname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
+                                + permFile + " at " + parser.getPositionDescription());
+                    } else {
+                        mAllowInPowerSaveExceptIdle.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("allow-in-power-save".equals(name) && allowAll) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    } else {
+                        mAllowInPowerSave.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("allow-in-data-usage-save".equals(name) && allowAll) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mAllowInDataUsageSave.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("app-link".equals(name) && allowAppConfigs) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<app-link> without package in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    } else {
+                        mLinkedApps.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mSystemUserWhitelistedApps.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mSystemUserBlacklistedApps.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    String clsname = parser.getAttributeValue(null, "class");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else if (clsname == null) {
+                        Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                } else {
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+            }
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Got exception parsing permissions.", e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Got exception parsing permissions.", e);
+        } finally {
+            IoUtils.closeQuietly(permReader);
+        }
+
+        // Some devices can be field-converted to FBE, so offer to splice in
+        // those features if not already defined by the static config
+        if (StorageManager.isFileEncryptedNativeOnly()) {
+            addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
+            addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
+        }
+
+        for (String featureName : mUnavailableFeatures) {
+            removeFeature(featureName);
+        }
+    }
+
+    private void addFeature(String name, int version) {
+        FeatureInfo fi = mAvailableFeatures.get(name);
+        if (fi == null) {
+            fi = new FeatureInfo();
+            fi.name = name;
+            fi.version = version;
+            mAvailableFeatures.put(name, fi);
+        } else {
+            fi.version = Math.max(fi.version, version);
+        }
+    }
+
+    private void removeFeature(String name) {
+        if (mAvailableFeatures.remove(name) != null) {
+            Slog.d(TAG, "Removed unavailable feature " + name);
+        }
+    }
+
+    void readPermission(XmlPullParser parser, String name)
+            throws IOException, XmlPullParserException {
+        if (mPermissions.containsKey(name)) {
+            throw new IllegalStateException("Duplicate permission definition for " + name);
+        }
+
+        final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false);
+        final PermissionEntry perm = new PermissionEntry(name, perUser);
+        mPermissions.put(name, perm);
+
+        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 ("group".equals(tagName)) {
+                String gidStr = parser.getAttributeValue(null, "gid");
+                if (gidStr != null) {
+                    int gid = Process.getGidForName(gidStr);
+                    perm.gids = appendInt(perm.gids, gid);
+                } else {
+                    Slog.w(TAG, "<group> without gid at "
+                            + parser.getPositionDescription());
+                }
+            }
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+}
diff --git a/core/java/com/android/server/backup/ShortcutBackupHelper.java b/core/java/com/android/server/backup/ShortcutBackupHelper.java
new file mode 100644
index 0000000..0b3f2ae
--- /dev/null
+++ b/core/java/com/android/server/backup/ShortcutBackupHelper.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.backup;
+
+import android.app.backup.BlobBackupHelper;
+import android.content.Context;
+import android.content.pm.IShortcutService;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+public class ShortcutBackupHelper extends BlobBackupHelper {
+    private static final String TAG = "ShortcutBackupAgent";
+    private static final int BLOB_VERSION = 1;
+
+    private static final String KEY_USER_FILE = "shortcutuser.xml";
+
+    public ShortcutBackupHelper() {
+        super(BLOB_VERSION, KEY_USER_FILE);
+    }
+
+    private IShortcutService getShortcutService() {
+        return IShortcutService.Stub.asInterface(
+                ServiceManager.getService(Context.SHORTCUT_SERVICE));
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        switch (key) {
+            case KEY_USER_FILE:
+                try {
+                    return getShortcutService().getBackupPayload(UserHandle.USER_SYSTEM);
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Backup failed", e);
+                }
+                break;
+            default:
+                Slog.w(TAG, "Unknown key: " + key);
+        }
+        return null;
+    }
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload) {
+        switch (key) {
+            case KEY_USER_FILE:
+                try {
+                    getShortcutService().applyRestore(payload, UserHandle.USER_SYSTEM);
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Restore failed", e);
+                }
+                break;
+            default:
+                Slog.w(TAG, "Unknown key: " + key);
+        }
+    }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index cee98b8..2d12fcd 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -17,9 +17,9 @@
 package com.android.server.backup;
 
 import android.app.IWallpaperManager;
+import android.app.backup.BackupAgentHelper;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupAgentHelper;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.WallpaperBackupHelper;
@@ -48,6 +48,7 @@
     private static final String NOTIFICATION_HELPER = "notifications";
     private static final String PERMISSION_HELPER = "permissions";
     private static final String USAGE_STATS_HELPER = "usage_stats";
+    private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
 
     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
     // are also used in the full-backup file format, so must not change unless steps are
@@ -70,6 +71,8 @@
     private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
     private static final String WALLPAPER_INFO_KEY = WallpaperBackupHelper.WALLPAPER_INFO_KEY;
 
+    private WallpaperBackupHelper mWallpaperHelper = null;
+
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
@@ -98,6 +101,7 @@
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+        addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
         super.onBackup(oldState, data, newState);
     }
 
@@ -121,18 +125,22 @@
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
             throws IOException {
-        // On restore, we also support a previous data schema "system_files"
-        addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this,
+        mWallpaperHelper = new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
-                new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
+                new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} );
+        addHelper(WALLPAPER_HELPER, mWallpaperHelper);
+
+        // On restore, we also support a previous data schema "system_files"
         addHelper("system_files", new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE },
                 new String[] { WALLPAPER_IMAGE_KEY} ));
+
         addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+        addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
 
         try {
             super.onRestore(data, appVersionCode, newState);
@@ -202,4 +210,9 @@
             }
         }
     }
+
+    @Override
+    public void onRestoreFinished() {
+        mWallpaperHelper.onRestoreFinished();
+    }
 }
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
index d45982e..5b421d9 100644
--- a/core/java/com/android/server/net/NetlinkTracker.java
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -102,6 +102,19 @@
     }
 
     @Override
+    public void interfaceRemoved(String iface) {
+        maybeLog("interfaceRemoved", iface);
+        if (mInterfaceName.equals(iface)) {
+            // Our interface was removed. Clear our LinkProperties and tell our owner that they are
+            // now empty. Note that from the moment that the interface is removed, any further
+            // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
+            // code that parses them will not be able to resolve the ifindex to an interface name.
+            clearLinkProperties();
+            mCallback.update();
+        }
+    }
+
+    @Override
     public void addressUpdated(String iface, LinkAddress address) {
         if (mInterfaceName.equals(iface)) {
             maybeLog("addressUpdated", iface, address);
diff --git a/core/java/com/android/server/net/NetworkPinner.java b/core/java/com/android/server/net/NetworkPinner.java
new file mode 100644
index 0000000..d922a48
--- /dev/null
+++ b/core/java/com/android/server/net/NetworkPinner.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A class that pins a process to the first network that satisfies a particular NetworkRequest.
+ *
+ * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
+ * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
+ * able to use that network because it's the system default.
+ *
+ * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
+ * we try not to set the default network unless they have already done so, and we try not to
+ * clear the default network unless we set it ourselves.
+ *
+ * This should maintain behaviour that's compatible with L, which would pin the whole system to
+ * any wifi network that was created via enableNetwork(..., true) until that network
+ * disconnected.
+ *
+ * Note that while this hack allows network traffic to flow, it is quite limited. For example:
+ *
+ * 1. setProcessDefaultNetwork only affects this process, so:
+ *    - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
+ *    - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
+ *      either, because other apps on the device will not be pinned.
+ * 2. The behaviour of other APIs is not modified. For example:
+ *    - getActiveNetworkInfo will return the system default network, not Wi-Fi.
+ *    - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
+ *    - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
+ *      will be surprised as well.
+ *
+ * This class is a per-process singleton because the process default network is a per-process
+ * singleton.
+ *
+ */
+public class NetworkPinner extends NetworkCallback {
+
+    private static final String TAG = NetworkPinner.class.getSimpleName();
+
+    @VisibleForTesting
+    protected static final Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static ConnectivityManager sCM;
+    @GuardedBy("sLock")
+    private static Callback sCallback;
+    @VisibleForTesting
+    @GuardedBy("sLock")
+    protected static Network sNetwork;
+
+    private static void maybeInitConnectivityManager(Context context) {
+        // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
+        // registered? Can we fix this by starting ConnectivityService before WifiService?
+        if (sCM == null) {
+            // Getting a ConnectivityManager does not leak the calling context, because it stores
+            // the application context and not the calling context.
+            sCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+            if (sCM == null) {
+                throw new IllegalStateException("Bad luck, ConnectivityService not started.");
+            }
+        }
+    }
+
+    private static class Callback extends NetworkCallback {
+        @Override
+        public void onAvailable(Network network) {
+            synchronized(sLock) {
+                if (this != sCallback) return;
+
+                if (sCM.getBoundNetworkForProcess() == null && sNetwork == null) {
+                    sCM.bindProcessToNetwork(network);
+                    sNetwork = network;
+                    Log.d(TAG, "Wifi alternate reality enabled on network " + network);
+                }
+                sLock.notify();
+            }
+        }
+
+        @Override
+        public void onLost(Network network) {
+            synchronized (sLock) {
+                if (this != sCallback) return;
+
+                if (network.equals(sNetwork) && network.equals(sCM.getBoundNetworkForProcess())) {
+                    unpin();
+                    Log.d(TAG, "Wifi alternate reality disabled on network " + network);
+                }
+                sLock.notify();
+            }
+        }
+    }
+
+    public static void pin(Context context, NetworkRequest request) {
+        synchronized (sLock) {
+            if (sCallback == null) {
+                maybeInitConnectivityManager(context);
+                sCallback = new Callback();
+                try {
+                    sCM.registerNetworkCallback(request, sCallback);
+                } catch (SecurityException e) {
+                    Log.d(TAG, "Failed to register network callback", e);
+                    sCallback = null;
+                }
+            }
+        }
+    }
+
+    public static void unpin() {
+        synchronized (sLock) {
+            if (sCallback != null) {
+                try {
+                    sCM.bindProcessToNetwork(null);
+                    sCM.unregisterNetworkCallback(sCallback);
+                } catch (SecurityException e) {
+                    Log.d(TAG, "Failed to unregister network callback", e);
+                }
+                sCallback = null;
+                sNetwork = null;
+            }
+        }
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 8b686b7..8a512a6 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -33,8 +33,10 @@
     com_android_internal_content_NativeLibraryHelper.cpp \
     com_google_android_gles_jni_EGLImpl.cpp \
     com_google_android_gles_jni_GLImpl.cpp.arm \
+    android_app_Activity.cpp \
+    android_app_ApplicationLoaders.cpp \
     android_app_NativeActivity.cpp \
-    android_auditing_SecurityLog.cpp \
+    android_app_admin_SecurityLog.cpp \
     android_opengl_EGL14.cpp \
     android_opengl_EGLExt.cpp \
     android_opengl_GLES10.cpp \
@@ -101,7 +103,6 @@
     android_util_jar_StrictJarFile.cpp \
     android_graphics_Canvas.cpp \
     android_graphics_Picture.cpp \
-    android/graphics/AvoidXfermode.cpp \
     android/graphics/Bitmap.cpp \
     android/graphics/BitmapFactory.cpp \
     android/graphics/Camera.cpp \
@@ -115,13 +116,10 @@
     android/graphics/Interpolator.cpp \
     android/graphics/MaskFilter.cpp \
     android/graphics/Matrix.cpp \
-    android/graphics/MinikinSkia.cpp \
-    android/graphics/MinikinUtils.cpp \
     android/graphics/Movie.cpp \
     android/graphics/NinePatch.cpp \
     android/graphics/NinePatchPeeker.cpp \
     android/graphics/Paint.cpp \
-    android/graphics/PaintImpl.cpp \
     android/graphics/Path.cpp \
     android/graphics/PathMeasure.cpp \
     android/graphics/PathEffect.cpp \
@@ -133,7 +131,6 @@
     android/graphics/Shader.cpp \
     android/graphics/SurfaceTexture.cpp \
     android/graphics/Typeface.cpp \
-    android/graphics/TypefaceImpl.cpp \
     android/graphics/Utils.cpp \
     android/graphics/Xfermode.cpp \
     android/graphics/YuvToJpegEncoder.cpp \
@@ -159,6 +156,7 @@
     android_hardware_UsbDevice.cpp \
     android_hardware_UsbDeviceConnection.cpp \
     android_hardware_UsbRequest.cpp \
+    android_hardware_location_ContextHubService.cpp \
     android_hardware_location_ActivityRecognitionHardware.cpp \
     android_util_FileObserver.cpp \
     android/opengl/poly_clip.cpp.arm \
@@ -188,16 +186,15 @@
     $(call include-path-for, bluedroid) \
     $(call include-path-for, libhardware)/hardware \
     $(call include-path-for, libhardware_legacy)/hardware_legacy \
-    $(TOP)/frameworks/av/include \
     $(TOP)/frameworks/base/media/jni \
     $(TOP)/system/core/base/include \
     $(TOP)/system/core/include \
     $(TOP)/system/media/camera/include \
     $(TOP)/system/netd/include \
     external/pdfium/core/include/fpdfapi \
-    external/pdfium/core/include/fpdfdoc \
     external/pdfium/fpdfsdk/include \
     external/pdfium/public \
+    external/pdfium \
     external/skia/include/private \
     external/skia/src/core \
     external/skia/src/effects \
@@ -259,7 +256,8 @@
     libprocessgroup \
     libnativebridge \
     libradio_metadata \
-    libnativeloader
+    libnativeloader \
+    libmemunreachable \
 
 LOCAL_SHARED_LIBRARIES += \
     libhwui \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 017fb53..7ff38fd5 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -95,6 +95,7 @@
 extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
 extern int register_android_hardware_UsbRequest(JNIEnv *env);
 extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env);
+extern int register_android_hardware_location_ContextHubService(JNIEnv* env);
 
 extern int register_android_media_AudioRecord(JNIEnv *env);
 extern int register_android_media_AudioSystem(JNIEnv *env);
@@ -108,7 +109,7 @@
  * JNI-based registration functions.  Note these are properly contained in
  * namespace android.
  */
-extern int register_android_auditing_SecurityLog(JNIEnv* env);
+extern int register_android_app_admin_SecurityLog(JNIEnv* env);
 extern int register_android_content_AssetManager(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
@@ -177,6 +178,8 @@
 extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
 extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
 extern int register_android_app_backup_FullBackup(JNIEnv *env);
+extern int register_android_app_ApplicationLoaders(JNIEnv* env);
+extern int register_android_app_Activity(JNIEnv *env);
 extern int register_android_app_ActivityThread(JNIEnv *env);
 extern int register_android_app_NativeActivity(JNIEnv *env);
 extern int register_android_media_RemoteDisplay(JNIEnv *env);
@@ -1182,8 +1185,7 @@
     void** args = (void**) malloc(3 * sizeof(void*));   // javaThreadShell must free
     int result;
 
-    if (!threadName)
-        threadName = "unnamed thread";
+    LOG_ALWAYS_FATAL_IF(threadName == nullptr, "threadName not provided to javaCreateThreadEtc");
 
     args[0] = (void*) entryFunction;
     args[1] = userData;
@@ -1251,7 +1253,7 @@
     REG_JNI(register_android_util_EventLog),
     REG_JNI(register_android_util_Log),
     REG_JNI(register_android_util_PathParser),
-    REG_JNI(register_android_auditing_SecurityLog),
+    REG_JNI(register_android_app_admin_SecurityLog),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
     REG_JNI(register_android_content_XmlBlock),
@@ -1356,6 +1358,7 @@
     REG_JNI(register_android_hardware_UsbDeviceConnection),
     REG_JNI(register_android_hardware_UsbRequest),
     REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),
+    REG_JNI(register_android_hardware_location_ContextHubService),
     REG_JNI(register_android_media_AudioRecord),
     REG_JNI(register_android_media_AudioSystem),
     REG_JNI(register_android_media_AudioTrack),
@@ -1371,6 +1374,8 @@
     REG_JNI(register_android_backup_FileBackupHelperBase),
     REG_JNI(register_android_backup_BackupHelperDispatcher),
     REG_JNI(register_android_app_backup_FullBackup),
+    REG_JNI(register_android_app_ApplicationLoaders),
+    REG_JNI(register_android_app_Activity),
     REG_JNI(register_android_app_ActivityThread),
     REG_JNI(register_android_app_NativeActivity),
     REG_JNI(register_android_util_jar_StrictJarFile),
diff --git a/core/jni/android/graphics/AvoidXfermode.cpp b/core/jni/android/graphics/AvoidXfermode.cpp
deleted file mode 100644
index 9ca1f26..0000000
--- a/core/jni/android/graphics/AvoidXfermode.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "AvoidXfermode.h"
-#include "SkColorPriv.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "SkString.h"
-
-AvoidXfermode::AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
-    if (tolerance > 255) {
-        tolerance = 255;
-    }
-    fTolerance = SkToU8(tolerance);
-    fOpColor = opColor;
-    fDistMul = (256 << 14) / (tolerance + 1);
-    fMode = mode;
-}
-
-SkFlattenable* AvoidXfermode::CreateProc(SkReadBuffer& buffer) {
-    const SkColor color = buffer.readColor();
-    const unsigned tolerance = buffer.readUInt();
-    const unsigned mode = buffer.readUInt();
-    return Create(color, tolerance, (Mode)mode);
-}
-
-void AvoidXfermode::flatten(SkWriteBuffer& buffer) const {
-    buffer.writeColor(fOpColor);
-    buffer.writeUInt(fTolerance);
-    buffer.writeUInt(fMode);
-}
-
-// returns 0..31
-static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
-    SkASSERT(r <= SK_R16_MASK);
-    SkASSERT(g <= SK_G16_MASK);
-    SkASSERT(b <= SK_B16_MASK);
-
-    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
-    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
-    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
-
-    return SkMax32(dr, SkMax32(dg, db));
-}
-
-// returns 0..255
-static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
-    SkASSERT(r <= 0xFF);
-    SkASSERT(g <= 0xFF);
-    SkASSERT(b <= 0xFF);
-
-    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
-    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
-    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
-
-    return SkMax32(dr, SkMax32(dg, db));
-}
-
-static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
-    int tmp = dist * mul - sub;
-    int result = (tmp + (1 << 13)) >> 14;
-
-    return result;
-}
-
-static inline unsigned Accurate255To256(unsigned x) {
-    return x + (x >> 7);
-}
-
-void AvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
-                             const SkAlpha aa[]) const {
-    unsigned    opR = SkColorGetR(fOpColor);
-    unsigned    opG = SkColorGetG(fOpColor);
-    unsigned    opB = SkColorGetB(fOpColor);
-    uint32_t    mul = fDistMul;
-    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
-
-    int MAX, mask;
-
-    if (kTargetColor_Mode == fMode) {
-        mask = -1;
-        MAX = 255;
-    } else {
-        mask = 0;
-        MAX = 0;
-    }
-
-    for (int i = 0; i < count; i++) {
-        int d = color_dist32(dst[i], opR, opG, opB);
-        // now reverse d if we need to
-        d = MAX + (d ^ mask) - mask;
-        SkASSERT((unsigned)d <= 255);
-        d = Accurate255To256(d);
-
-        d = scale_dist_14(d, mul, sub);
-        SkASSERT(d <= 256);
-
-        if (d > 0) {
-            if (aa) {
-                d = SkAlphaMul(d, Accurate255To256(*aa++));
-                if (0 == d) {
-                    continue;
-                }
-            }
-            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
-        }
-    }
-}
-
-static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
-    SkASSERT(scale <= 32);
-    scale <<= 3;
-
-    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
-                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
-                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
-}
-
-void AvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
-                             const SkAlpha aa[]) const {
-    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
-    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
-    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
-    uint32_t    mul = fDistMul;
-    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
-
-    int MAX, mask;
-
-    if (kTargetColor_Mode == fMode) {
-        mask = -1;
-        MAX = 31;
-    } else {
-        mask = 0;
-        MAX = 0;
-    }
-
-    for (int i = 0; i < count; i++) {
-        int d = color_dist16(dst[i], opR, opG, opB);
-        // now reverse d if we need to
-        d = MAX + (d ^ mask) - mask;
-        SkASSERT((unsigned)d <= 31);
-        // convert from 0..31 to 0..32
-        d += d >> 4;
-        d = scale_dist_14(d, mul, sub);
-        SkASSERT(d <= 32);
-
-        if (d > 0) {
-            if (aa) {
-                d = SkAlphaMul(d, Accurate255To256(*aa++));
-                if (0 == d) {
-                    continue;
-                }
-            }
-            dst[i] = SkBlend3216(src[i], dst[i], d);
-        }
-    }
-}
-
-void AvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
-        const SkAlpha aa[]) const {
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void AvoidXfermode::toString(SkString* str) const {
-    str->append("AvoidXfermode: opColor: ");
-    str->appendHex(fOpColor);
-    str->appendf("distMul: %d ", fDistMul);
-
-    static const char* gModeStrings[] = { "Avoid", "Target" };
-
-    str->appendf("mode: %s", gModeStrings[fMode]);
-}
-#endif
diff --git a/core/jni/android/graphics/AvoidXfermode.h b/core/jni/android/graphics/AvoidXfermode.h
deleted file mode 100644
index 8b7fb71..0000000
--- a/core/jni/android/graphics/AvoidXfermode.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef AvoidXfermode_DEFINED
-#define AvoidXfermode_DEFINED
-
-#include "SkColor.h"
-#include "SkTypes.h"
-#include "SkXfermode.h"
-
-/** \class AvoidXfermode
-
-    This xfermode will draw the src everywhere except on top of the specified
-    color.
-*/
-class AvoidXfermode : public SkXfermode {
-public:
-    enum Mode {
-        kAvoidColor_Mode,   //!< draw everywhere except on the opColor
-        kTargetColor_Mode   //!< draw only on top of the opColor
-    };
-
-    /** This xfermode draws, or doesn't draw, based on the destination's
-        distance from an op-color.
-
-        There are two modes, and each mode interprets a tolerance value.
-
-        Avoid: In this mode, drawing is allowed only on destination pixels that
-               are different from the op-color.
-               Tolerance near 0: avoid any colors even remotely similar to the op-color
-               Tolerance near 255: avoid only colors nearly identical to the op-color
-
-        Target: In this mode, drawing only occurs on destination pixels that
-                are similar to the op-color
-                Tolerance near 0: draw only on colors that are nearly identical to the op-color
-                Tolerance near 255: draw on any colors even remotely similar to the op-color
-     */
-    static AvoidXfermode* Create(SkColor opColor, U8CPU tolerance, Mode mode) {
-        return new AvoidXfermode(opColor, tolerance, mode);
-    }
-
-    // overrides from SkXfermode
-    void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
-            const SkAlpha aa[]) const override;
-    void xfer16(uint16_t dst[], const SkPMColor src[], int count,
-            const SkAlpha aa[]) const override;
-    void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
-            const SkAlpha aa[]) const override;
-
-    SK_TO_STRING_OVERRIDE()
-    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(AvoidXfermode)
-
-protected:
-    AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode);
-    void flatten(SkWriteBuffer&) const override;
-
-private:
-    SkColor     fOpColor;
-    uint32_t    fDistMul;   // x.14 cached from fTolerance
-    uint8_t     fTolerance;
-    Mode        fMode;
-
-    typedef SkXfermode INHERITED;
-};
-
-#endif
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 43e26b3..22a81d4 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,7 +1,6 @@
 #define LOG_TAG "Bitmap"
 #include "Bitmap.h"
 
-#include "Paint.h"
 #include "SkBitmap.h"
 #include "SkPixelRef.h"
 #include "SkImageEncoder.h"
@@ -18,6 +17,7 @@
 #include "android_nio_utils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include <Caches.h>
+#include <hwui/Paint.h>
 
 #include "core_jni_helpers.h"
 
@@ -251,13 +251,6 @@
 
 void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
         SkColorTable* ctable) {
-    {
-        android::AutoMutex _lock(mLock);
-        if (mPinnedRefCount) {
-            ALOGW("Called reconfigure on a bitmap that is in use! This may"
-                    " cause graphical corruption!");
-        }
-    }
     mPixelRef->reconfigure(info, rowBytes, ctable);
 }
 
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 8b248b0..4001283 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -73,6 +73,9 @@
         case SkEncodedFormat::kWBMP_SkEncodedFormat:
             mimeType = "image/vnd.wap.wbmp";
             break;
+        case SkEncodedFormat::kRAW_SkEncodedFormat:
+            mimeType = "image/x-adobe-dng";
+            break;
         default:
             mimeType = nullptr;
             break;
@@ -201,6 +204,26 @@
     const unsigned int mSize;
 };
 
+// Necessary for decodes when the native decoder cannot scale to appropriately match the sampleSize
+// (for example, RAW). If the sampleSize divides evenly into the dimension, we require that the
+// scale matches exactly. If sampleSize does not divide evenly, we allow the decoder to choose how
+// best to round.
+static bool needsFineScale(const int fullSize, const int decodedSize, const int sampleSize) {
+    if (fullSize % sampleSize == 0 && fullSize / sampleSize != decodedSize) {
+        return true;
+    } else if ((fullSize / sampleSize + 1) != decodedSize &&
+               (fullSize / sampleSize) != decodedSize) {
+        return true;
+    }
+    return false;
+}
+
+static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize,
+                           const int sampleSize) {
+    return needsFineScale(fullSize.width(), decodedSize.width(), sampleSize) ||
+           needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
+}
+
 static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
     // This function takes ownership of the input stream.  Since the SkAndroidCodec
     // will take ownership of the stream, we don't necessarily need to take ownership
@@ -250,7 +273,6 @@
             }
         }
     }
-    const bool willScale = scale != 1.0f;
 
     // Create the codec.
     NinePatchPeeker peeker;
@@ -269,15 +291,28 @@
         prefColorType = kN32_SkColorType;
     }
 
-    // Determine the output size and return if the client only wants the size.
+    // Determine the output size.
     SkISize size = codec->getSampledDimensions(sampleSize);
+
+    int scaledWidth = size.width();
+    int scaledHeight = size.height();
+    bool willScale = false;
+
+    // Apply a fine scaling step if necessary.
+    if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize)) {
+        willScale = true;
+        scaledWidth = codec->getInfo().width() / sampleSize;
+        scaledHeight = codec->getInfo().height() / sampleSize;
+    }
+
+    // Set the options and return if the client only wants the size.
     if (options != NULL) {
         jstring mimeType = encodedFormatToString(env, codec->getEncodedFormat());
         if (env->ExceptionCheck()) {
             return nullObjectReturn("OOM in encodedFormatToString()");
         }
-        env->SetIntField(options, gOptions_widthFieldID, size.width());
-        env->SetIntField(options, gOptions_heightFieldID, size.height());
+        env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
+        env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
         env->SetObjectField(options, gOptions_mimeFieldID, mimeType);
 
         if (onlyDecodeSize) {
@@ -285,6 +320,13 @@
         }
     }
 
+    // Scale is necessary due to density differences.
+    if (scale != 1.0f) {
+        willScale = true;
+        scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f);
+        scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f);
+    }
+
     android::Bitmap* reuseBitmap = nullptr;
     unsigned int existingBufferSize = 0;
     if (javaBitmap != NULL) {
@@ -381,13 +423,6 @@
             return nullObjectReturn("codec->getAndroidPixels() failed.");
     }
 
-    int scaledWidth = size.width();
-    int scaledHeight = size.height();
-    if (willScale) {
-        scaledWidth = int(scaledWidth * scale + 0.5f);
-        scaledHeight = int(scaledHeight * scale + 0.5f);
-    }
-
     jbyteArray ninePatchChunk = NULL;
     if (peeker.mPatch != NULL) {
         if (willScale) {
@@ -555,6 +590,12 @@
     std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file,
             SkFILEStream::kCallerPasses_Ownership));
 
+    // If there is no offset for the file descriptor, we use SkFILEStream directly.
+    if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
+        assert(isSeekable(dupDescriptor));
+        return doDecode(env, fileStream.release(), padding, bitmapFactoryOptions);
+    }
+
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
     // ensures that SkImageDecoder::Factory never rewinds beyond the
     // current position of the file descriptor.
@@ -584,7 +625,7 @@
 
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
+    return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE;
 }
 
 jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 6fcf689..76d6851 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -3,8 +3,8 @@
 
 #include "SkCamera.h"
 
-#include "Canvas.h"
 #include "GraphicsJNI.h"
+#include <hwui/Canvas.h>
 
 static jfieldID gNativeInstanceFieldID;
 
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
index 728bc1c..c841d6a 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -16,9 +16,9 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include "Paint.h"
 #include <core_jni_helpers.h>
 
+#include <hwui/Paint.h>
 #include <utils/RefBase.h>
 #include <CanvasProperty.h>
 
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 2e974a3..6dc251c 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -31,9 +31,9 @@
 #include <androidfw/AssetManager.h>
 #include "Utils.h"
 
-#include "TypefaceImpl.h"
+#include <hwui/MinikinSkia.h>
+#include <hwui/Typeface.h>
 #include <minikin/FontFamily.h>
-#include "MinikinSkia.h"
 
 #include <memory>
 
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index bd01c73..528541d 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -7,13 +7,13 @@
 #include "JNIHelp.h"
 #include "GraphicsJNI.h"
 
-#include "Canvas.h"
 #include "SkCanvas.h"
 #include "SkDevice.h"
 #include "SkMath.h"
 #include "SkRegion.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <cutils/ashmem.h>
+#include <hwui/Canvas.h>
 
 #include <Caches.h>
 #include <TextureCache.h>
@@ -723,6 +723,7 @@
         // Make sure that the recycled bitmap has the correct alpha type.
         mRecycledBitmap->setAlphaType(bitmap->alphaType());
 
+        bitmap->notifyPixelsChanged();
         bitmap->lockPixels();
         mNeedsCopy = false;
 
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index e99a3ff..5baa8f8 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -11,15 +11,15 @@
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkImageDecoder.h"
-#include <Canvas.h>
 #include <jni.h>
+#include <hwui/Canvas.h>
 
 class SkBitmapRegionDecoder;
 class SkCanvas;
 
 namespace android {
 class Paint;
-struct TypefaceImpl;
+struct Typeface;
 }
 
 class GraphicsJNI {
diff --git a/core/jni/android/graphics/MinikinSkia.cpp b/core/jni/android/graphics/MinikinSkia.cpp
deleted file mode 100644
index 8ac5d46..0000000
--- a/core/jni/android/graphics/MinikinSkia.cpp
+++ /dev/null
@@ -1,116 +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.
- */
-
-#include <SkTypeface.h>
-#include <SkPaint.h>
-
-#define LOG_TAG "Minikin"
-#include <cutils/log.h>
-
-#include "MinikinSkia.h"
-
-namespace android {
-
-MinikinFontSkia::MinikinFontSkia(SkTypeface *typeface) :
-    mTypeface(typeface) {
-}
-
-MinikinFontSkia::~MinikinFontSkia() {
-    SkSafeUnref(mTypeface);
-}
-
-static void MinikinFontSkia_SetSkiaPaint(const MinikinFont* font, SkPaint* skPaint, const MinikinPaint& paint) {
-    skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-    skPaint->setTextSize(paint.size);
-    skPaint->setTextScaleX(paint.scaleX);
-    skPaint->setTextSkewX(paint.skewX);
-    MinikinFontSkia::unpackPaintFlags(skPaint, paint.paintFlags);
-    // Apply font fakery on top of user-supplied flags.
-    MinikinFontSkia::populateSkPaint(skPaint, font, paint.fakery);
-}
-
-float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
-    const MinikinPaint &paint) const {
-    SkPaint skPaint;
-    uint16_t glyph16 = glyph_id;
-    SkScalar skWidth;
-    MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
-    skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
-#ifdef VERBOSE
-    ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
-#endif
-    return skWidth;
-}
-
-void MinikinFontSkia::GetBounds(MinikinRect* bounds, uint32_t glyph_id,
-    const MinikinPaint& paint) const {
-    SkPaint skPaint;
-    uint16_t glyph16 = glyph_id;
-    SkRect skBounds;
-    MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
-    skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
-    bounds->mLeft = skBounds.fLeft;
-    bounds->mTop = skBounds.fTop;
-    bounds->mRight = skBounds.fRight;
-    bounds->mBottom = skBounds.fBottom;
-}
-
-bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {
-    if (buf == NULL) {
-        const size_t tableSize = mTypeface->getTableSize(tag);
-        *size = tableSize;
-        return tableSize != 0;
-    } else {
-        const size_t actualSize = mTypeface->getTableData(tag, 0, *size, buf);
-        *size = actualSize;
-        return actualSize != 0;
-    }
-}
-
-SkTypeface *MinikinFontSkia::GetSkTypeface() const {
-    return mTypeface;
-}
-
-int32_t MinikinFontSkia::GetUniqueId() const {
-    return mTypeface->uniqueID();
-}
-
-uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
-    uint32_t flags = paint->getFlags();
-    SkPaint::Hinting hinting = paint->getHinting();
-    // select only flags that might affect text layout
-    flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
-            SkPaint::kSubpixelText_Flag | SkPaint::kDevKernText_Flag |
-            SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag |
-            SkPaint::kVerticalText_Flag);
-    flags |= (hinting << 16);
-    return flags;
-}
-
-void MinikinFontSkia::unpackPaintFlags(SkPaint* paint, uint32_t paintFlags) {
-    paint->setFlags(paintFlags & SkPaint::kAllFlags);
-    paint->setHinting(static_cast<SkPaint::Hinting>(paintFlags >> 16));
-}
-
-void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery) {
-    paint->setTypeface(reinterpret_cast<const MinikinFontSkia*>(font)->GetSkTypeface());
-    paint->setFakeBoldText(paint->isFakeBoldText() || fakery.isFakeBold());
-    if (fakery.isFakeItalic()) {
-        paint->setTextSkewX(paint->getTextSkewX() - 0.25f);
-    }
-}
-
-}
diff --git a/core/jni/android/graphics/MinikinSkia.h b/core/jni/android/graphics/MinikinSkia.h
deleted file mode 100644
index 8f469ba..0000000
--- a/core/jni/android/graphics/MinikinSkia.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
-#define _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
-
-#include <minikin/MinikinFont.h>
-
-namespace android {
-
-class MinikinFontSkia : public MinikinFont {
-public:
-    // Note: this takes ownership of the reference (will unref on dtor)
-    explicit MinikinFontSkia(SkTypeface *typeface);
-
-    ~MinikinFontSkia();
-
-    float GetHorizontalAdvance(uint32_t glyph_id,
-        const MinikinPaint &paint) const;
-
-    void GetBounds(MinikinRect* bounds, uint32_t glyph_id,
-        const MinikinPaint &paint) const;
-
-    // If buf is NULL, just update size
-    bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
-
-    int32_t GetUniqueId() const;
-
-    SkTypeface* GetSkTypeface() const;
-
-    static uint32_t packPaintFlags(const SkPaint* paint);
-    static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags);
-
-    // set typeface and fake bold/italic parameters
-    static void populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery);
-private:
-    SkTypeface *mTypeface;
-};
-
-}  // namespace android
-
-#endif  // _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
deleted file mode 100644
index 309d35b..0000000
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Minikin"
-#include <cutils/log.h>
-#include <string>
-
-#include "SkPathMeasure.h"
-#include "Paint.h"
-#include "TypefaceImpl.h"
-
-#include "MinikinUtils.h"
-
-namespace android {
-
-FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
-        const Paint* paint, TypefaceImpl* typeface) {
-    const TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
-    *pFont = resolvedFace->fFontCollection;
-    FontStyle resolved = resolvedFace->fStyle;
-
-    /* Prepare minikin FontStyle */
-    FontVariant minikinVariant = (paint->getFontVariant() == VARIANT_ELEGANT) ? VARIANT_ELEGANT
-            : VARIANT_COMPACT;
-    const uint32_t langListId = paint->getMinikinLangListId();
-    FontStyle minikinStyle(langListId, minikinVariant, resolved.getWeight(), resolved.getItalic());
-
-    /* Prepare minikin Paint */
-    // Note: it would be nice to handle fractional size values (it would improve smooth zoom
-    // behavior), but historically size has been treated as an int.
-    // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set.
-    minikinPaint->size = (int)paint->getTextSize();
-    minikinPaint->scaleX = paint->getTextScaleX();
-    minikinPaint->skewX = paint->getTextSkewX();
-    minikinPaint->letterSpacing = paint->getLetterSpacing();
-    minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
-    minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
-    minikinPaint->hyphenEdit = HyphenEdit(paint->getHyphenEdit());
-    return minikinStyle;
-}
-
-void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags,
-        TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
-        size_t bufSize) {
-    FontCollection *font;
-    MinikinPaint minikinPaint;
-    FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
-    layout->setFontCollection(font);
-    layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
-}
-
-float MinikinUtils::measureText(const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
-        const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) {
-    FontCollection *font;
-    MinikinPaint minikinPaint;
-    FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
-    return Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint,
-            font, advances);
-}
-
-bool MinikinUtils::hasVariationSelector(TypefaceImpl* typeface, uint32_t codepoint, uint32_t vs) {
-    const TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
-    return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
-}
-
-float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) {
-    switch (paint->getTextAlign()) {
-        case Paint::kCenter_Align:
-            return layout.getAdvance() * -0.5f;
-            break;
-        case Paint::kRight_Align:
-            return -layout.getAdvance();
-            break;
-        default:
-            break;
-    }
-    return 0;
-}
-
-float MinikinUtils::hOffsetForTextAlign(Paint* paint, const Layout& layout, const SkPath& path) {
-    float align = 0;
-    switch (paint->getTextAlign()) {
-        case Paint::kCenter_Align:
-            align = -0.5f;
-            break;
-        case Paint::kRight_Align:
-            align = -1;
-            break;
-        default:
-            return 0;
-    }
-    SkPathMeasure measure(path, false);
-    return align * (layout.getAdvance() - measure.getLength());
-}
-
-}
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
deleted file mode 100644
index 9152539..0000000
--- a/core/jni/android/graphics/MinikinUtils.h
+++ /dev/null
@@ -1,81 +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.
- */
-
-/**
- * Utilities for making Minikin work, especially from existing objects like
- * Paint and so on.
- **/
-
- // TODO: does this really need to be separate from MinikinSkia?
-
-#ifndef _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
-#define _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
-
-#include <minikin/Layout.h>
-#include "Paint.h"
-#include "MinikinSkia.h"
-#include "TypefaceImpl.h"
-
-namespace android {
-
-class MinikinUtils {
-public:
-    static FontStyle prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
-            const Paint* paint, TypefaceImpl* typeface);
-
-    static void doLayout(Layout* layout, const Paint* paint, int bidiFlags,
-            TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
-            size_t bufSize);
-
-    static float measureText(const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
-            const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances);
-
-    static bool hasVariationSelector(TypefaceImpl* typeface, uint32_t codepoint, uint32_t vs);
-
-    static float xOffsetForTextAlign(Paint* paint, const Layout& layout);
-
-    static float hOffsetForTextAlign(Paint* paint, const Layout& layout, const SkPath& path);
-    // f is a functor of type void f(size_t start, size_t end);
-    template <typename F>
-    static void forFontRun(const Layout& layout, Paint* paint, F& f) {
-        float saveSkewX = paint->getTextSkewX();
-        bool savefakeBold = paint->isFakeBoldText();
-        MinikinFont* curFont = NULL;
-        size_t start = 0;
-        size_t nGlyphs = layout.nGlyphs();
-        for (size_t i = 0; i < nGlyphs; i++) {
-            MinikinFont* nextFont = layout.getFont(i);
-            if (i > 0 && nextFont != curFont) {
-                MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
-                f(start, i);
-                paint->setTextSkewX(saveSkewX);
-                paint->setFakeBoldText(savefakeBold);
-                start = i;
-            }
-            curFont = nextFont;
-        }
-        if (nGlyphs > start) {
-            MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
-            f(start, nGlyphs);
-            paint->setTextSkewX(saveSkewX);
-            paint->setFakeBoldText(savefakeBold);
-        }
-    }
-};
-
-}  // namespace android
-
-#endif  // _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 498c590..71988f9c 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -1,7 +1,5 @@
-#include "Canvas.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "GraphicsJNI.h"
-#include "Paint.h"
 #include "ScopedLocalRef.h"
 #include "SkFrontBufferedStream.h"
 #include "SkMovie.h"
@@ -12,6 +10,8 @@
 
 #include <androidfw/Asset.h>
 #include <androidfw/ResourceTypes.h>
+#include <hwui/Canvas.h>
+#include <hwui/Paint.h>
 #include <jni.h>
 #include <netinet/in.h>
 
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 3ccbb35..4f2f389 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -19,12 +19,12 @@
 #define LOG_NDEBUG 1
 
 #include <androidfw/ResourceTypes.h>
+#include <hwui/Canvas.h>
+#include <hwui/Paint.h>
 #include <utils/Log.h>
 
 #include <ResourceCache.h>
 
-#include "Paint.h"
-#include "Canvas.h"
 #include "SkCanvas.h"
 #include "SkRegion.h"
 #include "GraphicsJNI.h"
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index d00e94c..1844a98 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -37,13 +37,13 @@
 #include "unicode/ushape.h"
 #include "utils/Blur.h"
 
+#include <hwui/MinikinSkia.h>
+#include <hwui/MinikinUtils.h>
+#include <hwui/Paint.h>
+#include <hwui/Typeface.h>
 #include <minikin/GraphemeBreak.h>
 #include <minikin/Measurement.h>
 #include <unicode/utf16.h>
-#include "MinikinSkia.h"
-#include "MinikinUtils.h"
-#include "Paint.h"
-#include "TypefaceImpl.h"
 
 #include <cassert>
 #include <cstring>
@@ -402,8 +402,8 @@
         const int kElegantDescent = -500;
         const int kElegantLeading = 0;
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
-        typeface = TypefaceImpl_resolveDefault(typeface);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
+        typeface = Typeface::resolveDefault(typeface);
         FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
         float saveSkewX = paint->getTextSkewX();
         bool savefakeBold = paint->isFakeBoldText();
@@ -474,7 +474,7 @@
         return descent - ascent + leading;
     }
 
-    static jfloat doTextAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface,
+    static jfloat doTextAdvances(JNIEnv *env, Paint *paint, Typeface* typeface,
             const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags,
             jfloatArray advances, jint advancesIndex) {
         NPE_CHECK_RETURN_ZERO(env, text);
@@ -510,7 +510,7 @@
             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
             jint bidiFlags, jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         jchar* textArray = env->GetCharArrayElements(text, NULL);
         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
                 index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
@@ -523,7 +523,7 @@
             jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags,
             jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
@@ -590,7 +590,7 @@
         SkPath tmpPath;
     };
 
-    static void getTextPath(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar* text,
+    static void getTextPath(JNIEnv* env, Paint* paint, Typeface* typeface, const jchar* text,
             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
         Layout layout;
         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
@@ -613,7 +613,7 @@
             jlong typefaceHandle, jint bidiFlags,
             jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
         getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
@@ -624,7 +624,7 @@
             jlong typefaceHandle, jint bidiFlags,
             jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
         getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
@@ -648,7 +648,7 @@
         return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
     }
 
-    static int breakText(JNIEnv* env, const Paint& paint, TypefaceImpl* typeface, const jchar text[],
+    static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
                          int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
                          const bool forwardScan) {
         size_t measuredCount = 0;
@@ -685,7 +685,7 @@
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
         bool forwardTextDirection;
         if (count < 0) {
@@ -714,7 +714,7 @@
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
         int count = env->GetStringLength(jtext);
         const jchar* text = env->GetStringChars(jtext, NULL);
@@ -724,7 +724,7 @@
     }
 
     static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
-            const Paint& paint, TypefaceImpl* typeface, jint bidiFlags) {
+            const Paint& paint, Typeface* typeface, jint bidiFlags) {
         SkRect  r;
         SkIRect ir;
 
@@ -743,7 +743,7 @@
     static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
                                 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
         env->ReleaseStringChars(text, textArray);
@@ -752,7 +752,7 @@
     static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
                         jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
         doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
@@ -771,7 +771,7 @@
     static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
             jint bidiFlags, jstring string) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         ScopedStringChars str(env, string);
 
         /* Start by rejecting unsupported base code point and variation selector pairs. */
@@ -820,10 +820,10 @@
         return nGlyphs > 0 && !layoutContainsNotdef(layout);
     }
 
-    static jfloat doRunAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
+    static jfloat doRunAdvance(const Paint* paint, Typeface* typeface, const jchar buf[],
             jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
         int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
-        if (offset == count) {
+        if (offset == start + count) {
             return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
                     bufSize, nullptr);
         }
@@ -837,7 +837,7 @@
             jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
             jint contextEnd, jboolean isRtl, jint offset) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
         jfloat result = doRunAdvance(paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, isRtl,
@@ -846,7 +846,7 @@
         return result;
     }
 
-    static jint doOffsetForAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
+    static jint doOffsetForAdvance(const Paint* paint, Typeface* typeface, const jchar buf[],
             jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) {
         int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
         std::unique_ptr<float[]> advancesArray(new float[count]);
@@ -859,7 +859,7 @@
             jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
             jint contextEnd, jboolean isRtl, jfloat advance) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
         jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, isRtl, advance);
diff --git a/core/jni/android/graphics/Paint.h b/core/jni/android/graphics/Paint.h
deleted file mode 100644
index cb6e622..0000000
--- a/core/jni/android/graphics/Paint.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GRAPHICS_PAINT_H_
-#define ANDROID_GRAPHICS_PAINT_H_
-
-#include <SkPaint.h>
-#include <string>
-
-#include <minikin/FontFamily.h>
-
-namespace android {
-
-class Paint : public SkPaint {
-public:
-    Paint();
-    Paint(const Paint& paint);
-    ~Paint();
-
-    Paint& operator=(const Paint& other);
-
-    friend bool operator==(const Paint& a, const Paint& b);
-    friend bool operator!=(const Paint& a, const Paint& b) {
-        return !(a == b);
-    }
-
-    void setLetterSpacing(float letterSpacing) {
-        mLetterSpacing = letterSpacing;
-    }
-
-    float getLetterSpacing() const {
-        return mLetterSpacing;
-    }
-
-    void setFontFeatureSettings(const std::string &fontFeatureSettings) {
-        mFontFeatureSettings = fontFeatureSettings;
-    }
-
-    std::string getFontFeatureSettings() const {
-        return mFontFeatureSettings;
-    }
-
-    void setMinikinLangListId(uint32_t minikinLangListId) {
-        mMinikinLangListId = minikinLangListId;
-    }
-
-    uint32_t getMinikinLangListId() const {
-        return mMinikinLangListId;
-    }
-
-    void setFontVariant(FontVariant variant) {
-        mFontVariant = variant;
-    }
-
-    FontVariant getFontVariant() const {
-        return mFontVariant;
-    }
-
-    void setHyphenEdit(uint32_t hyphen) {
-        mHyphenEdit = hyphen;
-    }
-
-    uint32_t getHyphenEdit() const {
-        return mHyphenEdit;
-    }
-
-private:
-    float mLetterSpacing = 0;
-    std::string mFontFeatureSettings;
-    uint32_t mMinikinLangListId;
-    FontVariant mFontVariant;
-    uint32_t mHyphenEdit = 0;
-};
-
-}  // namespace android
-
-#endif // ANDROID_GRAPHICS_PAINT_H_
diff --git a/core/jni/android/graphics/PaintImpl.cpp b/core/jni/android/graphics/PaintImpl.cpp
deleted file mode 100644
index bd513ae..0000000
--- a/core/jni/android/graphics/PaintImpl.cpp
+++ /dev/null
@@ -1,58 +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.
- */
-
-#include "Paint.h"
-#include <SkPaint.h>
-
-#define LOG_TAG "Paint"
-#include <cutils/log.h>
-
-namespace android {
-
-Paint::Paint() :
-        SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
-        mFontVariant(VARIANT_DEFAULT) {
-}
-
-Paint::Paint(const Paint& paint) : SkPaint(paint),
-        mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings),
-        mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant),
-        mHyphenEdit(paint.mHyphenEdit) {
-}
-
-Paint::~Paint() {
-}
-
-Paint& Paint::operator=(const Paint& other) {
-    SkPaint::operator=(other);
-    mLetterSpacing = other.mLetterSpacing;
-    mFontFeatureSettings = other.mFontFeatureSettings;
-    mMinikinLangListId = other.mMinikinLangListId;
-    mFontVariant = other.mFontVariant;
-    mHyphenEdit = other.mHyphenEdit;
-    return *this;
-}
-
-bool operator==(const Paint& a, const Paint& b) {
-    return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b)
-            && a.mLetterSpacing == b.mLetterSpacing
-            && a.mFontFeatureSettings == b.mFontFeatureSettings
-            && a.mMinikinLangListId == b.mMinikinLangListId
-            && a.mFontVariant == b.mFontVariant
-            && a.mHyphenEdit == b.mHyphenEdit;
-}
-
-}
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 2998c99..ab393f2 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -232,12 +232,6 @@
         obj->addPath(*src, *matrix);
     }
 
-    static void offset__FFPath(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy, jlong dstHandle) {
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
-        obj->offset(dx, dy, dst);
-    }
-
     static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->offset(dx, dy);
@@ -508,7 +502,6 @@
     {"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
     {"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
     {"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
-    {"native_offset","(JFFJ)V", (void*) SkPathGlue::offset__FFPath},
     {"native_offset","(JFF)V", (void*) SkPathGlue::offset__FF},
     {"native_setLastPoint","(JFF)V", (void*) SkPathGlue::setLastPoint},
     {"native_transform","(JJJ)V", (void*) SkPathGlue::transform__MatrixPath},
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index 6e83f1b..07e14a2 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include "Canvas.h"
 #include "Picture.h"
 #include "SkStream.h"
 
 #include <memory>
+#include <hwui/Canvas.h>
 
 namespace android {
 
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
index a106ecf..3784f0d 100644
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -22,10 +22,11 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include "Paint.h"
 #include "SkLayerRasterizer.h"
 #include "core_jni_helpers.h"
 
+#include <hwui/Paint.h>
+
 // Rasterizer.java holds a pointer (jlong) to this guy
 class NativeRasterizer {
 public:
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 2018e76..6e9830e 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -65,12 +65,12 @@
     EGLContext ctx = eglGetCurrentContext();
 
     if (dpy == EGL_NO_DISPLAY) {
-        ALOGE("isProtectedSurface: invalid current EGLDisplay");
+        ALOGI("isProtectedSurface: invalid current EGLDisplay");
         return false;
     }
 
     if (ctx == EGL_NO_CONTEXT) {
-        ALOGE("isProtectedSurface: invalid current EGLContext");
+        ALOGI("isProtectedSurface: invalid current EGLContext");
         return false;
     }
 
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e97b768..9a53cad 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -20,50 +20,57 @@
 #include "GraphicsJNI.h"
 #include "ScopedPrimitiveArray.h"
 #include "SkTypeface.h"
-#include "TypefaceImpl.h"
 #include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/AssetManager.h>
+#include <hwui/Typeface.h>
 
 using namespace android;
 
 static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
-    TypefaceImpl* family = reinterpret_cast<TypefaceImpl*>(familyHandle);
-    TypefaceImpl* face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)style);
+    Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
+    Typeface* face = Typeface::createFromTypeface(family, (SkTypeface::Style)style);
     // TODO: the following logic shouldn't be necessary, the above should always succeed.
     // Try to find the closest matching font, using the standard heuristic
     if (NULL == face) {
-        face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
+        face = Typeface::createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
     }
     for (int i = 0; NULL == face && i < 4; i++) {
-        face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)i);
+        face = Typeface::createFromTypeface(family, (SkTypeface::Style)i);
     }
     return reinterpret_cast<jlong>(face);
 }
 
 static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
-    TypefaceImpl* family = reinterpret_cast<TypefaceImpl*>(familyHandle);
-    TypefaceImpl* face = TypefaceImpl_createWeightAlias(family, weight);
+    Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
+    Typeface* face = Typeface::createWeightAlias(family, weight);
     return reinterpret_cast<jlong>(face);
 }
 
 static void Typeface_unref(JNIEnv* env, jobject obj, jlong faceHandle) {
-    TypefaceImpl* face = reinterpret_cast<TypefaceImpl*>(faceHandle);
-    TypefaceImpl_unref(face);
+    Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
+    if (face != NULL) {
+        face->unref();
+    }
 }
 
 static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) {
-    TypefaceImpl* face = reinterpret_cast<TypefaceImpl*>(faceHandle);
-    return TypefaceImpl_getStyle(face);
+    Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
+    return face->fSkiaStyle;
 }
 
 static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
     ScopedLongArrayRO families(env, familyArray);
-    return reinterpret_cast<jlong>(TypefaceImpl_createFromFamilies(families.get(), families.size()));
+    std::vector<FontFamily*> familyVec;
+    for (size_t i = 0; i < families.size(); i++) {
+        FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
+        familyVec.push_back(family);
+    }
+    return reinterpret_cast<jlong>(Typeface::createFromFamilies(familyVec));
 }
 
 static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
-    TypefaceImpl* face = reinterpret_cast<TypefaceImpl*>(faceHandle);
-    return TypefaceImpl_setDefault(face);
+    Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
+    return Typeface::setDefault(face);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
deleted file mode 100644
index da56290..0000000
--- a/core/jni/android/graphics/TypefaceImpl.cpp
+++ /dev/null
@@ -1,180 +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.
- */
-
-/**
- * This is the implementation of the Typeface object. Historically, it has
- * just been SkTypeface, but we are migrating to Minikin. For the time
- * being, that choice is hidden under the USE_MINIKIN compile-time flag.
- */
-
-#define LOG_TAG "TypefaceImpl"
-
-#include "jni.h"  // for jlong, remove when being passed proper type
-
-#include "SkTypeface.h"
-
-#include <vector>
-#include <minikin/FontCollection.h>
-#include <minikin/FontFamily.h>
-#include <minikin/Layout.h>
-#include "SkPaint.h"
-#include "MinikinSkia.h"
-
-#include "TypefaceImpl.h"
-#include "Utils.h"
-
-namespace android {
-
-// Resolve the 1..9 weight based on base weight and bold flag
-static void resolveStyle(TypefaceImpl* typeface) {
-    int weight = typeface->fBaseWeight / 100;
-    if (typeface->fSkiaStyle & SkTypeface::kBold) {
-        weight += 3;
-    }
-    if (weight > 9) {
-        weight = 9;
-    }
-    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
-    typeface->fStyle = FontStyle(weight, italic);
-}
-
-TypefaceImpl* gDefaultTypeface = NULL;
-pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
-
-// This installs a default typeface (from a hardcoded path) that allows
-// layouts to work (not crash on null pointer) before the default
-// typeface is set.
-// TODO: investigate why layouts are being created before Typeface.java
-// class initialization.
-static FontCollection *makeFontCollection() {
-    std::vector<FontFamily *>typefaces;
-    const char *fns[] = {
-        "/system/fonts/Roboto-Regular.ttf",
-    };
-
-    FontFamily *family = new FontFamily();
-    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
-        const char *fn = fns[i];
-        ALOGD("makeFontCollection adding %s", fn);
-        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
-        if (skFace != NULL) {
-            MinikinFont *font = new MinikinFontSkia(skFace);
-            family->addFont(font);
-            font->Unref();
-        } else {
-            ALOGE("failed to create font %s", fn);
-        }
-    }
-    typefaces.push_back(family);
-
-    FontCollection *result = new FontCollection(typefaces);
-    family->Unref();
-    return result;
-}
-
-static void getDefaultTypefaceOnce() {
-    Layout::init();
-    if (gDefaultTypeface == NULL) {
-        // We expect the client to set a default typeface, but provide a
-        // default so we can make progress before that happens.
-        gDefaultTypeface = new TypefaceImpl;
-        gDefaultTypeface->fFontCollection = makeFontCollection();
-        gDefaultTypeface->fSkiaStyle = SkTypeface::kNormal;
-        gDefaultTypeface->fBaseWeight = 400;
-        resolveStyle(gDefaultTypeface);
-    }
-}
-
-TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
-    if (src == NULL) {
-        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
-        return gDefaultTypeface;
-    } else {
-        return src;
-    }
-}
-
-TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
-    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
-    TypefaceImpl* result = new TypefaceImpl;
-    if (result != 0) {
-        result->fFontCollection = resolvedFace->fFontCollection;
-        result->fFontCollection->Ref();
-        result->fSkiaStyle = style;
-        result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
-    }
-    return result;
-}
-
-TypefaceImpl* TypefaceImpl_createWeightAlias(TypefaceImpl* src, int weight) {
-    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
-    TypefaceImpl* result = new TypefaceImpl;
-    if (result != 0) {
-        result->fFontCollection = resolvedFace->fFontCollection;
-        result->fFontCollection->Ref();
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
-        result->fBaseWeight = weight;
-        resolveStyle(result);
-    }
-    return result;
-}
-
-TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
-    std::vector<FontFamily *>familyVec;
-    for (size_t i = 0; i < size; i++) {
-        FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
-        familyVec.push_back(family);
-    }
-    TypefaceImpl* result = new TypefaceImpl;
-    result->fFontCollection = new FontCollection(familyVec);
-    if (size == 0) {
-        ALOGW("createFromFamilies creating empty collection");
-        result->fSkiaStyle = SkTypeface::kNormal;
-    } else {
-        const FontStyle defaultStyle;
-        FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
-        MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
-        if (mf != NULL) {
-            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
-            // TODO: probably better to query more precise style from family, will be important
-            // when we open up API to access 100..900 weights
-            result->fSkiaStyle = skTypeface->style();
-        } else {
-            result->fSkiaStyle = SkTypeface::kNormal;
-        }
-    }
-    result->fBaseWeight = 400;
-    resolveStyle(result);
-    return result;
-}
-
-void TypefaceImpl_unref(TypefaceImpl* face) {
-    if (face != NULL) {
-        face->fFontCollection->Unref();
-    }
-    delete face;
-}
-
-int TypefaceImpl_getStyle(TypefaceImpl* face) {
-    return face->fSkiaStyle;
-}
-
-void TypefaceImpl_setDefault(TypefaceImpl* face) {
-    gDefaultTypeface = face;
-}
-
-}
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
deleted file mode 100644
index 4b14917..0000000
--- a/core/jni/android/graphics/TypefaceImpl.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
-#define _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
-
-#include "jni.h"  // for jlong, eventually remove
-#include "SkTypeface.h"
-#include <androidfw/AssetManager.h>
-
-#include <minikin/FontCollection.h>
-
-namespace android {
-
-struct TypefaceImpl {
-    FontCollection *fFontCollection;
-
-    // style used for constructing and querying Typeface objects
-    SkTypeface::Style fSkiaStyle;
-    // base weight in CSS-style units, 100..900
-    int fBaseWeight;
-
-    // resolved style actually used for rendering
-    FontStyle fStyle;
-};
-
-// Note: it would be cleaner if the following functions were member
-// functions (static or otherwise) of the TypefaceImpl class. However,
-// that can't be easily accommodated in the case where TypefaceImpl
-// is just a pointer to SkTypeface, in the non-USE_MINIKIN case.
-// TODO: when #ifdef USE_MINIKIN is removed, move to member functions.
-
-TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src);
-
-TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style);
-
-TypefaceImpl* TypefaceImpl_createWeightAlias(TypefaceImpl* src, int baseweight);
-
-// When we remove the USE_MINIKIN ifdef, probably a good idea to move the casting
-// (from jlong to FontFamily*) to the caller in Typeface.cpp.
-TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size);
-
-void TypefaceImpl_unref(TypefaceImpl* face);
-
-int TypefaceImpl_getStyle(TypefaceImpl* face);
-
-void TypefaceImpl_setDefault(TypefaceImpl* face);
-
-}
-
-#endif  // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 4f9ce8b..5fa445e 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -116,3 +116,7 @@
     }
     return NULL;
 }
+
+bool android::isSeekable(int descriptor) {
+    return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
+}
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index c0b9410..d1a74a0 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -68,6 +68,10 @@
 
 jobject nullObjectReturn(const char msg[]);
 
+/** Check if the file descriptor is seekable.
+ */
+bool isSeekable(int descriptor);
+
 }; // namespace android
 
 #endif  // _ANDROID_GRAPHICS_UTILS_H_
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
index 7441acc..78975a4f 100644
--- a/core/jni/android/graphics/Xfermode.cpp
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -15,34 +15,20 @@
  */
 
 #include "jni.h"
-#include "GraphicsJNI.h"
+//#include "GraphicsJNI.h"
 #include "core_jni_helpers.h"
 
-#include "AvoidXfermode.h"
-#include "SkPixelXorXfermode.h"
+#include <SkXfermode.h>
 
 namespace android {
 
 class SkXfermodeGlue {
 public:
-
     static void finalizer(JNIEnv* env, jobject, jlong objHandle)
     {
         SkXfermode* obj = reinterpret_cast<SkXfermode *>(objHandle);
         SkSafeUnref(obj);
     }
-    
-    static jlong avoid_create(JNIEnv* env, jobject, jint opColor,
-                                jint tolerance, jint modeHandle)
-    {
-        AvoidXfermode::Mode mode = static_cast<AvoidXfermode::Mode>(modeHandle);
-        return reinterpret_cast<jlong>(AvoidXfermode::Create(opColor, tolerance, mode));
-    }
-
-    static jlong pixelxor_create(JNIEnv* env, jobject, jint opColor)
-    {
-        return reinterpret_cast<jlong>(SkPixelXorXfermode::Create(opColor));
-    }
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -51,24 +37,9 @@
     {"finalizer", "(J)V", (void*) SkXfermodeGlue::finalizer}
 };
 
-static const JNINativeMethod gAvoidMethods[] = {
-    {"nativeCreate", "(III)J", (void*) SkXfermodeGlue::avoid_create}
-};
-
-static const JNINativeMethod gPixelXorMethods[] = {
-    {"nativeCreate", "(I)J", (void*) SkXfermodeGlue::pixelxor_create}
-};
-
 int register_android_graphics_Xfermode(JNIEnv* env) {
     android::RegisterMethodsOrDie(env, "android/graphics/Xfermode", gXfermodeMethods,
                                   NELEM(gXfermodeMethods));
-    android::RegisterMethodsOrDie(env, "android/graphics/Xfermode", gXfermodeMethods,
-                                  NELEM(gXfermodeMethods));
-    android::RegisterMethodsOrDie(env, "android/graphics/AvoidXfermode", gAvoidMethods,
-                                  NELEM(gAvoidMethods));
-    android::RegisterMethodsOrDie(env, "android/graphics/PixelXorXfermode", gPixelXorMethods,
-                                  NELEM(gPixelXorMethods));
-
     return 0;
 }
 
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index 7a13fe4..88e37e5 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -19,7 +19,6 @@
 #include "core_jni_helpers.h"
 #include <vector>
 
-#include "Canvas.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 
 #include "SkDocument.h"
@@ -28,6 +27,8 @@
 #include "SkStream.h"
 #include "SkRect.h"
 
+#include <hwui/Canvas.h>
+
 namespace android {
 
 struct PageRecord {
@@ -94,8 +95,6 @@
             SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
                     &(page->mContentRect));
 
-            canvas->clipRect(page->mContentRect);
-            canvas->translate(page->mContentRect.left(), page->mContentRect.top());
             canvas->drawPicture(page->mPicture);
 
             document->endPage();
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 0177635..2c840bd 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -196,7 +196,7 @@
         return;
     }
 
-    CFX_AffineMatrix matrix;
+    CFX_Matrix matrix;
 
     SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr);
 
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 6ddfacf..27f3493 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -205,11 +205,10 @@
     clip.bottom = destBottom;
     fxgeDevice->SetClip_Rect(&clip);
 
-    CPDF_RenderContext* pageContext = new CPDF_RenderContext;
+    CPDF_RenderContext* pageContext = new CPDF_RenderContext(pPage);
     pContext->m_pContext = pageContext;
-    pageContext->Create(pPage);
 
-    CFX_AffineMatrix matrix;
+    CFX_Matrix matrix;
     if (!transform) {
         pPage->GetDisplayMatrix(matrix, destLeft, destTop, destRight - destLeft,
                 destBottom - destTop, 0);
@@ -232,8 +231,8 @@
     }
     pageContext->AppendObjectList(pPage, &matrix);
 
-    pContext->m_pRenderer = new CPDF_ProgressiveRenderer;
-    pContext->m_pRenderer->Start(pageContext, fxgeDevice, renderOptions, NULL);
+    pContext->m_pRenderer = new CPDF_ProgressiveRenderer(pageContext, fxgeDevice, renderOptions);
+    pContext->m_pRenderer->Start(NULL);
 
     fxgeDevice->RestoreState();
 
diff --git a/core/jni/android_app_Activity.cpp b/core/jni/android_app_Activity.cpp
new file mode 100644
index 0000000..56f4f01
--- /dev/null
+++ b/core/jni/android_app_Activity.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#include <poll.h>
+
+#include <string>
+
+#include "core_jni_helpers.h"
+
+extern "C" void android_dlwarning(void*, void (*)(void*, const char*));
+
+namespace android
+{
+
+static jstring getDlWarning_native(JNIEnv* env, jobject) {
+    std::string msg;
+    android_dlwarning(&msg, [](void* obj, const char* msg) {
+        if (msg != nullptr) {
+            *reinterpret_cast<std::string*>(obj) = msg;
+        }
+    });
+
+    return msg.empty() ? nullptr : env->NewStringUTF(msg.c_str());
+}
+
+static const JNINativeMethod g_methods[] = {
+    { "getDlWarning",
+        "()Ljava/lang/String;",
+        reinterpret_cast<void*>(getDlWarning_native) },
+};
+
+static const char* const kActivityPathName = "android/app/Activity";
+
+int register_android_app_Activity(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, kActivityPathName, g_methods, NELEM(g_methods));
+}
+
+} // namespace android
diff --git a/core/jni/android_app_ApplicationLoaders.cpp b/core/jni/android_app_ApplicationLoaders.cpp
new file mode 100644
index 0000000..89f22eb
--- /dev/null
+++ b/core/jni/android_app_ApplicationLoaders.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <string>
+
+#include "nativeloader/native_loader.h"
+
+#include "core_jni_helpers.h"
+
+
+static jstring createClassloaderNamespace_native(JNIEnv* env,
+                                              jobject clazz,
+                                              jobject classLoader,
+                                              jint targetSdkVersion,
+                                              jstring librarySearchPath,
+                                              jstring libraryPermittedPath,
+                                              jboolean isShared) {
+    return android::CreateClassLoaderNamespace(env, targetSdkVersion,
+                                               classLoader, isShared == JNI_TRUE,
+                                               librarySearchPath, libraryPermittedPath);
+}
+
+static const JNINativeMethod g_methods[] = {
+    { "createClassloaderNamespace",
+      "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;",
+      reinterpret_cast<void*>(createClassloaderNamespace_native) },
+};
+
+static const char* const kApplicationLoadersPathName = "android/app/ApplicationLoaders";
+
+namespace android
+{
+
+int register_android_app_ApplicationLoaders(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, kApplicationLoadersPathName, g_methods, NELEM(g_methods));
+}
+
+} // namespace android
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 88a56d2..6431b94 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -259,8 +259,7 @@
 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
         jobject messageQueue, jstring internalDataDir, jstring obbDir,
         jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,
-        jbyteArray savedState, jobject classLoader, jstring libraryPath,
-        jstring isolationPath) {
+        jbyteArray savedState, jobject classLoader, jstring libraryPath) {
     if (kLogTrace) {
         ALOGD("loadNativeCode_native");
     }
@@ -269,8 +268,7 @@
     std::unique_ptr<NativeCode> code;
     bool needNativeBridge = false;
 
-    void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader,
-                                     false, libraryPath, isolationPath);
+    void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader, libraryPath);
     if (handle == NULL) {
         if (NativeBridgeIsSupported(pathStr)) {
             handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
@@ -656,7 +654,7 @@
 
 static const JNINativeMethod g_methods[] = {
     { "loadNativeCode",
-        "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[BLjava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)J",
+        "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[BLjava/lang/ClassLoader;Ljava/lang/String;)J",
         (void*)loadNativeCode_native },
     { "getDlError", "()Ljava/lang/String;", (void*) getDlError_native },
     { "unloadNativeCode", "(J)V", (void*)unloadNativeCode_native },
diff --git a/core/jni/android_app_admin_SecurityLog.cpp b/core/jni/android_app_admin_SecurityLog.cpp
new file mode 100644
index 0000000..da47c4c
--- /dev/null
+++ b/core/jni/android_app_admin_SecurityLog.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <fcntl.h>
+
+#include "JNIHelp.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "log/logger.h"
+
+// The size of the tag number comes out of the payload size.
+#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
+
+namespace android {
+
+static jclass gCollectionClass;
+static jmethodID gCollectionAddID;
+
+static jclass gEventClass;
+static jmethodID gEventInitID;
+
+static jclass gIntegerClass;
+static jfieldID gIntegerValueID;
+
+static jclass gLongClass;
+static jfieldID gLongValueID;
+
+static jclass gFloatClass;
+static jfieldID gFloatValueID;
+
+static jclass gStringClass;
+
+
+static jboolean android_app_admin_SecurityLog_isLoggingEnabled(JNIEnv* env,
+                                                    jobject /* clazz */) {
+    return (bool)__android_log_security();
+}
+
+static jint android_app_admin_SecurityLog_writeEvent_String(JNIEnv* env,
+                                                    jobject /* clazz */,
+                                                    jint tag, jstring value) {
+    uint8_t buf[MAX_EVENT_PAYLOAD];
+
+    // Don't throw NPE -- I feel like it's sort of mean for a logging function
+    // to be all crashy if you pass in NULL -- but make the NULL value explicit.
+    const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
+    uint32_t len = strlen(str);
+    size_t max = sizeof(buf) - sizeof(len) - 2;  // Type byte, final newline
+    if (len > max) len = max;
+
+    buf[0] = EVENT_TYPE_STRING;
+    memcpy(&buf[1], &len, sizeof(len));
+    memcpy(&buf[1 + sizeof(len)], str, len);
+    buf[1 + sizeof(len) + len] = '\n';
+
+    if (value != NULL) env->ReleaseStringUTFChars(value, str);
+    return __android_log_security_bwrite(tag, buf, 2 + sizeof(len) + len);
+}
+
+static jint android_app_admin_SecurityLog_writeEvent_Array(JNIEnv* env, jobject clazz,
+                                                   jint tag, jobjectArray value) {
+    if (value == NULL) {
+        return android_app_admin_SecurityLog_writeEvent_String(env, clazz, tag, NULL);
+    }
+
+    uint8_t buf[MAX_EVENT_PAYLOAD];
+    const size_t max = sizeof(buf) - 1;  // leave room for final newline
+    size_t pos = 2;  // Save room for type tag & array count
+
+    jsize copied = 0, num = env->GetArrayLength(value);
+    for (; copied < num && copied < 255; ++copied) {
+        jobject item = env->GetObjectArrayElement(value, copied);
+        if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
+            if (pos + 1 + sizeof(jint) > max) break;
+            const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
+            jint len = strlen(str);
+            if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
+            buf[pos++] = EVENT_TYPE_STRING;
+            memcpy(&buf[pos], &len, sizeof(len));
+            memcpy(&buf[pos + sizeof(len)], str, len);
+            pos += sizeof(len) + len;
+            if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
+        } else if (env->IsInstanceOf(item, gIntegerClass)) {
+            jint intVal = env->GetIntField(item, gIntegerValueID);
+            if (pos + 1 + sizeof(intVal) > max) break;
+            buf[pos++] = EVENT_TYPE_INT;
+            memcpy(&buf[pos], &intVal, sizeof(intVal));
+            pos += sizeof(intVal);
+        } else if (env->IsInstanceOf(item, gLongClass)) {
+            jlong longVal = env->GetLongField(item, gLongValueID);
+            if (pos + 1 + sizeof(longVal) > max) break;
+            buf[pos++] = EVENT_TYPE_LONG;
+            memcpy(&buf[pos], &longVal, sizeof(longVal));
+            pos += sizeof(longVal);
+        } else if (env->IsInstanceOf(item, gFloatClass)) {
+            jfloat floatVal = env->GetFloatField(item, gFloatValueID);
+            if (pos + 1 + sizeof(floatVal) > max) break;
+            buf[pos++] = EVENT_TYPE_FLOAT;
+            memcpy(&buf[pos], &floatVal, sizeof(floatVal));
+            pos += sizeof(floatVal);
+        } else {
+            jniThrowException(env,
+                    "java/lang/IllegalArgumentException",
+                    "Invalid payload item type");
+            return -1;
+        }
+        env->DeleteLocalRef(item);
+    }
+
+    buf[0] = EVENT_TYPE_LIST;
+    buf[1] = copied;
+    buf[pos++] = '\n';
+    return __android_log_security_bwrite(tag, buf, pos);
+}
+
+static void readEvents(JNIEnv* env, int loggerMode, jlong startTime, jobject out) {
+    struct logger_list *logger_list;
+    if (startTime) {
+        logger_list = android_logger_list_alloc_time(loggerMode,
+                log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0);
+    } else {
+        logger_list = android_logger_list_alloc(loggerMode, 0, 0);
+    }
+    if (!logger_list) {
+        jniThrowIOException(env, errno);
+        return;
+    }
+
+    if (!android_logger_open(logger_list, LOG_ID_SECURITY)) {
+        jniThrowIOException(env, errno);
+        android_logger_list_free(logger_list);
+        return;
+    }
+
+    while (1) {
+        log_msg log_msg;
+        int ret = android_logger_list_read(logger_list, &log_msg);
+
+        if (ret == 0) {
+            break;
+        }
+        if (ret < 0) {
+            if (ret == -EINTR) {
+                continue;
+            }
+            if (ret == -EINVAL) {
+                jniThrowException(env, "java/io/IOException", "Event too short");
+            } else if (ret != -EAGAIN) {
+                jniThrowIOException(env, -ret);  // Will throw on return
+            }
+            break;
+        }
+
+        if (log_msg.id() != LOG_ID_SECURITY) {
+            continue;
+        }
+
+        jsize len = ret;
+        jbyteArray array = env->NewByteArray(len);
+        if (array == NULL) {
+            break;
+        }
+
+        jbyte *bytes = env->GetByteArrayElements(array, NULL);
+        memcpy(bytes, log_msg.buf, len);
+        env->ReleaseByteArrayElements(array, bytes, 0);
+
+        jobject event = env->NewObject(gEventClass, gEventInitID, array);
+        if (event == NULL) {
+            break;
+        }
+
+        env->CallBooleanMethod(out, gCollectionAddID, event);
+        env->DeleteLocalRef(event);
+        env->DeleteLocalRef(array);
+    }
+
+    android_logger_list_close(logger_list);
+}
+
+static void android_app_admin_SecurityLog_readEvents(JNIEnv* env, jobject /* clazz */,
+                                             jobject out) {
+
+    if (out == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, out);
+}
+
+static void android_app_admin_SecurityLog_readEventsSince(JNIEnv* env, jobject /* clazz */,
+                                             jlong timestamp,
+                                             jobject out) {
+
+    if (out == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, timestamp, out);
+}
+
+static void android_app_admin_SecurityLog_readPreviousEvents(JNIEnv* env, jobject /* clazz */,
+                                             jobject out) {
+
+    if (out == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_PSTORE, 0, out);
+}
+
+static void android_app_admin_SecurityLog_readEventsOnWrapping(JNIEnv* env, jobject /* clazz */,
+                                             jlong timestamp,
+                                             jobject out) {
+    if (out == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_WRAP, timestamp, out);
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gRegisterMethods[] = {
+    /* name, signature, funcPtr */
+    { "isLoggingEnabled",
+      "()Z",
+      (void*) android_app_admin_SecurityLog_isLoggingEnabled
+    },
+    { "writeEvent",
+      "(ILjava/lang/String;)I",
+      (void*) android_app_admin_SecurityLog_writeEvent_String
+    },
+    { "writeEvent",
+      "(I[Ljava/lang/Object;)I",
+      (void*) android_app_admin_SecurityLog_writeEvent_Array
+    },
+    { "readEvents",
+      "(Ljava/util/Collection;)V",
+      (void*) android_app_admin_SecurityLog_readEvents
+    },
+    { "readEventsSince",
+      "(JLjava/util/Collection;)V",
+      (void*) android_app_admin_SecurityLog_readEventsSince
+    },
+    { "readPreviousEvents",
+      "(Ljava/util/Collection;)V",
+      (void*) android_app_admin_SecurityLog_readPreviousEvents
+    },
+    { "readEventsOnWrapping",
+      "(JLjava/util/Collection;)V",
+      (void*) android_app_admin_SecurityLog_readEventsOnWrapping
+    },
+};
+
+static struct { const char *name; jclass *clazz; } gClasses[] = {
+    { "android/app/admin/SecurityLog$SecurityEvent", &gEventClass },
+    { "java/lang/Integer", &gIntegerClass },
+    { "java/lang/Long", &gLongClass },
+    { "java/lang/Float", &gFloatClass },
+    { "java/lang/String", &gStringClass },
+    { "java/util/Collection", &gCollectionClass },
+};
+
+static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
+    { &gIntegerClass, "value", "I", &gIntegerValueID },
+    { &gLongClass, "value", "J", &gLongValueID },
+    { &gFloatClass, "value", "F", &gFloatValueID },
+};
+
+static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
+    { &gEventClass, "<init>", "([B)V", &gEventInitID },
+    { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
+};
+
+int register_android_app_admin_SecurityLog(JNIEnv* env) {
+    for (int i = 0; i < NELEM(gClasses); ++i) {
+        jclass clazz = FindClassOrDie(env, gClasses[i].name);
+        *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz);
+    }
+
+    for (int i = 0; i < NELEM(gFields); ++i) {
+        *gFields[i].id = GetFieldIDOrDie(env,
+                *gFields[i].c, gFields[i].name, gFields[i].ft);
+    }
+
+    for (int i = 0; i < NELEM(gMethods); ++i) {
+        *gMethods[i].id = GetMethodIDOrDie(env,
+                *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
+    }
+
+    return RegisterMethodsOrDie(
+            env,
+            "android/app/admin/SecurityLog",
+            gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index cf73316..ded4dac 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -19,15 +19,14 @@
 #include "core_jni_helpers.h"
 
 #include <androidfw/ResourceTypes.h>
-#include <Canvas.h>
+#include <hwui/Canvas.h>
+#include <hwui/Paint.h>
+#include <hwui/Typeface.h>
+#include <minikin/Layout.h>
 
 #include "Bitmap.h"
 #include "SkDrawFilter.h"
 #include "SkGraphics.h"
-#include "Paint.h"
-#include "TypefaceImpl.h"
-
-#include "MinikinUtils.h"
 
 namespace android {
 
@@ -475,111 +474,13 @@
                                              vertA.ptr(), colorA.ptr(), paint);
 }
 
-static void simplifyPaint(int color, SkPaint* paint) {
-    paint->setColor(color);
-    paint->setShader(nullptr);
-    paint->setColorFilter(nullptr);
-    paint->setLooper(nullptr);
-    paint->setStrokeWidth(4 + 0.04 * paint->getTextSize());
-    paint->setStrokeJoin(SkPaint::kRound_Join);
-    paint->setLooper(nullptr);
-}
-
-class DrawTextFunctor {
-public:
-    DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
-                    const SkPaint& paint, float x, float y, MinikinRect& bounds,
-                    float totalAdvance)
-            : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint),
-              x(x), y(y), bounds(bounds), totalAdvance(totalAdvance) { }
-
-    void operator()(size_t start, size_t end) {
-        if (canvas->drawTextAbsolutePos()) {
-            for (size_t i = start; i < end; i++) {
-                glyphs[i] = layout.getGlyphId(i);
-                pos[2 * i] = x + layout.getX(i);
-                pos[2 * i + 1] = y + layout.getY(i);
-            }
-        } else {
-            for (size_t i = start; i < end; i++) {
-                glyphs[i] = layout.getGlyphId(i);
-                pos[2 * i] = layout.getX(i);
-                pos[2 * i + 1] = layout.getY(i);
-            }
-        }
-
-        size_t glyphCount = end - start;
-
-        if (CC_UNLIKELY(canvas->isHighContrastText() && paint.getAlpha() != 0)) {
-            // high contrast draw path
-            int color = paint.getColor();
-            int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color);
-            bool darken = channelSum < (128 * 3);
-
-            // outline
-            SkPaint outlinePaint(paint);
-            simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint);
-            outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style);
-            canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, outlinePaint, x, y,
-                    bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance);
-
-            // inner
-            SkPaint innerPaint(paint);
-            simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
-            innerPaint.setStyle(SkPaint::kFill_Style);
-            canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, innerPaint, x, y,
-                    bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance);
-        } else {
-            // standard draw path
-            canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, paint, x, y,
-                             bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom,
-                             totalAdvance);
-        }
-    }
-private:
-    const Layout& layout;
-    Canvas* canvas;
-    uint16_t* glyphs;
-    float* pos;
-    const SkPaint& paint;
-    float x;
-    float y;
-    MinikinRect& bounds;
-    float totalAdvance;
-};
-
-void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int contextCount,
-             float x, float y, int bidiFlags, const Paint& origPaint, TypefaceImpl* typeface) {
-    // minikin may modify the original paint
-    Paint paint(origPaint);
-
-    Layout layout;
-    MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
-
-    size_t nGlyphs = layout.nGlyphs();
-    std::unique_ptr<uint16_t[]> glyphs(new uint16_t[nGlyphs]);
-    std::unique_ptr<float[]> pos(new float[nGlyphs * 2]);
-
-    x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
-
-    MinikinRect bounds;
-    layout.getBounds(&bounds);
-    if (!canvas->drawTextAbsolutePos()) {
-        bounds.offset(x, y);
-    }
-
-    DrawTextFunctor f(layout, canvas, glyphs.get(), pos.get(),
-            paint, x, y, bounds, layout.getAdvance());
-    MinikinUtils::forFontRun(layout, &paint, f);
-}
-
 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
                           jlong paintHandle, jlong typefaceHandle) {
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
     jchar* jchars = env->GetCharArrayElements(text, NULL);
-    drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y,
+    get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
                                        bidiFlags, *paint, typeface);
     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
 }
@@ -588,10 +489,10 @@
                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
                            jlong paintHandle, jlong typefaceHandle) {
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
     const int count = end - start;
     const jchar* jchars = env->GetStringChars(text, NULL);
-    drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y,
+    get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
                                        bidiFlags, *paint, typeface);
     env->ReleaseStringChars(text, jchars);
 }
@@ -600,11 +501,11 @@
                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
                              jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
     const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
     jchar* jchars = env->GetCharArrayElements(text, NULL);
-    drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count,
+    get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
                                        contextCount, x, y, bidiFlags, *paint, typeface);
     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
 }
@@ -614,70 +515,28 @@
                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
                               jlong typefaceHandle) {
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
     int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
     jint count = end - start;
     jint contextCount = contextEnd - contextStart;
     const jchar* jchars = env->GetStringChars(text, NULL);
-    drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count,
+    get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
                                        contextCount, x, y, bidiFlags, *paint, typeface);
     env->ReleaseStringChars(text, jchars);
 }
 
-class DrawTextOnPathFunctor {
-public:
-    DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
-                float vOffset, const Paint& paint, const SkPath& path)
-            : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
-                paint(paint), path(path) {
-    }
-    void operator()(size_t start, size_t end) {
-        uint16_t glyphs[1];
-        for (size_t i = start; i < end; i++) {
-            glyphs[0] = layout.getGlyphId(i);
-            float x = hOffset + layout.getX(i);
-            float y = vOffset + layout.getY(i);
-            canvas->drawTextOnPath(glyphs, 1, path, x, y, paint);
-        }
-    }
-private:
-    const Layout& layout;
-    Canvas* canvas;
-    float hOffset;
-    float vOffset;
-    const Paint& paint;
-    const SkPath& path;
-};
-
-static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags,
-                           const SkPath& path, float hOffset, float vOffset,
-                           const Paint& paint, TypefaceImpl* typeface) {
-    Paint paintCopy(paint);
-    Layout layout;
-    MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
-    hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
-
-    // Set align to left for drawing, as we don't want individual
-    // glyphs centered or right-aligned; the offset above takes
-    // care of all alignment.
-    paintCopy.setTextAlign(Paint::kLeft_Align);
-
-    DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path);
-    MinikinUtils::forFontRun(layout, &paintCopy, f);
-}
-
 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
                                 jfloat vOffset, jint bidiFlags, jlong paintHandle,
                                 jlong typefaceHandle) {
     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
     jchar* jchars = env->GetCharArrayElements(text, NULL);
 
-    drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path,
+    get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path,
                    hOffset, vOffset, *paint, typeface);
 
     env->ReleaseCharArrayElements(text, jchars, 0);
@@ -688,12 +547,12 @@
                                  jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
     const jchar* jchars = env->GetStringChars(text, NULL);
     int count = env->GetStringLength(text);
 
-    drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path,
+    get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path,
                    hOffset, vOffset, *paint, typeface);
 
     env->ReleaseStringChars(text, jchars);
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index 14badb7..4b2a72d 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -175,13 +175,13 @@
     {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
     {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
     {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData},
-    {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start},
-    {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse},
+    {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
+    {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
     {"nEnd", "!(J)V", (void*)end},
     {"nReset", "!(J)V", (void*)reset},
 };
 
-const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator";
+const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT";
 int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) {
     gVectorDrawableAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName);
     gVectorDrawableAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env,
@@ -189,7 +189,7 @@
 
     gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
             env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished",
-            "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V");
+            "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V");
     return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable",
             gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 7314fbc..b04293e 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -14,55 +14,28 @@
  * limitations under the License.
  */
 
-#include "jni.h"
 #include "GraphicsJNI.h"
+#include "jni.h"
 #include "core_jni_helpers.h"
-#include "log/log.h"
 
-#include "Paint.h"
+#include "PathParser.h"
 #include "VectorDrawable.h"
 
+#include <hwui/Paint.h>
+
 namespace android {
 using namespace uirenderer;
 using namespace uirenderer::VectorDrawable;
 
+/**
+ * VectorDrawable's pre-draw construction.
+ */
 static jlong createTree(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
     VectorDrawable::Tree* tree = new VectorDrawable::Tree(rootGroup);
     return reinterpret_cast<jlong>(tree);
 }
 
-static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
-        jfloat viewportWidth, jfloat viewportHeight) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    tree->setViewportSize(viewportWidth, viewportHeight);
-}
-
-static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    return tree->setRootAlpha(alpha);
-}
-
-static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    return tree->getRootAlpha();
-}
-
-static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    tree->setAllowCaching(allowCaching);
-}
-
-static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
-        jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    SkRect rect;
-    GraphicsJNI::jrect_to_rect(env, jrect, &rect);
-    SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
-    tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
-}
-
 static jlong createEmptyFullPath(JNIEnv*, jobject) {
     VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath();
     return reinterpret_cast<jlong>(newPath);
@@ -75,46 +48,6 @@
     return reinterpret_cast<jlong>(newPath);
 }
 
-static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
-        jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
-        jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
-        jint strokeLineCap, jint strokeLineJoin) {
-    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->updateProperties(strokeWidth, strokeColor, strokeAlpha, fillColor, fillAlpha,
-            trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit, strokeLineCap,
-            strokeLineJoin);
-}
-
-static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
-    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
-    SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
-    path->setFillGradient(fillShader);
-}
-
-static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
-    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
-    SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
-    path->setStrokeGradient(strokeShader);
-}
-
-static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
-        jbyteArray outProperties, jint length) {
-    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    int8_t pathProperties[length];
-    bool success = fullPath->getProperties(pathProperties, length);
-    env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
-    return success;
-}
-
-static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
-        jfloatArray outProperties, jint length) {
-    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    float groupProperties[length];
-    bool success = group->getProperties(groupProperties, length);
-    env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
-    return success;
-}
-
 static jlong createEmptyClipPath(JNIEnv*, jobject) {
     VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath();
     return reinterpret_cast<jlong>(newPath);
@@ -145,180 +78,265 @@
     env->ReleaseStringUTFChars(nameStr, nodeName);
 }
 
-static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
-        jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
-    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->updateLocalMatrix(rotate, pivotX, pivotY, scaleX, scaleY, translateX, translateY);
-}
-
 static void addChild(JNIEnv*, jobject, jlong groupPtr, jlong childPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
     VectorDrawable::Node* child = reinterpret_cast<VectorDrawable::Node*>(childPtr);
     group->addChild(child);
 }
 
+static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    tree->setAllowCaching(allowCaching);
+}
+
+/**
+ * Draw
+ */
+static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
+        jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    SkRect rect;
+    GraphicsJNI::jrect_to_rect(env, jrect, &rect);
+    SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+    tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
+}
+
+/**
+ * Setters and getters for updating staging properties that can happen both pre-draw and post draw.
+ */
+static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
+        jfloat viewportWidth, jfloat viewportHeight) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    tree->mutateStagingProperties()->setViewportSize(viewportWidth, viewportHeight);
+}
+
+static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    return tree->mutateStagingProperties()->setRootAlpha(alpha);
+}
+
+static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    return tree->stagingProperties()->getRootAlpha();
+}
+
+static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
+        jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
+        jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
+        jint strokeLineCap, jint strokeLineJoin, jint fillType) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->mutateStagingProperties()->updateProperties(strokeWidth, strokeColor, strokeAlpha,
+            fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit,
+            strokeLineCap, strokeLineJoin, fillType);
+}
+
+static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
+    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+    SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+    path->mutateStagingProperties()->setFillGradient(fillShader);
+}
+
+static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
+    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+    SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+    path->mutateStagingProperties()->setStrokeGradient(strokeShader);
+}
+
+static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
+        jbyteArray outProperties, jint length) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    int8_t pathProperties[length];
+    bool success = fullPath->stagingProperties()->copyProperties(pathProperties, length);
+    env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
+    return success;
+}
+
+static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
+        jfloatArray outProperties, jint length) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    float groupProperties[length];
+    bool success = group->stagingProperties()->copyProperties(groupProperties, length);
+    env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
+    return success;
+}
+
+static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
+        jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->mutateStagingProperties()->updateProperties(rotate, pivotX, pivotY, scaleX, scaleY,
+            translateX, translateY);
+}
+
 static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
         jint stringLength) {
     VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
     const char* pathString = env->GetStringUTFChars(inputStr, NULL);
-    path->setPath(pathString, stringLength);
+
+    PathParser::ParseResult result;
+    PathData data;
+    PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+    path->mutateStagingProperties()->setData(data);
     env->ReleaseStringUTFChars(inputStr, pathString);
 }
 
+/**
+ * Setters and getters that should only be called from animation thread for animation purpose.
+ */
 static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getRotation();
+    return group->stagingProperties()->getRotation();
 }
 
 static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setRotation(rotation);
+    group->mutateStagingProperties()->setRotation(rotation);
 }
 
 static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getPivotX();
+    return group->stagingProperties()->getPivotX();
 }
 
 static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setPivotX(pivotX);
+    group->mutateStagingProperties()->setPivotX(pivotX);
 }
 
 static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getPivotY();
+    return group->stagingProperties()->getPivotY();
 }
 
 static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setPivotY(pivotY);
+    group->mutateStagingProperties()->setPivotY(pivotY);
 }
 
 static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getScaleX();
+    return group->stagingProperties()->getScaleX();
 }
 
 static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setScaleX(scaleX);
+    group->mutateStagingProperties()->setScaleX(scaleX);
 }
 
 static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getScaleY();
+    return group->stagingProperties()->getScaleY();
 }
 
 static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setScaleY(scaleY);
+    group->mutateStagingProperties()->setScaleY(scaleY);
 }
 
 static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getTranslateX();
+    return group->stagingProperties()->getTranslateX();
 }
 
 static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setTranslateX(translateX);
+    group->mutateStagingProperties()->setTranslateX(translateX);
 }
 
 static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getTranslateY();
+    return group->stagingProperties()->getTranslateY();
 }
 
 static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setTranslateY(translateY);
+    group->mutateStagingProperties()->setTranslateY(translateY);
 }
 
 static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
     VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
     PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
-    path->setPathData(*pathData);
+    path->mutateStagingProperties()->setData(*pathData);
 }
 
 static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getStrokeWidth();
+    return fullPath->stagingProperties()->getStrokeWidth();
 }
 
 static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setStrokeWidth(strokeWidth);
+    fullPath->mutateStagingProperties()->setStrokeWidth(strokeWidth);
 }
 
 static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getStrokeColor();
+    return fullPath->stagingProperties()->getStrokeColor();
 }
 
 static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setStrokeColor(strokeColor);
+    fullPath->mutateStagingProperties()->setStrokeColor(strokeColor);
 }
 
 static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getStrokeAlpha();
+    return fullPath->stagingProperties()->getStrokeAlpha();
 }
 
 static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setStrokeAlpha(strokeAlpha);
+    fullPath->mutateStagingProperties()->setStrokeAlpha(strokeAlpha);
 }
 
 static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getFillColor();
+    return fullPath->stagingProperties()->getFillColor();
 }
 
 static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setFillColor(fillColor);
+    fullPath->mutateStagingProperties()->setFillColor(fillColor);
 }
 
 static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getFillAlpha();
+    return fullPath->stagingProperties()->getFillAlpha();
 }
 
 static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setFillAlpha(fillAlpha);
+    fullPath->mutateStagingProperties()->setFillAlpha(fillAlpha);
 }
 
 static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getTrimPathStart();
+    return fullPath->stagingProperties()->getTrimPathStart();
 }
 
 static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setTrimPathStart(trimPathStart);
+    fullPath->mutateStagingProperties()->setTrimPathStart(trimPathStart);
 }
 
 static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getTrimPathEnd();
+    return fullPath->stagingProperties()->getTrimPathEnd();
 }
 
 static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setTrimPathEnd(trimPathEnd);
+    fullPath->mutateStagingProperties()->setTrimPathEnd(trimPathEnd);
 }
 
 static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getTrimPathOffset();
+    return fullPath->stagingProperties()->getTrimPathOffset();
 }
 
 static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setTrimPathOffset(trimPathOffset);
+    fullPath->mutateStagingProperties()->setTrimPathOffset(trimPathOffset);
 }
 
 static const JNINativeMethod gMethods[] = {
@@ -331,7 +349,7 @@
         {"nDraw", "(JJJLandroid/graphics/Rect;ZZ)V", (void*)draw},
         {"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
         {"nCreateFullPath", "!(J)J", (void*)createFullPath},
-        {"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+        {"nUpdateFullPathProperties", "!(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
         {"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
         {"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
         {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 806fcc3..91f003d 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -567,6 +567,45 @@
 
     // save context in opaque field
     env->SetLongField(thiz, fields.context, (jlong)context.get());
+
+    // Update default display orientation in case the sensor is reverse-landscape
+    CameraInfo cameraInfo;
+    status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
+    if (rc != NO_ERROR) {
+        return rc;
+    }
+    int defaultOrientation = 0;
+    switch (cameraInfo.orientation) {
+        case 0:
+            break;
+        case 90:
+            if (cameraInfo.facing == CAMERA_FACING_FRONT) {
+                defaultOrientation = 180;
+            }
+            break;
+        case 180:
+            defaultOrientation = 180;
+            break;
+        case 270:
+            if (cameraInfo.facing != CAMERA_FACING_FRONT) {
+                defaultOrientation = 180;
+            }
+            break;
+        default:
+            ALOGE("Unexpected camera orientation %d!", cameraInfo.orientation);
+            break;
+    }
+    if (defaultOrientation != 0) {
+        ALOGV("Setting default display orientation to %d", defaultOrientation);
+        rc = camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION,
+                defaultOrientation, 0);
+        if (rc != NO_ERROR) {
+            ALOGE("Unable to update default orientation: %s (%d)",
+                    strerror(-rc), rc);
+            return rc;
+        }
+    }
+
     return NO_ERROR;
 }
 
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e39bb1c..90f407f 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -36,15 +36,17 @@
 
 #include "core_jni_helpers.h"
 
-static struct {
+namespace {
+
+using namespace android;
+
+struct {
     jclass clazz;
     jmethodID dispatchSensorEvent;
     jmethodID dispatchFlushCompleteEvent;
     jmethodID dispatchAdditionalInfoEvent;
 } gBaseEventQueueClassInfo;
 
-namespace android {
-
 struct SensorOffsets
 {
     jclass      clazz;
@@ -72,9 +74,9 @@
 } gListOffsets;
 
 /*
- * The method below are not thread-safe and not intended to be
+ * nativeClassInit is not inteneded to be thread-safe. It should be called before other native...
+ * functions (except nativeCreate).
  */
-
 static void
 nativeClassInit (JNIEnv *_env, jclass _this)
 {
@@ -494,9 +496,7 @@
             (void*)nativeInjectSensorData },
 };
 
-}; // namespace android
-
-using namespace android;
+} //unnamed namespace
 
 int register_android_hardware_SensorManager(JNIEnv *env)
 {
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 7930027..f37fd78 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -33,9 +33,9 @@
 #include "core_jni_helpers.h"
 #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
 
+#include <android/hardware/ICameraService.h>
 #include <binder/IServiceManager.h>
 #include <camera/CameraMetadata.h>
-#include <camera/ICameraService.h>
 #include <camera/VendorTagDescriptor.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/ScopedPrimitiveArray.h>
@@ -906,32 +906,35 @@
 
 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
     const String16 NAME("media.camera");
-    sp<ICameraService> cameraService;
+    sp<hardware::ICameraService> cameraService;
     status_t err = getService(NAME, /*out*/&cameraService);
 
     if (err != OK) {
         ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
                 strerror(-err), err);
-        return err;
+        return hardware::ICameraService::ERROR_DISCONNECTED;
     }
 
-    sp<VendorTagDescriptor> desc;
-    err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
 
-    if (err == -EOPNOTSUPP) {
-        ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
+    if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
+        // No camera module available, not an error on devices with no cameras
         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
-
         return OK;
-    } else if (err != OK) {
-        ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
-                __FUNCTION__, strerror(-err), err);
-        return err;
+    } else if (!res.isOk()) {
+        VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+        ALOGE("%s: Failed to setup vendor tag descriptors: %s",
+                __FUNCTION__, res.toString8().string());
+        return res.serviceSpecificErrorCode();
     }
 
     err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
 
-    return err;
+    if (err != OK) {
+        return hardware::ICameraService::ERROR_INVALID_OPERATION;
+    }
+    return OK;
 }
 
 } // extern "C"
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index cb0abb6..d80d8f2 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #define LOG_TAG "DngCreator_JNI"
 #include <inttypes.h>
 #include <string.h>
@@ -80,6 +80,13 @@
         return nullptr; \
     }
 
+#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \
+    if (expr) { \
+        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
+        return nullptr; \
+    }
+
 
 #define ANDROID_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
 
@@ -195,8 +202,8 @@
 NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
         mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
         mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
-        mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false),
-        mDescriptionSet(false), mCaptureTimeSet(false) {}
+        mThumbnailHeight(0), mOrientation(TAG_ORIENTATION_UNKNOWN), mThumbnailSet(false),
+        mGpsSet(false), mDescriptionSet(false), mCaptureTimeSet(false) {}
 
 NativeContext::~NativeContext() {}
 
@@ -1096,7 +1103,7 @@
 
     {
         // Set orientation
-        uint16_t orientation = 1; // Normal
+        uint16_t orientation = TAG_ORIENTATION_NORMAL;
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
                 env, TAG_ORIENTATION, writer);
     }
@@ -1138,12 +1145,27 @@
     }
 
     {
-        // Set blacklevel tags
+        // Set blacklevel tags, using dynamic black level if available
         camera_metadata_entry entry =
-                characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
-        BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer);
-        const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
-        BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel,
+                results.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+        uint32_t blackLevelRational[8] = {0};
+        if (entry.count != 0) {
+            BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer);
+            for (size_t i = 0; i < entry.count; i++) {
+                blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.f[i] * 100);
+                blackLevelRational[i * 2 + 1] = 100;
+            }
+        } else {
+            // Fall back to static black level which is guaranteed
+            entry = characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+            BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer);
+            for (size_t i = 0; i < entry.count; i++) {
+                blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.i32[i]);
+                blackLevelRational[i * 2 + 1] = 1;
+            }
+
+        }
+        BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, 4, blackLevelRational,
                 TIFF_IFD_0), env, TAG_BLACKLEVEL, writer);
 
         uint16_t repeatDim[2] = {2, 2};
@@ -1770,6 +1792,8 @@
 
     {
         // Set up orientation tags.
+        // Note: There's only one orientation field for the whole file, in IFD0
+        // The main image and any thumbnails therefore have the same orientation.
         uint16_t orientation = nativeContext->getOrientation();
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
                 env, TAG_ORIENTATION, writer);
@@ -1851,7 +1875,6 @@
         }
 
         Vector<uint16_t> tagsToMove;
-        tagsToMove.add(TAG_ORIENTATION);
         tagsToMove.add(TAG_NEWSUBFILETYPE);
         tagsToMove.add(TAG_ACTIVEAREA);
         tagsToMove.add(TAG_BITSPERSAMPLE);
@@ -1882,12 +1905,6 @@
             return nullptr;
         }
 
-        // Make sure both IFDs get the same orientation tag
-        sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1);
-        if (orientEntry.get() != nullptr) {
-            writer->addEntry(orientEntry, TIFF_IFD_0);
-        }
-
         // Setup thumbnail tags
 
         {
@@ -1913,8 +1930,10 @@
 
         {
             // Set bits per sample
-            uint16_t bits = BITS_PER_RGB_SAMPLE;
-            BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0),
+            uint16_t bits[SAMPLES_PER_RGB_PIXEL];
+            for (int i = 0; i < SAMPLES_PER_RGB_PIXEL; i++) bits[i] = BITS_PER_RGB_SAMPLE;
+            BAIL_IF_INVALID_RET_NULL_SP(
+                    writer->addEntry(TAG_BITSPERSAMPLE, SAMPLES_PER_RGB_PIXEL, bits, TIFF_IFD_0),
                     env, TAG_BITSPERSAMPLE, writer);
         }
 
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index f1ea7ec..80f9d57 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -29,6 +29,7 @@
 
 #include <gui/Surface.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
 #include <ui/GraphicBuffer.h>
 #include <system/window.h>
 #include <hardware/camera3.h>
@@ -93,27 +94,17 @@
             cStep, yStride, cStride);
 }
 
-static status_t configureSurface(const sp<ANativeWindow>& anw,
-                                 int32_t width,
-                                 int32_t height,
-                                 int32_t pixelFmt,
-                                 int32_t maxBufferSlack) {
+static status_t connectSurface(const sp<Surface>& surface, int32_t maxBufferSlack) {
     status_t err = NO_ERROR;
-    err = native_window_set_buffers_dimensions(anw.get(), width, height);
-    if (err != NO_ERROR) {
-        ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__,
+
+    err = surface->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/NULL);
+    if (err != OK) {
+        ALOGE("%s: Unable to connect to surface, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
         return err;
     }
 
-    err = native_window_set_buffers_format(anw.get(), pixelFmt);
-    if (err != NO_ERROR) {
-        ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__,
-                strerror(-err), err);
-        return err;
-    }
-
-    err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
+    err = native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
@@ -121,19 +112,17 @@
     }
 
     int minUndequeuedBuffers;
-    err = anw.get()->query(anw.get(),
-            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-            &minUndequeuedBuffers);
+    err = static_cast<ANativeWindow*>(surface.get())->query(surface.get(),
+            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
                 __FUNCTION__, strerror(-err), err);
         return err;
     }
 
-    ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__,
-          maxBufferSlack + 1 + minUndequeuedBuffers,
-          width, height, pixelFmt);
-    err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
+    ALOGV("%s: Setting buffer count to %d", __FUNCTION__,
+            maxBufferSlack + 1 + minUndequeuedBuffers);
+    err = native_window_set_buffer_count(surface.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
@@ -509,6 +498,26 @@
     return usage;
 }
 
+static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz,
+          jobject surface) {
+    ALOGV("nativeDisconnectSurface");
+    if (surface == nullptr) return NO_ERROR;
+
+    sp<ANativeWindow> anw;
+    if ((anw = getNativeWindow(env, surface)) == NULL) {
+        ALOGV("Buffer queue has already been abandoned.");
+        return NO_ERROR;
+    }
+
+    status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA);
+    if(err != NO_ERROR) {
+        jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+            "Error while disconnecting surface");
+        return err;
+    }
+    return NO_ERROR;
+}
+
 static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
         jobject surfaceTexture, jintArray dimens) {
     ALOGV("nativeDetectTextureDimens");
@@ -540,15 +549,14 @@
     return NO_ERROR;
 }
 
-static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
-        jint width, jint height, jint pixelFormat) {
-    ALOGV("nativeConfigureSurface");
-    sp<ANativeWindow> anw;
-    if ((anw = getNativeWindow(env, surface)) == NULL) {
-        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+static jint LegacyCameraDevice_nativeConnectSurface(JNIEnv* env, jobject thiz, jobject surface) {
+    ALOGV("nativeConnectSurface");
+    sp<Surface> s;
+    if ((s = getSurface(env, surface)) == NULL) {
+        ALOGE("%s: Could not retrieve surface.", __FUNCTION__);
         return BAD_VALUE;
     }
-    status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK);
+    status_t err = connectSurface(s, CAMERA_DEVICE_BUFFER_SLACK);
     if (err != NO_ERROR) {
         ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
         return err;
@@ -740,9 +748,9 @@
     { "nativeDetectSurfaceDimens",
     "(Landroid/view/Surface;[I)I",
     (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
-    { "nativeConfigureSurface",
-    "(Landroid/view/Surface;III)I",
-    (void *)LegacyCameraDevice_nativeConfigureSurface },
+    { "nativeConnectSurface",
+    "(Landroid/view/Surface;)I",
+    (void *)LegacyCameraDevice_nativeConnectSurface },
     { "nativeProduceFrame",
     "(Landroid/view/Surface;[BIII)I",
     (void *)LegacyCameraDevice_nativeProduceFrame },
@@ -773,6 +781,9 @@
     { "nativeSetScalingMode",
     "(Landroid/view/Surface;I)I",
     (void *)LegacyCameraDevice_nativeSetScalingMode },
+    { "nativeDisconnectSurface",
+    "(Landroid/view/Surface;)I",
+    (void *)LegacyCameraDevice_nativeDisconnectSurface },
 };
 
 // Get all the required offsets in java class and register native functions
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
new file mode 100644
index 0000000..80ae550
--- /dev/null
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -0,0 +1,690 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "context_hub.h"
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "ContextHubService"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <map>
+#include <queue>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cutils/log.h>
+
+#include "JNIHelp.h"
+#include "core_jni_helpers.h"
+
+static constexpr int OS_APP_ID=-1;
+
+static constexpr int MIN_APP_ID=1;
+static constexpr int MAX_APP_ID=128;
+
+static constexpr size_t MSG_HEADER_SIZE=4;
+static constexpr int HEADER_FIELD_MSG_TYPE=0;
+//static constexpr int HEADER_FIELD_MSG_VERSION=1;
+static constexpr int HEADER_FIELD_HUB_HANDLE=2;
+static constexpr int HEADER_FIELD_APP_INSTANCE=3;
+
+
+namespace android {
+
+namespace {
+
+/*
+ * Finds the length of a statically-sized array using template trickery that
+ * also prevents it from being applied to the wrong type.
+ */
+template <typename T, size_t N>
+constexpr size_t array_length(T (&)[N]) { return N; }
+
+struct jniInfo_s {
+    JavaVM *vm;
+    jclass contextHubInfoClass;
+    jclass contextHubServiceClass;
+    jclass memoryRegionsClass;
+
+    jobject jContextHubService;
+
+    jmethodID msgReceiptCallBack;
+
+    jmethodID contextHubInfoCtor;
+    jmethodID contextHubInfoSetId;
+    jmethodID contextHubInfoSetName;
+    jmethodID contextHubInfoSetVendor;
+    jmethodID contextHubInfoSetToolchain;
+    jmethodID contextHubInfoSetPlatformVersion;
+    jmethodID contextHubInfoSetStaticSwVersion;
+    jmethodID contextHubInfoSetToolchainVersion;
+    jmethodID contextHubInfoSetPeakMips;
+    jmethodID contextHubInfoSetStoppedPowerDrawMw;
+    jmethodID contextHubInfoSetSleepPowerDrawMw;
+    jmethodID contextHubInfoSetPeakPowerDrawMw;
+    jmethodID contextHubInfoSetSupportedSensors;
+    jmethodID contextHubInfoSetMemoryRegions;
+    jmethodID contextHubInfoSetMaxPacketLenBytes;
+
+    jmethodID contextHubServiceMsgReceiptCallback;
+    jmethodID contextHubServiceAddAppInstance;
+};
+
+struct context_hub_info_s {
+    uint32_t *cookies;
+    int numHubs;
+    const struct context_hub_t *hubs;
+    struct context_hub_module_t *contextHubModule;
+};
+
+struct app_instance_info_s {
+    uint32_t hubHandle; // Id of the hub this app is on
+    int instanceId; // systemwide unique instance id - assigned
+    struct hub_app_info appInfo; // returned from the HAL
+    uint64_t truncName; // Possibly truncated name - logging
+};
+
+struct contextHubServiceDb_s {
+    int initialized;
+    context_hub_info_s hubInfo;
+    jniInfo_s jniInfo;
+    std::queue<int> freeIds;
+    std::map<int, app_instance_info_s *> appInstances;
+};
+
+}  // unnamed namespace
+
+static contextHubServiceDb_s db;
+
+int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
+                         void *cookie);
+
+const context_hub_t *get_hub_info(int hubHandle) {
+    if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
+        return &db.hubInfo.hubs[hubHandle];
+    }
+    return nullptr;
+}
+
+static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
+    const context_hub_t *info = get_hub_info(hubHandle);
+
+    if (info) {
+        return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
+    } else {
+        ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+        return -1;
+    }
+}
+
+static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
+    const context_hub_t *info = get_hub_info(hubHandle);
+
+    if (info) {
+        msg->app = info->os_app_name;
+        return 0;
+    } else {
+        ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+        return -1;
+    }
+}
+
+static int get_hub_id_for_hub_handle(int hubHandle) {
+    if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
+      return -1;
+    } else {
+      return db.hubInfo.hubs[hubHandle].hub_id;
+    }
+}
+
+static int get_hub_id_for_app_instance(int id) {
+    if (db.appInstances.find(id) == db.appInstances.end()) {
+        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+        return -1;
+    }
+
+    int hubHandle = db.appInstances[id]->hubHandle;
+
+    return db.hubInfo.hubs[hubHandle].hub_id;
+}
+
+static int set_dest_app(hub_message_t *msg, int id) {
+    if (db.appInstances.find(id) == db.appInstances.end()) {
+        ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id);
+        return -1;
+    }
+
+    msg->app = db.appInstances[id]->appInfo.name;
+    return 0;
+}
+
+static void send_query_for_apps() {
+    hub_message_t msg;
+
+    msg.message_type = CONTEXT_HUB_QUERY_APPS;
+    msg.message_len  = 0;
+
+    for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
+        ALOGD("Sending query for apps to hub %d", i);
+        set_os_app_as_destination(&msg, i);
+        if (send_msg_to_hub(&msg, i) != 0) {
+          ALOGW("Could not query hub %i for apps", i);
+        }
+    }
+}
+
+static int return_id(int id) {
+    // Note : This method is not thread safe.
+    // id returned is guarenteed to be in use
+    db.freeIds.push(id);
+    return 0;
+}
+
+static int generate_id(void) {
+    // Note : This method is not thread safe.
+    int retVal = -1;
+
+    if (!db.freeIds.empty()) {
+        retVal = db.freeIds.front();
+        db.freeIds.pop();
+    }
+
+    return retVal;
+}
+
+int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) {
+    // Not checking if the apps are indeed distinct
+
+    app_instance_info_s *entry;
+    void *appName;
+    hub_app_name_t *name;
+
+    assert(appInfo && appInfo->name && appInfo->name->app_name);
+
+    entry = (app_instance_info_s *) malloc(sizeof(app_instance_info_s));
+    appName = malloc(appInfo->name->app_name_len);
+    name = (hub_app_name_t *) malloc(sizeof(hub_app_name_t));
+
+    int appInstanceHandle = generate_id();
+
+    if (appInstanceHandle < 0 || !appName || !entry || !name) {
+        ALOGE("Cannot find resources to add app instance %d, %p, %p",
+            appInstanceHandle, appName, entry);
+
+        free(appName);
+        free(entry);
+        free(name);
+
+        if (appInstanceHandle >= 0) {
+            return_id(appInstanceHandle);
+        }
+
+        return -1;
+    }
+
+    memcpy(&(entry->appInfo), appInfo, sizeof(entry->appInfo));
+    memcpy(appName, appInfo->name->app_name, appInfo->name->app_name_len);
+    name->app_name = appName;
+    name->app_name_len = appInfo->name->app_name_len;
+    entry->appInfo.name = name;
+    entry->truncName = 0;
+    memcpy(&(entry->truncName), name->app_name,
+           sizeof(entry->truncName) < name->app_name_len ?
+           sizeof(entry->truncName) : name->app_name_len);
+
+    // Not checking for sanity of hubId
+    entry->hubHandle = hubHandle;
+    entry->instanceId = appInstanceHandle;
+    db.appInstances[appInstanceHandle] = entry;
+
+    // Finally - let the service know of this app instance
+    env->CallIntMethod(db.jniInfo.jContextHubService,
+                       db.jniInfo.contextHubServiceAddAppInstance,
+                       hubHandle, entry->instanceId, entry->truncName,
+                       entry->appInfo.version);
+
+    ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
+          " as appInstance %d, original name_length %" PRId32, entry->truncName,
+          entry->hubHandle, appInstanceHandle, name->app_name_len);
+
+    return appInstanceHandle;
+}
+
+int delete_app_instance(int id) {
+    if (db.appInstances.find(id) == db.appInstances.end()) {
+        return -1;
+    }
+
+    return_id(id);
+
+    if (db.appInstances[id]) {
+        // Losing the const cast below. This is intentional.
+        free((void *)db.appInstances[id]->appInfo.name->app_name);
+        free((void *)db.appInstances[id]->appInfo.name);
+        free(db.appInstances[id]);
+        db.appInstances.erase(id);
+    }
+
+    return 0;
+}
+
+
+static void initContextHubService() {
+    int err = 0;
+    db.hubInfo.hubs = nullptr;
+    db.hubInfo.numHubs = 0;
+    int i;
+
+    err = hw_get_module(CONTEXT_HUB_MODULE_ID,
+                        (hw_module_t const**)(&db.hubInfo.contextHubModule));
+
+    if (err) {
+      ALOGE("** Could not load %s module : err %s", CONTEXT_HUB_MODULE_ID,
+            strerror(-err));
+    }
+
+    // Prep for storing app info
+    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
+        db.freeIds.push(i);
+    }
+
+    if (db.hubInfo.contextHubModule) {
+        int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
+                                                                 &db.hubInfo.hubs);
+        ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
+        db.hubInfo.numHubs = retNumHubs;
+
+        if (db.hubInfo.numHubs > 0) {
+            db.hubInfo.numHubs = retNumHubs;
+            db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
+
+            if (!db.hubInfo.cookies) {
+                ALOGW("Ran out of memory allocating cookies, bailing");
+                return;
+            }
+
+            for (i = 0; i < db.hubInfo.numHubs; i++) {
+                db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
+                if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
+                                                                    context_hub_callback,
+                                                                    &db.hubInfo.cookies[i]) == 0) {
+                }
+            }
+        }
+
+        send_query_for_apps();
+    } else {
+        ALOGW("No Context Hub Module present");
+    }
+}
+
+static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) {
+    JNIEnv *env;
+
+    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+      return -1;
+    }
+
+    jbyteArray jmsg = env->NewByteArray(msgLen);
+    jintArray jheader = env->NewIntArray(headerLen);
+
+    env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
+    env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
+
+    return (env->CallIntMethod(db.jniInfo.jContextHubService,
+                          db.jniInfo.contextHubServiceMsgReceiptCallback,
+                          jheader, jmsg) != 0);
+}
+
+int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) {
+    int i;
+    JNIEnv *env;
+    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+            return -1;
+    }
+
+    int numApps = msgLen/sizeof(hub_app_info);
+    hub_app_info *info = (hub_app_info *)malloc(msgLen); // handle possible alignment
+
+    if (!info) {
+        return -1;
+    }
+
+    memcpy(info, msg, msgLen);
+    for (i = 0; i < numApps; i++) {
+        add_app_instance(info, hubHandle, env);
+        info++;
+    }
+
+    free(info);
+
+    return 0;
+}
+
+
+int handle_os_message(uint32_t msgType, uint32_t hubHandle,
+                      char *msg, int msgLen) {
+    int retVal;
+
+    switch(msgType) {
+        case CONTEXT_HUB_APPS_ENABLE:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_APPS_DISABLE:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_LOAD_APP:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_UNLOAD_APP:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_QUERY_APPS:
+            retVal = handle_query_apps_response(msg, msgLen, hubHandle);
+            break;
+
+        case CONTEXT_HUB_QUERY_MEMORY:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_LOAD_OS:
+            retVal = 0;
+            break;
+
+        default:
+            retVal = -1;
+            break;
+
+    }
+
+    return retVal;
+}
+
+static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
+    int *ptr = (int *)cookie;
+
+    if (!ptr || *ptr >= db.hubInfo.numHubs) {
+        return false;
+    }
+
+    if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+int context_hub_callback(uint32_t hubId,
+                         const struct hub_message_t *msg,
+                         void *cookie) {
+    int msgHeader[MSG_HEADER_SIZE];
+
+    if (!msg) {
+        return -1;
+    }
+
+    msgHeader[HEADER_FIELD_MSG_TYPE] = msg->message_type;
+
+    if (!sanity_check_cookie(cookie, hubId)) {
+        ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
+              hubId, cookie);
+
+        return -1;
+    }
+
+    msgHeader[HEADER_FIELD_HUB_HANDLE] = *(uint32_t*)cookie;
+
+    if (msgHeader[HEADER_FIELD_MSG_TYPE] < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE &&
+        msgHeader[HEADER_FIELD_MSG_TYPE] != 0 ) {
+        handle_os_message(msgHeader[HEADER_FIELD_MSG_TYPE],
+                          msgHeader[HEADER_FIELD_HUB_HANDLE],
+                          (char *)msg->message,
+                          msg->message_len);
+    } else {
+        onMessageReceipt(msgHeader, sizeof(msgHeader),
+                         (char *)msg->message, msg->message_len);
+    }
+
+    return 0;
+}
+
+static int init_jni(JNIEnv *env, jobject instance) {
+
+    if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
+        return -1;
+    }
+
+    db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
+
+    db.jniInfo.contextHubInfoClass =
+            env->FindClass("android/hardware/location/ContextHubInfo");
+
+    db.jniInfo.contextHubServiceClass =
+            env->FindClass("android/hardware/location/ContextHubService");
+
+    db.jniInfo.memoryRegionsClass =
+            env->FindClass("android/hardware/location/MemoryRegion");
+
+    db.jniInfo.contextHubInfoCtor =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
+    db.jniInfo.contextHubInfoSetId =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
+    db.jniInfo.contextHubInfoSetName =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
+                                "(Ljava/lang/String;)V");
+
+    db.jniInfo.contextHubInfoSetVendor =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setVendor", "(Ljava/lang/String;)V");
+    db.jniInfo.contextHubInfoSetToolchain =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setToolchain", "(Ljava/lang/String;)V");
+    db.jniInfo.contextHubInfoSetPlatformVersion =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setPlatformVersion", "(I)V");
+    db.jniInfo.contextHubInfoSetStaticSwVersion =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setStaticSwVersion", "(I)V");
+    db.jniInfo.contextHubInfoSetToolchainVersion =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setToolchainVersion", "(I)V");
+    db.jniInfo.contextHubInfoSetPeakMips =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setPeakMips", "(F)V");
+    db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setStoppedPowerDrawMw", "(F)V");
+    db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setSleepPowerDrawMw", "(F)V");
+    db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setPeakPowerDrawMw", "(F)V");
+    db.jniInfo.contextHubInfoSetSupportedSensors =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setSupportedSensors", "([I)V");
+    db.jniInfo.contextHubInfoSetMemoryRegions =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
+    db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
+             env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setMaxPacketLenBytes", "(I)V");
+
+
+    db.jniInfo.contextHubServiceMsgReceiptCallback =
+            env->GetMethodID(db.jniInfo.contextHubServiceClass, "onMessageReceipt",
+                               "([I[B)I");
+    db.jniInfo.contextHubInfoSetName =
+            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
+            "(Ljava/lang/String;)V");
+
+    db.jniInfo.contextHubServiceAddAppInstance =
+                 env->GetMethodID(db.jniInfo.contextHubServiceClass,
+                                    "addAppInstance", "(IIJI)I");
+
+
+
+    return 0;
+}
+
+static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t *hub) {
+    jstring jstrBuf;
+    jintArray jintBuf;
+    jobjectArray jmemBuf;
+
+    int dummyConnectedSensors[] = {1, 2, 3, 4, 5};
+
+    jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
+                                  db.jniInfo.contextHubInfoCtor);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
+
+    jstrBuf = env->NewStringUTF(hub->name);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
+
+    jstrBuf = env->NewStringUTF(hub->vendor);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
+
+    jstrBuf = env->NewStringUTF(hub->toolchain);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
+
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
+                        hub->stopped_power_draw_mw);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
+                        hub->sleep_power_draw_mw);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
+                        hub->peak_power_draw_mw);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
+                        hub->max_supported_msg_len);
+
+
+    // TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors);
+    // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
+    //                               hub->connected_sensors);
+    jintBuf = env->NewIntArray(array_length(dummyConnectedSensors));
+    env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
+
+    // We are not getting the memory regions from the CH Hal - change this when it is available
+    jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
+    // Note the zero size above. We do not need to set any elements
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
+
+
+    return jHub;
+}
+
+static jobjectArray nativeInitialize(JNIEnv *env, jobject instance)
+{
+    jobject hub;
+    jobjectArray retArray;
+
+    if (init_jni(env, instance) < 0) {
+        return nullptr;
+    }
+
+    initContextHubService();
+
+    if (db.hubInfo.numHubs > 1) {
+      ALOGW("Clamping the number of hubs to 1");
+      db.hubInfo.numHubs = 1;
+    }
+
+    retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
+
+    for(int i = 0; i < db.hubInfo.numHubs; i++) {
+        hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
+        env->SetObjectArrayElement(retArray, i, hub);
+    }
+
+    return retArray;
+}
+
+static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
+                              jbyteArray data_) {
+    jint retVal = -1; // Default to failure
+
+    jint *header = env->GetIntArrayElements(header_, 0);
+    unsigned int numHeaderElements = env->GetArrayLength(header_);
+    jbyte *data = env->GetByteArrayElements(data_, 0);
+    int dataBufferLength = env->GetArrayLength(data_);
+
+
+    if (numHeaderElements >= MSG_HEADER_SIZE) {
+        int setAddressSuccess;
+        int hubId;
+        hub_message_t msg;
+
+        if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
+            setAddressSuccess = (set_os_app_as_destination(&msg, header[HEADER_FIELD_HUB_HANDLE]) == 0);
+            hubId = get_hub_id_for_hub_handle(header[HEADER_FIELD_HUB_HANDLE]);
+        } else {
+            setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
+            hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
+        }
+
+        if (setAddressSuccess && hubId >= 0) {
+            msg.message_type = header[HEADER_FIELD_MSG_TYPE];
+            msg.message_len = dataBufferLength;
+            msg.message = data;
+            retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
+        } else {
+          ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
+                header[HEADER_FIELD_APP_INSTANCE],
+                header[HEADER_FIELD_HUB_HANDLE],
+                setAddressSuccess);
+        }
+    } else {
+        ALOGD("Malformed header len");
+    }
+
+    env->ReleaseIntArrayElements(header_, header, 0);
+    env->ReleaseByteArrayElements(data_, data, 0);
+
+    return retVal;
+}
+
+//--------------------------------------------------------------------------------------------------
+//
+static const JNINativeMethod gContextHubServiceMethods[] = {
+    {"nativeInitialize",
+             "()[Landroid/hardware/location/ContextHubInfo;",
+             (void*)nativeInitialize },
+    {"nativeSendMessage",
+            "([I[B)I",
+            (void*)nativeSendMessage }
+};
+
+}//namespace android
+
+using namespace android;
+
+int register_android_hardware_location_ContextHubService(JNIEnv *env)
+{
+    RegisterMethodsOrDie(env, "android/hardware/location/ContextHubService",
+            gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
+
+    return 0;
+}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d0326f1..1bc4285 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -180,54 +180,15 @@
 // ----------------------------------------------------------------------------
 static jint
 android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jobject jaa, jint sampleRateInHertz, jint channelMask, jint channelIndexMask,
-        jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
+        jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
+        jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName,
+        jlong nativeRecordInJavaObj)
 {
     //ALOGV(">> Entering android_media_AudioRecord_setup");
-    //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
-    //     sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes);
-
-    if (jaa == 0) {
-        ALOGE("Error creating AudioRecord: invalid audio attributes");
-        return (jint) AUDIO_JAVA_ERROR;
-    }
-
-    // channel index mask takes priority over channel position masks.
-    if (channelIndexMask) {
-        // Java channel index masks need the representation bits set.
-        channelMask = audio_channel_mask_from_representation_and_bits(
-                AUDIO_CHANNEL_REPRESENTATION_INDEX,
-                channelIndexMask);
-    }
-    // Java channel position masks map directly to the native definition
-
-    if (!audio_is_input_channel(channelMask)) {
-        ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
-        return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
-    }
-    uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
-
-    // compare the format against the Java constants
-    audio_format_t format = audioFormatToNative(audioFormat);
-    if (format == AUDIO_FORMAT_INVALID) {
-        ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
-        return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
-    }
-
-    size_t bytesPerSample = audio_bytes_per_sample(format);
-
-    if (buffSizeInBytes == 0) {
-         ALOGE("Error creating AudioRecord: frameCount is 0.");
-        return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
-    }
-    size_t frameSize = channelCount * bytesPerSample;
-    size_t frameCount = buffSizeInBytes / frameSize;
-
-    jclass clazz = env->GetObjectClass(thiz);
-    if (clazz == NULL) {
-        ALOGE("Can't find %s when setting up callback.", kClassPathName);
-        return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
-    }
+    //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d "
+    //     "nativeRecordInJavaObj=0x%llX",
+    //     sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes, nativeRecordInJavaObj);
+    audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
 
     if (jSession == NULL) {
         ALOGE("Error creating AudioRecord: invalid session ID pointer");
@@ -239,59 +200,136 @@
         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
         return (jint) AUDIO_JAVA_ERROR;
     }
-    int sessionId = nSession[0];
+    audio_session_t sessionId = (audio_session_t) nSession[0];
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
-    ScopedUtfChars opPackageNameStr(env, opPackageName);
-
-    // create an uninitialized AudioRecord object
-    sp<AudioRecord> lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
-
     audio_attributes_t *paa = NULL;
-    // read the AudioAttributes values
-    paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-    const jstring jtags =
-            (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
-    const char* tags = env->GetStringUTFChars(jtags, NULL);
-    // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
-    strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-    env->ReleaseStringUTFChars(jtags, tags);
-    paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
-    paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
-    ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
+    sp<AudioRecord> lpRecorder = 0;
+    audiorecord_callback_cookie *lpCallbackData = NULL;
 
-    audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
-    if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
-        flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == NULL) {
+        ALOGE("Can't find %s when setting up callback.", kClassPathName);
+        return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
     }
-    // create the callback information:
-    // this data will be passed with every AudioRecord callback
-    audiorecord_callback_cookie *lpCallbackData = new audiorecord_callback_cookie;
-    lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
-    // we use a weak reference so the AudioRecord object can be garbage collected.
-    lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
-    lpCallbackData->busy = false;
 
-    const status_t status = lpRecorder->set(paa->source,
-        sampleRateInHertz,
-        format,        // word length, PCM
-        channelMask,
-        frameCount,
-        recorderCallback,// callback_t
-        lpCallbackData,// void* user
-        0,             // notificationFrames,
-        true,          // threadCanCallJava
-        sessionId,
-        AudioRecord::TRANSFER_DEFAULT,
-        flags,
-        -1, -1,        // default uid, pid
-        paa);
+    // if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
+    if (nativeRecordInJavaObj == 0) {
+        if (jaa == 0) {
+            ALOGE("Error creating AudioRecord: invalid audio attributes");
+            return (jint) AUDIO_JAVA_ERROR;
+        }
 
-    if (status != NO_ERROR) {
-        ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
-                status);
-        goto native_init_failure;
+        if (jSampleRate == 0) {
+            ALOGE("Error creating AudioRecord: invalid sample rates");
+            return (jint) AUDIO_JAVA_ERROR;
+        }
+        jint elements[1];
+        env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
+        int sampleRateInHertz = elements[0];
+
+        // channel index mask takes priority over channel position masks.
+        if (channelIndexMask) {
+            // Java channel index masks need the representation bits set.
+            localChanMask = audio_channel_mask_from_representation_and_bits(
+                    AUDIO_CHANNEL_REPRESENTATION_INDEX,
+                    channelIndexMask);
+        }
+        // Java channel position masks map directly to the native definition
+
+        if (!audio_is_input_channel(localChanMask)) {
+            ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
+            return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
+        }
+        uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
+
+        // compare the format against the Java constants
+        audio_format_t format = audioFormatToNative(audioFormat);
+        if (format == AUDIO_FORMAT_INVALID) {
+            ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
+            return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
+        }
+
+        size_t bytesPerSample = audio_bytes_per_sample(format);
+
+        if (buffSizeInBytes == 0) {
+             ALOGE("Error creating AudioRecord: frameCount is 0.");
+            return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
+        }
+        size_t frameSize = channelCount * bytesPerSample;
+        size_t frameCount = buffSizeInBytes / frameSize;
+
+        ScopedUtfChars opPackageNameStr(env, opPackageName);
+
+        // create an uninitialized AudioRecord object
+        lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
+
+        // read the AudioAttributes values
+        paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+        const jstring jtags =
+                (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
+        const char* tags = env->GetStringUTFChars(jtags, NULL);
+        // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
+        strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+        env->ReleaseStringUTFChars(jtags, tags);
+        paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
+        paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
+        ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
+
+        audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
+        if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
+            flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
+        }
+        // create the callback information:
+        // this data will be passed with every AudioRecord callback
+        lpCallbackData = new audiorecord_callback_cookie;
+        lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
+        // we use a weak reference so the AudioRecord object can be garbage collected.
+        lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
+        lpCallbackData->busy = false;
+
+        const status_t status = lpRecorder->set(paa->source,
+            sampleRateInHertz,
+            format,        // word length, PCM
+            localChanMask,
+            frameCount,
+            recorderCallback,// callback_t
+            lpCallbackData,// void* user
+            0,             // notificationFrames,
+            true,          // threadCanCallJava
+            sessionId,
+            AudioRecord::TRANSFER_DEFAULT,
+            flags,
+            -1, -1,        // default uid, pid
+            paa);
+
+        if (status != NO_ERROR) {
+            ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
+                    status);
+            goto native_init_failure;
+        }
+    } else { // end if nativeRecordInJavaObj == 0)
+        lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
+        // TODO: We need to find out which members of the Java AudioRecord might need to be
+        // initialized from the Native AudioRecord
+        // these are directly returned from getters:
+        //  mSampleRate
+        //  mRecordSource
+        //  mAudioFormat
+        //  mChannelMask
+        //  mChannelCount
+        //  mState (?)
+        //  mRecordingState (?)
+        //  mPreferredDevice
+
+        // create the callback information:
+        // this data will be passed with every AudioRecord callback
+        lpCallbackData = new audiorecord_callback_cookie;
+        lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
+        // we use a weak reference so the AudioRecord object can be garbage collected.
+        lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
+        lpCallbackData->busy = false;
     }
 
     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
@@ -304,6 +342,11 @@
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
+    {
+        const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
+        env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
+    }
+
     {   // scope for the lock
         Mutex::Autolock l(sLock);
         sAudioRecordCallBackCookies.add(lpCallbackData);
@@ -342,7 +385,7 @@
     }
 
     return nativeToJavaStatus(
-            lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession));
+            lpRecorder->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
 }
 
 
@@ -717,8 +760,8 @@
     // name,               signature,  funcPtr
     {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;IIIII[ILjava/lang/String;)I",
-                                       (void *)android_media_AudioRecord_setup},
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
+                                      (void *)android_media_AudioRecord_setup},
     {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
     {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
     {"native_read_in_byte_array",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 80f8a64..7496124 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -109,7 +109,8 @@
     jfieldID    mRule;
     jfieldID    mFormat;
     jfieldID    mRouteFlags;
-    jfieldID    mRegistrationId;
+    jfieldID    mDeviceType;
+    jfieldID    mDeviceAddress;
     jfieldID    mMixType;
     jfieldID    mCallbackFlags;
 } gAudioMixFields;
@@ -320,7 +321,7 @@
 static jint
 android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
 {
-    return AudioSystem::newAudioUniqueId();
+    return AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
 }
 
 static jint
@@ -388,18 +389,47 @@
 }
 
 static void
-android_media_AudioSystem_recording_callback(int event, int session, int source)
+android_media_AudioSystem_recording_callback(int event, audio_session_t session, int source,
+        const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
+        audio_patch_handle_t patchHandle)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     if (env == NULL) {
         return;
     }
+    if (clientConfig == NULL || deviceConfig == NULL) {
+        ALOGE("Unexpected null client/device configurations in recording callback");
+        return;
+    }
 
+    // create an array for 2*3 integers to store the record configurations (client + device)
+    //                 plus 1 integer for the patch handle
+    const int REC_PARAM_SIZE = 7;
+    jintArray recParamArray = env->NewIntArray(REC_PARAM_SIZE);
+    if (recParamArray == NULL) {
+        ALOGE("recording callback: Couldn't allocate int array for configuration data");
+        return;
+    }
+    jint recParamData[REC_PARAM_SIZE];
+    recParamData[0] = (jint) audioFormatFromNative(clientConfig->format);
+    // FIXME this doesn't support index-based masks
+    recParamData[1] = (jint) inChannelMaskFromNative(clientConfig->channel_mask);
+    recParamData[2] = (jint) clientConfig->sample_rate;
+    recParamData[3] = (jint) audioFormatFromNative(deviceConfig->format);
+    // FIXME this doesn't support index-based masks
+    recParamData[4] = (jint) inChannelMaskFromNative(deviceConfig->channel_mask);
+    recParamData[5] = (jint) deviceConfig->sample_rate;
+    recParamData[6] = (jint) patchHandle;
+    env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData);
+
+    // callback into java
     jclass clazz = env->FindClass(kClassPathName);
     env->CallStaticVoidMethod(clazz,
             gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
-            event, session, source);
+            event, session, source, recParamArray);
     env->DeleteLocalRef(clazz);
+
+    env->DeleteLocalRef(recParamArray);
 }
 
 static jint
@@ -1510,7 +1540,7 @@
 static jint
 android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
 {
-    return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId);
+    return (jint) AudioSystem::getAudioHwSyncForSession((audio_session_t) sessionId);
 }
 
 static void
@@ -1532,13 +1562,15 @@
 {
     nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
     nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
+    nAudioMix->mDeviceType = (audio_devices_t)
+            env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType);
 
-    jstring jRegistrationId = (jstring)env->GetObjectField(jAudioMix,
-                                                           gAudioMixFields.mRegistrationId);
-    const char *nRegistrationId = env->GetStringUTFChars(jRegistrationId, NULL);
-    nAudioMix->mRegistrationId = String8(nRegistrationId);
-    env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId);
-    env->DeleteLocalRef(jRegistrationId);
+    jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioMix,
+                                                           gAudioMixFields.mDeviceAddress);
+    const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
+    nAudioMix->mDeviceAddress = String8(nDeviceAddress);
+    env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
+    env->DeleteLocalRef(jDeviceAddress);
 
     nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
 
@@ -1819,7 +1851,7 @@
                     "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
     gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
             GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
-                    "recordingCallbackFromNative", "(III)V");
+                    "recordingCallbackFromNative", "(III[I)V");
 
     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
@@ -1828,7 +1860,8 @@
     gAudioMixFields.mFormat = GetFieldIDOrDie(env, audioMixClass, "mFormat",
                                                 "Landroid/media/AudioFormat;");
     gAudioMixFields.mRouteFlags = GetFieldIDOrDie(env, audioMixClass, "mRouteFlags", "I");
-    gAudioMixFields.mRegistrationId = GetFieldIDOrDie(env, audioMixClass, "mRegistrationId",
+    gAudioMixFields.mDeviceType = GetFieldIDOrDie(env, audioMixClass, "mDeviceSystemType", "I");
+    gAudioMixFields.mDeviceAddress = GetFieldIDOrDie(env, audioMixClass, "mDeviceAddress",
                                                       "Ljava/lang/String;");
     gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
     gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1ab9504..024c21d 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -213,51 +213,17 @@
 
 // ----------------------------------------------------------------------------
 static jint
-android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jobject jaa,
-        jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask,
-        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
+android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
+        jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
+        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
+        jlong nativeAudioTrack) {
 
-    ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
-        sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);
+    ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
+        "nativeAudioTrack=0x%llX",
+        jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
+        nativeAudioTrack);
 
-    if (jaa == 0) {
-        ALOGE("Error creating AudioTrack: invalid audio attributes");
-        return (jint) AUDIO_JAVA_ERROR;
-    }
-
-    // Invalid channel representations are caught by !audio_is_output_channel() below.
-    audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
-            channelPositionMask, channelIndexMask);
-    if (!audio_is_output_channel(nativeChannelMask)) {
-        ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
-        return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
-    }
-
-    uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
-
-    // check the format.
-    // This function was called from Java, so we compare the format against the Java constants
-    audio_format_t format = audioFormatToNative(audioFormat);
-    if (format == AUDIO_FORMAT_INVALID) {
-        ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
-        return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
-    }
-
-    // compute the frame count
-    size_t frameCount;
-    if (audio_has_proportional_frames(format)) {
-        const size_t bytesPerSample = audio_bytes_per_sample(format);
-        frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
-    } else {
-        frameCount = buffSizeInBytes;
-    }
-
-    jclass clazz = env->GetObjectClass(thiz);
-    if (clazz == NULL) {
-        ALOGE("Can't find %s when setting up callback.", kClassPathName);
-        return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
-    }
+    sp<AudioTrack> lpTrack = 0;
 
     if (jSession == NULL) {
         ALOGE("Error creating AudioTrack: invalid session ID pointer");
@@ -269,95 +235,172 @@
         ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
         return (jint) AUDIO_JAVA_ERROR;
     }
-    int sessionId = nSession[0];
+    audio_session_t sessionId = (audio_session_t) nSession[0];
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
-    // create the native AudioTrack object
-    sp<AudioTrack> lpTrack = new AudioTrack();
+    AudioTrackJniStorage* lpJniStorage = NULL;
 
     audio_attributes_t *paa = NULL;
-    // read the AudioAttributes values
-    paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-    const jstring jtags =
-            (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
-    const char* tags = env->GetStringUTFChars(jtags, NULL);
-    // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
-    strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-    env->ReleaseStringUTFChars(jtags, tags);
-    paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
-    paa->content_type =
-            (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
-    paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
 
-    ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
-            paa->usage, paa->content_type, paa->flags, paa->tags);
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == NULL) {
+        ALOGE("Can't find %s when setting up callback.", kClassPathName);
+        return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
+    }
 
-    // initialize the callback information:
-    // this data will be passed with every AudioTrack callback
-    AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
-    lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
-    // we use a weak reference so the AudioTrack object can be garbage collected.
-    lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
-    lpJniStorage->mCallbackData.busy = false;
+    // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
+    if (nativeAudioTrack == 0) {
+        if (jaa == 0) {
+            ALOGE("Error creating AudioTrack: invalid audio attributes");
+            return (jint) AUDIO_JAVA_ERROR;
+        }
 
-    // initialize the native AudioTrack object
-    status_t status = NO_ERROR;
-    switch (memoryMode) {
-    case MODE_STREAM:
+        if (jSampleRate == 0) {
+            ALOGE("Error creating AudioTrack: invalid sample rates");
+            return (jint) AUDIO_JAVA_ERROR;
+        }
 
-        status = lpTrack->set(
-                AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
-                sampleRateInHertz,
-                format,// word length, PCM
-                nativeChannelMask,
-                frameCount,
-                AUDIO_OUTPUT_FLAG_NONE,
-                audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
-                0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
-                0,// shared mem
-                true,// thread can call Java
-                sessionId,// audio session ID
-                AudioTrack::TRANSFER_SYNC,
-                NULL,                         // default offloadInfo
-                -1, -1,                       // default uid, pid values
-                paa);
-        break;
+        int* sampleRates = env->GetIntArrayElements(jSampleRate, NULL);
+        int sampleRateInHertz = sampleRates[0];
+        env->ReleaseIntArrayElements(jSampleRate, sampleRates, JNI_ABORT);
 
-    case MODE_STATIC:
-        // AudioTrack is using shared memory
+        // Invalid channel representations are caught by !audio_is_output_channel() below.
+        audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
+                channelPositionMask, channelIndexMask);
+        if (!audio_is_output_channel(nativeChannelMask)) {
+            ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
+            return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
+        }
 
-        if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
-            ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
+        uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
+
+        // check the format.
+        // This function was called from Java, so we compare the format against the Java constants
+        audio_format_t format = audioFormatToNative(audioFormat);
+        if (format == AUDIO_FORMAT_INVALID) {
+            ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
+            return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
+        }
+
+        // compute the frame count
+        size_t frameCount;
+        if (audio_is_linear_pcm(format)) {
+            const size_t bytesPerSample = audio_bytes_per_sample(format);
+            frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
+        } else {
+            frameCount = buffSizeInBytes;
+        }
+
+        // create the native AudioTrack object
+        lpTrack = new AudioTrack();
+
+        // read the AudioAttributes values
+        paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+        const jstring jtags =
+                (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
+        const char* tags = env->GetStringUTFChars(jtags, NULL);
+        // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
+        strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+        env->ReleaseStringUTFChars(jtags, tags);
+        paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
+        paa->content_type =
+                (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
+        paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
+
+        ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
+                paa->usage, paa->content_type, paa->flags, paa->tags);
+
+        // initialize the callback information:
+        // this data will be passed with every AudioTrack callback
+        lpJniStorage = new AudioTrackJniStorage();
+        lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
+        // we use a weak reference so the AudioTrack object can be garbage collected.
+        lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+        lpJniStorage->mCallbackData.busy = false;
+
+        // initialize the native AudioTrack object
+        status_t status = NO_ERROR;
+        switch (memoryMode) {
+        case MODE_STREAM:
+
+            status = lpTrack->set(
+                    AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
+                    sampleRateInHertz,
+                    format,// word length, PCM
+                    nativeChannelMask,
+                    frameCount,
+                    AUDIO_OUTPUT_FLAG_NONE,
+                    audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
+                    0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
+                    0,// shared mem
+                    true,// thread can call Java
+                    sessionId,// audio session ID
+                    AudioTrack::TRANSFER_SYNC,
+                    NULL,                         // default offloadInfo
+                    -1, -1,                       // default uid, pid values
+                    paa);
+            break;
+
+        case MODE_STATIC:
+            // AudioTrack is using shared memory
+
+            if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
+                ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
+                goto native_init_failure;
+            }
+
+            status = lpTrack->set(
+                    AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
+                    sampleRateInHertz,
+                    format,// word length, PCM
+                    nativeChannelMask,
+                    frameCount,
+                    AUDIO_OUTPUT_FLAG_NONE,
+                    audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
+                    0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
+                    lpJniStorage->mMemBase,// shared mem
+                    true,// thread can call Java
+                    sessionId,// audio session ID
+                    AudioTrack::TRANSFER_SHARED,
+                    NULL,                         // default offloadInfo
+                    -1, -1,                       // default uid, pid values
+                    paa);
+            break;
+
+        default:
+            ALOGE("Unknown mode %d", memoryMode);
             goto native_init_failure;
         }
 
-        status = lpTrack->set(
-                AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
-                sampleRateInHertz,
-                format,// word length, PCM
-                nativeChannelMask,
-                frameCount,
-                AUDIO_OUTPUT_FLAG_NONE,
-                audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
-                0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
-                lpJniStorage->mMemBase,// shared mem
-                true,// thread can call Java
-                sessionId,// audio session ID
-                AudioTrack::TRANSFER_SHARED,
-                NULL,                         // default offloadInfo
-                -1, -1,                       // default uid, pid values
-                paa);
-        break;
+        if (status != NO_ERROR) {
+            ALOGE("Error %d initializing AudioTrack", status);
+            goto native_init_failure;
+        }
+    } else {  // end if (nativeAudioTrack == 0)
+        lpTrack = (AudioTrack*)nativeAudioTrack;
+        // TODO: We need to find out which members of the Java AudioTrack might
+        // need to be initialized from the Native AudioTrack
+        // these are directly returned from getters:
+        //  mSampleRate
+        //  mAudioFormat
+        //  mStreamType
+        //  mChannelConfiguration
+        //  mChannelCount
+        //  mState (?)
+        //  mPlayState (?)
+        // these may be used internally (Java AudioTrack.audioParamCheck():
+        //  mChannelMask
+        //  mChannelIndexMask
+        //  mDataLoadMode
 
-    default:
-        ALOGE("Unknown mode %d", memoryMode);
-        goto native_init_failure;
-    }
-
-    if (status != NO_ERROR) {
-        ALOGE("Error %d initializing AudioTrack", status);
-        goto native_init_failure;
+        // initialize the callback information:
+        // this data will be passed with every AudioTrack callback
+        lpJniStorage = new AudioTrackJniStorage();
+        lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
+        // we use a weak reference so the AudioTrack object can be garbage collected.
+        lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+        lpJniStorage->mCallbackData.busy = false;
     }
 
     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
@@ -370,6 +413,11 @@
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
+    {
+        const jint elements[1] = { (jint) lpTrack->getSampleRate() };
+        env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
+    }
+
     {   // scope for the lock
         Mutex::Autolock l(sLock);
         sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
@@ -385,9 +433,11 @@
     // since we had audio attributes, the stream type was derived from them during the
     // creation of the native AudioTrack: push the same value to the Java object
     env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
-    // audio attributes were copied in AudioTrack creation
-    free(paa);
-    paa = NULL;
+    if (paa != NULL) {
+        // audio attributes were copied in AudioTrack creation
+        free(paa);
+        paa = NULL;
+    }
 
 
     return (jint) AUDIO_JAVA_SUCCESS;
@@ -409,7 +459,6 @@
     return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
 }
 
-
 // ----------------------------------------------------------------------------
 static void
 android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
@@ -492,7 +541,6 @@
         return;
     }
     //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
-    lpTrack->stop();
 
     // delete the JNI data
     AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
@@ -1114,7 +1162,7 @@
     {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
     {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
     {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
-    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I",
+    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJ)I",
                                          (void *)android_media_AudioTrack_setup},
     {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
     {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index defb88a..2364787 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -26,10 +26,13 @@
 #include <net/if.h>
 #include <linux/filter.h>
 #include <linux/if.h>
+#include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
 #include <net/if_ether.h>
+#include <netinet/icmp6.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/udp.h>
 #include <cutils/properties.h>
 
@@ -38,7 +41,6 @@
 extern "C" {
 int ifc_enable(const char *ifname);
 int ifc_disable(const char *ifname);
-int ifc_reset_connections(const char *ifname, int reset_mask);
 }
 
 #define NETUTILS_PKG_NAME "android/net/NetworkUtils"
@@ -47,27 +49,11 @@
 
 static const uint16_t kDhcpClientPort = 68;
 
-static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
-      jstring ifname, jint mask)
-{
-    int result;
-
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-
-    ALOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
-          env, clazz, nameStr, mask);
-
-    result = ::ifc_reset_connections(nameStr, mask);
-    env->ReleaseStringUTFChars(ifname, nameStr);
-    return (jint)result;
-}
-
 static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
-    int fd = jniGetFDFromFileDescriptor(env, javaFd);
     uint32_t ip_offset = sizeof(ether_header);
     uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol);
-    uint32_t flags_offset = ip_offset +  offsetof(iphdr, frag_off);
+    uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
     uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest);
     struct sock_filter filter_code[] = {
         // Check the protocol is UDP.
@@ -94,6 +80,45 @@
         filter_code,
     };
 
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+        jniThrowExceptionFmt(env, "java/net/SocketException",
+                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+    }
+}
+
+static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
+        jint hardwareAddressType)
+{
+    if (hardwareAddressType != ARPHRD_ETHER) {
+        jniThrowExceptionFmt(env, "java/net/SocketException",
+                "attachRaFilter only supports ARPHRD_ETHER");
+        return;
+    }
+
+    uint32_t ipv6_offset = sizeof(ether_header);
+    uint32_t ipv6_next_header_offset = ipv6_offset + offsetof(ip6_hdr, ip6_nxt);
+    uint32_t icmp6_offset = ipv6_offset + sizeof(ip6_hdr);
+    uint32_t icmp6_type_offset = icmp6_offset + offsetof(icmp6_hdr, icmp6_type);
+    struct sock_filter filter_code[] = {
+        // Check IPv6 Next Header is ICMPv6.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  ipv6_next_header_offset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_ICMPV6, 0, 3),
+
+        // Check ICMPv6 type is Router Advertisement.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  icmp6_type_offset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    ND_ROUTER_ADVERT, 0, 1),
+
+        // Accept or reject.
+        BPF_STMT(BPF_RET | BPF_K,              0xffff),
+        BPF_STMT(BPF_RET | BPF_K,              0)
+    };
+    struct sock_fprog filter = {
+        sizeof(filter_code) / sizeof(filter_code[0]),
+        filter_code,
+    };
+
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
                 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -140,7 +165,6 @@
  */
 static const JNINativeMethod gNetworkUtilMethods[] = {
     /* name, signature, funcPtr */
-    { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
     { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
     { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
@@ -148,6 +172,7 @@
     { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
     { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
+    { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index c9b5af7..59b8911 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -2012,22 +2012,35 @@
 static void
 android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "deprecated");
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static void
+android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jobject name_buf) {
     jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
     jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
     jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
+    jbyteArray _nameArray = (jbyteArray)0;
+    jint _nameBufferOffset = (jint)0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
     jint _sizeRemaining;
     GLint *size = (GLint *) 0;
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
+    jint _nameRemaining;
+    GLchar* name = (GLchar*)0;
+
 
     length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
     size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
     type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
+    name = (GLchar*)getPointer(_env, name_buf, (jarray*)&_nameArray, &_nameRemaining, &_nameBufferOffset);
     if (length == NULL) {
         char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
@@ -2040,6 +2053,10 @@
         char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
+    if (name == NULL) {
+        char* _nameBase = (char *)_env->GetByteArrayElements(_nameArray, (jboolean*)0);
+        name = (GLchar *) (_nameBase + _nameBufferOffset);
+    }
     glGetTransformFeedbackVarying(
         (GLuint)program,
         (GLuint)index,
@@ -2047,11 +2064,7 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        // The cast below is incorrect. The driver will end up writing to the
-        // address specified by name, which will always crash the process since
-        // it is guaranteed to be in low memory. The additional static_cast
-        // suppresses the warning for now. http://b/19478262
-        (char *)static_cast<uintptr_t>(name)
+        (GLchar*)name
     );
     if (_typeArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
@@ -2062,6 +2075,9 @@
     if (_lengthArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
+    if (_nameArray) {
+        releaseArrayPointer<jbyteArray, jbyte*, ByteArrayReleaser>(_env, _nameArray, (jbyte*)name, JNI_TRUE);
+    }
 }
 
 /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
@@ -5155,6 +5171,21 @@
     }
 }
 
+/* void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint offset ) */
+static void
+android_glReadPixels__IIIIIII
+  (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jint offset) {
+    glReadPixels(
+        (GLint)x,
+        (GLint)y,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLenum)format,
+        (GLenum)type,
+        reinterpret_cast<GLvoid *>(offset)
+    );
+}
+
 static const char *classPathName = "android/opengl/GLES30";
 
 static const JNINativeMethod methods[] = {
@@ -5218,6 +5249,7 @@
 {"glTransformFeedbackVaryings", "(I[Ljava/lang/String;I)V", (void *) android_glTransformFeedbackVaryings },
 {"glGetTransformFeedbackVarying", "(III[II[II[II[BI)V", (void *) android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI },
 {"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B },
+{"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 },
 {"glGetTransformFeedbackVarying", "(II[II[II)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying1 },
 {"glGetTransformFeedbackVarying", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying2 },
 {"glVertexAttribIPointerBounds", "(IIIILjava/nio/Buffer;I)V", (void *) android_glVertexAttribIPointerBounds__IIIILjava_nio_Buffer_2I },
@@ -5320,6 +5352,7 @@
 {"glTexStorage3D", "(IIIIII)V", (void *) android_glTexStorage3D__IIIIII },
 {"glGetInternalformativ", "(IIII[II)V", (void *) android_glGetInternalformativ__IIII_3II },
 {"glGetInternalformativ", "(IIIILjava/nio/IntBuffer;)V", (void *) android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2 },
+{"glReadPixels", "(IIIIIII)V", (void *) android_glReadPixels__IIIIIII },
 };
 
 int register_android_opengl_jni_GLES30(JNIEnv *_env)
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 5751add..156e7bd 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -888,9 +888,69 @@
 static jint
 android_glCreateShaderProgramv
   (JNIEnv *_env, jobject _this, jint type, jobjectArray strings) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLsizei _count;
+    const GLchar** _strings = NULL;
+    jstring* _jstrings = NULL;
+    GLuint _returnValue = 0;
 
-    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
-    return 0;
+    if (!strings) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "strings == null";
+        goto exit;
+    }
+
+    _count = _env->GetArrayLength(strings);
+
+    _strings = (const GLchar**) calloc(_count, sizeof(const GLchar*));
+    if (!_strings) {
+        _exception = 1;
+        _exceptionType = "java/lang/OutOfMemoryError";
+        _exceptionMessage = "out of memory";
+        goto exit;
+    }
+
+    _jstrings = (jstring*) calloc(_count, sizeof(jstring));
+    if (!_jstrings) {
+        _exception = 1;
+        _exceptionType = "java/lang/OutOfMemoryError";
+        _exceptionMessage = "out of memory";
+        goto exit;
+    }
+
+    for(int i = 0; i < _count; i++) {
+        _jstrings[i] = (jstring) _env->GetObjectArrayElement(strings, i);
+        if (!_jstrings[i]) {
+            _exception = 1;
+            _exceptionType = "java/lang/IllegalArgumentException";
+            _exceptionMessage = "strings == null";
+            goto exit;
+        }
+        _strings[i] = _env->GetStringUTFChars(_jstrings[i], 0);
+    }
+
+    _returnValue = glCreateShaderProgramv((GLenum)type, _count, _strings);
+exit:
+    if (_strings && _jstrings) {
+        for(int i = 0; i < _count; i++) {
+            if (_strings[i] && _jstrings[i]) {
+                _env->ReleaseStringUTFChars(_jstrings[i], _strings[i]);
+            }
+        }
+    }
+    if (_strings) {
+        free(_strings);
+    }
+    if (_jstrings) {
+        free(_jstrings);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    return (jint)_returnValue;
 }
 /* void glBindProgramPipeline ( GLuint pipeline ) */
 static void
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 03a1e71..f870a89 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -21,6 +21,7 @@
 #include "utils/misc.h"
 #include "cutils/debugger.h"
 #include <memtrack/memtrack.h>
+#include <memunreachable/memunreachable.h>
 
 #include <cutils/log.h>
 #include <fcntl.h>
@@ -36,6 +37,9 @@
 #include <ctype.h>
 #include <malloc.h>
 
+#include <iomanip>
+#include <string>
+
 namespace android
 {
 
@@ -258,7 +262,13 @@
             }
             name = line + name_pos;
             nameLen = strlen(name);
-
+            // Trim the end of the line if it is " (deleted)".
+            const char* deleted_str = " (deleted)";
+            if (nameLen > (int)strlen(deleted_str) &&
+                strcmp(name+nameLen-strlen(deleted_str), deleted_str) == 0) {
+                nameLen -= strlen(deleted_str);
+                name[nameLen] = '\0';
+            }
             if ((strstr(name, "[heap]") == name)) {
                 whichHeap = HEAP_NATIVE;
             } else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
@@ -1023,6 +1033,13 @@
     close(fd);
 }
 
+static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz,
+    jint limit, jboolean contents)
+{
+    std::string s = GetUnreachableMemoryString(contents, limit);
+    return env->NewStringUTF(s.c_str());
+}
+
 /*
  * JNI registration.
  */
@@ -1058,6 +1075,8 @@
             (void*)android_os_Debug_getDeathObjectCount },
     { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
             (void*)android_os_Debug_dumpNativeBacktraceToFile },
+    { "getUnreachableMemory", "(IZ)Ljava/lang/String;",
+            (void*)android_os_Debug_getUnreachableMemory },
 };
 
 int register_android_os_Debug(JNIEnv *env)
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 83f76ea..13e4f1a 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -32,10 +32,12 @@
 
 #include "SkPaint.h"
 #include "SkTypeface.h"
-#include "MinikinSkia.h"
-#include "MinikinUtils.h"
-#include "Paint.h"
-#include "minikin/LineBreaker.h"
+#include <hwui/MinikinSkia.h>
+#include <hwui/MinikinUtils.h>
+#include <hwui/Paint.h>
+#include <minikin/FontCollection.h>
+#include <minikin/LineBreaker.h>
+#include <minikin/MinikinFont.h>
 
 namespace android {
 
@@ -154,7 +156,7 @@
         jlong nativePaint, jlong nativeTypeface, jint start, jint end, jboolean isRtl) {
     LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
     Paint* paint = reinterpret_cast<Paint*>(nativePaint);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(nativeTypeface);
+    Typeface* typeface = reinterpret_cast<Typeface*>(nativeTypeface);
     FontCollection *font;
     MinikinPaint minikinPaint;
     FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index ae109c6..abc6c4b 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -556,7 +556,7 @@
     }
 
     // For the rest of the function we will hold this lock, to serialize
-    // looking/creation of Java proxies for native Binder proxies.
+    // looking/creation/destruction of Java proxies for native Binder proxies.
     AutoMutex _l(mProxyLock);
 
     // Someone else's...  do we know about it?
@@ -1225,16 +1225,21 @@
 
 static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
 {
+    // Don't race with construction/initialization
+    AutoMutex _l(mProxyLock);
+
     IBinder* b = (IBinder*)
             env->GetLongField(obj, gBinderProxyOffsets.mObject);
     DeathRecipientList* drl = (DeathRecipientList*)
             env->GetLongField(obj, gBinderProxyOffsets.mOrgue);
 
     LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl);
-    env->SetLongField(obj, gBinderProxyOffsets.mObject, 0);
-    env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0);
-    drl->decStrong((void*)javaObjectForIBinder);
-    b->decStrong((void*)javaObjectForIBinder);
+    if (b != nullptr) {
+        env->SetLongField(obj, gBinderProxyOffsets.mObject, 0);
+        env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0);
+        drl->decStrong((void*)javaObjectForIBinder);
+        b->decStrong((void*)javaObjectForIBinder);
+    }
 
     IPCThreadState::self()->flushCommands();
 }
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index ee8fb19..f7a5e8a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -17,6 +17,8 @@
 
 #define LOG_TAG "Process"
 
+// To make sure cpu_set_t is included from sched.h
+#define _GNU_SOURCE 1
 #include <utils/Log.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -288,6 +290,139 @@
     return (int) sp;
 }
 
+#ifdef ENABLE_CPUSETS
+/** Sample CPUset list format:
+ *  0-3,4,6-8
+ */
+static void parse_cpuset_cpus(char *cpus, cpu_set_t *cpu_set) {
+    unsigned int start, end, matched, i;
+    char *cpu_range = strtok(cpus, ",");
+    while (cpu_range != NULL) {
+        start = end = 0;
+        matched = sscanf(cpu_range, "%u-%u", &start, &end);
+        cpu_range = strtok(NULL, ",");
+        if (start >= CPU_SETSIZE) {
+            ALOGE("parse_cpuset_cpus: ignoring CPU number larger than %d.", CPU_SETSIZE);
+            continue;
+        } else if (end >= CPU_SETSIZE) {
+            ALOGE("parse_cpuset_cpus: ignoring CPU numbers larger than %d.", CPU_SETSIZE);
+            end = CPU_SETSIZE - 1;
+        }
+        if (matched == 1) {
+            CPU_SET(start, cpu_set);
+        } else if (matched == 2) {
+            for (i = start; i <= end; i++) {
+                CPU_SET(i, cpu_set);
+            }
+        } else {
+            ALOGE("Failed to match cpus");
+        }
+    }
+    return;
+}
+
+/**
+ * Stores the CPUs assigned to the cpuset corresponding to the
+ * SchedPolicy in the passed in cpu_set.
+ */
+static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set)
+{
+    FILE *file;
+    const char *filename;
+
+    CPU_ZERO(cpu_set);
+
+    switch (policy) {
+        case SP_BACKGROUND:
+            filename = "/dev/cpuset/background/cpus";
+            break;
+        case SP_FOREGROUND:
+        case SP_AUDIO_APP:
+        case SP_AUDIO_SYS:
+            filename = "/dev/cpuset/foreground/cpus";
+            break;
+        case SP_TOP_APP:
+            filename = "/dev/cpuset/top-app/cpus";
+            break;
+        default:
+            filename = NULL;
+    }
+
+    if (!filename) return;
+
+    file = fopen(filename, "re");
+    if (file != NULL) {
+        // Parse cpus string
+        char *line = NULL;
+        size_t len = 0;
+        ssize_t num_read = getline(&line, &len, file);
+        fclose (file);
+        if (num_read > 0) {
+            parse_cpuset_cpus(line, cpu_set);
+        } else {
+            ALOGE("Failed to read %s", filename);
+        }
+        free(line);
+    }
+    return;
+}
+#endif
+
+
+/**
+ * Determine CPU cores exclusively assigned to the
+ * cpuset corresponding to the SchedPolicy and store
+ * them in the passed in cpu_set_t
+ */
+void get_exclusive_cpuset_cores(SchedPolicy policy, cpu_set_t *cpu_set) {
+#ifdef ENABLE_CPUSETS
+    int i;
+    cpu_set_t tmp_set;
+    get_cpuset_cores_for_policy(policy, cpu_set);
+    for (i = 0; i < SP_CNT; i++) {
+        if ((SchedPolicy) i == policy) continue;
+        get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
+        // First get cores exclusive to one set or the other
+        CPU_XOR(&tmp_set, cpu_set, &tmp_set);
+        // Then get the ones only in cpu_set
+        CPU_AND(cpu_set, cpu_set, &tmp_set);
+    }
+#else
+    (void) policy;
+    CPU_ZERO(cpu_set);
+#endif
+    return;
+}
+
+jintArray android_os_Process_getExclusiveCores(JNIEnv* env, jobject clazz) {
+    SchedPolicy sp;
+    cpu_set_t cpu_set;
+    jintArray cpus;
+    int pid = getpid();
+    if (get_sched_policy(pid, &sp) != 0) {
+        signalExceptionForGroupError(env, errno);
+        return NULL;
+    }
+    get_exclusive_cpuset_cores(sp, &cpu_set);
+    int num_cpus = CPU_COUNT(&cpu_set);
+    cpus = env->NewIntArray(num_cpus);
+    if (cpus == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return NULL;
+    }
+
+    jint* cpu_elements = env->GetIntArrayElements(cpus, 0);
+    int count = 0;
+    for (int i = 0; i < CPU_SETSIZE && count < num_cpus; i++) {
+        if (CPU_ISSET(i, &cpu_set)) {
+            cpu_elements[count++] = i;
+        }
+    }
+
+    env->ReleaseIntArrayElements(cpus, cpu_elements, 0);
+    return cpus;
+}
+
 static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, jboolean bgOk) {
     // Establishes the calling thread as illegal to put into the background.
     // Typically used only for the system process's main looper.
@@ -1053,6 +1188,7 @@
     {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
     {"setProcessGroup",     "(II)V", (void*)android_os_Process_setProcessGroup},
     {"getProcessGroup",     "(I)I", (void*)android_os_Process_getProcessGroup},
+    {"getExclusiveCores",   "()[I", (void*)android_os_Process_getExclusiveCores},
     {"setSwappiness",   "(IZ)Z", (void*)android_os_Process_setSwappiness},
     {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
     {"setUid", "(I)I", (void*)android_os_Process_setUid},
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 03c94a6..6aac0e4 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -28,11 +28,11 @@
 #include <SkRegion.h>
 
 
-#include <Canvas.h>
 #include <Rect.h>
 #include <RenderNode.h>
 #include <CanvasProperty.h>
-#include <Paint.h>
+#include <hwui/Canvas.h>
+#include <hwui/Paint.h>
 #include <renderthread/RenderProxy.h>
 
 #include "core_jni_helpers.h"
@@ -160,7 +160,7 @@
     }
     // In the emulator this property will be set > 0 when OpenGL ES 2.0 is
     // enabled, 0 otherwise. On old emulator versions it will be undefined.
-    property_get("ro.kernel.qemu.gles", prop, "0");
+    property_get("qemu.gles", prop, "0");
     return atoi(prop) > 0 ? JNI_TRUE : JNI_FALSE;
 }
 
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 3a0ddc9..6b774e8 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -24,8 +24,8 @@
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
 #include <gui/GLConsumer.h>
+#include <hwui/Paint.h>
 
-#include <Paint.h>
 #include <SkBitmap.h>
 #include <SkCanvas.h>
 #include <SkMatrix.h>
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index a9003c1..27e2ee8 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -28,8 +28,9 @@
 #include <DamageAccumulator.h>
 #include <Matrix.h>
 #include <RenderNode.h>
+#include <renderthread/CanvasContext.h>
 #include <TreeInfo.h>
-#include <Paint.h>
+#include <hwui/Paint.h>
 
 #include "core_jni_helpers.h"
 
@@ -42,6 +43,54 @@
         ? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
         : false)
 
+static JNIEnv* getenv(JavaVM* vm) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
+    }
+    return env;
+}
+
+static jmethodID gOnRenderNodeDetached;
+
+class RenderNodeContext : public VirtualLightRefBase {
+public:
+    RenderNodeContext(JNIEnv* env, jobject jobjRef) {
+        env->GetJavaVM(&mVm);
+        // This holds a weak ref because otherwise there's a cyclic global ref
+        // with this holding a strong global ref to the view which holds
+        // a strong ref to RenderNode which holds a strong ref to this.
+        mWeakRef = env->NewWeakGlobalRef(jobjRef);
+    }
+
+    virtual ~RenderNodeContext() {
+        JNIEnv* env = getenv(mVm);
+        env->DeleteWeakGlobalRef(mWeakRef);
+    }
+
+    jobject acquireLocalRef(JNIEnv* env) {
+        return env->NewLocalRef(mWeakRef);
+    }
+
+private:
+    JavaVM* mVm;
+    jweak mWeakRef;
+};
+
+// Called by ThreadedRenderer's JNI layer
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node) {
+    auto context = reinterpret_cast<RenderNodeContext*>(node->getUserContext());
+    if (!context) return;
+    jobject jnode = context->acquireLocalRef(env);
+    if (!jnode) {
+        // The owning node has been GC'd, release the context
+        node->setUserContext(nullptr);
+        return;
+    }
+    env->CallVoidMethod(jnode, gOnRenderNodeDetached);
+    env->DeleteLocalRef(jnode);
+}
+
 // ----------------------------------------------------------------------------
 // DisplayList view properties
 // ----------------------------------------------------------------------------
@@ -58,7 +107,8 @@
     return renderNode->getDebugSize();
 }
 
-static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz, jstring name) {
+static jlong android_view_RenderNode_create(JNIEnv* env, jobject thiz,
+        jstring name) {
     RenderNode* renderNode = new RenderNode();
     renderNode->incStrong(0);
     if (name != NULL) {
@@ -66,6 +116,7 @@
         renderNode->setName(textArray);
         env->ReleaseStringUTFChars(name, textArray);
     }
+    renderNode->setUserContext(new RenderNodeContext(env, thiz));
     return reinterpret_cast<jlong>(renderNode);
 }
 
@@ -487,15 +538,7 @@
 
         virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override {
             if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return;
-            ATRACE_NAME("Update SurfaceView position");
 
-            JNIEnv* env = jnienv();
-            jobject localref = env->NewLocalRef(mWeakRef);
-            if (CC_UNLIKELY(!localref)) {
-                jnienv()->DeleteWeakGlobalRef(mWeakRef);
-                mWeakRef = nullptr;
-                return;
-            }
             Matrix4 transform;
             info.damageAccumulator->computeCurrentTransform(&transform);
             const RenderProperties& props = node.properties();
@@ -505,10 +548,13 @@
             bounds.right -= info.windowInsetLeft;
             bounds.top -= info.windowInsetTop;
             bounds.bottom -= info.windowInsetTop;
-            env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
-                    (jlong) info.frameNumber, (jint) bounds.left, (jint) bounds.top,
-                    (jint) bounds.right, (jint) bounds.bottom);
-            env->DeleteLocalRef(localref);
+
+            auto functor = std::bind(
+                std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePosition), this,
+                (jlong) info.frameNumber, (jint) bounds.left, (jint) bounds.top,
+                (jint) bounds.right, (jint) bounds.bottom);
+
+            info.canvasContext.enqueueFrameWork(std::move(functor));
         }
 
     private:
@@ -520,6 +566,23 @@
             return env;
         }
 
+        void doUpdatePosition(jlong frameNumber, jint left, jint top,
+                jint right, jint bottom) {
+            ATRACE_NAME("Update SurfaceView position");
+
+            JNIEnv* env = jnienv();
+            jobject localref = env->NewLocalRef(mWeakRef);
+            if (CC_UNLIKELY(!localref)) {
+                jnienv()->DeleteWeakGlobalRef(mWeakRef);
+                mWeakRef = nullptr;
+                return;
+            }
+
+            env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
+                    frameNumber, left, top, right, bottom);
+            env->DeleteLocalRef(localref);
+        }
+
         JavaVM* mVm;
         jobject mWeakRef;
     };
@@ -614,6 +677,9 @@
     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
             "updateWindowPositionRT", "(JIIII)V");
+    clazz = FindClassOrDie(env, "android/view/RenderNode");
+    gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
+            "onRenderNodeDetached", "()V");
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index cf68449..14252dc 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -144,7 +144,7 @@
         PublicFormat f) {
     switch(f) {
         case PublicFormat::JPEG:
-            return HAL_DATASPACE_JFIF;
+            return HAL_DATASPACE_V0_JFIF;
         case PublicFormat::DEPTH_POINT_CLOUD:
         case PublicFormat::DEPTH16:
             return HAL_DATASPACE_DEPTH;
@@ -156,7 +156,7 @@
         case PublicFormat::YUV_420_888:
         case PublicFormat::NV21:
         case PublicFormat::YV12:
-            return HAL_DATASPACE_JFIF;
+            return HAL_DATASPACE_V0_JFIF;
         default:
             // Most formats map to UNKNOWN
             return HAL_DATASPACE_UNKNOWN;
@@ -210,7 +210,7 @@
             switch (dataSpace) {
                 case HAL_DATASPACE_DEPTH:
                     return PublicFormat::DEPTH_POINT_CLOUD;
-                case HAL_DATASPACE_JFIF:
+                case HAL_DATASPACE_V0_JFIF:
                     return PublicFormat::JPEG;
                 default:
                     // Assume otherwise-marked blobs are also JPEG
@@ -411,22 +411,27 @@
         return 0;
     }
 
+    android::view::Surface surfaceShim;
+
+    // Calling code in Surface.java has already read the name of the Surface
+    // from the Parcel
+    surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
+
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
-    sp<IBinder> binder(parcel->readStrongBinder());
 
     // update the Surface only if the underlying IGraphicBufferProducer
     // has changed.
-    if (self != NULL
-            && (IInterface::asBinder(self->getIGraphicBufferProducer()) == binder)) {
+    if (self != nullptr
+            && (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
+                    IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
         // same IGraphicBufferProducer, return ourselves
         return jlong(self.get());
     }
 
     sp<Surface> sur;
-    sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
-    if (gbp != NULL) {
+    if (surfaceShim.graphicBufferProducer != nullptr) {
         // we have a new IGraphicBufferProducer, create a new Surface for it
-        sur = new Surface(gbp, true);
+        sur = new Surface(surfaceShim.graphicBufferProducer, true);
         // and keep a reference before passing to java
         sur->incStrong(&sRefBaseOwner);
     }
@@ -447,7 +452,13 @@
         return;
     }
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
-    parcel->writeStrongBinder( self != 0 ? IInterface::asBinder(self->getIGraphicBufferProducer()) : NULL);
+    android::view::Surface surfaceShim;
+    if (self != nullptr) {
+        surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer();
+    }
+    // Calling code in Surface.java has already written the name of the Surface
+    // to the Parcel
+    surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true);
 }
 
 static jint nativeGetWidth(JNIEnv* env, jclass clazz, jlong nativeObject) {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1dfe40a..d8233a0 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -110,6 +110,13 @@
     ctrl->decStrong((void *)nativeCreate);
 }
 
+static void nativeDisconnect(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    if (ctrl != NULL) {
+        ctrl->disconnect();
+    }
+}
+
 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
         jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
@@ -302,6 +309,16 @@
     }
 }
 
+static void nativeSetFinalCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
+        jint l, jint t, jint r, jint b) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    Rect crop(l, t, r, b);
+    status_t err = ctrl->setFinalCrop(crop);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
 static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, jint layerStack) {
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     status_t err = ctrl->setLayerStack(layerStack);
@@ -595,6 +612,8 @@
             (void*)nativeRelease },
     {"nativeDestroy", "(J)V",
             (void*)nativeDestroy },
+    {"nativeDisconnect", "(J)V",
+            (void*)nativeDisconnect },
     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
             (void*)nativeScreenshotBitmap },
     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
@@ -621,6 +640,8 @@
             (void*)nativeSetFlags },
     {"nativeSetWindowCrop", "(JIIII)V",
             (void*)nativeSetWindowCrop },
+    {"nativeSetFinalCrop", "(JIIII)V",
+            (void*)nativeSetFinalCrop },
     {"nativeSetLayerStack", "(JI)V",
             (void*)nativeSetLayerStack },
     {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 07868c5..8019326 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -120,7 +120,13 @@
     std::string mMessage;
 };
 
-class RootRenderNode : public RenderNode, ErrorHandler {
+// TODO: Clean this up, it's a bit odd to need to call over to
+// rendernode's jni layer. Probably means RootRenderNode should be pulled
+// into HWUI with appropriate callbacks for the various JNI hooks so
+// that RenderNode's JNI layer can handle its own thing
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
+
+class RootRenderNode : public RenderNode, ErrorHandler, TreeObserver {
 public:
     RootRenderNode(JNIEnv* env) : RenderNode() {
         mLooper = Looper::getForThread();
@@ -131,12 +137,15 @@
 
     virtual ~RootRenderNode() {}
 
-    virtual void onError(const std::string& message) {
+    virtual void onError(const std::string& message) override {
         mLooper->sendMessage(new RenderingException(mVm, message), 0);
     }
 
-    virtual void prepareTree(TreeInfo& info) {
+    virtual void prepareTree(TreeInfo& info) override {
         info.errorHandler = this;
+        if (info.mode == TreeInfo::MODE_FULL) {
+            info.observer = this;
+        }
         // TODO: This is hacky
         info.windowInsetLeft = -stagingProperties().getLeft();
         info.windowInsetTop = -stagingProperties().getTop();
@@ -145,7 +154,8 @@
         info.updateWindowPositions = false;
         info.windowInsetLeft = 0;
         info.windowInsetTop = 0;
-        info.errorHandler = NULL;
+        info.errorHandler = nullptr;
+        info.observer = nullptr;
     }
 
     void sendMessage(const sp<MessageHandler>& handler) {
@@ -171,10 +181,27 @@
         mPendingAnimatingRenderNodes.clear();
     }
 
+    virtual void onMaybeRemovedFromTree(RenderNode* node) override {
+        mMaybeRemovedNodes.insert(sp<RenderNode>(node));
+    }
+
+    void processMaybeRemovedNodes(JNIEnv* env) {
+        // We can safely access mMaybeRemovedNodes here because
+        // we will only modify it in prepareTree calls that are
+        // MODE_FULL
+
+        for (auto& node : mMaybeRemovedNodes) {
+            if (node->hasParents()) continue;
+            onRenderNodeRemoved(env, node.get());
+        }
+        mMaybeRemovedNodes.clear();
+    }
+
 private:
     sp<Looper> mLooper;
     JavaVM* mVm;
     std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
+    std::set< sp<RenderNode> > mMaybeRemovedNodes;
 };
 
 class AnimationContextBridge : public AnimationContext {
@@ -473,13 +500,16 @@
 }
 
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize, jlong rootNodePtr) {
     LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
             "Mismatched size expectations, given %d expected %d",
             frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
     env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
-    return proxy->syncAndDrawFrame();
+    int ret = proxy->syncAndDrawFrame();
+    rootRenderNode->processMaybeRemovedNodes(env);
+    return ret;
 }
 
 static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
@@ -706,7 +736,7 @@
     { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
-    { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+    { "nSyncAndDrawFrame", "(J[JIJ)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 612f4df..3f4b2a6 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -302,9 +302,6 @@
         return false;
     }
 
-    // Unmount storage provided by root namespace and mount requested view
-    UnmountTree("/storage");
-
     String8 storageSource;
     if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
         storageSource = "/mnt/runtime/default";
@@ -667,12 +664,24 @@
   return pid;
 }
 
+static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) {
+    // Zygote process unmount root storage space initially before every child processes are forked.
+    // Every forked child processes (include SystemServer) only mount their own root storage space
+    // And no need unmount storage operation in MountEmulatedStorage method.
+    // Zygote process does not utilize root storage spaces and unshared its mount namespace from the ART.
+
+    UnmountTree("/storage");
+    return;
+}
+
 static const JNINativeMethod gMethods[] = {
     { "nativeForkAndSpecialize",
       "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
-      (void *) com_android_internal_os_Zygote_nativeForkSystemServer }
+      (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
+    { "nativeUnmountStorageOnInit", "()V",
+      (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit }
 };
 
 int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index eeff00f..88d75dd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -87,6 +87,7 @@
     <protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
+    <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
 
     <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
 
@@ -167,7 +168,7 @@
         android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
-   <protected-broadcast
+    <protected-broadcast
         android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
@@ -265,6 +266,7 @@
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
+    <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
@@ -296,10 +298,6 @@
     <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
     <protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
     <protected-broadcast android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED" />
-    <protected-broadcast android:name="android.intent.action.BUGREPORT_STARTED" />
-    <protected-broadcast android:name="android.intent.action.BUGREPORT_FINISHED" />
-    <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_FINISHED" />
-    <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_DISPATCH" />
 
     <!-- Legacy -->
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
@@ -350,6 +348,8 @@
     <protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
 
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
 
     <!-- Added in N -->
     <protected-broadcast android:name="android.intent.action.ANR" />
@@ -378,7 +378,10 @@
     <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" />
     <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
     <protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" />
+
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
 
     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
@@ -398,7 +401,6 @@
     <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
 
     <protected-broadcast android:name="com.android.bluetooth.btservice.action.ALARM_WAKEUP" />
-    <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
     <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_POLL" />
     <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_UPDATED" />
     <protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" />
@@ -416,6 +418,7 @@
     <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
     <protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" />
+    <protected-broadcast android:name="android.os.storage.action.DISK_SCANNED" />
     <protected-broadcast android:name="com.android.server.action.UPDATE_TWILIGHT_STATE" />
     <protected-broadcast android:name="com.android.server.device_idle.STEP_IDLE_STATE" />
     <protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
@@ -436,7 +439,6 @@
     <protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
 
     <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
-    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
 
     <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
     <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
@@ -454,6 +456,20 @@
 
     <protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
 
+    <protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
+    <protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
+    <protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
+
+    <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
+    <protected-broadcast android:name="com.android.ims.IMS_INCOMING_CALL" />
+    <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
+    <protected-broadcast android:name="com.android.intent.action.IMS_FEATURE_CHANGED" />
+    <protected-broadcast android:name="com.android.intent.action.IMS_CONFIG_CHANGED" />
+
+    <protected-broadcast android:name="com.android.internal.location.ALARM_WAKEUP" />
+    <protected-broadcast android:name="com.android.internal.location.ALARM_TIMEOUT" />
+    <protected-broadcast android:name="android.intent.action.GLOBAL_BUTTON" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -698,7 +714,9 @@
         android:description="@string/permgroupdesc_phone"
         android:priority="500" />
 
-    <!-- Allows read only access to phone state.
+    <!-- Allows read only access to phone state, including the phone number of the device,
+         current cellular network information, the status of any ongoing calls, and a list of any
+         {@link android.telecom.PhoneAccount}s registered on the device.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
          minSdkVersion}</a> and <a
@@ -827,6 +845,26 @@
         android:protectionLevel="dangerous"/>
 
     <!-- ====================================================================== -->
+    <!-- Permissions for accessing the UCE Service                              -->
+    <!-- ====================================================================== -->
+
+    <!-- @hide Allows an application to Access UCE-Presence.
+         <p>Protection level: dangerous
+    -->
+    <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:protectionLevel="signatureOrSystem"/>
+
+    <!-- @hide Allows an application to Access UCE-OPTIONS.
+         <p>Protection level: dangerous
+    -->
+    <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:protectionLevel="signatureOrSystem"/>
+
+
+
+    <!-- ====================================================================== -->
     <!-- Permissions for accessing the device camera                            -->
     <!-- ====================================================================== -->
     <eat-comment />
@@ -893,92 +931,82 @@
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.READ_PROFILE"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_PROFILE"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.READ_SOCIAL_STREAM"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_SOCIAL_STREAM"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.READ_USER_DICTIONARY"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_USER_DICTIONARY"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_SMS"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.MANAGE_ACCOUNTS"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.USE_CREDENTIALS"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.FLASHLIGHT"
         android:protectionLevel="normal"
-        android:permissionFlags="hidden"/>
+        android:permissionFlags="removed"/>
 
     <!-- ====================================================================== -->
     <!-- INSTALL PERMISSIONS                                                    -->
     <!-- ====================================================================== -->
 
-`   <!-- =========================================== -->
-    <!-- Permissions for accessing contact metadata -->
-    <!-- =========================================== -->
-    <eat-comment />
-
-    <!-- @SystemApi Allows an application to read/write contact metadata.
-         <p>Not for use by third-party applications. -->
-    <permission android:name="android.permission.READ_WRITE_CONTACT_METADATA"
-        android:protectionLevel="signature|system" />
-
     <!-- ================================== -->
     <!-- Permissions for accessing messages -->
     <!-- ================================== -->
@@ -990,6 +1018,11 @@
     <permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to filter carrier specific sms.
          @hide -->
     <permission android:name="android.permission.CARRIER_FILTER_SMS"
@@ -1484,11 +1517,21 @@
 
     <!-- Allows an application to manage access to documents, usually as part
          of a document picker.
+         <p>This permission should <em>only</em> be requested by the platform
+         document management app.  This permission cannot be granted to
+         third-party apps.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to cache content.
+         <p>Not for use by third-party applications.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.CACHE_CONTENT"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions for screenlock         -->
     <!-- ================================== -->
@@ -1612,6 +1655,11 @@
     <permission android:name="android.permission.GET_PACKAGE_IMPORTANCE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows use of PendingIntent.getIntent().
+         @hide -->
+    <permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions affecting the display of other applications  -->
     <!-- ================================== -->
@@ -1964,6 +2012,11 @@
     <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows but does not guarantee access to user passwords at the conclusion of add
+         account -->
+    <permission android:name="android.permission.GET_PASSWORD_PRIVILEGED"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows applications to RW to diagnostic resources.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DIAGNOSTIC"
@@ -2132,6 +2185,15 @@
     <permission android:name="android.permission.BIND_PRINT_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
+     to ensure that only the system can bind to it.
+     @hide
+     @SystemApi
+     <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
+            android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
          or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
          the system can bind to it.
@@ -2770,12 +2832,11 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link
-         android.service.notification.NotificationAssistantService},
-         to ensure that only the system can bind to it.
+         android.service.notification.NotificationRankerService         to ensure that only the system can bind to it.
          <p>Protection level: signature
          @hide This is not a third-party API (intended for system apps). -->
     -->
-    <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
+    <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link
@@ -2930,6 +2991,17 @@
     <permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
+         the system can bind to it.
+         <p>Protection level: signature -->
+    <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
+        android:protectionLevel="signature" />
+
+    <!-- Allows an application to whitelist tasks during lock task mode
+         @hide <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
+        android:protectionLevel="signature|setup" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -2939,9 +3011,9 @@
                  android:killAfterRestore="false"
                  android:icon="@drawable/ic_launcher_android"
                  android:supportsRtl="true"
-                 android:theme="@style/Theme.Material.DayNight.DarkActionBar"
-                 android:forceDeviceEncrypted="true"
-                 android:encryptionAware="true">
+                 android:theme="@style/Theme.Material.Light.DarkActionBar"
+                 android:defaultToDeviceProtectedStorage="true"
+                 android:directBootAware="true">
         <activity android:name="com.android.internal.app.ChooserActivity"
                 android:theme="@style/Theme.DeviceDefault.Resolver"
                 android:finishOnCloseSystemDialogs="true"
@@ -2975,7 +3047,7 @@
                 android:label="@string/managed_profile_label">
         </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/heavy_weight_switcher_title"
                 android:finishOnCloseSystemDialogs="true"
                 android:excludeFromRecents="true"
@@ -3008,7 +3080,7 @@
         <activity android:name="android.accounts.ChooseAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
@@ -3016,14 +3088,14 @@
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
                 android:excludeFromRecents="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
@@ -3031,19 +3103,19 @@
         <activity android:name="android.accounts.CantAddAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog.NoActionBar"
+                android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.DialogWhenLarge"
+                android:theme="@style/Theme.Material.Light.DialogWhenLarge"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
-               android:theme="@style/Theme.Material.DayNight.Dialog"
+               android:theme="@style/Theme.Material.Light.Dialog"
                android:label="@string/sync_too_many_deletes"
                android:process=":ui">
         </activity>
@@ -3063,7 +3135,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-                android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+                android:theme="@style/Theme.Material.Light.Dialog.Alert"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
@@ -3084,7 +3156,7 @@
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
                 android:excludeFromRecents="true"
                 android:process=":ui"
-                android:theme="@style/Theme.Material.DayNight.Dialog.Alert">
+                android:theme="@style/Theme.Material.Light.Dialog.Alert">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3092,7 +3164,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-                android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+                android:theme="@style/Theme.Material.Light.Dialog.Alert"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
diff --git a/core/res/assets/images/clock64.png b/core/res/assets/images/clock64.png
new file mode 100644
index 0000000..493a1ea
--- /dev/null
+++ b/core/res/assets/images/clock64.png
Binary files differ
diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml
index 6f3c4d42..c96e280 100644
--- a/core/res/res/anim/lock_screen_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_behind_enter.xml
@@ -16,7 +16,6 @@
   -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000"
         android:detachWallpaper="true"
         android:shareInterpolator="false"
         android:startOffset="100">
diff --git a/core/res/res/anim/progress_indeterminate_rotation_material.xml b/core/res/res/anim/progress_indeterminate_rotation_material.xml
index 5d3ba22..6e12105 100644
--- a/core/res/res/anim/progress_indeterminate_rotation_material.xml
+++ b/core/res/res/anim/progress_indeterminate_rotation_material.xml
@@ -16,7 +16,7 @@
 -->
 
 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="6665"
+    android:duration="4444"
     android:interpolator="@android:anim/linear_interpolator"
     android:propertyName="rotation"
     android:repeatCount="-1"
diff --git a/core/res/res/anim/slide_in_enter_micro.xml b/core/res/res/anim/slide_in_enter_micro.xml
new file mode 100644
index 0000000..c70874c
--- /dev/null
+++ b/core/res/res/anim/slide_in_enter_micro.xml
@@ -0,0 +1,29 @@
+<?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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:zAdjustment="top">
+    <translate android:fromYDelta="5%p" android:toYDelta="0"
+               android:duration="417"
+               android:interpolator="@android:interpolator/launch_task_micro_ydelta" />
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+           android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+           android:duration="150"
+           android:interpolator="@android:interpolator/launch_task_micro_alpha" />
+</set>
diff --git a/core/res/res/anim/slide_in_exit_micro.xml b/core/res/res/anim/slide_in_exit_micro.xml
new file mode 100644
index 0000000..f0d8c0b
--- /dev/null
+++ b/core/res/res/anim/slide_in_exit_micro.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:duration="417" />
+</set>
diff --git a/core/res/res/anim/slide_in_micro.xml b/core/res/res/anim/slide_in_micro.xml
deleted file mode 100644
index 6320e80..0000000
--- a/core/res/res/anim/slide_in_micro.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/anim/slide_in_micro.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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-    <translate android:fromXDelta="100%p" android:toXDelta="0"
-               android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-           android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-           android:duration="@android:integer/config_mediumAnimTime" />
-</set>
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index 4cb6df0..c647093 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -18,10 +18,13 @@
 */
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-    <translate android:fromXDelta="0" android:toXDelta="100%p"
-               android:duration="@android:integer/config_mediumAnimTime"/>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:zAdjustment="top">
+    <translate android:fromYDelta="0" android:toYDelta="5%p"
+               android:duration="250"
+               android:interpolator="@android:interpolator/fast_out_slow_in"/>
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-           android:duration="@android:integer/config_mediumAnimTime" />
+           android:startOffset="100" android:duration="150"
+           android:interpolator="@android:interpolator/fast_out_slow_in" />
 </set>
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.jpg b/core/res/res/drawable-nodpi/default_wallpaper.jpg
deleted file mode 100644
index d7475b4c..0000000
--- a/core/res/res/drawable-nodpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png
new file mode 100644
index 0000000..e9c4d5c
--- /dev/null
+++ b/core/res/res/drawable-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index bb423fef5..defa83a 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2015 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,20 +14,24 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
+        android:width="512dp"
+        android:height="512dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
     <path
-        android:pathData="M34.9,13.2c-0.8,-0.8,-4.2,-2.4,-10.9,-2.4s-10.1,1.6,-10.9,2.4c-0.8,0.8,-2.4,4.2,-2.4,10.9s1.6,10.1,2.4,10.9    c0.8,0.8,4.2,2.4,10.9,2.4s10.1,-1.6,10.9,-2.4c0.8,-0.8,2.4,-4.2,2.4,-10.9S35.6,14,34.9,13.2z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="#FF7E5BBF"
+        android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
     <path
-        android:pathData="M34.7,13.7c0,0.8,-1.2,1.5,-3.1,2.1c-1.9,0.5,-4.6,0.8,-7.6,0.8s-5.6,-0.3,-7.6,-0.8    c-1.9,-0.5,-3.1,-1.2,-3.1,-2.1s1.2,-1.5,3.1,-2.1c1.9,-0.5,4.6,-0.8,7.6,-0.8s5.6,0.3,7.6,0.8C33.5,12.1,34.7,12.9,34.7,13.7z"
-        android:fillColor="#EBEBEB"/>
+        android:fillColor="#FF7E5BBF"
+        android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
     <path
-        android:pathData="M30,13c-0.1,0,-0.1,0,-0.2,0c-0.4,-0.1,-0.7,-0.6,-0.6,-1l1.3,-5.5c0.1,-0.4,0.6,-0.7,1,-0.6c0.4,0.1,0.7,0.6,0.6,1    l-1.3,5.5C30.7,12.7,30.4,13,30,13z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="#40000000"
+        android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
     <path
-        android:pathData="M18,13c-0.4,0,-0.7,-0.3,-0.8,-0.6l-1.3,-5.5c-0.1,-0.4,0.2,-0.9,0.6,-1c0.4,-0.1,0.9,0.2,1,0.6l1.3,5.5    c0.1,0.4,-0.2,0.9,-0.6,1C18.1,13,18.1,13,18,13z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="#40000000"
+        android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
+    <path
+        android:fillColor="#FF55C4F5"
+        android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
 </vector>
+
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 8cc9961..5043cba 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,23 +14,23 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
     <path
-        android:pathData="M8.4,5.3c-0.2,0.0 -0.4,-0.2 -0.5,-0.4L7.1,1.6C7.0,1.4 7.2,1.1 7.4,1.0C7.7,0.9 8.0,1.1 8.0,1.4l0.8,3.3c0.1,0.3 -0.1,0.5 -0.4,0.6C8.5,5.3 8.4,5.3 8.4,5.3z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="#A0FFFFFF"
+        android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
     <path
-        android:pathData="M15.6,5.3c0.0,0.0 -0.1,0.0 -0.1,0.0c-0.3,-0.1 -0.4,-0.3 -0.4,-0.6L16.0,1.4C16.0,1.1 16.3,0.9 16.6,1.0c0.3,0.1 0.4,0.3 0.4,0.6l-0.8,3.3C16.1,5.1 15.9,5.3 15.6,5.3z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="#A0FFFFFF"
+        android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
     <path
-        android:pathData="M18.6,5.4c-0.1,-0.1 -0.2,-0.1 -0.3,-0.2c0.2,0.2 0.3,0.3 0.3,0.5c0.0,0.9 -2.9,1.7 -6.6,1.7S5.4,6.7 5.4,5.7c0.0,-0.2 0.1,-0.3 0.3,-0.5C5.6,5.3 5.5,5.4 5.4,5.4C5.0,5.9 4.0,8.0 4.0,12.0s1.0,6.1 1.4,6.6C5.9,19.0 8.0,20.0 12.0,20.0s6.1,-1.0 6.6,-1.4C19.0,18.1 20.0,16.0 20.0,12.0S19.0,5.9 18.6,5.4zM8.0,13.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0c0.0,-0.6 0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0C9.0,12.6 8.6,13.0 8.0,13.0zM16.0,13.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0c0.0,-0.6 0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0C17.0,12.6 16.6,13.0 16.0,13.0z"
-        android:fillColor="#FFFFFF"/>
-   <path
-        android:pathData="M5.35,5.7
-                          a 6.6 1.75 0 1 1 13.25 0
-                          a 6.6 1.75 0 1 1 -13.25 0
-                          z" 
-        android:fillColor="#BBFFFFFF" />
+        android:fillColor="#40000000"
+        android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
+    <path
+        android:fillColor="#40000000"
+        android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
 </vector>
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg
deleted file mode 100644
index 03a14c0..0000000
--- a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
new file mode 100644
index 0000000..9f3efa5
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg
deleted file mode 100644
index 543d118..0000000
--- a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
new file mode 100644
index 0000000..8199e70
--- /dev/null
+++ b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
index cd678f1..6448f3b 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
@@ -16,22 +16,22 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="76dp"
         android:width="76dp"
-        android:viewportHeight="48"
-        android:viewportWidth="48"
+        android:viewportHeight="76"
+        android:viewportWidth="76"
         android:tint="?attr/colorControlActivated">
 
     <group
         android:name="root"
-        android:translateX="24.0"
-        android:translateY="24.0" >
+        android:translateX="38.0"
+        android:translateY="38.0" >
         <path
             android:name="progressBar"
             android:fillColor="#00000000"
-            android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+            android:pathData="M0, 0 m 0, -29 a 29,29 0 1,1 0,58 a 29,29 0 1,1 0,-58"
             android:strokeColor="@color/white"
             android:strokeLineCap="square"
             android:strokeLineJoin="miter"
-            android:strokeWidth="4"
+            android:strokeWidth="6"
             android:trimPathEnd="0"
             android:trimPathOffset="0"
             android:trimPathStart="0" />
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
index 7f038f4..80e3355 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
@@ -27,7 +27,7 @@
         <path
             android:name="progressBar"
             android:fillColor="#00000000"
-            android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+            android:pathData="M0, 0 m 0, -18 a 18,18 0 1,1 0,36 a 18,18 0 1,1 0,-36"
             android:strokeColor="@color/white"
             android:strokeLineCap="square"
             android:strokeLineJoin="miter"
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
index 5625788..ebb632a 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
@@ -16,22 +16,22 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="16dp"
         android:width="16dp"
-        android:viewportHeight="48"
-        android:viewportWidth="48"
+        android:viewportHeight="16"
+        android:viewportWidth="16"
         android:tint="?attr/colorControlActivated">
 
     <group
         android:name="root"
-        android:translateX="24.0"
-        android:translateY="24.0" >
+        android:translateX="8.0"
+        android:translateY="8.0" >
         <path
             android:name="progressBar"
             android:fillColor="#00000000"
-            android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+            android:pathData="M0, 0 m 0, -5.9375 a 5.9375,5.9375 0 1,1 0,11.875 a 5.9375,5.9375 0 1,1 0,-11.875"
             android:strokeColor="@color/white"
             android:strokeLineCap="square"
             android:strokeLineJoin="miter"
-            android:strokeWidth="4"
+            android:strokeWidth="2.125"
             android:trimPathEnd="0"
             android:trimPathOffset="0"
             android:trimPathStart="0" />
diff --git a/core/res/res/drawable/work_widget_mask_view_background.xml b/core/res/res/drawable/work_widget_mask_view_background.xml
deleted file mode 100644
index 17f0dbc..0000000
--- a/core/res/res/drawable/work_widget_mask_view_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
- <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
-   <padding android:left="5dp" android:right="5dp" android:top="5dp" android:bottom="5dp"/>
-   <stroke android:width="1dp" android:color="#CCCCCC" />
- </shape>
diff --git a/core/res/res/interpolator/launch_task_micro_alpha.xml b/core/res/res/interpolator/launch_task_micro_alpha.xml
new file mode 100644
index 0000000..41b79b5
--- /dev/null
+++ b/core/res/res/interpolator/launch_task_micro_alpha.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:controlX1="0"
+                  android:controlY1="0"
+                  android:controlX2="0.7"
+                  android:controlY2="1" />
diff --git a/core/res/res/interpolator/launch_task_micro_ydelta.xml b/core/res/res/interpolator/launch_task_micro_ydelta.xml
new file mode 100644
index 0000000..acac761
--- /dev/null
+++ b/core/res/res/interpolator/launch_task_micro_ydelta.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:controlX1="0"
+                  android:controlY1="0"
+                  android:controlX2="0.4"
+                  android:controlY2="1" />
diff --git a/core/res/res/layout-sw600dp/preference_list_content_single.xml b/core/res/res/layout-sw600dp/preference_list_content_single.xml
new file mode 100644
index 0000000..88b1aa8
--- /dev/null
+++ b/core/res/res/layout-sw600dp/preference_list_content_single.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="1">
+
+        <LinearLayout
+            android:id="@+id/headers"
+            style="?attr/preferencePanelStyle"
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <ListView
+                android:id="@android:id/list"
+                android:layout_width="match_parent"
+                android:layout_height="0px"
+                android:layout_weight="1"
+                android:drawSelectorOnTop="false"
+                android:cacheColorHint="@android:color/transparent"
+                android:listPreferredItemHeight="48dp"
+                android:scrollbarAlwaysDrawVerticalTrack="true"
+                android:paddingStart="32dip"
+                android:paddingEnd="32dip"
+                android:paddingTop="32dip"
+                android:paddingBottom="32dip"
+                android:clipToPadding="false"/>
+
+            <FrameLayout android:id="@+id/list_footer"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <RelativeLayout android:id="@+id/button_bar"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_weight="0"
+        android:visibility="gone">
+
+        <Button android:id="@+id/back_button"
+            android:layout_width="150dip"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dip"
+            android:layout_alignParentStart="true"
+            android:text="@string/back_button_label"
+        />
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true">
+
+            <Button android:id="@+id/skip_button"
+                android:layout_width="150dip"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dip"
+                android:text="@string/skip_button_label"
+                android:visibility="gone"
+            />
+
+            <Button android:id="@+id/next_button"
+                android:layout_width="150dip"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dip"
+                android:text="@string/next_button_label"
+            />
+        </LinearLayout>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/layout-w600dp/preference_list_content_single.xml b/core/res/res/layout-w600dp/preference_list_content_single.xml
deleted file mode 100644
index d2fa5b9..0000000
--- a/core/res/res/layout-w600dp/preference_list_content_single.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent">
-
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="0px"
-        android:layout_weight="1">
-
-        <LinearLayout
-            android:id="@+id/headers"
-            style="?attr/preferencePanelStyle"
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingStart="32dip"
-            android:paddingEnd="32dip"
-            android:paddingTop="32dip"
-            android:paddingBottom="32dip" >
-
-            <ListView android:id="@android:id/list"
-                android:layout_width="match_parent"
-                android:layout_height="0px"
-                android:layout_weight="1"
-                android:drawSelectorOnTop="false"
-                android:cacheColorHint="@android:color/transparent"
-                android:listPreferredItemHeight="48dp"
-                android:scrollbarAlwaysDrawVerticalTrack="true" />
-
-            <FrameLayout android:id="@+id/list_footer"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0" />
-
-        </LinearLayout>
-
-    </LinearLayout>
-
-    <RelativeLayout android:id="@+id/button_bar"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:layout_weight="0"
-        android:visibility="gone">
-
-        <Button android:id="@+id/back_button"
-            android:layout_width="150dip"
-            android:layout_height="wrap_content"
-            android:layout_margin="5dip"
-            android:layout_alignParentStart="true"
-            android:text="@string/back_button_label"
-        />
-        <LinearLayout
-            android:orientation="horizontal"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentEnd="true">
-
-            <Button android:id="@+id/skip_button"
-                android:layout_width="150dip"
-                android:layout_height="wrap_content"
-                android:layout_margin="5dip"
-                android:text="@string/skip_button_label"
-                android:visibility="gone"
-            />
-
-            <Button android:id="@+id/next_button"
-                android:layout_width="150dip"
-                android:layout_height="wrap_content"
-                android:layout_margin="5dip"
-                android:text="@string/next_button_label"
-            />
-        </LinearLayout>
-    </RelativeLayout>
-</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 9f50937..6d33de6 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -34,7 +34,6 @@
             android:id="@+id/scrollView"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="@dimen/dialog_padding_top_material"
             android:clipToPadding="false">
 
             <LinearLayout
@@ -42,6 +41,12 @@
                 android:layout_height="wrap_content"
                 android:orientation="vertical">
 
+                <Space
+                    android:id="@+id/textSpacerNoTitle"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/dialog_padding_top_material" />
+
                 <TextView
                     android:id="@+id/message"
                     android:layout_width="match_parent"
@@ -53,7 +58,7 @@
                 <Space
                     android:id="@+id/textSpacerNoButtons"
                     android:visibility="gone"
-                    android:layout_width="0dp"
+                    android:layout_width="match_parent"
                     android:layout_height="@dimen/dialog_padding_top_material" />
             </LinearLayout>
         </ScrollView>
diff --git a/core/res/res/layout/alert_dialog_title_material.xml b/core/res/res/layout/alert_dialog_title_material.xml
index 738a637..eef9585 100644
--- a/core/res/res/layout/alert_dialog_title_material.xml
+++ b/core/res/res/layout/alert_dialog_title_material.xml
@@ -21,6 +21,8 @@
               android:layout_height="wrap_content"
               android:orientation="vertical">
 
+    <!-- If the client uses a customTitle, it will be added here. -->
+
     <LinearLayout
         android:id="@+id/title_template"
         android:layout_width="match_parent"
@@ -49,5 +51,9 @@
             style="?attr/windowTitleStyle" />
     </LinearLayout>
 
-    <!-- If the client uses a customTitle, it will be added here. -->
+    <Space
+        android:id="@+id/titleDividerNoCustom"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/dialog_title_divider_material" />
 </LinearLayout>
diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml
index 8bef116..5ad0f4c 100644
--- a/core/res/res/layout/app_anr_dialog.xml
+++ b/core/res/res/layout/app_anr_dialog.xml
@@ -19,7 +19,7 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:paddingTop="@dimen/aerr_padding_list_top"
-        android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+        android:paddingBottom="@dimen/aerr_padding_list_bottom">
 
     <Button
             android:id="@+id/aerr_close"
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index b9531f4..7147ea2 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -22,7 +22,7 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:paddingTop="@dimen/aerr_padding_list_top"
-        android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+        android:paddingBottom="@dimen/aerr_padding_list_bottom">
 
 
     <Button
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 41726fb..d12c8ba 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -25,63 +25,48 @@
         android:maxCollapsedHeightSmall="56dp"
         android:id="@id/contentPanel">
 
-    <LinearLayout
+    <RelativeLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_alwaysShow="true"
             android:elevation="8dp"
             android:paddingStart="16dp"
             android:background="@color/white" >
+        <TextView android:id="@+id/profile_button"
+                  android:layout_width="wrap_content"
+                  android:layout_height="48dp"
+                  android:layout_marginEnd="8dp"
+                  android:paddingStart="8dp"
+                  android:paddingEnd="8dp"
+                  android:visibility="gone"
+                  style="?attr/borderlessButtonStyle"
+                  android:textAppearance="?attr/textAppearanceButton"
+                  android:textColor="@color/material_deep_teal_500"
+                  android:gravity="center_vertical"
+                  android:layout_alignParentTop="true"
+                  android:layout_alignParentRight="true"
+                  android:singleLine="true"/>
         <ImageView android:id="@+id/title_icon"
                    android:layout_width="24dp"
                    android:layout_height="24dp"
-                   android:layout_gravity="start|center_vertical"
                    android:layout_marginEnd="16dp"
                    android:visibility="gone"
-                   android:scaleType="fitCenter" />
+                   android:scaleType="fitCenter"
+                   android:layout_below="@id/profile_button"
+                   android:layout_alignParentLeft="true"
+                   />
         <TextView android:id="@+id/title"
-                  android:layout_width="0dp"
                   android:layout_height="wrap_content"
-                  android:layout_weight="1"
+                  android:layout_width="wrap_content"
                   android:textAppearance="?attr/textAppearanceMedium"
                   android:textSize="14sp"
                   android:gravity="start|center_vertical"
                   android:paddingEnd="?attr/dialogPreferredPadding"
                   android:paddingTop="12dp"
-                  android:paddingBottom="12dp" />
-        <LinearLayout android:id="@+id/profile_button"
-                      android:layout_width="wrap_content"
-                      android:layout_height="48dp"
-                      android:layout_marginTop="4dp"
-                      android:layout_marginEnd="4dp"
-                      android:paddingStart="8dp"
-                      android:paddingEnd="8dp"
-                      android:paddingTop="4dp"
-                      android:paddingBottom="4dp"
-                      android:focusable="true"
-                      android:visibility="gone"
-                      style="?attr/borderlessButtonStyle">
-            <ImageView android:id="@+id/icon"
-                       android:layout_width="24dp"
-                       android:layout_height="24dp"
-                       android:layout_gravity="start|center_vertical"
-                       android:layout_marginStart="4dp"
-                       android:layout_marginEnd="16dp"
-                       android:layout_marginTop="12dp"
-                       android:layout_marginBottom="12dp"
-                       android:scaleType="fitCenter" />
-            <TextView android:id="@id/text1"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_gravity="start|center_vertical"
-                      android:layout_marginEnd="16dp"
-                      android:textAppearance="?attr/textAppearanceButton"
-                      android:textColor="?attr/textColorPrimary"
-                      android:minLines="1"
-                      android:maxLines="1"
-                      android:ellipsize="marquee" />
-        </LinearLayout>
-    </LinearLayout>
+                  android:paddingBottom="12dp"
+                  android:layout_below="@id/profile_button"
+                  android:layout_toRightOf="@id/title_icon"/>
+    </RelativeLayout>
 
     <ListView
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/language_picker_item.xml b/core/res/res/layout/language_picker_item.xml
index 22cb514..88012a9 100644
--- a/core/res/res/layout/language_picker_item.xml
+++ b/core/res/res/layout/language_picker_item.xml
@@ -14,37 +14,16 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:tools="http://schemas.android.com/tools"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:gravity="center_vertical"
-              android:orientation="horizontal"
-              android:layoutDirection="locale"
-              android:textDirection="locale"
-              android:paddingBottom="8dp"
-              android:paddingTop="8dp">
-
-    <TextView
-        android:id="@+id/locale"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        tools:text="France"
-        android:layout_weight="1"
-        android:padding="12dp"
-        android:paddingStart="18dp"
-        android:paddingEnd="18dp"
-        android:textAppearance="?android:attr/textAppearanceListItem"/>
-
-    <ImageView
-        android:id="@+id/l10nWarn"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:src="@android:drawable/stat_sys_warning"
-        android:focusableInTouchMode="false"
-        android:focusable="false"
-        android:paddingStart="12dp"
-        android:paddingEnd="12dp"
-        android:tint="?android:attr/colorAccent"/>
-
-</LinearLayout>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:id="@+id/locale"
+          android:gravity="center_vertical"
+          android:minHeight="?android:attr/listPreferredItemHeight"
+          android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+          android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+          android:textAppearance="?android:attr/textAppearanceListItem"
+          android:layoutDirection="locale"
+          android:textDirection="locale"
+          android:paddingBottom="8dp"
+          android:paddingTop="8dp" />
diff --git a/core/res/res/layout/language_picker_section_header.xml b/core/res/res/layout/language_picker_section_header.xml
index b12ec8c..6cbd7c3 100644
--- a/core/res/res/layout/language_picker_section_header.xml
+++ b/core/res/res/layout/language_picker_section_header.xml
@@ -23,4 +23,5 @@
           android:paddingStart="18dp"
           android:paddingEnd="18dp"
           android:textColor="?android:attr/colorAccent"
+          android:textStyle="bold"
           tools:text="@string/language_picker_section_all"/>
diff --git a/core/res/res/layout/notification_action_list.xml b/core/res/res/layout/notification_action_list.xml
deleted file mode 100644
index 400decc..0000000
--- a/core/res/res/layout/notification_action_list.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/actions"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:visibility="gone"
-    android:layout_marginBottom="8dp"
-    android:showDividers="middle"
-    android:divider="?android:attr/listDivider"
-    android:dividerPadding="12dp"
-    >
-    <!-- actions will be added here -->
-</LinearLayout>
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 2a4aa96..ac37c4a 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -17,9 +17,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/actions_container"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="-16dp"
-        android:layout_marginEnd="-16dp">
+        android:layout_height="wrap_content">
     <LinearLayout
             android:id="@+id/actions"
             android:layout_width="match_parent"
@@ -28,7 +26,7 @@
             android:orientation="horizontal"
             android:gravity="center_vertical"
             android:visibility="gone"
-            android:background="#ffeeeeee"
+            android:background="@color/notification_action_list"
             >
         <!-- actions will be added here -->
     </LinearLayout>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 6669bae..0bbaa24 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -20,9 +20,9 @@
     android:id="@+id/notification_header"
     android:orientation="horizontal"
     android:layout_width="wrap_content"
-    android:layout_height="48dp"
+    android:layout_height="53dp"
     android:clipChildren="false"
-    android:paddingTop="5dp"
+    android:paddingTop="10dp"
     android:paddingBottom="16dp"
     android:paddingStart="@dimen/notification_content_margin_start"
     android:paddingEnd="16dp">
@@ -33,16 +33,6 @@
         android:layout_marginEnd="3dp"
         />
     <TextView
-        android:id="@+id/number_of_children"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="@style/TextAppearance.Material.Notification"
-        android:layout_marginEnd="3dp"
-        android:layout_marginStart="2dp"
-        android:visibility="gone"
-        android:singleLine="true"
-        />
-    <TextView
         android:id="@+id/app_name_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index a37bfa9..ccd26fb 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -41,7 +41,7 @@
         android:layout_height="wrap_content"
         android:layout_gravity="bottom"
         android:layout_marginStart="@dimen/notification_content_margin_start"
-        android:layout_marginBottom="11dp"
+        android:layout_marginBottom="15dp"
         android:layout_marginEnd="@dimen/notification_content_margin_end" >
         <include layout="@layout/notification_template_progress" />
     </FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index f302087..c54fa18 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -49,7 +49,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="bottom"
             android:layout_marginStart="@dimen/notification_content_margin_start"
-            android:layout_marginBottom="11dp"
+            android:layout_marginBottom="15dp"
             android:layout_marginEnd="@dimen/notification_content_margin_end">
             <include layout="@layout/notification_template_progress" />
         </FrameLayout>
@@ -60,9 +60,5 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
     />
-    <include
-        layout="@layout/notification_material_action_list"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
+    <include layout="@layout/notification_material_action_list" />
 </LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index a5ed187..04ea12d 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -25,7 +25,7 @@
     >
     <include layout="@layout/notification_template_header"
         android:layout_width="match_parent"
-        android:layout_height="48dp"
+        android:layout_height="53dp"
         android:layout_gravity="start"/>
     <LinearLayout
         android:layout_width="match_parent"
@@ -50,9 +50,10 @@
             android:id="@+id/media_actions"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="-15dp"
+            android:layout_marginTop="-21dp"
             android:paddingStart="8dp"
-            android:paddingBottom="8dp"
+            android:paddingBottom="12dp"
+            android:gravity="top"
             android:orientation="horizontal"
             android:layoutDirection="ltr"
             >
@@ -65,7 +66,7 @@
         android:layout_height="@dimen/media_notification_expanded_image_max_size"
         android:minWidth="40dp"
         android:layout_marginEnd="16dp"
-        android:layout_marginBottom="16dp"
+        android:layout_marginBottom="20dp"
         android:layout_gravity="bottom|end"
         android:scaleType="centerCrop"
         />
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index 50aec6b..d87b9d9 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -27,8 +27,6 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="top"
-            android:paddingStart="@dimen/notification_content_margin_start"
-            android:paddingEnd="@dimen/notification_content_margin_end"
             android:layout_marginTop="@dimen/notification_content_margin_top"
             android:clipToPadding="false"
             android:orientation="vertical"
@@ -37,6 +35,8 @@
             android:id="@+id/notification_main_column"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
             android:orientation="vertical">
             <include layout="@layout/notification_template_part_line1"/>
             <include layout="@layout/notification_template_progress"/>
@@ -50,14 +50,15 @@
                 android:layout_weight="1"
                 android:layout_marginTop="13dp"
                 android:layout_marginBottom="16dp"
+                android:layout_marginStart="@dimen/notification_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
                 android:scaleType="centerCrop"
                 />
+
         <ViewStub android:layout="@layout/notification_material_reply_text"
                 android:id="@+id/notification_material_reply_container"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginStart="-16dp"
-                android:layout_marginEnd="-16dp"
                 />
         <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 9a4b28c..3638b20 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -22,38 +22,45 @@
     android:tag="bigText"
     >
     <include layout="@layout/notification_template_header" />
+
     <LinearLayout
-        android:id="@+id/notification_main_column"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:paddingStart="@dimen/notification_content_margin_start"
-        android:paddingEnd="@dimen/notification_content_margin_end"
-        android:layout_marginTop="@dimen/notification_content_margin_top"
-        android:clipToPadding="false"
-        android:minHeight="@dimen/notification_min_content_height"
-        android:orientation="vertical"
-        >
-        <include layout="@layout/notification_template_part_line1" />
-        <include layout="@layout/notification_template_progress" />
-        <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
             android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_marginTop="1.5dp"
-            android:paddingBottom="@dimen/notification_content_margin_bottom"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:singleLine="false"
-            android:layout_weight="1"
-            android:gravity="top"
-            android:visibility="gone"
-            />
+            android:layout_height="match_parent"
+            android:layout_gravity="top"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:clipToPadding="false"
+            android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:paddingStart="@dimen/notification_content_margin_start"
+            android:paddingEnd="@dimen/notification_content_margin_end"
+            android:clipToPadding="false"
+            android:minHeight="@dimen/notification_min_content_height"
+            android:orientation="vertical"
+            >
+            <include layout="@layout/notification_template_part_line1" />
+            <include layout="@layout/notification_template_progress" />
+            <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_marginTop="0.5dp"
+                android:paddingBottom="@dimen/notification_content_margin_bottom"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:singleLine="false"
+                android:layout_weight="1"
+                android:gravity="top"
+                android:visibility="gone"
+                />
+        </LinearLayout>
+
         <ViewStub android:layout="@layout/notification_material_reply_text"
                 android:id="@+id/notification_material_reply_container"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="-16dp"
-                android:layout_marginEnd="-16dp"
-        />
+                android:layout_height="wrap_content" />
         <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
     <include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 86902db..ce9acda 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -23,87 +23,99 @@
     >
     <include layout="@layout/notification_template_header" />
     <LinearLayout
-        android:id="@+id/notification_main_column"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:paddingStart="@dimen/notification_content_margin_start"
-        android:paddingEnd="@dimen/notification_content_margin_end"
-        android:layout_marginTop="@dimen/notification_content_margin_top"
-        android:minHeight="@dimen/notification_min_content_height"
-        android:clipToPadding="false"
-        android:orientation="vertical"
-        >
-        <include layout="@layout/notification_template_part_line1"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-        <include layout="@layout/notification_template_progress"
+            android:layout_height="match_parent"
+            android:layout_gravity="top"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:clipToPadding="false"
+            android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/notification_main_column"
             android:layout_width="match_parent"
-            android:layout_height="15dp"
-            android:layout_marginTop="4dp"/>
-        <TextView android:id="@+id/inbox_text0"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <TextView android:id="@+id/inbox_text1"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <TextView android:id="@+id/inbox_text2"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <TextView android:id="@+id/inbox_text3"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <TextView android:id="@+id/inbox_text4"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <TextView android:id="@+id/inbox_text5"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <TextView android:id="@+id/inbox_text6"
-            android:textAppearance="@style/TextAppearance.Material.Notification"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:paddingStart="@dimen/notification_content_margin_start"
+            android:paddingEnd="@dimen/notification_content_margin_end"
+            android:minHeight="@dimen/notification_min_content_height"
+            android:clipToPadding="false"
+            android:orientation="vertical"
+            >
+            <include layout="@layout/notification_template_part_line1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+            <include layout="@layout/notification_template_progress"
+                android:layout_width="match_parent"
+                android:layout_height="15dp"
+                android:layout_marginTop="4dp"/>
+            <TextView android:id="@+id/inbox_text0"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text1"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text2"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text3"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text4"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text5"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+            <TextView android:id="@+id/inbox_text6"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:visibility="gone"
+                android:layout_weight="1"
+                />
+        </LinearLayout>
+        <ViewStub android:layout="@layout/notification_material_reply_text"
+                android:id="@+id/notification_material_reply_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
         <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
     <include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index cda0636..ba6d30a 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -24,7 +24,7 @@
     >
     <include layout="@layout/notification_template_header"
         android:layout_width="fill_parent"
-        android:layout_height="48dp" />
+        android:layout_height="53dp" />
     <LinearLayout
         android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
@@ -51,10 +51,10 @@
         <LinearLayout
             android:id="@+id/media_actions"
             android:layout_width="wrap_content"
-            android:layout_height="match_parent"
+            android:layout_height="wrap_content"
             android:layout_gravity="bottom|end"
             android:layout_marginStart="10dp"
-            android:layout_marginBottom="8dp"
+            android:layout_marginBottom="12dp"
             android:layoutDirection="ltr"
             android:orientation="horizontal"
             >
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index 3b358ab..15ccc67 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -19,7 +19,7 @@
     android:layout_width="40dp"
     android:layout_height="40dp"
     android:layout_marginEnd="16dp"
-    android:layout_marginTop="32dp"
+    android:layout_marginTop="36dp"
     android:layout_gravity="top|end"
     android:scaleType="centerCrop"
     />
diff --git a/core/res/res/layout/notification_template_text.xml b/core/res/res/layout/notification_template_text.xml
index 38470cd..a318bda 100644
--- a/core/res/res/layout/notification_template_text.xml
+++ b/core/res/res/layout/notification_template_text.xml
@@ -14,12 +14,12 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.ImageFloatingTextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/text"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="top"
-    android:layout_marginTop="1.5dp"
+    android:layout_marginTop="0.5dp"
     android:ellipsize="marquee"
     android:fadingEdge="horizontal"
     android:gravity="top"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 00c25e6..fe43e1c 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -25,56 +25,43 @@
     android:maxCollapsedHeightSmall="56dp"
     android:id="@id/contentPanel">
 
-    <LinearLayout
+    <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alwaysShow="true"
         android:elevation="8dp"
-        android:background="@color/white" >
-        <TextView android:id="@+id/title"
-                  android:layout_width="0dp"
-                  android:layout_height="wrap_content"
-                  android:layout_weight="1"
-                  android:minHeight="56dp"
-                  android:textAppearance="?attr/textAppearanceMedium"
-                  android:gravity="start|center_vertical"
-                  android:paddingStart="?attr/dialogPreferredPadding"
-                  android:paddingEnd="?attr/dialogPreferredPadding"
-                  android:paddingTop="8dp"
-                  android:paddingBottom="8dp" />
-        <LinearLayout android:id="@+id/profile_button"
-                      android:layout_width="wrap_content"
-                      android:layout_height="48dp"
-                      android:layout_marginTop="4dp"
-                      android:layout_marginEnd="4dp"
-                      android:paddingStart="8dp"
-                      android:paddingEnd="8dp"
-                      android:paddingTop="4dp"
-                      android:paddingBottom="4dp"
-                      android:focusable="true"
-                      android:visibility="gone"
-                      style="?attr/borderlessButtonStyle">
-            <ImageView android:id="@+id/icon"
-                       android:layout_width="24dp"
-                       android:layout_height="24dp"
-                       android:layout_gravity="start|center_vertical"
-                       android:layout_marginStart="4dp"
-                       android:layout_marginEnd="16dp"
-                       android:layout_marginTop="12dp"
-                       android:layout_marginBottom="12dp"
-                       android:scaleType="fitCenter" />
-            <TextView android:id="@id/text1"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_gravity="start|center_vertical"
-                      android:layout_marginEnd="16dp"
-                      android:textAppearance="?attr/textAppearanceButton"
-                      android:textColor="?attr/textColorPrimary"
-                      android:minLines="1"
-                      android:maxLines="1"
-                      android:ellipsize="marquee" />
-        </LinearLayout>
-    </LinearLayout>
+        android:background="@color/white">
+
+        <TextView
+            android:id="@+id/profile_button"
+            android:layout_width="wrap_content"
+            android:layout_height="48dp"
+            android:layout_marginEnd="8dp"
+            android:paddingStart="8dp"
+            android:paddingEnd="8dp"
+            android:visibility="gone"
+            style="?attr/borderlessButtonStyle"
+            android:textAppearance="?attr/textAppearanceButton"
+            android:textColor="@color/material_deep_teal_500"
+            android:gravity="center_vertical"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:singleLine="true" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minHeight="56dp"
+            android:textAppearance="?attr/textAppearanceMedium"
+            android:gravity="start|center_vertical"
+            android:paddingStart="?attr/dialogPreferredPadding"
+            android:paddingEnd="?attr/dialogPreferredPadding"
+            android:paddingTop="8dp"
+            android:layout_below="@id/profile_button"
+            android:layout_alignParentLeft="true"
+            android:paddingBottom="8dp" />
+    </RelativeLayout>
 
     <ListView
         android:layout_width="match_parent"
@@ -85,21 +72,23 @@
         android:background="@color/white"
         android:elevation="8dp"
         android:nestedScrollingEnabled="true"
+        android:scrollIndicators="top|bottom"
         android:divider="@null" />
 
-    <TextView android:id="@+id/empty"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layout_alwaysShow="true"
-              android:text="@string/noApplications"
-              android:padding="32dp"
-              android:gravity="center"
-              android:visibility="gone" />
+    <TextView
+        android:id="@+id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alwaysShow="true"
+        android:text="@string/noApplications"
+        android:padding="32dp"
+        android:gravity="center"
+        android:visibility="gone" />
 
     <LinearLayout
         android:id="@+id/button_bar"
         android:visibility="gone"
-        style="?android:attr/buttonBarStyle"
+        style="?attr/buttonBarStyle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_ignoreOffset="true"
@@ -114,26 +103,30 @@
         android:paddingStart="12dp"
         android:paddingEnd="12dp"
         android:elevation="8dp">
-        <Button android:id="@+id/button_once"
-                android:layout_width="wrap_content"
-                android:layout_gravity="start"
-                android:maxLines="2"
-                style="?android:attr/buttonBarNegativeButtonStyle"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content"
-                android:enabled="false"
-                android:text="@string/activity_resolver_use_once"
-                android:onClick="onButtonClick" />
-        <Button android:id="@+id/button_always"
-                android:layout_width="wrap_content"
-                android:layout_gravity="end"
-                android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                style="?android:attr/buttonBarPositiveButtonStyle"
-                android:layout_height="wrap_content"
-                android:enabled="false"
-                android:text="@string/activity_resolver_use_always"
-                android:onClick="onButtonClick" />
+
+        <Button
+            android:id="@+id/button_once"
+            android:layout_width="wrap_content"
+            android:layout_gravity="start"
+            android:maxLines="2"
+            style="?attr/buttonBarNegativeButtonStyle"
+            android:minHeight="@dimen/alert_dialog_button_bar_height"
+            android:layout_height="wrap_content"
+            android:enabled="false"
+            android:text="@string/activity_resolver_use_once"
+            android:onClick="onButtonClick" />
+
+        <Button
+            android:id="@+id/button_always"
+            android:layout_width="wrap_content"
+            android:layout_gravity="end"
+            android:maxLines="2"
+            android:minHeight="@dimen/alert_dialog_button_bar_height"
+            style="?attr/buttonBarPositiveButtonStyle"
+            android:layout_height="wrap_content"
+            android:enabled="false"
+            android:text="@string/activity_resolver_use_always"
+            android:onClick="onButtonClick" />
     </LinearLayout>
 
 </com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 31361e5..ed7ef5e 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -22,8 +22,7 @@
     android:layout_height="match_parent"
     android:maxWidth="@dimen/resolver_max_width"
     android:maxCollapsedHeight="144dp"
-    android:id="@id/contentPanel"
-    >
+    android:id="@id/contentPanel">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -31,66 +30,75 @@
         android:layout_alwaysShow="true"
         android:orientation="vertical"
         android:background="@color/white"
-        android:elevation="8dp" >
+        android:elevation="8dp">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="64dp"
-            android:orientation="horizontal" >
+            android:orientation="horizontal">
 
-            <ImageView android:id="@+id/icon"
-                       android:layout_width="24dp"
-                       android:layout_height="24dp"
-                       android:layout_gravity="start|top"
-                       android:layout_marginStart="16dp"
-                       android:layout_marginEnd="16dp"
-                       android:layout_marginTop="20dp"
-                       android:scaleType="fitCenter" />
-            <TextView android:id="@+id/title"
-                      android:layout_width="0dp"
-                      android:layout_weight="1"
-                      android:layout_height="?android:attr/listPreferredItemHeight"
-                      android:layout_marginStart="16dp"
-                      android:textAppearance="?android:attr/textAppearanceMedium"
-                      android:gravity="start|center_vertical"
-                      android:paddingEnd="16dp" />
-            <LinearLayout android:id="@+id/profile_button"
-                          android:layout_width="wrap_content"
-                          android:layout_height="48dp"
-                          android:layout_marginTop="4dp"
-                          android:layout_marginEnd="4dp"
-                          android:paddingStart="8dp"
-                          android:paddingEnd="8dp"
-                          android:paddingTop="4dp"
-                          android:paddingBottom="4dp"
-                          android:focusable="true"
-                          android:visibility="gone"
-                          style="?attr/borderlessButtonStyle">
-                <ImageView android:id="@+id/icon"
-                           android:layout_width="24dp"
-                           android:layout_height="24dp"
-                           android:layout_gravity="start|center_vertical"
-                           android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
-                           android:layout_marginTop="12dp"
-                           android:layout_marginBottom="12dp"
-                           android:scaleType="fitCenter" />
-                <TextView android:id="@id/text1"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:layout_gravity="start|center_vertical"
-                          android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
-                          android:textAppearance="?attr/textAppearanceButton"
-                          android:textColor="?attr/textColorPrimary"
-                          android:minLines="1"
-                          android:maxLines="1"
-                          android:ellipsize="marquee" />
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:layout_gravity="start|top"
+                android:layout_marginStart="16dp"
+                android:layout_marginEnd="16dp"
+                android:layout_marginTop="20dp"
+                android:scaleType="fitCenter" />
+
+            <TextView
+                android:id="@+id/title"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="?attr/listPreferredItemHeight"
+                android:layout_marginStart="16dp"
+                android:textAppearance="?attr/textAppearanceMedium"
+                android:gravity="start|center_vertical"
+                android:paddingEnd="16dp" />
+
+            <LinearLayout
+                android:id="@+id/profile_button"
+                android:layout_width="wrap_content"
+                android:layout_height="48dp"
+                android:layout_marginTop="4dp"
+                android:layout_marginEnd="4dp"
+                android:paddingStart="8dp"
+                android:paddingEnd="8dp"
+                android:paddingTop="4dp"
+                android:paddingBottom="4dp"
+                android:focusable="true"
+                android:visibility="gone"
+                style="?attr/borderlessButtonStyle">
+
+                <ImageView
+                    android:id="@+id/icon"
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
+                    android:layout_gravity="start|center_vertical"
+                    android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginBottom="12dp"
+                    android:scaleType="fitCenter" />
+
+                <TextView
+                    android:id="@id/text1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="start|center_vertical"
+                    android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+                    android:textAppearance="?attr/textAppearanceButton"
+                    android:textColor="?attr/textColorPrimary"
+                    android:minLines="1"
+                    android:maxLines="1"
+                    android:ellipsize="marquee" />
             </LinearLayout>
         </LinearLayout>
 
         <LinearLayout
             android:id="@+id/button_bar"
             android:visibility="gone"
-            style="?android:attr/buttonBarStyle"
+            style="?attr/buttonBarStyle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_alwaysShow="true"
@@ -104,30 +112,36 @@
             android:paddingEnd="12dp"
             android:background="@color/white"
             android:elevation="8dp">
-            <Button android:id="@+id/button_once"
-                    android:layout_width="wrap_content"
-                    android:layout_gravity="start"
-                    android:maxLines="2"
-                    style="?android:attr/buttonBarNegativeButtonStyle"
-                    android:minHeight="@dimen/alert_dialog_button_bar_height"
-                    android:layout_height="wrap_content"
-                    android:enabled="false"
-                    android:text="@string/activity_resolver_use_once"
-                    android:onClick="onButtonClick" />
-            <Button android:id="@+id/button_always"
-                    android:layout_width="wrap_content"
-                    android:layout_gravity="end"
-                    android:maxLines="2"
-                    android:minHeight="@dimen/alert_dialog_button_bar_height"
-                    style="?android:attr/buttonBarPositiveButtonStyle"
-                    android:layout_height="wrap_content"
-                    android:enabled="false"
-                    android:text="@string/activity_resolver_use_always"
-                    android:onClick="onButtonClick" />
+
+            <Button
+                android:id="@+id/button_once"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:maxLines="2"
+                style="?attr/buttonBarNegativeButtonStyle"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content"
+                android:enabled="false"
+                android:text="@string/activity_resolver_use_once"
+                android:onClick="onButtonClick" />
+
+            <Button
+                android:id="@+id/button_always"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?attr/buttonBarPositiveButtonStyle"
+                android:layout_height="wrap_content"
+                android:enabled="false"
+                android:text="@string/activity_resolver_use_always"
+                android:onClick="onButtonClick" />
         </LinearLayout>
-        <View android:layout_width="match_parent"
-              android:layout_height="1dp"
-              android:background="?android:attr/dividerVertical" />
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="?attr/dividerVertical" />
     </LinearLayout>
 
     <ListView
@@ -140,6 +154,6 @@
         android:elevation="8dp"
         android:nestedScrollingEnabled="true"
         android:divider="@null"
-        />
+        android:scrollIndicators="top|bottom" />
 
 </com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/select_dialog_material.xml b/core/res/res/layout/select_dialog_material.xml
index 19ad407..9a068f9a 100644
--- a/core/res/res/layout/select_dialog_material.xml
+++ b/core/res/res/layout/select_dialog_material.xml
@@ -30,6 +30,6 @@
     android:scrollbars="vertical"
     android:overScrollMode="ifContentScrolls"
     android:textAlignment="viewStart"
-    android:paddingTop="@dimen/dialog_list_padding_vertical_material"
-    android:paddingBottom="@dimen/dialog_list_padding_vertical_material"
-    android:clipToPadding="false" />
+    android:clipToPadding="false"
+    android:paddingBottomNoButtons="@dimen/dialog_list_padding_bottom_no_buttons"
+    android:paddingTopNoTitle="@dimen/dialog_list_padding_top_no_title" />
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 20a80489..d1c65c0 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -31,9 +31,9 @@
         android:showDividers="middle">
         <ListView
             android:id="@+id/suggestionContainer"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="8dp"
+            android:paddingTop="4dp"
             android:paddingBottom="0dp"
             android:divider="@null" />
         <LinearLayout
diff --git a/core/res/res/layout/work_widget_mask_view.xml b/core/res/res/layout/work_widget_mask_view.xml
index ce86ddc..3c47705 100644
--- a/core/res/res/layout/work_widget_mask_view.xml
+++ b/core/res/res/layout/work_widget_mask_view.xml
@@ -15,20 +15,24 @@
     limitations under the License.
 -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/work_widget_mask_frame"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#F3374248" >
+    android:background="#F3374248"
+    android:clickable="true" >
 
     <ImageView android:id="@+id/work_widget_app_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"/>
+        android:layout_gravity="center"
+        android:clickable="false" />
 
-    <ImageView
+    <ImageView android:id="@+id/work_widget_badge_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="bottom|right"
         android:layout_marginBottom="4dp"
         android:layout_marginRight="4dp"
-        android:src="@drawable/ic_corp_badge_off" />
+        android:src="@drawable/ic_corp_badge_off"
+        android:clickable="false" />
 </FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6b158dc..2a16a1e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Beller-ID se verstek is nie beperk nie. Volgende oproep: nie beperk nie"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Diens nie verskaf nie."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Jy kan nie die beller-ID-instelling verander nie."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Beperkte toegang het verander"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datadiens word geblokkeer."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nooddiens word geblokkeer."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Stemdiens word geblokkeer."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Stembystand"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Sluit nou"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhoud word versteek volgens beleid"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Skakel oor na persoonlik"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Skakel oor na werk"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"in te gaan by jou kontakte"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigeer met %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Deel met"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Deel met %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Stuur met"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Stuur met %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Kies \'n Tuis-program"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Gebruik %1$s as Tuis"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Gebruik hierdie aksie by verstek."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Stel terug en herbegin program"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Stuur terugvoer"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Maak toe"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Demp"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Demp totdat toestel herbegin"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Wag"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Maak program toe"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Geen toestemmings benodig nie"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dit kan jou dalk geld kos"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB vir batterylaai"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB laai tans hierdie toestel"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB verskaf tans krag aan gekoppelde toestel"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB vir lêeroordrag"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB vir foto-oordrag"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB vir MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Raak vir meer opsies."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-ontfouter gekoppel"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Raak om USB-ontfouting te deaktiveer."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AANVAAR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIER"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Neem tans foutverslag …"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deel foutverslag?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deel tans foutverslag …"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Jou IT-administrateur het \'n foutverslag versoek om met die foutsporing van hierdie toestel te help. Programme en data sal dalk gedeel word."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEEL"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIER"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Verander sleutelbord"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Kies sleutelborde"</string>
     <string name="show_ime" msgid="2506087537466597099">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
     <string name="hardware" msgid="194658061510127999">"Wys virtuele sleutelbord"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Kies sleutelborduitleg"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Raak om \'n sleutelborduitleg te kies."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Stel fisieke sleutelbord op"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-luisteraar"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Toestandverskaffer"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Kennisgewingassistent"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Kennisgewingklassifiseringsdiens"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Meer opsies"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s - %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s-%2$s%3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interne geheue"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Interne gedeelde berging"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g>-SD-kaart"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-datastokkie"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vra PIN voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vra ontsluitpatroon voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vra wagwoord voordat jy ontspeld"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Program se grootte kan nie verander word nie; rollees dit met twee vingers."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Program sal dalk nie met verdeelde skerm werk nie."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Program steun nie verdeelde skerm nie."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Deur jou administrateur geïnstalleer"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Opgedateer deur jou administrateur"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> gekies</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrik as gevolg van die mense wat betrokke is."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Taalvoorkeur"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Voeg \'n taal by"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Streekvoorkeur"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Voer taalnaam in"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgestel"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is AF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Stel werkprofiel in staat om te werk, insluitend programme, agtergrondsinkronisering en verwante kenmerke."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Skakel aan"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Deur %1$s gedeaktiveer"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Deur %1$s-administrateur gedeaktiveer. Kontak hulle om meer uit te vind."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Jy het nuwe boodskappe"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Maak SMS-program oop om te bekyk"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Sommige funksies kan beperk wees"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Speld vas"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Ontspeld"</string>
     <string name="app_info" msgid="6856026610594615344">"Programinligting"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Doen \'n fabriekterugstelling om hierdie toestel sonder beperkinge te gebruik"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Raak om meer te wete te kom."</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 5332c62..0668c35 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"የደዋይ ID ነባሪዎች ወደአልተከለከለም። ቀጥሎ ጥሪ፡አልተከለከለም"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"የድምጽ እርዳታ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"አሁን ቆልፍ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ይዘቶች በመመሪያ ተደብቀዋል"</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="user_owner_label" msgid="1119010402169916617">"ወደ የግል ቀይር"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"ወደ ሥራ ቀይር"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ዕውቂያዎች"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"የእርስዎ እውቂያዎች ላይ ይድረሱባቸው"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"መገኛ አካባቢ"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ያርትዑ በ%1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"በሚከተለው ያጋሩ፦"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"በ%1$s ያጋሩ"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ይላኩ በ፦"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$sን በመጠቀም ይላኩ"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"የመነሻ መተግበሪያ ይምረጡ"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$sን እንደመነሻ ይጠቀሙ"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ለዕርምጃ ነባሪ ተጠቀም።"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ዳግም ያቀናብሩ እና መተግበሪያ ዳግም ያስጀምሩት"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ግብረመልስ ይላኩ"</string>
     <string name="aerr_close" msgid="2991640326563991340">"ዝጋ"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"ድምጽ-ከል አድርግ"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"መሣሪያ ዳግም እስኪጀመር ድረስ ድምጽ ያጥፉ"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"ጠብቅ"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"መተግበሪያን ዝጋ"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎት ይችላል"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"እሺ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ዩኤስቢ ለኃይል መሙላት"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ዩኤስቢ የዚህን መሣሪያ ኃይል በመሙላት ላይ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ዩኤስቢ ለተያያዘው መሣሪያ ኃይል በማቅረብ ላይ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ዩኤስቢ ለፋይል ሽግግር"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ዩኤስቢ ለፎቶ ሽግግር"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"ዩኤስቢ ለMIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"ለተጨማሪ አማራጮች ነካ ያድርጉ።"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB አድስ ተያይዟል"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ማረሚያ ላለማንቃት ዳስስ።"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ተቀበል"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ውድቅ አድርግ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"የሳንካ ሪፖርትን በመውሰድ ላይ…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"የሳንካ ሪፖርት ይጋራ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"የሳንካ ሪፖርትን በማጋራት ላይ…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"የእርስዎ አይቲ አስተዳዳሪ ለዚህ መሣሪያ መላ ለመፈለግ የሳንካ ሪፖርት ጠይቀዋል። መተግበሪያዎች እና ውሂብ ሊጋሩ ይችላሉ።"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"አጋራ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"አትቀበል"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ቁልፍ ሰሌዳ ይቀይሩ"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"ቁልፍ ሰሌዳዎችን ምረጥ"</string>
     <string name="show_ime" msgid="2506087537466597099">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገጽ ላይ አቆየው"</string>
     <string name="hardware" msgid="194658061510127999">"ምናባዊ የቁልፍ ሰሌዳን አሳይ"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"የቁልፍ ሰሌዳ አቀማመጥ ምረጥ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"የቁልፍ ሰሌዳ አቀማመጥ ለመምረጥ ንካ።"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"አካላዊ ቁልፍ ሰሌዳን ያዋቅሩ"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ልጣፍ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"የምናባዊ እውነታ አዳማጭ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"የሁኔታ አቅራቢ"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"የማሳወቂያ ረዳት"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"የማሳወቂያ ደረጃ ሰጪ አገልግሎት"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ተጨማሪ አማራጮች"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s፣ %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s፣ %2$s፣ %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"ውስጣዊ ማከማቻ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"የውስጥ የተጋራ ማከማቻ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD ካርድ"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> ኤስዲ ካርድ"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"የዩኤስቢ አንጻፊ"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ከመንቀል በፊት ፒን ጠይቅ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ከመንቀል በፊት የማስከፈቻ ስርዓተ-ጥለት ጠይቅ"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ከመንቀል በፊት የይለፍ ቃል ጠይቅ"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"የመተግበሪያው መጠን ሊቀየር የሚችል አይደለም፣ በሁለት ጣቶች ያሸብልሉት።"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"መተግበሪያ ከተከፈለ ማያ ገጽ ጋር ላይሠራ ይችላል"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"በእርስዎ አስተዳዳሪ ተጭኗል"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"በአስተዳዳሪዎ ተዘምኗል"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጧል</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"የተለያዩ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት (ይህ መለያ ያለው ተጠቃሚ አስቀድሞ አለ)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"የቋንቋ ምርጫ"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ቋንቋ ያክሉ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"የክልል ምርጫ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"የቋንቋ ስም ይተይቡ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"የተጠቆሙ"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"የሥራ ሁነታ ጠፍቷል"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"መተግበሪያዎችን፣ የበስተጀርባ ሥምረት እና ተዛማጅ ባሕሪዎችን ጨምሮ የሥራ መገለጫ እንዲሰራ ይፍቀዱ።"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"አብራ"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s ተሰናክሏል"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"በ%1$s አስተዳዳሪ ተሰናክሏል። የበለጠ ለመረዳት ያነጋግሯቸው።"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"አዲስ መልእክቶች አለዎት"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"ለመመልከት የኤስኤምኤስ መተግበሪያ ይክፈቱ"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"አንዳንድ ተግባሮች የተገደቡ ሊሆኑ ይችላሉ"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"ፒን"</string>
     <string name="unpin_target" msgid="3556545602439143442">"ንቀል"</string>
     <string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"ይህን መሣሪያ ያለምንም ገደብ ለመጠቀም የፋብሪካ ዳግም ያስጀምሩ"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"የበለጠ ለመረዳት ይንኩ።"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e592fb9..6a7c76c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -92,7 +92,6 @@
     <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>
@@ -238,13 +237,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"المساعد الصوتي"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"قفل الآن"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"تم إخفاء المحتويات بواسطة السياسة"</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="user_owner_label" msgid="1119010402169916617">"التبديل إلى الشخصي"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"التبديل إلى العمل"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"جهات الاتصال"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"الوصول إلى جهات اتصالك"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"الموقع"</string>
@@ -925,6 +923,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏تعديل باستخدام %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"مشاركة مع"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"‏مشاركة مع %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"إرسال باستخدام"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"‏إرسال باستخدام %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"تحديد تطبيق صفحة رئيسية"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"‏استخدام %1$s كصفحة رئيسية"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"الاستخدام بشكل افتراضي لهذا الإجراء."</string>
@@ -941,7 +941,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"إعادة ضبط التطبيق وإعادة تشغيله"</string>
     <string name="aerr_report" msgid="5371800241488400617">"إرسال تعليقات"</string>
     <string name="aerr_close" msgid="2991640326563991340">"إغلاق"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"تجاهل"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"التعطيل حتى إعادة تشغيل الجهاز"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"انتظار"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"إغلاق التطبيق"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1077,7 +1077,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"لا أذونات مطلوبة"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"قد يكلفك هذا مالاً."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"موافق"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏USB للشحن"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏يتم استخدام الاتصال عبر USB لشحن هذا الجهاز"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏يتم استخدام الاتصال عبر USB لإمداد الجهاز المتصل بالطاقة"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏USB لنقل الملفات"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏USB لنقل الصور"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB لـ MIDI"</string>
@@ -1085,24 +1086,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"المس للحصول على مزيد من الخيارات."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏تم توصيل تصحيح أخطاء USB"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"‏المس لتعطيل تصحيح أخطاء USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"رفض"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"جارٍ الحصول على تقرير الخطأ…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"هل تريد مشاركة تقرير الخطأ؟"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"جارٍ مشاركة تقرير الخطأ…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير خطأ للمساعدة في تحرِّي مشكلة هذا الجهاز وإصلاحها؛ ويمكن أن تتم مشاركة التطبيقات والبيانات."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"مشاركة"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"رفض"</string>
     <string name="select_input_method" msgid="8547250819326693584">"تغيير لوحة المفاتيح"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"اختيار لوحات المفاتيح"</string>
     <string name="show_ime" msgid="2506087537466597099">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
     <string name="hardware" msgid="194658061510127999">"إظهار لوحة المفاتيح الظاهرية"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"تحديد تخطيط لوحة مفاتيح"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"المس لتحديد تخطيط لوحة مفاتيح."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"تهيئة لوحة المفاتيح الفعلية"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
@@ -1175,8 +1169,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"مستمع واقع افتراضي"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"موفر الحالة"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"مساعد الإشعار"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"خدمة ترتيب أهمية الإشعارات"</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>
@@ -1265,7 +1260,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"المزيد من الخيارات"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s، %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s، %2$s، %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"وحدة تخزين داخلية"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"السعة التخزينية المشتركة الداخلية"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"‏بطاقة SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏بطاقة SD من <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"‏محرك أقراص USB"</string>
@@ -1513,7 +1508,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"المطالبة برقم التعريف الشخصي قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"المطالبة بنقش إلغاء القفل قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"المطالبة بكلمة المرور قبل إزالة التثبيت"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"التطبيق غير قابل لتغيير الحجم، يمكنك تمريره بإصبعين."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"يمكن ألا يعمل التطبيق مع وضع تقسيم الشاشة."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"التطبيق لا يتيح تقسيم الشاشة."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"تم تثبيت الحزمة عن طريق المشرف"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"تم التحديث بواسطة المشرف"</string>
@@ -1619,12 +1614,11 @@
       <item quantity="other">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g> من العناصر</item>
       <item quantity="one">تم تحديد <xliff:g id="COUNT_0">%1$d</xliff:g> عنصر</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"متنوعة"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"لقد عيَّنت أهمية هذه الإشعارات."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"لقد عيَّنت أهمية هذه الإشعارات."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"هل تسمح لـ <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g>؟"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"هل تسمح لـ <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> (يوجد مستخدم بهذا الحساب مسبقًا)؟"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"تفضيل اللغة"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"إضافة لغة"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"تفضيل المنطقة"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"اكتب اسم اللغة"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"المقترحة"</string>
@@ -1633,8 +1627,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"وضع العمل معطَّل"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"السماح باستخدام الملف الشخصي للعمل، بما في ذلك التطبيقات ومزامنة الخلفية والميزات ذات الصلة."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"تشغيل"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"‏تم تعطيل %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"‏تم التعطيل بواسطة مشرف %1$s. يمكنك الاتصال به لمعرفة المزيد."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"لديك رسائل جديدة"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"‏فتح تطبيق الرسائل القصيرة SMS للعرض"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ربما تكون بعض الوظائف مُقيّدة."</string>
@@ -1647,4 +1639,7 @@
     <string name="pin_target" msgid="3052256031352291362">"تثبيت"</string>
     <string name="unpin_target" msgid="3556545602439143442">"إزالة تثبيت"</string>
     <string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"يمكنك إعادة تعيين بيانات المصنع لاستخدام هذا الجهاز بدون قيود"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"المس للتعرف على مزيد من المعلومات."</string>
 </resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 7313063..e76ce87 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Adətən zəng edənin ID\'si məhdudlaşdırılmır. Növbəti zəng: Məhdudlaşdırılmayıb"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Xidmət təmin edilməyib."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Siz zəng edənin ID nizamlarını dəyişə bilməzsiz."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Məhdudlaşdırılmış keçid dəyişdi"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Data xidmət bağlıdır."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Təcili xidmət bağlıdır."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Səs xidməti bağlıdır."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Səs Yardımçısı"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"İndi kilidləyin"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Məzmun gizlidir"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Məzmun siyasət tərəfindən gizlədilib"</string>
     <string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistemi"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Şəxsi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Şəxsi profilə keçirin"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"İş profilinə keçirin"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarınıza daxil olun"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Yer"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ilə düzəliş edin"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Bununla paylaşın"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s ilə paylaşın"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"İstifadə edərək göndərin"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s istifadə edərək göndərin"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Əsas tətbiqi seçin"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s tətbiqini Əsas olaraq işlədin"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Bu fəaliyyət üçün defolt istifadə edin"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Tətbiqi sıfırlayın və yenidən başladın"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Geri əlaqə göndərin"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Bağla"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Susdur"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Cihaz yeniden başladılana kimi səssiz edin"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Gözləyin"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Tətbiqi qapadın"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Heç bir icazə tələb olunmur"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"bununla sizdən xərc tutula bilər"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Enerji doldurmaq üçün USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB bu cihaza enerji doldurur"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Qolulmuş cihaz üçün USB enerji tədarükü"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fayl transferi üçün USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Foto transfer üçün USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI üçün USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Əlavə seçimlər üçün toxunun."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB sazlama qoşuludur"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB debaqı deaktivasiya etmək üçün toxunun."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"QƏBUL EDİN"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RƏDD ET"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Baq hesabatı verilir..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Baq hesabatı paylaşılsın?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Baq hesabatı paylaşılır..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"İT admininiz bu cihazda nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi. Tətbiqlər və data paylaşıla bilər."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞIN"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RƏDD EDİN"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Klaviaturanı dəyişin"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturaları seçin"</string>
     <string name="show_ime" msgid="2506087537466597099">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
     <string name="hardware" msgid="194658061510127999">"Virtual klaviaturanı göstərin"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klaviatura sxemi seçin"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Klaviatura tərtibatı seçmək üçün toxunun."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziki klaviaturanı konfiqurasiya edin"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Divar kağızı"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Divar kağızını dəyişin"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildiriş dinləyən"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR dinləyici"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Şərait provayderi"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildiriş köməkçisi"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Bildiriş qiymətləndirici xidmət"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN aktivləşdirildi"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> tərəfindən aktivləşdirilib"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Şəbəkəni idarə etmək üçün toxunun."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Əlavə seçimlər"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Daxili yaddaş"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Daxili paylaşılan yaddaş"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kart"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kart"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB drayv"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ayırmadan öncə PIN istənilsin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ayırmadan öncə kilid modeli istənilsin"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ayırmadan öncə parol istənilsin"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Tətbiq ölçüləndirilmədi, iki barmağınızla sürüşdürün."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Tətbiq bölünmüş ekran ilə işləməyə bilər."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Administratorunuz tərəfindən quraşdırılıb"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Sizin administrator tərəfindən yeniləndi"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seçilib</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Müxtəlif"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabı ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə<xliff:g id="ACCOUNT">%2$s</xliff:g> (bu hesab ilə İstifadəçi artıq mövcuddur) hesabı ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Dil seçimi"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Dil əlavə edin"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region seçimi"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını daxil edin"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Təklif edilmiş"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"İş rejimi DEAKTİVDİR"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Tətbiq, arxa fon sinxronizasiyası və digər əlaqədar xüsusiyyətlər daxil olmaqla iş profilinin fəaliyyətinə icazə verin."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Aktivləşdirin"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s dekativ edildi"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s administratoru tərəfindən deaktiv edildi. Ətraflı məlumat üçün onlarla əlaqə saxlayın."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Yeni mesajlarınız var"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Baxmaq üçün SMS tətbiqini açın"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Bir neçə funksionallıq məhdudlaşdırıla bilər"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Pin kod"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Çıxarın"</string>
     <string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı məhdudiyyətsiz istifadə etmək üçün zavod sıfırlaması edin"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha çox məlumat üçün toxunun."</string>
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 3206faa..9231e9a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -89,7 +89,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID pozivaoca podrazumevano nije ograničen. Sledeći poziv: Nije ograničen."</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Usluga nije dobavljena."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Ne možete da promenite podešavanje ID-a korisnika."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ograničeni pristup je promenjen"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Usluga za podatke je blokirana."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Usluga za hitne slučajeve je blokirana."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Glasovna usluga je blokirana."</string>
@@ -164,7 +163,7 @@
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše <xliff:g id="CONTENT_TYPE">%s</xliff:g> izbrisanih stavki."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Memorija tableta je puna! Izbrišite neke datoteke da 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="tv" msgid="516619861191025923">"Skladišni prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
+    <string name="low_memory" product="tv" msgid="516619861191025923">"Memorijski prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Skladište telefona je puno! Izbrišite neke datoteke kako biste oslobodili prostor."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadgleda"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
@@ -232,13 +231,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj odmah"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je sakriven"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je sakriven smernicama"</string>
     <string name="safeMode" msgid="2788228061547930246">"Bezbedni režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Pređi na Lični profil"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Pređi na profil za Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupi kontaktima"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -313,7 +311,7 @@
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori tablet."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Dozvoljava aplikaciji da neke svoje delove trajno zadrži u memoriji. To može da ograniči memoriju dostupnu drugim aplikacijama i uspori TV."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori telefon."</string>
-    <string name="permlab_getPackageSize" msgid="7472921768357981986">"merenje prostora za skladištenje u aplikaciji"</string>
+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"merenje memorijskog prostora u aplikaciji"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Dozvoljava aplikaciji da preuzme veličine kôda, podataka i keša."</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"izmena podešavanja sistema"</string>
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Dozvoljava aplikaciji da menja podatke o podešavanju sistema. Zlonamerne aplikacije mogu da oštete konfiguraciju sistema."</string>
@@ -886,9 +884,9 @@
     <string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Metod unosa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje u vezi sa tekstom"</string>
-    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za skladištenje je na izmaku"</string>
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memorijski prostor je na izmaku"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno skladišnog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili zaustavljanje aplikacije."</string>
     <string name="ok" msgid="5970060430562524910">"Potvrdi"</string>
@@ -907,6 +905,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Izmenite pomoću aplikacije %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Delite pomoću"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Delite pomoću aplikacije %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Pošaljite pomoću:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Pošaljite pomoću: %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Izaberite aplikaciju za početnu stranicu"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Koristite %1$s za početnu"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Podrazumevano koristi za ovu radnju."</string>
@@ -923,7 +923,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Resetuj i ponovo pokreni aplikaciju"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Pošaljite povratne informacije"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignoriši"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignoriši dok se uređaj ne pokrene ponovo"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Čekaj"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Zatvori aplikaciju"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,7 +1053,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nije potrebna nijedna dozvola"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ovo će vam možda biti naplaćeno"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Potvrdi"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB puni ovaj uređaj"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB snabdeva energijom priključeni uređaj"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prenos datoteka"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos slika"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1061,24 +1062,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za još opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izveštaj o grešci se generiše…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li da podelite izveštaj o grešci?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deli se izveštaj o grešci…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema u vezi sa ovim uređajem. Aplikacije i podaci mogu da se dele."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Izaberite tastature"</string>
     <string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
     <string name="hardware" msgid="194658061510127999">"Prikaži virtuelnu tastaturu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Izbor rasporeda tastature"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite da biste izabrali raspored tastature."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurišite fizičku tastaturu"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -1151,8 +1145,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadina"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Promena pozadine"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Monitor obaveštenja"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Obrađivač za virtuelnu realnost"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dobavljač uslova"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obaveštenja"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Usluga rangiranja obaveštenja"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN je aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dodirnite da biste upravljali mrežom."</string>
@@ -1238,7 +1233,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Još opcija"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interna memorija"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Unutrašnji deljeni memorijski prostor"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kartica"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kartica"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB disk"</string>
@@ -1483,7 +1478,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN pre otkačinjanja"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži šablon za otključavanje pre otkačinjanja"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži lozinku pre otkačinjanja"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veličina aplikacije ne može da se menja. Pomerajte je pomoću dva prsta."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće funkcionisati sa podeljenim ekranom."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava podeljeni ekran."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalirao je vaš administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao je administrator"</string>
@@ -1562,12 +1557,11 @@
       <item quantity="few">Izabrane su <xliff:g id="COUNT_1">%1$d</xliff:g> stavke</item>
       <item quantity="other">Izabrano je <xliff:g id="COUNT_1">%1$d</xliff:g> stavki</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Vi podešavate važnost ovih obaveštenja."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Vi podešavate važnost ovih obaveštenja."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ovo je važno zbog ljudi koji učestvuju."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Želite li da dozvolite aplikaciji <xliff:g id="APP">%1$s</xliff:g> da napravi novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Želite li da dozvolite aplikaciji <xliff:g id="APP">%1$s</xliff:g> da napravi novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik sa ovim nalogom već postoji)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Podešavanje jezika"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Dodajte jezik"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Podešavanje regiona"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženi"</string>
@@ -1576,8 +1570,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Režim za Work je ISKLJUČEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Dozvoljava profilu za Work da funkcioniše, uključujući aplikacije, sinhronizaciju u pozadini i srodne funkcije."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Uključi"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Paket %1$s je onemogućen"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Onemogućio je administrator kompanije %1$s. Kontaktirajte ga da biste saznali više."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nove poruke"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorite aplikaciju za SMS da biste pregledali"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Neke funkcije su možda ograničene"</string>
@@ -1590,4 +1582,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Zakači"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Otkači"</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Resetujte uređaj na fabrička podešavanja da biste ga koristili bez ograničenja"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</string>
 </resources>
diff --git a/core/res/res/values-be-rBY-watch/strings.xml b/core/res/res/values-be-rBY-watch/strings.xml
new file mode 100644
index 0000000..41813df
--- /dev/null
+++ b/core/res/res/values-be-rBY-watch/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="android_upgrading_apk" msgid="1090732262010398759">"Праграма <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Датчыкі"</string>
+</resources>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..8a23529
--- /dev/null
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -0,0 +1,1607 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="byteShort" msgid="8340973892742019101">"B"</string>
+    <string name="kilobyteShort" msgid="5973789783504771878">"Кб"</string>
+    <string name="megabyteShort" msgid="6355851576770428922">"Мб"</string>
+    <string name="gigabyteShort" msgid="3259882455212193214">"Гб"</string>
+    <string name="terabyteShort" msgid="231613018159186962">"Тб"</string>
+    <string name="petabyteShort" msgid="5637816680144990219">"Пб"</string>
+    <string name="fileSizeSuffix" msgid="8897567456150907538">"<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="durationMinute" msgid="7155301744174623818">"<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="emptyPhoneNumber" msgid="7694063042079676517">"(Няма нумара тэлефона)"</string>
+    <string name="unknownName" msgid="6867811765370350269">"Невядома"</string>
+    <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Галасавая пошта"</string>
+    <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
+    <string name="mmiError" msgid="5154499457739052907">"Праблема падлучэння ці няправільны код MMI."</string>
+    <string name="mmiFdnError" msgid="5224398216385316471">"Выкарыстанне абмежаванае толькі дазволенымі нумарамі."</string>
+    <string name="serviceEnabled" msgid="8147278346414714315">"Служба была ўключана."</string>
+    <string name="serviceEnabledFor" msgid="6856228140453471041">"Служба была ўключана для:"</string>
+    <string name="serviceDisabled" msgid="1937553226592516411">"Служба была адключаная."</string>
+    <string name="serviceRegistered" msgid="6275019082598102493">"Рэгістрацыя прайшла паспяхова."</string>
+    <string name="serviceErased" msgid="1288584695297200972">"Паспяхова выдалена."</string>
+    <string name="passwordIncorrect" msgid="7612208839450128715">"Няправільны пароль."</string>
+    <string name="mmiComplete" msgid="8232527495411698359">"MMI завершаны."</string>
+    <string name="badPin" msgid="9015277645546710014">"Стары PIN-код уведзены няправільна."</string>
+    <string name="badPuk" msgid="5487257647081132201">"Няправільны PUK-код."</string>
+    <string name="mismatchPin" msgid="609379054496863419">"Уведзеныя PIN-коды не супадаюць."</string>
+    <string name="invalidPin" msgid="3850018445187475377">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
+    <string name="invalidPuk" msgid="8761456210898036513">"Увядзіце PUK з 8 лічбаў ці больш."</string>
+    <string name="needPuk" msgid="919668385956251611">"Ваша SIM-карта заблакавана PUK-кодам. Увядзіце PUK, каб разблакаваць карту."</string>
+    <string name="needPuk2" msgid="4526033371987193070">"Увядзіце PUK2 для разблакавання SIM-карты."</string>
+    <string name="enablePin" msgid="209412020907207950">"Не атрымалася, уключыце блакіроўку SIM/RUIM."</string>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">У вас засталася <xliff:g id="NUMBER_1">%d</xliff:g> спроба перад тым, як SIM-карта будзе заблакіравана.</item>
+      <item quantity="few">У вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спробы перад тым, як SIM-карта будзе заблакіравана.</item>
+      <item quantity="many">У вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спроб перад тым, як SIM-карта будзе заблакіравана.</item>
+      <item quantity="other">У вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спробы перад тым, як SIM-карта будзе заблакіравана.</item>
+    </plurals>
+    <string name="imei" msgid="2625429890869005782">"IMEI"</string>
+    <string name="meid" msgid="4841221237681254195">"MEID"</string>
+    <string name="ClipMmi" msgid="6952821216480289285">"Ідэнтыфікатар АВН"</string>
+    <string name="ClirMmi" msgid="7784673673446833091">"Ідэнтыфікатар АВН"</string>
+    <string name="ColpMmi" msgid="3065121483740183974">"Ідэнтыфікатар падлучанай лініі"</string>
+    <string name="ColrMmi" msgid="4996540314421889589">"Абмежаванне ідэнтыфікатара падлучанай лініі"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"Пераадрасацыя выкліку"</string>
+    <string name="CwMmi" msgid="9129678056795016867">"Чаканне выкліку"</string>
+    <string name="BaMmi" msgid="455193067926770581">"Забарона выкліку"</string>
+    <string name="PwdMmi" msgid="7043715687905254199">"Змена пароля"</string>
+    <string name="PinMmi" msgid="3113117780361190304">"Змена PIN-коду"</string>
+    <string name="CnipMmi" msgid="3110534680557857162">"Цяперашні нумар выкліку"</string>
+    <string name="CnirMmi" msgid="3062102121430548731">"Нумар выкліку абмежаваны"</string>
+    <string name="ThreeWCMmi" msgid="9051047170321190368">"Трохбаковы выклік"</string>
+    <string name="RuacMmi" msgid="7827887459138308886">"Адмова ад непажаданых раздражняючых выклікаў"</string>
+    <string name="CndMmi" msgid="3116446237081575808">"Дастаўка нумару выкліку"</string>
+    <string name="DndMmi" msgid="1265478932418334331">"Не турбаваць"</string>
+    <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Налады ідэнтыфікатару АВН па змаўчанні абмежаваныя. Наступны выклік: абмежавана"</string>
+    <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Ідэнтыфікатар АВН па змаўчанні абмежаваны. Наступны выклік: не абмежавана"</string>
+    <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Па змаўчанні ідэнтыфікатар АВН не абмежаваны. Наступны выклік: абмежаваны"</string>
+    <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Налады ідэнтыфікатару АВН па змаўчанні: не абмяжавана. Наступны выклік: не абмежавана"</string>
+    <string name="serviceNotProvisioned" msgid="8614830180508686666">"Служба не прадастаўляецца."</string>
+    <string name="CLIRPermanent" msgid="3377371145926835671">"Вы не можаце змяніць налады ідэнтыфікатара абанента, якi тэлефануе."</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">"Служба SMS заблакаваная."</string>
+    <string name="RestrictedOnVoiceData" msgid="996636487106171320">"Службы перадачы голаса/дадзеных заблакаваны."</string>
+    <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Службы перадачы голаса і SMS заблакаваныя."</string>
+    <string name="RestrictedOnAll" msgid="5643028264466092821">"Усе службы перадачы дадзеных, галасавыя і SMS-службы заблакаваны."</string>
+    <string name="peerTtyModeFull" msgid="6165351790010341421">"Аднарангавая прылада запытала рэжым TTY FULL"</string>
+    <string name="peerTtyModeHco" msgid="5728602160669216784">"Аднарангавая прылада запытала рэжым TTY НСО"</string>
+    <string name="peerTtyModeVco" msgid="1742404978686538049">"Аднарангавая прылада запытала рэжым TTY VCO"</string>
+    <string name="peerTtyModeOff" msgid="3280819717850602205">"Аднарангавая прылада запытала рэжым TTY OFF"</string>
+    <string name="serviceClassVoice" msgid="1258393812335258019">"Голас"</string>
+    <string name="serviceClassData" msgid="872456782077937893">"Дадзеныя"</string>
+    <string name="serviceClassFAX" msgid="5566624998840486475">"Факс"</string>
+    <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
+    <string name="serviceClassDataAsync" msgid="4523454783498551468">"Асінхронныя"</string>
+    <string name="serviceClassDataSync" msgid="7530000519646054776">"Сінхронныя"</string>
+    <string name="serviceClassPacket" msgid="6991006557993423453">"Пакет"</string>
+    <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+    <string name="roamingText0" msgid="7170335472198694945">"Індыкатар роўмінгу ўключаны"</string>
+    <string name="roamingText1" msgid="5314861519752538922">"Індыкатар роўмінгу адключаны"</string>
+    <string name="roamingText2" msgid="8969929049081268115">"Індыкатар роўмінгу міргае"</string>
+    <string name="roamingText3" msgid="5148255027043943317">"З раёну"</string>
+    <string name="roamingText4" msgid="8808456682550796530">"З будынку"</string>
+    <string name="roamingText5" msgid="7604063252850354350">"Роўмінг: пераважная сістэма"</string>
+    <string name="roamingText6" msgid="2059440825782871513">"Роўмінг: даступная сістэма"</string>
+    <string name="roamingText7" msgid="7112078724097233605">"Роўмінг: асацыятыўны партнёр"</string>
+    <string name="roamingText8" msgid="5989569778604089291">"Роўмінг: прэмiум-партнёр"</string>
+    <string name="roamingText9" msgid="7969296811355152491">"Роўмінг: поўная функцыянальнасць службы"</string>
+    <string name="roamingText10" msgid="3992906999815316417">"Роўмінг – частковая функцыянальнасць службы"</string>
+    <string name="roamingText11" msgid="4154476854426920970">"Банэр роўмінгу ўключаны"</string>
+    <string name="roamingText12" msgid="1189071119992726320">"Банэр роўмінгу адключаны"</string>
+    <string name="roamingTextSearching" msgid="8360141885972279963">"Пошук службы"</string>
+    <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-тэлефанія"</string>
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+  </string-array>
+    <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wfcDataSpnFormat" msgid="1118052028767666883">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Выкл."</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Прыярытэт Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Прыярытэт мабільнай сеткі"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Толькі Wi-Fi"</string>
+    <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не пераадрасоўваецца"</string>
+    <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+    <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> праз <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string>
+    <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не пераадрасоўваецца"</string>
+    <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="httpError" msgid="7956392511146698522">"Адбылася памылка сеткі."</string>
+    <string name="httpErrorLookup" msgid="4711687456111963163">"Не атрымалася знайсці URL."</string>
+    <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Схема аўтэнтыфікацыі сайта не падтрымліваецца."</string>
+    <string name="httpErrorAuth" msgid="1435065629438044534">"Памылка аўтэнтыфікацыі."</string>
+    <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Праверка сапраўднасці праз проксі-сервер скончылася няўдала."</string>
+    <string name="httpErrorConnect" msgid="8714273236364640549">"Немагчыма падлучыцца да сервера."</string>
+    <string name="httpErrorIO" msgid="2340558197489302188">"Немагчыма звязацца з серверам. Паўтарыце спробу пазней."</string>
+    <string name="httpErrorTimeout" msgid="4743403703762883954">"Час чакання злучэння з серверам скончыўся."</string>
+    <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Старонка змяшчае зашмат перанакіраванняў сервера."</string>
+    <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Пратакол не падтрымліваецца."</string>
+    <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Немагчыма ўсталяваць бяспечнае злучэнне."</string>
+    <string name="httpErrorBadUrl" msgid="3636929722728881972">"Немагчыма адкрыць старонку, таму што URL несапраўдны."</string>
+    <string name="httpErrorFile" msgid="2170788515052558676">"Немагчыма атрымаць доступ да файла."</string>
+    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Немагчыма знайсці патрабаваны файл."</string>
+    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Апрацоўваецца занадта шмат запытаў. Паспрабуйце яшчэ раз пазней."</string>
+    <string name="notification_title" msgid="8967710025036163822">"Памылка ўваходу ва ўлiковы запiс <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+    <string name="contentServiceSync" msgid="8353523060269335667">"Сінхранізацыя"</string>
+    <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="tv" msgid="516619861191025923">"Сховішча тэлевізара перапоўнена. Выдаліце некаторыя файлы, каб вызваліць месца."</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>
+    <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"Адміністратар вашага працоўнага профілю"</string>
+    <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
+    <string name="work_profile_deleted" msgid="5005572078641980632">"Рабочы профіль выдалены"</string>
+    <string name="work_profile_deleted_description" msgid="6305147513054341102">"Рабочы профіль выдалены з-за адсутнасці праграмы адміністравання."</string>
+    <string name="work_profile_deleted_details" msgid="226615743462361248">"Праграма для адміністравання рабочага профілю адсутнічае або пашкоджана. У выніку гэтага ваш рабочы профіль і звязаныя з ім даныя былі выдаленыя. Звярніцеся па дапамогу да адміністратара."</string>
+    <string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Ваш працоўны профіль больш не даступны на гэтай прыладзе."</string>
+    <string name="factory_reset_warning" msgid="5423253125642394387">"Даныя вашай прылады будуць сцерты"</string>
+    <string name="factory_reset_message" msgid="4905025204141900666">"Праграма для адміністравання не можа быць выкарыстана, таму што ў яе адсутнічаюць кампаненты або яна пашкоджана. Зараз даныя вашай прылады будуць сцерты. Звярніцеся па дапамогу да адміністратара."</string>
+    <string name="me" msgid="6545696007631404292">"Я"</string>
+    <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Параметры планшэта"</string>
+    <string name="power_dialog" product="tv" msgid="6153888706430556356">"Параметры ТБ"</string>
+    <string name="power_dialog" product="default" msgid="1319919075463988638">"Параметры тэлефона"</string>
+    <string name="silent_mode" msgid="7167703389802618663">"Бязгучны рэжым"</string>
+    <string name="turn_on_radio" msgid="3912793092339962371">"Уключыць бесправадную сетку"</string>
+    <string name="turn_off_radio" msgid="8198784949987062346">"Адключыць бесправадную сетку"</string>
+    <string name="screen_lock" msgid="799094655496098153">"Блакіроўка экрана"</string>
+    <string name="power_off" msgid="4266614107412865048">"Выключыць"</string>
+    <string name="silent_mode_silent" msgid="319298163018473078">"Званок выкл."</string>
+    <string name="silent_mode_vibrate" msgid="7072043388581551395">"Званок з вібрацыяй"</string>
+    <string name="silent_mode_ring" msgid="8592241816194074353">"Званок укл."</string>
+    <string name="reboot_to_update_title" msgid="6212636802536823850">"Сістэмнае абнаўленне Android"</string>
+    <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Падрыхтоўка да абнаўлення..."</string>
+    <string name="reboot_to_update_package" msgid="3871302324500927291">"Апрацоўка пакета абнаўлення..."</string>
+    <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Перазапуск..."</string>
+    <string name="reboot_to_reset_title" msgid="4142355915340627490">"Скід да заводскіх налад"</string>
+    <string name="reboot_to_reset_message" msgid="2432077491101416345">"Перазапуск..."</string>
+    <string name="shutdown_progress" msgid="2281079257329981203">"Выключэнне..."</string>
+    <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшэт будзе адключаны."</string>
+    <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Ваш тэлевізар будзе выключаны."</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>
+    <string name="reboot_safemode_confirm" msgid="55293944502784668">"Хочаце перазагрузіцца ў бяспечным рэжыме? Гэта дазволіць адключыць усе іншыя ўсталяваныя прыкладанні. Пасля перазагрузкi iх праца будзе адноўлена."</string>
+    <string name="recent_tasks_title" msgid="3691764623638127888">"Апошнія"</string>
+    <string name="no_recent_tasks" msgid="8794906658732193473">"Няма апошніх прыкладанняў."</string>
+    <string name="global_actions" product="tablet" msgid="408477140088053665">"Параметры планшэта"</string>
+    <string name="global_actions" product="tv" msgid="7240386462508182976">"Параметры ТБ"</string>
+    <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">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Інтэрактыўная справаздача"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Выкарыстоўвайце ў большасці выпадкаў. Гэта дазваляе сачыць за ходам справаздачы і ўводзіць дадатковыя звесткі аб праблеме. Могуць быць прапушчаны некаторыя раздзелы, якія выкарыстоўваюцца менш і паведаміць пра якія зойме шмат часу."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Поўная справаздача"</string>
+    <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Выкарыстоўвайце гэту опцыю, каб забяспечыць мінімальнае ўмяшанне сістэмы, калі прылада не адказвае ці працуе занадта павольна або калі вам патрэбны ўсе раздзелы справаздачы. Выкарыстоўваючы гэту опцыю, вы не зможаце зрабіць здымак экрана або ўвесці больш падрабязную інфармацыю."</string>
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунду.</item>
+      <item quantity="few">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунды.</item>
+      <item quantity="many">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунд.</item>
+      <item quantity="other">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунды.</item>
+    </plurals>
+    <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="global_action_assist" msgid="3892832961594295030">"Дапамога"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Галас. дапамога"</string>
+    <string name="global_action_lockdown" msgid="8751542514724332873">"Заблакір. зараз"</string>
+    <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+    <string name="notification_hidden_text" msgid="1135169301897151909">"Змесціва схавана"</string>
+    <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Змесціва, схаванае ў адпаведнасці з палітыкай"</string>
+    <string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Пераключыцца на асабісты"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Пераключыцца на працоўны"</string>
+    <string name="permgrouplab_contacts" msgid="3657758145679177612">"Кантакты"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"атрымліваць доступ да вашых кантактаў"</string>
+    <string name="permgrouplab_location" msgid="7275582855722310164">"Месцазнаходжанне"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"атрымліваць доступ да месцазнаходжання гэтай прылады"</string>
+    <string name="permgrouplab_calendar" msgid="5863508437783683902">"Каляндар"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"атрымліваць доступ да вашага календара"</string>
+    <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"адпраўляць і праглядаць SMS-паведамленні"</string>
+    <string name="permgrouplab_storage" msgid="1971118770546336966">"Сховішча"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"атрымліваць доступ да фатаграфій, медыяфайлаў і файлаў на вашай прыладзе"</string>
+    <string name="permgrouplab_microphone" msgid="171539900250043464">"Мікрафон"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"запісваць аўдыя"</string>
+    <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"рабіць фатаздымкі і запісваць відэа"</string>
+    <string name="permgrouplab_phone" msgid="5229115638567440675">"Тэлефон"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"рабіць тэлефонныя выклікі і кіраваць імі"</string>
+    <string name="permgrouplab_sensors" msgid="416037179223226722">"Датчыкі цела"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"атрымліваць з датчыка даныя асноўных фізіялагічных паказчыкаў"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Атрымайце змесцiва акна"</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Вывучыце змесцiва акна, з якiм вы працуеце."</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Уключыце Explore by Touch"</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Элемент, да якiх дакраналiся, могуць быць агучаны, а экран будзе працаваць з жэстамi."</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Уключыце паляпшэнне вэб-даступнасці"</string>
+    <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Сцэнарыi могуць быць усталяваны, каб зрабіць змесцiва прыкладання больш даступным."</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Глядзiце, што набiраеце"</string>
+    <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Уключае ў сябе асабістыя дадзеныя, такія як нумары крэдытных карт і паролі."</string>
+    <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Кіраваць павелічэннем дысплэя"</string>
+    <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Кіраваць маштабам дысплэя і пазіцыянаваннем."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Выконваць жэсты"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можна кранаць, праводзіць пальцам, маштабаваць шчыпком, а таксама выконваць іншыя жэсты."</string>
+    <string name="permlab_statusBar" msgid="7417192629601890791">"адключаць ці змяняць радок стану"</string>
+    <string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
+    <string name="permlab_statusBarService" msgid="4826835508226139688">"быць панэллю стану"</string>
+    <string name="permdesc_statusBarService" msgid="716113660795976060">"Дазваляе прыкладанням быць радком стану."</string>
+    <string name="permlab_expandStatusBar" msgid="1148198785937489264">"разгарнуць/згарнуць радок стану"</string>
+    <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Дазваляе прыкладанню разгортваць ці згортваць радок стану."</string>
+    <string name="permlab_install_shortcut" msgid="4279070216371564234">"усталёўваць ярлыкі"</string>
+    <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Дазваляе праграме дадаваць ярлыкі на Галоўны экран без умяшання карыстальніка."</string>
+    <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="permlab_receiveSms" msgid="8673471768947895082">"атрыманне тэкставых паведамленняў (SMS)"</string>
+    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Дазваляе прыкладанням атрымліваць і апрацоўваць SMS-паведамленні. Гэта значыць, што прыкладанне можа кантраляваць або выдаляць паведамленні, адпраўленыя на прыладу, не паказваючы іх вам."</string>
+    <string name="permlab_receiveMms" msgid="1821317344668257098">"атрыманне тэкставых паведамленняў (MMS)"</string>
+    <string name="permdesc_receiveMms" msgid="533019437263212260">"Дазваляе прыкладанням атрымліваць і апрацоўваць MMS-паведамленнi. Гэта значыць, што прыкладанне можа кантраляваць або выдаляць паведамленні, адпраўленыя на прыладу, не паказваючы іх вам."</string>
+    <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"чытаць паведамленні базавай станцыі"</string>
+    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Дазваляе прыкладанню чытаць паведамленні базавай станцыі, атрыманыя прыладай. Папярэджанні базавай станцыі дасылаюцца ў некаторыя месцы, каб папярэдзіць вас аб надзвычайных сітуацыях. Шкоднасныя прыкладанні могуць уплываць на прадукцыйнасць ці працу прылады пры атрыманні паведамлення базавай станцыі аб надзвычайнай сітуацыі."</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"чытаць падпісаныя каналы"</string>
+    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дазваляе прыкладанням атрымліваць інфармацыю пра каналы, якія сінхранізуюцца ў бягучы момант."</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"адпраўляць і праглядаць SMS-паведамленні"</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"Дазваляе прыкладанне для адпраўкі SMS паведамленняў. Гэта можа прывесці да нечаканых абвінавачванняў. Шкоднасныя праграмы могуць каштаваць вам грошай на адпраўку паведамленняў без вашага пацвярджэння."</string>
+    <string name="permlab_readSms" msgid="8745086572213270480">"чытанне сваiх тэкставых паведамленняў (SMS ці MMS)"</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Дазваляе прыкладанню чытаць SMS-паведамленнi, якія захоўваюцца на планшэце ці SIM-карце. Гэта дазваляе прыкладанням чытаць ўсе SMS-паведамленні, незалежна ад змесцiва або прыватнасці."</string>
+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Дазваляе праграме чытаць SMS-паведамленні, якія захоўваюцца на вашым тэлевізары або на SIM-карце. Гэта дазваляе праграме чытаць усе SMS-паведамленні, незалежна ад змесцiва або канфідэнцыяльнасці."</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Дазваляе прыкладанню чытаць SMS-паведамленні, якія захоўваюцца ў тэлефоне або на SIM-карце. Гэта дазваляе прыкладанням чытаць ўсе SMS-паведамленні, незалежна ад змесцiва або прыватнасці."</string>
+    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"атрыманне тэкставых паведамленняў (WAP)"</string>
+    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Дазваляе прыкладанням атрымліваць і апрацоўваць паведамленні WAP. Дзякуючы гэтаму дазволу можна кантраляваць або выдаляць паведамленні, пасланыя вам, не паказваючы іх."</string>
+    <string name="permlab_getTasks" msgid="6466095396623933906">"атрымаць запушчаныя прыкладанні"</string>
+    <string name="permdesc_getTasks" msgid="7454215995847658102">"Дазваляе прыкладанню атрымлiваць звесткi пра прыкладаннi, запушчаныя зараз i нядаўна. Прыкладанне можа знайсцi iнфармацыю пра тое, якiя прыкладаннi выкарыстоўваюцца на прыладзе."</string>
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"кіраваць профілем і ўладальнікамі прылады"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Дазваляе праграмам задаваць уладальнікаў профіляў і ўладальніка прылады."</string>
+    <string name="permlab_reorderTasks" msgid="2018575526934422779">"змяніць парадак запушчаных прыкладанняў"</string>
+    <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дазваляе прыкладанню перамяшчаць заданні на ​​пярэдні план і ў фон. Шкоднасныя прыкладанні могуць прымусова рабіць сябе асноўнымі без вашага ведама."</string>
+    <string name="permlab_enableCarMode" msgid="5684504058192921098">"дазваляць рэжым \"У аўтамабілі\""</string>
+    <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Дазваляе прыкладанню ўключаць рэжым гучнай сувязi."</string>
+    <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"закрыццё іншых прыкладанняў"</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Дазваляе прыкладанню завяршаць фонавыя працэсы іншых прыкладанняў. Гэта можа спынiць працу iншых прыкладанняў."</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"прыарытэт перад іншымі прыкладаннямі"</string>
+    <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Прыкладанне можа з\'яўляцца паверх iншых прыкладанняў. Яны могуць шкодзiць адно аднаму падчас працы iнтэрфейсаў або змяняць тое, што вы бачыце ў iншых прыкладаннях."</string>
+    <string name="permlab_persistentActivity" msgid="8841113627955563938">"прымусіць прыкладанне працаваць заўсёды"</string>
+    <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Дазваляе прыкладанню захоўваць некаторыя пастаянныя часткi ў памяцi. Гэта можа абмежаваць аб\'ём памяці, даступнай для іншых прыкладанняў, i запаволiць працу планшэта."</string>
+    <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Дазваляе праграме пастаянна захоўваць некаторыя свае часткi ў памяцi. Гэта можа абмежаваць аб\'ём памяці, даступнай для іншых праграм, i запаволiць працу тэлевізара."</string>
+    <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Дазваляе прыкладанню захоўваць некаторыя пастаянныя часткi ў памяцi. Гэта можа абмежаваць аб\'ём памяці, даступнай для іншых прыкладанняў, i запаволiць працу тэлефона."</string>
+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"вымерыць прастору для захоўвання прыкладання"</string>
+    <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дазваляе прыкладанням атрымліваць яго код, дадзеныя і аб\'ём кэш-памяці"</string>
+    <string name="permlab_writeSettings" msgid="2226195290955224730">"змена сістэмных налад"</string>
+    <string name="permdesc_writeSettings" msgid="7775723441558907181">"Дазваляе прыкладаннем змяняць дадзеныя налад сістэмы. Шкоднасныя прыкладанні могуць пашкодзіць канфігурацыю вашай сістэмы."</string>
+    <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"запуск пры загрузцы сістэмы"</string>
+    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Дазваляе прыкладанню самастойна запускацца, як толькі сістэма будзе цалкам загружана. Гэта можа павялічыць час запуску планшэту і дазволіць прыкладанню запаволіць увесь планшэт, прымушаючы яго працаваць заўсёды."</string>
+    <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Дазваляе праграме самастойна запускацца, як толькі сістэма будзе цалкам загружана. Гэта можа павялічыць час запуску тэлевізара і дазволіць праграме, пастаянна працуючы, запаволіць увесь тэлевізар."</string>
+    <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Дазваляе прыкладанням самастойна запускацца, як толькі сістэма будзе цалкам запушчана. Гэта можа павялічыць час запуску тэлефону і дазволіць прыкладанню запаволіць увесь тэлефон, прымушаючы яго працаваць заўсёды."</string>
+    <string name="permlab_broadcastSticky" msgid="7919126372606881614">"адпраўляць нетэрмiновую рассылку"</string>
+    <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Дазваляе прыкладанням адпраўляць далейшыя звязаныя перадачы, якія застаюцца пасля заканчэння асноўнай перадачы. Злоўжыванне можа зрабіць працу планшэта павольнай або няўстойлівай, прымушаючы яго выкарыстоўваць занадта шмат памяці."</string>
+    <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Дазваляе праграме адпраўляць «ліпучыя» трансляцыі, якія застаюцца актыўнымі пасля завяршэння перадачы. Злоўжыванне гэтым можа зрабіць працу тэлевізара павольнай або няўстойлівай, прымушаючы яго выкарыстоўваць занадта шмат памяці."</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">"Дазваляе прыкладанням счытваць дадзеныя аб кантактах, якія захоўваюцца на планшэце, у тым ліку звесткi пра тое, як часта вы выклiкалi канкрэтных абанентаў, пiсалi iм па электроннай пошце або кантактавалi іншымi спосабамі. Дзякуючы гэтаму дазволу прыкладаннi могуць захоўваць дадзеныя гiсторыi выклiкаў, а шкоднасныя прыкладаннi могуць адпраўляць кантактныя дадзеныя без вашага ведама."</string>
+    <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Дазваляе праграме счытваць даныя аб кантактах, якія захоўваюцца на вашым тэлевізары, у тым ліку звесткi пра тое, як часта вы выклiкалi канкрэтных абанентаў, пiсалi iм па электроннай пошце або кантактавалi з імі іншымi спосабамі. Праграмы з гэтым дазволам могуць захоўваць даныя вашай гiсторыi выклiкаў, а шкодныя праграмы могуць абагульваць даныя аб кантактах без вашага ведама."</string>
+    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Дазваляе прыкладанням счытваць дадзеныя аб кантактах, якія захоўваюцца на тэлефоне, у тым ліку звесткi пра частату, з якой вы выклiкалi iх, пiсалi iм па электроннай пошце ці кантактавалi іншым спосабам. Дзякуючы гэтаму дазволу прыкладаннi могуць захоўваць дадзеныя гiсторыi выклiкаў, а шкоднасныя прыкладаннi могуць адпраўляць кантактныя дадзеныя без вашага ведама."</string>
+    <string name="permlab_writeContacts" msgid="5107492086416793544">"змена кантактаў"</string>
+    <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Дазваляе прыкладанням змяняць дадзеныя аб кантактах, якія захоўваюцца на планшэце, у тым ліку частата, з якой вы выклiкалi асоб, пiсалi па электроннай пошце ці іншым спосабам кантактавалi з iмі. З гэтым дазволам прыкладаннi змогуць выдаляць кантактныя дадзеныя."</string>
+    <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Дазваляе праграме змяняць даныя аб кантактах, якія захоўваюцца на вашым тэлевізары, у тым ліку звесткi пра тое, як часта вы выклiкалi канкрэтных абанентаў, пiсалi iм па электроннай пошце або кантактавалi з імі іншымi спосабамі. Гэта дазваляе праграмам выдаляць даныя аб кантактах."</string>
+    <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Дазваляе прыкладанням змяняць дадзеныя аб кантактах, якія захоўваюцца на тэлефоне, у тым ліку частата, з якой вы выклiкалi асоб, пiсалi па электроннай пошце ці іншым спосабам кантактавалi з iмі. З гэтым дазволам прыкладаннi змогуць выдаляць кантактныя дадзеныя."</string>
+    <string name="permlab_readCallLog" msgid="3478133184624102739">"чытанне гiсторыi выклікаў"</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Дазваляе прыкладанням чытаць гiсторыю выклiкаў планшэта, у тым лiку дадзеныя пра ўваходныя i выходныя выклiкi. Дзякуючы гэтаму дазволу прыкладаннi могуць захоўваць дадзеныя гiсторыi выклiкаў, а шкоднасныя прыкладаннi могуць адпраўляць гiсторыю выклiкаў без вашага ведама."</string>
+    <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Дазваляе праграме счытваць гiсторыю выклiкаў тэлевізара, у тым лiку даныя пра ўваходныя i выходныя выклiкi. Праграмы з гэтым дазволам могуць захоўваць даныя вашай гiсторыi выклiкаў, а шкодныя праграмы могуць абагульваць гiсторыю выклiкаў без вашага ведама."</string>
+    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Дазваляе прыкладанням чытаць гiсторыю выклiкаў тэлефона, у тым лiку дадзеныя пра ўваходныя i выходныя выклiкi. Дзякуючы гэтаму дазволу прыкладаннi могуць захоўваць дадзеныя гiсторыi выклiкаў, а шкоднасныя прыкладаннi могуць адпраўляць гiсторыю выклiкаў без вашага ведама."</string>
+    <string name="permlab_writeCallLog" msgid="8552045664743499354">"запіс гiсторыi выклікаў"</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Дазваляе прыкладанню змяняць гiсторыю выклiкаў планшэта, у тым лiку дадзеныя пра ўваходныя i зыходныя выклiкi. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб выдаляць або змяняць гiсторыю выклікаў."</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Дазваляе праграме змяняць гiсторыю выклiкаў вашага тэлевізара, у тым лiку даныя пра ўваходныя i выходныя выклiкi. Шкодныя праграмы могуць выкарыстоўваць гэта, каб выдаляць або змяняць гiсторыю выклікаў."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Дазваляе прыкладанням змяняць гiсторыю выклiкаў тэлефону, у тым лiку дадзеныя пра ўваходныя і зыходныя выклiкi. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб выдаляць або змяняць гiсторыю выклікаў."</string>
+    <string name="permlab_bodySensors" msgid="4683341291818520277">"атрымліваць доступ да датчыкаў цела (напрыклад, пульсометраў)"</string>
+    <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Дазваляе праграме атрымліваць доступ да даных з датчыкаў, якія назіраюць за вашым фізічным станам, напрыклад, за частатой пульсу."</string>
+    <string name="permlab_readCalendar" msgid="5972727560257612398">"чытаць падзеі календара, а таксама прыватную інфармацыю"</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Дазваляе прыкладанню чытаць усе мерапрыемствы з календара, захаваныя на вашым планшэце, у тым ліку з сябрамi або калегамi. Гэта дазваляе прыкладанню адпраўляць дадзеныя календара, нягледзячы на прыватнасць i адчувальнасць."</string>
+    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Дазваляе праграме счытваць усе падзеі з календара, захаваныя на вашым тэлевізары, у тым ліку падзеі сяброў або калег. Гэта можа дазволіць праграме абагульваць або захоўваць даныя вашага календара, нягледзячы на канфідэнцыяльнасць або сакрэтнасць."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Дазваляе прыкладанню чытаць усе мерапрыемствы з календара, захаваныя на вашым тэлефоне, у тым ліку з сябрамi або калегамi. Гэта дазваляе прыкладанню адпраўляць дадзеныя календара, нягледзячы на прыватнасць i адчувальнасць."</string>
+    <string name="permlab_writeCalendar" msgid="8438874755193825647">"дадаваць ці змяняць падзеі календара і адпраўляць электронную пошту да гасцей без ведама ўладальнікаў"</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Дазваляе прыкладанню дадаваць, выдаляць, змяняць мерапрыемствы, якія можна рэдагаваць на планшэце, у тым ліку сустрэчы с сябрамi i калегамi. Гэта дазваляе прыкладанню адпраўляць паведамленні ад уладальнiкаў календароў або змяняць мерапрыемствы без ведама уладальнiкаў."</string>
+    <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Дазваляе праграме дадаваць, выдаляць, змяняць падзеі, якія вы можаце рэдагаваць на сваім тэлевізары, у тым ліку падзеі сяброў або калег. Гэта дазваляе праграме адпраўляць паведамленні ад імя уладальнiкаў календароў або змяняць падзеі без ведама ўладальнiкаў."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Дазваляе прыкладанню дадаваць, выдаляць, змяняць мерапрыемствы, якія можна рэдагаваць на тэлефоне, у тым ліку сустрэчы с сябрамi i калегамi. Гэта дазваляе прыкладанню адпраўляць паведамленні ад уладальнiкаў календароў або змяняць мерапрыемствы без ведама уладальнiкаў."</string>
+    <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"доступ да дадатковых камандаў пастаўшчыка месцазнаходжання"</string>
+    <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Дазваляе праграме атрымліваць доступ да дадатковых каманд службаў вызначэння месцазнаходжання. Гэта можа дазволіць праграме ўмешвацца ў функцыянаванне GPS або іншых крыніц даных аб месцазнаходжаннi."</string>
+    <string name="permlab_accessFineLocation" msgid="251034415460950944">"атрымліваць доступ да дакладнага месцазнаходжання (на аснове GPS і сеткі)"</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Дазваляе прыкладанню вызначаць дакладнае месцазнаходжанне з дапамогай GPS або сеткавых крынiц месцазнаходжання, напрыклад веж сотавай сувязi i Wi-Fi. Гэтыя службы вызначэння месцазнаходжання павiнны быць уключаны i даступныя для вашай прылады i прыкладання. Прыкладаннi могуць выкарыстоўваць гэта, каб вызначаць ваша прыблiзнае месцазнаходжанне, а таксама спажываць дадатковае сiлкаванне."</string>
+    <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"атрымліваць доступ да прыблізнага месцазнаходжання (на аснове даных сеткі)"</string>
+    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Дазваляе прыкладанню вызначаць прыблiзнае месцазнаходжанне. Гэта месцазнаходжанне вызначаецца спецыяльнымi службамi з выкарыстаннем сеткавых крынiц месцазнаходжання, напрыклад веж сотавай сувязi i Wi-Fi. Службы вызначэння месцазнаходжання павiнны быць уключаны i даступныя для вашай прылады i прыкладання. Прыкладаннi могуць выкарыстоўваць гэта, каб вызначаць ваша прыблiзнае месцазнаходжанне."</string>
+    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змяняць налады аудыё"</string>
+    <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Дазваляе прыкладанням змяняць глабальныя налады гуку, такія як моц і тое, што дынамік выкарыстоўваецца для выхаду."</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"запісваць аўдыё"</string>
+    <string name="permdesc_recordAudio" msgid="4906839301087980680">"Дазваляе прыкладанню запісваць аўдыё з дапамогай мікрафона. Дзякуючы гэтаму дазволу прыкладаннi могуць запiсваць аўдыё ў любы час без вашага пацвярджэння."</string>
+    <string name="permlab_sim_communication" msgid="2935852302216852065">"адпраўляць каманды на SIM-карту"</string>
+    <string name="permdesc_sim_communication" msgid="5725159654279639498">"Дазваляе праграме адпраўляць каманды SIM-карце. Гэта вельмі небяспечна."</string>
+    <string name="permlab_camera" msgid="3616391919559751192">"рабіць фатаграфіі і відэа"</string>
+    <string name="permdesc_camera" msgid="8497216524735535009">"Дазваляе прыкладанню рабiць фотаздымкi і здымаць відэа з дапамогай камеры. Дзякуючы ггэтаму дазволу прыкладанне можа ў любы час выкарыстоўваць камеру без вашага пацверджання."</string>
+    <string name="permlab_vibrate" msgid="7696427026057705834">"кіраванне вібрацыяй"</string>
+    <string name="permdesc_vibrate" msgid="6284989245902300945">"Дазваляе прыкладанням кіраваць вібрацыяй."</string>
+    <string name="permlab_callPhone" msgid="3925836347681847954">"непасрэдна набіраць тэлефонныя нумары"</string>
+    <string name="permdesc_callPhone" msgid="3740797576113760827">"Дазваляе прыкладанням званiць на тэлефонныя нумары без вашага ўмяшання. Гэта можа прывесці да нечаканага спагнання сродкаў або званкоў. Звярніце ўвагу, што прыкладанне не можа рабiць экстраныя выклікi. Шкоднасныя прыкладаннi могуць спаганяць з вас сродкi, робячы званкі без вашага пацверджання."</string>
+    <string name="permlab_accessImsCallService" msgid="3574943847181793918">"атрымліваць доступ да сэрвісу выклікаў IMS"</string>
+    <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Дазваляе праграмам выкарыстоўваць службу IMS, каб рабіць выклікі без вашага ўмяшання."</string>
+    <string name="permlab_readPhoneState" msgid="9178228524507610486">"чытанне статусу тэлефона і ідэнтыфікацыя"</string>
+    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дазваляе прыкладанням атрымлiваць доступ да функцый тэлефона на прыладзе. Дзякуючы гэтаму дазволу прыкладанне можа вызначаць iдэнтыфiкатары нумару тэлефона i прылады, незалежна ад таго, цi актыўны выклiк, i аддалены нумар, на якi робiцца выклiк."</string>
+    <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"прадухіліць планшэт ад пераходу ў рэжым сну"</string>
+    <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"прадухіленне пераходу тэлевізара ў рэжым сну"</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"забараняць тэлефону пераходзіць ў рэжым сну"</string>
+    <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дазваляе прыкладанням прадухіляць пераход планшэта ў рэжым сну."</string>
+    <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"Дазваляе праграме прадухіляць пераход тэлевізара ў рэжым сну."</string>
+    <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дазваляе прыкладанням прадухіляць тэлефон ад пераходу ў рэжым сну."</string>
+    <string name="permlab_transmitIr" msgid="7545858504238530105">"карыстацца інфрачырвоным перадатчыкам"</string>
+    <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Дазваляе праграме выкарыстоўваць інфрачырвоны перадатчык планшэта."</string>
+    <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"Дазваляе праграме выкарыстоўваць інфрачырвоны перадатчык тэлевізара."</string>
+    <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Дазваляе праграме выкарыстоўваць інфрачырвоны перадатчык тэлефона."</string>
+    <string name="permlab_setWallpaper" msgid="6627192333373465143">"усталёўваць шпалеры"</string>
+    <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Дазваляе прыкладанням ксталёўваць сiстэмныя шпалеры."</string>
+    <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"наладка памеру шпалер"</string>
+    <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Дазваляе прыкладанням задаваць падказкі па памеры сістэмных шпалер."</string>
+    <string name="permlab_setTimeZone" msgid="2945079801013077340">"усталёўваць часавы пояс"</string>
+    <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Дазваляе прыкладанням змяняць гадзінны пояс планшэта."</string>
+    <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Дазваляе праграме змяняць часавы пояс тэлевізара."</string>
+    <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Дазваляе прыкладанню змяняць гадзінны пояс тэлефона."</string>
+    <string name="permlab_getAccounts" msgid="1086795467760122114">"пошук уліковых запісаў на прыладзе"</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Дазваляе прыкладанню атрымлiваць спіс уліковых запісаў, вядомых планшэту. Сярод iх могуць быць улiковыя запiсы, створаныя прыкладаннямi, якiя вы ўсталявалi."</string>
+    <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Дазваляе праграме атрымлiваць спіс уліковых запісаў, вядомых тэлевізару. Сярод iх могуць быць любыя ўлiковыя запiсы, створаныя праграмамі, якiя вы ўсталявалi."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Дазваляе прыкладанню атрымлiваць спіс уліковых запісаў, вядомых тэлефону. Сярод iх могуць быць улiковыя запiсы, створаныя прыкладаннямi, якiя вы ўсталявалi."</string>
+    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"прагляд сеткавых злучэнняў"</string>
+    <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Дазваляе прыкладанню праглядаць звесткi пра падключэннi да сеткi, напрыклад пра тое, якiя сеткi iснуюць i з якiмi ёсць сувязь."</string>
+    <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"атрымліваць поўны доступ да сеткі"</string>
+    <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Дазваляе прыкладанням ствараць сеткавыя сокеты і выкарыстоўваць уласныя сеткавыя пратаколы. браўзер і іншыя прыкладаннi прадастаўляюць сродкі для перадачы дадзеных у Iнтэрнэт, так што гэты дазвол для перадачы дадзеных у Iнтэрнэце не патрабуецца."</string>
+    <string name="permlab_changeNetworkState" msgid="958884291454327309">"змяніць падлучэнне да сеткі"</string>
+    <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Дазваляе прыкладанням змяняць стан сеткавага падключэння."</string>
+    <string name="permlab_changeTetherState" msgid="5952584964373017960">"змяніць прывязку да падлучэння"</string>
+    <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Дазваляе прыкладанням змяняць стан прывязкі да сеткі."</string>
+    <string name="permlab_accessWifiState" msgid="5202012949247040011">"прагляд злучэнняў Wi-Fi"</string>
+    <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Дазваляе прыкладанню праглядаць звесткi пра падключэннi да сеткi, напрыклад пра тое, дзе ёсць сеткi Wi-Fi i якiя прылады Wi-Fi да iх падключаны."</string>
+    <string name="permlab_changeWifiState" msgid="6550641188749128035">"падключэнне да сеткі Wi-Fi і адключэнне ад яе"</string>
+    <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Дазваляе прыкладанням падключацца да кропак доступу Wi-Fi і адключацца ад iх, а таксама ўносіць змяненні ў канфiгурацыю прылад сеткі Wi-Fi."</string>
+    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"дазваляе прыём Wi-Fi Multicast"</string>
+    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Дазваляе прыкладанням атрымліваць пакеты, адпраўленыя на ўсе прылады з сеткi Wi-Fi з дапамогай групавых адрасоў, а не толькі на ваш планшэт. Будзе выкарыстоўвацца больш энергіі, чым у рэжыме нешматадраснай перадачы."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Дазваляе праграме атрымліваць пакеты, адпраўленыя ўсім прыладам у сетцы Wi-Fi з дапамогай адрасоў шматадраснай рассылкі, а не толькі на ваш тэлевізар. Будзе выкарыстоўвацца больш энергіі, чым у нешматадрасным рэжыме."</string>
+    <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Дазваляе прыкладанням атрымліваць пакеты, адпраўленыя на ўсе прылады з сеткi Wi-Fi з дапамогай групавых адрасоў, а не толькі на ваш тэлефон. Будзе выкарыстоўвацца больш энергіі, чым у рэжыме нешматадраснай перадачы."</string>
+    <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"атрыманне доступу да налад прылады Bluetooth"</string>
+    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Дазваляе прыкладанням наладжваць лакальны планшэт Bluetooth, выяўляць і падлучаць выдаленыя прылады."</string>
+    <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Дазваляе праграме наладжваць канфігурацыю лакальнага тэлевізара з Bluetooth, а таксама выяўляць аддаленыя прылады і спалучацца з імі."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Дазваляе прыкладанням наладжваць лакальны тэлефон Bluetooth, а таксама знаходзіць выдаленыя прылады i падлучацца да ix."</string>
+    <string name="permlab_accessWimaxState" msgid="4195907010610205703">"падключаць да WiMAX i адключаць ад яго"</string>
+    <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Дазваляе прыкладанню вызначаць, ці ўключаны WiMAX, і інфармацыю пра любую сетку WiMAX, якая спалучана з iншымi."</string>
+    <string name="permlab_changeWimaxState" msgid="340465839241528618">"Змяніць стан WiMAX"</string>
+    <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Дазваляе прыкладанням падключаць планшэт да сеткі WiMAX i адключаць яго ад яе."</string>
+    <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Дазваляе праграме падлучаць тэлевізар да сетак WiMAX і адлучаць яго ад іх."</string>
+    <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Дазваляе прыкладанням падключацца да сетак WiMAX і адключацца ад iх."</string>
+    <string name="permlab_bluetooth" msgid="6127769336339276828">"падлучэнне да прылады Bluetooth"</string>
+    <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Дазваляе прыкладанню праглядаць канфігурацыю Bluetooth на планшэце , а таксама здзяйсняць і прымаць злучэнні са спалучанымі прыладамі."</string>
+    <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Дазваляе праграме праглядаць канфігурацыю Bluetooth на тэлевізары, а таксама выконваць і прымаць злучэнні са спалучанымі прыладамі."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Дазваляе прыкладанню праглядаць канфігурацыю Bluetooth на тэлефоне , а таксама здзяйсняць і прымаць злучэнні са спалучанымі прыладамі."</string>
+    <string name="permlab_nfc" msgid="4423351274757876953">"кантроль Near Field Communication"</string>
+    <string name="permdesc_nfc" msgid="7120611819401789907">"Дазваляе прыкладаннzv спалучацца з тэгамі, картамі і счытваючымі прыладамі Near Field Communication (NFC)."</string>
+    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"адключэнне блакiроўкi экрана"</string>
+    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Дазваляе прыкладанням адключаць блакiроўку клавіятуры і любыя сродкі абароны, звязаныя з паролем. Прыкладам гэтага з\'яўляецца адключэнне тэлефонам блакiроўкi клавіятуры пры атрыманні ўваходнага выкліку і паўторнае ўключэнне блакiроўкi клавіятуры, калі выклік завершаны."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"кіраваць апаратнымі сродкамі для адбіткаў пальцаў"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дазваляе праграме выкарыстоўваць спосабы дадання і выдалення шаблонаў адбіткаў пальцаў для выкарыстання."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"выкарыстоўваць апаратныя сродкі для адбіткаў пальцаў"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дазваляе праграме выкарыстоўваць апаратныя сродкі распазнання адбіткаў пальцаў для аўтэнтыфікацыі"</string>
+    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Выяўлена частка адбіткаў пальцаў. Паспрабуйце яшчэ раз."</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Не атрымалася апрацаваць адбітак пальца. Паспрабуйце яшчэ раз."</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Датчык адбіткаў пальцаў брудны. Ачысціце яго і паспрабуйце яшчэ раз."</string>
+    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Палец рухаўся занадта хутка. Паспрабуйце яшчэ раз."</string>
+    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Палец рухаўся занадта павольна. Паспрабуйце яшчэ раз."</string>
+  <string-array name="fingerprint_acquired_vendor">
+  </string-array>
+    <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратныя сродкі адбіткаў пальцаў недаступныя."</string>
+    <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Адбіткі пальцаў нельга захаваць. Выдаліце існы адбітак."</string>
+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час чакання адбіткаў пальцаў выйшаў. Паспрабуйце яшчэ раз."</string>
+    <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Аперацыя з адбіткамі пальцаў скасавана."</string>
+    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Занадта шмат спроб. Паспрабуйце яшчэ раз пазней."</string>
+    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Паспрабуйце яшчэ раз."</string>
+    <string name="fingerprint_name_template" msgid="5870957565512716938">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string>
+  <string-array name="fingerprint_error_vendor">
+  </string-array>
+    <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Значок адбіткаў пальцаў"</string>
+    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"чытаць параметры сінхранізацыі"</string>
+    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Дазваляе прыкладанням чытаць параметры сінхранізацыі для ўліковага запісу. Напрыклад, яны могуць вызначыць, цi сiнхранiзавана з улiковым запiсам прыкладанне \"Кантакты\"."</string>
+    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"уключэнне ці адключэнне сінхранізацыi"</string>
+    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Дазваляе прыкладанню змяняць налады сінхранізацыі для ўліковага запісу. Напрыклад, гэта можа выкарыстоўвацца для ўключэння сінхранізацыі прыкладання \"Кантакты\" з уліковым запісам."</string>
+    <string name="permlab_readSyncStats" msgid="7396577451360202448">"чытаць статыстыку сінхранізацыі"</string>
+    <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Дазваляе прыкладанням чытаць статыстыку сінхранізацыі для ўліковага запісу, у тым ліку гісторыю сінхранізацыі мерапрыемстваў і наколькі сінхранізаваны дадзеныя."</string>
+    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"чытанне змесціва USB-назапашв."</string>
+    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"чытанне змесціва SD-карты"</string>
+    <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Дазваляе праграме счытваць змесціва вашага USB-сховішча."</string>
+    <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Дазваляе праграме счытваць змесціва вашай SD-карты."</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"зм. або выд. змес. USB-назап."</string>
+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"змяніць або выдаліць змесціва SD-карты"</string>
+    <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Дазваляе прыкладаням выконваць запіс ва USB-назапашвальнік."</string>
+    <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанням запісваць на SD-карту."</string>
+    <string name="permlab_use_sip" msgid="2052499390128979920">"ажыццяўленне/прыманне выклікаў SIP"</string>
+    <string name="permdesc_use_sip" msgid="2297804849860225257">"Дазваляе праграме рабіць і прымаць выклікі SIP."</string>
+    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"рэгістрацыя новых падлучэнняў сувязі SIM"</string>
+    <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Дазваляе праграме рэгістраваць новыя падлучэнні сувязі SIM."</string>
+    <string name="permlab_register_call_provider" msgid="108102120289029841">"рэгістрацыя новых падлучэнняў сувязі"</string>
+    <string name="permdesc_register_call_provider" msgid="7034310263521081388">"Дазваляе праграме рэгістраваць новыя падлучэнні сувязі."</string>
+    <string name="permlab_connection_manager" msgid="1116193254522105375">"кіраванне падлучэннямі сувязі"</string>
+    <string name="permdesc_connection_manager" msgid="5925480810356483565">"Дазваляе праграме кіраваць падлучэннямі сувязі."</string>
+    <string name="permlab_bind_incall_service" msgid="6773648341975287125">"узаемадзеянне з экранам бягучага выкліку"</string>
+    <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"Дазваляе праграме кіраваць тым, калі і як карыстальнік бачыць экран бягучага выкліку."</string>
+    <string name="permlab_bind_connection_service" msgid="3557341439297014940">"узаемадзеянне са службамі тэлефаніі"</string>
+    <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Дазваляе праграме ўзаемадзейнічаць са службамі тэлефаніі, каб рабіць/прымаць выклікі."</string>
+    <string name="permlab_control_incall_experience" msgid="9061024437607777619">"прапанаванне аперацый, звязаных з выклікам"</string>
+    <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Дазваляе праграме прапаноўваць аперацыі, звязаныя з выклікам."</string>
+    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"чытаць дадзеныя выкарыстання сеткі"</string>
+    <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Дазваляе прыкладанню счытваць дадзеныя аб гісторыі выкарыстання сеткі для пэўных сетак і прыкладанняў."</string>
+    <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"кіраванне палітыкай сеткі"</string>
+    <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string>
+    <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string>
+    <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string>
+    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прывязка да службы апавяшчэння слухача"</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дазваляе ўладальніку прывязвацца да верхняга ўзроўню інтэрфейсу службы  апавяшчэння слухачоў. Ніколі не патрэбнае для звычайных прыкладанняў."</string>
+    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"прывязка да службы пастаўшчыка ўмоў"</string>
+    <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дазваляе ўладальніку выконваць прывязку да інтэрфейсу верхняга ўзроўню пастаўшчыка ўмоў. Ніколі не павінна патрабавацца для звычайных праграм."</string>
+    <string name="permlab_bindDreamService" msgid="4153646965978563462">"прывязка да службы экраннай застаўкі"</string>
+    <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Дазваляе ўладальніку выконваць прывязку да інтэрфейсу верхняга ўзроўню службы экраннай застаўкі. Ніколі не павінна патрабавацца для звычайных праграм."</string>
+    <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="permlab_handoverStatus" msgid="7820353257219300883">"атрымліваць стан перадачы Android Beam"</string>
+    <string name="permdesc_handoverStatus" msgid="4788144087245714948">"Дазваляе праграме атрымліваць інфармацыю аб бягучых перадачах Android Beam"</string>
+    <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"выдаленне сертыфікатаў DRM"</string>
+    <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Дазваляе праграме выдаляць сертыфікаты DRM. Ніколі не павінна патрабавацца для звычайных праграм."</string>
+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"прывязка да службы паведамленняў аператара"</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Дазваляе ўладальніку выконваць прывязку да інтэрфейсу верхняга ўзроўню службы паведамленняў аператара. Ніколі не павінна патрабавацца для звычайных праграм."</string>
+    <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"прывязвацца з сэрвісаў аператара"</string>
+    <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Дазваляе ўладальніку ажыццяўляць прывязку да сэрвісаў аператара. Ніколі не павінна патрабавацца для звычайных праграм."</string>
+    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"атрымліваць доступ да рэжыму «Не турбаваць»"</string>
+    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Дазваляе праграме чытаць і выконваць запіс у канфігурацыю рэжыму «Не турбаваць»."</string>
+    <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Кіраваць даўжынёй і сімваламі, дазволенымі пры ўводзе пароляў і PIN-кодаў блакіроўкі экрана."</string>
+    <string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
+    <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Сачыць за колькасцю няправільных набраных пароляў падчас разблакоўкі экрана і блакаваць планшэт або сціраць усе дадзеныя на ім, калі няправільны пароль набраны занадта шмат разоў."</string>
+    <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Сачыць за колькасцю няправільна набраных пароляў падчас разблакіроўкі экрана і блакіраваць тэлевізар або сціраць усе даныя на ім, калі няправільны пароль набраны занадта шмат разоў."</string>
+    <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Сачыць за колькасцю няправільных набраных пароляў падчас разблакоўкі экрана і блакаваць тяэлефон або сціраць усе дадзеныя на ім, калі набрана занадта шмат няправільных пароляў."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Сачыць за колькасцю няправільна набраных пароляў падчас разблакіроўкі экрана і блакіраваць планшэт або сцерці ўсе даныя гэтага карыстальніка, калі няправільны пароль набраны занадта шмат разоў."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Сачыць за колькасцю няправільна набраных пароляў падчас разблакіроўкі экрана і блакіраваць тэлевізар або сцерці ўсе даныя гэтага карыстальніка, калі няправільны пароль набраны занадта шмат разоў."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Сачыць за колькасцю няправільна набраных пароляў падчас разблакіроўкі экрана і блакіраваць тэлефон або сцерці ўсе даныя гэтага карыстальніка, калі няправільны пароль набраны занадта шмат разоў."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Змяніць блакіроўку экрана"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Змяніць блакіроўку экрана."</string>
+    <string name="policylab_forceLock" msgid="2274085384704248431">"Заблакаваць экран"</string>
+    <string name="policydesc_forceLock" msgid="1141797588403827138">"Кіраванне часам і спосабам блакавання экрана"</string>
+    <string name="policylab_wipeData" msgid="3910545446758639713">"Сцерці ўсе дадзеныя"</string>
+    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Выдаліць дадзеныя з планшэта без папярэджання, выканаўшы скід налад."</string>
+    <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Сцерці даныя з тэлевізара без папярэджання, выканаўшы скід да заводскіх налад."</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Выдаліць дадзеныя з тэлефона без папярэджання, выканаўшы скід налад."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Сцерці карыстальніцкія даныя"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Сцерці даныя гэтага карыстальніка на дадзеным планшэце без папярэджання."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Сцерці даныя гэтага карыстальніка на дадзеным тэлевізары без папярэджання."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Сцерці даныя гэтага карыстальніка на дадзеным тэлефоне без папярэджання."</string>
+    <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Усталяваць глабальны проксі прылады"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Задаць агульны проксі-cервер прылады, які будзе выкарыстоўвацца, калі прылада актыўная. Толькі ўладальнік прылады можа задаць агульны проксі-сервер."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Задаць тэрмін дзеяння пароля блакіроўкі экрана"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Змяняць частату, з якой павінны мяняцца пароль, PIN-код або ўзор блакіроўкі экрана."</string>
+    <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Усталяваць шыфраванне сховішча."</string>
+    <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Запыт на шыфраванне захаваных дадзеных прыкладанняў."</string>
+    <string name="policylab_disableCamera" msgid="6395301023152297826">"Адключыць камеры"</string>
+    <string name="policydesc_disableCamera" msgid="2306349042834754597">"Забараніць выкарыстанне ўсіх камер прылады."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Адкл.некат.функцыі блак.экрана"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Забараніць выкарыстанне некаторых функцый блакіроўкі экрана."</string>
+  <string-array name="phoneTypes">
+    <item msgid="8901098336658710359">"Галоўная старонка"</item>
+    <item msgid="869923650527136615">"Мабільны"</item>
+    <item msgid="7897544654242874543">"Працоўны"</item>
+    <item msgid="1103601433382158155">"Працоўны факс"</item>
+    <item msgid="1735177144948329370">"Хатні факс"</item>
+    <item msgid="603878674477207394">"Пэйджар"</item>
+    <item msgid="1650824275177931637">"Іншы"</item>
+    <item msgid="9192514806975898961">"Асаблівы"</item>
+  </string-array>
+  <string-array name="emailAddressTypes">
+    <item msgid="8073994352956129127">"Хатні"</item>
+    <item msgid="7084237356602625604">"Працоўны"</item>
+    <item msgid="1112044410659011023">"Іншы"</item>
+    <item msgid="2374913952870110618">"Карыстальніцкі"</item>
+  </string-array>
+  <string-array name="postalAddressTypes">
+    <item msgid="6880257626740047286">"На Галоўную старонку"</item>
+    <item msgid="5629153956045109251">"Працоўны"</item>
+    <item msgid="4966604264500343469">"Іншы"</item>
+    <item msgid="4932682847595299369">"Карыстальніцкі"</item>
+  </string-array>
+  <string-array name="imAddressTypes">
+    <item msgid="1738585194601476694">"Хатні"</item>
+    <item msgid="1359644565647383708">"Працоўны"</item>
+    <item msgid="7868549401053615677">"Іншы"</item>
+    <item msgid="3145118944639869809">"Карыстальніцкі"</item>
+  </string-array>
+  <string-array name="organizationTypes">
+    <item msgid="7546335612189115615">"Працоўны"</item>
+    <item msgid="4378074129049520373">"Іншае"</item>
+    <item msgid="3455047468583965104">"Карыстальніцкі"</item>
+  </string-array>
+  <string-array name="imProtocols">
+    <item msgid="8595261363518459565">"AIM"</item>
+    <item msgid="7390473628275490700">"Windows Live"</item>
+    <item msgid="7882877134931458217">"Yahoo"</item>
+    <item msgid="5035376313200585242">"Skype"</item>
+    <item msgid="7532363178459444943">"QQ"</item>
+    <item msgid="3713441034299660749">"Google Talk"</item>
+    <item msgid="2506857312718630823">"ICQ"</item>
+    <item msgid="1648797903785279353">"Jabber"</item>
+  </string-array>
+    <string name="phoneTypeCustom" msgid="1644738059053355820">"Карыстальніцкі"</string>
+    <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="phoneTypeFaxHome" msgid="2067265972322971467">"Хатні факс"</string>
+    <string name="phoneTypePager" msgid="7582359955394921732">"Пэйджар"</string>
+    <string name="phoneTypeOther" msgid="1544425847868765990">"Іншы"</string>
+    <string name="phoneTypeCallback" msgid="2712175203065678206">"Зваротны выклік"</string>
+    <string name="phoneTypeCar" msgid="8738360689616716982">"Машына"</string>
+    <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Асноўны тэлефон кампаніі"</string>
+    <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
+    <string name="phoneTypeMain" msgid="6766137010628326916">"Галоўны"</string>
+    <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Іншы факс"</string>
+    <string name="phoneTypeRadio" msgid="4093738079908667513">"Радыё"</string>
+    <string name="phoneTypeTelex" msgid="3367879952476250512">"Тэлекс"</string>
+    <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Працоўны мабільны нумар"</string>
+    <string name="phoneTypeWorkPager" msgid="649938731231157056">"Працоўны пэйджар"</string>
+    <string name="phoneTypeAssistant" msgid="5596772636128562884">"Асістэнт"</string>
+    <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
+    <string name="eventTypeCustom" msgid="7837586198458073404">"Карыстальніцкі"</string>
+    <string name="eventTypeBirthday" msgid="2813379844211390740">"Дзень нараджэння"</string>
+    <string name="eventTypeAnniversary" msgid="3876779744518284000">"Гадавіна"</string>
+    <string name="eventTypeOther" msgid="7388178939010143077">"Іншае"</string>
+    <string name="emailTypeCustom" msgid="8525960257804213846">"Карыстальніцкі"</string>
+    <string name="emailTypeHome" msgid="449227236140433919">"Галоўная старонка"</string>
+    <string name="emailTypeWork" msgid="3548058059601149973">"Працоўны"</string>
+    <string name="emailTypeOther" msgid="2923008695272639549">"Іншы"</string>
+    <string name="emailTypeMobile" msgid="119919005321166205">"Мабільны"</string>
+    <string name="postalTypeCustom" msgid="8903206903060479902">"Карыстальніцкі"</string>
+    <string name="postalTypeHome" msgid="8165756977184483097">"Галоўная старонка"</string>
+    <string name="postalTypeWork" msgid="5268172772387694495">"Працоўны"</string>
+    <string name="postalTypeOther" msgid="2726111966623584341">"Іншы"</string>
+    <string name="imTypeCustom" msgid="2074028755527826046">"Карыстальніцкі"</string>
+    <string name="imTypeHome" msgid="6241181032954263892">"Галоўная старонка"</string>
+    <string name="imTypeWork" msgid="1371489290242433090">"Працоўны"</string>
+    <string name="imTypeOther" msgid="5377007495735915478">"Іншы"</string>
+    <string name="imProtocolCustom" msgid="6919453836618749992">"Карыстальніцкі"</string>
+    <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
+    <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
+    <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
+    <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
+    <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
+    <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
+    <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
+    <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
+    <string name="orgTypeWork" msgid="29268870505363872">"Працоўная"</string>
+    <string name="orgTypeOther" msgid="3951781131570124082">"Іншая"</string>
+    <string name="orgTypeCustom" msgid="225523415372088322">"Карыстальніцкі"</string>
+    <string name="relationTypeCustom" msgid="3542403679827297300">"Карыстальніцкі"</string>
+    <string name="relationTypeAssistant" msgid="6274334825195379076">"Памочнік"</string>
+    <string name="relationTypeBrother" msgid="8757913506784067713">"Брат"</string>
+    <string name="relationTypeChild" msgid="1890746277276881626">"Дзіця"</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Унутраны Партнёр"</string>
+    <string name="relationTypeFather" msgid="5228034687082050725">"Бацька"</string>
+    <string name="relationTypeFriend" msgid="7313106762483391262">"Сябар/сяброўка"</string>
+    <string name="relationTypeManager" msgid="6365677861610137895">"Кіраўнік"</string>
+    <string name="relationTypeMother" msgid="4578571352962758304">"Маці"</string>
+    <string name="relationTypeParent" msgid="4755635567562925226">"Бацька"</string>
+    <string name="relationTypePartner" msgid="7266490285120262781">"Партнёр"</string>
+    <string name="relationTypeReferredBy" msgid="101573059844135524">"Запрошаны"</string>
+    <string name="relationTypeRelative" msgid="1799819930085610271">"Адносны"</string>
+    <string name="relationTypeSister" msgid="1735983554479076481">"Сястра"</string>
+    <string name="relationTypeSpouse" msgid="394136939428698117">"Муж/жонка"</string>
+    <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Карыстальніцкі"</string>
+    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Галоўная старонка"</string>
+    <string name="sipAddressTypeWork" msgid="6920725730797099047">"Працоўны"</string>
+    <string name="sipAddressTypeOther" msgid="4408436162950119849">"Іншае"</string>
+    <string name="quick_contacts_not_available" msgid="746098007828579688">"Адсутнічае праграма для прагляду гэтага кантакту."</string>
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Увядзіце PIN-код"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Увядзіце PUK-код і новы PIN-код"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новы PIN-код"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Каб разблакаваць, увядзіце PIN-код"</string>
+    <string name="keyguard_password_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="6169005837238288522">"Не абслугоўваецца"</string>
+    <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Экран заблакаваны."</string>
+    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Націсніце \"Меню\", каб разблакаваць, або зрабіце экстраны выклік."</string>
+    <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Націсніце \"Меню\", каб разблакаваць."</string>
+    <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Намалюйце камбінацыю разблакоўкі, каб разблакаваць"</string>
+    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Экстранная сітуацыя"</string>
+    <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Вярнуцца да выкліку"</string>
+    <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Правільна!"</string>
+    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Паспрабуйце яшчэ раз"</string>
+    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Паўтарыце спробу"</string>
+    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Перавышана максімальная колькасць спроб разблакоўкі праз Фэйскантроль"</string>
+    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Няма SIM-карты"</string>
+    <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Няма SIM-карты ў планшэце."</string>
+    <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"У тэлевізары няма SIM-карты."</string>
+    <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"У тэлефоне няма SIM-карты."</string>
+    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Усталюйце SIM-карту."</string>
+    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
+    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM-карту немагчыма выкарыстоўваць"</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ваша SIM-карта была адключана назаўсёды.\n Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
+    <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Папярэдні трэк"</string>
+    <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Наступны трэк"</string>
+    <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Прыпыніць"</string>
+    <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"Прайграць"</string>
+    <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Спыніць"</string>
+    <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Перамотка назад"</string>
+    <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Перамотка ўперад"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"Толькі экстраныя выклікі"</string>
+    <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Сетка заблакаваная"</string>
+    <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-карта заблакавана PUK-кодам."</string>
+    <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Глядзіце \"Інструкцыю для карыстальніка\" або звяжыцеся са службай тэхнiчнай падтрымкі."</string>
+    <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карта заблакаваная."</string>
+    <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Разблакаванне SIM-карты..."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакаваць планшэт з дапамогай уваходу ў Google.\n\n Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Вы няправільна нарысавалі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлевізар з дапамогай імя карыстальніка Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакаваць тэлефон з дапамогай уваходу ў Google.\n\n Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Вы не змаглі разблакіраваць тэлевізар столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя даныя будуць згублены."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да заводскіх налад."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Вы не змаглі разблакіраваць тэлевізар столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Вы няправільна спрабавалі разблакаваць тэлефон некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да заводскіх налад."</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+    <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забылі ўзор?"</string>
+    <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_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>
+    <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Праверка..."</string>
+    <string name="lockscreen_unlock_label" msgid="737440483220667054">"Разблакаваць"</string>
+    <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Гук уключаны"</string>
+    <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Гук выключаны"</string>
+    <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Ключ пачаты"</string>
+    <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Ключ выдалены"</string>
+    <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Сотавы дададзены"</string>
+    <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"Дададзена клетка <xliff:g id="CELL_INDEX">%1$s</xliff:g>"</string>
+    <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Ключ завершаны"</string>
+    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Вобласць узора."</string>
+    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ВIджэт %2$d з %3$d."</string>
+    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Дадаць віджэт"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Пусты"</string>
+    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Вобласць разблакіроўкі разгарнута."</string>
+    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Вобласць разблакіроўкі згарнута."</string>
+    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Віджэт <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Селектар карыстальнiка"</string>
+    <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Стан"</string>
+    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Налады мультымедыя"</string>
+    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Змяненне парадку віджэтаў пачалося."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Змяненне парадку віджэтаў скончылася."</string>
+    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Віджэт <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> выдалены."</string>
+    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Разгарнуць вобласць разблакіроўкі."</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Разблакiроўка слайда."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Узор разблакiроўкі."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Фэйскантроль"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-код разблакiроўкі."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Пароль разблакiроўкі."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Вобласць узора."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Вобласць слайда."</string>
+    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"123"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"Alt"</string>
+    <string name="granularity_label_character" msgid="7336470535385009523">"Знак"</string>
+    <string name="granularity_label_word" msgid="7075570328374918660">"слова"</string>
+    <string name="granularity_label_link" msgid="5815508880782488267">"спасылка"</string>
+    <string name="granularity_label_line" msgid="5764267235026120888">"радок"</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_reboot" msgid="6320168203050791643">"Перазагрузіць"</string>
+    <string name="js_dialog_title" msgid="1987483977834603872">"На старонцы з адрасам <xliff:g id="TITLE">%s</xliff:g> вызначана:"</string>
+    <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
+    <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Пацвердзіце пераход"</string>
+    <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Пакінуць гэту старонку"</string>
+    <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Заставацца на гэтай старонцы"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nВы ўпэўнены, што хочаце пакiнуць гэту старонку?"</string>
+    <string name="save_password_label" msgid="6860261758665825069">"Пацвердзіць"</string>
+    <string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
+    <string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
+    <string name="setup_autofill" msgid="7103495070180590814">"Усталяванне аўтазапаўнення"</string>
+    <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
+    <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
+    <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
+    <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+    <string name="autofill_province" msgid="2231806553863422300">"Правінцыя"</string>
+    <string name="autofill_postal_code" msgid="4696430407689377108">"Паштовы індэкс"</string>
+    <string name="autofill_state" msgid="6988894195520044613">"Штат"</string>
+    <string name="autofill_zip_code" msgid="8697544592627322946">"Паштовы індэкс"</string>
+    <string name="autofill_county" msgid="237073771020362891">"Акруга"</string>
+    <string name="autofill_island" msgid="4020100875984667025">"Востраў"</string>
+    <string name="autofill_district" msgid="8400735073392267672">"Раён"</string>
+    <string name="autofill_department" msgid="5343279462564453309">"Аддзел"</string>
+    <string name="autofill_prefecture" msgid="2028499485065800419">"Прэфектура"</string>
+    <string name="autofill_parish" msgid="8202206105468820057">"Прыход"</string>
+    <string name="autofill_area" msgid="3547409050889952423">"Плошча"</string>
+    <string name="autofill_emirate" msgid="2893880978835698818">"Эмірат"</string>
+    <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"чытанне вэб-закладак і гісторыi"</string>
+    <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Дазваляе прыкладанню счытваць усе URL-адрасы, якiя былi наведаны ў браўзеры, а таксама ўсе закладкi. Увага: гэты дазвол нельга ажыццяўляць пабочнымi браўзерамi або iншымi прыкладаннямi з уласцiвасцямi браўзера."</string>
+    <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"запіс вэб-закладак і гісторыi"</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Дазваляе прыкладанням змяняць гісторыю браўзера або закладкі, якiя захоўваюцца на планшэце. Гэта можа дазволіць прыкладанню выдаляць або змяняць дадзеныя браўзера. Увага: гэты дазвол не распаўсюджваецца на пабочныя браўзеры i iншыя прыкладаннi з функцыямi браўзера."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Дазваляе праграме змяняць гісторыю Браўзера або закладкі, якiя захоўваюцца на вашым тэлевізары. Гэта можа дазволіць праграме сціраць або змяняць даныя Браўзера. Увага: гэты дазвол можа не распаўсюджвацца на староннія браўзеры або iншыя праграмы з магчымасцямі прагляду вэб-старонак."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Дазваляе прыкладанню змяняць гісторыю браўзера, і закладкі, захаваныя ў тэлефоне. Гэта дазволіць прыкладанню выдаляць або змяняць дадзеныя браўзера. Увага: гэты дазвол можа не дзейнiчаць для іншых браўзераў і іншых прыкладанняў з магчымасцямі вэб-браўзера."</string>
+    <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="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"змяніць дазволы геапазіцыянавання для браўзэра"</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні выпадковым вэб-сайтам."</string>
+    <string name="save_password_message" msgid="767344687139195790">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string>
+    <string name="save_password_notnow" msgid="6389675316706699758">"Не цяпер"</string>
+    <string name="save_password_remember" msgid="6491879678996749466">"Запомніць"</string>
+    <string name="save_password_never" msgid="8274330296785855105">"Ніколі"</string>
+    <string name="open_permission_deny" msgid="7374036708316629800">"У вас няма дазволу на адкрыццё гэтай старонкі."</string>
+    <string name="text_copied" msgid="4985729524670131385">"Тэкст скапіяваны ў буфер абмену."</string>
+    <string name="more_item_label" msgid="4650918923083320495">"Больш"</string>
+    <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="search_go" msgid="8298016669822141719">"Пошук"</string>
+    <string name="search_hint" msgid="1733947260773056054">"Пошук..."</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_submit" msgid="2688450133297983542">"Адправіць запыт"</string>
+    <string name="searchview_description_voice" msgid="2453203695674994440">"Галасавы пошук"</string>
+    <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Уключыць функцыю Explore by Touch?"</string>
+    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"Служба доступу <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> запытвае ўключэнне функцыі Explore by Touch. Калі функцыя Explore by Touch будзе ўключаная, вы зможаце пачуць або ўбачыць апісанні таго, што знаходзіцца пад вашым пальцам, або выконваць жэсты для ўзаемадзеяння з планшэтам."</string>
+    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Служба доступу <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> запытвае ўключэнне функцыі Explore by Touch. Калі функцыя Explore by Touch будзе ўключаная, вы зможаце пачуць або ўбачыць апісанні таго, што знаходзіцца пад вашым пальцам, або выконваць жэсты для ўзаемадзеяння з тэлефонам."</string>
+    <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц таму"</string>
+    <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Раней, чым 1 месяц таму"</string>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Апошні <xliff:g id="COUNT_1">%d</xliff:g> дзень</item>
+      <item quantity="few">Апошнія <xliff:g id="COUNT_1">%d</xliff:g> дні</item>
+      <item quantity="many">Апошнія <xliff:g id="COUNT_1">%d</xliff:g> дзён</item>
+      <item quantity="other">Апошнія <xliff:g id="COUNT_1">%d</xliff:g> дня</item>
+    </plurals>
+    <string name="last_month" msgid="3959346739979055432">"Апошні месяц"</string>
+    <string name="older" msgid="5211975022815554840">"Раней"</string>
+    <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="days" msgid="4774547661021344602">"д."</string>
+    <string name="hour" msgid="2126771916426189481">"гадзіна"</string>
+    <string name="hours" msgid="894424005266852993">"г."</string>
+    <string name="minute" msgid="9148878657703769868">"хв."</string>
+    <string name="minutes" msgid="5646001005827034509">"хв."</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>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> секунда</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> секунды</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунды</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> хвіліна</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> хвіліны</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> хвілін</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> хвіліны</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> гадзіна</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> гадзіны</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> гадзін</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> гадзіны</item>
+    </plurals>
+    <string name="VideoView_error_title" msgid="3534509135438353077">"Праблема з відэа"</string>
+    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відэа не падыходзіць для патокавай перадачы на ​​гэту прыладу."</string>
+    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Немагчыма прайграць гэта відэа."</string>
+    <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="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>
+    <string name="cut" msgid="3092569408438626261">"Выразаць"</string>
+    <string name="copy" msgid="2681946229533511987">"Капіяваць"</string>
+    <string name="paste" msgid="5629880836805036433">"Уставіць"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Уставіць як звычайны тэкст"</string>
+    <string name="replace" msgid="5781686059063148930">"Замяніць..."</string>
+    <string name="delete" msgid="6098684844021697789">"Выдаліць"</string>
+    <string name="copyUrl" msgid="2538211579596067402">"Скапіяваць URL"</string>
+    <string name="selectTextMode" msgid="1018691815143165326">"Выбраць тэкст"</string>
+    <string name="undo" msgid="7905788502491742328">"Адрабіць"</string>
+    <string name="redo" msgid="7759464876566803888">"Узнавіць"</string>
+    <string name="textSelectionCABTitle" msgid="5236850394370820357">"Вылучэнне тэксту"</string>
+    <string name="addToDictionary" msgid="4352161534510057874">"Дадаць у слоўнік"</string>
+    <string name="deleteText" msgid="6979668428458199034">"Выдалiць"</string>
+    <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_no_boot" msgid="6935190099204693424">"Не хапае сховішча для сістэмы. Пераканайцеся, што ў вас ёсць 250 МБ свабоднага месца, і перазапусціце."</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="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
+    <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
+    <string name="capital_on" msgid="1544682755514494298">"Уключыць"</string>
+    <string name="capital_off" msgid="6815870386972805832">"Адключана"</string>
+    <string name="whichApplication" msgid="4533185947064773386">"Завяршыць дзеянне з дапамогай"</string>
+    <string name="whichApplicationNamed" msgid="8260158865936942783">"Завяршыць дзеянне з дапамогай %1$s"</string>
+    <string name="whichViewApplication" msgid="3272778576700572102">"Адкрыць з дапамогай"</string>
+    <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Адкрыць з дапамогай %1$s"</string>
+    <string name="whichEditApplication" msgid="144727838241402655">"Рэдагаваць з дапамогай"</string>
+    <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Рэдагаваць з дапамогай %1$s"</string>
+    <string name="whichSendApplication" msgid="6902512414057341668">"Падзяліцца праз"</string>
+    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Падзяліцца праз %s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Адправіць з дапамогай"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Адправіць з дапамогай %1$s"</string>
+    <string name="whichHomeApplication" msgid="4307587691506919691">"Выберыце праграму Галоўнай старонкі"</string>
+    <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Выкарыстоўваць %1$s у якасці праграмы Галоўнай старонкі"</string>
+    <string name="alwaysUse" msgid="4583018368000610438">"Выкарыстоўваць па змаўчанні для гэтага дзеяння."</string>
+    <string name="use_a_different_app" msgid="8134926230585710243">"Выкарыстоўваць іншую праграму"</string>
+    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ачысціць па змаўчанні ў раздзеле \"Налады сістэмы &gt; Прыкладанні &gt; Спампаваныя\"."</string>
+    <string name="chooseActivity" msgid="7486876147751803333">"Выберыце дзеянне"</string>
+    <string name="chooseUsbActivity" msgid="6894748416073583509">"Выберыце прыкладанне для USB-прылады"</string>
+    <string name="noApplications" msgid="2991814273936504689">"Няма прыкладанняў, якія могуць выконваць гэты працэс."</string>
+    <string name="aerr_application" msgid="250320989337856518">"Праграма <xliff:g id="APPLICATION">%1$s</xliff:g> спынілася"</string>
+    <string name="aerr_process" msgid="6201597323218674729">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> спыніўся"</string>
+    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> шматразова спыняе працу"</string>
+    <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> шматразова спыняе працу"</string>
+    <string name="aerr_restart" msgid="9001379185665886595">"Перазапусціць праграму"</string>
+    <string name="aerr_reset" msgid="7645427603514220451">"Скінуць і перазапусціць праграму"</string>
+    <string name="aerr_report" msgid="5371800241488400617">"Адправіць водгук"</string>
+    <string name="aerr_close" msgid="2991640326563991340">"Закрыць"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Адключыць гук да перазагрузкі прылады"</string>
+    <string name="aerr_wait" msgid="3199956902437040261">"Пачакаць"</string>
+    <string name="aerr_close_app" msgid="3269334853724920302">"Закрыць праграму"</string>
+    <string name="anr_title" msgid="4351948481459135709"></string>
+    <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> не адказвае"</string>
+    <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> не адказвае"</string>
+    <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> не адказвае"</string>
+    <string name="anr_process" msgid="6156880875555921105">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> не адказвае"</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>
+    <string name="launch_warning_title" msgid="1547997780506713581">"Прыкл. перанакіраванае"</string>
+    <string name="launch_warning_replace" msgid="6202498949970281412">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> зараз запушчанае."</string>
+    <string name="launch_warning_original" msgid="188102023021668683">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> запушчанае."</string>
+    <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
+    <string name="screen_compat_mode_show" msgid="4013878876486655892">"Заўсёды паказваць"</string>
+    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады &gt; Прыкладанні &gt; Спампаваныя\"."</string>
+    <string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
+    <string name="smv_process" msgid="5120397012047462446">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> парушыў уласную палітыку StrictMode."</string>
+    <string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
+    <string name="android_start_title" msgid="8418054686415318207">"Android запускаецца..."</string>
+    <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Аптымізацыя сховішча."</string>
+    <string name="android_upgrading_apk" msgid="7904042682111526169">"Аптымізацыя прыкладання <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Падрыхтоўка <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
+    <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
+    <string name="android_upgrading_complete" msgid="1405954754112999229">"Завяршэнне загрузкі."</string>
+    <string name="heavy_weight_notification" msgid="9087063985776626166">"Прыкладанне \"<xliff:g id="APP">%1$s</xliff:g>\" запушчанае"</string>
+    <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Націсніце, каб перайсці да прыкладання"</string>
+    <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Пераключыць прыкладанні?"</string>
+    <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ужо запушчана іншае прыкладанне, якое павінна быць спынена перад запускам новага."</string>
+    <string name="old_app_action" msgid="493129172238566282">"Вярнуцца да <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+    <string name="old_app_description" msgid="2082094275580358049">"Не запускайце новыя прыкладанні."</string>
+    <string name="new_app_action" msgid="5472756926945440706">"Запусціць <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+    <string name="new_app_description" msgid="1932143598371537340">"Спыніць старыя прыкладанні без захавання."</string>
+    <string name="dump_heap_notification" msgid="2618183274836056542">"Працэс <xliff:g id="PROC">%1$s</xliff:g> перавысіў ліміт памяці"</string>
+    <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Быў сабраны дамп кучы; дакраніцеся, каб абагуліць"</string>
+    <string name="dump_heap_title" msgid="5864292264307651673">"Абагуліць дамп дынамічнай вобласці?"</string>
+    <string name="dump_heap_text" msgid="4809417337240334941">"Працэс <xliff:g id="PROC">%1$s</xliff:g> перавысіў ліміт памяці працэсу <xliff:g id="SIZE">%2$s</xliff:g>. Дамп дынамічнай вобласці даступны для вас, вы можаце абагуліць яго з распрацоўшчыкам. Будзьце асцярожныя: гэты дамп дынамічнай вобласці можа ўтрымліваць асабістую інфармацыю, да якой маюць доступ праграмы."</string>
+    <string name="sendText" msgid="5209874571959469142">"Выберыце дзеянне для тэкста"</string>
+    <string name="volume_ringtone" msgid="6885421406845734650">"Гучнасць званка"</string>
+    <string name="volume_music" msgid="5421651157138628171">"Гучнасць прайгравальніка"</string>
+    <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Прайграваецца праз Bluetooth"</string>
+    <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Усталяваны ціхі рэжым"</string>
+    <string name="volume_call" msgid="3941680041282788711">"Гучнасць падчас размовы"</string>
+    <string name="volume_bluetooth_call" msgid="2002891926351151534">"Гучнасць Bluetooth падчас выкліку"</string>
+    <string name="volume_alarm" msgid="1985191616042689100">"Гучнасць будзільніка"</string>
+    <string name="volume_notification" msgid="2422265656744276715">"Гучнасць апавяшчэнняў"</string>
+    <string name="volume_unknown" msgid="1400219669770445902">"Гучнасць"</string>
+    <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Гучнасць Bluetooth"</string>
+    <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Гучнасць рынгтона"</string>
+    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Гучнасць выкліка"</string>
+    <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучнасць прайгравальніка"</string>
+    <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучнасць апавяшчэнняў"</string>
+    <string name="ringtone_default" msgid="3789758980357696936">"Рынгтон па змаўчаннi"</string>
+    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Рынгтон па змаўчаннi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Няма"</string>
+    <string name="ringtone_picker_title" msgid="3515143939175119094">"Рынгтоны"</string>
+    <string name="ringtone_unknown" msgid="5477919988701784788">"Невядомы рынгтон"</string>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">сетка Wi-Fi даступная</item>
+      <item quantity="few">сеткі Wi-Fi даступныя</item>
+      <item quantity="many">сетак Wi-Fi даступна</item>
+      <item quantity="other">сеткі Wi-Fi даступна</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">адкрытая сетка Wi-Fi даступная</item>
+      <item quantity="few">адкрытыя сеткі Wi-Fi даступныя</item>
+      <item quantity="many">адкрытых сетак Wi-Fi даступна</item>
+      <item quantity="other">адкрытай сеткі Wi-Fi даступна</item>
+    </plurals>
+    <string name="wifi_available_sign_in" msgid="9157196203958866662">"Уваход у сетку Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1848877297365446605">"Увайдзіце ў сетку"</string>
+    <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
+    <skip />
+    <string name="wifi_no_internet" msgid="8451173622563841546">"У Wi-Fi няма доступу да Інтэрнэту"</string>
+    <string name="wifi_no_internet_detailed" msgid="7593858887662270131">"Дакраніцеся, каб убачыць параметры"</string>
+    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
+    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дазволіць падключэнне?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Праграма %1$s хоча падлучыцца да сеткі Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Праграма"</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або кропку доступу Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string>
+    <string name="accept" msgid="1645267259272829559">"Прыняць"</string>
+    <string name="decline" msgid="2112225451706137894">"Адхіліць"</string>
+    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string>
+    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Запрашэнне далучыцца"</string>
+    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Ад:"</string>
+    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Каму:"</string>
+    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
+    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Тэлефон будзе часова адключаны ад сеткі Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"Тэлевізар будзе часова адключаны ад сеткі Wi-Fi, пакуль ён падключаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Тэлефон будзе часова адключаны ад Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
+    <string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"Прыкладанне &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; дасылае вялікую колькасць SMS-паведамленняў. Дазволіць гэтаму прыкладанню працягваць адпраўляць паведамленні?"</string>
+    <string name="sms_control_yes" msgid="3663725993855816807">"Дазволіць"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Забараніць"</string>
+    <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; хоча адправiць паведамленне на адрас &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
+    <string name="sms_short_code_details" msgid="5873295990846059400">"Гэта "<b>"можа прывесці да спагнання аплаты"</b>" з рахунку вашага мабільнага тэлефона."</string>
+    <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Гэта прывядзе да спагнання аплаты з рахунку вашага мабільнага тэлефона."</b></string>
+    <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Адправiць"</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">"Пазней гэта можна змянiць у раздзеле \"Налады &gt; Прыкладаннi\""</string>
+    <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Заўсёды дазваляць"</string>
+    <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Ніколі не дазваляць"</string>
+    <string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта выдаленая"</string>
+    <string name="sim_removed_message" msgid="5450336489923274918">"Мабільная сетка будзе недаступная да перазагрузкі з сапраўднай SIM-картай."</string>
+    <string name="sim_done_button" msgid="827949989369963775">"Гатова"</string>
+    <string name="sim_added_title" msgid="3719670512889674693">"SIM-карта дадазеная"</string>
+    <string name="sim_added_message" msgid="7797975656153714319">"Перазапусціце прыладу, каб атрымаць доступ да мабільнай сеткі."</string>
+    <string name="sim_restart_button" msgid="4722407842815232347">"Перазапусціць"</string>
+    <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Каб ваша новая SIM-карта працавала належным чынам, вам неабходна ўсталяваць і адкрыць праграму ад вашага аператара."</string>
+    <string name="carrier_app_dialog_button" msgid="7900235513678617329">"АТРЫМАЦЬ ПРАГРАМУ"</string>
+    <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"НЕ ЗАРАЗ"</string>
+    <string name="carrier_app_notification_title" msgid="8921767385872554621">"Устаўлена новая SIM-карта"</string>
+    <string name="carrier_app_notification_text" msgid="1132487343346050225">"Краніце, каб наладзіць"</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>
+    <string name="perms_description_app" msgid="5139836143293299417">"Прадастаўленыя прыкладаннем <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
+    <string name="perm_costs_money" msgid="4902470324142151116">"за гэта можа спаганяцца плата"</string>
+    <string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Па USB зараджаецца гэта прыладу"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Па USB падачецца сілкаванне падключанай прыладзе"</string>
+    <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перадачы файлаў"</string>
+    <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перадачы фота"</string>
+    <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для MIDI"</string>
+    <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Падключаны да USB-прылады"</string>
+    <string name="usb_notification_message" msgid="7347368030849048437">"Дакраніцеся, каб атрымаць больш параметраў."</string>
+    <string name="adb_active_notification_title" msgid="6729044778949189918">"Прылада адладкі USB падключана"</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Націсніце, каб адключыць адладку USB."</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Стварэнне справаздачы пра памылку…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Падзяліцца справаздачай пра памылку?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Перадача справаздачы пра памылку..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ІТ-адміністратар запытаў справаздачу пра памылку для яе ліквідацыі на гэтай прыладзе. Можа адбыцца абагуленне праграм і даных."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"АБАГУЛІЦЬ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"АДХІЛІЦЬ"</string>
+    <string name="select_input_method" msgid="8547250819326693584">"Змяніць клавіятуру"</string>
+    <string name="show_ime" msgid="2506087537466597099">"Захоўваць яе на экране ў той час, калі фізічная клавіятура актыўная"</string>
+    <string name="hardware" msgid="194658061510127999">"Паказаць віртуальную клавіятуру"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Наладжванне фізічнай клавіятуры"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string>
+    <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
+    <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+    <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
+    <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Падрыхтоўка <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Праверка на наяўнасць памылак"</string>
+    <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"Для перадачы фатаграфій і медыяфайлаў"</string>
+    <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"Пашкоджаны носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="ext_media_unmountable_notification_message" msgid="1586311304430052169">"Носьбіт <xliff:g id="NAME">%s</xliff:g> пашкоджаны. Дакраніцеся, каб выправіць."</string>
+    <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g> не падтрымліваецца"</string>
+    <string name="ext_media_unsupported_notification_message" msgid="8789610369456474891">"Гэта прылада не падтрымлівае носьбіт <xliff:g id="NAME">%s</xliff:g>. Дакраніцеся, каб наладзіць яго ў фармаце, які падтрымліваецца."</string>
+    <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Носьбіт <xliff:g id="NAME">%s</xliff:g> нечакана выняты"</string>
+    <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Адключыце носьбіт <xliff:g id="NAME">%s</xliff:g>, перш чым вымаць яго, каб пазбегнуць страты даных."</string>
+    <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"Носьбіт <xliff:g id="NAME">%s</xliff:g> выдалены"</string>
+    <string name="ext_media_nomedia_notification_message" msgid="6471542972147056586">"Носьбіт <xliff:g id="NAME">%s</xliff:g> выдалены; устаўце новы"</string>
+    <string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"Выманне <xliff:g id="NAME">%s</xliff:g> працягваецца..."</string>
+    <string name="ext_media_unmounting_notification_message" msgid="4182843895023357756">"Не выдаляць"</string>
+    <string name="ext_media_init_action" msgid="7952885510091978278">"Наладзіць"</string>
+    <string name="ext_media_unmount_action" msgid="1121883233103278199">"Выняць"</string>
+    <string name="ext_media_browse_action" msgid="8322172381028546087">"Праглядзець"</string>
+    <string name="ext_media_missing_title" msgid="620980315821543904">"<xliff:g id="NAME">%s</xliff:g> адсутнічае"</string>
+    <string name="ext_media_missing_message" msgid="5761133583368750174">"Паўторна ўстаўце прыладу"</string>
+    <string name="ext_media_move_specific_title" msgid="1471100343872375842">"Перамяшчэнне <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="ext_media_move_title" msgid="1022809140035962662">"Перамяшчэнне даных"</string>
+    <string name="ext_media_move_success_title" msgid="8575300932957954671">"Перамяшчэнне завершана"</string>
+    <string name="ext_media_move_success_message" msgid="4199002148206265426">"Даныя перамешчаны на <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="ext_media_move_failure_title" msgid="7613189040358789908">"Не атрымалася перамясціць даныя"</string>
+    <string name="ext_media_move_failure_message" msgid="1978096440816403360">"Даныя пакінуты ў зыходным месцы"</string>
+    <string name="ext_media_status_removed" msgid="6576172423185918739">"Носьбіт выдалены"</string>
+    <string name="ext_media_status_unmounted" msgid="2551560878416417752">"Носьбіт выняты"</string>
+    <string name="ext_media_status_checking" msgid="6193921557423194949">"Праверка..."</string>
+    <string name="ext_media_status_mounted" msgid="7253821726503179202">"Гатова"</string>
+    <string name="ext_media_status_mounted_ro" msgid="8020978752406021015">"Толькі чытанне"</string>
+    <string name="ext_media_status_bad_removal" msgid="8395398567890329422">"Носьбіт выдалены небяспечна"</string>
+    <string name="ext_media_status_unmountable" msgid="805594039236667894">"Носьбіт пашкоджаны"</string>
+    <string name="ext_media_status_unsupported" msgid="4691436711745681828">"Не падтрымлiваецца"</string>
+    <string name="ext_media_status_ejecting" msgid="5463887263101234174">"Выманне..."</string>
+    <string name="ext_media_status_formatting" msgid="1085079556538644861">"Фарматаванне..."</string>
+    <string name="ext_media_status_missing" msgid="5638633895221670766">"Носьбіт не ўстаўлены"</string>
+    <string name="activity_list_empty" msgid="1675388330786841066">"Адпаведныя дзеянні не знойдзены."</string>
+    <string name="permlab_route_media_output" msgid="6243022988998972085">"накіроўваць вывад мультымедыйнага змесціва"</string>
+    <string name="permdesc_route_media_output" msgid="4932818749547244346">"Дазваляе прыкладанням маршрутызаваць мультымедыйны выхад на iншыя знешнiя прылады."</string>
+    <string name="permlab_readInstallSessions" msgid="3713753067455750349">"чытаць сеансы ўсталёўкі"</string>
+    <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Дазваляе праграме счытваць сеансы ўсталёўкі. Гэта дазваляе ёй праглядаць інфармацыю аб актыўных усталёўках пакета."</string>
+    <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"запытваць усталёўку пакетаў"</string>
+    <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Дазваляе праграме запытваць усталёўку пакетаў."</string>
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двойчы дакраніцеся, каб змянiць маштаб"</string>
+    <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Немагчыма дадаць віджэт."</string>
+    <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_done" msgid="8971516117910934605">"Гатова"</string>
+    <string name="ime_action_previous" msgid="1443550039250105948">"Назад"</string>
+    <string name="ime_action_default" msgid="2840921885558045721">"Выканаць"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Набраць нумар\nз выкарыстаннем <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="4947405226788104538">"Стварыць кантакт\nз дапамогай<xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <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="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>
+    <string name="forward_intent_to_owner" msgid="1207197447013960896">"Вы выкарыстоўваеце гэту праграму па-за межамі свайго працоўнага профілю"</string>
+    <string name="forward_intent_to_work" msgid="621480743856004612">"Вы выкарыстоўваеце гэту праграму ў сваім працоўным профілі"</string>
+    <string name="input_method_binding_label" msgid="1283557179944992649">"Метад уводу"</string>
+    <string name="sync_binding_label" msgid="3687969138375092423">"Сінхранізацыя"</string>
+    <string name="accessibility_binding_label" msgid="4148120742096474641">"Спецыяльныя магчымасці"</string>
+    <string name="wallpaper_binding_label" msgid="1240087844304687662">"Шпалеры"</string>
+    <string name="chooser_wallpaper" msgid="7873476199295190279">"Змена шпалер"</string>
+    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слухач апавяшчэння"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Сродак праслухоўвання ў рэжыме віртуальнай рэальнасці (VR)"</string>
+    <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Пастаўшчык умоў"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Служба ацэнкі важнасці апавяшчэнняў"</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>
+    <string name="vpn_text_long" msgid="6407351006249174473">"Падлучаны да сеанса \"<xliff:g id="SESSION">%s</xliff:g>\". Дакраніцеся, каб кiраваць сеткай."</string>
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Падключэнне заўсёды ўключанага VPN..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Заўсёды ўключаны i падключаны VPN"</string>
+    <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="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_message" msgid="8035230537563503262">"Дакраніцеся, каб выйсці з рэжыму \"Штурман\"."</string>
+    <string name="tethered_notification_title" msgid="3146694234398202601">"USB-мадэм або кропка доступу Wi-Fi актыўныя"</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="skip_button_label" msgid="1275362299471631819">"Прапусціць"</string>
+    <string name="no_matches" msgid="8129421908915840737">"Няма супадзенняў"</string>
+    <string name="find_on_page" msgid="1946799233822820384">"Знайсці на старонцы"</string>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> з <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> з <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> з <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> з <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
+    <string name="action_mode_done" msgid="7217581640461922289">"Гатова"</string>
+    <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Выдаленне дадзеных з USB-назапашвальнiка..."</string>
+    <string name="progress_erasing" product="default" msgid="6596988875507043042">"Выдаленне дадзеных з SD-карты..."</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">"Знайсці нiжэй"</string>
+    <string name="find_previous" msgid="2196723669388360506">"Знайсці вышэй"</string>
+    <string name="gpsNotifTicker" msgid="5622683912616496172">"Запыт пра месцазнаходжанне ад карыстальніка <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="gpsNotifTitle" msgid="5446858717157416839">"Запыт месцазнаходжання"</string>
+    <string name="gpsNotifMessage" msgid="1374718023224000702">"Запыт ад карыстальнiка <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
+    <string name="gpsVerifYes" msgid="2346566072867213563">"Так"</string>
+    <string name="gpsVerifNo" msgid="1146564937346454865">"Не"</string>
+    <string name="sync_too_many_deletes" msgid="5296321850662746890">"Выдаліць перавышаны ліміт"</string>
+    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Выдалена элементаў для тыпу сінхранiзацыi \"<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>\": <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>. Уліковы запіс <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Што вы жадаеце зрабіць?"</string>
+    <string name="sync_really_delete" msgid="2572600103122596243">"Выдаліць элементы."</string>
+    <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_button_label" msgid="3611982894853435874">"Дадаць уліковы запіс"</string>
+    <string name="number_picker_increment_button" msgid="2412072272832284313">"Павялічыць"</string>
+    <string name="number_picker_decrement_button" msgid="476050778386779067">"Паменшыць"</string>
+    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Націсніце і ўтрымлівайце <xliff:g id="VALUE">%s</xliff:g>."</string>
+    <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Правядзіце пальцам уверх, каб павялічыць, або ўніз, каб паменшыць."</string>
+    <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Павялічыць лічбу хвілін."</string>
+    <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Паменшыць лічбу хвілін."</string>
+    <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Павялічыць лічбу гадзін."</string>
+    <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Паменшыць лічбу гадзін."</string>
+    <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Усталяваць час пасля паўдня"</string>
+    <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Усталяваць час да паўдня"</string>
+    <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Павялічыць лічбу месяца"</string>
+    <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Паменшыць лічбу месяца"</string>
+    <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Павялічыць лічбу дня"</string>
+    <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Паменшыць лічбу дня"</string>
+    <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Павялічыць лічбу года"</string>
+    <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Паменшыць лічбу года"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Папярэдні месяц"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Наступны месяц"</string>
+    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Адмена"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Выдаліць"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Гатова"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Змена рэжыму"</string>
+    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="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">"Адправiць з дапамогай прыкладання <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">"Каб праслухаць паролi, падключыце гарнiтуру."</string>
+    <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Кропка."</string>
+    <string name="action_bar_home_description" msgid="5293600496601490216">"Перайсці да пачатковай старонкі"</string>
+    <string name="action_bar_up_description" msgid="2237496562952152589">"Перайсці ўверх"</string>
+    <string name="action_menu_overflow_description" msgid="2295659037509008453">"Больш налад"</string>
+    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
+    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Унутранае абагуленае сховішча"</string>
+    <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
+    <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-карта <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
+    <string name="storage_usb_drive" msgid="6261899683292244209">"USB-дыск"</string>
+    <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-дыск <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
+    <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</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="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string>
+    <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string>
+    <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Дасягн. ліміт маб.перадачы даных"</string>
+    <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Дасягн. ліміт перад. даных Wi-Fi"</string>
+    <string name="data_usage_limit_body" msgid="291731708279614081">"Перад.даных спын. да канца цыкла"</string>
+    <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Перавышаны ліміт 2G-3G"</string>
+    <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Перавышаны ліміт дадзеных 4G"</string>
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Перавыш.ліміт маб.перадачы даных"</string>
+    <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Перав. ліміт па дадзеным Wi-Fi"</string>
+    <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Аб\'ём <xliff:g id="SIZE">%s</xliff:g> перавышае устаноўл. мяжу."</string>
+    <string name="data_usage_restricted_title" msgid="5965157361036321914">"Зыходныя дадзеныя абмежаваныя"</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Націсніце, каб зняць абмежаванне."</string>
+    <string name="ssl_certificate" msgid="6510040486049237639">"Сертыфікат бяспекі"</string>
+    <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Гэты сертыфікат сапраўдны."</string>
+    <string name="issued_to" msgid="454239480274921032">"Выдадзены:"</string>
+    <string name="common_name" msgid="2233209299434172646">"Звычайнае імя:"</string>
+    <string name="org_name" msgid="6973561190762085236">"Арганізацыя:"</string>
+    <string name="org_unit" msgid="7265981890422070383">"Аддзел арганізацыі:"</string>
+    <string name="issued_by" msgid="2647584988057481566">"Выдана:"</string>
+    <string name="validity_period" msgid="8818886137545983110">"Тэрмін дзеяння:"</string>
+    <string name="issued_on" msgid="5895017404361397232">"Выдадзены:"</string>
+    <string name="expires_on" msgid="3676242949915959821">"Заканчваецца:"</string>
+    <string name="serial_number" msgid="758814067660862493">"Серыйны нумар:"</string>
+    <string name="fingerprints" msgid="4516019619850763049">"Адбіткі пальцаў:"</string>
+    <string name="sha256_fingerprint" msgid="4391271286477279263">"Адбітак пальцаў SHA-256:"</string>
+    <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="sending" msgid="3245653681008218030">"Адпраўка..."</string>
+    <string name="launchBrowserDefault" msgid="2057951947297614725">"Запусцiць браўзер?"</string>
+    <string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"Заўсёды"</string>
+    <string name="activity_resolver_use_once" msgid="2404644797149173758">"Толькі адзін раз"</string>
+    <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не падтрымлівае працоўны профіль"</string>
+    <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшэт"</string>
+    <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТБ"</string>
+    <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Тэлефон"</string>
+    <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Навушнікі"</string>
+    <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Дынамікі станцыi"</string>
+    <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
+    <string name="default_audio_route_category_name" msgid="3722811174003886946">"Сістэма"</string>
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string>
+    <string name="wireless_display_route_description" msgid="9070346425023979651">"Бесправадны дысплей"</string>
+    <string name="media_route_button_content_description" msgid="591703006349356016">"Перадача"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Падлучыцца да прылады"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Трансліраваць экран на прыладу"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Пошук прылад..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Налады"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Адлучыць"</string>
+    <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканiраванне..."</string>
+    <string name="media_route_status_connecting" msgid="6422571716007825440">"Падключэнне..."</string>
+    <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_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> кр. на цалю"</string>
+    <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", бяспечны"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільна ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Няправiльны пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Няправільны PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%1$d</xliff:g> с."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйце ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Увядзіце PIN-код SIM-карты"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Увядзіце PIN-код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Увядзіце пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-карта зараз адключана. Увядзіце PUK-код, каб працягнуць. Звяжыцеся са сваiм аператарам, каб атрымаць дадатковую iнфармацыю."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Увядзіце жаданы PIN-код"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Пацвердзіце жадан PIN-код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблакiроўка SIM-карты..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Няправільны PIN-код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK-код павінен змяшчаць 8 лічбаў."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Паўторна увядзіце правільны PUK-код. Неаднаразовыя спробы назаўжды адключаць SIM-карту."</string>
+    <string name="kg_invalid_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">"Каб разблакiраваць, увайдзіце ў свой уліковы запіс Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Імя карыстальніка (электронная пошта)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Увайсцi"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Няправільнае імя карыстальніка ці пароль."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыліся на імя карыстальніка або пароль?\nНаведайце "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="1052685197710252395">"Праверка ўлiковага запiсу..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Вы не змаглі разблакіраваць тэлевізар столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя даныя будуць згублены."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да завадскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Вы не змаглі разблакіраваць тэлевізар столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Вы няправільна спрабавалі разблакiраваць тэлефон некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Вы няправільна ўвялі ўзор разблакiроўкi столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакiраваць тэлевізар з дапамогай уліковага запісу вашай электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Выдалiць"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утрымлiвайце два пальцы, каб уключыць доступ."</string>
+    <string name="accessibility_enabled" msgid="1381972048564547685">"Даступнасць уключана."</string>
+    <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Даступнасць адменена."</string>
+    <string name="user_switched" msgid="3768006783166984410">"Бягучы карыстальнік <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="user_switching_message" msgid="2871009331809089783">"Пераход да <xliff:g id="NAME">%1$s</xliff:g>..."</string>
+    <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> выходзіць з сістэмы…"</string>
+    <string name="owner_name" msgid="2716755460376028154">"Уладальнік"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Памылка"</string>
+    <string name="error_message_change_not_allowed" msgid="1347282344200417578">"Ваш адміністратар не дазваляе гэту змену"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Прыкладанне для гэтага дзеяння не знойдзенае"</string>
+    <string name="revoke" msgid="5404479185228271586">"Ануляваць"</string>
+    <string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
+    <string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
+    <string name="mediasize_iso_a2" msgid="3097535991925798280">"ISO A2"</string>
+    <string name="mediasize_iso_a3" msgid="3023213259314236123">"ISO A3"</string>
+    <string name="mediasize_iso_a4" msgid="231745325296873764">"ISO A4"</string>
+    <string name="mediasize_iso_a5" msgid="3484327407340865411">"ISO A5"</string>
+    <string name="mediasize_iso_a6" msgid="4861908487129577530">"ISO A6"</string>
+    <string name="mediasize_iso_a7" msgid="5890208588072936130">"ISO A7"</string>
+    <string name="mediasize_iso_a8" msgid="4319425041085816612">"ISO A8"</string>
+    <string name="mediasize_iso_a9" msgid="4882220529506432008">"ISO A9"</string>
+    <string name="mediasize_iso_a10" msgid="2382866026365359391">"ISO A10"</string>
+    <string name="mediasize_iso_b0" msgid="3651827147402009675">"ISO B0"</string>
+    <string name="mediasize_iso_b1" msgid="6072859628278739957">"ISO В1"</string>
+    <string name="mediasize_iso_b2" msgid="1348731852150380378">"ISO В2"</string>
+    <string name="mediasize_iso_b3" msgid="2612510181259261379">"ISO B3"</string>
+    <string name="mediasize_iso_b4" msgid="695151378838115434">"ISO B4"</string>
+    <string name="mediasize_iso_b5" msgid="4863754285582212487">"ISO B5"</string>
+    <string name="mediasize_iso_b6" msgid="5305816292139647241">"ISO В6"</string>
+    <string name="mediasize_iso_b7" msgid="531673542602786624">"ISO B7"</string>
+    <string name="mediasize_iso_b8" msgid="9164474595708850034">"ISO B8"</string>
+    <string name="mediasize_iso_b9" msgid="282102976764774160">"ISO B9"</string>
+    <string name="mediasize_iso_b10" msgid="4517141714407898976">"ISO B10"</string>
+    <string name="mediasize_iso_c0" msgid="3103521357901591100">"ISO C0"</string>
+    <string name="mediasize_iso_c1" msgid="1231954105985048595">"ISO C1"</string>
+    <string name="mediasize_iso_c2" msgid="927702816980087462">"ISO С2"</string>
+    <string name="mediasize_iso_c3" msgid="835154173518304159">"ISO C3"</string>
+    <string name="mediasize_iso_c4" msgid="5095951985108194011">"ISO C4"</string>
+    <string name="mediasize_iso_c5" msgid="1985397450332305739">"ISO C5"</string>
+    <string name="mediasize_iso_c6" msgid="8147421924174693013">"ISO C6"</string>
+    <string name="mediasize_iso_c7" msgid="8993994925276122950">"ISO C7"</string>
+    <string name="mediasize_iso_c8" msgid="6871178104139598957">"ISO С8"</string>
+    <string name="mediasize_iso_c9" msgid="7983532635227561362">"ISO C9"</string>
+    <string name="mediasize_iso_c10" msgid="5040764293406765584">"ISO C10"</string>
+    <string name="mediasize_na_letter" msgid="2841414839888344296">"Letter"</string>
+    <string name="mediasize_na_gvrnmt_letter" msgid="5295836838862962809">"Government Letter"</string>
+    <string name="mediasize_na_legal" msgid="8621364037680465666">"Legal"</string>
+    <string name="mediasize_na_junior_legal" msgid="3309324162155085904">"Junior Legal"</string>
+    <string name="mediasize_na_ledger" msgid="5567030340509075333">"Ledger"</string>
+    <string name="mediasize_na_tabloid" msgid="4571735038501661757">"Tabloid"</string>
+    <string name="mediasize_na_index_3x5" msgid="5182901917818625126">"Index Card 3x5"</string>
+    <string name="mediasize_na_index_4x6" msgid="7687620625422312396">"Index Card 4x6"</string>
+    <string name="mediasize_na_index_5x8" msgid="8834215284646872800">"Index Card 5x8"</string>
+    <string name="mediasize_na_monarch" msgid="213639906956550754">"Monarch"</string>
+    <string name="mediasize_na_quarto" msgid="835778493593023223">"Quarto"</string>
+    <string name="mediasize_na_foolscap" msgid="1573911237983677138">"Foolscap"</string>
+    <string name="mediasize_chinese_roc_8k" msgid="3626855847189438896">"ROC 8K"</string>
+    <string name="mediasize_chinese_roc_16k" msgid="9182191577022943355">"ROC 16K"</string>
+    <string name="mediasize_chinese_prc_1" msgid="4793232644980170500">"PRC 1"</string>
+    <string name="mediasize_chinese_prc_2" msgid="5404109730975720670">"PRC 2"</string>
+    <string name="mediasize_chinese_prc_3" msgid="1335092253339363526">"PRC 3"</string>
+    <string name="mediasize_chinese_prc_4" msgid="9167997800486569834">"PRC 4"</string>
+    <string name="mediasize_chinese_prc_5" msgid="845875168823541497">"PRC 5"</string>
+    <string name="mediasize_chinese_prc_6" msgid="3220325667692648789">"PRC 6"</string>
+    <string name="mediasize_chinese_prc_7" msgid="1776792138507038527">"PRC 7"</string>
+    <string name="mediasize_chinese_prc_8" msgid="1417176642687456692">"PRC 8"</string>
+    <string name="mediasize_chinese_prc_9" msgid="4785983473123798365">"PRC 9"</string>
+    <string name="mediasize_chinese_prc_10" msgid="7847982299391851899">"PRC 10"</string>
+    <string name="mediasize_chinese_prc_16k" msgid="262793383539980677">"PRC 16K"</string>
+    <string name="mediasize_chinese_om_pa_kai" msgid="5256815579447959814">"Pa Kai"</string>
+    <string name="mediasize_chinese_om_dai_pa_kai" msgid="7336412963441354407">"Dai Pa Kai"</string>
+    <string name="mediasize_chinese_om_jurro_ku_kai" msgid="6324465444100490742">"Jurro Ku Kai"</string>
+    <string name="mediasize_japanese_jis_b10" msgid="1787262845627694376">"JIS B10"</string>
+    <string name="mediasize_japanese_jis_b9" msgid="3336035783663287470">"JIS B9"</string>
+    <string name="mediasize_japanese_jis_b8" msgid="6195398299104345731">"JIS B8"</string>
+    <string name="mediasize_japanese_jis_b7" msgid="1674621886902828884">"JIS B7"</string>
+    <string name="mediasize_japanese_jis_b6" msgid="4170576286062657435">"JIS B6"</string>
+    <string name="mediasize_japanese_jis_b5" msgid="4899297958100032533">"JIS B5"</string>
+    <string name="mediasize_japanese_jis_b4" msgid="4213158129126666847">"JIS B4"</string>
+    <string name="mediasize_japanese_jis_b3" msgid="8513715307410310696">"JIS B3"</string>
+    <string name="mediasize_japanese_jis_b2" msgid="4777690211897131190">"JIS В2"</string>
+    <string name="mediasize_japanese_jis_b1" msgid="4608142385457034603">"JIS В1"</string>
+    <string name="mediasize_japanese_jis_b0" msgid="7587108366572243991">"JIS B0"</string>
+    <string name="mediasize_japanese_jis_exec" msgid="5244075432263649068">"JIS Exec"</string>
+    <string name="mediasize_japanese_chou4" msgid="4941652015032631361">"Chou4"</string>
+    <string name="mediasize_japanese_chou3" msgid="6387319169263957010">"Chou3"</string>
+    <string name="mediasize_japanese_chou2" msgid="1299112025415343982">"Chou2"</string>
+    <string name="mediasize_japanese_hagaki" msgid="8070115620644254565">"Hagaki"</string>
+    <string name="mediasize_japanese_oufuku" msgid="6049065587307896564">"Oufuku"</string>
+    <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
+    <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
+    <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_cannot_write" msgid="8132505417935337724">"Памылка запісу змесціва"</string>
+    <string name="reason_unknown" msgid="6048913880184628119">"невядома"</string>
+    <string name="reason_service_unavailable" msgid="7824008732243903268">"Служба друку не ўключана"</string>
+    <string name="print_service_installed_title" msgid="2246317169444081628">"Усталявана служба <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="print_service_installed_message" msgid="5897362931070459152">"Краніце, каб уключыць"</string>
+    <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Увядзіце PIN-код адміністратара"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Увядзіце PIN-код"</string>
+    <string name="restr_pin_incorrect" msgid="8571512003955077924">"Няправільны"</string>
+    <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_error_doesnt_match" msgid="2224214190906994548">"PIN-коды не супадаюць. Паўтарыце спробу."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код занадта кароткі. Павінен змяшчаць не менш за 4 лічбы."</string>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Паспрабуйце яшчэ раз праз <xliff:g id="COUNT">%d</xliff:g> секунду</item>
+      <item quantity="few">Паспрабуйце яшчэ раз праз <xliff:g id="COUNT">%d</xliff:g> секунды</item>
+      <item quantity="many">Паспрабуйце яшчэ раз праз <xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="other">Паспрабуйце яшчэ раз праз <xliff:g id="COUNT">%d</xliff:g> секунды</item>
+    </plurals>
+    <string name="restr_pin_try_later" msgid="973144472490532377">"Паўтарыце спробу пазней"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Прагляд у поўнаэкранным рэжыме"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Для выхаду правядзіце зверху ўніз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Зразумела"</string>
+    <string name="done_label" msgid="2093726099505892398">"Гатова"</string>
+    <string name="hour_picker_description" msgid="6698199186859736512">"Кругавы паўзунок гадзін"</string>
+    <string name="minute_picker_description" msgid="8606010966873791190">"Кругавы паўзунок хвілін"</string>
+    <string name="select_hours" msgid="6043079511766008245">"Выберыце гадзіны"</string>
+    <string name="select_minutes" msgid="3974345615920336087">"Выберыце хвіліны"</string>
+    <string name="select_day" msgid="7774759604701773332">"Выберыце месяц і дзень"</string>
+    <string name="select_year" msgid="7952052866994196170">"Выберыце год"</string>
+    <string name="deleted_key" msgid="7659477886625566590">"Выдалена: <xliff:g id="KEY">%1$s</xliff:g>"</string>
+    <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (праца)"</string>
+    <string name="lock_to_app_toast" msgid="7570091317001980053">"Каб адмацаваць гэты экран, краніце і ўтрымлівайце кнопкі «Назад» і «Агляд» адначасова."</string>
+    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Каб адмацаваць гэты экран, краніце і ўтрымлівайце кнопку «Агляд»."</string>
+    <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Праграма замацавана: адмацаванне на гэтай прыладзе не дапускаецца."</string>
+    <string name="lock_to_app_start" msgid="6643342070839862795">"Экран замацаваны"</string>
+    <string name="lock_to_app_exit" msgid="8598219838213787430">"Экран адмацаваны"</string>
+    <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запытваць PIN-код перад адмацаваннем"</string>
+    <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запытваць узор разблакіроўкі перад адмацаваннем"</string>
+    <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запытваць пароль перад адмацаваннем"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Праграма можа не працаваць у рэжыме дзялення экрана."</string>
+    <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Праграма не падтрымлівае функцыю дзялення экрана."</string>
+    <string name="package_installed_device_owner" msgid="8420696545959087545">"Усталявана вашым адміністратарам"</string>
+    <string name="package_updated_device_owner" msgid="8856631322440187071">"Абноўлена вашым адміністратарам"</string>
+    <string name="package_deleted_device_owner" msgid="7650577387493101353">"Выдалена вашым адміністратарам"</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"Каб падоўжыць час працы акумулятара, у рэжыме эканоміі зараду памяншаецца прадукцыйнасць вашай прылады, абмяжоўваецца выкарыстанне вібрацыі, службаў вызначэння месцазнаходжання і большасці задач фонавай перадачы даных. Электронная пошта, абмен паведамленнямі і іншыя праграмы, якія выкарыстоўваюць сінхранізацыю, могуць не абнаўляцца, пакуль вы іх не адкрыеце.\n\nРэжым эканоміі зараду адключаецца аўтаматычна, калі прылада зараджаецца."</string>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">На %1$d хвіліну (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">На %1$d хвіліны (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">На %1$d хвілін (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">На %1$d хвіліны (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes_summary_short" formatted="false" msgid="6830154222366042597">
+      <item quantity="one">На %1$d хв (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">На %1$d хв (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">На %1$d хв (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">На %1$d хв (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">На %1$d гадзіну (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">На %1$d гадзіны (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">На %1$d гадзін (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">На %1$d гадзіны (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="4787552595253082371">
+      <item quantity="one">На %1$d гадз (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">На %1$d гадз (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">На %1$d гадз (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">На %1$d гадз (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">На %d хвіліну</item>
+      <item quantity="few">На %d хвіліны</item>
+      <item quantity="many">На %d хвілін</item>
+      <item quantity="other">На %d хвіліны</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes_short" formatted="false" msgid="2199350154433426128">
+      <item quantity="one">На %d хв</item>
+      <item quantity="few">На %d хв</item>
+      <item quantity="many">На %d хв</item>
+      <item quantity="other">На %d хв</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">На %d гадзіну</item>
+      <item quantity="few">На %d гадзіны</item>
+      <item quantity="many">На %d гадзін</item>
+      <item quantity="other">На %d гадзіны</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_short" formatted="false" msgid="6748277774662434217">
+      <item quantity="one">На %d гадз</item>
+      <item quantity="few">На %d гадз</item>
+      <item quantity="many">На %d гадз</item>
+      <item quantity="other">На %d гадз</item>
+    </plurals>
+    <string name="zen_mode_until" msgid="7336308492289875088">"Да <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+    <string name="zen_mode_alarm" msgid="9128205721301330797">"Да <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (наступны будзільнік)"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Пакуль вы не выключыце гэта"</string>
+    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Пакуль вы не выключыце рэжым «Не турбаваць»"</string>
+    <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
+    <string name="toolbar_collapse_description" msgid="2821479483960330739">"Згарнуць"</string>
+    <string name="zen_mode_feature_name" msgid="5254089399895895004">"Не турбаваць"</string>
+    <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Час бяздзеяння"</string>
+    <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Будні вечар"</string>
+    <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Выхадныя"</string>
+    <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Падзея"</string>
+    <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> адключыў(-ла) гук"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"На вашай прыладзе ўзнікла ўнутраная праблема, і яна можа працаваць нестабільна, пакуль вы не зробіце скід да заводскіх налад."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"На вашай прыладзе ўзнікла ўнутраная праблема. Для атрымання дадатковай інфармацыі звярніцеся да вытворцы."</string>
+    <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"Запыт USSD зменены на запыт DIAL."</string>
+    <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"Запыт USSD зменены на запыт SS."</string>
+    <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"Запыт USSD зменены на новы запыт USSD."</string>
+    <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Запыт SS зменены на запыт DIAL."</string>
+    <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Запыт SS зменены на запыт USSD."</string>
+    <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Запыт SS зменены на новы запыт SS."</string>
+    <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Працоўны профіль"</string>
+    <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Перыферыйны USB-порт Android"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"Перыферыйны USB-порт"</string>
+    <string name="floating_toolbar_open_overflow_description" msgid="4797287862999444631">"Дадатковыя параметры"</string>
+    <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"Закрыць лішак"</string>
+    <string name="maximize_button_text" msgid="7543285286182446254">"Разгарнуць"</string>
+    <string name="close_button_text" msgid="3937902162644062866">"Закрыць"</string>
+    <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> выбраны</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> выбрана</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> выбрана</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> выбрана</item>
+    </plurals>
+    <string name="importance_from_user" msgid="7318955817386549931">"Вы задалі важнасць гэтых апавяшчэнняў."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Гэта важна, бо з гэтым звязаны пэўныя людзі."</string>
+    <string name="user_creation_account_exists" msgid="1942606193570143289">"Дазволіць <xliff:g id="APP">%1$s</xliff:g> стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="user_creation_adding" msgid="4482658054622099197">"Дазволіць <xliff:g id="APP">%1$s</xliff:g> стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g> (Карыстальнік з гэтым уліковым запісам ужо існуе)?"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Дадаць мову"</string>
+    <string name="country_selection_title" msgid="2954859441620215513">"Параметры рэгіёна"</string>
+    <string name="search_language_hint" msgid="7042102592055108574">"Увядзіце назву мовы"</string>
+    <string name="language_picker_section_suggested" msgid="8414489646861640885">"Прапанаваныя"</string>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Усе мовы"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Шукаць"</string>
+    <string name="work_mode_off_title" msgid="8954725060677558855">"Рэжым працы АДКЛЮЧАНЫ"</string>
+    <string name="work_mode_off_message" msgid="3286169091278094476">"Дазволіць функцыянаванне працоўнага профілю, у тым ліку праграм, фонавай сінхранізацыі і звязаных з імі функцый."</string>
+    <string name="work_mode_turn_on" msgid="2062544985670564875">"Уключыць"</string>
+    <string name="new_sms_notification_title" msgid="8442817549127555977">"У вас ёсць новыя паведамленні"</string>
+    <string name="new_sms_notification_content" msgid="7002938807812083463">"Праглядзець праз праграму для SMS"</string>
+    <string name="user_encrypted_title" msgid="9054897468831672082">"Частка функц. можа быць абмеж."</string>
+    <string name="user_encrypted_message" msgid="4923292604515744267">"Краніце, каб разблакіраваць"</string>
+    <string name="user_encrypted_detail" msgid="5708447464349420392">"Карыст. даныя заблакіраваны"</string>
+    <string name="profile_encrypted_detail" msgid="3700965619978314974">"Рабочы профіль заблакіраваны"</string>
+    <string name="profile_encrypted_message" msgid="6964994232310195874">"Кран., каб разбл. раб. профіль"</string>
+    <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Падлучана да <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
+    <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Краніце для прагляду файлаў"</string>
+    <string name="pin_target" msgid="3052256031352291362">"Замацаваць"</string>
+    <string name="unpin_target" msgid="3556545602439143442">"Адмацаваць"</string>
+    <string name="app_info" msgid="6856026610594615344">"Інфармацыя пра праграму"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Выканайце скід да заводскіх налад, каб выкарыстоўваць гэту прыладу без абмежаванняў"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Краніце, каб даведацца больш."</string>
+</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a5255a6..76c7002 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласова помощ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заключване сега"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Съдържанието е скрито чрез правило"</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="user_owner_label" msgid="1119010402169916617">"Превключване към личния потребителски профил"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Превключване към служебния пoтребителски профил"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"има достъп до контактите ви"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактиране чрез %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Споделяне чрез"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Споделяне чрез %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Изпращане посредством"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Изпращане посредством %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Избиране на начално приложение"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Използване на %1$s като начално приложение"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Използване по подразбиране за това действие."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Нулиране и рестартиране на приложението"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Изпращане на отзиви"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Затваряне"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Спиране"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Спиране, докато устройството се рестартира"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Изчакване"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Затваряне на приложението"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Не се изискват разрешения"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"това може да ви струва пари"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB за зареждане"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"През USB се зарежда това устройство"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"През USB се зарежда свързаното устройство"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB за прехвърляне на файлове"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB за прехвърляне на снимки"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Докоснете за още опции."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняване на грешки през USB"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Докоснете за деактивиране"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЕМАМ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТХВЪРЛЯМ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Сигналът за програмна грешка се извлича…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели ли сигналът за програмна грешка?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Сигналът за програмна грешка се споделя…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Системният ви администратор поиска сигнал за програмна грешка с цел отстраняване на неизправностите на това устройство. Възможно е да бъдат споделени приложения и данни."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛЯНЕ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТХВЪРЛЯНЕ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Промяна на клавиатурата"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Избиране на клавиатури"</string>
     <string name="show_ime" msgid="2506087537466597099">"Показване на екрана, докато физическата клавиатура е активна"</string>
     <string name="hardware" msgid="194658061510127999">"Показване на вирт. клавиатура"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избиране на клавиатурна подредба"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Докоснете, за да изберете клавиатурна подредба."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуриране на физическата клавиатура"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Приемател за виртуална реалност"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Доставчик на условия"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помощник за известия"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Услуга за класифициране на известията"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Още опции"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"„%1$s“ – %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"„%1$s“, „%2$s“ – %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Вътрешно хранилище"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Вътрешно споделено хранилище"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD карта"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD карта от <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB устройство"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитване за ПИН код преди освобождаване"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запитване за фигура за отключване преди освобождаване"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запитване за парола преди освобождаване"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Приложението не може да се преоразмерява. Превъртете го с два пръста."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Приложението може да не работи в режим на разделен екран."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Приложението не поддържа разделен екран."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Инсталирано от администратора ви"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Актуализирано от администратора ви"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">Избрахте <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Избрахте <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Други"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Зададохте важността на тези известия."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Зададохте важността на тези известия."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Това е важно заради участващите хора."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g> (вече съществува потребител с този профил)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Езиково предпочитание"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Добавяне на език"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Предпочитание за региона"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Въведете име на език"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Работният режим е ИЗКЛЮЧЕН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Разрешаване на функционирането на служебния потребителски профил, включително приложенията, синхронизирането на заден план и свързаните функции."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Включване"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Пакетът „%1$s“ е деактивиран"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Деактивирано от администратора на %1$s. Свържете се с него, за да научите повече."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Имате нови съобщения"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Преглед в приложението за SMS"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Някои функции може да са огранич."</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Фиксиране"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Освобождаване"</string>
     <string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Възстановете фабричните настройки на това устройство, за да го използвате без ограничения"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Докоснете, за да научите повече."</string>
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index eacfd3b..620e532 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -28,11 +28,11 @@
     <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
     <string name="fileSizeSuffix" msgid="8897567456150907538">"<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="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="durationMinute" msgid="7155301744174623818">"<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>
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ডিফল্টরুপে কলার ID সীমাবদ্ধ করা থাকে না৷ পরবর্তী কল: সীমাবদ্ধ নয়"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"পরিষেবা প্রস্তুত নয়৷"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"আপনি কলার ID এর সেটিংস পরিবর্তন করতে পারবেন না৷"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"ভয়েস সহায়তা"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"এখনই লক করুন"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>টি)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"নীতির কারণে সামগ্রী লুকানো আছে"</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="user_owner_label" msgid="1119010402169916617">"ব্যক্তিগততে পাল্টান"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"কর্মস্থানে পাল্টান"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"পরিচিতি"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"আপনার পরিচিতিগুলিতে অ্যাক্সেস করুন"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"অবস্থান"</string>
@@ -831,8 +829,8 @@
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> এ"</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="hour" msgid="2126771916426189481">"ঘণ্টা"</string>
+    <string name="hours" msgid="894424005266852993">"ঘণ্টা"</string>
     <string name="minute" msgid="9148878657703769868">"মি"</string>
     <string name="minutes" msgid="5646001005827034509">"মিনিট"</string>
     <string name="second" msgid="3184235808021478">"সেকেন্ড"</string>
@@ -850,8 +848,8 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> মিনিট</item>
     </plurals>
     <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
-      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ঘন্টা</item>
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ঘন্টা</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ঘণ্টা</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ঘণ্টা</item>
     </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"ভিডিও সমস্যা"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"এই ভিডিওটি এই ডিভাইসে স্ট্রিমিং করার জন্য বৈধ নয়৷"</string>
@@ -871,7 +869,7 @@
     <string name="paste_as_plain_text" msgid="5427792741908010675">"প্লেইন টেক্সট হিসাবে আটকান"</string>
     <string name="replace" msgid="5781686059063148930">"প্রতিস্থাপন করুন..."</string>
     <string name="delete" msgid="6098684844021697789">"মুছুন"</string>
-    <string name="copyUrl" msgid="2538211579596067402">"URL অনুলিপি করুন"</string>
+    <string name="copyUrl" msgid="2538211579596067402">"URL কপি করুন"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"পাঠ্য নির্বাচন করুন"</string>
     <string name="undo" msgid="7905788502491742328">"পূর্বাবস্থায় ফিরুন"</string>
     <string name="redo" msgid="7759464876566803888">"পুনরায় করুন"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s দিয়ে সম্পাদনা করুন"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"এর সাথে শেয়ার করুন"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s এর সাথে শেয়ার করুন"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"এটি ব্যবহার করে পাঠান"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ব্যবহার করে পাঠান"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"একটি হোম অ্যাপ্লিকেশন নির্বাচন করুন"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"হোম হিসাবে %1$s ব্যবহার করুন"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"এই ক্রিয়াটির জন্য এটিকে ডিফল্টরুপে ব্যবহার করুন৷"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"পুনরায় সেট করুন এবং অ্যাপ্লিকেশান পুনরায় আরম্ভ করুন"</string>
     <string name="aerr_report" msgid="5371800241488400617">"প্রতিক্রিয়া পাঠান"</string>
     <string name="aerr_close" msgid="2991640326563991340">"বন্ধ করুন"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"নিঃশব্দ করুন"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"ডিভাইসটি পুনরায় আরম্ভ না হওয়া পর্যন্ত নিঃশব্দ করুন"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"অপেক্ষা করুন"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"অ্যাপ্লিকেশান বন্ধ করুন"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"কোনো অনুমতির প্রয়োজন নেই"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"এর জন্য অর্থপ্রদান করতে হতে পারে"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ঠিক আছে"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"চার্জ করার জন্য USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"এই ডিভাইসটি USB দ্বারা চার্জ করা হচ্ছে"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"সংযুক্ত ডিভাইসটিতে USB পাওয়ার সরবরাহ করছে"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ফাইল স্থানান্তরের জন্য USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ফটো স্থানান্তরের জন্য USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI এর জন্য USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"আরো বিকল্পের জন্য স্পর্শ করুন৷"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ডিবাগিং সংযুক্ত হয়েছে"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ডিবাগিং অক্ষম করতে স্পর্শ করুন৷"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"স্বীকার করুন"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"অস্বীকার করুন"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ত্রুটির প্রতিবেদন নেওয়া হচ্ছে..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ত্রুটির প্রতিবেদন শেয়ার করবেন?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ত্রুটির প্রতিবেদন শেয়ার করা হচ্ছে..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"আপনার আইটি প্রশাসক এই ডিভাইসটির সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন৷ অ্যাপ্লিকেশান এবং ডেটা শেয়ার করা হতে পারে৷"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"শেয়ার করুন"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"অস্বীকার করুন"</string>
     <string name="select_input_method" msgid="8547250819326693584">"কীবোর্ড পরিবর্তন করুন"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"কীবোর্ড চয়ন করুন"</string>
     <string name="show_ime" msgid="2506087537466597099">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
     <string name="hardware" msgid="194658061510127999">"ভার্চুয়াল কীবোর্ড দেখান"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"কীবোর্ডের লেআউট নির্বাচন করুন"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"একটি কীবোর্ডের লেআউট নির্বাচন করতে স্পর্শ করুন৷"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ফিজিক্যাল কীবোর্ড কনফিগার করুন"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ওয়ালপেপার"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ওয়ালপেপার পরিবর্তন করুন"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"বিজ্ঞপ্তির শ্রোতা"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR শ্রোতা"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"শর্ত প্রদানকারী"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"বিজ্ঞপ্তি সহায়ক"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"বিজ্ঞপ্তি র‌্যাঙ্কার পরিষেবা"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN সক্রিয়"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> এর দ্বারা VPN সক্রিয় করা হয়েছে"</string>
     <string name="vpn_text" msgid="3011306607126450322">"নেটওয়ার্ক পরিচালনা করতে স্পর্শ করুন৷"</string>
@@ -1197,8 +1192,8 @@
     <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"বাড়ানোর জন্য উপরের দিকে এবং কমানোর জন্য নীচের দিকে স্লাইড করুন৷"</string>
     <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"মিনিট বাড়ান"</string>
     <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"মিনিট কমান"</string>
-    <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"ঘন্টা বাড়ান"</string>
-    <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"ঘন্টা কমান"</string>
+    <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"ঘণ্টা বাড়ান"</string>
+    <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"ঘণ্টা কমান"</string>
     <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"PM সেট করুন"</string>
     <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"AM সেট করুন"</string>
     <string name="date_picker_increment_month_button" msgid="5369998479067934110">"মাস বাড়ান"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"আরো বিকল্প"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"অভ্যন্তরীণ সঞ্চয়স্থান"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"অভ্যন্তরীণ শেয়ার করা সঞ্চয়স্থান"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD কার্ড"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD কার্ড"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ড্রাইভ"</string>
@@ -1457,9 +1452,9 @@
     <string name="immersive_cling_description" msgid="3482371193207536040">"প্রস্থান করতে উপর থেকে নীচের দিকে সোয়াইপ করুন"</string>
     <string name="immersive_cling_positive" msgid="5016839404568297683">"বুঝেছি"</string>
     <string name="done_label" msgid="2093726099505892398">"সম্পন্ন হয়েছে"</string>
-    <string name="hour_picker_description" msgid="6698199186859736512">"বৃত্তাকার ঘন্টা নির্বাচকের স্লাইডার"</string>
+    <string name="hour_picker_description" msgid="6698199186859736512">"বৃত্তাকার ঘণ্টা নির্বাচকের স্লাইডার"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"বৃত্তাকার মিনিট নির্বাচকের স্লাইডার"</string>
-    <string name="select_hours" msgid="6043079511766008245">"ঘন্টা নির্বাচন করুন"</string>
+    <string name="select_hours" msgid="6043079511766008245">"ঘণ্টা নির্বাচন করুন"</string>
     <string name="select_minutes" msgid="3974345615920336087">"মিনিট নির্বাচন করুন"</string>
     <string name="select_day" msgid="7774759604701773332">"মাস এবং দিন নির্বাচন করুন"</string>
     <string name="select_year" msgid="7952052866994196170">"বছর নির্বাচন করুন"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"আনপিন করার আগে পিন চান"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"আনপিন করার আগে আনলক প্যাটার্ন চান"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"আনপিন করার আগে পাসওয়ার্ড চান"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"অ্যাপ্লিকেশানকে পুনরায় আকার দেওয়া যাবে না, দুটি আঙ্গুল ব্যবহার করে স্ক্রোল করুন৷"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"অ্যাপ্লিকেশানটি বিভক্ত স্ক্রীনে কাজ নাও করতে পারে৷"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"অ্যাপ্লিকেশান বিভক্ত-স্ক্রীন সমর্থন করে না৷"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"আপনার প্রশাসক দ্বারা ইনস্টল করা হয়েছে"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"আপনার প্রশাসক দ্বারা আপডেট করা হয়েছে"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"বিবিধ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"লোকজন জড়িত থাকার কারণে এটি গুরুত্বপূর্ণ।"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> কে <xliff:g id="ACCOUNT">%2$s</xliff:g> এর সাথে একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি দেবেন কি?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> কে <xliff:g id="ACCOUNT">%2$s</xliff:g> (একজন ব্যবহারকারী এই অ্যাকাউন্টে ইতিমধ্যেই বিদ্যমান আছেন) এর সাথে একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি দেবেন কি?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"পছন্দের ভাষা"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"একটি ভাষা যোগ করুন"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"পছন্দের অঞ্চল"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ভাষার নাম লিখুন"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"প্রস্তাবিত"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"কাজের মোড বন্ধ আছে"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"অ্যাপ্লিকেশান, পটভূমি সিঙ্ক এবং সম্পর্কিত বৈশিষ্ট্যগুলি সহ কর্মস্থলের প্রোফাইলটিকে কাজ করার মঞ্জুরি দিন।"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"চালু করুন"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s অক্ষম করা আছে"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s প্রশাসক অক্ষম করেছেন। আরো জানতে তাদের সাথে যোগাযোগ করুন।"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"আপনার নতুন বার্তা আছে"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"দেখার জন্য SMS অ্যাপ্লিকেশান খুলুন"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"কিছু ক্রিয়াকলাপ সীমিত হতে পারে"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"পিন করুন"</string>
     <string name="unpin_target" msgid="3556545602439143442">"আনপিন করুন"</string>
     <string name="app_info" msgid="6856026610594615344">"অ্যাপ্লিকেশানের তথ্য"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"কোনো বিধিনিষেধ ছাড়াই এই ডিভাইসটিকে ব্যবহার করতে ফ্যাক্টরি রিসেট করুন"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"আরো জানতে স্পর্শ করুন৷"</string>
 </resources>
diff --git a/core/res/res/values-bs-rBA-watch/strings.xml b/core/res/res/values-bs-rBA-watch/strings.xml
new file mode 100644
index 0000000..51d4120
--- /dev/null
+++ b/core/res/res/values-bs-rBA-watch/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g>. aplikac. od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzori"</string>
+</resources>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 84e2826..82639af 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -89,7 +89,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Prikaz ID-a pozivaoca u zadanim postavkama nije zabranjen. Sljedeći poziv: nije zabranjen"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Uslugu nije moguće koristiti."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Ne možete promijeniti postavke ID-a pozivaoca."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Promijenjen ograničen pristup"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Usluga prijenosa podataka je blokirana."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hitni pozivi su blokirani."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Govorne usluge su blokirane."</string>
@@ -232,13 +231,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj odmah"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je sakriven"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj skriven u skladu sa pravilima"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Poslovni"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Prebacite se na lični"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Prebacite se na radni"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupa vašim kontaktima"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -907,6 +905,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Podijeli koristeći"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Podijeli koristeći %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Pošalji koristeći"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Pošalji koristeći %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Odaberi glavnu aplikaciju"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Koristi %1$s kao glavnu aplikaciju"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Koristiti kao zadanu rezoluciju za ovu akciju."</string>
@@ -923,7 +923,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Vrati aplikaciju na zadano i pokreni ponovo"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Pošalji povratne informacije"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Zanemari"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Isključiti zvuk dok se uređaj ponovo ne pokrene"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Sačekaj"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Zatvori aplikaciju"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,7 +1053,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nisu potrebne dozvole"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ovo se možda dodatno plaća"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Uredu"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Ovaj uređaj se puni preko USB-a"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB napaja priključeni uređaj"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prijenos fajlova"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos slika"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1061,24 +1062,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Uređaj za USB otklanjanje grešaka povezan"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili USB otklanjanje grešaka."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBACI"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Prijem izvještaja o grešci..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Podijeliti izvještaj o grešci?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvještaja o grešci..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Vaš IT administrator je zatražio izvještaj o grešci kako bi pomogao u rješavanju problema ovog uređaja. Aplikacije i podaci se mogu dijeliti."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PODIJELI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBACI"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Promijeni tastaturu"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Odaberite tastature"</string>
     <string name="show_ime" msgid="2506087537466597099">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
     <string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tastaturu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Odaberite raspored tastature"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite za odabir rasporeda tastature."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguriraj fizičku tastaturu"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -1151,8 +1145,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Promijenite pozadinsku sliku"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Usluga za praćenje obavještenja"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR slušalac"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Pružalac uslova"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obavještenja"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Usluga rangiranja obavještenja"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
@@ -1238,7 +1233,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Više opcija"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interna pohrana"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Interno dijeljena pohrana"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kartica"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kartica"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB disk"</string>
@@ -1483,7 +1478,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN prije nego se otkači"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži uzorak za otključavanje prije nego se otkači"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži lozinku prije nego se otkači"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veličina aplikacije nije promjenjiva, pomičite je s dva prsta."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće raditi na podijeljenom ekranu"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava dijeljenje ekrana."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalirao administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao administrator"</string>
@@ -1562,12 +1557,11 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> stavki je odabrano</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Vi postavljate značaj ovih oabvještenja."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Vi određujete značaj ovih obavještenja."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ovo je značajno zbog osoba koje su uključene."</string>
-    <string name="user_creation_account_exists" msgid="1942606193570143289">"Da li dozvoljate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za nalog <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="user_creation_account_exists" msgid="1942606193570143289">"Da li dozvoljavate aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Da li dozvoljavate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (Korisnik sa ovim nalogom već postoji)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Izbor jezika"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Dodaj jezik"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Izbor regije"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
@@ -1576,8 +1570,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način rada je ISKLJUČEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogući radnom profilu da funkcionira, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Uključi"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s – onemogućeno"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Onemogućio administrator (%1$s). Obratite mu se za više informacija."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nove poruke"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorite SMS aplikaciju da biste pregledali poruke"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Neke funkcije mogu biti ograničene"</string>
@@ -1590,4 +1582,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Zakači"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Otkači"</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Vratite uređaj na fabričke postavke kako biste ga koristili bez ograničenja"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da saznate više."</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f9ecd06..6fcadfa 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El valor predeterminat de l\'identificador de l\'emissor és no restringit. Següent trucada: no restringit"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"No s\'ha proveït el servei."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"No pots canviar la configuració de l\'identificador de l\'emissor."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Accés restringit canviat"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"El servei de dades està bloquejat."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servei d\'emergència està bloquejat."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"El servei de veu està bloquejat."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. per veu"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloqueja ara"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contingut amagat de conformitat amb la política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Feina"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Canvia al perfil personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Canvia al perfil professional"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactes"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedir als contactes"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ubicació"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edita amb %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Comparteix amb"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Comparteix amb %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Envia mitjançant"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Envia mitjançant %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Seleccionar una aplicació Inici"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utilitzar %1$s com a Inici"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilitza-ho de manera predeterminada per a aquesta acció."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Restableix i reinicia l\'aplicació"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Envia suggeriments"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Tanca"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Silencia"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Silencia fins que es reiniciï el dispositiu"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Espera"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Tanca l\'aplicació"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No cal cap permís"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"pot ser que comporti càrrecs"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"D\'acord"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB per carregar"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"L\'USB està carregant el dispositiu"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"L\'USB subministra energia al dispositiu connectat"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB per transferir fitxers"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB per transferir fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per a MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Toca per veure més opcions."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuració USB activada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca per desactivar la depuració USB"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTA"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REBUTJA"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"S\'està creant l\'informe d\'errors…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vols compartir l\'informe d\'errors?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"S\'està compartint l\'informe d\'errors…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"L\'administrador de TI ha sol·licitat un informe d\'errors per resoldre els problemes d\'aquest dispositiu. És possible que es comparteixin aplicacions i dades."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTEIX"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REBUTJA"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Tria els teclats"</string>
     <string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
     <string name="hardware" msgid="194658061510127999">"Mostra el teclat virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona una disposició de teclat"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca per seleccionar una disposició de teclat."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclat físic"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Processador de realitat virtual"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveïdor de condicions"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistent de notificacions"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Servei de classificació 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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Més opcions"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Emmagatzematge intern"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Emmagatzematge intern compartit"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Targeta SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Targeta SD de: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unitat USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sol·licita el codi PIN per anul·lar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sol·licita el patró de desbloqueig per anul·lar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demana la contrasenya per anul·lar"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"No es pot canviar la mida de l\'aplicació. Desplaça-la amb dos dits."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"És possible que l\'aplicació no funcioni amb la pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"L\'aplicació no admet la pantalla dividida."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"L\'administrador ho ha instal·lat"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"L\'administrador l\'ha actualitzat"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">Seleccionats: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Seleccionats: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Altres"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Tu has definit la importància d\'aquestes notificacions."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Has definit la importància d\'aquestes notificacions."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Aquest missatge és important per les persones implicades."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ja hi ha un usuari amb aquest compte.)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferència d\'idioma"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Afegeix un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferència de regió"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nom de l\'idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerits"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode de feina desactivat"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permet que el perfil professional funcioni, incloses les aplicacions, la sincronització en segon pla i les funcions relacionades."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Activa"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Aplicació %1$s desactivada"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"L\'administrador de l\'empresa %1$s ha desactivat el paquet. Contacta-hi per obtenir-ne més informació."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Tens missatges nous"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Obre l\'aplicació de SMS per veure\'ls"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Algunes funcions es limitaran"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fixa"</string>
     <string name="unpin_target" msgid="3556545602439143442">"No fixis"</string>
     <string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restableix les dades de fàbrica del dispositiu per utilitzar-lo sense restriccions"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca per obtenir més informació."</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 19f8864..127d38b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -90,7 +90,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Služba není zřízena."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nastavení identifikace volajícího nesmíte měnit."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Omezený přístup byl změněn."</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datová služba je zablokována."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Tísňová linka je zablokována."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Hlasová služba je zablokována."</string>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlas. asistence"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah skrytý zásadami"</string>
     <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobní"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Práce"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Přepnout na osobní profil"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Přepnout na pracovní profil"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"přístup ke kontaktům"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upravit v aplikaci %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Sdílet v aplikaci"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Sdílet v aplikaci %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Odeslat pomocí aplikace"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Odeslat pomocí aplikace %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Výběr aplikace na plochu"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Jako plochu používat aplikaci %1$s."</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Použít jako výchozí nastavení pro tuto činnost."</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Obnovit a restartovat aplikaci"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Odeslat zpětnou vazbu"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zavřít"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorovat"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignorovat do restartu zařízení"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Počkat"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Zavřít aplikaci"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nejsou vyžadována žádná oprávnění"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"může vás to něco stát"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB na nabíjení"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Nabíjení zařízení přes USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Připojené zařízení se nabíjí přes USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB na přenos souborů"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB na přenos fotek"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB v režimu MIDI"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Klepnutím zobrazíte další možnosti."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes USB připojeno"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotykem zakážete ladění USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PŘIJMOUT"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODMÍTNOUT"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Vytváření zprávy o chybě…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Sdílet zprávu o chybě?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sdílení zprávy o chybě…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit. Aplikace a data mohou být sdílena."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SDÍLET"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMÍTNOUT"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Změna klávesnice"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Vybrat klávesnici"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
     <string name="hardware" msgid="194658061510127999">"Zobrazit virtuální klávesnici"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Výběr rozložení klávesnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotykem vyberte rozložení klávesnice."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurace fyzické klávesnice"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
@@ -1159,8 +1153,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Přijímač virtuální reality"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovatel podmínky"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent oznámení"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Služba na hodnocení důležitosti oznámení"</string>
     <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>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Další možnosti"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s – %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s – %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interní úložiště"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Interní sdílené úložiště"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD karta <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Jednotka USB"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Před uvolněním požádat o PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Před uvolněním požádat o bezpečnostní gesto"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Před uvolněním požádat o heslo"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Velikost aplikace nelze změnit. Zobrazení můžete posouvat dvěma prsty."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikace v režimu rozdělené obrazovky nemusí fungovat."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Nainstalováno administrátorem"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizováno administrátorem"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> položek</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> položka</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Různé"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Důležitost oznámení určujete vy."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Důležitost oznámení určujete vy."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Uživatel s tímto účtem již existuje.)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferovaný jazyk"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Přidat jazyk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferovaná oblast"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Zadejte název jazyka"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovní režim je VYPNUTÝ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Povolí fungování pracovního profilu, včetně aplikací, synchronizace na pozadí a souvisejících funkcí."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Zapnout"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Balíček %1$s byl zakázán"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Zakázáno administrátorem zařízení %1$s. Chcete-li získat další informace, kontaktujte jej."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Máte nové zprávy"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Zobrazíte je v aplikaci pro SMS"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Funkce mohou být omezeny"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Připnout"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Odepnout"</string>
     <string name="app_info" msgid="6856026610594615344">"Informace o aplikaci"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Chcete-li toto zařízení používat bez omezení, obnovte jej do továrního nastavení"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím zobrazíte další informace."</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 6c36d86..407f1f8 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Ikke begrænset"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjenesten leveres ikke!"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Du kan ikke ændre indstillingen for opkalds-id\'et."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begrænset adgang ændret"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjenesten er blokeret."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjenesten er blokeret."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Stemmetjenesten er blokeret."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Taleassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Indholdet er skjult af politikken"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Arbejde"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Skift til Tilpasset"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Skift til arbejde"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersoner"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Del med"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Del med %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Send via"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Send via %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Vælg en startapp"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Brug %1$s som startapp"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Nulstil og genstart appen"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Luk"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorer"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignorer, indtil enheden genstarter"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Vent"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Luk app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste dig penge"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB til opladning"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB, der oplader denne enhed"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, der leverer strøm til den tilsluttede enhed"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB til filoverførsel"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB til billedoverførsel"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB til MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Tryk for at se flere muligheder."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tryk for at deaktivere USB-fejlretning."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTÉR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AFVIS"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Opretter fejlrapport…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele fejlrapporten?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler fejlrapport…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen på enheden. Apps og data deles muligvis."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AFVIS"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Skift tastatur"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Vælg tastaturer"</string>
     <string name="show_ime" msgid="2506087537466597099">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
     <string name="hardware" msgid="194658061510127999">"Vis virtuelt tastatur"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Vælg tastaturlayout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tryk for at vælge et tastaturlayout."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurer fysisk tastatur"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-lyttefunktion"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tjeneste til formidling af betingelser"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Underretningsassistent"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste til rangering af underretninger"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere valgmuligheder"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Intern lagerplads"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Intern delt lagerplads"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-kort fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-drev"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bed om oplåsningsmønster ved deaktivering"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bed om adgangskode inden frigørelse"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Appens størrelse kan ikke ændres. Gennemgå den ved at rulle med to fingre."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen fungerer muligvis ikke i delt skærm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen understøtter ikke delt skærm."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installeret af din administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Opdateret af administrator"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>valgt</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Du angiver, hvor vigtige disse underretninger er."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse underretninger er."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Sprogindstilling"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Tilføj et sprog"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Områdeindstilling"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Angiv sprogets navn"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslået"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbejdstilstand er slået FRA"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillad, at arbejdsprofilen aktiveres, bl.a. i forbindelse med apps, baggrundssynkronisering og relaterede funktioner."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Slå til"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s er deaktiveret"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Deaktiveret af %1$s administrator. Kontakt vedkommende for at få flere oplysninger."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nye beskeder"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Åbn sms-appen for at se beskeden"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Nogle funktioner er begrænsede"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fastgør"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Frigør"</string>
     <string name="app_info" msgid="6856026610594615344">"Oplysninger om appen"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Gendan fabriksdataene på enheden for at bruge den uden begrænsninger"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryk for at få flere oplysninger."</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b68c7a1..e539a28 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Dienst nicht eingerichtet."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Du kannst die Einstellung für die Anrufer-ID nicht ändern."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Eingeschränkter Zugriff geändert"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Daten-Dienst ist gesperrt."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Notruf ist gesperrt."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Sprachdienst ist gesperrt."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Sprachassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Jetzt sperren"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhalte aufgrund der Richtlinien ausgeblendet"</string>
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Privat"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Geschäftlich"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Zu \"Privat\" wechseln"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Zu \"Arbeit\" wechseln"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"auf Kontakte zuzugreifen"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Mit %1$s bearbeiten"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Freigeben über"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Für %1$s freigeben"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Senden via"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Senden via %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Start-App auswählen"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s als Start-App verwenden"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Immer für diese Aktion verwenden"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"App zurücksetzen und neu starten"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Feedback geben"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Schließen"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorieren"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Bis zum Neustart des Geräts ausblenden"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Warten"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"App schließen"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Keine Berechtigungen erforderlich"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Hierfür können Gebühren anfallen."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB zum Aufladen"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gerät wird über USB aufgeladen"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Angeschlossenes Gerät wird über USB aufgeladen"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB für die Dateiübertragung"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB für die Fotoübertragung"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB für MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Für weitere Optionen tippen"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren berühren"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKZEPTIEREN"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ABLEHNEN"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Fehlerbericht wird abgerufen…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Fehlerbericht teilen?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Fehlerbericht wird geteilt…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung für dieses Gerät angefordert. Apps und Daten werden unter Umständen geteilt."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"TEILEN"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ABLEHNEN"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Tastatur ändern"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Tastatur auswählen"</string>
     <string name="show_ime" msgid="2506087537466597099">"Auf dem Display einblenden, wenn die physische Tastatur aktiv ist"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuelle Tastatur einblenden"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Tastaturlayout auswählen"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Zum Auswählen eines Tastaturlayouts berühren"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Physische Tastatur konfigurieren"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-Listener"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Bedingungsprovider"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Benachrichtigungsassistent"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Service für Einstufung von Benachrichtigungen"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Weitere Optionen"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s. %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s. %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interner Speicher"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Interner gemeinsamer Speicher"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-Karte"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-Karte von <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-Speichergerät"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vor dem Beenden nach Entsperrungsmuster fragen"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vor dem Beenden nach Passwort fragen"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Die Größe der App kann nicht angepasst werden. Scrolle sie mit zwei Fingern."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Die App funktioniert unter Umständen bei geteiltem Bildschirm nicht."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Von deinem Administrator installiert"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Von deinem Administrator aktualisiert"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ausgewählt</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ausgewählt</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Sonstige"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Du legst die Wichtigkeit dieser Benachrichtigungen fest."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Du hast die Wichtigkeit dieser Benachrichtigungen festgelegt."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Diese Benachrichtigung ist aufgrund der beteiligten Personen wichtig."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt? Dieses Konto wird jedoch bereits von einem anderen Nutzer verwendet."</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Spracheinstellung"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Sprache hinzufügen"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region auswählen"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Sprache eingeben"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Vorschläge"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbeitsmodus ist AUS"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Arbeitsprofil aktivieren, einschließlich Apps, Synchronisierung im Hintergrund und verknüpfter Funktionen."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Aktivieren"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s deaktiviert"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Durch den Administrator von %1$s deaktiviert. Setze dich für weitere Informationen mit ihm in Verbindung."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Du hast neue Nachrichten"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Zum Ansehen SMS-App öffnen"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Einige Funktionen sind evtl. eingeschränkt"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Markieren"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Markierung entfernen"</string>
     <string name="app_info" msgid="6856026610594615344">"App-Informationen"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Gerät auf Werkseinstellungen zurücksetzen, um es ohne Einschränkungen zu nutzen"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Für weitere Informationen tippen."</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 63d49b1..1e891d0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -163,7 +162,7 @@
     <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="tv" msgid="516619861191025923">"Ο χώρος αποθήκευσης της τηλεόρασης είναι πλήρης. Διαγράψτε ορισμένα αρχεία, για να ελευθερώσετε χώρο."</string>
+    <string name="low_memory" product="tv" msgid="516619861191025923">"Ο αποθηκευτικός χώρος της τηλεόρασης είναι πλήρης. Διαγράψτε ορισμένα αρχεία, για να ελευθερώσετε χώρο."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Φων.υποβοηθ."</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Κλείδωμα τώρα"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Το περιεχόμενο είναι κρυφό βάσει πολιτικής"</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="user_owner_label" msgid="1119010402169916617">"Μετάβαση σε προσωπικό προφίλ"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Μετάβαση σε προφίλ εργασίας"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Επαφές"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"πρόσβαση στις επαφές σας"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Τοποθεσία"</string>
@@ -311,7 +309,7 @@
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του tablet."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Επιτρέπει στην εφαρμογή να καθιστά τμήματά της μόνιμα στη μνήμη. Αυτό μπορεί να περιορίσει τη μνήμη που διατίθεται σε άλλες εφαρμογές, επιβραδύνοντας τη λειτουργία της τηλεόρασης."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του τηλεφώνου."</string>
-    <string name="permlab_getPackageSize" msgid="7472921768357981986">"μέτρηση χώρου αποθήκευσης εφαρμογής"</string>
+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"μέτρηση αποθηκευτικού χώρου εφαρμογής"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Επιτρέπει στην εφαρμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και προσωρινής μνήμης"</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"τροποποίηση ρυθμίσεων συστήματος"</string>
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων των ρυθμίσεων του συστήματος. Τυχόν κακόβουλες εφαρμογές ενδέχεται να καταστρέψουν τη διαμόρφωση του συστήματός σας."</string>
@@ -880,9 +878,9 @@
     <string name="deleteText" msgid="6979668428458199034">"Διαγραφή"</string>
     <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_title" msgid="5576272496365684834">"Ο αποθηκευτικός χώρος εξαντλείται"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ορισμένες λειτουργίες συστήματος ενδέχεται να μην λειτουργούν"</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Δεν υπάρχει αρκετός χώρος αποθήκευσης για το σύστημα. Βεβαιωθείτε ότι διαθέτετε 250 MB ελεύθερου χώρου και κάντε επανεκκίνηση."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Δεν υπάρχει αρκετός αποθηκευτικός χώρος για το σύστημα. Βεβαιωθείτε ότι διαθέτετε 250 MB ελεύθερου χώρου και κάντε επανεκκίνηση."</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">"OK"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Επεξεργασία με %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Κοινή χρήση με"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Κοινή χρήση με %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Αποστολή μέσω"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Αποστολή μέσω %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Επιλέξτε μια εφαρμογή Αρχικής σελίδας"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Χρήση %1$s ως Αρχικής σελίδας"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Χρήση από προεπιλογή για αυτήν την ενέργεια."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Επαναφορά και επανεκκίνηση εφαρμογής"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Αποστολή σχολίων"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Κλείσιμο"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Σίγαση"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Σίγαση μέχρι την επανεκκίνηση της συσκευής"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Αναμονή"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Κλείσιμο εφαρμογής"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Δεν απαιτούνται άδειες"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ενδέχεται να χρεωθείτε"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ΟΚ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB για φόρτιση"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Αυτή η συσκευή φορτίζεται μέσω USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Η συνδεδεμένη συσκευή τροφοδοτείται μέσω USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB για μεταφορά αρχείων"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB για μεταφορά φωτογραφιών"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB για MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Αγγίξτε για περισσότερες επιλογές."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Απεν. του εντοπ. σφαλμάτων USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ΑΠΟΔΟΧΗ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ΑΠΟΡΡΙΨΗ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Λήψη αναφοράς σφάλματος…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Κοινή χρήση αναφοράς σφάλματος;"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Κοινή χρήση αναφοράς σφάλματος…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Ο διαχειριστής IT σας ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος αυτής της συσκευής. Ενδέχεται να κοινοποιηθούν οι εφαρμογές και τα δεδομένα."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ΚΟΙΝΟΠΟΙΗΣΗ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ΑΠΟΡΡΙΨΗ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Αλλαγή πληκτρολογίου"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Επιλογή πληκτρολογίων"</string>
     <string name="show_ime" msgid="2506087537466597099">"Να παραμένει στην οθόνη όταν είναι ενεργό το φυσικό πληκτρολόγιο"</string>
     <string name="hardware" msgid="194658061510127999">"Εμφάνιση εικονικού πληκτρολ."</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Επιλογή διάταξης πληκτρολογίου"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Αγγίξτε για να επιλέξετε διάταξη πληκτρολογίου."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Διαμόρφωση φυσικού πληκτρολογίου"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Λειτουργία ακρόασης Εικονικής Πραγματικότητας"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Πάροχος συνθηκών"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Βοηθός ειδοποιήσεων"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Υπηρεσία κατάταξης ειδοποιήσεων"</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>
@@ -1171,7 +1166,7 @@
       <item quantity="one">1 αντιστοιχία</item>
     </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Τέλος"</string>
-    <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Διαγραφή χώρου αποθήκευσης USB..."</string>
+    <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Διαγραφή αποθηκευτικού χώρου USB..."</string>
     <string name="progress_erasing" product="default" msgid="6596988875507043042">"Διαγραφή κάρτας SD..."</string>
     <string name="share" msgid="1778686618230011964">"Κοινή χρ."</string>
     <string name="find" msgid="4808270900322985960">"Εύρεση"</string>
@@ -1229,12 +1224,12 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Περισσότερες επιλογές"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Εσωτερικός χώρος αποθήκευσης"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Εσωτερικός κοινόχρηστος αποθηκευτικός χώρος"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Κάρτα SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Κάρτα SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Μονάδα USB"</string>
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Μονάδα USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
-    <string name="storage_usb" msgid="3017954059538517278">"Χώρος αποθήκευσης USB"</string>
+    <string name="storage_usb" msgid="3017954059538517278">"Αποθηκευτικός χώρος USB"</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>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Να γίνεται ερώτηση για το μοτίβο ξεκλειδώματος, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Να γίνεται ερώτηση για τον κωδικό πρόσβασης, πριν από το ξεκαρφίτσωμα"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Το μέγεθος της εφαρμογής δεν είναι προσαρμόσιμο. Σύρετε προς τα κάτω με δύο δάχτυλα."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Δεν είναι δυνατή η λειτουργία της εφαρμογής με διαχωρισμό οθόνης."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Εγκαταστάθηκε από το διαχειριστή σας"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ενημερώθηκε από το διαχειριστή σας"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">Επιλέχτηκαν <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Επιλέχτηκε <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Διάφορα"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Να επιτραπεί στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με το λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Να επιτραπεί στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με το λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g> (υπάρχει ήδη χρήστης με αυτόν το λογαριασμό);"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Προτίμηση γλώσσας"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Προσθήκη γλώσσας"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Προτίμηση περιοχής"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Εισαγ. όνομα γλώσσας"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Προτεινόμενες"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Λειτουργία εργασίας ΑΠΕΝΕΡΓ/ΝΗ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Να επιτρέπεται η λειτουργία του προφίλ εργασίας σας, συμπεριλαμβανομένων των εφαρμογών, του συγχρονισμού στο παρασκήνιο και των σχετικών λειτουργιών."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Ενεργοποίηση"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Το %1$s απενεργοποιήθηκε"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Απενεργοποιήθηκε από το διαχειριστή της συσκευής %1$s. Επικοινωνήστε με το διαχειριστή για να μάθετε περισσότερα."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Έχετε νέα μηνύματα"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Άνοιγμα της εφαρμογής SMS για προβολή"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Μερ. λειτ. ίσως είναι περιορ."</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Καρφίτσωμα"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Ξεκαρφίτσωμα"</string>
     <string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Επαναφέρετε τις εργοστασιακές ρυθμίσεις για να χρησιμοποιήσετε αυτήν τη συσκευή χωρίς περιορισμούς"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Αγγίξτε για να μάθετε περισσότερα."</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 7a709b6..b94222c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Service not provisioned."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"You can\'t change the caller ID setting."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Restricted access changed"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Data service is blocked."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Emergency service is blocked."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Voice service is blocked."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Share with"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Share with %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Send using"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Send using %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Select a Home app"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Use %1$s as Home"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Use by default for this action."</string>
@@ -915,9 +915,9 @@
     <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> keeps stopping"</string>
     <string name="aerr_restart" msgid="9001379185665886595">"Restart app"</string>
     <string name="aerr_reset" msgid="7645427603514220451">"Reset and restart app"</string>
-    <string name="aerr_report" msgid="5371800241488400617">"Sending feedback"</string>
+    <string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Close"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Mute"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Mute until device restarts"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Wait"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Close app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
     <string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
     <string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Notification ranker service"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"More options"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Internal storage"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Internal shared storage"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD card"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB drive"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"App is not resizeable, scroll it with two fingers."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App does not support split-screen."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installed by your administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Turn on"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s disabled"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Disabled by %1$s administrator. Contact them to find out more."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"You have new messages"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Open SMS app to view"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Some functionality may be limited"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Pin"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7a709b6..b94222c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Service not provisioned."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"You can\'t change the caller ID setting."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Restricted access changed"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Data service is blocked."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Emergency service is blocked."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Voice service is blocked."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Share with"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Share with %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Send using"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Send using %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Select a Home app"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Use %1$s as Home"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Use by default for this action."</string>
@@ -915,9 +915,9 @@
     <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> keeps stopping"</string>
     <string name="aerr_restart" msgid="9001379185665886595">"Restart app"</string>
     <string name="aerr_reset" msgid="7645427603514220451">"Reset and restart app"</string>
-    <string name="aerr_report" msgid="5371800241488400617">"Sending feedback"</string>
+    <string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Close"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Mute"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Mute until device restarts"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Wait"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Close app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
     <string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
     <string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Notification ranker service"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"More options"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Internal storage"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Internal shared storage"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD card"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB drive"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"App is not resizeable, scroll it with two fingers."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App does not support split-screen."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installed by your administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Turn on"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s disabled"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Disabled by %1$s administrator. Contact them to find out more."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"You have new messages"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Open SMS app to view"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Some functionality may be limited"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Pin"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7a709b6..b94222c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Service not provisioned."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"You can\'t change the caller ID setting."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Restricted access changed"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Data service is blocked."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Emergency service is blocked."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Voice service is blocked."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Share with"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Share with %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Send using"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Send using %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Select a Home app"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Use %1$s as Home"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Use by default for this action."</string>
@@ -915,9 +915,9 @@
     <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> keeps stopping"</string>
     <string name="aerr_restart" msgid="9001379185665886595">"Restart app"</string>
     <string name="aerr_reset" msgid="7645427603514220451">"Reset and restart app"</string>
-    <string name="aerr_report" msgid="5371800241488400617">"Sending feedback"</string>
+    <string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Close"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Mute"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Mute until device restarts"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Wait"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Close app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
     <string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
     <string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Notification ranker service"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"More options"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Internal storage"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Internal shared storage"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD card"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB drive"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"App is not resizeable, scroll it with two fingers."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App does not support split-screen."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installed by your administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Turn on"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s disabled"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Disabled by %1$s administrator. Contact them to find out more."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"You have new messages"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Open SMS app to view"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Some functionality may be limited"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Pin"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 465eceb..0bfb9e0 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El Identificador de llamadas está predeterminado en no restringido. Llamada siguiente: no restringido"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Servicio no suministrado."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"No puedes cambiar la configuración del identificador de llamadas."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Se ha cambiado el acceso restringido"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencias está bloqueado."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"El servicio de voz está bloqueado."</string>
@@ -230,17 +229,16 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenido oculto debido a la política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Cambiar al perfil personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar al perfil de trabajo"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a los contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"acceso a la ubicación de este dispositivo"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"acceder a la ubicación de este dispositivo"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder al calendario"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Compartir con"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Compartir con %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Enviar con"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Enviar con %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Seleccionar una aplicación de la pantalla principal"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utilizar %1$s como aplicación de la pantalla principal"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Restablecer y reiniciar la app"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Enviar comentarios"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Cerrar"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Silenciar"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Silenciar hasta que se reinicie el dispositivo"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Esperar"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Cerrar app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -971,8 +971,8 @@
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Volumen de la llamada"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen de los medios"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificación"</string>
-    <string name="ringtone_default" msgid="3789758980357696936">"Tono de llamada predeterminado"</string>
-    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono de llamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+    <string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string>
+    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tono de llamada desconocido"</string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"esto puede costarte dinero"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB solo para realizar cargas"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Este dispositivo se está cargando mediante USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"El dispositivo conectado se está cargando mediante USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferir archivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferir fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Toca para ver más opciones."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración por USB conectada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración por USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Realizando un informe de errores…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"El administrador de TI solicitó un informe de errores para solucionar los problemas de este dispositivo. Es posible que se compartan apps y datos."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Cambiar el teclado"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Mantener en la pantalla cuando el teclado físico está activo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclado físico"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Procesador de realidad virtual"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificaciones"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Servicio de clasificación de notificaciones"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Almacenamiento interno"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Almacenamiento interno compartido"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Tarjeta SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Tarjeta SD de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidad USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar patrón de desbloqueo para quitar fijación"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar contraseña para quitar fijación"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"No se puede modificar el tamaño de la app. Desplázala con dos dedos."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Es posible que la app no funcione en el modo de pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"La app no es compatible con la función de pantalla dividida."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Lo instaló el administrador."</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por el administrador"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementos seleccionados</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento seleccionado</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Estableciste la importancia de estas notificaciones."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Estableciste la importancia de estas notificaciones."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Es importante debido a las personas involucradas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ya existe un usuario con esta cuenta)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de idioma"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Agregar un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nombre del idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo DESACTIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se active el perfil de trabajo, incluidas las apps, la sincronización en segundo plano y las funciones relacionadas."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Activar"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Se inhabilitó %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"El administrador de %1$s lo inhabilitó. Comunícate con él para obtener más información."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Tienes mensajes nuevos"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Abrir app de SMS para ver el mensaje"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Funciones limitadas"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fijar"</string>
     <string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
     <string name="app_info" msgid="6856026610594615344">"Información de la app"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece la configuración de fábrica para usar este dispositivo sin restricciones"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 2a0e000..99202ab 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"El servicio no se suministra."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"No puedes modificar el ID de emisor."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"El acceso restringido se ha modificado."</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencia está bloqueado."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"El servicio de voz está bloqueado."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt; 999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenidos ocultos por política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Cambiar a perfil personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar a perfil de trabajo"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a tus contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
@@ -277,7 +275,7 @@
     <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Permite que una aplicación añada accesos directos a la pantalla de inicio sin intervención del usuario."</string>
     <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="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirigir 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="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>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Compartir con"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Compartir con %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Enviar con"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Enviar con %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Selecciona una aplicación de inicio"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Usar %1$s como aplicación de inicio"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Usar siempre para esta acción"</string>
@@ -911,13 +911,13 @@
     <string name="noApplications" msgid="2991814273936504689">"Ninguna aplicación puede realizar esta acción."</string>
     <string name="aerr_application" msgid="250320989337856518">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> ha dejado de funcionar"</string>
     <string name="aerr_process" msgid="6201597323218674729">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha dejado de funcionar"</string>
-    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> sigue dejando de funcionar"</string>
-    <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> sigue dejando de funcionar"</string>
+    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> sigue sin funcionar"</string>
+    <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> sigue sin funcionar"</string>
     <string name="aerr_restart" msgid="9001379185665886595">"Reiniciar aplicación"</string>
     <string name="aerr_reset" msgid="7645427603514220451">"Restablecer y reiniciar aplicación"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Enviar sugerencias"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Cerrar"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Silenciar"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Silenciar hasta que se reinicie el dispositivo"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Esperar"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Cerrar aplicación"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"es posible que esto te cueste dinero"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para cargar"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Cargando este dispositivo por USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"El dispositivo conectado recibe la alimentación por USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferir archivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferir fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Toca para obtener más opciones"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para inhabilitarla"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de errores…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas de este dispositivo. Es posible que se compartan las aplicaciones y los datos."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Elegir teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclado físico"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Procesador de RV"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificaciones"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Servicio de clasificación de notificaciones"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Almacenamiento interno"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Almacenamiento interno compartido"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Tarjeta SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Tarjeta SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidad USB"</string>
@@ -1453,7 +1448,7 @@
       <item quantity="one">Vuelve a intentarlo en 1 segundo</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Volver a intentar más tarde"</string>
-    <string name="immersive_cling_title" msgid="8394201622932303336">"Mostrando pantalla completa"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Modo de pantalla completa"</string>
     <string name="immersive_cling_description" msgid="3482371193207536040">"Para salir, desliza hacia abajo desde arriba."</string>
     <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendido"</string>
     <string name="done_label" msgid="2093726099505892398">"Listo"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para desactivar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar patrón de desbloqueo para desactivar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar contraseña para desactivar"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"No se puede cambiar el tamaño de la aplicación, desplázala con dos dedos."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Es posible que la aplicación no funcione con la pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"La aplicación no admite la pantalla dividida."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado por tu administrador"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
@@ -1513,7 +1508,7 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta apagar el dispositivo"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta desactivar esta opción"</string>
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Hasta que desactives la opción No molestar"</string>
     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Contraer"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seleccionados</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Tú determinas la importancia de estas notificaciones."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Tú determinas la importancia de estas notificaciones."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Esto es importante por los usuarios implicados."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g> (ya existe un usuario con esta cuenta)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de idioma"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Añade un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nombre de idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1557,12 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo desactivado"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se utilice el perfil de trabajo, incluidas las aplicaciones, la sincronización en segundo plano y las funciones relacionadas."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Activar"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for suspended_package_title (3408150347778524435) -->
-    <skip />
-    <!-- String.format failed for translation -->
-    <!-- no translation found for suspended_package_message (6341091587106868601) -->
-    <skip />
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Tienes mensajes nuevos"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Abre la aplicación de SMS para ver el mensaje"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Algunas funciones limitadas"</string>
@@ -1575,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fijar"</string>
     <string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
     <string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece los datos de fábrica para usar este dispositivo sin restricciones"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</string>
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 15ba404..b1cc971 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Helistaja ID pole vaikimisi piiratud. Järgmine kõne: pole piiratud"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Teenus pole ette valmistatud."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Helistaja ID seadet ei saa muuta."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Piiratud juurdepääs muutunud"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Andmesideteenus on blokeeritud."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hädaabiteenus on blokeeritud."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Häälteenus on blokeeritud."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Häälabi"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lukusta kohe"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisu on eeskirjadega peidetud"</string>
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Isiklik"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Töö"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Lülita isiklikule profiilile"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Lülita tööprofiilile"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktid"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"juurdepääs kontaktidele"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Asukoht"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muutmine rakendusega %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Jagamine:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Jagamine rakendusega %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Saada rakendusega"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Saada rakendusega %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Avaekraani rakenduse valimine"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Rakenduse %1$s kasutamine avaekraanina"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Kasuta vaikimisi selleks toiminguks."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Lähtesta ja taaskäivita rakendus"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Saada tagasiside"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Sule"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Vaigista"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Vaigista, kuni seade taaskäivitatakse"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Oota"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Sule rakendus"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Lube pole vaja"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"see võib olla tasuline"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB laadimiseks"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Laadimiseks ühendage USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Ühendatud seade saab toidet USB kaudu"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB failide edastamiseks"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fotode edastamiseks"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI jaoks"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Puudutage rohkemate valikute kuvamiseks."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-silumine ühendatud"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Puudutage USB-silumise keelamiseks."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"NÕUSTU"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"KEELDU"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Veaaruande võtmine …"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kas jagada veaaruannet?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Veaaruande jagamine …"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT-administraator taotles veaaruannet, mis aitaks seadmes vigu otsida. Rakendusi ja andmeid võidakse jagada."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAGA"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KEELDU"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Klaviatuuri muutmine"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Vali klaviatuurid"</string>
     <string name="show_ime" msgid="2506087537466597099">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuaalse klaviatuuri kuvam."</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klaviatuuri paigutuse valimine"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Puudutage klaviatuuri paigutuse valimiseks."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Füüsilise klaviatuuri seadistamine"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtuaalreaalses režiimis kuulaja"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tingimuse pakkuja"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Märguannete abi"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Märguannete tähtsuse määramise teenus"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Rohkem valikuid"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Sisemine salvestusruum"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Sisemine jagatud mäluruum"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> SD-kaart"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-ketas"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Enne vabastamist küsi PIN-koodi"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Enne vabastamist küsi avamismustrit"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Enne vabastamist küsi parooli"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Rakenduse suurust ei saa muuta. Kerige kahe sõrmega."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Rakendus ei pruugi poolitatud ekraaniga töötada."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Rakendus ei toeta jagatud ekraani."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installis teie administraator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Värskendas administraator"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> on valitud</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Mitmesugust"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Teie määrasite nende märguannete tähtsuse."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Teie määrasite nende märguannete tähtsuse."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"See on tähtis osalevate inimeste tõttu."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g> (selle kontoga kasutaja on juba olemas)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Keele-eelistus"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Keele lisamine"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Piirkonnaeelistus"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Sisestage keele nimi"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Soovitatud"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Töörežiim on VÄLJA LÜLITATUD"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Lubatakse tööprofiili toimingud, sh rakendused, taustal sünkroonimine ja seotud funktsioonid."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Lülita sisse"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Üksus %1$s on keelatud"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Keelas seadme %1$s administraator. Lisateabe saamiseks võtke temaga ühendust."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Teile on uusi sõnumeid"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Avage vaatamiseks SMS-rakendus"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Funktsioon võib olla piiratud"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Kinnita"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Vabasta"</string>
     <string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Seadme piiranguteta kasutamiseks lähtestage see tehaseandmetele"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lisateabe saamiseks puudutage."</string>
 </resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index b8fa962..ea666d9 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Deien identifikazio-zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenik gabe"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Zerbitzua ez da hornitu."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Ezin duzu deien identifikazio-zerbitzuaren ezarpena aldatu."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Sarbide murriztua aldatu da"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datu-zerbitzua blokeatuta dago."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Larrialdi-zerbitzua blokeatuta dago."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Ahots-zerbitzua blokeatuta dago."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ahots-laguntza"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blokeatu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Gidalerro batzuk ezkutatu dira, gidalerroei jarraiki"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Lana"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Aldatu profil pertsonalera"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Aldatu laneko profilera"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktuak atzitzeko"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Partekatu hauen bidez:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partekatu %1$s aplikazioarekin"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Bidali honen bidez:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Bidali %1$s bidez"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Hautatu hasierako aplikazioa"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Erabili %1$s hasierako aplikazio gisa"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Erabili modu lehenetsian ekintza honetarako."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Berrezarri eta berrabiarazi aplikazioa"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Bidali iritzia"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Itxi"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ezkutatu"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ezkutatu gailua berrabiarazi arte"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Itxaron"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Itxi aplikazioa"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Ez da baimenik behar"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dirua kosta dakizuke"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Ados"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Kargatzeko USBa"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gailua USB bidez ari da kargatzen"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Konektatutako gailua USB bidez jasotzen ari da energia"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fitxategiak transferitzeko USBa"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Argazkiak transferitzeko USBa"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI modurako USBa"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Ukitu aukera gehiago ikusteko."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB arazketa desgaitzeko, ukitu hau."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ONARTU"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"BAZTERTU"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Akatsen txostena sortzen…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Akatsen txostena partekatu nahi duzu?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Akatsen txostena partekatzen…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTEKATU"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"BAZTERTU"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Aldatu teklatua"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Aukeratu teklatuak"</string>
     <string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
     <string name="hardware" msgid="194658061510127999">"Erakutsi teklatu birtuala"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Hautatu teklatuaren diseinua"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Ukitu teklatuaren diseinua hautatzeko."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguratu teklatu fisikoa"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Horma-papera"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Aldatu horma-papera"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Jakinarazpenak hautemateko zerbitzua"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Errealitate birtualeko hautemailea"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Baldintza-hornitzailea"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Jakinarazpenen laguntzailea"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Jakinarazpenen sailkapen-zerbitzua"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN eginbidea aktibatuta"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN konexioa aktibatu du"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Ukitu sarea kudeatzeko."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Aukera gehiago"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Barneko memoria"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Barneko biltegiratze partekatua"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD txartela"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD txartela"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB unitatea"</string>
@@ -1473,8 +1468,8 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Eskatu pasahitza aingura kendu aurretik"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Ezin da aldatu aplikazioaren tamaina. Erabili bi hatz aplikazioan gora eta behera egiteko."</string>
-    <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikazioak ez du onartzen pantaila banatua"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
+    <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikazioak ez du onartzen pantaila zatitua"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Administratzaileak instalatu du"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratzaileak eguneratu du"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratzaileak ezabatu du"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> hautatuta</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Askotarikoak"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Zuk ezarri zenuen jakinarazpen hauen garrantzia."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Zuk ezarri duzu jakinarazpen hauen garrantzia."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu? (Badago kontu hori duen erabiltzaile bat)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Hizkuntza-hobespena"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Gehitu hizkuntza"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Lurralde-hobespena"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Desaktibatuta dago laneko modua"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Baimendu laneko profilak funtzionatzea, besteak beste, aplikazioak, atzeko planoko sinkronizazioa eta erlazionatutako eginbideak."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Aktibatu"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Desgaituta dago %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Desgaitu egin du %1$s gailuaren administratzaileak. Informazio gehiago lortu nahi baduzu, jarri harekin harremanetan."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Mezu berriak dituzu"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Mezuak ikusteko, ireki SMS mezuen aplikazioa"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Funtzioak mugatuta egon litezke"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Ainguratu"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Kendu aingura"</string>
     <string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Berrezarri jatorrizko ezarpenak gailua murriztapenik gabe erabili ahal izateko"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sakatu informazio gehiago lortzeko."</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 02eafe9..df9d78f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"دستیار صوتی"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"اکنون قفل شود"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"محتوا بر اساس خط‌مشی پنهان شده است"</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="user_owner_label" msgid="1119010402169916617">"رفتن به نمایه شخصی"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"رفتن به نمایه کاری"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"مخاطبین"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"دسترسی به مخاطبین شما"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"مکان"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ویرایش با %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"اشتراک‌گذاری با"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"‏اشتراک‌گذاری با %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ارسال با استفاده از"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"‏ارسال با استفاده از %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"انتخاب یک برنامه صفحه اصلی"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"‏استفاده از %1$s به عنوان برنامه صفحه اصلی"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"استفاده به صورت پیش‌فرض برای این عملکرد."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"بازنشانی و راه‌اندازی مجدد برنامه"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ارسال بازخورد"</string>
     <string name="aerr_close" msgid="2991640326563991340">"بستن"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"بی‌صدا کردن"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"صامت کردن تا وقتی دستگاه راه‌اندازی مجدد شود"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"انتظار"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"بستن برنامه"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ممکن است برای شما هزینه داشته باشد"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"تأیید"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏USB برای شارژ کردن"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏شارژ کردن این دستگاه از طریق USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏شارژ دستگاه متصل از طریق USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏USB برای انتقال فایل"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏USB برای انتقال عکس"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB برای MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"برای گزینه‌های بیشتر لمس کنید."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏اشکال‌زدایی USB متصل شد"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"‏غیرفعال‌کردن اشکال‌زدایی‌USB: با لمس آن."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"پذیرفتن"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"نپذیرفتن"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"درحال گرفتن گزارش اشکال…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"گزارش اشکال به اشتراک گذاشته شود؟"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"درحال اشتراک‌گذاری گزارش اشکال…‏"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"سرپرست فناوری اطلاعات شما برای کمک به عیب‌یابی این دستگاه، گزارش اشکال درخواست کرده است. ممکن است برنامه‌ها و داده‌ها به اشتراک گذاشته شوند."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراک‌گذاری"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"نپذیرفتن"</string>
     <string name="select_input_method" msgid="8547250819326693584">"تغییر صفحه‌کلید"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"انتخاب صفحه‌کلیدها"</string>
     <string name="show_ime" msgid="2506087537466597099">"وقتی صفحه‌کلید فیزیکی فعال است این ویرایشگر را روی صفحه نگه‌می‌دارد"</string>
     <string name="hardware" msgid="194658061510127999">"نمایش صفحه‌کلید مجازی"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"انتخاب طرح‌بندی صفحه‌کلید"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"برای انتخاب یک طرح‌بندی صفحه‌کلید لمس کنید…"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"پیکربندی صفحه‌کلید فیزیکی"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"کاغذدیواری"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر کاغذدیواری"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"‏شنونده VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ارائه‌دهنده وضعیت"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"دستیار اعلان"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"سرویس رتبه‌بندی اعلان"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"سایر گزینه‌ها"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"‎%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"‎%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"حافظهٔ داخلی"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"حافظه داخلی مشترک"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"‏کارت SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏کارت SD ‏<xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"‏درایو USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"درخواست کد پین قبل از برداشتن پین"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"درخواست الگوی باز کردن قفل قبل از برداشتن پین"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"درخواست گذرواژه قبل از برداشتن پین"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"اندازه برنامه قابل تغییر نیست، با دو انگشت آن را پیمایش کنید."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"ممکن است برنامه با تقسیم صفحه کار نکند."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"برنامه از تقسیم صفحه پشتیبانی نمی‌کند."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"توسط سرپرستتان نصب شد"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"توسط سرپرست شما به‌روزرسانی شد"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one">‏<xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
       <item quantity="other">‏<xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقه"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"به دلیل افراد درگیر مهم است."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"به <xliff:g id="APP">%1$s</xliff:g> امکان داده شود کاربر جدیدی با <xliff:g id="ACCOUNT">%2$s</xliff:g> اضافه کند؟"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"به <xliff:g id="APP">%1$s</xliff:g> امکان داده شود کاربر جدیدی با <xliff:g id="ACCOUNT">%2$s</xliff:g> ایجاد کند (کاربری با این حساب از قبل وجود دارد)؟"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"اولویت‌های زبان"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"افزودن زبان"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"اولویت‌های منطقه"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"نام زبان را تایپ کنید"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"پیشنهادشده"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"حالت کاری خاموش است"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"به نمایه کاری اجازه فعالیت ( شامل استفاده از برنامه‌ها، همگام‌سازی در پس‌زمینه و قابلیت‌های مرتبط) داده شود."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"روشن کردن"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"‏%1$s غیرفعال است"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"‏سرپرست %1$s آن را غیرفعال کرده است. برای اطلاعات بیشتر با او تماس بگیرید."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"پیام‌های جدیدی دارید"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"برای مشاهده، برنامه پیامک را باز کنید"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ممکن است برخی از عملکردها محدود باشند"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"پین کردن"</string>
     <string name="unpin_target" msgid="3556545602439143442">"برداشتن پین"</string>
     <string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"برای استفاده بدون محدودیت از این دستگاه، بازنشانی کارخانه‌ای انجام دهید"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"برای یادگیری بیشتر لمس کنید."</string>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 812565a..c869961 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Soittajan tunnukseksi muutetaan rajoittamaton. Seuraava puhelu: ei rajoitettu"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Palvelua ei tarjota."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Et voi muuttaa soittajan tunnuksen asetusta."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Rajoitettua oikeutta muutettu"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Tiedonsiirtopalvelu on estetty."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hätäpalvelu on estetty."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Äänipalvelu on estetty."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ääniapuri"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisältö on piilotettu käytännön perusteella."</string>
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Henkilökoht."</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Työ"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Siirry henkilökohtaiseen profiiliin"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Siirry työprofiiliin"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktit"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"käyttää yhteystietoja"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Sijainti"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muokkaa sovelluksessa %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Jaa sovelluksessa"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Jaa sovelluksessa %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Lähetä sovelluksella"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Lähetä sovelluksella %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Valitse aloitusruutusovellus"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Käytä aloitusruutuna: %1$s"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Käytä oletuksena tälle toiminnolle."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Nollaa sovellus ja käynnistä uudelleen"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Lähetä palautetta"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Sulje"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ohita"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Mykistä laitteen uudelleenkäynnistykseen asti"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Odota"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Sulje sovellus"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Lupia ei tarvita"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"tämä voi maksaa"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB on lataustilassa"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Laitetta ladataan USB-yhteyden kautta"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Liitetty laite saa virtaa USB-yhteyden kautta"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB on tiedonsiirtotilassa"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB on kuvansiirtotilassa"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB on MIDI-tilassa"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Lisää vaihtoehtoja koskettamalla"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Sulje USB-vianetsintä koskettamalla."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"HYVÄKSY"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"HYLKÄÄ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Luodaan virheraporttia…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Jaetaanko virheraportti?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Jaetaan virheraporttia…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Järjestelmänvalvoja pyysi virheraporttia voidakseen auttaa laitteen vianetsinnässä. Sovelluksia ja tietoja voidaan jakaa."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAA"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HYLKÄÄ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Vaihda näppäimistö"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Valitse näppäimistöt"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
     <string name="hardware" msgid="194658061510127999">"Näytä virtuaalinen näppäimistö"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Valitse näppäimistöasettelu"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Kosketa ja valitse näppäimistöasettelu."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Määritä fyysinen näppäimistö"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtuaalitodellisuuden kuuntelija"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ehtojen toimituspalvelu"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ilmoitusapuri"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Ilmoitusten sijoituspalvelu"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Lisää asetuksia"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Sisäinen tallennustila"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Sisäinen jaettu tallennustila"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kortti"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-kortti: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-asema"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN ennen irrotusta"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pyydä lukituksenpoistokuvio ennen irrotusta"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pyydä salasana ennen irrotusta"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Sovelluksen kokoa ei voi muuttaa. Vieritä näkymää kahdella sormella."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Sovellus ei ehkä toimi jaetulla näytöllä."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Sovellus ei tue jaetun näytön tilaa."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Järjestelmänvalvoja on asentanut paketin."</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Järjestelmänvalvojasi on päivittänyt paketin."</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valittu</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> valittu</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Muut"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Voit valita näiden ilmoitusten tärkeyden."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Voit valita näiden ilmoitusten tärkeyden."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Myönnetäänkö sovellukselle <xliff:g id="APP">%1$s</xliff:g> oikeus luoda käyttäjä tilille <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Myönnetäänkö sovellukselle <xliff:g id="APP">%1$s</xliff:g> oikeus luoda käyttäjä tilille <xliff:g id="ACCOUNT">%2$s</xliff:g> (tilillä on jo käyttäjä)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Kieliasetus"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Lisää kieli"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Alueasetus"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Anna kielen nimi"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ehdotukset"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Työtila on pois käytöstä"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Sallii työprofiiliin toiminnan, esimerkiksi sovellukset ja taustasynkronoinnin."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Ota käyttöön"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s poisti tämän käytöstä"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Organisaation %1$s järjestelmänvalvojan käytöstä poistama. Kysy häneltä lisätietoja."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Sinulle on uusia viestejä"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Katso avaamalla tekstiviestisovellus."</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Toimintorajoitus mahdollinen"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Kiinnitä"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Irrota"</string>
     <string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Palauta tehdasasetukset, jotta voit käyttää tätä laitetta rajoituksitta"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lue lisätietoja koskettamalla."</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d6c933f..efc8af3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'accès limité a été modifié."</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Le service de données est bloqué."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Le service d\'appel d\'urgence est bloqué."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Le service vocal est bloqué."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. vocale"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux politiques"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Travail"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Passer au profil professionnel"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Partager"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partager avec %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Envoyer avec"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Envoyer avec %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Sélectionner une application pour l\'écran d\'accueil"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utiliser %1$s comme écran d\'accueil"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utiliser cette application par défaut pour cette action"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Réinitialiser et redémarrer l\'application"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Fermer"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Désactiver les notifications"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Désactiver jusqu\'au redémarrage de l\'appareil"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Attendre"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Fermer l\'application"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"cela peut engendrer des frais"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB pour la recharge"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Cet appareil est en cours de charge par USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Un connecteur USB alimente cet appareil"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB pour le transfert de fichiers"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB pour le transfert de photos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB pour MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Touchez pour afficher plus d\'options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désactiver le débogage USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création d\'un rapport de bogue en cours..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bogue?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bogue en cours..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applications et les données peuvent être partagées."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Choisir les claviers"</string>
     <string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
     <string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Sélectionnez la disposition du clavier"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Appuyez ici pour sélectionner une disposition de clavier."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurer le clavier physique"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Écouteur de réalité virtuelle"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistant des notifications"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Service de classement des notifications"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Plus d\'options"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Mémoire de stockage interne"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Stockage interne partagé"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Carte SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Carte mémoire SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Clé USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le NIP avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Impossible de redimensionner l\'application. Faites-la défiler avec deux doigts."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"L\'application n\'est pas compatible avec l\'écran partagé."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installé par votre administrateur"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Vous définissez l\'importance de ces notifications."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur associé à ce compte existe déjà.)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Préférences linguistiques"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Ajouter une langue"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggestions"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Le mode Travail est désactivé"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Activer"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s est désactivé"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Cette option a été désactivée par l\'administrateur de %1$s. Communiquez avec lui pour en savoir plus."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Vous avez de nouveaux messages"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Ouvrez l\'application de messagerie texte pour l\'afficher"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Certaines fonct. sont limitées"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Épingler"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Annuler l\'épinglage"</string>
     <string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablissez la configuration d\'usine de cet appareil pour l\'utiliser sans restrictions"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touchez ici pour en savoir plus."</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 897a289..4e83fa9 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'accès limité a été modifié."</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Le service de données est bloqué."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Le service d\'appel d\'urgence est bloqué."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Le service vocal est bloqué."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Assistance vocale"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux règles"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Professionnel"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Passer au profil professionnel"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Position"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Partager avec"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partager avec %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Envoyer avec"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Envoyer avec %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Sélectionner une application de l\'écran d\'accueil"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utiliser %1$s comme écran d\'accueil"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utiliser cette application par défaut pour cette action"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Réinitialiser et redémarrer l\'application"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Fermer"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorer"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignorer jusqu\'au redémarrage de l\'appareil"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Attendre"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Fermer l\'application"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Cela peut engendrer des frais"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Recharge par USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Recharge via USB de cet appareil…"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Alimentation via USB de l\'appareil connecté…"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB pour le transfert de fichiers"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB pour le transfert de photos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB en mode MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Appuyez pour afficher plus d\'options"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désact. débogage USB"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création du rapport de bug…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bug ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bug…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème lié à cet appareil. Il est possible que des applications et des données soient partagées."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Sélectionner des claviers"</string>
     <string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
     <string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Sélectionnez la disposition du clavier"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Appuyez ici pour sélectionner une disposition de clavier."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurer le clavier physique"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Écouteur de réalité virtuelle"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistant de notifications"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Service de classement des notifications"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Plus d\'options"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Mémoire de stockage interne"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Espace de stockage interne partagé"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Carte SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Carte SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Clé USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le code PIN avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Il est impossible de redimensionner l\'application. Faites-la défiler avec deux doigts."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Application incompatible avec l\'écran partagé."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installé par votre administrateur"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Vous définissez l\'importance de ces notifications."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> (un utilisateur associé à ce compte existe déjà) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Préférences linguistiques"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Ajouter une langue"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Saisissez la langue"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Recommandations"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode professionnel DÉSACTIVÉ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Activer"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s désactivé"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Désactivé par l\'administrateur %1$s. Contactez-le pour en savoir plus."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Vous avez de nouveaux messages"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Ouvrir l\'application de SMS pour afficher le message"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Des fonctionnalités peuvent être limitées"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Épingler"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Retirer"</string>
     <string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"− <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablir la configuration d\'usine pour utiliser cet appareil sans restrictions"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Appuyez ici pour en savoir plus."</string>
 </resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 0e54aad..2fa6087 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"De forma predeterminada, non se restrinxe o ID de chamada. Próxima chamada: non restrinxido."</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Servizo non ofrecido."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Non podes cambiar a configuración do ID de chamada."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Modificouse o acceso restrinxido"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"O servizo de datos está bloqueado."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O servizo de urxencia está bloqueado."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"O servizo de voz está bloqueado."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Ocultouse contido por causa da política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Traballo"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Cambiar ao perfil persoal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar ao perfil de traballo"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder aos teus contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Compartir con"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Compartir con %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Enviar a través de"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Enviar a través de %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Selecciona unha aplicación de Inicio"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utiliza %1$s como aplicación de Inicio"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Usar de forma predeterminada para esta acción."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Restablecer e reiniciar aplicación"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Dános a túa opinión"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Pechar"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignorar fallos ata que o dispositivo se reinicie"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Esperar"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Pechar aplicación"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Non é necesario ningún permiso"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"é posible que teñas que pagar"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carga"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"O USB está cargando este dispositivo"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"O USB está proporcionando enerxía ao dispositivo conectado"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferencia de ficheiros"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferencia de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Toca para ver máis opcións."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB conectada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para desactivala"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ANULAR"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de erros…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Queres compartir o informe de erros?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartindo informe de erros..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar os problemas deste dispositivo. É posible que se compartan aplicacións e datos."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ANULAR"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manteno na pantalla mentres o teclado físico estea activo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Seleccionar deseño de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un deseño de teclado."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura o teclado físico"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1143,8 +1137,9 @@
     <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">"Axente de escoita de notificacións"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Axente de escoita de RV"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condicións"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificacións"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Servizo de clasificación de notificacións"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> activou a VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca aquí para xestionar a rede."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Máis opcións"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Almacenamento interno"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Almacenamento compartido interno"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Tarxeta SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Tarxeta SD de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidade USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar un PIN antes de soltar a pantalla"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar un padrón de desbloqueo antes de soltar a pantalla"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar un contrasinal antes de soltar a pantalla"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Non se pode cambiar o tamaño da aplicación. Desprázate por ela con dous dedos."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Pode que a aplicación non funcione coa pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"A aplicación non é compatible coa función de pantalla dividida."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado polo administrador"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado polo administrador"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">Seleccionáronse <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Seleccionouse <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ti defines a importancia destas notificacións."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ti defines a importancia destas notificacións."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"É importante polas persoas involucradas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de idioma"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Engadir un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferencia de rexión"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suxeridos"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de traballo DESACTIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que funcione o perfil de traballo, incluídas as aplicacións, a sincronización en segundo plano e as funcións relacionadas."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Activar"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Desactivouse %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"O administrador de %1$s desactivou este paquete. Contacta con el para obter máis información."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Tes mensaxes novas"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Abre a aplicación de SMS para ver as mensaxes"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Pode haber funcións limitadas"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fixar"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
     <string name="app_info" msgid="6856026610594615344">"Información da aplicación"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablecemento dos valores de fábrica para usar este dispositivo sen restricións"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para acceder a máis información"</string>
 </resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 246f2b4..0b9f4ad 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"કૉલર ID પ્રતિબંધિત નહીં પર ડિફોલ્ટ છે. આગલો કૉલ: પ્રતિબંધિત નહીં"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"સેવાની જોગવાઈ કરી નથી."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"તમે કૉલર ID સેટિંગ બદલી શકતાં નથી."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"વૉઇસ સહાય"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"હવે લૉક કરો"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"સામગ્રીઓ છુપાવેલ છે"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"નીતિ દ્વારા સામગ્રી છુપાવાઈ"</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="user_owner_label" msgid="1119010402169916617">"વ્યક્તિગત પર સ્વિચ કરો"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"કાર્ય પર સ્વિચ કરો"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"સંપર્કો"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"તમારા સંપર્કોને ઍક્સેસ કરો"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s સાથે સંપાદિત કરો"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"આની સાથે શેર કરો"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s સાથે શેર કરો"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"આનો ઉપયોગ કરીને મોકલો"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s નો ઉપયોગ કરીને મોકલો"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"હોમ એપ્લિકેશન પસંદ કરો"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"હોમ તરીકે %1$s નો ઉપયોગ કરો"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"આ ક્રિયા માટે ડિફોલ્ટ તરીકે ઉપયોગમાં લો."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ફરીથી સેટ કરો અને ઍપ્લિકેશનને ફરીથી પ્રારંભ કરો"</string>
     <string name="aerr_report" msgid="5371800241488400617">"પ્રતિસાદ મોકલો"</string>
     <string name="aerr_close" msgid="2991640326563991340">"બંધ કરો"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"મ્યૂટ કરો"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"ઉપકરણ પુનઃપ્રારંભ ન થાય ત્યાં સુધી મ્યૂટ કરો"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"રાહ જુઓ"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ઍપ્લિકેશન બંધ કરો"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"કોઈ પરવાનગીઓ જરૂરી નથી"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"આનાથી તમારા પૈસા ખર્ચ થઈ શકે છે"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ઑકે"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ચાર્જ કરવા માટે USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"આ ઉપકરણને USB થી ચાર્જ કરે છે"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"જોડાયેલ ઉપકરણ માટે USB પાવર પૂરો પાડે છે"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ફાઇલ ટ્રાન્સફર માટે USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ફોટા ટ્રાન્સફર માટે USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI માટે USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"વધુ વિકલ્પો માટે ટચ કરો."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ડીબગિંગ કનેક્ટ થયું."</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ડીબગિંગ અક્ષમ કરવા માટે ટચ કરો."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"સ્વીકારો"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"નકારો"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"બગ રિપોર્ટ લઈ રહ્યાં છે…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"બગ રિપોર્ટ શેર કરીએ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"બગ રિપોર્ટ શેર કરી રહ્યાં છે…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"તમારા IT વ્યવસ્થાપક એ આ ઉપકરણની સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે. ઍપ્લિકેશનો અને ડેટા શેર કરવામાં આવી શકે છે."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"શેર કરો"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"નકારો"</string>
     <string name="select_input_method" msgid="8547250819326693584">"કીબોર્ડ બદલો"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"કીબોર્ડ્સ પસંદ કરો"</string>
     <string name="show_ime" msgid="2506087537466597099">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
     <string name="hardware" msgid="194658061510127999">"વર્ચ્યુઅલ કીબોર્ડ બતાવો"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"કીબોર્ડ લેઆઉટ પસંદ કરો."</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"કીબોર્ડ લેઆઉટ પસંદ કરવા માટે ટચ કરો."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ભૌતિક કીબોર્ડ ગોઠવો"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"વૉલપેપર"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"વૉલપેપર બદલો"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"સૂચના સાંભળનાર"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR સાંભળનાર"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"શરત પ્રદાતા"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"સૂચના સહાયક"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"સૂચના રેંકર સેવા"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN સક્રિય કર્યું"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> દ્વારા VPN સક્રિય થયું"</string>
     <string name="vpn_text" msgid="3011306607126450322">"નેટવર્કને સંચાલિત કરવા માટે ટચ કરો."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"વધુ વિકલ્પો"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"આંતરિક સંગ્રહ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"આંતરિક શેર કરેલો સ્ટોરેજ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD કાર્ડ"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD કાર્ડ"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ડ્રાઇવ"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"અનપિન કરતાં પહેલાં PIN માટે પૂછો"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"અનપિન કરતા પહેલાં અનલૉક પેટર્ન માટે પૂછો"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"અનપિન કરતાં પહેલાં પાસવર્ડ માટે પૂછો"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ઍપ્લિકેશનનું કદ બદલવા યોગ્ય નથી, બે આંગળીઓ વડે તેને સ્ક્રોલ કરો."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"વિભાજિત-સ્ક્રીન સાથે ઍપ્લિકેશન કદાચ કામ ન કરે."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ઍપ્લિકેશન સ્ક્રીન-વિભાજનનું સમર્થન કરતી નથી."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"તમારા વ્યવસ્થાપક દ્વારા ઇન્સ્ટોલ કરેલ"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ થયેલ"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"વિવિધ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"શામેલ થયેલ લોકોને કારણે આ મહત્વપૂર્ણ છે."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ને <xliff:g id="ACCOUNT">%2$s</xliff:g> સાથે એક નવા વપરાશકર્તાને બનાવવાની મંજૂરી આપીએ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> સાથે <xliff:g id="APP">%1$s</xliff:g> ને એક નવા વપરાશકર્તાને બનાવવાની મંજૂરી આપીએ (આ એકાઉન્ટ સાથેના એક વપરાશકર્તા પહેલાંથી અસ્તિત્વમાં છે)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ભાષા પસંદગી"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"એક ભાષા ઉમેરો"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"પ્રદેશ પસંદગી"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ભાષાનું નામ ટાઇપ કરો"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"સૂચવેલા"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"કાર્ય મોડ બંધ છે"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"કાર્ય પ્રોફાઇલને ઍપ્લિકેશનો, પૃષ્ઠભૂમિ સમન્વયન અને સંબંધિત સુવિધાઓ સહિતનું કાર્ય કરવાની મંજૂરી આપો."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ચાલુ કરો"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s અક્ષમ કરેલ"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ. વધુ જાણવા માટે તેમનો સંપર્ક કરો."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"તમારી પાસે નવા સંદેશા છે"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"જોવા માટે SMS ઍપ્લિકેશન ખોલો"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"કેટલીક કાર્યક્ષમતા મર્યાદિત હોઈ શકે છે"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"પિન કરો"</string>
     <string name="unpin_target" msgid="3556545602439143442">"અનપિન કરો"</string>
     <string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"આ ઉપકરણનો પ્રતિબંધો વિના ઉપયોગ કરવા માટે ફેક્ટરી રીસેટ કરો"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"વધુ જાણવા માટે ટચ કરો."</string>
 </resources>
diff --git a/core/res/res/values-h426dp-port/integers.xml b/core/res/res/values-h426dp-port/integers.xml
new file mode 100644
index 0000000..94abbec
--- /dev/null
+++ b/core/res/res/values-h426dp-port/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <integer name="date_picker_mode">2</integer>
+    <integer name="time_picker_mode">2</integer>
+</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5e76c16..474e81e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कॉलर ID प्रतिबंधित नहीं पर डिफ़ॉल्‍ट है. अगली कॉल: प्रतिबंधित नहीं"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"वॉइस सहायक"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"अभी लॉक करें"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"सामग्री पॉलिसी के द्वारा छिपी हुई है"</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="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफ़ाइल में स्विच करें"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"कार्य प्रोफ़ाइल में स्विच करें"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"अपने संपर्कों को ऐक्सेस करें"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s से संपादित करें"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"इससे साझा करें"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s से साझा करें"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"इसका उपयोग करके भेजें"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s का उपयोग करके भेजें"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"होम ऐप्स चुनें"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"होम के रूप में %1$s का उपयोग करें"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"इस क्रिया के लिए डिफ़ॉल्‍ट रूप से उपयोग करें."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ऐप रीसेट करें और पुन: प्रारंभ करें"</string>
     <string name="aerr_report" msgid="5371800241488400617">"फ़ीडबैक भेजें"</string>
     <string name="aerr_close" msgid="2991640326563991340">"बंद करें"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"म्यूट करें"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"डिवाइस पुन: प्रारंभ होने तक म्यूट करें"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"प्रतीक्षा करें"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ऐप बंद करें"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"किसी अनुमति की आवश्‍यकता नहीं है"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"इससे आपको धन देना पड़ सकता है"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ठीक है"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जिंग के लिए USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"यह डिवाइस USB से चार्ज हो रहा है"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"अटैच किए गए डिवाइस को USB से पावर मिल रही है"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"फ़ाइल स्‍थानांतरण के लिए USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"फ़ोटो स्‍थानांतरण के लिए USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI के लिए USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"और विकल्पों के लिए स्पर्श करें."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करना अक्षम करने के लिए स्‍पर्श करें."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करें"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार करें"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट प्राप्त की जा रही है…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्ट साझा करें?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्ट साझा की जा रही है…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"आपके आईटी व्यवस्थापक ने इस डिवाइस के समस्या निवारण में सहायता के लिए एक बग रिपोर्ट का अनुरोध किया है. ऐप्स और डेटा को साझा किया जा सकता है."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझा करें"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
     <string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड चुनें"</string>
     <string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्‍क्रीन पर बनाए रखें"</string>
     <string name="hardware" msgid="194658061510127999">"वर्चुअल कीबोर्ड दिखाएं"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"कीबोर्ड लेआउट को चुनें"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"कीबोर्ड लेआउट का चयन करने के लिए स्‍पर्श करें."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"भौतिक कीबोर्ड कॉन्फ़िगर करें"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उम्‍मीदवार"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"नोटिफिकेशन श्रवणकर्ता"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR श्रोता"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"स्थिति प्रदाता"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"नोटिफिकेशन सहायक"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"नोटिफ़िकेशन रैंकर सेवा"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"अधिक विकल्प"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"मोबाइल मेमोरी"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"आंतरिक साझा मेमोरी"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD कार्ड"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD कार्ड"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB डिस्‍क"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करने से पहले पिन के लिए पूछें"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"अनपिन करने से पहले अनलॉक पैटर्न के लिए पूछें"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"अनपिन करने से पहले पासवर्ड के लिए पूछें"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ऐप का आकार बदला नहीं जा सकता है, इसे दो अंगुलियों से स्क्रॉल करें."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"हो सकता है कि ऐप्लिकेशन विभाजित स्क्रीन के साथ काम ना करे."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ऐप विभाजित स्‍क्रीन का समर्थन नहीं करता है."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"आपके नियंत्रक द्वारा इंस्‍टॉल किया गया"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"आपके नियंत्रक द्वारा अपडेट किया गया"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के द्वारा एक नया उपयोगकर्ता बनाने दें?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के द्वारा एक नया उपयोगकर्ता बनाने दें (इस खाते वाला एक उपयोगकर्ता पहले से मौजूद है) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"भाषा प्राथमिकता"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"भाषा जोड़ें"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"क्षेत्र प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"भाषा का नाम लिखें"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाए गए"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद है"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ऐप्स, पृष्ठभूमि समन्वयन और संबंधित सुविधाओं सहित कार्य प्रोफ़ाइल को काम करने की अनुमति दें"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"चालू करें"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s को अक्षम किया गया"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s व्‍यवस्‍थापक द्वारा अक्षम किया गया. अधिक जानने के लिए उनसे संपर्क करें."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"आपके पास नए संदेश हैं"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"देखने के लिए SMS ऐप खोलें"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"कुछ कार्य क्षमताएं सीमित हो सकती हैं"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"पिन करें"</string>
     <string name="unpin_target" msgid="3556545602439143442">"अनपिन करें"</string>
     <string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"इस डिवाइस को प्रतिबंधों के बिना उपयोग करने के लिए फ़ैक्टरी रीसेट करें"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जानने के लिए स्पर्श करें."</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 619e9b9..837aa56 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -89,7 +89,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Zadana postavka ID-a pozivatelja nema ograničenje. Sljedeći poziv: Nije ograničen"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Usluga nije rezervirana."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Ne možete promijeniti postavku ID-a pozivatelja."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Promijenjen je ograničeni pristup"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Podatkovna usluga je blokirana."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hitna usluga je blokirana."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Glasovna usluga je blokirana."</string>
@@ -232,13 +231,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj sada"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je skriven prema pravilima"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobno"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Prijeđite na osobni"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Prijeđite na radni"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupati vašim kontaktima"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -907,6 +905,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uređivanje pomoću aplikacije %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Dijeljenje pomoću aplikacije"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Dijeljenje pomoću aplikacije %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Pošalji aplikacijom"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Slanje aplikacijom %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Odaberite početnu aplikaciju"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Upotrijebite %1$s kao početnu aplikaciju"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Koristi se kao zadana postavka za ovu lokaciju."</string>
@@ -923,7 +923,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Vrati aplikaciju na zadano i pokreni ponovo"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Pošalji povratne informacije"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Zanemari"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Zanemari do ponovnog pokretanja uređaja"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Čekaj"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Zatvori aplikaciju"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,7 +1053,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nije potrebno dopuštenje"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"možda ćete morati platiti"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"U redu"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Punjenje uređaja USB-om"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Napajanje priključenog uređaja USB-om"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prijenos datoteka"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos fotografija"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1061,24 +1062,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za uklanjanje pogrešaka USB-om"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da se onemogući otklanjanje pogrešaka USB-om."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izrada izvješća o programskoj pogrešci…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li podijeliti izvješće o programskoj pogrešci?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvješća o programskoj pogrešci…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema na uređaju. Moguće je da će se aplikacije i podaci dijeliti."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DIJELI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Promjena tipkovnice"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Odaberi tipkovnice"</string>
     <string name="show_ime" msgid="2506087537466597099">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>
     <string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tipkovnicu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Odaberite izgled tipkovnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite za odabir izgleda tipkovnice."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurirajte fizičku tipkovnicu"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -1151,8 +1145,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Slušatelj virtualne stvarnosti"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Davatalj uvjeta"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obavijesti"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Usluga rangiranja obavijesti"</string>
     <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>
@@ -1238,7 +1233,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Više opcija"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interna pohrana"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Unutarnja dijeljena pohrana"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kartica"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kartica"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB pogon"</string>
@@ -1483,7 +1478,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži uzorak za otključavanje radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži zaporku radi otkvačivanja"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veličina aplikacije ne može se mijenjati, pomičite je s dva prsta."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava podijeljeni zaslon."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalirao administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurira vaš administrator"</string>
@@ -1562,12 +1557,11 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> odabrane</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> odabranih</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Postavili ste važnost tih obavijesti."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Postavili ste važnost tih obavijesti."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Važno je zbog uključenih osoba."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Želite li dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Želite li dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s tim računom već postoji)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Postavke jezika"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Dodavanje jezika"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Postavke regije"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
@@ -1576,8 +1570,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni je način ISKLJUČEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogućuje radnom profilu da funkcionira, uključujući aplikacije, sinkronizaciju u pozadini i povezane značajke."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Uključi"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s – onemogućeno"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Onemogućio administrator (%1$s). Obratite mu se za više informacija."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nove poruke"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorite SMS aplikaciju da biste pregledali poruke"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Funkcije mogu biti ograničene"</string>
@@ -1590,4 +1582,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Prikvači"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Otkvači"</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Uređaj je vraćen na tvorničke postavke da biste ga mogli upotrebljavati bez ograničenja"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index be2a3fd..0c4705d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"A hívóazonosító alapértelmezett értéke nem korlátozott. Következő hívás: nem korlátozott"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"A szolgáltatás nincs biztosítva."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nem tudja módosítani a hívó fél azonosítója beállítást."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"A korlátozott hozzáférés módosítva"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Az adatszolgáltatás le van tiltva."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"A segélyszolgáltatás le van tiltva."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"A hangszolgáltatás letiltva."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Hangsegéd"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zárolás most"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalom elrejtve"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"A tartalom irányelv miatt elrejtve"</string>
     <string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Személyes"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Munkahelyi"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Átváltás személyes profilra"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Átváltás munkaprofilra"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Névjegyek"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"hozzáférés a névjegyekhez"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Helyadatok"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Szerkesztés a következővel: %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Megosztás a következővel:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Megosztás a következővel: %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Küldés a következővel:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Küldés a következővel: %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Válasszon kezdőalkalmazást"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"A(z) %1$s használata kezdőalkalmazásként"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Ez legyen az alapértelmezett program ehhez a művelethez."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Alkalmazás alaphelyzetbe állítása és újraindítása"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Visszajelzés küldése"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Bezárás"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Némítás"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Némítás az eszköz újraindulásáig"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Várakozás"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Alkalmazás bezárása"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nincs szükség engedélyre"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ez pénzbe kerülhet Önnek"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB töltéshez"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Az eszköz USB-s töltése"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"A csatlakoztatott eszköz USB-n keresztül való töltése"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB fájlátvitelhez"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fotóátvitelhez"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-hez"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Érintse meg a további lehetőségekhez."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Érintse meg az USB hibakeresés kikapcsolásához."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ELFOGADOM"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ELUTASÍTOM"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hibajelentés készítése…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Megosztja a hibajelentést?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hibajelentés megosztása…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"A rendszergazda hibajelentést kért, hogy segíthessen az eszközzel kapcsolatos probléma megoldásában. Előfordulhat, hogy a rendszer megosztja az alkalmazásokat és adatokat."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"MEGOSZTÁS"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ELUTASÍTÁS"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Billentyűzet megváltoztatása"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Billentyűzetek kiválasztása"</string>
     <string name="show_ime" msgid="2506087537466597099">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuális billentyűzet"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Válasszon billentyűzetkiosztást"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Érintse meg az egyik billentyűzetkiosztás kiválasztásához."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Állítsa be a fizikai billentyűzetet"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtuálisvalóság-figyelő"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Feltételbiztosító"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Értesítési segéd"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Értesítésrangsoroló szolgáltatás"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"További lehetőségek"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Belső tárhely"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Belső közös tárhely"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kártya"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD-kártya"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-meghajtó"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-kód kérése a rögzítés feloldásához"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Feloldási minta kérése a rögzítés feloldásához"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Jelszó kérése a rögzítés feloldásához"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Az alkalmazást nem lehet átméretezni – két ujjal görgessen."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"A rendszergazda telepítette"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Frissítette a rendszergazda"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> kiválasztva</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kiválasztva</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Vegyes"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ön állította be ezen értesítések fontossági szintjét."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ön állította be ezen értesítések fontossági szintjét."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ez az üzenet a résztvevők miatt fontos."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal? (Már létezik felhasználó ezzel a fiókkal.)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Nyelvi beállítás"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Nyelv hozzáadása"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Régió beállítása"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Adja meg a nyelvet"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Javasolt"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"A munka mód KI van kapcsolva"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Munkaprofil használatának engedélyezése, beleértve az alkalmazásokat, a háttérben való szinkronizálást és a kapcsolódó funkciókat."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Bekapcsolás"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s letiltva"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"A(z) %1$s szervezet rendszergazdája letiltotta. További információért vegye fel vele a kapcsolatot."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Új üzenetei érkeztek"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"SMS-alkalmazás megnyitása a megtekintéshez"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Egyes funkciók korlátozva lehetnek"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Rögzítés"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Feloldás"</string>
     <string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Állítsa vissza a gyári beállításokat az eszköz korlátozások nélküli használata érdekében"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Érintse meg a további információkért."</string>
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index b436f3d..4be90da 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Զանգողի ID-ն լռելյայն չսահմանափակված է: Հաջորդ զանգը` չսահմանափակված"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Ծառայությունը չի տրամադրվում:"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Դուք չեք կարող փոխել զանգողի ID-ի կարգավորումները:"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ձայնային օգնութ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Կողպել հիմա"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Բովանդակությունը թաքցվել է ըստ քաղաքականության"</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="user_owner_label" msgid="1119010402169916617">"Անցնել անհատական պրոֆիլին"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Անցնել աշխատանքային պրոֆիլին"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Կոնտակտներ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"կոնտակտների հասանելիություն"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Տեղադրություն"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Խմբագրել հետևյալով՝ %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Տարածել"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Տարածել ըստ %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Ուղարկել այս հավելվածով"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Ուղարկել %1$s հավելվածով"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Ընտրեք Հիմնական հավելվածը"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Օգտագործել %1$s-ը՝ որպես Հիմնական"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Օգտագործել լռելյայն այս գործողության համար:"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Վերակայել և վերագործարկել հավելվածը"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Ուղարկել կարծիք"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Փակել"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Անջատել ձայնը"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Անջատել ձայնը մինչև սարքի վերագործարկումը"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Սպասել"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Փակել հավելվածը"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Թույլտվություններ չեն պահանջվում"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Սա կարող է գումար պահանջել"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Լավ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Լիցքավորման USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Սարքի լիցքավորում USB լարի միջոցով"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Հոսանքի մատակարարում կցված սարքերին USB լարի միջոցով"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Ֆայլերի փոխանցման USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Լուսանկարների փոխանցման USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ի USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Հպեք` USB կարգաբերումը կասեցնելու համար:"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ԸՆԴՈՒՆԵԼ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ՄԵՐԺԵԼ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Վրիպակի զեկույցի ստեղծում…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Տրամադրե՞լ վրիպակի զեկույցը:"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Վրիպակի զեկույցի տրամադրում…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Այս սարքի անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց: Կարող են տրամադրվել տեղեկություններ ձեր հավելվածների մասին և այլ տվյալներ:"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ՏՐԱՄԱԴՐԵԼ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ՄԵՐԺԵԼ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Փոխել ստեղնաշարը"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Ընտրել ստեղնաշար"</string>
     <string name="show_ime" msgid="2506087537466597099">"Պահել էկրանին մինչդեռ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
     <string name="hardware" msgid="194658061510127999">"Ցույց տալ վիրտուալ ստեղնաշարը"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Ընտրեք ստեղնաշարի դիրքը"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Հպեք` ստեղնաշարի դիրքը ընտրելու համար:"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Կազմաձևեք ֆիզիկական ստեղնաշարը"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Պաստառ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ծանուցման ունկնդիր"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR ունկնդրիչ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Պայմանների մատակարար"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ծանուցումների օգնական"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Ծանուցումների դասակարգման ծառայություն"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Ավելի շատ ընտրանքներ"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Ներքին պահոց"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Համօգտագործվող ներքին հիշողություն"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD քարտ"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD քարտ <xliff:g id="MANUFACTURER">%s</xliff:g>-ից"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB սարքավար"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ապաամրացնելուց առաջ հարցնել ապակողպող նախշը"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ապաամրացնելուց առաջ հարցնել գաղտնաբառը"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Հավելվածի չափը հնարավոր չէ փոխել, ոլորեք այն երկու մատի օգնությամբ:"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում:"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Ադմինիստրատորը տեղադրել է այն"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ադմինիստրատորը թարմացրել է այն"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Զանազան"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Թույլ տա՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտվող ստեղծել:"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Թույլ տա՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտվող ստեղծել (նման հաշվով Օգտվող արդեն գոյություն ունի):"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Նախընտրելի լեզու"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Ավելացնել լեզու"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Նախընտրելի տարածաշրջան"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Մուտքագրեք լեզուն"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Առաջարկներ"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Աշխատանքային ռեժիմն ԱՆՋԱՏՎԱԾ Է"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Թույլատրել աշխատանքային պրոֆիլի (այդ թվում նաև հավելվածների, ֆոնային համաժամացման և առնչվող գործառական հնարավորությունների) աշխատանքը:"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Միացնել"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s-ը կասեցվել է"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Կասեցվել է %1$s ադմինիստրատորի կողմից: Ավելին իմանալու համար կապվեք նրա հետ:"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Դուք ունեք նոր հաղորդագրություններ"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Դիտելու համար բացել SMS հավելվածը"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Որոշ գործառույթներ կարող են սահմանափակված լինել"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Ամրացնել"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Ապամրացնել"</string>
     <string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Սարքն առանց սահմանափակումների օգտագործելու համար կատարեք գործարանային վերակայում"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Հպեք՝ ավելին իմանալու համար:"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 7c18d24..7218617 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nomor penelepon default tidak dibatasi. Panggilan selanjutnya: Tidak dibatasi"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Layanan tidak diperlengkapi."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Anda tidak dapat mengubah setelan nomor penelepon."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Akses terbatas berubah"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Layanan data dicekal."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Layanan darurat dicekal."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Layanan suara dicekal."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Konten disembunyikan menurut kebijakan"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pribadi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Kantor"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Beralih ke Pribadi"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Beralih ke Kantor"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontak"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kontak"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Bagikan dengan"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Bagikan dengan %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Kirim menggunakan"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Kirim menggunakan %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Pilih aplikasi Beranda"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Gunakan %1$s sebagai aplikasi Beranda"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Gunakan secara default untuk tindakan ini."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Setel ulang dan mulai ulang aplikasi"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Kirim masukan"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Tutup"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Bisukan"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Bisukan hingga perangkat dimulai ulang"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Tunggu"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Tutup aplikasi"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Tidak perlu izin"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ini mungkin tidak gratis"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Oke"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB untuk pengisian daya"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Isi daya perangkat ini melalui USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Suplai daya melalui USB ke perangkat yang terpasang"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB untuk transfer file"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB untuk transfer foto"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Sentuh untuk opsi lainnya."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB terhubung"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk menonaktifkan debugging USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SETUJU"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan bug…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bagikan laporan bug?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Membagikan laporan bug..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Admin IT meminta laporan bug untuk membantu memecahkan masalah perangkat ini. Aplikasi dan data mungkin dibagikan."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"BAGIKAN"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Ubah keyboard"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Pilih keyboard"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pertahankan di layar jika keyboard fisik masih aktif"</string>
     <string name="hardware" msgid="194658061510127999">"Tampilkan keyboard virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih tata letak keyboard"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih tata letak keyboard."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Mengonfigurasi keyboard fisik"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Pemroses Realitas Maya"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Penyedia ketentuan"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asisten notifikasi"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Layanan penentu peringkat notifikasi"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Opsi lainnya"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Penyimpanan internal"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Penyimpanan bersama internal"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kartu SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Kartu SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Drive USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Meminta PIN sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Meminta pola pembukaan kunci sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Meminta sandi sebelum melepas sematan"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Aplikasi tidak dapat diubah ukurannya, gulir dengan dua jari."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikasi mungkin tidak berfungsi dengan layar terpisah."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App tidak mendukung layar terpisah."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Dipasang oleh administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Diperbarui oleh administrator"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Lain-Lain"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Anda menyetel tingkat kepentingan notifikasi ini."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Anda menyetel nilai penting notifikasi ini."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ini penting karena orang-orang yang terlibat."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akun ini sudah ada) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferensi bahasa"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Tambahkan bahasa"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferensi wilayah"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Ketik nama bahasa"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Disarankan"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode kerja NONAKTIF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Izinkan profil kerja berfungsi, termasuk aplikasi, sinkronisasi latar belakang, dan fitur terkait."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Aktifkan"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s dinonaktifkan"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Dinonaktifkan oleh administrator %1$s. Hubungi administrator untuk mempelajari lebih lanjut."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Ada pesan baru"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Buka aplikasi SMS untuk melihat"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Beberapa fungsi mungkin terbatas"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Pasang pin"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Lepas pin"</string>
     <string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Dikembalikan ke setelan pabrik agar perangkat ini dapat digunakan tanpa batasan"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sentuh untuk mempelajari lebih lanjut."</string>
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 79ef76b..cebc4cc 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Númerabirting er sjálfgefið án takmarkana. Næsta símtal: Án takmarkana"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Þjónustu ekki útdeilt."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Þú getur ekki breytt stillingu númerabirtingar."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Takmörkuðum aðgangi breytt"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Lokað er fyrir gagnaþjónustu."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Lokað er fyrir neyðarþjónustu."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Lokað er fyrir raddþjónustu."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Raddaðstoð"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Læsa núna"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Efni falið með reglu"</string>
     <string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android kerfið"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persónulegt"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Vinna"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Skipta yfir í persónulegt snið"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Skipta yfir í vinnusnið"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Tengiliðir"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"fá aðgang að tengiliðunum þínum"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Staðsetning"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Breyta með %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Deila með"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Deila með %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Senda með því að nota"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Senda með því að nota %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Veldu heimaforrit"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Nota %1$s sem heimaforrit"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Nota sjálfgefið fyrir þessa aðgerð."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Endurstilla og endurræsa forritið"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Senda ábendingu"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Loka"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Þagga"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Þagga þangað til tæki er endurræst"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Bíða"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Loka forriti"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Engra heimilda þörf"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"þú gætir þurft að borga fyrir þetta"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Í lagi"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB fyrir hleðslu"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Þetta tæki er í USB-hleðslu"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Tengt tæki er í USB-hleðslu"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB fyrir skráaflutning"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fyrir myndaflutning"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB fyrir MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Snertu til að fá fleiri valkosti."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-villuleit tengd"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Snertu til að slökkva á USB-villuleit."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SAMÞYKKJA"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"HAFNA"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Tekur við villutilkynningu…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deila villutilkynningu?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deilir villutilkynningu..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit á þessu tæki. Forritum og gögnum verður hugsanlega deilt."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEILA"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HAFNA"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Skipta um lyklaborð"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Velja lyklaborð"</string>
     <string name="show_ime" msgid="2506087537466597099">"Haltu því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
     <string name="hardware" msgid="194658061510127999">"Sýna sýndarlyklaborð"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Veldu lyklaskipan"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Snertu til að velja lyklaskipan."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Stilla vélbúnaðarlyklaborð"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Veggfóður"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Skipta um veggfóður"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Tilkynningahlustun"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Sýndarveruleikavöktun"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Skilyrðaveita"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Tilkynningaaðstoð"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tilkynningaröðun"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN virkjað"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN er virkjað með <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Snertu til að hafa umsjón með netinu."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Fleiri valkostir"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Innbyggð geymsla"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Innbyggð samnýtt geymsla"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-kort frá <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-drif"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Biðja um opnunarmynstur til að losa"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Biðja um aðgangsorð til að losa"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Ekki er hægt að breyta stærð forritsins; flettu upp og niður með tveimur fingrum."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Hugsanlega virkar forritið ekki ef skjánum er skipt upp."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Forritið styður ekki að skjánum sé skipt."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Uppsett af kerfisstjóra"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Uppfært af kerfisstjóranum"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> valið</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valin</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Ýmislegt"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Þú stilltir mikilvægi þessara tilkynninga."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Þú stilltir mikilvægi þessara tilkynninga."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> (notandi með þennan reikning er þegar fyrir hendi)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Val tungumáls"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Bæta við tungumáli"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Svæðisval"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Sláðu inn heiti tungumáls"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Tillögur"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Slökkt á vinnusniði"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Leyfa virkni vinnusniðs, m.a. forrita, samstillingar í bakgrunni og tengdra eiginleika."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Kveikja"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s óvirkt"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Gert óvirkt af stjórnanda %1$s. Hafðu samband við hann til að fá frekari upplýsingar."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Þú ert með ný skilaboð"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Opnaðu SMS-forritið til að skoða"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Sum virkni kann að vera takmörkuð"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Festa"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Losa"</string>
     <string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Núllstilltu til að nota þetta tæki án takmarkana"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Snertu til að fá frekari upplýsingar."</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2ba3359..2a73990 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Servizio non fornito."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Non è possibile modificare l\'impostazione ID chiamante."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Accesso limitato modificato"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Il servizio dati è bloccato."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Il servizio di emergenza è bloccato."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Il servizio vocale è bloccato."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blocca ora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenuti nascosti in base alle norme"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personale"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Lavoro"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Passa al profilo personale"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Passa al profilo di lavoro"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedere ai contatti"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Posizione"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifica con %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Condividi con"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Condividi con %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Invia tramite"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Invia tramite %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Seleziona un\'app Home"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utilizza %1$s come Home"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Usa come predefinita per questa azione."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Reimposta e riavvia app"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Invia feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Chiudi"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Disattiva"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Disattiva fino al riavvio del dispositivo"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Attendi"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Chiudi app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nessuna autorizzazione richiesta"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"potrebbe comportare dei costi"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB per la ricarica"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dispositivo in carica tramite USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Dispositivo collegato alimentato tramite USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB per il trasferimento di file"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB per il trasferimento di foto"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per la modalità MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Tocca per visualizzare più opzioni."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tocca per disattivare il debug USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCETTO"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RIFIUTO"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Recupero della segnalazione di bug…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Condividere la segnalazione di bug?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Condivisione della segnalazione di bug…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi di questo dispositivo. Potrebbero essere condivisi dati e app."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"CONDIVIDI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RIFIUTO"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Cambia tastiera"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Scegli tastiera"</string>
     <string name="show_ime" msgid="2506087537466597099">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
     <string name="hardware" msgid="194658061510127999">"Mostra tastiera virtuale"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Seleziona layout tastiera"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tocca per selezionare un layout di tastiera."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura la tastiera fisica"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Listener realtà virtuale"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider condizioni"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente notifica"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Servizio di classificazione delle notifiche"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Altre opzioni"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Memoria interna"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Archivio condiviso interno"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Scheda SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Scheda SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unità USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Richiedi il PIN per lo sblocco"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Richiedi sequenza di sblocco prima di sbloccare"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Richiedi password prima di sbloccare"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Non è possibile ridimensionare l\'app: scorri con due dita."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"L\'app potrebbe non funzionare con lo schermo diviso."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"L\'app non supporta la modalità Schermo diviso."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installato dall\'amministratore"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aggiornato dall\'amministratore"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi selezionati</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento selezionato</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Vari"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Stabilisci tu l\'importanza di queste notifiche."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Stabilisci tu l\'importanza di queste notifiche."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Importante a causa delle persone coinvolte."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Esiste già un utente con questo account)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferenza lingua"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Aggiungi una lingua"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Area geografica preferita"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Digita nome lingua"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerite"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modalità Lavoro DISATTIVATA"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Attiva il profilo di lavoro, incluse app, sincronizzazione in background e funzioni correlate."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Attiva"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s disattivato"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Disattivato dall\'amministratore di %1$s. Contattalo per ulteriori informazioni."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Hai nuovi messaggi"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Apri l\'app SMS per la visualizzazione"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Funzioni potenzial. limitate"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Blocca"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Sblocca"</string>
     <string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Esegui il ripristino dei dati di fabbrica per utilizzare il dispositivo senza limitazioni"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tocca per ulteriori informazioni."</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a67319c..80435b6 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -90,7 +90,6 @@
     <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>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"נעל עכשיו"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"התוכן מוסתר על ידי המדיניות"</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="user_owner_label" msgid="1119010402169916617">"עבור ל\'אישי\'"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"עבור ל\'עבודה\'"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"אנשי קשר"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"גישה אל אנשי הקשר"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"מיקום"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ערוך באמצעות %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"שתף באמצעות"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"‏שתף באמצעות %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"שליחה באמצעות"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"‏שליחה באמצעות %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"בחר אפליקציה שתשמש כדף הבית"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"‏השתמש ב-%1$s כדף הבית"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"השתמש כברירת מחדל עבור פעולה זו."</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"אפס והפעל מחדש את האפליקציה"</string>
     <string name="aerr_report" msgid="5371800241488400617">"שלח משוב"</string>
     <string name="aerr_close" msgid="2991640326563991340">"סגור"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"השתק"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"השתק עד הפעלה מחדש של המכשיר"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"המתן"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"סגור את האפליקציה"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"לא דרושים אישורים"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"פעולה זו עשויה לחייב אותך בכסף:"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"אישור"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏USB לטעינה"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏USB טוען את המכשיר הזה"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏USB מספק מתח למכשיר המצורף"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏USB להעברת קבצים"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏USB להעברת תמונות"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB ל-MIDI"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"גע להצגת עוד אפשרויות."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏ניפוי באגים של USB מחובר"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"‏גע כדי להשבית ניפוי באגים בהתקן ה-USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"אישור"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"דחייה"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"עיבוד דוח על באג..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"האם לשתף דוח על באג?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"שיתוף דוח על באג…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"‏מנהל ה-IT שלך ביקש דוח על באג כדי לסייע בפתרון בעיות במכשיר זה. ייתכן שאפליקציות ונתונים ישותפו."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"שתף"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"דחה"</string>
     <string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"בחר מקלדות"</string>
     <string name="show_ime" msgid="2506087537466597099">"השאר אותו במסך בזמן שהמקלדת הפיזית פעילה"</string>
     <string name="hardware" msgid="194658061510127999">"הצג מקלדת וירטואלית"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"בחירת פריסת מקלדת"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"גע כדי לבחור פריסת מקלדת."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"הגדרת מקלדת פיזית"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
@@ -1159,8 +1153,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"‏VR ליסנר"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ספק תנאי"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"אסיסטנט ההודעות"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"שירות של דירוג הודעות"</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>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"‏%1$s‏, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"‏%1$s‏, %2$s‏, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"אחסון פנימי"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"אחסון משותף פנימי"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"‏כרטיס SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏כרטיס SD של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"‏כונן USB"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"‏בקש PIN לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"בקש קו ביטול נעילה לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"בקש סיסמה לפני ביטול הצמדה"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"אין אפשרות לשנות את גודל האפליקציה, גלול אותה בשתי אצבעות."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"ייתכן שהיישום לא יפעל עם מסך מפוצל."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"האפליקציה אינה תומכת במסך מפוצל."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"הותקנה על ידי מנהל המערכת שלך"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"עודכן על ידי מנהל המערכת שלך"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="other">בחרת <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">בחרת <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"שונות"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"אתה מגדיר את החשיבות של ההודעות האלה."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"אתה מגדיר את החשיבות של ההודעות האלה."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ההודעה חשובה בשל האנשים המעורבים."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"האם לאפשר ל-<xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש לחשבון <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"האם לאפשר ל-<xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש לחשבון <xliff:g id="ACCOUNT">%2$s</xliff:g> (כבר קיים משתמש לחשבון הזה) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"העדפת שפה"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"הוספת שפה"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"העדפת אזור"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"הקלד שם שפה"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"הצעות"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"מצב העבודה כבוי"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"אפשר לפרופיל העבודה לפעול, כולל אפליקציות, סנכרון ברקע ותכונות קשורות."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"הפעל"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"‏החבילה %1$s הושבתה"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"‏הושבתה על ידי מנהל המערכת של %1$s. צור איתו קשר כדי לקבל מידע נוסף."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"יש לך הודעות חדשות"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"‏פתח את אפליקציית ה-SMS כדי להציג"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ייתכן שחלק מהפונקציונליות תהיה מוגבלת"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"הצמד"</string>
     <string name="unpin_target" msgid="3556545602439143442">"בטל הצמדה"</string>
     <string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"איפוס להגדרות היצרן כדי לאפשר שימוש במכשיר ללא מגבלות"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"גע לקבלת מידע נוסף."</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 166eca7..394775f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -214,8 +213,7 @@
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"対話型レポート"</string>
     <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"ほとんどの場合はこのオプションを使用します。レポートの進行状況を追跡し、問題についての詳細情報を確認することができます。レポート作成に時間がかかってもあまり使用されないセクションは省略されることがあります。"</string>
     <string name="bugreport_option_full_title" msgid="6354382025840076439">"完全レポート"</string>
-    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
-    <skip />
+    <string name="bugreport_option_full_summary" msgid="6687306111256813257">"端末の反応がないとき、または速度が遅すぎるときにシステムへの影響を最小限に抑えたい場合は、このオプションを使用します。またすべてのレポート セクションを表示したい場合にもこのオプションを使用します。スクリーンショットは作成されず、詳細情報も表示できません。"</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item>
@@ -231,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 件)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ポリシーによって非表示になっているコンテンツ"</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="user_owner_label" msgid="1119010402169916617">"個人用に切り替える"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"仕事用に切り替える"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"連絡先"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"連絡先へのアクセス"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置情報"</string>
@@ -902,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sで編集"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"共有"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$sで共有"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"送信に使用するアプリ"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"送信に使用するアプリ: %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"ホームアプリを選択"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ホームとして%1$sを使用"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"常にこの操作で使用する"</string>
@@ -918,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"アプリをリセットして再起動"</string>
     <string name="aerr_report" msgid="5371800241488400617">"フィードバックを送信"</string>
     <string name="aerr_close" msgid="2991640326563991340">"閉じる"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"ミュート"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"端末が再起動するまでミュート"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"待機"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"アプリを閉じる"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1046,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"権限の許可は必要ありません"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"料金が発生する場合があります"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USBを充電に使用"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"この端末を USB で充電"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"接続した端末に USB で給電"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USBをファイル転送に使用"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USBを写真転送に使用"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USBをMIDIに使用"</string>
@@ -1054,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"タップしてその他のオプションを表示"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効化"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"同意する"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"同意しない"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"バグレポートを取得しています…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"バグレポートを共有しますか?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"バグレポートの共有中…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT 管理者からこの端末のトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました。アプリやデータが共有されることがあります。"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"共有する"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"共有しない"</string>
     <string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"キーボードの選択"</string>
     <string name="show_ime" msgid="2506087537466597099">"物理キーボードが有効になっている間は、画面に表示されます"</string>
     <string name="hardware" msgid="194658061510127999">"仮想キーボードの表示"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"キーボードレイアウトの選択"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"タップしてキーボードレイアウトを選択してください。"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"物理キーボードの設定"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
@@ -1144,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR リスナー"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"コンディションプロバイダ"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知アシスタント"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"通知ランカー サービス"</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>
@@ -1230,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"その他のオプション"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s、%2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s、%2$s、%3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"内部ストレージ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"内部共有ストレージ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SDカード"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g>製SDカード"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USBドライブ"</string>
@@ -1474,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"オフライン再生を解除する前にPINの入力を求める"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"オフライン再生を解除する前にパスワードの入力を求める"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"アプリのサイズは変更できません。2 本の指でスクロールしてください。"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"アプリは分割画面では動作しないことがあります。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"アプリで分割画面がサポートされていません。"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"管理者によってインストールされました"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"管理者によって更新されています"</string>
@@ -1544,27 +1538,19 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>件選択済み</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>件選択済み</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"その他"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"このような通知の重要度を設定します。"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"このような通知の重要度を設定します。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"関係するユーザーのため、この設定は重要です。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?(このアカウントのユーザーはすでに存在します)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"言語設定"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"言語を追加"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"地域設定"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"言語名を入力"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"言語の候補"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"すべての言語"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"検索"</string>
-    <!-- no translation found for work_mode_off_title (8954725060677558855) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (3286169091278094476) -->
-    <skip />
-    <!-- no translation found for work_mode_turn_on (2062544985670564875) -->
-    <skip />
-    <!-- no translation found for suspended_package_title (3408150347778524435) -->
-    <skip />
-    <!-- no translation found for suspended_package_message (6341091587106868601) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="8954725060677558855">"Work モード OFF"</string>
+    <string name="work_mode_off_message" msgid="3286169091278094476">"仕事用プロファイルで、アプリ、バックグラウンド同期などの関連機能の使用を許可します。"</string>
+    <string name="work_mode_turn_on" msgid="2062544985670564875">"ON にする"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"新着メッセージがあります"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"表示するには SMS アプリを開きます"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"一部機能が制限されている可能性"</string>
@@ -1577,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"固定"</string>
     <string name="unpin_target" msgid="3556545602439143442">"固定を解除"</string>
     <string name="app_info" msgid="6856026610594615344">"アプリ情報"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"制限なしでこの端末を使用するには初期状態にリセットしてください"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"タップして詳細をご確認ください。"</string>
 </resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 178e023..fcc56da 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ნაგულისხმებად დაყენებულია ნომრის დაფარვის გამორთვა. შემდეგი ზარი: არ არის დაფარული."</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"სერვისი არ არის მიწოდებული."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"არ შეგიძლიათ აბონენტის ID პარამეტრების შეცვლა."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"ხმოვანი ასისტ."</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ახლა ჩაკეტვა"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"შიგთავსი დამალულია წესების შესაბამისად"</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="user_owner_label" msgid="1119010402169916617">"პირად პროფილზე გადართვა"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"სამსახურის პროფილზე გადართვა"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"კონტაქტები"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"თქვენს კონტაქტებზე წვდომა"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"მდებარეობა"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"რედაქტირება %1$s-ით"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"გაზიარება:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s-თან გაზიარება"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"გაგზავნა:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"გაგზავნა %1$s-ის მეშვეობით"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"აირჩიეთ Home აპი"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s-ის გამოყენება ......Home-ად"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ამ ქმედებისთვის ნაგულისხმევად გამოყენება."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"გადაყენება და აპის გადატვირთვა"</string>
     <string name="aerr_report" msgid="5371800241488400617">"გამოხმაურება"</string>
     <string name="aerr_close" msgid="2991640326563991340">"დახურვა"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"დადუმება"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"დადუმება მოწყობილობის გადატვირთვამდე"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"მოცდა"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"აპის დახურვა"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ნებართვა საჭირო არ არის"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ამისათვის შესაძლოა მოგიწიოთ თანხის გადახდა"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB დამუხტვისთვის"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"მოწყობილობა USB-ის მეშვეობით იტენება"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"მიერთებულ მოწყობილობას ელკვებას USB აწვდის"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB ფაილების გადაცემისთვის"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB ფოტოების გადაცემისთვის"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-სთვის"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"შეეხეთ დამატებითი პარამეტრებისთვის."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB გამართვა შეერთებულია"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"შეეხეთ, რათა შეწყვიტოთ USB-ის გამართვა."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"მიღება"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"უარყოფა"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის შექმნა…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"გსურთ ხარვეზის შესახებ ანგარიშის გაზიარება?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გაზიარება…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ამ მოწყობილობის პრობლემების აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს, რა დროსაც შეიძლება გაზიარდეს აპები და მონაცემები."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"გაზიარება"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"უარყოფა"</string>
     <string name="select_input_method" msgid="8547250819326693584">"კლავიატურის შეცვლა"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"კლავიატურების არჩევა"</string>
     <string name="show_ime" msgid="2506087537466597099">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
     <string name="hardware" msgid="194658061510127999">"ვირტუალური კლავიატურის ჩვენება"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"შეარჩიეთ კლავიატურის განლაგება."</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"კლავიატურის განლაგების შესარჩევად შეეხეთ."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"მოახდინეთ ფიზიკური კლავიატურის კონფიგურაცია"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ფონი"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ფონის შეცვლა"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"შეტყობინებების მსმენელი"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"ვირტუალური რეალობის მსმენელი"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"მდგომარეობის პროვაიდერი"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"შეტყობინებათა ასისტენტი"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"შეტყობინებების მნიშვნელობის დონის შეფასების სერვისი"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"მეტი ვარიანტები"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"შიდა მეხსიერება"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"შიდა გაზიარებული მეხსიერება"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD ბარათი"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD ბარათი"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB დისკი"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"აპის ზომა ვერ შეიცვლება. გადაადგილდით მასში ორი თითის მეშვეობით."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"თქვენი ადმინისტრატორის მიერ დაყენებული"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> შერჩეული</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> შერჩეული</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"სხვადასხვა"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრა თქვენ მიერ."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრა თქვენ მიერ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს, <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს, <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას (ამ ანგარიშის მქონე მომხმარებელი უკვე არსებობს) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ენის პარამეტრები"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ენის დამატება"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"რეგიონის პარამეტრები"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"აკრიფეთ ენის სახელი"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"რეკომენდებული"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"სამსახურის რეჟიმი გამორთულია"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"სამსახურის პროფილის მუშაობის დაშვება, მათ შორის, აპების, ფონური სინქრონიზაციის და დაკავშირებული ფუნქციების."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ჩართვა"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s გათიშულია"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"გათიშულია „%1$s“-ის ადმინისტრატორის მიერ. დაუკავშირდით მას მეტის გასაგებად."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"თქვენ ახალი შეტყობინებები გაქვთ"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"სანახავად, გახსენით SMS აპი"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ზოგიერთი ფუნქცია შეიძლება შეიზღუდოს"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"ჩამაგრება"</string>
     <string name="unpin_target" msgid="3556545602439143442">"ჩამაგრების მოხსნა"</string>
     <string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"ამ მოწყობილობის შეზღუდვების გარეშე გამოსაყენებლად, დააბრუნეთ ქარხნული პარამეტრები"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"შეეხეთ მეტის გასაგებად."</string>
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 259278a..6eaa770 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Дауыс көмекшісі"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Қазір бекіту"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Мазмұн саясатқа сай жасырылған"</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="user_owner_label" msgid="1119010402169916617">"Жекеге ауысу"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Жұмысқа ауысу"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контактілер"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"контактілерге кіру"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Орын"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s көмегімен өңдеу"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Бөлісу"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s қолданбасымен бөлісу"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Келесі арқылы жіберу"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s арқылы жіберу"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"«Негізгі» қолданбасын таңдау"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s «Негізгі» ретінде пайдалану"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Бұл әрекет үшін бастапқы параметрін қолданыңыз."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Ысырып, қолданбаны қайта іске қосу"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Пікір жіберу"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Жабу"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Үнсіз"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Құрылғы қайта іске қосылғанша дыбысын өшіру"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Күту"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Қолданбаны жабу"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Рұқсат қажет емес"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"бұған төлем қажет болуы мүмкін"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Жарайды"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Зарядтауға арналған USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB арқылы зарядтау"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB жалғанған құрылғыға қуат беруде"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файлды тасымалдауға арналған USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Фотосуретті тасымалдауға арналған USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI режиміне арналған USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Қосымша параметрлер үшін түртіңіз."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB жөндеу қосылған"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB жөндеуді өшіру үшін түртіңіз."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ҚАБЫЛДАУ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ҚАБЫЛДАМАУ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Қате туралы есеп алынуда…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Қате туралы есепті бөлісу керек пе?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Қате туралы есеп бөлісілуде…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"АТ әкімшісі осы құрылғы ақауларын жоюға көмектесу үшін қате туралы есепті сұрады. Оған қолданбалар мен деректер көрсетілуі мүмкін."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛІСУ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ҚАБЫЛДАМАУ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Пернетақтаны өзгерту"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Пернетақталарды таңдау"</string>
     <string name="show_ime" msgid="2506087537466597099">"Физикалық пернетақта белсенді кезде оны экранда ұстау"</string>
     <string name="hardware" msgid="194658061510127999">"Виртуалды пернетақтаны көрсету"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Пернетақта орналасуын таңдау"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Пернетақта орналасуын таңдау үшін түртіңіз."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Физикалық пернетақтаны конфигурациялау"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Артқы фоны"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Артқы фонын өзгерту"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Хабар бақылағыш"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Виртуалды шынайылық тыңдаушысы"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт провайдері"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Хабарландыру көмекшісі"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Хабарландыруларды жіктеу қызметі"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN белсенді"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"ВЖЭ <xliff:g id="APP">%s</xliff:g> арқылы қосылған"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Желіні басқару үшін түрту."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Басқа опциялар"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Ішкі жад"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Ішкі ортақ қойма"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD картасы"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD картасы"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB дискі"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Босату алдында PIN кодын сұрау"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Босату алдында бекітпесін ашу өрнегін сұрау"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Босату алдында құпия сөзді сұрау"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Қолданба өлшемін өзгерту мүмкін емес, оны екі саусақпен айналдырыңыз."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Қолданба бөлінген экранда жұмыс істемеуі мүмкін."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Қодланба бөлінген экранды қолдамайды."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Әкімші орнатқан"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Әкімші жаңартты"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> таңдалды</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> таңдалды</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Әр түрлі"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Сіз осы хабарландырулардың маңыздылығын орнатасасыз."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Қатысты адамдарға байланысты бұл маңызды."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы жасауға рұқсат ету керек пе?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасында жаңа пайдаланушы жасауға рұқсат ету керек пе (осы есептік жазбасы бар пайдаланушы әлдеқашан бар) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Тіл параметрі"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Тілді қосу"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Аймақ параметрі"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Тіл атауын теріңіз"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ұсынылған"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Жұмыс режимі ӨШІРУЛІ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Жұмыс профиліне, соның ішінде, қолданбаларға, фондық синхрондауға және қатысты мүмкіндіктерге жұмыс істеуге рұқсат ету."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Қосу"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s өшірілген"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s әкімшісі өшірген. Қосымша мәліметтер алу үшін оларға хабарласыңыз."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Сізде жаңа хабарлар бар"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Көру үшін SMS қолданбасын ашыңыз"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Кейбір функциялар істемеуі мүмкін"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"PIN код"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Босату"</string>
     <string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Осы құрылғыны шектеусіз пайдалану үшін зауыттық параметрлерді қалпына келтіріңіз"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Қосымша мәліметтер алу үшін түртіңіз."</string>
 </resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 7390b6b..30d3c0a 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"ជំនួយសម្លេង"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ចាក់សោ​ឥឡូវនេះ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"បាន​លាក់​មាតិកា"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"មាតិកាត្រូវបានលាក់ដោយផ្អែកលើគោលការណ៍"</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="user_owner_label" msgid="1119010402169916617">"ប្តូរទៅផ្ទាល់ខ្លួន"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"ប្តូរទៅការងារ"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ទំនាក់ទំនង"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ចូលប្រើទំនាក់ទំនងរបស់អ្នក"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ទីតាំង"</string>
@@ -903,6 +901,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"កែសម្រួល​ជាមួយ​ %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"ចែករំលែក​ជាមួយ"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"ចែករំលែក​ជាមួយ"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ផ្ញើដោយប្រើ"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"ផ្ញើដោយប្រើ %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"ជ្រើស​កម្មវិធី​ដើម"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ប្រើ %1$s ជា​ដើម"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ប្រើ​តាម​លំនាំដើម​សម្រាប់​សកម្មភាព​នេះ។"</string>
@@ -919,7 +919,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"កំណត់ និងចាប់ផ្តើមកម្មវិធីឡើងវិញ"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ផ្ញើមតិ"</string>
     <string name="aerr_close" msgid="2991640326563991340">"បិទ"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"បិទ"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"បិទរហូតដល់ឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"រង់ចាំ"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"បិទកម្មវិធី"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1047,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"មិន​ទាមទារ​សិទ្ធិ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"វា​អាច​កាត់​លុយ​​អ្នក"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"យល់ព្រម"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB សម្រាប់បញ្ចូលថ្ម"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB កំពុងសាកឧបករណ៍នេះ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB កំពុងផ្គត់ផ្គង់ថាមពលទៅឧបករណ៍ដែលបានភ្ជាប់"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB សម្រាប់ការផ្ទេរឯកសារ"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB សម្រាប់ការផ្ទេររូបថត"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB សម្រាប់ MIDI"</string>
@@ -1055,24 +1056,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"ប៉ះដើម្បីបានជម្រើសថែមទៀត។"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"បាន​ភ្ជាប់​ការ​កែ​កំហុស​យូអេសប៊ី"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"ប៉ះ ដើម្បី​បិទ​ការ​កែ​កំហុស​យូអេសប៊ី។"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ព្រមទទួល"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"បដិសេធ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"កំពុងទទួលយករបាយការណ៍កំហុស…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ចែករំលែករបាយការណ៍កំហុសឬ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"កំពុងចែករំលែករបាយកំហុស…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីដោះស្រាយកំហុសឧបករណ៍នេះ។ កម្មវិធី និងទិន្នន័យអាចនឹងត្រូវបានចែករំលែក។"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ចែករំលែក"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"បដិសេធ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ប្ដូរ​ក្ដារចុច"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"ជ្រើស​ក្ដារចុច"</string>
     <string name="show_ime" msgid="2506087537466597099">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
     <string name="hardware" msgid="194658061510127999">"បង្ហាញក្ដារចុចនិម្មិត"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ជ្រើស​ប្លង់​ក្ដារ​ចុច"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ប៉ះ ​ដើម្បី​ជ្រើស​ប្លង់​​ក្ដារចុច។"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"កំណត់រចនាសម្ព័ន្ធក្តារចុចពិតប្រាកដ"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string>
@@ -1145,8 +1139,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ផ្ទាំង​រូបភាព"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ប្ដូរ​ផ្ទាំង​រូបភាព"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"កម្មវិធី​ស្ដាប់​ការ​ជូន​ដំណឹង"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"កម្មវិធីស្តាប់ VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ជំនួយការជូនដំណឹង"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"សេវាកម្មវាយតម្លៃការជូនដំណឹង"</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>
@@ -1231,7 +1226,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ជម្រើស​ច្រើន​ទៀត"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"ឧបករណ៍​ផ្ទុក​ខាង​ក្នុង"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"ឧបករណ៍ផ្ទុកដែលចែករំលែកខាងក្នុង"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"កាត​អេសឌី"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"កាត SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"ឧបករណ៍ផ្ទុក USB"</string>
@@ -1475,7 +1470,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"សួរ​រក​កូដ PIN មុន​ពេល​ផ្ដាច់"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"សួរ​រក​លំនាំ​ដោះ​សោ​មុន​ពេល​ផ្ដាច់"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"សួរ​រក​ពាក្យ​សម្ងាត់​មុន​ពេល​ផ្ដាច់"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"កម្មវិធីមិនអាចផ្លាស់ប្តូរទំហំបានទេ សូមរមូរវាដោយប្រើម្រាមដៃពីរ។"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"កម្មវិធីអាចនឹងមិនដំណើរការនៅលើអេក្រង់បំបែកទេ"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"បានដំឡើងដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"បានធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
@@ -1545,12 +1540,11 @@
       <item quantity="other">បានជ្រើស <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">បានជ្រើស <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"ផ្សេងៗ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"អនុញ្ញាតឲ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ឬទេ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"អនុញ្ញាតឲ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> (មានអ្នកប្រើសម្រាប់គណនីនេះរួចហើយ) ឬទេ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ចំណូល​ចិត្ត​ភាសា"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"បន្ថែមភាសា"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ចំណូលចិត្តតំបន់"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"វាយបញ្ចូលឈ្មោះភាសា"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"បាន​ស្នើ"</string>
@@ -1559,8 +1553,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"របៀបការងារបានបិទ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"អនុញ្ញាតឲ្យប្រវត្តិរូបការងារដំណើរការ ដោយរាប់បញ្ចូលទាំងកម្មវិធី ការធ្វើសមកាលកម្មផ្ទៃខាងក្រោយ និងលក្ខណៈពិសេសដែលពាក់ព័ន្ធ។"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"បើក"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"បានបិទដំណើរការ %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"បិទដំណើរការដោយអ្នកគ្រប់គ្រង %1$s។ សូមទាក់ទងពួកគេដើម្បីស្វែងយល់បន្ថែម។"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"អ្នកមានសារថ្មី"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"បើកកម្មវិធីសារ SMS ដើម្បីមើល"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"លទ្ធភាពប្រើមុខងារមួយចំនួនអាចត្រូវបាកម្រិត"</string>
@@ -1573,4 +1565,7 @@
     <string name="pin_target" msgid="3052256031352291362">"ខ្ទាស់"</string>
     <string name="unpin_target" msgid="3556545602439143442">"មិនខ្ទាស់"</string>
     <string name="app_info" msgid="6856026610594615344">"ព័ត៌មាន​កម្មវិធី"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"កំណត់ដូចចេញពីរោងចក្រឡើងវិញដើម្បីប្រើឧបករណ៍នេះដោយគ្មានការរឹតបន្តឹង"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ប៉ះ​ ដើម្បី​​ស្វែងយល់​បន្ថែម។"</string>
 </resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index ff1d028..087b399 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ಕರೆಮಾಡುವವರ ID ಅನ್ನು ನಿರ್ಬಂಧಿಸದಿರುವಂತೆ ಡೀಫಾಲ್ಟ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದಿನ ಕರೆ: ನಿರ್ಬಂಧಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"ಸೇವೆಯನ್ನು ಪೂರೈಸಲಾಗಿಲ್ಲ."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"ನೀವು ಕಾಲರ್‌ ID ಸೆಟ್ಟಿಂಗ್‌ ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ಈಗ ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ನೀತಿಯಿಂದ ಮರೆಮಾಡಲಾಗಿರುವ ವಿಷಯಗಳು"</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="user_owner_label" msgid="1119010402169916617">"ವೈಯಕ್ತಿಕಗೆ ಬದಲಿಸಿ"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"ಕೆಲಸಕ್ಕೆ ಬದಲಿಸು"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ಸಂಪರ್ಕಗಳು"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ಸ್ಥಳ"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ಜೊತೆಗೆ ಸಂಪಾದಿಸಿ"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"ಹೋಮ್‌ ಅಪ್ಲಿಕೇಶನ್‌  ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ಹೋಮ್‌ ಎಂಬಂತೆ %1$s ಅನ್ನು ಬಳಸಿ"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ಈ ಕ್ರಿಯೆಗೆ ಡೀಫಾಲ್ಟ್ ಆಗಿ ಬಳಸಿ."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ಅಪ್ಲಿಕೇಶನ್ ಮರುಹೊಂದಿಸಿ ಮತ್ತು ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ಪ್ರತಿಕ್ರಿಯೆ ಕಳುಹಿಸು"</string>
     <string name="aerr_close" msgid="2991640326563991340">"ಮುಚ್ಚು"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"ಮ್ಯೂಟ್"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"ಸಾಧನವು ಮರುಪ್ರಾರಂಭವಾಗುವವರೆಗೂ ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"ನಿರೀಕ್ಷಿಸು"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಮುಚ್ಚಿ"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ಯಾವುದೇ ಅನುಮತಿಗಳ ಅಗತ್ಯವಿಲ್ಲ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ಇದು ನಿಮ್ಮ ಹಣವನ್ನು ವ್ಯಯಿಸಬಹುದು"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ಸರಿ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ಚಾರ್ಜ್ ಮಾಡುವುದಕ್ಕಾಗಿ USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ಈ ಸಾಧನಕ್ಕೆ USB ಅನ್ನು ಚಾರ್ಜ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, ಲಗತ್ತಿಸಲಾದ ಸಾಧನಕ್ಕೆ ಪವರ್‌ ಪೂರೈಸುತ್ತಿದೆ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ಫೈಲ್‌ ವರ್ಗಾವಣೆಗೆ USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ಫೋಟೋ ವರ್ಗಾವಣೆಗೆ USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ಗೆ USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಸ್ಪರ್ಶಿಸಿ."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕ"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ಡೀಬಗಿಂಗ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ಸಮ್ಮತಿಸು"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ತಿರಸ್ಕರಿಸು"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ದೋಷದ ವರದಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚುವುದೇ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ಈ ಸಾಧನದ ಸಮಸ್ಯೆ ನಿವಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಬಗ್ ವರದಿಯನ್ನು ವಿನಂತಿಸಿದ್ದಾರೆ. ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ನಿರಾಕರಿಸು"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ಕೀಬೋರ್ಡ್ ಬದಲಿಸಿ"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"ಕೀಬೋರ್ಡ್‌ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="show_ime" msgid="2506087537466597099">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲೆ ಇರಿಸಿಕೊಳ್ಳಿ"</string>
     <string name="hardware" msgid="194658061510127999">"ವರ್ಚ್ಯುಯಲ್ ಕೀಬೋರ್ಡ್ ತೋರಿಸು"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆಯ್ಕೆ ಮಾಡಲು ಸ್ಪರ್ಶಿಸಿ"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ವಾಲ್‌ಪೇಪರ್"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ವಾಲ್‌ಪೇಪರ್ ಬದಲಿಸಿ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ಅಧಿಸೂಚನೆ ಕೇಳುಗ"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR ಕೇಳುವಿಕೆ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ಕಂಡೀಶನ್ ಪೂರೈಕೆದಾರರು"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ಅಧಿಸೂಚನೆ ಸಹಾಯಕ"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"ಅಧಿಸೂಚನೆ ಶ್ರೇಣಿಯ ಸೇವೆ"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ಮೂಲಕ VPN ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
     <string name="vpn_text" msgid="3011306607126450322">"ನೆಟ್‍ವರ್ಕ್ ನಿರ್ವಹಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ಇನ್ನಷ್ಟು ಆಯ್ಕೆಗಳು"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"ಆಂತರಿಕವಾಗಿ ಹಂಚಲಾದ ಸಂಗ್ರಹಣೆ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD ಕಾರ್ಡ್"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD ಕಾರ್ಡ್"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ಡ್ರೈವ್"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಿನ್‌ ಕೇಳು"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅನ್‌ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಕೇಳಿ"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್ ಕೇಳು"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ, ಅದನ್ನು ಎರಡು ಬೆರಳುಗಳಿಂದ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"ವಿಭಜಿಸಿದ ಪರದೆಯಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಸ್ಥಾಪಿಸಲಾಗಿದೆ"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ನವೀಕರಿಸಲಾಗಿದೆ"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"ಇತರೆ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ಜನರು ತೊಡಗಿಕೊಂಡಿರುವ ಕಾರಣ ಇದು ಅತ್ಯಂತ ಪ್ರಮುಖವಾಗಿದೆ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (ಈ ಖಾತೆಯ ಬಳಕೆದಾರರು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದ್ದಾರೆ) ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ಭಾಷೆಯ ಪ್ರಾಶಸ್ತ್ಯ"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ಭಾಷೆ ಸೇರಿಸಿ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ಪ್ರದೇಶ ಪ್ರಾಶಸ್ತ್ಯ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ಸಲಹೆ ಮಾಡಿರುವುದು"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಹಿನ್ನೆಲೆ ಸಿಂಕ್ ಮತ್ತು ಇತರ ಸಂಬಂಧಿತ ವೈಶಿಷ್ಟ್ಯಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌‌ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಅನುಮತಿಸಿ."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ಆನ್ ಮಾಡು"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s ನಿರ್ವಾಹಕರಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಇನ್ನಷ್ಟು ತಿಳಿದುಕೊಳ್ಳಲು ಅವರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"ನೀವು ಹೊಸ ಸಂದೇಶಗಳನ್ನು ಹೊಂದಿರುವಿರಿ"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"ವೀಕ್ಷಿಸಲು SMS ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಿರಿ"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ಕೆಲವು ಕಾರ್ಯನಿರ್ವಹಣೆಗಳು ಸೀಮಿತವಾಗಿರಬಹುದು"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"ಪಿನ್ ಮಾಡು"</string>
     <string name="unpin_target" msgid="3556545602439143442">"ಅನ್‌ಪಿನ್"</string>
     <string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"ನಿರ್ಬಂಧಗಳು ಇಲ್ಲದೆಯೇ ಈ ಸಾಧನವನ್ನು ಬಳಸಲು ಫ್ಯಾಕ್ಟರಿ ಮರುಹೊಂದಿಸಿ"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಸ್ಪರ್ಶಿಸಿ."</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index bc0228a..52de5ba 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"음성 지원"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"지금 잠그기"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>개)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"콘텐츠가 정책에 의해 숨겨졌습니다."</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="user_owner_label" msgid="1119010402169916617">"개인으로 전환"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"직장으로 전환"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s(으)로 수정"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"공유 대상"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s와(과) 공유"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"전송 시 사용할 앱"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"전송 시 사용할 앱: %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"홈 앱 선택"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s을(를) 홈 앱으로 사용"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"이 작업에 대해 기본값으로 사용"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"앱 재설정 및 다시 시작"</string>
     <string name="aerr_report" msgid="5371800241488400617">"의견 보내기"</string>
     <string name="aerr_close" msgid="2991640326563991340">"닫기"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"숨기기"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"기기가 다시 시작될 때까지 알림 끄기"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"대기"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"앱 닫기"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"권한 필요 없음"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"비용이 부과될 수 있습니다."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"확인"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"충전용 USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"이 기기를 USB로 충전"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"연결된 기기에 USB로 전력 공급"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"파일 전송용 USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"사진 전송용 USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI용 USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"더 많은 옵션을 확인하려면 터치하세요."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB 디버깅을 사용하지 않으려면 터치하세요."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"수락"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"거절"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"버그 보고서 가져오는 중..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"버그 보고서를 공유하시겠습니까?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"버그 신고서 공유 중..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT 관리자가 이 기기의 문제해결을 위해 버그 보고서를 요청했습니다. 앱과 데이터가 공유될 수 있습니다."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"공유"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"거부"</string>
     <string name="select_input_method" msgid="8547250819326693584">"키보드 변경"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"키보드 선택"</string>
     <string name="show_ime" msgid="2506087537466597099">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
     <string name="hardware" msgid="194658061510127999">"가상 키보드 표시"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"키보드 레이아웃 선택"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"터치하여 키보드 레이아웃을 선택합니다."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"물리적 키보드 설정"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"가상 현실 리스너"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"조건 제공자"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"알림 어시스턴트"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"알림 순위 지정 서비스"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"내부 저장소"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장공간"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 카드"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB 드라이브"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"고정 해제 이전에 잠금해제 패턴 요청"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"고정 해제 이전에 비밀번호 요청"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"앱에서 크기 조절이 불가능합니다. 두 손가락을 사용해 스크롤하세요."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"앱이 분할 화면에서 작동하지 않을 수 있습니다."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"앱이 화면 분할을 지원하지 않습니다."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"관리자가 설치함"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"관리자에 의해 업데이트됨"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>개 선택됨</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 선택됨</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"기타"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"이러한 알림의 중요도를 설정했습니다."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"이러한 알림의 중요도를 설정했습니다."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"관련된 사용자가 있으므로 중요합니다."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g>이(가) <xliff:g id="ACCOUNT">%2$s</xliff:g>(으)로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g>이(가) <xliff:g id="ACCOUNT">%2$s</xliff:g>(이 계정의 사용자가 이미 있음)(으)로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"언어 환경설정"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"언어 추가"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"지역 환경설정"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"언어 이름 입력"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"추천"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"직장 모드가 사용 중지됨"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"앱, 백그라운드 동기화 및 관련 기능을 포함한 직장 프로필이 작동하도록 허용"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"사용 설정"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s이(가) 사용 중지됨"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s 관리자에 의해 사용 중지되었습니다. 자세히 알아보려면 관리자에게 문의하세요."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"새 메시지 있음"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"SMS 앱을 열고 확인"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"일부 기능이 제한될 수 있습니다."</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"고정"</string>
     <string name="unpin_target" msgid="3556545602439143442">"고정 해제"</string>
     <string name="app_info" msgid="6856026610594615344">"앱 정보"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"제한 없이 기기를 사용하기 위한 초기화"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"자세한 내용을 보려면 터치하세요."</string>
 </resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 5fc6a62..34cc7e5 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Үн жардамчысы"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Азыр кулпулоо"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Тийиштүү саясат боюнча жашырылган мазмундар"</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="user_owner_label" msgid="1119010402169916617">"Жеке профилге которулуу"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Жумуш профилине которулуу"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Байланыштар"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызга уруксат"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
@@ -902,6 +900,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s менен түзөтүү"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Төмөнкү менен бөлүшүү"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s менен бөлүшүү"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Колдонмо тандаңыз"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s аркылуу жөнөтүү"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Башкы бет колдонмосун тандаңыз"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Башкы бет колдонмосу катары %1$s пайдалануу"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Бул аракет үчүн демейки боюнча колдонулсун."</string>
@@ -918,7 +918,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Колдонмону баштапкы абалга келтирип, кайра жүргүзүү"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Жооп пикир жөнөтүү"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Жабуу"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Үнсүз"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Түзмөк өчүрүлүп-күйгүзүлгүчө үнүн өчүрүү"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Күтүү"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Колдонмону жабуу"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1046,7 +1046,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Эч уруксаттын кереги жок"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"бул үчүн акы алынышы мүмкүн"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Жарайт"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Кубаттоо үчүн USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Бул түзмөк USB менен кубатталууда"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Тиркелген түзмөк USB менен кубатталууда"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файл өткөрүү үчүн USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Сүрөт өткөрүү үчүн USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI үчүн USB"</string>
@@ -1054,24 +1055,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Көбүрөөк параметр үчүн тийип коюңуз."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB мүчүлүштүктөрдү оңдоо туташтырылган"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB мүчүлүштүктөрдү жоюу мүмкүнчүлүгүн өчүрүү үчүн тийип коюңуз."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"КАБЫЛ АЛУУ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ЧЕТКЕ КАГУУ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Мүчүлүштүк тууралуу баяндама бөлүшүлсүнбү?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Мүчүлүштүк тууралуу баяндама бөлүшүлүүдө…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Бул түзмөктүн бузулууларын аныктап оңдоо үчүн IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Колдонмолор менен дайындар бөлүшүлүшү мүмкүн."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛҮШҮҮ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ЧЕТКЕ КАГУУ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Баскычтопту өзгөртүү"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Баскычтопторду тандаңыз"</string>
     <string name="show_ime" msgid="2506087537466597099">"Баскычтоп иштетилгенде экранда көрүнүп турсун"</string>
     <string name="hardware" msgid="194658061510127999">"Виртуалдык баскычтоп"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Тергичтин жайгашуусун тандоо"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Тергичтин жайгашуусун тандаш үчүн басыңыз."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Аппараттык баскычтопту конфигурациялоо"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string>
@@ -1144,8 +1138,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Тушкагаз"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Тушкагазды өзгөртүү"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Эскертүү тыңшагычы"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR режими"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт түзүүчү"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Эскертме жардамчысы"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Эскертмелердин маанилүүлүгүн баалоо кызматы"</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>
@@ -1230,7 +1225,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Дагы параметрлер"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Ички сактагыч"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Жалпы ички сактагыч"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD карта"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB түзмөк"</string>
@@ -1474,7 +1469,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Бошотуудан мурун кулпуну ачкан үлгү суралсын"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Бошотуудан мурун сырсөз суралсын"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Колдонмонун көлөмүн өзгөртүүгө болбойт, андыктан эки манжаңыз менен сыдырып караңыз."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Колдонмодо экран бөлүнбөшү мүмкүн."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Колдонмодо экран бөлүнбөйт."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Администраторуңуз тарабынан орнотулган"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Администраторуңуз жаңырткан"</string>
@@ -1544,12 +1539,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> тандалды</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Калган-каткандар"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби (мындай каттоо эсеби бар колдонуучу мурунтан эле бар) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Тил жөндөөлөрү"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Тил кошуңуз"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Чөлкөмдүк жөндөөлөр"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string>
@@ -1558,18 +1552,19 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Жумуш режими ӨЧҮРҮЛГӨН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Жумуш профилин, ошондой эле колдонмолорду, фондо шайкештирүү жана ага байланыштуу функцияларды иштетиңиз."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Күйгүзүү"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s өчүрүлгөн"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s администратору тарабынан өчүрүлгөн. Көбүрөөк билүү үчүн администраторго кайрылыңыз."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Сизге жаңы билдирүүлөр келди"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Көрүү үчүн SMS колдонмосун ачыңыз"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Айрым функциялар чектлши мүмкн"</string>
     <string name="user_encrypted_message" msgid="4923292604515744267">"Кулпусун ачуу үчүн таптаңыз"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"Колдончнн дайындары кулпуланды"</string>
     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Жумуш профили кулпуланган"</string>
-    <string name="profile_encrypted_message" msgid="6964994232310195874">"Таптап, жумуш профилин ачыңыз"</string>
+    <string name="profile_encrypted_message" msgid="6964994232310195874">"Таптап жумуш профилин ачыңыз"</string>
     <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> менен туташты"</string>
     <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Файлдарды көрүү үчүн таптап коюңуз"</string>
     <string name="pin_target" msgid="3052256031352291362">"Кадоо"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Кадоодон алып коюу"</string>
     <string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Бул түзмөктү чектөөсүз колдонуу үчүн аны баштапкы абалга келтириңиз"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Көбүрөөк билүү үчүн тийип коюңуз."</string>
 </resources>
diff --git a/core/res/res/values-ldrtl-television/config.xml b/core/res/res/values-ldrtl-television/config.xml
new file mode 100644
index 0000000..e237acc
--- /dev/null
+++ b/core/res/res/values-ldrtl-television/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for TV products.  Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
+    <string translatable="false" name="config_defaultPictureInPictureBounds">"112 54 592 324"</string>
+
+</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 0c146bd..ea62f9b 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ໝາຍເລກຜູ່ໂທ ໄດ້ຮັບການຕັ້ງຄ່າເລີ່ມຕົ້ນເປັນ ບໍ່ຖືກຈຳກັດ. ການໂທຄັ້ງຕໍ່ໄປ: ບໍ່ຖືກຈຳກັດ."</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"ບໍ່ໄດ້ເປີດໃຊ້ບໍລິການ."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"ທ່ານບໍ່ສາມາດປ່ຽນແປງການຕັ້ງຄ່າ Caller ID"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"ຊ່ວຍ​ເຫຼືອ​ທາງ​ສຽງ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ລັອກ​ດຽວ​ນີ້"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ເນື້ອຫາ​ຖືກ​ເຊື່ອງ​ໄວ້"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ເນື້ອຫາຖືກເຊື່ອງຕາມນະໂຍບາຍ"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</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="user_owner_label" msgid="1119010402169916617">"ສະລັບໄປໂປຣໄຟລ໌ສ່ວນຕົວ"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"ສະລັບໄປໂປຣໄຟລ໌ວຽ."</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ລາຍຊື່"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ເຂົ້າ​ຫາ​ລາຍ​ຊື່​ຂອງ​ທ່ານ"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ສະ​ຖານ​ທີ່"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ແກ້​ໄຂ​ໃນ %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"ແບ່ງປັນກັບ"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"ແບ່ງ​ປັນ​ກັບ %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ສົ່ງໂດຍໃຊ້"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"ສົ່ງໂດຍໃຊ້ %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"​ເລືອກ​ແອັບຯ​ໂຮມ"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"​ໃຊ້ %1$s ເປັນ​ໜ້າຫຼັກ"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ໃຊ້ໂດຍຄ່າເລີ່ມຕົນສຳລັບການເຮັດວຽກນີ້."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ຣີເຊັດ ແລະ ເລີ່ມແອັບໃໝ່"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ສົ່ງຄຳຕິຊົມ"</string>
     <string name="aerr_close" msgid="2991640326563991340">"ປິດ"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"ປິດສຽງ"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"ປິດສຽງຈົນກວ່າວ່າອຸປະກອນເລີ່ມໃໝ່"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"ລໍຖ້າ"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ປິດແອັບ"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ບໍ່ຕ້ອງການການອະນຸຍາດ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ລາຍການນີ້ອາດມີການເກັບເງິນ"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ຕົກລົງ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB ສຳ​ລັບ​ການ​ສາກ"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ກຳລັງສາກໄຟ USB ອຸປະກອນນີ້"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB ກຳລັງສະໜອງໄຟໃຫ້ກັບອຸປະກອນທີ່ເຊື່ອມຕໍ່ກັນ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB ສຳ​ລັບ​ການ​ໂອ​ນ​ໄຟ​ລ໌"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB ສຳ​ລັບ​ການ​ໂອນ​ໄຟ​ລ໌"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB ສຳ​ລັບ MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"ສຳ​ພັດ​ສຳ​ລັບ​ທາງ​ເລືອກ​ເພີ່ມ​ເຕີມ."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"ເຊື່ອມຕໍ່ການດີບັ໊ກຜ່ານ USB ແລ້ວ"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"ແຕະເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ຍອມຮັບ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ປະຕິເສດ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ກຳລັງຂໍລາຍງານຂໍ້ຜິດພາດ…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ແບ່ງປັນລາຍງານບັນຫາບໍ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ກຳລັງແບ່ງປັນລາຍງານບັນຫາ…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍເອົາລາຍງານບັນຫາ ເພື່ອຊ່ວຍແກ້ໄຂບັນຫາໃຫ້ອຸປະກອນນີ້. ອາດຈະມີການແບ່ງປັນແອັບ ແລະ ຂໍ້ມູນນຳ."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ແບ່ງປັນ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ປະຕິເສດ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"​ປ່ຽນ​ແປ້ນ​ພິມ"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"​ເລືອກ​ແປ້ນ​ພິມ"</string>
     <string name="show_ime" msgid="2506087537466597099">"ເປີດໃຊ້ໃຫ້ມັນຢູ່ໃນໜ້າຈໍໃນຂະນະທີ່ໃຊ້ແປ້ນພິມພາຍນອກຢູ່"</string>
     <string name="hardware" msgid="194658061510127999">"ສະແດງແປ້ນພິມສະເໝືອນ"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ເລືອກຮູບແບບແປ້ນພິມ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ກົດເພື່ອເລືອກຮູບແບບແປ້ນພິມ."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ຕັ້ງຄ່າແປ້ນພິມພາຍນອກ"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ພາບພື້ນຫຼັງ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ປ່ຽນພາບພື້ນຫຼັງ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ໂຕຟັງການແຈ້ງເຕືອນ"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"ຕົວຟັງ VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"​ຜູ່​ສະ​ໜອງ​ເງື່ອນ​ໄຂ"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ຕົວຊ່ວຍ​ການ​ແຈ້ງ​ເຕືອນ"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"ບໍລິການຈັດອັນດັບການແຈ້ງເຕືອນ"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ໂຕເລືອກອື່ນ"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍໃນ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນທີ່ແບ່ງປັນພາຍໃນ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> ແຜ່ນ SD"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ດ​ຣ້າຍ"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"​ຖາມ​ຫາ PIN ກ່ອນ​ຍົກ​ເລີກ​ການປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"​ຖາມ​ຫາ​ຮູບ​ແບບ​ປົດ​ລັອກ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"​ຖາມ​ຫາ​ລະ​ຫັດ​ຜ່ານ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ບໍ່ສາມາດປັບຂະໜາດແອັບໄດ້, ໃຫ້ເລື່ອນມັນໂດຍໃຊ້ນິ້ວມືສອງນິ້ວ."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບການແບ່ງໜ້າຈໍ."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ​ຕິດ​ຕັ້ງ​ໃສ່​ແລ້ວ"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ອັບ​ເດດ​ໂດຍ​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ​ແລ້ວ"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ຖືກເລືອກ​ແລ້ວ</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ຖືກເລືອກ​ແລ້ວ</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"ອື່ນໆ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ສຳລັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ບໍ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ສຳລັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> (ຜູ້ໃຊ້ສຳລັບບັນຊີນີ້ມີຢູ່ແລ້ວ) ບໍ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ການຕັ້ງຄ່າພາສາ"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ເພີ່ມພາສາ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ການຕັ້ງຄ່າພາກພື້ນ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ພິມຊື່ພາສາ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ແນະນຳ"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"ໂໝດບ່ອນເຮັດວຽກປິດຢູ່"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ອະນຸຍາດໃຫ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກສາມາດນຳໃຊ້ໄດ້ ເຊິ່ງຮວມທັງແອັບ, ການຊິ້ງຂໍ້ມູນໃນພື້ນຫຼັງ ແລະ ຄຸນສົມບັດທີ່ກ່ຽວຂ້ອງ."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ເປີດ​"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s ຖືກປິດໃຊ້ແລ້ວ"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"ຖືກປິດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ %1$s. ກະລຸນາຕິດຕໍ່ຫາພວກເຂົາເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"ທ່ານມີຂໍ້ຄວາມໃໝ່"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"ເປີດແອັບ SMS ເພື່ອເບິ່ງ"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ບາງຄວາມສາມາດນຳໃຊ້ອາດຈະຖືກຈຳກັດ"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"ປັກໝຸດ"</string>
     <string name="unpin_target" msgid="3556545602439143442">"ຖອນປັກໝຸດ"</string>
     <string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"ຣີເຊັດໃຫ້ເປັນຄ່າໂຮງງານເພື່ອໃຊ້ອຸປະກອນນີ້ໂດຍບໍ່ມີຂໍ້ຈຳກັດ"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e4d10ae..3e815ec 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -90,7 +90,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Skambintojo ID pagal numatytuosius nustatymus yra neapribotas. Kitas skambutis: neapribotas"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Paslauga neteikiama."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Negalima pakeisti skambinančiojo ID nustatymo."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Apribota prieiga pakeista"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Duomenų paslauga užblokuota."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Pagalbos paslauga užblokuota."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Balso paslauga užblokuota."</string>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Užrakinti dabar"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Turinys paslėptas vadovaujantis politika"</string>
     <string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
     <string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Asmeninė"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Darbo"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Perjungti į asmeninį režimą"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Perjungti į darbo režimą"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktai"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pasiekti kontaktus"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Vietovė"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redaguoti naudojant %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Bendrinti naudojant"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Bendrinti naudojant %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Siųsti naudojant"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Siųsti naudojant „%1$s“"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Pasirinkti pagrindinę programą"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Naudoti „%1$s“ kaip pagrindinę programą"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Šiam veiksmui tai naudoti pagal numatytuosius nustatymus."</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Nustatyti ir paleisti programą iš naujo"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Siųsti atsiliepimą"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Uždaryti"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Paslėpti"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignoruoti, kol įrenginys bus paleistas iš naujo"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Laukti"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Uždaryti programą"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nereikia leidimų"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"tai gali kainuoti"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Gerai"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB (įkrovimas)"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Įrenginys įkraunamas naudojant USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Maitinimas prijungtam įrenginiui tiekiamas naudojant USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB (failų perkėlimas)"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB (nuotraukų perkėlimas)"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB (MIDI)"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Palieskite, kad būtų rodoma daugiau parinkčių."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB derinimas prijungtas"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Neleisti USB derinimo."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SUTIKTI"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ATMESTI"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Pateikiamas pranešimas apie riktą…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bendrinti pranešimą apie riktą?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bendrinamas pranešimas apie riktą..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis šiame įrenginyje. Programos ir duomenys gali būti bendrinami."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"BENDRINTI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ATMESTI"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Klaviatūros keitimas"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Pasirinkti klaviatūras"</string>
     <string name="show_ime" msgid="2506087537466597099">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
     <string name="hardware" msgid="194658061510127999">"Rodyti virtualiąją klaviatūrą"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pasirinkite klaviatūros išdėstymą"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Palieskite, kad pasirinktumėte klaviatūros išdėstymą."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fizinės klaviatūros konfigūravimas"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
@@ -1159,8 +1153,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtualiosios realybės apdorojimo priemonė"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Sąlygos teikėjas"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pranešimų pagelbiklis"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Pranešimų reitingavimo paslauga"</string>
     <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>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Daugiau parinkčių"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Vidinė atmintis"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Vidinė bendroji atmintis"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kortelė"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"„<xliff:g id="MANUFACTURER">%s</xliff:g>“ SD kortelė"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Atmintukas"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prašyti PIN kodo prieš atsegant"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Prašyti atrakinimo piešinio prieš atsegant"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Prašyti slaptažodžio prieš atsegant"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Programos dydis nekeičiamas, slinkite dviem pirštais."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Programa gali neveikti naudojant skaidytą ekraną."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Programoje nepalaikomas skaidytas ekranas."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Įdiegė administratorius"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atnaujino administratorius"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="many">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item>
       <item quantity="other">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Įvairūs"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Galite nustatyti šių pranešimų svarbą."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Galite nustatyti šių pranešimų svarbą."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Kalbos nuostata"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Pridėkite kalbą"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regiono nuostata"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Darbo režimas išjungtas"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Leisti veikti darbo profiliui, įskaitant programas, sinchronizavimą fone ir susijusias funkcijas."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Įjungti"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s išjungtas"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Išjungė %1$s administratorius. Kad sužinotumėte daugiau, susisiekite su juo."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Turite naujų pranešimų"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Atidaryti SMS programą, norint peržiūrėti"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Kai kurios funkcijos gali būti ribojamos"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Prisegti"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Atsegti"</string>
     <string name="app_info" msgid="6856026610594615344">"Programos informacija"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"–<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Atkurkite gamyklinius nustatymus, kad galėtumėte naudoti šį įrenginį be apribojimų"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Palieskite, kad sužinotumėte daugiau."</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 2fda60c..56001fc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -89,7 +89,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Zvanītāja ID noklusējumi ir iestatīti uz Nav ierobežots. Nākamais zvans: nav ierobežots"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Pakalpojums netiek nodrošināts."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Zvanītāja ID iestatījumu nevar mainīt."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ierobežotā piekļuve ir mainīta"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datu pakalpojums ir bloķēts."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Ārkārtas pakalpojums ir bloķēts."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Balss pakalpojums ir bloķēts."</string>
@@ -232,13 +231,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Balss palīgs"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloķēt tūlīt"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Saskaņā ar politiku saturs ir paslēpts."</string>
     <string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personisks"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Darba"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Pārslēgt personīgo profilu"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Pārslēgt darba profilu"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersonas"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"piekļūt jūsu kontaktpersonu datiem"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Atrašanās vieta"</string>
@@ -907,6 +905,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediģēt, izmantojot %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Kopīgot, izmantojot"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Kopīgot, izmantojot %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Sūtīšana, izmantojot..."</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Sūtīšana, izmantojot: %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Sākuma lietotnes atlase"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"“%1$s” kā sākuma lietotnes izmantošana"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Pēc noklusējuma izmantot šai darbībai."</string>
@@ -923,7 +923,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Atiestatīt un restartēt lietotni"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Sūtīt atsauksmes"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Aizvērt"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Nerādīt"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Nerādīt, līdz ierīce tiks restartēta"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Gaidīt"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Aizvērt lietotni"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,7 +1053,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Atļaujas nav nepieciešamas."</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"par to no jums var tikt iekasēta maksa"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Labi"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB savienojums uzlādei"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB savienojums tiek izmantots šīs ierīces uzlādei"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB savienojums tiek izmantots pievienotās ierīces barošanai"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB savienojums failu pārsūtīšanai"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB savienojums fotoattēlu pārsūtīšanai"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB savienojums MIDI režīmā"</string>
@@ -1061,24 +1062,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Citas opcijas"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Iespējot USB atkļūdošanu."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"APSTIPRINĀT"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"NORAIDĪT"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Notiek kļūdas pārskata izveide…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vai kopīgot kļūdas pārskatu?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Notiek kļūdas pārskata kopīgošana…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu šajā ierīcē. Var tikt kopīgotas lietotnes un dati."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"KOPĪGOT"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NORAIDĪT"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Tastatūras maiņa"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Izvēlēties tastatūru"</string>
     <string name="show_ime" msgid="2506087537466597099">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuālās tastatūras rādīšana"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Atlasiet tastatūras izkārtojumu"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pieskarieties, lai atlasītu tastatūras izkārtojumu."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziskās tastatūras konfigurēšana"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
@@ -1151,8 +1145,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR klausītājs"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nosacījumu sniedzējs"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Paziņojumu palīgs"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Paziņojumu ranžēšanas pakalpojums"</string>
     <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>
@@ -1238,7 +1233,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Vairāk opciju"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s: %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s: %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Iekšējā atmiņa"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Iekšējā kopīgotā krātuve"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD karte"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD karte"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB disks"</string>
@@ -1483,7 +1478,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prasīt PIN kodu pirms atspraušanas"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pirms atspraušanas pieprasīt grafisko atslēgu"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pirms atspraušanas pieprasīt paroli"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Lietotnes lielumu nevar mainīt. Ritiniet to ar diviem pirkstiem."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Iespējams, lietotnē nedarbosies ekrāna sadalīšana."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalēja jūsu administrators"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atjaunināja administrators"</string>
@@ -1562,12 +1557,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīts</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Dažādi"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tas ir svarīgi iesaistīto personu dēļ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g> (lietotājs ar šādu kontu jau pastāv)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Valodas preference"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Pievienot valodu"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Reģiona preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Ierakstiet valodas nosaukumu"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ieteiktās"</string>
@@ -1576,8 +1570,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Darba režīms IZSLĒGTS"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Atļaujiet darboties darba profilam, tostarp lietotnēm, sinhronizācijai fonā un saistītajām funkcijām."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Ieslēgt"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Pakotne %1$s atspējota"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Atspējoja %1$s administrators. Lai uzzinātu vairāk, sazinieties ar administratoru."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Jums ir jaunas īsziņas."</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Lai skatītu, atveriet īsziņu lietotni."</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Funkcijas var būt ierobežotas"</string>
@@ -1590,4 +1582,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Piespraust"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Atspraust"</string>
     <string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rūpnīcas datu atiestatīšana ierīces neierobežotai izmantošanai"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pieskarieties, lai uzzinātu vairāk."</string>
 </resources>
diff --git a/core/res/res/values-mcc232-mnc11/config.xml b/core/res/res/values-mcc232-mnc11/config.xml
new file mode 100644
index 0000000..91e37b4
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc11/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23201</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc12/config.xml b/core/res/res/values-mcc232-mnc12/config.xml
new file mode 100644
index 0000000..91e37b4
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc12/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23201</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc160-be-rBY/strings.xml
new file mode 100644
index 0000000..39ec232
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="3017901214286816293">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-bs-rBA/strings.xml b/core/res/res/values-mcc310-mnc160-bs-rBA/strings.xml
new file mode 100644
index 0000000..20e163a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-bs-rBA/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="3017901214286816293">"Da biste pozivali i slali poruke preko Wi-Fi-ja, prvo zatražite od operatera da postavi tu uslugu. Potom u Postavkama ponovo uključite Wi-Fi pozivanje."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrirajte se kod svog operatera"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Wi-Fi pozivanje preko operatera %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc200-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc200-be-rBY/strings.xml
new file mode 100644
index 0000000..20431f6
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc200-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="9107329079910661798">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="2841003137832065541">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="6806975706640442517">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc210-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc210-be-rBY/strings.xml
new file mode 100644
index 0000000..463b405
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc210-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="5217754856196352581">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="4688475512286389971">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="5475635312889002673">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc220-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc220-be-rBY/strings.xml
new file mode 100644
index 0000000..2c6bd39
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc220-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="6238990105876016549">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="2866631708941520085">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="3422704506272221128">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc230-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc230-be-rBY/strings.xml
new file mode 100644
index 0000000..24d65fc
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc230-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="9007462326786949889">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="6747587721329739803">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="903741468703044544">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc240-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc240-be-rBY/strings.xml
new file mode 100644
index 0000000..42e1e34
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc240-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="2734345662112241986">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="5561711399459051107">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="6383482961309785661">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc250-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc250-be-rBY/strings.xml
new file mode 100644
index 0000000..490c278
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc250-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="3177110876268966">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="5743977848030289234">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="1221554601313232001">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc260-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc260-be-rBY/strings.xml
new file mode 100644
index 0000000..497366b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc260-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc260-bs-rBA/strings.xml b/core/res/res/values-mcc310-mnc260-bs-rBA/strings.xml
new file mode 100644
index 0000000..64e4862
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc260-bs-rBA/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Da biste pozivali i slali poruke preko Wi-Fi-ja, prvo zatražite od operatera da postavi tu uslugu. Potom u Postavkama ponovo uključite Wi-Fi pozivanje."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Registrirajte se kod svog operatera"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi pozivanje preko operatera %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc270-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc270-be-rBY/strings.xml
new file mode 100644
index 0000000..43e6fc5
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc270-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="6674750523418536585">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="5880767641285399402">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="5634367913183683816">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc310-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc310-be-rBY/strings.xml
new file mode 100644
index 0000000..1cdbdb1
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc310-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="1972026366984640493">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="1383416528714661108">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="7770475174975527040">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc490-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc490-be-rBY/strings.xml
new file mode 100644
index 0000000..51d5022
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc490-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="2780619740658228275">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="4633656294483906293">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="1518868466785799436">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc660-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc660-be-rBY/strings.xml
new file mode 100644
index 0000000..66523ed
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc660-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="4027376374798357928">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="5536938168415300276">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="979929705672330">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc800-be-rBY/strings.xml b/core/res/res/values-mcc310-mnc800-be-rBY/strings.xml
new file mode 100644
index 0000000..0a48e5e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc800-be-rBY/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="8435554129271297367">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="8993797655078232716">"Зарэгіструйцеся ў свайго аператара"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="8604078859021657352">"Wi-Fi-тэлефанія %s"</string>
+</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index d4f1722..060a9fa 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помош"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заклучи сега"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содржините се скриени поради политиката"</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="user_owner_label" msgid="1119010402169916617">"Префрлете на личен профил"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Префрли на работен профил"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапува до контактите"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Уреди со %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Сподели со"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Сподели со %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Испрати преку"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Испрати преку %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Изберете ја апликацијата Почетен"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Користете ја %1$s како Почетен"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Користи ја стандардно за ова дејство."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Ресетирај ја и рестартирај ја апликацијата"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Испрати повратни информации"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Затвори"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Исклучи звук"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Исклучи го звукот додека уредот не се рестартира"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Почекај"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Затвори ја апликацијата"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Не се потребни дозволи"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ова може да ве чини пари"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Во ред"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"УСБ за полнење"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Уредов се полни преку USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Прикачениот уред се напојува преку USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"УСБ за пренос на датотеки"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"УСБ за пренос на фотографии"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"УСБ за МИДИ"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Допри за повеќе опции."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Поврзано е отстранување грешки преку УСБ"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Допрете за да се оневозможи отстранувањето грешки преку USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИФАТИ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Се зема извештајот за грешки…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели извештајот за грешки?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Се споделува извештај за грешки…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Вашиот администратор за информатичка технологија побара извештај за грешки за да ви помогне во отстранувањето на грешките на овој уред. Апликациите и податоците може да бидат споделени."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛИ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Измени тастатура"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Избери тастатури"</string>
     <string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелна тастатура"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избери изглед на тастатура"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Допри за да избереш изглед на тастатура."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигурирајте физичка тастатура"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промени тапет"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известувања"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR слушател"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Давател на услов"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помошник за известувања"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Услуга за рангирање известувања"</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>
@@ -1231,7 +1226,7 @@
     <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
     <skip />
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Внатрешна меморија"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Внатрешно заедничко место за складирање"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"СД картичка"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> СД-картичка"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"УСБ-меморија"</string>
@@ -1475,7 +1470,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Прашај за ПИН пред откачување"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Прашај за шема за отклучување пред откачување"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Прашај за лозинка пред откачување"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Не може да се промени големината на апликацијата, лизгајте ја со два прста."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Апликацијата можеби нема да работи во поделен екран."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Апликацијата не поддржува поделен екран."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Инсталирано од администраторот"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирано од администраторот"</string>
@@ -1545,12 +1540,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> е избрана</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> се избрани</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ја поставивте важноста на известувањава."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ја поставивте важноста на известувањава."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ова е важно заради луѓето кои се вклучени."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Дозволувате ли <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Дозволувате ли <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g> (веќе постои корисник со оваа сметка)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Претпочитувања за јазик"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Додај јазик"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Претпочитувања за регион"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Внеси име на јазик"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
@@ -1559,8 +1553,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Режимот на работа е ИСКЛУЧЕН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозволете работниот профил да функционира, вклучувајќи ги апликациите, синхронизирањето во заднина и други поврзани функции."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Вклучи"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s е оневозможен"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Оневозможено од администраторот на %1$s. Контактирајте со него за да дознаете повеќе."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Имате нови пораки"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Отворете ја апликацијата за СМС за приказ"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Некои функции се ограничени"</string>
@@ -1573,4 +1565,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Прикачете"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Откачете"</string>
     <string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетирајте до фабричките поставки за уредов да го користите без ограничувања"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Допрете за да дознаете повеќе."</string>
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index f4c7243..f6ff1d8 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"വോയ്‌സ് സഹായം"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ഇപ്പോൾ ലോക്കുചെയ്യുക"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്‌റ്റുകൾ മറച്ചു"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"നയം അനുസരിച്ച് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</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="user_owner_label" msgid="1119010402169916617">"വ്യക്തിഗത പ്രൊഫൈലിലേക്ക് മാറുക"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"കോൺടാക്റ്റുകൾ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്‌സസ്സ് ചെയ്യുക"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ലൊക്കേഷൻ"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"ഇതുമായി പങ്കിടുക"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s എന്നതുമായി പങ്കിടുക"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച് അയയ്ക്കുക"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ഉപയോഗിച്ച് അയയ്ക്കുക"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"ഒരു ഹോം അപ്ലിക്കേഷൻ തിരഞ്ഞെടുക്കുക"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ഹോമായി %1$s എന്നത് ഉപയോഗിക്കുക"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ഈ പ്രവർത്തനത്തിന് സ്ഥിരമായി ഉപയോഗിക്കുക."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ആപ്പ് പുനഃക്രമീകരിച്ച് പുനഃരാരംഭിക്കുക"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ഫീഡ്‌ബാക്ക് അയയ്‌ക്കുക"</string>
     <string name="aerr_close" msgid="2991640326563991340">"അടയ്‌ക്കുക"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"മ്യൂട്ടുചെയ്യുക"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"ഉപകരണം പുനഃരാരംഭിക്കുന്നത് വരെ മ്യൂട്ടുചെയ്യുക"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"കാത്തിരിക്കുക"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ആപ്പ് അടയ്‌ക്കുക"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"അനുമതികളൊന്നും ആവശ്യമില്ല"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ഇത് നിങ്ങൾക്ക് പണച്ചെലവിനിടയാക്കാം"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ശരി"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ചാർജ്ജിംഗിനായുള്ള USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ഈ ഉപകരണം USB ചാർജുചെയ്യുന്നു"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ഘടിപ്പിച്ചിട്ടുള്ള ഉപകരണത്തിന് USB വൈദ്യുതി നൽകുന്നു"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ഫയൽ കൈമാറ്റത്തിനുള്ള USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ഫോട്ടോ കൈമാറ്റത്തിനായുള്ള USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-യ്‌ക്കായുള്ള USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"കൂടുതൽ ഓപ്‌ഷനുകൾക്ക് സ്‌പർശിക്കൂ."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ സ്‌പർശിക്കൂ."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"അംഗീകരിക്കുക"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"നിരസിക്കുക"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ബഗ് റിപ്പോർട്ട് എടുക്കുന്നു…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നു…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ഈ ഉപകരണത്തിലെ പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്‌മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു. ആപ്‌സും ഡാറ്റയും പങ്കിടപ്പെട്ടേക്കും."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"പങ്കിടുക"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"നിരസിക്കുക"</string>
     <string name="select_input_method" msgid="8547250819326693584">"കീബോഡ് മാറ്റുക"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"കീബോർഡുകൾ തിരഞ്ഞെടുക്കുക"</string>
     <string name="show_ime" msgid="2506087537466597099">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
     <string name="hardware" msgid="194658061510127999">"വെർച്വൽ കീബോർഡ് കാണിക്കുക"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ഒരു കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കാൻ സ്‌പർശിക്കുക."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ഫിസിക്കൽ കീബോർഡ് കോൺഫിഗർ ചെയ്യുക"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"വാൾപേപ്പർ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"വാൾപേപ്പർ മാറ്റുക"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"അറിയിപ്പ് ലിസണർ"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR ലിസണർ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"കണ്ടീഷൻ ദാതാവ്"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"അറിയിപ്പ് സഹായി"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"അറിയിപ്പ് റാങ്കർ സേവനം"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN സജീവമാക്കി"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ഉപയോഗിച്ച് VPN പ്രവർത്തനക്ഷമമാക്കി"</string>
     <string name="vpn_text" msgid="3011306607126450322">"നെറ്റ്‌വർക്ക് നിയന്ത്രിക്കാൻ സ്‌പർശിക്കുക."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"കൂടുതൽ‍ ഓപ്‌ഷനുകള്‍"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"ആന്തരിക സ്റ്റോറേജ്"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"പങ്കിട്ട ആന്തരിക സ്റ്റോറേജ്"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD കാർഡ്"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD കാർഡ്"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ഡ്രൈവ്"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ചെയ്യുംമുമ്പ് പിൻ ചോദിക്കൂ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടുക"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പാസ്‌വേഡ് ആവശ്യപ്പെടുക"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ആപ്പിന്റെ വലുപ്പം ക്രമീകരിക്കാൻ കഴിയില്ല, രണ്ട് വിരലുകൾ ഉപയോഗിച്ച് അത് സ്ക്രോൾ ചെയ്യുക."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"സ്പ്ലിറ്റ്-സ്ക്രീനിനൊപ്പം ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർ ഇൻസ്റ്റാളുചെയ്‌തു"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർ അപ്‌ഡേറ്റുചെയ്‌തു"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"പലവക"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ഉൾപ്പെട്ടിട്ടുള്ള ആളുകളെ കണക്കിലെടുക്കുമ്പോള്‍ ഇത് പ്രധാനപ്പെട്ടതാണ്‌."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് ഉപയോഗിച്ച് പുതിയൊരു ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് (ഈ അക്കൗണ്ട് ഉപയോഗിച്ചുള്ള ഒരു ഉപയോക്താവ് ഇതിനകം തന്നെ നിലവിലുണ്ട്) ഉപയോഗിച്ച് പുതിയൊരു ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ഭാഷാ മുൻഗണന"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ഒരു ഭാഷ ചേർക്കുക"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"മേഖലാ മുൻഗണന"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ഭാഷയുടെ പേര് ടൈപ്പുചെയ്യുക"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"നിര്‍‌ദ്ദേശിച്ചത്"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"ഔദ്യോഗിക മോഡ് ഓഫാണ്"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ആപ്സും, പശ്ചാത്തല സമന്വയവും ബന്ധപ്പെട്ട ഫീച്ചറുകളും ഉൾപ്പെടെ, ഔദ്യോഗിക പ്രൊഫൈലിനെ പ്രവർത്തിക്കാൻ അനുവദിക്കുക."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ഓണാക്കുക"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s പ്രവർത്തനരഹിതമാക്കി"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s അഡ്മിനിസ്ട്രേറ്റർ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു. കൂടുതലറിയാൻ അഡ്മിനിസ്ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"നിങ്ങൾക്ക് പുതിയ സന്ദേശങ്ങൾ ഉണ്ട്"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"കാണുന്നതിന് SMS ആപ്പ് തുറക്കുക"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ചില പ്രവർത്തനക്ഷമതകൾ പരിമിതപ്പെടാം"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"പിൻ ചെയ്യുക"</string>
     <string name="unpin_target" msgid="3556545602439143442">"അൺപിൻ ചെയ്യുക"</string>
     <string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"നിയന്ത്രണങ്ങൾ ഇല്ലാതെ ഈ ഉപകരണം ഉപയോഗിക്കാൻ ഫാക്ടറി റീസെറ്റ് നടത്തുക"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"കൂടുതലറിയുന്നതിന് സ്‌പർശിക്കുക."</string>
 </resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index aba5bc0..75105e6 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Дуудлага хийгчийн ID хязгаарлагдсан. Дараагийн дуудлага: Хязгаарлагдсан"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Үйлчилгээ провишн хийгдээгүй ."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Та дуудлага хийгчийн ID тохиргоог солиж чадахгүй."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Дуут туслах"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Одоо түгжих"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Удирдамжийн дагуу нуусан агуулга"</string>
     <string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Хувийн"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Ажил"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"\"Хувийн\" руу шилжих"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"\"Ажлын\" руу шилжих"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Харилцагчдын хаяг"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"харилцагч руугаа хандах"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Байршил"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ашиглан засварлах"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Хуваалцах"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s ашиглан хуваалцах"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Ашиглан илгээх"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s-г ашиглан илгээх"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Үндсэн апп-г сонгох"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s-г Үндсэн-р ашиглах"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Энэ ажиллагааг үндсэн болгох."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Апп-ыг шинэчилж, дахин эхлүүлэх"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Санал хүсэлт илгээх"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Хаах"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Дуу хаах"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Төхөөрөмжийг дахин эхлүүлэх хүртэл дууг нь хаах"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Хүлээх"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Апп-ыг хаах"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Зөвшөөрөл шаардахгүй"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Энэ таныг төлбөрт оруулж болзошгүй"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Тийм"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB цэнэглэгч"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Энэ төхөөрөмжийг USB цэнэглэж байна"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Залгасан төхөөрөмжөөс USB цэнэг авч байна"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файл шилжүүлэх USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Фото зураг шилжүүлэх USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ийн USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Нэмэлт сонголтыг харахын тулд дарна."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебагийг идэвхгүй болгох бол хүрнэ үү."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ЗӨВШӨӨРӨХ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ТАТГАЛЗАХ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Алдааны тайланг авч байна..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Алдааны тайланг хуваалцах уу?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Алдааны тайланг хуваалцаж байна..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Энэ төхөөрөмжийн асуудлыг шийдвэрлэхийн тулд таны IT админ алдааны тайланг хүслээ. Апп болон өгөгдлийг хуваалцсан байж болзошгүй."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ХУВААЛЦАХ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ТАТГАЛЗАХ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Гар сонгох"</string>
     <string name="show_ime" msgid="2506087537466597099">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
     <string name="hardware" msgid="194658061510127999">"Хийсвэр гарыг харуулах"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Гарын схемийг сонгох"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Гарын схемийг сонгох бол хүрнэ үү."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Биет гарыг хэлбэрт оруулах"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ханын зураг"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR сонсогч"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Нөхцөл нийлүүлэгч"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Мэдэгдлийн туслагч"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Мэдэгдлийг ангилах үйлчилгээ"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Нэмэлт сонголтууд"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Дотоод сан"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Дотоод хуваалцсан санах ой"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD карт"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD карт"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB диск"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Апп-ын хэмжээг өөрчлөх боломжгүй. Үүнийг 2 хуруугаар гүйлгэнэ үү."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Апп хуваагдсан дэлгэцэд ажиллахгүй."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Таны админ суулгасан байна"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Танай админ шинэчилсэн"</string>
@@ -1541,12 +1536,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> сонгосон</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> сонгосон</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Бусад"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g>-г <xliff:g id="ACCOUNT">%2$s</xliff:g>-р шинэ Хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g>-г <xliff:g id="ACCOUNT">%2$s</xliff:g>-р шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү (ийм бүртгэлтэй хэрэглэгч аль хэдийн байна) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Хэлний тохиргоо"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Хэл нэмэх"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Бүс нутгийн тохиргоо"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Улсын хэлийг бичнэ үү"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Санал болгосон"</string>
@@ -1555,8 +1549,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Ажлын горимыг УНТРААСАН байна"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Ажлын профайлд апп, дэвсгэр синхрончлол болон бусад холбоотой тохиргоог ажиллахыг зөвшөөрнө үү."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Асаах"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s идэвхгүй болгосон"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s админ идэвхгүй болгосон. Дэлгэрэнгүй мэдэхийн тулд тэдэнтэй холбоо барина уу."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Танд шинэ зурвасууд байна"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Үзэхийн тулд SMS аппыг нээх"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Зарим үйлдэл хязгаарлалттай байж болно"</string>
@@ -1569,4 +1561,7 @@
     <string name="pin_target" msgid="3052256031352291362">"PIN"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Энэ төхөөрөмжийг хязгаарлалтгүй ашиглахын тулд үйлдвэрийн тохиргоонд дахин тохируулна уу"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Дэлгэрэнгүй үзэх бол дарна уу."</string>
 </resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 1b1c7a8..8a3e564 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कॉलर ID डीफॉल्‍ट रूपात प्रतिबंधित नाही वर सेट असतो. पुढील कॉल: प्रतिबंधित नाही"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"सेवेची तरतूद केलेली नाही."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"आपण कॉलर ID सेटिंग बदलू शकत नाही."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"व्हॉइस सहाय्य"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"आता लॉक करा"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"धोरणाद्वारे सामग्री लपविली"</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="user_owner_label" msgid="1119010402169916617">"वैयक्तिकवर स्विच करा"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"कार्यावर स्विच करा"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"आपल्या संपर्कांवर प्रवेश"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s सह संपादित करा"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"यांच्यासह सामायिक करा"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s सह सामायिक करा"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"वापरून पाठवा"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s वापरून पाठवा"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"मुख्‍यपृष्‍ठ अ‍ॅप निवडा"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"मुख्यपृष्ठ म्हणून %1$s वापरा"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"या क्रियेसाठी डीफॉल्‍टनुसार वापरा."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"अॅप रीसेट आणि रीस्टार्ट करा"</string>
     <string name="aerr_report" msgid="5371800241488400617">"अभिप्राय पाठवा"</string>
     <string name="aerr_close" msgid="2991640326563991340">"बंद करा"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"नि:शब्द करा"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"डिव्हाइस रीस्टार्ट होईपर्यंत नि:शब्द करा"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"प्रतीक्षा करा"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"अॅप बंद करा"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"परवानग्या आवश्यक नाहीत"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"यासाठी आपले पैसे खर्च होऊ शकतात"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ठीक"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जिंगसाठी USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB हे डिव्हाइस चार्ज करीत आहे"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB संलग्न केलेल्या डिव्हाइसला पॉवरचा पुरवठा करीत आहे"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"स्थानांतरणासाठी USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"फोटो स्थानांतरणासाठी USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI साठी USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"अधिक पर्यायांसाठी स्पर्श करा."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग करणे कनेक्‍ट केले"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करणे अक्षम करण्यासाठी स्पर्श करा."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करा"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"नकार द्या"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"दोष अहवाल घेत आहे..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग अहवाल सामायिक करायचा?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"दोष अहवाल सामायिक करीत आहे..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"आपल्या IT प्रशासकाने या डिव्हाइसच्या समस्येचे निवारण करण्यात मदत करण्यासाठी दोष अहवालाची विनंती केली. अॅप्स आणि डेटा सामायिक केले जाऊ शकतात."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"सामायिक करा"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"नकार द्या"</string>
     <string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदला"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड निवडा"</string>
     <string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
     <string name="hardware" msgid="194658061510127999">"व्हर्च्युअल कीबोर्ड दर्शवा"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"कीबोर्ड लेआउट निवडा"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"कीबोर्ड लेआउट निवडण्यासाठी स्पर्श करा."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"वास्तविक कीबोर्ड कॉन्फिगर करा"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदला"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना ऐकणारा"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR श्रोता"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"अट प्रदाता"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहाय्यक"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"सूचना रॅंकर सेवा"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> द्वारे VPN सक्रिय केले आहे"</string>
     <string name="vpn_text" msgid="3011306607126450322">"नेटवर्क व्यवस्थापित करण्यासाठी स्पर्श करा."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"अधिक पर्याय"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"अंतर्गत संचयन"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"अंतर्गत सामायिक केलेला संचय"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD कार्ड"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD कार्ड"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ड्राइव्‍ह"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करण्‍यापूर्वी पिन साठी विचारा"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"अनपिन करण्‍यापूर्वी अनलॉक नमुन्यासाठी विचारा"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"अनपिन करण्‍यापूर्वी संकेतशब्दासाठी विचारा"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"अॅपचा आकार बदलण्यायोग्य नाही, दोन बोटांनी तो स्क्रोल करा."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"अॅप कदाचित विभाजित-स्क्रीनसह कार्य करू शकत नाही."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"अॅप स्क्रीन-विभाजनास समर्थन देत नाही."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"आपल्या प्रशासकाद्वारे स्थापित केले आहे"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"आपल्या प्रशासकाद्वारे अद्यतनित केले"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडला</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"संकीर्ण"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"आपण या सूचनांचे महत्त्व सेट केले."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"आपण या सूचनांचे महत्त्व सेट केले."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"सामील असलेल्या लोकांमुळे हे महत्वाचे आहे."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची (हे खाते असलेला वापरकर्ता आधीपासून विद्यमान आहे) <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"भाषा प्राधान्य"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"एक भाषा जोडा"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"प्रदेश प्राधान्य"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"भाषा नाव टाइप करा"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सूचित केलेले"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद आहे"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"कार्य प्रोफाइलला अॅप्स, पार्श्वभूमी संकालन आणि संबंधित वैशिष्ट्यांच्या समावेशासह कार्य करण्याची परवानगी द्या."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"चालू करा"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s अक्षम केले"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s प्रशासकाद्वारे अक्षम केले. अधिक जाणून घेण्‍यासाठी त्यांच्याशी संपर्क साधा."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"आपल्याकडे नवीन संदेश आहेत"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"पाहण्‍यासाठी SMS अॅप उघडा"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"काही कार्यक्षमता मर्यादित असू शकतात"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"पिन"</string>
     <string name="unpin_target" msgid="3556545602439143442">"अनपिन करा"</string>
     <string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"हे डिव्हाइस निर्बंधांशिवाय वापरण्यासाठी फॅक्टरी रीसेट करा"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जाणून घेण्यासाठी स्पर्श करा."</string>
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index f174b7c..5db9c77 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID pemanggil secara lalainya ditetapkan kepada tidak dihadkan. Panggilan seterusnya: Tidak terhad"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Perkhidmatan yang tidak diuntukkan."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Anda tidak boleh mengubah tetapan ID pemanggil."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Akses terhad diubah"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Perkhidmatan data disekat."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Perkhidmatan kecemasan disekat."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Perkhidmatan suara disekat."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Kandungan disembunyikan oleh dasar"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Tempat Kerja"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Beralih kepada Peribadi"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Beralih kepada Kerja"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kenalan"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kenalan anda"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Kongsi dengan"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Kongsi dengan %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Hantar menggunakan"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Hantar menggunakan %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Pilih apl Laman Utama"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Gunakan %1$s sebagai Laman Utama"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Gunakannya secara lalai untuk tindakan ini."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Tetapkan semula dan mulakan semula apl"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Hantar maklum balas"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Tutup"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Redam"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Redam sehingga peranti dimulakan semula"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Tunggu"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Tutup apl"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Tiada kebenaran diperlukan"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"anda mungkin dikenakan bayaran"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB untuk pengecasan"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Mengecas peranti ini melalui USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Membekalkan kuasa kepada peranti tersambung melalui USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB untuk pemindahan fail"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB untuk pemindahan foto"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Sentuh untuk mendapatkan lagi pilihan."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Penyahpepijatan USB disambungkan"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk melumpuhkan penyahpepijatan USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TERIMA"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan pepijat…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kongsi laporan pepijat?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Berkongsi laporan pepijat…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah peranti ini. Apl dan data mungkin dikongsi."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"KONGSI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Tukar papan kekunci"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Pilih papan kekunci"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
     <string name="hardware" msgid="194658061510127999">"Tunjukkan papan kekunci maya"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih susun atur papan kekunci"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih susun atur papan kekunci."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurasikan papan kekunci fizikal"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Pendengar VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Pembekal keadaan"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pembantu pemberitahuan"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Perkhidmatan penentu kedudukan pemberitahuan"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Lagi pilihan"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Storan dalaman"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Storan kongsi dalaman"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kad SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Kad SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Pemacu USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Minta corak buka kunci sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Minta kata laluan sebelum menyahsemat"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Apl tidak boleh ditukar saiznya, tatal apl itu menggunakan dua jari."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Apl mungkin tidak berfungsi dengan skrin pisah."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Apl tidak menyokong skrin pisah."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Dipasang oleh pentadbir anda"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Pelbagai"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Anda menetapkan kepentingan pemberitahuan ini."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Anda menetapkan kepentingan pemberitahuan ini."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Mesej ini penting disebabkan orang yang terlibat."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akaun ini sudah wujud)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Pilihan bahasa"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Tambahkan bahasa"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Pilihan wilayah"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Taipkan nama bahasa"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Dicadangkan"</string>
@@ -1557,11 +1551,9 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mod kerja DIMATIKAN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Benarkan profil kerja berfungsi, termasuk apl, penyegerakan latar belakang dan ciri yang berkaitan."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Hidupkan"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s dilumpuhkan"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Dilumpuhkan oleh pentadbir %1$s. Hubungi mereka untuk mengetahui lebih lanjut."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Anda mempunyai mesej baharu"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Buka apl SMS untuk melihat"</string>
-    <string name="user_encrypted_title" msgid="9054897468831672082">"Beberapa fungsi mungkin terhad"</string>
+    <string name="user_encrypted_title" msgid="9054897468831672082">"Sesetengah fungsi mungkin terhad"</string>
     <string name="user_encrypted_message" msgid="4923292604515744267">"Ketik untuk membuka kunci"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"Data pengguna dikunci"</string>
     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil kerja dikunci"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Semat"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Nyahsemat"</string>
     <string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Lakukan tetapan semula kilang untuk menggunakan peranti ini tanpa sekatan"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ketik untuk mengetahui lebih lanjut."</string>
 </resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 6fe0c88..5e5ec4e 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ပုံသေအားဖြင့် ခေါ်ဆိုသူအိုင်ဒီ(Caller ID)အား ကန့်သတ်မထားပါ။ နောက်ထပ်အဝင်ခေါ်ဆိုမှု-ကန့်သတ်မထားပါ။"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"ဝန်ဆောင်မှုအား ကန့်သတ်မထားပါ"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"သင်သည် ခေါ်ဆိုသူ ID ဆက်တင်ကို မပြောင်းလဲနိုင်ပါ။"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"အသံ အကူအညီ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ယခု သော့ပိတ်ရန်"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"၉၉၉+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"မူဝါဒမှ အကြောင်းအရာများကို ဝှက်ထားသည်"</string>
     <string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</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="user_owner_label" msgid="1119010402169916617">"ကိုယ်ပိုင်သီးသန့်အဖြစ် ပြောင်းပါ"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"အလုပ်သို့ ပြောင်းပါ"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"အဆက်အသွယ်များ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"သင့် အဆက်အသွယ်များအား ဝင်ရောက်သုံးရန်"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s နှင့် တည်းဖြတ်ရန်"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"...နှင့် မျှဝေရန်"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$sနှင့် မျှဝေရန်"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ကိုအသုံးပြု၍ ပို့ပါ"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ကိုအသုံးပြု၍ ပို့ပါ"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"ပင်မ appကို ရွေးပါ"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$sကို ပင်မအဖြစ် သုံးပါ"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ဤလှုပ်ရှားမှုအတွက် မူရင်းအတိုင်း အသုံးပြုပါ။"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"အက်ပ်ကို ပြန်လည်ပြင်ဆင်သတ်မှတ်ပြီး ပြန်လည်စတင်ပါ"</string>
     <string name="aerr_report" msgid="5371800241488400617">"တုံ့ပြန်ချက်ပို့ပါ"</string>
     <string name="aerr_close" msgid="2991640326563991340">"ပိတ်ပါ"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"အသံတိတ်ပါ"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"စက်ပစ္စည်း ပြန်လည်စတင်သည့်တိုင် အသံတိတ်ပါ"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"စောင့်ပါ"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"အက်ပ်ကိုပိတ်ပါ"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ခွင့်ပြုချက်မလိုအပ်ပါ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"သင့်အတွက် ပိုက်ဆံကုန်ကျနိုင်ပါသည်"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ကောင်းပြီ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"အားသွင်းရန်အတွက် USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB ဖြင့်ဤစက်ပစ္စည်းကို အားသွင်းနေသည်"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ချိတ်ဆက်ထားသည့် စက်ပစ္စည်းကို USB မှတစ်ဆင့် အားသွင်းနေသည်"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ဖိုင်လွှဲပြောင်းရန်အတွက် USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ဓာတ်ပုံလွှဲပြောင်းရန်အတွက် USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI အတွက် USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"ထပ်မံရွေးချယ်စရာများအတွက် ထိပါ"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB အမှားစစ်ခြင်းအား ချိတ်ဆက်ထားသည်"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ဒီဘာဂင် ပိတ်ရန် ထိပါ။"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"လက်ခံပါ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ငြင်းပယ်ပါ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ချွတ်ယွင်းချက် အစီရင်ခံစာပြုစုနေသည်..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို မျှဝေမလား။"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ချွတ်ယွင်းမှုအစီရင်ခံစာ မျှဝေနေသည်…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ဤစက်ပစ္စည်းကို ပြဿနာအဖြေရှာရာတွင် ကူညီရန် သင့်အိုင်တီစီမံခန့်ခွဲသူသည် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုထားသည်။ အက်ပ်များနှင့် ဒေတာကိုမျှဝေထားနိုင်ပါသည်။"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"မျှဝေပါ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ငြင်းပယ်ပါ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ကီးဘုတ် ပြောင်းလဲရန်"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"ကီးဘုတ်များကို ရွေးရန်"</string>
     <string name="show_ime" msgid="2506087537466597099">"စက်၏ကီးဘုတ်ကိုအသုံးပြုနေစဉ် ၎င်းကိုမျက်နှာပြင်ပေါ်တွင် ထားပါ"</string>
     <string name="hardware" msgid="194658061510127999">"ကီးဘုတ်အတုပြရန်"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"လက်ကွက် အပြင်အဆင်ရွေးရန်"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"လက်ကွက် အပြင်အဆင်ရွေးရန် တို့ထိပါ"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ရုပ်ပိုင်းဆိုင်ရာ အသွင်အပြင်ကို ပြင်ဆင်သတ်မှတ်ပါ"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"နောက်ခံ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"နောက်ခံပြောင်းခြင်း"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"အကြောင်းကြားချက် နားတောင်သူ"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR နားထောင်မှုစနစ်"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"အခြေအနေ စီမံပေးသူ"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"သတိပေးချက် အကူ"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"သတိပေးချက် အဆင့်သတ်မှတ်ခြင်းဝန်ဆောင်မှု"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN ဖွင့်ထားပါသည်"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>မှVPNအလုပ်လုပ်နေသည်"</string>
     <string name="vpn_text" msgid="3011306607126450322">"ကွန်ရက် ထိန်းသိမ်းရန် တို့ထိပါ"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ပိုမိုရွေးချယ်စရာများ"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s ၊ %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s ၊ %2$s ၊ %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"စက်တွင်း သိုလှောင်ထားမှု"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"စက်တွင်းမျှဝေထားသည့် သိုလှောင်ခန်း"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD ကဒ်"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD ကဒ်"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ဒရိုက်ဗ်"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ပင်မဖြုတ်မီမှာ သော့ဖွင့် ရေးဆွဲမှုပုံစံကို မေးကြည့်ရန်"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ပင်မဖြုတ်မီမှာ စကားဝှက်ကို မေးကြည့်ရန်"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"အက်ပ်ကို အရွယ်အစားချိန်၍မရပါ၊ လက်ချောင်းနှစ်ချောင်းဖြင့် အပေါ်အောက်ဆွဲပါ။"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"မျက်နှာပြင် ခွဲခြမ်းပြသမှုဖြင့် အက်ပ်သည် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"သင့် အက်ဒမင်မှ သွင်းယူထား၏"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"သင့်စီမံခန့်ခွဲသူမှ အဆင့်မြှင့်ထားပါသည်။"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"အထွေထွေ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ဤအသိပေးချက်များ၏ အရေးပါမှုကိုသင်သတ်မှတ်ပြီးပါပြီ။"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ဤသတိပေးချက်များ၏ အရေးပါမှုကိုသတ်မှတ်ပြီးပါပြီ။"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ကို <xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ဖန်တီးခွင့်ပြုမလား။"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> ကို <xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ် ဖန်တီးခွင့်ပြုမလား (ဤအကောင့်ဖြင့် အသုံးပြုသူ ရှိနှင့်ပြီးဖြစ်သည်)။"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ဘာသာစကားရွေးချယ်မှု"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ဘာသာစကားတစ်ခု ထည့်ပါ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ဒေသရွေးချယ်မှု"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ဘာသာစကားအမည် ထည့်ပါ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"အကြံပြုထားသော"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"အလုပ်မုဒ် ပိတ်ထားသည်"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"အက်ပ်များ၊ နောက်ခံစင့်ခ်လုပ်ခြင်း၊ နှင့်သက်ဆိုင်သည့်အင်္ဂါရပ်များကို ဆောင်ရွက်ရန် အလုပ်ပရိုဖိုင်ကိုခွင့်ပြုပါ။"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ဖွင့်ပါ"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s ကိုပိတ်ထားသည်"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်။ ပိုမိုလေ့လာရန် ၎င်းတို့ကိုဆက်သွယ်ပါ။"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"သင့်ထံတွင် စာအသစ်များရောက်နေသည်"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"ကြည့်ရှုရန် SMS အက်ပ်ကိုဖွင့်ပါ"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"အချို့လုပ်ဆောင်ချက်များ ကန့်သတ်ချက်ရှိနိုင်သည်"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"တွဲပါ"</string>
     <string name="unpin_target" msgid="3556545602439143442">"ဖြုတ်ပါ"</string>
     <string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"ဤစက်ပစ္စည်းကို ကန့်သတ်ချက်များမပါဘဲ အသုံးပြုရန် စက်ရုံထုတ်ဆက်တင်အတိုင်း ပြန်လည်သတ်မှတ်ပါ"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ပိုမိုလေ့လာရန် တို့ပါ။"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 3c7bfe3..cfccdeb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Du kan ikke endre innstillingen for anrops-ID."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Tilgangsbegrensning endret"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjenesten er blokkert."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjenesten er blokkert."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Taletjenesten er blokkert."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Talehjelp"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nå"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innholdet er skjult i henhold til retningslinjene"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Jobb"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Bytt til den personlige profilen"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Bytt til jobbprofilen"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"se kontaktene dine"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Posisjon"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Del med"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Del med %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Send via"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Send via %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Velg en startsideapp"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Bruk %1$s som startside"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Bruk som standardvalg."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Tilbakestill appen, og start den på nytt"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Send tilbakemelding"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Lukk"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorer"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignorer frem til enheten starter på nytt"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Vent"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Lukk app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste deg penger"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for lading"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Enheten lades via USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Den tilkoblede enheten får strøm via USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for filoverføring"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for bildeoverføring"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Trykk for å se flere alternativer."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-feilsøking tilkoblet"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Trykk for å slå av USB-feilsøking."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"GODTA"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AVSLÅ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kjører feilrapport …"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele feilrapporten?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler feilrapporten …"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT-administratoren har bedt om en feilrapport for å hjelpe med feilsøkingen på denne enheten. Apper og data kan bli delt."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVSLÅ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Endre tastatur"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Velg tastatur"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
     <string name="hardware" msgid="194658061510127999">"Vis det virtuelle tastaturet"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Velg tastaturoppsett"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Trykk for å velge et tastaturoppsett"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurer et fysisk tastatur"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyttetjeneste for virtuell virkelighet"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Betingelsesleverandør"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Varselassistent"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste for rangering av varsler"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere alternativer"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s – %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s – %2$s – %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Intern lagring"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Delt internlagring"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD-kort"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-stasjon"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-kode for å løsne apper"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Krev bruk av opplåsningsmønster for å løsne apper"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Krev passord for å løsne apper"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Du kan ikke endre størrelse på appen – rull med to fingre."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Det kan hende at appen ikke fungerer med delt skjerm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen støtter ikke delt skjerm."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Installert av administratoren"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Oppdatert av administratoren"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> er valgt</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Du angir viktigheten for disse varslene."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Du angir viktigheten for disse varslene."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er viktig på grunn av folkene som er involvert."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Det finnes allerede en bruker med denne kontoen.)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Språkinnstilling"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Legg til et språk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regionsinnstilling"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Skriv inn språknavn"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslått"</string>
@@ -1557,10 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Jobbmodus er AV"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Slå på jobbprofilen, inkludert apper, synkronisering i bakgrunnen og relaterte funksjoner."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Slå på"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s er slått av"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for suspended_package_message (6341091587106868601) -->
-    <skip />
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nye meldinger"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Åpne SMS-appen for å se"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Enkelte funksjoner kan være begrenset"</string>
@@ -1573,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fest"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Løsne"</string>
     <string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Tilbakestill til fabrikkstandard for å bruke denne enheten uten begrensninger"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Trykk for å finne ut mer."</string>
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 3379af7..fb817b5 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कलर ID पूर्वनिर्धारितको लागि रोकावट छैन। अर्को कल: रोकावट छैन"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"सेवाको व्यवस्था छैन।"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"तपाईँ कलर ID सेटिङ परिवर्तन गर्न सक्नुहुन्न।"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज सहायता"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"अब बन्द गर्नुहोस्"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"९९९+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"नीतिद्वारा लुकाइएका सामग्री"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"काम"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफाइलमा स्विच गर्नुहोस्"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"कार्य प्रोफाइलमा स्विच गर्नुहोस्"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"सम्पर्कहरू"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"तपाईँको सम्पर्कमा पहुँच गर्नुहोस्"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -907,6 +905,8 @@
     <skip />
     <string name="whichSendApplication" msgid="6902512414057341668">"साझेदारी गर्नुहोस्..."</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s सँग साझेदारी गर्नुहोस्"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"यसको प्रयोग गरी पठाउनुहोस्"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s को प्रयोग गरी पठाउनुहोस्"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"गृह अनुप्रयोग चयन गर्नुहोस्"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s लाई गृहको रूपमा प्रयोग गर्नुहोस्"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"यस कार्यको लागि पूर्वनिर्धारितबाट प्रयोग गर्नुहोस्।"</string>
@@ -923,7 +923,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"अनुप्रयोगलाई रिसेट गरी पुन: सुरु गर्नुहोस्"</string>
     <string name="aerr_report" msgid="5371800241488400617">"प्रतिक्रिया पठाउनुहोस्"</string>
     <string name="aerr_close" msgid="2991640326563991340">"बन्द गर्नुहोस्"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"म्यूट गर्नुहोस्"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"यन्त्र पुनः सुरु नभएसम्म म्यूट गर्नुहोस्"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"पर्खनुहोस्"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"अनुप्रयोग बन्द गर्नुहोस्"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1051,7 +1051,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"कुनै अनुमति आवश्यक छैन"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"सायद तपाईँलाई पैसा पर्न सक्छ।"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ठिक छ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जका लागि USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"यस यन्त्रलाई USB मार्फत चार्ज गर्दै"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"संलग्न गरिएको यन्त्रमा USB मार्फत पावर आपूर्ति गरिँदै"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"फाइल स्थानान्तरणको लागि USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"तस्बिर स्थानान्तरणको लागि USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI को लागि USB"</string>
@@ -1059,24 +1060,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"थप विकल्पहरूका लागि छुनुहोस्।"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने जडित छ"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB डिबग गर्ने असक्षम पार्न छुनुहोस्।"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार गर्नुहोस्"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार गर्नुहोस्"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट लिँदै..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्टलाई साझेदारी गर्ने हो?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्टलाई साझेदारी गर्दै ..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"तपाईँको IT प्रशासकले यस यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टका लागि अनुरोध गर्नुभएको छ। अनुप्रयोग र डेटा साझेदारी हुन सक्छ।"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझेदारी गर्नुहोस्"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार गर्नुहोस्"</string>
     <string name="select_input_method" msgid="8547250819326693584">"कुञ्जीपाटी परिवर्तन गर्नुहोस्"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड छान्नुहोस्"</string>
     <string name="show_ime" msgid="2506087537466597099">"भौतिक किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राख्नुहोस्"</string>
     <string name="hardware" msgid="194658061510127999">"भर्चुअल किबोर्ड देखाउनुहोस्"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"किबोर्ड रूपरेखा चयन गर्नुहोस्"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"किबोर्ड रूपरेखा चयन गर्न टच गर्नुहोस्।"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"फिजिकल किबोर्डलाई कन्फिगर गर्नुहोस्"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string>
@@ -1149,8 +1143,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"वालपेपर"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वालपेपर परिवर्तन गर्नुहोस्"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना सुन्नेवाला"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR श्रोता"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"सर्त प्रदायक"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहायक"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"सूचनालाई श्रेणी प्रदान गर्ने सेवा"</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>
@@ -1235,7 +1230,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"थप विकल्पहरू"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"आन्तरिक भण्डारण"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"साझेदारी गरिएको आन्तरिक भण्डारण"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD कार्ड"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD कार्ड"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ड्राइभ"</string>
@@ -1479,7 +1474,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"पिन निकाल्नुअघि खोल्ने रूपरेखा सोध्नुहोस्"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"अनुप्रयोगको आकार सानो-ठूलो बनाउन मिल्दैन, दुई औँलाले यसलाई स्क्रोल गर्नुहोस्।"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"अनुप्रयोगले विभाजित-स्क्रिनमा काम नगर्न सक्छ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"तपाईँको प्रशासकद्वारा स्थापना गरिएको"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"तपाईँको प्रशासकद्वारा अद्यावधिक गरिएको"</string>
@@ -1549,12 +1544,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयन गरियो</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> चयन गरियो</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहुन्छ।"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहोस् ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने (यस खाताको प्रयोगकर्ता पहिले नै अवस्थित छ) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"भाषाको प्राथमिकता"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"भाषा थप्नुहोस्"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"क्षेत्रको प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"भाषाको नाम टाइप गर्नुहोस्"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाव दिइयो"</string>
@@ -1563,18 +1557,19 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बन्द छ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"अनुप्रयोग, पृष्ठभूमि सिंक र सम्बन्धित विशेषताहरू सहित, कार्य प्रोफाइललाई कार्य गर्न अनुमति दिनुहोस्।"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"सक्रिय गर्नुहोस्"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s असक्षम भयो"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s प्रशासकद्वारा असक्षम गरिएको। थप जान्नका लागि तिनीहरूलाई सम्पर्क गर्नुहोस्।"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"तपाईंलाई नयाँ सन्देश आएको छ"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"हेर्नका लागि SMS अनुप्रयोग खोल्नुहोस्"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"केही कार्य सीमित हुनसक्छ"</string>
     <string name="user_encrypted_message" msgid="4923292604515744267">"अनलक गर्न ट्याप गर्नुहोस्"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"प्रयोगकर्ताको डेटा लक गरियो"</string>
-    <string name="profile_encrypted_detail" msgid="3700965619978314974">"कार्य प्रोफाइल बन्द भयो"</string>
+    <string name="profile_encrypted_detail" msgid="3700965619978314974">"कार्य प्रोफाइल लक भयो"</string>
     <string name="profile_encrypted_message" msgid="6964994232310195874">"कार्य प्रोफाइल अनलक गर्न ट्याप गर्नुहोस्"</string>
     <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> मा जडान गरिएको छ"</string>
     <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"फाइलहरू हेर्न ट्याप गर्नुहोस्"</string>
     <string name="pin_target" msgid="3052256031352291362">"पिन गर्नुहोस्"</string>
     <string name="unpin_target" msgid="3556545602439143442">"अनपिन गर्नुहोस्"</string>
     <string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"यस यन्त्रलाई सीमितताहरू बिना प्रयोग गर्नका लागि फ्याक्ट्री रिसेट गर्नुहोस्"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"थप जान्नका लागि छुनुहोस्।"</string>
 </resources>
diff --git a/core/res/res/values-night/themes_material_daynight.xml b/core/res/res/values-night/themes_material_daynight.xml
deleted file mode 100644
index b344582..0000000
--- a/core/res/res/values-night/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!--
-===============================================================
-                        PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
-                        PLEASE READ
-===============================================================
- -->
-<resources>
-
-    <!-- Material theme (day/night version) for activities. -->
-    <style name="Theme.Material.DayNight" parent="Theme.Material" />
-
-    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
-         with an inverse color profile. The dark action bar sharply stands out against
-         the light content (when applicable).  -->
-    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material" />
-
-    <!-- Variant of Material.DayNight with no action bar.  -->
-    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.NoActionBar" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen. This theme
-         sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen and extends into the display overscan region. This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
-
-    <!-- Variant of Material.DayNight that has no title bar and translucent
-         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
-         {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
-
-    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
-         to place your content. It makes the window floating, with a transparent
-         background, and turns off dimming behind the window. -->
-    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Panel" />
-
-    <!-- Material theme (day/night version) for dialog windows and activities,
-         which is used by the {@link android.app.Dialog} class. This changes
-         the window to be floating (not fill the entire screen), and puts a
-         frame around its contents. You can set this theme on an activity if
-         you would like to make an activity that looks like a Dialog. -->
-    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
-    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.BaseDialog" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Dialog.FixedSize" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Dialog.NoActionBar.FixedSize" />
-
-    <!-- Theme for a window that will be displayed either full-screen on
-         smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
-
-    <!-- Theme for a window with a dark action bar that will be displayed
-         either full-screen on smaller screens (small, normal) or as a dialog
-         on larger screens (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.DialogWhenLarge" />
-
-    <!-- Theme for a window without an action bar that will be displayed either full-screen
-         on smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
-
-    <!-- Theme for a presentation window on a secondary display. -->
-    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
-
-    <!-- Material user theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class. -->
-    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
-    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Dialog.BaseAlert" />
-
-    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.SearchBar" />
-    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ad987a2..3de8496 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt."</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Service niet voorzien."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"U kunt de instelling voor de beller-id niet wijzigen."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Beperkte toegang gewijzigd"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Gegevensservice is geblokkeerd."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Alarmservice is geblokkeerd."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Spraakservice is geblokkeerd."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persoonlijk"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Overschakelen naar persoonlijk profiel"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Overschakelen naar werkprofiel"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacten"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"toegang krijgen tot je contacten"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Locatie"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Bewerken met %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Delen met"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Delen met %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Verzenden met"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Verzenden met %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Een startschermapp selecteren"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s gebruiken voor startscherm"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Standaard gebruiken voor deze actie."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"App resetten en opnieuw starten"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Feedback verzenden"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Sluiten"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Negeren"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Verbergen tot apparaat opnieuw wordt opgestart"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Wachten"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"App sluiten"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"hieraan kunnen kosten zijn verbonden"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB voor opladen"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dit apparaat wordt opgeladen via USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Het aangesloten apparaat wordt via USB van voeding voorzien"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB voor bestandsoverdacht"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB voor foto-overdracht"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB voor MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Tik voor meer opties."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tik om USB-foutopsporing uit te schakelen."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTEREN"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIGEREN"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Bugrapport genereren…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bugrapport delen?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bugrapport delen…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Je IT-beheerder heeft een bugrapport aangevraagd om problemen met dit apparaat op te lossen. Apps en gegevens kunnen worden gedeeld."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELEN"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIGEREN"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Toetsenbord wijzigen"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Toetsenborden kiezen"</string>
     <string name="show_ime" msgid="2506087537466597099">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string>
     <string name="hardware" msgid="194658061510127999">"Virtueel toetsenbord tonen"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Toetsenbordindeling selecteren"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tik om een ​​toetsenbordindeling te selecteren."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fysiek toetsenbord configureren"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-listener"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider van voorwaarden"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Meldingsassistent"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Rangschikkingsservice voor meldingen"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Meer opties"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interne opslag"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Interne gedeelde opslag"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD-kaart"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-drive"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vraag pin voor losmaken"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vraag patroon voor losmaken"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vraag wachtwoord voor losmaken"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Formaat van app kan niet worden aangepast, scrol met twee vingers."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"App werkt mogelijk niet met gesplitst scherm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App biedt geen ondersteuning voor gesplitst scherm."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Geïnstalleerd door je beheerder"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Geüpdatet door je beheerder"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> geselecteerd</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> geselecteerd</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diversen"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Je stelt het belang van deze meldingen in."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Je stelt het belang van deze meldingen in."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrijk vanwege de betrokken mensen."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt (er is al een gebruiker met dit account)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Taalvoorkeur"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Een taal toevoegen"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regiovoorkeur"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Typ een taalnaam"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgesteld"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is UIT"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Functioneren van werkprofiel toestaan, waaronder apps, synchronisatie op de achtergrond en gerelateerde functies."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Inschakelen"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s is uitgeschakeld"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Uitgeschakeld door de beheerder van %1$s. Neem voor meer informatie contact op met de beheerder."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Je hebt nieuwe berichten"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Open je sms-app om ze te bekijken"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Bepaalde functionaliteit kan zijn beperkt"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Vastzetten"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Losmaken"</string>
     <string name="app_info" msgid="6856026610594615344">"App-info"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Zet dit apparaat terug op de fabrieksinstellingen om het zonder beperkingen te gebruiken"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tik voor meer informatie."</string>
 </resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index be6ddde..87f973f 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ਪ੍ਰਤਿਬੰਧਿਤ ਨਾ ਕਰਨ ਲਈ ਕਾਲਰ ID ਡਿਫੌਲਟਸ। ਅਗਲੀ ਕਾਲ: ਪ੍ਰਤਿਬੰਧਿਤ ਨਹੀਂ"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"ਸੇਵਾ ਪ੍ਰਬੰਧਿਤ ਨਹੀਂ ਹੈ।"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"ਤੁਸੀਂ ਕਾਲਰ ID ਸੈਟਿੰਗ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"ਵੌਇਸ ਅਸਿਸਟ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ਹੁਣ ਲੌਕ ਕਰੋ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ਸਮੱਗਰੀਆਂ ਲੁਕਾਈਆਂ ਗਈਆਂ"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ਨੀਤੀ ਦੁਆਰਾ ਸਮੱਗਰੀ ਲੁਕਾਈ ਗਈ"</string>
     <string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ਨਿੱਜੀ"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"ਕੰਮ"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"ਨਿੱਜੀ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"ਕੰਮ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ਸੰਪਰਕ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਨੂੰ ਐਕਸੈਸ ਕਰੋ"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ਨਾਲ ਸੰਪਾਦਿਤ ਕਰੋ"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"ਇਸ ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ਇਸ ਦੀ ਵਰਤੋਂ ਨਾਲ ਭੇਜੋ"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ਦੀ ਵਰਤੋਂ ਨਾਲ ਭੇਜੋ"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"ਇੱਕ ਹੋਮ ਐਪ ਚੁਣੋ"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ਘਰ ਦੇ ਤੌਰ ਤੇ %1$s ਨੂੰ ਵਰਤੋ"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ਇਸ ਕਿਰਿਆ ਲਈ ਬਾਇ ਡਿਫੌਲਟ ਵਰਤੋ।"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ਐਪ ਨੂੰ ਰੀਸੈੱਟ ਅਤੇ ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ਪ੍ਰਤੀਕਰਮ ਭੇਜੋ"</string>
     <string name="aerr_close" msgid="2991640326563991340">"ਬੰਦ ਕਰੋ"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"ਮਿਊਟ ਕਰੋ"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ ਤੱਕ ਮਿਊਟ ਕਰੋ"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"ਉਡੀਕ ਕਰੋ"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ਐਪ ਬੰਦ ਕਰੋ"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ਕੋਈ ਅਨੁਮਤੀਆਂ ਲੁੜੀਂਦੀਆਂ ਨਹੀਂ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ਇਸ ਨਾਲ ਤੁਹਾਨੂੰ ਖ਼ਰਚਾ ਪੈ ਸਕਦਾ ਹੈ"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ਠੀਕ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ਚਾਰਜਿੰਗ ਲਈ USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ਇਹ ਡੀਵਾਈਸ USB ਰਾਹੀਂ ਚਾਰਜ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ਨੱਥੀ ਕੀਤੀ ਡੀਵਾਈਸ ਨੂੰ USB ਰਾਹੀਂ ਪਾਵਰ ਮਿਲ ਰਹੀ ਹੈ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ਫ਼ਾਈਲ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ਫੋਟੋ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ਲਈ USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ਡੀਬਗਿੰਗ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਉਣ ਲਈ ਛੋਹਵੋ।"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ਸਵੀਕਾਰ ਕਰੋ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ਬੱਗ ਰਿਪਰੋਟ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ਕੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱੱਚ ਮਦਦ ਲਈ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ। ਐਪਾਂ ਅਤੇ ਡੈਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ਸਾਂਝੀ ਕਰੋ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ਕੀਬੋਰਡ ਬਦਲੋ"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"ਕੀਬੋਰਡਸ ਚੁਣੋ"</string>
     <string name="show_ime" msgid="2506087537466597099">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
     <string name="hardware" msgid="194658061510127999">"ਵਰਚੁਅਲ ਕੀ-ਬੋਰਡ ਵਿਖਾਓ"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ਕੀਬੋਰਡ ਲੇਆਊਟ ਚੁਣੋ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ਇੱਕ ਕੀਬੋਰਡ ਲੇਆਊਟ ਚੁਣਨ ਲਈ ਛੋਹਵੋ।"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ਵਾਲਪੇਪਰ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ਵਾਲਪੇਪਰ ਬਦਲੋ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ਸੂਚਨਾ ਸੁਣਨ ਵਾਲਾ"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR ਸਰੋਤਾ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ਸਥਿਤੀ ਪ੍ਰਦਾਤਾ"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ਸੂਚਨਾ ਸਹਾਇਕ"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"ਸੂਚਨਾ ਰੈਂਕਰ ਸੇਵਾ"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ਹੋਰ ਚੋਣਾਂ"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"ਅੰਦਰੂਨੀ ਸਟੋਰੇਜ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"ਅੰਦਰੂਨੀ ਸਾਂਝੀ ਕੀਤੀ ਗਈ ਸਟੋਰੇਜ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD ਕਾਰਡ"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD ਕਾਰਡ"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ਡ੍ਰਾਇਵ"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ਅਨਪਿਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ PIN ਮੰਗੋ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ਅਨਪਿਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪੈਟਰਨ ਅਨਲੌਕ ਕਰਨ ਲਈ ਪੁੱਛੋ"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ਅਨਪਿਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪਾਸਵਰਡ ਮੰਗੋ"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ਐਪ ਦਾ ਆਕਾਰ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ, ਇਸ ਨੂੰ ਦੋ ਉਂਗਲਾਂ ਨਾਲ ਸਕਰੋਲ ਕਰੋ।"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"ਤੁਹਾਡੇ ਪ੍ਰਬੰਧਕ ਵੱਲੋਂ ਇੰਸਟੌਲ ਕੀਤਾ ਗਿਆ"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"ਵਿਵਿਧ"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ਇਹ ਸ਼ਾਮਲ ਲੋਕਾਂ ਦੇ ਕਾਰਨ ਮਹੱਤਵਪੂਰਨ ਹੈ।"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਮਨਜ਼ੂਰੀ ਦੇਣੀ ਹੈ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਮਨਜ਼ੂਰੀ ਦੇਣੀ ਹੈ (ਇਸ ਖਾਤੇ ਨਾਲ ਇੱਕ ਵਰਤੋਂਕਾਰ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ਭਾਸ਼ਾ ਤਰਜੀਹ"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ਇੱਕ ਭਾਸ਼ਾ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ਖੇਤਰ ਤਰਜੀਹ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ਭਾਸ਼ਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"ਕੰਮ ਮੋਡ ਬੰਦ ਹੈ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ਐਪਾਂ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਮਕਾਲੀਕਰਨ, ਅਤੇ ਸਬੰਧਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋਏ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਕੰਮ ਕਰਨ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ।"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ਚਾਲੂ ਕਰੋ"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ। ਹੋਰ ਜਾਣਨ ਲਈ ਉਹਨਾਂ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"ਤੁਹਾਨੂੰ ਨਵੇਂ ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਹੋਏ ਹਨ"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"ਵੇਖਣ ਲਈ SMS ਐਪ ਖੋਲ੍ਹੋ"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ਕੁਝ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਸੀਮਿਤ ਹੋ ਸਕਦੀ ਹੈ"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"ਪਿੰਨ ਕਰੋ"</string>
     <string name="unpin_target" msgid="3556545602439143442">"ਅਨਪਿੰਨ ਕਰੋ"</string>
     <string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬਿਨਾਂ ਪਾਬੰਦੀਆਂ ਦੇ ਵਰਤਣ ਲਈ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਕਰੋ"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ਹੋਰ ਜਾਣਨ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 4700873..6be9a9d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -90,7 +90,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID rozmówcy ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: nie zastrzeżony"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Usługa nie jest świadczona."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nie możesz zmienić ustawienia ID rozmówcy."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Zmieniono ograniczenie dostępu"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Usługa transmisji danych jest zablokowana."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Usługa połączeń alarmowych jest zablokowana."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Usługa głosowa jest zablokowana."</string>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Asystent głosowy"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zablokuj teraz"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Treść ukryta z powodu zasad"</string>
     <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
     <string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobiste"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Praca"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Włącz profil osobisty"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Włącz profil do pracy"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostęp do kontaktów"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokalizacja"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edytuj w aplikacji %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Udostępnij przez:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Udostępnij przez %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Wyślij za pomocą"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Wyślij za pomocą %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Wybierz aplikację ekranu głównego"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Użyj %1$s jako ekranu głównego"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Domyślne dla tej czynności"</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Zresetuj aplikację i uruchom ją ponownie"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Prześlij opinię"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zamknij"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignoruj"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignoruj do momentu ponownego uruchomienia urządzenia"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Zaczekaj"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Zamknij aplikację"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"to może generować dodatkowe koszty"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB w trybie ładowania"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Ładowanie urządzenia przez USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Zasilanie urządzenia przez USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB w trybie przesyłania plików"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB w trybie przesyłania zdjęć"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB w trybie MIDI"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Kliknij, by zobaczyć więcej opcji."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotknij, aby wyłączyć debugowanie USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKCEPTUJ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODRZUĆ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zgłaszam błąd…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Udostępnić raport o błędzie?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Udostępniam raport o błędzie…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administrator poprosił o raport o błędzie, który pomoże w rozwiązaniu problemów na tym urządzeniu. Mogą zostać udostępnione aplikacje i dane."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"UDOSTĘPNIJ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODRZUĆ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Zmień klawiaturę"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Wybierz klawiatury"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
     <string name="hardware" msgid="194658061510127999">"Pokaż klawiaturę wirtualną"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Wybierz układ klawiatury"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Kliknij, by wybrać układ klawiatury."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Skonfiguruj klawiaturę fizyczną"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
@@ -1159,8 +1153,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Odbiornik rzeczywistości wirtualnej"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dostawca warunków"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asystent powiadomień"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Usługa rankingu powiadomień"</string>
     <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>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Więcej opcji"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Pamięć wewnętrzna"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Wewnętrzna pamięć współdzielona"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Karta SD (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Dysk USB"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Podaj PIN, aby odpiąć"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Aby odpiąć, poproś o wzór odblokowania"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Aby odpiąć, poproś o hasło"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Rozmiaru tej aplikacji nie można zmienić. Przewiń ją dwoma palcami."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacja może nie działać przy podzielonym ekranie."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacja nie obsługuje dzielonego ekranu."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Zainstalowany przez administratora"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Zaktualizowane przez administratora"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="other">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Wybrano <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Inne"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ustawiłeś ważność tych powiadomień."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ustawiłeś ważność tych powiadomień."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Zezwalasz aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Zezwalasz aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>)? Użytkownik z tym kontem już istnieje."</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Ustawienie języka"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Dodaj język"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Ustawienie regionu"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Wpisz nazwę języka"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerowane"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Tryb pracy jest WYŁĄCZONY"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Włącz profil do pracy, w tym aplikacje, synchronizację w tle i inne funkcje."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Włącz"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Wyłączono pakiet %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Wyłączone przez administratora organizacji %1$s. Skontaktuj się z nim, by dowiedzieć się więcej."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Masz nowe wiadomości"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Otwórz aplikację do SMS-ów, by wyświetlić wiadomość"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Niektóre funkcje mogą być niedostępne"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Przypnij"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Odepnij"</string>
     <string name="app_info" msgid="6856026610594615344">"O aplikacji"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Aby używać tego urządzenia bez ograniczeń, przywróć ustawienia fabryczne"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Kliknij, by dowiedzieć się więcej."</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 478165c..c8004bf 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"O serviço não foi habilitado."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Não é possível alterar a configuração de identificação de chamadas."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito alterado"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"O serviço de voz está bloqueado."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Alternar para \"Trabalho\""</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -244,7 +242,7 @@
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"envie e veja mensagens SMS"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Compartilhar com"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Compartilhar com %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Enviar usando"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Enviar usando %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Selecione um app de Página inicial"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Usar %1$s como Página inicial"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Usar como padrão para esta ação."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Redefinir e reiniciar app"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Enviar feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Fechar"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Desativar até que dispositivo seja reiniciado"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Aguarde"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Fechar app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"isso pode lhe custar dinheiro"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB carregando este dispositivo"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB fornecendo energia ao dispositivo conectado"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de arquivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecione o layout de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um layout de teclado."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Ouvinte de RV"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condições"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificação"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Serviço de classificação de notificação"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Armazenamento interno"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno compartilhado"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Drive USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir senha antes de liberar"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"O app não é redimensionável. Desloque-o com dois dedos."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"É possível que o app não funcione com o recurso de divisão de tela."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"O app não é compatível com a divisão de tela."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado pelo seu administrador"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Você definiu a importância dessas notificações."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferência de idioma"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1557,18 +1551,19 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Ativar"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s desativado"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Desativado pelo administrador de %1$s. Entre em contato com ele para saber mais."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Você tem mensagens novas"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Abra o app de SMS para ver"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Algumas funcionalidades são limitadas"</string>
     <string name="user_encrypted_message" msgid="4923292604515744267">"Toque para desbloquear"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"Dados do usuário bloqueados"</string>
     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de trabalho bloqueado"</string>
-    <string name="profile_encrypted_message" msgid="6964994232310195874">"Toque para desbloquear perfil de trabalho"</string>
+    <string name="profile_encrypted_message" msgid="6964994232310195874">"Toque p/ desbl. perfil de trab."</string>
     <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
     <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toque para ver os arquivos"</string>
     <string name="pin_target" msgid="3052256031352291362">"Fixar guia"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
     <string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 038bfe9..c2ba8ad 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID do autor da chamada é predefinido com não restrito. Chamada seguinte: Não restrita"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Serviço não fornecido."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Não pode alterar a definição da identificação de chamadas."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito modificado"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"O serviço de voz está bloqueado."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. de voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Mudar para pessoal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Mudar para trabalho"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"aceder aos contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localização"</string>
@@ -339,7 +337,7 @@
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite à aplicação modificar o registo de chamadas do tablet, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o registo de chamadas."</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite à aplicação modificar o registo de chamadas da sua TV, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o registo de chamadas."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite à aplicação modificar o registo de chamadas do telemóvel, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o seu registo de chamadas."</string>
-    <string name="permlab_bodySensors" msgid="4683341291818520277">"aceder a sensores corp. (como monit. do ritmo cardíaco)"</string>
+    <string name="permlab_bodySensors" msgid="4683341291818520277">"aceder a sensores corporais (como monitores do ritmo cardíaco)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Permite que a aplicação aceda a dados de sensores que monitorizam a sua condição física, como o ritmo cardíaco."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"ler eventos do calendário, para além de informações confidenciais"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite que a aplicação leia todos os eventos do calendário guardados no tablet, incluindo os de amigos ou colegas de trabalho. Pode permitir que a aplicação partilhe ou guarde dados do calendário, independentemente da confidencialidade ou sensibilidade."</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Partilhar com"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partilhar com %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Enviar com"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Enviar com %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Selecione uma aplicação Página inicial"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utilizar %1$s como Página inicial"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Repor e reiniciar aplicação"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Enviar comentários"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Fechar"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Desativar som até o dispositivo reiniciar"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Aguardar"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Fechar aplicação"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Não são necessárias permissões"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"isto poderá estar sujeito a custos"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Carregamento deste dispositivo por USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Fornecimento de energia ao dispositivo ligado por USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de ficheiros"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desat. a depuração USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"A criar relatório de erro…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Pretende partilhar o relatório de erro?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"A partilhar relatório de erro…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"O seu administrador de TI solicitou um relatório de erro para ajudar na resolução de problemas deste dispositivo. As aplicações e os dados podem ser partilhados."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTILHAR"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar o teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecionar esquema de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um esquema de teclado."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Serviço de escuta de RV"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fornecedor de condição"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificações"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Serviço de classificação de notificações"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"memória de armazenamento interno"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno partilhado"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidade USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de soltar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir sequência de desbloqueio antes de soltar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir palavra-passe antes de soltar"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"A aplicação não é redimensionável. Desloque-a com dois dedos."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"A aplicação pode não funcionar com o ecrã dividido."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"A aplicação não é compatível com o ecrã dividido."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado pelo administrador"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Definiu a importância destas notificações."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Definiu a importância destas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"É importante devido às pessoas envolvidas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Pretende permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Pretende permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferência de idioma"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir o funcionamento do perfil de trabalho, incluindo as aplicações, a sincronização em segundo plano e as funcionalidades relacionadas."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Ativar"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s desativado"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Desativado pelo administrador de %1$s. Contacte-o para saber mais."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Tem mensagens novas"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Abra a aplicação de SMS para ver"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Algumas funcionalid. limitadas"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fixar"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
     <string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Repor os dados de fábrica para utilizar o dispositivo sem restrições"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 478165c..c8004bf 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"O serviço não foi habilitado."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Não é possível alterar a configuração de identificação de chamadas."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito alterado"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"O serviço de voz está bloqueado."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Alternar para \"Trabalho\""</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -244,7 +242,7 @@
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"envie e veja mensagens SMS"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Compartilhar com"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Compartilhar com %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Enviar usando"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Enviar usando %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Selecione um app de Página inicial"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Usar %1$s como Página inicial"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Usar como padrão para esta ação."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Redefinir e reiniciar app"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Enviar feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Fechar"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Desativar até que dispositivo seja reiniciado"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Aguarde"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Fechar app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"isso pode lhe custar dinheiro"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB carregando este dispositivo"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB fornecendo energia ao dispositivo conectado"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de arquivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecione o layout de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um layout de teclado."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Ouvinte de RV"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condições"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificação"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Serviço de classificação de notificação"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Armazenamento interno"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno compartilhado"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Drive USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir senha antes de liberar"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"O app não é redimensionável. Desloque-o com dois dedos."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"É possível que o app não funcione com o recurso de divisão de tela."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"O app não é compatível com a divisão de tela."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado pelo seu administrador"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Você definiu a importância dessas notificações."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferência de idioma"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1557,18 +1551,19 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Ativar"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s desativado"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Desativado pelo administrador de %1$s. Entre em contato com ele para saber mais."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Você tem mensagens novas"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Abra o app de SMS para ver"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Algumas funcionalidades são limitadas"</string>
     <string name="user_encrypted_message" msgid="4923292604515744267">"Toque para desbloquear"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"Dados do usuário bloqueados"</string>
     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de trabalho bloqueado"</string>
-    <string name="profile_encrypted_message" msgid="6964994232310195874">"Toque para desbloquear perfil de trabalho"</string>
+    <string name="profile_encrypted_message" msgid="6964994232310195874">"Toque p/ desbl. perfil de trab."</string>
     <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
     <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toque para ver os arquivos"</string>
     <string name="pin_target" msgid="3052256031352291362">"Fixar guia"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
     <string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f707822..7485e65 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -45,7 +45,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mesaj vocal"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
     <string name="mmiError" msgid="5154499457739052907">"Problemă de conexiune sau cod MMI nevalid."</string>
-    <string name="mmiFdnError" msgid="5224398216385316471">"Operația este limitată la numerele cu apelări restricţionate."</string>
+    <string name="mmiFdnError" msgid="5224398216385316471">"Operația este limitată la numerele cu apelări restricționate."</string>
     <string name="serviceEnabled" msgid="8147278346414714315">"Serviciul a fost activat."</string>
     <string name="serviceEnabledFor" msgid="6856228140453471041">"Serviciul a fost activat pentru:"</string>
     <string name="serviceDisabled" msgid="1937553226592516411">"Serviciul a fost dezactivat."</string>
@@ -56,9 +56,9 @@
     <string name="badPin" msgid="9015277645546710014">"Codul PIN vechi introdus nu este corect."</string>
     <string name="badPuk" msgid="5487257647081132201">"Codul PUK introdus nu este corect."</string>
     <string name="mismatchPin" msgid="609379054496863419">"Codurile PIN introduse nu se potrivesc."</string>
-    <string name="invalidPin" msgid="3850018445187475377">"Introduceţi un cod PIN alcătuit din 4 până la 8 cifre."</string>
-    <string name="invalidPuk" msgid="8761456210898036513">"Introduceţi un cod PUK care să aibă 8 cifre sau mai mult."</string>
-    <string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceţi codul PUK pentru a-l debloca."</string>
+    <string name="invalidPin" msgid="3850018445187475377">"Introduceți un cod PIN alcătuit din 4 până la 8 cifre."</string>
+    <string name="invalidPuk" msgid="8761456210898036513">"Introduceți un cod PUK care să aibă 8 cifre sau mai mult."</string>
+    <string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceți codul PUK pentru a-l debloca."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Introduceți codul PUK2 pentru a debloca cardul SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Operațiunea nu a reușit. Activați blocarea cardului SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
@@ -78,18 +78,17 @@
     <string name="PwdMmi" msgid="7043715687905254199">"Modificare parolă"</string>
     <string name="PinMmi" msgid="3113117780361190304">"Cod PIN modificat"</string>
     <string name="CnipMmi" msgid="3110534680557857162">"Se apelează numărul prezent"</string>
-    <string name="CnirMmi" msgid="3062102121430548731">"Se apelează un număr restricţionat"</string>
+    <string name="CnirMmi" msgid="3062102121430548731">"Se apelează un număr restricționat"</string>
     <string name="ThreeWCMmi" msgid="9051047170321190368">"Apelare de tip conferință"</string>
     <string name="RuacMmi" msgid="7827887459138308886">"Respingere apeluri supărătoare nedorite"</string>
     <string name="CndMmi" msgid="3116446237081575808">"Se apelează serviciul de furnizare a numerelor"</string>
     <string name="DndMmi" msgid="1265478932418334331">"Nu deranjați"</string>
-    <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID-ul apelantului este restricţionat în mod prestabilit. Apelul următor: restricţionat"</string>
+    <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID-ul apelantului este restricționat în mod prestabilit. Apelul următor: restricționat"</string>
     <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID-ul apelantului este restricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
     <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: Restricționat."</string>
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Nu se asigură accesul la acest serviciu."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nu puteți să modificați setarea pentru ID-ul apelantului."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acces restricționat modificat"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Serviciul de date este blocat."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Serviciul de urgență este blocat."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Serviciul de voce este blocat."</string>
@@ -119,8 +118,8 @@
     <string name="roamingText6" msgid="2059440825782871513">"Roaming - sistem disponibil"</string>
     <string name="roamingText7" msgid="7112078724097233605">"Roaming - partenerAlliance"</string>
     <string name="roamingText8" msgid="5989569778604089291">"Roaming - partener Premium"</string>
-    <string name="roamingText9" msgid="7969296811355152491">"Roaming - funcţionalitate completă a serviciului"</string>
-    <string name="roamingText10" msgid="3992906999815316417">"Roaming - funcţionalitate parțială a serviciului"</string>
+    <string name="roamingText9" msgid="7969296811355152491">"Roaming - funcționalitate completă a serviciului"</string>
+    <string name="roamingText10" msgid="3992906999815316417">"Roaming - funcționalitate parțială a serviciului"</string>
     <string name="roamingText11" msgid="4154476854426920970">"Banner roaming activat"</string>
     <string name="roamingText12" msgid="1189071119992726320">"Banner roaming dezactivat"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Se caută serviciul"</string>
@@ -155,13 +154,13 @@
     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protocolul nu este acceptat."</string>
     <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Nu s-a putut stabili o conexiune securizată."</string>
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Pagina nu a putut fi deschisă, deoarece adresa URL nu este validă."</string>
-    <string name="httpErrorFile" msgid="2170788515052558676">"Fişierul nu a putut fi accesat."</string>
-    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nu s-a putut găsi fişierul solicitat."</string>
+    <string name="httpErrorFile" msgid="2170788515052558676">"Fișierul nu a putut fi accesat."</string>
+    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nu s-a putut găsi fișierul solicitat."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Există prea multe solicitări în curs de procesare. Încercați din nou mai târziu."</string>
     <string name="notification_title" msgid="8967710025036163822">"Eroare de conectare pentru <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Sincronizare"</string>
     <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="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="tv" msgid="516619861191025923">"Spațiul de stocare al televizorului este plin. Ștergeți câteva fișiere pentru a elibera spațiu."</string>
@@ -177,9 +176,9 @@
     <string name="factory_reset_warning" msgid="5423253125642394387">"Datele de pe dispozitiv vor fi șterse"</string>
     <string name="factory_reset_message" msgid="4905025204141900666">"Aplicația de administrare nu poate fi utilizată, deoarece este deteriorată sau îi lipsesc componente. Datele de pe dispozitiv vor fi șterse. Pentru asistență, contactați administratorul."</string>
     <string name="me" msgid="6545696007631404292">"Eu"</string>
-    <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opţiuni tablet PC"</string>
+    <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opțiuni tablet PC"</string>
     <string name="power_dialog" product="tv" msgid="6153888706430556356">"Opțiuni TV"</string>
-    <string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
+    <string name="power_dialog" product="default" msgid="1319919075463988638">"Opțiuni telefon"</string>
     <string name="silent_mode" msgid="7167703389802618663">"Mod Silențios"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"Activați funcția wireless"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Dezactivați funcția wireless"</string>
@@ -200,11 +199,11 @@
     <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>
-    <string name="reboot_safemode_confirm" msgid="55293944502784668">"Doriți să reporniţi în modul sigur? Astfel vor fi dezactivate toate aplicațiile terță parte pe care le-ați instalat. Acestea vor fi restabilite când reporniţi din nou."</string>
+    <string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniți în modul sigur"</string>
+    <string name="reboot_safemode_confirm" msgid="55293944502784668">"Doriți să reporniți în modul sigur? Astfel vor fi dezactivate toate aplicațiile terță parte pe care le-ați instalat. Acestea vor fi restabilite când reporniți din nou."</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"Recente"</string>
     <string name="no_recent_tasks" msgid="8794906658732193473">"Nu există aplicații recente."</string>
-    <string name="global_actions" product="tablet" msgid="408477140088053665">"Opţiuni tablet PC"</string>
+    <string name="global_actions" product="tablet" msgid="408477140088053665">"Opțiuni tablet PC"</string>
     <string name="global_actions" product="tv" msgid="7240386462508182976">"Opțiuni TV"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opțiuni telefon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Blocați ecranul"</string>
@@ -232,13 +231,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistent vocal"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conținutul este ascuns conform politicii"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Serviciu"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Comutați la Personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Comutați la Serviciu"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Persoane de contact"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceseze persoanele de contact"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string>
@@ -281,30 +279,30 @@
     <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="permlab_receiveSms" msgid="8673471768947895082">"primeşte mesaje text (SMS)"</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>
+    <string name="permlab_receiveMms" msgid="1821317344668257098">"primește mesaje text (MMS)"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. 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_readCellBroadcasts" msgid="1598328843619646166">"citește mesajele cu transmisie celulară"</string>
-    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgenţă. Aplicațiile rău intenţionate pot afecta performanța sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
+    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgență."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string>
-    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obţină detalii despre feedurile sincronizate în prezent."</string>
+    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obțină detalii despre feedurile sincronizate în prezent."</string>
     <string name="permlab_sendSms" msgid="7544599214260982981">"trimită și să vadă mesajele SMS"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neașteptate. Aplicațiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neașteptate. Aplicațiile rău intenționate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"citește mesajele text (SMS sau MMS)"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidențialitate al acestora."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
     <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Permite aplicației să citească mesajele SMS stocate pe telefon sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidențialitate al acestora."</string>
-    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"primeşte mesaje text (WAP)"</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Permite aplicației să citească mesajele SMS stocate pe telefon sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
+    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"primește mesaje text (WAP)"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau șterge mesajele care v-au fost trimise fără a vi le arăta."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"preluare aplicații care rulează"</string>
-    <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicației să preia informațiile despre activităţile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informații despre aplicațiile care sunt utilizate pe dispozitiv."</string>
+    <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicației să preia informațiile despre activitățile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informații despre aplicațiile care sunt utilizate pe dispozitiv."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"să gestioneze profilul și proprietarii dispozitivului"</string>
     <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Permite aplicațiilor să seteze proprietarii de profiluri și proprietarul dispozitivului."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"reordonare aplicații care rulează"</string>
-    <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite aplicației să mute activităţile în prim-plan și în fundal. Aplicația poate face acest lucru fără aportul dvs."</string>
-    <string name="permlab_enableCarMode" msgid="5684504058192921098">"activare mod Maşină"</string>
-    <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite aplicației să activeze modul Maşină."</string>
+    <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite aplicației să mute activitățile în prim-plan și în fundal. Aplicația poate face acest lucru fără aportul dvs."</string>
+    <string name="permlab_enableCarMode" msgid="5684504058192921098">"activare mod Mașină"</string>
+    <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite aplicației să activeze modul Mașină."</string>
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"închide alte aplicații"</string>
     <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Permite aplicației să oprească procesele derulate în fundal de alte aplicații. Acest lucru poate face ca respectivele aplicații să nu mai ruleze."</string>
     <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"suprapune elemente vizuale peste alte aplicații"</string>
@@ -316,7 +314,7 @@
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"măsurare spațiu de stocare al aplicației"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"modifică setări de sistem"</string>
-    <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permite aplicației să modifice datele din setările sistemului. Aplicațiile rău intenţionate pot corupe configuraţia sistemului dvs."</string>
+    <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permite aplicației să modifice datele din setările sistemului. Aplicațiile rău intenționate pot corupe configurația sistemului dvs."</string>
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"rulează la pornire"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea tabletei poate dura mai mult timp, iar rularea continuă a aplicației poate încetini dispozitivul."</string>
     <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea televizorului poate dura mai mult timp, iar funcționarea continuă a aplicației poate încetini televizorul."</string>
@@ -326,27 +324,27 @@
     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze televizorul, determinându-l să utilizeze prea multă memorie."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"citește agenda"</string>
-    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
+    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenționate pot distribui datele de contact fără știrea dvs."</string>
     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
-    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
+    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenționate pot distribui datele de contact fără știrea dvs."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"citește jurnalul de apeluri"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenționate pot distribui aceste date fără știrea dvs."</string>
     <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string>
-    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
+    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenționate pot distribui aceste date fără știrea dvs."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"scrie jurnalul de apeluri"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite aplicației să modifice jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău-intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
     <string name="permlab_bodySensors" msgid="4683341291818520277">"să acceseze senzorii corporali (cum ar fi monitoarele cardiace)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Permite aplicației să acceseze date de la senzorii care vă monitorizează starea fizică, cum ar fi ritmul cardiac."</string>
-    <string name="permlab_readCalendar" msgid="5972727560257612398">"citirea evenimentelor din calendar și a informațiilor confidenţiale"</string>
-    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite aplicației să citească toate evenimentele din calendar stocate pe tabletă, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
+    <string name="permlab_readCalendar" msgid="5972727560257612398">"citirea evenimentelor din calendar și a informațiilor confidențiale"</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite aplicației să citească toate evenimentele din calendar stocate pe tabletă, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Permite aplicației să citească toate evenimentele din calendar stocate pe televizor, inclusiv cele ale prietenilor sau colegilor. Cu această permisiune, aplicația poate să permită accesul la datele din calendar sau să le salveze, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
-    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaților fără știrea proprietarului"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe televizor, inclusiv pe cele ale prietenilor sau ale colegilor. Cu această permisiune, aplicația poate să trimită mesaje care par că vin din partea proprietarilor calendarului sau să modifice evenimentele fără cunoștința acestora."</string>
@@ -354,9 +352,9 @@
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
     <string name="permlab_accessFineLocation" msgid="251034415460950944">"să acceseze locația exactă (bazată pe GPS și pe rețea)"</string>
-    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite aplicației să obţină locația dvs. exactă utilizând sistemul GPS (Global Positioning System) sau surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicațiile pot utiliza această permisiune pentru a determina locația dvs. și pot să consume mai multă energie a bateriei."</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite aplicației să obțină locația dvs. exactă utilizând sistemul GPS (Global Positioning System) sau surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicațiile pot utiliza această permisiune pentru a determina locația dvs. și pot să consume mai multă energie a bateriei."</string>
     <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"să acceseze locația aproximativă (bazată pe rețea)"</string>
-    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obţină locația dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicațiile pot utiliza această permisiune pentru a determina locația dvs. aproximativă."</string>
+    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obțină locația dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicațiile pot utiliza această permisiune pentru a determina locația dvs. aproximativă."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modificare setări audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistreze sunet"</string>
@@ -368,11 +366,11 @@
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlează vibrarea"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite aplicației să controleze mecanismul de vibrare."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string>
-    <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neașteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicațiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
+    <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenția dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neașteptate. Cu această permisiune aplicația nu poate apela numerele de urgență. Aplicațiile rău intenționate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</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="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_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"împiedică intrarea televizorului în stare de inactivitate"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
@@ -392,11 +390,11 @@
     <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Permite aplicației să modifice fusul orar al televizorului."</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permite aplicației să schimbe fusul orar al telefonului."</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"găsește conturi pe dispozitiv"</string>
-    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Permite aplicației să obţină lista de conturi cunoscute de tabletă. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Permite aplicației să obțină lista de conturi cunoscute de tabletă. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
     <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Permite aplicației să obțină lista de conturi cunoscute de televizor. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permite aplicației să obţină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permite aplicației să obțină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"vizualizează conexiunile la rețea"</string>
-    <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Permite aplicației să vadă informațiile despre conexiunile la rețea, cum ar fi reţelele existente și cele care sunt conectate."</string>
+    <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Permite aplicației să vadă informațiile despre conexiunile la rețea, cum ar fi rețelele existente și cele care sunt conectate."</string>
     <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"să aibă acces deplin la rețea"</string>
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permite aplicației să creeze socluri de rețea și să utilizeze protocoale de rețea personalizate. Browserul și alte aplicații oferă mijloacele de trimitere a datelor pe internet, astfel încât această permisiune nu este necesară pentru trimiterea datelor pe internet."</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"modificare conectivitate în rețea"</string>
@@ -404,9 +402,9 @@
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"modificare conectivitate tethering"</string>
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permite aplicației să modifice starea de conectivitate prin tethering la rețea."</string>
     <string name="permlab_accessWifiState" msgid="5202012949247040011">"vizualizează conexiunile Wi-Fi"</string>
-    <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite aplicației să vadă informațiile despre reţelele Wi-Fi, de ex. dacă o rețea Wi-Fi este activată, precum și numele dispozitivelor conectate la rețeaua Wi-Fi."</string>
+    <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite aplicației să vadă informațiile despre rețelele Wi-Fi, de ex. dacă o rețea Wi-Fi este activată, precum și numele dispozitivelor conectate la rețeaua Wi-Fi."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"se conectează și se deconectează de la Wi-Fi"</string>
-    <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Permite aplicației să se conecteze și să se deconecteze de la punctele de acces Wi-Fi, precum și să efectueze modificări în configuraţia dispozitivului pentru reţelele Wi-Fi."</string>
+    <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Permite aplicației să se conecteze și să se deconecteze de la punctele de acces Wi-Fi, precum și să efectueze modificări în configurația dispozitivului pentru rețelele Wi-Fi."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitere recepționare difuzare multiplă Wi-Fi"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar tableta dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar televizorul dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
@@ -416,19 +414,19 @@
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Permite aplicației să configureze televizorul Bluetooth local, precum și să descopere și să se asocieze cu dispozitive la distanță."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite aplicației să configureze telefonul Bluetooth local, să descopere și să se împerecheze cu dispozitive la distanță."</string>
     <string name="permlab_accessWimaxState" msgid="4195907010610205703">"se conectează și se deconectează de la WiMAX"</string>
-    <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite aplicației să stabilească dacă o rețea WiMAX este activată și să vadă informațiile cu privire la toate reţelele WiMAX conectate."</string>
+    <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite aplicației să stabilească dacă o rețea WiMAX este activată și să vadă informațiile cu privire la toate rețelele WiMAX conectate."</string>
     <string name="permlab_changeWimaxState" msgid="340465839241528618">"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="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="tv" msgid="6022307083934827718">"Permite aplicației să conecteze și să deconecteze televizorul 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="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_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="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="tv" msgid="3974124940101104206">"Permite aplicației să vadă configurația funcției Bluetooth a televizorului, precum și să efectueze și să accepte conexiuni cu dispozitive asociate."</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>
+    <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>
     <string name="permlab_nfc" msgid="4423351274757876953">"controlare schimb de date prin Near Field Communication"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite aplicației să comunice cu etichetele, cardurile și cititoarele NFC (Near Field Communication)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"dezactivează blocarea ecranului"</string>
-    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite aplicației să dezactiveze blocarea tastelor și orice modalitate asociată de securizare prin parolă. De exemplu, telefonul dezactivează blocarea tastelor când se primeşte un apel telefonic și reactivează blocarea tastelor la terminarea apelului."</string>
+    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite aplicației să dezactiveze blocarea tastelor și orice modalitate asociată de securizare prin parolă. De exemplu, telefonul dezactivează blocarea tastelor când se primește un apel telefonic și reactivează blocarea tastelor la terminarea apelului."</string>
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestionează hardware-ul pentru amprentă"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite aplicației să invoce metode pentru a adăuga și pentru a șterge șabloane de amprentă pentru utilizare."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"folosește hardware-ul pentru amprentă"</string>
@@ -456,12 +454,12 @@
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Permite unei aplicații să modifice setările de sincronizare ale unui cont. De exemplu, cu această permisiune aplicația poate activa sincronizarea aplicației Persoane cu un anumit cont."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"citire statistici privind sincronizarea"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Permite unei aplicații să citească statisticile de sincronizare ale unui cont, inclusiv istoricul evenimentelor de sincronizare și volumul datelor sincronizate."</string>
-    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"citește conţinutul stocării USB"</string>
-    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"citește conţinutul cardului SD"</string>
+    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"citește conținutul stocării USB"</string>
+    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"citește conținutul cardului SD"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Permite aplic. citirea conținutului stoc. USB."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Permite aplicației citirea conținutul cardului SD."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau șterge conţinutul stocării USB"</string>
-    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau șterge conţinutul cardului SD"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau șterge conținutul stocării USB"</string>
+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau șterge conținutul cardului SD"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permite scriere în stoc. USB."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicației să scrie pe cardul SD."</string>
     <string name="permlab_use_sip" msgid="2052499390128979920">"efectuarea/primirea apelurilor SIP"</string>
@@ -483,7 +481,7 @@
     <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"gestionează politica de rețea"</string>
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicației să gestioneze politicile de rețea și să definească regulile specifice aplicațiilor."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificați modul de calcul al utilizării rețelei"</string>
-    <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicației să modifice modul în care este calculată utilizarea rețelei pentru aplicații. Nu se utilizează de aplicațiile obişnuite."</string>
+    <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicației să modifice modul în care este calculată utilizarea rețelei pentru aplicații. Nu se utilizează de aplicațiile obișnuite."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
     <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>
@@ -513,7 +511,7 @@
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setați reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Stabiliți lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizați încercările de deblocare a ecranului"</string>
-    <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocaţi tableta sau ștergeți datele acesteia dacă sunt introduse prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați tableta sau ștergeți datele acesteia dacă sunt introduse prea multe parole incorecte."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați televizorul sau ștergeți toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați telefonul sau ștergeți toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
     <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați tableta sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
@@ -593,7 +591,7 @@
     <string name="phoneTypePager" msgid="7582359955394921732">"Pager"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"Altele"</string>
     <string name="phoneTypeCallback" msgid="2712175203065678206">"Apelare inversă"</string>
-    <string name="phoneTypeCar" msgid="8738360689616716982">"Maşină"</string>
+    <string name="phoneTypeCar" msgid="8738360689616716982">"Mașină"</string>
     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Numărul de telefon principal al companiei"</string>
     <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
     <string name="phoneTypeMain" msgid="6766137010628326916">"Număr de telefon principal"</string>
@@ -606,7 +604,7 @@
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"Asistent"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
     <string name="eventTypeCustom" msgid="7837586198458073404">"Personalizate"</string>
-    <string name="eventTypeBirthday" msgid="2813379844211390740">"Zi de naştere"</string>
+    <string name="eventTypeBirthday" msgid="2813379844211390740">"Zi de naștere"</string>
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Zi aniversară"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Altul"</string>
     <string name="emailTypeCustom" msgid="8525960257804213846">"Personalizat"</string>
@@ -655,13 +653,13 @@
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Serviciu"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Altul"</string>
     <string name="quick_contacts_not_available" msgid="746098007828579688">"Nu s-a găsit nicio aplicație pentru a afișa această persoană de contact."</string>
-    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduceţi codul PIN"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introduceţi codul PUK și noul cod PIN"</string>
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduceți codul PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introduceți codul PUK și noul cod PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Codul PUK"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Noul cod PIN"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceţi parola"</font></string>
-    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string>
-    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceți parola"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceți parola pentru a debloca"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceți codul PIN pentru a debloca"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsați Meniu, apoi 0."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgență"</string>
@@ -669,43 +667,43 @@
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecranul este blocat."</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Apăsați Meniu pentru deblocare."</string>
-    <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenaţi modelul pentru a debloca"</string>
+    <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenați modelul pentru a debloca"</string>
     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Urgență"</string>
-    <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Reveniţi la apel"</string>
+    <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Reveniți la apel"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Corect!"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Încercați din nou"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Încercați din nou"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depăşit numărul maxim de încercări pentru Deblocare facială"</string>
+    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depășit numărul maxim de încercări pentru Deblocare facială"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Niciun card SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nu există card SIM în computerul tablet PC."</string>
     <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Niciun card SIM în televizor."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Telefonul nu are card SIM."</string>
-    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Introduceţi un card SIM."</string>
-    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Cardul SIM lipsește sau nu poate fi citit. Introduceţi un card SIM."</string>
+    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Introduceți un card SIM."</string>
+    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Cardul SIM lipsește sau nu poate fi citit. Introduceți un card SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Card SIM inutilizabil."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Cardul dvs. SIM este dezactivat definitiv.\n Contactaţi furnizorul de servicii wireless pentru a obţine un alt card SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Cardul dvs. SIM este dezactivat definitiv.\n Contactați furnizorul de servicii wireless pentru a obține un alt card SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Melodia anterioară"</string>
     <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Melodia următoare"</string>
     <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pauză"</string>
     <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"Redați"</string>
     <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Opriți"</string>
-    <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Derulaţi"</string>
-    <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Derulaţi rapid înainte"</string>
+    <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Derulați"</string>
+    <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Derulați rapid înainte"</string>
     <string name="emergency_calls_only" msgid="6733978304386365407">"Numai apeluri de urgență"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rețea blocată"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Cardul SIM este blocat cu codul PUK."</string>
-    <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultați Ghidul de utilizare sau contactaţi Serviciul de relații cu clienții."</string>
+    <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultați Ghidul de utilizare sau contactați Serviciul de relații cu clienții."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Cardul SIM este blocat."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Se deblochează cardul SIM..."</string>
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați telefonul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a televizorului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, televizorul va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acesta va fi acum resetat la setările prestabilite din fabrică."</string>
@@ -713,14 +711,14 @@
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Ați uitat modelul?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Deblocare cont"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Prea multe încercări de desenare a modelului"</string>
-    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Pentru a debloca, conectaţi-vă folosind Contul Google."</string>
+    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Pentru a debloca, conectați-vă folosind Contul Google."</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nume de utilizator (e-mail)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parolă"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Conectați-vă"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nume de utilizator sau parolă nevalide."</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ați uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Se verifică..."</string>
-    <string name="lockscreen_unlock_label" msgid="737440483220667054">"Deblocaţi"</string>
+    <string name="lockscreen_unlock_label" msgid="737440483220667054">"Deblocați"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sunet activat"</string>
     <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sunet dezactivat"</string>
     <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Desenarea modelului a început"</string>
@@ -758,7 +756,7 @@
     <string name="granularity_label_link" msgid="5815508880782488267">"link"</string>
     <string name="granularity_label_line" msgid="5764267235026120888">"rând"</string>
     <string name="factorytest_failed" msgid="5410270329114212041">"Testarea de fabrică nu a reușit"</string>
-    <string name="factorytest_not_system" msgid="4435201656767276723">"Acţiunea FACTORY_TEST este acceptată doar pentru pachetele instalate în /system/app."</string>
+    <string name="factorytest_not_system" msgid="4435201656767276723">"Acțiunea FACTORY_TEST este acceptată doar pentru pachetele instalate în /system/app."</string>
     <string name="factorytest_no_action" msgid="872991874799998561">"Nu s-a găsit niciun pachet care să ofere acțiunea FACTORY_TEST."</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reporniți"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La pagina de la „<xliff:g id="TITLE">%s</xliff:g>” apare:"</string>
@@ -776,7 +774,7 @@
     <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
     <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
     <string name="autofill_province" msgid="2231806553863422300">"Provincie"</string>
-    <string name="autofill_postal_code" msgid="4696430407689377108">"Cod poştal"</string>
+    <string name="autofill_postal_code" msgid="4696430407689377108">"Cod poștal"</string>
     <string name="autofill_state" msgid="6988894195520044613">"Stat"</string>
     <string name="autofill_zip_code" msgid="8697544592627322946">"Cod ZIP"</string>
     <string name="autofill_county" msgid="237073771020362891">"Județ"</string>
@@ -798,10 +796,10 @@
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite aplicației să adauge mesaje în Mesaje primite în mesageria vocală."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modificare permisiuni pentru locația geografică a browserului"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicației să modifice permisiunile privind locația geografică a browserului. Aplicațiile rău intenţionate pot utiliza această permisiune pentru a permite trimiterea informațiilor privind locația către site-uri web arbitrare."</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicației să modifice permisiunile privind locația geografică a browserului. Aplicațiile rău intenționate pot utiliza această permisiune pentru a permite trimiterea informațiilor privind locația către site-uri web arbitrare."</string>
     <string name="save_password_message" msgid="767344687139195790">"Doriți ca browserul să rețină această parolă?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string>
-    <string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string>
+    <string name="save_password_remember" msgid="6491879678996749466">"Rețineți"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Niciodată"</string>
     <string name="open_permission_deny" msgid="7374036708316629800">"Nu aveți permisiunea de a deschide această pagină."</string>
     <string name="text_copied" msgid="4985729524670131385">"Text copiat în clipboard."</string>
@@ -818,8 +816,8 @@
     <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteți interogarea"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Explorați prin atingere?"</string>
-    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> dorește să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string>
-    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> dorește să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string>
+    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> dorește să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacționa cu tableta."</string>
+    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> dorește să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacționa cu telefonul."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
     <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -866,8 +864,8 @@
     <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">"prânz"</string>
     <string name="Noon" msgid="3342127745230013127">"Prânz"</string>
-    <string name="midnight" msgid="7166259508850457595">"miezul nopţii"</string>
-    <string name="Midnight" msgid="5630806906897892201">"Miezul nopţii"</string>
+    <string name="midnight" msgid="7166259508850457595">"miezul nopții"</string>
+    <string name="Midnight" msgid="5630806906897892201">"Miezul nopții"</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">"Selectați-le pe toate"</string>
@@ -882,12 +880,12 @@
     <string name="undo" msgid="7905788502491742328">"Anulați"</string>
     <string name="redo" msgid="7759464876566803888">"Repetați"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selectare text"</string>
-    <string name="addToDictionary" msgid="4352161534510057874">"Adăugați în dicţionar"</string>
+    <string name="addToDictionary" msgid="4352161534510057874">"Adăugați în dicționar"</string>
     <string name="deleteText" msgid="6979668428458199034">"Ștergeți"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Metodă de intrare"</string>
-    <string name="editTextMenuTitle" msgid="4909135564941815494">"Acţiuni pentru text"</string>
-    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spaţiul de stocare aproape ocupat"</string>
-    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcții de sistem să nu funcţioneze"</string>
+    <string name="editTextMenuTitle" msgid="4909135564941815494">"Acțiuni pentru text"</string>
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spațiul de stocare aproape ocupat"</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcții de sistem să nu funcționeze"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Spațiu de stocare insuficient pentru sistem. Asigurați-vă că aveți 250 MB de spațiu liber și reporniți."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> rulează acum"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"Atingeți pentru mai multe informații sau pentru a opri aplicația."</string>
@@ -907,6 +905,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editați cu %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Trimiteți prin"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Distribuiți cu %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Trimiteți folosind"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Trimiteți folosind %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Selectați o aplicație de pe ecranul de pornire"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utilizați %1$s ca ecran de pornire"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Se utilizează în mod prestabilit pentru această acțiune."</string>
@@ -923,7 +923,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Resetați și reporniți aplicația"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Trimiteți feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Închideți"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Dezactivați"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Dezactivați până la repornirea dispozitivului"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Așteptați"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Închideți aplicația"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -933,11 +933,11 @@
     <string name="anr_process" msgid="6156880875555921105">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Raportați"</string>
-    <string name="wait" msgid="7147118217226317732">"Aşteptaţi"</string>
+    <string name="wait" msgid="7147118217226317732">"Așteptați"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă.\n\nDoriți să o închideți?"</string>
-    <string name="launch_warning_title" msgid="1547997780506713581">"Aplicaţie redirecționată"</string>
-    <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string>
-    <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
+    <string name="launch_warning_title" msgid="1547997780506713581">"Aplicație redirecționată"</string>
+    <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcționează acum."</string>
+    <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată inițial."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Afișați întotdeauna"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
@@ -952,11 +952,11 @@
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Se finalizează pornirea."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Atingeți pentru a comuta la aplicație"</string>
-    <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Comutaţi între aplicații?"</string>
+    <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Comutați între aplicații?"</string>
     <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"O altă aplicație rulează deja și trebuie oprită înainte a putea porni o aplicație nouă."</string>
-    <string name="old_app_action" msgid="493129172238566282">"Reveniţi la <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+    <string name="old_app_action" msgid="493129172238566282">"Reveniți la <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="old_app_description" msgid="2082094275580358049">"Nu porniți aplicația nouă."</string>
-    <string name="new_app_action" msgid="5472756926945440706">"Porniţi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+    <string name="new_app_action" msgid="5472756926945440706">"Porniți <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Opriți vechea aplicație fără să salvați."</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> a depășit limita de memorie"</string>
     <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Datele privind memoria au fost culese; atingeți pentru a trimite"</string>
@@ -992,7 +992,7 @@
       <item quantity="other">Rețele Wi-Fi deschise disponibile</item>
       <item quantity="one">Rețea Wi-Fi deschisă disponibilă</item>
     </plurals>
-    <string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectați-vă la reţeaua Wi-Fi"</string>
+    <string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectați-vă la rețeaua Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Conectați-vă la rețea"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
@@ -1004,26 +1004,26 @@
     <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplicația %1$s dorește să se conecteze la rețeaua Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"O aplicație"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniți Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeți pentru setări"</string>
-    <string name="accept" msgid="1645267259272829559">"Acceptaţi"</string>
-    <string name="decline" msgid="2112225451706137894">"Refuzaţi"</string>
+    <string name="accept" msgid="1645267259272829559">"Acceptați"</string>
+    <string name="decline" msgid="2112225451706137894">"Refuzați"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitația a fost trimisă."</string>
     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitație pentru conectare"</string>
     <string name="wifi_p2p_from_message" msgid="570389174731951769">"De la:"</string>
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Către:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceţi codul PIN necesar:"</string>
+    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceți codul PIN necesar:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string>
     <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableta se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectată la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"Televizorul se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la reţeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="select_character" msgid="3365550120617701745">"Introduceți caracterul"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trimite un număr mare de mesaje SMS. Permiteți acestei aplicații să trimită în continuare mesaje?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"Permiteți"</string>
-    <string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Refuzați"</string>
     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; intenționează să trimită un mesaj la &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Acest lucru "<b>"poate genera costuri"</b>" în contul dvs. mobil."</string>
     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Acest lucru va genera costuri în contul dvs. mobil."</b></string>
@@ -1038,14 +1038,14 @@
     <string name="sim_done_button" msgid="827949989369963775">"Terminat"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"Card SIM adăugat"</string>
     <string name="sim_added_message" msgid="7797975656153714319">"Reporniți dispozitivul pentru a accesa rețeaua mobilă."</string>
-    <string name="sim_restart_button" msgid="4722407842815232347">"Reporniţi"</string>
+    <string name="sim_restart_button" msgid="4722407842815232347">"Reporniți"</string>
     <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Pentru ca noul SIM să funcționeze corect, va trebui să instalați și să deschideți o aplicație de la operatorul dvs."</string>
     <string name="carrier_app_dialog_button" msgid="7900235513678617329">"DESCĂRCAȚI APLICAȚIA"</string>
     <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NU ACUM"</string>
     <string name="carrier_app_notification_title" msgid="8921767385872554621">"S-a introdus un card SIM nou"</string>
     <string name="carrier_app_notification_text" msgid="1132487343346050225">"Atingeți pentru a-l configura"</string>
-    <string name="time_picker_dialog_title" msgid="8349362623068819295">"Setaţi ora"</string>
-    <string name="date_picker_dialog_title" msgid="5879450659453782278">"Setaţi data"</string>
+    <string name="time_picker_dialog_title" msgid="8349362623068819295">"Setați ora"</string>
+    <string name="date_picker_dialog_title" msgid="5879450659453782278">"Setați data"</string>
     <string name="date_time_set" msgid="5777075614321087758">"Setați"</string>
     <string name="date_time_done" msgid="2507683751759308828">"Terminat"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NOU: "</font></string>
@@ -1053,7 +1053,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nu se solicită nicio permisiune"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"aceasta poate să genereze costuri"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Conexiune USB pentru încărcare"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dispozitivul se încarcă prin USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Dispozitivul atașat se încarcă prin USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Conexiune USB pentru transferul fișierelor"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Conexiune USB pentru transferul fotografiilor"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"Conexiune USB pentru MIDI"</string>
@@ -1061,24 +1062,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Atingeți pentru mai multe opțiuni."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Atingeți pentru a dezactiva depanarea USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTAȚI"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUZAȚI"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Se creează un raport de eroare…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Trimiteți raportul de eroare?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Se trimite raportul de eroare…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. Este posibil să se permită accesul la date și aplicații."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"TRIMITEȚI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZAȚI"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Schimbați tastatura"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Alegeți tastaturi"</string>
     <string name="show_ime" msgid="2506087537466597099">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
     <string name="hardware" msgid="194658061510127999">"Afișați tastatura virtuală"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selectați aspectul tastaturii"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Atingeți pentru a selecta un aspect de tastatură."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurați tastatura fizică"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
@@ -1125,7 +1119,7 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite unei aplicații accesul la citirea sesiunilor de instalare. Aceasta poate vedea detalii despre instalările de pachete active."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"să solicite pachete de instalare"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite unei aplicații să solicite instalarea pachetelor."</string>
-    <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeți de două ori pentru a mări/micşora"</string>
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeți de două ori pentru a mări/micșora"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nu s-a putut adăuga widgetul."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Accesați"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Căutați"</string>
@@ -1134,13 +1128,13 @@
     <string name="ime_action_done" msgid="8971516117910934605">"Terminat"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Înapoi"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"Executați"</string>
-    <string name="dial_number_using" msgid="5789176425167573586">"Formaţi numărul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="dial_number_using" msgid="5789176425167573586">"Formați numărul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="create_contact_using" msgid="4947405226788104538">"Creați contactul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Următoarele aplicații solicită permisiunea de a accesa contul dvs. acum și în viitor."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Permiteți această solicitare?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Solicitare de acces"</string>
     <string name="allow" msgid="7225948811296386551">"Permiteți"</string>
-    <string name="deny" msgid="2081879885755434506">"Refuzaţi"</string>
+    <string name="deny" msgid="2081879885755434506">"Refuzați"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Permisiune solicitată"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permisiune solicitată\npentru contul <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Utilizați această aplicație în afara profilului de serviciu"</string>
@@ -1149,29 +1143,30 @@
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronizare"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilitate"</string>
     <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="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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Instrument de ascultare pentru Realitatea virtuală"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Furnizor de condiții"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent pentru notificări"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Serviciul de clasificare a notificărilor"</string>
     <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>
-    <string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeți pentru a gestiona reţeaua."</string>
-    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la reţeaua VPN activată permanent…"</string>
-    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la reţeaua VPN activată permanent"</string>
+    <string name="vpn_text" msgid="3011306607126450322">"Atingeți pentru a gestiona rețeaua."</string>
+    <string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeți pentru a gestiona rețeaua."</string>
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la rețeaua VPN activată permanent…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la rețeaua VPN activată permanent"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de rețea VPN activată permanent"</string>
     <string name="vpn_lockdown_config" msgid="6415899150671537970">"Atingeți pentru a configura"</string>
     <string name="upload_file" msgid="2897957172366730416">"Alegeți un fișier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
-    <string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
+    <string name="reset" msgid="2448168080964209908">"Resetați"</string>
     <string name="submit" msgid="1602335572089911941">"Trimiteți"</string>
-    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Maşină activat"</string>
-    <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieşi din modul Maşină."</string>
+    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Mașină activat"</string>
+    <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieși din modul Mașină."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"Atingeți pentru a configura."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Înapoi"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Înainte"</string>
-    <string name="skip_button_label" msgid="1275362299471631819">"Omiteţi"</string>
+    <string name="skip_button_label" msgid="1275362299471631819">"Omiteți"</string>
     <string name="no_matches" msgid="8129421908915840737">"Nicio potrivire"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Găsiți pe pagină"</string>
     <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
@@ -1192,10 +1187,10 @@
     <string name="gpsNotifMessage" msgid="1374718023224000702">"Solicitat de <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
     <string name="gpsVerifYes" msgid="2346566072867213563">"Da"</string>
     <string name="gpsVerifNo" msgid="1146564937346454865">"Nu"</string>
-    <string name="sync_too_many_deletes" msgid="5296321850662746890">"Limita pentru ştergere a fost depăşită"</string>
-    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente şterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceți?"</string>
+    <string name="sync_too_many_deletes" msgid="5296321850662746890">"Limita pentru ștergere a fost depășită"</string>
+    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente șterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceți?"</string>
     <string name="sync_really_delete" msgid="2572600103122596243">"Ștergeți elementele"</string>
-    <string name="sync_undo_deletes" msgid="2941317360600338602">"Anulați aceste ştergeri"</string>
+    <string name="sync_undo_deletes" msgid="2941317360600338602">"Anulați aceste ștergeri"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Nu trebuie să luați nicio măsură deocamdată"</string>
     <string name="choose_account_label" msgid="5655203089746423927">"Alegeți un cont"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Adăugați un cont"</string>
@@ -1203,13 +1198,13 @@
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Creșteți"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"Reduceți"</string>
     <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeți și țineți apăsat <xliff:g id="VALUE">%s</xliff:g>."</string>
-    <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisaţi în sus pentru a creşte și în jos pentru a reduce."</string>
+    <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisați în sus pentru a crește și în jos pentru a reduce."</string>
     <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creșteți valoarea pentru minute"</string>
     <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reduceți valoarea pentru minute"</string>
     <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creșteți valoarea pentru oră"</string>
     <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Reduceți valoarea pentru oră"</string>
-    <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Setaţi valoarea PM"</string>
-    <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setaţi valoarea AM"</string>
+    <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Setați valoarea PM"</string>
+    <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setați valoarea AM"</string>
     <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creșteți valoarea pentru lună"</string>
     <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Reduceți valoarea pentru lună"</string>
     <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creșteți valoarea pentru zi"</string>
@@ -1230,15 +1225,15 @@
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Permiteți accesul pentru"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Permiteți accesul pentru <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Mâner glisant. Atingeți și țineți apăsat."</string>
-    <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Glisaţi pentru a debloca."</string>
-    <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conectaţi un set căşti-microfon pentru a auzi tastele apăsate când introduceţi parola."</string>
+    <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Glisați pentru a debloca."</string>
+    <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conectați un set căști-microfon pentru a auzi tastele apăsate când introduceți parola."</string>
     <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punct."</string>
-    <string name="action_bar_home_description" msgid="5293600496601490216">"Navigaţi la ecranul de pornire"</string>
-    <string name="action_bar_up_description" msgid="2237496562952152589">"Navigaţi în sus"</string>
+    <string name="action_bar_home_description" msgid="5293600496601490216">"Navigați la ecranul de pornire"</string>
+    <string name="action_bar_up_description" msgid="2237496562952152589">"Navigați în sus"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mai multe opțiuni"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Stocare internă"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Memorie internă comună"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Card SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Card SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unitate USB"</string>
@@ -1252,12 +1247,12 @@
     <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Ați atins limita de date mobile"</string>
     <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Ați atins limita de date Wi-Fi"</string>
     <string name="data_usage_limit_body" msgid="291731708279614081">"S-au întrerupt datele pentru restul ciclului"</string>
-    <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"S-a depăşit limita de date 2G-3G"</string>
-    <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"S-a depăşit limita de date 4G"</string>
+    <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"S-a depășit limita de date 2G-3G"</string>
+    <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"S-a depășit limita de date 4G"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Limită de date mobile depășită"</string>
-    <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"S-a depăşit limita de date Wi-Fi"</string>
+    <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"S-a depășit limita de date Wi-Fi"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> peste limita specificată."</string>
-    <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datele de fundal restricţionate"</string>
+    <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datele de fundal restricționate"</string>
     <string name="data_usage_restricted_body" msgid="6741521330997452990">"Atingeți pt. a elimina limita."</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Certificat de securitate"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certificatul este valid."</string>
@@ -1308,25 +1303,25 @@
     <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">", securizat"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
-    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greșit"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greșită"</string>
-    <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greșit"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercați din nou peste <xliff:g id="NUMBER">%1$d</xliff:g> (de) secunde."</string>
-    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string>
-    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
-    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
-    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceţi parola"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceţi codul PUK pentru a continua. Contactaţi operatorul pentru mai multe detalii."</string>
-    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceţi codul PIN dorit"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenați modelul"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceți codul PIN al cardului SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceți codul PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceți parola"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceți codul PUK pentru a continua. Contactați operatorul pentru mai multe detalii."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceți codul PIN dorit"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmați codul PIN dorit"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
-    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceți un cod PIN format din 4 până la 8 cifre."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Codul PUK trebuie să conțină 8 numere."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceți codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectaţi-vă cu Contul dvs. Google."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectați-vă cu Contul dvs. Google."</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"Nume de utilizator (e-mail)"</string>
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Parolă"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Conectați-vă"</string>
@@ -1336,17 +1331,17 @@
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a televizorului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, televizorul va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminați"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mențineți două degete pe ecran pentru a activa accesibilitatea."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"S-a activat accesibilitatea."</string>
@@ -1483,7 +1478,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicită modelul pentru deblocare înainte de a anula fixarea"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicită parola înainte de a anula fixarea"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Aplicația nu poate fi redimensionată. Derulați în ea cu două degete."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplicația nu acceptă ecranul împărțit."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalat de administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizat de un administrator"</string>
@@ -1562,12 +1557,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selectate</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selectat</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Dvs. setați importanța acestor notificări."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Dvs. setați importanța acestor notificări."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Notificarea este importantă având în vedere persoanele implicate."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>? (există deja un utilizator cu acest cont)"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Limba preferată"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Adăugați o limbă"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regiunea preferată"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Numele limbii"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerate"</string>
@@ -1576,18 +1570,19 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modul de serviciu e DEZACTIVAT"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permiteți profilului de serviciu să funcționeze, inclusiv aplicațiile, sincronizarea în fundal și funcțiile asociate."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Activați"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Dezactivat de %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Dezactivat de administratorul companiei %1$s. Contactați-l pentru a afla mai multe."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Aveți mesaje noi"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Deschideți aplicația pentru SMS-uri ca să vizualizați"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Unele funcții ar putea fi limitate"</string>
     <string name="user_encrypted_message" msgid="4923292604515744267">"Atingeți pentru a debloca"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"Datele utilizatorului: blocate"</string>
     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil de serviciu blocat"</string>
-    <string name="profile_encrypted_message" msgid="6964994232310195874">"Atingeți ca să deblocați profilul de serviciu"</string>
+    <string name="profile_encrypted_message" msgid="6964994232310195874">"Atingeți ca să deblocați"</string>
     <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectat la <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
     <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Atingeți pentru a vedea fișierele"</string>
     <string name="pin_target" msgid="3052256031352291362">"Fixați"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Anulați fixarea"</string>
     <string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Reveniți la setările din fabrică pentru a folosi acest dispozitiv fără restricții"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Atingeți pentru a afla mai multe."</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8ed321f..5926bfd 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -90,7 +90,6 @@
     <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>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Аудиоподсказки"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содержимое скрыто в соответствии с заданными правилами"</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="user_owner_label" msgid="1119010402169916617">"Перейти в личный профиль"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Перейти в рабочий профиль"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакты"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"доступ к контактам"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактировать с помощью приложения \"%1$s\""</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Поделиться с помощью:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Поделиться через %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Выберите приложение"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Отправка с помощью %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Выберите главное приложение"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Назначьте приложение \"%1$s\" главным"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"По умолчанию для этого действия"</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Сбросить и перезапустить"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Отправить отзыв"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Закрыть"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Скрыть"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Отключить до перезагрузки устройства"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Подождать"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Закрыть приложение"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Не требуется разрешений"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"это может стоить вам денег!"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Зарядка через USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Зарядка через USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Подача питания на подключенное устройство через USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Передача файлов через USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Передача фото через USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI через USB"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Нажмите, чтобы настроить."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Нажмите, чтобы отключить отладку по USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИНЯТЬ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТКЛОНИТЬ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Подготовка отчета об ошибке"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Разрешить доступ к информации об ошибке?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Отправка отчета об ошибке"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Администратор запросил отчет об ошибке, чтобы устранить неполадку. Он может получить доступ к приложениям и данным."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПРЕДОСТАВИТЬ ДОСТУП"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТКЛОНИТЬ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Выбор раскладки"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Выбрать раскладку"</string>
     <string name="show_ime" msgid="2506087537466597099">"Показывать на экране, когда физическая клавиатура включена"</string>
     <string name="hardware" msgid="194658061510127999">"Виртуальная клавиатура"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Выберите раскладку клавиатуры"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Нажмите, чтобы выбрать раскладку клавиатуры."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Настройка физической клавиатуры"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
@@ -1159,8 +1153,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-режим"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Поставщик условий"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ассистент уведомлений"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Сервис для оценки важности уведомлений"</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>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Ещё"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Внутр. накопитель"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Внутренний общий накопитель"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-карта <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-накопитель"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-код для отключения"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запрашивать графический ключ для отключения блокировки"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запрашивать пароль для отключения блокировки"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Размер окна нельзя изменить. Прокрутите страницу двумя пальцами."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Приложение не поддерживает разделение экрана."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Приложение не поддерживает разделение экрана."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Установлено администратором"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Обновлено администратором"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="many">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Другое"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Вы определяете важность этих уведомлений."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Вы определяете важность этих уведомлений."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Важное (люди)"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать пользователя для аккаунта <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя для аккаунта <xliff:g id="ACCOUNT">%2$s</xliff:g> (пользователь c таким аккаунтом уже есть)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Языковые настройки"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Добавьте язык"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Региональные настройки"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Введите язык"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Рекомендуемые"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Рабочий режим отключен"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Включить рабочий профиль: приложения, фоновую синхронизацию и связанные функции."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Включить"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Пакет \"%1$s\" заблокирован"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Пакет заблокирован администратором компании \"%1$s\". Обратитесь к нему за дополнительной информацией."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Новые сообщения"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Чтобы просмотреть, откройте приложение для обмена SMS"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Некоторые функции недоступны"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Закрепить"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Открепить"</string>
     <string name="app_info" msgid="6856026610594615344">"О приложении"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Сброс до заводских настроек для работы без ограничений"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Нажмите, чтобы узнать больше."</string>
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index ee0afad..6c76da0 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"අමතන්නාගේ ID සුපුරුදු අනුව සීමා වී නැත. මීළඟ ඇමතුම: සීමා කර ඇත"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"සේවාවන් සපයා නැත."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"අමතන්නාගේ ID සැකසීම ඔබට වෙනස්කල නොහැක."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"හඬ සහායක"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"දැන් අගුළු දමන්න"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ප්‍රතිපත්තිය විසින් අන්තර්ගතය සඟවන ලදී"</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="user_owner_label" msgid="1119010402169916617">"පුද්ගලික වෙත මාරු වන්න"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"කාර්යාලය වෙත මාරු වන්න"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"සම්බන්ධතා"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ඔබේ සම්බන්ධතාවලට පිවිසෙන්න"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string>
@@ -903,6 +901,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s සමඟ සංස්කරණය කරන්න"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"සමඟ බෙදාගන්න"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%s සමඟ බෙදාගන්න"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"මෙය භාවිතයෙන් යවන්න"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s භාවිතයෙන් යවන්න"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"මුල් පිටු යෙදුම තෝරන්න"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"මුල් පිටු යෙදුම ලෙස %1$s න් භාවිතා කරන්න"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"මෙම ක්‍රියාව සඳහා සුපුරුද්දෙන් භාවිත කරන්න."</string>
@@ -919,7 +919,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"යෙදුම නැවත සකසා නැවත ආරම්භ කරන්න"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ප්‍රතිපෝෂණය යවන්න"</string>
     <string name="aerr_close" msgid="2991640326563991340">"වසන්න"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"නිහඬ කරන්න"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"උපාංගය නැවත ආරම්භ වන තෙක් නිහඬ කරන්න"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"රැඳී සිටින්න"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"යෙදුම වසන්න"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1047,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"අවසර අවශ්‍ය නොමැත"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"මෙමඟින් ඔබට මුදල් වැය විය හැක"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"හරි"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ආරෝපණය කිරීම සඳහා USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"මෙම උපාංගය USB වෙතින් ආරෝපණය"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"අමුණා ඇති උපාංගයට USB මඟින් බලය සපයමින්"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ගොනු හුවමාරුව සඳහා USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ඡායාරූප හුවමාරුව සඳහා USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI සඳහා USB"</string>
@@ -1055,24 +1056,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"වඩා වැඩි විකල්ප සඳහා ස්පර්ශ කරන්න."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB නිදොස්කරණය සම්බන්ධිතයි"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB නිදොස්කරණය අබල කිරීමට ස්පර්ශ කරන්න."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"පිළිගන්න"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ප්‍රතික්ෂේප කරන්න"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"දෝෂ වාර්තාවක් ගනිමින්…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"දෝෂ වාර්තාව බෙදා ගන්නද?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"දෝෂ වාර්තාවක් බෙදා ගනිමින්..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"මෙම උපාංගය දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත. යෙදුම් සහ දත්ත බෙදා ගත හැකිය."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"බෙදා ගන්න"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ප්‍රතික්ෂේප කරන්න"</string>
     <string name="select_input_method" msgid="8547250819326693584">"යතුරු පුවරු වෙනස් කිරීම"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"යතුරු පුවරු තෝරන්න"</string>
     <string name="show_ime" msgid="2506087537466597099">"භෞතික යතුරු පුවරුව සක්‍රිය අතරතුර එය තිරය මත තබා ගන්න"</string>
     <string name="hardware" msgid="194658061510127999">"අතථ්‍ය යතුරු පුවරුව පෙන්වන්න"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"යතුරු පුවරුවට පිරිසැලැස්ම තෝරන්න"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"යතුරු පුවරුවට පිරිසැලැස්මක් තේරීමට ස්පර්ශ කරන්න."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"භෞතික යතුරු පුවරුව වින්‍යාස කරන්න"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string>
@@ -1145,8 +1139,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"බිතුපත"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"බිතුපත වෙනස් කරන්න"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"දැනුම්දීම් අසන්නා"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR සවන් දෙන්නා"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"තත්ත්වය සපයන්නා"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"දැනුම්දීම් සහායක"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"දැනුම්දීම් ශ්‍රේණිගත කිරීමේ සේවාව"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN ක්‍රියාත්මකයි"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> මඟින් VPN සක්‍රීය කරන ලදි"</string>
     <string name="vpn_text" msgid="3011306607126450322">"ජාලය කළමනාකරණය කිරීමට ස්පර්ශ කරන්න."</string>
@@ -1231,7 +1226,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"තවත් විකල්ප"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"අභ්‍යන්තර ආචයනය"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"අභ්‍යන්තර බෙදා ගත් ගබඩාව"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD පත"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD කාඩ්පත"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB ධාවකය"</string>
@@ -1475,7 +1470,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ගැලවීමට පෙර PIN විමසන්න"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ගැලවීමට පෙර අගුළු අරින රටාව සඳහා අසන්න"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ගැලවීමට පෙර මුරපදය විමසන්න"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"යෙදුම ප්‍රතිප්‍රමාණ කළ හැකි නොවේ, එය ඇඟිලි දෙකකින් අනුචලනය කරන්න."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"යෙදුම බෙදුම්-තිරය සමග ක්‍රියා නොකළ හැකිය."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"ඔබගේ පරිපාලක විසින් ස්ථාපනය කරන ලද"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ඔබගේ පරිපාලක විසින් යාවත්කාලීන කරන ලදී"</string>
@@ -1545,12 +1540,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"විවිධාකාර"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද (මෙම ගිණුම සහිත පරිශීලකයෙකු දැනටමත් සිටී) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"භාෂා මනාප"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"භාෂාවක් එක් කරන්න"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ප්‍රදේශ මනාපය"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"භාෂා නම ටයිප් කරන්න"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"යෝජිත"</string>
@@ -1559,8 +1553,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"වැඩ ප්‍රකාරය ක්‍රියාවිරහිතයි"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"යෙදුම්, පසුබිම සමමුහුර්ත කිරීම, සහ සම්බන්ධිත විශේෂාංග ඇතුළුව, ක්‍රියා කිරීමට කාර්යාල පැතිකඩට ඉඩ දෙන්න"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ක්‍රියාත්මක කරන්න"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s අබල කරන ලදී"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s පරිපාලක විසින් අබල කරන ලදී. තව දැන ගැනීමට ඔවුන් අමතන්න."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"ඔබට නව පණිවිඩ තිබේ"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"බැලීමට විවෘත SMS යෙදුම විවෘත කරන්න"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"ඇතැම් ක්‍රියාකාරිත්ව සීමිත විය හැකිය"</string>
@@ -1573,4 +1565,7 @@
     <string name="pin_target" msgid="3052256031352291362">"අමුණන්න"</string>
     <string name="unpin_target" msgid="3556545602439143442">"ගලවන්න"</string>
     <string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"සීමා කිරීම්වලින් තොරව මෙම උපාංගය භාවිත කිරීමට කර්මාන්ත ශාලා යළි සැකසීම"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"තව දැන ගැනීමට ස්පර්ශ කරන්න."</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 88e3939..ec45070 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -90,7 +90,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"V predvolenom nastavení nie je identifikácia volajúceho obmedzená. Ďalší hovor: Bez obmedzenia"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Služba nie je poskytovaná."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nemôžete meniť nastavenia identifikácie volajúceho."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Obmedzený prístup bol zmenený"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Údajová služba je zablokovaná."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Tiesňová služba je zablokovaná."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Hlasová služba je zablokovaná."</string>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlasový asistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Uzamknúť"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah je na základe pravidiel skrytý"</string>
     <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobné"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Práca"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Prepnúť na osobný"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Prepnúť na pracovný"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"prístup k vašim kontaktom"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upraviť v aplikácii %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Zdieľať"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Zdieľať v aplikácii %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Odoslať pomocou aplikácie"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Odoslať pomocou aplikácie %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Výber aplikácie na plochu"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Ako plochu používať aplikáciu %1$s"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Použiť ako predvolené nastavenie pre túto akciu."</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Resetovať a reštartovať aplikáciu"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Odoslať spätnú väzbu"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zavrieť"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Ignorovať"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignorovať do reštartu zariadenia"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Čakať"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Zavrieť aplikáciu"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nevyžadujú sa žiadne oprávnenia."</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"môžu sa vám účtovať poplatky"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB na nabíjanie"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Prebieha nabíjanie tohto zariadenia pomocou USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Prebieha nabíjanie pripojeného zariadenia pomocou USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB na prenos súborov"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB na prenos fotiek"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB na pripojenie zariadenia MIDI"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Ďalšie možnosti zobrazíte klepnutím."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Klepnutím zakážete ladenie cez USB"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIJAŤ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODMIETNUŤ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Preberá sa hlásenie chyby…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chcete zdieľať hlásenie chyby?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Zdieľa sa hlásenie chyby…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Správca IT si vyžiadal hlásenie chyby, aby mohol vyriešiť problém na tomto zariadení. Aplikácie a dáta môžu byť zdieľané."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ZDIEĽAŤ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMIETNUŤ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Zmeniť klávesnicu"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Vybrať klávesnicu"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
     <string name="hardware" msgid="194658061510127999">"Zobraziť virtuálnu klávesnicu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Zvoľte rozloženie klávesnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotykom zvoľte rozloženie klávesnice."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurácia fyzickej klávesnice"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
@@ -1159,8 +1153,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Prijímač VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovateľ podmienky"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent upozornení"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Služba na hodnotenie upozornení"</string>
     <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>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Viac možností"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Interné úložisko"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Interné zdieľané úložisko"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD karta"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD karta <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Disk USB"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred uvoľnením požiadať o číslo PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pred uvoľnením požiadať o bezpečnostný vzor"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pred uvoľnením požiadať o heslo"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veľkosť aplikácie nie je možné zmeniť. Zobrazenie môžete posúvať dvoma prstami."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikácia nemusí fungovať so zapnutou rozdelenou obrazovkou."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Inštalovaný správcom"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizované správcom"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="other">Vybrané: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Vybrané: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Rôzne"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Nastavili ste dôležitosť týchto upozornení."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Nastavili ste dôležitosť týchto upozornení."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Táto správa je dôležitá vzhľadom na osoby, ktorých sa to týka."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g> (používateľ s týmto účtom už existuje)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Jazykové predvoľby"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Pridať jazyk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferovaný región"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Zadajte názov jazyka"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovný režim je VYPNUTÝ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Povoľte fungovanie pracovného profilu vrátane aplikácií, synchronizácie na pozadí a súvisiacich funkcií."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Zapnúť"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Balík %1$s bol zakázaný"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Zakázané správcom %1$s. Ak chcete získať ďalšie informácie, kontaktujte ho."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Máte nové správy."</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorte aplikáciu pre SMS a zobrazte správu"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Niektoré funkcie môžu byť obmedzené"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Pripnúť"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Uvoľniť"</string>
     <string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ak chcete toto zariadenie používať bez obmedzení, obnovte na ňom továrenské nastavenia"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím získate ďalšie informácie."</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e821a7f..b2dba7e 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -90,7 +90,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID klicatelja je ponastavljen na neomejeno. Naslednji klic: ni omejeno"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Storitev ni nastavljena in omogočena."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Ne morete spremeniti nastavitve ID-ja klicatelja."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Omejen dostop je spremenjen"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Podatkovna storitev je blokirana."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Klic v sili je blokiran."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Glasovna storitev je blokirana."</string>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Glas. pomočnik"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zakleni zdaj"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Pravilnik je skril vsebino"</string>
     <string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osebno"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Služba"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Preklop na osebni profil"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Preklop na delovni profil"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Stiki"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostop do stikov"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Urejanje z aplikacijo %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Skupna raba z aplikacijo"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Skupna raba z aplikacijo %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Pošiljanje z aplikacijo"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Pošiljanje z aplikacijo %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Izbira aplikacije na začetnem zaslonu"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Uporaba aplikacije %1$s na začetnem zaslonu"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Privzeta uporaba za to dejanje."</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Ponastavitev in vnovični zagon aplikacije"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Pošlji povratne informacije"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zapri"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Prezri"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Prezri do vnovičnega zagona naprave"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Počakajte"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Zapri aplikacijo"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Ni zahtevanih dovoljenj"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"to je lahko plačljivo"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"V redu"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za polnjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Polnjenje akumulatorja v napravi prek USB-ja"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Napajanje priključene naprave prek USB-ja"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prenos datotek"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos fotografij"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Za več možnosti se dotaknite."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje in odpravljanje napak USB je povezano"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotaknite se, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SPREJMEM"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"NE SPREJMEM"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zajemanje poročila o napakah …"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite poslati poročilo o napakah?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Pošiljanje poročila o napakah …"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Skrbnik za IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SKUPNA RABA"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NE SPREJMEM"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Sprememba tipkovnice"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Izbira tipkovnic"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
     <string name="hardware" msgid="194658061510127999">"Pokaži navidezno tipkovnico"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Izberite razporeditev tipkovnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotaknite se, da izberete razporeditev tipkovnice"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguriranje fizične tipkovnice"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -1159,8 +1153,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Poslušalec za navidezno resničnost"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ponudnik pogojev"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomočnik za obvestila"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Storitev za določanje stopenj pomembnosti obvestil"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktivirala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Več možnosti"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Notranja shramba"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Notranja shramba v skupni rabi"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kartica SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Kartica SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Pogon USB"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Zahtevaj PIN pred odpenjanjem"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pred odpenjanjem vprašaj za vzorec za odklepanje"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pred odpenjanjem vprašaj za geslo"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Velikosti aplikacije ni mogoče spremeniti. Po njej se pomikajte z dvema prstoma."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Namestil skrbnik"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Posodobil skrbnik"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> izbrani</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> izbranih</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Vi določite raven pomembnosti teh obvestil."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Vi določite raven pomembnosti teh obvestil."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Pomembno zaradi udeleženih ljudi."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Dovolite, da aplikacija <xliff:g id="APP">%1$s</xliff:g> ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Dovolite aplikaciji <xliff:g id="APP">%1$s</xliff:g>, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g> (uporabnik s tem računom že obstaja)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Nastavitev jezika"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Dodajanje jezika"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Nastavitev območja"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Vnesite ime jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predlagano"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Delovni način IZKLOPLJEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Dovoljeno delovanje delovnega profila, vključno z aplikacijami, sinhronizacijo v ozadju in povezanimi funkcijami."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Vklop"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s – onemogočeno"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Onemogočil skrbnik %1$s. Za več informacij se obrnite nanj."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nova sporočila."</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Za ogled odprite aplikacijo za SMS-je"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Nekatere funkcije bodo omejene"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Pripenjanje"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Odpenjanje"</string>
     <string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ponastavitev naprave na tovarniške nastavitve za uporabo brez omejitev"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dotaknite se, če želite izvedeti več."</string>
 </resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index ed2c066..1846399 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ja e telefonuesit kalon me paracaktim në listën e të telefonuesve të pakufizuar. Telefonata e radhës: e pakufizuar!"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Shërbimi nuk është përgatitur."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nuk mund ta ndryshosh cilësimin e ID-së së telefonuesit."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Qasja e kufizuar u ndryshua"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Shërbimi i të dhënave është i bllokuar."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Shërbimi i urgjencës është i bllokuar."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Shërbimi me zë është bllokuar."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ndihma zanore"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Kyç tani"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Përmbajtjet janë të fshehura"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Përmbajtja është e fshehur për shkak të politikës"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemi \"android\""</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Puna"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Ndryshoje te \"Personale\""</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Ndryshoje te \"Puna\""</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktet"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"qasu te kontaktet e tua"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redakto me %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Shpërnda publikisht me"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Shpërnda publikisht me %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Dërgo me"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Dërgo me %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Përzgjidh një aplikacion nga ekrani bazë"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Përdore %1$s si faqe bazë"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Përdore si parametër të paracaktuar për këtë veprim."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Rivendos dhe rinis aplikacionin"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Dërgo komentin"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Mbyll"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Çaktivizo audion"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Vendose në heshtje deri kur të riniset pajisja"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Prit!"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Mbyll aplikacionin"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nuk kërkohen leje"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"kjo mund të të kushtojë para"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Në rregull"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB-ja për ngarkim"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Kjo pajisje ngarkohet me USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Pajisja e lidhur furnizohet me enrgji me USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB për transferimin e skedarëve"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB për transferimin e fotografive"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB për MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Prek për më shumë opsione."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Korrigjuesi i USB-së i lidhur"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Prek për të çaktivizuar korrigjimin e gabimeve të USB-së."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRANO"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUZO"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Po merret raporti i defekteve në kod…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Të ndahet raporti i defektit në kod?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Po ndan raportin e defekteve në kod..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve. Aplikacioni dhe të dhënat mund të ndahen."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHPËRNDA"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZO"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Ndërro tastierë"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Zgjidh tastierat"</string>
     <string name="show_ime" msgid="2506087537466597099">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
     <string name="hardware" msgid="194658061510127999">"Shfaq tastierën virtuale"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Përzgjidh planin e tastierës"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Prek për të përzgjedhur tastierën."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguro tastierën fizike"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Imazhi i sfondit"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ndrysho imazhin e sfondit"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Dëgjues njoftimesh"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Dëgjues VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ofrues kushtesh"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistenti i njoftimeve"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Shërbimi i klasifikimit të njoftimeve"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN-ja u aktivizua"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN-ja është aktivizuar nga <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Prek për të menaxhuar rrjetin."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Opsione të tjera"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Hapësira e brendshme ruajtëse"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Hapësira ruajtëse e brendshme e ndarë"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Karta SD nga <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-ja"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Zhgozhdimi kërkon PIN-in"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Kërko model shkyçjeje para heqjes së gozhdimit"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Kërko fjalëkalim para heqjes nga gozhdimi."</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Përmasa e apl. nuk mund të ndryshohet, lëvize atë me të dy gishtat."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacioni mund të mos funksionojë me ekranin e ndarë."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"U instalua nga administratori yt"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Përditësuar nga administratori"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> të zgjedhura</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> i zgjedhur</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Të ndryshme"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Është i rëndësishëm për shkak të personave të përfshirë."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Dëshiron të lejosh <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Dëshiron të lejosh <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> (një përdorues me këtë llogari ekziston tashmë) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Preferenca për gjuhën"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Shto një gjuhë"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferenca e rajonit"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Shkruaj emrin e gjuhës"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugjeruar"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modaliteti i punës është JOAKTIV"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Lejoje profilin e punës të funksionojë, duke përfshirë aplikacionet, sinkronizimin në sfond dhe funksionet e lidhura."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Aktivizo"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s është çaktivizuar"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Çaktivizuar nga administratori i %1$s. Kontaktoje për të mësuar më shumë."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Ke mesazhe të reja"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Hap aplikacionin SMS për ta parë"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Disa funksione mund të jenë të kufizuara"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Gozhdo"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Zhgozhdo"</string>
     <string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rivendos cilësimet e fabrikës për ta përdorur këtë pajisje pa kufizime"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Prek për të mësuar më shumë."</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2212c98..2112dbb 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -89,7 +89,6 @@
     <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>
@@ -164,7 +163,7 @@
     <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="tv" msgid="516619861191025923">"Складишни простор на ТВ-у је попуњен. Избришите неке датотеке да бисте ослободили простор."</string>
+    <string name="low_memory" product="tv" msgid="516619861191025923">"Меморијски простор на ТВ-у је попуњен. Избришите неке датотеке да бисте ослободили простор."</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>
@@ -232,13 +231,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помоћ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Закључај одмах"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Садржај је сакривен смерницама"</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="user_owner_label" msgid="1119010402169916617">"Пређи на Лични профил"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Пређи на профил за Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"приступи контактима"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -313,7 +311,7 @@
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Дозвољава апликацији да учини сопствене компоненте трајним у меморији. Ово може да ограничи меморију доступну другим апликацијама и успори таблет."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Дозвољава апликацији да неке своје делове трајно задржи у меморији. То може да ограничи меморију доступну другим апликацијама и успори ТВ."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Дозвољава апликацији да учини сопствене компоненте трајним у меморији. Ово може да ограничи меморију доступну другим апликацијама и успори телефон."</string>
-    <string name="permlab_getPackageSize" msgid="7472921768357981986">"мерење простора за складиштење у апликацији"</string>
+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"мерење меморијског простора у апликацији"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дозвољава апликацији да преузме величине кôда, података и кеша."</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"измена подешавања система"</string>
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Дозвољава апликацији да мења податке о подешавању система. Злонамерне апликације могу да оштете конфигурацију система."</string>
@@ -886,9 +884,9 @@
     <string name="deleteText" msgid="6979668428458199034">"Избриши"</string>
     <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_title" msgid="5576272496365684834">"Меморијски простор је на измаку"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно складишног простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно меморијског простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</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>
@@ -907,6 +905,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измените помоћу апликације %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Делите помоћу"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Делите помоћу апликације %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Пошаљите помоћу:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Пошаљите помоћу: %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Изаберите апликацију за почетну страницу"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Користите %1$s за почетну"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Подразумевано користи за ову радњу."</string>
@@ -923,7 +923,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Ресетуј и поново покрени апликацију"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Пошаљите повратне информације"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Затвори"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Игнориши"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Игнориши док се уређај не покрене поново"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Чекај"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Затвори апликацију"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,7 +1053,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Није потребна ниједна дозвола"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ово ће вам можда бити наплаћено"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Потврди"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB за пуњење"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB пуни овај уређај"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB снабдева енергијом прикључени уређај"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB за пренос датотека"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB за пренос слика"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
@@ -1061,24 +1062,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Додирните за још опција."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИХВАТИ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Извештај о грешци се генерише…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Желите ли да поделите извештај о грешци?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Дели се извештај о грешци…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема у вези са овим уређајем. Апликације и подаци могу да се деле."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ДЕЛИ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Изаберите тастатуре"</string>
     <string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелну тастатуру"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избор распореда тастатуре"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Додирните да бисте изабрали распоред тастатуре."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуришите физичку тастатуру"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1151,8 +1145,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Обрађивач за виртуелну реалност"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Добављач услова"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помоћник за обавештења"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Услуга рангирања обавештења"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN је активиран"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
@@ -1238,7 +1233,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Још опција"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Интерна меморија"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Унутрашњи дељени меморијски простор"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD картица"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD картица"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB диск"</string>
@@ -1483,7 +1478,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тражи PIN пре откачињања"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тражи шаблон за откључавање пре откачињања"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тражи лозинку пре откачињања"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Величина апликације не може да се мења. Померајте је помоћу два прста."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Апликација можда неће функционисати са подељеним екраном."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Апликација не подржава подељени екран."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Инсталирао је ваш администратор"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирао је администратор"</string>
@@ -1562,12 +1557,11 @@
       <item quantity="few">Изабране су <xliff:g id="COUNT_1">%1$d</xliff:g> ставке</item>
       <item quantity="other">Изабрано је <xliff:g id="COUNT_1">%1$d</xliff:g> ставки</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ви подешавате важност ових обавештења."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ви подешавате важност ових обавештења."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ово је важно због људи који учествују."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Желите ли да дозволите апликацији <xliff:g id="APP">%1$s</xliff:g> да направи новог корисника за <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Желите ли да дозволите апликацији <xliff:g id="APP">%1$s</xliff:g> да направи новог корисника за <xliff:g id="ACCOUNT">%2$s</xliff:g> (корисник са овим налогом већ постоји)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Подешавање језика"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Додајте језик"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Подешавање региона"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Унесите назив језика"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
@@ -1576,8 +1570,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Режим за Work је ИСКЉУЧЕН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозвољава профилу за Work да функционише, укључујући апликације, синхронизацију у позадини и сродне функције."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Укључи"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Пакет %1$s је онемогућен"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Онемогућио је администратор компаније %1$s. Контактирајте га да бисте сазнали више."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Имате нове поруке"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Отворите апликацију за SMS да бисте прегледали"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Неке функције су можда ограничене"</string>
@@ -1590,4 +1582,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Закачи"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Откачи"</string>
     <string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетујте уређај на фабричка подешавања да бисте га користили без ограничења"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Додирните да бисте сазнали више."</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8483eaa..832d4a2 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Inte begränsad"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjänsten är inte etablerad."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Det går inte att ändra inställningen för nummerpresentatör."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begränsad åtkomst har ändrats"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjänsten är blockerad."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Räddningstjänsten är blockerad."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Rösttjänsten är blockerad."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innehåll har dolts p.g.a. en policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personligt"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Arbetet"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Byt till din personliga profil"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Byt till jobbprofilen"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"få tillgång till dina kontakter"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Plats"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigera med %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Dela med"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Dela med %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Skicka med"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Skicka med %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Välj en startsidesapp"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Använd %1$s som startsida"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Använd som standard för denna åtgärd."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Återställ och starta om appen"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Skicka feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Stäng"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Dölj"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Ignorera tills enheten har startat om"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Vänta"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Stäng appen"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"detta kan kosta pengar"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB för laddning"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Enheten laddas via USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"En ansluten enhet strömförsörjs via USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB för överföring av filer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB för överföring av foton"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB för MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Visa fler alternativ genom att trycka."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tryck om du vill inaktivera USB-felsökning."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"GODKÄNN"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AVVISA"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Felrapporten överförs …"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Felrapporten delas …"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT-administratören har bett om en felrapport som hjälp vid felsökningen av den här enheten. Appar och data kan komma att delas."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELA"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVVISA"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Byt tangentbord"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Välj tangentbord"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ha kvar den på skärmen när det fysiska tangentbordet används"</string>
     <string name="hardware" msgid="194658061510127999">"Visa virtuellt tangentbord"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Välj en tangentbordslayout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Välj en tangentbordslayout genom att trycka."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurera fysiskt tangentbord"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyssnare för virtuell verklighet"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Leverantör"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Aviseringsassistent"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Rankningstjänst för aviseringar"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Fler alternativ"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"lagring"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Delat internt lagringsutrymme"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-kort (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-enhet"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Be om pinkod innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Be om upplåsningsmönster innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Be om lösenord innan skärmen slutar fästas"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Det går inte att ändra appens storlek. Rulla med två fingrar."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen kanske inte fungerar med delad skärm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen har inte stöd för delad skärm."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Paketet har installerats av administratören"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Uppdaterat av administratören"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> har valts</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> har valts</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Du anger hur viktiga aviseringarna är."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Du anger hur viktiga aviseringarna är."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Detta är viktigt på grund av personerna som deltar."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g> (det finns redan en användare med det här kontot)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Språkinställning"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Lägg till ett språk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regionsinställningar"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Ange språket"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Förslag"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbetsläget är inaktiverat"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillåt att jobbprofilen är aktiv, inklusive appar, bakgrundssynkronisering och andra tillhörande funktioner."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Aktivera"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s har inaktiverats"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Inaktiverat av administratören för %1$s. Kontakta administratören om du vill veta mer."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nya meddelanden"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Öppna sms-appen och visa meddelandet"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Vissa funktioner är begränsade"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Fäst"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Lossa"</string>
     <string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Återställ enheten till standardinställningarna om du vill använda den utan begränsningar"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryck här om du vill läsa mer."</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8564764..e0a32f6 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Chaguo-msingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo: Haijazuiliwa"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Huduma haitathminiwi."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Hauwezi kubadilisha mpangilio wa kitambulisho cha anayepiga."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ufikiaji uliozuiwa umebadilishwa"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Huduma ya data imezuiwa."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Huduma ya dharura imezuiwa."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Huduma ya sauti imezuiwa."</string>
@@ -232,13 +231,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Usaidizi wa Sauti"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Funga sasa"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Maudhui yamefichwa kulingana na sera"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Binafsi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Kazini"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Badili uweke wasifu wa Binafsi"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Badili uweke wasifu wa Kazini"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Anwani"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ifikie anwani zako"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string>
@@ -903,6 +901,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Badilisha kwa %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Shiriki na"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Shiriki na %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Tuma kwa kutumia"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Tuma kwa kutumia %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Chagua programu ya Mwanzo"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Tumia %1$s kama  programu ya Mwanzo"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguo-msingi la kitendo hiki."</string>
@@ -919,7 +919,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Weka na uanzishe upya programu"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Tuma maoni yako"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Funga"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Komesha"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Komesha hadi kifaa kianze upya"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Subiri"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Funga programu"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1047,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Hakuna vibali vinavyohitajika"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"huenda hii ikakugharimu pesa"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Sawa"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB kwa ajili ya kuchaji"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Unachaji kifaa hiki ukitumia USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB inachaji kifaa ulichounganisha"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB kwa ajili ya kuhamisha faili"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB kwa ajili ya kuhamisha picha"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB kwa ajili ya MIDI"</string>
@@ -1055,24 +1056,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Gusa kwa chaguo zaidi."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji wa USB umeunganishwa"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili uzime utatuaji wa USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"KUBALI"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"KATAA"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Inatayarisha ripoti ya hitilafu…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Ungependa kushiriki ripoti ya hitilafu?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Inashiriki ripoti ya hitilafu…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Msimamizi wako wa TEHAMA ameomba ripoti ya hitilafu ili kusaidia katika utatuzi wa hitilafu kwenye kifaa hiki. Programu na data zinaweza kushirikiwa."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHIRIKI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KATAA"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Badilisha kibodi"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Chagua kibodi"</string>
     <string name="show_ime" msgid="2506087537466597099">"Iweke kwenye skrini wakati kibodi inapotumika"</string>
     <string name="hardware" msgid="194658061510127999">"Onyesha kibodi pepe"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Teua mpangilio wa kibodi"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Gusa ili kuchagua mpangilio wa kibodi."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Sanidi kibodi halisi"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
@@ -1145,8 +1139,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Kisikilizaji cha Uhalisia Pepe"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Mtoa masharti"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Mratibu wa arifa"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Huduma ya kupanga arifa"</string>
     <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>
@@ -1231,7 +1226,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Chaguo zaidi"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Hifadhi ya mfumo"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Hifadhi ya ndani inayoshirikiwa"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kadi ya SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Kadi ya SD iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Hifadhi ya USB"</string>
@@ -1475,7 +1470,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Omba PIN kabla hujabandua"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Omba mchoro wa kufungua kabla hujabandua"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Omba nenosiri kabla hujabandua"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Programu haiwezi kurekebishwa ukubwa, sogeza kwa kutumia vidole viwili."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Huenda programu isifanye kazi kwenye skrini inayogawanywa."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Kilisakinishwa na msimamizi wako"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Kimesasiswa na msimamizi wako"</string>
@@ -1545,12 +1540,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> vimechaguliwa</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kimechaguliwa</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Anuwai"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Uliweka umuhimu wa arifa hizi."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Uliweka mipangilio ya umuhimu wa arifa hizi."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Hii ni muhimu kwa sababu ya watu waliohusika."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iunde Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iunde Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g> (Je, akaunti hii tayari ina Mtumiaji)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Lugha ninayopendelea"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Ongeza lugha"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Mapendeleo ya eneo"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Weka jina la lugha"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Inayopendekezwa"</string>
@@ -1559,8 +1553,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Hali ya kazi IMEZIMWA"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Ruhusu wasifu wa kazini utumike, ikiwa ni pamoja na programu, usawazishaji wa chini chini na vipengele vinavyohusiana."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Washa"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Imezimwa na %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Imezimwa na msimamizi wa %1$s. Wasiliana naye ili upate maelezo zaidi."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Una ujumbe mpya"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Fungua programu ya SMS ili uweze kuangalia"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Huenda baadhi ya utendaji ukawa vikwazo"</string>
@@ -1573,4 +1565,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Bandika"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Bandua"</string>
     <string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Rejesha mipangilio iliyotoka nayo kiwandani ili utumie kifaa hiki bila vikwazo"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Gusa ili kupata maelezo zaidi."</string>
 </resources>
diff --git a/core/res/res/values-sw600dp/dimens_material.xml b/core/res/res/values-sw600dp/dimens_material.xml
index 3bbb352..1ec5c0f 100644
--- a/core/res/res/values-sw600dp/dimens_material.xml
+++ b/core/res/res/values-sw600dp/dimens_material.xml
@@ -23,6 +23,8 @@
     <dimen name="action_bar_default_height_material">64dp</dimen>
     <!-- Default content inset of an action bar. -->
     <dimen name="action_bar_content_inset_material">24dp</dimen>
+    <!-- Default content inset of an action bar with navigation present. -->
+    <dimen name="action_bar_content_inset_with_nav">80dp</dimen>
 
     <!-- Default start padding of an action bar. -->
     <dimen name="action_bar_default_padding_start_material">8dp</dimen>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index b5f3673..773301f 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"குரல் உதவி"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"இப்போது பூட்டு"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"கொள்கையின்படி உள்ளடக்கம் மறைக்கப்பட்டது"</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="user_owner_label" msgid="1119010402169916617">"தனிப்பட்ட சுயவிவரத்திற்கு மாறு"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"பணிச் சுயவிவரத்திற்கு மாறு"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"தொடர்புகள்"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"தொடர்புகளை அணுகும்"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"இருப்பிடம்"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s மூலம் திருத்து"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"இதன் மூலம் பகிர்"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s மூலம் பகிர்"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"இதைப் பயன்படுத்தி அனுப்பு:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$sஐப் பயன்படுத்தி அனுப்பு"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"முகப்புப் பயன்பாட்டைத் தேர்வுசெய்க"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$sஐ முகப்பாகப் பயன்படுத்து"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"இந்தச் செயலுக்கு இயல்பாகப் பயன்படுத்து."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"பயன்பாட்டை மீட்டமைத்து மீண்டும் தொடங்கு"</string>
     <string name="aerr_report" msgid="5371800241488400617">"கருத்து தெரிவி"</string>
     <string name="aerr_close" msgid="2991640326563991340">"மூடு"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"முடக்கு"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"சாதனம் மீண்டும் தொடங்கும் வரை முடக்கு"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"காத்திரு"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"பயன்பாட்டை மூடு"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"அனுமதிகள் தேவையில்லை"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"இதனால் நீங்கள் கட்டணம் செலுத்த வேண்டியிருக்கலாம்"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"சரி"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB, சார்ஜ் செய்வதற்கு மட்டும்"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"இந்தச் சாதனத்தை USB சார்ஜ் செய்கிறது"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"இணைத்துள்ள சாதனத்திற்கு USB சக்தி அளிக்கிறது"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB, கோப்புப் பரிமாற்றத்துக்கு மட்டும்"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB, படப் பரிமாற்றத்துக்கு மட்டும்"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB, MIDIக்கு மட்டும்"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"கூடுதல் விருப்பங்களுக்காகத் தொடவும்."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB பிழைத்திருத்தத்தை முடக்க, தொடவும்."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"சரி"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"வேண்டாம்"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"பிழை அறிக்கையை எடுக்கிறது…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"பிழை அறிக்கையைப் பகிரவா?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"பிழை அறிக்கையைப் பகிர்கிறது…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"இந்தச் சாதனத்தின் பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார். பயன்பாடுகளும் தரவும் பகிரப்படலாம்."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"பகிர்"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"வேண்டாம்"</string>
     <string name="select_input_method" msgid="8547250819326693584">"விசைப்பலகையை மாற்று"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"விசைப்பலகைகளைத் தேர்வுசெய்க"</string>
     <string name="show_ime" msgid="2506087537466597099">"கைமுறை விசைப்பலகை இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
     <string name="hardware" msgid="194658061510127999">"விர்ச்சுவல் விசைப்பலகையை காட்டு"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"விசைப்பலகைத் தளவமைப்பைத் தேர்ந்தெடுக்கவும்"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"விசைப்பலகைத் தளவமைப்பைத் தேர்ந்தெடுக்க தொடவும்."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"கைமுறை விசைப்பலகையை உள்ளமைக்கவும்"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"வால்பேப்பர்"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"வால்பேப்பரை மாற்று"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"அறிவிப்புகளைக் கண்காணிக்கும் சேவை"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR லிஷனர்"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"நிபந்தனை வழங்குநர்"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"அறிவிப்பு உதவி"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"அறிவிப்பை மதிப்பீடு செய்யும் சேவை"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN செயல்படுத்தப்பட்டது"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ஆல் VPN செயல்படுத்தப்பட்டது"</string>
     <string name="vpn_text" msgid="3011306607126450322">"நெட்வொர்க்கை நிர்வகிக்கத் தொடவும்."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"மேலும் விருப்பங்கள்"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"அகச் சேமிப்பிடம்"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"பகிர்ந்த சேமிப்பகம் (அகம்)"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD கார்டு"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD கார்டு"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB டிரைவ்"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"அகற்றும் முன் PINஐக் கேள்"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"அகற்றும் முன் திறத்தல் வடிவத்தைக் கேள்"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"அகற்றும் முன் கடவுச்சொல்லைக் கேள்"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"பயன்பாட்டின் அளவை மாற்ற முடியாது. இருவிரல்களைப் பயன்படுத்தி, அதை உருட்டவும்."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"திரைப் பிரிப்பில் பயன்பாடு வேலைசெய்யாமல் போகக்கூடும்."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"திரையைப் பிரிப்பதைப் பயன்பாடு ஆதரிக்கவில்லை."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"நிர்வாகி நிறுவினார்"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டன</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டது</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"இதர அமைப்பு"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ஈடுபட்டுள்ளவர்களின் காரணமாக, இது முக்கியமானது."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g>ஐ அனுமதிக்கவா?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (இந்தக் கணக்கில் ஏற்கனவே ஒரு பயனர் உள்ளார்) மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g>ஐ அனுமதிக்கவா?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"மொழி விருப்பம்"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"மொழியைச் சேர்"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"மண்டல விருப்பம்"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"மொழி பெயரை உள்ளிடுக"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"பரிந்துரைகள்"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"பணிப் பயன்முறை முடக்கப்பட்டது"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"செயல்பட, பணி சுயவிவரத்தை அனுமதி. இதில் பயன்பாடுகள், பின்னணி ஒத்திசைவு மற்றும் தொடர்புடைய அம்சங்கள் அடங்கும்."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"இயக்கு"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s முடக்கப்பட்டது"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s நிர்வாகி முடக்கியுள்ளார். மேலும் அறிய, அவரைத் தொடர்புகொள்ளவும்."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"புதிய செய்திகள் வந்துள்ளன"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"பார்க்க, SMS பயன்பாட்டைத் திறக்கவும்"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"சில செயல்பாடு வரம்பிடப்பட்டிருக்கலாம்"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"பின் செய்"</string>
     <string name="unpin_target" msgid="3556545602439143442">"பின்னை அகற்று"</string>
     <string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"இந்தச் சாதனத்தைக் கட்டுப்பாடுகளின்றிப் பயன்படுத்த, ஆரம்ப நிலைக்கு மீட்டமைக்கவும்"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"மேலும் அறிய தொடவும்."</string>
 </resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index e7d0fa8..4809c98 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"కాలర్ ID డిఫాల్ట్‌గా అపరిమితానికి ఉంటుంది. తదుపరి కాల్: అపరిమితం"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"సేవ కేటాయించబడలేదు."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"మీరు కాలర్ ID సెట్టింగ్‌ను మార్చలేరు."</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"వాయిస్ సహాయకం"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ఇప్పుడు లాక్ చేయండి"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్‌లు దాచబడ్డాయి"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"విధానం ద్వారా కంటెంట్‌లు దాచబడ్డాయి"</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="user_owner_label" msgid="1119010402169916617">"వ్యక్తిగతానికి మార్చు"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"కార్యాలయానికి మార్చు"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"పరిచయాలు"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"మీ పరిచయాలను ప్రాప్యత చేయడానికి"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"స్థానం"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sతో సవరించు"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"దీనితో భాగస్వామ్యం చేయి"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$sతో భాగస్వామ్యం చేయి"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"దీన్ని ఉపయోగించి పంపండి"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$sని ఉపయోగించి పంపండి"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"హోమ్ అనువర్తనాన్ని ఎంచుకోండి"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$sని హోమ్‌గా ఉపయోగించండి"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ఈ చర్యకు డిఫాల్ట్‌గా ఉపయోగించండి."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"రీసెట్ చేసి, అనువర్తనాన్ని పునఃప్రారంభించు"</string>
     <string name="aerr_report" msgid="5371800241488400617">"అభిప్రాయాన్ని పంపు"</string>
     <string name="aerr_close" msgid="2991640326563991340">"మూసివేయి"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"మ్యూట్ చేయి"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"పరికరం పునఃప్రారంభమయ్యే వరకు మ్యూట్ చేయి"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"వేచి ఉండండి"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"అనువర్తనాన్ని మూసివేయి"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"అనుమతులు అవసరం లేదు"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"దీనికి మీకు డబ్బు ఖర్చు కావచ్చు"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"సరే"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ఛార్జింగ్ కోసం USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ఈ పరికరం USB మోడ్‌లో ఛార్జ్ అవుతోంది"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"జోడించిన పరికరానికి USB ద్వారా పవర్ సరఫరా అవుతోంది"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ఫైల్ బదిలీ కోసం USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ఫోటో బదిలీ కోసం USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI కోసం USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"మరిన్ని ఎంపికల కోసం తాకండి."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB డీబగ్గింగ్‌ను నిలిపివేయడానికి తాకండి."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ఆమోదిస్తున్నాను"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"తిరస్కరిస్తున్నాను"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"బగ్ నివేదికను తీస్తోంది…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"మీ ఐటి నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. అనువర్తనాలు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"భాగస్వామ్యం చేయి"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"తిరస్కరిస్తున్నాను"</string>
     <string name="select_input_method" msgid="8547250819326693584">"కీబోర్డ్‌ను మార్చు"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"కీబోర్డ్‌లను ఎంచుకోండి"</string>
     <string name="show_ime" msgid="2506087537466597099">"దీన్ని భౌతిక కీబోర్డ్ సక్రియంగా ఉన్నప్పుడు స్క్రీన్‌పై ఉంచుతుంది"</string>
     <string name="hardware" msgid="194658061510127999">"వర్చువల్ కీబోర్డ్‌ను చూపు"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"కీబోర్డ్ లేఅవుట్‌ను ఎంచుకోండి"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"కీబోర్డ్ లేఅవుట్‌ను ఎంచుకోవడానికి తాకండి."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"భౌతిక కీబోర్డుని కాన్ఫిగర్ చేయండి"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్‌ను ఎంచుకోవడానికి నొక్కండి"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్‌లు"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"వాల్‌పేపర్"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"వాల్‌పేపర్‌ను మార్చండి"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"నోటిఫికేషన్ పరిశీలన"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR పరిశీలన"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"షరతు ప్రదాత"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"నోటిఫికేషన్ సహాయకం"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"నోటిఫికేషన్ ర్యాంకర్ సేవ"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN సక్రియం చేయబడింది"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ద్వారా VPN సక్రియం చేయబడింది"</string>
     <string name="vpn_text" msgid="3011306607126450322">"నెట్‌వర్క్‌ను నిర్వహించడానికి తాకండి."</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"మరిన్ని ఎంపికలు"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"అంతర్గత నిల్వ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"అంతర్గత భాగస్వామ్య నిల్వ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD కార్డు"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD కార్డ్"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB డ్రైవ్"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ నమూనా కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"అనువర్తన పరిమాణాన్ని మార్చడం సాధ్యపడదు, రెండు వేళ్లతో దీన్ని స్క్రోల్ చేయండి."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"స్క్రీన్ విభజనతో అనువర్తనం పని చేయకపోవచ్చు."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"మీ నిర్వాహకులు ఇన్‌స్టాల్ చేసారు"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"మీ నిర్వాహకుడు నవీకరించారు"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఎంచుకోబడ్డాయి</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"ఇతరాలు"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ని అనుమతించాలా ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో (ఈ ఖాతాతో ఇప్పటికే ఒక వినియోగదారు ఉన్నారు) కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ని అనుమతించాలా?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"భాష ప్రాధాన్యత"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"భాషను జోడించండి"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ప్రాంతం ప్రాధాన్యత"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"భాష పేరును టైప్ చేయండి"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"సూచించినవి"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"కార్యాలయ మోడ్ ఆఫ్ చేయబడింది"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"అనువర్తనాలు, నేపథ్య సమకాలీకరణ మరియు సంబంధిత లక్షణాలతో సహా కార్యాలయ ప్రొఫైల్‌ను పని చేయడానికి అనుమతించండి."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"ఆన్ చేయి"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$sని నిలిపివేసారు"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$sని నిర్వాహకుడు నిలిపివేసారు. మరింత తెలుసుకోవడానికి వారిని సంప్రదించండి."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"మీకు కొత్త సందేశాలు ఉన్నాయి"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"వీక్షించడానికి SMS అనువర్తనాన్ని తెరవండి"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"కొంత కార్యాచరణ పరిమితం కావచ్చు"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"పిన్ చేయి"</string>
     <string name="unpin_target" msgid="3556545602439143442">"అన్‌‌పిన్‌ ‌చేయి"</string>
     <string name="app_info" msgid="6856026610594615344">"అనువర్తన సమాచారం"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"ఈ పరికరాన్ని ఎటువంటి పరిమితులు లేకుండా ఉపయోగించడానికి ఫ్యాక్టరీ రీసెట్ చేయండి"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"మరింత తెలుసుకోవడానికి తాకండి."</string>
 </resources>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 0f98cfb..c0716e9 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -25,10 +25,5 @@
     <bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
 
     <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
-    <string translatable="false" name="config_defaultPictureInPictureBounds">"1420 100 1820 325"</string>
-
-    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
-         is located in center. -->
-    <string translatable="false" name="config_centeredPictureInPictureBounds">"600 331 1320 749"</string>
-
+    <string translatable="false" name="config_defaultPictureInPictureBounds">"1328 54 1808 324"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 8486c7be..0ea2e52 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"ตัวช่วยเสียง"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ล็อกเลย"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาถูกซ่อนไว้"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"มีการซ่อนเนื้อหาโดยนโยบาย"</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="user_owner_label" msgid="1119010402169916617">"เปลี่ยนไปใช้โปรไฟล์ส่วนตัว"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"เปลี่ยนไปใช้โปรไฟล์งาน"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"รายชื่อติดต่อ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"เข้าถึงรายชื่อติดต่อ"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ตำแหน่ง"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"แก้ไขด้วย %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"แชร์กับ"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"แชร์กับ %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"ส่งโดยใช้"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"ส่งโดยใช้ %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"เลือกแอปหน้าแรก"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ใช้ %1$s เป็นหน้าแรก"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ใช้ค่าเริ่มต้นสำหรับการทำงานนี้"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"รีเซ็ตแอปและเปิดใหม่"</string>
     <string name="aerr_report" msgid="5371800241488400617">"ส่งความคิดเห็น"</string>
     <string name="aerr_close" msgid="2991640326563991340">"ปิด"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"ปิด"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"ปิดการแจ้งเตือนจนกว่าอุปกรณ์จะรีสตาร์ท"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"รอ"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ปิดแอป"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ไม่ต้องการการอนุญาต"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"รายการนี้อาจมีการเรียกเก็บเงิน"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ตกลง"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB สำหรับการชาร์จ"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"กำลังชาร์จอุปกรณ์นี้ด้วย USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"กำลังจ่ายไฟให้อุปกรณ์ที่เชื่อมต่ออยู่ผ่าน USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB สำหรับการโอนไฟล์"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB สำหรับการโอนรูปภาพ"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB สำหรับ MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"แตะเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ยอมรับ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ปฏิเสธ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"กำลังสร้างรายงานข้อบกพร่อง…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"แชร์รายงานข้อบกพร่องไหม"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"กำลังแชร์รายงานข้อบกพร่อง…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ปัญหาอุปกรณ์นี้ อาจมีการแชร์แอปและข้อมูล"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"แชร์"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ปฏิเสธ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"เลือกแป้นพิมพ์"</string>
     <string name="show_ime" msgid="2506087537466597099">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
     <string name="hardware" msgid="194658061510127999">"แสดงแป้นพิมพ์เสมือน"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"เลือกรูปแบบแป้นพิมพ์"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"แตะเพื่อเลือกรูปแบบแป้นพิมพ์"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"กำหนดค่าแป้นพิมพ์จริง"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Listener ความเป็นจริงเสมือน"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ผู้เสนอเงื่อนไข"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ผู้ช่วยการแจ้งเตือน"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"บริการตัวจัดอันดับการแจ้งเตือน"</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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ตัวเลือกเพิ่มเติม"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"ที่จัดเก็บข้อมูลภายใน"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"ที่จัดเก็บข้อมูลที่ใช้ร่วมกันภายใน"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"การ์ด SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"การ์ด SD ของ <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"ไดรฟ์ USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ขอรูปแบบการปลดล็อกก่อนเลิกตรึง"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ขอรหัสผ่านก่อนเลิกตรึง"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"แอปไม่สามารถปรับขนาดได้ เลื่อนแอปด้วยนิ้ว 2 นิ้ว"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"แอปอาจใช้ไม่ได้กับโหมดแยกหน้าจอ"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"แอปไม่สนับสนุนการแยกหน้าจอ"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"ติดตั้งโดยผู้ดูแลระบบของคุณ"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"อัปเดตโดยผู้ดูแลระบบ"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">เลือกไว้ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item>
       <item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"เบ็ดเตล็ด"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> (มีผู้ใช้ที่มีบัญชีนี้อยู่แล้ว) ไหม"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"ค่ากำหนดภาษา"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"เพิ่มภาษา"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ค่ากำหนดภูมิภาค"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"พิมพ์ชื่อภาษา"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"แนะนำ"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"โหมดทำงานปิดอยู่"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"อนุญาตให้โปรไฟล์งานทำงานได้ ซึ่งรวมถึงแอป การซิงค์ในพื้นหลัง และคุณลักษณะอื่นที่เกี่ยวข้อง"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"เปิด"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"ปิดใช้ %1$s แล้ว"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"ผู้ดูแลระบบ %1$s ได้ปิดใช้แล้ว โปรดสอบถามข้อมูลเพิ่มเติมจากเขา"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"คุณมีข้อความใหม่"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"เปิดแอป SMS เพื่อดู"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"อาจมีข้อจำกัดในบางฟังก์ชัน"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"ปักหมุด"</string>
     <string name="unpin_target" msgid="3556545602439143442">"เลิกปักหมุด"</string>
     <string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"รีเซ็ตเป็นค่าเริ่มต้นเพื่อใช้อุปกรณ์นี้โดยไร้ข้อจำกัด"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"แตะเพื่อเรียนรู้เพิ่มเติม"</string>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 70b32c7..00918a4 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Naka-default na hindi pinaghihigpitan ang Caller ID. Susunod na tawag: Hindi pinaghihigpitan"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Hindi naprobisyon ang serbisyo."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Hindi mo mababago ang setting ng caller ID."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Nabago ang pinaghihigpitang access"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Naka-block ang serbisyo ng data."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Naka-block ang pang-emergency na serbisyo."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Naka-block ang serbisyo ng voice."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"I-lock ngayon"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Itinago ang mga content alinsunod sa patakaran"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabaho"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Lumipat sa Personal"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Lumipat sa para sa Trabaho"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Mga Contact"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ina-access ang iyong mga contact"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokasyon"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"I-edit gamit ang %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Ibahagi gamit ang"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Ibahagi gamit ang %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Ipadala gamit ang"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Ipadala gamit ang %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Pumili ng app sa Home"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Gamitin ang %1$s bilang Home"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Gamitin bilang default para sa pagkilos na ito."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"I-reset at i-restart ang app"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Magpadala ng feedback"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Isara"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"I-mute"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"I-mute hanggang sa mag-restart ang device"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Maghintay"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Isara ang app"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Walang mga kinakailangang pahintulot"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"maaari itong magdulot ng gastos sa iyo"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para sa pagcha-charge"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"China-charge sa USB ang device na ito"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB ang nagbibigay ng power sa nakakabit na device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para sa paglipat ng file"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para sa paglipat ng larawan"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para sa MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Pindutin para sa higit pang mga opsyon."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Pindutin upang i-disable ang pagde-debug ng USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TANGGAPIN"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TANGGIHAN"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kinukuha ang ulat ng bug…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Humiling ang iyong IT admin ng isang ulat ng bug upang makatulong sa pag-troubleshoot sa device na ito. Maaaring ibahagi ang mga app at data."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"IBAHAGI"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TANGGIHAN"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Baguhin ang keyboard"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Pumili ng mga keyboard"</string>
     <string name="show_ime" msgid="2506087537466597099">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
     <string name="hardware" msgid="194658061510127999">"Ipakita ang virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pumili ng layout ng keyboard"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pindutin upang pumili ng layout ng keyboard."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"I-configure ang pisikal na keyboard"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nagbibigay ng kundisyon"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Serbisyo sa pag-rank ng notification"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Higit pang mga pagpipilian"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Panloob na storage"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Internal na nakabahaging storage"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD card"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB drive"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Humingi ng password bago mag-unpin"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Hindi nare-resize ang app, mag-scroll dito gamit ang dalawang daliri."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Maaaring hindi gumana ang app sa split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Hindi sinusuportahan ng app ang split-screen."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Na-install ng iyong administrator"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Na-update ng iyong administrator"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Iba Pa"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ikaw ang magtatakda ng kahalagahan ng mga notification na ito."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ikaw ang magtatakda sa kahalagahan ng mga notification na ito."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Mahalaga ito dahil sa mga taong kasangkot."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> (mayroon nang User sa account na ito) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Kagustuhan sa wika"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Magdagdag ng wika"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Kagustuhan sa rehiyon"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"I-type ang wika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iminumungkahi"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"NAKA-OFF ang work mode"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Payagang gumana ang profile sa trabaho, kasama na ang mga app, pag-sync sa background at mga may kaugnayang feature."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"I-on"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"Na-disable ang %1$s"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Na-disable ng administrator ng %1$s. Makipag-ugnayan sa administrator upang matuto nang higit pa."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Mayroon kang mga bagong mensahe"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Buksan ang SMS app upang tingnan"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Limitado ilang functionality"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"I-pin"</string>
     <string name="unpin_target" msgid="3556545602439143442">"I-unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"I-factory reset upang magamit ang device na ito nang walang mga paghihigpit"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pindutin upang matuto nang higit pa."</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ee55277..4db8264 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmamış"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Hizmet sağlanamadı."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Arayanın kimliği ayarını değiştiremezsiniz."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Kısıtlanmış erişim değiştirildi"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Veri hizmeti engellendi."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Acil durum hizmeti engellendi."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Ses hizmeti engellendi."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Sesli Yardım"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"İçerikler politika nedeniyle gizlendi"</string>
     <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Kişisel"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Kişisel Profile Geç"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"İş Profiline Geç"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kişiler"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kişilerinize erişme"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Konum"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ile düzenle"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Şununla paylaş:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s ile paylaş"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Göndermek için kullanılacak uygulama"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s uygulamasını kullanarak gönderin"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Ana Ekran uygulaması seçin"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Ana Ekran olarak %1$s uygulamasını kullanın"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Varsayılan olarak bu işlem için kullan."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Uygulamayı sıfırla ve yeniden başlat"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Geri bildirim gönder"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Kapat"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Yok say"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Cihaz yeniden başlatılana kadar bir daha gösterme"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Bekle"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Uygulamayı kapat"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"bunun için sizden ücret alınabilir"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Tamam"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Şarj için USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Bu cihaz USB\'den şarj oluyor"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, bağlı cihaza güç sağlıyor"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Dosya aktarımı için USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Fotoğraf aktarımı için USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI için USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Daha fazla seçenek için dokunun."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"KABUL ET"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REDDET"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hata raporu alınıyor…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Hata raporu paylaşılsın mı?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hata raporu paylaşılıyor..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"BT yöneticiniz, bu cihazda sorun gidermeye yardımcı olması için bir hata raporu istedi. Uygulamalar ve veriler paylaşılabilir."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REDDET"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Klavyeyi değiştir"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Klavyeyi seç"</string>
     <string name="show_ime" msgid="2506087537466597099">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
     <string name="hardware" msgid="194658061510127999">"Sanal klavyeyi göster"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klavye düzeni seçin"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Bir klavye düzeni seçmek için dokunun."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziksel klavyeyi yapılandırın"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Sanal Gerçeklik dinleyici"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Durum sağlayıcı"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildirim yardımcısı"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Bildirim sıralama hizmeti"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Diğer seçenekler"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Dahili depolama birimi"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Dahili olarak paylaşılan depolama alanı"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kart"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kartı"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB sürücü"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Sabitlemeyi kaldırmadan önce şifre sor"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Uygulama yeniden boyutlandırılamaz. İki parmağınızla kaydırın."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Uygulama bölünmüş ekranda çalışmayabilir."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Uygulama bölünmüş ekranı desteklemiyor."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Yöneticiniz tarafından yüklendi"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Yöneticiniz tarafından güncellendi"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe seçildi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe seçildi</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Çeşitli"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Bu bildirimlerin önem derecesini ayarladınız."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Bu bildirimlerin önem derecesini ayarladınız."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Bu, dahil olan kişiler nedeniyle önemlidir."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi (bu hesaba sahip bir kullanıcı zaten var)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Dil tercihi"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Dil ekleyin"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Bölge tercihi"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını yazın"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Önerilen"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"İş modu KAPALI"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Uygulamalar, arka planda senkronizasyon ve ilgili özellikler dahil olmak üzere iş profilinin çalışmasına izin ver."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Aç"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s devre dışı bırakıldı"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s yöneticisi tarafından devre dışı bırakıldı. Daha fazla bilgi edinmek için kendileriyle iletişime geçin."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Yeni mesajlarınız var"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Görüntülemek için SMS uygulamasını açın"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Bazı işlevler sınırlı olabilir"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Sabitle"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Sabitlemeyi kaldır"</string>
     <string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı kısıtlama olmadan kullanmak için fabrika ayarlarına sıfırlayın"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha fazla bilgi edinmek için dokunun."</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f546d56..fe7be12 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -90,7 +90,6 @@
     <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>
@@ -234,13 +233,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Голос. підказки"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Блокувати зараз"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Вміст сховано згідно з правилом"</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="user_owner_label" msgid="1119010402169916617">"Перейти в особистий профіль"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Перейти в робочий профіль"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"отримувати доступ до контактів"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Геодані"</string>
@@ -913,6 +911,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редагувати за допомогою %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Надіслати через"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Надіслати через %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Надіслати через додаток"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Надіслати через додаток %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Вибрати головний додаток"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Зробити додаток %1$s головним"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Використ. за умовч. для цієї дії."</string>
@@ -929,7 +929,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Скинути та перезапустити додаток"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Надіслати відгук"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Закрити"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Вимкнути звук"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Вимкнути звук до перезавантаження пристрою"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Чекати"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Закрити додаток"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,7 +1061,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Дозвіл не потрібний"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"це платна послуга"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB для заряджання"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB-кабель, через який заряджається цей пристрій"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB-кабель, через який живиться під’єднаний пристрій"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перенесення файлів"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перенесення фотографій"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для режиму MIDI"</string>
@@ -1069,24 +1070,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Торкніться, щоб побачити більше опцій."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB завершено"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Торкніться, щоб вимкнути налагодження USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЙНЯТИ"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ВІДХИЛИТИ"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Створюється повідомлення про помилку…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Надіслати звіт про помилку?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Надсилається звіт про помилку…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Ваш IT-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему з пристроєм. Він може отримати доступ до ваших додатків і даних."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПОДІЛИТИСЯ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ВІДХИЛИТИ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Змінити клавіатуру"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Вибрати клавіатури"</string>
     <string name="show_ime" msgid="2506087537466597099">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
     <string name="hardware" msgid="194658061510127999">"Показати віртуальну клавіатуру"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Виберіть розкладку клавіатури"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Торкніться, щоб вибрати розкладку клавіатури."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Налаштуйте фізичну клавіатуру"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1159,8 +1153,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Обробник віртуальної реальності"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Постачальник умов"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Диспетчер сповіщень"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Служба встановлення пріоритетності сповіщень"</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>
@@ -1247,7 +1242,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Інші варіанти"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Внутрішня пам’ять"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Внутрішнє спільне сховище"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Карта SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Карта SD (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Носій USB"</string>
@@ -1493,7 +1488,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-код для відкріплення"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запитувати ключ розблокування перед відкріпленням"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запитувати пароль перед відкріпленням"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Розмір додатка не можна змінити. Прокручуйте його двома пальцями."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Додаток може не працювати в режимі розділеного екрана."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Додаток не підтримує розділення екрана."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Установив адміністратор"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Оновлено адміністратором"</string>
@@ -1581,12 +1576,11 @@
       <item quantity="many">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Інше"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Ви вказуєте пріоритет цих сповіщень."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Ви вказуєте пріоритет цих сповіщень."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Важливе з огляду на учасників."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g> (користувач із таким обліковим записом уже існує)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Вибір мови"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Додати мову"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Вибір регіону"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Введіть назву мови"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Пропозиції"</string>
@@ -1595,8 +1589,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Робочий профіль ВИМКНЕНО"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Увімкнути робочий профіль, зокрема додатки, фонову синхронізацію та пов’язані функції."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Увімкнути"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s вимкнено"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Вимкнув адміністратор %1$s. Зв’яжіться з ним, щоб дізнатися більше."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"У вас є нові повідомлення"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Щоб переглянути, відкрийте додаток для SMS"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Деякі функції можуть не працювати"</string>
@@ -1609,4 +1601,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Закріпити"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Відкріпити"</string>
     <string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Відновіть заводські параметри, щоб використовувати пристрій без обмежень"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Торкніться, щоб дізнатися більше."</string>
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 80d4c85..5236b7f 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"‏کالر ID کی ڈیفالٹ ترتیب غیر محدود کردہ ہے۔ اگلی کال: غیر محدود کردہ"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"سروس فراہم نہیں کی گئی۔"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"‏آپ کالر ID کی ترتیبات تبدیل نہیں کر سکتے ہیں۔"</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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"‎999+‎"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"مواد پالیسی کے تحت مخفی ہے"</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="user_owner_label" msgid="1119010402169916617">"ذاتی پر سوئچ کریں"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"کام پر سوئچ کریں"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"رابطے"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"اپنے رابطوں تک رسائی حاصل کریں"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"مقام"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏%1$s کے ساتھ ترمیم کریں"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"اس کے ساتھ اشتراک کریں"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"‏%1$s کے ساتھ اشتراک کریں"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"بھیجیں بذریعہ"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"‏بھیجیں بذریعہ ‎%1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"‏ایک Home ایپ منتخب کریں"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"‏%1$s کو Home کے بطور استعمال کریں"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"اس کارروائی کیلئے بطور ڈیفالٹ استعمال کریں۔"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"ایپ کو دوبارہ ترتیب دیں اور دوبارہ شروع کریں"</string>
     <string name="aerr_report" msgid="5371800241488400617">"تاثرات بھیجیں"</string>
     <string name="aerr_close" msgid="2991640326563991340">"بند کریں"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"خاموش کریں"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"آلہ دوبارہ اسٹارٹ ہونے تک خاموش رکھیں"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"انتظار کریں"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ایپ بند کریں"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"کوئی اجازتیں درکار نہیں ہیں"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"اس میں آپ کا پیسہ خرچ ہو سکتا ہے"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ٹھیک ہے"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏چارجنگ کیلئے USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏USB اس آلے کو چارج کر رہی ہے"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏منسلکہ آلے کو USB پاور سپلائی کر رہی ہے"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏فائل کی منتقلی کیلئے USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏تصویر کی منتقلی کیلئے USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏MIDI کیلئے USB"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"مزید اختیارات کیلئے ٹچ کریں۔"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏USB ڈیبگ کرنا مربوط ہو گیا"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"‏USB ڈیبگنگ کو غیر فعال کرنے کیلئے ٹچ کریں۔"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول کریں"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"مسترد کریں"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"بگ رپورٹ لی جا رہی ہے…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"بگ رپورٹ کا اشتراک کریں؟"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"بگ رپورٹ کا اشتراک ہو رہا ہے…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"‏آپ کے IT منتظم نے اس آلہ کا مسئلہ حل کرنے میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی ہے۔ ایپس اور ڈیٹا کا اشتراک ہو سکتا ہے۔"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراک کریں"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"مسترد کریں"</string>
     <string name="select_input_method" msgid="8547250819326693584">"کی بورڈ تبدیل کریں"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"کی بورڈز منتخب کریں"</string>
     <string name="show_ime" msgid="2506087537466597099">"‏جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
     <string name="hardware" msgid="194658061510127999">"ورچوئل کی بورڈ دکھائیں"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"کی بورڈ کا خاکہ منتخب کریں"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ایک کی بورڈ کا خاکہ منتخب کرنے کیلئے چھوئیں۔"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"فزیکل کی بورڈ کنفیگر کریں"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"وال پیپر"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"وال پیپر تبدیل کریں"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"اطلاع سننے والا"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"‏VR سامع"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"شرط فراہم کنندہ"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"اطلاع کا معاون"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"اطلاع کی درجہ بندی سروس"</string>
     <string name="vpn_title" msgid="19615213552042827">"‏VPN فعال ہوگیا"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"‏<xliff:g id="APP">%s</xliff:g> کے ذریعہ VPN فعال ہے"</string>
     <string name="vpn_text" msgid="3011306607126450322">"نیٹ ورک کا نظم کرنے کیلئے چھوئیں۔"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"مزید اختیارات"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"داخلی اسٹوریج"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"اندرونی اشتراک کردہ اسٹوریج"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"‏SD کارڈ"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏<xliff:g id="MANUFACTURER">%s</xliff:g> SD کارڈ"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"‏USB ڈرائیو"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"‏پن ہٹانے سے پہلے PIN طلب کریں"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ایپ ری سائز ایبل نہیں ہے، اسے دو انگلیوں کے ساتھ سکرول کریں۔"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"ممکن ہے کہ ایپ سپلٹ اسکرین کے ساتھ کام نہ کرے۔"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"آپ کے منتظم کی جانب سے انسٹال کر دیا گیا"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"آپ کے منتظم نے اپ ڈيٹ کر دیا"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> منتخب کردہ</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> منتخب کردہ</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقات"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"اس میں موجود لوگوں کی وجہ سے یہ اہم ہے۔"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں؟"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں (اس اکاؤنٹ کے ساتھ ایک صارف پہلے سے موجود ہے) ؟"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"زبان کی ترجیح"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"ایک زبان شامل کریں"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"علاقہ کی ترجیح"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"زبان کا نام ٹائپ کریں"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"تجویز کردہ"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"کام موڈ آف ہے"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"دفتری پروفائل کو کام کرنے دیں، بشمول ایپس، پس منظر کی مطابقت پذیری اور متعلقہ خصوصیات۔"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"آن کریں"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"‏%1$s غیر فعال کردہ"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"‏%1$s منتظم کی جانب سے غیر فعال کر دیا گیا۔ مزید جاننے کیلئے ان سے رابطہ کریں۔"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"آپ کے پاس نئے پیغامات ہیں"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"‏دیکھنے کیلئے SMS ایپ کھولیں"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"کچھ فعالیت محدود ہو سکتی ہے"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"پن کریں"</string>
     <string name="unpin_target" msgid="3556545602439143442">"پن ہٹائیں"</string>
     <string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"بغیر کسی حدود کے استعمال کرنے کیلئے اس آلے کو فیکٹری ری سیٹ کریں"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"مزید جاننے کیلئے ٹچ کریں۔"</string>
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 8b5e230..6cb65a3 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Qo‘ng‘iroq qiluvchi ma’lumotlari cheklanmagan. Keyingi qo‘ng‘iroq: cheklanmagan"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Xizmat ishalamaydi."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Qo‘ng‘iroq qiluvchining ID raqami sozlamasini o‘zgartirib bo‘lmaydi."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Cheklangan ruxsatlar o‘zgartirildi"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Ma’lumot xizmati bloklandi."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Favqulodda xizmati bloklandi."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Ovoz xizmati bloklandi."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ovozli yordam"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Qulflash"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Qoidaga muvofiq kontent yashirilgan"</string>
     <string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android tizimi"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Shaxsiy"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Ish"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Shaxsiy profilga o‘tish"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Ishchi profilga o‘tish"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarga kirish"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
@@ -894,13 +892,15 @@
     <string name="capital_on" msgid="1544682755514494298">"I"</string>
     <string name="capital_off" msgid="6815870386972805832">"O"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Ilovani tanlang"</string>
-    <string name="whichApplicationNamed" msgid="8260158865936942783">"“%1$s” ilovasi yordamida bajarish"</string>
+    <string name="whichApplicationNamed" msgid="8260158865936942783">"“%1$s” bilan ochish"</string>
     <string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
-    <string name="whichViewApplicationNamed" msgid="2286418824011249620">"“%1$s” yordamida ochish"</string>
+    <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s bilan ochish"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"“%1$s” yordamida tahrirlash"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Ulashish…"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"“%1$s” orqali ulashish"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Ilovani tanlang"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s orqali yuborish"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Bosh ilovani tanlash"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s: Bosh ilova sifatida foydalanish"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Ushbu amaldan standart sifatida foydalanish"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Ilovani qayta tiklash va qayta ishga tushirish"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Fikr-mulohaza yuborish"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Yopish"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"E’tiborsiz qoldirish"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Qurilma o‘chib yonguncha e’tiborsiz qoldirish"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Kuting"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Ilovani yopish"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -998,7 +998,7 @@
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct’ni ishga tushirish. Bu Wi-Fi mijoz/ulanish nuqtasini o‘chiradi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ishga tushirilmadi."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoqilgan"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoniq"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sozlamalarga kirish uchun bosing"</string>
     <string name="accept" msgid="1645267259272829559">"Qabul qilish"</string>
     <string name="decline" msgid="2112225451706137894">"Rad qilish"</string>
@@ -1019,7 +1019,7 @@
     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;ga xabar jo‘natishni xohlaydi."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Bunda, mobil hisobingizdan "<b>"to‘lov olinishi mumkin"</b>"."</string>
     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bunda, mobil hisobingizdan to‘lov olinishi mumkin."</b></string>
-    <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Jo‘natish"</string>
+    <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Yuborish"</string>
     <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Bekor qilish"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Tanlovim eslab qolinsin"</string>
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Siz buni keyinroq sozlamalar &gt; ilovalar menusidan o‘zgartirishingiz mumkin"</string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Hech qanday ruxsat talab qilinmaydi"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"buning uchun sizdan haq olinishi mumkin"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB orqali quvvatlash"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB orqali quvvatlash"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB orqali ulangan qurilma quvvatlanmoqda"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB orqali fayl o‘tkazish"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB orqali rasm o‘tkazish"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB orqali MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Sozlash uchun bosing."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"O‘chirib qo‘yish uchun bosing."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"QABUL QILISH"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RAD ETISH"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Xatoliklar hisoboti olinmoqda…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Xatoliklar hisoboti yuborilsinmi?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Xatoliklar hisoboti yuborilmoqda…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administratoringiz bu qurilma nosozliklarini tuzatish uchun xatoliklar hisobotini so‘ramoqda. Ilova va ma’lumotlardan foydalanilishi mumkin."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ULASHISH"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RAD ETISH"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Klaviaturani o‘zgartirish"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturani tanlash"</string>
     <string name="show_ime" msgid="2506087537466597099">"Tashqi klaviaturadan foydalanilayotganda buni ekranda saqlab turish"</string>
     <string name="hardware" msgid="194658061510127999">"Virtual klaviatura ko‘rsatilsin"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Tugmalar tartibini tanlash"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tugmalar tartibini tanlash uchun bosing."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Tashqi klaviaturani sozlash"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
@@ -1121,7 +1115,7 @@
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Qidirish"</string>
-    <string name="ime_action_send" msgid="2316166556349314424">"Jo‘natish"</string>
+    <string name="ime_action_send" msgid="2316166556349314424">"Yuborish"</string>
     <string name="ime_action_next" msgid="3138843904009813834">"Keyingi"</string>
     <string name="ime_action_done" msgid="8971516117910934605">"Tayyor"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Old."</string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fon rasmi"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Fon rasmini o‘zgartirish"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirishnoma tinglovchisi"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR rejimi"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Shartlarni taqdim etuvchi"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildirishnoma yordamchisi"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Bildirishnomalarni baholash xizmati"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN faollashtirildi"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> tomonidan faollashtirilgan"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Tarmoqni boshqarish uchun bosing."</string>
@@ -1156,7 +1151,7 @@
     <string name="upload_file" msgid="2897957172366730416">"Faylni tanlash"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Hech qanday fayl tanlanmadi"</string>
     <string name="reset" msgid="2448168080964209908">"Tiklash"</string>
-    <string name="submit" msgid="1602335572089911941">"Jo‘natish"</string>
+    <string name="submit" msgid="1602335572089911941">"Yuborish"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mashina usuli yoqilgan"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Avtomashina rejimidan chiqish uchun bosing."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"Modem rejimi yoniq"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Ko‘proq sozlamalar"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Ichki xotira"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Ichki umumiy xotira"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD karta"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kartasi"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB xotira"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Yechishda PIN-kod so‘ralsin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bo‘shatishdan oldin chizmali parol so‘ralsin"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bo‘shatishdan oldin parol so‘ralsin"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Oyna o‘lchamini o‘zgartirib bo‘lmaydi. Sahifani ikkita barmoq bilan aylantiring."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Ilova ekranni ikkiga bo‘lish rejimini qo‘llab-quvvatlamaydi."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Administratoringiz tomonidan o‘rnatilgan"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratoringiz tomonidan yangilandi"</string>
@@ -1511,7 +1506,7 @@
       <item quantity="other">%d soat</item>
       <item quantity="one">1 soat</item>
     </plurals>
-    <string name="zen_mode_until" msgid="7336308492289875088">"Ushbu vaqtgacha: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+    <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha (keyingi signal)"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Men o‘chirmaguncha"</string>
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"“Bezovta qilinmasin” rejimi o‘chirilmaguncha"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta tanlandi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta tanlandi</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Boshqa belgilar"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Bu odamlar siz uchun muhim."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi (bunday hisobdagi foydalanuvchi allaqachon mavjud) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Til sozlamalari"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Tilni qo‘shing"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Hudud sozlamalari"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Til nomini kiriting"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Taklif etiladi"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Ish rejimi O‘CHIQ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Ishchi profilini yoqish: ilovalar, fonda sinxronlash va bog‘liq funksiyalar."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Yoqish"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s o‘chirilgan"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"%1$s administratori tomonidan o‘chirilgan. Batafsil ma’lumot uchun bog‘laning."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Sizga yangi SMS keldi"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Ko‘rish uchun SMS ilovasini oching"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Ba’zi funksiyalar cheklanishi m-n"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Qadash"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Olib tashlash"</string>
     <string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu qurilmadan cheklovlarsiz foydalanish uchun zavod sozlamalarini tiklang"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ko‘proq o‘rganish uchun bosing."</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 7d4e43f..29eef92 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Số gọi đến mặc định thành không bị giới hạn. Cuộc gọi tiếp theo. Không bị giới hạn"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Dịch vụ không được cấp phép."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Bạn không thể thay đổi cài đặt ID người gọi."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Quyền truy cập bị giới hạn đã thay đổi"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Dịch vụ dữ liệu bị chặn."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Dịch vụ khẩn cấp đã bị chặn."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Dịch vụ thoại đã bị chặn."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Trợ lý thoại"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Khóa ngay"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Nội dung bị ẩn theo chính sách"</string>
     <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Cá nhân"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Cơ quan"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Chuyển sang Cá nhân"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Chuyển sang Công việc"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Danh bạ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"truy cập vào danh bạ của bạn"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Vị trí"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Chỉnh sửa bằng %1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Chia sẻ với"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Chia sẻ với %1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Gửi bằng"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Gửi bằng %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Chọn ứng dụng Home"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Sử dụng %1$s làm Home"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Sử dụng theo mặc định đối với tác vụ này."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Đặt lại và khởi động lại ứng dụng"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Gửi phản hồi"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Đóng"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Bỏ qua"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Tắt tiếng cho đến khi thiết bị khởi động lại"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Đợi"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Đóng ứng dụng"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Không yêu cầu quyền"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"bạn có thể mất tiền vì điều này"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB để sạc"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Sạc qua USB thiết bị này"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Nguồn cấp điện qua USB cho thiết bị được kết nối"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB để truyền tệp"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB để truyền ảnh"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB cho MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Chạm để có các tùy chọn khác."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Chạm để vô hiệu hóa gỡ lỗi USB."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"CHẤP NHẬN"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TỪ CHỐI"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Đang thu thập báo cáo lỗi…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chia sẻ báo cáo lỗi?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Đang chia sẻ báo cáo lỗi…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Quản trị viên CNTT của bạn đã yêu cầu báo cáo lỗi để giúp khắc phục sự cố thiết bị này. Bạn có thể chia sẻ ứng dụng và dữ liệu."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"CHIA SẺ"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TỪ CHỐI"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Thay đổi bàn phím"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Chọn bàn phím"</string>
     <string name="show_ime" msgid="2506087537466597099">"Tiếp tục sử dụng ứng dụng trên màn hình trong khi bàn phím thực đang hoạt động"</string>
     <string name="hardware" msgid="194658061510127999">"Hiển thị bàn phím ảo"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Chọn bố cục bàn phím"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Chạm để chọn bố cục bàn phím."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Định cấu hình bàn phím thực"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Trình nghe VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Trình cung cấp điều kiện"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Trợ lý thông báo"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Dịch vụ xếp hạng thông báo"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Tùy chọn khác"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Bộ nhớ trong"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Bộ nhớ trong dùng chung"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Thẻ SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Thẻ SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Ổ USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Hỏi mã PIN trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Hỏi hình mở khóa trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Hỏi mật khẩu trước khi bỏ ghim"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Ứng dụng không đổi kích thước được, hãy cuộn ứng dụng bằng hai ngón tay."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Ứng dụng có thể không hoạt động với tính năng chia đôi màn hình."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Được cài đặt bởi quản trị viên của bạn"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Được cập nhật bởi quản trị viên của bạn"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">Đã chọn <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Đã chọn <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Khác"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Bạn đặt tầm quan trọng của các thông báo này."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Bạn đặt tầm quan trọng của các thông báo này."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Thông báo này quan trọng vì những người có liên quan."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g> (người dùng có tài khoản này đã tồn tại)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Tùy chọn ngôn ngữ"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Thêm ngôn ngữ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Tùy chọn khu vực"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nhập tên ngôn ngữ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ðược đề xuất"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Chế độ làm việc đang TẮT"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Cho phép hồ sơ công việc hoạt động, bao gồm ứng dụng, đồng bộ hóa trong nền và các tính năng liên quan."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Bật"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s đã bị tắt"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Đã bị quản trị viên %1$s tắt. Hãy liên hệ với quản trị viên để tìm hiểu thêm."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Bạn có tin nhắn mới"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Mở ứng dụng SMS để xem"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Một số chức năng có thể bị hạn chế"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Ghim"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Bỏ ghim"</string>
     <string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Khôi phục cài đặt gốc để sử dụng thiết bị này mà không bị hạn chế"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Chạm để tìm hiểu thêm."</string>
 </resources>
diff --git a/core/res/res/values-w426dp-land/integers.xml b/core/res/res/values-w426dp-land/integers.xml
new file mode 100644
index 0000000..94abbec
--- /dev/null
+++ b/core/res/res/values-w426dp-land/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <integer name="date_picker_mode">2</integer>
+    <integer name="time_picker_mode">2</integer>
+</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b8ea898..3b26e46 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 条)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"内容已隐藏(根据政策规定)"</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="user_owner_label" msgid="1119010402169916617">"切换到“个人”"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"切换到“工作”"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"访问您的通讯录"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用%1$s编辑"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"分享方式"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"使用%1$s分享"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"通过以下应用发送"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"通过1$s发送"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"选择主屏幕应用"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"将“%1$s”设为主屏幕应用"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"设为默认选项。"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"重置并重启应用"</string>
     <string name="aerr_report" msgid="5371800241488400617">"发送反馈"</string>
     <string name="aerr_close" msgid="2991640326563991340">"关闭"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"忽略(直到设备重启)"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"等待"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"关闭应用"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"不需要任何权限"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"这可能会产生费用"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"确定"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"正在通过 USB 充电"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在通过 USB 为此设备充电"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在通过 USB 为连接的设备充电"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"正在通过 USB 传输文件"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"正在通过 USB 传输照片"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"正在通过 USB 连接到 MIDI 接口"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"触摸以查看更多选项。"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到USB调试"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"触摸可停用USB调试。"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒绝"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在生成错误报告…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享错误报告吗?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享错误报告…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"您的 IT 管理员希望获取错误报告,以便排查此设备的问题。报告可能会透露您设备上的应用和数据。"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒绝"</string>
     <string name="select_input_method" msgid="8547250819326693584">"更改键盘"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"选择键盘"</string>
     <string name="show_ime" msgid="2506087537466597099">"连接到实体键盘时使其在屏幕上保持显示状态"</string>
     <string name="hardware" msgid="194658061510127999">"显示虚拟键盘"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"选择键盘布局"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"触摸可选择键盘布局。"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"配置实体键盘"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR 监听器"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知助手"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"通知重要性排序服务"</string>
     <string name="vpn_title" msgid="19615213552042827">"已激活VPN"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>已激活VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多选项"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s:%2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s - %2$s:%3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"内部存储设备"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"内部共享存储空间"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD卡"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 卡"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"U 盘"</string>
@@ -1339,9 +1334,9 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"删除"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"要将音量调高到推荐水平以上吗?\n\n长时间保持高音量可能会损伤听力。"</string>
-    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持续按住双指即可启用无障碍功能。"</string>
-    <string name="accessibility_enabled" msgid="1381972048564547685">"无障碍功能已启用。"</string>
-    <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消无障碍功能。"</string>
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持续按住双指即可启用辅助功能。"</string>
+    <string name="accessibility_enabled" msgid="1381972048564547685">"辅助功能已启用。"</string>
+    <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消辅助功能。"</string>
     <string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="user_switching_message" msgid="2871009331809089783">"正在切换为<xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="8939524935808875155">"正在将<xliff:g id="NAME">%1$s</xliff:g>退出帐号…"</string>
@@ -1473,12 +1468,12 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消时要求绘制解锁图案"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消时要求输入密码"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"无法调整该应用的大小,请用双指滚动该应用。"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"应用可能无法在分屏模式下正常运行。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"应用不支持分屏。"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理员安装"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"已被管理员删除"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,节电助手会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n节电助手会在设备充电时自动关闭。"</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,省电模式会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n省电模式会在设备充电时自动关闭。"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d 分钟(到<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">1 分钟(到<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1543,12 +1538,11 @@
       <item quantity="other">已选择 <xliff:g id="COUNT_1">%1$d</xliff:g> 项</item>
       <item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"这些通知的重要性由您来设置。"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"这些通知的重要性由您来设置。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定的人,因此被归为重要通知。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"语言偏好设置"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"添加语言"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"区域偏好设置"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建议语言"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已关闭"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"启用工作资料,包括应用、后台同步和相关功能。"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"开启"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"%1$s已被禁用"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"该软件包已被%1$s管理员禁用。请与管理员联系以了解详情。"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"您有新消息"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"打开短信应用查看"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"部分功能可能会受到限制"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"固定"</string>
     <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
     <string name="app_info" msgid="6856026610594615344">"应用信息"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"恢复出厂设置即可正常使用此设备,不受任何限制"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"触摸即可了解详情。"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 5464fbf..28f2bac 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"語音助手"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"已根據政策隱藏內容"</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="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"切換至工作設定檔"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通訊錄"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的通訊錄"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"分享對象"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"與 %1$s 分享"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"使用以下應用程式傳送:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"使用「%1$s」傳送"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"選取主螢幕應用程式"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"使用「%1$s」作為主螢幕"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"設定用於執行這項操作。"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"重設並重新啟動應用程式"</string>
     <string name="aerr_report" msgid="5371800241488400617">"傳送意見反映"</string>
     <string name="aerr_close" msgid="2991640326563991340">"關閉"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"忽略直至裝置重新啟動"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"等一下"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"關閉應用程式"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"不需授權"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"這可能需要付費"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB 充電"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在透過 USB 為此裝置充電"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在透過 USB 為已連接的裝置供電"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB 檔案傳輸"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB 相片傳輸"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"輕觸以瀏覽更多選項。"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在取得錯誤報告…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"您的 IT 管理員要求您提供錯誤報告,以協助解決此裝置的問題。報告可能包含應用程式和相關資料。"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
     <string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
     <string name="show_ime" msgid="2506087537466597099">"在實體鍵盤處於連接狀態時保持顯示"</string>
     <string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"選取鍵盤配置"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"輕觸即可選取鍵盤配置。"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"設定實體鍵盤"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"虛擬現實接聽器"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件供應商"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"通知排序服務"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN 已啟用。"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網絡。"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多選項"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s:%2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s (%2$s):%3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"內部儲存空間"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"內部共用儲存空間"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 記憶卡"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 卡"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB 驅動器"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"無法調整應用程式的大小,請用兩隻手指捲動此應用程式。"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"應用程式可能無法在分割畫面中運作。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"應用程式不支援分割畫面。"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理員安裝"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"已由您的管理員更新"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
       <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"您可以為這些通知設定重要性。"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"您可以設定這些通知的重要性。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及的人。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者 (此帳戶目前已有此使用者) 嗎?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"語言偏好設定"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"新增語言"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"輸入語言名稱"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"推薦"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已關閉"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"允許使用應用程式、背景同步及相關功能的工作設定檔。"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"開啟"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"已停用「%1$s」"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"「%1$s」管理員已停用此套件。請與管理員聯絡以瞭解詳情。"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"您有新的訊息"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"開啟短訊應用程式查看內容"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"部分功能可能會受到限制"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"固定"</string>
     <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
     <string name="app_info" msgid="6856026610594615344">"應用程式資料"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"將此裝置回復至原廠設定後,使用將不受限制"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸以瞭解詳情。"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ff6dc23..dfc7890 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -88,7 +88,6 @@
     <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>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"內容已依據政策隱藏"</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="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"切換至公司設定檔"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"聯絡人"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的聯絡人"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"選擇分享工具"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"透過 %1$s 分享"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"透過以下應用程式傳送:"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"透過「%1$s」傳送"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"選取主螢幕應用程式"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"使用「%1$s」做為主螢幕"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"設為預設應用程式。"</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"重設並重新啟動應用程式"</string>
     <string name="aerr_report" msgid="5371800241488400617">"提供意見"</string>
     <string name="aerr_close" msgid="2991640326563991340">"關閉"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"略過直到裝置重新啟動"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"等候"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"關閉應用程式"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"無須許可"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"這可能需要付費"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"正在透過 USB 充電"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在透過 USB 為這個裝置充電"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在透過 USB 為連接的裝置供電"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB 檔案傳輸"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB 相片傳輸"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"輕觸即可顯示更多選項。"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在接收錯誤報告…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"您的 IT 管理員要求您提供錯誤報告,以便排解這個裝置發生的問題。報告可能會揭露裝置中的應用程式和相關資料。"</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
     <string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
     <string name="show_ime" msgid="2506087537466597099">"有連接的實體鍵盤時保持顯示"</string>
     <string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"選取鍵盤配置"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"輕觸即可選取鍵盤配置。"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"設定實體鍵盤"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
@@ -1143,8 +1137,9 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR 接聽器"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件提供者"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"通知重要性排序服務"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN 已啟用"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多選項"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s:%2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s - %2$s:%3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"內部儲存空間"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"內部共用儲存空間"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 卡"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 卡"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB 隨身碟"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"無法調整這個應用程式的大小,請用雙指捲動該應用程式。"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"應用程式可能無法在分割畫面中運作。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"這個應用程式不支援分割畫面。"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理員安裝"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"由您的管理員更新"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
       <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"這些通知的重要性由您決定。"</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"這些通知的重要性由您決定。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"這則通知涉及特定人士,因此被歸為重要通知。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"要允許 <xliff:g id="APP">%1$s</xliff:g> 為 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"要允許 <xliff:g id="APP">%1$s</xliff:g> 為 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎 (這個帳戶目前已有使用者)?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"語言偏好設定"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"新增語言"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"請輸入語言名稱"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議語言"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work 模式已關閉"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"啟用 Work 設定檔,包括應用程式、背景同步處理和相關功能。"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"開啟"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"已由「%1$s」停用"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"這個套件已由「%1$s」管理員停用。請與對方聯絡以瞭解詳情。"</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"您有新訊息"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"開啟簡訊應用程式來查看內容"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"部分功能可能受到鎖定"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"固定"</string>
     <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
     <string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"恢復原廠設定即可正常使用這個裝置"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸即可瞭解詳情。"</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 6793a9a..e32f26b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -88,7 +88,6 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"I-ID Yomshayeli ishintshela kokungavinjelwe. Ucingo olulandelayo: Aluvinjelwe"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Isevisi ayilungiselelwe."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Ngeke ukwazi ukuguqul izilungiselelo zemininingwane yoshayayo."</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ukufinyelela okuvinjelwe kushintshiwe"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Isevisi yedatha ivaliwe."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Isevisi ephuthumayo ivimbelwe."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Isevisi yezwi ivimbelwe."</string>
@@ -230,13 +229,12 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Isisekeli sezwi"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Khiya manje"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string>
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Okuqukethwe kufihlwe inqubomgomo"</string>
     <string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Okomuntu siqu"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Umsebenzi"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"Shintshela komuntu siqu"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Shintshela kumsebenzi"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Oxhumana nabo"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"finyelela koxhumana nabo"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Indawo"</string>
@@ -901,6 +899,8 @@
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Hlela nge-%1$s"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Yabelana no-"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Yabelana no-%1$s"</string>
+    <string name="whichSendToApplication" msgid="8272422260066642057">"Thumela usebenzisa"</string>
+    <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Thumela usebenzisa i-%1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Khetha uhlelo lokusebenza lasekhaya"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Sebenzisa i-%1$s njengekhaya"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Sebenzisa ngokuzenzakalelayo kulesenzo."</string>
@@ -917,7 +917,7 @@
     <string name="aerr_reset" msgid="7645427603514220451">"Setha kabusha uphinde uqalise kabusha uhlelo lokusebenza"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Thumela impendulo"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Vala"</string>
-    <string name="aerr_mute" msgid="7698966346654789433">"Thulisa"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"Thulisa ize iqalise kabusha idivayisi"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Linda"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"Vala uhlelo lokusebenza"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1045,7 +1045,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Ayikho imvume edingekayo"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"lokhu kungakudlela imali"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"KULUNGILE"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"I-USB yokushaja"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"I-USB ishaja le divayisi"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"I-USB inikeza amandla kudivayisi enamathiselwe"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"I-USB yokudluliswa kwefayela"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"I-USB yokudluliswa kwesithombe"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"I-USB ye-MIDI"</string>
@@ -1053,24 +1054,17 @@
     <string name="usb_notification_message" msgid="7347368030849048437">"Thinta ukuze uthole ezinye izinketho."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Thinta ukwenza ukuthi ukudibhaga kwe-USB kungasebenzi."</string>
-    <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_title (7692523022154791488) -->
-    <skip />
-    <!-- no translation found for share_remote_bugreport_notification_message (8643704339578372992) -->
-    <skip />
-    <!-- no translation found for share_finished_remote_bugreport_notification_message (4627312060769912353) -->
-    <skip />
-    <!-- no translation found for sharing_remote_bugreport_notification_message (673106383408474893) -->
-    <skip />
-    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"YAMUKELA"</string>
-    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"YENQABA"</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Ithatha umbiko wesiphazamisi..."</string>
+    <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Yabelana ngombiko wesiphazamisi?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Yabelana ngombiko wesiphazamisi..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Umqondisi wakho we-IT ucele umbiko wesiphazamisi ukukusiza ukuxazulula inkinga kule divayisi. Izinhlelo zokusebenza nedatha ingabiwa."</string>
+    <string name="share_remote_bugreport_action" msgid="6249476773913384948">"YABELANA"</string>
+    <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"YENQABA"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Shintsha ikhibhodi"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Khetha amakhibhodi"</string>
     <string name="show_ime" msgid="2506087537466597099">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
     <string name="hardware" msgid="194658061510127999">"Bonisa ikhibhodi ebonakalayo"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Khetha isendlalelo sekhibhodi"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Thinta ukuze ukhethe isendlalelo sekhibhodi."</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Lungisa ikhibhodi yoqobo"</string>
+    <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
@@ -1143,8 +1137,9 @@
     <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>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Isilaleli se-VR"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Umhlinzeki wesimo"</string>
-    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Umsizi wesaziso"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Isevisi yesilinganisi sesaziso"</string>
     <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>
@@ -1229,7 +1224,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Izinketho ezingaphezulu"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Isitoreji sangaphakathi"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Isitoreji esabiwe sangaphakathi"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Ikhadi le-SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> ikhadi le-SD"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Idrayivu ye-USB"</string>
@@ -1473,7 +1468,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Cela iphinikhodi ngaphambi kokuphina"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Cela iphethini yokuvula ngaphambi kokususa ukuphina"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Cela iphasiwedi ngaphambi kokususa ukuphina"</string>
-    <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Uhlelo lokusebenza alukwazi ukunikezwa usayizi omusha, liskrole ngeminwe emibili."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Izinhlelo zokusebenza kungenzeka zingasebenzi ngesikrini esihlukanisiwe."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Ifakwe ngumlawuli wakho"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ibuyekezwe ngumqondisi wakho"</string>
@@ -1543,12 +1538,11 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
     </plurals>
-    <string name="default_notification_topic_label" msgid="227586145791870829">"Okwahlukahlukene"</string>
-    <string name="importance_from_topic" msgid="3572280439880023233">"Usethe ukubaluleka kwalezi zaziso."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Usethe ukubaluleka kwalezi zaziso."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukudala umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukudala umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> (umsebenzisi onale akhawunti usuvel ukhona) ?"</string>
-    <string name="language_selection_title" msgid="7181332986330337171">"Okuncamelayo kolimi"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Engeza ulwimi"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Okuncamelayo kwesifunda"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Thayipha igama lolimi"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Okuphakanyisiwe"</string>
@@ -1557,8 +1551,6 @@
     <string name="work_mode_off_title" msgid="8954725060677558855">"Imodi yomsebenzi IVALIWE"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Vumela iphrofayela yomsebenzi ukuze isebenze, efaka izinhlelo zokusebenza, ukuvumelanisa kwangemuva, nezici ezisondelene."</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Vula"</string>
-    <string name="suspended_package_title" msgid="3408150347778524435">"I-%1$s ikhutshaziwe"</string>
-    <string name="suspended_package_message" msgid="6341091587106868601">"Ikhutshazwe umlawuli we-%1$s. Xhumana nabo ukuze ufunde kabanzi."</string>
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Unemilayezo emisha"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Vula uhlelo lokusebenza lwe-SMS ukuze ubuke"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Okunye ukusebenza kungakhawulelwe"</string>
@@ -1571,4 +1563,7 @@
     <string name="pin_target" msgid="3052256031352291362">"Phina"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Susa ukuphina"</string>
     <string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string>
+    <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="audit_safemode_notification" msgid="6416076898350685856">"Setha kabusha ukuze usebenzise idivayisi ngaphandle kwemikhawulo"</string>
+    <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Thinta ukuze ufunde kabanzi."</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4480944..0ed1f13 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -593,6 +593,9 @@
              the appearance matches the branding of the app requesting the fingerprint scan.-->
         <attr name="fingerprintAuthDrawable" format="reference" />
 
+	<!-- Asset that should be used to show users the position of the NFC antenna on the device. -->
+	<attr name="nfcAntennaPositionDrawable" format="reference" />
+
         <!-- ============ -->
         <!-- Panel styles -->
         <!-- ============ -->
@@ -2843,6 +2846,11 @@
             <!-- Pointer icon of a hand sign while grabbing something. -->
             <enum name="grabbing" value="1021" />
         </attr>
+
+        <!-- Whether this view has elements that may overlap when drawn. See
+             {@link android.view.View#forceHasOverlappingRendering(boolean)}. -->
+        <attr name="forceHasOverlappingRendering" format="boolean" />
+
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3520,6 +3528,13 @@
              This setting implies fastScrollEnabled. -->
         <attr name="fastScrollAlwaysVisible" format="boolean" />
     </declare-styleable>
+    <!-- @hide -->
+    <declare-styleable name="RecycleListView">
+        <!-- Bottom padding to use when no buttons are present. -->
+        <attr name="paddingBottomNoButtons" format="dimension" />
+        <!-- Top padding to use when no title is present. -->
+        <attr name="paddingTopNoTitle" format="dimension" />
+    </declare-styleable>
     <declare-styleable name="AbsSpinner">
         <!-- Reference to an array resource that will populate the Spinner.  For static content,
              this is simpler than populating the Spinner programmatically. -->
@@ -3539,6 +3554,9 @@
              If no format string is specified, the Chronometer will simply display
              "MM:SS" or "H:MM:SS". -->
         <attr name="format" format="string" localization="suggested" />
+        <!-- Specifies whether this Chronometer counts down or counts up from the base.
+              If not specified this is false and the Chronometer counts up. -->
+        <attr name="countDown" format="boolean" />
     </declare-styleable>
     <declare-styleable name="CompoundButton">
         <!-- Indicates the initial checked state of this button. -->
@@ -4373,8 +4391,7 @@
         <attr name="autoLink" />
         <!-- If set to false, keeps the movement method from being set
              to the link movement method even if autoLink causes links
-             to be found or the input text contains a
-             {@link android.text.style.ClickableSpan ClickableSpan}. -->
+             to be found. -->
         <attr name="linksClickable" format="boolean" />
         <!-- If set, specifies that this TextView has a numeric input method.
              The default is false.
@@ -5870,6 +5887,12 @@
         </attr>
         <!-- sets the Miter limit for a stroked path -->
         <attr name="strokeMiterLimit" format="float"/>
+        <!-- sets the fillType for a path. It is the same as SVG's "fill-rule" properties.
+             For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty -->
+        <attr name="fillType" format="enum">
+            <enum name="nonZero" value="0"/>
+            <enum name="evenOdd" value="1"/>
+        </attr>
     </declare-styleable>
 
     <!-- Defines the clip path used in VectorDrawables. -->
@@ -7627,6 +7650,12 @@
         <!-- Minimum inset for content views within a bar. Navigation buttons and
              menu views are excepted. Only valid for some themes and configurations. -->
         <attr name="contentInsetRight" format="dimension" />
+        <!-- Minimum inset for content views within a bar when a navigation button
+             is present, such as the Up button. Only valid for some themes and configurations. -->
+        <attr name="contentInsetStartWithNavigation" format="dimension" />
+        <!-- Minimum inset for content views within a bar when actions from a menu
+             are present. Only valid for some themes and configurations. -->
+        <attr name="contentInsetEndWithActions" format="dimension" />
         <!-- Elevation for the action bar itself -->
         <attr name="elevation" />
         <!-- Reference to a theme that should be used to inflate popups
@@ -7994,6 +8023,8 @@
         <attr name="contentInsetEnd" />
         <attr name="contentInsetLeft" />
         <attr name="contentInsetRight" />
+        <attr name="contentInsetStartWithNavigation" />
+        <attr name="contentInsetEndWithActions" />
         <attr name="maxButtonHeight" format="dimension" />
         <attr name="navigationButtonStyle" format="reference" />
         <attr name="buttonGravity">
@@ -8045,12 +8076,19 @@
          {@link android.media.tv.TvInputService#SERVICE_META_DATA} meta-data entry.
          Described here are the attributes that can be included in that tag. -->
     <declare-styleable name="TvInputService">
-        <!-- Component name of an activity for setup of this service.
-             The setup includes scanning channels and registering EPG data. -->
+        <!-- Component name of an activity that allows the user to set up this service. -->
         <attr name="setupActivity" format="string" />
-        <!-- Component name of an activity that allows the user to modify
-             the settings for this service. -->
+        <!-- Component name of an activity that allows the user to modify the settings for this
+             service. -->
         <attr name="settingsActivity" />
+        <!-- Attribute whether the TV input service can record programs. This value can be changed
+             at runtime by calling
+             {@link android.media.tv.TvInputService#updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo)}. -->
+        <attr name="canRecord" format="boolean" />
+        <!-- The number of tuners that the TV input service is associated with. This value can be
+             changed at runtime by calling
+             {@link android.media.tv.TvInputService#updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo)}. -->
+        <attr name="tunerCount" format="integer" />
     </declare-styleable>
 
     <!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the
@@ -8160,6 +8198,8 @@
              Defined in same coordinates as the path itself -->
         <attr name="endY" format="float" />
 
+        <!-- Defines the tile mode of the gradient. SweepGradient don't support tiling. -->
+        <attr name="tileMode"/>
     </declare-styleable>
 
     <!-- Describes an item of a GradientColor. Minimally need 2 items to define the gradient
@@ -8172,4 +8212,15 @@
         <!-- The current color for the offset inside the gradient. -->
         <attr name="color" />
     </declare-styleable>
+
+    <!-- @hide Attributes which will be read by the Activity to intialize the 
+               base activity TaskDescription. -->
+    <declare-styleable name="ActivityTaskDescription">
+        <!-- @hide From Theme.colorPrimary, used for the TaskDescription primary 
+                   color. -->
+        <attr name="colorPrimary" />
+        <!-- @hide From Theme.colorBackground, used for the TaskDescription background 
+                   color. -->
+        <attr name="colorBackground" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4b81987..5b4364d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -109,13 +109,6 @@
          included in the system image. Third-party apps cannot use it.</em> -->
     <attr name="allowClearUserData" format="boolean" />
 
-    <!-- Option to let applications specify that user data should
-         never be encrypted if an Encrypted File System solution
-         is enabled. Specifically, this is an "opt-out" feature, meaning
-         that, by default, user data will be encrypted if the EFS feature
-         is enabled. -->
-    <attr name="neverEncrypt" format="boolean" />
-
     <!-- Option to indicate this application is only for testing purposes.
          For example, it may expose functionality or data outside of itself
          that would cause a security hole, but is useful for testing.  This
@@ -232,6 +225,9 @@
             granted any application pre-installed on the system image (not just privileged
             apps). -->
         <flag name="preinstalled" value="0x400" />
+        <!-- Additional flag from base permission type: this permission can be automatically
+            granted to the setup wizard app -->
+        <flag name="setup" value="0x800" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
@@ -248,9 +244,12 @@
              may cost the user money.  Such permissions may be highlighted
              when shown to the user with this additional information.  -->
         <flag name="costsMoney" value="0x0001" />
-        <!-- Additional flag from base permission type: this permission is hidden
-             and should not show in the UI. -->
-        <flag name="hidden" value="0x2" />
+        <!-- Additional flag from base permission type: this permission has been
+             removed and it is no longer enforced. It shouldn't be shown in the
+             UI. Removed permissions are kept as normal permissions for backwards
+             compatibility as apps may be checking them before calling an API.
+        -->
+        <flag name="removed" value="0x2" />
     </attr>
 
     <!-- Specified the name of a group that this permission is associated
@@ -576,10 +575,10 @@
          single integer, with higher numbers considered to be better. -->
     <attr name="priority" format="integer" />
 
-    <!-- Indicate if this component is aware of encryption lifecycle, and can be
+    <!-- Indicate if this component is aware of direct boot lifecycle, and can be
          safely run before the user has entered their credentials (such as a lock
          pattern or PIN). -->
-    <attr name="encryptionAware" format="boolean" />
+    <attr name="directBootAware" format="boolean" />
 
     <!-- Specify how an activity should be launched.  See the
          <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
@@ -1259,7 +1258,6 @@
         <attr name="restoreNeedsApplication" />
         <attr name="restoreAnyVersion" />
         <attr name="backupInForeground" />
-        <attr name="neverEncrypt" />
         <!-- Request that your application's processes be created with
              a large Dalvik heap.  This applies to <em>all</em> processes
              created for the application.  It only applies to the first
@@ -1303,8 +1301,8 @@
         <attr name="usesCleartextTraffic" />
         <attr name="multiArch" />
         <attr name="extractNativeLibs" />
-        <attr name="forceDeviceEncrypted" format="boolean" />
-        <attr name="encryptionAware" />
+        <attr name="defaultToDeviceProtectedStorage" format="boolean" />
+        <attr name="directBootAware" />
         <attr name="resizeableActivity" />
     </declare-styleable>
     <!-- The <code>permission</code> tag declares a security permission that can be
@@ -1683,7 +1681,7 @@
         <attr name="enabled" />
         <attr name="exported" />
         <attr name="singleUser" />
-        <attr name="encryptionAware" />
+        <attr name="directBootAware" />
     </declare-styleable>
 
     <!-- Attributes that can be supplied in an AndroidManifest.xml
@@ -1767,7 +1765,7 @@
              with it is through the Service API (binding and starting). -->
         <attr name="isolatedProcess" format="boolean" />
         <attr name="singleUser" />
-        <attr name="encryptionAware" />
+        <attr name="directBootAware" />
         <!-- If the service is an {@link android.R.attr#isolatedProcess} service, this permits a
              client to bind to the service as if it were running it its own package.  The service
              must also be {@link android.R.attr#exported} if this flag is set. -->
@@ -1807,7 +1805,7 @@
         <attr name="enabled" />
         <attr name="exported" />
         <attr name="singleUser" />
-        <attr name="encryptionAware" />
+        <attr name="directBootAware" />
     </declare-styleable>
 
     <!-- The <code>activity</code> tag declares an
@@ -1880,7 +1878,7 @@
         <attr name="supportsPictureInPicture" />
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
-        <attr name="encryptionAware" />
+        <attr name="directBootAware" />
         <!-- @hide This activity is always focusable regardless of if it is in a task/stack whose
              activities are normally not focusable.
              For example, {@link android.R.attr#supportsPictureInPicture} activities are placed
@@ -2267,13 +2265,20 @@
         <!-- Where to initially position the activity inside the available space. Uses constants
              defined in {@link android.view.Gravity}. -->
         <attr name="gravity" />
+        <!-- Minimal width of the activity.
+
+         <p><strong>NOTE:</strong> A task's root activity value is applied to all additional
+         activities launched in the task. That is if the root activity of a task set minimal width,
+         then the system will set the same minimal width on all other activities in the task. It
+         will also ignore any other minimal width attributes of non-root activities. -->
+        <attr name="minimalWidth" format="dimension" />
         <!-- Minimal height of the activity.
 
          <p><strong>NOTE:</strong> A task's root activity value is applied to all additional
-         activities launched in the task. That is if the root activity of a task set minimal size,
-         then the system will set the same minimal size on all other activities in the task. It will
-         also ignore any other minimal size attributes of non-root activities. -->
-        <attr name="minimalSize" format="dimension" />
+         activities launched in the task. That is if the root activity of a task set minimal height,
+         then the system will set the same minimal height on all other activities in the task. It
+         will also ignore any other minimal height attributes of non-root activities. -->
+        <attr name="minimalHeight" format="dimension" />
     </declare-styleable>
 
 </resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 7711825..bddd225 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -130,11 +130,15 @@
     <drawable name="notification_template_divider">#29000000</drawable>
     <drawable name="notification_template_divider_media">#29ffffff</drawable>
 
+    <color name="notification_material_background_color">#ffffffff</color>
+
     <color name="notification_default_color">#757575</color> <!-- Gray 600 -->
     <color name="notification_icon_default_color">@color/notification_default_color</color>
 
     <color name="notification_progress_background_color">@color/secondary_text_material_light</color>
 
+    <color name="notification_action_list">#ffeeeeee</color>
+
     <!-- Keyguard colors -->
     <color name="keyguard_avatar_frame_color">#ffffffff</color>
     <color name="keyguard_avatar_frame_shadow_color">#80000000</color>
@@ -176,4 +180,7 @@
 
     <!-- Status bar color for semi transparent mode. -->
     <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
+
+    <color name="resize_shadow_start_color">#2a000000</color>
+    <color name="resize_shadow_end_color">#00000000</color>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3a185d6..b4371c1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -29,6 +29,7 @@
     <string-array name="config_statusBarIcons">
         <item><xliff:g id="id">@string/status_bar_rotate</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_headset</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_data_saver</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_ime</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_sync_failing</xliff:g></item>
@@ -56,6 +57,7 @@
 
     <string translatable="false" name="status_bar_rotate">rotate</string>
     <string translatable="false" name="status_bar_headset">headset</string>
+    <string translatable="false" name="status_bar_data_saver">data_saver</string>
     <string translatable="false" name="status_bar_managed_profile">managed_profile</string>
     <string translatable="false" name="status_bar_ime">ime</string>
     <string translatable="false" name="status_bar_sync_failing">sync_failing</string>
@@ -441,6 +443,9 @@
     <!-- Boolean indicating whether or not wifi firmware debugging is enabled -->
     <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">true</bool>
 
+    <!-- Integer size limit, in KB, for a single WifiLogger ringbuffer -->
+    <integer translatable="false" name="config_wifi_logger_ring_buffer_size_limit_kb">32</integer>
+
     <!-- Boolean indicating whether or not wifi should turn off when emergency call is made -->
     <bool translatable="false" name="config_wifi_turn_off_during_emergency_call">false</bool>
 
@@ -573,6 +578,9 @@
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
 
+    <!-- Fast brightness animation ramp rate -->
+    <integer translatable="false" name="config_brightness_ramp_rate_fast">200</integer>
+
     <!-- Don't name config resources like this.  It should look like config_annoyDianne -->
     <bool name="config_annoy_dianne">true</bool>
 
@@ -800,6 +808,13 @@
     -->
     <integer name="config_longPressOnPowerBehavior">1</integer>
 
+    <!-- Control the behavior when the user long presses the back button.  Non-zero values are only
+         valid for watches as part of CDD/CTS.
+            0 - Nothing
+            1 - Go to voice assist
+    -->
+    <integer name="config_longPressOnBackBehavior">0</integer>
+
     <!-- Control the behavior when the user short presses the power button.
             0 - Nothing
             1 - Go to sleep (doze)
@@ -1848,6 +1863,10 @@
         <item>-1</item>
     </integer-array>
 
+    <!-- When true, local displays that do not contain any of their own content will automatically
+         mirror the content of the default display. -->
+    <bool name="config_localDisplaysMirrorContent">true</bool>
+
     <!-- When true use the linux /dev/input/event subsystem to detect the switch changes
          on the headphone/microphone jack. When false use the older uevent framework. -->
     <bool name="config_useDevInputEventForAudioJack">false</bool>
@@ -2435,13 +2454,17 @@
          flag). -->
     <bool name="config_forceWindowDrawsStatusBarBackground">true</bool>
 
+    <!-- Controls the opacity of the navigation bar depending on the visibility of the
+         various workspace stacks.
+         0 - Nav bar is always opaque when either the freeform stack or docked stack is visible.
+         1 - Nav bar is always translucent when the freeform stack is visible, otherwise always
+         opaque.
+         -->
+    <integer name="config_navBarOpacityMode">0</integer>
+
     <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
     <string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
 
-    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
-         is located in center. -->
-    <string translatable="false" name="config_centeredPictureInPictureBounds">"0 0 300 300"</string>
-
     <!-- Controls the snap mode for the docked stack divider
              0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
              1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
@@ -2468,4 +2491,33 @@
          much in the way of user data.
     -->
     <bool name="config_strongAuthRequiredOnBoot">true</bool>
+
+    <!-- Wallpaper cropper package. Used as the default cropper if the active launcher doesn't
+         handle wallpaper cropping.
+    -->
+    <string name="config_wallpaperCropperPackage" translatable="false">com.android.wallpapercropper</string>
+
+    <!-- True if the device supports at least one form of multi-window.
+         E.g. freeform, split-screen, picture-in-picture. -->
+    <bool name="config_supportsMultiWindow">true</bool>
+
+    <!-- True if the device requires AppWidgetService even if it does not have
+         the PackageManager.FEATURE_APP_WIDGETS feature -->
+    <bool name="config_enableAppWidgetService">false</bool>
+
+    <!-- True if the device supports Sustained Performance Mode-->
+    <bool name="config_sustainedPerformanceModeSupported">false</bool>
+
+    <!-- Controls how we deal with externally connected physical keyboards.
+         0 - When using this device, it is not clear for users to recognize when the physical
+             keyboard is (should be) connected and when it is (should be) disconnected.  Most of
+             phones and tablets with Bluetooth keyboard would fall into this category because the
+             connected Bluetooth keyboard may or may not be nearby the host device.
+         1 - When using this device, it is clear for users to recognize when the physical
+             keyboard is (should be) connected and when it is (should be) disconnected.
+             Devices with wired USB keyboard is one clear example.  Some 2-in-1 convertible
+             tablets with dedicated keyboards may have the same affordance to wired USB keyboard.
+    -->
+    <integer name="config_externalHardKeyboardBehavior">0</integer>
+
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 1005704..a21f276 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -22,6 +22,8 @@
     <dimen name="thumbnail_width">192dp</dimen>
     <!-- The height that is used when creating thumbnails of applications. -->
     <dimen name="thumbnail_height">192dp</dimen>
+    <!-- The amount to scale a fullscreen screenshot thumbnail. -->
+    <item name="thumbnail_fullscreen_scale" type="fraction">60%</item>
     <!-- The standard size (both width and height) of an application icon that
          will be displayed in the app launcher and elsewhere. -->
     <dimen name="app_icon_size">48dip</dimen>
@@ -151,16 +153,13 @@
     <dimen name="notification_content_picture_margin">56dp</dimen>
 
     <!-- height of the content margin to accomodate for the header -->
-    <dimen name="notification_content_margin_top">30dp</dimen>
+    <dimen name="notification_content_margin_top">37.5dp</dimen>
 
     <!-- height of the content margin on the bottom -->
-    <dimen name="notification_content_margin_bottom">13dp</dimen>
-
-    <!-- height of notification header view if present -->
-    <dimen name="notification_header_height">32dp</dimen>
+    <dimen name="notification_content_margin_bottom">16dp</dimen>
 
     <!-- Height of a small notification in the status bar -->
-    <dimen name="notification_min_height">84dp</dimen>
+    <dimen name="notification_min_height">92dp</dimen>
 
     <!-- The width of the big icons in notifications. -->
     <dimen name="notification_large_icon_width">64dp</dimen>
@@ -177,7 +176,7 @@
     <dimen name="media_notification_expanded_image_max_size">94dp</dimen>
 
     <!-- The maximum size of the image in the expanded media notification -->
-    <dimen name="media_notification_expanded_image_margin_bottom">16dp</dimen>
+    <dimen name="media_notification_expanded_image_margin_bottom">20dp</dimen>
 
     <!-- The margin of the content to an image-->
     <dimen name="notification_content_image_margin_end">8dp</dimen>
@@ -268,7 +267,7 @@
     <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
     <dimen name="notification_text_size">14sp</dimen>
     <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
-    <dimen name="notification_title_text_size">16sp</dimen>
+    <dimen name="notification_title_text_size">14sp</dimen>
     <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
     <dimen name="notification_subtext_size">12sp</dimen>
 
@@ -451,6 +450,9 @@
     <item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
 
     <item type="dimen" name="aerr_padding_list_top">15dp</item>
+    <item type="dimen" name="aerr_padding_list_bottom">8dp</item>
 
     <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
+
+    <dimen name="resize_shadow_size">5dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 2fe4f66..00e48a0 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -41,6 +41,8 @@
     <dimen name="action_bar_default_padding_end_material">0dp</dimen>
     <!-- Default content inset of an action bar. -->
     <dimen name="action_bar_content_inset_material">16dp</dimen>
+    <!-- Default content inset of an action bar when a navigation button is present. -->
+    <dimen name="action_bar_content_inset_with_nav">72dp</dimen>
     <!-- Vertical padding around action bar icons. -->
     <dimen name="action_bar_icon_vertical_padding_material">16dp</dimen>
     <!-- Top margin for action bar subtitles -->
@@ -115,13 +117,13 @@
 
     <dimen name="dialog_padding_material">24dp</dimen>
     <dimen name="dialog_padding_top_material">18dp</dimen>
+    <dimen name="dialog_title_divider_material">8dp</dimen>
+    <dimen name="dialog_list_padding_top_no_title">8dp</dimen>
+    <dimen name="dialog_list_padding_bottom_no_buttons">8dp</dimen>
 
     <!-- Dialog padding minus control padding, used to fix alignment. -->
     <dimen name="select_dialog_padding_start_material">20dp</dimen>
 
-    <!-- Padding above and below selection dialog lists. -->
-    <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
-
     <dimen name="seekbar_track_background_height_material">2dp</dimen>
     <dimen name="seekbar_track_progress_height_material">2dp</dimen>
 
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index 8e27226..8f8d59e 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -23,4 +23,7 @@
     <integer name="button_pressed_animation_delay">100</integer>
     <integer name="disabled_alpha_animation_duration">100</integer>
     <integer name="dock_enter_exit_duration">250</integer>
+
+    <integer name="date_picker_mode">1</integer>
+    <integer name="time_picker_mode">1</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 13812630..6ff7139 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2664,7 +2664,7 @@
     <public type="attr" name="subMenuArrow" />
     <public type="attr" name="defaultWidth" />
     <public type="attr" name="defaultHeight" />
-    <public type="attr" name="minimalSize" />
+    <public type="attr" name="minimalWidth" />
     <public type="attr" name="resizeableActivity" />
     <public type="attr" name="supportsPictureInPicture" />
     <public type="attr" name="titleMargin" />
@@ -2679,8 +2679,8 @@
     <public type="attr" name="contextPopupMenuStyle" />
     <public type="attr" name="textAppearancePopupMenuHeader" />
     <public type="attr" name="windowBackgroundFallback" />
-    <public type="attr" name="forceDeviceEncrypted" />
-    <public type="attr" name="encryptionAware" />
+    <public type="attr" name="defaultToDeviceProtectedStorage" />
+    <public type="attr" name="directBootAware" />
     <public type="attr" name="preferenceFragmentStyle" />
     <public type="attr" name="canControlMagnification" />
     <public type="attr" name="languageTag" />
@@ -2702,9 +2702,22 @@
     <public type="attr" name="hotSpotY" />
     <public type="attr" name="version" />
     <public type="attr" name="backupInForeground" />
+    <public type="attr" name="countDown" />
+    <public type="attr" name="canRecord" />
+    <public type="attr" name="tunerCount" />
+    <public type="attr" name="nfcAntennaPositionDrawable" />
+    <public type="attr" name="fillType" />
+    <public type="attr" name="popupEnterTransition" />
+    <public type="attr" name="popupExitTransition" />
+    <public type="attr" name="minimalHeight" />
+    <public type="attr" name="forceHasOverlappingRendering" />
+    <public type="attr" name="contentInsetStartWithNavigation" />
+    <public type="attr" name="contentInsetEndWithActions" />
 
     <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
     <public type="style" name="Widget.Material.SeekBar.Discrete" />
+    <public type="style" name="Widget.Material.CompoundButton.Switch" />
+    <public type="style" name="Widget.Material.Light.CompoundButton.Switch" />
 
     <public type="id" name="accessibilityActionSetProgress" />
     <public type="id" name="icon_frame" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index da88146..b4f95dc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -185,8 +185,6 @@
     <!-- Displayed to tell the user that they cannot change the caller ID setting. -->
     <string name="CLIRPermanent">You can\'t change the caller ID setting.</string>
 
-    <!-- Notification title to tell the user that restricted state is changed by access control. -->
-    <string name="RestrictedChangedTitle">Restricted access changed</string>
     <!-- Displayed to tell the user that data service is blocked by access control. -->
     <string name="RestrictedOnData">Data service is blocked.</string>
     <!-- Displayed to tell the user that emergency service is blocked by access control. -->
@@ -550,9 +548,6 @@
          [CHAR LIMIT=4] -->
     <string name="status_bar_notification_info_overflow">999+</string>
 
-    <!-- The number of notifications in the notification header. An example would be (2) or (12) -->
-    <string name="notification_children_count_bracketed">(<xliff:g id="notificationCount" example="1">%d</xliff:g>)</string>
-
     <!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
     <string name="notification_header_divider_symbol" translatable="false">•</string>
 
@@ -568,11 +563,11 @@
     <!-- 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. [CHAR LIMIT=15] -->
-    <string name="user_owner_label">Personal</string>
+    <!-- Label for the user owner in the intent forwarding app. -->
+    <string name="user_owner_label">Switch to Personal</string>
 
-    <!-- Label for a corporate profile in the intent forwarding app. [CHAR LIMIT=15] -->
-    <string name="managed_profile_label">Work</string>
+    <!-- Label for a corporate profile in the intent forwarding app. -->
+    <string name="managed_profile_label">Switch to 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_contacts">Contacts</string>
@@ -2572,6 +2567,13 @@
     <!-- Title of intent resolver dialog when selecting a sharing application to run
          and a previously used application is known. -->
     <string name="whichSendApplicationNamed">Share with %1$s</string>
+    <!-- Title of intent resolver dialog when selecting an application to run to
+         send content to a specific recipient. Often used for email. -->
+    <string name="whichSendToApplication">Send using</string>
+    <!-- Title of intent resolver dialog when selecting an application to run to
+         send content to a specific recipient and a previously used application is known.
+         Often used for email. -->
+    <string name="whichSendToApplicationNamed">Send using %1$s</string>
     <!-- Title of intent resolver dialog when selecting a HOME application to run. -->
     <string name="whichHomeApplication">Select a Home app</string>
     <!-- Title of intent resolver dialog when selecting a HOME application to run
@@ -2902,7 +2904,9 @@
     <string name="dlg_ok">OK</string>
 
     <!-- USB_PREFERENCES: Notification for when the user connected to the charger only.  This is the title -->
-    <string name="usb_charging_notification_title">USB for charging</string>
+    <string name="usb_charging_notification_title">USB charging this device</string>
+    <!-- USB_PREFERENCES: Notification for when the user connects the phone to supply power to attached device.  This is the title -->
+    <string name="usb_supplying_notification_title">USB supplying power to attached device</string>
     <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MTP mode.  This is the title -->
     <string name="usb_mtp_notification_title">USB for file transfer</string>
     <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in PTP mode.  This is the title -->
@@ -2919,20 +2923,18 @@
     <!-- Message of notification shown when ADB is actively connected to the phone. -->
     <string name="adb_active_notification_message">Touch to disable USB debugging.</string>
 
+    <!-- Title of notification shown to indicate that bug report is being collected. -->
+    <string name="taking_remote_bugreport_notification_title">Taking bug report\u2026</string>
     <!-- Title of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
     <string name="share_remote_bugreport_notification_title">Share bug report?</string>
     <!-- Title of notification shown to indicate that bug report is still being collected after sharing was accepted. -->
     <string name="sharing_remote_bugreport_notification_title">Sharing bug report\u2026</string>
-    <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
-    <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down.</string>
-    <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
-    <string name="share_finished_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
-    <!-- Message of notification shown to shown to indicate that bug report is still being collected after sharing was accepted. -->
-    <string name="sharing_remote_bugreport_notification_message">This may temporarily slow down your device</string>
+    <!-- Message of a notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
+    <string name="share_remote_bugreport_notification_message_finished">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
     <!-- Acceptance label of notification shown to ask for user consent for sharing the remote bugreport. -->
-    <string name="share_remote_bugreport_notification_accept">ACCEPT</string>
+    <string name="share_remote_bugreport_action">SHARE</string>
     <!-- Decline label of notification shown to ask for user consent for sharing the remote bugreport. -->
-    <string name="share_remote_bugreport_notification_decline">DECLINE</string>
+    <string name="decline_remote_bugreport_action">DECLINE</string>
 
     <!-- Used to replace %s in urls retreived from the signin server with locales.  For Some        -->
     <!-- devices we don't support all the locales we ship to and need to replace the '%s' with a    -->
@@ -2943,18 +2945,17 @@
 
     <!-- Title of the pop-up dialog in which the user switches keyboard, also known as input method. -->
     <string name="select_input_method">Change keyboard</string>
-    <!-- Title of a button to open the settings to enable or disable keyboards, also known as input methods [CHAR LIMIT=30] -->
-    <string name="configure_input_methods">Choose keyboards</string>
     <!-- Summary text of a toggle switch to enable/disable use of the IME while a physical
          keyboard is connected -->
     <string name="show_ime">Keep it on screen while physical keyboard is active</string>
     <!-- Title of the physical keyboard category in the input method selector [CHAR LIMIT=30] -->
     <string name="hardware">Show virtual keyboard</string>
 
-    <!-- Title of the notification to prompt the user to select a keyboard layout. -->
-    <string name="select_keyboard_layout_notification_title">Select keyboard layout</string>
-    <!-- Message of the notification to prompt the user to select a keyboard layout. -->
-    <string name="select_keyboard_layout_notification_message">Touch to select a keyboard layout.</string>
+    <!-- Title of the notification to prompt the user to configure physical keyboard settings. -->
+    <string name="select_keyboard_layout_notification_title">Configure physical keyboard</string>
+    <!-- Message of the notification to prompt the user to configure physical keyboard settings
+         where the user can associate language with physical keyboard layout. -->
+    <string name="select_keyboard_layout_notification_message">Tap to select language and layout</string>
 
     <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
     <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
@@ -3139,11 +3140,13 @@
     <!-- Label to show for a service that is running because it is observing
          the user's notifications. -->
     <string name="notification_listener_binding_label">Notification listener</string>
+    <!-- Label to show for a service that is running because the system is in VR mode. -->
+    <string name="vr_listener_binding_label">VR listener</string>
     <!-- Label to show for a service that is running because it is providing conditions. -->
     <string name="condition_provider_service_binding_label">Condition provider</string>
     <!-- Label to show for a service that is running because it is observing and modifying the
          importance of the user's notifications. -->
-    <string name="notification_assistant_binding_label">Notification assistant</string>
+    <string name="notification_ranker_binding_label">Notification ranker service</string>
 
     <!-- Do Not Translate: Alternate eri.xml -->
     <string name="alternate_eri_file">/data/eri.xml</string>
@@ -3366,8 +3369,8 @@
          tapping/clicking the whole thing is going to do. -->
     <string name="action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>
 
-    <!-- Storage description for internal storage. [CHAR LIMIT=NONE] -->
-    <string name="storage_internal">Internal storage</string>
+    <!-- Storage description for internal shared storage. [CHAR LIMIT=NONE] -->
+    <string name="storage_internal">Internal shared storage</string>
 
     <!-- Storage description for a generic SD card. [CHAR LIMIT=NONE] -->
     <string name="storage_sd_card">SD card</string>
@@ -4016,8 +4019,8 @@
     <string name="lock_to_app_unlock_password">Ask for password before unpinning</string>
 
     <!-- Multi-Window strings -->
-    <!-- Warning message when a non-resizeble tasks is docked whose display windows are cropped. -->
-    <string name="dock_cropped_windows_text">App is not resizeable, scroll it with two fingers.</string>
+    <!-- Warning message when an app that got forced to be resizable gets shown in split-screen -->
+    <string name="dock_forced_resizable">App may not work with split-screen.</string>
     <!-- Warning message when we try to dock a non-resizeble tasks and launch it in fullscreen instead. -->
     <string name="dock_non_resizeble_failed_to_dock_text">App does not support split-screen.</string>
 
@@ -4173,7 +4176,7 @@
     <!-- Locale picker strings -->
 
     <!-- Title for the language selection screen [CHAR LIMIT=25] -->
-    <string name="language_selection_title">Language preference</string>
+    <string name="language_selection_title">Add a language</string>
     <!-- Title for the region selection screen [CHAR LIMIT=25] -->
     <string name="country_selection_title">Region preference</string>
     <!-- Hint text in a search edit box (used to filter long language / country lists) [CHAR LIMIT=25] -->
@@ -4193,10 +4196,6 @@
     <string name="work_mode_off_message">Allow work profile to function, including apps, background sync, and related features.</string>
     <!-- Title for button to turn on work profile. [CHAR LIMIT=NONE] -->
     <string name="work_mode_turn_on">Turn on</string>
-    <!-- Title for dialog displayed when a packge is suspended by device admin. [CHAR LIMIT=30] -->
-    <string name="suspended_package_title">%1$s disabled</string>
-    <!-- Message for dialog displayed when a packge is suspended by device admin. [CHAR LIMIT=NONE] -->
-    <string name="suspended_package_message">Disabled by %1$s administrator. Contact them to learn more.</string>
 
     <!-- Notification title shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
     <string name="new_sms_notification_title">You have new messages</string>
@@ -4230,4 +4229,12 @@
     <!-- View application info for a target. -->
     <string name="app_info">App info</string>
 
+    <!-- The representation of a time duration when negative. An example is -1:14. This can be used with a countdown timer for example.-->
+    <string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string>
+
+    <!-- Title of notification shown when device has been forced to safe mode after a security compromise. -->
+    <string name="audit_safemode_notification">Factory reset to use this device without restrictions</string>
+    <!-- Description of notification shown when device has been forced to safe mode after a security compromise. -->
+    <string name="audit_safemode_notification_details">Touch to learn more.</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 86b9f1d..790dcfa 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1234,6 +1234,7 @@
         <item name="collapseIcon">?attr/homeAsUpIndicator</item>
         <item name="collapseContentDescription">@string/toolbar_collapse_description</item>
         <item name="contentInsetStart">16dp</item>
+        <item name="contentInsetStartWithNavigation">@dimen/action_bar_content_inset_with_nav</item>
         <item name="touchscreenBlocksFocus">true</item>
     </style>
 
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index 6c69141..fdf9e31 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -1175,7 +1175,6 @@
     <style name="Widget.Holo.SuggestionItem" parent="TextAppearance.Holo.Medium">
         <item name="background">@color/white</item>
         <item name="drawablePadding">8dip</item>
-        <item name="ellipsize">marquee</item>
         <item name="gravity">start|center_vertical</item>
         <item name="layout_gravity">start|center_vertical</item>
         <item name="layout_height">wrap_content</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 9efcfda..2420c1a 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -311,7 +311,7 @@
     <style name="TextAppearance.Material.Widget.PopupMenu.Header">
         <item name="fontFamily">@string/font_family_title_material</item>
         <item name="textSize">@dimen/text_size_menu_header_material</item>
-        <item name="textColor">?attr/textColorSecondary</item>
+        <item name="textColor">?attr/colorAccent</item>
     </style>
 
     <style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" />
@@ -652,7 +652,7 @@
     </style>
 
     <style name="Widget.Material.TimePicker">
-        <item name="timePickerMode">clock</item>
+        <item name="timePickerMode">@integer/time_picker_mode</item>
         <item name="legacyLayout">@layout/time_picker_legacy_material</item>
         <!-- Attributes for new-style TimePicker. -->
         <item name="internalLayout">@layout/time_picker_material</item>
@@ -666,7 +666,7 @@
     </style>
 
     <style name="Widget.Material.DatePicker">
-        <item name="datePickerMode">calendar</item>
+        <item name="datePickerMode">@integer/date_picker_mode</item>
         <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
         <item name="calendarViewShown">true</item>
         <!-- Attributes for new-style DatePicker. -->
@@ -944,6 +944,7 @@
         <item name="homeLayout">@layout/action_bar_home_material</item>
         <item name="gravity">center_vertical</item>
         <item name="contentInsetStart">@dimen/action_bar_content_inset_material</item>
+        <item name="contentInsetStartWithNavigation">@dimen/action_bar_content_inset_with_nav</item>
         <item name="contentInsetEnd">@dimen/action_bar_content_inset_material</item>
         <item name="elevation">@dimen/action_bar_elevation_material</item>
         <item name="popupTheme">?attr/actionBarPopupTheme</item>
@@ -993,10 +994,8 @@
     </style>
 
     <style name="Widget.Material.SuggestionItem" parent="@android:style/TextAppearance.Material.Body1">
-        <item name="alpha">.87</item>
-        <item name="textColor">@color/black</item>
+        <item name="textColor">?attr/textColorSecondary</item>
         <item name="drawablePadding">8dip</item>
-        <item name="ellipsize">marquee</item>
         <item name="gravity">start|center_vertical</item>
         <item name="layout_gravity">start|center_vertical</item>
         <item name="layout_height">48dip</item>
@@ -1010,14 +1009,12 @@
     </style>
 
     <style name="TextAppearance.Material.TextSuggestionHighlight" parent="Widget.Material.SuggestionItem">
-        <item name="textColor">#009688</item>
+        <item name="textColor">?attr/textColorPrimary</item>
     </style>
 
     <style name="Widget.Material.SuggestionButton" parent="@android:style/TextAppearance.Material.Button">
-        <item name="alpha">.87</item>
-        <item name="textColor">#009688</item>
+        <item name="textColor">?attr/colorAccent</item>
         <item name="drawablePadding">8dip</item>
-        <item name="ellipsize">marquee</item>
         <item name="gravity">start|center_vertical</item>
         <item name="layout_gravity">start|center_vertical</item>
         <item name="layout_height">48dip</item>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 7dde5f8..341a0a4 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -17,27 +17,27 @@
     <style name="Animation.Micro"/>
 
     <style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
-        <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
-        <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item>
-        <item name="activityOpenExitAnimation">@null</item>
+        <item name="activityOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="activityOpenExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="activityCloseEnterAnimation">@null</item>
         <item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
-        <item name="taskOpenEnterAnimation">@anim/slide_in_micro</item>
-        <item name="taskOpenExitAnimation">@null</item>
+        <item name="taskOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="taskCloseEnterAnimation">@null</item>
         <item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
-        <item name="taskToFrontEnterAnimation">@anim/slide_in_micro</item>
-        <item name="taskToFrontExitAnimation">@null</item>
+        <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="taskToBackEnterAnimation">@null</item>
         <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
         <item name="wallpaperOpenEnterAnimation">@null</item>
         <item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
-        <item name="wallpaperCloseEnterAnimation">@anim/slide_in_micro</item>
-        <item name="wallpaperCloseExitAnimation">@null</item>
+        <item name="wallpaperCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="wallpaperCloseExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="wallpaperIntraOpenEnterAnimation">@null</item>
         <item name="wallpaperIntraOpenExitAnimation">@anim/slide_out_micro</item>
-        <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_micro</item>
-        <item name="wallpaperIntraCloseExitAnimation">@null</item>
+        <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
     </style>
 
     <style name="AlertDialog.Micro" parent="AlertDialog.Material.Light">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 746e7fd..2ce555a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -298,14 +298,17 @@
   <java-symbol type="bool" name="config_wifi_enable_5GHz_preference" />
   <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
   <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" />
+  <java-symbol type="integer" name="config_wifi_logger_ring_buffer_size_limit_kb" />
   <java-symbol type="bool" name="config_wifi_turn_off_during_emergency_call" />
   <java-symbol type="bool" name="config_supportMicNearUltrasound" />
   <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
   <java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />
   <java-symbol type="bool" name="config_freeformWindowManagement" />
+  <java-symbol type="bool" name="config_supportsMultiWindow" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
+  <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
+  <java-symbol type="bool" name="config_enableAppWidgetService" />
   <java-symbol type="string" name="config_defaultPictureInPictureBounds" />
-  <java-symbol type="string" name="config_centeredPictureInPictureBounds" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
@@ -379,6 +382,7 @@
   <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_immersive_mode_confirmation_panic" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
+  <java-symbol type="integer" name="config_longPressOnBackBehavior" />
   <java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAdjust" />
   <java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_max_pan_devices" />
@@ -484,7 +488,6 @@
   <java-symbol type="string" name="Noon" />
   <java-symbol type="string" name="PinMmi" />
   <java-symbol type="string" name="PwdMmi" />
-  <java-symbol type="string" name="RestrictedChangedTitle" />
   <java-symbol type="string" name="RestrictedOnAllVoice" />
   <java-symbol type="string" name="RestrictedOnData" />
   <java-symbol type="string" name="RestrictedOnEmergency" />
@@ -610,7 +613,7 @@
   <java-symbol type="string" name="display_manager_overlay_display_name" />
   <java-symbol type="string" name="display_manager_overlay_display_secure_suffix" />
   <java-symbol type="string" name="display_manager_overlay_display_title" />
-  <java-symbol type="string" name="dock_cropped_windows_text" />
+  <java-symbol type="string" name="dock_forced_resizable" />
   <java-symbol type="string" name="dock_non_resizeble_failed_to_dock_text" />
   <java-symbol type="string" name="double_tap_toast" />
   <java-symbol type="string" name="durationDays" />
@@ -1509,6 +1512,10 @@
   <java-symbol type="dimen" name="docked_stack_minimize_thickness" />
   <java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
   <java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
+  <java-symbol type="fraction" name="thumbnail_fullscreen_scale" />
+  <java-symbol type="dimen" name="resize_shadow_size" />
+  <java-symbol type="color" name="resize_shadow_start_color" />
+  <java-symbol type="color" name="resize_shadow_end_color" />
   <java-symbol type="dimen" name="navigation_bar_height" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
   <java-symbol type="dimen" name="navigation_bar_width" />
@@ -1737,6 +1744,7 @@
   <java-symbol type="integer" name="config_defaultNotificationLedOff" />
   <java-symbol type="integer" name="config_defaultNotificationLedOn" />
   <java-symbol type="integer" name="config_deskDockKeepsScreenOn" />
+  <java-symbol type="integer" name="config_externalHardKeyboardBehavior" />
   <java-symbol type="integer" name="config_lightSensorWarmupTime" />
   <java-symbol type="integer" name="config_lowBatteryCloseWarningBump" />
   <java-symbol type="integer" name="config_lowBatteryWarningLevel" />
@@ -1759,6 +1767,7 @@
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
   <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
+  <java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
   <java-symbol type="layout" name="launch_warning" />
   <java-symbol type="layout" name="safe_mode" />
@@ -1769,13 +1778,12 @@
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
+  <java-symbol type="string" name="taking_remote_bugreport_notification_title" />
   <java-symbol type="string" name="share_remote_bugreport_notification_title" />
-  <java-symbol type="string" name="share_remote_bugreport_notification_message" />
-  <java-symbol type="string" name="share_finished_remote_bugreport_notification_message" />
   <java-symbol type="string" name="sharing_remote_bugreport_notification_title" />
-  <java-symbol type="string" name="sharing_remote_bugreport_notification_message" />
-  <java-symbol type="string" name="share_remote_bugreport_notification_accept" />
-  <java-symbol type="string" name="share_remote_bugreport_notification_decline" />
+  <java-symbol type="string" name="share_remote_bugreport_notification_message_finished" />
+  <java-symbol type="string" name="share_remote_bugreport_action" />
+  <java-symbol type="string" name="decline_remote_bugreport_action" />
   <java-symbol type="string" name="aerr_application" />
   <java-symbol type="string" name="aerr_process" />
   <java-symbol type="string" name="aerr_application_repeated" />
@@ -1804,7 +1812,6 @@
   <java-symbol type="string" name="config_wimaxServiceClassname" />
   <java-symbol type="string" name="config_wimaxServiceJarLocation" />
   <java-symbol type="string" name="config_wimaxStateTrackerClassname" />
-  <java-symbol type="string" name="configure_input_methods" />
   <java-symbol type="string" name="data_usage_3g_limit_snoozed_title" />
   <java-symbol type="string" name="data_usage_3g_limit_title" />
   <java-symbol type="string" name="data_usage_4g_limit_snoozed_title" />
@@ -1841,8 +1848,9 @@
   <java-symbol type="string" name="low_internal_storage_view_text_no_boot" />
   <java-symbol type="string" name="low_internal_storage_view_title" />
   <java-symbol type="string" name="notification_listener_binding_label" />
+  <java-symbol type="string" name="vr_listener_binding_label" />
   <java-symbol type="string" name="condition_provider_service_binding_label" />
-  <java-symbol type="string" name="notification_assistant_binding_label" />
+  <java-symbol type="string" name="notification_ranker_binding_label" />
   <java-symbol type="string" name="report" />
   <java-symbol type="string" name="select_input_method" />
   <java-symbol type="string" name="select_keyboard_layout_notification_title" />
@@ -1857,6 +1865,7 @@
   <java-symbol type="string" name="usb_notification_message" />
   <java-symbol type="string" name="usb_ptp_notification_title" />
   <java-symbol type="string" name="usb_midi_notification_title" />
+  <java-symbol type="string" name="usb_supplying_notification_title" />
   <java-symbol type="string" name="vpn_text" />
   <java-symbol type="string" name="vpn_text_long" />
   <java-symbol type="string" name="vpn_title" />
@@ -1893,6 +1902,8 @@
   <java-symbol type="string" name="config_customVpnConfirmDialogComponent" />
   <java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
   <java-symbol type="string" name="config_persistentDataPackageName" />
+  <java-symbol type="string" name="audit_safemode_notification" />
+  <java-symbol type="string" name="audit_safemode_notification_details" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
@@ -2207,6 +2218,8 @@
   <java-symbol type="string" name="whichEditApplicationNamed" />
   <java-symbol type="string" name="whichSendApplication" />
   <java-symbol type="string" name="whichSendApplicationNamed" />
+  <java-symbol type="string" name="whichSendToApplication" />
+  <java-symbol type="string" name="whichSendToApplicationNamed" />
   <java-symbol type="attr" name="lightY" />
   <java-symbol type="attr" name="lightZ" />
   <java-symbol type="attr" name="lightRadius" />
@@ -2390,6 +2403,7 @@
 
   <java-symbol type="string" name="config_packagedKeyboardName" />
   <java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
+  <java-symbol type="integer" name="config_navBarOpacityMode" />
   <java-symbol type="color" name="system_bar_background_semi_transparent" />
 
   <!-- EditText suggestion popup. -->
@@ -2403,11 +2417,9 @@
   <java-symbol type="id" name="notification_material_reply_text_2" />
   <java-symbol type="id" name="notification_material_reply_text_3" />
 
-  <java-symbol type="string" name="notification_children_count_bracketed" />
   <java-symbol type="string" name="notification_hidden_text" />
   <java-symbol type="string" name="notification_hidden_by_policy_text" />
   <java-symbol type="id" name="app_name_text" />
-  <java-symbol type="id" name="number_of_children" />
   <java-symbol type="id" name="header_sub_text" />
   <java-symbol type="id" name="expand_button" />
   <java-symbol type="id" name="notification_header" />
@@ -2420,19 +2432,20 @@
   <java-symbol type="drawable" name="ic_collapse_notification" />
   <java-symbol type="drawable" name="ic_expand_bundle" />
   <java-symbol type="drawable" name="ic_collapse_bundle" />
-  <java-symbol type="dimen" name="notification_header_height" />
   <java-symbol type="dimen" name="notification_min_content_height" />
   <java-symbol type="dimen" name="notification_header_shrink_min_width" />
   <java-symbol type="dimen" name="notification_content_margin_start" />
   <java-symbol type="dimen" name="notification_content_margin_end" />
   <java-symbol type="dimen" name="notification_content_picture_margin" />
   <java-symbol type="dimen" name="notification_content_margin_top" />
+  <java-symbol type="dimen" name="notification_content_margin_bottom" />
   <java-symbol type="string" name="importance_from_user" />
   <java-symbol type="string" name="importance_from_person" />
 
   <java-symbol type="layout" name="work_widget_mask_view" />
+  <java-symbol type="id" name="work_widget_mask_frame" />
   <java-symbol type="id" name="work_widget_app_icon" />
-  <java-symbol type="drawable" name="work_widget_mask_view_background" />
+  <java-symbol type="id" name="work_widget_badge_icon" />
 
   <java-symbol type="id" name="aerr_report" />
   <java-symbol type="id" name="aerr_reset" />
@@ -2440,26 +2453,9 @@
   <java-symbol type="id" name="aerr_close" />
   <java-symbol type="id" name="aerr_mute" />
 
-  <!-- Framework-private Material.DayNight styles. -->
-  <java-symbol type="style" name="Theme.Material.DayNight" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DarkActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Alert" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Panel" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
-
   <java-symbol type="string" name="status_bar_rotate" />
   <java-symbol type="string" name="status_bar_headset" />
+  <java-symbol type="string" name="status_bar_data_saver" />
   <java-symbol type="string" name="status_bar_managed_profile" />
   <java-symbol type="string" name="status_bar_ime" />
   <java-symbol type="string" name="status_bar_sync_failing" />
@@ -2485,7 +2481,6 @@
   <java-symbol type="string" name="status_bar_clock" />
 
   <!-- Locale picker -->
-  <java-symbol type="id" name="l10nWarn" />
   <java-symbol type="id" name="locale_search_menu" />
   <java-symbol type="layout" name="language_picker_item" />
   <java-symbol type="layout" name="language_picker_section_header" />
@@ -2502,8 +2497,6 @@
   <java-symbol type="string" name="work_mode_off_title" />
   <java-symbol type="string" name="work_mode_off_message" />
   <java-symbol type="string" name="work_mode_turn_on" />
-  <java-symbol type="string" name="suspended_package_title" />
-  <java-symbol type="string" name="suspended_package_message" />
 
   <!-- New SMS notification while phone is locked. -->
   <java-symbol type="string" name="new_sms_notification_title" />
@@ -2531,6 +2524,9 @@
   <java-symbol type="string" name="usb_mtp_launch_notification_title" />
   <java-symbol type="string" name="usb_mtp_launch_notification_description" />
 
+  <java-symbol type="color" name="notification_action_list" />
+  <java-symbol type="color" name="notification_material_background_color" />
+
   <!-- Resolver target actions -->
   <java-symbol type="array" name="resolver_target_actions_pin" />
   <java-symbol type="array" name="resolver_target_actions_unpin" />
@@ -2540,4 +2536,13 @@
   <java-symbol type="string" name="carrier_app_dialog_not_now" />
   <java-symbol type="string" name="carrier_app_notification_title" />
   <java-symbol type="string" name="carrier_app_notification_text" />
+  <java-symbol type="string" name="negative_duration" />
+
+  <!-- WallpaperManager config -->
+  <java-symbol type="string" name="config_wallpaperCropperPackage" />
+
+  <java-symbol type="id" name="textSpacerNoTitle" />
+  <java-symbol type="id" name="titleDividerNoCustom" />
+
+  <java-symbol type="bool" name="config_sustainedPerformanceModeSupported" />
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index dd8baa7..11bb106 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -544,9 +544,7 @@
         <item name="windowNoTitle">true</item>
         <item name="windowBackground">@color/transparent</item>
         <item name="backgroundDimEnabled">true</item>
-        <item name="windowTranslucentStatus">false</item>
-        <item name="windowTranslucentNavigation">false</item>
-        <item name="windowDrawsSystemBarBackgrounds">false</item>
+        <item name="statusBarColor">@color/transparent</item>
         <item name="windowContentOverlay">@null</item>
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 5970a22..6611eb1 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -223,6 +223,7 @@
         <item name="textSelectHandleWindowStyle">@style/Widget.Material.TextSelectHandle</item>
         <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item_material</item>
         <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container_material</item>
+        <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Material.TextSuggestionHighlight</item>
         <item name="textCursorDrawable">@drawable/text_cursor_material</item>
 
         <!-- Widget styles -->
@@ -1293,7 +1294,7 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
+    <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
 
@@ -1303,7 +1304,7 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.DayNight.NoActionBar">
+    <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.Light.NoActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
 
@@ -1312,41 +1313,41 @@
         <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
     </style>
 
-    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
+    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
     <style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
 
-    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
+    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
     <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
 
-    <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar">
+    <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.DayNight.DialogWhenLarge.NoActionBar">
+    <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
+    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
+    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
+    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
diff --git a/core/res/res/values/themes_material_daynight.xml b/core/res/res/values/themes_material_daynight.xml
deleted file mode 100644
index 4ecca6b..0000000
--- a/core/res/res/values/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!--
-===============================================================
-                        PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
-                        PLEASE READ
-===============================================================
- -->
-<resources>
-
-    <!-- Material theme (day/night vesion) for activities. -->
-    <style name="Theme.Material.DayNight" parent="Theme.Material.Light" />
-
-    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
-         with an inverse color profile. The dark action bar sharply stands out against
-         the light content (when applicable).  -->
-    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
-
-    <!-- Variant of Material.DayNight with no action bar.  -->
-    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen. This theme
-         sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen and extends into the display overscan region. This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
-
-    <!-- Variant of Material.DayNight that has no title bar and translucent
-         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
-         {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
-
-    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
-         to place your content. It makes the window floating, with a transparent
-         background, and turns off dimming behind the window. -->
-    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Light.Panel" />
-
-    <!-- Material theme (day/night vesion) for dialog windows and activities,
-         which is used by the {@link android.app.Dialog} class. This changes
-         the window to be floating (not fill the entire screen), and puts a
-         frame around its contents. You can set this theme on an activity if
-         you would like to make an activity that looks like a Dialog. -->
-    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
-    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.Light.BaseDialog" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Light.Dialog.FixedSize" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
-
-    <!-- Theme for a window that will be displayed either full-screen on
-         smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
-
-    <!-- Theme for a window with a dark action bar that will be displayed
-         either full-screen on smaller screens (small, normal) or as a dialog
-         on larger screens (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
-
-    <!-- Theme for a window without an action bar that will be displayed either full-screen
-         on smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
-
-    <!-- Theme for a presentation window on a secondary display. -->
-    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
-
-    <!-- Material user theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class. -->
-    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
-    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert" />
-
-    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.Light.SearchBar" />
-    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.Light.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 8bf635e..478d66c 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,7 +24,6 @@
         <item name="windowBackground">@color/black</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
     </style>
@@ -42,7 +41,6 @@
         <item name="windowBackground">@color/white</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
     </style>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 76b5fe1..2e593a3 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -94,11 +94,27 @@
   <!-- This is the battery capacity in mAh (measured at nominal voltage) -->
   <item name="battery.capacity">1000</item>
 
-  <array name="wifi.batchedscan"> <!-- mA -->
-      <value>.0002</value> <!-- 1-8/hr -->
-      <value>.002</value>  <!-- 9-64/hr -->
-      <value>.02</value>   <!-- 65-512/hr -->
-      <value>.2</value>    <!-- 513-4,096/hr -->
-      <value>2</value>    <!-- 4097-/hr -->
+  <!-- Wifi related values. -->
+  <!-- Idle Receive current for wifi radio in mA. 0 by default-->
+  <item name="wifi.controller.idle">0</item>
+  <!-- Rx current for wifi radio in mA. 0 by default-->
+  <item name="wifi.controller.rx">0</item>
+  <!-- Tx current for wifi radio in mA. 0 by default-->
+  <item name="wifi.controller.tx">0</item>
+  <!-- Current at each of the wifi Tx levels in mA. The number of tx levels varies per device
+       and is available only of wifi chipsets which support the tx level reporting. Use
+        wifi.tx for other chipsets. none by default -->
+  <array name="wifi.controller.tx_levels"> <!-- mA -->
   </array>
+  <!-- Operating volatage for wifi radio in mV. 0 by default-->
+  <item name="wifi.controller.voltage">0</item>
+
+  <array name="wifi.batchedscan"> <!-- mA -->
+    <value>.0002</value> <!-- 1-8/hr -->
+    <value>.002</value>  <!-- 9-64/hr -->
+    <value>.02</value>   <!-- 65-512/hr -->
+    <value>.2</value>    <!-- 513-4,096/hr -->
+    <value>2</value>    <!-- 4097-/hr -->
+  </array>
+
 </device>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index cf7978c..c02a01a 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -102,7 +102,7 @@
     <!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
          http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf,
          visual voicemail code for EE: 887 -->
-    <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|887|83669|34664|40406" />
+    <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406" />
 
     <!-- Georgia: 4 digits, known premium codes listed -->
     <shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
@@ -214,7 +214,7 @@
 
     <!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
          visual voicemail code for T-Mobile: 122 -->
-    <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:567|578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" free="122|87902" />
+    <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567" free="122|87902" />
 
     <!-- Vietnam -->
     <shortcode country="vn" free="5001" />
diff --git a/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
new file mode 100644
index 0000000..a6e433f
--- /dev/null
+++ b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.util;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.util.Patterns;
+
+import java.util.regex.Pattern;
+
+public class LinkifyBenchmark {
+    private static final String MATCHING_STR = " http://user:pass@host.com:5432/path?k=v#f " +
+            "host.com:5432/path?k=v#f ";
+
+    private static final String NONMATCHING_STR = " Neque porro quisquam est qui dolorem ipsum " +
+            "quia dolor sit amet, consectetur, adipisci velit ";
+
+    // this pattern does not recognize strings without http scheme therefore is expected to be
+    // faster in MATCHING_STR case.
+    private static final Pattern BASIC_PATTERN = Pattern.compile(
+            "(?:\\b|$|^)http://[a-zA-Z0-9:\\.@\\?=#/]+(?:\\b|$|^)");
+
+    @Param({"1", "4", "16", "64", "256"})
+    private String mParamCopyAmount;
+
+    @Param({MATCHING_STR, NONMATCHING_STR})
+    private String mParamBasicText;
+
+    private Spannable mTestSpannable;
+
+    @BeforeExperiment
+    protected void setUp() throws Exception {
+        int copyAmount = Integer.valueOf(mParamCopyAmount);
+        StringBuilder strBuilder = new StringBuilder();
+        for (int i = 0; i < copyAmount; i++) {
+            strBuilder.append(mParamBasicText);
+        }
+        mTestSpannable = new SpannableString(strBuilder.toString());
+    }
+
+    @AfterExperiment
+    protected void tearDown() {
+        mTestSpannable = null;
+    }
+
+    @Benchmark
+    public void timeNewRegEx(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            Linkify.addLinks(mTestSpannable, Patterns.AUTOLINK_WEB_URL, "http://",
+                    new String[]{"http://", "https://", "rtsp://"}, null, null);
+        }
+    }
+
+    @Benchmark
+    public void timeOldRegEx(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            Linkify.addLinks(mTestSpannable, Patterns.WEB_URL, "http://",
+                    new String[]{"http://", "https://", "rtsp://"}, null, null);
+        }
+    }
+
+    @Benchmark
+    public void timeBasicRegEx(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            Linkify.addLinks(mTestSpannable, BASIC_PATTERN, "http://",
+                    new String[]{"http://", "https://", "rtsp://"}, null, null);
+        }
+    }
+
+}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index bfa2b10..b7926cf 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -111,7 +111,7 @@
     <!-- accessibility test permissions -->
     <uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
 
-    <application android:theme="@style/Theme">
+    <application android:theme="@style/Theme" android:supportsRtl="true">
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="org.apache.http.legacy" android:required="false" />
         <meta-data
@@ -1093,7 +1093,12 @@
             </intent-filter>
         </activity>
 
-
+        <activity android:name="android.view.ViewCaptureTestActivity" android:label="ViewCaptureTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
 
         <!-- Activity-level metadata -->
         <meta-data android:name="com.android.frameworks.coretests.isApp" android:value="true" />
@@ -1251,6 +1256,15 @@
         <service android:name="android.os.BinderThreadPriorityService"
                 android:process=":BinderThreadPriorityService" />
 
+        <!-- Used by ApplyOverrideConfigurationTest -->
+        <activity android:name="android.app.activity.ApplyOverrideConfigurationActivity"
+                  android:configChanges="orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <!-- Application components used for search manager tests -->
 
         <activity android:name="android.app.activity.SearchableActivity"
diff --git a/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png b/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png
new file mode 100644
index 0000000..52092c4
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png
Binary files differ
diff --git a/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png b/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png
new file mode 100644
index 0000000..3bcbd9a
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png
Binary files differ
diff --git a/core/tests/coretests/res/layout/remote_views_test.xml b/core/tests/coretests/res/layout/remote_views_test.xml
new file mode 100644
index 0000000..c5f7a47
--- /dev/null
+++ b/core/tests/coretests/res/layout/remote_views_test.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:id="@+id/layout"
+        android:orientation="vertical">
+
+    <TextView android:id="@+id/text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    <ImageView android:id="@+id/image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/core/tests/coretests/res/layout/view_capture_snapshot.xml b/core/tests/coretests/res/layout/view_capture_snapshot.xml
new file mode 100644
index 0000000..0b589a4
--- /dev/null
+++ b/core/tests/coretests/res/layout/view_capture_snapshot.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+
+    <LinearLayout android:id="@+id/capture"
+        android:background="#00f"
+        android:orientation="vertical"
+        android:layout_width="100px"
+        android:layout_height="100px">
+
+        <View android:id="@+id/child1"
+            android:background="#f00"
+            android:layout_width="match_parent"
+            android:layout_height="25px"/>
+
+        <View android:id="@+id/child2"
+            android:background="#fff"
+            android:layout_width="match_parent"
+            android:layout_height="25px"
+            android:visibility="invisible"/>
+
+        <View android:id="@+id/child3"
+            android:background="#ff0"
+            android:layout_width="match_parent"
+            android:layout_height="25px"
+            android:visibility="gone"/>
+
+        <View android:id="@+id/child4"
+            android:background="#0ff"
+            android:layout_width="match_parent"
+            android:layout_height="25px" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 998c72a..b908d92 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -328,7 +328,12 @@
         // Only a1's pause listener should be called.
         assertTrue(l1.pauseCalled);
         assertFalse(l1.resumeCalled);
-        a1.resume();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.resume();
+            }
+        });
 
         Thread.sleep(a1.getTotalDuration());
 
@@ -900,6 +905,10 @@
                 a1.start();
                 a2.reverse();
                 a3.start();
+                // Check that the animators' values are immediately set to end value in the case of
+                // 0-duration.
+                assertEquals(A1_END_VALUE, a1.getAnimatedValue());
+                assertEquals(A2_START_VALUE, a2.getAnimatedValue());
             }
         });
         Thread.sleep(POLL_INTERVAL);
@@ -946,6 +955,10 @@
 
                 a1.start();
                 a2.start();
+
+                // In the case of 0 duration scale applied to a non-0 duration, check that the
+                // value is immediately set to the start value.
+                assertEquals(A2_START_VALUE, a2.getAnimatedValue());
             }
         });
         Thread.sleep(POLL_INTERVAL);
@@ -957,6 +970,8 @@
                 assertTrue(l2.startCalled);
                 assertTrue(l1.endCalled);
                 assertTrue(l2.endCalled);
+                assertEquals(A1_END_VALUE, a1.getAnimatedValue());
+                assertEquals(A2_END_VALUE, a2.getAnimatedValue());
             }
         });
 
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index af2a944..bae4ecc 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -81,8 +81,7 @@
     protected static final int DEFAULT_WAIT_POLL_TIME = 5 * 1000;  // 5 seconds
 
     protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000;  // 1 second
-    protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes
-    protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes
+    protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 30 * 1000; // 30 seconds
 
     protected static final int DOWNLOAD_TO_SYSTEM_CACHE = 1;
     protected static final int DOWNLOAD_TO_DOWNLOAD_CACHE_DIR = 2;
@@ -970,7 +969,7 @@
     protected void verifyInt(Cursor cursor, String columnName, int expected) {
         int index = cursor.getColumnIndex(columnName);
         int actual = cursor.getInt(index);
-        assertEquals(expected, actual);
+        assertEquals(String.format("Expected = %d : Actual = %d", expected, actual), expected, actual);
     }
 
     /**
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index 7019980..d1a5d28 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -23,18 +23,16 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.test.suitebuilder.annotation.LargeTest;
-
-import android.test.suitebuilder.annotation.Suppress;
 import com.google.mockwebserver.MockResponse;
 
 import java.io.File;
+import java.util.concurrent.TimeoutException;
 import java.util.Iterator;
 import java.util.Set;
 
 /**
  * Integration tests of the DownloadManager API.
  */
-@Suppress  // Failing.
 public class DownloadManagerFunctionalTest extends DownloadManagerBaseTest {
     private static final String TAG = "DownloadManagerFunctionalTest";
     private final static String CACHE_DIR =
@@ -79,7 +77,11 @@
         request.setTitle(DEFAULT_FILENAME);
 
         long dlRequest = mDownloadManager.enqueue(request);
-        waitForDownloadOrTimeout(dlRequest);
+        try {
+            waitForDownloadOrTimeout(dlRequest);
+        } catch (TimeoutException ex) {
+            // it is expected to timeout as download never finishes
+        }
 
         Cursor cursor = getCursor(dlRequest);
         try {
@@ -114,7 +116,7 @@
         verifyDownload(dlRequest, blobData);
         mDownloadManager.remove(dlRequest);
     }
-    
+
     /**
      * Helper to verify a standard single-file download from the mock server, and clean up after
      * verification
@@ -135,9 +137,7 @@
 
             verifyFileSize(pfd, fileSize);
             verifyFileContents(pfd, fileData);
-            int colIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
-            String fileName = cursor.getString(colIndex);
-            assertTrue(fileName.startsWith(CACHE_DIR));
+            assertTrue(new File(CACHE_DIR + "/" + DEFAULT_FILENAME).exists());
         } finally {
             pfd.close();
             cursor.close();
@@ -161,7 +161,6 @@
 
             Uri localUri = Uri.fromFile(existentFile);
             request.setDestinationUri(localUri);
-
             long dlRequest = mDownloadManager.enqueue(request);
 
             // wait for the download to complete
@@ -285,20 +284,30 @@
         Uri uri = getServerUri(DEFAULT_FILENAME);
         enqueueResponse(buildResponse(HTTP_PARTIAL_CONTENT));
 
-        doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE);
+        doErrorTest(uri, DownloadManager.ERROR_CANNOT_RESUME);
     }
 
     /**
      * Tests the download failure error from an unhandled HTTP status code
      */
     @LargeTest
-    public void testErrorHttpDataError_invalidRedirect() throws Exception {
+    public void testRelativeRedirect() throws Exception {
         Uri uri = getServerUri(DEFAULT_FILENAME);
         final MockResponse resp = buildResponse(HTTP_REDIRECT);
-        resp.setHeader("Location", "://blah.blah.blah.com");
+        resp.setHeader("Location", ":" + uri.getSchemeSpecificPart());
         enqueueResponse(resp);
 
-        doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR);
+        byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
+        enqueueResponse(buildResponse(HTTP_OK, blobData));
+
+        Request request = new Request(uri);
+        request.setTitle(DEFAULT_FILENAME);
+
+        long dlRequest = mDownloadManager.enqueue(request);
+        waitForDownloadOrTimeout(dlRequest);
+
+        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
+        assertEquals(1, mReceiver.numDownloadsCompleted());
     }
 
     /**
diff --git a/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java
new file mode 100644
index 0000000..3df522d
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR 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.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+
+public class ApplyOverrideConfigurationActivity extends Activity {
+
+    @Override
+    protected void attachBaseContext(Context newBase) {
+        super.attachBaseContext(newBase);
+
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.smallestScreenWidthDp = ApplyOverrideConfigurationTest.OVERRIDE_WIDTH;
+        applyOverrideConfiguration(overrideConfig);
+    }
+}
diff --git a/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java
new file mode 100644
index 0000000..15ed77e
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR 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.activity;
+
+import android.app.UiAutomation;
+import android.content.res.Configuration;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.ActivityInstrumentationTestCase2;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ApplyOverrideConfigurationTest extends
+        ActivityInstrumentationTestCase2<ApplyOverrideConfigurationActivity> {
+
+    public static final int OVERRIDE_WIDTH = 9999;
+
+    public ApplyOverrideConfigurationTest() {
+        super(ApplyOverrideConfigurationActivity.class);
+    }
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+    }
+
+    @Test
+    public void testConfigurationIsOverriden() throws Exception {
+        Configuration config = getActivity().getResources().getConfiguration();
+        assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
+
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90);
+
+        config = getActivity().getResources().getConfiguration();
+        assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
+    }
+
+    @After
+    @Override
+    public void tearDown() throws Exception {
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+        super.tearDown();
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/ContainerEncryptionParamsTest.java b/core/tests/coretests/src/android/content/pm/ContainerEncryptionParamsTest.java
deleted file mode 100644
index 7deaa9a..0000000
--- a/core/tests/coretests/src/android/content/pm/ContainerEncryptionParamsTest.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-import java.util.Arrays;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-public class ContainerEncryptionParamsTest extends AndroidTestCase {
-    private static final String ENC_ALGORITHM = "AES/CBC/PKCS7Padding";
-
-    private static final byte[] IV_BYTES = "FOOBAR".getBytes();
-
-    private static final IvParameterSpec ENC_PARAMS = new IvParameterSpec(IV_BYTES);
-
-    private static final byte[] ENC_KEY_BYTES = "abcd1234wxyz7890".getBytes();
-
-    private static final SecretKey ENC_KEY = new SecretKeySpec(ENC_KEY_BYTES, "RAW");
-
-    private static final String MAC_ALGORITHM = "HMAC-SHA1";
-
-    private static final byte[] MAC_KEY_BYTES = "4wxyzabcd1237890".getBytes();
-
-    private static final SecretKey MAC_KEY = new SecretKeySpec(MAC_KEY_BYTES, "RAW");
-
-    private static final byte[] MAC_TAG = "faketag".getBytes();
-
-    private static final int AUTHENTICATED_START = 5;
-
-    private static final int ENCRYPTED_START = 11;
-
-    private static final int DATA_END = 19;
-
-    public void testParcel() throws Exception {
-        ContainerEncryptionParams expected = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        Parcel parcel = Parcel.obtain();
-        expected.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-
-        ContainerEncryptionParams actual = ContainerEncryptionParams.CREATOR
-                .createFromParcel(parcel);
-
-        assertEquals(ENC_ALGORITHM, actual.getEncryptionAlgorithm());
-
-        if (!(actual.getEncryptionSpec() instanceof IvParameterSpec)) {
-            fail("encryption parameters should be IvParameterSpec");
-        } else {
-            IvParameterSpec actualParams = (IvParameterSpec) actual.getEncryptionSpec();
-            assertTrue(Arrays.equals(IV_BYTES, actualParams.getIV()));
-        }
-
-        assertEquals(ENC_KEY, actual.getEncryptionKey());
-
-        assertEquals(MAC_ALGORITHM, actual.getMacAlgorithm());
-
-        assertNull(actual.getMacSpec());
-
-        assertEquals(MAC_KEY, actual.getMacKey());
-
-        assertTrue(Arrays.equals(MAC_TAG, actual.getMacTag()));
-
-        assertEquals(AUTHENTICATED_START, actual.getAuthenticatedDataStart());
-
-        assertEquals(ENCRYPTED_START, actual.getEncryptedDataStart());
-
-        assertEquals(DATA_END, actual.getDataEnd());
-    }
-
-    public void testEquals_Success() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertEquals(params1, params2);
-    }
-
-    public void testEquals_EncAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(new String(
-                "AES-256/CBC/PKCS7Padding"), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_EncParams_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec("BLAHBLAH".getBytes()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_EncKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec("BLAHBLAH".getBytes(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_MacAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), "BLAHBLAH", null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_MacKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec("FAKE_MAC_KEY".getBytes(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_MacTag_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), "broken".getBytes(),
-                AUTHENTICATED_START, ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_AuthenticatedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START - 1,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_EncryptedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START - 1, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_DataEnd_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END + 1);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testHashCode_Success() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertEquals(params1.hashCode(), params2.hashCode());
-    }
-
-    public void testHashCode_EncAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(new String(
-                "AES-256/CBC/PKCS7Padding"), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_EncParams_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec("BLAHBLAH".getBytes()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_EncKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec("BLAHBLAH".getBytes(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_MacAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), "BLAHBLAH", null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_MacKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec("FAKE_MAC_KEY".getBytes(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_MacTag_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), "broken".getBytes(),
-                AUTHENTICATED_START, ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_AuthenticatedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START - 1,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_EncryptedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START - 1, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_DataEnd_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END + 1);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-}
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index e9fd5fb..47554a6 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -17,20 +17,18 @@
 package android.content.res;
 
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.TypedValue;
 
 import com.android.frameworks.coretests.R;
 
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 
 public class ConfigurationBoundResourceCacheTest
         extends ActivityInstrumentationTestCase2<ResourceCacheActivity> {
 
     ConfigurationBoundResourceCache<Float> mCache;
 
-    Method mCalcConfigChanges;
-
     public ConfigurationBoundResourceCacheTest() {
         super(ResourceCacheActivity.class);
     }
@@ -38,36 +36,45 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mCache = new ConfigurationBoundResourceCache<Float>(getActivity().getResources());
+        mCache = new ConfigurationBoundResourceCache<>();
     }
 
+    @SmallTest
     public void testGetEmpty() {
-        assertNull(mCache.get(-1, null));
+        final Resources res = getActivity().getResources();
+        assertNull(mCache.getInstance(-1, res, null));
     }
 
+    @SmallTest
     public void testSetGet() {
         mCache.put(1, null, new DummyFloatConstantState(5f));
-        assertEquals(5f, mCache.get(1, null));
-        assertNotSame(5f, mCache.get(1, null));
-        assertEquals(null, mCache.get(1, getActivity().getTheme()));
+        final Resources res = getActivity().getResources();
+        assertEquals(5f, mCache.getInstance(1, res, null));
+        assertNotSame(5f, mCache.getInstance(1, res, null));
+        assertEquals(null, mCache.getInstance(1, res, getActivity().getTheme()));
     }
 
+    @SmallTest
     public void testSetGetThemed() {
         mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f));
-        assertEquals(null, mCache.get(1, null));
-        assertEquals(5f, mCache.get(1, getActivity().getTheme()));
-        assertNotSame(5f, mCache.get(1, getActivity().getTheme()));
+        final Resources res = getActivity().getResources();
+        assertEquals(null, mCache.getInstance(1, res, null));
+        assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+        assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
     }
 
+    @SmallTest
     public void testMultiThreadPutGet() {
         mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f));
         mCache.put(1, null, new DummyFloatConstantState(10f));
-        assertEquals(10f, mCache.get(1, null));
-        assertNotSame(10f, mCache.get(1, null));
-        assertEquals(5f, mCache.get(1, getActivity().getTheme()));
-        assertNotSame(5f, mCache.get(1, getActivity().getTheme()));
+        final Resources res = getActivity().getResources();
+        assertEquals(10f, mCache.getInstance(1, res, null));
+        assertNotSame(10f, mCache.getInstance(1, res, null));
+        assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+        assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
     }
 
+    @SmallTest
     public void testVoidConfigChange()
             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
         TypedValue staticValue = new TypedValue();
@@ -83,11 +90,12 @@
                 Configuration.ORIENTATION_PORTRAIT
                 : Configuration.ORIENTATION_LANDSCAPE;
         int changes = calcConfigChanges(res, newCnf);
-        assertEquals(staticDim, mCache.get(key, getActivity().getTheme()));
+        assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
         mCache.onConfigurationChange(changes);
-        assertEquals(staticDim, mCache.get(key, getActivity().getTheme()));
+        assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
     }
 
+    @SmallTest
     public void testEffectiveConfigChange()
             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
         TypedValue changingValue = new TypedValue();
@@ -105,11 +113,12 @@
                 Configuration.ORIENTATION_PORTRAIT
                 : Configuration.ORIENTATION_LANDSCAPE;
         int changes = calcConfigChanges(res, newCnf);
-        assertEquals(changingDim, mCache.get(key, getActivity().getTheme()));
+        assertEquals(changingDim, mCache.getInstance(key, res, getActivity().getTheme()));
         mCache.onConfigurationChange(changes);
         assertNull(mCache.get(key, getActivity().getTheme()));
     }
 
+    @SmallTest
     public void testConfigChangeMultipleResources()
             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
         TypedValue staticValue = new TypedValue();
@@ -130,17 +139,19 @@
                 Configuration.ORIENTATION_PORTRAIT
                 : Configuration.ORIENTATION_LANDSCAPE;
         int changes = calcConfigChanges(res, newCnf);
-        assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic,
+        assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
                 getActivity().getTheme()));
-        assertEquals(changingDim, mCache.get(R.dimen.resource_cache_test_orientation_dependent,
-                getActivity().getTheme()));
+        assertEquals(changingDim,
+                mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
+                        getActivity().getTheme()));
         mCache.onConfigurationChange(changes);
-        assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic,
+        assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
                 getActivity().getTheme()));
-        assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent,
+        assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
                 getActivity().getTheme()));
     }
 
+    @SmallTest
     public void testConfigChangeMultipleThemes()
             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
         TypedValue[] staticValues = new TypedValue[]{new TypedValue(), new TypedValue()};
@@ -172,31 +183,27 @@
         int changes = calcConfigChanges(res, newCnf);
         for (int i = 0; i < 2; i++) {
             final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
-            assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme));
+            assertEquals(staticDim,
+                    mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
             assertEquals(changingDim,
-                    mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme));
+                    mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
+                            theme));
         }
         mCache.onConfigurationChange(changes);
         for (int i = 0; i < 2; i++) {
             final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
-            assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme));
-            assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme));
+            assertEquals(staticDim,
+                    mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
+            assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
+                    theme));
         }
     }
 
-    private int calcConfigChanges(Resources resources, Configuration configuration)
-            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
-        if (mCalcConfigChanges == null) {
-            mCalcConfigChanges = Resources.class.getDeclaredMethod("calcConfigChanges",
-                    Configuration.class);
-            mCalcConfigChanges.setAccessible(true);
-        }
-        return (Integer) mCalcConfigChanges.invoke(resources, configuration);
-
+    private static int calcConfigChanges(Resources resources, Configuration configuration) {
+        return resources.calcConfigChanges(configuration);
     }
 
-    static class DummyFloatConstantState extends
-            ConstantState<Float> {
+    static class DummyFloatConstantState extends ConstantState<Float> {
 
         final Float mObj;
 
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
new file mode 100644
index 0000000..d4bb0f3
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR 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.res;
+
+import android.annotation.NonNull;
+import android.app.ResourcesManager;
+import android.os.Binder;
+import android.support.test.filters.SmallTest;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+import android.util.TypedValue;
+import android.view.Display;
+import junit.framework.TestCase;
+
+public class ResourcesManagerTest extends TestCase {
+    private static final String APP_ONE_RES_DIR = "app_one.apk";
+    private static final String APP_ONE_RES_SPLIT_DIR = "app_one_split.apk";
+    private static final String APP_TWO_RES_DIR = "app_two.apk";
+    private static final String LIB_RES_DIR = "lib.apk";
+
+    private ResourcesManager mResourcesManager;
+    private DisplayMetrics mDisplayMetrics;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDisplayMetrics = new DisplayMetrics();
+        mDisplayMetrics.setToDefaults();
+
+        // Override defaults (which take device specific properties).
+        mDisplayMetrics.density = 1.0f;
+        mDisplayMetrics.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
+        mDisplayMetrics.xdpi = DisplayMetrics.DENSITY_DEFAULT;
+        mDisplayMetrics.ydpi = DisplayMetrics.DENSITY_DEFAULT;
+        mDisplayMetrics.noncompatDensity = mDisplayMetrics.density;
+        mDisplayMetrics.noncompatDensityDpi = mDisplayMetrics.densityDpi;
+        mDisplayMetrics.noncompatXdpi = DisplayMetrics.DENSITY_DEFAULT;
+        mDisplayMetrics.noncompatYdpi = DisplayMetrics.DENSITY_DEFAULT;
+
+        mResourcesManager = new ResourcesManager() {
+            @Override
+            protected AssetManager createAssetManager(@NonNull ResourcesKey key) {
+                return new AssetManager();
+            }
+
+            @Override
+            protected DisplayMetrics getDisplayMetrics(int displayId) {
+                return mDisplayMetrics;
+            }
+        };
+    }
+
+    @SmallTest
+    public void testMultipleCallsWithIdenticalParametersCacheReference() {
+        Resources resources = mResourcesManager.getResources(
+                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources);
+
+        Resources newResources = mResourcesManager.getResources(
+                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(newResources);
+        assertSame(resources, newResources);
+    }
+
+    @SmallTest
+    public void testMultipleCallsWithDifferentParametersReturnDifferentReferences() {
+        Resources resources = mResourcesManager.getResources(
+                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources);
+
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.smallestScreenWidthDp = 200;
+        Resources newResources = mResourcesManager.getResources(
+                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, overrideConfig,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(newResources);
+        assertNotSame(resources, newResources);
+    }
+
+    @SmallTest
+    public void testAddingASplitCreatesANewImpl() {
+        Resources resources1 = mResourcesManager.getResources(
+                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources1);
+
+        Resources resources2 = mResourcesManager.getResources(
+                null, APP_ONE_RES_DIR, new String[] { APP_ONE_RES_SPLIT_DIR }, null, null,
+                Display.DEFAULT_DISPLAY, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources2);
+
+        assertNotSame(resources1, resources2);
+        assertNotSame(resources1.getImpl(), resources2.getImpl());
+    }
+
+    @SmallTest
+    public void testUpdateConfigurationUpdatesAllAssetManagers() {
+        Resources resources1 = mResourcesManager.getResources(
+                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources1);
+
+        Resources resources2 = mResourcesManager.getResources(
+                null, APP_TWO_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources2);
+
+        Binder activity = new Binder();
+        final Configuration overrideConfig = new Configuration();
+        overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        Resources resources3 = mResourcesManager.getResources(
+                activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
+                overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources3);
+
+        // No Resources object should be the same.
+        assertNotSame(resources1, resources2);
+        assertNotSame(resources1, resources3);
+        assertNotSame(resources2, resources3);
+
+        // Each ResourcesImpl should be different.
+        assertNotSame(resources1.getImpl(), resources2.getImpl());
+        assertNotSame(resources1.getImpl(), resources3.getImpl());
+        assertNotSame(resources2.getImpl(), resources3.getImpl());
+
+        Configuration newConfig = new Configuration();
+        newConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null);
+
+        final Configuration expectedConfig = new Configuration();
+        expectedConfig.setLocales(LocaleList.getAdjustedDefault());
+        expectedConfig.densityDpi = mDisplayMetrics.densityDpi;
+        expectedConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
+
+        assertEquals(expectedConfig, resources1.getConfiguration());
+        assertEquals(expectedConfig, resources2.getConfiguration());
+        assertEquals(expectedConfig, resources3.getConfiguration());
+    }
+
+    @SmallTest
+    public void testTwoActivitiesWithIdenticalParametersShareImpl() {
+        Binder activity1 = new Binder();
+        Resources resources1 = mResourcesManager.getResources(
+                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources1);
+
+        Binder activity2 = new Binder();
+        Resources resources2 = mResourcesManager.getResources(
+                activity2, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources1);
+
+        // The references themselves should be unique.
+        assertNotSame(resources1, resources2);
+
+        // The implementations should be the same.
+        assertSame(resources1.getImpl(), resources2.getImpl());
+    }
+
+    @SmallTest
+    public void testThemesGetUpdatedWithNewImpl() {
+        Binder activity1 = new Binder();
+        Resources resources1 = mResourcesManager.createBaseActivityResources(
+                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources1);
+
+        Resources.Theme theme = resources1.newTheme();
+        assertSame(resources1, theme.getResources());
+        theme.applyStyle(android.R.style.Theme_NoTitleBar, false);
+
+        TypedValue value = new TypedValue();
+        assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
+        assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
+        assertTrue(value.data != 0);
+
+        final Configuration overrideConfig = new Configuration();
+        overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mResourcesManager.updateResourcesForActivity(activity1, overrideConfig);
+        assertSame(resources1, theme.getResources());
+
+        // Make sure we can still access the data.
+        assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
+        assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
+        assertTrue(value.data != 0);
+    }
+
+    @SmallTest
+    public void testMultipleResourcesForOneActivityGetUpdatedWhenActivityBaseUpdates() {
+        Binder activity1 = new Binder();
+
+        // Create a Resources for the Activity.
+        Configuration config1 = new Configuration();
+        config1.densityDpi = 280;
+        Resources resources1 = mResourcesManager.createBaseActivityResources(
+                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources1);
+
+        // Create a Resources based on the Activity.
+        Configuration config2 = new Configuration();
+        config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+        Resources resources2 = mResourcesManager.getResources(
+                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config2,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources2);
+
+        assertNotSame(resources1, resources2);
+        assertNotSame(resources1.getImpl(), resources2.getImpl());
+
+        final Configuration expectedConfig1 = new Configuration();
+        expectedConfig1.setLocales(LocaleList.getAdjustedDefault());
+        expectedConfig1.densityDpi = 280;
+        assertEquals(expectedConfig1, resources1.getConfiguration());
+
+        // resources2 should be based on the Activity's override config, so the density should
+        // be the same as resources1.
+        final Configuration expectedConfig2 = new Configuration();
+        expectedConfig2.setLocales(LocaleList.getAdjustedDefault());
+        expectedConfig2.densityDpi = 280;
+        expectedConfig2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+        assertEquals(expectedConfig2, resources2.getConfiguration());
+
+        // Now update the Activity base override, and both resources should update.
+        config1.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mResourcesManager.updateResourcesForActivity(activity1, config1);
+
+        expectedConfig1.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        assertEquals(expectedConfig1, resources1.getConfiguration());
+
+        expectedConfig2.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        assertEquals(expectedConfig2, resources2.getConfiguration());
+    }
+}
diff --git a/core/tests/coretests/src/android/graphics/PathOffsetTest.java b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
new file mode 100644
index 0000000..950f873
--- /dev/null
+++ b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.graphics;
+
+
+import android.graphics.Bitmap.Config;
+import android.graphics.Path.Direction;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PathOffsetTest {
+
+    private static final int SQUARE = 10;
+    private static final int WIDTH = 100;
+    private static final int HEIGHT = 100;
+    private static final int START_X = 10;
+    private static final int START_Y = 20;
+    private static final int OFFSET_X = 30;
+    private static final int OFFSET_Y = 40;
+
+    @Test
+    @SmallTest
+    public void testPathOffset() {
+        Path actualPath = new Path();
+        actualPath.addRect(START_X, START_Y, START_X + SQUARE, START_Y + SQUARE, Direction.CW);
+        assertTrue(actualPath.isSimplePath);
+        actualPath.offset(OFFSET_X, OFFSET_Y);
+        assertTrue(actualPath.isSimplePath);
+
+        Path expectedPath = new Path();
+        expectedPath.addRect(START_X + OFFSET_X, START_Y + OFFSET_Y, START_X + OFFSET_X + SQUARE,
+                START_Y + OFFSET_Y + SQUARE, Direction.CW);
+
+        assertPaths(actualPath, expectedPath);
+    }
+
+    @Test
+    @SmallTest
+    public void testPathOffsetWithDestination() {
+        Path initialPath = new Path();
+        initialPath.addRect(START_X, START_Y, START_X + SQUARE, START_Y + SQUARE, Direction.CW);
+        Path actualPath = new Path();
+        assertTrue(initialPath.isSimplePath);
+        assertTrue(actualPath.isSimplePath);
+        initialPath.offset(OFFSET_X, OFFSET_Y, actualPath);
+        assertTrue(actualPath.isSimplePath);
+
+        Path expectedPath = new Path();
+        expectedPath.addRect(START_X + OFFSET_X, START_Y + OFFSET_Y, START_X + OFFSET_X + SQUARE,
+                START_Y + OFFSET_Y + SQUARE, Direction.CW);
+
+        assertPaths(actualPath, expectedPath);
+    }
+
+    private static void assertPaths(Path actual, Path expected) {
+        Bitmap actualBitmap = drawAndGetBitmap(actual);
+        Bitmap expectedBitmap = drawAndGetBitmap(expected);
+        assertTrue(actualBitmap.sameAs(expectedBitmap));
+    }
+
+    private static Bitmap drawAndGetBitmap(Path path) {
+        Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Config.ARGB_8888);
+        bitmap.eraseColor(Color.BLACK);
+        Paint paint = new Paint();
+        paint.setColor(Color.RED);
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawPath(path, paint);
+        return bitmap;
+    }
+
+}
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 9ab62cc..e7aca78 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -23,10 +23,10 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.os.UserHandle;
 import android.test.InstrumentationTestCase;
-import android.util.Pair;
 
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
@@ -58,25 +58,26 @@
 
     public void testGetAllValidScorers() throws Exception {
         // Package 1 - Valid scorer.
-        Pair<ResolveInfo, ResolveInfo> package1 = buildResolveInfo("package1", 1, true, true,
-                false);
+        ResolveInfoHolder package1 = buildResolveInfo("package1", 1, true, true, false, false);
 
         // Package 2 - Receiver does not have BROADCAST_NETWORK_PRIVILEGED permission.
-        Pair<ResolveInfo, ResolveInfo> package2 = buildResolveInfo("package2", 2, false, true,
-                false);
+        ResolveInfoHolder package2 = buildResolveInfo("package2", 2, false, true, false, false);
 
         // Package 3 - App does not have SCORE_NETWORKS permission.
-        Pair<ResolveInfo, ResolveInfo> package3 = buildResolveInfo("package3", 3, true, false,
-                false);
+        ResolveInfoHolder package3 = buildResolveInfo("package3", 3, true, false, false, false);
 
         // Package 4 - Valid scorer w/ optional config activity.
-        Pair<ResolveInfo, ResolveInfo> package4 = buildResolveInfo("package4", 4, true, true, true);
+        ResolveInfoHolder package4 = buildResolveInfo("package4", 4, true, true, true, false);
 
-        List<Pair<ResolveInfo, ResolveInfo>> scorers = new ArrayList<>();
+        // Package 5 - Valid scorer w/ optional service to bind to.
+        ResolveInfoHolder package5 = buildResolveInfo("package5", 5, true, true, false, true);
+
+        List<ResolveInfoHolder> scorers = new ArrayList<>();
         scorers.add(package1);
         scorers.add(package2);
         scorers.add(package3);
         scorers.add(package4);
+        scorers.add(package5);
         setScorers(scorers);
 
         Iterator<NetworkScorerAppData> result =
@@ -94,14 +95,20 @@
         assertEquals(4, next.mPackageUid);
         assertEquals(".ConfigActivity", next.mConfigurationActivityClassName);
 
+        assertTrue(result.hasNext());
+        next = result.next();
+        assertEquals("package5", next.mPackageName);
+        assertEquals(5, next.mPackageUid);
+        assertEquals(".ScoringService", next.mScoringServiceClassName);
+
         assertFalse(result.hasNext());
     }
 
-    private void setScorers(List<Pair<ResolveInfo, ResolveInfo>> scorers) {
+    private void setScorers(List<ResolveInfoHolder> scorers) {
         List<ResolveInfo> receivers = new ArrayList<>();
-        for (final Pair<ResolveInfo, ResolveInfo> scorer : scorers) {
-            receivers.add(scorer.first);
-            if (scorer.second != null) {
+        for (final ResolveInfoHolder scorer : scorers) {
+            receivers.add(scorer.scorerResolveInfo);
+            if (scorer.configActivityResolveInfo != null) {
                 // This scorer has a config activity.
                 Mockito.when(mMockPm.queryIntentActivities(
                         Mockito.argThat(new ArgumentMatcher<Intent>() {
@@ -110,10 +117,26 @@
                                 Intent intent = (Intent) object;
                                 return NetworkScoreManager.ACTION_CUSTOM_ENABLE.equals(
                                         intent.getAction())
-                                        && scorer.first.activityInfo.packageName.equals(
+                                        && scorer.scorerResolveInfo.activityInfo.packageName.equals(
                                                 intent.getPackage());
                             }
-                        }), Mockito.eq(0))).thenReturn(Collections.singletonList(scorer.second));
+                        }), Mockito.eq(0))).thenReturn(
+                                Collections.singletonList(scorer.configActivityResolveInfo));
+            }
+
+            if (scorer.serviceResolveInfo != null) {
+                // This scorer has a service to bind to
+                Mockito.when(mMockPm.resolveService(
+                        Mockito.argThat(new ArgumentMatcher<Intent>() {
+                            @Override
+                            public boolean matches(Object object) {
+                                Intent intent = (Intent) object;
+                                return NetworkScoreManager.ACTION_SCORE_NETWORKS.equals(
+                                        intent.getAction())
+                                        && scorer.scorerResolveInfo.activityInfo.packageName.equals(
+                                        intent.getPackage());
+                            }
+                        }), Mockito.eq(0))).thenReturn(scorer.serviceResolveInfo);
             }
         }
 
@@ -128,9 +151,9 @@
                 .thenReturn(receivers);
     }
 
-    private Pair<ResolveInfo, ResolveInfo> buildResolveInfo(String packageName, int packageUid,
-            boolean hasReceiverPermission, boolean hasScorePermission, boolean hasConfigActivity)
-            throws Exception {
+    private ResolveInfoHolder buildResolveInfo(String packageName, int packageUid,
+            boolean hasReceiverPermission, boolean hasScorePermission, boolean hasConfigActivity,
+            boolean hasServiceInfo) throws Exception {
         Mockito.when(mMockPm.checkPermission(permission.SCORE_NETWORKS, packageName))
                 .thenReturn(hasScorePermission ?
                         PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
@@ -150,6 +173,27 @@
             configActivityInfo.activityInfo = new ActivityInfo();
             configActivityInfo.activityInfo.name = ".ConfigActivity";
         }
-        return Pair.create(resolveInfo, configActivityInfo);
+
+        ResolveInfo serviceInfo = null;
+        if (hasServiceInfo) {
+            serviceInfo = new ResolveInfo();
+            serviceInfo.serviceInfo = new ServiceInfo();
+            serviceInfo.serviceInfo.name = ".ScoringService";
+        }
+
+        return new ResolveInfoHolder(resolveInfo, configActivityInfo, serviceInfo);
+    }
+
+    private static class ResolveInfoHolder {
+        final ResolveInfo scorerResolveInfo;
+        final ResolveInfo configActivityResolveInfo;
+        final ResolveInfo serviceResolveInfo;
+
+        public ResolveInfoHolder(ResolveInfo scorerResolveInfo,
+                ResolveInfo configActivityResolveInfo, ResolveInfo serviceResolveInfo) {
+            this.scorerResolveInfo = scorerResolveInfo;
+            this.configActivityResolveInfo = configActivityResolveInfo;
+            this.serviceResolveInfo = serviceResolveInfo;
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index a723977..9074f8a 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -17,8 +17,8 @@
 package android.net;
 
 import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_DEFAULT;
-import static android.net.NetworkStats.ROAMING_ROAMING;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.ROAMING_YES;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
 import static android.net.NetworkStats.SET_DBG_VPN_IN;
@@ -46,57 +46,57 @@
 
     public void testFindIndex() throws Exception {
         final NetworkStats stats = new NetworkStats(TEST_START, 4)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L,
                         0L, 10)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 1024L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L,
                         8L, 11)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
                         1024L, 8L, 12)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 1024L, 8L,
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L,
                         1024L, 8L, 12);
 
-        assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING));
-        assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT));
-        assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT));
-        assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT));
-        assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT));
+        assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES));
+        assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO));
+        assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO));
+        assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO));
+        assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, ROAMING_NO));
     }
 
     public void testFindIndexHinted() {
         final NetworkStats stats = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L,
                         0L, 10)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 1024L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L,
                         8L, 11)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
                         1024L, 8L, 12)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 1024L, 8L,
                         0L, 0L, 10)
-                .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 0L, 0L, 1024L,
+                .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 0L, 0L, 1024L,
                         8L, 11)
-                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
                         1024L, 8L, 12)
-                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 1024L, 8L,
+                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L,
                         1024L, 8L, 12);
 
         // verify that we correctly find across regardless of hinting
         for (int hint = 0; hint < stats.size(); hint++) {
             assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE,
-                    ROAMING_DEFAULT, hint));
+                    ROAMING_NO, hint));
             assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE,
-                    ROAMING_DEFAULT, hint));
+                    ROAMING_NO, hint));
             assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE,
-                    ROAMING_DEFAULT, hint));
+                    ROAMING_NO, hint));
             assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE,
-                    ROAMING_DEFAULT, hint));
+                    ROAMING_NO, hint));
             assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
-                    ROAMING_DEFAULT, hint));
+                    ROAMING_NO, hint));
             assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
-                    ROAMING_DEFAULT, hint));
+                    ROAMING_NO, hint));
             assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
-                    ROAMING_ROAMING, hint));
+                    ROAMING_YES, hint));
             assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE,
-                    ROAMING_DEFAULT, hint));
+                    ROAMING_NO, hint));
         }
     }
 
@@ -106,41 +106,41 @@
         assertEquals(0, stats.size());
         assertEquals(3, stats.internalSize());
 
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L, 1L, 2L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L,
                 2L, 3);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 2L, 2L, 2L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L, 2L,
                 2L, 4);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 3L, 3L, 2L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L, 2L,
                 2L, 5);
 
         assertEquals(3, stats.size());
         assertEquals(3, stats.internalSize());
 
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 4L, 40L, 4L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L, 40L, 4L,
                 40L, 7);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 5L, 50L, 4L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L, 50L, 4L,
                 40L, 8);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 6L, 60L, 5L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L, 60L, 5L,
                 50L, 10);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 7L, 70L, 5L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L, 70L, 5L,
                 50L, 11);
 
         assertEquals(7, stats.size());
         assertTrue(stats.internalSize() >= 7);
 
-        assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L, 1L,
+        assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L,
                 2L, 2L, 3);
-        assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 2L, 2L,
+        assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L,
                 2L, 2L, 4);
-        assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 3L, 3L,
+        assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L,
                 2L, 2L, 5);
-        assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 4L,
+        assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L,
                 40L, 4L, 40L, 7);
-        assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 5L,
+        assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L,
                 50L, 4L, 40L, 8);
-        assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 6L,
+        assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L,
                 60L, 5L, 50L, 10);
-        assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 7L,
+        assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L,
                 70L, 5L, 50L, 11);
     }
 
@@ -152,19 +152,19 @@
         stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
                 -128L, -1L, -1);
 
-        assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 384L, 3L,
+        assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, ROAMING_NO, 384L, 3L,
                 128L, 1L, 9);
-        assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, ROAMING_DEFAULT, 128L, 1L, 128L,
+        assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, ROAMING_NO, 128L, 1L, 128L,
                 1L, 2);
 
         // now try combining that should create row
         stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L,
                 128L, 1L, 3);
-        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 1L,
+        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 1L,
                 128L, 1L, 3);
         stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L,
                 128L, 1L, 3);
-        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 256L, 2L,
+        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 256L, 2L,
                 256L, 2L, 6);
     }
 
@@ -180,9 +180,9 @@
         final NetworkStats result = after.subtract(before);
 
         // identical data should result in zero delta
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
                 0L, 0);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
                 0L, 0);
     }
 
@@ -198,9 +198,9 @@
         final NetworkStats result = after.subtract(before);
 
         // expect delta between measurements
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L, 1L, 2L,
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L,
                 1L, 4);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 3L, 1L, 4L,
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 3L, 1L, 4L,
                 1L, 8);
     }
 
@@ -217,11 +217,11 @@
         final NetworkStats result = after.subtract(before);
 
         // its okay to have new rows
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
                 0L, 0);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
                 0L, 0);
-        assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+        assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
                 1024L, 8L, 20);
     }
 
@@ -237,7 +237,7 @@
 
         // should silently drop omitted rows
         assertEquals(1, result.size());
-        assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L,
+        assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L,
                 2L, 3L, 4L, 0);
         assertEquals(4L, result.getTotalBytes());
     }
@@ -264,11 +264,11 @@
         assertEquals(64L, uidTag.getTotalBytes());
 
         final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L, 0L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 32L, 0L, 0L, 0L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 32L, 0L, 0L, 0L,
                         0L);
         assertEquals(96L, uidRoaming.getTotalBytes());
     }
@@ -283,11 +283,11 @@
 
     public void testGroupedByIfaceAll() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
-                .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L, 2L,
+                .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, 2L,
                         20L)
-                .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
                         2L, 20L)
-                .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, ROAMING_ROAMING, 128L, 8L, 0L, 2L,
+                .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, ROAMING_YES, 128L, 8L, 0L, 2L,
                         20L);
         final NetworkStats grouped = uidStats.groupedByIface();
 
@@ -300,19 +300,19 @@
 
     public void testGroupedByIface() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
                         2L, 20L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 512L, 32L, 0L,
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L,
                         0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 4L, 0L, 0L,
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 512L, 32L,
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L,
                         0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
                         0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 128L, 8L, 0L, 0L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 8L, 0L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L,
                         0L, 0L);
 
         final NetworkStats grouped = uidStats.groupedByIface();
@@ -328,49 +328,49 @@
 
     public void testAddAllValues() {
         final NetworkStats first = new NetworkStats(TEST_START, 5)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L,
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L, 0L,
                         0L, 0L)
-                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_ROAMING, 32L, 0L, 0L,
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L,
                         0L, 0L);
 
         final NetworkStats second = new NetworkStats(TEST_START, 2)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L,
+                .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L,
                         0L, 0L, 0L)
-                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_ROAMING, 32L, 0L, 0L,
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L,
                         0L, 0L);
 
         first.combineAllValues(second);
 
         assertEquals(4, first.size());
-        assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 64L, 0L, 0L,
+        assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 64L, 0L, 0L,
                 0L, 0L);
-        assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 32L, 0L,
+        assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L,
                 0L, 0L, 0L);
-        assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_ROAMING, 64L, 0L,
+        assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 64L, 0L,
                 0L, 0L, 0L);
-        assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L,
+        assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L,
                 0L, 0L, 0L, 0L);
     }
 
     public void testGetTotal() {
         final NetworkStats stats = new NetworkStats(TEST_START, 7)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
                         2L, 20L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 512L, 32L, 0L,
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L,
                         0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 4L, 0L, 0L,
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 512L, 32L,
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L,
                         0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
                         0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 128L, 8L, 0L, 0L,
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L,
                         0L)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 8L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L,
                         0L, 0L);
 
         assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
@@ -396,9 +396,9 @@
         final NetworkStats after = before.withoutUids(new int[] { 100 });
         assertEquals(6, before.size());
         assertEquals(2, after.size());
-        assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L,
+        assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L,
                 0L, 0L, 0L);
-        assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 128L, 8L, 0L,
+        assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L,
                 0L, 0L);
     }
 
@@ -457,53 +457,53 @@
         assertEquals(21, delta.size());
 
         // tunIface and TEST_IFACE entries are not changed.
-        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                 39605L, 46L, 12259L, 55L, 0L);
-        assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE,  ROAMING_DEFAULT, 0L, 0L,
+        assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L,
                 0L, 0L, 0L);
-        assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                 72667L, 197L, 43909L, 241L, 0L);
-        assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
                 9297L, 17L, 4128L, 21L, 0L);
-        assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                 4983L, 10L, 1801L, 12L, 0L);
-        assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 0L, 0L,
+        assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L,
                 0L, 0L, 0L);
-        assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, ROAMING_DEFAULT,
+        assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
                 21691L, 41L, 13820L, 51L, 0L);
-        assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, ROAMING_DEFAULT, 1281L,
+        assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO, 1281L,
                 2L, 665L, 2L, 0L);
-        assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1685L, 5L,
+        assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1685L, 5L,
                 2070L, 6L, 0L);
 
         // Existing underlying Iface entries are updated
-        assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                 44783L, 54L, 13829L, 60L, 0L);
-        assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
                 0L, 0L, 0L, 0L, 0L);
 
         // VPN underlying Iface entries are updated
-        assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                 28304L, 27L, 1719L, 12L, 0L);
-        assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
+        assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
                 0L, 0L, 0L, 0L, 0L);
 
         // New entries are added for new application's underlying Iface traffic
-        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                 72667L, 197L, 41872L, 219L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
+        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
                 9297L, 17L, 3936, 19L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_DEFAULT,
+        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
                 21691L, 41L, 13179L, 46L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_DEFAULT,
+        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO,
                 1281L, 2L, 634L, 1L, 0L);
 
         // New entries are added for debug purpose
-        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_DEFAULT,
+        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
                 39605L, 46L, 11690, 49, 0);
-        assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_DEFAULT,
+        assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
                 81964, 214, 45808, 238, 0);
-        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_DEFAULT,
+        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
                 4983, 10, 1717, 10, 0);
         assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
                 126552, 270, 59215, 297, 0);
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
index 3feb0e9..d56a405 100644
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.print.PrintAttributes;
@@ -61,7 +62,6 @@
 public abstract class BasePrintTest extends InstrumentationTestCase {
 
     private static final long OPERATION_TIMEOUT = 30000;
-    private static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
     private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
     private static final String COMMAND_LIST_ENABLED_IME_COMPONENTS = "ime list -s";
     private static final String COMMAND_PREFIX_ENABLE_IME = "ime enable ";
@@ -249,8 +249,9 @@
     protected void clearPrintSpoolerData() throws Exception {
         assertTrue("failed to clear print spooler data",
                 runShellCommand(getInstrumentation(), String.format(
-                        "pm clear --user %d %s", CURRENT_USER_ID, PRINT_SPOOLER_PACKAGE_NAME))
-                                .contains(PM_CLEAR_SUCCESS_OUTPUT));
+                        "pm clear --user %d %s", CURRENT_USER_ID,
+                        PrintManager.PRINT_SPOOLER_PACKAGE_NAME))
+                        .contains(PM_CLEAR_SUCCESS_OUTPUT));
     }
 
     @SuppressWarnings("unchecked")
@@ -281,7 +282,8 @@
         }
         if (onRequestCustomPrinterIcon != null) {
             doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
-                    any(PrinterId.class), any(CustomPrinterIconCallback.class));
+                    any(PrinterId.class), any(CancellationSignal.class),
+                    any(CustomPrinterIconCallback.class));
         }
         if (onStopPrinterStateTracking != null) {
             doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 5179b42..d491ec4 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -27,31 +27,19 @@
 import android.os.Process;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.print.IPrintDocumentAdapter;
-import android.print.IPrintJobStateChangeListener;
-import android.print.IPrintManager;
-import android.print.IPrinterDiscoveryObserver;
-import android.print.PageRange;
-import android.print.PrintAttributes;
 import android.print.PrintAttributes.Margins;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Resolution;
-import android.print.PrintDocumentAdapter;
-import android.print.PrintJob;
-import android.print.PrintJobId;
-import android.print.PrintJobInfo;
-import android.print.PrintManager;
-import android.print.PrinterCapabilitiesInfo;
-import android.print.PrinterDiscoverySession;
-import android.print.PrinterId;
-import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
 
 import android.print.mockservice.MockPrintService;
 import android.print.mockservice.PrintServiceCallbacks;
 import android.print.mockservice.PrinterDiscoverySessionCallbacks;
 import android.print.mockservice.StubbablePrinterDiscoverySession;
 
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
@@ -134,7 +122,7 @@
 
                                 if (session.getPrinters().isEmpty()) {
                                     final String PRINTER_NAME = "good printer";
-                                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+                                    List<PrinterInfo> printers = new ArrayList<>();
 
                                     // Add the printer.
                                     mGoodPrinterId = session.getService()
@@ -184,6 +172,29 @@
     }
 
     /**
+     * Create a IPrintServicesChangeListener object.
+     *
+     * @return the object
+     * @throws Exception if the object could not be created.
+     */
+    private IPrintServicesChangeListener createMockIPrintServicesChangeListener() throws Exception {
+        return new PrintManager.PrintServicesChangeListenerWrapper(null,
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Create a IPrintServiceRecommendationsChangeListener object.
+     *
+     * @return the object
+     * @throws Exception if the object could not be created.
+     */
+    private IRecommendationsChangeListener
+    createMockIPrintServiceRecommendationsChangeListener() throws Exception {
+        return new PrintManager.PrintServiceRecommendationsChangeListenerWrapper(null,
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
      * Create a IPrinterDiscoveryObserver object.
      *
      * @return the object
@@ -193,6 +204,16 @@
         return new PrinterDiscoverySession.PrinterDiscoveryObserver(null);
     }
 
+    private void startPrinting() {
+        mGoodPrintJob = print(createMockAdapter(), null);
+
+        // Wait for PrintActivity to be ready
+        waitForStartAdapterCallbackCalled();
+
+        // Wait for printer discovery session to be ready
+        waitForPrinterDiscoverySessionStartCallbackCalled();
+    }
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -201,20 +222,12 @@
 
         mGoodComponentName = getActivity().getComponentName();
 
-        mGoodPrintJob = print(createMockAdapter(), null);
-
         mIPrintManager = IPrintManager.Stub
                 .asInterface(ServiceManager.getService(Context.PRINT_SERVICE));
 
         // Generate dummy printerId which is a valid PrinterId object, but does not correspond to a
         // printer
         mBadPrinterId = new PrinterId(mGoodComponentName, "dummy printer");
-
-        // Wait for PrintActivity to be ready
-        waitForStartAdapterCallbackCalled();
-
-        // Wait for printer discovery session to be ready
-        waitForPrinterDiscoverySessionStartCallbackCalled();
     }
 
     /**
@@ -222,11 +235,11 @@
      */
     private interface Invokable {
         /**
-         * Execute the {@link Invokable}
+         * Execute the invokable
          *
          * @throws Exception
          */
-        public void run() throws Exception;
+        void run() throws Exception;
     }
 
     /**
@@ -254,7 +267,10 @@
     /**
      * test IPrintManager.getPrintJobInfo
      */
+    @LargeTest
     public void testGetPrintJobInfo() throws Exception {
+        startPrinting();
+
         assertEquals(mGoodPrintJob.getId(), mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(),
                         mAppId, mUserId).getId());
         assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId));
@@ -273,7 +289,10 @@
     /**
      * test IPrintManager.getPrintJobInfos
      */
+    @LargeTest
     public void testGetPrintJobInfos() throws Exception {
+        startPrinting();
+
         List<PrintJobInfo> infos = mIPrintManager.getPrintJobInfos(mAppId, mUserId);
 
         boolean foundPrintJob = false;
@@ -298,13 +317,14 @@
     /**
      * test IPrintManager.print
      */
+    @LargeTest
     public void testPrint() throws Exception {
         final String name = "dummy print job";
 
         final IPrintDocumentAdapter adapter = new PrintManager
                 .PrintDocumentAdapterDelegate(getActivity(), createMockAdapter());
 
-        // Valid parameters are tested in setUp()
+        startPrinting();
 
         assertException(new Invokable() {
             @Override
@@ -351,7 +371,10 @@
     /**
      * test IPrintManager.cancelPrintJob
      */
+    @LargeTest
     public void testCancelPrintJob() throws Exception {
+        startPrinting();
+
         // Invalid print jobs IDs do not produce an exception
         mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId);
         mIPrintManager.cancelPrintJob(null, mAppId, mUserId);
@@ -372,7 +395,10 @@
     /**
      * test IPrintManager.restartPrintJob
      */
+    @LargeTest
     public void testRestartPrintJob() throws Exception {
+        startPrinting();
+
         mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
 
         // Invalid print jobs IDs do not produce an exception
@@ -392,6 +418,7 @@
     /**
      * test IPrintManager.addPrintJobStateChangeListener
      */
+    @MediumTest
     public void testAddPrintJobStateChangeListener() throws Exception {
         final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
 
@@ -417,6 +444,7 @@
     /**
      * test IPrintManager.removePrintJobStateChangeListener
      */
+    @MediumTest
     public void testRemovePrintJobStateChangeListener() throws Exception {
         final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
 
@@ -438,21 +466,161 @@
     }
 
     /**
-     * test IPrintManager.getInstalledPrintServices
+     * test IPrintManager.addPrintServicesChangeListener
      */
-    public void testGetInstalledPrintServices() throws Exception {
-        List<PrintServiceInfo> printServices = mIPrintManager.getInstalledPrintServices(mUserId);
-        assertTrue(printServices.size() >= 2);
+    @MediumTest
+    public void testAddPrintServicesChangeListener() throws Exception {
+        final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
+
+        mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.addPrintServicesChangeListener(null, mUserId);
+            }
+        }, NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
 
     /**
-     * test IPrintManager.getEnabledPrintServices
+     * test IPrintManager.removePrintServicesChangeListener
      */
-    public void testGetEnabledPrintServices() throws Exception {
-        List<PrintServiceInfo> printServices = mIPrintManager.getEnabledPrintServices(mUserId);
-        assertTrue(printServices.size() >= 2);
+    @MediumTest
+    public void testRemovePrintServicesChangeListener() throws Exception {
+        final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
+
+        mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+        mIPrintManager.removePrintServicesChangeListener(listener, mUserId);
+
+        // Removing unknown listeners is a no-op
+        mIPrintManager.removePrintServicesChangeListener(listener, mUserId);
+
+        mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.removePrintServicesChangeListener(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.getPrintServices
+     */
+    @MediumTest
+    public void testGetPrintServices() throws Exception {
+        List<PrintServiceInfo> printServices = mIPrintManager.getPrintServices(
+                PrintManager.ALL_SERVICES, mUserId);
+        assertTrue(printServices.size() >= 1);
+
+        printServices = mIPrintManager.getPrintServices(0, mUserId);
+        assertEquals(printServices, null);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.getPrintServices(~PrintManager.ALL_SERVICES, mUserId);
+            }
+        }, IllegalArgumentException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.setPrintServiceEnabled
+     */
+    @MediumTest
+    public void testSetPrintServiceEnabled() throws Exception {
+        final ComponentName printService = mIPrintManager.getPrintServices(
+                PrintManager.ALL_SERVICES, mUserId).get(0).getComponentName();
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.setPrintServiceEnabled(printService, false, mUserId);
+            }
+        }, SecurityException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.setPrintServiceEnabled(printService, true, mUserId);
+            }
+        }, SecurityException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true,
+                                mUserId);
+            }
+        }, SecurityException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.setPrintServiceEnabled(null, true, mUserId);
+            }
+        }, SecurityException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.addPrintServiceRecommendationsChangeListener
+     */
+    @MediumTest
+    public void testAddPrintServiceRecommendationsChangeListener() throws Exception {
+        final IRecommendationsChangeListener listener =
+                createMockIPrintServiceRecommendationsChangeListener();
+
+        mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.addPrintServiceRecommendationsChangeListener(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.removePrintServicesChangeListener
+     */
+    @MediumTest
+    public void testRemovePrintServiceRecommendationsChangeListener() throws Exception {
+        final IRecommendationsChangeListener listener =
+                createMockIPrintServiceRecommendationsChangeListener();
+
+        mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+        mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId);
+
+        // Removing unknown listeners is a no-op
+        mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId);
+
+        mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.removePrintServiceRecommendationsChangeListener(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.getPrintServiceRecommendations
+     */
+    @MediumTest
+    public void testGetPrintServiceRecommendations() throws Exception {
+        mIPrintManager.getPrintServiceRecommendations(mUserId);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -460,6 +628,7 @@
     /**
      * test IPrintManager.createPrinterDiscoverySession
      */
+    @MediumTest
     public void testCreatePrinterDiscoverySession() throws Exception {
         final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
 
@@ -485,7 +654,10 @@
     /**
      * test IPrintManager.startPrinterDiscovery
      */
+    @LargeTest
     public void testStartPrinterDiscovery() throws Exception {
+        startPrinting();
+
         final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
         final List<PrinterId> goodPrinters = new ArrayList<>();
         goodPrinters.add(mGoodPrinterId);
@@ -525,6 +697,7 @@
     /**
      * test IPrintManager.stopPrinterDiscovery
      */
+    @MediumTest
     public void testStopPrinterDiscovery() throws Exception {
         final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
 
@@ -548,7 +721,10 @@
     /**
      * test IPrintManager.validatePrinters
      */
+    @LargeTest
     public void testValidatePrinters() throws Exception {
+        startPrinting();
+
         final List<PrinterId> goodPrinters = new ArrayList<>();
         goodPrinters.add(mGoodPrinterId);
 
@@ -586,7 +762,10 @@
     /**
      * test IPrintManager.startPrinterStateTracking
      */
+    @LargeTest
     public void testStartPrinterStateTracking() throws Exception {
+        startPrinting();
+
         mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
 
         // Bad printers do no cause exceptions
@@ -605,7 +784,10 @@
     /**
      * test IPrintManager.getCustomPrinterIcon
      */
+    @LargeTest
     public void testGetCustomPrinterIcon() throws Exception {
+        startPrinting();
+
         mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
 
         // Bad printers do no cause exceptions
@@ -624,7 +806,10 @@
     /**
      * test IPrintManager.stopPrinterStateTracking
      */
+    @LargeTest
     public void testStopPrinterStateTracking() throws Exception {
+        startPrinting();
+
         mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
         mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
 
@@ -648,6 +833,7 @@
     /**
      * test IPrintManager.destroyPrinterDiscoverySession
      */
+    @MediumTest
     public void testDestroyPrinterDiscoverySession() throws Exception {
         final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
 
diff --git a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
index 26b7cae..be002e2 100644
--- a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
+++ b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
@@ -16,6 +16,7 @@
 
 package android.print.mockservice;
 
+import android.os.CancellationSignal;
 import android.print.PrinterId;
 import android.printservice.CustomPrinterIconCallback;
 
@@ -42,7 +43,7 @@
     public abstract void onStartPrinterStateTracking(PrinterId printerId);
 
     public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
-            CustomPrinterIconCallback callback);
+            CancellationSignal cancellationSignal, CustomPrinterIconCallback callback);
 
     public abstract void onStopPrinterStateTracking(PrinterId printerId);
 
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
index 04683f2..e132d79 100644
--- a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
@@ -16,6 +16,7 @@
 
 package android.print.mockservice;
 
+import android.os.CancellationSignal;
 import android.print.PrinterId;
 import android.printservice.CustomPrinterIconCallback;
 import android.printservice.PrintService;
@@ -70,9 +71,9 @@
 
     @Override
     public void onRequestCustomPrinterIcon(PrinterId printerId,
-            CustomPrinterIconCallback callback) {
+            CancellationSignal cancellationSignal, CustomPrinterIconCallback callback) {
         if (mCallbacks != null) {
-            mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+            mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
         }
     }
 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index d554a50..cbed96c 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -20,6 +20,8 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.Layout.Alignment;
 import static android.text.Layout.Alignment.*;
+import android.text.TextPaint;
+import android.text.method.EditorState;
 import android.util.Log;
 
 import junit.framework.TestCase;
@@ -33,6 +35,10 @@
  * @Suppress
  */
 public class StaticLayoutTest extends TestCase {
+    private static final int DEFAULT_OUTER_WIDTH = 150;
+    private static final Alignment DEFAULT_ALIGN = Alignment.ALIGN_CENTER;
+    private static final float SPACE_MULTI = 1.0f;
+    private static final float SPACE_ADD = 0.0f;
 
     /**
      * Basic test showing expected behavior and relationship between font
@@ -321,4 +327,91 @@
         assertEquals(topPad, l.getTopPadding());
         assertEquals(botPad, l.getBottomPadding());
     }
+
+    private void moveCursorToRightCursorableOffset(EditorState state, TextPaint paint) {
+        assertEquals("The editor has selection", state.mSelectionStart, state.mSelectionEnd);
+        final Layout layout = builder().setText(state.mText.toString()).setPaint(paint).build();
+        final int newOffset = layout.getOffsetToRightOf(state.mSelectionStart);
+        state.mSelectionStart = state.mSelectionEnd = newOffset;
+    }
+
+    private void moveCursorToLeftCursorableOffset(EditorState state, TextPaint paint) {
+        assertEquals("The editor has selection", state.mSelectionStart, state.mSelectionEnd);
+        final Layout layout = builder().setText(state.mText.toString()).setPaint(paint).build();
+        final int newOffset = layout.getOffsetToLeftOf(state.mSelectionStart);
+        state.mSelectionStart = state.mSelectionEnd = newOffset;
+    }
+
+    /**
+     * Tests for keycap, variation selectors, flags are in CTS.
+     * See {@link android.text.cts.StaticLayoutTest}.
+     */
+    public void testEmojiOffset() {
+        EditorState state = new EditorState();
+        TextPaint paint = new TextPaint();
+
+        // Odd numbered regional indicator symbols.
+        // U+1F1E6 is REGIONAL INDICATOR SYMBOL LETTER A, U+1F1E8 is REGIONAL INDICATOR SYMBOL
+        // LETTER C.
+        state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+1F1E6 U+1F1E8 | U+1F1E6 U+1F1E8 U+1F1E6");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 | U+1F1E6");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6 |");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6 |");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 | U+1F1E6");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("U+1F1E6 U+1F1E8 | U+1F1E6 U+1F1E8 U+1F1E6");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
+        moveCursorToLeftCursorableOffset(state, paint);
+
+        // Zero width sequence
+        final String zwjSequence = "U+1F468 U+200D U+2764 U+FE0F U+200D U+1F468";
+        state.setByString("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
+        moveCursorToRightCursorableOffset(state, paint);
+        state.assertEquals(zwjSequence + " | " + zwjSequence + " " + zwjSequence);
+        moveCursorToRightCursorableOffset(state, paint);
+        state.assertEquals(zwjSequence + " " + zwjSequence + " | " + zwjSequence);
+        moveCursorToRightCursorableOffset(state, paint);
+        state.assertEquals(zwjSequence + " " + zwjSequence + " " + zwjSequence + " |");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.assertEquals(zwjSequence + " " + zwjSequence + " " + zwjSequence + " |");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.assertEquals(zwjSequence + " " + zwjSequence + " | " + zwjSequence);
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.assertEquals(zwjSequence + " | " + zwjSequence + " " + zwjSequence);
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.assertEquals("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.assertEquals("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
+        moveCursorToLeftCursorableOffset(state, paint);
+
+        // Emoji modifiers
+        // U+261D is WHITE UP POINTING INDEX, U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
+        state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+261D U+1F3FB | U+261D U+1F3FB U+261D U+1F3FB");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+261D U+1F3FB U+261D U+1F3FB | U+261D U+1F3FB");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB |");
+        moveCursorToRightCursorableOffset(state, paint);
+        state.setByString("U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB |");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("U+261D U+1F3FB U+261D U+1F3FB | U+261D U+1F3FB");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("U+261D U+1F3FB | U+261D U+1F3FB U+261D U+1F3FB");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
+        moveCursorToLeftCursorableOffset(state, paint);
+        state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
+        moveCursorToLeftCursorableOffset(state, paint);
+    }
 }
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index d2e811c..e1b305f 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -29,7 +29,8 @@
 /**
  * Test backspace key handling of {@link android.text.method.BaseKeyListner}.
  *
- * TODO: Move some of test cases to the CTS.
+ * Only contains edge cases. For normal cases, see {@see android.text.method.cts.BackspaceTest}.
+ * TODO: introduce test cases for surrogate pairs and replacement span.
  */
 public class BackspaceTest extends KeyListenerTestCase {
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
@@ -65,85 +66,13 @@
     }
 
     @SmallTest
-    public void testSurrogatePairs() {
-        EditorState state = new EditorState();
-
-        state.setByString("U+1F441 |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        state.setByString("U+1F441 U+1F5E8 |");
-        backspace(state, 0);
-        state.assertEquals("U+1F441 |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        // TODO: introduce edge cases.
-    }
-
-    @SmallTest
-    public void testReplacementSpan() {
-        EditorState state = new EditorState();
-
-        // ReplacementSpan will be set to "()" region.
-        state.setByString("'abc' ( 'de' ) 'fg' |");
-        backspace(state, 0);
-        state.assertEquals("'abc' ( 'de' ) 'f' |");
-        backspace(state, 0);
-        state.assertEquals("'abc' ( 'de' ) |");
-        backspace(state, 0);
-        state.assertEquals("'abc' |");
-        backspace(state, 0);
-        state.assertEquals("'ab' |");
-        backspace(state, 0);
-        state.assertEquals("'a' |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        state.setByString("'abc' [ ( 'de' ) ] 'fg'");
-        backspace(state, 0);
-        state.assertEquals("'abc' | 'fg'");
-        backspace(state, 0);
-        state.assertEquals("'ab' | 'fg'");
-        backspace(state, 0);
-        state.assertEquals("'a' | 'fg'");
-        backspace(state, 0);
-        state.assertEquals("| 'fg'");
-        backspace(state, 0);
-        state.assertEquals("| 'fg'");
-
-        state.setByString("'ab' [ 'c' ( 'de' ) 'f' ] 'g'");
-        backspace(state, 0);
-        state.assertEquals("'ab' | 'g'");
-        backspace(state, 0);
-        state.assertEquals("'a' | 'g'");
-        backspace(state, 0);
-        state.assertEquals("| 'g'");
-        backspace(state, 0);
-        state.assertEquals("| 'g'");
-
-        // TODO: introduce edge cases.
-    }
-
-    @SmallTest
     public void testCombiningEnclosingKeycaps() {
         EditorState state = new EditorState();
 
-        // U+20E3 is COMBINING ENCLOSING KEYCAP.
-        state.setByString("'1' U+20E3 |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        // Variation selector before COMBINING ECLOSING KEYCAP
-        state.setByString("'1' U+FE0E U+20E3 |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
         state.setByString("'1' U+E0101 U+20E3 |");
         backspace(state, 0);
         state.assertEquals("|");
 
-        // Edge cases
         // multiple COMBINING ENCLOSING KEYCAP
         state.setByString("'1' U+20E3 U+20E3 |");
         backspace(state, 0);
@@ -168,17 +97,6 @@
     public void testVariationSelector() {
         EditorState state = new EditorState();
 
-        // U+FE0F is VARIATION SELECTOR-16.
-        state.setByString("'#' U+FE0F |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        // U+E0100 is VARIATION SELECTOR-17.
-        state.setByString("U+845B U+E0100 |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        // Edge cases
         // Isolated variation selector
         state.setByString("U+FE0F |");
         backspace(state, 0);
@@ -256,7 +174,6 @@
         backspace(state, 0);
         state.assertEquals("|");
 
-        // Edge cases
         // End with ZERO WIDTH JOINER
         state.setByString("U+1F441 U+200D |");
         backspace(state, 0);
@@ -307,35 +224,6 @@
     public void testFlags() {
         EditorState state = new EditorState();
 
-        // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
-        // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S.
-        state.setByString("U+1F1FA U+1F1F8 |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        state.setByString("'a' U+1F1FA U+1F1F8 |");
-        backspace(state, 0);
-        state.assertEquals("'a' |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        state.setByString("U+1F1FA U+1F1F8 U+1F1FA U+1F1F8 |");
-        backspace(state, 0);
-        state.assertEquals("U+1F1FA U+1F1F8 |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        state.setByString("'a' U+1F1FA U+1F1F8 'b' U+1F1FA U+1F1F8 |");
-        backspace(state, 0);
-        state.assertEquals("'a' U+1F1FA U+1F1F8 'b' |");
-        backspace(state, 0);
-        state.assertEquals("'a' U+1F1FA U+1F1F8 |");
-        backspace(state, 0);
-        state.assertEquals("'a' |");
-        backspace(state, 0);
-        state.assertEquals("|");
-
-        // Edcae cases
         // Isolated regional indicator symbol
         state.setByString("U+1F1FA |");
         backspace(state, 0);
@@ -358,7 +246,6 @@
         backspace(state, 0);
         state.assertEquals("|");
 
-        // Edge cases
         // Isolated emoji modifier
         state.setByString("U+1F3FB |");
         backspace(state, 0);
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
new file mode 100644
index 0000000..0fed77c
--- /dev/null
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.method;
+
+import android.app.Activity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.InputType;
+import android.text.method.BaseKeyListener;
+import android.text.method.KeyListenerTestCase;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.TextView.BufferType;
+
+/**
+ * Test forward delete key handling of  {@link android.text.method.BaseKeyListener}.
+ *
+ * Only contains edge cases. For normal cases, see {@see android.text.method.cts.ForwardDeleteTest}.
+ * TODO: introduce test cases for surrogate pairs and replacement span.
+ */
+public class ForwardDeleteTest extends KeyListenerTestCase {
+    private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
+        public int getInputType() {
+            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        }
+    };
+
+    // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
+    // Then update the state to the result of TextView.
+    private void forwardDelete(final EditorState state, int modifiers) {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView.setText(state.mText, BufferType.EDITABLE);
+                mTextView.setKeyListener(mKeyListener);
+                mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.hasWindowFocus());
+
+        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        state.mText = mTextView.getText();
+        state.mSelectionStart = mTextView.getSelectionStart();
+        state.mSelectionEnd = mTextView.getSelectionEnd();
+    }
+
+    @SmallTest
+    public void testCombiningEnclosingKeycaps() {
+        EditorState state = new EditorState();
+
+        // multiple COMBINING ENCLOSING KEYCAP
+        state.setByString("| '1' U+20E3 U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+20E3 U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testVariationSelector() {
+        EditorState state = new EditorState();
+
+        // Isolated variation selectors
+        state.setByString("| U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple variation selectors
+        state.setByString("| U+FE0F U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+FE0F U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+E0100 U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+E0100 U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Multiple variation selectors
+        state.setByString("| '#' U+FE0F U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| '#' U+FE0F U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+845B U+E0100 U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+845B U+E0100 U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testEmojiZeroWidthJoinerSequence() {
+        EditorState state = new EditorState();
+
+        // U+200D is ZERO WIDTH JOINER.
+        state.setByString("| U+1F441 U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // End with ZERO WIDTH JOINER
+        state.setByString("| U+1F441 U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER
+        state.setByString("| U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Multiple ZERO WIDTH JOINER
+        state.setByString("| U+1F441 U+200D U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated ZERO WIDTH JOINER
+        state.setByString("| U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple ZERO WIDTH JOINER
+        state.setByString("| U+200D U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testFlags() {
+        EditorState state = new EditorState();
+
+        // Isolated regional indicator symbol
+        state.setByString("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Odd numbered regional indicator symbols
+        state.setByString("| U+1F1FA U+1F1F8 U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testEmojiModifier() {
+        EditorState state = new EditorState();
+
+        // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
+        state.setByString("| U+1F466 U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated emoji modifier
+        state.setByString("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple emoji modifier
+        state.setByString("| U+1F3FB U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Multiple emoji modifiers
+        state.setByString("| U+1F466 U+1F3FB U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testMixedEdgeCases() {
+        EditorState state = new EditorState();
+
+        // COMBINING ENCLOSING KEYCAP + variation selector
+        state.setByString("| '1' U+20E3 U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+2665 U+FE0F U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER
+        state.setByString("| '1' U+20E3 U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER
+        state.setByString("| '1' U+20E3 U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F5E8 ");
+
+        // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+200D U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+1F441 U+200D U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + regional indicator symbol
+        state.setByString("| '1' U+20E3 U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+1F1FA U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + emoji modifier
+        state.setByString("| '1' U+20E3 U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // Emoji modifier + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+1F466 U+1F3FB U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + end with ZERO WIDTH JOINER
+        state.setByString("| U+2665 U+FE0F U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + ZERO WIDTH JOINER
+        state.setByString("| U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER + variation selector
+        state.setByString("| U+200D U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // ZERO WIDTH JOINER + variation selector
+        state.setByString("| U+1F469 U+200D U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + regional indicator symbol
+        state.setByString("| U+2665 U+FE0F U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + variation selector
+        state.setByString("| U+1F1FA U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + emoji modifier
+        state.setByString("| U+2665 U+FE0F U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // Emoji modifier + variation selector
+        state.setByString("| U+1F466 U+1F3FB U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER + regional indicator symbol
+        state.setByString("| U+200D U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // ZERO WIDTH JOINER + regional indicator symbol
+        state.setByString("| U+1F469 U+200D U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+
+        // Regional indicator symbol + end with ZERO WIDTH JOINER
+        state.setByString("| U+1F1FA U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + ZERO WIDTH JOINER
+        state.setByString("| U+1F1FA U+200D U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER + emoji modifier
+        state.setByString("| U+200D U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // ZERO WIDTH JOINER + emoji modifier
+        state.setByString("| U+1F469 U+200D U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // Emoji modifier + end with ZERO WIDTH JOINER
+        state.setByString("| U+1F466 U+1F3FB U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Emoji modifier + ZERO WIDTH JOINER
+        state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + emoji modifier
+        state.setByString("| U+1F1FA U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Emoji modifier + regional indicator symbol
+        state.setByString("| U+1F466 U+1F3FB U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+}
diff --git a/core/tests/coretests/src/android/transition/AutoTransitionTest.java b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
new file mode 100644
index 0000000..834fb7a
--- /dev/null
+++ b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.transition;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+public class AutoTransitionTest {
+    @Test
+    @SmallTest
+    public void testFadeOutMoveFadeIn() throws Throwable {
+        AutoTransition autoTransition = new AutoTransition();
+        assertEquals(3, autoTransition.getTransitionCount());
+        Transition fadeOut = autoTransition.getTransitionAt(0);
+        assertNotNull(fadeOut);
+        assertTrue(fadeOut instanceof Fade);
+        assertEquals(Visibility.MODE_OUT, ((Fade)fadeOut).getMode());
+
+        Transition move = autoTransition.getTransitionAt(1);
+        assertNotNull(move);
+        assertTrue(move instanceof ChangeBounds);
+
+        Transition fadeIn = autoTransition.getTransitionAt(2);
+        assertNotNull(fadeIn);
+        assertTrue(fadeIn instanceof Fade);
+        assertEquals(Visibility.MODE_IN, ((Fade)fadeIn).getMode());
+
+        assertEquals(TransitionSet.ORDERING_SEQUENTIAL, autoTransition.getOrdering());
+    }
+}
diff --git a/core/tests/coretests/src/android/transition/SlideTransitionTest.java b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
new file mode 100644
index 0000000..8b9ec74
--- /dev/null
+++ b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.transition;
+
+import android.animation.AnimatorSetActivity;
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
+public class SlideTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
+
+    Activity mActivity;
+
+    public SlideTransitionTest() {
+        super(AnimatorSetActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        mActivity = getActivity();
+    }
+
+    @SmallTest
+    public void testShortSlide() throws Throwable {
+        final float slideFraction = 0.5f;
+        final View square1 = mActivity.findViewById(R.id.square1);
+        final View sceneRoot = mActivity.findViewById(R.id.container);
+        final SlideTranslationValueRatchet ratchet = new SlideTranslationValueRatchet(square1);
+        square1.getViewTreeObserver().addOnPreDrawListener(ratchet);
+
+        final Slide slideOut = new Slide(Gravity.BOTTOM);
+        final float finalOffsetOut = sceneRoot.getHeight() * slideFraction;
+        slideOut.setSlideFraction(slideFraction);
+        TransitionLatch latch = setVisibilityInTransition(slideOut, R.id.square1, View.INVISIBLE);
+        assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
+        assertEquals(0f, square1.getTranslationY(), 0.1f);
+        assertEquals(View.VISIBLE, square1.getVisibility());
+        Thread.sleep(100);
+        assertFalse(square1.getTranslationY() < 0.1
+                || square1.getTranslationY() > finalOffsetOut - 0.1);
+        assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
+        // Give this 20% slop in case some frames get dropped.
+        assertTrue(finalOffsetOut * 0.8 < ratchet.maxY);
+        assertTrue(finalOffsetOut + 0.1 > ratchet.maxY);
+        assertEquals(View.INVISIBLE, square1.getVisibility());
+
+        ratchet.reset();
+        final Slide slideIn = new Slide(Gravity.BOTTOM);
+        final float initialOffsetIn = sceneRoot.getHeight() * slideFraction;
+        slideIn.setSlideFraction(slideFraction);
+        latch = setVisibilityInTransition(slideIn, R.id.square1, View.VISIBLE);
+        assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
+        assertEquals(initialOffsetIn, square1.getTranslationY(), 0.1f);
+        assertEquals(View.VISIBLE, square1.getVisibility());
+        Thread.sleep(100);
+        assertFalse(square1.getTranslationY() < 0.1
+                || square1.getTranslationY() > initialOffsetIn - 0.1);
+        assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
+        assertEquals(0f, ratchet.minY, 0.1);
+        assertEquals(0f, square1.getTranslationY(), 0.1);
+        assertEquals(View.VISIBLE, square1.getVisibility());
+
+        square1.getViewTreeObserver().removeOnPreDrawListener(ratchet);
+    }
+
+    public TransitionLatch setVisibilityInTransition(final Transition transition, int viewId,
+            final int visibility) throws Throwable {
+        final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.container);
+        final View view = sceneRoot.findViewById(viewId);
+        TransitionLatch latch = new TransitionLatch();
+        transition.addListener(latch);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(sceneRoot, transition);
+                view.setVisibility(visibility);
+            }
+        });
+        return latch;
+    }
+
+    public static class TransitionLatch implements Transition.TransitionListener {
+        public CountDownLatch startLatch = new CountDownLatch(1);
+        public CountDownLatch endLatch = new CountDownLatch(1);
+        public CountDownLatch cancelLatch = new CountDownLatch(1);
+        public CountDownLatch pauseLatch = new CountDownLatch(1);
+        public CountDownLatch resumeLatch = new CountDownLatch(1);
+
+        @Override
+        public void onTransitionStart(Transition transition) {
+            startLatch.countDown();
+        }
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            endLatch.countDown();
+            transition.removeListener(this);
+        }
+
+        @Override
+        public void onTransitionCancel(Transition transition) {
+            cancelLatch.countDown();
+        }
+
+        @Override
+        public void onTransitionPause(Transition transition) {
+            pauseLatch.countDown();
+        }
+
+        @Override
+        public void onTransitionResume(Transition transition) {
+            resumeLatch.countDown();
+        }
+    }
+
+    private static class SlideTranslationValueRatchet
+            implements ViewTreeObserver.OnPreDrawListener {
+
+        private final View mView;
+        private boolean mInitialized;
+        public float minX = Float.NaN;
+        public float minY = Float.NaN;
+        public float maxX = Float.NaN;
+        public float maxY = Float.NaN;
+
+        public SlideTranslationValueRatchet(View view) {
+            mView = view;
+        }
+
+        public void reset() {
+            minX = minY = maxX = maxY = Float.NaN;
+            mInitialized = false;
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            if (!mInitialized) {
+                minX = maxX = mView.getTranslationX();
+                minY = maxY = mView.getTranslationY();
+                mInitialized = true;
+            } else {
+                minX = Math.min(minX, mView.getTranslationX());
+                minY = Math.min(minY, mView.getTranslationY());
+                maxX = Math.max(maxX, mView.getTranslationX());
+                maxY = Math.max(maxY, mView.getTranslationY());
+            }
+            return true;
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/transition/TransitionTest.java b/core/tests/coretests/src/android/transition/TransitionTest.java
new file mode 100644
index 0000000..7e72e25
--- /dev/null
+++ b/core/tests/coretests/src/android/transition/TransitionTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.transition;
+
+import android.animation.AnimatorSetActivity;
+import android.app.Activity;
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase2;
+import android.transition.Transition.EpicenterCallback;
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
+
+public class TransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
+    Activity mActivity;
+    public TransitionTest() {
+        super(AnimatorSetActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        mActivity = getActivity();
+    }
+
+    public void testClone() throws Throwable {
+        View square1 = mActivity.findViewById(R.id.square1);
+        View square2 = mActivity.findViewById(R.id.square2);
+        View square3 = mActivity.findViewById(R.id.square3);
+        Fade fade = new Fade();
+        fade.setStartDelay(1000);
+        fade.setDuration(1001);
+
+        fade.addTarget(square1);
+        fade.excludeTarget(square2, true);
+        fade.excludeChildren(square3, true);
+
+        fade.addTarget(R.id.square4);
+        fade.excludeTarget(R.id.square3, true);
+        fade.excludeChildren(R.id.square2, true);
+
+        fade.addTarget("hello");
+        fade.excludeTarget("world", true);
+
+        fade.addTarget(View.class);
+        fade.excludeTarget(TextView.class, true);
+
+        fade.setMatchOrder(Transition.MATCH_ID);
+        fade.setPropagation(new CircularPropagation());
+        fade.setPathMotion(new ArcMotion());
+        fade.setInterpolator(new AccelerateInterpolator());
+        fade.setNameOverrides(new ArrayMap<>());
+
+        EpicenterCallback epicenterCallback = new EpicenterCallback() {
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                return null;
+            }
+        };
+
+        fade.setEpicenterCallback(epicenterCallback);
+
+        Fade clone = (Fade) fade.clone();
+        assertEquals(fade.mStartDelay, clone.mStartDelay);
+        assertEquals(fade.mDuration, clone.mDuration);
+        assertEquals(fade.mInterpolator, clone.mInterpolator);
+        assertEquals(fade.mPropagation, clone.mPropagation);
+        assertEquals(fade.getPathMotion(), clone.getPathMotion());
+        assertEquals(fade.getEpicenterCallback(), clone.getEpicenterCallback());
+        assertEquals(fade.mNameOverrides, clone.mNameOverrides);
+        assertEquals(fade.mMatchOrder, clone.mMatchOrder);
+
+        assertEquals(fade.mTargets, clone.mTargets);
+        assertEquals(fade.mTargetExcludes, clone.mTargetExcludes);
+        assertEquals(fade.mTargetChildExcludes, clone.mTargetChildExcludes);
+
+        assertEquals(fade.mTargetIds, clone.mTargetIds);
+        assertEquals(fade.mTargetIdExcludes, clone.mTargetIdExcludes);
+        assertEquals(fade.mTargetIdChildExcludes, clone.mTargetIdChildExcludes);
+
+        assertEquals(fade.mTargetNames, clone.mTargetNames);
+        assertEquals(fade.mTargetNameExcludes, clone.mTargetNameExcludes);
+
+        assertEquals(fade.mTargetTypes, clone.mTargetTypes);
+        assertEquals(fade.mTargetTypeExcludes, clone.mTargetTypeExcludes);
+    }
+}
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index d383775..348f8fd 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -25,7 +25,7 @@
 
 public class PatternsTest extends TestCase {
 
-    //Tests for Patterns.TOP_LEVEL_DOMAIN
+    // Tests for Patterns.TOP_LEVEL_DOMAIN
 
     @SmallTest
     public void testTldPattern() throws Exception {
@@ -56,7 +56,7 @@
         assertFalse("Matched invalid TLD!", t);
     }
 
-    //Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
+    // Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
 
     @SmallTest
     public void testIanaTopLevelDomains_matchesValidTld() throws Exception {
@@ -94,7 +94,7 @@
         assertFalse("Should not match invalid Punycode TLD", pattern.matcher("xn").matches());
     }
 
-    //Tests for Patterns.WEB_URL
+    // Tests for Patterns.WEB_URL
 
     @SmallTest
     public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
@@ -208,7 +208,7 @@
                 Patterns.WEB_URL.matcher(url).matches());
     }
 
-    //Tests for Patterns.AUTOLINK_WEB_URL
+    // Tests for Patterns.AUTOLINK_WEB_URL
 
     @SmallTest
     public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
@@ -419,7 +419,7 @@
                 Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
     }
 
-    //Tests for Patterns.IP_ADDRESS
+    // Tests for Patterns.IP_ADDRESS
 
     @SmallTest
     public void testIpPattern() throws Exception {
@@ -432,7 +432,7 @@
         assertFalse("Invalid IP", t);
     }
 
-    //Tests for Patterns.DOMAIN_NAME
+    // Tests for Patterns.DOMAIN_NAME
 
     @SmallTest
     public void testDomain_matchesPunycodeTld() throws Exception {
@@ -508,7 +508,227 @@
                 Patterns.DOMAIN_NAME.matcher(domain).matches());
     }
 
-    //Tests for Patterns.PHONE
+    // Tests for Patterns.AUTOLINK_EMAIL_ADDRESS
+
+    public void testAutoLinkEmailAddress_matchesShortValidEmail() throws Exception {
+        String email = "a@a.co";
+        assertTrue("Should match short valid email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesRegularEmail() throws Exception {
+        String email = "email@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesEmailWithMultipleSubdomains() throws Exception {
+        String email = "email@e.somelongdomainnameforandroid.abc.uk";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithDot() throws Exception {
+        String email = "e.mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithPlus() throws Exception {
+        String email = "e+mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithUnderscore() throws Exception {
+        String email = "e_mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithDash() throws Exception {
+        String email = "e-mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithApostrophe() throws Exception {
+        String email = "e'mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithDigits() throws Exception {
+        String email = "123@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesUnicodeLocalPart() throws Exception {
+        String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithEmoji() throws Exception {
+        String email = "smiley\u263A@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithSurrogatePairs() throws Exception {
+        String email = "\uD83C\uDF38@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainWithDash() throws Exception {
+        String email = "email@an-droid.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesUnicodeDomain() throws Exception {
+        String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesUnicodeLocalPartAndDomain() throws Exception {
+        String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainWithEmoji() throws Exception {
+        String email = "smiley@\u263Aandroid.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainWithSurrogatePairs() throws Exception {
+        String email = "email@\uD83C\uDF38android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartAndDomainWithSurrogatePairs()
+            throws Exception {
+        String email = "\uD83C\uDF38@\uD83C\uDF38android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchStringWithoutAtSign() throws Exception {
+        String email = "android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchPlainString() throws Exception {
+        String email = "email";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchStringWithMultipleAtSigns() throws Exception {
+        String email = "email@android@android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchEmailWithoutTld() throws Exception {
+        String email = "email@android";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchLocalPartEndingWithDot() throws Exception {
+        String email = "email.@android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchLocalPartStartingWithDot() throws Exception {
+        String email = ".email@android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchDomainStartingWithDash() throws Exception {
+        String email = "email@-android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchDomainWithConsecutiveDots() throws Exception {
+        String email = "email@android..com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchEmailWithIpAsDomain() throws Exception {
+        String email = "email@127.0.0.1";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchEmailWithInvalidTld() throws Exception {
+        String email = "email@android.c";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartUpTo64Chars() throws Exception {
+        String localPart = "";
+        for (int i = 0; i < 64; i++) {
+            localPart += "a";
+        }
+        String email = localPart + "@android.com";
+
+        assertTrue("Should match local part of length: " + localPart.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+        email = localPart + "a@android.com";
+        assertFalse("Should not match local part of length: " + localPart.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesSubdomainUpTo63Chars() throws Exception {
+        String subdomain = "";
+        for (int i = 0; i < 63; i++) {
+            subdomain += "a";
+        }
+        String email = "email@" + subdomain + ".com";
+
+        assertTrue("Should match subdomain of length: " + subdomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+        subdomain += "a";
+        email = "email@" + subdomain + ".com";
+        assertFalse("Should not match local part of length: " + subdomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainUpTo255Chars() throws Exception {
+        String longDomain = "";
+        while (longDomain.length() <= 250) {
+            longDomain += "d.";
+        }
+        longDomain += "com";
+        assertEquals(255, longDomain.length());
+        String email = "a@" + longDomain;
+
+        assertTrue("Should match domain of length: " + longDomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+        email = email + "m";
+        assertEquals(258, email.length());
+        assertFalse("Should not match domain of length: " + longDomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    // Tests for Patterns.PHONE
 
     @SmallTest
     public void testPhonePattern() throws Exception {
diff --git a/core/tests/coretests/src/android/view/RemoteViewsTest.java b/core/tests/coretests/src/android/view/RemoteViewsTest.java
new file mode 100644
index 0000000..9c4fd70
--- /dev/null
+++ b/core/tests/coretests/src/android/view/RemoteViewsTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.view;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Tests for RemoteViews.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RemoteViewsTest {
+
+    @Rule
+    public final ExpectedException exception = ExpectedException.none();
+
+    private Context mContext;
+    private String mPackage;
+    private LinearLayout mContainer;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getContext();
+        mPackage = mPackage;
+        mContainer = new LinearLayout(mContext);
+    }
+
+    @Test
+    public void clone_doesNotCopyBitmap() {
+        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+        Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+
+        original.setImageViewBitmap(R.id.image, bitmap);
+        RemoteViews clone = original.clone();
+        View inflated = clone.apply(mContext, mContainer);
+
+        Drawable drawable = ((ImageView) inflated.findViewById(R.id.image)).getDrawable();
+        assertSame(bitmap, ((BitmapDrawable)drawable).getBitmap());
+    }
+
+    @Test
+    public void clone_originalCanStillBeApplied() {
+        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+        RemoteViews clone = original.clone();
+
+        clone.apply(mContext, mContainer);
+    }
+
+    @Test
+    public void clone_clones() {
+        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+        RemoteViews clone = original.clone();
+        original.setTextViewText(R.id.text, "test");
+        View inflated = clone.apply(mContext, mContainer);
+
+        TextView textView = (TextView) inflated.findViewById(R.id.text);
+        assertEquals("", textView.getText());
+    }
+
+    @Test
+    public void clone_child_fails() {
+        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+        RemoteViews child = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+        original.addView(R.id.layout, child);
+
+        exception.expect(IllegalStateException.class);
+        RemoteViews clone = child.clone();
+    }
+
+    @Test
+    public void clone_repeatedly() {
+        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+        original.clone();
+        original.clone();
+
+        original.apply(mContext, mContainer);
+    }
+
+    @Test
+    public void clone_chained() {
+        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+        RemoteViews clone = original.clone().clone();
+
+        clone.apply(mContext, mContainer);
+    }
+
+}
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTest.java b/core/tests/coretests/src/android/view/ViewCaptureTest.java
new file mode 100644
index 0000000..15cfe23
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewCaptureTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseIntArray;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+public class ViewCaptureTest {
+
+    private static final SparseIntArray EXPECTED_CHILDREN_VISIBILITY = new SparseIntArray();
+    static {
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child1, View.VISIBLE);
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child2, View.INVISIBLE);
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child3, View.GONE);
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child4, View.VISIBLE);
+    }
+
+    @Rule
+    public ActivityTestRule<ViewCaptureTestActivity> mActivityRule = new ActivityTestRule<>(
+            ViewCaptureTestActivity.class);
+
+    private Activity mActivity;
+    private ViewGroup mViewToCapture;
+
+    @Before
+    public void setUp() throws Exception {
+        mActivity = mActivityRule.getActivity();
+        mViewToCapture = (ViewGroup) mActivity.findViewById(R.id.capture);
+    }
+
+    @Test
+    @SmallTest
+    public void testCreateSnapshot() {
+        assertChildrenVisibility();
+        testCreateSnapshot(true, R.drawable.view_capture_test_no_children_golden);
+        assertChildrenVisibility();
+        testCreateSnapshot(false, R.drawable.view_capture_test_with_children_golden);
+        assertChildrenVisibility();
+    }
+
+    private void testCreateSnapshot(boolean skipChildren, int goldenResId) {
+        Bitmap result = mViewToCapture.createSnapshot(Bitmap.Config.ARGB_8888, 0, skipChildren);
+        Bitmap golden = BitmapFactory.decodeResource(mActivity.getResources(), goldenResId);
+        assertTrue(golden.sameAs(result));
+    }
+
+    private void assertChildrenVisibility() {
+        for (int i = 0; i < EXPECTED_CHILDREN_VISIBILITY.size(); i++) {
+            int id = EXPECTED_CHILDREN_VISIBILITY.keyAt(i);
+            View child = mViewToCapture.findViewById(id);
+            Assert.assertEquals(EXPECTED_CHILDREN_VISIBILITY.get(id), child.getVisibility());
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
new file mode 100644
index 0000000..20e3eb5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+public class ViewCaptureTestActivity extends Activity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.view_capture_snapshot);
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/EditorCursorTest.java b/core/tests/coretests/src/android/widget/EditorCursorTest.java
index 04c8b8c..6d650ff 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorTest.java
@@ -16,16 +16,34 @@
 
 package android.widget;
 
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.Choreographer;
 import android.view.ViewGroup;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.widget.espresso.TextViewAssertions.hasInsertionPointerOnLeft;
+import static android.widget.espresso.TextViewAssertions.hasInsertionPointerOnRight;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.isEmptyString;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.Matchers.sameInstance;
+
 public class EditorCursorTest extends ActivityInstrumentationTestCase2<TextViewActivity> {
 
+
+    private final static String LTR_STRING = "aaaaaaaaaaaaaaaaaaaaaa";
+    private final static String LTR_HINT = "hint";
+    private final static String RTL_STRING = "مرحبا الروبوت مرحبا الروبوت مرحبا الروبوت";
+    private final static String RTL_HINT = "الروبوت";
+    private final static int CURSOR_BLINK_MS = 500;
+
     private EditText mEditText;
-    private final String RTL_STRING = "مرحبا الروبوت مرحبا الروبوت مرحبا الروبوت";
 
     public EditorCursorTest() {
         super(TextViewActivity.class);
@@ -55,110 +73,160 @@
             @Override
             public void run() {
                 getActivity().setContentView(layout);
-                mEditText.requestFocus();
             }
         });
         getInstrumentation().waitForIdleSync();
+        onView(sameInstance(mEditText)).perform(click());
     }
 
     @SmallTest
-    public void testCursorIsInViewBoundariesWhenOnRightForLtr() throws Exception {
+    public void testCursorIsInViewBoundariesWhenOnRightForLtr() {
         // Asserts that when an EditText has LTR text, and cursor is at the end (right),
         // cursor is drawn to the right edge of the view
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEditText.setText("aaaaaaaaaaaaaaaaaaaaaa");
-                int length = mEditText.getText().length();
-                mEditText.setSelection(length, length);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        setEditTextText(LTR_STRING, LTR_STRING.length());
 
-        Editor editor = mEditText.getEditorForTesting();
-        Drawable drawable = editor.getCursorDrawable()[0];
-        Rect drawableBounds = drawable.getBounds();
-        Rect drawablePadding = new Rect();
-        drawable.getPadding(drawablePadding);
-
-        // right edge of the view including the scroll
-        int maxRight = mEditText.getWidth() - mEditText.getCompoundPaddingRight()
-                - mEditText.getCompoundPaddingLeft() + +mEditText.getScrollX();
-        int diff = drawableBounds.right - drawablePadding.right - maxRight;
-        assertTrue(diff >= 0 && diff <= 1);
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
     }
 
     @SmallTest
-    public void testCursorIsInViewBoundariesWhenOnLeftForLtr() throws Exception {
+    public void testCursorIsInViewBoundariesWhenOnLeftForLtr() {
         // Asserts that when an EditText has LTR text, and cursor is at the beginning,
         // cursor is drawn to the left edge of the view
+        setEditTextText(LTR_STRING, 0);
 
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEditText.setText("aaaaaaaaaaaaaaaaaaaaaa");
-                mEditText.setSelection(0, 0);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-
-        Drawable drawable = mEditText.getEditorForTesting().getCursorDrawable()[0];
-        Rect drawableBounds = drawable.getBounds();
-        Rect drawablePadding = new Rect();
-        drawable.getPadding(drawablePadding);
-
-        int diff = drawableBounds.left + drawablePadding.left;
-        assertTrue(diff >= 0 && diff <= 1);
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
     }
 
     @SmallTest
-    public void testCursorIsInViewBoundariesWhenOnRightForRtl() throws Exception {
+    public void testCursorIsInViewBoundariesWhenOnRightForRtl() {
         // Asserts that when an EditText has RTL text, and cursor is at the end,
         // cursor is drawn to the left edge of the view
+        setEditTextText(RTL_STRING, 0);
 
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEditText.setText(RTL_STRING);
-                mEditText.setSelection(0, 0);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-
-        Drawable drawable = mEditText.getEditorForTesting().getCursorDrawable()[0];
-        Rect drawableBounds = drawable.getBounds();
-        Rect drawablePadding = new Rect();
-        drawable.getPadding(drawablePadding);
-
-        int maxRight = mEditText.getWidth() - mEditText.getCompoundPaddingRight()
-                - mEditText.getCompoundPaddingLeft() + mEditText.getScrollX();
-
-        int diff = drawableBounds.right - drawablePadding.right - maxRight;
-        assertTrue(diff >= 0 && diff <= 1);
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
     }
 
     @SmallTest
-    public void testCursorIsInViewBoundariesWhenOnLeftForRtl() throws Exception {
+    public void testCursorIsInViewBoundariesWhenOnLeftForRtl() {
         // Asserts that when an EditText has RTL text, and cursor is at the beginning,
         // cursor is drawn to the right edge of the view
+        setEditTextText(RTL_STRING, RTL_STRING.length());
 
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
+    }
+
+    /* Tests for cursor positioning with hint */
+    @SmallTest
+    public void testCursorIsOnLeft_withFirstStrongLtrAlgorithm() {
+        setEditTextHint(null, TextView.TEXT_DIRECTION_FIRST_STRONG_LTR, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+        assertThat(mEditText.getHint(), nullValue());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
+
+        setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_LTR, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
+
+        setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_LTR, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
+    }
+
+    @SmallTest
+    public void testCursorIsOnRight_withFirstStrongRtlAlgorithm() {
+        setEditTextHint(null, TextView.TEXT_DIRECTION_FIRST_STRONG_RTL, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+        assertThat(mEditText.getHint(), nullValue());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
+
+        setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_RTL, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
+
+        setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_FIRST_STRONG_RTL, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
+    }
+
+    @SmallTest
+    public void testCursorIsOnLeft_withLtrAlgorithm() {
+        setEditTextHint(null, TextView.TEXT_DIRECTION_LTR, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+        assertThat(mEditText.getHint(), nullValue());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
+
+        setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_LTR, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
+
+        setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_LTR, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnLeft());
+    }
+
+    @SmallTest
+    public void testCursorIsOnRight_withRtlAlgorithm() {
+        setEditTextHint(null, TextView.TEXT_DIRECTION_RTL, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+        assertThat(mEditText.getHint(), nullValue());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
+
+        setEditTextHint(LTR_HINT, TextView.TEXT_DIRECTION_RTL, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
+
+        setEditTextHint(RTL_HINT, TextView.TEXT_DIRECTION_RTL, 0);
+        assertThat(mEditText.getText().toString(), isEmptyString());
+
+        onView(sameInstance(mEditText)).check(hasInsertionPointerOnRight());
+    }
+
+    private void setEditTextProperties(final String text, final String hint,
+            final Integer textDirection, final Integer selection) {
         getActivity().runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mEditText.setText(RTL_STRING);
-                int length = mEditText.getText().length();
-                mEditText.setSelection(length, length);
+                if (textDirection != null) mEditText.setTextDirection(textDirection);
+                if (text != null) mEditText.setText(text);
+                if (hint != null) mEditText.setHint(hint);
+                if (selection != null) mEditText.setSelection(selection);
             }
         });
         getInstrumentation().waitForIdleSync();
 
-        Drawable drawable = mEditText.getEditorForTesting().getCursorDrawable()[0];
-        Rect drawableBounds = drawable.getBounds();
-        Rect drawablePadding = new Rect();
-        drawable.getPadding(drawablePadding);
-
-        int diff = drawableBounds.left - mEditText.getScrollX() + drawablePadding.left;
-        assertTrue(diff >= 0 && diff <= 1);
+        // wait for cursor to be drawn. updateCursorPositions function is called during draw() and
+        // only when cursor is visible during blink.
+        final CountDownLatch latch = new CountDownLatch(1);
+        mEditText.postOnAnimationDelayed(new Runnable() {
+            @Override
+            public void run() {
+                latch.countDown();
+            }
+        }, CURSOR_BLINK_MS);
+        try {
+            assertThat("Problem while waiting for the cursor to blink",
+                    latch.await(10, TimeUnit.SECONDS), equalTo(true));
+        } catch (Exception e) {
+            fail("Problem while waiting for the cursor to blink");
+        }
     }
 
+    private void setEditTextHint(final String hint, final int textDirection, final int selection) {
+        setEditTextProperties(null, hint, textDirection, selection);
+    }
+
+    private void setEditTextText(final String text, final Integer selection) {
+        setEditTextProperties(text, null, null, selection);
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index 3d8fe69..59ffd56 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -20,6 +20,7 @@
 import android.content.res.TypedArray;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
@@ -32,6 +33,8 @@
 
 /**
  * SuggestionsPopupWindowTest tests.
+ *
+ * TODO: Add tests for when there are no suggestions
  */
 public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2<TextViewActivity> {
 
@@ -40,6 +43,7 @@
     }
 
     @SmallTest
+    @Suppress
     public void testTextAppearanceInSuggestionsPopup() {
         final Activity activity = getActivity();
 
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index 00df87d..923b829 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -143,6 +143,8 @@
 
         onView(withId(R.id.textview)).check(hasSelection(""));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("i")));
+
+        // TODO: Add tests for suggestions
     }
 
     @SmallTest
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 5dae4a8..ecf88f1 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -16,8 +16,10 @@
 
 package android.widget;
 
+import static android.support.test.espresso.action.ViewActions.longClick;
 import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
 import static android.widget.espresso.DragHandleUtils.onHandleView;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.onFloatingToolBarItem;
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
 import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
@@ -44,8 +46,12 @@
 
 import com.android.frameworks.coretests.R;
 
+import android.support.test.espresso.action.EspressoKey;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.InputType;
 import android.view.KeyEvent;
 
 import static org.hamcrest.Matchers.anyOf;
@@ -172,6 +178,12 @@
         onView(withId(R.id.textview)).check(hasSelection(""));
         assertNoSelectionHandles();
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
+
+        // Test undo returns to the original state.
+        onView(withId(R.id.textview)).perform(pressKey(
+                (new EspressoKey.Builder()).withCtrlPressed(true).withKeyCode(KeyEvent.KEYCODE_Z)
+                        .build()));
+        onView(withId(R.id.textview)).check(matches(withText(text)));
     }
 
     @SmallTest
@@ -225,6 +237,33 @@
     }
 
     @SmallTest
+    public void testToolbarAppearsAfterSelection_withFirstStringLtrAlgorithmAndRtlHint()
+            throws Exception {
+        // after the hint layout change, the floating toolbar was not visible in the case below
+        // this test tests that the floating toolbar is displayed on the screen and is visible to
+        // user.
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        textView.post(new Runnable() {
+            @Override
+            public void run() {
+                textView.setTextDirection(TextView.TEXT_DIRECTION_FIRST_STRONG_LTR);
+                textView.setInputType(InputType.TYPE_CLASS_TEXT);
+                textView.setSingleLine(true);
+                textView.setHint("الروبوت");
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView("test"));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
+        onFloatingToolBarItem(withText(com.android.internal.R.string.cut)).perform(click());
+        onView(withId(R.id.textview)).perform(longClick());
+        sleepForFloatingToolbarPopup();
+
+        assertFloatingToolbarIsDisplayed();
+    }
+
+    @SmallTest
     public void testToolbarAndInsertionHandle() throws Exception {
         final String text = "text";
         onView(withId(R.id.textview)).perform(click());
@@ -346,6 +385,51 @@
     }
 
     @SmallTest
+    public void testSelectionHandles_bidi() throws Exception {
+        final String text = "abc \u0621\u0622\u0623 def";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        assertNoSelectionHandles();
+
+        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0622')));
+
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .check(matches(isDisplayed()));
+        onHandleView(com.android.internal.R.id.selection_end_handle)
+                .check(matches(isDisplayed()));
+
+        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
+
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
+        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
+
+        onHandleView(com.android.internal.R.id.selection_end_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
+        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
+
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623') + 1,
+                        false));
+        onView(withId(R.id.textview)).check(hasSelection("\u0623"));
+
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0621'),
+                        false));
+        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
+
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
+        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623"));
+
+        onHandleView(com.android.internal.R.id.selection_end_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
+        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623 def"));
+    }
+
+    @SmallTest
     public void testSelectionHandles_multiLine() throws Exception {
         final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
         onView(withId(R.id.textview)).perform(click());
@@ -527,4 +611,90 @@
                 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i')));
         onView(withId(R.id.textview)).check(hasSelection("hijk"));
     }
+
+    @SmallTest
+    public void testSetSelectionAndActionMode() throws Exception {
+        final String text = "abc def";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        assertFloatingToolbarIsNotDisplayed();
+        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
+        getInstrumentation().waitForIdleSync();
+        sleepForFloatingToolbarPopup();
+        // Don't automatically start action mode.
+        assertFloatingToolbarIsNotDisplayed();
+        // Make sure that "Select All" is included in the selection action mode when the entire text
+        // is not selected.
+        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('e')));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        // Changing the selection range by API should not interrupt the selection action mode.
+        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
+        getInstrumentation().waitForIdleSync();
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.selectAll));
+        // Make sure that "Select All" is no longer included when the entire text is selected by
+        // API.
+        textView.post(
+                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
+        getInstrumentation().waitForIdleSync();
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        assertFloatingToolbarDoesNotContainItem(
+                getActivity().getString(com.android.internal.R.string.selectAll));
+        // Make sure that shrinking the selection range to cursor (an empty range) by API
+        // terminates selection action mode and does not trigger the insertion action mode.
+        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0));
+        getInstrumentation().waitForIdleSync();
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsNotDisplayed();
+        // Make sure that user click can trigger the insertion action mode.
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        // Make sure that an existing insertion action mode keeps alive after the insertion point is
+        // moved by API.
+        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0));
+        getInstrumentation().waitForIdleSync();
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        assertFloatingToolbarDoesNotContainItem(
+                getActivity().getString(com.android.internal.R.string.copy));
+        // Make sure that selection action mode is started after selection is created by API when
+        // insertion action mode is active.
+        textView.post(
+                () -> Selection.setSelection((Spannable) textView.getText(), 1, text.length()));
+        getInstrumentation().waitForIdleSync();
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.copy));
+    }
+
+    @SmallTest
+    public void testTransientState() throws Exception {
+        final String text = "abc def";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        assertFalse(textView.hasTransientState());
+
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
+        // hasTransientState should return true when user generated selection is active.
+        assertTrue(textView.hasTransientState());
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
+        // hasTransientState should return false as the selection has been cleared.
+        assertFalse(textView.hasTransientState());
+        textView.post(
+                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
+        getInstrumentation().waitForIdleSync();
+        // hasTransientState should return false when selection is created by API.
+        assertFalse(textView.hasTransientState());
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index f02fe00..0f7f359 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -54,6 +54,16 @@
     }
 
     /**
+     * Creates a {@link ViewInteraction} for the floating bar menu item with the given matcher.
+     *
+     * @param matcher The matcher for the menu item.
+     */
+    public static ViewInteraction onFloatingToolBarItem(Matcher<View> matcher) {
+        return onView(matcher)
+                .inRoot(withDecorView(hasDescendant(withTagValue(is(TAG)))));
+    }
+
+    /**
      * Asserts that the floating toolbar is displayed on screen.
      *
      * @throws AssertionError if the assertion fails
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index b8ea2de..bec4180 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -21,7 +21,6 @@
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
 import android.support.test.espresso.action.MotionEvents;
 import android.support.test.espresso.action.MotionEvents.DownResultHolder;
 import android.support.test.espresso.action.Press;
@@ -34,7 +33,7 @@
  * ViewAction for performing an click on View by a mouse.
  */
 public final class MouseClickAction implements ViewAction {
-    private final GeneralClickAction mGeneralClickAction;
+    private final ViewClickAction mViewClickAction;
     @MouseUiController.MouseButton
     private final int mButton;
 
@@ -100,30 +99,22 @@
      */
     public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
             @MouseUiController.MouseButton int button) {
-        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider, Press.PINPOINT);
+        mViewClickAction = new ViewClickAction(tapper, coordinatesProvider, Press.PINPOINT);
         mButton = button;
     }
 
     @Override
     public Matcher<View> getConstraints() {
-        return mGeneralClickAction.getConstraints();
+        return mViewClickAction.getConstraints();
     }
 
     @Override
     public String getDescription() {
-        return mGeneralClickAction.getDescription();
+        return mViewClickAction.getDescription();
     }
 
     @Override
     public void perform(UiController uiController, View view) {
-        mGeneralClickAction.perform(new MouseUiController(uiController, mButton), view);
-        long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
-        if (0 < doubleTapTimeout) {
-            // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
-            // detected as a triple click. e.g. 2 double clicks are detected as a triple click and
-            // a single click because espresso isn't aware of triple click detection logic, which
-            // is TextView specific gesture.
-            uiController.loopMainThreadForAtLeast(doubleTapTimeout);
-        }
+        mViewClickAction.perform(new MouseUiController(uiController, mButton), view);
     }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 1dd6e17..335d021 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -21,7 +21,6 @@
 import android.support.test.espresso.PerformException;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
 import android.support.test.espresso.action.Press;
 import android.support.test.espresso.action.Tap;
 import android.support.test.espresso.util.HumanReadables;
@@ -29,6 +28,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.Editor;
+import android.widget.Editor.HandleView;
 import android.widget.TextView;
 
 /**
@@ -50,7 +50,7 @@
      */
     public static ViewAction clickOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new GeneralClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
+                new ViewClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
     }
 
     /**
@@ -96,7 +96,7 @@
      */
     public static ViewAction doubleClickOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
+                new ViewClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
     }
 
     /**
@@ -126,7 +126,7 @@
      */
     public static ViewAction longPressOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
+                new ViewClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
     }
 
     /**
@@ -311,18 +311,87 @@
      * @param endIndex The index of the TextView's text to end the drag at
      */
     public static ViewAction dragHandle(TextView textView, Handle handleType, int endIndex) {
-        final int currentOffset = handleType == Handle.SELECTION_START ?
-                textView.getSelectionStart() : textView.getSelectionEnd();
+        return dragHandle(textView, handleType, endIndex, true);
+    }
+
+    /**
+     * Returns an action that tap then drags on the handle from the current position to endIndex on
+     * the TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView's drag-handle displayed on screen
+     * <ul>
+     *
+     * @param textView TextView the handle is on
+     * @param handleType Type of the handle
+     * @param endIndex The index of the TextView's text to end the drag at
+     * @param primary whether to use primary direction to get coordinate form index when endIndex is
+     * at a direction boundary.
+     */
+    public static ViewAction dragHandle(TextView textView, Handle handleType, int endIndex,
+            boolean primary) {
         return actionWithAssertions(
                 new DragAction(
                         DragAction.Drag.TAP,
-                        new HandleCoordinates(textView, handleType, currentOffset),
-                        new HandleCoordinates(textView, handleType, endIndex),
+                        new CurrentHandleCoordinates(textView),
+                        new HandleCoordinates(textView, handleType, endIndex, primary),
                         Press.FINGER,
                         Editor.HandleView.class));
     }
 
     /**
+     * A provider of the x, y coordinates of the handle dragging point.
+     */
+    private static final class CurrentHandleCoordinates implements CoordinatesProvider {
+        // Must be larger than Editor#LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS.
+        private final TextView mTextView;
+        private final String mActionDescription;
+
+
+        public CurrentHandleCoordinates(TextView textView) {
+            mTextView = textView;
+            mActionDescription = "Could not locate handle.";
+        }
+
+        @Override
+        public float[] calculateCoordinates(View view) {
+            try {
+                return locateHandle(view);
+            } catch (StringIndexOutOfBoundsException e) {
+                throw new PerformException.Builder()
+                        .withActionDescription(mActionDescription)
+                        .withViewDescription(HumanReadables.describe(view))
+                        .withCause(e)
+                        .build();
+            }
+        }
+
+        private float[] locateHandle(View view) {
+            final Rect bounds = new Rect();
+            view.getBoundsOnScreen(bounds);
+            final Rect visibleDisplayBounds = new Rect();
+            mTextView.getWindowVisibleDisplayFrame(visibleDisplayBounds);
+            visibleDisplayBounds.right -= 1;
+            visibleDisplayBounds.bottom -= 1;
+            if (!visibleDisplayBounds.intersect(bounds)) {
+                throw new PerformException.Builder()
+                        .withActionDescription(mActionDescription
+                                + " The handle is entirely out of the visible display frame of"
+                                + "the TextView's window.")
+                        .withViewDescription(HumanReadables.describe(view))
+                        .build();
+            }
+            final float dragPointX = Math.max(Math.min(bounds.centerX(),
+                    visibleDisplayBounds.right), visibleDisplayBounds.left);
+            final float verticalOffset = bounds.height() * 0.7f;
+            final float dragPointY = Math.max(Math.min(bounds.top + verticalOffset,
+                    visibleDisplayBounds.bottom), visibleDisplayBounds.top);
+            return new float[] {dragPointX, dragPointY};
+        }
+    }
+
+    /**
      * A provider of the x, y coordinates of the handle that points the specified text index in a
      * text view.
      */
@@ -332,14 +401,17 @@
         private final TextView mTextView;
         private final Handle mHandleType;
         private final int mIndex;
+        private final boolean mPrimary;
         private final String mActionDescription;
 
-        public HandleCoordinates(TextView textView, Handle handleType, int index) {
+        public HandleCoordinates(TextView textView, Handle handleType, int index, boolean primary) {
             mTextView = textView;
             mHandleType = handleType;
             mIndex = index;
+            mPrimary = primary;
             mActionDescription = "Could not locate " + handleType.toString()
-                    + " handle that points text index: " + index;
+                    + " handle that points text index: " + index
+                    + " (" + (primary ? "primary" : "secondary" ) + ")";
         }
 
         @Override
@@ -356,17 +428,26 @@
         }
 
         private float[] locateHandlePointsTextIndex(View view) {
+            if (!(view instanceof HandleView)) {
+                throw new PerformException.Builder()
+                        .withActionDescription(mActionDescription + " The view is not a HandleView")
+                        .withViewDescription(HumanReadables.describe(view))
+                        .build();
+            }
+            final HandleView handleView = (HandleView) view;
             final int currentOffset = mHandleType == Handle.SELECTION_START ?
                     mTextView.getSelectionStart() : mTextView.getSelectionEnd();
 
             final Layout layout = mTextView.getLayout();
+
             final int currentLine = layout.getLineForOffset(currentOffset);
             final int targetLine = layout.getLineForOffset(mIndex);
-
+            final float currentX = handleView.getHorizontal(layout, currentOffset);
+            final float currentY = layout.getLineTop(currentLine);
             final float[] currentCoordinates =
-                    (new TextCoordinates(currentOffset)).calculateCoordinates(mTextView);
+                    TextCoordinates.convertToScreenCoordinates(mTextView, currentX, currentY);
             final float[] targetCoordinates =
-                    (new TextCoordinates(mIndex)).calculateCoordinates(mTextView);
+                    (new TextCoordinates(mIndex, mPrimary)).calculateCoordinates(mTextView);
             final Rect bounds = new Rect();
             view.getBoundsOnScreen(bounds);
             final Rect visibleDisplayBounds = new Rect();
@@ -403,17 +484,24 @@
     private static final class TextCoordinates implements CoordinatesProvider {
 
         private final int mIndex;
+        private final boolean mPrimary;
         private final String mActionDescription;
 
         public TextCoordinates(int index) {
+            this(index, true);
+        }
+
+        public TextCoordinates(int index, boolean primary) {
             mIndex = index;
-            mActionDescription = "Could not locate text at index: " + mIndex;
+            mPrimary = primary;
+            mActionDescription = "Could not locate text at index: " + mIndex
+                    + " (" + (primary ? "primary" : "secondary" ) + ")";
         }
 
         @Override
         public float[] calculateCoordinates(View view) {
             try {
-                return locateTextAtIndex((TextView) view, mIndex);
+                return locateTextAtIndex((TextView) view, mIndex, mPrimary);
             } catch (ClassCastException e) {
                 throw new PerformException.Builder()
                         .withActionDescription(mActionDescription)
@@ -432,19 +520,30 @@
         /**
          * @throws StringIndexOutOfBoundsException
          */
-        private float[] locateTextAtIndex(TextView textView, int index) {
+        private float[] locateTextAtIndex(TextView textView, int index, boolean primary) {
             if (index < 0 || index > textView.getText().length()) {
                 throw new StringIndexOutOfBoundsException(index);
             }
-            final int[] xy = new int[2];
-            textView.getLocationOnScreen(xy);
             final Layout layout = textView.getLayout();
             final int line = layout.getLineForOffset(index);
-            final float x = textView.getTotalPaddingLeft() - textView.getScrollX()
-                    + layout.getPrimaryHorizontal(index);
-            final float y = textView.getTotalPaddingTop() - textView.getScrollY()
-                    + layout.getLineTop(line);
-            return new float[]{x + xy[0], y + xy[1]};
+            return convertToScreenCoordinates(textView,
+                    (primary ? layout.getPrimaryHorizontal(index)
+                            : layout.getSecondaryHorizontal(index)),
+                    layout.getLineTop(line));
+        }
+
+        /**
+         * Convert TextView's local coordinates to on screen coordinates.
+         * @param textView the TextView
+         * @param x local horizontal coordinate
+         * @param y local vertical coordinate
+         * @return
+         */
+        public static float[] convertToScreenCoordinates(TextView textView, float x, float y) {
+            final int[] xy = new int[2];
+            textView.getLocationOnScreen(xy);
+            return new float[]{ x + textView.getTotalPaddingLeft() - textView.getScrollX() + xy[0],
+                    y + textView.getTotalPaddingTop() - textView.getScrollY() + xy[1] };
         }
     }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
index 37c7425..6e44cd8 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -19,15 +19,23 @@
 import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.number.IsCloseTo.closeTo;
 
+import android.annotation.IntDef;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.ViewAssertion;
 import android.view.View;
+import android.widget.EditText;
 import android.widget.TextView;
 
 import junit.framework.AssertionFailedError;
 import org.hamcrest.Matcher;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A collection of assertions on a {@link android.widget.TextView}.
  */
@@ -113,6 +121,22 @@
     }
 
     /**
+     * Returns a {@link ViewAssertion} that asserts that the EditText insertion pointer is on
+     * the left edge.
+     */
+    public static ViewAssertion hasInsertionPointerOnLeft() {
+        return new CursorPositionAssertion(CursorPositionAssertion.LEFT);
+    }
+
+    /**
+     * Returns a {@link ViewAssertion} that asserts that the EditText insertion pointer is on
+     * the right edge.
+     */
+    public static ViewAssertion hasInsertionPointerOnRight() {
+        return new CursorPositionAssertion(CursorPositionAssertion.RIGHT);
+    }
+
+    /**
      * A {@link ViewAssertion} to check the selected text in a {@link TextView}.
      */
     private static final class TextSelectionAssertion implements ViewAssertion {
@@ -142,4 +166,54 @@
             }
         }
     }
+
+    /**
+     * {@link ViewAssertion} to check that EditText cursor is on a given position.
+     */
+    static class CursorPositionAssertion implements ViewAssertion {
+
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef({LEFT, RIGHT})
+        public @interface CursorEdgePositionType {}
+        public static final int LEFT = 0;
+        public static final int RIGHT = 1;
+
+        private final int mPosition;
+
+        private CursorPositionAssertion(@CursorEdgePositionType int position) {
+            this.mPosition = position;
+        }
+
+        @Override
+        public void check(View view, NoMatchingViewException exception) {
+            if (!(view instanceof EditText)) {
+                throw new AssertionFailedError("View should be an instance of EditText");
+            }
+            EditText editText = (EditText) view;
+            Drawable drawable = editText.getEditorForTesting().getCursorDrawable()[0];
+            Rect drawableBounds = drawable.getBounds();
+            Rect drawablePadding = new Rect();
+            drawable.getPadding(drawablePadding);
+
+            final int diff;
+            final String positionStr;
+            switch (mPosition) {
+                case LEFT:
+                    positionStr = "left";
+                    diff = drawableBounds.left - editText.getScrollX() + drawablePadding.left;
+                    break;
+                case RIGHT:
+                    positionStr = "right";
+                    int maxRight = editText.getWidth() - editText.getCompoundPaddingRight()
+                            - editText.getCompoundPaddingLeft() + editText.getScrollX();
+                    diff = drawableBounds.right - drawablePadding.right - maxRight;
+                    break;
+                default:
+                    throw new AssertionFailedError("Unknown position for cursor assertion");
+            }
+
+            assertThat("Cursor should be on the " + positionStr, Double.valueOf(diff),
+                    closeTo(0f, 1f));
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
new file mode 100644
index 0000000..8bce1b0
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.espresso;
+
+import org.hamcrest.Matcher;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Tapper;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+public final class ViewClickAction implements ViewAction {
+    private final GeneralClickAction mGeneralClickAction;
+
+    public ViewClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
+            PrecisionDescriber precisionDescriber) {
+        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
+                precisionDescriber);
+    }
+
+    @Override
+    public Matcher<View> getConstraints() {
+        return mGeneralClickAction.getConstraints();
+    }
+
+    @Override
+    public String getDescription() {
+        return mGeneralClickAction.getDescription();
+    }
+
+    @Override
+    public void perform(UiController uiController, View view) {
+        mGeneralClickAction.perform(uiController, view);
+        long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+        if (0 < doubleTapTimeout) {
+            // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
+            // detected as a double click or triple click. e.g. 2 double clicks on TextView are
+            // detected as a triple click and a single click because espresso isn't aware of
+            // TextView specific gestures.
+            uiController.loopMainThreadForAtLeast(doubleTapTimeout);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index f962a43..6b5e4ad 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -21,6 +21,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.os.Parcel;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -36,6 +37,10 @@
 import java.util.Locale;
 import java.util.Objects;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.isIn;
+import static org.hamcrest.Matchers.not;
+
 public class InputMethodUtilsTest extends InstrumentationTestCase {
     private static final boolean IS_AUX = true;
     private static final boolean IS_DEFAULT = true;
@@ -65,6 +70,7 @@
     private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
     private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
     private static final String SUBTYPE_MODE_VOICE = "voice";
+    private static final String SUBTYPE_MODE_HANDWRITING = "handwriting";
     private static final String SUBTYPE_MODE_ANY = null;
     private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
     private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
@@ -186,6 +192,9 @@
         final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
                 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
                 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
         final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
                 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
                 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
@@ -207,6 +216,31 @@
         final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
                 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
                 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr",
+                "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ",
+                "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en",
+                SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr",
+                SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr",
+                "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
+                !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ",
+                "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
+                !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
         final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
                 createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
                         !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
@@ -227,15 +261,15 @@
             subtypes.add(autoSubtype);  // overridesImplicitlyEnabledSubtype == true
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
             final InputMethodInfo imi = createDummyInputMethodInfo(
                     "com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_EN_US))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_EN_US), imi);
             assertEquals(1, result.size());
             verifyEquality(autoSubtype, result.get(0));
         }
@@ -251,16 +285,18 @@
             subtypes.add(nonAutoFil);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
             final InputMethodInfo imi = createDummyInputMethodInfo(
                     "com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_EN_US))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_EN_US), imi);
+            assertEquals(2, result.size());
             verifyEquality(nonAutoEnUS, result.get(0));
+            verifyEquality(nonAutoHandwritingEn, result.get(1));
         }
 
         // Make sure that a subtype whose locale is exactly equal to the specified locale is
@@ -273,17 +309,18 @@
             subtypes.add(nonAutoJa);
             subtypes.add(nonAutoFil);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
             final InputMethodInfo imi = createDummyInputMethodInfo(
                     "com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_EN_GB))
-                                    .getResources(),
-                            imi);
-            assertEquals(1, result.size());
+                            getResourcesForLocales(LOCALE_EN_GB), imi);
+            assertEquals(2, result.size());
             verifyEquality(nonAutoEnGB, result.get(0));
+            verifyEquality(nonAutoHandwritingEn, result.get(1));
         }
 
         // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and
@@ -297,17 +334,18 @@
             subtypes.add(nonAutoFil);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
             final InputMethodInfo imi = createDummyInputMethodInfo(
                     "com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_FR))
-                                    .getResources(),
-                            imi);
-            assertEquals(1, result.size());
+                            getResourcesForLocales(LOCALE_FR), imi);
+            assertEquals(2, result.size());
             verifyEquality(nonAutoFrCA, result.get(0));
+            verifyEquality(nonAutoHandwritingFr, result.get(1));
         }
         // Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
         {
@@ -317,17 +355,18 @@
             subtypes.add(nonAutoFil);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
             final InputMethodInfo imi = createDummyInputMethodInfo(
                     "com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_FR_CA))
-                                    .getResources(),
-                            imi);
-            assertEquals(1, result.size());
+                            getResourcesForLocales(LOCALE_FR_CA), imi);
+            assertEquals(2, result.size());
             verifyEquality(nonAutoFrCA, result.get(0));
+            verifyEquality(nonAutoHandwritingFr, result.get(1));
         }
 
         // Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
@@ -338,21 +377,154 @@
             subtypes.add(nonAutoJa);    // not ASCII capable
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
             subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
             final InputMethodInfo imi = createDummyInputMethodInfo(
                     "com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_JA_JP))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_JA_JP), imi);
             assertEquals(3, result.size());
             verifyEquality(nonAutoJa, result.get(0));
             verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
             verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
         }
 
+        // Make sure that if there is no subtype that matches the language requested, then we just
+        // use the first keyboard subtype.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoHi);
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(LOCALE_JA_JP), imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoHi, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoHi);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(LOCALE_JA_JP), imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnUS, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoHi);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(LOCALE_JA_JP), imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnUS, result.get(0));
+        }
+
+        // Make sure that both language and script are taken into account to find the best matching
+        // subtype.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoSrCyrl);
+            subtypes.add(nonAutoSrLatn);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
+            subtypes.add(nonAutoHandwritingSrCyrl);
+            subtypes.add(nonAutoHandwritingSrLatn);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi);
+            assertEquals(2, result.size());
+            assertThat(nonAutoSrLatn, isIn(result));
+            assertThat(nonAutoHandwritingSrLatn, isIn(result));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoSrCyrl);
+            subtypes.add(nonAutoSrLatn);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
+            subtypes.add(nonAutoHandwritingSrCyrl);
+            subtypes.add(nonAutoHandwritingSrLatn);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi);
+            assertEquals(2, result.size());
+            assertThat(nonAutoSrCyrl, isIn(result));
+            assertThat(nonAutoHandwritingSrCyrl, isIn(result));
+        }
+
+        // Make sure that secondary locales are taken into account to find the best matching
+        // subtype.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoEnGB);
+            subtypes.add(nonAutoSrCyrl);
+            subtypes.add(nonAutoSrLatn);
+            subtypes.add(nonAutoFr);
+            subtypes.add(nonAutoFrCA);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoHandwritingFr);
+            subtypes.add(nonAutoHandwritingSrCyrl);
+            subtypes.add(nonAutoHandwritingSrLatn);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(
+                                    Locale.forLanguageTag("sr-Latn-RS-x-android"),
+                                    Locale.forLanguageTag("ja-JP"),
+                                    Locale.forLanguageTag("fr-FR"),
+                                    Locale.forLanguageTag("en-GB"),
+                                    Locale.forLanguageTag("en-US")),
+                            imi);
+            assertEquals(6, result.size());
+            assertThat(nonAutoEnGB, isIn(result));
+            assertThat(nonAutoFr, isIn(result));
+            assertThat(nonAutoSrLatn, isIn(result));
+            assertThat(nonAutoHandwritingEn, isIn(result));
+            assertThat(nonAutoHandwritingFr, isIn(result));
+            assertThat(nonAutoHandwritingSrLatn, isIn(result));
+        }
+
         // Make sure that 3-letter language code can be handled.
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
@@ -364,9 +536,7 @@
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_FIL_PH))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_FIL_PH), imi);
             assertEquals(1, result.size());
             verifyEquality(nonAutoFil, result.get(0));
         }
@@ -384,9 +554,7 @@
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_FI))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_FI), imi);
             assertEquals(1, result.size());
             verifyEquality(nonAutoJa, result.get(0));
         }
@@ -402,9 +570,7 @@
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_IN))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_IN), imi);
             assertEquals(1, result.size());
             verifyEquality(nonAutoIn, result.get(0));
         }
@@ -418,9 +584,7 @@
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_ID))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_ID), imi);
             assertEquals(1, result.size());
             verifyEquality(nonAutoIn, result.get(0));
         }
@@ -434,9 +598,7 @@
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_IN))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_IN), imi);
             assertEquals(1, result.size());
             verifyEquality(nonAutoId, result.get(0));
         }
@@ -450,12 +612,36 @@
                     subtypes);
             final ArrayList<InputMethodSubtype> result =
                     InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
-                            createTargetContextWithLocales(new LocaleList(LOCALE_ID))
-                                    .getResources(),
-                            imi);
+                            getResourcesForLocales(LOCALE_ID), imi);
             assertEquals(1, result.size());
             verifyEquality(nonAutoId, result.get(0));
         }
+
+        // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and the system
+        // provides multiple locales, we try to enable multiple subtypes.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoFrCA);
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
+            assertThat(nonAutoFrCA, isIn(result));
+            assertThat(nonAutoEnUS, isIn(result));
+            assertThat(nonAutoJa, isIn(result));
+            assertThat(nonAutoIn, not(isIn(result)));
+            assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
+            assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
+        }
     }
 
     @SmallTest
@@ -638,6 +824,10 @@
                 .createConfigurationContext(resourceConfiguration);
     }
 
+    private Resources getResourcesForLocales(Locale... locales) {
+        return createTargetContextWithLocales(new LocaleList(locales)).getResources();
+    }
+
     private String[] getPackageNames(final ArrayList<InputMethodInfo> imis) {
         final String[] packageNames = new String[imis.size()];
         for (int i = 0; i < imis.size(); ++i) {
@@ -683,7 +873,15 @@
     private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
             boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) {
+        return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary,
+                overridesImplicitlyEnabledSubtype, isAsciiCapable,
+                isEnabledWhenDefaultIsNotAsciiCapable);
+    }
 
+    private static InputMethodSubtype createDummyInputMethodSubtype(String locale,
+            String languageTag, String mode, boolean isAuxiliary,
+            boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable,
+            boolean isEnabledWhenDefaultIsNotAsciiCapable) {
         final StringBuilder subtypeExtraValue = new StringBuilder();
         if (isEnabledWhenDefaultIsNotAsciiCapable) {
             subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
@@ -701,6 +899,7 @@
                 .setSubtypeNameResId(0)
                 .setSubtypeIconResId(0)
                 .setSubtypeLocale(locale)
+                .setLanguageTag(languageTag)
                 .setSubtypeMode(mode)
                 .setSubtypeExtraValue(subtypeExtraValue.toString())
                 .setIsAuxiliary(isAuxiliary)
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
new file mode 100644
index 0000000..deba40f
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.inputmethod;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.LocaleList;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class LocaleUtilsTest extends InstrumentationTestCase {
+
+    private static final LocaleUtils.LocaleExtractor<Locale> sIdentityMapper =
+            new LocaleUtils.LocaleExtractor<Locale>() {
+                @Override
+                public Locale get(Locale source) {
+                    return source;
+                }
+            };
+
+    @SmallTest
+    public void testFilterByLanguageEmptyLanguageList() throws Exception {
+        final ArrayList<Locale> availableLocales = new ArrayList<>();
+        availableLocales.add(Locale.forLanguageTag("en-US"));
+        availableLocales.add(Locale.forLanguageTag("fr-CA"));
+        availableLocales.add(Locale.forLanguageTag("in"));
+        availableLocales.add(Locale.forLanguageTag("ja"));
+        availableLocales.add(Locale.forLanguageTag("fil"));
+
+        final LocaleList preferredLocales = LocaleList.getEmptyLocaleList();
+
+        final ArrayList<Locale> dest = new ArrayList<>();
+        LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+        assertEquals(0, dest.size());
+    }
+
+    @SmallTest
+    public void testFilterDoesNotMatchAnything() throws Exception {
+        final ArrayList<Locale> availableLocales = new ArrayList<>();
+        availableLocales.add(Locale.forLanguageTag("en-US"));
+        availableLocales.add(Locale.forLanguageTag("fr-CA"));
+        availableLocales.add(Locale.forLanguageTag("in"));
+        availableLocales.add(Locale.forLanguageTag("ja"));
+        availableLocales.add(Locale.forLanguageTag("fil"));
+
+        final LocaleList preferredLocales = LocaleList.forLanguageTags("zh-Hans-TW");
+
+        final ArrayList<Locale> dest = new ArrayList<>();
+        LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+        assertEquals(0, dest.size());
+    }
+
+    @SmallTest
+    public void testFilterByLanguageEmptySource() throws Exception {
+        final ArrayList<Locale> availableLocales = new ArrayList<>();
+
+        final LocaleList preferredLocales = LocaleList.forLanguageTags("fr,en-US,ja-JP");
+
+        final ArrayList<Locale> dest = new ArrayList<>();
+        LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+        assertEquals(0, dest.size());
+    }
+
+    @SmallTest
+    public void testFilterByLanguageNullAvailableLocales() throws Exception {
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(null);
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(0, dest.size());
+        }
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(null);
+            availableLocales.add(null);
+            availableLocales.add(null);
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(0, dest.size());
+        }
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(null);
+            availableLocales.add(Locale.forLanguageTag("en-US"));
+            availableLocales.add(null);
+            availableLocales.add(null);
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(1), dest.get(0));  // "en-US"
+        }
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(null);
+            availableLocales.add(Locale.forLanguageTag("en"));
+            availableLocales.add(null);
+            availableLocales.add(null);
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(1), dest.get(0));  // "en"
+        }
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(null);
+            availableLocales.add(Locale.forLanguageTag("ja-JP"));
+            availableLocales.add(null);
+            availableLocales.add(null);
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(0, dest.size());
+        }
+    }
+
+    @SmallTest
+    public void testFilterByLanguage() throws Exception {
+        {
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("en-US"));
+            availableLocales.add(Locale.forLanguageTag("fr-CA"));
+            availableLocales.add(Locale.forLanguageTag("in"));
+            availableLocales.add(Locale.forLanguageTag("ja"));
+            availableLocales.add(Locale.forLanguageTag("fil"));
+
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("fr,en-US,ja-JP");
+
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(3, dest.size());
+            assertEquals(availableLocales.get(1), dest.get(0));  // "fr-CA"
+            assertEquals(availableLocales.get(0), dest.get(1));  // "en-US"
+            assertEquals(availableLocales.get(3), dest.get(2));  // "ja"
+        }
+        {
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("en-US"));
+            availableLocales.add(Locale.forLanguageTag("en-GB"));
+            availableLocales.add(Locale.forLanguageTag("en-IN"));
+
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("en-US");
+
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(0), dest.get(0));  // "en-US"
+        }
+    }
+
+    @SmallTest
+    public void testFilterByLanguageTheSameLanguage() throws Exception {
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("fr-CA"));
+            availableLocales.add(Locale.forLanguageTag("en-US"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(1), dest.get(0));  // "en-US"
+        }
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("fr-CA"));
+            availableLocales.add(Locale.forLanguageTag("en"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(1), dest.get(0));  // "en"
+        }
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("fr-CA"));
+            availableLocales.add(Locale.forLanguageTag("en-CA"));
+            availableLocales.add(Locale.forLanguageTag("en-IN"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(2), dest.get(0));  // "en-IN"
+        }
+        {
+            final LocaleList preferredLocales =
+                    LocaleList.forLanguageTags("en-AU,en-GB,en-US,en-IN");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("fr-CA"));
+            availableLocales.add(Locale.forLanguageTag("en-CA"));
+            availableLocales.add(Locale.forLanguageTag("en-NZ"));
+            availableLocales.add(Locale.forLanguageTag("en-BZ"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(1), dest.get(0));  // "en-CA"
+        }
+    }
+
+    @SmallTest
+    public void testFilterByLanguageFallbackRules() throws Exception {
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-BA"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-ME"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-BA"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-CS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-ME"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(7), dest.get(0));  // "sr-Latn-RS"
+        }
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS-x-android");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-BA"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-ME"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-BA"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-CS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-ME"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(7), dest.get(0));  // "sr-Latn-RS"
+        }
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-BA-x-android"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS-x-android"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-ME-x-android"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS-x-android"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-BA-x-android"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-CS-x-android"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-ME-x-android"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-RS-x-android"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(7), dest.get(0));  // "sr-Latn-RS-x-android"
+        }
+
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(2), dest.get(0));  // "sr-Latn"
+        }
+
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-RS");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr"));
+            availableLocales.add(Locale.forLanguageTag("sr-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(0), dest.get(0));  // "sr"
+        }
+
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr"));
+            availableLocales.add(Locale.forLanguageTag("sr-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(2), dest.get(0));  // "sr-Latn"
+        }
+
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr"));
+            availableLocales.add(Locale.forLanguageTag("sr-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(0), dest.get(0));  // "sr"
+        }
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+            availableLocales.add(Locale.forLanguageTag("sr-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(1), dest.get(0));  // "sr-RS"
+        }
+
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(0), dest.get(0));  // "sr-Cyrl-RS"
+        }
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+            availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            assertEquals(availableLocales.get(0), dest.get(0));  // "sr-Latn-RS"
+        }
+    }
+
+    public void testFilterKnownLimitation() throws Exception {
+        // Following test cases are not for intentional behavior but checks for preventing the
+        // behavior from becoming worse.
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("ja-Hrkt");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("ja-Jpan"));
+            availableLocales.add(Locale.forLanguageTag("ja-Hrkt"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            // Should be ja-Jpan since it supports ja-Hrkt and listed before ja-Hrkt.
+            assertEquals(availableLocales.get(1), dest.get(0));
+        }
+        {
+            final LocaleList preferredLocales = LocaleList.forLanguageTags("zh-Hani");
+            final ArrayList<Locale> availableLocales = new ArrayList<>();
+            availableLocales.add(Locale.forLanguageTag("zh-Hans"));
+            availableLocales.add(Locale.forLanguageTag("zh-Hant"));
+            availableLocales.add(Locale.forLanguageTag("zh-Hanb"));
+            availableLocales.add(Locale.forLanguageTag("zh-Hani"));
+            final ArrayList<Locale> dest = new ArrayList<>();
+            LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+            assertEquals(1, dest.size());
+            // Should be zh-Hans since it supports zh-Hani. Also zh-Hant, zh-Hanb supports zh-Hani.
+            assertEquals(availableLocales.get(3), dest.get(0));
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
index 12a75b8..327f3fd 100644
--- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.net;
 
-import static android.net.NetworkStats.ROAMING_DEFAULT;
+import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
@@ -157,7 +157,7 @@
 
     private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
             int tag, long rxBytes, long txBytes) {
-        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_DEFAULT);
+        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO);
         final NetworkStats.Entry entry = stats.getValues(i, null);
         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
@@ -165,7 +165,7 @@
 
     private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
             int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
-        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_DEFAULT);
+        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO);
         final NetworkStats.Entry entry = stats.getValues(i, null);
         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
         assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
new file mode 100644
index 0000000..1c3cd38
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsServTest extends TestCase {
+    private static final String TAG = "BatteryStatsServTest";
+
+    public static class TestServ extends BatteryStatsImpl.Uid.Pkg.Serv {
+        TestServ(MockBatteryStatsImpl bsi) {
+            super(bsi);
+        }
+
+        void populate() {
+            mStartTime = 1010;
+            mRunningSince = 2021;
+            mRunning = true;
+            mStarts = 4042;
+            mLaunchedTime = 5053;
+            mLaunchedSince = 6064;
+            mLaunched = true;
+            mLaunches = 8085;
+            mLoadedStartTime = 9096;
+            mLoadedStarts = 10017;
+            mLoadedLaunches = 11118;
+            mLastStartTime = 12219;
+            mLastStarts = 13310;
+            mLastLaunches = 14411;
+            mUnpluggedStartTime = 15512;
+            mUnpluggedStarts = 16613;
+            mUnpluggedLaunches = 17714;
+        }
+
+        long getStartTime() {
+            return mStartTime;
+        }
+
+        long getRunningSince() {
+            return mRunningSince;
+        }
+
+        void setRunning(boolean val) {
+            mRunning = val;
+        }
+
+        boolean getRunning() {
+            return mRunning;
+        }
+
+        int getStarts() {
+            return mStarts;
+        }
+
+        long getLaunchedTime() {
+            return mLaunchedTime;
+        }
+
+        long getLaunchedSince() {
+            return mLaunchedSince;
+        }
+
+        void setLaunched(boolean val) {
+            mLaunched = val;
+        }
+
+        boolean getLaunched() {
+            return mLaunched;
+        }
+
+        int getLaunches() {
+            return mLaunches;
+        }
+
+        long getLoadedStartTime() {
+            return mLoadedStartTime;
+        }
+
+        int getLoadedStarts() {
+            return mLoadedStarts;
+        }
+
+        int getLoadedLaunches() {
+            return mLoadedLaunches;
+        }
+
+        long getLastStartTime() {
+            return mLastStartTime;
+        }
+
+        int getLastStarts() {
+            return mLastStarts;
+        }
+
+        int getLastLaunches() {
+            return mLastLaunches;
+        }
+
+        long getUnpluggedStartTime() {
+            return mUnpluggedStartTime;
+        }
+
+        int getUnpluggedStarts() {
+            return mUnpluggedStarts;
+        }
+
+        int getUnpluggedLaunches() {
+            return mUnpluggedLaunches;
+        }
+    }
+
+    /**
+     * Test that the constructor and detach methods touch the time bast observer list.
+     */
+    @SmallTest
+    public void testConstructAndDetach() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+
+        TestServ serv = new TestServ(bsi);
+        Assert.assertTrue(bsi.getOnBatteryTimeBase().hasObserver(serv));
+
+        serv.detach();
+        Assert.assertFalse(bsi.getOnBatteryTimeBase().hasObserver(serv));
+    }
+
+    /**
+     * Test OnTimeStarted
+     */
+    @SmallTest
+    public void testOnTimeStarted() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setRunning(true);
+        serv.onTimeStarted(111111, 20000, 222222);
+        Assert.assertEquals(18989, serv.getUnpluggedStartTime());
+        Assert.assertEquals(4042, serv.getUnpluggedStarts());
+        Assert.assertEquals(8085, serv.getUnpluggedLaunches());
+
+        serv.populate();
+        serv.setRunning(false);
+        serv.onTimeStarted(111111, 20000, 222222);
+        Assert.assertEquals(1010, serv.getUnpluggedStartTime());
+        Assert.assertEquals(4042, serv.getUnpluggedStarts());
+        Assert.assertEquals(8085, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test parceling and unparceling.
+     */
+    @SmallTest
+    public void testParceling() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ orig = new TestServ(bsi);
+        orig.populate();
+
+        Parcel parcel = Parcel.obtain();
+        orig.writeToParcelLocked(parcel);
+
+        parcel.setDataPosition(0);
+
+        TestServ serv = new TestServ(bsi);
+        serv.readFromParcelLocked(parcel);
+   
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(0, serv.getLastStartTime());
+        Assert.assertEquals(0, serv.getLastStarts());
+        Assert.assertEquals(0, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test getLaunchTimeToNow()
+     */
+    @SmallTest
+    public void testLaunchTimeToNow() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setLaunched(true);
+        Assert.assertEquals(8989, serv.getLaunchTimeToNowLocked(10000));
+
+        serv.populate();
+        serv.setLaunched(false);
+        Assert.assertEquals(5053, serv.getLaunchTimeToNowLocked(10000));
+
+    }
+
+    /**
+     * Test getStartTimeToNow()
+     */
+    @SmallTest
+    public void testStartTimeToNow() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setRunning(true);
+        Assert.assertEquals(18989, serv.getStartTimeToNowLocked(20000));
+
+        serv.populate();
+        serv.setRunning(false);
+        Assert.assertEquals(1010, serv.getStartTimeToNowLocked(20000));
+    }
+
+    /**
+     * Test startLaunchedLocked while not previously launched
+     */
+    @SmallTest
+    public void testStartLaunchedLockedWhileLaunched() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 777777L;
+            }
+        };
+
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setLaunched(true);
+        serv.startLaunchedLocked();
+
+        // No changes
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test startLaunchedLocked while previously launched
+     */
+    @SmallTest
+    public void testStartLaunchedLockedWhileNotLaunched() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 777777L;
+            }
+        };
+
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setLaunched(false);
+        serv.startLaunchedLocked();
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(777777L, serv.getLaunchedSince()); // <-- changed
+        Assert.assertTrue(serv.getLaunched()); // <-- changed
+        Assert.assertEquals(8086, serv.getLaunches()); // <-- changed
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test stopLaunchedLocked when not previously launched.
+     */
+    @SmallTest
+    public void testStopLaunchedLockedWhileNotLaunched() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 777777L;
+            }
+        };
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setLaunched(false);
+
+        serv.stopLaunchedLocked();
+
+        // No changes
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertFalse(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test stopLaunchedLocked when previously launched, with measurable time between
+     * start and stop.
+     */
+    @SmallTest
+    public void testStopLaunchedLockedWhileLaunchedNormal() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 777777L;
+            }
+        };
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setLaunched(true);
+
+        serv.stopLaunchedLocked();
+
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(777777L-6064+5053, serv.getLaunchedTime()); // <-- changed 
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertFalse(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test stopLaunchedLocked when previously launched, with no measurable time between
+     * start and stop.
+     */
+    @SmallTest
+    public void testStopLaunchedLockedWhileLaunchedTooQuick() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 6064L;
+            }
+        };
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setLaunched(true);
+
+        serv.stopLaunchedLocked();
+
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertFalse(serv.getLaunched());
+        Assert.assertEquals(8085-1, serv.getLaunches()); // <-- changed 
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test startRunningLocked while previously running
+     */
+    @SmallTest
+    public void testStartRunningLockedWhileRunning() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 777777L;
+            }
+        };
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setRunning(true);
+
+        serv.startRunningLocked();
+
+        // no change
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test startRunningLocked while not previously launched
+     */
+    @SmallTest
+    public void testStartRunningLockedWhileNotRunning() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 777777L;
+            }
+        };
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setRunning(false);
+
+        serv.startRunningLocked();
+
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(777777L, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042+1, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test stopRunningLocked when previously launched, with measurable time between
+     * start and stop.
+     */
+    @SmallTest
+    public void testStopRunningLockedWhileRunningNormal() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 777777L;
+            }
+        };
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setRunning(true);
+
+        serv.stopRunningLocked();
+
+        Assert.assertEquals(777777L-2021+1010, serv.getStartTime()); // <-- changed
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertFalse(serv.getRunning()); // <-- changed
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test stopRunningLocked when previously launched, with measurable time between
+     * start and stop.
+     */
+    @SmallTest
+    public void testStopRunningLockedWhileRunningTooQuick() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+            @Override
+            public long getBatteryUptimeLocked() {
+                return 2021;
+            }
+        };
+        TestServ serv = new TestServ(bsi);
+
+        serv.populate();
+        serv.setRunning(true);
+
+        serv.stopRunningLocked();
+
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertFalse(serv.getRunning()); // <-- changed
+        Assert.assertEquals(4042-1, serv.getStarts()); // <-- changed
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test that getBatteryStats returns the BatteryStatsImpl passed in to the contstructor.
+     */
+    @SmallTest
+    public void testGetBatteryStats() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+
+        Assert.assertEquals(bsi, serv.getBatteryStats());
+    }
+
+    /**
+     * Test getLaunches
+     */
+    @SmallTest
+    public void testGetLaunches() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+        serv.populate();
+
+        Assert.assertEquals(8085, serv.getLaunches(BatteryStats.STATS_SINCE_CHARGED));
+        Assert.assertEquals(8085-11118, serv.getLaunches(BatteryStats.STATS_CURRENT));
+        Assert.assertEquals(8085-17714, serv.getLaunches(BatteryStats.STATS_SINCE_UNPLUGGED));
+
+        // No change to fields
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test getStartTime while running
+     */
+    @SmallTest
+    public void testGetStartTimeRunning() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+        serv.populate();
+        serv.setRunning(true);
+
+        final long startTimeToNow = 1010 + 20000 - 2021;
+
+        Assert.assertEquals(startTimeToNow,
+                serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
+        Assert.assertEquals(startTimeToNow-9096,
+                serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
+        Assert.assertEquals(startTimeToNow-15512,
+                serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+        // No change to fields
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+    /**
+     * Test getStartTime while not running
+     */
+    @SmallTest
+    public void testGetStartTimeNotRunning() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+        serv.populate();
+        serv.setRunning(false);
+
+        final long startTimeToNow = 1010;
+
+        Assert.assertEquals(startTimeToNow,
+                serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
+        Assert.assertEquals(startTimeToNow-9096,
+                serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
+        Assert.assertEquals(startTimeToNow-15512,
+                serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+        // No change to fields
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertFalse(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+
+
+    /**
+     * Test getStarts
+     */
+    @SmallTest
+    public void testGetStarts() throws Exception  {
+        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+        TestServ serv = new TestServ(bsi);
+        serv.populate();
+
+        Assert.assertEquals(4042, serv.getStarts(BatteryStats.STATS_SINCE_CHARGED));
+        Assert.assertEquals(4042-10017, serv.getStarts(BatteryStats.STATS_CURRENT));
+        Assert.assertEquals(4042-16613, serv.getStarts(BatteryStats.STATS_SINCE_UNPLUGGED));
+
+        // No change to fields
+        Assert.assertEquals(1010, serv.getStartTime());
+        Assert.assertEquals(2021, serv.getRunningSince());
+        Assert.assertTrue(serv.getRunning());
+        Assert.assertEquals(4042, serv.getStarts());
+        Assert.assertEquals(5053, serv.getLaunchedTime());
+        Assert.assertEquals(6064, serv.getLaunchedSince());
+        Assert.assertTrue(serv.getLaunched());
+        Assert.assertEquals(8085, serv.getLaunches());
+        Assert.assertEquals(9096, serv.getLoadedStartTime());
+        Assert.assertEquals(10017, serv.getLoadedStarts());
+        Assert.assertEquals(11118, serv.getLoadedLaunches());
+        Assert.assertEquals(12219, serv.getLastStartTime());
+        Assert.assertEquals(13310, serv.getLastStarts());
+        Assert.assertEquals(14411, serv.getLastLaunches());
+        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+        Assert.assertEquals(16613, serv.getUnpluggedStarts());
+        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+    }
+    
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
new file mode 100644
index 0000000..05aa53c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -0,0 +1,15 @@
+package com.android.internal.os;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+        BatteryStatsServTest.class,
+        BatteryStatsTimeBaseTest.class,
+        BatteryStatsTimerTest.class,
+        BatteryStatsUidTest.class,
+    })
+public class BatteryStatsTests {
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
new file mode 100644
index 0000000..ab92f15
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsTimeBaseTest extends TestCase {
+    private static final String TAG = "BatteryStatsTimeBaseTest";
+
+    static class TestTimeBase extends BatteryStatsImpl.TimeBase {
+
+        public void populate(long uptime, long realtime, boolean running, long pastUptime,
+                long uptimeStart, long pastRealtime, long realtimeStart,
+                long unpluggedUptime, long unpluggedRealtime) {
+            mUptime = uptime;
+            mRealtime = realtime;
+            mRunning = running;
+            mPastUptime = pastUptime;
+            mUptimeStart = uptimeStart;
+            mPastRealtime = pastRealtime;
+            mRealtimeStart = realtimeStart;
+            mUnpluggedUptime = unpluggedUptime;
+            mUnpluggedRealtime = unpluggedRealtime;
+        }
+
+        public void verify(long uptime, long realtime, boolean running, long pastUptime,
+                long uptimeStart, long pastRealtime, long realtimeStart,
+                long unpluggedUptime, long unpluggedRealtime) {
+            Assert.assertEquals(uptime, mUptime);
+            Assert.assertEquals(realtime, mRealtime);
+            Assert.assertEquals(running, mRunning);
+            Assert.assertEquals(pastUptime, mPastUptime);
+            Assert.assertEquals(uptimeStart, mUptimeStart);
+            Assert.assertEquals(pastRealtime, mPastRealtime);
+            Assert.assertEquals(realtimeStart, mRealtimeStart);
+            Assert.assertEquals(unpluggedUptime, mUnpluggedUptime);
+            Assert.assertEquals(unpluggedRealtime, mUnpluggedRealtime);
+        }
+    }
+
+    /**
+     * Test the observers and the setRunning call.
+     */
+    @SmallTest
+    public void testRunning() throws Exception {
+        TestTimeBase tb = new TestTimeBase();
+
+        // Toggle running once, to accumulate past uptime and past realtime
+        // so the test values aren't 0.
+        tb.setRunning(true, 100, 10000);
+        tb.setRunning(false, 200, 11000);
+        Assert.assertEquals(100, tb.getUptimeStart());
+        Assert.assertEquals(10000, tb.getRealtimeStart());
+
+        // Create some observers
+        BatteryStatsImpl.TimeBaseObs observer1 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+        BatteryStatsImpl.TimeBaseObs observer2 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+        BatteryStatsImpl.TimeBaseObs observer3 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+
+        // Add them
+        tb.add(observer1);
+        tb.add(observer2);
+        tb.add(observer3);
+        Assert.assertTrue(tb.hasObserver(observer1));
+        Assert.assertTrue(tb.hasObserver(observer2));
+        Assert.assertTrue(tb.hasObserver(observer3));
+
+        // Remove one
+        tb.remove(observer3);
+        Assert.assertTrue(tb.hasObserver(observer1));
+        Assert.assertTrue(tb.hasObserver(observer2));
+        Assert.assertFalse(tb.hasObserver(observer3));
+
+        // Start running, make sure we get a started call on the two active observers
+        // and not the third.
+        tb.setRunning(true, 250, 14000);
+
+        Assert.assertTrue(tb.isRunning());
+
+        if (false) {
+            Log.d(TAG, "mUptimeStart=" + tb.getUptimeStart()
+                    + " mRealtimeStart=" + tb.getRealtimeStart()
+                    + " mUptime=" + tb.getUptime(250)
+                    + " mRealtime=" + tb.getRealtime(14000)
+                    + " isRunning=" + tb.isRunning());
+        }
+
+        Assert.assertEquals(250, tb.getUptimeStart());
+        Assert.assertEquals(14000, tb.getRealtimeStart());
+        Assert.assertEquals(100, tb.getUptime(250));
+        Assert.assertEquals(1000, tb.getRealtime(14000));
+
+        Mockito.verify(observer1).onTimeStarted(14000, 100, 1000);
+        Mockito.verify(observer1, Mockito.never()).onTimeStopped(-1, -1, -1);
+        Mockito.verifyNoMoreInteractions(observer1);
+        Mockito.verify(observer2).onTimeStarted(14000, 100, 1000);
+        Mockito.verify(observer2, Mockito.never()).onTimeStopped(-1, -1, -1);
+        Mockito.verifyNoMoreInteractions(observer2);
+
+        Mockito.reset(observer1);
+        Mockito.reset(observer2);
+        Mockito.reset(observer3);
+
+        // Advance the "timer" and make sure the getters account for the current time passed in
+        Assert.assertEquals(400, tb.getUptime(550));
+        Assert.assertEquals(1555, tb.getRealtime(14555));
+
+        // Stop running, make sure we get a stopped call on the two active observers
+        // and not the third.
+        tb.setRunning(false, 402, 14002);
+
+        Assert.assertFalse(tb.isRunning());
+
+        if (false) {
+            Log.d(TAG, "mUptimeStart=" + tb.getUptimeStart()
+                    + " mRealtimeStart=" + tb.getRealtimeStart()
+                    + " mUptime=" + tb.getUptime(250)
+                    + " mRealtime=" + tb.getRealtime(14000)
+                    + " isRunning=" + tb.isRunning());
+        }
+
+        Assert.assertEquals(252, tb.getUptime(402));
+        Assert.assertEquals(1002, tb.getRealtime(14002));
+
+        Mockito.verify(observer1).onTimeStopped(14002, 252, 1002);
+        Mockito.verify(observer1, Mockito.never()).onTimeStopped(-1, -1, -1);
+        Mockito.verifyNoMoreInteractions(observer1);
+        Mockito.verify(observer2).onTimeStopped(14002, 252, 1002);
+        Mockito.verify(observer2, Mockito.never()).onTimeStopped(-1, -1, -1);
+        Mockito.verifyNoMoreInteractions(observer2);
+
+        // Advance the "timer" and make sure the getters account for the current time passed in
+        // is the same as the time when running went to false.
+        Assert.assertEquals(252, tb.getUptime(600));
+        Assert.assertEquals(1002, tb.getRealtime(17000));
+    }
+
+    /**
+     * Test that reset while running updates the plugged and unplugged times
+     */
+    @SmallTest
+    public void testResetWhileRunning() throws Exception {
+        TestTimeBase tb = new TestTimeBase();
+        tb.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+        tb.reset(666, 6666);
+
+        // Not sure if this is a bug: reset while running does not
+        // reset mPastUptime, but while it is running it does.
+        tb.verify(100, 200, true, 300, 666, 500, 6666, 300, 500);
+    }
+
+    /**
+     * Test that reset while running updates the plugged and unplugged times
+     */
+    @SmallTest
+    public void testResetWhileNotRunning() throws Exception {
+        TestTimeBase tb = new TestTimeBase();
+        tb.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+        tb.reset(666, 6666);
+
+        tb.verify(100, 200, false, 0, 400, 0, 600, 700, 800);
+    }
+
+    /**
+     * Test init
+     */
+    @SmallTest
+    public void testInit() throws Exception {
+        TestTimeBase tb = new TestTimeBase();
+        tb.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+        tb.init(666, 6666);
+
+        tb.verify(0, 0, false, 0, 666, 0, 6666, 0, 0);
+    }
+
+    /**
+     * Test writeToParcel and readFromParcel
+     */
+    @SmallTest
+    public void testParcellingWhileRunning() throws Exception {
+        TestTimeBase tb1 = new TestTimeBase();
+
+        tb1.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+        Parcel parcel = Parcel.obtain();
+        tb1.writeToParcel(parcel, 666, 6666);
+
+        parcel.setDataPosition(0);
+
+        TestTimeBase tb2 = new TestTimeBase();
+        tb2.readFromParcel(parcel);
+
+        // Running is not preserved across parceling
+        tb2.verify(100, 200, false, 300+666-400, 400, 500+6666-600, 600, 700, 800);
+    }
+
+    /**
+     * Test writeToParcel and readFromParcel
+     */
+    @SmallTest
+    public void testParcellingWhileNotRunning() throws Exception {
+        TestTimeBase tb1 = new TestTimeBase();
+
+        tb1.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+        Parcel parcel = Parcel.obtain();
+        tb1.writeToParcel(parcel, 666, 6666);
+
+        parcel.setDataPosition(0);
+
+        TestTimeBase tb2 = new TestTimeBase();
+        tb2.readFromParcel(parcel);
+
+        tb2.verify(100, 200, false, 300, 400, 500, 600, 700, 800);
+    }
+
+    /**
+     * Test writeSummaryToParcel and readSummaryFromParcel
+     */
+    @SmallTest
+    public void testSummary() throws Exception {
+        TestTimeBase tb1 = new TestTimeBase();
+
+        tb1.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+        Parcel parcel = Parcel.obtain();
+        tb1.writeSummaryToParcel(parcel, 666, 6666);
+
+        parcel.setDataPosition(0);
+
+        TestTimeBase tb2 = new TestTimeBase();
+
+        // readSummaryFromParcel doesn't affect the other fields.
+        // Not sure if this is deliberate
+        tb2.populate(1, 2, true, 3, 4, 5, 6, 7, 8);
+
+        tb2.readSummaryFromParcel(parcel);
+
+        tb2.verify(666, 6766, true, 3, 4, 5, 6, 7, 8);
+    }
+
+    /**
+     * Test computeUptime
+     */
+    @SmallTest
+    public void testComputeUptime() throws Exception {
+        TestTimeBase tb = new TestTimeBase();
+
+        tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+        Assert.assertEquals(100+300+666-400,
+                tb.computeUptime(666, BatteryStats.STATS_SINCE_CHARGED));
+        Assert.assertEquals(300+666-400,
+                tb.computeUptime(666, BatteryStats.STATS_CURRENT));
+        Assert.assertEquals(300+666-400-50,
+                tb.computeUptime(666, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+        Assert.assertEquals(0, tb.computeUptime(666, 6000));
+    }
+
+    /**
+     * Test computeUptime
+     */
+    @SmallTest
+    public void testComputeRealtime() throws Exception {
+        TestTimeBase tb = new TestTimeBase();
+
+        tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+        Assert.assertEquals(200+500+6666-600,
+                tb.computeRealtime(6666, BatteryStats.STATS_SINCE_CHARGED));
+        Assert.assertEquals(500+6666-600,
+                tb.computeRealtime(6666, BatteryStats.STATS_CURRENT));
+        Assert.assertEquals(500+6666-600-60,
+                tb.computeRealtime(6666, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+        Assert.assertEquals(0, tb.computeUptime(666, 6000));
+    }
+
+    /**
+     * Test dump
+     */
+    @SmallTest
+    public void testDump() throws Exception {
+        TestTimeBase tb = new TestTimeBase();
+
+        tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+
+        tb.dump(pw, "+++++ ");
+
+        pw.close();
+
+        // note the spaces at the ends of the lines which come from formatTimeMs.
+        final String CORRECT = "+++++ mRunning=true\n"
+                + "+++++ mUptime=0ms \n"
+                + "+++++ mRealtime=0ms \n"
+                + "+++++ mPastUptime=0ms mUptimeStart=0ms mUnpluggedUptime=0ms \n"
+                + "+++++ mPastRealtime=0ms mRealtimeStart=0ms mUnpluggedRealtime=0ms \n";
+
+        Assert.assertEquals(CORRECT, sw.toString());
+    }
+
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
new file mode 100644
index 0000000..3e17fcb
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.util.StringBuilderPrinter;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl.Clocks;
+import com.android.internal.os.BatteryStatsImpl.TimeBase;
+import com.android.internal.os.BatteryStatsImpl.Timer;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsTimerTest extends TestCase {
+    private static final String TAG = "BatteryStatsTest";
+
+    class TestTimer extends Timer {
+        long nextComputeRunTime;
+        long lastComputeRunTimeRealtime;
+
+        int nextComputeCurrentCount;
+
+        TestTimer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
+            super(clocks, type, timeBase, in);
+        }
+
+        TestTimer(Clocks clocks, int type, TimeBase timeBase) {
+            super(clocks, type, timeBase);
+        }
+
+        protected long computeRunTimeLocked(long curBatteryRealtime) {
+            lastComputeRunTimeRealtime = curBatteryRealtime;
+            return nextComputeRunTime;
+        }
+
+        protected int computeCurrentCountLocked() {
+            return nextComputeCurrentCount;
+        }
+
+        public int getCount() {
+            return mCount;
+        }
+
+        public void setCount(int val) {
+            mCount = val;
+        }
+
+        public int getLoadedCount() {
+            return mLoadedCount;
+        }
+
+        public void setLoadedCount(int val) {
+            mLoadedCount = val;
+        }
+
+        public int getLastCount() {
+            return mLastCount;
+        }
+
+        public void setLastCount(int val) {
+            mLastCount = val;
+        }
+
+        public int getUnpluggedCount() {
+            return mUnpluggedCount;
+        }
+
+        public void setUnpluggedCount(int val) {
+            mUnpluggedCount = val;
+        }
+
+        public long getTotalTime() {
+            return mTotalTime;
+        }
+
+        public void setTotalTime(long val) {
+            mTotalTime = val;
+        }
+
+        public long getLoadedTime() {
+            return mLoadedTime;
+        }
+
+        public void setLoadedTime(long val) {
+            mLoadedTime = val;
+        }
+
+        public long getLastTime() {
+            return mLastTime;
+        }
+
+        public void setLastTime(long val) {
+            mLastTime = val;
+        }
+
+        public long getUnpluggedTime() {
+            return mUnpluggedTime;
+        }
+
+        public void setUnpluggedTime(long val) {
+            mUnpluggedTime = val;
+        }
+
+        public long getTimeBeforeMark() {
+            return mTimeBeforeMark;
+        }
+
+        public void setTimeBeforeMark(long val) {
+            mTimeBeforeMark = val;
+        }
+    }
+
+    /**
+     * Tests that the flow through TimeBase.setRunning propagates through
+     * to the timer.
+     */
+    @SmallTest
+    public void testRunning() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer = new TestTimer(clocks, 0, timeBase);
+        timer.nextComputeCurrentCount = 3000;
+
+        // Test that starting the timer counts the unplugged time and counters
+        timer.nextComputeRunTime = 4;
+        timer.onTimeStarted(10, 20, 50);
+        Assert.assertEquals(50, timer.lastComputeRunTimeRealtime);
+        Assert.assertEquals(4, timer.getUnpluggedTime());
+        Assert.assertEquals(0, timer.getUnpluggedCount());
+
+        // Test that stopping the timer updates mTotalTime and mCount
+        timer.nextComputeRunTime = 17;
+        timer.onTimeStopped(100, 130, 170);
+        Assert.assertEquals(17, timer.getTotalTime());
+        Assert.assertEquals(3000, timer.getCount());
+    }
+
+    /**
+     * Tests that the parcel can be parceled and unparceled without losing anything.
+     */
+    @SmallTest
+    public void testParceling() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        MockClocks clocks = new MockClocks();
+
+        // Test write then read
+        TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
+        timer1.setCount(1);
+        timer1.setLoadedCount(2);
+        timer1.setLastCount(3);
+        timer1.setUnpluggedCount(4);
+        timer1.setTotalTime(9223372036854775807L);
+        timer1.setLoadedTime(9223372036854775806L);
+        timer1.setLastTime(9223372036854775805L);
+        timer1.setUnpluggedTime(9223372036854775804L);
+        timer1.setTimeBeforeMark(9223372036854775803L);
+        timer1.nextComputeRunTime = 201;
+
+        Parcel parcel = Parcel.obtain();
+        Timer.writeTimerToParcel(parcel, timer1, 77);
+
+        parcel.setDataPosition(0);
+        Assert.assertTrue("parcel null object", parcel.readInt() != 0);
+
+        TestTimer timer2 = new TestTimer(clocks, 0, timeBase, parcel);
+        Assert.assertEquals(1, timer2.getCount());
+        Assert.assertEquals(2, timer2.getLoadedCount());
+        Assert.assertEquals(0, timer2.getLastCount()); // NOT saved
+        Assert.assertEquals(4, timer2.getUnpluggedCount());
+        Assert.assertEquals(201, timer2.getTotalTime()); // from computeRunTimeLocked()
+        Assert.assertEquals(9223372036854775806L, timer2.getLoadedTime());
+        Assert.assertEquals(0, timer2.getLastTime()); // NOT saved
+        Assert.assertEquals(9223372036854775804L, timer2.getUnpluggedTime());
+        Assert.assertEquals(9223372036854775803L, timer2.getTimeBeforeMark());
+
+        parcel.recycle();
+    }
+
+    /**
+     * Tests that the parcel can be parceled and unparceled without losing anything.
+     */
+    @SmallTest
+    public void testParcelingNull() throws Exception {
+        // Test writing null
+        Parcel parcel = Parcel.obtain();
+        Timer.writeTimerToParcel(parcel, null, 88);
+
+        parcel.setDataPosition(0);
+        Assert.assertEquals(0, parcel.readInt());
+
+        parcel.recycle();
+    }
+
+    /**
+     * Tests that reset() clears the correct times.
+     */
+    @SmallTest
+    public void testResetNoDetach() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer = new TestTimer(clocks, 0, timeBase);
+        timer.setCount(1);
+        timer.setLoadedCount(2);
+        timer.setLastCount(3);
+        timer.setUnpluggedCount(4);
+        timer.setTotalTime(9223372036854775807L);
+        timer.setLoadedTime(9223372036854775806L);
+        timer.setLastTime(9223372036854775805L);
+        timer.setUnpluggedTime(9223372036854775804L);
+        timer.setTimeBeforeMark(9223372036854775803L);
+
+        timer.reset(false);
+
+        Assert.assertEquals(0, timer.getCount());
+        Assert.assertEquals(0, timer.getLoadedCount());
+        Assert.assertEquals(0, timer.getLastCount());
+        Assert.assertEquals(4, timer.getUnpluggedCount());
+        Assert.assertEquals(0, timer.getTotalTime());
+        Assert.assertEquals(0, timer.getLoadedTime());
+        Assert.assertEquals(0, timer.getLastTime());
+        Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
+        Assert.assertEquals(0, timer.getTimeBeforeMark());
+
+        // reset(false) shouldn't remove it from the list
+        Assert.assertEquals(true, timeBase.hasObserver(timer));
+    }
+
+    /**
+     * Tests that reset() clears the correct times.
+     */
+    @SmallTest
+    public void testResetDetach() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer = new TestTimer(clocks, 0, timeBase);
+        timer.setCount(1);
+        timer.setLoadedCount(2);
+        timer.setLastCount(3);
+        timer.setUnpluggedCount(4);
+        timer.setTotalTime(9223372036854775807L);
+        timer.setLoadedTime(9223372036854775806L);
+        timer.setLastTime(9223372036854775805L);
+        timer.setUnpluggedTime(9223372036854775804L);
+        timer.setTimeBeforeMark(9223372036854775803L);
+
+        timer.reset(true);
+
+        Assert.assertEquals(0, timer.getCount());
+        Assert.assertEquals(0, timer.getLoadedCount());
+        Assert.assertEquals(0, timer.getLastCount());
+        Assert.assertEquals(4, timer.getUnpluggedCount());
+        Assert.assertEquals(0, timer.getTotalTime());
+        Assert.assertEquals(0, timer.getLoadedTime());
+        Assert.assertEquals(0, timer.getLastTime());
+        Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
+        Assert.assertEquals(0, timer.getTimeBeforeMark());
+
+        // reset(true) should remove it from the list
+        Assert.assertEquals(false, timeBase.hasObserver(timer));
+    }
+
+    /**
+     * Tests reading and writing the summary to a parcel
+     */
+    @SmallTest
+    public void testSummaryParceling() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        timeBase.setRunning(true, 10, 20);
+        timeBase.setRunning(false, 45, 60);
+        Assert.assertEquals(40, timeBase.getRealtime(200));
+        // the past uptime is 35 and the past runtime is 40
+
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
+        timer1.setCount(1);
+        timer1.setLoadedCount(2);
+        timer1.setLastCount(3);
+        timer1.setUnpluggedCount(4);
+        timer1.setTotalTime(9223372036854775807L);
+        timer1.setLoadedTime(9223372036854775806L);
+        timer1.setLastTime(9223372036854775805L);
+        timer1.setUnpluggedTime(9223372036854775804L);
+        timer1.setTimeBeforeMark(9223372036854775803L);
+
+        Parcel parcel = Parcel.obtain();
+        timer1.nextComputeRunTime = 9223372036854775800L;
+        timer1.writeSummaryFromParcelLocked(parcel, 201);
+        Assert.assertEquals(40, timer1.lastComputeRunTimeRealtime);
+
+        TestTimer timer2 = new TestTimer(clocks, 0, timeBase);
+
+        // Make sure that all the values get touched
+        timer2.setCount(666);
+        timer2.setLoadedCount(666);
+        timer2.setLastCount(666);
+        timer2.setUnpluggedCount(666);
+        timer2.setTotalTime(666);
+        timer2.setLoadedTime(666);
+        timer2.setLastTime(666);
+        timer2.setUnpluggedTime(666);
+        timer2.setTimeBeforeMark(666);
+
+        parcel.setDataPosition(0);
+
+        parcel.setDataPosition(0);
+        timer2.readSummaryFromParcelLocked(parcel);
+
+        Assert.assertEquals(1, timer2.getCount());
+        Assert.assertEquals(1, timer2.getLoadedCount());
+        Assert.assertEquals(0, timer2.getLastCount());
+        Assert.assertEquals(1, timer2.getUnpluggedCount());
+        Assert.assertEquals(9223372036854775800L, timer2.getTotalTime());
+        Assert.assertEquals(9223372036854775800L, timer2.getLoadedTime());
+        Assert.assertEquals(0, timer2.getLastTime());
+        Assert.assertEquals(9223372036854775800L, timer2.getUnpluggedTime());
+        Assert.assertEquals(9223372036854775800L, timer2.getTimeBeforeMark());
+
+        parcel.recycle();
+    }
+
+    /**
+     * Tests getTotalTimeLocked
+     */
+    @SmallTest
+    public void testGetTotalTimeLocked() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        timeBase.setRunning(true, 10, 20);
+        timeBase.setRunning(false, 45, 60);
+        Assert.assertEquals(40, timeBase.getRealtime(200));
+
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer = new TestTimer(clocks, 0, timeBase);
+        timer.setCount(1);
+        timer.setLoadedCount(2);
+        timer.setLastCount(3);
+        timer.setUnpluggedCount(4);
+        timer.setTotalTime(100);
+        timer.setLoadedTime(200);
+        timer.setLastTime(300);
+        timer.setUnpluggedTime(400);
+        timer.setTimeBeforeMark(500);
+
+        timer.nextComputeRunTime = 10000;
+
+        // Timer.getTotalTimeLocked(STATS_SINCE_CHARGED)
+        timer.lastComputeRunTimeRealtime = -1;
+        Assert.assertEquals(10000,
+                timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_CHARGED));
+        Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+
+        // Timer.getTotalTimeLocked(STATS_CURRENT)
+        timer.lastComputeRunTimeRealtime = -1;
+        Assert.assertEquals(9800, timer.getTotalTimeLocked(66, BatteryStats.STATS_CURRENT));
+        Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+
+        // Timer.getTotalTimeLocked(STATS_SINCE_UNPLUGGED)
+        timer.lastComputeRunTimeRealtime = -1;
+        Assert.assertEquals(9600, timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_UNPLUGGED));
+        Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+    }
+
+    /**
+     * Tests getCountLocked
+     */
+    @SmallTest
+    public void testGetCountLocked() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        timeBase.setRunning(true, 10, 20);
+        timeBase.setRunning(false, 45, 60);
+        Assert.assertEquals(40, timeBase.getRealtime(200));
+
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer = new TestTimer(clocks, 0, timeBase);
+        timer.setCount(1);
+        timer.setLoadedCount(2);
+        timer.setLastCount(3);
+        timer.setUnpluggedCount(4);
+        timer.setTotalTime(100);
+        timer.setLoadedTime(200);
+        timer.setLastTime(300);
+        timer.setUnpluggedTime(400);
+        timer.setTimeBeforeMark(500);
+
+        // Timer.getCountLocked(STATS_SINCE_CHARGED)
+        timer.nextComputeCurrentCount = 10000;
+        Assert.assertEquals(10000, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+        // Timer.getCountLocked(STATS_CURRENT)
+        timer.nextComputeCurrentCount = 10000;
+        Assert.assertEquals(9998, timer.getCountLocked(BatteryStats.STATS_CURRENT));
+
+        // Timer.getCountLocked(STATS_SINCE_UNPLUGGED)
+        timer.nextComputeCurrentCount = 10000;
+        Assert.assertEquals(9996, timer.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
+    }
+
+    /**
+     * Tests getTimeSinceMarkLocked
+     */
+    @SmallTest
+    public void testGetTimeSinceMarked() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        timeBase.setRunning(true, 10, 20);
+        timeBase.setRunning(false, 45, 60);
+        Assert.assertEquals(40, timeBase.getRealtime(200));
+
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer = new TestTimer(clocks, 0, timeBase);
+        timer.setCount(1);
+        timer.setLoadedCount(2);
+        timer.setLastCount(3);
+        timer.setUnpluggedCount(4);
+        timer.setTotalTime(100);
+        timer.setLoadedTime(200);
+        timer.setLastTime(300);
+        timer.setUnpluggedTime(400);
+        timer.setTimeBeforeMark(500);
+
+        timer.nextComputeRunTime = 10000;
+        Assert.assertEquals(9500, timer.getTimeSinceMarkLocked(666));
+    }
+
+    /**
+     * Tests logState
+     */
+    @SmallTest
+    public void testLogState() throws Exception {
+        TimeBase timeBase = new TimeBase();
+        MockClocks clocks = new MockClocks();
+
+        TestTimer timer = new TestTimer(clocks, 0, timeBase);
+        timer.setTotalTime(100);
+        timer.setLoadedTime(200);
+        timer.setLastTime(300);
+        timer.setUnpluggedTime(400);
+        timer.setTimeBeforeMark(500);
+        timer.setCount(1);
+        timer.setLoadedCount(2);
+        timer.setLastCount(3);
+        timer.setUnpluggedCount(4);
+        timer.setTotalTime(9223372036854775807L);
+        timer.setLoadedTime(9223372036854775806L);
+        timer.setLastTime(9223372036854775805L);
+        timer.setUnpluggedTime(9223372036854775804L);
+        timer.setTimeBeforeMark(9223372036854775803L);
+
+        StringBuilder sb = new StringBuilder();
+        StringBuilderPrinter pw = new StringBuilderPrinter(sb);
+
+        timer.logState(pw, "  ");
+
+        Assert.assertEquals(
+                      "  mCount=1 mLoadedCount=2 mLastCount=3 mUnpluggedCount=4\n"
+                    + "  mTotalTime=9223372036854775807 mLoadedTime=9223372036854775806\n"
+                    + "  mLastTime=9223372036854775805 mUnpluggedTime=9223372036854775804\n",
+                sb.toString());
+    }
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
new file mode 100644
index 0000000..a7e75a2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.mockito.Mockito;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsUidTest extends TestCase {
+    private static final String TAG = "BatteryStatsTimeBaseTest";
+
+    static class TestBsi extends BatteryStatsImpl {
+        TestBsi(MockClocks clocks) {
+            super(clocks);
+        }
+    }
+
+    /**
+     * Test the observers and the setRunning call.
+     */
+    @SmallTest
+    public void testParceling() throws Exception  {
+    }
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
new file mode 100644
index 0000000..3924489
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.mockito.Mockito;
+
+/**
+ * Mocks a BatteryStatsImpl object.
+ */
+public class MockBatteryStatsImpl extends BatteryStatsImpl {
+    public BatteryStatsImpl.Clocks clocks;
+
+    MockBatteryStatsImpl() {
+        super(new MockClocks());
+        this.clocks = mClocks;
+    }
+
+    public TimeBase getOnBatteryTimeBase() {
+        return mOnBatteryTimeBase;
+    }
+
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/MockClocks.java b/core/tests/coretests/src/com/android/internal/os/MockClocks.java
new file mode 100644
index 0000000..f750c37
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/MockClocks.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+public class MockClocks implements BatteryStatsImpl.Clocks {
+    public long realtime;
+    public long uptime;
+
+    @Override
+    public long elapsedRealtime() {
+        return realtime;
+    }
+
+    @Override
+    public long uptimeMillis() {
+        return uptime;
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 1966313..2a24881 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -22,7 +22,6 @@
 import android.view.ActionMode;
 import android.view.ActionMode.Callback;
 import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -291,9 +290,6 @@
 
         @Override
         public void onActionModeFinished(ActionMode mode) {}
-
-        @Override
-        public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {}
     }
 
     private static final class MockActionModeCallback implements ActionMode.Callback {
diff --git a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
new file mode 100644
index 0000000..b3897ce
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS 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.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ArrayUtilsTest extends TestCase {
+
+    @SmallTest
+    public void testUnstableRemoveIf() throws Exception {
+        java.util.function.Predicate<Object> isNull = new java.util.function.Predicate<Object>() {
+            @Override
+            public boolean test(Object o) {
+                return o == null;
+            }
+        };
+
+        final Object a = new Object();
+        final Object b = new Object();
+        final Object c = new Object();
+
+        ArrayList<Object> collection = null;
+        assertEquals(0, ArrayUtils.unstableRemoveIf(collection, isNull));
+
+        collection = new ArrayList<>();
+        assertEquals(0, ArrayUtils.unstableRemoveIf(collection, isNull));
+
+        collection = new ArrayList<>(Collections.singletonList(a));
+        assertEquals(0, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(1, collection.size());
+        assertTrue(collection.contains(a));
+
+        collection = new ArrayList<>(Collections.singletonList(null));
+        assertEquals(1, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(0, collection.size());
+
+        collection = new ArrayList<>(Arrays.asList(a, b));
+        assertEquals(0, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(2, collection.size());
+        assertTrue(collection.contains(a));
+        assertTrue(collection.contains(b));
+
+        collection = new ArrayList<>(Arrays.asList(a, null));
+        assertEquals(1, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(1, collection.size());
+        assertTrue(collection.contains(a));
+
+        collection = new ArrayList<>(Arrays.asList(null, a));
+        assertEquals(1, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(1, collection.size());
+        assertTrue(collection.contains(a));
+
+        collection = new ArrayList<>(Arrays.asList(null, null));
+        assertEquals(2, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(0, collection.size());
+
+        collection = new ArrayList<>(Arrays.asList(a, b, c));
+        assertEquals(0, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(3, collection.size());
+        assertTrue(collection.contains(a));
+        assertTrue(collection.contains(b));
+        assertTrue(collection.contains(c));
+
+        collection = new ArrayList<>(Arrays.asList(a, b, null));
+        assertEquals(1, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(2, collection.size());
+        assertTrue(collection.contains(a));
+        assertTrue(collection.contains(b));
+
+        collection = new ArrayList<>(Arrays.asList(a, null, b));
+        assertEquals(1, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(2, collection.size());
+        assertTrue(collection.contains(a));
+        assertTrue(collection.contains(b));
+
+        collection = new ArrayList<>(Arrays.asList(null, a, b));
+        assertEquals(1, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(2, collection.size());
+        assertTrue(collection.contains(a));
+        assertTrue(collection.contains(b));
+
+        collection = new ArrayList<>(Arrays.asList(a, null, null));
+        assertEquals(2, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(1, collection.size());
+        assertTrue(collection.contains(a));
+
+        collection = new ArrayList<>(Arrays.asList(null, null, a));
+        assertEquals(2, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(1, collection.size());
+        assertTrue(collection.contains(a));
+
+        collection = new ArrayList<>(Arrays.asList(null, a, null));
+        assertEquals(2, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(1, collection.size());
+        assertTrue(collection.contains(a));
+
+        collection = new ArrayList<>(Arrays.asList(null, null, null));
+        assertEquals(3, ArrayUtils.unstableRemoveIf(collection, isNull));
+        assertEquals(0, collection.size());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java b/core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java
new file mode 100644
index 0000000..fbf5523
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 junit.framework.TestCase;
+
+public class ProgressReporterTest extends TestCase {
+    private ProgressReporter r;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        r = new ProgressReporter(0, null);
+    }
+
+    private void assertProgress(int expected) {
+        assertEquals(expected, r.getProgress());
+    }
+
+    private void assertRange(int start, int len) {
+        final int[] range = r.getSegmentRange();
+        assertEquals("start", start, range[0]);
+        assertEquals("len", len, range[1]);
+    }
+
+    public void testBasic() throws Exception {
+        assertProgress(0);
+
+        r.setProgress(20);
+        assertProgress(20);
+
+        r.setProgress(-20);
+        assertProgress(0);
+
+        r.setProgress(1024);
+        assertProgress(100);
+    }
+
+    public void testSegment() throws Exception {
+        r.setProgress(20);
+        assertProgress(20);
+
+        final int[] lastRange = r.startSegment(40);
+        {
+            assertProgress(20);
+
+            r.setProgress(50);
+            assertProgress(40);
+        }
+        r.endSegment(lastRange);
+        assertProgress(60);
+
+        r.setProgress(80);
+        assertProgress(80);
+    }
+
+    public void testSegmentOvershoot() throws Exception {
+        r.setProgress(20);
+        assertProgress(20);
+
+        final int[] lastRange = r.startSegment(40);
+        {
+            r.setProgress(-100, 2);
+            assertProgress(20);
+
+            r.setProgress(1, 2);
+            assertProgress(40);
+
+            r.setProgress(100, 2);
+            assertProgress(60);
+        }
+        r.endSegment(lastRange);
+        assertProgress(60);
+    }
+
+    public void testSegmentNested() throws Exception {
+        r.setProgress(20);
+        assertProgress(20);
+        assertRange(0, 100);
+
+        final int[] lastRange = r.startSegment(40);
+        assertRange(20, 40);
+        {
+            r.setProgress(50);
+            assertProgress(40);
+
+            final int[] lastRange2 = r.startSegment(25);
+            assertRange(40, 10);
+            {
+                r.setProgress(0);
+                assertProgress(40);
+
+                r.setProgress(50);
+                assertProgress(45);
+
+                r.setProgress(100);
+                assertProgress(50);
+            }
+            r.endSegment(lastRange2);
+            assertProgress(50);
+        }
+        r.endSegment(lastRange);
+        assertProgress(60);
+    }
+}
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index 0c20876..b512396 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -9,7 +9,7 @@
 	$(call all-java-files-under, src)
 
 LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib
+LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
 LOCAL_JAVA_LIBRARIES := android.test.runner
 LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index f949e1a..3c6c32e 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -12,7 +12,8 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test
+    android-support-test \
+    mockito-target
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
index 5f36c2d..3cef336 100644
--- a/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
@@ -16,16 +16,32 @@
 
 package com.android.internal.util;
 
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.util.Xml;
+
 import junit.framework.TestCase;
 
+import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Tests for {@link FastXmlSerializer}
  */
+@SmallTest
 public class FastXmlSerializerTest extends TestCase {
+    private static final String TAG = "FastXmlSerializerTest";
+
+    private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH TRUE.
+
+    private static final String ROOT_TAG = "root";
+    private static final String ATTR = "attr";
+
     public void testEmptyText() throws Exception {
         final ByteArrayOutputStream stream = new ByteArrayOutputStream();
 
@@ -44,4 +60,93 @@
         assertEquals("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                 + "<string name=\"meow\"></string>\n", stream.toString());
     }
+
+    private boolean checkPreserved(String description, String str) {
+        boolean ok = true;
+        byte[] data;
+        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            final XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(baos, StandardCharsets.UTF_16.name());
+            out.startDocument(null, true);
+
+            out.startTag(null, ROOT_TAG);
+            out.attribute(null, ATTR, str);
+            out.text(str);
+            out.endTag(null, ROOT_TAG);
+
+            out.endDocument();
+            baos.flush();
+            data = baos.toByteArray();
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to serialize: " + description, e);
+            return false;
+        }
+
+        if (ENABLE_DUMP) {
+            Log.d(TAG, "Dump:");
+            Log.d(TAG, new String(data));
+        }
+
+        try (final ByteArrayInputStream baos = new ByteArrayInputStream(data)) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(baos, StandardCharsets.UTF_16.name());
+
+            int type;
+            String tag = null;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (type == XmlPullParser.START_TAG) {
+                    tag = parser.getName();
+                    if (ROOT_TAG.equals(tag)) {
+                        String read = parser.getAttributeValue(null, ATTR);
+                        if (!str.equals(read)) {
+                            Log.e(TAG, "Attribute not preserved: " + description
+                                    + " input=\"" + str + "\", but read=\"" + read + "\"");
+                            ok = false;
+                        }
+                    }
+                }
+                if (type == XmlPullParser.TEXT && ROOT_TAG.equals(tag)) {
+                    String read = parser.getText();
+                    if (!str.equals(parser.getText())) {
+                        Log.e(TAG, "Text not preserved: " + description
+                                + " input=\"" + str + "\", but read=\"" + read + "\"");
+                        ok = false;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to parse: " + description, e);
+            return false;
+        }
+        return ok;
+    }
+
+    private boolean check(String description, String str) throws Exception {
+        boolean ok = false;
+        ok |= checkPreserved(description, str);
+        ok |= checkPreserved(description + " wrapped with spaces" ,"  " + str + "  ");
+        return ok;
+    }
+
+    @LargeTest
+    public void testAllCharacters() throws Exception {
+        boolean ok = true;
+        for (int i = 0; i < 0xffff; i++) {
+            if (0xd800 <= i && i <= 0xdfff) {
+                // Surrogate pair characters.
+                continue;
+            }
+            ok &= check("char: " + i, String.valueOf((char) i));
+        }
+        // Dangling surrogate pairs. We can't preserve them.
+        assertFalse(check("+ud800", "\ud800"));
+        assertFalse(check("+udc00", "\udc00"));
+
+        for (int i = 0xd800; i < 0xdc00; i ++) {
+            for (int j = 0xdc00; j < 0xe000; j++) {
+                ok &= check("char: " + i, String.valueOf((char) i) + String.valueOf((char) j));
+            }
+        }
+        assertTrue("Some tests failed.  See logcat for details.", ok);
+    }
 }
diff --git a/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
new file mode 100644
index 0000000..32b969a
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static org.junit.Assert.*;
+
+import com.android.internal.util.MessageUtils;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.SparseArray;
+
+import org.junit.Test;
+
+
+class A {
+    // Should not see these.
+    private int mMember;
+    public final int CMD_NOT_STATIC = 7;
+    private static final String CMD_NOT_INT = "not an integer";
+    public static int CMD_NOT_FINAL = 34;
+    public static final int kWrongPrefix = 99;
+
+    // Should see these.
+    private static final int CMD_DO_SOMETHING = 12;
+    public static final int EVENT_SOMETHING_HAPPENED = 45;
+}
+
+class B {
+    public static final int CMD_FOO = 56;
+    public static final int EVENT_BAR = 55;
+    public static final int NOTIFICATION_BAZ = 12;
+}
+
+/**
+ * Unit tests for {@link com.android.util.MessageUtils}.
+ */
+@SmallTest
+public class MessageUtilsTest {
+
+    private static final Class[] CLASSES = { A.class, B.class };
+
+    private SparseArray<String> makeSparseArray(int[] keys, String[] values) throws Exception {
+        assertEquals("Must specify same number of keys and values", keys.length, values.length);
+        SparseArray<String> out = new SparseArray<>();
+        for (int i = 0; i < keys.length; i++) {
+            out.put(keys[i], values[i]);
+        }
+        return out;
+    }
+
+    private void assertSparseArrayEquals(
+            SparseArray<String> a1, SparseArray<String> a2) throws Exception {
+        String msg = String.format("%s != %s", a1.toString(), a2.toString());
+        assertEquals(msg, a1.size(), a2.size());
+        int size = a1.size();
+        for (int i = 0; i < size; i++) {
+            assertEquals(msg, a1.keyAt(i), a2.keyAt(i));
+            assertEquals(msg, a1.valueAt(i), a2.valueAt(i));
+        }
+    }
+
+    @Test
+    public void basicOperation() throws Exception {
+        SparseArray<String> expected = makeSparseArray(
+            new int[]{12, 45, 55, 56},
+            new String[]{"CMD_DO_SOMETHING", "EVENT_SOMETHING_HAPPENED", "EVENT_BAR", "CMD_FOO"});
+        assertSparseArrayEquals(expected, MessageUtils.findMessageNames(CLASSES));
+    }
+
+    @Test
+    public void withPrefixes() throws Exception {
+        SparseArray<String> expected = makeSparseArray(
+            new int[]{45, 55},
+            new String[]{"EVENT_SOMETHING_HAPPENED", "EVENT_BAR"});
+        assertSparseArrayEquals(expected, MessageUtils.findMessageNames(CLASSES,
+                new String[]{"EVENT_"}));
+    }
+
+    @Test(expected=MessageUtils.DuplicateConstantError.class)
+    public void duplicateConstants() {
+        MessageUtils.findMessageNames(CLASSES, new String[]{"CMD_", "NOTIFICATION_"});
+    }
+
+}
diff --git a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
new file mode 100644
index 0000000..da8bc1d
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * Unit tests for {@link com.android.internal.util.WakeupMessage}.
+ */
+@SmallTest
+public class WakeupMessageTest {
+    private static final String TEST_CMD_NAME = "TEST cmd Name";
+    private static final int TEST_CMD = 18;
+    private static final int TEST_ARG1 = 33;
+    private static final int TEST_ARG2 = 182;
+
+    @Mock AlarmManager mAlarmManager;
+    WakeupMessage mMessage;
+    // Make a spy so that we can verify calls to it
+    @Spy MessageCapturingHandler mHandler = new MessageCapturingHandler();
+
+    ArgumentCaptor<AlarmManager.OnAlarmListener> mListenerCaptor =
+            ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+
+    /**
+     * A Handler that will capture the most recent message sent to it.
+     *
+     * This handler is setup on the main Looper
+     */
+    public static class MessageCapturingHandler extends Handler {
+        private Message mLastMessage;
+
+        public MessageCapturingHandler() {
+            super(Looper.getMainLooper(), /* Nothing is actually dispatched on this Looper */
+                    null, false);
+        }
+
+        @Override
+        public void handleMessage(Message m) {
+            // need to copy since it will be recycled after this method returns
+            mLastMessage = Message.obtain(m);
+        }
+
+        public Message getLastMessage() {
+            return mLastMessage;
+        }
+    }
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        Context context = mock(Context.class);
+        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+        // capture the listener for each AlarmManager.setExact call
+        doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), any(String.class),
+                mListenerCaptor.capture(), any(Handler.class));
+
+        mMessage = new WakeupMessage(context, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
+                TEST_ARG2);
+    }
+
+    /**
+     * Ensure the test is cleaned up and ready for the next test.
+     */
+    @After
+    public void cleanup() {
+        validateMockitoUsage();
+    }
+
+    private void scheduleAndVerifyAlarm(long when) {
+        mMessage.schedule(when);
+        verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when),
+                eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler));
+    }
+
+    private void verifyMessageDispatchedOnce() {
+        verify(mHandler, times(1)).handleMessage(any(Message.class));
+        assertEquals("what", TEST_CMD, mHandler.getLastMessage().what);
+        assertEquals("arg1", TEST_ARG1, mHandler.getLastMessage().arg1);
+        assertEquals("arg2", TEST_ARG2, mHandler.getLastMessage().arg2);
+    }
+
+    /**
+     * Schedule and deliver a single message
+     */
+    @Test
+    public void scheduleAndDeliverMessage() {
+        final long when = 1001;
+        scheduleAndVerifyAlarm(when);
+        verify(mHandler, never()).handleMessage(any(Message.class));
+        mListenerCaptor.getValue().onAlarm();
+        verifyMessageDispatchedOnce();
+    }
+
+    /**
+     * Check that the message is not delivered if cancel is called it after its alarm fires but
+     * before onAlarm is called.
+     *
+     * This ensures that if cancel is called on the handler thread, any previously-scheduled message
+     * is guaranteed not to be delivered.
+     */
+    @Test
+    public void scheduleAndCancelMessage() {
+        final long when = 1010;
+        scheduleAndVerifyAlarm(when);
+        mMessage.cancel();
+        mListenerCaptor.getValue().onAlarm();
+        verify(mHandler, never()).handleMessage(any(Message.class));
+    }
+
+    /**
+     * Verify nothing happens when cancel is called without a schedule
+     */
+    @Test
+    public void cancelWithoutSchedule() {
+        mMessage.cancel();
+    }
+
+    /**
+     * Verify that the message is silently rescheduled if schedule is called twice without the
+     * message being dispatched first.
+     */
+    @Test
+    public void scheduleTwiceWithoutMessageDispatched() {
+        final long when1 = 1011;
+        final long when2 = 1012;
+        scheduleAndVerifyAlarm(when1);
+        scheduleAndVerifyAlarm(when2);
+        mListenerCaptor.getValue().onAlarm();
+        verifyMessageDispatchedOnce();
+    }
+
+}
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index de741b3..f4c5b53 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -95,3 +95,19 @@
 
 build-one-font-module :=
 font_src_files :=
+
+
+# Run sanity tests on fonts on checkbuild
+checkbuild: fontchain_lint
+
+FONTCHAIN_LINTER := frameworks/base/tools/fonts/fontchain_lint.py
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+CHECK_EMOJI := false
+else
+CHECK_EMOJI := true
+endif
+
+.PHONY: fontchain_lint
+fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml $(PRODUCT_OUT)/system.img
+	PYTHONPATH=$$PYTHONPATH:external/fonttools/Lib \
+	python $(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index dc302c7..bcac6a1 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -88,242 +88,246 @@
     </family>
 
     <!-- fallback fonts -->
-    <family variant="elegant">
+    <family lang="und-Arab" variant="elegant">
         <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
         <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Arab" variant="compact">
         <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
     </family>
-    <family>
+    <family lang="und-Ethi">
         <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
     </family>
-    <family>
+    <family lang="und-Hebr">
         <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Thai" variant="elegant">
         <font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Thai" variant="compact">
         <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
     </family>
-    <family>
+    <family lang="und-Armn">
         <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
     </family>
-    <family>
+    <!-- TODO: add Geok -->
+    <family lang="und-Geor">
         <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Deva" variant="elegant">
         <font weight="400" style="normal">NotoSansDevanagari-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansDevanagari-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Deva" variant="compact">
         <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
     </family>
-    <!-- Gujarati should come after Devanagari -->
-    <family variant="elegant">
+
+    <!-- All scripts of India should come after Devanagari, due to shared
+         danda characters.
+    -->
+    <family lang="und-Gujr" variant="elegant">
         <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Gujr" variant="compact">
         <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
     </family>
-    <!-- Gurmukhi should come after Devanagari -->
-    <family variant="elegant">
+    <family lang="und-Guru" variant="elegant">
         <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGurmukhi-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Guru" variant="compact">
         <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Taml" variant="elegant">
         <font weight="400" style="normal">NotoSansTamil-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTamil-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Taml" variant="compact">
         <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Mlym" variant="elegant">
         <font weight="400" style="normal">NotoSansMalayalam-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansMalayalam-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Mlym" variant="compact">
         <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Beng" variant="elegant">
         <font weight="400" style="normal">NotoSansBengali-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansBengali-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Beng" variant="compact">
         <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Telu" variant="elegant">
         <font weight="400" style="normal">NotoSansTelugu-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTelugu-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Telu" variant="compact">
         <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Knda" variant="elegant">
         <font weight="400" style="normal">NotoSansKannada-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKannada-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Knda" variant="compact">
         <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Orya" variant="elegant">
         <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Orya" variant="compact">
         <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
     </family>
-    <family>
+
+    <family lang="und-Sinh">
         <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Khmr" variant="elegant">
         <font weight="400" style="normal">NotoSansKhmer-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKhmer-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Khmr" variant="compact">
         <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Laoo" variant="elegant">
         <font weight="400" style="normal">NotoSansLao-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Laoo" variant="compact">
         <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
     </family>
-    <family variant="elegant">
+    <family lang="und-Mymr" variant="elegant">
         <font weight="400" style="normal">NotoSansMyanmar-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansMyanmar-Bold.ttf</font>
     </family>
-    <family variant="compact">
+    <family lang="und-Mymr" variant="compact">
         <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
     </family>
-    <family>
+    <family lang="und-Thaa">
         <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
     </family>
-    <family>
+    <family lang="und-Cham">
         <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
     </family>
-    <family>
+    <family lang="und-Bali">
         <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Bamu">
         <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Batk">
         <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Bugi">
         <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Buhd">
         <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Cans">
         <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Cher">
         <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Copt">
         <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Glag">
         <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Hano">
         <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Java">
         <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Kali">
         <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Lepc">
         <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Limb">
         <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Lisu">
         <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Mand">
         <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Mtei">
         <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Talu">
         <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Nkoo">
         <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Olck">
         <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Rjng">
         <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Saur">
         <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Sund">
         <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Sylo">
         <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Syre">
         <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Tagb">
         <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Lana">
         <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Tavt">
         <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Tibt">
         <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Tfng">
         <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Vaii">
         <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Yiii">
         <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
     </family>
     <family>
@@ -332,6 +336,7 @@
     <family lang="zh-Hans">
         <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
     </family>
+    <!-- TODO: Add Bopo -->
     <family lang="zh-Hant">
         <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
     </family>
@@ -351,10 +356,10 @@
         Tai Le and Mongolian are intentionally kept last, to make sure they don't override
         the East Asian punctuation for Chinese.
     -->
-    <family>
+    <family lang="und-Tale">
         <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
     </family>
-    <family>
+    <family lang="und-Mong">
         <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
     </family>
 </familyset>
diff --git a/data/keyboards/qwerty2.kcm b/data/keyboards/qwerty2.kcm
index d96914f..b981d83 100644
--- a/data/keyboards/qwerty2.kcm
+++ b/data/keyboards/qwerty2.kcm
@@ -23,8 +23,8 @@
     number:                             '2'
     base:                               'a'
     shift, capslock:                    'A'
-    alt:                                'a'
-    shift+alt, capslock+alt:            'A'
+    alt:                                '\u00e1'
+    shift+alt, capslock+alt:            '\u00c1'
 }
 
 key B {
@@ -41,8 +41,8 @@
     number:                             '2'
     base:                               'c'
     shift, capslock:                    'C'
-    alt:                                '\u00e7'
-    shift+alt, capslock+alt:            '\u00e7'
+    alt:                                '\u00a9'
+    shift+alt, capslock+alt:            '\u00a2'
 }
 
 key D {
@@ -50,8 +50,8 @@
     number:                             '3'
     base:                               'd'
     shift, capslock:                    'D'
-    alt:                                '\''
-    shift+alt, capslock+alt:            '\''
+    alt:                                '\u00f0'
+    shift+alt, capslock+alt:            '\u00d0'
 }
 
 key E {
@@ -59,8 +59,8 @@
     number:                             '3'
     base:                               'e'
     shift, capslock:                    'E'
-    alt:                                '"'
-    shift+alt, capslock+alt:            '\u0301'
+    alt:                                '\u00e9'
+    shift+alt, capslock+alt:            '\u00c9'
 }
 
 key F {
@@ -95,8 +95,8 @@
     number:                             '4'
     base:                               'i'
     shift, capslock:                    'I'
-    alt:                                '-'
-    shift+alt, capslock+alt:            '\u0302'
+    alt:                                '\u00ed'
+    shift+alt, capslock+alt:            '\u00cd'
 }
 
 key J {
@@ -122,8 +122,8 @@
     number:                             '5'
     base:                               'l'
     shift, capslock:                    'L'
-    alt:                                ':'
-    shift+alt, capslock+alt:            '`'
+    alt:                                '\u00f8'
+    shift+alt, capslock+alt:            '\u00d8'
 }
 
 key M {
@@ -131,7 +131,7 @@
     number:                             '6'
     base:                               'm'
     shift, capslock:                    'M'
-    alt:                                '%'
+    alt:                                '\u00b5'
     shift+alt, capslock+alt:            none
 }
 
@@ -140,8 +140,8 @@
     number:                             '6'
     base:                               'n'
     shift, capslock:                    'N'
-    alt:                                none
-    shift+alt, capslock+alt:            '\u0303'
+    alt:                                '\u00f1'
+    shift+alt, capslock+alt:            '\u00d1'
 }
 
 key O {
@@ -149,8 +149,8 @@
     number:                             '6'
     base:                               'o'
     shift, capslock:                    'O'
-    alt:                                '+'
-    shift+alt, capslock+alt:            '+'
+    alt:                                '\u00f3'
+    shift+alt, capslock+alt:            '\u00d3'
 }
 
 key P {
@@ -158,8 +158,8 @@
     number:                             '7'
     base:                               'p'
     shift, capslock:                    'P'
-    alt:                                '='
-    shift+alt, capslock+alt:            '\u00a5'
+    alt:                                '\u00f6'
+    shift+alt, capslock+alt:            '\u00d6'
 }
 
 key Q {
@@ -167,8 +167,8 @@
     number:                             '7'
     base:                               'q'
     shift, capslock:                    'Q'
-    alt:                                '|'
-    shift+alt, capslock+alt:            '\u0300'
+    alt:                                '\u00e4'
+    shift+alt, capslock+alt:            '\u00c4'
 }
 
 key R {
@@ -176,8 +176,8 @@
     number:                             '7'
     base:                               'r'
     shift, capslock:                    'R'
-    alt:                                '`'
-    shift+alt, capslock+alt:            '\u20ac'
+    alt:                                '\u00ae'
+    shift+alt, capslock+alt:            'R'
 }
 
 key S {
@@ -185,8 +185,8 @@
     number:                             '7'
     base:                               's'
     shift, capslock:                    'S'
-    alt:                                '\\'
-    shift+alt, capslock+alt:            '\u00df'
+    alt:                                '\u00df'
+    shift+alt, capslock+alt:            '\u00a7'
 }
 
 key T {
@@ -194,8 +194,8 @@
     number:                             '8'
     base:                               't'
     shift, capslock:                    'T'
-    alt:                                '{'
-    shift+alt, capslock+alt:            '\u00a3'
+    alt:                                '\u00fe'
+    shift+alt, capslock+alt:            '\u00de'
 }
 
 key U {
@@ -203,8 +203,8 @@
     number:                             '8'
     base:                               'u'
     shift, capslock:                    'U'
-    alt:                                '_'
-    shift+alt, capslock+alt:            '\u0308'
+    alt:                                '\u00fa'
+    shift+alt, capslock+alt:            '\u00da'
 }
 
 key V {
@@ -221,8 +221,8 @@
     number:                             '9'
     base:                               'w'
     shift, capslock:                    'W'
-    alt:                                '~'
-    shift+alt, capslock+alt:            '~'
+    alt:                                '\u00e5'
+    shift+alt, capslock+alt:            '\u00c5'
 }
 
 key X {
@@ -239,8 +239,8 @@
     number:                             '9'
     base:                               'y'
     shift, capslock:                    'Y'
-    alt:                                '}'
-    shift+alt, capslock+alt:            '\u00a1'
+    alt:                                '\u00fc'
+    shift+alt, capslock+alt:            '\u00dc'
 }
 
 key Z {
@@ -248,8 +248,8 @@
     number:                             '9'
     base:                               'z'
     shift, capslock:                    'Z'
-    alt:                                'z'
-    shift+alt, capslock+alt:            'Z'
+    alt:                                '\u00e6'
+    shift+alt, capslock+alt:            '\u00c6'
 }
 
 key COMMA {
@@ -257,8 +257,8 @@
     number:                             ','
     base:                               ','
     shift:                              '<'
-    alt:                                ','
-    shift+alt:                          ','
+    alt:                                '\u00e7'
+    shift+alt:                          '\u00c7'
 }
 
 key PERIOD {
@@ -284,7 +284,7 @@
     number:                             '/'
     base:                               '/'
     shift:                              '?'
-    alt:                                '?'
+    alt:                                '\u00bf'
     shift+alt:                          '?'
 }
 
@@ -320,7 +320,7 @@
     number:                             '0'
     base:                               '0'
     shift:                              ')'
-    alt:                                ')'
+    alt:                                '\u02bc'
     shift+alt:                          ')'
 }
 
@@ -329,8 +329,8 @@
     number:                             '1'
     base:                               '1'
     shift:                              '!'
-    alt:                                '!'
-    shift+alt:                          '!'
+    alt:                                '\u00a1'
+    shift+alt:                          '\u00b9'
 }
 
 key 2 {
@@ -338,7 +338,7 @@
     number:                             '2'
     base:                               '2'
     shift:                              '@'
-    alt:                                '@'
+    alt:                                '\u00b2'
     shift+alt:                          '@'
 }
 
@@ -347,7 +347,7 @@
     number:                             '3'
     base:                               '3'
     shift:                              '#'
-    alt:                                '#'
+    alt:                                '\u00b3'
     shift+alt:                          '#'
 }
 
@@ -356,8 +356,8 @@
     number:                             '4'
     base:                               '4'
     shift:                              '$'
-    alt:                                '$'
-    shift+alt:                          '$'
+    alt:                                '\u00a4'
+    shift+alt:                          '\u00a3'
 }
 
 key 5 {
@@ -365,7 +365,7 @@
     number:                             '5'
     base:                               '5'
     shift:                              '%'
-    alt:                                '%'
+    alt:                                '\u20ac'
     shift+alt:                          '%'
 }
 
@@ -374,8 +374,8 @@
     number:                             '6'
     base:                               '6'
     shift:                              '^'
-    alt:                                '^'
-    shift+alt:                          '^'
+    alt:                                '\u00bc'
+    shift+alt:                          '\u0302'
 }
 
 key 7 {
@@ -383,7 +383,7 @@
     number:                             '7'
     base:                               '7'
     shift:                              '&'
-    alt:                                '&'
+    alt:                                '\u00bd'
     shift+alt:                          '&'
 }
 
@@ -392,7 +392,7 @@
     number:                             '8'
     base:                               '8'
     shift:                              '*'
-    alt:                                '*'
+    alt:                                '\u00be'
     shift+alt:                          '*'
 }
 
@@ -401,7 +401,7 @@
     number:                             '9'
     base:                               '9'
     shift:                              '('
-    alt:                                '('
+    alt:                                '\u02bb'
     shift+alt:                          '('
 }
 
@@ -410,8 +410,8 @@
     number:                             '`'
     base:                               '`'
     shift:                              '~'
-    alt:                                '`'
-    shift+alt:                          '~'
+    alt:                                '\u0300'
+    shift+alt:                          '\u0303'
 }
 
 key MINUS {
@@ -419,7 +419,7 @@
     number:                             '-'
     base:                               '-'
     shift:                              '_'
-    alt:                                '-'
+    alt:                                '\u00a5'
     shift+alt:                          '_'
 }
 
@@ -428,8 +428,8 @@
     number:                             '='
     base:                               '='
     shift:                              '+'
-    alt:                                '='
-    shift+alt:                          '+'
+    alt:                                '\u00d7'
+    shift+alt:                          '\u00f7'
 }
 
 key LEFT_BRACKET {
@@ -437,7 +437,7 @@
     number:                             '['
     base:                               '['
     shift:                              '{'
-    alt:                                '['
+    alt:                                '\u00ab'
     shift+alt:                          '{'
 }
 
@@ -446,7 +446,7 @@
     number:                             ']'
     base:                               ']'
     shift:                              '}'
-    alt:                                ']'
+    alt:                                '\u00bb'
     shift+alt:                          '}'
 }
 
@@ -455,8 +455,8 @@
     number:                             '\\'
     base:                               '\\'
     shift:                              '|'
-    alt:                                '\\'
-    shift+alt:                          '|'
+    alt:                                '\u00ac'
+    shift+alt:                          '\u00a6'
 }
 
 key SEMICOLON {
@@ -464,8 +464,8 @@
     number:                             ';'
     base:                               ';'
     shift:                              ':'
-    alt:                                ';'
-    shift+alt:                          ':'
+    alt:                                '\u00b6'
+    shift+alt:                          '\u00b0'
 }
 
 key APOSTROPHE {
@@ -473,8 +473,8 @@
     number:                             '\''
     base:                               '\''
     shift:                              '"'
-    alt:                                '\''
-    shift+alt:                          '"'
+    alt:                                '\u0301'
+    shift+alt:                          '\u0308'
 }
 
 key STAR {
diff --git a/docs/docs-documentation-redirect.html b/docs/docs-documentation-redirect.html
index 98a265e..dbdf8b4 100644
--- a/docs/docs-documentation-redirect.html
+++ b/docs/docs-documentation-redirect.html
@@ -1,9 +1,9 @@
 <html>
 <head>
-<meta http-equiv="refresh" content="0;url=documentation.html">
+<meta http-equiv="refresh" content="0;url=reference/packages.html">
 </head>
 <body>
-<a href="documentation.html">click here if you are not redirected</a>
+<a href="reference/packages.html">click here if you are not redirected</a>
 </body>
 </html>
 
diff --git a/docs/docs-preview-index.html b/docs/docs-preview-index.html
new file mode 100644
index 0000000..e26b57c
--- /dev/null
+++ b/docs/docs-preview-index.html
@@ -0,0 +1,103 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
+<meta content="IE=edge" http-equiv="X-UA-Compatible">
+<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
+
+<title>Android N Developer Preview</title>
+
+<!-- STYLESHEETS -->
+<link rel="stylesheet"
+href="http://fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
+<link href="assets/css/default.css?v=17" rel="stylesheet" type="text/css">
+<!-- JAVASCRIPT -->
+<script src="https://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 = "../";
+  var metaTags = ["develop, getstarted, sdk, appquality, landing"];
+  var devsite = false;
+</script>
+<script src="assets/js/docs.js?v=3" type="text/javascript"></script>
+</head>
+
+<body>
+<div id="header-wrapper">
+  <div class="dac-header" id="header">
+    <div class="dac-header-inner">
+      <a class="dac-nav-toggle" data-dac-toggle-nav="" href="javascript:;"
+        title="Open navigation">
+        <span class="dac-nav-hamburger">
+          <span class="dac-nav-hamburger-top"></span>
+          <span class="dac-nav-hamburger-mid"></span>
+          <span class="dac-nav-hamburger-bot"></span>
+        </span>
+      </a>
+      <a class="dac-header-logo" href="index.html">
+        <img class="dac-header-logo-image" src="assets/images/android_logo.png"
+          srcset="assets/images/android_logo@2x.png 2x" width="32" height="36"
+          alt="Android"> Developers
+        </a>
+    </div>
+  </div>
+</div>
+<nav class="dac-nav">
+  <div class="dac-nav-dimmer" data-dac-toggle-nav=""></div>
+  <ul class="dac-nav-list" data-dac-nav="">
+    <li class="dac-nav-item dac-nav-head">
+      <a class="dac-nav-link dac-nav-logo" data-dac-toggle-nav=""
+        href="javascript:;" title="Close navigation">
+        <img class="dac-logo-image" src="assets/images/android_logo.png"
+          srcset="assets/images/android_logo@2x.png 2x" width="32" height="36"
+          alt="Android"> Developers
+      </a>
+    </li>
+    <li class="dac-nav-item develop">
+      <a class="dac-nav-link" href="reference/packages.html"
+        >API Reference</a>
+    </li>
+  </ul>
+</nav>
+
+<section class="dac-expand" style="padding-top:40px;background-color:#eee">
+  <div class="wrap" style="max-width:1100px;margin-top:0;height:100%">
+    <div class="cols dac-hero-content" style="padding-bottom:1em;">
+      <div class="col-11of16">
+
+
+<h1>Android N Developer Preview</h1>
+<p>
+  Get ready for Android N!
+  <strong>Test your apps</strong> on Nexus devices. Support new system
+  behaviors to <strong>save power and memory</strong>.
+  Extend your apps with <strong>multi-window UI</strong>,
+  <strong>direct reply notifications</strong> and more.
+</p>
+
+<h2>Get Started</h2>
+<ul>
+  <li>View the <a href="reference/packages.html">API Reference</a></li>
+  <li>Read Diff Reports:</a>
+    <ul>
+      <li><a href="sdk/api_diff/n-preview-1/changes.html"
+        >API 23 --> Preview 1</a></li>
+    </ul>
+  </li>
+  <li>Downloads and additional documentation are available at the
+    <a href="http://developer.android.com/preview/index.html">
+      Android N Developer Preview site</a></li>
+  <li>For information about Developer Preview 1, visit the
+    <a href="http://developer.android.com/preview/support.html">Support</a>
+    page.</li>
+</ul>
+
+
+      </div>
+    </div>
+  </div>
+</section>
+</body>
+</html>
diff --git a/docs/docs-redirect-index.html b/docs/docs-redirect-index.html
index dc0bc72..ea5f186 100644
--- a/docs/docs-redirect-index.html
+++ b/docs/docs-redirect-index.html
@@ -1,8 +1,8 @@
-<html>

-<head>

-<meta http-equiv="refresh" content="0;url=framework/index.html">

-</head>

-<body>

-<a href="framework/index.html">click here if you are not redirected</a>

-</body>

-</html>

+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=framework/index.html">
+</head>
+<body>
+<a href="framework/index.html">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/docs-redirect.html b/docs/docs-redirect.html
index 4e0743e..d83564c 100644
--- a/docs/docs-redirect.html
+++ b/docs/docs-redirect.html
@@ -1,8 +1,8 @@
-<html>

-<head>

-<meta http-equiv="refresh" content="0;url=docs/offline.html">

-</head>

-<body>

-<a href="docs/offline.html">click here if you are not redirected</a>

-</body>

-</html>

+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=docs/offline.html">
+</head>
+<body>
+<a href="docs/offline.html">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/docs-samples-redirect.html b/docs/docs-samples-redirect.html
index 4e549e6..abefe6c 100644
--- a/docs/docs-samples-redirect.html
+++ b/docs/docs-samples-redirect.html
@@ -1,8 +1,8 @@
-<html>

-<head>

-<meta http-equiv="refresh" content="0;url=../../samples/">

-</head>

-<body>

-<a href="../../samples/">click here if you are not redirected</a>

-</body>

-</html>

+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=../../samples/">
+</head>
+<body>
+<a href="../../samples/">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index f3f2e5e..e99c15a 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -631,6 +631,16 @@
     </ul>
   </li>
 
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/security/index.html">
+        <span class="en">Security</span>
+    </a></div>
+    <ul>
+        <li><a href="<?cs var:toroot ?>guide/topics/security/security-config.html">
+        <span class="en">Network Security Config</span>
+        </a></li>
+    </ul>
+  </li>
 
 </ul>
 
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 46db371..a745d00 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -178,6 +178,20 @@
 android.content.Context#MODE_WORLD_READABLE}, and {@link
 android.content.Context#MODE_WORLD_WRITEABLE}.</p>
 
+<p class="note"><strong>Note:</strong> The constants {@link
+android.content.Context#MODE_WORLD_READABLE} and {@link
+android.content.Context#MODE_WORLD_WRITEABLE} have been deprecated since API level 17.
+Starting from Android N their use will result in a {@link java.lang.SecurityException}
+to be thrown.
+This means that apps targeting Android N and higher
+cannot share private files by name, and attempts to share a "file://" URI will result in a
+{@link android.os.FileUriExposedException} to be thrown. If your app needs to share private
+files with other apps, it may use a {@link android.support.v4.content.FileProvider} with
+the {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}.
+See also <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.
+</p>
+
 <p>To read a file from internal storage:</p>
 
 <ol>
diff --git a/docs/html/guide/topics/graphics/hardware-accel.jd b/docs/html/guide/topics/graphics/hardware-accel.jd
index e3f1d9e..ca7255b 100644
--- a/docs/html/guide/topics/graphics/hardware-accel.jd
+++ b/docs/html/guide/topics/graphics/hardware-accel.jd
@@ -284,7 +284,7 @@
     </tr>
     <tr>
         <td class="label_neg">drawPicture()</td>
-        <td class="value_neg">23</td>
+        <td class="value_pos">23</td>
     </tr>
     <tr>
         <td class="label_pos">drawPosText()</td>
@@ -421,14 +421,6 @@
         <td colspan="5" class="s5">Xfermode</td>
     </tr>
     <tr>
-        <td class="label_neg">AvoidXfermode</td>
-        <td class="value_neg">&#10007;</td>
-    </tr>
-    <tr>
-        <td class="label_neg">PixelXorXfermode</td>
-        <td class="value_neg">&#10007;</td>
-    </tr>
-    <tr>
         <td class="label_neg">PorterDuff.Mode.DARKEN (framebuffer)</td>
         <td class="value_neg">&#10007;</td>
     </tr>
diff --git a/docs/html/guide/topics/renderscript/reference/overview.jd b/docs/html/guide/topics/renderscript/reference/overview.jd
index 5e824ee..017a713 100644
--- a/docs/html/guide/topics/renderscript/reference/overview.jd
+++ b/docs/html/guide/topics/renderscript/reference/overview.jd
@@ -611,7 +611,7 @@
   </tr>
 </tbody></table>
 <h2>Conversion Functions</h2>
-<p> The functions below convert from a numerical vector type to another, of from one color
+<p> The functions below convert from a numerical vector type to another, or from one color
 representation to another.
 </p>
 <table class='jd-sumtable'><tbody>
diff --git a/docs/html/guide/topics/renderscript/reference/rs_convert.jd b/docs/html/guide/topics/renderscript/reference/rs_convert.jd
index d4bf77fa..89fd040 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_convert.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_convert.jd
@@ -4,7 +4,7 @@
 
 <div class='renderscript'>
 <h2>Overview</h2>
-<p> The functions below convert from a numerical vector type to another, of from one color
+<p> The functions below convert from a numerical vector type to another, or from one color
 representation to another.
 </p>
 <h2>Summary</h2>
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 0a96a15..e60ca9f 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -1,484 +1,484 @@
-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 or language on a device, use the Settings application.</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 BCP-47 language tag, for

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

-  </li>

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

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

-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.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>

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

-1.</li>

-</ol>

-

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

-

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

-

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

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

-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 or language on a device, use the Settings application.</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 BCP-47 language tag, for
+example, Canadian French would be <code>fr-CA</code>.<br>
+  </li>
+  <li>Launch an emulator.</li>
+  <li>From a command-line shell on the host computer, run the following
+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.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>
+    </code>Replace bracketed sections with the  appropriate codes from Step
+1.</li>
+</ol>
+
+<p>For instance, to test in Canadian French:</p>
+
+<p><code>setprop persist.sys.locale fr-CA;stop;sleep 5;start </code></p>
+
+<p>This will cause the emulator  to restart. (It will look like a full reboot,
+but it is not.) Once the Home screen appears again, re-launch your application (for
+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/security/index.jd b/docs/html/guide/topics/security/index.jd
new file mode 100644
index 0000000..22fb775
--- /dev/null
+++ b/docs/html/guide/topics/security/index.jd
@@ -0,0 +1,7 @@
+page.title=Security
+page.landing=true
+page.landing.intro=Configure the security of your application.
+
+@jd:body
+<div class="landing-docs">
+</div>
diff --git a/docs/html/guide/topics/security/security-config.jd b/docs/html/guide/topics/security/security-config.jd
new file mode 100644
index 0000000..4cee253
--- /dev/null
+++ b/docs/html/guide/topics/security/security-config.jd
@@ -0,0 +1,539 @@
+page.title=Network Security Config
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+<li><a href="#SupportedFeatures">Features</a></li>
+<li><a href="#Examples">Examples</a>
+    <ol>
+    <li><a href="#TrustingCustomCas">Trusting Custom CAs</a>
+        <ol>
+        <li><a href="#TrustingACustomCa">Trusting a Custom CA</a></li>
+        <li><a href="#LimitingCas">Limiting the Set of Trusted CAs</a></li>
+        <li><a href="#TrustingAdditionalCas">Trusting Additional CAs</a></li>
+        </ol>
+    </li>
+    <li><a href="#TrustingDebugCa">Debugging-only CAs</a></li>
+    <li><a href="#UsesCleartextTraffic">Cleartext Traffic Opt-Out</a></li>
+    <li><a href="#CertificatePinning">Certificate Pinning</a></li>
+    <li><a href="#ConfigInheritance">Configuration Inheritance</a></li>
+    </ol>
+</li>
+<li><a href="#FileFormat">Configuration File Format</a></li>
+</ol>
+</div>
+</div>
+
+<p>The Android Network Security Config lets apps customize their network security settings
+in a safe, declarative configuration file without modifying application code.
+These settings can be configured for specific domains and app-wide.</p>
+
+<h2 id="SupportedFeatures">Features</h2>
+<ul>
+<li><b>Custom trust anchors.</b> Lets an application customize which Certificate Authorities (CA) are trusted
+for its secure connections. For example, trusting particular self-signed certificates or restricting the set of public
+CAs that the app trusts.
+</li>
+<li><b>Debug-only overrides.</b> Lets an application developer safely debug secure connections of their
+application without added risk to the installed base.
+</li>
+<li><b>Cleartext traffic opt-out.</b> Lets an application protect itself from accidental usage of cleartext traffic.</li>
+<li><b>Certificate pinning.</b> An advanced feature that lets an application restrict pin its secure connection
+to particular certificates.</li>
+</ul>
+
+<h2 id="Examples">Examples</h2>
+<h3 id="TrustingCustomCas">Trusting Custom CAs</h3>
+<p>An application may want to trust a custom set of CAs instead of the platform
+default. The most common reasons of this are:
+<ul>
+<li>Connecting to a host with a custom certificate authority(self-signed, issued by an internal corporate CA, etc).</li>
+<li>Limiting the set of CAs to only the CAs you trust instead of every preinstalled CA.</li>
+<li>Trusting additional CAs not included in the system.</li>
+</ul>
+</p>
+<p>By default secure (e.g. TLS, HTTPS) connections from all applications trust the pre-installed system CAs, and
+applications targeting API level 23 (Android M) and below also trust the user-added CA store by default.
+An application can customize its own connections using {@code base-config} (for app-wide customization) or
+{@code domain-config} (for per-domain customization).</p>
+
+<h4 id="TrustingACustomCa">Trusting a Custom CA</h4>
+<p>Assume you want to connect to your host which uses a self-signed SSL certificate or to
+a host whose SSL certificate is issued by a non-public CA which you trust, e.g., your company's internal
+CA.</p>
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/my_ca"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>Add the self-signed or non-public CA certificate, in PEM or DER format, to {@code res/raw/my_ca}.</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+</pre>
+</p>
+<h4 id="LimitingCas">Limiting the Set of Trusted CAs</h4>
+<p>An application that does not want to trust all CAs trusted by system can instead specify its own
+reduced set of CAs to trust. This protects the application from fradulent certificates issued by any
+of the other CAs.</p>
+
+<p>The config to limit the set of trusted CAs is similar to <a href="#TrustingACustomCa">trusting a custom CA</a>
+for a specific domain except that multiple CAs are provided in the resource.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+        &lt;domain includeSubdomains="true"&gt;cdn.example.com&lt;/domain&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/trusted_roots"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>Add the trusted CAs, in PEM or DER format, to {@code res/raw/trusted_roots}.
+Note that if using PEM format the file must contain <em>only</em> PEM data and no extra text.
+You can also provide multiple <a href="certificates"><code>&lt;certificates&gt;</code></a> elements instead
+of one.</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+</pre>
+</p>
+
+<h4 id="TrustingAdditionalCas">Trusting Additional CAs</h4>
+<p>An application may want to trust additional CAs not trusted by the system, this could be due to
+the system not yet including the CA or a CA that does not meet the requirements for inclusion into
+the Android system. An application can do this by specifying multiple certificate sources for a configuration.
+</p>
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;base-config&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/extracas"/&gt;
+            &lt;certificates src="system"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/base-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+</pre>
+</p>
+
+<h3 id="TrustingDebugCa">Debugging-only CAs</h3>
+<p>When debugging an application that connects over HTTPS you may want to connect to a local development
+server, which does not have the SSL certificate for your production server. In order to support this
+without any modification to your application's code you can specify debug-only CAs that are
+<i>only</i> trusted when <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
+is {@code true} by using {@code debug-overrides}. Normally IDEs and build tools set this flag automatically for non-release builds.</p>
+<p>This is safer than the usual conditional code because, as a security precaution, application stores
+do not accept applications which are marked debuggable.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;debug-overrides&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/debug_cas"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/debug-overrides&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+</pre>
+</p>
+
+<h3 id="UsesCleartextTraffic">Cleartext Traffic Opt-Out</h3>
+<p>Applications which intend to connect to destinations using only secure connections can opt-out
+of supporting cleartext (i.e. plain HTTP instead of HTTPS) to those destinations. This helps prevent
+accidental regressions in applications due to changes in URLs provided by external sources such as
+backend servers.</p>
+<p>See {a href="{@docRoot}reference/android/security/NetworkSecurityPolicy.html#isCleartextTrafficPermitted()} for more details.</p>
+
+<p>For example, an application may want to ensure that all connections to {@code secure.example.com} are always
+done over HTTPS to protect sensitive traffic from hostile networks.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config usesCleartextTraffic="false"&gt;
+        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+</pre>
+</p>
+
+<h3 id="CertificatePinning">Certificate Pinning</h3>
+<p>Normally an application trusts all preinstalled CAs. If any of these CAs were to issue a fradulent certificate
+the application would be at risk from a MiTM attack. Some applications choose to limit the set of
+certificates they accept by either limiting the set of CAs they trust or by certificate pinning.</p>
+
+<p>Certificate pinning is done by providing a set of certificates by hash of the public key (SubjectPublicKeyInfo
+of the X.509 certificate). A certificate chain is then only valid if the certificate chain contains at least
+one of the pinned public keys.</p>
+
+<p>Note that when using certificate pinning you should always include a backup key so that if you
+are forced to switch to new keys, or change CAs (when pinning to a CA certificate or an intermediate of that CA), 
+your application's connectivity is unaffected. Otherwise you will have to push out an update to the
+application to restore connectivity.</p>
+
+<p>Additionally it is possible to set an expiration time for pins after which pinning will not be
+performed. This helps prevent connectivity issues in applications which have not been updated.
+However, setting an expiration time on pins may enable pinning bypass.
+</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+        &lt;pin-set expiration="2018-01-01"&gt;
+            &lt;pin digest="SHA-256"&gt;7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=&lt;/pin&gt;
+            &lt;!-- backup pin --&gt
+            &lt;pin digest="SHA-256"&gt;fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=&lt;/pin&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+</pre>
+</p>
+
+<h3 id="ConfigInheritance">Configuration Inheritance</h3>
+<p>Values not set in a specific config will be inherited.
+This allows more complex configurations while keeping the configuration file readable.</p>
+
+<p>If a value is not set in a specific entry then value from the next more general entry will be used.
+Values not set in a {@code domain-config} will be taken from the parent {@code domain-config}, if nested, or
+from the {@code base-config} if not. Values not set in the {@code base-config} will use
+the platform default values.
+
+<p>For example consider, where all connections to subdomains of {@code example.com}
+must use a custom set of CAs. Additonally cleartext traffic to these domains is permitted
+<em>except</em> when connecting to {@code secure.example.com}. By nesting the configuration
+for {@code secure.example.com} inside the configuration for {@code example.com} the
+{@code trust-anchors} does not need to be duplicated.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/my_ca"/&gt;
+        &lt;/trust-anchors&gt;
+        &lt;domain-config cleartextTrafficPermitted="false"&gt;
+            &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+        &lt;/domain-config&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+</pre>
+</p>
+
+<h2 id="FileFormat">Configuration File Format</h2>
+<p>The configuration file is XML. Here is what it can contain:</p>
+</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;base-config&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="..."/&gt;
+            ...
+        &lt;/trust-anchors&gt;
+    &lt;/base-config&gt;
+
+    &lt;domain-config&gt;
+        &lt;domain&gt;android.com&lt;/domain&gt;
+        ...
+        &lt;trust-anchors&gt;
+            &lt;certificates src="..."/&gt;
+            ...
+        &lt;/trust-anchors&gt;
+        &lt;pin-set&gt;
+            &lt;pin digest="..."&gt;...&lt;/pin&gt;
+            ...
+        &lt;/pin-set&gt;
+    &lt;/domain-config&gt;
+    ...
+    &lt;debug-overrides&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="..."/&gt;
+            ...
+        &lt;/trust-anchors&gt;
+    &lt;/debug-overrides&gt;
+&lt;/network-security-config&gt;
+</pre>
+
+<h3 id="network-security-config">&lt;network-security-config&gt;</h3>
+<dl class="xml">
+<dt>can contain:</dt>
+<dd>0 or 1 <code><a href="#base-config">&lt;base-config&gt;</a></code>
+<br/>Any number of <code><a href="#domain-config">&lt;domain-config&gt;</a></code>
+<br/>0 or 1<code><a href="#debug-overrides">&lt;debug-overrides&gt;</a></code>
+</dd>
+</dl>
+
+
+<h3 id="base-config">&lt;base-config&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;base-config <a href="#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
+    ...
+&lt;/base-config&gt;</pre></dd>
+<dt>can contain:</dt>
+<dd><code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code></dd>
+<dt>descrption:</dt>
+<dd>
+The default configuration used by all connections whose destination is not covered by a
+<a href="#domain-config"><code>domain-config</code></a>.
+
+<p>Any values that are not set will use the platform default values.
+The default configuration for applications targeting above API level 24 and above:
+<pre>
+&lt;base-config usesCleartextTraffic="true"&gt;
+    &lt;trust-anchors&gt;
+        &lt;certificates src="system" /&gt;
+    &lt;/trust-anchors&gt;
+&lt;/base-config&gt;
+</pre>
+The default configuration for applications targeting API level 23 and below is:
+<pre>
+&lt;base-config usesCleartextTraffic="true"&gt;
+    &lt;trust-anchors&gt;
+        &lt;certificates src="system" /&gt;
+        &lt;certificates src="user" /&gt;
+    &lt;/trust-anchors&gt;
+&lt;/base-config&gt;
+</pre>
+</p>
+</dd>
+</dl>
+
+<h3 id="domain-config">&lt;domain-config&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;domain-config <a href="#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
+    ...
+&lt;/domain-config&gt;</pre></dd>
+<dt>Can Contain:</dt>
+
+<dd>
+1 or more <code><a href="#domain">&lt;domain&gt;</a></code>
+<br/>0 or 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
+<br/>0 or 1 <code><a href="#pin-set">&lt;pin-set&gt;</code></a>
+<br/>Any number of nested <code>&lt;domain-config&gt;</code></dd>
+
+<dt>Descrption</dt>
+<dd>Configuration used for connections to specific destinations as the defined by {@code domain} elements.
+
+<p>Note that if multiple {@code domain-config} elements cover a destination the config with the most specific (longest)
+matching domain rule will be used.</p></dd>
+</dl>
+
+<h3 id="domain">&lt;domain&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;domain includeSubdomains=["true" | "false"]&gt;example.com&lt;/domain&gt;</pre></dd>
+<dt>Attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code includeSubdomains}</dt>
+<dd>If {@code "true"} then this domain rule will match the domain and all subdomains, including
+subdomains of subdomains, otherwise the rule only applies to exact matches.</dd>
+</dl>
+</dd>
+
+<dt>Descrption:</dt>
+</dl>
+
+<h3 id="debug-overrides">&lt;debug-overrides&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;debug-overrides&gt;
+    ...
+&lt;/debug-overrides&gt;</pre></dd>
+<dt>Can Contain:</dt>
+<dd>0 or 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code></dd>
+<dt>Description:</dt>
+<dd>Overrides to be applied when
+<a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a> is
+{@code "true"} which is normally the case for non-release builds generated by IDEs and build tools.
+Trust anchors specified in {@code debug-overrides} are added to all other configurations and certificate
+pinning is not performed when the server's certificate chain uses one of these debug-only trust anchors.
+If <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a> is
+{@code "false"} then this section is completely ignored.
+</dd>
+</dl>
+
+<h3 id="trust-anchors">&lt;trust-anchors&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">&lt;trust-anchors&gt;
+...
+&lt;/trust-anchors&gt;
+</pre></dd>
+<dt>Can Contain:</dt>
+<dd>Any number of <code><a href="#certificates">&lt;certificates&gt;</a></code></dd>
+<dt>Description:</dt>
+<dd>Set of trust anchors for secure connections.</dd>
+</dl>
+
+
+<h3 id="certificates">&lt;certificates&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;certificates src=["system" | "user" | "<i>raw resource</i>"]
+              overridePins=["true" | "false"] /&gt;
+</pre></dd>
+<dt>description:</dt>
+<dd>Set of X.509 certificates for {@code trust-anchors} elements.</dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code src}</dt>
+<dd>
+The source of CA certificates, can be one of
+<ul>
+    <li>a raw resource id pointing to a file containing X.509 certificates. Certificates must be encoded in DER or PEM format.
+        In the case of PEM certificates the file <em>must not</em> contain extra non-PEM data such as comments.</li>
+    <li>{@code "system"} for the pre-installed system CA certificates</li>
+    <li>{@code "user"} for user-added CA certificates</li>
+</ul>
+</dd>
+
+<dt>{@code overridePins}</dt>
+<dd>
+Specifies if the CAs from this source bypass certificate pinning. If {@code "true"} then certificate chains which
+chain through one of the CAs from this source then pinning will not be performed. This can be useful
+for debug CAs or to support letting the user MiTM your app's secure traffic.
+<p>
+Default is {@code "false"} unless specified in a {@code debug-overrides} element, in which case the default is {@code "true"}.
+</p>
+</dd>
+</dl>
+</dd>
+
+<h3 id="pin-set">&lt;pin-set&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">&lt;pin-set expiration="date"&gt;
+...
+&lt;/pin-set&gt;
+</pre></dd>
+<dt>Can Contain:</dt>
+<dd>Any number of <code><a href="#pin">&lt;pin&gt;</a></code></dd>
+<dt>Description:</dt>
+<dd>A set of public key pins. For a secure connection to be trusted, one of the public keys in the chain of trust must
+be in the set of pins. See <code><a href="#pin">&lt;pin&gt;</a></code> for the format of pins.</dd>
+<dt>Attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code expiration}</dt>
+<dd>The date, in {@code yyyy-MM-dd} format, at and after which the pins expire, thus disabling pinning.
+If the attribute is not set then the pins do not expire.
+<p>Expiration helps prevent connectivity issues in applications which do not get updates to their
+pin set, for example because the user disabled application updates.</p>
+</dd>
+</dl>
+</dd>
+
+<h3 id="pin">&lt;pin&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">&lt;pin digest=["SHA-256"]&gt;base64 encoded digest of X.509 SubjectPublicKeyInfo (SPKI)&lt;/pin&gt</pre></dd>
+<dt>Attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code digest}</dt>
+<dd>The digest algorithm used to generate the pin. Currently only {@code "SHA-256"} is supported.</dd>
+</dl>
+</dd>
+</dl>
diff --git a/docs/html/guide/topics/sensors/sensors_overview.jd b/docs/html/guide/topics/sensors/sensors_overview.jd
index 0b3cb2b..53faca0 100644
--- a/docs/html/guide/topics/sensors/sensors_overview.jd
+++ b/docs/html/guide/topics/sensors/sensors_overview.jd
@@ -465,6 +465,7 @@
 ...
 
 mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+mSensor = null;
 
 if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
   List&lt;Sensor&gt; gravSensors = mSensorManager.getSensorList(Sensor.TYPE_GRAVITY);
@@ -476,7 +477,7 @@
     }
   }
 }
-else{
+if (mSensor == null){
   // Use the accelerometer.
   if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
     mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index cab4163..264e741 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -393,7 +393,7 @@
     only affects notifications generated by applications in the managed profile.</li>
     </ul>
   </li>
-  <li>The {@link android.app.admin.DevicePolicyManager#createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle) createAndInitializeUser()} and {@link android.app.admin.DevicePolicyManager#createUser(android.content.ComponentName, java.lang.String) createUser()} methods have been deprecated.</li>
+  <li>The {@link android.app.admin.DevicePolicyManager#createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int) createAndManageUser()} method replaces createAndInitializeUser(), which has been removed.</li>
   <li>The {@link android.app.admin.DevicePolicyManager#setScreenCaptureDisabled(android.content.ComponentName, boolean) setScreenCaptureDisabled()}
 method now also blocks the assist structure when an app of the given user is in the foreground. </li>
   <li>{@link android.app.admin.DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
index 49a9169..58a1d5f 100644
--- a/docs/html/training/basics/data-storage/files.jd
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -59,7 +59,7 @@
 <p><b>Internal storage:</b></p>
 <ul>
 <li>It's always available.</li>
-<li>Files saved here are accessible by only your app by default.</li>
+<li>Files saved here are accessible by only your app.</li>
 <li>When the user uninstalls your app, the system removes all your app's files from
 internal storage.</li>
 </ul>
@@ -83,6 +83,12 @@
 with other apps or allow the user to access with a computer.</p>
 </div>
 
+<p class="note">
+<strong>Note:</strong> Before Android N, internal files could be made accessible to other
+apps by means of relaxing file system permissions. This is no longer the case. If you wish
+to make the content of a private file accessible to other apps, your app may use the
+{@link android.support.v4.content.FileProvider}. See <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.</p>
 
 <p class="note" style="clear:both">
 <strong>Tip:</strong> Although apps are installed onto the internal storage by
diff --git a/docs/overview-ext.html b/docs/overview-ext.html
index 5720245..f80d629 100644
--- a/docs/overview-ext.html
+++ b/docs/overview-ext.html
@@ -1,8 +1,8 @@
-<body>

-Some random libraries that we've imported:

-<ul>

-    <li>GData</li>

-    <li>Apache commons HTTPClient</li>

-    <li>A sax parser</li>

-</ul>

-</body>

+<body>
+Some random libraries that we've imported:
+<ul>
+    <li>GData</li>
+    <li>Apache commons HTTPClient</li>
+    <li>A sax parser</li>
+</ul>
+</body>
diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java
index 48ee6fa..683c157 100644
--- a/graphics/java/android/graphics/AvoidXfermode.java
+++ b/graphics/java/android/graphics/AvoidXfermode.java
@@ -19,6 +19,8 @@
 /**
  * AvoidXfermode xfermode will draw the src everywhere except on top of the
  * opColor or, depending on the Mode, draw only on top of the opColor.
+ *
+ * @removed
  */
 @Deprecated
 public class AvoidXfermode extends Xfermode {
@@ -53,9 +55,5 @@
         if (tolerance < 0 || tolerance > 255) {
             throw new IllegalArgumentException("tolerance must be 0..255");
         }
-        native_instance = nativeCreate(opColor, tolerance, mode.nativeInt);
     }
-
-    private static native long nativeCreate(int opColor, int tolerance,
-                                            int nativeMode);
 }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d4f745d..af99f79 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -91,8 +91,11 @@
     // a Canvas object.
     private static final long NATIVE_ALLOCATION_SIZE = 525;
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-        getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+    // Use a Holder to allow static initialization of Canvas in the boot image.
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+    }
 
     // This field is used to finalize the native Canvas properly
     private Runnable mFinalizer;
@@ -107,7 +110,8 @@
         if (!isHardwareAccelerated()) {
             // 0 means no native bitmap
             mNativeCanvasWrapper = initRaster(null);
-            mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+            mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                    this, mNativeCanvasWrapper);
         } else {
             mFinalizer = null;
         }
@@ -128,7 +132,8 @@
         }
         throwIfCannotDraw(bitmap);
         mNativeCanvasWrapper = initRaster(bitmap);
-        mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+        mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                this, mNativeCanvasWrapper);
         mBitmap = bitmap;
         mDensity = bitmap.mDensity;
     }
@@ -139,7 +144,8 @@
             throw new IllegalStateException();
         }
         mNativeCanvasWrapper = nativeCanvas;
-        mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+        mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                this, mNativeCanvasWrapper);
         mDensity = Bitmap.getDefaultDensity();
     }
 
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 8f7c6a62..7871aa8 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -179,10 +179,10 @@
         int tag = 0;
         String tagStr = parser.getAttributeValue(null, "tag");
         if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
-            tag = tagStr.charAt(0) << 24 +
-                  tagStr.charAt(1) << 16 +
-                  tagStr.charAt(2) <<  8 +
-                  tagStr.charAt(3);
+            tag = (tagStr.charAt(0) << 24) +
+                  (tagStr.charAt(1) << 16) +
+                  (tagStr.charAt(2) <<  8) +
+                  (tagStr.charAt(3)      );
         } else {
             throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
         }
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 5efc00c..b6a209f 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -45,15 +45,11 @@
                 int outlineLeft, int outlineTop, int outlineRight, int outlineBottom,
                 float outlineRadius, int outlineAlpha, float decodeScale) {
             opticalRect = new Rect(opticalLeft, opticalTop, opticalRight, opticalBottom);
-            outlineRect = new Rect(outlineLeft, outlineTop, outlineRight, outlineBottom);
+            opticalRect.scale(decodeScale);
 
-            if (decodeScale != 1.0f) {
-                // if bitmap was scaled when decoded, scale the insets from the metadata values
-                opticalRect.scale(decodeScale);
+            outlineRect = scaleInsets(outlineLeft, outlineTop,
+                    outlineRight, outlineBottom, decodeScale);
 
-                // round inward while scaling outline, as the outline should always be conservative
-                outlineRect.scaleRoundIn(decodeScale);
-            }
             this.outlineRadius = outlineRadius * decodeScale;
             this.outlineAlpha = outlineAlpha / 255.0f;
         }
@@ -62,6 +58,23 @@
         public final Rect outlineRect;
         public final float outlineRadius;
         public final float outlineAlpha;
+
+        /**
+         * Scales up the rect by the given scale, ceiling values, so actual outline Rect
+         * grows toward the inside.
+         */
+        public static Rect scaleInsets(int left, int top, int right, int bottom, float scale) {
+            if (scale == 1.0f) {
+                return new Rect(left, top, right, bottom);
+            }
+
+            Rect result = new Rect();
+            result.left = (int) Math.ceil(left * scale);
+            result.top = (int) Math.ceil(top * scale);
+            result.right = (int) Math.ceil(right * scale);
+            result.bottom = (int) Math.ceil(bottom * scale);
+            return  result;
+        }
     }
 
     private final Bitmap mBitmap;
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index aa40408..aa81b91 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -17,9 +17,13 @@
 package android.graphics;
 
 import android.annotation.FloatRange;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.graphics.drawable.Drawable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Defines a simple shape, used for bounding graphical regions.
  * <p>
@@ -31,13 +35,36 @@
  * @see Drawable#getOutline(Outline)
  */
 public final class Outline {
-    /** @hide */
-    public Path mPath;
+    private static final float RADIUS_UNDEFINED = Float.NEGATIVE_INFINITY;
 
     /** @hide */
-    public Rect mRect;
+    public static final int MODE_EMPTY = 0;
     /** @hide */
-    public float mRadius;
+    public static final int MODE_ROUND_RECT = 1;
+    /** @hide */
+    public static final int MODE_CONVEX_PATH = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false,
+            value = {
+                    MODE_EMPTY,
+                    MODE_ROUND_RECT,
+                    MODE_CONVEX_PATH,
+            })
+    public @interface Mode {}
+
+    /** @hide */
+    @Mode
+    public int mMode = MODE_EMPTY;
+
+    /** @hide */
+    public final Path mPath = new Path();
+
+    /** @hide */
+    public final Rect mRect = new Rect();
+    /** @hide */
+    public float mRadius = RADIUS_UNDEFINED;
     /** @hide */
     public float mAlpha;
 
@@ -60,9 +87,10 @@
      * @see #isEmpty()
      */
     public void setEmpty() {
-        mPath = null;
-        mRect = null;
-        mRadius = 0;
+        mMode = MODE_EMPTY;
+        mPath.rewind();
+        mRect.setEmpty();
+        mRadius = RADIUS_UNDEFINED;
     }
 
     /**
@@ -74,7 +102,7 @@
      * @see #setEmpty()
      */
     public boolean isEmpty() {
-        return mRect == null && mPath == null;
+        return mMode == MODE_EMPTY;
     }
 
 
@@ -87,7 +115,7 @@
      * @see {@link android.view.View#setClipToOutline(boolean)}
      */
     public boolean canClip() {
-        return !isEmpty() && mRect != null;
+        return mMode != MODE_CONVEX_PATH;
     }
 
     /**
@@ -119,19 +147,9 @@
      * @param src Source outline to copy from.
      */
     public void set(@NonNull Outline src) {
-        if (src.mPath != null) {
-            if (mPath == null) {
-                mPath = new Path();
-            }
-            mPath.set(src.mPath);
-            mRect = null;
-        }
-        if (src.mRect != null) {
-            if (mRect == null) {
-                mRect = new Rect();
-            }
-            mRect.set(src.mRect);
-        }
+        mMode = src.mMode;
+        mPath.set(src.mPath);
+        mRect.set(src.mRect);
         mRadius = src.mRadius;
         mAlpha = src.mAlpha;
     }
@@ -162,10 +180,10 @@
             return;
         }
 
-        if (mRect == null) mRect = new Rect();
+        mMode = MODE_ROUND_RECT;
         mRect.set(left, top, right, bottom);
         mRadius = radius;
-        mPath = null;
+        mPath.rewind();
     }
 
     /**
@@ -176,6 +194,34 @@
     }
 
     /**
+     * Populates {@code outBounds} with the outline bounds, if set, and returns
+     * {@code true}. If no outline bounds are set, or if a path has been set
+     * via {@link #setConvexPath(Path)}, returns {@code false}.
+     *
+     * @param outRect the rect to populate with the outline bounds, if set
+     * @return {@code true} if {@code outBounds} was populated with outline
+     *         bounds, or {@code false} if no outline bounds are set
+     */
+    public boolean getRect(@NonNull Rect outRect) {
+        if (mMode != MODE_ROUND_RECT) {
+            return false;
+        }
+        outRect.set(mRect);
+        return true;
+    }
+
+    /**
+     * Returns the rounded rect radius, if set, or a value less than 0 if a path has
+     * been set via {@link #setConvexPath(Path)}. A return value of {@code 0}
+     * indicates a non-rounded rect.
+     *
+     * @return the rounded rect radius, or value < 0
+     */
+    public float getRadius() {
+        return mRadius;
+    }
+
+    /**
      * Sets the outline to the oval defined by input rect.
      */
     public void setOval(int left, int top, int right, int bottom) {
@@ -190,10 +236,11 @@
             return;
         }
 
-        if (mPath == null) mPath = new Path();
-        mPath.reset();
+        mMode = MODE_CONVEX_PATH;
+        mPath.rewind();
         mPath.addOval(left, top, right, bottom, Path.Direction.CW);
-        mRect = null;
+        mRect.setEmpty();
+        mRadius = RADIUS_UNDEFINED;
     }
 
     /**
@@ -216,20 +263,20 @@
         if (!convexPath.isConvex()) {
             throw new IllegalArgumentException("path must be convex");
         }
-        if (mPath == null) mPath = new Path();
 
+        mMode = MODE_CONVEX_PATH;
         mPath.set(convexPath);
-        mRect = null;
-        mRadius = -1.0f;
+        mRect.setEmpty();
+        mRadius = RADIUS_UNDEFINED;
     }
 
     /**
      * Offsets the Outline by (dx,dy)
      */
     public void offset(int dx, int dy) {
-        if (mRect != null) {
+        if (mMode == MODE_ROUND_RECT) {
             mRect.offset(dx, dy);
-        } else if (mPath != null) {
+        } else if (mMode == MODE_CONVEX_PATH) {
             mPath.offset(dx, dy);
         }
     }
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 534121a..0dae796 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -44,8 +44,11 @@
     // The approximate size of a native paint object.
     private static final long NATIVE_PAINT_SIZE = 98;
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-        nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
+    // Use a Holder to allow static initialization of Paint in the boot image.
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
+    }
 
     /**
      * @hide
@@ -452,7 +455,7 @@
      */
     public Paint(int flags) {
         mNativePaint = nInit();
-        sRegistry.registerNativeAllocation(this, mNativePaint);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
         setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS);
         // TODO: Turning off hinting has undesirable side effects, we need to
         //       revisit hinting once we add support for subpixel positioning
@@ -471,7 +474,7 @@
      */
     public Paint(Paint paint) {
         mNativePaint = nInitWithPaint(paint.getNativeInstance());
-        sRegistry.registerNativeAllocation(this, mNativePaint);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
         setClassVariablesFrom(paint);
     }
 
@@ -1491,9 +1494,14 @@
     }
 
     /**
-     * Get font feature settings.  Default is null.
+     * Returns the font feature settings. The format is the same as the CSS
+     * font-feature-settings attribute:
+     * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+     *     http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
      *
-     * @return the paint's currently set font feature settings.
+     * @return the paint's currently set font feature settings. Default is null.
+     *
+     * @see #setFontFeatureSettings(String)
      */
     public String getFontFeatureSettings() {
         return mFontFeatureSettings;
@@ -1503,7 +1511,10 @@
      * Set font feature settings.
      *
      * The format is the same as the CSS font-feature-settings attribute:
-     * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
+     * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+     *     http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
+     *
+     * @see #getFontFeatureSettings()
      *
      * @param settings the font feature settings string to use, may be null.
      */
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index da3deff..de391af 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -16,6 +16,9 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 /**
  * The Path class encapsulates compound (multiple contour) geometric paths
  * consisting of straight line segments, quadratic curves, and cubic curves.
@@ -91,10 +94,22 @@
 
     /** Replace the contents of this with the contents of src.
     */
-    public void set(Path src) {
-        if (this != src) {
-            isSimplePath = src.isSimplePath;
-            native_set(mNativePath, src.mNativePath);
+    public void set(@NonNull Path src) {
+        if (this == src) {
+            return;
+        }
+        isSimplePath = src.isSimplePath;
+        native_set(mNativePath, src.mNativePath);
+        if (!isSimplePath) {
+            return;
+        }
+
+        if (rects != null && src.rects != null) {
+            rects.set(src.rects);
+        } else if (rects != null && src.rects == null) {
+            rects.setEmpty();
+        } else if (src.rects != null) {
+            rects = new Region(src.rects);
         }
     }
 
@@ -685,13 +700,13 @@
      * @param dst The translated path is written here. If this is null, then
      *            the original path is modified.
      */
-    public void offset(float dx, float dy, Path dst) {
-        long dstNative = 0;
+    public void offset(float dx, float dy, @Nullable Path dst) {
         if (dst != null) {
-            dstNative = dst.mNativePath;
-            dst.isSimplePath = false;
+            dst.set(this);
+        } else {
+            dst = this;
         }
-        native_offset(mNativePath, dx, dy, dstNative);
+        dst.offset(dx, dy);
     }
 
     /**
@@ -701,7 +716,15 @@
      * @param dy The amount in the Y direction to offset the entire path
      */
     public void offset(float dx, float dy) {
-        isSimplePath = false;
+        if (isSimplePath && rects == null) {
+            // nothing to offset
+            return;
+        }
+        if (isSimplePath && dx == Math.rint(dx) && dy == Math.rint(dy)) {
+            rects.translate((int) dx, (int) dy);
+        } else {
+            isSimplePath = false;
+        }
         native_offset(mNativePath, dx, dy);
     }
 
@@ -823,7 +846,6 @@
     private static native void native_addPath(long nPath, long src, float dx, float dy);
     private static native void native_addPath(long nPath, long src);
     private static native void native_addPath(long nPath, long src, long matrix);
-    private static native void native_offset(long nPath, float dx, float dy, long dst_path);
     private static native void native_offset(long nPath, float dx, float dy);
     private static native void native_setLastPoint(long nPath, float dx, float dy);
     private static native void native_transform(long nPath, long matrix, long dst_path);
diff --git a/graphics/java/android/graphics/PathMeasure.java b/graphics/java/android/graphics/PathMeasure.java
index 0416159..2848949 100644
--- a/graphics/java/android/graphics/PathMeasure.java
+++ b/graphics/java/android/graphics/PathMeasure.java
@@ -112,7 +112,7 @@
      * Given a start and stop distance, return in dst the intervening
      * segment(s). If the segment is zero-length, return false, else return
      * true. startD and stopD are pinned to legal values (0..getLength()).
-     * If startD <= stopD then return false (and leave dst untouched).
+     * If startD >= stopD then return false (and leave dst untouched).
      * Begin the segment with a moveTo if startWithMoveTo is true.
      *
      * <p>On {@link android.os.Build.VERSION_CODES#KITKAT} and earlier
@@ -121,6 +121,19 @@
      * such as <code>dst.rLineTo(0, 0)</code>.</p>
      */
     public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) {
+        // Skia used to enforce this as part of it's API, but has since relaxed that restriction
+        // so to maintain consistency in our API we enforce the preconditions here.
+        float length = getLength();
+        if (startD < 0) {
+            startD = 0;
+        }
+        if (stopD > length) {
+            stopD = length;
+        }
+        if (startD >= stopD) {
+            return false;
+        }
+
         dst.isSimplePath = false;
         return native_getSegment(native_instance, startD, stopD, dst.ni(), startWithMoveTo);
     }
diff --git a/graphics/java/android/graphics/PixelXorXfermode.java b/graphics/java/android/graphics/PixelXorXfermode.java
index 0080e65..27884e0 100644
--- a/graphics/java/android/graphics/PixelXorXfermode.java
+++ b/graphics/java/android/graphics/PixelXorXfermode.java
@@ -17,17 +17,11 @@
 package android.graphics;
 
 /**
- * PixelXorXfermode implements a simple pixel xor (op ^ src ^ dst).
- * This transformation does not follow premultiplied conventions, therefore
- * this mode *always* returns an opaque color (alpha == 255). Thus it is
- * not really usefull for operating on blended colors.
+ * @removed
  */
 @Deprecated
 public class PixelXorXfermode extends Xfermode {
 
     public PixelXorXfermode(int opColor) {
-        native_instance = nativeCreate(opColor);
     }
-
-    private static native long nativeCreate(int opColor);
 }
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 0cde0b9..7f579a2 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -30,6 +30,11 @@
  * These fields can be accessed directly. Use width() and height() to retrieve
  * the rectangle's width and height. Note: most methods do not check to see that
  * the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
+ * <p>
+ * Note that the right and bottom coordinates are exclusive. This means a Rect
+ * being drawn untransformed onto a {@link android.graphics.Canvas} will draw
+ * into the column and row described by its left and top coordinates, but not
+ * those of its bottom and right.
  */
 public final class Rect implements Parcelable {
     public int left;
@@ -642,16 +647,4 @@
         }
     }
 
-    /**
-     * Scales up the rect by the given scale, rounding values toward the inside.
-     * @hide
-     */
-    public void scaleRoundIn(float scale) {
-        if (scale != 1.0f) {
-            left = (int) Math.ceil(left * scale);
-            top = (int) Math.ceil(top * scale);
-            right = (int) Math.floor(right * scale);
-            bottom = (int) Math.floor(bottom * scale);
-        }
-    }
 }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index c486c1f..35385eb 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -27,6 +27,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityThread;
 import android.app.Application;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -35,11 +36,13 @@
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.Outline;
+import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.os.Build;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.LongArray;
 import android.util.PathParser;
@@ -154,7 +157,7 @@
     private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
 
     /** Local, mutable animator set. */
-    private final VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimator(this);
+    private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorUI(this);
 
     /**
      * The resources against which this drawable was created. Used to attempt
@@ -164,8 +167,8 @@
 
     private AnimatedVectorDrawableState mAnimatedVectorState;
 
-    /** Whether the animator set has been prepared. */
-    private boolean mHasAnimatorSet;
+    /** The animator set that is parsed from the xml. */
+    private AnimatorSet mAnimatorSetFromXml = null;
 
     private boolean mMutated;
 
@@ -228,15 +231,13 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mAnimatedVectorState.getChangingConfigurations();
     }
 
     @Override
     public void draw(Canvas canvas) {
-        if (canvas.isHardwareAccelerated()) {
-            mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas);
-        }
+        mAnimatorSet.onDraw(canvas);
         mAnimatedVectorState.mVectorDrawable.draw(canvas);
     }
 
@@ -260,6 +261,13 @@
         return mAnimatedVectorState.mVectorDrawable.setLayoutDirection(layoutDirection);
     }
 
+    /**
+     * AnimatedVectorDrawable is running on render thread now. Therefore, if the root alpha is being
+     * animated, then the root alpha value we get from this call could be out of sync with alpha
+     * value used in the render thread. Otherwise, the root alpha should be always the same value.
+     *
+     * @return the containing vector drawable's root alpha value.
+     */
     @Override
     public int getAlpha() {
         return mAnimatedVectorState.mVectorDrawable.getAlpha();
@@ -276,6 +284,11 @@
     }
 
     @Override
+    public ColorFilter getColorFilter() {
+        return mAnimatedVectorState.mVectorDrawable.getColorFilter();
+    }
+
+    @Override
     public void setTintList(ColorStateList tint) {
         mAnimatedVectorState.mVectorDrawable.setTintList(tint);
     }
@@ -308,7 +321,7 @@
 
     @Override
     public int getOpacity() {
-        return mAnimatedVectorState.mVectorDrawable.getOpacity();
+        return PixelFormat.TRANSLUCENT;
     }
 
     @Override
@@ -392,6 +405,24 @@
         mRes = state.mPendingAnims == null ? null : res;
     }
 
+    /**
+     * Force to animate on UI thread.
+     * @hide
+     */
+    public void forceAnimationOnUI() {
+        if (mAnimatorSet instanceof VectorDrawableAnimatorRT) {
+            VectorDrawableAnimatorRT animator = (VectorDrawableAnimatorRT) mAnimatorSet;
+            if (animator.isRunning()) {
+                throw new UnsupportedOperationException("Cannot force Animated Vector Drawable to" +
+                        " run on UI thread when the animation has started on RenderThread.");
+            }
+            mAnimatorSet = new VectorDrawableAnimatorUI(this);
+            if (mAnimatorSetFromXml != null) {
+                mAnimatorSet.init(mAnimatorSetFromXml);
+            }
+        }
+    }
+
     @Override
     public boolean canApplyTheme() {
         return (mAnimatedVectorState != null && mAnimatedVectorState.canApplyTheme())
@@ -419,7 +450,7 @@
     }
 
     private static class AnimatedVectorDrawableState extends ConstantState {
-        int mChangingConfigurations;
+        @Config int mChangingConfigurations;
         VectorDrawable mVectorDrawable;
 
         /** Animators that require a theme before inflation. */
@@ -483,7 +514,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations;
         }
 
@@ -612,30 +643,48 @@
      * Resets the AnimatedVectorDrawable to the start state as specified in the animators.
      */
     public void reset() {
+        ensureAnimatorSet();
+        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+            Log.w(LOGTAG, "calling reset on AVD: " +
+                    ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                    getConstantState()).mVectorDrawable.getConstantState()).mRootName
+                    + ", at: " + this);
+        }
         mAnimatorSet.reset();
     }
 
     @Override
     public void start() {
         ensureAnimatorSet();
+        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+            Log.w(LOGTAG, "calling start on AVD: " +
+                    ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                    getConstantState()).mVectorDrawable.getConstantState()).mRootName
+                    + ", at: " + this);
+        }
         mAnimatorSet.start();
     }
 
     @NonNull
     private void ensureAnimatorSet() {
-        if (!mHasAnimatorSet) {
+        if (mAnimatorSetFromXml == null) {
             // TODO: Skip the AnimatorSet creation and init the VectorDrawableAnimator directly
             // with a list of LocalAnimators.
-            AnimatorSet set = new AnimatorSet();
-            mAnimatedVectorState.prepareLocalAnimators(set, mRes);
-            mHasAnimatorSet = true;
-            mAnimatorSet.initWithAnimatorSet(set);
+            mAnimatorSetFromXml = new AnimatorSet();
+            mAnimatedVectorState.prepareLocalAnimators(mAnimatorSetFromXml, mRes);
+            mAnimatorSet.init(mAnimatorSetFromXml);
             mRes = null;
         }
     }
 
     @Override
     public void stop() {
+        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+            Log.w(LOGTAG, "calling stop on AVD: " +
+                    ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                            getConstantState()).mVectorDrawable.getConstantState())
+                            .mRootName + ", at: " + this);
+        }
         mAnimatorSet.end();
     }
 
@@ -667,17 +716,17 @@
 
     private final Callback mCallback = new Callback() {
         @Override
-        public void invalidateDrawable(Drawable who) {
+        public void invalidateDrawable(@NonNull Drawable who) {
             invalidateSelf();
         }
 
         @Override
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
+        public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
             scheduleSelf(what, when);
         }
 
         @Override
-        public void unscheduleDrawable(Drawable who, Runnable what) {
+        public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
             unscheduleSelf(what);
         }
     };
@@ -724,7 +773,7 @@
     // A helper function to clean up the animator listener in the mAnimatorSet.
     private void removeAnimatorSetListener() {
         if (mAnimatorListener != null) {
-            mAnimatorSet.removeListener();
+            mAnimatorSet.removeListener(mAnimatorListener);
             mAnimatorListener = null;
         }
     }
@@ -754,13 +803,150 @@
         mAnimationCallbacks.clear();
     }
 
+    private interface VectorDrawableAnimator {
+        void init(@NonNull AnimatorSet set);
+        void start();
+        void end();
+        void reset();
+        void reverse();
+        boolean canReverse();
+        void setListener(AnimatorListener listener);
+        void removeListener(AnimatorListener listener);
+        void onDraw(Canvas canvas);
+        boolean isStarted();
+        boolean isRunning();
+    }
+
+    private static class VectorDrawableAnimatorUI implements VectorDrawableAnimator {
+        // mSet is only initialized in init(). So we need to check whether it is null before any
+        // operation.
+        private AnimatorSet mSet = null;
+        private final Drawable mDrawable;
+        // Caching the listener in the case when listener operation is called before the mSet is
+        // setup by init().
+        private ArrayList<AnimatorListener> mListenerArray = null;
+
+        VectorDrawableAnimatorUI(@NonNull AnimatedVectorDrawable drawable) {
+            mDrawable = drawable;
+        }
+
+        @Override
+        public void init(@NonNull AnimatorSet set) {
+            if (mSet != null) {
+                // Already initialized
+                throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
+                        "re-initialized");
+            }
+            // Keep a deep copy of the set, such that set can be still be constantly representing
+            // the static content from XML file.
+            mSet = set.clone();
+
+            // If there are listeners added before calling init(), now they should be setup.
+            if (mListenerArray != null && !mListenerArray.isEmpty()) {
+                for (int i = 0; i < mListenerArray.size(); i++) {
+                    mSet.addListener(mListenerArray.get(i));
+                }
+                mListenerArray.clear();
+                mListenerArray = null;
+            }
+        }
+
+        // Although start(), reset() and reverse() should call init() already, it is better to
+        // protect these functions from NPE in any situation.
+        @Override
+        public void start() {
+            if (mSet == null || mSet.isStarted()) {
+                return;
+            }
+            mSet.start();
+            invalidateOwningView();
+        }
+
+        @Override
+        public void end() {
+            if (mSet == null) {
+                return;
+            }
+            mSet.end();
+        }
+
+        @Override
+        public void reset() {
+            if (mSet == null) {
+                return;
+            }
+            start();
+            mSet.cancel();
+        }
+
+        @Override
+        public void reverse() {
+            if (mSet == null) {
+                return;
+            }
+            mSet.reverse();
+            invalidateOwningView();
+        }
+
+        @Override
+        public boolean canReverse() {
+            return mSet != null && mSet.canReverse();
+        }
+
+        @Override
+        public void setListener(AnimatorListener listener) {
+            if (mSet == null) {
+                if (mListenerArray == null) {
+                    mListenerArray = new ArrayList<AnimatorListener>();
+                }
+                mListenerArray.add(listener);
+            } else {
+                mSet.addListener(listener);
+            }
+        }
+
+        @Override
+        public void removeListener(AnimatorListener listener) {
+            if (mSet == null) {
+                if (mListenerArray == null) {
+                    return;
+                }
+                mListenerArray.remove(listener);
+            } else {
+                mSet.removeListener(listener);
+            }
+        }
+
+        @Override
+        public void onDraw(Canvas canvas) {
+            if (mSet != null && mSet.isStarted()) {
+                invalidateOwningView();
+            }
+        }
+
+        @Override
+        public boolean isStarted() {
+            return mSet != null && mSet.isStarted();
+        }
+
+        @Override
+        public boolean isRunning() {
+            return mSet != null && mSet.isRunning();
+        }
+
+        private void invalidateOwningView() {
+            mDrawable.invalidateSelf();
+        }
+    }
+
     /**
      * @hide
      */
-    public static class VectorDrawableAnimator {
-        private static final int NONE = 0;
+    public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator {
         private static final int START_ANIMATION = 1;
         private static final int REVERSE_ANIMATION = 2;
+        private static final int RESET_ANIMATION = 3;
+        private static final int END_ANIMATION = 4;
         private AnimatorListener mListener = null;
         private final LongArray mStartDelays = new LongArray();
         private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -776,10 +962,10 @@
         private final VirtualRefBasePtr mSetRefBasePtr;
         private WeakReference<RenderNode> mLastSeenTarget = null;
         private int mLastListenerId = 0;
-        private int mPendingAnimationAction = NONE;
+        private final IntArray mPendingAnimationActions = new IntArray();
         private final Drawable mDrawable;
 
-        VectorDrawableAnimator(AnimatedVectorDrawable drawable) {
+        VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
             mDrawable = drawable;
             mSetPtr = nCreateAnimatorSet();
             // Increment ref count on native AnimatorSet, so it doesn't get released before Java
@@ -787,7 +973,8 @@
             mSetRefBasePtr = new VirtualRefBasePtr(mSetPtr);
         }
 
-        private void initWithAnimatorSet(AnimatorSet set) {
+        @Override
+        public void init(@NonNull AnimatorSet set) {
             if (mInitialized) {
                 // Already initialized
                 throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
@@ -816,7 +1003,7 @@
             ArrayList<Animator> animators = set.getChildAnimations();
 
             boolean playTogether = set.shouldPlayTogether();
-            // Convert AnimatorSet to VectorDrawableAnimator
+            // Convert AnimatorSet to VectorDrawableAnimatorRT
             for (int i = 0; i < animators.size(); i++) {
                 Animator animator = animators.get(i);
                 // Here we only support ObjectAnimator
@@ -1032,16 +1219,29 @@
         protected void recordLastSeenTarget(DisplayListCanvas canvas) {
             mLastSeenTarget = new WeakReference<RenderNode>(
                     RenderNodeAnimatorSetHelper.getTarget(canvas));
-            if (mPendingAnimationAction != NONE) {
+            if (mPendingAnimationActions.size() > 0 && useLastSeenTarget()) {
                 if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                     Log.d(LOGTAG, "Target is set in the next frame");
                 }
-                if (mPendingAnimationAction == START_ANIMATION) {
-                    start();
-                } else if (mPendingAnimationAction == REVERSE_ANIMATION) {
-                    reverse();
+                for (int i = 0; i < mPendingAnimationActions.size(); i++) {
+                    handlePendingAction(mPendingAnimationActions.get(i));
                 }
-                mPendingAnimationAction = NONE;
+                mPendingAnimationActions.clear();
+            }
+        }
+
+        private void handlePendingAction(int pendingAnimationAction) {
+            if (pendingAnimationAction == START_ANIMATION) {
+                startAnimation();
+            } else if (pendingAnimationAction == REVERSE_ANIMATION) {
+                reverseAnimation();
+            } else if (pendingAnimationAction == RESET_ANIMATION) {
+                resetAnimation();
+            } else if (pendingAnimationAction == END_ANIMATION) {
+                endAnimation();
+            } else {
+                throw new UnsupportedOperationException("Animation action " +
+                        pendingAnimationAction + "is not supported");
             }
         }
 
@@ -1060,21 +1260,79 @@
             mDrawable.invalidateSelf();
         }
 
+        private void addPendingAction(int pendingAnimationAction) {
+            invalidateOwningView();
+            mPendingAnimationActions.add(pendingAnimationAction);
+        }
+
+        @Override
         public void start() {
             if (!mInitialized) {
                 return;
             }
 
-            if (!useLastSeenTarget()) {
-                invalidateOwningView();
-                mPendingAnimationAction = START_ANIMATION;
+            if (useLastSeenTarget()) {
+                if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                    Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
+                }
+                startAnimation();
+            } else {
+                addPendingAction(START_ANIMATION);
+            }
+
+        }
+
+        @Override
+        public void end() {
+            if (!mInitialized) {
                 return;
             }
 
-            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
+            if (useLastSeenTarget()) {
+                endAnimation();
+            } else {
+                addPendingAction(END_ANIMATION);
+            }
+        }
+
+        @Override
+        public void reset() {
+            if (!mInitialized) {
+                return;
             }
 
+            if (useLastSeenTarget()) {
+                resetAnimation();
+            } else {
+                addPendingAction(RESET_ANIMATION);
+            }
+        }
+
+        // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential
+        // animators or when the animator set has a start delay
+        @Override
+        public void reverse() {
+            if (!mIsReversible || !mInitialized) {
+                return;
+            }
+            if (useLastSeenTarget()) {
+                if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                    Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
+                }
+                reverseAnimation();
+            } else {
+                addPendingAction(REVERSE_ANIMATION);
+            }
+        }
+
+        // This should only be called after animator has been added to the RenderNode target.
+        private void startAnimation() {
+            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                Log.w(LOGTAG, "starting animation on VD: " +
+                        ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                                mDrawable.getConstantState()).mVectorDrawable.getConstantState())
+                                .mRootName);
+            }
             mStarted = true;
             nStart(mSetPtr, this, ++mLastListenerId);
             invalidateOwningView();
@@ -1083,36 +1341,26 @@
             }
         }
 
-        public void end() {
-            if (mInitialized && useLastSeenTarget()) {
-                // If no target has ever been set, no-op
-                nEnd(mSetPtr);
-                invalidateOwningView();
-            }
-        }
-
-        public void reset() {
-            if (mInitialized && useLastSeenTarget()) {
-                // If no target has ever been set, no-op
-                nReset(mSetPtr);
-                invalidateOwningView();
-            }
-        }
-
-        // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential
-        // animators or when the animator set has a start delay
-        void reverse() {
-            if (!mIsReversible || !mInitialized) {
-                return;
-            }
-            if (!useLastSeenTarget()) {
-                invalidateOwningView();
-                mPendingAnimationAction = REVERSE_ANIMATION;
-                return;
-            }
+        // This should only be called after animator has been added to the RenderNode target.
+        private void endAnimation() {
             if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
+                Log.w(LOGTAG, "ending animation on VD: " +
+                        ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                                mDrawable.getConstantState()).mVectorDrawable.getConstantState())
+                                .mRootName);
             }
+            nEnd(mSetPtr);
+            invalidateOwningView();
+        }
+
+        // This should only be called after animator has been added to the RenderNode target.
+        private void resetAnimation() {
+            nReset(mSetPtr);
+            invalidateOwningView();
+        }
+
+        // This should only be called after animator has been added to the RenderNode target.
+        private void reverseAnimation() {
             mStarted = true;
             nReverse(mSetPtr, this, ++mLastListenerId);
             invalidateOwningView();
@@ -1125,29 +1373,41 @@
             return mSetPtr;
         }
 
-        boolean canReverse() {
+        @Override
+        public boolean canReverse() {
             return mIsReversible;
         }
 
-        boolean isStarted() {
+        @Override
+        public boolean isStarted() {
             return mStarted;
         }
 
-        boolean isRunning() {
+        @Override
+        public boolean isRunning() {
             if (!mInitialized) {
                 return false;
             }
             return mStarted;
         }
 
-        void setListener(AnimatorListener listener) {
+        @Override
+        public void setListener(AnimatorListener listener) {
             mListener = listener;
         }
 
-        void removeListener() {
+        @Override
+        public void removeListener(AnimatorListener listener) {
             mListener = null;
         }
 
+        @Override
+        public void onDraw(Canvas canvas) {
+            if (canvas.isHardwareAccelerated()) {
+                recordLastSeenTarget((DisplayListCanvas) canvas);
+            }
+        }
+
         private void onAnimationEnd(int listenerId) {
             if (listenerId != mLastListenerId) {
                 return;
@@ -1156,13 +1416,16 @@
                 Log.d(LOGTAG, "on finished called from native");
             }
             mStarted = false;
+            // Invalidate in the end of the animation to make sure the data in
+            // RT thread is synced back to UI thread.
+            invalidateOwningView();
             if (mListener != null) {
                 mListener.onAnimationEnd(null);
             }
         }
 
         // onFinished: should be called from native
-        private static void callOnFinished(VectorDrawableAnimator set, int id) {
+        private static void callOnFinished(VectorDrawableAnimatorRT set, int id) {
             set.onAnimationEnd(id);
         }
     }
@@ -1183,8 +1446,8 @@
     private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
             float endValue);
     private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length);
-    private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set, int id);
-    private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set, int id);
+    private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
+    private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
     private static native void nEnd(long animatorSetPtr);
     private static native void nReset(long animatorSetPtr);
 }
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index bffbc75..9d8ede0 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -17,6 +17,7 @@
 package android.graphics.drawable;
 
 import android.annotation.NonNull;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -454,7 +455,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mBitmapState.getChangingConfigurations();
     }
 
@@ -910,7 +911,7 @@
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
         boolean mAutoMirrored = false;
 
-        int mChangingConfigurations;
+        @Config int mChangingConfigurations;
         boolean mRebuildShader;
 
         BitmapState(Bitmap bitmap) {
@@ -958,7 +959,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 5ad31f7..7524cac 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -18,6 +18,7 @@
 
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
+import android.content.pm.ActivityInfo.Config;
 import android.graphics.*;
 import android.graphics.PorterDuff.Mode;
 import android.content.res.ColorStateList;
@@ -70,7 +71,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mColorState.getChangingConfigurations();
     }
 
@@ -292,7 +293,7 @@
         int mBaseColor; // base color, independent of setAlpha()
         @ViewDebug.ExportedProperty
         int mUseColor;  // basecolor modulated by setAlpha()
-        int mChangingConfigurations;
+        @Config int mChangingConfigurations;
         ColorStateList mTint = null;
         Mode mTintMode = DEFAULT_TINT_MODE;
 
@@ -326,7 +327,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 3d8437d..4f600b4 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -19,6 +19,7 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -134,7 +135,7 @@
 
     private int[] mStateSet = StateSet.WILD_CARD;
     private int mLevel = 0;
-    private int mChangingConfigurations = 0;
+    private @Config int mChangingConfigurations = 0;
     private Rect mBounds = ZERO_BOUNDS_RECT;  // lazily becomes a new Rect()
     private WeakReference<Callback> mCallback = null;
     private boolean mVisible = true;
@@ -249,7 +250,7 @@
      *
      * @see android.content.pm.ActivityInfo
      */
-    public void setChangingConfigurations(int configs) {
+    public void setChangingConfigurations(@Config int configs) {
         mChangingConfigurations = configs;
     }
 
@@ -266,7 +267,7 @@
      *
      * @see android.content.pm.ActivityInfo
      */
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return mChangingConfigurations;
     }
 
@@ -308,7 +309,7 @@
      * to supply your implementation of the interface to the drawable; it uses
      * this interface to schedule and execute animation changes.
      */
-    public static interface Callback {
+    public interface Callback {
         /**
          * Called when the drawable needs to be redrawn.  A view at this point
          * should invalidate itself (or at least the part of itself where the
@@ -316,7 +317,7 @@
          *
          * @param who The drawable that is requesting the update.
          */
-        public void invalidateDrawable(Drawable who);
+        void invalidateDrawable(@NonNull Drawable who);
 
         /**
          * A Drawable can call this to schedule the next frame of its
@@ -330,7 +331,7 @@
          * @param when The time (in milliseconds) to run.  The timebase is
          *             {@link android.os.SystemClock#uptimeMillis}
          */
-        public void scheduleDrawable(Drawable who, Runnable what, long when);
+        void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when);
 
         /**
          * A Drawable can call this to unschedule an action previously
@@ -342,7 +343,7 @@
          * @param who The drawable being unscheduled.
          * @param what The action being unscheduled.
          */
-        public void unscheduleDrawable(Drawable who, Runnable what);
+        void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what);
     }
 
     /**
@@ -1197,6 +1198,8 @@
 
     /**
      * Inflate this Drawable from an XML resource optionally styled by a theme.
+     * This can't be called more than once for each Drawable. Note that framework may have called
+     * this once to create the Drawable instance from XML resource.
      *
      * @param r Resources used to resolve attribute values
      * @param parser XML parser from which to inflate this Drawable
@@ -1294,7 +1297,7 @@
          * Return a bit mask of configuration changes that will impact
          * this drawable (and thus require completely reloading it).
          */
-        public abstract int getChangingConfigurations();
+        public abstract @Config int getChangingConfigurations();
 
         /**
          * @return Total pixel count
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index d05c66a..42f4863 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -17,6 +17,7 @@
 package android.graphics.drawable;
 
 import android.annotation.NonNull;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -87,7 +88,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations()
                 | mDrawableContainerState.getChangingConfigurations();
     }
@@ -373,21 +374,21 @@
     }
 
     @Override
-    public void invalidateDrawable(Drawable who) {
+    public void invalidateDrawable(@NonNull Drawable who) {
         if (who == mCurrDrawable && getCallback() != null) {
             getCallback().invalidateDrawable(this);
         }
     }
 
     @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+    public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
         if (who == mCurrDrawable && getCallback() != null) {
             getCallback().scheduleDrawable(this, what, when);
         }
     }
 
     @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
+    public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
         if (who == mCurrDrawable && getCallback() != null) {
             getCallback().unscheduleDrawable(this, what);
         }
@@ -649,8 +650,8 @@
 
         Resources mSourceRes;
         int mDensity = DisplayMetrics.DENSITY_DEFAULT;
-        int mChangingConfigurations;
-        int mChildrenChangingConfigurations;
+        @Config int mChangingConfigurations;
+        @Config int mChildrenChangingConfigurations;
 
         SparseArray<ConstantState> mDrawableFutures;
         Drawable[] mDrawables;
@@ -781,7 +782,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations | mChildrenChangingConfigurations;
         }
 
@@ -804,6 +805,7 @@
             mConstantPadding = null;
             mCheckedPadding = false;
             mCheckedConstantSize = false;
+            mCheckedConstantState = false;
 
             return pos;
         }
@@ -898,19 +900,19 @@
          * @param res the resources used to inflate density-dependent values
          */
         final void updateDensity(Resources res) {
-            if (mSourceRes != null) {
+            if (res != null) {
                 mSourceRes = res;
-            }
 
-            // The density may have changed since the last update (if any). Any
-            // dimension-type attributes will need their default values scaled.
-            final int targetDensity = Drawable.resolveDensity(res, mDensity);
-            final int sourceDensity = mDensity;
-            mDensity = targetDensity;
+                // The density may have changed since the last update (if any). Any
+                // dimension-type attributes will need their default values scaled.
+                final int targetDensity = Drawable.resolveDensity(res, mDensity);
+                final int sourceDensity = mDensity;
+                mDensity = targetDensity;
 
-            if (sourceDensity != targetDensity) {
-                mCheckedConstantSize = false;
-                mCheckedPadding = false;
+                if (sourceDensity != targetDensity) {
+                    mCheckedConstantSize = false;
+                    mCheckedPadding = false;
+                }
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index c427870..5abfc54 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -23,6 +23,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -198,7 +199,7 @@
     }
 
     @Override
-    public void invalidateDrawable(Drawable who) {
+    public void invalidateDrawable(@NonNull Drawable who) {
         final Callback callback = getCallback();
         if (callback != null) {
             callback.invalidateDrawable(this);
@@ -206,7 +207,7 @@
     }
 
     @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+    public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
         final Callback callback = getCallback();
         if (callback != null) {
             callback.scheduleDrawable(this, what, when);
@@ -214,7 +215,7 @@
     }
 
     @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
+    public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
         final Callback callback = getCallback();
         if (callback != null) {
             callback.unscheduleDrawable(this, what);
@@ -229,7 +230,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations()
                 | (mState != null ? mState.getChangingConfigurations() : 0)
                 | mDrawable.getChangingConfigurations();
@@ -444,7 +445,7 @@
     abstract static class DrawableWrapperState extends Drawable.ConstantState {
         private int[] mThemeAttrs;
 
-        int mChangingConfigurations;
+        @Config int mChangingConfigurations;
         int mDensity = DisplayMetrics.DENSITY_DEFAULT;
 
         Drawable.ConstantState mDrawableState;
@@ -524,7 +525,7 @@
         public abstract Drawable newDrawable(@Nullable Resources res);
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | (mDrawableState != null ? mDrawableState.getChangingConfigurations() : 0);
         }
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index f9208cd..bcc354c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -17,8 +17,10 @@
 package android.graphics.drawable;
 
 import android.annotation.ColorInt;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -51,6 +53,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * A Drawable with a color gradient for buttons, backgrounds, etc.
@@ -108,6 +112,11 @@
      */
     public static final int RING = 3;
 
+    /** @hide */
+    @IntDef({RECTANGLE, OVAL, LINE, RING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Shape {}
+
     /**
      * Gradient is linear (default.)
      */
@@ -123,6 +132,11 @@
      */
     public static final int SWEEP_GRADIENT  = 2;
 
+    /** @hide */
+    @IntDef({LINEAR_GRADIENT, RADIAL_GRADIENT, SWEEP_GRADIENT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface GradientType {}
+
     /** Radius is in pixels. */
     private static final int RADIUS_TYPE_PIXELS = 0;
 
@@ -132,6 +146,11 @@
     /** Radius is a fraction of the bounds size. */
     private static final int RADIUS_TYPE_FRACTION_PARENT = 2;
 
+    /** @hide */
+    @IntDef({RADIUS_TYPE_PIXELS, RADIUS_TYPE_FRACTION, RADIUS_TYPE_FRACTION_PARENT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RadiusType {}
+
     private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f;
     private static final float DEFAULT_THICKNESS_RATIO = 9.0f;
 
@@ -404,7 +423,7 @@
      *
      * @see #mutate()
      */
-    public void setShape(int shape) {
+    public void setShape(@Shape int shape) {
         mRingPath = null;
         mPathIsDirty = true;
         mGradientState.setShape(shape);
@@ -412,6 +431,18 @@
     }
 
     /**
+     * Returns the type of shape used by this drawable, one of {@link #LINE},
+     * {@link #OVAL}, {@link #RECTANGLE} or {@link #RING}.
+     *
+     * @return the type of shape used by this drawable
+     * @see #setShape(int)
+     */
+    @Shape
+    public int getShape() {
+        return mGradientState.mShape;
+    }
+
+    /**
      * Sets the type of gradient used by this drawable.
      * <p>
      * <strong>Note</strong>: changing this property will affect all instances
@@ -424,7 +455,7 @@
      * @see #mutate()
      * @see #getGradientType()
      */
-    public void setGradientType(int gradient) {
+    public void setGradientType(@GradientType int gradient) {
         mGradientState.setGradientType(gradient);
         mGradientIsDirty = true;
         invalidateSelf();
@@ -438,6 +469,7 @@
      * @return the type of gradient used by this drawable
      * @see #setGradientType(int)
      */
+    @GradientType
     public int getGradientType() {
         return mGradientState.mGradient;
     }
@@ -534,7 +566,7 @@
      * @see #mutate()
      * @see #setLevel(int)
      * @see #getLevel()
-     * @see #isUseLevel()
+     * @see #getUseLevel()
      */
     public void setUseLevel(boolean useLevel) {
         mGradientState.mUseLevel = useLevel;
@@ -550,7 +582,7 @@
      *         {@code false} otherwise
      * @see #setUseLevel(boolean)
      */
-    public boolean isUseLevel() {
+    public boolean getUseLevel() {
         return mGradientState.mUseLevel;
     }
 
@@ -616,7 +648,8 @@
      */
     @Nullable
     public int[] getColors() {
-        return mGradientState.mGradientColors.clone();
+        return mGradientState.mGradientColors == null ?
+                null : mGradientState.mGradientColors.clone();
     }
 
     @Override
@@ -848,7 +881,7 @@
      * @see #mutate()
      * @see #getColor
      */
-    public void setColor(ColorStateList colorStateList) {
+    public void setColor(@Nullable ColorStateList colorStateList) {
         mGradientState.setSolidColors(colorStateList);
         final int color;
         if (colorStateList == null) {
@@ -870,6 +903,7 @@
      * @see #setColor(int)
      * @see #setColor(ColorStateList)
      */
+    @Nullable
     public ColorStateList getColor() {
         return mGradientState.mSolidColors;
     }
@@ -925,7 +959,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mGradientState.getChangingConfigurations();
     }
 
@@ -951,12 +985,13 @@
     }
 
     @Override
+    @Nullable
     public ColorFilter getColorFilter() {
         return mColorFilter;
     }
 
     @Override
-    public void setColorFilter(ColorFilter colorFilter) {
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
         if (colorFilter != mColorFilter) {
             mColorFilter = colorFilter;
             invalidateSelf();
@@ -964,14 +999,14 @@
     }
 
     @Override
-    public void setTintList(ColorStateList tint) {
+    public void setTintList(@Nullable ColorStateList tint) {
         mGradientState.mTint = tint;
         mTintFilter = updateTintFilter(mTintFilter, tint, mGradientState.mTintMode);
         invalidateSelf();
     }
 
     @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
+    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
         mGradientState.mTintMode = tintMode;
         mTintFilter = updateTintFilter(mTintFilter, mGradientState.mTint, tintMode);
         invalidateSelf();
@@ -1543,7 +1578,7 @@
             final TypedValue tv = a.peekValue(R.styleable.GradientDrawableGradient_gradientRadius);
             if (tv != null) {
                 final float radius;
-                final int radiusType;
+                final @RadiusType int radiusType;
                 if (tv.type == TypedValue.TYPE_FRACTION) {
                     radius = tv.getFraction(1.0f, 1.0f);
 
@@ -1624,7 +1659,9 @@
             return false;
         }
 
-        if (!isOpaque(mFillPaint.getColor())) {
+        // Don't check opacity if we're using a gradient, as we've already
+        // checked the gradient opacity in mOpaqueOverShape.
+        if (mGradientState.mGradientColors == null && !isOpaque(mFillPaint.getColor())) {
             return false;
         }
 
@@ -1698,15 +1735,15 @@
     }
 
     final static class GradientState extends ConstantState {
-        public int mChangingConfigurations;
-        public int mShape = RECTANGLE;
-        public int mGradient = LINEAR_GRADIENT;
+        public @Config int mChangingConfigurations;
+        public @Shape int mShape = RECTANGLE;
+        public @GradientType int mGradient = LINEAR_GRADIENT;
         public int mAngle = 0;
         public Orientation mOrientation;
         public ColorStateList mSolidColors;
         public ColorStateList mStrokeColors;
-        public int[] mGradientColors;
-        public int[] mTempColors; // no need to copy
+        public @ColorInt int[] mGradientColors;
+        public @ColorInt int[] mTempColors; // no need to copy
         public float[] mTempPositions; // no need to copy
         public float[] mPositions;
         public int mStrokeWidth = -1; // if >= 0 use stroking.
@@ -1727,7 +1764,7 @@
         float mCenterX = 0.5f;
         float mCenterY = 0.5f;
         float mGradientRadius = 0.5f;
-        int mGradientRadiusType = RADIUS_TYPE_PIXELS;
+        @RadiusType int mGradientRadiusType = RADIUS_TYPE_PIXELS;
         boolean mUseLevel = false;
         boolean mUseLevelForShape = true;
 
@@ -1926,19 +1963,19 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | (mStrokeColors != null ? mStrokeColors.getChangingConfigurations() : 0)
                     | (mSolidColors != null ? mSolidColors.getChangingConfigurations() : 0)
                     | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
 
-        public void setShape(int shape) {
+        public void setShape(@Shape int shape) {
             mShape = shape;
             computeOpacity();
         }
 
-        public void setGradientType(int gradient) {
+        public void setGradientType(@GradientType int gradient) {
             mGradient = gradient;
         }
 
@@ -1947,13 +1984,13 @@
             mCenterY = y;
         }
 
-        public void setGradientColors(int[] colors) {
+        public void setGradientColors(@Nullable int[] colors) {
             mGradientColors = colors;
             mSolidColors = null;
             computeOpacity();
         }
 
-        public void setSolidColors(ColorStateList colors) {
+        public void setSolidColors(@Nullable ColorStateList colors) {
             mGradientColors = null;
             mSolidColors = colors;
             computeOpacity();
@@ -1984,7 +2021,8 @@
                     && mRadiusArray == null;
         }
 
-        public void setStroke(int width, ColorStateList colors, float dashWidth, float dashGap) {
+        public void setStroke(int width, @Nullable ColorStateList colors, float dashWidth,
+                float dashGap) {
             mStrokeWidth = width;
             mStrokeColors = colors;
             mStrokeDashWidth = dashWidth;
@@ -2012,7 +2050,7 @@
             mHeight = height;
         }
 
-        public void setGradientRadius(float gradientRadius, int type) {
+        public void setGradientRadius(float gradientRadius, @RadiusType int type) {
             mGradientRadius = gradientRadius;
             mGradientRadiusType = type;
         }
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 0de4c2c..2b950d3 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -243,13 +243,15 @@
     }
 
     /**
-     * Invokes {@link #loadDrawable(Context)} on a background thread
-     * and then runs <code>andThen</code> on the UI thread when finished.
+     * Invokes {@link #loadDrawable(Context)} on a background thread and notifies the <code>
+     * {@link OnDrawableLoadedListener#onDrawableLoaded listener} </code> on the {@code handler}
+     * when finished.
      *
      * @param context {@link Context Context} in which to load the drawable; see
      *                {@link #loadDrawable(Context)}
-     * @param listener a callback to run on the provided
-     * @param handler {@link Handler} on which to run <code>andThen</code>.
+     * @param listener to be {@link OnDrawableLoadedListener#onDrawableLoaded notified} when
+     *                 {@link #loadDrawable(Context)} finished
+     * @param handler {@link Handler} on which to notify the {@code listener}
      */
     public void loadDrawableAsync(Context context, final OnDrawableLoadedListener listener,
             Handler handler) {
@@ -627,6 +629,11 @@
         return this;
     }
 
+    /** @hide */
+    public boolean hasTint() {
+        return (mTintList != null) || (mTintMode != DEFAULT_TINT_MODE);
+    }
+
     /**
      * Create an Icon pointing to an image file specified by path.
      *
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index e2150c0..d9c3a02 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -88,7 +89,7 @@
      * @see #getLayerInsetStart(int)
      * @see #getLayerInsetEnd(int)
      */
-    public static final int UNDEFINED_INSET = Integer.MIN_VALUE;
+    public static final int INSET_UNDEFINED = Integer.MIN_VALUE;
 
     LayerState mLayerState;
 
@@ -758,7 +759,7 @@
      * @attr ref android.R.styleable#LayerDrawableItem_bottom
      */
     public void setLayerInset(int index, int l, int t, int r, int b) {
-        setLayerInsetInternal(index, l, t, r, b, UNDEFINED_INSET, UNDEFINED_INSET);
+        setLayerInsetInternal(index, l, t, r, b, INSET_UNDEFINED, INSET_UNDEFINED);
     }
 
     /**
@@ -873,7 +874,7 @@
     /**
      * @param index the index of the layer
      * @return the number of pixels to inset from the start bound, or
-     *         {@link #UNDEFINED_INSET} if not specified
+     *         {@link #INSET_UNDEFINED} if not specified
      * @attr ref android.R.styleable#LayerDrawableItem_start
      */
     public int getLayerInsetStart(int index) {
@@ -884,7 +885,7 @@
     /**
      * @param index the index of the layer to adjust
      * @param e number of pixels to inset from the end bound, or
-     *         {@link #UNDEFINED_INSET} if not specified
+     *         {@link #INSET_UNDEFINED} if not specified
      * @attr ref android.R.styleable#LayerDrawableItem_end
      */
     public void setLayerInsetEnd(int index, int e) {
@@ -944,17 +945,17 @@
     }
 
     @Override
-    public void invalidateDrawable(Drawable who) {
+    public void invalidateDrawable(@NonNull Drawable who) {
         invalidateSelf();
     }
 
     @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+    public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
         scheduleSelf(what, when);
     }
 
     @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
+    public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
         unscheduleSelf(what);
     }
 
@@ -971,7 +972,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mLayerState.getChangingConfigurations();
     }
 
@@ -1502,8 +1503,8 @@
             // insets.
             final int insetRtlL = isLayoutRtl ? r.mInsetE : r.mInsetS;
             final int insetRtlR = isLayoutRtl ? r.mInsetS : r.mInsetE;
-            final int insetL = insetRtlL == UNDEFINED_INSET ? r.mInsetL : insetRtlL;
-            final int insetR = insetRtlR == UNDEFINED_INSET ? r.mInsetR : insetRtlR;
+            final int insetL = insetRtlL == INSET_UNDEFINED ? r.mInsetL : insetRtlL;
+            final int insetR = insetRtlR == INSET_UNDEFINED ? r.mInsetR : insetRtlR;
 
             // Establish containing region based on aggregate padding and
             // requested insets for the current layer.
@@ -1601,8 +1602,8 @@
             // left / right ones.
             final int insetRtlL = isLayoutRtl ? r.mInsetE : r.mInsetS;
             final int insetRtlR = isLayoutRtl ? r.mInsetS : r.mInsetE;
-            final int insetL = insetRtlL == UNDEFINED_INSET ? r.mInsetL : insetRtlL;
-            final int insetR = insetRtlR == UNDEFINED_INSET ? r.mInsetR : insetRtlR;
+            final int insetL = insetRtlL == INSET_UNDEFINED ? r.mInsetL : insetRtlL;
+            final int insetR = insetRtlR == INSET_UNDEFINED ? r.mInsetR : insetRtlR;
 
             // Don't apply padding and insets for children that don't have
             // an intrinsic dimension.
@@ -1762,8 +1763,8 @@
         public int[] mThemeAttrs;
         public int mDensity = DisplayMetrics.DENSITY_DEFAULT;
         public int mInsetL, mInsetT, mInsetR, mInsetB;
-        public int mInsetS = UNDEFINED_INSET;
-        public int mInsetE = UNDEFINED_INSET;
+        public int mInsetS = INSET_UNDEFINED;
+        public int mInsetE = INSET_UNDEFINED;
         public int mWidth = -1;
         public int mHeight = -1;
         public int mGravity = Gravity.NO_GRAVITY;
@@ -1832,10 +1833,10 @@
             mInsetT = Drawable.scaleFromDensity(mInsetT, sourceDensity, targetDensity, false);
             mInsetR = Drawable.scaleFromDensity(mInsetR, sourceDensity, targetDensity, false);
             mInsetB = Drawable.scaleFromDensity(mInsetB, sourceDensity, targetDensity, false);
-            if (mInsetS != UNDEFINED_INSET) {
+            if (mInsetS != INSET_UNDEFINED) {
                 mInsetS = Drawable.scaleFromDensity(mInsetS, sourceDensity, targetDensity, false);
             }
-            if (mInsetE != UNDEFINED_INSET) {
+            if (mInsetE != INSET_UNDEFINED) {
                 mInsetE = Drawable.scaleFromDensity(mInsetE, sourceDensity, targetDensity, false);
             }
             if (mWidth > 0) {
@@ -1864,8 +1865,8 @@
         int mPaddingEnd = -1;
         int mOpacityOverride = PixelFormat.UNKNOWN;
 
-        int mChangingConfigurations;
-        int mChildrenChangingConfigurations;
+        @Config int mChangingConfigurations;
+        @Config int mChildrenChangingConfigurations;
 
         private boolean mHaveOpacity;
         private int mOpacity;
@@ -1989,7 +1990,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | mChildrenChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index bfbdfa5..d962385 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -66,11 +67,16 @@
 public class NinePatchDrawable extends Drawable {
     // dithering helps a lot, and is pretty cheap, so default is true
     private static final boolean DEFAULT_DITHER = false;
+
+    /** Temporary rect used for density scaling. */
+    private Rect mTempRect;
+
     private NinePatchState mNinePatchState;
-    private NinePatch mNinePatch;
     private PorterDuffColorFilter mTintFilter;
     private Rect mPadding;
     private Insets mOpticalInsets = Insets.NONE;
+    private Rect mOutlineInsets;
+    private float mOutlineRadius;
     private Paint mPaint;
     private boolean mMutated;
 
@@ -86,8 +92,9 @@
 
     /**
      * Create drawable from raw nine-patch data, not dealing with density.
+     *
      * @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
-     * to ensure that the drawable has correctly set its target density.
+     *             to ensure that the drawable has correctly set its target density.
      */
     @Deprecated
     public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
@@ -101,7 +108,6 @@
     public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
             Rect padding, String srcName) {
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
-        mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
     /**
@@ -114,16 +120,17 @@
             Rect padding, Rect opticalInsets, String srcName) {
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
                 res);
-        mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
     /**
      * Create drawable from existing nine-patch, not dealing with density.
+     *
      * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
-     * to ensure that the drawable has correctly set its target density.
+     *             to ensure that the drawable has correctly set its target
+     *             density.
      */
     @Deprecated
-    public NinePatchDrawable(NinePatch patch) {
+    public NinePatchDrawable(@NonNull NinePatch patch) {
         this(new NinePatchState(patch, new Rect()), null);
     }
 
@@ -131,9 +138,8 @@
      * Create drawable from existing nine-patch, setting initial target density
      * based on the display metrics of the resources.
      */
-    public NinePatchDrawable(Resources res, NinePatch patch) {
+    public NinePatchDrawable(@Nullable Resources res, @NonNull NinePatch patch) {
         this(new NinePatchState(patch, new Rect()), res);
-        mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
     /**
@@ -146,7 +152,7 @@
      * @see android.graphics.Bitmap#setDensity(int)
      * @see android.graphics.Bitmap#getDensity()
      */
-    public void setTargetDensity(Canvas canvas) {
+    public void setTargetDensity(@NonNull Canvas canvas) {
         setTargetDensity(canvas.getDensity());
     }
 
@@ -158,7 +164,7 @@
      * @see android.graphics.Bitmap#setDensity(int)
      * @see android.graphics.Bitmap#getDensity()
      */
-    public void setTargetDensity(DisplayMetrics metrics) {
+    public void setTargetDensity(@NonNull DisplayMetrics metrics) {
         setTargetDensity(metrics.densityDpi);
     }
 
@@ -171,78 +177,24 @@
      * @see android.graphics.Bitmap#getDensity()
      */
     public void setTargetDensity(int density) {
-        if (density != mTargetDensity) {
-            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
-            if (mNinePatch != null) {
-                computeBitmapSize();
-            }
+        if (density == 0) {
+            density = DisplayMetrics.DENSITY_DEFAULT;
+        }
+
+        if (mTargetDensity != density) {
+            mTargetDensity = density;
+
+            computeBitmapSize();
             invalidateSelf();
         }
     }
 
-    private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
-        int left = Drawable.scaleFromDensity(insets.left, sdensity, tdensity, true);
-        int top = Drawable.scaleFromDensity(insets.top, sdensity, tdensity, true);
-        int right = Drawable.scaleFromDensity(insets.right, sdensity, tdensity, true);
-        int bottom = Drawable.scaleFromDensity(insets.bottom, sdensity, tdensity, true);
-        return Insets.of(left, top, right, bottom);
-    }
-
-    private void computeBitmapSize() {
-        final int sdensity = mNinePatch.getDensity();
-        final int tdensity = mTargetDensity;
-        if (sdensity == tdensity) {
-            mBitmapWidth = mNinePatch.getWidth();
-            mBitmapHeight = mNinePatch.getHeight();
-            mOpticalInsets = mNinePatchState.mOpticalInsets;
-        } else {
-            mBitmapWidth = Drawable.scaleFromDensity(
-                    mNinePatch.getWidth(), sdensity, tdensity, true);
-            mBitmapHeight = Drawable.scaleFromDensity(
-                    mNinePatch.getHeight(), sdensity, tdensity, true);
-            if (mNinePatchState.mPadding != null && mPadding != null) {
-                Rect dest = mPadding;
-                Rect src = mNinePatchState.mPadding;
-                if (dest == src) {
-                    mPadding = dest = new Rect(src);
-                }
-                dest.left = Drawable.scaleFromDensity(src.left, sdensity, tdensity, true);
-                dest.top = Drawable.scaleFromDensity(src.top, sdensity, tdensity, true);
-                dest.right = Drawable.scaleFromDensity(src.right, sdensity, tdensity, true);
-                dest.bottom = Drawable.scaleFromDensity(src.bottom, sdensity, tdensity, true);
-            }
-            mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity);
-        }
-    }
-
-    /**
-     * Sets the nine patch used by this drawable.
-     *
-     * @param ninePatch the nine patch for this drawable
-     */
-    public void setNinePatch(NinePatch ninePatch) {
-        if (mNinePatch != ninePatch) {
-            mNinePatch = ninePatch;
-            if (ninePatch != null) {
-                computeBitmapSize();
-            } else {
-                mBitmapWidth = mBitmapHeight = -1;
-                mOpticalInsets = Insets.NONE;
-            }
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return the nine patch used by this drawable
-     */
-    public NinePatch getNinePatch() {
-        return mNinePatch;
-    }
-
     @Override
     public void draw(Canvas canvas) {
-        final Rect bounds = getBounds();
+        final NinePatchState state = mNinePatchState;
+
+        Rect bounds = getBounds();
+        int restoreToCount = -1;
 
         final boolean clearColorFilter;
         if (mTintFilter != null && getPaint().getColorFilter() == null) {
@@ -252,22 +204,52 @@
             clearColorFilter = false;
         }
 
-        final boolean needsMirroring = needsMirroring();
-        if (needsMirroring) {
-            // Mirror the 9patch
-            canvas.translate(bounds.right - bounds.left, 0);
-            canvas.scale(-1.0f, 1.0f);
-        }
-
         final int restoreAlpha;
-        if (mNinePatchState.mBaseAlpha != 1.0f) {
-            restoreAlpha = mPaint.getAlpha();
-            mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f));
+        if (state.mBaseAlpha != 1.0f) {
+            restoreAlpha = getPaint().getAlpha();
+            mPaint.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
         } else {
             restoreAlpha = -1;
         }
 
-        mNinePatch.draw(canvas, bounds, mPaint);
+        final boolean needsDensityScaling = canvas.getDensity() == 0;
+        if (needsDensityScaling) {
+            restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+            // Apply density scaling.
+            final float scale = mTargetDensity / (float) state.mNinePatch.getDensity();
+            final float px = bounds.left;
+            final float py = bounds.top;
+            canvas.scale(scale, scale, px, py);
+
+            if (mTempRect == null) {
+                mTempRect = new Rect();
+            }
+
+            // Scale the bounds to match.
+            final Rect scaledBounds = mTempRect;
+            scaledBounds.left = bounds.left;
+            scaledBounds.top = bounds.top;
+            scaledBounds.right = bounds.left + Math.round(bounds.width() / scale);
+            scaledBounds.bottom = bounds.top + Math.round(bounds.height() / scale);
+            bounds = scaledBounds;
+        }
+
+        final boolean needsMirroring = needsMirroring();
+        if (needsMirroring) {
+            restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+            // Mirror the 9patch.
+            final float cx = (bounds.left + bounds.right) / 2.0f;
+            final float cy = (bounds.top + bounds.bottom) / 2.0f;
+            canvas.scale(-1.0f, 1.0f, cx, cy);
+        }
+
+        state.mNinePatch.draw(canvas, bounds, mPaint);
+
+        if (restoreToCount >= 0) {
+            canvas.restoreToCount(restoreToCount);
+        }
 
         if (clearColorFilter) {
             mPaint.setColorFilter(null);
@@ -279,43 +261,41 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mNinePatchState.getChangingConfigurations();
     }
 
     @Override
-    public boolean getPadding(Rect padding) {
-        final Rect scaledPadding = mPadding;
-        if (scaledPadding != null) {
-            if (needsMirroring()) {
-                padding.set(scaledPadding.right, scaledPadding.top,
-                        scaledPadding.left, scaledPadding.bottom);
-            } else {
-                padding.set(scaledPadding);
-            }
+    public boolean getPadding(@NonNull Rect padding) {
+        if (mPadding != null) {
+            padding.set(mPadding);
             return (padding.left | padding.top | padding.right | padding.bottom) != 0;
+        } else {
+            return super.getPadding(padding);
         }
-        return false;
     }
 
     @Override
     public void getOutline(@NonNull Outline outline) {
         final Rect bounds = getBounds();
-        if (bounds.isEmpty()) return;
+        if (bounds.isEmpty()) {
+            return;
+        }
 
-        if (mNinePatchState != null) {
-            NinePatch.InsetStruct insets = mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
+        if (mNinePatchState != null && mOutlineInsets != null) {
+            final NinePatch.InsetStruct insets =
+                    mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
             if (insets != null) {
-                final Rect outlineInsets = insets.outlineRect;
-                outline.setRoundRect(bounds.left + outlineInsets.left,
-                        bounds.top + outlineInsets.top,
-                        bounds.right - outlineInsets.right,
-                        bounds.bottom - outlineInsets.bottom,
-                        insets.outlineRadius);
+                outline.setRoundRect(bounds.left + mOutlineInsets.left,
+                        bounds.top + mOutlineInsets.top,
+                        bounds.right - mOutlineInsets.right,
+                        bounds.bottom - mOutlineInsets.bottom,
+                        mOutlineRadius);
                 outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f));
                 return;
             }
         }
+
         super.getOutline(outline);
     }
 
@@ -324,11 +304,12 @@
      */
     @Override
     public Insets getOpticalInsets() {
+        final Insets opticalInsets = mOpticalInsets;
         if (needsMirroring()) {
-            return Insets.of(mOpticalInsets.right, mOpticalInsets.top,
-                    mOpticalInsets.left, mOpticalInsets.bottom);
+            return Insets.of(opticalInsets.right, opticalInsets.top,
+                    opticalInsets.left, opticalInsets.bottom);
         } else {
-            return mOpticalInsets;
+            return opticalInsets;
         }
     }
 
@@ -352,7 +333,7 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter colorFilter) {
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
         if (mPaint == null && colorFilter == null) {
             // Fast common case -- leave at no color filter.
             return;
@@ -362,14 +343,14 @@
     }
 
     @Override
-    public void setTintList(ColorStateList tint) {
+    public void setTintList(@Nullable ColorStateList tint) {
         mNinePatchState.mTint = tint;
         mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
         invalidateSelf();
     }
 
     @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
+    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
         mNinePatchState.mTintMode = tintMode;
         mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
         invalidateSelf();
@@ -409,10 +390,7 @@
 
     @Override
     public boolean isFilterBitmap() {
-        if (mPaint == null) {
-            return false;
-        }
-        return getPaint().isFilterBitmap();
+        return mPaint != null && getPaint().isFilterBitmap();
     }
 
     @Override
@@ -430,7 +408,7 @@
     /**
      * Updates the constant state from the values in the typed array.
      */
-    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+    private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException {
         final Resources r = a.getResources();
         final NinePatchState state = mNinePatchState;
 
@@ -491,12 +469,10 @@
         if (tint != null) {
             state.mTint = tint;
         }
-
-        state.mTargetDensity = Drawable.resolveDensity(r, state.mTargetDensity);
     }
 
     @Override
-    public void applyTheme(Theme t) {
+    public void applyTheme(@NonNull Theme t) {
         super.applyTheme(t);
 
         final NinePatchState state = mNinePatchState;
@@ -528,6 +504,7 @@
         return mNinePatchState != null && mNinePatchState.canApplyTheme();
     }
 
+    @NonNull
     public Paint getPaint() {
         if (mPaint == null) {
             mPaint = new Paint();
@@ -536,45 +513,26 @@
         return mPaint;
     }
 
-    /**
-     * Retrieves the width of the source .png file (before resizing).
-     */
     @Override
     public int getIntrinsicWidth() {
         return mBitmapWidth;
     }
 
-    /**
-     * Retrieves the height of the source .png file (before resizing).
-     */
     @Override
     public int getIntrinsicHeight() {
         return mBitmapHeight;
     }
 
     @Override
-    public int getMinimumWidth() {
-        return mBitmapWidth;
-    }
-
-    @Override
-    public int getMinimumHeight() {
-        return mBitmapHeight;
-    }
-
-    /**
-     * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
-     * value of OPAQUE or TRANSLUCENT.
-     */
-    @Override
     public int getOpacity() {
-        return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ?
-                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+        return mNinePatchState.mNinePatch.hasAlpha()
+                || (mPaint != null && mPaint.getAlpha() < 255) ?
+                        PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
     }
 
     @Override
     public Region getTransparentRegion() {
-        return mNinePatch.getTransparentRegion(getBounds());
+        return mNinePatchState.mNinePatch.getTransparentRegion(getBounds());
     }
 
     @Override
@@ -587,7 +545,6 @@
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mNinePatchState = new NinePatchState(mNinePatchState);
-            mNinePatch = mNinePatchState.mNinePatch;
             mMutated = true;
         }
         return this;
@@ -619,8 +576,9 @@
     }
 
     final static class NinePatchState extends ConstantState {
+        @Config int mChangingConfigurations;
+
         // Values loaded during inflation.
-        int[] mThemeAttrs = null;
         NinePatch mNinePatch = null;
         ColorStateList mTint = null;
         Mode mTintMode = DEFAULT_TINT_MODE;
@@ -628,10 +586,9 @@
         Insets mOpticalInsets = Insets.NONE;
         float mBaseAlpha = 1.0f;
         boolean mDither = DEFAULT_DITHER;
-        int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
         boolean mAutoMirrored = false;
 
-        int mChangingConfigurations;
+        int[] mThemeAttrs;
 
         NinePatchState() {
             // Empty constructor.
@@ -655,27 +612,24 @@
             mAutoMirrored = autoMirror;
         }
 
-        // Copy constructor
-
-        NinePatchState(@NonNull NinePatchState state) {
-            // We don't deep-copy any fields because they are all immutable.
-            mNinePatch = state.mNinePatch;
-            mTint = state.mTint;
-            mTintMode = state.mTintMode;
-            mThemeAttrs = state.mThemeAttrs;
-            mPadding = state.mPadding;
-            mOpticalInsets = state.mOpticalInsets;
-            mBaseAlpha = state.mBaseAlpha;
-            mDither = state.mDither;
-            mChangingConfigurations = state.mChangingConfigurations;
-            mTargetDensity = state.mTargetDensity;
-            mAutoMirrored = state.mAutoMirrored;
+        NinePatchState(@NonNull NinePatchState orig) {
+            mChangingConfigurations = orig.mChangingConfigurations;
+            mNinePatch = orig.mNinePatch;
+            mTint = orig.mTint;
+            mTintMode = orig.mTintMode;
+            mPadding = orig.mPadding;
+            mOpticalInsets = orig.mOpticalInsets;
+            mBaseAlpha = orig.mBaseAlpha;
+            mDither = orig.mDither;
+            mAutoMirrored = orig.mAutoMirrored;
+            mThemeAttrs = orig.mThemeAttrs;
         }
 
         @Override
         public boolean canApplyTheme() {
             return mThemeAttrs != null
-                    || (mTint != null && mTint.canApplyTheme());
+                    || (mTint != null && mTint.canApplyTheme())
+                    || super.canApplyTheme();
         }
 
         @Override
@@ -698,50 +652,102 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
     }
 
+    private void computeBitmapSize() {
+        final NinePatch ninePatch = mNinePatchState.mNinePatch;
+        if (ninePatch == null) {
+            return;
+        }
+
+        final int sourceDensity = ninePatch.getDensity();
+        final int targetDensity = mTargetDensity;
+
+        final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
+        if (sourceOpticalInsets != Insets.NONE) {
+            final int left = Drawable.scaleFromDensity(
+                    sourceOpticalInsets.left, sourceDensity, targetDensity, true);
+            final int top = Drawable.scaleFromDensity(
+                    sourceOpticalInsets.top, sourceDensity, targetDensity, true);
+            final int right = Drawable.scaleFromDensity(
+                    sourceOpticalInsets.right, sourceDensity, targetDensity, true);
+            final int bottom = Drawable.scaleFromDensity(
+                    sourceOpticalInsets.bottom, sourceDensity, targetDensity, true);
+            mOpticalInsets = Insets.of(left, top, right, bottom);
+        } else {
+            mOpticalInsets = Insets.NONE;
+        }
+
+        final Rect sourcePadding = mNinePatchState.mPadding;
+        if (sourcePadding != null) {
+            if (mPadding == null) {
+                mPadding = new Rect();
+            }
+            mPadding.left = Drawable.scaleFromDensity(
+                    sourcePadding.left, sourceDensity, targetDensity, false);
+            mPadding.top = Drawable.scaleFromDensity(
+                    sourcePadding.top, sourceDensity, targetDensity, false);
+            mPadding.right = Drawable.scaleFromDensity(
+                    sourcePadding.right, sourceDensity, targetDensity, false);
+            mPadding.bottom = Drawable.scaleFromDensity(
+                    sourcePadding.bottom, sourceDensity, targetDensity, false);
+        } else {
+            mPadding = null;
+        }
+
+        mBitmapHeight = Drawable.scaleFromDensity(
+                ninePatch.getHeight(), sourceDensity, targetDensity, true);
+        mBitmapWidth = Drawable.scaleFromDensity(
+                ninePatch.getWidth(), sourceDensity, targetDensity, true);
+
+        final NinePatch.InsetStruct insets = ninePatch.getBitmap().getNinePatchInsets();
+        if (insets != null) {
+            Rect outlineRect = insets.outlineRect;
+            mOutlineInsets = NinePatch.InsetStruct.scaleInsets(outlineRect.left, outlineRect.top,
+                    outlineRect.right, outlineRect.bottom, targetDensity / (float) sourceDensity);
+            mOutlineRadius = Drawable.scaleFromDensity(
+                    insets.outlineRadius, sourceDensity, targetDensity);
+        } else {
+            mOutlineInsets = null;
+        }
+    }
+
     /**
      * The one constructor to rule them all. This is called by all public
      * constructors to set the state and initialize local properties.
+     *
+     * @param state constant state to assign to the new drawable
      */
-    private NinePatchDrawable(NinePatchState state, Resources res) {
+    private NinePatchDrawable(@NonNull NinePatchState state, @Nullable Resources res) {
         mNinePatchState = state;
 
         updateLocalState(res);
-
-        // Push density applied by setNinePatchState into state.
-        mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
     /**
      * Initializes local dynamic properties from state.
      */
-    private void updateLocalState(Resources res) {
+    private void updateLocalState(@Nullable Resources res) {
         final NinePatchState state = mNinePatchState;
 
-        if (res != null) {
-            final int densityDpi = res.getDisplayMetrics().densityDpi;
-            mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
-        } else {
-            mTargetDensity = state.mTargetDensity;
-        }
-
-
         // If we can, avoid calling any methods that initialize Paint.
         if (state.mDither != DEFAULT_DITHER) {
             setDither(state.mDither);
         }
 
-        // Make a local copy of the padding.
-        if (state.mPadding != null) {
-            mPadding = new Rect(state.mPadding);
+        // The nine-patch may have been created without a Resources object, in
+        // which case we should try to match the density of the nine patch (if
+        // available).
+        if (res == null && state.mNinePatch != null) {
+            mTargetDensity = state.mNinePatch.getDensity();
+        } else {
+            mTargetDensity = Drawable.resolveDensity(res, mTargetDensity);
         }
-
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
-        setNinePatch(state.mNinePatch);
+        computeBitmapSize();
     }
 }
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index ee0861a..caf2e7a 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -23,6 +23,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -1033,7 +1034,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return super.getChangingConfigurations()
                     | (mColor != null ? mColor.getChangingConfigurations() : 0);
         }
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 30b588e..fe82a93 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -260,7 +261,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mShapeState.getChangingConfigurations();
     }
 
@@ -526,7 +527,7 @@
      */
     final static class ShapeState extends ConstantState {
         int[] mThemeAttrs;
-        int mChangingConfigurations;
+        @Config int mChangingConfigurations;
         Paint mPaint;
         Shape mShape;
         ColorStateList mTint = null;
@@ -571,7 +572,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index e5c235e..0122338 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.os.SystemClock;
@@ -259,7 +260,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations;
         }
     }
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 9e0f1b4..e75fb98 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -16,6 +16,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.ComplexColor;
 import android.content.res.GradientColor;
@@ -52,8 +53,15 @@
 import java.util.Stack;
 
 /**
- * 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.
+ * This lets you create a drawable based on an XML vector graphic.
+ * <p/>
+ * <strong>Note:</strong> To optimize for the re-drawing performance, one bitmap cache is created
+ * for each VectorDrawable. Therefore, referring to the same VectorDrawable means sharing the same
+ * bitmap cache. If these references don't agree upon on the same size, the bitmap will be recreated
+ * and redrawn every time size is changed. In other words, if a VectorDrawable is used for
+ * different sizes, it is more efficient to create multiple VectorDrawables, one for each size.
+ * <p/>
+ * VectorDrawable can be defined in an XML file with the <code>&lt;vector></code> element.
  * <p/>
  * The vector drawable has the following elements:
  * <p/>
@@ -364,7 +372,9 @@
 
     @Override
     public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
+        // We can't tell whether the drawable is fully opaque unless we examine all the pixels,
+        // but we could tell it is transparent if the root alpha is 0.
+        return getAlpha() == 0 ? PixelFormat.TRANSPARENT : PixelFormat.TRANSLUCENT;
     }
 
     @Override
@@ -684,7 +694,7 @@
     }
 
     @Override
-    public int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations() | mVectorState.getChangingConfigurations();
     }
 
@@ -712,7 +722,7 @@
     static class VectorDrawableState extends ConstantState {
         // Variables below need to be copied (deep copy if applicable) for mutation.
         int[] mThemeAttrs;
-        int mChangingConfigurations;
+        @Config int mChangingConfigurations;
         ColorStateList mTint = null;
         Mode mTintMode = DEFAULT_TINT_MODE;
         boolean mAutoMirrored;
@@ -821,7 +831,7 @@
         }
 
         @Override
-        public int getChangingConfigurations() {
+        public @Config int getChangingConfigurations() {
             return mChangingConfigurations
                     | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
@@ -921,7 +931,7 @@
 
         // mLocalMatrix is updated based on the update of transformation information,
         // either parsed from the XML or by animation.
-        private int mChangingConfigurations;
+        private @Config int mChangingConfigurations;
         private int[] mThemeAttrs;
         private String mGroupName = null;
 
@@ -1167,7 +1177,7 @@
         protected PathParser.PathData mPathData = null;
 
         String mPathName;
-        int mChangingConfigurations;
+        @Config int mChangingConfigurations;
 
         public VPath() {
             // Empty constructor.
@@ -1278,8 +1288,10 @@
         private static final int STROKE_LINE_CAP_INDEX = 8;
         private static final int STROKE_LINE_JOIN_INDEX = 9;
         private static final int STROKE_MITER_LIMIT_INDEX = 10;
-        private static final int TOTAL_PROPERTY_COUNT = 11;
+        private static final int FILL_TYPE_INDEX = 11;
+        private static final int TOTAL_PROPERTY_COUNT = 12;
 
+        // Property map for animatable attributes.
         private final static HashMap<String, Integer> sPropertyMap
                 = new HashMap<String, Integer> () {
             {
@@ -1396,6 +1408,7 @@
             int strokeLineCap =  properties.getInt(STROKE_LINE_CAP_INDEX * 4);
             int strokeLineJoin = properties.getInt(STROKE_LINE_JOIN_INDEX * 4);
             float strokeMiterLimit = properties.getFloat(STROKE_MITER_LIMIT_INDEX * 4);
+            int fillType = properties.getInt(FILL_TYPE_INDEX * 4);
             Shader fillGradient = null;
             Shader strokeGradient = null;
             // Account for any configuration changes.
@@ -1471,10 +1484,11 @@
                     R.styleable.VectorDrawablePath_trimPathOffset, trimPathOffset);
             trimPathStart = a.getFloat(
                     R.styleable.VectorDrawablePath_trimPathStart, trimPathStart);
+            fillType = a.getInt(R.styleable.VectorDrawablePath_fillType, fillType);
 
             nUpdateFullPathProperties(mNativePtr, strokeWidth, strokeColor, strokeAlpha,
                     fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset,
-                    strokeMiterLimit, strokeLineCap, strokeLineJoin);
+                    strokeMiterLimit, strokeLineCap, strokeLineJoin, fillType);
         }
 
         @Override
@@ -1642,7 +1656,7 @@
     private static native void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
             int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
             float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
-            int strokeLineJoin);
+            int strokeLineJoin, int fillType);
     private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
     private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
 
diff --git a/graphics/java/android/graphics/drawable/shapes/ArcShape.java b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
index 84731b0..c4b239f 100644
--- a/graphics/java/android/graphics/drawable/shapes/ArcShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
@@ -17,6 +17,7 @@
 package android.graphics.drawable.shapes;
 
 import android.graphics.Canvas;
+import android.graphics.Outline;
 import android.graphics.Paint;
 
 /**
@@ -46,5 +47,11 @@
     public void draw(Canvas canvas, Paint paint) {
         canvas.drawArc(rect(), mStart, mSweep, true, paint);
     }
+
+    @Override
+    public void getOutline(Outline outline) {
+        // Since we don't support concave outlines, arc shape does not attempt
+        // to provide an outline.
+    }
 }
 
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index d8801b8..05596f0 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -35,6 +35,8 @@
 
 #include <android/configuration.h>
 
+#include <memory>
+
 namespace android {
 
 /**
@@ -1151,9 +1153,13 @@
         uint32_t screenConfig2;
     };
 
-    // If true, it means that the script of the locale was explicitly provided.
-    // If false, it means that the script was automatically computed.
-    bool localeScriptWasProvided;
+    // If false and localeScript is set, it means that the script of the locale
+    // was explicitly provided.
+    //
+    // If true, it means that localeScript was automatically computed.
+    // localeScript may still not be set in this case, which means that we
+    // tried but could not compute a script.
+    bool localeScriptWasComputed;
 
     void copyFromDeviceNoSwap(const ResTable_config& o);
     
@@ -1233,7 +1239,7 @@
 
     inline void clearLocale() {
         locale = 0;
-        localeScriptWasProvided = false;
+        localeScriptWasComputed = false;
         memset(localeScript, 0, sizeof(localeScript));
         memset(localeVariant, 0, sizeof(localeVariant));
     }
@@ -1872,9 +1878,30 @@
     struct Entry;
     struct Package;
     struct PackageGroup;
-    struct bag_set;
     typedef Vector<Type*> TypeList;
 
+    struct bag_set {
+        size_t numAttrs;    // number in array
+        size_t availAttrs;  // total space in array
+        uint32_t typeSpecFlags;
+        // Followed by 'numAttr' bag_entry structures.
+    };
+
+    /**
+     * Configuration dependent cached data. This must be cleared when the configuration is
+     * changed (setParameters).
+     */
+    struct TypeCacheEntry {
+        TypeCacheEntry() : cachedBags(NULL) {}
+
+        // Computed attribute bags for this type.
+        bag_set** cachedBags;
+
+        // Pre-filtered list of configurations (per asset path) that match the parameters set on this
+        // ResTable.
+        Vector<std::shared_ptr<Vector<const ResTable_type*>>> filteredConfigs;
+    };
+
     status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
             bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
 
@@ -1896,6 +1923,13 @@
 
     mutable Mutex               mLock;
 
+    // Mutex that controls access to the list of pre-filtered configurations
+    // to check when looking up entries.
+    // When iterating over a bag, the mLock mutex is locked. While mLock is locked,
+    // we do resource lookups.
+    // Mutex is not reentrant, so we must use a different lock than mLock.
+    mutable Mutex               mFilteredConfigLock;
+
     status_t                    mError;
 
     ResTable_config             mParams;
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 302b0bd..6830a74 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -217,42 +217,42 @@
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
+     * Delete all types (private key, user certificate, CA certificate) for a
      * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Returns {@code true} if the alias no longer contains any types.
      */
     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
         return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
+     * Delete all types (private key, user certificate, CA certificate) for a
      * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Returns {@code true} if the alias no longer contains any types.
      */
     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
          * Make sure every type is deleted. There can be all three types, so
          * don't use a conditional here.
          */
-        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid)
-                | keystore.delete(Credentials.USER_SECRET_KEY + alias, uid)
-                | deleteCertificateTypesForAlias(keystore, alias, uid);
+        return deletePrivateKeyTypeForAlias(keystore, alias, uid)
+                & deleteSecretKeyTypeForAlias(keystore, alias, uid)
+                & deleteCertificateTypesForAlias(keystore, alias, uid);
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
-     * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Delete certificate types (user certificate, CA certificate) for a
+     * particular {@code alias}. Both can exist for any given alias.
+     * Returns {@code true} if the alias no longer contains either type.
      */
     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
         return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
-     * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Delete certificate types (user certificate, CA certificate) for a
+     * particular {@code alias}. Both can exist for any given alias.
+     * Returns {@code true} if the alias no longer contains either type.
      */
     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
@@ -260,12 +260,12 @@
          * so don't use a conditional here.
          */
         return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
-                | keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
+                & keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
     }
 
     /**
      * Delete private key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias) {
         return deletePrivateKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
@@ -273,7 +273,7 @@
 
     /**
      * Delete private key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
         return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid);
@@ -281,7 +281,7 @@
 
     /**
      * Delete secret key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias) {
         return deleteSecretKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
@@ -289,7 +289,7 @@
 
     /**
      * Delete secret key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
         return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index cfcb4e0..deea972 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -27,12 +27,13 @@
     // APIs used by KeyChain
     String requestPrivateKey(String alias);
     byte[] getCertificate(String alias);
+    byte[] getCaCertificates(String alias);
 
     // APIs used by CertInstaller
     void installCaCertificate(in byte[] caCertificate);
 
     // APIs used by DevicePolicyManager
-    boolean installKeyPair(in byte[] privateKey, in byte[] userCert, String alias);
+    boolean installKeyPair(in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias);
     boolean removeKeyPair(String alias);
 
     // APIs used by Settings
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 7adad8a..cce58c2 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -42,6 +42,8 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.BlockingQueue;
@@ -389,7 +391,12 @@
 
     /**
      * Returns the {@code X509Certificate} chain for the requested
-     * alias, or null if no there is no result.
+     * alias, or null if there is no result.
+     * <p>
+     * <strong>Note:</strong> If a certificate chain was explicitly specified when the alias was
+     * installed, this method will return that chain. If only the client certificate was specified
+     * at the installation time, this method will try to build a certificate chain using all
+     * available trust anchors (preinstalled and user-added).
      *
      * <p> This method may block while waiting for a connection to another process, and must never
      * be called from the main thread.
@@ -413,11 +420,31 @@
             if (certificateBytes == null) {
                 return null;
             }
-
-            TrustedCertificateStore store = new TrustedCertificateStore();
-            List<X509Certificate> chain = store
-                    .getCertificateChain(toCertificate(certificateBytes));
-            return chain.toArray(new X509Certificate[chain.size()]);
+            X509Certificate leafCert = toCertificate(certificateBytes);
+            final byte[] certChainBytes = keyChainService.getCaCertificates(alias);
+            // If the keypair is installed with a certificate chain by either
+            // DevicePolicyManager.installKeyPair or CertInstaller, return that chain.
+            if (certChainBytes != null && certChainBytes.length != 0) {
+                Collection<X509Certificate> chain = toCertificates(certChainBytes);
+                ArrayList<X509Certificate> fullChain = new ArrayList<>(chain.size() + 1);
+                fullChain.add(leafCert);
+                fullChain.addAll(chain);
+                return fullChain.toArray(new X509Certificate[fullChain.size()]);
+            } else {
+                // If there isn't a certificate chain, either due to a pre-existing keypair
+                // installed before N, or no chain is explicitly installed under the new logic,
+                // fall back to old behavior of constructing the chain from trusted credentials.
+                //
+                // This logic exists to maintain old behaviour for already installed keypair, at
+                // the cost of potentially returning extra certificate chain for new clients who
+                // explicitly installed only the client certificate without a chain. The latter
+                // case is actually no different from pre-N behaviour of getCertificateChain(),
+                // in that sense this change introduces no regression. Besides the returned chain
+                // is still valid so the consumer of the chain should have no problem verifying it.
+                TrustedCertificateStore store = new TrustedCertificateStore();
+                List<X509Certificate> chain = store.getCertificateChain(leafCert);
+                return chain.toArray(new X509Certificate[chain.size()]);
+            }
         } catch (CertificateException e) {
             throw new KeyChainException(e);
         } catch (RemoteException e) {
@@ -486,6 +513,21 @@
         }
     }
 
+    /** @hide */
+    @NonNull
+    public static Collection<X509Certificate> toCertificates(@NonNull byte[] bytes) {
+        if (bytes == null) {
+            throw new IllegalArgumentException("bytes == null");
+        }
+        try {
+            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            return (Collection<X509Certificate>) certFactory.generateCertificates(
+                    new ByteArrayInputStream(bytes));
+        } catch (CertificateException e) {
+            throw new AssertionError(e);
+        }
+    }
+
     /**
      * @hide for reuse by CertInstaller and Settings.
      * @see KeyChain#bind
@@ -547,11 +589,8 @@
         Intent intent = new Intent(IKeyChainService.class.getName());
         ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
         intent.setComponent(comp);
-        boolean isBound = context.bindServiceAsUser(intent,
-                                                    keyChainServiceConnection,
-                                                    Context.BIND_AUTO_CREATE,
-                                                    user);
-        if (!isBound) {
+        if (comp == null || !context.bindServiceAsUser(
+                intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) {
             throw new AssertionError("could not bind to KeyChainService");
         }
         return new KeyChainConnection(context, keyChainServiceConnection, q.take());
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 3090ac1..70e4b6f 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -183,7 +183,8 @@
 
     public boolean delete(String key, int uid) {
         try {
-            return mBinder.del(key, uid) == NO_ERROR;
+            int ret = mBinder.del(key, uid);
+            return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
index 156f45f6..be390ff 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
@@ -193,12 +193,12 @@
         putSignatureImpl("NONEwithECDSA",
                 PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE");
 
-        putSignatureImpl("ECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
-        put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
-        put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
+        putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
+        put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
+        put("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA");
         // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1)
-        put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "ECDSA");
+        put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
+        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "SHA1withECDSA");
 
         // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
         putSignatureImpl("SHA224withECDSA",
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 1321a83..b234d0f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -234,7 +234,8 @@
                 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
                         spec.isUserAuthenticationRequired(),
                         spec.getUserAuthenticationValidityDurationSeconds(),
-                        spec.isUserAuthenticationValidWhileOnBody());
+                        spec.isUserAuthenticationValidWhileOnBody(),
+                        spec.isInvalidatedByBiometricEnrollment());
             } catch (IllegalStateException | IllegalArgumentException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
@@ -273,7 +274,8 @@
         KeymasterUtils.addUserAuthArgs(args,
                 spec.isUserAuthenticationRequired(),
                 spec.getUserAuthenticationValidityDurationSeconds(),
-                spec.isUserAuthenticationValidWhileOnBody());
+                spec.isUserAuthenticationValidWhileOnBody(),
+                spec.isInvalidatedByBiometricEnrollment());
         KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
                 args,
                 mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 830402a..1818f52 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -345,7 +345,8 @@
                 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
                         mSpec.isUserAuthenticationRequired(),
                         mSpec.getUserAuthenticationValidityDurationSeconds(),
-                        mSpec.isUserAuthenticationValidWhileOnBody());
+                        mSpec.isUserAuthenticationValidWhileOnBody(),
+                        mSpec.isInvalidatedByBiometricEnrollment());
             } catch (IllegalArgumentException | IllegalStateException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
@@ -531,7 +532,8 @@
         KeymasterUtils.addUserAuthArgs(args,
                 mSpec.isUserAuthenticationRequired(),
                 mSpec.getUserAuthenticationValidityDurationSeconds(),
-                mSpec.isUserAuthenticationValidWhileOnBody());
+                mSpec.isUserAuthenticationValidWhileOnBody(),
+                mSpec.isInvalidatedByBiometricEnrollment());
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
                 mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 5f5f2c2..0379863 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -17,10 +17,12 @@
 package android.security.keystore;
 
 import android.security.Credentials;
+import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterDefs;
 
+import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.ProviderException;
 import java.security.spec.InvalidKeySpecException;
@@ -91,6 +93,7 @@
         @KeyProperties.BlockModeEnum String[] blockModes;
         int keymasterSwEnforcedUserAuthenticators;
         int keymasterHwEnforcedUserAuthenticators;
+        List<BigInteger> keymasterSecureUserIds;
         try {
             if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 insideSecureHardware = true;
@@ -147,6 +150,8 @@
                     keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
             keymasterHwEnforcedUserAuthenticators =
                     keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+            keymasterSecureUserIds =
+                keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
         } catch (IllegalArgumentException e) {
             throw new ProviderException("Unsupported key characteristic", e);
         }
@@ -170,6 +175,15 @@
         boolean userAuthenticationValidWhileOnBody =
                 keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
 
+        boolean invalidatedByBiometricEnrollment = false;
+        if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT
+            || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT) {
+            // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
+            invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
+                    && !keymasterSecureUserIds.isEmpty()
+                    && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
+        }
+
         return new KeyInfo(entryAlias,
                 insideSecureHardware,
                 origin,
@@ -185,7 +199,16 @@
                 userAuthenticationRequired,
                 (int) userAuthenticationValidityDurationSeconds,
                 userAuthenticationRequirementEnforcedBySecureHardware,
-                userAuthenticationValidWhileOnBody);
+                userAuthenticationValidWhileOnBody,
+                invalidatedByBiometricEnrollment);
+    }
+
+    private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
+    	try {
+    		return BigInteger.valueOf(GateKeeper.getSecureUserId());
+    	} catch (IllegalStateException e) {
+    		throw new ProviderException("Failed to get GateKeeper secure user ID", e);
+    	}
     }
 
     @Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index d660020..fcbb553 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -499,7 +499,8 @@
                 KeymasterUtils.addUserAuthArgs(importArgs,
                         spec.isUserAuthenticationRequired(),
                         spec.getUserAuthenticationValidityDurationSeconds(),
-                        spec.isUserAuthenticationValidWhileOnBody());
+                        spec.isUserAuthenticationValidWhileOnBody(),
+                        spec.isInvalidatedByBiometricEnrollment());
                 importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
                         spec.getKeyValidityStart());
                 importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -694,7 +695,8 @@
             KeymasterUtils.addUserAuthArgs(args,
                     params.isUserAuthenticationRequired(),
                     params.getUserAuthenticationValidityDurationSeconds(),
-                    params.isUserAuthenticationValidWhileOnBody());
+                    params.isUserAuthenticationValidWhileOnBody(),
+                    params.isInvalidatedByBiometricEnrollment());
             KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
                     args,
                     keymasterAlgorithm,
@@ -763,11 +765,6 @@
 
     @Override
     public void engineDeleteEntry(String alias) throws KeyStoreException {
-        if (!engineContainsAlias(alias)) {
-            return;
-        }
-        // At least one entry corresponding to this alias exists in keystore
-
         if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid)) {
             throw new KeyStoreException("Failed to delete entry: " + alias);
         }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index a84e7f34..127d756 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -253,6 +253,7 @@
     private final byte[] mAttestationChallenge;
     private final boolean mUniqueIdIncluded;
     private final boolean mUserAuthenticationValidWhileOnBody;
+    private final boolean mInvalidatedByBiometricEnrollment;
 
     /**
      * @hide should be built with Builder
@@ -279,7 +280,8 @@
             int userAuthenticationValidityDurationSeconds,
             byte[] attestationChallenge,
             boolean uniqueIdIncluded,
-            boolean userAuthenticationValidWhileOnBody) {
+            boolean userAuthenticationValidWhileOnBody,
+            boolean invalidatedByBiometricEnrollment) {
         if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
         }
@@ -324,6 +326,7 @@
         mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
         mUniqueIdIncluded = uniqueIdIncluded;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+        mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
     }
 
     /**
@@ -607,6 +610,19 @@
     }
 
     /**
+     * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
+     * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
+     * require fingerprint user authentication for every use.
+     *
+     * @see #isUserAuthenticationRequired()
+     * @see #getUserAuthenticationValidityDurationSeconds()
+     * @see Builder#setInvalidatedByBiometricEnrollment(boolean)
+     */
+    public boolean isInvalidatedByBiometricEnrollment() {
+        return mInvalidatedByBiometricEnrollment;
+    }
+
+    /**
      * Builder of {@link KeyGenParameterSpec} instances.
      */
     public final static class Builder {
@@ -633,6 +649,7 @@
         private byte[] mAttestationChallenge = null;
         private boolean mUniqueIdIncluded = false;
         private boolean mUserAuthenticationValidWhileOnBody;
+        private boolean mInvalidatedByBiometricEnrollment = true;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -966,8 +983,10 @@
          * or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
          * Additionally, if the key requires that user authentication takes place for every use of
          * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
-         * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
-         * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
+         * no more fingerprints are enrolled, unless {@link
+         * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
+         * enrollment. Attempts to initialize cryptographic operations using such keys will throw
+         * {@link KeyPermanentlyInvalidatedException}.</li>
          * </ul>
          *
          * <p>This authorization applies only to secret key and private key operations. Public key
@@ -1110,6 +1129,30 @@
         }
 
         /**
+         * Sets whether this key should be invalidated on fingerprint enrollment.  This
+         * applies only to keys which require user authentication (see {@link
+         * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
+         * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
+         * valid for fingerprint authentication only.
+         *
+         * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
+         * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
+         * fingerprint is enrolled, or when all existing fingerprints are deleted.  That may be
+         * changed by calling this method with {@code invalidateKey} set to {@code false}.
+         *
+         * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+         * improves security by ensuring that an unauthorized person who obtains the password can't
+         * gain the use of fingerprint-authenticated keys by enrolling their own finger.  However,
+         * invalidating keys makes key-dependent operations impossible, requiring some fallback
+         * procedure to authenticate the user and set up a new key.
+         */
+        @NonNull
+        public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
+            mInvalidatedByBiometricEnrollment = invalidateKey;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@code KeyGenParameterSpec}.
          */
         @NonNull
@@ -1136,7 +1179,8 @@
                     mUserAuthenticationValidityDurationSeconds,
                     mAttestationChallenge,
                     mUniqueIdIncluded,
-                    mUserAuthenticationValidWhileOnBody);
+                    mUserAuthenticationValidWhileOnBody,
+                    mInvalidatedByBiometricEnrollment);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index f77b5ba..fa6d8b3 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -80,6 +80,7 @@
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
     private final boolean mUserAuthenticationValidWhileOnBody;
+    private final boolean mInvalidatedByBiometricEnrollment;
 
     /**
      * @hide
@@ -99,7 +100,8 @@
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
             boolean userAuthenticationRequirementEnforcedBySecureHardware,
-            boolean userAuthenticationValidWhileOnBody) {
+            boolean userAuthenticationValidWhileOnBody,
+            boolean invalidatedByBiometricEnrollment) {
         mKeystoreAlias = keystoreKeyAlias;
         mInsideSecureHardware = insideSecureHardware;
         mOrigin = origin;
@@ -119,6 +121,7 @@
         mUserAuthenticationRequirementEnforcedBySecureHardware =
                 userAuthenticationRequirementEnforcedBySecureHardware;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+        mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
     }
 
     /**
@@ -290,4 +293,12 @@
     public boolean isUserAuthenticationValidWhileOnBody() {
         return mUserAuthenticationValidWhileOnBody;
     }
+
+    /**
+     * Returns {@code true} if the key will be invalidated by enrollment of a new fingerprint or
+     * removal of all fingerprints.
+     */
+    public boolean isInvalidatedByBiometricEnrollment() {
+        return mInvalidatedByBiometricEnrollment;
+    }
 }
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 4700b68..fa57bdb 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -215,6 +215,7 @@
     private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mUserAuthenticationValidWhileOnBody;
+    private final boolean mInvalidatedByBiometricEnrollment;
 
     private KeyProtection(
             Date keyValidityStart,
@@ -228,7 +229,8 @@
             boolean randomizedEncryptionRequired,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
-            boolean userAuthenticationValidWhileOnBody) {
+            boolean userAuthenticationValidWhileOnBody,
+            boolean invalidatedByBiometricEnrollment) {
         mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
         mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
         mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -243,6 +245,7 @@
         mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+        mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
     }
 
     /**
@@ -412,6 +415,19 @@
     }
 
     /**
+     * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
+     * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
+     * require fingerprint user authentication for every use.
+     *
+     * @see #isUserAuthenticationRequired()
+     * @see #getUserAuthenticationValidityDurationSeconds()
+     * @see Builder#setInvalidatedByBiometricEnrollment(boolean)
+     */
+    public boolean isInvalidatedByBiometricEnrollment() {
+        return mInvalidatedByBiometricEnrollment;
+    }
+
+    /**
      * Builder of {@link KeyProtection} instances.
      */
     public final static class Builder {
@@ -428,6 +444,7 @@
         private boolean mUserAuthenticationRequired;
         private int mUserAuthenticationValidityDurationSeconds = -1;
         private boolean mUserAuthenticationValidWhileOnBody;
+        private boolean mInvalidatedByBiometricEnrollment = true;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -638,9 +655,10 @@
          * or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
          * Additionally, if the key requires that user authentication takes place for every use of
          * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
-         * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
-         * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
-         * </ul>
+         * no more fingerprints are enrolled, unless {@link
+         * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
+         * enrollment. Attempts to initialize cryptographic operations using such keys will throw
+         * {@link KeyPermanentlyInvalidatedException}.</li> </ul>
          *
          * <p>This authorization applies only to secret key and private key operations. Public key
          * operations are not restricted.
@@ -729,6 +747,30 @@
         }
 
         /**
+         * Sets whether this key should be invalidated on fingerprint enrollment.  This
+         * applies only to keys which require user authentication (see {@link
+         * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
+         * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
+         * valid for fingerprint authentication only.
+         *
+         * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
+         * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
+         * fingerprint is enrolled, or when all existing fingerprints are deleted.  That may be
+         * changed by calling this method with {@code invalidateKey} set to {@code false}.
+         *
+         * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+         * improves security by ensuring that an unauthorized person who obtains the password can't
+         * gain the use of fingerprint-authenticated keys by enrolling their own finger.  However,
+         * invalidating keys makes key-dependent operations impossible, requiring some fallback
+         * procedure to authenticate the user and set up a new key.
+         */
+        @NonNull
+        public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
+            mInvalidatedByBiometricEnrollment = invalidateKey;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@link KeyProtection}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -747,7 +789,8 @@
                     mRandomizedEncryptionRequired,
                     mUserAuthenticationRequired,
                     mUserAuthenticationValidityDurationSeconds,
-                    mUserAuthenticationValidWhileOnBody);
+                    mUserAuthenticationValidWhileOnBody,
+                    mInvalidatedByBiometricEnrollment);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 3a008bc..f5272aa 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -97,7 +97,8 @@
     public static void addUserAuthArgs(KeymasterArguments args,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
-            boolean userAuthenticationValidWhileOnBody) {
+            boolean userAuthenticationValidWhileOnBody,
+            boolean invalidatedByBiometricEnrollment) {
         if (!userAuthenticationRequired) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
             return;
@@ -117,8 +118,20 @@
                         "At least one fingerprint must be enrolled to create keys requiring user"
                         + " authentication for every use");
             }
-            args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
-                    KeymasterArguments.toUint64(fingerprintOnlySid));
+
+            long sid;
+            if (invalidatedByBiometricEnrollment) {
+                // The fingerprint-only SID will change on fingerprint enrollment or removal of all,
+                // enrolled fingerprints, invalidating the key.
+                sid = fingerprintOnlySid;
+            } else {
+                // The root SID will *not* change on fingerprint enrollment, or removal of all
+                // enrolled fingerprints, allowing the key to remain valid.
+                sid = getRootSid();
+            }
+
+            args.addUnsignedLong(
+                    KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
             args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
             if (userAuthenticationValidWhileOnBody) {
                 throw new ProviderException("Key validity extension while device is on-body is not "
@@ -127,11 +140,7 @@
         } else {
             // The key is authorized for use for the specified amount of time after the user has
             // authenticated. Whatever unlocks the secure lock screen should authorize this key.
-            long rootSid = GateKeeper.getSecureUserId();
-            if (rootSid == 0) {
-                throw new IllegalStateException("Secure lock screen must be enabled"
-                        + " to create keys requiring user authentication");
-            }
+            long rootSid = getRootSid();
             args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
                     KeymasterArguments.toUint64(rootSid));
             args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
@@ -184,4 +193,13 @@
                 break;
         }
     }
+
+    private static long getRootSid() {
+        long rootSid = GateKeeper.getSecureUserId();
+        if (rootSid == 0) {
+            throw new IllegalStateException("Secure lock screen must be enabled"
+                    + " to create keys requiring user authentication");
+        }
+        return rootSid;
+    }
 }
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 3277c36..1ccc59a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include <limits>
+#include <memory>
 #include <type_traits>
 
 #include <androidfw/ByteBucketArray.h>
@@ -1869,8 +1870,8 @@
 
     // The language & region are equal, so compare the scripts and variants.
     const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
-    const char *lScript = l.localeScriptWasProvided ? l.localeScript : emptyScript;
-    const char *rScript = r.localeScriptWasProvided ? r.localeScript : emptyScript;
+    const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript;
+    const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript;
     int script = memcmp(lScript, rScript, sizeof(l.localeScript));
     if (script) {
         return script;
@@ -2015,11 +2016,11 @@
     // scripts since it seems more useful to do so. We will consider
     // "en-US-POSIX" to be more specific than "en-Latn-US".
 
-    const int score = (localeScriptWasProvided ? 1 : 0) +
-        ((localeVariant[0] != 0) ? 2 : 0);
+    const int score = ((localeScript[0] != '\0' && !localeScriptWasComputed) ? 1 : 0) +
+        ((localeVariant[0] != '\0') ? 2 : 0);
 
-    const int oScore = (o.localeScriptWasProvided ? 1 : 0) +
-        ((o.localeVariant[0] != 0) ? 2 : 0);
+    const int oScore = (o.localeScript[0] != '\0' && !o.localeScriptWasComputed ? 1 : 0) +
+        ((o.localeVariant[0] != '\0') ? 2 : 0);
 
     return score - oScore;
 
@@ -2534,7 +2535,8 @@
         if (settings.localeScript[0] == '\0') { // could not determine the request's script
             countriesMustMatch = true;
         } else {
-            if (localeScript[0] == '\0') { // script was not provided, so we try to compute it
+            if (localeScript[0] == '\0' && !localeScriptWasComputed) {
+                // script was not provided or computed, so we try to compute it
                 localeDataComputeScript(computed_script, language, country);
                 if (computed_script[0] == '\0') { // we could not compute the script
                     countriesMustMatch = true;
@@ -2683,8 +2685,8 @@
     if (!language[0]) {
         return;
     }
-
-    if (!localeScriptWasProvided && !localeVariant[0]) {
+    const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed;
+    if (!scriptWasProvided && !localeVariant[0]) {
         // Legacy format.
         if (out.size() > 0) {
             out.append("-");
@@ -2714,7 +2716,7 @@
     size_t len = unpackLanguage(buf);
     out.append(buf, len);
 
-    if (localeScriptWasProvided) {
+    if (scriptWasProvided) {
         out.append("+");
         out.append(localeScript, sizeof(localeScript));
     }
@@ -2745,7 +2747,7 @@
         charsWritten += unpackLanguage(str);
     }
 
-    if (localeScriptWasProvided) {
+    if (localeScript[0] && !localeScriptWasComputed) {
         if (charsWritten) {
             str[charsWritten++] = '-';
         }
@@ -2786,7 +2788,6 @@
                for (size_t i = 1; i < 4; ++i) {
                    config->localeScript[i] = tolower(start[i]);
                }
-               config->localeScriptWasProvided = true;
                break;
            }
        case 5:
@@ -2806,7 +2807,6 @@
 
 void ResTable_config::setBcp47Locale(const char* in) {
     locale = 0;
-    localeScriptWasProvided = false;
     memset(localeScript, 0, sizeof(localeScript));
     memset(localeVariant, 0, sizeof(localeVariant));
 
@@ -2823,9 +2823,10 @@
 
     const size_t size = in + strlen(in) - start;
     assignLocaleComponent(this, start, size);
-    if (localeScript[0] == '\0') {
+    localeScriptWasComputed = (localeScript[0] == '\0');
+    if (localeScriptWasComputed) {
         computeScript();
-    };
+    }
 }
 
 String8 ResTable_config::toString() const {
@@ -3193,7 +3194,6 @@
         , name(_name)
         , id(_id)
         , largestTypeId(0)
-        , bags(NULL)
         , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
         , isSystemAsset(_isSystemAsset)
     { }
@@ -3220,36 +3220,41 @@
         }
     }
 
+    /**
+     * Clear all cache related data that depends on parameters/configuration.
+     * This includes the bag caches and filtered types.
+     */
     void clearBagCache() {
-        if (bags) {
+        for (size_t i = 0; i < typeCacheEntries.size(); i++) {
             if (kDebugTableNoisy) {
-                printf("bags=%p\n", bags);
+                printf("type=%zu\n", i);
             }
-            for (size_t i = 0; i < bags->size(); i++) {
+            const TypeList& typeList = types[i];
+            if (!typeList.isEmpty()) {
+                TypeCacheEntry& cacheEntry = typeCacheEntries.editItemAt(i);
+
+                // Reset the filtered configurations.
+                cacheEntry.filteredConfigs.clear();
+
+                bag_set** typeBags = cacheEntry.cachedBags;
                 if (kDebugTableNoisy) {
-                    printf("type=%zu\n", i);
+                    printf("typeBags=%p\n", typeBags);
                 }
-                const TypeList& typeList = types[i];
-                if (!typeList.isEmpty()) {
-                    bag_set** typeBags = bags->get(i);
+
+                if (typeBags) {
+                    const size_t N = typeList[0]->entryCount;
                     if (kDebugTableNoisy) {
-                        printf("typeBags=%p\n", typeBags);
+                        printf("type->entryCount=%zu\n", N);
                     }
-                    if (typeBags) {
-                        const size_t N = typeList[0]->entryCount;
-                        if (kDebugTableNoisy) {
-                            printf("type->entryCount=%zu\n", N);
+                    for (size_t j = 0; j < N; j++) {
+                        if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF) {
+                            free(typeBags[j]);
                         }
-                        for (size_t j = 0; j < N; j++) {
-                            if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
-                                free(typeBags[j]);
-                        }
-                        free(typeBags);
                     }
+                    free(typeBags);
+                    cacheEntry.cachedBags = NULL;
                 }
             }
-            delete bags;
-            bags = NULL;
         }
     }
 
@@ -3277,9 +3282,11 @@
 
     uint8_t                         largestTypeId;
 
-    // Computed attribute bags, first indexed by the type and second
-    // by the entry in that type.
-    ByteBucketArray<bag_set**>*     bags;
+    // Cached objects dependent on the parameters/configuration of this ResTable.
+    // Gets cleared whenever the parameters/configuration changes.
+    // These are stored here in a parallel structure because the data in `types` may
+    // be shared by other ResTable's (framework resources are shared this way).
+    ByteBucketArray<TypeCacheEntry> typeCacheEntries;
 
     // The table mapping dynamic references to resolved references for
     // this package group.
@@ -3293,14 +3300,6 @@
     const bool                      isSystemAsset;
 };
 
-struct ResTable::bag_set
-{
-    size_t numAttrs;    // number in array
-    size_t availAttrs;  // total space in array
-    uint32_t typeSpecFlags;
-    // Followed by 'numAttr' bag_entry structures.
-};
-
 ResTable::Theme::Theme(const ResTable& table)
     : mTable(table)
     , mTypeSpecFlags(0)
@@ -3936,7 +3935,9 @@
         if (Res_GETPACKAGE(resID)+1 == 0) {
             ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
         } else {
+#ifndef STATIC_ANDROIDFW_FOR_TOOLS
             ALOGW("No known package when getting name for resource number 0x%08x", resID);
+#endif
         }
         return false;
     }
@@ -4192,39 +4193,32 @@
     }
 
     // First see if we've already computed this bag...
-    if (grp->bags) {
-        bag_set** typeSet = grp->bags->get(t);
-        if (typeSet) {
-            bag_set* set = typeSet[e];
-            if (set) {
-                if (set != (bag_set*)0xFFFFFFFF) {
-                    if (outTypeSpecFlags != NULL) {
-                        *outTypeSpecFlags = set->typeSpecFlags;
-                    }
-                    *outBag = (bag_entry*)(set+1);
-                    if (kDebugTableSuperNoisy) {
-                        ALOGI("Found existing bag for: 0x%x\n", resID);
-                    }
-                    return set->numAttrs;
+    TypeCacheEntry& cacheEntry = grp->typeCacheEntries.editItemAt(t);
+    bag_set** typeSet = cacheEntry.cachedBags;
+    if (typeSet) {
+        bag_set* set = typeSet[e];
+        if (set) {
+            if (set != (bag_set*)0xFFFFFFFF) {
+                if (outTypeSpecFlags != NULL) {
+                    *outTypeSpecFlags = set->typeSpecFlags;
                 }
-                ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
-                     resID);
-                return BAD_INDEX;
+                *outBag = (bag_entry*)(set+1);
+                if (kDebugTableSuperNoisy) {
+                    ALOGI("Found existing bag for: 0x%x\n", resID);
+                }
+                return set->numAttrs;
             }
+            ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
+                 resID);
+            return BAD_INDEX;
         }
     }
 
     // Bag not found, we need to compute it!
-    if (!grp->bags) {
-        grp->bags = new ByteBucketArray<bag_set**>();
-        if (!grp->bags) return NO_MEMORY;
-    }
-
-    bag_set** typeSet = grp->bags->get(t);
     if (!typeSet) {
         typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
         if (!typeSet) return NO_MEMORY;
-        grp->bags->set(t, typeSet);
+        cacheEntry.cachedBags = typeSet;
     }
 
     // Mark that we are currently working on this one.
@@ -4430,18 +4424,56 @@
 
 void ResTable::setParameters(const ResTable_config* params)
 {
-    mLock.lock();
+    AutoMutex _lock(mLock);
+    AutoMutex _lock2(mFilteredConfigLock);
+
     if (kDebugTableGetEntry) {
         ALOGI("Setting parameters: %s\n", params->toString().string());
     }
     mParams = *params;
-    for (size_t i=0; i<mPackageGroups.size(); i++) {
+    for (size_t p = 0; p < mPackageGroups.size(); p++) {
+        PackageGroup* packageGroup = mPackageGroups.editItemAt(p);
         if (kDebugTableNoisy) {
-            ALOGI("CLEARING BAGS FOR GROUP %zu!", i);
+            ALOGI("CLEARING BAGS FOR GROUP %zu!", p);
         }
-        mPackageGroups[i]->clearBagCache();
+        packageGroup->clearBagCache();
+
+        // Find which configurations match the set of parameters. This allows for a much
+        // faster lookup in getEntry() if the set of values is narrowed down.
+        for (size_t t = 0; t < packageGroup->types.size(); t++) {
+            if (packageGroup->types[t].isEmpty()) {
+                continue;
+            }
+
+            TypeList& typeList = packageGroup->types.editItemAt(t);
+
+            // Retrieve the cache entry for this type.
+            TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries.editItemAt(t);
+
+            for (size_t ts = 0; ts < typeList.size(); ts++) {
+                Type* type = typeList.editItemAt(ts);
+
+                std::shared_ptr<Vector<const ResTable_type*>> newFilteredConfigs =
+                        std::make_shared<Vector<const ResTable_type*>>();
+
+                for (size_t ti = 0; ti < type->configs.size(); ti++) {
+                    ResTable_config config;
+                    config.copyFromDtoH(type->configs[ti]->config);
+
+                    if (config.match(mParams)) {
+                        newFilteredConfigs->add(type->configs[ti]);
+                    }
+                }
+
+                if (kDebugTableNoisy) {
+                    ALOGD("Updating pkg=%zu type=%zu with %zu filtered configs",
+                          p, t, newFilteredConfigs->size());
+                }
+
+                cacheEntry.filteredConfigs.add(newFilteredConfigs);
+            }
+        }
     }
-    mLock.unlock();
 }
 
 void ResTable::getParameters(ResTable_config* params) const
@@ -5974,9 +6006,32 @@
             specFlags = -1;
         }
 
-        const size_t numConfigs = typeSpec->configs.size();
+        const Vector<const ResTable_type*>* candidateConfigs = &typeSpec->configs;
+
+        std::shared_ptr<Vector<const ResTable_type*>> filteredConfigs;
+        if (config && memcmp(&mParams, config, sizeof(mParams)) == 0) {
+            // Grab the lock first so we can safely get the current filtered list.
+            AutoMutex _lock(mFilteredConfigLock);
+
+            // This configuration is equal to the one we have previously cached for,
+            // so use the filtered configs.
+
+            const TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries[typeIndex];
+            if (i < cacheEntry.filteredConfigs.size()) {
+                if (cacheEntry.filteredConfigs[i]) {
+                    // Grab a reference to the shared_ptr so it doesn't get destroyed while
+                    // going through this list.
+                    filteredConfigs = cacheEntry.filteredConfigs[i];
+
+                    // Use this filtered list.
+                    candidateConfigs = filteredConfigs.get();
+                }
+            }
+        }
+
+        const size_t numConfigs = candidateConfigs->size();
         for (size_t c = 0; c < numConfigs; c++) {
-            const ResTable_type* const thisType = typeSpec->configs[c];
+            const ResTable_type* const thisType = candidateConfigs->itemAt(c);
             if (thisType == NULL) {
                 continue;
             }
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 4b8d65c..2bf9b12 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -125,10 +125,10 @@
 
      if (script != NULL) {
          memcpy(out->localeScript, script, 4);
-         out->localeScriptWasProvided = true;
+         out->localeScriptWasComputed = false;
      } else {
          out->computeScript();
-         out->localeScriptWasProvided = false;
+         out->localeScriptWasComputed = true;
      }
 
      if (variant != NULL) {
@@ -182,7 +182,7 @@
     EXPECT_EQ('n', test.language[1]);
     EXPECT_EQ('U', test.country[0]);
     EXPECT_EQ('S', test.country[1]);
-    EXPECT_FALSE(test.localeScriptWasProvided);
+    EXPECT_TRUE(test.localeScriptWasComputed);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
     EXPECT_EQ(0, test.localeVariant[0]);
 
@@ -203,7 +203,7 @@
     EXPECT_EQ('e', test.language[0]);
     EXPECT_EQ('n', test.language[1]);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
-    EXPECT_TRUE(test.localeScriptWasProvided);
+    EXPECT_FALSE(test.localeScriptWasComputed);
     memset(out, 1, 4);
     test.unpackRegion(out);
     EXPECT_EQ('4', out[0]);
@@ -216,7 +216,7 @@
     EXPECT_EQ('d', out[0]);
     EXPECT_EQ('e', out[1]);
     EXPECT_EQ('\0', out[2]);
-    EXPECT_FALSE(test.localeScriptWasProvided);
+    EXPECT_TRUE(test.localeScriptWasComputed);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
     memset(out, 1, 4);
     test.unpackRegion(out);
@@ -229,7 +229,7 @@
     EXPECT_EQ('d', out[0]);
     EXPECT_EQ('e', out[1]);
     EXPECT_EQ('\0', out[2]);
-    EXPECT_TRUE(test.localeScriptWasProvided);
+    EXPECT_FALSE(test.localeScriptWasComputed);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
     memset(out, 1, 4);
     test.unpackRegion(out);
@@ -270,11 +270,11 @@
     fillIn("en", NULL, "Latn", NULL, &config);
 
     char out[RESTABLE_MAX_LOCALE_LEN];
-    config.localeScriptWasProvided = true;
+    config.localeScriptWasComputed = false;
     config.getBcp47Locale(out);
     EXPECT_EQ(0, strcmp("en-Latn", out));
 
-    config.localeScriptWasProvided = false;
+    config.localeScriptWasComputed = true;
     config.getBcp47Locale(out);
     EXPECT_EQ(0, strcmp("en", out));
 }
@@ -379,7 +379,7 @@
 
     // emulate packages built with older AAPT
     memset(supported.localeScript, '\0', 4);
-    supported.localeScriptWasProvided = false;
+    supported.localeScriptWasComputed = false;
 
     EXPECT_TRUE(supported.match(requested));
 }
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index dcfe91e..7cd7fb5 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -282,4 +282,46 @@
     testU16StringToInt(u"0x1ffffffff", 0U, false, true);
 }
 
+TEST(ResTableTest, ShareButDontModifyResTable) {
+    ResTable sharedTable;
+    ASSERT_EQ(NO_ERROR, sharedTable.add(basic_arsc, basic_arsc_len));
+
+    ResTable_config param;
+    memset(&param, 0, sizeof(param));
+    param.language[0] = 'v';
+    param.language[1] = 's';
+    sharedTable.setParameters(&param);
+
+    // Check that we get the default value for @integer:number1
+    Res_value val;
+    ssize_t block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+    ASSERT_EQ(uint32_t(600), val.data);
+
+    // Create a new table that shares the entries of the shared table.
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(&sharedTable, false));
+
+    // Set a new configuration on the new table.
+    memset(&param, 0, sizeof(param));
+    param.language[0] = 's';
+    param.language[1] = 'v';
+    param.country[0] = 'S';
+    param.country[1] = 'E';
+    table.setParameters(&param);
+
+    // Check that we get a new value in the new table.
+    block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+    ASSERT_EQ(uint32_t(400), val.data);
+
+    // Check that we still get the old value in the shared table.
+    block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
+    ASSERT_GE(block, 0);
+    ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+    ASSERT_EQ(uint32_t(600), val.data);
 }
+
+} // namespace
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index aaac740..6694dd0 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -46,7 +46,7 @@
 
 namespace integer {
     enum {
-        number1     = 0x7f040000,   // default, sv
+        number1     = 0x7f040000,   // default, sv, vs
         number2     = 0x7f040001,   // default
 
         test3       = 0x7f090000,   // default (in feature)
diff --git a/libs/androidfw/tests/data/basic/basic_arsc.h b/libs/androidfw/tests/data/basic/basic_arsc.h
index 13ab4fa..e497401 100644
--- a/libs/androidfw/tests/data/basic/basic_arsc.h
+++ b/libs/androidfw/tests/data/basic/basic_arsc.h
@@ -1,5 +1,5 @@
 unsigned char basic_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x68, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x0c, 0x00, 0x0c, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x1c, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
@@ -16,7 +16,7 @@
   0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
   0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
   0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
-  0xa0, 0x06, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+  0x44, 0x07, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
   0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
   0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
   0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
@@ -73,68 +73,81 @@
   0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00,
-  0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
-  0x05, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00,
-  0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+  0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+  0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02,
+  0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
   0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
   0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x4c, 0x00, 0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x4c, 0x00, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0x06, 0x7f, 0x01, 0x02, 0x44, 0x00, 0x5c, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+  0xc8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x7f, 0x01, 0x02, 0x4c, 0x00,
+  0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x76, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x90, 0x01, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x44, 0x00, 0x90, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x58, 0x02, 0x00, 0x00,
+  0x01, 0x02, 0x4c, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+  0x90, 0x01, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x98, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -146,16 +159,17 @@
   0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x7f, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x00,
   0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
-  0x7c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+  0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
-  0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
+  0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02,
+  0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00
 };
-unsigned int basic_arsc_len = 1896;
+unsigned int basic_arsc_len = 2060;
diff --git a/libs/androidfw/tests/data/basic/res/values-vs/values.xml b/libs/androidfw/tests/data/basic/res/values-vs/values.xml
new file mode 100644
index 0000000..4a5a640
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/res/values-vs/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>
+    <integer name="number1">600</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h b/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
index b742d28..a2aa598 100644
--- a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
@@ -1,5 +1,5 @@
 unsigned char split_de_fr_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x0c, 0x00, 0xf4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
@@ -10,7 +10,7 @@
   0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00,
   0x61, 0x00, 0x69, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00,
   0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x69, 0x00, 0x20, 0x00,
-  0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x5c, 0x03, 0x00, 0x00,
+  0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x6c, 0x03, 0x00, 0x00,
   0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
   0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
   0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
@@ -57,30 +57,32 @@
   0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00,
   0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
-  0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+  0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x64, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+  0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+  0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00
 };
-unsigned int split_de_fr_arsc_len = 996;
+unsigned int split_de_fr_arsc_len = 1012;
diff --git a/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
index e9fb7ea..0cc3915 100644
--- a/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
@@ -1,10 +1,10 @@
 unsigned char split_hdpi_v4_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x08, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x0c, 0x00, 0x10, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00,
   0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
-  0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+  0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
   0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
   0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
   0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
@@ -50,19 +50,20 @@
   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
   0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00
 };
-unsigned int split_hdpi_v4_arsc_len = 776;
+unsigned int split_hdpi_v4_arsc_len = 784;
diff --git a/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
index 7835f71..d44ba96 100644
--- a/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
@@ -1,10 +1,10 @@
 unsigned char split_xhdpi_v4_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x0c, 0x00, 0x14, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x78, 0x00,
   0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x02, 0x20, 0x01, 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x20, 0x01, 0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
   0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00,
   0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00,
   0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00,
@@ -50,19 +50,20 @@
   0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
   0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
-unsigned int split_xhdpi_v4_arsc_len = 780;
+unsigned int split_xhdpi_v4_arsc_len = 788;
diff --git a/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
index f805db1..2f3f682 100644
--- a/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
@@ -1,10 +1,10 @@
 unsigned char split_xxhdpi_v4_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x0c, 0x00, 0x14, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x78, 0x00,
   0x78, 0x00, 0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00,
-  0x00, 0x02, 0x20, 0x01, 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x20, 0x01, 0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
   0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00,
   0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00,
   0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00,
@@ -50,19 +50,20 @@
   0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
   0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
-unsigned int split_xxhdpi_v4_arsc_len = 780;
+unsigned int split_xxhdpi_v4_arsc_len = 788;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8660b75..be816f7 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -12,6 +12,11 @@
 hwui_src_files := \
     font/CacheTexture.cpp \
     font/Font.cpp \
+    hwui/Canvas.cpp \
+    hwui/MinikinSkia.cpp \
+    hwui/MinikinUtils.cpp \
+    hwui/PaintImpl.cpp \
+    hwui/Typeface.cpp \
     renderstate/Blend.cpp \
     renderstate/MeshState.cpp \
     renderstate/OffscreenBufferPool.cpp \
@@ -41,7 +46,6 @@
     AnimatorManager.cpp \
     AssetAtlas.cpp \
     Caches.cpp \
-    Canvas.cpp \
     CanvasState.cpp \
     ClipArea.cpp \
     DamageAccumulator.cpp \
@@ -119,6 +123,7 @@
         BakedOpState.cpp \
         FrameBuilder.cpp \
         LayerBuilder.cpp \
+        OpDumper.cpp \
         RecordingCanvas.cpp
 
     hwui_cflags += -DHWUI_NEW_OPS
@@ -142,7 +147,9 @@
 
 hwui_c_includes += \
     external/skia/include/private \
-    external/skia/src/core
+    external/skia/src/core \
+    external/harfbuzz_ng/src \
+    external/freetype/include
 
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
     hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
@@ -226,22 +233,26 @@
 LOCAL_MODULE := hwui_unit_tests
 LOCAL_MODULE_TAGS := tests
 LOCAL_STATIC_LIBRARIES := libhwui_static_null_gpu
+LOCAL_SHARED_LIBRARIES := libmemunreachable
 LOCAL_CFLAGS := \
         $(hwui_cflags) \
         -DHWUI_NULL_GPU
 
 LOCAL_SRC_FILES += \
     $(hwui_test_common_src_files) \
+    tests/unit/main.cpp \
     tests/unit/CanvasStateTests.cpp \
     tests/unit/ClipAreaTests.cpp \
-    tests/unit/CrashHandlerInjector.cpp \
     tests/unit/DamageAccumulatorTests.cpp \
     tests/unit/DeviceInfoTests.cpp \
     tests/unit/FatVectorTests.cpp \
+    tests/unit/GlopBuilderTests.cpp \
     tests/unit/GpuMemoryTrackerTests.cpp \
     tests/unit/LayerUpdateQueueTests.cpp \
     tests/unit/LinearAllocatorTests.cpp \
+    tests/unit/MatrixTests.cpp \
     tests/unit/OffscreenBufferPoolTests.cpp \
+    tests/unit/RenderNodeTests.cpp \
     tests/unit/SkiaBehaviorTests.cpp \
     tests/unit/StringUtilsTests.cpp \
     tests/unit/TextDropShadowCacheTests.cpp \
@@ -250,10 +261,14 @@
 
 ifeq (true, $(HWUI_NEW_OPS))
     LOCAL_SRC_FILES += \
+        tests/unit/BakedOpDispatcherTests.cpp \
+        tests/unit/BakedOpRendererTests.cpp \
         tests/unit/BakedOpStateTests.cpp \
         tests/unit/FrameBuilderTests.cpp \
         tests/unit/LeakCheckTests.cpp \
-        tests/unit/RecordingCanvasTests.cpp
+        tests/unit/OpDumperTests.cpp \
+        tests/unit/RecordingCanvasTests.cpp \
+        tests/unit/SkiaCanvasTests.cpp
 endif
 
 include $(LOCAL_PATH)/hwui_static_deps.mk
@@ -300,14 +315,15 @@
 LOCAL_CFLAGS := \
         $(hwui_cflags) \
         -DHWUI_NULL_GPU
-LOCAL_C_INCLUDES += bionic/benchmarks/
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_null_gpu
-LOCAL_STATIC_LIBRARIES := libbenchmark libbase
+LOCAL_STATIC_LIBRARIES := libgoogle-benchmark
 
 LOCAL_SRC_FILES += \
     $(hwui_test_common_src_files) \
+    tests/microbench/main.cpp \
     tests/microbench/DisplayListCanvasBench.cpp \
+    tests/microbench/FontBench.cpp \
     tests/microbench/LinearAllocatorBench.cpp \
     tests/microbench/PathParserBench.cpp \
     tests/microbench/ShadowBench.cpp \
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 294edb6..bd71e0d 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -160,6 +160,10 @@
     }
 
     if (!mStagingRequests.empty()) {
+        // No interpolator was set, use the default
+        if (mPlayState == PlayState::NotStarted && !mInterpolator) {
+            mInterpolator.reset(Interpolator::createDefaultInterpolator());
+        }
         // Keep track of the play state and play time before they are changed when
         // staging requests are resolved.
         nsecs_t currentPlayTime = mPlayTime;
@@ -222,10 +226,6 @@
         // Set to 0 so that the animate() basically instantly finishes
         mStartTime = 0;
     }
-    // No interpolator was set, use the default
-    if (!mInterpolator) {
-        mInterpolator.reset(Interpolator::createDefaultInterpolator());
-    }
     if (mDuration < 0 || mDuration > 50000) {
         ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
     }
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 2198fcc..f170e9c 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -95,11 +95,11 @@
 
 class AnimateFunctor {
 public:
-    AnimateFunctor(TreeInfo& info, AnimationContext& context)
-            : dirtyMask(0), mInfo(info), mContext(context) {}
+    AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
+            : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
 
     bool operator() (sp<BaseRenderNodeAnimator>& animator) {
-        dirtyMask |= animator->dirtyMask();
+        *mDirtyMask |= animator->dirtyMask();
         bool remove = animator->animate(mContext);
         if (remove) {
             animator->detach();
@@ -114,11 +114,10 @@
         return remove;
     }
 
-    uint32_t dirtyMask;
-
 private:
     TreeInfo& mInfo;
     AnimationContext& mContext;
+    uint32_t* mDirtyMask;
 };
 
 uint32_t AnimatorManager::animate(TreeInfo& info) {
@@ -143,12 +142,13 @@
 }
 
 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
-    AnimateFunctor functor(info, mAnimationHandle->context());
+    uint32_t dirtyMask;
+    AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
     auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
     mAnimators.erase(newEnd, mAnimators.end());
     mAnimationHandle->notifyAnimationsRan();
     mParent.mProperties.updateMatrix();
-    return functor.dirtyMask;
+    return dirtyMask;
 }
 
 static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index f83e1fa..5fb8425 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -30,6 +30,7 @@
 #include <algorithm>
 #include <math.h>
 #include <SkPaintDefaults.h>
+#include <SkPathOps.h>
 
 namespace android {
 namespace uirenderer {
@@ -60,7 +61,10 @@
     for (size_t i = 0; i < opList.count; i++) {
         const BakedOpState& state = *(opList.states[i]);
         TextureVertex* rectVerts = &vertices[i * 4];
-        Rect opBounds = state.computedState.clippedBounds;
+
+        // calculate unclipped bounds, since they'll determine texture coordinates
+        Rect opBounds = state.op->unmappedBounds;
+        state.computedState.transform.mapRect(opBounds);
         if (CC_LIKELY(state.computedState.transform.isPureTranslate())) {
             // pure translate, so snap (same behavior as onBitmapOp)
             opBounds.snapToPixelBoundaries();
@@ -191,7 +195,7 @@
 }
 
 static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
-        const TextOp& op, const BakedOpState& state) {
+        const TextOp& op, const BakedOpState& textOpState) {
     renderer.caches().textureState().activateTexture(0);
 
     PaintUtils::TextShadow textShadow;
@@ -212,13 +216,41 @@
 
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
-            .setRoundRectClipState(state.roundRectClipState)
+            .setRoundRectClipState(textOpState.roundRectClipState)
             .setMeshTexturedUnitQuad(nullptr)
-            .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha)
-            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, textOpState.alpha)
+            .setTransform(textOpState.computedState.transform, TransformFlags::None)
             .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
             .build();
-    renderer.renderGlop(state, glop);
+
+    // Compute damage bounds and clip (since may differ from those in textOpState).
+    // Bounds should be same as text op, but with dx/dy offset and radius outset
+    // applied in local space.
+    auto& transform = textOpState.computedState.transform;
+    Rect shadowBounds = op.unmappedBounds; // STROKE
+    const bool expandForStroke = op.paint->getStyle() != SkPaint::kFill_Style;
+    if (expandForStroke) {
+        shadowBounds.outset(op.paint->getStrokeWidth() * 0.5f);
+    }
+    shadowBounds.translate(textShadow.dx, textShadow.dy);
+    shadowBounds.outset(textShadow.radius, textShadow.radius);
+    transform.mapRect(shadowBounds);
+    if (CC_UNLIKELY(expandForStroke &&
+            (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
+        shadowBounds.outset(0.5f);
+    }
+
+    auto clipState = textOpState.computedState.clipState;
+    if (clipState->mode != ClipMode::Rectangle
+            || !clipState->rect.contains(shadowBounds)) {
+        // need clip, so pass it and clip bounds
+        shadowBounds.doIntersect(clipState->rect);
+    } else {
+        // don't need clip, ignore
+        clipState = nullptr;
+    }
+
+    renderer.renderGlop(&shadowBounds, clipState, glop);
 }
 
 enum class TextRenderType {
@@ -334,15 +366,15 @@
 }
 
 static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state,
-        PathTexture& texture, const RecordedOp& op) {
+        float xOffset, float yOffset, PathTexture& texture, const SkPaint& paint) {
     Rect dest(texture.width(), texture.height());
-    dest.translate(texture.left - texture.offset,
-            texture.top - texture.offset);
+    dest.translate(xOffset + texture.left - texture.offset,
+            yOffset + texture.top - texture.offset);
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshTexturedUnitQuad(nullptr)
-            .setFillPathTexturePaint(texture, *(op.paint), state.alpha)
+            .setFillPathTexturePaint(texture, paint, state.alpha)
             .setTransform(state.computedState.transform,  TransformFlags::None)
             .setModelViewMapUnitToRect(dest)
             .build();
@@ -368,7 +400,8 @@
                 op.startAngle, op.sweepAngle, op.useCenter, op.paint);
         const AutoTexture holder(texture);
         if (CC_LIKELY(holder.texture)) {
-            renderPathTexture(renderer, state, *texture, op);
+            renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+                    *texture, *(op.paint));
         }
     } else {
         SkRect rect = getBoundsOfFill(op);
@@ -501,6 +534,22 @@
     renderer.renderGlop(state, glop);
 }
 
+void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) {
+    SkPaint paint;
+    paint.setColor(op.color);
+    paint.setXfermodeMode(op.mode);
+
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshUnitQuad()
+            .setFillPaint(paint, state.alpha)
+            .setTransform(Matrix4::identity(), TransformFlags::None)
+            .setModelViewMapUnitToRect(state.computedState.clipState->rect)
+            .build();
+    renderer.renderGlop(state, glop);
+}
+
 void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
     renderer.renderFunctor(op, state);
 }
@@ -519,12 +568,19 @@
                 op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
         const AutoTexture holder(texture);
         if (CC_LIKELY(holder.texture)) {
-            renderPathTexture(renderer, state, *texture, op);
+            renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.right,
+                    *texture, *(op.paint));
         }
     } else {
         SkPath path;
         SkRect rect = getBoundsOfFill(op);
         path.addOval(rect);
+
+        if (state.computedState.localProjectionPathMask != nullptr) {
+            // Mask the ripple path by the local space projection mask in local space.
+            // Note that this can create CCW paths.
+            Op(path, *state.computedState.localProjectionPathMask, kIntersect_SkPathOp, &path);
+        }
         renderConvexPath(renderer, state, path, *(op.paint));
     }
 }
@@ -562,7 +618,9 @@
     PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint);
     const AutoTexture holder(texture);
     if (CC_LIKELY(holder.texture)) {
-        renderPathTexture(renderer, state, *texture, op);
+        // Unlike other callers to renderPathTexture, no offsets are used because PathOp doesn't
+        // have any translate built in, other than what's in the SkPath itself
+        renderPathTexture(renderer, state, 0, 0, *texture, *(op.paint));
     }
 }
 
@@ -588,7 +646,8 @@
                      op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
              const AutoTexture holder(texture);
              if (CC_LIKELY(holder.texture)) {
-                 renderPathTexture(renderer, state, *texture, op);
+                 renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+                         *texture, *(op.paint));
              }
         } else {
             SkPath path;
@@ -622,7 +681,8 @@
                 op.rx, op.ry, op.paint);
         const AutoTexture holder(texture);
         if (CC_LIKELY(holder.texture)) {
-            renderPathTexture(renderer, state, *texture, op);
+            renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+                    *texture, *(op.paint));
         }
     } else {
         const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect(
@@ -749,10 +809,6 @@
                         Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
                 .build();
         renderer.renderGlop(state, glop);
-
-        if (op.destroy) {
-            renderer.renderState().layerPool().putOrDelete(buffer);
-        }
     }
 }
 
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 35c8f6b..3c302b3 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -37,9 +37,23 @@
     return buffer;
 }
 
+void BakedOpRenderer::recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) {
+    mRenderState.layerPool().putOrDelete(offscreenBuffer);
+}
+
 void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) {
     LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
 
+    // subtract repaintRect from region, since it will be regenerated
+    if (repaintRect.contains(0, 0,
+                offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight)) {
+        // repaint full layer, so throw away entire region
+        offscreenBuffer->region.clear();
+    } else {
+        offscreenBuffer->region.subtractSelf(android::Rect(repaintRect.left, repaintRect.top,
+                repaintRect.right, repaintRect.bottom));
+    }
+
     mRenderTarget.offscreenBuffer = offscreenBuffer;
 
     // create and bind framebuffer
@@ -135,17 +149,7 @@
         mRenderState.stencil().disable();
     }
 
-    mCaches.clearGarbage();
-    mCaches.pathCache.trim();
-    mCaches.tessellationCache.trim();
-
-#if DEBUG_MEMORY_USAGE
-    mCaches.dumpMemoryUsage();
-#else
-    if (Properties::debugLevel & kDebugMemory) {
-        mCaches.dumpMemoryUsage();
-    }
-#endif
+    // Note: we leave FBO 0 renderable here, for post-frame-content decoration
 }
 
 void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
@@ -179,6 +183,39 @@
     return texture;
 }
 
+void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
+    std::vector<Vertex> vertices;
+    vertices.reserve(count);
+    Vertex* vertex = vertices.data();
+
+    for (int index = 0; index < count; index += 4) {
+        float l = rects[index + 0];
+        float t = rects[index + 1];
+        float r = rects[index + 2];
+        float b = rects[index + 3];
+
+        Vertex::set(vertex++, l, t);
+        Vertex::set(vertex++, r, t);
+        Vertex::set(vertex++, l, b);
+        Vertex::set(vertex++, r, b);
+    }
+
+    LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "decoration only supported for FBO 0");
+    // TODO: Currently assume full FBO damage, due to FrameInfoVisualizer::unionDirty.
+    // Should should scissor/set mHasDrawn safely.
+    mRenderState.scissor().setEnabled(false);
+    mHasDrawn = true;
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setRoundRectClipState(nullptr)
+            .setMeshIndexedQuads(vertices.data(), count / 4)
+            .setFillPaint(*paint, 1.0f)
+            .setTransform(Matrix4::identity(), TransformFlags::None)
+            .setModelViewIdentityEmptyBounds()
+            .build();
+    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+}
+
 // clears and re-fills stencil with provided rendertarget space quads,
 // and then put stencil into test mode
 void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
@@ -296,16 +333,13 @@
         }
     }
 
-    // dirty offscreenbuffer
-    if (dirtyBounds && mRenderTarget.offscreenBuffer) {
-        // register layer damage to draw-back region
-        android::Rect dirty(dirtyBounds->left, dirtyBounds->top,
-                dirtyBounds->right, dirtyBounds->bottom);
-        mRenderTarget.offscreenBuffer->region.orSelf(dirty);
+    if (dirtyBounds) {
+        // dirty offscreenbuffer if present
+        dirtyRenderTarget(*dirtyBounds);
     }
 }
 
-void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const ClipBase* clip,
+void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip,
         const Glop& glop) {
     prepareRender(dirtyBounds, clip);
     mRenderState.render(glop, mRenderTarget.orthoMatrix);
@@ -329,29 +363,9 @@
     mRenderState.invokeFunctor(op.functor, DrawGlInfo::kModeDraw, &info);
 }
 
-#define VALIDATE_RECT_ARG(rect, arg) \
-        ((isnanf(rect.arg) || rect.arg < -10000 || rect.arg > 10000) ? (\
-            ALOGW("suspicious " #rect "." #arg "! %f", rect.arg),\
-            false) : true)
-
-#define VALIDATE_RECT(rect) \
-    VALIDATE_RECT_ARG(rect, bottom) & \
-    VALIDATE_RECT_ARG(rect, left) & \
-    VALIDATE_RECT_ARG(rect, top) & \
-    VALIDATE_RECT_ARG(rect, right)
-
 void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) {
     if (mRenderTarget.offscreenBuffer) {
-        bool valid = VALIDATE_RECT(uiDirty);
-        android::Rect dirty;
-        if (valid) {
-            dirty = android::Rect(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
-        } else {
-            dirty = android::Rect(0, 0,
-                    mRenderTarget.offscreenBuffer->viewportWidth,
-                    mRenderTarget.offscreenBuffer->viewportHeight);
-        }
-        mRenderTarget.offscreenBuffer->region.orSelf(dirty);
+        mRenderTarget.offscreenBuffer->dirty(uiDirty);
     }
 }
 
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 55ea935..62bc564 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HWUI_BAKED_OP_RENDERER_H
-#define ANDROID_HWUI_BAKED_OP_RENDERER_H
+#pragma once
 
 #include "BakedOpState.h"
 #include "Matrix.h"
@@ -41,6 +40,7 @@
  */
 class BakedOpRenderer {
 public:
+    typedef void (*GlopReceiver)(BakedOpRenderer&, const Rect*, const ClipBase*, const Glop&);
     /**
      * Position agnostic shadow lighting info. Used with all shadow ops in scene.
      */
@@ -54,8 +54,10 @@
         uint8_t spotShadowAlpha;
     };
 
-    BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, const LightInfo& lightInfo)
-            : mRenderState(renderState)
+    BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque,
+            const LightInfo& lightInfo)
+            : mGlopReceiver(DefaultGlopReceiver)
+            , mRenderState(renderState)
             , mCaches(caches)
             , mOpaque(opaque)
             , mLightInfo(lightInfo) {
@@ -67,6 +69,7 @@
     void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect);
     void endFrame(const Rect& repaintRect);
     WARN_UNUSED_RESULT OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
+    void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer);
     void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect);
     void endLayer();
     WARN_UNUSED_RESULT OffscreenBuffer* copyToLayer(const Rect& area);
@@ -81,11 +84,30 @@
     }
     void renderFunctor(const FunctorOp& op, const BakedOpState& state);
 
-    void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
+    void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop) {
+        mGlopReceiver(*this, dirtyBounds, clip, glop);
+    }
     bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
     void dirtyRenderTarget(const Rect& dirtyRect);
     bool didDraw() const { return mHasDrawn; }
+
+    uint32_t getViewportWidth() const { return mRenderTarget.viewportWidth; }
+    uint32_t getViewportHeight() const { return mRenderTarget.viewportHeight; }
+
+    // simple draw methods, to be used for end frame decoration
+    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint) {
+        float ltrb[4] = { left, top, right, bottom };
+        drawRects(ltrb, 4, paint);
+    }
+    void drawRects(const float* rects, int count, const SkPaint* paint);
+protected:
+    GlopReceiver mGlopReceiver;
 private:
+    static void DefaultGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
+            const ClipBase* clip, const Glop& glop) {
+        renderer.renderGlopImpl(dirtyBounds, clip, glop);
+    }
+    void renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
     void setViewport(uint32_t width, uint32_t height);
     void clearColorBuffer(const Rect& clearRect);
     void prepareRender(const Rect* dirtyBounds, const ClipBase* clip);
@@ -126,5 +148,3 @@
 
 }; // namespace uirenderer
 }; // namespace android
-
-#endif // ANDROID_HWUI_BAKED_OP_RENDERER_H
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index a542c26..b70d586 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -21,6 +21,15 @@
 namespace android {
 namespace uirenderer {
 
+static int computeClipSideFlags(const Rect& clip, const Rect& bounds) {
+    int clipSideFlags = 0;
+    if (clip.left > bounds.left) clipSideFlags |= OpClipSideFlags::Left;
+    if (clip.top > bounds.top) clipSideFlags |= OpClipSideFlags::Top;
+    if (clip.right < bounds.right) clipSideFlags |= OpClipSideFlags::Right;
+    if (clip.bottom < bounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
+    return clipSideFlags;
+}
+
 ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
         const RecordedOp& recordedOp, bool expandForStroke) {
     // resolvedMatrix = parentMatrix * localMatrix
@@ -54,26 +63,108 @@
         clipState = nullptr;
         clippedBounds.setEmpty();
     } else {
-        // Not rejected! compute true clippedBounds and clipSideFlags
-        if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
-        if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
-        if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
-        if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
+        // Not rejected! compute true clippedBounds, clipSideFlags, and path mask
+        clipSideFlags = computeClipSideFlags(clipRect, clippedBounds);
         clippedBounds.doIntersect(clipRect);
+
+        if (CC_UNLIKELY(snapshot.projectionPathMask)) {
+            // map projection path mask from render target space into op space,
+            // so intersection with op geometry is possible
+            Matrix4 inverseTransform;
+            inverseTransform.loadInverse(transform);
+            SkMatrix skInverseTransform;
+            inverseTransform.copyTo(skInverseTransform);
+
+            auto localMask = allocator.create<SkPath>();
+            snapshot.projectionPathMask->transform(skInverseTransform, localMask);
+            localProjectionPathMask = localMask;
+        }
     }
 }
 
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+        const Matrix4& localTransform, const ClipBase* localClip) {
+    transform.loadMultiply(*snapshot.transform, localTransform);
+    clipState = snapshot.mutateClipArea().serializeIntersectedClip(allocator,
+            localClip, *(snapshot.transform));
+    clippedBounds = clipState->rect;
+    clipSideFlags = OpClipSideFlags::Full;
+    localProjectionPathMask = nullptr;
+}
+
 ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot)
         : transform(*snapshot.transform)
         , clipState(snapshot.mutateClipArea().serializeClip(allocator))
         , clippedBounds(clipState->rect)
-        , clipSideFlags(OpClipSideFlags::Full) {}
+        , clipSideFlags(OpClipSideFlags::Full)
+        , localProjectionPathMask(nullptr) {}
 
-ResolvedRenderState::ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect)
+ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& dstRect)
         : transform(Matrix4::identity())
-        , clipState(viewportRect)
+        , clipState(clipRect)
         , clippedBounds(dstRect)
-        , clipSideFlags(OpClipSideFlags::None) {}
+        , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect))
+        , localProjectionPathMask(nullptr) {
+    clippedBounds.doIntersect(clipRect->rect);
+}
+
+BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
+        Snapshot& snapshot, const RecordedOp& recordedOp) {
+    if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+    BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
+            allocator, snapshot, recordedOp, false);
+    if (bakedState->computedState.clippedBounds.isEmpty()) {
+        // bounds are empty, so op is rejected
+        allocator.rewindIfLastAlloc(bakedState);
+        return nullptr;
+    }
+    return bakedState;
+}
+
+BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator,
+        Snapshot& snapshot, const RecordedOp& recordedOp) {
+    if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+    return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
+}
+
+BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
+        Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+    if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+    bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
+            ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
+            : true;
+
+    BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
+           allocator, snapshot, recordedOp, expandForStroke);
+    if (bakedState->computedState.clippedBounds.isEmpty()) {
+        // bounds are empty, so op is rejected
+        // NOTE: this won't succeed if a clip was allocated
+        allocator.rewindIfLastAlloc(bakedState);
+        return nullptr;
+    }
+    return bakedState;
+}
+
+BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator,
+        Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+    if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+
+    // clip isn't empty, so construct the op
+    return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
+}
+
+BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator,
+        const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
+    return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
+}
+
+void BakedOpState::setupOpacity(const SkPaint* paint) {
+    computedState.opaqueOverClippedBounds = computedState.transform.isSimple()
+            && computedState.clipState->mode == ClipMode::Rectangle
+            && MathUtils::areEqual(alpha, 1.0f)
+            && !roundRectClipState
+            && PaintUtils::isOpaquePaint(paint);
+}
 
 } // namespace uirenderer
 } // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 5a5845a..e1441fc 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -55,6 +55,10 @@
     ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
             const RecordedOp& recordedOp, bool expandForStroke);
 
+    // Constructor for unbounded ops *with* transform/clip
+    ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+            const Matrix4& localTransform, const ClipBase* localClip);
+
     // Constructor for unbounded ops without transform/clip (namely shadows)
     ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
 
@@ -88,6 +92,8 @@
     const ClipBase* clipState = nullptr;
     Rect clippedBounds;
     int clipSideFlags = 0;
+    const SkPath* localProjectionPathMask = nullptr;
+    bool opaqueOverClippedBounds = false;
 };
 
 /**
@@ -98,55 +104,29 @@
 class BakedOpState {
 public:
     static BakedOpState* tryConstruct(LinearAllocator& allocator,
-            Snapshot& snapshot, const RecordedOp& recordedOp) {
-        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
-        BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
-                allocator, snapshot, recordedOp, false);
-        if (bakedState->computedState.clippedBounds.isEmpty()) {
-            // bounds are empty, so op is rejected
-            allocator.rewindIfLastAlloc(bakedState);
-            return nullptr;
-        }
-        return bakedState;
-    }
+            Snapshot& snapshot, const RecordedOp& recordedOp);
+
+    static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator,
+            Snapshot& snapshot, const RecordedOp& recordedOp);
 
     enum class StrokeBehavior {
-        // stroking is forced, regardless of style on paint
+        // stroking is forced, regardless of style on paint (such as for lines)
         Forced,
         // stroking is defined by style on paint
         StyleDefined,
     };
 
     static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
-            Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
-        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
-        bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
-                ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
-                : true;
-
-        BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
-                allocator, snapshot, recordedOp, expandForStroke);
-        if (bakedState->computedState.clippedBounds.isEmpty()) {
-            // bounds are empty, so op is rejected
-            // NOTE: this won't succeed if a clip was allocated
-            allocator.rewindIfLastAlloc(bakedState);
-            return nullptr;
-        }
-        return bakedState;
-    }
+            Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior);
 
     static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
-            Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
-        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
-
-        // clip isn't empty, so construct the op
-        return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
-    }
+            Snapshot& snapshot, const ShadowOp* shadowOpPtr);
 
     static BakedOpState* directConstruct(LinearAllocator& allocator,
-            const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
-        return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
-    }
+            const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp);
+
+    // Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent.
+    void setupOpacity(const SkPaint* paint);
 
     // computed state:
     ResolvedRenderState computedState;
@@ -154,7 +134,6 @@
     // simple state (straight pointer/value storage):
     const float alpha;
     const RoundRectClipState* roundRectClipState;
-    const ProjectionPathMask* projectionPathMask;
     const RecordedOp* op;
 
 private:
@@ -165,21 +144,25 @@
             : computedState(allocator, snapshot, recordedOp, expandForStroke)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
-            , projectionPathMask(snapshot.projectionPathMask)
+            , op(&recordedOp) {}
+
+    // TODO: fix this brittleness
+    BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp)
+            : computedState(allocator, snapshot, recordedOp.localMatrix, recordedOp.localClip)
+            , alpha(snapshot.alpha)
+            , roundRectClipState(snapshot.roundRectClipState)
             , op(&recordedOp) {}
 
     BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr)
             : computedState(allocator, snapshot)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
-            , projectionPathMask(snapshot.projectionPathMask)
             , op(shadowOpPtr) {}
 
-    BakedOpState(const ClipRect* viewportRect, const Rect& dstRect, const RecordedOp& recordedOp)
-            : computedState(viewportRect, dstRect)
+    BakedOpState(const ClipRect* clipRect, const Rect& dstRect, const RecordedOp& recordedOp)
+            : computedState(clipRect, dstRect)
             , alpha(1.0f)
             , roundRectClipState(nullptr)
-            , projectionPathMask(nullptr)
             , op(&recordedOp) {}
 };
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 330dc29..eac9359 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -92,6 +92,8 @@
      */
     bool init();
 
+    bool isInitialized() { return mInitialized; }
+
     /**
      * Flush the cache.
      *
diff --git a/libs/hwui/Canvas.cpp b/libs/hwui/Canvas.cpp
deleted file mode 100644
index 11ae1a1..0000000
--- a/libs/hwui/Canvas.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Canvas.h"
-
-#include "DisplayListCanvas.h"
-#include "RecordingCanvas.h"
-#include <SkDrawFilter.h>
-
-namespace android {
-
-Canvas* Canvas::create_recording_canvas(int width, int height) {
-#if HWUI_NEW_OPS
-    return new uirenderer::RecordingCanvas(width, height);
-#else
-    return new uirenderer::DisplayListCanvas(width, height);
-#endif
-}
-
-void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) {
-    uint32_t flags;
-    SkDrawFilter* drawFilter = getDrawFilter();
-    if (drawFilter) {
-        SkPaint paintCopy(paint);
-        drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
-        flags = paintCopy.getFlags();
-    } else {
-        flags = paint.getFlags();
-    }
-    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
-        // Same values used by Skia
-        const float kStdStrikeThru_Offset   = (-6.0f / 21.0f);
-        const float kStdUnderline_Offset    = (1.0f / 9.0f);
-        const float kStdUnderline_Thickness = (1.0f / 18.0f);
-
-        SkScalar left = x;
-        SkScalar right = x + length;
-        float textSize = paint.getTextSize();
-        float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
-        if (flags & SkPaint::kUnderlineText_Flag) {
-            SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
-            SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
-            drawRect(left, top, right, bottom, paint);
-        }
-        if (flags & SkPaint::kStrikeThruText_Flag) {
-            SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
-            SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
-            drawRect(left, top, right, bottom, paint);
-        }
-    }
-}
-
-} // namespace android
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
deleted file mode 100644
index 27facdf..0000000
--- a/libs/hwui/Canvas.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GRAPHICS_CANVAS_H
-#define ANDROID_GRAPHICS_CANVAS_H
-
-#include <cutils/compiler.h>
-#include <utils/Functor.h>
-
-#include "utils/NinePatch.h"
-
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <SkMatrix.h>
-
-namespace android {
-
-namespace uirenderer {
-    class CanvasPropertyPaint;
-    class CanvasPropertyPrimitive;
-    class DeferredLayerUpdater;
-    class DisplayList;
-    class RenderNode;
-}
-
-namespace SaveFlags {
-
-// These must match the corresponding Canvas API constants.
-enum {
-    Matrix        = 0x01,
-    Clip          = 0x02,
-    HasAlphaLayer = 0x04,
-    ClipToLayer   = 0x10,
-
-    // Helper constant
-    MatrixClip    = Matrix | Clip,
-};
-typedef uint32_t Flags;
-
-} // namespace SaveFlags
-
-namespace uirenderer {
-namespace VectorDrawable {
-class Tree;
-};
-};
-typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
-
-class ANDROID_API Canvas {
-public:
-    virtual ~Canvas() {};
-
-    static Canvas* create_canvas(const SkBitmap& bitmap);
-
-    static Canvas* create_recording_canvas(int width, int height);
-
-    /**
-     *  Create a new Canvas object which delegates to an SkCanvas.
-     *
-     *  @param skiaCanvas Must not be NULL. All drawing calls will be
-     *      delegated to this object. This function will call ref() on the
-     *      SkCanvas, and the returned Canvas will unref() it upon
-     *      destruction.
-     *  @return new Canvas object. Will not return NULL.
-     */
-    static Canvas* create_canvas(SkCanvas* skiaCanvas);
-
-    /**
-     *  Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
-     *  It is useful for testing and clients (e.g. Picture/Movie) that expect to
-     *  draw their contents into an SkCanvas.
-     *
-     *  The SkCanvas returned is *only* valid until another Canvas call is made
-     *  that would change state (e.g. matrix or clip). Clients of asSkCanvas()
-     *  are responsible for *not* persisting this pointer.
-     *
-     *  Further, the returned SkCanvas should NOT be unref'd and is valid until
-     *  this canvas is destroyed or a new bitmap is set.
-     */
-    virtual SkCanvas* asSkCanvas() = 0;
-
-
-    virtual void setBitmap(const SkBitmap& bitmap) = 0;
-
-    virtual bool isOpaque() = 0;
-    virtual int width() = 0;
-    virtual int height() = 0;
-
-// ----------------------------------------------------------------------------
-// View System operations (not exposed in public Canvas API)
-// ----------------------------------------------------------------------------
-
-    virtual void resetRecording(int width, int height) = 0;
-    virtual uirenderer::DisplayList* finishRecording() = 0;
-    virtual void insertReorderBarrier(bool enableReorder) = 0;
-
-    virtual void setHighContrastText(bool highContrastText) = 0;
-    virtual bool isHighContrastText() = 0;
-
-    virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
-            uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
-            uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
-            uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) = 0;
-    virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
-            uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
-            uirenderer::CanvasPropertyPaint* paint) = 0;
-
-    virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
-    virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
-    virtual void callDrawGLFunction(Functor* functor) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
-
-    // Save (layer)
-    virtual int getSaveCount() const = 0;
-    virtual int save(SaveFlags::Flags flags) = 0;
-    virtual void restore() = 0;
-    virtual void restoreToCount(int saveCount) = 0;
-
-    virtual int saveLayer(float left, float top, float right, float bottom,
-                const SkPaint* paint, SaveFlags::Flags flags) = 0;
-    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SaveFlags::Flags flags) = 0;
-
-    // Matrix
-    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
-    virtual void setMatrix(const SkMatrix& matrix) = 0;
-
-    virtual void concat(const SkMatrix& matrix) = 0;
-    virtual void rotate(float degrees) = 0;
-    virtual void scale(float sx, float sy) = 0;
-    virtual void skew(float sx, float sy) = 0;
-    virtual void translate(float dx, float dy) = 0;
-
-    // clip
-    virtual bool getClipBounds(SkRect* outRect) const = 0;
-    virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
-    virtual bool quickRejectPath(const SkPath& path) const = 0;
-
-    virtual bool clipRect(float left, float top, float right, float bottom,
-            SkRegion::Op op = SkRegion::kIntersect_Op) = 0;
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
-
-    // filters
-    virtual SkDrawFilter* getDrawFilter() = 0;
-    virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
-    virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
-    virtual void drawPaint(const SkPaint& paint) = 0;
-
-    // Geometry
-    virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
-    virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
-    virtual void drawLine(float startX, float startY, float stopX, float stopY,
-                const SkPaint& paint) = 0;
-    virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
-    virtual void drawRect(float left, float top, float right, float bottom,
-            const SkPaint& paint) = 0;
-    virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
-    virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint& paint) = 0;
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
-    virtual void drawOval(float left, float top, float right, float bottom,
-            const SkPaint& paint) = 0;
-    virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
-    virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
-    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
-                              const float* verts, const float* tex, const int* colors,
-                              const uint16_t* indices, int indexCount, const SkPaint& paint) = 0;
-
-    // Bitmap-based
-    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
-            const SkPaint* paint) = 0;
-    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
-            const SkPaint* paint) = 0;
-    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint) = 0;
-    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint) = 0;
-    virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
-            float dstLeft, float dstTop, float dstRight, float dstBottom,
-            const SkPaint* paint) = 0;
-
-    // Text
-    /**
-     * drawText: count is of glyphs
-     * totalAdvance: used to define width of text decorations (underlines, strikethroughs).
-     */
-    virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
-            const SkPaint& paint, float x, float y,
-            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
-            float totalAdvance) = 0;
-    /** drawTextOnPath: count is of glyphs */
-    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-            float hOffset, float vOffset, const SkPaint& paint) = 0;
-
-    /**
-     * Specifies if the positions passed to ::drawText are absolute or relative
-     * to the (x,y) value provided.
-     *
-     * If true the (x,y) values are ignored. Otherwise, those (x,y) values need
-     * to be added to each glyph's position to get its absolute position.
-     */
-    virtual bool drawTextAbsolutePos() const = 0;
-
-    /**
-     * Draws a VectorDrawable onto the canvas.
-     */
-    virtual void drawVectorDrawable(VectorDrawableRoot* tree);
-
-protected:
-    void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
-};
-
-}; // namespace android
-#endif // ANDROID_GRAPHICS_CANVAS_H
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 43ff33f..e2149d1 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include "Canvas.h"
 #include "CanvasState.h"
+#include "hwui/Canvas.h"
 #include "utils/MathUtils.h"
 
 namespace android {
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index e368537..f886dda 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -41,6 +41,10 @@
     return transformedBounds;
 }
 
+void ClipBase::dump() const {
+    ALOGD("mode %d" RECT_STRING, mode, RECT_ARGS(rect));
+}
+
 /*
  * TransformedRectangle
  */
@@ -375,15 +379,13 @@
             serialization->rect.set(mClipRegion.getBounds());
             break;
         }
+        // TODO: this is only done for draw time, should eventually avoid for record time
+        serialization->rect.snapToPixelBoundaries();
         mLastSerialization = serialization;
     }
     return mLastSerialization;
 }
 
-inline static const Rect& getRect(const ClipBase* scb) {
-    return reinterpret_cast<const ClipRect*>(scb)->rect;
-}
-
 inline static const RectangleList& getRectList(const ClipBase* scb) {
     return reinterpret_cast<const ClipRectList*>(scb)->rectList;
 }
@@ -404,11 +406,17 @@
     return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
 }
 
+static const ClipRect sEmptyClipRect(Rect(0, 0));
+
 const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
         const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
+
     // if no recordedClip passed, just serialize current state
     if (!recordedClip) return serializeClip(allocator);
 
+    // if either is empty, clip is empty
+    if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
+
     if (!mLastResolutionResult
             || recordedClip != mLastResolutionClip
             || recordedClipTransform != mLastResolutionTransform) {
@@ -419,9 +427,10 @@
                 && recordedClip->mode == ClipMode::Rectangle
                 && recordedClipTransform.rectToRect())) {
             // common case - result is a single rectangle
-            auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
+            auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
             recordedClipTransform.mapRect(rectClip->rect);
             rectClip->rect.doIntersect(mClipRect);
+            rectClip->rect.snapToPixelBoundaries();
             mLastResolutionResult = rectClip;
         } else if (CC_UNLIKELY(mMode == ClipMode::Region
                 || recordedClip->mode == ClipMode::Region
@@ -432,11 +441,11 @@
             case ClipMode::Rectangle:
                 if (CC_LIKELY(recordedClipTransform.rectToRect())) {
                     // simple transform, skip creating SkPath
-                    Rect resultClip(getRect(recordedClip));
+                    Rect resultClip(recordedClip->rect);
                     recordedClipTransform.mapRect(resultClip);
                     other.setRect(resultClip.toSkIRect());
                 } else {
-                    SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
+                    SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
                             recordedClipTransform);
                     other.setPath(transformedRect, createViewportRegion());
                 }
@@ -468,6 +477,7 @@
                 regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
                 break;
             }
+            // Don't need to snap, since region's in int bounds
             regionClip->rect.set(regionClip->region.getBounds());
             mLastResolutionResult = regionClip;
         } else {
@@ -478,7 +488,7 @@
             }
 
             if (recordedClip->mode == ClipMode::Rectangle) {
-                rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
+                rectList.intersectWith(recordedClip->rect, recordedClipTransform);
             } else {
                 const RectangleList& other = getRectList(recordedClip);
                 for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
@@ -489,6 +499,7 @@
                 }
             }
             rectListClip->rect = rectList.calculateBounds();
+            rectListClip->rect.snapToPixelBoundaries();
             mLastResolutionResult = rectListClip;
         }
     }
@@ -499,7 +510,7 @@
     if (!clip) return; // nothing to do
 
     if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
-        clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
+        clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
     } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
         auto&& rectList = getRectList(clip);
         for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 479796d..1654eb8 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -106,6 +106,8 @@
     // Bounds of the clipping area, used to define the scissor, and define which
     // portion of the stencil is updated/used
     Rect rect;
+
+    void dump() const;
 };
 
 struct ClipRect : ClipBase {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 6a3c890..44a24c8 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -47,6 +47,9 @@
         return false;
     }
 
+    int getWidth() { return mWidth; }
+    int getHeight() { return mHeight; }
+
     ANDROID_API bool setBlend(bool blend) {
         if (blend != mBlend) {
             mBlend = blend;
@@ -75,6 +78,10 @@
         mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
     }
 
+    SkMatrix* getTransform() {
+        return mTransform;
+    }
+
     ANDROID_API void setPaint(const SkPaint* paint);
 
     void apply();
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 59f0d7c..181b343 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,6 +45,7 @@
         , regions(stdAllocator)
         , referenceHolders(stdAllocator)
         , functors(stdAllocator)
+        , pushStagingFunctors(stdAllocator)
         , hasDrawOps(false) {
 }
 
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 60cc7ba..e209e2a 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -110,6 +110,16 @@
 };
 
 /**
+ * Functor that can be used for objects with data in both UI thread and RT to keep the data
+ * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
+ */
+struct PushStagingFunctor {
+    PushStagingFunctor() {}
+    virtual ~PushStagingFunctor() {}
+    virtual void operator ()() {}
+};
+
+/**
  * Data structure that holds the list of commands used in display list stream
  */
 class DisplayList {
@@ -142,6 +152,7 @@
 
     const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
     const LsaVector<Functor*>& getFunctors() const { return functors; }
+    const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
 
     size_t addChild(NodeOpType* childOp);
 
@@ -183,6 +194,11 @@
     // List of functors
     LsaVector<Functor*> functors;
 
+    // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+    // but a callback during sync DisplayList, unlike the list of functors defined above, which
+    // gets special treatment exclusive for webview.
+    LsaVector<PushStagingFunctor*> pushStagingFunctors;
+
     bool hasDrawOps; // only used if !HWUI_NEW_OPS
 
     void cleanupResources();
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 00560d7..c6e92ab 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -415,15 +415,11 @@
 
 void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
     mDisplayList->ref(tree);
-    const SkBitmap& bitmap = tree->getBitmapUpdateIfDirty();
-    SkPaint* paint = tree->getPaint();
-    const SkRect bounds = tree->getBounds();
-    addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap),
-            0, 0, bitmap.width(), bitmap.height(),
-            bounds.left(), bounds.top(), bounds.right(), bounds.bottom(), refPaint(paint)));
+    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+    addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
 }
 
-void DisplayListCanvas::drawTextOnPath(const uint16_t* glyphs, int count,
+void DisplayListCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count,
         const SkPath& path, float hOffset, float vOffset, const SkPaint& paint) {
     if (!glyphs || count <= 0) return;
 
@@ -434,7 +430,7 @@
     addDrawOp(op);
 }
 
-void DisplayListCanvas::drawText(const uint16_t* glyphs, const float* positions,
+void DisplayListCanvas::drawGlyphs(const uint16_t* glyphs, const float* positions,
         int count, const SkPaint& paint, float x, float y,
         float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
         float totalAdvance) {
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index a703e22..d6a5794 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
 #define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
 
-#include "Canvas.h"
 #include "CanvasState.h"
 #include "DisplayList.h"
 #include "RenderNode.h"
 #include "ResourceCache.h"
 #include "SkiaCanvasProxy.h"
+#include "hwui/Canvas.h"
 #include "utils/Macros.h"
 
 #include <SkDrawFilter.h>
@@ -209,10 +209,10 @@
     virtual void drawVectorDrawable(VectorDrawableRoot* tree) override;
 
     // Text
-    virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
+    virtual void drawGlyphs(const uint16_t* glyphs, const float* positions, int count,
             const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
             float boundsRight, float boundsBottom, float totalAdvance) override;
-    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+    virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
             float hOffset, float vOffset, const SkPaint& paint) override;
     virtual bool drawTextAbsolutePos() const override { return false; }
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 98315d0..59f073f 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -28,6 +28,7 @@
 #include "UvMapper.h"
 #include "utils/LinearAllocator.h"
 #include "utils/PaintUtils.h"
+#include "VectorDrawable.h"
 
 #include <algorithm>
 
@@ -1107,6 +1108,30 @@
     float* mRadius;
 };
 
+class DrawVectorDrawableOp : public DrawOp {
+public:
+    DrawVectorDrawableOp(VectorDrawableRoot* tree, const SkRect& bounds)
+            : DrawOp(nullptr), mTree(tree), mDst(bounds) {}
+
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty();
+        SkPaint* paint = mTree->getPaint();
+        renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()),
+                mDst, paint);
+    }
+
+    virtual void output(int level, uint32_t logFlags) const override {
+        OP_LOG("Draw Vector Drawable %p", mTree);
+    }
+
+    virtual const char* name() override { return "DrawVectorDrawable"; }
+
+private:
+    VectorDrawableRoot* mTree;
+    SkRect mDst;
+
+};
+
 class DrawOvalOp : public DrawStrokableOp {
 public:
     DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index 97dec88..9a39ec2 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -17,6 +17,7 @@
 #define FLOATCOLOR_H
 
 #include "utils/Macros.h"
+#include "utils/MathUtils.h"
 
 #include <stdint.h>
 
@@ -38,6 +39,17 @@
                 || b > 0.0f;
     }
 
+    bool operator==(const FloatColor& other) const {
+        return MathUtils::areEqual(r, other.r)
+                && MathUtils::areEqual(g, other.g)
+                && MathUtils::areEqual(b, other.b)
+                && MathUtils::areEqual(a, other.a);
+    }
+
+    bool operator!=(const FloatColor& other) const {
+        return !(*this == other);
+    }
+
     float r;
     float g;
     float b;
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 4f51036..0401f2d 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -16,11 +16,11 @@
 
 #include "FrameBuilder.h"
 
-#include "Canvas.h"
 #include "LayerUpdateQueue.h"
 #include "RenderNode.h"
 #include "VectorDrawable.h"
 #include "renderstate/OffscreenBufferPool.h"
+#include "hwui/Canvas.h"
 #include "utils/FatVector.h"
 #include "utils/PaintUtils.h"
 #include "utils/TraceUtils.h"
@@ -34,10 +34,11 @@
 FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
         uint32_t viewportWidth, uint32_t viewportHeight,
         const std::vector< sp<RenderNode> >& nodes,
-        const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches* caches)
+        const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches& caches)
         : mCanvasState(*this)
         , mCaches(caches)
-        , mLightRadius(lightGeometry.radius) {
+        , mLightRadius(lightGeometry.radius)
+        , mDrawFbo0(!nodes.empty()) {
     ATRACE_NAME("prepare drawing commands");
 
     mLayerBuilders.reserve(layers.entries().size());
@@ -203,8 +204,9 @@
         mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
     }
 
-    bool quickRejected = properties.getClipToBounds()
-            && mCanvasState.quickRejectConservative(0, 0, width, height);
+    bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty()
+            || (properties.getClipToBounds()
+                    && mCanvasState.quickRejectConservative(0, 0, width, height));
     if (!quickRejected) {
         // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
         if (node.getLayer()) {
@@ -363,15 +365,13 @@
         casterPath = frameAllocatedPath;
     }
 
-
     if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
         Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
         Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
         node.applyViewPropertyTransforms(shadowMatrixXY, false);
         node.applyViewPropertyTransforms(shadowMatrixZ, true);
 
-        LOG_ALWAYS_FATAL_IF(!mCaches, "Caches needed for shadows");
-        sp<TessellationCache::ShadowTask> task = mCaches->tessellationCache.getShadowTask(
+        sp<TessellationCache::ShadowTask> task = mCaches.tessellationCache.getShadowTask(
                 mCanvasState.currentTransform(),
                 mCanvasState.getLocalClipBounds(),
                 casterAlpha >= 1.0f,
@@ -389,34 +389,38 @@
 }
 
 void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
-    const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
     int count = mCanvasState.save(SaveFlags::MatrixClip);
+    const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
 
-    // can't be null, since DL=null node rejection happens before deferNodePropsAndOps
-    const DisplayList& displayList = *(renderNode.getDisplayList());
-
-    const RecordedOp* op = (displayList.getOps()[displayList.projectionReceiveIndex]);
-    const RenderNodeOp* backgroundOp = static_cast<const RenderNodeOp*>(op);
-    const RenderProperties& backgroundProps = backgroundOp->renderNode->properties();
-
-    // Transform renderer to match background we're projecting onto
-    // (by offsetting canvas by translationX/Y of background rendernode, since only those are set)
-    mCanvasState.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
-
-    // If the projection receiver has an outline, we mask projected content to it
-    // (which we know, apriori, are all tessellated paths)
-    mCanvasState.setProjectionPathMask(mAllocator, projectionReceiverOutline);
-
-    // draw projected nodes
-    for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) {
-        RenderNodeOp* childOp = renderNode.mProjectedNodes[i];
-
-        int restoreTo = mCanvasState.save(SaveFlags::Matrix);
-        mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
-        deferRenderNodeOpImpl(*childOp);
-        mCanvasState.restoreToCount(restoreTo);
+    SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
+    if (projectionReceiverOutline) {
+        // transform the mask for this projector into render target space
+        // TODO: consider combining both transforms by stashing transform instead of applying
+        SkMatrix skCurrentTransform;
+        mCanvasState.currentTransform()->copyTo(skCurrentTransform);
+        projectionReceiverOutline->transform(
+                skCurrentTransform,
+                &transformedMaskPath);
+        mCanvasState.setProjectionPathMask(mAllocator, &transformedMaskPath);
     }
 
+    for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) {
+        RenderNodeOp* childOp = renderNode.mProjectedNodes[i];
+        RenderNode& childNode = *childOp->renderNode;
+
+        // Draw child if it has content, but ignore state in childOp - matrix already applied to
+        // transformFromCompositingAncestor, and record-time clip is ignored when projecting
+        if (!childNode.nothingToDraw()) {
+            int restoreTo = mCanvasState.save(SaveFlags::MatrixClip);
+
+            // Apply transform between ancestor and projected descendant
+            mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
+
+            deferNodePropsAndOps(childNode);
+
+            mCanvasState.restoreToCount(restoreTo);
+        }
+    }
     mCanvasState.restoreToCount(count);
 }
 
@@ -478,13 +482,19 @@
  * Defers an unmergeable, strokeable op, accounting correctly
  * for paint's style on the bounds being computed.
  */
-void FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
         BakedOpState::StrokeBehavior strokeBehavior) {
     // Note: here we account for stroke when baking the op
     BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
             mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
-    if (!bakedState) return; // quick rejected
+    if (!bakedState) return nullptr; // quick rejected
+
+    if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) {
+        bakedState->setupOpacity(op.paint);
+    }
+
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
+    return bakedState;
 }
 
 /**
@@ -513,10 +523,10 @@
     BakedOpState* bakedState = tryBakeOpState(op);
     if (!bakedState) return; // quick rejected
 
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+    if (op.bitmap->isOpaque()) {
+        bakedState->setupOpacity(op.paint);
+    }
 
-    // TODO: Fix this ( b/26569206 )
-/*
     // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
     // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
     // MergingDrawBatch::canMergeWith()
@@ -531,7 +541,6 @@
     } else {
         currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
     }
-*/
 }
 
 void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
@@ -573,8 +582,14 @@
     deferOvalOp(*resolvedOp);
 }
 
+void FrameBuilder::deferColorOp(const ColorOp& op) {
+    BakedOpState* bakedState = tryBakeUnboundedOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
+}
+
 void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
+    BakedOpState* bakedState = tryBakeUnboundedOpState(op);
     if (!bakedState) return; // quick rejected
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
 }
@@ -607,7 +622,10 @@
 }
 
 void FrameBuilder::deferPathOp(const PathOp& op) {
-    deferStrokeableOp(op, OpBatchType::Bitmap);
+    auto state = deferStrokeableOp(op, OpBatchType::AlphaMaskTexture);
+    if (CC_LIKELY(state)) {
+        mCaches.pathCache.precache(op.path, op.paint);
+    }
 }
 
 void FrameBuilder::deferPointsOp(const PointsOp& op) {
@@ -620,7 +638,12 @@
 }
 
 void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) {
-    deferStrokeableOp(op, tessBatchId(op));
+    auto state = deferStrokeableOp(op, tessBatchId(op));
+    if (CC_LIKELY(state && !op.paint->getPathEffect())) {
+        // TODO: consider storing tessellation task in BakedOpState
+        mCaches.tessellationCache.precacheRoundRect(state->computedState.transform, *(op.paint),
+                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
+    }
 }
 
 void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
@@ -646,7 +669,9 @@
 }
 
 void FrameBuilder::deferTextOp(const TextOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
+    BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
+            mAllocator, *mCanvasState.writableSnapshot(), op,
+            BakedOpState::StrokeBehavior::StyleDefined);
     if (!bakedState) return; // quick rejected
 
     batchid_t batchId = textBatchId(*(op.paint));
@@ -658,16 +683,43 @@
     } else {
         currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
     }
+
+    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
+    auto& totalTransform = bakedState->computedState.transform;
+    if (totalTransform.isPureTranslate() || totalTransform.isPerspective()) {
+        fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::I());
+    } else {
+        // Partial transform case, see BakedOpDispatcher::renderTextOp
+        float sx, sy;
+        totalTransform.decomposeScale(sx, sy);
+        fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::MakeScale(
+                roundf(std::max(1.0f, sx)),
+                roundf(std::max(1.0f, sy))));
+    }
 }
 
 void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
+    BakedOpState* bakedState = tryBakeUnboundedOpState(op);
     if (!bakedState) return; // quick rejected
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
+
+    mCaches.fontRenderer.getFontRenderer().precache(
+            op.paint, op.glyphs, op.glyphCount, SkMatrix::I());
 }
 
 void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
+    if (CC_UNLIKELY(!op.layer->isRenderable())) return;
+
+    const TextureLayerOp* textureLayerOp = &op;
+    // Now safe to access transform (which was potentially unready at record time)
+    if (!op.layer->getTransform().isIdentity()) {
+        // non-identity transform present, so 'inject it' into op by copying + replacing matrix
+        Matrix4 combinedMatrix(op.localMatrix);
+        combinedMatrix.multiply(op.layer->getTransform());
+        textureLayerOp = mAllocator.create<TextureLayerOp>(op, combinedMatrix);
+    }
+    BakedOpState* bakedState = tryBakeOpState(*textureLayerOp);
+
     if (!bakedState) return; // quick rejected
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
 }
@@ -782,39 +834,50 @@
     boundsTransform.mapRect(dstRect);
     dstRect.doIntersect(mCanvasState.currentSnapshot()->getRenderTargetClip());
 
-    // Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume)
-    OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr);
+    if (dstRect.isEmpty()) {
+        // Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored
+        currentLayer().activeUnclippedSaveLayers.push_back(nullptr);
+    } else {
+        // Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume)
+        OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr);
 
-    /**
-     * First, defer an operation to copy out the content from the rendertarget into a layer.
-     */
-    auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
-    BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
-            &(currentLayer().viewportClip), dstRect, *copyToOp);
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
+        /**
+         * First, defer an operation to copy out the content from the rendertarget into a layer.
+         */
+        auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
+        BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
+                &(currentLayer().repaintClip), dstRect, *copyToOp);
+        currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
 
-    /**
-     * Defer a clear rect, so that clears from multiple unclipped layers can be drawn
-     * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible
-     */
-    currentLayer().deferLayerClear(dstRect);
+        /**
+         * Defer a clear rect, so that clears from multiple unclipped layers can be drawn
+         * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible
+         */
+        currentLayer().deferLayerClear(dstRect);
 
-    /**
-     * And stash an operation to copy that layer back under the rendertarget until
-     * a balanced EndUnclippedLayerOp is seen
-     */
-    auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
-    bakedState = BakedOpState::directConstruct(mAllocator,
-            &(currentLayer().viewportClip), dstRect, *copyFromOp);
-    currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
+        /**
+         * And stash an operation to copy that layer back under the rendertarget until
+         * a balanced EndUnclippedLayerOp is seen
+         */
+        auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
+        bakedState = BakedOpState::directConstruct(mAllocator,
+                &(currentLayer().repaintClip), dstRect, *copyFromOp);
+        currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
+    }
 }
 
 void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) {
     LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!");
 
     BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back();
-    currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer);
     currentLayer().activeUnclippedSaveLayers.pop_back();
+    if (copyFromLayerOp) {
+        currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer);
+    }
+}
+
+void FrameBuilder::finishDefer() {
+    mCaches.fontRenderer.endPrecaching();
 }
 
 } // namespace uirenderer
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index f44306a..039ab6b 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -65,14 +65,16 @@
             uint32_t viewportWidth, uint32_t viewportHeight,
             const std::vector< sp<RenderNode> >& nodes,
             const LightGeometry& lightGeometry,
-            Caches* caches)
-            : FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightGeometry, Rect(), caches) {}
+            Caches& caches)
+            : FrameBuilder(layers, clip, viewportWidth, viewportHeight,
+                    nodes, lightGeometry, Rect(), caches) {}
 
     FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
             uint32_t viewportWidth, uint32_t viewportHeight,
             const std::vector< sp<RenderNode> >& nodes,
             const LightGeometry& lightGeometry,
-            const Rect &contentDrawBounds, Caches* caches);
+            const Rect &contentDrawBounds,
+            Caches& caches);
 
     virtual ~FrameBuilder() {}
 
@@ -81,10 +83,11 @@
      *
      * It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use
      * state->op->opId to lookup a receiver that will be called when the op is replayed.
-     *
      */
     template <typename StaticDispatcher, typename Renderer>
     void replayBakedOps(Renderer& renderer) {
+        std::vector<OffscreenBuffer*> temporaryLayers;
+        finishDefer();
         /**
          * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
          * dispatch the op via a method on a static dispatcher when the op is replayed.
@@ -127,6 +130,7 @@
             } else if (!layer.empty()) {
                 // save layer - skip entire layer if empty (in which case, LayerOp has null layer).
                 layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height);
+                temporaryLayers.push_back(layer.offscreenBuffer);
                 GL_CHECKPOINT(MODERATE);
                 layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
                 GL_CHECKPOINT(MODERATE);
@@ -135,12 +139,18 @@
         }
 
         GL_CHECKPOINT(MODERATE);
-        const LayerBuilder& fbo0 = *(mLayerBuilders[0]);
-        renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
-        GL_CHECKPOINT(MODERATE);
-        fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
-        GL_CHECKPOINT(MODERATE);
-        renderer.endFrame(fbo0.repaintRect);
+        if (CC_LIKELY(mDrawFbo0)) {
+            const LayerBuilder& fbo0 = *(mLayerBuilders[0]);
+            renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
+            GL_CHECKPOINT(MODERATE);
+            fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
+            GL_CHECKPOINT(MODERATE);
+            renderer.endFrame(fbo0.repaintRect);
+        }
+
+        for (auto& temporaryLayer : temporaryLayers) {
+            renderer.recycleTemporaryLayer(temporaryLayer);
+        }
     }
 
     void dump() const {
@@ -157,6 +167,7 @@
     virtual GLuint getTargetFbo() const override { return 0; }
 
 private:
+    void finishDefer();
     enum class ChildrenSelectMode {
         Negative,
         Positive
@@ -173,6 +184,10 @@
     BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
         return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
     }
+    BakedOpState* tryBakeUnboundedOpState(const RecordedOp& recordedOp) {
+        return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
+    }
+
 
     // should always be surrounded by a save/restore pair, and not called if DisplayList is null
     void deferNodePropsAndOps(RenderNode& node);
@@ -194,7 +209,7 @@
         return mAllocator.create<SkPath>();
     }
 
-    void deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+    BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
             BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);
 
     /**
@@ -226,12 +241,14 @@
 
     CanvasState mCanvasState;
 
-    Caches* mCaches = nullptr;
+    Caches& mCaches;
 
     float mLightRadius;
 
     // contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches
     LinearAllocator mAllocator;
+
+    const bool mDrawFbo0;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index b7dd3b7..adadd32 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -15,7 +15,11 @@
  */
 #include "FrameInfoVisualizer.h"
 
+#if HWUI_NEW_OPS
+#include "BakedOpRenderer.h"
+#else
 #include "OpenGLRenderer.h"
+#endif
 #include "utils/Color.h"
 
 #include <cutils/compiler.h>
@@ -88,7 +92,7 @@
     }
 }
 
-void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::draw(ContentRenderer* renderer) {
     RETURN_IF_DISABLED();
 
     if (mShowDirtyRegions) {
@@ -96,7 +100,7 @@
         if (mFlashToggle) {
             SkPaint paint;
             paint.setColor(0x7fff0000);
-            canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
+            renderer->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
                     mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
         }
     }
@@ -111,9 +115,9 @@
         info.markSwapBuffers();
         info.markFrameCompleted();
 
-        initializeRects(canvas->getViewportHeight(), canvas->getViewportWidth());
-        drawGraph(canvas);
-        drawThreshold(canvas);
+        initializeRects(renderer->getViewportHeight(), renderer->getViewportWidth());
+        drawGraph(renderer);
+        drawThreshold(renderer);
     }
 }
 
@@ -194,27 +198,26 @@
     }
 }
 
-void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::drawGraph(ContentRenderer* renderer) {
     SkPaint paint;
     for (size_t i = 0; i < Bar.size(); i++) {
         nextBarSegment(Bar[i].start, Bar[i].end);
         paint.setColor(Bar[i].color & BAR_FAST_MASK);
-        canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
+        renderer->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
         paint.setColor(Bar[i].color & BAR_JANKY_MASK);
-        canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
+        renderer->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
     }
 }
 
-void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::drawThreshold(ContentRenderer* renderer) {
     SkPaint paint;
     paint.setColor(THRESHOLD_COLOR);
-    paint.setStrokeWidth(mThresholdStroke);
-
-    float pts[4];
-    pts[0] = 0.0f;
-    pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
-    pts[2] = canvas->getViewportWidth();
-    canvas->drawLines(pts, 4, &paint);
+    float yLocation = renderer->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
+    renderer->drawRect(0.0f,
+            yLocation - mThresholdStroke/2,
+            renderer->getViewportWidth(),
+            yLocation + mThresholdStroke/2,
+            &paint);
 }
 
 bool FrameInfoVisualizer::consumeProperties() {
diff --git a/libs/hwui/FrameInfoVisualizer.h b/libs/hwui/FrameInfoVisualizer.h
index cf877c4..83adf19 100644
--- a/libs/hwui/FrameInfoVisualizer.h
+++ b/libs/hwui/FrameInfoVisualizer.h
@@ -28,7 +28,13 @@
 namespace android {
 namespace uirenderer {
 
+#if HWUI_NEW_OPS
+class BakedOpRenderer;
+typedef BakedOpRenderer ContentRenderer;
+#else
 class OpenGLRenderer;
+typedef OpenGLRenderer ContentRenderer;
+#endif
 
 // TODO: This is a bit awkward as it needs to match the thing in CanvasContext
 // A better abstraction here would be nice but iterators are painful
@@ -46,7 +52,7 @@
     void setDensity(float density);
 
     void unionDirty(SkRect* dirty);
-    void draw(OpenGLRenderer* canvas);
+    void draw(ContentRenderer* renderer);
 
     void dumpData(int fd);
 
@@ -56,8 +62,8 @@
 
     void initializeRects(const int baseline, const int width);
     void nextBarSegment(FrameInfoIndex start, FrameInfoIndex end);
-    void drawGraph(OpenGLRenderer* canvas);
-    void drawThreshold(OpenGLRenderer* canvas);
+    void drawGraph(ContentRenderer* renderer);
+    void drawThreshold(ContentRenderer* renderer);
 
     inline float durationMS(size_t index, FrameInfoIndex start, FrameInfoIndex end) {
         float duration = mFrameSource[index].duration(start, end) * 0.000001f;
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index e72f396..6a96634 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -81,8 +81,10 @@
  * vertex/index/Texture/RoundRectClipState pointers prevent this from
  * being safe.
  */
-// TODO: PREVENT_COPY_AND_ASSIGN(...) or similar
 struct Glop {
+    PREVENT_COPY_AND_ASSIGN(Glop);
+public:
+    Glop() { }
     struct Mesh {
         GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
 
@@ -149,7 +151,7 @@
        }
     } transform;
 
-    const RoundRectClipState* roundRectClipState;
+    const RoundRectClipState* roundRectClipState = nullptr;
 
     /**
      * Blending to be used by this draw - both GL_NONE if blending is disabled.
@@ -161,11 +163,13 @@
         GLenum dst;
     } blend;
 
+#if !HWUI_NEW_OPS
     /**
      * Bounds of the drawing command in layer space. Only mapped into layer
      * space once GlopBuilder::build() is called.
      */
-    Rect bounds;
+    Rect bounds; // TODO: remove for HWUI_NEW_OPS
+#endif
 
     /**
      * Additional render state to enumerate:
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 45fc16c..7d4f410 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -492,7 +492,9 @@
 
     mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
     mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = destination;
+#endif
     return *this;
 }
 
@@ -516,7 +518,9 @@
 
     mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
     mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = destination;
+#endif
     return *this;
 }
 
@@ -524,8 +528,10 @@
     TRIGGER_STAGE(kModelViewStage);
 
     mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = source;
     mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
     return *this;
 }
 
@@ -545,8 +551,10 @@
     }
 
     mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = source;
     mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
     return *this;
 }
 
@@ -643,7 +651,9 @@
 
     // Final step: populate program and map bounds into render target space
     mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+#if !HWUI_NEW_OPS
     mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds);
+#endif
 }
 
 void GlopBuilder::dump(const Glop& glop) {
@@ -676,11 +686,16 @@
             fill.skiaShaderData.skiaShaderType);
 
     ALOGD("Glop transform");
-    glop.transform.modelView.dump("model view");
-    glop.transform.canvas.dump("canvas");
+    glop.transform.modelView.dump("  model view");
+    glop.transform.canvas.dump("  canvas");
+    ALOGD_IF(glop.transform.transformFlags, "  transformFlags 0x%x", glop.transform.transformFlags);
+
+    ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState);
 
     ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst);
+#if !HWUI_NEW_OPS
     ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds));
+#endif
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index c305f65..d1ff670 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -15,12 +15,16 @@
  */
 #include "JankTracker.h"
 
+#include "Properties.h"
+
 #include <algorithm>
 #include <cutils/ashmem.h>
 #include <cutils/log.h>
 #include <cstdio>
 #include <errno.h>
 #include <inttypes.h>
+#include <limits>
+#include <cmath>
 #include <sys/mman.h>
 
 namespace android {
@@ -52,32 +56,35 @@
 static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
 
 /*
- * Frames that are exempt from jank metrics.
- * First-draw frames, for example, are expected to
- * be slow, this is hidden from the user with window animations and
- * other tricks
- *
- * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas()
+ * We don't track direct-drawing via Surface:lockHardwareCanvas()
  * for now
  *
  * TODO: kSurfaceCanvas can negatively impact other drawing by using up
  * time on the RenderThread, figure out how to attribute that as a jank-causer
  */
-static const int64_t EXEMPT_FRAMES_FLAGS
-        = FrameInfoFlags::WindowLayoutChanged
-        | FrameInfoFlags::SurfaceCanvas;
+static const int64_t EXEMPT_FRAMES_FLAGS = FrameInfoFlags::SurfaceCanvas;
 
 // The bucketing algorithm controls so to speak
 // If a frame is <= to this it goes in bucket 0
-static const uint32_t kBucketMinThreshold = 7;
+static const uint32_t kBucketMinThreshold = 5;
 // If a frame is > this, start counting in increments of 2ms
 static const uint32_t kBucket2msIntervals = 32;
 // If a frame is > this, start counting in increments of 4ms
 static const uint32_t kBucket4msIntervals = 48;
 
+// For testing purposes to try and eliminate test infra overhead we will
+// consider any unknown delay of frame start as part of the test infrastructure
+// and filter it out of the frame profile data
+static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync;
+
+// The interval of the slow frame histogram
+static const uint32_t kSlowFrameBucketIntervalMs = 50;
+// The start point of the slow frame bucket in ms
+static const uint32_t kSlowFrameBucketStartMs = 150;
+
 // This will be called every frame, performance sensitive
 // Uses bit twiddling to avoid branching while achieving the packing desired
-static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime, uint32_t max) {
+static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime) {
     uint32_t index = static_cast<uint32_t>(ns2ms(frameTime));
     // If index > kBucketMinThreshold mask will be 0xFFFFFFFF as a result
     // of negating 1 (twos compliment, yaay) else mask will be 0
@@ -95,7 +102,7 @@
     // be a pretty garbage value right now. However, mask is 0 so we'll end
     // up with the desired result of 0.
     index = (index - kBucketMinThreshold) & mask;
-    return index < max ? index : max;
+    return index;
 }
 
 // Only called when dumping stats, less performance sensitive
@@ -206,20 +213,30 @@
     mData->totalFrameCount++;
     // Fast-path for jank-free frames
     int64_t totalDuration =
-            frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::IntendedVsync];
-    uint32_t framebucket = frameCountIndexForFrameTime(
-            totalDuration, mData->frameCounts.size());
+            frame[FrameInfoIndex::FrameCompleted] - frame[sFrameStart];
+    uint32_t framebucket = frameCountIndexForFrameTime(totalDuration);
     // Keep the fast path as fast as possible.
     if (CC_LIKELY(totalDuration < mFrameInterval)) {
         mData->frameCounts[framebucket]++;
         return;
     }
 
+    // Only things like Surface.lockHardwareCanvas() are exempt from tracking
     if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
         return;
     }
 
-    mData->frameCounts[framebucket]++;
+    if (framebucket <= mData->frameCounts.size()) {
+        mData->frameCounts[framebucket]++;
+    } else {
+        framebucket = (ns2ms(totalDuration) - kSlowFrameBucketStartMs)
+                / kSlowFrameBucketIntervalMs;
+        framebucket = std::min(framebucket,
+                static_cast<uint32_t>(mData->slowFrameCounts.size() - 1));
+        framebucket = std::max(framebucket, 0u);
+        mData->slowFrameCounts[framebucket]++;
+    }
+
     mData->jankFrameCount++;
 
     for (int i = 0; i < NUM_BUCKETS; i++) {
@@ -239,6 +256,9 @@
 }
 
 void JankTracker::dumpData(const ProfileData* data, int fd) {
+    if (sFrameStart != FrameInfoIndex::IntendedVsync) {
+        dprintf(fd, "\nNote: Data has been filtered!");
+    }
     dprintf(fd, "\nStats since: %" PRIu64 "ns", data->statStartTime);
     dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
     dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
@@ -250,6 +270,15 @@
     for (int i = 0; i < NUM_BUCKETS; i++) {
         dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
     }
+    dprintf(fd, "\nHISTOGRAM:");
+    for (size_t i = 0; i < data->frameCounts.size(); i++) {
+        dprintf(fd, " %ums=%u", frameTimeForFrameCountIndex(i),
+                data->frameCounts[i]);
+    }
+    for (size_t i = 0; i < data->slowFrameCounts.size(); i++) {
+        dprintf(fd, " %zums=%u", (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs,
+                data->slowFrameCounts[i]);
+    }
     dprintf(fd, "\n");
 }
 
@@ -259,11 +288,20 @@
     mData->totalFrameCount = 0;
     mData->jankFrameCount = 0;
     mData->statStartTime = systemTime(CLOCK_MONOTONIC);
+    sFrameStart = Properties::filterOutTestOverhead
+            ? FrameInfoIndex::HandleInputStart
+            : FrameInfoIndex::IntendedVsync;
 }
 
 uint32_t JankTracker::findPercentile(const ProfileData* data, int percentile) {
     int pos = percentile * data->totalFrameCount / 100;
     int remaining = data->totalFrameCount - pos;
+    for (int i = data->slowFrameCounts.size() - 1; i >= 0; i--) {
+        remaining -= data->slowFrameCounts[i];
+        if (remaining <= 0) {
+            return (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs;
+        }
+    }
     for (int i = data->frameCounts.size() - 1; i >= 0; i--) {
         remaining -= data->frameCounts[i];
         if (remaining <= 0) {
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 3887e5e..84b8c3f 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -44,7 +44,9 @@
 struct ProfileData {
     std::array<uint32_t, NUM_BUCKETS> jankTypeCounts;
     // See comments on kBucket* constants for what this holds
-    std::array<uint32_t, 55> frameCounts;
+    std::array<uint32_t, 57> frameCounts;
+    // Holds a histogram of frame times in 50ms increments from 150ms to 5s
+    std::array<uint16_t, 97> slowFrameCounts;
 
     uint32_t totalFrameCount;
     uint32_t jankFrameCount;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 114347d..cdbbbab 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -197,7 +197,12 @@
 }
 
 void Layer::clearTexture() {
-    caches.textureState().unbindTexture(texture.mId);
+    // There's a rare possibility that Caches could have been destroyed already
+    // since this method is queued up as a task.
+    // Since this is a reset method, treat this as non-fatal.
+    if (caches.isInitialized()) {
+        caches.textureState().unbindTexture(texture.mId);
+    }
     texture.mId = 0;
 }
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index e00ae66..1e5498b 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -216,6 +216,10 @@
         this->renderTarget = renderTarget;
     }
 
+    inline bool isRenderable() const {
+        return renderTarget != GL_NONE;
+    }
+
     void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
         texture.setWrap(wrap, bindTexture, force, renderTarget);
     }
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index 1ba3bf2..eea11bf 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -140,7 +140,10 @@
         // Identical round rect clip state means both ops will clip in the same way, or not at all.
         // As the state objects are const, we can compare their pointers to determine mergeability
         if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
-        if (lhs->projectionPathMask != rhs->projectionPathMask) return false;
+
+        // Local masks prevent merge, since they're potentially in different coordinate spaces
+        if (lhs->computedState.localProjectionPathMask
+                || rhs->computedState.localProjectionPathMask) return false;
 
         /* Clipping compatibility check
          *
@@ -199,10 +202,10 @@
         : width(width)
         , height(height)
         , repaintRect(repaintRect)
+        , repaintClip(repaintRect)
         , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr)
         , beginLayerOp(beginLayerOp)
-        , renderNode(renderNode)
-        , viewportClip(Rect(width, height)) {}
+        , renderNode(renderNode) {}
 
 // iterate back toward target to see if anything drawn since should overlap the new op
 // if no target, merging ops still iterate to find similar batch to insert after
@@ -233,13 +236,28 @@
     mClearRects.push_back(rect);
 }
 
+void LayerBuilder::onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState) {
+    if (bakedState->op->opId != RecordedOpId::CopyToLayerOp) {
+        // First non-CopyToLayer, so stop stashing up layer clears for unclipped save layers,
+        // and issue them together in one draw.
+        flushLayerClears(allocator);
+
+        if (CC_UNLIKELY(activeUnclippedSaveLayers.empty()
+                && bakedState->computedState.opaqueOverClippedBounds
+                && bakedState->computedState.clippedBounds.contains(repaintRect))) {
+            // discard all deferred drawing ops, since new one will occlude them
+            clear();
+        }
+    }
+}
+
 void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
     if (CC_UNLIKELY(!mClearRects.empty())) {
         const int vertCount = mClearRects.size() * 4;
         // put the verts in the frame allocator, since
         //     1) SimpleRectsOps needs verts, not rects
         //     2) even if mClearRects stored verts, std::vectors will move their contents
-        Vertex* const verts = (Vertex*) allocator.alloc<Vertex>(vertCount * sizeof(Vertex));
+        Vertex* const verts = (Vertex*) allocator.create_trivial_array<Vertex>(vertCount);
 
         Vertex* currentVert = verts;
         Rect bounds = mClearRects[0];
@@ -260,18 +278,14 @@
                 Matrix4::identity(), nullptr, paint,
                 verts, vertCount);
         BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
-                &viewportClip, bounds, *op);
+                &repaintClip, bounds, *op);
         deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices);
     }
 }
 
 void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
         BakedOpState* op, batchid_t batchId) {
-    if (batchId != OpBatchType::CopyToLayer) {
-        // if first op after one or more unclipped saveLayers, flush the layer clears
-        flushLayerClears(allocator);
-    }
-
+    onDeferOp(allocator, op);
     OpBatch* targetBatch = mBatchLookup[batchId];
 
     size_t insertBatchIndex = mBatches.size();
@@ -292,10 +306,7 @@
 
 void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
         BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
-    if (batchId != OpBatchType::CopyToLayer) {
-        // if first op after one or more unclipped saveLayers, flush the layer clears
-        flushLayerClears(allocator);
-    }
+    onDeferOp(allocator, op);
     MergingOpBatch* targetBatch = nullptr;
 
     // Try to merge with any existing batch with same mergeId
@@ -345,9 +356,18 @@
     }
 }
 
+void LayerBuilder::clear() {
+    mBatches.clear();
+    for (int i = 0; i < OpBatchType::Count; i++) {
+        mBatchLookup[i] = nullptr;
+        mMergingBatchLookup[i].clear();
+    }
+}
+
 void LayerBuilder::dump() const {
-    ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p",
-            this, width, height, offscreenBuffer, beginLayerOp, renderNode);
+    ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)",
+            this, width, height, offscreenBuffer, beginLayerOp,
+            renderNode, renderNode ? renderNode->getName() : "-");
     for (const BatchBase* batch : mBatches) {
         batch->dump();
     }
diff --git a/libs/hwui/LayerBuilder.h b/libs/hwui/LayerBuilder.h
index 99968e1..4de432c 100644
--- a/libs/hwui/LayerBuilder.h
+++ b/libs/hwui/LayerBuilder.h
@@ -100,23 +100,22 @@
         return mBatches.empty();
     }
 
-    void clear() {
-        mBatches.clear();
-    }
+    void clear();
 
     void dump() const;
 
     const uint32_t width;
     const uint32_t height;
     const Rect repaintRect;
+    const ClipRect repaintClip;
     OffscreenBuffer* offscreenBuffer;
     const BeginLayerOp* beginLayerOp;
     const RenderNode* renderNode;
-    const ClipRect viewportClip;
 
     // list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps
     std::vector<BakedOpState*> activeUnclippedSaveLayers;
 private:
+    void onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState);
     void flushLayerClears(LinearAllocator& allocator);
 
     std::vector<BatchBase*> mBatches;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e04b9a2..137316f 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -353,7 +353,7 @@
 
 bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
-    if (layer
+    if (layer && layer->isRenderable()
             && bitmap->width() <= caches.maxTextureSize
             && bitmap->height() <= caches.maxTextureSize) {
 
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 73ebd1304..709156c 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -437,6 +437,14 @@
     y = dy * dz;
 }
 
+/**
+ * Set the contents of the rect to be the bounding rect around each of the corners, mapped by the
+ * matrix.
+ *
+ * NOTE: an empty rect to an arbitrary matrix isn't guaranteed to have an empty output, since that's
+ * important for conservative bounds estimation (e.g. rotate45Matrix.mapRect of Rect(0, 10) should
+ * result in non-empty.
+ */
 void Matrix4::mapRect(Rect& r) const {
     if (isIdentity()) return;
 
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 1c25f26..36007cd 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HWUI_MATRIX_H
-#define ANDROID_HWUI_MATRIX_H
-
-#include <SkMatrix.h>
-
-#include <cutils/compiler.h>
+#pragma once
 
 #include "Rect.h"
 
+#include <cutils/compiler.h>
+#include <iomanip>
+#include <ostream>
+#include <SkMatrix.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -218,6 +218,22 @@
 
     void dump(const char* label = nullptr) const;
 
+    friend std::ostream& operator<<(std::ostream& os, const Matrix4& matrix) {
+        if (matrix.isSimple()) {
+            os << "offset " << matrix.getTranslateX() << "x" << matrix.getTranslateY();
+            if (!matrix.isPureTranslate()) {
+                os << ", scale " << matrix[kScaleX] << "x" << matrix[kScaleY];
+            }
+        } else {
+            os << "[" << matrix[0];
+            for (int i = 1; i < 16; i++) {
+                os << ", " << matrix[i];
+            }
+            os << "]";
+        }
+        return os;
+    }
+
     static const Matrix4& identity();
 
 private:
@@ -244,4 +260,3 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_HWUI_MATRIX_H
diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp
new file mode 100644
index 0000000..c34cfbe
--- /dev/null
+++ b/libs/hwui/OpDumper.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "OpDumper.h"
+
+#include "RecordedOp.h"
+
+namespace android {
+namespace uirenderer {
+
+#define STRINGIFY(n) #n,
+static const char* sOpNameLut[] = BUILD_FULL_OP_LUT(STRINGIFY);
+
+void OpDumper::dump(const RecordedOp& op, std::ostream& output, int level) {
+    for (int i = 0; i < level; i++) {
+        output << "  ";
+    }
+
+    Rect localBounds(op.unmappedBounds);
+    op.localMatrix.mapRect(localBounds);
+    output << sOpNameLut[op.opId] << " " << localBounds;
+
+    if (op.localClip && !op.localClip->rect.contains(localBounds)) {
+        output << std::fixed << std::setprecision(0)
+             << " clip=" << op.localClip->rect
+             << " mode=" << (int)op.localClip->mode;
+    }
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpDumper.h b/libs/hwui/OpDumper.h
new file mode 100644
index 0000000..c99b517
--- /dev/null
+++ b/libs/hwui/OpDumper.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ostream>
+
+namespace android {
+namespace uirenderer {
+
+struct RecordedOp;
+
+class OpDumper {
+public:
+    static void dump(const RecordedOp& op, std::ostream& output, int level = 0);
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b7a5923..53ea7fa 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -17,7 +17,6 @@
 #include <GpuMemoryTracker.h>
 #include "OpenGLRenderer.h"
 
-#include "Canvas.h"
 #include "DeferredDisplayList.h"
 #include "GammaFontRenderer.h"
 #include "Glop.h"
@@ -32,6 +31,7 @@
 #include "SkiaShader.h"
 #include "Vector.h"
 #include "VertexBuffer.h"
+#include "hwui/Canvas.h"
 #include "utils/GLUtils.h"
 #include "utils/PaintUtils.h"
 #include "utils/TraceUtils.h"
@@ -1148,7 +1148,9 @@
 
     // always store/restore, since these are just pointers
     state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
+#if !HWUI_NEW_OPS
     state.mProjectionPathMask = currentSnapshot()->projectionPathMask;
+#endif
     return false;
 }
 
@@ -1156,7 +1158,9 @@
     setGlobalMatrix(state.mMatrix);
     writableSnapshot()->alpha = state.mAlpha;
     writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
+#if !HWUI_NEW_OPS
     writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
+#endif
 
     if (state.mClipValid && !skipClipRestore) {
         writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
@@ -1409,7 +1413,9 @@
     if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
         // TODO: specify more clearly when a draw should dirty the layer.
         // is writing to the stencil the only time we should ignore this?
+#if !HWUI_NEW_OPS
         dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+#endif
         mDirty = true;
     }
 }
@@ -1833,6 +1839,7 @@
         path.addCircle(x, y, radius);
     }
 
+#if !HWUI_NEW_OPS
     if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) {
         // mask ripples with projection mask
         SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask);
@@ -1852,6 +1859,7 @@
         // in local space. Note that this can create CCW paths.
         Op(path, maskPath, kIntersect_SkPathOp, &path);
     }
+#endif
     drawConvexPath(path, p);
 }
 
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 6df994c..165c7db 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -36,12 +36,14 @@
     CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
 
     uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
-    void unmap() override;
 
     uint8_t* getMappedPointer() const override;
 
     void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
 
+protected:
+    void unmap() override;
+
 private:
     std::unique_ptr<uint8_t[]> mBuffer;
 };
@@ -81,12 +83,14 @@
     ~GpuPixelBuffer();
 
     uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
-    void unmap() override;
 
     uint8_t* getMappedPointer() const override;
 
     void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
 
+protected:
+    void unmap() override;
+
 private:
     GLuint mBuffer;
     uint8_t* mMappedPointer;
@@ -118,6 +122,7 @@
             LOG_ALWAYS_FATAL("Failed to map PBO");
         }
         mAccessMode = mode;
+        mCaches.pixelBufferState().unbind();
     }
 
     return mMappedPointer;
@@ -147,6 +152,7 @@
     unmap();
     glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
             GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
+    mCaches.pixelBufferState().unbind();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index aac5ec4..bbef36b 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -91,14 +91,6 @@
     virtual uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) = 0;
 
     /**
-     * Unmaps this buffer, if needed. After the buffer is unmapped,
-     * the pointer previously returned by map() becomes invalid and
-     * should not be used. After calling this method, getMappedPointer()
-     * will always return NULL.
-     */
-    virtual void unmap() = 0;
-
-    /**
      * Returns the current access mode for this buffer. If the buffer
      * is not mapped, this method returns kAccessMode_None.
      */
@@ -204,6 +196,14 @@
             mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
     }
 
+    /**
+     * Unmaps this buffer, if needed. After the buffer is unmapped,
+     * the pointer previously returned by map() becomes invalid and
+     * should not be used. After calling this method, getMappedPointer()
+     * will always return NULL.
+     */
+    virtual void unmap() = 0;
+
     GLenum mFormat;
 
     uint32_t mWidth;
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index bbd8c72..6f68c2b 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -66,6 +66,8 @@
 
 bool Properties::waitForGpuCompletion = false;
 
+bool Properties::filterOutTestOverhead = false;
+
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {'\0',};
 
@@ -156,6 +158,8 @@
     textureCacheFlushRate = std::max(0.0f, std::min(1.0f,
             property_get_float(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, DEFAULT_TEXTURE_CACHE_FLUSH_RATE)));
 
+    filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false);
+
     return (prevDebugLayersUpdates != debugLayersUpdates)
             || (prevDebugOverdraw != debugOverdraw)
             || (prevDebugStencilClip != debugStencilClip);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 249b5b0..171873d 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -151,6 +151,8 @@
  */
 #define PROPERTY_ENABLE_PARTIAL_UPDATES "debug.hwui.enable_partial_updates"
 
+#define PROPERTY_FILTER_TEST_OVERHEAD "debug.hwui.filter_test_overhead"
+
 ///////////////////////////////////////////////////////////////////////////////
 // Runtime configuration properties
 ///////////////////////////////////////////////////////////////////////////////
@@ -294,6 +296,10 @@
     // Should be used only by test apps
     static bool waitForGpuCompletion;
 
+    // Should only be set by automated tests to try and filter out
+    // any overhead they add
+    static bool filterOutTestOverhead;
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 8f837f6..0932d65 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -53,7 +53,7 @@
     } else {
         animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
     }
-    mGroup->setPropertyValue(mPropertyId, animatedValue);
+    mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
 }
 
 inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) {
@@ -72,7 +72,7 @@
 
 void FullPathColorPropertyValuesHolder::setFraction(float fraction) {
     SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction);
-    mFullPath->setColorPropertyValue(mPropertyId, animatedValue);
+    mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue);
 }
 
 void FullPathPropertyValuesHolder::setFraction(float fraction) {
@@ -82,17 +82,17 @@
     } else {
         animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
     }
-    mFullPath->setPropertyValue(mPropertyId, animatedValue);
+    mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
 }
 
 void PathDataPropertyValuesHolder::setFraction(float fraction) {
     VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction);
-    mPath->setPathData(mPathData);
+    mPath->mutateProperties()->setData(mPathData);
 }
 
 void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
     float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
-    mTree->setRootAlpha(animatedValue);
+    mTree->mutateProperties()->setRootAlpha(animatedValue);
 }
 
 } // namepace uirenderer
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index bb26e2e..aee9d63 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -90,6 +90,7 @@
         UNMERGEABLE_OP_FN(ArcOp) \
         UNMERGEABLE_OP_FN(BitmapMeshOp) \
         UNMERGEABLE_OP_FN(BitmapRectOp) \
+        UNMERGEABLE_OP_FN(ColorOp) \
         UNMERGEABLE_OP_FN(FunctorOp) \
         UNMERGEABLE_OP_FN(LinesOp) \
         UNMERGEABLE_OP_FN(OvalOp) \
@@ -119,6 +120,9 @@
 #define BUILD_RENDERABLE_OP_LUT(OP_FN) \
         { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
 
+#define BUILD_FULL_OP_LUT(OP_FN) \
+        { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) }
+
 /**
  * Op mapping functions, which skip unsupported ops.
  *
@@ -253,9 +257,21 @@
     const float* radius;
 };
 
+struct ColorOp : RecordedOp {
+    // Note: unbounded op that will fillclip, so no bounds/matrix needed
+    ColorOp(const ClipBase* localClip, int color, SkXfermode::Mode mode)
+            : RecordedOp(RecordedOpId::ColorOp, Rect(), Matrix4::identity(), localClip, nullptr)
+            , color(color)
+            , mode(mode) {}
+    const int color;
+    const SkXfermode::Mode mode;
+};
+
 struct FunctorOp : RecordedOp {
-    FunctorOp(BASE_PARAMS_PAINTLESS, Functor* functor)
-            : SUPER_PAINTLESS(FunctorOp)
+    // Note: undefined record-time bounds, since this op fills the clip
+    // TODO: explicitly define bounds
+    FunctorOp(const Matrix4& localMatrix, const ClipBase* localClip, Functor* functor)
+            : RecordedOp(RecordedOpId::FunctorOp, Rect(), localMatrix, localClip, nullptr)
             , functor(functor) {}
     Functor* functor;
 };
@@ -382,9 +398,10 @@
 };
 
 struct TextOnPathOp : RecordedOp {
-    TextOnPathOp(BASE_PARAMS, const glyph_t* glyphs, int glyphCount,
-            const SkPath* path, float hOffset, float vOffset)
-            : SUPER(TextOnPathOp)
+    // TODO: explicitly define bounds
+    TextOnPathOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
+            const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset, float vOffset)
+            : RecordedOp(RecordedOpId::TextOnPathOp, Rect(), localMatrix, localClip, paint)
             , glyphs(glyphs)
             , glyphCount(glyphCount)
             , path(path)
@@ -402,6 +419,14 @@
     TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer)
             : SUPER_PAINTLESS(TextureLayerOp)
             , layer(layer) {}
+
+    // Copy an existing TextureLayerOp, replacing the underlying matrix
+    TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix)
+            : RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix,
+                    op.localClip, op.paint)
+            , layer(op.layer) {
+
+    }
     Layer* layer;
 };
 
@@ -476,22 +501,20 @@
  * when creating/tracking a SkPaint* during defer isn't worth the bother.
  */
 struct LayerOp : RecordedOp {
-    // Records a one-use (saveLayer) layer for drawing. Once drawn, the layer will be destroyed.
+    // Records a one-use (saveLayer) layer for drawing.
     LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
             : SUPER_PAINTLESS(LayerOp)
             , layerHandle(layerHandle)
             , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
             , mode(PaintUtils::getXfermodeDirect(paint))
-            , colorFilter(paint ? paint->getColorFilter() : nullptr)
-            , destroy(true) {}
+            , colorFilter(paint ? paint->getColorFilter() : nullptr) {}
 
     LayerOp(RenderNode& node)
             : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
             , layerHandle(node.getLayerHandle())
             , alpha(node.properties().layerProperties().alpha() / 255.0f)
             , mode(node.properties().layerProperties().xferMode())
-            , colorFilter(node.properties().layerProperties().colorFilter())
-            , destroy(false) {}
+            , colorFilter(node.properties().layerProperties().colorFilter()) {}
 
     // Records a handle to the Layer object, since the Layer itself won't be
     // constructed until after this operation is constructed.
@@ -502,9 +525,6 @@
     // pointer to object owned by either LayerProperties, or a recorded Paint object in a
     // BeginLayerOp. Lives longer than LayerOp in either case, so no skia ref counting is used.
     SkColorFilter* colorFilter;
-
-    // whether to destroy the layer, once rendered
-    const bool destroy;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 0adb21c..b78497d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -234,18 +234,17 @@
 // android/graphics/Canvas draw operations
 // ----------------------------------------------------------------------------
 void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
-    SkPaint paint;
-    paint.setColor(color);
-    paint.setXfermodeMode(mode);
-    drawPaint(paint);
+    addOp(alloc().create_trivial<ColorOp>(
+            getRecordedClip(),
+            color,
+            mode));
 }
 
 void RecordingCanvas::drawPaint(const SkPaint& paint) {
-    addOp(alloc().create_trivial<RectOp>(
-            mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
-            Matrix4::identity(),
-            getRecordedClip(),
-            refPaint(&paint)));
+    SkRect bounds;
+    if (getClipBounds(&bounds)) {
+        drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint);
+    }
 }
 
 static Rect calcBoundsOfPoints(const float* points, int floatCount) {
@@ -290,7 +289,7 @@
 void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
     if (rects == nullptr) return;
 
-    Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc<Vertex>(vertexCount * sizeof(Vertex));
+    Vertex* rectData = (Vertex*) mDisplayList->allocator.create_trivial_array<Vertex>(vertexCount);
     Vertex* vertex = rectData;
 
     float left = FLT_MAX;
@@ -347,11 +346,15 @@
 }
 void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, const SkPaint& paint) {
-    addOp(alloc().create_trivial<RoundRectOp>(
-            Rect(left, top, right, bottom),
-            *(mState.currentSnapshot()->transform),
-            getRecordedClip(),
-            refPaint(&paint), rx, ry));
+    if (CC_LIKELY(MathUtils::isPositive(rx) || MathUtils::isPositive(ry))) {
+        addOp(alloc().create_trivial<RoundRectOp>(
+                Rect(left, top, right, bottom),
+                *(mState.currentSnapshot()->transform),
+                getRecordedClip(),
+                refPaint(&paint), rx, ry));
+    } else {
+        drawRect(left, top, right, bottom, paint);
+    }
 }
 
 void RecordingCanvas::drawRoundRect(
@@ -427,10 +430,11 @@
 }
 
 void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
+    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
     mDisplayList->ref(tree);
     addOp(alloc().create_trivial<VectorDrawableOp>(
             tree,
-            Rect(tree->getBounds()),
+            Rect(tree->stagingProperties()->getBounds()),
             *(mState.currentSnapshot()->transform),
             getRecordedClip()));
 }
@@ -511,7 +515,7 @@
 }
 
 // Text
-void RecordingCanvas::drawText(const uint16_t* glyphs, const float* positions, int glyphCount,
+void RecordingCanvas::drawGlyphs(const uint16_t* glyphs, const float* positions, int glyphCount,
             const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
             float boundsRight, float boundsBottom, float totalAdvance) {
     if (!glyphs || !positions || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
@@ -527,12 +531,11 @@
     drawTextDecorations(x, y, totalAdvance, paint);
 }
 
-void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
+void RecordingCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
             float hOffset, float vOffset, const SkPaint& paint) {
     if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
     glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
     addOp(alloc().create_trivial<TextOnPathOp>(
-            mState.getLocalClipBounds(), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
             refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
@@ -554,15 +557,17 @@
             getRecordedClip(),
             renderNode);
     int opIndex = addOp(op);
-    int childIndex = mDisplayList->addChild(op);
+    if (CC_LIKELY(opIndex >= 0)) {
+        int childIndex = mDisplayList->addChild(op);
 
-    // update the chunk's child indices
-    DisplayList::Chunk& chunk = mDisplayList->chunks.back();
-    chunk.endChildIndex = childIndex + 1;
+        // update the chunk's child indices
+        DisplayList::Chunk& chunk = mDisplayList->chunks.back();
+        chunk.endChildIndex = childIndex + 1;
 
-    if (renderNode->stagingProperties().isProjectionReceiver()) {
-        // use staging property, since recording on UI thread
-        mDisplayList->projectionReceiveIndex = opIndex;
+        if (renderNode->stagingProperties().isProjectionReceiver()) {
+            // use staging property, since recording on UI thread
+            mDisplayList->projectionReceiveIndex = opIndex;
+        }
     }
 }
 
@@ -570,28 +575,32 @@
     // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
     mDisplayList->ref(layerHandle);
 
-    Layer* layer = layerHandle->backingLayer();
-    Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
-    totalTransform.multiply(layer->getTransform());
-
+    // Note that the backing layer has *not* yet been updated, so don't trust
+    // its width, height, transform, etc...!
     addOp(alloc().create_trivial<TextureLayerOp>(
-            Rect(layer->getWidth(), layer->getHeight()),
-            totalTransform,
+            Rect(layerHandle->getWidth(), layerHandle->getHeight()),
+            *(mState.currentSnapshot()->transform),
             getRecordedClip(),
-            layer));
+            layerHandle->backingLayer()));
 }
 
 void RecordingCanvas::callDrawGLFunction(Functor* functor) {
     mDisplayList->functors.push_back(functor);
     addOp(alloc().create_trivial<FunctorOp>(
-            mState.getLocalClipBounds(), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
             functor));
 }
 
 size_t RecordingCanvas::addOp(RecordedOp* op) {
-    // TODO: validate if "addDrawOp" quickrejection logic is useful before adding
+    // skip op with empty clip
+    if (op->localClip && op->localClip->rect.isEmpty()) {
+        // NOTE: this rejection happens after op construction/content ref-ing, so content ref'd
+        // and held by renderthread isn't affected by clip rejection.
+        // Could rewind alloc here if desired, but callers would have to not touch op afterwards.
+        return -1;
+    }
+
     int insertIndex = mDisplayList->ops.size();
     mDisplayList->ops.push_back(op);
     if (mDeferredBarrierType != DeferredBarrierType::None) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 719872d..acb88e2 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_HWUI_RECORDING_CANVAS_H
 #define ANDROID_HWUI_RECORDING_CANVAS_H
 
-#include "Canvas.h"
 #include "CanvasState.h"
 #include "DisplayList.h"
 #include "ResourceCache.h"
 #include "SkiaCanvasProxy.h"
 #include "Snapshot.h"
+#include "hwui/Canvas.h"
 #include "utils/LinearAllocator.h"
 #include "utils/Macros.h"
 #include "utils/NinePatch.h"
@@ -191,13 +191,16 @@
             const SkPaint* paint) override;
 
     // Text
-    virtual void drawText(const uint16_t* glyphs, const float* positions, int glyphCount,
-            const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
-            float boundsRight, float boundsBottom, float totalAdvance) override;
-    virtual void drawTextOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
-            float hOffset, float vOffset, const SkPaint& paint) override;
     virtual bool drawTextAbsolutePos() const override { return false; }
 
+protected:
+    virtual void drawGlyphs(const uint16_t* text, const float* positions, int count,
+            const SkPaint& paint, float x, float y,
+            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+            float totalAdvance) override;
+    virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) override;
+
 private:
     const ClipBase* getRecordedClip() {
         return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc());
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 30c925c..de4fa55 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HWUI_RECT_H
-#define ANDROID_HWUI_RECT_H
+#pragma once
 
-#include <cmath>
-#include <algorithm>
-#include <SkRect.h>
+#include "Vertex.h"
 
 #include <utils/Log.h>
 
-#include "Vertex.h"
+#include <algorithm>
+#include <cmath>
+#include <iomanip>
+#include <ostream>
+#include <SkRect.h>
 
 namespace android {
 namespace uirenderer {
@@ -282,9 +283,24 @@
     void dump(const char* label = nullptr) const {
         ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom);
     }
+
+    friend std::ostream& operator<<(std::ostream& os, const Rect& rect) {
+        if (rect.isEmpty()) {
+            // Print empty, but continue, since empty rects may still have useful coordinate info
+            os << "(empty)";
+        }
+
+        if (rect.left == 0 && rect.top == 0) {
+            return os << "[" << rect.right << " x " << rect.bottom << "]";
+        }
+
+        return os << "[" << rect.left
+                << " " << rect.top
+                << " " << rect.right
+                << " " << rect.bottom << "]";
+    }
 }; // class Rect
 
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_HWUI_RECT_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9ac76a4..9578486 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -19,8 +19,9 @@
 #include "DamageAccumulator.h"
 #include "Debug.h"
 #if HWUI_NEW_OPS
-#include "RecordedOp.h"
 #include "BakedOpRenderer.h"
+#include "RecordedOp.h"
+#include "OpDumper.h"
 #endif
 #include "DisplayListOp.h"
 #include "LayerRenderer.h"
@@ -67,7 +68,7 @@
 }
 
 RenderNode::~RenderNode() {
-    deleteDisplayList();
+    deleteDisplayList(nullptr);
     delete mStagingDisplayList;
 #if HWUI_NEW_OPS
     LOG_ALWAYS_FATAL_IF(mLayer, "layer missed detachment!");
@@ -87,7 +88,7 @@
     // If mParentCount == 0 we are the sole reference to this RenderNode,
     // so immediately free the old display list
     if (!mParentCount && !mStagingDisplayList) {
-        deleteDisplayList();
+        deleteDisplayList(nullptr);
     }
 }
 
@@ -95,6 +96,34 @@
  * This function is a simplified version of replay(), where we simply retrieve and log the
  * display list. This function should remain in sync with the replay() function.
  */
+#if HWUI_NEW_OPS
+void RenderNode::output(uint32_t level, const char* label) {
+    ALOGD("%s (%s %p%s%s%s%s%s)",
+            label,
+            getName(),
+            this,
+            (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""),
+            (properties().hasShadow() ? ", casting shadow" : ""),
+            (isRenderable() ? "" : ", empty"),
+            (properties().getProjectBackwards() ? ", projected" : ""),
+            (mLayer != nullptr ? ", on HW Layer" : ""));
+    properties().debugOutputProperties(level + 1);
+
+    if (mDisplayList) {
+        for (auto&& op : mDisplayList->getOps()) {
+            std::stringstream strout;
+            OpDumper::dump(*op, strout, level + 1);
+            if (op->opId == RecordedOpId::RenderNodeOp) {
+                auto rnOp = reinterpret_cast<const RenderNodeOp*>(op);
+                rnOp->renderNode->output(level + 1, strout.str().c_str());
+            } else {
+                ALOGD("%s", strout.str().c_str());
+            }
+        }
+    }
+    ALOGD("%*s/RenderNode(%s %p)", level * 2, "", getName(), this);
+}
+#else
 void RenderNode::output(uint32_t level) {
     ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this,
             getName(),
@@ -104,22 +133,16 @@
             (properties().getProjectBackwards() ? ", projected" : ""),
             (mLayer != nullptr ? ", on HW Layer" : ""));
     ALOGD("%*s%s %d", level * 2, "", "Save", SaveFlags::MatrixClip);
-
     properties().debugOutputProperties(level);
-
     if (mDisplayList) {
-#if HWUI_NEW_OPS
-        LOG_ALWAYS_FATAL("op dumping unsupported");
-#else
         // TODO: consider printing the chunk boundaries here
         for (auto&& op : mDisplayList->getOps()) {
             op->output(level, DisplayListOp::kOpLogFlag_Recurse);
         }
-#endif
     }
-
     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
-}
+    }
+#endif
 
 void RenderNode::copyTo(proto::RenderNode *pnode) {
     pnode->set_id(static_cast<uint64_t>(
@@ -439,7 +462,7 @@
 }
 #endif
 
-void RenderNode::syncDisplayList() {
+void RenderNode::syncDisplayList(TreeObserver* observer) {
     // Make sure we inc first so that we don't fluctuate between 0 and 1,
     // which would thrash the layer cache
     if (mStagingDisplayList) {
@@ -447,13 +470,16 @@
             child->renderNode->incParentRefCount();
         }
     }
-    deleteDisplayList();
+    deleteDisplayList(observer);
     mDisplayList = mStagingDisplayList;
     mStagingDisplayList = nullptr;
     if (mDisplayList) {
         for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) {
             (*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr);
         }
+        for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
+            (*mDisplayList->getPushStagingFunctors()[i])();
+        }
     }
 }
 
@@ -463,15 +489,15 @@
         // Damage with the old display list first then the new one to catch any
         // changes in isRenderable or, in the future, bounds
         damageSelf(info);
-        syncDisplayList();
+        syncDisplayList(info.observer);
         damageSelf(info);
     }
 }
 
-void RenderNode::deleteDisplayList() {
+void RenderNode::deleteDisplayList(TreeObserver* observer) {
     if (mDisplayList) {
         for (auto&& child : mDisplayList->getChildren()) {
-            child->renderNode->decParentRefCount();
+            child->renderNode->decParentRefCount(observer);
         }
     }
     delete mDisplayList;
@@ -503,32 +529,35 @@
     }
 }
 
-void RenderNode::destroyHardwareResources() {
+void RenderNode::destroyHardwareResources(TreeObserver* observer) {
     if (mLayer) {
         destroyLayer(mLayer);
         mLayer = nullptr;
     }
     if (mDisplayList) {
         for (auto&& child : mDisplayList->getChildren()) {
-            child->renderNode->destroyHardwareResources();
+            child->renderNode->destroyHardwareResources(observer);
         }
         if (mNeedsDisplayListSync) {
             // Next prepare tree we are going to push a new display list, so we can
             // drop our current one now
-            deleteDisplayList();
+            deleteDisplayList(observer);
         }
     }
 }
 
-void RenderNode::decParentRefCount() {
+void RenderNode::decParentRefCount(TreeObserver* observer) {
     LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
     mParentCount--;
     if (!mParentCount) {
+        if (observer) {
+            observer->onMaybeRemovedFromTree(this);
+        }
         // If a child of ours is being attached to our parent then this will incorrectly
         // destroy its hardware resources. However, this situation is highly unlikely
         // and the failure is "just" that the layer is re-created, so this should
         // be safe enough
-        destroyHardwareResources();
+        destroyHardwareResources(observer);
     }
 }
 
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index e037645..b0136cf 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -68,6 +68,7 @@
 class SaveOp;
 class RestoreToCountOp;
 class TreeInfo;
+class TreeObserver;
 
 namespace proto {
 class RenderNode;
@@ -123,7 +124,11 @@
     void defer(DeferStateStruct& deferStruct, const int level);
     void replay(ReplayStateStruct& replayStruct, const int level);
 
+#if HWUI_NEW_OPS
+    ANDROID_API void output(uint32_t level = 0, const char* label = "Root");
+#else
     ANDROID_API void output(uint32_t level = 1);
+#endif
     ANDROID_API int getDebugSize();
     void copyTo(proto::RenderNode* node);
 
@@ -150,6 +155,14 @@
         }
     }
 
+    VirtualLightRefBase* getUserContext() const {
+        return mUserContext.get();
+    }
+
+    void setUserContext(VirtualLightRefBase* context) {
+        mUserContext = context;
+    }
+
     bool isPropertyFieldDirty(DirtyPropertyMask field) const {
         return mDirtyPropertyFields & field;
     }
@@ -183,7 +196,7 @@
     }
 
     ANDROID_API virtual void prepareTree(TreeInfo& info);
-    void destroyHardwareResources();
+    void destroyHardwareResources(TreeObserver* observer);
 
     // UI thread only!
     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -228,6 +241,12 @@
         mPositionListener.reset(listener);
     }
 
+    // This is only modified in MODE_FULL, so it can be safely accessed
+    // on the UI thread.
+    ANDROID_API bool hasParents() {
+        return mParentCount;
+    }
+
 private:
     typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
 
@@ -287,7 +306,7 @@
 
 
     void syncProperties();
-    void syncDisplayList();
+    void syncDisplayList(TreeObserver* observer);
 
     void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
     void pushStagingPropertiesChanges(TreeInfo& info);
@@ -298,13 +317,14 @@
 #endif
     void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
     void pushLayerUpdate(TreeInfo& info);
-    void deleteDisplayList();
+    void deleteDisplayList(TreeObserver* observer);
     void damageSelf(TreeInfo& info);
 
     void incParentRefCount() { mParentCount++; }
-    void decParentRefCount();
+    void decParentRefCount(TreeObserver* observer);
 
     String8 mName;
+    sp<VirtualLightRefBase> mUserContext;
 
     uint32_t mDirtyPropertyFields;
     RenderProperties mProperties;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index b848af4..5ebf545 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -23,9 +23,9 @@
 #include <SkPath.h>
 #include <SkPathOps.h>
 
-#include "Canvas.h"
 #include "Matrix.h"
 #include "OpenGLRenderer.h"
+#include "hwui/Canvas.h"
 #include "utils/MathUtils.h"
 
 namespace android {
@@ -102,22 +102,23 @@
 
 void RenderProperties::debugOutputProperties(const int level) const {
     if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
-        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
+        ALOGD("%*s(Translate (left, top) %d, %d)", level * 2, "",
+                mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
     }
     if (mStaticMatrix) {
-        ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
+        ALOGD("%*s(ConcatMatrix (static) %p: " SK_MATRIX_STRING ")",
                 level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
     }
     if (mAnimationMatrix) {
-        ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
+        ALOGD("%*s(ConcatMatrix (animation) %p: " SK_MATRIX_STRING ")",
                 level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
     }
     if (hasTransformMatrix()) {
         if (isTransformTranslateOnly()) {
-            ALOGD("%*sTranslate %.2f, %.2f, %.2f",
+            ALOGD("%*s(Translate %.2f, %.2f, %.2f)",
                     level * 2, "", getTranslationX(), getTranslationY(), getZ());
         } else {
-            ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
+            ALOGD("%*s(ConcatMatrix %p: " SK_MATRIX_STRING ")",
                     level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
         }
     }
@@ -132,7 +133,7 @@
 
         if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
             // simply scale rendering content's alpha
-            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
+            ALOGD("%*s(ScaleAlpha %.2f)", level * 2, "", mPrimitiveFields.mAlpha);
         } else {
             // savelayeralpha to create an offscreen buffer to apply alpha
             Rect layerBounds(0, 0, getWidth(), getHeight());
@@ -140,21 +141,37 @@
                 getClippingRectForFlags(clipFlags, &layerBounds);
                 clipFlags = 0; // all clipping done by savelayer
             }
-            ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
+            ALOGD("%*s(SaveLayerAlpha %d, %d, %d, %d, %d, 0x%x)", level * 2, "",
                     (int)layerBounds.left, (int)layerBounds.top,
                     (int)layerBounds.right, (int)layerBounds.bottom,
                     (int)(mPrimitiveFields.mAlpha * 255),
                     SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer);
         }
-
-
     }
+
     if (clipFlags) {
         Rect clipRect;
         getClippingRectForFlags(clipFlags, &clipRect);
-        ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
+        ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "",
                 (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
     }
+
+    if (getRevealClip().willClip()) {
+        Rect bounds;
+        getRevealClip().getBounds(&bounds);
+        ALOGD("%*s(Clip to reveal clip with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+                RECT_ARGS(bounds));
+    }
+
+    auto& outline = mPrimitiveFields.mOutline;
+    if (outline.getShouldClip()) {
+        if (outline.isEmpty()) {
+            ALOGD("%*s(Clip to empty outline)", level * 2, "");
+        } else if (outline.willClip()) {
+            ALOGD("%*s(Clip to outline with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+                    RECT_ARGS(outline.getBounds()));
+        }
+    }
 }
 
 void RenderProperties::updateMatrix() {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index bd4442d..1b459c1 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#include "Canvas.h"
 #include "CanvasProperty.h"
 #include "Layer.h"
 #include "RenderNode.h"
+#include "hwui/Canvas.h"
 
 #include <SkCanvas.h>
 #include <SkClipStack.h>
@@ -147,13 +147,6 @@
             float dstLeft, float dstTop, float dstRight, float dstBottom,
             const SkPaint* paint) override;
 
-    virtual void drawText(const uint16_t* text, const float* positions, int count,
-            const SkPaint& paint, float x, float y,
-            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
-            float totalAdvance) override;
-    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-            float hOffset, float vOffset, const SkPaint& paint) override;
-
     virtual bool drawTextAbsolutePos() const  override { return true; }
     virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
 
@@ -169,6 +162,14 @@
     virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
     virtual void callDrawGLFunction(Functor* functor) override;
 
+protected:
+    virtual void drawGlyphs(const uint16_t* text, const float* positions, int count,
+            const SkPaint& paint, float x, float y,
+            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+            float totalAdvance) override;
+    virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) override;
+
 private:
     struct SaveRec {
         int              saveCount;
@@ -746,33 +747,23 @@
 }
 
 void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
-    const SkBitmap& bitmap = vectorDrawable->getBitmapUpdateIfDirty();
-    SkRect bounds = vectorDrawable->getBounds();
-    drawBitmap(bitmap, 0, 0, bitmap.width(), bitmap.height(),
-            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
-            vectorDrawable->getPaint());
+    vectorDrawable->drawStaging(this);
 }
 
 // ----------------------------------------------------------------------------
 // Canvas draw operations: Text
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count,
+void SkiaCanvas::drawGlyphs(const uint16_t* text, const float* positions, int count,
         const SkPaint& paint, float x, float y,
         float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
         float totalAdvance) {
-    // Set align to left for drawing, as we don't want individual
-    // glyphs centered or right-aligned; the offset above takes
-    // care of all alignment.
-    SkPaint paintCopy(paint);
-    paintCopy.setTextAlign(SkPaint::kLeft_Align);
-
     static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
-    mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
+    mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paint);
     drawTextDecorations(x, y, totalAdvance, paint);
 }
 
-void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+void SkiaCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
         float hOffset, float vOffset, const SkPaint& paint) {
     mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint);
 }
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 6530d4ed8..9df32b28 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -290,7 +290,7 @@
     }
 
     static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
-    mCanvas->drawText(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
+    mCanvas->drawGlyphs(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
                       x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
 }
 
@@ -318,15 +318,20 @@
         posArray = pointStorage.get();
     }
 
-    // compute conservative bounds
-    // NOTE: We could call the faster paint.getFontBounds for a less accurate,
-    //       but even more conservative bounds if this  is too slow.
+    // Compute conservative bounds.  If the content has already been processed
+    // by Minikin then it had already computed these bounds.  Unfortunately,
+    // there is no way to capture those bounds as part of the Skia drawPosText
+    // API so we need to do that computation again here.
     SkRect bounds;
-    glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
-    bounds.offset(x, y);
+    for (int i = 0; i < glyphs.count; i++) {
+        SkRect glyphBounds;
+        glyphs.paint.measureText(&glyphs.glyphIDs[i], sizeof(uint16_t), &glyphBounds);
+        glyphBounds.offset(pos[i].fX, pos[i].fY);
+        bounds.join(glyphBounds);
+    }
 
     static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
-    mCanvas->drawText(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
+    mCanvas->drawGlyphs(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
                       bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
 }
 
@@ -344,7 +349,7 @@
         const SkMatrix* matrix, const SkPaint& origPaint) {
     // convert to glyphIDs if necessary
     GlyphIDConverter glyphs(text, byteLength, origPaint);
-    mCanvas->drawTextOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint);
+    mCanvas->drawGlyphsOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint);
 }
 
 void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index e342d19..973c55f 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -20,7 +20,7 @@
 #include <cutils/compiler.h>
 #include <SkCanvas.h>
 
-#include "Canvas.h"
+#include "hwui/Canvas.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 27fea1f..d784280 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -16,7 +16,7 @@
 
 #include "Snapshot.h"
 
-#include "Canvas.h"
+#include "hwui/Canvas.h"
 
 namespace android {
 namespace uirenderer {
@@ -146,6 +146,9 @@
 }
 
 void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
+#if HWUI_NEW_OPS
+    LOG_ALWAYS_FATAL("not supported - not needed by new ops");
+#else
     // build (reverse ordered) list of the stack of snapshots, terminated with a NULL
     Vector<const Snapshot*> snapshotList;
     snapshotList.push(nullptr);
@@ -171,6 +174,7 @@
             outTransform->multiply(*(current->transform));
         }
     }
+#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -223,15 +227,19 @@
 }
 
 void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
+#if HWUI_NEW_OPS
+    // TODO: remove allocator param for HWUI_NEW_OPS
+    projectionPathMask = path;
+#else
     if (path) {
         ProjectionPathMask* mask = new (allocator) ProjectionPathMask;
         mask->projectionMask = path;
         buildScreenSpaceTransform(&(mask->projectionMaskTransform));
-
         projectionPathMask = mask;
     } else {
         projectionPathMask = nullptr;
     }
+#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 0ac2f14..3a01d04 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -44,7 +44,7 @@
  */
 class RoundRectClipState {
 public:
-    /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
+    static void* operator new(size_t size) = delete;
     static void* operator new(size_t size, LinearAllocator& allocator) {
         return allocator.alloc<RoundRectClipState>(size);
     }
@@ -63,9 +63,10 @@
     float radius;
 };
 
+// TODO: remove for HWUI_NEW_OPS
 class ProjectionPathMask {
 public:
-    /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
+    static void* operator new(size_t size) = delete;
     static void* operator new(size_t size, LinearAllocator& allocator) {
         return allocator.alloc<ProjectionPathMask>(size);
     }
@@ -219,6 +220,7 @@
      * Fills outTransform with the current, total transform to screen space,
      * across layer boundaries.
      */
+    // TODO: remove for HWUI_NEW_OPS
     void buildScreenSpaceTransform(Matrix4* outTransform) const;
 
     /**
@@ -294,9 +296,13 @@
     const RoundRectClipState* roundRectClipState;
 
     /**
-     * Current projection masking path - used exclusively to mask tessellated circles.
+     * Current projection masking path - used exclusively to mask projected, tessellated circles.
      */
+#if HWUI_NEW_OPS
+    const SkPath* projectionPathMask;
+#else
     const ProjectionPathMask* projectionPathMask;
+#endif
 
     void dump() const;
 
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index accd303..a43e544 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -32,6 +32,7 @@
 class DamageAccumulator;
 class LayerUpdateQueue;
 class OpenGLRenderer;
+class RenderNode;
 class RenderState;
 
 class ErrorHandler {
@@ -41,6 +42,17 @@
     ~ErrorHandler() {}
 };
 
+class TreeObserver {
+public:
+    // Called when a RenderNode's parent count hits 0.
+    // Due to the unordered nature of tree pushes, once prepareTree
+    // is finished it is possible that the node was "resurrected" and has
+    // a non-zero parent count.
+    virtual void onMaybeRemovedFromTree(RenderNode* node) {}
+protected:
+    ~TreeObserver() {}
+};
+
 // This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
 class TreeInfo {
     PREVENT_COPY_AND_ASSIGN(TreeInfo);
@@ -86,6 +98,10 @@
 #endif
     ErrorHandler* errorHandler = nullptr;
 
+    // Optional, may be nullptr. Used to allow things to observe interesting
+    // tree state changes
+    TreeObserver* observer = nullptr;
+
     // Frame number for use with synchronized surfaceview position updating
     int64_t frameNumber = -1;
     int32_t windowInsetLeft = 0;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 2e3856f..adfe45c 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -17,6 +17,7 @@
 #include "VectorDrawable.h"
 
 #include "PathParser.h"
+#include "SkColorFilter.h"
 #include "SkImageInfo.h"
 #include "SkShader.h"
 #include <utils/Log.h>
@@ -32,41 +33,36 @@
 
 const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
 
-void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY) {
+void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY,
+        bool useStagingData) {
     float matrixScale = getMatrixScale(groupStackedMatrix);
     if (matrixScale == 0) {
         // When either x or y is scaled to 0, we don't need to draw anything.
         return;
     }
 
-    const SkPath updatedPath = getUpdatedPath();
     SkMatrix pathMatrix(groupStackedMatrix);
     pathMatrix.postScale(scaleX, scaleY);
 
     //TODO: try apply the path matrix to the canvas instead of creating a new path.
     SkPath renderPath;
     renderPath.reset();
-    renderPath.addPath(updatedPath, pathMatrix);
+
+    if (useStagingData) {
+        SkPath tmpPath;
+        getStagingPath(&tmpPath);
+        renderPath.addPath(tmpPath, pathMatrix);
+    } else {
+        renderPath.addPath(getUpdatedPath(), pathMatrix);
+    }
 
     float minScale = fmin(scaleX, scaleY);
     float strokeScale = minScale * matrixScale;
-    drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
-}
-
-void Path::setPathData(const Data& data) {
-    if (mData == data) {
-        return;
-    }
-    // Updates the path data. Note that we don't generate a new Skia path right away
-    // because there are cases where the animation is changing the path data, but the view
-    // that hosts the VD has gone off screen, in which case we won't even draw. So we
-    // postpone the Skia path generation to the draw time.
-    mData = data;
-    mSkPathDirty = true;
+    drawPath(outCanvas, renderPath, strokeScale, pathMatrix, useStagingData);
 }
 
 void Path::dump() {
-    ALOGD("Path: %s has %zu points", mName.c_str(), mData.points.size());
+    ALOGD("Path: %s has %zu points", mName.c_str(), mProperties.getData().points.size());
 }
 
 float Path::getMatrixScale(const SkMatrix& groupStackedMatrix) {
@@ -95,203 +91,215 @@
     }
     return matrixScale;
 }
+
+// Called from UI thread during the initial setup/theme change.
 Path::Path(const char* pathStr, size_t strLength) {
     PathParser::ParseResult result;
-    PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
-    if (!result.failureOccurred) {
-        VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-    }
-}
-
-Path::Path(const Data& data) {
-    mData = data;
-    // Now we need to construct a path
-    VectorDrawableUtils::verbsToPath(&mSkPath, data);
+    Data data;
+    PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+    mStagingProperties.setData(data);
 }
 
 Path::Path(const Path& path) : Node(path) {
-    mData = path.mData;
-    VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-}
-
-bool Path::canMorph(const Data& morphTo) {
-    return VectorDrawableUtils::canMorph(mData, morphTo);
-}
-
-bool Path::canMorph(const Path& path) {
-    return canMorph(path.mData);
+    mStagingProperties.syncProperties(path.mStagingProperties);
 }
 
 const SkPath& Path::getUpdatedPath() {
     if (mSkPathDirty) {
         mSkPath.reset();
-        VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+        VectorDrawableUtils::verbsToPath(&mSkPath, mProperties.getData());
         mSkPathDirty = false;
     }
     return mSkPath;
 }
 
-void Path::setPath(const char* pathStr, size_t strLength) {
-    PathParser::ParseResult result;
-    mSkPathDirty = true;
-    PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+void Path::getStagingPath(SkPath* outPath) {
+    outPath->reset();
+    VectorDrawableUtils::verbsToPath(outPath, mStagingProperties.getData());
+}
+
+void Path::syncProperties() {
+    if (mStagingPropertiesDirty) {
+        mProperties.syncProperties(mStagingProperties);
+    } else {
+        mStagingProperties.syncProperties(mProperties);
+    }
+    mStagingPropertiesDirty = false;
 }
 
 FullPath::FullPath(const FullPath& path) : Path(path) {
-    mProperties = path.mProperties;
-    SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
-    SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
+    mStagingProperties.syncProperties(path.mStagingProperties);
+}
+
+static void applyTrim(SkPath* outPath, const SkPath& inPath, float trimPathStart, float trimPathEnd,
+        float trimPathOffset) {
+    if (trimPathStart == 0.0f && trimPathEnd == 1.0f) {
+        *outPath = inPath;
+        return;
+    }
+    outPath->reset();
+    if (trimPathStart == trimPathEnd) {
+        // Trimmed path should be empty.
+        return;
+    }
+    SkPathMeasure measure(inPath, false);
+    float len = SkScalarToFloat(measure.getLength());
+    float start = len * fmod((trimPathStart + trimPathOffset), 1.0f);
+    float end = len * fmod((trimPathEnd + trimPathOffset), 1.0f);
+
+    if (start > end) {
+        measure.getSegment(start, len, outPath, true);
+        if (end > 0) {
+            measure.getSegment(0, end, outPath, true);
+        }
+    } else {
+        measure.getSegment(start, end, outPath, true);
+    }
 }
 
 const SkPath& FullPath::getUpdatedPath() {
-    if (!mSkPathDirty && !mTrimDirty) {
+    if (!mSkPathDirty && !mProperties.mTrimDirty) {
         return mTrimmedSkPath;
     }
     Path::getUpdatedPath();
-    if (mProperties.trimPathStart != 0.0f || mProperties.trimPathEnd != 1.0f) {
-        applyTrim();
+    if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
+        mProperties.mTrimDirty = false;
+        applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
+                mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
         return mTrimmedSkPath;
     } else {
         return mSkPath;
     }
 }
 
-void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
-        SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
-        float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin) {
-    mProperties.strokeWidth = strokeWidth;
-    mProperties.strokeColor = strokeColor;
-    mProperties.strokeAlpha = strokeAlpha;
-    mProperties.fillColor = fillColor;
-    mProperties.fillAlpha = fillAlpha;
-    mProperties.strokeMiterLimit = strokeMiterLimit;
-    mProperties.strokeLineCap = strokeLineCap;
-    mProperties.strokeLineJoin = strokeLineJoin;
-
-    // If any trim property changes, mark trim dirty and update the trim path
-    setTrimPathStart(trimPathStart);
-    setTrimPathEnd(trimPathEnd);
-    setTrimPathOffset(trimPathOffset);
+void FullPath::getStagingPath(SkPath* outPath) {
+    Path::getStagingPath(outPath);
+    SkPath inPath = *outPath;
+    applyTrim(outPath, inPath, mStagingProperties.getTrimPathStart(),
+            mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
 }
 
+void FullPath::dump() {
+    Path::dump();
+    ALOGD("stroke width, color, alpha: %f, %d, %f, fill color, alpha: %d, %f",
+            mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
+            mProperties.getFillColor(), mProperties.getFillAlpha());
+}
+
+
 inline SkColor applyAlpha(SkColor color, float alpha) {
     int alphaBytes = SkColorGetA(color);
     return SkColorSetA(color, alphaBytes * alpha);
 }
 
-void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale,
-                        const SkMatrix& matrix){
+void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeScale,
+                        const SkMatrix& matrix, bool useStagingData){
+    const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
+
     // Draw path's fill, if fill color or gradient is valid
     bool needsFill = false;
-    if (mFillGradient != nullptr) {
-        mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.fillAlpha));
-        SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
-        mPaint.setShader(newShader);
+    SkPaint paint;
+    if (properties.getFillGradient() != nullptr) {
+        paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
+        SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix);
+        paint.setShader(newShader);
         needsFill = true;
-    } else if (mProperties.fillColor != SK_ColorTRANSPARENT) {
-        mPaint.setColor(applyAlpha(mProperties.fillColor, mProperties.fillAlpha));
+    } else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
+        paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
         needsFill = true;
     }
 
     if (needsFill) {
-        mPaint.setStyle(SkPaint::Style::kFill_Style);
-        mPaint.setAntiAlias(true);
-        outCanvas->drawPath(renderPath, mPaint);
+        paint.setStyle(SkPaint::Style::kFill_Style);
+        paint.setAntiAlias(true);
+        SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
+        renderPath.setFillType(ft);
+        outCanvas->drawPath(renderPath, paint);
     }
 
-    // Draw path's stroke, if stroke color or gradient is valid
+    // Draw path's stroke, if stroke color or Gradient is valid
     bool needsStroke = false;
-    if (mStrokeGradient != nullptr) {
-        mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.strokeAlpha));
-        SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
-        mPaint.setShader(newShader);
+    if (properties.getStrokeGradient() != nullptr) {
+        paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
+        SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix);
+        paint.setShader(newShader);
         needsStroke = true;
-    } else if (mProperties.strokeColor != SK_ColorTRANSPARENT) {
-        mPaint.setColor(applyAlpha(mProperties.strokeColor, mProperties.strokeAlpha));
+    } else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
+        paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
         needsStroke = true;
     }
     if (needsStroke) {
-        mPaint.setStyle(SkPaint::Style::kStroke_Style);
-        mPaint.setAntiAlias(true);
-        mPaint.setStrokeJoin(SkPaint::Join(mProperties.strokeLineJoin));
-        mPaint.setStrokeCap(SkPaint::Cap(mProperties.strokeLineCap));
-        mPaint.setStrokeMiter(mProperties.strokeMiterLimit);
-        mPaint.setStrokeWidth(mProperties.strokeWidth * strokeScale);
-        outCanvas->drawPath(renderPath, mPaint);
+        paint.setStyle(SkPaint::Style::kStroke_Style);
+        paint.setAntiAlias(true);
+        paint.setStrokeJoin(SkPaint::Join(properties.getStrokeLineJoin()));
+        paint.setStrokeCap(SkPaint::Cap(properties.getStrokeLineCap()));
+        paint.setStrokeMiter(properties.getStrokeMiterLimit());
+        paint.setStrokeWidth(properties.getStrokeWidth() * strokeScale);
+        outCanvas->drawPath(renderPath, paint);
     }
 }
 
-/**
- * Applies trimming to the specified path.
- */
-void FullPath::applyTrim() {
-    if (mProperties.trimPathStart == 0.0f && mProperties.trimPathEnd == 1.0f) {
-        // No trimming necessary.
-        return;
-    }
-    SkPathMeasure measure(mSkPath, false);
-    float len = SkScalarToFloat(measure.getLength());
-    float start = len * fmod((mProperties.trimPathStart + mProperties.trimPathOffset), 1.0f);
-    float end = len * fmod((mProperties.trimPathEnd + mProperties.trimPathOffset), 1.0f);
+void FullPath::syncProperties() {
+    Path::syncProperties();
 
-    mTrimmedSkPath.reset();
-    if (start > end) {
-        measure.getSegment(start, len, &mTrimmedSkPath, true);
-        measure.getSegment(0, end, &mTrimmedSkPath, true);
+    if (mStagingPropertiesDirty) {
+        mProperties.syncProperties(mStagingProperties);
     } else {
-        measure.getSegment(start, end, &mTrimmedSkPath, true);
+        // Update staging property with property values from animation.
+        mStagingProperties.syncProperties(mProperties);
     }
-    mTrimDirty = false;
+    mStagingPropertiesDirty = false;
 }
 
-REQUIRE_COMPATIBLE_LAYOUT(FullPath::Properties);
+REQUIRE_COMPATIBLE_LAYOUT(FullPath::FullPathProperties::PrimitiveFields);
 
 static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t");
 static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t");
 
-bool FullPath::getProperties(int8_t* outProperties, int length) {
-    int propertyDataSize = sizeof(Properties);
+bool FullPath::FullPathProperties::copyProperties(int8_t* outProperties, int length) const {
+    int propertyDataSize = sizeof(FullPathProperties::PrimitiveFields);
     if (length != propertyDataSize) {
         LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
                 propertyDataSize, length);
         return false;
     }
-    Properties* out = reinterpret_cast<Properties*>(outProperties);
-    *out = mProperties;
+
+    PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+    *out = mPrimitiveFields;
     return true;
 }
 
-void FullPath::setColorPropertyValue(int propertyId, int32_t value) {
+void FullPath::FullPathProperties::setColorPropertyValue(int propertyId, int32_t value) {
     Property currentProperty = static_cast<Property>(propertyId);
-    if (currentProperty == Property::StrokeColor) {
-        mProperties.strokeColor = value;
-    } else if (currentProperty == Property::FillColor) {
-        mProperties.fillColor = value;
+    if (currentProperty == Property::strokeColor) {
+        setStrokeColor(value);
+    } else if (currentProperty == Property::fillColor) {
+        setFillColor(value);
     } else {
-        LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property with id: %d",
-                propertyId);
+        LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property"
+                " with id: %d", propertyId);
     }
 }
 
-void FullPath::setPropertyValue(int propertyId, float value) {
+void FullPath::FullPathProperties::setPropertyValue(int propertyId, float value) {
     Property property = static_cast<Property>(propertyId);
     switch (property) {
-    case Property::StrokeWidth:
+    case Property::strokeWidth:
         setStrokeWidth(value);
         break;
-    case Property::StrokeAlpha:
+    case Property::strokeAlpha:
         setStrokeAlpha(value);
         break;
-    case Property::FillAlpha:
+    case Property::fillAlpha:
         setFillAlpha(value);
         break;
-    case Property::TrimPathStart:
+    case Property::trimPathStart:
         setTrimPathStart(value);
         break;
-    case Property::TrimPathEnd:
+    case Property::trimPathEnd:
         setTrimPathEnd(value);
         break;
-    case Property::TrimPathOffset:
+    case Property::trimPathOffset:
         setTrimPathOffset(value);
         break;
     default:
@@ -300,17 +308,17 @@
     }
 }
 
-void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
-        float strokeScale, const SkMatrix& matrix){
+void ClipPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath,
+        float strokeScale, const SkMatrix& matrix, bool useStagingData){
     outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
 }
 
 Group::Group(const Group& group) : Node(group) {
-    mProperties = group.mProperties;
+    mStagingProperties.syncProperties(group.mStagingProperties);
 }
 
 void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
-        float scaleY) {
+        float scaleY, bool useStagingData) {
     // TODO: Try apply the matrix to the canvas instead of passing it down the tree
 
     // Calculate current group's matrix by preConcat the parent's and
@@ -318,14 +326,15 @@
     // Basically the Mfinal = Mviewport * M0 * M1 * M2;
     // Mi the local matrix at level i of the group tree.
     SkMatrix stackedMatrix;
-    getLocalMatrix(&stackedMatrix);
+    const GroupProperties& prop = useStagingData ? mStagingProperties : mProperties;
+    getLocalMatrix(&stackedMatrix, prop);
     stackedMatrix.postConcat(currentMatrix);
 
     // Save the current clip information, which is local to this group.
     outCanvas->save();
     // Draw the group tree in the same order as the XML file.
     for (auto& child : mChildren) {
-        child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
+        child->draw(outCanvas, stackedMatrix, scaleX, scaleY, useStagingData);
     }
     // Restore the previous clip information.
     outCanvas->restore();
@@ -333,96 +342,106 @@
 
 void Group::dump() {
     ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
+    ALOGD("Group translateX, Y : %f, %f, scaleX, Y: %f, %f", mProperties.getTranslateX(),
+            mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
     for (size_t i = 0; i < mChildren.size(); i++) {
         mChildren[i]->dump();
     }
 }
 
-void Group::updateLocalMatrix(float rotate, float pivotX, float pivotY,
-        float scaleX, float scaleY, float translateX, float translateY) {
-    setRotation(rotate);
-    setPivotX(pivotX);
-    setPivotY(pivotY);
-    setScaleX(scaleX);
-    setScaleY(scaleY);
-    setTranslateX(translateX);
-    setTranslateY(translateY);
+void Group::syncProperties() {
+    // Copy over the dirty staging properties
+    if (mStagingPropertiesDirty) {
+        mProperties.syncProperties(mStagingProperties);
+    } else {
+        mStagingProperties.syncProperties(mProperties);
+    }
+    mStagingPropertiesDirty = false;
+    for (auto& child : mChildren) {
+        child->syncProperties();
+    }
 }
 
-void Group::getLocalMatrix(SkMatrix* outMatrix) {
+void Group::getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties) {
     outMatrix->reset();
     // TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of
     // translating to pivot for rotating and scaling, then translating back.
-    outMatrix->postTranslate(-mProperties.pivotX, -mProperties.pivotY);
-    outMatrix->postScale(mProperties.scaleX, mProperties.scaleY);
-    outMatrix->postRotate(mProperties.rotate, 0, 0);
-    outMatrix->postTranslate(mProperties.translateX + mProperties.pivotX,
-            mProperties.translateY + mProperties.pivotY);
+    outMatrix->postTranslate(-properties.getPivotX(), -properties.getPivotY());
+    outMatrix->postScale(properties.getScaleX(), properties.getScaleY());
+    outMatrix->postRotate(properties.getRotation(), 0, 0);
+    outMatrix->postTranslate(properties.getTranslateX() + properties.getPivotX(),
+            properties.getTranslateY() + properties.getPivotY());
 }
 
 void Group::addChild(Node* child) {
     mChildren.emplace_back(child);
+    if (mPropertyChangedListener != nullptr) {
+        child->setPropertyChangedListener(mPropertyChangedListener);
+    }
 }
 
-bool Group::getProperties(float* outProperties, int length) {
-    int propertyCount = static_cast<int>(Property::Count);
+bool Group::GroupProperties::copyProperties(float* outProperties, int length) const {
+    int propertyCount = static_cast<int>(Property::count);
     if (length != propertyCount) {
         LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
                 propertyCount, length);
         return false;
     }
-    Properties* out = reinterpret_cast<Properties*>(outProperties);
-    *out = mProperties;
+
+    PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+    *out = mPrimitiveFields;
     return true;
 }
 
 // TODO: Consider animating the properties as float pointers
-float Group::getPropertyValue(int propertyId) const {
+// Called on render thread
+float Group::GroupProperties::getPropertyValue(int propertyId) const {
     Property currentProperty = static_cast<Property>(propertyId);
     switch (currentProperty) {
-    case Property::Rotate:
-        return mProperties.rotate;
-    case Property::PivotX:
-        return mProperties.pivotX;
-    case Property::PivotY:
-        return mProperties.pivotY;
-    case Property::ScaleX:
-        return mProperties.scaleX;
-    case Property::ScaleY:
-        return mProperties.scaleY;
-    case Property::TranslateX:
-        return mProperties.translateX;
-    case Property::TranslateY:
-        return mProperties.translateY;
+    case Property::rotate:
+        return getRotation();
+    case Property::pivotX:
+        return getPivotX();
+    case Property::pivotY:
+        return getPivotY();
+    case Property::scaleX:
+        return getScaleX();
+    case Property::scaleY:
+        return getScaleY();
+    case Property::translateX:
+        return getTranslateX();
+    case Property::translateY:
+        return getTranslateY();
     default:
         LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
         return 0;
     }
 }
 
-void Group::setPropertyValue(int propertyId, float value) {
+// Called on render thread
+void Group::GroupProperties::setPropertyValue(int propertyId, float value) {
     Property currentProperty = static_cast<Property>(propertyId);
     switch (currentProperty) {
-    case Property::Rotate:
-        mProperties.rotate = value;
+    case Property::rotate:
+        setRotation(value);
         break;
-    case Property::PivotX:
-        mProperties.pivotX = value;
+    case Property::pivotX:
+        setPivotX(value);
         break;
-    case Property::PivotY:
-        mProperties.pivotY = value;
+    case Property::pivotY:
+        setPivotY(value);
         break;
-    case Property::ScaleX:
-        mProperties.scaleX = value;
+    case Property::scaleX:
+        setScaleX(value);
         break;
-    case Property::ScaleY:
-        mProperties.scaleY = value;
+    case Property::scaleY:
+        setScaleY(value);
         break;
-    case Property::TranslateX:
-        mProperties.translateX = value;
+    case Property::translateX:
+        setTranslateX(value);
         break;
-    case Property::TranslateY:
-        mProperties.translateY = value;
+    case Property::translateY:
+        setTranslateY(value);
         break;
     default:
         LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
@@ -430,7 +449,11 @@
 }
 
 bool Group::isValidProperty(int propertyId) {
-    return propertyId >= 0 && propertyId < static_cast<int>(Property::Count);
+    return GroupProperties::isValidProperty(propertyId);
+}
+
+bool Group::GroupProperties::isValidProperty(int propertyId) {
+    return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
 }
 
 void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
@@ -439,18 +462,18 @@
     // avoid blurry scaling, we have to draw into a bitmap with exact pixel
     // size first. This bitmap size is determined by the bounds and the
     // canvas scale.
-    outCanvas->getMatrix(&mCanvasMatrix);
-    mBounds = bounds;
+    SkMatrix canvasMatrix;
+    outCanvas->getMatrix(&canvasMatrix);
     float canvasScaleX = 1.0f;
     float canvasScaleY = 1.0f;
-    if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.getSkewY() == 0) {
+    if (canvasMatrix.getSkewX() == 0 && canvasMatrix.getSkewY() == 0) {
         // Only use the scale value when there's no skew or rotation in the canvas matrix.
         // TODO: Add a cts test for drawing VD on a canvas with negative scaling factors.
-        canvasScaleX = fabs(mCanvasMatrix.getScaleX());
-        canvasScaleY = fabs(mCanvasMatrix.getScaleY());
+        canvasScaleX = fabs(canvasMatrix.getScaleX());
+        canvasScaleY = fabs(canvasMatrix.getScaleY());
     }
-    int scaledWidth = (int) (mBounds.width() * canvasScaleX);
-    int scaledHeight = (int) (mBounds.height() * canvasScaleY);
+    int scaledWidth = (int) (bounds.width() * canvasScaleX);
+    int scaledHeight = (int) (bounds.height() * canvasScaleY);
     scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
     scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
 
@@ -458,63 +481,105 @@
         return;
     }
 
-    mPaint.setColorFilter(colorFilter);
-
+    mStagingProperties.setScaledSize(scaledWidth, scaledHeight);
     int saveCount = outCanvas->save(SaveFlags::MatrixClip);
-    outCanvas->translate(mBounds.fLeft, mBounds.fTop);
+    outCanvas->translate(bounds.fLeft, bounds.fTop);
 
     // Handle RTL mirroring.
     if (needsMirroring) {
-        outCanvas->translate(mBounds.width(), 0);
+        outCanvas->translate(bounds.width(), 0);
         outCanvas->scale(-1.0f, 1.0f);
     }
+    mStagingProperties.setColorFilter(colorFilter);
 
     // At this point, canvas has been translated to the right position.
     // And we use this bound for the destination rect for the drawBitmap, so
     // we offset to (0, 0);
-    mBounds.offsetTo(0, 0);
-    createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
-
+    SkRect tmpBounds = bounds;
+    tmpBounds.offsetTo(0, 0);
+    mStagingProperties.setBounds(tmpBounds);
     outCanvas->drawVectorDrawable(this);
-
     outCanvas->restoreToCount(saveCount);
 }
 
-SkPaint* Tree::getPaint() {
-    SkPaint* paint;
-    if (mRootAlpha == 1.0f && mPaint.getColorFilter() == NULL) {
-        paint = NULL;
-    } else {
-        mPaint.setFilterQuality(kLow_SkFilterQuality);
-        mPaint.setAlpha(mRootAlpha * 255);
-        paint = &mPaint;
+void Tree::drawStaging(Canvas* outCanvas) {
+    bool redrawNeeded = allocateBitmapIfNeeded(&mStagingCache.bitmap,
+            mStagingProperties.getScaledWidth(), mStagingProperties.getScaledHeight());
+    // draw bitmap cache
+    if (redrawNeeded || mStagingCache.dirty) {
+        updateBitmapCache(&mStagingCache.bitmap, true);
+        mStagingCache.dirty = false;
     }
-    return paint;
+
+    SkPaint tmpPaint;
+    SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
+    outCanvas->drawBitmap(mStagingCache.bitmap, 0, 0,
+            mStagingCache.bitmap.width(), mStagingCache.bitmap.height(),
+            mStagingProperties.getBounds().left(), mStagingProperties.getBounds().top(),
+            mStagingProperties.getBounds().right(), mStagingProperties.getBounds().bottom(), paint);
+}
+
+SkPaint* Tree::getPaint() {
+    return updatePaint(&mPaint, &mProperties);
+}
+
+// Update the given paint with alpha and color filter. Return nullptr if no color filter is
+// specified and root alpha is 1. Otherwise, return updated paint.
+SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
+    if (prop->getRootAlpha() == 1.0f && prop->getColorFilter() == nullptr) {
+        return nullptr;
+    } else {
+        outPaint->setColorFilter(mStagingProperties.getColorFilter());
+        outPaint->setFilterQuality(kLow_SkFilterQuality);
+        outPaint->setAlpha(prop->getRootAlpha() * 255);
+        return outPaint;
+    }
 }
 
 const SkBitmap& Tree::getBitmapUpdateIfDirty() {
-    mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
-    SkCanvas outCanvas(mCachedBitmap);
-    float scaleX = (float) mCachedBitmap.width() / mViewportWidth;
-    float scaleY = (float) mCachedBitmap.height() / mViewportHeight;
-    mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY);
-    mCacheDirty = false;
-    return mCachedBitmap;
+    bool redrawNeeded = allocateBitmapIfNeeded(&mCache.bitmap, mProperties.getScaledWidth(),
+            mProperties.getScaledHeight());
+    if (redrawNeeded || mCache.dirty) {
+        updateBitmapCache(&mCache.bitmap, false);
+        mCache.dirty = false;
+    }
+    return mCache.bitmap;
 }
 
-void Tree::createCachedBitmapIfNeeded(int width, int height) {
-    if (!canReuseBitmap(width, height)) {
+void Tree::updateBitmapCache(SkBitmap* outCache, bool useStagingData) {
+    outCache->eraseColor(SK_ColorTRANSPARENT);
+    SkCanvas outCanvas(*outCache);
+    float viewportWidth = useStagingData ?
+            mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
+    float viewportHeight = useStagingData ?
+            mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
+    float scaleX = outCache->width() / viewportWidth;
+    float scaleY = outCache->height() / viewportHeight;
+    mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY, useStagingData);
+}
+
+bool Tree::allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height) {
+    if (!canReuseBitmap(*outCache, width, height)) {
         SkImageInfo info = SkImageInfo::Make(width, height,
                 kN32_SkColorType, kPremul_SkAlphaType);
-        mCachedBitmap.setInfo(info);
+        outCache->setInfo(info);
         // TODO: Count the bitmap cache against app's java heap
-        mCachedBitmap.allocPixels(info);
-        mCacheDirty = true;
+        outCache->allocPixels(info);
+        return true;
     }
+    return false;
 }
 
-bool Tree::canReuseBitmap(int width, int height) {
-    return width == mCachedBitmap.width() && height == mCachedBitmap.height();
+bool Tree::canReuseBitmap(const SkBitmap& bitmap, int width, int height) {
+    return width == bitmap.width() && height == bitmap.height();
+}
+
+void Tree::onPropertyChanged(TreeProperties* prop) {
+    if (prop == &mStagingProperties) {
+        mStagingCache.dirty = true;
+    } else {
+        mCache.dirty = true;
+    }
 }
 
 }; // namespace VectorDrawable
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 36a8aeb..e4c7ed7 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -17,10 +17,12 @@
 #ifndef ANDROID_HWUI_VPATH_H
 #define ANDROID_HWUI_VPATH_H
 
-#include "Canvas.h"
+#include "hwui/Canvas.h"
+#include "DisplayList.h"
 
 #include <SkBitmap.h>
 #include <SkColor.h>
+#include <SkColorFilter.h>
 #include <SkCanvas.h>
 #include <SkMatrix.h>
 #include <SkPaint.h>
@@ -38,8 +40,11 @@
 namespace uirenderer {
 
 namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
+#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
 #define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
+#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+    onPropertyChanged(); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
 
 /* A VectorDrawable is composed of a tree of nodes.
  * Each node can be a group node, or a path.
@@ -52,22 +57,65 @@
  *          /     \             |
  *         Path   Path         Path
  *
+ * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
+ * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
+ * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
+ * Each cache has their own generation id to track whether they are up to date with the latest
+ * change in the tree.
+ *
+ * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
+ * all the properties, and viewport change, etc.) are only modifying the staging properties. The
+ * staging properties will then be marked dirty and will be pushed over to render thread properties
+ * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
+ * staging properties with render thread properties to reflect the latest animation value.
+ *
  */
+
+class PropertyChangedListener {
+public:
+    PropertyChangedListener(bool* dirty, bool* stagingDirty)
+            : mDirty(dirty), mStagingDirty(stagingDirty) {}
+    void onPropertyChanged() {
+            *mDirty = true;
+    }
+    void onStagingPropertyChanged() {
+            *mStagingDirty = true;
+    }
+private:
+    bool* mDirty;
+    bool* mStagingDirty;
+};
+
 class ANDROID_API Node {
 public:
+    class Properties {
+    public:
+        Properties(Node* node) : mNode(node) {}
+        inline void onPropertyChanged() {
+            mNode->onPropertyChanged(this);
+        }
+    private:
+        Node* mNode;
+    };
     Node(const Node& node) {
         mName = node.mName;
     }
     Node() {}
     virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
-            float scaleX, float scaleY) = 0;
+            float scaleX, float scaleY, bool useStagingData) = 0;
     virtual void dump() = 0;
     void setName(const char* name) {
         mName = name;
     }
+    virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
+        mPropertyChangedListener = listener;
+    }
+    virtual void onPropertyChanged(Properties* properties) = 0;
     virtual ~Node(){}
+    virtual void syncProperties() = 0;
 protected:
     std::string mName;
+    PropertyChangedListener* mPropertyChangedListener = nullptr;
 };
 
 class ANDROID_API Path : public Node {
@@ -81,148 +129,267 @@
                     && points == data.points;
         }
     };
-    Path(const Data& nodes);
+
+    class PathProperties : public Properties {
+    public:
+        PathProperties(Node* node) : Properties(node) {}
+        void syncProperties(const PathProperties& prop) {
+            mData = prop.mData;
+            onPropertyChanged();
+        }
+        void setData(const Data& data) {
+            // Updates the path data. Note that we don't generate a new Skia path right away
+            // because there are cases where the animation is changing the path data, but the view
+            // that hosts the VD has gone off screen, in which case we won't even draw. So we
+            // postpone the Skia path generation to the draw time.
+            if (data == mData) {
+                return;
+            }
+            mData = data;
+            onPropertyChanged();
+
+        }
+        const Data& getData() const {
+            return mData;
+        }
+    private:
+        Data mData;
+    };
+
     Path(const Path& path);
     Path(const char* path, size_t strLength);
     Path() {}
+
     void dump() override;
-    bool canMorph(const Data& path);
-    bool canMorph(const Path& path);
     void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
-            float scaleX, float scaleY) override;
-    void setPath(const char* path, size_t strLength);
-    void setPathData(const Data& data);
+            float scaleX, float scaleY, bool useStagingData) override;
     static float getMatrixScale(const SkMatrix& groupStackedMatrix);
+    virtual void syncProperties() override;
+    virtual void onPropertyChanged(Properties* prop) override {
+        if (prop == &mStagingProperties) {
+            mStagingPropertiesDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onStagingPropertyChanged();
+            }
+        } else if (prop == &mProperties){
+            mSkPathDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onPropertyChanged();
+            }
+        }
+    }
+    PathProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const PathProperties* stagingProperties() { return &mStagingProperties; }
+
+    // This should only be called from animations on RT
+    PathProperties* mutateProperties() { return &mProperties; }
 
 protected:
     virtual const SkPath& getUpdatedPath();
-    virtual void drawPath(SkCanvas *outCanvas, const SkPath& renderPath,
-            float strokeScale, const SkMatrix& matrix) = 0;
-    Data mData;
-    SkPath mSkPath;
+    virtual void getStagingPath(SkPath* outPath);
+    virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
+            float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
+
+    // Internal data, render thread only.
     bool mSkPathDirty = true;
+    SkPath mSkPath;
+
+private:
+    PathProperties mProperties = PathProperties(this);
+    PathProperties mStagingProperties = PathProperties(this);
+    bool mStagingPropertiesDirty = true;
 };
 
 class ANDROID_API FullPath: public Path {
 public:
+    class FullPathProperties : public Properties {
+    public:
+        struct PrimitiveFields {
+            float strokeWidth = 0;
+            SkColor strokeColor = SK_ColorTRANSPARENT;
+            float strokeAlpha = 1;
+            SkColor fillColor = SK_ColorTRANSPARENT;
+            float fillAlpha = 1;
+            float trimPathStart = 0;
+            float trimPathEnd = 1;
+            float trimPathOffset = 0;
+            int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
+            int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
+            float strokeMiterLimit = 4;
+            int fillType = 0; /* non-zero or kWinding_FillType in Skia */
+        };
+        FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
+        void syncProperties(const FullPathProperties& prop) {
+            mPrimitiveFields = prop.mPrimitiveFields;
+            mTrimDirty = true;
+            fillGradient.reset(prop.fillGradient);
+            strokeGradient.reset(prop.strokeGradient);
+            onPropertyChanged();
+        }
+        void setFillGradient(SkShader* gradient) {
+            if(fillGradient != gradient){
+                fillGradient.reset(gradient);
+                onPropertyChanged();
+            }
+        }
+        void setStrokeGradient(SkShader* gradient) {
+            if(strokeGradient != gradient){
+                strokeGradient.reset(gradient);
+                onPropertyChanged();
+            }
+        }
+        SkShader* getFillGradient() const {
+            return fillGradient;
+        }
+        SkShader* getStrokeGradient() const {
+            return strokeGradient;
+        }
+        float getStrokeWidth() const{
+            return mPrimitiveFields.strokeWidth;
+        }
+        void setStrokeWidth(float strokeWidth) {
+            VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+        }
+        SkColor getStrokeColor() const{
+            return mPrimitiveFields.strokeColor;
+        }
+        void setStrokeColor(SkColor strokeColor) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+        }
+        float getStrokeAlpha() const{
+            return mPrimitiveFields.strokeAlpha;
+        }
+        void setStrokeAlpha(float strokeAlpha) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+        }
+        SkColor getFillColor() const {
+            return mPrimitiveFields.fillColor;
+        }
+        void setFillColor(SkColor fillColor) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+        }
+        float getFillAlpha() const{
+            return mPrimitiveFields.fillAlpha;
+        }
+        void setFillAlpha(float fillAlpha) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+        }
+        float getTrimPathStart() const{
+            return mPrimitiveFields.trimPathStart;
+        }
+        void setTrimPathStart(float trimPathStart) {
+            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+        }
+        float getTrimPathEnd() const{
+            return mPrimitiveFields.trimPathEnd;
+        }
+        void setTrimPathEnd(float trimPathEnd) {
+            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+        }
+        float getTrimPathOffset() const{
+            return mPrimitiveFields.trimPathOffset;
+        }
+        void setTrimPathOffset(float trimPathOffset) {
+            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+        }
 
-struct Properties {
-    float strokeWidth = 0;
-    SkColor strokeColor = SK_ColorTRANSPARENT;
-    float strokeAlpha = 1;
-    SkColor fillColor = SK_ColorTRANSPARENT;
-    float fillAlpha = 1;
-    float trimPathStart = 0;
-    float trimPathEnd = 1;
-    float trimPathOffset = 0;
-    int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
-    int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
-    float strokeMiterLimit = 4;
-};
+        float getStrokeMiterLimit() const {
+            return mPrimitiveFields.strokeMiterLimit;
+        }
+        float getStrokeLineCap() const {
+            return mPrimitiveFields.strokeLineCap;
+        }
+        float getStrokeLineJoin() const {
+            return mPrimitiveFields.strokeLineJoin;
+        }
+        float getFillType() const {
+            return mPrimitiveFields.fillType;
+        }
+        bool copyProperties(int8_t* outProperties, int length) const;
+        void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
+                SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
+                float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
+                int fillType) {
+            mPrimitiveFields.strokeWidth = strokeWidth;
+            mPrimitiveFields.strokeColor = strokeColor;
+            mPrimitiveFields.strokeAlpha = strokeAlpha;
+            mPrimitiveFields.fillColor = fillColor;
+            mPrimitiveFields.fillAlpha = fillAlpha;
+            mPrimitiveFields.trimPathStart = trimPathStart;
+            mPrimitiveFields.trimPathEnd = trimPathEnd;
+            mPrimitiveFields.trimPathOffset = trimPathOffset;
+            mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
+            mPrimitiveFields.strokeLineCap = strokeLineCap;
+            mPrimitiveFields.strokeLineJoin = strokeLineJoin;
+            mPrimitiveFields.fillType = fillType;
+            mTrimDirty = true;
+            onPropertyChanged();
+        }
+        // Set property values during animation
+        void setColorPropertyValue(int propertyId, int32_t value);
+        void setPropertyValue(int propertyId, float value);
+        bool mTrimDirty;
+    private:
+        enum class Property {
+            strokeWidth = 0,
+            strokeColor,
+            strokeAlpha,
+            fillColor,
+            fillAlpha,
+            trimPathStart,
+            trimPathEnd,
+            trimPathOffset,
+            strokeLineCap,
+            strokeLineJoin,
+            strokeMiterLimit,
+            fillType,
+            count,
+        };
+        PrimitiveFields mPrimitiveFields;
+        SkAutoTUnref<SkShader> fillGradient;
+        SkAutoTUnref<SkShader> strokeGradient;
+    };
 
+    // Called from UI thread
     FullPath(const FullPath& path); // for cloning
     FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
     FullPath() : Path() {}
-    FullPath(const Data& nodes) : Path(nodes) {}
+    void dump() override;
+    FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const FullPathProperties* stagingProperties() { return &mStagingProperties; }
 
-    ~FullPath() {
-        SkSafeUnref(mFillGradient);
-        SkSafeUnref(mStrokeGradient);
-    }
+    // This should only be called from animations on RT
+    FullPathProperties* mutateProperties() { return &mProperties; }
 
-    void updateProperties(float strokeWidth, SkColor strokeColor,
-            float strokeAlpha, SkColor fillColor, float fillAlpha,
-            float trimPathStart, float trimPathEnd, float trimPathOffset,
-            float strokeMiterLimit, int strokeLineCap, int strokeLineJoin);
-    // TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
-    float getStrokeWidth() {
-        return mProperties.strokeWidth;
+    virtual void syncProperties() override;
+    virtual void onPropertyChanged(Properties* properties) override {
+        Path::onPropertyChanged(properties);
+        if (properties == &mStagingProperties) {
+            mStagingPropertiesDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onStagingPropertyChanged();
+            }
+        } else if (properties == &mProperties) {
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onPropertyChanged();
+            }
+        }
     }
-    void setStrokeWidth(float strokeWidth) {
-        mProperties.strokeWidth = strokeWidth;
-    }
-    SkColor getStrokeColor() {
-        return mProperties.strokeColor;
-    }
-    void setStrokeColor(SkColor strokeColor) {
-        mProperties.strokeColor = strokeColor;
-    }
-    float getStrokeAlpha() {
-        return mProperties.strokeAlpha;
-    }
-    void setStrokeAlpha(float strokeAlpha) {
-        mProperties.strokeAlpha = strokeAlpha;
-    }
-    SkColor getFillColor() {
-        return mProperties.fillColor;
-    }
-    void setFillColor(SkColor fillColor) {
-        mProperties.fillColor = fillColor;
-    }
-    float getFillAlpha() {
-        return mProperties.fillAlpha;
-    }
-    void setFillAlpha(float fillAlpha) {
-        mProperties.fillAlpha = fillAlpha;
-    }
-    float getTrimPathStart() {
-        return mProperties.trimPathStart;
-    }
-    void setTrimPathStart(float trimPathStart) {
-        VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty);
-    }
-    float getTrimPathEnd() {
-        return mProperties.trimPathEnd;
-    }
-    void setTrimPathEnd(float trimPathEnd) {
-        VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty);
-    }
-    float getTrimPathOffset() {
-        return mProperties.trimPathOffset;
-    }
-    void setTrimPathOffset(float trimPathOffset) {
-        VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty);
-    }
-    bool getProperties(int8_t* outProperties, int length);
-    void setColorPropertyValue(int propertyId, int32_t value);
-    void setPropertyValue(int propertyId, float value);
-
-    void setFillGradient(SkShader* fillGradient) {
-        SkRefCnt_SafeAssign(mFillGradient, fillGradient);
-    };
-    void setStrokeGradient(SkShader* strokeGradient) {
-        SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
-    };
-
 
 protected:
     const SkPath& getUpdatedPath() override;
-    void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
-            float strokeScale, const SkMatrix& matrix) override;
-
+    void getStagingPath(SkPath* outPath) override;
+    void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
+            float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
 private:
-    enum class Property {
-        StrokeWidth = 0,
-        StrokeColor,
-        StrokeAlpha,
-        FillColor,
-        FillAlpha,
-        TrimPathStart,
-        TrimPathEnd,
-        TrimPathOffset,
-        StrokeLineCap,
-        StrokeLineJoin,
-        StrokeMiterLimit,
-        Count,
-    };
-    // Applies trimming to the specified path.
-    void applyTrim();
-    Properties mProperties;
-    bool mTrimDirty = true;
+
+    FullPathProperties mProperties = FullPathProperties(this);
+    FullPathProperties mStagingProperties = FullPathProperties(this);
+    bool mStagingPropertiesDirty = true;
+
+    // Intermediate data for drawing, render thread only
     SkPath mTrimmedSkPath;
-    SkPaint mPaint;
-    SkShader* mStrokeGradient = nullptr;
-    SkShader* mFillGradient = nullptr;
+
 };
 
 class ANDROID_API ClipPath: public Path {
@@ -230,143 +397,316 @@
     ClipPath(const ClipPath& path) : Path(path) {}
     ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
     ClipPath() : Path() {}
-    ClipPath(const Data& nodes) : Path(nodes) {}
 
 protected:
-    void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
-            float strokeScale, const SkMatrix& matrix) override;
+    void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
+            float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
 };
 
 class ANDROID_API Group: public Node {
 public:
-    struct Properties {
-        float rotate = 0;
-        float pivotX = 0;
-        float pivotY = 0;
-        float scaleX = 1;
-        float scaleY = 1;
-        float translateX = 0;
-        float translateY = 0;
+    class GroupProperties : public Properties {
+    public:
+        GroupProperties(Node* mNode) : Properties(mNode) {}
+        struct PrimitiveFields {
+            float rotate = 0;
+            float pivotX = 0;
+            float pivotY = 0;
+            float scaleX = 1;
+            float scaleY = 1;
+            float translateX = 0;
+            float translateY = 0;
+        } mPrimitiveFields;
+        void syncProperties(const GroupProperties& prop) {
+            mPrimitiveFields = prop.mPrimitiveFields;
+            onPropertyChanged();
+        }
+        float getRotation() const {
+            return mPrimitiveFields.rotate;
+        }
+        void setRotation(float rotation) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+        }
+        float getPivotX() const {
+            return mPrimitiveFields.pivotX;
+        }
+        void setPivotX(float pivotX) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+        }
+        float getPivotY() const {
+            return mPrimitiveFields.pivotY;
+        }
+        void setPivotY(float pivotY) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+        }
+        float getScaleX() const {
+            return mPrimitiveFields.scaleX;
+        }
+        void setScaleX(float scaleX) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+        }
+        float getScaleY() const {
+            return mPrimitiveFields.scaleY;
+        }
+        void setScaleY(float scaleY) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+        }
+        float getTranslateX() const {
+            return mPrimitiveFields.translateX;
+        }
+        void setTranslateX(float translateX) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+        }
+        float getTranslateY() const {
+            return mPrimitiveFields.translateY;
+        }
+        void setTranslateY(float translateY) {
+            VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+        }
+        void updateProperties(float rotate, float pivotX, float pivotY,
+                float scaleX, float scaleY, float translateX, float translateY) {
+            mPrimitiveFields.rotate = rotate;
+            mPrimitiveFields.pivotX = pivotX;
+            mPrimitiveFields.pivotY = pivotY;
+            mPrimitiveFields.scaleX = scaleX;
+            mPrimitiveFields.scaleY = scaleY;
+            mPrimitiveFields.translateX = translateX;
+            mPrimitiveFields.translateY = translateY;
+            onPropertyChanged();
+        }
+        void setPropertyValue(int propertyId, float value);
+        float getPropertyValue(int propertyId) const;
+        bool copyProperties(float* outProperties, int length) const;
+        static bool isValidProperty(int propertyId);
+    private:
+        enum class Property {
+            rotate = 0,
+            pivotX,
+            pivotY,
+            scaleX,
+            scaleY,
+            translateX,
+            translateY,
+            // Count of the properties, must be at the end.
+            count,
+        };
     };
+
     Group(const Group& group);
     Group() {}
-    float getRotation() {
-        return mProperties.rotate;
-    }
-    void setRotation(float rotation) {
-        mProperties.rotate = rotation;
-    }
-    float getPivotX() {
-        return mProperties.pivotX;
-    }
-    void setPivotX(float pivotX) {
-        mProperties.pivotX = pivotX;
-    }
-    float getPivotY() {
-        return mProperties.pivotY;
-    }
-    void setPivotY(float pivotY) {
-        mProperties.pivotY = pivotY;
-    }
-    float getScaleX() {
-        return mProperties.scaleX;
-    }
-    void setScaleX(float scaleX) {
-        mProperties.scaleX = scaleX;
-    }
-    float getScaleY() {
-        return mProperties.scaleY;
-    }
-    void setScaleY(float scaleY) {
-        mProperties.scaleY = scaleY;
-    }
-    float getTranslateX() {
-        return mProperties.translateX;
-    }
-    void setTranslateX(float translateX) {
-        mProperties.translateX = translateX;
-    }
-    float getTranslateY() {
-        return mProperties.translateY;
-    }
-    void setTranslateY(float translateY) {
-        mProperties.translateY = translateY;
-    }
-    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
-            float scaleX, float scaleY) override;
-    void updateLocalMatrix(float rotate, float pivotX, float pivotY,
-            float scaleX, float scaleY, float translateX, float translateY);
-    void getLocalMatrix(SkMatrix* outMatrix);
     void addChild(Node* child);
+    virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
+        Node::setPropertyChangedListener(listener);
+        for (auto& child : mChildren) {
+             child->setPropertyChangedListener(listener);
+        }
+    }
+    virtual void syncProperties() override;
+    GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const GroupProperties* stagingProperties() { return &mStagingProperties; }
+
+    // This should only be called from animations on RT
+    GroupProperties* mutateProperties() { return &mProperties; }
+
+    // Methods below could be called from either UI thread or Render Thread.
+    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
+            float scaleX, float scaleY, bool useStagingData) override;
+    void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
     void dump() override;
-    bool getProperties(float* outProperties, int length);
-    float getPropertyValue(int propertyId) const;
-    void setPropertyValue(int propertyId, float value);
     static bool isValidProperty(int propertyId);
 
+    virtual void onPropertyChanged(Properties* properties) override {
+        if (properties == &mStagingProperties) {
+            mStagingPropertiesDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onStagingPropertyChanged();
+            }
+        } else {
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onPropertyChanged();
+            }
+        }
+    }
+
 private:
-    enum class Property {
-        Rotate = 0,
-        PivotX,
-        PivotY,
-        ScaleX,
-        ScaleY,
-        TranslateX,
-        TranslateY,
-        // Count of the properties, must be at the end.
-        Count,
-    };
+    GroupProperties mProperties = GroupProperties(this);
+    GroupProperties mStagingProperties = GroupProperties(this);
+    bool mStagingPropertiesDirty = true;
     std::vector< std::unique_ptr<Node> > mChildren;
-    Properties mProperties;
 };
 
 class ANDROID_API Tree : public VirtualLightRefBase {
 public:
-    Tree(Group* rootNode) : mRootNode(rootNode) {}
+    Tree(Group* rootNode) : mRootNode(rootNode) {
+        mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
+    }
     void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
             const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+    void drawStaging(Canvas* canvas);
 
     const SkBitmap& getBitmapUpdateIfDirty();
-    void createCachedBitmapIfNeeded(int width, int height);
-    bool canReuseBitmap(int width, int height);
     void setAllowCaching(bool allowCaching) {
         mAllowCaching = allowCaching;
     }
-    bool setRootAlpha(float rootAlpha) {
-        return VD_SET_PROP(mRootAlpha, rootAlpha);
+    SkPaint* getPaint();
+    void syncProperties() {
+        if (mStagingProperties.mNonAnimatablePropertiesDirty) {
+            mProperties.syncNonAnimatableProperties(mStagingProperties);
+            mStagingProperties.mNonAnimatablePropertiesDirty = false;
+        }
+
+        if (mStagingProperties.mAnimatablePropertiesDirty) {
+            mProperties.syncAnimatableProperties(mStagingProperties);
+        } else {
+            mStagingProperties.syncAnimatableProperties(mProperties);
+        }
+        mStagingProperties.mAnimatablePropertiesDirty = false;
+        mRootNode->syncProperties();
     }
 
-    float getRootAlpha() {
-        return mRootAlpha;
-    }
-    void setViewportSize(float viewportWidth, float viewportHeight) {
-        mViewportWidth = viewportWidth;
-        mViewportHeight = viewportHeight;
-    }
-    SkPaint* getPaint();
-    const SkRect& getBounds() const {
-        return mBounds;
-    }
+    class TreeProperties {
+    public:
+        TreeProperties(Tree* tree) : mTree(tree) {}
+        // Properties that can only be modified by UI thread, therefore sync should
+        // only go from UI to RT
+        struct NonAnimatableProperties {
+            float viewportWidth = 0;
+            float viewportHeight = 0;
+            SkRect bounds;
+            int scaledWidth = 0;
+            int scaledHeight = 0;
+            SkColorFilter* colorFilter = nullptr;
+            ~NonAnimatableProperties() {
+                SkSafeUnref(colorFilter);
+            }
+        } mNonAnimatableProperties;
+        bool mNonAnimatablePropertiesDirty = true;
+
+        float mRootAlpha = 1.0f;
+        bool mAnimatablePropertiesDirty = true;
+
+        void syncNonAnimatableProperties(const TreeProperties& prop) {
+            // Copy over the data that can only be changed in UI thread
+            if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
+                SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
+                        prop.mNonAnimatableProperties.colorFilter);
+            }
+            mNonAnimatableProperties = prop.mNonAnimatableProperties;
+        }
+
+        void setViewportSize(float width, float height) {
+            if (mNonAnimatableProperties.viewportWidth != width
+                    || mNonAnimatableProperties.viewportHeight != height) {
+                mNonAnimatablePropertiesDirty = true;
+                mNonAnimatableProperties.viewportWidth = width;
+                mNonAnimatableProperties.viewportHeight = height;
+                mTree->onPropertyChanged(this);
+            }
+        }
+        void setBounds(const SkRect& bounds) {
+            if (mNonAnimatableProperties.bounds != bounds) {
+                mNonAnimatableProperties.bounds = bounds;
+                mNonAnimatablePropertiesDirty = true;
+                mTree->onPropertyChanged(this);
+            }
+        }
+
+        void setScaledSize(int width, int height) {
+            if (mNonAnimatableProperties.scaledWidth != width
+                    || mNonAnimatableProperties.scaledHeight != height) {
+                mNonAnimatableProperties.scaledWidth = width;
+                mNonAnimatableProperties.scaledHeight = height;
+                mNonAnimatablePropertiesDirty = true;
+                mTree->onPropertyChanged(this);
+            }
+        }
+        void setColorFilter(SkColorFilter* filter) {
+            if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
+                mNonAnimatablePropertiesDirty = true;
+                mTree->onPropertyChanged(this);
+            }
+        }
+        SkColorFilter* getColorFilter() const{
+            return mNonAnimatableProperties.colorFilter;
+        }
+
+        float getViewportWidth() const {
+            return mNonAnimatableProperties.viewportWidth;
+        }
+        float getViewportHeight() const {
+            return mNonAnimatableProperties.viewportHeight;
+        }
+        float getScaledWidth() const {
+            return mNonAnimatableProperties.scaledWidth;
+        }
+        float getScaledHeight() const {
+            return mNonAnimatableProperties.scaledHeight;
+        }
+        void syncAnimatableProperties(const TreeProperties& prop) {
+            mRootAlpha = prop.mRootAlpha;
+        }
+        bool setRootAlpha(float rootAlpha) {
+            if (rootAlpha != mRootAlpha) {
+                mAnimatablePropertiesDirty = true;
+                mRootAlpha = rootAlpha;
+                mTree->onPropertyChanged(this);
+                return true;
+            }
+            return false;
+        }
+        float getRootAlpha() const { return mRootAlpha;}
+        const SkRect& getBounds() const {
+            return mNonAnimatableProperties.bounds;
+        }
+        Tree* mTree;
+    };
+    void onPropertyChanged(TreeProperties* prop);
+    TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const TreeProperties* stagingProperties() { return &mStagingProperties; }
+    PushStagingFunctor* getFunctor() { return &mFunctor;}
+
+    // This should only be called from animations on RT
+    TreeProperties* mutateProperties() { return &mProperties; }
 
 private:
+    class VectorDrawableFunctor : public PushStagingFunctor {
+    public:
+        VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
+        virtual void operator ()() {
+            mTree->syncProperties();
+        }
+    private:
+        Tree* mTree;
+    };
+
+    SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
+    bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
+    bool canReuseBitmap(const SkBitmap&, int width, int height);
+    void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
     // Cap the bitmap size, such that it won't hurt the performance too much
     // and it won't crash due to a very large scale.
     // The drawable will look blurry above this size.
     const static int MAX_CACHED_BITMAP_SIZE;
 
-    bool mCacheDirty = true;
     bool mAllowCaching = true;
-    float mViewportWidth = 0;
-    float mViewportHeight = 0;
-    float mRootAlpha = 1.0f;
-
     std::unique_ptr<Group> mRootNode;
-    SkRect mBounds;
-    SkMatrix mCanvasMatrix;
-    SkPaint mPaint;
-    SkPathMeasure mPathMeasure;
-    SkBitmap mCachedBitmap;
 
+    TreeProperties mProperties = TreeProperties(this);
+    TreeProperties mStagingProperties = TreeProperties(this);
+
+    VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
+
+    SkPaint mPaint;
+    struct Cache {
+        SkBitmap bitmap;
+        bool dirty = true;
+    };
+
+    Cache mStagingCache;
+    Cache mCache;
+
+    PropertyChangedListener mPropertyChangedListener
+            = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
 };
 
 } // namespace VectorDrawable
diff --git a/libs/hwui/debug/nullgles.cpp b/libs/hwui/debug/nullgles.cpp
index ffb0649..8689f98 100644
--- a/libs/hwui/debug/nullgles.cpp
+++ b/libs/hwui/debug/nullgles.cpp
@@ -133,6 +133,15 @@
     }
 }
 
+GLenum glCheckFramebufferStatus(GLenum target) {
+    switch (target) {
+    case GL_FRAMEBUFFER:
+        return GL_FRAMEBUFFER_COMPLETE;
+    default:
+        return 0; // error case
+    }
+}
+
 const char* getString(GLenum name) {
     switch (name) {
     case GL_VENDOR:
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 9a825fd..8e04c87 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -356,8 +356,6 @@
 }
 
 void Font::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs) {
-    ATRACE_NAME("Precache Glyphs");
-
     if (numGlyphs == 0 || glyphs == nullptr) {
         return;
     }
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
new file mode 100644
index 0000000..7bfa15a
--- /dev/null
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Canvas.h"
+
+#include "DisplayListCanvas.h"
+#include "RecordingCanvas.h"
+#include "MinikinUtils.h"
+#include "Paint.h"
+#include "Typeface.h"
+
+#include <SkDrawFilter.h>
+
+namespace android {
+
+Canvas* Canvas::create_recording_canvas(int width, int height) {
+#if HWUI_NEW_OPS
+    return new uirenderer::RecordingCanvas(width, height);
+#else
+    return new uirenderer::DisplayListCanvas(width, height);
+#endif
+}
+
+void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) {
+    uint32_t flags;
+    SkDrawFilter* drawFilter = getDrawFilter();
+    if (drawFilter) {
+        SkPaint paintCopy(paint);
+        drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
+        flags = paintCopy.getFlags();
+    } else {
+        flags = paint.getFlags();
+    }
+    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
+        // Same values used by Skia
+        const float kStdStrikeThru_Offset   = (-6.0f / 21.0f);
+        const float kStdUnderline_Offset    = (1.0f / 9.0f);
+        const float kStdUnderline_Thickness = (1.0f / 18.0f);
+
+        SkScalar left = x;
+        SkScalar right = x + length;
+        float textSize = paint.getTextSize();
+        float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
+        if (flags & SkPaint::kUnderlineText_Flag) {
+            SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
+            SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
+            drawRect(left, top, right, bottom, paint);
+        }
+        if (flags & SkPaint::kStrikeThruText_Flag) {
+            SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
+            SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
+            drawRect(left, top, right, bottom, paint);
+        }
+    }
+}
+
+static void simplifyPaint(int color, SkPaint* paint) {
+    paint->setColor(color);
+    paint->setShader(nullptr);
+    paint->setColorFilter(nullptr);
+    paint->setLooper(nullptr);
+    paint->setStrokeWidth(4 + 0.04 * paint->getTextSize());
+    paint->setStrokeJoin(SkPaint::kRound_Join);
+    paint->setLooper(nullptr);
+}
+
+class DrawTextFunctor {
+public:
+    DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
+            const SkPaint& paint, float x, float y, MinikinRect& bounds, float totalAdvance)
+        : layout(layout)
+        , canvas(canvas)
+        , glyphs(glyphs)
+        , pos(pos)
+        , paint(paint)
+        , x(x)
+        , y(y)
+        , bounds(bounds)
+        , totalAdvance(totalAdvance) {
+    }
+
+    void operator()(size_t start, size_t end) {
+        if (canvas->drawTextAbsolutePos()) {
+            for (size_t i = start; i < end; i++) {
+                glyphs[i] = layout.getGlyphId(i);
+                pos[2 * i] = x + layout.getX(i);
+                pos[2 * i + 1] = y + layout.getY(i);
+            }
+        } else {
+            for (size_t i = start; i < end; i++) {
+                glyphs[i] = layout.getGlyphId(i);
+                pos[2 * i] = layout.getX(i);
+                pos[2 * i + 1] = layout.getY(i);
+            }
+        }
+
+        size_t glyphCount = end - start;
+
+        if (CC_UNLIKELY(canvas->isHighContrastText() && paint.getAlpha() != 0)) {
+            // high contrast draw path
+            int color = paint.getColor();
+            int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color);
+            bool darken = channelSum < (128 * 3);
+
+            // outline
+            SkPaint outlinePaint(paint);
+            simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint);
+            outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style);
+            canvas->drawGlyphs(glyphs + start, pos + (2 * start), glyphCount, outlinePaint, x, y,
+                    bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance);
+
+            // inner
+            SkPaint innerPaint(paint);
+            simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
+            innerPaint.setStyle(SkPaint::kFill_Style);
+            canvas->drawGlyphs(glyphs + start, pos + (2 * start), glyphCount, innerPaint, x, y,
+                    bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance);
+        } else {
+            // standard draw path
+            canvas->drawGlyphs(glyphs + start, pos + (2 * start), glyphCount, paint, x, y,
+                    bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance);
+        }
+    }
+private:
+    const Layout& layout;
+    Canvas* canvas;
+    uint16_t* glyphs;
+    float* pos;
+    const SkPaint& paint;
+    float x;
+    float y;
+    MinikinRect& bounds;
+    float totalAdvance;
+};
+
+void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount,
+        float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface) {
+    // minikin may modify the original paint
+    Paint paint(origPaint);
+
+    Layout layout;
+    MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
+
+    size_t nGlyphs = layout.nGlyphs();
+    std::unique_ptr<uint16_t[]> glyphs(new uint16_t[nGlyphs]);
+    std::unique_ptr<float[]> pos(new float[nGlyphs * 2]);
+
+    x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
+
+    MinikinRect bounds;
+    layout.getBounds(&bounds);
+    if (!drawTextAbsolutePos()) {
+        bounds.offset(x, y);
+    }
+
+    // Set align to left for drawing, as we don't want individual
+    // glyphs centered or right-aligned; the offset above takes
+    // care of all alignment.
+    paint.setTextAlign(Paint::kLeft_Align);
+
+    DrawTextFunctor f(layout, this, glyphs.get(), pos.get(),
+            paint, x, y, bounds, layout.getAdvance());
+    MinikinUtils::forFontRun(layout, &paint, f);
+}
+
+class DrawTextOnPathFunctor {
+public:
+    DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
+            float vOffset, const Paint& paint, const SkPath& path)
+        : layout(layout)
+        , canvas(canvas)
+        , hOffset(hOffset)
+        , vOffset(vOffset)
+        , paint(paint)
+        , path(path) {
+    }
+
+    void operator()(size_t start, size_t end) {
+        uint16_t glyphs[1];
+        for (size_t i = start; i < end; i++) {
+            glyphs[0] = layout.getGlyphId(i);
+            float x = hOffset + layout.getX(i);
+            float y = vOffset + layout.getY(i);
+            canvas->drawGlyphsOnPath(glyphs, 1, path, x, y, paint);
+        }
+    }
+private:
+    const Layout& layout;
+    Canvas* canvas;
+    float hOffset;
+    float vOffset;
+    const Paint& paint;
+    const SkPath& path;
+};
+
+void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path,
+        float hOffset, float vOffset, const Paint& paint, Typeface* typeface) {
+    Paint paintCopy(paint);
+    Layout layout;
+    MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
+    hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
+
+    // Set align to left for drawing, as we don't want individual
+    // glyphs centered or right-aligned; the offset above takes
+    // care of all alignment.
+    paintCopy.setTextAlign(Paint::kLeft_Align);
+
+    DrawTextOnPathFunctor f(layout, this, hOffset, vOffset, paintCopy, path);
+    MinikinUtils::forFontRun(layout, &paintCopy, f);
+}
+
+} // namespace android
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
new file mode 100644
index 0000000..5dbda43
--- /dev/null
+++ b/libs/hwui/hwui/Canvas.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GRAPHICS_CANVAS_H
+#define ANDROID_GRAPHICS_CANVAS_H
+
+#include <cutils/compiler.h>
+#include <utils/Functor.h>
+
+#include "utils/NinePatch.h"
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkMatrix.h>
+
+namespace android {
+
+namespace uirenderer {
+    class CanvasPropertyPaint;
+    class CanvasPropertyPrimitive;
+    class DeferredLayerUpdater;
+    class DisplayList;
+    class RenderNode;
+}
+
+namespace SaveFlags {
+
+// These must match the corresponding Canvas API constants.
+enum {
+    Matrix        = 0x01,
+    Clip          = 0x02,
+    HasAlphaLayer = 0x04,
+    ClipToLayer   = 0x10,
+
+    // Helper constant
+    MatrixClip    = Matrix | Clip,
+};
+typedef uint32_t Flags;
+
+} // namespace SaveFlags
+
+namespace uirenderer {
+class SkiaCanvasProxy;
+namespace VectorDrawable {
+class Tree;
+};
+};
+typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
+
+class Paint;
+struct Typeface;
+
+class ANDROID_API Canvas {
+public:
+    virtual ~Canvas() {};
+
+    static Canvas* create_canvas(const SkBitmap& bitmap);
+
+    static Canvas* create_recording_canvas(int width, int height);
+
+    /**
+     *  Create a new Canvas object which delegates to an SkCanvas.
+     *
+     *  @param skiaCanvas Must not be NULL. All drawing calls will be
+     *      delegated to this object. This function will call ref() on the
+     *      SkCanvas, and the returned Canvas will unref() it upon
+     *      destruction.
+     *  @return new Canvas object. Will not return NULL.
+     */
+    static Canvas* create_canvas(SkCanvas* skiaCanvas);
+
+    /**
+     *  Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
+     *  It is useful for testing and clients (e.g. Picture/Movie) that expect to
+     *  draw their contents into an SkCanvas.
+     *
+     *  The SkCanvas returned is *only* valid until another Canvas call is made
+     *  that would change state (e.g. matrix or clip). Clients of asSkCanvas()
+     *  are responsible for *not* persisting this pointer.
+     *
+     *  Further, the returned SkCanvas should NOT be unref'd and is valid until
+     *  this canvas is destroyed or a new bitmap is set.
+     */
+    virtual SkCanvas* asSkCanvas() = 0;
+
+
+    virtual void setBitmap(const SkBitmap& bitmap) = 0;
+
+    virtual bool isOpaque() = 0;
+    virtual int width() = 0;
+    virtual int height() = 0;
+
+// ----------------------------------------------------------------------------
+// View System operations (not exposed in public Canvas API)
+// ----------------------------------------------------------------------------
+
+    virtual void resetRecording(int width, int height) = 0;
+    virtual uirenderer::DisplayList* finishRecording() = 0;
+    virtual void insertReorderBarrier(bool enableReorder) = 0;
+
+    virtual void setHighContrastText(bool highContrastText) = 0;
+    virtual bool isHighContrastText() = 0;
+
+    virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
+            uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
+            uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
+            uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) = 0;
+    virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
+            uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
+            uirenderer::CanvasPropertyPaint* paint) = 0;
+
+    virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
+    virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
+    virtual void callDrawGLFunction(Functor* functor) = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas state operations
+// ----------------------------------------------------------------------------
+
+    // Save (layer)
+    virtual int getSaveCount() const = 0;
+    virtual int save(SaveFlags::Flags flags) = 0;
+    virtual void restore() = 0;
+    virtual void restoreToCount(int saveCount) = 0;
+
+    virtual int saveLayer(float left, float top, float right, float bottom,
+                const SkPaint* paint, SaveFlags::Flags flags) = 0;
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, SaveFlags::Flags flags) = 0;
+
+    // Matrix
+    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
+    virtual void setMatrix(const SkMatrix& matrix) = 0;
+
+    virtual void concat(const SkMatrix& matrix) = 0;
+    virtual void rotate(float degrees) = 0;
+    virtual void scale(float sx, float sy) = 0;
+    virtual void skew(float sx, float sy) = 0;
+    virtual void translate(float dx, float dy) = 0;
+
+    // clip
+    virtual bool getClipBounds(SkRect* outRect) const = 0;
+    virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
+    virtual bool quickRejectPath(const SkPath& path) const = 0;
+
+    virtual bool clipRect(float left, float top, float right, float bottom,
+            SkRegion::Op op = SkRegion::kIntersect_Op) = 0;
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
+
+    // filters
+    virtual SkDrawFilter* getDrawFilter() = 0;
+    virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations
+// ----------------------------------------------------------------------------
+    virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
+    virtual void drawPaint(const SkPaint& paint) = 0;
+
+    // Geometry
+    virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
+    virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
+    virtual void drawLine(float startX, float startY, float stopX, float stopY,
+                const SkPaint& paint) = 0;
+    virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
+    virtual void drawRect(float left, float top, float right, float bottom,
+            const SkPaint& paint) = 0;
+    virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
+    virtual void drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint& paint) = 0;
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
+    virtual void drawOval(float left, float top, float right, float bottom,
+            const SkPaint& paint) = 0;
+    virtual void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
+    virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
+    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
+                              const float* verts, const float* tex, const int* colors,
+                              const uint16_t* indices, int indexCount, const SkPaint& paint) = 0;
+
+    // Bitmap-based
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
+            const SkPaint* paint) = 0;
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+            const SkPaint* paint) = 0;
+    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint) = 0;
+    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint) = 0;
+    virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+            float dstLeft, float dstTop, float dstRight, float dstBottom,
+            const SkPaint* paint) = 0;
+
+    /**
+     * Specifies if the positions passed to ::drawText are absolute or relative
+     * to the (x,y) value provided.
+     *
+     * If true the (x,y) values are ignored. Otherwise, those (x,y) values need
+     * to be added to each glyph's position to get its absolute position.
+     */
+    virtual bool drawTextAbsolutePos() const = 0;
+
+    /**
+     * Draws a VectorDrawable onto the canvas.
+     */
+    virtual void drawVectorDrawable(VectorDrawableRoot* tree);
+
+    /**
+     * Converts utf16 text to glyphs, calculating position and boundary,
+     * and delegating the final draw to virtual drawGlyphs method.
+     */
+    void drawText(const uint16_t* text, int start, int count, int contextCount,
+            float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface);
+
+    void drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path,
+            float hOffset, float vOffset, const Paint& paint, Typeface* typeface);
+
+protected:
+    void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
+
+    /**
+     * drawText: count is of glyphs
+     * totalAdvance: used to define width of text decorations (underlines, strikethroughs).
+     */
+    virtual void drawGlyphs(const uint16_t* glyphs, const float* positions, int count,
+            const SkPaint& paint, float x, float y,
+            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+            float totalAdvance) = 0;
+    /** drawTextOnPath: count is of glyphs */
+    virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) = 0;
+
+    friend class DrawTextFunctor;
+    friend class DrawTextOnPathFunctor;
+    friend class uirenderer::SkiaCanvasProxy;
+};
+
+}; // namespace android
+#endif // ANDROID_GRAPHICS_CANVAS_H
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
new file mode 100644
index 0000000..b9e3358
--- /dev/null
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include "MinikinSkia.h"
+
+#include <SkPaint.h>
+#include <SkTypeface.h>
+#include <cutils/log.h>
+
+namespace android {
+
+MinikinFontSkia::MinikinFontSkia(SkTypeface *typeface) :
+    mTypeface(typeface) {
+}
+
+MinikinFontSkia::~MinikinFontSkia() {
+    SkSafeUnref(mTypeface);
+}
+
+static void MinikinFontSkia_SetSkiaPaint(const MinikinFont* font, SkPaint* skPaint, const MinikinPaint& paint) {
+    skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    skPaint->setTextSize(paint.size);
+    skPaint->setTextScaleX(paint.scaleX);
+    skPaint->setTextSkewX(paint.skewX);
+    MinikinFontSkia::unpackPaintFlags(skPaint, paint.paintFlags);
+    // Apply font fakery on top of user-supplied flags.
+    MinikinFontSkia::populateSkPaint(skPaint, font, paint.fakery);
+}
+
+float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
+    const MinikinPaint &paint) const {
+    SkPaint skPaint;
+    uint16_t glyph16 = glyph_id;
+    SkScalar skWidth;
+    MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+    skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
+#ifdef VERBOSE
+    ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
+#endif
+    return skWidth;
+}
+
+void MinikinFontSkia::GetBounds(MinikinRect* bounds, uint32_t glyph_id,
+    const MinikinPaint& paint) const {
+    SkPaint skPaint;
+    uint16_t glyph16 = glyph_id;
+    SkRect skBounds;
+    MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+    skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
+    bounds->mLeft = skBounds.fLeft;
+    bounds->mTop = skBounds.fTop;
+    bounds->mRight = skBounds.fRight;
+    bounds->mBottom = skBounds.fBottom;
+}
+
+bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {
+    if (buf == NULL) {
+        const size_t tableSize = mTypeface->getTableSize(tag);
+        *size = tableSize;
+        return tableSize != 0;
+    } else {
+        const size_t actualSize = mTypeface->getTableData(tag, 0, *size, buf);
+        *size = actualSize;
+        return actualSize != 0;
+    }
+}
+
+SkTypeface *MinikinFontSkia::GetSkTypeface() const {
+    return mTypeface;
+}
+
+int32_t MinikinFontSkia::GetUniqueId() const {
+    return mTypeface->uniqueID();
+}
+
+uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
+    uint32_t flags = paint->getFlags();
+    SkPaint::Hinting hinting = paint->getHinting();
+    // select only flags that might affect text layout
+    flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
+            SkPaint::kSubpixelText_Flag | SkPaint::kDevKernText_Flag |
+            SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag |
+            SkPaint::kVerticalText_Flag);
+    flags |= (hinting << 16);
+    return flags;
+}
+
+void MinikinFontSkia::unpackPaintFlags(SkPaint* paint, uint32_t paintFlags) {
+    paint->setFlags(paintFlags & SkPaint::kAllFlags);
+    paint->setHinting(static_cast<SkPaint::Hinting>(paintFlags >> 16));
+}
+
+void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery) {
+    paint->setTypeface(reinterpret_cast<const MinikinFontSkia*>(font)->GetSkTypeface());
+    paint->setFakeBoldText(paint->isFakeBoldText() || fakery.isFakeBold());
+    if (fakery.isFakeItalic()) {
+        paint->setTextSkewX(paint->getTextSkewX() - 0.25f);
+    }
+}
+
+}
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
new file mode 100644
index 0000000..1d50168
--- /dev/null
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
+#define _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
+
+#include <cutils/compiler.h>
+#include <minikin/MinikinFont.h>
+
+class SkPaint;
+class SkTypeface;
+
+namespace android {
+
+class ANDROID_API MinikinFontSkia : public MinikinFont {
+public:
+    // Note: this takes ownership of the reference (will unref on dtor)
+    explicit MinikinFontSkia(SkTypeface *typeface);
+
+    ~MinikinFontSkia();
+
+    float GetHorizontalAdvance(uint32_t glyph_id,
+        const MinikinPaint &paint) const;
+
+    void GetBounds(MinikinRect* bounds, uint32_t glyph_id,
+        const MinikinPaint &paint) const;
+
+    // If buf is NULL, just update size
+    bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
+
+    int32_t GetUniqueId() const;
+
+    SkTypeface* GetSkTypeface() const;
+
+    static uint32_t packPaintFlags(const SkPaint* paint);
+    static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags);
+
+    // set typeface and fake bold/italic parameters
+    static void populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery);
+private:
+    SkTypeface *mTypeface;
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
new file mode 100644
index 0000000..67b775d
--- /dev/null
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "MinikinUtils.h"
+
+#include "Paint.h"
+#include "SkPathMeasure.h"
+#include "Typeface.h"
+
+#include <cutils/log.h>
+#include <string>
+
+namespace android {
+
+FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
+        const Paint* paint, Typeface* typeface) {
+    const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
+    *pFont = resolvedFace->fFontCollection;
+    FontStyle resolved = resolvedFace->fStyle;
+
+    /* Prepare minikin FontStyle */
+    FontVariant minikinVariant = (paint->getFontVariant() == VARIANT_ELEGANT) ? VARIANT_ELEGANT
+            : VARIANT_COMPACT;
+    const uint32_t langListId = paint->getMinikinLangListId();
+    FontStyle minikinStyle(langListId, minikinVariant, resolved.getWeight(), resolved.getItalic());
+
+    /* Prepare minikin Paint */
+    // Note: it would be nice to handle fractional size values (it would improve smooth zoom
+    // behavior), but historically size has been treated as an int.
+    // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set.
+    minikinPaint->size = (int)paint->getTextSize();
+    minikinPaint->scaleX = paint->getTextScaleX();
+    minikinPaint->skewX = paint->getTextSkewX();
+    minikinPaint->letterSpacing = paint->getLetterSpacing();
+    minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
+    minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
+    minikinPaint->hyphenEdit = HyphenEdit(paint->getHyphenEdit());
+    return minikinStyle;
+}
+
+void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags,
+        Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
+        size_t bufSize) {
+    FontCollection *font;
+    MinikinPaint minikinPaint;
+    FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+    layout->setFontCollection(font);
+    layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
+}
+
+float MinikinUtils::measureText(const Paint* paint, int bidiFlags, Typeface* typeface,
+        const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) {
+    FontCollection *font;
+    MinikinPaint minikinPaint;
+    FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+    return Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint,
+            font, advances);
+}
+
+bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs) {
+    const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
+    return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
+}
+
+float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) {
+    switch (paint->getTextAlign()) {
+        case Paint::kCenter_Align:
+            return layout.getAdvance() * -0.5f;
+            break;
+        case Paint::kRight_Align:
+            return -layout.getAdvance();
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+
+float MinikinUtils::hOffsetForTextAlign(Paint* paint, const Layout& layout, const SkPath& path) {
+    float align = 0;
+    switch (paint->getTextAlign()) {
+        case Paint::kCenter_Align:
+            align = -0.5f;
+            break;
+        case Paint::kRight_Align:
+            align = -1;
+            break;
+        default:
+            return 0;
+    }
+    SkPathMeasure measure(path, false);
+    return align * (layout.getAdvance() - measure.getLength());
+}
+
+}
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
new file mode 100644
index 0000000..cfaa961
--- /dev/null
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -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.
+ */
+
+/**
+ * Utilities for making Minikin work, especially from existing objects like
+ * Paint and so on.
+ **/
+
+ // TODO: does this really need to be separate from MinikinSkia?
+
+#ifndef _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
+#define _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
+
+#include <cutils/compiler.h>
+#include <minikin/Layout.h>
+#include "Paint.h"
+#include "MinikinSkia.h"
+#include "Typeface.h"
+
+namespace android {
+
+class MinikinUtils {
+public:
+    ANDROID_API static FontStyle prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
+            const Paint* paint, Typeface* typeface);
+
+    ANDROID_API static void doLayout(Layout* layout, const Paint* paint, int bidiFlags,
+            Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
+            size_t bufSize);
+
+    ANDROID_API static float measureText(const Paint* paint, int bidiFlags, Typeface* typeface,
+            const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances);
+
+    ANDROID_API static bool hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs);
+
+    ANDROID_API static float xOffsetForTextAlign(Paint* paint, const Layout& layout);
+
+    ANDROID_API static float hOffsetForTextAlign(Paint* paint, const Layout& layout, const SkPath& path);
+    // f is a functor of type void f(size_t start, size_t end);
+    template <typename F>
+    ANDROID_API static void forFontRun(const Layout& layout, Paint* paint, F& f) {
+        float saveSkewX = paint->getTextSkewX();
+        bool savefakeBold = paint->isFakeBoldText();
+        MinikinFont* curFont = NULL;
+        size_t start = 0;
+        size_t nGlyphs = layout.nGlyphs();
+        for (size_t i = 0; i < nGlyphs; i++) {
+            MinikinFont* nextFont = layout.getFont(i);
+            if (i > 0 && nextFont != curFont) {
+                MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
+                f(start, i);
+                paint->setTextSkewX(saveSkewX);
+                paint->setFakeBoldText(savefakeBold);
+                start = i;
+            }
+            curFont = nextFont;
+        }
+        if (nGlyphs > start) {
+            MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
+            f(start, nGlyphs);
+            paint->setTextSkewX(saveSkewX);
+            paint->setFakeBoldText(savefakeBold);
+        }
+    }
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
new file mode 100644
index 0000000..9599c30
--- /dev/null
+++ b/libs/hwui/hwui/Paint.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GRAPHICS_PAINT_H_
+#define ANDROID_GRAPHICS_PAINT_H_
+
+#include <cutils/compiler.h>
+
+#include <SkPaint.h>
+#include <string>
+
+#include <minikin/FontFamily.h>
+
+namespace android {
+
+class ANDROID_API Paint : public SkPaint {
+public:
+    Paint();
+    Paint(const Paint& paint);
+    Paint(const SkPaint& paint);
+    ~Paint();
+
+    Paint& operator=(const Paint& other);
+
+    friend bool operator==(const Paint& a, const Paint& b);
+    friend bool operator!=(const Paint& a, const Paint& b) {
+        return !(a == b);
+    }
+
+    void setLetterSpacing(float letterSpacing) {
+        mLetterSpacing = letterSpacing;
+    }
+
+    float getLetterSpacing() const {
+        return mLetterSpacing;
+    }
+
+    void setFontFeatureSettings(const std::string& fontFeatureSettings) {
+        mFontFeatureSettings = fontFeatureSettings;
+    }
+
+    std::string getFontFeatureSettings() const {
+        return mFontFeatureSettings;
+    }
+
+    void setMinikinLangListId(uint32_t minikinLangListId) {
+        mMinikinLangListId = minikinLangListId;
+    }
+
+    uint32_t getMinikinLangListId() const {
+        return mMinikinLangListId;
+    }
+
+    void setFontVariant(FontVariant variant) {
+        mFontVariant = variant;
+    }
+
+    FontVariant getFontVariant() const {
+        return mFontVariant;
+    }
+
+    void setHyphenEdit(uint32_t hyphen) {
+        mHyphenEdit = hyphen;
+    }
+
+    uint32_t getHyphenEdit() const {
+        return mHyphenEdit;
+    }
+
+private:
+    float mLetterSpacing = 0;
+    std::string mFontFeatureSettings;
+    uint32_t mMinikinLangListId;
+    FontVariant mFontVariant;
+    uint32_t mHyphenEdit = 0;
+};
+
+}  // namespace android
+
+#endif // ANDROID_GRAPHICS_PAINT_H_
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
new file mode 100644
index 0000000..b27672c
--- /dev/null
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include "Paint.h"
+
+namespace android {
+
+Paint::Paint() :
+        SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
+        mFontVariant(VARIANT_DEFAULT) {
+}
+
+Paint::Paint(const Paint& paint) : SkPaint(paint),
+        mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings),
+        mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant),
+        mHyphenEdit(paint.mHyphenEdit) {
+}
+
+Paint::Paint(const SkPaint& paint) : SkPaint(paint),
+        mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
+        mFontVariant(VARIANT_DEFAULT) {
+}
+
+Paint::~Paint() {
+}
+
+Paint& Paint::operator=(const Paint& other) {
+    SkPaint::operator=(other);
+    mLetterSpacing = other.mLetterSpacing;
+    mFontFeatureSettings = other.mFontFeatureSettings;
+    mMinikinLangListId = other.mMinikinLangListId;
+    mFontVariant = other.mFontVariant;
+    mHyphenEdit = other.mHyphenEdit;
+    return *this;
+}
+
+bool operator==(const Paint& a, const Paint& b) {
+    return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b)
+            && a.mLetterSpacing == b.mLetterSpacing
+            && a.mFontFeatureSettings == b.mFontFeatureSettings
+            && a.mMinikinLangListId == b.mMinikinLangListId
+            && a.mFontVariant == b.mFontVariant
+            && a.mHyphenEdit == b.mHyphenEdit;
+}
+
+}
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
new file mode 100644
index 0000000..fa8ad5d
--- /dev/null
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is the implementation of the Typeface object. Historically, it has
+ * just been SkTypeface, but we are migrating to Minikin. For the time
+ * being, that choice is hidden under the USE_MINIKIN compile-time flag.
+ */
+
+#include "Typeface.h"
+
+#include "MinikinSkia.h"
+#include "SkTypeface.h"
+#include "SkPaint.h"
+
+#include <minikin/FontCollection.h>
+#include <minikin/FontFamily.h>
+#include <minikin/Layout.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// Resolve the 1..9 weight based on base weight and bold flag
+static void resolveStyle(Typeface* typeface) {
+    int weight = typeface->fBaseWeight / 100;
+    if (typeface->fSkiaStyle & SkTypeface::kBold) {
+        weight += 3;
+    }
+    if (weight > 9) {
+        weight = 9;
+    }
+    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
+    typeface->fStyle = FontStyle(weight, italic);
+}
+
+Typeface* gDefaultTypeface = NULL;
+pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
+
+// This installs a default typeface (from a hardcoded path) that allows
+// layouts to work (not crash on null pointer) before the default
+// typeface is set.
+// TODO: investigate why layouts are being created before Typeface.java
+// class initialization.
+static FontCollection *makeFontCollection() {
+    std::vector<FontFamily *>typefaces;
+    const char *fns[] = {
+        "/system/fonts/Roboto-Regular.ttf",
+    };
+
+    FontFamily *family = new FontFamily();
+    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
+        const char *fn = fns[i];
+        ALOGD("makeFontCollection adding %s", fn);
+        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
+        if (skFace != NULL) {
+            MinikinFont *font = new MinikinFontSkia(skFace);
+            family->addFont(font);
+            font->Unref();
+        } else {
+            ALOGE("failed to create font %s", fn);
+        }
+    }
+    typefaces.push_back(family);
+
+    FontCollection *result = new FontCollection(typefaces);
+    family->Unref();
+    return result;
+}
+
+static void getDefaultTypefaceOnce() {
+    Layout::init();
+    if (gDefaultTypeface == NULL) {
+        // We expect the client to set a default typeface, but provide a
+        // default so we can make progress before that happens.
+        gDefaultTypeface = new Typeface;
+        gDefaultTypeface->fFontCollection = makeFontCollection();
+        gDefaultTypeface->fSkiaStyle = SkTypeface::kNormal;
+        gDefaultTypeface->fBaseWeight = 400;
+        resolveStyle(gDefaultTypeface);
+    }
+}
+
+Typeface* Typeface::resolveDefault(Typeface* src) {
+    if (src == NULL) {
+        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
+        return gDefaultTypeface;
+    } else {
+        return src;
+    }
+}
+
+Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
+    Typeface* resolvedFace = Typeface::resolveDefault(src);
+    Typeface* result = new Typeface;
+    if (result != 0) {
+        result->fFontCollection = resolvedFace->fFontCollection;
+        result->fFontCollection->Ref();
+        result->fSkiaStyle = style;
+        result->fBaseWeight = resolvedFace->fBaseWeight;
+        resolveStyle(result);
+    }
+    return result;
+}
+
+Typeface* Typeface::createWeightAlias(Typeface* src, int weight) {
+    Typeface* resolvedFace = Typeface::resolveDefault(src);
+    Typeface* result = new Typeface;
+    if (result != 0) {
+        result->fFontCollection = resolvedFace->fFontCollection;
+        result->fFontCollection->Ref();
+        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fBaseWeight = weight;
+        resolveStyle(result);
+    }
+    return result;
+}
+
+Typeface* Typeface::createFromFamilies(const std::vector<FontFamily*>& families) {
+    Typeface* result = new Typeface;
+    result->fFontCollection = new FontCollection(families);
+    if (families.empty()) {
+        ALOGW("createFromFamilies creating empty collection");
+        result->fSkiaStyle = SkTypeface::kNormal;
+    } else {
+        const FontStyle defaultStyle;
+        FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
+        MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
+        if (mf != NULL) {
+            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
+            // TODO: probably better to query more precise style from family, will be important
+            // when we open up API to access 100..900 weights
+            result->fSkiaStyle = skTypeface->style();
+        } else {
+            result->fSkiaStyle = SkTypeface::kNormal;
+        }
+    }
+    result->fBaseWeight = 400;
+    resolveStyle(result);
+    return result;
+}
+
+void Typeface::unref() {
+    fFontCollection->Unref();
+    delete this;
+}
+
+void Typeface::setDefault(Typeface* face) {
+    gDefaultTypeface = face;
+}
+
+}
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
new file mode 100644
index 0000000..8862e5a
--- /dev/null
+++ b/libs/hwui/hwui/Typeface.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
+#define _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
+
+#include "SkTypeface.h"
+
+#include <cutils/compiler.h>
+#include <minikin/FontCollection.h>
+#include <vector>
+
+namespace android {
+
+struct ANDROID_API Typeface {
+    FontCollection *fFontCollection;
+
+    // style used for constructing and querying Typeface objects
+    SkTypeface::Style fSkiaStyle;
+    // base weight in CSS-style units, 100..900
+    int fBaseWeight;
+
+    // resolved style actually used for rendering
+    FontStyle fStyle;
+
+    void unref();
+
+    static Typeface* resolveDefault(Typeface* src);
+
+    static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
+
+    static Typeface* createWeightAlias(Typeface* src, int baseweight);
+
+    static Typeface* createFromFamilies(const std::vector<FontFamily*>& families);
+
+    static void setDefault(Typeface* face);
+};
+
+}
+
+#endif  // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index 7d4ef0f..2990952 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -21,8 +21,11 @@
     libskia \
     libui \
     libgui \
-    libprotobuf-cpp-lite
+    libprotobuf-cpp-lite \
+    libharfbuzz_ng \
+    libft2 \
+    libminikin
 
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
     LOCAL_SHARED_LIBRARIES += libRS libRScpp
-endif
\ No newline at end of file
+endif
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 03cb5ce..b575c69 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -34,7 +34,6 @@
     glGenBuffers(1, &mUnitQuadBuffer);
     glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
     glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
-
     mCurrentBuffer = mUnitQuadBuffer;
 
     uint16_t regionIndices[kMaxNumberOfQuads * 6];
@@ -78,26 +77,18 @@
 // Buffer Objects
 ///////////////////////////////////////////////////////////////////////////////
 
-bool MeshState::bindMeshBuffer() {
-    return bindMeshBuffer(mUnitQuadBuffer);
-}
-
-bool MeshState::bindMeshBuffer(GLuint buffer) {
-    if (!buffer) buffer = mUnitQuadBuffer;
-    return bindMeshBufferInternal(buffer);
-}
-
-bool MeshState::unbindMeshBuffer() {
-    return bindMeshBufferInternal(0);
-}
-
-bool MeshState::bindMeshBufferInternal(GLuint buffer) {
+void MeshState::bindMeshBuffer(GLuint buffer) {
     if (mCurrentBuffer != buffer) {
         glBindBuffer(GL_ARRAY_BUFFER, buffer);
         mCurrentBuffer = buffer;
-        return true;
+
+        // buffer has changed, so invalidate cached vertex pos/texcoord pointers
+        resetVertexPointers();
     }
-    return false;
+}
+
+void MeshState::unbindMeshBuffer() {
+    return bindMeshBuffer(0);
 }
 
 void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size,
@@ -122,16 +113,22 @@
 // Vertices
 ///////////////////////////////////////////////////////////////////////////////
 
-void MeshState::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
+void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride) {
+    // update pos coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
+    if (mCurrentBuffer == 0
+            || vertices != mCurrentPositionPointer
+            || stride != mCurrentPositionStride) {
         glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
         mCurrentPositionPointer = vertices;
         mCurrentPositionStride = stride;
     }
 }
 
-void MeshState::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
+void MeshState::bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride) {
+    // update tex coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
+    if (mCurrentBuffer == 0
+            || vertices != mCurrentTexCoordsPointer
+            || stride != mCurrentTexCoordsStride) {
         glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
         mCurrentTexCoordsPointer = vertices;
         mCurrentTexCoordsStride = stride;
@@ -143,10 +140,6 @@
     mCurrentTexCoordsPointer = this;
 }
 
-void MeshState::resetTexCoordsVertexPointer() {
-    mCurrentTexCoordsPointer = this;
-}
-
 void MeshState::enableTexCoordsVertexArray() {
     if (!mTexCoordsArrayEnabled) {
         glEnableVertexAttribArray(Program::kBindingTexCoords);
@@ -166,26 +159,18 @@
 // Indices
 ///////////////////////////////////////////////////////////////////////////////
 
-bool MeshState::bindIndicesBufferInternal(const GLuint buffer) {
+void MeshState::bindIndicesBuffer(const GLuint buffer) {
     if (mCurrentIndicesBuffer != buffer) {
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
         mCurrentIndicesBuffer = buffer;
-        return true;
     }
-    return false;
 }
 
-bool MeshState::bindQuadIndicesBuffer() {
-    return bindIndicesBufferInternal(mQuadListIndices);
-}
-
-bool MeshState::unbindIndicesBuffer() {
+void MeshState::unbindIndicesBuffer() {
     if (mCurrentIndicesBuffer) {
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
         mCurrentIndicesBuffer = 0;
-        return true;
     }
-    return false;
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
index 6c0fb78..dd68468 100644
--- a/libs/hwui/renderstate/MeshState.h
+++ b/libs/hwui/renderstate/MeshState.h
@@ -60,20 +60,16 @@
     ///////////////////////////////////////////////////////////////////////////////
     // Buffer objects
     ///////////////////////////////////////////////////////////////////////////////
-    /**
-     * Binds the VBO used to render simple textured quads.
-     */
-    bool bindMeshBuffer();
 
     /**
      * Binds the specified VBO if needed. If buffer == 0, binds default simple textured quad.
      */
-    bool bindMeshBuffer(GLuint buffer);
+    void bindMeshBuffer(GLuint buffer);
 
     /**
-     * Unbinds the VBO used to render simple textured quads.
+     * Unbinds the current VBO if active.
      */
-    bool unbindMeshBuffer();
+    void unbindMeshBuffer();
 
     void genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data, GLenum usage);
     void deleteMeshBuffer(GLuint);
@@ -85,21 +81,20 @@
      * Binds an attrib to the specified float vertex pointer.
      * Assumes a stride of gTextureVertexStride and a size of 2.
      */
-    void bindPositionVertexPointer(bool force, const GLvoid* vertices,
+    void bindPositionVertexPointer(const GLvoid* vertices,
             GLsizei stride = kTextureVertexStride);
 
     /**
      * Binds an attrib to the specified float vertex pointer.
      * Assumes a stride of gTextureVertexStride and a size of 2.
      */
-    void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices,
+    void bindTexCoordsVertexPointer(const GLvoid* vertices,
             GLsizei stride = kTextureVertexStride);
 
     /**
      * Resets the vertex pointers.
      */
     void resetVertexPointers();
-    void resetTexCoordsVertexPointer();
 
     void enableTexCoordsVertexArray();
     void disableTexCoordsVertexArray();
@@ -107,12 +102,8 @@
     ///////////////////////////////////////////////////////////////////////////////
     // Indices
     ///////////////////////////////////////////////////////////////////////////////
-    /**
-     * Binds a global indices buffer that can draw up to
-     * gMaxNumberOfQuads quads.
-     */
-    bool bindQuadIndicesBuffer();
-    bool unbindIndicesBuffer();
+    void bindIndicesBuffer(const GLuint buffer);
+    void unbindIndicesBuffer();
 
     ///////////////////////////////////////////////////////////////////////////////
     // Getters - for use in Glop building
@@ -121,8 +112,6 @@
     GLuint getQuadListIBO() { return mQuadListIndices; }
 private:
     MeshState();
-    bool bindMeshBufferInternal(const GLuint buffer);
-    bool bindIndicesBufferInternal(const GLuint buffer);
 
     GLuint mUnitQuadBuffer;
 
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index 54f38e8..73b6c02 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -54,6 +54,14 @@
     return Rect(0, viewportHeight * texY, viewportWidth * texX, 0);
 }
 
+void OffscreenBuffer::dirty(Rect dirtyArea) {
+    dirtyArea.doIntersect(0, 0, viewportWidth, viewportHeight);
+    if (!dirtyArea.isEmpty()) {
+        region.orSelf(android::Rect(dirtyArea.left, dirtyArea.top,
+                dirtyArea.right, dirtyArea.bottom));
+    }
+}
+
 void OffscreenBuffer::updateMeshFromRegion() {
     // avoid T-junctions as they cause artifacts in between the resultant
     // geometry when complex transforms occur.
@@ -119,7 +127,7 @@
 }
 
 void OffscreenBufferPool::clear() {
-    for (auto entry : mPool) {
+    for (auto& entry : mPool) {
         delete entry.layer;
     }
     mPool.clear();
@@ -156,6 +164,9 @@
         // resize in place
         layer->viewportWidth = width;
         layer->viewportHeight = height;
+
+        // entire area will be repainted (and may be smaller) so clear usage region
+        layer->region.clear();
         return layer;
     }
     putOrDelete(layer);
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index 94155ef..089f131 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -48,6 +48,8 @@
 
     Rect getTextureCoordinates();
 
+    void dirty(Rect dirtyArea);
+
     // must be called prior to rendering, to construct/update vertex buffer
     void updateMeshFromRegion();
 
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index e535f2f..ea4391b 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -292,28 +292,27 @@
     // ---------- Mesh setup ----------
     // --------------------------------
     // vertices
-    const bool force = meshState().bindMeshBufferInternal(vertices.bufferObject)
-            || (vertices.position != nullptr);
-    meshState().bindPositionVertexPointer(force, vertices.position, vertices.stride);
+    meshState().bindMeshBuffer(vertices.bufferObject);
+    meshState().bindPositionVertexPointer(vertices.position, vertices.stride);
 
     // indices
-    meshState().bindIndicesBufferInternal(indices.bufferObject);
+    meshState().bindIndicesBuffer(indices.bufferObject);
 
     if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
         const Glop::Fill::TextureData& texture = fill.texture;
         // texture always takes slot 0, shader samplers increment from there
         mCaches->textureState().activateTexture(0);
 
+        mCaches->textureState().bindTexture(texture.target, texture.texture->id());
         if (texture.clamp != GL_INVALID_ENUM) {
-            texture.texture->setWrap(texture.clamp, true, false, texture.target);
+            texture.texture->setWrap(texture.clamp, false, false, texture.target);
         }
         if (texture.filter != GL_INVALID_ENUM) {
-            texture.texture->setFilter(texture.filter, true, false, texture.target);
+            texture.texture->setFilter(texture.filter, false, false, texture.target);
         }
 
-        mCaches->textureState().bindTexture(texture.target, texture.texture->id());
         meshState().enableTexCoordsVertexArray();
-        meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
+        meshState().bindTexCoordsVertexPointer(vertices.texCoord, vertices.stride);
 
         if (texture.textureTransform) {
             glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
@@ -361,11 +360,9 @@
         const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
         while (elementsCount > 0) {
             GLsizei drawCount = std::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
-
-            // rebind pointers without forcing, since initial bind handled above
-            meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
+            meshState().bindPositionVertexPointer(vertexData, vertices.stride);
             if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
-                meshState().bindTexCoordsVertexPointer(false,
+                meshState().bindTexCoordsVertexPointer(
                         vertexData + kMeshTextureOffset, vertices.stride);
             }
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4f528b1..63fa788 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -19,7 +19,6 @@
 
 #include "AnimationContext.h"
 #include "Caches.h"
-#include "Canvas.h"
 #include "DeferredLayerUpdater.h"
 #include "EglManager.h"
 #include "LayerUpdateQueue.h"
@@ -27,6 +26,7 @@
 #include "OpenGLRenderer.h"
 #include "Properties.h"
 #include "RenderThread.h"
+#include "hwui/Canvas.h"
 #include "renderstate/RenderState.h"
 #include "renderstate/Stencil.h"
 #include "protos/hwui.pb.h"
@@ -86,10 +86,12 @@
     freePrefetechedLayers();
     destroyHardwareResources();
     mAnimationContext->destroy();
+#if !HWUI_NEW_OPS
     if (mCanvas) {
         delete mCanvas;
         mCanvas = nullptr;
     }
+#endif
 }
 
 void CanvasContext::setSurface(Surface* surface) {
@@ -345,15 +347,29 @@
     mEglManager.damageFrame(frame, dirty);
 
 #if HWUI_NEW_OPS
+    auto& caches = Caches::getInstance();
     FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
-            mRenderNodes, mLightGeometry, mContentDrawBounds, &Caches::getInstance());
+            mRenderNodes, mLightGeometry, mContentDrawBounds, caches);
     mLayerUpdateQueue.clear();
-    BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
+    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
             mOpaque, mLightInfo);
-    // TODO: profiler().draw(mCanvas);
     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+    profiler().draw(&renderer);
     bool drew = renderer.didDraw();
 
+    // post frame cleanup
+    caches.clearGarbage();
+    caches.pathCache.trim();
+    caches.tessellationCache.trim();
+
+#if DEBUG_MEMORY_USAGE
+    mCaches.dumpMemoryUsage();
+#else
+    if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
+        caches.dumpMemoryUsage();
+    }
+#endif
+
 #else
     mCanvas->prepareDirty(frame.width(), frame.height(),
             dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
@@ -470,13 +486,15 @@
     bool drew = mCanvas->finish();
 #endif
 
+    waitOnFences();
+
     GL_CHECKPOINT(LOW);
 
     // Even if we decided to cancel the frame, from the perspective of jank
     // metrics the frame was swapped at this point
     mCurrentFrameInfo->markSwapBuffers();
 
-    if (drew) {
+    if (drew || mEglManager.damageRequiresSwap()) {
         if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
             setSurface(nullptr);
         }
@@ -558,7 +576,7 @@
 
 static void destroyPrefetechedNode(RenderNode* node) {
     ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
-    node->destroyHardwareResources();
+    node->destroyHardwareResources(nullptr);
     node->decStrong(nullptr);
 }
 
@@ -571,9 +589,11 @@
 
 void CanvasContext::buildLayer(RenderNode* node) {
     ATRACE_CALL();
-    if (!mEglManager.hasEglContext() || !mCanvas) {
-        return;
-    }
+    if (!mEglManager.hasEglContext()) return;
+#if !HWUI_NEW_OPS
+    if (!mCanvas) return;
+#endif
+
     // buildLayer() will leave the tree in an unknown state, so we must stop drawing
     stopDrawing();
 
@@ -593,7 +613,15 @@
     node->setPropertyFieldsDirty(RenderNode::GENERIC);
 
 #if HWUI_NEW_OPS
-    // TODO: support buildLayer
+    static const std::vector< sp<RenderNode> > emptyNodeList;
+    auto& caches = Caches::getInstance();
+    FrameBuilder frameBuilder(mLayerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1,
+            emptyNodeList, mLightGeometry, mContentDrawBounds, caches);
+    mLayerUpdateQueue.clear();
+    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
+            mOpaque, mLightInfo);
+    LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
+    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
 #else
     mCanvas->markLayersAsBuildLayers();
     mCanvas->flushLayerUpdates();
@@ -613,7 +641,7 @@
     if (mEglManager.hasEglContext()) {
         freePrefetechedLayers();
         for (const sp<RenderNode>& node : mRenderNodes) {
-            node->destroyHardwareResources();
+            node->destroyHardwareResources(nullptr);
         }
         Caches& caches = Caches::getInstance();
         // Make sure to release all the textures we were owning as there won't
@@ -712,6 +740,37 @@
 #endif
 }
 
+void CanvasContext::waitOnFences() {
+    if (mFrameFences.size()) {
+        ATRACE_CALL();
+        for (auto& fence : mFrameFences) {
+            fence->getResult();
+        }
+        mFrameFences.clear();
+    }
+}
+
+class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
+public:
+    FuncTaskProcessor(Caches& caches)
+            : TaskProcessor<bool>(&caches.tasks) {}
+
+    virtual void onProcess(const sp<Task<bool> >& task) override {
+        FuncTask* t = static_cast<FuncTask*>(task.get());
+        t->func();
+        task->setResult(true);
+    }
+};
+
+void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
+    if (!mFrameWorkProcessor.get()) {
+        mFrameWorkProcessor = new FuncTaskProcessor(Caches::getInstance());
+    }
+    sp<FuncTask> task(new FuncTask());
+    task->func = func;
+    mFrameWorkProcessor->add(task);
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index cb61e51..6d0889e 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -24,6 +24,8 @@
 #include "IContextFactory.h"
 #include "LayerUpdateQueue.h"
 #include "RenderNode.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
 #include "utils/RingBuffer.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
@@ -41,6 +43,7 @@
 #include <utils/Functor.h>
 #include <gui/Surface.h>
 
+#include <functional>
 #include <set>
 #include <string>
 #include <vector>
@@ -159,6 +162,9 @@
         }
     }
 
+    // Used to queue up work that needs to be completed before this frame completes
+    ANDROID_API void enqueueFrameWork(std::function<void()>&& func);
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -170,6 +176,8 @@
 
     void freePrefetechedLayers();
 
+    void waitOnFences();
+
     EGLint mLastFrameWidth = 0;
     EGLint mLastFrameHeight = 0;
 
@@ -188,10 +196,11 @@
     RingBuffer<SwapHistory, 3> mSwapHistory;
 
     bool mOpaque;
-    OpenGLRenderer* mCanvas = nullptr;
 #if HWUI_NEW_OPS
     BakedOpRenderer::LightInfo mLightInfo;
     FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 };
+#else
+    OpenGLRenderer* mCanvas = nullptr;
 #endif
 
     bool mHaveNewSurface = false;
@@ -213,6 +222,16 @@
 
     // Stores the bounds of the main content.
     Rect mContentDrawBounds;
+
+    // TODO: This is really a Task<void> but that doesn't really work
+    // when Future<> expects to be able to get/set a value
+    struct FuncTask : public Task<bool> {
+        std::function<void()> func;
+    };
+    class FuncTaskProcessor;
+
+    std::vector< sp<FuncTask> > mFrameFences;
+    sp<TaskProcessor<bool> > mFrameWorkProcessor;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 364d4dd..8def7ad 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -270,6 +270,12 @@
         // Ensure we always have a valid surface & context
         surface = mPBufferSurface;
     }
+    // TODO: Temporary to help diagnose b/27286867
+    if (mCurrentSurface == mPBufferSurface || surface == mPBufferSurface) {
+        ALOGD("Switching from surface %p%s to %p%s", mCurrentSurface,
+                mCurrentSurface == mPBufferSurface ? " (pbuffer)" : "",
+                        surface, surface == mPBufferSurface ? " (pbuffer)" : "");
+    }
     if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
         if (errOut) {
             *errOut = eglGetError();
@@ -324,6 +330,10 @@
 #endif
 }
 
+bool EglManager::damageRequiresSwap() {
+    return EglExtensions.setDamage && mSwapBehavior == SwapBehavior::BufferAge;
+}
+
 bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
 
     if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 62b5b99..459baed 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -70,6 +70,10 @@
     bool makeCurrent(EGLSurface surface, EGLint* errOut = nullptr);
     Frame beginFrame(EGLSurface surface);
     void damageFrame(const Frame& frame, const SkRect& dirty);
+    // If this returns true it is mandatory that swapBuffers is called
+    // if damageFrame is called without subsequent calls to damageFrame().
+    // See EGL_KHR_partial_update for more information
+    bool damageRequiresSwap();
     bool swapBuffers(const Frame& frame, const SkRect& screenDirty);
 
     // Returns true iff the surface is now preserving buffers.
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 04223a7..16dd108 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -56,6 +56,7 @@
     enum {
         FrameStats = 1 << 0,
         Reset      = 1 << 1,
+        JankStats  = 1 << 2,
     };
 };
 
@@ -415,7 +416,6 @@
 CREATE_BRIDGE4(dumpProfileInfo, CanvasContext* context, RenderThread* thread,
         int fd, int dumpFlags) {
     args->context->profiler().dumpData(args->fd);
-    args->thread->jankTracker().dump(args->fd);
     if (args->dumpFlags & DumpFlags::FrameStats) {
         args->context->dumpFrames(args->fd);
     }
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 9595a85..c762eed 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -16,12 +16,10 @@
 
 #include "TestUtils.h"
 
+#include "hwui/Paint.h"
 #include "DeferredLayerUpdater.h"
 #include "LayerRenderer.h"
 
-#include <unistd.h>
-#include <signal.h>
-
 namespace android {
 namespace uirenderer {
 
@@ -44,17 +42,21 @@
 
 sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
         renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
-        std::function<void(Matrix4*)> transformSetupCallback) {
+        const SkMatrix& transform) {
+    Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
+    layer->getTransform().load(transform);
+
+    sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
+    layerUpdater->setSize(width, height);
+    layerUpdater->setTransform(&transform);
+
+    // updateLayer so it's ready to draw
     bool isOpaque = true;
     bool forceFilter = true;
     GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES;
-
-    Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
     LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter,
-            renderTarget, Matrix4::identity().data);
-    transformSetupCallback(&(layer->getTransform()));
+    renderTarget, Matrix4::identity().data);
 
-    sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
     return layerUpdater;
 }
 
@@ -90,73 +92,20 @@
     *outTotalAdvance = totalAdvance;
 }
 
-void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
+
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
         const SkPaint& paint, float x, float y) {
-    // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
-    LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
-            "must use glyph encoding");
-    SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
-    SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
-
-    std::vector<glyph_t> glyphs;
-    std::vector<float> positions;
-    float totalAdvance;
-    Rect bounds;
-    layoutTextUnscaled(paint, text, &glyphs, &positions, &totalAdvance, &bounds);
-
-    // apply alignment via x parameter (which JNI layer would have done)
-    if (paint.getTextAlign() == SkPaint::kCenter_Align) {
-        x -= totalAdvance / 2;
-    } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
-        x -= totalAdvance;
-    }
-
-    bounds.translate(x, y);
-
-    // Force left alignment, since alignment offset is already baked in
-    SkPaint alignPaintCopy(paint);
-    alignPaintCopy.setTextAlign(SkPaint::kLeft_Align);
-    canvas->drawText(glyphs.data(), positions.data(), glyphs.size(), alignPaintCopy, x, y,
-                bounds.left, bounds.top, bounds.right, bounds.bottom, totalAdvance);
+    auto utf16 = asciiToUtf16(text);
+    canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, 0, paint, nullptr);
 }
 
-void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
         const SkPaint& paint, const SkPath& path) {
-    // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
-    LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
-            "must use glyph encoding");
-    SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
-    SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
-
-    std::vector<glyph_t> glyphs;
-    while (*text != '\0') {
-        SkUnichar unichar = SkUTF8_NextUnichar(&text);
-        glyphs.push_back(autoCache.getCache()->unicharToGlyph(unichar));
-    }
-    canvas->drawTextOnPath(glyphs.data(), glyphs.size(), path, 0, 0, paint);
-}
-
-static void defaultCrashHandler() {
-    fprintf(stderr, "RenderThread crashed!");
-}
-
-static std::function<void()> gCrashHandler = defaultCrashHandler;
-static sighandler_t gPreviousSignalHandler;
-
-static void signalHandler(int sig) {
-    gCrashHandler();
-    if (gPreviousSignalHandler) {
-        gPreviousSignalHandler(sig);
-    }
-}
-
-void TestUtils::setRenderThreadCrashHandler(std::function<void()> crashHandler) {
-    gCrashHandler = crashHandler;
+    auto utf16 = asciiToUtf16(text);
+    canvas->drawTextOnPath(utf16.get(), strlen(text), 0, path, 0, 0, paint, nullptr);
 }
 
 void TestUtils::TestTask::run() {
-    gPreviousSignalHandler = signal(SIGABRT, signalHandler);
-
     // RenderState only valid once RenderThread is running, so queried here
     RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
 
@@ -164,9 +113,15 @@
     rtCallback(renderthread::RenderThread::getInstance());
     renderState.flush(Caches::FlushMode::Full);
     renderState.onGLContextDestroyed();
+}
 
-    // Restore the previous signal handler
-    signal(SIGABRT, gPreviousSignalHandler);
+std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) {
+    const int length = strlen(str);
+    std::unique_ptr<uint16_t[]> utf16(new uint16_t[length]);
+    for (int i = 0; i < length; i++) {
+        utf16.get()[i] = str[i];
+    }
+    return utf16;
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 6f23705..5492035 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -122,7 +122,7 @@
 
     static sp<DeferredLayerUpdater> createTextureLayerUpdater(
             renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
-            std::function<void(Matrix4*)> transformSetupCallback);
+            const SkMatrix& transform);
 
     template<class CanvasType>
     static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
@@ -180,8 +180,6 @@
 
     typedef std::function<void(renderthread::RenderThread& thread)> RtCallback;
 
-    static void setRenderThreadCrashHandler(std::function<void()> crashHandler);
-
     class TestTask : public renderthread::RenderTask {
     public:
         TestTask(RtCallback rtCallback)
@@ -209,16 +207,18 @@
             std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions,
             float* outTotalAdvance, Rect* outBounds);
 
-    static void drawTextToCanvas(TestCanvas* canvas, const char* text,
+    static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
             const SkPaint& paint, float x, float y);
 
-    static void drawTextToCanvas(TestCanvas* canvas, const char* text,
+    static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
             const SkPaint& paint, const SkPath& path);
 
+    static std::unique_ptr<uint16_t[]> asciiToUtf16(const char* str);
+
 private:
     static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
         node->syncProperties();
-        node->syncDisplayList();
+        node->syncDisplayList(nullptr);
         auto displayList = node->getDisplayList();
         if (displayList) {
             for (auto&& childOp : displayList->getChildren()) {
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
new file mode 100644
index 0000000..63c067b
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestSceneBase.h"
+#include "utils/Color.h"
+
+#include <minikin/Layout.h>
+#include <hwui/Paint.h>
+
+#include <cstdio>
+
+class GlyphStressAnimation;
+
+static TestScene::Registrar _GlyphStress(TestScene::Info{
+    "glyphstress",
+    "A stress test for both the glyph cache, and glyph rendering.",
+    TestScene::simpleCreateScene<GlyphStressAnimation>
+});
+
+class GlyphStressAnimation : public TestScene {
+public:
+    sp<RenderNode> container;
+    void createContent(int width, int height, TestCanvas& canvas) override {
+        container = TestUtils::createNode(0, 0, width, height, nullptr);
+        doFrame(0); // update container
+
+        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+        canvas.drawRenderNode(container.get());
+    }
+
+    void doFrame(int frameNr) override {
+        std::unique_ptr<uint16_t[]> text = TestUtils::asciiToUtf16(
+                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+        ssize_t textLength = 26 * 2;
+
+        TestCanvas canvas(
+                container->stagingProperties().getWidth(),
+                container->stagingProperties().getHeight());
+        Paint paint;
+        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        paint.setAntiAlias(true);
+        paint.setColor(Color::Black);
+        for (int i = 0; i < 5; i++) {
+            paint.setTextSize(10 + (frameNr % 20) + i * 20);
+            canvas.drawText(text.get(), 0, textLength, textLength,
+                    0, 100 * (i + 2), kBidi_Force_LTR, paint, nullptr);
+        }
+
+        container->setStagingDisplayList(canvas.finishRecording());
+    }
+};
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index 43e247e..ab368c05 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -136,9 +136,9 @@
             textPaint.setAntiAlias(true);
             char buf[256];
             snprintf(buf, sizeof(buf), "This card is #%d", cardId);
-            TestUtils::drawTextToCanvas(&canvas, buf, textPaint, cardHeight, dp(25));
+            TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, cardHeight, dp(25));
             textPaint.setTextSize(dp(15));
-            TestUtils::drawTextToCanvas(&canvas, "This is some more text on the card", textPaint,
+            TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
                     cardHeight, dp(45));
 
             canvas.drawBitmap(createRandomCharIcon(), dp(10), dp(10), nullptr);
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
index 1823db2..be8f48b 100644
--- a/libs/hwui/tests/common/scenes/TextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -39,14 +39,14 @@
 
             paint.setColor(Color::Black);
             for (int i = 0; i < 10; i++) {
-                TestUtils::drawTextToCanvas(&canvas, "Test string", paint, 400, i * 100);
+                TestUtils::drawUtf8ToCanvas(&canvas, "Test string", paint, 400, i * 100);
             }
 
             SkPath path;
             path.addOval(SkRect::MakeLTRB(100, 100, 300, 300));
 
             paint.setColor(Color::Blue_500);
-            TestUtils::drawTextToCanvas(&canvas, "This is a neat circle of text!", paint, path);
+            TestUtils::drawUtf8ToCanvas(&canvas, "This is a neat circle of text!", paint, path);
         });
         canvas.drawRenderNode(card.get());
     }
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index b317c12..06b68d1 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
 
 #include "DisplayList.h"
 #if HWUI_NEW_OPS
@@ -23,7 +23,6 @@
 #include "DisplayListCanvas.h"
 #endif
 #include "tests/common/TestUtils.h"
-#include "tests/microbench/MicroBench.h"
 
 using namespace android;
 using namespace android::uirenderer;
@@ -34,74 +33,64 @@
 typedef DisplayListCanvas TestCanvas;
 #endif
 
-BENCHMARK_NO_ARG(BM_DisplayList_alloc);
-void BM_DisplayList_alloc::Run(int iters) {
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+void BM_DisplayList_alloc(benchmark::State& benchState) {
+    while (benchState.KeepRunning()) {
         auto displayList = new DisplayList();
-        MicroBench::DoNotOptimize(displayList);
+        benchmark::DoNotOptimize(displayList);
         delete displayList;
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_DisplayList_alloc);
 
-BENCHMARK_NO_ARG(BM_DisplayList_alloc_theoretical);
-void BM_DisplayList_alloc_theoretical::Run(int iters) {
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+void BM_DisplayList_alloc_theoretical(benchmark::State& benchState) {
+    while (benchState.KeepRunning()) {
         auto displayList = new char[sizeof(DisplayList)];
-        MicroBench::DoNotOptimize(displayList);
+        benchmark::DoNotOptimize(displayList);
         delete[] displayList;
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_DisplayList_alloc_theoretical);
 
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_empty);
-void BM_DisplayListCanvas_record_empty::Run(int iters) {
+void BM_DisplayListCanvas_record_empty(benchmark::State& benchState) {
     TestCanvas canvas(100, 100);
     delete canvas.finishRecording();
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+    while (benchState.KeepRunning()) {
         canvas.resetRecording(100, 100);
-        MicroBench::DoNotOptimize(&canvas);
+        benchmark::DoNotOptimize(&canvas);
         delete canvas.finishRecording();
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_DisplayListCanvas_record_empty);
 
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_saverestore);
-void BM_DisplayListCanvas_record_saverestore::Run(int iters) {
+void BM_DisplayListCanvas_record_saverestore(benchmark::State& benchState) {
     TestCanvas canvas(100, 100);
     delete canvas.finishRecording();
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+    while (benchState.KeepRunning()) {
         canvas.resetRecording(100, 100);
         canvas.save(SaveFlags::MatrixClip);
         canvas.save(SaveFlags::MatrixClip);
-        MicroBench::DoNotOptimize(&canvas);
+        benchmark::DoNotOptimize(&canvas);
         canvas.restore();
         canvas.restore();
         delete canvas.finishRecording();
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_DisplayListCanvas_record_saverestore);
 
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_translate);
-void BM_DisplayListCanvas_record_translate::Run(int iters) {
+void BM_DisplayListCanvas_record_translate(benchmark::State& benchState) {
     TestCanvas canvas(100, 100);
     delete canvas.finishRecording();
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+    while (benchState.KeepRunning()) {
         canvas.resetRecording(100, 100);
         canvas.scale(10, 10);
-        MicroBench::DoNotOptimize(&canvas);
+        benchmark::DoNotOptimize(&canvas);
         delete canvas.finishRecording();
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_DisplayListCanvas_record_translate);
 
 /**
  * Simulate a simple view drawing a background, overlapped by an image.
@@ -109,16 +98,14 @@
  * Note that the recording commands are intentionally not perfectly efficient, as the
  * View system frequently produces unneeded save/restores.
  */
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_simpleBitmapView);
-void BM_DisplayListCanvas_record_simpleBitmapView::Run(int iters) {
+void BM_DisplayListCanvas_record_simpleBitmapView(benchmark::State& benchState) {
     TestCanvas canvas(100, 100);
     delete canvas.finishRecording();
 
     SkPaint rectPaint;
     SkBitmap iconBitmap = TestUtils::createSkBitmap(80, 80);
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+    while (benchState.KeepRunning()) {
         canvas.resetRecording(100, 100);
         {
             canvas.save(SaveFlags::MatrixClip);
@@ -131,11 +118,11 @@
             canvas.drawBitmap(iconBitmap, 0, 0, nullptr);
             canvas.restore();
         }
-        MicroBench::DoNotOptimize(&canvas);
+        benchmark::DoNotOptimize(&canvas);
         delete canvas.finishRecording();
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView);
 
 class NullClient: public CanvasStateClient {
     void onViewportInitialized() override {}
@@ -143,48 +130,42 @@
     GLuint getTargetFbo() const override { return 0; }
 };
 
-BENCHMARK_NO_ARG(BM_CanvasState_saverestore);
-void BM_CanvasState_saverestore::Run(int iters) {
+void BM_CanvasState_saverestore(benchmark::State& benchState) {
     NullClient client;
     CanvasState state(client);
     state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+    while (benchState.KeepRunning()) {
         state.save(SaveFlags::MatrixClip);
         state.save(SaveFlags::MatrixClip);
-        MicroBench::DoNotOptimize(&state);
+        benchmark::DoNotOptimize(&state);
         state.restore();
         state.restore();
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_CanvasState_saverestore);
 
-BENCHMARK_NO_ARG(BM_CanvasState_init);
-void BM_CanvasState_init::Run(int iters) {
+void BM_CanvasState_init(benchmark::State& benchState) {
     NullClient client;
     CanvasState state(client);
     state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+    while (benchState.KeepRunning()) {
         state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
-        MicroBench::DoNotOptimize(&state);
+        benchmark::DoNotOptimize(&state);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_CanvasState_init);
 
-BENCHMARK_NO_ARG(BM_CanvasState_translate);
-void BM_CanvasState_translate::Run(int iters) {
+void BM_CanvasState_translate(benchmark::State& benchState) {
     NullClient client;
     CanvasState state(client);
     state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; ++i) {
+    while (benchState.KeepRunning()) {
         state.translate(5, 5, 0);
-        MicroBench::DoNotOptimize(&state);
+        benchmark::DoNotOptimize(&state);
         state.translate(-5, -5, 0);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_CanvasState_translate);
diff --git a/libs/hwui/tests/microbench/FontBench.cpp b/libs/hwui/tests/microbench/FontBench.cpp
new file mode 100644
index 0000000..df3d041
--- /dev/null
+++ b/libs/hwui/tests/microbench/FontBench.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <benchmark/benchmark.h>
+
+#include "GammaFontRenderer.h"
+#include "tests/common/TestUtils.h"
+
+#include <SkPaint.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+void BM_FontRenderer_precache_cachehits(benchmark::State& state) {
+    TestUtils::runOnRenderThread([&state](renderthread::RenderThread& thread) {
+        SkPaint paint;
+        paint.setTextSize(20);
+        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        GammaFontRenderer gammaFontRenderer;
+        FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
+        fontRenderer.setFont(&paint, SkMatrix::I());
+
+        std::vector<glyph_t> glyphs;
+        std::vector<float> positions;
+        float totalAdvance;
+        uirenderer::Rect bounds;
+        TestUtils::layoutTextUnscaled(paint, "This is a test",
+                &glyphs, &positions, &totalAdvance, &bounds);
+
+        fontRenderer.precache(&paint, glyphs.data(), glyphs.size(), SkMatrix::I());
+
+        while (state.KeepRunning()) {
+            fontRenderer.precache(&paint, glyphs.data(), glyphs.size(), SkMatrix::I());
+        }
+    });
+}
+BENCHMARK(BM_FontRenderer_precache_cachehits);
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index 7845eb4..0aef620 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
 
 #include "BakedOpState.h"
 #include "BakedOpDispatcher.h"
@@ -27,7 +27,6 @@
 #include "tests/common/TestScene.h"
 #include "tests/common/TestUtils.h"
 #include "Vector.h"
-#include "tests/microbench/MicroBench.h"
 
 #include <vector>
 
@@ -62,38 +61,34 @@
     return vec;
 }
 
-BENCHMARK_NO_ARG(BM_FrameBuilder_defer);
-void BM_FrameBuilder_defer::Run(int iters) {
+void BM_FrameBuilder_defer(benchmark::State& state) {
     auto nodes = createTestNodeList();
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+    while (state.KeepRunning()) {
         FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-                nodes, sLightGeometry, nullptr);
-        MicroBench::DoNotOptimize(&frameBuilder);
+                nodes, sLightGeometry, Caches::getInstance());
+        benchmark::DoNotOptimize(&frameBuilder);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_FrameBuilder_defer);
 
-BENCHMARK_NO_ARG(BM_FrameBuilder_deferAndRender);
-void BM_FrameBuilder_deferAndRender::Run(int iters) {
-    TestUtils::runOnRenderThread([this, iters](RenderThread& thread) {
+void BM_FrameBuilder_deferAndRender(benchmark::State& state) {
+    TestUtils::runOnRenderThread([&state](RenderThread& thread) {
         auto nodes = createTestNodeList();
 
         RenderState& renderState = thread.renderState();
         Caches& caches = Caches::getInstance();
 
-        StartBenchmarkTiming();
-        for (int i = 0; i < iters; i++) {
+        while (state.KeepRunning()) {
             FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-                    nodes, sLightGeometry, nullptr);
+                    nodes, sLightGeometry, Caches::getInstance());
 
             BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
             frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
-            MicroBench::DoNotOptimize(&renderer);
+            benchmark::DoNotOptimize(&renderer);
         }
-        StopBenchmarkTiming();
     });
 }
+BENCHMARK(BM_FrameBuilder_deferAndRender);
 
 static std::vector<sp<RenderNode>> getSyncedSceneNodes(const char* sceneName) {
     gDisplay = getBuiltInDisplay(); // switch to real display if present
@@ -113,47 +108,43 @@
     return nodes;
 }
 
-static void benchDeferScene(testing::Benchmark& benchmark, int iters, const char* sceneName) {
-    auto nodes = getSyncedSceneNodes(sceneName);
-    benchmark.StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
-        FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
-                SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
-                nodes, sLightGeometry, nullptr);
-        MicroBench::DoNotOptimize(&frameBuilder);
-    }
-    benchmark.StopBenchmarkTiming();
-}
+static auto SCENES = {
+        "listview",
+};
 
-static void benchDeferAndRenderScene(testing::Benchmark& benchmark,
-        int iters, const char* sceneName) {
-    TestUtils::runOnRenderThread([&benchmark, iters, sceneName](RenderThread& thread) {
+void BM_FrameBuilder_defer_scene(benchmark::State& state) {
+    TestUtils::runOnRenderThread([&state](RenderThread& thread) {
+        const char* sceneName = *(SCENES.begin() + state.range_x());
+        state.SetLabel(sceneName);
+        auto nodes = getSyncedSceneNodes(sceneName);
+        while (state.KeepRunning()) {
+            FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
+                    SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
+                    nodes, sLightGeometry, Caches::getInstance());
+            benchmark::DoNotOptimize(&frameBuilder);
+        }
+    });
+}
+BENCHMARK(BM_FrameBuilder_defer_scene)->DenseRange(0, SCENES.size() - 1);
+
+void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) {
+    TestUtils::runOnRenderThread([&state](RenderThread& thread) {
+        const char* sceneName = *(SCENES.begin() + state.range_x());
+        state.SetLabel(sceneName);
         auto nodes = getSyncedSceneNodes(sceneName);
 
         RenderState& renderState = thread.renderState();
         Caches& caches = Caches::getInstance();
 
-        benchmark.StartBenchmarkTiming();
-        for (int i = 0; i < iters; i++) {
+        while (state.KeepRunning()) {
             FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
                     SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
-                    nodes, sLightGeometry, nullptr);
+                    nodes, sLightGeometry, Caches::getInstance());
 
             BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
             frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
-            MicroBench::DoNotOptimize(&renderer);
+            benchmark::DoNotOptimize(&renderer);
         }
-        benchmark.StopBenchmarkTiming();
     });
 }
-
-BENCHMARK_NO_ARG(BM_FrameBuilder_listview_defer);
-void BM_FrameBuilder_listview_defer::Run(int iters) {
-    benchDeferScene(*this, iters, "listview");
-}
-
-BENCHMARK_NO_ARG(BM_FrameBuilder_listview_deferAndRender);
-void BM_FrameBuilder_listview_deferAndRender::Run(int iters) {
-    benchDeferAndRenderScene(*this, iters, "listview");
-}
-
+BENCHMARK(BM_FrameBuilder_deferAndRender_scene)->DenseRange(0, SCENES.size() - 1);
diff --git a/libs/hwui/tests/microbench/LinearAllocatorBench.cpp b/libs/hwui/tests/microbench/LinearAllocatorBench.cpp
index 28513e4..3c0a6c5 100644
--- a/libs/hwui/tests/microbench/LinearAllocatorBench.cpp
+++ b/libs/hwui/tests/microbench/LinearAllocatorBench.cpp
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
 
-#include "tests/microbench/MicroBench.h"
 #include "utils/LinearAllocator.h"
 
 #include <vector>
@@ -24,30 +23,26 @@
 using namespace android;
 using namespace android::uirenderer;
 
-BENCHMARK_NO_ARG(BM_LinearStdAllocator_vectorBaseline);
-void BM_LinearStdAllocator_vectorBaseline::Run(int iters) {
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+static void BM_LinearStdAllocator_vectorBaseline(benchmark::State& state) {
+    while (state.KeepRunning()) {
         std::vector<char> v;
         for (int j = 0; j < 200; j++) {
             v.push_back(j);
         }
-        MicroBench::DoNotOptimize(&v);
+        benchmark::DoNotOptimize(&v);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_LinearStdAllocator_vectorBaseline);
 
-BENCHMARK_NO_ARG(BM_LinearStdAllocator_vector);
-void BM_LinearStdAllocator_vector::Run(int iters) {
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+static void BM_LinearStdAllocator_vector(benchmark::State& state) {
+    while (state.KeepRunning()) {
         LinearAllocator la;
         LinearStdAllocator<void*> stdAllocator(la);
         std::vector<char, LinearStdAllocator<char> > v(stdAllocator);
         for (int j = 0; j < 200; j++) {
             v.push_back(j);
         }
-        MicroBench::DoNotOptimize(&v);
+        benchmark::DoNotOptimize(&v);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_LinearStdAllocator_vector);
diff --git a/libs/hwui/tests/microbench/MicroBench.h b/libs/hwui/tests/microbench/MicroBench.h
deleted file mode 100644
index f05e92c..0000000
--- a/libs/hwui/tests/microbench/MicroBench.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef MICROBENCH_MICROBENCH_H
-#define MICROBENCH_MICROBENCH_H
-
-namespace android {
-namespace uirenderer {
-
-#define NO_INLINE __attribute__ ((noinline))
-
-class MicroBench {
-public:
-    template <class Tp>
-    static inline void DoNotOptimize(Tp const& value) {
-        asm volatile("" : "+rm" (const_cast<Tp&>(value)));
-    }
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* MICROBENCH_MICROBENCH_H */
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index bd742c6..4186539 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
 
 #include "PathParser.h"
 #include "VectorDrawable.h"
@@ -26,26 +26,26 @@
 
 static const char* sPathString = "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10";
 
-BENCHMARK_NO_ARG(BM_PathParser_parseStringPathForSkPath);
-void BM_PathParser_parseStringPathForSkPath::Run(int iter) {
+void BM_PathParser_parseStringPathForSkPath(benchmark::State& state) {
     SkPath skPath;
     size_t length = strlen(sPathString);
     PathParser::ParseResult result;
-    StartBenchmarkTiming();
-    for (int i = 0; i < iter; i++) {
+    while (state.KeepRunning()) {
         PathParser::parseStringForSkPath(&skPath, &result, sPathString, length);
+        benchmark::DoNotOptimize(&result);
+        benchmark::DoNotOptimize(&skPath);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_PathParser_parseStringPathForSkPath);
 
-BENCHMARK_NO_ARG(BM_PathParser_parseStringPathForPathData);
-void BM_PathParser_parseStringPathForPathData::Run(int iter) {
+void BM_PathParser_parseStringPathForPathData(benchmark::State& state) {
     size_t length = strlen(sPathString);
     PathData outData;
     PathParser::ParseResult result;
-    StartBenchmarkTiming();
-    for (int i = 0; i < iter; i++) {
+    while (state.KeepRunning()) {
         PathParser::getPathDataFromString(&outData, &result, sPathString, length);
+        benchmark::DoNotOptimize(&result);
+        benchmark::DoNotOptimize(&outData);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_PathParser_parseStringPathForPathData);
diff --git a/libs/hwui/tests/microbench/ShadowBench.cpp b/libs/hwui/tests/microbench/ShadowBench.cpp
index 98ec4d9..a0fc6e8 100644
--- a/libs/hwui/tests/microbench/ShadowBench.cpp
+++ b/libs/hwui/tests/microbench/ShadowBench.cpp
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
 
 #include "Matrix.h"
 #include "Rect.h"
 #include "Vector.h"
 #include "VertexBuffer.h"
 #include "TessellationCache.h"
-#include "tests/microbench/MicroBench.h"
 
 #include <SkPath.h>
 
@@ -78,39 +77,35 @@
             testData.lightRadius, *ambient, *spot);
 }
 
-BENCHMARK_NO_ARG(BM_TessellateShadows_roundrect_opaque);
-void BM_TessellateShadows_roundrect_opaque::Run(int iters) {
+void BM_TessellateShadows_roundrect_opaque(benchmark::State& state) {
     ShadowTestData shadowData;
     createShadowTestData(&shadowData);
     SkPath path;
     path.addRoundRect(SkRect::MakeWH(100, 100), 5, 5);
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+    while (state.KeepRunning()) {
         VertexBuffer ambient;
         VertexBuffer spot;
         tessellateShadows(shadowData, true, path, &ambient, &spot);
-        MicroBench::DoNotOptimize(&ambient);
-        MicroBench::DoNotOptimize(&spot);
+        benchmark::DoNotOptimize(&ambient);
+        benchmark::DoNotOptimize(&spot);
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_TessellateShadows_roundrect_opaque);
 
-BENCHMARK_NO_ARG(BM_TessellateShadows_roundrect_translucent);
-void BM_TessellateShadows_roundrect_translucent::Run(int iters) {
+void BM_TessellateShadows_roundrect_translucent(benchmark::State& state) {
     ShadowTestData shadowData;
     createShadowTestData(&shadowData);
     SkPath path;
     path.reset();
     path.addRoundRect(SkRect::MakeLTRB(0, 0, 100, 100), 5, 5);
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+    while (state.KeepRunning()) {
         std::unique_ptr<VertexBuffer> ambient(new VertexBuffer);
         std::unique_ptr<VertexBuffer> spot(new VertexBuffer);
         tessellateShadows(shadowData, false, path, ambient.get(), spot.get());
-        MicroBench::DoNotOptimize(ambient.get());
-        MicroBench::DoNotOptimize(spot.get());
+        benchmark::DoNotOptimize(ambient.get());
+        benchmark::DoNotOptimize(spot.get());
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_TessellateShadows_roundrect_translucent);
diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp
index 0ea30e47..c6b9f3b 100644
--- a/libs/hwui/tests/microbench/TaskManagerBench.cpp
+++ b/libs/hwui/tests/microbench/TaskManagerBench.cpp
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
 
 #include "thread/Task.h"
 #include "thread/TaskManager.h"
 #include "thread/TaskProcessor.h"
-#include "tests/microbench/MicroBench.h"
 
 #include <vector>
 
@@ -39,55 +38,51 @@
     }
 };
 
-BENCHMARK_NO_ARG(BM_TaskManager_allocateTask);
-void BM_TaskManager_allocateTask::Run(int iters) {
+void BM_TaskManager_allocateTask(benchmark::State& state) {
     std::vector<sp<TrivialTask> > tasks;
-    tasks.reserve(iters);
+    tasks.reserve(state.max_iterations);
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+    while (state.KeepRunning()) {
         tasks.emplace_back(new TrivialTask);
-        MicroBench::DoNotOptimize(tasks.back());
+        benchmark::DoNotOptimize(tasks.back());
     }
-    StopBenchmarkTiming();
 }
+BENCHMARK(BM_TaskManager_allocateTask);
 
-BENCHMARK_NO_ARG(BM_TaskManager_enqueueTask);
-void BM_TaskManager_enqueueTask::Run(int iters) {
+void BM_TaskManager_enqueueTask(benchmark::State& state) {
     TaskManager taskManager;
     sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
     std::vector<sp<TrivialTask> > tasks;
-    tasks.reserve(iters);
+    tasks.reserve(state.max_iterations);
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+    while (state.KeepRunning()) {
         tasks.emplace_back(new TrivialTask);
-        MicroBench::DoNotOptimize(tasks.back());
+        benchmark::DoNotOptimize(tasks.back());
         processor->add(tasks.back());
     }
-    StopBenchmarkTiming();
 
     for (sp<TrivialTask>& task : tasks) {
         task->getResult();
     }
 }
+BENCHMARK(BM_TaskManager_enqueueTask);
 
-BENCHMARK_NO_ARG(BM_TaskManager_enqueueRunDeleteTask);
-void BM_TaskManager_enqueueRunDeleteTask::Run(int iters) {
+void BM_TaskManager_enqueueRunDeleteTask(benchmark::State& state) {
     TaskManager taskManager;
     sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
     std::vector<sp<TrivialTask> > tasks;
-    tasks.reserve(iters);
+    tasks.reserve(state.max_iterations);
 
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
+    while (state.KeepRunning()) {
         tasks.emplace_back(new TrivialTask);
-        MicroBench::DoNotOptimize(tasks.back());
+        benchmark::DoNotOptimize(tasks.back());
         processor->add(tasks.back());
     }
+    state.ResumeTiming();
     for (sp<TrivialTask>& task : tasks) {
-        MicroBench::DoNotOptimize(task->getResult());
+        benchmark::DoNotOptimize(task->getResult());
     }
     tasks.clear();
-    StopBenchmarkTiming();
+    state.PauseTiming();
 }
+BENCHMARK(BM_TaskManager_enqueueRunDeleteTask);
diff --git a/libs/hwui/tests/microbench/main.cpp b/libs/hwui/tests/microbench/main.cpp
new file mode 100644
index 0000000..a0157bc
--- /dev/null
+++ b/libs/hwui/tests/microbench/main.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <benchmark/benchmark.h>
+
+BENCHMARK_MAIN();
diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh
index 09d4869..0572ee55 100755
--- a/libs/hwui/tests/scripts/prep_volantis.sh
+++ b/libs/hwui/tests/scripts/prep_volantis.sh
@@ -49,6 +49,6 @@
 # 684000 708000 756000 804000 852000 (kHz)
 
 S=324000000
-echo "set gpu to $s hz"
+echo "set gpu to $S hz"
 adb shell "echo 1 > /d/clock/override.gbus/state"
 adb shell "echo $S > /d/clock/override.gbus/rate"
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
new file mode 100644
index 0000000..5471486
--- /dev/null
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <RecordedOp.h>
+#include <BakedOpDispatcher.h>
+#include <BakedOpRenderer.h>
+#include <tests/common/TestUtils.h>
+
+using namespace android::uirenderer;
+
+static BakedOpRenderer::LightInfo sLightInfo;
+static Rect sBaseClip(100, 100);
+
+class ValidatingBakedOpRenderer : public BakedOpRenderer {
+public:
+    ValidatingBakedOpRenderer(RenderState& renderState, std::function<void(const Glop& glop)> validator)
+            : BakedOpRenderer(Caches::getInstance(), renderState, true, sLightInfo)
+            , mValidator(validator) {
+        mGlopReceiver = ValidatingGlopReceiver;
+    }
+private:
+    static void ValidatingGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
+            const ClipBase* clip, const Glop& glop) {
+
+        auto vbor = reinterpret_cast<ValidatingBakedOpRenderer*>(&renderer);
+        vbor->mValidator(glop);
+    }
+    std::function<void(const Glop& glop)> mValidator;
+};
+
+typedef void (*BakedOpReceiver)(BakedOpRenderer&, const BakedOpState&);
+
+static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op,
+        std::function<void(const Glop& glop)> glopVerifier) {
+    // Create op, and wrap with basic state.
+    LinearAllocator allocator;
+    auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), sBaseClip);
+    auto state = BakedOpState::tryConstruct(allocator, *snapshot, *op);
+    ASSERT_NE(nullptr, state);
+
+    int glopCount = 0;
+    auto glopReceiver = [&glopVerifier, &glopCount] (const Glop& glop) {
+        ASSERT_EQ(glopCount++, 0) << "Only one Glop expected";
+        glopVerifier(glop);
+    };
+    ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
+
+    // Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior
+#define X(Type) \
+        [](BakedOpRenderer& renderer, const BakedOpState& state) { \
+            BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \
+        },
+    static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
+#undef X
+    unmergedReceivers[op->opId](renderer, *state);
+    ASSERT_EQ(1, glopCount) << "Exactly one Glop expected";
+}
+
+RENDERTHREAD_TEST(BakedOpDispatcher, onArc_position) {
+    SkPaint strokePaint;
+    strokePaint.setStyle(SkPaint::kStroke_Style);
+    strokePaint.setStrokeWidth(4);
+    ArcOp op(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint, 0, 270, true);
+    testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
+        // validate glop produced by renderPathTexture (so texture, unit quad)
+        auto texture = glop.fill.texture.texture;
+        ASSERT_NE(nullptr, texture);
+        float expectedOffset = floor(4 * 1.5f + 0.5f);
+        EXPECT_EQ(expectedOffset, reinterpret_cast<PathTexture*>(texture)->offset)
+                << "Should see conservative offset from PathCache::computeBounds";
+        Rect expectedBounds(10, 15, 20, 25);
+        expectedBounds.outset(expectedOffset);
+#if !HWUI_NEW_OPS
+        EXPECT_EQ(expectedBounds, glop.bounds) << "bounds outset by stroke 'offset'";
+#endif
+        Matrix4 expectedModelView;
+        expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0);
+        expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1);
+        EXPECT_EQ(expectedModelView, glop.transform.modelView)
+                << "X and Y offsets, and scale both applied to model view";
+    });
+}
+
+RENDERTHREAD_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
+    SkPaint layerPaint;
+    layerPaint.setAlpha(128);
+    OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
+    LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer);
+    testUnmergedGlopDispatch(renderThread, &op, [&renderThread] (const Glop& glop) {
+        // rect glop is dispatched with paint props applied
+        EXPECT_EQ(renderThread.renderState().meshState().getUnitQuadVBO(),
+                glop.mesh.vertices.bufferObject) << "Unit quad should be drawn";
+        EXPECT_EQ(nullptr, glop.fill.texture.texture) << "Should be no texture when layer is null";
+        EXPECT_FLOAT_EQ(128 / 255.0f, glop.fill.color.a) << "Rect quad should use op alpha";
+    });
+}
diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
new file mode 100644
index 0000000..59bd75e
--- /dev/null
+++ b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <BakedOpRenderer.h>
+#include <tests/common/TestUtils.h>
+
+using namespace android::uirenderer;
+
+const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+
+RENDERTHREAD_TEST(BakedOpRenderer, startRepaintLayer_clear) {
+    BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(), true, sLightInfo);
+    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200u, 200u);
+
+    layer.dirty(Rect(200, 200));
+    {
+        renderer.startRepaintLayer(&layer, Rect(200, 200));
+        EXPECT_TRUE(layer.region.isEmpty()) << "Repaint full layer should clear region";
+        renderer.endLayer();
+    }
+
+    layer.dirty(Rect(200, 200));
+    {
+        renderer.startRepaintLayer(&layer, Rect(100, 200)); // repainting left side
+        EXPECT_TRUE(layer.region.isRect());
+        //ALOGD("bounds %d %d %d %d", RECT_ARGS(layer.region.getBounds()));
+        EXPECT_EQ(android::Rect(100, 0, 200, 200), layer.region.getBounds())
+                << "Left side being repainted, so right side should be clear";
+        renderer.endLayer();
+    }
+
+    // right side is now only dirty portion
+    {
+        renderer.startRepaintLayer(&layer, Rect(100, 0, 200, 200)); // repainting right side
+        EXPECT_TRUE(layer.region.isEmpty())
+                << "Now right side being repainted, so region should be entirely clear";
+        renderer.endLayer();
+    }
+}
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
index 68d74ee..0afabd8 100644
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ b/libs/hwui/tests/unit/CanvasStateTests.cpp
@@ -16,9 +16,9 @@
 
 #include "CanvasState.h"
 
-#include "Canvas.h"
 #include "Matrix.h"
 #include "Rect.h"
+#include "hwui/Canvas.h"
 #include "utils/LinearAllocator.h"
 
 #include <gtest/gtest.h>
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index 679569e..822d04f 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -27,7 +27,7 @@
 namespace android {
 namespace uirenderer {
 
-static Rect kViewportBounds(0, 0, 2048, 2048);
+static Rect kViewportBounds(2048, 2048);
 
 static ClipArea createClipArea() {
     ClipArea area;
@@ -140,17 +140,15 @@
 
     // rect list
     Matrix4 rotate;
-    rotate.loadRotate(2.0f);
-    area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+    rotate.loadRotate(5.0f);
+    area.clipRectWithTransform(Rect(50, 50, 150, 150), &rotate, SkRegion::kIntersect_Op);
     {
         auto serializedClip = area.serializeClip(allocator);
         ASSERT_NE(nullptr, serializedClip);
         ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
         auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
         EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
-        EXPECT_FALSE(clipRectList->rect.isEmpty());
-        EXPECT_FLOAT_EQ(199.87817f, clipRectList->rect.right)
-            << "Right side should be clipped by rotated rect";
+        EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect);
         EXPECT_EQ(serializedClip, area.serializeClip(allocator))
                 << "Requery of clip on unmodified ClipArea must return same pointer.";
     }
@@ -228,6 +226,7 @@
 
         ClipRegion recordedClip;
         recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
+        recordedClip.rect = Rect(200, 200);
 
         Matrix4 translate10x20;
         translate10x20.loadTranslate(10, 20, 0);
@@ -240,5 +239,28 @@
     }
 }
 
+TEST(ClipArea, serializeIntersectedClip_snap) {
+    ClipArea area(createClipArea());
+    area.setClip(100.2, 100.4, 500.6, 500.8);
+    LinearAllocator allocator;
+
+    {
+        // no recorded clip case
+        auto resolvedClip = area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity());
+        EXPECT_EQ(Rect(100, 100, 501, 501), resolvedClip->rect);
+    }
+    {
+        // recorded clip case
+        ClipRect recordedClip(Rect(100.12, 100.74));
+        Matrix4 translateScale;
+        translateScale.loadTranslate(100, 100, 0);
+        translateScale.scale(2, 3, 1); // recorded clip will have non-int coords, even after transform
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
+        ASSERT_NE(nullptr, resolvedClip);
+        EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode);
+        EXPECT_EQ(Rect(100, 100, 300, 402), resolvedClip->rect);
+    }
+}
+
 } // namespace uirenderer
 } // namespace android
diff --git a/libs/hwui/tests/unit/CrashHandlerInjector.cpp b/libs/hwui/tests/unit/CrashHandlerInjector.cpp
deleted file mode 100644
index b1c678d..0000000
--- a/libs/hwui/tests/unit/CrashHandlerInjector.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "tests/common/TestUtils.h"
-
-#include <gtest/gtest.h>
-#include <cstdio>
-
-using namespace android::uirenderer;
-
-static void gunitCrashHandler() {
-    auto testinfo = ::testing::UnitTest::GetInstance()->current_test_info();
-    printf("[  FAILED  ] %s.%s\n", testinfo->test_case_name(),
-            testinfo->name());
-    printf("[  FATAL!  ] RenderThread crashed, aborting tests!\n");
-    fflush(stdout);
-}
-
-static void hookError() {
-    TestUtils::setRenderThreadCrashHandler(gunitCrashHandler);
-}
-
-class HookErrorInit {
-public:
-    HookErrorInit() { hookError(); }
-};
-
-static HookErrorInit sInit;
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index f49dd3f..0ea246f 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -30,6 +30,7 @@
 namespace uirenderer {
 
 const LayerUpdateQueue sEmptyLayerUpdateQueue;
+const std::vector< sp<RenderNode> > sEmptyNodeList;
 const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
 
 
@@ -48,9 +49,12 @@
 public:
     virtual ~TestRendererBase() {}
     virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
-        ADD_FAILURE() << "Layer creation not expected in this test";
+        ADD_FAILURE() << "Temporary layers not expected in this test";
         return nullptr;
     }
+    virtual void recycleTemporaryLayer(OffscreenBuffer*) {
+        ADD_FAILURE() << "Temporary layers not expected in this test";
+    }
     virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
         ADD_FAILURE() << "Layer repaint not expected in this test";
     }
@@ -107,7 +111,7 @@
 
 class FailRenderer : public TestRendererBase {};
 
-TEST(FrameBuilder, simple) {
+RENDERTHREAD_TEST(FrameBuilder, simple) {
     class SimpleTestRenderer : public TestRendererBase {
     public:
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -133,13 +137,13 @@
         canvas.drawBitmap(bitmap, 10, 10, nullptr);
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
 }
 
-TEST(FrameBuilder, simpleStroke) {
+RENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
     class SimpleStrokeTestRenderer : public TestRendererBase {
     public:
         void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
@@ -159,13 +163,13 @@
         canvas.drawPoint(50, 50, strokedPaint);
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SimpleStrokeTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-TEST(FrameBuilder, simpleRejection) {
+RENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
     auto node = TestUtils::createNode(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
@@ -174,13 +178,13 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
 
     FailRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-TEST(FrameBuilder, simpleBatching) {
+RENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
     const int LOOPS = 5;
     class SimpleBatchingTestRenderer : public TestRendererBase {
     public:
@@ -209,15 +213,130 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SimpleBatchingTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2 * LOOPS, renderer.getIndex())
             << "Expect number of ops = 2 * loop count";
 }
 
-// TODO: Disabled due to b/26793764
-TEST(FrameBuilder, DISABLED_clippedMerging) {
+RENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
+    class EmptyNoFbo0TestRenderer : public TestRendererBase {
+    public:
+        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+            ADD_FAILURE() << "Primary frame draw not expected in this test";
+        }
+        void endFrame(const Rect& repaintRect) override {
+            ADD_FAILURE() << "Primary frame draw not expected in this test";
+        }
+    };
+
+    // Pass empty node list, so no work is enqueued for Fbo0
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            sEmptyNodeList, sLightGeometry, Caches::getInstance());
+    EmptyNoFbo0TestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
+RENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
+    class EmptyWithFbo0TestRenderer : public TestRendererBase {
+    public:
+        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+            EXPECT_EQ(0, mIndex++);
+        }
+        void endFrame(const Rect& repaintRect) override {
+            EXPECT_EQ(1, mIndex++);
+        }
+    };
+    auto node = TestUtils::createNode(10, 10, 110, 110,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        // no drawn content
+    });
+    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
+
+    // Draw, but pass empty node list, so no work is done for primary frame
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            syncedNodeList, sLightGeometry, Caches::getInstance());
+    EmptyWithFbo0TestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
+            " but fbo0 update lifecycle should still be observed";
+}
+
+RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
+    class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
+    public:
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(mIndex++, 0) << "Should be one rect";
+            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds)
+                    << "Last rect should occlude others.";
+        }
+    };
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.drawRect(0, 0, 200, 200, SkPaint());
+        canvas.drawRect(0, 0, 200, 200, SkPaint());
+        canvas.drawRect(10, 10, 190, 190, SkPaint());
+    });
+
+    // Damage (and therefore clip) is same as last draw, subset of renderable area.
+    // This means last op occludes other contents, and they'll be rejected to avoid overdraw.
+    SkRect damageRect = SkRect::MakeLTRB(10, 10, 190, 190);
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, damageRect, 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+    EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
+            << "Recording must not have rejected ops, in order for this test to be valid";
+
+    AvoidOverdrawRectsTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
+}
+
+RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
+    static SkBitmap opaqueBitmap = TestUtils::createSkBitmap(50, 50,
+            SkColorType::kRGB_565_SkColorType);
+    static SkBitmap transpBitmap = TestUtils::createSkBitmap(50, 50,
+            SkColorType::kAlpha_8_SkColorType);
+    class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
+    public:
+        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+            switch(mIndex++) {
+            case 0:
+                EXPECT_EQ(opaqueBitmap.pixelRef(), op.bitmap->pixelRef());
+                break;
+            case 1:
+                EXPECT_EQ(transpBitmap.pixelRef(), op.bitmap->pixelRef());
+                break;
+            default:
+                ADD_FAILURE() << "Only two ops expected.";
+            }
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 50, 50,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.drawRect(0, 0, 50, 50, SkPaint());
+        canvas.drawRect(0, 0, 50, 50, SkPaint());
+        canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
+
+        // only the below draws should remain, since they're
+        canvas.drawBitmap(opaqueBitmap, 0, 0, nullptr);
+        canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(50, 50), 50, 50,
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+    EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
+            << "Recording must not have rejected ops, in order for this test to be valid";
+
+    AvoidOverdrawBitmapsTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
+}
+
+RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
     class ClippedMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedBitmapOps(const MergedBakedOpList& opList) override {
@@ -251,13 +370,13 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     ClippedMergingTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, textMerging) {
+RENDERTHREAD_TEST(FrameBuilder, textMerging) {
     class TextMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedTextOps(const MergedBakedOpList& opList) override {
@@ -275,17 +394,17 @@
         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         paint.setAntiAlias(true);
         paint.setTextSize(50);
-        TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
-        TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
+        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
+        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     TextMergingTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
 }
 
-TEST(FrameBuilder, textStrikethrough) {
+RENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
     const int LOOPS = 5;
     class TextStrikethroughTestRenderer : public TestRendererBase {
     public:
@@ -306,19 +425,75 @@
         textPaint.setStrikeThruText(true);
         textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         for (int i = 0; i < LOOPS; i++) {
-            TestUtils::drawTextToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
+            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
         }
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     TextStrikethroughTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2 * LOOPS, renderer.getIndex())
             << "Expect number of ops = 2 * loop count";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
-    class TextureLayerTestRenderer : public TestRendererBase {
+static auto styles = {
+        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
+
+RENDERTHREAD_TEST(FrameBuilder, textStyle) {
+    class TextStyleTestRenderer : public TestRendererBase {
+    public:
+        void onMergedTextOps(const MergedBakedOpList& opList) override {
+            ASSERT_EQ(0, mIndex);
+            ASSERT_EQ(3u, opList.count);
+            mIndex += opList.count;
+
+            int index = 0;
+            for (auto style : styles) {
+                auto state = opList.states[index++];
+                ASSERT_EQ(style, state->op->paint->getStyle())
+                        << "Remainder of validation relies upon stable merged order";
+                ASSERT_EQ(0, state->computedState.clipSideFlags)
+                        << "Clipped bounds validation requires unclipped ops";
+            }
+
+            Rect fill = opList.states[0]->computedState.clippedBounds;
+            Rect stroke = opList.states[1]->computedState.clippedBounds;
+            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
+                    << "Stroke+Fill should be same as stroke";
+
+            EXPECT_TRUE(stroke.contains(fill));
+            EXPECT_FALSE(fill.contains(stroke));
+
+            // outset by half the stroke width
+            Rect outsetFill(fill);
+            outsetFill.outset(5);
+            EXPECT_EQ(stroke, outsetFill);
+        }
+    };
+    auto node = TestUtils::createNode(0, 0, 400, 400,
+            [](RenderProperties& props, TestCanvas& canvas) {
+        SkPaint paint;
+        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        paint.setAntiAlias(true);
+        paint.setTextSize(50);
+        paint.setStrokeWidth(10);
+
+        // draw 3 copies of the same text overlapping, each with a different style.
+        // They'll get merged, but with
+        for (auto style : styles) {
+            paint.setStyle(style);
+            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
+        }
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+    TextStyleTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
+}
+
+RENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
+    class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
     public:
         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(0, mIndex++);
@@ -332,9 +507,7 @@
     };
 
     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
-            [](Matrix4* transform) {
-        transform->loadTranslate(5, 5, 0);
-    });
+            SkMatrix::MakeTrans(5, 5));
 
     auto node = TestUtils::createNode(0, 0, 200, 200,
             [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
@@ -344,12 +517,105 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
-    TextureLayerTestRenderer renderer;
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+    TextureLayerClipLocalMatrixTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(1, renderer.getIndex());
 }
 
+RENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
+    class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
+    public:
+        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+
+            Matrix4 expected;
+            expected.loadTranslate(35, 45, 0);
+            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
+        }
+    };
+
+    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+            SkMatrix::MakeTrans(5, 5));
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.translate(30, 40);
+        canvas.drawLayer(layerUpdater.get());
+        canvas.restore();
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+    TextureLayerCombineMatricesTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex());
+}
+
+RENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
+    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+            SkMatrix::MakeTrans(5, 5));
+    layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.drawLayer(layerUpdater.get());
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+    FailRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
+RENDERTHREAD_TEST(FrameBuilder, functor_reject) {
+    class FunctorTestRenderer : public TestRendererBase {
+    public:
+        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+        }
+    };
+    Functor noopFunctor;
+
+    // 1 million pixel tall view, scrolled down 80%
+    auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
+            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.translate(0, -800000);
+        canvas.callDrawGLFunction(&noopFunctor);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(scrolledFunctorView),
+            sLightGeometry, Caches::getInstance());
+    FunctorTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
+}
+
+RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
+    class ColorTestRenderer : public TestRendererBase {
+    public:
+        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
+                    << "Color op should be expanded to bounds of surrounding";
+        }
+    };
+
+    auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        props.setClipToBounds(false);
+        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(unclippedColorView),
+            sLightGeometry, Caches::getInstance());
+    ColorTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
+}
+
 TEST(FrameBuilder, renderNode) {
     class RenderNodeTestRenderer : public TestRendererBase {
     public:
@@ -389,12 +655,13 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
     RenderNodeTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2, renderer.getIndex());
 }
 
-TEST(FrameBuilder, clipped) {
+RENDERTHREAD_TEST(FrameBuilder, clipped) {
     class ClippedTestRenderer : public TestRendererBase {
     public:
         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
@@ -413,12 +680,12 @@
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
             SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
-            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     ClippedTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-TEST(FrameBuilder, saveLayer_simple) {
+RENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
     class SaveLayerSimpleTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -446,6 +713,10 @@
             EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
             EXPECT_TRUE(state.computedState.transform.isIdentity());
         }
+        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+            EXPECT_EQ(4, mIndex++);
+            EXPECT_EQ(nullptr, offscreenBuffer);
+        }
     };
 
     auto node = TestUtils::createNode(0, 0, 200, 200,
@@ -455,13 +726,13 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SaveLayerSimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(4, renderer.getIndex());
+    EXPECT_EQ(5, renderer.getIndex());
 }
 
-TEST(FrameBuilder, saveLayer_nested) {
+RENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
     /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
      * - startTemporaryLayer2, rect2 endLayer2
      * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
@@ -510,6 +781,15 @@
                 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
             } else { ADD_FAILURE(); }
         }
+        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+            const int index = mIndex++;
+            // order isn't important, but we need to see both
+            if (index == 10) {
+                EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
+            } else if (index == 11) {
+                EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
+            } else { ADD_FAILURE(); }
+        }
     };
 
     auto node = TestUtils::createNode(0, 0, 800, 800,
@@ -527,13 +807,13 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SaveLayerNestedTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(10, renderer.getIndex());
+    EXPECT_EQ(12, renderer.getIndex());
 }
 
-TEST(FrameBuilder, saveLayer_contentRejection) {
+RENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
         auto node = TestUtils::createNode(0, 0, 200, 200,
                 [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
@@ -547,14 +827,14 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
 
     FailRenderer renderer;
     // should see no ops, even within the layer, since the layer should be rejected
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-TEST(FrameBuilder, saveLayerUnclipped_simple) {
+RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
     class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -590,13 +870,13 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SaveLayerUnclippedSimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
+RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
     class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -644,18 +924,74 @@
         canvas.restoreToCount(restoreTo);
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SaveLayerUnclippedMergedClearsTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(10, renderer.getIndex())
             << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
 }
 
+RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
+    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
+    public:
+        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+        }
+        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            ASSERT_NE(nullptr, op.paint);
+            EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
+            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
+                    << "Expect dirty rect as clip";
+            ASSERT_NE(nullptr, state.computedState.clipState);
+            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
+            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        // save smaller than clip, so we get unclipped behavior
+        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+        canvas.drawRect(0, 0, 200, 200, SkPaint());
+        canvas.restore();
+    });
+
+    // draw with partial screen dirty, and assert we see that rect later
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+    SaveLayerUnclippedClearClipTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex());
+}
+
+RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        // unclipped savelayer + rect both in area that won't intersect with dirty
+        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
+        canvas.drawRect(100, 100, 200, 200, SkPaint());
+        canvas.restore();
+    });
+
+    // draw with partial screen dirty that doesn't intersect with savelayer
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+    FailRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
 /* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
  * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
  * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
  */
-TEST(FrameBuilder, saveLayerUnclipped_complex) {
+RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
     class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
@@ -689,10 +1025,15 @@
         }
         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(9, mIndex++);
+            EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
         }
         void endFrame(const Rect& repaintRect) override {
             EXPECT_EQ(11, mIndex++);
         }
+        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+            EXPECT_EQ(12, mIndex++);
+            EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
+        }
     };
 
     auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
@@ -706,10 +1047,10 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     SaveLayerUnclippedComplexTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(12, renderer.getIndex());
+    EXPECT_EQ(13, renderer.getIndex());
 }
 
 RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
@@ -764,7 +1105,7 @@
     layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
 
     FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedNodeList, sLightGeometry, nullptr);
+            syncedNodeList, sLightGeometry, Caches::getInstance());
     HwLayerSimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(6, renderer.getIndex());
@@ -831,6 +1172,9 @@
         void endFrame(const Rect& repaintRect) override {
             EXPECT_EQ(12, mIndex++);
         }
+        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+            EXPECT_EQ(13, mIndex++);
+        }
     };
 
     auto child = TestUtils::createNode(50, 50, 150, 150,
@@ -865,16 +1209,74 @@
     layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
 
     FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedList, sLightGeometry, nullptr);
+            syncedList, sLightGeometry, Caches::getInstance());
     HwLayerComplexTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(13, renderer.getIndex());
+    EXPECT_EQ(14, renderer.getIndex());
 
     // clean up layer pointers, so we can safely destruct RenderNodes
     *(child->getLayerHandle()) = nullptr;
     *(parent->getLayerHandle()) = nullptr;
 }
 
+
+RENDERTHREAD_TEST(FrameBuilder, buildLayer) {
+    class BuildLayerTestRenderer : public TestRendererBase {
+    public:
+        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
+            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
+            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
+        }
+        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+
+            EXPECT_TRUE(state.computedState.transform.isIdentity())
+                    << "Transform should be reset within layer";
+
+            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
+                    << "Damage rect should be used to clip layer content";
+        }
+        void endLayer() override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+            ADD_FAILURE() << "Primary frame draw not expected in this test";
+        }
+        void endFrame(const Rect& repaintRect) override {
+            ADD_FAILURE() << "Primary frame draw not expected in this test";
+        }
+    };
+
+    auto node = TestUtils::createNode(10, 10, 110, 110,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        props.mutateLayerProperties().setType(LayerType::RenderLayer);
+        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
+    });
+    OffscreenBuffer** layerHandle = node->getLayerHandle();
+
+    // create RenderNode's layer here in same way prepareTree would
+    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
+    *layerHandle = &layer;
+
+    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
+
+    // only enqueue partial damage
+    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
+
+    // Draw, but pass empty node list, so no work is done for primary frame
+    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1,
+            sEmptyNodeList, sLightGeometry, Caches::getInstance());
+    BuildLayerTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(3, renderer.getIndex());
+
+    // clean up layer pointer, so we can safely destruct RenderNode
+    *layerHandle = nullptr;
+}
+
 static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
     SkPaint paint;
     paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
@@ -889,7 +1291,7 @@
     node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
     canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
 }
-TEST(FrameBuilder, zReorder) {
+RENDERTHREAD_TEST(FrameBuilder, zReorder) {
     class ZReorderTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -914,13 +1316,13 @@
         drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
     ZReorderTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(10, renderer.getIndex());
 };
 
-TEST(FrameBuilder, projectionReorder) {
+RENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
     static const int scrollX = 5;
     static const int scrollY = 10;
     class ProjectionReorderTestRenderer : public TestRendererBase {
@@ -934,21 +1336,26 @@
                 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
                 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
                 expectedMatrix.loadIdentity();
+                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
                 break;
             case 1:
                 EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
                 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
-                expectedMatrix.loadTranslate(50, 50, 0); // TODO: should scroll be respected here?
+                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
+                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+                EXPECT_EQ(Rect(-35, -30, 45, 50),
+                        Rect(state.computedState.localProjectionPathMask->getBounds()));
                 break;
             case 2:
                 EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
                 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
                 expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
+                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
                 break;
             default:
                 ADD_FAILURE();
             }
-            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
+            EXPECT_EQ(expectedMatrix, state.computedState.transform);
         }
     };
 
@@ -989,6 +1396,9 @@
     });
     auto parent = TestUtils::createNode(0, 0, 100, 100,
             [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+        // Set a rect outline for the projecting ripple to be masked against.
+        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
+
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
         canvas.drawRenderNode(receiverBackground.get());
@@ -997,12 +1407,151 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
     ProjectionReorderTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(3, renderer.getIndex());
 }
 
+RENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
+    static const int scrollX = 5;
+    static const int scrollY = 10;
+    class ProjectionHwLayerTestRenderer : public TestRendererBase {
+    public:
+        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
+            EXPECT_EQ(0, mIndex++);
+        }
+        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+        }
+        void endLayer() override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+        }
+        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(4, mIndex++);
+            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+            Matrix4 expected;
+            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
+            EXPECT_EQ(expected, state.computedState.transform);
+            EXPECT_EQ(Rect(-85, -80, 295, 300),
+                    Rect(state.computedState.localProjectionPathMask->getBounds()));
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(5, mIndex++);
+            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+        }
+    };
+    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setProjectionReceiver(true);
+        // scroll doesn't apply to background, so undone via translationX/Y
+        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
+        properties.setTranslationX(scrollX);
+        properties.setTranslationY(scrollY);
+
+        canvas.drawRect(0, 0, 400, 400, SkPaint());
+    });
+    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setProjectBackwards(true);
+        properties.setClipToBounds(false);
+        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+    });
+    auto child = TestUtils::createNode(100, 100, 300, 300,
+            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
+        canvas.drawRenderNode(projectingRipple.get());
+        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
+    });
+    auto parent = TestUtils::createNode(0, 0, 400, 400,
+            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+        // Set a rect outline for the projecting ripple to be masked against.
+        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
+        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
+        canvas.drawRenderNode(receiverBackground.get());
+        canvas.drawRenderNode(child.get());
+    });
+
+    OffscreenBuffer** layerHandle = child->getLayerHandle();
+
+    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
+    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
+    Matrix4 windowTransform;
+    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
+    layer.setWindowTransform(windowTransform);
+    *layerHandle = &layer;
+
+    auto syncedList = TestUtils::createSyncedNodeList(parent);
+    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
+    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+            syncedList, sLightGeometry, Caches::getInstance());
+    ProjectionHwLayerTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(6, renderer.getIndex());
+
+    // clean up layer pointer, so we can safely destruct RenderNode
+    *layerHandle = nullptr;
+}
+
+RENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
+    static const int scrollX = 500000;
+    static const int scrollY = 0;
+    class ProjectionChildScrollTestRenderer : public TestRendererBase {
+    public:
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            ASSERT_NE(nullptr, state.computedState.clipState);
+            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
+            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+    };
+    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setProjectionReceiver(true);
+        canvas.drawRect(0, 0, 400, 400, SkPaint());
+    });
+    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        // scroll doesn't apply to background, so undone via translationX/Y
+        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
+        properties.setTranslationX(scrollX);
+        properties.setTranslationY(scrollY);
+        properties.setProjectBackwards(true);
+        properties.setClipToBounds(false);
+        canvas.drawOval(0, 0, 200, 200, SkPaint());
+    });
+    auto child = TestUtils::createNode(0, 0, 400, 400,
+            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
+        // Record time clip will be ignored by projectee
+        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
+
+        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
+        canvas.drawRenderNode(projectingRipple.get());
+    });
+    auto parent = TestUtils::createNode(0, 0, 400, 400,
+            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+        canvas.drawRenderNode(receiverBackground.get());
+        canvas.drawRenderNode(child.get());
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
+    ProjectionChildScrollTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2, renderer.getIndex());
+}
+
 // creates a 100x100 shadow casting node with provided translationZ
 static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
     return TestUtils::createNode(0, 0, 100, 100,
@@ -1040,7 +1589,7 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(parent), sLightGeometry, &Caches::getInstance());
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
     ShadowTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2, renderer.getIndex());
@@ -1067,6 +1616,9 @@
         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(4, mIndex++);
         }
+        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+            EXPECT_EQ(5, mIndex++);
+        }
     };
 
     auto parent = TestUtils::createNode(0, 0, 200, 200,
@@ -1082,11 +1634,10 @@
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             TestUtils::createSyncedNodeList(parent),
-            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
-            &Caches::getInstance());
+            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
     ShadowSaveLayerTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(5, renderer.getIndex());
+    EXPECT_EQ(6, renderer.getIndex());
 }
 
 RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
@@ -1135,8 +1686,7 @@
     layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
     FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             syncedList,
-            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30},
-            &Caches::getInstance());
+            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
     ShadowHwLayerTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(5, renderer.getIndex());
@@ -1145,7 +1695,7 @@
     *layerHandle = nullptr;
 }
 
-TEST(FrameBuilder, shadowLayering) {
+RENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
     class ShadowLayeringTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -1166,8 +1716,7 @@
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             TestUtils::createSyncedNodeList(parent),
-            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
-            &Caches::getInstance());
+            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
     ShadowLayeringTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
@@ -1195,13 +1744,13 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
     PropertyTestRenderer renderer(opValidateCallback);
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
 }
 
-TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
     testProperty([](RenderProperties& properties) {
         properties.setAlpha(0.5f);
         properties.setHasOverlappingRendering(false);
@@ -1210,7 +1759,7 @@
     });
 }
 
-TEST(FrameBuilder, renderPropClipping) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
     testProperty([](RenderProperties& properties) {
         properties.setClipToBounds(true);
         properties.setClipBounds(Rect(10, 20, 300, 400));
@@ -1220,7 +1769,7 @@
     });
 }
 
-TEST(FrameBuilder, renderPropRevealClip) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableRevealClip().set(true, 50, 50, 25);
     }, [](const RectOp& op, const BakedOpState& state) {
@@ -1231,7 +1780,7 @@
     });
 }
 
-TEST(FrameBuilder, renderPropOutlineClip) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableOutline().setShouldClip(true);
         properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
@@ -1243,7 +1792,7 @@
     });
 }
 
-TEST(FrameBuilder, renderPropTransform) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
     testProperty([](RenderProperties& properties) {
         properties.setLeftTopRightBottom(10, 10, 110, 110);
 
@@ -1317,6 +1866,9 @@
         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(3, mIndex++);
         }
+        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
+            EXPECT_EQ(4, mIndex++);
+        }
     private:
         SaveLayerAlphaData* mOutData;
     };
@@ -1337,15 +1889,15 @@
     auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            nodes, sLightGeometry, nullptr);
+            nodes, sLightGeometry, Caches::getInstance());
     SaveLayerAlphaClipTestRenderer renderer(outObservedData);
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 
     // assert, since output won't be valid if we haven't seen a save layer triggered
-    ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
+    ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
 }
 
-TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         properties.setTranslationX(10); // offset rendering content
@@ -1361,7 +1913,7 @@
             << "expect content to be translated as part of being clipped";
 }
 
-TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         // Translate and rotate the view so that the only visible part is the top left corner of
@@ -1380,7 +1932,7 @@
     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
 }
 
-TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
+RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         properties.setPivotX(0);
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
new file mode 100644
index 0000000..95543d3
--- /dev/null
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "Glop.h"
+#include "GlopBuilder.h"
+#include "Rect.h"
+#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
+
+#include <SkPaint.h>
+
+using namespace android::uirenderer;
+
+static void expectFillEq(Glop::Fill& expectedFill, Glop::Fill& builtFill) {
+    EXPECT_EQ(expectedFill.colorEnabled, builtFill.colorEnabled);
+    if (expectedFill.colorEnabled)
+        EXPECT_EQ(expectedFill.color, builtFill.color);
+
+    EXPECT_EQ(expectedFill.filterMode, builtFill.filterMode);
+    if (expectedFill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
+        EXPECT_EQ(expectedFill.filter.color, builtFill.filter.color);
+    } else if (expectedFill.filterMode == ProgramDescription::ColorFilterMode::Matrix) {
+        Glop::Fill::Filter::Matrix& expectedMatrix = expectedFill.filter.matrix;
+        Glop::Fill::Filter::Matrix& builtMatrix = expectedFill.filter.matrix;
+        EXPECT_TRUE(std::memcmp(expectedMatrix.matrix, builtMatrix.matrix,
+                sizeof(Glop::Fill::Filter::Matrix::matrix)));
+        EXPECT_TRUE(std::memcmp(expectedMatrix.vector, builtMatrix.vector,
+                sizeof(Glop::Fill::Filter::Matrix::vector)));
+    }
+    EXPECT_EQ(expectedFill.skiaShaderData.skiaShaderType, builtFill.skiaShaderData.skiaShaderType);
+    EXPECT_EQ(expectedFill.texture.clamp, builtFill.texture.clamp);
+    EXPECT_EQ(expectedFill.texture.filter, builtFill.texture.filter);
+    EXPECT_EQ(expectedFill.texture.target, builtFill.texture.target);
+    EXPECT_EQ(expectedFill.texture.textureTransform, builtFill.texture.textureTransform);
+}
+
+static void expectBlendEq(Glop::Blend& expectedBlend, Glop::Blend& builtBlend) {
+    EXPECT_EQ(expectedBlend.src, builtBlend.src);
+    EXPECT_EQ(expectedBlend.dst, builtBlend.dst);
+}
+
+static void expectMeshEq(Glop::Mesh& expectedMesh, Glop::Mesh& builtMesh) {
+    EXPECT_EQ(expectedMesh.elementCount, builtMesh.elementCount);
+    EXPECT_EQ(expectedMesh.primitiveMode, builtMesh.primitiveMode);
+    EXPECT_EQ(expectedMesh.indices.indices, builtMesh.indices.indices);
+    EXPECT_EQ(expectedMesh.indices.bufferObject, builtMesh.indices.bufferObject);
+    EXPECT_EQ(expectedMesh.vertices.attribFlags, builtMesh.vertices.attribFlags);
+    EXPECT_EQ(expectedMesh.vertices.bufferObject, builtMesh.vertices.bufferObject);
+    EXPECT_EQ(expectedMesh.vertices.color, builtMesh.vertices.color);
+    EXPECT_EQ(expectedMesh.vertices.position, builtMesh.vertices.position);
+    EXPECT_EQ(expectedMesh.vertices.stride, builtMesh.vertices.stride);
+    EXPECT_EQ(expectedMesh.vertices.texCoord, builtMesh.vertices.texCoord);
+
+    if (builtMesh.vertices.position) {
+        for (int i = 0; i < 4; i++) {
+            TextureVertex& expectedVertex = expectedMesh.mappedVertices[i];
+            TextureVertex& builtVertex = builtMesh.mappedVertices[i];
+            EXPECT_EQ(expectedVertex.u, builtVertex.u);
+            EXPECT_EQ(expectedVertex.v, builtVertex.v);
+            EXPECT_EQ(expectedVertex.x, builtVertex.x);
+            EXPECT_EQ(expectedVertex.y, builtVertex.y);
+        }
+    }
+}
+
+static void expectTransformEq(Glop::Transform& expectedTransform, Glop::Transform& builtTransform) {
+    EXPECT_EQ(expectedTransform.canvas, builtTransform.canvas);
+    EXPECT_EQ(expectedTransform.modelView, builtTransform.modelView);
+    EXPECT_EQ(expectedTransform.transformFlags, expectedTransform.transformFlags);
+}
+
+static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) {
+#if !HWUI_NEW_OPS
+    EXPECT_EQ(expectedGlop.bounds, builtGlop.bounds);
+#endif
+    expectBlendEq(expectedGlop.blend, builtGlop.blend);
+    expectFillEq(expectedGlop.fill, builtGlop.fill);
+    expectMeshEq(expectedGlop.mesh, builtGlop.mesh);
+    expectTransformEq(expectedGlop.transform, builtGlop.transform);
+}
+
+static std::unique_ptr<Glop> blackUnitQuadGlop(RenderState& renderState) {
+    std::unique_ptr<Glop> glop(new Glop());
+    glop->blend = { GL_ZERO, GL_ZERO };
+    glop->mesh.elementCount = 4;
+    glop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    glop->mesh.indices.indices = nullptr;
+    glop->mesh.indices.bufferObject = GL_ZERO;
+    glop->mesh.vertices = {
+            renderState.meshState().getUnitQuadVBO(),
+            VertexAttribFlags::None,
+            nullptr, nullptr, nullptr,
+            kTextureVertexStride };
+    glop->transform.modelView.loadIdentity();
+    glop->fill.colorEnabled = true;
+    glop->fill.color.set(Color::Black);
+    glop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType;
+    glop->fill.filterMode = ProgramDescription::ColorFilterMode::None;
+    glop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+    return glop;
+}
+
+RENDERTHREAD_TEST(GlopBuilder, rectSnapTest) {
+    RenderState& renderState = renderThread.renderState();
+    Caches& caches = Caches::getInstance();
+    SkPaint paint;
+    Rect dest(1, 1, 100, 100);
+    Matrix4 simpleTranslate;
+    simpleTranslate.loadTranslate(0.7, 0.7, 0);
+    Glop glop;
+    GlopBuilder(renderState, caches, &glop)
+            .setRoundRectClipState(nullptr)
+            .setMeshUnitQuad()
+            .setFillPaint(paint, 1.0f)
+            .setTransform(simpleTranslate, TransformFlags::None)
+            .setModelViewMapUnitToRectSnap(dest)
+            .build();
+
+    std::unique_ptr<Glop> goldenGlop(blackUnitQuadGlop(renderState));
+    // Rect(1,1,100,100) is the set destination,
+    // so unit quad should be translated by (1,1) and scaled by (99, 99)
+    // Tricky part: because translate (0.7, 0.7) and snapping were set in glopBuilder,
+    // unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels.
+    goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0);
+    goldenGlop->transform.modelView.scale(99, 99, 1);
+#if !HWUI_NEW_OPS
+    goldenGlop->bounds = android::uirenderer::Rect(1.70, 1.70, 100.70, 100.70);
+#endif
+    goldenGlop->transform.canvas = simpleTranslate;
+    goldenGlop->fill.texture.filter = GL_NEAREST;
+    expectGlopEq(*goldenGlop, glop);
+}
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index da786c7..e2fc376 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -30,6 +30,25 @@
 const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
 const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
 
+RENDERTHREAD_TEST(LeakCheck, saveLayer_overdrawRejection) {
+    auto node = TestUtils::createNode(0, 0, 100, 100,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
+        canvas.drawRect(0, 0, 100, 100, SkPaint());
+        canvas.restore();
+
+        // opaque draw, rejects saveLayer beneath
+        canvas.drawRect(0, 0, 100, 100, SkPaint());
+    });
+    RenderState& renderState = renderThread.renderState();
+    Caches& caches = Caches::getInstance();
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+            TestUtils::createSyncedNodeList(node), sLightGeometery, Caches::getInstance());
+    BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
+    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+}
+
 RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
     auto node = TestUtils::createNode(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
@@ -41,7 +60,7 @@
     Caches& caches = Caches::getInstance();
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightGeometery, nullptr);
+            TestUtils::createSyncedNodeList(node), sLightGeometery, Caches::getInstance());
     BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
 }
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 402a09c..ffcbf12 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -113,3 +113,21 @@
     EXPECT_GT(lastLocation + 20, &v[0]);
 
 }
+
+TEST(LsaVector, dtorCheck) {
+    LinearAllocator allocator;
+    LinearStdAllocator<void*> stdAllocator(allocator);
+
+    for (int size : {1, 2, 3, 500}) {
+        int destroyed = 0;
+        {
+            LsaVector<std::unique_ptr<TestUtils::SignalingDtor> > vector(stdAllocator);
+            for (int i = 0; i < size; i++) {
+                vector.emplace_back(new TestUtils::SignalingDtor(&destroyed));
+            }
+            EXPECT_EQ(0, destroyed);
+            EXPECT_EQ(size, (int) vector.size());
+        }
+        EXPECT_EQ(size, destroyed);
+    }
+}
diff --git a/libs/hwui/tests/unit/MatrixTests.cpp b/libs/hwui/tests/unit/MatrixTests.cpp
new file mode 100644
index 0000000..eddab87
--- /dev/null
+++ b/libs/hwui/tests/unit/MatrixTests.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+
+using namespace android::uirenderer;
+
+TEST(Matrix, mapRect_emptyScaleSkew) {
+    // Skew, so we don't hit identity/translate/simple fast paths
+    Matrix4 scaleMatrix;
+    scaleMatrix.loadScale(10, 10, 1);
+    scaleMatrix.skew(0.1f, 0.1f);
+
+    // non-zero empty rect, so sorting x/y would make rect non-empty
+    Rect empty(15, 20, 15, 100);
+    ASSERT_TRUE(empty.isEmpty());
+    scaleMatrix.mapRect(empty);
+    EXPECT_EQ(Rect(170, 215, 250, 1015), empty);
+    EXPECT_FALSE(empty.isEmpty())
+        << "Empty 'line' rect doesn't remain empty when skewed.";
+}
+
+TEST(Matrix, mapRect_emptyRotate) {
+    // Skew, so we don't hit identity/translate/simple fast paths
+    Matrix4 skewMatrix;
+    skewMatrix.loadRotate(45);
+
+    // non-zero empty rect, so sorting x/y would make rect non-empty
+    Rect lineRect(0, 100);
+    ASSERT_TRUE(lineRect.isEmpty());
+    skewMatrix.mapRect(lineRect);
+    EXPECT_FALSE(lineRect.isEmpty())
+        << "Empty 'line' rect doesn't remain empty when rotated.";
+}
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 2fd8795..b7950aa 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -30,105 +30,126 @@
     EXPECT_EQ(1024u, OffscreenBuffer::computeIdealDimension(1000));
 }
 
-TEST(OffscreenBuffer, construct) {
-    TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
-        OffscreenBuffer layer(thread.renderState(), Caches::getInstance(), 49u, 149u);
-        EXPECT_EQ(49u, layer.viewportWidth);
-        EXPECT_EQ(149u, layer.viewportHeight);
+RENDERTHREAD_TEST(OffscreenBuffer, construct) {
+    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u);
+    EXPECT_EQ(49u, layer.viewportWidth);
+    EXPECT_EQ(149u, layer.viewportHeight);
 
-        EXPECT_EQ(64u, layer.texture.width());
-        EXPECT_EQ(192u, layer.texture.height());
+    EXPECT_EQ(64u, layer.texture.width());
+    EXPECT_EQ(192u, layer.texture.height());
 
-        EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
-    });
+    EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
 }
 
-TEST(OffscreenBuffer, getTextureCoordinates) {
-    TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
-        OffscreenBuffer layerAligned(thread.renderState(), Caches::getInstance(), 256u, 256u);
-        EXPECT_EQ(Rect(0, 1, 1, 0),
-                layerAligned.getTextureCoordinates());
+RENDERTHREAD_TEST(OffscreenBuffer, getTextureCoordinates) {
+    OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
+    EXPECT_EQ(Rect(0, 1, 1, 0),
+            layerAligned.getTextureCoordinates());
 
-        OffscreenBuffer layerUnaligned(thread.renderState(), Caches::getInstance(), 200u, 225u);
-        EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0),
-                layerUnaligned.getTextureCoordinates());
-    });
+    OffscreenBuffer layerUnaligned(renderThread.renderState(), Caches::getInstance(), 200u, 225u);
+    EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0),
+            layerUnaligned.getTextureCoordinates());
 }
 
-TEST(OffscreenBufferPool, construct) {
-    TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
-        OffscreenBufferPool pool;
-        EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty";
-        EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty";
-        EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize())
-                << "pool must read size from Properties";
-    });
+RENDERTHREAD_TEST(OffscreenBuffer, dirty) {
+    OffscreenBuffer buffer(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
+    buffer.dirty(Rect(-100, -100, 100, 100));
+    EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds());
 }
 
-TEST(OffscreenBufferPool, getPutClear) {
-    TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
-        OffscreenBufferPool pool;
-
-        auto layer = pool.get(thread.renderState(), 100u, 200u);
-        EXPECT_EQ(100u, layer->viewportWidth);
-        EXPECT_EQ(200u, layer->viewportHeight);
-
-        ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize());
-
-        pool.putOrDelete(layer);
-        ASSERT_EQ(layer->getSizeInBytes(), pool.getSize());
-
-        auto layer2 = pool.get(thread.renderState(), 102u, 202u);
-        EXPECT_EQ(layer, layer2) << "layer should be recycled";
-        ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer";
-
-        pool.putOrDelete(layer);
-        EXPECT_EQ(1u, pool.getCount());
-        pool.clear();
-        EXPECT_EQ(0u, pool.getSize());
-        EXPECT_EQ(0u, pool.getCount());
-    });
+RENDERTHREAD_TEST(OffscreenBufferPool, construct) {
+    OffscreenBufferPool pool;
+    EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty";
+    EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty";
+    EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize())
+            << "pool must read size from Properties";
 }
 
-TEST(OffscreenBufferPool, resize) {
-    TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
-        OffscreenBufferPool pool;
+RENDERTHREAD_TEST(OffscreenBufferPool, getPutClear) {
+    OffscreenBufferPool pool;
 
-        auto layer = pool.get(thread.renderState(), 64u, 64u);
+    auto layer = pool.get(renderThread.renderState(), 100u, 200u);
+    EXPECT_EQ(100u, layer->viewportWidth);
+    EXPECT_EQ(200u, layer->viewportHeight);
 
-        // resize in place
-        ASSERT_EQ(layer, pool.resize(layer, 60u, 55u));
-        EXPECT_EQ(60u, layer->viewportWidth);
-        EXPECT_EQ(55u, layer->viewportHeight);
-        EXPECT_EQ(64u, layer->texture.width());
-        EXPECT_EQ(64u, layer->texture.height());
+    ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize());
 
-        // resized to use different object in pool
-        auto layer2 = pool.get(thread.renderState(), 128u, 128u);
-        pool.putOrDelete(layer2);
-        ASSERT_EQ(1u, pool.getCount());
-        ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u));
-        EXPECT_EQ(120u, layer2->viewportWidth);
-        EXPECT_EQ(125u, layer2->viewportHeight);
-        EXPECT_EQ(128u, layer2->texture.width());
-        EXPECT_EQ(128u, layer2->texture.height());
+    pool.putOrDelete(layer);
+    ASSERT_EQ(layer->getSizeInBytes(), pool.getSize());
 
-        // original allocation now only thing in pool
-        EXPECT_EQ(1u, pool.getCount());
-        EXPECT_EQ(layer->getSizeInBytes(), pool.getSize());
+    auto layer2 = pool.get(renderThread.renderState(), 102u, 202u);
+    EXPECT_EQ(layer, layer2) << "layer should be recycled";
+    ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer";
 
-        pool.putOrDelete(layer2);
-    });
+    pool.putOrDelete(layer);
+    EXPECT_EQ(1u, pool.getCount());
+    pool.clear();
+    EXPECT_EQ(0u, pool.getSize());
+    EXPECT_EQ(0u, pool.getCount());
 }
 
-TEST(OffscreenBufferPool, putAndDestroy) {
-    TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
-        OffscreenBufferPool pool;
-        // layer too big to return to the pool
-        // Note: this relies on the fact that the pool won't reject based on max texture size
-        auto hugeLayer = pool.get(thread.renderState(), pool.getMaxSize() / 64, 64);
-        EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize());
-        pool.putOrDelete(hugeLayer);
-        EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
-    });
+RENDERTHREAD_TEST(OffscreenBufferPool, resize) {
+    OffscreenBufferPool pool;
+
+    auto layer = pool.get(renderThread.renderState(), 64u, 64u);
+    layer->dirty(Rect(64, 64));
+
+    // resize in place
+    ASSERT_EQ(layer, pool.resize(layer, 60u, 55u));
+    EXPECT_TRUE(layer->region.isEmpty()) << "In place resize should clear usage region";
+    EXPECT_EQ(60u, layer->viewportWidth);
+    EXPECT_EQ(55u, layer->viewportHeight);
+    EXPECT_EQ(64u, layer->texture.width());
+    EXPECT_EQ(64u, layer->texture.height());
+
+    // resized to use different object in pool
+    auto layer2 = pool.get(renderThread.renderState(), 128u, 128u);
+    layer2->dirty(Rect(128, 128));
+    EXPECT_FALSE(layer2->region.isEmpty());
+    pool.putOrDelete(layer2);
+    ASSERT_EQ(1u, pool.getCount());
+
+    ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u));
+    EXPECT_TRUE(layer2->region.isEmpty()) << "Swap resize should clear usage region";
+    EXPECT_EQ(120u, layer2->viewportWidth);
+    EXPECT_EQ(125u, layer2->viewportHeight);
+    EXPECT_EQ(128u, layer2->texture.width());
+    EXPECT_EQ(128u, layer2->texture.height());
+
+    // original allocation now only thing in pool
+    EXPECT_EQ(1u, pool.getCount());
+    EXPECT_EQ(layer->getSizeInBytes(), pool.getSize());
+
+    pool.putOrDelete(layer2);
+}
+
+RENDERTHREAD_TEST(OffscreenBufferPool, putAndDestroy) {
+    OffscreenBufferPool pool;
+    // layer too big to return to the pool
+    // Note: this relies on the fact that the pool won't reject based on max texture size
+    auto hugeLayer = pool.get(renderThread.renderState(), pool.getMaxSize() / 64, 64);
+    EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize());
+    pool.putOrDelete(hugeLayer);
+    EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
+}
+
+RENDERTHREAD_TEST(OffscreenBufferPool, clear) {
+    EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
+    OffscreenBufferPool pool;
+
+    // Create many buffers, with several at each size
+    std::vector<OffscreenBuffer*> buffers;
+    for (int size = 32; size <= 128; size += 32) {
+        for (int i = 0; i < 10; i++) {
+            buffers.push_back(pool.get(renderThread.renderState(), size, size));
+        }
+    }
+    EXPECT_EQ(0u, pool.getCount()) << "Expect nothing inside";
+    for (auto& buffer : buffers) pool.putOrDelete(buffer);
+    EXPECT_EQ(40u, pool.getCount()) << "Expect all items added";
+    EXPECT_EQ(40, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
+    pool.clear();
+    EXPECT_EQ(0u, pool.getCount()) << "Expect all items cleared";
+
+    EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
 }
diff --git a/libs/hwui/tests/unit/OpDumperTests.cpp b/libs/hwui/tests/unit/OpDumperTests.cpp
new file mode 100644
index 0000000..01840d7
--- /dev/null
+++ b/libs/hwui/tests/unit/OpDumperTests.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "tests/common/TestUtils.h"
+#include "OpDumper.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(OpDumper, dump) {
+    SkPaint paint;
+    RectOp op(uirenderer::Rect(100, 100), Matrix4::identity(), nullptr, &paint);
+
+    std::stringstream stream;
+    OpDumper::dump(op, stream);
+    EXPECT_STREQ("RectOp [100 x 100]", stream.str().c_str());
+
+    stream.str("");
+    OpDumper::dump(op, stream, 2);
+    EXPECT_STREQ("    RectOp [100 x 100]", stream.str().c_str());
+
+    ClipRect clipRect(uirenderer::Rect(50, 50));
+    op.localClip = &clipRect;
+
+    stream.str("");
+    OpDumper::dump(op, stream, 2);
+    EXPECT_STREQ("    RectOp [100 x 100] clip=[50 x 50] mode=0", stream.str().c_str());
+}
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index cd9ffc5..58376c6 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -16,9 +16,16 @@
 
 #include <gtest/gtest.h>
 
+#include <DeferredLayerUpdater.h>
 #include <RecordedOp.h>
 #include <RecordingCanvas.h>
+#include <hwui/Paint.h>
+#include <minikin/Layout.h>
 #include <tests/common/TestUtils.h>
+#include <utils/Color.h>
+
+#include <SkGradientShader.h>
+#include <SkShader.h>
 
 namespace android {
 namespace uirenderer {
@@ -33,6 +40,12 @@
     }
 }
 
+static void validateSingleOp(std::unique_ptr<DisplayList>& dl,
+        std::function<void(const RecordedOp& op)> opValidator) {
+    ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
+    opValidator(*(dl->getOps()[0]));
+}
+
 TEST(RecordingCanvas, emptyPlayback) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
@@ -57,6 +70,17 @@
             << "Clip should be serialized once";
 }
 
+TEST(RecordingCanvas, emptyClipRect) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+        canvas.clipRect(100, 100, 200, 200, SkRegion::kIntersect_Op);
+        canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
+        canvas.restore();
+    });
+    ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
+}
+
 TEST(RecordingCanvas, drawArc) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
@@ -102,13 +126,30 @@
     EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
 }
 
-TEST(RecordingCanvas, drawText) {
+TEST(RecordingCanvas, drawRoundRect) {
+    // Round case - stays rounded
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+        canvas.drawRoundRect(0, 0, 100, 100, 10, 10, SkPaint());
+    });
+    ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
+    ASSERT_EQ(RecordedOpId::RoundRectOp, dl->getOps()[0]->opId);
+
+    // Non-rounded case - turned into drawRect
+    dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+        canvas.drawRoundRect(0, 0, 100, 100, 0, -1, SkPaint());
+    });
+    ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
+    ASSERT_EQ(RecordedOpId::RectOp, dl->getOps()[0]->opId)
+        << "Non-rounded rects should be converted";
+}
+
+TEST(RecordingCanvas, drawGlyphs) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setTextSize(20);
         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-        TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
+        TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
     });
 
     int count = 0;
@@ -123,7 +164,7 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(RecordingCanvas, drawText_strikeThruAndUnderline) {
+TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -133,7 +174,7 @@
             for (int j = 0; j < 2; j++) {
                 paint.setUnderlineText(i != 0);
                 paint.setStrikeThruText(j != 0);
-                TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
+                TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
             }
         }
     });
@@ -155,18 +196,18 @@
     EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
 }
 
-TEST(RecordingCanvas, drawText_forceAlignLeft) {
+TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setTextSize(20);
         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         paint.setTextAlign(SkPaint::kLeft_Align);
-        TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
+        TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
         paint.setTextAlign(SkPaint::kCenter_Align);
-        TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
+        TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
         paint.setTextAlign(SkPaint::kRight_Align);
-        TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
+        TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
     });
 
     int count = 0;
@@ -185,6 +226,18 @@
     ASSERT_EQ(3, count);
 }
 
+TEST(RecordingCanvas, drawColor) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        canvas.drawColor(Color::Black, SkXfermode::kSrcOver_Mode);
+    });
+
+    ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
+    auto op = *(dl->getOps()[0]);
+    EXPECT_EQ(RecordedOpId::ColorOp, op.opId);
+    EXPECT_EQ(nullptr, op.localClip);
+    EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds";
+}
+
 TEST(RecordingCanvas, backgroundAndImage) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkBitmap bitmap;
@@ -238,6 +291,21 @@
     ASSERT_EQ(2, count);
 }
 
+RENDERTHREAD_TEST(RecordingCanvas, textureLayer) {
+    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+            SkMatrix::MakeTrans(5, 5));
+
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
+            [&layerUpdater](RecordingCanvas& canvas) {
+        canvas.drawLayer(layerUpdater.get());
+    });
+
+    validateSingleOp(dl, [] (const RecordedOp& op) {
+        ASSERT_EQ(RecordedOpId::TextureLayerOp, op.opId);
+        ASSERT_TRUE(op.localMatrix.isIdentity()) << "Op must not apply matrix at record time.";
+    });
+}
+
 TEST(RecordingCanvas, saveLayer_simple) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer);
@@ -417,9 +485,7 @@
             // since the same clip will be computed at draw time. If such a change is made, this
             // check could be done at record time by querying the clip, or the clip could be altered
             // slightly so that it is serialized.
-            EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
-                    (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
-
+            EXPECT_EQ(Rect(59, 59, 341, 341), op.localClip->rect);
             EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
             expectedMatrix.loadIdentity();
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -428,6 +494,21 @@
     EXPECT_EQ(3, count);
 }
 
+TEST(RecordingCanvas, drawRenderNode_rejection) {
+    auto child = TestUtils::createNode(50, 50, 150, 150,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&child](RecordingCanvas& canvas) {
+        canvas.clipRect(0, 0, 0, 0, SkRegion::kIntersect_Op); // empty clip, reject node
+        canvas.drawRenderNode(child.get()); // shouldn't crash when rejecting node...
+    });
+    ASSERT_TRUE(dl->isEmpty());
+}
+
 TEST(RecordingCanvas, drawRenderNode_projection) {
     sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150,
             [](RenderProperties& props, RecordingCanvas& canvas) {
@@ -511,36 +592,127 @@
 
 TEST(RecordingCanvas, refPaint) {
     SkPaint paint;
-    paint.setAntiAlias(true);
-    paint.setTextSize(20);
-    paint.setTextAlign(SkPaint::kLeft_Align);
-    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
 
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
         paint.setColor(SK_ColorBLUE);
-        // first three should use same paint
+        // first two should use same paint
         canvas.drawRect(0, 0, 200, 10, paint);
         SkPaint paintCopy(paint);
         canvas.drawRect(0, 10, 200, 20, paintCopy);
-        TestUtils::drawTextToCanvas(&canvas, "helloworld", paint, 50, 25);
 
         // only here do we use different paint ptr
         paint.setColor(SK_ColorRED);
         canvas.drawRect(0, 20, 200, 30, paint);
     });
     auto ops = dl->getOps();
-    ASSERT_EQ(4u, ops.size());
+    ASSERT_EQ(3u, ops.size());
 
-    // first three are the same
+    // first two are the same
     EXPECT_NE(nullptr, ops[0]->paint);
     EXPECT_NE(&paint, ops[0]->paint);
     EXPECT_EQ(ops[0]->paint, ops[1]->paint);
-    EXPECT_EQ(ops[0]->paint, ops[2]->paint);
 
     // last is different, but still copied / non-null
-    EXPECT_NE(nullptr, ops[3]->paint);
-    EXPECT_NE(ops[0]->paint, ops[3]->paint);
-    EXPECT_NE(&paint, ops[3]->paint);
+    EXPECT_NE(nullptr, ops[2]->paint);
+    EXPECT_NE(ops[0]->paint, ops[2]->paint);
+    EXPECT_NE(&paint, ops[2]->paint);
+}
+
+TEST(RecordingCanvas, refBitmap) {
+    SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
+        canvas.drawBitmap(bitmap, 0, 0, nullptr);
+    });
+    auto& bitmaps = dl->getBitmapResources();
+    EXPECT_EQ(1u, bitmaps.size());
+}
+
+TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
+    SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
+        SkPaint paint;
+        SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(bitmap,
+                SkShader::TileMode::kClamp_TileMode,
+                SkShader::TileMode::kClamp_TileMode));
+        paint.setShader(shader);
+        canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+    });
+    auto& bitmaps = dl->getBitmapResources();
+    EXPECT_EQ(1u, bitmaps.size());
+}
+
+TEST(RecordingCanvas, refBitmapInShader_composeShader) {
+    SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
+        SkPaint paint;
+        SkAutoTUnref<SkShader> shader1(SkShader::CreateBitmapShader(bitmap,
+                SkShader::TileMode::kClamp_TileMode,
+                SkShader::TileMode::kClamp_TileMode));
+
+        SkPoint center;
+        center.set(50, 50);
+        SkColor colors[2];
+        colors[0] = Color::Black;
+        colors[1] = Color::White;
+        SkAutoTUnref<SkShader> shader2(SkGradientShader::CreateRadial(center, 50, colors, nullptr, 2,
+                SkShader::TileMode::kRepeat_TileMode));
+
+        SkAutoTUnref<SkShader> composeShader(SkShader::CreateComposeShader(shader1, shader2,
+                SkXfermode::Mode::kMultiply_Mode));
+        paint.setShader(composeShader);
+        canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+    });
+    auto& bitmaps = dl->getBitmapResources();
+    EXPECT_EQ(1u, bitmaps.size());
+}
+
+TEST(RecordingCanvas, drawText) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        Paint paint;
+        paint.setAntiAlias(true);
+        paint.setTextSize(20);
+        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
+        canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL);
+    });
+
+    int count = 0;
+    playbackOps(*dl, [&count](const RecordedOp& op) {
+        count++;
+        ASSERT_EQ(RecordedOpId::TextOp, op.opId);
+        EXPECT_EQ(nullptr, op.localClip);
+        EXPECT_TRUE(op.localMatrix.isIdentity());
+        EXPECT_TRUE(op.unmappedBounds.getHeight() >= 10);
+        EXPECT_TRUE(op.unmappedBounds.getWidth() >= 25);
+    });
+    ASSERT_EQ(1, count);
+}
+
+TEST(RecordingCanvas, drawTextInHighContrast) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        canvas.setHighContrastText(true);
+        Paint paint;
+        paint.setColor(SK_ColorWHITE);
+        paint.setAntiAlias(true);
+        paint.setTextSize(20);
+        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
+        canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL);
+    });
+
+    int count = 0;
+    playbackOps(*dl, [&count](const RecordedOp& op) {
+        ASSERT_EQ(RecordedOpId::TextOp, op.opId);
+        if (count++ == 0) {
+            EXPECT_EQ(SK_ColorBLACK, op.paint->getColor());
+            EXPECT_EQ(SkPaint::kStrokeAndFill_Style, op.paint->getStyle());
+        } else {
+            EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+            EXPECT_EQ(SkPaint::kFill_Style, op.paint->getStyle());
+        }
+
+    });
+    ASSERT_EQ(2, count);
 }
 
 } // namespace uirenderer
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
new file mode 100644
index 0000000..7c57a50
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "RenderNode.h"
+#include "TreeInfo.h"
+#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(RenderNode, hasParents) {
+    auto child = TestUtils::createNode(0, 0, 200, 400,
+            [](RenderProperties& props, TestCanvas& canvas) {
+        canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+    });
+    auto parent = TestUtils::createNode(0, 0, 200, 400,
+            [&child](RenderProperties& props, TestCanvas& canvas) {
+        canvas.drawRenderNode(child.get());
+    });
+
+    TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+    EXPECT_TRUE(child->hasParents()) << "Child node has no parent";
+    EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+    TestUtils::recordNode(*parent, [](TestCanvas& canvas) {
+        canvas.drawColor(Color::Amber_500, SkXfermode::kSrcOver_Mode);
+    });
+
+    EXPECT_TRUE(child->hasParents()) << "Child should still have a parent";
+    EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+    TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+    EXPECT_FALSE(child->hasParents()) << "Child should be removed";
+    EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+}
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 586625b..875e260 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -41,3 +41,10 @@
     EXPECT_EQ(SkShader::kRepeat_TileMode, xy[1]);
     EXPECT_EQ(origBitmap.pixelRef(), bitmap.pixelRef());
 }
+
+TEST(SkiaBehavior, genIds) {
+    SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+    uint32_t genId = bitmap.getGenerationID();
+    bitmap.notifyPixelsChanged();
+    EXPECT_NE(genId, bitmap.getGenerationID());
+}
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
new file mode 100644
index 0000000..5a01193
--- /dev/null
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "tests/common/TestUtils.h"
+
+#include <gtest/gtest.h>
+#include <RecordingCanvas.h>
+#include <SkPicture.h>
+#include <SkPictureRecorder.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+/**
+ * Verify that we get the same culling bounds for text for (1) drawing glyphs
+ * directly to a Canvas or (2) going through a SkPicture as an intermediate step.
+ */
+TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        // setup test variables
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setTextSize(20);
+        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        static const char* text = "testing text bounds";
+
+        // draw text directly into Recording canvas
+        TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 25, 25);
+
+        // record the same text draw into a SkPicture and replay it into a Recording canvas
+        SkPictureRecorder recorder;
+        SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0);
+        std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas));
+        TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25);
+        SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
+
+        canvas.asSkCanvas()->drawPicture(picture);
+    });
+
+    // verify that the text bounds and matrices match
+    ASSERT_EQ(2U, dl->getOps().size());
+    auto directOp = dl->getOps()[0];
+    auto pictureOp = dl->getOps()[1];
+    ASSERT_EQ(RecordedOpId::TextOp, directOp->opId);
+    EXPECT_EQ(directOp->opId, pictureOp->opId);
+    EXPECT_EQ(directOp->unmappedBounds, pictureOp->unmappedBounds);
+    EXPECT_EQ(directOp->localMatrix, pictureOp->localMatrix);
+}
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
new file mode 100644
index 0000000..409a12d
--- /dev/null
+++ b/libs/hwui/tests/unit/main.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+#include "Caches.h"
+#include "thread/TaskManager.h"
+#include "tests/common/TestUtils.h"
+
+#include <memunreachable/memunreachable.h>
+
+#include <cstdio>
+#include <iostream>
+#include <map>
+#include <unordered_set>
+#include <signal.h>
+#include <unistd.h>
+
+using namespace std;
+using namespace android;
+using namespace android::uirenderer;
+
+static auto CRASH_SIGNALS = {
+        SIGABRT,
+        SIGSEGV,
+        SIGBUS,
+};
+
+static map<int, struct sigaction> gSigChain;
+
+static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) {
+    auto testinfo = ::testing::UnitTest::GetInstance()->current_test_info();
+    printf("[  FAILED  ] %s.%s\n", testinfo->test_case_name(),
+            testinfo->name());
+    printf("[  FATAL!  ] Process crashed, aborting tests!\n");
+    fflush(stdout);
+
+    // restore the default sighandler and re-raise
+    struct sigaction sa = gSigChain[sig];
+    sigaction(sig, &sa, nullptr);
+    raise(sig);
+}
+
+static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) {
+    // merge them all
+    UnreachableMemoryInfo merged;
+    unordered_set<uintptr_t> addrs;
+    merged.allocation_bytes = 0;
+    merged.leak_bytes = 0;
+    merged.num_allocations = 0;
+    merged.num_leaks = 0;
+    for (auto& info : infolist) {
+        // We'll be a little hazzy about these ones and just hope the biggest
+        // is the most accurate
+        merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes);
+        merged.num_allocations = max(merged.num_allocations, info.num_allocations);
+        for (auto& leak : info.leaks) {
+             if (addrs.find(leak.begin) == addrs.end()) {
+                 merged.leaks.push_back(leak);
+                 merged.num_leaks++;
+                 merged.leak_bytes += leak.size;
+                 addrs.insert(leak.begin);
+             }
+        }
+    }
+
+    // Now log the result
+    if (merged.num_leaks) {
+        cout << endl << "Leaked memory!" << endl;
+        if (!merged.leaks[0].backtrace.num_frames) {
+            cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'"
+                    << endl << "and 'setprop libc.debug.malloc.options backtrace=8'"
+                    << " to get backtraces" << endl;
+        }
+        cout << merged.ToString(false);
+    }
+}
+
+static void checkForLeaks() {
+    // TODO: Until we can shutdown the RT thread we need to do this in
+    // two passes as GetUnreachableMemory has limited insight into
+    // thread-local caches so some leaks will not be properly tagged as leaks
+    nsecs_t before = systemTime();
+    UnreachableMemoryInfo rtMemInfo;
+    TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) {
+        if (Caches::hasInstance()) {
+            Caches::getInstance().tasks.stop();
+        }
+        // Check for leaks
+        if (!GetUnreachableMemory(rtMemInfo)) {
+            cerr << "Failed to get unreachable memory!" << endl;
+            return;
+        }
+    });
+    UnreachableMemoryInfo uiMemInfo;
+    if (!GetUnreachableMemory(uiMemInfo)) {
+        cerr << "Failed to get unreachable memory!" << endl;
+        return;
+    }
+    logUnreachable({rtMemInfo, uiMemInfo});
+    nsecs_t after = systemTime();
+    cout << "Leak check took " << ns2ms(after - before) << "ms" << endl;
+}
+
+int main(int argc, char* argv[]) {
+    // Register a crash handler
+    struct sigaction sa;
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = &gtestSigHandler;
+    sa.sa_flags = SA_SIGINFO;
+    for (auto sig : CRASH_SIGNALS) {
+        struct sigaction old_sa;
+        sigaction(sig, &sa, &old_sa);
+        gSigChain.insert(pair<int, struct sigaction>(sig, old_sa));
+    }
+
+    // Run the tests
+    testing::InitGoogleTest(&argc, argv);
+    int ret = RUN_ALL_TESTS();
+    checkForLeaks();
+    return ret;
+}
+
diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h
index 6cb23e5..0a7acb0 100644
--- a/libs/hwui/thread/Barrier.h
+++ b/libs/hwui/thread/Barrier.h
@@ -33,11 +33,6 @@
         mCondition.signal(mType);
     }
 
-    void close() {
-        Mutex::Autolock l(mLock);
-        mOpened = false;
-    }
-
     void wait() const {
         Mutex::Autolock l(mLock);
         while (!mOpened) {
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index 0a0e185..34c8c6b 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -84,6 +84,13 @@
         return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
     }
 
+    template<class T>
+    T* create_trivial_array(int count) {
+        static_assert(std::is_trivially_destructible<T>::value,
+                "Error, called create_trivial_array on a non-trivial type");
+        return reinterpret_cast<T*>(allocImpl(sizeof(T) * count));
+    }
+
     /**
      * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
      * state if possible.
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index db53713..4faab9a 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -67,6 +67,21 @@
                 && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
     }
 
+    static bool isOpaquePaint(const SkPaint* paint) {
+        if (!paint) return true; // default (paintless) behavior is SrcOver, black
+
+        if (paint->getAlpha() != 0xFF
+                || PaintUtils::isBlendedShader(paint->getShader())
+                || PaintUtils::isBlendedColorFilter(paint->getColorFilter())) {
+            return false;
+        }
+
+        // Only let simple srcOver / src blending modes declare opaque, since behavior is clear.
+        SkXfermode::Mode mode = getXfermode(paint->getXfermode());
+        return mode == SkXfermode::Mode::kSrcOver_Mode
+                || mode == SkXfermode::Mode::kSrc_Mode;
+    }
+
     static bool isBlendedShader(const SkShader* shader) {
         if (shader == nullptr) {
             return false;
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
index 05a3d59..5add957 100644
--- a/libs/hwui/utils/StringUtils.h
+++ b/libs/hwui/utils/StringUtils.h
@@ -42,7 +42,7 @@
         static const char* SUFFIXES[] = {"B", "KiB", "MiB"};
         size_t suffix = 0;
         double temp = d.bytes;
-        while (temp > 1000 && suffix < 2) {
+        while (temp > 1024 && suffix < 2) {
             temp /= 1024.0;
             suffix++;
         }
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 5ba3f2c..df42a73 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -16,126 +16,75 @@
 
 package android.location;
 
-import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * A class containing a GPS clock timestamp.
  * It represents a measurement of the GPS receiver's clock.
  */
 public final class GnssClock implements Parcelable {
-
     // The following enumerations must be in sync with the values declared in gps.h
 
-    /** The type of the GPS Clock. */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({CLOCK_TYPE_UNKNOWN, CLOCK_TYPE_LOCAL_HW_TIME, CLOCK_TYPE_GPS_TIME})
-    public @interface GnssClockType {}
-
-    /**
-     * The type of the time stored is not available or it is unknown.
-     */
-    public static final byte CLOCK_TYPE_UNKNOWN = 0;
-
-    /**
-     * The source of the time value reported by this class is the 'Local Hardware Clock'.
-     */
-    public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1;
-
-    /**
-     * The source of the time value reported by this class is the 'GPS time' derived from
-     * satellites (epoch = Jan 6, 1980).
-     */
-    public static final byte CLOCK_TYPE_GPS_TIME = 2;
-
-    private static final short HAS_NO_FLAGS = 0;
-    private static final short HAS_LEAP_SECOND = (1<<0);
-    private static final short HAS_TIME_UNCERTAINTY = (1<<1);
-    private static final short HAS_FULL_BIAS = (1<<2);
-    private static final short HAS_BIAS = (1<<3);
-    private static final short HAS_BIAS_UNCERTAINTY = (1<<4);
-    private static final short HAS_DRIFT = (1<<5);
-    private static final short HAS_DRIFT_UNCERTAINTY = (1<<6);
+    private static final int HAS_NO_FLAGS = 0;
+    private static final int HAS_LEAP_SECOND = (1<<0);
+    private static final int HAS_TIME_UNCERTAINTY = (1<<1);
+    private static final int HAS_FULL_BIAS = (1<<2);
+    private static final int HAS_BIAS = (1<<3);
+    private static final int HAS_BIAS_UNCERTAINTY = (1<<4);
+    private static final int HAS_DRIFT = (1<<5);
+    private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
 
     // End enumerations in sync with gps.h
 
-    private short mFlags;
-    private short mLeapSecond;
-    private byte mType;
-    private long mTimeInNs;
-    private double mTimeUncertaintyInNs;
-    private long mFullBiasInNs;
-    private double mBiasInNs;
-    private double mBiasUncertaintyInNs;
-    private double mDriftInNsPerSec;
-    private double mDriftUncertaintyInNsPerSec;
+    private int mFlags;
+    private int mLeapSecond;
+    private long mTimeNanos;
+    private double mTimeUncertaintyNanos;
+    private long mFullBiasNanos;
+    private double mBiasNanos;
+    private double mBiasUncertaintyNanos;
+    private double mDriftNanosPerSecond;
+    private double mDriftUncertaintyNanosPerSecond;
     private int mHardwareClockDiscontinuityCount;
 
-    GnssClock() {
+    /**
+     * @hide
+     */
+    @TestApi
+    public GnssClock() {
         initialize();
     }
 
     /**
      * Sets all contents to the values stored in the provided object.
+     * @hide
      */
+    @TestApi
     public void set(GnssClock clock) {
         mFlags = clock.mFlags;
         mLeapSecond = clock.mLeapSecond;
-        mType = clock.mType;
-        mTimeInNs = clock.mTimeInNs;
-        mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
-        mFullBiasInNs = clock.mFullBiasInNs;
-        mBiasInNs = clock.mBiasInNs;
-        mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
-        mDriftInNsPerSec = clock.mDriftInNsPerSec;
-        mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+        mTimeNanos = clock.mTimeNanos;
+        mTimeUncertaintyNanos = clock.mTimeUncertaintyNanos;
+        mFullBiasNanos = clock.mFullBiasNanos;
+        mBiasNanos = clock.mBiasNanos;
+        mBiasUncertaintyNanos = clock.mBiasUncertaintyNanos;
+        mDriftNanosPerSecond = clock.mDriftNanosPerSecond;
+        mDriftUncertaintyNanosPerSecond = clock.mDriftUncertaintyNanosPerSecond;
         mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
     }
 
     /**
      * Resets all the contents to its original state.
+     * @hide
      */
+    @TestApi
     public void reset() {
         initialize();
     }
 
     /**
-     * Gets the type of time reported by {@link #getTimeInNs()}.
-     */
-    @GnssClockType
-    public byte getType() {
-        return mType;
-    }
-
-    /**
-     * Sets the type of time reported.
-     */
-    public void setType(@GnssClockType byte value) {
-        mType = value;
-    }
-
-    /**
-     * Gets a string representation of the 'type'.
-     * For internal and logging use only.
-     */
-    private String getTypeString() {
-        switch (mType) {
-            case CLOCK_TYPE_UNKNOWN:
-                return "Unknown";
-            case CLOCK_TYPE_GPS_TIME:
-                return "GpsTime";
-            case CLOCK_TYPE_LOCAL_HW_TIME:
-                return "LocalHwClock";
-            default:
-                return "<Invalid:" + mType + ">";
-        }
-    }
-
-    /**
      * Returns true if {@link #getLeapSecond()} is available, false otherwise.
      */
     public boolean hasLeapSecond() {
@@ -149,58 +98,61 @@
      *
      * The value is only available if {@link #hasLeapSecond()} is true.
      */
-    public short getLeapSecond() {
+    public int getLeapSecond() {
         return mLeapSecond;
     }
 
     /**
      * Sets the leap second associated with the clock's time.
+     * @hide
      */
-    public void setLeapSecond(short leapSecond) {
+    @TestApi
+    public void setLeapSecond(int leapSecond) {
         setFlag(HAS_LEAP_SECOND);
         mLeapSecond = leapSecond;
     }
 
     /**
      * Resets the leap second associated with the clock's time.
+     * @hide
      */
+    @TestApi
     public void resetLeapSecond() {
         resetFlag(HAS_LEAP_SECOND);
-        mLeapSecond = Short.MIN_VALUE;
+        mLeapSecond = Integer.MIN_VALUE;
     }
 
     /**
-     * Gets the GPS receiver internal clock value in nanoseconds.
-     * This can be either the 'local hardware clock' value ({@link #CLOCK_TYPE_LOCAL_HW_TIME}), or the
-     * current GPS time derived inside GPS receiver ({@link #CLOCK_TYPE_GPS_TIME}).
-     * {@link #getType()} defines the time reported.
+     * Gets the GNSS receiver internal clock value in nanoseconds.
      *
      * For 'local hardware clock' this value is expected to be monotonically increasing during the
      * reporting session. The real GPS time can be derived by compensating
-     * {@link #getFullBiasInNs()} (when it is available) from this value.
+     * {@link #getFullBiasNanos()} (when it is available) from this value.
      *
      * For 'GPS time' this value is expected to be the best estimation of current GPS time that GPS
-     * receiver can achieve. {@link #getTimeUncertaintyInNs()} should be available when GPS time is
+     * receiver can achieve. {@link #getTimeUncertaintyNanos()} should be available when GPS time is
      * specified.
      *
-     * Sub-nanosecond accuracy can be provided by means of {@link #getBiasInNs()}.
-     * The reported time includes {@link #getTimeUncertaintyInNs()}.
+     * Sub-nanosecond accuracy can be provided by means of {@link #getBiasNanos()}.
+     * The reported time includes {@link #getTimeUncertaintyNanos()}.
      */
-    public long getTimeInNs() {
-        return mTimeInNs;
+    public long getTimeNanos() {
+        return mTimeNanos;
     }
 
     /**
-     * Sets the GPS receiver internal clock in nanoseconds.
+     * Sets the GNSS receiver internal clock in nanoseconds.
+     * @hide
      */
-    public void setTimeInNs(long timeInNs) {
-        mTimeInNs = timeInNs;
+    @TestApi
+    public void setTimeNanos(long timeNanos) {
+        mTimeNanos = timeNanos;
     }
 
     /**
-     * Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
+     * Returns true if {@link #getTimeUncertaintyNanos()} is available, false otherwise.
      */
-    public boolean hasTimeUncertaintyInNs() {
+    public boolean hasTimeUncertaintyNanos() {
         return isFlagSet(HAS_TIME_UNCERTAINTY);
     }
 
@@ -208,190 +160,211 @@
      * Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
      * The uncertainty is represented as an absolute (single sided) value.
      *
-     * The value is only available if {@link #hasTimeUncertaintyInNs()} is true.
+     * The value is only available if {@link #hasTimeUncertaintyNanos()} is true.
      */
-    public double getTimeUncertaintyInNs() {
-        return mTimeUncertaintyInNs;
+    public double getTimeUncertaintyNanos() {
+        return mTimeUncertaintyNanos;
     }
 
     /**
      * Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
+     * @hide
      */
-    public void setTimeUncertaintyInNs(double timeUncertaintyInNs) {
+    @TestApi
+    public void setTimeUncertaintyNanos(double timeUncertaintyNanos) {
         setFlag(HAS_TIME_UNCERTAINTY);
-        mTimeUncertaintyInNs = timeUncertaintyInNs;
+        mTimeUncertaintyNanos = timeUncertaintyNanos;
     }
 
     /**
      * Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
+     * @hide
      */
-    public void resetTimeUncertaintyInNs() {
+    @TestApi
+    public void resetTimeUncertaintyNanos() {
         resetFlag(HAS_TIME_UNCERTAINTY);
-        mTimeUncertaintyInNs = Double.NaN;
+        mTimeUncertaintyNanos = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getFullBiasInNs()} is available, false otherwise.
+     * Returns true if {@link #getFullBiasNanos()} is available, false otherwise.
      */
-    public boolean hasFullBiasInNs() {
+    public boolean hasFullBiasNanos() {
         return isFlagSet(HAS_FULL_BIAS);
     }
 
     /**
-     * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
+     * Gets the difference between hardware clock ({@link #getTimeNanos()}) inside GPS receiver and
      * the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
      *
-     * This value is available if {@link #CLOCK_TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
-     * the clock for GPS time.
-     * {@link #getBiasUncertaintyInNs()} should be used for quality check.
+     * This value is available if the receiver has estimated GPS time. If the computed time is for a
+     * non-GPS constellation, the time offset of that constellation to GPS has to be applied to fill
+     * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyNanos()} in
+     * it, and it should be used for quality check. The value is only available if
+     * {@link #hasFullBiasNanos()} is true.
      *
      * The sign of the value is defined by the following equation:
-     *      true time (GPS time) = time_ns + (full_bias_ns + bias_ns)
-     *
-     * The reported full bias includes {@link #getBiasUncertaintyInNs()}.
-     * The value is onl available if {@link #hasFullBiasInNs()} is true.
+     *      local estimate of GPS time = time_ns + (full_bias_ns + bias_ns)
      */
-    public long getFullBiasInNs() {
-        return mFullBiasInNs;
+    public long getFullBiasNanos() {
+        return mFullBiasNanos;
     }
 
     /**
      * Sets the full bias in nanoseconds.
+     * @hide
      */
-    public void setFullBiasInNs(long value) {
+    @TestApi
+    public void setFullBiasNanos(long value) {
         setFlag(HAS_FULL_BIAS);
-        mFullBiasInNs = value;
+        mFullBiasNanos = value;
     }
 
     /**
      * Resets the full bias in nanoseconds.
+     * @hide
      */
-    public void resetFullBiasInNs() {
+    @TestApi
+    public void resetFullBiasNanos() {
         resetFlag(HAS_FULL_BIAS);
-        mFullBiasInNs = Long.MIN_VALUE;
+        mFullBiasNanos = Long.MIN_VALUE;
     }
 
     /**
-     * Returns true if {@link #getBiasInNs()} is available, false otherwise.
+     * Returns true if {@link #getBiasNanos()} is available, false otherwise.
      */
-    public boolean hasBiasInNs() {
+    public boolean hasBiasNanos() {
         return isFlagSet(HAS_BIAS);
     }
 
     /**
      * Gets the clock's sub-nanosecond bias.
-     * The reported bias includes {@link #getBiasUncertaintyInNs()}.
+     * The reported bias includes {@link #getBiasUncertaintyNanos()}.
      *
-     * The value is only available if {@link #hasBiasInNs()} is true.
+     * The value is only available if {@link #hasBiasNanos()} is true.
      */
-    public double getBiasInNs() {
-        return mBiasInNs;
+    public double getBiasNanos() {
+        return mBiasNanos;
     }
 
     /**
      * Sets the sub-nanosecond bias.
+     * @hide
      */
-    public void setBiasInNs(double biasInNs) {
+    @TestApi
+    public void setBiasNanos(double biasNanos) {
         setFlag(HAS_BIAS);
-        mBiasInNs = biasInNs;
+        mBiasNanos = biasNanos;
     }
 
     /**
      * Resets the clock's Bias in nanoseconds.
+     * @hide
      */
-    public void resetBiasInNs() {
+    @TestApi
+    public void resetBiasNanos() {
         resetFlag(HAS_BIAS);
-        mBiasInNs = Double.NaN;
+        mBiasNanos = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getBiasUncertaintyInNs()} is available, false otherwise.
+     * Returns true if {@link #getBiasUncertaintyNanos()} is available, false otherwise.
      */
-    public boolean hasBiasUncertaintyInNs() {
+    public boolean hasBiasUncertaintyNanos() {
         return isFlagSet(HAS_BIAS_UNCERTAINTY);
     }
 
     /**
      * Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
      *
-     * The value is only available if {@link #hasBiasUncertaintyInNs()} is true.
+     * The value is only available if {@link #hasBiasUncertaintyNanos()} is true.
      */
-    public double getBiasUncertaintyInNs() {
-        return mBiasUncertaintyInNs;
+    public double getBiasUncertaintyNanos() {
+        return mBiasUncertaintyNanos;
     }
 
     /**
      * Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+     * @hide
      */
-    public void setBiasUncertaintyInNs(double biasUncertaintyInNs) {
+    @TestApi
+    public void setBiasUncertaintyNanos(double biasUncertaintyNanos) {
         setFlag(HAS_BIAS_UNCERTAINTY);
-        mBiasUncertaintyInNs = biasUncertaintyInNs;
+        mBiasUncertaintyNanos = biasUncertaintyNanos;
     }
 
     /**
      * Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+     * @hide
      */
-    public void resetBiasUncertaintyInNs() {
+    @TestApi
+    public void resetBiasUncertaintyNanos() {
         resetFlag(HAS_BIAS_UNCERTAINTY);
-        mBiasUncertaintyInNs = Double.NaN;
+        mBiasUncertaintyNanos = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getDriftInNsPerSec()} is available, false otherwise.
+     * Returns true if {@link #getDriftNanosPerSecond()} is available, false otherwise.
      */
-    public boolean hasDriftInNsPerSec() {
+    public boolean hasDriftNanosPerSecond() {
         return isFlagSet(HAS_DRIFT);
     }
 
     /**
      * Gets the clock's Drift in nanoseconds per second.
      * A positive value indicates that the frequency is higher than the nominal frequency.
-     * The reported drift includes {@link #getDriftUncertaintyInNsPerSec()}.
+     * The reported drift includes {@link #getDriftUncertaintyNanosPerSecond()}.
      *
-     * The value is only available if {@link #hasDriftInNsPerSec()} is true.
+     * The value is only available if {@link #hasDriftNanosPerSecond()} is true.
      */
-    public double getDriftInNsPerSec() {
-        return mDriftInNsPerSec;
+    public double getDriftNanosPerSecond() {
+        return mDriftNanosPerSecond;
     }
 
     /**
      * Sets the clock's Drift in nanoseconds per second.
+     * @hide
      */
-    public void setDriftInNsPerSec(double driftInNsPerSec) {
+    @TestApi
+    public void setDriftNanosPerSecond(double driftNanosPerSecond) {
         setFlag(HAS_DRIFT);
-        mDriftInNsPerSec = driftInNsPerSec;
+        mDriftNanosPerSecond = driftNanosPerSecond;
     }
 
     /**
      * Resets the clock's Drift in nanoseconds per second.
+     * @hide
      */
-    public void resetDriftInNsPerSec() {
+    @TestApi
+    public void resetDriftNanosPerSecond() {
         resetFlag(HAS_DRIFT);
-        mDriftInNsPerSec = Double.NaN;
+        mDriftNanosPerSecond = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getDriftUncertaintyInNsPerSec()} is available, false otherwise.
+     * Returns true if {@link #getDriftUncertaintyNanosPerSecond()} is available, false otherwise.
      */
-    public boolean hasDriftUncertaintyInNsPerSec() {
+    public boolean hasDriftUncertaintyNanosPerSecond() {
         return isFlagSet(HAS_DRIFT_UNCERTAINTY);
     }
 
     /**
      * Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
      *
-     * The value is only available if {@link #hasDriftUncertaintyInNsPerSec()} is true.
+     * The value is only available if {@link #hasDriftUncertaintyNanosPerSecond()} is true.
      */
-    public double getDriftUncertaintyInNsPerSec() {
-        return mDriftUncertaintyInNsPerSec;
+    public double getDriftUncertaintyNanosPerSecond() {
+        return mDriftUncertaintyNanosPerSecond;
     }
 
     /**
      * Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+     * @hide
      */
-    public void setDriftUncertaintyInNsPerSec(double driftUncertaintyInNsPerSec) {
+    @TestApi
+    public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
         setFlag(HAS_DRIFT_UNCERTAINTY);
-        mDriftUncertaintyInNsPerSec = driftUncertaintyInNsPerSec;
+        mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
     }
 
     /**
@@ -403,17 +376,21 @@
 
     /**
      * Sets count of last hardware clock discontinuity.
+     * @hide
      */
+    @TestApi
     public void setHardwareClockDiscontinuityCount(int value) {
         mHardwareClockDiscontinuityCount = value;
     }
 
     /**
      * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+     * @hide
      */
-    public void resetDriftUncertaintyInNsPerSec() {
+    @TestApi
+    public void resetDriftUncertaintyNanosPerSecond() {
         resetFlag(HAS_DRIFT_UNCERTAINTY);
-        mDriftUncertaintyInNsPerSec = Double.NaN;
+        mDriftUncertaintyNanosPerSecond = Double.NaN;
     }
 
     public static final Creator<GnssClock> CREATOR = new Creator<GnssClock>() {
@@ -421,16 +398,15 @@
         public GnssClock createFromParcel(Parcel parcel) {
             GnssClock gpsClock = new GnssClock();
 
-            gpsClock.mFlags = (short) parcel.readInt();
-            gpsClock.mLeapSecond = (short) parcel.readInt();
-            gpsClock.mType = parcel.readByte();
-            gpsClock.mTimeInNs = parcel.readLong();
-            gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
-            gpsClock.mFullBiasInNs = parcel.readLong();
-            gpsClock.mBiasInNs = parcel.readDouble();
-            gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
-            gpsClock.mDriftInNsPerSec = parcel.readDouble();
-            gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+            gpsClock.mFlags = parcel.readInt();
+            gpsClock.mLeapSecond = parcel.readInt();
+            gpsClock.mTimeNanos = parcel.readLong();
+            gpsClock.mTimeUncertaintyNanos = parcel.readDouble();
+            gpsClock.mFullBiasNanos = parcel.readLong();
+            gpsClock.mBiasNanos = parcel.readDouble();
+            gpsClock.mBiasUncertaintyNanos = parcel.readDouble();
+            gpsClock.mDriftNanosPerSecond = parcel.readDouble();
+            gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
             gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
 
             return gpsClock;
@@ -446,14 +422,13 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mFlags);
         parcel.writeInt(mLeapSecond);
-        parcel.writeByte(mType);
-        parcel.writeLong(mTimeInNs);
-        parcel.writeDouble(mTimeUncertaintyInNs);
-        parcel.writeLong(mFullBiasInNs);
-        parcel.writeDouble(mBiasInNs);
-        parcel.writeDouble(mBiasUncertaintyInNs);
-        parcel.writeDouble(mDriftInNsPerSec);
-        parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+        parcel.writeLong(mTimeNanos);
+        parcel.writeDouble(mTimeUncertaintyNanos);
+        parcel.writeLong(mFullBiasNanos);
+        parcel.writeDouble(mBiasNanos);
+        parcel.writeDouble(mBiasUncertaintyNanos);
+        parcel.writeDouble(mDriftNanosPerSecond);
+        parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
         parcel.writeInt(mHardwareClockDiscontinuityCount);
     }
 
@@ -468,39 +443,38 @@
         final String formatWithUncertainty = "   %-15s = %-25s   %-26s = %s\n";
         StringBuilder builder = new StringBuilder("GnssClock:\n");
 
-        builder.append(String.format(format, "Type", getTypeString()));
-
         builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "TimeInNs",
-                mTimeInNs,
-                "TimeUncertaintyInNs",
-                hasTimeUncertaintyInNs() ? mTimeUncertaintyInNs : null));
+                "TimeNanos",
+                mTimeNanos,
+                "TimeUncertaintyNanos",
+                hasTimeUncertaintyNanos() ? mTimeUncertaintyNanos : null));
 
         builder.append(String.format(
                 format,
-                "FullBiasInNs",
-                hasFullBiasInNs() ? mFullBiasInNs : null));
+                "FullBiasNanos",
+                hasFullBiasNanos() ? mFullBiasNanos : null));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "BiasInNs",
-                hasBiasInNs() ? mBiasInNs : null,
-                "BiasUncertaintyInNs",
-                hasBiasUncertaintyInNs() ? mBiasUncertaintyInNs : null));
+                "BiasNanos",
+                hasBiasNanos() ? mBiasNanos : null,
+                "BiasUncertaintyNanos",
+                hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "DriftInNsPerSec",
-                hasDriftInNsPerSec() ? mDriftInNsPerSec : null,
-                "DriftUncertaintyInNsPerSec",
-                hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
+                "DriftNanosPerSecond",
+                hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
+                "DriftUncertaintyNanosPerSecond",
+                hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
 
-        builder.append(String.format(format, "HardwareClockDiscontinuityCount",
-                getType() == CLOCK_TYPE_LOCAL_HW_TIME
-                        ? mHardwareClockDiscontinuityCount : null));
+        builder.append(String.format(
+                format,
+                "HardwareClockDiscontinuityCount",
+                mHardwareClockDiscontinuityCount));
 
         return builder.toString();
     }
@@ -508,26 +482,25 @@
     private void initialize() {
         mFlags = HAS_NO_FLAGS;
         resetLeapSecond();
-        setType(CLOCK_TYPE_UNKNOWN);
-        setTimeInNs(Long.MIN_VALUE);
-        resetTimeUncertaintyInNs();
-        resetFullBiasInNs();
-        resetBiasInNs();
-        resetBiasUncertaintyInNs();
-        resetDriftInNsPerSec();
-        resetDriftUncertaintyInNsPerSec();
+        setTimeNanos(Long.MIN_VALUE);
+        resetTimeUncertaintyNanos();
+        resetFullBiasNanos();
+        resetBiasNanos();
+        resetBiasUncertaintyNanos();
+        resetDriftNanosPerSecond();
+        resetDriftUncertaintyNanosPerSecond();
         setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
     }
 
-    private void setFlag(short flag) {
+    private void setFlag(int flag) {
         mFlags |= flag;
     }
 
-    private void resetFlag(short flag) {
+    private void resetFlag(int flag) {
         mFlags &= ~flag;
     }
 
-    private boolean isFlagSet(short flag) {
+    private boolean isFlagSet(int flag) {
         return (mFlags & flag) == flag;
     }
 }
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index a619ab2..d78ccee 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.TestApi;
 import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -28,83 +29,38 @@
  */
 public final class GnssMeasurement implements Parcelable {
     private int mFlags;
-    private short mSvid;
-    private byte mConstellationType;
-    private double mTimeOffsetInNs;
-    private short mState;
-    private long mReceivedSvTimeInNs;
-    private long mReceivedSvTimeUncertaintyInNs;
-    private double mCn0InDbHz;
-    private double mPseudorangeRateInMetersPerSec;
-    private double mPseudorangeRateUncertaintyInMetersPerSec;
-    private short mAccumulatedDeltaRangeState;
-    private double mAccumulatedDeltaRangeInMeters;
-    private double mAccumulatedDeltaRangeUncertaintyInMeters;
-    private double mPseudorangeInMeters;
-    private double mPseudorangeUncertaintyInMeters;
-    private double mCodePhaseInChips;
-    private double mCodePhaseUncertaintyInChips;
-    private float mCarrierFrequencyInHz;
+    private int mSvid;
+    private int mConstellationType;
+    private double mTimeOffsetNanos;
+    private int mState;
+    private long mReceivedSvTimeNanos;
+    private long mReceivedSvTimeUncertaintyNanos;
+    private double mCn0DbHz;
+    private double mPseudorangeRateMetersPerSecond;
+    private double mPseudorangeRateUncertaintyMetersPerSecond;
+    private int mAccumulatedDeltaRangeState;
+    private double mAccumulatedDeltaRangeMeters;
+    private double mAccumulatedDeltaRangeUncertaintyMeters;
+    private float mCarrierFrequencyHz;
     private long mCarrierCycles;
     private double mCarrierPhase;
     private double mCarrierPhaseUncertainty;
-    private byte mLossOfLock;
-    private int mBitNumber;
-    private short mTimeFromLastBitInMs;
-    private double mDopplerShiftInHz;
-    private double mDopplerShiftUncertaintyInHz;
-    private byte mMultipathIndicator;
+    private int mMultipathIndicator;
     private double mSnrInDb;
-    private double mElevationInDeg;
-    private double mElevationUncertaintyInDeg;
-    private double mAzimuthInDeg;
-    private double mAzimuthUncertaintyInDeg;
-    private boolean mUsedInFix;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
     private static final int HAS_NO_FLAGS = 0;
     private static final int HAS_SNR = (1<<0);
-    private static final int HAS_ELEVATION = (1<<1);
-    private static final int HAS_ELEVATION_UNCERTAINTY = (1<<2);
-    private static final int HAS_AZIMUTH = (1<<3);
-    private static final int HAS_AZIMUTH_UNCERTAINTY = (1<<4);
-    private static final int HAS_PSEUDORANGE = (1<<5);
-    private static final int HAS_PSEUDORANGE_UNCERTAINTY = (1<<6);
-    private static final int HAS_CODE_PHASE = (1<<7);
-    private static final int HAS_CODE_PHASE_UNCERTAINTY = (1<<8);
     private static final int HAS_CARRIER_FREQUENCY = (1<<9);
     private static final int HAS_CARRIER_CYCLES = (1<<10);
     private static final int HAS_CARRIER_PHASE = (1<<11);
     private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
-    private static final int HAS_BIT_NUMBER = (1<<13);
-    private static final int HAS_TIME_FROM_LAST_BIT = (1<<14);
-    private static final int HAS_DOPPLER_SHIFT = (1<<15);
-    private static final int HAS_DOPPLER_SHIFT_UNCERTAINTY = (1<<16);
-    // private static final int HAS_USED_IN_FIX = (1<<17);
-    private static final int HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
-
-    /** The status of 'loss of lock'. */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({LOSS_OF_LOCK_UNKNOWN, LOSS_OF_LOCK_OK, LOSS_OF_LOCK_CYCLE_SLIP})
-    public @interface LossOfLockStatus {}
 
     /**
-     * The indicator is not available or it is unknown.
+     * The status of the multipath indicator.
+     * @hide
      */
-    public static final byte LOSS_OF_LOCK_UNKNOWN = 0;
-
-    /**
-     * The measurement does not present any indication of 'loss of lock'.
-     */
-    public static final byte LOSS_OF_LOCK_OK = 1;
-
-    /**
-     * 'Loss of lock' detected between the previous and current observation: cycle slip possible.
-     */
-    public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2;
-
-    /** The status of multipath. */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({MULTIPATH_INDICATOR_UNKNOWN, MULTIPATH_INDICATOR_DETECTED,
         MULTIPATH_INDICATOR_NOT_USED})
@@ -113,129 +69,124 @@
     /**
      * The indicator is not available or it is unknown.
      */
-    public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0;
+    public static final int MULTIPATH_INDICATOR_UNKNOWN = 0;
 
     /**
      * The measurement has been indicated to use multi-path.
      */
-    public static final byte MULTIPATH_INDICATOR_DETECTED = 1;
+    public static final int MULTIPATH_INDICATOR_DETECTED = 1;
 
     /**
      * The measurement has been indicated not tu use multi-path.
      */
-    public static final byte MULTIPATH_INDICATOR_NOT_USED = 2;
+    public static final int MULTIPATH_INDICATOR_NOT_USED = 2;
+
+    /** This GNSS measurement's tracking state is invalid or unknown. */
+    public static final int STATE_UNKNOWN = 0;
+    /** This GNSS measurement's tracking state has code lock. */
+    public static final int STATE_CODE_LOCK = (1<<0);
+    /** This GNSS measurement's tracking state has bit sync. */
+    public static final int STATE_BIT_SYNC = (1<<1);
+    /** This GNSS measurement's tracking state has sub-frame sync. */
+    public static final int STATE_SUBFRAME_SYNC = (1<<2);
+    /** This GNSS measurement's tracking state has time-of-week decoded. */
+    public static final int STATE_TOW_DECODED = (1<<3);
+    /** This GNSS measurement's tracking state contains millisecond ambiguity. */
+    public static final int STATE_MSEC_AMBIGUOUS = (1<<4);
+    /** This GNSS measurement's tracking state has symbol sync. */
+    public static final int STATE_SYMBOL_SYNC = (1<<5);
+    /** This Glonass measurement's tracking state has string sync. */
+    public static final int STATE_GLO_STRING_SYNC = (1<<6);
+    /** This Glonass measurement's tracking state has time-of-day decoded. */
+    public static final int STATE_GLO_TOD_DECODED = (1<<7);
+    /** This Beidou measurement's tracking state has D2 bit sync. */
+    public static final int STATE_BDS_D2_BIT_SYNC = (1<<8);
+    /** This Beidou measurement's tracking state has D2 sub-frame sync. */
+    public static final int STATE_BDS_D2_SUBFRAME_SYNC = (1<<9);
+    /** This Galileo measurement's tracking state has E1B/C code lock. */
+    public static final int STATE_GAL_E1BC_CODE_LOCK = (1<<10);
+    /** This Galileo measurement's tracking state has E1C secondary code lock. */
+    public static final int STATE_GAL_E1C_2ND_CODE_LOCK = (1<<11);
+    /** This Galileo measurement's tracking state has E1B page sync. */
+    public static final int STATE_GAL_E1B_PAGE_SYNC = (1<<12);
+    /** This SBAS measurement's tracking state has whole second level sync. */
+    public static final int STATE_SBAS_SYNC = (1<<13);
 
     /**
-     * The state of GNSS receiver the measurement is invalid or unknown.
+     * All the GNSS receiver state flags, for bit masking purposes (not a sensible state for any
+     * individual measurement.)
      */
-    public static final short STATE_UNKNOWN = 0;
-
-    /**
-     * The state of the GNSS receiver is ranging code lock.
-     */
-    public static final short STATE_CODE_LOCK = (1<<0);
-
-    /**
-     * The state of the GNSS receiver is in bit sync.
-     */
-    public static final short STATE_BIT_SYNC = (1<<1);
-
-    /**
-     *The state of the GNSS receiver is in sub-frame sync.
-     */
-    public static final short STATE_SUBFRAME_SYNC = (1<<2);
-
-    /**
-     * The state of the GNSS receiver has TOW decoded.
-     */
-    public static final short STATE_TOW_DECODED = (1<<3);
-
-    /**
-     * The state of the GNSS receiver contains millisecond ambiguity.
-     */
-    public static final short STATE_MSEC_AMBIGUOUS = (1<<4);
-
-    /**
-     * All the GNSS receiver state flags.
-     */
-    private static final short STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
-            | STATE_TOW_DECODED | STATE_MSEC_AMBIGUOUS;
+    private static final int STATE_ALL = 0x3fff;  // 2 bits + 4 bits + 4 bits + 4 bits = 14 bits
 
     /**
      * The state of the 'Accumulated Delta Range' is invalid or unknown.
      */
-    public static final short ADR_STATE_UNKNOWN = 0;
+    public static final int ADR_STATE_UNKNOWN = 0;
 
     /**
      * The state of the 'Accumulated Delta Range' is valid.
      */
-    public static final short ADR_STATE_VALID = (1<<0);
+    public static final int ADR_STATE_VALID = (1<<0);
 
     /**
      * The state of the 'Accumulated Delta Range' has detected a reset.
      */
-    public static final short ADR_STATE_RESET = (1<<1);
+    public static final int ADR_STATE_RESET = (1<<1);
 
     /**
      * The state of the 'Accumulated Delta Range' has a cycle slip detected.
      */
-    public static final short ADR_STATE_CYCLE_SLIP = (1<<2);
+    public static final int ADR_STATE_CYCLE_SLIP = (1<<2);
 
     /**
      * All the 'Accumulated Delta Range' flags.
      */
-    private static final short ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
+    private static final int ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
 
     // End enumerations in sync with gps.h
 
-    GnssMeasurement() {
+    /**
+     * @hide
+     */
+    @TestApi
+    public GnssMeasurement() {
         initialize();
     }
 
     /**
      * Sets all contents to the values stored in the provided object.
+     * @hide
      */
+    @TestApi
     public void set(GnssMeasurement measurement) {
         mFlags = measurement.mFlags;
         mSvid = measurement.mSvid;
         mConstellationType = measurement.mConstellationType;
-        mTimeOffsetInNs = measurement.mTimeOffsetInNs;
+        mTimeOffsetNanos = measurement.mTimeOffsetNanos;
         mState = measurement.mState;
-        mReceivedSvTimeInNs = measurement.mReceivedSvTimeInNs;
-        mReceivedSvTimeUncertaintyInNs = measurement.mReceivedSvTimeUncertaintyInNs;
-        mCn0InDbHz = measurement.mCn0InDbHz;
-        mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec;
-        mPseudorangeRateUncertaintyInMetersPerSec =
-                measurement.mPseudorangeRateUncertaintyInMetersPerSec;
+        mReceivedSvTimeNanos = measurement.mReceivedSvTimeNanos;
+        mReceivedSvTimeUncertaintyNanos = measurement.mReceivedSvTimeUncertaintyNanos;
+        mCn0DbHz = measurement.mCn0DbHz;
+        mPseudorangeRateMetersPerSecond = measurement.mPseudorangeRateMetersPerSecond;
+        mPseudorangeRateUncertaintyMetersPerSecond =
+                measurement.mPseudorangeRateUncertaintyMetersPerSecond;
         mAccumulatedDeltaRangeState = measurement.mAccumulatedDeltaRangeState;
-        mAccumulatedDeltaRangeInMeters = measurement.mAccumulatedDeltaRangeInMeters;
-        mAccumulatedDeltaRangeUncertaintyInMeters =
-                measurement.mAccumulatedDeltaRangeUncertaintyInMeters;
-        mPseudorangeInMeters = measurement.mPseudorangeInMeters;
-        mPseudorangeUncertaintyInMeters = measurement.mPseudorangeUncertaintyInMeters;
-        mCodePhaseInChips = measurement.mCodePhaseInChips;
-        mCodePhaseUncertaintyInChips = measurement.mCodePhaseUncertaintyInChips;
-        mCarrierFrequencyInHz = measurement.mCarrierFrequencyInHz;
+        mAccumulatedDeltaRangeMeters = measurement.mAccumulatedDeltaRangeMeters;
+        mAccumulatedDeltaRangeUncertaintyMeters =
+                measurement.mAccumulatedDeltaRangeUncertaintyMeters;
+        mCarrierFrequencyHz = measurement.mCarrierFrequencyHz;
         mCarrierCycles = measurement.mCarrierCycles;
         mCarrierPhase = measurement.mCarrierPhase;
         mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty;
-        mLossOfLock = measurement.mLossOfLock;
-        mBitNumber = measurement.mBitNumber;
-        mTimeFromLastBitInMs = measurement.mTimeFromLastBitInMs;
-        mDopplerShiftInHz = measurement.mDopplerShiftInHz;
-        mDopplerShiftUncertaintyInHz = measurement.mDopplerShiftUncertaintyInHz;
         mMultipathIndicator = measurement.mMultipathIndicator;
         mSnrInDb = measurement.mSnrInDb;
-        mElevationInDeg = measurement.mElevationInDeg;
-        mElevationUncertaintyInDeg = measurement.mElevationUncertaintyInDeg;
-        mAzimuthInDeg = measurement.mAzimuthInDeg;
-        mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
-        mUsedInFix = measurement.mUsedInFix;
     }
 
     /**
      * Resets all the contents to its original state.
+     * @hide
      */
+    @TestApi
     public void reset() {
         initialize();
     }
@@ -244,14 +195,16 @@
      * Gets the Pseudo-random number (PRN).
      * Range: [1, 32]
      */
-    public short getSvid() {
+    public int getSvid() {
         return mSvid;
     }
 
     /**
      * Sets the Pseud-random number (PRN).
+     * @hide
      */
-    public void setSvid(short value) {
+    @TestApi
+    public void setSvid(int value) {
         mSvid = value;
     }
 
@@ -259,21 +212,24 @@
      * Getst the constellation type.
      */
     @GnssStatus.ConstellationType
-    public byte getConstellationType() {
+    public int getConstellationType() {
         return mConstellationType;
     }
 
     /**
      * Sets the constellation type.
+     * @hide
      */
-    public void setConstellationType(@GnssStatus.ConstellationType byte value) {
+    @TestApi
+    public void setConstellationType(@GnssStatus.ConstellationType int value) {
         mConstellationType = value;
     }
 
     /**
      * Gets the time offset at which the measurement was taken in nanoseconds.
-     * The reference receiver's time is specified by {@link GnssClock#getTimeInNs()} and should be
-     * interpreted in the same way as indicated by {@link GnssClock#getType()}.
+     *
+     * The reference receiver's time from which this is offset is specified by
+     * {@link GnssClock#getTimeNanos()}.
      *
      * The sign of this value is given by the following equation:
      *      measurement time = time_ns + time_offset_ns
@@ -281,31 +237,35 @@
      * The value provides an individual time-stamp for the measurement, and allows sub-nanosecond
      * accuracy.
      */
-    public double getTimeOffsetInNs() {
-        return mTimeOffsetInNs;
+    public double getTimeOffsetNanos() {
+        return mTimeOffsetNanos;
     }
 
     /**
      * Sets the time offset at which the measurement was taken in nanoseconds.
+     * @hide
      */
-    public void setTimeOffsetInNs(double value) {
-        mTimeOffsetInNs = value;
+    @TestApi
+    public void setTimeOffsetNanos(double value) {
+        mTimeOffsetNanos = value;
     }
 
     /**
      * Gets per-satellite sync state.
      * It represents the current sync state for the associated satellite.
      *
-     * This value helps interpret {@link #getReceivedSvTimeInNs()}.
+     * This value helps interpret {@link #getReceivedSvTimeNanos()}.
      */
-    public short getState() {
+    public int getState() {
         return mState;
     }
 
     /**
      * Sets the sync state.
+     * @hide
      */
-    public void setState(short value) {
+    @TestApi
+    public void setState(int value) {
         mState = value;
     }
 
@@ -317,29 +277,58 @@
         if (mState == STATE_UNKNOWN) {
             return "Unknown";
         }
+
         StringBuilder builder = new StringBuilder();
-        if ((mState & STATE_CODE_LOCK) == STATE_CODE_LOCK) {
+        if ((mState & STATE_CODE_LOCK) != 0) {
             builder.append("CodeLock|");
         }
-        if ((mState & STATE_BIT_SYNC) == STATE_BIT_SYNC) {
+        if ((mState & STATE_BIT_SYNC) != 0) {
             builder.append("BitSync|");
         }
-        if ((mState & STATE_SUBFRAME_SYNC) == STATE_SUBFRAME_SYNC) {
+        if ((mState & STATE_SUBFRAME_SYNC) != 0) {
             builder.append("SubframeSync|");
         }
-        if ((mState & STATE_TOW_DECODED) == STATE_TOW_DECODED) {
+        if ((mState & STATE_TOW_DECODED) != 0) {
             builder.append("TowDecoded|");
         }
-        if ((mState & STATE_MSEC_AMBIGUOUS) == STATE_MSEC_AMBIGUOUS) {
-            builder.append("MsecAmbiguous");
+        if ((mState & STATE_MSEC_AMBIGUOUS) != 0) {
+            builder.append("MsecAmbiguous|");
         }
+        if ((mState & STATE_SYMBOL_SYNC) != 0) {
+            builder.append("SymbolSync|");
+        }
+        if ((mState & STATE_GLO_STRING_SYNC) != 0) {
+            builder.append("GloStringSync|");
+        }
+        if ((mState & STATE_GLO_TOD_DECODED) != 0) {
+            builder.append("GloTodDecoded|");
+        }
+        if ((mState & STATE_BDS_D2_BIT_SYNC) != 0) {
+            builder.append("BdsD2BitSync|");
+        }
+        if ((mState & STATE_BDS_D2_SUBFRAME_SYNC) != 0) {
+            builder.append("BdsD2SubframeSync|");
+        }
+        if ((mState & STATE_GAL_E1BC_CODE_LOCK) != 0) {
+            builder.append("GalE1bcCodeLock|");
+        }
+        if ((mState & STATE_GAL_E1C_2ND_CODE_LOCK) != 0) {
+            builder.append("E1c2ndCodeLock|");
+        }
+        if ((mState & STATE_GAL_E1B_PAGE_SYNC) != 0) {
+            builder.append("GalE1bPageSync|");
+        }
+        if ((mState & STATE_SBAS_SYNC) != 0) {
+            builder.append("SbasSync|");
+        }
+
         int remainingStates = mState & ~STATE_ALL;
         if (remainingStates > 0) {
             builder.append("Other(");
             builder.append(Integer.toBinaryString(remainingStates));
             builder.append(")|");
         }
-        builder.deleteCharAt(builder.length() - 1);
+        builder.setLength(builder.length() - 1);
         return builder.toString();
     }
 
@@ -407,29 +396,33 @@
      *     Symbol sync     : [ 0   2ms ]   : STATE_SYMBOL_SYNC is set
      *     Message         : [ 0    1s ]   : STATE_SBAS_SYNC is set
      */
-    public long getReceivedSvTimeInNs() {
-        return mReceivedSvTimeInNs;
+    public long getReceivedSvTimeNanos() {
+        return mReceivedSvTimeNanos;
     }
 
     /**
      * Sets the received GNSS time in nanoseconds.
+     * @hide
      */
-    public void setReceivedSvTimeInNs(long value) {
-        mReceivedSvTimeInNs = value;
+    @TestApi
+    public void setReceivedSvTimeNanos(long value) {
+        mReceivedSvTimeNanos = value;
     }
 
     /**
      * Gets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
      */
-    public long getReceivedSvTimeUncertaintyInNs() {
-        return mReceivedSvTimeUncertaintyInNs;
+    public long getReceivedSvTimeUncertaintyNanos() {
+        return mReceivedSvTimeUncertaintyNanos;
     }
 
     /**
      * Sets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
+     * @hide
      */
-    public void setReceivedSvTimeUncertaintyInNs(long value) {
-        mReceivedSvTimeUncertaintyInNs = value;
+    @TestApi
+    public void setReceivedSvTimeUncertaintyNanos(long value) {
+        mReceivedSvTimeUncertaintyNanos = value;
     }
 
     /**
@@ -438,79 +431,78 @@
      *
      * The value contains the measured C/N0 for the signal at the antenna input.
      */
-    public double getCn0InDbHz() {
-        return mCn0InDbHz;
+    public double getCn0DbHz() {
+        return mCn0DbHz;
     }
 
     /**
      * Sets the carrier-to-noise density in dB-Hz.
+     * @hide
      */
-    public void setCn0InDbHz(double value) {
-        mCn0InDbHz = value;
+    @TestApi
+    public void setCn0DbHz(double value) {
+        mCn0DbHz = value;
     }
 
     /**
      * Gets the Pseudorange rate at the timestamp in m/s.
-     * The reported value includes {@link #getPseudorangeRateUncertaintyInMetersPerSec()}.
      *
-     * The correction of a given Pseudorange Rate value includes corrections from receiver and
-     * satellite clock frequency errors.
-     * {@link #isPseudorangeRateCorrected()} identifies the type of value reported.
+     * The reported value includes {@link #getPseudorangeRateUncertaintyMetersPerSecond()}.
      *
-     * A positive 'uncorrected' value indicates that the SV is moving away from the receiver.
-     * The sign of the 'uncorrected' Pseudorange Rate and its relation to the sign of
-     * {@link #getDopplerShiftInHz()} is given by the equation:
+     * The value is uncorrected, hence corrections for receiver and satellite clock frequency errors
+     * should not be included.
+     *
+     * A positive 'uncorrected' value indicates that the SV is moving away from the receiver. The
+     * sign of the 'uncorrected' 'pseudorange rate' and its relation to the sign of 'doppler shift'
+     * is given by the equation:
+     *
      *      pseudorange rate = -k * doppler shift   (where k is a constant)
      */
-    public double getPseudorangeRateInMetersPerSec() {
-        return mPseudorangeRateInMetersPerSec;
+    public double getPseudorangeRateMetersPerSecond() {
+        return mPseudorangeRateMetersPerSecond;
     }
 
     /**
      * Sets the pseudorange rate at the timestamp in m/s.
+     * @hide
      */
-    public void setPseudorangeRateInMetersPerSec(double value) {
-        mPseudorangeRateInMetersPerSec = value;
-    }
-
-    /**
-     * See {@link #getPseudorangeRateInMetersPerSec()} for more details.
-     *
-     * @return {@code true} if {@link #getPseudorangeRateInMetersPerSec()} contains a corrected
-     *         value, {@code false} if it contains an uncorrected value.
-     */
-    public boolean isPseudorangeRateCorrected() {
-        return !isFlagSet(HAS_UNCORRECTED_PSEUDORANGE_RATE);
+    @TestApi
+    public void setPseudorangeRateMetersPerSecond(double value) {
+        mPseudorangeRateMetersPerSecond = value;
     }
 
     /**
      * Gets the pseudorange's rate uncertainty (1-Sigma) in m/s.
      * The uncertainty is represented as an absolute (single sided) value.
      */
-    public double getPseudorangeRateUncertaintyInMetersPerSec() {
-        return mPseudorangeRateUncertaintyInMetersPerSec;
+    public double getPseudorangeRateUncertaintyMetersPerSecond() {
+        return mPseudorangeRateUncertaintyMetersPerSecond;
     }
 
     /**
      * Sets the pseudorange's rate uncertainty (1-Sigma) in m/s.
+     * @hide
      */
-    public void setPseudorangeRateUncertaintyInMetersPerSec(double value) {
-        mPseudorangeRateUncertaintyInMetersPerSec = value;
+    @TestApi
+    public void setPseudorangeRateUncertaintyMetersPerSecond(double value) {
+        mPseudorangeRateUncertaintyMetersPerSecond = value;
     }
 
     /**
      * Gets 'Accumulated Delta Range' state.
-     * It indicates whether {@link #getAccumulatedDeltaRangeInMeters()} is reset or there is a
+     * It indicates whether {@link #getAccumulatedDeltaRangeMeters()} is reset or there is a
      * cycle slip (indicating 'loss of lock').
      */
-    public short getAccumulatedDeltaRangeState() {
+    public int getAccumulatedDeltaRangeState() {
         return mAccumulatedDeltaRangeState;
     }
 
     /**
      * Sets the 'Accumulated Delta Range' state.
+     * @hide
      */
-    public void setAccumulatedDeltaRangeState(short value) {
+    @TestApi
+    public void setAccumulatedDeltaRangeState(int value) {
         mAccumulatedDeltaRangeState = value;
     }
 
@@ -544,24 +536,26 @@
 
     /**
      * Gets the accumulated delta range since the last channel reset, in meters.
-     * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyInMeters()}.
+     * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyMeters()}.
      *
      * The availability of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
      *
      * A positive value indicates that the SV is moving away from the receiver.
-     * The sign of {@link #getAccumulatedDeltaRangeInMeters()} and its relation to the sign of
+     * The sign of {@link #getAccumulatedDeltaRangeMeters()} and its relation to the sign of
      * {@link #getCarrierPhase()} is given by the equation:
      *          accumulated delta range = -k * carrier phase    (where k is a constant)
      */
-    public double getAccumulatedDeltaRangeInMeters() {
-        return mAccumulatedDeltaRangeInMeters;
+    public double getAccumulatedDeltaRangeMeters() {
+        return mAccumulatedDeltaRangeMeters;
     }
 
     /**
      * Sets the accumulated delta range in meters.
+     * @hide
      */
-    public void setAccumulatedDeltaRangeInMeters(double value) {
-        mAccumulatedDeltaRangeInMeters = value;
+    @TestApi
+    public void setAccumulatedDeltaRangeMeters(double value) {
+        mAccumulatedDeltaRangeMeters = value;
     }
 
     /**
@@ -570,158 +564,26 @@
      *
      * The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
      */
-    public double getAccumulatedDeltaRangeUncertaintyInMeters() {
-        return mAccumulatedDeltaRangeUncertaintyInMeters;
+    public double getAccumulatedDeltaRangeUncertaintyMeters() {
+        return mAccumulatedDeltaRangeUncertaintyMeters;
     }
 
     /**
      * Sets the accumulated delta range's uncertainty (1-sigma) in meters.
      *
      * The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
-     */
-    public void setAccumulatedDeltaRangeUncertaintyInMeters(double value) {
-        mAccumulatedDeltaRangeUncertaintyInMeters = value;
-    }
-
-    /**
-     * Returns true if {@link #getPseudorangeInMeters()} is available, false otherwise.
-     */
-    public boolean hasPseudorangeInMeters() {
-        return isFlagSet(HAS_PSEUDORANGE);
-    }
-
-    /**
-     * Gets the best derived pseudorange by the chipset, in meters.
-     * The reported pseudorange includes {@link #getPseudorangeUncertaintyInMeters()}.
      *
-     * The value is only available if {@link #hasPseudorangeInMeters()} is true.
+     * @hide
      */
-    public double getPseudorangeInMeters() {
-        return mPseudorangeInMeters;
+    @TestApi
+    public void setAccumulatedDeltaRangeUncertaintyMeters(double value) {
+        mAccumulatedDeltaRangeUncertaintyMeters = value;
     }
 
     /**
-     * Sets the Pseudo-range in meters.
+     * Returns true if {@link #getCarrierFrequencyHz()} is available, false otherwise.
      */
-    public void setPseudorangeInMeters(double value) {
-        setFlag(HAS_PSEUDORANGE);
-        mPseudorangeInMeters = value;
-    }
-
-    /**
-     * Resets the Pseudo-range in meters.
-     */
-    public void resetPseudorangeInMeters() {
-        resetFlag(HAS_PSEUDORANGE);
-        mPseudorangeInMeters = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getPseudorangeUncertaintyInMeters()} is available, false otherwise.
-     */
-    public boolean hasPseudorangeUncertaintyInMeters() {
-        return isFlagSet(HAS_PSEUDORANGE_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the pseudorange's uncertainty (1-Sigma) in meters.
-     * The value contains the 'pseudorange' and 'clock' uncertainty in it.
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasPseudorangeUncertaintyInMeters()} is true.
-     */
-    public double getPseudorangeUncertaintyInMeters() {
-        return mPseudorangeUncertaintyInMeters;
-    }
-
-    /**
-     * Sets the pseudo-range's uncertainty (1-Sigma) in meters.
-     */
-    public void setPseudorangeUncertaintyInMeters(double value) {
-        setFlag(HAS_PSEUDORANGE_UNCERTAINTY);
-        mPseudorangeUncertaintyInMeters = value;
-    }
-
-    /**
-     * Resets the pseudo-range's uncertainty (1-Sigma) in meters.
-     */
-    public void resetPseudorangeUncertaintyInMeters() {
-        resetFlag(HAS_PSEUDORANGE_UNCERTAINTY);
-        mPseudorangeUncertaintyInMeters = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getCodePhaseInChips()} is available, false otherwise.
-     */
-    public boolean hasCodePhaseInChips() {
-        return isFlagSet(HAS_CODE_PHASE);
-    }
-
-    /**
-     * Gets the fraction of the current C/A code cycle.
-     * Range: [0, 1023]
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
-     * The reported code-phase includes {@link #getCodePhaseUncertaintyInChips()}.
-     *
-     * The value is only available if {@link #hasCodePhaseInChips()} is true.
-     */
-    public double getCodePhaseInChips() {
-        return mCodePhaseInChips;
-    }
-
-    /**
-     * Sets the Code-phase in chips.
-     */
-    public void setCodePhaseInChips(double value) {
-        setFlag(HAS_CODE_PHASE);
-        mCodePhaseInChips = value;
-    }
-
-    /**
-     * Resets the Code-phase in chips.
-     */
-    public void resetCodePhaseInChips() {
-        resetFlag(HAS_CODE_PHASE);
-        mCodePhaseInChips = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getCodePhaseUncertaintyInChips()} is available, false otherwise.
-     */
-    public boolean hasCodePhaseUncertaintyInChips() {
-        return isFlagSet(HAS_CODE_PHASE_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the code-phase's uncertainty (1-Sigma) as a fraction of chips.
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasCodePhaseUncertaintyInChips()} is true.
-     */
-    public double getCodePhaseUncertaintyInChips() {
-        return mCodePhaseUncertaintyInChips;
-    }
-
-    /**
-     * Sets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
-     */
-    public void setCodePhaseUncertaintyInChips(double value) {
-        setFlag(HAS_CODE_PHASE_UNCERTAINTY);
-        mCodePhaseUncertaintyInChips = value;
-    }
-
-    /**
-     * Resets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
-     */
-    public void resetCodePhaseUncertaintyInChips() {
-        resetFlag(HAS_CODE_PHASE_UNCERTAINTY);
-        mCodePhaseUncertaintyInChips = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getCarrierFrequencyInHz()} is available, false otherwise.
-     */
-    public boolean hasCarrierFrequencyInHz() {
+    public boolean hasCarrierFrequencyHz() {
         return isFlagSet(HAS_CARRIER_FREQUENCY);
     }
 
@@ -729,26 +591,30 @@
      * Gets the carrier frequency at which codes and messages are modulated, it can be L1 or L2.
      * If the field is not set, the carrier frequency corresponds to L1.
      *
-     * The value is only available if {@link #hasCarrierFrequencyInHz()} is true.
+     * The value is only available if {@link #hasCarrierFrequencyHz()} is true.
      */
-    public float getCarrierFrequencyInHz() {
-        return mCarrierFrequencyInHz;
+    public float getCarrierFrequencyHz() {
+        return mCarrierFrequencyHz;
     }
 
     /**
      * Sets the Carrier frequency (L1 or L2) in Hz.
+     * @hide
      */
-    public void setCarrierFrequencyInHz(float carrierFrequencyInHz) {
+    @TestApi
+    public void setCarrierFrequencyHz(float carrierFrequencyHz) {
         setFlag(HAS_CARRIER_FREQUENCY);
-        mCarrierFrequencyInHz = carrierFrequencyInHz;
+        mCarrierFrequencyHz = carrierFrequencyHz;
     }
 
     /**
      * Resets the Carrier frequency (L1 or L2) in Hz.
+     * @hide
      */
-    public void resetCarrierFrequencyInHz() {
+    @TestApi
+    public void resetCarrierFrequencyHz() {
         resetFlag(HAS_CARRIER_FREQUENCY);
-        mCarrierFrequencyInHz = Float.NaN;
+        mCarrierFrequencyHz = Float.NaN;
     }
 
     /**
@@ -760,7 +626,7 @@
 
     /**
      * The number of full carrier cycles between the satellite and the receiver.
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+     * The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}.
      *
      * The value is only available if {@link #hasCarrierCycles()} is true.
      */
@@ -770,7 +636,9 @@
 
     /**
      * Sets the number of full carrier cycles between the satellite and the receiver.
+     * @hide
      */
+    @TestApi
     public void setCarrierCycles(long value) {
         setFlag(HAS_CARRIER_CYCLES);
         mCarrierCycles = value;
@@ -778,7 +646,9 @@
 
     /**
      * Resets the number of full carrier cycles between the satellite and the receiver.
+     * @hide
      */
+    @TestApi
     public void resetCarrierCycles() {
         resetFlag(HAS_CARRIER_CYCLES);
         mCarrierCycles = Long.MIN_VALUE;
@@ -796,7 +666,7 @@
      * Range: [0.0, 1.0].
      * This is usually the fractional part of the complete carrier phase measurement.
      *
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+     * The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}.
      * The reported carrier-phase includes {@link #getCarrierPhaseUncertainty()}.
      *
      * The value is only available if {@link #hasCarrierPhase()} is true.
@@ -807,7 +677,9 @@
 
     /**
      * Sets the RF phase detected by the receiver.
+     * @hide
      */
+    @TestApi
     public void setCarrierPhase(double value) {
         setFlag(HAS_CARRIER_PHASE);
         mCarrierPhase = value;
@@ -815,7 +687,9 @@
 
     /**
      * Resets the RF phase detected by the receiver.
+     * @hide
      */
+    @TestApi
     public void resetCarrierPhase() {
         resetFlag(HAS_CARRIER_PHASE);
         mCarrierPhase = Double.NaN;
@@ -840,7 +714,9 @@
 
     /**
      * Sets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+     * @hide
      */
+    @TestApi
     public void setCarrierPhaseUncertainty(double value) {
         setFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
         mCarrierPhaseUncertainty = value;
@@ -848,190 +724,28 @@
 
     /**
      * Resets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+     * @hide
      */
+    @TestApi
     public void resetCarrierPhaseUncertainty() {
         resetFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
         mCarrierPhaseUncertainty = Double.NaN;
     }
 
     /**
-     * Gets a value indicating the 'loss of lock' state of the event.
-     */
-    @LossOfLockStatus
-    public byte getLossOfLock() {
-        return mLossOfLock;
-    }
-
-    /**
-     * Sets the 'loss of lock' status.
-     */
-    public void setLossOfLock(@LossOfLockStatus byte value) {
-        mLossOfLock = value;
-    }
-
-    /**
-     * Gets a string representation of the 'loss of lock'.
-     * For internal and logging use only.
-     */
-    private String getLossOfLockString() {
-        switch (mLossOfLock) {
-            case LOSS_OF_LOCK_UNKNOWN:
-                return "Unknown";
-            case LOSS_OF_LOCK_OK:
-                return "Ok";
-            case LOSS_OF_LOCK_CYCLE_SLIP:
-                return "CycleSlip";
-            default:
-                return "<Invalid:" + mLossOfLock + ">";
-        }
-    }
-
-    /**
-     * Returns true if {@link #getBitNumber()} is available, false otherwise.
-     */
-    public boolean hasBitNumber() {
-        return isFlagSet(HAS_BIT_NUMBER);
-    }
-
-    /**
-     * Gets the number of GPS bits transmitted since Sat-Sun midnight (GPS week).
-     *
-     * The value is only available if {@link #hasBitNumber()} is true.
-     */
-    public int getBitNumber() {
-        return mBitNumber;
-    }
-
-    /**
-     * Sets the bit number within the broadcast frame.
-     */
-    public void setBitNumber(int bitNumber) {
-        setFlag(HAS_BIT_NUMBER);
-        mBitNumber = bitNumber;
-    }
-
-    /**
-     * Resets the bit number within the broadcast frame.
-     */
-    public void resetBitNumber() {
-        resetFlag(HAS_BIT_NUMBER);
-        mBitNumber = Integer.MIN_VALUE;
-    }
-
-    /**
-     * Returns true if {@link #getTimeFromLastBitInMs()} is available, false otherwise.
-     */
-    public boolean hasTimeFromLastBitInMs() {
-        return isFlagSet(HAS_TIME_FROM_LAST_BIT);
-    }
-
-    /**
-     * Gets the elapsed time since the last received bit in milliseconds.
-     * Range: [0, 20].
-     *
-     * The value is only available if {@link #hasTimeFromLastBitInMs()} is true.
-     */
-    public short getTimeFromLastBitInMs() {
-        return mTimeFromLastBitInMs;
-    }
-
-    /**
-     * Sets the elapsed time since the last received bit in milliseconds.
-     */
-    public void setTimeFromLastBitInMs(short value) {
-        setFlag(HAS_TIME_FROM_LAST_BIT);
-        mTimeFromLastBitInMs = value;
-    }
-
-    /**
-     * Resets the elapsed time since the last received bit in milliseconds.
-     */
-    public void resetTimeFromLastBitInMs() {
-        resetFlag(HAS_TIME_FROM_LAST_BIT);
-        mTimeFromLastBitInMs = Short.MIN_VALUE;
-    }
-
-    /**
-     * Returns true if {@link #getDopplerShiftInHz()} is available, false otherwise.
-     */
-    public boolean hasDopplerShiftInHz() {
-        return isFlagSet(HAS_DOPPLER_SHIFT);
-    }
-
-    /**
-     * Gets the Doppler Shift in Hz.
-     * A positive value indicates that the SV is moving toward the receiver.
-     *
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
-     * The reported doppler shift includes {@link #getDopplerShiftUncertaintyInHz()}.
-     *
-     * The value is only available if {@link #hasDopplerShiftInHz()} is true.
-     */
-    public double getDopplerShiftInHz() {
-        return mDopplerShiftInHz;
-    }
-
-    /**
-     * Sets the Doppler shift in Hz.
-     */
-    public void setDopplerShiftInHz(double value) {
-        setFlag(HAS_DOPPLER_SHIFT);
-        mDopplerShiftInHz = value;
-    }
-
-    /**
-     * Resets the Doppler shift in Hz.
-     */
-    public void resetDopplerShiftInHz() {
-        resetFlag(HAS_DOPPLER_SHIFT);
-        mDopplerShiftInHz = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getDopplerShiftUncertaintyInHz()} is available, false otherwise.
-     */
-    public boolean hasDopplerShiftUncertaintyInHz() {
-        return isFlagSet(HAS_DOPPLER_SHIFT_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the Doppler's Shift uncertainty (1-Sigma) in Hz.
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasDopplerShiftUncertaintyInHz()} is true.
-     */
-    public double getDopplerShiftUncertaintyInHz() {
-        return mDopplerShiftUncertaintyInHz;
-    }
-
-    /**
-     * Sets the Doppler's shift uncertainty (1-Sigma) in Hz.
-     */
-    public void setDopplerShiftUncertaintyInHz(double value) {
-        setFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
-        mDopplerShiftUncertaintyInHz = value;
-    }
-
-    /**
-     * Resets the Doppler's shift uncertainty (1-Sigma) in Hz.
-     */
-    public void resetDopplerShiftUncertaintyInHz() {
-        resetFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
-        mDopplerShiftUncertaintyInHz = Double.NaN;
-    }
-
-    /**
      * Gets a value indicating the 'multipath' state of the event.
      */
     @MultipathIndicator
-    public byte getMultipathIndicator() {
+    public int getMultipathIndicator() {
         return mMultipathIndicator;
     }
 
     /**
      * Sets the 'multi-path' indicator.
+     * @hide
      */
-    public void setMultipathIndicator(@MultipathIndicator byte value) {
+    @TestApi
+    public void setMultipathIndicator(@MultipathIndicator int value) {
         mMultipathIndicator = value;
     }
 
@@ -1070,7 +784,9 @@
 
     /**
      * Sets the Signal-to-noise ratio (SNR) in dB.
+     * @hide
      */
+    @TestApi
     public void setSnrInDb(double snrInDb) {
         setFlag(HAS_SNR);
         mSnrInDb = snrInDb;
@@ -1078,206 +794,38 @@
 
     /**
      * Resets the Signal-to-noise ratio (SNR) in dB.
+     * @hide
      */
+    @TestApi
     public void resetSnrInDb() {
         resetFlag(HAS_SNR);
         mSnrInDb = Double.NaN;
     }
 
-    /**
-     * Returns true if {@link #getElevationInDeg()} is available, false otherwise.
-     */
-    public boolean hasElevationInDeg() {
-        return isFlagSet(HAS_ELEVATION);
-    }
-
-    /**
-     * Gets the Elevation in degrees.
-     * Range: [-90, 90]
-     * The reported elevation includes {@link #getElevationUncertaintyInDeg()}.
-     *
-     * The value is only available if {@link #hasElevationInDeg()} is true.
-     */
-    public double getElevationInDeg() {
-        return mElevationInDeg;
-    }
-
-    /**
-     * Sets the Elevation in degrees.
-     */
-    public void setElevationInDeg(double elevationInDeg) {
-        setFlag(HAS_ELEVATION);
-        mElevationInDeg = elevationInDeg;
-    }
-
-    /**
-     * Resets the Elevation in degrees.
-     */
-    public void resetElevationInDeg() {
-        resetFlag(HAS_ELEVATION);
-        mElevationInDeg = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getElevationUncertaintyInDeg()} is available, false otherwise.
-     */
-    public boolean hasElevationUncertaintyInDeg() {
-        return isFlagSet(HAS_ELEVATION_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the elevation's uncertainty (1-Sigma) in degrees.
-     * Range: [0, 90]
-     *
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasElevationUncertaintyInDeg()} is true.
-     */
-    public double getElevationUncertaintyInDeg() {
-        return mElevationUncertaintyInDeg;
-    }
-
-    /**
-     * Sets the elevation's uncertainty (1-Sigma) in degrees.
-     */
-    public void setElevationUncertaintyInDeg(double value) {
-        setFlag(HAS_ELEVATION_UNCERTAINTY);
-        mElevationUncertaintyInDeg = value;
-    }
-
-    /**
-     * Resets the elevation's uncertainty (1-Sigma) in degrees.
-     */
-    public void resetElevationUncertaintyInDeg() {
-        resetFlag(HAS_ELEVATION_UNCERTAINTY);
-        mElevationUncertaintyInDeg = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getAzimuthInDeg()} is available, false otherwise.
-     */
-    public boolean hasAzimuthInDeg() {
-        return isFlagSet(HAS_AZIMUTH);
-    }
-
-    /**
-     * Gets the azimuth in degrees.
-     * Range: [0, 360).
-     *
-     * The reported azimuth includes {@link #getAzimuthUncertaintyInDeg()}.
-     *
-     * The value is only available if {@link #hasAzimuthInDeg()} is true.
-     */
-    public double getAzimuthInDeg() {
-        return mAzimuthInDeg;
-    }
-
-    /**
-     * Sets the Azimuth in degrees.
-     */
-    public void setAzimuthInDeg(double value) {
-        setFlag(HAS_AZIMUTH);
-        mAzimuthInDeg = value;
-    }
-
-    /**
-     * Resets the Azimuth in degrees.
-     */
-    public void resetAzimuthInDeg() {
-        resetFlag(HAS_AZIMUTH);
-        mAzimuthInDeg = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getAzimuthUncertaintyInDeg()} is available, false otherwise.
-     */
-    public boolean hasAzimuthUncertaintyInDeg() {
-        return isFlagSet(HAS_AZIMUTH_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the azimuth's uncertainty (1-Sigma) in degrees.
-     * Range: [0, 180].
-     *
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasAzimuthUncertaintyInDeg()} is true.
-     */
-    public double getAzimuthUncertaintyInDeg() {
-        return mAzimuthUncertaintyInDeg;
-    }
-
-    /**
-     * Sets the Azimuth's uncertainty (1-Sigma) in degrees.
-     */
-    public void setAzimuthUncertaintyInDeg(double value) {
-        setFlag(HAS_AZIMUTH_UNCERTAINTY);
-        mAzimuthUncertaintyInDeg = value;
-    }
-
-    /**
-     * Resets the Azimuth's uncertainty (1-Sigma) in degrees.
-     */
-    public void resetAzimuthUncertaintyInDeg() {
-        resetFlag(HAS_AZIMUTH_UNCERTAINTY);
-        mAzimuthUncertaintyInDeg = Double.NaN;
-    }
-
-    /**
-     * Gets a flag indicating whether the GNSS represented by the measurement was used for computing
-     * the most recent fix.
-     *
-     * @return A non-null value if the data is available, null otherwise.
-     */
-    public boolean isUsedInFix() {
-        return mUsedInFix;
-    }
-
-    /**
-     * Sets the Used-in-Fix flag.
-     */
-    public void setUsedInFix(boolean value) {
-        mUsedInFix = value;
-    }
-
     public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
         @Override
         public GnssMeasurement createFromParcel(Parcel parcel) {
             GnssMeasurement gnssMeasurement = new GnssMeasurement();
 
             gnssMeasurement.mFlags = parcel.readInt();
-            gnssMeasurement.mSvid = (short) parcel.readInt();
-            gnssMeasurement.mConstellationType = parcel.readByte();
-            gnssMeasurement.mTimeOffsetInNs = parcel.readDouble();
-            gnssMeasurement.mState = (short) parcel.readInt();
-            gnssMeasurement.mReceivedSvTimeInNs = parcel.readLong();
-            gnssMeasurement.mReceivedSvTimeUncertaintyInNs = parcel.readLong();
-            gnssMeasurement.mCn0InDbHz = parcel.readDouble();
-            gnssMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble();
-            gnssMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble();
-            gnssMeasurement.mAccumulatedDeltaRangeState = (short) parcel.readInt();
-            gnssMeasurement.mAccumulatedDeltaRangeInMeters = parcel.readDouble();
-            gnssMeasurement.mAccumulatedDeltaRangeUncertaintyInMeters = parcel.readDouble();
-            gnssMeasurement.mPseudorangeInMeters = parcel.readDouble();
-            gnssMeasurement.mPseudorangeUncertaintyInMeters = parcel.readDouble();
-            gnssMeasurement.mCodePhaseInChips = parcel.readDouble();
-            gnssMeasurement.mCodePhaseUncertaintyInChips = parcel.readDouble();
-            gnssMeasurement.mCarrierFrequencyInHz = parcel.readFloat();
+            gnssMeasurement.mSvid = parcel.readInt();
+            gnssMeasurement.mConstellationType = parcel.readInt();
+            gnssMeasurement.mTimeOffsetNanos = parcel.readDouble();
+            gnssMeasurement.mState = parcel.readInt();
+            gnssMeasurement.mReceivedSvTimeNanos = parcel.readLong();
+            gnssMeasurement.mReceivedSvTimeUncertaintyNanos = parcel.readLong();
+            gnssMeasurement.mCn0DbHz = parcel.readDouble();
+            gnssMeasurement.mPseudorangeRateMetersPerSecond = parcel.readDouble();
+            gnssMeasurement.mPseudorangeRateUncertaintyMetersPerSecond = parcel.readDouble();
+            gnssMeasurement.mAccumulatedDeltaRangeState = parcel.readInt();
+            gnssMeasurement.mAccumulatedDeltaRangeMeters = parcel.readDouble();
+            gnssMeasurement.mAccumulatedDeltaRangeUncertaintyMeters = parcel.readDouble();
+            gnssMeasurement.mCarrierFrequencyHz = parcel.readFloat();
             gnssMeasurement.mCarrierCycles = parcel.readLong();
             gnssMeasurement.mCarrierPhase = parcel.readDouble();
             gnssMeasurement.mCarrierPhaseUncertainty = parcel.readDouble();
-            gnssMeasurement.mLossOfLock = parcel.readByte();
-            gnssMeasurement.mBitNumber = parcel.readInt();
-            gnssMeasurement.mTimeFromLastBitInMs = (short) parcel.readInt();
-            gnssMeasurement.mDopplerShiftInHz = parcel.readDouble();
-            gnssMeasurement.mDopplerShiftUncertaintyInHz = parcel.readDouble();
-            gnssMeasurement.mMultipathIndicator = parcel.readByte();
+            gnssMeasurement.mMultipathIndicator = parcel.readInt();
             gnssMeasurement.mSnrInDb = parcel.readDouble();
-            gnssMeasurement.mElevationInDeg = parcel.readDouble();
-            gnssMeasurement.mElevationUncertaintyInDeg = parcel.readDouble();
-            gnssMeasurement.mAzimuthInDeg = parcel.readDouble();
-            gnssMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
-            gnssMeasurement.mUsedInFix = parcel.readInt() != 0;
 
             return gnssMeasurement;
         }
@@ -1292,37 +840,23 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mFlags);
         parcel.writeInt(mSvid);
-        parcel.writeByte(mConstellationType);
-        parcel.writeDouble(mTimeOffsetInNs);
+        parcel.writeInt(mConstellationType);
+        parcel.writeDouble(mTimeOffsetNanos);
         parcel.writeInt(mState);
-        parcel.writeLong(mReceivedSvTimeInNs);
-        parcel.writeLong(mReceivedSvTimeUncertaintyInNs);
-        parcel.writeDouble(mCn0InDbHz);
-        parcel.writeDouble(mPseudorangeRateInMetersPerSec);
-        parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec);
+        parcel.writeLong(mReceivedSvTimeNanos);
+        parcel.writeLong(mReceivedSvTimeUncertaintyNanos);
+        parcel.writeDouble(mCn0DbHz);
+        parcel.writeDouble(mPseudorangeRateMetersPerSecond);
+        parcel.writeDouble(mPseudorangeRateUncertaintyMetersPerSecond);
         parcel.writeInt(mAccumulatedDeltaRangeState);
-        parcel.writeDouble(mAccumulatedDeltaRangeInMeters);
-        parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyInMeters);
-        parcel.writeDouble(mPseudorangeInMeters);
-        parcel.writeDouble(mPseudorangeUncertaintyInMeters);
-        parcel.writeDouble(mCodePhaseInChips);
-        parcel.writeDouble(mCodePhaseUncertaintyInChips);
-        parcel.writeFloat(mCarrierFrequencyInHz);
+        parcel.writeDouble(mAccumulatedDeltaRangeMeters);
+        parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyMeters);
+        parcel.writeFloat(mCarrierFrequencyHz);
         parcel.writeLong(mCarrierCycles);
         parcel.writeDouble(mCarrierPhase);
         parcel.writeDouble(mCarrierPhaseUncertainty);
-        parcel.writeByte(mLossOfLock);
-        parcel.writeInt(mBitNumber);
-        parcel.writeInt(mTimeFromLastBitInMs);
-        parcel.writeDouble(mDopplerShiftInHz);
-        parcel.writeDouble(mDopplerShiftUncertaintyInHz);
-        parcel.writeByte(mMultipathIndicator);
+        parcel.writeInt(mMultipathIndicator);
         parcel.writeDouble(mSnrInDb);
-        parcel.writeDouble(mElevationInDeg);
-        parcel.writeDouble(mElevationUncertaintyInDeg);
-        parcel.writeDouble(mAzimuthInDeg);
-        parcel.writeDouble(mAzimuthUncertaintyInDeg);
-        parcel.writeInt(mUsedInFix ? 1 : 0);
     }
 
     @Override
@@ -1338,29 +872,25 @@
 
         builder.append(String.format(format, "Svid", mSvid));
         builder.append(String.format(format, "ConstellationType", mConstellationType));
-        builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs));
+        builder.append(String.format(format, "TimeOffsetNanos", mTimeOffsetNanos));
 
         builder.append(String.format(format, "State", getStateString()));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "ReceivedSvTimeInNs",
-                mReceivedSvTimeInNs,
-                "ReceivedSvTimeUncertaintyInNs",
-                mReceivedSvTimeUncertaintyInNs));
+                "ReceivedSvTimeNanos",
+                mReceivedSvTimeNanos,
+                "ReceivedSvTimeUncertaintyNanos",
+                mReceivedSvTimeUncertaintyNanos));
 
-        builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz));
+        builder.append(String.format(format, "Cn0DbHz", mCn0DbHz));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "PseudorangeRateInMetersPerSec",
-                mPseudorangeRateInMetersPerSec,
-                "PseudorangeRateUncertaintyInMetersPerSec",
-                mPseudorangeRateUncertaintyInMetersPerSec));
-        builder.append(String.format(
-                format,
-                "PseudorangeRateIsCorrected",
-                isPseudorangeRateCorrected()));
+                "PseudorangeRateMetersPerSecond",
+                mPseudorangeRateMetersPerSecond,
+                "PseudorangeRateUncertaintyMetersPerSecond",
+                mPseudorangeRateUncertaintyMetersPerSecond));
 
         builder.append(String.format(
                 format,
@@ -1369,29 +899,15 @@
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "AccumulatedDeltaRangeInMeters",
-                mAccumulatedDeltaRangeInMeters,
-                "AccumulatedDeltaRangeUncertaintyInMeters",
-                mAccumulatedDeltaRangeUncertaintyInMeters));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "PseudorangeInMeters",
-                hasPseudorangeInMeters() ? mPseudorangeInMeters : null,
-                "PseudorangeUncertaintyInMeters",
-                hasPseudorangeUncertaintyInMeters() ? mPseudorangeUncertaintyInMeters : null));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "CodePhaseInChips",
-                hasCodePhaseInChips() ? mCodePhaseInChips : null,
-                "CodePhaseUncertaintyInChips",
-                hasCodePhaseUncertaintyInChips() ? mCodePhaseUncertaintyInChips : null));
+                "AccumulatedDeltaRangeMeters",
+                mAccumulatedDeltaRangeMeters,
+                "AccumulatedDeltaRangeUncertaintyMeters",
+                mAccumulatedDeltaRangeUncertaintyMeters));
 
         builder.append(String.format(
                 format,
-                "CarrierFrequencyInHz",
-                hasCarrierFrequencyInHz() ? mCarrierFrequencyInHz : null));
+                "CarrierFrequencyHz",
+                hasCarrierFrequencyHz() ? mCarrierFrequencyHz : null));
 
         builder.append(String.format(
                 format,
@@ -1405,25 +921,6 @@
                 "CarrierPhaseUncertainty",
                 hasCarrierPhaseUncertainty() ? mCarrierPhaseUncertainty : null));
 
-        builder.append(String.format(format, "LossOfLock", getLossOfLockString()));
-
-        builder.append(String.format(
-                format,
-                "BitNumber",
-                hasBitNumber() ? mBitNumber : null));
-
-        builder.append(String.format(
-                format,
-                "TimeFromLastBitInMs",
-                hasTimeFromLastBitInMs() ? mTimeFromLastBitInMs : null));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "DopplerShiftInHz",
-                hasDopplerShiftInHz() ? mDopplerShiftInHz : null,
-                "DopplerShiftUncertaintyInHz",
-                hasDopplerShiftUncertaintyInHz() ? mDopplerShiftUncertaintyInHz : null));
-
         builder.append(String.format(format, "MultipathIndicator", getMultipathIndicatorString()));
 
         builder.append(String.format(
@@ -1431,58 +928,28 @@
                 "SnrInDb",
                 hasSnrInDb() ? mSnrInDb : null));
 
-        builder.append(String.format(
-                formatWithUncertainty,
-                "ElevationInDeg",
-                hasElevationInDeg() ? mElevationInDeg : null,
-                "ElevationUncertaintyInDeg",
-                hasElevationUncertaintyInDeg() ? mElevationUncertaintyInDeg : null));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "AzimuthInDeg",
-                hasAzimuthInDeg() ? mAzimuthInDeg : null,
-                "AzimuthUncertaintyInDeg",
-                hasAzimuthUncertaintyInDeg() ? mAzimuthUncertaintyInDeg : null));
-
-        builder.append(String.format(format, "UsedInFix", mUsedInFix));
-
         return builder.toString();
     }
 
     private void initialize() {
         mFlags = HAS_NO_FLAGS;
-        setSvid((short) 0);
-        setTimeOffsetInNs(Long.MIN_VALUE);
+        setSvid(0);
+        setTimeOffsetNanos(Long.MIN_VALUE);
         setState(STATE_UNKNOWN);
-        setReceivedSvTimeInNs(Long.MIN_VALUE);
-        setReceivedSvTimeUncertaintyInNs(Long.MAX_VALUE);
-        setCn0InDbHz(Double.MIN_VALUE);
-        setPseudorangeRateInMetersPerSec(Double.MIN_VALUE);
-        setPseudorangeRateUncertaintyInMetersPerSec(Double.MIN_VALUE);
+        setReceivedSvTimeNanos(Long.MIN_VALUE);
+        setReceivedSvTimeUncertaintyNanos(Long.MAX_VALUE);
+        setCn0DbHz(Double.MIN_VALUE);
+        setPseudorangeRateMetersPerSecond(Double.MIN_VALUE);
+        setPseudorangeRateUncertaintyMetersPerSecond(Double.MIN_VALUE);
         setAccumulatedDeltaRangeState(ADR_STATE_UNKNOWN);
-        setAccumulatedDeltaRangeInMeters(Double.MIN_VALUE);
-        setAccumulatedDeltaRangeUncertaintyInMeters(Double.MIN_VALUE);
-        resetPseudorangeInMeters();
-        resetPseudorangeUncertaintyInMeters();
-        resetCodePhaseInChips();
-        resetCodePhaseUncertaintyInChips();
-        resetCarrierFrequencyInHz();
+        setAccumulatedDeltaRangeMeters(Double.MIN_VALUE);
+        setAccumulatedDeltaRangeUncertaintyMeters(Double.MIN_VALUE);
+        resetCarrierFrequencyHz();
         resetCarrierCycles();
         resetCarrierPhase();
         resetCarrierPhaseUncertainty();
-        setLossOfLock(LOSS_OF_LOCK_UNKNOWN);
-        resetBitNumber();
-        resetTimeFromLastBitInMs();
-        resetDopplerShiftInHz();
-        resetDopplerShiftUncertaintyInHz();
         setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
         resetSnrInDb();
-        resetElevationInDeg();
-        resetElevationUncertaintyInDeg();
-        resetAzimuthInDeg();
-        resetAzimuthUncertaintyInDeg();
-        setUsedInFix(false);
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java
index b744a03..ec252a8 100644
--- a/location/java/android/location/GnssMeasurementsEvent.java
+++ b/location/java/android/location/GnssMeasurementsEvent.java
@@ -33,46 +33,49 @@
  * Events are delivered to registered instances of {@link Callback}.
  */
 public final class GnssMeasurementsEvent implements Parcelable {
-    /** The status of GPS measurements event. */
+    /**
+     * The status of the GNSS measurements event.
+     * @hide
+     */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GNSS_LOCATION_DISABLED})
     public @interface GnssMeasurementsStatus {}
 
     /**
-     * The system does not support tracking of GPS Measurements. This status will not change in the
+     * The system does not support tracking of GNSS Measurements. This status will not change in the
      * future.
      */
     public static final int STATUS_NOT_SUPPORTED = 0;
 
     /**
-     * GPS Measurements are successfully being tracked, it will receive updates once they are
+     * GNSS Measurements are successfully being tracked, it will receive updates once they are
      * available.
      */
     public static final int STATUS_READY = 1;
 
     /**
-     * GPS provider or Location is disabled, updates will not be received until they are enabled.
+     * GNSS provider or Location is disabled, updates will not be received until they are enabled.
      */
-    public static final int STATUS_GPS_LOCATION_DISABLED = 2;
+    public static final int STATUS_GNSS_LOCATION_DISABLED = 2;
 
     private final GnssClock mClock;
     private final Collection<GnssMeasurement> mReadOnlyMeasurements;
 
     /**
-     * Used for receiving GPS satellite measurements from the GPS engine.
+     * Used for receiving GNSS satellite measurements from the GNSS engine.
      * Each measurement contains raw and computed data identifying a satellite.
      * You can implement this interface and call
-     * {@link LocationManager#registerGnssMeasurementCallback}.
+     * {@link LocationManager#registerGnssMeasurementsCallback}.
      */
     public static abstract class Callback {
 
         /**
-         * Returns the latest collected GPS Measurements.
+         * Reports the latest collected GNSS Measurements.
          */
         public void onGnssMeasurementsReceived(GnssMeasurementsEvent eventArgs) {}
 
         /**
-         * Returns the latest status of the GPS Measurements sub-system.
+         * Reports the latest status of the GNSS Measurements sub-system.
          */
         public void onStatusChanged(@GnssMeasurementsStatus int status) {}
     }
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index faefd0bb..a5eace8 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.TestApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.os.Parcel;
@@ -32,68 +33,76 @@
 
     private static final byte[] EMPTY_ARRAY = new byte[0];
 
-    /** The type of the GPS Clock. */
+    /**
+     * The type of the GPS Clock.
+     * @hide
+     */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_GPS_L1CA, MESSAGE_TYPE_GPS_L2CNAV,
-        MESSAGE_TYPE_GPS_L5CNAV, MESSAGE_TYPE_GPS_CNAV2, MESSAGE_TYPE_GLO_L1CA, MESSAGE_TYPE_BDS_D1,
-        MESSAGE_TYPE_BDS_D2, MESSAGE_TYPE_GAL_I, MESSAGE_TYPE_GAL_F})
+    @IntDef({TYPE_UNKNOWN, TYPE_GPS_L1CA, TYPE_GPS_L2CNAV, TYPE_GPS_L5CNAV, TYPE_GPS_CNAV2,
+        TYPE_GLO_L1CA, TYPE_BDS_D1, TYPE_BDS_D2, TYPE_GAL_I, TYPE_GAL_F})
     public @interface GnssNavigationMessageType {}
 
     // The following enumerations must be in sync with the values declared in gps.h
 
     /** Message type unknown */
-    public static final short MESSAGE_TYPE_UNKNOWN = 0;
+    public static final int TYPE_UNKNOWN = 0;
     /** GPS L1 C/A message contained in the structure.  */
-    public static final short MESSAGE_TYPE_GPS_L1CA = 0x0101;
+    public static final int TYPE_GPS_L1CA = 0x0101;
     /** GPS L2-CNAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GPS_L2CNAV = 0x0102;
+    public static final int TYPE_GPS_L2CNAV = 0x0102;
     /** GPS L5-CNAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GPS_L5CNAV = 0x0103;
+    public static final int TYPE_GPS_L5CNAV = 0x0103;
     /** GPS CNAV-2 message contained in the structure. */
-    public static final short MESSAGE_TYPE_GPS_CNAV2 = 0x0104;
+    public static final int TYPE_GPS_CNAV2 = 0x0104;
     /** Glonass L1 CA message contained in the structure. */
-    public static final short MESSAGE_TYPE_GLO_L1CA = 0x0301;
+    public static final int TYPE_GLO_L1CA = 0x0301;
     /** Beidou D1 message contained in the structure. */
-    public static final short MESSAGE_TYPE_BDS_D1 = 0x0501;
+    public static final int TYPE_BDS_D1 = 0x0501;
     /** Beidou D2 message contained in the structure. */
-    public static final short MESSAGE_TYPE_BDS_D2 = 0x0502;
+    public static final int TYPE_BDS_D2 = 0x0502;
     /** Galileo I/NAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GAL_I = 0x0601;
+    public static final int TYPE_GAL_I = 0x0601;
     /** Galileo F/NAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GAL_F = 0x0602;
+    public static final int TYPE_GAL_F = 0x0602;
 
     /**
      * The Navigation Message Status is 'unknown'.
      */
-    public static final short STATUS_UNKNOWN = 0;
+    public static final int STATUS_UNKNOWN = 0;
 
     /**
      * The Navigation Message was received without any parity error in its navigation words.
      */
-    public static final short STATUS_PARITY_PASSED = (1<<0);
+    public static final int STATUS_PARITY_PASSED = (1<<0);
 
     /**
      * The Navigation Message was received with words that failed parity check, but the receiver was
      * able to correct those words.
      */
-    public static final short STATUS_PARITY_REBUILT = (1<<1);
+    public static final int STATUS_PARITY_REBUILT = (1<<1);
 
     // End enumerations in sync with gps.h
 
-    private short mType;
-    private short mSvid;
-    private short mMessageId;
-    private short mSubmessageId;
+    private int mType;
+    private int mSvid;
+    private int mMessageId;
+    private int mSubmessageId;
     private byte[] mData;
-    private short mStatus;
+    private int mStatus;
 
-    GnssNavigationMessage() {
+    /**
+     * @hide
+     */
+    @TestApi
+    public GnssNavigationMessage() {
         initialize();
     }
 
     /**
      * Sets all contents to the values stored in the provided object.
+     * @hide
      */
+    @TestApi
     public void set(GnssNavigationMessage navigationMessage) {
         mType = navigationMessage.mType;
         mSvid = navigationMessage.mSvid;
@@ -105,7 +114,9 @@
 
     /**
      * Resets all the contents to its original state.
+     * @hide
      */
+    @TestApi
     public void reset() {
         initialize();
     }
@@ -114,14 +125,16 @@
      * Gets the type of the navigation message contained in the object.
      */
     @GnssNavigationMessageType
-    public short getType() {
+    public int getType() {
         return mType;
     }
 
     /**
      * Sets the type of the navigation message.
+     * @hide
      */
-    public void setType(@GnssNavigationMessageType short value) {
+    @TestApi
+    public void setType(@GnssNavigationMessageType int value) {
         mType = value;
     }
 
@@ -131,25 +144,25 @@
      */
     private String getTypeString() {
         switch (mType) {
-            case MESSAGE_TYPE_UNKNOWN:
+            case TYPE_UNKNOWN:
                 return "Unknown";
-            case MESSAGE_TYPE_GPS_L1CA:
+            case TYPE_GPS_L1CA:
                 return "GPS L1 C/A";
-            case MESSAGE_TYPE_GPS_L2CNAV:
+            case TYPE_GPS_L2CNAV:
                 return "GPS L2-CNAV";
-            case MESSAGE_TYPE_GPS_L5CNAV:
+            case TYPE_GPS_L5CNAV:
                 return "GPS L5-CNAV";
-            case MESSAGE_TYPE_GPS_CNAV2:
+            case TYPE_GPS_CNAV2:
                 return "GPS CNAV2";
-            case MESSAGE_TYPE_GLO_L1CA:
+            case TYPE_GLO_L1CA:
                 return "Glonass L1 C/A";
-            case MESSAGE_TYPE_BDS_D1:
+            case TYPE_BDS_D1:
                 return "Beidou D1";
-            case MESSAGE_TYPE_BDS_D2:
+            case TYPE_BDS_D2:
                 return "Beidou D2";
-            case MESSAGE_TYPE_GAL_I:
+            case TYPE_GAL_I:
                 return "Galileo I";
-            case MESSAGE_TYPE_GAL_F:
+            case TYPE_GAL_F:
                 return "Galileo F";
             default:
                 return "<Invalid:" + mType + ">";
@@ -160,14 +173,16 @@
      * Gets the Pseudo-random number.
      * Range: [1, 32].
      */
-    public short getSvid() {
+    public int getSvid() {
         return mSvid;
     }
 
     /**
      * Sets the Pseud-random number.
+     * @hide
      */
-    public void setSvid(short value) {
+    @TestApi
+    public void setSvid(int value) {
         mSvid = value;
     }
 
@@ -177,14 +192,16 @@
      * subframe 4 and 5, this value corresponds to the 'frame id' of the navigation message.
      * Subframe 1, 2, 3 does not contain a 'frame id' and this might be reported as -1.
      */
-    public short getMessageId() {
+    public int getMessageId() {
         return mMessageId;
     }
 
     /**
      * Sets the Message Identifier.
+     * @hide
      */
-    public void setMessageId(short value) {
+    @TestApi
+    public void setMessageId(int value) {
         mMessageId = value;
     }
 
@@ -194,14 +211,16 @@
      * (or frame) that is being transmitted. i.e. for L1 C/A the sub-message identifier corresponds
      * to the sub-frame Id of the navigation message.
      */
-    public short getSubmessageId() {
+    public int getSubmessageId() {
         return mSubmessageId;
     }
 
     /**
      * Sets the Sub-message identifier.
+     * @hide
      */
-    public void setSubmessageId(short value) {
+    @TestApi
+    public void setSubmessageId(int value) {
         mSubmessageId = value;
     }
 
@@ -216,7 +235,9 @@
 
     /**
      * Sets the data associated with the Navigation Message.
+     * @hide
      */
+    @TestApi
     public void setData(byte[] value) {
         if (value == null) {
             throw new InvalidParameterException("Data must be a non-null array");
@@ -228,14 +249,16 @@
     /**
      * Gets the Status of the navigation message contained in the object.
      */
-    public short getStatus() {
+    public int getStatus() {
         return mStatus;
     }
 
     /**
      * Sets the status of the navigation message.
+     * @hide
      */
-    public void setStatus(short value) {
+    @TestApi
+    public void setStatus(int value) {
         mStatus = value;
     }
 
@@ -262,22 +285,15 @@
         public GnssNavigationMessage createFromParcel(Parcel parcel) {
             GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
 
-            navigationMessage.setType((short) parcel.readInt());
-            navigationMessage.setSvid((short) parcel.readInt());
-            navigationMessage.setMessageId((short) parcel.readInt());
-            navigationMessage.setSubmessageId((short) parcel.readInt());
-
+            navigationMessage.setType(parcel.readInt());
+            navigationMessage.setSvid(parcel.readInt());
+            navigationMessage.setMessageId(parcel.readInt());
+            navigationMessage.setSubmessageId(parcel.readInt());
             int dataLength = parcel.readInt();
             byte[] data = new byte[dataLength];
             parcel.readByteArray(data);
             navigationMessage.setData(data);
-
-            if (parcel.dataAvail() >= Integer.SIZE) {
-                int status = parcel.readInt();
-                navigationMessage.setStatus((short) status);
-            } else {
-                navigationMessage.setStatus(STATUS_UNKNOWN);
-            }
+            navigationMessage.setStatus(parcel.readInt());
 
             return navigationMessage;
         }
@@ -328,7 +344,7 @@
     }
 
     private void initialize() {
-        mType = MESSAGE_TYPE_UNKNOWN;
+        mType = TYPE_UNKNOWN;
         mSvid = 0;
         mMessageId = -1;
         mSubmessageId = -1;
diff --git a/location/java/android/location/GnssNavigationMessageEvent.java b/location/java/android/location/GnssNavigationMessageEvent.java
index 19c82e9..992dfc3 100644
--- a/location/java/android/location/GnssNavigationMessageEvent.java
+++ b/location/java/android/location/GnssNavigationMessageEvent.java
@@ -30,9 +30,12 @@
  * Events are delivered to registered instances of {@link Callback}.
  */
 public final class GnssNavigationMessageEvent implements Parcelable {
-    /** The status of GPS measurements event. */
+    /**
+     * The status of GPS measurements event.
+     * @hide
+     */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GNSS_LOCATION_DISABLED})
     public @interface GnssNavigationMessageStatus {}
 
     /**
@@ -50,7 +53,7 @@
     /**
      * GPS provider or Location is disabled, updated will not be received until they are enabled.
      */
-    public static final int STATUS_GPS_LOCATION_DISABLED = 2;
+    public static final int STATUS_GNSS_LOCATION_DISABLED = 2;
 
     private final GnssNavigationMessage mNavigationMessage;
 
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 06ce30c..d76feec 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -27,21 +27,24 @@
  */
 public final class GnssStatus {
     /** Unknown constellation type. */
-    public static final byte CONSTELLATION_UNKNOWN = 0;
+    public static final int CONSTELLATION_UNKNOWN = 0;
     /** Constellation type constant for GPS. */
-    public static final byte CONSTELLATION_GPS = 1;
+    public static final int CONSTELLATION_GPS = 1;
     /** Constellation type constant for SBAS. */
-    public static final byte CONSTELLATION_SBAS = 2;
+    public static final int CONSTELLATION_SBAS = 2;
     /** Constellation type constant for Glonass. */
-    public static final byte CONSTELLATION_GLONASS = 3;
+    public static final int CONSTELLATION_GLONASS = 3;
     /** Constellation type constant for QZSS. */
-    public static final byte CONSTELLATION_QZSS = 4;
+    public static final int CONSTELLATION_QZSS = 4;
     /** Constellation type constant for Beidou. */
-    public static final byte CONSTELLATION_BEIDOU = 5;
+    public static final int CONSTELLATION_BEIDOU = 5;
     /** Constellation type constant for Galileo. */
-    public static final byte CONSTELLATION_GALILEO = 6;
+    public static final int CONSTELLATION_GALILEO = 6;
 
-    /** Constellation type. */
+    /**
+     * Constellation type.
+     * @hide
+     */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({CONSTELLATION_UNKNOWN, CONSTELLATION_GPS, CONSTELLATION_SBAS, CONSTELLATION_GLONASS,
             CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO})
@@ -66,16 +69,16 @@
 
     /* These package private values are modified by the LocationManager class */
     /* package */ int[] mSvidWithFlags;
-    /* package */ float[] mSnrs;
+    /* package */ float[] mCn0DbHz;
     /* package */ float[] mElevations;
     /* package */ float[] mAzimuths;
     /* package */ int mSvCount;
 
-    GnssStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+    GnssStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
             float[] azimuths) {
         mSvCount = svCount;
         mSvidWithFlags = svidWithFlags;
-        mSnrs = snrs;
+        mCn0DbHz = cn0s;
         mElevations = elevations;
         mAzimuths = azimuths;
     }
@@ -92,8 +95,8 @@
      * @param satIndex the index of the satellite in the list.
      */
     @ConstellationType
-    public byte getConstellationType(int satIndex) {
-        return (byte) ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+    public int getConstellationType(int satIndex) {
+        return ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
                 & CONSTELLATION_TYPE_MASK);
     }
 
@@ -109,23 +112,23 @@
      * Retrieves the signal-noise ration of the satellite at the specified position.
      * @param satIndex the index of the satellite in the list.
      */
-    public float getSnr(int satIndex) {
-        return mSnrs[satIndex];
+    public float getCn0DbHz(int satIndex) {
+        return mCn0DbHz[satIndex];
     }
 
     /**
      * Retrieves the elevation of the satellite at the specified position.
      * @param satIndex the index of the satellite in the list.
      */
-    public float getElevation(int satIndex) {
-        return 0f;
+    public float getElevationDegrees(int satIndex) {
+        return mElevations[satIndex];
     }
 
     /**
      * Retrieves the azimuth the satellite at the specified position.
      * @param satIndex the index of the satellite in the list.
      */
-    public float getAzimuth(int satIndex) {
+    public float getAzimuthDegrees(int satIndex) {
         return mAzimuths[satIndex];
     }
 
diff --git a/location/java/android/location/GnssStatusCallback.java b/location/java/android/location/GnssStatusCallback.java
index b86171b..0d2955a 100644
--- a/location/java/android/location/GnssStatusCallback.java
+++ b/location/java/android/location/GnssStatusCallback.java
@@ -32,13 +32,13 @@
 
     /**
      * Called when the GNSS system has received its first fix since starting.
-     * @param ttff the time from start to first fix.
+     * @param ttffMillis the time from start to first fix in milliseconds.
      */
-    public void onFirstFix(int ttff) {}
+    public void onFirstFix(int ttffMillis) {}
 
     /**
      * Called periodically to report GNSS satellite status.
      * @param status the current status of all satellites.
      */
     public void onSatelliteStatusChanged(GnssStatus status) {}
-}
\ No newline at end of file
+}
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 7b3dd7d..bc518f9 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -138,7 +138,7 @@
     // For API-compat a public ctor() is not available
     GpsStatus() {}
 
-    private void setStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+    private void setStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
             float[] azimuths) {
         clearSatellites();
         for (int i = 0; i < svCount; i++) {
@@ -158,7 +158,7 @@
                 }
 
                 satellite.mValid = true;
-                satellite.mSnr = snrs[i];
+                satellite.mSnr = cn0s[i];
                 satellite.mElevation = elevations[i];
                 satellite.mAzimuth = azimuths[i];
                 satellite.mHasEphemeris =
@@ -179,7 +179,7 @@
      */
     void setStatus(GnssStatus status, int timeToFirstFix) {
         mTimeToFirstFix = timeToFirstFix;
-        setStatus(status.mSvCount, status.mSvidWithFlags, status.mSnrs, status.mElevations,
+        setStatus(status.mSvCount, status.mSvidWithFlags, status.mCn0DbHz, status.mElevations,
                 status.mAzimuths);
     }
 
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index 8c7d06e..d84614f 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -26,7 +26,7 @@
     void onGnssStarted();
     void onGnssStopped();
     void onFirstFix(int ttff);
-    void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] snrs,
+    void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] cn0s,
             in float[] elevations, in float[] azimuths);
     void onNmeaReceived(long timestamp, String nmea);
 }
diff --git a/location/java/android/location/INetInitiatedListener.aidl b/location/java/android/location/INetInitiatedListener.aidl
index f2f5a32..fc64dd6 100644
--- a/location/java/android/location/INetInitiatedListener.aidl
+++ b/location/java/android/location/INetInitiatedListener.aidl
@@ -1,26 +1,26 @@
-/*

-**

-** Copyright 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.location;

-

-/**

- * {@hide}

- */

-interface INetInitiatedListener

-{

-    boolean sendNiResponse(int notifId, int userResponse);

-}

+/*
+**
+** Copyright 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.location;
+
+/**
+ * {@hide}
+ */
+interface INetInitiatedListener
+{
+    boolean sendNiResponse(int notifId, int userResponse);
+}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 4d0d1bd..50f0bad 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -891,7 +891,7 @@
             l.mSpeed = in.readFloat();
             l.mBearing = in.readFloat();
             l.mAccuracy = in.readFloat();
-            l.mExtras = in.readBundle();
+            l.mExtras = Bundle.setDefusable(in.readBundle(), true);
             return l;
         }
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index e14e36d..28db099 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -307,7 +307,7 @@
             try {
                 mService.locationCallbackFinished(this);
             } catch (RemoteException e) {
-                Log.e(TAG, "locationCallbackFinished: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -341,9 +341,8 @@
         try {
             return mService.getAllProviders();
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -357,9 +356,8 @@
         try {
             return mService.getProviders(null, enabledOnly);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -382,9 +380,8 @@
             }
             return createProvider(name, properties);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -402,9 +399,8 @@
         try {
             return mService.getProviders(criteria, enabledOnly);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -434,9 +430,8 @@
         try {
             return mService.getBestProvider(criteria, enabledOnly);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -885,7 +880,7 @@
         try {
             mService.requestLocationUpdates(request, transport, intent, packageName);
        } catch (RemoteException e) {
-           Log.e(TAG, "RemoteException", e);
+           throw e.rethrowFromSystemServer();
        }
     }
 
@@ -911,7 +906,7 @@
         try {
             mService.removeUpdates(transport, null, packageName);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -930,7 +925,7 @@
         try {
             mService.removeUpdates(null, intent, packageName);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -992,7 +987,7 @@
         try {
             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1040,7 +1035,7 @@
         try {
             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1067,7 +1062,7 @@
         try {
             mService.removeGeofence(null, intent, packageName);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1095,7 +1090,7 @@
         try {
             mService.removeGeofence(fence, intent, packageName);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1117,7 +1112,7 @@
         try {
             mService.removeGeofence(null, intent, packageName);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1148,8 +1143,7 @@
         try {
             return mService.isProviderEnabled(provider);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1173,8 +1167,7 @@
         try {
             return mService.getLastLocation(null, packageName);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1205,8 +1198,7 @@
         try {
             return mService.getLastLocation(request, packageName);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1237,7 +1229,7 @@
         try {
             mService.addTestProvider(name, properties, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1255,7 +1247,7 @@
         try {
             mService.removeTestProvider(provider, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1292,7 +1284,7 @@
         try {
             mService.setTestProviderLocation(provider, loc, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1310,7 +1302,7 @@
         try {
             mService.clearTestProviderLocation(provider, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1330,7 +1322,7 @@
         try {
             mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1348,7 +1340,7 @@
         try {
             mService.clearTestProviderEnabled(provider, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1371,7 +1363,7 @@
             mService.setTestProviderStatus(provider, status, extras, updateTime,
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1389,7 +1381,7 @@
         try {
             mService.clearTestProviderStatus(provider, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1562,9 +1554,9 @@
 
         @Override
         public void onSvStatusChanged(int svCount, int[] prnWithFlags,
-                float[] snrs, float[] elevations, float[] azimuths) {
+                float[] cn0s, float[] elevations, float[] azimuths) {
             if (mGnssCallback != null) {
-                mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths);
+                mGnssStatus = new GnssStatus(svCount, prnWithFlags, cn0s, elevations, azimuths);
 
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
@@ -1615,8 +1607,7 @@
                 mGpsStatusListeners.put(listener, transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
-            result = false;
+            throw e.rethrowFromSystemServer();
         }
 
         return result;
@@ -1635,7 +1626,7 @@
                 mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1679,8 +1670,7 @@
                 mGnssStatusListeners.put(callback, transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
-            result = false;
+            throw e.rethrowFromSystemServer();
         }
 
         return result;
@@ -1698,7 +1688,7 @@
                 mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1728,8 +1718,7 @@
                 mGpsNmeaListeners.put(listener, transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
-            result = false;
+            throw e.rethrowFromSystemServer();
         }
 
         return result;
@@ -1748,7 +1737,7 @@
                 mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1792,8 +1781,7 @@
                 mGnssNmeaListeners.put(listener, transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
-            result = false;
+            throw e.rethrowFromSystemServer();
         }
 
         return result;
@@ -1811,13 +1799,13 @@
                 mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
      * No-op method to keep backward-compatibility.
-     * Don't use it. Use {@link #registerGnssMeasurementCallback} instead.
+     * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead.
      * @hide
      * @deprecated
      */
@@ -1834,8 +1822,8 @@
      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
      */
     @RequiresPermission(ACCESS_FINE_LOCATION)
-    public boolean registerGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback) {
-        return registerGnssMeasurementCallback(callback, null);
+    public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
+        return registerGnssMeasurementsCallback(callback, null);
     }
 
     /**
@@ -1846,14 +1834,14 @@
      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
      */
     @RequiresPermission(ACCESS_FINE_LOCATION)
-    public boolean registerGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback,
+    public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback,
             Handler handler) {
         return mGnssMeasurementCallbackTransport.add(callback, handler);
     }
 
     /**
      * No-op method to keep backward-compatibility.
-     * Don't use it. Use {@link #unregisterGnssMeasurementCallback} instead.
+     * Don't use it. Use {@link #unregisterGnssMeasurementsCallback} instead.
      * @hide
      * @deprecated
      */
@@ -1867,7 +1855,7 @@
      *
      * @param callback a {@link GnssMeasurementsEvent.Callback} object to remove.
      */
-    public void unregisterGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback) {
+    public void unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
         mGnssMeasurementCallbackTransport.remove(callback);
     }
 
@@ -1963,8 +1951,7 @@
         try {
             return mService.getGnssYearOfHardware();
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getGnssSystemInfo: ", e);
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1983,8 +1970,7 @@
         try {
             return mService.sendExtraCommand(provider, command, extras);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in sendExtraCommand: ", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1998,8 +1984,7 @@
         try {
             return mService.sendNiResponse(notifId, userResponse);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in sendNiResponse: ", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/location/tests/locationtests/src/android/location/GpsStatusTest.java b/location/tests/locationtests/src/android/location/GpsStatusTest.java
index 4808faf..316e88d 100644
--- a/location/tests/locationtests/src/android/location/GpsStatusTest.java
+++ b/location/tests/locationtests/src/android/location/GpsStatusTest.java
@@ -40,7 +40,7 @@
     private GpsStatus mStatus;
     private int mCount;
     private int[] mPrns;
-    private float[] mSnrs;
+    private float[] mCn0s;
     private float[] mElevations;
     private float[] mAzimuth;
     private int mEphemerisMask;
@@ -179,7 +179,7 @@
 
     private void verifySatellites(GpsStatus status) {
         verifySatelliteCount(status, mCount);
-        verifySatellites(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask,
+        verifySatellites(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask,
                 mAlmanacMask, mUsedInFixMask);
     }
 
@@ -187,7 +187,7 @@
             GpsStatus status,
             int count,
             int[] prns,
-            float[] snrs,
+            float[] cn0s,
             float[] elevations,
             float[] azimuth,
             int ephemerisMask,
@@ -197,7 +197,7 @@
             int prn = prns[i];
             GpsSatellite satellite = getSatellite(status, prn);
             assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite);
-            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), snrs[i], satellite.getSnr());
+            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), cn0s[i], satellite.getSnr());
             assertEquals(
                     getSatelliteAssertInfo(i, prn, "Elevation"),
                     elevations[i],
@@ -247,7 +247,7 @@
     }
 
     private void setSatellites(GpsStatus status) throws Exception {
-        set(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
+        set(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
                 mUsedInFixMask);
     }
 
@@ -255,7 +255,7 @@
             GpsStatus status,
             int count,
             int[] prns,
-            float[] snrs,
+            float[] cn0s,
             float[] elevations,
             float[] azimuth,
             int ephemerisMask,
@@ -279,7 +279,7 @@
                 status,
                 count,
                 prns,
-                snrs,
+                cn0s,
                 elevations,
                 azimuth,
                 ephemerisMask,
@@ -333,7 +333,7 @@
         if (!reusePrns) {
             mPrns = generateIntArray(count);
         }
-        mSnrs = generateFloatArray(count);
+        mCn0s = generateFloatArray(count);
         mElevations = generateFloatArray(count);
         mAzimuth = generateFloatArray(count);
         mEphemerisMask = generateMask(mPrns);
diff --git a/media/java/android/media/AudioDeviceCallback.java b/media/java/android/media/AudioDeviceCallback.java
index d9f0037..a5b1d24 100644
--- a/media/java/android/media/AudioDeviceCallback.java
+++ b/media/java/android/media/AudioDeviceCallback.java
@@ -19,7 +19,7 @@
 /**
  * AudioDeviceCallback defines the mechanism by which applications can receive notifications
  * of audio device connection and disconnection events.
- * @see AudioManager#registerAudioDeviceCallback.
+ * @see AudioManager#registerAudioDeviceCallback(AudioDeviceCallback, android.os.Handler handler).
  */
 public abstract class AudioDeviceCallback {
     /**
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 45529ef..9922b72 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -111,6 +111,10 @@
      * A device type connected over IP.
      */
     public static final int TYPE_IP               = 20;
+    /**
+     * A type-agnostic device used for communication with external audio systems
+     */
+    public static final int TYPE_BUS              = 21;
 
     private final AudioDevicePort mPort;
 
@@ -279,6 +283,7 @@
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BUS, TYPE_BUS);
 
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
@@ -296,6 +301,7 @@
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS);
 
         // not covered here, legacy
         //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
@@ -323,6 +329,7 @@
         EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
         EXT_TO_INT_DEVICE_MAPPING.put(TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
         EXT_TO_INT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_OUT_IP);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_OUT_BUS);
     }
 }
 
diff --git a/media/java/android/media/AudioFormat.aidl b/media/java/android/media/AudioFormat.aidl
new file mode 100644
index 0000000..8613f55
--- /dev/null
+++ b/media/java/android/media/AudioFormat.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable AudioFormat;
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 000a56d..a4484e7 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -18,10 +18,13 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * The {@link AudioFormat} class is used to access a number of audio format and
@@ -209,7 +212,7 @@
  * AudioTrack.getPlaybackHeadPosition()}),
  * depending on the context where audio frame is used.
  */
-public class AudioFormat {
+public final class AudioFormat implements Parcelable {
 
     //---------------------------------------------------------
     // Constants
@@ -253,6 +256,11 @@
     public static final int ENCODING_AAC_HE_V2 = 12;
     /** Audio data format: compressed audio wrapped in PCM for HDMI
      * or S/PDIF passthrough.
+     * IEC61937 uses a stereo stream of 16-bit samples as the wrapper.
+     * So the channel mask for the track must be {@link #CHANNEL_OUT_STEREO}.
+     * Data should be written to the stream in a short[] array.
+     * If the data is written in a byte[] array then there may be endian problems
+     * on some platforms when converting to short internally.
      */
     public static final int ENCODING_IEC61937 = 13;
 
@@ -332,6 +340,24 @@
             CHANNEL_OUT_LOW_FREQUENCY);
     // CHANNEL_OUT_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_OUT_ALL
 
+    /** Minimum value for sample rate,
+     *  assuming AudioTrack and AudioRecord share the same limitations.
+     * @hide
+     */
+    // never unhide
+    public static final int SAMPLE_RATE_HZ_MIN = 4000;
+    /** Maximum value for sample rate,
+     *  assuming AudioTrack and AudioRecord share the same limitations.
+     * @hide
+     */
+    // never unhide
+    public static final int SAMPLE_RATE_HZ_MAX = 192000;
+    /** Sample rate will be a route-dependent value.
+     * For AudioTrack, it is usually the sink sample rate,
+     * and for AudioRecord it is usually the source sample rate.
+     */
+    public static final int SAMPLE_RATE_UNSPECIFIED = 0;
+
     /**
      * @hide
      * Return the input channel mask corresponding to an output channel mask.
@@ -558,7 +584,7 @@
     }
 
     /**
-     * Constructor used by the JNI
+     * Constructor used by the JNI.  Parameters are not checked for validity.
      */
     // Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this
     // constructor
@@ -607,12 +633,9 @@
     /**
      * Return the sample rate.
      * @return one of the values that can be set in {@link Builder#setSampleRate(int)} or
-     * 0 if not set.
+     * {@link #SAMPLE_RATE_UNSPECIFIED} if not set.
      */
     public int getSampleRate() {
-        if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) == 0) {
-            return 0;
-        }
         return mSampleRate;
     }
 
@@ -684,7 +707,7 @@
      */
     public static class Builder {
         private int mEncoding = ENCODING_INVALID;
-        private int mSampleRate = 0;
+        private int mSampleRate = SAMPLE_RATE_UNSPECIFIED;
         private int mChannelMask = CHANNEL_INVALID;
         private int mChannelIndexMask = 0;
         private int mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_NONE;
@@ -715,6 +738,8 @@
         public AudioFormat build() {
             AudioFormat af = new AudioFormat(1980/*ignored*/);
             af.mEncoding = mEncoding;
+            // not calling setSampleRate is equivalent to calling
+            // setSampleRate(SAMPLE_RATE_UNSPECIFIED)
             af.mSampleRate = mSampleRate;
             af.mChannelMask = mChannelMask;
             af.mChannelIndexMask = mChannelIndexMask;
@@ -792,7 +817,7 @@
          *    are specified but do not have the same channel count.
          */
         public @NonNull Builder setChannelMask(int channelMask) {
-            if (channelMask == 0) {
+            if (channelMask == CHANNEL_INVALID) {
                 throw new IllegalArgumentException("Invalid zero channel mask");
             } else if (/* channelMask != 0 && */ mChannelIndexMask != 0 &&
                     Integer.bitCount(channelMask) != Integer.bitCount(mChannelIndexMask)) {
@@ -864,7 +889,11 @@
          * @throws java.lang.IllegalArgumentException
          */
         public Builder setSampleRate(int sampleRate) throws IllegalArgumentException {
-            if ((sampleRate <= 0) || (sampleRate > 192000)) {
+            // TODO Consider whether to keep the MIN and MAX range checks here.
+            // It is not necessary and poses the problem of defining the limits independently from
+            // native implementation or platform capabilities.
+            if (((sampleRate < SAMPLE_RATE_HZ_MIN) || (sampleRate > SAMPLE_RATE_HZ_MAX)) &&
+                    sampleRate != SAMPLE_RATE_UNSPECIFIED) {
                 throw new IllegalArgumentException("Invalid sample rate " + sampleRate);
             }
             mSampleRate = sampleRate;
@@ -874,6 +903,64 @@
     }
 
     @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AudioFormat that = (AudioFormat) o;
+
+        if (mPropertySetMask != that.mPropertySetMask) return false;
+
+        // return false if any of the properties is set and the values differ
+        return !((((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
+                            && (mEncoding != that.mEncoding))
+                    || (((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
+                            && (mSampleRate != that.mSampleRate))
+                    || (((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0)
+                            && (mChannelMask != that.mChannelMask))
+                    || (((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0)
+                            && (mChannelIndexMask != that.mChannelIndexMask)));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPropertySetMask, mSampleRate, mEncoding, mChannelMask,
+                mChannelIndexMask);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mPropertySetMask);
+        dest.writeInt(mEncoding);
+        dest.writeInt(mSampleRate);
+        dest.writeInt(mChannelMask);
+        dest.writeInt(mChannelIndexMask);
+    }
+
+    private AudioFormat(Parcel in) {
+        mPropertySetMask = in.readInt();
+        mEncoding = in.readInt();
+        mSampleRate = in.readInt();
+        mChannelMask = in.readInt();
+        mChannelIndexMask = in.readInt();
+    }
+
+    public static final Parcelable.Creator<AudioFormat> CREATOR =
+            new Parcelable.Creator<AudioFormat>() {
+        public AudioFormat createFromParcel(Parcel p) {
+            return new AudioFormat(p);
+        }
+        public AudioFormat[] newArray(int size) {
+            return new AudioFormat[size];
+        }
+    };
+
+    @Override
     public String toString () {
         return new String("AudioFormat:"
                 + " props=" + mPropertySetMask
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index dc534be..00eff91 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -21,6 +21,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
@@ -177,16 +178,6 @@
         "android.media.MASTER_MUTE_CHANGED_ACTION";
 
     /**
-     * @hide Broadcast intent when the master mono state changes.
-     * Includes the new mono state
-     *
-     * @see #EXTRA_MASTER_MONO
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String MASTER_MONO_CHANGED_ACTION =
-        "android.media.MASTER_MONO_CHANGED_ACTION";
-
-    /**
      * The new vibrate setting for a particular type.
      *
      * @see #VIBRATE_SETTING_CHANGED_ACTION
@@ -265,13 +256,6 @@
         "android.media.EXTRA_STREAM_VOLUME_MUTED";
 
     /**
-     * @hide The new master mono state for the master mono changed intent.
-     * Value is boolean
-     */
-    public static final String EXTRA_MASTER_MONO =
-        "android.media.EXTRA_MASTER_MONO";
-
-    /**
      * Broadcast Action: Wired Headset plugged in or unplugged.
      *
      * You <em>cannot</em> receive this through components declared
@@ -826,7 +810,7 @@
             service.adjustStreamVolume(streamType, direction, flags,
                     getContext().getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustStreamVolume", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -894,18 +878,7 @@
             service.setMasterMute(mute, flags, getContext().getOpPackageName(),
                     UserHandle.getCallingUserId());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMasterMute", e);
-        }
-    }
-
-    /** @hide */
-    public void setMasterMono(boolean mono) {
-        IAudioService service = getService();
-        try {
-            service.setMasterMono(mono, getContext().getOpPackageName(),
-                    UserHandle.getCallingUserId());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMasterMono", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -921,8 +894,7 @@
         try {
             return service.getRingerModeExternal();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getRingerMode", e);
-            return RINGER_MODE_NORMAL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -942,8 +914,7 @@
         try {
             return service.isValidRingerMode(ringerMode);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in isValidRingerMode", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -959,8 +930,7 @@
         try {
             return service.getStreamMaxVolume(streamType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getStreamMaxVolume", e);
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -977,8 +947,7 @@
         try {
             return service.getStreamMinVolume(streamType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getStreamMinVolume", e);
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -995,8 +964,7 @@
         try {
             return service.getStreamVolume(streamType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getStreamVolume", e);
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1010,8 +978,7 @@
         try {
             return service.getLastAudibleStreamVolume(streamType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1026,8 +993,7 @@
         try {
             return service.getUiSoundsStreamType();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getUiSoundsStreamType", e);
-            return STREAM_RING;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1039,6 +1005,9 @@
      * according to user settings.
      * <p>This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
+     * unless the app has been granted Do Not Disturb Access.
+     * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
      * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
      *            {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
      * @see #getRingerMode()
@@ -1052,7 +1021,7 @@
         try {
             service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setRingerMode", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1060,6 +1029,9 @@
      * Sets the volume index for a particular stream.
      * <p>This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
+     * the app has been granted Do Not Disturb Access.
+     * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
      * @param streamType The stream whose volume index should be set.
      * @param index The volume index to set. See
      *            {@link #getStreamMaxVolume(int)} for the largest valid value.
@@ -1073,7 +1045,7 @@
         try {
             service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setStreamVolume", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1150,8 +1122,7 @@
         try {
             return service.isStreamMute(streamType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in isStreamMute", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1165,23 +1136,7 @@
         try {
             return service.isMasterMute();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in isMasterMute", e);
-            return false;
-        }
-    }
-
-    /**
-     * get master mono state.
-     *
-     * @hide
-     */
-    public boolean isMasterMono() {
-        IAudioService service = getService();
-        try {
-            return service.isMasterMono();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in isMasterMono", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1197,7 +1152,7 @@
         try {
             service.forceVolumeControlStream(streamType, mICallBack);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in forceVolumeControlStream", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1225,8 +1180,7 @@
         try {
             return service.shouldVibrate(vibrateType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in shouldVibrate", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1252,8 +1206,7 @@
         try {
             return service.getVibrateSetting(vibrateType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getVibrateSetting", e);
-            return VIBRATE_SETTING_OFF;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1280,7 +1233,7 @@
         try {
             service.setVibrateSetting(vibrateType, vibrateSetting);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setVibrateSetting", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1298,7 +1251,7 @@
         try {
             service.setSpeakerphoneOn(on);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setSpeakerphoneOn", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1312,8 +1265,7 @@
         try {
             return service.isSpeakerphoneOn();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in isSpeakerphoneOn", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
      }
 
@@ -1454,7 +1406,7 @@
             service.startBluetoothSco(mICallBack,
                     getContext().getApplicationInfo().targetSdkVersion);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in startBluetoothSco", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1478,7 +1430,7 @@
         try {
             service.startBluetoothScoVirtualCall(mICallBack);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in startBluetoothScoVirtualCall", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1497,7 +1449,7 @@
         try {
             service.stopBluetoothSco(mICallBack);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in stopBluetoothSco", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1515,7 +1467,7 @@
         try {
             service.setBluetoothScoOn(on);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setBluetoothScoOn", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1530,8 +1482,7 @@
         try {
             return service.isBluetoothScoOn();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in isBluetoothScoOn", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1603,7 +1554,7 @@
             service.setMicrophoneMute(on, getContext().getOpPackageName(),
                     UserHandle.getCallingUserId());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMicrophoneMute", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1636,7 +1587,7 @@
         try {
             service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMode", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1652,8 +1603,7 @@
         try {
             return service.getMode();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getMode", e);
-            return MODE_INVALID;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1790,8 +1740,7 @@
         try {
             return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in isAudioFocusExclusive()", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1957,7 +1906,7 @@
         try {
             service.playSoundEffect(effectType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in playSoundEffect"+e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1992,7 +1941,7 @@
         try {
             service.playSoundEffect(effectType);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in playSoundEffect"+e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2024,7 +1973,7 @@
         try {
             service.playSoundEffectVolume(effectType, volume);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in playSoundEffect"+e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2046,7 +1995,7 @@
         try {
             service.loadSoundEffects();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in loadSoundEffects"+e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2060,7 +2009,7 @@
         try {
             service.unloadSoundEffects();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unloadSoundEffects"+e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2200,14 +2149,15 @@
                                 }
                                 if (listener != null) {
                                     Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
-                                            + msg.what + ") for " + msg.obj);
+                                            + msg.arg1 + ") for " + msg.obj);
                                     listener.onAudioFocusChange(msg.arg1);
                                 }
                                 break;
                             case MSSG_RECORDING_CONFIG_CHANGE:
-                                final AudioRecordingCallback cb = (AudioRecordingCallback) msg.obj;
-                                if (cb != null) {
-                                    cb.onRecordConfigChanged();
+                                final RecordConfigChangeCallbackData cbData =
+                                        (RecordConfigChangeCallbackData) msg.obj;
+                                if (cbData.mCb != null) {
+                                    cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
                                 }
                                 break;
                             default:
@@ -2471,7 +2421,7 @@
                     getContext().getOpPackageName() /* package name */, flags,
                     ap != null ? ap.cb() : null);
         } catch (RemoteException e) {
-            Log.e(TAG, "Can't call requestAudioFocus() on AudioService:", e);
+            throw e.rethrowFromSystemServer();
         }
         return status;
     }
@@ -2497,7 +2447,7 @@
                     AUDIOFOCUS_FLAG_LOCK,
                     null /* policy token */);
         } catch (RemoteException e) {
-            Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService:", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2513,7 +2463,7 @@
             service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
                     null /*AudioAttributes, legacy behavior*/);
         } catch (RemoteException e) {
-            Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService:", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2542,7 +2492,7 @@
             status = service.abandonAudioFocus(mAudioFocusDispatcher,
                     getIdForAudioFocusListener(l), aa);
         } catch (RemoteException e) {
-            Log.e(TAG, "Can't call abandonAudioFocus() on AudioService:", e);
+            throw e.rethrowFromSystemServer();
         }
         return status;
     }
@@ -2756,8 +2706,7 @@
             }
             // successful registration
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in registerAudioPolicyAsync()", e);
-            return ERROR;
+            throw e.rethrowFromSystemServer();
         }
         return SUCCESS;
     }
@@ -2776,7 +2725,7 @@
             service.unregisterAudioPolicyAsync(policy.cb());
             policy.setRegistration(null);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unregisterAudioPolicyAsync()", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2788,13 +2737,16 @@
      * this abstract class and register it with
      * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
      * to be notified.
-     * Use {@link AudioManager#getActiveRecordConfigurations()} to query the current configuration.
+     * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
+     * configuration.
      */
     public static abstract class AudioRecordingCallback {
         /**
          * Called whenever the device recording configuration has changed.
+         * @param configs array containing the results of
+         *      {@link AudioManager#getActiveRecordingConfigurations()}.
          */
-        public void onRecordConfigChanged() {}
+        public void onRecordingConfigChanged(AudioRecordingConfiguration[] configs) {}
     }
 
     private static class AudioRecordingCallbackInfo {
@@ -2806,6 +2758,17 @@
         }
     }
 
+    private final static class RecordConfigChangeCallbackData {
+        final AudioRecordingCallback mCb;
+        final AudioRecordingConfiguration[] mConfigs;
+
+        RecordConfigChangeCallbackData(AudioRecordingCallback cb,
+                AudioRecordingConfiguration[] configs) {
+            mCb = cb;
+            mConfigs = configs;
+        }
+    }
+
     /**
      * Register a callback to be notified of audio recording changes through
      * {@link AudioRecordingCallback}
@@ -2836,7 +2799,7 @@
                     try {
                         service.registerRecordingCallback(mRecCb);
                     } catch (RemoteException e) {
-                        Log.e(TAG, "Dead object in registerRecordingCallback", e);
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             } else {
@@ -2868,7 +2831,7 @@
                     try {
                         service.unregisterRecordingCallback(mRecCb);
                     } catch (RemoteException e) {
-                        Log.e(TAG, "Dead object in unregisterRecordingCallback", e);
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             } else {
@@ -2883,13 +2846,12 @@
      * @return a non-null array of recording configurations. An array of length 0 indicates there is
      *     no recording active when queried.
      */
-    public @NonNull AudioRecordConfiguration[] getActiveRecordConfigurations() {
+    public @NonNull AudioRecordingConfiguration[] getActiveRecordingConfigurations() {
         final IAudioService service = getService();
         try {
-            return service.getActiveRecordConfigurations();
+            return service.getActiveRecordingConfigurations();
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to retrieve active record configurations", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2942,14 +2904,15 @@
 
     private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
 
-        public void dispatchRecordingConfigChange() {
+        public void dispatchRecordingConfigChange(AudioRecordingConfiguration[] configs) {
             synchronized(mRecordCallbackLock) {
                 if (mRecordCallbackList != null) {
                     for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
                         final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
                         if (arci.mHandler != null) {
                             final Message m = arci.mHandler.obtainMessage(
-                                    MSSG_RECORDING_CONFIG_CHANGE/*what*/, arci.mCb/*obj*/);
+                                    MSSG_RECORDING_CONFIG_CHANGE/*what*/,
+                                    new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
                             arci.mHandler.sendMessage(m);
                         }
                     }
@@ -2972,7 +2935,7 @@
         try {
             service.reloadAudioSettings();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in reloadAudioSettings"+e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2987,7 +2950,7 @@
         try {
             service.avrcpSupportsAbsoluteVolume(address, support);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in avrcpSupportsAbsoluteVolume", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3281,7 +3244,7 @@
             service.setWiredDeviceConnectionState(type, state, address, name,
                     mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setWiredDeviceConnectionState "+e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3303,7 +3266,7 @@
         try {
             delay = service.setBluetoothA2dpDeviceConnectionState(device, state, profile);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setBluetoothA2dpDeviceConnectionState "+e);
+            throw e.rethrowFromSystemServer();
         }
         return delay;
     }
@@ -3313,7 +3276,7 @@
         try {
             return getService().getRingtonePlayer();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3321,6 +3284,7 @@
      * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
      * for this device's primary output stream, in decimal Hz.
      */
+    // FIXME Deprecate
     public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
             "android.media.property.OUTPUT_SAMPLE_RATE";
 
@@ -3328,6 +3292,7 @@
      * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
      * for this device's primary output stream, in decimal PCM frames.
      */
+    // FIXME Deprecate
     public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
             "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
 
@@ -3406,7 +3371,7 @@
         try {
             getService().setVolumeController(controller);
         } catch (RemoteException e) {
-            Log.w(TAG, "Error setting volume controller", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3420,7 +3385,7 @@
         try {
             getService().notifyVolumeControllerVisible(controller, visible);
         } catch (RemoteException e) {
-            Log.w(TAG, "Error notifying about volume controller visibility", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3432,8 +3397,7 @@
         try {
             return getService().isStreamAffectedByRingerMode(streamType);
         } catch (RemoteException e) {
-            Log.w(TAG, "Error calling isStreamAffectedByRingerMode", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3445,8 +3409,7 @@
         try {
             return getService().isStreamAffectedByMute(streamType);
         } catch (RemoteException e) {
-            Log.w(TAG, "Error calling isStreamAffectedByMute", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3458,7 +3421,7 @@
         try {
             getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.w(TAG, "Error disabling safe media volume", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3470,7 +3433,7 @@
         try {
             getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
         } catch (RemoteException e) {
-            Log.w(TAG, "Error calling setRingerModeInternal", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3482,8 +3445,7 @@
         try {
             return getService().getRingerModeInternal();
         } catch (RemoteException e) {
-            Log.w(TAG, "Error calling getRingerModeInternal", e);
-            return RINGER_MODE_NORMAL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3495,7 +3457,7 @@
         try {
             getService().setVolumePolicy(policy);
         } catch (RemoteException e) {
-            Log.w(TAG, "Error calling setVolumePolicy", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3510,8 +3472,7 @@
         try {
             return getService().setHdmiSystemAudioSupported(on);
         } catch (RemoteException e) {
-            Log.w(TAG, "Error setting system audio mode", e);
-            return AudioSystem.DEVICE_NONE;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3525,8 +3486,7 @@
         try {
             return getService().isHdmiSystemAudioSupported();
         } catch (RemoteException e) {
-            Log.w(TAG, "Error querying system audio mode", e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java
index acadb41..6c70213 100644
--- a/media/java/android/media/AudioPatch.java
+++ b/media/java/android/media/AudioPatch.java
@@ -53,6 +53,13 @@
         return mSinks;
     }
 
+    /**
+     * Get the system unique patch ID.
+     */
+    public int id() {
+        return mHandle.id();
+    }
+
     @Override
     public String toString() {
         StringBuilder s = new StringBuilder();
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index e342385..ca306cc 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -57,10 +57,6 @@
     // Constants
     //--------------------
 
-    /** Minimum value for sample rate */
-    private static final int SAMPLE_RATE_HZ_MIN = 4000;
-    /** Maximum value for sample rate */
-    private static final int SAMPLE_RATE_HZ_MAX = 192000;
 
     /**
      *  indicates AudioRecord state is not successfully initialized.
@@ -168,8 +164,9 @@
     //--------------------
     /**
      * The audio data sampling rate in Hz.
+     * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
      */
-    private int mSampleRate;
+    private int mSampleRate; // initialized by all constructors via audioParamCheck()
     /**
      * The number of input audio channels (1 is mono, 2 is stereo)
      */
@@ -231,7 +228,7 @@
     /**
      * Audio session ID
      */
-    private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+    private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
     /**
      * AudioAttributes
      */
@@ -251,6 +248,9 @@
      * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
      *   rate that is guaranteed to work on all devices, but other rates such as 22050,
      *   16000, and 11025 may work on some devices.
+     *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+     *   which is usually the sample rate of the source.
+     *   {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
      *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
@@ -337,16 +337,9 @@
             mAudioAttributes = attributes;
         }
 
-        int rate = 0;
-        if ((format.getPropertySetMask()
-                & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
-        {
-            rate = format.getSampleRate();
-        } else {
-            rate = AudioSystem.getPrimaryOutputSamplingRate();
-            if (rate <= 0) {
-                rate = 44100;
-            }
+        int rate = format.getSampleRate();
+        if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
+            rate = 0;
         }
 
         int encoding = AudioFormat.ENCODING_DEFAULT;
@@ -373,19 +366,21 @@
 
         audioBuffSizeCheck(bufferSizeInBytes);
 
+        int[] sampleRate = new int[] {mSampleRate};
         int[] session = new int[1];
         session[0] = sessionId;
         //TODO: update native initialization when information about hardware init failure
         //      due to capture device already open is available.
         int initResult = native_setup( new WeakReference<AudioRecord>(this),
-                mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask,
+                mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask,
                 mAudioFormat, mNativeBufferSizeInBytes,
-                session, ActivityThread.currentOpPackageName());
+                session, ActivityThread.currentOpPackageName(), 0 /*nativeRecordInJavaObj*/);
         if (initResult != SUCCESS) {
             loge("Error code "+initResult+" when initializing native AudioRecord object.");
             return; // with mState == STATE_UNINITIALIZED
         }
 
+        mSampleRate = sampleRate[0];
         mSessionId = session[0];
 
         mState = STATE_INITIALIZED;
@@ -395,14 +390,52 @@
      * A constructor which explicitly connects a Native (C++) AudioRecord. For use by
      * the AudioRecordRoutingProxy subclass.
      * @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord
-     * (associated with an OpenSL ES recorder).
+     * (associated with an OpenSL ES recorder). Note: the caller must ensure a correct
+     * value here as no error checking is or can be done.
      */
     /*package*/ AudioRecord(long nativeRecordInJavaObj) {
-        mNativeRecorderInJavaObj = nativeRecordInJavaObj;
+        mNativeRecorderInJavaObj = 0;
+        mNativeCallbackCookie = 0;
+        mNativeDeviceCallback = 0;
 
-        // other initialization here...
+        // other initialization...
+        if (nativeRecordInJavaObj != 0) {
+            deferred_connect(nativeRecordInJavaObj);
+        } else {
+            mState = STATE_UNINITIALIZED;
+        }
+    }
 
-        mState = STATE_INITIALIZED;
+    /**
+     * @hide
+     */
+    /* package */ void deferred_connect(long  nativeRecordInJavaObj) {
+        if (mState != STATE_INITIALIZED) {
+            int[] session = { 0 };
+            int[] rates = { 0 };
+            //TODO: update native initialization when information about hardware init failure
+            //      due to capture device already open is available.
+            // Note that for this native_setup, we are providing an already created/initialized
+            // *Native* AudioRecord, so the attributes parameters to native_setup() are ignored.
+            int initResult = native_setup(new WeakReference<AudioRecord>(this),
+                    null /*mAudioAttributes*/,
+                    rates /*mSampleRates*/,
+                    0 /*mChannelMask*/,
+                    0 /*mChannelIndexMask*/,
+                    0 /*mAudioFormat*/,
+                    0 /*mNativeBufferSizeInBytes*/,
+                    session,
+                    ActivityThread.currentOpPackageName(),
+                    nativeRecordInJavaObj);
+            if (initResult != SUCCESS) {
+                loge("Error code "+initResult+" when initializing native AudioRecord object.");
+                return; // with mState == STATE_UNINITIALIZED
+            }
+
+            mSessionId = session[0];
+
+            mState = STATE_INITIALIZED;
+        }
     }
 
     /**
@@ -623,6 +656,7 @@
 
         return mask;
     }
+
     // postconditions:
     //    mRecordSource is valid
     //    mAudioFormat is valid
@@ -642,7 +676,9 @@
 
         //--------------
         // sample rate
-        if ((sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX)) {
+        if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
+                sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
+                sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
             throw new IllegalArgumentException(sampleRateInHz
                     + "Hz is not a supported sample rate.");
         }
@@ -714,7 +750,11 @@
     // Getters
     //--------------------
     /**
-     * Returns the configured audio data sample rate in Hz
+     * Returns the configured audio sink sample rate in Hz.
+     * The sink sample rate never changes after construction.
+     * If the constructor had a specific sample rate, then the sink sample rate is that value.
+     * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
+     * then the sink sample rate is a route-dependent default value based on the source [sic].
      */
     public int getSampleRate() {
         return mSampleRate;
@@ -861,6 +901,7 @@
      * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
      * configuration values.
      * @param sampleRateInHz the sample rate expressed in Hertz.
+     *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
      *   {@link AudioFormat#CHANNEL_IN_STEREO}
@@ -1708,13 +1749,17 @@
 
     private native final int native_setup(Object audiorecord_this,
             Object /*AudioAttributes*/ attributes,
-            int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
-            int buffSizeInBytes, int[] sessionId, String opPackageName);
+            int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
+            int buffSizeInBytes, int[] sessionId, String opPackageName,
+            long nativeRecordInJavaObj);
 
     // TODO remove: implementation calls directly into implementation of native_release()
     private native final void native_finalize();
 
-    private native final void native_release();
+    /**
+     * @hide
+     */
+    public native final void native_release();
 
     private native final int native_start(int syncEvent, int sessionId);
 
diff --git a/media/java/android/media/AudioRecordConfiguration.aidl b/media/java/android/media/AudioRecordConfiguration.aidl
deleted file mode 100644
index afe912b..0000000
--- a/media/java/android/media/AudioRecordConfiguration.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media;
-
-parcelable AudioRecordConfiguration;
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordConfiguration.java
deleted file mode 100644
index 69df88f..0000000
--- a/media/java/android/media/AudioRecordConfiguration.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * The AudioRecordConfiguration class collects the information describing an audio recording
- * session. This information is returned through the
- * {@link AudioManager#getActiveRecordConfigurations()} method.
- *
- */
-public class AudioRecordConfiguration implements Parcelable {
-
-    private final int mSessionId;
-
-    private final int mClientSource;
-
-    private final AudioFormat mDeviceFormat;
-    private final AudioFormat mClientFormat;
-
-    private final AudioDeviceInfo mRecDevice;
-
-    /**
-     * @hide
-     */
-    public AudioRecordConfiguration(int session, int source) {
-        mSessionId = session;
-        mClientSource = source;
-        mDeviceFormat = new AudioFormat.Builder().build();
-        mClientFormat = new AudioFormat.Builder().build();
-        mRecDevice = null;
-    }
-
-    /**
-     * @hide
-     */
-    public AudioRecordConfiguration(int session, int source, AudioFormat devFormat,
-            AudioFormat clientFormat, AudioDeviceInfo device) {
-        mSessionId = session;
-        mClientSource = source;
-        mDeviceFormat = devFormat;
-        mClientFormat = clientFormat;
-        mRecDevice = device;
-    }
-
-    /**
-     * Returns the audio source being used for the recording.
-     * @return one of {@link MediaRecorder.AudioSource#MIC},
-     *       {@link MediaRecorder.AudioSource#VOICE_UPLINK},
-     *       {@link MediaRecorder.AudioSource#VOICE_DOWNLINK},
-     *       {@link MediaRecorder.AudioSource#VOICE_CALL},
-     *       {@link MediaRecorder.AudioSource#CAMCORDER},
-     *       {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
-     *       {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
-     */
-    public int getClientAudioSource() { return mClientSource; }
-
-    /**
-     * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
-     * @return the session number.
-     */
-    public int getClientAudioSessionId() { return mSessionId; }
-
-    /**
-     * Returns the audio format at which audio is recorded on this Android device.
-     * Note that it may differ from the client application recording format
-     * (see {@link #getClientFormat()}).
-     * @return the device recording format
-     */
-    public AudioFormat getFormat() { return mDeviceFormat; }
-
-    /**
-     * Returns the audio format at which the client application is recording audio.
-     * Note that it may differ from the actual recording format (see {@link #getFormat()}).
-     * @return the recording format
-     */
-    public AudioFormat getClientFormat() { return mClientFormat; }
-
-    /**
-     * Returns the audio input device used for this recording.
-     * @return the audio recording device
-     */
-    public AudioDeviceInfo getAudioDevice() { return mRecDevice; }
-
-    public static final Parcelable.Creator<AudioRecordConfiguration> CREATOR
-            = new Parcelable.Creator<AudioRecordConfiguration>() {
-        /**
-         * Rebuilds an AudioRecordConfiguration previously stored with writeToParcel().
-         * @param p Parcel object to read the AudioRecordConfiguration from
-         * @return a new AudioRecordConfiguration created from the data in the parcel
-         */
-        public AudioRecordConfiguration createFromParcel(Parcel p) {
-            return new AudioRecordConfiguration(p);
-        }
-        public AudioRecordConfiguration[] newArray(int size) {
-            return new AudioRecordConfiguration[size];
-        }
-    };
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mSessionId, mClientSource);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mSessionId);
-        dest.writeInt(mClientSource);
-    }
-
-    private AudioRecordConfiguration(Parcel in) {
-        mSessionId = in.readInt();
-        mClientSource = in.readInt();
-        mDeviceFormat = new AudioFormat.Builder().build();
-        mClientFormat = new AudioFormat.Builder().build();
-        mRecDevice = null;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || !(o instanceof AudioRecordConfiguration)) return false;
-
-        final AudioRecordConfiguration that = (AudioRecordConfiguration) o;
-         return ((mSessionId == that.mSessionId)
-                 && (mClientSource == that.mClientSource));
-    }
-}
\ No newline at end of file
diff --git a/media/java/android/media/AudioRecordingConfiguration.aidl b/media/java/android/media/AudioRecordingConfiguration.aidl
new file mode 100644
index 0000000..c63d30b
--- /dev/null
+++ b/media/java/android/media/AudioRecordingConfiguration.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.media;
+
+parcelable AudioRecordingConfiguration;
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
new file mode 100644
index 0000000..cd6f95a
--- /dev/null
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * The AudioRecordingConfiguration class collects the information describing an audio recording
+ * session. This information is returned through the
+ * {@link AudioManager#getActiveRecordingConfigurations()} method.
+ *
+ */
+public final class AudioRecordingConfiguration implements Parcelable {
+    private final static String TAG = new String("AudioRecordingConfiguration");
+
+    private final int mSessionId;
+
+    private final int mClientSource;
+
+    private final AudioFormat mDeviceFormat;
+    private final AudioFormat mClientFormat;
+
+    private final int mPatchHandle;
+
+    /**
+     * @hide
+     */
+    public AudioRecordingConfiguration(int session, int source, AudioFormat devFormat,
+            AudioFormat clientFormat, int patchHandle) {
+        mSessionId = session;
+        mClientSource = source;
+        mDeviceFormat = devFormat;
+        mClientFormat = clientFormat;
+        mPatchHandle = patchHandle;
+    }
+
+    /** @hide */
+    @IntDef({
+        MediaRecorder.AudioSource.DEFAULT,
+        MediaRecorder.AudioSource.VOICE_UPLINK,
+        MediaRecorder.AudioSource.VOICE_DOWNLINK,
+        MediaRecorder.AudioSource.VOICE_CALL,
+        MediaRecorder.AudioSource.CAMCORDER,
+        MediaRecorder.AudioSource.VOICE_RECOGNITION,
+        MediaRecorder.AudioSource.VOICE_COMMUNICATION
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AudioSource {}
+
+    /**
+     * Returns the audio source being used for the recording.
+     * @return one of {@link MediaRecorder.AudioSource#MIC},
+     *       {@link MediaRecorder.AudioSource#VOICE_UPLINK},
+     *       {@link MediaRecorder.AudioSource#VOICE_DOWNLINK},
+     *       {@link MediaRecorder.AudioSource#VOICE_CALL},
+     *       {@link MediaRecorder.AudioSource#CAMCORDER},
+     *       {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
+     *       {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
+     */
+    public @AudioSource int getClientAudioSource() { return mClientSource; }
+
+    /**
+     * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
+     * @return the session number.
+     */
+    public int getClientAudioSessionId() { return mSessionId; }
+
+    /**
+     * Returns the audio format at which audio is recorded on this Android device.
+     * Note that it may differ from the client application recording format
+     * (see {@link #getClientFormat()}).
+     * @return the device recording format
+     */
+    public AudioFormat getFormat() { return mDeviceFormat; }
+
+    /**
+     * Returns the audio format at which the client application is recording audio.
+     * Note that it may differ from the actual recording format (see {@link #getFormat()}).
+     * @return the recording format
+     */
+    public AudioFormat getClientFormat() { return mClientFormat; }
+
+    /**
+     * Returns information about the audio input device used for this recording.
+     * @return the audio recording device or null if this information cannot be retrieved
+     */
+    public AudioDeviceInfo getAudioDevice() {
+        // build the AudioDeviceInfo from the patch handle
+        ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
+        if (AudioManager.listAudioPatches(patches) != AudioManager.SUCCESS) {
+            Log.e(TAG, "Error retrieving list of audio patches");
+            return null;
+        }
+        for (int i = 0 ; i < patches.size() ; i++) {
+            final AudioPatch patch = patches.get(i);
+            if (patch.id() == mPatchHandle) {
+                final AudioPortConfig[] sources = patch.sources();
+                if ((sources != null) && (sources.length > 0)) {
+                    // not supporting multiple sources, so just look at the first source
+                    final int devId = sources[0].port().id();
+                    final AudioDeviceInfo[] devices =
+                            AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
+                    for (int j = 0; j < devices.length; j++) {
+                        if (devices[j].getId() == devId) {
+                            return devices[j];
+                        }
+                    }
+                }
+                // patch handle is unique, there won't be another with the same handle
+                break;
+            }
+        }
+        Log.e(TAG, "Couldn't find device for recording, did recording end already?");
+        return null;
+    }
+
+    public static final Parcelable.Creator<AudioRecordingConfiguration> CREATOR
+            = new Parcelable.Creator<AudioRecordingConfiguration>() {
+        /**
+         * Rebuilds an AudioRecordingConfiguration previously stored with writeToParcel().
+         * @param p Parcel object to read the AudioRecordingConfiguration from
+         * @return a new AudioRecordingConfiguration created from the data in the parcel
+         */
+        public AudioRecordingConfiguration createFromParcel(Parcel p) {
+            return new AudioRecordingConfiguration(p);
+        }
+        public AudioRecordingConfiguration[] newArray(int size) {
+            return new AudioRecordingConfiguration[size];
+        }
+    };
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSessionId, mClientSource);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSessionId);
+        dest.writeInt(mClientSource);
+        mClientFormat.writeToParcel(dest, 0);
+        mDeviceFormat.writeToParcel(dest, 0);
+        dest.writeInt(mPatchHandle);
+    }
+
+    private AudioRecordingConfiguration(Parcel in) {
+        mSessionId = in.readInt();
+        mClientSource = in.readInt();
+        mClientFormat = AudioFormat.CREATOR.createFromParcel(in);
+        mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in);
+        mPatchHandle = in.readInt();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof AudioRecordingConfiguration)) return false;
+
+        AudioRecordingConfiguration that = (AudioRecordingConfiguration) o;
+
+        return ((mSessionId == that.mSessionId)
+                && (mClientSource == that.mClientSource)
+                && (mPatchHandle == that.mPatchHandle)
+                && (mClientFormat.equals(that.mClientFormat))
+                && (mDeviceFormat.equals(that.mDeviceFormat)));
+    }
+}
\ No newline at end of file
diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java
index 2161cf3..41f92d4 100644
--- a/media/java/android/media/AudioRouting.java
+++ b/media/java/android/media/AudioRouting.java
@@ -41,6 +41,14 @@
     public AudioDeviceInfo getPreferredDevice();
 
     /**
+     * Returns an {@link AudioDeviceInfo} identifying the current routing of this
+     * AudioTrack/AudioRecord.
+     * Note: The query is only valid if the AudioTrack/AudioRecord is currently playing.
+     * If it is not, <code>getRoutedDevice()</code> will return null.
+     */
+    public AudioDeviceInfo getRoutedDevice();
+
+    /**
      * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
      * changes on this AudioTrack/AudioRecord.
      * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index aa0d78d..f597440 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -273,7 +273,23 @@
      */
     public interface AudioRecordingCallback
     {
-        void onRecordingConfigurationChanged(int event, int session, int source);
+        /**
+         * Callback for recording activity notifications events
+         * @param event
+         * @param session
+         * @param source
+         * @param recordingFormat an array of ints containing respectively the client and device
+         *    recording configurations (2*3 ints), followed by the patch handle:
+         *    index 0: client format
+         *          1: client channel mask
+         *          2: client sample rate
+         *          3: device format
+         *          4: device channel mask
+         *          5: device sample rate
+         *          6: patch handle
+         */
+        void onRecordingConfigurationChanged(int event, int session, int source,
+                int[] recordingFormat);
     }
 
     private static AudioRecordingCallback sRecordingCallback;
@@ -285,13 +301,23 @@
         }
     }
 
-    private static void recordingCallbackFromNative(int event, int session, int source) {
+    /**
+     * Callback from native for recording configuration updates.
+     * @param event
+     * @param session
+     * @param source
+     * @param recordingFormat see
+     *     {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])} for
+     *     the description of the record format.
+     */
+    private static void recordingCallbackFromNative(int event, int session, int source,
+            int[] recordingFormat) {
         AudioRecordingCallback cb = null;
         synchronized (AudioSystem.class) {
             cb = sRecordingCallback;
         }
         if (cb != null) {
-            cb.onRecordingConfigurationChanged(event, session, source);
+            cb.onRecordingConfigurationChanged(event, session, source, recordingFormat);
         }
     }
 
@@ -346,6 +372,7 @@
     public static final int DEVICE_OUT_AUX_LINE = 0x200000;
     public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000;
     public static final int DEVICE_OUT_IP = 0x800000;
+    public static final int DEVICE_OUT_BUS = 0x1000000;
 
     public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
 
@@ -373,6 +400,7 @@
                                               DEVICE_OUT_AUX_LINE |
                                               DEVICE_OUT_SPEAKER_SAFE |
                                               DEVICE_OUT_IP |
+                                              DEVICE_OUT_BUS |
                                               DEVICE_OUT_DEFAULT);
     public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
                                                    DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -412,6 +440,7 @@
     public static final int DEVICE_IN_BLUETOOTH_A2DP = DEVICE_BIT_IN | 0x20000;
     public static final int DEVICE_IN_LOOPBACK = DEVICE_BIT_IN | 0x40000;
     public static final int DEVICE_IN_IP = DEVICE_BIT_IN | 0x80000;
+    public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000;
     public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
 
     public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
@@ -434,6 +463,7 @@
                                              DEVICE_IN_BLUETOOTH_A2DP |
                                              DEVICE_IN_LOOPBACK |
                                              DEVICE_IN_IP |
+                                             DEVICE_IN_BUS |
                                              DEVICE_IN_DEFAULT);
     public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
     public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -469,6 +499,7 @@
     public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line";
     public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe";
     public static final String DEVICE_OUT_IP_NAME = "ip";
+    public static final String DEVICE_OUT_BUS_NAME = "bus";
 
     public static final String DEVICE_IN_COMMUNICATION_NAME = "communication";
     public static final String DEVICE_IN_AMBIENT_NAME = "ambient";
@@ -490,6 +521,7 @@
     public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp";
     public static final String DEVICE_IN_LOOPBACK_NAME = "loopback";
     public static final String DEVICE_IN_IP_NAME = "ip";
+    public static final String DEVICE_IN_BUS_NAME = "bus";
 
     public static String getOutputDeviceName(int device)
     {
@@ -542,6 +574,8 @@
             return DEVICE_OUT_SPEAKER_SAFE_NAME;
         case DEVICE_OUT_IP:
             return DEVICE_OUT_IP_NAME;
+        case DEVICE_OUT_BUS:
+            return DEVICE_OUT_BUS_NAME;
         case DEVICE_OUT_DEFAULT:
         default:
             return Integer.toString(device);
@@ -591,6 +625,8 @@
             return DEVICE_IN_LOOPBACK_NAME;
         case DEVICE_IN_IP:
             return DEVICE_IN_IP_NAME;
+        case DEVICE_IN_BUS:
+            return DEVICE_IN_BUS_NAME;
         case DEVICE_IN_DEFAULT:
         default:
             return Integer.toString(device);
@@ -602,7 +638,7 @@
     public static final int PHONE_STATE_RINGING = 1;
     public static final int PHONE_STATE_INCALL = 2;
 
-    // device categories config for setForceUse, must match AudioSystem::forced_config
+    // device categories config for setForceUse, must match audio_policy_forced_cfg_t
     public static final int FORCE_NONE = 0;
     public static final int FORCE_SPEAKER = 1;
     public static final int FORCE_HEADPHONES = 2;
@@ -616,17 +652,20 @@
     public static final int FORCE_NO_BT_A2DP = 10;
     public static final int FORCE_SYSTEM_ENFORCED = 11;
     public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
-    private static final int NUM_FORCE_CONFIG = 13;
+    public static final int FORCE_ENCODED_SURROUND_NEVER = 13;
+    public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14;
+    public static final int NUM_FORCE_CONFIG = 15;
     public static final int FORCE_DEFAULT = FORCE_NONE;
 
-    // usage for setForceUse, must match AudioSystem::force_use
+    // usage for setForceUse, must match audio_policy_force_use_t
     public static final int FOR_COMMUNICATION = 0;
     public static final int FOR_MEDIA = 1;
     public static final int FOR_RECORD = 2;
     public static final int FOR_DOCK = 3;
     public static final int FOR_SYSTEM = 4;
     public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
-    private static final int NUM_FORCE_USE = 6;
+    public static final int FOR_ENCODED_SURROUND = 6;
+    private static final int NUM_FORCE_USE = 7;
 
     // usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
     public static final int SYNC_EVENT_NONE = 0;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6fc2f87..621129d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -91,11 +91,6 @@
      */
     private static final float GAIN_MAX = 1.0f;
 
-    /** Minimum value for sample rate */
-    private static final int SAMPLE_RATE_HZ_MIN = 4000;
-    /** Maximum value for sample rate */
-    private static final int SAMPLE_RATE_HZ_MAX = 192000;
-
     /** Maximum value for AudioTrack channel count
      * @hide public for MediaCode only, do not un-hide or change to a numeric literal
      */
@@ -254,6 +249,7 @@
     private final Looper mInitializationLooper;
     /**
      * The audio data source sampling rate in Hz.
+     * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
      */
     private int mSampleRate; // initialized by all constructors via audioParamCheck()
     /**
@@ -299,7 +295,7 @@
     /**
      * Audio session ID
      */
-    private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+    private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
     /**
      * Reference to the app-ops service.
      */
@@ -340,6 +336,9 @@
      *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
      *   {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
      * @param sampleRateInHz the initial source sample rate expressed in Hz.
+     *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+     *   which is usually the sample rate of the sink.
+     *   {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -369,7 +368,7 @@
             int bufferSizeInBytes, int mode)
     throws IllegalArgumentException {
         this(streamType, sampleRateInHz, channelConfig, audioFormat,
-                bufferSizeInBytes, mode, AudioSystem.AUDIO_SESSION_ALLOCATE);
+                bufferSizeInBytes, mode, AudioManager.AUDIO_SESSION_ID_GENERATE);
     }
 
     /**
@@ -389,6 +388,8 @@
      *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
      *   {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
      * @param sampleRateInHz the initial source sample rate expressed in Hz.
+     *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+     *   which is usually the sample rate of the sink.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -461,16 +462,11 @@
             looper = Looper.getMainLooper();
         }
 
-        int rate = 0;
-        if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
-        {
-            rate = format.getSampleRate();
-        } else {
-            rate = AudioSystem.getPrimaryOutputSamplingRate();
-            if (rate <= 0) {
-                rate = 44100;
-            }
+        int rate = format.getSampleRate();
+        if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
+            rate = 0;
         }
+
         int channelIndexMask = 0;
         if ((format.getPropertySetMask()
                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
@@ -503,17 +499,19 @@
             throw new IllegalArgumentException("Invalid audio session ID: "+sessionId);
         }
 
+        int[] sampleRate = new int[] {mSampleRate};
         int[] session = new int[1];
         session[0] = sessionId;
         // native initialization
         int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
-                mSampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
-                mNativeBufferSizeInBytes, mDataLoadMode, session);
+                sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
+                mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/);
         if (initResult != SUCCESS) {
             loge("Error code "+initResult+" when initializing AudioTrack.");
             return; // with mState == STATE_UNINITIALIZED
         }
 
+        mSampleRate = sampleRate[0];
         mSessionId = session[0];
 
         if (mDataLoadMode == MODE_STATIC) {
@@ -528,13 +526,18 @@
      * the AudioTrackRoutingProxy subclass.
      * @param nativeTrackInJavaObj a C/C++ pointer to a native AudioTrack
      * (associated with an OpenSL ES player).
+     * IMPORTANT: For "N", this method is ONLY called to setup a Java routing proxy,
+     * i.e. IAndroidConfiguration::AcquireJavaProxy(). If we call with a 0 in nativeTrackInJavaObj
+     * it means that the OpenSL player interface hasn't been realized, so there is no native
+     * Audiotrack to connect to. In this case wait to call deferred_connect() until the
+     * OpenSLES interface is realized.
      */
     /*package*/ AudioTrack(long nativeTrackInJavaObj) {
-        mNativeTrackInJavaObj = nativeTrackInJavaObj;
-
         // "final"s
         mAttributes = null;
         mAppOps = null;
+        mNativeTrackInJavaObj = 0;
+        mJniData = 0;
 
         // remember which looper is associated with the AudioTrack instantiation
         Looper looper;
@@ -544,8 +547,41 @@
         mInitializationLooper = looper;
 
         // other initialization...
+        if (nativeTrackInJavaObj != 0) {
+            deferred_connect(nativeTrackInJavaObj);
+        } else {
+            mState = STATE_UNINITIALIZED;
+        }
+    }
 
-        mState = STATE_INITIALIZED;
+    /**
+     * @hide
+     */
+    /* package */ void deferred_connect(long nativeTrackInJavaObj) {
+        if (mState != STATE_INITIALIZED) {
+            // Note that for this native_setup, we are providing an already created/initialized
+            // *Native* AudioTrack, so the attributes parameters to native_setup() are ignored.
+            int[] session = { 0 };
+            int[] rates = { 0 };
+            int initResult = native_setup(new WeakReference<AudioTrack>(this),
+                    null /*mAttributes - NA*/,
+                    rates /*sampleRate - NA*/,
+                    0 /*mChannelMask - NA*/,
+                    0 /*mChannelIndexMask - NA*/,
+                    0 /*mAudioFormat - NA*/,
+                    0 /*mNativeBufferSizeInBytes - NA*/,
+                    0 /*mDataLoadMode - NA*/,
+                    session,
+                    nativeTrackInJavaObj);
+            if (initResult != SUCCESS) {
+                loge("Error code "+initResult+" when initializing AudioTrack.");
+                return; // with mState == STATE_UNINITIALIZED
+            }
+
+            mSessionId = session[0];
+
+            mState = STATE_INITIALIZED;
+        }
     }
 
     /**
@@ -560,14 +596,14 @@
      * AudioTrack player = new AudioTrack.Builder()
      *         .setAudioAttributes(new AudioAttributes.Builder()
      *                  .setUsage(AudioAttributes.USAGE_ALARM)
-     *                  .setContentType(CONTENT_TYPE_MUSIC)
+     *                  .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
      *                  .build())
      *         .setAudioFormat(new AudioFormat.Builder()
      *                 .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
-     *                 .setSampleRate(441000)
+     *                 .setSampleRate(44100)
      *                 .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
      *                 .build())
-     *         .setBufferSize(minBuffSize)
+     *         .setBufferSizeInBytes(minBuffSize)
      *         .build();
      * </pre>
      * <p>
@@ -712,7 +748,7 @@
             if (mFormat == null) {
                 mFormat = new AudioFormat.Builder()
                         .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
-                        .setSampleRate(AudioSystem.getPrimaryOutputSamplingRate())
+                        //.setSampleRate(AudioFormat.SAMPLE_RATE_UNSPECIFIED)
                         .setEncoding(AudioFormat.ENCODING_DEFAULT)
                         .build();
             }
@@ -762,12 +798,23 @@
                                  int audioFormat, int mode) {
         //--------------
         // sample rate, note these values are subject to change
-        if (sampleRateInHz < SAMPLE_RATE_HZ_MIN || sampleRateInHz > SAMPLE_RATE_HZ_MAX) {
+        if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
+                sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
+                sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
             throw new IllegalArgumentException(sampleRateInHz
                     + "Hz is not a supported sample rate.");
         }
         mSampleRate = sampleRateInHz;
 
+        // IEC61937 is based on stereo. We could coerce it to stereo.
+        // But the application needs to know the stream is stereo so that
+        // it is encoded and played correctly. So better to just reject it.
+        if (audioFormat == AudioFormat.ENCODING_IEC61937
+                && channelConfig != AudioFormat.CHANNEL_OUT_STEREO) {
+            throw new IllegalArgumentException(
+                    "ENCODING_IEC61937 must be configured as CHANNEL_OUT_STEREO");
+        }
+
         //--------------
         // channel config
         mChannelConfiguration = channelConfig;
@@ -948,7 +995,13 @@
     }
 
     /**
-     * Returns the configured audio data sample rate in Hz
+     * Returns the configured audio source sample rate in Hz.
+     * The initial source sample rate depends on the constructor parameters,
+     * but the source sample rate may change if {@link #setPlaybackRate(int)} is called.
+     * If the constructor had a specific sample rate, then the initial sink sample rate is that
+     * value.
+     * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
+     * then the initial sink sample rate is a route-dependent default value based on the source [sic].
      */
     public int getSampleRate() {
         return mSampleRate;
@@ -1067,7 +1120,7 @@
      * <p> See also {@link AudioManager#getProperty(String)} for key
      * {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
      * @return current size in frames of the <code>AudioTrack</code> buffer.
-     * @throws IllegalStateException
+     * @throws IllegalStateException if track is not initialized.
      */
     public int getBufferSizeInFrames() {
         return native_get_buffer_size_frames();
@@ -1094,7 +1147,7 @@
      * @param bufferSizeInFrames requested buffer size
      * @return the actual buffer size in frames or an error code,
      *    {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
-     * @throws IllegalStateException
+     * @throws IllegalStateException if track is not initialized.
      */
     public int setBufferSizeInFrames(int bufferSizeInFrames) {
         if (mDataLoadMode == MODE_STATIC || mState == STATE_UNINITIALIZED) {
@@ -1123,7 +1176,7 @@
      *  <p> See also {@link AudioManager#getProperty(String)} for key
      *  {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
      *  @return maximum size in frames of the <code>AudioTrack</code> buffer.
-     *  @throws IllegalStateException
+     *  @throws IllegalStateException if track is not initialized.
      */
     public int getBufferCapacityInFrames() {
         return native_get_buffer_capacity_frames();
@@ -1190,13 +1243,12 @@
      * An underrun occurs if the application does not write audio
      * data quickly enough, causing the buffer to underflow
      * and a potential audio glitch or pop.
+     * <p>
      * Underruns are less likely when buffer sizes are large.
-     * <p> Though the "int" type is signed 32-bits, the value should be reinterpreted
-     * as if it is unsigned 32-bits.
-     * That is, the next position after 0x7FFFFFFF is (int) 0x80000000.
-     * This is a continuously advancing counter. It can wrap around to zero
-     * if there are too many underruns. If there were, for example, 68 underruns per
-     * second then the counter would wrap in 2 years.
+     * It may be possible to eliminate underruns by recreating the AudioTrack with
+     * a larger buffer.
+     * Or by using {@link #setBufferSizeInFrames(int)} to dynamically increase the
+     * effective size of the buffer.
      */
     public int getUnderrunCount() {
         return native_get_underrun_count();
@@ -1218,6 +1270,7 @@
      * to a higher value than the initial source sample rate, be sure to configure the buffer size
      * based on the highest planned sample rate.
      * @param sampleRateInHz the source sample rate expressed in Hz.
+     *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
      * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -1255,7 +1308,9 @@
         }
 
         // sample rate, note these values are subject to change
-        if ( (sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX) ) {
+        // Note: AudioFormat.SAMPLE_RATE_UNSPECIFIED is not allowed
+        if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||
+                (sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) {
             loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate.");
             return ERROR_BAD_VALUE;
         }
@@ -2763,12 +2818,15 @@
     //     AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC
     private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
             Object /*AudioAttributes*/ attributes,
-            int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
-            int buffSizeInBytes, int mode, int[] sessionId);
+            int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
+            int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack);
 
     private native final void native_finalize();
 
-    private native final void native_release();
+    /**
+     * @hide
+     */
+    public native final void native_release();
 
     private native final void native_start();
 
diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java
index 06fe6ff..170d9de 100644
--- a/media/java/android/media/DrmInitData.java
+++ b/media/java/android/media/DrmInitData.java
@@ -28,6 +28,12 @@
 public abstract class DrmInitData {
 
     /**
+     * Prevent public constuctor access
+     */
+    /* package private */ DrmInitData() {
+    }
+
+    /**
      * Retrieves initialization data for a given DRM scheme, specified by its UUID.
      *
      * @param schemeUuid The DRM scheme's UUID.
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 7fb67ee..3d7e744 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -16,92 +16,330 @@
 
 package android.media;
 
+import android.annotation.NonNull;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+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.RandomAccessFile;
-import java.util.regex.Pattern;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
 
 /**
  * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
  * <p>
  * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF and RAF.
+ * <p>
+ * Attribute mutation is supported for JPEG image files.
  */
 public class ExifInterface {
+    private static final String TAG = "ExifInterface";
+    private static final boolean DEBUG = false;
+
     // The Exif tag names
+    /** Type is String. */
+    public static final String TAG_ARTIST = "Artist";
     /** Type is int. */
-    public static final String TAG_ORIENTATION = "Orientation";
+    public static final String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+    /** Type is int. */
+    public static final String TAG_COMPRESSION = "Compression";
+    /** Type is String. */
+    public static final String TAG_COPYRIGHT = "Copyright";
     /** Type is String. */
     public static final String TAG_DATETIME = "DateTime";
     /** Type is String. */
+    public static final String TAG_IMAGE_DESCRIPTION = "ImageDescription";
+    /** Type is int. */
+    public static final String TAG_IMAGE_LENGTH = "ImageLength";
+    /** Type is int. */
+    public static final String TAG_IMAGE_WIDTH = "ImageWidth";
+    /** Type is int. */
+    public static final String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+    /** Type is int. */
+    public static final String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+    /** Type is String. */
     public static final String TAG_MAKE = "Make";
     /** Type is String. */
     public static final String TAG_MODEL = "Model";
     /** Type is int. */
-    public static final String TAG_FLASH = "Flash";
+    public static final String TAG_ORIENTATION = "Orientation";
     /** Type is int. */
-    public static final String TAG_IMAGE_WIDTH = "ImageWidth";
+    public static final String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
     /** Type is int. */
-    public static final String TAG_IMAGE_LENGTH = "ImageLength";
-    /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
-    public static final String TAG_GPS_LATITUDE = "GPSLatitude";
-    /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
-    public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
+    public static final String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+    /** Type is rational. */
+    public static final String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+    /** Type is rational. */
+    public static final String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+    /** Type is int. */
+    public static final String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+    /** Type is int. */
+    public static final String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+    /** Type is int. */
+    public static final String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
     /** Type is String. */
-    public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
+    public static final String TAG_SOFTWARE = "Software";
+    /** Type is int. */
+    public static final String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+    /** Type is int. */
+    public static final String TAG_STRIP_OFFSETS = "StripOffsets";
+    /** Type is int. */
+    public static final String TAG_TRANSFER_FUNCTION = "TransferFunction";
+    /** Type is rational. */
+    public static final String TAG_WHITE_POINT = "WhitePoint";
+    /** Type is rational. */
+    public static final String TAG_X_RESOLUTION = "XResolution";
+    /** Type is rational. */
+    public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+    /** Type is int. */
+    public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+    /** Type is int. */
+    public static final String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+    /** Type is rational. */
+    public static final String TAG_Y_RESOLUTION = "YResolution";
+    /** Type is rational. */
+    public static final String TAG_APERTURE_VALUE = "ApertureValue";
+    /** Type is rational. */
+    public static final String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
     /** Type is String. */
-    public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    public static final String TAG_CFA_PATTERN = "CFAPattern";
+    /** Type is int. */
+    public static final String TAG_COLOR_SPACE = "ColorSpace";
     /** Type is String. */
-    public static final String TAG_EXPOSURE_TIME = "ExposureTime";
-    /** Type is String. */
-    public static final String TAG_APERTURE = "FNumber";
-    /** Type is String. */
-    public static final String TAG_ISO = "ISOSpeedRatings";
+    public static final String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+    /** Type is rational. */
+    public static final String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+    /** Type is int. */
+    public static final String TAG_CONTRAST = "Contrast";
+    /** Type is int. */
+    public static final String TAG_CUSTOM_RENDERED = "CustomRendered";
     /** Type is String. */
     public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+    /** Type is String. */
+    public static final String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+    /** Type is String. */
+    public static final String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+    /** Type is double. */
+    public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+    /** Type is String. */
+    public static final String TAG_EXIF_VERSION = "ExifVersion";
+    /** Type is double. */
+    public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+    /** Type is rational. */
+    public static final String TAG_EXPOSURE_INDEX = "ExposureIndex";
+    /** Type is int. */
+    public static final String TAG_EXPOSURE_MODE = "ExposureMode";
+    /** Type is int. */
+    public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
+    /** Type is double. */
+    public static final String TAG_EXPOSURE_TIME = "ExposureTime";
+    /** Type is double. */
+    public static final String TAG_F_NUMBER = "FNumber";
+    /**
+     * Type is double.
+     *
+     * @deprecated use {@link #TAG_F_NUMBER} instead
+     */
+    @Deprecated
+    public static final String TAG_APERTURE = "FNumber";
+    /** Type is String. */
+    public static final String TAG_FILE_SOURCE = "FileSource";
+    /** Type is int. */
+    public static final String TAG_FLASH = "Flash";
+    /** Type is rational. */
+    public static final String TAG_FLASH_ENERGY = "FlashEnergy";
+    /** Type is String. */
+    public static final String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+    /** Type is rational. */
+    public static final String TAG_FOCAL_LENGTH = "FocalLength";
+    /** Type is int. */
+    public static final String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+    /** Type is int. */
+    public static final String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+    /** Type is rational. */
+    public static final String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+    /** Type is rational. */
+    public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+    /** Type is rational. */
+    public static final String TAG_GAIN_CONTROL = "GainControl";
+    /** Type is int. */
+    public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+    /**
+     * Type is int.
+     *
+     * @deprecated use {@link #TAG_ISO_SPEED_RATINGS} instead
+     */
+    @Deprecated
+    public static final String TAG_ISO = "ISOSpeedRatings";
+    /** Type is String. */
+    public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
+    /** Type is int. */
+    public static final String TAG_LIGHT_SOURCE = "LightSource";
+    /** Type is String. */
+    public static final String TAG_MAKER_NOTE = "MakerNote";
+    /** Type is rational. */
+    public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+    /** Type is int. */
+    public static final String TAG_METERING_MODE = "MeteringMode";
+    /** Type is String. */
+    public static final String TAG_OECF = "OECF";
+    /** Type is int. */
+    public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+    /** Type is int. */
+    public static final String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+    /** Type is String. */
+    public static final String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+    /** Type is int. */
+    public static final String TAG_SATURATION = "Saturation";
+    /** Type is int. */
+    public static final String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+    /** Type is String. */
+    public static final String TAG_SCENE_TYPE = "SceneType";
+    /** Type is int. */
+    public static final String TAG_SENSING_METHOD = "SensingMethod";
+    /** Type is int. */
+    public static final String TAG_SHARPNESS = "Sharpness";
+    /** Type is rational. */
+    public static final String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+    /** Type is String. */
+    public static final String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+    /** Type is String. */
+    public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
     /** Type is int. */
     public static final String TAG_SUBSEC_TIME = "SubSecTime";
     /** Type is int. */
-    public static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+    public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
     /** Type is int. */
     public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
-
-    /**
-     * @hide
-     */
-    public static final String TAG_SUBSECTIME = "SubSecTime";
-
+    /** Type is int. */
+    public static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+    /** Type is int. */
+    public static final String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+    /** Type is int. */
+    public static final String TAG_SUBJECT_AREA = "SubjectArea";
+    /** Type is double. */
+    public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+    /** Type is int. */
+    public static final String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+    /** Type is int. */
+    public static final String TAG_SUBJECT_LOCATION = "SubjectLocation";
+    /** Type is String. */
+    public static final String TAG_USER_COMMENT = "UserComment";
+    /** Type is int. */
+    public static final String TAG_WHITE_BALANCE = "WhiteBalance";
     /**
      * The altitude (in meters) based on the reference in TAG_GPS_ALTITUDE_REF.
      * Type is rational.
      */
     public static final String TAG_GPS_ALTITUDE = "GPSAltitude";
-
     /**
      * 0 if the altitude is above sea level. 1 if the altitude is below sea
      * level. Type is int.
      */
     public static final String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
-
     /** Type is String. */
-    public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    public static final String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
+    /** Type is rational. */
+    public static final String TAG_GPS_DOP = "GPSDOP";
     /** Type is String. */
     public static final String TAG_GPS_DATESTAMP = "GPSDateStamp";
-    /** Type is int. */
-    public static final String TAG_WHITE_BALANCE = "WhiteBalance";
     /** Type is rational. */
-    public static final String TAG_FOCAL_LENGTH = "FocalLength";
+    public static final String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+    /** Type is String. */
+    public static final String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+    /** Type is rational. */
+    public static final String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+    /** Type is String. */
+    public static final String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+    /** Type is rational. */
+    public static final String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+    /** Type is String. */
+    public static final String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+    /** Type is rational. */
+    public static final String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+    /** Type is String. */
+    public static final String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+    /** Type is int. */
+    public static final String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+    /** Type is rational. */
+    public static final String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+    /** Type is String. */
+    public static final String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
+    /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
+    public static final String TAG_GPS_LATITUDE = "GPSLatitude";
+    /** Type is String. */
+    public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
+    /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
+    public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
+    /** Type is String. */
+    public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    /** Type is String. */
+    public static final String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+    /** Type is String. */
+    public static final String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
     /** Type is String. Name of GPS processing method used for location finding. */
     public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+    /** Type is String. */
+    public static final String TAG_GPS_SATELLITES = "GPSSatellites";
+    /** Type is rational. */
+    public static final String TAG_GPS_SPEED = "GPSSpeed";
+    /** Type is String. */
+    public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+    /** Type is String. */
+    public static final String TAG_GPS_STATUS = "GPSStatus";
+    /** Type is String. */
+    public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    /** Type is rational. */
+    public static final String TAG_GPS_TRACK = "GPSTrack";
+    /** Type is String. */
+    public static final String TAG_GPS_TRACK_REF = "GPSTrackRef";
+    /** Type is String. */
+    public static final String TAG_GPS_VERSION_ID = "GPSVersionID";
+    /** Type is String. */
+    public static final String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
+    /** Type is int. */
+    public static final String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+    /** Type is int. */
+    public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+
+    // Private tags used for pointing the other IFD offset. The types of the following tags are int.
+    private static final String TAG_EXIF_IFD_POINTER = "ExifIFDPointer";
+    private static final String TAG_GPS_INFO_IFD_POINTER = "GPSInfoIFDPointer";
+    private static final String TAG_INTEROPERABILITY_IFD_POINTER = "InteroperabilityIFDPointer";
 
     // Private tags used for thumbnail information.
     private static final String TAG_HAS_THUMBNAIL = "hasThumbnail";
     private static final String TAG_THUMBNAIL_OFFSET = "thumbnailOffset";
     private static final String TAG_THUMBNAIL_LENGTH = "thumbnailLength";
+    private static final String TAG_THUMBNAIL_DATA = "thumbnailData";
 
     // Constants used for the Orientation Exif tag.
     public static final int ORIENTATION_UNDEFINED = 0;
@@ -119,30 +357,316 @@
     // Constants used for white balance
     public static final int WHITEBALANCE_AUTO = 0;
     public static final int WHITEBALANCE_MANUAL = 1;
+
+    private static final byte[] JPEG_SIGNATURE = new byte[] {(byte) 0xff, (byte) 0xd8, (byte) 0xff};
+    private static final int JPEG_SIGNATURE_SIZE = 3;
+
     private static SimpleDateFormat sFormatter;
 
-    static {
-        System.loadLibrary("jhead_jni");
-        System.loadLibrary("media_jni");
-        initRawNative();
+    // See Exchangeable image file format for digital still cameras: Exif version 2.2.
+    // The following values are for parsing EXIF data area. There are tag groups in EXIF data area.
+    // They are called "Image File Directory". They have multiple data formats to cover various
+    // image metadata from GPS longitude to camera model name.
 
+    // Types of Exif byte alignments (see JEITA CP-3451 page 10)
+    private static final short BYTE_ALIGN_II = 0x4949;  // II: Intel order
+    private static final short BYTE_ALIGN_MM = 0x4d4d;  // MM: Motorola order
+
+    // Formats for the value in IFD entry (See TIFF 6.0 spec Types page 15).
+    private static final int IFD_FORMAT_BYTE = 1;
+    private static final int IFD_FORMAT_STRING = 2;
+    private static final int IFD_FORMAT_USHORT = 3;
+    private static final int IFD_FORMAT_ULONG = 4;
+    private static final int IFD_FORMAT_URATIONAL = 5;
+    private static final int IFD_FORMAT_SBYTE = 6;
+    private static final int IFD_FORMAT_UNDEFINED = 7;
+    private static final int IFD_FORMAT_SSHORT = 8;
+    private static final int IFD_FORMAT_SLONG = 9;
+    private static final int IFD_FORMAT_SRATIONAL = 10;
+    private static final int IFD_FORMAT_SINGLE = 11;
+    private static final int IFD_FORMAT_DOUBLE = 12;
+    // Sizes of the components of each IFD value format
+    private static final int[] IFD_FORMAT_BYTES_PER_FORMAT = new int[] {
+            0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8
+    };
+    private static final byte[] EXIF_ASCII_PREFIX = new byte[] {
+            0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0
+    };
+
+    // A class for indicating EXIF tag.
+    private static class ExifTag {
+        public final int number;
+        public final String name;
+
+        private ExifTag(String name, int number) {
+            this.name = name;
+            this.number = number;
+        }
+    }
+
+    // Primary image IFD TIFF tags (See JEITA CP-3451 Table 14. page 54).
+    private static final ExifTag[] IFD_TIFF_TAGS = new ExifTag[] {
+            new ExifTag(TAG_IMAGE_WIDTH, 256),
+            new ExifTag(TAG_IMAGE_LENGTH, 257),
+            new ExifTag(TAG_BITS_PER_SAMPLE, 258),
+            new ExifTag(TAG_COMPRESSION, 259),
+            new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262),
+            new ExifTag(TAG_IMAGE_DESCRIPTION, 270),
+            new ExifTag(TAG_MAKE, 271),
+            new ExifTag(TAG_MODEL, 272),
+            new ExifTag(TAG_STRIP_OFFSETS, 273),
+            new ExifTag(TAG_ORIENTATION, 274),
+            new ExifTag(TAG_SAMPLES_PER_PIXEL, 277),
+            new ExifTag(TAG_ROWS_PER_STRIP, 278),
+            new ExifTag(TAG_STRIP_BYTE_COUNTS, 279),
+            new ExifTag(TAG_X_RESOLUTION, 282),
+            new ExifTag(TAG_Y_RESOLUTION, 283),
+            new ExifTag(TAG_PLANAR_CONFIGURATION, 284),
+            new ExifTag(TAG_RESOLUTION_UNIT, 296),
+            new ExifTag(TAG_TRANSFER_FUNCTION, 301),
+            new ExifTag(TAG_SOFTWARE, 305),
+            new ExifTag(TAG_DATETIME, 306),
+            new ExifTag(TAG_ARTIST, 315),
+            new ExifTag(TAG_WHITE_POINT, 318),
+            new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319),
+            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513),
+            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514),
+            new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529),
+            new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530),
+            new ExifTag(TAG_Y_CB_CR_POSITIONING, 531),
+            new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532),
+            new ExifTag(TAG_COPYRIGHT, 33432),
+            new ExifTag(TAG_EXIF_IFD_POINTER, 34665),
+            new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853),
+    };
+    // Primary image IFD Exif Private tags (See JEITA CP-3451 Table 15. page 55).
+    private static final ExifTag[] IFD_EXIF_TAGS = new ExifTag[] {
+            new ExifTag(TAG_EXPOSURE_TIME, 33434),
+            new ExifTag(TAG_F_NUMBER, 33437),
+            new ExifTag(TAG_EXPOSURE_PROGRAM, 34850),
+            new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852),
+            new ExifTag(TAG_ISO_SPEED_RATINGS, 34855),
+            new ExifTag(TAG_OECF, 34856),
+            new ExifTag(TAG_EXIF_VERSION, 36864),
+            new ExifTag(TAG_DATETIME_ORIGINAL, 36867),
+            new ExifTag(TAG_DATETIME_DIGITIZED, 36868),
+            new ExifTag(TAG_COMPONENTS_CONFIGURATION, 37121),
+            new ExifTag(TAG_COMPRESSED_BITS_PER_PIXEL, 37122),
+            new ExifTag(TAG_SHUTTER_SPEED_VALUE, 37377),
+            new ExifTag(TAG_APERTURE_VALUE, 37378),
+            new ExifTag(TAG_BRIGHTNESS_VALUE, 37379),
+            new ExifTag(TAG_EXPOSURE_BIAS_VALUE, 37380),
+            new ExifTag(TAG_MAX_APERTURE_VALUE, 37381),
+            new ExifTag(TAG_SUBJECT_DISTANCE, 37382),
+            new ExifTag(TAG_METERING_MODE, 37383),
+            new ExifTag(TAG_LIGHT_SOURCE, 37384),
+            new ExifTag(TAG_FLASH, 37385),
+            new ExifTag(TAG_FOCAL_LENGTH, 37386),
+            new ExifTag(TAG_SUBJECT_AREA, 37396),
+            new ExifTag(TAG_MAKER_NOTE, 37500),
+            new ExifTag(TAG_USER_COMMENT, 37510),
+            new ExifTag(TAG_SUBSEC_TIME, 37520),
+            new ExifTag(TAG_SUBSEC_TIME_ORIG, 37521),
+            new ExifTag(TAG_SUBSEC_TIME_DIG, 37522),
+            new ExifTag(TAG_FLASHPIX_VERSION, 40960),
+            new ExifTag(TAG_COLOR_SPACE, 40961),
+            new ExifTag(TAG_PIXEL_X_DIMENSION, 40962),
+            new ExifTag(TAG_PIXEL_Y_DIMENSION, 40963),
+            new ExifTag(TAG_RELATED_SOUND_FILE, 40964),
+            new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965),
+            new ExifTag(TAG_FLASH_ENERGY, 41483),
+            new ExifTag(TAG_SPATIAL_FREQUENCY_RESPONSE, 41484),
+            new ExifTag(TAG_FOCAL_PLANE_X_RESOLUTION, 41486),
+            new ExifTag(TAG_FOCAL_PLANE_Y_RESOLUTION, 41487),
+            new ExifTag(TAG_FOCAL_PLANE_RESOLUTION_UNIT, 41488),
+            new ExifTag(TAG_SUBJECT_LOCATION, 41492),
+            new ExifTag(TAG_EXPOSURE_INDEX, 41493),
+            new ExifTag(TAG_SENSING_METHOD, 41495),
+            new ExifTag(TAG_FILE_SOURCE, 41728),
+            new ExifTag(TAG_SCENE_TYPE, 41729),
+            new ExifTag(TAG_CFA_PATTERN, 41730),
+            new ExifTag(TAG_CUSTOM_RENDERED, 41985),
+            new ExifTag(TAG_EXPOSURE_MODE, 41986),
+            new ExifTag(TAG_WHITE_BALANCE, 41987),
+            new ExifTag(TAG_DIGITAL_ZOOM_RATIO, 41988),
+            new ExifTag(TAG_FOCAL_LENGTH_IN_35MM_FILM, 41989),
+            new ExifTag(TAG_SCENE_CAPTURE_TYPE, 41990),
+            new ExifTag(TAG_GAIN_CONTROL, 41991),
+            new ExifTag(TAG_CONTRAST, 41992),
+            new ExifTag(TAG_SATURATION, 41993),
+            new ExifTag(TAG_SHARPNESS, 41994),
+            new ExifTag(TAG_DEVICE_SETTING_DESCRIPTION, 41995),
+            new ExifTag(TAG_SUBJECT_DISTANCE_RANGE, 41996),
+            new ExifTag(TAG_IMAGE_UNIQUE_ID, 42016),
+    };
+    // Primary image IFD GPS Info tags (See JEITA CP-3451 Table 16. page 56).
+    private static final ExifTag[] IFD_GPS_TAGS = new ExifTag[] {
+            new ExifTag(TAG_GPS_VERSION_ID, 0),
+            new ExifTag(TAG_GPS_LATITUDE_REF, 1),
+            new ExifTag(TAG_GPS_LATITUDE, 2),
+            new ExifTag(TAG_GPS_LONGITUDE_REF, 3),
+            new ExifTag(TAG_GPS_LONGITUDE, 4),
+            new ExifTag(TAG_GPS_ALTITUDE_REF, 5),
+            new ExifTag(TAG_GPS_ALTITUDE, 6),
+            new ExifTag(TAG_GPS_TIMESTAMP, 7),
+            new ExifTag(TAG_GPS_SATELLITES, 8),
+            new ExifTag(TAG_GPS_STATUS, 9),
+            new ExifTag(TAG_GPS_MEASURE_MODE, 10),
+            new ExifTag(TAG_GPS_DOP, 11),
+            new ExifTag(TAG_GPS_SPEED_REF, 12),
+            new ExifTag(TAG_GPS_SPEED, 13),
+            new ExifTag(TAG_GPS_TRACK_REF, 14),
+            new ExifTag(TAG_GPS_TRACK, 15),
+            new ExifTag(TAG_GPS_IMG_DIRECTION_REF, 16),
+            new ExifTag(TAG_GPS_IMG_DIRECTION, 17),
+            new ExifTag(TAG_GPS_MAP_DATUM, 18),
+            new ExifTag(TAG_GPS_DEST_LATITUDE_REF, 19),
+            new ExifTag(TAG_GPS_DEST_LATITUDE, 20),
+            new ExifTag(TAG_GPS_DEST_LONGITUDE_REF, 21),
+            new ExifTag(TAG_GPS_DEST_LONGITUDE, 22),
+            new ExifTag(TAG_GPS_DEST_BEARING_REF, 23),
+            new ExifTag(TAG_GPS_DEST_BEARING, 24),
+            new ExifTag(TAG_GPS_DEST_DISTANCE_REF, 25),
+            new ExifTag(TAG_GPS_DEST_DISTANCE, 26),
+            new ExifTag(TAG_GPS_PROCESSING_METHOD, 27),
+            new ExifTag(TAG_GPS_AREA_INFORMATION, 28),
+            new ExifTag(TAG_GPS_DATESTAMP, 29),
+            new ExifTag(TAG_GPS_DIFFERENTIAL, 30),
+    };
+    // Primary image IFD Interoperability tag (See JEITA CP-3451 Table 17. page 56).
+    private static final ExifTag[] IFD_INTEROPERABILITY_TAGS = new ExifTag[] {
+            new ExifTag(TAG_INTEROPERABILITY_INDEX, 1),
+    };
+    // IFD Thumbnail tags (See JEITA CP-3451 Table 18. page 57).
+    private static final ExifTag[] IFD_THUMBNAIL_TAGS = new ExifTag[] {
+            new ExifTag(TAG_THUMBNAIL_IMAGE_WIDTH, 256),
+            new ExifTag(TAG_THUMBNAIL_IMAGE_LENGTH, 257),
+            new ExifTag(TAG_BITS_PER_SAMPLE, 258),
+            new ExifTag(TAG_COMPRESSION, 259),
+            new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262),
+            new ExifTag(TAG_IMAGE_DESCRIPTION, 270),
+            new ExifTag(TAG_MAKE, 271),
+            new ExifTag(TAG_MODEL, 272),
+            new ExifTag(TAG_STRIP_OFFSETS, 273),
+            new ExifTag(TAG_ORIENTATION, 274),
+            new ExifTag(TAG_SAMPLES_PER_PIXEL, 277),
+            new ExifTag(TAG_ROWS_PER_STRIP, 278),
+            new ExifTag(TAG_STRIP_BYTE_COUNTS, 279),
+            new ExifTag(TAG_X_RESOLUTION, 282),
+            new ExifTag(TAG_Y_RESOLUTION, 283),
+            new ExifTag(TAG_PLANAR_CONFIGURATION, 284),
+            new ExifTag(TAG_RESOLUTION_UNIT, 296),
+            new ExifTag(TAG_TRANSFER_FUNCTION, 301),
+            new ExifTag(TAG_SOFTWARE, 305),
+            new ExifTag(TAG_DATETIME, 306),
+            new ExifTag(TAG_ARTIST, 315),
+            new ExifTag(TAG_WHITE_POINT, 318),
+            new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319),
+            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513),
+            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514),
+            new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529),
+            new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530),
+            new ExifTag(TAG_Y_CB_CR_POSITIONING, 531),
+            new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532),
+            new ExifTag(TAG_COPYRIGHT, 33432),
+            new ExifTag(TAG_EXIF_IFD_POINTER, 34665),
+            new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853),
+    };
+
+    // See JEITA CP-3451 Figure 5. page 9.
+    // The following values are used for indicating pointers to the other Image File Directorys.
+
+    // Indices of Exif Ifd tag groups
+    private static final int IFD_TIFF_HINT = 0;
+    private static final int IFD_EXIF_HINT = 1;
+    private static final int IFD_GPS_HINT = 2;
+    private static final int IFD_INTEROPERABILITY_HINT = 3;
+    private static final int IFD_THUMBNAIL_HINT = 4;
+    // List of Exif tag groups
+    private static final ExifTag[][] EXIF_TAGS = new ExifTag[][] {
+            IFD_TIFF_TAGS, IFD_EXIF_TAGS, IFD_GPS_TAGS, IFD_INTEROPERABILITY_TAGS,
+            IFD_THUMBNAIL_TAGS
+    };
+    // List of tags for pointing to the other image file directory offset.
+    private static final ExifTag[] IFD_POINTER_TAGS = new ExifTag[] {
+            new ExifTag(TAG_EXIF_IFD_POINTER, 34665),
+            new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853),
+            new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965),
+    };
+    // List of indices of the indicated tag groups according to the IFD_POINTER_TAGS
+    private static final int[] IFD_POINTER_TAG_HINTS = new int[] {
+            IFD_EXIF_HINT, IFD_GPS_HINT, IFD_INTEROPERABILITY_HINT
+    };
+    // Tags for indicating the thumbnail offset and length
+    private static final ExifTag JPEG_INTERCHANGE_FORMAT_TAG =
+            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513);
+    private static final ExifTag JPEG_INTERCHANGE_FORMAT_LENGTH_TAG =
+            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514);
+
+    // Mappings from tag number to tag name and each item represents one IFD tag group.
+    private static final HashMap[] sExifTagMapsForReading = new HashMap[EXIF_TAGS.length];
+    // Mappings from tag name to tag number and each item represents one IFD tag group.
+    private static final HashMap[] sExifTagMapsForWriting = new HashMap[EXIF_TAGS.length];
+
+    // See JPEG File Interchange Format Version 1.02.
+    // The following values are defined for handling JPEG streams. In this implementation, we are
+    // not only getting information from EXIF but also from some JPEG special segments such as
+    // MARKER_COM for user comment and MARKER_SOFx for image width and height.
+
+    // Identifier for EXIF APP1 segment in JPEG
+    private static final byte[] IDENTIFIER_EXIF_APP1 =
+            "Exif\0\0".getBytes(Charset.forName("US-ASCII"));
+    // JPEG segment markers, that each marker consumes two bytes beginning with 0xff and ending with
+    // the indicator. There is no SOF4, SOF8, SOF16 markers in JPEG and SOFx markers indicates start
+    // of frame(baseline DCT) and the image size info exists in its beginning part.
+    private static final byte MARKER = (byte) 0xff;
+    private static final byte MARKER_SOI = (byte) 0xd8;
+    private static final byte MARKER_SOF0 = (byte) 0xc0;
+    private static final byte MARKER_SOF1 = (byte) 0xc1;
+    private static final byte MARKER_SOF2 = (byte) 0xc2;
+    private static final byte MARKER_SOF3 = (byte) 0xc3;
+    private static final byte MARKER_SOF5 = (byte) 0xc5;
+    private static final byte MARKER_SOF6 = (byte) 0xc6;
+    private static final byte MARKER_SOF7 = (byte) 0xc7;
+    private static final byte MARKER_SOF9 = (byte) 0xc9;
+    private static final byte MARKER_SOF10 = (byte) 0xca;
+    private static final byte MARKER_SOF11 = (byte) 0xcb;
+    private static final byte MARKER_SOF13 = (byte) 0xcd;
+    private static final byte MARKER_SOF14 = (byte) 0xce;
+    private static final byte MARKER_SOF15 = (byte) 0xcf;
+    private static final byte MARKER_SOS = (byte) 0xda;
+    private static final byte MARKER_APP1 = (byte) 0xe1;
+    private static final byte MARKER_COM = (byte) 0xfe;
+    private static final byte MARKER_EOI = (byte) 0xd9;
+
+    static {
+        System.loadLibrary("media_jni");
+        nativeInitRaw();
         sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
         sFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+        // Build up the hash tables to look up Exif tags for reading Exif tags.
+        for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+            sExifTagMapsForReading[hint] = new HashMap();
+            sExifTagMapsForWriting[hint] = new HashMap();
+            for (ExifTag tag : EXIF_TAGS[hint]) {
+                sExifTagMapsForReading[hint].put(tag.number, tag.name);
+                sExifTagMapsForWriting[hint].put(tag.name, tag.number);
+            }
+        }
     }
 
     private final String mFilename;
-    private final HashMap<String, String> mAttributes = new HashMap<>();
+    private final FileDescriptor mSeekableFileDescriptor;
+    private final AssetManager.AssetInputStream mAssetInputStream;
+    private final boolean mIsInputStream;
     private boolean mIsRaw;
+    private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
     private boolean mHasThumbnail;
     // The following values used for indicating a thumbnail position.
     private int mThumbnailOffset;
     private int mThumbnailLength;
-
-    // Because the underlying implementation (jhead) uses static variables,
-    // there can only be one user at a time for the native functions (and
-    // they cannot keep state in the native code across function calls). We
-    // use sLock to serialize the accesses.
-    private static final Object sLock = new Object();
+    private byte[] mThumbnailBytes;
 
     // Pattern to check non zero timestamp
     private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
@@ -154,9 +678,78 @@
         if (filename == null) {
             throw new IllegalArgumentException("filename cannot be null");
         }
+        FileInputStream in = null;
+        mAssetInputStream = null;
         mFilename = filename;
-        // First test whether a given file is a one of RAW format or not.
-        loadAttributes();
+        mIsInputStream = false;
+        try {
+            in = new FileInputStream(filename);
+            if (isSeekableFD(in.getFD())) {
+                mSeekableFileDescriptor = in.getFD();
+            } else {
+                mSeekableFileDescriptor = null;
+            }
+            loadAttributes(in);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    /**
+     * Reads Exif tags from the specified image file descriptor. Attribute mutation is supported
+     * for writable and seekable file descriptors only.
+     */
+    public ExifInterface(FileDescriptor fileDescriptor) throws IOException {
+        if (fileDescriptor == null) {
+            throw new IllegalArgumentException("fileDescriptor cannot be null");
+        }
+        mAssetInputStream = null;
+        mFilename = null;
+        if (isSeekableFD(fileDescriptor)) {
+            mSeekableFileDescriptor = fileDescriptor;
+            // Keep the original file descriptor in order to save attributes when it's seekable.
+            // Otherwise, just close the given file descriptor after reading it because the save
+            // feature won't be working.
+            try {
+                fileDescriptor = Os.dup(fileDescriptor);
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+        } else {
+            mSeekableFileDescriptor = null;
+        }
+        mIsInputStream = false;
+        FileInputStream in = null;
+        try {
+            in = new FileInputStream(fileDescriptor);
+            loadAttributes(in);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    /**
+     * Reads Exif tags from the specified image input stream. Attribute mutation is not supported
+     * for input streams.
+     */
+    public ExifInterface(InputStream inputStream) throws IOException {
+        if (inputStream == null) {
+            throw new IllegalArgumentException("inputStream cannot be null");
+        }
+        mFilename = null;
+        if (inputStream instanceof AssetManager.AssetInputStream) {
+            mAssetInputStream = (AssetManager.AssetInputStream) inputStream;
+            mSeekableFileDescriptor = null;
+        } else if (inputStream instanceof FileInputStream
+                && isSeekableFD(((FileInputStream) inputStream).getFD())) {
+            mAssetInputStream = null;
+            mSeekableFileDescriptor = ((FileInputStream) inputStream).getFD();
+        } else {
+            mAssetInputStream = null;
+            mSeekableFileDescriptor = null;
+        }
+        mIsInputStream = true;
+        loadAttributes(inputStream);
     }
 
     /**
@@ -166,7 +759,15 @@
      * @param tag the name of the tag.
      */
     public String getAttribute(String tag) {
-        return mAttributes.get(tag);
+        // Retrieves all tag groups. The value from primary image tag group has a higher priority
+        // than the value from the thumbnail tag group if there are more than one candidates.
+        for (int i = 0; i < EXIF_TAGS.length; ++i) {
+            Object value = mAttributes[i].get(tag);
+            if (value != null) {
+                return (String) value;
+            }
+        }
+        return null;
     }
 
     /**
@@ -178,34 +779,34 @@
      * @param defaultValue the value to return if the tag is not available.
      */
     public int getAttributeInt(String tag, int defaultValue) {
-        String value = mAttributes.get(tag);
+        String value = getAttribute(tag);
         if (value == null) return defaultValue;
         try {
             return Integer.valueOf(value);
-        } catch (NumberFormatException ex) {
+        } catch (NumberFormatException e) {
             return defaultValue;
         }
     }
 
     /**
-     * Returns the double value of the specified rational tag. If there is no
-     * such tag in the image file or the value cannot be parsed as double, return
-     * <var>defaultValue</var>.
+     * Returns the double value of the tag that is specified as rational or contains a
+     * double-formatted value. If there is no such tag in the image file or the value cannot be
+     * parsed as double, return <var>defaultValue</var>.
      *
      * @param tag the name of the tag.
      * @param defaultValue the value to return if the tag is not available.
      */
     public double getAttributeDouble(String tag, double defaultValue) {
-        String value = mAttributes.get(tag);
+        String value = getAttribute(tag);
         if (value == null) return defaultValue;
         try {
             int index = value.indexOf("/");
-            if (index == -1) return defaultValue;
+            if (index == -1) return Double.parseDouble(value);
             double denom = Double.parseDouble(value.substring(index + 1));
             if (denom == 0) return defaultValue;
             double num = Double.parseDouble(value.substring(0, index));
             return num / denom;
-        } catch (NumberFormatException ex) {
+        } catch (NumberFormatException e) {
             return defaultValue;
         }
     }
@@ -217,81 +818,144 @@
      * @param value the value of the tag.
      */
     public void setAttribute(String tag, String value) {
-        mAttributes.put(tag, value);
+        for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+            if (i == IFD_THUMBNAIL_HINT && !mHasThumbnail) {
+                continue;
+            }
+            if (sExifTagMapsForWriting[i].containsKey(tag)) {
+                mAttributes[i].put(tag, value);
+            }
+        }
     }
 
     /**
-     * Initialize mAttributes with the attributes from the file mFilename.
+     * Update the values of the tags in the tag groups if any value for the tag already was stored.
      *
-     * mAttributes is a HashMap which stores the Exif attributes of the file.
-     * The key is the standard tag name and the value is the tag's value: e.g.
-     * Model -&gt; Nikon. Numeric values are stored as strings.
-     *
-     * This function also initialize mHasThumbnail to indicate whether the
-     * file has a thumbnail inside.
+     * @param tag the name of the tag.
+     * @param value the value of the tag.
+     * @return Returns {@code true} if updating is placed.
      */
-    private void loadAttributes() throws IOException {
-        HashMap map = getRawAttributesNative(mFilename);
-        mIsRaw = map != null;
-        if (mIsRaw) {
-            for (Object o : map.entrySet()) {
-                Map.Entry entry = (Map.Entry) o;
-                String attrName = (String) entry.getKey();
-                String attrValue = (String) entry.getValue();
+    private boolean updateAttribute(String tag, String value) {
+        boolean updated = false;
+        for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+            if (mAttributes[i].containsKey(tag)) {
+                mAttributes[i].put(tag, value);
+                updated = true;
+            }
+        }
+        return updated;
+    }
 
-                switch (attrName) {
-                    case TAG_HAS_THUMBNAIL:
-                        mHasThumbnail = attrValue.equalsIgnoreCase("true");
-                        break;
-                    case TAG_THUMBNAIL_OFFSET:
-                        mThumbnailOffset = Integer.parseInt(attrValue);
-                        break;
-                    case TAG_THUMBNAIL_LENGTH:
-                        mThumbnailLength = Integer.parseInt(attrValue);
-                        break;
-                    default:
-                        mAttributes.put(attrName, attrValue);
-                        break;
+    /**
+     * Remove any values of the specified tag.
+     *
+     * @param tag the name of the tag.
+     */
+    private void removeAttribute(String tag) {
+        for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+            mAttributes[i].remove(tag);
+        }
+    }
+
+    /**
+     * This function decides which parser to read the image data according to the given input stream
+     * type and the content of the input stream. In each case, it reads the first three bytes to
+     * determine whether the image data format is JPEG or not.
+     */
+    private void loadAttributes(@NonNull InputStream in) throws IOException {
+        try {
+            // Initialize mAttributes.
+            for (int i = 0; i < EXIF_TAGS.length; ++i) {
+                mAttributes[i] = new HashMap();
+            }
+
+            // Process RAW input stream
+            if (mAssetInputStream != null) {
+                long asset = mAssetInputStream.getNativeAsset();
+                if (handleRawResult(nativeGetRawAttributesFromAsset(asset))) {
+                    return;
+                }
+            } else if (mSeekableFileDescriptor != null) {
+                if (handleRawResult(nativeGetRawAttributesFromFileDescriptor(
+                        mSeekableFileDescriptor))) {
+                    return;
+                }
+            } else {
+                in = new BufferedInputStream(in, JPEG_SIGNATURE_SIZE);
+                if (!isJpegInputStream((BufferedInputStream) in) && handleRawResult(
+                        nativeGetRawAttributesFromInputStream(in))) {
+                    return;
                 }
             }
-            return;
+
+            // Process JPEG input stream
+            getJpegAttributes(in);
+        } catch (IOException e) {
+            // Ignore exceptions in order to keep the compatibility with the old versions of
+            // ExifInterface.
+            Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file"
+                    + "(ExifInterface supports JPEG and some RAW image formats only) "
+                    + "or a corrupted JPEG file to ExifInterface.", e);
+        } finally {
+            if (DEBUG) {
+                printAttributes();
+            }
+        }
+    }
+
+    private static boolean isJpegInputStream(BufferedInputStream in) throws IOException {
+        in.mark(JPEG_SIGNATURE_SIZE);
+        byte[] signatureBytes = new byte[JPEG_SIGNATURE_SIZE];
+        if (in.read(signatureBytes) != JPEG_SIGNATURE_SIZE) {
+            throw new EOFException();
+        }
+        boolean isJpeg = Arrays.equals(JPEG_SIGNATURE, signatureBytes);
+        in.reset();
+        return isJpeg;
+    }
+
+    private boolean handleRawResult(HashMap map) {
+        if (map == null) {
+            return false;
         }
 
-        // format of string passed from native C code:
-        // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
-        // example:
-        // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
+        // Mark for disabling the save feature.
+        mIsRaw = true;
 
-        String attrStr;
-        synchronized (sLock) {
-            attrStr = getAttributesNative(mFilename);
+        String value = (String) map.remove(TAG_HAS_THUMBNAIL);
+        mHasThumbnail = value != null && value.equalsIgnoreCase("true");
+        value = (String) map.remove(TAG_THUMBNAIL_OFFSET);
+        if (value != null) {
+            mThumbnailOffset = Integer.parseInt(value);
+        }
+        value = (String) map.remove(TAG_THUMBNAIL_LENGTH);
+        if (value != null) {
+            mThumbnailLength = Integer.parseInt(value);
+        }
+        mThumbnailBytes = (byte[]) map.remove(TAG_THUMBNAIL_DATA);
+
+        for (Map.Entry entry : (Set<Map.Entry>) map.entrySet()) {
+            setAttribute((String) entry.getKey(), (String) entry.getValue());
         }
 
-        // get count
-        int ptr = attrStr.indexOf(' ');
-        int count = Integer.parseInt(attrStr.substring(0, ptr));
-        // skip past the space between item count and the rest of the attributes
-        ++ptr;
+        return true;
+    }
 
-        for (int i = 0; i < count; i++) {
-            // extract the attribute name
-            int equalPos = attrStr.indexOf('=', ptr);
-            String attrName = attrStr.substring(ptr, equalPos);
-            ptr = equalPos + 1;     // skip past =
+    private static boolean isSeekableFD(FileDescriptor fd) throws IOException {
+        try {
+            Os.lseek(fd, 0, OsConstants.SEEK_CUR);
+            return true;
+        } catch (ErrnoException e) {
+            return false;
+        }
+    }
 
-            // extract the attribute value length
-            int lenPos = attrStr.indexOf(' ', ptr);
-            int attrLen = Integer.parseInt(attrStr.substring(ptr, lenPos));
-            ptr = lenPos + 1;       // skip pas the space
-
-            // extract the attribute value
-            String attrValue = attrStr.substring(ptr, ptr + attrLen);
-            ptr += attrLen;
-
-            if (attrName.equals(TAG_HAS_THUMBNAIL)) {
-                mHasThumbnail = attrValue.equalsIgnoreCase("true");
-            } else {
-                mAttributes.put(attrName, attrValue);
+    // Prints out attributes for debugging.
+    private void printAttributes() {
+        for (int i = 0; i < mAttributes.length; ++i) {
+            Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size());
+            for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
+                Log.d(TAG, "tagName: " + entry.getKey() + ", tagValue: " + entry.getValue());
             }
         }
     }
@@ -299,7 +963,7 @@
     /**
      * Save the tag data into the original image file. This is expensive because it involves
      * copying all the data from one file to another and deleting the old file and renaming the
-     * other. It's best to use{@link #setAttribute(String,String)} to set all attributes to write
+     * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
      * and make a single call rather than multiple calls for each attribute.
      */
     public void saveAttributes() throws IOException {
@@ -307,33 +971,61 @@
             throw new UnsupportedOperationException(
                     "ExifInterface does not support saving attributes on RAW formats.");
         }
+        if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
+            throw new UnsupportedOperationException(
+                    "ExifInterface does not support saving attributes for the current input.");
+        }
 
-        // format of string passed to native C code:
-        // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
-        // example:
-        // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
-        StringBuilder sb = new StringBuilder();
-        int size = mAttributes.size();
-        if (mAttributes.containsKey(TAG_HAS_THUMBNAIL)) {
-            --size;
-        }
-        sb.append(size).append(" ");
-        for (Map.Entry<String, String> entry : mAttributes.entrySet()) {
-            String key = entry.getKey();
-            if (key.equals(TAG_HAS_THUMBNAIL)) {
-                // this is a fake attribute not saved as an exif tag
-                continue;
+        // Keep the thumbnail in memory
+        mThumbnailBytes = getThumbnail();
+
+        FileInputStream in = null;
+        FileOutputStream out = null;
+        File tempFile = null;
+        try {
+            // Move the original file to temporary file.
+            if (mFilename != null) {
+                tempFile = new File(mFilename + ".tmp");
+                File originalFile = new File(mFilename);
+                if (!originalFile.renameTo(tempFile)) {
+                    throw new IOException("Could'nt rename to " + tempFile.getAbsolutePath());
+                }
+            } else if (mSeekableFileDescriptor != null) {
+                tempFile = File.createTempFile("temp", "jpg");
+                Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+                in = new FileInputStream(mSeekableFileDescriptor);
+                out = new FileOutputStream(tempFile);
+                Streams.copy(in, out);
             }
-            String val = entry.getValue();
-            sb.append(key).append("=");
-            sb.append(val.length()).append(" ");
-            sb.append(val);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        } finally {
+            IoUtils.closeQuietly(in);
+            IoUtils.closeQuietly(out);
         }
-        String s = sb.toString();
-        synchronized (sLock) {
-            saveAttributesNative(mFilename, s);
-            commitChangesNative(mFilename);
+
+        in = null;
+        out = null;
+        try {
+            // Save the new file.
+            in = new FileInputStream(tempFile);
+            if (mFilename != null) {
+                out = new FileOutputStream(mFilename);
+            } else if (mSeekableFileDescriptor != null) {
+                Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+                out = new FileOutputStream(mSeekableFileDescriptor);
+            }
+            saveJpegAttributes(in, out);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        } finally {
+            IoUtils.closeQuietly(in);
+            IoUtils.closeQuietly(out);
+            tempFile.delete();
         }
+
+        // Discard the thumbnail in memory
+        mThumbnailBytes = null;
     }
 
     /**
@@ -349,27 +1041,44 @@
      * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)}
      */
     public byte[] getThumbnail() {
-        if (mIsRaw) {
-            if (mHasThumbnail) {
-                try (RandomAccessFile file = new RandomAccessFile(mFilename, "r")) {
-                    if (file.length() < mThumbnailLength + mThumbnailOffset) {
-                        throw new IOException("Corrupted image.");
-                    }
-                    file.seek(mThumbnailOffset);
-
-                    byte[] buffer = new byte[mThumbnailLength];
-                    file.readFully(buffer);
-                    return buffer;
-                } catch (IOException e) {
-                    // Couldn't get a thumbnail image.
-                }
-            }
+        if (!mHasThumbnail) {
             return null;
         }
-
-        synchronized (sLock) {
-            return getThumbnailNative(mFilename);
+        if (mThumbnailBytes != null) {
+            return mThumbnailBytes;
         }
+
+        // Read the thumbnail.
+        FileInputStream in = null;
+        try {
+            if (mAssetInputStream != null) {
+                return nativeGetThumbnailFromAsset(
+                        mAssetInputStream.getNativeAsset(), mThumbnailOffset, mThumbnailLength);
+            } else if (mFilename != null) {
+                in = new FileInputStream(mFilename);
+            } else if (mSeekableFileDescriptor != null) {
+                FileDescriptor fileDescriptor = Os.dup(mSeekableFileDescriptor);
+                Os.lseek(fileDescriptor, 0, OsConstants.SEEK_SET);
+                in = new FileInputStream(fileDescriptor);
+            }
+            if (in == null) {
+                // Should not be reached this.
+                throw new FileNotFoundException();
+            }
+            if (in.skip(mThumbnailOffset) != mThumbnailOffset) {
+                throw new IOException("Corrupted image");
+            }
+            byte[] buffer = new byte[mThumbnailLength];
+            if (in.read(buffer) != mThumbnailLength) {
+                throw new IOException("Corrupted image");
+            }
+            return buffer;
+        } catch (IOException | ErrnoException e) {
+            // Couldn't get a thumbnail image.
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+        return null;
     }
 
     /**
@@ -378,19 +1087,17 @@
      *
      * @return two-element array, the offset in the first value, and length in
      *         the second, or {@code null} if no thumbnail was found.
-     * @hide
      */
     public long[] getThumbnailRange() {
-        if (mIsRaw) {
-            long[] range = new long[2];
-            range[0] = mThumbnailOffset;
-            range[1] = mThumbnailLength;
-            return range;
+        if (!mHasThumbnail) {
+            return null;
         }
 
-        synchronized (sLock) {
-            return getThumbnailRangeNative(mFilename);
-        }
+        long[] range = new long[2];
+        range[0] = mThumbnailOffset;
+        range[1] = mThumbnailLength;
+
+        return range;
     }
 
     /**
@@ -399,10 +1106,10 @@
      * Exif tags are not available.
      */
     public boolean getLatLong(float output[]) {
-        String latValue = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE);
-        String latRef = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE_REF);
-        String lngValue = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE);
-        String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
+        String latValue = getAttribute(TAG_GPS_LATITUDE);
+        String latRef = getAttribute(TAG_GPS_LATITUDE_REF);
+        String lngValue = getAttribute(TAG_GPS_LONGITUDE);
+        String lngRef = getAttribute(TAG_GPS_LONGITUDE_REF);
 
         if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
             try {
@@ -428,7 +1135,7 @@
         int ref = getAttributeInt(TAG_GPS_ALTITUDE_REF, -1);
 
         if (altitude >= 0 && ref >= 0) {
-            return (double) (altitude * ((ref == 1) ? -1 : 1));
+            return (altitude * ((ref == 1) ? -1 : 1));
         } else {
             return defaultValue;
         }
@@ -440,7 +1147,7 @@
      * @hide
      */
     public long getDateTime() {
-        String dateTimeString = mAttributes.get(TAG_DATETIME);
+        String dateTimeString = getAttribute(TAG_DATETIME);
         if (dateTimeString == null
                 || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1;
 
@@ -452,7 +1159,7 @@
             if (datetime == null) return -1;
             long msecs = datetime.getTime();
 
-            String subSecs = mAttributes.get(TAG_SUBSECTIME);
+            String subSecs = getAttribute(TAG_SUBSEC_TIME);
             if (subSecs != null) {
                 try {
                     long sub = Long.valueOf(subSecs);
@@ -461,10 +1168,11 @@
                     }
                     msecs += sub;
                 } catch (NumberFormatException e) {
+                    // Ignored
                 }
             }
             return msecs;
-        } catch (IllegalArgumentException ex) {
+        } catch (IllegalArgumentException e) {
             return -1;
         }
     }
@@ -475,11 +1183,13 @@
      * @hide
      */
     public long getGpsDateTime() {
-        String date = mAttributes.get(TAG_GPS_DATESTAMP);
-        String time = mAttributes.get(TAG_GPS_TIMESTAMP);
+        String date = getAttribute(TAG_GPS_DATESTAMP);
+        String time = getAttribute(TAG_GPS_TIMESTAMP);
         if (date == null || time == null
                 || (!sNonZeroTimePattern.matcher(date).matches()
-                && !sNonZeroTimePattern.matcher(time).matches())) return -1;
+                && !sNonZeroTimePattern.matcher(time).matches())) {
+            return -1;
+        }
 
         String dateTimeString = date + ' ' + time;
 
@@ -488,13 +1198,12 @@
             Date datetime = sFormatter.parse(dateTimeString, pos);
             if (datetime == null) return -1;
             return datetime.getTime();
-        } catch (IllegalArgumentException ex) {
+        } catch (IllegalArgumentException e) {
             return -1;
         }
     }
 
-    private static float convertRationalLatLonToFloat(
-            String rationalString, String ref) {
+    private static float convertRationalLatLonToFloat(String rationalString, String ref) {
         try {
             String [] parts = rationalString.split(",");
 
@@ -522,22 +1231,1166 @@
         }
     }
 
-    // JNI methods for JPEG.
-    private static native boolean appendThumbnailNative(String fileName,
-            String thumbnailFileName);
+    // Loads EXIF attributes from a JPEG input stream.
+    private void getJpegAttributes(InputStream inputStream) throws IOException {
+        // See JPEG File Interchange Format Specification page 5.
+        if (DEBUG) {
+            Log.d(TAG, "getJpegAttributes starting with: " + inputStream);
+        }
+        DataInputStream dataInputStream = new DataInputStream(inputStream);
+        byte marker;
+        int bytesRead = 0;
+        if ((marker = dataInputStream.readByte()) != MARKER) {
+            throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
+        }
+        ++bytesRead;
+        if (dataInputStream.readByte() != MARKER_SOI) {
+            throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
+        }
+        ++bytesRead;
+        while (true) {
+            marker = dataInputStream.readByte();
+            if (marker != MARKER) {
+                throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff));
+            }
+            ++bytesRead;
+            marker = dataInputStream.readByte();
+            if (DEBUG) {
+                Log.d(TAG, "Found JPEG segment indicator: " + Integer.toHexString(marker & 0xff));
+            }
+            ++bytesRead;
 
-    private static native void saveAttributesNative(String fileName,
-            String compressedAttributes);
+            // EOI indicates the end of an image and in case of SOS, JPEG image stream starts and
+            // the image data will terminate right after.
+            if (marker == MARKER_EOI || marker == MARKER_SOS) {
+                break;
+            }
+            int length = dataInputStream.readUnsignedShort() - 2;
+            bytesRead += 2;
+            if (DEBUG) {
+                Log.d(TAG, "JPEG segment: " + Integer.toHexString(marker & 0xff) + " (length: "
+                        + (length + 2) + ")");
+            }
+            if (length < 0) {
+                throw new IOException("Invalid length");
+            }
+            switch (marker) {
+                case MARKER_APP1: {
+                    if (DEBUG) {
+                        Log.d(TAG, "MARKER_APP1");
+                    }
+                    if (length < 6) {
+                        // Skip if it's not an EXIF APP1 segment.
+                        break;
+                    }
+                    byte[] identifier = new byte[6];
+                    if (inputStream.read(identifier) != 6) {
+                        throw new IOException("Invalid exif");
+                    }
+                    bytesRead += 6;
+                    length -= 6;
+                    if (!Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
+                        // Skip if it's not an EXIF APP1 segment.
+                        break;
+                    }
+                    if (length <= 0) {
+                        throw new IOException("Invalid exif");
+                    }
+                    if (DEBUG) {
+                        Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")");
+                    }
+                    byte[] bytes = new byte[length];
+                    if (dataInputStream.read(bytes) != length) {
+                        throw new IOException("Invalid exif");
+                    }
+                    readExifSegment(bytes, bytesRead);
+                    bytesRead += length;
+                    length = 0;
+                    break;
+                }
 
-    private static native String getAttributesNative(String fileName);
+                case MARKER_COM: {
+                    byte[] bytes = new byte[length];
+                    if (dataInputStream.read(bytes) != length) {
+                        throw new IOException("Invalid exif");
+                    }
+                    length = 0;
+                    mAttributes[IFD_EXIF_HINT].put(TAG_USER_COMMENT,
+                            new String(bytes, Charset.forName("US-ASCII")));
+                    break;
+                }
 
-    private static native void commitChangesNative(String fileName);
+                case MARKER_SOF0:
+                case MARKER_SOF1:
+                case MARKER_SOF2:
+                case MARKER_SOF3:
+                case MARKER_SOF5:
+                case MARKER_SOF6:
+                case MARKER_SOF7:
+                case MARKER_SOF9:
+                case MARKER_SOF10:
+                case MARKER_SOF11:
+                case MARKER_SOF13:
+                case MARKER_SOF14:
+                case MARKER_SOF15: {
+                    if (dataInputStream.skipBytes(1) != 1) {
+                        throw new IOException("Invalid SOFx");
+                    }
+                    mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH,
+                            String.valueOf(dataInputStream.readUnsignedShort()));
+                    mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH,
+                            String.valueOf(dataInputStream.readUnsignedShort()));
+                    length -= 5;
+                    break;
+                }
 
-    private static native byte[] getThumbnailNative(String fileName);
+                default: {
+                    break;
+                }
+            }
+            if (length < 0) {
+                throw new IOException("Invalid length");
+            }
+            if (dataInputStream.skipBytes(length) != length) {
+                throw new IOException("Invalid JPEG segment");
+            }
+            bytesRead += length;
+        }
+    }
 
-    private static native long[] getThumbnailRangeNative(String fileName);
+    // Stores a new JPEG image with EXIF attributes into a given output stream.
+    private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream)
+            throws IOException {
+        // See JPEG File Interchange Format Specification page 5.
+        if (DEBUG) {
+            Log.d(TAG, "saveJpegAttributes starting with (inputStream: " + inputStream
+                    + ", outputStream: " + outputStream + ")");
+        }
+        DataInputStream dataInputStream = new DataInputStream(inputStream);
+        ExifDataOutputStream dataOutputStream = new ExifDataOutputStream(outputStream);
+        if (dataInputStream.readByte() != MARKER) {
+            throw new IOException("Invalid marker");
+        }
+        dataOutputStream.writeByte(MARKER);
+        if (dataInputStream.readByte() != MARKER_SOI) {
+            throw new IOException("Invalid marker");
+        }
+        dataOutputStream.writeByte(MARKER_SOI);
+
+        // Write EXIF APP1 segment
+        dataOutputStream.writeByte(MARKER);
+        dataOutputStream.writeByte(MARKER_APP1);
+        writeExifSegment(dataOutputStream, 6);
+
+        byte[] bytes = new byte[4096];
+
+        while (true) {
+            byte marker = dataInputStream.readByte();
+            if (marker != MARKER) {
+                throw new IOException("Invalid marker");
+            }
+            marker = dataInputStream.readByte();
+            switch (marker) {
+                case MARKER_APP1: {
+                    int length = dataInputStream.readUnsignedShort() - 2;
+                    if (length < 0) {
+                        throw new IOException("Invalid length");
+                    }
+                    byte[] identifier = new byte[6];
+                    if (length >= 6) {
+                        if (dataInputStream.read(identifier) != 6) {
+                            throw new IOException("Invalid exif");
+                        }
+                        if (Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
+                            // Skip the original EXIF APP1 segment.
+                            if (dataInputStream.skip(length - 6) != length - 6) {
+                                throw new IOException("Invalid length");
+                            }
+                            break;
+                        }
+                    }
+                    // Copy non-EXIF APP1 segment.
+                    dataOutputStream.writeByte(MARKER);
+                    dataOutputStream.writeByte(marker);
+                    dataOutputStream.writeUnsignedShort(length + 2);
+                    if (length >= 6) {
+                        length -= 6;
+                        dataOutputStream.write(identifier);
+                    }
+                    int read;
+                    while (length > 0 && (read = dataInputStream.read(
+                            bytes, 0, Math.min(length, bytes.length))) >= 0) {
+                        dataOutputStream.write(bytes, 0, read);
+                        length -= read;
+                    }
+                    break;
+                }
+                case MARKER_EOI:
+                case MARKER_SOS: {
+                    dataOutputStream.writeByte(MARKER);
+                    dataOutputStream.writeByte(marker);
+                    // Copy all the remaining data
+                    Streams.copy(dataInputStream, dataOutputStream);
+                    return;
+                }
+                default: {
+                    // Copy JPEG segment
+                    dataOutputStream.writeByte(MARKER);
+                    dataOutputStream.writeByte(marker);
+                    int length = dataInputStream.readUnsignedShort();
+                    dataOutputStream.writeUnsignedShort(length);
+                    length -= 2;
+                    if (length < 0) {
+                        throw new IOException("Invalid length");
+                    }
+                    int read;
+                    while (length > 0 && (read = dataInputStream.read(
+                            bytes, 0, Math.min(length, bytes.length))) >= 0) {
+                        dataOutputStream.write(bytes, 0, read);
+                        length -= read;
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    // Reads the given EXIF byte area and save its tag data into attributes.
+    private void readExifSegment(byte[] exifBytes, int exifOffsetFromBeginning) throws IOException {
+        // Parse TIFF Headers. See JEITA CP-3451C Table 1. page 10.
+        ByteOrderAwarenessDataInputStream dataInputStream =
+                new ByteOrderAwarenessDataInputStream(exifBytes);
+
+        // Read byte align
+        short byteOrder = dataInputStream.readShort();
+        switch (byteOrder) {
+            case BYTE_ALIGN_II:
+                if (DEBUG) {
+                    Log.d(TAG, "readExifSegment: Byte Align II");
+                }
+                dataInputStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+                break;
+            case BYTE_ALIGN_MM:
+                if (DEBUG) {
+                    Log.d(TAG, "readExifSegment: Byte Align MM");
+                }
+                dataInputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+                break;
+            default:
+                throw new IOException("Invalid byte order: " + Integer.toHexString(byteOrder));
+        }
+
+        int startCode = dataInputStream.readUnsignedShort();
+        if (startCode != 0x2a) {
+            throw new IOException("Invalid exif start: " + Integer.toHexString(startCode));
+        }
+
+        // Read first ifd offset
+        long firstIfdOffset = dataInputStream.readUnsignedInt();
+        if (firstIfdOffset < 8 || firstIfdOffset >= exifBytes.length) {
+            throw new IOException("Invalid first Ifd offset: " + firstIfdOffset);
+        }
+        firstIfdOffset -= 8;
+        if (firstIfdOffset > 0) {
+            if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset) {
+                throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset);
+            }
+        }
+
+        // Read primary image TIFF image file directory.
+        readImageFileDirectory(dataInputStream, IFD_TIFF_HINT);
+
+        // Process thumbnail.
+        String jpegInterchangeFormatString = getAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
+        String jpegInterchangeFormatLengthString =
+                getAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
+        if (jpegInterchangeFormatString != null && jpegInterchangeFormatLengthString != null) {
+            try {
+                int jpegInterchangeFormat = Integer.parseInt(jpegInterchangeFormatString);
+                int jpegInterchangeFormatLength = Integer
+                        .parseInt(jpegInterchangeFormatLengthString);
+                // The following code limits the size of thumbnail size not to overflow EXIF data area.
+                jpegInterchangeFormatLength = Math.min(jpegInterchangeFormat
+                        + jpegInterchangeFormatLength, exifOffsetFromBeginning + exifBytes.length)
+                        - jpegInterchangeFormat;
+                if (jpegInterchangeFormat > 0 && jpegInterchangeFormatLength > 0) {
+                    mHasThumbnail = true;
+                    mThumbnailOffset = exifOffsetFromBeginning + jpegInterchangeFormat;
+                    mThumbnailLength = jpegInterchangeFormatLength;
+
+                    if (mFilename == null && mAssetInputStream == null
+                            && mSeekableFileDescriptor == null) {
+                        // Save the thumbnail in memory if the input doesn't support reading again.
+                        byte[] thumbnailBytes = new byte[jpegInterchangeFormatLength];
+                        dataInputStream.seek(jpegInterchangeFormat);
+                        dataInputStream.readFully(thumbnailBytes);
+                        mThumbnailBytes = thumbnailBytes;
+
+                        if (DEBUG) {
+                            Bitmap bitmap = BitmapFactory.decodeByteArray(
+                                    thumbnailBytes, 0, thumbnailBytes.length);
+                            Log.d(TAG, "Thumbnail offset: " + mThumbnailOffset + ", length: "
+                                    + mThumbnailLength + ", width: " + bitmap.getWidth()
+                                    + ", height: "
+                                    + bitmap.getHeight());
+                        }
+                    }
+                }
+            } catch (NumberFormatException e) {
+                // Ignored the corrupted image.
+            }
+        }
+
+        // For compatibility, keep data formats as follows.
+        convertToInt(TAG_IMAGE_WIDTH);
+        convertToInt(TAG_IMAGE_LENGTH);
+        convertToInt(TAG_ORIENTATION);
+        convertToInt(TAG_FLASH);
+        convertToRational(TAG_FOCAL_LENGTH);
+        convertToDouble(TAG_DIGITAL_ZOOM_RATIO);
+        convertToDouble(TAG_EXPOSURE_TIME);
+        convertToDouble(TAG_F_NUMBER);
+        convertToDouble(TAG_SUBJECT_DISTANCE);
+        convertToInt(TAG_ISO_SPEED_RATINGS);
+        convertToDouble(TAG_EXPOSURE_BIAS_VALUE);
+        convertToInt(TAG_WHITE_BALANCE);
+        convertToInt(TAG_LIGHT_SOURCE);
+        convertToInt(TAG_METERING_MODE);
+        convertToInt(TAG_EXPOSURE_PROGRAM);
+        convertToInt(TAG_EXPOSURE_MODE);
+        convertToRational(TAG_GPS_ALTITUDE);
+        convertToInt(TAG_GPS_ALTITUDE_REF);
+        convertToRational(TAG_GPS_LONGITUDE);
+        convertToRational(TAG_GPS_LATITUDE);
+        convertToTimestamp(TAG_GPS_TIMESTAMP);
+
+        // The value of DATETIME tag has the same value of DATETIME_ORIGINAL tag.
+        String valueOfDateTimeOriginal = getAttribute(TAG_DATETIME_ORIGINAL);
+        if (valueOfDateTimeOriginal != null) {
+            mAttributes[IFD_TIFF_HINT].put(TAG_DATETIME, valueOfDateTimeOriginal);
+        }
+
+        // Add the default value.
+        if (getAttribute(TAG_IMAGE_WIDTH) == null) {
+            mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, "0");
+        }
+        if (getAttribute(TAG_IMAGE_LENGTH) == null) {
+            mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, "0");
+        }
+        if (getAttribute(TAG_ORIENTATION) == null) {
+            mAttributes[IFD_TIFF_HINT].put(TAG_ORIENTATION, "0");
+        }
+        if (getAttribute(TAG_LIGHT_SOURCE) == null) {
+            mAttributes[IFD_EXIF_HINT].put(TAG_LIGHT_SOURCE, "0");
+        }
+    }
+
+    // Converts the tag value to timestamp; Otherwise deletes the given tag.
+    private void convertToTimestamp(String tagName) {
+        String entryValue = getAttribute(tagName);
+        if (entryValue == null) return;
+        int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+        String[] components = entryValue.split(",");
+        if (dataFormat == IFD_FORMAT_SRATIONAL && components.length == 3) {
+            StringBuilder stringBuilder = new StringBuilder();
+            for (String component : components) {
+                if (stringBuilder.length() > 0) {
+                    stringBuilder.append(":");
+                }
+                String[] rationalNumber = component.split("/");
+                int numerator = Integer.parseInt(rationalNumber[0]);
+                int denominator = Integer.parseInt(rationalNumber[1]);
+                if (denominator == 0) {
+                    numerator = 0;
+                    denominator = 1;
+                }
+                int value = numerator / denominator;
+                stringBuilder.append(String.format("%02d", value));
+            }
+            updateAttribute(tagName, stringBuilder.toString());
+        } else if (dataFormat != IFD_FORMAT_STRING) {
+            removeAttribute(tagName);
+        }
+    }
+
+    // Checks the tag value of a given tag formatted in double type; Otherwise try to convert it to
+    // double type or delete it.
+    private void convertToDouble(String tagName) {
+        String entryValue = getAttribute(tagName);
+        if (entryValue == null) return;
+        int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+        switch (dataFormat) {
+            case IFD_FORMAT_SRATIONAL: {
+                StringBuilder stringBuilder = new StringBuilder();
+                String[] components = entryValue.split(",");
+                for (String component : components) {
+                    if (stringBuilder.length() > 0) {
+                        stringBuilder.append(",");
+                    }
+                    String[] rationalNumber = component.split("/");
+                    int numerator = Integer.parseInt(rationalNumber[0]);
+                    int denominator = Integer.parseInt(rationalNumber[1]);
+                    if (denominator == 0) {
+                        numerator = 0;
+                        denominator = 1;
+                    }
+                    stringBuilder.append((double) numerator / denominator);
+                }
+                updateAttribute(tagName, stringBuilder.toString());
+                break;
+            }
+            case IFD_FORMAT_DOUBLE:
+                // Keep it as is.
+                break;
+            default:
+                removeAttribute(tagName);
+                break;
+        }
+    }
+
+    // Checks the tag value of a given tag formatted in int type; Otherwise deletes the tag value.
+    private void convertToRational(String tagName) {
+        String entryValue = getAttribute(tagName);
+        if (entryValue == null) return;
+        int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+        switch (dataFormat) {
+            case IFD_FORMAT_SLONG:
+            case IFD_FORMAT_DOUBLE: {
+                StringBuilder stringBuilder = new StringBuilder();
+                String[] components = entryValue.split(",");
+                for (String component : components) {
+                    if (stringBuilder.length() > 0) {
+                        stringBuilder.append(",");
+                    }
+                    double doubleValue = Double.parseDouble(component);
+                    stringBuilder.append((int) (doubleValue * 10000.0)).append("/").append(10000);
+                }
+                updateAttribute(tagName, stringBuilder.toString());
+                break;
+            }
+            case IFD_FORMAT_SRATIONAL:
+                // Keep it as is.
+                break;
+            default:
+                removeAttribute(tagName);
+                break;
+        }
+    }
+
+    // Checks the tag value of a given tag formatted in int type; Otherwise deletes the tag value.
+    private void convertToInt(String tagName) {
+        String entryValue = getAttribute(tagName);
+        if (entryValue == null) return;
+        int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+        if (dataFormat != IFD_FORMAT_SLONG) {
+            removeAttribute(tagName);
+        }
+    }
+
+    // Reads image file directory, which is a tag group in EXIF.
+    private void readImageFileDirectory(ByteOrderAwarenessDataInputStream dataInputStream, int hint)
+            throws IOException {
+        if (dataInputStream.peek() + 2 > dataInputStream.mLength) {
+            // Return if there is no data from the offset.
+            return;
+        }
+        // See JEITA CP-3451 Figure 5. page 9.
+        short numberOfDirectoryEntry = dataInputStream.readShort();
+        if (dataInputStream.peek() + 12 * numberOfDirectoryEntry > dataInputStream.mLength) {
+            // Return if the size of entries is too big.
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
+        }
+
+        for (short i = 0; i < numberOfDirectoryEntry; ++i) {
+            int tagNumber = dataInputStream.readUnsignedShort();
+            int dataFormat = dataInputStream.readUnsignedShort();
+            int numberOfComponents = dataInputStream.readInt();
+            long nextEntryOffset = dataInputStream.peek() + 4;  // next four bytes is for data
+                                                                // offset or value.
+            // Look up a corresponding tag from tag number
+            String tagName = (String) sExifTagMapsForReading[hint].get(tagNumber);
+
+            if (DEBUG) {
+                Log.d(TAG, String.format("hint: %d, tagNumber: %d, tagName: %s, dataFormat: %d, " +
+                        "numberOfComponents: %d", hint, tagNumber, tagName, dataFormat,
+                        numberOfComponents));
+            }
+
+            if (tagName == null || dataFormat <= 0 ||
+                    dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) {
+                // Skip if the parsed tag number is not defined or invalid data format.
+                if (tagName == null) {
+                    Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber);
+                } else {
+                    Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat);
+                }
+                dataInputStream.seek(nextEntryOffset);
+                continue;
+            }
+
+            // Read a value from data field or seek to the value offset which is stored in data
+            // field if the size of the entry value is bigger than 4.
+            int byteCount = numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat];
+            if (byteCount > 4) {
+                long offset = dataInputStream.readUnsignedInt();
+                if (DEBUG) {
+                    Log.d(TAG, "seek to data offset: " + offset);
+                }
+                if (offset + byteCount <= dataInputStream.mLength) {
+                    dataInputStream.seek(offset);
+                } else {
+                     // Skip if invalid data offset.
+                    Log.w(TAG, "Skip the tag entry since data offset is invalid: " + offset);
+                    dataInputStream.seek(nextEntryOffset);
+                    continue;
+                }
+            }
+
+            // Recursively parse IFD when a IFD pointer tag appears.
+            int innerIfdHint = getIfdHintFromTagNumber(tagNumber);
+            if (DEBUG) {
+                Log.d(TAG, "innerIfdHint: " + innerIfdHint + " byteCount: " + byteCount);
+            }
+            if (innerIfdHint >= 0) {
+                long offset = -1L;
+                // Get offset from data field
+                switch (dataFormat) {
+                    case IFD_FORMAT_USHORT: {
+                        offset = dataInputStream.readUnsignedShort();
+                        break;
+                    }
+                    case IFD_FORMAT_SSHORT: {
+                        offset = dataInputStream.readShort();
+                        break;
+                    }
+                    case IFD_FORMAT_ULONG: {
+                        offset = dataInputStream.readUnsignedInt();
+                        break;
+                    }
+                    case IFD_FORMAT_SLONG: {
+                        offset = dataInputStream.readInt();
+                        break;
+                    }
+                    default: {
+                        // Nothing to do
+                        break;
+                    }
+                }
+                if (DEBUG) {
+                    Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tagName));
+                }
+                if (offset > 0L && offset < dataInputStream.mLength) {
+                    dataInputStream.seek(offset);
+                    readImageFileDirectory(dataInputStream, innerIfdHint);
+                } else {
+                    Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset);
+                }
+
+                dataInputStream.seek(nextEntryOffset);
+                continue;
+            }
+
+            if (numberOfComponents == 1 || dataFormat == IFD_FORMAT_STRING
+                    || dataFormat == IFD_FORMAT_UNDEFINED) {
+                String entryValue = readExifEntryValue(
+                        dataInputStream, dataFormat, numberOfComponents);
+                if (entryValue != null) {
+                    mAttributes[hint].put(tagName, entryValue);
+                }
+            } else {
+                StringBuilder entryValueBuilder = new StringBuilder();
+                for (int c = 0; c < numberOfComponents; ++c) {
+                    if (entryValueBuilder.length() > 0) {
+                        entryValueBuilder.append(",");
+                    }
+                    entryValueBuilder.append(readExifEntryValue(
+                            dataInputStream, dataFormat, numberOfComponents));
+                }
+                mAttributes[hint].put(tagName, entryValueBuilder.toString());
+            }
+
+            if (dataInputStream.peek() != nextEntryOffset) {
+                dataInputStream.seek(nextEntryOffset);
+            }
+        }
+
+        if (dataInputStream.peek() + 4 <= dataInputStream.mLength) {
+            long nextIfdOffset = dataInputStream.readUnsignedInt();
+            if (DEBUG) {
+                Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
+            }
+            // The next IFD offset needs to be bigger than 8
+            // since the first IFD offset is at least 8.
+            if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) {
+                dataInputStream.seek(nextIfdOffset);
+                readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT);
+            }
+        }
+    }
+
+    // Reads a value from where the entry value are stored.
+    private String readExifEntryValue(ByteOrderAwarenessDataInputStream dataInputStream,
+            int dataFormat, int numberOfComponents) throws IOException {
+        // See TIFF 6.0 spec Types. page 15.
+        switch (dataFormat) {
+            case IFD_FORMAT_BYTE: {
+                return String.valueOf(dataInputStream.readByte());
+            }
+            case IFD_FORMAT_SBYTE: {
+                return String.valueOf(dataInputStream.readByte() & 0xff);
+            }
+            case IFD_FORMAT_USHORT: {
+                return String.valueOf(dataInputStream.readUnsignedShort());
+            }
+            case IFD_FORMAT_SSHORT: {
+                return String.valueOf(dataInputStream.readUnsignedInt());
+            }
+            case IFD_FORMAT_ULONG: {
+                return String.valueOf(dataInputStream.readInt());
+            }
+            case IFD_FORMAT_SLONG: {
+                return String.valueOf(dataInputStream.readInt());
+            }
+            case IFD_FORMAT_URATIONAL:
+            case IFD_FORMAT_SRATIONAL: {
+                int numerator = dataInputStream.readInt();
+                int denominator = dataInputStream.readInt();
+                return numerator + "/" + denominator;
+            }
+            case IFD_FORMAT_SINGLE: {
+                return String.valueOf(dataInputStream.readFloat());
+            }
+            case IFD_FORMAT_DOUBLE: {
+                return String.valueOf(dataInputStream.readDouble());
+            }
+            case IFD_FORMAT_UNDEFINED:  // Usually UNDEFINED format is ASCII.
+            case IFD_FORMAT_STRING: {
+                byte[] bytes = new byte[numberOfComponents];
+                dataInputStream.readFully(bytes);
+                int index = 0;
+                if (numberOfComponents >= EXIF_ASCII_PREFIX.length) {
+                    boolean same = true;
+                    for (int i = 0; i < EXIF_ASCII_PREFIX.length; ++i) {
+                        if (bytes[i] != EXIF_ASCII_PREFIX[i]) {
+                            same = false;
+                            break;
+                        }
+                    }
+                    if (same) {
+                        index = EXIF_ASCII_PREFIX.length;
+                    }
+                }
+
+                StringBuilder stringBuilder = new StringBuilder();
+                while (index < numberOfComponents) {
+                    int ch = bytes[index];
+                    if (ch == 0) {
+                        break;
+                    }
+                    if (ch >= 32) {
+                        stringBuilder.append((char) ch);
+                    }
+                    else {
+                        stringBuilder.append('?');
+                    }
+                    ++index;
+                }
+                return stringBuilder.toString();
+            }
+            default: {
+                // Nothing to do
+                return null;
+            }
+        }
+    }
+
+    // Gets the corresponding IFD group index of the given tag number for writing Exif Tags.
+    private static int getIfdHintFromTagNumber(int tagNumber) {
+        for (int i = 0; i < IFD_POINTER_TAG_HINTS.length; ++i) {
+            if (IFD_POINTER_TAGS[i].number == tagNumber) {
+                return IFD_POINTER_TAG_HINTS[i];
+            }
+        }
+        return -1;
+    }
+
+    // Writes an Exif segment into the given output stream.
+    private int writeExifSegment(ExifDataOutputStream dataOutputStream, int exifOffsetFromBeginning)
+            throws IOException {
+        // The following variables are for calculating each IFD tag group size in bytes.
+        int[] ifdOffsets = new int[EXIF_TAGS.length];
+        int[] ifdDataSizes = new int[EXIF_TAGS.length];
+
+        // Remove IFD pointer tags (we'll re-add it later.)
+        for (ExifTag tag : IFD_POINTER_TAGS) {
+            removeAttribute(tag.name);
+        }
+        // Remove old thumbnail data
+        removeAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
+        removeAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
+
+        // Remove null value tags.
+        for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+            for (Object obj : mAttributes[hint].entrySet().toArray()) {
+                Map.Entry entry = (Map.Entry) obj;
+                if (entry.getValue() == null) {
+                    mAttributes[hint].remove(entry.getKey());
+                }
+            }
+        }
+
+        // Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD
+        // offset when there is one or more tags in the thumbnail IFD.
+        if (!mAttributes[IFD_INTEROPERABILITY_HINT].isEmpty()) {
+            mAttributes[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].name, "0");
+        }
+        if (!mAttributes[IFD_EXIF_HINT].isEmpty()) {
+            mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].name, "0");
+        }
+        if (!mAttributes[IFD_GPS_HINT].isEmpty()) {
+            mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name, "0");
+        }
+        if (mHasThumbnail) {
+            mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name, "0");
+            mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
+                    String.valueOf(mThumbnailLength));
+        }
+
+        // Calculate IFD group data area sizes. IFD group data area is assigned to save the entry
+        // value which has a bigger size than 4 bytes.
+        for (int i = 0; i < 5; ++i) {
+            int sum = 0;
+            for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
+                String entryValue = (String) ((Map.Entry) entry).getValue();
+                int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+                int size = getSizeOfExifEntryValue(dataFormat, entryValue);
+                if (size > 4) {
+                    sum += size;
+                }
+            }
+            ifdDataSizes[i] += sum;
+        }
+
+        // Calculate IFD offsets.
+        int position = 8;
+        for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+            if (!mAttributes[hint].isEmpty()) {
+                ifdOffsets[hint] = position;
+                position += 2 + mAttributes[hint].size() * 12 + 4 + ifdDataSizes[hint];
+            }
+        }
+        if (mHasThumbnail) {
+            int thumbnailOffset = position;
+            mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
+                    String.valueOf(thumbnailOffset));
+            mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
+                    String.valueOf(mThumbnailLength));
+            mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
+            position += mThumbnailLength;
+        }
+
+        // Calculate the total size
+        int totalSize = position + 8;  // eight bytes is for header part.
+        if (DEBUG) {
+            Log.d(TAG, "totalSize length: " + totalSize);
+            for (int i = 0; i < 5; ++i) {
+                Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d",
+                        i, ifdOffsets[i], mAttributes[i].size(), ifdDataSizes[i]));
+            }
+        }
+
+        // Update IFD pointer tags with the calculated offsets.
+        if (!mAttributes[IFD_EXIF_HINT].isEmpty()) {
+            mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].name,
+                    String.valueOf(ifdOffsets[IFD_EXIF_HINT]));
+        }
+        if (!mAttributes[IFD_GPS_HINT].isEmpty()) {
+            mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name,
+                    String.valueOf(ifdOffsets[IFD_GPS_HINT]));
+        }
+        if (!mAttributes[IFD_INTEROPERABILITY_HINT].isEmpty()) {
+            mAttributes[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].name,
+                    String.valueOf(ifdOffsets[IFD_INTEROPERABILITY_HINT]));
+        }
+
+        // Write TIFF Headers. See JEITA CP-3451C Table 1. page 10.
+        dataOutputStream.writeUnsignedShort(totalSize);
+        dataOutputStream.write(IDENTIFIER_EXIF_APP1);
+        dataOutputStream.writeShort(BYTE_ALIGN_MM);
+        dataOutputStream.writeUnsignedShort(0x2a);
+        dataOutputStream.writeUnsignedInt(8);
+
+        // Write IFD groups. See JEITA CP-3451C Figure 7. page 12.
+        for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+            if (!mAttributes[hint].isEmpty()) {
+                // See JEITA CP-3451C 4.6.2 IFD structure. page 13.
+                // Write entry count
+                dataOutputStream.writeUnsignedShort(mAttributes[hint].size());
+
+                // Write entry info
+                int dataOffset = ifdOffsets[hint] + 2 + mAttributes[hint].size() * 12 + 4;
+                for (Map.Entry entry : (Set<Map.Entry>) mAttributes[hint].entrySet()) {
+                    // Convert tag name to tag number.
+                    int tagNumber = (int) sExifTagMapsForWriting[hint].get(entry.getKey());
+                    String entryValue = (String) entry.getValue();
+
+                    int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+                    int numberOfComponents = getNumberOfComponentsInExifEntryValue(dataFormat,
+                            entryValue);
+                    int byteCount = getSizeOfExifEntryValue(dataFormat, entryValue);
+
+                    dataOutputStream.writeUnsignedShort(tagNumber);
+                    dataOutputStream.writeUnsignedShort(dataFormat);
+                    dataOutputStream.writeInt(numberOfComponents);
+                    if (byteCount > 4) {
+                        dataOutputStream.writeUnsignedInt(dataOffset);
+                        dataOffset += byteCount;
+                    } else {
+                        int bytesWritten = writeExifEntryValue(dataOutputStream, entryValue);
+                        // Fill zero up to 4 bytes
+                        if (bytesWritten < 4) {
+                            for (int i = bytesWritten; i < 4; ++i) {
+                                dataOutputStream.write(0);
+                            }
+                        }
+                    }
+                }
+
+                // Write the next offset. It writes the offset of thumbnail IFD if there is one or
+                // more tags in the thumbnail IFD when the current IFD is the primary image TIFF
+                // IFD; Otherwise 0.
+                if (hint == 0 && !mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) {
+                    dataOutputStream.writeUnsignedInt(ifdOffsets[IFD_THUMBNAIL_HINT]);
+                } else {
+                    dataOutputStream.writeUnsignedInt(0);
+                }
+
+                // Write values of data field exceeding 4 bytes after the next offset.
+                for (Map.Entry entry : (Set<Map.Entry>) mAttributes[hint].entrySet()) {
+                    String entryValue = (String) entry.getValue();
+
+                    int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+                    int byteCount = getSizeOfExifEntryValue(dataFormat, entryValue);
+                    if (byteCount > 4) {
+                        writeExifEntryValue(dataOutputStream, entryValue);
+                    }
+                }
+            }
+        }
+
+        // Write thumbnail
+        if (mHasThumbnail) {
+            dataOutputStream.write(getThumbnail());
+        }
+
+        return totalSize;
+    }
+
+    // Writes EXIF entry value and its entry value type will be automatically determined.
+    private static int writeExifEntryValue(ExifDataOutputStream dataOutputStream, String entryValue)
+            throws IOException {
+        int bytesWritten = 0;
+        int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+
+        if (dataFormat == IFD_FORMAT_STRING) {
+            byte[] asciiArray = (entryValue + '\0').getBytes(Charset.forName("US-ASCII"));
+            dataOutputStream.write(asciiArray);
+            return asciiArray.length;
+        }
+
+        // Values can be composed of several components. Each component is separated by char ','.
+        String[] components = entryValue.split(",");
+        for (String component : components) {
+            switch (dataFormat) {
+                case IFD_FORMAT_SLONG:
+                    dataOutputStream.writeInt(Integer.parseInt(component));
+                    bytesWritten += 4;
+                    break;
+                case IFD_FORMAT_DOUBLE:
+                    dataOutputStream.writeDouble(Double.parseDouble(component));
+                    bytesWritten += 8;
+                    break;
+                case IFD_FORMAT_SRATIONAL:
+                    String[] rationalNumber = component.split("/");
+                    dataOutputStream.writeInt(Integer.parseInt(rationalNumber[0]));
+                    dataOutputStream.writeInt(Integer.parseInt(rationalNumber[1]));
+                    bytesWritten += 8;
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+        return bytesWritten;
+    }
+
+    // Determines the data format of EXIF entry value.
+    private static int getDataFormatOfExifEntryValue(String entryValue) {
+        // See TIFF 6.0 spec Types. page 15.
+        // Take the first component if there are more than one component.
+        if (entryValue.contains(",")) {
+            String[] entryValues = entryValue.split(",");
+            int dataFormat = getDataFormatOfExifEntryValue(entryValues[0]);
+            if (dataFormat == IFD_FORMAT_STRING) {
+                return IFD_FORMAT_STRING;
+            }
+            for (int i = 1; i < entryValues.length; ++i) {
+                if (getDataFormatOfExifEntryValue(entryValues[i]) != dataFormat) {
+                    return IFD_FORMAT_STRING;
+                }
+            }
+            return dataFormat;
+        }
+
+        if (entryValue.contains("/")) {
+            String[] rationalNumber = entryValue.split("/");
+            if (rationalNumber.length == 2) {
+                try {
+                    Integer.parseInt(rationalNumber[0]);
+                    Integer.parseInt(rationalNumber[1]);
+                    return IFD_FORMAT_SRATIONAL;
+                } catch (NumberFormatException e)  {
+                    // Ignored
+                }
+            }
+            return IFD_FORMAT_STRING;
+        }
+        try {
+            Integer.parseInt(entryValue);
+            return IFD_FORMAT_SLONG;
+        } catch (NumberFormatException e) {
+            // Ignored
+        }
+        try {
+            Double.parseDouble(entryValue);
+            return IFD_FORMAT_DOUBLE;
+        } catch (NumberFormatException e) {
+            // Ignored
+        }
+        return IFD_FORMAT_STRING;
+    }
+
+    // Determines the size of EXIF entry value.
+    private static int getSizeOfExifEntryValue(int dataFormat, String entryValue) {
+        // See TIFF 6.0 spec Types page 15.
+        if (dataFormat == IFD_FORMAT_STRING) {
+            return (entryValue + '\0').getBytes(Charset.forName("US-ASCII")).length;
+        }
+        int bytesEstimated = 0;
+        String[] components = entryValue.split(",");
+        for (String component : components) {
+            switch (dataFormat) {
+                case IFD_FORMAT_SLONG:
+                    bytesEstimated += 4;
+                    break;
+                case IFD_FORMAT_DOUBLE:
+                    bytesEstimated += 8;
+                    break;
+                case IFD_FORMAT_SRATIONAL:
+                    bytesEstimated += 8;
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+        return bytesEstimated;
+    }
+
+    // Determines the number of components of EXIF entry value.
+    private static int getNumberOfComponentsInExifEntryValue(int dataFormat, String entryValue) {
+        if (dataFormat == IFD_FORMAT_STRING) {
+            return (entryValue + '\0').getBytes(Charset.forName("US-ASCII")).length;
+        }
+        int count = 1;
+        for (int i = 0; i < entryValue.length(); ++i) {
+            if (entryValue.charAt(i) == ',') {
+                ++count;
+            }
+        }
+        return count;
+    }
+
+    // An input stream to parse EXIF data area, which can be written in either little or big endian
+    // order.
+    private static class ByteOrderAwarenessDataInputStream extends ByteArrayInputStream {
+        private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
+        private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
+
+        private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
+        private final long mLength;
+        private long mPosition;
+
+        public ByteOrderAwarenessDataInputStream(byte[] bytes) {
+            super(bytes);
+            mLength = bytes.length;
+            mPosition = 0L;
+        }
+
+        public void setByteOrder(ByteOrder byteOrder) {
+            mByteOrder = byteOrder;
+        }
+
+        public void seek(long byteCount) throws IOException {
+            mPosition = 0L;
+            reset();
+            if (skip(byteCount) != byteCount) {
+                throw new IOException("Couldn't seek up to the byteCount");
+            }
+        }
+
+        public long peek() {
+            return mPosition;
+        }
+
+        public void readFully(byte[] buffer) throws IOException {
+            mPosition += buffer.length;
+            if (mPosition > mLength) {
+                throw new EOFException();
+            }
+            if (super.read(buffer, 0, buffer.length) != buffer.length) {
+                throw new IOException("Couldn't read up to the length of buffer");
+            }
+        }
+
+        public byte readByte() throws IOException {
+            ++mPosition;
+            if (mPosition > mLength) {
+                throw new EOFException();
+            }
+            int ch = super.read();
+            if (ch < 0) {
+                throw new EOFException();
+            }
+            return (byte) ch;
+        }
+
+        public short readShort() throws IOException {
+            mPosition += 2;
+            if (mPosition > mLength) {
+                throw new EOFException();
+            }
+            int ch1 = super.read();
+            int ch2 = super.read();
+            if ((ch1 | ch2) < 0) {
+                throw new EOFException();
+            }
+            if (mByteOrder == LITTLE_ENDIAN) {
+                return (short) ((ch2 << 8) + (ch1));
+            } else if (mByteOrder == BIG_ENDIAN) {
+                return (short) ((ch1 << 8) + (ch2));
+            }
+            throw new IOException("Invalid byte order: " + mByteOrder);
+        }
+
+        public int readInt() throws IOException {
+            mPosition += 4;
+            if (mPosition > mLength) {
+                throw new EOFException();
+            }
+            int ch1 = super.read();
+            int ch2 = super.read();
+            int ch3 = super.read();
+            int ch4 = super.read();
+            if ((ch1 | ch2 | ch3 | ch4) < 0) {
+                throw new EOFException();
+            }
+            if (mByteOrder == LITTLE_ENDIAN) {
+                return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1);
+            } else if (mByteOrder == BIG_ENDIAN) {
+                return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
+            }
+            throw new IOException("Invalid byte order: " + mByteOrder);
+        }
+
+        @Override
+        public long skip(long byteCount) {
+            long skipped = super.skip(Math.min(byteCount, mLength - mPosition));
+            mPosition += skipped;
+            return skipped;
+        }
+
+        public int readUnsignedShort() throws IOException {
+            mPosition += 2;
+            if (mPosition > mLength) {
+                throw new EOFException();
+            }
+            int ch1 = super.read();
+            int ch2 = super.read();
+            if ((ch1 | ch2) < 0) {
+                throw new EOFException();
+            }
+            if (mByteOrder == LITTLE_ENDIAN) {
+                return ((ch2 << 8) + (ch1));
+            } else if (mByteOrder == BIG_ENDIAN) {
+                return ((ch1 << 8) + (ch2));
+            }
+            throw new IOException("Invalid byte order: " + mByteOrder);
+        }
+
+        public long readUnsignedInt() throws IOException {
+            return readInt() & 0xffffffffL;
+        }
+
+        public long readLong() throws IOException {
+            mPosition += 8;
+            if (mPosition > mLength) {
+                throw new EOFException();
+            }
+            int ch1 = super.read();
+            int ch2 = super.read();
+            int ch3 = super.read();
+            int ch4 = super.read();
+            int ch5 = super.read();
+            int ch6 = super.read();
+            int ch7 = super.read();
+            int ch8 = super.read();
+            if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
+                throw new EOFException();
+            }
+            if (mByteOrder == LITTLE_ENDIAN) {
+                return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40)
+                        + ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16)
+                        + ((long) ch2 << 8) + (long) ch1);
+            } else if (mByteOrder == BIG_ENDIAN) {
+                return (((long) ch1 << 56) + ((long) ch2 << 48) + ((long) ch3 << 40)
+                        + ((long) ch4 << 32) + ((long) ch5 << 24) + ((long) ch6 << 16)
+                        + ((long) ch7 << 8) + (long) ch8);
+            }
+            throw new IOException("Invalid byte order: " + mByteOrder);
+        }
+
+        public float readFloat() throws IOException {
+            return Float.intBitsToFloat(readInt());
+        }
+
+        public double readDouble() throws IOException {
+            return Double.longBitsToDouble(readLong());
+        }
+    }
+
+    // An output stream to write EXIF data area, that will be written in big endian byte order.
+    private static class ExifDataOutputStream extends DataOutputStream {
+        public ExifDataOutputStream(OutputStream out) {
+            super(out);
+        }
+
+        public void writeUnsignedShort(int val) throws IOException {
+            writeShort((short) val);
+        }
+
+        public void writeUnsignedInt(long val) throws IOException {
+            writeInt((int) val);
+        }
+    }
 
     // JNI methods for RAW formats.
-    private static native void initRawNative();
-    private static native HashMap getRawAttributesNative(String filename);
+    private static native void nativeInitRaw();
+    private static native byte[] nativeGetThumbnailFromAsset(
+            long asset, int thumbnailOffset, int thumbnailLength);
+    private static native HashMap nativeGetRawAttributesFromAsset(long asset);
+    private static native HashMap nativeGetRawAttributesFromFileDescriptor(FileDescriptor fd);
+    private static native HashMap nativeGetRawAttributesFromInputStream(InputStream in);
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index abe92c7..97f670b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -20,7 +20,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
 import android.media.AudioAttributes;
-import android.media.AudioRecordConfiguration;
+import android.media.AudioRecordingConfiguration;
 import android.media.AudioRoutesInfo;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioRoutesObserver;
@@ -54,10 +54,6 @@
 
     void setMasterMute(boolean mute, int flags, String callingPackage, int userId);
 
-    boolean isMasterMono();
-
-    void setMasterMono(boolean mute, String callingPackage, int userId);
-
     int getStreamVolume(int streamType);
 
     int getStreamMinVolume(int streamType);
@@ -168,5 +164,5 @@
 
     oneway void unregisterRecordingCallback(in IRecordingConfigDispatcher rcdb);
 
-    AudioRecordConfiguration[] getActiveRecordConfigurations();
+    AudioRecordingConfiguration[] getActiveRecordingConfigurations();
 }
diff --git a/media/java/android/media/IMediaResourceMonitor.aidl b/media/java/android/media/IMediaResourceMonitor.aidl
index 7b4bc39..cf0e56d 100644
--- a/media/java/android/media/IMediaResourceMonitor.aidl
+++ b/media/java/android/media/IMediaResourceMonitor.aidl
@@ -19,6 +19,6 @@
 /** {@hide} */
 interface IMediaResourceMonitor
 {
-    oneway void notifyResourceGranted(in int pid, String type, String subType, long value);
+    oneway void notifyResourceGranted(in int pid, in int type);
 }
 
diff --git a/media/java/android/media/IRecordingConfigDispatcher.aidl b/media/java/android/media/IRecordingConfigDispatcher.aidl
index a5eb8b9f..e803283 100644
--- a/media/java/android/media/IRecordingConfigDispatcher.aidl
+++ b/media/java/android/media/IRecordingConfigDispatcher.aidl
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import android.media.AudioRecordingConfiguration;
+
 /**
  * AIDL for the RecordingActivity monitor in AudioService to signal audio recording updates.
  *
@@ -23,6 +25,6 @@
  */
 oneway interface IRecordingConfigDispatcher {
 
-    void dispatchRecordingConfigChange();
+    void dispatchRecordingConfigChange(in AudioRecordingConfiguration[] configs);
 
 }
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 8091421..4b1e39f 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -18,6 +18,7 @@
 
 import android.media.AudioAttributes;
 import android.net.Uri;
+import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
 
 /**
@@ -36,4 +37,6 @@
 
     /** Return the title of the media. */
     String getTitle(in Uri uri);
+
+    ParcelFileDescriptor openRingtone(in Uri uri);
 }
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 397ab15..81cc035 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -153,6 +153,7 @@
 
         mSurface = nativeGetSurface();
 
+        mIsReaderValid = true;
         // Estimate the native buffer allocation size and register it so it gets accounted for
         // during GC. Note that this doesn't include the buffers required by the buffer queue
         // itself and the buffers requested by the producer.
@@ -326,11 +327,14 @@
      */
     private int acquireNextSurfaceImage(SurfaceImage si) {
         synchronized (mCloseLock) {
-            int status = nativeImageSetup(si);
+            // A null image will eventually be returned if ImageReader is already closed.
+            int status = ACQUIRE_NO_BUFS;
+            if (mIsReaderValid) {
+                status = nativeImageSetup(si);
+            }
 
             switch (status) {
                 case ACQUIRE_SUCCESS:
-                    si.createSurfacePlanes();
                     si.mIsImageValid = true;
                 case ACQUIRE_NO_BUFS:
                 case ACQUIRE_MAX_IMAGES:
@@ -498,6 +502,7 @@
          * acquire operations.
          */
         synchronized (mCloseLock) {
+            mIsReaderValid = false;
             for (Image image : mAcquiredImages) {
                 image.close();
             }
@@ -613,6 +618,7 @@
 
     private final Object mListenerLock = new Object();
     private final Object mCloseLock = new Object();
+    private boolean mIsReaderValid = false;
     private OnImageAvailableListener mListener;
     private ListenerHandler mListenerHandler;
     // Keep track of the successfully acquired Images. This need to be thread safe as the images
@@ -638,7 +644,14 @@
             synchronized (mListenerLock) {
                 listener = mListener;
             }
-            if (listener != null) {
+
+            // It's dangerous to fire onImageAvailable() callback when the ImageReader is being
+            // closed, as application could acquire next image in the onImageAvailable() callback.
+            boolean isReaderValid = false;
+            synchronized (mCloseLock) {
+                isReaderValid = mIsReaderValid;
+            }
+            if (listener != null && isReaderValid) {
                 listener.onImageAvailable(ImageReader.this);
             }
         }
@@ -679,7 +692,7 @@
                     width = ImageReader.this.getWidth();
                     break;
                 default:
-                    width = nativeGetWidth(mFormat);
+                    width = nativeGetWidth();
             }
             return width;
         }
@@ -695,7 +708,7 @@
                     height = ImageReader.this.getHeight();
                     break;
                 default:
-                    height = nativeGetHeight(mFormat);
+                    height = nativeGetHeight();
             }
             return height;
         }
@@ -715,6 +728,10 @@
         @Override
         public Plane[] getPlanes() {
             throwISEIfImageIsInvalid();
+
+            if (mPlanes == null) {
+                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
+            }
             // Shallow copy is fine.
             return mPlanes.clone();
         }
@@ -752,7 +769,8 @@
         }
 
         private void clearSurfacePlanes() {
-            if (mIsImageValid) {
+            // Image#getPlanes may not be called before the image is closed.
+            if (mIsImageValid && mPlanes != null) {
                 for (int i = 0; i < mPlanes.length; i++) {
                     if (mPlanes[i] != null) {
                         mPlanes[i].clearBuffer();
@@ -762,32 +780,25 @@
             }
         }
 
-        private void createSurfacePlanes() {
-            mPlanes = new SurfacePlane[ImageReader.this.mNumPlanes];
-            for (int i = 0; i < ImageReader.this.mNumPlanes; i++) {
-                mPlanes[i] = nativeCreatePlane(i, ImageReader.this.mFormat);
-            }
-        }
         private class SurfacePlane extends android.media.Image.Plane {
-            // SurfacePlane instance is created by native code when a new SurfaceImage is created
-            private SurfacePlane(int index, int rowStride, int pixelStride) {
-                mIndex = index;
+            // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
+            // called
+            private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
                 mRowStride = rowStride;
                 mPixelStride = pixelStride;
+                mBuffer = buffer;
+                /**
+                 * Set the byteBuffer order according to host endianness (native
+                 * order), otherwise, the byteBuffer order defaults to
+                 * ByteOrder.BIG_ENDIAN.
+                 */
+                mBuffer.order(ByteOrder.nativeOrder());
             }
 
             @Override
             public ByteBuffer getBuffer() {
-                SurfaceImage.this.throwISEIfImageIsInvalid();
-                if (mBuffer != null) {
-                    return mBuffer;
-                } else {
-                    mBuffer = SurfaceImage.this.nativeImageGetBuffer(mIndex,
-                            ImageReader.this.mFormat);
-                    // Set the byteBuffer order according to host endianness (native order),
-                    // otherwise, the byteBuffer order defaults to ByteOrder.BIG_ENDIAN.
-                    return mBuffer.order(ByteOrder.nativeOrder());
-                }
+                throwISEIfImageIsInvalid();
+                return mBuffer;
             }
 
             @Override
@@ -823,7 +834,6 @@
                 mBuffer = null;
             }
 
-            final private int mIndex;
             final private int mPixelStride;
             final private int mRowStride;
 
@@ -846,10 +856,10 @@
         // If this image is detached from the ImageReader.
         private AtomicBoolean mIsDetached = new AtomicBoolean(false);
 
-        private synchronized native ByteBuffer nativeImageGetBuffer(int idx, int readerFormat);
-        private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat);
-        private synchronized native int nativeGetWidth(int format);
-        private synchronized native int nativeGetHeight(int format);
+        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
+                int readerFormat);
+        private synchronized native int nativeGetWidth();
+        private synchronized native int nativeGetHeight();
         private synchronized native int nativeGetFormat(int readerFormat);
     }
 
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 851d436..83a4f17 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -748,8 +748,8 @@
             final private int mPixelStride;
             final private int mRowStride;
 
-            // SurfacePlane instance is created by native code when a new
-            // SurfaceImage is created
+            // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
+            // called
             private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
                 mRowStride = rowStride;
                 mPixelStride = pixelStride;
@@ -795,7 +795,7 @@
 
         }
 
-        // this will create the SurfacePlane object and fill the information
+        // Create the SurfacePlane object and fill the information
         private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt);
 
         private synchronized native int nativeGetWidth();
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index 1fee587..983ca75 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -45,8 +45,7 @@
     private static final int NUM_MEDIA_SOUND_STREAMS = 1;
 
     private SoundPool mSoundPool;
-    private int[]     mSoundIds;
-    private int       mSoundIdToPlay;
+    private SoundState[] mSounds;
 
     private static final String[] SOUND_FILES = {
         "/system/media/audio/ui/camera_click.ogg",
@@ -88,22 +87,57 @@
      */
     public static final int STOP_VIDEO_RECORDING  = 3;
 
-    private static final int SOUND_NOT_LOADED = -1;
+    /**
+     * States for SoundState.
+     * STATE_NOT_LOADED             : sample not loaded
+     * STATE_LOADING                : sample being loaded: waiting for load completion callback
+     * STATE_LOADING_PLAY_REQUESTED : sample being loaded and playback request received
+     * STATE_LOADED                 : sample loaded, ready for playback
+     */
+    private static final int STATE_NOT_LOADED             = 0;
+    private static final int STATE_LOADING                = 1;
+    private static final int STATE_LOADING_PLAY_REQUESTED = 2;
+    private static final int STATE_LOADED                 = 3;
 
+    private class SoundState {
+        public final int name;
+        public int id;
+        public int state;
+
+        public SoundState(int name) {
+            this.name = name;
+            id = 0; // 0 is an invalid sample ID.
+            state = STATE_NOT_LOADED;
+        }
+    }
     /**
      * Construct a new MediaActionSound instance. Only a single instance is
      * needed for playing any platform media action sound; you do not need a
      * separate instance for each sound type.
      */
     public MediaActionSound() {
-        mSoundPool = new SoundPool(NUM_MEDIA_SOUND_STREAMS,
-                AudioManager.STREAM_SYSTEM_ENFORCED, 0);
+        mSoundPool = new SoundPool.Builder()
+                .setMaxStreams(NUM_MEDIA_SOUND_STREAMS)
+                .setAudioAttributes(new AudioAttributes.Builder()
+                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                    .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                    .build())
+                .build();
         mSoundPool.setOnLoadCompleteListener(mLoadCompleteListener);
-        mSoundIds = new int[SOUND_FILES.length];
-        for (int i = 0; i < mSoundIds.length; i++) {
-            mSoundIds[i] = SOUND_NOT_LOADED;
+        mSounds = new SoundState[SOUND_FILES.length];
+        for (int i = 0; i < mSounds.length; i++) {
+            mSounds[i] = new SoundState(i);
         }
-        mSoundIdToPlay = SOUND_NOT_LOADED;
+    }
+
+    private int loadSound(SoundState sound) {
+        int id = mSoundPool.load(SOUND_FILES[sound.name], 1);
+        if (id > 0) {
+            sound.state = STATE_LOADING;
+            sound.id = id;
+        }
+        return id;
     }
 
     /**
@@ -118,13 +152,22 @@
      * @see #START_VIDEO_RECORDING
      * @see #STOP_VIDEO_RECORDING
      */
-    public synchronized void load(int soundName) {
+    public void load(int soundName) {
         if (soundName < 0 || soundName >= SOUND_FILES.length) {
             throw new RuntimeException("Unknown sound requested: " + soundName);
         }
-        if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
-            mSoundIds[soundName] =
-                    mSoundPool.load(SOUND_FILES[soundName], 1);
+        SoundState sound = mSounds[soundName];
+        synchronized (sound) {
+            switch (sound.state) {
+            case STATE_NOT_LOADED:
+                if (loadSound(sound) <= 0) {
+                    Log.e(TAG, "load() error loading sound: " + soundName);
+                }
+                break;
+            default:
+                Log.e(TAG, "load() called in wrong state: " + sound + " for sound: "+ soundName);
+                break;
+            }
         }
     }
 
@@ -159,16 +202,31 @@
      * @see #START_VIDEO_RECORDING
      * @see #STOP_VIDEO_RECORDING
      */
-    public synchronized void play(int soundName) {
+    public void play(int soundName) {
         if (soundName < 0 || soundName >= SOUND_FILES.length) {
             throw new RuntimeException("Unknown sound requested: " + soundName);
         }
-        if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
-            mSoundIdToPlay =
-                    mSoundPool.load(SOUND_FILES[soundName], 1);
-            mSoundIds[soundName] = mSoundIdToPlay;
-        } else {
-            mSoundPool.play(mSoundIds[soundName], 1.0f, 1.0f, 0, 0, 1.0f);
+        SoundState sound = mSounds[soundName];
+        synchronized (sound) {
+            switch (sound.state) {
+            case STATE_NOT_LOADED:
+                loadSound(sound);
+                if (loadSound(sound) <= 0) {
+                    Log.e(TAG, "play() error loading sound: " + soundName);
+                    break;
+                }
+                // FALL THROUGH
+
+            case STATE_LOADING:
+                sound.state = STATE_LOADING_PLAY_REQUESTED;
+                break;
+            case STATE_LOADED:
+                mSoundPool.play(sound.id, 1.0f, 1.0f, 0, 0, 1.0f);
+                break;
+            default:
+                Log.e(TAG, "play() called in wrong state: " + sound.state + " for sound: "+ soundName);
+                break;
+            }
         }
     }
 
@@ -176,14 +234,37 @@
             new SoundPool.OnLoadCompleteListener() {
         public void onLoadComplete(SoundPool soundPool,
                 int sampleId, int status) {
-            if (status == 0) {
-                if (mSoundIdToPlay == sampleId) {
-                    soundPool.play(sampleId, 1.0f, 1.0f, 0, 0, 1.0f);
-                    mSoundIdToPlay = SOUND_NOT_LOADED;
+            for (SoundState sound : mSounds) {
+                if (sound.id != sampleId) {
+                    continue;
                 }
-            } else {
-                Log.e(TAG, "Unable to load sound for playback (status: " +
-                        status + ")");
+                int playSoundId = 0;
+                synchronized (sound) {
+                    if (status != 0) {
+                        sound.state = STATE_NOT_LOADED;
+                        sound.id = 0;
+                        Log.e(TAG, "OnLoadCompleteListener() error: " + status +
+                                " loading sound: "+ sound.name);
+                        return;
+                    }
+                    switch (sound.state) {
+                    case STATE_LOADING:
+                        sound.state = STATE_LOADED;
+                        break;
+                    case STATE_LOADING_PLAY_REQUESTED:
+                        playSoundId = sound.id;
+                        sound.state = STATE_LOADED;
+                        break;
+                    default:
+                        Log.e(TAG, "OnLoadCompleteListener() called in wrong state: "
+                                + sound.state + " for sound: "+ sound.name);
+                        break;
+                    }
+                }
+                if (playSoundId != 0) {
+                    soundPool.play(playSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
+                }
+                break;
             }
         }
     };
@@ -195,6 +276,12 @@
      */
     public void release() {
         if (mSoundPool != null) {
+            for (SoundState sound : mSounds) {
+                synchronized (sound) {
+                    sound.state = STATE_NOT_LOADED;
+                    sound.id = 0;
+                }
+            }
             mSoundPool.release();
             mSoundPool = null;
         }
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index f1f8437..c73cad4 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2074,6 +2074,16 @@
          */
         public static final int ERROR_SESSION_NOT_OPENED = 5;
 
+        /**
+         * This indicates that an operation was attempted that could not be
+         * supported by the crypto system of the device in its current
+         * configuration.  It may occur when the license policy requires
+         * device security features that aren't supported by the device,
+         * or due to an internal error in the crypto system that prevents
+         * the specified security policy from being met.
+         */
+        public static final int ERROR_UNSUPPORTED_OPERATION = 6;
+
         /** @hide */
         @IntDef({
             ERROR_NO_KEY,
@@ -2081,6 +2091,7 @@
             ERROR_RESOURCE_BUSY,
             ERROR_INSUFFICIENT_OUTPUT_PROTECTION,
             ERROR_SESSION_NOT_OPENED,
+            ERROR_UNSUPPORTED_OPERATION
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface CryptoErrorCode {}
@@ -2221,7 +2232,10 @@
         public int mode;
 
         /**
-         * Metadata describing encryption pattern for the protected bytes in a subsample.
+         * Metadata describing an encryption pattern for the protected bytes in
+         * a subsample.  An encryption pattern consists of a repeating sequence
+         * of crypto blocks comprised of a number of encrypted blocks followed
+         * by a number of unencrypted, or skipped, blocks.
          */
         public final static class Pattern {
             /**
@@ -2273,6 +2287,10 @@
          */
         private Pattern pattern;
 
+        /**
+         * Set the subsample count, clear/encrypted sizes, key, IV and mode fields of
+         * a {@link MediaCodec.CryptoInfo} instance.
+         */
         public void set(
                 int newNumSubSamples,
                 @NonNull int[] newNumBytesOfClearData,
@@ -2289,6 +2307,10 @@
             pattern = new Pattern(0, 0);
         }
 
+        /**
+         * Set the encryption pattern on a {@link MediaCodec.CryptoInfo} instance.
+         * See {@link MediaCodec.CryptoInfo.Pattern}.
+         */
         public void setPattern(Pattern newPattern) {
             pattern = newPattern;
         }
@@ -3339,14 +3361,6 @@
         }
 
 
-        private int readInt(@NonNull ByteBuffer buffer, boolean asLong) {
-            if (asLong) {
-                return (int)buffer.getLong();
-            } else {
-                return buffer.getInt();
-            }
-        }
-
         public MediaImage(
                 @NonNull ByteBuffer buffer, @NonNull ByteBuffer info, boolean readOnly,
                 long timestamp, int xOffset, int yOffset, @Nullable Rect cropRect) {
@@ -3361,39 +3375,46 @@
             mYOffset = yOffset;
             mInfo = info;
 
-            // read media-info.  the size of media info can be 80 or 156/160 depending on
-            // whether it was created on a 32- or 64-bit process.  See MediaImage
-            if (info.remaining() == 80 || info.remaining() == 156 || info.remaining() == 160) {
-                boolean sizeIsLong = info.remaining() != 80;
-                int type = readInt(info, info.remaining() == 160);
+            // read media-info.  See MediaImage2
+            if (info.remaining() == 104) {
+                int type = info.getInt();
                 if (type != TYPE_YUV) {
                     throw new UnsupportedOperationException("unsupported type: " + type);
                 }
-                int numPlanes = readInt(info, sizeIsLong);
+                int numPlanes = info.getInt();
                 if (numPlanes != 3) {
                     throw new RuntimeException("unexpected number of planes: " + numPlanes);
                 }
-                mWidth = readInt(info, sizeIsLong);
-                mHeight = readInt(info, sizeIsLong);
+                mWidth = info.getInt();
+                mHeight = info.getInt();
                 if (mWidth < 1 || mHeight < 1) {
                     throw new UnsupportedOperationException(
                             "unsupported size: " + mWidth + "x" + mHeight);
                 }
-                int bitDepth = readInt(info, sizeIsLong);
+                int bitDepth = info.getInt();
                 if (bitDepth != 8) {
                     throw new UnsupportedOperationException("unsupported bit depth: " + bitDepth);
                 }
+                int bitDepthAllocated = info.getInt();
+                if (bitDepthAllocated != 8) {
+                    throw new UnsupportedOperationException(
+                            "unsupported allocated bit depth: " + bitDepthAllocated);
+                }
                 mPlanes = new MediaPlane[numPlanes];
                 for (int ix = 0; ix < numPlanes; ix++) {
-                    int planeOffset = readInt(info, sizeIsLong);
-                    int colInc = readInt(info, sizeIsLong);
-                    int rowInc = readInt(info, sizeIsLong);
-                    int horiz = readInt(info, sizeIsLong);
-                    int vert = readInt(info, sizeIsLong);
+                    int planeOffset = info.getInt();
+                    int colInc = info.getInt();
+                    int rowInc = info.getInt();
+                    int horiz = info.getInt();
+                    int vert = info.getInt();
                     if (horiz != vert || horiz != (ix == 0 ? 1 : 2)) {
                         throw new UnsupportedOperationException("unexpected subsampling: "
                                 + horiz + "x" + vert + " on plane " + ix);
                     }
+                    if (colInc < 1 || rowInc < 1) {
+                        throw new UnsupportedOperationException("unexpected strides: "
+                                + colInc + " pixel, " + rowInc + " row on plane " + ix);
+                    }
 
                     buffer.clear();
                     buffer.position(mBuffer.position() + planeOffset
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index d9690f0..2bd9781 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2231,6 +2231,7 @@
                     switch (profileLevel.profile) {
                         case CodecProfileLevel.HEVCProfileMain:
                         case CodecProfileLevel.HEVCProfileMain10:
+                        case CodecProfileLevel.HEVCProfileMain10HDR10:
                             break;
                         default:
                             Log.w(TAG, "Unrecognized profile "
@@ -2632,8 +2633,9 @@
         public static final int VP9Level62 = 0x1000;
 
         // from OMX_VIDEO_HEVCPROFILETYPE
-        public static final int HEVCProfileMain   = 0x01;
-        public static final int HEVCProfileMain10 = 0x02;
+        public static final int HEVCProfileMain        = 0x01;
+        public static final int HEVCProfileMain10      = 0x02;
+        public static final int HEVCProfileMain10HDR10 = 0x1000;
 
         // from OMX_VIDEO_HEVCLEVELTYPE
         public static final int HEVCMainTierLevel1  = 0x1;
@@ -2664,12 +2666,13 @@
         public static final int HEVCHighTierLevel62 = 0x2000000;
 
         // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
-        public static final int DolbyVisionProfileDvavDer = 0x1;
-        public static final int DolbyVisionProfileDvavDen = 0x2;
-        public static final int DolbyVisionProfileDvheDer = 0x3;
-        public static final int DolbyVisionProfileDvheDen = 0x4;
-        public static final int DolbyVisionProfileDvheDtr = 0x5;
-        public static final int DolbyVisionProfileDvheStn = 0x6;
+        public static final int DolbyVisionProfileDvavPer = 0x1;
+        public static final int DolbyVisionProfileDvavPen = 0x2;
+        public static final int DolbyVisionProfileDvheDer = 0x4;
+        public static final int DolbyVisionProfileDvheDen = 0x8;
+        public static final int DolbyVisionProfileDvheDtr = 0x10;
+        public static final int DolbyVisionProfileDvheStn = 0x20;
+        public static final int DolbyVisionProfileDvheDth = 0x40;
 
         // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
         public static final int DolbyVisionLevelHd24    = 0x1;
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index db0c5bb..2650ee0 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1070,16 +1070,15 @@
      * A CryptoSession is obtained using {@link #getCryptoSession}
      */
     public final class CryptoSession {
-        private MediaDrm mDrm;
         private byte[] mSessionId;
 
-        CryptoSession(@NonNull MediaDrm drm, @NonNull byte[] sessionId,
-                @NonNull String cipherAlgorithm, @NonNull String macAlgorithm)
+        CryptoSession(@NonNull byte[] sessionId,
+                      @NonNull String cipherAlgorithm,
+                      @NonNull String macAlgorithm)
         {
             mSessionId = sessionId;
-            mDrm = drm;
-            setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
-            setMacAlgorithmNative(drm, sessionId, macAlgorithm);
+            setCipherAlgorithmNative(MediaDrm.this, sessionId, cipherAlgorithm);
+            setMacAlgorithmNative(MediaDrm.this, sessionId, macAlgorithm);
         }
 
         /**
@@ -1092,7 +1091,7 @@
         @NonNull
         public byte[] encrypt(
                 @NonNull byte[] keyid, @NonNull byte[] input, @NonNull byte[] iv) {
-            return encryptNative(mDrm, mSessionId, keyid, input, iv);
+            return encryptNative(MediaDrm.this, mSessionId, keyid, input, iv);
         }
 
         /**
@@ -1105,7 +1104,7 @@
         @NonNull
         public byte[] decrypt(
                 @NonNull byte[] keyid, @NonNull byte[] input, @NonNull byte[] iv) {
-            return decryptNative(mDrm, mSessionId, keyid, input, iv);
+            return decryptNative(MediaDrm.this, mSessionId, keyid, input, iv);
         }
 
         /**
@@ -1116,7 +1115,7 @@
          */
         @NonNull
         public byte[] sign(@NonNull byte[] keyid, @NonNull byte[] message) {
-            return signNative(mDrm, mSessionId, keyid, message);
+            return signNative(MediaDrm.this, mSessionId, keyid, message);
         }
 
         /**
@@ -1130,7 +1129,7 @@
          */
         public boolean verify(
                 @NonNull byte[] keyid, @NonNull byte[] message, @NonNull byte[] signature) {
-            return verifyNative(mDrm, mSessionId, keyid, message, signature);
+            return verifyNative(MediaDrm.this, mSessionId, keyid, message, signature);
         }
     };
 
@@ -1158,7 +1157,7 @@
             @NonNull byte[] sessionId,
             @NonNull String cipherAlgorithm, @NonNull String macAlgorithm)
     {
-        return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
+        return new CryptoSession(sessionId, cipherAlgorithm, macAlgorithm);
     }
 
     /**
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index b339925..24a400e4 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -28,6 +28,8 @@
 import android.net.Uri;
 import android.os.IBinder;
 
+import com.android.internal.util.Preconditions;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -189,6 +191,26 @@
     }
 
     /**
+     * Sets the data source (AssetFileDescriptor) to use. It is the caller's
+     * responsibility to close the file descriptor. It is safe to do so as soon
+     * as this call returns.
+     *
+     * @param afd the AssetFileDescriptor for the file you want to extract from.
+     */
+    public final void setDataSource(@NonNull AssetFileDescriptor afd)
+            throws IOException, IllegalArgumentException, IllegalStateException {
+        Preconditions.checkNotNull(afd);
+        // Note: using getDeclaredLength so that our behavior is the same
+        // as previous versions when the content provider is returning
+        // a full file.
+        if (afd.getDeclaredLength() < 0) {
+            setDataSource(afd.getFileDescriptor());
+        } else {
+            setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
+        }
+    }
+
+    /**
      * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
      * to close the file descriptor. It is safe to do so as soon as this call returns.
      *
@@ -253,16 +275,23 @@
                     return initDataMap.get(schemeUuid);
                 }
             };
-        } else if (formatMap.containsKey("crypto-key")) {
-            ByteBuffer buf = (ByteBuffer) formatMap.get("crypto-key");
-            buf.rewind();
-            final byte[] data = new byte[buf.remaining()];
-            buf.get(data);
-            return new DrmInitData() {
-                public SchemeInitData get(UUID schemeUuid) {
-                    return new DrmInitData.SchemeInitData("webm", data);
+        } else {
+            int numTracks = getTrackCount();
+            for (int i = 0; i < numTracks; ++i) {
+                Map<String, Object> trackFormatMap = getTrackFormatNative(i);
+                if (!trackFormatMap.containsKey("crypto-key")) {
+                    continue;
                 }
-            };
+                ByteBuffer buf = (ByteBuffer) trackFormatMap.get("crypto-key");
+                buf.rewind();
+                final byte[] data = new byte[buf.remaining()];
+                buf.get(data);
+                return new DrmInitData() {
+                    public SchemeInitData get(UUID schemeUuid) {
+                        return new DrmInitData.SchemeInitData("webm", data);
+                    }
+                };
+            }
         }
         return null;
     }
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 646ab4e..346f083 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -16,6 +16,10 @@
 
 package android.media;
 
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.Map;
@@ -504,7 +508,8 @@
      * The associated value is an integer.
      * Constants are declared in {@link MediaCodecInfo.CodecProfileLevel}.
      * This key is used as a hint, and is only supported for codecs
-     * that specify a profile.
+     * that specify a profile. Note: Codecs are free to use all the available
+     * coding tools at the specified profile.
      *
      * @see MediaCodecInfo.CodecCapabilities#profileLevels
      */
@@ -606,6 +611,16 @@
     /** BT.2020 color chromacity coordinates with KR = 0.2627, KB = 0.0593. */
     public static final int COLOR_STANDARD_BT2020 = 6;
 
+    /** @hide */
+    @IntDef({
+        COLOR_STANDARD_BT709,
+        COLOR_STANDARD_BT601_PAL,
+        COLOR_STANDARD_BT601_NTSC,
+        COLOR_STANDARD_BT2020,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ColorStandard {}
+
     /**
      * An optional key describing the opto-electronic transfer function used
      * for the video content.
@@ -628,6 +643,16 @@
     /** ARIB STD-B67 hybrid-log-gamma transfer function. This is used by some HDR video content. */
     public static final int COLOR_TRANSFER_HLG = 7;
 
+    /** @hide */
+    @IntDef({
+        COLOR_TRANSFER_LINEAR,
+        COLOR_TRANSFER_SDR_VIDEO,
+        COLOR_TRANSFER_ST2084,
+        COLOR_TRANSFER_HLG,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ColorTransfer {}
+
     /**
      * An optional key describing the range of the component values of the video content.
      *
@@ -644,6 +669,41 @@
     /** Full range. Y, Cr and Cb component values range from 0 to 255 for 8-bit content. */
     public static final int COLOR_RANGE_FULL = 1;
 
+    /** @hide */
+    @IntDef({
+        COLOR_RANGE_LIMITED,
+        COLOR_RANGE_FULL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ColorRange {}
+
+    /**
+     * An optional key describing the static metadata of HDR (high-dynamic-range) video content.
+     *
+     * The associated value is a ByteBuffer. This buffer contains the raw contents of the
+     * Static Metadata Descriptor (including the descriptor ID) of an HDMI Dynamic Range and
+     * Mastering InfoFrame as defined by CTA-861.3. This key must be provided to video decoders
+     * for HDR video content unless this information is contained in the bitstream and the video
+     * decoder supports an HDR-capable profile. This key must be provided to video encoders for
+     * HDR video content.
+     */
+    public static final String KEY_HDR_STATIC_INFO = "hdr-static-info";
+
+    /**
+     * A key describing a unique ID for the content of a media track.
+     *
+     * <p>This key is used by {@link MediaExtractor}. Some extractors provide multiple encodings
+     * of the same track (e.g. float audio tracks for FLAC and WAV may be expressed as two
+     * tracks via MediaExtractor: a normal PCM track for backward compatibility, and a float PCM
+     * track for added fidelity. Similarly, Dolby Vision extractor may provide a baseline SDR
+     * version of a DV track.) This key can be used to identify which MediaExtractor tracks refer
+     * to the same underlying content.
+     * </p>
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_TRACK_ID = "track-id";
+
     /* package private */ MediaFormat(Map<String, Object> map) {
         mMap = map;
     }
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 39bcef5..9ebf10f 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -16,6 +16,7 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.annotation.StringDef;
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -30,6 +31,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Set;
 
 /**
@@ -39,6 +42,40 @@
     private static final String TAG = "MediaMetadata";
 
     /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR,
+            METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION,
+            METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI,
+            METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE,
+            METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI,
+            METADATA_KEY_MEDIA_ID})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TextKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER,
+            METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LongKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BitmapKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RatingKey {}
+
+    /**
      * The title of the media.
      */
     public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
@@ -232,7 +269,7 @@
      */
     public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
 
-    private static final String[] PREFERRED_DESCRIPTION_ORDER = {
+    private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = {
             METADATA_KEY_TITLE,
             METADATA_KEY_ARTIST,
             METADATA_KEY_ALBUM,
@@ -242,13 +279,13 @@
             METADATA_KEY_COMPOSER
     };
 
-    private static final String[] PREFERRED_BITMAP_ORDER = {
+    private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = {
             METADATA_KEY_DISPLAY_ICON,
             METADATA_KEY_ART,
             METADATA_KEY_ALBUM_ART
     };
 
-    private static final String[] PREFERRED_URI_ORDER = {
+    private static final @TextKey String[] PREFERRED_URI_ORDER = {
             METADATA_KEY_DISPLAY_ICON_URI,
             METADATA_KEY_ART_URI,
             METADATA_KEY_ALBUM_ART_URI
@@ -328,7 +365,7 @@
     }
 
     private MediaMetadata(Parcel in) {
-        mBundle = in.readBundle();
+        mBundle = Bundle.setDefusable(in.readBundle(), true);
     }
 
     /**
@@ -349,7 +386,7 @@
      * @param key The key the value is stored under
      * @return a CharSequence value, or null
      */
-    public CharSequence getText(String key) {
+    public CharSequence getText(@TextKey String key) {
         return mBundle.getCharSequence(key);
     }
 
@@ -362,7 +399,7 @@
      * @param key The key the value is stored under
      * @return a String value, or null
      */
-    public String getString(String key) {
+    public String getString(@TextKey String key) {
         CharSequence text = getText(key);
         if (text != null) {
             return text.toString();
@@ -377,7 +414,7 @@
      * @param key The key the value is stored under
      * @return a long value
      */
-    public long getLong(String key) {
+    public long getLong(@LongKey String key) {
         return mBundle.getLong(key, 0);
     }
 
@@ -388,7 +425,7 @@
      * @param key The key the value is stored under
      * @return A {@link Rating} or null
      */
-    public Rating getRating(String key) {
+    public Rating getRating(@RatingKey String key) {
         Rating rating = null;
         try {
             rating = mBundle.getParcelable(key);
@@ -406,7 +443,7 @@
      * @param key The key the value is stored under
      * @return A {@link Bitmap} or null
      */
-    public Bitmap getBitmap(String key) {
+    public Bitmap getBitmap(@BitmapKey String key) {
         Bitmap bmp = null;
         try {
             bmp = mBundle.getParcelable(key);
@@ -612,7 +649,7 @@
          * @param value The CharSequence value to store
          * @return The Builder to allow chaining
          */
-        public Builder putText(String key, CharSequence value) {
+        public Builder putText(@TextKey String key, CharSequence value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
                     throw new IllegalArgumentException("The " + key
@@ -654,7 +691,7 @@
          * @param value The String value to store
          * @return The Builder to allow chaining
          */
-        public Builder putString(String key, String value) {
+        public Builder putString(@TextKey String key, String value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
                     throw new IllegalArgumentException("The " + key
@@ -681,7 +718,7 @@
          * @param value The long value to store
          * @return The Builder to allow chaining
          */
-        public Builder putLong(String key, long value) {
+        public Builder putLong(@LongKey String key, long value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
                     throw new IllegalArgumentException("The " + key
@@ -705,7 +742,7 @@
          * @param value The Rating value to store
          * @return The Builder to allow chaining
          */
-        public Builder putRating(String key, Rating value) {
+        public Builder putRating(@RatingKey String key, Rating value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
                     throw new IllegalArgumentException("The " + key
@@ -734,7 +771,7 @@
          * @param value The Bitmap to store
          * @return The Builder to allow chaining
          */
-        public Builder putBitmap(String key, Bitmap value) {
+        public Builder putBitmap(@BitmapKey String key, Bitmap value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
                     throw new IllegalArgumentException("The " + key
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 8618ec9..7117fbd 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -34,7 +34,7 @@
 /**
  * MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or
  * webm file as the output and at most one audio and/or one video elementary
- * stream.
+ * stream. MediaMuxer does not support muxing B-frames.
  * <p>
  * It is generally used like this:
  *
@@ -127,7 +127,8 @@
      * @param path The path of the output media file.
      * @param format The format of the output media file.
      * @see android.media.MediaMuxer.OutputFormat
-     * @throws IOException if failed to open the file for write
+     * @throws IllegalArgumentException if path is invalid or format is not supported.
+     * @throws IOException if failed to open the file for write.
      */
     public MediaMuxer(@NonNull String path, @Format int format) throws IOException {
         if (path == null) {
@@ -165,6 +166,8 @@
      * By default, the rotation degree is 0.</p>
      * @param degrees the angle to be rotated clockwise in degrees.
      * The supported angles are 0, 90, 180, and 270 degrees.
+     * @throws IllegalArgumentException if degree is not supported.
+     * @throws IllegalStateException If this method is called after {@link #start}.
      */
     public void setOrientationHint(int degrees) {
         if (degrees != 0 && degrees != 90  && degrees != 180 && degrees != 270) {
@@ -217,6 +220,8 @@
      * Starts the muxer.
      * <p>Make sure this is called after {@link #addTrack} and before
      * {@link #writeSampleData}.</p>
+     * @throws IllegalStateException If this method is called after {@link #start}
+     * or Muxer is released
      */
     public void start() {
         if (mNativeObject == 0) {
@@ -233,6 +238,7 @@
     /**
      * Stops the muxer.
      * <p>Once the muxer stops, it can not be restarted.</p>
+     * @throws IllegalStateException if muxer is in the wrong state.
      */
     public void stop() {
         if (mState == MUXER_STATE_STARTED) {
@@ -264,6 +270,8 @@
      *               MediaFormat.
      * @return The track index for this newly added track, and it should be used
      * in the {@link #writeSampleData}.
+     * @throws IllegalArgumentException if format is invalid.
+     * @throws IllegalStateException if muxer is in the wrong state.
      */
     public int addTrack(@NonNull MediaFormat format) {
         if (format == null) {
@@ -314,6 +322,8 @@
      * @param byteBuf The encoded sample.
      * @param trackIndex The track index for this sample.
      * @param bufferInfo The buffer information related to this sample.
+     * @throws IllegalArgumentException if trackIndex, byteBuf or bufferInfo is  invalid.
+     * @throws IllegalStateException if muxer is in wrong state.
      * MediaMuxer uses the flags provided in {@link MediaCodec.BufferInfo},
      * to signal sync frames.
      */
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 26e466e..b78869e 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -57,6 +57,7 @@
 import android.media.SyncParams;
 
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.Preconditions;
 
 import libcore.io.IoBridge;
 import libcore.io.Libcore;
@@ -964,8 +965,8 @@
      * @param uri the Content URI of the data you want to play
      * @throws IllegalStateException if it is called in an invalid state
      */
-    public void setDataSource(Context context, Uri uri)
-        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+    public void setDataSource(@NonNull Context context, @NonNull Uri uri)
+            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
         setDataSource(context, uri, null);
     }
 
@@ -981,47 +982,46 @@
      *                to disallow or allow cross domain redirection.
      * @throws IllegalStateException if it is called in an invalid state
      */
-    public void setDataSource(Context context, Uri uri, Map<String, String> headers)
-            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+    public void setDataSource(@NonNull Context context, @NonNull Uri uri,
+            @Nullable Map<String, String> headers) throws IOException, IllegalArgumentException,
+                    SecurityException, IllegalStateException {
+        final ContentResolver resolver = context.getContentResolver();
         final String scheme = uri.getScheme();
         if (ContentResolver.SCHEME_FILE.equals(scheme)) {
             setDataSource(uri.getPath());
             return;
         } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
                 && Settings.AUTHORITY.equals(uri.getAuthority())) {
-            // Redirect ringtones to go directly to underlying provider
-            uri = RingtoneManager.getActualDefaultRingtoneUri(context,
-                    RingtoneManager.getDefaultType(uri));
-            if (uri == null) {
-                throw new FileNotFoundException("Failed to resolve default ringtone");
-            }
-        }
-
-        AssetFileDescriptor fd = null;
-        try {
-            ContentResolver resolver = context.getContentResolver();
-            fd = resolver.openAssetFileDescriptor(uri, "r");
-            if (fd == null) {
+            // Try cached ringtone first since the actual provider may not be
+            // encryption aware, or it may be stored on CE media storage
+            final int type = RingtoneManager.getDefaultType(uri);
+            final Uri cacheUri = RingtoneManager.getCacheForType(type);
+            final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
+            if (attemptDataSource(resolver, cacheUri)) {
                 return;
-            }
-            // Note: using getDeclaredLength so that our behavior is the same
-            // as previous versions when the content provider is returning
-            // a full file.
-            if (fd.getDeclaredLength() < 0) {
-                setDataSource(fd.getFileDescriptor());
+            } else if (attemptDataSource(resolver, actualUri)) {
+                return;
             } else {
-                setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
+                setDataSource(uri.toString(), headers);
             }
-            return;
-        } catch (SecurityException | IOException ex) {
-            Log.w(TAG, "Couldn't open file on client side; trying server side: " + ex);
-        } finally {
-            if (fd != null) {
-                fd.close();
+        } else {
+            // Try requested Uri locally first, or fallback to media server
+            if (attemptDataSource(resolver, uri)) {
+                return;
+            } else {
+                setDataSource(uri.toString(), headers);
             }
         }
+    }
 
-        setDataSource(uri.toString(), headers);
+    private boolean attemptDataSource(ContentResolver resolver, Uri uri) {
+        try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
+            setDataSource(afd);
+            return true;
+        } catch (NullPointerException | SecurityException | IOException ex) {
+            Log.w(TAG, "Couldn't open " + uri + ": " + ex);
+            return false;
+        }
     }
 
     /**
@@ -1102,6 +1102,26 @@
         throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
 
     /**
+     * Sets the data source (AssetFileDescriptor) to use. It is the caller's
+     * responsibility to close the file descriptor. It is safe to do so as soon
+     * as this call returns.
+     *
+     * @param afd the AssetFileDescriptor for the file you want to play
+     */
+    public void setDataSource(@NonNull AssetFileDescriptor afd)
+            throws IOException, IllegalArgumentException, IllegalStateException {
+        Preconditions.checkNotNull(afd);
+        // Note: using getDeclaredLength so that our behavior is the same
+        // as previous versions when the content provider is returning
+        // a full file.
+        if (afd.getDeclaredLength() < 0) {
+            setDataSource(afd.getFileDescriptor());
+        } else {
+            setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
+        }
+    }
+
+    /**
      * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
      * to close the file descriptor. It is safe to do so as soon as this call returns.
      *
@@ -2825,13 +2845,17 @@
                             MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
                     sendMessage(msg2);
                 }
-                if (mOnPreparedListener != null)
-                    mOnPreparedListener.onPrepared(mMediaPlayer);
+                OnPreparedListener onPreparedListener = mOnPreparedListener;
+                if (onPreparedListener != null)
+                    onPreparedListener.onPrepared(mMediaPlayer);
                 return;
 
             case MEDIA_PLAYBACK_COMPLETE:
-                if (mOnCompletionListener != null)
-                    mOnCompletionListener.onCompletion(mMediaPlayer);
+                {
+                    OnCompletionListener onCompletionListener = mOnCompletionListener;
+                    if (onCompletionListener != null)
+                        onCompletionListener.onCompletion(mMediaPlayer);
+                }
                 stayAwake(false);
                 return;
 
@@ -2855,13 +2879,15 @@
                 break;
 
             case MEDIA_BUFFERING_UPDATE:
-                if (mOnBufferingUpdateListener != null)
-                    mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
+                OnBufferingUpdateListener onBufferingUpdateListener = mOnBufferingUpdateListener;
+                if (onBufferingUpdateListener != null)
+                    onBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
                 return;
 
             case MEDIA_SEEK_COMPLETE:
-                if (mOnSeekCompleteListener != null) {
-                    mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
+                OnSeekCompleteListener onSeekCompleteListener = mOnSeekCompleteListener;
+                if (onSeekCompleteListener != null) {
+                    onSeekCompleteListener.onSeekComplete(mMediaPlayer);
                 }
                 // fall through
 
@@ -2875,8 +2901,9 @@
                 return;
 
             case MEDIA_SET_VIDEO_SIZE:
-                if (mOnVideoSizeChangedListener != null) {
-                    mOnVideoSizeChangedListener.onVideoSizeChanged(
+                OnVideoSizeChangedListener onVideoSizeChangedListener = mOnVideoSizeChangedListener;
+                if (onVideoSizeChangedListener != null) {
+                    onVideoSizeChangedListener.onVideoSizeChanged(
                         mMediaPlayer, msg.arg1, msg.arg2);
                 }
                 return;
@@ -2884,11 +2911,15 @@
             case MEDIA_ERROR:
                 Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
                 boolean error_was_handled = false;
-                if (mOnErrorListener != null) {
-                    error_was_handled = mOnErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
+                OnErrorListener onErrorListener = mOnErrorListener;
+                if (onErrorListener != null) {
+                    error_was_handled = onErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
                 }
-                if (mOnCompletionListener != null && ! error_was_handled) {
-                    mOnCompletionListener.onCompletion(mMediaPlayer);
+                {
+                    OnCompletionListener onCompletionListener = mOnCompletionListener;
+                    if (onCompletionListener != null && ! error_was_handled) {
+                        onCompletionListener.onCompletion(mMediaPlayer);
+                    }
                 }
                 stayAwake(false);
                 return;
@@ -2924,47 +2955,52 @@
                     break;
                 }
 
-                if (mOnInfoListener != null) {
-                    mOnInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
+                OnInfoListener onInfoListener = mOnInfoListener;
+                if (onInfoListener != null) {
+                    onInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
                 }
                 // No real default action so far.
                 return;
             case MEDIA_TIMED_TEXT:
-                if (mOnTimedTextListener == null)
+                OnTimedTextListener onTimedTextListener = mOnTimedTextListener;
+                if (onTimedTextListener == null)
                     return;
                 if (msg.obj == null) {
-                    mOnTimedTextListener.onTimedText(mMediaPlayer, null);
+                    onTimedTextListener.onTimedText(mMediaPlayer, null);
                 } else {
                     if (msg.obj instanceof Parcel) {
                         Parcel parcel = (Parcel)msg.obj;
                         TimedText text = new TimedText(parcel);
                         parcel.recycle();
-                        mOnTimedTextListener.onTimedText(mMediaPlayer, text);
+                        onTimedTextListener.onTimedText(mMediaPlayer, text);
                     }
                 }
                 return;
 
             case MEDIA_SUBTITLE_DATA:
-                if (mOnSubtitleDataListener == null) {
+                OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener;
+                if (onSubtitleDataListener == null) {
                     return;
                 }
                 if (msg.obj instanceof Parcel) {
                     Parcel parcel = (Parcel) msg.obj;
                     SubtitleData data = new SubtitleData(parcel);
                     parcel.recycle();
-                    mOnSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
+                    onSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
                 }
                 return;
 
             case MEDIA_META_DATA:
-                if (mOnTimedMetaDataAvailableListener == null) {
+                OnTimedMetaDataAvailableListener onTimedMetaDataAvailableListener =
+                    mOnTimedMetaDataAvailableListener;
+                if (onTimedMetaDataAvailableListener == null) {
                     return;
                 }
                 if (msg.obj instanceof Parcel) {
                     Parcel parcel = (Parcel) msg.obj;
                     TimedMetaData data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
                     parcel.recycle();
-                    mOnTimedMetaDataAvailableListener.onTimedMetaDataAvailable(mMediaPlayer, data);
+                    onTimedMetaDataAvailableListener.onTimedMetaDataAvailable(mMediaPlayer, data);
                 }
                 return;
 
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index bcc2b406..d8e0d6d 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -1547,18 +1547,30 @@
 
         private Object mTag;
 
+        /** @hide */
+        @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface PlaybackType {}
+
         /**
          * The default playback type, "local", indicating the presentation of the media is happening
          * on the same device (e&#46;g&#46; a phone, a tablet) as where it is controlled from.
          * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_LOCAL = 0;
+
         /**
          * A playback type indicating the presentation of the media is happening on
          * a different device (i&#46;e&#46; the remote device) than where it is controlled from.
          * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_REMOTE = 1;
+
+        /** @hide */
+         @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE})
+         @Retention(RetentionPolicy.SOURCE)
+         private @interface PlaybackVolume {}
+
         /**
          * Playback information indicating the playback volume is fixed, i&#46;e&#46; it cannot be
          * controlled from this object. An example of fixed playback volume is a remote player,
@@ -1783,6 +1795,7 @@
          * @return the type of playback associated with this route
          * @see UserRouteInfo#setPlaybackType(int)
          */
+        @PlaybackType
         public int getPlaybackType() {
             return mPlaybackType;
         }
@@ -1874,6 +1887,7 @@
          * @return how volume is handling on the route
          * @see UserRouteInfo#setVolumeHandling(int)
          */
+        @PlaybackVolume
         public int getVolumeHandling() {
             return mVolumeHandling;
         }
@@ -2164,7 +2178,7 @@
          *    ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}).
          * @param type
          */
-        public void setPlaybackType(int type) {
+        public void setPlaybackType(@RouteInfo.PlaybackType int type) {
             if (mPlaybackType != type) {
                 mPlaybackType = type;
                 configureSessionVolume();
@@ -2177,7 +2191,7 @@
          * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}).
          * @param volumeHandling
          */
-        public void setVolumeHandling(int volumeHandling) {
+        public void setVolumeHandling(@RouteInfo.PlaybackVolume int volumeHandling) {
             if (mVolumeHandling != volumeHandling) {
                 mVolumeHandling = volumeHandling;
                 configureSessionVolume();
@@ -2268,7 +2282,8 @@
                 return;
             }
             if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
-                int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED;
+                @VolumeProvider.ControlType int volumeControl =
+                        VolumeProvider.VOLUME_CONTROL_FIXED;
                 switch (mVolumeHandling) {
                     case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE:
                         volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
@@ -2294,7 +2309,8 @@
 
         class SessionVolumeProvider extends VolumeProvider {
 
-            public SessionVolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
+            public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl,
+                    int maxVolume, int currentVolume) {
                 super(volumeControl, maxVolume, currentVolume);
             }
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 78f357f..5fd85d1 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1042,13 +1042,13 @@
 
             if(needToSetSettings) {
                 if (notifications) {
-                    setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
+                    setRingtoneIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
                     mDefaultNotificationSet = true;
                 } else if (ringtones) {
-                    setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
+                    setRingtoneIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
                     mDefaultRingtoneSet = true;
                 } else if (alarms) {
-                    setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
+                    setRingtoneIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
                     mDefaultAlarmSet = true;
                 }
             }
@@ -1063,18 +1063,18 @@
                     pathFilenameStart + filenameLength == path.length();
         }
 
-        private void setSettingIfNotSet(String settingName, Uri uri, long rowId) {
-
-            if(wasSettingAlreadySet(settingName)) {
+        private void setRingtoneIfNotSet(String settingName, Uri uri, long rowId) {
+            if (wasRingtoneAlreadySet(settingName)) {
                 return;
             }
 
             ContentResolver cr = mContext.getContentResolver();
             String existingSettingValue = Settings.System.getString(cr, settingName);
             if (TextUtils.isEmpty(existingSettingValue)) {
-                // Set the setting to the given URI
-                Settings.System.putString(cr, settingName,
-                        ContentUris.withAppendedId(uri, rowId).toString());
+                final Uri settingUri = Settings.System.getUriFor(settingName);
+                final Uri ringtoneUri = ContentUris.withAppendedId(uri, rowId);
+                RingtoneManager.setActualDefaultRingtoneUri(mContext,
+                        RingtoneManager.getDefaultType(settingUri), ringtoneUri);
             }
             Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
         }
@@ -1107,7 +1107,7 @@
         return base + "_set";
     }
 
-    private boolean wasSettingAlreadySet(String name) {
+    private boolean wasRingtoneAlreadySet(String name) {
         ContentResolver cr = mContext.getContentResolver();
         String indicatorName = settingSetIndicatorName(name);
         try {
@@ -1134,9 +1134,9 @@
             selectionArgs = new String[] { "" };
         }
 
-        mDefaultRingtoneSet = wasSettingAlreadySet(Settings.System.RINGTONE);
-        mDefaultNotificationSet = wasSettingAlreadySet(Settings.System.NOTIFICATION_SOUND);
-        mDefaultAlarmSet = wasSettingAlreadySet(Settings.System.ALARM_ALERT);
+        mDefaultRingtoneSet = wasRingtoneAlreadySet(Settings.System.RINGTONE);
+        mDefaultNotificationSet = wasRingtoneAlreadySet(Settings.System.NOTIFICATION_SOUND);
+        mDefaultAlarmSet = wasRingtoneAlreadySet(Settings.System.ALARM_ALERT);
 
         // Tell the provider to not delete the file.
         // If the file is truly gone the delete is unnecessary, and we want to avoid
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
index a518bb4..04d5364f 100644
--- a/media/java/android/media/Rating.java
+++ b/media/java/android/media/Rating.java
@@ -16,10 +16,14 @@
 
 package android.media;
 
+import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A class to encapsulate rating information used as content metadata.
  * A rating is defined by its rating style (see {@link #RATING_HEART},
@@ -32,6 +36,21 @@
     private final static String TAG = "Rating";
 
     /**
+     * @hide
+     */
+    @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS,
+            RATING_5_STARS, RATING_PERCENTAGE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Style {}
+
+    /**
+     * @hide
+     */
+    @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StarStyle {}
+
+    /**
      * Indicates a rating style is not supported. A Rating will never have this
      * type, but can be used by other classes to indicate they do not support
      * Rating.
@@ -75,7 +94,7 @@
 
     private final float mRatingValue;
 
-    private Rating(int ratingStyle, float rating) {
+    private Rating(@Style int ratingStyle, float rating) {
         mRatingStyle = ratingStyle;
         mRatingValue = rating;
     }
@@ -124,7 +143,7 @@
      *    or {@link #RATING_PERCENTAGE}.
      * @return null if an invalid rating style is passed, a new Rating instance otherwise.
      */
-    public static Rating newUnratedRating(int ratingStyle) {
+    public static Rating newUnratedRating(@Style int ratingStyle) {
         switch(ratingStyle) {
             case RATING_HEART:
             case RATING_THUMB_UP_DOWN:
@@ -172,7 +191,7 @@
      * @return null if the rating style is invalid, or the rating is out of range,
      *     a new Rating instance otherwise.
      */
-    public static Rating newStarRating(int starRatingStyle, float starRating) {
+    public static Rating newStarRating(@StarStyle int starRatingStyle, float starRating) {
         float maxRating = -1.0f;
         switch(starRatingStyle) {
             case RATING_3_STARS:
@@ -225,6 +244,7 @@
      *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
      *    or {@link #RATING_PERCENTAGE}.
      */
+    @Style
     public int getRatingStyle() {
         return mRatingStyle;
     }
@@ -285,4 +305,4 @@
             return mRatingValue;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 025029e..86ebae1 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -16,23 +16,30 @@
 
 package android.media;
 
-import com.android.internal.database.SortCursor;
-
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Activity;
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Settings.System;
 import android.util.Log;
 
+import com.android.internal.database.SortCursor;
+
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -217,9 +224,9 @@
      */
     public static final int URI_COLUMN_INDEX = 2;
 
-    private Activity mActivity;
-    private Context mContext;
-    
+    private final Activity mActivity;
+    private final Context mContext;
+
     private Cursor mCursor;
 
     private int mType = TYPE_RINGTONE;
@@ -240,7 +247,8 @@
      * @param activity The activity used to get a managed cursor.
      */
     public RingtoneManager(Activity activity) {
-        mContext = mActivity = activity;
+        mActivity = activity;
+        mContext = activity;
         setType(mType);
     }
 
@@ -252,6 +260,7 @@
      * @param context The context to used to get a cursor.
      */
     public RingtoneManager(Context context) {
+        mActivity = null;
         mContext = context;
         setType(mType);
     }
@@ -265,7 +274,6 @@
      * @see #EXTRA_RINGTONE_TYPE           
      */
     public void setType(int type) {
-
         if (mCursor != null) {
             throw new IllegalStateException(
                     "Setting filter columns should be done before querying for ringtones.");
@@ -635,7 +643,8 @@
     public static Uri getActualDefaultRingtoneUri(Context context, int type) {
         String setting = getSettingForType(type);
         if (setting == null) return null;
-        final String uriString = Settings.System.getString(context.getContentResolver(), setting);
+        final String uriString = Settings.System.getStringForUser(context.getContentResolver(),
+                setting, context.getUserId());
         return uriString != null ? Uri.parse(uriString) : null;
     }
     
@@ -650,12 +659,48 @@
      * @see #getActualDefaultRingtoneUri(Context, int)
      */
     public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
+        final ContentResolver resolver = context.getContentResolver();
+
         String setting = getSettingForType(type);
         if (setting == null) return;
-        Settings.System.putString(context.getContentResolver(), setting,
-                ringtoneUri != null ? ringtoneUri.toString() : null);
+        Settings.System.putStringForUser(resolver, setting,
+                ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());
+
+        // Stream selected ringtone into cache so it's available for playback
+        // when CE storage is still locked
+        if (ringtoneUri != null) {
+            final Uri cacheUri = getCacheForType(type);
+            try (InputStream in = openRingtone(context, ringtoneUri);
+                    OutputStream out = resolver.openOutputStream(cacheUri)) {
+                Streams.copy(in, out);
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to cache ringtone: " + e);
+            }
+        }
     }
-    
+
+    /**
+     * Try opening the given ringtone locally first, but failover to
+     * {@link IRingtonePlayer} if we can't access it directly. Typically happens
+     * when process doesn't hold
+     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}.
+     */
+    private static InputStream openRingtone(Context context, Uri uri) throws IOException {
+        final ContentResolver resolver = context.getContentResolver();
+        try {
+            return resolver.openInputStream(uri);
+        } catch (SecurityException | IOException e) {
+            Log.w(TAG, "Failed to open directly; attempting failover: " + e);
+            final IRingtonePlayer player = context.getSystemService(AudioManager.class)
+                    .getRingtonePlayer();
+            try {
+                return new ParcelFileDescriptor.AutoCloseInputStream(player.openRingtone(uri));
+            } catch (Exception e2) {
+                throw new IOException(e2);
+            }
+        }
+    }
+
     private static String getSettingForType(int type) {
         if ((type & TYPE_RINGTONE) != 0) {
             return Settings.System.RINGTONE;
@@ -667,7 +712,20 @@
             return null;
         }
     }
-    
+
+    /** {@hide} */
+    public static Uri getCacheForType(int type) {
+        if ((type & TYPE_RINGTONE) != 0) {
+            return Settings.System.RINGTONE_CACHE_URI;
+        } else if ((type & TYPE_NOTIFICATION) != 0) {
+            return Settings.System.NOTIFICATION_SOUND_CACHE_URI;
+        } else if ((type & TYPE_ALARM) != 0) {
+            return Settings.System.ALARM_ALERT_CACHE_URI;
+        } else {
+            return null;
+        }
+    }
+
     /**
      * Returns whether the given {@link Uri} is one of the default ringtones.
      * 
diff --git a/media/java/android/media/VolumeProvider.java b/media/java/android/media/VolumeProvider.java
index 5d1e004..1c017c5 100644
--- a/media/java/android/media/VolumeProvider.java
+++ b/media/java/android/media/VolumeProvider.java
@@ -15,8 +15,12 @@
  */
 package android.media;
 
+import android.annotation.IntDef;
 import android.media.session.MediaSession;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Handles requests to adjust or set the volume on a session. This is also used
  * to push volume updates back to the session. The provider must call
@@ -26,6 +30,14 @@
  * {@link MediaSession#setPlaybackToRemote}.
  */
 public abstract class VolumeProvider {
+
+    /**
+     * @hide
+     */
+    @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ControlType {}
+
     /**
      * The volume is fixed and can not be modified. Requests to change volume
      * should be ignored.
@@ -61,7 +73,7 @@
      * @param maxVolume The maximum allowed volume.
      * @param currentVolume The current volume on the output.
      */
-    public VolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
+    public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
         mControlType = volumeControl;
         mMaxVolume = maxVolume;
         mCurrentVolume = currentVolume;
@@ -72,6 +84,7 @@
      *
      * @return The volume control type for this volume provider
      */
+    @ControlType
     public final int getVolumeControl() {
         return mControlType;
     }
@@ -145,4 +158,4 @@
     public static abstract class Callback {
         public abstract void onVolumeChanged(VolumeProvider volumeProvider);
     }
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 4ffac6d..adeb834 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -17,7 +17,9 @@
 package android.media.audiopolicy;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioSystem;
 
@@ -34,21 +36,28 @@
     private AudioMixingRule mRule;
     private AudioFormat mFormat;
     private int mRouteFlags;
-    private String mRegistrationId;
     private int mMixType = MIX_TYPE_INVALID;
+
+    // written by AudioPolicy
     int mMixState = MIX_STATE_DISABLED;
     int mCallbackFlags;
+    String mDeviceAddress;
+
+    // initialized in constructor, read by AudioPolicyConfig
+    final int mDeviceSystemType; // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
 
     /**
      * All parameters are guaranteed valid through the Builder.
      */
-    private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags) {
+    private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags,
+            int deviceType, String deviceAddress) {
         mRule = rule;
         mFormat = format;
         mRouteFlags = routeFlags;
-        mRegistrationId = null;
         mMixType = rule.getTargetMixType();
         mCallbackFlags = callbackFlags;
+        mDeviceSystemType = deviceType;
+        mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
     }
 
     // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
@@ -74,6 +83,8 @@
     @SystemApi
     public static final int ROUTE_FLAG_LOOP_BACK = 0x1 << 1;
 
+    private static final int ROUTE_FLAG_SUPPORTED = ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK;
+
     // MIX_TYPE_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h
     /**
      * @hide
@@ -142,12 +153,12 @@
     }
 
     void setRegistration(String regId) {
-        mRegistrationId = regId;
+        mDeviceAddress = regId;
     }
 
     /** @hide */
     public String getRegistration() {
-        return mRegistrationId;
+        return mDeviceAddress;
     }
 
     /** @hide */
@@ -172,6 +183,9 @@
         private AudioFormat mFormat = null;
         private int mRouteFlags = 0;
         private int mCallbackFlags = 0;
+        // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
+        private int mDeviceSystemType = AudioSystem.DEVICE_NONE;
+        private String mDeviceAddress = null;
 
         /**
          * @hide
@@ -200,7 +214,7 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        public Builder setMixingRule(AudioMixingRule rule)
+        Builder setMixingRule(AudioMixingRule rule)
                 throws IllegalArgumentException {
             if (rule == null) {
                 throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
@@ -216,7 +230,7 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        public Builder setCallbackFlags(int flags) throws IllegalArgumentException {
+        Builder setCallbackFlags(int flags) throws IllegalArgumentException {
             if ((flags != 0) && ((flags & CALLBACK_FLAGS_ALL) == 0)) {
                 throw new IllegalArgumentException("Illegal callback flags 0x"
                         + Integer.toHexString(flags).toUpperCase());
@@ -226,6 +240,19 @@
         }
 
         /**
+         * @hide
+         * Only used by AudioPolicyConfig, not a public API.
+         * @param deviceType an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
+         * @param address
+         * @return the same Builder instance.
+         */
+        Builder setDevice(int deviceType, String address) {
+            mDeviceSystemType = deviceType;
+            mDeviceAddress = address;
+            return this;
+        }
+
+        /**
          * Sets the {@link AudioFormat} for the mix.
          * @param format a non-null {@link AudioFormat} instance.
          * @return the same Builder instance.
@@ -242,7 +269,8 @@
         }
 
         /**
-         * Sets the routing behavior for the mix.
+         * Sets the routing behavior for the mix. If not set, routing behavior will default to
+         * {@link AudioMix#ROUTE_FLAG_LOOP_BACK}.
          * @param routeFlags one of {@link AudioMix#ROUTE_FLAG_LOOP_BACK},
          *     {@link AudioMix#ROUTE_FLAG_RENDER}
          * @return the same Builder instance.
@@ -254,15 +282,41 @@
             if (routeFlags == 0) {
                 throw new IllegalArgumentException("Illegal empty route flags");
             }
-            if ((routeFlags & (ROUTE_FLAG_LOOP_BACK | ROUTE_FLAG_RENDER)) == 0) {
+            if ((routeFlags & ROUTE_FLAG_SUPPORTED) == 0) {
                 throw new IllegalArgumentException("Invalid route flags 0x"
-                        + Integer.toHexString(routeFlags) + "when creating an AudioMix");
+                        + Integer.toHexString(routeFlags) + "when configuring an AudioMix");
+            }
+            if ((routeFlags & ~ROUTE_FLAG_SUPPORTED) != 0) {
+                throw new IllegalArgumentException("Unknown route flags 0x"
+                        + Integer.toHexString(routeFlags) + "when configuring an AudioMix");
             }
             mRouteFlags = routeFlags;
             return this;
         }
 
         /**
+         * Sets the audio device used for playback. Cannot be used in the context of an audio
+         * policy used to inject audio to be recorded, or in a mix whose route flags doesn't
+         * specify {@link AudioMix#ROUTE_FLAG_RENDER}.
+         * @param device a non-null AudioDeviceInfo describing the audio device to play the output
+         *     of this mix.
+         * @return the same Builder instance
+         * @throws IllegalArgumentException
+         */
+        @SystemApi
+        public Builder setDevice(@NonNull AudioDeviceInfo device) throws IllegalArgumentException {
+            if (device == null) {
+                throw new IllegalArgumentException("Illegal null AudioDeviceInfo argument");
+            }
+            if (!device.isSink()) {
+                throw new IllegalArgumentException("Unsupported device type on mix, not a sink");
+            }
+            mDeviceSystemType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
+            mDeviceAddress = device.getAddress();
+            return this;
+        }
+
+        /**
          * Combines all of the settings and return a new {@link AudioMix} object.
          * @return a new {@link AudioMix} object
          * @throws IllegalArgumentException if no {@link AudioMixingRule} has been set.
@@ -273,17 +327,49 @@
                 throw new IllegalArgumentException("Illegal null AudioMixingRule");
             }
             if (mRouteFlags == 0) {
-                // no route flags set, use default
-                mRouteFlags = ROUTE_FLAG_RENDER;
+                // no route flags set, use default as described in Builder.setRouteFlags(int)
+                mRouteFlags = ROUTE_FLAG_LOOP_BACK;
+            }
+            // can't do loop back AND render at same time in this implementation
+            if (mRouteFlags == (ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK)) {
+                throw new IllegalArgumentException("Unsupported route behavior combination 0x" +
+                        Integer.toHexString(mRouteFlags));
             }
             if (mFormat == null) {
+                // FIXME Can we eliminate this?  Will AudioMix work with an unspecified sample rate?
                 int rate = AudioSystem.getPrimaryOutputSamplingRate();
                 if (rate <= 0) {
                     rate = 44100;
                 }
                 mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
             }
-            return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags);
+            if ((mDeviceSystemType != AudioSystem.DEVICE_NONE)
+                    && (mDeviceSystemType != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)
+                    && (mDeviceSystemType != AudioSystem.DEVICE_IN_REMOTE_SUBMIX)) {
+                if ((mRouteFlags & ROUTE_FLAG_RENDER) == 0) {
+                    throw new IllegalArgumentException(
+                            "Can't have audio device without flag ROUTE_FLAG_RENDER");
+                }
+                if (mRule.getTargetMixType() != AudioMix.MIX_TYPE_PLAYERS) {
+                    throw new IllegalArgumentException("Unsupported device on non-playback mix");
+                }
+            } else {
+                if ((mRouteFlags & ROUTE_FLAG_RENDER) == ROUTE_FLAG_RENDER) {
+                    throw new IllegalArgumentException(
+                            "Can't have flag ROUTE_FLAG_RENDER without an audio device");
+                }
+                if ((mRouteFlags & ROUTE_FLAG_SUPPORTED) == ROUTE_FLAG_LOOP_BACK) {
+                    if (mRule.getTargetMixType() == MIX_TYPE_PLAYERS) {
+                        mDeviceSystemType = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+                    } else if (mRule.getTargetMixType() == MIX_TYPE_RECORDERS) {
+                        mDeviceSystemType = AudioSystem.DEVICE_IN_REMOTE_SUBMIX;
+                    } else {
+                        throw new IllegalArgumentException("Unknown mixing rule type");
+                    }
+                }
+            }
+            return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType,
+                    mDeviceAddress);
         }
     }
 }
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 5d2bac0..cafa5a8 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -17,6 +17,8 @@
 package android.media.audiopolicy;
 
 import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioPatch;
 import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -81,6 +83,9 @@
             dest.writeInt(mix.getRouteFlags());
             // write callback flags
             dest.writeInt(mix.mCallbackFlags);
+            // write device information
+            dest.writeInt(mix.mDeviceSystemType);
+            dest.writeString(mix.mDeviceAddress);
             // write mix format
             dest.writeInt(mix.getFormat().getSampleRate());
             dest.writeInt(mix.getFormat().getEncoding());
@@ -104,6 +109,8 @@
             mixBuilder.setRouteFlags(routeFlags);
             // read callback flags
             mixBuilder.setCallbackFlags(in.readInt());
+            // read device information
+            mixBuilder.setDevice(in.readInt(), in.readString());
             // read mix format
             int sampleRate = in.readInt();
             int encoding = in.readInt();
@@ -197,8 +204,14 @@
         int mixIndex = 0;
         for (AudioMix mix : mMixes) {
             if (!mRegistrationId.isEmpty()) {
-                mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
-                        + mixIndex++);
+                if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) ==
+                        AudioMix.ROUTE_FLAG_LOOP_BACK) {
+                    mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
+                            + mixIndex++);
+                } else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) ==
+                        AudioMix.ROUTE_FLAG_RENDER) {
+                    mix.setRegistration(mix.mDeviceAddress);
+                }
             } else {
                 mix.setRegistration("");
             }
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 2f72df6..7c6adad 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -57,8 +57,9 @@
  * <h3>Standard Extra Data</h3>
  *
  * <p>These are the current standard fields that can be used as extra data via
- * {@link #subscribe(String, Bundle, SubscriptionCallback)}, {@link #unsubscribe(String, Bundle)},
- * and {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
+ * {@link #subscribe(String, Bundle, SubscriptionCallback)},
+ * {@link #unsubscribe(String, SubscriptionCallback)}, and
+ * {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
  *
  * <ul>
  *     <li> {@link #EXTRA_PAGE}
@@ -71,9 +72,8 @@
 
     /**
      * Used as an int extra field to denote the page number to subscribe.
-     * The value of {@code EXTRA_PAGE} should be greater than or equal to 1.
+     * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
      *
-     * @see android.service.media.MediaBrowserService.BrowserRoot
      * @see #EXTRA_PAGE_SIZE
      */
     public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
@@ -82,7 +82,6 @@
      * Used as an int extra field to denote the number of media items in a page.
      * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
      *
-     * @see android.service.media.MediaBrowserService.BrowserRoot
      * @see #EXTRA_PAGE
      */
     public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
@@ -367,7 +366,7 @@
         if (options == null) {
             throw new IllegalArgumentException("options are null");
         }
-        subscribeInternal(parentId, options, callback);
+        subscribeInternal(parentId, new Bundle(options), callback);
     }
 
     /**
@@ -385,7 +384,7 @@
     }
 
     /**
-     * Unsubscribes for changes to the children of the specified media id.
+     * Unsubscribes for changes to the children of the specified media id through a callback.
      * <p>
      * The query callback will no longer be invoked for results associated with
      * this id once this method returns.
@@ -393,13 +392,13 @@
      *
      * @param parentId The id of the parent media item whose list of children
      *            will be unsubscribed.
-     * @param options A bundle sent to the media browse service to subscribe.
+     * @param callback A callback sent to the media browse service to subscribe.
      */
-    public void unsubscribe(@NonNull String parentId, @NonNull Bundle options) {
-        if (options == null) {
-            throw new IllegalArgumentException("options are null");
+    public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback is null");
         }
-        unsubscribeInternal(parentId, options);
+        unsubscribeInternal(parentId, callback);
     }
 
     /**
@@ -492,7 +491,7 @@
         }
     }
 
-    private void unsubscribeInternal(String parentId, Bundle options) {
+    private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
         // Check arguments.
         if (TextUtils.isEmpty(parentId)) {
             throw new IllegalArgumentException("parentId is empty.");
@@ -502,16 +501,21 @@
         Subscription sub = mSubscriptions.get(parentId);
 
         // Tell the service if necessary.
-        if (sub != null && sub.removeCallback(options) && mState == CONNECT_STATE_CONNECTED) {
+        if (mState == CONNECT_STATE_CONNECTED && sub != null) {
             try {
-                // NOTE: Do not call removeSubscriptionWithOptions when options are null. Otherwise,
-                // it will break the action of support library which expects removeSubscription will
-                // be called when options are null.
-                if (options == null) {
+                if (callback == null) {
                     mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
                 } else {
-                    mServiceBinder.removeSubscriptionWithOptions(
-                            parentId, options, mServiceCallbacks);
+                    final List<SubscriptionCallback> callbacks = sub.getCallbacks();
+                    final List<Bundle> optionsList = sub.getOptionsList();
+                    for (int i = callbacks.size() - 1; i >= 0; --i) {
+                        if (callbacks.get(i) == callback) {
+                            mServiceBinder.removeSubscriptionWithOptions(
+                                    parentId, optionsList.get(i), mServiceCallbacks);
+                            callbacks.remove(i);
+                            optionsList.remove(i);
+                        }
+                    }
                 }
             } catch (RemoteException ex) {
                 // Process is crashing. We will disconnect, and upon reconnect we will
@@ -519,7 +523,8 @@
                 Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
             }
         }
-        if (sub != null && sub.isEmpty()) {
+
+        if (sub != null && (sub.isEmpty() || callback == null)) {
             mSubscriptions.remove(parentId);
         }
     }
@@ -635,7 +640,6 @@
                     return;
                 }
 
-                List<MediaItem> data = list == null ? null : list.getList();
                 if (DBG) {
                     Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
                 }
@@ -646,10 +650,19 @@
                     // Tell the app.
                     SubscriptionCallback subscriptionCallback = subscription.getCallback(options);
                     if (subscriptionCallback != null) {
+                        List<MediaItem> data = list == null ? null : list.getList();
                         if (options == null) {
-                            subscriptionCallback.onChildrenLoaded(parentId, data);
+                            if (data == null) {
+                                subscriptionCallback.onError(parentId);
+                            } else {
+                                subscriptionCallback.onChildrenLoaded(parentId, data);
+                            }
                         } else {
-                            subscriptionCallback.onChildrenLoaded(parentId, data, options);
+                            if (data == null) {
+                                subscriptionCallback.onError(parentId, options);
+                            } else {
+                                subscriptionCallback.onChildrenLoaded(parentId, data, options);
+                            }
                         }
                         return;
                     }
@@ -850,21 +863,21 @@
          * Called when the list of children is loaded or updated.
          *
          * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded, or null if the id is invalid.
+         * @param children The children which were loaded.
          */
-        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
+        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
         }
 
         /**
          * Called when the list of children is loaded or updated.
          *
          * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded, or null if the id is invalid.
-         * @param options A bundle of service-specific arguments to send to the media
+         * @param children The children which were loaded.
+         * @param options A bundle of service-specific arguments sent to the media
          *            browse service. The contents of this bundle may affect the
          *            information returned when browsing.
          */
-        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children,
+        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
                 @NonNull Bundle options) {
         }
 
@@ -1112,16 +1125,5 @@
             mCallbacks.add(callback);
             mOptionsList.add(options);
         }
-
-        public boolean removeCallback(Bundle options) {
-            for (int i = 0; i < mOptionsList.size(); ++i) {
-                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
-                    mCallbacks.remove(i);
-                    mOptionsList.remove(i);
-                    return true;
-                }
-            }
-            return false;
-        }
     }
 }
diff --git a/media/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java
index b06e598..2943e60 100644
--- a/media/java/android/media/browse/MediaBrowserUtils.java
+++ b/media/java/android/media/browse/MediaBrowserUtils.java
@@ -50,7 +50,7 @@
             startIndex1 = 0;
             endIndex1 = Integer.MAX_VALUE;
         } else {
-            startIndex1 = pageSize1 * (page1 - 1);
+            startIndex1 = pageSize1 * page1;
             endIndex1 = startIndex1 + pageSize1 - 1;
         }
 
@@ -58,7 +58,7 @@
             startIndex2 = 0;
             endIndex2 = Integer.MAX_VALUE;
         } else {
-            startIndex2 = pageSize2 * (page2 - 1);
+            startIndex2 = pageSize2 * page2;
             endIndex2 = startIndex2 + pageSize2 - 1;
         }
 
diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
index c2cc2b9..d5115de 100644
--- a/media/java/android/media/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -28,7 +28,8 @@
     void closeDevice();
 
     // connects the input port pfd to the specified output port
-    void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
+    // Returns the PID of the called process.
+    int connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
 
     MidiDeviceInfo getDeviceInfo();
     void setDeviceInfo(in MidiDeviceInfo deviceInfo);
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index e1990cd..e4588fe 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -19,6 +19,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -181,9 +182,16 @@
         }
          try {
             IBinder token = new Binder();
-            mDeviceServer.connectPorts(token, pfd, outputPortNumber);
-            // close our copy of the file descriptor
-            IoUtils.closeQuietly(pfd);
+            int calleePid = mDeviceServer.connectPorts(token, pfd, outputPortNumber);
+            // If the service is a different Process then it will duplicate the pfd
+            // and we can safely close this one.
+            // But if the service is in the same Process then closing the pfd will
+            // kill the connection. So don't do that.
+            if (calleePid != Process.myPid()) {
+                // close our copy of the file descriptor
+                IoUtils.closeQuietly(pfd);
+            }
+
             return new MidiConnection(token, inputPort);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in connectPorts");
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index 19ff624..f0abf71 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -254,7 +254,7 @@
         }
 
         @Override
-        public void connectPorts(IBinder token, ParcelFileDescriptor pfd,
+        public int connectPorts(IBinder token, ParcelFileDescriptor pfd,
                 int outputPortNumber) {
             MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
             MidiDispatcher dispatcher = mOutputPortDispatchers[outputPortNumber];
@@ -270,6 +270,7 @@
             synchronized (mPortClients) {
                 mPortClients.put(token, client);
             }
+            return Process.myPid(); // for caller to detect same process ID
         }
 
         @Override
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 266b0d9..07c8ae8 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -186,8 +186,7 @@
         try {
             mService.registerListener(mToken, deviceListener);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in registerDeviceListener");
-            return;
+            throw e.rethrowFromSystemServer();
         }
         mDeviceListeners.put(callback, deviceListener);
     }
@@ -203,7 +202,7 @@
             try {
                 mService.unregisterListener(mToken, deviceListener);
             } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException in unregisterDeviceListener");
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -217,8 +216,7 @@
         try {
            return mService.getDevices();
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getDevices");
-            return new MidiDeviceInfo[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -267,7 +265,7 @@
         try {
             mService.openDevice(mToken, deviceInfo, callback);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in openDevice");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -306,7 +304,7 @@
         try {
             mService.openBluetoothDevice(mToken, bluetoothDevice, callback);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in openDevice");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -326,8 +324,7 @@
             }
             return server;
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in createVirtualDevice");
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 }
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index bd0019f..3affee5c0 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -50,4 +50,6 @@
     void setPlaybackToLocal(in AudioAttributes attributes);
     void setPlaybackToRemote(int control, int max);
     void setCurrentVolume(int currentVolume);
+
+    String getCallingPackage();
 }
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 13db00e..622900f 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -592,10 +592,11 @@
         }
 
         /**
-         * Request that the player prepare its playback. Once the preparation is done, the session
-         * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
-         * {@link #play} can be called to start playback. If the preparation is not needed,
-         * {@link #play} can be directly called without this method.
+         * Request that the player prepare its playback. In other words, other sessions can continue
+         * to play during the preparation of this session. This method can be used to speed up the
+         * start of the playback. Once the preparation is done, the session will change its playback
+         * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
+         * start playback.
          */
         public void prepare() {
             try {
@@ -606,10 +607,12 @@
         }
 
         /**
-         * Request that the player prepare playback for a specific media id. Once the preparation is
-         * done, the session will change its playback state to {@link PlaybackState#STATE_PAUSED}.
-         * Afterwards, {@link #play} can be called to start playback. If the preparation is not
-         * needed, {@link #playFromMediaId} can be directly called without this method.
+         * Request that the player prepare playback for a specific media id. In other words, other
+         * sessions can continue to play during the preparation of this session. This method can be
+         * used to speed up the start of the playback. Once the preparation is done, the session
+         * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+         * {@link #play} can be called to start playback. If the preparation is not needed,
+         * {@link #playFromMediaId} can be directly called without this method.
          *
          * @param mediaId The id of the requested media.
          * @param extras Optional extras that can include extra information about the media item
@@ -628,12 +631,13 @@
         }
 
         /**
-         * Request that the player prepare playback for a specific search query.
-         * An empty or null query should be treated as a request to prepare any
-         * music. Once the preparation is done, the session will change its playback state to
-         * {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to start
-         * playback. If the preparation is not needed, {@link #playFromSearch} can be directly
-         * called without this method.
+         * Request that the player prepare playback for a specific search query. An empty or null
+         * query should be treated as a request to prepare any music. In other words, other sessions
+         * can continue to play during the preparation of this session. This method can be used to
+         * speed up the start of the playback. Once the preparation is done, the session will
+         * change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+         * {@link #play} can be called to start playback. If the preparation is not needed,
+         * {@link #playFromSearch} can be directly called without this method.
          *
          * @param query The search query.
          * @param extras Optional extras that can include extra information
@@ -653,11 +657,12 @@
         }
 
         /**
-         * Request that the player prepare playback for a specific {@link Uri}.
-         * Once the preparation is done, the session will change its playback state to
-         * {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to start
-         * playback. If the preparation is not needed, {@link #playFromUri} can be directly
-         * called without this method.
+         * Request that the player prepare playback for a specific {@link Uri}. In other words,
+         * other sessions can continue to play during the preparation of this session. This method
+         * can be used to speed up the start of the playback. Once the preparation is done, the
+         * session will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+         * {@link #play} can be called to start playback. If the preparation is not needed,
+         * {@link #playFromUri} can be directly called without this method.
          *
          * @param uri The URI of the requested media.
          * @param extras Optional extras that can include extra information about the media item
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 3b1b6c8..7f9653d 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -469,7 +469,7 @@
      * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
      * </ul>
      */
-    public void setRatingType(int type) {
+    public void setRatingType(@Rating.Style int type) {
         try {
             mBinder.setRatingType(type);
         } catch (RemoteException e) {
@@ -512,6 +512,22 @@
         }
     }
 
+    /**
+     * Returns the name of the package that sent the last media button, transport control, or
+     * command from controllers and the system. This is only valid while in a request callback, such
+     * as {@link Callback#onPlay}.
+     *
+     * @hide
+     */
+    public String getCallingPackage() {
+        try {
+            return mBinder.getCallingPackage();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Dead object in getCallingPackage.", e);
+        }
+        return null;
+    }
+
     private void dispatchPrepare() {
         postToCallback(CallbackMessageHandler.MSG_PREPARE);
     }
@@ -814,40 +830,45 @@
         }
 
         /**
-         * Override to handle requests to prepare playback. The state of playback should be updated
-         * to {@link PlaybackState#STATE_PAUSED} after the preparation is done. Override
-         * {@link #onPlay} to handle requests for starting playback of prepared content.
+         * Override to handle requests to prepare playback. During the preparation, a session should
+         * not hold audio focus in order to allow other sessions play seamlessly. The state of
+         * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
+         * done.
          */
         public void onPrepare() {
         }
 
         /**
          * Override to handle requests to prepare for playing a specific mediaId that was provided
-         * by your app's {@link MediaBrowserService}. The state of playback should be updated
-         * to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback of
-         * the prepared content should start in the implementation of {@link #onPlay}. Override
-         * {@link #onPlayFromMediaId} to handle requests for starting playback without preparation.
+         * by your app's {@link MediaBrowserService}. During the preparation, a session should not
+         * hold audio focus in order to allow other sessions play seamlessly. The state of playback
+         * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+         * The playback of the prepared content should start in the implementation of
+         * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
+         * playback without preparation.
          */
         public void onPrepareFromMediaId(String mediaId, Bundle extras) {
         }
 
         /**
-         * Override to handle requests to prepare playback from a search query. An
-         * empty query indicates that the app may prepare any music. The
-         * implementation should attempt to make a smart choice about what to
-         * play. The state of playback should be updated to {@link PlaybackState#STATE_PAUSED}
-         * after the preparation is done. The playback of the prepared content should start
-         * in the implementation of {@link #onPlay}. Override {@link #onPlayFromSearch}
-         * to handle requests for starting playback without preparation.
+         * Override to handle requests to prepare playback from a search query. An empty query
+         * indicates that the app may prepare any music. The implementation should attempt to make a
+         * smart choice about what to play. During the preparation, a session should not hold audio
+         * focus in order to allow other sessions play seamlessly. The state of playback should be
+         * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
+         * of the prepared content should start in the implementation of {@link #onPlay}. Override
+         * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
          */
         public void onPrepareFromSearch(String query, Bundle extras) {
         }
 
         /**
          * Override to handle requests to prepare a specific media item represented by a URI.
-         * The state of playback should be updated to {@link PlaybackState#STATE_PAUSED}
-         * after the preparation is done. The playback of the prepared content should start in
-         * the implementation of {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
+         * During the preparation, a session should not hold audio focus in order to allow
+         * other sessions play seamlessly. The state of playback should be updated to
+         * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+         * The playback of the prepared content should start in the implementation of
+         * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
          * for starting playback without preparation.
          */
         public void onPrepareFromUri(Uri uri, Bundle extras) {
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index c61d7ad..95cb8ae 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -154,8 +154,8 @@
                     metadata.getString(MediaMetadata.METADATA_KEY_WRITER));
         }
         if (metadata.containsKey(MediaMetadata.METADATA_KEY_YEAR)) {
-            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR),
-                    metadata.getString(MediaMetadata.METADATA_KEY_YEAR));
+            oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR),
+                    metadata.getLong(MediaMetadata.METADATA_KEY_YEAR));
         }
         return oldMetadata;
     }
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 1485cd7..8283c8b 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -16,6 +16,7 @@
 package android.media.session;
 
 import android.annotation.DrawableRes;
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.media.RemoteControlClient;
 import android.os.Bundle;
@@ -26,6 +27,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Playback state for a {@link MediaSession}. This includes a state like
  * {@link PlaybackState#STATE_PLAYING}, the current playback position,
@@ -35,6 +39,17 @@
     private static final String TAG = "PlaybackState";
 
     /**
+     * @hide
+     */
+    @IntDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
+            ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
+            ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
+            ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
+            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Actions {}
+
+    /**
      * Indicates this session supports the stop command.
      *
      * @see Builder#setActions(long)
@@ -161,6 +176,15 @@
     public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
 
     /**
+     * @hide
+     */
+    @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
+            STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
+            STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    /**
      * 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.
      *
@@ -349,9 +373,11 @@
      * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
      * </ul>
      */
+    @State
     public int getState() {
         return mState;
     }
+
     /**
      * Get the current playback position in ms.
      */
@@ -403,6 +429,7 @@
      * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
      * </ul>
      */
+    @Actions
     public long getActions() {
         return mActions;
     }
@@ -866,7 +893,8 @@
          *            timebase that the position was updated at.
          * @return this
          */
-        public Builder setState(int state, long position, float playbackSpeed, long updateTime) {
+        public Builder setState(@State int state, long position, float playbackSpeed,
+                long updateTime) {
             mState = state;
             mPosition = position;
             mUpdateTime = updateTime;
@@ -907,7 +935,7 @@
          *            normal playback.
          * @return this
          */
-        public Builder setState(int state, long position, float playbackSpeed) {
+        public Builder setState(@State int state, long position, float playbackSpeed) {
             return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
         }
 
@@ -938,7 +966,7 @@
          * @param actions The set of actions allowed.
          * @return this
          */
-        public Builder setActions(long actions) {
+        public Builder setActions(@Actions long actions) {
             mActions = actions;
             return this;
         }
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index 8f022db..df0961b 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -289,8 +289,8 @@
          * @hide
          */
         @Override
-        public void onDetected(SoundTrigger.RecognitionEvent event) {
-            Slog.d(TAG, "onDetected()" + event);
+        public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
+            Slog.d(TAG, "onGenericSoundTriggerDetected()" + event);
             Message.obtain(mHandler,
                     MSG_SOUND_TRIGGER_DETECTED,
                     new EventPayload(event.triggerInData, event.captureAvailable,
@@ -298,6 +298,11 @@
                     .sendToTarget();
         }
 
+        @Override
+        public void onKeyphraseDetected(SoundTrigger.KeyphraseRecognitionEvent event) {
+            Slog.e(TAG, "Ignoring onKeyphraseDetected() called for " + event);
+        }
+
         /**
          * @hide
          */
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 4fd3310..fdd7fc2 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -69,6 +69,7 @@
         try {
             mSoundTriggerService.updateSoundModel(model.getGenericSoundModel());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -81,7 +82,7 @@
             return new Model(mSoundTriggerService.getSoundModel(
                     new ParcelUuid(soundModelId)));
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -92,6 +93,7 @@
         try {
             mSoundTriggerService.deleteSoundModel(new ParcelUuid(soundModelId));
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index 5dd4e85..72f8b57 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -45,7 +45,7 @@
     void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
 
     // For the recording session
-    void onTuned(int seq);
+    void onTuned(int seq, in Uri channelUri);
     void onRecordingStopped(in Uri recordedProgramUri, int seq);
     void onError(int error, int seq);
 }
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index 60d6f0d..af76f90 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -42,7 +42,7 @@
     void onTimeShiftCurrentPositionChanged(long timeMs);
 
     // For the recording session
-    void onTuned();
+    void onTuned(in Uri channelUri);
     void onRecordingStopped(in Uri recordedProgramUri);
     void onError(int error);
 }
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 1c11842..e8c50e3 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
@@ -25,6 +26,7 @@
 import android.net.Uri;
 import android.os.IBinder;
 import android.provider.BaseColumns;
+import android.text.TextUtils;
 import android.util.ArraySet;
 
 import java.util.ArrayList;
@@ -53,6 +55,13 @@
     /** The authority for the TV provider. */
     public static final String AUTHORITY = "android.media.tv";
 
+    /**
+     * Permission to read TV listings. This is required to read all the TV channel and program
+     * information available on the system.
+     * @hide
+     */
+    public static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
+
     private static final String PATH_CHANNEL = "channel";
     private static final String PATH_PROGRAM = "program";
     private static final String PATH_RECORDED_PROGRAM = "recorded_program";
@@ -304,33 +313,28 @@
     }
 
     /**
-     * Returns true, if {@code uri} is a channel URI.
-     * @hide
+     * Returns {@code true}, if {@code uri} is a channel URI.
      */
     public static final boolean isChannelUri(Uri uri) {
         return isChannelUriForTunerInput(uri) || isChannelUriForPassthroughInput(uri);
     }
 
     /**
-     * Returns true, if {@code uri} is a channel URI for a tuner input.
-     * @hide
+     * Returns {@code true}, if {@code uri} is a channel URI for a tuner input.
      */
     public static final boolean isChannelUriForTunerInput(Uri uri) {
         return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
     }
 
     /**
-     * Returns true, if {@code uri} is a channel URI for a passthrough input.
-     * @hide
+     * Returns {@code true}, if {@code uri} is a channel URI for a pass-through input.
      */
-    @SystemApi
     public static final boolean isChannelUriForPassthroughInput(Uri uri) {
         return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PASSTHROUGH);
     }
 
     /**
-     * Returns true, if {@code uri} is a program URI.
-     * @hide
+     * Returns {@code true}, if {@code uri} is a program URI.
      */
     public static final boolean isProgramUri(Uri uri) {
         return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PROGRAM);
@@ -571,16 +575,11 @@
         /**
          * 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 original_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 {{@code COLUMN_ORIGINAL_NETWORK_ID},
-         * {@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}} for its channels.
+         * <p>It is used to identify the originating delivery system, if applicable. Use the same
+         * coding for {@code original_network_id} for ETSI EN 300 468/TR 101 211 and ARIB STD-B10.
          *
-         * <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>This is a required field only if the underlying broadcast standard defines the same
+         * name field. Otherwise, leave empty.
          *
          * <p>Type: INTEGER
          */
@@ -589,13 +588,13 @@
         /**
          * 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
+         * <p>It 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.
+         * the MPEG Transport Stream.
          *
-         * <p>This is a required field if the current channel is transmitted via the MPEG Transport
-         * Stream.
+         * <p>This is a required field only if the current channel is transmitted via the MPEG
+         * Transport Stream. Leave empty otherwise.
          *
          * <p>Type: INTEGER
          */
@@ -604,15 +603,13 @@
         /**
          * 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>It is used to identify the current service, or channel from any other services within
+         * a given Transport Stream, if applicable. Use the same coding for {@code service_id} in
+         * ETSI EN 300 468 and ARIB STD-B10 or {@code program_number} in ISO/IEC 13818-1.
          *
-         * <p>This is a required field if the current channel is transmitted via the MPEG Transport
-         * Stream.
+         * <p>This is a required field only if the underlying broadcast standard defines the same
+         * name field, or the current channel is transmitted via the MPEG Transport Stream. Leave
+         * empty otherwise.
          *
          * <p>Type: INTEGER
          */
@@ -962,8 +959,9 @@
          * The title of this TV program.
          *
          * <p>If this program is an episodic TV show, it is recommended that the title is the series
-         * title and its related fields ({@link #COLUMN_SEASON_NUMBER},
-         * {@link #COLUMN_EPISODE_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+         * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
+         * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
          *
          * <p>Type: TEXT
          */
@@ -975,19 +973,65 @@
          * <p>Can be empty.
          *
          * <p>Type: INTEGER
+         *
+         * @deprecated Use {@link #COLUMN_SEASON_DISPLAY_NUMBER} instead.
          */
+        @Deprecated
         public static final String COLUMN_SEASON_NUMBER = "season_number";
 
         /**
+         * The season display number of this TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+
+        /**
+         * The title of the season for this TV program for episodic TV shows.
+         *
+         * <p>This is an optional field supplied only when the season has a special title
+         * (e.g. The Final Season). If provided, the applications should display it instead of
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
+         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+         * "Season The Final Season"). When displaying multiple programs, the order should be based
+         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_TITLE = "season_title";
+
+        /**
          * The episode number of this TV program for episodic TV shows.
          *
          * <p>Can be empty.
          *
          * <p>Type: INTEGER
+         *
+         * @deprecated Use {@link #COLUMN_EPISODE_DISPLAY_NUMBER} instead.
          */
+        @Deprecated
         public static final String COLUMN_EPISODE_NUMBER = "episode_number";
 
         /**
+         * The episode display number of this TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+
+        /**
          * The episode title of this TV program for episodic TV shows.
          *
          * <p>Can be empty.
@@ -1325,7 +1369,11 @@
              * @return an encoded genre string that can be inserted into the
              *         {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
              */
-            public static String encode(String... genres) {
+            public static String encode(@NonNull String... genres) {
+                if (genres == null) {
+                    // MNC and before will throw a NPE.
+                    return null;
+                }
                 StringBuilder sb = new StringBuilder();
                 String separator = "";
                 for (String genre : genres) {
@@ -1360,8 +1408,9 @@
              *            {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
              * @return genre strings.
              */
-            public static String[] decode(String genres) {
-                if (genres.isEmpty()) {
+            public static String[] decode(@NonNull String genres) {
+                if (TextUtils.isEmpty(genres)) {
+                    // MNC and before will throw a NPE for {@code null} genres.
                     return EMPTY_STRING_ARRAY;
                 }
                 if (genres.indexOf(COMMA) == -1 && genres.indexOf(DOUBLE_QUOTE) == -1) {
@@ -1458,8 +1507,9 @@
          * The title of this recorded TV program.
          *
          * <p>If this recorded program is an episodic TV show, it is recommended that the title is
-         * the series title and its related fields ({@link #COLUMN_SEASON_NUMBER},
-         * {@link #COLUMN_EPISODE_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+         * the series title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_EPISODE_DISPLAY_NUMBER},
+         * and {@link #COLUMN_EPISODE_TITLE}) are filled in.
          *
          * <p>Type: TEXT
          * @see Programs#COLUMN_TITLE
@@ -1467,24 +1517,46 @@
         public static final String COLUMN_TITLE = Programs.COLUMN_TITLE;
 
         /**
-         * The season number of this recorded TV program for episodic TV shows.
+         * The season display number of this recorded TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
          *
          * <p>Can be empty.
          *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_SEASON_NUMBER
+         * <p>Type: TEXT
          */
-        public static final String COLUMN_SEASON_NUMBER = Programs.COLUMN_SEASON_NUMBER;
+        public static final String COLUMN_SEASON_DISPLAY_NUMBER =
+                Programs.COLUMN_SEASON_DISPLAY_NUMBER;
 
         /**
-         * The episode number of this recorded TV program for episodic TV shows.
+         * The title of the season for this recorded TV program for episodic TV shows.
+         *
+         * <p>This is an optional field supplied only when the season has a special title
+         * (e.g. The Final Season). If provided, the applications should display it instead of
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER} without alterations.
+         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+         * "Season The Final Season"). When displaying multiple programs, the order should be based
+         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
          *
          * <p>Can be empty.
          *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_EPISODE_NUMBER
+         * <p>Type: TEXT
          */
-        public static final String COLUMN_EPISODE_NUMBER = Programs.COLUMN_EPISODE_NUMBER;
+        public static final String COLUMN_SEASON_TITLE = Programs.COLUMN_SEASON_TITLE;
+
+        /**
+         * The episode display number of this recorded TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_EPISODE_DISPLAY_NUMBER =
+                Programs.COLUMN_EPISODE_DISPLAY_NUMBER;
 
         /**
          * The episode title of this recorded TV program for episodic TV shows.
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index f0a9426..03dc699 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -105,31 +105,38 @@
     public static final int TYPE_DISPLAY_PORT = 1008;
 
     /**
-     * The ID of the TV input to provide to the setup activity and settings activity.
+     * Used as a String extra field in setup intents created by {@link #createSetupIntent()} to
+     * supply the ID of a specific TV input to set up.
      */
     public static final String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID";
 
     private final ResolveInfo mService;
+
     private final String mId;
-    private final String mParentId;
     private final int mType;
-    private final int mTunerCount;
-    private final boolean mCanRecord;
     private final boolean mIsHardwareInput;
-    private final Bundle mExtras;
+
+    // TODO: Remove mIconUri when createTvInputInfo() is removed.
+    private Uri mIconUri;
+
+    private final CharSequence mLabel;
+    private final int mLabelResId;
+    private final Icon mIcon;
+    private final Icon mIconStandby;
+    private final Icon mIconDisconnected;
 
     // Attributes from XML meta data.
-    private String mSetupActivity;
-    private String mSettingsActivity;
+    private final String mSetupActivity;
+    private final String mSettingsActivity;
+    private final boolean mCanRecord;
+    private final int mTunerCount;
 
-    private HdmiDeviceInfo mHdmiDeviceInfo;
-    private int mLabelResId;
-    // TODO: Remove when createTvInputInfo() is removed.
-    private String mLabel;
-    private Icon mIcon;
-    // TODO: Remove when createTvInputInfo() is removed.
-    private Uri mIconUri;
-    private boolean mIsConnectedToHdmiSwitch;
+    // Attributes specific to HDMI
+    private final HdmiDeviceInfo mHdmiDeviceInfo;
+    private final boolean mIsConnectedToHdmiSwitch;
+    private final String mParentId;
+
+    private final Bundle mExtras;
 
     /**
      * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
@@ -154,8 +161,8 @@
         TvInputInfo info = new TvInputInfo.Builder(context, service)
                 .setHdmiDeviceInfo(hdmiDeviceInfo)
                 .setParentId(parentId)
+                .setLabel(label)
                 .build();
-        info.mLabel = label;
         info.mIconUri = iconUri;
         return info;
     }
@@ -208,8 +215,8 @@
                     throws XmlPullParserException, IOException {
         TvInputInfo info = new TvInputInfo.Builder(context, service)
                 .setTvInputHardwareInfo(hardwareInfo)
+                .setLabel(label)
                 .build();
-        info.mLabel = label;
         info.mIconUri = iconUri;
         return info;
     }
@@ -239,31 +246,27 @@
                 .build();
     }
 
-    /**
-     * Constructor.
-     *
-     * @param service The ResolveInfo returned from the package manager about this TV input service.
-     * @param id ID of this TV input. Should be generated via generateInputId*().
-     * @param parentId ID of this TV input's parent input. {@code null} if none exists.
-     * @param type The type of this TV input service.
-     * @param isHardwareInput {@code true} if this TV input represents a hardware device.
-     *            {@code false} otherwise.
-     * @param isConnectedToHdmiSwitch Whether a CEC device for this TV input is connected to an HDMI
-     *            switch, i.e., the device isn't directly connected to a HDMI port.
-     * @param tunerCount The number of tuners this TV input has.
-     * @param canRecord Whether this TV input can record TV programs.
-     */
-    private TvInputInfo(ResolveInfo service, String id, String parentId, int type,
-            boolean isHardwareInput, boolean isConnectedToHdmiSwitch, int tunerCount,
-            boolean canRecord, Bundle extras) {
+    private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
+            CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
+            String setupActivity, String settingsActivity, boolean canRecord, int tunerCount,
+            HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId,
+            Bundle extras) {
         mService = service;
         mId = id;
-        mParentId = parentId;
         mType = type;
         mIsHardwareInput = isHardwareInput;
-        mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
-        mTunerCount = tunerCount;
+        mLabel = label;
+        mLabelResId = labelResId;
+        mIcon = icon;
+        mIconStandby = iconStandby;
+        mIconDisconnected = iconDisconnected;
+        mSetupActivity = setupActivity;
+        mSettingsActivity = settingsActivity;
         mCanRecord = canRecord;
+        mTunerCount = tunerCount;
+        mHdmiDeviceInfo = hdmiDeviceInfo;
+        mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
+        mParentId = parentId;
         mExtras = extras;
     }
 
@@ -347,12 +350,12 @@
     /**
      * Returns the number of tuners this TV input has.
      *
-     * <p>This method is valid only for the input of type {@link #TYPE_TUNER}.
+     * <p>This method is valid only for inputs of type {@link #TYPE_TUNER}. For inputs of other
+     * types, it returns 0.
      *
      * <p>Tuners correspond to physical/logical resources that allow reception of TV signal. Having
      * <i>N</i> tuners means that the TV input is capable of receiving <i>N</i> different channels
      * concurrently.
-     *
      */
     public int getTunerCount() {
         return mTunerCount;
@@ -478,6 +481,36 @@
         return loadServiceIcon(context);
     }
 
+    /**
+     * Loads the user-displayed icon for this TV input per input state.
+     *
+     * @param context Supplies a {@link Context} used to load the icon.
+     * @param state The input state. Should be one of the followings.
+     *              {@link TvInputManager#INPUT_STATE_CONNECTED},
+     *              {@link TvInputManager#INPUT_STATE_CONNECTED_STANDBY} and
+     *              {@link TvInputManager#INPUT_STATE_DISCONNECTED}.
+     * @return a Drawable containing the TV input's icon for the given state or {@code null} if such
+     *         an icon is not defined.
+     * @hide
+     */
+    @SystemApi
+    public Drawable loadIcon(@NonNull Context context, int state) {
+        if (state == TvInputManager.INPUT_STATE_CONNECTED) {
+            return loadIcon(context);
+        } else if (state == TvInputManager.INPUT_STATE_CONNECTED_STANDBY) {
+            if (mIconStandby != null) {
+                return mIconStandby.loadDrawable(context);
+            }
+        } else if (state == TvInputManager.INPUT_STATE_DISCONNECTED) {
+            if (mIconDisconnected != null) {
+                return mIconDisconnected.loadDrawable(context);
+            }
+        } else {
+            throw new IllegalArgumentException("Unknown state: " + state);
+        }
+        return null;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -499,21 +532,23 @@
         }
 
         TvInputInfo obj = (TvInputInfo) o;
-        return TextUtils.equals(mId, obj.mId)
-                && TextUtils.equals(mParentId, obj.mParentId)
-                && Objects.equals(mService, obj.mService)
-                && TextUtils.equals(mSetupActivity, obj.mSetupActivity)
-                && TextUtils.equals(mSettingsActivity, obj.mSettingsActivity)
+        return Objects.equals(mService, obj.mService)
+                && TextUtils.equals(mId, obj.mId)
                 && mType == obj.mType
-                && mTunerCount == obj.mTunerCount
-                && mCanRecord == obj.mCanRecord
                 && mIsHardwareInput == obj.mIsHardwareInput
-                && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
-                && Objects.equals(mIcon, obj.mIcon)
+                && TextUtils.equals(mLabel, obj.mLabel)
                 && Objects.equals(mIconUri, obj.mIconUri)
                 && mLabelResId == obj.mLabelResId
-                && TextUtils.equals(mLabel, obj.mLabel)
+                && Objects.equals(mIcon, obj.mIcon)
+                && Objects.equals(mIconStandby, obj.mIconStandby)
+                && Objects.equals(mIconDisconnected, obj.mIconDisconnected)
+                && TextUtils.equals(mSetupActivity, obj.mSetupActivity)
+                && TextUtils.equals(mSettingsActivity, obj.mSettingsActivity)
+                && mCanRecord == obj.mCanRecord
+                && mTunerCount == obj.mTunerCount
+                && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
                 && mIsConnectedToHdmiSwitch == obj.mIsConnectedToHdmiSwitch
+                && TextUtils.equals(mParentId, obj.mParentId)
                 && Objects.equals(mExtras, obj.mExtras);
     }
 
@@ -532,21 +567,23 @@
      */
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeString(mId);
-        dest.writeString(mParentId);
         mService.writeToParcel(dest, flags);
-        dest.writeString(mSetupActivity);
-        dest.writeString(mSettingsActivity);
+        dest.writeString(mId);
         dest.writeInt(mType);
-        dest.writeInt(mTunerCount);
-        dest.writeByte(mCanRecord ? (byte) 1 : 0);
         dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
-        dest.writeParcelable(mHdmiDeviceInfo, flags);
-        dest.writeParcelable(mIcon, flags);
+        TextUtils.writeToParcel(mLabel, dest, flags);
         dest.writeParcelable(mIconUri, flags);
         dest.writeInt(mLabelResId);
-        dest.writeString(mLabel);
+        dest.writeParcelable(mIcon, flags);
+        dest.writeParcelable(mIconStandby, flags);
+        dest.writeParcelable(mIconDisconnected, flags);
+        dest.writeString(mSetupActivity);
+        dest.writeString(mSettingsActivity);
+        dest.writeByte(mCanRecord ? (byte) 1 : 0);
+        dest.writeInt(mTunerCount);
+        dest.writeParcelable(mHdmiDeviceInfo, flags);
         dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
+        dest.writeString(mParentId);
         dest.writeBundle(mExtras);
     }
 
@@ -572,21 +609,23 @@
     };
 
     private TvInputInfo(Parcel in) {
-        mId = in.readString();
-        mParentId = in.readString();
         mService = ResolveInfo.CREATOR.createFromParcel(in);
-        mSetupActivity = in.readString();
-        mSettingsActivity = in.readString();
+        mId = in.readString();
         mType = in.readInt();
-        mTunerCount = in.readInt();
-        mCanRecord = in.readByte() == 1;
         mIsHardwareInput = in.readByte() == 1;
-        mHdmiDeviceInfo = in.readParcelable(null);
-        mIcon = in.readParcelable(null);
+        mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mIconUri = in.readParcelable(null);
         mLabelResId = in.readInt();
-        mLabel = in.readString();
+        mIcon = in.readParcelable(null);
+        mIconStandby = in.readParcelable(null);
+        mIconDisconnected = in.readParcelable(null);
+        mSetupActivity = in.readString();
+        mSettingsActivity = in.readString();
+        mCanRecord = in.readByte() == 1;
+        mTunerCount = in.readInt();
+        mHdmiDeviceInfo = in.readParcelable(null);
         mIsConnectedToHdmiSwitch = in.readByte() == 1;
+        mParentId = in.readString();
         mExtras = in.readBundle();
     }
 
@@ -622,24 +661,30 @@
 
         private final Context mContext;
         private final ResolveInfo mResolveInfo;
-        private Icon mIcon;
+        private CharSequence mLabel;
         private int mLabelResId;
-        private int mTunerCount = 1;
-        private boolean mCanRecord;
+        private Icon mIcon;
+        private Icon mIconStandby;
+        private Icon mIconDisconnected;
+        private String mSetupActivity;
+        private String mSettingsActivity;
+        private Boolean mCanRecord;
+        private Integer mTunerCount;
+        private TvInputHardwareInfo mTvInputHardwareInfo;
         private HdmiDeviceInfo mHdmiDeviceInfo;
         private String mParentId;
-        private TvInputHardwareInfo mTvInputHardwareInfo;
         private Bundle mExtras;
 
         /**
          * Constructs a new builder for {@link TvInputInfo}.
          *
          * @param context A Context of the application package implementing this class.
-         * @param cls The component class that is to be used for the {@link TvInputService}.
+         * @param component The name of the application component to be used for the
+         *            {@link TvInputService}.
          */
-        public Builder(Context context, Class<?> cls) {
+        public Builder(Context context, ComponentName component) {
             mContext = context;
-            Intent intent = new Intent(TvInputService.SERVICE_INTERFACE).setClass(context, cls);
+            Intent intent = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
             mResolveInfo = context.getPackageManager().resolveService(intent,
                     PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
         }
@@ -676,6 +721,47 @@
         }
 
         /**
+         * Sets the icon for a given input state.
+         *
+         * @param icon The icon that represents this TV input for the given state.
+         * @param state The input state. Should be one of the followings.
+         *              {@link TvInputManager#INPUT_STATE_CONNECTED},
+         *              {@link TvInputManager#INPUT_STATE_CONNECTED_STANDBY} and
+         *              {@link TvInputManager#INPUT_STATE_DISCONNECTED}.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setIcon(Icon icon, int state) {
+            if (state == TvInputManager.INPUT_STATE_CONNECTED) {
+                this.mIcon = icon;
+            } else if (state == TvInputManager.INPUT_STATE_CONNECTED_STANDBY) {
+                this.mIconStandby = icon;
+            } else if (state == TvInputManager.INPUT_STATE_DISCONNECTED) {
+                this.mIconDisconnected = icon;
+            } else {
+                throw new IllegalArgumentException("Unknown state: " + state);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the label.
+         *
+         * @param label The text to be used as label.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setLabel(CharSequence label) {
+            if (mLabelResId != 0) {
+                throw new IllegalStateException("Resource ID for label is already set.");
+            }
+            this.mLabel = label;
+            return this;
+        }
+
+        /**
          * Sets the label.
          *
          * @param resId The resource ID of the text to use.
@@ -684,6 +770,9 @@
          */
         @SystemApi
         public Builder setLabel(int resId) {
+            if (mLabel != null) {
+                throw new IllegalStateException("Label text is already set.");
+            }
             this.mLabelResId = resId;
             return this;
         }
@@ -791,20 +880,19 @@
                 type = TYPE_HDMI;
                 isHardwareInput = true;
                 isConnectedToHdmiSwitch = (mHdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
-                mTunerCount = 0;
             } else if (mTvInputHardwareInfo != null) {
                 id = generateInputId(componentName, mTvInputHardwareInfo);
                 type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER);
                 isHardwareInput = true;
-                mTunerCount = 0;
             } else {
                 id = generateInputId(componentName);
                 type = TYPE_TUNER;
             }
-
-            TvInputInfo info = new TvInputInfo(mResolveInfo, id, mParentId, type, isHardwareInput,
-                    isConnectedToHdmiSwitch, mTunerCount, mCanRecord, mExtras);
-            return parseServiceMetadata(type, info);
+            parseServiceMetadata(type);
+            return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
+                    mIcon, mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
+                    mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
+                    mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras);
         }
 
         private static String generateInputId(ComponentName name) {
@@ -826,7 +914,7 @@
                     + tvInputHardwareInfo.getDeviceId();
         }
 
-        private TvInputInfo parseServiceMetadata(int inputType, TvInputInfo info)
+        private void parseServiceMetadata(int inputType)
                 throws XmlPullParserException, IOException {
             ServiceInfo si = mResolveInfo.serviceInfo;
             PackageManager pm = mContext.getPackageManager();
@@ -853,26 +941,32 @@
 
                 TypedArray sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.TvInputService);
-                info.mSetupActivity = sa.getString(
+                mSetupActivity = sa.getString(
                         com.android.internal.R.styleable.TvInputService_setupActivity);
                 if (DEBUG) {
-                    Log.d(TAG, "Setup activity loaded. [" + info.mSetupActivity + "] for "
-                            + si.name);
+                    Log.d(TAG, "Setup activity loaded. [" + mSetupActivity + "] for " + si.name);
                 }
-                if (inputType == TYPE_TUNER && TextUtils.isEmpty(info.mSetupActivity)) {
+                if (inputType == TYPE_TUNER && TextUtils.isEmpty(mSetupActivity)) {
                     throw new XmlPullParserException("Setup activity not found in " + si.name);
                 }
-                info.mSettingsActivity = sa.getString(
+                mSettingsActivity = sa.getString(
                         com.android.internal.R.styleable.TvInputService_settingsActivity);
                 if (DEBUG) {
-                    Log.d(TAG, "Settings activity loaded. [" + info.mSettingsActivity + "] for "
+                    Log.d(TAG, "Settings activity loaded. [" + mSettingsActivity + "] for "
                             + si.name);
                 }
+                if (mCanRecord == null) {
+                    mCanRecord = sa.getBoolean(
+                            com.android.internal.R.styleable.TvInputService_canRecord, false);
+                }
+                if (mTunerCount == null && inputType == TYPE_TUNER) {
+                    mTunerCount = sa.getInt(
+                            com.android.internal.R.styleable.TvInputService_tunerCount, 1);
+                }
                 sa.recycle();
             } catch (NameNotFoundException e) {
                 throw new XmlPullParserException("Unable to create context for: " + si.packageName);
             }
-            return info;
         }
     }
 
@@ -966,6 +1060,15 @@
             }
             Settings.Secure.putStringForUser(context.getContentResolver(),
                     Settings.Secure.TV_INPUT_HIDDEN_INPUTS, builder.toString(), userId);
+
+            // Notify of the TvInputInfo changes.
+            TvInputManager tm = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
+            for (String inputId : hiddenInputIds) {
+                TvInputInfo info = tm.getTvInputInfo(inputId);
+                if (info != null) {
+                    tm.updateTvInputInfo(info);
+                }
+            }
         }
 
         /**
@@ -996,6 +1099,15 @@
             }
             Settings.Secure.putStringForUser(context.getContentResolver(),
                     Settings.Secure.TV_INPUT_CUSTOM_LABELS, builder.toString(), userId);
+
+            // Notify of the TvInputInfo changes.
+            TvInputManager tm = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
+            for (String inputId : customLabels.keySet()) {
+                TvInputInfo info = tm.getTvInputInfo(inputId);
+                if (info != null) {
+                    tm.updateTvInputInfo(info);
+                }
+            }
         }
 
         private static void ensureValidField(String value) {
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 51aae90..b4536b1 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.graphics.Rect;
 import android.media.PlaybackParams;
@@ -55,7 +56,26 @@
 
 /**
  * Central system API to the overall TV input framework (TIF) architecture, which arbitrates
- * interaction between applications and the selected TV inputs.
+ * interaction between applications and the selected TV inputs. You can retrieve an instance of
+ * this interface with {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.TV_INPUT_SERVICE)}.
+ *
+ * <p>There are three primary parties involved in the TV input framework (TIF) architecture:
+ *
+ * <ul>
+ * <li>The <strong>TV input manager</strong> as expressed by this class is the central point of the
+ * system that manages interaction between all other parts. It is expressed as the client-side API
+ * here which exists in each application context and communicates with a global system service that
+ * manages the interaction across all processes.
+ * <li>A <strong>TV input</strong> implemented by {@link TvInputService} represents an input source
+ * of TV, which can be a pass-through input such as HDMI, or a tuner input which provides broadcast
+ * TV programs. The system binds to the TV input per application’s request.
+ * on implementing TV inputs.
+ * <li><strong>Applications</strong> talk to the TV input manager to list TV inputs and check their
+ * status. Once an application find the input to use, it uses {@link TvView} or
+ * {@link TvRecordingClient} for further interaction such as watching and recording broadcast TV
+ * programs.
+ * </ul>
  */
 public final class TvInputManager {
     private static final String TAG = "TvInputManager";
@@ -113,6 +133,13 @@
      */
     public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = VIDEO_UNAVAILABLE_REASON_END;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
+            VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
+            VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
+    public @interface VideoUnavailableReason {}
+
     /**
      * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
      * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Unknown status. Also
@@ -142,6 +169,12 @@
      */
     public static final int TIME_SHIFT_STATUS_AVAILABLE = 3;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
+            TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
+    public @interface TimeShiftStatus {}
+
     /**
      * Value returned by {@link TvInputService.Session#onTimeShiftGetCurrentPosition()} and
      * {@link TvInputService.Session#onTimeShiftGetStartPosition()} when time shifting has not
@@ -207,6 +240,11 @@
      */
     public static final int INPUT_STATE_DISCONNECTED = 2;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
+    public @interface InputState {}
+
     /**
      * Broadcast intent action when the user blocked content ratings change. For use with the
      * {@link #isRatingBlocked}.
@@ -266,6 +304,14 @@
     public static final String META_DATA_CONTENT_RATING_SYSTEMS =
             "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
 
+    /**
+     * Activity action to set up channel sources i.e.&nbsp;TV inputs of type
+     * {@link TvInputInfo#TYPE_TUNER}. When invoked, the system will display an appropriate UI for
+     * the user to initiate the individual setup flow provided by
+     * {@link android.R.attr#setupActivity} of each TV input service.
+     */
+    public static final String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
+
     private final ITvInputManager mService;
 
     private final Object mLock = new Object();
@@ -293,7 +339,6 @@
      * Interface used to receive the created session.
      * @hide
      */
-    @SystemApi
     public abstract static class SessionCallback {
         /**
          * This is called after {@link TvInputManager#createSession} has been processed.
@@ -409,9 +454,7 @@
          * @param top Top position.
          * @param right Right position.
          * @param bottom Bottom position.
-         * @hide
          */
-        @SystemApi
         public void onLayoutSurface(Session session, int left, int top, int right, int bottom) {
         }
 
@@ -421,9 +464,7 @@
          * @param session A {@link TvInputManager.Session} associated with this callback
          * @param eventType The type of the event.
          * @param eventArgs Optional arguments of the event.
-         * @hide
          */
-        @SystemApi
         public void onSessionEvent(Session session, String eventType, Bundle eventArgs) {
         }
 
@@ -470,8 +511,10 @@
         /**
          * This is called when the recording session has been tuned to the given channel and is
          * ready to start recording.
+         *
+         * @param channelUri The URI of a channel.
          */
-        void onTuned(Session session) {
+        void onTuned(Session session, Uri channelUri) {
         }
 
         // For the recording session only
@@ -645,11 +688,11 @@
         }
 
         // For the recording session only
-        void postTuned() {
+        void postTuned(final Uri channelUri) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mSessionCallback.onTuned(mSession);
+                    mSessionCallback.onTuned(mSession, channelUri);
                 }
             });
         }
@@ -690,7 +733,7 @@
          * <li>{@link TvInputManager#INPUT_STATE_DISCONNECTED}
          * </ul>
          */
-        public void onInputStateChanged(String inputId, int state) {
+        public void onInputStateChanged(String inputId, @InputState int state) {
         }
 
         /**
@@ -731,9 +774,7 @@
          *
          * <p>Because the system automatically creates a <code>TvInputInfo</code> object for each TV
          * input based on the information collected from the <code>AndroidManifest.xml</code>, this
-         * method is only called back when such information has changed dynamically or when the TV
-         * input service implementation wants to pass additional information that is not specified
-         * by the manifest file, such as ability to record and tuner count.
+         * method is only called back when such information has changed dynamically.
          *
          * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
          */
@@ -802,11 +843,21 @@
 
     /**
      * Interface used to receive events from Hardware objects.
+     *
      * @hide
      */
     @SystemApi
     public abstract static class HardwareCallback {
+        /**
+         * This is called when {@link Hardware} is no longer available for the client.
+         */
         public abstract void onReleased();
+
+        /**
+         * This is called when the underlying {@link TvStreamConfig} has been changed.
+         *
+         * @param configs The new {@link TvStreamConfig}s.
+         */
         public abstract void onStreamConfigChanged(TvStreamConfig[] configs);
     }
 
@@ -1007,14 +1058,14 @@
             }
 
             @Override
-            public void onTuned(int seq) {
+            public void onTuned(int seq, Uri channelUri) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
                     if (record == null) {
                         Log.e(TAG, "Callback not found for seq " + seq);
                         return;
                     }
-                    record.postTuned();
+                    record.postTuned(channelUri);
                 }
             }
 
@@ -1103,7 +1154,7 @@
                 }
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "TvInputManager initialization failed", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1116,7 +1167,7 @@
         try {
             return mService.getTvInputList(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1132,7 +1183,7 @@
         try {
             return mService.getTvInputInfo(inputId, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1149,7 +1200,7 @@
         try {
             mService.updateTvInputInfo(inputInfo, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException("Error trying to update " + inputInfo, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1166,6 +1217,7 @@
      * @param inputId The ID of the TV input.
      * @throws IllegalArgumentException if the argument is {@code null}.
      */
+    @InputState
     public int getInputState(@NonNull String inputId) {
         Preconditions.checkNotNull(inputId);
         synchronized (mLock) {
@@ -1220,7 +1272,7 @@
         try {
             return mService.isParentalControlsEnabled(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1233,11 +1285,12 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
     public void setParentalControlsEnabled(boolean enabled) {
         try {
             mService.setParentalControlsEnabled(enabled, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1252,7 +1305,7 @@
         try {
             return mService.isRatingBlocked(rating.flattenToString(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1271,7 +1324,7 @@
             }
             return ratings;
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1284,12 +1337,13 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
     public void addBlockedRating(@NonNull TvContentRating rating) {
         Preconditions.checkNotNull(rating);
         try {
             mService.addBlockedRating(rating.flattenToString(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1302,12 +1356,13 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
     public void removeBlockedRating(@NonNull TvContentRating rating) {
         Preconditions.checkNotNull(rating);
         try {
             mService.removeBlockedRating(rating.flattenToString(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1320,7 +1375,7 @@
         try {
             return mService.getTvContentRatingSystemList(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1335,7 +1390,6 @@
      * @param handler A {@link Handler} that the session creation will be delivered to.
      * @hide
      */
-    @SystemApi
     public void createSession(@NonNull String inputId, @NonNull final SessionCallback callback,
             @NonNull Handler handler) {
         createSessionInternal(inputId, false, callback, handler);
@@ -1352,7 +1406,6 @@
      * @param handler A {@link Handler} that the session creation will be delivered to.
      * @hide
      */
-    @SystemApi
     public void createRecordingSession(@NonNull String inputId,
             @NonNull final SessionCallback callback, @NonNull Handler handler) {
         createSessionInternal(inputId, true, callback, handler);
@@ -1370,7 +1423,7 @@
             try {
                 mService.createSession(mClient, inputId, isRecordingSession, seq, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1394,7 +1447,7 @@
         try {
             return mService.getAvailableTvStreamConfigList(inputId, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1412,7 +1465,7 @@
         try {
             return mService.captureFrame(inputId, surface, config, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1426,7 +1479,7 @@
         try {
             return mService.isSingleSessionActive(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1436,26 +1489,51 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
     public List<TvInputHardwareInfo> getHardwareList() {
         try {
             return mService.getHardwareList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Returns acquired TvInputManager.Hardware object for given deviceId.
+     * Acquires {@link Hardware} object for the given device ID.
      *
-     * If there are other Hardware object acquired for the same deviceId, calling this method will
-     * preempt the previously acquired object and report {@link HardwareCallback#onReleased} to the
-     * old object.
+     * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+     * acquired Hardware.
+     *
+     * @param deviceId The device ID to acquire Hardware for.
+     * @param callback A callback to receive updates on Hardware.
+     * @param info The TV input which will use the acquired Hardware.
+     * @return Hardware on success, {@code null} otherwise.
+     *
+     * @removed
+     */
+    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
+    public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
+            TvInputInfo info) {
+        return acquireTvInputHardware(deviceId, info, callback);
+    }
+
+    /**
+     * Acquires {@link Hardware} object for the given device ID.
+     *
+     * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+     * acquired Hardware.
+     *
+     * @param deviceId The device ID to acquire Hardware for.
+     * @param callback A callback to receive updates on Hardware.
+     * @param info The TV input which will use the acquired Hardware.
+     * @return Hardware on success, {@code null} otherwise.
      *
      * @hide
      */
     @SystemApi
-    public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
-            TvInputInfo info) {
+    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
+    public Hardware acquireTvInputHardware(int deviceId, TvInputInfo info,
+            final HardwareCallback callback) {
         try {
             return new Hardware(
                     mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
@@ -1470,21 +1548,25 @@
                 }
             }, info, mUserId));
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
      * Releases previously acquired hardware object.
      *
+     * @param deviceId The device ID this Hardware was acquired for
+     * @param hardware Hardware to release.
+     *
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
     public void releaseTvInputHardware(int deviceId, Hardware hardware) {
         try {
             mService.releaseTvInputHardware(deviceId, hardware.getInterface(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1498,7 +1580,7 @@
         try {
             return mService.getDvbDeviceList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1521,7 +1603,7 @@
             }
             return mService.openDvbDevice(info, device);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1529,7 +1611,6 @@
      * The Session provides the per-session functionality of TV inputs.
      * @hide
      */
-    @SystemApi
     public static final class Session {
         static final int DISPATCH_IN_PROGRESS = -1;
         static final int DISPATCH_NOT_HANDLED = 0;
@@ -1592,7 +1673,7 @@
             try {
                 mService.releaseSession(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
 
             releaseInternal();
@@ -1612,7 +1693,7 @@
             try {
                 mService.setMainSession(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1630,7 +1711,7 @@
             try {
                 mService.setSurface(mToken, surface, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1641,9 +1722,7 @@
          * @param format The new PixelFormat of the surface.
          * @param width The new width of the surface.
          * @param height The new height of the surface.
-         * @hide
          */
-        @SystemApi
         public void dispatchSurfaceChanged(int format, int width, int height) {
             if (mToken == null) {
                 Log.w(TAG, "The session has been already released");
@@ -1652,7 +1731,7 @@
             try {
                 mService.dispatchSurfaceChanged(mToken, format, width, height, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1673,7 +1752,7 @@
                 }
                 mService.setVolume(mToken, volume, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1691,9 +1770,7 @@
          *
          * @param channelUri The URI of a channel.
          * @param params A set of extra parameters which might be handled with this tune event.
-         * @hide
          */
-        @SystemApi
         public void tune(@NonNull Uri channelUri, Bundle params) {
             Preconditions.checkNotNull(channelUri);
             if (mToken == null) {
@@ -1713,7 +1790,7 @@
             try {
                 mService.tune(mToken, channelUri, params, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1730,7 +1807,7 @@
             try {
                 mService.setCaptionEnabled(mToken, enabled, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1772,7 +1849,7 @@
             try {
                 mService.selectTrack(mToken, type, trackId, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1920,7 +1997,7 @@
             try {
                 mService.timeShiftPlay(mToken, recordedProgramUri, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1935,7 +2012,7 @@
             try {
                 mService.timeShiftPause(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1950,7 +2027,7 @@
             try {
                 mService.timeShiftResume(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1971,7 +2048,7 @@
             try {
                 mService.timeShiftSeekTo(mToken, timeMs, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1988,7 +2065,7 @@
             try {
                 mService.timeShiftSetPlaybackParams(mToken, params, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2005,7 +2082,7 @@
             try {
                 mService.timeShiftEnablePositionTracking(mToken, enable, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2023,7 +2100,7 @@
             try {
                 mService.startRecording(mToken, programHint, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2038,7 +2115,7 @@
             try {
                 mService.stopRecording(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2050,9 +2127,7 @@
          *            i.e. prefixed with a package name you own, so that different developers will
          *            not create conflicting commands.
          * @param data Any data to include with the command.
-         * @hide
          */
-        @SystemApi
         public void sendAppPrivateCommand(String action, Bundle data) {
             if (mToken == null) {
                 Log.w(TAG, "The session has been already released");
@@ -2061,7 +2136,7 @@
             try {
                 mService.sendAppPrivateCommand(mToken, action, data, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2089,7 +2164,7 @@
             try {
                 mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2107,7 +2182,7 @@
             try {
                 mService.relayoutOverlayView(mToken, frame, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2122,7 +2197,7 @@
             try {
                 mService.removeOverlayView(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2138,7 +2213,7 @@
             try {
                 mService.unblockContent(mToken, unblockedRating.flattenToString(), mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index da4a038..97ef6d8 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -262,10 +262,8 @@
      *
      * <p>The system automatically creates a <code>TvInputInfo</code> object for each TV input,
      * based on the information collected from the <code>AndroidManifest.xml</code>, thus it is not
-     * necessary to call this method unless such information has changed dynamically. This may be
-     * also used to pass additional information that is not specified by the manifest file, such as
-     * ability to record and tuner count. Use {@link TvInputInfo.Builder} to build a new
-     * <code>TvInputInfo</code> object.
+     * necessary to call this method unless such information has changed dynamically.
+     * Use {@link TvInputInfo.Builder} to build a new <code>TvInputInfo</code> object.
      *
      * <p>Attempting to change information about a TV input that the calling package does not own
      * does nothing.
@@ -493,7 +491,7 @@
          * until this method is called.
          *
          * <p>The TV input service must call this method as soon as the content rendered onto its
-         * surface is ready for viewing. This method must be called each time {@link #onTune(Uri)}
+         * surface is ready for viewing. This method must be called each time {@link #onTune}
          * is called.
          *
          * @see #notifyVideoUnavailable
@@ -530,7 +528,8 @@
          *            </ul>
          * @see #notifyVideoAvailable
          */
-        public void notifyVideoUnavailable(final int reason) {
+        public void notifyVideoUnavailable(
+                @TvInputManager.VideoUnavailableReason final int reason) {
             if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START
                     || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
                 Log.e(TAG, "notifyVideoUnavailable - unknown reason: " + reason);
@@ -662,7 +661,7 @@
          * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
          * </ul>
          */
-        public void notifyTimeShiftStatusChanged(final int status) {
+        public void notifyTimeShiftStatusChanged(@TvInputManager.TimeShiftStatus final int status) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
                 @Override
@@ -839,14 +838,15 @@
         public abstract boolean onTune(Uri channelUri);
 
         /**
-         * Calls {@link #onTune(Uri)}. Override this method in order to handle {@code params}.
+         * Calls {@link #onTune(Uri)}. Override this method in order to handle domain-specific
+         * features that are only known between certain TV inputs and their clients.
          *
          * @param channelUri The URI of the channel.
-         * @param params The extra parameters from other applications.
+         * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
+         *            name, i.e. prefixed with a package name you own, so that different developers
+         *            will not create conflicting keys.
          * @return {@code true} if the tuning was successful, {@code false} otherwise.
-         * @hide
          */
-        @SystemApi
         public boolean onTune(Uri channelUri, Bundle params) {
             return onTune(channelUri);
         }
@@ -905,9 +905,7 @@
          *            i.e. prefixed with a package name you own, so that different developers will
          *            not create conflicting commands.
          * @param data Any data to include with the command.
-         * @hide
          */
-        @SystemApi
         public void onAppPrivateCommand(@NonNull String action, Bundle data) {
         }
 
@@ -1211,7 +1209,7 @@
         }
 
         /**
-         * Calls {@link #onTune}.
+         * Calls {@link #onTune(Uri, Bundle)}.
          */
         void tune(Uri channelUri, Bundle params) {
             mCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
@@ -1569,8 +1567,10 @@
          * passed channel and call this method to indicate that it is now available for immediate
          * recording. When {@link #onStartRecording(Uri)} is called, recording must start with
          * minimal delay.
+         *
+         * @param channelUri The URI of a channel.
          */
-        public void notifyTuned() {
+        public void notifyTuned(Uri channelUri) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
                 @Override
@@ -1578,7 +1578,7 @@
                     try {
                         if (DEBUG) Log.d(TAG, "notifyTuned");
                         if (mSessionCallback != null) {
-                            mSessionCallback.onTuned();
+                            mSessionCallback.onTuned(channelUri);
                         }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyTuned", e);
@@ -1681,7 +1681,7 @@
          * <p>The application may call this method before starting or after stopping recording, but
          * not during recording.
          *
-         * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+         * <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or
          * {@link #notifyError(int)} otherwise.
          *
          * @param channelUri The URI of a channel.
@@ -1689,19 +1689,20 @@
         public abstract void onTune(Uri channelUri);
 
         /**
-         * Called when the application requests to tune to a given channel for TV program recording.
+         * Calls {@link #onTune(Uri)}. Override this method in order to handle domain-specific
+         * features that are only known between certain TV inputs and their clients.
          *
          * <p>The application may call this method before starting or after stopping recording, but
          * not during recording.
          *
-         * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+         * <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or
          * {@link #notifyError(int)} otherwise.
          *
          * @param channelUri The URI of a channel.
-         * @param params Extra parameters.
-         * @hide
+         * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
+         *            name, i.e. prefixed with a package name you own, so that different developers
+         *            will not create conflicting keys.
          */
-        @SystemApi
         public void onTune(Uri channelUri, Bundle params) {
             onTune(channelUri);
         }
@@ -1710,8 +1711,8 @@
          * Called when the application requests to start TV program recording. Recording must start
          * immediately when this method is called.
          *
-         * <p>The application may supply the URI for a TV program as a hint for filling in program
-         * specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
+         * <p>The application may supply the URI for a TV program for filling in program specific
+         * data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
          * A non-null {@code programHint} implies the started recording should be of that specific
          * program, whereas null {@code programHint} does not impose such a requirement and the
          * recording can span across multiple TV programs. In either case, the application must call
@@ -1720,10 +1721,10 @@
          * <p>The session must call {@link #notifyError(int)} if the start request cannot be
          * fulfilled.
          *
-         * @param programHint The URI for the TV program to record as a hint, built by
+         * @param programUri The URI for the TV program to record, built by
          *            {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
          */
-        public abstract void onStartRecording(@Nullable Uri programHint);
+        public abstract void onStartRecording(@Nullable Uri programUri);
 
         /**
          * Called when the application requests to stop TV program recording. Recording must stop
@@ -1754,9 +1755,7 @@
          *            i.e. prefixed with a package name you own, so that different developers will
          *            not create conflicting commands.
          * @param data Any data to include with the command.
-         * @hide
          */
-        @SystemApi
         public void onAppPrivateCommand(@NonNull String action, Bundle data) {
         }
 
@@ -1836,7 +1835,7 @@
      * a hardware TV Input (e.g. HDMI 1) and forward the application's surface to the session so
      * that the user can see the screen of the hardware TV Input when she tunes to a channel from
      * this TV input. The implementation of this class is expected to change the channel of the
-     * external set-top box via a proprietary protocol when {@link HardwareSession#onTune(Uri)} is
+     * external set-top box via a proprietary protocol when {@link HardwareSession#onTune} is
      * requested by the application.
      *
      * <p>Note that this class is not for inputs for internal hardware like built-in tuner and HDMI
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 1c920f5..a5ff29f 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -76,11 +76,12 @@
      * during recording.
      *
      * <p>The recording session will respond by calling
-     * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+     * {@link RecordingCallback#onTuned(Uri)} if the tune request was fulfilled, or
      * {@link RecordingCallback#onError(int)} otherwise.
      *
      * @param inputId The ID of the TV input for the given channel.
      * @param channelUri The URI of a channel.
+     * @throws IllegalStateException If recording is already started.
      */
     public void tune(String inputId, Uri channelUri) {
         tune(inputId, channelUri, null);
@@ -90,21 +91,23 @@
      * Tunes to a given channel for TV program recording. The first tune request will create a new
      * recording session for the corresponding TV input and establish a connection between the
      * application and the session. If recording has already started in the current recording
-     * session, this method throws an exception.
+     * session, this method throws an exception. This can be used to provide domain-specific
+     * features that are only known between certain client and their TV inputs.
      *
      * <p>The application may call this method before starting or after stopping recording, but not
      * during recording.
      *
      * <p>The recording session will respond by calling
-     * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+     * {@link RecordingCallback#onTuned(Uri)} if the tune request was fulfilled, or
      * {@link RecordingCallback#onError(int)} otherwise.
      *
      * @param inputId The ID of the TV input for the given channel.
      * @param channelUri The URI of a channel.
-     * @param params Extra parameters.
-     * @hide
+     * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
+     *            name, i.e. prefixed with a package name you own, so that different developers will
+     *            not create conflicting keys.
+     * @throws IllegalStateException If recording is already started.
      */
-    @SystemApi
     public void tune(String inputId, Uri channelUri, Bundle params) {
         if (DEBUG) Log.d(TAG, "tune(" + channelUri + ")");
         if (TextUtils.isEmpty(inputId)) {
@@ -152,8 +155,8 @@
      * immediately when this method is called. If the current recording session has not yet tuned to
      * any channel, this method throws an exception.
      *
-     * <p>The application may supply the URI for a TV program as a hint for filling in program
-     * specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
+     * <p>The application may supply the URI for a TV program for filling in program specific data
+     * fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
      * A non-null {@code programHint} implies the started recording should be of that specific
      * program, whereas null {@code programHint} does not impose such a requirement and the
      * recording can span across multiple TV programs. In either case, the application must call
@@ -162,15 +165,16 @@
      * <p>The recording session will respond by calling {@link RecordingCallback#onError(int)} if
      * the start request cannot be fulfilled.
      *
-     * @param programHint The URI for the TV program to record as a hint, built by
+     * @param programUri The URI for the TV program to record, built by
      *            {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
+     * @throws IllegalStateException If {@link #tune} request hasn't been handled yet.
      */
-    public void startRecording(@Nullable Uri programHint) {
+    public void startRecording(@Nullable Uri programUri) {
         if (!mIsTuned) {
             throw new IllegalStateException("startRecording failed - not yet tuned");
         }
         if (mSession != null) {
-            mSession.startRecording(programHint);
+            mSession.startRecording(programUri);
             mIsRecordingStarted = true;
         }
     }
@@ -197,16 +201,14 @@
     }
 
     /**
-     * Calls {@link TvInputService.RecordingSession#appPrivateCommand(String, Bundle)} for the
-     * current recording session.
+     * Sends a private command to the underlying TV input. This can be used to provide
+     * domain-specific features that are only known between certain clients and their TV inputs.
      *
      * @param action The name of the private command to send. This <em>must</em> be a scoped name,
      *            i.e. prefixed with a package name you own, so that different developers will not
      *            create conflicting commands.
      * @param data An optional bundle to send with the command.
-     * @hide
      */
-    @SystemApi
     public void sendAppPrivateCommand(@NonNull String action, Bundle data) {
         if (TextUtils.isEmpty(action)) {
             throw new IllegalArgumentException("action cannot be null or an empty string");
@@ -245,8 +247,10 @@
         /**
          * This is called when the recording session has been tuned to the given channel and is
          * ready to start recording.
+         *
+         * @param channelUri The URI of a channel.
          */
-        public void onTuned() {
+        public void onTuned(Uri channelUri) {
         }
 
         /**
@@ -327,7 +331,7 @@
         }
 
         @Override
-        void onTuned(TvInputManager.Session session) {
+        void onTuned(TvInputManager.Session session, Uri channelUri) {
             if (DEBUG) {
                 Log.d(TAG, "onTuned()");
             }
@@ -336,7 +340,7 @@
                 return;
             }
             mIsTuned = true;
-            mCallback.onTuned();
+            mCallback.onTuned(channelUri);
         }
 
         @Override
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index 6a44b1e..e623353 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -121,6 +121,8 @@
 
     /**
      * Returns the audio channel count. Valid only for {@link #TYPE_AUDIO} tracks.
+     *
+     * @throws IllegalStateException if not called on an audio track
      */
     public final int getAudioChannelCount() {
         if (mType != TYPE_AUDIO) {
@@ -131,6 +133,8 @@
 
     /**
      * Returns the audio sample rate, in the unit of Hz. Valid only for {@link #TYPE_AUDIO} tracks.
+     *
+     * @throws IllegalStateException if not called on an audio track
      */
     public final int getAudioSampleRate() {
         if (mType != TYPE_AUDIO) {
@@ -142,6 +146,8 @@
     /**
      * Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
      * tracks.
+     *
+     * @throws IllegalStateException if not called on a video track
      */
     public final int getVideoWidth() {
         if (mType != TYPE_VIDEO) {
@@ -153,6 +159,8 @@
     /**
      * Returns the height of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
      * tracks.
+     *
+     * @throws IllegalStateException if not called on a video track
      */
     public final int getVideoHeight() {
         if (mType != TYPE_VIDEO) {
@@ -164,6 +172,8 @@
     /**
      * Returns the frame rate of the video, in the unit of fps (frames per second). Valid only for
      * {@link #TYPE_VIDEO} tracks.
+     *
+     * @throws IllegalStateException if not called on a video track
      */
     public final float getVideoFrameRate() {
         if (mType != TYPE_VIDEO) {
@@ -175,6 +185,8 @@
     /**
      * Returns the pixel aspect ratio (the ratio of a pixel's width to its height) of the video.
      * Valid only for {@link #TYPE_VIDEO} tracks.
+     *
+     * @throws IllegalStateException if not called on a video track
      */
     public final float getVideoPixelAspectRatio() {
         if (mType != TYPE_VIDEO) {
@@ -189,6 +201,8 @@
      *
      * <p>The complete list of values are defined in ETSI TS 101 154 V1.7.1 Annex B, ATSC A/53 Part
      * 4 and SMPTE 2016-1-2007.
+     *
+     * @throws IllegalStateException if not called on a video track
      */
     public final byte getVideoActiveFormatDescription() {
         if (mType != TYPE_VIDEO) {
@@ -268,6 +282,8 @@
          * @param type The type of the track.
          * @param id The ID of the track that uniquely identifies the current track among all the
          *            other tracks in the same TV program.
+         * @throws IllegalArgumentException if the type is not any of {@link #TYPE_AUDIO},
+         *                                  {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}
          */
         public Builder(int type, @NonNull String id) {
             if (type != TYPE_AUDIO
@@ -304,6 +320,7 @@
          * Sets the audio channel count. Valid only for {@link #TYPE_AUDIO} tracks.
          *
          * @param audioChannelCount The audio channel count.
+         * @throws IllegalStateException if not called on an audio track
          */
         public final Builder setAudioChannelCount(int audioChannelCount) {
             if (mType != TYPE_AUDIO) {
@@ -318,6 +335,7 @@
          * tracks.
          *
          * @param audioSampleRate The audio sample rate.
+         * @throws IllegalStateException if not called on an audio track
          */
         public final Builder setAudioSampleRate(int audioSampleRate) {
             if (mType != TYPE_AUDIO) {
@@ -332,6 +350,7 @@
          * tracks.
          *
          * @param videoWidth The width of the video.
+         * @throws IllegalStateException if not called on a video track
          */
         public final Builder setVideoWidth(int videoWidth) {
             if (mType != TYPE_VIDEO) {
@@ -346,6 +365,7 @@
          * tracks.
          *
          * @param videoHeight The height of the video.
+         * @throws IllegalStateException if not called on a video track
          */
         public final Builder setVideoHeight(int videoHeight) {
             if (mType != TYPE_VIDEO) {
@@ -360,6 +380,7 @@
          * {@link #TYPE_VIDEO} tracks.
          *
          * @param videoFrameRate The frame rate of the video.
+         * @throws IllegalStateException if not called on a video track
          */
         public final Builder setVideoFrameRate(float videoFrameRate) {
             if (mType != TYPE_VIDEO) {
@@ -379,6 +400,7 @@
          * pixel aspect ratio for most video formats.
          *
          * @param videoPixelAspectRatio The pixel aspect ratio of the video.
+         * @throws IllegalStateException if not called on a video track
          */
         public final Builder setVideoPixelAspectRatio(float videoPixelAspectRatio) {
             if (mType != TYPE_VIDEO) {
@@ -398,6 +420,7 @@
          * 4 and SMPTE 2016-1-2007.
          *
          * @param videoActiveFormatDescription The AFD code of the video.
+         * @throws IllegalStateException if not called on a video track
          */
         public final Builder setVideoActiveFormatDescription(byte videoActiveFormatDescription) {
             if (mType != TYPE_VIDEO) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 5c4b528..02ee0cc 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -56,7 +57,7 @@
  * TV inputs available on the system can be obtained by calling
  * {@link TvInputManager#getTvInputList() TvInputManager.getTvInputList()}.)
  *
- * <p>Once the application supplies the URI for a specific TV channel to {@link #tune(String, Uri)}
+ * <p>Once the application supplies the URI for a specific TV channel to {@link #tune}
  * method, it takes care of underlying service binding (and unbinding if the current TvView is
  * already bound to a service) and automatically allocates/deallocates resources needed. In addition
  * to a few essential methods to control how the contents are presented, it also provides a way to
@@ -206,13 +207,18 @@
     }
 
     /**
-     * Sets the Z order of a window owning the surface of this TvView above the normal TvView
-     * but below an application.
+     * Controls whether the TvView's surface is placed on top of another regular surface view in the
+     * window (but still behind the window itself).
+     * This is typically used to place overlays on top of an underlying TvView.
      *
-     * @see SurfaceView#setZOrderMediaOverlay
-     * @hide
+     * <p>Note that this must be set before the TvView's containing window is attached to the
+     * window manager.
+     *
+     * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
+     *
+     * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false}
+     *            otherwise.
      */
-    @SystemApi
     public void setZOrderMediaOverlay(boolean isMediaOverlay) {
         if (isMediaOverlay) {
             mWindowZOrder = ZORDER_MEDIA_OVERLAY;
@@ -230,12 +236,18 @@
     }
 
     /**
-     * Sets the Z order of a window owning the surface of this TvView on top of an application.
+     * Controls whether the TvView's surface is placed on top of its window. Normally it is placed
+     * behind the window, to allow it to (for the most part) appear to composite with the views in
+     * the hierarchy.  By setting this, you cause it to be placed above the window. This means that
+     * none of the contents of the window this TvView is in will be visible on top of its surface.
      *
-     * @see SurfaceView#setZOrderOnTop
-     * @hide
+     * <p>Note that this must be set before the TvView's containing window is attached to the window
+     * manager.
+     *
+     * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
+     *
+     * @param onTop {@code true} to be on top of its window, {@code false} otherwise.
      */
-    @SystemApi
     public void setZOrderOnTop(boolean onTop) {
         if (onTop) {
             mWindowZOrder = ZORDER_ON_TOP;
@@ -280,14 +292,15 @@
     }
 
     /**
-     * Tunes to a given channel.
+     * Tunes to a given channel. This can be used to provide domain-specific features that are only
+     * known between certain clients and their TV inputs.
      *
      * @param inputId The ID of TV input for the given channel.
      * @param channelUri The URI of a channel.
-     * @param params Extra parameters.
-     * @hide
+     * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
+     *            name, i.e. prefixed with a package name you own, so that different developers will
+     *            not create conflicting keys.
      */
-    @SystemApi
     public void tune(String inputId, Uri channelUri, Bundle params) {
         if (DEBUG) Log.d(TAG, "tune(" + channelUri + ")");
         if (TextUtils.isEmpty(inputId)) {
@@ -360,11 +373,8 @@
      *
      * @param unblockedRating A TvContentRating to unblock.
      * @see TvInputService.Session#notifyContentBlocked(TvContentRating)
-     * @hide
-     * @deprecated Use {@link #unblockContent} instead.
+     * @removed
      */
-    @Deprecated
-    @SystemApi
     public void requestUnblockContent(TvContentRating unblockedRating) {
         unblockContent(unblockedRating);
     }
@@ -379,6 +389,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
     public void unblockContent(TvContentRating unblockedRating) {
         if (mSession != null) {
             mSession.unblockContent(unblockedRating);
@@ -539,16 +550,14 @@
     }
 
     /**
-     * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)} for the current
-     * session.
+     * Sends a private command to the underlying TV input. This can be used to provide
+     * domain-specific features that are only known between certain clients and their TV inputs.
      *
      * @param action The name of the private command to send. This <em>must</em> be a scoped name,
      *            i.e. prefixed with a package name you own, so that different developers will not
      *            create conflicting commands.
      * @param data An optional bundle to send with the command.
-     * @hide
      */
-    @SystemApi
     public void sendAppPrivateCommand(@NonNull String action, Bundle data) {
         if (TextUtils.isEmpty(action)) {
             throw new IllegalArgumentException("action cannot be null or an empty string");
@@ -893,7 +902,7 @@
 
         /**
          * This is invoked when the channel of this TvView is changed by the underlying TV input
-         * without any {@link TvView#tune(String, Uri)} request.
+         * without any {@link TvView#tune} request.
          *
          * @param inputId The ID of the TV input bound to this view.
          * @param channelUri The URI of a channel.
@@ -955,7 +964,8 @@
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
          * </ul>
          */
-        public void onVideoUnavailable(String inputId, int reason) {
+        public void onVideoUnavailable(
+                String inputId, @TvInputManager.VideoUnavailableReason int reason) {
         }
 
         /**
@@ -1000,7 +1010,8 @@
          * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
          * </ul>
          */
-        public void onTimeShiftStatusChanged(String inputId, int status) {
+        public void onTimeShiftStatusChanged(
+                String inputId, @TvInputManager.TimeShiftStatus int status) {
         }
     }
 
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 29bcc19..760a2d1 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -713,8 +713,7 @@
         };
     }
 
-
-    private MtpPropertyList getObjectPropertyList(long handle, int format, long property,
+    private MtpPropertyList getObjectPropertyList(int handle, int format, int property,
                         int groupCode, int depth) {
         // FIXME - implement group support
         if (groupCode != 0) {
@@ -722,29 +721,29 @@
         }
 
         MtpPropertyGroup propertyGroup;
-        if (property == 0xFFFFFFFFL) {
-            if (format == 0 && handle > 0) {
+        if (property == 0xffffffff) {
+            if (format == 0 && handle != 0 && handle != 0xffffffff) {
                 // return properties based on the object's format
-                format = getObjectFormat((int)handle);
+                format = getObjectFormat(handle);
             }
-             propertyGroup = mPropertyGroupsByFormat.get(format);
-             if (propertyGroup == null) {
+            propertyGroup = mPropertyGroupsByFormat.get(format);
+            if (propertyGroup == null) {
                 int[] propertyList = getSupportedObjectProperties(format);
                 propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
                         mVolumeName, propertyList);
-                mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
+                mPropertyGroupsByFormat.put(format, propertyGroup);
             }
         } else {
-              propertyGroup = mPropertyGroupsByProperty.get(property);
-             if (propertyGroup == null) {
-                int[] propertyList = new int[] { (int)property };
-                propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
-                        mVolumeName, propertyList);
-                mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
+            propertyGroup = mPropertyGroupsByProperty.get(property);
+            if (propertyGroup == null) {
+                final int[] propertyList = new int[] { property };
+                propertyGroup = new MtpPropertyGroup(
+                        this, mMediaProvider, mVolumeName, propertyList);
+                mPropertyGroupsByProperty.put(property, propertyGroup);
             }
         }
 
-        return propertyGroup.getPropertyList((int)handle, format, depth);
+        return propertyGroup.getPropertyList(handle, format, depth);
     }
 
     private int renameFile(int handle, String newName) {
@@ -970,7 +969,7 @@
         Cursor c = null;
         try {
             c = mMediaProvider.query(mObjectsUri, FORMAT_PROJECTION,
-                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
+                            ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 return c.getInt(1);
             } else {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 0e7013c..d0ef37c 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -355,6 +355,19 @@
         }
     }
 
+    /**
+     * Returns object size in 64-bit integer.
+     *
+     * Though MtpObjectInfo#getCompressedSize returns the object size in 32-bit unsigned integer,
+     * this method returns the object size in 64-bit integer from the object property. Thus it can
+     * fetch 4GB+ object size correctly. If the device does not support objectSize property, it
+     * throws IOException.
+     * @hide
+     */
+    public long getObjectSizeLong(int handle, int format) throws IOException {
+        return native_get_object_size_long(handle, format);
+    }
+
     // used by the JNI code
     private long mNativeContext;
 
@@ -381,4 +394,5 @@
     private native int native_submit_event_request();
     private native MtpEvent native_reap_event_request(int handle);
     private native void native_discard_event_request(int handle);
+    private native long native_get_object_size_long(int handle, int format) throws IOException;
 }
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 480acd9..6954045 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -45,6 +45,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
@@ -120,8 +121,8 @@
      * they are done. If more than one of those methods is called, an exception will
      * be thrown.
      *
-     * @see MediaBrowserService#onLoadChildren
-     * @see MediaBrowserService#onLoadItem
+     * @see #onLoadChildren
+     * @see #onLoadItem
      */
     public class Result<T> {
         private Object mDebug;
@@ -367,11 +368,16 @@
      * {@link Result#detach result.detach} may be called before returning from
      * this function, and then {@link Result#sendResult result.sendResult}
      * called when the loading is complete.
+     * </p><p>
+     * In case the media item does not have any children, call {@link Result#sendResult}
+     * with an empty list. When the given {@code parentId} is invalid, implementations must
+     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+     * {@link MediaBrowser.SubscriptionCallback#onError}.
+     * </p>
      *
      * @param parentId The id of the parent media item whose children are to be
      *            queried.
-     * @param result The Result to send the list of children to, or null if the
-     *            id is invalid.
+     * @param result The Result to send the list of children to.
      */
     public abstract void onLoadChildren(@NonNull String parentId,
             @NonNull Result<List<MediaBrowser.MediaItem>> result);
@@ -385,11 +391,16 @@
      * {@link Result#detach result.detach} may be called before returning from
      * this function, and then {@link Result#sendResult result.sendResult}
      * called when the loading is complete.
+     * </p><p>
+     * In case the media item does not have any children, call {@link Result#sendResult}
+     * with an empty list. When the given {@code parentId} is invalid, implementations must
+     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+     * {@link MediaBrowser.SubscriptionCallback#onError}.
+     * </p>
      *
      * @param parentId The id of the parent media item whose children are to be
      *            queried.
-     * @param result The Result to send the list of children to, or null if the
-     *            id is invalid.
+     * @param result The Result to send the list of children to.
      * @param options A bundle of service-specific arguments sent from the media
      *            browse. The information returned through the result should be
      *            affected by the contents of this bundle.
@@ -411,13 +422,18 @@
      * result.detach} may be called before returning from this function, and
      * then {@link Result#sendResult result.sendResult} called when the item has
      * been loaded.
-     * <p>
-     * The default implementation sends a null result.
+     * </p><p>
+     * When the given {@code itemId} is invalid, implementations must call
+     * {@link Result#sendResult result.sendResult} with {@code null}, which will
+     * invoke {@link MediaBrowser.ItemCallback#onError}.
+     * </p><p>
+     * The default implementation calls {@link Result#sendResult result.sendResult}
+     * with {@code null}.
+     * </p>
      *
      * @param itemId The id for the specific
      *            {@link android.media.browse.MediaBrowser.MediaItem}.
-     * @param result The Result to send the item to, or null if the id is
-     *            invalid.
+     * @param result The Result to send the item to.
      */
     public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
         result.sendResult(null);
@@ -558,6 +574,9 @@
      * Remove the subscription.
      */
     private boolean removeSubscription(String id, ConnectionRecord connection, Bundle options) {
+        if (options == null) {
+            return connection.subscriptions.remove(id) != null;
+        }
         boolean removed = false;
         List<Bundle> optionsList = connection.subscriptions.get(id);
         if (optionsList != null) {
@@ -630,15 +649,18 @@
 
     private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
             final Bundle options) {
+        if (list == null) {
+            return null;
+        }
         int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
         int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
         if (page == -1 && pageSize == -1) {
             return list;
         }
-        int fromIndex = pageSize * (page - 1);
+        int fromIndex = pageSize * page;
         int toIndex = fromIndex + pageSize;
-        if (page < 1 || pageSize < 1 || fromIndex >= list.size()) {
-            return null;
+        if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
+            return Collections.EMPTY_LIST;
         }
         if (toIndex > list.size()) {
             toIndex = list.size();
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a326f6f..29739ca 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -43,14 +43,10 @@
     libcamera_client \
     libmtp \
     libusbhost \
-    libjhead \
     libexif \
     libpiex \
     libstagefright_amrnb_common
 
-LOCAL_REQUIRED_MODULES := \
-    libjhead_jni
-
 LOCAL_STATIC_LIBRARIES := \
     libstagefright_amrnbenc
 
@@ -68,7 +64,6 @@
     frameworks/av/media/mtp \
     frameworks/native/include/media/openmax \
     $(call include-path-for, libhardware)/hardware \
-    system/media/camera/include \
     $(PV_INCLUDES) \
     $(JNI_H_INCLUDE)
 
diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
index ba38569..418a3f2 100644
--- a/media/jni/android_media_ExifInterface.cpp
+++ b/media/jni/android_media_ExifInterface.cpp
@@ -19,12 +19,15 @@
 
 #include "android_media_Utils.h"
 
+#include "android/graphics/CreateJavaOutputStreamAdaptor.h"
 #include "src/piex_types.h"
 #include "src/piex.h"
 
 #include <jni.h>
 #include <JNIHelp.h>
+#include <androidfw/Asset.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android/graphics/Utils.h>
 #include <nativehelper/ScopedLocalRef.h>
 
 #include <utils/Log.h>
@@ -35,6 +38,9 @@
 
 using namespace android;
 
+static const char kJpegSignatureChars[] = {(char)0xff, (char)0xd8, (char)0xff};
+static const int kJpegSignatureSize = 3;
+
 #define FIND_CLASS(var, className) \
     var = env->FindClass(className); \
     LOG_FATAL_IF(! var, "Unable to find class " className);
@@ -82,29 +88,58 @@
                   "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
 }
 
-static jobject ExifInterface_getRawMetadata(
-        JNIEnv* env, jclass /* clazz */, jstring jfilename) {
-    const char* filenameChars = env->GetStringUTFChars(jfilename, NULL);
-    if (filenameChars == NULL) {
+static bool is_asset_stream(const SkStream& stream) {
+    return stream.hasLength() && stream.hasPosition();
+}
+
+static jobject ExifInterface_getThumbnailFromAsset(
+        JNIEnv* env, jclass /* clazz */, jlong jasset, jint jthumbnailOffset,
+        jint jthumbnailLength) {
+    Asset* asset = reinterpret_cast<Asset*>(jasset);
+    std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset));
+
+    std::unique_ptr<jbyte[]> thumbnailData(new jbyte[(int)jthumbnailLength]);
+    if (thumbnailData.get() == NULL) {
+        ALOGI("No memory to get thumbnail");
         return NULL;
     }
-    String8 filename(filenameChars);
-    env->ReleaseStringUTFChars(jfilename, filenameChars);
+
+    // Do not know the current offset. So rewind it.
+    stream->rewind();
+
+    // Read thumbnail.
+    stream->skip((int)jthumbnailOffset);
+    stream->read((void*)thumbnailData.get(), (int)jthumbnailLength);
+
+    // Copy to the byte array.
+    jbyteArray byteArray = env->NewByteArray(jthumbnailLength);
+    env->SetByteArrayRegion(byteArray, 0, jthumbnailLength, thumbnailData.get());
+    return byteArray;
+}
+
+static jobject getRawAttributes(JNIEnv* env, SkStream* stream, bool returnThumbnail) {
+    std::unique_ptr<SkStream> streamDeleter(stream);
+
+    std::unique_ptr<::piex::StreamInterface> piexStream;
+    if (is_asset_stream(*stream)) {
+        piexStream.reset(new AssetStream(streamDeleter.release()));
+    } else {
+        piexStream.reset(new BufferedStream(streamDeleter.release()));
+    }
 
     piex::PreviewImageData image_data;
-    std::unique_ptr<FileStream> stream(new FileStream(filename));
 
-    if (!GetExifFromRawImage(stream.get(), filename, image_data)) {
-        ALOGI("Raw image not detected: %s", filename.string());
+    if (!GetExifFromRawImage(piexStream.get(), String8("[piex stream]"), image_data)) {
+        ALOGI("Raw image not detected");
         return NULL;
     }
 
     KeyedVector<String8, String8> map;
 
-    if (image_data.thumbnail_length > 0) {
+    if (image_data.thumbnail.length > 0) {
         map.add(String8("hasThumbnail"), String8("true"));
-        map.add(String8("thumbnailOffset"), String8::format("%d", image_data.thumbnail_offset));
-        map.add(String8("thumbnailLength"), String8::format("%d", image_data.thumbnail_length));
+        map.add(String8("thumbnailOffset"), String8::format("%d", image_data.thumbnail.offset));
+        map.add(String8("thumbnailLength"), String8::format("%d", image_data.thumbnail.length));
     } else {
         map.add(String8("hasThumbnail"), String8("false"));
     }
@@ -254,7 +289,117 @@
         }
     }
 
-    return KeyedVectorToHashMap(env, map);
+    jobject hashMap = KeyedVectorToHashMap(env, map);
+
+    if (returnThumbnail) {
+        std::unique_ptr<jbyte[]> thumbnailData(new jbyte[image_data.thumbnail.length]);
+        if (thumbnailData.get() == NULL) {
+            ALOGE("No memory to parse a thumbnail");
+            return NULL;
+        }
+        jbyteArray jthumbnailByteArray = env->NewByteArray(image_data.thumbnail.length);
+        if (jthumbnailByteArray == NULL) {
+            ALOGE("No memory to parse a thumbnail");
+            return NULL;
+        }
+        piexStream.get()->GetData(image_data.thumbnail.offset, image_data.thumbnail.length,
+                (uint8_t*)thumbnailData.get());
+        env->SetByteArrayRegion(
+                jthumbnailByteArray, 0, image_data.thumbnail.length, thumbnailData.get());
+        jstring jkey = env->NewStringUTF(String8("thumbnailData"));
+        env->CallObjectMethod(hashMap, gFields.hashMap.put, jkey, jthumbnailByteArray);
+        env->DeleteLocalRef(jkey);
+        env->DeleteLocalRef(jthumbnailByteArray);
+    }
+    return hashMap;
+}
+
+static jobject ExifInterface_getRawAttributesFromAsset(
+        JNIEnv* env, jclass /* clazz */, jlong jasset) {
+    std::unique_ptr<char[]> jpegSignature(new char[kJpegSignatureSize]);
+    if (jpegSignature.get() == NULL) {
+        ALOGE("No enough memory to parse");
+        return NULL;
+    }
+
+    Asset* asset = reinterpret_cast<Asset*>(jasset);
+    std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset));
+
+    if (stream.get()->read(jpegSignature.get(), kJpegSignatureSize) != kJpegSignatureSize) {
+        // Rewind the stream.
+        stream.get()->rewind();
+
+        ALOGI("Corrupted image.");
+        return NULL;
+    }
+
+    // Rewind the stream.
+    stream.get()->rewind();
+
+    if (memcmp(jpegSignature.get(), kJpegSignatureChars, kJpegSignatureSize) == 0) {
+        ALOGI("Should be a JPEG stream.");
+        return NULL;
+    }
+
+    // Try to parse from the given stream.
+    jobject result = getRawAttributes(env, stream.get(), false);
+
+    // Rewind the stream for the chance to read JPEG.
+    if (result == NULL) {
+        stream.get()->rewind();
+    }
+    return result;
+}
+
+static jobject ExifInterface_getRawAttributesFromFileDescriptor(
+        JNIEnv* env, jclass /* clazz */, jobject jfileDescriptor) {
+    std::unique_ptr<char[]> jpegSignature(new char[kJpegSignatureSize]);
+    if (jpegSignature.get() == NULL) {
+        ALOGE("No enough memory to parse");
+        return NULL;
+    }
+
+    int fd = jniGetFDFromFileDescriptor(env, jfileDescriptor);
+    if (fd < 0) {
+        ALOGI("Invalid file descriptor");
+        return NULL;
+    }
+
+    // Restore the file descriptor's offset on exiting this function.
+    AutoFDSeek autoRestore(fd);
+
+    int dupFd = dup(fd);
+
+    FILE* file = fdopen(dupFd, "r");
+    if (file == NULL) {
+        ALOGI("Failed to open the file descriptor");
+        return NULL;
+    }
+
+    if (fgets(jpegSignature.get(), kJpegSignatureSize, file) == NULL) {
+        ALOGI("Corrupted image.");
+        return NULL;
+    }
+
+    if (memcmp(jpegSignature.get(), kJpegSignatureChars, kJpegSignatureSize) == 0) {
+        ALOGI("Should be a JPEG stream.");
+        return NULL;
+    }
+
+    // Rewind the file descriptor.
+    fseek(file, 0L, SEEK_SET);
+
+    std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file,
+                SkFILEStream::kCallerPasses_Ownership));
+    return getRawAttributes(env, fileStream.get(), false);
+}
+
+static jobject ExifInterface_getRawAttributesFromInputStream(
+        JNIEnv* env, jclass /* clazz */, jobject jinputStream) {
+    jbyteArray byteArray = env->NewByteArray(8*1024);
+    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
+    std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, jinputStream, scoper.get()));
+    return getRawAttributes(env, stream.get(), true);
 }
 
 } // extern "C"
@@ -262,9 +407,14 @@
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    { "initRawNative", "()V", (void *)ExifInterface_initRaw },
-    { "getRawAttributesNative", "(Ljava/lang/String;)Ljava/util/HashMap;",
-      (void*)ExifInterface_getRawMetadata },
+    { "nativeInitRaw", "()V", (void *)ExifInterface_initRaw },
+    { "nativeGetThumbnailFromAsset", "(JII)[B", (void *)ExifInterface_getThumbnailFromAsset },
+    { "nativeGetRawAttributesFromAsset", "(J)Ljava/util/HashMap;",
+      (void*)ExifInterface_getRawAttributesFromAsset },
+    { "nativeGetRawAttributesFromFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/util/HashMap;",
+      (void*)ExifInterface_getRawAttributesFromFileDescriptor },
+    { "nativeGetRawAttributesFromInputStream", "(Ljava/io/InputStream;)Ljava/util/HashMap;",
+      (void*)ExifInterface_getRawAttributesFromInputStream },
 };
 
 int register_android_media_ExifInterface(JNIEnv *env) {
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 4ac62f5..c3993ae 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -16,6 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ImageReader_JNI"
+#include "android_media_Utils.h"
 #include <utils/Log.h>
 #include <utils/misc.h>
 #include <utils/List.h>
@@ -23,7 +24,6 @@
 
 #include <cstdio>
 
-#include <gui/CpuConsumer.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 #include <camera3.h>
@@ -37,8 +37,6 @@
 #include <stdint.h>
 #include <inttypes.h>
 
-#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
-
 #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID       "mNativeContext"
 #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID   "mNativeBuffer"
 #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID       "mTimestamp"
@@ -47,9 +45,6 @@
 
 using namespace android;
 
-enum {
-    IMAGE_READER_MAX_NUM_PLANES = 3,
-};
 
 enum {
     ACQUIRE_SUCCESS = 0,
@@ -65,6 +60,7 @@
 static struct {
     jfieldID mNativeBuffer;
     jfieldID mTimestamp;
+    jfieldID mPlanes;
 } gSurfaceImageClassInfo;
 
 static struct {
@@ -89,21 +85,12 @@
 
     virtual void onFrameAvailable(const BufferItem& item);
 
-    CpuConsumer::LockedBuffer* getLockedBuffer();
-    void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer);
+    BufferItem* getBufferItem();
+    void returnBufferItem(BufferItem* buffer);
 
-    BufferItem* getOpaqueBuffer();
-    void returnOpaqueBuffer(BufferItem* buffer);
 
-    void setCpuConsumer(const sp<CpuConsumer>& consumer) { mConsumer = consumer; }
-    CpuConsumer* getCpuConsumer() { return mConsumer.get(); }
-
-    void setOpaqueConsumer(const sp<BufferItemConsumer>& consumer) { mOpaqueConsumer = consumer; }
-    BufferItemConsumer* getOpaqueConsumer() { return mOpaqueConsumer.get(); }
-    // This is the only opaque format exposed in the ImageFormat public API.
-    // Note that we do support CPU access for HAL_PIXEL_FORMAT_RAW_OPAQUE
-    // (ImageFormat#RAW_PRIVATE) so it doesn't count as opaque here.
-    bool isOpaque() { return mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; }
+    void setBufferConsumer(const sp<BufferItemConsumer>& consumer) { mConsumer = consumer; }
+    BufferItemConsumer* getBufferConsumer() { return mConsumer.get(); }
 
     void setProducer(const sp<IGraphicBufferProducer>& producer) { mProducer = producer; }
     IGraphicBufferProducer* getProducer() { return mProducer.get(); }
@@ -124,10 +111,8 @@
     static JNIEnv* getJNIEnv(bool* needsDetach);
     static void detachJNI();
 
-    List<CpuConsumer::LockedBuffer*> mBuffers;
-    List<BufferItem*> mOpaqueBuffers;
-    sp<CpuConsumer> mConsumer;
-    sp<BufferItemConsumer> mOpaqueConsumer;
+    List<BufferItem*> mBuffers;
+    sp<BufferItemConsumer> mConsumer;
     sp<IGraphicBufferProducer> mProducer;
     jobject mWeakThiz;
     jclass mClazz;
@@ -140,12 +125,14 @@
 JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env,
         jobject weakThiz, jclass clazz, int maxImages) :
     mWeakThiz(env->NewGlobalRef(weakThiz)),
-    mClazz((jclass)env->NewGlobalRef(clazz)) {
+    mClazz((jclass)env->NewGlobalRef(clazz)),
+    mFormat(0),
+    mDataSpace(HAL_DATASPACE_UNKNOWN),
+    mWidth(-1),
+    mHeight(-1) {
     for (int i = 0; i < maxImages; i++) {
-        CpuConsumer::LockedBuffer *buffer = new CpuConsumer::LockedBuffer;
-        BufferItem* opaqueBuffer = new BufferItem;
+        BufferItem* buffer = new BufferItem;
         mBuffers.push_back(buffer);
-        mOpaqueBuffers.push_back(opaqueBuffer);
     }
 }
 
@@ -174,36 +161,21 @@
     }
 }
 
-CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() {
+BufferItem* JNIImageReaderContext::getBufferItem() {
     if (mBuffers.empty()) {
         return NULL;
     }
-    // Return a LockedBuffer pointer and remove it from the list
-    List<CpuConsumer::LockedBuffer*>::iterator it = mBuffers.begin();
-    CpuConsumer::LockedBuffer* buffer = *it;
+    // Return a BufferItem pointer and remove it from the list
+    List<BufferItem*>::iterator it = mBuffers.begin();
+    BufferItem* buffer = *it;
     mBuffers.erase(it);
     return buffer;
 }
 
-void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer* buffer) {
+void JNIImageReaderContext::returnBufferItem(BufferItem* buffer) {
     mBuffers.push_back(buffer);
 }
 
-BufferItem* JNIImageReaderContext::getOpaqueBuffer() {
-    if (mOpaqueBuffers.empty()) {
-        return NULL;
-    }
-    // Return an opaque buffer pointer and remove it from the list
-    List<BufferItem*>::iterator it = mOpaqueBuffers.begin();
-    BufferItem* buffer = *it;
-    mOpaqueBuffers.erase(it);
-    return buffer;
-}
-
-void JNIImageReaderContext::returnOpaqueBuffer(BufferItem* buffer) {
-    mOpaqueBuffers.push_back(buffer);
-}
-
 JNIImageReaderContext::~JNIImageReaderContext() {
     bool needsDetach = false;
     JNIEnv* env = getJNIEnv(&needsDetach);
@@ -217,25 +189,15 @@
         detachJNI();
     }
 
-    // Delete LockedBuffers
-    for (List<CpuConsumer::LockedBuffer *>::iterator it = mBuffers.begin();
+    // Delete buffer items.
+    for (List<BufferItem *>::iterator it = mBuffers.begin();
             it != mBuffers.end(); it++) {
         delete *it;
     }
 
-    // Delete opaque buffers
-    for (List<BufferItem *>::iterator it = mOpaqueBuffers.begin();
-            it != mOpaqueBuffers.end(); it++) {
-        delete *it;
-    }
-
-    mBuffers.clear();
     if (mConsumer != 0) {
         mConsumer.clear();
     }
-    if (mOpaqueConsumer != 0) {
-        mOpaqueConsumer.clear();
-    }
 }
 
 void JNIImageReaderContext::onFrameAvailable(const BufferItem& /*item*/)
@@ -257,11 +219,6 @@
 
 extern "C" {
 
-static bool isFormatOpaque(int format) {
-    // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
-    return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-}
-
 static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz)
 {
     JNIImageReaderContext *ctx;
@@ -270,24 +227,6 @@
     return ctx;
 }
 
-static CpuConsumer* ImageReader_getCpuConsumer(JNIEnv* env, jobject thiz)
-{
-    ALOGV("%s:", __FUNCTION__);
-    JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
-    if (ctx == NULL) {
-        jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
-        return NULL;
-    }
-
-    if (ctx->isOpaque()) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                "Opaque ImageReader doesn't support this method");
-        return NULL;
-    }
-
-    return ctx->getCpuConsumer();
-}
-
 static IGraphicBufferProducer* ImageReader_getProducer(JNIEnv* env, jobject thiz)
 {
     ALOGV("%s:", __FUNCTION__);
@@ -315,411 +254,7 @@
             reinterpret_cast<jlong>(ctx.get()));
 }
 
-static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image)
-{
-    return reinterpret_cast<CpuConsumer::LockedBuffer*>(
-            env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
-}
-
-static void Image_setBuffer(JNIEnv* env, jobject thiz,
-        const CpuConsumer::LockedBuffer* buffer)
-{
-    env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
-}
-
-static void Image_setOpaqueBuffer(JNIEnv* env, jobject thiz,
-        const BufferItem* buffer)
-{
-    env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
-}
-
-static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride)
-{
-    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
-    uint32_t size = 0;
-    uint32_t width = buffer->width;
-    uint8_t* jpegBuffer = buffer->data;
-
-    if (usingRGBAOverride) {
-        width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
-    }
-
-    // First check for JPEG transport header at the end of the buffer
-    uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
-    struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
-    if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
-        size = blob->jpeg_size;
-        ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
-    }
-
-    // failed to find size, default to whole buffer
-    if (size == 0) {
-        /*
-         * This is a problem because not including the JPEG header
-         * means that in certain rare situations a regular JPEG blob
-         * will be misidentified as having a header, in which case
-         * we will get a garbage size value.
-         */
-        ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
-                __FUNCTION__, width);
-        size = width;
-    }
-
-    return size;
-}
-
-static bool usingRGBAToJpegOverride(int32_t bufferFormat, int32_t readerCtxFormat) {
-    return readerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888;
-}
-
-static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t readerCtxFormat)
-{
-    // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
-    // write limitations for some platforms (b/17379185).
-    if (usingRGBAToJpegOverride(bufferFormat, readerCtxFormat)) {
-        return HAL_PIXEL_FORMAT_BLOB;
-    }
-    return bufferFormat;
-}
-
-static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
-                                uint8_t **base, uint32_t *size, int32_t readerFormat)
-{
-    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
-    ALOG_ASSERT(base != NULL, "base is NULL!!!");
-    ALOG_ASSERT(size != NULL, "size is NULL!!!");
-    ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
-
-    ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
-
-    uint32_t dataSize, ySize, cSize, cStride;
-    uint8_t *cb, *cr;
-    uint8_t *pData = NULL;
-    int bytesPerPixel = 0;
-
-    dataSize = ySize = cSize = cStride = 0;
-    int32_t fmt = buffer->flexFormat;
-
-    bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, readerFormat);
-    fmt = applyFormatOverrides(fmt, readerFormat);
-    switch (fmt) {
-        case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            pData =
-                (idx == 0) ?
-                    buffer->data :
-                (idx == 1) ?
-                    buffer->dataCb :
-                buffer->dataCr;
-            // only map until last pixel
-            if (idx == 0) {
-                dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
-            } else {
-                dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
-                        buffer->chromaStep * (buffer->width / 2 - 1) + 1;
-            }
-            break;
-        // NV21
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            cr = buffer->data + (buffer->stride * buffer->height);
-            cb = cr + 1;
-            // only map until last pixel
-            ySize = buffer->width * (buffer->height - 1) + buffer->width;
-            cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
-
-            pData =
-                (idx == 0) ?
-                    buffer->data :
-                (idx == 1) ?
-                    cb:
-                cr;
-
-            dataSize = (idx == 0) ? ySize : cSize;
-            break;
-        case HAL_PIXEL_FORMAT_YV12:
-            // Y and C stride need to be 16 pixel aligned.
-            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
-                                "Stride is not 16 pixel aligned %d", buffer->stride);
-
-            ySize = buffer->stride * buffer->height;
-            cStride = ALIGN(buffer->stride / 2, 16);
-            cr = buffer->data + ySize;
-            cSize = cStride * buffer->height / 2;
-            cb = cr + cSize;
-
-            pData =
-                (idx == 0) ?
-                    buffer->data :
-                (idx == 1) ?
-                    cb :
-                cr;
-            dataSize = (idx == 0) ? ySize : cSize;
-            break;
-        case HAL_PIXEL_FORMAT_Y8:
-            // Single plane, 8bpp.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height;
-            break;
-        case HAL_PIXEL_FORMAT_Y16:
-            bytesPerPixel = 2;
-            // Single plane, 16bpp, strides are specified in pixels, not in bytes
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            break;
-        case HAL_PIXEL_FORMAT_BLOB:
-            // Used for JPEG data, height must be 1, width == size, single plane.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            ALOG_ASSERT(buffer->height == 1,
-                    "JPEG should has height value one but got %d", buffer->height);
-
-            pData = buffer->data;
-            dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
-            break;
-        case HAL_PIXEL_FORMAT_RAW16:
-            // Single plane 16bpp bayer data.
-            bytesPerPixel = 2;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            break;
-        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
-            // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            ALOG_ASSERT(buffer->height == 1,
-                    "RAW_PRIVATE should has height value one but got %d", buffer->height);
-            pData = buffer->data;
-            dataSize = buffer->width;
-            break;
-        case HAL_PIXEL_FORMAT_RAW10:
-            // Single plane 10bpp bayer data.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            LOG_ALWAYS_FATAL_IF(buffer->width % 4,
-                                "Width is not multiple of 4 %d", buffer->width);
-            LOG_ALWAYS_FATAL_IF(buffer->height % 2,
-                                "Height is not even %d", buffer->height);
-            LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
-                                "stride (%d) should be at least %d",
-                                buffer->stride, buffer->width * 10 / 8);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height;
-            break;
-        case HAL_PIXEL_FORMAT_RAW12:
-            // Single plane 10bpp bayer data.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            LOG_ALWAYS_FATAL_IF(buffer->width % 4,
-                                "Width is not multiple of 4 %d", buffer->width);
-            LOG_ALWAYS_FATAL_IF(buffer->height % 2,
-                                "Height is not even %d", buffer->height);
-            LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 12 / 8),
-                                "stride (%d) should be at least %d",
-                                buffer->stride, buffer->width * 12 / 8);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height;
-            break;
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-            // Single plane, 32bpp.
-            bytesPerPixel = 4;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            break;
-        case HAL_PIXEL_FORMAT_RGB_565:
-            // Single plane, 16bpp.
-            bytesPerPixel = 2;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            break;
-        case HAL_PIXEL_FORMAT_RGB_888:
-            // Single plane, 24bpp.
-            bytesPerPixel = 3;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            break;
-        default:
-            jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
-                                 "Pixel format: 0x%x is unsupported", fmt);
-            break;
-    }
-
-    *base = pData;
-    *size = dataSize;
-}
-
-static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
-        int32_t halReaderFormat)
-{
-    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
-    ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx);
-
-    int pixelStride = 0;
-    ALOG_ASSERT(buffer != NULL, "buffer is NULL");
-
-    int32_t fmt = buffer->flexFormat;
-
-    fmt = applyFormatOverrides(fmt, halReaderFormat);
-
-    switch (fmt) {
-        case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            pixelStride = (idx == 0) ? 1 : buffer->chromaStep;
-            break;
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            pixelStride = (idx == 0) ? 1 : 2;
-            break;
-        case HAL_PIXEL_FORMAT_Y8:
-            // Single plane 8bpp data.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pixelStride = 1;
-            break;
-        case HAL_PIXEL_FORMAT_YV12:
-            pixelStride = 1;
-            break;
-        case HAL_PIXEL_FORMAT_BLOB:
-        case HAL_PIXEL_FORMAT_RAW10:
-        case HAL_PIXEL_FORMAT_RAW12:
-            // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
-            // those are single plane data with pixel stride 0 since they don't really have a
-            // well defined pixel stride
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pixelStride = 0;
-            break;
-        case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW16:
-        case HAL_PIXEL_FORMAT_RGB_565:
-            // Single plane 16bpp data.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pixelStride = 2;
-            break;
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pixelStride = 4;
-            break;
-        case HAL_PIXEL_FORMAT_RGB_888:
-            // Single plane, 24bpp.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pixelStride = 3;
-            break;
-        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pixelStride = 0; // RAW OPAQUE doesn't have pixel stride
-            break;
-        default:
-            jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
-                                 "Pixel format: 0x%x is unsupported", fmt);
-            break;
-    }
-
-    return pixelStride;
-}
-
-static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
-        int32_t halReaderFormat)
-{
-    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
-    ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
-
-    int rowStride = 0;
-    ALOG_ASSERT(buffer != NULL, "buffer is NULL");
-
-    int32_t fmt = buffer->flexFormat;
-
-    fmt = applyFormatOverrides(fmt, halReaderFormat);
-
-    switch (fmt) {
-        case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            rowStride = (idx == 0) ? buffer->stride : buffer->chromaStride;
-            break;
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            rowStride = buffer->width;
-            break;
-        case HAL_PIXEL_FORMAT_YV12:
-            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
-                                "Stride is not 16 pixel aligned %d", buffer->stride);
-            rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
-            break;
-        case HAL_PIXEL_FORMAT_BLOB:
-            // Blob is used for JPEG data. It is single plane and has 0 row stride and
-            // 0 pixel stride
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            rowStride = 0;
-            break;
-        case HAL_PIXEL_FORMAT_RAW10:
-        case HAL_PIXEL_FORMAT_RAW12:
-            // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            rowStride = buffer->stride;
-            break;
-        case HAL_PIXEL_FORMAT_Y8:
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
-                                "Stride is not 16 pixel aligned %d", buffer->stride);
-            rowStride = buffer->stride;
-            break;
-        case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW16:
-            // In native side, strides are specified in pixels, not in bytes.
-            // Single plane 16bpp bayer data. even width/height,
-            // row stride multiple of 16 pixels (32 bytes)
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
-                                "Stride is not 16 pixel aligned %d", buffer->stride);
-            rowStride = buffer->stride * 2;
-            break;
-        case HAL_PIXEL_FORMAT_RGB_565:
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            rowStride = buffer->stride * 2;
-            break;
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            rowStride = buffer->stride * 4;
-            break;
-        case HAL_PIXEL_FORMAT_RGB_888:
-            // Single plane, 24bpp.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            rowStride = buffer->stride * 3;
-            break;
-        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            rowStride = 0; // RAW OPAQUE doesn't have row stride
-            break;
-        default:
-            ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
-            jniThrowException(env, "java/lang/UnsupportedOperationException",
-                              "unsupported buffer format");
-          break;
-    }
-
-    return rowStride;
-}
-
-static int Image_getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
-    if (buffer == NULL) return -1;
-
-    if (!buffer->crop.isEmpty()) {
-        return buffer->crop.getWidth();
-    }
-    return buffer->width;
-}
-
-static int Image_getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
-    if (buffer == NULL) return -1;
-
-    if (!buffer->crop.isEmpty()) {
-        return buffer->crop.getHeight();
-    }
-    return buffer->height;
-}
-
-// --------------------------Methods for opaque Image and ImageReader----------
-
-static BufferItemConsumer* ImageReader_getOpaqueConsumer(JNIEnv* env, jobject thiz)
+static BufferItemConsumer* ImageReader_getBufferConsumer(JNIEnv* env, jobject thiz)
 {
     ALOGV("%s:", __FUNCTION__);
     JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
@@ -728,40 +263,21 @@
         return NULL;
     }
 
-    if (!ctx->isOpaque()) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                "Non-opaque ImageReader doesn't support this method");
-    }
-
-    return ctx->getOpaqueConsumer();
+    return ctx->getBufferConsumer();
 }
 
-static BufferItem* Image_getOpaqueBuffer(JNIEnv* env, jobject image)
+static void Image_setBufferItem(JNIEnv* env, jobject thiz,
+        const BufferItem* buffer)
+{
+    env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
+}
+
+static BufferItem* Image_getBufferItem(JNIEnv* env, jobject image)
 {
     return reinterpret_cast<BufferItem*>(
             env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
 }
 
-static int Image_getOpaqueBufferWidth(BufferItem* buffer) {
-    if (buffer == NULL) return -1;
-
-    if (!buffer->mCrop.isEmpty()) {
-        return buffer->mCrop.getWidth();
-    }
-    return buffer->mGraphicBuffer->getWidth();
-}
-
-static int Image_getOpaqueBufferHeight(BufferItem* buffer) {
-    if (buffer == NULL) return -1;
-
-    if (!buffer->mCrop.isEmpty()) {
-        return buffer->mCrop.getHeight();
-    }
-
-    return buffer->mGraphicBuffer->getHeight();
-}
-
-
 
 // ----------------------------------------------------------------------------
 
@@ -784,6 +300,11 @@
                         "can't find android/graphics/ImageReader.%s",
                         ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID);
 
+    gSurfaceImageClassInfo.mPlanes = env->GetFieldID(
+            imageClazz, "mPlanes", "[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;");
+    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mPlanes == NULL,
+            "can't find android/media/ImageReader$ReaderSurfaceImage.mPlanes");
+
     gImageReaderClassInfo.mNativeContext = env->GetFieldID(
             clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J");
     LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL,
@@ -800,7 +321,7 @@
     // FindClass only gives a local reference of jclass object.
     gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
     gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>",
-            "(Landroid/media/ImageReader$SurfaceImage;III)V");
+            "(Landroid/media/ImageReader$SurfaceImage;IILjava/nio/ByteBuffer;)V");
     LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL,
             "Can not find SurfacePlane constructor");
 }
@@ -831,81 +352,52 @@
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
     BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
-    sp<ConsumerBase> consumer;
-    sp<CpuConsumer> cpuConsumer;
-    sp<BufferItemConsumer> opaqueConsumer;
+    sp<BufferItemConsumer> bufferConsumer;
     String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
             width, height, format, maxImages, getpid(),
             createProcessUniqueId());
+    uint32_t consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+
     if (isFormatOpaque(nativeFormat)) {
         // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
         // encoding. The only possibility will be ZSL output.
-        opaqueConsumer =
-                new BufferItemConsumer(gbConsumer, GRALLOC_USAGE_SW_READ_NEVER, maxImages,
-                        /*controlledByApp*/true);
-        if (opaqueConsumer == NULL) {
-            jniThrowRuntimeException(env, "Failed to allocate native opaque consumer");
-            return;
-        }
-        ctx->setOpaqueConsumer(opaqueConsumer);
-        opaqueConsumer->setName(consumerName);
-        consumer = opaqueConsumer;
-    } else {
-        cpuConsumer = new CpuConsumer(gbConsumer, maxImages, /*controlledByApp*/true);
-        // TODO: throw dvm exOutOfMemoryError?
-        if (cpuConsumer == NULL) {
-            jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
-            return;
-        }
-        ctx->setCpuConsumer(cpuConsumer);
-        cpuConsumer->setName(consumerName);
-        consumer = cpuConsumer;
+        consumerUsage = GRALLOC_USAGE_SW_READ_NEVER;
     }
+    bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
+            /*controlledByApp*/true);
+    if (bufferConsumer == nullptr) {
+        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+                "Failed to allocate native buffer consumer for format 0x%x", nativeFormat);
+        return;
+    }
+    ctx->setBufferConsumer(bufferConsumer);
+    bufferConsumer->setName(consumerName);
 
     ctx->setProducer(gbProducer);
-    consumer->setFrameAvailableListener(ctx);
+    bufferConsumer->setFrameAvailableListener(ctx);
     ImageReader_setNativeContext(env, thiz, ctx);
     ctx->setBufferFormat(nativeFormat);
     ctx->setBufferDataspace(nativeDataspace);
     ctx->setBufferWidth(width);
     ctx->setBufferHeight(height);
 
-    // Set the width/height/format/dataspace to the CpuConsumer
-    // TODO: below code can be simplified once b/19977701 is fixed.
-    if (isFormatOpaque(nativeFormat)) {
-        res = opaqueConsumer->setDefaultBufferSize(width, height);
-        if (res != OK) {
-            jniThrowException(env, "java/lang/IllegalStateException",
-                              "Failed to set opaque consumer buffer size");
-            return;
-        }
-        res = opaqueConsumer->setDefaultBufferFormat(nativeFormat);
-        if (res != OK) {
-            jniThrowException(env, "java/lang/IllegalStateException",
-                              "Failed to set opaque consumer buffer format");
-        }
-        res = opaqueConsumer->setDefaultBufferDataSpace(nativeDataspace);
-        if (res != OK) {
-            jniThrowException(env, "java/lang/IllegalStateException",
-                              "Failed to set opaque consumer buffer dataSpace");
-        }
-    } else {
-        res = cpuConsumer->setDefaultBufferSize(width, height);
-        if (res != OK) {
-            jniThrowException(env, "java/lang/IllegalStateException",
-                              "Failed to set CpuConsumer buffer size");
-            return;
-        }
-        res = cpuConsumer->setDefaultBufferFormat(nativeFormat);
-        if (res != OK) {
-            jniThrowException(env, "java/lang/IllegalStateException",
-                              "Failed to set CpuConsumer buffer format");
-        }
-        res = cpuConsumer->setDefaultBufferDataSpace(nativeDataspace);
-        if (res != OK) {
-            jniThrowException(env, "java/lang/IllegalStateException",
-                              "Failed to set CpuConsumer buffer dataSpace");
-        }
+    // Set the width/height/format/dataspace to the bufferConsumer.
+    res = bufferConsumer->setDefaultBufferSize(width, height);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                          "Failed to set buffer consumer default size (%dx%d) for format 0x%x",
+                          width, height, nativeFormat);
+        return;
+    }
+    res = bufferConsumer->setDefaultBufferFormat(nativeFormat);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                          "Failed to set buffer consumer default format 0x%x", nativeFormat);
+    }
+    res = bufferConsumer->setDefaultBufferDataSpace(nativeDataspace);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                          "Failed to set buffer consumer default dataSpace 0x%x", nativeDataspace);
     }
 }
 
@@ -919,12 +411,8 @@
         return;
     }
 
-    ConsumerBase* consumer = NULL;
-    if (ctx->isOpaque()) {
-        consumer = ImageReader_getOpaqueConsumer(env, thiz);
-    } else {
-        consumer = ImageReader_getCpuConsumer(env, thiz);
-    }
+    BufferItemConsumer* consumer = NULL;
+    consumer = ImageReader_getBufferConsumer(env, thiz);
 
     if (consumer != NULL) {
         consumer->abandon();
@@ -933,6 +421,39 @@
     ImageReader_setNativeContext(env, thiz, NULL);
 }
 
+static sp<Fence> Image_unlockIfLocked(JNIEnv* env, jobject image) {
+    ALOGV("%s", __FUNCTION__);
+    BufferItem* buffer = Image_getBufferItem(env, image);
+    if (buffer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Image is not initialized");
+        return Fence::NO_FENCE;
+    }
+
+    // Is locked?
+    bool wasBufferLocked = false;
+    jobject planes = NULL;
+    if (!isFormatOpaque(buffer->mGraphicBuffer->getPixelFormat())) {
+        planes = env->GetObjectField(image, gSurfaceImageClassInfo.mPlanes);
+    }
+    wasBufferLocked = (planes != NULL);
+    if (wasBufferLocked) {
+        status_t res = OK;
+        int fenceFd = -1;
+        if (wasBufferLocked) {
+            res = buffer->mGraphicBuffer->unlockAsync(&fenceFd);
+            if (res != OK) {
+                jniThrowRuntimeException(env, "unlock buffer failed");
+                return Fence::NO_FENCE;
+            }
+        }
+        sp<Fence> releaseFence = new Fence(fenceFd);
+        return releaseFence;
+        ALOGV("Successfully unlocked the image");
+    }
+    return Fence::NO_FENCE;
+}
+
 static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)
 {
     ALOGV("%s:", __FUNCTION__);
@@ -942,156 +463,18 @@
         return;
     }
 
-    if (ctx->isOpaque()) {
-        BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
-        BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
-        opaqueConsumer->releaseBuffer(*opaqueBuffer); // Not using fence for now.
-        Image_setOpaqueBuffer(env, image, NULL);
-        ctx->returnOpaqueBuffer(opaqueBuffer);
-        ALOGV("%s: Opaque Image has been released", __FUNCTION__);
-    } else {
-        CpuConsumer* consumer = ctx->getCpuConsumer();
-        CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image);
-        if (!buffer) {
-            // Release an already closed image is harmless.
-            return;
-        }
-        consumer->unlockBuffer(*buffer);
-        Image_setBuffer(env, image, NULL);
-        ctx->returnLockedBuffer(buffer);
-        ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
-    }
-}
-
-static jint ImageReader_opaqueImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
-    ALOGV("%s:", __FUNCTION__);
-    if (ctx == NULL || !ctx->isOpaque()) {
-        jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
-        return -1;
+    BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
+    BufferItem* buffer = Image_getBufferItem(env, image);
+    if (buffer == nullptr) {
+        // Release an already closed image is harmless.
+        return;
     }
 
-    BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
-    BufferItem* buffer = ctx->getOpaqueBuffer();
-    if (buffer == NULL) {
-        ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
-            " maxImages buffers");
-        return ACQUIRE_MAX_IMAGES;
-    }
-
-    status_t res = opaqueConsumer->acquireBuffer(buffer, 0);
-    if (res != OK) {
-        ctx->returnOpaqueBuffer(buffer);
-        if (res == INVALID_OPERATION) {
-            // Max number of images were already acquired.
-            ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-            return ACQUIRE_MAX_IMAGES;
-        } else {
-            ALOGE("%s: Acquire image failed with error: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-            return ACQUIRE_NO_BUFFERS;
-        }
-    }
-
-    // Set SurfaceImage instance member variables
-    Image_setOpaqueBuffer(env, image, buffer);
-    env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
-            static_cast<jlong>(buffer->mTimestamp));
-
-    return ACQUIRE_SUCCESS;
-}
-
-static jint ImageReader_lockedImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
-    CpuConsumer* consumer = ctx->getCpuConsumer();
-    CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer();
-    if (buffer == NULL) {
-        ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
-            " maxImages buffers");
-        return ACQUIRE_MAX_IMAGES;
-    }
-    status_t res = consumer->lockNextBuffer(buffer);
-    if (res != NO_ERROR) {
-        ctx->returnLockedBuffer(buffer);
-        if (res != BAD_VALUE /*no buffers*/) {
-            if (res == NOT_ENOUGH_DATA) {
-                return ACQUIRE_MAX_IMAGES;
-            } else {
-                ALOGE("%s Fail to lockNextBuffer with error: %d ",
-                      __FUNCTION__, res);
-                jniThrowExceptionFmt(env, "java/lang/AssertionError",
-                          "Unknown error (%d) when we tried to lock buffer.",
-                          res);
-            }
-        }
-        return ACQUIRE_NO_BUFFERS;
-    }
-
-    if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
-        jniThrowException(env, "java/lang/UnsupportedOperationException",
-                "NV21 format is not supported by ImageReader");
-        return -1;
-    }
-
-    // Check if the left-top corner of the crop rect is origin, we currently assume this point is
-    // zero, will revist this once this assumption turns out problematic.
-    Point lt = buffer->crop.leftTop();
-    if (lt.x != 0 || lt.y != 0) {
-        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
-                "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
-        return -1;
-    }
-
-    // Check if the producer buffer configurations match what ImageReader configured.
-    int outputWidth = Image_getBufferWidth(buffer);
-    int outputHeight = Image_getBufferHeight(buffer);
-
-    int imgReaderFmt = ctx->getBufferFormat();
-    int imageReaderWidth = ctx->getBufferWidth();
-    int imageReaderHeight = ctx->getBufferHeight();
-    if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
-            (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
-        ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
-                __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
-    }
-
-    int bufFmt = buffer->format;
-    if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-        bufFmt = buffer->flexFormat;
-    }
-    if (imgReaderFmt != bufFmt) {
-        if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
-                HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
-            // Special casing for when producer switches to a format compatible with flexible YUV
-            // (HAL_PIXEL_FORMAT_YCbCr_420_888).
-            ctx->setBufferFormat(bufFmt);
-            ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
-        } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB && bufFmt == HAL_PIXEL_FORMAT_RGBA_8888) {
-            // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
-            // write limitations for (b/17379185).
-            ALOGD("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__);
-        } else {
-            // Return the buffer to the queue.
-            consumer->unlockBuffer(*buffer);
-            ctx->returnLockedBuffer(buffer);
-
-            // Throw exception
-            ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
-                    buffer->format, ctx->getBufferFormat());
-            String8 msg;
-            msg.appendFormat("The producer output buffer format 0x%x doesn't "
-                    "match the ImageReader's configured buffer format 0x%x.",
-                    bufFmt, ctx->getBufferFormat());
-            jniThrowException(env, "java/lang/UnsupportedOperationException",
-                    msg.string());
-            return -1;
-        }
-    }
-    // Set SurfaceImage instance member variables
-    Image_setBuffer(env, image, buffer);
-    env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
-            static_cast<jlong>(buffer->timestamp));
-
-    return ACQUIRE_SUCCESS;
+    sp<Fence> releaseFence = Image_unlockIfLocked(env, image);
+    bufferConsumer->releaseBuffer(*buffer, releaseFence);
+    Image_setBufferItem(env, image, NULL);
+    ctx->returnBufferItem(buffer);
+    ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
 }
 
 static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
@@ -1103,11 +486,99 @@
         return -1;
     }
 
-    if (ctx->isOpaque()) {
-        return ImageReader_opaqueImageSetup(env, ctx, image);
-    } else {
-        return ImageReader_lockedImageSetup(env, ctx, image);
+    BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
+    BufferItem* buffer = ctx->getBufferItem();
+    if (buffer == NULL) {
+        ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
+            " maxImages buffers");
+        return ACQUIRE_MAX_IMAGES;
     }
+
+    status_t res = bufferConsumer->acquireBuffer(buffer, 0);
+    if (res != OK) {
+        ctx->returnBufferItem(buffer);
+        if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
+            if (res == INVALID_OPERATION) {
+                // Max number of images were already acquired.
+                ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)",
+                        __FUNCTION__, strerror(-res), res);
+                return ACQUIRE_MAX_IMAGES;
+            } else {
+                ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
+                        __FUNCTION__, strerror(-res), res);
+                jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                        "Unknown error (%d) when we tried to acquire an image.",
+                                          res);
+                return ACQUIRE_NO_BUFFERS;
+            }
+        }
+        // This isn't really an error case, as the application may acquire buffer at any time.
+        return ACQUIRE_NO_BUFFERS;
+    }
+
+    // Add some extra checks for non-opaque formats.
+    if (!isFormatOpaque(ctx->getBufferFormat())) {
+        // Check if the left-top corner of the crop rect is origin, we currently assume this point is
+        // zero, will revisit this once this assumption turns out problematic.
+        Point lt = buffer->mCrop.leftTop();
+        if (lt.x != 0 || lt.y != 0) {
+            jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                    "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
+            return -1;
+        }
+
+        // Check if the producer buffer configurations match what ImageReader configured.
+        int outputWidth = getBufferWidth(buffer);
+        int outputHeight = getBufferHeight(buffer);
+
+        int imgReaderFmt = ctx->getBufferFormat();
+        int imageReaderWidth = ctx->getBufferWidth();
+        int imageReaderHeight = ctx->getBufferHeight();
+        int bufferFormat = buffer->mGraphicBuffer->getPixelFormat();
+        if ((bufferFormat != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
+                (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
+            ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
+                    __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
+        }
+        if (imgReaderFmt != bufferFormat) {
+            if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
+                    isPossiblyYUV(bufferFormat)) {
+                // Treat formats that are compatible with flexible YUV
+                // (HAL_PIXEL_FORMAT_YCbCr_420_888) as HAL_PIXEL_FORMAT_YCbCr_420_888.
+                ALOGV("%s: Treat buffer format to 0x%x as HAL_PIXEL_FORMAT_YCbCr_420_888",
+                        __FUNCTION__, bufferFormat);
+            } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB &&
+                    bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888) {
+                // Using HAL_PIXEL_FORMAT_RGBA_8888 Gralloc buffers containing JPEGs to get around
+                // SW write limitations for (b/17379185).
+                ALOGV("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__);
+            } else {
+                // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
+                // used anywhere yet.
+                bufferConsumer->releaseBuffer(*buffer);
+                ctx->returnBufferItem(buffer);
+
+                // Throw exception
+                ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
+                        bufferFormat, ctx->getBufferFormat());
+                String8 msg;
+                msg.appendFormat("The producer output buffer format 0x%x doesn't "
+                        "match the ImageReader's configured buffer format 0x%x.",
+                        bufferFormat, ctx->getBufferFormat());
+                jniThrowException(env, "java/lang/UnsupportedOperationException",
+                        msg.string());
+                return -1;
+            }
+        }
+
+    }
+
+    // Set SurfaceImage instance member variables
+    Image_setBufferItem(env, image, buffer);
+    env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
+            static_cast<jlong>(buffer->mTimestamp));
+
+    return ACQUIRE_SUCCESS;
 }
 
 static jint ImageReader_detachImage(JNIEnv* env, jobject thiz, jobject image) {
@@ -1118,29 +589,23 @@
         return -1;
     }
 
-    status_t res = OK;
-    if (!ctx->isOpaque()) {
-        // TODO: Non-Opaque format detach is not implemented yet.
-        jniThrowRuntimeException(env,
-                "nativeDetachImage is not implemented yet for non-opaque format !!!");
-        return -1;
-    }
-
-    BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
-    BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
-    if (!opaqueBuffer) {
+    BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
+    BufferItem* buffer = Image_getBufferItem(env, image);
+    if (!buffer) {
         ALOGE(
-                "Opaque Image already released and can not be detached from ImageReader!!!");
+                "Image already released and can not be detached from ImageReader!!!");
         jniThrowException(env, "java/lang/IllegalStateException",
-                "Opaque Image detach from ImageReader failed: buffer was already released");
+                "Image detach from ImageReader failed: buffer was already released");
         return -1;
     }
 
-    res = opaqueConsumer->detachBuffer(opaqueBuffer->mSlot);
+    status_t res = OK;
+    Image_unlockIfLocked(env, image);
+    res = bufferConsumer->detachBuffer(buffer->mSlot);
     if (res != OK) {
-        ALOGE("Opaque Image detach failed: %s (%d)!!!", strerror(-res), res);
+        ALOGE("Image detach failed: %s (%d)!!!", strerror(-res), res);
         jniThrowRuntimeException(env,
-                "nativeDetachImage failed for opaque image!!!");
+                "nativeDetachImage failed for image!!!");
         return res;
     }
     return OK;
@@ -1152,7 +617,7 @@
 
     IGraphicBufferProducer* gbp = ImageReader_getProducer(env, thiz);
     if (gbp == NULL) {
-        jniThrowRuntimeException(env, "CpuConsumer is uninitialized");
+        jniThrowRuntimeException(env, "Buffer consumer is uninitialized");
         return NULL;
     }
 
@@ -1160,98 +625,115 @@
     return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
 }
 
-static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int readerFormat)
+static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
+    ALOGV("%s", __FUNCTION__);
+    BufferItem* buffer = Image_getBufferItem(env, thiz);
+    if (buffer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Image is not initialized");
+        return;
+    }
+
+    status_t res = lockImageFromBuffer(buffer,
+            GRALLOC_USAGE_SW_READ_OFTEN, buffer->mFence->dup(), image);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+                "lock buffer failed for format 0x%x",
+                buffer->mGraphicBuffer->getPixelFormat());
+        return;
+    }
+
+    // Carry over some fields from BufferItem.
+    image->crop        = buffer->mCrop;
+    image->transform   = buffer->mTransform;
+    image->scalingMode = buffer->mScalingMode;
+    image->timestamp   = buffer->mTimestamp;
+    image->dataSpace   = buffer->mDataSpace;
+    image->frameNumber = buffer->mFrameNumber;
+
+    ALOGV("%s: Successfully locked the image", __FUNCTION__);
+    // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
+    // and we don't set them here.
+}
+
+static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
+        int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
+    ALOGV("%s", __FUNCTION__);
+
+    status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
+            pixelStride, rowStride);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                             "Pixel format: 0x%x is unsupported", buffer->flexFormat);
+    }
+}
+
+static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
+        int numPlanes, int readerFormat)
 {
-    int rowStride, pixelStride;
+    ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
+    int rowStride = 0;
+    int pixelStride = 0;
+    uint8_t *pData = NULL;
+    uint32_t dataSize = 0;
+    jobject byteBuffer = NULL;
+
     PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
     int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
         publicReaderFormat);
 
-    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
+    if (isFormatOpaque(halReaderFormat) && numPlanes > 0) {
+        String8 msg;
+        msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
+                " must be 0", halReaderFormat, numPlanes);
+        jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
+        return NULL;
+    }
+
+    jobjectArray surfacePlanes = env->NewObjectArray(numPlanes, gSurfacePlaneClassInfo.clazz,
+            /*initial_element*/NULL);
+    if (surfacePlanes == NULL) {
+        jniThrowRuntimeException(env, "Failed to create SurfacePlane arrays,"
+                " probably out of memory");
+        return NULL;
+    }
     if (isFormatOpaque(halReaderFormat)) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                "Opaque images from Opaque ImageReader do not have any planes");
-        return NULL;
+        // Return 0 element surface array.
+        return surfacePlanes;
     }
 
-    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+    LockedImage lockedImg = LockedImage();
+    Image_getLockedImage(env, thiz, &lockedImg);
+    // Create all SurfacePlanes
+    for (int i = 0; i < numPlanes; i++) {
+        Image_getLockedImageInfo(env, &lockedImg, i, halReaderFormat,
+                &pData, &dataSize, &pixelStride, &rowStride);
+        byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
+        if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                    "Failed to allocate ByteBuffer");
+            return NULL;
+        }
 
-    ALOG_ASSERT(buffer != NULL);
-    if (buffer == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
+        // Finally, create this SurfacePlane.
+        jobject surfacePlane = env->NewObject(gSurfacePlaneClassInfo.clazz,
+                    gSurfacePlaneClassInfo.ctor, thiz, rowStride, pixelStride, byteBuffer);
+        env->SetObjectArrayElement(surfacePlanes, i, surfacePlane);
     }
 
-    rowStride = Image_imageGetRowStride(env, buffer, idx, halReaderFormat);
-    pixelStride = Image_imageGetPixelStride(env, buffer, idx, halReaderFormat);
-
-    jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
-            gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
-
-    return surfPlaneObj;
+    return surfacePlanes;
 }
 
-static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx, int readerFormat)
+static jint Image_getWidth(JNIEnv* env, jobject thiz)
 {
-    uint8_t *base = NULL;
-    uint32_t size = 0;
-    jobject byteBuffer;
-    PublicFormat readerPublicFormat = static_cast<PublicFormat>(readerFormat);
-    int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
-            readerPublicFormat);
-
-    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
-
-    if (isFormatOpaque(readerHalFormat)) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                "Opaque images from Opaque ImageReader do not have any plane");
-        return NULL;
-    }
-
-    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
-
-    if (buffer == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
-    }
-
-    // Create byteBuffer from native buffer
-    Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerHalFormat);
-
-    if (size > static_cast<uint32_t>(INT32_MAX)) {
-        // Byte buffer have 'int capacity', so check the range
-        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
-                "Size too large for bytebuffer capacity %" PRIu32, size);
-        return NULL;
-    }
-
-    byteBuffer = env->NewDirectByteBuffer(base, size);
-    // TODO: throw dvm exOutOfMemoryError?
-    if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
-        jniThrowException(env, "java/lang/IllegalStateException", "Failed to allocate ByteBuffer");
-    }
-
-    return byteBuffer;
+    BufferItem* buffer = Image_getBufferItem(env, thiz);
+    return getBufferWidth(buffer);
 }
 
-static jint Image_getWidth(JNIEnv* env, jobject thiz, jint format)
+static jint Image_getHeight(JNIEnv* env, jobject thiz)
 {
-    if (isFormatOpaque(format)) {
-        BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
-        return Image_getOpaqueBufferWidth(opaqueBuffer);
-    } else {
-        CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
-        return Image_getBufferWidth(buffer);
-    }
-}
-
-static jint Image_getHeight(JNIEnv* env, jobject thiz, jint format)
-{
-    if (isFormatOpaque(format)) {
-        BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
-        return Image_getOpaqueBufferHeight(opaqueBuffer);
-    } else {
-        CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
-        return Image_getBufferHeight(buffer);
-    }
+    BufferItem* buffer = Image_getBufferItem(env, thiz);
+    return getBufferHeight(buffer);
 }
 
 static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat)
@@ -1260,12 +742,21 @@
         // Assuming opaque reader produce opaque images.
         return static_cast<jint>(PublicFormat::PRIVATE);
     } else {
-        CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+        BufferItem* buffer = Image_getBufferItem(env, thiz);
         int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
                 static_cast<PublicFormat>(readerFormat));
-        int32_t fmt = applyFormatOverrides(buffer->flexFormat, readerHalFormat);
+        int32_t fmt = applyFormatOverrides(
+                buffer->mGraphicBuffer->getPixelFormat(), readerHalFormat);
+        // Override the image format to HAL_PIXEL_FORMAT_YCbCr_420_888 if the actual format is
+        // NV21 or YV12. This could only happen when the Gralloc HAL version is v0.1 thus doesn't
+        // support lockycbcr(), the CpuConsumer need to use the lock() method in the
+        // lockNextBuffer() call. For Gralloc HAL v0.2 or newer, this format should already be
+        // overridden to HAL_PIXEL_FORMAT_YCbCr_420_888 for the flexible YUV compatible formats.
+        if (isPossiblyYUV(fmt)) {
+            fmt = HAL_PIXEL_FORMAT_YCbCr_420_888;
+        }
         PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
-                fmt, buffer->dataSpace);
+                fmt, buffer->mDataSpace);
         return static_cast<jint>(publicFmt);
     }
 }
@@ -1285,11 +776,10 @@
 };
 
 static const JNINativeMethod gImageMethods[] = {
-    {"nativeImageGetBuffer",   "(II)Ljava/nio/ByteBuffer;",   (void*)Image_getByteBuffer },
-    {"nativeCreatePlane",      "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
-                                                              (void*)Image_createSurfacePlane },
-    {"nativeGetWidth",         "(I)I",                        (void*)Image_getWidth },
-    {"nativeGetHeight",        "(I)I",                        (void*)Image_getHeight },
+    {"nativeCreatePlanes",      "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
+                                                              (void*)Image_createSurfacePlanes },
+    {"nativeGetWidth",         "()I",                        (void*)Image_getWidth },
+    {"nativeGetHeight",        "()I",                        (void*)Image_getHeight },
     {"nativeGetFormat",        "(I)I",                        (void*)Image_getFormat },
 };
 
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index f50da85..d5d9fc9 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -16,34 +16,28 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ImageWriter_JNI"
+#include "android_media_Utils.h"
+
 #include <utils/Log.h>
 #include <utils/String8.h>
 
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
-#include <gui/CpuConsumer.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <camera3.h>
-
 #include <jni.h>
 #include <JNIHelp.h>
 
 #include <stdint.h>
 #include <inttypes.h>
 
-#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
-
 #define IMAGE_BUFFER_JNI_ID           "mNativeBuffer"
 
 // ----------------------------------------------------------------------------
 
 using namespace android;
 
-enum {
-    IMAGE_WRITER_MAX_NUM_PLANES = 3,
-};
-
 static struct {
     jmethodID postEventFromNative;
     jfieldID mWriterFormat;
@@ -60,8 +54,6 @@
     jmethodID ctor;
 } gSurfacePlaneClassInfo;
 
-typedef CpuConsumer::LockedBuffer LockedImage;
-
 // ----------------------------------------------------------------------------
 
 class JNIImageWriterContext : public BnProducerListener {
@@ -181,13 +173,11 @@
 
 // -------------------------------Private method declarations--------------
 
-static bool isPossiblyYUV(PixelFormat format);
 static void Image_setNativeContext(JNIEnv* env, jobject thiz,
         sp<GraphicBuffer> buffer, int fenceFd);
 static void Image_getNativeContext(JNIEnv* env, jobject thiz,
         GraphicBuffer** buffer, int* fenceFd);
 static void Image_unlockIfLocked(JNIEnv* env, jobject thiz);
-static bool isFormatOpaque(int format);
 
 // --------------------------ImageWriter methods---------------------------------------
 
@@ -672,28 +662,6 @@
     return buffer->getHeight();
 }
 
-// Some formats like JPEG defined with different values between android.graphics.ImageFormat and
-// graphics.h, need convert to the one defined in graphics.h here.
-static int Image_getPixelFormat(JNIEnv* env, int format) {
-    int jpegFormat;
-    jfieldID fid;
-
-    ALOGV("%s: format = 0x%x", __FUNCTION__, format);
-
-    jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
-    ALOG_ASSERT(imageFormatClazz != NULL);
-
-    fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
-    jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);
-
-    // Translate the JPEG to BLOB for camera purpose.
-    if (format == jpegFormat) {
-        format = HAL_PIXEL_FORMAT_BLOB;
-    }
-
-    return format;
-}
-
 static jint Image_getFormat(JNIEnv* env, jobject thiz) {
     ALOGV("%s", __FUNCTION__);
     GraphicBuffer* buffer;
@@ -704,7 +672,10 @@
         return 0;
     }
 
-    return Image_getPixelFormat(env, buffer->getPixelFormat());
+    // ImageWriter doesn't support data space yet, assuming it is unknown.
+    PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
+            buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN);
+    return static_cast<jint>(publicFmt);
 }
 
 static void Image_setFenceFd(JNIEnv* env, jobject thiz, int fenceFd) {
@@ -723,272 +694,34 @@
         return;
     }
 
-    void* pData = NULL;
-    android_ycbcr ycbcr = android_ycbcr();
-    status_t res;
-    int format = Image_getFormat(env, thiz);
-    int flexFormat = format;
-    if (isPossiblyYUV(format)) {
-        // ImageWriter doesn't use crop by itself, app sets it, use the no crop version.
-        res = buffer->lockAsyncYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr, fenceFd);
-        // Clear the fenceFd as it is already consumed by lock call.
-        Image_setFenceFd(env, thiz, /*fenceFd*/-1);
-        if (res != OK) {
-            jniThrowRuntimeException(env, "lockAsyncYCbCr failed for YUV buffer");
-            return;
-        }
-        pData = ycbcr.y;
-        flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+    // ImageWriter doesn't use crop by itself, app sets it, use the no crop version.
+    const Rect noCrop(buffer->width, buffer->height);
+    status_t res = lockImageFromBuffer(
+            buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, noCrop, fenceFd, image);
+    // Clear the fenceFd as it is already consumed by lock call.
+    Image_setFenceFd(env, thiz, /*fenceFd*/-1);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+                "lock buffer failed for format 0x%x",
+                buffer->getPixelFormat());
+        return;
     }
 
-    // lockAsyncYCbCr for YUV is unsuccessful.
-    if (pData == NULL) {
-        res = buffer->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, &pData, fenceFd);
-        if (res != OK) {
-            jniThrowRuntimeException(env, "lockAsync failed");
-            return;
-        }
-    }
-
-    image->data = reinterpret_cast<uint8_t*>(pData);
-    image->width = buffer->getWidth();
-    image->height = buffer->getHeight();
-    image->format = format;
-    image->flexFormat = flexFormat;
-    image->stride = (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : buffer->getStride();
-
-    image->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
-    image->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
-    image->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
-    image->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
-    ALOGV("Successfully locked the image");
+    ALOGV("%s: Successfully locked the image", __FUNCTION__);
     // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
     // and we don't set them here.
 }
 
-static bool usingRGBAToJpegOverride(int32_t bufferFormat, int32_t writerCtxFormat) {
-    return writerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888;
-}
-
-static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t writerCtxFormat)
-{
-    // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
-    // write limitations for some platforms (b/17379185).
-    if (usingRGBAToJpegOverride(bufferFormat, writerCtxFormat)) {
-        return HAL_PIXEL_FORMAT_BLOB;
-    }
-    return bufferFormat;
-}
-
-static uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride) {
-    ALOGV("%s", __FUNCTION__);
-    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
-    uint32_t size = 0;
-    uint32_t width = buffer->width;
-    uint8_t* jpegBuffer = buffer->data;
-
-    if (usingRGBAOverride) {
-        width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
-    }
-
-    // First check for JPEG transport header at the end of the buffer
-    uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
-    struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
-    if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
-        size = blob->jpeg_size;
-        ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
-    }
-
-    // failed to find size, default to whole buffer
-    if (size == 0) {
-        /*
-         * This is a problem because not including the JPEG header
-         * means that in certain rare situations a regular JPEG blob
-         * will be misidentified as having a header, in which case
-         * we will get a garbage size value.
-         */
-        ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
-                __FUNCTION__, width);
-        size = width;
-    }
-
-    return size;
-}
-
 static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
         int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
     ALOGV("%s", __FUNCTION__);
-    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
-    ALOG_ASSERT(base != NULL, "base is NULL!!!");
-    ALOG_ASSERT(size != NULL, "size is NULL!!!");
-    ALOG_ASSERT(pixelStride != NULL, "pixelStride is NULL!!!");
-    ALOG_ASSERT(rowStride != NULL, "rowStride is NULL!!!");
-    ALOG_ASSERT((idx < IMAGE_WRITER_MAX_NUM_PLANES) && (idx >= 0));
 
-    ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
-
-    uint32_t dataSize, ySize, cSize, cStride;
-    uint32_t pStride = 0, rStride = 0;
-    uint8_t *cb, *cr;
-    uint8_t *pData = NULL;
-    int bytesPerPixel = 0;
-
-    dataSize = ySize = cSize = cStride = 0;
-    int32_t fmt = buffer->flexFormat;
-
-    bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, writerFormat);
-    fmt = applyFormatOverrides(fmt, writerFormat);
-    switch (fmt) {
-        case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            pData =
-                (idx == 0) ?
-                    buffer->data :
-                (idx == 1) ?
-                    buffer->dataCb :
-                buffer->dataCr;
-            // only map until last pixel
-            if (idx == 0) {
-                pStride = 1;
-                rStride = buffer->stride;
-                dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
-            } else {
-                pStride = buffer->chromaStep;
-                rStride = buffer->chromaStride;
-                dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
-                        buffer->chromaStep * (buffer->width / 2 - 1) + 1;
-            }
-            break;
-        // NV21
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            cr = buffer->data + (buffer->stride * buffer->height);
-            cb = cr + 1;
-            // only map until last pixel
-            ySize = buffer->width * (buffer->height - 1) + buffer->width;
-            cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
-
-            pData =
-                (idx == 0) ?
-                    buffer->data :
-                (idx == 1) ?
-                    cb:
-                cr;
-
-            dataSize = (idx == 0) ? ySize : cSize;
-            pStride = (idx == 0) ? 1 : 2;
-            rStride = buffer->width;
-            break;
-        case HAL_PIXEL_FORMAT_YV12:
-            // Y and C stride need to be 16 pixel aligned.
-            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
-                                "Stride is not 16 pixel aligned %d", buffer->stride);
-
-            ySize = buffer->stride * buffer->height;
-            cStride = ALIGN(buffer->stride / 2, 16);
-            cr = buffer->data + ySize;
-            cSize = cStride * buffer->height / 2;
-            cb = cr + cSize;
-
-            pData =
-                (idx == 0) ?
-                    buffer->data :
-                (idx == 1) ?
-                    cb :
-                cr;
-            dataSize = (idx == 0) ? ySize : cSize;
-            pStride = 1;
-            rStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
-            break;
-        case HAL_PIXEL_FORMAT_Y8:
-            // Single plane, 8bpp.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height;
-            pStride = 1;
-            rStride = buffer->stride;
-            break;
-        case HAL_PIXEL_FORMAT_Y16:
-            bytesPerPixel = 2;
-            // Single plane, 16bpp, strides are specified in pixels, not in bytes
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            pStride = bytesPerPixel;
-            rStride = buffer->stride * 2;
-            break;
-        case HAL_PIXEL_FORMAT_BLOB:
-            // Used for JPEG data, height must be 1, width == size, single plane.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height);
-
-            pData = buffer->data;
-            dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
-            pStride = bytesPerPixel;
-            rowStride = 0;
-            break;
-        case HAL_PIXEL_FORMAT_RAW16:
-            // Single plane 16bpp bayer data.
-            bytesPerPixel = 2;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            pStride = bytesPerPixel;
-            rStride = buffer->stride * 2;
-            break;
-        case HAL_PIXEL_FORMAT_RAW10:
-            // Single plane 10bpp bayer data.
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            LOG_ALWAYS_FATAL_IF(buffer->width % 4,
-                                "Width is not multiple of 4 %d", buffer->width);
-            LOG_ALWAYS_FATAL_IF(buffer->height % 2,
-                                "Height is not even %d", buffer->height);
-            LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
-                                "stride (%d) should be at least %d",
-                                buffer->stride, buffer->width * 10 / 8);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height;
-            pStride = 0;
-            rStride = buffer->stride;
-            break;
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-            // Single plane, 32bpp.
-            bytesPerPixel = 4;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            pStride = bytesPerPixel;
-            rStride = buffer->stride * 4;
-            break;
-        case HAL_PIXEL_FORMAT_RGB_565:
-            // Single plane, 16bpp.
-            bytesPerPixel = 2;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            pStride = bytesPerPixel;
-            rStride = buffer->stride * 2;
-            break;
-        case HAL_PIXEL_FORMAT_RGB_888:
-            // Single plane, 24bpp.
-            bytesPerPixel = 3;
-            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pData = buffer->data;
-            dataSize = buffer->stride * buffer->height * bytesPerPixel;
-            pStride = bytesPerPixel;
-            rStride = buffer->stride * 3;
-            break;
-        default:
-            jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
-                                 "Pixel format: 0x%x is unsupported", fmt);
-            break;
+    status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
+            pixelStride, rowStride);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                             "Pixel format: 0x%x is unsupported", buffer->flexFormat);
     }
-
-    *base = pData;
-    *size = dataSize;
-    *pixelStride = pStride;
-    *rowStride = rStride;
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
@@ -1024,7 +757,8 @@
     Image_getLockedImage(env, thiz, &lockedImg);
 
     // Create all SurfacePlanes
-    writerFormat = Image_getPixelFormat(env, writerFormat);
+    PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat);
+    writerFormat = android_view_Surface_mapPublicFormatToHalFormat(publicWriterFormat);
     for (int i = 0; i < numPlanes; i++) {
         Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
                 &pData, &dataSize, &pixelStride, &rowStride);
@@ -1044,39 +778,6 @@
     return surfacePlanes;
 }
 
-// -------------------------------Private convenience methods--------------------
-
-static bool isFormatOpaque(int format) {
-    // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
-    return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-}
-
-static bool isPossiblyYUV(PixelFormat format) {
-    switch (static_cast<int>(format)) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-        case HAL_PIXEL_FORMAT_RGB_888:
-        case HAL_PIXEL_FORMAT_RGB_565:
-        case HAL_PIXEL_FORMAT_BGRA_8888:
-        case HAL_PIXEL_FORMAT_Y8:
-        case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW16:
-        case HAL_PIXEL_FORMAT_RAW10:
-        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
-        case HAL_PIXEL_FORMAT_BLOB:
-        case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-            return false;
-
-        case HAL_PIXEL_FORMAT_YV12:
-        case HAL_PIXEL_FORMAT_YCbCr_420_888:
-        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        default:
-            return true;
-    }
-}
-
 } // extern "C"
 
 // ----------------------------------------------------------------------------
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 2004a3a..810996e 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -65,6 +65,7 @@
     jint cryptoErrorResourceBusy;
     jint cryptoErrorInsufficientOutputProtection;
     jint cryptoErrorSessionNotOpened;
+    jint cryptoErrorUnsupportedOperation;
 } gCryptoErrorCodes;
 
 static struct CodecActionCodes {
@@ -869,6 +870,10 @@
             err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
             defaultMsg = "Attempted to use a closed session";
             break;
+        case ERROR_DRM_CANNOT_HANDLE:
+            err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
+            defaultMsg = "Operation not supported in this configuration";
+            break;
         default:  /* Other negative DRM error codes go out as is. */
             break;
     }
@@ -1302,7 +1307,10 @@
     jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
 
     CryptoPlugin::Pattern pattern;
-    if (patternObj != NULL) {
+    if (patternObj == NULL) {
+        pattern.mEncryptBlocks = 0;
+        pattern.mSkipBlocks = 0;
+    } else {
         pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
         pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
     }
@@ -1770,6 +1778,11 @@
     gCryptoErrorCodes.cryptoErrorSessionNotOpened =
         env->GetStaticIntField(clazz.get(), field);
 
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
+        env->GetStaticIntField(clazz.get(), field);
+
     clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
     CHECK(clazz.get() != NULL);
     field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 3b892cb..537b56d 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -116,7 +116,8 @@
         return UNKNOWN_ERROR;
     }
     if (mSizeIsCached) {
-        return mCachedSize;
+        *size = mCachedSize;
+        return OK;
     }
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index e9d62de..2fb1a3b 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -906,14 +906,16 @@
     android_media_MediaPlayer_release(env, thiz);
 }
 
-static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz, jint sessionId) {
+static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz,
+        jint sessionId) {
     ALOGV("set_session_id(): %d", sessionId);
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
-    process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );
+    process_media_player_call( env, thiz, mp->setAudioSessionId((audio_session_t) sessionId), NULL,
+            NULL);
 }
 
 static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env,  jobject thiz) {
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 701f7ac..922ad79 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -26,7 +26,6 @@
 #include <utils/Log.h>
 
 #include <gui/Surface.h>
-#include <camera/ICameraService.h>
 #include <camera/Camera.h>
 #include <media/mediarecorder.h>
 #include <media/stagefright/PersistentSurface.h>
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index c08a5e3..62685c9 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -26,19 +26,82 @@
 
 #include <nativehelper/ScopedLocalRef.h>
 
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
 namespace android {
 
+AssetStream::AssetStream(SkStream* stream)
+    : mStream(stream) {
+}
+
+AssetStream::~AssetStream() {
+}
+
+piex::Error AssetStream::GetData(
+        const size_t offset, const size_t length, std::uint8_t* data) {
+    // Seek first.
+    if (mPosition != offset) {
+        if (!mStream->seek(offset)) {
+            return piex::Error::kFail;
+        }
+    }
+
+    // Read bytes.
+    size_t size = mStream->read((void*)data, length);
+    mPosition += size;
+
+    return size == length ? piex::Error::kOk : piex::Error::kFail;
+}
+
+BufferedStream::BufferedStream(SkStream* stream)
+    : mStream(stream) {
+}
+
+BufferedStream::~BufferedStream() {
+}
+
+piex::Error BufferedStream::GetData(
+        const size_t offset, const size_t length, std::uint8_t* data) {
+    // Seek first.
+    if (offset + length > mStreamBuffer.bytesWritten()) {
+        size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
+        if (sizeToRead <= kMinSizeToRead) {
+            sizeToRead = kMinSizeToRead;
+        }
+        void* tempBuffer = malloc(sizeToRead);
+        if (tempBuffer != NULL) {
+            size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
+            if (bytesRead != sizeToRead) {
+                free(tempBuffer);
+                return piex::Error::kFail;
+            }
+            mStreamBuffer.write(tempBuffer, bytesRead);
+            free(tempBuffer);
+        }
+    }
+
+    // Read bytes.
+    if (mStreamBuffer.read((void*)data, offset, length)) {
+        return piex::Error::kOk;
+    } else {
+        return piex::Error::kFail;
+    }
+}
+
+FileStream::FileStream(const int fd)
+    : mPosition(0) {
+    mFile = fdopen(fd, "r");
+    if (mFile == NULL) {
+        return;
+    }
+}
+
 FileStream::FileStream(const String8 filename)
-    : mPosition(0),
-      mSize(0) {
+    : mPosition(0) {
     mFile = fopen(filename.string(), "r");
     if (mFile == NULL) {
         return;
     }
-    // Get the size.
-    fseek(mFile, 0l, SEEK_END);
-    mSize = ftell(mFile);
-    fseek(mFile, 0l, SEEK_SET);
 }
 
 FileStream::~FileStream() {
@@ -64,7 +127,7 @@
     mPosition += size;
 
     // Handle errors.
-    if (ferror(mFile) || (size == 0 && feof(mFile))) {
+    if (ferror(mFile)) {
         ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length);
         return piex::Error::kFail;
     }
@@ -75,21 +138,12 @@
     return mFile != NULL;
 }
 
-size_t FileStream::size() const {
-    return mSize;
-}
-
 bool GetExifFromRawImage(
-        FileStream* stream, const String8& filename, piex::PreviewImageData& image_data) {
+        piex::StreamInterface* stream, const String8& filename,
+        piex::PreviewImageData& image_data) {
     // Reset the PreviewImageData to its default.
     image_data = piex::PreviewImageData();
 
-    if (!stream->exists()) {
-        // File is not exists.
-        ALOGV("File is not exists: %s", filename.string());
-        return false;
-    }
-
     if (!piex::IsRaw(stream)) {
         // Format not supported.
         ALOGV("Format not supported: %s", filename.string());
@@ -104,12 +158,6 @@
         return false;
     }
 
-    if (image_data.thumbnail_offset + image_data.thumbnail_length > stream->size()) {
-        // Corrupted image.
-        ALOGV("Corrupted file: %s", filename.string());
-        return false;
-    }
-
     return true;
 }
 
@@ -259,6 +307,11 @@
         AMessage::Type valueType;
         const char *key = msg->getEntryNameAt(i, &valueType);
 
+        if (!strncmp(key, "android._", 9)) {
+            // don't expose private keys (starting with android._)
+            continue;
+        }
+
         jobject valueObj = NULL;
 
         switch (valueType) {
@@ -412,6 +465,11 @@
         env->ReleaseStringUTFChars((jstring)keyObj, tmp);
         tmp = NULL;
 
+        if (key.startsWith("android._")) {
+            // don't propagate private keys (starting with android._)
+            continue;
+        }
+
         jobject valueObj = env->GetObjectArrayElement(values, i);
 
         if (env->IsInstanceOf(valueObj, stringClass.get())) {
@@ -496,5 +554,398 @@
     return OK;
 }
 
+// -----------Utility functions used by ImageReader/Writer JNI-----------------
+
+enum {
+    IMAGE_MAX_NUM_PLANES = 3,
+};
+
+bool usingRGBAToJpegOverride(int32_t imageFormat,
+        int32_t containerFormat) {
+    return containerFormat == HAL_PIXEL_FORMAT_BLOB && imageFormat == HAL_PIXEL_FORMAT_RGBA_8888;
+}
+
+int32_t applyFormatOverrides(int32_t imageFormat, int32_t containerFormat) {
+    // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
+    // write limitations for some platforms (b/17379185).
+    if (usingRGBAToJpegOverride(imageFormat, containerFormat)) {
+        return HAL_PIXEL_FORMAT_BLOB;
+    }
+    return containerFormat;
+}
+
+bool isFormatOpaque(int format) {
+    // This is the only opaque format exposed in the ImageFormat public API.
+    // Note that we do support CPU access for HAL_PIXEL_FORMAT_RAW_OPAQUE
+    // (ImageFormat#RAW_PRIVATE) so it doesn't count as opaque here.
+    return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+}
+
+bool isPossiblyYUV(PixelFormat format) {
+    switch (static_cast<int>(format)) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_Y8:
+        case HAL_PIXEL_FORMAT_Y16:
+        case HAL_PIXEL_FORMAT_RAW16:
+        case HAL_PIXEL_FORMAT_RAW10:
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+        case HAL_PIXEL_FORMAT_BLOB:
+        case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+            return false;
+
+        case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+        default:
+            return true;
+    }
+}
+
+uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride) {
+    ALOGV("%s", __FUNCTION__);
+    LOG_ALWAYS_FATAL_IF(buffer == NULL, "Input buffer is NULL!!!");
+    uint32_t size = 0;
+    uint32_t width = buffer->width;
+    uint8_t* jpegBuffer = buffer->data;
+
+    if (usingRGBAOverride) {
+        width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
+    }
+
+    // First check for JPEG transport header at the end of the buffer
+    uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
+    struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
+    if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
+        size = blob->jpeg_size;
+        ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
+    }
+
+    // failed to find size, default to whole buffer
+    if (size == 0) {
+        /*
+         * This is a problem because not including the JPEG header
+         * means that in certain rare situations a regular JPEG blob
+         * will be mis-identified as having a header, in which case
+         * we will get a garbage size value.
+         */
+        ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
+                __FUNCTION__, width);
+        size = width;
+    }
+
+    return size;
+}
+
+status_t getLockedImageInfo(LockedImage* buffer, int idx,
+        int32_t containerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
+    ALOGV("%s", __FUNCTION__);
+    LOG_ALWAYS_FATAL_IF(buffer == NULL, "Input buffer is NULL!!!");
+    LOG_ALWAYS_FATAL_IF(base == NULL, "base is NULL!!!");
+    LOG_ALWAYS_FATAL_IF(size == NULL, "size is NULL!!!");
+    LOG_ALWAYS_FATAL_IF(pixelStride == NULL, "pixelStride is NULL!!!");
+    LOG_ALWAYS_FATAL_IF(rowStride == NULL, "rowStride is NULL!!!");
+    LOG_ALWAYS_FATAL_IF((idx >= IMAGE_MAX_NUM_PLANES) || (idx < 0), "idx (%d) is illegal", idx);
+
+    ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
+
+    uint32_t dataSize, ySize, cSize, cStride;
+    uint32_t pStride = 0, rStride = 0;
+    uint8_t *cb, *cr;
+    uint8_t *pData = NULL;
+    int bytesPerPixel = 0;
+
+    dataSize = ySize = cSize = cStride = 0;
+    int32_t fmt = buffer->flexFormat;
+
+    bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, containerFormat);
+    fmt = applyFormatOverrides(fmt, containerFormat);
+    switch (fmt) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            pData =
+                (idx == 0) ?
+                    buffer->data :
+                (idx == 1) ?
+                    buffer->dataCb :
+                buffer->dataCr;
+            // only map until last pixel
+            if (idx == 0) {
+                pStride = 1;
+                rStride = buffer->stride;
+                dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
+            } else {
+                pStride = buffer->chromaStep;
+                rStride = buffer->chromaStride;
+                dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
+                        buffer->chromaStep * (buffer->width / 2 - 1) + 1;
+            }
+            break;
+        // NV21
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            cr = buffer->data + (buffer->stride * buffer->height);
+            cb = cr + 1;
+            // only map until last pixel
+            ySize = buffer->width * (buffer->height - 1) + buffer->width;
+            cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
+
+            pData =
+                (idx == 0) ?
+                    buffer->data :
+                (idx == 1) ?
+                    cb:
+                cr;
+
+            dataSize = (idx == 0) ? ySize : cSize;
+            pStride = (idx == 0) ? 1 : 2;
+            rStride = buffer->width;
+            break;
+        case HAL_PIXEL_FORMAT_YV12:
+            // Y and C stride need to be 16 pixel aligned.
+            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
+                                "Stride is not 16 pixel aligned %d", buffer->stride);
+
+            ySize = buffer->stride * buffer->height;
+            cStride = ALIGN(buffer->stride / 2, 16);
+            cr = buffer->data + ySize;
+            cSize = cStride * buffer->height / 2;
+            cb = cr + cSize;
+
+            pData =
+                (idx == 0) ?
+                    buffer->data :
+                (idx == 1) ?
+                    cb :
+                cr;
+            dataSize = (idx == 0) ? ySize : cSize;
+            pStride = 1;
+            rStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
+            break;
+        case HAL_PIXEL_FORMAT_Y8:
+            // Single plane, 8bpp.
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height;
+            pStride = 1;
+            rStride = buffer->stride;
+            break;
+        case HAL_PIXEL_FORMAT_Y16:
+            bytesPerPixel = 2;
+            // Single plane, 16bpp, strides are specified in pixels, not in bytes
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            pStride = bytesPerPixel;
+            rStride = buffer->stride * 2;
+            break;
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Used for JPEG data, height must be 1, width == size, single plane.
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            // When RGBA override is being used, buffer height will be equal to width
+            if (usingRGBAOverride) {
+                LOG_ALWAYS_FATAL_IF(buffer->height != buffer->width,
+                        "RGBA override BLOB format buffer should have height == width");
+            } else {
+                LOG_ALWAYS_FATAL_IF(buffer->height != 1,
+                        "BLOB format buffer should have height value 1");
+            }
+
+
+            pData = buffer->data;
+            dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
+            pStride = 0;
+            rStride = 0;
+            break;
+        case HAL_PIXEL_FORMAT_RAW16:
+            // Single plane 16bpp bayer data.
+            bytesPerPixel = 2;
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            pStride = bytesPerPixel;
+            rStride = buffer->stride * 2;
+            break;
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            LOG_ALWAYS_FATAL_IF(buffer->height != 1,
+                    "RAW_PRIVATE should has height value one but got %d", buffer->height);
+            pData = buffer->data;
+            dataSize = buffer->width;
+            pStride = 0; // RAW OPAQUE doesn't have pixel stride
+            rStride = 0; // RAW OPAQUE doesn't have row stride
+            break;
+        case HAL_PIXEL_FORMAT_RAW10:
+            // Single plane 10bpp bayer data.
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            LOG_ALWAYS_FATAL_IF(buffer->width % 4,
+                                "Width is not multiple of 4 %d", buffer->width);
+            LOG_ALWAYS_FATAL_IF(buffer->height % 2,
+                                "Height is not even %d", buffer->height);
+            LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
+                                "stride (%d) should be at least %d",
+                                buffer->stride, buffer->width * 10 / 8);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height;
+            pStride = 0;
+            rStride = buffer->stride;
+            break;
+        case HAL_PIXEL_FORMAT_RAW12:
+            // Single plane 10bpp bayer data.
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            LOG_ALWAYS_FATAL_IF(buffer->width % 4,
+                                "Width is not multiple of 4 %d", buffer->width);
+            LOG_ALWAYS_FATAL_IF(buffer->height % 2,
+                                "Height is not even %d", buffer->height);
+            LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 12 / 8),
+                                "stride (%d) should be at least %d",
+                                buffer->stride, buffer->width * 12 / 8);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height;
+            pStride = 0;
+            rStride = buffer->stride;
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            // Single plane, 32bpp.
+            bytesPerPixel = 4;
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            pStride = bytesPerPixel;
+            rStride = buffer->stride * 4;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_565:
+            // Single plane, 16bpp.
+            bytesPerPixel = 2;
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            pStride = bytesPerPixel;
+            rStride = buffer->stride * 2;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_888:
+            // Single plane, 24bpp.
+            bytesPerPixel = 3;
+            LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+            pData = buffer->data;
+            dataSize = buffer->stride * buffer->height * bytesPerPixel;
+            pStride = bytesPerPixel;
+            rStride = buffer->stride * 3;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    *base = pData;
+    *size = dataSize;
+    *pixelStride = pStride;
+    *rowStride = rStride;
+
+    return OK;
+}
+
+status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage,
+        const Rect& rect, int fenceFd, LockedImage* outputImage) {
+    ALOGV("%s: Try to lock the GraphicBuffer", __FUNCTION__);
+
+    if (buffer == nullptr || outputImage == nullptr) {
+        ALOGE("Input BufferItem or output LockedImage is NULL!");
+        return BAD_VALUE;
+    }
+    if (isFormatOpaque(buffer->getPixelFormat())) {
+        ALOGE("Opaque format buffer is not lockable!");
+        return BAD_VALUE;
+    }
+
+    void* pData = NULL;
+    android_ycbcr ycbcr = android_ycbcr();
+    status_t res;
+    int format = buffer->getPixelFormat();
+    int flexFormat = format;
+    if (isPossiblyYUV(format)) {
+        res = buffer->lockAsyncYCbCr(inUsage, rect, &ycbcr, fenceFd);
+        pData = ycbcr.y;
+        flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+    }
+
+    // lockAsyncYCbCr for YUV is unsuccessful.
+    if (pData == NULL) {
+        res = buffer->lockAsync(inUsage, rect, &pData, fenceFd);
+        if (res != OK) {
+            ALOGE("Lock buffer failed!");
+            return res;
+        }
+    }
+
+    outputImage->data = reinterpret_cast<uint8_t*>(pData);
+    outputImage->width = buffer->getWidth();
+    outputImage->height = buffer->getHeight();
+    outputImage->format = format;
+    outputImage->flexFormat = flexFormat;
+    outputImage->stride =
+            (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : buffer->getStride();
+
+    outputImage->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
+    outputImage->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
+    outputImage->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
+    outputImage->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
+    ALOGV("%s: Successfully locked the image from the GraphicBuffer", __FUNCTION__);
+    // Crop, transform, scalingMode, timestamp, and frameNumber should be set by caller,
+    // and cann't be set them here.
+    return OK;
+}
+
+status_t lockImageFromBuffer(BufferItem* bufferItem, uint32_t inUsage,
+        int fenceFd, LockedImage* outputImage) {
+    ALOGV("%s: Try to lock the BufferItem", __FUNCTION__);
+    if (bufferItem == nullptr || outputImage == nullptr) {
+        ALOGE("Input BufferItem or output LockedImage is NULL!");
+        return BAD_VALUE;
+    }
+
+    status_t res = lockImageFromBuffer(bufferItem->mGraphicBuffer, inUsage, bufferItem->mCrop,
+            fenceFd, outputImage);
+    if (res != OK) {
+        ALOGE("%s: lock graphic buffer failed", __FUNCTION__);
+        return res;
+    }
+
+    outputImage->crop        = bufferItem->mCrop;
+    outputImage->transform   = bufferItem->mTransform;
+    outputImage->scalingMode = bufferItem->mScalingMode;
+    outputImage->timestamp   = bufferItem->mTimestamp;
+    outputImage->dataSpace   = bufferItem->mDataSpace;
+    outputImage->frameNumber = bufferItem->mFrameNumber;
+    ALOGV("%s: Successfully locked the image from the BufferItem", __FUNCTION__);
+    return OK;
+}
+
+int getBufferWidth(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
+
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getWidth();
+    }
+
+    ALOGV("%s: buffer->mGraphicBuffer: %p", __FUNCTION__, buffer->mGraphicBuffer.get());
+    return buffer->mGraphicBuffer->getWidth();
+}
+
+int getBufferHeight(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
+
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getHeight();
+    }
+
+    ALOGV("%s: buffer->mGraphicBuffer: %p", __FUNCTION__, buffer->mGraphicBuffer.get());
+    return buffer->mGraphicBuffer->getHeight();
+}
+
 }  // namespace android
 
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 762c904..8184f94 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -21,20 +21,65 @@
 #include "src/piex.h"
 
 #include <android_runtime/AndroidRuntime.h>
+#include <camera3.h>
+#include <gui/CpuConsumer.h>
 #include <jni.h>
 #include <JNIHelp.h>
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
+#include <SkStream.h>
 
 namespace android {
 
+class AssetStream : public piex::StreamInterface {
+private:
+    SkStream *mStream;
+    size_t mPosition;
+
+public:
+    AssetStream(SkStream* stream);
+    ~AssetStream();
+
+    // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
+    // provided by the caller, guaranteed to be at least "length" bytes long.
+    // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
+    // 'offset' bytes from the start of the stream.
+    // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
+    // change the contents of 'data'.
+    piex::Error GetData(
+            const size_t offset, const size_t length, std::uint8_t* data) override;
+};
+
+class BufferedStream : public piex::StreamInterface {
+private:
+    SkStream *mStream;
+    // Growable memory stream
+    SkDynamicMemoryWStream mStreamBuffer;
+
+    // Minimum size to read on filling the buffer.
+    const size_t kMinSizeToRead = 8192;
+
+public:
+    BufferedStream(SkStream* stream);
+    ~BufferedStream();
+
+    // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
+    // provided by the caller, guaranteed to be at least "length" bytes long.
+    // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
+    // 'offset' bytes from the start of the stream.
+    // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
+    // change the contents of 'data'.
+    piex::Error GetData(
+            const size_t offset, const size_t length, std::uint8_t* data) override;
+};
+
 class FileStream : public piex::StreamInterface {
 private:
     FILE *mFile;
     size_t mPosition;
-    size_t mSize;
 
 public:
+    FileStream(const int fd);
     FileStream(const String8 filename);
     ~FileStream();
 
@@ -47,13 +92,12 @@
     piex::Error GetData(
             const size_t offset, const size_t length, std::uint8_t* data) override;
     bool exists() const;
-    size_t size() const;
 };
 
 // Reads EXIF metadata from a given raw image via piex.
 // And returns true if the operation is successful; otherwise, false.
 bool GetExifFromRawImage(
-        FileStream* stream, const String8& filename, piex::PreviewImageData& image_data);
+        piex::StreamInterface* stream, const String8& filename, piex::PreviewImageData& image_data);
 
 // Returns true if the conversion is successful; otherwise, false.
 bool ConvertKeyValueArraysToKeyedVector(
@@ -68,6 +112,33 @@
         JNIEnv *env, jobjectArray keys, jobjectArray values,
         sp<AMessage> *msg);
 
+// -----------Utility functions used by ImageReader/Writer JNI-----------------
+
+typedef CpuConsumer::LockedBuffer LockedImage;
+
+bool usingRGBAToJpegOverride(int32_t imageFormat, int32_t containerFormat);
+
+int32_t applyFormatOverrides(int32_t imageFormat, int32_t containerFormat);
+
+uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride);
+
+bool isFormatOpaque(int format);
+
+bool isPossiblyYUV(PixelFormat format);
+
+status_t getLockedImageInfo(LockedImage* buffer, int idx, int32_t containerFormat,
+        uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride);
+
+status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage,
+        const Rect& rect, int fenceFd, LockedImage* outputImage);
+
+status_t lockImageFromBuffer(BufferItem* bufferItem, uint32_t inUsage,
+        int fenceFd, LockedImage* outputImage);
+
+int getBufferWidth(BufferItem *buffer);
+
+int getBufferHeight(BufferItem *buffer);
+
 };  // namespace android
 
 #endif //  _ANDROID_MEDIA_UTILS_H_
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 556f2c7..39f2a32 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -231,11 +231,11 @@
 }
 
 MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
-                                            MtpObjectFormat format,
-                                            MtpObjectHandle parent,
-                                            MtpStorageID storage,
-                                            uint64_t size,
-                                            time_t modified) {
+                                               MtpObjectFormat format,
+                                               MtpObjectHandle parent,
+                                               MtpStorageID storage,
+                                               uint64_t size,
+                                               time_t modified) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring pathStr = env->NewStringUTF(path);
     MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
@@ -249,7 +249,7 @@
 }
 
 void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
-                                MtpObjectFormat format, bool succeeded) {
+                                  MtpObjectFormat format, bool succeeded) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring pathStr = env->NewStringUTF(path);
     env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
@@ -261,8 +261,8 @@
 }
 
 MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
-                                    MtpObjectFormat format,
-                                    MtpObjectHandle parent) {
+                                                  MtpObjectFormat format,
+                                                  MtpObjectHandle parent) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
                 (jint)storageID, (jint)format, (jint)parent);
@@ -281,8 +281,8 @@
 }
 
 int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
-                                MtpObjectFormat format,
-                                MtpObjectHandle parent) {
+                                 MtpObjectFormat format,
+                                 MtpObjectHandle parent) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     int result = env->CallIntMethod(mDatabase, method_getNumObjects,
                 (jint)storageID, (jint)format, (jint)parent);
@@ -364,11 +364,21 @@
 }
 
 MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
-                                            MtpObjectProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpObjectProperty property,
+                                                      MtpDataPacket& packet) {
+    static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
+                  "Casting MtpObjectHandle to jint loses a value");
+    static_assert(sizeof(jint) >= sizeof(MtpObjectProperty),
+                  "Casting MtpObjectProperty to jint loses a value");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
-                (jlong)handle, 0, (jlong)property, 0, 0);
+    jobject list = env->CallObjectMethod(
+            mDatabase,
+            method_getObjectPropertyList,
+            static_cast<jint>(handle),
+            0,
+            static_cast<jint>(property),
+            0,
+            0);
     MtpResponseCode result = env->GetIntField(list, field_mResult);
     int count = env->GetIntField(list, field_mCount);
     if (result == MTP_RESPONSE_OK && count != 1)
@@ -532,8 +542,8 @@
 }
 
 MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
-                                            MtpObjectProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpObjectProperty property,
+                                                      MtpDataPacket& packet) {
     int         type;
 
     if (!getObjectPropertyInfo(property, type))
@@ -563,7 +573,7 @@
 }
 
 MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpDataPacket& packet) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
     if (property == MTP_DEVICE_PROPERTY_BATTERY_LEVEL) {
@@ -636,7 +646,7 @@
 }
 
 MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpDataPacket& packet) {
     int         type;
 
     if (!getDevicePropertyInfo(property, type))
@@ -670,12 +680,20 @@
 }
 
 MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
-                                            uint32_t format, uint32_t property,
-                                            int groupCode, int depth,
-                                            MtpDataPacket& packet) {
+                                                     uint32_t format, uint32_t property,
+                                                     int groupCode, int depth,
+                                                     MtpDataPacket& packet) {
+    static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
+                  "Casting MtpObjectHandle to jint loses a value");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
-                (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth);
+    jobject list = env->CallObjectMethod(
+            mDatabase,
+            method_getObjectPropertyList,
+            static_cast<jint>(handle),
+            static_cast<jint>(format),
+            static_cast<jint>(property),
+            static_cast<jint>(groupCode),
+            static_cast<jint>(depth));
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     if (!list)
         return MTP_RESPONSE_GENERAL_ERROR;
@@ -787,7 +805,7 @@
 }
 
 MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
-                                            MtpObjectInfo& info) {
+                                             MtpObjectInfo& info) {
     MtpString       path;
     int64_t         length;
     MtpObjectFormat format;
@@ -864,7 +882,7 @@
                 break;
             }
 
-            info.mThumbCompressedSize = image_data.thumbnail_length;
+            info.mThumbCompressedSize = image_data.thumbnail.length;
             info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
             info.mImagePixWidth = image_data.full_width;
             info.mImagePixHeight = image_data.full_height;
@@ -914,19 +932,19 @@
                     break;
                 }
 
-                if (image_data.thumbnail_length == 0) {
+                if (image_data.thumbnail.length == 0) {
                     // No thumbnail.
                     break;
                 }
 
-                result = malloc(image_data.thumbnail_length);
+                result = malloc(image_data.thumbnail.length);
                 if (result) {
                     piex::Error err = stream.get()->GetData(
-                            image_data.thumbnail_offset,
-                            image_data.thumbnail_length,
+                            image_data.thumbnail.offset,
+                            image_data.thumbnail.length,
                             (std::uint8_t *)result);
                     if (err == piex::Error::kOk) {
-                        outThumbSize = image_data.thumbnail_length;
+                        outThumbSize = image_data.thumbnail.length;
                     } else {
                         free(result);
                     }
@@ -940,9 +958,9 @@
 }
 
 MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
-                                            MtpString& outFilePath,
-                                            int64_t& outFileLength,
-                                            MtpObjectFormat& outFormat) {
+                                                 MtpString& outFilePath,
+                                                 int64_t& outFileLength,
+                                                 MtpObjectFormat& outFormat) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
                 (jint)handle, mStringBuffer, mLongBuffer);
@@ -1056,7 +1074,7 @@
 }
 
 MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
-                                                    MtpObjectHandleList* references) {
+                                                   MtpObjectHandleList* references) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     int count = references->size();
     jintArray array = env->NewIntArray(count);
@@ -1077,7 +1095,7 @@
 }
 
 MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
-                                            MtpObjectFormat format) {
+                                                  MtpObjectFormat format) {
     static const int channelEnum[] = {
                                         1,  // mono
                                         2,  // stereo
@@ -1313,7 +1331,7 @@
         return -1;
     }
     method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
-            "(JIJII)Landroid/mtp/MtpPropertyList;");
+            "(IIIII)Landroid/mtp/MtpPropertyList;");
     if (method_getObjectPropertyList == NULL) {
         ALOGE("Can't find getObjectPropertyList");
         return -1;
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 0ecb750..6e434b2 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -42,6 +42,7 @@
 #include "MtpDeviceInfo.h"
 #include "MtpStorageInfo.h"
 #include "MtpObjectInfo.h"
+#include "MtpProperty.h"
 
 using namespace android;
 
@@ -700,6 +701,42 @@
     device->discardEventRequest(seq);
 }
 
+// Returns object size in 64-bit integer. If the MTP device does not support the property, it
+// throws IOException.
+static jlong android_mtp_MtpDevice_get_object_size_long(
+        JNIEnv *env, jobject thiz, jint handle, jint format) {
+    MtpDevice* const device = get_device_from_object(env, thiz);
+    if (!device) {
+        env->ThrowNew(clazz_io_exception, "Failed to obtain MtpDevice.");
+        return 0;
+    }
+
+    std::unique_ptr<MtpProperty> property(
+            device->getObjectPropDesc(MTP_PROPERTY_OBJECT_SIZE, format));
+    if (!property) {
+        env->ThrowNew(clazz_io_exception, "Failed to obtain property desc.");
+        return 0;
+    }
+
+    if (property->getDataType() != MTP_TYPE_UINT64) {
+        env->ThrowNew(clazz_io_exception, "Unexpected property data type.");
+        return 0;
+    }
+
+    if (!device->getObjectPropValue(handle, property.get())) {
+        env->ThrowNew(clazz_io_exception, "Failed to obtain property value.");
+        return 0;
+    }
+
+    const jlong object_size = static_cast<jlong>(property->getCurrentValue().u.u64);
+    if (object_size < 0) {
+        env->ThrowNew(clazz_io_exception, "Object size is too large to express as jlong.");
+        return 0;
+    }
+
+    return object_size;
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
@@ -733,6 +770,8 @@
     {"native_reap_event_request",   "(I)Landroid/mtp/MtpEvent;",
                                             (void *)android_mtp_MtpDevice_reap_event_request},
     {"native_discard_event_request", "(I)V", (void *)android_mtp_MtpDevice_discard_event_request},
+
+    {"native_get_object_size_long", "(II)J", (void *)android_mtp_MtpDevice_get_object_size_long},
 };
 
 int register_android_mtp_MtpDevice(JNIEnv *env)
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index fa69135..10efe18 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -351,7 +351,7 @@
                                     priority,
                                     effectCallback,
                                     &lpJniStorage->mCallbackData,
-                                    sessionId,
+                                    (audio_session_t) sessionId,
                                     0);
     if (lpAudioEffect == 0) {
         ALOGE("Error creating AudioEffect");
@@ -819,7 +819,7 @@
     effect_descriptor_t *descriptors = new effect_descriptor_t[AudioEffect::kMaxPreProcessing];
     uint32_t numEffects = AudioEffect::kMaxPreProcessing;
 
-    status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
+    status_t status = AudioEffect::queryDefaultPreProcessing((audio_session_t) audioSession,
                                            descriptors,
                                            &numEffects);
     if (status != NO_ERROR || numEffects == 0) {
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 3d3adba..f1a8c6f 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -388,7 +388,7 @@
                                   0,
                                   android_media_visualizer_effect_callback,
                                   lpJniStorage,
-                                  sessionId);
+                                  (audio_session_t) sessionId);
     if (lpVisualizer == 0) {
         ALOGE("Error creating Visualizer");
         goto setup_failure;
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index b63df6f..d2dc440 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -554,6 +554,10 @@
                     if (bufidx >= 0) {
                         size_t bufsize;
                         uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
+                        if (buf == nullptr) {
+                            ALOGE("AMediaCodec_getInputBuffer returned nullptr, short decode");
+                            break;
+                        }
                         int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
                         ALOGV("read %d", sampleSize);
                         if (sampleSize < 0) {
@@ -563,10 +567,16 @@
                         }
                         int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
 
-                        AMediaCodec_queueInputBuffer(codec, bufidx,
+                        media_status_t mstatus = AMediaCodec_queueInputBuffer(codec, bufidx,
                                 0 /* offset */, sampleSize, presentationTimeUs,
                                 sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
-                        AMediaExtractor_advance(ex);
+                        if (mstatus != AMEDIA_OK) {
+                            // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
+                            ALOGE("AMediaCodec_queueInputBuffer returned status %d, short decode",
+                                    (int)mstatus);
+                            break;
+                        }
+                        (void)AMediaExtractor_advance(ex);
                     }
                 }
 
@@ -581,6 +591,10 @@
                     ALOGV("got decoded buffer size %d", info.size);
 
                     uint8_t *buf = AMediaCodec_getOutputBuffer(codec, status, NULL /* out_size */);
+                    if (buf == nullptr) {
+                        ALOGE("AMediaCodec_getOutputBuffer returned nullptr, short decode");
+                        break;
+                    }
                     size_t dataSize = info.size;
                     if (dataSize > available) {
                         dataSize = available;
@@ -589,7 +603,14 @@
                     writePos += dataSize;
                     written += dataSize;
                     available -= dataSize;
-                    AMediaCodec_releaseOutputBuffer(codec, status, false /* render */);
+                    media_status_t mstatus = AMediaCodec_releaseOutputBuffer(
+                            codec, status, false /* render */);
+                    if (mstatus != AMEDIA_OK) {
+                        // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
+                        ALOGE("AMediaCodec_releaseOutputBuffer returned status %d, short decode",
+                                (int)mstatus);
+                        break;
+                    }
                     if (available == 0) {
                         // there might be more data, but there's no space for it
                         sawOutputEOS = true;
@@ -610,21 +631,21 @@
                 }
             }
 
-            AMediaCodec_stop(codec);
-            AMediaCodec_delete(codec);
-            AMediaExtractor_delete(ex);
+            (void)AMediaCodec_stop(codec);
+            (void)AMediaCodec_delete(codec);
+            (void)AMediaExtractor_delete(ex);
             if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) rate) ||
                     !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, numChannels)) {
-                AMediaFormat_delete(format);
+                (void)AMediaFormat_delete(format);
                 return UNKNOWN_ERROR;
             }
-            AMediaFormat_delete(format);
+            (void)AMediaFormat_delete(format);
             *memsize = written;
             return OK;
         }
-        AMediaFormat_delete(format);
+        (void)AMediaFormat_delete(format);
     }
-    AMediaExtractor_delete(ex);
+    (void)AMediaExtractor_delete(ex);
     return UNKNOWN_ERROR;
 }
 
diff --git a/media/mca/effect/java/android/media/effect/package-info.java b/media/mca/effect/java/android/media/effect/package-info.java
deleted file mode 100644
index b2c14ff..0000000
--- a/media/mca/effect/java/android/media/effect/package-info.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.media.effect;
-
-/**
- * <h1>Effect Framework</h1>
- *
- * This package includes a collection of high-performance visual effects that make use of the
- * mobile filter framework subsystem.
- *
- * TODO: More Documentation
- *
- */
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 7c1142b..7e438a1 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -11,7 +11,6 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := easymocklib \
     mockito-target \
-    core-tests \
     android-support-test \
     android-ex-camera2
 
diff --git a/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_ii.jpg b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_ii.jpg
new file mode 100644
index 0000000..477cd3a
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_ii.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_mm.jpg b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_mm.jpg
new file mode 100644
index 0000000..78ac703
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_mm.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/assets/lg_g4_iso_800.dng b/media/tests/MediaFrameworkTest/assets/lg_g4_iso_800.dng
new file mode 100644
index 0000000..5fcc720
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/lg_g4_iso_800.dng
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/assets/volantis.jpg b/media/tests/MediaFrameworkTest/assets/volantis.jpg
new file mode 100644
index 0000000..cfe300f
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/volantis.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_ii.jpg b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_ii.jpg
new file mode 100644
index 0000000..477cd3a
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_ii.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_mm.jpg b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_mm.jpg
new file mode 100644
index 0000000..78ac703
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_mm.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/lg_g4_iso_800.dng b/media/tests/MediaFrameworkTest/res/raw/lg_g4_iso_800.dng
new file mode 100644
index 0000000..5fcc720
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/lg_g4_iso_800.dng
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/volantis.jpg b/media/tests/MediaFrameworkTest/res/raw/volantis.jpg
new file mode 100644
index 0000000..cfe300f
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/volantis.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
new file mode 100644
index 0000000..3c5dd37
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <array name="exifbyteorderii_jpg">
+        <item>true</item>
+        <item>512</item>
+        <item>288</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>SAMSUNG</item>
+        <item>SM-N900S</item>
+        <item>2.200</item>
+        <item>2016:01:29 18:32:27</item>
+        <item>0.033</item>
+        <item>0</item>
+        <item>413/100</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>480</item>
+        <item>640</item>
+        <item>50</item>
+        <item>6</item>
+        <item>0</item>
+    </array>
+    <array name="exifbyteordermm_jpg">
+        <item>false</item>
+        <item>0</item>
+        <item>0</item>
+        <item>true</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>LGE</item>
+        <item>Nexus 5</item>
+        <item>2.400</item>
+        <item>2016:01:29 15:44:58</item>
+        <item>0.017</item>
+        <item>0</item>
+        <item>3970/1000</item>
+        <item>0/1000</item>
+        <item>0</item>
+        <item>1970:01:01</item>
+        <item>0/1,0/1,0/10000</item>
+        <item>N</item>
+        <item>0/1,0/1,0/10000</item>
+        <item>E</item>
+        <item>GPS</item>
+        <item>00:00:00</item>
+        <item>176</item>
+        <item>144</item>
+        <item>146</item>
+        <item>0</item>
+        <item>0</item>
+    </array>
+    <array name="lg_g4_iso_800_dng">
+        <item>true</item>
+        <item>256</item>
+        <item>144</item>
+        <item>true</item>
+        <item>53.834507</item>
+        <item>10.69585</item>
+        <item>0.0</item>
+        <item>LGE</item>
+        <item>LG-H815</item>
+        <item>1.800</item>
+        <item>2015:11:12 16:46:18</item>
+        <item>0.0040</item>
+        <item>0.0</item>
+        <item>442/100</item>
+        <item>0/1</item>
+        <item>0</item>
+        <item>1970:01:17</item>
+        <item>53/1,50/1,423/100</item>
+        <item>N</item>
+        <item>10/1,41/1,4506/100</item>
+        <item>E</item>
+        <item />
+        <item>18:08:10</item>
+        <item>337</item>
+        <item>600</item>
+        <item>800</item>
+        <item>1</item>
+        <item>0</item>
+    </array>
+    <array name="volantis_jpg">
+        <item>false</item>
+        <item>0</item>
+        <item>0</item>
+        <item>true</item>
+        <item>37.423</item>
+        <item>-122.162</item>
+        <item>0.0</item>
+        <item>htc</item>
+        <item>Nexus 9</item>
+        <item>1.2904</item>
+        <item>2016:03:09 17:36:42</item>
+        <item>0.0083</item>
+        <item>64</item>
+        <item>3097/1000</item>
+        <item />
+        <item />
+        <item>2016:03:09</item>
+        <item>37/1,25/1,2291/100</item>
+        <item>N</item>
+        <item>122/1,9/1,4330/100</item>
+        <item>W</item>
+        <item />
+        <item>08:35:34</item>
+        <item>720</item>
+        <item>1280</item>
+        <item>175</item>
+        <item>1</item>
+        <item>0</item>
+    </array>
+</resources>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 11d9070..9be7004 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -50,6 +50,7 @@
         addMediaScannerUnitTests(suite);
         addCameraUnitTests(suite);
         addImageReaderTests(suite);
+        addExifInterfaceTests(suite);
         return suite;
     }
 
@@ -59,10 +60,7 @@
     }
 
     private void addCameraUnitTests(TestSuite suite) {
-        suite.addTestSuite(CameraUtilsDecoratorTest.class);
-        suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
         suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
-        suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
         suite.addTestSuite(CameraUtilsTypeReferenceTest.class);
         suite.addTestSuite(CameraMetadataTest.class);
     }
@@ -109,4 +107,8 @@
     private void addMediaScannerUnitTests(TestSuite suite) {
         suite.addTestSuite(MediaInserterTest.class);
     }
+
+    private void addExifInterfaceTests(TestSuite suite) {
+        suite.addTestSuite(ExifInterfaceTest.class);
+    }
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 6f74203..9a0946e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -19,16 +19,16 @@
 import android.hardware.CameraInfo;
 import android.hardware.ICamera;
 import android.hardware.ICameraClient;
+import android.hardware.ICameraService;
 import android.hardware.ICameraServiceListener;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
-import android.hardware.camera2.utils.BinderHolder;
-import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
@@ -84,14 +84,7 @@
     public void testCameraInfo() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            CameraInfo info = new CameraInfo();
-            info.info.facing = -1;
-            info.info.orientation = -1;
-
-            assertTrue(
-                    "Camera service returned info for camera " + cameraId,
-                    mUtils.getCameraService().getCameraInfo(cameraId, info) ==
-                    CameraBinderTestUtils.NO_ERROR);
+            CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId);
             assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
             assertTrue("Orientation was not set for camera " + cameraId,
                     info.info.orientation != -1);
@@ -105,20 +98,17 @@
     public void testGetLegacyParameters() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            String[] parameters = new String[1];
-            assertEquals("Camera service returned parameters for camera " + cameraId,
-                    CameraBinderTestUtils.NO_ERROR,
-                    mUtils.getCameraService().getLegacyParameters(cameraId, /*out*/parameters));
-            assertNotNull(parameters[0]);
+            String parameters = mUtils.getCameraService().getLegacyParameters(cameraId);
+            assertNotNull(parameters);
             assertTrue("Parameters should have at least one character in it",
-                    parameters[0].length() > 0);
+                    parameters.length() > 0);
 
-            int end = parameters[0].length();
+            int end = parameters.length();
             if (end > MAX_PARAMETERS_LENGTH) {
                 end = MAX_PARAMETERS_LENGTH;
             }
 
-            Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters[0].substring(0, end));
+            Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters.substring(0, end));
         }
     }
 
@@ -127,14 +117,8 @@
     public void testSupportsCamera2Api() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
+            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
 
-            if (res != CameraBinderTestUtils.NO_ERROR && res != -android.system.OsConstants.EOPNOTSUPP) {
-                fail("Camera service returned bad value when queried if it supports camera2 api: "
-                        + res + " for camera ID " + cameraId);
-            }
-
-            boolean supports = res == CameraBinderTestUtils.NO_ERROR;
             Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
         }
     }
@@ -144,10 +128,10 @@
     public void testSupportsCamera1Api() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
-            assertEquals(
-                    "Camera service returned bad value when queried if it supports camera1 api: "
-                    + res + " for camera ID " + cameraId, CameraBinderTestUtils.NO_ERROR, res);
+            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
+            assertTrue(
+                    "Camera service returned false when queried if it supports camera1 api " +
+                    " for camera ID " + cameraId, supports);
         }
     }
 
@@ -169,11 +153,10 @@
 
             String clientPackageName = getContext().getPackageName();
 
-            BinderHolder holder = new BinderHolder();
-            CameraBinderDecorator.newInstance(mUtils.getCameraService())
+            ICamera cameraUser = mUtils.getCameraService()
                     .connect(dummyCallbacks, cameraId, clientPackageName,
-                    CameraBinderTestUtils.USE_CALLING_UID, holder);
-            ICamera cameraUser = ICamera.Stub.asInterface(holder.getBinder());
+                            ICameraService.USE_CALLING_UID,
+                            ICameraService.USE_CALLING_PID);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
             Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -191,14 +174,11 @@
 
             String clientPackageName = getContext().getPackageName();
 
-            BinderHolder holder = new BinderHolder();
-
             try {
-                CameraBinderDecorator.newInstance(mUtils.getCameraService())
+                cameraUser = mUtils.getCameraService()
                         .connectLegacy(dummyCallbacks, cameraId, CAMERA_HAL_API_VERSION_1_0,
-                        clientPackageName,
-                        CameraBinderTestUtils.USE_CALLING_UID, holder);
-                cameraUser = ICamera.Stub.asInterface(holder.getBinder());
+                                clientPackageName,
+                                ICameraService.USE_CALLING_UID);
                 assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
                 Log.v(TAG, String.format("Camera %s connected as HAL1 legacy device", cameraId));
@@ -284,11 +264,11 @@
 
             String clientPackageName = getContext().getPackageName();
 
-            BinderHolder holder = new BinderHolder();
-            CameraBinderDecorator.newInstance(mUtils.getCameraService())
-                    .connectDevice(dummyCallbacks, cameraId,
-                    clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
-            ICameraDeviceUser cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+            ICameraDeviceUser cameraUser =
+                    mUtils.getCameraService().connectDevice(
+                        dummyCallbacks, cameraId,
+                        clientPackageName,
+                        ICameraService.USE_CALLING_UID);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
             Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -323,27 +303,33 @@
 
             ICameraServiceListener listener = new DummyCameraServiceListener();
 
-            assertTrue(
-                    "Listener was removed before added",
-                    mUtils.getCameraService().removeListener(listener) ==
-                    CameraBinderTestUtils.BAD_VALUE);
+            try {
+                mUtils.getCameraService().removeListener(listener);
+                fail("Listener was removed before added");
+            } catch (ServiceSpecificException e) {
+                assertEquals("Listener was removed before added",
+                        e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+            }
 
-            assertTrue("Listener was not added",
-                    mUtils.getCameraService().addListener(listener) ==
-                    CameraBinderTestUtils.NO_ERROR);
-            assertTrue(
-                    "Listener was wrongly added again",
-                    mUtils.getCameraService().addListener(listener) ==
-                    CameraBinderTestUtils.ALREADY_EXISTS);
+            mUtils.getCameraService().addListener(listener);
 
-            assertTrue(
-                    "Listener was not removed",
-                    mUtils.getCameraService().removeListener(listener) ==
-                    CameraBinderTestUtils.NO_ERROR);
-            assertTrue(
-                    "Listener was wrongly removed again",
-                    mUtils.getCameraService().removeListener(listener) ==
-                    CameraBinderTestUtils.BAD_VALUE);
+            try {
+                mUtils.getCameraService().addListener(listener);
+                fail("Listener was wrongly added again");
+            } catch (ServiceSpecificException e) {
+                assertEquals("Listener was wrongly added again",
+                        e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
+            }
+
+            mUtils.getCameraService().removeListener(listener);
+
+            try {
+                mUtils.getCameraService().removeListener(listener);
+                fail("Listener was wrongly removed twice");
+            } catch (ServiceSpecificException e) {
+                assertEquals("Listener was wrongly removed twice",
+                        e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+            }
         }
     }
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
index 5c4b23b..38fc49f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
@@ -18,10 +18,6 @@
 
     static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
 
-    protected static final int USE_CALLING_UID = -1;
-    protected static final int BAD_VALUE = -EINVAL;
-    protected static final int INVALID_OPERATION = -ENOSYS;
-    protected static final int ALREADY_EXISTS = -EEXIST;
     public static final int NO_ERROR = 0;
     private final Context mContext;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index d71b44b..5c1d8a7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -18,6 +18,7 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
+import android.hardware.ICameraService;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
@@ -27,12 +28,13 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.BinderHolder;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.media.Image;
 import android.media.ImageReader;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -164,11 +166,10 @@
     }
 
     private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception {
-        CameraMetadataNative metadata = new CameraMetadataNative();
+        CameraMetadataNative metadata = null;
         assertTrue(metadata.isEmpty());
 
-        int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
         assertFalse(metadata.isEmpty());
 
         CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false,
@@ -183,12 +184,13 @@
         return request;
     }
 
-    private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
-        int requestId = mCameraUser.submitRequest(request, streaming, null);
+    private SubmitInfo submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
+        SubmitInfo requestInfo = mCameraUser.submitRequest(request, streaming);
         assertTrue(
-                "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
-                requestId >= 0);
-        return requestId;
+                "Request IDs should be non-negative (expected: >= 0, actual: " +
+                requestInfo.getRequestId() + ")",
+                requestInfo.getRequestId() >= 0);
+        return requestInfo;
     }
 
     @Override
@@ -214,10 +216,8 @@
 
         mMockCb = spy(dummyCallbacks);
 
-        BinderHolder holder = new BinderHolder();
-        mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
-                clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
-        mCameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+        mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
+                clientPackageName, ICameraService.USE_CALLING_UID);
         assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
@@ -238,11 +238,10 @@
 
     @SmallTest
     public void testCreateDefaultRequest() throws Exception {
-        CameraMetadataNative metadata = new CameraMetadataNative();
+        CameraMetadataNative metadata = null;
         assertTrue(metadata.isEmpty());
 
-        int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
         assertFalse(metadata.isEmpty());
 
     }
@@ -252,18 +251,28 @@
         int streamId = mCameraUser.createStream(mOutputConfiguration);
         assertEquals(0, streamId);
 
-        assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(mOutputConfiguration));
+        try {
+            mCameraUser.createStream(mOutputConfiguration);
+            fail("Creating same stream twice");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Creating same stream twice",
+                    e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
+        }
 
-        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
+        mCameraUser.deleteStream(streamId);
     }
 
     @SmallTest
     public void testDeleteInvalidStream() throws Exception {
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(-1));
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0));
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(1));
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0xC0FFEE));
+        int[] badStreams = { -1, 0, 1, 0xC0FFEE };
+        for (int badStream : badStreams) {
+            try {
+                mCameraUser.deleteStream(badStream);
+                fail("Allowed bad stream delete");
+            } catch (ServiceSpecificException e) {
+                assertEquals(e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+            }
+        }
     }
 
     @SmallTest
@@ -273,8 +282,13 @@
         int streamId = mCameraUser.createStream(mOutputConfiguration);
         assertEquals(0, streamId);
 
-        assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(mOutputConfiguration));
+        try {
+            mCameraUser.createStream(mOutputConfiguration);
+            fail("Created same stream twice");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Created same stream twice",
+                    ICameraService.ERROR_ALREADY_EXISTS, e.errorCode);
+        }
 
         // Create second stream with a different surface.
         SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
@@ -286,8 +300,8 @@
         assertEquals(1, streamId2);
 
         // Clean up streams
-        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
-        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId2));
+        mCameraUser.deleteStream(streamId);
+        mCameraUser.deleteStream(streamId2);
     }
 
     @SmallTest
@@ -295,16 +309,25 @@
 
         CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
         CaptureRequest request1 = builder.build();
-        int status = mCameraUser.submitRequest(request1, /* streaming */false, null);
-        assertEquals("Expected submitRequest to return BAD_VALUE " +
-                "since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
+        try {
+            SubmitInfo requestInfo = mCameraUser.submitRequest(request1, /* streaming */false);
+            fail("Exception expected");
+        } catch(ServiceSpecificException e) {
+            assertEquals("Expected submitRequest to throw ServiceSpecificException with BAD_VALUE " +
+                    "since we had 0 surface targets set.", ICameraService.ERROR_ILLEGAL_ARGUMENT,
+                    e.errorCode);
+        }
 
         builder.addTarget(mSurface);
         CaptureRequest request2 = builder.build();
-        status = mCameraUser.submitRequest(request2, /* streaming */false, null);
-        assertEquals("Expected submitRequest to return BAD_VALUE since " +
-                "the target surface wasn't registered with createStream.",
-                CameraBinderTestUtils.BAD_VALUE, status);
+        try {
+            SubmitInfo requestInfo = mCameraUser.submitRequest(request2, /* streaming */false);
+            fail("Exception expected");
+        } catch(ServiceSpecificException e) {
+            assertEquals("Expected submitRequest to throw ILLEGAL_ARGUMENT " +
+                    "ServiceSpecificException since the target wasn't registered with createStream.",
+                    ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+        }
     }
 
     @SmallTest
@@ -314,9 +337,10 @@
         CaptureRequest request = builder.build();
 
         // Submit valid request twice.
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
-        int requestId2 = submitCameraRequest(request, /* streaming */false);
-        assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+        assertNotSame("Request IDs should be unique for multiple requests",
+                requestInfo1.getRequestId(), requestInfo2.getRequestId());
 
     }
 
@@ -329,32 +353,35 @@
 
         // Submit valid request once (non-streaming), and another time
         // (streaming)
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
 
-        int requestIdStreaming = submitCameraRequest(request, /* streaming */true);
-        assertNotSame("Request IDs should be unique for multiple requests", requestId1,
-                requestIdStreaming);
+        SubmitInfo requestInfoStreaming = submitCameraRequest(request, /* streaming */true);
+        assertNotSame("Request IDs should be unique for multiple requests",
+                requestInfo1.getRequestId(),
+                requestInfoStreaming.getRequestId());
 
-        int status = mCameraUser.cancelRequest(-1, null);
-        assertEquals("Invalid request IDs should not be cancellable",
-                CameraBinderTestUtils.BAD_VALUE, status);
+        try {
+            long lastFrameNumber = mCameraUser.cancelRequest(-1);
+            fail("Expected exception");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Invalid request IDs should not be cancellable",
+                    ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+        }
 
-        status = mCameraUser.cancelRequest(requestId1, null);
-        assertEquals("Non-streaming request IDs should not be cancellable",
-                CameraBinderTestUtils.BAD_VALUE, status);
+        try {
+            long lastFrameNumber = mCameraUser.cancelRequest(requestInfo1.getRequestId());
+            fail("Expected exception");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Non-streaming request IDs should not be cancellable",
+                    ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+        }
 
-        status = mCameraUser.cancelRequest(requestIdStreaming, null);
-        assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
-                status);
-
+        long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
     }
 
     @SmallTest
     public void testCameraInfo() throws RemoteException {
-        CameraMetadataNative info = new CameraMetadataNative();
-
-        int status = mCameraUser.getCameraInfo(/*out*/info);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        CameraMetadataNative info = mCameraUser.getCameraInfo();
 
         assertFalse(info.isEmpty());
         assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -362,10 +389,7 @@
 
     @SmallTest
     public void testCameraCharacteristics() throws RemoteException {
-        CameraMetadataNative info = new CameraMetadataNative();
-
-        int status = mUtils.getCameraService().getCameraCharacteristics(mCameraId, /*out*/info);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId);
 
         assertFalse(info.isEmpty());
         assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -374,18 +398,19 @@
     @SmallTest
     public void testWaitUntilIdle() throws Exception {
         CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
-        int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
+        SubmitInfo requestInfoStreaming = submitCameraRequest(builder.build(), /* streaming */true);
 
         // Test Bad case first: waitUntilIdle when there is active repeating request
-        int status = mCameraUser.waitUntilIdle();
-        assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
-            CameraBinderTestUtils.INVALID_OPERATION, status);
+        try {
+            mCameraUser.waitUntilIdle();
+        } catch (ServiceSpecificException e) {
+            assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
+                    ICameraService.ERROR_INVALID_OPERATION, e.errorCode);
+        }
 
         // Test good case, waitUntilIdle when there is no active repeating request
-        status = mCameraUser.cancelRequest(requestIdStreaming, null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
-        status = mCameraUser.waitUntilIdle();
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
+        mCameraUser.waitUntilIdle();
     }
 
     @SmallTest
@@ -411,12 +436,12 @@
         ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class);
 
         // Test both single request and streaming request.
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted(
                 any(CaptureResultExtras.class),
                 anyLong());
 
-        int streamingId = submitCameraRequest(request, /* streaming */true);
+        SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
                 .onCaptureStarted(
                         any(CaptureResultExtras.class),
@@ -436,22 +461,22 @@
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Try streaming
-        int streamingId = submitCameraRequest(request, /* streaming */true);
+        SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
 
         // Wait a bit to fill up the queue
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Cancel and make sure we eventually quiesce
-        status = mCameraUser.cancelRequest(streamingId, null);
+        long lastFrameNumber = mCameraUser.cancelRequest(streamingInfo.getRequestId());
 
         verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onDeviceIdle();
 
         // Submit a few capture requests
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
-        int requestId2 = submitCameraRequest(request, /* streaming */false);
-        int requestId3 = submitCameraRequest(request, /* streaming */false);
-        int requestId4 = submitCameraRequest(request, /* streaming */false);
-        int requestId5 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
 
         // And wait for more idle
         verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onDeviceIdle();
@@ -463,38 +488,34 @@
         int status;
 
         // Initial flush should work
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        long lastFrameNumber = mCameraUser.flush();
 
         // Then set up a stream
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Flush should still be a no-op, really
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        lastFrameNumber = mCameraUser.flush();
 
         // Submit a few capture requests
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
-        int requestId2 = submitCameraRequest(request, /* streaming */false);
-        int requestId3 = submitCameraRequest(request, /* streaming */false);
-        int requestId4 = submitCameraRequest(request, /* streaming */false);
-        int requestId5 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
 
         // Then flush and wait for idle
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        lastFrameNumber = mCameraUser.flush();
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onDeviceIdle();
 
         // Now a streaming request
-        int streamingId = submitCameraRequest(request, /* streaming */true);
+        SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
 
         // Wait a bit to fill up the queue
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Then flush and wait for the idle callback
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        lastFrameNumber = mCameraUser.flush();
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onDeviceIdle();
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
deleted file mode 100644
index 33c6388..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
+++ /dev/null
@@ -1,173 +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.mediaframeworktest.unit;
-
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-import android.os.TransactionTooLargeException;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import static org.mockito.Mockito.*;
-import static android.hardware.camera2.utils.CameraBinderDecorator.*;
-import static android.hardware.camera2.CameraAccessException.*;
-import static android.system.OsConstants.*;
-
-import junit.framework.Assert;
-
-public class CameraUtilsBinderDecoratorTest extends junit.framework.TestCase {
-
-    private interface ICameraBinderStereotype {
-
-        double doNothing();
-
-        // int is a 'status_t'
-        int doSomethingPositive();
-
-        int doSomethingNoError();
-
-        int doSomethingPermissionDenied();
-
-        int doSomethingAlreadyExists();
-
-        int doSomethingBadValue();
-
-        int doSomethingDeadObject() throws CameraRuntimeException;
-
-        int doSomethingBadPolicy() throws CameraRuntimeException;
-
-        int doSomethingDeviceBusy() throws CameraRuntimeException;
-
-        int doSomethingNoSuchDevice() throws CameraRuntimeException;
-
-        int doSomethingUnknownErrorCode();
-
-        int doSomethingThrowDeadObjectException() throws RemoteException;
-
-        int doSomethingThrowTransactionTooLargeException() throws RemoteException;
-    }
-
-    private static final double SOME_ARBITRARY_DOUBLE = 1.0;
-    private static final int SOME_ARBITRARY_POSITIVE_INT = 5;
-    private static final int SOME_ARBITRARY_NEGATIVE_INT = -0xC0FFEE;
-
-    @SmallTest
-    public void testStereotypes() {
-
-        ICameraBinderStereotype mock = mock(ICameraBinderStereotype.class);
-        try {
-            when(mock.doNothing()).thenReturn(SOME_ARBITRARY_DOUBLE);
-            when(mock.doSomethingPositive()).thenReturn(SOME_ARBITRARY_POSITIVE_INT);
-            when(mock.doSomethingNoError()).thenReturn(NO_ERROR);
-            when(mock.doSomethingPermissionDenied()).thenReturn(PERMISSION_DENIED);
-            when(mock.doSomethingAlreadyExists()).thenReturn(ALREADY_EXISTS);
-            when(mock.doSomethingBadValue()).thenReturn(BAD_VALUE);
-            when(mock.doSomethingDeadObject()).thenReturn(DEAD_OBJECT);
-            when(mock.doSomethingBadPolicy()).thenReturn(-EACCES);
-            when(mock.doSomethingDeviceBusy()).thenReturn(-EBUSY);
-            when(mock.doSomethingNoSuchDevice()).thenReturn(-ENODEV);
-            when(mock.doSomethingUnknownErrorCode()).thenReturn(SOME_ARBITRARY_NEGATIVE_INT);
-            when(mock.doSomethingThrowDeadObjectException()).thenThrow(new DeadObjectException());
-            when(mock.doSomethingThrowTransactionTooLargeException()).thenThrow(
-                    new TransactionTooLargeException());
-        } catch (RemoteException e) {
-            Assert.fail("Unreachable");
-        }
-
-        ICameraBinderStereotype decoratedMock = CameraBinderDecorator.newInstance(mock);
-
-        // ignored by decorator because return type is double, not int
-        assertEquals(SOME_ARBITRARY_DOUBLE, decoratedMock.doNothing());
-
-        // pass through for positive values
-        assertEquals(SOME_ARBITRARY_POSITIVE_INT, decoratedMock.doSomethingPositive());
-
-        // pass through NO_ERROR
-        assertEquals(NO_ERROR, decoratedMock.doSomethingNoError());
-
-        try {
-            decoratedMock.doSomethingPermissionDenied();
-            Assert.fail("Should've thrown SecurityException");
-        } catch (SecurityException e) {
-        }
-
-        assertEquals(ALREADY_EXISTS, decoratedMock.doSomethingAlreadyExists());
-
-        try {
-            decoratedMock.doSomethingBadValue();
-            Assert.fail("Should've thrown IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            decoratedMock.doSomethingDeadObject();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISCONNECTED, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingBadPolicy();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISABLED, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingDeviceBusy();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_IN_USE, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingNoSuchDevice();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISCONNECTED, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingUnknownErrorCode();
-            Assert.fail("Should've thrown UnsupportedOperationException");
-        } catch (UnsupportedOperationException e) {
-            assertEquals(String.format("Unknown error %d",
-                    SOME_ARBITRARY_NEGATIVE_INT), e.getMessage());
-        }
-
-        try {
-            decoratedMock.doSomethingThrowDeadObjectException();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISCONNECTED, e.getReason());
-        } catch (RemoteException e) {
-            Assert.fail("Should not throw a DeadObjectException directly, but rethrow");
-        }
-
-        try {
-            decoratedMock.doSomethingThrowTransactionTooLargeException();
-            Assert.fail("Should've thrown UnsupportedOperationException");
-        } catch (UnsupportedOperationException e) {
-            assertTrue(e.getCause() instanceof TransactionTooLargeException);
-        } catch (RemoteException e) {
-            Assert.fail("Should not throw a TransactionTooLargeException directly, but rethrow");
-        }
-    }
-
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
deleted file mode 100644
index c3b6006..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
+++ /dev/null
@@ -1,171 +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.mediaframeworktest.unit;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.camera2.utils.*;
-import android.hardware.camera2.utils.Decorator.DecoratorListener;
-
-import junit.framework.Assert;
-
-import java.lang.reflect.Method;
-
-/**
- * adb shell am instrument -e class 'com.android.mediaframeworktest.unit.CameraUtilsDecoratorTest' \
- *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
- */
-public class CameraUtilsDecoratorTest extends junit.framework.TestCase {
-    private DummyListener mDummyListener;
-    private DummyInterface mIface;
-
-    @Override
-    public void setUp() {
-        mDummyListener = new DummyListener();
-        mIface = Decorator.newInstance(new DummyImpl(), mDummyListener);
-    }
-
-    interface DummyInterface {
-        int addValues(int x, int y, int z);
-
-        void raiseException() throws Exception;
-
-        void raiseUnsupportedOperationException() throws UnsupportedOperationException;
-    }
-
-    class DummyImpl implements DummyInterface {
-        @Override
-        public int addValues(int x, int y, int z) {
-            return x + y + z;
-        }
-
-        @Override
-        public void raiseException() throws Exception {
-            throw new Exception("Test exception");
-        }
-
-        @Override
-        public void raiseUnsupportedOperationException() throws UnsupportedOperationException {
-            throw new UnsupportedOperationException("Test exception");
-        }
-    }
-
-    class DummyListener implements DecoratorListener {
-
-        public boolean beforeCalled = false;
-        public boolean afterCalled = false;
-        public boolean catchCalled = false;
-        public boolean finallyCalled = false;
-        public Object resultValue = null;
-
-        public boolean raiseException = false;
-
-        @Override
-        public void onBeforeInvocation(Method m, Object[] args) {
-            beforeCalled = true;
-        }
-
-        @Override
-        public void onAfterInvocation(Method m, Object[] args, Object result) {
-            afterCalled = true;
-            resultValue = result;
-
-            if (raiseException) {
-                throw new UnsupportedOperationException("Test exception");
-            }
-        }
-
-        @Override
-        public boolean onCatchException(Method m, Object[] args, Throwable t) {
-            catchCalled = true;
-            return false;
-        }
-
-        @Override
-        public void onFinally(Method m, Object[] args) {
-            finallyCalled = true;
-        }
-
-    };
-
-    @SmallTest
-    public void testDecorator() {
-
-        // TODO rewrite this using mocks
-
-        assertTrue(mIface.addValues(1, 2, 3) == 6);
-        assertTrue(mDummyListener.beforeCalled);
-        assertTrue(mDummyListener.afterCalled);
-
-        int resultValue = (Integer)mDummyListener.resultValue;
-        assertTrue(resultValue == 6);
-        assertTrue(mDummyListener.finallyCalled);
-        assertFalse(mDummyListener.catchCalled);
-    }
-
-    @SmallTest
-    public void testDecoratorExceptions() {
-
-        boolean gotExceptions = false;
-        try {
-            mIface.raiseException();
-        } catch (Exception e) {
-            gotExceptions = true;
-            assertTrue(e.getMessage() == "Test exception");
-        }
-        assertTrue(gotExceptions);
-        assertTrue(mDummyListener.beforeCalled);
-        assertFalse(mDummyListener.afterCalled);
-        assertTrue(mDummyListener.catchCalled);
-        assertTrue(mDummyListener.finallyCalled);
-    }
-
-    @SmallTest
-    public void testDecoratorUnsupportedOperationException() {
-
-        boolean gotExceptions = false;
-        try {
-            mIface.raiseUnsupportedOperationException();
-        } catch (UnsupportedOperationException e) {
-            gotExceptions = true;
-            assertTrue(e.getMessage() == "Test exception");
-        }
-        assertTrue(gotExceptions);
-        assertTrue(mDummyListener.beforeCalled);
-        assertFalse(mDummyListener.afterCalled);
-        assertTrue(mDummyListener.catchCalled);
-        assertTrue(mDummyListener.finallyCalled);
-    }
-
-    @SmallTest
-    public void testDecoratorRaisesException() {
-
-        boolean gotExceptions = false;
-        try {
-            mDummyListener.raiseException = true;
-            mIface.addValues(1, 2, 3);
-            Assert.fail("unreachable");
-        } catch (UnsupportedOperationException e) {
-            gotExceptions = true;
-            assertTrue(e.getMessage() == "Test exception");
-        }
-        assertTrue(gotExceptions);
-        assertTrue(mDummyListener.beforeCalled);
-        assertTrue(mDummyListener.afterCalled);
-        assertFalse(mDummyListener.catchCalled);
-        assertTrue(mDummyListener.finallyCalled);
-    }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
deleted file mode 100644
index 02c9f2a..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
+++ /dev/null
@@ -1,77 +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.mediaframeworktest.unit;
-
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-public class CameraUtilsRuntimeExceptionTest extends junit.framework.TestCase {
-
-    @SmallTest
-    public void testCameraRuntimeException1() {
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345);
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertNull(e.getMessage());
-            assertNull(e.getCause());
-        }
-    }
-
-    @SmallTest
-    public void testCameraRuntimeException2() {
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello");
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertEquals("Hello", e.getMessage());
-            assertNull(e.getCause());
-        }
-    }
-
-    @SmallTest
-    public void testCameraRuntimeException3() {
-        Throwable cause = new IllegalStateException("For great justice");
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, cause);
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertNull(e.getMessage());
-            assertEquals(cause, e.getCause());
-        }
-    }
-
-    @SmallTest
-    public void testCameraRuntimeException4() {
-        Throwable cause = new IllegalStateException("For great justice");
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello", cause);
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertEquals("Hello", e.getMessage());
-            assertEquals(cause, e.getCause());
-        }
-    }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
new file mode 100644
index 0000000..312d9aa
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.android.mediaframeworktest.R;
+
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.ExifInterface;
+import android.os.Environment;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+public class ExifInterfaceTest extends AndroidTestCase {
+    private static final String TAG = ExifInterface.class.getSimpleName();
+    private static final boolean VERBOSE = false;  // lots of logging
+
+    private static final double DIFFERENCE_TOLERANCE = .001;
+
+    // List of files.
+    private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
+    private static final String EXIF_BYTE_ORDER_MM_JPEG = "image_exif_byte_order_mm.jpg";
+    private static final String LG_G4_ISO_800_DNG = "lg_g4_iso_800.dng";
+    private static final String VOLANTIS_JPEG = "volantis.jpg";
+    private static final int[] IMAGE_RESOURCES = new int[] {
+            R.raw.image_exif_byte_order_ii,  R.raw.image_exif_byte_order_mm, R.raw.lg_g4_iso_800,
+            R.raw.volantis };
+    private static final String[] IMAGE_FILENAMES = new String[] {
+            EXIF_BYTE_ORDER_II_JPEG, EXIF_BYTE_ORDER_MM_JPEG, LG_G4_ISO_800_DNG, VOLANTIS_JPEG };
+
+    private static final String[] EXIF_TAGS = {
+            ExifInterface.TAG_MAKE,
+            ExifInterface.TAG_MODEL,
+            ExifInterface.TAG_F_NUMBER,
+            ExifInterface.TAG_DATETIME,
+            ExifInterface.TAG_EXPOSURE_TIME,
+            ExifInterface.TAG_FLASH,
+            ExifInterface.TAG_FOCAL_LENGTH,
+            ExifInterface.TAG_GPS_ALTITUDE,
+            ExifInterface.TAG_GPS_ALTITUDE_REF,
+            ExifInterface.TAG_GPS_DATESTAMP,
+            ExifInterface.TAG_GPS_LATITUDE,
+            ExifInterface.TAG_GPS_LATITUDE_REF,
+            ExifInterface.TAG_GPS_LONGITUDE,
+            ExifInterface.TAG_GPS_LONGITUDE_REF,
+            ExifInterface.TAG_GPS_PROCESSING_METHOD,
+            ExifInterface.TAG_GPS_TIMESTAMP,
+            ExifInterface.TAG_IMAGE_LENGTH,
+            ExifInterface.TAG_IMAGE_WIDTH,
+            ExifInterface.TAG_ISO_SPEED_RATINGS,
+            ExifInterface.TAG_ORIENTATION,
+            ExifInterface.TAG_WHITE_BALANCE
+    };
+
+    private static class ExpectedValue {
+        // Thumbnail information.
+        public final boolean hasThumbnail;
+        public final int thumbnailWidth;
+        public final int thumbnailHeight;
+
+        // GPS information.
+        public final boolean hasLatLong;
+        public final float latitude;
+        public final float longitude;
+        public final float altitude;
+
+        // Values.
+        public final String make;
+        public final String model;
+        public final float aperture;
+        public final String datetime;
+        public final float exposureTime;
+        public final float flash;
+        public final String focalLength;
+        public final String gpsAltitude;
+        public final String gpsAltitudeRef;
+        public final String gpsDatestamp;
+        public final String gpsLatitude;
+        public final String gpsLatitudeRef;
+        public final String gpsLongitude;
+        public final String gpsLongitudeRef;
+        public final String gpsProcessingMethod;
+        public final String gpsTimestamp;
+        public final int imageLength;
+        public final int imageWidth;
+        public final String iso;
+        public final int orientation;
+        public final int whiteBalance;
+
+        private static String getString(TypedArray typedArray, int index) {
+            String stringValue = typedArray.getString(index);
+            if (stringValue == null || stringValue.equals("")) {
+                return null;
+            }
+            return stringValue.trim();
+        }
+
+        public ExpectedValue(TypedArray typedArray) {
+            // Reads thumbnail information.
+            hasThumbnail = typedArray.getBoolean(0, false);
+            thumbnailWidth = typedArray.getInt(1, 0);
+            thumbnailHeight = typedArray.getInt(2, 0);
+
+            // Reads GPS information.
+            hasLatLong = typedArray.getBoolean(3, false);
+            latitude = typedArray.getFloat(4, 0f);
+            longitude = typedArray.getFloat(5, 0f);
+            altitude = typedArray.getFloat(6, 0f);
+
+            // Reads values.
+            make = getString(typedArray, 7);
+            model = getString(typedArray, 8);
+            aperture = typedArray.getFloat(9, 0f);
+            datetime = getString(typedArray, 10);
+            exposureTime = typedArray.getFloat(11, 0f);
+            flash = typedArray.getFloat(12, 0f);
+            focalLength = getString(typedArray, 13);
+            gpsAltitude = getString(typedArray, 14);
+            gpsAltitudeRef = getString(typedArray, 15);
+            gpsDatestamp = getString(typedArray, 16);
+            gpsLatitude = getString(typedArray, 17);
+            gpsLatitudeRef = getString(typedArray, 18);
+            gpsLongitude = getString(typedArray, 19);
+            gpsLongitudeRef = getString(typedArray, 20);
+            gpsProcessingMethod = getString(typedArray, 21);
+            gpsTimestamp = getString(typedArray, 22);
+            imageLength = typedArray.getInt(23, 0);
+            imageWidth = typedArray.getInt(24, 0);
+            iso = getString(typedArray, 25);
+            orientation = typedArray.getInt(26, 0);
+            whiteBalance = typedArray.getInt(27, 0);
+
+            typedArray.recycle();
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String outputPath = new File(Environment.getExternalStorageDirectory(),
+                    IMAGE_FILENAMES[i]).getAbsolutePath();
+            try (InputStream inputStream = getContext().getResources().openRawResource(
+                    IMAGE_RESOURCES[i])) {
+                try (FileOutputStream outputStream = new FileOutputStream(outputPath)) {
+                    Streams.copy(inputStream, outputStream);
+                }
+            }
+        }
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String imageFilePath = new File(Environment.getExternalStorageDirectory(),
+                    IMAGE_FILENAMES[i]).getAbsolutePath();
+            File imageFile = new File(imageFilePath);
+            if (imageFile.exists()) {
+                imageFile.delete();
+            }
+        }
+
+        super.tearDown();
+    }
+
+    private void printExifTagsAndValues(String fileName, ExifInterface exifInterface) {
+        // Prints thumbnail information.
+        if (exifInterface.hasThumbnail()) {
+            byte[] thumbnailBytes = exifInterface.getThumbnail();
+            if (thumbnailBytes != null) {
+                Log.v(TAG, fileName + " Thumbnail size = " + thumbnailBytes.length);
+                Bitmap bitmap = BitmapFactory.decodeByteArray(
+                        thumbnailBytes, 0, thumbnailBytes.length);
+                if (bitmap == null) {
+                    Log.e(TAG, fileName + " Corrupted thumbnail!");
+                } else {
+                    Log.v(TAG, fileName + " Thumbnail size: " + bitmap.getWidth() + ", "
+                            + bitmap.getHeight());
+                }
+            } else {
+                Log.e(TAG, fileName + " Unexpected result: No thumbnails were found. "
+                        + "A thumbnail is expected.");
+            }
+        } else {
+            if (exifInterface.getThumbnail() != null) {
+                Log.e(TAG, fileName + " Unexpected result: A thumbnail was found. "
+                        + "No thumbnail is expected.");
+            } else {
+                Log.v(TAG, fileName + " No thumbnail");
+            }
+        }
+
+        // Prints GPS information.
+        Log.v(TAG, fileName + " Altitude = " + exifInterface.getAltitude(.0));
+
+        float[] latLong = new float[2];
+        if (exifInterface.getLatLong(latLong)) {
+            Log.v(TAG, fileName + " Latitude = " + latLong[0]);
+            Log.v(TAG, fileName + " Longitude = " + latLong[1]);
+        } else {
+            Log.v(TAG, fileName + " No latlong data");
+        }
+
+        // Prints values.
+        for (String tagKey : EXIF_TAGS) {
+            String tagValue = exifInterface.getAttribute(tagKey);
+            Log.v(TAG, fileName + " Key{" + tagKey + "} = '" + tagValue + "'");
+        }
+    }
+
+    private void assertIntTag(ExifInterface exifInterface, String tag, int expectedValue) {
+        int intValue = exifInterface.getAttributeInt(tag, 0);
+        assertEquals(expectedValue, intValue);
+    }
+
+    private void assertFloatTag(ExifInterface exifInterface, String tag, float expectedValue) {
+        double doubleValue = exifInterface.getAttributeDouble(tag, 0.0);
+        assertEquals(expectedValue, doubleValue, DIFFERENCE_TOLERANCE);
+    }
+
+    private void assertStringTag(ExifInterface exifInterface, String tag, String expectedValue) {
+        String stringValue = exifInterface.getAttribute(tag);
+        if (stringValue != null) {
+            stringValue = stringValue.trim();
+        }
+
+        assertEquals(expectedValue, stringValue);
+    }
+
+    private void compareWithExpectedValue(ExifInterface exifInterface,
+            ExpectedValue expectedValue, String verboseTag) {
+        if (VERBOSE) {
+            printExifTagsAndValues(verboseTag, exifInterface);
+        }
+        // Checks a thumbnail image.
+        assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
+        if (expectedValue.hasThumbnail) {
+            byte[] thumbnailBytes = exifInterface.getThumbnail();
+            assertNotNull(thumbnailBytes);
+            Bitmap thumbnailBitmap =
+                    BitmapFactory.decodeByteArray(thumbnailBytes, 0, thumbnailBytes.length);
+            assertNotNull(thumbnailBitmap);
+            assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+            assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
+        } else {
+            assertNull(exifInterface.getThumbnail());
+        }
+
+        // Checks GPS information.
+        float[] latLong = new float[2];
+        assertEquals(expectedValue.hasLatLong, exifInterface.getLatLong(latLong));
+        if (expectedValue.hasLatLong) {
+            assertEquals(expectedValue.latitude, latLong[0], DIFFERENCE_TOLERANCE);
+            assertEquals(expectedValue.longitude, latLong[1], DIFFERENCE_TOLERANCE);
+        }
+        assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
+
+        // Checks values.
+        assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
+        assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
+        assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
+        assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
+        assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
+        assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
+        assertStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE, expectedValue.gpsAltitude);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE_REF,
+                expectedValue.gpsAltitudeRef);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_DATESTAMP, expectedValue.gpsDatestamp);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE, expectedValue.gpsLatitude);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE_REF,
+                expectedValue.gpsLatitudeRef);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE, expectedValue.gpsLongitude);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE_REF,
+                expectedValue.gpsLongitudeRef);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_PROCESSING_METHOD,
+                expectedValue.gpsProcessingMethod);
+        assertStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP, expectedValue.gpsTimestamp);
+        assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
+        assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
+        assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
+        assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
+        assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
+    }
+
+    private void testExifInterfaceCommon(File imageFile, ExpectedValue expectedValue)
+            throws IOException {
+        String verboseTag = imageFile.getName();
+
+        // Creates via path.
+        ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+        compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+
+        // Creates from an asset file.
+        InputStream in = null;
+        try {
+            in = mContext.getAssets().open(imageFile.getName());
+            exifInterface = new ExifInterface(in);
+            compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+
+        // Creates via InputStream.
+        in = null;
+        try {
+            in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+            exifInterface = new ExifInterface(in);
+            compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+
+        // Creates via FileDescriptor.
+        FileDescriptor fd = null;
+        try {
+            fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
+            exifInterface = new ExifInterface(fd);
+            compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        } finally {
+            IoUtils.closeQuietly(fd);
+        }
+    }
+
+    private void testSaveAttributes_withFileName(File imageFile, ExpectedValue expectedValue)
+            throws IOException {
+        String verboseTag = imageFile.getName();
+
+        ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+        exifInterface.saveAttributes();
+        exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+        compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+
+        // Test for modifying one attribute.
+        String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+        exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
+        exifInterface.saveAttributes();
+        exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+        assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+        // Restore the backup value.
+        exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
+        exifInterface.saveAttributes();
+        exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+        compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+    }
+
+    private void testSaveAttributes_withFileDescriptor(File imageFile, ExpectedValue expectedValue)
+            throws IOException {
+        String verboseTag = imageFile.getName();
+
+        FileDescriptor fd = null;
+        try {
+            fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
+            ExifInterface exifInterface = new ExifInterface(fd);
+            exifInterface.saveAttributes();
+            Os.lseek(fd, 0, OsConstants.SEEK_SET);
+            exifInterface = new ExifInterface(fd);
+            compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+
+            // Test for modifying one attribute.
+            String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+            exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
+            exifInterface.saveAttributes();
+            Os.lseek(fd, 0, OsConstants.SEEK_SET);
+            exifInterface = new ExifInterface(fd);
+            assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+            // Restore the backup value.
+            exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
+            exifInterface.saveAttributes();
+            Os.lseek(fd, 0, OsConstants.SEEK_SET);
+            exifInterface = new ExifInterface(fd);
+            compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        } finally {
+            IoUtils.closeQuietly(fd);
+        }
+    }
+
+    private void testSaveAttributes_withInputStream(File imageFile, ExpectedValue expectedValue)
+            throws IOException {
+        InputStream in = null;
+        try {
+            in = getContext().getAssets().open(imageFile.getName());
+            ExifInterface exifInterface = new ExifInterface(in);
+            exifInterface.saveAttributes();
+        } catch (UnsupportedOperationException e) {
+            // Expected. saveAttributes is not supported with an ExifInterface object which was
+            // created with InputStream.
+            return;
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+        fail("Should not reach here!");
+    }
+
+    private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
+            throws IOException {
+        ExpectedValue expectedValue = new ExpectedValue(
+                getContext().getResources().obtainTypedArray(typedArrayResourceId));
+        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+        // Test for reading from various inputs.
+        testExifInterfaceCommon(imageFile, expectedValue);
+
+        // Test for saving attributes.
+        testSaveAttributes_withFileName(imageFile, expectedValue);
+        testSaveAttributes_withFileDescriptor(imageFile, expectedValue);
+        testSaveAttributes_withInputStream(imageFile, expectedValue);
+    }
+
+    private void testExifInterfaceForRaw(String fileName, int typedArrayResourceId)
+            throws IOException {
+        ExpectedValue expectedValue = new ExpectedValue(
+                getContext().getResources().obtainTypedArray(typedArrayResourceId));
+        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+        // Test for reading from various inputs.
+        testExifInterfaceCommon(imageFile, expectedValue);
+
+        // Since ExifInterface does not support for saving attributes for RAW files, do not test
+        // about writing back in here.
+    }
+
+    public void testReadExifDataFromExifByteOrderIIJpeg() throws Throwable {
+        testExifInterfaceForJpeg(EXIF_BYTE_ORDER_II_JPEG, R.array.exifbyteorderii_jpg);
+    }
+
+    public void testReadExifDataFromExifByteOrderMMJpeg() throws Throwable {
+        testExifInterfaceForJpeg(EXIF_BYTE_ORDER_MM_JPEG, R.array.exifbyteordermm_jpg);
+    }
+
+    public void testReadExifDataFromLgG4Iso800Dng() throws Throwable {
+        testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
+    }
+
+    public void testDoNotFailOnCorruptedImage() throws Throwable {
+        // To keep the compatibility with old versions of ExifInterface, even on a corrupted image,
+        // it shouldn't raise any exceptions except an IOException when unable to open a file.
+        byte[] bytes = new byte[1024];
+        try {
+            new ExifInterface(new ByteArrayInputStream(bytes));
+            // Always success
+        } catch (IOException e) {
+            fail("Should not reach here!");
+        }
+    }
+
+    public void testReadExifDataFromVolantisJpg() throws Throwable {
+        // Test if it is possible to parse the volantis generated JPEG smoothly.
+        testExifInterfaceForJpeg(VOLANTIS_JPEG, R.array.volantis_jpg);
+    }
+}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 76c701a..5cfe300 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -105,6 +105,14 @@
 
 /*****************************************************************************/
 
+int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
+        int32_t samplingPeriodUs, int maxBatchReportLatencyUs)
+{
+    return static_cast<SensorEventQueue*>(queue)->enableSensor(
+            static_cast<Sensor const*>(sensor)->getHandle(), samplingPeriodUs,
+                    maxBatchReportLatencyUs, 0);
+}
+
 int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor)
 {
     return static_cast<SensorEventQueue*>(queue)->enableSensor(
diff --git a/opengl/java/android/opengl/GLES30.java b/opengl/java/android/opengl/GLES30.java
index 342ffa4..74181c5 100644
--- a/opengl/java/android/opengl/GLES30.java
+++ b/opengl/java/android/opengl/GLES30.java
@@ -889,7 +889,10 @@
     );
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
-
+    /**
+     * @deprecated
+     * Use the version that takes a ByteBuffer as the last argument, or the versions that return a String.
+     * */
     public static native void glGetTransformFeedbackVarying(
         int program,
         int index,
@@ -902,6 +905,18 @@
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
 
+    public static native void glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        int bufsize,
+        java.nio.IntBuffer length,
+        java.nio.IntBuffer size,
+        java.nio.IntBuffer type,
+        java.nio.ByteBuffer name
+    );
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
     public static native String glGetTransformFeedbackVarying(
         int program,
         int index,
@@ -1791,4 +1806,16 @@
         java.nio.IntBuffer params
     );
 
+    // C function void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint offset )
+
+    public static native void glReadPixels(
+        int x,
+        int y,
+        int width,
+        int height,
+        int format,
+        int type,
+        int offset
+    );
+
 }
diff --git a/packages/BackupRestoreConfirmation/res/values-be-rBY/strings.xml b/packages/BackupRestoreConfirmation/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..24662fe
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-be-rBY/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="backup_confirm_title" msgid="827563724209303345">"Поўнае рэзервовае капіяванне"</string>
+    <string name="restore_confirm_title" msgid="5469365809567486602">"Поўнае аднаўленне"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Было прапанавана поўнае рэзервовае капіяванне ўсіх дадзеных на падлучаным настольным кампутары. Дазволіць гэта?\n\nКалі вы самі не запытвалі рэзервовае капiяванне, спынiце аперацыю."</string>
+    <string name="allow_backup_button_label" msgid="4217228747769644068">"Рэзервовае капіяванне дадзеных"</string>
+    <string name="deny_backup_button_label" msgid="6009119115581097708">"Не ствараць рэзервовыя копіі"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Запытана поўнае аднаўленне ўсіх дадзеных з падлучанага настольнага кампутара. Дазволіць гэта?\n\nКалі вы самі не запытвалі аднаўленне, не дазваляйце працягваць аперацыю. Гэта прывядзе да замены якіх-небудзь дадзеных, якія зараз знаходзяцца на прыладзе."</string>
+    <string name="allow_restore_button_label" msgid="3081286752277127827">"Аднавіць мае дадзеныя"</string>
+    <string name="deny_restore_button_label" msgid="1724367334453104378">"Не аднаўляць"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Увядзіце ваш бягучы пароль рэзервовага капіявання ніжэй:"</string>
+    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Увядзіце нiжэй пароль для расшыфравання прылады."</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Увядзіце пароль для расшыфравання прылады. Ён таксама будзе выкарыстоўвацца для расшыфравання рэзервовай копіі."</string>
+    <string name="backup_enc_password_text" msgid="4981585714795233099">"Увядзіце пароль, які выкарыстоўваецца для шыфравання ўсіх дадзеных рэзервовага капіявання. Калі гэтае поле пакінуць пустым, будзе выкарыстоўвацца бягучы пароль рэзервовага капіявання:"</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Калі вы жадаеце зашыфраваць усе дадзеныя рэзервовага капіявання, увядзіце пароль ніжэй:"</string>
+    <string name="backup_enc_password_required" msgid="7889652203371654149">"Даныя на вашай прыладзе зашыфраваны, таму вы павінны зашыфраваць рэзервовую копію. Калі ласка, увядзіце пароль ніжэй:"</string>
+    <string name="restore_enc_password_text" msgid="6140898525580710823">"Калі дадзеныя для аднаўлення зашыфраваныя, увядзіце пароль ніжэй:"</string>
+    <string name="toast_backup_started" msgid="550354281452756121">"Рэзервовае капіяванне..."</string>
+    <string name="toast_backup_ended" msgid="3818080769548726424">"Рэзервовае капіяванне скончылася"</string>
+    <string name="toast_restore_started" msgid="7881679218971277385">"Пачынаецца аднаўленне..."</string>
+    <string name="toast_restore_ended" msgid="1764041639199696132">"Аднаўленне скончылася"</string>
+    <string name="toast_timeout" msgid="5276598587087626877">"Тайм-аўт аперацыі"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-bs-rBA/strings.xml b/packages/BackupRestoreConfirmation/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..53b0bce
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-bs-rBA/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="backup_confirm_title" msgid="827563724209303345">"Napraviti potpunu rezervnu kopiju"</string>
+    <string name="restore_confirm_title" msgid="5469365809567486602">"Izvrši potpuno obnavljanje"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Zatraženo je pravljenje potpune rezervne kopije svih podataka na povezani računar. Da li želite da dozvolite to?\n\nPrekinite radnju ukoliko to niste sami zatražili."</string>
+    <string name="allow_backup_button_label" msgid="4217228747769644068">"Napravi rezervnu kopiju mojih podataka"</string>
+    <string name="deny_backup_button_label" msgid="6009119115581097708">"Nemoj napraviti rezervnu kopiju"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Sa povezanog računara je upućen zahtjev za potpuno obnavljanje svih podataka. Želite li to dozvoliti?\n\nUkoliko niste uputili zahtjev za obnavljanje, prekinite radnju. Ovim će zamijeniti svi podaci koji su trenutno na uređaju!"</string>
+    <string name="allow_restore_button_label" msgid="3081286752277127827">"Obnovi moje podatke"</string>
+    <string name="deny_restore_button_label" msgid="1724367334453104378">"Prekinuti obnavljanje podataka"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Ispod unesite svoju trenutnu lozinku za rezervnu kopiju:"</string>
+    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Ispod unesite svoju lozinku za šifriranje uređaja."</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Molimo vas unesite svoju lozinku za šifriranje uređaja ispod. Ona će se koristiti i za šifriranje arhive rezervnih kopija."</string>
+    <string name="backup_enc_password_text" msgid="4981585714795233099">"Unesite lozinku za šifriranje potpune rezervne kopije podataka. Ukoliko ne unesete lozinku, primijenit će se vaša trenutna lozinka za rezervnu kopiju:"</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ukoliko želite šifrirati potpunu rezervnu kopiju podataka, unesite lozinku ispod:"</string>
+    <string name="backup_enc_password_required" msgid="7889652203371654149">"Pošto je vaš uređaj šifriran, potrebno je šifrirati rezervnu kopiju. Unesite šifru ispod:"</string>
+    <string name="restore_enc_password_text" msgid="6140898525580710823">"Ukoliko su podaci za obnavljanje šifrirani, unesite lozinku ispod:"</string>
+    <string name="toast_backup_started" msgid="550354281452756121">"Pravljenje rezervne kopije..."</string>
+    <string name="toast_backup_ended" msgid="3818080769548726424">"Pravljenje rezervne kopije završeno"</string>
+    <string name="toast_restore_started" msgid="7881679218971277385">"Počinje obnavljanje podataka..."</string>
+    <string name="toast_restore_ended" msgid="1764041639199696132">"Obnavljanje podatka završeno"</string>
+    <string name="toast_timeout" msgid="5276598587087626877">"Isteklo je vrijeme za izvršenje radnje"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
index d863091..966e7f9 100644
--- a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
@@ -22,18 +22,18 @@
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Creați copii de rezervă pentru datele dvs."</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nu creați copii de rezervă"</string>
     <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. ați solicitat această restabilire, nu permiteți continuarea operațiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
-    <string name="allow_restore_button_label" msgid="3081286752277127827">"Restabiliţi datele dvs."</string>
+    <string name="allow_restore_button_label" msgid="3081286752277127827">"Restabiliți datele dvs."</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Nu restabiliți"</string>
-    <string name="current_password_text" msgid="8268189555578298067">"Introduceţi mai jos parola actuală pentru copia de rezervă:"</string>
-    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Introduceţi mai jos parola pentru criptarea dispozitivului."</string>
-    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Introduceţi mai jos parola de criptare a dispozitivului. Aceasta va fi utilizată, de asemenea, pentru a cripta arhiva copiei de rezervă."</string>
-    <string name="backup_enc_password_text" msgid="4981585714795233099">"Introduceţi o parolă pentru a o utiliza la criptarea datelor copiei de rezervă complete. Dacă acest câmp rămâne necompletat, pentru copierea de rezervă se va utiliza parola dvs. actuală."</string>
-    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Dacă doriți să criptaţi datele copiei de rezervă complete, introduceţi o parolă mai jos:"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Introduceți mai jos parola actuală pentru copia de rezervă:"</string>
+    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Introduceți mai jos parola pentru criptarea dispozitivului."</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Introduceți mai jos parola de criptare a dispozitivului. Aceasta va fi utilizată, de asemenea, pentru a cripta arhiva copiei de rezervă."</string>
+    <string name="backup_enc_password_text" msgid="4981585714795233099">"Introduceți o parolă pentru a o utiliza la criptarea datelor copiei de rezervă complete. Dacă acest câmp rămâne necompletat, pentru copierea de rezervă se va utiliza parola dvs. actuală."</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Dacă doriți să criptați datele copiei de rezervă complete, introduceți o parolă mai jos:"</string>
     <string name="backup_enc_password_required" msgid="7889652203371654149">"Întrucât dispozitivul este criptat, trebuie să criptați backupurile. Introduceți o parolă mai jos:"</string>
-    <string name="restore_enc_password_text" msgid="6140898525580710823">"Dacă datele pentru restabilire sunt criptate, introduceţi parola mai jos:"</string>
+    <string name="restore_enc_password_text" msgid="6140898525580710823">"Dacă datele pentru restabilire sunt criptate, introduceți parola mai jos:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Se începe copierea de rezervă..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Copierea de rezervă a fost finalizată"</string>
-    <string name="toast_restore_started" msgid="7881679218971277385">"Se porneşte restabilirea..."</string>
+    <string name="toast_restore_started" msgid="7881679218971277385">"Se pornește restabilirea..."</string>
     <string name="toast_restore_ended" msgid="1764041639199696132">"Restabilirea s-a încheiat"</string>
     <string name="toast_timeout" msgid="5276598587087626877">"Operația a expirat"</string>
 </resources>
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index aea8585..f21fd88 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -27,7 +27,8 @@
         <activity
             android:name="com.android.captiveportallogin.CaptivePortalLoginActivity"
             android:label="@string/action_bar_label"
-            android:theme="@style/AppTheme" >
+            android:theme="@style/AppTheme"
+            android:configChanges="keyboardHidden|orientation|screenSize" >
             <intent-filter>
                 <action android:name="android.net.conn.CAPTIVE_PORTAL"/>
                 <category android:name="android.intent.category.DEFAULT"/>
diff --git a/packages/CaptivePortalLogin/res/values-be-rBY/strings.xml b/packages/CaptivePortalLogin/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..5391946
--- /dev/null
+++ b/packages/CaptivePortalLogin/res/values-be-rBY/strings.xml
@@ -0,0 +1,11 @@
+<?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_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
+    <string name="action_use_network" msgid="6076184727448466030">"Выкарыстоўваць гэтую сетку як ёсць"</string>
+    <string name="action_do_not_use_network" msgid="4577366536956516683">"Не выкарыстоўваць гэту сетку"</string>
+    <string name="action_bar_label" msgid="917235635415966620">"Увайсці ў сетку"</string>
+    <string name="ssl_error_warning" msgid="6653188881418638872">"У сеткі, да якой вы спрабуеце далучыцца, ёсць праблемы з бяспекай."</string>
+    <string name="ssl_error_example" msgid="647898534624078900">"Напрыклад, старонка ўваходу можа не належаць указанай арганізацыі."</string>
+    <string name="ssl_error_continue" msgid="6492718244923937110">"Усё роўна працягнуць праз браўзер"</string>
+</resources>
diff --git a/packages/CaptivePortalLogin/res/values-bs-rBA/strings.xml b/packages/CaptivePortalLogin/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..3237e5e
--- /dev/null
+++ b/packages/CaptivePortalLogin/res/values-bs-rBA/strings.xml
@@ -0,0 +1,11 @@
+<?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_name" msgid="5934709770924185752">"Prijava na zaštitnom portalu"</string>
+    <string name="action_use_network" msgid="6076184727448466030">"Koristi ovu mrežu kakva jeste"</string>
+    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne koristi ovu mrežu"</string>
+    <string name="action_bar_label" msgid="917235635415966620">"Prijavi me na mrežu"</string>
+    <string name="ssl_error_warning" msgid="6653188881418638872">"Mreža kojoj pokušavate pristupiti ima sigurnosnih problema."</string>
+    <string name="ssl_error_example" msgid="647898534624078900">"Naprimjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
+    <string name="ssl_error_continue" msgid="6492718244923937110">"Ipak nastavi preko preglednika"</string>
+</resources>
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
new file mode 100644
index 0000000..537b171
--- /dev/null
+++ b/packages/CtsShim/Android.mk
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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)
+
+###########################################################
+# Variant: Privileged app
+
+include $(CLEAR_VARS)
+# this needs to be a privileged application
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShimPriv
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := priv_shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
+
+###########################################################
+# Variant: System app
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShim
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
diff --git a/packages/CtsShim/priv_shim/AndroidManifest.xml b/packages/CtsShim/priv_shim/AndroidManifest.xml
new file mode 100644
index 0000000..0a3f823
--- /dev/null
+++ b/packages/CtsShim/priv_shim/AndroidManifest.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 for the privileged CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.priv.ctsshim">
+    <application android:label="CtsShim">
+
+        <!-- These activities don't actually exist; define them just to test the filters !-->
+
+        <!-- install test; [some] high priority filters granted -->
+        <activity android:name=".InstallPriority">
+            <!-- normal actions; priority will be granted -->
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEARCH" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+
+            <!-- protected actions; priority will be denied -->
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND_MULTIPLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SENDTO" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; single, equivalent filter -->
+        <activity android:name=".UpgradeMatch">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.MATCH" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; multiple, equivalent filters -->
+        <activity android:name=".UpgradeMatchMultiple">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+
+            <intent-filter android:priority="150">
+                <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="http" />
+                <data android:scheme="https" />
+                <data android:host="www.google.com" android:port="80" />
+                <data android:host="www.google.com" android:port="8080" />
+                <data android:host="goo.gl" android:port="443" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; lower priority -->
+        <activity android:name=".UpgradeLowerPriority">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.LOWER_PRIORITY" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; action subset -->
+        <activity android:name=".UpgradeActionSubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.ACTION_SUB" />
+                <action android:name="com.android.cts.action.ACTION_SUB_2" />
+                <action android:name="com.android.cts.action.ACTION_SUB_3" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; category subset -->
+        <activity android:name=".UpgradeCategorySubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.CATEGORY_SUB" />
+                <category android:name="android.intent.category.INFO" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; scheme subset -->
+        <activity android:name=".UpgradeSchemeSubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.SCHEME_SUB" />
+                <data android:scheme="content" />
+                <data android:scheme="flubber" />
+                <data android:scheme="zoodle" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; authority subset -->
+        <activity android:name=".UpgradeAuthoritySubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.AUTHORITY_SUB" />
+                <data android:host="www.google.com" android:port="80" />
+                <data android:host="www.google.com" android:port="8080" />
+                <data android:host="mail.google.com" android:port="80" />
+                <data android:host="goo.gl" android:port="443" />
+            </intent-filter>
+        </activity>
+
+
+        <!-- upgrade test; new action -->
+        <activity android:name=".UpgradeNewAction">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_ACTION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; new category -->
+        <activity android:name=".UpgradeNewCategory">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_CATEGORY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; new scheme -->
+        <activity android:name=".UpgradeNewScheme">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_SCHEME" />
+                <data android:scheme="content" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; new authority -->
+        <activity android:name=".UpgradeNewAuthority">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_AUTHORITY" />
+                <data android:host="www.google.com" android:port="80" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
+
diff --git a/packages/CtsShim/shim/AndroidManifest.xml b/packages/CtsShim/shim/AndroidManifest.xml
new file mode 100644
index 0000000..ee4b547
--- /dev/null
+++ b/packages/CtsShim/shim/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 for the system CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.system.ctsshim">
+    <application android:label="CtsShim">
+
+        <!-- These activities don't actually exist; define them just to test the filters !-->
+
+        <!-- install test; high priority filter DENIED -->
+        <activity android:name=".InstallPriority">
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEARCH" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND_MULTIPLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SENDTO" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
+
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index ccf1501..55d000c 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -13,8 +13,8 @@
 
     <application android:label="@string/service_name"
                  android:allowBackup="false"
-                 android:forceDeviceEncrypted="true"
-                 android:encryptionAware="true">
+                 android:defaultToDeviceProtectedStorage="true"
+                 android:directBootAware="true">
 
         <service android:name=".DefaultContainerService"
                  android:enabled="true"
diff --git a/packages/DefaultContainerService/res/values-be-rBY/strings.xml b/packages/DefaultContainerService/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..68621b6
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-be-rBY/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<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>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-bs-rBA/strings.xml b/packages/DefaultContainerService/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..56b7db1
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-bs-rBA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<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">"Pomoćnik pristupa paketu"</string>
+</resources>
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 1a4e3eb..3197abd 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
 # The design lib requires that the client package use appcompat themes.
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
 # Supplies material design components, e.g. Snackbar.
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-design
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
@@ -29,9 +30,16 @@
   --extra-packages android.support.design \
   --extra-packages android.support.v7.recyclerview
 
+LOCAL_JACK_FLAGS := \
+  -D jack.optimization.inner-class.accessors=true
+
+# Only enable asserts on userdebug/eng builds
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+LOCAL_JACK_FLAGS += -D jack.assert.policy=enable
+endif
+
 LOCAL_PACKAGE_NAME := DocumentsUI
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
-
-include $(LOCAL_PATH)/tests/Android.mk
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 58e7709..69912ab 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -1,9 +1,12 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.documentsui">
 
+    <uses-permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
     <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
     <uses-permission android:name="android.permission.REMOVE_TASKS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.CACHE_CONTENT" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 
     <application
         android:name=".DocumentsApplication"
@@ -39,22 +42,10 @@
         </activity>
 
         <activity
-            android:name=".DownloadsActivity"
-            android:theme="@style/DocumentsTheme"
-            android:label="@string/downloads_label"
-            android:icon="@drawable/ic_doc_text">
-            <intent-filter>
-                <action android:name="android.provider.action.MANAGE_ROOT" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:mimeType="vnd.android.document/root" />
-            </intent-filter>
-        </activity>
-
-        <activity
             android:name=".LauncherActivity"
-            android:theme="@android:style/Theme.NoDisplay"
-            android:icon="@drawable/ic_files_app"
-            android:label="@string/files_label">
+            android:label="@string/downloads_label"
+            android:icon="@mipmap/ic_launcher_downloads"
+            android:theme="@android:style/Theme.NoDisplay">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -63,10 +54,10 @@
 
         <activity
             android:name=".FilesActivity"
-            android:theme="@style/DocumentsTheme"
-            android:icon="@drawable/ic_files_app"
-            android:label="@string/files_label"
-            android:documentLaunchMode="intoExisting">
+            android:label="@string/downloads_label"
+            android:icon="@mipmap/ic_launcher_downloads"
+            android:documentLaunchMode="intoExisting"
+            android:theme="@style/DocumentsTheme">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
             </intent-filter>
@@ -76,6 +67,10 @@
                 <data android:mimeType="vnd.android.document/root" />
             </intent-filter>
             <intent-filter>
+                <action android:name="android.intent.action.VIEW_DOWNLOADS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="application/zip"
@@ -112,6 +107,12 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name=".BootReceiver" android:enabled="false">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
+        </receiver>
+
         <service
             android:name=".services.FileOperationService"
             android:exported="false">
diff --git a/packages/DocumentsUI/app-perf-tests/Android.mk b/packages/DocumentsUI/app-perf-tests/Android.mk
new file mode 100644
index 0000000..3f12906
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+#LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+
+LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator
+
+LOCAL_PACKAGE_NAME := DocumentsUIAppPerfTests
+LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
new file mode 100644
index 0000000..0013b6b
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.documentsui.appperftests">
+
+    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity
+            android:name="com.android.documentsui.LauncherActivity" />
+    </application>
+
+    <!-- This package instrumentates itself, so the DocumentsUI process can be killed without
+         killing the testing package. -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.documentsui.appperftests"
+        android:label="App performance tests for DocumentsUI" />
+
+</manifest>
diff --git a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
new file mode 100644
index 0000000..ce2fc13
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.support.test.uiautomator.UiDevice;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+@LargeTest
+public class FilesAppPerfTest extends InstrumentationTestCase {
+
+    // Keys used to report metrics to APCT.
+    private static final String KEY_FILES_COLD_START_PERFORMANCE_MEDIAN =
+            "files-cold-start-performance-median";
+    private static final String KEY_FILES_WARM_START_PERFORMANCE_MEDIAN =
+            "files-warm-start-performance-median";
+
+    private static final String TARGET_PACKAGE = "com.android.documentsui";
+
+    private static final int NUM_MEASUREMENTS = 10;
+
+    private LauncherActivity mActivity;
+    private UiDevice mDevice;
+
+    @Override
+    public void setUp() {
+        mDevice = UiDevice.getInstance(getInstrumentation());
+    }
+
+    public void testFilesColdStartPerformance() throws Exception {
+        runFilesStartPerformanceTest(true);
+    }
+
+    public void testFilesWarmStartPerformance() throws Exception {
+        runFilesStartPerformanceTest(false);
+    }
+
+    public void runFilesStartPerformanceTest(boolean cold) throws Exception {
+        long[] measurements = new long[NUM_MEASUREMENTS];
+        for (int i = 0; i < NUM_MEASUREMENTS; i++) {
+            if (cold) {
+                // Kill all providers, as well as DocumentsUI to measure a cold start.
+                killProviders();
+                mDevice.executeShellCommand("am force-stop " + TARGET_PACKAGE);
+            }
+            mDevice.waitForIdle();
+
+            LauncherActivity.testCaseLatch = new CountDownLatch(1);
+            mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+                    LauncherActivity.class, null);
+            LauncherActivity.testCaseLatch.await();
+            measurements[i] = LauncherActivity.measurement;
+        }
+
+        reportMetrics(cold ? KEY_FILES_COLD_START_PERFORMANCE_MEDIAN
+                : KEY_FILES_WARM_START_PERFORMANCE_MEDIAN, measurements);
+    }
+
+    private void reportMetrics(String key, long[] measurements) {
+        final Bundle status = new Bundle();
+        Arrays.sort(measurements);
+        final long median = measurements[NUM_MEASUREMENTS / 2 - 1];
+        status.putDouble(key, median);
+
+        getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+    }
+
+    private void killProviders() throws Exception {
+        final Context context = getInstrumentation().getContext();
+        final PackageManager pm = context.getPackageManager();
+        final ActivityManager am = (ActivityManager) context.getSystemService(
+                Context.ACTIVITY_SERVICE);
+        final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
+        final List<ResolveInfo> providers = pm.queryIntentContentProviders(intent, 0);
+        for (ResolveInfo info : providers) {
+            final String packageName = info.providerInfo.packageName;
+            am.killBackgroundProcesses(packageName);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/LauncherActivity.java
new file mode 100644
index 0000000..21fc52e
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/LauncherActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.Shared.EXTRA_BENCHMARK;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+
+public class LauncherActivity extends Activity {
+    private static final String TARGET_PACKAGE = "com.android.documentsui";
+    private static final int BENCHMARK_REQUEST_CODE = 1986;
+
+    public static CountDownLatch testCaseLatch = null;
+    public static long measurement = -1;
+
+    private long mStartTime = -1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        new Handler().post(new Runnable() {
+            @Override public void run() {
+                final Intent intent = new Intent("android.intent.action.OPEN_DOCUMENT");
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.putExtra(EXTRA_BENCHMARK, true);
+                intent.setType("*/*");
+
+                mStartTime = System.currentTimeMillis();
+                startActivityForResult(intent, BENCHMARK_REQUEST_CODE);
+            }
+        });
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == BENCHMARK_REQUEST_CODE) {
+            measurement = System.currentTimeMillis() - mStartTime;
+            testCaseLatch.countDown();
+            finish();
+        }
+    }
+}
diff --git a/packages/DocumentsUI/perf-tests/Android.mk b/packages/DocumentsUI/perf-tests/Android.mk
new file mode 100644
index 0000000..5ebf85f
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+    $(call all-java-files-under, ../tests/src/com/android/documentsui/bots) \
+    ../tests/src/com/android/documentsui/ActivityTest.java \
+    ../tests/src/com/android/documentsui/DocumentsProviderHelper.java \
+    ../tests/src/com/android/documentsui/StubProvider.java
+
+LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator ub-janktesthelper
+
+LOCAL_PACKAGE_NAME := DocumentsUIPerfTests
+LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/packages/DocumentsUI/perf-tests/AndroidManifest.xml b/packages/DocumentsUI/perf-tests/AndroidManifest.xml
new file mode 100644
index 0000000..97353e7
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.documentsui.perftests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <provider
+            android:name="com.android.documentsui.StressProvider"
+            android:authorities="com.android.documentsui.stressprovider"
+            android:exported="true"
+            android:grantUriPermissions="true"
+            android:permission="android.permission.MANAGE_DOCUMENTS"
+            android:enabled="true">
+            <intent-filter>
+                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+            </intent-filter>
+        </provider>
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.documentsui"
+        android:label="Performance tests for DocumentsUI" />
+
+</manifest>
diff --git a/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg b/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg
new file mode 100644
index 0000000..dd2da3e
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg
Binary files differ
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
new file mode 100644
index 0000000..bf056f1
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.StressProvider.DEFAULT_AUTHORITY;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_0_ID;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_1_ID;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.EventListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
+@LargeTest
+public class FilesActivityPerfTest extends ActivityTest<FilesActivity> {
+
+    // Constants starting with KEY_ are used to report metrics to APCT.
+    private static final String KEY_FILES_LISTED_PERFORMANCE_FIRST =
+            "files-listed-performance-first";
+
+    private static final String KEY_FILES_LISTED_PERFORMANCE_MEDIAN =
+            "files-listed-performance-median";
+
+    private static final String TESTED_URI =
+            "content://com.android.documentsui.stressprovider/document/STRESS_ROOT_1_DOC";
+
+    private static final int NUM_MEASUREMENTS = 10;
+
+    public FilesActivityPerfTest() {
+        super(FilesActivity.class);
+    }
+
+    @Override
+    protected RootInfo getInitialRoot() {
+        return rootDir0;
+    }
+
+    @Override
+    protected String getTestingProviderAuthority() {
+        return DEFAULT_AUTHORITY;
+    }
+
+    @Override
+    protected void setupTestingRoots() throws RemoteException {
+        rootDir0 = mDocsHelper.getRoot(STRESS_ROOT_0_ID);
+        rootDir1 = mDocsHelper.getRoot(STRESS_ROOT_1_ID);
+    }
+
+    @Override
+    public void initTestFiles() throws RemoteException {
+        // Nothing to create, already done by StressProvider.
+    }
+
+    public void testFilesListedPerformance() throws Exception {
+        final BaseActivity activity = getActivity();
+
+        final List<Long> measurements = new ArrayList<Long>();
+        EventListener listener;
+        for (int i = 0; i < 10; i++) {
+            final CountDownLatch signal = new CountDownLatch(1);
+            listener = new EventListener() {
+                @Override
+                public void onDirectoryNavigated(Uri uri) {
+                    if (uri != null && TESTED_URI.equals(uri.toString())) {
+                        mStartTime = System.currentTimeMillis();
+                    } else {
+                        mStartTime = -1;
+                    }
+                }
+
+                @Override
+                public void onDirectoryLoaded(Uri uri) {
+                    if (uri == null || !TESTED_URI.equals(uri.toString())) {
+                        return;
+                    }
+                    assertTrue(mStartTime != -1);
+                    getInstrumentation().waitForIdle(new Runnable() {
+                        @Override
+                        public void run() {
+                            assertTrue(mStartTime != -1);
+                            measurements.add(System.currentTimeMillis() - mStartTime);
+                            signal.countDown();
+                        }
+                    });
+                }
+
+                private long mStartTime = -1;
+            };
+
+            try {
+                activity.addEventListener(listener);
+                bots.roots.openRoot(STRESS_ROOT_1_ID);
+                signal.await();
+            } finally {
+                activity.removeEventListener(listener);
+            }
+
+            assertEquals(i + 1, measurements.size());
+
+            // Go back to the empty root.
+            bots.roots.openRoot(STRESS_ROOT_0_ID);
+        }
+
+        assertEquals(NUM_MEASUREMENTS, measurements.size());
+
+        final Bundle status = new Bundle();
+        status.putDouble(KEY_FILES_LISTED_PERFORMANCE_FIRST, measurements.get(0));
+
+        final Long[] rawMeasurements = measurements.toArray(new Long[NUM_MEASUREMENTS]);
+        Arrays.sort(rawMeasurements);
+
+        final long median = rawMeasurements[NUM_MEASUREMENTS / 2 - 1];
+        status.putDouble(KEY_FILES_LISTED_PERFORMANCE_MEDIAN, median);
+
+        getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+    }
+}
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java
new file mode 100644
index 0000000..cb2d904
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.StressProvider.DEFAULT_AUTHORITY;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_0_ID;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_2_ID;
+
+import android.app.Activity;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import android.content.Intent;
+import android.content.Context;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.JankTestBase;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.jank.GfxMonitor;
+import android.support.test.uiautomator.UiScrollable;
+import android.util.Log;
+
+import com.android.documentsui.FilesActivity;
+import com.android.documentsui.bots.RootsListBot;
+import com.android.documentsui.bots.DirectoryListBot;
+
+@LargeTest
+public class FilesJankPerfTest extends JankTestBase {
+    private static final String DOCUMENTSUI_PACKAGE = "com.android.documentsui";
+    private static final int MAX_FLINGS = 10;
+    private static final int BOT_TIMEOUT = 5000;
+
+    private RootsListBot mRootsListBot;
+    private DirectoryListBot mDirListBot;
+    private Activity mActivity = null;
+
+    public void setUpInLoop() {
+        final UiDevice device = UiDevice.getInstance(getInstrumentation());
+        final Context context = getInstrumentation().getTargetContext();
+        mRootsListBot = new RootsListBot(device, context, BOT_TIMEOUT);
+        mDirListBot = new DirectoryListBot(device, context, BOT_TIMEOUT);
+
+        final Intent intent = new Intent(context, FilesActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mActivity = getInstrumentation().startActivitySync(intent);
+    }
+
+    public void tearDownInLoop() {
+        if (mActivity != null) {
+            mActivity.finish();
+            mActivity = null;
+        }
+    }
+
+    public void setupAndOpenInLoop() throws Exception {
+        setUpInLoop();
+        openRoot();
+    }
+
+    public void openRoot() throws Exception {
+        mRootsListBot.openRoot(STRESS_ROOT_2_ID);
+    }
+
+    @JankTest(expectedFrames=0, beforeLoop="setUpInLoop", afterLoop="tearDownInLoop")
+    @GfxMonitor(processName=DOCUMENTSUI_PACKAGE)
+    public void testOpenRootJankPerformance() throws Exception {
+        openRoot();
+        getInstrumentation().waitForIdleSync();
+    }
+
+    @JankTest(expectedFrames=0, beforeLoop="setupAndOpenInLoop", afterLoop="tearDownInLoop")
+    @GfxMonitor(processName=DOCUMENTSUI_PACKAGE)
+    public void testFlingJankPerformance() throws Exception {
+        new UiScrollable(mDirListBot.findDocumentsList().getSelector()).flingToEnd(MAX_FLINGS);
+        getInstrumentation().waitForIdleSync();
+    }
+}
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
new file mode 100644
index 0000000..f9b06f8
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.database.MatrixCursor;
+import android.graphics.Point;
+import android.os.CancellationSignal;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsProvider;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * Provider with thousands of files for testing loading time of directories in DocumentsUI.
+ * It doesn't support any file operations.
+ */
+public class StressProvider extends DocumentsProvider {
+
+    public static final String DEFAULT_AUTHORITY = "com.android.documentsui.stressprovider";
+
+    // Empty root.
+    public static final String STRESS_ROOT_0_ID = "STRESS_ROOT_0";
+
+    // Root with thousands of directories.
+    public static final String STRESS_ROOT_1_ID = "STRESS_ROOT_1";
+
+    // Root with hundreds of files.
+    public static final String STRESS_ROOT_2_ID = "STRESS_ROOT_2";
+
+    private static final String STRESS_ROOT_0_DOC_ID = "STRESS_ROOT_0_DOC";
+    private static final String STRESS_ROOT_1_DOC_ID = "STRESS_ROOT_1_DOC";
+    private static final String STRESS_ROOT_2_DOC_ID = "STRESS_ROOT_2_DOC";
+
+    private static final int STRESS_ROOT_1_ITEMS = 10000;
+    private static final int STRESS_ROOT_2_ITEMS = 300;
+
+    private static final String MIME_TYPE_IMAGE = "image/jpeg";
+    private static final long REFERENCE_TIMESTAMP = 1459159369359L;
+
+    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
+            Root.COLUMN_AVAILABLE_BYTES
+    };
+    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+            Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+    };
+
+    private String mAuthority = DEFAULT_AUTHORITY;
+
+    // Map from a root document id to children document ids.
+    private Map<String, ArrayList<StubDocument>> mChildDocuments = new HashMap<>();
+
+    private Map<String, StubDocument> mDocuments = new HashMap<>();
+    private Map<String, StubRoot> mRoots = new HashMap<>();
+
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        mAuthority = info.authority;
+        super.attachInfo(context, info);
+    }
+
+    @Override
+    public boolean onCreate() {
+        StubDocument document;
+
+        ArrayList<StubDocument> children = new ArrayList<StubDocument>();
+        mChildDocuments.put(STRESS_ROOT_1_DOC_ID, children);
+        for (int i = 0; i < STRESS_ROOT_1_ITEMS; i++) {
+            document = StubDocument.createDirectory(i);
+            mDocuments.put(document.id, document);
+            children.add(document);
+        }
+
+        children = new ArrayList<StubDocument>();
+        mChildDocuments.put(STRESS_ROOT_2_DOC_ID, children);
+        for (int i = 0; i < STRESS_ROOT_2_ITEMS; i++) {
+            try {
+                document = StubDocument.createFile(
+                        getContext(), MIME_TYPE_IMAGE,
+                        com.android.documentsui.perftests.R.raw.earth_small,
+                        STRESS_ROOT_1_ITEMS + i);
+            } catch (IOException e) {
+                return false;
+            }
+            mDocuments.put(document.id, document);
+            children.add(document);
+        }
+
+        mRoots.put(STRESS_ROOT_0_ID, new StubRoot(STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID));
+        mRoots.put(STRESS_ROOT_1_ID, new StubRoot(STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID));
+        mRoots.put(STRESS_ROOT_2_ID, new StubRoot(STRESS_ROOT_2_ID, STRESS_ROOT_2_DOC_ID));
+
+        mDocuments.put(STRESS_ROOT_0_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_0_DOC_ID));
+        mDocuments.put(STRESS_ROOT_1_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_1_DOC_ID));
+        mDocuments.put(STRESS_ROOT_2_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_2_DOC_ID));
+
+        return true;
+    }
+
+    @Override
+    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(DEFAULT_ROOT_PROJECTION);
+        for (StubRoot root : mRoots.values()) {
+            includeRoot(result, root);
+        }
+        return result;
+    }
+
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
+        final StubDocument document = mDocuments.get(documentId);
+        includeDocument(result, document);
+        return result;
+    }
+
+    @Override
+    public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
+            String sortOrder)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
+        final ArrayList<StubDocument> childDocuments = mChildDocuments.get(parentDocumentId);
+        if (childDocuments != null) {
+            for (StubDocument document : childDocuments) {
+                includeDocument(result, document);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public AssetFileDescriptor openDocumentThumbnail(String docId, Point sizeHint,
+            CancellationSignal signal)
+            throws FileNotFoundException {
+        final StubDocument document = mDocuments.get(docId);
+        return getContext().getResources().openRawResourceFd(document.thumbnail);
+    }
+
+    @Override
+    public ParcelFileDescriptor openDocument(String docId, String mode,
+            CancellationSignal signal)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    private void includeRoot(MatrixCursor result, StubRoot root) {
+        final RowBuilder row = result.newRow();
+        row.add(Root.COLUMN_ROOT_ID, root.id);
+        row.add(Root.COLUMN_FLAGS, 0);
+        row.add(Root.COLUMN_TITLE, root.id);
+        row.add(Root.COLUMN_DOCUMENT_ID, root.documentId);
+    }
+
+    private void includeDocument(MatrixCursor result, StubDocument document) {
+        final RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, document.id);
+        row.add(Document.COLUMN_DISPLAY_NAME, document.id);
+        row.add(Document.COLUMN_SIZE, document.size);
+        row.add(Document.COLUMN_MIME_TYPE, document.mimeType);
+        row.add(Document.COLUMN_FLAGS,
+                document.thumbnail != -1 ? Document.FLAG_SUPPORTS_THUMBNAIL : 0);
+        row.add(Document.COLUMN_LAST_MODIFIED, document.lastModified);
+    }
+
+    private static String getStubDocumentIdForFile(File file) {
+        return file.getAbsolutePath();
+    }
+
+    private static class StubDocument {
+        final String mimeType;
+        final String id;
+        final int size;
+        final long lastModified;
+        final int thumbnail;
+
+        private StubDocument(String mimeType, String id, int size, long lastModified,
+                int thumbnail) {
+            this.mimeType = mimeType;
+            this.id = id;
+            this.size = size;
+            this.lastModified = lastModified;
+            this.thumbnail = thumbnail;
+        }
+
+        public static StubDocument createDirectory(int index) {
+            return new StubDocument(
+                    DocumentsContract.Document.MIME_TYPE_DIR, createRandomId(index), 0,
+                    createRandomTime(index), -1);
+        }
+
+        public static StubDocument createDirectory(String id) {
+            return new StubDocument(DocumentsContract.Document.MIME_TYPE_DIR, id, 0, 0, -1);
+        }
+
+        public static StubDocument createFile(Context context, String mimeType, int thumbnail,
+                int index) throws IOException {
+            return new StubDocument(
+                    mimeType, createRandomId(index), createRandomSize(index),
+                    createRandomTime(index), thumbnail);
+        }
+
+        private static String createRandomId(int index) {
+            final Random random = new Random(index);
+            final StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < 20; i++) {
+                builder.append((char) (random.nextInt(96) + 32));
+            }
+            builder.append(index);  // Append a number to guarantee uniqueness.
+            return builder.toString();
+        }
+
+        private static int createRandomSize(int index) {
+            final Random random = new Random(index);
+            return random.nextInt(1024 * 1024 * 100);  // Up to 100 MB.
+        }
+
+        private static long createRandomTime(int index) {
+            final Random random = new Random(index);
+            // Up to 30 days backwards from REFERENCE_TIMESTAMP.
+            return REFERENCE_TIMESTAMP - random.nextLong() % 1000L * 60 * 60 * 24 * 30;
+        }
+    }
+
+    private static class StubRoot {
+        final String id;
+        final String documentId;
+
+        public StubRoot(String id, String documentId) {
+            this.id = id;
+            this.documentId = documentId;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/res/animator-ldrtl/dir_enter.xml b/packages/DocumentsUI/res/animator-ldrtl/dir_enter.xml
deleted file mode 100644
index 6c7e224..0000000
--- a/packages/DocumentsUI/res/animator-ldrtl/dir_enter.xml
+++ /dev/null
@@ -1,22 +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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:valueFrom="-1"
-    android:valueTo="0"
-    android:propertyName="position"
-    android:valueType="floatType"
-    android:duration="@android:integer/config_mediumAnimTime"
-    android:interpolator="@android:interpolator/decelerate_quad" />
diff --git a/packages/DocumentsUI/res/animator-ldrtl/dir_leave.xml b/packages/DocumentsUI/res/animator-ldrtl/dir_leave.xml
deleted file mode 100644
index 8e2925c..0000000
--- a/packages/DocumentsUI/res/animator-ldrtl/dir_leave.xml
+++ /dev/null
@@ -1,22 +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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:valueFrom="0"
-    android:valueTo="-1"
-    android:propertyName="position"
-    android:valueType="floatType"
-    android:duration="@android:integer/config_mediumAnimTime"
-    android:interpolator="@android:interpolator/accelerate_quad" />
diff --git a/packages/DocumentsUI/res/animator/dir_enter.xml b/packages/DocumentsUI/res/animator/dir_enter.xml
index 7f547f1..570104e 100644
--- a/packages/DocumentsUI/res/animator/dir_enter.xml
+++ b/packages/DocumentsUI/res/animator/dir_enter.xml
@@ -13,10 +13,24 @@
      limitations under the License.
 -->
 
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:valueFrom="1"
-    android:valueTo="0"
-    android:propertyName="position"
-    android:valueType="floatType"
-    android:duration="@android:integer/config_mediumAnimTime"
-    android:interpolator="@android:interpolator/decelerate_quad" />
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:ordering="together">
+
+    <objectAnimator
+        android:valueFrom="0f"
+        android:valueTo="1f"
+        android:propertyName="alpha"
+        android:valueType="floatType"
+        android:duration="200"
+        android:interpolator="@android:interpolator/decelerate_quad" />
+
+    <!-- position property maps to AnimationView.setPosition -->
+    <objectAnimator
+        android:propertyName="position"
+        android:valueFrom="1"
+        android:valueTo="0"
+        android:valueType="floatType"
+        android:duration="350"
+        android:interpolator="@android:interpolator/decelerate_quad" />
+
+</set>
diff --git a/packages/DocumentsUI/res/animator/dir_frozen.xml b/packages/DocumentsUI/res/animator/dir_frozen.xml
deleted file mode 100644
index b541d13..0000000
--- a/packages/DocumentsUI/res/animator/dir_frozen.xml
+++ /dev/null
@@ -1,21 +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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:valueFrom="0"
-    android:valueTo="0"
-    android:propertyName="position"
-    android:valueType="floatType"
-    android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/packages/DocumentsUI/res/animator/dir_leave.xml b/packages/DocumentsUI/res/animator/dir_leave.xml
index fda0faf..5929625 100644
--- a/packages/DocumentsUI/res/animator/dir_leave.xml
+++ b/packages/DocumentsUI/res/animator/dir_leave.xml
@@ -13,10 +13,25 @@
      limitations under the License.
 -->
 
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:valueFrom="0"
-    android:valueTo="1"
-    android:propertyName="position"
-    android:valueType="floatType"
-    android:duration="@android:integer/config_mediumAnimTime"
-    android:interpolator="@android:interpolator/accelerate_quad" />
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:ordering="together">
+
+    <objectAnimator
+        android:valueFrom="1f"
+        android:valueTo="0f"
+        android:propertyName="alpha"
+        android:valueType="floatType"
+        android:duration="150"
+        android:startOffset="100"
+        android:interpolator="@android:interpolator/decelerate_quad" />
+
+    <!-- position property maps to AnimationView.setPosition -->
+    <objectAnimator
+        android:valueFrom="0"
+        android:valueTo="1"
+        android:propertyName="position"
+        android:valueType="floatType"
+        android:duration="250"
+        android:interpolator="@android:interpolator/accelerate_quad" />
+
+</set>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/animator/fade_in.xml b/packages/DocumentsUI/res/animator/fade_in.xml
new file mode 100644
index 0000000..3ce012b
--- /dev/null
+++ b/packages/DocumentsUI/res/animator/fade_in.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueFrom="0f"
+    android:valueTo="1f"
+    android:propertyName="alpha"
+    android:valueType="floatType"
+    android:duration="@android:integer/config_mediumAnimTime"
+    android:interpolator="@android:interpolator/decelerate_quad" />
diff --git a/packages/DocumentsUI/res/animator/fade_out.xml b/packages/DocumentsUI/res/animator/fade_out.xml
new file mode 100644
index 0000000..8d02c77
--- /dev/null
+++ b/packages/DocumentsUI/res/animator/fade_out.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:valueFrom="1f"
+    android:valueTo="0f"
+    android:propertyName="alpha"
+    android:valueType="floatType"
+    android:duration="@android:integer/config_mediumAnimTime"
+    android:interpolator="@android:interpolator/decelerate_quad" />
diff --git a/packages/DocumentsUI/res/color/item_details.xml b/packages/DocumentsUI/res/color/item_details.xml
new file mode 100644
index 0000000..ac21fe3
--- /dev/null
+++ b/packages/DocumentsUI/res/color/item_details.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_enabled="true"
+        android:color="?android:attr/textColorPrimary"
+        android:alpha="0.54" />
+</selector>
diff --git a/packages/DocumentsUI/res/color/item_root_primary_text.xml b/packages/DocumentsUI/res/color/item_root_primary_text.xml
index 551245f..a5a65b2 100644
--- a/packages/DocumentsUI/res/color/item_root_primary_text.xml
+++ b/packages/DocumentsUI/res/color/item_root_primary_text.xml
@@ -15,8 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:state_activated="true" android:color="?android:colorAccent" />
-    <item android:state_focused="false" android:state_activated="true" android:color="?android:colorAccent" />
+  <item android:state_focused="true" android:state_activated="true" android:color="@color/root_activated_color" />
+  <item android:state_focused="false" android:state_activated="true" android:color="@color/root_activated_color" />
     <item android:state_enabled="false" android:alpha="@*android:dimen/disabled_alpha_material_light" android:color="@*android:color/primary_text_default_material_light" />
     <item android:color="@*android:color/primary_text_default_material_light" />
 </selector>
diff --git a/packages/DocumentsUI/res/color/item_title.xml b/packages/DocumentsUI/res/color/item_title.xml
new file mode 100644
index 0000000..9fff2f1
--- /dev/null
+++ b/packages/DocumentsUI/res/color/item_title.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_enabled="true"
+        android:color="?android:attr/textColorPrimary"
+        android:alpha="0.87" />
+    <item
+        android:state_enabled="false"
+        android:color="?android:attr/textColorPrimary"
+        android:alpha="0.54" />
+</selector>
diff --git a/packages/DocumentsUI/res/drawable/drag_shadow_background.xml b/packages/DocumentsUI/res/drawable/drag_shadow_background.xml
new file mode 100644
index 0000000..49465cb
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/drag_shadow_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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">
+  <solid android:color="@color/item_doc_background" />
+  <stroke
+      android:width="1dp"
+      android:color="#ff9f9f9f" />
+  <corners
+      android:bottomRightRadius="3dp"
+      android:bottomLeftRadius="3dp"
+      android:topLeftRadius="3dp"
+      android:topRightRadius="3dp"/>
+</shape>
diff --git a/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml b/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml
new file mode 100644
index 0000000..199a308
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+        android:fromDegrees="90"
+        android:toDegrees="90"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:drawable="@drawable/ic_breadcrumb_arrow">
+</rotate>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_files_app.xml b/packages/DocumentsUI/res/drawable/ic_files_app.xml
deleted file mode 100644
index ff7189e..0000000
--- a/packages/DocumentsUI/res/drawable/ic_files_app.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/icon256"
-    android:tint="?android:attr/colorControlNormal"
-    android:autoMirrored="true" />
diff --git a/packages/DocumentsUI/res/drawable/ic_sd_storage.xml b/packages/DocumentsUI/res/drawable/ic_sd_storage.xml
index b0f3cc3..5aeebbb 100644
--- a/packages/DocumentsUI/res/drawable/ic_sd_storage.xml
+++ b/packages/DocumentsUI/res/drawable/ic_sd_storage.xml
@@ -14,8 +14,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/packages/DocumentsUI/res/drawable/ic_usb_storage.xml b/packages/DocumentsUI/res/drawable/ic_usb_storage.xml
new file mode 100644
index 0000000..2a8d024
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_usb_storage.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M15 7v4h1v2h-3V5h2l-3,-4,-3 4h2v8H8v-2.07c.7,-.37 1.2,-1.08 1.2,-1.93 0,-1.21,-.99,-2.2,-2.2,-2.2,-1.21 0,-2.2.99,-2.2 2.2 0 .85.5 1.56 1.2 1.93V13c0 1.11.89 2 2 2h3v3.05c-.71.37,-1.2 1.1,-1.2 1.95 0 1.22.99 2.2 2.2 2.2 1.21 0 2.2,-.98 2.2,-2.2 0,-.85,-.49,-1.58,-1.2,-1.95V15h3c1.11 0 2,-.89 2,-2v-2h1V7h-4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/icon256.png b/packages/DocumentsUI/res/drawable/icon256.png
deleted file mode 100644
index 631c951..0000000
--- a/packages/DocumentsUI/res/drawable/icon256.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml b/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml
new file mode 100644
index 0000000..a1c2910
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="24dp"
+    android:paddingStart="24dp"
+    android:paddingEnd="24dp"
+    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+    android:textColor="@*android:color/primary_text_default_material_light">
+</TextView>
diff --git a/packages/DocumentsUI/res/layout/dialog_file_name.xml b/packages/DocumentsUI/res/layout/dialog_file_name.xml
index 5ed476f..3a95a13 100644
--- a/packages/DocumentsUI/res/layout/dialog_file_name.xml
+++ b/packages/DocumentsUI/res/layout/dialog_file_name.xml
@@ -17,6 +17,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:fitsSystemWindows="true"
     android:padding="?android:attr/listPreferredItemPaddingEnd">
 
     <EditText
diff --git a/packages/DocumentsUI/res/layout/dialog_open_scoped_directory.xml b/packages/DocumentsUI/res/layout/dialog_open_scoped_directory.xml
new file mode 100644
index 0000000..bfb0271
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/dialog_open_scoped_directory.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:theme="@style/Theme.AppCompat.Light.Dialog.Alert"
+    android:orientation="vertical"
+    android:paddingEnd="24dp"
+    android:paddingStart="24dp" >
+
+    <TextView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/message"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingEnd="24dp"
+        android:paddingStart="32dp"
+        android:paddingTop="24dp">
+    </TextView>
+
+    <CheckBox
+        android:id="@+id/do_not_ask_checkbox"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dip"
+        android:text="@string/never_ask_again"
+        android:textColor="?android:attr/textColorSecondary"
+        android:visibility="gone" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/layout/drag_shadow_layout.xml b/packages/DocumentsUI/res/layout/drag_shadow_layout.xml
new file mode 100644
index 0000000..26613ef
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/drag_shadow_layout.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:paddingStart="8dp"
+    android:paddingEnd="8dp"
+    android:orientation="horizontal"
+    android:gravity="center_vertical|left"
+    android:background="@drawable/drag_shadow_background">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/root_icon_size"
+        android:layout_height="@dimen/root_icon_size"
+        android:scaleType="centerInside"
+        android:contentDescription="@null"
+        android:duplicateParentState="true"/>
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:maxLines="1"
+        android:ellipsize="end"
+        android:textAlignment="viewStart"
+        android:textColor="@color/item_title"
+        android:paddingStart="8dp"/>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
index 065102b..b65c5a0 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -46,6 +46,8 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="4dp"
+                    android:popupTheme="?actionBarPopupTheme"
+                    android:background="@android:color/transparent"
                     android:overlapAnchor="true" />
 
             </com.android.documentsui.DocumentsToolbar>
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index 84a928d..deb0894 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -44,6 +44,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginStart="4dp"
+                android:popupTheme="?actionBarPopupTheme"
+                android:background="@android:color/transparent"
                 android:overlapAnchor="true" />
 
         </com.android.documentsui.DocumentsToolbar>
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 03c6a83..8eb46dd 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.dirlist.AnimationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/directory_background"
@@ -99,4 +100,4 @@
 
     </FrameLayout>
 
-</com.android.documentsui.DirectoryView>
+</com.android.documentsui.dirlist.AnimationView>
diff --git a/packages/DocumentsUI/res/layout/fragment_save.xml b/packages/DocumentsUI/res/layout/fragment_save.xml
index 7aac620..a889b9f 100644
--- a/packages/DocumentsUI/res/layout/fragment_save.xml
+++ b/packages/DocumentsUI/res/layout/fragment_save.xml
@@ -21,6 +21,7 @@
     android:orientation="horizontal"
     android:baselineAligned="false"
     android:gravity="center_vertical"
+    android:fitsSystemWindows="true"
     android:minHeight="?android:attr/listPreferredItemHeightSmall">
 
     <FrameLayout
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
index d866145..36af9b9 100644
--- a/packages/DocumentsUI/res/layout/item_dir_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -23,14 +23,16 @@
     android:elevation="@dimen/grid_item_elevation"
     android:focusable="true" >
 
+    <!-- The height is 48px.
+         paddingTop (9dp) + @dimen/check_icon_size (30dp) + paddingBottom (9dp) -->
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="horizontal"
-        android:paddingBottom="16dp"
-        android:paddingLeft="12dp"
+        android:paddingBottom="9dp"
+        android:paddingLeft="9dp"
         android:paddingRight="12dp"
-        android:paddingTop="16dp"
+        android:paddingTop="9dp"
         android:gravity="center_vertical">
 
         <FrameLayout
@@ -62,11 +64,11 @@
             android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:ellipsize="middle"
+            android:ellipsize="end"
             android:singleLine="true"
             android:textAlignment="viewStart"
             android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-            android:textColor="@*android:color/primary_text_default_material_light" />
+            android:textColor="@color/item_title" />
 
     </LinearLayout>
 
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 1890f2f..56a061f 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -90,10 +90,10 @@
             android:layout_alignParentTop="true"
             android:layout_toEndOf="@id/icon_mime_sm"
             android:singleLine="true"
-            android:ellipsize="middle"
+            android:ellipsize="end"
             android:textAlignment="viewStart"
             android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-            android:textColor="@*android:color/primary_text_default_material_light" />
+            android:textColor="@color/item_title" />
 
         <TextView
             android:id="@+id/size"
@@ -106,7 +106,7 @@
             android:ellipsize="end"
             android:textAlignment="viewStart"
             android:textAppearance="@android:style/TextAppearance.Material.Caption"
-            android:textColor="@*android:color/primary_text_default_material_light" />
+            android:textColor="@color/item_details" />
 
         <TextView
             android:id="@+id/date"
@@ -118,7 +118,7 @@
             android:ellipsize="end"
             android:textAlignment="viewStart"
             android:textAppearance="@android:style/TextAppearance.Material.Caption"
-            android:textColor="@*android:color/primary_text_default_material_light" />
+            android:textColor="@color/item_details" />
 
     </RelativeLayout>
 
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 8d98377..a939fcd 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -73,18 +73,19 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:orientation="vertical" >
+            android:orientation="vertical"
+            android:layout_gravity="center_vertical" >
 
             <TextView
                 android:id="@android:id/title"
                 android:layout_width="wrap_content"
                 android:layout_height="0dp"
                 android:layout_weight="1"
-                android:ellipsize="middle"
+                android:ellipsize="end"
                 android:singleLine="true"
                 android:textAlignment="viewStart"
                 android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-                android:textColor="?android:attr/textColorPrimary" />
+                android:textColor="@color/item_title" />
 
             <LinearLayout
                 android:id="@+id/line2"
@@ -101,8 +102,8 @@
                     android:ellipsize="end"
                     android:singleLine="true"
                     android:textAlignment="viewStart"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
-                    android:textColor="?android:attr/textColorSecondary" />
+                    android:textAppearance="@android:style/TextAppearance.Material.Caption"
+                    android:textColor="@color/item_details" />
 
                 <TextView
                     android:id="@+id/size"
@@ -112,8 +113,8 @@
                     android:ellipsize="end"
                     android:singleLine="true"
                     android:textAlignment="viewStart"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
-                    android:textColor="?android:attr/textColorSecondary" />
+                    android:textAppearance="@android:style/TextAppearance.Material.Caption"
+                    android:textColor="@color/item_details" />
 
                 <TextView
                     android:id="@android:id/summary"
@@ -124,8 +125,8 @@
                     android:ellipsize="end"
                     android:singleLine="true"
                     android:textAlignment="viewStart"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
-                    android:textColor="?android:attr/textColorSecondary" />
+                    android:textAppearance="@android:style/TextAppearance.Material.Caption"
+                    android:textColor="@color/item_details" />
             </LinearLayout>
         </LinearLayout>
     </LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index ff80d07..816cb8a 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -27,8 +27,6 @@
     <FrameLayout
         android:layout_width="@dimen/icon_size"
         android:layout_height="@dimen/icon_size"
-        android:layout_marginStart="@dimen/root_icon_margin"
-        android:layout_marginEnd="@dimen/root_icon_margin"
         android:duplicateParentState="true">
 
         <ImageView
@@ -55,7 +53,7 @@
             android:singleLine="true"
             android:ellipsize="end"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@android:style/TextAppearance.Material.Menu"
             android:textColor="@color/item_root_primary_text" />
 
         <TextView
@@ -65,7 +63,7 @@
             android:singleLine="true"
             android:ellipsize="end"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@android:style/TextAppearance.Material.Caption"
             android:textColor="@color/item_root_primary_text" />
 
     </LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_subdir.xml b/packages/DocumentsUI/res/layout/item_subdir.xml
index 821432d..ffe4afe 100644
--- a/packages/DocumentsUI/res/layout/item_subdir.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir.xml
@@ -24,23 +24,13 @@
     android:orientation="horizontal"
     android:baselineAligned="false">
 
-    <ImageView
-        android:id="@+id/subdir"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:paddingEnd="8dp"
-        android:scaleType="centerInside"
-        android:visibility="gone"
-        android:src="@drawable/ic_subdirectory_arrow"
-        android:contentDescription="@null" />
-
     <TextView
         android:id="@android:id/title"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:singleLine="true"
-        android:ellipsize="middle"
+        android:ellipsize="end"
         android:textAlignment="viewStart"
         android:textAppearance="@android:style/TextAppearance.Material.Subhead"
         android:textColor="?android:attr/textColorPrimary" />
diff --git a/packages/DocumentsUI/res/layout/item_subdir_title.xml b/packages/DocumentsUI/res/layout/item_subdir_title.xml
index 4c839d0..8d0d807 100644
--- a/packages/DocumentsUI/res/layout/item_subdir_title.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir_title.xml
@@ -26,8 +26,9 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:singleLine="true"
-        android:ellipsize="middle"
+        android:ellipsize="end"
         android:textAlignment="viewStart"
+        android:drawablePadding="12dp"
+        android:drawableRight="@drawable/ic_breadcrumb_arrow_down"
         android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
-
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
index 235d22d..7b7e229 100644
--- a/packages/DocumentsUI/res/layout/single_pane_layout.xml
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -43,6 +43,8 @@
                 android:id="@+id/stack"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:popupTheme="?actionBarPopupTheme"
+                android:background="@android:color/transparent"
                 android:layout_marginStart="4dp"
                 android:overlapAnchor="true" />
 
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 73571af..85e7a7a 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -31,65 +31,68 @@
         android:actionViewClass="android.widget.SearchView"
         android:imeOptions="actionSearch"
         android:visible="false" />
-    <item
-        android:id="@+id/menu_grid"
-        android:title="@string/menu_grid"
-        android:icon="@drawable/ic_menu_view_grid"
-        android:showAsAction="always" />
-    <item
-        android:id="@+id/menu_list"
-        android:title="@string/menu_list"
-        android:icon="@drawable/ic_menu_view_list"
-        android:showAsAction="always" />
+<!-- This group is being hidden when searching is in full bar mode-->
+    <group android:id="@+id/group_hide_when_searching">
+        <item
+            android:id="@+id/menu_grid"
+            android:title="@string/menu_grid"
+            android:icon="@drawable/ic_menu_view_grid"
+            android:showAsAction="always" />
+        <item
+            android:id="@+id/menu_list"
+            android:title="@string/menu_list"
+            android:icon="@drawable/ic_menu_view_list"
+            android:showAsAction="always" />
 
-    <item
-        android:id="@+id/menu_new_window"
-        android:title="@string/menu_new_window"
-        android:alphabeticShortcut="n"
-        android:showAsAction="never"
-        android:visible="false" />
-    <item
-        android:id="@+id/menu_create_dir"
-        android:title="@string/menu_create_dir"
-        android:icon="@drawable/ic_menu_new_folder"
-        android:alphabeticShortcut="e"
-        android:showAsAction="never"
-        android:visible="false" />
-    <item
-        android:id="@+id/menu_paste_from_clipboard"
-        android:title="@string/menu_paste_from_clipboard"
-        android:alphabeticShortcut="v"
-        android:showAsAction="never"
-        android:visible="false" />
-    <!-- Copy action is defined in mode_directory.xml -->
-    <item
-        android:id="@+id/menu_sort"
-        android:title="@string/menu_sort"
-        android:icon="@drawable/ic_menu_sortby"
-        android:showAsAction="never">
-        <menu>
-            <item
-                android:id="@+id/menu_sort_name"
-                android:title="@string/sort_name" />
-            <item
-                android:id="@+id/menu_sort_date"
-                android:title="@string/sort_date" />
-            <item
-                android:id="@+id/menu_sort_size"
-                android:title="@string/sort_size" />
-        </menu>
-    </item>
-    <item
-        android:id="@+id/menu_file_size"
-        android:showAsAction="never"
-        android:visible="false" />
-    <item
-        android:id="@+id/menu_advanced"
-        android:showAsAction="never"
-        android:visible="false" />
-    <item
-        android:id="@+id/menu_settings"
-        android:title="@string/menu_settings"
-        android:showAsAction="never"
-        android:visible="false" />
+        <item
+            android:id="@+id/menu_new_window"
+            android:title="@string/menu_new_window"
+            android:alphabeticShortcut="n"
+            android:showAsAction="never"
+            android:visible="false" />
+        <item
+            android:id="@+id/menu_create_dir"
+            android:title="@string/menu_create_dir"
+            android:icon="@drawable/ic_menu_new_folder"
+            android:alphabeticShortcut="e"
+            android:showAsAction="never"
+            android:visible="false" />
+        <item
+            android:id="@+id/menu_paste_from_clipboard"
+            android:title="@string/menu_paste_from_clipboard"
+            android:alphabeticShortcut="v"
+            android:showAsAction="never"
+            android:visible="false" />
+        <!-- Copy action is defined in mode_directory.xml -->
+        <item
+            android:id="@+id/menu_sort"
+            android:title="@string/menu_sort"
+            android:icon="@drawable/ic_menu_sortby"
+            android:showAsAction="ifRoom">
+            <menu>
+                <item
+                    android:id="@+id/menu_sort_name"
+                    android:title="@string/sort_name" />
+                <item
+                    android:id="@+id/menu_sort_date"
+                    android:title="@string/sort_date" />
+                <item
+                    android:id="@+id/menu_sort_size"
+                    android:title="@string/sort_size" />
+            </menu>
+        </item>
+        <item
+            android:id="@+id/menu_file_size"
+            android:showAsAction="never"
+            android:visible="false" />
+        <item
+            android:id="@+id/menu_advanced"
+            android:showAsAction="never"
+            android:visible="false" />
+        <item
+            android:id="@+id/menu_settings"
+            android:title="@string/menu_settings"
+            android:showAsAction="never"
+            android:visible="false" />
+    </group>
 </menu>
diff --git a/packages/DocumentsUI/res/mipmap-hdpi/ic_launcher_downloads.png b/packages/DocumentsUI/res/mipmap-hdpi/ic_launcher_downloads.png
new file mode 100644
index 0000000..f958bbd
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-hdpi/ic_launcher_downloads.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-mdpi/ic_launcher_downloads.png b/packages/DocumentsUI/res/mipmap-mdpi/ic_launcher_downloads.png
new file mode 100644
index 0000000..f2e9376
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-mdpi/ic_launcher_downloads.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-xhdpi/ic_launcher_downloads.png b/packages/DocumentsUI/res/mipmap-xhdpi/ic_launcher_downloads.png
new file mode 100644
index 0000000..4dc5336
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-xhdpi/ic_launcher_downloads.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-xxhdpi/ic_launcher_downloads.png b/packages/DocumentsUI/res/mipmap-xxhdpi/ic_launcher_downloads.png
new file mode 100644
index 0000000..8716290
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-xxhdpi/ic_launcher_downloads.png
Binary files differ
diff --git a/packages/DocumentsUI/res/mipmap-xxxhdpi/ic_launcher_downloads.png b/packages/DocumentsUI/res/mipmap-xxxhdpi/ic_launcher_downloads.png
new file mode 100644
index 0000000..f5be219
--- /dev/null
+++ b/packages/DocumentsUI/res/mipmap-xxxhdpi/ic_launcher_downloads.png
Binary files differ
diff --git a/packages/DocumentsUI/res/values-af/config.xml b/packages/DocumentsUI/res/values-af/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-af/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index b8bc289..1a7c620 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Deel via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopieer tans lêers"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Skuif tans lêers"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Vee tans lêers uit"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> oor"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopieer tans <xliff:g id="COUNT_1">%1$d</xliff:g> lêers.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Hernoem"</string>
     <string name="rename_error" msgid="4203041674883412606">"Kon nie dokument hernoem nie"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige lêers is omgeskakel"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot jou data, insluitend foto\'s en video\'s, op <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Moenie weer vra nie"</string>
     <string name="allow" msgid="7225948811296386551">"Laat toe"</string>
     <string name="deny" msgid="2081879885755434506">"Weier"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> gekies</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vee \"<xliff:g id="NAME">%1$s</xliff:g>\" uit?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vee vouer \"<xliff:g id="NAME">%1$s</xliff:g>\" en sy inhoud uit?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> lêers uit?</item>
+      <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> lêer uit?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> vouers en hul inhoud uit?</item>
+      <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> vouer en sy inhoud uit?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> items uit?</item>
+      <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> item uit?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-am/config.xml b/packages/DocumentsUI/res/values-am/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-am/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index f28c433..ca43dab 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"በሚከተለው በኩል ያጋሩ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ፋይሎች በመገልበጥ ላይ"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ፋይሎችን በመውሰድ ላይ"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ፋይሎችን በመሰረዝ ላይ"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ቀርቷል"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች በመቅዳት ላይ።</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"እንደገና ሰይም"</string>
     <string name="rename_error" msgid="4203041674883412606">"ሰነዱን ዳግም መሰየም አልተሳካም"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"አንዳንድ ፋይሎች ተለውጠዋል"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> በ<xliff:g id="STORAGE"><i>^3</i></xliff:g> ላይ የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መደረሻ ይሰጠው?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መዳረሻ ለ<xliff:g id="APPNAME"><b>^1</b></xliff:g> ይሰጠው?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"በ<xliff:g id="STORAGE"><i>^2</i></xliff:g> ላይ ያሉትን ፎቶዎች እና ቪዲዮዎች ጨምሮ የውሂብዎ መዳረሻ ለ<xliff:g id="APPNAME"><b>^1</b></xliff:g> ይሰጥ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"ዳግም አትጠይቅ"</string>
     <string name="allow" msgid="7225948811296386551">"ይፍቀዱ"</string>
     <string name="deny" msgid="2081879885755434506">"ያስተባብሉ"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"«<xliff:g id="NAME">%1$s</xliff:g>» ይሰረዝ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"አቃፊ «<xliff:g id="NAME">%1$s</xliff:g>» እና ይዘቶቹ ይሰረዙ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> አቃፊዎች እና ይዘቶቻቸው ይሰረዙ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> አቃፊዎች እና ይዘቶቻቸው ይሰረዙ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎች ይሰረዙ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎች ይሰረዙ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ar/config.xml b/packages/DocumentsUI/res/values-ar/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ar/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index c19e406..e6fac50 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"مشاركة عبر"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"جارٍ نسخ الملفات"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"نقل الملفات"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"جارٍ حذف الملفات"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"المدة المتبقية: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="zero">جارٍ نسخ <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات.</item>
@@ -137,6 +138,44 @@
     <string name="menu_rename" msgid="7678802479104285353">"إعادة تسمية"</string>
     <string name="rename_error" msgid="4203041674883412606">"أخفقت إعادة تسمية المستند."</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"تم تحويل بعض الملفات"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"هل تريد منح التطبيق <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى الدليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> على <xliff:g id="STORAGE"><i>^3</i></xliff:g>؟"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"هل تريد تمكين <xliff:g id="APPNAME"><b>^1</b></xliff:g> من الدخول إلى دليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>؟"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"هل تريد منح <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى بياناتك، بما في ذلك الصور ومقاطع الفيديو على <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"عدم السؤال مرة أخرى"</string>
     <string name="allow" msgid="7225948811296386551">"السماح"</string>
     <string name="deny" msgid="2081879885755434506">"رفض"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="zero">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="two">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="few">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="many">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">تم تحديد <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"هل تريد حذف \"<xliff:g id="NAME">%1$s</xliff:g>\"؟"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"هل تريد حذف المجلد \"<xliff:g id="NAME">%1$s</xliff:g>\" ومحتوياته؟"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+      <item quantity="two">هل تريد حذف ملفين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+      <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات؟</item>
+      <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفًا؟</item>
+      <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+      <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> ملف؟</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلد ومحتوياته؟</item>
+      <item quantity="two">هل تريد حذف مجلدين (<xliff:g id="COUNT_1">%1$d</xliff:g>) ومحتوياتهما؟</item>
+      <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلدات ومحتوياتها؟</item>
+      <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلدًا ومحتويات هذه المجلدات؟</item>
+      <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلد ومحتويات هذه المجلدات؟</item>
+      <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> مجلد ومحتوياته؟</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر؟</item>
+      <item quantity="two">هل تريد حذف عنصرين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+      <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عناصر؟</item>
+      <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصرًا؟</item>
+      <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر؟</item>
+      <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> عنصر؟</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/config.xml b/packages/DocumentsUI/res/values-az-rAZ/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-az-rAZ/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index dc9a390..75a0686 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Bunun vasitəsilə paylaş:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Fayllar kopyalanır"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Fayllar köçürülür"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Fayllar silinir"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> qalıb"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fayl kopyalanır.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Adını dəyişdirin"</string>
     <string name="rename_error" msgid="4203041674883412606">"Sənəd adını dəyişmək uğursuz oldu"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bəzi fayllar konvertasiya edilib"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> yaddaşında <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> yaddaşında foto və videolar daxil olmaqla datanıza <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təmin edilsin?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Bir daha soruşmayın"</string>
     <string name="allow" msgid="7225948811296386551">"İcazə verin"</string>
     <string name="deny" msgid="2081879885755434506">"Rədd et"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seçilib</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" silinsin?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" qovluğu və onun məzmunu silinsin?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> fayl silinsin?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fayl silinsin?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> qovluq və onun məzmunu silinsin?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> qovluq və onun məzmunu silinsin?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> element silinsin?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> element silinsin?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/config.xml b/packages/DocumentsUI/res/values-b+sr+Latn/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-b+sr+Latn/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 1e1a2f7..34c08bd 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Delite preko"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Datoteke se premeštaju"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Datoteke se brišu"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
@@ -116,6 +117,32 @@
     <string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
     <string name="rename_error" msgid="4203041674883412606">"Preimenovanje dokumenta nije uspelo"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke datoteke su konvertovane"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li da aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobrite pristup direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na memorijskom prostoru <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite da dozvolite da <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristupa direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite da li da dozvolite da aplikacija <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristupa podacima, uključujući slike i video snimke, na lokaciji <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ne pitaj ponovo"</string>
     <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
     <string name="deny" msgid="2081879885755434506">"Odbij"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Izabrana je <xliff:g id="COUNT_1">%1$d</xliff:g> stavka</item>
+      <item quantity="few">Izabrane su <xliff:g id="COUNT_1">%1$d</xliff:g> stavke</item>
+      <item quantity="other">Izabrano je <xliff:g id="COUNT_1">%1$d</xliff:g> stavki</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li da izbrišete „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li da izbrišete direktorijum „<xliff:g id="NAME">%1$s</xliff:g>“ i njegov sadržaj?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+      <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+      <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijum i njihov sadržaj?</item>
+      <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijuma i njihov sadržaj?</item>
+      <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijuma i njihov sadržaj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+      <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+      <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-be-rBY/strings.xml b/packages/DocumentsUI/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..8493c477
--- /dev/null
+++ b/packages/DocumentsUI/res/values-be-rBY/strings.xml
@@ -0,0 +1,159 @@
+<?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.
+ -->
+
+<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="files_label" msgid="6051402950202690279">"Файлы"</string>
+    <string name="downloads_label" msgid="959113951084633612">"Спампоўкі"</string>
+    <string name="title_open" msgid="4353228937663917801">"Адкрыць з"</string>
+    <string name="title_save" msgid="2433679664882857999">"Захаваць у"</string>
+    <string name="menu_create_dir" msgid="2547620241173881754">"Новая папка"</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="8239065133341597825">"Налады сховішча"</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_delete" msgid="8138799623850614177">"Выдаліць"</string>
+    <string name="menu_select_all" msgid="8323579667348729928">"Выбраць усё"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Капіраваць у..."</string>
+    <string name="menu_move" msgid="1828090633118079817">"Перамясціць у..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Новае акно"</string>
+    <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Капіраваць"</string>
+    <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Уставіць"</string>
+    <string name="menu_advanced_show" msgid="4693652895715631401">"Паказаць унутр. сховішча"</string>
+    <string name="menu_advanced_hide" msgid="4218809952721972589">"Схаваць унутр. сховішча"</string>
+    <string name="menu_file_size_show" msgid="3240323619260823076">"Паказаць памеры файлаў"</string>
+    <string name="menu_file_size_hide" msgid="8881975928502581042">"Схаваць памеры файлаў"</string>
+    <string name="button_select" msgid="527196987259139214">"Выбраць"</string>
+    <string name="button_copy" msgid="8706475544635021302">"Капіраваць"</string>
+    <string name="button_move" msgid="2202666023104202232">"Перамясціць"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Адхіліць"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Паўтарыце спробу"</string>
+    <string name="sort_name" msgid="9183560467917256779">"Па назве"</string>
+    <string name="sort_date" msgid="586080032956151448">"Па даце ўнясення змен"</string>
+    <string name="sort_size" msgid="3350681319735474741">"Па памеры"</string>
+    <string name="drawer_open" msgid="4545466532430226949">"Паказаць каранёвыя папкі"</string>
+    <string name="drawer_close" msgid="7602734368552123318">"Схаваць каранёвыя папкі"</string>
+    <string name="save_error" msgid="6167009778003223664">"Не атрымалася захаваць дакумент"</string>
+    <string name="create_error" msgid="3735649141335444215">"Не атрымалася стварыць папку"</string>
+    <string name="query_error" msgid="5999895349602476581">"Зараз немагчыма загрузіць змесціва"</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>
+    <string name="root_type_device" msgid="7121342474653483538">"Прылады"</string>
+    <string name="root_type_apps" msgid="8838065367985945189">"Іншыя праграмы"</string>
+    <string name="empty" msgid="7858882803708117596">"Няма элементаў"</string>
+    <string name="no_results" msgid="6622510343880730446">"Няма супадзенняў у %1$s"</string>
+    <string name="toast_no_application" msgid="4632640357724698144">"Немагчыма адкрыць файл"</string>
+    <string name="toast_failed_delete" msgid="2180678019407244069">"Немагчыма выдаліць некаторыя дакументы"</string>
+    <string name="share_via" msgid="8966594246261344259">"Абагуліць праз"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Капіраванне файлаў"</string>
+    <string name="move_notification_title" msgid="6193835179777284805">"Перамяшчэнне файлаў"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Выдаленне файлаў"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Засталося <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Капіраванне <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+      <item quantity="few">Капіраванне <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў.</item>
+      <item quantity="many">Капіраванне <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў.</item>
+      <item quantity="other">Капіраванне <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+    </plurals>
+    <plurals name="move_begin" formatted="false" msgid="8430330882138871643">
+      <item quantity="one">Перамяшчэнне <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+      <item quantity="few">Перамяшчэнне <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў.</item>
+      <item quantity="many">Перамяшчэнне <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў.</item>
+      <item quantity="other">Перамяшчэнне <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+    </plurals>
+    <plurals name="deleting" formatted="false" msgid="5054338566802559411">
+      <item quantity="one">Выдаленне <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+      <item quantity="few">Выдаленне <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў.</item>
+      <item quantity="many">Выдаленне <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў.</item>
+      <item quantity="other">Выдаленне <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+    </plurals>
+    <string name="undo" msgid="7905788502491742328">"Адрабіць"</string>
+    <string name="copy_preparing" msgid="3896202461003039386">"Падрыхтоўка да капіравання..."</string>
+    <string name="move_preparing" msgid="2772219441375531410">"Падрыхтоўка да перамяшчэння..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Падрыхтоўка да выдалення..."</string>
+    <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+      <item quantity="one">Не атрымалася скапіраваць <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+      <item quantity="few">Не атрымалася скапіраваць <xliff:g id="COUNT_1">%1$d</xliff:g> файлы</item>
+      <item quantity="many">Не атрымалася скапіраваць <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў</item>
+      <item quantity="other">Не атрымалася скапіраваць <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+    </plurals>
+    <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+      <item quantity="one">Не атрымалася перамясціць <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+      <item quantity="few">Не атрымалася перамясціць <xliff:g id="COUNT_1">%1$d</xliff:g> файлы</item>
+      <item quantity="many">Не атрымалася перамясціць <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў</item>
+      <item quantity="other">Не атрымалася перамясціць <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+    </plurals>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+      <item quantity="one">Не атрымалася выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+      <item quantity="few">Не атрымалася выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлы</item>
+      <item quantity="many">Не атрымалася выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў</item>
+      <item quantity="other">Не атрымалася выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Дакраніцеся, каб прагледзець больш падрабязна"</string>
+    <string name="close" msgid="3043722427445528732">"Закрыць"</string>
+    <string name="copy_failure_alert_content" msgid="4563147454522476183">"Не былі скапіраваны наступныя файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+    <string name="move_failure_alert_content" msgid="2635075788682922861">"Не былі перамешчаны наступныя файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+    <string name="copy_converted_warning_content" msgid="5753861488218674361">"Гэтыя файлы былі сканвертаваныя ў іншы фармат: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+    <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
+      <item quantity="one">У буфер абмену скапіраваны <xliff:g id="COUNT_1">%1$d</xliff:g> файл.</item>
+      <item quantity="few">У буфер абмену скапіраваны <xliff:g id="COUNT_1">%1$d</xliff:g> файлы.</item>
+      <item quantity="many">У буфер абмену скапіравана <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў.</item>
+      <item quantity="other">У буфер абмену скапіравана <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+    </plurals>
+    <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Немагчыма ўставіць выбраныя файлы ў гэта месца."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Перайменаваць"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Не атрымалася перайменаваць дакумент"</string>
+    <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некаторыя файлы былі сканвертаваныя"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да дырэкторыі <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> у <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да дырэкторыі <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Даць <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да вашых даных, у тым ліку фатаграфій і відэа, на <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Больш не пытацца"</string>
+    <string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
+    <string name="deny" msgid="2081879885755434506">"Забараніць"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Выбраны <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="few">Выбраны <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="many">Выбрана <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Выбрана <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Выдаліць \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Выдаліць папку \"<xliff:g id="NAME">%1$s</xliff:g>\" і яе змесціва?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлы?</item>
+      <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў?</item>
+      <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папку і іх змесціва?</item>
+      <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папкі і іх змесціва?</item>
+      <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папак і іх змесціва?</item>
+      <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папкі і іх змесціва?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элемент?</item>
+      <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элементы?</item>
+      <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элементаў?</item>
+      <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элемента?</item>
+    </plurals>
+</resources>
diff --git a/packages/DocumentsUI/res/values-bg/config.xml b/packages/DocumentsUI/res/values-bg/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-bg/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 4a6d499..1914bf5 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Споделяне чрез"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файловете се копират"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файловете се преместват"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Изтриване на файлове"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Оставащо време: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Копират се <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Преименуване"</string>
     <string name="rename_error" msgid="4203041674883412606">"Преименуването на документа не бе успешно"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Някои файлове бяха преобразувани"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ в/ъв <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до данните ви в хранилището (<xliff:g id="STORAGE"><i>^2</i></xliff:g>), включително снимки и видеоклипове?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Без повторно питане"</string>
     <string name="allow" msgid="7225948811296386551">"Разрешаване"</string>
     <string name="deny" msgid="2081879885755434506">"Отказване"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">Избрахте <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Избрахте <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Искате ли да изтриете „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Искате ли да изтриете папката „<xliff:g id="NAME">%1$s</xliff:g>“ и съдържанието в нея?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+      <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> файл?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> папки и съдържанието в тях?</item>
+      <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> папка и съдържанието в нея?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> елемента?</item>
+      <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> елемент?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/config.xml b/packages/DocumentsUI/res/values-bn-rBD/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-bn-rBD/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index f53cfa8..d931c2b 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -32,7 +32,7 @@
     <string name="menu_share" msgid="3075149983979628146">"শেয়ার করুন"</string>
     <string name="menu_delete" msgid="8138799623850614177">"মুছুন"</string>
     <string name="menu_select_all" msgid="8323579667348729928">"সবগুলি নির্বাচন করুন"</string>
-    <string name="menu_copy" msgid="3612326052677229148">"এতে অনুলিপি করুন…"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"এতে কপি করুন…"</string>
     <string name="menu_move" msgid="1828090633118079817">"এতে সরান..."</string>
     <string name="menu_new_window" msgid="1226032889278727538">"নতুন উইন্ডো"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"প্রতিলিপি করুন"</string>
@@ -42,7 +42,7 @@
     <string name="menu_file_size_show" msgid="3240323619260823076">"ফাইলের আকার দেখান"</string>
     <string name="menu_file_size_hide" msgid="8881975928502581042">"ফাইলের আকার লুকান"</string>
     <string name="button_select" msgid="527196987259139214">"নির্বাচন করুন"</string>
-    <string name="button_copy" msgid="8706475544635021302">"অনুলিপি করুন"</string>
+    <string name="button_copy" msgid="8706475544635021302">"কপি করুন"</string>
     <string name="button_move" msgid="2202666023104202232">"সরান"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"খারিজ করুন"</string>
     <string name="button_retry" msgid="4392027584153752797">"আবার চেষ্টা করুন"</string>
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"এর মাধ্যমে শেয়ার করুন"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ফাইলগুলি অনুলিপি করা হচ্ছে"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ফাইলগুলি সরানো হচ্ছে"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ফাইলগুলি মোছা হচ্ছে"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> বাকি"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল অনুলিপি করা হচ্ছে৷</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"পুনঃনামকরণ"</string>
     <string name="rename_error" msgid="4203041674883412606">"দস্তাবেজের পুনঃনামকরণ ব্যর্থ হয়েছে৷"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"কিছু ফাইল রূপান্তরিত হয়েছে"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="STORAGE"><i>^3</i></xliff:g> এ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার মঞ্জুরি দিতে চান?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার অনুমতি দেবেন?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> এ থাকা ফটো ও ভিডিওগুলি সমেত <xliff:g id="APPNAME"><b>^1</b></xliff:g> কে আপনার ডেটা অ্যাক্সেস করার অনুমতি দেবেন?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"আর জিজ্ঞাসা করবেন না"</string>
     <string name="allow" msgid="7225948811296386551">"অনুমতি দিন"</string>
     <string name="deny" msgid="2081879885755434506">"আস্বীকার করুন"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" মুছবেন?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ফোল্ডার এবং এটির সামগ্রীগুলিকে মুছবেন?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফোল্ডার এবং সেগুলির সামগ্রী মুছবেন?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফোল্ডার এবং সেগুলির সামগ্রী মুছবেন?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম মুছবেন?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম মুছবেন?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/config.xml b/packages/DocumentsUI/res/values-bs-rBA/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-bs-rBA/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index d315166..47ff436 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Podijeli preko"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiraju se fajlovi"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Premještanje fajlova"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Brisanje fajlova"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopira se <xliff:g id="COUNT_1">%1$d</xliff:g> fajl.</item>
@@ -116,6 +117,32 @@
     <string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
     <string name="rename_error" msgid="4203041674883412606">"Nije uspjelo preimenovanje dokumenta"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke od datoteka su pretvorene"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Omogućiti <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Odobriti aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite li odobriti aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup svojim podacima, uključujući fotografije i video zapise, na <xliff:g id="STORAGE"><i>^2</i></xliff:g> ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ne pitaj ponovo"</string>
     <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
     <string name="deny" msgid="2081879885755434506">"Odbijte"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> stavka je odabrana</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> stavki je odabrano</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li izbrisati \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li izbrisati folder \"<xliff:g id="NAME">%1$s</xliff:g>\" i njegov sadržaj?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> folder i njihov sadržaj?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> foldera i njihov sadržaj?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> foldera i njihov sadržaj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ca/config.xml b/packages/DocumentsUI/res/values-ca/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ca/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 96bfbb7..09af97d 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"S\'estan copiant fitxers"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"S\'estan movent fitxers"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Suprimint els fitxers"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Temps restant: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">S\'estan copiant <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Canvia el nom"</string>
     <string name="rename_error" msgid="4203041674883412606">"No s\'ha pogut canviar el nom del document"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de l\'emmagatzematge <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés a les dades de <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incloses les fotos i els vídeos?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"No m\'ho demanis més"</string>
     <string name="allow" msgid="7225948811296386551">"Permet"</string>
     <string name="deny" msgid="2081879885755434506">"Denega"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elements seleccionats</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> element seleccionat</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vols suprimir el fitxer <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vols suprimir la carpeta <xliff:g id="NAME">%1$s</xliff:g> i el seu contingut?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers?</item>
+      <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> carpetes i el seu contingut?</item>
+      <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta i el seu contingut?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> elements?</item>
+      <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-cs/config.xml b/packages/DocumentsUI/res/values-cs/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-cs/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index a6e79b6..cba2e0e 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopírování souborů"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Přesouvání souborů"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Mazání souborů"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Zbývající čas: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Kopírování <xliff:g id="COUNT_1">%1$d</xliff:g> souborů</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"Přejmenovat"</string>
     <string name="rename_error" msgid="4203041674883412606">"Dokument se nepodařilo přejmenovat."</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Některé soubory byly převedeny"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložišti <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup ke svým datům v úložišti <xliff:g id="STORAGE"><i>^2</i></xliff:g>, včetně fotek a videí?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Příště se neptat"</string>
     <string name="allow" msgid="7225948811296386551">"Povolit"</string>
     <string name="deny" msgid="2081879885755434506">"Odepřít"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="few">Vybrány <xliff:g id="COUNT_1">%1$d</xliff:g> položky</item>
+      <item quantity="many">Vybráno <xliff:g id="COUNT_1">%1$d</xliff:g> položky</item>
+      <item quantity="other">Vybráno <xliff:g id="COUNT_1">%1$d</xliff:g> položek</item>
+      <item quantity="one">Vybrána <xliff:g id="COUNT_0">%1$d</xliff:g> položka</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Smazat soubor <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Smazat složku <xliff:g id="NAME">%1$s</xliff:g> a její obsah?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> soubory?</item>
+      <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souboru?</item>
+      <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souborů?</item>
+      <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> soubor?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složky a jejich obsah?</item>
+      <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složky a jejich obsah?</item>
+      <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složek a jejich obsah?</item>
+      <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> složku a její obsah?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položek?</item>
+      <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> položku?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-da/config.xml b/packages/DocumentsUI/res/values-da/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-da/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index a0b7c1f..f048e34 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Filerne slettes"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> tilbage"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Omdøb"</string>
     <string name="rename_error" msgid="4203041674883412606">"Dokumentet kunne ikke omdøbes"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nogle filer er konverteret"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til mappen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til indekset <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til dine data, herunder billeder og videoer på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Spørg ikke igen"</string>
     <string name="allow" msgid="7225948811296386551">"Tillad"</string>
     <string name="deny" msgid="2081879885755434506">"Afvis"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Der er valgt <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Der er valgt <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vil du slette \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vil du slette mappen \"<xliff:g id="NAME">%1$s</xliff:g>\" og dens indhold?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> fil?</item>
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mappe og dens indhold?</item>
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mapper og deres indhold?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> element?</item>
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> elementer?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-de/config.xml b/packages/DocumentsUI/res/values-de/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-de/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 2d968fe..a6eae70 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Dateien werden kopiert"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Dateien werden verschoben"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Dateien werden gelöscht"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Noch <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien werden kopiert.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Umbenennen"</string>
     <string name="rename_error" msgid="4203041674883412606">"Dokument konnte nicht umbenannt werden"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Einige Dateien wurden konvertiert"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> auf <xliff:g id="STORAGE"><i>^3</i></xliff:g> geben?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Möchtest du <xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> geben?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Möchtest du <xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf deine Daten auf <xliff:g id="STORAGE"><i>^2</i></xliff:g> geben, einschließlich Fotos und Videos?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Nicht mehr fragen"</string>
     <string name="allow" msgid="7225948811296386551">"Zulassen"</string>
     <string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ausgewählt</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ausgewählt</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" löschen?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ordner \"<xliff:g id="NAME">%1$s</xliff:g>\" und dessen Inhalte löschen?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Dateien löschen?</item>
+      <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Datei löschen?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Ordner und deren Inhalte löschen?</item>
+      <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Ordner und dessen Inhalte löschen?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Elemente löschen?</item>
+      <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Element löschen?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-el/config.xml b/packages/DocumentsUI/res/values-el/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-el/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 6c9896d..7dc2067 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Αντιγραφή αρχείων"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Μετακίνηση αρχείων"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Διαγραφή αρχείων"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Απομένουν <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Μετονομασία"</string>
     <string name="rename_error" msgid="4203041674883412606">"Αποτυχία μετονομασίας εγγράφου"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Ορισμένα αρχεία μετατράπηκαν"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Να εκχωρηθεί στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> πρόσβαση στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> στον αποθηκευτικό χώρο <xliff:g id="STORAGE"><i>^3</i></xliff:g>;"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Εκχώρηση πρόσβασης στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>;"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Θέλετε να εκχωρήσετε πρόσβαση στα δεδομένα σας στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g>, συμπεριλαμβανομένων των φωτογραφιών και των βίντεό σας, στον αποθηκευτικό χώρο <xliff:g id="STORAGE"><i>^2</i></xliff:g>;"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Να μην ερωτηθώ ξανά"</string>
     <string name="allow" msgid="7225948811296386551">"Να επιτρέπεται"</string>
     <string name="deny" msgid="2081879885755434506">"Άρνηση"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> επιλεγμένα</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> επιλεγμένο</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Να διαγραφεί το αρχείο \"<xliff:g id="NAME">%1$s</xliff:g>\";"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Να διαγραφεί ο φάκελος \"<xliff:g id="NAME">%1$s</xliff:g>\" και τα περιεχόμενά του;"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία;</item>
+      <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείο;</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> φάκελοι και τα περιεχόμενά τους;</item>
+      <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> φάκελος και τα περιεχόμενά του;</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> στοιχεία;</item>
+      <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> στοιχείο;</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/config.xml b/packages/DocumentsUI/res/values-en-rAU/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-en-rAU/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 5bc4f59..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Moving files"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Deleting files"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"rename"</string>
     <string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
     <string name="allow" msgid="7225948811296386551">"Allow"</string>
     <string name="deny" msgid="2081879885755434506">"Deny"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/config.xml b/packages/DocumentsUI/res/values-en-rGB/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-en-rGB/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 5bc4f59..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Moving files"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Deleting files"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"rename"</string>
     <string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
     <string name="allow" msgid="7225948811296386551">"Allow"</string>
     <string name="deny" msgid="2081879885755434506">"Deny"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/config.xml b/packages/DocumentsUI/res/values-en-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-en-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 5bc4f59..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Moving files"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Deleting files"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"rename"</string>
     <string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
     <string name="allow" msgid="7225948811296386551">"Allow"</string>
     <string name="deny" msgid="2081879885755434506">"Deny"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/config.xml b/packages/DocumentsUI/res/values-es-rUS/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-es-rUS/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index e212053..87641a7 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Borrando los archivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Faltan <xliff:g id="DURATION">%s</xliff:g>."</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Cambiar nombre"</string>
     <string name="rename_error" msgid="4203041674883412606">"No se pudo cambiar el nombre del documento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se convirtieron algunos archivos"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"¿Otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> en <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Quieres otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Quieres otorgar acceso a la app de <xliff:g id="APPNAME"><b>^1</b></xliff:g> a tus datos, incluidas tus fotos y videos en <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"No volver a preguntar"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementos seleccionados</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento seleccionado</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"¿Deseas borrar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"¿Deseas borrar la carpeta \"<xliff:g id="NAME">%1$s</xliff:g>\" y su contenido?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+      <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item>
+      <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+      <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es/config.xml b/packages/DocumentsUI/res/values-es/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-es/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 28f3fd0..9054561 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminando archivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Tiempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Cambiar nombre"</string>
     <string name="rename_error" msgid="4203041674883412606">"Error al cambiar el nombre del documento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> (<xliff:g id="STORAGE"><i>^3</i></xliff:g>)?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda a tus datos, incluidos los vídeos y las fotos, de <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"No volver a preguntar"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seleccionados</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"¿Eliminar <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"¿Eliminar la carpeta <xliff:g id="NAME">%1$s</xliff:g> y su contenido?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+      <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item>
+      <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+      <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/config.xml b/packages/DocumentsUI/res/values-et-rEE/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-et-rEE/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index d8d6bea..4bb2a9b 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Jagage teenusega"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Failide kopeerimine"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Failide teisaldamine"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Failide kustutamine"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Jäänud on <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faili kopeerimine.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Nimeta ümber"</string>
     <string name="rename_error" msgid="4203041674883412606">"Dokumendi ümbernimetamine ebaõnnestus"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Mõned failid teisendati"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> salvestusruumis <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs teie andmetele (sh fotod ja videod) salvestusruumis <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ära enam küsi"</string>
     <string name="allow" msgid="7225948811296386551">"Luba"</string>
     <string name="deny" msgid="2081879885755434506">"Keela"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> on valitud</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Kas kustutada fail „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Kas kustutada kaust „<xliff:g id="NAME">%1$s</xliff:g>” ja selle sisu?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> faili?</item>
+      <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> kausta ja nende sisu?</item>
+      <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> kaust ja selle sisu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> üksust?</item>
+      <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> üksus?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/config.xml b/packages/DocumentsUI/res/values-eu-rES/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-eu-rES/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index a8f3517..d2bf89d 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partekatu honen bidez:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Fitxategiak kopiatzen"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Fitxategiak mugitzea"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Fitxategiak ezabatzea"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Falta den denbora: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi kopiatzen.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Aldatu izena"</string>
     <string name="rename_error" msgid="4203041674883412606">"Ezin izan zaio aldatu izena dokumentuari"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Artxibo batzuk bihurtu dira"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="STORAGE"><i>^3</i></xliff:g> unitateko <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktorioa atzitzeko baimena eman nahi diozu?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktoriorako sarbidea eman nahi diozu?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari zure datuak atzitzea baimendu nahi diozu, besteak beste, <xliff:g id="STORAGE"><i>^2</i></xliff:g> biltegian dituzun argazkiak eta bideoak?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ez galdetu berriro"</string>
     <string name="allow" msgid="7225948811296386551">"Onartu"</string>
     <string name="deny" msgid="2081879885755434506">"Ukatu"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> hautatuta</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ezabatu nahi duzu?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" karpeta eta bertako edukia ezabatu nahi duzu?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi ezabatu nahi dituzu?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi ezabatu nahi duzu?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> karpeta eta beren eduki guztia ezabatu nahi duzu?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> karpeta eta bere eduki guztia ezabatu nahi duzu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementu ezabatu nahi dituzu?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elementu ezabatu nahi duzu?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fa/config.xml b/packages/DocumentsUI/res/values-fa/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-fa/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 3b3d559..1a4c035 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"اشتراک‌گذاری از طریق"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"در حال کپی کردن فایل‌ها"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"درحال انتقال فایل‌ها"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"در حال حذف فایل‌ها"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی‌مانده"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">در حال کپی کردن <xliff:g id="COUNT_1">%1$d</xliff:g> فایل.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"تغییر نام"</string>
     <string name="rename_error" msgid="4203041674883412606">"نام سند تغییر نکرد"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"بعضی از فایل‌ها تبدیل شدند"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه داده شود به فهرست راهنمای <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> در <xliff:g id="STORAGE"><i>^3</i></xliff:g> دسترسی داشته باشد؟"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه دسترسی به دایرکتوری <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> داده شود؟"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه می‌دهید به داده‌هایتان دسترسی پیدا کند، از جمله عکس‌ها و ویدیوهایتان در <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"دوباره سؤال نشود"</string>
     <string name="allow" msgid="7225948811296386551">"ارزیابی‌شده"</string>
     <string name="deny" msgid="2081879885755434506">"اجازه ندارد"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">‏<xliff:g id="COUNT_1">%1$d</xliff:g> مورد انتخاب شد</item>
+      <item quantity="other">‏<xliff:g id="COUNT_1">%1$d</xliff:g> مورد انتخاب شد</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"«<xliff:g id="NAME">%1$s</xliff:g>» حذف شود؟"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"پوشه «<xliff:g id="NAME">%1$s</xliff:g>» و محتوای آن حذف شود؟"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> پوشه و محتوای آن‌ها حذف شود؟</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> پوشه و محتوای آن‌ها حذف شود؟</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف شود؟</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف شود؟</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fi/config.xml b/packages/DocumentsUI/res/values-fi/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-fi/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 14513bd..dfcfe89 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopioidaan tiedostoja"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Siirretään tiedostoja"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Poistetaan tiedostoja"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> jäljellä"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopioidaan <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Nimeä uudelleen"</string>
     <string name="rename_error" msgid="4203041674883412606">"Dokumentin nimen muuttaminen epäonnistui."</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Joitakin tiedostoja muunnettiin."</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Myönnetäänkö sovellukselle <xliff:g id="APPNAME"><b>^1</b></xliff:g> sijainnissa <xliff:g id="STORAGE"><i>^3</i></xliff:g> olevan hakemiston <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> käyttöoikeus?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Saako <xliff:g id="APPNAME"><b>^1</b></xliff:g> käyttää hakemistoa <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Myönnetäänkö sovellukselle <xliff:g id="APPNAME"><b>^1</b></xliff:g> sijainnissa <xliff:g id="STORAGE"><i>^2</i></xliff:g> olevien tietojesi, mukaan lukien valokuviesi ja videoidesi, käyttöoikeus?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Älä kysy uudestaan"</string>
     <string name="allow" msgid="7225948811296386551">"Salli"</string>
     <string name="deny" msgid="2081879885755434506">"Kiellä"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valittu</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> valittu</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Poistetaanko <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Poistetaanko kansio <xliff:g id="NAME">%1$s</xliff:g> ja sen sisältö?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa?</item>
+      <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> tiedosto?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> kansiota ja niiden sisältö?</item>
+      <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> kansio ja sen sisältö?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> kohdetta?</item>
+      <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> kohde?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/config.xml b/packages/DocumentsUI/res/values-fr-rCA/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-fr-rCA/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 0d35f4a..543e226 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partager par"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers..."</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Déplacement des fichiers"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Suppression des fichiers"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Durée restante : <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copier de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Renommer"</string>
     <string name="rename_error" msgid="4203041674883412606">"Impossible de renommer le document"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sur <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Voulez-vous accorder l\'accès à vos données à <xliff:g id="APPNAME"><b>^1</b></xliff:g>, y compris vos photos et vos vidéos, sur <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ne plus me demander"</string>
     <string name="allow" msgid="7225948811296386551">"Autoriser"</string>
     <string name="deny" msgid="2081879885755434506">"Refuser"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Supprimer « <xliff:g id="NAME">%1$s</xliff:g> »?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Supprimer le dossier «  <xliff:g id="NAME">%1$s</xliff:g> » et son contenu?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr/config.xml b/packages/DocumentsUI/res/values-fr/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-fr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 7ed98bb..05716d7 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partager via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers en cours"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Déplacement de fichiers"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Suppression des fichiers…"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Temps restant : <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours…</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Renommer"</string>
     <string name="rename_error" msgid="4203041674883412606">"Échec du changement de nom du document."</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" sur <xliff:g id="STORAGE"><i>^3</i></xliff:g> ?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" ?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à vos données, y compris les photos et les vidéos, sur <xliff:g id="STORAGE"><i>^2</i></xliff:g> ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ne plus demander"</string>
     <string name="allow" msgid="7225948811296386551">"Autoriser"</string>
     <string name="deny" msgid="2081879885755434506">"Refuser"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Supprimer \"<xliff:g id="NAME">%1$s</xliff:g>\" ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Supprimer le dossier \"<xliff:g id="NAME">%1$s</xliff:g>\" et son contenu ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier ?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu ?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément ?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/config.xml b/packages/DocumentsUI/res/values-gl-rES/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-gl-rES/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index 645eb04..5797a96 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando ficheiros"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Mover ficheiros"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminando ficheiros"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Tempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Cambiar nome"</string>
     <string name="rename_error" msgid="4203041674883412606">"Non se puido cambiar o nome do documento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Convertéronse algúns ficheiros"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Queres outorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no almacenamento de <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Queres darlle acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Queres darlle acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> aos teus datos almacenados en <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incluídos vídeos e fotos?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Non preguntar de novo"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Rexeitar"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">Seleccionáronse <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Seleccionouse <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Queres eliminar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Queres eliminar o cartafol \"<xliff:g id="NAME">%1$s</xliff:g>\" e o seu contido?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+      <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> cartafoles e os seus contidos?</item>
+      <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> cartafol e os seus contidos?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+      <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/config.xml b/packages/DocumentsUI/res/values-gu-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-gu-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 927906a..48e43c4 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"આના દ્વારા શેર કરો"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ફાઇલો કૉપિ કરી રહ્યાં છે"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ફાઇલો ખસેડી રહ્યાં છે"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ફાઇલને નીકાળી રહ્યાં છે"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> બાકી"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલો કૉપિ કરી રહ્યાં છે.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"નામ બદલો"</string>
     <string name="rename_error" msgid="4203041674883412606">"દસ્તાવેજનું નામ બદલવામાં નિષ્ફળ થયાં"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"કેટલીક ફાઇલો રૂપાંતરિત કરી હતી"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="STORAGE"><i>^3</i></xliff:g> પર <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="STORAGE"><i>^2</i></xliff:g> પર ફોટા અને વિડિઓઝ સહિત તમારા ડેટાની અ‍ૅક્સેસ આપીએ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"ફરીથી પૂછશો નહીં"</string>
     <string name="allow" msgid="7225948811296386551">"મંજૂરી આપો"</string>
     <string name="deny" msgid="2081879885755434506">"નકારો"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ને કાઢી નાખીએ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ફોલ્ડર અને તેની સામગ્રીઓને કાઢી નાખીએ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફોલ્ડર અને તેમની સામગ્રીઓ કાઢી નાખીએ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફોલ્ડર અને તેમની સામગ્રીઓ કાઢી નાખીએ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમ કાઢી નાખીએ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમ કાઢી નાખીએ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hi/config.xml b/packages/DocumentsUI/res/values-hi/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-hi/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index f947d3d..fa82ee8 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"इसके द्वारा साझा करें"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"फ़ाइलें कॉपी हो रही हैं"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"फाइलें ले जाई जा रही हैं"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"फ़ाइलें हटाई जा रही हैं"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शेष"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें कॉपी की जा रही हैं.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"नाम बदलें"</string>
     <string name="rename_error" msgid="4203041674883412606">"दस्‍तावेज़ का नाम बदलना विफल रहा"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"कुछ फ़ाइलें रूपांतरित हो गई थीं"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^3</i></xliff:g> पर <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस दें?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस प्रदान करें?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^2</i></xliff:g> पर मौजूद फ़ोटो और वीडियो सहित, अपने डेटा का एक्सेस प्रदान करें?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"फिर से ना पूछें"</string>
     <string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
     <string name="deny" msgid="2081879885755434506">"अस्वीकारें"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" को हटाएं?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" फ़ोल्डर और उसकी सामग्रियां हटाएं?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ोल्डर और उनकी सामग्री हटाएं?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ोल्डर और उनकी सामग्री हटाएं?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम हटाएं?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम हटाएं?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hr/config.xml b/packages/DocumentsUI/res/values-hr/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-hr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index bfac527..7988c71 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Dijeli putem"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Premještanje datoteka"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Brisanje datoteka"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
@@ -116,6 +117,32 @@
     <string name="menu_rename" msgid="7678802479104285353">"Promijeni naziv"</string>
     <string name="rename_error" msgid="4203041674883412606">"Naziv dokumenta nije promijenjen"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke su datoteke konvertirane"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na pohrani <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti da pristupa direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dopustiti pristup podacima, uključujući fotografije i videozapise na vanjskoj pohrani (<xliff:g id="STORAGE"><i>^2</i></xliff:g>)?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Više me ne pitaj"</string>
     <string name="allow" msgid="7225948811296386551">"Dopusti"</string>
     <string name="deny" msgid="2081879885755434506">"Odbij"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Odabrano: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="few">Odabrano: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Odabrano: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li izbrisati datoteku \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li izbrisati mapu \"<xliff:g id="NAME">%1$s</xliff:g>\" i njezin sadržaj?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapu i njihov sadržaj?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mape i njihov sadržaj?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapa i njihov sadržaj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hu/config.xml b/packages/DocumentsUI/res/values-hu/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-hu/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 220d99c..fb666b5 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Megosztás itt:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Fájlok másolása"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Fájlok áthelyezése"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Fájlok törlése"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> van hátra"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fájl másolása.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Átnevezés"</string>
     <string name="rename_error" msgid="4203041674883412606">"Nem sikerült átnevezni a dokumentumot"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Egyes fájlokat konvertált a rendszer"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> számára a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz itt: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> alkalmazásnak a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> számára az Ön adataihoz, beleértve a következő tárhelyen található képekhez és videókhoz: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ne jelenjen meg többé"</string>
     <string name="allow" msgid="7225948811296386551">"Engedélyezés"</string>
     <string name="deny" msgid="2081879885755434506">"Elutasítás"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> kiválasztva</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kiválasztva</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Törli a következőt: „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Törli „<xliff:g id="NAME">%1$s</xliff:g>” mappát a tartalmával együtt?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt?</item>
+      <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> mappát a tartalmukkal együtt?</item>
+      <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> mappát a tartalmával együtt?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> elemet?</item>
+      <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> elemet?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/config.xml b/packages/DocumentsUI/res/values-hy-rAM/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-hy-rAM/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 4448fe4..f6c3ad5 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Տարածել"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Ֆայլերի պատճենում"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Ֆայլերի տեղափոխում"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Ֆայլերը ջնջվում են"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Մնացել է <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլի պատճենում:</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Վերանվանել"</string>
     <string name="rename_error" msgid="4203041674883412606">"Չհաջողվեց վերանվանել փաստաթուղթը"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Որոշ ֆայլեր փոխարկվել են"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ի <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="STORAGE"><i>^2</i></xliff:g>-ում պահվող ձեր տվյալները, այդ թվում նաև լուսանկարները և տեսանյութերը, օգտագործելու թույլտվություն:"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Այլևս չհարցնել"</string>
     <string name="allow" msgid="7225948811296386551">"Թույլատրել"</string>
     <string name="deny" msgid="2081879885755434506">"Մերժել"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ջնջե՞լ «<xliff:g id="NAME">%1$s</xliff:g>» ֆայլը:"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ջնջե՞լ «<xliff:g id="NAME">%1$s</xliff:g>» պանակը՝ բովանդակության հետ մեկտեղ:"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+      <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> պանակ՝ բովանդակության հետ մեկտեղ:</item>
+      <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> պանակ՝ բովանդակության հետ մեկտեղ:</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> տարր:</item>
+      <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> տարր:</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-in/config.xml b/packages/DocumentsUI/res/values-in/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-in/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 4d4e810..a8aee52 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Bagikan melalui"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Menyalin file"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Memindahkan file"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Menghapus file"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Ganti nama"</string>
     <string name="rename_error" msgid="4203041674883412606">"Gagal mengganti nama dokumen"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Beberapa file dikonversi"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke data Anda, termasuk foto dan video, di <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Jangan tanya lagi"</string>
     <string name="allow" msgid="7225948811296386551">"Izinkan"</string>
     <string name="deny" msgid="2081879885755434506">"Tolak"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Hapus \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Hapus folder \"<xliff:g id="NAME">%1$s</xliff:g>\" dan kontennya?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> folder dan kontennya?</item>
+      <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> folder dan kontennya?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+      <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/config.xml b/packages/DocumentsUI/res/values-is-rIS/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-is-rIS/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index d7e4284..88aaced 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Deila í gegnum"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Afritar skrár"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Skrár færðar"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eyðir skrám"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> eftir"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Afritar <xliff:g id="COUNT_1">%1$d</xliff:g> skrá.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Endurnefna"</string>
     <string name="rename_error" msgid="4203041674883412606">"Ekki tókst að endurnefna skjalið"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sumum skrám var umbreytt"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> á <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Viltu veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að gögnunum þínum, þar á meðal myndum og myndskeiðum, á <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ekki spyrja aftur"</string>
     <string name="allow" msgid="7225948811296386551">"Leyfa"</string>
     <string name="deny" msgid="2081879885755434506">"Hafna"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> valið</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valin</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Eyða „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Eyða möppunni „<xliff:g id="NAME">%1$s</xliff:g>“ og öllu innihaldi hennar?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá?</item>
+      <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> möppu og innihaldi þeirra?</item>
+      <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> möppum og innihaldi þeirra?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> atriði?</item>
+      <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> atriðum?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-it/config.xml b/packages/DocumentsUI/res/values-it/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-it/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 373f480..b7497db 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Condividi via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copia di file in corso"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Spostamento di file"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminazione dei file"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> rimanenti"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Rinomina"</string>
     <string name="rename_error" msgid="4203041674883412606">"Ridenominazione documento non riuscita"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alcuni file sono stati convertiti"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> su <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso ai tuoi dati, inclusi video e foto, sull\'unità <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Non chiedermelo più"</string>
     <string name="allow" msgid="7225948811296386551">"Consenti"</string>
     <string name="deny" msgid="2081879885755434506">"Nega"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi selezionati</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento selezionato</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Eliminare \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Eliminare la cartella \"<xliff:g id="NAME">%1$s</xliff:g>\" e i relativi contenuti?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> cartelle e i relativi contenuti?</item>
+      <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> cartella e i relativi contenuti?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi?</item>
+      <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-iw/config.xml b/packages/DocumentsUI/res/values-iw/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-iw/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 8806079..4498f8c 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"שתף באמצעות"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"מעתיק קבצים"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"מעביר קבצים"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"מחיקת קבצים מתבצעת"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"זמן נותר: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="two">מעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים.</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"שנה שם"</string>
     <string name="rename_error" msgid="4203041674883412606">"ניסיון שינוי שם המסמך נכשל"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"קבצים מסוימים הומרו"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לספריה <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> באחסון <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה אל ספריית <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לנתונים שלך, כולל תמונות וסרטונים, השמורים ב<xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"אל תשאל שוב"</string>
     <string name="allow" msgid="7225948811296386551">"אפשר"</string>
     <string name="deny" msgid="2081879885755434506">"דחה"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> נבחר</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"האם למחוק את \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"האם למחוק את התיקייה \"<xliff:g id="NAME">%1$s</xliff:g>\" ואת התוכן שלה?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+      <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+      <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+      <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> תיקייה ואת התוכן שלה?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+      <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+      <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+      <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> פריט?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ja/config.xml b/packages/DocumentsUI/res/values-ja/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ja/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index e0b82e5..bfb1c3a 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"共有ツール"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ファイルのコピー中"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ファイルを移動中"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ファイルを削除しています"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"残り<xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>個のファイルをコピーしています。</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"名前を変更"</string>
     <string name="rename_error" msgid="4203041674883412606">"ドキュメントの名前を変更できませんでした"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"「<xliff:g id="STORAGE"><i>^3</i></xliff:g>」の「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリに「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」へのアクセスを許可しますか?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」アプリに「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリへのアクセスを許可しますか?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>の写真や動画などのデータへのアクセスを「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」に許可しますか?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"今後表示しない"</string>
     <string name="allow" msgid="7225948811296386551">"許可"</string>
     <string name="deny" msgid="2081879885755434506">"拒否"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個を選択中</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個を選択中</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"「<xliff:g id="NAME">%1$s</xliff:g>」を削除しますか?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"フォルダ「<xliff:g id="NAME">%1$s</xliff:g>」とそのコンテンツを削除しますか?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のフォルダとそのコンテンツを削除しますか?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のフォルダとそのコンテンツを削除しますか?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個の項目を削除しますか?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個の項目を削除しますか?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/config.xml b/packages/DocumentsUI/res/values-ka-rGE/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ka-rGE/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 5e1ddd3..f0e9e86 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"გაზიარება:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"მიმდ. ფაილების კოპირება"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ფაილების გადაადგილება"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ფაილების წაშლა…"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"დარჩა <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">მიმდინარეობს <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის კოპირება.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"გადარქმევა"</string>
     <string name="rename_error" msgid="4203041674883412606">"დოკუმენტის გადარქმევა ვერ მოხერხდა"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ზოგიერთი ფაილი გარდაქმნილია"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ის დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს <xliff:g id="STORAGE"><i>^2</i></xliff:g>-ზე არსებულ მონაცემებზე, მათ შორის, ფოტოებსა და ვიდეოებზე, წვდომის უფლებით?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"აღარ მკითხოთ"</string>
     <string name="allow" msgid="7225948811296386551">"უფლების მიცემა"</string>
     <string name="deny" msgid="2081879885755434506">"აკრძალვა"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">არჩეულია <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">არჩეულია <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"გსურთ, წაშალოთ „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"გსურთ, წაშალოთ საქაღალდე „<xliff:g id="NAME">%1$s</xliff:g>“ და მისი შიგთავსი?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის წაშლა?</item>
+      <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ფაილის წაშლა?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> საქაღალდისა და მათი შიგთავსის წაშლა?</item>
+      <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> საქაღალდისა და მისი შიგთავსის წაშლა?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ერთეულის წაშლა?</item>
+      <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ერთეულის წაშლა?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/config.xml b/packages/DocumentsUI/res/values-kk-rKZ/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-kk-rKZ/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 5b6b94d..2687900 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Бөлісу"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файлдарды көшіру"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файлдар тасымалдануда"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Файлдар жойылуда"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> қалды"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды көшіру.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Атын өзгерту"</string>
     <string name="rename_error" msgid="4203041674883412606">"Құжат қайта аталмады"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="STORAGE"><i>^3</i></xliff:g> қоймасындағы <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына өтуге рұқсат беру керек пе?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына қатынас беру керек пе?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> <xliff:g id="STORAGE"><i>^2</i></xliff:g> қоймасындағы деректерге, соның ішінде фотосуреттерге және бейнелерге кіру мүмкіндігін беру керек пе?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Қайта сұралмасын"</string>
     <string name="allow" msgid="7225948811296386551">"Рұқсат беру"</string>
     <string name="deny" msgid="2081879885755434506">"Бас тарту"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> таңдалды</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> таңдалды</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" жою керек пе?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" қалтасын және оның мазмұнын жою керек пе?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды жою керек пе?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файлды жою керек пе?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> қалтаны ішіндегісімен бірге жою керек пе?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> қалтаны ішіндегісімен бірге жою керек пе?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> элементті жою керек пе?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> элементті жою керек пе?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/config.xml b/packages/DocumentsUI/res/values-km-rKH/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-km-rKH/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 4664bd4..ea24043 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"ចែករំលែក​តាម"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"កំពុងថតចម្លងឯកសារ"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ផ្លាស់ទីឯកសារ"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"កំពុងលុបឯកសារ"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"នៅសល់ <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">កំពុងថតចម្លងឯកសារចំនួន <xliff:g id="COUNT_1">%1$d</xliff:g> ។</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"ប្ដូរឈ្មោះ"</string>
     <string name="rename_error" msgid="4203041674883412606">"បានបរាជ័យក្នុងការប្តូរឈ្មោះឯកសារ"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ឯកសារមួយចំនួនត្រូវបានបម្លែង"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> នៅលើ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ឬ?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"ផ្តល់សិទ្ធិអនុញ្ញាតដល់ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ដើម្បីចូលដំណើរការទិន្នន័យរបស់អ្នក រាប់បញ្ចូលទាំងរូបថត និងវីដេអូ នៅលើ <xliff:g id="STORAGE"><i>^2</i></xliff:g> ឬទេ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"កុំសួរទៀត"</string>
     <string name="allow" msgid="7225948811296386551">"អនុញ្ញាត​"</string>
     <string name="deny" msgid="2081879885755434506">"បដិសេធ"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">បានជ្រើស <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">បានជ្រើស <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"លុប \"<xliff:g id="NAME">%1$s</xliff:g>\" ឬ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"លុបថតឯកសារ \"<xliff:g id="NAME">%1$s</xliff:g>\" និងមាតិការបស់វាឬ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">លុបឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> ច្បាប់ឬ?</item>
+      <item quantity="one">លុបឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> ច្បាប់ឬ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">លុបថតឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> និងមាតិការបស់វាឬ?</item>
+      <item quantity="one">លុបថតឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> និងមាតិការបស់វាឬ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">លុបធាតុ <xliff:g id="COUNT_1">%1$d</xliff:g> ឬ?</item>
+      <item quantity="one">លុបធាតុ <xliff:g id="COUNT_0">%1$d</xliff:g> ឬ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/config.xml b/packages/DocumentsUI/res/values-kn-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-kn-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 487a7b3..c756009 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"ಈ ಮೂಲಕ ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ಫೈಲ್‌ಗಳನ್ನು ಸರಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ಫೈಲ್ ಅಳಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ಉಳಿದಿದೆ"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"ಮರುಹೆಸರಿಸು"</string>
     <string name="rename_error" msgid="4203041674883412606">"ಡಾಕ್ಯುಮೆಂಟ್ ಮರುಹೆಸರಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ಕೆಲವು ಫೈಲ್‌ಗಳನ್ನು ಪರಿವರ್ತಿಸಲಾಗಿದೆ"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> ರಲ್ಲಿ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿಗೆ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ಪ್ರವೇಶ ನೀಡುವುದೇ?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g><xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿ ಪ್ರವೇಶಿಸಲು ಅನುಮತಿಸುವುದೇ?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> ಸಂಗ್ರಹಣೆಯಲ್ಲಿನ ಪೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APPNAME"><b>^1</b></xliff:g> ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುವುದೇ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"ಮತ್ತೆ ಕೇಳಬೇಡಿ"</string>
     <string name="allow" msgid="7225948811296386551">"ಅನುಮತಿಸು"</string>
     <string name="deny" msgid="2081879885755434506">"ನಿರಾಕರಿಸು"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಅಳಿಸುವುದೇ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಫೋಲ್ಡರ್‌ ಮತ್ತು ಅದರ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್‌ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್‌ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ko/config.xml b/packages/DocumentsUI/res/values-ko/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ko/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 62336c7..4d5dcf9 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"공유 방법"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"파일 복사 중"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"파일 이동"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"파일 삭제"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> 남음"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 복사합니다.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"이름 바꾸기"</string>
     <string name="rename_error" msgid="4203041674883412606">"문서 이름을 변경하지 못했습니다."</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"일부 파일이 변환되었습니다."</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="STORAGE"><i>^3</i></xliff:g>에서 <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>에서 사진, 동영상 등 <xliff:g id="STORAGE"><i>^2</i></xliff:g>의 내 데이터에 액세스하도록 허용하시겠습니까?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"다시 묻지 않음"</string>
     <string name="allow" msgid="7225948811296386551">"허용"</string>
     <string name="deny" msgid="2081879885755434506">"거부"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>개 선택됨</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 선택됨</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"<xliff:g id="NAME">%1$s</xliff:g>을(를) 삭제하시겠습니까?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\'<xliff:g id="NAME">%1$s</xliff:g>\' 폴더와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+      <item quantity="one">파일 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">폴더 <xliff:g id="COUNT_1">%1$d</xliff:g>개와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?</item>
+      <item quantity="one">폴더 <xliff:g id="COUNT_0">%1$d</xliff:g>개와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">항목 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+      <item quantity="one">항목 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/config.xml b/packages/DocumentsUI/res/values-ky-rKG/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ky-rKG/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index f93f709..1b39039 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Кийинки аркылуу бөлүшүү:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файлдар көчүрүлүүдө"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файлдар жылдырылууда…"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Файлдар жок кылынууда"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> калды"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көчүрүлүүдө.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Аталышын өзгөртүү"</string>
     <string name="rename_error" msgid="4203041674883412606">"Документтин аталышы өзгөртүлбөй калды"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Айрым файлдардын форматы өзгөртүлдү"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="STORAGE"><i>^3</i></xliff:g> түзмөгүндөгү <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> папканы пайдалануу мүмкүнчүлүгү берилсинби?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогун пайдалануу мүмкүнчүлүгү берилсинби?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="STORAGE"><i>^2</i></xliff:g> түзмөгүндөгү дайындарыңыз, сүрөттөрүңүз жана видеолоруңузду пайдалануу мүмкүнчүлүгү берилсинби?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Экинчи суралбасын"</string>
     <string name="allow" msgid="7225948811296386551">"Уруксат берүү"</string>
     <string name="deny" msgid="2081879885755434506">"Жок"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> тандалды</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" жок кылынсынбы?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" куржуну мазмуну менен жок кылынсынбы?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жок кылынсынбы?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жок кылынсынбы?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> куржун мазмуну менен жок кылынсынбы?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> куржун мазмуну менен жок кылынсынбы?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> нерсе жок кылынсынбы?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> нерсе жок кылынсынбы?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/config.xml b/packages/DocumentsUI/res/values-lo-rLA/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-lo-rLA/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 4b36057..a4f381d 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"ແບ່ງປັນຜ່ານ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ກຳ​ລັງ​ອັດ​ສຳ​ເນົາ​ໄຟ​ລ໌"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ກຳ​ລັງ​ຍ້າຍ​ໄຟ​ລ໌"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ກຳລັງລຶບໄຟລ໌"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ຍັງ​ເຫຼືອ​ຢູ່"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">ກຳ​ລັງ​ອັດ​ສຳ​ເນົາ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟ​ລ໌.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"ປ່ຽນຊື່"</string>
     <string name="rename_error" msgid="4203041674883412606">"ປ່ຽນຊື່ເອກະສານບໍ່ສຳເລັດ"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ປ່ຽນແປງບາງໄຟລ໌ແລ້ວ"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"ອະນຸຍາດສິດເຂົ້າເຖິງໃຫ້ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ເພື່ອເຂົ້າໄດເຣກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ຢູ່ <xliff:g id="STORAGE"><i>^3</i></xliff:g> ບໍ?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ອະນຸມັດ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ໃຫ້ເຂົ້າຫາໄດເຣັກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ບໍ?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"ອະນຸມັດໃຫ້ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ເຂົ້າເຖິງຂໍ້ມູນຂອງທ່ານ ເຊິ່ງຮວມເຖິງຮູບພາບ ແລະ ວິດີໂອໃນ <xliff:g id="STORAGE"><i>^2</i></xliff:g> ໄດ້ບໍ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"ບໍ່ຕ້ອງຖາມຄືນ"</string>
     <string name="allow" msgid="7225948811296386551">"ອະນຸຍາດ"</string>
     <string name="deny" msgid="2081879885755434506">"ປະ​ຕິ​ເສດ"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">ເລືອກ <xliff:g id="COUNT_1">%1$d</xliff:g> ແລ້ວ</item>
+      <item quantity="one">ເລືອກ <xliff:g id="COUNT_0">%1$d</xliff:g> ແລ້ວ</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ລຶບ \"<xliff:g id="NAME">%1$s</xliff:g>\" ອອກບໍ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ລຶບໂຟນເດີ \"<xliff:g id="NAME">%1$s</xliff:g>\" ແລະ ເນື້ອຫາທັງໝົດຂອງມັນອອກບໍ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
+      <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໂຟນເດີ ແລະ ເນື້ອຫາຂອງມັນອອກບໍ?</item>
+      <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໂຟນເດີ ແລະ ເນື້ອຫາຂອງມັນອອກບໍ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ລາຍການອອກບໍ?</item>
+      <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ລາຍການອອກບໍ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lt/config.xml b/packages/DocumentsUI/res/values-lt/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-lt/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 8de09ce..2e0df93 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Bendrinti naudojant"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopijuojami failai"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Perkeliami failai"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Failų ištrynimas"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Liko: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopijuojamas <xliff:g id="COUNT_1">%1$d</xliff:g> failas.</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"Pervardyti"</string>
     <string name="rename_error" msgid="4203041674883412606">"Nepavyko pervardyti dokumento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Kai kurie failai buvo konvertuoti"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Suteikti programai „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie duomenų, įskaitant nuotraukas ir vaizdo įrašus, <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Daugiau neklausti"</string>
     <string name="allow" msgid="7225948811296386551">"Leisti"</string>
     <string name="deny" msgid="2081879885755434506">"Atmesti"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Pasirinktas <xliff:g id="COUNT_1">%1$d</xliff:g> elementas</item>
+      <item quantity="few">Pasirinkti <xliff:g id="COUNT_1">%1$d</xliff:g> elementai</item>
+      <item quantity="many">Pasirinkta <xliff:g id="COUNT_1">%1$d</xliff:g> elemento</item>
+      <item quantity="other">Pasirinkta <xliff:g id="COUNT_1">%1$d</xliff:g> elementų</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ištrinti „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ištrinti aplanką „<xliff:g id="NAME">%1$s</xliff:g>“ ir jo turinį?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failą?</item>
+      <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+      <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo?</item>
+      <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplanką ir jų turinį?</item>
+      <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplankus ir jų turinį?</item>
+      <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplanko ir jų turinį?</item>
+      <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplankų ir jų turinį?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementą?</item>
+      <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementus?</item>
+      <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elemento?</item>
+      <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementų?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lv/config.xml b/packages/DocumentsUI/res/values-lv/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-lv/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 7711941..fb81aa0 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Notiek failu kopēšana"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Failu pārvietošana"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Notiek failu dzēšana"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Atlikušais laiks: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="zero">Notiek <xliff:g id="COUNT_1">%1$d</xliff:g> failu kopēšana.</item>
@@ -116,6 +117,32 @@
     <string name="menu_rename" msgid="7678802479104285353">"Pārdēvēt"</string>
     <string name="rename_error" msgid="4203041674883412606">"Neizdevās pārdēvēt dokumentu"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Daži faili tika pārveidoti."</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Vai atļaut lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļūt direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> šajā krātuvē: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vai piešķirt lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļuvi direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vai atļaut lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļūt jūsu datiem, tostarp fotoattēliem un videoklipiem, šajā krātuvē: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Turpmāk vairs nejautāt"</string>
     <string name="allow" msgid="7225948811296386551">"Atļaut"</string>
     <string name="deny" msgid="2081879885755434506">"Noraidīt"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="zero"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīts</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vai izdzēst failu “<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vai izdzēst mapi “<xliff:g id="NAME">%1$s</xliff:g>” un tās saturu?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+      <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu?</item>
+      <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapes un to saturu?</item>
+      <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapi un to saturu?</item>
+      <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapes un to saturu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumus?</item>
+      <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumu?</item>
+      <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumus?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/config.xml b/packages/DocumentsUI/res/values-mk-rMK/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-mk-rMK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 7798ea6..ad428a0 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Сподели преку"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Се копираат датотеки"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Датотеките се преместуваат"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Се бришат датотеките"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Уште <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Се копира <xliff:g id="COUNT_1">%1$d</xliff:g> датотека.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Преименувај"</string>
     <string name="rename_error" msgid="4203041674883412606">"Не успеа да се преименува документот"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некои датотеки беа конвертирани"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Да се овозможи пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до вашите податоци, вклучувајќи фотографии и видеа, на <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Не прашувај повторно"</string>
     <string name="allow" msgid="7225948811296386551">"Дозволи"</string>
     <string name="deny" msgid="2081879885755434506">"Одбиј"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> е избрана</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> се избрани</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Да се избрише „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Да се избрише папката „<xliff:g id="NAME">%1$s</xliff:g>“ и нејзините содржини?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+      <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> папка и нивните содржини?</item>
+      <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> папки и нивните содржини?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> ставка?</item>
+      <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> ставки?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/config.xml b/packages/DocumentsUI/res/values-ml-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ml-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index a9f9a46..5a16512 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"ഇതുവഴി പങ്കിടുക"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ഫയലുകൾ പകർത്തുന്നു"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ഫയലുകൾ നീക്കുന്നു"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ഫയലുകൾ ഇല്ലാതാക്കുന്നു"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ശേഷിക്കുന്നു"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ പകർത്തുന്നു.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"പേരുമാറ്റുക"</string>
     <string name="rename_error" msgid="4203041674883412606">"ഡോക്യുമെന്റിന്റെ പേരുമാറ്റുന്നത് പരാജയപ്പെട്ടു"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ചില ഫയലുകൾ പരിവർത്തനം ചെയ്യപ്പെട്ടു"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> സ്റ്റോറേജിലെ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്റ്ററിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്ടറിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> സ്റ്റോറേജിലെ ഫോട്ടോകളും വീഡിയോകളും ഉൾപ്പെടെ, നിങ്ങളുടെ ഡാറ്റയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ്സ് അനുവദിക്കണോ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"വീണ്ടും ആവശ്യപ്പെടരുത്"</string>
     <string name="allow" msgid="7225948811296386551">"അനുവദിക്കുക"</string>
     <string name="deny" msgid="2081879885755434506">"നിരസിക്കുക"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ഇല്ലാതാക്കണോ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" എന്ന ഫോൾഡറും അതിലെ ഉള്ളടങ്ങളും ഇല്ലാതാക്കണോ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ ഇല്ലാതാക്കണോ?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ ഇല്ലാതാക്കണോ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫോൾഡറുകളും അവയിലെ ഉള്ളടക്കങ്ങളും ഇല്ലാതാക്കണോ?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫോൾഡറും അതിലെ ഉള്ളടക്കങ്ങളും ഇല്ലാതാക്കണോ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഇനങ്ങൾ ഇല്ലാതാക്കണോ?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഇനം ഇല്ലാതാക്കണോ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/config.xml b/packages/DocumentsUI/res/values-mn-rMN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-mn-rMN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 0663588..cf2c2d4 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Дараахаар дамжуулан хуваалцах"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файлуудыг хуулж байна"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файлыг зөөвөрлөж байна"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Эдгээр файлыг устгаж байна"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> үлдсэн"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлуудыг хуулж байна.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Нэр өөрчлөх"</string>
     <string name="rename_error" msgid="4203041674883412606">"Баримт бичгийн нэрийн өөрчилж чадсангүй"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Зарим файлыг хөрвүүлсэн"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g>-д байгаа <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандахыг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д зөвшөөрөх үү?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандах эрхийг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д олгох уу?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>-д байгаа зураг, видео гэх мэт таны өгөгдөлд <xliff:g id="APPNAME"><b>^1</b></xliff:g> хандахыг зөвшөөрөх үү?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Дахин бүү асуу"</string>
     <string name="allow" msgid="7225948811296386551">"Зөвшөөрөх"</string>
     <string name="deny" msgid="2081879885755434506">"Татгалзах"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> сонгосон</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> сонгосон</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"-г устгах уу?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" фолдер болон үүний агуулгыг устгах уу?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлыг устгах уу?</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> файлыг устгах уу?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> фолдер болон агуулгуудыг нь устгах уу?</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> фолдер болон агуулгыг нь устгах уу?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> зүйлийг устгах уу?</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> зүйлийг устгах уу?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/config.xml b/packages/DocumentsUI/res/values-mr-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-mr-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index 82bb882..09dd133 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"द्वारे सामायिक करा"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"फायली कॉपी करीत आहे"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"फायली हलविणे"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"फायली हटवित आहे"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शिल्लक"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल कॉपी करीत आहे.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"पुनर्नामित करा"</string>
     <string name="rename_error" msgid="4203041674883412606">"दस्तऐवज पुनर्नामित करण्‍यात अयशस्वी झाले"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"काही फायली रूपांतरित केल्या होत्या"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> वर <xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकेवर प्रवेशाची मंजूरी द्यायची?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकमध्ये प्रवेश मंजूर करायचा?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="STORAGE"><i>^2</i></xliff:g> वर फोटो आणि व्हिडिओंसह, आपल्या डेटामध्ये प्रवेश करण्याची मंजूरी द्यायची?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"पुन्हा विचारू नका"</string>
     <string name="allow" msgid="7225948811296386551">"अनुमती द्या"</string>
     <string name="deny" msgid="2081879885755434506">"नकार द्या"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडला</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" हटवायची?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" फोल्डर आणि त्यामधील सामग्री हटवायची?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल हटवायची?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फायली हटवायच्या?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डर आणि त्यामधील सामग्री हटवायची?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डर आणि त्यामधील सामग्री हटवायची?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम हटवायचा?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम हटवायचे?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/config.xml b/packages/DocumentsUI/res/values-ms-rMY/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ms-rMY/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 64f6163..9eb3d49 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Menyalin fail"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Mengalihkan fail"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Memadamkan fail"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Namakan semula"</string>
     <string name="rename_error" msgid="4203041674883412606">"Gagal menamakan semula dokumen"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sesetengah fail telah ditukarkan"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada data anda, termasuk foto dan video pada <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Jangan tanya lagi"</string>
     <string name="allow" msgid="7225948811296386551">"Benarkan"</string>
     <string name="deny" msgid="2081879885755434506">"Nafi"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Padamkan \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Padamkan folder \"<xliff:g id="NAME">%1$s</xliff:g>\" dan kandungannya?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail?</item>
+      <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> folder dan kandungannya?</item>
+      <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> folder dan kandungannya?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+      <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/config.xml b/packages/DocumentsUI/res/values-my-rMM/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-my-rMM/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 2813f2d..7c637c4 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"မှ ဝေမျှပါ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ဖိုင်များကူယူနေသည်"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ဖိုင်များ ရွှေ့နေသည်"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ဖိုင်များကို ဖျက်နေသည်"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ကျန်ရှိသည်"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ဖိုင်များကို ကူးယူနေသည်။</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"အမည်ပြောင်းရန်"</string>
     <string name="rename_error" msgid="4203041674883412606">"စာရွက်စာတမ်းကို အမည်ပြောင်းခြင်း မအောင်မြင်ပါ"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"အချို့ဖိုင်များကို ပြောင်းလဲထားသည်"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ကို <xliff:g id="STORAGE"><i>^3</i></xliff:g> ရှိ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> လမ်းညွှန်အား အသုံးပြုခွင့်ပေးမလား။"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> အား <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> စာရင်းကို အသုံးပြုခွင့်ပေးမလား။"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> ရှိဓာတ်ပုံများနှင့် ဗီဒီယိုများအပါအဝင် သင့်ဒေတာများကို <xliff:g id="APPNAME"><b>^1</b></xliff:g> အားအသုံးပြုခွင့်ပေးမလား။"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"နောက်ထပ်မမေးပါနှင့်"</string>
     <string name="allow" msgid="7225948811296386551">"ခွင့်ပြုသည်"</string>
     <string name="deny" msgid="2081879885755434506">"ငြင်းပယ်သည်"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ခုရွေးချယ်ထားသည်</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ခုရွေးချယ်ထားသည်</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ကိုဖျက်မလား။"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ဖိုင်တွဲနှင့် ၎င်းတွင်ပါဝင်သည့် အကြောင်းအရာများကို ဖျက်မလား။"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">ဖိုင် <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+      <item quantity="one">ဖိုင် <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">ဖိုင်တွဲ <xliff:g id="COUNT_1">%1$d</xliff:g> ခုနှင့် ၎င်း၏အကြောင်းအရာများကို ဖျက်မလား။</item>
+      <item quantity="one">ဖိုင်တွဲ <xliff:g id="COUNT_0">%1$d</xliff:g> ခုနှင့် ၎င်း၏အကြောင်းအရာများကို ဖျက်မလား။</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">အကြောင်းအရာ <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+      <item quantity="one">အကြောင်းအရာ <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nb/config.xml b/packages/DocumentsUI/res/values-nb/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-nb/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index d79b279..3c344eb 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Sletter filene"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> gjenstår"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Gi nytt navn"</string>
     <string name="rename_error" msgid="4203041674883412606">"Kunne ikke gi dokumentet nytt navn"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Noen filer er konvertert"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til dataene dine – inkludert bilder og videoer – på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ikke spør igjen"</string>
     <string name="allow" msgid="7225948811296386551">"Tillat"</string>
     <string name="deny" msgid="2081879885755434506">"Avslå"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> er valgt</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vil du slette «<xliff:g id="NAME">%1$s</xliff:g>»?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vil du slette «<xliff:g id="NAME">%1$s</xliff:g>»-mappen og innholdet i den?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mapper og innholdet i dem?</item>
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> mappe og innholdet i den?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> elementer?</item>
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/config.xml b/packages/DocumentsUI/res/values-ne-rNP/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ne-rNP/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 057e03f..9fef037 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"माध्यमबाट साझेदारी गर्नुहोस्"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"फाइलहरू प्रतिलिपि गर्दै:"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"फाइलहरू सार्दै"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"फाइलहरूलाई मेट्दै"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g>बाँकी"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g>फाइलहरू प्रतिलिप गर्दै।</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"पुन: नामाकरण गर्नुहोस्"</string>
     <string name="rename_error" msgid="4203041674883412606">"कागजात पुन: नामाकरण गर्न असफल भयो"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"केही फाइलहरू परिवर्तन गरिएका थिए"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="STORAGE"><i>^3</i></xliff:g> मा भएको <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामा पहुँच गर्न अनुमति दिने हो?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामाथि पहुँच गर्न अनुमति प्रदान गर्ने हो?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="STORAGE"><i>^2</i></xliff:g> मा भएका तस्बिर र भिडियोहरू लगायत तपाईँको डेटामा पहुँच गर्नका लागि अनुमति दिने हो?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"फेरि नसोध्नुहोस्"</string>
     <string name="allow" msgid="7225948811296386551">"अनुमति दिनुहोस्"</string>
     <string name="deny" msgid="2081879885755434506">"अस्वीकार गर्नुहोस्"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> लाई चयन गरियो</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> लाई चयन गरियो</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" लाई मेट्ने हो?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"फोल्डर \"<xliff:g id="NAME">%1$s</xliff:g>\" र यसका सामग्रीहरूलाई मेट्ने हो?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फाइलहरूलाई मेट्ने हो?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फाइललाई मेट्ने हो?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डरहरू र तिनीहरूका सामग्रीहरूलाई मेट्ने हो?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फोल्डर र यसका सामग्रीहरूलाई मेट्ने हो?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> वस्तुहरूलाई मेट्ने हो?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> वस्तुलाई मेट्ने हो?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nl/config.xml b/packages/DocumentsUI/res/values-nl/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-nl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 99a9f91..c5b9d76 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Delen via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Bestanden kopiëren"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Bestanden verplaatsen"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Bestanden verwijderen"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> resterend"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden kopiëren.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Naam wijzigen"</string>
     <string name="rename_error" msgid="4203041674883412606">"Kan naam van document niet wijzigen"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige bestanden zijn geconverteerd"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot je gegevens, waaronder foto\'s en video\'s, op <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Niet meer vragen"</string>
     <string name="allow" msgid="7225948811296386551">"Toestaan"</string>
     <string name="deny" msgid="2081879885755434506">"Weigeren"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> geselecteerd</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> geselecteerd</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"<xliff:g id="NAME">%1$s</xliff:g> verwijderen?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Map <xliff:g id="NAME">%1$s</xliff:g> en de bijbehorende inhoud verwijderen?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden verwijderen?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> bestand verwijderen?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> mappen en de bijbehorende inhoud verwijderen?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> map en de bijbehorende inhoud verwijderen?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> items verwijderen?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> item verwijderen?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/config.xml b/packages/DocumentsUI/res/values-pa-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-pa-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 758a4d8..7d5e14a 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"ਇਸ ਰਾਹੀਂ ਸ਼ੇਅਰ ਕਰੋ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ਫਾਈਲਾਂ ਕਾਪੀ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ਫ਼ਾਈਲਾਂ ਨੂੰ ਮੂਵ ਕਰ ਰਿਹਾ ਹੈ"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ਬਾਕੀ"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ਫਾਈਲਾਂ ਕਾਪੀ ਕਰ ਰਿਹਾ ਹੈ।</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"ਮੁੜ-ਨਾਮਕਰਨ ਕਰੋ"</string>
     <string name="rename_error" msgid="4203041674883412606">"ਦਸਤਾਵੇਜ਼ ਦਾ ਮੁੜ-ਨਾਮਕਰਨ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ਕੁਝ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="STORAGE"><i>^3</i></xliff:g> \'ਤੇ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="STORAGE"><i>^2</i></xliff:g> \'ਤੇ ਫੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਸਮੇਤ, ਤੁਹਾਡੇ ਡੈਟੇ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"ਦੁਬਾਰਾ ਨਾ ਪੁੱਛੋ"</string>
     <string name="allow" msgid="7225948811296386551">"ਆਗਿਆ ਦਿਓ"</string>
     <string name="deny" msgid="2081879885755434506">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀ ਗਈ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀਆਂ ਗਈਆਂ</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ਕੀ \"<xliff:g id="NAME">%1$s</xliff:g>\" ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ਫੋਲਡਰ \"<xliff:g id="NAME">%1$s</xliff:g>\" ਅਤੇ ਉਸ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+      <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫੋਲਡਰਾਂ ਅਤੇ ਉਹਨਾਂ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+      <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫੋਲਡਰਾਂ ਅਤੇ ਉਹਨਾਂ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+      <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pl/config.xml b/packages/DocumentsUI/res/values-pl/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-pl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 8a4d17c..ca007d7 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Udostępnij przez:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiowanie plików"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Przenoszenie plików"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Usuwam pliki"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Pozostało: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Kopiowanie <xliff:g id="COUNT_1">%1$d</xliff:g> plików.</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"Zmień nazwę"</string>
     <string name="rename_error" msgid="4203041674883412606">"Nie udało się zmienić nazwy dokumentu"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektóre pliki zostały przekonwertowane"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Zezwolić aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> na dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> w pamięci masowej <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Przyznać aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Zezwolić aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> na dostęp do Twoich danych, w tym zdjęć i filmów, zapisanych w pamięci <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Nie pytaj ponownie"</string>
     <string name="allow" msgid="7225948811296386551">"Zezwól"</string>
     <string name="deny" msgid="2081879885755434506">"Odmów"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="few">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="many">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Wybrano <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Usunąć „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Usunąć folder „<xliff:g id="NAME">%1$s</xliff:g>” i jego zawartość?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliki?</item>
+      <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików?</item>
+      <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku?</item>
+      <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> plik?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> foldery wraz z zawartością?</item>
+      <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> folderów wraz z zawartością?</item>
+      <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> folderu wraz z zawartością?</item>
+      <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> folder wraz z zawartością?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementy?</item>
+      <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementów?</item>
+      <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementu?</item>
+      <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/config.xml b/packages/DocumentsUI/res/values-pt-rBR/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-pt-rBR/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 391a053..21359c7 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Excluindo arquivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Renomear"</string>
     <string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no/na <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Negar"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Excluir \" <xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Excluir pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e o respectivo conteúdo?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/config.xml b/packages/DocumentsUI/res/values-pt-rPT/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-pt-rPT/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 448ddfe..aea1249 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"A copiar ficheiros"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"A mover ficheiros"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminar ficheiros"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Faltam <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">A copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Mudar o nome"</string>
     <string name="rename_error" msgid="4203041674883412606">"Falha ao mudar o nome do documento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns ficheiros foram convertidos"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no(a) <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no(a) <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Recusar"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Pretende eliminar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Pretende eliminar a pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e os respetivos conteúdos?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e os respetivos conteúdos?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> pasta e os respetivos conteúdos?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt/config.xml b/packages/DocumentsUI/res/values-pt/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-pt/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 391a053..21359c7 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Excluindo arquivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Renomear"</string>
     <string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no/na <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Negar"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Excluir \" <xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Excluir pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e o respectivo conteúdo?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ro/config.xml b/packages/DocumentsUI/res/values-ro/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ro/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 565a4e9..4b833b1 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Trimiteți prin"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Se copiază fișierele"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Se mută fișierele"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Se șterg fișierele"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Timp rămas: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Se copiază <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere.</item>
@@ -116,6 +117,32 @@
     <string name="menu_rename" msgid="7678802479104285353">"Redenumiți"</string>
     <string name="rename_error" msgid="4203041674883412606">"Documentul nu a putut fi redenumit"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Unele fișiere au fost convertite"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> accesul la directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de pe <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> să acceseze directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> să vă acceseze datele, inclusiv fotografiile și videoclipurile, de pe <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Nu mai întreba"</string>
     <string name="allow" msgid="7225948811296386551">"Permiteți"</string>
-    <string name="deny" msgid="2081879885755434506">"Refuzaţi"</string>
+    <string name="deny" msgid="2081879885755434506">"Refuzați"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> selectate</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selectate</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selectat</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ștergeți „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ștergeți dosarul „<xliff:g id="NAME">%1$s</xliff:g>” și conținutul acestuia?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere?</item>
+      <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere?</item>
+      <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> fișier?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> dosare și conținutul acestora?</item>
+      <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de dosare și conținutul acestora?</item>
+      <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> dosar și conținutul acestuia?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> elemente?</item>
+      <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de elemente?</item>
+      <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ru/config.xml b/packages/DocumentsUI/res/values-ru/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ru/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index ec97840..6ba635d 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Поделиться"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Копирование файлов"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Перемещение файлов"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Удаление файлов…"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Осталось <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файл...</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"Переименовать"</string>
     <string name="rename_error" msgid="4203041674883412606">"Не удалось переименовать документ"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Формат некоторых файлов изменен"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" на устройстве \"<xliff:g id="STORAGE"><i>^3</i></xliff:g>\"?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к вашим данным, включая фото и видео, на носителе: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Больше не спрашивать"</string>
     <string name="allow" msgid="7225948811296386551">"Разрешить"</string>
     <string name="deny" msgid="2081879885755434506">"Отклонить"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="few">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="many">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Удалить файл \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Удалить папку \"<xliff:g id="NAME">%1$s</xliff:g>\" со всем содержимым?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+      <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов?</item>
+      <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папку со всем содержимым?</item>
+      <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папки со всем содержимым?</item>
+      <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папок со всем содержимым?</item>
+      <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папки со всем содержимым?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объект?</item>
+      <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объекта?</item>
+      <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объектов?</item>
+      <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объекта?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/config.xml b/packages/DocumentsUI/res/values-si-rLK/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-si-rLK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index fdfabe2..41c9d4a 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"හරහා බෙදාගන්න"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ගොනු පිටපත් කරමින්"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ගොනු ගෙන යාම"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ගොනු මකමින්"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ඉතිරියි"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් පිටපත් කරමින්.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"යළි නම් කරන්න"</string>
     <string name="rename_error" msgid="4203041674883412606">"ලේඛනය යළි නම් කිරීම අසාර්ථක විය"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"සමහර ගොනු පරිවර්තනය කරන ලදී"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> හට <xliff:g id="STORAGE"><i>^3</i></xliff:g> මත <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ප්‍රවේශය දෙන්නද?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ප්‍රවේශය <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ලබා දෙන්නද?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> හි, ඡායාරූප සහ වීඩියෝ ඇතුළුව, ඔබේ දත්තවලට <xliff:g id="APPNAME"><b>^1</b></xliff:g> හට ප්‍රවේශය ලබා දෙන්නද?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"නැවත අසන්න එපා"</string>
     <string name="allow" msgid="7225948811296386551">"අවසර දෙන්න"</string>
     <string name="deny" msgid="2081879885755434506">"ප්‍රතික්ෂේප කරන්න"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>ක් තෝරන ලදී</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ක් තෝරන ලදී</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" මකන්නද?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ෆෝල්ඩරය හා එහි අන්තර්ගත මකන්නද?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+      <item quantity="other">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">ෆෝල්ඩර <xliff:g id="COUNT_1">%1$d</xliff:g> ක් හා එහි අන්තර්ගත මකන්නද?</item>
+      <item quantity="other">ෆෝල්ඩර <xliff:g id="COUNT_1">%1$d</xliff:g> ක් හා එහි අන්තර්ගත මකන්නද?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+      <item quantity="other">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sk/config.xml b/packages/DocumentsUI/res/values-sk/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-sk/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 4d29021..1ff01b0 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Zdieľať"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopírovanie súborov"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Presúvajú sa súbory"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Odstraňujú sa súbory"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Zostáva: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Kopírujú sa <xliff:g id="COUNT_1">%1$d</xliff:g> súbory.</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"Premenovať"</string>
     <string name="rename_error" msgid="4203041674883412606">"Premenovanie dokumentu zlyhalo"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektoré súbory boli konvertované"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložisku <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Chcete aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> udeliť prístup k dátam (vrátane fotiek a videí) v úložisku <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Nabudúce sa nepýtať"</string>
     <string name="allow" msgid="7225948811296386551">"Povoliť"</string>
     <string name="deny" msgid="2081879885755434506">"Zamietnuť"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="few">Vybraté: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="many">Vybraté: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Vybraté: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Vybraté: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Odstrániť <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Odstrániť priečinok <xliff:g id="NAME">%1$s</xliff:g> a jeho obsah?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory?</item>
+      <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru?</item>
+      <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov?</item>
+      <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinky a ich obsah?</item>
+      <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinka a jeho obsah?</item>
+      <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinkov a ich obsah?</item>
+      <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> priečinok a jeho obsah?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položiek?</item>
+      <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> položku?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sl/config.xml b/packages/DocumentsUI/res/values-sl/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-sl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index dc17a08..d8b983c 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Deli z drugimi prek"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datotek"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Premikanje datotek"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Brisanje datotek"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Še <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
     <string name="rename_error" msgid="4203041674883412606">"Dokumenta ni bilo mogoče preimenovati"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nekatere datoteke so bile pretvorjene"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v shrambi <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Odobrite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dostop do podatkov, vključno s fotografijami in videoposnetki, v shrambi <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ne sprašuj več"</string>
     <string name="allow" msgid="7225948811296386551">"Dovoli"</string>
     <string name="deny" msgid="2081879885755434506">"Zavrni"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> izbran</item>
+      <item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> izbrana</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> izbrani</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> izbranih</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ali želite izbrisati »<xliff:g id="NAME">%1$s</xliff:g>«?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ali želite izbrisati mapo »<xliff:g id="NAME">%1$s</xliff:g>« in njeno vsebino?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteko?</item>
+      <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteki?</item>
+      <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+      <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datotek?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapo in njihovo vsebino?</item>
+      <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapi in njihovo vsebino?</item>
+      <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mape in njihovo vsebino?</item>
+      <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> map in njihovo vsebino?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> element?</item>
+      <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elementa?</item>
+      <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elemente?</item>
+      <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elementov?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/config.xml b/packages/DocumentsUI/res/values-sq-rAL/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-sq-rAL/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 5ae1f2a..933a537 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Shpërnda publikisht përmes"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Po kopjon skedarët"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Po zhvendos skedarët"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Po fshin skedarët"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> të mbetura"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Po kopjon <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Riemërto"</string>
     <string name="rename_error" msgid="4203041674883412606">"Riemërtimi i dokumentit dështoi"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Disa skedarë u konvertuan"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Jepi aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> në <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"T\'i jepet aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"T\'i jepet aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te të dhënat, duke përfshirë fotografitë dhe videot, në <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Mos pyet përsëri"</string>
     <string name="allow" msgid="7225948811296386551">"Lejo"</string>
     <string name="deny" msgid="2081879885755434506">"Moho"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> të zgjedhur</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> i zgjedhur</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Të fshihet \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Të fshihet dosja \"<xliff:g id="NAME">%1$s</xliff:g>\" dhe përmbajtja e saj?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë?</item>
+      <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> skedar?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> dosje dhe përmbajtjet e saj?</item>
+      <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> dosje dhe përmbajtjet e saj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> artikuj?</item>
+      <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> artikull?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sr/config.xml b/packages/DocumentsUI/res/values-sr/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-sr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index e207c2e..0505f42 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Делите преко"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Копирање датотека"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Датотеке се премештају"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Датотеке се бришу"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Још <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке.</item>
@@ -116,6 +117,32 @@
     <string name="menu_rename" msgid="7678802479104285353">"Преименуј"</string>
     <string name="rename_error" msgid="4203041674883412606">"Преименовање документа није успело"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Неке датотеке су конвертоване"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Желите ли да апликацији <xliff:g id="APPNAME"><b>^1</b></xliff:g> одобрите приступ директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на меморијском простору <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Желите да дозволите да <xliff:g id="APPNAME"><b>^1</b></xliff:g> приступа директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Желите да ли да дозволите да апликација <xliff:g id="APPNAME"><b>^1</b></xliff:g> приступа подацима, укључујући слике и видео снимке, на локацији <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Не питај поново"</string>
     <string name="allow" msgid="7225948811296386551">"Дозволи"</string>
     <string name="deny" msgid="2081879885755434506">"Одбиј"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Изабрана је <xliff:g id="COUNT_1">%1$d</xliff:g> ставка</item>
+      <item quantity="few">Изабране су <xliff:g id="COUNT_1">%1$d</xliff:g> ставке</item>
+      <item quantity="other">Изабрано је <xliff:g id="COUNT_1">%1$d</xliff:g> ставки</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Желите ли да избришете „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Желите ли да избришете директоријум „<xliff:g id="NAME">%1$s</xliff:g>“ и његов садржај?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку?</item>
+      <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке?</item>
+      <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријум и њихов садржај?</item>
+      <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријума и њихов садржај?</item>
+      <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријума и њихов садржај?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставку?</item>
+      <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставке?</item>
+      <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставки?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sv/config.xml b/packages/DocumentsUI/res/values-sv/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-sv/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index dfc42a3..99f334b 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Dela via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopierar filer"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Filer flyttas"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Filerna tas bort"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> återstår"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopierar <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Byt namn"</string>
     <string name="rename_error" msgid="4203041674883412606">"Det gick inte att byta namn på dokumentet"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Vissa filer konverterades"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till din data (inklusive foton och videor) på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Fråga inte igen"</string>
     <string name="allow" msgid="7225948811296386551">"Tillåt"</string>
     <string name="deny" msgid="2081879885755434506">"Neka"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> har valts</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> har valts</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vill du radera <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vill du radera mappen <xliff:g id="NAME">%1$s</xliff:g> och dess innehåll?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+      <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g>  mappar och deras innehåll?</item>
+      <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> mapp och dess innehåll?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g> objekt?</item>
+      <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> objekt?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw/config.xml b/packages/DocumentsUI/res/values-sw/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-sw/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index cbdb44c..566e6a4 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Shiriki kupitia"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Inanakili faili"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Inahamisha faili"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Inafuta faili"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Zimesalia <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Inanakili faili <xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Badilisha jina"</string>
     <string name="rename_error" msgid="4203041674883412606">"Imeshindwa kubadilisha jina la hati"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Baadhi ya faili zimebadilishwa muundo"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kwenye <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie data yako, ikiwa ni pamoja na picha na video kwenye <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Usiniulize tena"</string>
     <string name="allow" msgid="7225948811296386551">"Ruhusu"</string>
     <string name="deny" msgid="2081879885755434506">"Kataza"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">Imechagua <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Imechagua <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ungependa kufuta \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ungependa kufuta folda ya \"<xliff:g id="NAME">%1$s</xliff:g>\" na maudhui yake?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Ungependa kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="one">Ungependa kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Ungependa kufuta folda <xliff:g id="COUNT_1">%1$d</xliff:g> na maudhui yaliyomo?</item>
+      <item quantity="one">Ungependa kufuta folda <xliff:g id="COUNT_0">%1$d</xliff:g> na maudhui yaliyomo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Ungependa kufuta vipengee <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="one">Ungependa kufuta kipengee <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/config.xml b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
index 8d9526d..6893d7a 100644
--- a/packages/DocumentsUI/res/values-sw720dp-land/config.xml
+++ b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
@@ -15,5 +15,4 @@
 -->
 
 <resources>
-    <bool name="always_show_summary">true</bool>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
index fa11244..1b67ee5 100644
--- a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
@@ -20,4 +20,5 @@
 
     <dimen name="list_divider_inset">80dp</dimen>
 
+    <dimen name="max_drawer_width">320dp</dimen>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/colors.xml b/packages/DocumentsUI/res/values-sw720dp/colors.xml
new file mode 100644
index 0000000..3ecafe2
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <color name="menu_search_background">#ff676f74</color>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/config.xml b/packages/DocumentsUI/res/values-sw720dp/config.xml
new file mode 100644
index 0000000..4898e74
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <!-- Indicates if search view is taking the whole toolbar space -->
+    <bool name="full_bar_search_view">false</bool>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
index 2488fa2..982b204 100644
--- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -18,4 +18,7 @@
     <dimen name="grid_padding_horiz">16dp</dimen>
     <dimen name="grid_padding_vert">16dp</dimen>
 
+    <dimen name="list_item_padding">24dp</dimen>
+
+    <dimen name="max_drawer_width">320dp</dimen>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/config.xml b/packages/DocumentsUI/res/values-ta-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ta-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 3f85a17..9a8b4ec 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"இதன் வழியாகப் பகிர்"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"கோப்புகளை நகலெடுத்தல்"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"கோப்புகளை நகர்த்துதல்"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"கோப்புகளை நீக்குகிறது"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> மீதமுள்ளது"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நகலெடுக்கிறது.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"மறுபெயரிடு"</string>
     <string name="rename_error" msgid="4203041674883412606">"ஆவணத்திற்கு மறுபெயரிடுவதில் தோல்வி"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"சில கோப்புகள் மாற்றப்பட்டன"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> இல் உள்ள <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக, <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> இல் உள்ள படங்கள், வீடியோக்கள் உட்பட எல்லா தரவையும் அணுக, <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"மீண்டும் கேட்காதே"</string>
     <string name="allow" msgid="7225948811296386551">"அனுமதி"</string>
     <string name="deny" msgid="2081879885755434506">"நிராகரி"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டன</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டது</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"ஐ நீக்கவா?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" கோப்புறையையும் அதன் உள்ளடக்கத்தையும் நீக்கவா?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நீக்கவா?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்கவா?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புறைகளையும் அவற்றின் உள்ளடக்கத்தையும் நீக்கவா?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்புறையையும் அதன் உள்ளடக்கத்தையும் நீக்கவா?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> உருப்படிகளை நீக்கவா?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> உருப்படியை நீக்கவா?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/config.xml b/packages/DocumentsUI/res/values-te-rIN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-te-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 07a7e6d..224d0db 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"దీని ద్వారా భాగస్వామ్యం చేయండి"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ఫైల్‌లు కాపీ అవుతున్నాయి"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ఫైల్‌లను తరలిస్తోంది"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"ఫైల్‌లను తొలగిస్తోంది"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> మిగిలి ఉంది"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్‌లను కాపీ చేస్తోంది.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"పేరు మార్చు"</string>
     <string name="rename_error" msgid="4203041674883412606">"పత్రం పేరు మార్చడంలో విఫలమైంది"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"కొన్ని పైల్‌లు మార్చబడ్డాయి"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="STORAGE"><i>^3</i></xliff:g>లో <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>లో ఫోటోలు మరియు వీడియోలతో సహా మీ డేటా ప్రాప్యతను <xliff:g id="APPNAME"><b>^1</b></xliff:g>కి మంజూరు చేయాలా?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"మళ్లీ అడగవద్దు"</string>
     <string name="allow" msgid="7225948811296386551">"అనుమతించండి"</string>
     <string name="deny" msgid="2081879885755434506">"తిరస్కరించండి"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఎంచుకోబడ్డాయి</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"ని తొలగించాలా?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ఫోల్డర్‌ని మరియు అందులోని కంటెంట్‌లను తొలగించాలా?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్‌లను తొలగించాలా?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్‌ను తొలగించాలా?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫోల్డర్‌లు మరియు వీటిలోని కంటెంట్‌లను తొలగించాలా?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫోల్డర్ మరియు దీనిలోని కంటెంట్‌లను తొలగించాలా?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> అంశాలను తొలగించాలా?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> అంశాన్ని తొలగించాలా?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-th/config.xml b/packages/DocumentsUI/res/values-th/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-th/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 8562ef65..af07584 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"แชร์ผ่าน"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"กำลังคัดลอกไฟล์"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"กำลังย้ายไฟล์"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"กำลังลบไฟล์"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"เหลือ <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">กำลังคัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"เปลี่ยนชื่อ"</string>
     <string name="rename_error" msgid="4203041674883412606">"ไม่สามารถเปลี่ยนชื่อเอกสาร"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"แปลงบางไฟล์แล้ว"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ในการเข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ใน <xliff:g id="STORAGE"><i>^3</i></xliff:g> ไหม"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> เข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ไหม"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> เข้าถึงข้อมูลของคุณ รวมถึงรูปภาพและวิดีโอใน <xliff:g id="STORAGE"><i>^2</i></xliff:g> ไหม"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"ไม่ต้องถามอีก"</string>
     <string name="allow" msgid="7225948811296386551">"อนุญาต"</string>
     <string name="deny" msgid="2081879885755434506">"ปฏิเสธ"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">เลือกไว้ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item>
+      <item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ลบ \"<xliff:g id="NAME">%1$s</xliff:g>\" ไหม"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ลบโฟลเดอร์ \"<xliff:g id="NAME">%1$s</xliff:g>\" และเนื้อหาข้างในไหม"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+      <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> โฟลเดอร์และเนื้อหาข้างในใช่ไหม</item>
+      <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> โฟลเดอร์และเนื้อหาข้างในใช่ไหม</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการใช่ไหม</item>
+      <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการใช่ไหม</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tl/config.xml b/packages/DocumentsUI/res/values-tl/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-tl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index de0c9bd..b2acf05 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kinokopya ang mga file"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Inililipat ang mga file"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Pagde-delete ng mga file"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> na lang ang natitira"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kumokopya ng <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Palitan ang pangalan"</string>
     <string name="rename_error" msgid="4203041674883412606">"Hindi napalitan ang pangalan ng dokumento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Na-convert ang ilang file"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Bigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa directory ng <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Bibigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa direktoryong <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Bigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa iyong data, kabilang ang mga larawan at video, sa <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Huwag nang tatanunging muli"</string>
     <string name="allow" msgid="7225948811296386551">"Payagan"</string>
     <string name="deny" msgid="2081879885755434506">"Tanggihan"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Gusto mo bang i-delete ang \"<xliff:g id="NAME">%1$s</xliff:g>?\""</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Gusto mo bang i-delete ang folder na \"<xliff:g id="NAME">%1$s</xliff:g>\" at ang mga content nito?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> (na) file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> folder at mga content ng mga ito?</item>
+      <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na folder at mga content ng mga ito?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+      <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tr/config.xml b/packages/DocumentsUI/res/values-tr/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-tr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index c9245c6..c5653c9 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Dosyalar kopyalanıyor"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Dosyalar taşınıyor"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Dosyalar siliniyor"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> kaldı"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanıyor.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Yeniden Adlandır"</string>
     <string name="rename_error" msgid="4203041674883412606">"Dokümanın adı değiştirilemedi"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bazı dosyalar dönüştürüldü"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına <xliff:g id="STORAGE"><i>^3</i></xliff:g> depolama alanındaki <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişim izni verilsin mi?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişmek için <xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına izin verilsin mi?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasının, fotoğraflar ve videolar dahil olmak üzere <xliff:g id="STORAGE"><i>^2</i></xliff:g> üzerindeki verilerinize erişmesine izin verilsin mi?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Tekrar sorma"</string>
     <string name="allow" msgid="7225948811296386551">"İzin Ver"</string>
     <string name="deny" msgid="2081879885755434506">"Reddet"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe seçildi</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe seçildi</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" silinsin mi?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" adlı klasör ve içindekiler silinsin mi?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinsin mi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinsin mi?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> klasör ve içindekiler silinsin mi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> klasör ve içindekiler silinsin mi?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe silinsin mi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe silinsin mi?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uk/config.xml b/packages/DocumentsUI/res/values-uk/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-uk/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 5f2b99c..21532b6 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Надіслати через"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Копіювання файлів"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Переміщення файлів"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Видалення файлів"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Залишилося <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлу.</item>
@@ -123,6 +124,36 @@
     <string name="menu_rename" msgid="7678802479104285353">"Перейменувати"</string>
     <string name="rename_error" msgid="4203041674883412606">"Не вдалося перейменувати документ"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Деякі файли конвертовано"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на пристрої пам’яті <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до ваших даних, зокрема до фотографій і відео, які містить <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Не запитувати знову"</string>
     <string name="allow" msgid="7225948811296386551">"Дозвол."</string>
     <string name="deny" msgid="2081879885755434506">"Забор."</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="few">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="many">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Видалити файл <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Видалити папку \"<xliff:g id="NAME">%1$s</xliff:g>\" та її вміст?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файли?</item>
+      <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлів?</item>
+      <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлу?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папку та їх вміст?</item>
+      <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папки та їх вміст?</item>
+      <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папок та їх вміст?</item>
+      <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папки та їх вміст?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елемент?</item>
+      <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елементи?</item>
+      <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елементів?</item>
+      <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елемента?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/config.xml b/packages/DocumentsUI/res/values-ur-rPK/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-ur-rPK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 40831eb..eb0cfc8 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"اشتراک کریں بذریعہ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"فائلیں کاپی ہو رہی ہیں"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"فائلیں منتقل ہو رہی ہیں"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"فائلیں حذف کی جا رہی ہیں"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی ہے"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں کاپی کی جا رہی ہیں۔</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"نام تبدیل کریں"</string>
     <string name="rename_error" msgid="4203041674883412606">"دستاویز کا نام تبدیل کرنے میں ناکام"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"کچھ فائلوں کو تبدیل کیا گیا تھا"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="STORAGE"><i>^3</i></xliff:g> پر <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی عطا کریں؟"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی دیں؟"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو اپنے ڈیٹا بشمول <xliff:g id="STORAGE"><i>^2</i></xliff:g> پر موجود تصاویر اور ویڈیوز تک رسائی عطا کریں؟"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"دوبارہ نہ پوچھیں"</string>
     <string name="allow" msgid="7225948811296386551">"اجازت دیں"</string>
     <string name="deny" msgid="2081879885755434506">"مسترد کریں"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> منتخب کردہ</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> منتخب کردہ</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" حذف کریں؟"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" فولڈر اور اس کی مشمولات حذف کریں؟"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف کریں؟</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف کریں؟</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فولڈرز اور ان کے مشمولات حذف کریں؟</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فولڈر اور اس کے مشمولات حذف کریں؟</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> آئٹمز حذف کریں؟</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> آئٹم حذف کریں؟</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/config.xml b/packages/DocumentsUI/res/values-uz-rUZ/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-uz-rUZ/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index 48fa9a6..2654308 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Quyidagi orqali ulashish"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Fayllar nusxalanmoqda"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Ko‘chirib o‘tkazilmoqda"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Fayllar o‘chirilmoqda"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> qoldi"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl nusxalanmoqda</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Qayta nomlash"</string>
     <string name="rename_error" msgid="4203041674883412606">"Hujjatni qayta nomlab bo‘lmadi"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^3</i></xliff:g> xotirasidagi “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^2</i></xliff:g> xotirasidagi ma’lumotlardan, jumladan, rasmlar va videolardan foydalanishiga ruxsat berilsinmi?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Boshqa so‘ralmasin"</string>
     <string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
     <string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta belgilandi</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta belgilandi</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"“<xliff:g id="NAME">%1$s</xliff:g>” fayli o‘chirib tashlansinmi?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"“<xliff:g id="NAME">%1$s</xliff:g>” jildi ichidagi kontentlari bilan o‘chirib tashlansinmi?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl o‘chirilsinmi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl o‘chirib tashlansinmi?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta jild ichidagi kontentlari bilan o‘chirib tashlansinmi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta jild ichidagi kontentlari bilan o‘chirib tashlansinmi?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta element o‘chirib tashlansinmi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta element o‘chirib tashlansinmi?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-vi/config.xml b/packages/DocumentsUI/res/values-vi/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-vi/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 66a5b73..9af7db0 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Chia sẻ qua"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Đang sao chép tệp"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Đang di chuyển tệp"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Đang xóa tệp"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Còn <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Đang sao chép <xliff:g id="COUNT_1">%1$d</xliff:g> tệp.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Đổi tên"</string>
     <string name="rename_error" msgid="4203041674883412606">"Không đổi được tên tài liệu"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Đã chuyển đổi một số tệp"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập vào thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> trong <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập vào dữ liệu của bạn, kể cả ảnh và video trên <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Không hỏi lại"</string>
     <string name="allow" msgid="7225948811296386551">"Cho phép"</string>
     <string name="deny" msgid="2081879885755434506">"Từ chối"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">Đã chọn <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Đã chọn <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Xóa \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Xóa thư mục \"<xliff:g id="NAME">%1$s</xliff:g>\" và nội dung của thư mục?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp?</item>
+      <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> thư mục và nội dung trong đó?</item>
+      <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> thư mục và nội dung trong đó?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> mục?</item>
+      <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> mục?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/config.xml b/packages/DocumentsUI/res/values-zh-rCN/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-zh-rCN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index bb48b0c..e3db1a0 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"分享方式"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"正在复制文件"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"正在移动文件"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"正在删除文件"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"剩余时间:<xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">正在复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"重命名"</string>
     <string name="rename_error" msgid="4203041674883412606">"无法重命名文档"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分文件已转换成其他格式"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的“<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>”目录吗?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>目录吗?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问您 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的数据(包括照片和视频)吗?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"不再询问"</string>
     <string name="allow" msgid="7225948811296386551">"允许"</string>
     <string name="deny" msgid="2081879885755434506">"拒绝"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">已选择 <xliff:g id="COUNT_1">%1$d</xliff:g> 项</item>
+      <item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要删除“<xliff:g id="NAME">%1$s</xliff:g>”吗?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要删除文件夹“<xliff:g id="NAME">%1$s</xliff:g>”及其中的内容吗?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件?</item>
+      <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件夹及其中的内容?</item>
+      <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件夹及其中的内容?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 项?</item>
+      <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 项?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/config.xml b/packages/DocumentsUI/res/values-zh-rHK/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-zh-rHK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index f8d46d5..f13a4bd1 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"正在複製檔案"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"正在刪除檔案"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"重新命名"</string>
     <string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄存取權嗎?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄的存取權嗎?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"要向「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的相片和影片等資料的存取權嗎?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"不要再詢問"</string>
     <string name="allow" msgid="7225948811296386551">"允許"</string>
     <string name="deny" msgid="2081879885755434506">"拒絕"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
+      <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」資料夾及其內容嗎?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個資料夾及其內容嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個資料夾及其內容嗎?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目嗎?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/config.xml b/packages/DocumentsUI/res/values-zh-rTW/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-zh-rTW/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index ad77ad4..f8f8282 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"複製檔案"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"正在刪除檔案"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"重新命名"</string>
     <string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"要允許「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」存取 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的資料 (包括相片和影片) 嗎?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"不要再詢問"</string>
     <string name="allow" msgid="7225948811296386551">"允許"</string>
     <string name="deny" msgid="2081879885755434506">"拒絕"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
+      <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」資料夾和當中的內容嗎?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個資料夾和當中的內容嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個資料夾和當中的內容嗎?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目嗎?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zu/config.xml b/packages/DocumentsUI/res/values-zu/config.xml
deleted file mode 100644
index 843a8aa..0000000
--- a/packages/DocumentsUI/res/values-zu/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index c49500c..a0b9f7f 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -67,6 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Ikopisha amafayela"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Ihambisa amafayela"</string>
+    <string name="delete_notification_title" msgid="3329403967712437496">"Ukususa amafayela"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> okusele"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Ikopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
@@ -109,6 +110,28 @@
     <string name="menu_rename" msgid="7678802479104285353">"Qamba kabusha"</string>
     <string name="rename_error" msgid="4203041674883412606">"Yehlulekile ukuqamba kabusha idokhumenti"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Amanye amafayela aguqulelwe"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"Nika i-<xliff:g id="APPNAME"><b>^1</b></xliff:g> ukufinyelela ekuqondiseni kwe-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ku-<xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Nika ukufinyelela kwe-<xliff:g id="APPNAME"><b>^1</b></xliff:g> kwinkomba ye-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Nikeza i-<xliff:g id="APPNAME"><b>^1</b></xliff:g> ukufinyelela kudatha yakho, okufaka izithombe namavidiyo, ku-<xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="4295278542972859268">"Ungaphindi ubuze"</string>
     <string name="allow" msgid="7225948811296386551">"Vumela"</string>
     <string name="deny" msgid="2081879885755434506">"Yala"</string>
+    <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Susa i-\"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Susa ifolda engu-\"<xliff:g id="NAME">%1$s</xliff:g>\" nokuqukethwe kwalo?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Susa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="other">Susa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Susa amafolda angu-<xliff:g id="COUNT_1">%1$d</xliff:g> nokuqukethwe kwawo?</item>
+      <item quantity="other">Susa amafolda angu-<xliff:g id="COUNT_1">%1$d</xliff:g> nokuqukethwe kwawo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Susa izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="other">Susa izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 3785adf..1660e26 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -16,6 +16,7 @@
 
 <resources>
     <color name="material_grey_400">#ffbdbdbd</color>
+    <color name="material_teal_700">#ff00796b</color>
 
     <!-- This is the window background, but also the background for anything
          else that needs to manually declare a background matching the "default"
@@ -23,9 +24,7 @@
     <color name="window_background">#fff1f1f1</color>
     <color name="drawer_background">#fff1f1f1</color>
     <color name="directory_background">#fff7f7f7</color>
-    <color name="item_doc_background">#fffafafa</color>
-    <color name="item_doc_background_selected">#ffe0f2f1</color>
-    <color name="menu_search_background">#ff676f74</color>
+    <color name="menu_search_background">@android:color/transparent</color>
 
     <color name="primary_dark">@*android:color/primary_dark_material_dark</color>
     <color name="primary">@*android:color/material_blue_grey_900</color>
@@ -35,4 +34,13 @@
 
     <color name="band_select_background">#88ffffff</color>
     <color name="band_select_border">#44000000</color>
+
+    <color name="item_doc_background_disabled">#fff4f4f4</color>
+
+    <color name="root_activated_color">@color/material_teal_700</color>
+
+    <!-- TODO: Would be nice to move this to a color-set, but not sure how to support animation -->
+    <color name="item_doc_background">#fffafafa</color>
+    <color name="item_doc_background_selected">#ffe0f2f1</color>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index 07498a0..f0cab08 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -19,7 +19,16 @@
     <bool name="config_defaultAdvancedDevices">false</bool>
 
     <!-- Intentionally unset. Vendors should set this in an overlay. -->
-    <string name="trusted_quick_viewer_package"></string>
+    <string name="trusted_quick_viewer_package" translatable="false"></string>
+
+    <!-- overridden for RTL langs -->
     <bool name="list_divider_inset_left">true</bool>
-    <bool name="always_show_summary">false</bool>
+
+    <!-- Flags setup as productivity oriented in which case Downloads app will be presented
+             as Files app. Including showing of the Documents and "advanced" roots. -->
+    <bool name="productivity_device">false</bool>
+
+    <!-- Indicates if search view is taking the whole toolbar space -->
+    <bool name="full_bar_search_view">true</bool>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index 9fc8a73..e682994 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -37,4 +37,9 @@
     <dimen name="dir_elevation">8dp</dimen>
     <dimen name="drag_shadow_size">120dp</dimen>
     <dimen name="grid_item_elevation">2dp</dimen>
+    <dimen name="max_drawer_width">280dp</dimen>
+
+    <dimen name="drag_shadow_width">160dp</dimen>
+    <dimen name="drag_shadow_height">48dp</dimen>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index b97918e..eb99a0d 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -18,9 +18,6 @@
     <!-- Title of the documents application [CHAR LIMIT=32] -->
     <string name="app_label">Documents</string>
 
-    <!-- Title of the standalone files activity. [CHAR LIMIT=32] -->
-    <string name="files_label">Files</string>
-
     <!-- Title of the standalone downloads activity. [CHAR LIMIT=32] -->
     <string name="downloads_label">Downloads</string>
 
@@ -134,6 +131,8 @@
     <string name="copy_notification_title">Copying files</string>
     <!-- Title of the move notification [CHAR LIMIT=24] -->
     <string name="move_notification_title">Moving files</string>
+    <!-- Title of the move notification [CHAR LIMIT=24] -->
+    <string name="delete_notification_title">Deleting files</string>
     <!-- Text shown on the copy notification to indicate remaining time, in minutes [CHAR LIMIT=24] -->
     <string name="copy_remaining"><xliff:g id="duration" example="3 minutes">%s</xliff:g> left</string>
     <!-- Toast shown when a file copy is kicked off -->
@@ -198,12 +197,52 @@
          during a copy. [CHAR LIMIT=48] -->
     <string name="notification_copy_files_converted_title">Some files were converted</string>
 
-    <!--  DO NOT TRANSLATE - final phrase has not been decided yet (b/26750152) -->
+    <!-- Text in an alert dialog asking user to grant app access to a given directory in an external storage volume -->
     <string name="open_external_dialog_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
-        access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> folder on
+        access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory on
         <xliff:g id="storage" example="SD Card"><i>^3</i></xliff:g>?</string>
+    <!-- Text in an alert dialog asking user to grant app access to a given directory in the internal storage -->
+    <string name="open_external_dialog_request_primary_volume">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
+        access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory?</string>
+    <!-- Text in an alert dialog asking user to grant app access to all data in an external storage volume -->
+    <string name="open_external_dialog_root_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
+        access to your data, including photos and videos, on <xliff:g id="storage" example="SD Card"><i>^2</i></xliff:g>?</string>
+    <!-- Checkbox that allows user to not be questioned about the directory access request again -->
+    <string name="never_ask_again">Don\'t ask again</string>
     <!-- Text in the button asking user to allow access to a given directory. -->
     <string name="allow">Allow</string>
     <!-- Text in the button asking user to deny access to a given directory. -->
     <string name="deny">Deny</string>
+    <!-- Dialog text shown to users when asking if they want to delete files (a confirmation). -->
+    <!-- Label text showing user how many items are selected. Can be one or more elements. -->
+    <plurals name="elements_selected">
+        <item quantity="one"><xliff:g id="count" example="1">%1$d</xliff:g> selected</item>
+        <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
+    </plurals>
+
+    <!-- Label text showing user how many items are being dragged. Can be one or more elements. -->
+    <plurals name="elements_dragged">
+        <item quantity="one"><xliff:g id="count" example="1">%1$d</xliff:g> item</item>
+        <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> items</item>
+    </plurals>
+
+    <!-- Dialog text shown to users when asking if they want to delete a file (a confirmation) -->
+    <string name="delete_filename_confirmation_message">Delete \"<xliff:g id="name" example="cat.jpg">%1$s</xliff:g>\"?</string>
+    <!-- Dialog text shown to users when asking if they want to delete a folder (a confirmation) -->
+    <string name="delete_foldername_confirmation_message">Delete folder \"<xliff:g id="name" example="Photos">%1$s</xliff:g>\" and its contents?</string>
+    <!-- Dialog text shown to users when asking if they want to delete files (a confirmation). -->
+    <plurals name="delete_files_confirmation_message">
+        <item quantity="one">Delete <xliff:g id="count" example="1">%1$d</xliff:g> file?</item>
+        <item quantity="other">Delete <xliff:g id="count" example="3">%1$d</xliff:g> files?</item>
+    </plurals>
+    <!-- Dialog text shown to users when asking if they want to delete folders (a confirmation). -->
+    <plurals name="delete_folders_confirmation_message">
+        <item quantity="one">Delete <xliff:g id="count" example="1">%1$d</xliff:g> folder and its contents?</item>
+        <item quantity="other">Delete <xliff:g id="count" example="3">%1$d</xliff:g> folders and their contents?</item>
+    </plurals>
+    <!-- Dialog text shown to users when asking if they want to delete mixed type items: files and folders (a confirmation). -->
+    <plurals name="delete_items_confirmation_message">
+        <item quantity="one">Delete <xliff:g id="count" example="1">%1$d</xliff:g> item?</item>
+        <item quantity="other">Delete <xliff:g id="count" example="3">%1$d</xliff:g> items?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index f4dfd73..b0996aa 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -29,6 +29,7 @@
         <item name="android:colorPrimary">@color/primary</item>
         <item name="android:colorAccent">@color/accent</item>
         <item name="colorActionMode">@color/action_mode</item>
+        <item name="android:queryBackground">@color/menu_search_background</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -42,11 +43,7 @@
     <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal">
         <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item>
         <item name="android:minHeight">3dp</item>
-        <item name="android:maxHeight">3dp</item>    
-    </style>
-
-    <!--  TODO: use the proper dialog and/or inline if not overriding -->
-    <style name="AlertDialogTheme" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
+        <item name="android:maxHeight">3dp</item>
     </style>
 
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index b67a6915..0d6ddf2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -17,24 +17,26 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.EXTRA_BENCHMARK;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.State.ACTION_OPEN;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.State.MODE_GRID;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_ENTER;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_LEAVE;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.app.Activity;
 import android.app.Fragment;
+import android.app.FragmentManager;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
-import android.database.Cursor;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.MessageQueue.IdleHandler;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
 import android.support.annotation.CallSuper;
@@ -44,47 +46,44 @@
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.WindowManager;
 import android.widget.Spinner;
 
-import com.android.documentsui.SearchManager.SearchManagerListener;
+import com.android.documentsui.SearchViewManager.SearchManagerListener;
 import com.android.documentsui.State.ViewMode;
+import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.concurrent.Executor;
 
 public abstract class BaseActivity extends Activity
         implements SearchManagerListener, NavigationView.Environment {
 
-    static final String EXTRA_STATE = "state";
-
-    // See comments where this const is referenced for details.
-    private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
+    private static final String BENCHMARK_TESTING_PACKAGE = "com.android.documentsui.appperftests";
 
     State mState;
     RootsCache mRoots;
-    SearchManager mSearchManager;
+    SearchViewManager mSearchManager;
     DrawerController mDrawer;
     NavigationView mNavigator;
+    List<EventListener> mEventListeners = new ArrayList<>();
 
     private final String mTag;
 
     @LayoutRes
     private int mLayoutId;
 
-    // Track the time we opened the drawer in response to back being pressed.
-    // We use the time gap to figure out whether to close app or reopen the drawer.
-    private long mDrawerLastFiddled;
-
     private boolean mNavDrawerHasFocus;
+    private long mStartTime;
 
     public abstract void onDocumentPicked(DocumentInfo doc, Model model);
     public abstract void onDocumentsPicked(List<DocumentInfo> docs);
@@ -102,13 +101,30 @@
     @CallSuper
     @Override
     public void onCreate(Bundle icicle) {
+        // This flag is being set here as a result of the bug. When the flag was set in the
+        // styles.xml keyboard was messing the layout of dialogs (create dir, rename).
+        // Attempts were made to keep the flag in the main theme and to override it in the dialog
+        // layout xml or to create separate style for dialog and assign it in styles.xml.
+        // None of this brought successful results.
+        // Setting the flag works here most probably because of the timing when it is set. Also the
+        // setting might not affect the dialogs that are created in new windows or it affects them
+        // in the different way that having this in the style.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+        // Record the time when onCreate is invoked for metric.
+        mStartTime = new Date().getTime();
+
         super.onCreate(icicle);
 
+        final Intent intent = getIntent();
+
+        addListenerForLaunchCompletion();
+
         setContentView(mLayoutId);
 
         mDrawer = DrawerController.create(this);
         mState = getState(icicle);
-        Metrics.logActivityLaunch(this, mState, getIntent());
+        Metrics.logActivityLaunch(this, mState, intent);
 
         mRoots = DocumentsApplication.getRootsCache(this);
 
@@ -121,9 +137,10 @@
                     }
                 });
 
-        mSearchManager = new SearchManager(this);
+        mSearchManager = new SearchViewManager(this, icicle);
 
         DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
+        Display.adjustToolbar(toolbar, this);
         setActionBar(toolbar);
         mNavigator = new NavigationView(
                 mDrawer,
@@ -141,7 +158,9 @@
         boolean showMenu = super.onCreateOptionsMenu(menu);
 
         getMenuInflater().inflate(R.menu.activity, menu);
-        mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar));
+        mNavigator.update();
+        boolean fullBarSearch = getResources().getBoolean(R.bool.full_bar_search_view);
+        mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar), fullBarSearch);
 
         return showMenu;
     }
@@ -163,7 +182,7 @@
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
 
         // Search uses backend ranking; no sorting, recents doesn't support sort.
-        sort.setVisible(!inRecents && !mSearchManager.isSearching());
+        sort.setEnabled(!inRecents && !mSearchManager.isSearching());
         sortSize.setVisible(mState.showSize); // Only sort by size when file sizes are visible
         fileSize.setVisible(!mState.forceSize);
 
@@ -171,8 +190,8 @@
         grid.setVisible(mState.derivedMode != State.MODE_GRID);
         list.setVisible(mState.derivedMode != State.MODE_LIST);
 
-        advanced.setVisible(!mState.forceAdvanced);
-        advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
+        advanced.setVisible(mState.showAdvancedOption);
+        advanced.setTitle(mState.showAdvancedOption && mState.showAdvanced
                 ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
         fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
                 ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
@@ -188,34 +207,34 @@
 
     private State getState(@Nullable Bundle icicle) {
         if (icicle != null) {
-            State state = icicle.<State>getParcelable(EXTRA_STATE);
+            State state = icicle.<State>getParcelable(Shared.EXTRA_STATE);
             if (DEBUG) Log.d(mTag, "Recovered existing state object: " + state);
             return state;
         }
 
-        State state = createSharedState();
-        includeState(state);
-        if (DEBUG) Log.d(mTag, "Created new state object: " + state);
-        return state;
-    }
-
-    private State createSharedState() {
         State state = new State();
 
         final Intent intent = getIntent();
 
         state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
-
         state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false);
         state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this);
-
-        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
-        state.showAdvanced = state.forceAdvanced
-                || LocalPreferences.getDisplayAdvancedDevices(this);
-
         state.initAcceptMimes(intent);
         state.excludedAuthorities = getExcludedAuthorities();
 
+        includeState(state);
+
+        // Advanced roots are shown by deafult without menu option if forced by config or intent.
+        state.showAdvanced = Shared.shouldShowDeviceRoot(this, intent);
+        // Menu option is shown for whitelisted intents if advanced roots are not shown by default.
+        state.showAdvancedOption = !state.showAdvanced &&
+                (state.action == ACTION_OPEN ||
+                        state.action == ACTION_CREATE ||
+                        state.action == ACTION_OPEN_TREE ||
+                        state.action == ACTION_GET_CONTENT);
+
+        if (DEBUG) Log.d(mTag, "Created new state object: " + state);
+
         return state;
     }
 
@@ -224,6 +243,9 @@
     }
 
     void onRootPicked(RootInfo root) {
+        // Clicking on the current root removes search
+        mSearchManager.cancelSearch();
+
         // Skip refreshing if root nor directory didn't change
         if (root.equals(getCurrentRoot()) && mState.stack.size() == 1) {
             return;
@@ -233,13 +255,12 @@
 
         // Clear entire backstack and start in new root
         mState.onRootChanged(root);
-        mSearchManager.update(root);
 
         // Recents is always in memory, so we just load it directly.
         // Otherwise we delegate loading data from disk to a task
         // to ensure a responsive ui.
         if (mRoots.isRecentsRoot(root)) {
-            refreshCurrentRootAndDirectory(ANIM_NONE);
+            refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
         } else {
             new PickRootTask(this, root).executeOnExecutor(getExecutorForCurrentDirectory());
         }
@@ -247,6 +268,7 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
+        Metrics.logMenuAction(this, item.getItemId());
 
         switch (item.getItemId()) {
             case android.R.id.home:
@@ -258,6 +280,7 @@
                 return true;
 
             case R.id.menu_search:
+                // SearchViewManager listens for this directly.
                 return false;
 
             case R.id.menu_sort_name:
@@ -287,7 +310,7 @@
                 return true;
 
             case R.id.menu_advanced:
-                setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this));
+                setDisplayAdvancedDevices(!mState.showAdvanced);
                 return true;
 
             case R.id.menu_file_size:
@@ -314,6 +337,12 @@
         CreateDirectoryFragment.show(getFragmentManager());
     }
 
+    void onDirectoryCreated(DocumentInfo doc) {
+        // By default we do nothing, just let the new directory appear.
+        // DocumentsActivity auto-opens directories after creating them
+        // As that is more attuned to the "picker" use cases it supports.
+    }
+
     /**
      * Returns true if a directory can be created in the current location.
      * @return
@@ -328,19 +357,17 @@
                 && !root.isDownloads();
     }
 
-    void onDirectoryCreated(DocumentInfo doc) {
-        checkArgument(doc.isDirectory());
-        openContainerDocument(doc);
-    }
-
     void openContainerDocument(DocumentInfo doc) {
-        checkArgument(doc.isContainer());
+        assert(doc.isContainer());
+
+        notifyDirectoryNavigated(doc.derivedUri);
+
         mState.pushDocument(doc);
         // Show an opening animation only if pressing "back" would get us back to the
         // previous directory. Especially after opening a root document, pressing
         // back, wouldn't go to the previous root, but close the activity.
         final int anim = (mState.hasLocationChanged() && mState.stack.size() > 1)
-                ? ANIM_ENTER : ANIM_NONE;
+                ? AnimationView.ANIM_ENTER : AnimationView.ANIM_NONE;
         refreshCurrentRootAndDirectory(anim);
     }
 
@@ -364,24 +391,35 @@
         invalidateOptionsMenu();
     }
 
+    final void loadRoot(final Uri uri) {
+        new LoadRootTask(this, uri).executeOnExecutor(
+                ProviderExecutor.forAuthority(uri.getAuthority()));
+    }
+
     /**
      * Called when search results changed.
      * Refreshes the content of the directory. It doesn't refresh elements on the action bar.
      * e.g. The current directory name displayed on the action bar won't get updated.
      */
     @Override
-    public void onSearchChanged() {
-        refreshDirectory(ANIM_NONE);
+    public void onSearchChanged(@Nullable String query) {
+        // We should not get here if root is not searchable
+        assert(canSearchRoot());
+        reloadSearch(query);
     }
 
-    /**
-     * Called when search query changed.
-     * Updates the state object.
-     * @param query - New query
-     */
     @Override
-    public void onSearchQueryChanged(String query) {
-        mState.currentSearch = query;
+    public void onSearchFinished() {
+        // Restores menu icons state
+        invalidateOptionsMenu();
+    }
+
+    private void reloadSearch(String query) {
+        FragmentManager fm = getFragmentManager();
+        RootInfo root = getCurrentRoot();
+        DocumentInfo cwd = getCurrentDirectory();
+
+        DirectoryFragment.reloadSearch(fm, root, cwd, query);
     }
 
     final List<String> getExcludedAuthorities() {
@@ -431,9 +469,19 @@
         return mState;
     }
 
+    /*
+     * Get the default directory to be presented after starting the activity.
+     * Method can be overridden if the change of the behavior of the the child activity is needed.
+     */
+    public Uri getDefaultRoot() {
+        return Shared.shouldShowDocumentsRoot(this, getIntent())
+                ? DocumentsContract.buildHomeUri()
+                : DocumentsContract.buildRootUri(
+                        "com.android.providers.downloads.documents", "downloads");
+    }
+
     void setDisplayAdvancedDevices(boolean display) {
-        LocalPreferences.setDisplayAdvancedDevices(this, display);
-        mState.showAdvanced = mState.forceAdvanced | display;
+        mState.showAdvanced = display;
         RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
         invalidateOptionsMenu();
     }
@@ -486,7 +534,8 @@
     @Override
     protected void onSaveInstanceState(Bundle state) {
         super.onSaveInstanceState(state);
-        state.putParcelable(EXTRA_STATE, mState);
+        state.putParcelable(Shared.EXTRA_STATE, mState);
+        mSearchManager.onSaveInstanceState(state);
     }
 
     @Override
@@ -538,42 +587,24 @@
             return;
         }
 
-        int size = mState.stack.size();
-
-        // Do some "do what a I want" drawer fiddling, but don't
-        // do it if user already hit back recently and we recently
-        // did some fiddling.
-        if (mDrawer.isPresent()
-                && (System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
-            // Close drawer if it is open.
-            if (mDrawer.isOpen()) {
-                mDrawer.setOpen(false);
-                mDrawerLastFiddled = System.currentTimeMillis();
-                return;
-            }
-
-            // Open the Close drawer if it is closed and we're at the top of a root.
-            if (size == 1) {
-                mDrawer.setOpen(true);
-                // Remember so we don't just close it again if back is pressed again.
-                mDrawerLastFiddled = System.currentTimeMillis();
-                return;
-            }
-        }
-
-        if (popDir()) {
+        if (onBeforePopDir() || popDir()) {
             return;
         }
 
         super.onBackPressed();
     }
 
+    boolean onBeforePopDir() {
+        // Files app overrides this with some fancy logic.
+        return false;
+    }
+
     public void onStackPicked(DocumentStack stack) {
         try {
             // Update the restored stack to ensure we have freshest data
             stack.updateDocuments(getContentResolver());
             mState.setStack(stack);
-            refreshCurrentRootAndDirectory(ANIM_SIDE);
+            refreshCurrentRootAndDirectory(AnimationView.ANIM_SIDE);
 
         } catch (FileNotFoundException e) {
             Log.w(mTag, "Failed to restore stack: " + e);
@@ -601,16 +632,38 @@
                 return true;
             }
         } else if (keyCode == KeyEvent.KEYCODE_TAB) {
+            Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_SWITCH_FOCUS);
             // Tab toggles focus on the navigation drawer.
             toggleNavDrawerFocus();
             return true;
         } else if (keyCode == KeyEvent.KEYCODE_DEL) {
+            Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_BACK);
             popDir();
             return true;
         }
         return super.onKeyDown(keyCode, event);
     }
 
+    public void addEventListener(EventListener listener) {
+        mEventListeners.add(listener);
+    }
+
+    public void removeEventListener(EventListener listener) {
+        mEventListeners.remove(listener);
+    }
+
+    public void notifyDirectoryLoaded(Uri uri) {
+        for (EventListener listener : mEventListeners) {
+            listener.onDirectoryLoaded(uri);
+        }
+    }
+
+    void notifyDirectoryNavigated(Uri uri) {
+        for (EventListener listener : mEventListeners) {
+            listener.onDirectoryNavigated(uri);
+        }
+    }
+
     /**
      * Toggles focus between the navigation drawer and the directory listing. If the drawer isn't
      * locked, open/close it as appropriate.
@@ -652,12 +705,50 @@
     private boolean popDir() {
         if (mState.stack.size() > 1) {
             mState.stack.pop();
-            refreshCurrentRootAndDirectory(ANIM_LEAVE);
+            refreshCurrentRootAndDirectory(AnimationView.ANIM_LEAVE);
             return true;
         }
         return false;
     }
 
+    /**
+     * Closes the activity when it's idle.
+     */
+    private void addListenerForLaunchCompletion() {
+        addEventListener(new EventListener() {
+            @Override
+            public void onDirectoryNavigated(Uri uri) {
+            }
+
+            @Override
+            public void onDirectoryLoaded(Uri uri) {
+                removeEventListener(this);
+                getMainLooper().getQueue().addIdleHandler(new IdleHandler() {
+                    @Override
+                    public boolean queueIdle() {
+                        // If startup benchmark is requested by a whitelisted testing package, then
+                        // close the activity once idle, and notify the testing activity.
+                        if (getIntent().getBooleanExtra(EXTRA_BENCHMARK, false) &&
+                                BENCHMARK_TESTING_PACKAGE.equals(getCallingPackage())) {
+                            setResult(RESULT_OK);
+                            finish();
+                        }
+
+                        Metrics.logStartupMs(
+                                BaseActivity.this, (int) (new Date().getTime() - mStartTime));
+
+                        // Remove the idle handler.
+                        return false;
+                    }
+                });
+                new Handler().post(new Runnable() {
+                    @Override public void run() {
+                    }
+                });
+            }
+        });
+    }
+
     private static final class PickRootTask extends PairedTask<BaseActivity, Void, DocumentInfo> {
         private RootInfo mRoot;
 
@@ -681,7 +772,7 @@
 
     private static final class HandleRootsChangedTask
             extends PairedTask<BaseActivity, RootInfo, RootInfo> {
-        DocumentInfo mHome;
+        DocumentInfo mDownloadsDocument;
 
         public HandleRootsChangedTask(BaseActivity activity) {
             super(activity);
@@ -689,31 +780,32 @@
 
         @Override
         protected RootInfo run(RootInfo... roots) {
-            checkArgument(roots.length == 1);
+            assert(roots.length == 1);
+
             final RootInfo currentRoot = roots[0];
             final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking();
-            RootInfo homeRoot = null;
+            RootInfo downloadsRoot = null;
             for (final RootInfo root : cachedRoots) {
-                if (root.isHome()) {
-                    homeRoot = root;
+                if (root.isDownloads()) {
+                    downloadsRoot = root;
                 }
                 if (root.getUri().equals(currentRoot.getUri())) {
                     // We don't need to change the current root as the current root was not removed.
                     return null;
                 }
             }
-            Preconditions.checkNotNull(homeRoot);
-            mHome = mOwner.getRootDocumentBlocking(homeRoot);
-            return homeRoot;
+            assert(downloadsRoot != null);
+            mDownloadsDocument = mOwner.getRootDocumentBlocking(downloadsRoot);
+            return downloadsRoot;
         }
 
         @Override
-        protected void finish(RootInfo homeRoot) {
-            if (homeRoot != null && mHome != null) {
+        protected void finish(RootInfo downloadsRoot) {
+            if (downloadsRoot != null && mDownloadsDocument != null) {
                 // Clear entire backstack and start in new root
-                mOwner.mState.onRootChanged(homeRoot);
-                mOwner.mSearchManager.update(homeRoot);
-                mOwner.openContainerDocument(mHome);
+                mOwner.mState.onRootChanged(downloadsRoot);
+                mOwner.mSearchManager.update(downloadsRoot);
+                mOwner.openContainerDocument(mDownloadsDocument);
             }
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BootReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/BootReceiver.java
new file mode 100644
index 0000000..cdea9d7
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/BootReceiver.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Prime {@link RootsCache} when the system is booted.
+ */
+public class BootReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // We already spun up our application object before getting here, which
+        // kicked off a task to load roots, so this broadcast is finished once
+        // that first pass is done.
+        DocumentsApplication.getRootsCache(context).setBootCompletedResult(goAsync());
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 40bd754..5b5a96e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -82,6 +82,9 @@
         builder.setNegativeButton(android.R.string.cancel, null);
         final AlertDialog dialog = builder.create();
 
+        // Workaround for the problem - virtual keyboard doesn't show on the phone.
+        Shared.ensureKeyboardPresent(context, dialog);
+
         editText.setOnEditorActionListener(
                 new OnEditorActionListener() {
                     @Override
@@ -150,10 +153,12 @@
             if (result != null) {
                 // Navigate into newly created child
                 mActivity.onDirectoryCreated(result);
+                Metrics.logCreateDirOperation(getContext());
             } else {
-                Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show();
+                Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT)
+                        .show();
+                Metrics.logCreateDirError(getContext());
             }
-
             mActivity.setPending(false);
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index b0542b9..d2e918c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -53,19 +53,21 @@
     private final RootInfo mRoot;
     private final Uri mUri;
     private final int mUserSortOrder;
+    private final boolean mSearchMode;
 
     private DocumentInfo mDoc;
     private CancellationSignal mSignal;
     private DirectoryResult mResult;
 
     public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
-            int userSortOrder) {
+            int userSortOrder, boolean inSearchMode) {
         super(context, ProviderExecutor.forAuthority(root.authority));
         mType = type;
         mRoot = root;
         mUri = uri;
         mUserSortOrder = userSortOrder;
         mDoc = doc;
+        mSearchMode = inSearchMode;
     }
 
     @Override
@@ -81,9 +83,10 @@
         final String authority = mUri.getAuthority();
 
         final DirectoryResult result = new DirectoryResult();
+        result.doc = mDoc;
 
         // Use default document when searching
-        if (mType == DirectoryFragment.TYPE_SEARCH) {
+        if (mSearchMode) {
             final Uri docUri = DocumentsContract.buildDocumentUri(
                     mRoot.authority, mRoot.documentId);
             try {
@@ -106,7 +109,7 @@
         }
 
         // Search always uses ranking from provider
-        if (mType == DirectoryFragment.TYPE_SEARCH) {
+        if (mSearchMode) {
             result.sortOrder = State.SORT_ORDER_UNKNOWN;
         }
 
@@ -127,7 +130,7 @@
 
             cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
 
-            if (mType == DirectoryFragment.TYPE_SEARCH) {
+            if (mSearchMode) {
                 // Filter directories out of search results, for now
                 cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
index 22e438a..6268643 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
@@ -22,12 +22,15 @@
 import android.content.ContentProviderClient;
 import android.database.Cursor;
 
+import com.android.documentsui.model.DocumentInfo;
+
 import libcore.io.IoUtils;
 
 public class DirectoryResult implements AutoCloseable {
     ContentProviderClient client;
     public Cursor cursor;
     public Exception exception;
+    public DocumentInfo doc;
 
     public int sortOrder = SORT_ORDER_UNKNOWN;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
deleted file mode 100644
index 000b92a..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ /dev/null
@@ -1,57 +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.documentsui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.LinearLayout;
-
-public class DirectoryView extends LinearLayout {
-    private float mPosition = 0f;
-
-    private int mWidth;
-
-    public DirectoryView(Context context) {
-        super(context);
-    }
-
-    public DirectoryView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        mWidth = w;
-        setPosition(mPosition);
-    }
-
-    public float getPosition() {
-        return mPosition;
-    }
-
-    public void setPosition(float position) {
-        mPosition = position;
-        setX((mWidth > 0) ? (mPosition * mWidth) : 0);
-
-        if (mPosition != 0) {
-            setTranslationZ(getResources().getDimensionPixelSize(R.dimen.dir_elevation));
-        } else {
-            setTranslationZ(0);
-        }
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Display.java b/packages/DocumentsUI/src/com/android/documentsui/Display.java
new file mode 100644
index 0000000..d46a3ea
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Display.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Point;
+import android.util.TypedValue;
+import android.view.WindowManager;
+import android.widget.Toolbar;
+
+/*
+ * Convenience class for getting display related attributes
+ */
+public final class Display {
+    /*
+     * Returns the screen width in raw pixels.
+     */
+    public static float screenWidth(Activity activity) {
+        Point size = new Point();
+        activity.getWindowManager().getDefaultDisplay().getSize(size);
+        return size.x;
+    }
+
+    /*
+     * Returns logical density of the display.
+     */
+    public static float density(Context context) {
+        return context.getResources().getDisplayMetrics().density;
+    }
+
+    /*
+     * Returns action bar height in raw pixels.
+     */
+    public static float actionBarHeight(Context context) {
+        int height = 0;
+        TypedValue tv = new TypedValue();
+        if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
+            height = TypedValue.complexToDimensionPixelSize(tv.data,
+                    context.getResources().getDisplayMetrics());
+        }
+        return height;
+    }
+
+    /*
+     * Returns status bar height in raw pixels.
+     */
+    private static int statusBarHeight(Context context) {
+        int height = 0;
+        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
+                "android");
+        if (resourceId > 0) {
+            height = context.getResources().getDimensionPixelSize(resourceId);
+        }
+        return height;
+    }
+
+    /*
+     * Adjusts toolbar for the layout with translucent status bar. Increases the
+     * height of the toolbar and adds padding at the top to accommodate status bar visible above
+     * toolbar.
+     */
+    public static void adjustToolbar(Toolbar toolbar, Activity activity) {
+        if ((activity.getWindow().getAttributes().flags
+                & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
+            int statusBarHeight = Display.statusBarHeight(activity);
+            toolbar.getLayoutParams().height = (int) (Display.actionBarHeight(activity)
+                    + statusBarHeight);
+            toolbar.setPadding(toolbar.getPaddingLeft(), statusBarHeight, toolbar.getPaddingRight(),
+                    toolbar.getPaddingBottom());
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index b3c2846..15bfc3b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -28,7 +28,6 @@
 import android.util.Log;
 
 import com.android.documentsui.model.DocumentInfo;
-import com.android.internal.util.Preconditions;
 
 import libcore.io.IoUtils;
 
@@ -85,7 +84,7 @@
      * This should be run from inside an AsyncTask.
      */
     public List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
-        Preconditions.checkNotNull(clipData);
+        assert(clipData != null);
         final List<DocumentInfo> srcDocs = new ArrayList<>();
 
         int count = clipData.getItemCount();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index ec7dde9..40b54d3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -22,7 +22,6 @@
 import static com.android.documentsui.State.ACTION_OPEN;
 import static com.android.documentsui.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -46,6 +45,7 @@
 
 import com.android.documentsui.RecentsProvider.RecentColumns;
 import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.model.DocumentInfo;
@@ -94,13 +94,25 @@
             RootsFragment.show(getFragmentManager(), null);
         }
 
-        if (!mState.restored) {
-            // In this case, we set the activity title in AsyncTask.onPostExecute().  To prevent
-            // talkback from reading aloud the default title, we clear it here.
-            setTitle("");
-            new RestoreStackTask(this).execute();
+        if (mState.restored) {
+            if (DEBUG) Log.d(TAG, "Stack already resolved");
         } else {
-            refreshCurrentRootAndDirectory(ANIM_NONE);
+            // We set the activity title in AsyncTask.onPostExecute().
+            // To prevent talkback from reading aloud the default title, we clear it here.
+            setTitle("");
+
+            // As a matter of policy we don't load the last used stack for the copy
+            // destination picker (user is already in Files app).
+            // Concensus was that the experice was too confusing.
+            // In all other cases, where the user is visiting us from another app
+            // we restore the stack as last used from that app.
+            if (mState.action == ACTION_PICK_COPY_DESTINATION) {
+                if (DEBUG) Log.d(TAG, "Launching directly into Home directory.");
+                loadRoot(getDefaultRoot());
+            } else {
+                if (DEBUG) Log.d(TAG, "Attempting to load last used stack for calling package.");
+                new LoadLastUsedStackTask(this).execute();
+            }
         }
     }
 
@@ -142,30 +154,6 @@
         }
     }
 
-    private void onStackRestored(boolean restored, boolean external) {
-        // Show drawer when no stack restored, but only when requesting
-        // non-visual content. However, if we last used an external app,
-        // drawer is always shown.
-
-        boolean showDrawer = false;
-        if (!restored) {
-            showDrawer = true;
-        }
-        if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
-            showDrawer = false;
-        }
-        if (external && mState.action == ACTION_GET_CONTENT) {
-            showDrawer = true;
-        }
-        if (mState.action == ACTION_PICK_COPY_DESTINATION) {
-            showDrawer = true;
-        }
-
-        if (showDrawer) {
-            mNavigator.revealRootsDrawer(true);
-        }
-    }
-
     public void onAppPicked(ResolveInfo info) {
         final Intent intent = new Intent(getIntent());
         intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
@@ -176,7 +164,7 @@
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        Log.d(TAG, "onActivityResult() code=" + resultCode);
+        if (DEBUG) Log.d(TAG, "onActivityResult() code=" + resultCode);
 
         // Only relay back results when not canceled; otherwise stick around to
         // let the user pick another app/backend.
@@ -215,8 +203,8 @@
                        mState.action == ACTION_PICK_COPY_DESTINATION) {
                 title = getResources().getString(R.string.title_save);
             } else {
-                // If all else fails, just call it "Files".
-                title = getResources().getString(R.string.files_label);
+                // If all else fails, just call it "Documents".
+                title = getResources().getString(R.string.app_label);
             }
         }
 
@@ -290,13 +278,8 @@
                 mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
             }
         } else {
-            if (mSearchManager.isSearching()) {
-                // Ongoing search
-                DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
-            } else {
                 // Normal boring directory
                 DirectoryFragment.showDirectory(fm, root, cwd, anim);
-            }
         }
 
         // Forget any replacement target
@@ -321,6 +304,12 @@
                 .executeOnExecutor(getExecutorForCurrentDirectory());
     }
 
+    @Override
+    void onDirectoryCreated(DocumentInfo doc) {
+        assert(doc.isDirectory());
+        openContainerDocument(doc);
+    }
+
     void onSaveRequested(String mimeType, String displayName) {
         new CreateFinishTask(this, mimeType, displayName)
                 .executeOnExecutor(getExecutorForCurrentDirectory());
@@ -399,7 +388,7 @@
 
     @Override
     void onTaskFinished(Uri... uris) {
-        Log.d(TAG, "onFinished() " + Arrays.toString(uris));
+        if (DEBUG) Log.d(TAG, "onFinished() " + Arrays.toString(uris));
 
         final Intent intent = new Intent();
         if (uris.length == 1) {
@@ -441,16 +430,19 @@
     }
 
     /**
-     * Restores the stack from Recents for the specified package.
+     * Loads the last used path (stack) from Recents (history).
+     * The path selected is based on the calling package name. So the last
+     * path for an app like Gmail can be different than the last path
+     * for an app like DropBox.
      */
-    private static final class RestoreStackTask
+    private static final class LoadLastUsedStackTask
             extends PairedTask<DocumentsActivity, Void, Void> {
 
         private volatile boolean mRestoredStack;
         private volatile boolean mExternal;
         private State mState;
 
-        public RestoreStackTask(DocumentsActivity activity) {
+        public LoadLastUsedStackTask(DocumentsActivity activity) {
             super(activity);
             mState = activity.mState;
         }
@@ -499,8 +491,8 @@
         @Override
         protected void finish(Void result) {
             mState.restored = true;
-            mOwner.refreshCurrentRootAndDirectory(ANIM_NONE);
-            mOwner.onStackRestored(mRestoredStack, mExternal);
+            mState.external = mExternal;
+            mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
         }
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
index 9005442..5ea6cfa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
@@ -69,7 +69,7 @@
         final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024;
 
         mRoots = new RootsCache(this);
-        mRoots.updateAsync();
+        mRoots.updateAsync(false);
 
         mThumbnails = new ThumbnailCache(memoryClassBytes / 4);
 
@@ -105,7 +105,7 @@
                 final String packageName = data.getSchemeSpecificPart();
                 mRoots.updatePackageAsync(packageName);
             } else {
-                mRoots.updateAsync();
+                mRoots.updateAsync(true);
             }
         }
     };
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
deleted file mode 100644
index f7a45e2..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
+++ /dev/null
@@ -1,190 +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.documentsui;
-
-import static com.android.documentsui.State.ACTION_MANAGE;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.content.ActivityNotFoundException;
-import android.content.ClipData;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.DocumentsContract;
-import android.support.design.widget.Snackbar;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.Toolbar;
-
-import com.android.documentsui.dirlist.DirectoryFragment;
-import com.android.documentsui.dirlist.Model;
-import com.android.documentsui.model.DocumentInfo;
-import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.List;
-
-// Let's face it. MANAGE_ROOT is used almost exclusively
-// for downloads, and is specialized for this purpose.
-// So it is now thusly christened.
-public class DownloadsActivity extends BaseActivity {
-    private static final String TAG = "DownloadsActivity";
-
-    public DownloadsActivity() {
-        super(R.layout.downloads_activity, TAG);
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        final Context context = this;
-
-        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
-        toolbar.setTitleTextAppearance(context,
-                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
-
-        if (!mState.restored) {
-            // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent
-            // talkback from reading aloud the default title, we clear it here.
-            setTitle("");
-            final Uri rootUri = getIntent().getData();
-            new RestoreRootTask(this, rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
-        } else {
-            refreshCurrentRootAndDirectory(ANIM_NONE);
-        }
-    }
-
-    @Override
-    void includeState(State state) {
-        state.action = ACTION_MANAGE;
-        state.acceptMimes = new String[] { "*/*" };
-        state.allowMultiple = true;
-        state.showSize = true;
-        state.excludedAuthorities = getExcludedAuthorities();
-    }
-
-    @Override
-    protected void onPostCreate(Bundle savedInstanceState) {
-        super.onPostCreate(savedInstanceState);
-        mNavigator.update();
-    }
-
-    @Override
-    public String getDrawerTitle() {
-        return null;  // being and nothingness
-    }
-
-    @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        super.onPrepareOptionsMenu(menu);
-
-        final MenuItem advanced = menu.findItem(R.id.menu_advanced);
-        final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
-        final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
-        final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
-
-        advanced.setVisible(false);
-        createDir.setVisible(false);
-        pasteFromCb.setEnabled(false);
-        fileSize.setVisible(false);
-
-        Menus.disableHiddenItems(menu);
-        return true;
-    }
-
-    @Override
-    void refreshDirectory(int anim) {
-        final FragmentManager fm = getFragmentManager();
-        final RootInfo root = getCurrentRoot();
-        final DocumentInfo cwd = getCurrentDirectory();
-
-        // If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
-        // root).
-        Preconditions.checkNotNull(cwd);
-
-        if (mState.currentSearch != null) {
-            // Ongoing search
-            DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
-        } else {
-            // Normal boring directory
-            DirectoryFragment.showDirectory(fm, root, cwd, anim);
-        }
-    }
-
-    @Override
-    public void onDocumentPicked(DocumentInfo doc, Model model) {
-        Preconditions.checkArgument(!doc.isDirectory());
-        // First try managing the document; we expect manager to filter
-        // based on authority, so we don't grant.
-        final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
-        manage.setData(doc.derivedUri);
-
-        try {
-            startActivity(manage);
-        } catch (ActivityNotFoundException ex) {
-            // Fall back to viewing.
-            final Intent view = new Intent(Intent.ACTION_VIEW);
-            view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            view.setData(doc.derivedUri);
-
-            try {
-                startActivity(view);
-            } catch (ActivityNotFoundException ex2) {
-                Snackbars.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT)
-                        .show();
-            }
-        }
-    }
-
-    @Override
-    public void onDocumentsPicked(List<DocumentInfo> docs) {}
-
-    @Override
-    void onTaskFinished(Uri... uris) {
-        Log.d(TAG, "onFinished() " + Arrays.toString(uris));
-
-        final Intent intent = new Intent();
-        if (uris.length == 1) {
-            intent.setData(uris[0]);
-        } else if (uris.length > 1) {
-            final ClipData clipData = new ClipData(
-                    null, mState.acceptMimes, new ClipData.Item(uris[0]));
-            for (int i = 1; i < uris.length; i++) {
-                clipData.addItem(new ClipData.Item(uris[i]));
-            }
-            intent.setClipData(clipData);
-        }
-
-        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
-                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
-
-        setResult(Activity.RESULT_OK, intent);
-        finish();
-    }
-
-    public static DownloadsActivity get(Fragment fragment) {
-        return (DownloadsActivity) fragment.getActivity();
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
index bcf69c4..7a4099a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -16,23 +16,56 @@
 
 package com.android.documentsui;
 
-import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.documentsui.Shared.DEBUG;
 
+import android.annotation.IntDef;
 import android.app.Activity;
+import android.content.Context;
 import android.support.v4.app.ActionBarDrawerToggle;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.util.Log;
 import android.view.View;
 import android.widget.Toolbar;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A facade over the various pieces comprising "roots fragment in a Drawer".
  *
  * @see DrawerController#create(DrawerLayout)
  */
 abstract class DrawerController implements DrawerListener {
+    public static final String TAG = "DrawerController";
 
+    // Drawer opening triggered by tapping the navigation icon
+    public static final int OPENED_HAMBURGER = 0;
+    // Drawer opening triggered by swiping right from the edge of the screen
+    public static final int OPENED_SWIPE = 1;
+    // Mostly programmatically forced drawer opening
+    public static final int OPENED_OTHER = 2;
+
+    @IntDef(flag = true, value = {
+            OPENED_HAMBURGER,
+            OPENED_SWIPE,
+            OPENED_OTHER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Trigger {}
+
+    /**
+     * Toggles the drawer and sets the OPENED_OTHER as the action that causes opening the drawer.
+     * @param open
+     */
     abstract void setOpen(boolean open);
+
+    /**
+     * Toggles the drawer.
+     * @param open
+     * @param trigger Indicates what action caused opening the drawer. It is ignored for closing.
+     */
+    abstract void setOpen(boolean open, @Trigger int trigger);
     abstract boolean isPresent();
     abstract boolean isOpen();
     abstract void setTitle(String title);
@@ -51,6 +84,8 @@
 
         View drawer = activity.findViewById(R.id.drawer_roots);
         Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar);
+        Display.adjustToolbar(toolbar, activity);
+        drawer.getLayoutParams().width = calculateDrawerWidth(activity);
 
         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                 activity,
@@ -69,21 +104,34 @@
         return new DummyDrawerController();
     }
 
+    private static int calculateDrawerWidth(Activity activity) {
+        // Material design specification for navigation drawer:
+        // https://www.google.com/design/spec/patterns/navigation-drawer.html
+        float width = Display.screenWidth(activity) - Display.actionBarHeight(activity);
+        float maxWidth = activity.getResources().getDimension(R.dimen.max_drawer_width);
+        int finalWidth = (int) ((width > maxWidth ? maxWidth : width));
+
+        if (DEBUG)
+            Log.d(TAG, "Calculated drawer width:" + (finalWidth / Display.density(activity)));
+
+        return finalWidth;
+    }
+
     /**
      * Runtime controller that manages a real drawer.
      */
     private static final class RuntimeDrawerController extends DrawerController {
-
         private final ActionBarDrawerToggle mToggle;
         private DrawerLayout mLayout;
         private View mDrawer;
         private Toolbar mToolbar;
+        private @Trigger int mTrigger = OPENED_OTHER;
 
         public RuntimeDrawerController(
                 DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle,
                 Toolbar drawerToolbar) {
             mToolbar = drawerToolbar;
-            checkArgument(layout != null);
+            assert(layout != null);
 
             mLayout = layout;
             mDrawer = drawer;
@@ -94,8 +142,14 @@
 
         @Override
         void setOpen(boolean open) {
+            setOpen(open, OPENED_OTHER);
+        }
+
+        @Override
+        void setOpen(boolean open, @Trigger int trigger) {
             if (open) {
                 mLayout.openDrawer(mDrawer);
+                mTrigger = trigger;
             } else {
                 mLayout.closeDrawer(mDrawer);
             }
@@ -129,16 +183,21 @@
         @Override
         public void onDrawerOpened(View drawerView) {
             mToggle.onDrawerOpened(drawerView);
+            Metrics.logDrawerOpened(mToolbar.getContext(), mTrigger);
         }
 
         @Override
         public void onDrawerClosed(View drawerView) {
             mToggle.onDrawerClosed(drawerView);
+            mTrigger = OPENED_OTHER;
         }
 
         @Override
         public void onDrawerStateChanged(int newState) {
             mToggle.onDrawerStateChanged(newState);
+            if (newState == DrawerLayout.STATE_DRAGGING) {
+                mTrigger = OPENED_SWIPE;
+            }
         }
     }
 
@@ -150,6 +209,8 @@
         @Override
         void setOpen(boolean open) {}
 
+        @Override
+        void setOpen(boolean open, @Trigger int trigger) {}
 
         @Override
         boolean isOpen() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/EventListener.java b/packages/DocumentsUI/src/com/android/documentsui/EventListener.java
new file mode 100644
index 0000000..c15e9a6
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/EventListener.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.net.Uri;
+import android.support.annotation.Nullable;
+
+public interface EventListener {
+    /**
+     * @param uri Uri navigated to. If recents, then null.
+     */
+    void onDirectoryNavigated(@Nullable Uri uri);
+
+    /**
+     * @param uri Uri of the loaded directory. If recents, then null.
+     */
+    void onDirectoryLoaded(@Nullable Uri uri);
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index c0faba3..527eb78 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -18,9 +18,6 @@
 
 import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.FragmentManager;
@@ -33,7 +30,6 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
-import android.support.annotation.Nullable;
 import android.support.design.widget.Snackbar;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -42,6 +38,7 @@
 
 import com.android.documentsui.OperationDialogFragment.DialogType;
 import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.model.DocumentInfo;
@@ -63,6 +60,12 @@
 
     public static final String TAG = "FilesActivity";
 
+    // See comments where this const is referenced for details.
+    private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
+
+    // Track the time we opened the drawer in response to back being pressed.
+    // We use the time gap to figure out whether to close app or reopen the drawer.
+    private long mDrawerLastFiddled;
     private DocumentClipper mClipper;
 
     public FilesActivity() {
@@ -82,7 +85,6 @@
 
         if (mState.restored) {
             if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
-            refreshCurrentRootAndDirectory(ANIM_NONE);
         } else if (!mState.stack.isEmpty()) {
             // If a non-empty stack is present in our state it was read (presumably)
             // from EXTRA_STACK intent extra. In this case, we'll skip other means of
@@ -93,25 +95,21 @@
             // Launch URIs support sensible activity management, but don't specify a real
             // content target.
             if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
-            checkState(uri == null || uri.getAuthority() == null ||
+            assert(uri == null || uri.getAuthority() == null ||
                     LauncherActivity.isLaunchUri(uri));
-            refreshCurrentRootAndDirectory(ANIM_NONE);
+            refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
         } else if (intent.getAction() == Intent.ACTION_VIEW) {
-            checkArgument(uri != null);
+            assert(uri != null);
             new OpenUriForViewTask(this).executeOnExecutor(
                     ProviderExecutor.forAuthority(uri.getAuthority()), uri);
         } else if (DocumentsContract.isRootUri(this, uri)) {
             if (DEBUG) Log.d(TAG, "Launching with root URI.");
             // If we've got a specific root to display, restore that root using a dedicated
             // authority. That way a misbehaving provider won't result in an ANR.
-            new RestoreRootTask(this, uri).executeOnExecutor(
-                    ProviderExecutor.forAuthority(uri.getAuthority()));
+            loadRoot(uri);
         } else {
-            if (DEBUG) Log.d(TAG, "Launching into Home directory.");
-            // If all else fails, try to load "Home" directory.
-            final Uri homeUri = DocumentsContract.buildHomeUri();
-            new RestoreRootTask(this, homeUri).executeOnExecutor(
-                    ProviderExecutor.forAuthority(homeUri.getAuthority()));
+            if (DEBUG) Log.d(TAG, "All other means skipped. Launching into default directory.");
+            loadRoot(getDefaultRoot());
         }
 
         final @DialogType int dialogType = intent.getIntExtra(
@@ -141,7 +139,7 @@
         state.allowMultiple = true;
 
         // Options specific to the DocumentsActivity.
-        checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
+        assert(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
 
         final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
         if (stack != null) {
@@ -182,7 +180,10 @@
 
     @Override
     public String getDrawerTitle() {
-        return getResources().getString(R.string.files_label);
+        Intent intent = getIntent();
+        return (intent != null && intent.hasExtra(Intent.EXTRA_TITLE))
+                ? intent.getStringExtra(Intent.EXTRA_TITLE)
+                : getTitle().toString();
     }
 
     @Override
@@ -203,6 +204,8 @@
         newWindow.setVisible(true);
 
         Menus.disableHiddenItems(menu, pasteFromCb);
+        // It hides icon if searching in progress
+        mSearchManager.updateMenu();
         return true;
     }
 
@@ -210,21 +213,24 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.menu_create_dir:
-                checkState(canCreateDirectory());
+                assert(canCreateDirectory());
                 showCreateDirectoryDialog();
-                return true;
+                break;
             case R.id.menu_new_window:
                 createNewWindow();
-                return true;
+                break;
             case R.id.menu_paste_from_clipboard:
                 DirectoryFragment dir = getDirectoryFragment();
                 if (dir != null) {
                     dir.pasteFromClipboard();
                 }
-                return true;
+                break;
+            default:
+                return super.onOptionsItemSelected(item);
         }
 
-        return super.onOptionsItemSelected(item);
+        Metrics.logMenuAction(this, item.getItemId());
+        return true;
     }
 
     private void createNewWindow() {
@@ -235,7 +241,7 @@
         // With new multi-window mode we have to pick how we are launched.
         // By default we'd be launched in-place above the existing app.
         // By setting launch-to-side ActivityManager will open us to side.
-        if (inMultiWindow()) {
+        if (isInMultiWindowMode()) {
             intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
         }
 
@@ -248,16 +254,13 @@
         final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
 
+        assert(!mSearchManager.isSearching());
+
         if (cwd == null) {
             DirectoryFragment.showRecentsOpen(fm, anim);
         } else {
-            if (mState.currentSearch != null) {
-                // Ongoing search
-                DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
-            } else {
-                // Normal boring directory
-                DirectoryFragment.showDirectory(fm, root, cwd, anim);
-            }
+            // Normal boring directory
+            DirectoryFragment.showDirectory(fm, root, cwd, anim);
         }
     }
 
@@ -285,6 +288,30 @@
      * Launches an intent to view the specified document.
      */
     private void openDocument(DocumentInfo doc, Model model) {
+
+        // Anything on downloads goes through the back through downloads manager
+        // (that's the MANAGE_DOCUMENT bit).
+        // This is done for two reasons:
+        // 1) The file in question might be a failed/queued or otherwise have some
+        //    specialized download handling.
+        // 2) For APKs, the download manager will add on some important security stuff
+        //    like origin URL.
+        // All other files not on downloads, event APKs, would get no benefit from this
+        // treatment, thusly the "isDownloads" check.
+        if (getCurrentRoot().isDownloads()) {
+            // First try managing the document; we expect manager to filter
+            // based on authority, so we don't grant.
+            final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
+            manage.setData(doc.derivedUri);
+
+            try {
+                startActivity(manage);
+                return;
+            } catch (ActivityNotFoundException ex) {
+                // fall back to regular handling below.
+            }
+        }
+
         Intent intent = new QuickViewIntentBuilder(
                 getPackageManager(), getResources(), doc, model).build();
 
@@ -299,7 +326,7 @@
             }
         }
 
-        // Fallback to traditional VIEW action...
+        // Fall back to traditional VIEW action...
         intent = new Intent(Intent.ACTION_VIEW);
         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         intent.setData(doc.derivedUri);
@@ -325,18 +352,21 @@
             case KeyEvent.KEYCODE_A:
                 dir = getDirectoryFragment();
                 if (dir != null) {
+                    Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_SELECT_ALL);
                     dir.selectAllFiles();
                 }
                 return true;
             case KeyEvent.KEYCODE_C:
                 dir = getDirectoryFragment();
                 if (dir != null) {
+                    Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_COPY);
                     dir.copySelectedToClipboard();
                 }
                 return true;
             case KeyEvent.KEYCODE_V:
                 dir = getDirectoryFragment();
                 if (dir != null) {
+                    Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_PASTE);
                     dir.pasteFromClipboard();
                 }
                 return true;
@@ -345,6 +375,34 @@
         }
     }
 
+    // Do some "do what a I want" drawer fiddling, but don't
+    // do it if user already hit back recently and we recently
+    // did some fiddling.
+    @Override
+    boolean onBeforePopDir() {
+        int size = mState.stack.size();
+
+        if (mDrawer.isPresent()
+                && (System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
+            // Close drawer if it is open.
+            if (mDrawer.isOpen()) {
+                mDrawer.setOpen(false);
+                mDrawerLastFiddled = System.currentTimeMillis();
+                return true;
+            }
+
+            // Open the Close drawer if it is closed and we're at the top of a root.
+            if (size <= 1) {
+                mDrawer.setOpen(true);
+                // Remember so we don't just close it again if back is pressed again.
+                mDrawerLastFiddled = System.currentTimeMillis();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     // Turns out only DocumentsActivity was ever calling saveStackBlocking.
     // There may be a  case where we want to contribute entries from
     // Behavior here in FilesActivity, but it isn't yet obvious.
@@ -365,7 +423,7 @@
 
     @Override
     void onTaskFinished(Uri... uris) {
-        Log.d(TAG, "onFinished() " + Arrays.toString(uris));
+        if (DEBUG) Log.d(TAG, "onFinished() " + Arrays.toString(uris));
 
         final Intent intent = new Intent();
         if (uris.length == 1) {
@@ -427,7 +485,7 @@
 
         @Override
         protected void finish(Void result) {
-            mOwner.refreshCurrentRootAndDirectory(ANIM_NONE);
+            mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
         }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
index 7930c28..5cb6ca3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
@@ -87,9 +87,24 @@
         startActivity(intent);
     }
 
-    static final Intent createLaunchIntent(Context context) {
-        Intent intent = new Intent(context, FilesActivity.class);
+    static final Intent createLaunchIntent(Activity activity) {
+        Intent intent = new Intent(activity, FilesActivity.class);
         intent.setData(buildLaunchUri());
+
+        // Relay any config overrides bits present in the original intent.
+        Intent original = activity.getIntent();
+        if (original != null) {
+            if (original.hasExtra(Shared.EXTRA_PRODUCTIVITY_MODE)) {
+                intent.putExtra(
+                        Shared.EXTRA_PRODUCTIVITY_MODE,
+                        original.getBooleanExtra(Shared.EXTRA_PRODUCTIVITY_MODE, false));
+            }
+            if (original.hasExtra(Intent.EXTRA_TITLE)) {
+                intent.putExtra(
+                        Intent.EXTRA_TITLE,
+                        original.getStringExtra(Intent.EXTRA_TITLE));
+            }
+        }
         return intent;
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LoadRootTask.java b/packages/DocumentsUI/src/com/android/documentsui/LoadRootTask.java
new file mode 100644
index 0000000..c5d359b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/LoadRootTask.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import com.android.documentsui.model.RootInfo;
+
+final class LoadRootTask extends PairedTask<BaseActivity, Void, RootInfo> {
+    private static final String TAG = "RestoreRootTask";
+
+    private final Uri mRootUri;
+
+    public LoadRootTask(BaseActivity activity, Uri rootUri) {
+        super(activity);
+        mRootUri = rootUri;
+    }
+
+    @Override
+    protected RootInfo run(Void... params) {
+        String rootId = DocumentsContract.getRootId(mRootUri);
+        return mOwner.mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
+    }
+
+    @Override
+    protected void finish(RootInfo root) {
+        mOwner.mState.restored = true;
+
+        if (root != null) {
+            mOwner.onRootPicked(root);
+        } else {
+            Log.w(TAG, "Failed to find root: " + mRootUri);
+            mOwner.finish();
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index 4bffc49..2315664 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -17,54 +17,92 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.State.MODE_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.UserHandle;
 import android.preference.PreferenceManager;
 
 import com.android.documentsui.State.ViewMode;
 import com.android.documentsui.model.RootInfo;
 
 public class LocalPreferences {
-    private static final String KEY_ADVANCED_DEVICES = "advancedDevices";
     private static final String KEY_FILE_SIZE = "fileSize";
     private static final String ROOT_VIEW_MODE_PREFIX = "rootViewMode-";
 
-    public static boolean getDisplayAdvancedDevices(Context context) {
-        boolean defaultAdvanced = context.getResources()
-                .getBoolean(R.bool.config_defaultAdvancedDevices);
-        return PreferenceManager.getDefaultSharedPreferences(context)
-                .getBoolean(KEY_ADVANCED_DEVICES, defaultAdvanced);
-    }
-
     public static boolean getDisplayFileSize(Context context) {
-        return PreferenceManager.getDefaultSharedPreferences(context)
-                .getBoolean(KEY_FILE_SIZE, false);
+        return getPrefs(context).getBoolean(KEY_FILE_SIZE, false);
     }
 
-    public static @ViewMode int getViewMode(
-            Context context, RootInfo root, @ViewMode int fallback) {
-        return PreferenceManager.getDefaultSharedPreferences(context)
-                .getInt(createKey(root), fallback);
-    }
-
-    public static void setDisplayAdvancedDevices(Context context, boolean display) {
-        PreferenceManager.getDefaultSharedPreferences(context).edit()
-                .putBoolean(KEY_ADVANCED_DEVICES, display).apply();
+    public static @ViewMode int getViewMode(Context context, RootInfo root,
+            @ViewMode int fallback) {
+        return getPrefs(context).getInt(createKey(root), fallback);
     }
 
     public static void setDisplayFileSize(Context context, boolean display) {
-        PreferenceManager.getDefaultSharedPreferences(context).edit()
-                .putBoolean(KEY_FILE_SIZE, display).apply();
+        getPrefs(context).edit().putBoolean(KEY_FILE_SIZE, display).apply();
     }
 
     public static void setViewMode(Context context, RootInfo root, @ViewMode int viewMode) {
-        checkArgument(viewMode != MODE_UNKNOWN);
-        PreferenceManager.getDefaultSharedPreferences(context).edit()
-                .putInt(createKey(root), viewMode).apply();
+        assert(viewMode != MODE_UNKNOWN);
+
+        getPrefs(context).edit().putInt(createKey(root), viewMode).apply();
+    }
+
+    private static SharedPreferences getPrefs(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context);
     }
 
     private static String createKey(RootInfo root) {
         return ROOT_VIEW_MODE_PREFIX + root.authority + root.rootId;
     }
+
+    public static final int PERMISSION_ASK = 0;
+    public static final int PERMISSION_ASK_AGAIN = 1;
+    public static final int PERMISSION_NEVER_ASK = -1;
+
+    @IntDef(flag = true, value = {
+            PERMISSION_ASK,
+            PERMISSION_ASK_AGAIN,
+            PERMISSION_NEVER_ASK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionStatus {}
+
+    /**
+     * Methods below are used to keep track of denied user requests on scoped directory access so
+     * the dialog is not offered when user checked the 'Do not ask again' box
+     *
+     * <p>It uses a shared preferences, whose key is:
+     * <ol>
+     * <li>{@code USER_ID|PACKAGE_NAME|VOLUME_UUID|DIRECTORY} for storage volumes that have a UUID
+     * (typically physical volumes like SD cards).
+     * <li>{@code USER_ID|PACKAGE_NAME||DIRECTORY} for storage volumes that do not have a UUID
+     * (typically the emulated volume used for primary storage
+     * </ol>
+     */
+    static @PermissionStatus int getScopedAccessPermissionStatus(Context context,
+            String packageName, @Nullable String uuid, String directory) {
+        final String key = getScopedAccessDenialsKey(packageName, uuid, directory);
+        return getPrefs(context).getInt(key, PERMISSION_ASK);
+    }
+
+    static void setScopedAccessPermissionStatus(Context context, String packageName,
+            @Nullable String uuid, String directory, @PermissionStatus int status) {
+      final String key = getScopedAccessDenialsKey(packageName, uuid, directory);
+      getPrefs(context).edit().putInt(key, status).apply();
+    }
+
+    private static String getScopedAccessDenialsKey(String packageName, String uuid,
+            String directory) {
+        final int userId = UserHandle.myUserId();
+        return uuid == null
+                ? userId + "|" + packageName + "||" + directory
+                : userId + "|" + packageName + "|" + uuid + "|" + directory;
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index 699605f..05cc7e6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -16,23 +16,28 @@
 
 package com.android.documentsui;
 
+import static android.os.Environment.STANDARD_DIRECTORIES;
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.util.Log;
+import android.view.KeyEvent;
 
+import com.android.documentsui.State.ActionType;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperationService.OpType;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -56,11 +61,17 @@
     private static final String COUNT_CREATE_MIME = "docsui_create_mime";
     private static final String COUNT_GET_CONTENT_MIME = "docsui_get_content_mime";
     private static final String COUNT_BROWSE_ROOT = "docsui_browse_root";
-    private static final String COUNT_MANAGE_ROOT = "docsui_manage_root";
+    @Deprecated private static final String COUNT_MANAGE_ROOT = "docsui_manage_root";
     private static final String COUNT_MULTI_WINDOW = "docsui_multi_window";
     private static final String COUNT_FILEOP_SYSTEM = "docsui_fileop_system";
     private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external";
     private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled";
+    private static final String COUNT_STARTUP_MS = "docsui_startup_ms";
+    private static final String COUNT_DRAWER_OPENED = "docsui_drawer_opened";
+    private static final String COUNT_DRAG_N_DROP = "docsui_drag_n_drop";
+    private static final String COUNT_SEARCH = "docsui_search";
+    private static final String COUNT_MENU_ACTION = "docsui_menu_action";
+    private static final String COUNT_KEYBOARD_ACTION = "docsui_keyboard_action";
 
     // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
     // root that is not explicitly recognized by the Metrics code (see {@link
@@ -141,10 +152,14 @@
     private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 6; // Move to a system provider.
     private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 7; // Move to a 3rd-party provider.
     private static final int FILEOP_DELETE = 8;
+    private static final int FILEOP_RENAME = 9;
+    private static final int FILEOP_CREATE_DIR = 10;
     private static final int FILEOP_OTHER_ERROR = 100;
     private static final int FILEOP_DELETE_ERROR = 101;
     private static final int FILEOP_MOVE_ERROR = 102;
     private static final int FILEOP_COPY_ERROR = 103;
+    private static final int FILEOP_RENAME_ERROR = 104;
+    private static final int FILEOP_CREATE_DIR_ERROR = 105;
 
     @IntDef(flag = true, value = {
             FILEOP_OTHER,
@@ -155,10 +170,14 @@
             FILEOP_MOVE_SYSTEM_PROVIDER,
             FILEOP_MOVE_EXTERNAL_PROVIDER,
             FILEOP_DELETE,
+            FILEOP_RENAME,
+            FILEOP_CREATE_DIR,
             FILEOP_OTHER_ERROR,
             FILEOP_COPY_ERROR,
             FILEOP_MOVE_ERROR,
-            FILEOP_DELETE_ERROR
+            FILEOP_DELETE_ERROR,
+            FILEOP_RENAME_ERROR,
+            FILEOP_CREATE_DIR_ERROR
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FileOp {}
@@ -182,8 +201,71 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface MetricsOpType {}
 
-    // Codes representing different launch actions. These are used for bucketing stats in the
-    // COUNT_LAUNCH_ACTION histogram.
+    // Codes representing different provider types.  Used for sorting file operations when logging.
+    private static final int PROVIDER_INTRA = 0;
+    private static final int PROVIDER_SYSTEM = 1;
+    private static final int PROVIDER_EXTERNAL = 2;
+
+    @IntDef(flag = false, value = {
+            PROVIDER_INTRA,
+            PROVIDER_SYSTEM,
+            PROVIDER_EXTERNAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Provider {}
+
+
+    // Codes representing different menu actions. These are used for bucketing stats in the
+    // COUNT_MENU_ACTION histogram.
+    // Both regular toolbar menu and action mode menu operations are included.
+    // Do not change or rearrange these values, that will break historical data. Only add to the
+    // list.
+    // Do not use negative numbers or zero; clearcut only handles positive integers.
+    private static final int ACTION_MENU_OTHER = 1;
+    private static final int ACTION_MENU_GRID = 2;
+    private static final int ACTION_MENU_LIST = 3;
+    private static final int ACTION_MENU_SORT = 4;
+    private static final int ACTION_MENU_SORT_NAME = 5;
+    private static final int ACTION_MENU_SORT_DATE = 6;
+    private static final int ACTION_MENU_SORT_SIZE = 7;
+    private static final int ACTION_MENU_SEARCH = 8;
+    private static final int ACTION_MENU_SHOW_SIZE = 9;
+    private static final int ACTION_MENU_SETTINGS = 10;
+    private static final int ACTION_MENU_COPY_TO = 11;
+    private static final int ACTION_MENU_MOVE_TO = 12;
+    private static final int ACTION_MENU_DELETE = 13;
+    private static final int ACTION_MENU_RENAME = 14;
+    private static final int ACTION_MENU_CREATE_DIR = 15;
+    private static final int ACTION_MENU_SELECT_ALL = 16;
+    private static final int ACTION_MENU_SHARE = 17;
+    private static final int ACTION_MENU_OPEN = 18;
+    private static final int ACTION_MENU_ADVANCED = 19;
+
+    @IntDef(flag = false, value = {
+            ACTION_MENU_OTHER,
+            ACTION_MENU_GRID,
+            ACTION_MENU_LIST,
+            ACTION_MENU_SORT,
+            ACTION_MENU_SORT_NAME,
+            ACTION_MENU_SORT_DATE,
+            ACTION_MENU_SORT_SIZE,
+            ACTION_MENU_SHOW_SIZE,
+            ACTION_MENU_SETTINGS,
+            ACTION_MENU_COPY_TO,
+            ACTION_MENU_MOVE_TO,
+            ACTION_MENU_DELETE,
+            ACTION_MENU_RENAME,
+            ACTION_MENU_CREATE_DIR,
+            ACTION_MENU_SELECT_ALL,
+            ACTION_MENU_SHARE,
+            ACTION_MENU_OPEN,
+            ACTION_MENU_ADVANCED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MenuAction {}
+
+    // Codes representing different menu actions. These are used for bucketing stats in the
+    // COUNT_MENU_ACTION histogram.
     // Do not change or rearrange these values, that will break historical data. Only add to the
     // list.
     // Do not use negative numbers or zero; clearcut only handles positive integers.
@@ -192,7 +274,7 @@
     private static final int ACTION_CREATE = 3;
     private static final int ACTION_GET_CONTENT = 4;
     private static final int ACTION_OPEN_TREE = 5;
-    private static final int ACTION_MANAGE = 6;
+    @Deprecated private static final int ACTION_MANAGE = 6;
     private static final int ACTION_BROWSE = 7;
     private static final int ACTION_PICK_COPY_DESTINATION = 8;
 
@@ -209,18 +291,45 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface MetricsAction {}
 
-    // Codes representing different provider types.  Used for sorting file operations when logging.
-    private static final int PROVIDER_INTRA = 0;
-    private static final int PROVIDER_SYSTEM = 1;
-    private static final int PROVIDER_EXTERNAL = 2;
+    // Codes representing different keyboard shortcut triggered actions. These are used for
+    // bucketing stats in the COUNT_KEYBOARD_ACTION histogram.
+    // Do not change or rearrange these values, that will break historical data. Only add to the
+    // list.
+    // Do not use negative numbers or zero; clearcut only handles positive integers.
+    public static final int ACTION_KEYBOARD_OTHER = 1;
+    public static final int ACTION_KEYBOARD_PASTE = 2;
+    public static final int ACTION_KEYBOARD_COPY = 3;
+    public static final int ACTION_KEYBOARD_DELETE = 4;
+    public static final int ACTION_KEYBOARD_SELECT_ALL = 5;
+    public static final int ACTION_KEYBOARD_BACK = 6;
+    public static final int ACTION_KEYBOARD_SWITCH_FOCUS = 7;
 
-    @IntDef(flag = true, value = {
-            PROVIDER_INTRA,
-            PROVIDER_SYSTEM,
-            PROVIDER_EXTERNAL
+    @IntDef(flag = false, value = {
+            ACTION_KEYBOARD_OTHER,
+            ACTION_KEYBOARD_PASTE,
+            ACTION_KEYBOARD_COPY,
+            ACTION_KEYBOARD_DELETE,
+            ACTION_KEYBOARD_SELECT_ALL,
+            ACTION_KEYBOARD_BACK,
+            ACTION_KEYBOARD_SWITCH_FOCUS
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface Provider {}
+    public @interface KeyboardAction {}
+
+    // Codes representing different actions to open the drawer. They are used for bucketing stats in
+    // the COUNT_DRAWER_OPENED histogram.
+    // Do not change or rearrange these values, that will break historical data. Only add to the
+    // list.
+    // Do not use negative numbers or zero; clearcut only handles positive integers.
+    private static final int DRAWER_OPENED_HAMBURGER = 1;
+    private static final int DRAWER_OPENED_SWIPE = 2;
+
+    @IntDef(flag = true, value = {
+            DRAWER_OPENED_HAMBURGER,
+            DRAWER_OPENED_SWIPE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DrawerTrigger {}
 
     /**
      * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
@@ -244,9 +353,6 @@
             case State.ACTION_GET_CONTENT:
                 logHistogram(context, COUNT_GET_CONTENT_MIME, sanitizeMime(intent.getType()));
                 break;
-            case State.ACTION_MANAGE:
-                logHistogram(context, COUNT_MANAGE_ROOT, sanitizeRoot(uri));
-                break;
             case State.ACTION_BROWSE:
                 logHistogram(context, COUNT_BROWSE_ROOT, sanitizeRoot(uri));
                 break;
@@ -285,6 +391,20 @@
     }
 
     /**
+     * Logs a drawer opened event. Call this when the user opens drawer by swipe or by clicking the
+     * hamburger icon.
+     * @param context
+     * @param trigger type of action that opened the drawer
+     */
+    public static void logDrawerOpened(Context context, @DrawerController.Trigger int trigger) {
+        if (trigger == DrawerController.OPENED_HAMBURGER) {
+            logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_HAMBURGER);
+        } else if (trigger == DrawerController.OPENED_SWIPE) {
+            logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_SWIPE);
+        }
+    }
+
+    /**
      * Logs file operation stats. Call this when a file operation has completed. The given
      * DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one
      * provider to another vs copying within a given provider).  No PII is logged.
@@ -315,6 +435,28 @@
     }
 
     /**
+     * Logs create directory operation. It is a part of file operation stats. We do not
+     * differentiate between internal and external locations, all create directory operations are
+     * logged under COUNT_FILEOP_SYSTEM. Call this when a create directory operation has completed.
+     *
+     * @param context
+     */
+    public static void logCreateDirOperation(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR);
+    }
+
+    /**
+     * Logs rename file operation. It is a part of file operation stats. We do not differentiate
+     * between internal and external locations, all rename operations are logged under
+     * COUNT_FILEOP_SYSTEM. Call this when a rename file operation has completed.
+     *
+     * @param context
+     */
+    public static void logRenameFileOperation(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME);
+    }
+
+    /**
      * Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete)
      * fails.
      *
@@ -347,7 +489,29 @@
     }
 
     /**
-     * Log the cancellation of a file operation.  Call this when a Job is canceled.
+     * Logs create directory operation error. We do not differentiate between internal and external
+     * locations, all create directory errors are logged under COUNT_FILEOP_SYSTEM. Call this when a
+     * create directory operation fails.
+     *
+     * @param context
+     */
+    public static void logCreateDirError(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR);
+    }
+
+    /**
+     * Logs rename file operation error. We do not differentiate between internal and external
+     * locations, all rename errors are logged under COUNT_FILEOP_SYSTEM. Call this
+     * when a rename file operation fails.
+     *
+     * @param context
+     */
+    public static void logRenameFileError(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME_ERROR);
+    }
+
+    /**
+     * Logs the cancellation of a file operation.  Call this when a Job is canceled.
      * @param context
      * @param operationType
      */
@@ -355,6 +519,44 @@
         logHistogram(context, COUNT_FILEOP_CANCELED, toMetricsOpType(operationType));
     }
 
+    /**
+     * Logs keyboard shortcut actions. Since keyboard shortcuts have their corresponding menu items,
+     * they are identified by menu item resource id for convenience.
+     * @param context
+     * @param keyCode
+     */
+    public static void logKeyboardAction(Context context, @KeyboardAction int action) {
+        logHistogram(context, COUNT_KEYBOARD_ACTION, action);
+    }
+
+    /**
+     * Logs startup time in milliseconds.
+     * @param context
+     * @param startupMs Startup time in milliseconds.
+     */
+    public static void logStartupMs(Context context, int startupMs) {
+        logHistogram(context, COUNT_STARTUP_MS, startupMs);
+    }
+
+    /**
+     * Logs a drag and drop action. Call this when the user drops the content triggering copy.
+     * operation.
+     *
+     * @param context
+     */
+    public static void logDragNDrop(Context context) {
+        logCount(context, COUNT_DRAG_N_DROP);
+    }
+
+    /**
+     * Logs a search. Call this when the search operation is finished.
+     *
+     * @param context
+     */
+    public static void logSearch(Context context) {
+        logCount(context, COUNT_SEARCH);
+    }
+
     private static void logInterProviderFileOps(
             Context context,
             String histogram,
@@ -363,7 +565,7 @@
         if (operationType == FileOperationService.OPERATION_DELETE) {
             logHistogram(context, histogram, FILEOP_DELETE);
         } else {
-            checkArgument(dst != null);
+            assert(dst != null);
             @Provider int providerType =
                     isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL;
             logHistogram(context, histogram, getOpCode(operationType, providerType));
@@ -377,6 +579,171 @@
         logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA));
     }
 
+    // Types for logInvalidScopedAccessRequest
+    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS =
+            "scoped_directory_access_invalid_args";
+    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY =
+            "scoped_directory_access_invalid_dir";
+    public static final String SCOPED_DIRECTORY_ACCESS_ERROR =
+            "scoped_directory_access_error";
+
+    @StringDef(value = {
+            SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS,
+            SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY,
+            SCOPED_DIRECTORY_ACCESS_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InvalidScopedAccess{}
+
+    public static void logInvalidScopedAccessRequest(Context context,
+            @InvalidScopedAccess String type) {
+        MetricsLogger.count(context, type, 1);
+        switch (type) {
+            case SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS:
+            case SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY:
+            case SCOPED_DIRECTORY_ACCESS_ERROR:
+                MetricsLogger.count(context, type, 1);
+                break;
+            default:
+                Log.wtf(TAG, "invalid InvalidScopedAccess: " + type);
+        }
+    }
+
+    // Types for logValidScopedAccessRequest
+    public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED = 0;
+    public static final int SCOPED_DIRECTORY_ACCESS_GRANTED = 1;
+    public static final int SCOPED_DIRECTORY_ACCESS_DENIED = 2;
+    public static final int SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST = 3;
+    public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED = 4;
+
+    @IntDef(flag = true, value = {
+            SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED,
+            SCOPED_DIRECTORY_ACCESS_GRANTED,
+            SCOPED_DIRECTORY_ACCESS_DENIED,
+            SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST,
+            SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScopedAccessGrant {}
+
+    public static void logValidScopedAccessRequest(Activity activity, String directory,
+            @ScopedAccessGrant int type) {
+        int index = -1;
+        if (OpenExternalDirectoryActivity.DIRECTORY_ROOT.equals(directory)) {
+            index = -2;
+        } else {
+            for (int i = 0; i < STANDARD_DIRECTORIES.length; i++) {
+                if (STANDARD_DIRECTORIES[i].equals(directory)) {
+                    index = i;
+                    break;
+                }
+            }
+        }
+        final String packageName = activity.getCallingPackage();
+        switch (type) {
+            case SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_GRANTED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_DENIED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_FOLDER, index);
+                break;
+            default:
+                Log.wtf(TAG, "invalid ScopedAccessGrant: " + type);
+        }
+    }
+
+    /**
+     * Logs menu action that was selected by user.
+     * @param context
+     * @param id Resource id of the menu item.
+     */
+    public static void logMenuAction(Context context, int id) {
+        @MenuAction int menuAction = ACTION_MENU_OTHER;
+        switch (id) {
+            case R.id.menu_grid:
+                menuAction = ACTION_MENU_GRID;
+                break;
+            case R.id.menu_list:
+                menuAction = ACTION_MENU_LIST;
+                break;
+            case R.id.menu_sort:
+                menuAction = ACTION_MENU_SORT;
+                break;
+            case R.id.menu_sort_name:
+                menuAction = ACTION_MENU_SORT_NAME;
+                break;
+            case R.id.menu_sort_date:
+                menuAction = ACTION_MENU_SORT_DATE;
+                break;
+            case R.id.menu_sort_size:
+                menuAction = ACTION_MENU_SORT_SIZE;
+                break;
+            case R.id.menu_search:
+                menuAction = ACTION_MENU_SEARCH;
+                break;
+            case R.id.menu_file_size:
+                menuAction = ACTION_MENU_SHOW_SIZE;
+                break;
+            case R.id.menu_settings:
+                menuAction = ACTION_MENU_SETTINGS;
+                break;
+            case R.id.menu_copy_to:
+                menuAction = ACTION_MENU_COPY_TO;
+                break;
+            case R.id.menu_move_to:
+                menuAction = ACTION_MENU_MOVE_TO;
+                break;
+            case R.id.menu_delete:
+                menuAction = ACTION_MENU_DELETE;
+                break;
+            case R.id.menu_rename:
+                menuAction = ACTION_MENU_RENAME;
+                break;
+            case R.id.menu_create_dir:
+                menuAction = ACTION_MENU_CREATE_DIR;
+                break;
+            case R.id.menu_select_all:
+                menuAction = ACTION_MENU_SELECT_ALL;
+                break;
+            case R.id.menu_share:
+                menuAction = ACTION_MENU_SHARE;
+                break;
+            case R.id.menu_open:
+                menuAction = ACTION_MENU_OPEN;
+                break;
+            case R.id.menu_advanced:
+                menuAction = ACTION_MENU_ADVANCED;
+                break;
+            default:
+                break;
+        }
+        logHistogram(context, COUNT_MENU_ACTION, menuAction);
+    }
+
     /**
      * Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
      *
@@ -395,7 +762,7 @@
      * @param name The name of the histogram.
      * @param bucket The bucket to increment.
      */
-    private static void logHistogram(Context context, String name, int bucket) {
+    private static void logHistogram(Context context, String name, @ActionType int bucket) {
         if (DEBUG) Log.d(TAG, name + ": " + bucket);
         MetricsLogger.histogram(context, name, bucket);
     }
@@ -561,8 +928,6 @@
                 return ACTION_GET_CONTENT;
             case State.ACTION_OPEN_TREE:
                 return ACTION_OPEN_TREE;
-            case State.ACTION_MANAGE:
-                return ACTION_MANAGE;
             case State.ACTION_BROWSE:
                 return ACTION_BROWSE;
             case State.ACTION_PICK_COPY_DESTINATION:
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 9df55a0..2f202e7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -16,12 +16,15 @@
 
 package com.android.documentsui;
 
+import android.annotation.Nullable;
+
 import com.android.documentsui.model.DocumentInfo;
 import com.android.internal.util.Predicate;
 
 public class MimePredicate implements Predicate<DocumentInfo> {
     private final String[] mFilters;
 
+    private static final String APK_TYPE = "application/vnd.android.package-archive";
     /**
      * MIME types that are visual in nature. For example, they should always be
      * shown as thumbnails in list mode.
@@ -92,4 +95,8 @@
             return false;
         }
     }
+
+    public static boolean isApkType(@Nullable String mimeType) {
+        return APK_TYPE.equals(mimeType);
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index 4cba135..f6fe47b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -19,7 +19,6 @@
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_LEAVE;
 
 import android.annotation.Nullable;
 import android.graphics.drawable.Drawable;
@@ -30,10 +29,10 @@
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.BaseAdapter;
-import android.widget.ImageView;
 import android.widget.Spinner;
 import android.widget.TextView;
 
+import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
 
@@ -92,7 +91,7 @@
 
     private void onNavigationIconClicked() {
         if (mDrawer.isPresent()) {
-            mDrawer.setOpen(true);
+            mDrawer.setOpen(true, DrawerController.OPENED_HAMBURGER);
         }
     }
 
@@ -105,7 +104,7 @@
         while (mState.stack.size() > position + 1) {
             mState.popDocument();
         }
-        mEnv.refreshCurrentRootAndDirectory(ANIM_LEAVE);
+        mEnv.refreshCurrentRootAndDirectory(AnimationView.ANIM_LEAVE);
     }
 
     void update() {
@@ -220,17 +219,14 @@
                         .inflate(R.layout.item_subdir, parent, false);
             }
 
-            final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
             final DocumentInfo doc = getItem(position);
 
             if (position == 0) {
                 final RootInfo root = mEnv.getCurrentRoot();
                 title.setText(root.title);
-                subdir.setVisibility(View.GONE);
             } else {
                 title.setText(doc.displayName);
-                subdir.setVisibility(View.VISIBLE);
             }
 
             return convertView;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
index 025faea..854be0b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -17,22 +17,40 @@
 package com.android.documentsui;
 
 import static android.os.Environment.isStandardDirectory;
+import static android.os.Environment.STANDARD_DIRECTORIES;
 import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
 import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
+import static com.android.documentsui.LocalPreferences.getScopedAccessPermissionStatus;
+import static com.android.documentsui.LocalPreferences.PERMISSION_ASK;
+import static com.android.documentsui.LocalPreferences.PERMISSION_ASK_AGAIN;
+import static com.android.documentsui.LocalPreferences.PERMISSION_NEVER_ASK;
+import static com.android.documentsui.LocalPreferences.setScopedAccessPermissionStatus;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_DENIED;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ERROR;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_GRANTED;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY;
+import static com.android.documentsui.Metrics.logInvalidScopedAccessRequest;
+import static com.android.documentsui.Metrics.logValidScopedAccessRequest;
 import static com.android.documentsui.Shared.DEBUG;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.content.ContentProviderClient;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
+import android.content.UriPermission;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
@@ -46,6 +64,11 @@
 import android.provider.DocumentsContract;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.TextView;
 
 import java.io.File;
 import java.io.IOException;
@@ -61,14 +84,26 @@
     private static final String EXTRA_FILE = "com.android.documentsui.FILE";
     private static final String EXTRA_APP_LABEL = "com.android.documentsui.APP_LABEL";
     private static final String EXTRA_VOLUME_LABEL = "com.android.documentsui.VOLUME_LABEL";
+    private static final String EXTRA_VOLUME_UUID = "com.android.documentsui.VOLUME_UUID";
+    private static final String EXTRA_IS_ROOT = "com.android.documentsui.IS_ROOT";
+    private static final String EXTRA_IS_PRIMARY = "com.android.documentsui.IS_PRIMARY";
+    // Special directory name representing the full volume
+    static final String DIRECTORY_ROOT = "ROOT_DIRECTORY";
+
+    private ContentProviderClient mExternalStorageClient;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            if (DEBUG) Log.d(TAG, "activity.onCreateDialog(): reusing instance");
+            return;
+        }
 
         final Intent intent = getIntent();
         if (intent == null) {
             if (DEBUG) Log.d(TAG, "missing intent");
+            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
             setResult(RESULT_CANCELED);
             finish();
             return;
@@ -78,79 +113,126 @@
             if (DEBUG)
                 Log.d(TAG, "extra " + EXTRA_STORAGE_VOLUME + " is not a StorageVolume: "
                         + storageVolume);
+            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
             setResult(RESULT_CANCELED);
             finish();
             return;
         }
-        final String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME);
+        String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME );
         if (directoryName == null) {
-            if (DEBUG) Log.d(TAG, "missing extra " + EXTRA_DIRECTORY_NAME + " on " + intent);
+            directoryName = DIRECTORY_ROOT;
+        }
+        final StorageVolume volume = (StorageVolume) storageVolume;
+        if (getScopedAccessPermissionStatus(getApplicationContext(), getCallingPackage(),
+                volume.getUuid(), directoryName) == PERMISSION_NEVER_ASK) {
+            logValidScopedAccessRequest(this, directoryName,
+                    SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED);
             setResult(RESULT_CANCELED);
             finish();
             return;
         }
 
         final int userId = UserHandle.myUserId();
-        if (!showFragment(this, userId, (StorageVolume) storageVolume, directoryName)) {
+        if (!showFragment(this, userId, volume, directoryName)) {
             setResult(RESULT_CANCELED);
             finish();
             return;
         }
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mExternalStorageClient != null) {
+            mExternalStorageClient.close();
+        }
+    }
+
     /**
      * Validates the given path (volume + directory) and display the appropriate dialog asking the
      * user to grant access to it.
      */
-    private static boolean showFragment(Activity activity, int userId, StorageVolume storageVolume,
-            String directoryName) {
+    private static boolean showFragment(OpenExternalDirectoryActivity activity, int userId,
+            StorageVolume storageVolume, String directoryName) {
         if (DEBUG)
             Log.d(TAG, "showFragment() for volume " + storageVolume.dump() + ", directory "
                     + directoryName + ", and user " + userId);
+        final boolean isRoot = directoryName.equals(DIRECTORY_ROOT);
+        final boolean isPrimary = storageVolume.isPrimary();
+
+        if (isRoot && isPrimary) {
+            if (DEBUG) Log.d(TAG, "root access requested on primary volume");
+            return false;
+        }
+
+        final File volumeRoot = storageVolume.getPathFile();
         File file;
         try {
-            file = new File(storageVolume.getPathFile(), directoryName).getCanonicalFile();
+            file = isRoot ? volumeRoot : new File(volumeRoot, directoryName).getCanonicalFile();
         } catch (IOException e) {
             Log.e(TAG, "Could not get canonical file for volume " + storageVolume.dump()
                     + " and directory " + directoryName);
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             return false;
         }
         final StorageManager sm =
                 (StorageManager) activity.getSystemService(Context.STORAGE_SERVICE);
 
-        final String root = file.getParent();
-        final String directory = file.getName();
-
-        // Verify directory is valid.
-        if (TextUtils.isEmpty(directory) || !isStandardDirectory(directory)) {
-            if (DEBUG)
-                Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
-                        + file.getAbsolutePath() + "')");
-            return false;
+        final String root, directory;
+        if (isRoot) {
+            root = volumeRoot.getAbsolutePath();
+            directory = ".";
+        } else {
+            root = file.getParent();
+            directory = file.getName();
+            // Verify directory is valid.
+            if (TextUtils.isEmpty(directory) || !isStandardDirectory(directory)) {
+                if (DEBUG)
+                    Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
+                            + file.getAbsolutePath() + "')");
+                logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY);
+                return false;
+            }
         }
 
-        // Gets volume label and converted path
+        // Gets volume label and converted path.
         String volumeLabel = null;
+        String volumeUuid = null;
         final List<VolumeInfo> volumes = sm.getVolumes();
         if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
+        File internalRoot = null;
         for (VolumeInfo volume : volumes) {
             if (isRightVolume(volume, root, userId)) {
-                final File internalRoot = volume.getInternalPathForUser(userId);
+                internalRoot = volume.getInternalPathForUser(userId);
                 // Must convert path before calling getDocIdForFileCreateNewDir()
                 if (DEBUG) Log.d(TAG, "Converting " + root + " to " + internalRoot);
-                file = new File(internalRoot, directory);
+                file = isRoot ? internalRoot : new File(internalRoot, directory);
                 volumeLabel = sm.getBestVolumeDescription(volume);
+                volumeUuid = volume.getFsUuid();
                 break;
             }
         }
+
+        // Checks if the user has granted the permission already.
+        final Intent intent = getIntentForExistingPermission(activity, isRoot, internalRoot, file);
+        if (intent != null) {
+            logValidScopedAccessRequest(activity, directory,
+                    SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED);
+            activity.setResult(RESULT_OK, intent);
+            activity.finish();
+            return true;
+        }
+
         if (volumeLabel == null) {
             Log.e(TAG, "Could not get volume for " + file);
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             return false;
         }
 
         // Gets the package label.
         final String appLabel = getAppLabel(activity);
         if (appLabel == null) {
+            // Error already logged.
             return false;
         }
 
@@ -158,7 +240,10 @@
         final Bundle args = new Bundle();
         args.putString(EXTRA_FILE, file.getAbsolutePath());
         args.putString(EXTRA_VOLUME_LABEL, volumeLabel);
+        args.putString(EXTRA_VOLUME_UUID, volumeUuid);
         args.putString(EXTRA_APP_LABEL, appLabel);
+        args.putBoolean(EXTRA_IS_ROOT, isRoot);
+        args.putBoolean(EXTRA_IS_PRIMARY, isPrimary);
 
         final FragmentManager fm = activity.getFragmentManager();
         final FragmentTransaction ft = fm.beginTransaction();
@@ -177,6 +262,7 @@
         try {
             return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString();
         } catch (NameNotFoundException e) {
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             Log.w(TAG, "Could not get label for package " + packageName);
             return null;
         }
@@ -196,7 +282,7 @@
         return volume.isVisibleForWrite(userId) && root.equals(path);
     }
 
-    private static Intent createGrantedUriPermissionsIntent(ContentProviderClient provider,
+    private static Uri getGrantedUriPermission(Context context, ContentProviderClient provider,
             File file) {
         // Calls ExternalStorageProvider to get the doc id for the file
         final Bundle bundle;
@@ -204,22 +290,33 @@
             bundle = provider.call("getDocIdForFileCreateNewDir", file.getPath(), null);
         } catch (RemoteException e) {
             Log.e(TAG, "Did not get doc id from External Storage provider for " + file, e);
+            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
             return null;
         }
         final String docId = bundle == null ? null : bundle.getString("DOC_ID");
         if (docId == null) {
             Log.e(TAG, "Did not get doc id from External Storage provider for " + file);
+            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
             return null;
         }
-        Log.d(TAG, "doc id for " + file + ": " + docId);
+        if (DEBUG) Log.d(TAG, "doc id for " + file + ": " + docId);
 
         final Uri uri = DocumentsContract.buildTreeDocumentUri(EXTERNAL_STORAGE_AUTH, docId);
         if (uri == null) {
             Log.e(TAG, "Could not get URI for doc id " + docId);
             return null;
         }
-
         if (DEBUG) Log.d(TAG, "URI for " + file + ": " + uri);
+        return uri;
+    }
+
+    private static Intent createGrantedUriPermissionsIntent(Context context,
+            ContentProviderClient provider, File file) {
+        final Uri uri = getGrantedUriPermission(context, provider, file);
+        return createGrantedUriPermissionsIntent(uri);
+    }
+
+    private static Intent createGrantedUriPermissionsIntent(Uri uri) {
         final Intent intent = new Intent();
         intent.setData(uri);
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
@@ -229,81 +326,170 @@
         return intent;
     }
 
+    private static Intent getIntentForExistingPermission(OpenExternalDirectoryActivity activity,
+            boolean isRoot, File root, File file) {
+        final String packageName = activity.getCallingPackage();
+        final ContentProviderClient storageClient = activity.getExternalStorageClient();
+        final Uri grantedUri = getGrantedUriPermission(activity, storageClient, file);
+        final Uri rootUri = root.equals(file) ? grantedUri
+                : getGrantedUriPermission(activity, storageClient, root);
+
+        if (DEBUG)
+            Log.d(TAG, "checking if " + packageName + " already has permission for " + grantedUri
+                    + " or its root (" + rootUri + ")");
+        final ActivityManager am =
+                (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
+        for (UriPermission uriPermission : am.getGrantedUriPermissions(packageName).getList()) {
+            final Uri uri = uriPermission.getUri();
+            if (uri == null) {
+                Log.w(TAG, "null URI for " + uriPermission);
+                continue;
+            }
+            if (uri.equals(grantedUri) || uri.equals(rootUri)) {
+                if (DEBUG) Log.d(TAG, packageName + " already has permission: " + uriPermission);
+                return createGrantedUriPermissionsIntent(grantedUri);
+            }
+        }
+        if (DEBUG) Log.d(TAG, packageName + " does not have permission for " + grantedUri);
+        return null;
+    }
+
     public static class OpenExternalDirectoryDialogFragment extends DialogFragment {
 
         private File mFile;
+        private String mVolumeUuid;
         private String mVolumeLabel;
         private String mAppLabel;
-        private ContentProviderClient mExternalStorageClient;
-        private ContentResolver mResolver;
+        private boolean mIsRoot;
+        private boolean mIsPrimary;
+        private CheckBox mDontAskAgain;
+        private OpenExternalDirectoryActivity mActivity;
+        private AlertDialog mDialog;
 
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
+            setRetainInstance(true);
             final Bundle args = getArguments();
             if (args != null) {
                 mFile = new File(args.getString(EXTRA_FILE));
+                mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);
                 mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL);
                 mAppLabel = args.getString(EXTRA_APP_LABEL);
-                mResolver = getContext().getContentResolver();
+                mIsRoot = args.getBoolean(EXTRA_IS_ROOT);
+                mIsPrimary= args.getBoolean(EXTRA_IS_PRIMARY);
             }
+            mActivity = (OpenExternalDirectoryActivity) getActivity();
         }
 
         @Override
-        public void onDestroy() {
-            super.onDestroy();
-            if (mExternalStorageClient != null) {
-                mExternalStorageClient.close();
+        public void onDestroyView() {
+            // Workaround for https://code.google.com/p/android/issues/detail?id=17423
+            if (mDialog != null && getRetainInstance()) {
+                mDialog.setDismissMessage(null);
             }
+            super.onDestroyView();
         }
 
         @Override
         public Dialog onCreateDialog(Bundle savedInstanceState) {
-            final String folder = mFile.getName();
-            final Activity activity = getActivity();
+            if (mDialog != null) {
+                if (DEBUG) Log.d(TAG, "fragment.onCreateDialog(): reusing dialog");
+                return mDialog;
+            }
+            if (mActivity != getActivity()) {
+                // Sanity check.
+                Log.wtf(TAG, "activity references don't match on onCreateDialog(): mActivity = "
+                        + mActivity + " , getActivity() = " + getActivity());
+                mActivity = (OpenExternalDirectoryActivity) getActivity();
+            }
+            final String directory = mFile.getName();
+            final String directoryName = mIsRoot ? DIRECTORY_ROOT : directory;
+            final Context context = mActivity.getApplicationContext();
             final OnClickListener listener = new OnClickListener() {
 
                 @Override
                 public void onClick(DialogInterface dialog, int which) {
                     Intent intent = null;
                     if (which == DialogInterface.BUTTON_POSITIVE) {
-                        intent = createGrantedUriPermissionsIntent(getExternalStorageClient(),
-                                mFile);
+                        intent = createGrantedUriPermissionsIntent(mActivity,
+                                mActivity.getExternalStorageClient(), mFile);
                     }
                     if (which == DialogInterface.BUTTON_NEGATIVE || intent == null) {
-                        activity.setResult(RESULT_CANCELED);
+                        logValidScopedAccessRequest(mActivity, directoryName,
+                                SCOPED_DIRECTORY_ACCESS_DENIED);
+                        final boolean checked = mDontAskAgain.isChecked();
+                        if (checked) {
+                            logValidScopedAccessRequest(mActivity, directory,
+                                    SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST);
+                            setScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
+                                    mVolumeUuid, directoryName, PERMISSION_NEVER_ASK);
+                        } else {
+                            setScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
+                                    mVolumeUuid, directoryName, PERMISSION_ASK_AGAIN);
+                        }
+                        mActivity.setResult(RESULT_CANCELED);
                     } else {
-                        activity.setResult(RESULT_OK, intent);
+                        logValidScopedAccessRequest(mActivity, directory,
+                                SCOPED_DIRECTORY_ACCESS_GRANTED);
+                        mActivity.setResult(RESULT_OK, intent);
                     }
-                    activity.finish();
+                    mActivity.finish();
                 }
             };
 
-            final CharSequence message = TextUtils
-                    .expandTemplate(
-                            getText(R.string.open_external_dialog_request), mAppLabel, folder,
-                            mVolumeLabel);
-            return new AlertDialog.Builder(activity, R.style.AlertDialogTheme)
-                    .setMessage(message)
+            @SuppressLint("InflateParams")
+            // It's ok pass null ViewRoot on AlertDialogs.
+            final View view = View.inflate(mActivity, R.layout.dialog_open_scoped_directory, null);
+            final CharSequence message;
+            if (mIsRoot) {
+                message = TextUtils.expandTemplate(getText(
+                        R.string.open_external_dialog_root_request), mAppLabel, mVolumeLabel);
+            } else {
+                message = TextUtils.expandTemplate(
+                        getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
+                                : R.string.open_external_dialog_request),
+                        mAppLabel, directory, mVolumeLabel);
+            }
+            final TextView messageField = (TextView) view.findViewById(R.id.message);
+            messageField.setText(message);
+            mDialog = new AlertDialog.Builder(mActivity, R.style.Theme_AppCompat_Light_Dialog_Alert)
+                    .setView(view)
                     .setPositiveButton(R.string.allow, listener)
                     .setNegativeButton(R.string.deny, listener)
                     .create();
+
+            mDontAskAgain = (CheckBox) view.findViewById(R.id.do_not_ask_checkbox);
+            if (getScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
+                    mVolumeUuid, directoryName) == PERMISSION_ASK_AGAIN) {
+                mDontAskAgain.setVisibility(View.VISIBLE);
+                mDontAskAgain.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+                    @Override
+                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                        mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!isChecked);
+                    }
+                });
+            }
+
+            return mDialog;
         }
 
         @Override
         public void onCancel(DialogInterface dialog) {
             super.onCancel(dialog);
             final Activity activity = getActivity();
+            logValidScopedAccessRequest(activity, mFile.getName(), SCOPED_DIRECTORY_ACCESS_DENIED);
             activity.setResult(RESULT_CANCELED);
             activity.finish();
         }
+    }
 
-        private synchronized ContentProviderClient getExternalStorageClient() {
-            if (mExternalStorageClient == null) {
-                mExternalStorageClient =
-                        mResolver.acquireContentProviderClient(EXTERNAL_STORAGE_AUTH);
-            }
-            return mExternalStorageClient;
+    private synchronized ContentProviderClient getExternalStorageClient() {
+        if (mExternalStorageClient == null) {
+            mExternalStorageClient =
+                    getContentResolver().acquireContentProviderClient(EXTERNAL_STORAGE_AUTH);
         }
+        return mExternalStorageClient;
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 32543c8..933506c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -19,7 +19,6 @@
 import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -101,7 +100,8 @@
      */
     public void setPickTarget(
             int action, @OpType int copyOperationSubType, DocumentInfo pickTarget) {
-        checkArgument(copyOperationSubType != OPERATION_DELETE);
+        assert(copyOperationSubType != OPERATION_DELETE);
+
         mAction = action;
         mCopyOperationSubType = copyOperationSubType;
         mPickTarget = pickTarget;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
index b0e332f..8145edc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
@@ -19,7 +19,6 @@
 import android.os.AsyncTask;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -85,7 +84,7 @@
     private Executor mNonPreemptingExecutor = new Executor() {
         @Override
         public void execute(Runnable command) {
-            Preconditions.checkNotNull(command);
+            assert(command != null);
             mQueue.add(command);
         }
     };
@@ -93,7 +92,7 @@
     @Override
     public void execute(Runnable command) {
         preempt();
-        Preconditions.checkNotNull(command);
+        assert(command != null);
         mQueue.add(command);
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index a77a9b3..8fcd9d1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -113,8 +113,8 @@
     }
 
     private int collectViewableUris(ArrayList<Uri> uris) {
-        final List<String> siblingIds = mModel.getModelIds();
-        uris.ensureCapacity(siblingIds.size());
+        final String[] siblingIds = mModel.getModelIds();
+        uris.ensureCapacity(siblingIds.length);
 
         int documentLocation = 0;
         Cursor cursor;
@@ -124,8 +124,8 @@
         Uri uri;
 
         // Cursor's are not guaranteed to be immutable. Hence, traverse it only once.
-        for (int i = 0; i < siblingIds.size(); i++) {
-            cursor = mModel.getItem(siblingIds.get(i));
+        for (int i = 0; i < siblingIds.length; i++) {
+            cursor = mModel.getItem(siblingIds[i]);
 
             mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
             if (Document.MIME_TYPE_DIR.equals(mimeType)) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 92ffb93..6ef9154 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
 import android.content.ContentProvider;
@@ -95,6 +96,7 @@
         public static final String PACKAGE_NAME = "package_name";
         public static final String STACK = "stack";
         public static final String TIMESTAMP = "timestamp";
+        // Indicates handler was an external app, like photos.
         public static final String EXTERNAL = "external";
     }
 
@@ -337,7 +339,7 @@
                 if (predicate.apply(authority)) {
                     db.delete(TABLE_STATE, StateColumns.AUTHORITY + "=?", new String[] {
                             authority });
-                    Log.d(TAG, "Purged state for " + authority);
+                    if (DEBUG) Log.d(TAG, "Purged state for " + authority);
                 }
             }
         } finally {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java b/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java
deleted file mode 100644
index 9048b9d..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.documentsui;
-
-import android.net.Uri;
-import android.provider.DocumentsContract;
-import android.util.Log;
-
-import com.android.documentsui.model.RootInfo;
-
-final class RestoreRootTask extends PairedTask<BaseActivity, Void, RootInfo> {
-    private static final String TAG = "RestoreRootTask";
-
-    private final Uri mRootUri;
-
-    public RestoreRootTask(BaseActivity activity, Uri rootUri) {
-        super(activity);
-        mRootUri = rootUri;
-    }
-
-    @Override
-    protected RootInfo run(Void... params) {
-        String rootId = DocumentsContract.getRootId(mRootUri);
-        return mOwner.mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
-    }
-
-    @Override
-    protected void finish(RootInfo root) {
-        mOwner.mState.restored = true;
-
-        if (root != null) {
-            mOwner.onRootPicked(root);
-        } else {
-            Log.w(TAG, "Failed to find root: " + mRootUri);
-            mOwner.finish();
-        }
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 216509d..594e02f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -17,9 +17,8 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.Shared.TAG;
-import static com.android.internal.util.Preconditions.checkState;
 
+import android.content.BroadcastReceiver.PendingResult;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -32,6 +31,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.provider.DocumentsContract;
@@ -41,13 +41,12 @@
 
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
+
+import libcore.io.IoUtils;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 
-import libcore.io.IoUtils;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -64,6 +63,8 @@
     public static final Uri sNotificationUri = Uri.parse(
             "content://com.android.documentsui.roots/");
 
+    private static final String TAG = "RootsCache";
+
     private final Context mContext;
     private final ContentObserver mObserver;
     private OnCacheUpdateListener mCacheUpdateListener;
@@ -74,6 +75,11 @@
     private final CountDownLatch mFirstLoad = new CountDownLatch(1);
 
     @GuardedBy("mLock")
+    private boolean mFirstLoadDone;
+    @GuardedBy("mLock")
+    private PendingResult mBootCompletedResult;
+
+    @GuardedBy("mLock")
     private Multimap<String, RootInfo> mRoots = ArrayListMultimap.create();
     @GuardedBy("mLock")
     private HashSet<String> mStoppedAuthorities = new HashSet<>();
@@ -90,7 +96,8 @@
                 // Special root for recents
                 derivedIcon = R.drawable.ic_root_recent;
                 derivedType = RootInfo.TYPE_RECENTS;
-                flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD;
+                flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD
+                        | Root.FLAG_SUPPORTS_CREATE;
                 title = mContext.getString(R.string.root_recent);
                 availableBytes = -1;
             }};
@@ -115,25 +122,32 @@
     /**
      * Gather roots from all known storage providers.
      */
-    public void updateAsync() {
-        // Verifying an assumption about the recents root being immutable.
-        if (DEBUG) {
-            checkState(mRecentsRoot.authority == null);
-            checkState(mRecentsRoot.rootId == null);
-            checkState(mRecentsRoot.derivedIcon == R.drawable.ic_root_recent);
-            checkState(mRecentsRoot.derivedType == RootInfo.TYPE_RECENTS);
-            checkState(mRecentsRoot.flags == (Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD));
-            checkState(mRecentsRoot.title == mContext.getString(R.string.root_recent));
-            checkState(mRecentsRoot.availableBytes == -1);
-        }
-        new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    public void updateAsync(boolean forceRefreshAll) {
+
+        // NOTE: This method is called when the UI language changes.
+        // For that reason we update our RecentsRoot to reflect
+        // the current language.
+        mRecentsRoot.title = mContext.getString(R.string.root_recent);
+
+        // Nothing else about the root should ever change.
+        assert(mRecentsRoot.authority == null);
+        assert(mRecentsRoot.rootId == null);
+        assert(mRecentsRoot.derivedIcon == R.drawable.ic_root_recent);
+        assert(mRecentsRoot.derivedType == RootInfo.TYPE_RECENTS);
+        assert(mRecentsRoot.flags == (Root.FLAG_LOCAL_ONLY
+                | Root.FLAG_SUPPORTS_IS_CHILD
+                | Root.FLAG_SUPPORTS_CREATE));
+        assert(mRecentsRoot.availableBytes == -1);
+
+        new UpdateTask(forceRefreshAll, null)
+                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     /**
      * Gather roots from storage providers belonging to given package name.
      */
     public void updatePackageAsync(String packageName) {
-        new UpdateTask(packageName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        new UpdateTask(false, packageName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     /**
@@ -146,7 +160,25 @@
         }
     }
 
-    private void waitForFirstLoad() {
+    public void setBootCompletedResult(PendingResult result) {
+        synchronized (mLock) {
+            // Quickly check if we've already finished loading, otherwise hang
+            // out until first pass is finished.
+            if (mFirstLoadDone) {
+                result.finish();
+            } else {
+                mBootCompletedResult = result;
+            }
+        }
+    }
+
+    /**
+     * Block until the first {@link UpdateTask} pass has finished.
+     *
+     * @return {@code true} if cached roots is ready to roll, otherwise
+     *         {@code false} if we timed out while waiting.
+     */
+    private boolean waitForFirstLoad() {
         boolean success = false;
         try {
             success = mFirstLoad.await(15, TimeUnit.SECONDS);
@@ -155,6 +187,7 @@
         if (!success) {
             Log.w(TAG, "Timeout waiting for first update");
         }
+        return success;
     }
 
     /**
@@ -166,7 +199,7 @@
         synchronized (mLock) {
             for (String authority : mStoppedAuthorities) {
                 if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority);
-                mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
+                mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
             }
             mStoppedAuthorities.clear();
         }
@@ -185,42 +218,35 @@
             if (DEBUG) {
                 Log.d(TAG, "Loading stopped authority " + authority);
             }
-            mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
+            mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
             mStoppedAuthorities.remove(authority);
         }
     }
 
     private class UpdateTask extends AsyncTask<Void, Void, Void> {
-        private final String mFilterPackage;
+        private final boolean mForceRefreshAll;
+        private final String mForceRefreshPackage;
 
         private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
         private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
 
         /**
-         * Update all roots.
+         * Create task to update roots cache.
+         *
+         * @param forceRefreshAll when true, all previously cached values for
+         *            all packages should be ignored.
+         * @param forceRefreshPackage when non-null, all previously cached
+         *            values for this specific package should be ignored.
          */
-        public UpdateTask() {
-            this(null);
-        }
-
-        /**
-         * Only update roots belonging to given package name. Other roots will
-         * be copied from cached {@link #mRoots} values.
-         */
-        public UpdateTask(String filterPackage) {
-            mFilterPackage = filterPackage;
+        public UpdateTask(boolean forceRefreshAll, String forceRefreshPackage) {
+            mForceRefreshAll = forceRefreshAll;
+            mForceRefreshPackage = forceRefreshPackage;
         }
 
         @Override
         protected Void doInBackground(Void... params) {
             final long start = SystemClock.elapsedRealtime();
 
-            if (mFilterPackage != null) {
-                // Need at least first load, since we're going to be using
-                // previously cached values for non-matching packages.
-                waitForFirstLoad();
-            }
-
             mTaskRoots.put(mRecentsRoot.authority, mRecentsRoot);
 
             final ContentResolver resolver = mContext.getContentResolver();
@@ -237,6 +263,11 @@
             if (DEBUG)
                 Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms");
             synchronized (mLock) {
+                mFirstLoadDone = true;
+                if (mBootCompletedResult != null) {
+                    mBootCompletedResult.finish();
+                    mBootCompletedResult = null;
+                }
                 mRoots = mTaskRoots;
                 mStoppedAuthorities = mTaskStoppedAuthorities;
             }
@@ -261,29 +292,18 @@
                 return;
             }
 
-            // Try using cached roots if filtering
-            boolean cacheHit = false;
-            if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
-                synchronized (mLock) {
-                    if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) {
-                        if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority);
-                        cacheHit = true;
-                    }
-                }
-            }
-
-            // Cache miss, or loading everything
-            if (!cacheHit) {
-                mTaskRoots.putAll(info.authority,
-                        loadRootsForAuthority(mContext.getContentResolver(), info.authority));
-            }
+            final boolean forceRefresh = mForceRefreshAll
+                    || Objects.equals(info.packageName, mForceRefreshPackage);
+            mTaskRoots.putAll(info.authority, loadRootsForAuthority(mContext.getContentResolver(),
+                    info.authority, forceRefresh));
         }
     }
 
     /**
      * Bring up requested provider and query for all active roots.
      */
-    private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) {
+    private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority,
+            boolean forceRefresh) {
         if (DEBUG) Log.d(TAG, "Loading roots for " + authority);
 
         synchronized (mObservedAuthorities) {
@@ -294,9 +314,18 @@
             }
         }
 
-        final List<RootInfo> roots = new ArrayList<>();
         final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
+        if (!forceRefresh) {
+            // Look for roots data that we might have cached for ourselves in the
+            // long-lived system process.
+            final Bundle systemCache = resolver.getCache(rootsUri);
+            if (systemCache != null) {
+                if (DEBUG) Log.d(TAG, "System cache hit for " + authority);
+                return systemCache.getParcelableArrayList(TAG);
+            }
+        }
 
+        final ArrayList<RootInfo> roots = new ArrayList<>();
         ContentProviderClient client = null;
         Cursor cursor = null;
         try {
@@ -312,6 +341,14 @@
             IoUtils.closeQuietly(cursor);
             ContentProviderClient.releaseQuietly(client);
         }
+
+        // Cache these freshly parsed roots over in the long-lived system
+        // process, in case our process goes away. The system takes care of
+        // invalidating the cache if the package or Uri changes.
+        final Bundle systemCache = new Bundle();
+        systemCache.putParcelableArrayList(TAG, roots);
+        resolver.putCache(rootsUri, systemCache);
+
         return roots;
     }
 
@@ -324,8 +361,8 @@
         synchronized (mLock) {
             RootInfo root = getRootLocked(authority, rootId);
             if (root == null) {
-                mRoots.putAll(
-                        authority, loadRootsForAuthority(mContext.getContentResolver(), authority));
+                mRoots.putAll(authority,
+                        loadRootsForAuthority(mContext.getContentResolver(), authority, false));
                 root = getRootLocked(authority, rootId);
             }
             return root;
@@ -412,45 +449,69 @@
     static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
         final List<RootInfo> matching = new ArrayList<>();
         for (RootInfo root : roots) {
-            // Exclude read-only devices when creating
-            if (state.action == State.ACTION_CREATE && !root.supportsCreate()) continue;
-            if (state.action == State.ACTION_PICK_COPY_DESTINATION
-                    && !root.supportsCreate()) continue;
-            // Exclude roots that don't support directory picking
-            if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) continue;
-            // Exclude advanced devices when not requested
-            if (!state.showAdvanced && root.isAdvanced()) continue;
-            // Exclude non-local devices when local only
-            if (state.localOnly && !root.isLocalOnly()) continue;
-            // Exclude downloads roots as it doesn't support directory creation (actually
-            // we just don't show them).
-            // TODO: Add flag to check the root supports directory creation.
-            if (state.directoryCopy && !root.isDownloads()) continue;
 
-            // Only show empty roots when creating, or in browse mode.
-            if (root.isEmpty() && (state.action == State.ACTION_OPEN
-                    || state.action == State.ACTION_GET_CONTENT)) {
-                if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
+            if (DEBUG) Log.d(TAG, "Evaluating " + root);
+
+            if (state.action == State.ACTION_CREATE && !root.supportsCreate()) {
+                if (DEBUG) Log.d(TAG, "Excluding read-only root because: ACTION_CREATE.");
                 continue;
             }
 
-            // Only include roots that serve requested content
+            if (state.action == State.ACTION_PICK_COPY_DESTINATION
+                    && !root.supportsCreate()) {
+                if (DEBUG) Log.d(
+                        TAG, "Excluding read-only root because: ACTION_PICK_COPY_DESTINATION.");
+                continue;
+            }
+
+            if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) {
+                if (DEBUG) Log.d(
+                        TAG, "Excluding root !supportsChildren because: ACTION_OPEN_TREE.");
+                continue;
+            }
+
+            if (!state.showAdvanced && root.isAdvanced()) {
+                if (DEBUG) Log.d(TAG, "Excluding root because: unwanted advanced device.");
+                continue;
+            }
+
+            if (state.localOnly && !root.isLocalOnly()) {
+                if (DEBUG) Log.d(TAG, "Excluding root because: unwanted non-local device.");
+                continue;
+            }
+
+            if (state.directoryCopy && root.isDownloads()) {
+                if (DEBUG) Log.d(
+                        TAG, "Excluding downloads root because: unsupported directory copy.");
+                continue;
+            }
+
+            if (state.action == State.ACTION_OPEN && root.isEmpty()) {
+                if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_OPEN.");
+                continue;
+            }
+
+            if (state.action == State.ACTION_GET_CONTENT && root.isEmpty()) {
+                if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_GET_CONTENT.");
+                continue;
+            }
+
             final boolean overlap =
                     MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
                     MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
             if (!overlap) {
-                continue;
-            }
-
-            // Exclude roots from the calling package.
-            if (state.excludedAuthorities.contains(root.authority)) {
                 if (DEBUG) Log.d(
-                        TAG, "Excluding root " + root.authority + " from calling package.");
+                        TAG, "Excluding root because: unsupported content types > "
+                        + state.acceptMimes);
                 continue;
             }
 
-            if (DEBUG) Log.d(
-                    TAG, "Including root " + root + " in roots list.");
+            if (state.excludedAuthorities.contains(root.authority)) {
+                if (DEBUG) Log.d(TAG, "Excluding root because: owned by calling package.");
+                continue;
+            }
+
+            if (DEBUG) Log.d(TAG, "Including " + root);
             matching.add(root);
         }
         return matching;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 9f83c04..8bbcc30 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -18,6 +18,7 @@
 
 import static com.android.documentsui.Shared.DEBUG;
 
+import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
@@ -117,7 +118,7 @@
 
                 Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
 
-                mAdapter = new RootsAdapter(context, result, handlerAppIntent);
+                mAdapter = new RootsAdapter(context, result, handlerAppIntent, state);
                 mList.setAdapter(mAdapter);
 
                 onCurrentRootChanged();
@@ -308,8 +309,8 @@
          * @param handlerAppIntent When not null, apps capable of handling the original
          *     intent will be included in list of roots (in special section at bottom).
          */
-        public RootsAdapter(
-                Context context, Collection<RootInfo> roots, @Nullable Intent handlerAppIntent) {
+        public RootsAdapter(Context context, Collection<RootInfo> roots,
+                @Nullable Intent handlerAppIntent, State state) {
             super(context, 0);
 
             final List<RootItem> libraries = new ArrayList<>();
@@ -317,7 +318,11 @@
 
             for (final RootInfo root : roots) {
                 final RootItem item = new RootItem(root);
-                if (root.isLibrary()) {
+
+                if (root.isHome() &&
+                        !Shared.shouldShowDocumentsRoot(context, ((Activity) context).getIntent())) {
+                    continue;
+                } else if (root.isLibrary()) {
                     if (DEBUG) Log.d(TAG, "Adding " + root + " as library.");
                     libraries.add(item);
                 } else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java
deleted file mode 100644
index 69f54c7..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java
+++ /dev/null
@@ -1,210 +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.documentsui;
-
-import android.provider.DocumentsContract.Root;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.widget.SearchView;
-import android.widget.SearchView.OnQueryTextListener;
-
-import com.android.documentsui.model.RootInfo;
-
-/**
- * Manages searching UI behavior.
- */
-final class SearchManager implements
-        SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener {
-
-    public interface SearchManagerListener {
-        void onSearchChanged();
-
-        void onSearchQueryChanged(String query);
-    }
-
-    public static final String TAG = "SearchManger";
-
-    private SearchManagerListener mListener;
-    private String currentSearch;
-    private boolean mSearchExpanded;
-    private boolean mIgnoreNextClose;
-
-    private DocumentsToolbar mActionBar;
-    private MenuItem mMenu;
-    private SearchView mView;
-
-    public SearchManager(SearchManagerListener listener) {
-        mListener = listener;
-    }
-
-    public void setSearchMangerListener(SearchManagerListener listener) {
-        mListener = listener;
-    }
-
-    public void install(DocumentsToolbar actionBar) {
-        assert (mActionBar == null);
-        mActionBar = actionBar;
-        mMenu = actionBar.getSearchMenu();
-        mView = (SearchView) mMenu.getActionView();
-
-        mView.setOnQueryTextListener(this);
-        mView.setOnCloseListener(this);
-        mView.setOnSearchClickListener(this);
-        mView.setOnQueryTextFocusChangeListener(this);
-    }
-
-    /**
-     * @param root Info about the current directory.
-     */
-    void update(RootInfo root) {
-        if (mMenu == null) {
-            Log.d(TAG, "update called before Search MenuItem installed.");
-            return;
-        }
-
-        if (currentSearch != null) {
-            mMenu.expandActionView();
-
-            mView.setIconified(false);
-            mView.clearFocus();
-            mView.setQuery(currentSearch, false);
-        } else {
-            mView.clearFocus();
-            if (!mView.isIconified()) {
-                mIgnoreNextClose = true;
-                mView.setIconified(true);
-            }
-
-            if (mMenu.isActionViewExpanded()) {
-                mMenu.collapseActionView();
-            }
-        }
-
-        showMenu(root != null
-                && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0));
-    }
-
-    void showMenu(boolean visible) {
-        if (mMenu == null) {
-            Log.d(TAG, "showMenu called before Search MenuItem installed.");
-            return;
-        }
-
-        mMenu.setVisible(visible);
-        if (!visible) {
-            currentSearch = null;
-            if (mListener != null) {
-                mListener.onSearchQueryChanged(currentSearch);
-            }
-        }
-    }
-
-    /**
-     * Cancels current search operation. Triggers clearing and collapsing the SearchView.
-     *
-     * @return True if it cancels search. False if it does not operate search currently.
-     */
-    boolean cancelSearch() {
-        if (isExpanded() || isSearching()) {
-            // If the query string is not empty search view won't get iconified
-            mView.setQuery("", false);
-            // Causes calling onClose(). onClose() is triggering directory content update.
-            mView.setIconified(true);
-            return true;
-        }
-        return false;
-    }
-
-    boolean isSearching() {
-        return currentSearch != null;
-    }
-
-    boolean isExpanded() {
-        return mSearchExpanded;
-    }
-
-    /**
-     * Clears the search. Clears the SearchView background color. Triggers refreshing of the
-     * directory content.
-     * @return True if the default behavior of clearing/dismissing SearchView should be overridden.
-     *         False otherwise.
-     */
-    @Override
-    public boolean onClose() {
-        mSearchExpanded = false;
-        if (mIgnoreNextClose) {
-            mIgnoreNextClose = false;
-            return false;
-        }
-
-        mView.setBackgroundColor(
-                mView.getResources().getColor(android.R.color.transparent, null));
-
-        // Refresh the directory if a search was done
-        if (currentSearch != null) {
-            currentSearch = null;
-            if (mListener != null) {
-                mListener.onSearchQueryChanged(currentSearch);
-                mListener.onSearchChanged();
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Sets mSearchExpanded. Called when search icon is clicked to start search. Used to detect when
-     * the view expanded instead of onMenuItemActionExpand, because SearchView has showAsAction set
-     * to always and onMenuItemAction* methods are not called.
-     */
-    @Override
-    public void onClick(View v) {
-        mSearchExpanded = true;
-        mView.setBackgroundColor(
-                mView.getResources().getColor(R.color.menu_search_background, null));
-    }
-
-    @Override
-    public boolean onQueryTextSubmit(String query) {
-        currentSearch = query;
-        mView.clearFocus();
-        if (mListener != null) {
-            mListener.onSearchQueryChanged(currentSearch);
-            mListener.onSearchChanged();
-        }
-        return true;
-    }
-
-    @Override
-    public void onFocusChange(View v, boolean hasFocus) {
-        if (!hasFocus) {
-            if (currentSearch == null) {
-                mView.setIconified(true);
-            } else if (TextUtils.isEmpty(mView.getQuery())) {
-                cancelSearch();
-            }
-        }
-    }
-
-    @Override
-    public boolean onQueryTextChange(String newText) {
-        return false;
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
new file mode 100644
index 0000000..945ed34
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
@@ -0,0 +1,299 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.Shared.DEBUG;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.provider.DocumentsContract.Root;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnActionExpandListener;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.widget.SearchView;
+import android.widget.SearchView.OnQueryTextListener;
+
+import com.android.documentsui.model.RootInfo;
+
+/**
+ * Manages searching UI behavior.
+ */
+final class SearchViewManager implements
+        SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener,
+        OnActionExpandListener {
+
+    public interface SearchManagerListener {
+        void onSearchChanged(@Nullable String query);
+        void onSearchFinished();
+    }
+
+    public static final String TAG = "SearchManger";
+
+    private SearchManagerListener mListener;
+    private boolean mSearchExpanded;
+    private String mCurrentSearch;
+    private boolean mIgnoreNextClose;
+    private boolean mFullBar;
+
+    private DocumentsToolbar mActionBar;
+    private MenuItem mMenuItem;
+    private SearchView mSearchView;
+
+    public SearchViewManager(SearchManagerListener listener, @Nullable Bundle savedState) {
+        mListener = listener;
+        mCurrentSearch = savedState != null ? savedState.getString(Shared.EXTRA_QUERY) : null;
+    }
+
+    public void setSearchMangerListener(SearchManagerListener listener) {
+        mListener = listener;
+    }
+
+    public void install(DocumentsToolbar actionBar, boolean isFullBarSearch) {
+        mActionBar = actionBar;
+        mMenuItem = actionBar.getSearchMenu();
+        mSearchView = (SearchView) mMenuItem.getActionView();
+
+        mSearchView.setOnQueryTextListener(this);
+        mSearchView.setOnCloseListener(this);
+        mSearchView.setOnSearchClickListener(this);
+        mSearchView.setOnQueryTextFocusChangeListener(this);
+
+        mFullBar = isFullBarSearch;
+        if (mFullBar) {
+            mMenuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
+                    | MenuItem.SHOW_AS_ACTION_ALWAYS);
+            mMenuItem.setOnActionExpandListener(this);
+        }
+
+        restoreSearch();
+    }
+
+    /**
+     * Used to hide menu icons, when the search is being restored. Needed because search restoration
+     * is done before onPrepareOptionsMenu(Menu menu) that is overriding the icons visibility.
+     */
+    public void updateMenu() {
+        if (isSearching() && mFullBar) {
+            Menu menu = mActionBar.getMenu();
+            menu.setGroupVisible(R.id.group_hide_when_searching, false);
+        }
+    }
+
+    /**
+     * @param root Info about the current directory.
+     */
+    void update(RootInfo root) {
+        if (mMenuItem == null) {
+            if (DEBUG) Log.d(TAG, "update called before Search MenuItem installed.");
+            return;
+        }
+
+        if (mCurrentSearch != null) {
+            mMenuItem.expandActionView();
+
+            mSearchView.setIconified(false);
+            mSearchView.clearFocus();
+            mSearchView.setQuery(mCurrentSearch, false);
+        } else {
+            mSearchView.clearFocus();
+            if (!mSearchView.isIconified()) {
+                mIgnoreNextClose = true;
+                mSearchView.setIconified(true);
+            }
+
+            if (mMenuItem.isActionViewExpanded()) {
+                mMenuItem.collapseActionView();
+            }
+        }
+
+        showMenu(root != null
+                && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0));
+    }
+
+    void showMenu(boolean visible) {
+        if (mMenuItem == null) {
+            if (DEBUG) Log.d(TAG, "showMenu called before Search MenuItem installed.");
+            return;
+        }
+
+        if (!visible) {
+            mCurrentSearch = null;
+        }
+
+        mMenuItem.setVisible(visible);
+    }
+
+    /**
+     * Cancels current search operation. Triggers clearing and collapsing the SearchView.
+     *
+     * @return True if it cancels search. False if it does not operate search currently.
+     */
+    boolean cancelSearch() {
+        if (isExpanded() || isSearching()) {
+            // If the query string is not empty search view won't get iconified
+            mSearchView.setQuery("", false);
+
+            if (mFullBar) {
+               onClose();
+            } else {
+                // Causes calling onClose(). onClose() is triggering directory content update.
+                mSearchView.setIconified(true);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Sets search view into the searching state. Used to restore state after device orientation
+     * change.
+     */
+    private void restoreSearch() {
+        if (isSearching()) {
+            if(mFullBar) {
+                mMenuItem.expandActionView();
+            } else {
+                mSearchView.setIconified(false);
+            }
+            onSearchExpanded();
+            mSearchView.setQuery(mCurrentSearch, false);
+            mSearchView.clearFocus();
+        }
+    }
+
+    private void onSearchExpanded() {
+        mSearchExpanded = true;
+        if(mFullBar) {
+            Menu menu = mActionBar.getMenu();
+            menu.setGroupVisible(R.id.group_hide_when_searching, false);
+        } else {
+            // If search in full-bar mode it will be logged in FilesActivity#onOptionsItemSelected
+            Metrics.logMenuAction(mActionBar.getContext(), R.id.menu_search);
+        }
+    }
+
+    /**
+     * Clears the search. Triggers refreshing of the directory content.
+     * @return True if the default behavior of clearing/dismissing SearchView should be overridden.
+     *         False otherwise.
+     */
+    @Override
+    public boolean onClose() {
+        mSearchExpanded = false;
+        if (mIgnoreNextClose) {
+            mIgnoreNextClose = false;
+            return false;
+        }
+
+        // Refresh the directory if a search was done
+        if (mCurrentSearch != null) {
+            mCurrentSearch = null;
+            if (mListener != null) {
+                mListener.onSearchChanged(mCurrentSearch);
+            }
+        }
+
+        if(mFullBar) {
+            mMenuItem.collapseActionView();
+        }
+        mListener.onSearchFinished();
+
+        return false;
+    }
+
+    /**
+     * Called when owning activity is saving state to be used to restore state during creation.
+     * @param state Bundle to save state too
+     */
+    public void onSaveInstanceState(Bundle state) {
+        state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
+    }
+
+    /**
+     * Sets mSearchExpanded. Called when search icon is clicked to start search for both search view
+     * modes.
+     */
+    @Override
+    public void onClick(View v) {
+        onSearchExpanded();
+    }
+
+    @Override
+    public boolean onQueryTextSubmit(String query) {
+        mCurrentSearch = query;
+        mSearchView.clearFocus();
+        if (mListener != null) {
+            mListener.onSearchChanged(mCurrentSearch);
+        }
+        return true;
+    }
+
+    /**
+     * Used to detect and handle back button pressed event when search is expanded.
+     */
+    @Override
+    public void onFocusChange(View v, boolean hasFocus) {
+        if (!hasFocus) {
+            if (mCurrentSearch == null) {
+                mSearchView.setIconified(true);
+            } else if (TextUtils.isEmpty(mSearchView.getQuery())) {
+                cancelSearch();
+            }
+        }
+    }
+
+    @Override
+    public boolean onQueryTextChange(String newText) {
+        return false;
+    }
+
+    @Override
+    public boolean onMenuItemActionCollapse(MenuItem item) {
+        Menu menu = mActionBar.getMenu();
+        menu.setGroupVisible(R.id.group_hide_when_searching, true);
+
+        // Handles case when search view is collapsed by using the arrow on the left of the bar
+        if (isExpanded() || isSearching()) {
+            cancelSearch();
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onMenuItemActionExpand(MenuItem item) {
+        return true;
+    }
+
+    String getCurrentSearch() {
+        return mCurrentSearch;
+    }
+
+    boolean isSearching() {
+        return mCurrentSearch != null;
+    }
+
+    boolean isExpanded() {
+        return mSearchExpanded;
+    }
+
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index b90a119..1ba836a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -16,10 +16,15 @@
 
 package com.android.documentsui;
 
+import android.app.AlertDialog;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.provider.DocumentsContract;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.format.Time;
+import android.view.WindowManager;
 
 import java.text.Collator;
 import java.util.ArrayList;
@@ -28,25 +33,76 @@
 /** @hide */
 public final class Shared {
 
+    public static final String TAG = "Documents";
+
+    public static final boolean DEBUG = false;
+
     /** Intent action name to pick a copy destination. */
     public static final String ACTION_PICK_COPY_DESTINATION =
             "com.android.documentsui.PICK_COPY_DESTINATION";
 
     /**
+     * Extra flag allowing app to be opened in productivity mode (less downloadsy).
+     * Useful developers and the likes. When set to true overrides the default
+     * config value of productivity_device.
+     */
+    public static final String EXTRA_PRODUCTIVITY_MODE = "com.android.documentsui.PRODUCTIVITY";
+
+    /**
      * Extra boolean flag for {@link ACTION_PICK_COPY_DESTINATION}, which
      * specifies if the destination directory needs to create new directory or not.
      */
     public static final String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY";
 
-    public static final boolean DEBUG = true;
-    public static final String TAG = "Documents";
+    /**
+     * Extra flag used to store the current stack so user opens in right spot.
+     */
     public static final String EXTRA_STACK = "com.android.documentsui.STACK";
 
+    /**
+     * Extra flag used to store query of type String in the bundle.
+     */
+    public static final String EXTRA_QUERY = "query";
 
     /**
-     * String prefix used to indicate the document is a directory.
+     * Extra flag used to store state of type State in the bundle.
      */
-    public static final char DIR_PREFIX = '\001';
+    public static final String EXTRA_STATE = "state";
+
+    /**
+     * Extra flag used to store type of DirectoryFragment's type ResultType type in the bundle.
+     */
+    public static final String EXTRA_TYPE = "type";
+
+    /**
+     * Extra flag used to store root of type RootInfo in the bundle.
+     */
+    public static final String EXTRA_ROOT = "root";
+
+    /**
+     * Extra flag used to store document of DocumentInfo type in the bundle.
+     */
+    public static final String EXTRA_DOC = "document";
+
+    /**
+     * Extra flag used to store DirectoryFragment's selection of Selection type in the bundle.
+     */
+    public static final String EXTRA_SELECTION = "selection";
+
+    /**
+     * Extra flag used to store DirectoryFragment's search mode of boolean type in the bundle.
+     */
+    public static final String EXTRA_SEARCH_MODE = "searchMode";
+
+    /**
+     * Extra flag used to store DirectoryFragment's ignore state of boolean type in the bundle.
+     */
+    public static final String EXTRA_IGNORE_STATE = "ignoreState";
+
+    /**
+     * Extra for an Intent for enabling performance benchmark. Used only by tests.
+     */
+    public static final String EXTRA_BENCHMARK = "com.android.documentsui.benchmark";
 
     private static final Collator sCollator;
 
@@ -95,8 +151,7 @@
 
     /**
      * Compare two strings against each other using system default collator in a
-     * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX}
-     * before other items.
+     * case-insensitive mode.
      */
     public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
         final boolean leftEmpty = TextUtils.isEmpty(lhs);
@@ -106,12 +161,55 @@
         if (leftEmpty) return -1;
         if (rightEmpty) return 1;
 
-        final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX);
-        final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX);
-
-        if (leftDir && !rightDir) return -1;
-        if (rightDir && !leftDir) return 1;
-
         return sCollator.compare(lhs, rhs);
     }
+
+    /**
+     * Compare two strings against each other using system default collator in a
+     * case-insensitive mode.
+     */
+    public static int compareToIgnoreCase(String lhs, String rhs) {
+        return sCollator.compare(lhs, rhs);
+    }
+
+    public static boolean isHardwareKeyboardAvailable(Context context) {
+        return context.getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS;
+    }
+
+    public static void ensureKeyboardPresent(Context context, AlertDialog dialog) {
+        if (!isHardwareKeyboardAvailable(context)) {
+            dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        }
+    }
+
+    /*
+     * Returns true if app is running in "productivity mode".
+     */
+    public static boolean productivityMode(Context context) {
+        return context.getResources().getBoolean(R.bool.productivity_device);
+    }
+
+    /*
+     * Returns true if app is running in "productivity mode".
+     */
+    private static boolean isProductivityMode(Context context, Intent intent) {
+        return intent.getBooleanExtra(
+                Shared.EXTRA_PRODUCTIVITY_MODE,
+                context.getResources().getBoolean(R.bool.productivity_device));
+    }
+
+    /*
+     * Returns true if "Documents" root should be shown.
+     */
+    public static boolean shouldShowDocumentsRoot(Context context, Intent intent) {
+        return isProductivityMode(context, intent);
+    }
+
+    /*
+     * Returns true if device root should be shown.
+     */
+    public static boolean shouldShowDeviceRoot(Context context, Intent intent) {
+        return isProductivityMode(context, intent)
+                || intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
index 48c1a73..b4d7971 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
@@ -16,8 +16,6 @@
 
 package com.android.documentsui;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.app.Activity;
 import android.support.design.widget.Snackbar;
 import android.view.View;
@@ -26,12 +24,13 @@
     private Snackbars() {}
 
     public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
-        return Snackbars.makeSnackbar(activity, activity.getResources().getText(messageId), duration);
+        return Snackbars.makeSnackbar(
+                activity, activity.getResources().getText(messageId), duration);
     }
 
-    public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration)
-    {
-        final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout));
+    public static final Snackbar makeSnackbar(
+            Activity activity, CharSequence message, int duration) {
+        final View view = activity.findViewById(R.id.coordinator_layout);
         return Snackbar.make(view, message, duration);
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 0948ab1..c7d60e3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -43,13 +43,24 @@
 
     private static final String TAG = "State";
 
-    public static final int ACTION_OPEN = 1;
-    public static final int ACTION_CREATE = 2;
-    public static final int ACTION_GET_CONTENT = 3;
-    public static final int ACTION_OPEN_TREE = 4;
-    public static final int ACTION_MANAGE = 5;
-    public static final int ACTION_BROWSE = 6;
-    public static final int ACTION_PICK_COPY_DESTINATION = 8;
+    @IntDef(flag = true, value = {
+            ACTION_BROWSE,
+            ACTION_PICK_COPY_DESTINATION,
+            ACTION_OPEN,
+            ACTION_CREATE,
+            ACTION_GET_CONTENT,
+            ACTION_OPEN_TREE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ActionType {}
+    // File manager and related private picking activity.
+    public static final int ACTION_BROWSE = 1;
+    public static final int ACTION_PICK_COPY_DESTINATION = 2;
+    // All public picking activities
+    public static final int ACTION_OPEN = 3;
+    public static final int ACTION_CREATE = 4;
+    public static final int ACTION_GET_CONTENT = 5;
+    public static final int ACTION_OPEN_TREE = 6;
 
     @IntDef(flag = true, value = {
             MODE_UNKNOWN,
@@ -67,7 +78,7 @@
     public static final int SORT_ORDER_LAST_MODIFIED = 2;
     public static final int SORT_ORDER_SIZE = 3;
 
-    public int action;
+    public @ActionType int action;
     public String[] acceptMimes;
 
     /** Derived from local preferences */
@@ -82,9 +93,13 @@
     public boolean forceSize;
     public boolean showSize;
     public boolean localOnly;
-    public boolean forceAdvanced;
+    public boolean showAdvancedOption;
     public boolean showAdvanced;
     public boolean restored;
+    /*
+     * Indicates handler was an external app, like photos.
+     */
+    public boolean external;
 
     // Indicates that a copy operation (or move) includes a directory.
     // Why? Directory creation isn't supported by some roots (like Downloads).
@@ -105,9 +120,6 @@
     private boolean mInitialRootChanged;
     private boolean mInitialDocChanged;
 
-    /** Currently active search, overriding any stack. */
-    public String currentSearch;
-
     /** Instance state for every shown directory */
     public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
 
@@ -160,11 +172,13 @@
         mStackTouched = true;
     }
 
+    // This will return true even when the initial location is set.
+    // To get a read on if the user has changed something, use #hasInitialLocationChanged.
     public boolean hasLocationChanged() {
         return mStackTouched;
     }
 
-    public boolean initialLocationHasChanged() {
+    public boolean hasInitialLocationChanged() {
         return mInitialRootChanged || mInitialDocChanged;
     }
 
@@ -182,11 +196,11 @@
         out.writeInt(forceSize ? 1 : 0);
         out.writeInt(showSize ? 1 : 0);
         out.writeInt(localOnly ? 1 : 0);
-        out.writeInt(forceAdvanced ? 1 : 0);
+        out.writeInt(showAdvancedOption ? 1 : 0);
         out.writeInt(showAdvanced ? 1 : 0);
         out.writeInt(restored ? 1 : 0);
+        out.writeInt(external ? 1 : 0);
         DurableUtils.writeToParcel(out, stack);
-        out.writeString(currentSearch);
         out.writeMap(dirState);
         out.writeParcelable(selectedDocuments, 0);
         out.writeList(selectedDocumentsForCopy);
@@ -213,11 +227,11 @@
             state.forceSize = in.readInt() != 0;
             state.showSize = in.readInt() != 0;
             state.localOnly = in.readInt() != 0;
-            state.forceAdvanced = in.readInt() != 0;
+            state.showAdvancedOption = in.readInt() != 0;
             state.showAdvanced = in.readInt() != 0;
             state.restored = in.readInt() != 0;
+            state.external = in.readInt() != 0;
             DurableUtils.readFromParcel(in, state.stack);
-            state.currentSearch = in.readString();
             in.readMap(state.dirState, loader);
             state.selectedDocuments = in.readParcelable(loader);
             in.readList(state.selectedDocumentsForCopy, loader);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/AnimationView.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/AnimationView.java
new file mode 100644
index 0000000..a666456
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/AnimationView.java
@@ -0,0 +1,112 @@
+/*
+ * 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.documentsui.dirlist;
+
+import android.annotation.IntDef;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+import com.android.documentsui.R;
+import com.android.documentsui.Shared;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class exists solely to support animated transition of our directory fragment.
+ * The structure of this class is tightly coupled with the static animations defined in
+ * res/animator, specifically the "position" property referenced by
+ * res/animator/dir_{enter,leave}.xml.
+ */
+public class AnimationView extends LinearLayout {
+
+    @IntDef(flag = true, value = {
+            ANIM_NONE,
+            ANIM_SIDE,
+            ANIM_LEAVE,
+            ANIM_ENTER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AnimationType {}
+    public static final int ANIM_NONE = 1;
+    public static final int ANIM_SIDE = 2;
+    public static final int ANIM_LEAVE = 3;
+    public static final int ANIM_ENTER = 4;
+
+    private float mPosition = 0f;
+
+    // The distance the animation will cover...currently matches the height of the
+    // content area.
+    private int mSpan;
+
+    public AnimationView(Context context) {
+        super(context);
+    }
+
+    public AnimationView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mSpan = h;
+        setPosition(mPosition);
+    }
+
+    public float getPosition() {
+        return mPosition;
+    }
+
+    public void setPosition(float position) {
+        mPosition = position;
+        // Warning! If we ever decide to switch this to setX (slide left/right)
+        // please remember to add RLT variations of the animations under res/animator-ldrtl.
+        setY((mSpan > 0) ? (mPosition * mSpan) : 0);
+
+        if (mPosition != 0) {
+            setTranslationZ(getResources().getDimensionPixelSize(R.dimen.dir_elevation));
+        } else {
+            setTranslationZ(0);
+        }
+    }
+
+    /**
+     * Configures custom animations on the transaction according to the specified
+     * @AnimationType.
+     */
+    static void setupAnimations(
+            FragmentTransaction ft, @AnimationType int anim, Bundle args) {
+        switch (anim) {
+            case AnimationView.ANIM_SIDE:
+                args.putBoolean(Shared.EXTRA_IGNORE_STATE, true);
+                break;
+            case AnimationView.ANIM_ENTER:
+                // TODO: Document which behavior is being tailored
+                //     by passing this bit. Remove if possible.
+                args.putBoolean(Shared.EXTRA_IGNORE_STATE, true);
+                ft.setCustomAnimations(R.animator.dir_enter, R.animator.fade_out);
+                break;
+            case AnimationView.ANIM_LEAVE:
+                ft.setCustomAnimations(R.animator.fade_in, R.animator.dir_leave);
+                break;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 4583dec..630f359 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -17,32 +17,30 @@
 package com.android.documentsui.dirlist;
 
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.State.ACTION_MANAGE;
 import static com.android.documentsui.State.MODE_GRID;
 import static com.android.documentsui.State.MODE_LIST;
 import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
-import static com.google.common.base.Preconditions.checkArgument;
 
 import android.annotation.IntDef;
 import android.annotation.StringRes;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.AlertDialog;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.app.LoaderManager.LoaderCallbacks;
 import android.content.ClipData;
-import android.content.ContentResolver;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.Loader;
 import android.database.Cursor;
 import android.graphics.Canvas;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -52,6 +50,7 @@
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
 import android.support.design.widget.Snackbar;
+import android.support.v13.view.DragStartHelper;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
 import android.support.v7.widget.RecyclerView;
@@ -65,6 +64,7 @@
 import android.view.ActionMode;
 import android.view.DragEvent;
 import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -72,9 +72,9 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.widget.ImageView;
 import android.widget.TextView;
+import android.widget.Toolbar;
 
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.DirectoryLoader;
@@ -86,7 +86,7 @@
 import com.android.documentsui.Events.MotionInputEvent;
 import com.android.documentsui.Menus;
 import com.android.documentsui.MessageBar;
-import com.android.documentsui.MimePredicate;
+import com.android.documentsui.Metrics;
 import com.android.documentsui.R;
 import com.android.documentsui.RecentsLoader;
 import com.android.documentsui.RootsCache;
@@ -101,35 +101,30 @@
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperationService.OpType;
 import com.android.documentsui.services.FileOperations;
-
 import com.google.common.collect.Lists;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Display the documents inside a single directory.
  */
-public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
+public class DirectoryFragment extends Fragment
+        implements DocumentsAdapter.Environment, LoaderCallbacks<DirectoryResult> {
 
     @IntDef(flag = true, value = {
             TYPE_NORMAL,
-            TYPE_SEARCH,
             TYPE_RECENT_OPEN
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ResultType {}
     public static final int TYPE_NORMAL = 1;
-    public static final int TYPE_SEARCH = 2;
-    public static final int TYPE_RECENT_OPEN = 3;
-
-    public static final int ANIM_NONE = 1;
-    public static final int ANIM_SIDE = 2;
-    public static final int ANIM_LEAVE = 3;
-    public static final int ANIM_ENTER = 4;
+    public static final int TYPE_RECENT_OPEN = 2;
 
     @IntDef(flag = true, value = {
             REQUEST_COPY_DESTINATION
@@ -138,19 +133,8 @@
     public @interface RequestCode {}
     public static final int REQUEST_COPY_DESTINATION = 1;
 
-    static final boolean DEBUG_ENABLE_DND = true;
-
     private static final String TAG = "DirectoryFragment";
     private static final int LOADER_ID = 42;
-    private static final int DELETE_UNDO_TIMEOUT = 5000;
-    private static final int DELETE_JOB_DELAY = 5500;
-    private static final int EMPTY_REVEAL_DURATION = 250;
-
-    private static final String EXTRA_TYPE = "type";
-    private static final String EXTRA_ROOT = "root";
-    private static final String EXTRA_DOC = "doc";
-    private static final String EXTRA_QUERY = "query";
-    private static final String EXTRA_IGNORE_STATE = "ignoreState";
 
     private Model mModel;
     private MultiSelectManager mSelectionManager;
@@ -164,30 +148,37 @@
     private RecyclerView mRecView;
     private ListeningGestureDetector mGestureDetector;
 
-    private @ResultType int mType = TYPE_NORMAL;
     private String mStateKey;
 
     private int mLastSortOrder = SORT_ORDER_UNKNOWN;
     private DocumentsAdapter mAdapter;
-    private LoaderCallbacks<DirectoryResult> mCallbacks;
     private FragmentTuner mTuner;
     private DocumentClipper mClipper;
     private GridLayoutManager mLayout;
     private int mColumnCount = 1;  // This will get updated when layout changes.
 
+    private LayoutInflater mInflater;
     private MessageBar mMessageBar;
     private View mProgressBar;
 
+    // Directory fragment state is defined by: root, document, query, type, selection
+    private @ResultType int mType = TYPE_NORMAL;
+    private RootInfo mRoot;
+    private DocumentInfo mDocument;
+    private String mQuery = null;
+    private Selection mSelection = null;
+    private boolean mSearchMode = false;
+    private @Nullable ActionMode mActionMode;
+
     @Override
     public View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        mInflater = inflater;
         final View view = inflater.inflate(R.layout.fragment_directory, container, false);
 
         mMessageBar = MessageBar.create(getChildFragmentManager());
         mProgressBar = view.findViewById(R.id.progressbar);
-
         mEmptyView = view.findViewById(android.R.id.empty);
-
         mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
         mRecView.setRecyclerListener(
                 new RecyclerListener() {
@@ -199,17 +190,16 @@
 
         mRecView.setItemAnimator(new DirectoryItemAnimator(getActivity()));
 
-        // TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
-        if (DEBUG_ENABLE_DND) {
-            setupDragAndDropOnDirectoryView(mRecView);
-        }
+        // Make the recycler and the empty views responsive to drop events.
+        mRecView.setOnDragListener(mOnDragListener);
+        mEmptyView.setOnDragListener(mOnDragListener);
 
         return view;
     }
 
     @Override
     public void onDestroyView() {
-        super.onDestroyView();
+        mSelectionManager.clearSelection();
 
         // Cancel any outstanding thumbnail requests
         final int count = mRecView.getChildCount();
@@ -217,6 +207,8 @@
             final View view = mRecView.getChildAt(i);
             cancelThumbnailTask(view);
         }
+
+        super.onDestroyView();
     }
 
     @Override
@@ -226,9 +218,16 @@
         final Context context = getActivity();
         final State state = getDisplayState();
 
-        final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
-        final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
-        mStateKey = buildStateKey(root, doc);
+        // Read arguments when object created for the first time.
+        // Restore state if fragment recreated.
+        Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState;
+        mRoot = args.getParcelable(Shared.EXTRA_ROOT);
+        mDocument = args.getParcelable(Shared.EXTRA_DOC);
+        mStateKey = buildStateKey(mRoot, mDocument);
+        mQuery = args.getString(Shared.EXTRA_QUERY);
+        mType = args.getInt(Shared.EXTRA_TYPE);
+        mSelection = args.getParcelable(Shared.EXTRA_SELECTION);
+        mSearchMode = args.getBoolean(Shared.EXTRA_SEARCH_MODE);
 
         mIconHelper = new IconHelper(context, MODE_GRID);
 
@@ -244,17 +243,11 @@
         }
         mRecView.setLayoutManager(mLayout);
 
-        mGestureDetector = new ListeningGestureDetector(this.getContext(), new GestureListener());
+        mGestureDetector =
+                new ListeningGestureDetector(this.getContext(), mDragHelper, new GestureListener());
 
         mRecView.addOnItemTouchListener(mGestureDetector);
 
-        // final here because we'll manually bump the listener iwhen we had an initial selection,
-        // but only after the model is fully loaded.
-        final SelectionModeListener selectionListener = new SelectionModeListener();
-        final Selection initialSelection = state.selectedDocuments.hasDirectoryKey(mStateKey)
-            ? state.selectedDocuments
-            : null;
-
         // TODO: instead of inserting the view into the constructor, extract listener-creation code
         // and set the listener on the view after the fact.  Then the view doesn't need to be passed
         // into the selection manager.
@@ -264,9 +257,9 @@
                 state.allowMultiple
                     ? MultiSelectManager.MODE_MULTIPLE
                     : MultiSelectManager.MODE_SINGLE,
-                initialSelection);
+                null);
 
-        mSelectionManager.addCallback(selectionListener);
+        mSelectionManager.addCallback(new SelectionModeListener());
 
         mModel = new Model();
         mModel.addUpdateListener(mAdapter);
@@ -275,106 +268,31 @@
         // Make sure this is done after the RecyclerView is set up.
         mFocusManager = new FocusManager(context, mRecView, mModel);
 
-        mType = getArguments().getInt(EXTRA_TYPE);
-
         mTuner = FragmentTuner.pick(getContext(), state);
         mClipper = new DocumentClipper(context);
 
-        boolean hideGridTitles;
-        if (mType == TYPE_RECENT_OPEN) {
-            // Hide titles when showing recents for picking images/videos
-            hideGridTitles = MimePredicate.mimeMatches(
-                    MimePredicate.VISUAL_MIMES, state.acceptMimes);
-        } else {
-            hideGridTitles = (doc != null) && doc.isGridTitlesHidden();
-        }
-        GridDocumentHolder.setHideTitles(hideGridTitles);
-
         final ActivityManager am = (ActivityManager) context.getSystemService(
                 Context.ACTIVITY_SERVICE);
         boolean svelte = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
         mIconHelper.setThumbnailsEnabled(!svelte);
 
-        mCallbacks = new LoaderCallbacks<DirectoryResult>() {
-            @Override
-            public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
-                final String query = getArguments().getString(EXTRA_QUERY);
-
-                Uri contentsUri;
-                switch (mType) {
-                    case TYPE_NORMAL:
-                        contentsUri = DocumentsContract.buildChildDocumentsUri(
-                                doc.authority, doc.documentId);
-                        if (state.action == ACTION_MANAGE) {
-                            contentsUri = DocumentsContract.setManageMode(contentsUri);
-                        }
-                        return new DirectoryLoader(
-                                context, mType, root, doc, contentsUri, state.userSortOrder);
-                    case TYPE_SEARCH:
-                        contentsUri = DocumentsContract.buildSearchDocumentsUri(
-                                root.authority, root.rootId, query);
-                        if (state.action == ACTION_MANAGE) {
-                            contentsUri = DocumentsContract.setManageMode(contentsUri);
-                        }
-                        return new DirectoryLoader(
-                                context, mType, root, doc, contentsUri, state.userSortOrder);
-                    case TYPE_RECENT_OPEN:
-                        final RootsCache roots = DocumentsApplication.getRootsCache(context);
-                        return new RecentsLoader(context, roots, state);
-                    default:
-                        throw new IllegalStateException("Unknown type " + mType);
-                }
-            }
-
-            @Override
-            public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
-                if (!isAdded()) return;
-
-                mModel.update(result);
-                state.derivedSortOrder = result.sortOrder;
-
-                updateDisplayState();
-
-                if (initialSelection != null) {
-                    selectionListener.onSelectionChanged();
-                }
-
-                // Restore any previous instance state
-                final SparseArray<Parcelable> container = state.dirState.remove(mStateKey);
-                if (container != null && !getArguments().getBoolean(EXTRA_IGNORE_STATE, false)) {
-                    getView().restoreHierarchyState(container);
-                } else if (mLastSortOrder != state.derivedSortOrder) {
-                    // The derived sort order takes the user sort order into account, but applies
-                    // directory-specific defaults when the user doesn't explicitly set the sort
-                    // order. Scroll to the top if the sort order actually changed.
-                    mRecView.smoothScrollToPosition(0);
-                }
-
-                mLastSortOrder = state.derivedSortOrder;
-
-                mTuner.onModelLoaded(mModel, mType);
-            }
-
-            @Override
-            public void onLoaderReset(Loader<DirectoryResult> loader) {
-                mModel.update(null);
-            }
-        };
-
         // Kick off loader at least once
-        getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
+        getLoaderManager().restartLoader(LOADER_ID, null, this);
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
-        State state = getDisplayState();
-        if (mSelectionManager.hasSelection()) {
-            mSelectionManager.getSelection(state.selectedDocuments);
-            state.selectedDocuments.setDirectoryKey(mStateKey);
-            if (!state.selectedDocuments.isEmpty()) {
-                if (DEBUG) Log.d(TAG, "Persisted selection: " + state.selectedDocuments);
-            }
-        }
+        super.onSaveInstanceState(outState);
+
+        mSelectionManager.getSelection(mSelection);
+
+        outState.putInt(Shared.EXTRA_TYPE, mType);
+        outState.putParcelable(Shared.EXTRA_ROOT, mRoot);
+        outState.putParcelable(Shared.EXTRA_DOC, mDocument);
+        outState.putString(Shared.EXTRA_QUERY, mQuery);
+        outState.putParcelable(Shared.EXTRA_SELECTION, mSelection);
+        outState.putBoolean(Shared.EXTRA_SEARCH_MODE, mSearchMode);
+
     }
 
     @Override
@@ -419,7 +337,9 @@
 
     private boolean handleViewItem(String id) {
         final Cursor cursor = mModel.getItem(id);
-        checkNotNull(cursor, "Cursor cannot be null.");
+
+        assert(cursor != null);
+
         final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
         if (mTuner.isDocumentEnabled(docMimeType, docFlags)) {
@@ -449,7 +369,7 @@
     public void onSortOrderChanged() {
         // Sort order is implemented as a sorting wrapper around directory
         // results. So when sort order changes, we force a reload of the directory.
-        getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
+        getLoaderManager().restartLoader(LOADER_ID, null, this);
     }
 
     public void onViewModeChanged() {
@@ -490,8 +410,9 @@
         int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
         int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
 
-        checkState(mRecView.getWidth() > 0);
-        int columnCount = Math.max(1,
+        // RecyclerView sometimes gets a width of 0 (see b/27150284).  Clamp so that we always lay
+        // out the grid with at least 2 columns.
+        int columnCount = Math.max(2,
                 (mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin));
 
         return columnCount;
@@ -522,7 +443,7 @@
             implements MultiSelectManager.Callback, ActionMode.Callback {
 
         private Selection mSelected = new Selection();
-        private ActionMode mActionMode;
+        private int mNoCopyCount = 0;
         private int mNoDeleteCount = 0;
         private int mNoRenameCount = -1;
         private Menu mMenu;
@@ -531,7 +452,9 @@
         public boolean onBeforeItemStateChange(String modelId, boolean selected) {
             if (selected) {
                 final Cursor cursor = mModel.getItem(modelId);
-                checkNotNull(cursor, "Cursor cannot be null.");
+
+                assert(cursor != null);
+
                 final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
                 final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
                 return mTuner.canSelectType(docMimeType, docFlags);
@@ -552,7 +475,11 @@
             // triggered on "silent" selection updates (i.e. we might be reacting to unfinalized
             // selection changes here)
             final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
-            if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) {
+            if ((docFlags & Document.FLAG_PARTIAL) != 0) {
+                mNoCopyCount += selected ? 1 : -1;
+            }
+            if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0
+                    && (docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) {
                 mNoDeleteCount += selected ? 1 : -1;
             }
             if ((docFlags & Document.FLAG_SUPPORTS_RENAME) != 0) {
@@ -583,7 +510,10 @@
             getActivity().getWindow().setStatusBarColor(color.data);
 
             if (mActionMode != null) {
-                mActionMode.setTitle(String.valueOf(mSelected.size()));
+                final String title = Shared.getQuantityString(getActivity(),
+                        R.plurals.elements_selected, mSelected.size());
+                mActionMode.setTitle(title);
+                mRecView.announceForAccessibility(title);
             }
         }
 
@@ -597,14 +527,44 @@
             mSelected.clear();
             mNoDeleteCount = 0;
             mNoRenameCount = -1;
+
+            // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode.
+            final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
+            toolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+
+            // This toolbar is not present in the fixed_layout
+            final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(R.id.roots_toolbar);
+            if (rootsToolbar != null) {
+                rootsToolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+            }
         }
 
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+
             int size = mSelectionManager.getSelection().size();
             mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
             mode.setTitle(TextUtils.formatSelectedCount(size));
-            return (size > 0);
+
+            if (size > 0) {
+                // Hide the toolbars if action mode is enabled, so TalkBack doesn't navigate to
+                // these controls when using linear navigation.
+                final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
+                toolbar.setImportantForAccessibility(
+                        View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+
+                // This toolbar is not present in the fixed_layout
+                final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(
+                        R.id.roots_toolbar);
+                if (rootsToolbar != null) {
+                    rootsToolbar.setImportantForAccessibility(
+                            View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+                }
+                return true;
+            }
+
+            return false;
         }
 
         @Override
@@ -614,24 +574,30 @@
             return true;
         }
 
-        boolean canRenameSelection() {
-            return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1;
+        boolean canCopySelection() {
+            return mNoCopyCount == 0;
         }
 
         boolean canDeleteSelection() {
             return mNoDeleteCount == 0;
         }
 
+        boolean canRenameSelection() {
+            return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1;
+        }
+
         private void updateActionMenu() {
-            checkNotNull(mMenu);
+            assert(mMenu != null);
 
             // Delegate update logic to our owning action, since specialized logic is desired.
-            mTuner.updateActionMenu(mMenu, mType, canDeleteSelection(), canRenameSelection());
+            mTuner.updateActionMenu(
+                    mMenu, mType, canCopySelection(), canDeleteSelection(), canRenameSelection());
             Menus.disableHiddenItems(mMenu);
         }
 
         @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            Metrics.logMenuAction(getContext(), item.getItemId());
 
             Selection selection = mSelectionManager.getSelection(new Selection());
 
@@ -643,18 +609,16 @@
 
                 case R.id.menu_share:
                     shareDocuments(selection);
-                    mode.finish();
                     return true;
 
                 case R.id.menu_delete:
-                    // Exit selection mode first, so we avoid deselecting deleted documents.
-                    mode.finish();
+                    // deleteDocuments will end action mode if the documents are deleted.
+                    // It won't end action mode if user cancels the delete.
                     deleteDocuments(selection);
                     return true;
 
                 case R.id.menu_copy_to:
                     transferDocuments(selection, FileOperationService.OPERATION_COPY);
-                    mode.finish();
                     return true;
 
                 case R.id.menu_move_to:
@@ -672,8 +636,10 @@
                     return true;
 
                 case R.id.menu_rename:
-                    renameDocuments(selection);
+                    // Exit selection mode first, so we avoid deselecting deleted
+                    // (renamed) documents.
                     mode.finish();
+                    renameDocuments(selection);
                     return true;
 
                 default:
@@ -757,52 +723,87 @@
         }.execute(selected);
     }
 
-    private void deleteDocuments(final Selection selected) {
+    private String generateDeleteMessage(final List<DocumentInfo> docs) {
+        String message;
+        int dirsCount = 0;
 
-        checkArgument(!selected.isEmpty());
+        for (DocumentInfo doc : docs) {
+            if (doc.isDirectory()) {
+                ++dirsCount;
+            }
+        }
+
+        if (docs.size() == 1) {
+            // Deleteing 1 file xor 1 folder in cwd
+            message = dirsCount == 0
+                    ? getActivity().getString(R.string.delete_filename_confirmation_message,
+                            docs.get(0).displayName)
+                    : getActivity().getString(R.string.delete_foldername_confirmation_message,
+                            docs.get(0).displayName);
+        } else if (dirsCount == 0) {
+            // Deleting only files in cwd
+            message = Shared.getQuantityString(getActivity(),
+                    R.plurals.delete_files_confirmation_message, docs.size());
+        } else if (dirsCount == docs.size()) {
+            // Deleting only folders in cwd
+            message = Shared.getQuantityString(getActivity(),
+                    R.plurals.delete_folders_confirmation_message, docs.size());
+        } else {
+            // Deleting mixed items (files and folders) in cwd
+            message = Shared.getQuantityString(getActivity(),
+                    R.plurals.delete_items_confirmation_message, docs.size());
+        }
+        return message;
+    }
+
+    private void deleteDocuments(final Selection selected) {
+        assert(!selected.isEmpty());
+
         final DocumentInfo srcParent = getDisplayState().stack.peek();
         new GetDocumentsTask() {
             @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                // Hide the files in the UI.
-                final SparseArray<String> hidden = mAdapter.hide(selected.getAll());
+            void onDocumentsReady(final List<DocumentInfo> docs) {
 
-                checkState(DELETE_JOB_DELAY > DELETE_UNDO_TIMEOUT);
-                String operationId = FileOperations.delete(
-                        getActivity(), docs, srcParent, getDisplayState().stack,
-                        DELETE_JOB_DELAY);
-                showDeleteSnackbar(hidden, operationId);
-            }
-        }.execute(selected);
-    }
+                TextView message =
+                        (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
+                message.setText(generateDeleteMessage(docs));
 
-    private void showDeleteSnackbar(final SparseArray<String> hidden, final String jobId) {
-
-        Context context = getActivity();
-        String message = Shared.getQuantityString(context, R.plurals.deleting, hidden.size());
-
-        // Show a snackbar informing the user that files will be deleted, and give them an option to
-        // cancel.
-        final Activity activity = getActivity();
-        Snackbars.makeSnackbar(activity, message, DELETE_UNDO_TIMEOUT)
-                .setAction(
-                        R.string.undo,
-                        new View.OnClickListener() {
-                            @Override
-                            public void onClick(View view) {}
-                        })
-                .setCallback(
-                        new Snackbar.Callback() {
-                            @Override
-                            public void onDismissed(Snackbar snackbar, int event) {
-                                if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
-                                    // If the delete was cancelled, just unhide the files.
-                                    FileOperations.cancel(activity, jobId);
-                                    mAdapter.unhide(hidden);
+                // This "insta-hides" files that are being deleted, because
+                // the delete operation may be not execute immediately (it
+                // may be queued up on the FileOperationService.)
+                // To hide the files locally, we call the hide method on the adapter
+                // ...which a live object...cannot be parceled.
+                // For that reason, for now, we implement this dialog NOT
+                // as a fragment (which can survive rotation and have its own state),
+                // but as a simple runtime dialog. So rotating a device with an
+                // active delete dialog...results in that dialog disappearing.
+                // We can do better, but don't have cycles for it now.
+                new AlertDialog.Builder(getActivity())
+                    .setView(message)
+                    .setPositiveButton(
+                         android.R.string.yes,
+                         new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int id) {
+                                // Finish selection mode first which clears selection so we
+                                // don't end up trying to deselect deleted documents.
+                                // This is done here, rather in the onActionItemClicked
+                                // so we can avoid de-selecting items in the case where
+                                // the user cancels the delete.
+                                if (mActionMode != null) {
+                                    mActionMode.finish();
                                 }
+                                // Hide the files in the UI...since the operation
+                                // might be queued up on FileOperationService.
+                                // We're walking a line here.
+                                mAdapter.hide(selected.getAll());
+                                FileOperations.delete(
+                                        getActivity(), docs, srcParent, getDisplayState().stack);
                             }
                         })
-                .show();
+                    .setNegativeButton(android.R.string.no, null)
+                    .show();
+            }
+        }.execute(selected);
     }
 
     private void transferDocuments(final Selection selected, final @OpType int mode) {
@@ -854,7 +855,7 @@
     private void renameDocuments(Selection selected) {
         // Batch renaming not supported
         // Rename option is only available in menu when 1 document selected
-        checkArgument(selected.size() == 1);
+        assert(selected.size() == 1);
 
         new GetDocumentsTask() {
             @Override
@@ -872,9 +873,7 @@
 
     @Override
     public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {
-        if (DEBUG_ENABLE_DND) {
-            setupDragAndDropOnDocumentView(holder.itemView, cursor);
-        }
+        setupDragAndDropOnDocumentView(holder.itemView, cursor);
     }
 
     @Override
@@ -969,7 +968,8 @@
     }
 
     private void copyFromClipData(final ClipData clipData, final DocumentInfo destination) {
-        checkNotNull(clipData);
+        assert(clipData != null);
+
         new AsyncTask<Void, Void, List<DocumentInfo>>() {
 
             @Override
@@ -1011,25 +1011,6 @@
         FileOperations.copy(getActivity(), docs, tmpStack);
     }
 
-    private ClipData getClipDataFromDocuments(List<DocumentInfo> docs) {
-        Context context = getActivity();
-        final ContentResolver resolver = context.getContentResolver();
-        ClipData clipData = null;
-        for (DocumentInfo doc : docs) {
-            final Uri uri = DocumentsContract.buildDocumentUri(doc.authority, doc.documentId);
-            if (clipData == null) {
-                // TODO: figure out what this string should be.
-                // Currently it is not displayed anywhere in the UI, but this might change.
-                final String label = "";
-                clipData = ClipData.newUri(resolver, label, uri);
-            } else {
-                // TODO: update list of mime types in ClipData.
-                clipData.addItem(new ClipData.Item(uri));
-            }
-        }
-        return clipData;
-    }
-
     public void copySelectedToClipboard() {
         Selection selection = mSelectionManager.getSelection(new Selection());
         if (!selection.isEmpty()) {
@@ -1039,7 +1020,7 @@
     }
 
     void copySelectionToClipboard(Selection selection) {
-        checkArgument(!selection.isEmpty());
+        assert(!selection.isEmpty());
         new GetDocumentsTask() {
             @Override
             void onDocumentsReady(List<DocumentInfo> docs) {
@@ -1072,7 +1053,7 @@
         }
 
         // Can't copy folders to downloads, because we don't show folders there.
-        if (!root.isDownloads()) {
+        if (root.isDownloads()) {
             for (DocumentInfo docs : files) {
                 if (docs.isDirectory()) {
                     return false;
@@ -1084,8 +1065,19 @@
     }
 
     public void selectAllFiles() {
+        // Exclude disabled files
+        List<String> enabled = new ArrayList<String>();
+        for (String id : mAdapter.getModelIds()) {
+            Cursor cursor = getModel().getItem(id);
+            String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+            int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+            if (isDocumentEnabled(docMimeType, docFlags)) {
+                enabled.add(id);
+            }
+        }
+
         // Only select things currently visible in the adapter.
-        boolean changed = mSelectionManager.setItemsSelected(mAdapter.getModelIds(), true);
+        boolean changed = mSelectionManager.setItemsSelected(enabled, true);
         if (changed) {
             updateDisplayState();
         }
@@ -1098,11 +1090,6 @@
         mFocusManager.restoreLastFocus();
     }
 
-    private void setupDragAndDropOnDirectoryView(View view) {
-        // Listen for drops on non-directory items and empty space.
-        view.setOnDragListener(mOnDragListener);
-    }
-
     private void setupDragAndDropOnDocumentView(View view, Cursor cursor) {
         final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
         if (Document.MIME_TYPE_DIR.equals(docMimeType)) {
@@ -1111,7 +1098,8 @@
             view.setOnDragListener(mOnDragListener);
         }
 
-        view.setOnLongClickListener(mLongClickListener);
+        // Make all items draggable.
+        view.setOnLongClickListener(onLongClickListener);
     }
 
     private View.OnDragListener mOnDragListener = new View.OnDragListener() {
@@ -1122,28 +1110,67 @@
                     // TODO: Check if the event contains droppable data.
                     return true;
 
-                // TODO: Highlight potential drop target directory?
                 // TODO: Expand drop target directory on hover?
                 case DragEvent.ACTION_DRAG_ENTERED:
-                case DragEvent.ACTION_DRAG_LOCATION:
+                    setDropTargetHighlight(v, true);
+                    return true;
                 case DragEvent.ACTION_DRAG_EXITED:
+                    setDropTargetHighlight(v, false);
+                    return true;
+
+                case DragEvent.ACTION_DRAG_LOCATION:
+                    return true;
+
                 case DragEvent.ACTION_DRAG_ENDED:
+                    if (event.getResult()) {
+                        // Exit selection mode if the drop was handled.
+                        mSelectionManager.clearSelection();
+                    }
                     return true;
 
                 case DragEvent.ACTION_DROP:
-                    String dstId = getModelId(v);
-                    DocumentInfo dstDir = null;
-                    if (dstId != null) {
-                        Cursor dstCursor = mModel.getItem(dstId);
-                        checkNotNull(dstCursor, "Cursor cannot be null.");
-                        dstDir = DocumentInfo.fromDirectoryCursor(dstCursor);
-                        // TODO: Do not drop into the directory where the documents came from.
+                    // After a drop event, always stop highlighting the target.
+                    setDropTargetHighlight(v, false);
+                    // Don't copy from the cwd into the cwd. Note: this currently doesn't work for
+                    // multi-window drag, because localState isn't carried over from one process to
+                    // another.
+                    Object src = event.getLocalState();
+                    DocumentInfo dst = getDestination(v);
+                    if (Objects.equals(src, dst)) {
+                        return false;
                     }
-                    copyFromClipData(event.getClipData(), dstDir);
+                    Metrics.logDragNDrop(getContext());
+                    copyFromClipData(event.getClipData(), dst);
                     return true;
             }
             return false;
         }
+
+        private DocumentInfo getDestination(View v) {
+            String id = getModelId(v);
+            if (id != null) {
+                Cursor dstCursor = mModel.getItem(id);
+                assert(dstCursor != null);
+                return DocumentInfo.fromDirectoryCursor(dstCursor);
+            }
+
+            if (v == mRecView || v == mEmptyView) {
+                return getDisplayState().stack.peek();
+            }
+
+            return null;
+        }
+
+        private void setDropTargetHighlight(View v, boolean highlight) {
+            // Note: use exact comparison - this code is searching for views which are children of
+            // the RecyclerView instance in the UI.
+            if (v.getParent() == mRecView) {
+                RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(v);
+                if (vh instanceof DocumentHolder) {
+                    ((DocumentHolder) vh).setHighlighted(highlight);
+                }
+            }
+        }
     };
 
     /**
@@ -1169,21 +1196,14 @@
      *     a document item view.
      */
     private String getModelId(View view) {
-        while (true) {
-            if (view.getLayoutParams() instanceof RecyclerView.LayoutParams) {
-                RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
-                if (vh instanceof DocumentHolder) {
-                    return ((DocumentHolder) vh).modelId;
-                } else {
-                    return null;
-                }
+        View itemView = mRecView.findContainingItemView(view);
+        if (itemView != null) {
+            RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(itemView);
+            if (vh instanceof DocumentHolder) {
+                return ((DocumentHolder) vh).modelId;
             }
-            ViewParent parent = view.getParent();
-            if (parent == null || !(parent instanceof View)) {
-                return null;
-            }
-            view = (View) parent;
         }
+        return null;
     }
 
     private List<DocumentInfo> getDraggableDocuments(View currentItemView) {
@@ -1203,47 +1223,75 @@
         }
 
         final Cursor cursor = mModel.getItem(modelId);
-        checkNotNull(cursor, "Cursor cannot be null.");
-        final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
 
-        return Lists.newArrayList(doc);
+        assert(cursor != null);
+
+        return Lists.newArrayList(
+                DocumentInfo.fromDirectoryCursor(cursor));
     }
 
-    private Drawable getDragShadowIcon(List<DocumentInfo> docs) {
-        if (docs.size() == 1) {
-            final DocumentInfo doc = docs.get(0);
-            return mIconHelper.getDocumentIcon(getActivity(), doc.authority, doc.documentId,
-                    doc.mimeType, doc.icon);
+    private static class DragShadowBuilder extends View.DragShadowBuilder {
+
+        private final Context mContext;
+        private final IconHelper mIconHelper;
+        private final LayoutInflater mInflater;
+        private final View mShadowView;
+        private final TextView mTitle;
+        private final ImageView mIcon;
+        private final int mWidth;
+        private final int mHeight;
+
+        public DragShadowBuilder(Context context, IconHelper iconHelper, List<DocumentInfo> docs) {
+            mContext = context;
+            mIconHelper = iconHelper;
+            mInflater = LayoutInflater.from(context);
+
+            mWidth = mContext.getResources().getDimensionPixelSize(R.dimen.drag_shadow_width);
+            mHeight= mContext.getResources().getDimensionPixelSize(R.dimen.drag_shadow_height);
+
+            mShadowView = mInflater.inflate(R.layout.drag_shadow_layout, null);
+            mTitle = (TextView) mShadowView.findViewById(android.R.id.title);
+            mIcon = (ImageView) mShadowView.findViewById(android.R.id.icon);
+
+            mTitle.setText(getTitle(docs));
+            mIcon.setImageDrawable(getIcon(docs));
         }
-        return getActivity().getDrawable(R.drawable.ic_doc_generic);
-    }
 
-    private class DrawableShadowBuilder extends View.DragShadowBuilder {
+        private Drawable getIcon(List<DocumentInfo> docs) {
+            if (docs.size() == 1) {
+                final DocumentInfo doc = docs.get(0);
+                return mIconHelper.getDocumentIcon(mContext, doc.authority, doc.documentId,
+                        doc.mimeType, doc.icon);
+            }
+            return mContext.getDrawable(R.drawable.ic_doc_generic);
+        }
 
-        private final Drawable mShadow;
-
-        private final int mShadowDimension;
-
-        public DrawableShadowBuilder(Drawable shadow) {
-            mShadow = shadow;
-            mShadowDimension = getResources().getDimensionPixelSize(
-                    R.dimen.drag_shadow_size);
-            mShadow.setBounds(0, 0, mShadowDimension, mShadowDimension);
+        private String getTitle(List<DocumentInfo> docs) {
+            if (docs.size() == 1) {
+                final DocumentInfo doc = docs.get(0);
+                return doc.displayName;
+            }
+            return Shared.getQuantityString(mContext, R.plurals.elements_dragged, docs.size());
         }
 
         @Override
         public void onProvideShadowMetrics(
                 Point shadowSize, Point shadowTouchPoint) {
-            shadowSize.set(mShadowDimension, mShadowDimension);
-            shadowTouchPoint.set(mShadowDimension / 2, mShadowDimension / 2);
+            shadowSize.set(mWidth, mHeight);
+            shadowTouchPoint.set(mWidth, mHeight);
         }
 
         @Override
         public void onDrawShadow(Canvas canvas) {
-            mShadow.draw(canvas);
+            Rect r = canvas.getClipBounds();
+            // Calling measure is necessary in order for all child views to get correctly laid out.
+            mShadowView.measure(
+                    View.MeasureSpec.makeMeasureSpec(r.right- r.left, View.MeasureSpec.EXACTLY),
+                    View.MeasureSpec.makeMeasureSpec(r.top- r.bottom, View.MeasureSpec.EXACTLY));
+            mShadowView.layout(r.left, r.top, r.right, r.bottom);
+            mShadowView.draw(canvas);
         }
     }
-
     /**
      * Abstract task providing support for loading documents *off*
      * the main thread. And if it isn't obvious, creating a list
@@ -1296,6 +1344,11 @@
                 return false;
             }
 
+            // Ignore tab key events.  Those should be handled by the top-level key handler.
+            if (keyCode == KeyEvent.KEYCODE_TAB) {
+                return false;
+            }
+
             if (mFocusManager.handleKey(doc, keyCode, event)) {
                 // Handle range selection adjustments. Extending the selection will adjust the
                 // bounds of the in-progress range selection. Each time an unshifted navigation
@@ -1313,12 +1366,26 @@
             }
 
             // Handle enter key events
-            if (keyCode == KeyEvent.KEYCODE_ENTER) {
-                if (event.isShiftPressed()) {
-                    return onSelect(doc);
-                } else {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_ENTER:
+                    if (event.isShiftPressed()) {
+                        return onSelect(doc);
+                    }
+                    // For non-shifted enter keypresses, fall through.
+                case KeyEvent.KEYCODE_DPAD_CENTER:
+                case KeyEvent.KEYCODE_BUTTON_A:
                     return onActivate(doc);
-                }
+                case KeyEvent.KEYCODE_FORWARD_DEL:
+                    // This has to be handled here instead of in a keyboard shortcut, because
+                    // keyboard shortcuts all have to be modified with the 'Ctrl' key.
+                    if (mSelectionManager.hasSelection()) {
+                        Metrics.logKeyboardAction(getContext(), Metrics.ACTION_KEYBOARD_DELETE);
+                        deleteDocuments(mSelectionManager.getSelection());
+                    }
+                    // Always handle the key, even if there was nothing to delete. This is a
+                    // precaution to prevent other handlers from potentially picking up the event
+                    // and triggering extra behaviours.
+                    return true;
             }
 
             return false;
@@ -1342,7 +1409,7 @@
             mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
 
             if (model.isEmpty()) {
-                if (getDisplayState().currentSearch != null) {
+                if (mSearchMode) {
                     showNoResults(getDisplayState().stack.root);
                 } else {
                     showEmptyDirectory();
@@ -1351,6 +1418,11 @@
                 showDirectory();
                 mAdapter.notifyDataSetChanged();
             }
+
+            if (!model.isLoading()) {
+                ((BaseActivity) getActivity()).notifyDirectoryLoaded(
+                    model.doc != null ? model.doc.derivedUri : null);
+            }
         }
 
         @Override
@@ -1359,18 +1431,19 @@
         }
     }
 
-    private View.OnLongClickListener mLongClickListener = new View.OnLongClickListener() {
+    private DragStartHelper.OnDragStartListener mOnDragStartListener =
+            new DragStartHelper.OnDragStartListener() {
         @Override
-        public boolean onLongClick(View v) {
-            if (mGestureDetector.mouseSpawnedLastEvent()) {
+        public boolean onDragStart(View v, DragStartHelper helper) {
+            if (isSelected(getModelId(v))) {
                 List<DocumentInfo> docs = getDraggableDocuments(v);
                 if (docs.isEmpty()) {
                     return false;
                 }
-                v.startDrag(
-                        getClipDataFromDocuments(docs),
-                        new DrawableShadowBuilder(getDragShadowIcon(docs)),
-                        null,
+                v.startDragAndDrop(
+                        mClipper.getClipDataForDocuments(docs),
+                        new DragShadowBuilder(getActivity(), mIconHelper, docs),
+                        getDisplayState().stack.peek(),
                         View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
                                 View.DRAG_FLAG_GLOBAL_URI_WRITE
                 );
@@ -1381,6 +1454,15 @@
         }
     };
 
+    private DragStartHelper mDragHelper = new DragStartHelper(null, mOnDragStartListener);
+
+    private View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
+        @Override
+        public boolean onLongClick(View v) {
+            return mDragHelper.onLongClick(v);
+        }
+    };
+
     // Previously we listened to events with one class, only to bounce them forward
     // to GestureDetector. We're still doing that here, but with a single class
     // that reduces overall complexity in our glue code.
@@ -1388,9 +1470,12 @@
             implements OnItemTouchListener {
 
         private int mLastTool = -1;
+        private DragStartHelper mDragHelper;
 
-        public ListeningGestureDetector(Context context, GestureListener listener) {
+        public ListeningGestureDetector(
+                Context context, DragStartHelper dragHelper, GestureListener listener) {
             super(context, listener);
+            mDragHelper = dragHelper;
             setOnDoubleTapListener(listener);
         }
 
@@ -1405,12 +1490,27 @@
         @Override
         public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
             mLastTool = e.getToolType(0);
-            onTouchEvent(e);  // bounce this forward to our detecty heart
+
+            // Detect drag events. When a drag is detected, intercept the rest of the gesture.
+            View itemView = rv.findChildViewUnder(e.getX(), e.getY());
+            if (itemView != null && mDragHelper.onTouch(itemView,  e)) {
+                return true;
+            }
+            // Forward unhandled events to the GestureDetector.
+            onTouchEvent(e);
+
             return false;
         }
 
         @Override
-        public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
+        public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+            View itemView = rv.findChildViewUnder(e.getX(), e.getY());
+            mDragHelper.onTouch(itemView,  e);
+            // Note: even though this event is being handled as part of a drag gesture, continue
+            // forwarding to the GestureDetector. The detector needs to see the entire cluster of
+            // events in order to properly interpret gestures.
+            onTouchEvent(e);
+        }
 
         @Override
         public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
@@ -1468,43 +1568,51 @@
 
     public static void showDirectory(
             FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
-        show(fm, TYPE_NORMAL, root, doc, null, anim);
-    }
-
-    public static void showSearch(FragmentManager fm, RootInfo root, String query, int anim) {
-        show(fm, TYPE_SEARCH, root, null, query, anim);
+        create(fm, TYPE_NORMAL, root, doc, null, anim);
     }
 
     public static void showRecentsOpen(FragmentManager fm, int anim) {
-        show(fm, TYPE_RECENT_OPEN, null, null, null, anim);
+        create(fm, TYPE_RECENT_OPEN, null, null, null, anim);
     }
 
-    private static void show(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
+    public static void reloadSearch(FragmentManager fm, RootInfo root, DocumentInfo doc,
+            String query) {
+        DirectoryFragment df = get(fm);
+
+        df.mQuery = query;
+        df.mRoot = root;
+        df.mDocument = doc;
+        df.mSearchMode =  query != null;
+        df.getLoaderManager().restartLoader(LOADER_ID, null, df);
+    }
+
+    public static void reload(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
+            String query) {
+        DirectoryFragment df = get(fm);
+        df.mType = type;
+        df.mQuery = query;
+        df.mRoot = root;
+        df.mDocument = doc;
+        df.mSearchMode =  query != null;
+        df.getLoaderManager().restartLoader(LOADER_ID, null, df);
+    }
+
+    public static void create(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
             String query, int anim) {
         final Bundle args = new Bundle();
-        args.putInt(EXTRA_TYPE, type);
-        args.putParcelable(EXTRA_ROOT, root);
-        args.putParcelable(EXTRA_DOC, doc);
-        args.putString(EXTRA_QUERY, query);
+        args.putInt(Shared.EXTRA_TYPE, type);
+        args.putParcelable(Shared.EXTRA_ROOT, root);
+        args.putParcelable(Shared.EXTRA_DOC, doc);
+        args.putString(Shared.EXTRA_QUERY, query);
+        args.putParcelable(Shared.EXTRA_SELECTION, new Selection());
 
         final FragmentTransaction ft = fm.beginTransaction();
-        switch (anim) {
-            case ANIM_SIDE:
-                args.putBoolean(EXTRA_IGNORE_STATE, true);
-                break;
-            case ANIM_ENTER:
-                args.putBoolean(EXTRA_IGNORE_STATE, true);
-                ft.setCustomAnimations(R.animator.dir_enter, R.animator.dir_frozen);
-                break;
-            case ANIM_LEAVE:
-                ft.setCustomAnimations(R.animator.dir_frozen, R.animator.dir_leave);
-                break;
-        }
+        AnimationView.setupAnimations(ft, anim, args);
 
         final DirectoryFragment fragment = new DirectoryFragment();
         fragment.setArguments(args);
 
-        ft.replace(R.id.container_directory, fragment);
+        ft.replace(getFragmentId(), fragment);
         ft.commitAllowingStateLoss();
     }
 
@@ -1518,9 +1626,82 @@
 
     public static @Nullable DirectoryFragment get(FragmentManager fm) {
         // TODO: deal with multiple directories shown at once
-        Fragment fragment = fm.findFragmentById(R.id.container_directory);
+        Fragment fragment = fm.findFragmentById(getFragmentId());
         return fragment instanceof DirectoryFragment
                 ? (DirectoryFragment) fragment
                 : null;
     }
-}
+
+    private static int getFragmentId() {
+        return R.id.container_directory;
+    }
+
+    @Override
+    public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
+        Context context = getActivity();
+        State state = getDisplayState();
+
+        Uri contentsUri;
+        switch (mType) {
+            case TYPE_NORMAL:
+                contentsUri = mSearchMode ? DocumentsContract.buildSearchDocumentsUri(
+                        mRoot.authority, mRoot.rootId, mQuery)
+                        : DocumentsContract.buildChildDocumentsUri(
+                                mDocument.authority, mDocument.documentId);
+                if (mTuner.enableManagedMode()) {
+                    contentsUri = DocumentsContract.setManageMode(contentsUri);
+                }
+                return new DirectoryLoader(
+                        context, mType, mRoot, mDocument, contentsUri, state.userSortOrder,
+                        mSearchMode);
+            case TYPE_RECENT_OPEN:
+                final RootsCache roots = DocumentsApplication.getRootsCache(context);
+                return new RecentsLoader(context, roots, state);
+
+            default:
+                throw new IllegalStateException("Unknown type " + mType);
+        }
+    }
+
+    @Override
+    public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
+        if (!isAdded()) return;
+        if (mSearchMode) {
+            Metrics.logSearch(getContext());
+        }
+
+        State state = getDisplayState();
+
+        mAdapter.notifyDataSetChanged();
+        mModel.update(result);
+
+        state.derivedSortOrder = result.sortOrder;
+
+        updateLayout(state.derivedMode);
+
+        if (mSelection != null) {
+            mSelectionManager.setItemsSelected(mSelection.toList(), true);
+        }
+
+        // Restore any previous instance state
+        final SparseArray<Parcelable> container = state.dirState.remove(mStateKey);
+        if (container != null && !getArguments().getBoolean(Shared.EXTRA_IGNORE_STATE, false)) {
+            getView().restoreHierarchyState(container);
+        } else if (mLastSortOrder != state.derivedSortOrder) {
+            // The derived sort order takes the user sort order into account, but applies
+            // directory-specific defaults when the user doesn't explicitly set the sort
+            // order. Scroll to the top if the sort order actually changed.
+            mRecView.smoothScrollToPosition(0);
+        }
+
+        mLastSortOrder = state.derivedSortOrder;
+
+        mTuner.onModelLoaded(mModel, mType, mSearchMode);
+
+    }
+
+    @Override
+    public void onLoaderReset(Loader<DirectoryResult> loader) {
+        mModel.update(null);
+    }
+  }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
index 1bfc6e9..450341f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -16,9 +16,7 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
-
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.database.Cursor;
 import android.graphics.Rect;
@@ -38,17 +36,19 @@
         extends RecyclerView.ViewHolder
         implements View.OnKeyListener {
 
+    static final float DISABLED_ALPHA = 0.3f;
+
     public @Nullable String modelId;
 
-    final int mSelectedItemColor;
-    final int mDefaultItemColor;
-    final boolean mAlwaysShowSummary;
     final Context mContext;
+    final @ColorInt int mDefaultBgColor;
+    final @ColorInt int mSelectedBgColor;
 
     DocumentHolder.EventListener mEventListener;
     private View.OnKeyListener mKeyListener;
     private View mSelectionHotspot;
 
+
     public DocumentHolder(Context context, ViewGroup parent, int layout) {
         this(context, inflateLayout(context, parent, layout));
     }
@@ -60,9 +60,8 @@
 
         mContext = context;
 
-        mDefaultItemColor = context.getColor(R.color.item_doc_background);
-        mSelectedItemColor = context.getColor(R.color.item_doc_background_selected);
-        mAlwaysShowSummary = context.getResources().getBoolean(R.bool.always_show_summary);
+        mDefaultBgColor = context.getColor(R.color.item_doc_background);
+        mSelectedBgColor = context.getColor(R.color.item_doc_background_selected);
 
         mSelectionHotspot = itemView.findViewById(R.id.icon_check);
     }
@@ -75,34 +74,57 @@
      */
     public abstract void bind(Cursor cursor, String modelId, State state);
 
-    public void setSelected(boolean selected) {
+    /**
+     * Makes the associated item view appear selected. Note that this merely affects the appearance
+     * of the view, it doesn't actually select the item.
+     * TODO: Use the DirectoryItemAnimator instead of manually controlling animation using a boolean
+     * flag.
+     *
+     * @param selected
+     * @param animate Whether or not to animate the change. Only selection changes initiated by the
+     *            selection manager should be animated. See
+     *            {@link ModelBackedDocumentsAdapter#onBindViewHolder(DocumentHolder, int, java.util.List)}
+     */
+    public void setSelected(boolean selected, boolean animate) {
+        // Note: the animate param doesn't apply for this base implementation, because the
+        // DirectoryItemAnimator takes care of it. It's required by subclasses, which perform their
+        // own animation.
         itemView.setActivated(selected);
-        itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
+        itemView.setBackgroundColor(selected ? mSelectedBgColor : mDefaultBgColor);
+    }
+
+    /**
+     * Highlights the associated item view.
+     * @param highlighted
+     */
+    public void setHighlighted(boolean highlighted) {
+        itemView.setBackgroundColor(highlighted ? mSelectedBgColor : mDefaultBgColor);
+    }
+
+    public void setEnabled(boolean enabled) {
+        setEnabledRecursive(itemView, enabled);
     }
 
     @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         // Event listener should always be set.
-        checkNotNull(mEventListener);
+        assert(mEventListener != null);
+
         return mEventListener.onKey(this,  keyCode,  event);
     }
 
     public void addEventListener(DocumentHolder.EventListener listener) {
         // Just handle one for now; switch to a list if necessary.
-        checkState(mEventListener == null);
+        assert(mEventListener == null);
         mEventListener = listener;
     }
 
     public void addOnKeyListener(View.OnKeyListener listener) {
         // Just handle one for now; switch to a list if necessary.
-        checkState(mKeyListener == null);
+        assert(mKeyListener == null);
         mKeyListener = listener;
     }
 
-    public void setEnabled(boolean enabled) {
-        setEnabledRecursive(itemView, enabled);
-    }
-
     public boolean onSingleTapUp(MotionEvent event) {
         if (Events.isMouseEvent(event)) {
             // Mouse clicks select.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
index 0930c22..0bbecf9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -74,13 +74,6 @@
     abstract public SparseArray<String> hide(String... ids);
 
     /**
-     * Unhides a set of previously hidden items.
-     *
-     * @param ids A sparse array of IDs from a previous call to {@link #hide}.
-     */
-    abstract void unhide(SparseArray<String> ids);
-
-    /**
      * Returns a class that yields the span size for a particular element. This is
      * primarily useful in {@link SectionBreakDocumentsAdapterWrapper} where
      * we adjust sizes.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
index 7f867d5..ac05c05 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
@@ -18,7 +18,11 @@
 
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
 import android.provider.DocumentsContract.Document;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -38,6 +42,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
 
 /**
  * A class that handles navigation and focus within the DirectoryFragment.
@@ -113,6 +119,11 @@
      * Requests focus on the item that last had focus. Scrolls to that item if necessary.
      */
     public void restoreLastFocus() {
+        if (mAdapter.getItemCount() == 0) {
+            // Nothing to focus.
+            return;
+        }
+
         if (mLastFocusPosition != RecyclerView.NO_POSITION) {
             // The system takes care of situations when a view is no longer on screen, etc,
             focusItem(mLastFocusPosition);
@@ -254,10 +265,23 @@
      * @param pos
      */
     private void focusItem(final int pos) {
+        focusItem(pos, null);
+    }
+
+    /**
+     * Requests focus for the item in the given adapter position, scrolling the RecyclerView if
+     * necessary.
+     *
+     * @param pos
+     * @param callback A callback to call after the given item has been focused.
+     */
+    private void focusItem(final int pos, @Nullable final FocusCallback callback) {
         // If the item is already in view, focus it; otherwise, scroll to it and focus it.
         RecyclerView.ViewHolder vh = mView.findViewHolderForAdapterPosition(pos);
         if (vh != null) {
-            vh.itemView.requestFocus();
+            if (vh.itemView.requestFocus() && callback != null) {
+                callback.onFocus(vh.itemView);
+            }
         } else {
             // Set a one-time listener to request focus when the scroll has completed.
             mView.addOnScrollListener(
@@ -269,7 +293,9 @@
                                 RecyclerView.ViewHolder vh =
                                         view.findViewHolderForAdapterPosition(pos);
                                 if (vh != null) {
-                                    vh.itemView.requestFocus();
+                                    if (vh.itemView.requestFocus() && callback != null) {
+                                        callback.onFocus(vh.itemView);
+                                    }
                                 } else {
                                     // This might happen in weird corner cases, e.g. if the user is
                                     // scrolling while a delete operation is in progress. In that
@@ -291,6 +317,10 @@
         return mLayout.getSpanCount() > 1;
     }
 
+    private interface FocusCallback {
+        public void onFocus(View view);
+    }
+
     /**
      * A helper class for handling type-to-focus. Instantiate this class, and pass it KeyEvents via
      * the {@link #handleKey(DocumentHolder, int, KeyEvent)} method. The class internally will build
@@ -299,15 +329,24 @@
      * highlights instances of the search term found in the view.
      */
     private class TitleSearchHelper {
-        final private KeyListener mTextListener = new TextKeyListener(Capitalize.NONE, false);
-        final private Editable mSearchString = Editable.Factory.getInstance().newEditable("");
-        final private Highlighter mHighlighter = new Highlighter();
-        final private BackgroundColorSpan mSpan;
+        static private final int SEARCH_TIMEOUT = 500;  // ms
+
+        private final KeyListener mTextListener = new TextKeyListener(Capitalize.NONE, false);
+        private final Editable mSearchString = Editable.Factory.getInstance().newEditable("");
+        private final Highlighter mHighlighter = new Highlighter();
+        private final BackgroundColorSpan mSpan;
+
         private List<String> mIndex;
         private boolean mActive;
+        private Timer mTimer;
+        private KeyEvent mLastEvent;
+        private Handler mUiRunner;
 
         public TitleSearchHelper(Context context) {
             mSpan = new BackgroundColorSpan(context.getColor(R.color.accent_dark));
+            // Handler for running things on the main UI thread. Needed for updating the UI from a
+            // timer (see #activate, below).
+            mUiRunner = new Handler(Looper.getMainLooper());
         }
 
         /**
@@ -325,7 +364,7 @@
                 case KeyEvent.KEYCODE_ENTER:
                     if (mActive) {
                         // These keys end any active searches.
-                        deactivate();
+                        endSearch();
                         return true;
                     } else {
                         // Don't handle these key events if there is no active search.
@@ -333,7 +372,9 @@
                     }
                 case KeyEvent.KEYCODE_SPACE:
                     // This allows users to search for files with spaces in their names, but ignores
-                    // spacebar events when a text search is not active.
+                    // spacebar events when a text search is not active. Ignoring the spacebar
+                    // event is necessary because other handlers (see FocusManager#handleKey) also
+                    // listen for and handle it.
                     if (!mActive) {
                         return false;
                     }
@@ -341,7 +382,7 @@
 
             // Navigation keys also end active searches.
             if (Events.isNavigationKeyCode(keyCode)) {
-                deactivate();
+                endSearch();
                 // Don't handle the keycode, so navigation still occurs.
                 return false;
             }
@@ -350,20 +391,17 @@
             boolean handled = mTextListener.onKeyDown(doc.itemView, mSearchString, keyCode, event);
 
             // Delete is processed by the text listener, but not "handled". Check separately for it.
-            if (handled || keyCode == KeyEvent.KEYCODE_DEL) {
-                String searchString = mSearchString.toString();
-                if (searchString.length() == 0) {
+            if (keyCode == KeyEvent.KEYCODE_DEL) {
+                handled = true;
+            }
+
+            if (handled) {
+                mLastEvent = event;
+                if (mSearchString.length() == 0) {
                     // Don't perform empty searches.
                     return false;
                 }
-                activate();
-                for (int pos = 0; pos < mIndex.size(); pos++) {
-                    String title = mIndex.get(pos);
-                    if (title != null && title.startsWith(searchString)) {
-                        focusItem(pos);
-                        break;
-                    }
-                }
+                search();
             }
 
             return handled;
@@ -373,10 +411,17 @@
          * Activates the search helper, which changes its key handling and updates the search index
          * and highlights if necessary. Call this each time the search term is updated.
          */
-        private void activate() {
+        private void search() {
             if (!mActive) {
-                // Install listeners.
+                // The model listener invalidates the search index when the model changes.
                 mModel.addUpdateListener(mModelListener);
+
+                // Used to keep the current search alive until the timeout expires. If the user
+                // presses another key within that time, that keystroke is added to the current
+                // search. Otherwise, the current search ends, and subsequent keystrokes start a new
+                // search.
+                mTimer = new Timer();
+                mActive = true;
             }
 
             // If the search index was invalidated, rebuild it
@@ -384,71 +429,42 @@
                 buildIndex();
             }
 
-            // TODO: Uncomment this to enable search term highlighting in the UI.
-//            mHighlighter.activate();
-
-            mActive = true;
-        }
-
-        /**
-         * Deactivates the search helper (see {@link #activate()}). Call this when a search ends.
-         */
-        private void deactivate() {
-            if (mActive) {
-                // Remove listeners.
-                mModel.removeUpdateListener(mModelListener);
-            }
-
-            // TODO: Uncomment this when search-term highlighting is enabled in the UI.
-//            mHighlighter.deactivate();
-
-            mIndex = null;
-            mSearchString.clear();
-            mActive = false;
-        }
-
-        /**
-         * Applies title highlights to the given view. The view must have a title field that is a
-         * spannable text field.  If this condition is not met, this function does nothing.
-         *
-         * @param view
-         */
-        private void applyHighlight(View view) {
-            TextView titleView = (TextView) view.findViewById(android.R.id.title);
-            if (titleView == null) {
-                return;
-            }
-
-            String searchString = mSearchString.toString();
-            CharSequence tmpText = titleView.getText();
-            if (tmpText instanceof Spannable) {
-                Spannable title = (Spannable) tmpText;
-                String titleString = title.toString();
-                if (titleString.startsWith(searchString)) {
-                    title.setSpan(mSpan, 0, searchString.length(),
-                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-                } else {
-                    title.removeSpan(mSpan);
+            // Search for the current search term.
+            // Perform case-insensitive search.
+            String searchString = mSearchString.toString().toLowerCase();
+            for (int pos = 0; pos < mIndex.size(); pos++) {
+                String title = mIndex.get(pos);
+                if (title != null && title.startsWith(searchString)) {
+                    focusItem(pos, new FocusCallback() {
+                        @Override
+                        public void onFocus(View view) {
+                            mHighlighter.applyHighlight(view);
+                            // Using a timer repeat period of SEARCH_TIMEOUT/2 means the amount of
+                            // time between the last keystroke and a search expiring is actually
+                            // between 500 and 750 ms. A smaller timer period results in less
+                            // variability but does more polling.
+                            mTimer.schedule(new TimeoutTask(), 0, SEARCH_TIMEOUT / 2);
+                        }
+                    });
+                    break;
                 }
             }
         }
 
         /**
-         * Removes title highlights from the given view. The view must have a title field that is a
-         * spannable text field.  If this condition is not met, this function does nothing.
-         *
-         * @param view
+         * Ends the current search (see {@link #search()}.
          */
-        private void removeHighlight(View view) {
-            TextView titleView = (TextView) view.findViewById(android.R.id.title);
-            if (titleView == null) {
-                return;
+        private void endSearch() {
+            if (mActive) {
+                mModel.removeUpdateListener(mModelListener);
+                mTimer.cancel();
             }
 
-            CharSequence tmpText = titleView.getText();
-            if (tmpText instanceof Spannable) {
-                ((Spannable) tmpText).removeSpan(mSpan);
-            }
+            mHighlighter.removeHighlight();
+
+            mIndex = null;
+            mSearchString.clear();
+            mActive = false;
         }
 
         /**
@@ -461,8 +477,10 @@
             for (int i = 0; i < itemCount; i++) {
                 String modelId = mAdapter.getModelId(i);
                 if (modelId != null) {
-                    index.add(
-                            getCursorString(mModel.getItem(modelId), Document.COLUMN_DISPLAY_NAME));
+                    String title =
+                            getCursorString(mModel.getItem(modelId), Document.COLUMN_DISPLAY_NAME);
+                    // Perform case-insensitive search.
+                    index.add(title.toLowerCase());
                 } else {
                     index.add("");
                 }
@@ -484,43 +502,58 @@
             }
         };
 
-        private class Highlighter implements RecyclerView.OnChildAttachStateChangeListener {
-            /**
-             * Starts highlighting instances of the current search term in the UI.
-             */
-            public void activate() {
-                // Update highlights on all views
-                int itemCount = mView.getChildCount();
-                for (int i = 0; i < itemCount; i++) {
-                    applyHighlight(mView.getChildAt(i));
+        private class TimeoutTask extends TimerTask {
+            @Override
+            public void run() {
+                long last = mLastEvent.getEventTime();
+                long now = SystemClock.uptimeMillis();
+                if ((now - last) > SEARCH_TIMEOUT) {
+                    // endSearch must run on the main thread because it does UI work
+                    mUiRunner.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            endSearch();
+                        }
+                    });
                 }
-                // Keep highlights up-to-date as items come in and out of view.
-                mView.addOnChildAttachStateChangeListener(this);
             }
+        };
+
+        private class Highlighter {
+            private Spannable mCurrentHighlight;
 
             /**
-             * Stops highlighting instances of the current search term in the UI.
+             * Applies title highlights to the given view. The view must have a title field that is a
+             * spannable text field.  If this condition is not met, this function does nothing.
+             *
+             * @param view
              */
-            public void deactivate() {
-                // Remove highlights on all views
-                int itemCount = mView.getChildCount();
-                for (int i = 0; i < itemCount; i++) {
-                    removeHighlight(mView.getChildAt(i));
-                }
-                // Stop updating highlights.
-                mView.removeOnChildAttachStateChangeListener(this);
-            }
-
-            @Override
-            public void onChildViewAttachedToWindow(View view) {
-                applyHighlight(view);
-            }
-
-            @Override
-            public void onChildViewDetachedFromWindow(View view) {
+            private void applyHighlight(View view) {
                 TextView titleView = (TextView) view.findViewById(android.R.id.title);
-                if (titleView != null) {
-                    removeHighlight(titleView);
+                if (titleView == null) {
+                    return;
+                }
+
+                CharSequence tmpText = titleView.getText();
+                if (tmpText instanceof Spannable) {
+                    if (mCurrentHighlight != null) {
+                        mCurrentHighlight.removeSpan(mSpan);
+                    }
+                    mCurrentHighlight = (Spannable) tmpText;
+                    mCurrentHighlight.setSpan(
+                            mSpan, 0, mSearchString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+            }
+
+            /**
+             * Removes title highlights from the given view. The view must have a title field that is a
+             * spannable text field.  If this condition is not met, this function does nothing.
+             *
+             * @param view
+             */
+            private void removeHighlight() {
+                if (mCurrentHighlight != null) {
+                    mCurrentHighlight.removeSpan(mSpan);
                 }
             }
         };
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index a9b0fd1..016cc9e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -16,24 +16,19 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.State.ACTION_BROWSE;
 import static com.android.documentsui.State.ACTION_CREATE;
 import static com.android.documentsui.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.State.ACTION_MANAGE;
 import static com.android.documentsui.State.ACTION_OPEN;
 import static com.android.documentsui.State.ACTION_OPEN_TREE;
-import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
 
 import android.content.Context;
-import android.os.SystemProperties;
 import android.provider.DocumentsContract.Document;
-import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 
-import com.android.documentsui.DocumentsActivity;
-import com.android.documentsui.FilesActivity;
+import com.android.documentsui.BaseActivity;
 import com.android.documentsui.Menus;
 import com.android.documentsui.MimePredicate;
 import com.android.documentsui.R;
@@ -58,16 +53,14 @@
         switch (state.action) {
             case ACTION_BROWSE:
                 return new FilesTuner(context, state);
-            case ACTION_MANAGE:
-                return new DownloadsTuner(context, state);
             default:
                 return new DocumentsTuner(context, state);
         }
     }
 
-
-    public abstract void updateActionMenu(Menu menu, int dirType, boolean canDelete,
-            boolean canRename);
+    public abstract void updateActionMenu(
+            Menu menu, @ResultType int dirType,
+            boolean canCopy, boolean canDelete, boolean canRename);
 
     // Subtly different from isDocumentEnabled. The reason may be illuminated as follows.
     // A folder is enabled such that it may be double clicked, even in settings
@@ -84,7 +77,13 @@
         return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
     }
 
-    abstract void onModelLoaded(Model model, @ResultType int resultType);
+    abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
+
+    /**
+     * When managed mode is enabled, active downloads will be visible in the UI.
+     * Presumably this should only be true when in the downloads directory.
+     */
+    abstract boolean enableManagedMode();
 
     /**
      * Provides support for Platform specific specializations of DirectoryFragment.
@@ -105,7 +104,8 @@
                 return false;
             }
 
-            if (mState.action == ACTION_OPEN_TREE) {
+            if (mState.action == ACTION_OPEN_TREE
+                    || mState.action == ACTION_PICK_COPY_DESTINATION) {
                 // In this case nothing *ever* is selectable...the expected user behavior is
                 // they navigate *into* a folder, then click a confirmation button indicating
                 // that the current directory is the directory they are picking.
@@ -140,78 +140,54 @@
         }
 
         @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
-                boolean canRename) {
+        public void updateActionMenu(
+                Menu menu, @ResultType int dirType,
+                boolean canCopy, boolean canDelete, boolean canRename) {
 
-            boolean copyEnabled = dirType != DirectoryFragment.TYPE_RECENT_OPEN;
-            boolean moveEnabled =
-                    SystemProperties.getBoolean("debug.documentsui.enable_move", false);
-            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled);
-
-            final MenuItem open = menu.findItem(R.id.menu_open);
-            final MenuItem share = menu.findItem(R.id.menu_share);
-            final MenuItem delete = menu.findItem(R.id.menu_delete);
-            final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
-            final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
-            final MenuItem rename = menu.findItem(R.id.menu_rename);
+            MenuItem open = menu.findItem(R.id.menu_open);
+            MenuItem share = menu.findItem(R.id.menu_share);
+            MenuItem delete = menu.findItem(R.id.menu_delete);
+            MenuItem rename = menu.findItem(R.id.menu_rename);
+            MenuItem selectAll = menu.findItem(R.id.menu_select_all);
 
             open.setVisible(true);
             share.setVisible(false);
             delete.setVisible(false);
-            copyTo.setVisible(copyEnabled);
-            copyTo.setEnabled(copyEnabled);
-            moveTo.setVisible(moveEnabled);
-            moveTo.setEnabled(moveEnabled);
             rename.setVisible(false);
+            selectAll.setVisible(mState.allowMultiple);
+
+            Menus.disableHiddenItems(menu);
         }
 
         @Override
-        void onModelLoaded(Model model, @ResultType int resultType) {
-            // When launched into empty recents, show drawer
-            if (resultType == DirectoryFragment.TYPE_RECENT_OPEN
-                    && model.isEmpty()
-                    && !mState.hasLocationChanged()) {
-                ((DocumentsActivity) mContext).setRootsDrawerOpen(true);
+        void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
+            boolean showDrawer = false;
+
+            if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
+                showDrawer = false;
+            }
+            if (mState.external && mState.action == ACTION_GET_CONTENT) {
+                showDrawer = true;
+            }
+            if (mState.action == ACTION_PICK_COPY_DESTINATION) {
+                showDrawer = true;
+            }
+
+            // When launched into empty root, open drawer.
+            if (model.isEmpty()) {
+                showDrawer = true;
+            }
+
+            if (showDrawer && !mState.hasInitialLocationChanged() && !isSearch) {
+                // This noops on layouts without drawer, so no need to guard.
+                ((BaseActivity) mContext).setRootsDrawerOpen(true);
             }
         }
-    }
-
-    /**
-     * Provides support for Platform specific specializations of DirectoryFragment.
-     */
-    private static final class DownloadsTuner extends FragmentTuner {
-
-        public DownloadsTuner(Context context, State state) {
-            super(context, state);
-        }
 
         @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
-                boolean canRename) {
-            checkArgument(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
-
-            boolean moveEnabled =
-                    SystemProperties.getBoolean("debug.documentsui.enable_move", false);
-            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(true);
-
-            final MenuItem open = menu.findItem(R.id.menu_open);
-            final MenuItem share = menu.findItem(R.id.menu_share);
-            final MenuItem delete = menu.findItem(R.id.menu_delete);
-            final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
-            final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
-            final MenuItem rename = menu.findItem(R.id.menu_rename);
-
-            open.setVisible(false);
-            delete.setVisible(canDelete);
-            copyTo.setVisible(true);
-            copyTo.setEnabled(true);
-            moveTo.setVisible(moveEnabled);
-            moveTo.setEnabled(moveEnabled);
-            rename.setVisible(false);
+        public boolean enableManagedMode() {
+            return false;
         }
-
-        @Override
-        void onModelLoaded(Model model, @ResultType int resultType) {}
     }
 
     /**
@@ -219,51 +195,60 @@
      */
     private static final class FilesTuner extends FragmentTuner {
 
-        private static final String TAG = "FilesTuner";
-
         public FilesTuner(Context context, State state) {
             super(context, state);
         }
 
         @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
-                boolean canRename) {
+        public void updateActionMenu(
+                Menu menu, @ResultType int dirType,
+                boolean canCopy, boolean canDelete, boolean canRename) {
 
             MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
             MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
-            copy.setEnabled(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
+            copy.setEnabled(canCopy);
 
             MenuItem rename = menu.findItem(R.id.menu_rename);
+            MenuItem moveTo = menu.findItem(R.id.menu_move_to);
+            MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
+
+            copyTo.setVisible(true);
+            moveTo.setVisible(true);
             rename.setVisible(true);
+
+            copyTo.setEnabled(canCopy);
+            moveTo.setEnabled(canCopy && canDelete);
             rename.setEnabled(canRename);
 
             menu.findItem(R.id.menu_share).setVisible(true);
             menu.findItem(R.id.menu_delete).setVisible(canDelete);
-
             menu.findItem(R.id.menu_open).setVisible(false);
-            menu.findItem(R.id.menu_copy_to).setVisible(true);
-            menu.findItem(R.id.menu_move_to).setVisible(true);
 
             Menus.disableHiddenItems(menu, copy, paste);
         }
 
         @Override
-        void onModelLoaded(Model model, @ResultType int resultType) {
-            if (DEBUG) Log.d(TAG, "Handling model loaded. Has Location shcnage: " + mState.initialLocationHasChanged());
+        void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
             // When launched into empty root, open drawer.
-            if (model.isEmpty() && !mState.initialLocationHasChanged()
-                    && resultType != DirectoryFragment.TYPE_SEARCH) {
-                if (DEBUG) Log.d(TAG, "Showing roots drawer cuz stuffs empty.");
-
+            if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
                 // This noops on layouts without drawer, so no need to guard.
-                ((FilesActivity) mContext).setRootsDrawerOpen(true);
+                ((BaseActivity) mContext).setRootsDrawerOpen(true);
             }
-            if (DEBUG) Log.d(TAG, "Donezo.");
+        }
+
+        @Override
+        public boolean enableManagedMode() {
+            // When in downloads top level directory, we also show active downloads.
+            // And while we don't allow folders in Downloads, we do allow Zip files in
+            // downloads that themselves can be opened and viewed like directories.
+            // This method helps us understand when to kick in on those special behaviors.
+            return mState.stack.root != null
+                    && mState.stack.root.isDownloads()
+                    && mState.stack.size() == 1;
         }
     }
 
     private static boolean isDirectory(String mimeType) {
         return Document.MIME_TYPE_DIR.equals(mimeType);
     }
-
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
index e672327..ce5bcb1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
@@ -17,7 +17,6 @@
 package com.android.documentsui.dirlist;
 
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.content.Context;
 import android.database.Cursor;
@@ -43,12 +42,17 @@
     }
 
     @Override
-    public void setSelected(boolean selected) {
-        super.setSelected(selected);
+    public void setSelected(boolean selected, boolean animate) {
+        super.setSelected(selected, animate);
         float checkAlpha = selected ? 1f : 0f;
 
-        mIconCheck.animate().alpha(checkAlpha).start();
-        mIconMime.animate().alpha(1f - checkAlpha).start();
+        if (animate) {
+            mIconCheck.animate().alpha(checkAlpha).start();
+            mIconMime.animate().alpha(1f - checkAlpha).start();
+        } else {
+            mIconCheck.setAlpha(checkAlpha);
+            mIconMime.setAlpha(1f - checkAlpha);
+        }
     }
 
     /**
@@ -58,11 +62,12 @@
      * @param state Current display state.
      */
     public void bind(Cursor cursor, String modelId, State state) {
-        checkNotNull(cursor, "Cursor cannot be null.");
+        assert(cursor != null);
 
         this.modelId = modelId;
 
         final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
-        mTitle.setText(docDisplayName);
+        mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
+
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
index 8eaed17e..c4f6f11 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -19,8 +19,8 @@
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
@@ -38,6 +38,7 @@
 import com.android.documentsui.State;
 
 final class GridDocumentHolder extends DocumentHolder {
+
     private static boolean mHideTitles;
 
     final TextView mTitle;
@@ -49,9 +50,13 @@
     final ImageView mIconCheck;
     final IconHelper mIconHelper;
 
+    private final @ColorInt int mDisabledBgColor;
+
     public GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
         super(context, parent, R.layout.item_doc_grid);
 
+        mDisabledBgColor = context.getColor(R.color.item_doc_background_disabled);
+
         mTitle = (TextView) itemView.findViewById(android.R.id.title);
         mDate = (TextView) itemView.findViewById(R.id.date);
         mSize = (TextView) itemView.findViewById(R.id.size);
@@ -64,12 +69,42 @@
     }
 
     @Override
-    public void setSelected(boolean selected) {
-        super.setSelected(selected);
+    public void setSelected(boolean selected, boolean animate) {
+        // We always want to make sure our check box disappears if we're not selected,
+        // even if the item is disabled. This is because this object can be reused
+        // and this method will be called to setup initial state.
         float checkAlpha = selected ? 1f : 0f;
+        if (animate) {
+            mIconCheck.animate().alpha(checkAlpha).start();
+        } else {
+            mIconCheck.setAlpha(checkAlpha);
+        }
 
-        mIconCheck.animate().alpha(checkAlpha).start();
-        mIconMimeSm.animate().alpha(1f - checkAlpha).start();
+        // But it should be an error to be set to selected && be disabled.
+        if (!itemView.isEnabled()) {
+            assert(!selected);
+            return;
+        }
+
+        super.setSelected(selected, animate);
+
+        if (animate) {
+            mIconMimeSm.animate().alpha(1f - checkAlpha).start();
+        } else {
+            mIconMimeSm.setAlpha(1f - checkAlpha);
+        }
+    }
+
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+
+        // Text colors enabled/disabled is handle via a color set.
+        itemView.setBackgroundColor(enabled ? mDefaultBgColor : mDisabledBgColor);
+        float imgAlpha = enabled ? 1f : DISABLED_ALPHA;
+
+        mIconMimeLg.setAlpha(imgAlpha);
+        mIconMimeSm.setAlpha(imgAlpha);
+        mIconThumb.setAlpha(imgAlpha);
     }
 
     /**
@@ -79,9 +114,9 @@
      * @param state Current display state.
      */
     public void bind(Cursor cursor, String modelId, State state) {
-        this.modelId = modelId;
+        assert(cursor != null);
 
-        checkNotNull(cursor, "Cursor cannot be null.");
+        this.modelId = modelId;
 
         final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
         final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
@@ -123,12 +158,4 @@
             mSize.setText(Formatter.formatFileSize(mContext, docSize));
         }
     }
-
-    /**
-     * Sets whether to hide titles on subsequently created GridDocumentHolder items.
-     * @param hideTitles
-     */
-    public static void setHideTitles(boolean hideTitles) {
-        mHideTitles = hideTitles;
-    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index be6413b..ace53e0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -19,7 +19,6 @@
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.content.Context;
 import android.database.Cursor;
@@ -30,6 +29,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.documentsui.R;
@@ -39,9 +39,10 @@
 
 final class ListDocumentHolder extends DocumentHolder {
     final TextView mTitle;
-    final TextView mSummary;
+    final LinearLayout mDetails;  // Container of date/size/summary
     final TextView mDate;
     final TextView mSize;
+    final TextView mSummary;
     final ImageView mIconMime;
     final ImageView mIconThumb;
     final ImageView mIconCheck;
@@ -51,24 +52,54 @@
         super(context, parent, R.layout.item_doc_list);
 
         mTitle = (TextView) itemView.findViewById(android.R.id.title);
-        mSummary = (TextView) itemView.findViewById(android.R.id.summary);
         mDate = (TextView) itemView.findViewById(R.id.date);
         mSize = (TextView) itemView.findViewById(R.id.size);
+        mSummary = (TextView) itemView.findViewById(android.R.id.summary);
         mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
         mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
         mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
+        // Warning: mDetails view doesn't exists in layout-sw720dp-land layout
+        mDetails = (LinearLayout) itemView.findViewById(R.id.line2);
 
         mIconHelper = iconHelper;
     }
 
     @Override
-    public void setSelected(boolean selected) {
-        super.setSelected(selected);
+    public void setSelected(boolean selected, boolean animate) {
+        // We always want to make sure our check box disappears if we're not selected,
+        // even if the item is disabled. But it should be an error (see assert below)
+        // to be set to selected && be disabled.
         float checkAlpha = selected ? 1f : 0f;
+        if (animate) {
+            mIconCheck.animate().alpha(checkAlpha).start();
+        } else {
+            mIconCheck.setAlpha(checkAlpha);
+        }
 
-        mIconCheck.animate().alpha(checkAlpha).start();
-        mIconMime.animate().alpha(1f - checkAlpha).start();
-        mIconThumb.animate().alpha(1f - checkAlpha).start();
+        if (!itemView.isEnabled()) {
+            assert(!selected);
+            return;
+        }
+
+        super.setSelected(selected, animate);
+
+        if (animate) {
+            mIconMime.animate().alpha(1f - checkAlpha).start();
+            mIconThumb.animate().alpha(1f - checkAlpha).start();
+        } else {
+            mIconMime.setAlpha(1f - checkAlpha);
+            mIconThumb.setAlpha(1f - checkAlpha);
+        }
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+
+        // Text colors enabled/disabled is handle via a color set.
+        final float imgAlpha = enabled ? 1f : DISABLED_ALPHA;
+        mIconMime.setAlpha(imgAlpha);
+        mIconThumb.setAlpha(imgAlpha);
     }
 
     /**
@@ -79,9 +110,9 @@
      */
     @Override
     public void bind(Cursor cursor, String modelId, State state) {
-        this.modelId = modelId;
+        assert(cursor != null);
 
-        checkNotNull(cursor, "Cursor cannot be null.");
+        this.modelId = modelId;
 
         final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
         final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
@@ -92,6 +123,7 @@
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
         final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
         final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+        final boolean isDirectory = Document.MIME_TYPE_DIR.equals(docMimeType);
 
         mIconHelper.stopLoading(mIconThumb);
 
@@ -106,32 +138,39 @@
         mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
         mTitle.setVisibility(View.VISIBLE);
 
-        if (docSummary != null) {
-            mSummary.setText(docSummary);
-            mSummary.setVisibility(View.VISIBLE);
+
+        boolean hasDetails = false;
+        if (isDirectory) {
+            // Note, we don't show any details for any directory...ever.
+            hasDetails = false;
         } else {
-            mSummary.setVisibility(View.INVISIBLE);
+            if (docSummary != null) {
+                hasDetails = true;
+                mSummary.setText(docSummary);
+                mSummary.setVisibility(View.VISIBLE);
+            } else {
+                mSummary.setVisibility(View.INVISIBLE);
+            }
+
+            if (docLastModified > 0) {
+                hasDetails = true;
+                mDate.setText(Shared.formatTime(mContext, docLastModified));
+            } else {
+                mDate.setText(null);
+            }
+
+            if (state.showSize && docSize > -1) {
+                hasDetails = true;
+                mSize.setVisibility(View.VISIBLE);
+                mSize.setText(Formatter.formatFileSize(mContext, docSize));
+            } else {
+                mSize.setVisibility(View.GONE);
+            }
         }
 
-        if (docLastModified == -1) {
-            mDate.setText(null);
-        } else {
-            mDate.setText(Shared.formatTime(mContext, docLastModified));
+        // mDetails view doesn't exists in layout-sw720dp-land layout
+        if (mDetails != null) {
+            mDetails.setVisibility(hasDetails ? View.VISIBLE : View.GONE);
         }
-
-        if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
-            mSize.setVisibility(View.GONE);
-        } else {
-            mSize.setVisibility(View.VISIBLE);
-            mSize.setText(Formatter.formatFileSize(mContext, docSize));
-        }
-    }
-
-    @Override
-    public void setEnabled(boolean enabled) {
-        super.setEnabled(enabled);
-        final float iconAlpha = enabled ? 1f : 0.5f;
-        mIconMime.setAlpha(iconAlpha);
-        mIconThumb.setAlpha(iconAlpha);
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index 9684a5a..3642b01 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -20,13 +20,10 @@
 import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
 import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
 import static com.android.documentsui.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.model.DocumentInfo.getCursorLong;
-import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.database.Cursor;
+import android.database.MergeCursor;
 import android.os.Bundle;
-import android.os.Looper;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
@@ -50,6 +47,7 @@
 @VisibleForTesting
 public class Model {
     private static final String TAG = "Model";
+    private static final String EMPTY = "";
 
     private boolean mIsLoading;
     private List<UpdateListener> mUpdateListeners = new ArrayList<>();
@@ -61,35 +59,19 @@
      * A sorted array of model IDs for the files currently in the Model.  Sort order is determined
      * by {@link #mSortOrder}
      */
-    private List<String> mIds = new ArrayList<>();
+    private String mIds[] = new String[0];
     private int mSortOrder = SORT_ORDER_DISPLAY_NAME;
 
+    private int mAuthorityIndex = -1;
+    private int mDocIdIndex = -1;
+    private int mMimeTypeIndex = -1;
+    private int mDisplayNameIndex = -1;
+    private int mSizeIndex = -1;
+    private int mLastModifiedIndex = -1;
+
     @Nullable String info;
     @Nullable String error;
-
-    /**
-     * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
-     * string that can be used to identify the document referred to by the cursor.
-     *
-     * @param c A cursor that refers to a document.
-     */
-    private static String createModelId(Cursor c) {
-        // TODO: Maybe more efficient to use just the document ID, in cases where there is only one
-        // authority (which should be the majority of cases).
-        return createModelId(
-                getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY),
-                getCursorString(c, Document.COLUMN_DOCUMENT_ID));
-    }
-
-    /**
-     * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
-     * string that can be used to identify the document referred to by the cursor.
-     *
-     * @param c A cursor that refers to a document.
-     */
-    static String createModelId(String authority, String docId) {
-        return authority + "|" + docId;
-    }
+    @Nullable DocumentInfo doc;
 
     private void notifyUpdateListeners() {
         for (UpdateListener listener: mUpdateListeners) {
@@ -109,10 +91,11 @@
         if (result == null) {
             mCursor = null;
             mCursorCount = 0;
-            mIds.clear();
+            mIds = new String[0];
             mPositions.clear();
             info = null;
             error = null;
+            doc = null;
             mIsLoading = false;
             notifyUpdateListeners();
             return;
@@ -127,6 +110,15 @@
         mCursor = result.cursor;
         mCursorCount = mCursor.getCount();
         mSortOrder = result.sortOrder;
+        mAuthorityIndex = mCursor.getColumnIndex(RootCursorWrapper.COLUMN_AUTHORITY);
+        assert(mAuthorityIndex != -1);
+        mDocIdIndex = mCursor.getColumnIndex(Document.COLUMN_DOCUMENT_ID);
+        mMimeTypeIndex = mCursor.getColumnIndex(Document.COLUMN_MIME_TYPE);
+        mDisplayNameIndex = mCursor.getColumnIndex(Document.COLUMN_DISPLAY_NAME);
+        mLastModifiedIndex = mCursor.getColumnIndex(Document.COLUMN_LAST_MODIFIED);
+        mSizeIndex = mCursor.getColumnIndex(Document.COLUMN_SIZE);
+
+        doc = result.doc;
 
         updateModelData();
 
@@ -151,74 +143,88 @@
      */
     private void updateModelData() {
         int[] positions = new int[mCursorCount];
-        mIds.clear();
-        String[] stringValues = new String[mCursorCount];
+        mIds = new String[mCursorCount];
+        boolean[] isDirs = new boolean[mCursorCount];
+        String[] displayNames = null;
         long[] longValues = null;
 
-        if (mSortOrder == SORT_ORDER_LAST_MODIFIED || mSortOrder == SORT_ORDER_SIZE) {
-            longValues = new long[mCursorCount];
+        switch (mSortOrder) {
+            case SORT_ORDER_DISPLAY_NAME:
+                displayNames = new String[mCursorCount];
+                break;
+            case SORT_ORDER_LAST_MODIFIED:
+            case SORT_ORDER_SIZE:
+                longValues = new long[mCursorCount];
+                break;
         }
 
+        String mimeType;
+
         mCursor.moveToPosition(-1);
         for (int pos = 0; pos < mCursorCount; ++pos) {
             mCursor.moveToNext();
             positions[pos] = pos;
-            mIds.add(createModelId(mCursor));
 
-            switch(mSortOrder) {
+            // Generates a Model ID for a cursor entry that refers to a document. The Model ID is a
+            // unique string that can be used to identify the document referred to by the cursor.
+            // If the cursor is a merged cursor over multiple authorities, then prefix the ids
+            // with the authority to avoid collisions.
+            if (mCursor instanceof MergeCursor) {
+                mIds[pos] = getStringOrEmpty(mAuthorityIndex) + "|" + getStringOrEmpty(mDocIdIndex);
+            } else {
+                mIds[pos] = getStringOrEmpty(mDocIdIndex);
+            }
+
+            mimeType = getStringOrEmpty(mMimeTypeIndex);
+            isDirs[pos] = Document.MIME_TYPE_DIR.equals(mimeType);
+
+            switch (mSortOrder) {
                 case SORT_ORDER_DISPLAY_NAME:
-                    final String mimeType = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
-                    final String displayName = getCursorString(
-                            mCursor, Document.COLUMN_DISPLAY_NAME);
-                    if (Document.MIME_TYPE_DIR.equals(mimeType)) {
-                        stringValues[pos] = Shared.DIR_PREFIX + displayName;
-                    } else {
-                        stringValues[pos] = displayName;
-                    }
+                    displayNames[pos] = getStringOrEmpty(mDisplayNameIndex);
                     break;
                 case SORT_ORDER_LAST_MODIFIED:
-                    longValues[pos] = getLastModified(mCursor);
-                    stringValues[pos] = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
+                    longValues[pos] = getLastModified();
                     break;
                 case SORT_ORDER_SIZE:
-                    longValues[pos] = getCursorLong(mCursor, Document.COLUMN_SIZE);
-                    stringValues[pos] = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
+                    longValues[pos] = getDocSize();
                     break;
             }
         }
 
         switch (mSortOrder) {
             case SORT_ORDER_DISPLAY_NAME:
-                binarySort(stringValues, positions, mIds);
+                binarySort(displayNames, isDirs, positions, mIds);
                 break;
             case SORT_ORDER_LAST_MODIFIED:
             case SORT_ORDER_SIZE:
-                binarySort(longValues, stringValues, positions, mIds);
+                binarySort(longValues, isDirs, positions, mIds);
                 break;
         }
 
         // Populate the positions.
         mPositions.clear();
         for (int i = 0; i < mCursorCount; ++i) {
-            mPositions.put(mIds.get(i), positions[i]);
+            mPositions.put(mIds[i], positions[i]);
         }
     }
 
     /**
      * Sorts model data. Takes three columns of index-corresponded data. The first column is the
-     * sort key. Rows are sorted in ascending alphabetical order on the sort key. This code is based
-     * on TimSort.binarySort().
+     * sort key. Rows are sorted in ascending alphabetical order on the sort key.
+     * Directories are always shown first. This code is based on TimSort.binarySort().
      *
      * @param sortKey Data is sorted in ascending alphabetical order.
+     * @param isDirs Array saying whether an item is a directory or not.
      * @param positions Cursor positions to be sorted.
      * @param ids Model IDs to be sorted.
      */
-    private static void binarySort(String[] sortKey, int[] positions, List<String> ids) {
+    private static void binarySort(String[] sortKey, boolean[] isDirs, int[] positions, String[] ids) {
         final int count = positions.length;
         for (int start = 1; start < count; start++) {
             final int pivotPosition = positions[start];
             final String pivotValue = sortKey[start];
-            final String pivotId = ids.get(start);
+            final boolean pivotIsDir = isDirs[start];
+            final String pivotId = ids[start];
 
             int left = 0;
             int right = start;
@@ -226,9 +232,18 @@
             while (left < right) {
                 int mid = (left + right) >>> 1;
 
-                final String lhs = pivotValue;
-                final String rhs = sortKey[mid];
-                final int compare = Shared.compareToIgnoreCaseNullable(lhs, rhs);
+                // Directories always go in front.
+                int compare = 0;
+                final boolean rhsIsDir = isDirs[mid];
+                if (pivotIsDir && !rhsIsDir) {
+                    compare = -1;
+                } else if (!pivotIsDir && rhsIsDir) {
+                    compare = 1;
+                } else {
+                    final String lhs = pivotValue;
+                    final String rhs = sortKey[mid];
+                    compare = Shared.compareToIgnoreCase(lhs, rhs);
+                }
 
                 if (compare < 0) {
                     right = mid;
@@ -242,23 +257,25 @@
                 case 2:
                     positions[left + 2] = positions[left + 1];
                     sortKey[left + 2] = sortKey[left + 1];
-                    ids.set(left + 2, ids.get(left + 1));
+                    isDirs[left + 2] = isDirs[left + 1];
+                    ids[left + 2] = ids[left + 1];
                 case 1:
                     positions[left + 1] = positions[left];
                     sortKey[left + 1] = sortKey[left];
-                    ids.set(left + 1, ids.get(left));
+                    isDirs[left + 1] = isDirs[left];
+                    ids[left + 1] = ids[left];
                     break;
                 default:
                     System.arraycopy(positions, left, positions, left + 1, n);
                     System.arraycopy(sortKey, left, sortKey, left + 1, n);
-                    for (int i = n; i >= 1; --i) {
-                        ids.set(left + i, ids.get(left + i - 1));
-                    }
+                    System.arraycopy(isDirs, left, isDirs, left + 1, n);
+                    System.arraycopy(ids, left, ids, left + 1, n);
             }
 
             positions[left] = pivotPosition;
             sortKey[left] = pivotValue;
-            ids.set(left, pivotId);
+            isDirs[left] = pivotIsDir;
+            ids[left] = pivotId;
         }
     }
 
@@ -269,18 +286,18 @@
      * numerical order on the sort key. This code is based on TimSort.binarySort().
      *
      * @param sortKey Data is sorted in descending numerical order.
-     * @param mimeTypes Corresponding mime types. Directories will be sorted ahead of documents.
+     * @param isDirs Array saying whether an item is a directory or not.
      * @param positions Cursor positions to be sorted.
      * @param ids Model IDs to be sorted.
      */
     private static void binarySort(
-            long[] sortKey, String[] mimeTypes, int[] positions, List<String> ids) {
+            long[] sortKey, boolean[] isDirs, int[] positions, String[] ids) {
         final int count = positions.length;
         for (int start = 1; start < count; start++) {
             final int pivotPosition = positions[start];
             final long pivotValue = sortKey[start];
-            final String pivotMime = mimeTypes[start];
-            final String pivotId = ids.get(start);
+            final boolean pivotIsDir = isDirs[start];
+            final String pivotId = ids[start];
 
             int left = 0;
             int right = start;
@@ -288,13 +305,12 @@
             while (left < right) {
                 int mid = ((left + right) >>> 1);
 
-                // First bucket by mime type.  Directories always go in front.
+                // Directories always go in front.
                 int compare = 0;
-                final boolean lhsIsDir = Document.MIME_TYPE_DIR.equals(pivotMime);
-                final boolean rhsIsDir = Document.MIME_TYPE_DIR.equals(mimeTypes[mid]);
-                if (lhsIsDir && !rhsIsDir) {
+                final boolean rhsIsDir = isDirs[mid];
+                if (pivotIsDir && !rhsIsDir) {
                     compare = -1;
-                } else if (!lhsIsDir && rhsIsDir) {
+                } else if (!pivotIsDir && rhsIsDir) {
                     compare = 1;
                 } else {
                     final long lhs = pivotValue;
@@ -309,7 +325,7 @@
                 // have identical numerical sort keys.  One common example of this scenario is seen
                 // when sorting a set of active downloads by mod time.
                 if (compare == 0) {
-                    compare = pivotId.compareTo(ids.get(mid));
+                    compare = pivotId.compareTo(ids[mid]);
                 }
 
                 if (compare < 0) {
@@ -324,38 +340,65 @@
                 case 2:
                     positions[left + 2] = positions[left + 1];
                     sortKey[left + 2] = sortKey[left + 1];
-                    mimeTypes[left + 2] = mimeTypes[left + 1];
-                    ids.set(left + 2, ids.get(left + 1));
+                    isDirs[left + 2] = isDirs[left + 1];
+                    ids[left + 2] = ids[left + 1];
                 case 1:
                     positions[left + 1] = positions[left];
                     sortKey[left + 1] = sortKey[left];
-                    mimeTypes[left + 1] = mimeTypes[left];
-                    ids.set(left + 1, ids.get(left));
+                    isDirs[left + 1] = isDirs[left];
+                    ids[left + 1] = ids[left];
                     break;
                 default:
                     System.arraycopy(positions, left, positions, left + 1, n);
                     System.arraycopy(sortKey, left, sortKey, left + 1, n);
-                    System.arraycopy(mimeTypes, left, mimeTypes, left + 1, n);
-                    for (int i = n; i >= 1; --i) {
-                        ids.set(left + i, ids.get(left + i - 1));
-                    }
+                    System.arraycopy(isDirs, left, isDirs, left + 1, n);
+                    System.arraycopy(ids, left, ids, left + 1, n);
             }
 
             positions[left] = pivotPosition;
             sortKey[left] = pivotValue;
-            mimeTypes[left] = pivotMime;
-            ids.set(left, pivotId);
+            isDirs[left] = pivotIsDir;
+            ids[left] = pivotId;
         }
     }
 
     /**
-     * @return Timestamp for the given document. Some docs (e.g. active downloads) have a null
-     * timestamp - these will be replaced with MAX_LONG so that such files get sorted to the top
-     * when sorting by date.
+     * @return Value of the string column, or an empty string if no value, or empty value.
      */
-    long getLastModified(Cursor cursor) {
-        long l = getCursorLong(mCursor, Document.COLUMN_LAST_MODIFIED);
-        return (l == -1) ? Long.MAX_VALUE : l;
+    private String getStringOrEmpty(int columnIndex) {
+        if (columnIndex == -1)
+            return EMPTY;
+        final String result = mCursor.getString(columnIndex);
+        return result != null ? result : EMPTY;
+    }
+
+    /**
+     * @return Timestamp for the given document. Some docs (e.g. active downloads) have a null
+     * or missing timestamp - these will be replaced with MAX_LONG so that such files get sorted to
+     * the top when sorting by date.
+     */
+    private long getLastModified() {
+        if (mLastModifiedIndex == -1)
+            return Long.MAX_VALUE;
+        try {
+            final long result = mCursor.getLong(mLastModifiedIndex);
+            return result > 0 ? result : Long.MAX_VALUE;
+        } catch (NumberFormatException e) {
+            return Long.MAX_VALUE;
+        }
+    }
+
+    /**
+     * @return Size for the given document. If the size is unknown or invalid, returns 0.
+     */
+    private long getDocSize() {
+        if (mSizeIndex == -1)
+            return 0;
+        try {
+            return mCursor.getLong(mSizeIndex);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
     }
 
     public @Nullable Cursor getItem(String modelId) {
@@ -381,9 +424,9 @@
         final List<DocumentInfo> docs =  new ArrayList<>(size);
         for (String modelId: items.getAll()) {
             final Cursor cursor = getItem(modelId);
-            checkNotNull(cursor, "Cursor cannot be null.");
-            final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
-            docs.add(doc);
+            assert(cursor != null);
+
+            docs.add(DocumentInfo.fromDirectoryCursor(cursor));
         }
         return docs;
     }
@@ -412,7 +455,7 @@
      * @return An ordered array of model IDs representing the documents in the model. It is sorted
      *         according to the current sort order, which was set by the last model update.
      */
-    public List<String> getModelIds() {
+    public String[] getModelIds() {
         return mIds;
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index dd27790..ca3b2e2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -102,7 +102,7 @@
     public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
         if (payload.contains(SELECTION_CHANGED_MARKER)) {
             final boolean selected = mEnv.isSelected(mModelIds.get(position));
-            holder.setSelected(selected);
+            holder.setSelected(selected, true);
         } else {
             onBindViewHolder(holder, position);
         }
@@ -117,8 +117,13 @@
         final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
 
-        holder.setSelected(mEnv.isSelected(modelId));
-        holder.setEnabled(mEnv.isDocumentEnabled(docMimeType, docFlags));
+        boolean enabled = mEnv.isDocumentEnabled(docMimeType, docFlags);
+        boolean selected = mEnv.isSelected(modelId);
+        if (!enabled) {
+            assert(!selected);
+        }
+        holder.setEnabled(enabled);
+        holder.setSelected(mEnv.isSelected(modelId), false);
 
         mEnv.onBindDocumentHolder(holder, cursor);
     }
@@ -134,8 +139,8 @@
             Log.d(TAG, "Updating model with hidden ids: " + mHiddenIds);
         }
 
-        List<String> modelIds = model.getModelIds();
-        mModelIds = new ArrayList<>(modelIds.size());
+        String[] modelIds = model.getModelIds();
+        mModelIds = new ArrayList<>(modelIds.length);
         for (String id : modelIds) {
             if (!mHiddenIds.contains(id)) {
                 mModelIds.add(id);
@@ -181,28 +186,6 @@
     }
 
     @Override
-    public void unhide(SparseArray<String> ids) {
-        if (DEBUG) Log.d(TAG, "Unhiding ids: " + ids);
-
-        // An ArrayList can shrink at runtime...and in fact
-        // it does when we clear it completely.
-        // This means we can't call add(pos, id) without
-        // first checking the list size.
-        List<String> oldIds = mModelIds;
-        mModelIds = new ArrayList<>(oldIds.size() + ids.size());
-        mModelIds.addAll(oldIds);
-
-        // Finally insert the unhidden items.
-        for (int i = 0; i < ids.size(); i++) {
-            int pos = ids.keyAt(i);
-            String id = ids.get(pos);
-            mHiddenIds.remove(id);
-            mModelIds.add(pos, id);
-            notifyItemInserted(pos);
-        }
-    }
-
-    @Override
     public List<String> getModelIds() {
         return mModelIds;
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index c8b6f85..b80486d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -19,9 +19,6 @@
 import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.dirlist.ModelBackedDocumentsAdapter.ITEM_TYPE_DIRECTORY;
 import static com.android.documentsui.dirlist.ModelBackedDocumentsAdapter.ITEM_TYPE_DOCUMENT;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.annotation.IntDef;
 import android.graphics.Point;
@@ -134,8 +131,12 @@
             @SelectionMode int mode,
             @Nullable Selection initialSelection) {
 
-        mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
-        mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
+        assert(environment != null);
+        assert(adapter != null);
+
+        mEnvironment = environment;
+        mAdapter = adapter;
+
         mSingleSelect = mode == MODE_SINGLE;
         if (initialSelection != null) {
             mSelection.copyFrom(initialSelection);
@@ -168,8 +169,8 @@
 
                     @Override
                     public void onItemRangeRemoved(int startPosition, int itemCount) {
-                        checkState(startPosition >= 0);
-                        checkState(itemCount > 0);
+                        assert(startPosition >= 0);
+                        assert(itemCount > 0);
 
                         mSelection.cancelProvisionalSelection();
                         // Remove any disappeared IDs from the selection.
@@ -356,7 +357,8 @@
      * @param modelId
      */
     public void toggleSelection(String modelId) {
-        checkNotNull(modelId);
+        assert(modelId != null);
+
         boolean changed = false;
         if (mSelection.contains(modelId)) {
             changed = attemptDeselect(modelId);
@@ -389,7 +391,8 @@
      * @param pos The new end position for the selection range.
      */
     void snapRangeSelection(int pos) {
-        checkNotNull(mRanger);
+        assert(mRanger != null);
+
         mRanger.snapSelection(pos);
         notifySelectionChanged();
     }
@@ -436,7 +439,7 @@
      * @param selected New selection state.
      */
     private void updateRange(int begin, int end, boolean selected) {
-        checkState(end >= begin);
+        assert(end >= begin);
         for (int i = begin; i <= end; i++) {
             String id = mAdapter.getModelId(i);
             if (id == null) {
@@ -474,7 +477,7 @@
      * @return True if the update was applied.
      */
     private boolean attemptDeselect(String id) {
-        checkArgument(id != null);
+        assert(id != null);
         if (notifyBeforeItemStateChange(id, false)) {
             mSelection.remove(id);
             notifyItemStateChanged(id, false);
@@ -491,7 +494,7 @@
      * @return True if the update was applied.
      */
     private boolean attemptSelect(String id) {
-        checkArgument(id != null);
+        assert(id != null);
         boolean canSelect = notifyBeforeItemStateChange(id, true);
         if (!canSelect) {
             return false;
@@ -519,7 +522,7 @@
      * (identified by {@code position}) changes.
      */
     private void notifyItemStateChanged(String id, boolean selected) {
-        checkArgument(id != null);
+        assert(id != null);
         int lastListener = mCallbacks.size() - 1;
         for (int i = lastListener; i > -1; i--) {
             mCallbacks.get(i).onItemStateChanged(id, selected);
@@ -555,8 +558,8 @@
         }
 
         private void snapSelection(int position) {
-            checkState(mRanger != null);
-            checkArgument(position != RecyclerView.NO_POSITION);
+            assert(mRanger != null);
+            assert(position != RecyclerView.NO_POSITION);
 
             if (mEnd == UNDEFINED || mEnd == mBegin) {
                 // Reset mEnd so it can be established in establishRange.
@@ -568,7 +571,7 @@
         }
 
         private void establishRange(int position) {
-            checkState(mRanger.mEnd == UNDEFINED);
+            assert(mRanger.mEnd == UNDEFINED);
 
             if (position == mBegin) {
                 mEnd = position;
@@ -584,8 +587,8 @@
         }
 
         private void reviseRange(int position) {
-            checkState(mEnd != UNDEFINED);
-            checkState(mBegin != mEnd);
+            assert(mEnd != UNDEFINED);
+            assert(mBegin != mEnd);
 
             if (position == mEnd) {
                 if (DEBUG) Log.i(TAG, "Skipping no-op revision click on mEndRange.");
@@ -657,15 +660,22 @@
         // item A is tapped (and selected), then an in-progress band select covers A then uncovers
         // A, A should still be selected as it has been saved. To ensure this behavior, the saved
         // selection must be tracked separately.
-        private Set<String> mSelection = new HashSet<>();
-        private Set<String> mProvisionalSelection = new HashSet<>();
+        private final Set<String> mSelection;
+        private final Set<String> mProvisionalSelection;
         private String mDirectoryKey;
 
-        @VisibleForTesting
-        public Selection(String... ids) {
-            for (int i = 0; i < ids.length; i++) {
-                add(ids[i]);
-            }
+        public Selection() {
+            mSelection = new HashSet<String>();
+            mProvisionalSelection = new HashSet<String>();
+        }
+
+        /**
+         * Used by CREATOR.
+         */
+        private Selection(String directoryKey, List<String> selection) {
+            mDirectoryKey = directoryKey;
+            mSelection = new HashSet<String>(selection);
+            mProvisionalSelection = new HashSet<String>();
         }
 
         /**
@@ -687,7 +697,7 @@
          * Returns an unordered array of selected positions (including any
          * provisional selections current in effect).
          */
-        private List<String> toList() {
+        public List<String> toList() {
             ArrayList<String> selection = new ArrayList<String>(mSelection);
             selection.addAll(mProvisionalSelection);
             return selection;
@@ -810,8 +820,11 @@
 
         @VisibleForTesting
         void copyFrom(Selection source) {
-            mSelection = new HashSet<>(source.mSelection);
-            mProvisionalSelection = new HashSet<>(source.mProvisionalSelection);
+            mSelection.clear();
+            mSelection.addAll(source.mSelection);
+
+            mProvisionalSelection.clear();
+            mProvisionalSelection.addAll(source.mProvisionalSelection);
         }
 
         @Override
@@ -878,6 +891,26 @@
             // We don't include provisional selection since it is
             // typically coupled to some other runtime state (like a band).
         }
+
+        public static final ClassLoaderCreator<Selection> CREATOR =
+                new ClassLoaderCreator<Selection>() {
+            @Override
+            public Selection createFromParcel(Parcel in) {
+                return createFromParcel(in, null);
+            }
+
+            @Override
+            public Selection createFromParcel(Parcel in, ClassLoader loader) {
+                return new Selection(
+                        in.readString(),
+                        in.readArrayList(loader));
+            }
+
+            @Override
+            public Selection[] newArray(int size) {
+                return new Selection[size];
+            }
+        };
     }
 
     /**
@@ -898,7 +931,6 @@
         Rect getAbsoluteRectForChildViewAt(int index);
         int getAdapterPositionAt(int index);
         int getColumnCount();
-        int getRowCount();
         int getChildCount();
         int getVisibleChildCount();
         /**
@@ -975,13 +1007,6 @@
         }
 
         @Override
-        public int getRowCount() {
-            int numFullColumns = getChildCount() / getColumnCount();
-            boolean hasPartiallyFullColumn = getChildCount() % getColumnCount() != 0;
-            return numFullColumns + (hasPartiallyFullColumn ? 1 : 0);
-        }
-
-        @Override
         public int getHeight() {
             return mView.getHeight();
         }
@@ -1155,7 +1180,7 @@
          * @param input
          */
         private void processInputEvent(InputEvent input) {
-            checkArgument(input.isMouseEvent());
+            assert(input.isMouseEvent());
 
             if (shouldStop(input)) {
                 endBandSelect();
@@ -1458,6 +1483,7 @@
          *     top-left of the viewport would have a relative origin of (0, 0), even though its
          *     absolute point has a higher y-value.
          */
+        @VisibleForTesting
         void resizeSelection(Point relativePointer) {
             mPointer = mHelper.createAbsolutePoint(relativePointer);
             updateModel();
@@ -1516,11 +1542,7 @@
                         mColumnBounds, new Limits(absoluteChildRect.left, absoluteChildRect.right));
             }
 
-            if (mRowBounds.size() != mHelper.getRowCount()) {
-                // If not all y-limits have been recorded, record this one.
-                recordLimits(
-                        mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
-            }
+            recordLimits(mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
 
             SparseIntArray columnList = mColumns.get(absoluteChildRect.left);
             if (columnList == null) {
@@ -1585,7 +1607,7 @@
         private void updateSelection(Rect rect) {
             int columnStart =
                     Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
-            checkState(columnStart >= 0);
+            assert(columnStart >= 0);
             int columnEnd = columnStart;
 
             for (int i = columnStart; i < mColumnBounds.size()
@@ -1714,6 +1736,11 @@
                 return ((Limits) other).lowerLimit == lowerLimit &&
                         ((Limits) other).upperLimit == upperLimit;
             }
+
+            @Override
+            public String toString() {
+                return "(" + lowerLimit + ", " + upperLimit + ")";
+            }
         }
 
         /**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 7394c12..73aa366 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -17,7 +17,6 @@
 package com.android.documentsui.dirlist;
 
 import static com.android.documentsui.Shared.TAG;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -36,16 +35,18 @@
 import android.support.design.widget.Snackbar;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.inputmethod.EditorInfo;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.Metrics;
 import com.android.documentsui.R;
+import com.android.documentsui.Shared;
 import com.android.documentsui.Snackbars;
 import com.android.documentsui.model.DocumentInfo;
 
@@ -55,6 +56,7 @@
 public class RenameDocumentFragment extends DialogFragment {
     private static final String TAG_RENAME_DOCUMENT = "rename_document";
     private DocumentInfo mDocument;
+    private EditText mEditText;
 
     public static void show(FragmentManager fm, DocumentInfo document) {
         final RenameDocumentFragment dialog = new RenameDocumentFragment();
@@ -62,6 +64,11 @@
         dialog.show(fm, TAG_RENAME_DOCUMENT);
     }
 
+    /**
+     * Creates the dialog UI.
+     * @param savedInstanceState
+     * @return
+     */
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         Context context = getActivity();
@@ -69,8 +76,7 @@
         LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
         View view = dialogInflater.inflate(R.layout.dialog_file_name, null, false);
 
-        final EditText editText = (EditText) view.findViewById(android.R.id.text1);
-        fillWithFileName(editText, mDocument.displayName);
+        mEditText = (EditText) view.findViewById(android.R.id.text1);
         builder.setTitle(R.string.menu_rename);
         builder.setView(view);
 
@@ -79,7 +85,7 @@
                 new OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        renameDocuments(editText.getText().toString());
+                        renameDocuments(mEditText.getText().toString());
                     }
                 });
 
@@ -87,7 +93,10 @@
 
         final AlertDialog dialog = builder.create();
 
-        editText.setOnEditorActionListener(
+        // Workaround for the problem - virtual keyboard doesn't show on the phone.
+        Shared.ensureKeyboardPresent(context, dialog);
+
+        mEditText.setOnEditorActionListener(
                 new OnEditorActionListener() {
                     @Override
                     public boolean onEditorAction(
@@ -95,18 +104,51 @@
                         if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null
                                 && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
                                 && event.hasNoModifiers())) {
-                            renameDocuments(editText.getText().toString());
+                            renameDocuments(mEditText.getText().toString());
                             dialog.dismiss();
                             return true;
                         }
                         return false;
                     }
                 });
-
         return dialog;
     }
 
     /**
+     * Sets/Restores the data.
+     * @param savedInstanceState
+     * @return
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        if(savedInstanceState == null) {
+            // Fragment created for the first time, we set the text.
+            // mDocument value was set in show
+            mEditText.setText(mDocument.displayName);
+        }
+        else {
+            // Fragment restored, text was restored automatically.
+            // mDocument value needs to be restored.
+            mDocument = savedInstanceState.getParcelable(Shared.EXTRA_DOC);
+        }
+        // Do selection in both cases, because we cleared it.
+        selectFileName(mEditText);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        // Clear selection before storing state and restore it manually,
+        // because otherwise after rotation selection is displayed with cut/copy menu visible :/
+        clearFileNameSelection(mEditText);
+
+        super.onSaveInstanceState(outState);
+
+        outState.putParcelable(Shared.EXTRA_DOC, mDocument);
+    }
+
+    /**
      * Validates if string is a proper document name.
      * Checks if string is not empty. More rules might be added later.
      * @param docName string representing document name
@@ -120,12 +162,21 @@
      * Fills text field with the file name and selects the name without extension.
      *
      * @param editText text field to be filled
-     * @param name full name of the file
      */
-    private void fillWithFileName(EditText editText, String name) {
-        editText.setText(name);
-        int separatorIndex = name.indexOf(".");
-        editText.setSelection(0, separatorIndex == -1 ? name.length() : separatorIndex);
+    private void selectFileName(EditText editText) {
+        String text = editText.getText().toString();
+        int separatorIndex = text.indexOf(".");
+        editText.setSelection(0,
+                (separatorIndex == -1 || mDocument.isDirectory()) ? text.length() : separatorIndex);
+    }
+
+    /**
+     * Clears selection in text field.
+     *
+     * @param editText text field to be cleared.
+     */
+    private void clearFileNameSelection(EditText editText) {
+        editText.setSelection(0, 0);
     }
 
     private void renameDocuments(String newDisplayName) {
@@ -157,7 +208,7 @@
 
         @Override
         protected DocumentInfo doInBackground(DocumentInfo... document) {
-            checkArgument(document.length == 1);
+            assert(document.length == 1);
             final ContentResolver resolver = mActivity.getContentResolver();
             ContentProviderClient client = null;
 
@@ -177,11 +228,13 @@
 
         @Override
         protected void onPostExecute(DocumentInfo result) {
-            if (result == null) {
+            if (result != null) {
+                Metrics.logRenameFileOperation(getContext());
+            } else {
                 Snackbars.makeSnackbar(mActivity, R.string.rename_error, Snackbar.LENGTH_SHORT)
                         .show();
+                Metrics.logRenameFileError(getContext());
             }
-
             mActivity.setPending(false);
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
index 2485ad9..b698059 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
@@ -16,8 +16,6 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.internal.util.Preconditions.checkArgument;
-
 import android.content.Context;
 import android.database.Cursor;
 import android.support.v7.widget.GridLayoutManager;
@@ -171,13 +169,6 @@
     }
 
     @Override
-    void unhide(SparseArray<String> ids) {
-        // NOTE: We hear about these changes and adjust break position
-        // in our AdapterDataObserver.
-        mDelegate.unhide(ids);
-    }
-
-    @Override
     List<String> getModelIds() {
         return mDelegate.getModelIds();
     }
@@ -204,12 +195,12 @@
         }
 
         public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
-            checkArgument(itemCount == 1);
+            assert(itemCount == 1);
             notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload);
         }
 
         public void onItemRangeInserted(int positionStart, int itemCount) {
-            checkArgument(itemCount == 1);
+            assert(itemCount == 1);
             if (positionStart < mBreakPosition) {
                 mBreakPosition++;
             }
@@ -217,7 +208,7 @@
         }
 
         public void onItemRangeRemoved(int positionStart, int itemCount) {
-            checkArgument(itemCount == 1);
+            assert(itemCount == 1);
             if (positionStart < mBreakPosition) {
                 mBreakPosition--;
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index e9fdab0..31ce837 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -74,7 +74,6 @@
         summary = null;
         size = -1;
         icon = 0;
-
         derivedUri = null;
     }
 
@@ -207,7 +206,14 @@
         return "Document{"
                 + "docId=" + documentId
                 + ", name=" + displayName
+                + ", isContainer=" + isContainer()
                 + ", isDirectory=" + isDirectory()
+                + ", isArchive=" + isArchive()
+                + ", isPartial=" + isPartial()
+                + ", isVirtualDocument=" + isVirtualDocument()
+                + ", isDeleteSupported=" + isDeleteSupported()
+                + ", isCreateSupported=" + isCreateSupported()
+                + ", isRenameSupported=" + isRenameSupported()
                 + "}";
     }
 
@@ -231,18 +237,22 @@
         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
     }
 
+    public boolean isRemoveSupported() {
+        return (flags & Document.FLAG_SUPPORTS_REMOVE) != 0;
+    }
+
     public boolean isRenameSupported() {
         return (flags & Document.FLAG_SUPPORTS_RENAME) != 0;
     }
 
-    public boolean isGridTitlesHidden() {
-        return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0;
-    }
-
     public boolean isArchive() {
         return (flags & Document.FLAG_ARCHIVE) != 0;
     }
 
+    public boolean isPartial() {
+        return (flags & Document.FLAG_PARTIAL) != 0;
+    }
+
     public boolean isContainer() {
         return isDirectory() || isArchive();
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 3897058..0709652 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui.model;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.compareToIgnoreCaseNullable;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
@@ -31,6 +32,7 @@
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.documentsui.IconUtils;
 import com.android.documentsui.R;
@@ -47,11 +49,13 @@
  * Representation of a {@link Root}.
  */
 public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
+
+    private static final String TAG = "RootInfo";
     private static final int VERSION_INIT = 1;
     private static final int VERSION_DROP_TYPE = 2;
 
     // The values of these constants determine the sort order of various roots in the RootsFragment.
-    @IntDef(flag = true, value = {
+    @IntDef(flag = false, value = {
             TYPE_IMAGES,
             TYPE_VIDEO,
             TYPE_AUDIO,
@@ -59,6 +63,8 @@
             TYPE_DOWNLOADS,
             TYPE_LOCAL,
             TYPE_MTP,
+            TYPE_SD,
+            TYPE_USB,
             TYPE_OTHER
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -70,7 +76,9 @@
     public static final int TYPE_DOWNLOADS = 5;
     public static final int TYPE_LOCAL = 6;
     public static final int TYPE_MTP = 7;
-    public static final int TYPE_OTHER = 8;
+    public static final int TYPE_SD = 8;
+    public static final int TYPE_USB = 9;
+    public static final int TYPE_OTHER = 10;
 
     public String authority;
     public String rootId;
@@ -185,33 +193,40 @@
     private void deriveFields() {
         derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
 
-        // TODO: remove these special case icons
         if (isHome()) {
+            derivedType = TYPE_LOCAL;
             derivedIcon = R.drawable.ic_root_documents;
-            derivedType = TYPE_LOCAL;
-        } else if (isExternalStorage()) {
-            derivedIcon = R.drawable.ic_root_smartphone;
-            derivedType = TYPE_LOCAL;
-            // TODO: Apply SD card icon to SD devices.
-        } else if (isDownloads()) {
-            derivedIcon = R.drawable.ic_root_download;
-            derivedType = TYPE_DOWNLOADS;
-        } else if (isImages()) {
-            derivedIcon = R.drawable.ic_doc_image;
-            derivedType = TYPE_IMAGES;
-        } else if (isVideos()) {
-            derivedIcon = R.drawable.ic_doc_video;
-            derivedType = TYPE_VIDEO;
-        } else if (isAudio()) {
-            derivedIcon = R.drawable.ic_doc_audio;
-            derivedType = TYPE_AUDIO;
-        } else if (isRecents()) {
-            derivedType = TYPE_RECENTS;
         } else if (isMtp()) {
             derivedType = TYPE_MTP;
+            derivedIcon = R.drawable.ic_usb_storage;
+        } else if (isUsb()) {
+            derivedType = TYPE_USB;
+            derivedIcon = R.drawable.ic_usb_storage;
+        } else if (isSd()) {
+            derivedType = TYPE_SD;
+            derivedIcon = R.drawable.ic_sd_storage;
+        } else if (isExternalStorage()) {
+            derivedType = TYPE_LOCAL;
+            derivedIcon = R.drawable.ic_root_smartphone;
+        } else if (isDownloads()) {
+            derivedType = TYPE_DOWNLOADS;
+            derivedIcon = R.drawable.ic_root_download;
+        } else if (isImages()) {
+            derivedType = TYPE_IMAGES;
+            derivedIcon = R.drawable.ic_doc_image;
+        } else if (isVideos()) {
+            derivedType = TYPE_VIDEO;
+            derivedIcon = R.drawable.ic_doc_video;
+        } else if (isAudio()) {
+            derivedType = TYPE_AUDIO;
+            derivedIcon = R.drawable.ic_doc_audio;
+        } else if (isRecents()) {
+            derivedType = TYPE_RECENTS;
         } else {
             derivedType = TYPE_OTHER;
         }
+
+        if (DEBUG) Log.d(TAG, "Finished deriving fields: " + this);
     }
 
     public Uri getUri() {
@@ -295,6 +310,14 @@
         return (flags & Root.FLAG_EMPTY) != 0;
     }
 
+    public boolean isSd() {
+        return (flags & Root.FLAG_REMOVABLE_SD) != 0;
+    }
+
+    public boolean isUsb() {
+        return (flags & Root.FLAG_REMOVABLE_USB) != 0;
+    }
+
     public Drawable loadIcon(Context context) {
         if (derivedIcon != 0) {
             return context.getDrawable(derivedIcon);
@@ -362,7 +385,14 @@
 
     @Override
     public String toString() {
-        return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
+        return "Root{"
+                + "authority=" + authority
+                + ", rootId=" + rootId
+                + ", title=" + title
+                + ", isUsb=" + isUsb()
+                + ", isSd=" + isSd()
+                + ", isMtp=" + isMtp()
+                + "}";
     }
 
     public String getDirectoryString() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index dad8697..f10af43 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -29,7 +29,6 @@
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
 import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
 import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
-import static com.google.common.base.Preconditions.checkArgument;
 
 import android.annotation.StringRes;
 import android.app.Notification;
@@ -46,6 +45,8 @@
 import android.os.RemoteException;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.webkit.MimeTypeMap;
@@ -67,12 +68,15 @@
 import java.util.List;
 
 class CopyJob extends Job {
+
     private static final String TAG = "CopyJob";
-    private static final int PROGRESS_INTERVAL_MILLIS = 1000;
+    private static final int PROGRESS_INTERVAL_MILLIS = 500;
+
     final List<DocumentInfo> mSrcs;
     final ArrayList<DocumentInfo> convertedFiles = new ArrayList<>();
 
     private long mStartTime = -1;
+
     private long mBatchSize;
     private long mBytesCopied;
     private long mLastNotificationTime;
@@ -92,7 +96,7 @@
             String id, DocumentStack stack, List<DocumentInfo> srcs) {
         super(service, appContext, listener, OPERATION_COPY, id, stack);
 
-        checkArgument(!srcs.isEmpty());
+        assert(!srcs.isEmpty());
         this.mSrcs = srcs;
     }
 
@@ -105,7 +109,7 @@
             @OpType int opType, String id, DocumentStack destination, List<DocumentInfo> srcs) {
         super(service, appContext, listener, opType, id, destination);
 
-        checkArgument(!srcs.isEmpty());
+        assert(!srcs.isEmpty());
         this.mSrcs = srcs;
     }
 
@@ -129,10 +133,19 @@
     }
 
     Notification getProgressNotification(@StringRes int msgId) {
-        double completed = (double) this.mBytesCopied / mBatchSize;
-        mProgressBuilder.setProgress(100, (int) (completed * 100), false);
-        mProgressBuilder.setContentInfo(
-                NumberFormat.getPercentInstance().format(completed));
+        if (mBatchSize >= 0) {
+            double completed = (double) this.mBytesCopied / mBatchSize;
+            mProgressBuilder.setProgress(100, (int) (completed * 100), false);
+            mProgressBuilder.setContentInfo(
+                    NumberFormat.getPercentInstance().format(completed));
+        } else {
+            // If the total file size failed to compute on some files, then show
+            // an indeterminate spinner. CopyJob would most likely fail on those
+            // files while copying, but would continue with another files.
+            // Also, if the total size is 0 bytes, show an indeterminate spinner.
+            mProgressBuilder.setProgress(0, 0, true);
+        }
+
         if (mRemainingTime > 0) {
             mProgressBuilder.setContentText(service.getString(msgId,
                     DateUtils.formatDuration(mRemainingTime)));
@@ -208,11 +221,15 @@
     }
 
     @Override
-    void start() throws RemoteException {
+    void start() {
         mStartTime = elapsedRealtime();
 
-        // client
-        mBatchSize = calculateSize(mSrcs);
+        try {
+            mBatchSize = calculateSize(mSrcs);
+        } catch (ResourceException e) {
+            Log.w(TAG, "Failed to calculate total size. Copying without progress.");
+            mBatchSize = -1;
+        }
 
         DocumentInfo srcInfo;
         DocumentInfo dstInfo = stack.peek();
@@ -220,9 +237,13 @@
             srcInfo = mSrcs.get(i);
 
             // Guard unsupported recursive operation.
-            if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
-                onFileFailed(srcInfo,
-                        "Skipping recursive operation on directory " + dstInfo.derivedUri + ".");
+            try {
+                if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
+                    throw new ResourceException("Cannot copy to itself recursively.");
+                }
+            } catch (ResourceException e) {
+                Log.e(TAG, e.toString());
+                onFileFailed(srcInfo);
                 continue;
             }
 
@@ -230,7 +251,12 @@
                     "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")"
                     + " to " + dstInfo.displayName + " (" + dstInfo.derivedUri + ")");
 
-            processDocument(srcInfo, null, dstInfo);
+            try {
+                processDocument(srcInfo, null, dstInfo);
+            } catch (ResourceException e) {
+                Log.e(TAG, e.toString());
+                onFileFailed(srcInfo);
+            }
         }
         Metrics.logFileOperation(service, operationType, mSrcs, dstInfo);
     }
@@ -259,13 +285,12 @@
      * @param src DocumentInfos for the documents to copy.
      * @param srcParent DocumentInfo for the parent of the document to process.
      * @param dstDirInfo The destination directory.
-     * @return True on success, false on failure.
-     * @throws RemoteException
+     * @throws ResourceException
      *
      * TODO: Stop passing srcParent, as it's not used for copy, but for move only.
      */
-    boolean processDocument(DocumentInfo src, DocumentInfo srcParent,
-            DocumentInfo dstDirInfo) throws RemoteException {
+    void processDocument(DocumentInfo src, DocumentInfo srcParent,
+            DocumentInfo dstDirInfo) throws ResourceException {
 
         // TODO: When optimized copy kicks in, we'll not making any progress updates.
         // For now. Local storage isn't using optimized copy.
@@ -274,22 +299,25 @@
         // If not supported, then fallback to byte-by-byte copy/move.
         if (src.authority.equals(dstDirInfo.authority)) {
             if ((src.flags & Document.FLAG_SUPPORTS_COPY) != 0) {
-                if (DocumentsContract.copyDocument(getClient(src), src.derivedUri,
-                        dstDirInfo.derivedUri) == null) {
-                    onFileFailed(src,
-                            "Provider side copy failed for documents: " + src.derivedUri + ".");
-                    return false;
+                try {
+                    if (DocumentsContract.copyDocument(getClient(src), src.derivedUri,
+                            dstDirInfo.derivedUri) != null) {
+                        return;
+                    }
+                } catch (RemoteException | RuntimeException e) {
+                    Log.e(TAG, "Provider side copy failed for: " + src.derivedUri
+                            + " due to an exception: " + e);
                 }
-                return true;
+                // If optimized copy fails, then fallback to byte-by-byte copy.
+                if (DEBUG) Log.d(TAG, "Fallback to byte-by-byte copy for: " + src.derivedUri);
             }
         }
 
         // If we couldn't do an optimized copy...we fall back to vanilla byte copy.
-        return byteCopyDocument(src, dstDirInfo);
+        byteCopyDocument(src, dstDirInfo);
     }
 
-    boolean byteCopyDocument(DocumentInfo src, DocumentInfo dest)
-            throws RemoteException {
+    void byteCopyDocument(DocumentInfo src, DocumentInfo dest) throws ResourceException {
         final String dstMimeType;
         final String dstDisplayName;
 
@@ -297,8 +325,14 @@
         // If the file is virtual, but can be converted to another format, then try to copy it
         // as such format. Also, append an extension for the target mime type (if known).
         if (src.isVirtualDocument()) {
-            final String[] streamTypes = getContentResolver().getStreamTypes(
-                    src.derivedUri, "*/*");
+            String[] streamTypes = null;
+            try {
+                streamTypes = getContentResolver().getStreamTypes(src.derivedUri, "*/*");
+            } catch (RuntimeException e) {
+                throw new ResourceException(
+                        "Failed to obtain streamable types for %s due to an exception.",
+                        src.derivedUri, e);
+            }
             if (streamTypes != null && streamTypes.length > 0) {
                 dstMimeType = streamTypes[0];
                 final String extension = MimeTypeMap.getSingleton().
@@ -306,8 +340,8 @@
                 dstDisplayName = src.displayName +
                         (extension != null ? "." + extension : src.displayName);
             } else {
-                onFileFailed(src, "Cannot copy virtual file. No streamable formats available.");
-                return false;
+                throw new ResourceException("Cannot copy virtual file %s. No streamable formats "
+                        + "available.", src.derivedUri);
             }
         } else {
             dstMimeType = src.mimeType;
@@ -316,33 +350,35 @@
 
         // Create the target document (either a file or a directory), then copy recursively the
         // contents (bytes or children).
-        final Uri dstUri = DocumentsContract.createDocument(
-                getClient(dest), dest.derivedUri, dstMimeType, dstDisplayName);
+        Uri dstUri = null;
+        try {
+            dstUri = DocumentsContract.createDocument(
+                    getClient(dest), dest.derivedUri, dstMimeType, dstDisplayName);
+        } catch (RemoteException | RuntimeException e) {
+            throw new ResourceException(
+                    "Couldn't create destination document " + dstDisplayName + " in directory %s "
+                    + "due to an exception.", dest.derivedUri, e);
+        }
         if (dstUri == null) {
             // If this is a directory, the entire subdir will not be copied over.
-            onFileFailed(src,
-                    "Couldn't create destination document " + dstDisplayName
-                    + " in directory " + dest.displayName + ".");
-            return false;
+            throw new ResourceException(
+                    "Couldn't create destination document " + dstDisplayName + " in directory %s.",
+                    dest.derivedUri);
         }
 
         DocumentInfo dstInfo = null;
         try {
             dstInfo = DocumentInfo.fromUri(getContentResolver(), dstUri);
-        } catch (FileNotFoundException e) {
-            onFileFailed(src,
-                    "Could not load DocumentInfo for newly created file: " + dstUri + ".");
-            return false;
+        } catch (FileNotFoundException | RuntimeException e) {
+            throw new ResourceException("Could not load DocumentInfo for newly created file %s.",
+                    dstUri);
         }
 
-        final boolean success;
         if (Document.MIME_TYPE_DIR.equals(src.mimeType)) {
-            success = copyDirectoryHelper(src, dstInfo);
+            copyDirectoryHelper(src, dstInfo);
         } else {
-            success = copyFileHelper(src, dstInfo, dstMimeType);
+            copyFileHelper(src, dstInfo, dest, dstMimeType);
         }
-
-        return success;
     }
 
     /**
@@ -352,11 +388,10 @@
      * @param srcDir Info of the directory to copy from. The routine will copy the directory's
      *            contents, not the directory itself.
      * @param destDir Info of the directory to copy to. Must be created beforehand.
-     * @return True on success, false if some of the children failed to copy.
-     * @throws RemoteException
+     * @throws ResourceException
      */
-    private boolean copyDirectoryHelper(DocumentInfo srcDir, DocumentInfo destDir)
-            throws RemoteException {
+    private void copyDirectoryHelper(DocumentInfo srcDir, DocumentInfo destDir)
+            throws ResourceException {
         // Recurse into directories. Copy children into the new subdirectory.
         final String queryColumns[] = new String[] {
                 Document.COLUMN_DISPLAY_NAME,
@@ -367,106 +402,145 @@
         };
         Cursor cursor = null;
         boolean success = true;
+        // Iterate over srcs in the directory; copy to the destination directory.
+        final Uri queryUri = buildChildDocumentsUri(srcDir.authority, srcDir.documentId);
         try {
-            // Iterate over srcs in the directory; copy to the destination directory.
-            final Uri queryUri = buildChildDocumentsUri(srcDir.authority, srcDir.documentId);
-            cursor = getClient(srcDir).query(queryUri, queryColumns, null, null, null);
-            while (cursor.moveToNext() && !isCanceled()) {
-                DocumentInfo src = DocumentInfo.fromCursor(cursor, srcDir.authority);
-                success &= processDocument(src, srcDir, destDir);
+            try {
+                cursor = getClient(srcDir).query(queryUri, queryColumns, null, null, null);
+            } catch (RemoteException | RuntimeException e) {
+                throw new ResourceException("Failed to query children of %s due to an exception.",
+                        srcDir.derivedUri, e);
             }
+
+            DocumentInfo src;
+            while (cursor.moveToNext() && !isCanceled()) {
+                try {
+                    src = DocumentInfo.fromCursor(cursor, srcDir.authority);
+                    processDocument(src, srcDir, destDir);
+                } catch (RuntimeException e) {
+                    Log.e(TAG, "Failed to recursively process a file %s due to an exception."
+                            .format(srcDir.derivedUri.toString()), e);
+                    success = false;
+                }
+            }
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Failed to copy a file %s to %s. "
+                    .format(srcDir.derivedUri.toString(), destDir.derivedUri.toString()), e);
+            success = false;
         } finally {
             IoUtils.closeQuietly(cursor);
         }
 
-        return success;
+        if (!success) {
+            throw new RuntimeException("Some files failed to copy during a recursive "
+                    + "directory copy.");
+        }
     }
 
     /**
      * Handles copying a single file.
      *
-     * @param srcUriInfo Info of the file to copy from.
-     * @param dstUriInfo Info of the *file* to copy to. Must be created beforehand.
+     * @param src Info of the file to copy from.
+     * @param dest Info of the *file* to copy to. Must be created beforehand.
+     * @param destParent Info of the parent of the destination.
      * @param mimeType Mime type for the target. Can be different than source for virtual files.
-     * @return True on success, false on error.
-     * @throws RemoteException
+     * @throws ResourceException
      */
-    private boolean copyFileHelper(DocumentInfo src, DocumentInfo dest, String mimeType)
-            throws RemoteException {
+    private void copyFileHelper(DocumentInfo src, DocumentInfo dest, DocumentInfo destParent,
+            String mimeType) throws ResourceException {
         CancellationSignal canceller = new CancellationSignal();
+        AssetFileDescriptor srcFileAsAsset = null;
         ParcelFileDescriptor srcFile = null;
         ParcelFileDescriptor dstFile = null;
         InputStream in = null;
-        OutputStream out = null;
+        ParcelFileDescriptor.AutoCloseOutputStream out = null;
+        boolean success = false;
 
-        boolean success = true;
         try {
             // If the file is virtual, but can be converted to another format, then try to copy it
             // as such format.
             if (src.isVirtualDocument()) {
-                final AssetFileDescriptor srcFileAsAsset =
-                        getClient(src).openTypedAssetFileDescriptor(
+                try {
+                    srcFileAsAsset = getClient(src).openTypedAssetFileDescriptor(
                                 src.derivedUri, mimeType, null, canceller);
+                } catch (FileNotFoundException | RemoteException | RuntimeException e) {
+                    throw new ResourceException("Failed to open a file as asset for %s due to an "
+                            + "exception.", src.derivedUri, e);
+                }
                 srcFile = srcFileAsAsset.getParcelFileDescriptor();
-                in = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
+                try {
+                    in = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
+                } catch (IOException e) {
+                    throw new ResourceException("Failed to open a file input stream for %s due "
+                            + "an exception.", src.derivedUri, e);
+                }
             } else {
-                srcFile = getClient(src).openFile(src.derivedUri, "r", canceller);
+                try {
+                    srcFile = getClient(src).openFile(src.derivedUri, "r", canceller);
+                } catch (FileNotFoundException | RemoteException | RuntimeException e) {
+                    throw new ResourceException(
+                            "Failed to open a file for %s due to an exception.", src.derivedUri, e);
+                }
                 in = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
             }
 
-            dstFile = getClient(dest).openFile(dest.derivedUri, "w", canceller);
+            try {
+                dstFile = getClient(dest).openFile(dest.derivedUri, "w", canceller);
+            } catch (FileNotFoundException | RemoteException | RuntimeException e) {
+                throw new ResourceException("Failed to open the destination file %s for writing "
+                        + "due to an exception.", dest.derivedUri, e);
+            }
             out = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
 
             byte[] buffer = new byte[32 * 1024];
             int len;
-            while ((len = in.read(buffer)) != -1) {
-                if (isCanceled()) {
-                    if (DEBUG) Log.d(TAG, "Canceled copy mid-copy. Id:" + id);
-                    success = false;
-                    break;
+            try {
+                while ((len = in.read(buffer)) != -1) {
+                    if (isCanceled()) {
+                        if (DEBUG) Log.d(TAG, "Canceled copy mid-copy of: " + src.derivedUri);
+                        return;
+                    }
+                    out.write(buffer, 0, len);
+                    makeCopyProgress(len);
                 }
-                out.write(buffer, 0, len);
-                makeCopyProgress(len);
+
+                // Need to invoke IoUtils.close explicitly to avoid from ignoring errors at flush.
+                IoUtils.close(dstFile.getFileDescriptor());
+                srcFile.checkError();
+            } catch (IOException e) {
+                throw new ResourceException(
+                        "Failed to copy bytes from %s to %s due to an IO exception.",
+                        src.derivedUri, dest.derivedUri, e);
             }
 
-            srcFile.checkError();
-        } catch (IOException e) {
-            success = false;
-            onFileFailed(src, "Exception thrown while copying from "
-                    + src.derivedUri + " to " + dest.derivedUri + ".");
-
-            if (dstFile != null) {
-                try {
-                    dstFile.closeWithError(e.getMessage());
-                } catch (IOException closeError) {
-                    Log.e(TAG, "Error closing destination", closeError);
-                }
+            if (src.isVirtualDocument()) {
+               convertedFiles.add(src);
             }
+
+            success = true;
         } finally {
+            if (!success) {
+                if (dstFile != null) {
+                    try {
+                        dstFile.closeWithError("Error copying bytes.");
+                    } catch (IOException closeError) {
+                        Log.w(TAG, "Error closing destination.", closeError);
+                    }
+                }
+
+                if (DEBUG) Log.d(TAG, "Cleaning up failed operation leftovers.");
+                canceller.cancel();
+                try {
+                    deleteDocument(dest, destParent);
+                } catch (ResourceException e) {
+                    Log.w(TAG, "Failed to cleanup after copy error: " + src.derivedUri, e);
+                }
+            }
+
             // This also ensures the file descriptors are closed.
             IoUtils.closeQuietly(in);
             IoUtils.closeQuietly(out);
         }
-
-        if (!success) {
-            if (DEBUG) Log.d(TAG, "Cleaning up failed operation leftovers.");
-            canceller.cancel();
-            try {
-                DocumentsContract.deleteDocument(getClient(dest), dest.derivedUri);
-            } catch (RemoteException e) {
-                // RemoteExceptions usually signal that the connection is dead, so there's no
-                // point attempting to continue. Propagate the exception up so the copy job is
-                // cancelled.
-                Log.w(TAG, "Failed to cleanup after copy error: " + src.derivedUri, e);
-                throw e;
-            }
-        }
-
-        if (src.isVirtualDocument() && success) {
-           convertedFiles.add(src);
-        }
-
-        return success;
     }
 
     /**
@@ -475,16 +549,20 @@
      *
      * @param srcs
      * @return Size in bytes.
-     * @throws RemoteException
+     * @throws ResourceException
      */
-    private long calculateSize(List<DocumentInfo> srcs)
-            throws RemoteException {
+    private long calculateSize(List<DocumentInfo> srcs) throws ResourceException {
         long result = 0;
 
         for (DocumentInfo src : srcs) {
             if (src.isDirectory()) {
                 // Directories need to be recursed into.
-                result += calculateFileSizesRecursively(getClient(src), src.derivedUri);
+                try {
+                    result += calculateFileSizesRecursively(getClient(src), src.derivedUri);
+                } catch (RemoteException e) {
+                    throw new ResourceException("Failed to obtain the client for %s.",
+                            src.derivedUri);
+                }
             } else {
                 result += src.size;
             }
@@ -495,10 +573,10 @@
     /**
      * Calculates (recursively) the cumulative size of all the files under the given directory.
      *
-     * @throws RemoteException
+     * @throws ResourceException
      */
     private static long calculateFileSizesRecursively(
-            ContentProviderClient client, Uri uri) throws RemoteException {
+            ContentProviderClient client, Uri uri) throws ResourceException {
         final String authority = uri.getAuthority();
         final Uri queryUri = buildChildDocumentsUri(authority, getDocumentId(uri));
         final String queryColumns[] = new String[] {
@@ -524,6 +602,9 @@
                     result += size > 0 ? size : 0;
                 }
             }
+        } catch (RemoteException | RuntimeException e) {
+            throw new ResourceException(
+                    "Failed to calculate size for %s due to an exception.", uri, e);
         } finally {
             IoUtils.closeQuietly(cursor);
         }
@@ -533,21 +614,22 @@
 
     /**
      * Returns true if {@code doc} is a descendant of {@code parentDoc}.
-     * @throws RemoteException
+     * @throws ResourceException
      */
     boolean isDescendentOf(DocumentInfo doc, DocumentInfo parent)
-            throws RemoteException {
+            throws ResourceException {
         if (parent.isDirectory() && doc.authority.equals(parent.authority)) {
-            return isChildDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+            try {
+                return isChildDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+            } catch (RemoteException | RuntimeException e) {
+                throw new ResourceException(
+                        "Failed to check if %s is a child of %s due to an exception.",
+                        doc.derivedUri, parent.derivedUri, e);
+            }
         }
         return false;
     }
 
-    private void onFileFailed(DocumentInfo file, String msg) {
-        Log.w(TAG, msg);
-        onFileFailed(file);
-    }
-
     @Override
     public String toString() {
         return new StringBuilder()
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index 11c3a29..8f45162 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -22,7 +22,6 @@
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.content.Context;
-import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.documentsui.Metrics;
@@ -58,8 +57,8 @@
     @Override
     Builder createProgressBuilder() {
         return super.createProgressBuilder(
-                service.getString(R.string.move_notification_title),
-                R.drawable.ic_menu_copy,
+                service.getString(R.string.delete_notification_title),
+                R.drawable.ic_menu_delete,
                 service.getString(android.R.string.cancel),
                 R.drawable.ic_cab_cancel);
     }
@@ -81,13 +80,13 @@
     }
 
     @Override
-    void start() throws RemoteException {
+    void start() {
         for (DocumentInfo doc : mSrcs) {
             if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri);
-            // TODO: Start using mSrcParent as soon as DocumentsProvider::removeDocument() is
-            // implemented.
-            if (!deleteDocument(doc)) {
-                Log.w(TAG, "Failed to delete document @ " + doc.derivedUri);
+            try {
+                deleteDocument(doc, mSrcParent);
+            } catch (ResourceException e) {
+                Log.e(TAG, "Failed to delete document @ " + doc.derivedUri);
                 onFileFailed(doc);
             }
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index 05a3f11..580fa38 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -17,9 +17,6 @@
 package com.android.documentsui.services;
 
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.annotation.IntDef;
 import android.app.NotificationManager;
@@ -136,12 +133,12 @@
 
         String jobId = intent.getStringExtra(EXTRA_JOB_ID);
         @OpType int operationType = intent.getIntExtra(EXTRA_OPERATION, OPERATION_UNKNOWN);
-        checkArgument(jobId != null);
+        assert(jobId != null);
 
         if (intent.hasExtra(EXTRA_CANCEL)) {
             handleCancel(intent);
         } else {
-            checkArgument(operationType != OPERATION_UNKNOWN);
+            assert(operationType != OPERATION_UNKNOWN);
             handleOperation(intent, serviceId, jobId, operationType);
         }
 
@@ -173,9 +170,9 @@
             mWakeLock.acquire();
         }
 
-        checkState(job != null);
+        assert(job != null);
         int delay = intent.getIntExtra(EXTRA_DELAY, DEFAULT_DELAY);
-        checkArgument(delay <= MAX_DELAY);
+        assert(delay <= MAX_DELAY);
         if (DEBUG) Log.d(
                 TAG, "Scheduling job " + job.id + " to run in " + delay + " milliseconds.");
         ScheduledFuture<?> future = executor.schedule(job, delay, TimeUnit.MILLISECONDS);
@@ -188,8 +185,10 @@
      * @param intent The cancellation intent.
      */
     private void handleCancel(Intent intent) {
-        checkArgument(intent.hasExtra(EXTRA_CANCEL));
-        String jobId = checkNotNull(intent.getStringExtra(EXTRA_JOB_ID));
+        assert(intent.hasExtra(EXTRA_CANCEL));
+        assert(intent.getStringExtra(EXTRA_JOB_ID) != null);
+
+        String jobId = intent.getStringExtra(EXTRA_JOB_ID);
 
         if (DEBUG) Log.d(TAG, "handleCancel: " + jobId);
 
@@ -253,7 +252,8 @@
                 throw new UnsupportedOperationException();
         }
 
-        return checkNotNull(job);
+        assert(job != null);
+        return job;
     }
 
     @GuardedBy("mRunning")
@@ -261,7 +261,7 @@
         if (DEBUG) Log.d(TAG, "deleteJob: " + job.id);
 
         JobRecord record = mRunning.remove(job.id);
-        checkArgument(record != null);
+        assert(record != null);
         record.job.cleanup();
 
         if (mRunning.isEmpty()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
index 9d017ee..748da00 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
@@ -22,7 +22,6 @@
 import static com.android.documentsui.Shared.asArrayList;
 import static com.android.documentsui.Shared.getQuantityString;
 import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
-import static com.android.documentsui.services.FileOperationService.EXTRA_DELAY;
 import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
 import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
@@ -159,25 +158,22 @@
     }
 
     /**
-     * Starts the service for a move operation.
+     * Starts the service for a delete operation.
      *
      * @param jobId A unique jobid for this job.
      *     Use {@link #createJobId} if you don't have one handy.
-     * @param srcDocs A list of src files to copy.
+     * @param srcDocs A list of src files to delete.
      * @param srcParent Parent of all the source documents.
-     * @param delay Number of milliseconds to wait before executing the job.
      * @return Id of the job.
      */
     public static String delete(
             Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
-            DocumentStack location, int delay) {
+            DocumentStack location) {
         String jobId = createJobId();
-        if (DEBUG) Log.d(TAG, "Initiating 'delete' operation id " + jobId
-                + " delayed by " + delay + " milliseconds.");
+        if (DEBUG) Log.d(TAG, "Initiating 'delete' operation id " + jobId + ".");
 
         Intent intent = createBaseIntent(OPERATION_DELETE, activity, jobId, srcDocs, srcParent,
                 location);
-        intent.putExtra(EXTRA_DELAY, delay);
         activity.startService(intent);
 
         return jobId;
@@ -188,7 +184,7 @@
      *
      * @param jobId A unique jobid for this job.
      *     Use {@link #createJobId} if you don't have one handy.
-     * @param srcDocs A list of src files to copy.
+     * @param srcDocs A list of src files for an operation.
      * @return Id of the job.
      */
     public static Intent createBaseIntent(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index 77517ca..c723ac6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -23,8 +23,6 @@
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
 import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.DrawableRes;
 import android.annotation.PluralsRes;
@@ -98,7 +96,7 @@
     Job(Context service, Context appContext, Listener listener,
             @OpType int operationType, String id, DocumentStack stack) {
 
-        checkArgument(operationType != OPERATION_UNKNOWN);
+        assert(operationType != OPERATION_UNKNOWN);
 
         this.service = service;
         this.appContext = appContext;
@@ -116,19 +114,17 @@
         listener.onStart(this);
         try {
             start();
-        } catch (Exception e) {
-            // In the case of an unmanaged failure, we still want
-            // to resolve business in an orderly fashion. That'll
-            // ensure the service is shut down and notifications
-            // shown/closed.
-            Log.e(TAG, "Operation failed due to an exception.", e);
+        } catch (RuntimeException e) {
+            // No exceptions should be thrown here, as all calls to the provider must be
+            // handled within Job implementations. However, just in case catch them here.
+            Log.e(TAG, "Operation failed due to an unhandled runtime exception.", e);
             Metrics.logFileOperationErrors(service, operationType, failedFiles);
         } finally {
             listener.onFinished(this);
         }
     }
 
-    abstract void start() throws RemoteException;
+    abstract void start();
 
     abstract Notification getSetupNotification();
     // TODO: Progress notification for deletes.
@@ -152,7 +148,8 @@
             mClients.put(doc.authority, client);
         }
 
-        return checkNotNull(client);
+        assert(client != null);
+        return client;
     }
 
     final void cleanup() {
@@ -186,20 +183,25 @@
         return false;
     }
 
-    final boolean deleteDocument(DocumentInfo doc) {
+    final void deleteDocument(DocumentInfo doc, DocumentInfo parent) throws ResourceException {
         try {
-            DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to delete file: " + doc.derivedUri, e);
-            return false;
+            if (doc.isRemoveSupported()) {
+                DocumentsContract.removeDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+            } else if (doc.isDeleteSupported()) {
+                DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
+            } else {
+                throw new ResourceException("Unable to delete source document as the file is " +
+                        "not deletable nor removable: %s.", doc.derivedUri);
+            }
+        } catch (RemoteException | RuntimeException e) {
+            throw new ResourceException("Failed to delete file %s due to an exception.",
+                    doc.derivedUri, e);
         }
-
-        return true;  // victory dance!
     }
 
     Notification getSetupNotification(String content) {
-        mProgressBuilder.setProgress(0, 0, true);
-        mProgressBuilder.setContentText(content);
+        mProgressBuilder.setProgress(0, 0, true)
+                .setContentText(content);
         return mProgressBuilder.build();
     }
 
@@ -218,6 +220,7 @@
                 .setCategory(Notification.CATEGORY_ERROR)
                 .setSmallIcon(icon)
                 .setAutoCancel(true);
+
         return errorBuilder.build();
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index 9b72077..aaa7596 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -16,12 +16,12 @@
 
 package com.android.documentsui.services;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
 
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.content.Context;
-import android.net.Uri;
 import android.os.RemoteException;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
@@ -37,6 +37,7 @@
 final class MoveJob extends CopyJob {
 
     private static final String TAG = "MoveJob";
+
     final DocumentInfo mSrcParent;
 
     /**
@@ -71,7 +72,7 @@
 
     @Override
     public Notification getProgressNotification() {
-        return getProgressNotification(R.string.copy_preparing);
+        return getProgressNotification(R.string.copy_remaining);
     }
 
     @Override
@@ -80,8 +81,8 @@
                 R.plurals.move_error_notification_title, R.drawable.ic_menu_copy);
     }
 
-    boolean processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
-            throws RemoteException {
+    void processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
+            throws ResourceException {
 
         // TODO: When optimized move kicks in, we're not making any progress updates. FIX IT!
 
@@ -89,13 +90,18 @@
         // If not supported, then fallback to byte-by-byte copy/move.
         if (src.authority.equals(dest.authority)) {
             if ((src.flags & Document.FLAG_SUPPORTS_MOVE) != 0) {
-                if (DocumentsContract.moveDocument(getClient(src), src.derivedUri,
-                        srcParent != null ? srcParent.derivedUri : mSrcParent.derivedUri,
-                        dest.derivedUri) == null) {
-                    onFileFailed(src);
-                    return false;
+                try {
+                    if (DocumentsContract.moveDocument(getClient(src), src.derivedUri,
+                            srcParent != null ? srcParent.derivedUri : mSrcParent.derivedUri,
+                            dest.derivedUri) != null) {
+                        return;
+                    }
+                } catch (RemoteException | RuntimeException e) {
+                    Log.e(TAG, "Provider side move failed for: " + src.derivedUri
+                            + " due to an exception: " + e);
                 }
-                return true;
+                // If optimized move fails, then fallback to byte-by-byte copy.
+                if (DEBUG) Log.d(TAG, "Fallback to byte-by-byte move for: " + src.derivedUri);
             }
         }
 
@@ -103,16 +109,15 @@
         // conversion, and the source file should not be deleted in such case (as it's a different
         // file).
         if (src.isVirtualDocument()) {
-            Log.w(TAG, "Cannot move virtual files byte by byte.");
-            onFileFailed(src);
-            return false;
+            throw new ResourceException("Cannot move virtual file %s byte by byte.",
+                    src.derivedUri);
         }
 
         // If we couldn't do an optimized copy...we fall back to vanilla byte copy.
-        boolean copied = byteCopyDocument(src, dest);
+        byteCopyDocument(src, dest);
 
-        // TODO: Replace deleteDocument() with removeDocument() once implemented.
-        return copied && !isCanceled() && deleteDocument(src);
+        // Remove the source document.
+        deleteDocument(src, srcParent);
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/ResourceException.java b/packages/DocumentsUI/src/com/android/documentsui/services/ResourceException.java
new file mode 100644
index 0000000..7d3d91a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/ResourceException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.services;
+
+import android.net.Uri;
+
+public class ResourceException extends Exception {
+    public ResourceException(String message, Exception e) {
+        super(message, e);
+    }
+
+    public ResourceException(String message, Uri uri1, Exception e) {
+        super(String.format(message, uri1.toString()), e);
+    }
+
+    public ResourceException(String message, Uri uri1, Uri uri2, Exception e) {
+        super(String.format(message, uri1.toString(), uri2.toString()), e);
+    }
+
+    public ResourceException(String message) {
+        super(message);
+    }
+
+    public ResourceException(String message, Uri uri1) {
+        super(String.format(message, uri1.toString()));
+    }
+
+    public ResourceException(String message, Uri uri1, Uri uri2) {
+        super(message.format(uri1.toString(), uri2.toString()));
+    }
+}
diff --git a/packages/DocumentsUI/tests/Android.mk b/packages/DocumentsUI/tests/Android.mk
index b65ac98..3983f78 100644
--- a/packages/DocumentsUI/tests/Android.mk
+++ b/packages/DocumentsUI/tests/Android.mk
@@ -7,8 +7,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target ub-uiautomator
+LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator
 
 LOCAL_PACKAGE_NAME := DocumentsUITests
 LOCAL_INSTRUMENTATION_FOR := DocumentsUI
diff --git a/packages/DocumentsUI/tests/AndroidManifest.xml b/packages/DocumentsUI/tests/AndroidManifest.xml
index a312427..b986285 100644
--- a/packages/DocumentsUI/tests/AndroidManifest.xml
+++ b/packages/DocumentsUI/tests/AndroidManifest.xml
@@ -2,6 +2,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.documentsui.tests">
 
+    <uses-permission android:name="android.permission.INTERNET" />
+
     <application>
         <uses-library android:name="android.test.runner" />
         <provider
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
index 34f1120..683fd6c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
@@ -20,22 +20,27 @@
 import static com.android.documentsui.StubProvider.ROOT_0_ID;
 import static com.android.documentsui.StubProvider.ROOT_1_ID;
 
+import android.annotation.Nullable;
 import android.app.Activity;
-import android.app.Instrumentation;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.RemoteException;
 import android.provider.DocumentsContract.Document;
-import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.Configurator;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.Until;
 import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
 import android.view.MotionEvent;
 
+import com.android.documentsui.BaseActivity;
+import com.android.documentsui.EventListener;
+import com.android.documentsui.bots.DirectoryListBot;
+import com.android.documentsui.bots.KeyboardBot;
+import com.android.documentsui.bots.RootsListBot;
+import com.android.documentsui.bots.UiBot;
 import com.android.documentsui.model.RootInfo;
 
 /**
@@ -56,13 +61,12 @@
     public static final String fileName4 = "poodles.text";
     public static final String fileNameNoRename = "NO_RENAMEfile.txt";
 
-    public UiBot bot;
+    public Bots bots;
     public UiDevice device;
     public Context context;
 
     public RootInfo rootDir0;
     public RootInfo rootDir1;
-
     ContentResolver mResolver;
     DocumentsProviderHelper mDocsHelper;
     ContentProviderClient mClient;
@@ -71,26 +75,51 @@
         super(activityClass);
     }
 
+    /*
+     * Returns the root that will be opened within the activity.
+     * By default tests are started with one of the test roots.
+     * Override the method if you want to open different root on start.
+     * @return Root that will be opened. Return null if you want to open activity's default root.
+     */
+    @Nullable
+    protected RootInfo getInitialRoot() {
+        return rootDir0;
+    }
+
+    /**
+     * Returns the authority of the testing provider begin used.
+     * By default it's StubProvider's authority.
+     * @return Authority of the provider.
+     */
+    protected String getTestingProviderAuthority() {
+        return DEFAULT_AUTHORITY;
+    }
+
+    /**
+     * Resolves testing roots.
+     */
+    protected void setupTestingRoots() throws RemoteException {
+        rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
+        rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
+    }
+
     @Override
     public void setUp() throws Exception {
         device = UiDevice.getInstance(getInstrumentation());
         // NOTE: Must be the "target" context, else security checks in content provider will fail.
         context = getInstrumentation().getTargetContext();
-        bot = new UiBot(device, context, TIMEOUT);
+
+        bots = new Bots(device, context, TIMEOUT);
 
         Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
-        bot.revealLauncher();
 
         mResolver = context.getContentResolver();
-        mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
-        mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
+        mClient = mResolver.acquireUnstableContentProviderClient(getTestingProviderAuthority());
+        mDocsHelper = new DocumentsProviderHelper(getTestingProviderAuthority(), mClient);
 
-        rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
-        rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
+        setupTestingRoots();
 
         launchActivity();
-
-        bot.revealApp();
         resetStorage();
     }
 
@@ -104,6 +133,9 @@
         final Intent intent = context.getPackageManager().getLaunchIntentForPackage(
                 UiBot.TARGET_PKG);
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (getInitialRoot() != null) {
+            intent.setData(getInitialRoot().getUri());
+        }
         setActivityIntent(intent);
         getActivity();  // Launch the activity.
     }
@@ -125,12 +157,29 @@
     }
 
     void assertDefaultContentOfTestDir0() throws UiObjectNotFoundException {
-        bot.assertDocumentsCount(ROOT_0_ID, 4);
-        bot.assertHasDocuments(fileName1, fileName2, dirName1, fileNameNoRename);
+        bots.directory.assertDocumentsCount(4);
+        bots.directory.assertDocumentsPresent(fileName1, fileName2, dirName1, fileNameNoRename);
     }
 
     void assertDefaultContentOfTestDir1() throws UiObjectNotFoundException {
-        bot.assertDocumentsCount(ROOT_1_ID, 2);
-        bot.assertHasDocuments(fileName3, fileName4);
+        bots.directory.assertDocumentsCount(2);
+        bots.directory.assertDocumentsPresent(fileName3, fileName4);
+    }
+
+    /**
+     * Handy collection of bots for working with Files app.
+     */
+    public static final class Bots {
+        public final UiBot main;
+        public final RootsListBot roots;
+        public final DirectoryListBot directory;
+        public final KeyboardBot keyboard;
+
+        private Bots(UiDevice device, Context context, int timeout) {
+            this.main = new UiBot(device, context, TIMEOUT);
+            this.roots = new RootsListBot(device, context, TIMEOUT);
+            this.directory = new DirectoryListBot(device, context, TIMEOUT);
+            this.keyboard = new KeyboardBot(device, context, TIMEOUT);
+        }
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
index af478ea..16ed2d9 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
@@ -106,13 +106,15 @@
         return createDocument(root.documentId, mimeType, name);
     }
 
-    public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags)
+    public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags,
+            String... streamTypes)
             throws RemoteException {
         Bundle in = new Bundle();
         in.putInt(StubProvider.EXTRA_FLAGS, flags);
         in.putString(StubProvider.EXTRA_PARENT_ID, documentId);
         in.putString(Document.COLUMN_MIME_TYPE, mimeType);
         in.putString(Document.COLUMN_DISPLAY_NAME, name);
+        in.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
 
         Bundle out = mClient.call("createDocumentWithFlags", null, in);
         Uri uri = out.getParcelable(DocumentsContract.EXTRA_URI);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
deleted file mode 100644
index c51f927..0000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.documentsui;
-
-import static com.android.documentsui.StubProvider.ROOT_0_ID;
-
-import android.content.Intent;
-import android.os.RemoteException;
-import android.provider.DocumentsContract;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
-
-@LargeTest
-public class DownloadsActivityUiTest extends ActivityTest<DownloadsActivity> {
-
-    public DownloadsActivityUiTest() {
-        super(DownloadsActivity.class);
-    }
-
-    @Override
-    void launchActivity() {
-        final Intent intent = new Intent(DocumentsContract.ACTION_MANAGE_ROOT);
-        intent.setDataAndType(rootDir0.getUri(), DocumentsContract.Root.MIME_TYPE_ITEM);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        setActivityIntent(intent);
-        getActivity();  // Launch the activity.
-    }
-
-    @Override
-    void initTestFiles() throws RemoteException {
-        mDocsHelper.createDocument(rootDir0, "text/plain", "file0.log");
-        mDocsHelper.createDocument(rootDir0, "image/png", "file1.png");
-        mDocsHelper.createDocument(rootDir0, "text/csv", "file2.csv");
-    }
-
-    public void testWindowTitle() throws Exception {
-        initTestFiles();
-
-        bot.assertWindowTitle(ROOT_0_ID);
-    }
-
-    public void testFilesListed() throws Exception {
-        initTestFiles();
-
-        bot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
-    }
-
-    public void testFilesList_LiveUpdate() throws Exception {
-        initTestFiles();
-
-        mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
-
-        bot.waitForDocument("Ham & Cheese.sandwich");
-        bot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
-    }
-
-    public void testDeleteDocument() throws Exception {
-        initTestFiles();
-
-        bot.clickDocument("file1.png");
-        device.waitForIdle();
-        bot.menuDelete().click();
-
-        bot.waitForDeleteSnackbar();
-        assertFalse(bot.hasDocuments("file1.png"));
-
-        bot.waitForDeleteSnackbarGone();
-        assertFalse(bot.hasDocuments("file1.png"));
-    }
-
-    public void testSupportsShare() throws Exception {
-        initTestFiles();
-
-        bot.clickDocument("file1.png");
-        device.waitForIdle();
-        assertNotNull(bot.menuShare());
-    }
-
-    public void testClosesOnBack() throws Exception {
-        DownloadsActivity activity = getActivity();
-        device.pressBack();
-        device.wait(Until.gone(By.text(ROOT_0_ID)), TIMEOUT);  // wait for the window to go away
-        assertTrue(activity.isDestroyed());
-    }
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
index 95515db..69f0e67 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -19,9 +19,21 @@
 import static com.android.documentsui.StubProvider.ROOT_0_ID;
 import static com.android.documentsui.StubProvider.ROOT_1_ID;
 
+import android.app.DownloadManager;
+import android.app.DownloadManager.Request;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
 import android.os.RemoteException;
+import android.provider.DocumentsContract;
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiObject;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import com.android.documentsui.model.RootInfo;
 
 @LargeTest
 public class FilesActivityUiTest extends ActivityTest<FilesActivity> {
@@ -31,6 +43,11 @@
     }
 
     @Override
+    protected RootInfo getInitialRoot() {
+        return null;
+    }
+
+    @Override
     public void initTestFiles() throws RemoteException {
         mDocsHelper.createDocument(rootDir0, "text/plain", "file0.log");
         mDocsHelper.createDocument(rootDir0, "image/png", "file1.png");
@@ -43,110 +60,165 @@
     public void testRootsListed() throws Exception {
         initTestFiles();
 
-        bot.openRoot(ROOT_0_ID);
-
         // Should also have Drive, but that requires pre-configuration of devices
         // We omit for now.
-        bot.assertHasRoots(
+        bots.roots.assertRootsPresent(
                 "Images",
                 "Videos",
                 "Audio",
                 "Downloads",
-                "Documents",
                 ROOT_0_ID,
                 ROOT_1_ID);
+
+        // Separate logic for "Documents" root, which presence depends on the config setting
+        if (Shared.shouldShowDocumentsRoot(context, new Intent(DocumentsContract.ACTION_BROWSE))) {
+            bots.roots.assertRootsPresent("Documents");
+        } else {
+            bots.roots.assertRootsAbsent("Documents");
+        }
     }
 
     public void testFilesListed() throws Exception {
         initTestFiles();
 
-        bot.openRoot(ROOT_0_ID);
-        bot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
+        bots.roots.openRoot(ROOT_0_ID);
+        bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv");
     }
 
-    public void testLoadsHomeDirectoryByDefault() throws Exception {
+    public void testLoadsDownloadsDirectoryByDefault() throws Exception {
         initTestFiles();
 
         device.waitForIdle();
-        bot.assertWindowTitle("Documents");
+        bots.main.assertWindowTitle("Downloads");
     }
 
     public void testRootClickSetsWindowTitle() throws Exception {
         initTestFiles();
 
-        bot.openRoot("Downloads");
-        bot.assertWindowTitle("Downloads");
+        bots.roots.openRoot("Downloads");
+        bots.main.assertWindowTitle("Downloads");
     }
 
     public void testFilesList_LiveUpdate() throws Exception {
         initTestFiles();
 
-        bot.openRoot(ROOT_0_ID);
+        bots.roots.openRoot(ROOT_0_ID);
         mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
 
-        bot.waitForDocument("Ham & Cheese.sandwich");
-        bot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
+        bots.directory.waitForDocument("Ham & Cheese.sandwich");
+        bots.directory.assertDocumentsPresent(
+                "file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
+    }
+
+    public void testCreateDirectory() throws Exception {
+        initTestFiles();
+
+        bots.roots.openRoot(ROOT_0_ID);
+
+        bots.main.openOverflowMenu();
+        bots.main.menuNewFolder().click();
+        bots.main.setDialogText("Kung Fu Panda");
+
+        bots.keyboard.pressEnter();
+
+        bots.directory.assertDocumentsPresent("Kung Fu Panda");
     }
 
     public void testDeleteDocument() throws Exception {
         initTestFiles();
 
-        bot.openRoot(ROOT_0_ID);
+        bots.roots.openRoot(ROOT_0_ID);
 
-        bot.clickDocument("file1.png");
+        bots.directory.clickDocument("file1.png");
         device.waitForIdle();
-        bot.menuDelete().click();
+        bots.main.menuDelete().click();
 
-        bot.waitForDeleteSnackbar();
-        assertFalse(bot.hasDocuments("file1.png"));
+        bots.main.findDialogOkButton().click();
 
-        bot.waitForDeleteSnackbarGone();
-        assertFalse(bot.hasDocuments("file1.png"));
+        bots.directory.assertDocumentsAbsent("file1.png");
+    }
 
-        // Now delete from another root.
-        bot.openRoot(ROOT_1_ID);
+    public void testDeleteDocument_Cancel() throws Exception {
+        initTestFiles();
 
-        bot.clickDocument("poodles.text");
+        bots.roots.openRoot(ROOT_0_ID);
+
+        bots.directory.clickDocument("file1.png");
         device.waitForIdle();
-        bot.menuDelete().click();
+        bots.main.menuDelete().click();
 
-        bot.waitForDeleteSnackbar();
-        assertFalse(bot.hasDocuments("poodles.text"));
+        bots.main.findDialogCancelButton().click();
 
-        bot.waitForDeleteSnackbarGone();
-        assertFalse(bot.hasDocuments("poodles.text"));
+        bots.directory.assertDocumentsPresent("file1.png");
     }
 
     // Tests that pressing tab switches focus between the roots and directory listings.
+    @Suppress
     public void testKeyboard_tab() throws Exception {
-        bot.pressKey(KeyEvent.KEYCODE_TAB);
-        bot.assertHasFocus("com.android.documentsui:id/roots_list");
-        bot.pressKey(KeyEvent.KEYCODE_TAB);
-        bot.assertHasFocus("com.android.documentsui:id/dir_list");
+        bots.main.pressKey(KeyEvent.KEYCODE_TAB);
+        bots.roots.assertHasFocus();
+        bots.main.pressKey(KeyEvent.KEYCODE_TAB);
+        bots.directory.assertHasFocus();
     }
 
     // Tests that arrow keys do not switch focus away from the dir list.
+    @Suppress
     public void testKeyboard_arrowsDirList() throws Exception {
         for (int i = 0; i < 10; i++) {
-            bot.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
-            bot.assertHasFocus("com.android.documentsui:id/dir_list");
+            bots.main.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
+            bots.directory.assertHasFocus();
         }
         for (int i = 0; i < 10; i++) {
-            bot.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
-            bot.assertHasFocus("com.android.documentsui:id/dir_list");
+            bots.main.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+            bots.directory.assertHasFocus();
         }
     }
 
     // Tests that arrow keys do not switch focus away from the roots list.
     public void testKeyboard_arrowsRootsList() throws Exception {
-        bot.pressKey(KeyEvent.KEYCODE_TAB);
+        bots.main.pressKey(KeyEvent.KEYCODE_TAB);
         for (int i = 0; i < 10; i++) {
-            bot.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
-            bot.assertHasFocus("com.android.documentsui:id/roots_list");
+            bots.main.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+            bots.roots.assertHasFocus();
         }
         for (int i = 0; i < 10; i++) {
-            bot.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
-            bot.assertHasFocus("com.android.documentsui:id/roots_list");
+            bots.main.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
+            bots.roots.assertHasFocus();
         }
     }
+
+    // We don't really need to test the entirety of download support
+    // since downloads is (almost) just another provider.
+    @Suppress
+    public void testDownload_Queued() throws Exception {
+        DownloadManager dm = (DownloadManager) context.getSystemService(
+                Context.DOWNLOAD_SERVICE);
+        // This downloads ends up being queued (because DNS can't be resolved).
+        // We'll still see an entry in the downloads UI with a "Queued" label.
+        dm.enqueue(new Request(Uri.parse("http://hammychamp.toodles")));
+
+        bots.roots.openRoot("Downloads");
+        bots.directory.assertDocumentsPresent("Queued");
+    }
+
+    @Suppress
+    public void testDownload_RetryUnsuccessful() throws Exception {
+        DownloadManager dm = (DownloadManager) context.getSystemService(
+                Context.DOWNLOAD_SERVICE);
+        // This downloads fails! But it'll still show up.
+        dm.enqueue(new Request(Uri.parse("http://www.google.com/hamfancy")));
+
+        bots.roots.openRoot("Downloads");
+        UiObject doc = bots.directory.findDocument("Unsuccessful");
+        doc.waitForExists(TIMEOUT);
+
+        int toolType = Configurator.getInstance().getToolType();
+        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
+        doc.click();
+        Configurator.getInstance().setToolType(toolType);
+
+        assertTrue(bots.main.findDownloadRetryDialog().exists());
+
+        device.pressBack(); // to clear the dialog.
+    }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
index 770bc2c..9a06807 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
@@ -16,15 +16,12 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.StubProvider.ROOT_0_ID;
-
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
 
 @LargeTest
 public class RenameDocumentUiTest extends ActivityTest<FilesActivity> {
 
-    private static final String TAG = "RenamDocumentUiTest";
-
     private final String newName = "kitties.log";
 
     public RenameDocumentUiTest() {
@@ -35,125 +32,120 @@
     public void setUp() throws Exception {
         super.setUp();
         initTestFiles();
-        bot.openRoot(ROOT_0_ID);
     }
 
     public void testRenameEnabled_SingleSelection() throws Exception {
-        bot.selectDocument(fileName1);
-        bot.openOverflowMenu();
-        bot.assertMenuEnabled(R.string.menu_rename, true);
+        bots.directory.selectDocument(fileName1);
+        bots.main.openOverflowMenu();
+        bots.main.assertMenuEnabled(R.string.menu_rename, true);
 
         // Dismiss more options window
         device.pressBack();
     }
 
     public void testNoRenameSupport_SingleSelection() throws Exception {
-        bot.selectDocument(fileNameNoRename);
-        bot.openOverflowMenu();
-        bot.assertMenuEnabled(R.string.menu_rename, false);
+        bots.directory.selectDocument(fileNameNoRename);
+        bots.main.openOverflowMenu();
+        bots.main.assertMenuEnabled(R.string.menu_rename, false);
 
         // Dismiss more options window
         device.pressBack();
     }
 
     public void testOneHasRenameSupport_MultipleSelection() throws Exception {
-        bot.selectDocument(fileName1);
-        bot.selectDocument(fileNameNoRename);
-        bot.openOverflowMenu();
-        bot.assertMenuEnabled(R.string.menu_rename, false);
+        bots.directory.selectDocument(fileName1);
+        bots.directory.selectDocument(fileNameNoRename);
+        bots.main.openOverflowMenu();
+        bots.main.assertMenuEnabled(R.string.menu_rename, false);
 
         // Dismiss more options window
         device.pressBack();
     }
 
     public void testRenameDisabled_MultipleSelection() throws Exception {
-        bot.selectDocument(fileName1);
-        bot.selectDocument(fileName2);
-        bot.openOverflowMenu();
-        bot.assertMenuEnabled(R.string.menu_rename, false);
+        bots.directory.selectDocument(fileName1);
+        bots.directory.selectDocument(fileName2);
+        bots.main.openOverflowMenu();
+        bots.main.assertMenuEnabled(R.string.menu_rename, false);
 
         // Dismiss more options window
         device.pressBack();
     }
 
+    @Suppress
     public void testRenameFile_OkButton() throws Exception {
-        bot.selectDocument(fileName1);
-        bot.openOverflowMenu();
-        bot.openDialog(R.string.menu_rename);
-        bot.setDialogText(newName);
+        bots.directory.selectDocument(fileName1);
+        bots.main.openOverflowMenu();
+        bots.main.menuRename().click();
+        bots.main.setDialogText(newName);
 
         device.waitForIdle(TIMEOUT);
-        bot.findRenameDialogOkButton().click();
+        bots.main.findDialogOkButton().click();
         device.waitForIdle(TIMEOUT);
 
-        bot.assertDocument(fileName1, false);
-        bot.assertDocument(newName, true);
-        bot.assertDocumentsCount(4);
+        bots.directory.assertDocumentsAbsent(fileName1);
+        bots.directory.assertDocumentsPresent(newName);
+        bots.directory.assertDocumentsCount(4);
     }
 
     public void testRenameFile_Enter() throws Exception {
-        bot.selectDocument(fileName1);
-        bot.openOverflowMenu();
-        bot.openDialog(R.string.menu_rename);
-        bot.setDialogText(newName);
+        bots.directory.selectDocument(fileName1);
+        bots.main.openOverflowMenu();
+        bots.main.menuRename().click();
+        bots.main.setDialogText(newName);
 
-        pressEnter();
+        bots.keyboard.pressEnter();
 
-        bot.assertDocument(fileName1, false);
-        bot.assertDocument(newName, true);
-        bot.assertDocumentsCount(4);
+        bots.directory.assertDocumentsAbsent(fileName1);
+        bots.directory.assertDocumentsPresent(newName);
+        bots.directory.assertDocumentsCount(4);
     }
 
+    @Suppress
     public void testRenameFile_Cancel() throws Exception {
-        bot.selectDocument(fileName1);
-        bot.openOverflowMenu();
-        bot.openDialog(R.string.menu_rename);
-        bot.setDialogText(newName);
+        bots.directory.selectDocument(fileName1);
+        bots.main.openOverflowMenu();
+        bots.main.menuRename().click();
+        bots.main.setDialogText(newName);
 
         device.waitForIdle(TIMEOUT);
-        bot.findRenameDialogCancelButton().click();
+        bots.main.findDialogCancelButton().click();
         device.waitForIdle(TIMEOUT);
 
-        bot.assertDocument(fileName1, true);
-        bot.assertDocument(newName, false);
-        bot.assertDocumentsCount(4);
+        bots.directory.assertDocumentsPresent(fileName1);
+        bots.directory.assertDocumentsAbsent(newName);
+        bots.directory.assertDocumentsCount(4);
     }
 
     public void testRenameDir() throws Exception {
         String oldName = "Dir1";
         String newName = "Dir123";
 
-        bot.selectDocument(oldName);
-        bot.openOverflowMenu();
-        bot.openDialog(R.string.menu_rename);
-        bot.setDialogText(newName);
+        bots.directory.selectDocument(oldName);
+        bots.main.openOverflowMenu();
+        bots.main.menuRename().click();
+        bots.main.setDialogText(newName);
 
-        pressEnter();
+        bots.keyboard.pressEnter();
 
-        bot.assertDocument(oldName, false);
-        bot.assertDocument(newName, true);
-        bot.assertDocumentsCount(4);
+        bots.directory.assertDocumentsAbsent(oldName);
+        bots.directory.assertDocumentsPresent(newName);
+        bots.directory.assertDocumentsCount(4);
     }
 
     public void testRename_NameExists() throws Exception {
         // Check that document with the new name exists
-        bot.assertDocument(fileName2, true);
-        bot.selectDocument(fileName1);
-        bot.openOverflowMenu();
-        bot.openDialog(R.string.menu_rename);
-        bot.setDialogText(fileName2);
+        bots.directory.assertDocumentsPresent(fileName2);
+        bots.directory.selectDocument(fileName1);
+        bots.main.openOverflowMenu();
+        bots.main.menuRename().click();
+        bots.main.setDialogText(fileName2);
 
-        pressEnter();
+        bots.keyboard.pressEnter();
 
-        bot.assertSnackbar(R.string.rename_error);
-        bot.assertDocument(fileName1, true);
-        bot.assertDocument(fileName2, true);
-        bot.assertDocumentsCount(4);
-    }
-
-    private void pressEnter() {
-        device.waitForIdle(TIMEOUT);
-        device.pressEnter();
-        device.waitForIdle(TIMEOUT);
+        bots.directory.assertSnackbar(R.string.rename_error);
+        bots.directory.assertDocumentsPresent(fileName1);
+        bots.directory.assertDocumentsPresent(fileName2);
+        bots.directory.assertDocumentsCount(4);
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootUiTest.java
deleted file mode 100644
index 1d1d3b5..0000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootUiTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.documentsui;
-
-import static com.android.documentsui.StubProvider.ROOT_0_ID;
-
-import android.support.test.uiautomator.Configurator;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.MotionEvent;
-
-@LargeTest
-public class RootUiTest extends ActivityTest<FilesActivity> {
-
-    private static final String TAG = "RootUiTest";
-
-    public RootUiTest() {
-        super(FilesActivity.class);
-    }
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        initTestFiles();
-        bot.openRoot(ROOT_0_ID);
-    }
-
-    public void testRootTapped_GoToRootFromChildDir() throws Exception {
-        bot.openDocument(dirName1);
-        bot.assertWindowTitle(dirName1);
-        bot.openRoot(ROOT_0_ID);
-        bot.assertWindowTitle(ROOT_0_ID);
-        assertDefaultContentOfTestDir0();
-    }
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 7d3498e..2e81545 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -16,6 +16,9 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.RootsCache.getMatchingRoots;
+import static com.google.common.collect.Lists.newArrayList;
+
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -28,23 +31,18 @@
 @SmallTest
 public class RootsCacheTest extends AndroidTestCase {
 
-    private static RootInfo buildForMimeTypes(String... mimeTypes) {
-        final RootInfo root = new RootInfo();
-        root.derivedMimeTypes = mimeTypes;
-        return root;
-    }
+    private static RootInfo mNull = new RootInfo();
+    private static RootInfo mEmpty = buildForMimeTypes();
+    private static RootInfo mWild = buildForMimeTypes("*/*");
+    private static RootInfo mImages = buildForMimeTypes("image/*");
+    private static RootInfo mAudio = buildForMimeTypes(
+            "audio/*", "application/ogg", "application/x-flac");
+    private static RootInfo mDocs = buildForMimeTypes(
+            "application/msword", "application/vnd.ms-excel");
+    private static RootInfo mMalformed1 = buildForMimeTypes("meow");
+    private static RootInfo mMalformed2 = buildForMimeTypes("*/meow");
 
-    private RootInfo mNull = new RootInfo();
-    private RootInfo mEmpty = buildForMimeTypes();
-    private RootInfo mWild = buildForMimeTypes("*/*");
-    private RootInfo mImages = buildForMimeTypes("image/*");
-    private RootInfo mAudio = buildForMimeTypes("audio/*", "application/ogg", "application/x-flac");
-    private RootInfo mDocs = buildForMimeTypes("application/msword", "application/vnd.ms-excel");
-    private RootInfo mMalformed1 = buildForMimeTypes("meow");
-    private RootInfo mMalformed2 = buildForMimeTypes("*/meow");
-
-    private List<RootInfo> mRoots = Lists.newArrayList(
-            mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
+    private List<RootInfo> mRoots;
 
     private State mState;
 
@@ -52,70 +50,87 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        mRoots = Lists.newArrayList(
+                mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
+
         mState = new State();
         mState.action = State.ACTION_OPEN;
         mState.showAdvanced = true;
         mState.localOnly = false;
     }
 
-    public void testMatchingRootsEverything() throws Exception {
+    public void testMatchingRoots_Everything() throws Exception {
         mState.acceptMimes = new String[] { "*/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsPngOrWild() throws Exception {
+    public void testMatchingRoots_DirectoryCopy() throws Exception {
+        RootInfo downloads = buildForMimeTypes("*/*");
+        downloads.authority = "com.android.providers.downloads.documents";
+        mRoots.add(downloads);
+
+        mState.acceptMimes = new String[] { "*/*" };
+        mState.directoryCopy = true;
+
+        // basically we're asserting that the results don't contain downloads
+        assertContainsExactly(
+                newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRoots_PngOrWild() throws Exception {
         mState.acceptMimes = new String[] { "image/png", "*/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsAudioWild() throws Exception {
+    public void testMatchingRoots_AudioWild() throws Exception {
         mState.acceptMimes = new String[] { "audio/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsAudioWildOrImageWild() throws Exception {
+    public void testMatchingRoots_AudioWildOrImageWild() throws Exception {
         mState.acceptMimes = new String[] { "audio/*", "image/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio, mImages),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio, mImages),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsAudioSpecific() throws Exception {
+    public void testMatchingRoots_AudioSpecific() throws Exception {
         mState.acceptMimes = new String[] { "audio/mpeg" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsDocument() throws Exception {
+    public void testMatchingRoots_Document() throws Exception {
         mState.acceptMimes = new String[] { "application/msword" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mDocs),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mDocs),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsApplication() throws Exception {
+    public void testMatchingRoots_Application() throws Exception {
         mState.acceptMimes = new String[] { "application/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio, mDocs),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio, mDocs),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsFlacOrPng() throws Exception {
+    public void testMatchingRoots_FlacOrPng() throws Exception {
         mState.acceptMimes = new String[] { "application/x-flac", "image/png" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio, mImages),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio, mImages),
+                getMatchingRoots(mRoots, mState));
     }
 
     public void testExcludedAuthorities() throws Exception {
-        final List<RootInfo> roots = Lists.newArrayList();
+        final List<RootInfo> roots = newArrayList();
 
         // Set up some roots
         for (int i = 0; i < 5; ++i) {
@@ -124,7 +139,7 @@
             roots.add(root);
         }
         // Make some allowed authorities
-        List<RootInfo> allowedRoots = Lists.newArrayList(
+        List<RootInfo> allowedRoots = newArrayList(
             roots.get(0), roots.get(2), roots.get(4));
         // Set up the excluded authority list
         for (RootInfo root: roots) {
@@ -136,7 +151,7 @@
 
         assertContainsExactly(
             allowedRoots,
-            RootsCache.getMatchingRoots(roots, mState));
+            getMatchingRoots(roots, mState));
     }
 
     private static void assertContainsExactly(List<?> expected, List<?> actual) {
@@ -145,4 +160,10 @@
             assertTrue(actual.contains(o));
         }
     }
+
+    private static RootInfo buildForMimeTypes(String... mimeTypes) {
+        final RootInfo root = new RootInfo();
+        root.derivedMimeTypes = mimeTypes;
+        return root;
+    }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java
new file mode 100644
index 0000000..621410a
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.StubProvider.ROOT_0_ID;
+import static com.android.documentsui.StubProvider.ROOT_1_ID;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+@LargeTest
+public class RootsUiTest extends ActivityTest<FilesActivity> {
+
+    private static final String TAG = "RootUiTest";
+
+    public RootsUiTest() {
+        super(FilesActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        initTestFiles();
+    }
+
+    public void testRootTapped_GoToRootFromChildDir() throws Exception {
+        bots.directory.openDocument(dirName1);
+        bots.main.assertWindowTitle(dirName1);
+        bots.roots.openRoot(ROOT_0_ID);
+        bots.main.assertWindowTitle(ROOT_0_ID);
+        assertDefaultContentOfTestDir0();
+    }
+
+    @Suppress
+    public void testRootChanged_ClearSelection() throws Exception {
+        bots.directory.selectDocument(fileName1);
+        bots.main.assertInActionMode(true);
+
+        bots.roots.openRoot(ROOT_1_ID);
+        bots.main.assertInActionMode(false);
+    }
+
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
index b8d8795..a9451a6 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
@@ -20,65 +20,66 @@
 import static com.android.documentsui.StubProvider.ROOT_1_ID;
 
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
 
 @LargeTest
 public class SearchViewUiTest extends ActivityTest<FilesActivity> {
 
-    private static final String TAG = "SearchViewUiTest";
-
     public SearchViewUiTest() {
         super(FilesActivity.class);
     }
 
+    @Suppress
     public void testSearchView_ExpandsOnClick() throws Exception {
-        bot.openSearchView();
-        bot.assertSearchTextFiledAndIcon(true, false);
+        bots.main.openSearchView();
+        bots.main.assertSearchTextFiledAndIcon(true, false);
     }
 
     public void testSearchView_CollapsesOnBack() throws Exception {
-        bot.openSearchView();
+        bots.main.openSearchView();
 
         device.pressBack();
 
-        bot.assertSearchTextFiledAndIcon(false, true);
+        bots.main.assertSearchTextFiledAndIcon(false, true);
     }
 
+    @Suppress
     public void testSearchView_ClearsTextOnBack() throws Exception {
         String query = "file2";
-        bot.openSearchView();
-        bot.setSearchQuery(query);
+        bots.main.openSearchView();
+        bots.main.setSearchQuery(query);
 
         device.pressBack();
 
-        bot.assertSearchTextFiledAndIcon(false, true);
+        bots.main.assertSearchTextFiledAndIcon(false, true);
     }
 
+    @Suppress
     public void testSearch_ResultsFound() throws Exception {
         initTestFiles();
-        bot.openRoot(ROOT_0_ID);
         assertDefaultContentOfTestDir0();
 
         String query = "file1";
-        bot.openSearchView();
-        bot.setSearchQuery(query);
-        bot.assertSearchTextField(true, query);
+        bots.main.openSearchView();
+        bots.main.setSearchQuery(query);
+        bots.main.assertSearchTextField(true, query);
 
         device.pressEnter();
 
-        bot.assertDocumentsCountOnList(true, 2);
-        bot.assertHasDocuments(fileName1, fileName2);
+        bots.directory.assertDocumentsCountOnList(true, 2);
+        bots.directory.assertDocumentsPresent(fileName1, fileName2);
 
-        bot.assertSearchTextField(false, query);
+        bots.main.assertSearchTextField(false, query);
     }
 
+    @Suppress
     public void testSearchResultsFound_ClearsOnBack() throws Exception {
         initTestFiles();
-        bot.openRoot(ROOT_0_ID);
         assertDefaultContentOfTestDir0();
 
         String query = fileName1;
-        bot.openSearchView();
-        bot.setSearchQuery(query);
+        bots.main.openSearchView();
+        bots.main.setSearchQuery(query);
 
         device.pressEnter();
         device.pressBack();
@@ -86,34 +87,34 @@
         assertDefaultContentOfTestDir0();
     }
 
+    @Suppress
     public void testSearch_NoResults() throws Exception {
         initTestFiles();
-        bot.openRoot(ROOT_0_ID);
         assertDefaultContentOfTestDir0();
 
         String query = "chocolate";
-        bot.openSearchView();
-        bot.setSearchQuery(query);
+        bots.main.openSearchView();
+        bots.main.setSearchQuery(query);
 
         device.pressEnter();
 
-        bot.assertDocumentsCountOnList(false, 0);
+        bots.directory.assertDocumentsCountOnList(false, 0);
 
         device.waitForIdle();
         String msg = String.valueOf(context.getString(R.string.no_results));
-        bot.assertMessageTextView(String.format(msg, "TEST_ROOT_0"));
+        bots.directory.assertMessageTextView(String.format(msg, "TEST_ROOT_0"));
 
-        bot.assertSearchTextField(false, query);
+        bots.main.assertSearchTextField(false, query);
     }
 
+    @Suppress
     public void testSearchNoResults_ClearsOnBack() throws Exception {
         initTestFiles();
-        bot.openRoot(ROOT_0_ID);
         assertDefaultContentOfTestDir0();
 
         String query = "chocolate";
-        bot.openSearchView();
-        bot.setSearchQuery(query);
+        bots.main.openSearchView();
+        bots.main.setSearchQuery(query);
 
         device.pressEnter();
         device.pressBack();
@@ -122,32 +123,32 @@
         assertDefaultContentOfTestDir0();
     }
 
+    @Suppress
     public void testSearchResultsFound_ClearsOnDirectoryChange() throws Exception {
         initTestFiles();
-        bot.openRoot(ROOT_0_ID);
         assertDefaultContentOfTestDir0();
 
         String query = fileName1;
-        bot.openSearchView();
-        bot.setSearchQuery(query);
+        bots.main.openSearchView();
+        bots.main.setSearchQuery(query);
 
         device.pressEnter();
 
-        bot.openRoot(ROOT_1_ID);
+        bots.roots.openRoot(ROOT_1_ID);
         assertDefaultContentOfTestDir1();
 
-        bot.openRoot(ROOT_0_ID);
+        bots.roots.openRoot(ROOT_0_ID);
         assertDefaultContentOfTestDir0();
     }
 
     public void testSearchIconVisible_RootWithSearchSupport() throws Exception {
-        bot.openRoot(ROOT_0_ID);
-        bot.assertSearchTextFiledAndIcon(false, true);
+        bots.roots.openRoot(ROOT_0_ID);
+        bots.main.assertSearchTextFiledAndIcon(false, true);
     }
 
     public void testSearchIconHidden_RootNoSearchSupport() throws Exception {
-        bot.openRoot(ROOT_1_ID);
-        bot.assertSearchTextFiledAndIcon(false, false);
+        bots.roots.openRoot(ROOT_1_ID);
+        bots.main.assertSearchTextFiledAndIcon(false, false);
     }
 
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index 2527650..f71ce5d 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -518,28 +518,29 @@
         String rootId = extras.getString(EXTRA_PARENT_ID);
         String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
         String name = extras.getString(Document.COLUMN_DISPLAY_NAME);
+        List<String> streamTypes = extras.getStringArrayList(EXTRA_STREAM_TYPES);
         int flags = extras.getInt(EXTRA_FLAGS);
 
         Bundle out = new Bundle();
         String documentId = null;
         try {
-            documentId = createDocument(rootId, mimeType, name, flags);
+            documentId = createDocument(rootId, mimeType, name, flags, streamTypes);
             Uri uri = DocumentsContract.buildDocumentUri(mAuthority, documentId);
             out.putParcelable(DocumentsContract.EXTRA_URI, uri);
         } catch (FileNotFoundException e) {
-            Log.d(TAG, "Cretaing document with flags failed" + name);
+            Log.d(TAG, "Creating document with flags failed" + name);
         }
         return out;
     }
 
-    public String createDocument(String parentId, String mimeType, String displayName, int flags)
-            throws FileNotFoundException {
+    public String createDocument(String parentId, String mimeType, String displayName, int flags,
+            List<String> streamTypes) throws FileNotFoundException {
 
         StubDocument parent = mStorage.get(parentId);
         File file = createFile(parent, mimeType, displayName);
 
         final StubDocument document = StubDocument.createDocumentWithFlags(file, mimeType, parent,
-                flags);
+                flags, streamTypes);
         mStorage.put(document.documentId, document);
         Log.d(TAG, "Created document " + document.documentId);
         notifyParentChanged(document.parentId);
@@ -787,8 +788,9 @@
         }
 
         public static StubDocument createDocumentWithFlags(
-                File file, String mimeType, StubDocument parent, int flags) {
-            return new StubDocument(file, mimeType, new ArrayList<String>(), flags, parent);
+                File file, String mimeType, StubDocument parent, int flags,
+                List<String> streamTypes) {
+            return new StubDocument(file, mimeType, streamTypes, flags, parent);
         }
 
         public static StubDocument createVirtualDocument(
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
deleted file mode 100644
index d2f8403..0000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.documentsui;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
-
-import android.app.Activity;
-import android.content.Context;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.Configurator;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiScrollable;
-import android.support.test.uiautomator.UiSelector;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.inputmethod.InputMethodManager;
-
-import junit.framework.Assert;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * A test helper class that provides support for controlling DocumentsUI activities
- * programmatically, and making assertions against the state of the UI.
- */
-class UiBot {
-    public static final String TARGET_PKG = "com.android.documentsui";
-
-    private static final String TAG = "UiBot";
-    private static final String LAUNCHER_PKG = "com.android.launcher";
-
-    private static final BySelector SNACK_DELETE =
-            By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
-
-    private UiDevice mDevice;
-    private Context mContext;
-    private int mTimeout;
-
-    public UiBot(UiDevice device, Context context, int timeout) {
-        mDevice = device;
-        mContext = context;
-        mTimeout = timeout;
-    }
-
-    UiObject findRoot(String label) throws UiObjectNotFoundException {
-        final UiSelector rootsList = new UiSelector().resourceId(
-                "com.android.documentsui:id/container_roots").childSelector(
-                new UiSelector().resourceId("com.android.documentsui:id/roots_list"));
-
-        // We might need to expand drawer if not visible
-        if (!new UiObject(rootsList).waitForExists(mTimeout)) {
-            Log.d(TAG, "Failed to find roots list; trying to expand");
-            final UiSelector hamburger = new UiSelector().resourceId(
-                    "com.android.documentsui:id/toolbar").childSelector(
-                    new UiSelector().className("android.widget.ImageButton").clickable(true));
-            new UiObject(hamburger).click();
-        }
-
-        // Wait for the first list item to appear
-        new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
-
-        // Now scroll around to find our item
-        new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
-        return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
-    }
-
-    void openRoot(String label) throws UiObjectNotFoundException {
-        findRoot(label).click();
-        mDevice.waitForIdle();
-    }
-
-    void assertWindowTitle(String expected) {
-        // Turns out the title field on a window does not have
-        // an id associated with it at runtime (which confuses the hell out of me)
-        // In code we address this via "android.R.id.title".
-        UiObject2 o = find(By.text(expected));
-        // It's a bit of a conceit that we then *assert* that the title
-        // is the value that we used to identify the UiObject2.
-        // If the preceeding lookup fails, this'll choke with an NPE.
-        // But given the issue described in the comment above, we're
-        // going to do it anyway. Because we shouldn't be looking up
-        // the uiobject by it's expected content :|
-        assertEquals(expected, o.getText());
-    }
-
-    void assertHasRoots(String... labels) throws UiObjectNotFoundException {
-        List<String> missing = new ArrayList<>();
-        for (String label : labels) {
-            if (!findRoot(label).exists()) {
-                missing.add(label);
-            }
-        }
-        if (!missing.isEmpty()) {
-            Assert.fail(
-                    "Expected roots " + Arrays.asList(labels) + ", but missing " + missing);
-        }
-    }
-
-    void assertMenuEnabled(int id, boolean enabled) {
-        UiObject2 menu= findMenuWithName(mContext.getString(id));
-        assertNotNull(menu);
-        assertEquals(enabled, menu.isEnabled());
-    }
-
-    void assertDocumentsCount(int count) throws UiObjectNotFoundException {
-        UiObject docsList = findDocumentsList();
-        assertEquals(count, docsList.getChildCount());
-    }
-
-    void assertDocumentsCount(String dir, int count) throws UiObjectNotFoundException {
-        openRoot(dir);
-        UiObject docsList = findDocumentsList();
-        assertEquals(count, docsList.getChildCount());
-    }
-
-    void assertSearchTextField(boolean isFocused, String query)
-            throws UiObjectNotFoundException {
-        UiObject textField = findSearchViewTextField();
-        UiObject searchIcon = findSearchViewIcon();
-
-        assertFalse(searchIcon.exists());
-        assertTrue(textField.exists());
-        assertEquals(isFocused, textField.isFocused());
-        if(query != null) {
-            assertEquals(query, textField.getText());
-        }
-    }
-
-    void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) {
-        assertEquals(searchTextFieldExists, findSearchViewTextField().exists());
-        assertEquals(searchIconExists, findSearchViewIcon().exists());
-    }
-
-    void assertHasDocuments(String... labels) throws UiObjectNotFoundException {
-        List<String> missing = new ArrayList<>();
-        for (String label : labels) {
-            if (!findDocument(label).exists()) {
-                missing.add(label);
-            }
-        }
-        if (!missing.isEmpty()) {
-            Assert.fail(
-                    "Expected documents " + Arrays.asList(labels) + ", but missing " + missing);
-        }
-    }
-
-    void assertDocument(String name, boolean exists) throws UiObjectNotFoundException {
-        UiObject doc = findDocument(name);
-        assertEquals(exists, doc.exists());
-    }
-
-    void assertDocumentsCountOnList(boolean exists, int count) throws UiObjectNotFoundException {
-        UiObject docsList = findDocumentsList();
-        assertEquals(exists, docsList.exists());
-        if(docsList.exists()) {
-            assertEquals(count, docsList.getChildCount());
-        }
-    }
-
-    void assertMessageTextView(String message) throws UiObjectNotFoundException {
-        UiObject messageTextView = findMessageTextView();
-        assertTrue(messageTextView.exists());
-
-        String msg = String.valueOf(message);
-        assertEquals(String.format(msg, "TEST_ROOT_0"), messageTextView.getText());
-
-    }
-    void assertSnackbar(int id) {
-        assertNotNull(getSnackbar(mContext.getString(id)));
-    }
-
-    /**
-     * Asserts that the specified view or one of its descendents has focus.
-     */
-    void assertHasFocus(String resourceName) {
-        UiObject2 candidate = mDevice.findObject(By.res(resourceName));
-        assertNotNull("Expected " + resourceName + " to have focus, but it didn't.",
-            candidate.findObject(By.focused(true)));
-    }
-
-    void openDocument(String label) throws UiObjectNotFoundException {
-        int toolType = Configurator.getInstance().getToolType();
-        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
-        UiObject doc = findDocument(label);
-        doc.click();
-        Configurator.getInstance().setToolType(toolType);
-    }
-
-    void clickDocument(String label) throws UiObjectNotFoundException {
-        findDocument(label).click();
-    }
-
-    void openSearchView() throws UiObjectNotFoundException {
-        UiObject searchView = findSearchView();
-        searchView.click();
-        assertTrue(searchView.exists());
-    }
-
-    void setSearchQuery(String query) throws UiObjectNotFoundException {
-        UiObject searchView = findSearchView();
-        assertTrue(searchView.exists());
-        UiObject searchTextField = findSearchViewTextField();
-        searchTextField.setText(query);
-        assertSearchTextField(true, query);
-    }
-
-    UiObject openOverflowMenu() throws UiObjectNotFoundException {
-        UiObject obj = findMenuMoreOptions();
-        obj.click();
-        mDevice.waitForIdle(mTimeout);
-        return obj;
-    }
-
-    void openDialog(int id) {
-        UiObject2 menu= findMenuWithName(mContext.getString(id));
-        assertNotNull(menu);
-        assertEquals(true, menu.isEnabled());
-        menu.click();
-    }
-
-    void setDialogText(String text) throws UiObjectNotFoundException {
-        findDialogEditText().setText(text);
-    }
-
-    UiObject selectDocument(String label) throws UiObjectNotFoundException {
-        UiObject doc = findDocument(label);
-        doc.longClick();
-        return doc;
-    }
-
-    UiObject2 getSnackbar(String message) {
-        return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
-    }
-
-    void waitForDeleteSnackbar() {
-        mDevice.wait(Until.findObject(SNACK_DELETE), mTimeout);
-    }
-
-    void waitForDeleteSnackbarGone() {
-        // wait a little longer for snackbar to go away, as it disappears after a timeout.
-        mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
-    }
-
-    void waitForDocument(String label) throws UiObjectNotFoundException {
-        findDocument(label).waitForExists(mTimeout);
-    }
-
-    void switchViewMode() {
-        UiObject2 mode = menuGridMode();
-        if (mode != null) {
-            mode.click();
-        } else {
-            menuListMode().click();
-        }
-    }
-
-    UiObject2 menuGridMode() {
-        // Note that we're using By.desc rather than By.res, because of b/25285770
-        return find(By.desc("Grid view"));
-    }
-
-    UiObject2 menuListMode() {
-        // Note that we're using By.desc rather than By.res, because of b/25285770
-        return find(By.desc("List view"));
-    }
-
-    UiObject2 menuDelete() {
-        return find(By.res("com.android.documentsui:id/menu_delete"));
-    }
-
-    UiObject2 menuShare() {
-        return find(By.res("com.android.documentsui:id/menu_share"));
-    }
-
-    private UiObject2 find(BySelector selector) {
-        mDevice.wait(Until.findObject(selector), mTimeout);
-        return mDevice.findObject(selector);
-    }
-
-    private UiObject findObject(String resourceId) {
-        final UiSelector object = new UiSelector().resourceId(resourceId);
-        return mDevice.findObject(object);
-    }
-
-    private UiObject findObject(String parentResourceId, String childResourceId) {
-        final UiSelector selector = new UiSelector()
-                .resourceId(parentResourceId)
-                .childSelector(new UiSelector().resourceId(childResourceId));
-        return mDevice.findObject(selector);
-    }
-
-    UiObject findDocument(String label) throws UiObjectNotFoundException {
-        final UiSelector docList = new UiSelector().resourceId(
-                "com.android.documentsui:id/container_directory").childSelector(
-                        new UiSelector().resourceId("com.android.documentsui:id/dir_list"));
-
-        // Wait for the first list item to appear
-        new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
-
-        // new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
-        return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
-    }
-
-    boolean hasDocuments(String... labels) throws UiObjectNotFoundException {
-        for (String label : labels) {
-            if (!findDocument(label).exists()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    UiObject findDocumentsList() {
-        return findObject(
-                "com.android.documentsui:id/container_directory",
-                "com.android.documentsui:id/dir_list");
-    }
-
-    UiObject findSearchView() {
-        return findObject("com.android.documentsui:id/menu_search");
-    }
-
-    UiObject findSearchViewTextField() {
-        return findObject("com.android.documentsui:id/menu_search", "android:id/search_src_text");
-    }
-
-    UiObject findSearchViewIcon() {
-        return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
-    }
-
-    UiObject findMessageTextView() {
-        return findObject(
-                "com.android.documentsui:id/container_directory",
-                "com.android.documentsui:id/message");
-    }
-
-    UiObject findActionModeBar() {
-        return findObject("android:id/action_mode_bar");
-    }
-
-    UiObject findDialogEditText() {
-        return findObject("android:id/content", "android:id/text1");
-    }
-
-    UiObject findRenameDialogOkButton() {
-        return findObject("android:id/content", "android:id/button1");
-    }
-
-    UiObject findRenameDialogCancelButton() {
-        return findObject("android:id/content", "android:id/button2");
-    }
-
-    UiObject findMenuLabelWithName(String label) {
-        UiSelector selector = new UiSelector().text(label);
-        return mDevice.findObject(selector);
-    }
-
-    UiObject2 findMenuWithName(String label) {
-        List<UiObject2> menuItems = mDevice.findObjects(By.clazz("android.widget.LinearLayout"));
-        Iterator<UiObject2> it = menuItems.iterator();
-
-        UiObject2 menuItem = null;
-        while(it.hasNext()) {
-            menuItem = it.next();
-            UiObject2 text = menuItem.findObject(By.text(label));
-            if(text != null) {
-                break;
-            }
-        }
-        return menuItem;
-    }
-
-    UiObject findMenuMoreOptions() {
-        UiSelector selector = new UiSelector().className("android.widget.ImageButton")
-                .descriptionContains("More options");
-        //TODO: use the system string ? android.R.string.action_menu_overflow_description
-        return mDevice.findObject(selector);
-    }
-
-    // Indirect way to detect the keyboard.
-    boolean isKeyboardPresent() {
-        InputMethodManager inputManager = (InputMethodManager) mContext
-                .getSystemService(Context.INPUT_METHOD_SERVICE);
-        return inputManager.isAcceptingText();
-    }
-
-    void dismissKeyboardIfPresent() {
-        if(isKeyboardPresent()) {
-            mDevice.pressBack();
-        }
-    }
-
-    void revealLauncher() {
-        mDevice.pressHome();
-        mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), mTimeout);
-    }
-
-    void revealApp() {
-        mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), mTimeout);
-        mDevice.waitForIdle();
-    }
-
-    void pressKey(int keyCode) {
-        mDevice.pressKeyCode(keyCode);
-    }
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/BaseBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/BaseBot.java
new file mode 100644
index 0000000..1d2b47f
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/BaseBot.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.bots;
+
+import static junit.framework.Assert.assertNotNull;
+
+import android.content.Context;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+
+/**
+ * A test helper class that provides support for controlling directory list
+ * and making assertions against the state of it.
+ */
+abstract class BaseBot {
+    final UiDevice mDevice;
+    final Context mContext;
+    final int mTimeout;
+
+    BaseBot(UiDevice device, Context context, int timeout) {
+        mDevice = device;
+        mContext = context;
+        mTimeout = timeout;
+    }
+
+    /**
+     * Asserts that the specified view or one of its descendents has focus.
+     */
+    protected void assertHasFocus(String resourceName) {
+        UiObject2 candidate = mDevice.findObject(By.res(resourceName));
+        assertNotNull("Expected " + resourceName + " to have focus, but it didn't.",
+            candidate.findObject(By.focused(true)));
+    }
+
+    protected UiObject2 find(BySelector selector) {
+        mDevice.wait(Until.findObject(selector), mTimeout);
+        return mDevice.findObject(selector);
+    }
+
+    protected UiObject findObject(String resourceId) {
+        final UiSelector object = new UiSelector().resourceId(resourceId);
+        return mDevice.findObject(object);
+    }
+
+    protected UiObject findObject(String parentResourceId, String childResourceId) {
+        final UiSelector selector = new UiSelector()
+                .resourceId(parentResourceId)
+                .childSelector(new UiSelector().resourceId(childResourceId));
+        return mDevice.findObject(selector);
+    }
+
+    protected void waitForIdle() {
+        mDevice.waitForIdle(mTimeout);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
new file mode 100644
index 0000000..7c1e2196
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.bots;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+import android.view.MotionEvent;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * A test helper class that provides support for controlling directory list
+ * and making assertions against the state of it.
+ */
+public class DirectoryListBot extends BaseBot {
+    private static final String DIR_LIST_ID = "com.android.documentsui:id/dir_list";
+
+    private static final BySelector SNACK_DELETE =
+            By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
+
+    public DirectoryListBot(UiDevice device, Context context, int timeout) {
+        super(device, context, timeout);
+    }
+
+    public void assertDocumentsCount(int count) throws UiObjectNotFoundException {
+        UiObject docsList = findDocumentsList();
+        assertEquals(count, docsList.getChildCount());
+    }
+
+    public void assertDocumentsPresent(String... labels) throws UiObjectNotFoundException {
+        List<String> absent = new ArrayList<>();
+        for (String label : labels) {
+            if (!findDocument(label).exists()) {
+                absent.add(label);
+            }
+        }
+        if (!absent.isEmpty()) {
+            Assert.fail("Expected documents " + Arrays.asList(labels)
+                    + ", but missing " + absent);
+        }
+    }
+
+    public void assertDocumentsAbsent(String... labels) throws UiObjectNotFoundException {
+        List<String> found = new ArrayList<>();
+        for (String label : labels) {
+            if (findDocument(label).exists()) {
+                found.add(label);
+            }
+        }
+        if (!found.isEmpty()) {
+            Assert.fail("Expected documents not present" + Arrays.asList(labels)
+                    + ", but present " + found);
+        }
+    }
+
+    public void assertDocumentsCountOnList(boolean exists, int count) throws UiObjectNotFoundException {
+        UiObject docsList = findDocumentsList();
+        assertEquals(exists, docsList.exists());
+        if(docsList.exists()) {
+            assertEquals(count, docsList.getChildCount());
+        }
+    }
+
+    public void assertMessageTextView(String message) throws UiObjectNotFoundException {
+        UiObject messageTextView = findMessageTextView();
+        assertTrue(messageTextView.exists());
+
+        String msg = String.valueOf(message);
+        assertEquals(String.format(msg, "TEST_ROOT_0"), messageTextView.getText());
+
+    }
+
+    private UiObject findMessageTextView() {
+        return findObject(
+                "com.android.documentsui:id/container_directory",
+                "com.android.documentsui:id/message");
+    }
+
+    public void assertSnackbar(int id) {
+        assertNotNull(getSnackbar(mContext.getString(id)));
+    }
+
+    public void openDocument(String label) throws UiObjectNotFoundException {
+        int toolType = Configurator.getInstance().getToolType();
+        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
+        UiObject doc = findDocument(label);
+        doc.click();
+        Configurator.getInstance().setToolType(toolType);
+    }
+
+    public void clickDocument(String label) throws UiObjectNotFoundException {
+        findDocument(label).click();
+    }
+
+    public UiObject selectDocument(String label) throws UiObjectNotFoundException {
+        UiObject doc = findDocument(label);
+        doc.longClick();
+        return doc;
+    }
+
+    public UiObject2 getSnackbar(String message) {
+        return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
+    }
+
+    public void waitForDeleteSnackbar() {
+        mDevice.wait(Until.findObject(SNACK_DELETE), mTimeout);
+    }
+
+    public void waitForDeleteSnackbarGone() {
+        // wait a little longer for snackbar to go away, as it disappears after a timeout.
+        mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
+    }
+
+    public void waitForDocument(String label) throws UiObjectNotFoundException {
+        findDocument(label).waitForExists(mTimeout);
+    }
+
+    public UiObject findDocument(String label) throws UiObjectNotFoundException {
+        final UiSelector docList = new UiSelector().resourceId(
+                "com.android.documentsui:id/container_directory").childSelector(
+                        new UiSelector().resourceId(DIR_LIST_ID));
+
+        // Wait for the first list item to appear
+        new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
+
+        // new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
+        return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
+    }
+
+    public boolean hasDocuments(String... labels) throws UiObjectNotFoundException {
+        for (String label : labels) {
+            if (!findDocument(label).exists()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public UiObject findDocumentsList() {
+        return findObject(
+                "com.android.documentsui:id/container_directory",
+                DIR_LIST_ID);
+    }
+
+    public void assertHasFocus() {
+        assertHasFocus(DIR_LIST_ID);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/KeyboardBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/KeyboardBot.java
new file mode 100644
index 0000000..4c47cfa
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/KeyboardBot.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.bots;
+
+import android.content.Context;
+import android.support.test.uiautomator.UiDevice;
+import android.view.inputmethod.InputMethodManager;
+
+/**
+ * A test helper class that provides support for keyboard manipulation.
+ */
+public class KeyboardBot extends BaseBot {
+
+    public KeyboardBot(UiDevice device, Context context, int timeout) {
+        super(device, context, timeout);
+    }
+
+    public void dismissKeyboardIfPresent() {
+        if(isKeyboardPresent()) {
+            mDevice.pressBack();
+        }
+    }
+
+    // Indirect way to detect the keyboard.
+    private boolean isKeyboardPresent() {
+        InputMethodManager inputManager = (InputMethodManager) mContext
+                .getSystemService(Context.INPUT_METHOD_SERVICE);
+        return inputManager.isAcceptingText();
+    }
+
+    public void pressEnter() {
+        waitForIdle();
+        mDevice.pressEnter();
+        waitForIdle();
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/RootsListBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/RootsListBot.java
new file mode 100644
index 0000000..096af10
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/RootsListBot.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.bots;
+
+import android.content.Context;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A test helper class that provides support for controlling and asserting against
+ * the roots list drawer.
+ */
+public class RootsListBot extends BaseBot {
+    private static final String ROOTS_LIST_ID = "com.android.documentsui:id/roots_list";
+    private static final String TAG = "RootsListBot";
+
+    public RootsListBot(UiDevice device, Context context, int timeout) {
+        super(device, context, timeout);
+    }
+
+    private UiObject findRoot(String label) throws UiObjectNotFoundException {
+        final UiSelector rootsList = new UiSelector().resourceId(
+                "com.android.documentsui:id/container_roots").childSelector(
+                new UiSelector().resourceId(ROOTS_LIST_ID));
+
+        // We might need to expand drawer if not visible
+        if (!new UiObject(rootsList).waitForExists(mTimeout)) {
+            Log.d(TAG, "Failed to find roots list; trying to expand");
+            final UiSelector hamburger = new UiSelector().resourceId(
+                    "com.android.documentsui:id/toolbar").childSelector(
+                    new UiSelector().className("android.widget.ImageButton").clickable(true));
+            new UiObject(hamburger).click();
+        }
+
+        // Wait for the first list item to appear
+        new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
+
+        // Now scroll around to find our item
+        new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
+        return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
+    }
+
+    public void openRoot(String label) throws UiObjectNotFoundException {
+        findRoot(label).click();
+        mDevice.waitForIdle();
+    }
+
+    public void assertRootsPresent(String... labels) throws UiObjectNotFoundException {
+        List<String> missing = new ArrayList<>();
+        for (String label : labels) {
+            if (!findRoot(label).exists()) {
+                missing.add(label);
+            }
+        }
+        if (!missing.isEmpty()) {
+            Assert.fail(
+                    "Expected roots " + Arrays.asList(labels) + ", but missing " + missing);
+        }
+    }
+
+    public void assertRootsAbsent(String... labels) throws UiObjectNotFoundException {
+        List<String> unexpected = new ArrayList<>();
+        for (String label : labels) {
+            if (findRoot(label).exists()) {
+                unexpected.add(label);
+            }
+        }
+        if (!unexpected.isEmpty()) {
+            Assert.fail("Unexpected roots " + unexpected);
+        }
+    }
+
+    public void assertHasFocus() {
+        assertHasFocus(ROOTS_LIST_ID);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
new file mode 100644
index 0000000..4c8dc00
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.bots;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+
+import com.android.documentsui.R;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A test helper class that provides support for controlling DocumentsUI activities
+ * programmatically, and making assertions against the state of the UI.
+ *
+ * <p>Support for working directly with Roots and Directory view can be found
+ * in the respective bots.
+ */
+public class UiBot extends BaseBot {
+    public static final String TARGET_PKG = "com.android.documentsui";
+    private static final String LAUNCHER_PKG = "com.android.launcher";
+
+    public UiBot(UiDevice device, Context context, int timeout) {
+        super(device, context, timeout);
+    }
+
+    public void assertWindowTitle(String expected) {
+        // Turns out the title field on a window does not have
+        // an id associated with it at runtime (which confuses the hell out of me)
+        // In code we address this via "android.R.id.title".
+        UiObject2 o = find(By.text(expected));
+        // It's a bit of a conceit that we then *assert* that the title
+        // is the value that we used to identify the UiObject2.
+        // If the preceeding lookup fails, this'll choke with an NPE.
+        // But given the issue described in the comment above, we're
+        // going to do it anyway. Because we shouldn't be looking up
+        // the uiobject by it's expected content :|
+        assertEquals(expected, o.getText());
+    }
+
+    public void assertMenuEnabled(int id, boolean enabled) {
+        UiObject2 menu= findMenuWithName(mContext.getString(id));
+        assertNotNull(menu);
+        assertEquals(enabled, menu.isEnabled());
+    }
+
+    public void assertSearchTextField(boolean isFocused, String query)
+            throws UiObjectNotFoundException {
+        UiObject textField = findSearchViewTextField();
+        UiObject searchIcon = findSearchViewIcon();
+
+        assertFalse(searchIcon.exists());
+        assertTrue(textField.exists());
+        assertEquals(isFocused, textField.isFocused());
+        if(query != null) {
+            assertEquals(query, textField.getText());
+        }
+    }
+
+    public void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) {
+        assertEquals(searchTextFieldExists, findSearchViewTextField().exists());
+        assertEquals(searchIconExists, findSearchViewIcon().exists());
+    }
+
+    public void assertInActionMode(boolean inActionMode) {
+        UiObject actionModeBar = findActionModeBar();
+        assertEquals(inActionMode, actionModeBar.exists());
+    }
+
+    public void openSearchView() throws UiObjectNotFoundException {
+        UiObject searchView = findSearchView();
+        searchView.click();
+        assertTrue(searchView.exists());
+    }
+
+    public void setSearchQuery(String query) throws UiObjectNotFoundException {
+        UiObject searchView = findSearchView();
+        assertTrue(searchView.exists());
+        UiObject searchTextField = findSearchViewTextField();
+        searchTextField.setText(query);
+        assertSearchTextField(true, query);
+    }
+
+    public UiObject openOverflowMenu() throws UiObjectNotFoundException {
+        UiObject obj = findMenuMoreOptions();
+        obj.click();
+        mDevice.waitForIdle(mTimeout);
+        return obj;
+    }
+
+    public void setDialogText(String text) throws UiObjectNotFoundException {
+        findDialogEditText().setText(text);
+    }
+
+    void switchViewMode() {
+        UiObject2 mode = menuGridMode();
+        if (mode != null) {
+            mode.click();
+        } else {
+            menuListMode().click();
+        }
+    }
+
+    UiObject2 menuGridMode() {
+        // Note that we're using By.desc rather than By.res, because of b/25285770
+        return find(By.desc("Grid view"));
+    }
+
+        UiObject2 menuListMode() {
+        // Note that we're using By.desc rather than By.res, because of b/25285770
+        return find(By.desc("List view"));
+    }
+
+    public UiObject2 menuDelete() {
+        return find(By.res("com.android.documentsui:id/menu_delete"));
+    }
+
+    public UiObject2 menuShare() {
+        return find(By.res("com.android.documentsui:id/menu_share"));
+    }
+
+    public UiObject2 menuRename() {
+        return findMenuWithName(mContext.getString(R.string.menu_rename));
+    }
+
+    public UiObject2 menuNewFolder() {
+        return findMenuWithName(mContext.getString(R.string.menu_create_dir));
+    }
+
+    UiObject findSearchView() {
+        return findObject("com.android.documentsui:id/menu_search");
+    }
+
+    UiObject findSearchViewTextField() {
+        return findObject("com.android.documentsui:id/menu_search", "android:id/search_src_text");
+    }
+
+    UiObject findSearchViewIcon() {
+        return mContext.getResources().getBoolean(R.bool.full_bar_search_view)
+                ? findObject("com.android.documentsui:id/menu_search")
+                : findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
+    }
+
+    UiObject findActionModeBar() {
+        return findObject("android:id/action_mode_bar");
+    }
+
+    public UiObject findDialogEditText() {
+        return findObject("android:id/content", "android:id/text1");
+    }
+
+    public UiObject findDownloadRetryDialog() {
+        UiSelector selector = new UiSelector().text("Couldn't download");
+        UiObject title = mDevice.findObject(selector);
+        title.waitForExists(mTimeout);
+        return title;
+    }
+
+    public UiObject findDialogOkButton() {
+        UiObject object = findObject("android:id/content", "android:id/button1");
+        object.waitForExists(mTimeout);
+        return object;
+    }
+
+    public UiObject findDialogCancelButton() {
+        UiObject object = findObject("android:id/content", "android:id/button2");
+        object.waitForExists(mTimeout);
+        return object;
+    }
+
+    UiObject findMenuLabelWithName(String label) {
+        UiSelector selector = new UiSelector().text(label);
+        return mDevice.findObject(selector);
+    }
+
+    UiObject2 findMenuWithName(String label) {
+        List<UiObject2> menuItems = mDevice.findObjects(By.clazz("android.widget.LinearLayout"));
+        Iterator<UiObject2> it = menuItems.iterator();
+
+        UiObject2 menuItem = null;
+        while(it.hasNext()) {
+            menuItem = it.next();
+            UiObject2 text = menuItem.findObject(By.text(label));
+            if(text != null) {
+                break;
+            }
+        }
+        return menuItem;
+    }
+
+    UiObject findMenuMoreOptions() {
+        UiSelector selector = new UiSelector().className("android.widget.ImageButton")
+                .descriptionContains("More options");
+        //TODO: use the system string ? android.R.string.action_menu_overflow_description
+        return mDevice.findObject(selector);
+    }
+
+    public void pressKey(int keyCode) {
+        mDevice.pressKeyCode(keyCode);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
index 2244be9..7ab51ba2 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
@@ -68,33 +68,11 @@
 
     // Tests that the item count is correct.
     public void testHide_ItemCount() {
-        List<String> ids = mModel.getModelIds();
-        mAdapter.hide(ids.get(0), ids.get(1));
+        String[] ids = mModel.getModelIds();
+        mAdapter.hide(ids[0], ids[1]);
         assertEquals(mModel.getItemCount() - 2, mAdapter.getItemCount());
     }
 
-    // Tests that the items can be hidden and unhidden.
-    public void testUnhide_ItemCount() {
-        List<String> ids = mModel.getModelIds();
-        SparseArray<String> hidden = mAdapter.hide(ids.toArray(new String[ids.size()]));
-        mAdapter.unhide(hidden);
-        assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
-    }
-
-    // Tests that the items can be hidden and unhidden.
-    public void testUnhide_PreservesOrder() {
-        List<String> ids = mModel.getModelIds();
-        SparseArray<String> hidden = mAdapter.hide(
-                ids.get(0), ids.get(1), ids.get(5), ids.get(9));
-        mAdapter.unhide(hidden);
-
-        // Finally ensure the restored items are in the original order
-        // by checking them against the model.
-        for (int i = 0; i < mAdapter.getItemCount(); i++) {
-            assertEquals(mModel.idForPosition(i), mAdapter.getModelId(i));
-        }
-    }
-
     private final class TestEnvironment implements DocumentsAdapter.Environment {
         private final Context testContext;
 
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
index 4b0bc41..b816287 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -21,6 +21,7 @@
 import android.content.ContextWrapper;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.database.MergeCursor;
 import android.provider.DocumentsContract.Document;
 import android.test.AndroidTestCase;
 import android.test.mock.MockContentResolver;
@@ -107,7 +108,7 @@
 
         assertTrue(model.isEmpty());
         assertEquals(0, model.getItemCount());
-        assertEquals(0, model.getModelIds().size());
+        assertEquals(0, model.getModelIds().length);
     }
 
     // Tests that the item count is correct.
@@ -117,21 +118,25 @@
 
     // Tests multiple authorities with clashing document IDs.
     public void testModelIdIsUnique() {
-        MatrixCursor cIn = new MatrixCursor(COLUMNS);
+        MatrixCursor cIn1 = new MatrixCursor(COLUMNS);
+        MatrixCursor cIn2 = new MatrixCursor(COLUMNS);
 
         // Make two sets of items with the same IDs, under different authorities.
         final String AUTHORITY0 = "auth0";
         final String AUTHORITY1 = "auth1";
+
         for (int i = 0; i < ITEM_COUNT; ++i) {
-            MatrixCursor.RowBuilder row0 = cIn.newRow();
+            MatrixCursor.RowBuilder row0 = cIn1.newRow();
             row0.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY0);
             row0.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
 
-            MatrixCursor.RowBuilder row1 = cIn.newRow();
+            MatrixCursor.RowBuilder row1 = cIn2.newRow();
             row1.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY1);
             row1.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
         }
 
+        Cursor cIn = new MergeCursor(new Cursor[] { cIn1, cIn2 });
+
         // Update the model, then make sure it contains all the expected items.
         DirectoryResult r = new DirectoryResult();
         r.cursor = cIn;
@@ -165,10 +170,10 @@
 
     // Tests the base case for Model.getItem.
     public void testGetItem() {
-        List<String> ids = model.getModelIds();
-        assertEquals(ITEM_COUNT, ids.size());
+        String[] ids = model.getModelIds();
+        assertEquals(ITEM_COUNT, ids.length);
         for (int i = 0; i < ITEM_COUNT; ++i) {
-            Cursor c = model.getItem(ids.get(i));
+            Cursor c = model.getItem(ids[i]);
             assertEquals(i, c.getPosition());
         }
     }
@@ -284,7 +289,7 @@
             String id = Integer.toString(i);
             row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
             row.add(Document.COLUMN_DOCUMENT_ID, id);
-            currentDownloads.add(Model.createModelId(AUTHORITY, id));
+            currentDownloads.add(id);
         }
 
         DirectoryResult r = new DirectoryResult();
@@ -292,14 +297,14 @@
         r.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
         model.update(r);
 
-        List<String> ids = model.getModelIds();
+        String[] ids = model.getModelIds();
 
         // Check that all items were accounted for
-        assertEquals(ITEM_COUNT + DL_COUNT, ids.size());
+        assertEquals(ITEM_COUNT + DL_COUNT, ids.length);
 
         // Check that active downloads are sorted to the top.
         for (int i = 0; i < DL_COUNT; i++) {
-            assertTrue(currentDownloads.contains(ids.get(i)));
+            assertTrue(currentDownloads.contains(ids[i]));
         }
     }
 
@@ -316,11 +321,11 @@
     }
 
     private Selection positionToSelection(int... positions) {
-        List<String> ids = model.getModelIds();
+        String[] ids = model.getModelIds();
         Selection s = new Selection();
         // Construct a selection of the given positions.
         for (int p: positions) {
-            s.add(ids.get(p));
+            s.add(ids[p]);
         }
         return s;
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
index 353d4bd..0c0e0b7 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
@@ -27,6 +27,7 @@
 import com.android.documentsui.dirlist.MultiSelectManager.GridModel;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 @SmallTest
@@ -42,6 +43,17 @@
     private Set<String> lastSelection;
     private int viewWidth;
 
+    // TLDR: Don't call model.{start|resize}Selection; use the local #startSelection and
+    // #resizeSelection methods instead.
+    //
+    // The reason for this is that selection is stateful and involves operations that take the
+    // current UI state (e.g scrolling) into account. This test maintains its own copy of the
+    // selection bounds as control data for verifying selections. Keep this data in sync by calling
+    // #startSelection and
+    // #resizeSelection.
+    private Point mSelectionOrigin;
+    private Point mSelectionPoint;
+
     private void initData(final int numChildren, int numColumns) {
         env = new TestEnvironment(numChildren, numColumns);
         adapter = new TestDocumentsAdapter(new ArrayList<String>()) {
@@ -76,139 +88,241 @@
 
     public void testSelectionLeftOfItems() {
         initData(20, 5);
-        model.startSelection(new Point(0, 10));
-        model.resizeSelection(new Point(1, 11));
-        assertSelected();
+        startSelection(new Point(0, 10));
+        resizeSelection(new Point(1, 11));
+        assertNoSelection();
         assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionRightOfItems() {
         initData(20, 4);
-        model.startSelection(new Point(viewWidth - 1, 10));
-        model.resizeSelection(new Point(viewWidth - 2, 11));
-        assertSelected();
+        startSelection(new Point(viewWidth - 1, 10));
+        resizeSelection(new Point(viewWidth - 2, 11));
+        assertNoSelection();
         assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionAboveItems() {
         initData(20, 4);
-        model.startSelection(new Point(10, 0));
-        model.resizeSelection(new Point(11, 1));
-        assertSelected();
+        startSelection(new Point(10, 0));
+        resizeSelection(new Point(11, 1));
+        assertNoSelection();
         assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionBelowItems() {
         initData(5, 4);
-        model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
-        model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
-        assertSelected();
+        startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
+        resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
+        assertNoSelection();
         assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testVerticalSelectionBetweenItems() {
         initData(20, 4);
-        model.startSelection(new Point(106, 0));
-        model.resizeSelection(new Point(107, 200));
-        assertSelected();
+        startSelection(new Point(106, 0));
+        resizeSelection(new Point(107, 200));
+        assertNoSelection();
         assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testHorizontalSelectionBetweenItems() {
         initData(20, 4);
-        model.startSelection(new Point(0, 105));
-        model.resizeSelection(new Point(200, 106));
-        assertSelected();
+        startSelection(new Point(0, 105));
+        resizeSelection(new Point(200, 106));
+        assertNoSelection();
         assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testGrowingAndShrinkingSelection() {
         initData(20, 4);
-        model.startSelection(new Point(0, 0));
-        model.resizeSelection(new Point(5, 5));
-        assertSelected(0);
-        model.resizeSelection(new Point(109, 109));
-        assertSelected(0);
-        model.resizeSelection(new Point(110, 109));
-        assertSelected(0, 1);
-        model.resizeSelection(new Point(110, 110));
-        assertSelected(0, 1, 4, 5);
-        model.resizeSelection(new Point(214, 214));
-        assertSelected(0, 1, 4, 5);
-        model.resizeSelection(new Point(215, 214));
-        assertSelected(0, 1, 2, 4, 5, 6);
-        model.resizeSelection(new Point(214, 214));
-        assertSelected(0, 1, 4, 5);
-        model.resizeSelection(new Point(110, 110));
-        assertSelected(0, 1, 4, 5);
-        model.resizeSelection(new Point(110, 109));
-        assertSelected(0, 1);
-        model.resizeSelection(new Point(109, 109));
-        assertSelected(0);
-        model.resizeSelection(new Point(5, 5));
-        assertSelected(0);
-        model.resizeSelection(new Point(0, 0));
-        assertSelected();
+        startSelection(new Point(0, 0));
+
+        resizeSelection(new Point(5, 5));
+        verifySelection();
+
+        resizeSelection(new Point(109, 109));
+        verifySelection();
+
+        resizeSelection(new Point(110, 109));
+        verifySelection();
+
+        resizeSelection(new Point(110, 110));
+        verifySelection();
+
+        resizeSelection(new Point(214, 214));
+        verifySelection();
+
+        resizeSelection(new Point(215, 214));
+        verifySelection();
+
+        resizeSelection(new Point(214, 214));
+        verifySelection();
+
+        resizeSelection(new Point(110, 110));
+        verifySelection();
+
+        resizeSelection(new Point(110, 109));
+        verifySelection();
+
+        resizeSelection(new Point(109, 109));
+        verifySelection();
+
+        resizeSelection(new Point(5, 5));
+        verifySelection();
+
+        resizeSelection(new Point(0, 0));
+        verifySelection();
+
         assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionMovingAroundOrigin() {
         initData(16, 4);
-        model.startSelection(new Point(210, 210));
-        model.resizeSelection(new Point(viewWidth - 1, 0));
-        assertSelected(2, 3, 6, 7);
-        model.resizeSelection(new Point(0, 0));
-        assertSelected(0, 1, 4, 5);
-        model.resizeSelection(new Point(0, 420));
-        assertSelected(8, 9, 12, 13);
-        model.resizeSelection(new Point(viewWidth - 1, 420));
-        assertSelected(10, 11, 14, 15);
-        assertEquals(10, model.getPositionNearestOrigin());
+
+        startSelection(new Point(210, 210));
+        resizeSelection(new Point(viewWidth - 1, 0));
+        verifySelection();
+
+        resizeSelection(new Point(0, 0));
+        verifySelection();
+
+        resizeSelection(new Point(0, 420));
+        verifySelection();
+
+        resizeSelection(new Point(viewWidth - 1, 420));
+        verifySelection();
+
+        // This is manually figured and will need to be adjusted if the separator position is
+        // changed.
+        assertEquals(7, model.getPositionNearestOrigin());
     }
 
     public void testScrollingBandSelect() {
         initData(40, 4);
-        model.startSelection(new Point(0, 0));
-        model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
-        assertSelected(0, 4, 8, 12, 16);
+
+        startSelection(new Point(0, 0));
+        resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+        verifySelection();
+
         scroll(CHILD_VIEW_EDGE_PX);
-        assertSelected(0, 4, 8, 12, 16, 20);
-        model.resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
-        assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21);
+        verifySelection();
+
+        resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
+        verifySelection();
+
         scroll(CHILD_VIEW_EDGE_PX);
-        assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25);
+        verifySelection();
+
         scroll(-2 * CHILD_VIEW_EDGE_PX);
-        assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17);
-        model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
-        assertSelected(0, 4, 8, 12, 16);
+        verifySelection();
+
+        resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+        verifySelection();
+
         assertEquals(0, model.getPositionNearestOrigin());
     }
 
-    private void assertSelected(int... selectedPositions) {
-        assertEquals(selectedPositions.length, lastSelection.size());
-        for (int position : selectedPositions) {
-            assertTrue(lastSelection.contains(Integer.toString(position)));
+    /** Returns the current selection area as a Rect. */
+    private Rect getSelectionArea() {
+        // Construct a rect from the two selection points.
+        Rect selectionArea = new Rect(
+                mSelectionOrigin.x, mSelectionOrigin.y, mSelectionOrigin.x, mSelectionOrigin.y);
+        selectionArea.union(mSelectionPoint.x, mSelectionPoint.y);
+        // Rect intersection tests are exclusive of bounds, while the MSM's selection code is
+        // inclusive. Expand the rect by 1 pixel in all directions to account for this.
+        selectionArea.inset(-1, -1);
+
+        return selectionArea;
+    }
+
+    /** Asserts that the selection is currently empty. */
+    private void assertNoSelection() {
+        assertEquals("Unexpected items " + lastSelection + " in selection " + getSelectionArea(),
+                0, lastSelection.size());
+    }
+
+    /** Verifies the selection using actual bbox checks. */
+    private void verifySelection() {
+        Rect selectionArea = getSelectionArea();
+        for (TestEnvironment.Item item: env.items) {
+            if (Rect.intersects(selectionArea, item.rect)) {
+                assertTrue("Expected item " + item + " was not in selection " + selectionArea,
+                        lastSelection.contains(item.name));
+            } else {
+                assertFalse("Unexpected item " + item + " in selection" + selectionArea,
+                        lastSelection.contains(item.name));
+            }
         }
     }
 
+    private void startSelection(Point p) {
+        model.startSelection(p);
+        mSelectionOrigin = env.createAbsolutePoint(p);
+    }
+
+    private void resizeSelection(Point p) {
+        model.resizeSelection(p);
+        mSelectionPoint = env.createAbsolutePoint(p);
+    }
+
     private void scroll(int dy) {
         assertTrue(env.verticalOffset + VIEWPORT_HEIGHT + dy <= env.getTotalHeight());
         env.verticalOffset += dy;
+        // Correct the cached selection point as well.
+        mSelectionPoint.y += dy;
         model.onScrolled(null, 0, dy);
     }
 
     private static final class TestEnvironment implements MultiSelectManager.SelectionEnvironment {
 
-        public int horizontalOffset = 0;
-        public int verticalOffset = 0;
         private final int mNumColumns;
         private final int mNumRows;
         private final int mNumChildren;
+        private final int mSeparatorPosition;
+
+        public int horizontalOffset = 0;
+        public int verticalOffset = 0;
+        private List<Item> items = new ArrayList<>();
 
         public TestEnvironment(int numChildren, int numColumns) {
             mNumChildren = numChildren;
             mNumColumns = numColumns;
-            mNumRows = (int) Math.ceil((double) numChildren / mNumColumns);
+            mSeparatorPosition = mNumColumns + 1;
+            mNumRows = setupGrid();
+        }
+
+        private int setupGrid() {
+            // Split the input set into folders and documents. Do this such that there is a
+            // partially-populated row in the middle of the grid, to test corner cases in layout
+            // code.
+            int y = VIEW_PADDING_PX;
+            int i = 0;
+            int numRows = 0;
+            while (i < mNumChildren) {
+                int top = y;
+                int height = CHILD_VIEW_EDGE_PX;
+                int width = CHILD_VIEW_EDGE_PX;
+                for (int j = 0; j < mNumColumns && i < mNumChildren; j++) {
+                    int left = VIEW_PADDING_PX + (j * (width + VIEW_PADDING_PX));
+                    items.add(new Item(
+                            Integer.toString(i),
+                            new Rect(
+                                    left,
+                                    top,
+                                    left + width - 1,
+                                    top + height - 1)));
+
+                    // Create a partially populated row at the separator position.
+                    if (++i == mSeparatorPosition) {
+                        break;
+                    }
+                }
+                y += height + VIEW_PADDING_PX;
+                numRows++;
+            }
+
+            return numRows;
         }
 
         private int getTotalHeight() {
@@ -227,8 +341,16 @@
 
         private int getNumItemsInRow(int index) {
             assertTrue(index >= 0 && index < mNumRows);
-            if (index == mNumRows - 1 && mNumChildren % mNumColumns != 0) {
-                return mNumChildren % mNumColumns;
+            int mod = mSeparatorPosition % mNumColumns;
+            if (index == (mSeparatorPosition / mNumColumns)) {
+                // The row containing the separator may be incomplete
+                return mod > 0 ? mod : mNumColumns;
+            }
+            // Account for the partial separator row in the final row tally.
+            if (index == mNumRows - 1) {
+                // The last row may be incomplete
+                int finalRowCount = (mNumChildren - mod) % mNumColumns;
+                return finalRowCount > 0 ? finalRowCount : mNumColumns;
             }
 
             return mNumColumns;
@@ -257,21 +379,18 @@
 
         @Override
         public int getAdapterPositionAt(int index) {
-            return index + mNumColumns * (getFirstVisibleRowIndex());
+            // Account for partial rows by actually tallying up the items in hidden rows.
+            int hiddenCount = 0;
+            for (int i = 0; i < getFirstVisibleRowIndex(); i++) {
+                hiddenCount += getNumItemsInRow(i);
+            }
+            return index + hiddenCount;
         }
 
         @Override
         public Rect getAbsoluteRectForChildViewAt(int index) {
-            int adapterPosition = (getFirstVisibleRowIndex() * mNumColumns) + index;
-            int rowIndex = adapterPosition / mNumColumns;
-            int columnIndex = adapterPosition % mNumColumns;
-
-            Rect rect = new Rect();
-            rect.top = VIEW_PADDING_PX + rowIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
-            rect.bottom = rect.top + CHILD_VIEW_EDGE_PX - 1;
-            rect.left = VIEW_PADDING_PX + columnIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
-            rect.right = rect.left + CHILD_VIEW_EDGE_PX - 1;
-            return rect;
+            int adapterPosition = getAdapterPositionAt(index);
+            return items.get(adapterPosition).rect;
         }
 
         @Override
@@ -285,11 +404,6 @@
         }
 
         @Override
-        public int getRowCount() {
-            return mNumRows;
-        }
-
-        @Override
         public void showBand(Rect rect) {
             throw new UnsupportedOperationException();
         }
@@ -328,5 +442,19 @@
         public boolean isLayoutItem(int adapterPosition) {
             return false;
         }
+
+        public static final class Item {
+            public String name;
+            public Rect rect;
+
+            public Item(String n, Rect r) {
+                name = n;
+                rect = r;
+            }
+
+            public String toString() {
+                return name + ": " + rect;
+            }
+        }
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
index 267f47d..e170dbb 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -61,11 +61,6 @@
     }
 
     @Override
-    void unhide(SparseArray<String> ids) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         throw new UnsupportedOperationException();
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
index d8c29db..2d819ff 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
@@ -62,9 +62,7 @@
         update(r);
     }
 
-    // Note that model id includes authority qualifier and is distinct
-    // WRT documentId because of this.
     String idForPosition(int p) {
-        return createModelId(mAuthority, Integer.toString(p));
+        return Integer.toString(p);
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
index 8e624a0..56e54a6 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
@@ -87,11 +87,6 @@
     }
 
     @Override
-    public int getRowCount() {
-        return 0;
-    }
-
-    @Override
     public int getChildCount() {
         return 0;
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
index 543396e..bb7c01a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
@@ -16,6 +16,10 @@
 
 package com.android.documentsui.services;
 
+import static com.google.common.collect.Lists.newArrayList;
+
+import android.net.Uri;
+import android.provider.DocumentsContract.Document;
 import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.documentsui.model.DocumentInfo;
@@ -38,6 +42,21 @@
         runCopyVirtualNonTypedFileTest();
     }
 
+    public void testCopy_BackendSideVirtualTypedFile_Fallback() throws Exception {
+        mDocs.assertChildCount(mDestRoot, 0);
+
+        Uri testFile = mDocs.createDocumentWithFlags(
+                mSrcRoot.documentId, "virtual/mime-type", "tokyo.sth",
+                Document.FLAG_VIRTUAL_DOCUMENT | Document.FLAG_SUPPORTS_COPY
+                        | Document.FLAG_SUPPORTS_MOVE, "application/pdf");
+
+        createJob(newArrayList(testFile)).run();
+
+        mJobListener.waitForFinished();
+        mDocs.assertChildCount(mDestRoot, 1);
+        mDocs.assertHasFile(mDestRoot, "tokyo.sth.pdf");  // Copy should convert file to PDF.
+    }
+
     public void testCopyEmptyDir() throws Exception {
         runCopyEmptyDirTest();
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
index 749264a..24181d6 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
@@ -59,6 +59,21 @@
         mDocs.assertChildCount(mSrcRoot, 1);
     }
 
+    public void testMove_BackendSideVirtualTypedFile_Fallback() throws Exception {
+        Uri testFile = mDocs.createDocumentWithFlags(
+                mSrcRoot.documentId, "virtual/mime-type", "tokyo.sth",
+                Document.FLAG_VIRTUAL_DOCUMENT | Document.FLAG_SUPPORTS_COPY
+                        | Document.FLAG_SUPPORTS_MOVE, "application/pdf");
+
+        createJob(newArrayList(testFile)).run();
+        mJobListener.waitForFinished();
+
+        // Should have failed, source not deleted. Moving by bytes for virtual files
+        // is not supported.
+        mDocs.assertChildCount(mDestRoot, 0);
+        mDocs.assertChildCount(mSrcRoot, 1);
+    }
+
     public void testMoveEmptyDir() throws Exception {
         runCopyEmptyDirTest();
 
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
index a1c6dab..9147a57 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
@@ -21,7 +21,6 @@
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.content.Context;
-import android.os.RemoteException;
 
 import com.android.documentsui.R;
 import com.android.documentsui.model.DocumentInfo;
@@ -38,7 +37,7 @@
     }
 
     @Override
-    void start() throws RemoteException {
+    void start() {
         mStarted = true;
     }
 
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 100b35c..c2ca998 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -15,18 +15,27 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     package="android.ext.services"
     android:versionCode="1"
     android:versionName="1"
     coreApp="true">
 
     <application android:label="@string/app_name"
-        android:allowBackup="false"
-        android:forceDeviceEncrypted="true"
-        android:encryptionAware="true">
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
 
         <library android:name="android.ext.services"/>
 
+        <service android:name=".notification.Ranker"
+                android:label="@string/notification_ranker"
+                android:permission="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
+                android:exported="true">
+            <intent-filter>
+                <action android:name="android.service.notification.NotificationRankerService" />
+            </intent-filter>
+        </service>
+
     </application>
 
 </manifest>
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index 531e517..0763403 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -16,4 +16,5 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name">Android Services Library</string>
+    <string name="notification_ranker">Android Notification Ranking Service</string>
 </resources>
diff --git a/packages/ExtServices/src/android/ext/services/notification/Ranker.java b/packages/ExtServices/src/android/ext/services/notification/Ranker.java
new file mode 100644
index 0000000..0b2b1a4
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/notification/Ranker.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ext.services.notification;
+
+import android.service.notification.NotificationRankerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+/**
+ * Class that provides an updatable ranker module for the notification manager..
+ */
+public final class Ranker extends NotificationRankerService {
+    private static final String TAG = "RocketRanker";
+    private static final boolean DEBUG =  Log.isLoggable(TAG, Log.DEBUG);;
+
+    @Override
+    public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance,
+            boolean user) {
+        if (DEBUG) Log.i(TAG, "ENQUEUED " + sbn.getKey());
+        return null;
+    }
+
+    @Override
+    public void onNotificationPosted(StatusBarNotification sbn) {
+        if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey());
+    }
+
+    @Override
+    public void onListenerConnected() {
+        if (DEBUG) Log.i(TAG, "CONNECTED");
+    }
+}
\ No newline at end of file
diff --git a/packages/ExtShared/AndroidManifest.xml b/packages/ExtShared/AndroidManifest.xml
index e2e81d0..04d865e 100644
--- a/packages/ExtShared/AndroidManifest.xml
+++ b/packages/ExtShared/AndroidManifest.xml
@@ -22,8 +22,8 @@
 
     <application android:label="@string/app_name"
         android:allowBackup="false"
-        android:forceDeviceEncrypted="true"
-        android:encryptionAware="true">
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
 
         <library android:name="android.ext.shared"/>
 
diff --git a/packages/ExternalStorageProvider/res/values-af/strings.xml b/packages/ExternalStorageProvider/res/values-af/strings.xml
index b5a159d..1de881d 100644
--- a/packages/ExternalStorageProvider/res/values-af/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-af/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Eksterne berging"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Interne berging"</string>
-    <string name="root_home" msgid="7931555396767513359">"Tuis"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-am/strings.xml b/packages/ExternalStorageProvider/res/values-am/strings.xml
index f4f296d..230fb06 100644
--- a/packages/ExternalStorageProvider/res/values-am/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-am/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ውጫዊ ማከማቻ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"ውስጣዊ ማከማቻ"</string>
-    <string name="root_home" msgid="7931555396767513359">"መነሻ"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ሰነዶች"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ar/strings.xml b/packages/ExternalStorageProvider/res/values-ar/strings.xml
index 4eee3e8..b20a056 100644
--- a/packages/ExternalStorageProvider/res/values-ar/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ar/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"وحدة تخزين خارجية"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"وحدة تخزين داخلية"</string>
-    <string name="root_home" msgid="7931555396767513359">"الرئيسية"</string>
+    <string name="root_documents" msgid="4051252304075469250">"مستندات"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml b/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml
index f7e5f8b..cd5ba2f 100644
--- a/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Xarici Yaddaş"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Daxili yaddaş"</string>
-    <string name="root_home" msgid="7931555396767513359">"Əsas səhifə"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Sənədlər"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml b/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
index b280d4f..fefbc28 100644
--- a/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Spoljna memorija"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Interna memorija"</string>
-    <string name="root_home" msgid="7931555396767513359">"Početni"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-be-rBY/strings.xml b/packages/ExternalStorageProvider/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..526bc39
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/values-be-rBY/strings.xml
@@ -0,0 +1,22 @@
+<?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.
+ -->
+
+<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">"Вонкавае сховішча"</string>
+    <string name="root_internal_storage" msgid="827844243068584127">"Унутранае сховішча"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Дакументы"</string>
+</resources>
diff --git a/packages/ExternalStorageProvider/res/values-bg/strings.xml b/packages/ExternalStorageProvider/res/values-bg/strings.xml
index 7081b17..f5dce31 100644
--- a/packages/ExternalStorageProvider/res/values-bg/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-bg/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Външно хранилище"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Вътрешно хранилище"</string>
-    <string name="root_home" msgid="7931555396767513359">"Начална директория"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml b/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml
index 842aed4..3668065 100644
--- a/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"বাহ্যিক সঞ্চয়স্থান"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"অভ্যন্তরীণ সঞ্চয়স্থান"</string>
-    <string name="root_home" msgid="7931555396767513359">"হোম"</string>
+    <string name="root_documents" msgid="4051252304075469250">"দস্তাবেজগুলি"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-bs-rBA/strings.xml b/packages/ExternalStorageProvider/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..20177f0
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/values-bs-rBA/strings.xml
@@ -0,0 +1,22 @@
+<?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.
+ -->
+
+<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">"Aplikacija za vanjsku pohranu"</string>
+    <string name="root_internal_storage" msgid="827844243068584127">"Interna pohrana"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
+</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ca/strings.xml b/packages/ExternalStorageProvider/res/values-ca/strings.xml
index b3fd9f7..15e9d46 100644
--- a/packages/ExternalStorageProvider/res/values-ca/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ca/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Emmagatzematge extern"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Emmagatzematge intern"</string>
-    <string name="root_home" msgid="7931555396767513359">"Inici"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-cs/strings.xml b/packages/ExternalStorageProvider/res/values-cs/strings.xml
index 2eab596..b68a928 100644
--- a/packages/ExternalStorageProvider/res/values-cs/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-cs/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Externí úložiště"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Interní úložiště"</string>
-    <string name="root_home" msgid="7931555396767513359">"Výchozí adresář"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-da/strings.xml b/packages/ExternalStorageProvider/res/values-da/strings.xml
index d008f0e..dc565ae 100644
--- a/packages/ExternalStorageProvider/res/values-da/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-da/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Ekstern lagerplads"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Intern lagerplads"</string>
-    <string name="root_home" msgid="7931555396767513359">"Hjem"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-de/strings.xml b/packages/ExternalStorageProvider/res/values-de/strings.xml
index 50fc680..318634a 100644
--- a/packages/ExternalStorageProvider/res/values-de/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-de/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Externer Speicher"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Interner Speicher"</string>
-    <string name="root_home" msgid="7931555396767513359">"Zuhause"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-el/strings.xml b/packages/ExternalStorageProvider/res/values-el/strings.xml
index 9537afd..b3aa792 100644
--- a/packages/ExternalStorageProvider/res/values-el/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-el/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Εξωτερικός αποθηκευτικός χώρος"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Εσωτερικός αποθηκευτικός χώρος"</string>
-    <string name="root_home" msgid="7931555396767513359">"Αρχική οθόνη"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Έγγραφα"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml b/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml
index be7aebc..f88eb9e 100644
--- a/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"External Storage"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
-    <string name="root_home" msgid="7931555396767513359">"Home"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
index be7aebc..f88eb9e 100644
--- a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"External Storage"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
-    <string name="root_home" msgid="7931555396767513359">"Home"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
index be7aebc..f88eb9e 100644
--- a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"External Storage"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
-    <string name="root_home" msgid="7931555396767513359">"Home"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
index 64a042d..e7e38b5 100644
--- a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
-    <string name="root_home" msgid="7931555396767513359">"Casa"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-es/strings.xml b/packages/ExternalStorageProvider/res/values-es/strings.xml
index d59755e..e7e38b5 100644
--- a/packages/ExternalStorageProvider/res/values-es/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
-    <string name="root_home" msgid="7931555396767513359">"Inicio"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
index 7ea2caa..6824e9d 100644
--- a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Väline talletusruum"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Sisemine salvestusruum"</string>
-    <string name="root_home" msgid="7931555396767513359">"Kodu"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumendid"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml b/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml
index 2f94acb..5881bf2 100644
--- a/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Kanpoko memoria"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Barneko memoria"</string>
-    <string name="root_home" msgid="7931555396767513359">"Etxea"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumentuak"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-fa/strings.xml b/packages/ExternalStorageProvider/res/values-fa/strings.xml
index c8c49a5..9ae8a47 100644
--- a/packages/ExternalStorageProvider/res/values-fa/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fa/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"حافظه خارجی"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"حافظهٔ داخلی"</string>
-    <string name="root_home" msgid="7931555396767513359">"صفحه اصلی"</string>
+    <string name="root_documents" msgid="4051252304075469250">"اسناد"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-fi/strings.xml b/packages/ExternalStorageProvider/res/values-fi/strings.xml
index 660228a..9d1fbaa 100644
--- a/packages/ExternalStorageProvider/res/values-fi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fi/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Ulkoinen tallennustila"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Sisäinen tallennustila"</string>
-    <string name="root_home" msgid="7931555396767513359">"Koti"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumentit"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
index b94682f..b3fdd48 100644
--- a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
-    <string name="root_home" msgid="7931555396767513359">"Accueil"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr/strings.xml b/packages/ExternalStorageProvider/res/values-fr/strings.xml
index 6a84bb4..b3fdd48 100644
--- a/packages/ExternalStorageProvider/res/values-fr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
-    <string name="root_home" msgid="7931555396767513359">"Répertoire de base"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml b/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml
index d51eae9..780213f 100644
--- a/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Almacenamento externo"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Almacenamento interno"</string>
-    <string name="root_home" msgid="7931555396767513359">"Inicio"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml
index 3bcc72d..ec8a0bd 100644
--- a/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"બાહ્ય સંગ્રહ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"આંતરિક સંગ્રહ"</string>
-    <string name="root_home" msgid="7931555396767513359">"હોમ"</string>
+    <string name="root_documents" msgid="4051252304075469250">"દસ્તાવેજો"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-hi/strings.xml b/packages/ExternalStorageProvider/res/values-hi/strings.xml
index 93cc712..8538081 100644
--- a/packages/ExternalStorageProvider/res/values-hi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hi/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"बाहरी मेमोरी"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"मोबाइल मेमोरी"</string>
-    <string name="root_home" msgid="7931555396767513359">"होम"</string>
+    <string name="root_documents" msgid="4051252304075469250">"दस्तावेज़"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-hr/strings.xml b/packages/ExternalStorageProvider/res/values-hr/strings.xml
index c866351..a74f8e8 100644
--- a/packages/ExternalStorageProvider/res/values-hr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hr/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Vanjska pohrana"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Unutarnja pohrana"</string>
-    <string name="root_home" msgid="7931555396767513359">"Početna"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-hu/strings.xml b/packages/ExternalStorageProvider/res/values-hu/strings.xml
index db1c7db..3f72b41 100644
--- a/packages/ExternalStorageProvider/res/values-hu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hu/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Külső tárhely"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Belső tárhely"</string>
-    <string name="root_home" msgid="7931555396767513359">"Otthon"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumentumok"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
index 0e1de49..5360124 100644
--- a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Արտաքին պահոց"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Ներքին պահոց"</string>
-    <string name="root_home" msgid="7931555396767513359">"Գլխավոր էջ"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Փաստաթղթեր"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-in/strings.xml b/packages/ExternalStorageProvider/res/values-in/strings.xml
index ca7f823..42acde7 100644
--- a/packages/ExternalStorageProvider/res/values-in/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-in/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Penyimpanan Eksternal"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Penyimpanan internal"</string>
-    <string name="root_home" msgid="7931555396767513359">"Rumah"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumen"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml b/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml
index ad04002..0306165 100644
--- a/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Ytri geymsla"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Innbyggð geymsla"</string>
-    <string name="root_home" msgid="7931555396767513359">"Heim"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Skjöl"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-it/strings.xml b/packages/ExternalStorageProvider/res/values-it/strings.xml
index 686ee1a..957b5ff 100644
--- a/packages/ExternalStorageProvider/res/values-it/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-it/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Archivio esterno"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Memoria interna"</string>
-    <string name="root_home" msgid="7931555396767513359">"Home"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documenti"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-iw/strings.xml b/packages/ExternalStorageProvider/res/values-iw/strings.xml
index b45fb5c..775506a 100644
--- a/packages/ExternalStorageProvider/res/values-iw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-iw/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"אחסון חיצוני"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"אחסון פנימי"</string>
-    <string name="root_home" msgid="7931555396767513359">"דף הבית"</string>
+    <string name="root_documents" msgid="4051252304075469250">"מסמכים"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ja/strings.xml b/packages/ExternalStorageProvider/res/values-ja/strings.xml
index 5c09bf4..188fca2 100644
--- a/packages/ExternalStorageProvider/res/values-ja/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ja/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"外部ストレージ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"内部ストレージ"</string>
-    <string name="root_home" msgid="7931555396767513359">"ホーム"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ドキュメント"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
index c1bc5c7..cc04860 100644
--- a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"გარე მეხსიერება"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"შიდა მეხსიერება"</string>
-    <string name="root_home" msgid="7931555396767513359">"მთავარი"</string>
+    <string name="root_documents" msgid="4051252304075469250">"დოკუმენტები"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml b/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml
index cf05782..ad49036 100644
--- a/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Сыртқы жад"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Ішкі жад"</string>
-    <string name="root_home" msgid="7931555396767513359">"Негізгі бет"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Құжаттар"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
index a2e926f..9cf76d4 100644
--- a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ឧបករណ៍​​ផ្ទុក​ខាងក្រៅ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"ឧបករណ៍​ផ្ទុក​ខាង​ក្នុង"</string>
-    <string name="root_home" msgid="7931555396767513359">"ដើម"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ឯកសារ"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml
index 1f0cfbf..e32b1d3 100644
--- a/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆ"</string>
-    <string name="root_home" msgid="7931555396767513359">"ಮುಖಪುಟ"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ಡಾಕ್ಯುಮೆಂಟ್‌ಗಳು"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ko/strings.xml b/packages/ExternalStorageProvider/res/values-ko/strings.xml
index 365648d..849d37e 100644
--- a/packages/ExternalStorageProvider/res/values-ko/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ko/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"외부 저장소"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"내부 저장소"</string>
-    <string name="root_home" msgid="7931555396767513359">"홈"</string>
+    <string name="root_documents" msgid="4051252304075469250">"문서"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml b/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml
index 4a0f211..d3ccf7f1 100644
--- a/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Тышкы сактагыч"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Ички сактагыч"</string>
-    <string name="root_home" msgid="7931555396767513359">"Башкы бет"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Документтер"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
index 9de6519..cecd9f5 100644
--- a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍນອກ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍໃນ"</string>
-    <string name="root_home" msgid="7931555396767513359">"​ໜ້າຫຼັກ"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ເອ​ກະ​ສານ"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-lt/strings.xml b/packages/ExternalStorageProvider/res/values-lt/strings.xml
index 84ca2d4..240ea89 100644
--- a/packages/ExternalStorageProvider/res/values-lt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lt/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Išorinė atmintinė"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Vidinė atmintinė"</string>
-    <string name="root_home" msgid="7931555396767513359">"Pagrindinis katalogas"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumentai"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-lv/strings.xml b/packages/ExternalStorageProvider/res/values-lv/strings.xml
index 7eff0b9..d308fe8 100644
--- a/packages/ExternalStorageProvider/res/values-lv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lv/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Ārējā krātuve"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Iekšējā atmiņa"</string>
-    <string name="root_home" msgid="7931555396767513359">"Sākumdirektorijs"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml b/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml
index fe6b753..8943d23 100644
--- a/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Надворешна меморија"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Внатрешна меморија"</string>
-    <string name="root_home" msgid="7931555396767513359">"Почетна страница"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
index 5369ec9..08e6dae 100644
--- a/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ബാഹ്യ സ്റ്റോറേജ്"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"ആന്തരിക സ്റ്റോറേജ്"</string>
-    <string name="root_home" msgid="7931555396767513359">"വീട്"</string>
+    <string name="root_documents" msgid="4051252304075469250">"പ്രമാണങ്ങൾ"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
index 4604f32..3d7b7f7 100644
--- a/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Гадаад сан"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Дотоод сан"</string>
-    <string name="root_home" msgid="7931555396767513359">"Нүүр хуудас"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Документүүд"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml
index 1310b0e..a7e7fbb 100644
--- a/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"बाह्य संचयन"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"अंतर्गत संचयन"</string>
-    <string name="root_home" msgid="7931555396767513359">"निवास"</string>
+    <string name="root_documents" msgid="4051252304075469250">"दस्तऐवज"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
index 007a1be..cb4d736 100644
--- a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Storan Luaran"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Storan dalaman"</string>
-    <string name="root_home" msgid="7931555396767513359">"Rumah"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumen"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml b/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml
index 2df9a33..dc9d684 100644
--- a/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ပြင်ပသိုလှောင်ရာပစ္စည်း"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"စက်တွင်း သိုလှောင်ထားမှု"</string>
-    <string name="root_home" msgid="7931555396767513359">"ပင်မ"</string>
+    <string name="root_documents" msgid="4051252304075469250">"စာရွက်စာတန်းများ"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-nb/strings.xml b/packages/ExternalStorageProvider/res/values-nb/strings.xml
index 315d932..a9ecb69 100644
--- a/packages/ExternalStorageProvider/res/values-nb/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nb/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Ekstern lagring"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
-    <string name="root_home" msgid="7931555396767513359">"Hjem"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml b/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml
index 4a9a8cd..5294043 100644
--- a/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"बाह्य भण्डारण"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"आन्तरिक भण्डारण"</string>
-    <string name="root_home" msgid="7931555396767513359">"गृह"</string>
+    <string name="root_documents" msgid="4051252304075469250">"कागजातहरू"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-nl/strings.xml b/packages/ExternalStorageProvider/res/values-nl/strings.xml
index 0ae88ce..bde6166 100644
--- a/packages/ExternalStorageProvider/res/values-nl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nl/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Externe opslag"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Interne opslag"</string>
-    <string name="root_home" msgid="7931555396767513359">"Startscherm"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documenten"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml
index a805dd8..0e91589 100644
--- a/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ਬਾਹਰੀ ਸਟੋਰੇਜ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"ਅੰਦਰੂਨੀ ਸਟੋਰੇਜ"</string>
-    <string name="root_home" msgid="7931555396767513359">"ਘਰ"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ਦਸਤਾਵੇਜ਼"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-pl/strings.xml b/packages/ExternalStorageProvider/res/values-pl/strings.xml
index 66d83c7..6c5e7d7 100644
--- a/packages/ExternalStorageProvider/res/values-pl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pl/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Pamięć zewnętrzna"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Pamięć wewnętrzna"</string>
-    <string name="root_home" msgid="7931555396767513359">"Katalog domowy"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml
index 958eef4..77c89b8 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
-    <string name="root_home" msgid="7931555396767513359">"Página inicial"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
index c8865e1..77c89b8 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
-    <string name="root_home" msgid="7931555396767513359">"Casa"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt/strings.xml b/packages/ExternalStorageProvider/res/values-pt/strings.xml
index 958eef4..77c89b8 100644
--- a/packages/ExternalStorageProvider/res/values-pt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
-    <string name="root_home" msgid="7931555396767513359">"Página inicial"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ro/strings.xml b/packages/ExternalStorageProvider/res/values-ro/strings.xml
index 5bb4a7c..abd0b98 100644
--- a/packages/ExternalStorageProvider/res/values-ro/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ro/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Stocare externă"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Stocare internă"</string>
-    <string name="root_home" msgid="7931555396767513359">"Director principal"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Documente"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ru/strings.xml b/packages/ExternalStorageProvider/res/values-ru/strings.xml
index a651371..740272f 100644
--- a/packages/ExternalStorageProvider/res/values-ru/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ru/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Внешний накопитель"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Внутренний накопитель"</string>
-    <string name="root_home" msgid="7931555396767513359">"Мои файлы"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Документы"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml b/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml
index 5292403..15334bb 100644
--- a/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"බාහිර ආචයනය"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"අභ්‍යන්තර ආචයනය"</string>
-    <string name="root_home" msgid="7931555396767513359">"මුල් පිටුව"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ලේඛන"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sk/strings.xml b/packages/ExternalStorageProvider/res/values-sk/strings.xml
index 5157888..9be7b79 100644
--- a/packages/ExternalStorageProvider/res/values-sk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sk/strings.xml
@@ -18,5 +18,5 @@
     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_home" msgid="7931555396767513359">"Predvolený adresár"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sl/strings.xml b/packages/ExternalStorageProvider/res/values-sl/strings.xml
index dd2cc24..6ffa698 100644
--- a/packages/ExternalStorageProvider/res/values-sl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sl/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Zunanja shramba"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Notranja shramba"</string>
-    <string name="root_home" msgid="7931555396767513359">"Korenska mapa"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml b/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml
index 3aafd1c..dc346ea 100644
--- a/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Hapësirë e jashtme ruajtjeje"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Hapësira e brendshme ruajtëse"</string>
-    <string name="root_home" msgid="7931555396767513359">"Kreu"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sr/strings.xml b/packages/ExternalStorageProvider/res/values-sr/strings.xml
index 2d987ef..54238a4 100644
--- a/packages/ExternalStorageProvider/res/values-sr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sr/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Спољна меморија"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Интерна меморија"</string>
-    <string name="root_home" msgid="7931555396767513359">"Почетни"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sv/strings.xml b/packages/ExternalStorageProvider/res/values-sv/strings.xml
index bc4788a..6eac11e 100644
--- a/packages/ExternalStorageProvider/res/values-sv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sv/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Extern lagring"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
-    <string name="root_home" msgid="7931555396767513359">"Hem"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokument"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sw/strings.xml b/packages/ExternalStorageProvider/res/values-sw/strings.xml
index dcca92a..0d0e483 100644
--- a/packages/ExternalStorageProvider/res/values-sw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sw/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Hifadhi ya Nje"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Hifadhi ya ndani"</string>
-    <string name="root_home" msgid="7931555396767513359">"Mwanzo"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Hati"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml
index b859e7a..d7bafbc 100644
--- a/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"வெளிப்புறச் சேமிப்பிடம்"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"அகச் சேமிப்பிடம்"</string>
-    <string name="root_home" msgid="7931555396767513359">"முகப்பு"</string>
+    <string name="root_documents" msgid="4051252304075469250">"ஆவணங்கள்"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml
index 934877e..800d18e 100644
--- a/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"బాహ్య నిల్వ"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"అంతర్గత నిల్వ"</string>
-    <string name="root_home" msgid="7931555396767513359">"హోమ్"</string>
+    <string name="root_documents" msgid="4051252304075469250">"పత్రాలు"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-th/strings.xml b/packages/ExternalStorageProvider/res/values-th/strings.xml
index 957d6b7..796635e 100644
--- a/packages/ExternalStorageProvider/res/values-th/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-th/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"ที่จัดเก็บข้อมูลภายนอก"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"ที่จัดเก็บข้อมูลภายใน"</string>
-    <string name="root_home" msgid="7931555396767513359">"Home"</string>
+    <string name="root_documents" msgid="4051252304075469250">"เอกสาร"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-tl/strings.xml b/packages/ExternalStorageProvider/res/values-tl/strings.xml
index be7aebc..529cdc2 100644
--- a/packages/ExternalStorageProvider/res/values-tl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tl/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"External Storage"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
-    <string name="root_home" msgid="7931555396767513359">"Home"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Mga Dokumento"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-tr/strings.xml b/packages/ExternalStorageProvider/res/values-tr/strings.xml
index 2ce1411..d6bd52a 100644
--- a/packages/ExternalStorageProvider/res/values-tr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tr/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Harici Depolama"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Dahili depolama"</string>
-    <string name="root_home" msgid="7931555396767513359">"Ev"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Dokümanlar"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-uk/strings.xml b/packages/ExternalStorageProvider/res/values-uk/strings.xml
index 0033bca..b8206e0 100644
--- a/packages/ExternalStorageProvider/res/values-uk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-uk/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Зовнішня пам’ять"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Внутрішня пам’ять"</string>
-    <string name="root_home" msgid="7931555396767513359">"Головний екран"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml b/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml
index df46fb0..02454bc 100644
--- a/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"بیرونی اسٹوریج"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"داخلی اسٹوریج"</string>
-    <string name="root_home" msgid="7931555396767513359">"ہوم"</string>
+    <string name="root_documents" msgid="4051252304075469250">"دستاویزات"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml b/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml
index 069e137..07cc14c 100644
--- a/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Tashqi xotira"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Ichki xotira"</string>
-    <string name="root_home" msgid="7931555396767513359">"Mening fayllarim"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Hujjatlar"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-vi/strings.xml b/packages/ExternalStorageProvider/res/values-vi/strings.xml
index 39e9c6c..b171c93 100644
--- a/packages/ExternalStorageProvider/res/values-vi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-vi/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Bộ nhớ ngoài"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Bộ nhớ trong"</string>
-    <string name="root_home" msgid="7931555396767513359">"Nhà riêng"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Tài liệu"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
index ea20dce..7df77dd 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"外部存储设备"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"内部存储空间"</string>
-    <string name="root_home" msgid="7931555396767513359">"主目录"</string>
+    <string name="root_documents" msgid="4051252304075469250">"文档"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
index 27f1f0a..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
-    <string name="root_home" msgid="7931555396767513359">"主目錄"</string>
+    <string name="root_documents" msgid="4051252304075469250">"文件"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
index b2d764a..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
-    <string name="root_home" msgid="7931555396767513359">"主畫面"</string>
+    <string name="root_documents" msgid="4051252304075469250">"文件"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-zu/strings.xml b/packages/ExternalStorageProvider/res/values-zu/strings.xml
index 8a7c7df..4a0a845 100644
--- a/packages/ExternalStorageProvider/res/values-zu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zu/strings.xml
@@ -18,5 +18,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7123375275748530234">"Isitoreji sangaphandle"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Isitoreji sangaphakathi"</string>
-    <string name="root_home" msgid="7931555396767513359">"Ekhaya"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Amadokhumenti"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 97dfd47..62f33bf 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -34,6 +34,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelFileDescriptor.OnCloseListener;
 import android.os.UserHandle;
+import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.provider.DocumentsContract;
@@ -41,6 +42,7 @@
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
+import android.provider.Settings;
 import android.support.provider.DocumentArchiveHelper;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -62,6 +64,7 @@
 public class ExternalStorageProvider extends DocumentsProvider {
     private static final String TAG = "ExternalStorage";
 
+    private static final boolean DEBUG = false;
     private static final boolean LOG_INOTIFY = false;
 
     public static final String AUTHORITY = "com.android.externalstorage.documents";
@@ -136,10 +139,25 @@
             if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
                 // We currently only support a single emulated volume mounted at
                 // a time, and it's always considered the primary
+                if (DEBUG) Log.d(TAG, "Found primary volume: " + volume);
                 rootId = ROOT_ID_PRIMARY_EMULATED;
+
                 if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
-                    title = getContext().getString(R.string.root_internal_storage);
+                    // This is basically the user's primary device storage.
+                    // Use device name for the volume since this is likely same thing
+                    // the user sees when they mount their phone on another device.
+                    String deviceName = Settings.Global.getString(
+                            getContext().getContentResolver(), Settings.Global.DEVICE_NAME);
+
+                    // Device name should always be set. In case it isn't, though,
+                    // fall back to a localized "Internal Storage" string.
+                    title = !TextUtils.isEmpty(deviceName)
+                            ? deviceName
+                            : getContext().getString(R.string.root_internal_storage);
                 } else {
+                    // This should cover all other storage devices, like an SD card
+                    // or USB OTG drive plugged in. Using getBestVolumeDescription()
+                    // will give us a nice string like "Samsung SD card" or "SanDisk USB drive"
                     final VolumeInfo privateVol = mStorageManager.findPrivateForEmulated(volume);
                     title = mStorageManager.getBestVolumeDescription(privateVol);
                 }
@@ -167,6 +185,14 @@
             root.flags = Root.FLAG_LOCAL_ONLY
                     | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
 
+            final DiskInfo disk = volume.getDisk();
+            if (DEBUG) Log.d(TAG, "Disk for root " + rootId + " is " + disk);
+            if (disk != null && disk.isSd()) {
+                root.flags |= Root.FLAG_REMOVABLE_SD;
+            } else if (disk != null && disk.isUsb()) {
+                root.flags |= Root.FLAG_REMOVABLE_USB;
+            }
+
             if (volume.isPrimary()) {
                 // save off the primary volume for subsequent "Home" dir initialization.
                 primaryVolume = volume;
@@ -193,8 +219,9 @@
             }
         }
 
-        // Finally, if primary storage is available we add the "Home" directory,
-        // creating it as needed.
+        // Finally, if primary storage is available we add the "Documents" directory.
+        // If I recall correctly the actual directory is created on demand
+        // by calling either getPathForUser, or getInternalPathForUser.
         if (primaryVolume != null && primaryVolume.isVisible()) {
             final RootInfo root = new RootInfo();
             root.rootId = ROOT_ID_HOME;
@@ -211,8 +238,7 @@
                 root.flags |= Root.FLAG_SUPPORTS_CREATE;
             }
 
-            // Create the "Home" directory on disk, but don't the localized root.title
-            // since the directories shouldn't be localized.
+            // Create the "Documents" directory on disk (don't use the localized title).
             root.visiblePath = new File(
                     primaryVolume.getPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
             root.path = new File(
@@ -391,6 +417,10 @@
             if (mArchiveHelper.isArchivedDocument(docId)) {
                 return mArchiveHelper.isChildDocument(parentDocId, docId);
             }
+            // Archives do not contain regular files.
+            if (mArchiveHelper.isArchivedDocument(parentDocId)) {
+                return false;
+            }
 
             final File parent = getFileForDocId(parentDocId).getCanonicalFile();
             final File doc = getFileForDocId(docId).getCanonicalFile();
diff --git a/packages/FakeOemFeatures/AndroidManifest.xml b/packages/FakeOemFeatures/AndroidManifest.xml
index fe74ad8..a66521d 100644
--- a/packages/FakeOemFeatures/AndroidManifest.xml
+++ b/packages/FakeOemFeatures/AndroidManifest.xml
@@ -12,8 +12,8 @@
         android:allowBackup="false"
         android:hardwareAccelerated="true"
         android:label="Fake OEM Features"
-        android:forceDeviceEncrypted="true"
-        android:encryptionAware="true">
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
 
         <service android:name=".FakeCoreService" android:process=":core"
                 android:label="Fake OEM Core Service" />
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index ed84c0d..a8319ab 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -29,8 +29,8 @@
     <application
             android:label="@string/app_label"
             android:process="system"
-            android:forceDeviceEncrypted="true"
-            android:encryptionAware="true">
+            android:defaultToDeviceProtectedStorage="true"
+            android:directBootAware="true">
 
         <uses-library android:name="com.android.location.provider" />
 
diff --git a/packages/FusedLocation/res/values-be-rBY/strings.xml b/packages/FusedLocation/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..0d2cccc
--- /dev/null
+++ b/packages/FusedLocation/res/values-be-rBY/strings.xml
@@ -0,0 +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">"Fused Location"</string>
+</resources>
diff --git a/packages/FusedLocation/res/values-bs-rBA/strings.xml b/packages/FusedLocation/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..f21c87b
--- /dev/null
+++ b/packages/FusedLocation/res/values-bs-rBA/strings.xml
@@ -0,0 +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">"Kombinirana lokacija."</string>
+</resources>
diff --git a/packages/InputDevices/AndroidManifest.xml b/packages/InputDevices/AndroidManifest.xml
index 07885ea..9507c9f 100644
--- a/packages/InputDevices/AndroidManifest.xml
+++ b/packages/InputDevices/AndroidManifest.xml
@@ -7,8 +7,8 @@
             android:allowClearUserData="false"
             android:label="@string/app_label"
             android:process="system"
-            android:forceDeviceEncrypted="true"
-            android:encryptionAware="true">
+            android:defaultToDeviceProtectedStorage="true"
+            android:directBootAware="true">
 
         <receiver android:name=".InputDeviceReceiver"
                 android:label="@string/keyboard_layouts_label">
diff --git a/packages/InputDevices/res/values-be-rBY/strings.xml b/packages/InputDevices/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..7d7683c
--- /dev/null
+++ b/packages/InputDevices/res/values-be-rBY/strings.xml
@@ -0,0 +1,44 @@
+<?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="8016145283189546017">"Input Devices"</string>
+    <string name="keyboard_layouts_label" msgid="6688773268302087545">"Клавіятура Android"</string>
+    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Англійская (Злучанае Каралеўства)"</string>
+    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Англійская (ЗША)"</string>
+    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Англійская (ЗША), міжнар. раскладка"</string>
+    <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Англійская (ЗША), раскладка Colemak"</string>
+    <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Англійская (ЗША), раскладка Дворака"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Англійская (ЗША), раскладка Workman"</string>
+    <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Нямецкая"</string>
+    <string name="keyboard_layout_french_label" msgid="813450119589383723">"Французская"</string>
+    <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Французская (Канада)"</string>
+    <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"Руская"</string>
+    <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"Руская, раскладка Mac"</string>
+    <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"Іспанская"</string>
+    <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"Французская (Швейцарыя)"</string>
+    <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Нямецкая (Швейцарыя)"</string>
+    <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Бельгійская"</string>
+    <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Балгарская"</string>
+    <string name="keyboard_layout_italian" msgid="6497079660449781213">"Італьянская"</string>
+    <string name="keyboard_layout_danish" msgid="8036432066627127851">"Дацкая"</string>
+    <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Нарвежская"</string>
+    <string name="keyboard_layout_swedish" msgid="732959109088479351">"Шведская"</string>
+    <string name="keyboard_layout_finnish" msgid="5585659438924315466">"Фінская"</string>
+    <string name="keyboard_layout_croatian" msgid="4172229471079281138">"Харвацкая"</string>
+    <string name="keyboard_layout_czech" msgid="1349256901452975343">"Чэшская"</string>
+    <string name="keyboard_layout_estonian" msgid="8775830985185665274">"Эстонская"</string>
+    <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Венгерская"</string>
+    <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Ісландская"</string>
+    <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"Бразільская"</string>
+    <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"Партугальская"</string>
+    <string name="keyboard_layout_slovak" msgid="2469379934672837296">"Славацкая"</string>
+    <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>
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латышская"</string>
+</resources>
diff --git a/packages/InputDevices/res/values-bs-rBA/strings.xml b/packages/InputDevices/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..9672ae8
--- /dev/null
+++ b/packages/InputDevices/res/values-bs-rBA/strings.xml
@@ -0,0 +1,44 @@
+<?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="8016145283189546017">"Ulazni uređaji"</string>
+    <string name="keyboard_layouts_label" msgid="6688773268302087545">"Android tastatura"</string>
+    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"engleski (UK)"</string>
+    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"engleski (SAD)"</string>
+    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"engleski (SAD), međunarodni stil"</string>
+    <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"engleski (SAD), Colemak stil"</string>
+    <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"engleski (SAD), Dvorak stil"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engleski (SAD), Workman"</string>
+    <string name="keyboard_layout_german_label" msgid="8451565865467909999">"njemački"</string>
+    <string name="keyboard_layout_french_label" msgid="813450119589383723">"francuski"</string>
+    <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francuski (Kanada)"</string>
+    <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"ruski"</string>
+    <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"ruski, Mac stil"</string>
+    <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"španski"</string>
+    <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"švicarski francuski"</string>
+    <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švicarski njemački"</string>
+    <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijski"</string>
+    <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarski"</string>
+    <string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanski"</string>
+    <string name="keyboard_layout_danish" msgid="8036432066627127851">"danski"</string>
+    <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveški"</string>
+    <string name="keyboard_layout_swedish" msgid="732959109088479351">"švedski"</string>
+    <string name="keyboard_layout_finnish" msgid="5585659438924315466">"finski"</string>
+    <string name="keyboard_layout_croatian" msgid="4172229471079281138">"hrvatski"</string>
+    <string name="keyboard_layout_czech" msgid="1349256901452975343">"češki"</string>
+    <string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonski"</string>
+    <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"mađarski"</string>
+    <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandski"</string>
+    <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"brazilski"</string>
+    <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"portugalski"</string>
+    <string name="keyboard_layout_slovak" msgid="2469379934672837296">"slovački"</string>
+    <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenački"</string>
+    <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turski"</string>
+    <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinski"</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">"litvanski"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španski (Latinska Amerika)"</string>
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvijski"</string>
+</resources>
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 54972b4..165fe05 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -46,8 +46,8 @@
         android:process="com.android.systemui"
         android:persistent="true"
         android:supportsRtl="true"
-        android:forceDeviceEncrypted="true"
-        android:encryptionAware="true">
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
 
     </application>
 </manifest>
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index 1db5f61..8ad4c5e 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK-bewerking het misluk!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode is aanvaar!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen diens nie."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Wissel invoermetode"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Vliegtuigmodus"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Patroon word vereis nadat toestel herbegin het"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN word vereis nadat toestel herbegin het"</string>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 2b19d7a..0425622 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"የሲም PUK ክወና አልተሳካም!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ኮዱ ተቀባይነት አግኝቷል!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ከአገልግሎት መስጫ ክልል ውጪ።"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"የግቤት ስልት ቀይር"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"የአውሮፕላን ሁነታ"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"መሣሪያ ዳግም ከጀመረ በኋላ ሥርዓተ ጥለት ያስፈልጋል"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"መሣሪያ ዳግም ከጀመረ በኋላ ፒን ያስፈልጋል"</string>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index efaad1f..442f29e 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -116,7 +116,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏أخفقت عملية PUK لبطاقة SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"تم قبول الرمز!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"لا تتوفر خدمة"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"تبديل أسلوب الإدخال"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"وضع الطائرة"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"يجب رسم النقش بعد إعادة تشغيل الجهاز."</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"يجب إدخال رقم التعريف الشخصي بعد إعادة تشغيل الجهاز."</string>
diff --git a/packages/Keyguard/res/values-az-rAZ/strings.xml b/packages/Keyguard/res/values-az-rAZ/strings.xml
index 4450c01..686024b 100644
--- a/packages/Keyguard/res/values-az-rAZ/strings.xml
+++ b/packages/Keyguard/res/values-az-rAZ/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK əməliyyatı alınmadı!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Qəbul Edildi!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Xidmət yoxdur."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Daxiletmə metodu düyməsinə keç"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Daxiletmə metoduna keçin"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Təyyarə rejimi"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Cihaz yeniden başladıqdan sonra qəlib kod tələb olunur"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Cihaz yeniden başladıqdan sonra PIN tələb olunur"</string>
diff --git a/packages/Keyguard/res/values-b+sr+Latn/strings.xml b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
index 0eb4210..a0af289 100644
--- a/packages/Keyguard/res/values-b+sr+Latn/strings.xml
+++ b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
@@ -110,7 +110,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Radnja sa SIM PUK kodom nije uspela!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kôd je prihvaćen!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Oflajn ste."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Dugme Promeni metod unosa."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Promeni metod unosa"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Režim rada u avionu"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Treba da unesete šablon kada se uređaj ponovo pokrene"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Treba da unesete PIN kada se uređaj ponovo pokrene"</string>
diff --git a/packages/Keyguard/res/values-be-rBY/strings.xml b/packages/Keyguard/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..59464bd
--- /dev/null
+++ b/packages/Keyguard/res/values-be-rBY/strings.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<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>
+    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Новы PIN-код SIM-карты"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Каб разблакаваць, увядзіце PIN-код"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Няправільны PIN-код."</string>
+    <string name="keyguard_charged" msgid="3272223906073492454">"Зараджаны"</string>
+    <string name="keyguard_plugged_in" msgid="9087497435553252863">"Зарадка"</string>
+    <string name="keyguard_plugged_in_charging_fast" msgid="6671162730167305479">"Зараджаецца хутка"</string>
+    <string name="keyguard_plugged_in_charging_slowly" msgid="1964714661071163229">"Зараджаецца павольна"</string>
+    <string name="keyguard_low_battery" msgid="8143808018719173859">"Падключыце зарадную прыладу."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Націсніце кнопку \"Меню\", каб разблакіраваць."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Сетка заблакiраваная"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Няма SIM-карты"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"У планшэце няма SIM-карты."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"У тэлефоне няма SIM-карты."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Устаўце SIM-карту."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM-карту немагчыма выкарыстоўваць."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Ваша SIM-карта была адключана назаўсёды.\n Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-карта заблакiраваная."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-карта заблакiравана PUK-кодам."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Разблакiраванне SIM-карты..."</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Узор разблакiроўкі."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-код разблакiроўкі."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Пароль разблакiроўкі."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Вобласць узора."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Вобласць слайда."</string>
+    <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Поле для PIN-кода"</string>
+    <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Поле для PIN-кода SIM-карты"</string>
+    <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Поле для PUK-кода SIM-карты"</string>
+    <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Наступны будзільнік пастаўлены на <xliff:g id="ALARM">%1$s</xliff:g>"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Выдаліць"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільна ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Няправiльны пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Няправільны PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйце ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Увядзіце PIN-код SIM-карты"</string>
+    <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Увядзіце PIN-код SIM-карты «<xliff:g id="CARRIER">%1$s</xliff:g>»"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Увядзіце PIN-код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Увядзіце пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-карта зараз адключана. Увядзіце PUK-код, каб працягнуць. Звяжыцеся са сваiм аператарам, каб атрымаць дадатковую iнфармацыю."</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"SIM-карта «<xliff:g id="CARRIER">%1$s</xliff:g>» зараз адключана. Увядзіце PUK-код, каб працягнуць. Каб атрымаць дадатковую iнфармацыю, звяжыцеся з аператарам."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Увядзіце жаданы PIN-код"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Пацвердзіце жадан PIN-код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблакiроўка SIM-карты..."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-код павінен утрымлiваць 8 лiчбаў і больш."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Паўторна увядзіце правільны PUK-код. Неаднаразовыя спробы назаўжды адключаць SIM-карту."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коды не супадаюць"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Занадта шмат спроб паўтарыць шаблон!"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэты прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэты прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Няправільны PIN-код SIM-карты, цяпер вы павінны звязацца з аператарам для разблакіроўкі прылады."</string>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Няправільны PIN-код SIM-карты, у вас засталася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
+      <item quantity="few">Няправільны PIN-код SIM-карты, у вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спробы.</item>
+      <item quantity="many">Няправільны PIN-код SIM-карты, у вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спроб.</item>
+      <item quantity="other">Няправільны PIN-код SIM-карты, у вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спробы.</item>
+    </plurals>
+    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-карта не прыдатная для выкарыстання. Звяжыцеся з аператарам."</string>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Няправільны PUK-код SIM-карты, у вас засталася <xliff:g id="NUMBER_1">%d</xliff:g> спроба перад тым, як SIM-карта перастане працаваць назаўжды.</item>
+      <item quantity="few">Няправільны PUK-код SIM-карты, у вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спробы перад тым, як SIM-карта перастане працаваць назаўжды.</item>
+      <item quantity="many">Няправільны PUK-код SIM-карты, у вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спроб перад тым, як SIM-карта перастане працаваць назаўжды.</item>
+      <item quantity="other">Няправільны PUK-код SIM-карты, у вас засталося <xliff:g id="NUMBER_1">%d</xliff:g> спробы перад тым, як SIM-карта перастане працаваць назаўжды.</item>
+    </plurals>
+    <string name="kg_password_pin_failed" msgid="6268288093558031564">"Разблакіраваць SIM-карту PIN-кодам не атрымалася!"</string>
+    <string name="kg_password_puk_failed" msgid="2838824369502455984">"Разблакіраваць SIM-карту PUK-кодам не атрымалася!"</string>
+    <string name="kg_pin_accepted" msgid="1448241673570020097">"Код прыняты!"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Не абслугоўваецца."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Пераключэнне рэжыму ўводу"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Рэжым палёту"</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Пасля перазапуску прылады патрабуецца ўзор"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Пасля перазапуску прылады патрабуецца PIN-код"</string>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Пасля перазапуску прылады патрабуецца пароль"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Для забеспячэння дадатковай бяспекі патрабуецца ўзор"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Для забеспячэння дадатковай бяспекі патрабуецца PIN-код"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Для забеспячэння дадатковай бяспекі патрабуецца пароль"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Пры пераключэнні профіляў патрабуецца ўзор"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Пры пераключэнні профіляў патрабуецца PIN-код"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Пры пераключэнні профіляў патрабуецца пароль"</string>
+    <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
+      <item quantity="one">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце ўзор.</item>
+      <item quantity="few">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце ўзор.</item>
+      <item quantity="many">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце ўзор.</item>
+      <item quantity="other">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце ўзор.</item>
+    </plurals>
+    <plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="2118758475374354849">
+      <item quantity="one">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце PIN-код.</item>
+      <item quantity="few">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце PIN-код.</item>
+      <item quantity="many">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце PIN-код.</item>
+      <item quantity="other">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце PIN-код.</item>
+    </plurals>
+    <plurals name="kg_prompt_reason_time_password" formatted="false" msgid="5132693663364913675">
+      <item quantity="one">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце пароль.</item>
+      <item quantity="few">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце пароль.</item>
+      <item quantity="many">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце пароль.</item>
+      <item quantity="other">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце пароль.</item>
+    </plurals>
+    <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Не распазнаны"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index ae95c49..9d4047a 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Операцията с PUK кода за SIM картата не бе успешна!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодът е приет!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Няма покритие."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Превключване на метода на въвеждане"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Самолетен режим"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"След рестартиране на устройството се изисква фигура"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"След рестартиране на устройството се изисква ПИН код"</string>
diff --git a/packages/Keyguard/res/values-bn-rBD/strings.xml b/packages/Keyguard/res/values-bn-rBD/strings.xml
index 1dd8af8..8b62687 100644
--- a/packages/Keyguard/res/values-bn-rBD/strings.xml
+++ b/packages/Keyguard/res/values-bn-rBD/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"সিম PUK ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"কোড স্বীকৃত হয়েছে!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"কোনো পরিষেবা নেই৷"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ইনপুট পদ্ধতির বোতাম পরিবর্তন করুন৷"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ইনপুট পদ্ধতি পাল্টান"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"বিমান মোড"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ডিভাইস পুনরায় আরম্ভ করার পর প্যাটার্নের প্রয়োজন হবে"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ডিভাইস পুনরায় আরম্ভ করার পর PIN এর প্রয়োজন হবে"</string>
diff --git a/packages/Keyguard/res/values-bs-rBA/strings.xml b/packages/Keyguard/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..fdf795c
--- /dev/null
+++ b/packages/Keyguard/res/values-bs-rBA/strings.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<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">"Čuvar tastature"</string>
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Unesite SIM PUK i novi PIN kôd"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK kôd"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Novi SIM PIN kôd"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dodirnite za unos lozinke"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Unesite lozinku za otključavanje tipkovnice"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje tipkovnice"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Pogrešan PIN."</string>
+    <string name="keyguard_charged" msgid="3272223906073492454">"Napunjeno"</string>
+    <string name="keyguard_plugged_in" msgid="9087497435553252863">"Punjenje"</string>
+    <string name="keyguard_plugged_in_charging_fast" msgid="6671162730167305479">"Brzo punjenje"</string>
+    <string name="keyguard_plugged_in_charging_slowly" msgid="1964714661071163229">"Sporo punjenje"</string>
+    <string name="keyguard_low_battery" msgid="8143808018719173859">"Povežite na punjač."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Pritisnite meni da otključate."</string>
+    <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Mreža je zaključana"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nema SIM kartice"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Nema SIM kartice u tabletu."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Nema SIM kartice u telefonu."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Umetnite SIM karticu."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM kartica nedostaje ili se ne može pročitati. Umetnite SIM karticu."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Neupotrebljiva SIM kartica."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Vaša SIM kartica je trajno onemogućena. \n Obratite se svom pružaocu bežičnih usluga za drugu SIM karticu."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kartica je zaključana."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kartica je zaključana PUK kodom."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Otključavanje SIM kartice…"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Otključavanje uzorkom."</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje pinom."</string>
+    <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje lozinkom."</string>
+    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Uzorak oblasti."</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast za pomjeranje klizača."</string>
+    <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Prostor za PIN"</string>
+    <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Prostor za SIM PIN"</string>
+    <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Prostor za SIM PUK"</string>
+    <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Naredni alarm je podešen za <xliff:g id="ALARM">%1$s</xliff:g>"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Potvrdi"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravili ste uzorak?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan uzorak"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Broj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte obrazac"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN za SIM"</string>
+    <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Unesite SIM PIN za \"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Unesite lozinku"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM je sada onemogućen. Unesite PUK kôd da nastavite. Obratite se operateru za detalje."</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"SIM operator \"<xliff:g id="CARRIER">%1$s</xliff:g>\" je sada isključen. Unesite PUK kôd da nastavite. Za više detalja obratite se operateru."</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Unesite željeni PIN kôd"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrdi željeni PIN kôd"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Otključavanje SIM kartice…"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Unesite PIN koji sadrži od 4 do 8 brojeva."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kôd treba da sadrži 8 brojeva ili više."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi se ne poklapaju"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja otključavanja pomoću uzorka"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Pogrešno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Pogrešno ste unijeli lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Pogrešno ste nacrtali uzorak <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, tablet će biti vraćen na fabričke postavke a svi podaci će biti izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, telefon će biti vraćen na fabričke postavke a svi podaci će biti izbrisani."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Tablet će sada biti vraćen na fabričke postavke a svi podaci će biti izbrisani."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Telefon će sada biti vraćen na fabričke postavke a svi podaci će biti izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će biti uklonjen a svi podaci korisnika bit će izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će biti uklonjen a svi podaci korisnika bit će izbrisani."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Korisnik će biti uklonjen a svi podaci korisnika bit će izbrisani."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Korisnik će biti uklonjen a svi podaci korisnika bit će izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, poslovni profil će biti uklonjen a svi podaci s profila bit će izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, poslovni profil će biti uklonjen a svi podaci s profila bit će izbrisani."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Poslovni profil će biti uklonjen a svi podaci s profila bit će izbrisani."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Poslovni profil će biti uklonjen a svi podaci s profila bit će izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate tablet pomoću e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate telefon pomoću e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Pogrešan PIN kôd za SIM. Morate obratiti svom operateru za otključavanje uređaja."</string>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">PIN kôd za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
+      <item quantity="few">PIN kôd za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+      <item quantity="other">PIN kôd za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+    </plurals>
+    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM je neupotrebljiv. Obratite se svom operateru."</string>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">PUK kôd za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj prije nego SIM kartica postane trajno neupotrebljiva.</item>
+      <item quantity="few">PUK kôd za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije nego SIM kartica postane trajno neupotrebljiva.</item>
+      <item quantity="other">PUK kôd za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije nego SIM kartica postane trajno neupotrebljiva.</item>
+    </plurals>
+    <string name="kg_password_pin_failed" msgid="6268288093558031564">"Korištenje PIN-a za SIM nije uspjelo!"</string>
+    <string name="kg_password_puk_failed" msgid="2838824369502455984">"Korištenje PUK-a za SIM nije uspjelo!"</string>
+    <string name="kg_pin_accepted" msgid="1448241673570020097">"Kôd je prihvaćen"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nema usluge."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Promijeni način unosa"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Način rada u avionu"</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Potreban je uzorak nakon ponovnog pokretanja uređaja"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Potreban je PIN nakon ponovnog pokretanja uređaja"</string>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Potrebna je lozinka nakon ponovnog pokretanja uređaja"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Uzorak je potreban radi dodatne sigurnosti"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN je potreban radi dodatne sigurnosti"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Lozinka je potrebna radi dodatne sigurnosti"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Potreban je uzorak nakon prelaska na drugi profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Potreban je PIN nakon prelaska na drugi profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Potrebna je lozinka nakon prelaska na drugi profil"</string>
+    <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
+      <item quantity="one">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite obrazac.</item>
+      <item quantity="few">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite obrazac.</item>
+      <item quantity="other">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite obrazac.</item>
+    </plurals>
+    <plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="2118758475374354849">
+      <item quantity="one">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite PIN.</item>
+      <item quantity="few">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite PIN.</item>
+      <item quantity="other">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite PIN.</item>
+    </plurals>
+    <plurals name="kg_prompt_reason_time_password" formatted="false" msgid="5132693663364913675">
+      <item quantity="one">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite lozinku.</item>
+      <item quantity="few">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite lozinku.</item>
+      <item quantity="other">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite lozinku.</item>
+    </plurals>
+    <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nije prepoznat"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index 70e9fd1..dc8b178 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Hi ha hagut un problema en l\'operació del PUK de la SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"S\'ha acceptat el codi."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sense servei."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Canvia el mètode d\'introducció"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Mode d\'avió"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Cal introduir el patró quan es reinicia el dispositiu"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Cal introduir el PIN quan es reinicia el dispositiu"</string>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 96944cf..cf1dd34 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operace pomocí kódu PUK SIM karty se nezdařila!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód byl přijat."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žádný signál."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Přepnout metodu zadávání"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Režim Letadlo"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Po restartování zařízení je vyžadováno gesto"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Po restartování zařízení je vyžadován kód PIN"</string>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index 5ce1ef0..0af41f5 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-koden til SIM-kortet blev afvist."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden blev accepteret."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen dækning."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Skift indtastningsmetode"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Flytilstand"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Du skal indtaste et mønster efter genstart af enheden"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Der skal indtaste en pinkode efter genstart af enheden"</string>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index f1fc198..269c5c0 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Fehler beim Entsperren mithilfe des PUK-Codes der SIM-Karte"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code akzeptiert"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Kein Dienst"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Eingabemethode wechseln"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Flugmodus"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Nach dem Neustart des Geräts ist die Eingabe des Musters erforderlich."</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Nach dem Neustart des Geräts ist die Eingabe der PIN erforderlich."</string>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 535bee8..be3b349 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Αποτυχία λειτουργίας κωδικού PUK κάρτας SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Αποδεκτός κωδικός!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Καμία υπηρεσία."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Εναλλαγή μεθόδου εισαγωγής"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Λειτουργία πτήσης"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Απαιτείται μοτίβο μετά την επανεκκίνηση της συσκευής"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Απαιτείται PIN μετά την επανεκκίνηση της συσκευής"</string>
diff --git a/packages/Keyguard/res/values-en-rAU/strings.xml b/packages/Keyguard/res/values-en-rAU/strings.xml
index 63b2137..e2af2d6 100644
--- a/packages/Keyguard/res/values-en-rAU/strings.xml
+++ b/packages/Keyguard/res/values-en-rAU/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK operation failed!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Switch input method"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Pattern required after device restarts"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN required after device restarts"</string>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index 63b2137..e2af2d6 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK operation failed!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Switch input method"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Pattern required after device restarts"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN required after device restarts"</string>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index 63b2137..e2af2d6 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK operation failed!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Switch input method"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Pattern required after device restarts"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN required after device restarts"</string>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index cf903eb..6a9b824 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Error al desbloquear la tarjeta SIM con el PUK"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Cambiar método de entrada"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modo de avión"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Se requiere el patrón después de reiniciar el dispositivo"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Se requiere el PIN después de reiniciar el dispositivo"</string>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index a131cc1..9861d26 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Error al intentar desbloquear la tarjeta SIM con el código PUK"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Cambiar método de introducción"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modo avión"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Debes introducir el patrón después de reiniciar el dispositivo"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Debes introducir el PIN después de reiniciar el dispositivo"</string>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index 47aadf0..0a62009 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-i PUK-koodi toiming ebaõnnestus."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kood on õige."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Vaheta sisestusmeetodit"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Lennukirežiim"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Pärast seadme taaskäivitamist tuleb sisestada muster"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Pärast seadme taaskäivitamist tuleb sisestada PIN-kood"</string>
diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml
index 1c834e9..351c05a 100644
--- a/packages/Keyguard/res/values-eu-rES/strings.xml
+++ b/packages/Keyguard/res/values-eu-rES/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM txartelaren PUK eragiketak huts egin du!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodea onartu da!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Zerbitzurik gabe."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Idazketa-metodoa aldatzeko botoia."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Aldatu idazketa-metodoa"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Hegaldi modua"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Eredua marraztu beharko duzu gailua berrabiarazten denean"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN kodea idatzi beharko duzu gailua berrabiarazten denean"</string>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index 166e0d9..b8a87a2 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏عملیات PUK سیم کارت ناموفق بود!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کد پذیرفته شد!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"خدماتی وجود ندارد."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"تغییر روش ورودی"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"حالت هواپیما"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"بعد از بازنشانی دستگاه باید الگو وارد شود"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"بعد از بازنشانی دستگاه باید پین وارد شود"</string>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index bba241e..a876351 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-kortin PUK-toiminto epäonnistui!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koodi hyväksytty!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ei yhteyttä."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Vaihda syöttötapaa."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Lentokonetila"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Kuvio vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN-koodi vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index 6b63e04..e0e06cf 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Le déverrouillage de la carte SIM par code PUK a échoué."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Changer de méthode d\'entrée"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Mode Avion"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Le motif est exigé après le redémarrage de l\'appareil"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Le NIP est exigé après le redémarrage de l\'appareil"</string>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index 73b9552..eff9e91 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Échec du déverrouillage à l\'aide de la clé PUK de la carte SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Changer le mode de saisie"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Mode Avion"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Veuillez saisir le schéma après le redémarrage de l\'appareil."</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Veuillez saisir le code d\'accès après le redémarrage de l\'appareil."</string>
diff --git a/packages/Keyguard/res/values-gl-rES/strings.xml b/packages/Keyguard/res/values-gl-rES/strings.xml
index 05767c9..b27cdad 100644
--- a/packages/Keyguard/res/values-gl-rES/strings.xml
+++ b/packages/Keyguard/res/values-gl-rES/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Erro ao tentar desbloquar a tarxeta SIM co código PUK."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Non hai servizo."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Cambiar o botón do método de entrada."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Cambiar de método de entrada"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modo avión"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"É necesario o padrón despois do reinicio do dispositivo"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"É necesario o PIN despois do reinicio do dispositivo"</string>
diff --git a/packages/Keyguard/res/values-gu-rIN/strings.xml b/packages/Keyguard/res/values-gu-rIN/strings.xml
index 1b346a2..169bf6e 100644
--- a/packages/Keyguard/res/values-gu-rIN/strings.xml
+++ b/packages/Keyguard/res/values-gu-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ઓપરેશન નિષ્ફળ થયું!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"કોડ સ્વીકાર્યો!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"કોઈ સેવા ."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ઇનપુટ પદ્ધતિ બટન સ્વિચ કરો."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ઇનપુટ પદ્ધતિ સ્વિચ કરો"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"એરપ્લેન મોડ"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ઉપકરણ પુનઃપ્રારંભ થાય તે પછી પેટર્ન જરૂરી છે"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ઉપકરણ પુનઃપ્રારંભ થાય તે પછી PIN જરૂરી છે"</string>
diff --git a/packages/Keyguard/res/values-h560dp/dimens.xml b/packages/Keyguard/res/values-h560dp/dimens.xml
index 1683113..469ce52 100644
--- a/packages/Keyguard/res/values-h560dp/dimens.xml
+++ b/packages/Keyguard/res/values-h560dp/dimens.xml
@@ -16,5 +16,5 @@
   -->
 
 <resources>
-    <dimen name="widget_big_font_size">96dp</dimen>
+    <dimen name="widget_big_font_size">84dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-h650dp/dimens.xml b/packages/Keyguard/res/values-h650dp/dimens.xml
index 1cd2162..cb89cb4 100644
--- a/packages/Keyguard/res/values-h650dp/dimens.xml
+++ b/packages/Keyguard/res/values-h650dp/dimens.xml
@@ -16,5 +16,5 @@
   -->
 
 <resources>
-    <dimen name="widget_big_font_size">100dp</dimen>
+    <dimen name="widget_big_font_size">88dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index 47aefab..dd9123b 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"सिम PUK की कार्यवाही विफल रही!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकार किया गया!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कोई सेवा नहीं."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"इनपुट पद्धति‍ बदलें"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"हवाई जहाज़ मोड"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"डिवाइस के पुनः प्रारंभ होने पर पैटर्न की आवश्यकता होती है"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"डिवाइस के पुनः प्रारंभ होने पर पिन की आवश्यकता होती है"</string>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index c65db7f..0f3b1ca 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -110,7 +110,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operacija PUK-a SIM kartice nije uspjela!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kôd je prihvaćen!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nema usluge."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Promjena načina unosa"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Način rada u zrakoplovu"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Nakon ponovnog pokretanja uređaja morate unijeti uzorak"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Nakon ponovnog pokretanja uređaja morate unijeti PIN"</string>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 104735d..7901698 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"A SIM kártya PUK-művelete sikertelen!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód elfogadva."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nincs szolgáltatás."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Beviteli mód váltása"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Repülős üzemmód"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Az eszköz újraindítását követően meg kell adni a mintát"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Az eszköz újraindítását követően meg kell adni a PIN-kódot"</string>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index 0c70508..e223cb9 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK գործողությունը ձախողվեց:"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Կոդն ընդունվեց:"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ծառայություն չկա:"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Փոխարկել մուտքագրման եղանակը"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Ինքնաթիռային ռեժիմ"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել նախշը"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել PIN կոդը"</string>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index b409646..7a5642e 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operasi PUK SIM gagal!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode Diterima!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tidak ada layanan."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Beralih metode masukan"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Mode pesawat"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Pola diperlukan setelah perangkat dimulai ulang"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN diperlukan setelah perangkat dimulai ulang"</string>
diff --git a/packages/Keyguard/res/values-is-rIS/strings.xml b/packages/Keyguard/res/values-is-rIS/strings.xml
index 53c33f0..cece780 100644
--- a/packages/Keyguard/res/values-is-rIS/strings.xml
+++ b/packages/Keyguard/res/values-is-rIS/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-aðgerð SIM-korts mistókst!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Númer samþykkt!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ekkert símasamband."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Hnappur til að skipta um innsláttaraðferð."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Skipta um innsláttaraðferð"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Flugstilling"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Mynsturs er krafist þegar tækið er endurræst"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN-númers er krafist þegar tækið er endurræst"</string>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index 6ede2f9..3473863 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operazione con PUK della SIM non riuscita."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Codice accettato."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nessun servizio."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Cambia metodo di immissione"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modalità aereo"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Sequenza obbligatoria dopo il riavvio del dispositivo"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN obbligatorio dopo il riavvio del dispositivo"</string>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index 43ff724..316fce7 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏פעולת קוד ה-PUK של כרטיס ה-SIM נכשלה!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"הקוד התקבל!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"אין קליטה."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"החלפת שיטת קלט"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"מצב טיסה"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"יש להזין את קו ביטול הנעילה לאחר הפעלה מחדש של המכשיר"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"‏יש להזין PIN לאחר הפעלה מחדש של המכשיר"</string>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index 503e18e..c44f2e1 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -32,7 +32,7 @@
     <string name="keyguard_charged" msgid="3272223906073492454">"充電完了"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"充電中"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="6671162730167305479">"急速充電中"</string>
-    <string name="keyguard_plugged_in_charging_slowly" msgid="1964714661071163229">"緩速充電中"</string>
+    <string name="keyguard_plugged_in_charging_slowly" msgid="1964714661071163229">"低速充電中"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"充電してください。"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"メニューからロックを解除できます。"</string>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"ネットワークがロックされました"</string>
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK操作に失敗しました。"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"コードが承認されました。"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"通信サービスはありません。"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"入力方法の切り替え"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"機内モード"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"端末の再起動後にパターンの入力が必要となります"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"端末の再起動後に PIN の入力が必要となります"</string>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index 2fdd668..3ceb80a 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ოპერაცია ჩაიშალა!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"კოდი მიღებულია!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"არ არის სერვისი."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"შეყვანის მეთოდის გადართვა"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"თვითმფრინავის რეჟიმი"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა ნიმუშის შეყვანა"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა PIN-კოდის შეყვანა"</string>
diff --git a/packages/Keyguard/res/values-kk-rKZ/strings.xml b/packages/Keyguard/res/values-kk-rKZ/strings.xml
index fd5cf93..517f4e9 100644
--- a/packages/Keyguard/res/values-kk-rKZ/strings.xml
+++ b/packages/Keyguard/res/values-kk-rKZ/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK жұмысы орындалмады!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код қабылданды!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Қызмет көрсетілмейді."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Енгізу әдісі түймесін ауыстыру."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Енгізу әдісін ауыстыру"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Ұшақ режимі"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Құрылғы қайта іске қосылғаннан кейін өрнекті енгізу қажет"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Құрылғы қайта іске қосылғаннан кейін PIN кодты енгізу қажет"</string>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index 2da8370..6afeadf 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"បាន​បរាជ័យ​ក្នុង​ការ​ប្រតិបត្តិ​​លេខ​កូដ PUK ស៊ីម!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"បាន​ទទួល​យក​លេខ​កូដ​!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មាន​សេវា​"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ប្ដូរ​វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"របៀបក្នុងយន្តហោះ"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"តម្រូវឲ្យប្រើលំនាំបន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"តម្រូវឲ្យបញ្ចូលកូដ PIN បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
diff --git a/packages/Keyguard/res/values-kn-rIN/strings.xml b/packages/Keyguard/res/values-kn-rIN/strings.xml
index 31deb66..7724ef7 100644
--- a/packages/Keyguard/res/values-kn-rIN/strings.xml
+++ b/packages/Keyguard/res/values-kn-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"ಸಿಮ್‌ PUK ಕಾರ್ಯಾಚರಣೆ ವಿಫಲಗೊಂಡಿದೆ!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ಕೋಡ್ ಅಂಗೀಕೃತವಾಗಿದೆ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ಯಾವುದೇ ಸೇವೆಯಿಲ್ಲ."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ಇನ್‌ಪುಟ್ ವಿಧಾನ ಬದಲಿಸು ಬಟನ್."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ಇನ್‌ಪುಟ್‌‌ ವಿಧಾನ ಬದಲಿಸಿ"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index 67d6acb..a4860ce 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK 작업이 실패했습니다."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"코드 승인 완료"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"서비스 불가"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"입력 방법 전환"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"비행기 모드"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"기기가 다시 시작되면 패턴이 필요합니다."</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"기기가 다시 시작되면 PIN이 필요합니다."</string>
diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml
index 5403c71..098d5a2 100644
--- a/packages/Keyguard/res/values-ky-rKG/strings.xml
+++ b/packages/Keyguard/res/values-ky-rKG/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-картанын PUK-кодун ачуу кыйрады!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код кабыл алынды!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Байланыш жок."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Киргизүү ыкмасын которуу баскычы."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Киргизүү ыкмасын өзгөртүү"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Учак режими"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Түзмөк кайра күйгүзүлгөндөн кийин графикалык ачкыч талап кылынат"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Түзмөк кайра күйгүзүлгөндөн кийин PIN код талап кылынат"</string>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index e99b22d..0c59008 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK ຂອງ SIM ເຮັດວຽກລົ້ມເຫຼວ!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ລະ​ຫັດ​ຖືກຕອບຮັບແລ້ວ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ບໍ່ມີບໍລິການ"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ໂໝດໃນຍົນ"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ຈຳເປັນຕ້ອງມີແບບຮູບ ຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ຈຳເປັນຕ້ອງມີ PIN ຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index fd83ece..109adfb 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Nepavyko atlikti SIM kortelės PUK kodo operacijos."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodas priimtas."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nėra paslaugos."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Perjungti įvesties metodą"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Lėktuvo režimas"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Iš naujo paleidus įrenginį būtinas atrakinimo piešinys"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Iš naujo paleidus įrenginį būtinas PIN kodas"</string>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 5a35912..bd349d7 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -110,7 +110,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM kartes PUK koda ievadīšana neizdevās."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kods ir pieņemts!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nav pakalpojuma."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Pārslēgt ievades metodi"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Lidojuma režīms"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Pēc ierīces restartēšanas ir jāievada atbloķēšanas kombinācija."</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Pēc ierīces restartēšanas ir jāievada PIN kods."</string>
diff --git a/packages/Keyguard/res/values-mk-rMK/strings.xml b/packages/Keyguard/res/values-mk-rMK/strings.xml
index a1e224d..8d110ee 100644
--- a/packages/Keyguard/res/values-mk-rMK/strings.xml
+++ b/packages/Keyguard/res/values-mk-rMK/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"СИМ картичката не се отклучи со ПУК кодот!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодот е прифатен!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нема услуга."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Копче за префрање метод на внес."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Префрли метод на внесување"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим на работа во авион"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Потребна е шема по рестартирање на уредот"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Потребен е ПИН-код по рестартирање на уредот"</string>
diff --git a/packages/Keyguard/res/values-ml-rIN/strings.xml b/packages/Keyguard/res/values-ml-rIN/strings.xml
index 3a898d8..3a0a1a9 100644
--- a/packages/Keyguard/res/values-ml-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ml-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"സിം PUK പ്രവർത്തനം പരാജയപ്പെട്ടു!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"കോഡ് അംഗികരിച്ചു!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"സേവനമൊന്നുമില്ല."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ടൈപ്പുചെയ്യൽ രീതി ബട്ടൺ മാറുക."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ഇൻപുട്ട് രീതി മാറുക"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ഫ്ലൈറ്റ് മോഡ്"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ഉപകരണം പുനരാരംഭിച്ചതിന് ശേഷം പാറ്റേൺ ആവശ്യമാണ്"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ഉപകരണം പുനരാരംഭിച്ചതിന് ശേഷം പിൻ ആവശ്യമാണ്"</string>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 410ec4b..a93164a 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"СИМ ПҮК ажиллуулах амжилтгүй боллоо!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код зөвшөөрөгдлөө!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Үйлчилгээ байхгүй."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Оролтын аргыг солих"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Нислэгийн горим"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Төхөөрөмжийг дахин эхлүүлсний дараа зурган түгжээ оруулах шаардлагатай"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Төхөөрөмжийг дахин эхлүүлсний дараа PIN оруулах шаардлагатай"</string>
diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml
index 0418a7b..e15c4b9 100644
--- a/packages/Keyguard/res/values-mr-rIN/strings.xml
+++ b/packages/Keyguard/res/values-mr-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"सिम PUK कार्य अयशस्‍वी झाले!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्‍वीकारला!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"सेवा नाही."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धत स्‍विच करा बटण."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"इनपुट पद्धत स्विच करा"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"विमान मोड"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"डिव्‍हाइस रीस्टार्ट झाल्यावर नमुना आवश्‍यक आहे"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"डिव्‍हाइस रीस्टार्ट झाल्यावर पिन आवश्‍यक आहे"</string>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index e8c0bab..42a11ff 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operasi PUK SIM gagal!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Diterima!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tiada perkhidmatan."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Tukar kaedah masukan"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Mod Pesawat"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Corak diperlukan setelah peranti dimulakan semula"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN diperlukan setelah peranti dimulakan semula"</string>
diff --git a/packages/Keyguard/res/values-my-rMM/strings.xml b/packages/Keyguard/res/values-my-rMM/strings.xml
index 86c6e78..f384079 100644
--- a/packages/Keyguard/res/values-my-rMM/strings.xml
+++ b/packages/Keyguard/res/values-my-rMM/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် လုပ်ဆောင်မှု မအောင်မြင်ပါ"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ကုဒ်နံပါတ်ကို လက်ခံလိုက်ပါသည်"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ဆားဗစ် မရှိပါ"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ထည့်သွင်းခြင်းခလုတ်အား ပြောင်းခြင်း"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ထည့်သွင်းမှုနည်းလမ်းကို ပြောင်းလဲပါ"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"လေယာဉ်ပေါ်သုံးစနစ်"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ကိရိယာကို ပြန်ဖွင့်လျှင် ပုံစံ လိုအပ်ပါသည်"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ကိရိယာကို ပြန်ဖွင့်လျှင် PIN လိုအပ်ပါသည်"</string>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index a31c52c..210ad18 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-koden for SIM-kortet ble avvist."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden er godkjent."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjeneste."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Bytt inndatametode"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Flymodus"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Du må tegne mønsteret etter at enheten har startet på nytt"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Du må skrive inn PIN-koden etter at enheten har startet på nytt"</string>
diff --git a/packages/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml
index 5a3b7ec..99d4ff0 100644
--- a/packages/Keyguard/res/values-ne-rNP/strings.xml
+++ b/packages/Keyguard/res/values-ne-rNP/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK राख्‍ने कार्य बिफल भयो!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकृत!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कुनै सेवा छैन।"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"इनपुट विधिलाई स्विच गर्नुहोस्"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"हवाइजहाज मोड"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"यन्त्र पुनः सुरू भएपछि ढाँचा आवश्यक"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"यन्त्र पुनः सुरू भएपछि PIN आवश्यक"</string>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 8ded2e8..873a523 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Bewerking met pukcode voor simkaart is mislukt."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code geaccepteerd."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen service"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Invoermethode schakelen"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Vliegtuigmodus"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Patroon vereist nadat het apparaat opnieuw is opgestart"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Pincode vereist nadat het apparaat opnieuw is opgestart"</string>
diff --git a/packages/Keyguard/res/values-pa-rIN/strings.xml b/packages/Keyguard/res/values-pa-rIN/strings.xml
index e867df2..54d1040 100644
--- a/packages/Keyguard/res/values-pa-rIN/strings.xml
+++ b/packages/Keyguard/res/values-pa-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ਓਪਰੇਸ਼ਨ ਅਸਫਲ!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ਕੋਡ ਸਵੀਕਾਰ ਕੀਤਾ ਗਿਆ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ।"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ਇਨਪੁਟ ਵਿਧੀ ਬਟਨ ਸਵਿਚ ਕਰੋ।"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ਇਨਪੁੱਟ ਵਿਧੀ ਸਵਿੱਚ ਕਰੋ"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ਏਅਰਪਲੇਨ ਮੋਡ"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ਡੀਵਾਈਸ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਹੋਣ ਤੋਂ ਬਾਅਦ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ਡੀਵਾਈਸ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਹੋਣ ਤੋਂ ਬਾਅਦ PIN ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 3bd9caf..6a2e81a 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operacja z kodem PUK karty SIM nie udała się."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod został zaakceptowany."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Brak usługi."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Przełącz metodę wprowadzania"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Tryb samolotowy"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Po ponownym uruchomieniu urządzenia wymagany jest wzór"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Po ponownym uruchomieniu urządzenia wymagany jest kod PIN"</string>
diff --git a/packages/Keyguard/res/values-pt-rBR/strings.xml b/packages/Keyguard/res/values-pt-rBR/strings.xml
index 4f1afab..2d1a703 100644
--- a/packages/Keyguard/res/values-pt-rBR/strings.xml
+++ b/packages/Keyguard/res/values-pt-rBR/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Falha na operação de PUK do SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceito."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Alterar o método de entrada"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modo avião"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"O padrão é exigido após a reinicialização do dispositivo"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"O PIN é exigido após a reinicialização do dispositivo"</string>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index 49c2f16..5a4973b 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Falha ao introduzir o PUK do cartão SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceite!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Alternar o método de introdução."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modo de avião"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"É necessário um padrão após reiniciar o dispositivo"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"É necessário um PIN após reiniciar o dispositivo"</string>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index 4f1afab..2d1a703 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Falha na operação de PUK do SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceito."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Alterar o método de entrada"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modo avião"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"O padrão é exigido após a reinicialização do dispositivo"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"O PIN é exigido após a reinicialização do dispositivo"</string>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index 439de3d..0a5d4fe 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -21,13 +21,13 @@
 <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_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>
     <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Codul PIN nou pentru cardul SIM"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceţi parola"</font></string>
-    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string>
-    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceți parola"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceți parola pentru a debloca"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceți codul PIN pentru a debloca"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Încărcată"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Se încarcă"</string>
@@ -58,28 +58,28 @@
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeți"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
-    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greșit"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greșită"</string>
-    <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greșit"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercați din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string>
-    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenați modelul"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceți codul PIN al cardului SIM"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Introduceți codul PIN al cardului SIM pentru „<xliff:g id="CARRIER">%1$s</xliff:g>”"</string>
-    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
-    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceţi parola"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceţi codul PUK pentru a continua. Contactaţi operatorul pentru mai multe detalii."</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceți codul PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceți parola"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceți codul PUK pentru a continua. Contactați operatorul pentru mai multe detalii."</string>
     <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"Cardul SIM „<xliff:g id="CARRIER">%1$s</xliff:g>” este acum dezactivat. Pentru a continua, introduceți codul PUK. Pentru detalii, contactați operatorul."</string>
-    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceţi codul PIN dorit"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceți codul PIN dorit"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmați codul PIN dorit"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
-    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceți un cod PIN format din 4 până la 8 cifre."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Codul PUK trebuie să aibă minimum 8 cifre."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceți codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
@@ -92,8 +92,8 @@
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codul PIN pentru cardul SIM este incorect. Contactați operatorul pentru a vă debloca dispozitivul."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="few">Codul PIN pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări.</item>
@@ -110,7 +110,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Deblocarea cu ajutorul codului PUK pentru cardul SIM nu a reușit!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Cod acceptat!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Fără serviciu."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Comutați metoda de introducere a textului"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Mod Avion"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Modelul este necesar după repornirea dispozitivului"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Codul PIN este necesar după repornirea dispozitivului"</string>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 2f03166..d56263a 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Не удалось разблокировать SIM-карту"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код принят"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нет сигнала."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Сменить способ ввода"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим полета"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"После перезагрузки устройства необходимо ввести графический ключ"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"После перезагрузки устройства необходимо ввести PIN-код"</string>
diff --git a/packages/Keyguard/res/values-si-rLK/strings.xml b/packages/Keyguard/res/values-si-rLK/strings.xml
index 82ef914..a0170fb 100644
--- a/packages/Keyguard/res/values-si-rLK/strings.xml
+++ b/packages/Keyguard/res/values-si-rLK/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ක්‍රියාවලිය අපොහොසත් විය!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"කේතය පිළිගැණුනි!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"සේවාව නැත."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්‍රමය මාරු කිරීමේ බොත්තම."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ආදාන ක්‍රමය මාරු කිරීම"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ගුවන්යානා ප්‍රකාරය"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"උපාංගය නැවත ආරම්භ වූ පසු රටාව අවශ්‍යයි"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"උපාංගය නැවත ආරම්භ වූ පසු PIN අංකය අවශ්‍යයි"</string>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 72958ce..008a7b0 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operácia kódu PUK SIM karty zlyhala!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód bol prijatý!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žiadny signál"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Prepnúť metódu vstupu"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Režim v lietadle"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Po reštartovaní zariadenia musíte zadať bezpečnostný vzor"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Po reštartovaní zariadenia musíte zadať kód PIN"</string>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index 83a6e49..a7cd7ab 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Postopek za odklepanje s kodo PUK kartice SIM ni uspel."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koda je sprejeta."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ni storitve."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Preklop načina vnosa"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Način za letalo"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Po vnovičnem zagonu naprave je treba vnesti vzorec"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Po vnovičnem zagonu naprave je treba vnesti kodo PIN"</string>
diff --git a/packages/Keyguard/res/values-sq-rAL/strings.xml b/packages/Keyguard/res/values-sq-rAL/strings.xml
index 4cd2692..870f3bf 100644
--- a/packages/Keyguard/res/values-sq-rAL/strings.xml
+++ b/packages/Keyguard/res/values-sq-rAL/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operacioni i PUK-ut të kartës SIM dështoi!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodi u pranua!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nuk ka shërbim."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butoni i metodës së ndërrimit të hyrjeve."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Ndërro metodën e hyrjes"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Modaliteti i aeroplanit"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Kërkohet motivi pas rinisjes së pajisjes"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Kërkohet kodi PIN pas rinisjes së pajisjes"</string>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index fa6bc09..20f098e 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -110,7 +110,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Радња са SIM PUK кодом није успела!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кôд је прихваћен!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Офлајн сте."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Промени метод уноса"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим рада у авиону"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Треба да унесете шаблон када се уређај поново покрене"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Треба да унесете PIN када се уређај поново покрене"</string>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 10b5991..a77d79e 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Det gick inte att låsa upp med PUK-koden för SIM-kortet."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden godkändes!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjänst."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Byt inmatningsmetod"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Flygplansläge"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Du måste ange grafiskt lösenord när du startat om enheten"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Du måste ange pinkod när du startat om enheten"</string>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index 77eaf2a..8413dad 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Utendakazi wa PUK ya SIM umeshindwa!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Msimbo Umekubaliwa!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hakuna huduma."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Badilisha mbinu ya kuingiza data"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Hali ya ndegeni"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Mchoro unahitajika baada ya kuanzisha kifaa upya"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"PIN inahitajika baada ya kifaa kuanzishwa upya"</string>
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index a487644..c34012d 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -20,5 +20,5 @@
 <resources>
 
     <!-- Overload default clock widget parameters -->
-    <dimen name="widget_big_font_size">100dp</dimen>
+    <dimen name="widget_big_font_size">88dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index b181682..a3b01b6 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -26,9 +26,9 @@
     <dimen name="keyguard_security_view_margin">12dp</dimen>
 
     <!-- Overload default clock widget parameters -->
-    <dimen name="widget_big_font_size">125dp</dimen>
+    <dimen name="widget_big_font_size">110dp</dimen>
     <dimen name="widget_label_font_size">16sp</dimen>
-    <dimen name="bottom_text_spacing_digital">-16dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-1dp</dimen>
 
     <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
          Should be 0 on devices with plenty of room (e.g. tablets) -->
diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml
index 08ab791..210c7eb 100644
--- a/packages/Keyguard/res/values-sw720dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw720dp/dimens.xml
@@ -24,5 +24,5 @@
     <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
     <dimen name="keyguard_security_height">420dp</dimen>
 
-    <dimen name="widget_big_font_size">138dp</dimen>
+    <dimen name="widget_big_font_size">122dp</dimen>
 </resources>
diff --git a/packages/Keyguard/res/values-ta-rIN/strings.xml b/packages/Keyguard/res/values-ta-rIN/strings.xml
index 5ddad8c..e43238f 100644
--- a/packages/Keyguard/res/values-ta-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ta-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"சிம் PUK செயல்பாடு தோல்வி!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"குறியீடு ஏற்கப்பட்டது!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"சேவை இல்லை."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"உள்ளீட்டு முறையை மாற்றும் பொத்தான்."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"உள்ளீட்டு முறையை மாற்று"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"விமானப் பயன்முறை"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"சாதனத்தை மீண்டும் தொடங்கியதும் வடிவத்தை வரைய வேண்டும்"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"சாதனத்தை மீண்டும் தொடங்கியதும் பின்னை உள்ளிட வேண்டும்"</string>
diff --git a/packages/Keyguard/res/values-te-rIN/strings.xml b/packages/Keyguard/res/values-te-rIN/strings.xml
index e10490c..7c9b37d 100644
--- a/packages/Keyguard/res/values-te-rIN/strings.xml
+++ b/packages/Keyguard/res/values-te-rIN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"సిమ్ PUK చర్య విఫలమైంది!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"కోడ్ ఆమోదించబడింది!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"సేవ లేదు."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ఇన్‌పుట్ పద్ధతి మార్చే బటన్."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"ఇన్‌పుట్ పద్ధతిని మారుస్తుంది"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ఎయిర్‌ప్లైన్ మోడ్"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత నమూనా నమోదు చేయడం ఆవశ్యకం"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత PIN నమోదు చేయడం ఆవశ్యకం"</string>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index d3fe71e..00c920c 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"การปลดล็อกด้วย PUK ของซิมล้มเหลว!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"รหัสได้รับการยอมรับ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ไม่มีบริการ"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"สลับวิธีการป้อนข้อมูล"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"โหมดบนเครื่องบิน"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ต้องใช้รูปแบบหลังจากอุปกรณ์รีสตาร์ท"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ต้องระบุ PIN หลังจากอุปกรณ์รีสตาร์ท"</string>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 6e6adec..2e428530 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Nabigo ang operasyon ng SIM PUK!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Tinanggap ang Code!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Walang serbisyo."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Magpalit ng pamamaraan ng pag-input"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Airplane mode"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Kinakailangan ang pattern pagkatapos mag-restart ng device"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Kinakailangan ang PIN pagkatapos mag-restart ng device"</string>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 46c3d00..484505a 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK işlemi başarısız oldu!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Kabul Edildi!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hizmet yok."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Giriş yöntemini değiştir"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Uçak modu"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Cihaz yeniden başladıktan sonra desen gerekir"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Cihaz yeniden başladıktan sonra PIN gerekir"</string>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index c1b742e..c137bf0 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -112,7 +112,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Помилка введення PUK-коду SIM-карти."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код прийнято."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Зв’язку немає."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Змінити метод введення"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим польоту"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Після перезавантаження пристрою потрібно ввести ключ"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Після перезавантаження пристрою потрібно ввести PIN-код"</string>
diff --git a/packages/Keyguard/res/values-ur-rPK/strings.xml b/packages/Keyguard/res/values-ur-rPK/strings.xml
index 48986e6..d131c34 100644
--- a/packages/Keyguard/res/values-ur-rPK/strings.xml
+++ b/packages/Keyguard/res/values-ur-rPK/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏SIM PUK کارروائی ناکام ہو گئی!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کوڈ قبول کر لیا گیا!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"کوئی سروس نہیں ہے۔"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"اندراج کا طریقہ سوئچ کرنے کا بٹن۔"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"اندراج کا طریقہ سوئچ کریں"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ہوائی جہاز وضع"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"آلہ دوبارہ چالو ہونے کے بعد پیٹرن درکار ہوتا ہے"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"‏آلہ دوبارہ چالو ہونے کے بعد PIN درکار ہوتا ہے"</string>
diff --git a/packages/Keyguard/res/values-uz-rUZ/strings.xml b/packages/Keyguard/res/values-uz-rUZ/strings.xml
index 7e9f504..d1e2941 100644
--- a/packages/Keyguard/res/values-uz-rUZ/strings.xml
+++ b/packages/Keyguard/res/values-uz-rUZ/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM karta PUK jarayoni amalga oshmadi!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod qabul qilindi!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aloqa yo‘q."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Kiritish uslubi tugmasini almashtirish."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Matn kiritish usulini o‘zgartirish"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Parvoz rejimi"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Qurilma o‘chirib yoqilgandan so‘ng chizmali kalit talab qilinadi"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Qurilma o‘chirib yoqilgandan so‘ng PIN kod talab qilinadi"</string>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 6f81101..4203c94 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Thao tác mã PUK của SIM không thành công!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Mã được chấp nhận!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Không có dịch vụ."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Chuyển phương thức nhập"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Chế độ trên máy bay"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Yêu cầu hình mở khóa sau khi thiết bị khởi động lại"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Yêu cầu mã PIN sau khi thiết bị khởi động lại"</string>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 2c86a7a..a73dcb6 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM卡PUK码操作失败!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"代码正确!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"无服务。"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"切换输入法"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"飞行模式"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"重启设备后需要绘制解锁图案"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"重启设备后需要输入 PIN 码"</string>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index f21dbca..e9d1208 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK 碼操作失敗!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"切換輸入法"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"飛航模式"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"裝置重新啟動後,需要解除上鎖圖案才能使用"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"裝置重新啟動後,需要輸入 PIN 才能使用"</string>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 0cb4b16..36cf9de 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM 卡 PUK 碼操作失敗!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"切換輸入法"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"飛航模式"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"裝置重新啟動後需要畫出解鎖圖案"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"裝置重新啟動後需要輸入 PIN 碼"</string>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index 9e17dba..68086b2 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -108,7 +108,7 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Umsebenzi we-PUK ye-SIM wehlulekile!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Ikhodi yamukelwe!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ayikho isevisi."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
+    <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Shintsha indlela yokufaka"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Isimo sendiza"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Iphethini iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Iphinikhodi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 18d893a..7b952be2 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -39,9 +39,9 @@
     <dimen name="eca_overlap">-10dip</dimen>
 
     <!-- Default clock parameters -->
-    <dimen name="bottom_text_spacing_digital">-10dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-1dp</dimen>
     <dimen name="widget_label_font_size">14sp</dimen>
-    <dimen name="widget_big_font_size">88dp</dimen>
+    <dimen name="widget_big_font_size">78dp</dimen>
 
     <!-- The y translation to apply at the start in appear animations. -->
     <dimen name="appear_y_translation_start">32dp</dimen>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 746457f..61966b2 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -302,7 +302,7 @@
     <string name="keyguard_carrier_default">No service.</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" msgid="5032926134740456424">Switch input method button.</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">Switch input method</string>
 
     <!-- Description of airplane mode -->
     <string name="airplane_mode">Airplane mode</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index ec2a173..434631e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -413,7 +413,7 @@
      * @return true if the menu key should be enabled
      */
     private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
-    private boolean shouldEnableMenuKey() {
+    public boolean shouldEnableMenuKey() {
         final Resources res = getResources();
         final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
         final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
@@ -421,15 +421,6 @@
         return !configDisabled || isTestHarness || fileOverride;
     }
 
-    public boolean handleMenuKey() {
-        // The following enables the MENU key to work for testing automation
-        if (shouldEnableMenuKey()) {
-            dismiss();
-            return true;
-        }
-        return false;
-    }
-
     public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
         mViewMediatorCallback = viewMediatorCallback;
         // Update ViewMediator with the current input method requirements
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index cedd88d..fe98cb8 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -89,7 +89,12 @@
             return true;
         }
         if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
-            int number = keyCode - KeyEvent.KEYCODE_0 ;
+            int number = keyCode - KeyEvent.KEYCODE_0;
+            performNumberClick(number);
+            return true;
+        }
+        if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9) {
+            int number = keyCode - KeyEvent.KEYCODE_NUMPAD_0;
             performNumberClick(number);
             return true;
         }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 409f6a7..a7e4e12 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -464,7 +464,7 @@
         return 0;
     }
 
-    private int getLayoutIdFor(SecurityMode securityMode) {
+    protected int getLayoutIdFor(SecurityMode securityMode) {
         switch (securityMode) {
             case Pattern: return R.layout.keyguard_pattern_view;
             case PIN: return R.layout.keyguard_pin_view;
@@ -519,6 +519,9 @@
     @Override
     public void showPromptReason(int reason) {
         if (mCurrentSecuritySelection != SecurityMode.None) {
+            if (reason != PROMPT_REASON_NONE) {
+                Log.i(TAG, "Strong auth required, reason: " + reason);
+            }
             getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
         }
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 454221a..2b549f1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -77,6 +77,7 @@
             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+            case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
                 return SecurityMode.Password;
 
             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
index b31b0b1..0f945ee 100644
--- a/packages/MtpDocumentsProvider/Android.mk
+++ b/packages/MtpDocumentsProvider/Android.mk
@@ -9,5 +9,10 @@
 LOCAL_JNI_SHARED_LIBRARIES := libappfuse_jni
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
+# Only enable asserts on userdebug/eng builds
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+LOCAL_JACK_FLAGS += -D jack.assert.policy=enable
+endif
+
 include $(BUILD_PACKAGE)
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/MtpDocumentsProvider/AndroidManifest.xml b/packages/MtpDocumentsProvider/AndroidManifest.xml
index 2dd49ab..843b313 100644
--- a/packages/MtpDocumentsProvider/AndroidManifest.xml
+++ b/packages/MtpDocumentsProvider/AndroidManifest.xml
@@ -15,10 +15,12 @@
                 <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
             </intent-filter>
         </provider>
-        
+
         <service android:name=".MtpDocumentsService" />
 
         <activity android:name=".ReceiverActivity"
+                  android:label="@string/downloads_app_label"
+                  android:icon="@mipmap/ic_launcher_download"
                   android:theme="@android:style/Theme.NoDisplay"
                   android:screenOrientation="locked"
                   android:excludeFromRecents="true">
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
index 2b44d51..eb96015 100644
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -51,6 +51,9 @@
 static jclass app_fuse_class;
 static jmethodID app_fuse_get_file_size;
 static jmethodID app_fuse_read_object_bytes;
+static jmethodID app_fuse_write_object_bytes;
+static jmethodID app_fuse_flush_file_handle;
+static jmethodID app_fuse_close_file_handle;
 static jfieldID app_fuse_buffer;
 
 // NOTE:
@@ -140,6 +143,9 @@
             case FUSE_READ:
                 invoke_handler(fd, req, &AppFuse::handle_fuse_read);
                 return true;
+            case FUSE_WRITE:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_write);
+                return true;
             case FUSE_RELEASE:
                 invoke_handler(fd, req, &AppFuse::handle_fuse_release);
                 return true;
@@ -289,17 +295,41 @@
         return 0;
     }
 
+    int handle_fuse_write(const fuse_in_header& /* header */,
+                          const fuse_write_in* in,
+                          FuseResponse<fuse_write_out>* out) {
+        if (in->size > MAX_WRITE) {
+            return -EINVAL;
+        }
+        const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
+        if (it == handles_.end()) {
+            return -EBADF;
+        }
+        const uint64_t offset = in->offset;
+        const uint32_t size = in->size;
+        const void* const buffer = reinterpret_cast<const uint8_t*>(in) + sizeof(fuse_write_in);
+        uint32_t written_size;
+        const int result = write_object_bytes(
+                in->fh, it->second, offset, size, buffer, &written_size);
+        if (result < 0) {
+            return result;
+        }
+        out->prepare_buffer();
+        out->data()->size = written_size;
+        return 0;
+    }
+
     int handle_fuse_release(const fuse_in_header& /* header */,
                             const fuse_release_in* in,
                             FuseResponse<void>* /* out */) {
         handles_.erase(in->fh);
-        return 0;
+        return env_->CallIntMethod(self_, app_fuse_close_file_handle, file_handle_to_jlong(in->fh));
     }
 
     int handle_fuse_flush(const fuse_in_header& /* header */,
-                          const void* /* in */,
+                          const fuse_flush_in* in,
                           FuseResponse<void>* /* out */) {
-        return 0;
+        return env_->CallIntMethod(self_, app_fuse_flush_file_handle, file_handle_to_jlong(in->fh));
     }
 
     template <typename T, typename S>
@@ -355,6 +385,42 @@
         return read_size;
     }
 
+    int write_object_bytes(uint64_t handle, int inode, uint64_t offset, uint32_t size,
+                           const void* buffer, uint32_t* written_size) {
+        static_assert(sizeof(uint64_t) <= sizeof(jlong),
+                      "jlong must be able to express any uint64_t values");
+        ScopedLocalRef<jbyteArray> array(
+                env_,
+                static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
+        {
+            ScopedByteArrayRW bytes(env_, array.get());
+            if (bytes.get() == nullptr) {
+                return -EIO;
+            }
+            memcpy(bytes.get(), buffer, size);
+        }
+        const int result = env_->CallIntMethod(
+                self_,
+                app_fuse_write_object_bytes,
+                file_handle_to_jlong(handle),
+                inode,
+                offset,
+                size,
+                array.get());
+        if (result < 0) {
+            return result;
+        }
+        *written_size = result;
+        return 0;
+    }
+
+    static jlong file_handle_to_jlong(uint64_t handle) {
+        static_assert(
+                sizeof(uint64_t) <= sizeof(jlong),
+                "jlong must be able to express any uint64_t values");
+        return static_cast<jlong>(handle);
+    }
+
     static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
                            size_t reply_size) {
         // Don't send any data for error case.
@@ -463,12 +529,40 @@
         return -1;
     }
 
+    app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(JIJI[B)I");
+    if (app_fuse_write_object_bytes == nullptr) {
+        ALOGE("Can't find writeObjectBytes");
+        return -1;
+    }
+
+    app_fuse_flush_file_handle = env->GetMethodID(app_fuse_class, "flushFileHandle", "(J)I");
+    if (app_fuse_flush_file_handle == nullptr) {
+        ALOGE("Can't find flushFileHandle");
+        return -1;
+    }
+
+    app_fuse_close_file_handle = env->GetMethodID(app_fuse_class, "closeFileHandle", "(J)I");
+    if (app_fuse_close_file_handle == nullptr) {
+        ALOGE("Can't find closeFileHandle");
+        return -1;
+    }
+
     app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
     if (app_fuse_buffer == nullptr) {
         ALOGE("Can't find mBuffer");
         return -1;
     }
 
+    const jfieldID read_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_READ", "I");
+    if (static_cast<int>(env->GetStaticIntField(app_fuse_class, read_max_fied)) != MAX_READ) {
+        return -1;
+    }
+
+    const jfieldID write_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_WRITE", "I");
+    if (static_cast<int>(env->GetStaticIntField(app_fuse_class, write_max_fied)) != MAX_WRITE) {
+        return -1;
+    }
+
     const int result = android::AndroidRuntime::registerNativeMethods(
             env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
     if (result < 0) {
diff --git a/packages/MtpDocumentsProvider/res/mipmap-hdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-hdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f958bbd
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/mipmap-hdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-mdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-mdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f2e9376
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/mipmap-mdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-xhdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-xhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..4dc5336
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/mipmap-xhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-xxhdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-xxhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..8716290
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/mipmap-xxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-xxxhdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-xxxhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f5be219
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/mipmap-xxxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/values/strings.xml b/packages/MtpDocumentsProvider/res/values/strings.xml
index f3a3fcf..0c1ec50 100644
--- a/packages/MtpDocumentsProvider/res/values/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values/strings.xml
@@ -15,8 +15,10 @@
 -->
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Title of the external storage application [CHAR LIMIT=32] -->
-    <string name="app_label">Files</string>
+    <!-- App title of MtpDocumentsProvider [CHAR LIMIT=32] -->
+    <string name="app_label">MTP Host</string>
+    <!-- App title of DocumentsUI [CHAR LIMIT=32] -->
+    <string name="downloads_app_label">Downloads</string>
     <!-- Name of MTP root shown in UI. Please align the two strings (device
          model and storage name) in proper order in the language.
          [CHAR LIMIT=32] -->
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
index 6a98405..88858a8 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -20,6 +20,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.storage.StorageManager;
+import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
 import com.android.internal.annotations.VisibleForTesting;
@@ -34,12 +35,18 @@
         System.loadLibrary("appfuse_jni");
     }
 
+    private static final boolean DEBUG = false;
+
     /**
      * Max read amount specified at the FUSE kernel implementation.
      * The value is copied from sdcard.c.
      */
+    @UsedByNative("com_android_mtp_AppFuse.cpp")
     static final int MAX_READ = 128 * 1024;
 
+    @UsedByNative("com_android_mtp_AppFuse.cpp")
+    static final int MAX_WRITE = 256 * 1024;
+
     private final String mName;
     private final Callback mCallback;
 
@@ -47,7 +54,7 @@
      * Buffer for read bytes request.
      * Don't use the buffer from the out of AppFuseMessageThread.
      */
-    private byte[] mBuffer = new byte[MAX_READ];
+    private byte[] mBuffer = new byte[Math.max(MAX_READ, MAX_WRITE)];
 
     private Thread mMessageThread;
     private ParcelFileDescriptor mDeviceFd;
@@ -79,11 +86,23 @@
         }
     }
 
-    public ParcelFileDescriptor openFile(int i) throws FileNotFoundException {
+    /**
+     * Opens a file on app fuse and returns ParcelFileDescriptor.
+     *
+     * @param i ID for opened file.
+     * @param mode Mode for opening file.
+     * @see ParcelFileDescriptor#MODE_READ_ONLY
+     * @see ParcelFileDescriptor#MODE_WRITE_ONLY
+     */
+    public ParcelFileDescriptor openFile(int i, int mode) throws FileNotFoundException {
+        Preconditions.checkArgument(
+                mode == ParcelFileDescriptor.MODE_READ_ONLY ||
+                mode == (ParcelFileDescriptor.MODE_WRITE_ONLY |
+                         ParcelFileDescriptor.MODE_TRUNCATE));
         return ParcelFileDescriptor.open(new File(
                 getMountPoint(),
                 Integer.toString(i)),
-                ParcelFileDescriptor.MODE_READ_ONLY);
+                mode);
     }
 
     File getMountPoint() {
@@ -100,7 +119,7 @@
         long getFileSize(int inode) throws FileNotFoundException;
 
         /**
-         * Returns flie bytes for the give inode.
+         * Returns file bytes for the give inode.
          * @param inode
          * @param offset Offset for file bytes.
          * @param size Size for file bytes.
@@ -109,6 +128,34 @@
          * @throws IOException
          */
         long readObjectBytes(int inode, long offset, long size, byte[] bytes) throws IOException;
+
+        /**
+         * Handles writing bytes for the give inode.
+         * @param fileHandle
+         * @param inode
+         * @param offset Offset for file bytes.
+         * @param size Size for file bytes.
+         * @param bytes Buffer to store file bytes.
+         * @return Number of read bytes. Must not be negative.
+         * @throws IOException
+         */
+        int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
+                throws IOException, ErrnoException;
+
+        /**
+         * Flushes bytes for file handle.
+         * @param fileHandle
+         * @throws IOException
+         * @throws ErrnoException
+         */
+        void flushFileHandle(long fileHandle) throws IOException, ErrnoException;
+
+        /**
+         * Closes file handle.
+         * @param fileHandle
+         * @throws IOException
+         */
+        void closeFileHandle(long fileHandle) throws IOException, ErrnoException;
     }
 
     @UsedByNative("com_android_mtp_AppFuse.cpp")
@@ -116,8 +163,8 @@
     private long getFileSize(int inode) {
         try {
             return mCallback.getFileSize(inode);
-        } catch (FileNotFoundException e) {
-            return -OsConstants.ENOENT;
+        } catch (Exception error) {
+            return -getErrnoFromException(error);
         }
     }
 
@@ -131,8 +178,61 @@
             // It's OK to share the same mBuffer among requests because the requests are processed
             // by AppFuseMessageThread sequentially.
             return mCallback.readObjectBytes(inode, offset, size, mBuffer);
-        } catch (IOException e) {
-            return -OsConstants.EIO;
+        } catch (Exception error) {
+            return -getErrnoFromException(error);
+        }
+    }
+
+    @UsedByNative("com_android_mtp_AppFuse.cpp")
+    @WorkerThread
+    private /* unsgined */ int writeObjectBytes(long fileHandler,
+                                                int inode,
+                                                /* unsigned */ long offset,
+                                                /* unsigned */ int size,
+                                                byte[] bytes) {
+        try {
+            return mCallback.writeObjectBytes(fileHandler, inode, offset, size, bytes);
+        } catch (Exception error) {
+            return -getErrnoFromException(error);
+        }
+    }
+
+    @UsedByNative("com_android_mtp_AppFuse.cpp")
+    @WorkerThread
+    private int flushFileHandle(long fileHandle) {
+        try {
+            mCallback.flushFileHandle(fileHandle);
+            return 0;
+        } catch (Exception error) {
+            return -getErrnoFromException(error);
+        }
+    }
+
+    @UsedByNative("com_android_mtp_AppFuse.cpp")
+    @WorkerThread
+    private int closeFileHandle(long fileHandle) {
+        try {
+            mCallback.closeFileHandle(fileHandle);
+            return 0;
+        } catch (Exception error) {
+            return -getErrnoFromException(error);
+        }
+    }
+
+    private static int getErrnoFromException(Exception error) {
+        if (DEBUG) {
+            Log.e(MtpDocumentsProvider.TAG, "AppFuse callbacks", error);
+        }
+        if (error instanceof FileNotFoundException) {
+            return OsConstants.ENOENT;
+        } else if (error instanceof IOException) {
+            return OsConstants.EIO;
+        } else if (error instanceof UnsupportedOperationException) {
+            return OsConstants.ENOTSUP;
+        } else if (error instanceof IllegalArgumentException) {
+            return OsConstants.EINVAL;
+        } else {
+            return OsConstants.EIO;
         }
     }
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java b/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java
new file mode 100644
index 0000000..83488cd
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when the device is busy and the requested operation cannon be completed.
+ */
+class BusyDeviceException extends IOException {
+    BusyDeviceException() {
+        super("The MTP device is busy.");
+    }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index 90b5c09..246b95de 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -16,8 +16,11 @@
 
 package com.android.mtp;
 
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
 import android.content.ContentResolver;
 import android.database.Cursor;
+import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
 import android.net.Uri;
 import android.os.Bundle;
@@ -25,6 +28,8 @@
 import android.provider.DocumentsContract;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -38,79 +43,118 @@
  * background thread to load the rest documents and caches its result for next requests.
  * TODO: Rename this class to ObjectInfoLoader
  */
-class DocumentLoader {
+class DocumentLoader implements AutoCloseable {
     static final int NUM_INITIAL_ENTRIES = 10;
     static final int NUM_LOADING_ENTRIES = 20;
     static final int NOTIFY_PERIOD_MS = 500;
 
+    private final MtpDeviceRecord mDevice;
     private final MtpManager mMtpManager;
     private final ContentResolver mResolver;
     private final MtpDatabase mDatabase;
     private final TaskList mTaskList = new TaskList();
-    private boolean mHasBackgroundThread = false;
+    private Thread mBackgroundThread;
 
-    DocumentLoader(MtpManager mtpManager, ContentResolver resolver, MtpDatabase database) {
+    DocumentLoader(MtpDeviceRecord device, MtpManager mtpManager, ContentResolver resolver,
+                   MtpDatabase database) {
+        mDevice = device;
         mMtpManager = mtpManager;
         mResolver = resolver;
         mDatabase = database;
     }
 
-    private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
-            throws IOException {
-        final ArrayList<MtpObjectInfo> objects = new ArrayList<>();
-        for (int i = 0; i < handles.length; i++) {
-            final MtpObjectInfo info = manager.getObjectInfo(deviceId, handles[i]);
-            if (info == null) {
-                Log.e(MtpDocumentsProvider.TAG,
-                        "Failed to obtain object info handle=" + handles[i]);
-                continue;
-            }
-            objects.add(info);
-        }
-        return objects.toArray(new MtpObjectInfo[objects.size()]);
-    }
-
+    /**
+     * Queries the child documents of given parent.
+     * It loads the first NUM_INITIAL_ENTRIES of object info, then launches the background thread
+     * to load the rest.
+     */
     synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
             throws IOException {
+        assert parent.mDeviceId == mDevice.deviceId;
+
         LoaderTask task = mTaskList.findTask(parent);
         if (task == null) {
             if (parent.mDocumentId == null) {
                 throw new FileNotFoundException("Parent not found.");
             }
-
-            int parentHandle = parent.mObjectHandle;
-            // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
-            // getObjectHandles if we would like to obtain children under the root.
-            if (parent.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
-                parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
-            }
             // TODO: Handle nit race around here.
             // 1. getObjectHandles.
             // 2. putNewDocument.
             // 3. startAddingChildDocuemnts.
             // 4. stopAddingChildDocuments - It removes the new document added at the step 2,
             //     because it is not updated between start/stopAddingChildDocuments.
-            task = new LoaderTask(mDatabase, parent, mMtpManager.getObjectHandles(
-                    parent.mDeviceId, parent.mStorageId, parentHandle));
-            task.fillDocuments(loadDocuments(
-                    mMtpManager,
-                    parent.mDeviceId,
-                    task.getUnloadedObjectHandles(NUM_INITIAL_ENTRIES)));
+            task = new LoaderTask(mMtpManager, mDatabase, mDevice.operationsSupported, parent);
+            task.loadObjectHandles();
+            task.loadObjectInfoList(NUM_INITIAL_ENTRIES);
         } else {
             // Once remove the existing task in order to add it to the head of the list.
             mTaskList.remove(task);
         }
 
         mTaskList.addFirst(task);
-        if (task.getState() == LoaderTask.STATE_LOADING && !mHasBackgroundThread) {
-            mHasBackgroundThread = true;
-            new BackgroundLoaderThread().start();
+        if (task.getState() == LoaderTask.STATE_LOADING) {
+            resume();
         }
         return task.createCursor(mResolver, columnNames);
     }
 
-    synchronized void clearTasks() {
-        mTaskList.clear();
+    /**
+     * Resumes a background thread.
+     */
+    synchronized void resume() {
+        if (mBackgroundThread == null) {
+            mBackgroundThread = new BackgroundLoaderThread();
+            mBackgroundThread.start();
+        }
+    }
+
+    /**
+     * Obtains next task to be run in background thread, or release the reference to background
+     * thread.
+     *
+     * Worker thread that receives null task needs to exit.
+     */
+    @WorkerThread
+    synchronized @Nullable LoaderTask getNextTaskOrReleaseBackgroundThread() {
+        Preconditions.checkState(mBackgroundThread != null);
+
+        final LoaderTask task = mTaskList.findRunningTask();
+        if (task != null) {
+            return task;
+        }
+
+        final Identifier identifier = mDatabase.getUnmappedDocumentsParent(mDevice.deviceId);
+        if (identifier != null) {
+            final LoaderTask existingTask = mTaskList.findTask(identifier);
+            if (existingTask != null) {
+                Preconditions.checkState(existingTask.getState() != LoaderTask.STATE_LOADING);
+                mTaskList.remove(existingTask);
+            }
+            final LoaderTask newTask = new LoaderTask(
+                    mMtpManager, mDatabase, mDevice.operationsSupported, identifier);
+            newTask.loadObjectHandles();
+            mTaskList.addFirst(newTask);
+            return newTask;
+        }
+
+        mBackgroundThread = null;
+        return null;
+    }
+
+    /**
+     * Terminates background thread.
+     */
+    @Override
+    public void close() throws InterruptedException {
+        final Thread thread;
+        synchronized (this) {
+            mTaskList.clear();
+            thread = mBackgroundThread;
+        }
+        if (thread != null) {
+            thread.interrupt();
+            thread.join();
+        }
     }
 
     synchronized void clearCompletedTasks() {
@@ -121,42 +165,37 @@
         mTaskList.clearTask(parentIdentifier);
     }
 
+    /**
+     * Background thread to fetch object info.
+     */
     private class BackgroundLoaderThread extends Thread {
+        /**
+         * Finds task that needs to be processed, then loads NUM_LOADING_ENTRIES of object info and
+         * store them to the database. If it does not find a task, exits the thread.
+         */
         @Override
         public void run() {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            while (true) {
-                LoaderTask task;
-                int deviceId;
-                int[] handles;
-                synchronized (DocumentLoader.this) {
-                    task = mTaskList.findRunningTask();
-                    if (task == null) {
-                        mHasBackgroundThread = false;
-                        return;
-                    }
-                    deviceId = task.mIdentifier.mDeviceId;
-                    handles = task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES);
+            while (!Thread.interrupted()) {
+                final LoaderTask task = getNextTaskOrReleaseBackgroundThread();
+                if (task == null) {
+                    return;
                 }
-
-                try {
-                    final MtpObjectInfo[] objectInfos =
-                            loadDocuments(mMtpManager, deviceId, handles);
-                    task.fillDocuments(objectInfos);
-                    final boolean shouldNotify =
-                            task.mLastNotified.getTime() <
-                            new Date().getTime() - NOTIFY_PERIOD_MS ||
-                            task.getState() != LoaderTask.STATE_LOADING;
-                    if (shouldNotify) {
-                        task.notify(mResolver);
-                    }
-                } catch (IOException exception) {
-                    task.setError(exception);
+                task.loadObjectInfoList(NUM_LOADING_ENTRIES);
+                final boolean shouldNotify =
+                        task.mLastNotified.getTime() <
+                        new Date().getTime() - NOTIFY_PERIOD_MS ||
+                        task.getState() != LoaderTask.STATE_LOADING;
+                if (shouldNotify) {
+                    task.notify(mResolver);
                 }
             }
         }
     }
 
+    /**
+     * Task list that has helper methods to search/clear tasks.
+     */
     private static class TaskList extends LinkedList<LoaderTask> {
         LoaderTask findTask(Identifier parent) {
             for (int i = 0; i < size(); i++) {
@@ -197,34 +236,72 @@
         }
     }
 
+    /**
+     * Loader task.
+     * Each task is responsible for fetching child documents for the given parent document.
+     */
     private static class LoaderTask {
-        static final int STATE_LOADING = 0;
-        static final int STATE_COMPLETED = 1;
-        static final int STATE_ERROR = 2;
+        static final int STATE_START = 0;
+        static final int STATE_LOADING = 1;
+        static final int STATE_COMPLETED = 2;
+        static final int STATE_ERROR = 3;
 
+        final MtpManager mManager;
         final MtpDatabase mDatabase;
+        final int[] mOperationsSupported;
         final Identifier mIdentifier;
-        final int[] mObjectHandles;
+        int[] mObjectHandles;
+        int mState;
         Date mLastNotified;
-        int mNumLoaded;
-        Exception mError;
+        int mPosition;
+        IOException mError;
 
-        LoaderTask(MtpDatabase database, Identifier identifier, int[] objectHandles) {
+        LoaderTask(MtpManager manager, MtpDatabase database, int[] operationsSupported,
+                Identifier identifier) {
+            assert operationsSupported != null;
+            assert identifier.mDocumentType != MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE;
+            mManager = manager;
             mDatabase = database;
+            mOperationsSupported = operationsSupported;
             mIdentifier = identifier;
-            mObjectHandles = objectHandles;
-            mNumLoaded = 0;
+            mObjectHandles = null;
+            mState = STATE_START;
+            mPosition = 0;
             mLastNotified = new Date();
         }
 
-        Cursor createCursor(ContentResolver resolver, String[] columnNames) throws IOException {
+        synchronized void loadObjectHandles() {
+            assert mState == STATE_START;
+            int parentHandle = mIdentifier.mObjectHandle;
+            // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
+            // getObjectHandles if we would like to obtain children under the root.
+            if (mIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
+                parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
+            }
+            try {
+                mObjectHandles = mManager.getObjectHandles(
+                        mIdentifier.mDeviceId, mIdentifier.mStorageId, parentHandle);
+                mState = STATE_LOADING;
+            } catch (IOException error) {
+                mError = error;
+                mState = STATE_ERROR;
+            }
+        }
+
+        /**
+         * Returns a cursor that traverses the child document of the parent document handled by the
+         * task.
+         * The returned task may have a EXTRA_LOADING flag.
+         */
+        synchronized Cursor createCursor(ContentResolver resolver, String[] columnNames)
+                throws IOException {
             final Bundle extras = new Bundle();
             switch (getState()) {
                 case STATE_LOADING:
                     extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
                     break;
                 case STATE_ERROR:
-                    throw new IOException(mError);
+                    throw mError;
             }
 
             final Cursor cursor =
@@ -235,65 +312,111 @@
             return cursor;
         }
 
-        int getState() {
-            if (mError != null) {
-                return STATE_ERROR;
-            } else if (mNumLoaded == mObjectHandles.length) {
-                return STATE_COMPLETED;
-            } else {
-                return STATE_LOADING;
+        /**
+         * Stores object information into database.
+         */
+        void loadObjectInfoList(int count) {
+            synchronized (this) {
+                if (mState != STATE_LOADING) {
+                    return;
+                }
+                if (mPosition == 0) {
+                    try{
+                        mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
+                    } catch (FileNotFoundException error) {
+                        mError = error;
+                        mState = STATE_ERROR;
+                        return;
+                    }
+                }
+            }
+            final ArrayList<MtpObjectInfo> infoList = new ArrayList<>();
+            for (int chunkEnd = mPosition + count;
+                    mPosition < mObjectHandles.length && mPosition < chunkEnd;
+                    mPosition++) {
+                try {
+                    infoList.add(mManager.getObjectInfo(
+                            mIdentifier.mDeviceId, mObjectHandles[mPosition]));
+                } catch (IOException error) {
+                    Log.e(MtpDocumentsProvider.TAG, "Failed to load object info", error);
+                }
+            }
+            final long[] objectSizeList = new long[infoList.size()];
+            for (int i = 0; i < infoList.size(); i++) {
+                final MtpObjectInfo info = infoList.get(i);
+                // Compressed size is 32-bit unsigned integer but getCompressedSize returns the
+                // value in Java int (signed 32-bit integer). Use getCompressedSizeLong instead
+                // to get the value in Java long.
+                if (info.getCompressedSizeLong() != 0xffffffffl) {
+                    objectSizeList[i] = info.getCompressedSizeLong();
+                    continue;
+                }
+
+                if (!MtpDeviceRecord.isSupported(
+                        mOperationsSupported,
+                        MtpConstants.OPERATION_GET_OBJECT_PROP_DESC) ||
+                        !MtpDeviceRecord.isSupported(
+                                mOperationsSupported,
+                                MtpConstants.OPERATION_GET_OBJECT_PROP_VALUE)) {
+                    objectSizeList[i] = -1;
+                    continue;
+                }
+
+                // Object size is more than 4GB.
+                try {
+                    objectSizeList[i] = mManager.getObjectSizeLong(
+                            mIdentifier.mDeviceId,
+                            info.getObjectHandle(),
+                            info.getFormat());
+                } catch (IOException error) {
+                    Log.e(MtpDocumentsProvider.TAG, "Failed to get object size property.", error);
+                    objectSizeList[i] = -1;
+                }
+            }
+            synchronized (this) {
+                try {
+                    mDatabase.getMapper().putChildDocuments(
+                            mIdentifier.mDeviceId,
+                            mIdentifier.mDocumentId,
+                            mOperationsSupported,
+                            infoList.toArray(new MtpObjectInfo[infoList.size()]),
+                            objectSizeList);
+                } catch (FileNotFoundException error) {
+                    // Looks like the parent document information is removed.
+                    // Adding documents has already cancelled in Mapper so we don't need to invoke
+                    // stopAddingDocuments.
+                    mError = error;
+                    mState = STATE_ERROR;
+                    return;
+                }
+                if (mPosition >= mObjectHandles.length) {
+                    try{
+                        mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+                        mState = STATE_COMPLETED;
+                    } catch (FileNotFoundException error) {
+                        mError = error;
+                        mState = STATE_ERROR;
+                        return;
+                    }
+                }
             }
         }
 
-        int[] getUnloadedObjectHandles(int count) {
-            return Arrays.copyOfRange(
-                    mObjectHandles,
-                    mNumLoaded,
-                    Math.min(mNumLoaded + count, mObjectHandles.length));
+        /**
+         * Returns a state of the task.
+         */
+        int getState() {
+            return mState;
         }
 
+        /**
+         * Notifies a change of child list of the document.
+         */
         void notify(ContentResolver resolver) {
             resolver.notifyChange(createUri(), null, false);
             mLastNotified = new Date();
         }
 
-        void fillDocuments(MtpObjectInfo[] objectInfoList) {
-            if (objectInfoList.length == 0 || getState() != STATE_LOADING) {
-                return;
-            }
-            try{
-                if (mNumLoaded == 0) {
-                    mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
-                }
-                mDatabase.getMapper().putChildDocuments(
-                        mIdentifier.mDeviceId, mIdentifier.mDocumentId, objectInfoList);
-                mNumLoaded += objectInfoList.length;
-                if (getState() != STATE_LOADING) {
-                    mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
-                }
-            } catch (FileNotFoundException exception) {
-                setErrorInternal(exception);
-            }
-        }
-
-        void setError(Exception error) {
-            final int lastState = getState();
-            setErrorInternal(error);
-            if (lastState == STATE_LOADING) {
-                try {
-                    mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
-                } catch (FileNotFoundException exception) {
-                    setErrorInternal(exception);
-                }
-            }
-        }
-
-        private void setErrorInternal(Exception error) {
-            Log.e(MtpDocumentsProvider.TAG, "Error in DocumentLoader thread", error);
-            mError = error;
-            mNumLoaded = 0;
-        }
-
         private Uri createUri() {
             return DocumentsContract.buildChildDocumentsUri(
                     MtpDocumentsProvider.AUTHORITY, mIdentifier.mDocumentId);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
index 5e3417a..adc71ae 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
@@ -89,7 +89,8 @@
      * @return If roots are added or removed from the database.
      * @throws FileNotFoundException
      */
-    synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots)
+    synchronized boolean putStorageDocuments(
+            String parentDocumentId, int[] operationsSupported, MtpRoot[] roots)
             throws FileNotFoundException {
         final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
         database.beginTransaction();
@@ -100,7 +101,11 @@
                 valuesList[i] = new ContentValues();
                 extraValuesList[i] = new ContentValues();
                 MtpDatabase.getStorageDocumentValues(
-                        valuesList[i], extraValuesList[i], parentDocumentId, roots[i]);
+                        valuesList[i],
+                        extraValuesList[i],
+                        parentDocumentId,
+                        operationsSupported,
+                        roots[i]);
             }
             final boolean changed = putDocuments(
                     parentDocumentId,
@@ -123,14 +128,27 @@
      * @param deviceId Device ID
      * @param parentId Parent document ID.
      * @param documents List of document information.
+     * @param documentSizes 64-bit size of documents. MtpObjectInfo#getComporessedSize will be
+     *     ignored because it does not contain 4GB> object size. Can be -1 if the size is unknown.
      * @throws FileNotFoundException
      */
-    synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents)
+    synchronized void putChildDocuments(
+            int deviceId, String parentId,
+            int[] operationsSupported,
+            MtpObjectInfo[] documents,
+            long[] documentSizes)
             throws FileNotFoundException {
+        assert documents.length == documentSizes.length;
         final ContentValues[] valuesList = new ContentValues[documents.length];
         for (int i = 0; i < documents.length; i++) {
             valuesList[i] = new ContentValues();
-            MtpDatabase.getObjectDocumentValues(valuesList[i], deviceId, parentId, documents[i]);
+            MtpDatabase.getObjectDocumentValues(
+                    valuesList[i],
+                    deviceId,
+                    parentId,
+                    operationsSupported,
+                    documents[i],
+                    documentSizes[i]);
         }
         putDocuments(
                 parentId,
@@ -162,9 +180,8 @@
 
     /**
      * Starts adding new documents.
-     * The methods decides mapping mode depends on if all documents under the given parent have MTP
-     * identifier or not. If all the documents have MTP identifier, it uses the identifier to find
-     * a corresponding existing row. Otherwise it does heuristic.
+     * It changes the direct child documents of the given document from VALID to INVALIDATED.
+     * Note that it keeps DISCONNECTED documents as they are.
      *
      * @param parentDocumentId Parent document ID or NULL for root documents.
      * @throws FileNotFoundException
@@ -286,12 +303,16 @@
     }
 
     /**
-     * Maps 'pending' document and 'invalidated' document that shares the same column of groupKey.
-     * If the database does not find corresponding 'invalidated' document, it just removes
-     * 'invalidated' document from the database.
+     * Stops adding documents.
+     * It handles 'invalidated' and 'disconnected' documents which we don't put corresponding
+     * documents so far.
+     * If the type adding document is 'device' or 'storage', the document may appear again
+     * afterward. The method marks such documents as 'disconnected'. If the type of adding document
+     * is 'object', it seems the documents are really removed from the remote MTP device. So the
+     * method deletes the metadata from the database.
      *
      * @param parentId Parent document ID or null for root documents.
-     * @return Whether the methods adds or removed visible rows.
+     * @return Whether the methods changes file metadata in database.
      * @throws FileNotFoundException
      */
     boolean stopAddingDocuments(@Nullable String parentId) throws FileNotFoundException {
@@ -313,7 +334,9 @@
             mInMappingIds.remove(parentId);
 
             boolean changed = false;
-            // Delete/disconnect all invalidated rows that cannot be mapped.
+            // Delete/disconnect all invalidated/disconnected rows that cannot be mapped.
+            // If parentIdentifier is null, added documents are devices.
+            // if parentIdentifier is DOCUMENT_TYPE_DEVICE, added documents are storages.
             final boolean keepUnmatchedDocument =
                     parentIdentifier == null ||
                     parentIdentifier.mDocumentType == DOCUMENT_TYPE_DEVICE;
@@ -325,8 +348,9 @@
                 }
             } else {
                 if (mDatabase.deleteDocumentsAndRootsRecursively(
-                        COLUMN_ROW_STATE + " = ? AND " + selection,
-                        DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
+                        COLUMN_ROW_STATE + " IN (?, ?) AND " + selection,
+                        DatabaseUtils.appendSelectionArgs(
+                                strings(ROW_STATE_INVALIDATED, ROW_STATE_DISCONNECTED), args))) {
                     changed = true;
                 }
             }
@@ -404,12 +428,7 @@
             return null;
         }
         try {
-            final Identifier identifier = mDatabase.createIdentifier(parentId);
-            if (mDatabase.getRowState(parentId) == ROW_STATE_DISCONNECTED) {
-                throw new FileNotFoundException(
-                        "document: " + parentId + " is in disconnected device.");
-            }
-            return identifier;
+            return mDatabase.createIdentifier(parentId);
         } catch (FileNotFoundException error) {
             mInMappingIds.remove(parentId);
             throw error;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index ca5c799..cce619e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -32,6 +32,7 @@
 import android.media.MediaFile;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
+import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
@@ -40,7 +41,9 @@
 import com.android.internal.util.Preconditions;
 
 import java.io.FileNotFoundException;
+import java.util.HashSet;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Database for MTP objects.
@@ -369,11 +372,16 @@
      * newly added and never mapped with existing ones.
      * @param parentDocumentId
      * @param info
+     * @param size Object size. info#getCompressedSize() will be ignored because it does not contain
+     *     object size more than 4GB.
      * @return Document ID of added document.
      */
-    String putNewDocument(int deviceId, String parentDocumentId, MtpObjectInfo info) {
+    String putNewDocument(
+            int deviceId, String parentDocumentId, int[] operationsSupported, MtpObjectInfo info,
+            long size) {
         final ContentValues values = new ContentValues();
-        getObjectDocumentValues(values, deviceId, parentDocumentId, info);
+        getObjectDocumentValues(
+                values, deviceId, parentDocumentId, operationsSupported, info, size);
         mDatabase.beginTransaction();
         try {
             final long id = mDatabase.insert(TABLE_DOCUMENTS, null, values);
@@ -406,15 +414,15 @@
                         COLUMN_STORAGE_ID,
                         COLUMN_OBJECT_HANDLE,
                         COLUMN_DOCUMENT_TYPE),
-                SELECTION_DOCUMENT_ID,
-                strings(documentId),
+                SELECTION_DOCUMENT_ID + " AND " + COLUMN_ROW_STATE + " IN (?, ?)",
+                strings(documentId, ROW_STATE_VALID, ROW_STATE_INVALIDATED),
                 null,
                 null,
                 null,
                 "1");
         try {
             if (cursor.getCount() == 0) {
-                throw new FileNotFoundException("ID is not found.");
+                throw new FileNotFoundException("ID \"" + documentId + "\" is not found.");
             } else {
                 cursor.moveToNext();
                 return new Identifier(
@@ -581,9 +589,10 @@
         }
     }
 
-    void updateObject(String documentId, int deviceId, String parentId, MtpObjectInfo info) {
+    void updateObject(String documentId, int deviceId, String parentId, int[] operationsSupported,
+                      MtpObjectInfo info, Long size) {
         final ContentValues values = new ContentValues();
-        getObjectDocumentValues(values, deviceId, parentId, info);
+        getObjectDocumentValues(values, deviceId, parentId, operationsSupported, info, size);
 
         mDatabase.beginTransaction();
         try {
@@ -598,6 +607,108 @@
         }
     }
 
+    /**
+     * Obtains a document that has already mapped but has unmapped children.
+     * @param deviceId Device to find documents.
+     * @return Identifier of found document or null.
+     */
+    @Nullable Identifier getUnmappedDocumentsParent(int deviceId) {
+        final String fromClosure =
+                TABLE_DOCUMENTS + " AS child INNER JOIN " +
+                TABLE_DOCUMENTS + " AS parent ON " +
+                "child." + COLUMN_PARENT_DOCUMENT_ID + " = " +
+                "parent." + Document.COLUMN_DOCUMENT_ID;
+        final String whereClosure =
+                "parent." + COLUMN_DEVICE_ID + " = ? AND " +
+                "parent." + COLUMN_ROW_STATE + " IN (?, ?) AND " +
+                "parent." + COLUMN_DOCUMENT_TYPE + " != ? AND " +
+                "child." + COLUMN_ROW_STATE + " = ?";
+        try (final Cursor cursor = mDatabase.query(
+                fromClosure,
+                strings("parent." + COLUMN_DEVICE_ID,
+                        "parent." + COLUMN_STORAGE_ID,
+                        "parent." + COLUMN_OBJECT_HANDLE,
+                        "parent." + Document.COLUMN_DOCUMENT_ID,
+                        "parent." + COLUMN_DOCUMENT_TYPE),
+                whereClosure,
+                strings(deviceId, ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_DEVICE,
+                        ROW_STATE_DISCONNECTED),
+                null,
+                null,
+                null,
+                "1")) {
+            if (cursor.getCount() == 0) {
+                return null;
+            }
+            cursor.moveToNext();
+            return new Identifier(
+                    cursor.getInt(0),
+                    cursor.getInt(1),
+                    cursor.getInt(2),
+                    cursor.getString(3),
+                    cursor.getInt(4));
+        }
+    }
+
+    /**
+     * Removes metadata except for data used by outgoingPersistedUriPermissions.
+     */
+    void cleanDatabase(Uri[] outgoingPersistedUris) {
+        mDatabase.beginTransaction();
+        try {
+            final Set<String> ids = new HashSet<>();
+            for (final Uri uri : outgoingPersistedUris) {
+                String documentId = DocumentsContract.getDocumentId(uri);
+                while (documentId != null) {
+                    if (ids.contains(documentId)) {
+                        break;
+                    }
+                    ids.add(documentId);
+                    try (final Cursor cursor = mDatabase.query(
+                            TABLE_DOCUMENTS,
+                            strings(COLUMN_PARENT_DOCUMENT_ID),
+                            SELECTION_DOCUMENT_ID,
+                            strings(documentId),
+                            null,
+                            null,
+                            null)) {
+                        documentId = cursor.moveToNext() ? cursor.getString(0) : null;
+                    }
+                }
+            }
+            deleteDocumentsAndRoots(
+                    Document.COLUMN_DOCUMENT_ID + " NOT IN " + getIdList(ids), null);
+            mDatabase.setTransactionSuccessful();
+        } finally {
+            mDatabase.endTransaction();
+        }
+    }
+
+    int getLastBootCount() {
+        try (final Cursor cursor = mDatabase.query(
+                TABLE_LAST_BOOT_COUNT, strings(COLUMN_VALUE), null, null, null, null, null)) {
+            if (cursor.moveToNext()) {
+                return cursor.getInt(0);
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    void setLastBootCount(int value) {
+        Preconditions.checkArgumentNonnegative(value, "Boot count must not be negative.");
+        mDatabase.beginTransaction();
+        try {
+            final ContentValues values = new ContentValues();
+            values.put(COLUMN_VALUE, value);
+            mDatabase.delete(TABLE_LAST_BOOT_COUNT, null, null);
+            mDatabase.insert(TABLE_LAST_BOOT_COUNT, null, values);
+            mDatabase.setTransactionSuccessful();
+        } finally {
+            mDatabase.endTransaction();
+        }
+    }
+
     private static class OpenHelper extends SQLiteOpenHelper {
         public OpenHelper(Context context, int flags) {
             super(context,
@@ -610,12 +721,14 @@
         public void onCreate(SQLiteDatabase db) {
             db.execSQL(QUERY_CREATE_DOCUMENTS);
             db.execSQL(QUERY_CREATE_ROOT_EXTRA);
+            db.execSQL(QUERY_CREATE_LAST_BOOT_COUNT);
         }
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            db.execSQL("DROP TABLE " + TABLE_DOCUMENTS);
-            db.execSQL("DROP TABLE " + TABLE_ROOT_EXTRA);
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_DOCUMENTS);
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_ROOT_EXTRA);
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_LAST_BOOT_COUNT);
             onCreate(db);
         }
     }
@@ -642,13 +755,16 @@
         values.putNull(Document.COLUMN_SUMMARY);
         values.putNull(Document.COLUMN_LAST_MODIFIED);
         values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
-        values.put(Document.COLUMN_FLAGS, 0);
+        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
+                device.operationsSupported,
+                Document.MIME_TYPE_DIR,
+                0,
+                MtpConstants.PROTECTION_STATUS_NONE,
+                DOCUMENT_TYPE_DEVICE));
         values.putNull(Document.COLUMN_SIZE);
 
         extraValues.clear();
-        extraValues.put(
-                Root.COLUMN_FLAGS,
-                Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+        extraValues.put(Root.COLUMN_FLAGS, getRootFlags(device.operationsSupported));
         extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES);
         extraValues.putNull(Root.COLUMN_CAPACITY_BYTES);
         extraValues.put(Root.COLUMN_MIME_TYPES, "");
@@ -657,12 +773,16 @@
     /**
      * Gets {@link ContentValues} for the given root.
      * @param values {@link ContentValues} that receives values.
+     * @param extraValues {@link ContentValues} that receives extra values for roots.
+     * @param parentDocumentId Parent document ID.
+     * @param operationsSupported Array of Operation code supported by the device.
      * @param root Root to be converted {@link ContentValues}.
      */
     static void getStorageDocumentValues(
             ContentValues values,
             ContentValues extraValues,
             String parentDocumentId,
+            int[] operationsSupported,
             MtpRoot root) {
         values.clear();
         values.put(COLUMN_DEVICE_ID, root.mDeviceId);
@@ -676,12 +796,15 @@
         values.putNull(Document.COLUMN_SUMMARY);
         values.putNull(Document.COLUMN_LAST_MODIFIED);
         values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
-        values.put(Document.COLUMN_FLAGS, 0);
+        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
+                operationsSupported,
+                Document.MIME_TYPE_DIR,
+                0,
+                MtpConstants.PROTECTION_STATUS_NONE,
+                DOCUMENT_TYPE_STORAGE));
         values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace);
 
-        extraValues.put(
-                Root.COLUMN_FLAGS,
-                Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+        extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported));
         extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
         extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
         extraValues.put(Root.COLUMN_MIME_TYPES, "");
@@ -692,23 +815,14 @@
      * @param values {@link ContentValues} that receives values.
      * @param deviceId Device ID of the object.
      * @param parentId Parent document ID of the object.
-     * @param info MTP object info.
+     * @param info MTP object info. getCompressedSize will be ignored.
+     * @param size 64-bit size of documents. Negative value is regarded as unknown size.
      */
     static void getObjectDocumentValues(
-            ContentValues values, int deviceId, String parentId, MtpObjectInfo info) {
+            ContentValues values, int deviceId, String parentId,
+            int[] operationsSupported, MtpObjectInfo info, long size) {
         values.clear();
         final String mimeType = getMimeType(info);
-        int flag = 0;
-        if (info.getProtectionStatus() == 0) {
-            flag |= Document.FLAG_SUPPORTS_DELETE |
-                    Document.FLAG_SUPPORTS_WRITE;
-            if (mimeType == Document.MIME_TYPE_DIR) {
-                flag |= Document.FLAG_DIR_SUPPORTS_CREATE;
-            }
-        }
-        if (info.getThumbCompressedSize() > 0) {
-            flag |= Document.FLAG_SUPPORTS_THUMBNAIL;
-        }
         values.put(COLUMN_DEVICE_ID, deviceId);
         values.put(COLUMN_STORAGE_ID, info.getStorageId());
         values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle());
@@ -722,19 +836,35 @@
                 Document.COLUMN_LAST_MODIFIED,
                 info.getDateModified() != 0 ? info.getDateModified() : null);
         values.putNull(Document.COLUMN_ICON);
-        values.put(Document.COLUMN_FLAGS, flag);
-        values.put(Document.COLUMN_SIZE, info.getCompressedSize());
+        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
+                operationsSupported, mimeType, info.getThumbCompressedSizeLong(),
+                info.getProtectionStatus(), DOCUMENT_TYPE_OBJECT));
+        if (size >= 0) {
+            values.put(Document.COLUMN_SIZE, size);
+        } else {
+            values.putNull(Document.COLUMN_SIZE);
+        }
     }
 
     private static String getMimeType(MtpObjectInfo info) {
         if (info.getFormat() == MtpConstants.FORMAT_ASSOCIATION) {
             return DocumentsContract.Document.MIME_TYPE_DIR;
         }
+
         final String formatCodeMimeType = MediaFile.getMimeTypeForFormatCode(info.getFormat());
+        final String mediaFileMimeType = MediaFile.getMimeTypeForFile(info.getName());
+
+        // Format code can be mapped with multiple mime types, e.g. FORMAT_MPEG is mapped with
+        // audio/mp4 and video/mp4.
+        // As file extension contains more information than format code, returns mime type obtained
+        // from file extension if it is consistent with format code.
+        if (mediaFileMimeType != null &&
+                MediaFile.getFormatCode("", mediaFileMimeType) == info.getFormat()) {
+            return mediaFileMimeType;
+        }
         if (formatCodeMimeType != null) {
             return formatCodeMimeType;
         }
-        final String mediaFileMimeType = MediaFile.getMimeTypeForFile(info.getName());
         if (mediaFileMimeType != null) {
             return mediaFileMimeType;
         }
@@ -742,6 +872,41 @@
         return "application/octet-stream";
     }
 
+    private static int getRootFlags(int[] operationsSupported) {
+        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD;
+        if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
+            rootFlag |= Root.FLAG_SUPPORTS_CREATE;
+        }
+        return rootFlag;
+    }
+
+    private static int getDocumentFlags(
+            @Nullable int[] operationsSupported, String mimeType, long thumbnailSize,
+            int protectionState, @DocumentType int documentType) {
+        int flag = 0;
+        if (!mimeType.equals(Document.MIME_TYPE_DIR) &&
+                MtpDeviceRecord.isWritingSupported(operationsSupported) &&
+                protectionState == MtpConstants.PROTECTION_STATUS_NONE) {
+            flag |= Document.FLAG_SUPPORTS_WRITE;
+        }
+        if (MtpDeviceRecord.isSupported(
+                operationsSupported, MtpConstants.OPERATION_DELETE_OBJECT) &&
+                (protectionState == MtpConstants.PROTECTION_STATUS_NONE ||
+                 protectionState == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA) &&
+                documentType == DOCUMENT_TYPE_OBJECT) {
+            flag |= Document.FLAG_SUPPORTS_DELETE;
+        }
+        if (mimeType.equals(Document.MIME_TYPE_DIR) &&
+                MtpDeviceRecord.isWritingSupported(operationsSupported) &&
+                protectionState == MtpConstants.PROTECTION_STATUS_NONE) {
+            flag |= Document.FLAG_DIR_SUPPORTS_CREATE;
+        }
+        if (thumbnailSize > 0) {
+            flag |= Document.FLAG_SUPPORTS_THUMBNAIL;
+        }
+        return flag;
+    }
+
     static String[] strings(Object... args) {
         final String[] results = new String[args.length];
         for (int i = 0; i < args.length; i++) {
@@ -749,4 +914,16 @@
         }
         return results;
     }
+
+    private static String getIdList(Set<String> ids) {
+        String result = "(";
+        for (final String id : ids) {
+            if (result.length() > 1) {
+                result += ",";
+            }
+            result += id;
+        }
+        result += ")";
+        return result;
+    }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index ff4b89f..6d98e34 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -30,7 +30,7 @@
  * Class containing MtpDatabase constants.
  */
 class MtpDatabaseConstants {
-    static final int DATABASE_VERSION = 4;
+    static final int DATABASE_VERSION = 5;
     static final String DATABASE_NAME = "database";
 
     static final int FLAG_DATABASE_IN_MEMORY = 1;
@@ -48,6 +48,11 @@
     static final String TABLE_ROOT_EXTRA = "RootExtra";
 
     /**
+     * Table containing last boot count.
+     */
+    static final String TABLE_LAST_BOOT_COUNT = "LastBootCount";
+
+    /**
      * 'FROM' closure of joining TABLE_DOCUMENTS and TABLE_ROOT_EXTRA.
      */
     static final String JOIN_ROOTS = createJoinFromClosure(
@@ -62,7 +67,13 @@
     static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id";
     static final String COLUMN_DOCUMENT_TYPE = "document_type";
     static final String COLUMN_ROW_STATE = "row_state";
-    static final String COLUMN_MAPPING_KEY = "column_mapping_key";
+    static final String COLUMN_MAPPING_KEY = "mapping_key";
+
+    /**
+     * Value for TABLE_LAST_BOOT_COUNT.
+     * Type: INTEGER
+     */
+    static final String COLUMN_VALUE = "value";
 
     /**
      * The state represents that the row has a valid object handle.
@@ -133,6 +144,9 @@
             Root.COLUMN_CAPACITY_BYTES + " INTEGER," +
             Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);";
 
+    static final String QUERY_CREATE_LAST_BOOT_COUNT =
+            "CREATE TABLE " + TABLE_LAST_BOOT_COUNT + " (value INTEGER NOT NULL);";
+
     /**
      * Map for columns names to provide DocumentContract.Root compatible columns.
      * @see SQLiteQueryBuilder#setProjectionMap(Map)
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
index 71716bd..c52b81d 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
@@ -17,6 +17,7 @@
 package com.android.mtp;
 
 import android.annotation.Nullable;
+import android.mtp.MtpConstants;
 
 class MtpDeviceRecord {
     public final int deviceId;
@@ -38,4 +39,36 @@
         this.operationsSupported = operationsSupported;
         this.eventsSupported = eventsSupported;
     }
+
+    /**
+     * Helper method to check operations/events are supported by the device or not.
+     */
+    static boolean isSupported(@Nullable int[] supportedList, int code) {
+        if (supportedList == null) {
+            return false;
+        }
+        for (int i = 0; i < supportedList.length; i++) {
+            if (supportedList[i] == code) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static boolean isPartialReadSupported(@Nullable int[] supportedList, long fileSize) {
+        if (isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
+            return true;
+        }
+        if (0 <= fileSize &&
+                fileSize <= 0xffffffffL &&
+                isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
+            return true;
+        }
+        return false;
+    }
+
+    static boolean isWritingSupported(@Nullable int[] supportedList) {
+        return isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT_INFO) &&
+                isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT);
+    }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index d329e3c..50781bf 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -17,32 +17,44 @@
 package com.android.mtp;
 
 import android.content.ContentResolver;
+import android.content.Context;
+import android.content.UriPermission;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.database.sqlite.SQLiteDiskIOException;
 import android.graphics.Point;
 import android.media.MediaFile;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.storage.StorageManager;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
+import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.mtp.exceptions.BusyDeviceException;
 
+import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeoutException;
 
 /**
  * DocumentsProvider for MTP devices.
@@ -76,6 +88,7 @@
     private MtpDatabase mDatabase;
     private AppFuse mAppFuse;
     private ServiceIntentSender mIntentSender;
+    private Context mContext;
 
     /**
      * Provides singleton instance to MtpDocumentsService.
@@ -87,6 +100,7 @@
     @Override
     public boolean onCreate() {
         sSingleton = this;
+        mContext = getContext();
         mResources = getContext().getResources();
         mMtpManager = new MtpManager(getContext());
         mResolver = getContext().getContentResolver();
@@ -95,25 +109,50 @@
         mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
         mAppFuse = new AppFuse(TAG, new AppFuseCallback());
         mIntentSender = new ServiceIntentSender(getContext());
+
+        // Check boot count and cleans database if it's first time to launch MtpDocumentsProvider
+        // after booting.
+        try {
+            final int bootCount = Settings.Global.getInt(mResolver, Settings.Global.BOOT_COUNT, -1);
+            final int lastBootCount = mDatabase.getLastBootCount();
+            if (bootCount != -1 && bootCount != lastBootCount) {
+                mDatabase.setLastBootCount(bootCount);
+                final List<UriPermission> permissions =
+                        mResolver.getOutgoingPersistedUriPermissions();
+                final Uri[] uris = new Uri[permissions.size()];
+                for (int i = 0; i < permissions.size(); i++) {
+                    uris[i] = permissions.get(i).getUri();
+                }
+                mDatabase.cleanDatabase(uris);
+            }
+        } catch (SQLiteDiskIOException error) {
+            // It can happen due to disk shortage.
+            Log.e(TAG, "Failed to clean database.", error);
+            return false;
+        }
+
         // TODO: Mount AppFuse on demands.
         try {
             mAppFuse.mount(getContext().getSystemService(StorageManager.class));
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to start app fuse.", e);
+        } catch (IOException error) {
+            Log.e(TAG, "Failed to start app fuse.", error);
             return false;
         }
+
         resume();
         return true;
     }
 
     @VisibleForTesting
     boolean onCreateForTesting(
+            Context context,
             Resources resources,
             MtpManager mtpManager,
             ContentResolver resolver,
             MtpDatabase database,
             StorageManager storageManager,
             ServiceIntentSender intentSender) {
+        mContext = context;
         mResources = resources;
         mMtpManager = mtpManager;
         mResolver = resolver;
@@ -122,6 +161,7 @@
         mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
         mAppFuse = new AppFuse(TAG, new AppFuseCallback());
         mIntentSender = intentSender;
+
         // TODO: Mount AppFuse on demands.
         try {
             mAppFuse.mount(storageManager);
@@ -201,33 +241,44 @@
         final Identifier identifier = mDatabase.createIdentifier(documentId);
         try {
             openDevice(identifier.mDeviceId);
-            switch (mode) {
-                case "r":
-                    final long fileSize = getFileSize(documentId);
-                    // MTP getPartialObject operation does not support files that are larger than
-                    // 4GB. Fallback to non-seekable file descriptor.
-                    // TODO: Use getPartialObject64 for MTP devices that support Android vendor
-                    // extension.
-                    if (fileSize <= 0xffffffffl) {
-                        return mAppFuse.openFile(Integer.parseInt(documentId));
-                    } else {
-                        return getPipeManager(identifier).readDocument(mMtpManager, identifier);
-                    }
-                case "w":
-                    // TODO: Clear the parent document loader task (if exists) and call notify
-                    // when writing is completed.
-                    return getPipeManager(identifier).writeDocument(
-                            getContext(), mMtpManager, identifier);
-                case "rw":
-                    // TODO: Add support for "rw" mode.
+            final MtpDeviceRecord device = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
+            // Turn off MODE_CREATE because openDocument does not allow to create new files.
+            final int modeFlag =
+                    ParcelFileDescriptor.parseMode(mode) & ~ParcelFileDescriptor.MODE_CREATE;
+            if ((modeFlag & ParcelFileDescriptor.MODE_READ_ONLY) != 0) {
+                long fileSize;
+                try {
+                    fileSize = getFileSize(documentId);
+                } catch (UnsupportedOperationException exception) {
+                    fileSize = -1;
+                }
+                if (MtpDeviceRecord.isPartialReadSupported(
+                        device.operationsSupported, fileSize)) {
+                    return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+                } else {
+                    // If getPartialObject{|64} are not supported for the device, returns
+                    // non-seekable pipe FD instead.
+                    return getPipeManager(identifier).readDocument(mMtpManager, identifier);
+                }
+            } else if ((modeFlag & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0) {
+                // TODO: Clear the parent document loader task (if exists) and call notify
+                // when writing is completed.
+                if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
+                    return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+                } else {
                     throw new UnsupportedOperationException(
-                            "The provider does not support 'rw' mode.");
-                default:
-                    throw new IllegalArgumentException("Unknown mode for openDocument: " + mode);
+                            "The device does not support writing operation.");
+                }
+            } else {
+                // TODO: Add support for "rw" mode.
+                throw new UnsupportedOperationException("The provider does not support 'rw' mode.");
             }
+        } catch (FileNotFoundException | RuntimeException error) {
+            Log.e(MtpDocumentsProvider.TAG, "openDocument", error);
+            throw error;
         } catch (IOException error) {
             Log.e(MtpDocumentsProvider.TAG, "openDocument", error);
-            throw new FileNotFoundException(error.getMessage());
+            throw new IllegalStateException(error);
         }
     }
 
@@ -287,31 +338,79 @@
         if (DEBUG) {
             Log.d(TAG, "createDocument: " + displayName);
         }
+        final Identifier parentId;
+        final MtpDeviceRecord record;
+        final ParcelFileDescriptor[] pipe;
         try {
-            final Identifier parentId = mDatabase.createIdentifier(parentDocumentId);
+            parentId = mDatabase.createIdentifier(parentDocumentId);
             openDevice(parentId.mDeviceId);
-            final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
-            pipe[0].close();  // 0 bytes for a new document.
-            final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
-                    MtpConstants.FORMAT_ASSOCIATION :
-                    MediaFile.getFormatCode(displayName, mimeType);
-            final MtpObjectInfo info = new MtpObjectInfo.Builder()
-                    .setStorageId(parentId.mStorageId)
-                    .setParent(parentId.mObjectHandle)
-                    .setFormat(formatCode)
-                    .setName(displayName)
-                    .build();
-            final int objectHandle = mMtpManager.createDocument(parentId.mDeviceId, info, pipe[1]);
+            record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
+            if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) {
+                throw new UnsupportedOperationException(
+                        "Writing operation is not supported by the device.");
+            }
+            pipe = ParcelFileDescriptor.createReliablePipe();
+            int objectHandle = -1;
+            MtpObjectInfo info = null;
+            try {
+                pipe[0].close();  // 0 bytes for a new document.
+
+                final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
+                        MtpConstants.FORMAT_ASSOCIATION :
+                        MediaFile.getFormatCode(displayName, mimeType);
+                info = new MtpObjectInfo.Builder()
+                        .setStorageId(parentId.mStorageId)
+                        .setParent(parentId.mObjectHandle)
+                        .setFormat(formatCode)
+                        .setName(displayName)
+                        .build();
+
+                final String[] parts = FileUtils.splitFileName(mimeType, displayName);
+                final String baseName = parts[0];
+                final String extension = parts[1];
+                for (int i = 0; i <= 32; i++) {
+                    final MtpObjectInfo infoUniqueName;
+                    if (i == 0) {
+                        infoUniqueName = info;
+                    } else {
+                        String suffixedName = baseName + " (" + i + " )";
+                        if (!extension.isEmpty()) {
+                            suffixedName += "." + extension;
+                        }
+                        infoUniqueName =
+                                new MtpObjectInfo.Builder(info).setName(suffixedName).build();
+                    }
+                    try {
+                        objectHandle = mMtpManager.createDocument(
+                                parentId.mDeviceId, infoUniqueName, pipe[1]);
+                        break;
+                    } catch (SendObjectInfoFailure exp) {
+                        // This can be caused when we have an existing file with the same name.
+                        continue;
+                    }
+                }
+            } finally {
+                pipe[1].close();
+            }
+            if (objectHandle == -1) {
+                throw new IllegalArgumentException(
+                        "The file name \"" + displayName + "\" is conflicted with existing files " +
+                        "and the provider failed to find unique name.");
+            }
             final MtpObjectInfo infoWithHandle =
                     new MtpObjectInfo.Builder(info).setObjectHandle(objectHandle).build();
             final String documentId = mDatabase.putNewDocument(
-                    parentId.mDeviceId, parentDocumentId, infoWithHandle);
+                    parentId.mDeviceId, parentDocumentId, record.operationsSupported,
+                    infoWithHandle, 0l);
             getDocumentLoader(parentId).clearTask(parentId);
             notifyChildDocumentsChange(parentDocumentId);
             return documentId;
+        } catch (FileNotFoundException | RuntimeException error) {
+            Log.e(TAG, "createDocument", error);
+            throw error;
         } catch (IOException error) {
             Log.e(TAG, "createDocument", error);
-            throw new FileNotFoundException(error.getMessage());
+            throw new IllegalStateException(error);
         }
     }
 
@@ -323,15 +422,19 @@
             if (DEBUG) {
                 Log.d(TAG, "Open device " + deviceId);
             }
-            mMtpManager.openDevice(deviceId);
-            mDeviceToolkits.put(
-                    deviceId, new DeviceToolkit(mMtpManager, mResolver, mDatabase));
+            final MtpDeviceRecord device = mMtpManager.openDevice(deviceId);
+            final DeviceToolkit toolkit =
+                    new DeviceToolkit(mMtpManager, mResolver, mDatabase, device);
+            mDeviceToolkits.put(deviceId, toolkit);
             mIntentSender.sendUpdateNotificationIntent();
             try {
                 mRootScanner.resume().await();
             } catch (InterruptedException error) {
                 Log.e(TAG, "openDevice", error);
             }
+            // Resume document loader to remap disconnected document ID. Must be invoked after the
+            // root scanner resumes.
+            toolkit.mDocumentLoader.resume();
         }
     }
 
@@ -343,20 +446,15 @@
         mIntentSender.sendUpdateNotificationIntent();
     }
 
-    int[] getOpenedDeviceIds() {
+    MtpDeviceRecord[] getOpenedDeviceRecordsCache() {
         synchronized (mDeviceListLock) {
-            return mMtpManager.getOpenedDeviceIds();
-        }
-    }
-
-    String getDeviceName(int deviceId) throws IOException {
-        synchronized (mDeviceListLock) {
-            for (final MtpDeviceRecord device : mMtpManager.getDevices()) {
-                if (device.deviceId == deviceId) {
-                    return device.name;
-                }
+            final MtpDeviceRecord[] records = new MtpDeviceRecord[mDeviceToolkits.size()];
+            int i = 0;
+            for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
+                records[i] = toolkit.mDeviceRecord;
+                i++;
             }
-            throw new IOException("Not found the device: " + Integer.toString(deviceId));
+            return records;
         }
     }
 
@@ -387,10 +485,14 @@
     public void shutdown() {
         synchronized (mDeviceListLock) {
             try {
-                for (final int id : mMtpManager.getOpenedDeviceIds()) {
+                // Copy the opened key set because it will be modified when closing devices.
+                final Integer[] keySet =
+                        mDeviceToolkits.keySet().toArray(new Integer[mDeviceToolkits.size()]);
+                for (final int id : keySet) {
                     closeDeviceInternal(id);
                 }
-            } catch (InterruptedException|IOException e) {
+                mRootScanner.pause();
+            } catch (InterruptedException | IOException | TimeoutException e) {
                 // It should fail unit tests by throwing runtime exception.
                 throw new RuntimeException(e);
             } finally {
@@ -425,12 +527,9 @@
         if (DEBUG) {
             Log.d(TAG, "Close device " + deviceId);
         }
-        getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
+        getDeviceToolkit(deviceId).close();
         mDeviceToolkits.remove(deviceId);
         mMtpManager.closeDevice(deviceId);
-        if (getOpenedDeviceIds().length == 0) {
-            mRootScanner.pause();
-        }
     }
 
     private DeviceToolkit getDeviceToolkit(int deviceId) throws FileNotFoundException {
@@ -457,6 +556,9 @@
                 MtpDatabase.strings(Document.COLUMN_SIZE, Document.COLUMN_DISPLAY_NAME));
         try {
             if (cursor.moveToNext()) {
+                if (cursor.isNull(0)) {
+                    throw new UnsupportedOperationException();
+                }
                 return cursor.getLong(0);
             } else {
                 throw new FileNotFoundException();
@@ -481,28 +583,94 @@
         return cursor;
     }
 
-    private static class DeviceToolkit {
+    private static class DeviceToolkit implements AutoCloseable {
         public final PipeManager mPipeManager;
         public final DocumentLoader mDocumentLoader;
+        public final MtpDeviceRecord mDeviceRecord;
 
-        public DeviceToolkit(MtpManager manager, ContentResolver resolver, MtpDatabase database) {
+        public DeviceToolkit(MtpManager manager,
+                             ContentResolver resolver,
+                             MtpDatabase database,
+                             MtpDeviceRecord record) {
             mPipeManager = new PipeManager(database);
-            mDocumentLoader = new DocumentLoader(manager, resolver, database);
+            mDocumentLoader = new DocumentLoader(record, manager, resolver, database);
+            mDeviceRecord = record;
+        }
+
+        @Override
+        public void close() throws InterruptedException {
+            mPipeManager.close();
+            mDocumentLoader.close();
         }
     }
 
     private class AppFuseCallback implements AppFuse.Callback {
-        @Override
-        public long readObjectBytes(
-                int inode, long offset, long size, byte[] buffer) throws IOException {
-            final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
-            return mMtpManager.getPartialObject(
-                    identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
-        }
+        private final Map<Long, MtpFileWriter> mWriters = new HashMap<>();
 
         @Override
         public long getFileSize(int inode) throws FileNotFoundException {
             return MtpDocumentsProvider.this.getFileSize(String.valueOf(inode));
         }
+
+        @Override
+        public long readObjectBytes(
+                int inode, long offset, long size, byte[] buffer) throws IOException {
+            final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
+            final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
+
+            if (MtpDeviceRecord.isSupported(
+                    record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
+                return mMtpManager.getPartialObject64(
+                        identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
+            }
+
+            if (0 <= offset && offset <= 0xffffffffL && MtpDeviceRecord.isSupported(
+                    record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
+                return mMtpManager.getPartialObject(
+                        identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
+            }
+
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int writeObjectBytes(
+                long fileHandle, int inode, long offset, int size, byte[] bytes)
+                throws IOException, ErrnoException {
+            final MtpFileWriter writer;
+            if (mWriters.containsKey(fileHandle)) {
+                writer = mWriters.get(fileHandle);
+            } else {
+                writer = new MtpFileWriter(mContext, String.valueOf(inode));
+                mWriters.put(fileHandle, writer);
+            }
+            return writer.write(offset, size, bytes);
+        }
+
+        @Override
+        public void flushFileHandle(long fileHandle) throws IOException, ErrnoException {
+            final MtpFileWriter writer = mWriters.get(fileHandle);
+            if (writer == null) {
+                // File handle for reading.
+                return;
+            }
+            final MtpDeviceRecord device = getDeviceToolkit(
+                    mDatabase.createIdentifier(writer.getDocumentId()).mDeviceId).mDeviceRecord;
+            writer.flush(mMtpManager, mDatabase, device.operationsSupported);
+        }
+
+        @Override
+        public void closeFileHandle(long fileHandle) throws IOException, ErrnoException {
+            final MtpFileWriter writer = mWriters.get(fileHandle);
+            if (writer == null) {
+                // File handle for reading.
+                return;
+            }
+            try {
+                writer.close();
+            } finally {
+                mWriters.remove(fileHandle);
+            }
+        }
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
index 9c4952b..9b42b78 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
@@ -67,38 +67,25 @@
      */
     private boolean updateForegroundState() {
         final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
-        final int[] deviceIds = provider.getOpenedDeviceIds();
         int notificationId = 0;
         Notification notification = null;
         // TODO: Hide notification if the device has already been removed.
-        for (final int deviceId : deviceIds) {
-            try {
-                final String title = getResources().getString(
-                        R.string.accessing_notification_title,
-                        provider.getDeviceName(deviceIds[0]));
-                final String description = getResources().getString(
-                        R.string.accessing_notification_description);
-                notificationId = deviceId;
-                notification = new Notification.Builder(this)
-                        .setLocalOnly(true)
-                        .setContentTitle(title)
-                        .setContentText(description)
-                        .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
-                        .setCategory(Notification.CATEGORY_SYSTEM)
-                        .setPriority(Notification.PRIORITY_LOW)
-                        .build();
-                mNotificationManager.notify(deviceId, notification);
-            } catch (IOException exp) {
-                logErrorMessage(exp);
-                // If we failed to obtain device name, it looks the device is unusable.
-                // Because this is the last device we opened, we should hide the notification
-                // for the case.
-                try {
-                    provider.closeDevice(deviceIds[0]);
-                } catch (IOException | InterruptedException closeError) {
-                    logErrorMessage(closeError);
-                }
-            }
+        for (final MtpDeviceRecord record : provider.getOpenedDeviceRecordsCache()) {
+            final String title = getResources().getString(
+                    R.string.accessing_notification_title,
+                    record.name);
+            final String description = getResources().getString(
+                    R.string.accessing_notification_description);
+            notificationId = record.deviceId;
+            notification = new Notification.Builder(this)
+                    .setLocalOnly(true)
+                    .setContentTitle(title)
+                    .setContentText(description)
+                    .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
+                    .setCategory(Notification.CATEGORY_SYSTEM)
+                    .setPriority(Notification.PRIORITY_LOW)
+                    .build();
+            mNotificationManager.notify(record.deviceId, notification);
         }
 
         if (notification != null) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java
new file mode 100644
index 0000000..3e1bedc
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.content.Context;
+import android.mtp.MtpObjectInfo;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.IOException;
+
+class MtpFileWriter implements AutoCloseable {
+    final ParcelFileDescriptor mCacheFd;
+    final String mDocumentId;
+    boolean mDirty;
+
+    MtpFileWriter(Context context, String documentId) throws IOException {
+        mDocumentId = documentId;
+        mDirty = false;
+        final File tempFile = File.createTempFile("mtp", "tmp", context.getCacheDir());
+        mCacheFd = ParcelFileDescriptor.open(
+                tempFile,
+                ParcelFileDescriptor.MODE_READ_WRITE |
+                ParcelFileDescriptor.MODE_TRUNCATE |
+                ParcelFileDescriptor.MODE_CREATE);
+        tempFile.delete();
+    }
+
+    String getDocumentId() {
+        return mDocumentId;
+    }
+
+    int write(long offset, int size, byte[] bytes) throws IOException, ErrnoException {
+        Preconditions.checkArgumentNonnegative(offset, "offset");
+        Preconditions.checkArgumentNonnegative(size, "size");
+        Preconditions.checkArgument(size <= bytes.length);
+        if (size == 0) {
+            return 0;
+        }
+        mDirty = true;
+        Os.lseek(mCacheFd.getFileDescriptor(), offset, OsConstants.SEEK_SET);
+        return Os.write(mCacheFd.getFileDescriptor(), bytes, 0, size);
+    }
+
+    void flush(MtpManager manager, MtpDatabase database, int[] operationsSupported)
+            throws IOException, ErrnoException {
+        // Skip unnecessary flush.
+        if (!mDirty) {
+            return;
+        }
+
+        // Get the placeholder object info.
+        final Identifier identifier = database.createIdentifier(mDocumentId);
+        final MtpObjectInfo placeholderObjectInfo =
+                manager.getObjectInfo(identifier.mDeviceId, identifier.mObjectHandle);
+
+        // Delete the target object info if it already exists (as a placeholder).
+        manager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
+
+        // Create the target object info with a correct file size and upload the file.
+        final long size = Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_END);
+        final MtpObjectInfo targetObjectInfo = new MtpObjectInfo.Builder(placeholderObjectInfo)
+                .setCompressedSize(size)
+                .build();
+
+        Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+        final int newObjectHandle = manager.createDocument(
+                identifier.mDeviceId, targetObjectInfo, mCacheFd);
+
+        final MtpObjectInfo newObjectInfo = manager.getObjectInfo(
+                identifier.mDeviceId, newObjectHandle);
+        final Identifier parentIdentifier =
+                database.getParentIdentifier(identifier.mDocumentId);
+        database.updateObject(
+                identifier.mDocumentId,
+                identifier.mDeviceId,
+                parentIdentifier.mDocumentId,
+                operationsSupported,
+                newObjectInfo,
+                size);
+
+        mDirty = false;
+    }
+
+    @Override
+    public void close() throws IOException {
+        mCacheFd.close();
+    }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 37dc761..00d31a7 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -33,7 +33,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.mtp.exceptions.BusyDeviceException;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -65,16 +64,14 @@
      */
     private static final int PROTOCOL_MTP = 0;
 
-
     private final UsbManager mManager;
-    // TODO: Save and restore the set of opened device.
     private final SparseArray<MtpDevice> mDevices = new SparseArray<>();
 
     MtpManager(Context context) {
         mManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
     }
 
-    synchronized void openDevice(int deviceId) throws IOException {
+    synchronized MtpDeviceRecord openDevice(int deviceId) throws IOException {
         UsbDevice rawDevice = null;
         for (final UsbDevice candidate : mManager.getDeviceList().values()) {
             if (candidate.getDeviceId() == deviceId) {
@@ -113,6 +110,8 @@
         }
 
         mDevices.put(deviceId, device);
+
+        return createDeviceRecord(rawDevice);
     }
 
     synchronized void closeDevice(int deviceId) throws IOException {
@@ -126,50 +125,19 @@
             if (!isMtpDevice(device)) {
                 continue;
             }
-            final MtpDevice mtpDevice = mDevices.get(device.getDeviceId());
-            final boolean opened = mtpDevice != null;
-            final String name = device.getProductName();
-            MtpRoot[] roots;
-            int[] operationsSupported = null;
-            int[] eventsSupported = null;
-            if (opened) {
-                try {
-                    roots = getRoots(device.getDeviceId());
-                } catch (IOException exp) {
-                    Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exp);
-                    // If we failed to fetch roots for the device, we still returns device model
-                    // with an empty set of roots so that the device is shown DocumentsUI as long as
-                    // the device is physically connected.
-                    roots = new MtpRoot[0];
-                }
-                final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
-                if (info != null) {
-                    operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
-                    eventsSupported = mtpDevice.getDeviceInfo().getEventsSupported();
-                }
-            } else {
-                roots = new MtpRoot[0];
-            }
-            devices.add(new MtpDeviceRecord(
-                    device.getDeviceId(), name, device.getSerialNumber(), opened, roots,
-                    operationsSupported, eventsSupported));
+            devices.add(createDeviceRecord(device));
         }
         return devices.toArray(new MtpDeviceRecord[devices.size()]);
     }
 
-    synchronized int[] getOpenedDeviceIds() {
-        final int[] result = new int[mDevices.size()];
-        for (int i = 0; i < result.length; i++) {
-            result[i] = mDevices.keyAt(i);
-        }
-        return result;
-    }
-
-    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
-            throws IOException {
+    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
         final MtpDevice device = getDevice(deviceId);
         synchronized (device) {
-            return device.getObjectInfo(objectHandle);
+            final MtpObjectInfo info = device.getObjectInfo(objectHandle);
+            if (info == null) {
+                throw new IOException("Failed to get object info: " + objectHandle);
+            }
+            return info;
         }
     }
 
@@ -177,7 +145,12 @@
             throws IOException {
         final MtpDevice device = getDevice(deviceId);
         synchronized (device) {
-            return device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+            final int[] handles =
+                    device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+            if (handles == null) {
+                throw new IOException("Failed to fetch object handles.");
+            }
+            return handles;
         }
     }
 
@@ -189,7 +162,6 @@
         }
     }
 
-    @VisibleForTesting
     long getPartialObject(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
             throws IOException {
         final MtpDevice device = getDevice(deviceId);
@@ -198,6 +170,14 @@
         }
     }
 
+    long getPartialObject64(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
+            throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        synchronized (device) {
+            return device.getPartialObject64(objectHandle, offset, size, buffer);
+        }
+    }
+
     byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
         final MtpDevice device = getDevice(deviceId);
         synchronized (device) {
@@ -220,7 +200,7 @@
         synchronized (device) {
             final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
             if (sendObjectInfoResult == null) {
-                throw new IOException("Failed to create a document");
+                throw new SendObjectInfoFailure();
             }
             if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
                 if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
@@ -257,6 +237,11 @@
         return device.readEvent(signal);
     }
 
+    long getObjectSizeLong(int deviceId, int objectHandle, int format) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        return device.getObjectSizeLong(objectHandle, format);
+    }
+
     private synchronized MtpDevice getDevice(int deviceId) throws IOException {
         final MtpDevice device = mDevices.get(deviceId);
         if (device == null) {
@@ -281,6 +266,36 @@
         }
     }
 
+    private MtpDeviceRecord createDeviceRecord(UsbDevice device) {
+        final MtpDevice mtpDevice = mDevices.get(device.getDeviceId());
+        final boolean opened = mtpDevice != null;
+        final String name = device.getProductName();
+        MtpRoot[] roots;
+        int[] operationsSupported = null;
+        int[] eventsSupported = null;
+        if (opened) {
+            try {
+                roots = getRoots(device.getDeviceId());
+            } catch (IOException exp) {
+                Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exp);
+                // If we failed to fetch roots for the device, we still returns device model
+                // with an empty set of roots so that the device is shown DocumentsUI as long as
+                // the device is physically connected.
+                roots = new MtpRoot[0];
+            }
+            final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
+            if (info != null) {
+                operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
+                eventsSupported = mtpDevice.getDeviceInfo().getEventsSupported();
+            }
+        } else {
+            roots = new MtpRoot[0];
+        }
+        return new MtpDeviceRecord(
+                device.getDeviceId(), name, device.getSerialNumber(), opened, roots,
+                operationsSupported, eventsSupported);
+    }
+
     static boolean isMtpDevice(UsbDevice device) {
         for (int i = 0; i < device.getInterfaceCount(); i++) {
             final UsbInterface usbInterface = device.getInterface(i);
@@ -292,7 +307,7 @@
             if (usbInterface.getInterfaceClass() == UsbConstants.USB_SUBCLASS_VENDOR_SPEC &&
                     usbInterface.getInterfaceSubclass() == SUBCLASS_MTP &&
                     usbInterface.getInterfaceProtocol() == PROTOCOL_MTP &&
-                    usbInterface.getName().equals("MTP")) {
+                    "MTP".equals(usbInterface.getName())) {
                 return true;
             }
         }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 645bfcd..795bbc1 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -16,18 +16,20 @@
 
 package com.android.mtp;
 
-import android.content.Context;
-import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 class PipeManager {
+    /**
+     * Milliseconds we wait for background thread when pausing.
+     */
+    private final static long AWAIT_TERMINATION_TIMEOUT = 2000;
+
     final ExecutorService mExecutor;
     final MtpDatabase mDatabase;
 
@@ -46,13 +48,6 @@
         return task.getReadingFileDescriptor();
     }
 
-    ParcelFileDescriptor writeDocument(Context context, MtpManager model, Identifier identifier)
-            throws IOException {
-        final Task task = new WriteDocumentTask(context, model, identifier, mDatabase);
-        mExecutor.execute(task);
-        return task.getWritingFileDescriptor();
-    }
-
     ParcelFileDescriptor readThumbnail(MtpManager model, Identifier identifier) throws IOException {
         final Task task = new GetThumbnailTask(model, identifier);
         mExecutor.execute(task);
@@ -73,10 +68,6 @@
         ParcelFileDescriptor getReadingFileDescriptor() {
             return mDescriptors[0];
         }
-
-        ParcelFileDescriptor getWritingFileDescriptor() {
-            return mDescriptors[1];
-        }
     }
 
     private static class ImportFileTask extends Task {
@@ -100,78 +91,6 @@
         }
     }
 
-    private static class WriteDocumentTask extends Task {
-        private final Context mContext;
-        private final MtpDatabase mDatabase;
-
-        WriteDocumentTask(
-                Context context, MtpManager model, Identifier identifier, MtpDatabase database)
-                throws IOException {
-            super(model, identifier);
-            mContext = context;
-            mDatabase = database;
-        }
-
-        @Override
-        public void run() {
-            File tempFile = null;
-            try {
-                // Obtain a temporary file and copy the data to it.
-                tempFile = File.createTempFile("mtp", "tmp", mContext.getCacheDir());
-                try (
-                    final FileOutputStream tempOutputStream =
-                            new ParcelFileDescriptor.AutoCloseOutputStream(
-                                    ParcelFileDescriptor.open(
-                                            tempFile, ParcelFileDescriptor.MODE_WRITE_ONLY));
-                    final ParcelFileDescriptor.AutoCloseInputStream inputStream =
-                            new ParcelFileDescriptor.AutoCloseInputStream(mDescriptors[0])
-                ) {
-                    final byte[] buffer = new byte[32 * 1024];
-                    int bytes;
-                    while ((bytes = inputStream.read(buffer)) != -1) {
-                        mDescriptors[0].checkError();
-                        tempOutputStream.write(buffer, 0, bytes);
-                    }
-                    tempOutputStream.flush();
-                }
-
-                // Get the placeholder object info.
-                final MtpObjectInfo placeholderObjectInfo =
-                        mManager.getObjectInfo(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
-
-                // Delete the target object info if it already exists (as a placeholder).
-                mManager.deleteDocument(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
-
-                // Create the target object info with a correct file size and upload the file.
-                final MtpObjectInfo targetObjectInfo =
-                        new MtpObjectInfo.Builder(placeholderObjectInfo)
-                                .setCompressedSize(tempFile.length())
-                                .build();
-                final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
-                        tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
-                final int newObjectHandle = mManager.createDocument(
-                        mIdentifier.mDeviceId, targetObjectInfo, tempInputDescriptor);
-
-                final MtpObjectInfo newObjectInfo = mManager.getObjectInfo(
-                        mIdentifier.mDeviceId, newObjectHandle);
-                final Identifier parentIdentifier =
-                        mDatabase.getParentIdentifier(mIdentifier.mDocumentId);
-                mDatabase.updateObject(
-                        mIdentifier.mDocumentId,
-                        mIdentifier.mDeviceId,
-                        parentIdentifier.mDocumentId,
-                        newObjectInfo);
-            } catch (IOException error) {
-                Log.w(MtpDocumentsProvider.TAG,
-                        "Failed to send a file because of: " + error.getMessage());
-            } finally {
-                if (tempFile != null) {
-                    tempFile.delete();
-                }
-            }
-        }
-    }
-
     private static class GetThumbnailTask extends Task {
         GetThumbnailTask(MtpManager model, Identifier identifier) throws IOException {
             super(model, identifier);
@@ -195,7 +114,8 @@
         }
     }
 
-    void close() {
-        mExecutor.shutdown();
+    boolean close() throws InterruptedException {
+        mExecutor.shutdownNow();
+        return mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS);
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
index a48bf12..2e9133b 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
@@ -26,8 +26,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 final class RootScanner {
     /**
@@ -56,7 +56,7 @@
     final MtpDatabase mDatabase;
 
     ExecutorService mExecutor;
-    FutureTask<Void> mCurrentTask;
+    private UpdateRootsRunnable mCurrentTask;
 
     RootScanner(
             ContentResolver resolver,
@@ -84,41 +84,52 @@
             mExecutor = Executors.newSingleThreadExecutor();
         }
         if (mCurrentTask != null) {
-            // Cancel previous task.
-            mCurrentTask.cancel(true);
+            // Stop previous task.
+            mCurrentTask.stop();
         }
-        final UpdateRootsRunnable runnable = new UpdateRootsRunnable();
-        mCurrentTask = new FutureTask<Void>(runnable, null);
-        mExecutor.submit(mCurrentTask);
-        return runnable.mFirstScanCompleted;
+        mCurrentTask = new UpdateRootsRunnable();
+        mExecutor.execute(mCurrentTask);
+        return mCurrentTask.mFirstScanCompleted;
     }
 
     /**
      * Stops background thread and wait for its termination.
      * @throws InterruptedException
      */
-    synchronized void pause() throws InterruptedException {
+    synchronized void pause() throws InterruptedException, TimeoutException {
         if (mExecutor == null) {
             return;
         }
         mExecutor.shutdownNow();
-        if (!mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS)) {
-            Log.e(MtpDocumentsProvider.TAG, "Failed to terminate RootScanner's background thread.");
+        try {
+            if (!mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS)) {
+                throw new TimeoutException(
+                        "Timeout for terminating RootScanner's background thread.");
+            }
+        } finally {
+            mExecutor = null;
         }
-        mExecutor = null;
     }
 
     /**
      * Runnable to scan roots and update the database information.
      */
     private final class UpdateRootsRunnable implements Runnable {
+        /**
+         * Count down latch that specifies the runnable is stopped.
+         */
+        final CountDownLatch mStopped = new CountDownLatch(1);
+
+        /**
+         * Count down latch that specifies the first scan is completed.
+         */
         final CountDownLatch mFirstScanCompleted = new CountDownLatch(1);
 
         @Override
         public void run() {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
             int pollingCount = 0;
-            while (true) {
+            while (mStopped.getCount() > 0) {
                 boolean changed = false;
 
                 // Update devices.
@@ -149,7 +160,8 @@
                     }
                     try {
                         mDatabase.getMapper().startAddingDocuments(documentId);
-                        if (mDatabase.getMapper().putStorageDocuments(documentId, device.roots)) {
+                        if (mDatabase.getMapper().putStorageDocuments(
+                                documentId, device.eventsSupported, device.roots)) {
                             changed = true;
                         }
                         if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
@@ -166,16 +178,23 @@
                 }
                 mFirstScanCompleted.countDown();
                 pollingCount++;
+                if (devices.length == 0) {
+                    break;
+                }
                 try {
                     // Use SHORT_POLLING_PERIOD for the first SHORT_POLLING_TIMES because it is
                     // more likely to add new root just after the device is added.
                     // TODO: Use short interval only for a device that is just added.
-                    Thread.sleep(pollingCount > SHORT_POLLING_TIMES ?
-                        LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL);
+                    mStopped.await(pollingCount > SHORT_POLLING_TIMES ?
+                            LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL, TimeUnit.MILLISECONDS);
                 } catch (InterruptedException exp) {
                     break;
                 }
             }
         }
+
+        void stop() {
+            mStopped.countDown();
+        }
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java b/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java
new file mode 100644
index 0000000..db7d777
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when sendObjectInfo failed.
+ */
+class SendObjectInfoFailure extends IOException {
+    SendObjectInfoFailure() {
+        super("Failed to MtpDevice#sendObjectInfo.");
+    }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java b/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
index a7f295f..2ded925 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
@@ -22,7 +22,7 @@
 /**
  * Annotation that shows the method is used by JNI.
  */
-@Target(ElementType.METHOD)
+@Target({ElementType.METHOD, ElementType.FIELD})
 public @interface UsedByNative {
     /**
      * JNI file name that uses the method.
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java b/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
deleted file mode 100644
index 55f55b0..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp.exceptions;
-
-import java.io.IOException;
-
-/**
- * Exception thrown when the device is busy and the requested operation cannon be completed.
- */
-public class BusyDeviceException extends IOException {
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
index c0973bd..e421de7 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
@@ -23,6 +23,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import libcore.io.IoUtils;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -56,7 +58,8 @@
                     }
                 });
         appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(INODE);
+        final ParcelFileDescriptor fd = appFuse.openFile(
+                INODE, ParcelFileDescriptor.MODE_READ_ONLY);
         fd.close();
         appFuse.close();
     }
@@ -67,11 +70,21 @@
         final AppFuse appFuse = new AppFuse("test", new TestCallback());
         appFuse.mount(storageManager);
         try {
-            appFuse.openFile(INODE);
+            appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_ONLY);
             fail();
-        } catch (Throwable t) {
-            assertTrue(t instanceof FileNotFoundException);
-        }
+        } catch (FileNotFoundException exp) {}
+        appFuse.close();
+    }
+
+    public void testOpenFile_illegalMode() throws IOException {
+        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+        final int INODE = 10;
+        final AppFuse appFuse = new AppFuse("test", new TestCallback());
+        appFuse.mount(storageManager);
+        try {
+            appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_WRITE);
+            fail();
+        } catch (IllegalArgumentException exp) {}
         appFuse.close();
     }
 
@@ -105,7 +118,8 @@
                     }
                 });
         appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(fileInode);
+        final ParcelFileDescriptor fd = appFuse.openFile(
+                fileInode, ParcelFileDescriptor.MODE_READ_ONLY);
         try (final ParcelFileDescriptor.AutoCloseInputStream stream =
                 new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
             final byte[] buffer = new byte[1024];
@@ -115,6 +129,112 @@
         appFuse.close();
     }
 
+    public void testWriteFile() throws IOException {
+        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+        final int INODE = 10;
+        final byte[] resultBytes = new byte[5];
+        final AppFuse appFuse = new AppFuse(
+                "test",
+                new TestCallback() {
+                    @Override
+                    public long getFileSize(int inode) throws FileNotFoundException {
+                        if (inode != INODE) {
+                            throw new FileNotFoundException();
+                        }
+                        return resultBytes.length;
+                    }
+
+                    @Override
+                    public int writeObjectBytes(
+                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
+                        for (int i = 0; i < size; i++) {
+                            resultBytes[(int)(offset + i)] = bytes[i];
+                        }
+                        return size;
+                    }
+                });
+        appFuse.mount(storageManager);
+        final ParcelFileDescriptor fd = appFuse.openFile(
+                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
+        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+            stream.write('a');
+            stream.write('b');
+            stream.write('c');
+            stream.write('d');
+            stream.write('e');
+        }
+        final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' };
+        assertTrue(Arrays.equals(BYTES, resultBytes));
+        appFuse.close();
+    }
+
+    public void testWriteFile_writeError() throws IOException {
+        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+        final int INODE = 10;
+        final AppFuse appFuse = new AppFuse(
+                "test",
+                new TestCallback() {
+                    @Override
+                    public long getFileSize(int inode) throws FileNotFoundException {
+                        if (inode != INODE) {
+                            throw new FileNotFoundException();
+                        }
+                        return 5;
+                    }
+                });
+        appFuse.mount(storageManager);
+        final ParcelFileDescriptor fd = appFuse.openFile(
+                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
+        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+            stream.write('a');
+            fail();
+        } catch (IOException e) {
+        }
+        appFuse.close();
+    }
+
+    public void testWriteFile_flushError() throws IOException {
+        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+        final int INODE = 10;
+        final AppFuse appFuse = new AppFuse(
+                "test",
+                new TestCallback() {
+                    @Override
+                    public long getFileSize(int inode) throws FileNotFoundException {
+                        if (inode != INODE) {
+                            throw new FileNotFoundException();
+                        }
+                        return 5;
+                    }
+
+                    @Override
+                    public int writeObjectBytes(
+                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
+                        return size;
+                    }
+
+                    @Override
+                    public void flushFileHandle(long fileHandle) throws IOException {
+                        throw new IOException();
+                    }
+                });
+        appFuse.mount(storageManager);
+        final ParcelFileDescriptor fd = appFuse.openFile(
+                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
+        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+            stream.write('a');
+            try {
+                IoUtils.close(fd.getFileDescriptor());
+                fail();
+            } catch (IOException e) {
+            }
+        }
+        appFuse.close();
+    }
+
     private static class TestCallback implements AppFuse.Callback {
         @Override
         public long getFileSize(int inode) throws FileNotFoundException {
@@ -126,5 +246,17 @@
                 throws IOException {
             throw new IOException();
         }
+
+        @Override
+        public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
+                throws IOException {
+            throw new IOException();
+        }
+
+        @Override
+        public void flushFileHandle(long fileHandle) throws IOException {}
+
+        @Override
+        public void closeFileHandle(long fileHandle) {}
     }
 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 474da07..45f89e4 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -44,26 +44,28 @@
 
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(1, "Device", null, true, new MtpRoot[0], null, null));
+                new MtpDeviceRecord(0, "Device", null, true, new MtpRoot[0], null, null));
         mDatabase.getMapper().stopAddingDocuments(null);
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", new int[0], new MtpRoot[] {
                 new MtpRoot(0, 0, "Storage", 1000, 1000, "")
         });
         mDatabase.getMapper().stopAddingDocuments("1");
 
         mManager = new BlockableTestMtpManager(getContext());
         mResolver = new TestContentResolver();
-        mLoader = new DocumentLoader(mManager, mResolver, mDatabase);
     }
 
     @Override
-    public void tearDown() {
+    public void tearDown() throws Exception {
+        mLoader.close();
         mDatabase.close();
     }
 
     public void testBasic() throws Exception {
+        setUpLoader();
+
         final Uri uri = DocumentsContract.buildChildDocumentsUri(
                 MtpDocumentsProvider.AUTHORITY, mParentIdentifier.mDocumentId);
         setUpDocument(mManager, 40);
@@ -100,6 +102,55 @@
         assertEquals(2, mResolver.getChangeCount(uri));
     }
 
+    public void testError_GetObjectHandles() throws Exception {
+        mManager = new BlockableTestMtpManager(getContext()) {
+            @Override
+            int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
+                    throws IOException {
+                throw new IOException();
+            }
+        };
+        setUpLoader();
+        mManager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, null);
+        try {
+            try (final Cursor cursor = mLoader.queryChildDocuments(
+                    MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {}
+            fail();
+        } catch (IOException exception) {
+            // Expect exception.
+        }
+    }
+
+    public void testError_GetObjectInfo() throws Exception {
+        mManager = new BlockableTestMtpManager(getContext()) {
+            @Override
+            MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+                if (objectHandle == DocumentLoader.NUM_INITIAL_ENTRIES) {
+                    throw new IOException();
+                } else {
+                    return super.getObjectInfo(deviceId, objectHandle);
+                }
+            }
+        };
+        setUpLoader();
+        setUpDocument(mManager, DocumentLoader.NUM_INITIAL_ENTRIES);
+        try (final Cursor cursor = mLoader.queryChildDocuments(
+                MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {
+            // Even if MtpManager returns an error for a document, loading must complete.
+            assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
+        }
+    }
+
+    private void setUpLoader() {
+        mLoader = new DocumentLoader(
+                new MtpDeviceRecord(
+                        0, "Device", "Key", true, new MtpRoot[0],
+                        TestUtil.OPERATIONS_SUPPORTED, new int[0]),
+                mManager,
+                mResolver,
+                mDatabase);
+    }
+
     private void setUpDocument(TestMtpManager manager, int count) {
         int[] childDocuments = new int[count];
         for (int i = 0; i < childDocuments.length; i++) {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 05c9c57..404047b 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -17,8 +17,11 @@
 package com.android.mtp;
 
 import android.database.Cursor;
+import android.media.MediaFile;
+import android.media.MediaFile.MediaFileType;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
+import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
@@ -26,14 +29,16 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.io.FileNotFoundException;
+import java.util.Arrays;
 
 import static android.provider.DocumentsContract.Document.*;
 import static com.android.mtp.MtpDatabase.strings;
 import static com.android.mtp.MtpDatabaseConstants.*;
+import static com.android.mtp.TestUtil.OPERATIONS_SUPPORTED;
 
 @SmallTest
 public class MtpDatabaseTest extends AndroidTestCase {
-    private final String[] COLUMN_NAMES = new String[] {
+    private static final String[] COLUMN_NAMES = new String[] {
         DocumentsContract.Document.COLUMN_DOCUMENT_ID,
         MtpDatabaseConstants.COLUMN_DEVICE_ID,
         MtpDatabaseConstants.COLUMN_STORAGE_ID,
@@ -75,13 +80,10 @@
     }
 
     public void testPutSingleStorageDocuments() throws Exception {
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", null /* deviceKey */, true, new MtpRoot[0], null, null));
-        mDatabase.getMapper().stopAddingDocuments(null);
+        addTestDevice();
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 1, "Storage", 1000, 2000, "")
         });
         mDatabase.getMapper().stopAddingDocuments("1");
@@ -101,7 +103,7 @@
             assertTrue(isNull(cursor, COLUMN_SUMMARY));
             assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
-            assertEquals(0, getInt(cursor, COLUMN_FLAGS));
+            assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS));
             assertEquals(1000, getInt(cursor, COLUMN_SIZE));
             assertEquals(
                     MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE,
@@ -143,7 +145,7 @@
         addTestDevice();
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 1, "Storage", 1000, 2000, ""),
                 new MtpRoot(0, 2, "Storage", 2000, 4000, ""),
                 new MtpRoot(0, 3, "/@#%&<>Storage", 3000, 6000,"")
@@ -163,7 +165,7 @@
             assertTrue(isNull(cursor, COLUMN_SUMMARY));
             assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
-            assertEquals(0, getInt(cursor, COLUMN_FLAGS));
+            assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS));
             assertEquals(1000, getInt(cursor, COLUMN_SIZE));
             assertEquals(
                     MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
@@ -194,11 +196,11 @@
         addTestStorage("1");
 
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
                 createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
-        });
+        }, new long[] { 1024L, 2L * 1024L * 1024L, 3L * 1024L * 1024L});
 
         final Cursor cursor = mDatabase.queryChildDocuments(COLUMN_NAMES, "2");
         assertEquals(3, cursor.getCount());
@@ -263,6 +265,58 @@
         cursor.close();
     }
 
+    public void testPutChildDocuments_operationsSupported() throws Exception {
+        addTestDevice();
+        addTestStorage("1");
+
+        // Put a document with empty supported operations.
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putChildDocuments(0, "2", new int[0], new MtpObjectInfo[] {
+                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
+        }, new long[] { 1024L });
+        mDatabase.getMapper().stopAddingDocuments("2");
+
+        try (final Cursor cursor =
+                mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals(0, cursor.getInt(0));
+        }
+
+        // Put a document with writable operations.
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putChildDocuments(0, "2", new int[] {
+                MtpConstants.OPERATION_SEND_OBJECT,
+                MtpConstants.OPERATION_SEND_OBJECT_INFO,
+        }, new MtpObjectInfo[] {
+                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
+        }, new long[] { 1024L });
+        mDatabase.getMapper().stopAddingDocuments("2");
+
+        try (final Cursor cursor =
+                mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals(Document.FLAG_SUPPORTS_WRITE, cursor.getInt(0));
+        }
+
+        // Put a document with deletable operations.
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putChildDocuments(0, "2", new int[] {
+                MtpConstants.OPERATION_DELETE_OBJECT
+        }, new MtpObjectInfo[] {
+                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
+        }, new long[] { 1024L });
+        mDatabase.getMapper().stopAddingDocuments("2");
+
+        try (final Cursor cursor =
+                mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals(Document.FLAG_SUPPORTS_DELETE, cursor.getInt(0));
+        }
+    }
+
     public void testRestoreIdForRootDocuments() throws Exception {
         final String[] columns = new String[] {
                 DocumentsContract.Document.COLUMN_DOCUMENT_ID,
@@ -273,7 +327,7 @@
         // Add device and two storages.
         addTestDevice();
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage A", 1000, 0, ""),
                 new MtpRoot(0, 101, "Storage B", 1001, 0, "")
         });
@@ -304,7 +358,7 @@
 
         // Add two storages, but one's name is different from previous one.
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 200, "Storage A", 2000, 0, ""),
                 new MtpRoot(0, 202, "Storage C", 2002, 0, "")
         });
@@ -337,11 +391,11 @@
         addTestStorage("1");
 
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
                 createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
-        });
+        }, new long[] { 1024L, 2L * 1024L * 1024L, 3L * 1024L * 1024L});
         mDatabase.getMapper().clearMapping();
 
         addTestDevice();
@@ -355,10 +409,10 @@
         }
 
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 createDocument(203, "video.mp4", MtpConstants.FORMAT_MP4_CONTAINER, 1024),
-        });
+        }, new long[] { 1024L, 1024L });
         mDatabase.getMapper().stopAddingDocuments("2");
 
         {
@@ -398,10 +452,10 @@
 
         mDatabase.getMapper().startAddingDocuments("1");
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage", 0, 0, "")
         });
-        mDatabase.getMapper().putStorageDocuments("2", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(1, 100, "Storage", 0, 0, "")
         });
 
@@ -442,10 +496,10 @@
 
         mDatabase.getMapper().startAddingDocuments("1");
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 200, "Storage", 2000, 0, "")
         });
-        mDatabase.getMapper().putStorageDocuments("2", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(1, 300, "Storage", 3000, 0, "")
         });
         mDatabase.getMapper().stopAddingDocuments("1");
@@ -488,21 +542,21 @@
         addTestDevice();
         addTestStorage("1");
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
                 createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
-        });
+        }, new long[] { 0L, 0L });
         mDatabase.getMapper().stopAddingDocuments("2");
 
         // Put note.txt in each directory.
         mDatabase.getMapper().startAddingDocuments("3");
         mDatabase.getMapper().startAddingDocuments("4");
-        mDatabase.getMapper().putChildDocuments(0, "3", new MtpObjectInfo[] {
+        mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        });
-        mDatabase.getMapper().putChildDocuments(0, "4", new MtpObjectInfo[] {
+        }, new long[] { 1024L });
+        mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(101, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        });
+        }, new long[] { 1024L });
 
         // Clear mapping.
         mDatabase.getMapper().clearMapping();
@@ -511,21 +565,21 @@
         addTestDevice();
         addTestStorage("1");
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] {
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
                 createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
-        });
+        }, new long[] { 0L, 0L });
         mDatabase.getMapper().stopAddingDocuments("2");
 
         // Add note.txt in each directory again.
         mDatabase.getMapper().startAddingDocuments("3");
         mDatabase.getMapper().startAddingDocuments("4");
-        mDatabase.getMapper().putChildDocuments(0, "3", new MtpObjectInfo[] {
+        mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        });
-        mDatabase.getMapper().putChildDocuments(0, "4", new MtpObjectInfo[] {
+        }, new long[] { 1024L });
+        mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
                 createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        });
+        }, new long[] { 1024L });
         mDatabase.getMapper().stopAddingDocuments("3");
         mDatabase.getMapper().stopAddingDocuments("4");
 
@@ -562,7 +616,7 @@
         addTestDevice();
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
@@ -576,7 +630,7 @@
         }
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 200, "Storage", 2000, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
@@ -584,7 +638,7 @@
         addTestDevice();
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 300, "Storage", 3000, 0, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("1");
@@ -625,7 +679,7 @@
         // Add a device and two storages that has same name.
         addTestDevice();
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 200, "Storage", 2000, 0, ""),
                 new MtpRoot(0, 201, "Storage", 2001, 0, ""),
         });
@@ -658,13 +712,13 @@
         // The client code should be able to replace existing rows with new information.
         // Add one.
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("1");
         // Replace it.
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage B", 1000, 1000, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("1");
@@ -703,7 +757,7 @@
         // Add one.
         addTestDevice();
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
@@ -717,11 +771,11 @@
 
             // Add one.
             mDatabase.getMapper().startAddingDocuments("1");
-            mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+            mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                     new MtpRoot(0, 101, "Storage B", 1000, 1000, ""),
             });
             // Add one more before resolving unmapped documents.
-            mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+            mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                     new MtpRoot(0, 102, "Storage B", 1000, 1000, ""),
             });
             mDatabase.getMapper().stopAddingDocuments("1");
@@ -763,7 +817,7 @@
         }
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage A", 0, 0, "")
         });
         mDatabase.getMapper().stopAddingDocuments("1");
@@ -778,7 +832,7 @@
         }
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage A", 0, 0, ""),
                 new MtpRoot(0, 101, "Storage B", 0, 0, "")
         });
@@ -798,18 +852,15 @@
         addTestDevice();
 
         mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("1");
 
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(
-                0,
-                "2",
-                new MtpObjectInfo[] {
-                        createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-                });
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+                createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
+        }, new long[] { 1024L });
         mDatabase.getMapper().stopAddingDocuments("2");
 
         assertEquals("2", mDatabase.getParentIdentifier("3").mDocumentId);
@@ -820,21 +871,15 @@
         addTestStorage("1");
 
         mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(
-                0,
-                "2",
-                new MtpObjectInfo[] {
-                        createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
-                });
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+                createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
+        }, new long[] { 1024L });
         mDatabase.getMapper().stopAddingDocuments("2");
 
         mDatabase.getMapper().startAddingDocuments("3");
-        mDatabase.getMapper().putChildDocuments(
-                0,
-                "3",
-                new MtpObjectInfo[] {
-                        createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-                });
+        mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+                createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
+        }, new long[] { 1024L });
         mDatabase.getMapper().stopAddingDocuments("3");
 
         mDatabase.deleteDocument("3");
@@ -863,7 +908,9 @@
         assertEquals(
                 "3",
                 mDatabase.putNewDocument(
-                        0, "2", createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024)));
+                        0, "2", OPERATIONS_SUPPORTED,
+                        createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
+                        1024L));
 
         {
             final Cursor cursor =
@@ -881,9 +928,9 @@
 
         mDatabase.getMapper().startAddingDocuments("2");
         mDatabase.putNewDocument(
-                0,
-                "2",
-                createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024));
+                0, "2", OPERATIONS_SUPPORTED,
+                createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
+                1024L);
         mDatabase.getMapper().stopAddingDocuments("2");
 
         {
@@ -982,6 +1029,99 @@
         assertFalse(mDatabase.getMapper().stopAddingDocuments(null));
     }
 
+    public void testSetBootCount() {
+        assertEquals(0, mDatabase.getLastBootCount());
+        mDatabase.setLastBootCount(10);
+        assertEquals(10, mDatabase.getLastBootCount());
+        try {
+            mDatabase.setLastBootCount(-1);
+            fail();
+        } catch (IllegalArgumentException e) {}
+    }
+
+    public void testCleanDatabase() throws FileNotFoundException {
+        // Add tree.
+        addTestDevice();
+        addTestStorage("1");
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+                createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024),
+                createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024),
+        }, new long[] { 1024L, 1024L });
+        mDatabase.getMapper().stopAddingDocuments("2");
+
+        // Disconnect the device.
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().stopAddingDocuments(null);
+
+        // Clean database.
+        mDatabase.cleanDatabase(new Uri[] {
+                DocumentsContract.buildDocumentUri(MtpDocumentsProvider.AUTHORITY, "3")
+        });
+
+        // Add tree again.
+        addTestDevice();
+        addTestStorage("1");
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+                createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024),
+                createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024),
+        }, new long[] { 1024L, 1024L });
+        mDatabase.getMapper().stopAddingDocuments("2");
+
+        try (final Cursor cursor = mDatabase.queryChildDocuments(
+                strings(COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME), "2")) {
+            assertEquals(2, cursor.getCount());
+
+            // Persistent uri uses the same ID.
+            cursor.moveToNext();
+            assertEquals("3", cursor.getString(0));
+            assertEquals("apple.txt", cursor.getString(1));
+
+            // Others does not.
+            cursor.moveToNext();
+            assertEquals("5", cursor.getString(0));
+            assertEquals("orange.txt", cursor.getString(1));
+        }
+    }
+
+    public void testFormatCodeForMpeg() throws FileNotFoundException {
+        addTestDevice();
+        addTestStorage("1");
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+            createDocument(100, "audio.m4a", MtpConstants.FORMAT_MPEG, 1000),
+            createDocument(101, "video.m4v", MtpConstants.FORMAT_MPEG, 1000),
+            createDocument(102, "unknown.mp4", MtpConstants.FORMAT_MPEG, 1000),
+            createDocument(103, "inconsistent.txt", MtpConstants.FORMAT_MPEG, 1000),
+            createDocument(104, "noext", MtpConstants.FORMAT_UNDEFINED, 1000),
+        }, new long[] { 1000L, 1000L, 1000L, 1000L, 1000L });
+        mDatabase.getMapper().stopAddingDocuments("2");
+        try (final Cursor cursor = mDatabase.queryChildDocuments(
+                strings(COLUMN_DISPLAY_NAME,  COLUMN_MIME_TYPE),
+                "2")) {
+            assertEquals(5, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("audio.m4a", cursor.getString(0));
+            assertEquals("audio/mp4", cursor.getString(1));
+            cursor.moveToNext();
+            assertEquals("video.m4v", cursor.getString(0));
+            assertEquals("video/mp4", cursor.getString(1));
+            cursor.moveToNext();
+            // Assume that the file is video as we don't have any hints to find out if the file is
+            // video or audio.
+            assertEquals("unknown.mp4", cursor.getString(0));
+            assertEquals("video/mp4", cursor.getString(1));
+            // Don't return mime type that is inconsistent with format code.
+            cursor.moveToNext();
+            assertEquals("inconsistent.txt", cursor.getString(0));
+            assertEquals("video/mp4", cursor.getString(1));
+            cursor.moveToNext();
+            assertEquals("noext", cursor.getString(0));
+            assertEquals("application/octet-stream", cursor.getString(1));
+        }
+    }
+
     private void addTestDevice() throws FileNotFoundException {
         TestUtil.addTestDevice(mDatabase);
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 5eda9b2..9ed15c8 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -21,7 +21,9 @@
 import android.mtp.MtpObjectInfo;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
 import android.os.storage.StorageManager;
+import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.system.Os;
 import android.system.OsConstants;
@@ -29,14 +31,13 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
-import com.android.mtp.exceptions.BusyDeviceException;
-
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.concurrent.TimeoutException;
 
 import static com.android.mtp.MtpDatabase.strings;
+import static com.android.mtp.TestUtil.OPERATIONS_SUPPORTED;
 
 @MediumTest
 public class MtpDocumentsProviderTest extends AndroidTestCase {
@@ -76,7 +77,7 @@
                             2048 /* total space */,
                             "" /* no volume identifier */)
                 },
-                null,
+                OPERATIONS_SUPPORTED,
                 null));
 
         mProvider.resumeRootScanner();
@@ -97,7 +98,7 @@
         } catch (Throwable error) {
             assertTrue(error instanceof IOException);
         }
-        assertEquals(0, mProvider.getOpenedDeviceIds().length);
+        assertEquals(0, mProvider.getOpenedDeviceRecordsCache().length);
 
         // Check if the following notification is the first one or not.
         mMtpManager.addValidDevice(new MtpDeviceRecord(
@@ -114,7 +115,7 @@
                             2048 /* total space */,
                             "" /* no volume identifier */)
                 },
-                null,
+                OPERATIONS_SUPPORTED,
                 null));
         mProvider.resumeRootScanner();
         mResolver.waitForNotification(ROOTS_URI, 1);
@@ -138,7 +139,7 @@
                             2048 /* total space */,
                             "" /* no volume identifier */)
                 },
-                null,
+                OPERATIONS_SUPPORTED,
                 null));
         mMtpManager.setObjectHandles(0, 1, -1, new int[0]);
         mProvider.resumeRootScanner();
@@ -154,16 +155,16 @@
             assertEquals(1, cursor.getLong(1));
         }
         {
-            final int [] openedDevice = mProvider.getOpenedDeviceIds();
+            final MtpDeviceRecord[] openedDevice = mProvider.getOpenedDeviceRecordsCache();
             assertEquals(0, openedDevice.length);
         }
         // Device is opened automatically when querying its children.
         try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {}
 
         {
-            final int [] openedDevice = mProvider.getOpenedDeviceIds();
+            final MtpDeviceRecord[] openedDevice = mProvider.getOpenedDeviceRecordsCache();
             assertEquals(1, openedDevice.length);
-            assertEquals(0, openedDevice[0]);
+            assertEquals(0, openedDevice[0].deviceId);
         }
     }
 
@@ -183,7 +184,7 @@
                                 2048 /* total space */,
                                 "" /* no volume identifier */)
                 },
-                null,
+                OPERATIONS_SUPPORTED,
                 null));
         mMtpManager.addValidDevice(new MtpDeviceRecord(
                 1,
@@ -199,7 +200,7 @@
                             4096 /* total space */,
                             "Identifier B" /* no volume identifier */)
                 },
-                null,
+                new int[0] /* No operations supported */,
                 null));
 
         {
@@ -224,7 +225,7 @@
             cursor.moveToNext();
             cursor.moveToNext();
             assertEquals("2", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device B Storage B", cursor.getString(3));
             assertEquals("2", cursor.getString(4));
@@ -240,7 +241,7 @@
                 "Device key A",
                 false /* unopened */,
                 new MtpRoot[0],
-                null,
+                OPERATIONS_SUPPORTED,
                 null));
         mMtpManager.addValidDevice(new MtpDeviceRecord(
                 1,
@@ -256,15 +257,13 @@
                             4096 /* total space */,
                             "Identifier B" /* no volume identifier */)
                 },
-                null,
+                OPERATIONS_SUPPORTED,
                 null));
         {
             mProvider.openDevice(0);
-            mProvider.resumeRootScanner();
             mResolver.waitForNotification(ROOTS_URI, 1);
 
             mProvider.openDevice(1);
-            mProvider.resumeRootScanner();
             mResolver.waitForNotification(ROOTS_URI, 2);
 
             final Cursor cursor = mProvider.queryRoots(null);
@@ -353,7 +352,6 @@
         assertEquals(1422716400000L, cursor.getLong(3));
         assertEquals(
                 DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_SUPPORTS_WRITE |
                 DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE,
                 cursor.getInt(4));
         assertEquals(0, cursor.getInt(5));
@@ -410,7 +408,7 @@
         assertEquals("image/jpeg", cursor.getString(1));
         assertEquals("image.jpg", cursor.getString(2));
         assertEquals(0, cursor.getLong(3));
-        assertEquals(DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL, cursor.getInt(4));
+        assertEquals(Document.FLAG_SUPPORTS_THUMBNAIL, cursor.getInt(4));
         assertEquals(1024 * 1024 * 5, cursor.getInt(5));
 
         cursor.close();
@@ -421,20 +419,16 @@
         try {
             mProvider.queryChildDocuments("1", null, null);
             fail();
-        } catch (Throwable error) {
-            assertTrue(error instanceof FileNotFoundException);
-        }
+        } catch (FileNotFoundException error) {}
     }
 
     public void testQueryChildDocuments_documentError() throws Exception {
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
         setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
         mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
-        try {
-            mProvider.queryChildDocuments("1", null, null);
-            fail();
-        } catch (Throwable error) {
-            assertTrue(error instanceof FileNotFoundException);
+        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+            assertEquals(0, cursor.getCount());
+            assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
         }
     }
 
@@ -540,17 +534,41 @@
         }
     }
 
+    public void testOpenDocument_writing() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        setupRoots(0, new MtpRoot[] {
+                new MtpRoot(0, 0, "Storage", 0, 0, "")
+        });
+        final String documentId = mProvider.createDocument("2", "text/plain", "test.txt");
+        {
+            final ParcelFileDescriptor fd = mProvider.openDocument(documentId, "w", null);
+            try (ParcelFileDescriptor.AutoCloseOutputStream stream =
+                    new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+                stream.write("Hello".getBytes());
+            }
+        }
+        {
+            final ParcelFileDescriptor fd = mProvider.openDocument(documentId, "r", null);
+            try (ParcelFileDescriptor.AutoCloseInputStream stream =
+                    new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+                final byte[] bytes = new byte[5];
+                stream.read(bytes);
+                assertTrue(Arrays.equals("Hello".getBytes(), bytes));
+            }
+        }
+    }
+
     public void testBusyDevice() throws Exception {
         mMtpManager = new TestMtpManager(getContext()) {
             @Override
-            void openDevice(int deviceId) throws IOException {
+            MtpDeviceRecord openDevice(int deviceId) throws IOException {
                 throw new BusyDeviceException();
             }
         };
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
         mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0, "Device A", null /* deviceKey */, false /* unopened */, new MtpRoot[0], null,
-                null));
+                0, "Device A", null /* deviceKey */, false /* unopened */, new MtpRoot[0],
+                OPERATIONS_SUPPORTED, null));
 
         mProvider.resumeRootScanner();
         mResolver.waitForNotification(ROOTS_URI, 1);
@@ -570,7 +588,8 @@
     public void testLockedDevice() throws Exception {
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
         mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0, "Device A", null, false /* unopened */, new MtpRoot[0], null, null));
+                0, "Device A", null, false /* unopened */, new MtpRoot[0], OPERATIONS_SUPPORTED,
+                null));
 
         mProvider.resumeRootScanner();
         mResolver.waitForNotification(ROOTS_URI, 1);
@@ -587,11 +606,166 @@
         }
     }
 
+    public void testMappingDisconnectedDocuments() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        mMtpManager.addValidDevice(new MtpDeviceRecord(
+                0,
+                "Device A",
+                "device key",
+                true /* opened */,
+                new MtpRoot[] {
+                    new MtpRoot(
+                            0 /* deviceId */,
+                            1 /* storageId */,
+                            "Storage A" /* volume description */,
+                            1024 /* free space */,
+                            2048 /* total space */,
+                            "" /* no volume identifier */)
+                },
+                OPERATIONS_SUPPORTED,
+                null));
+
+        final String[] names = strings("Directory A", "Directory B", "Directory C");
+        final int objectHandleOffset = 100;
+        for (int i = 0; i < names.length; i++) {
+            final int parentHandle = i == 0 ?
+                    MtpManager.OBJECT_HANDLE_ROOT_CHILDREN : objectHandleOffset + i - 1;
+            final int objectHandle = i + objectHandleOffset;
+            mMtpManager.setObjectHandles(0, 1, parentHandle, new int[] { objectHandle });
+            mMtpManager.setObjectInfo(
+                    0,
+                    new MtpObjectInfo.Builder()
+                            .setName(names[i])
+                            .setObjectHandle(objectHandle)
+                            .setFormat(MtpConstants.FORMAT_ASSOCIATION)
+                            .setStorageId(1)
+                            .build());
+        }
+
+        mProvider.resumeRootScanner();
+        mResolver.waitForNotification(ROOTS_URI, 1);
+
+        final int documentIdOffset = 2;
+        for (int i = 0; i < names.length; i++) {
+            try (final Cursor cursor = mProvider.queryChildDocuments(
+                    String.valueOf(documentIdOffset + i),
+                    strings(Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME),
+                    null)) {
+                assertEquals(1, cursor.getCount());
+                cursor.moveToNext();
+                assertEquals(String.valueOf(documentIdOffset + i + 1), cursor.getString(0));
+                assertEquals(names[i], cursor.getString(1));
+            }
+        }
+
+        mProvider.closeDevice(0);
+        mResolver.waitForNotification(ROOTS_URI, 2);
+
+        mProvider.openDevice(0);
+        mResolver.waitForNotification(ROOTS_URI, 3);
+
+        for (int i = 0; i < names.length; i++) {
+            mResolver.waitForNotification(DocumentsContract.buildChildDocumentsUri(
+                    MtpDocumentsProvider.AUTHORITY,
+                    String.valueOf(documentIdOffset + i)), 1);
+            try (final Cursor cursor = mProvider.queryChildDocuments(
+                    String.valueOf(documentIdOffset + i),
+                    strings(Document.COLUMN_DOCUMENT_ID),
+                    null)) {
+                assertEquals(1, cursor.getCount());
+                cursor.moveToNext();
+                assertEquals(String.valueOf(documentIdOffset + i + 1), cursor.getString(0));
+            }
+        }
+    }
+
+    public void testCreateDocument_noWritingSupport() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        mMtpManager.addValidDevice(new MtpDeviceRecord(
+                0, "Device A", null /* deviceKey */, false /* unopened */,
+                new MtpRoot[] {
+                        new MtpRoot(
+                                0 /* deviceId */,
+                                1 /* storageId */,
+                                "Storage A" /* volume description */,
+                                1024 /* free space */,
+                                2048 /* total space */,
+                                "" /* no volume identifier */)
+                },
+                new int[0] /* no operations supported */, null));
+        mProvider.resumeRootScanner();
+        mResolver.waitForNotification(ROOTS_URI, 1);
+        try {
+            mProvider.createDocument("1", "text/palin", "note.txt");
+            fail();
+        } catch (UnsupportedOperationException exception) {}
+    }
+
+    public void testOpenDocument_noWritingSupport() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        mMtpManager.addValidDevice(new MtpDeviceRecord(
+                0, "Device A", null /* deviceKey */, false /* unopened */,
+                new MtpRoot[] {
+                        new MtpRoot(
+                                0 /* deviceId */,
+                                1 /* storageId */,
+                                "Storage A" /* volume description */,
+                                1024 /* free space */,
+                                2048 /* total space */,
+                                "" /* no volume identifier */)
+                },
+                new int[0] /* no operations supported */, null));
+        mMtpManager.setObjectHandles(
+                0, 1, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, new int[] { 100 });
+        mMtpManager.setObjectInfo(
+                0, new MtpObjectInfo.Builder().setObjectHandle(100).setName("note.txt").build());
+        mProvider.resumeRootScanner();
+        mResolver.waitForNotification(ROOTS_URI, 1);
+        try (final Cursor cursor = mProvider.queryChildDocuments(
+                "1", strings(Document.COLUMN_DOCUMENT_ID), null)) {
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("3", cursor.getString(0));
+        }
+        try {
+            mProvider.openDocument("3", "w", null);
+            fail();
+        } catch (UnsupportedOperationException exception) {}
+    }
+
+    public void testObjectSizeLong() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
+        mMtpManager.setObjectSizeLong(0, 100, MtpConstants.FORMAT_EXIF_JPEG, 0x400000000L);
+        setupDocuments(
+                0,
+                0,
+                MtpManager.OBJECT_HANDLE_ROOT_CHILDREN,
+                "1",
+                new MtpObjectInfo[] {
+                        new MtpObjectInfo.Builder()
+                                .setObjectHandle(100)
+                                .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
+                                .setName("image.jpg")
+                                .setCompressedSize(0xffffffffl)
+                                .build()
+                });
+
+        final Cursor cursor = mProvider.queryDocument("3", new String[] {
+                DocumentsContract.Document.COLUMN_SIZE
+        });
+        assertEquals(1, cursor.getCount());
+
+        cursor.moveToNext();
+        assertEquals(0x400000000L, cursor.getLong(0));
+    }
+
     private void setupProvider(int flag) {
         mDatabase = new MtpDatabase(getContext(), flag);
         mProvider = new MtpDocumentsProvider();
         final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
         assertTrue(mProvider.onCreateForTesting(
+                getContext(),
                 mResources,
                 mMtpManager,
                 mResolver,
@@ -617,7 +791,7 @@
         final int changeCount = mResolver.getChangeCount(ROOTS_URI);
         mMtpManager.addValidDevice(
                 new MtpDeviceRecord(deviceId, "Device", null /* deviceKey */, false /* unopened */,
-                roots, null, null));
+                roots, OPERATIONS_SUPPORTED, null));
         mProvider.openDevice(deviceId);
         mResolver.waitForNotification(ROOTS_URI, changeCount + 1);
         return getStrings(mProvider.queryRoots(strings(DocumentsContract.Root.COLUMN_ROOT_ID)));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index 94f87ff..53dc3db 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,10 +16,7 @@
 
 package com.android.mtp;
 
-import android.database.Cursor;
-import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
@@ -45,6 +42,12 @@
         mPipeManager = new PipeManager(mDatabase, mExecutor);
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        assertTrue(mPipeManager.close());
+        mDatabase.close();
+    }
+
     public void testReadDocument_basic() throws Exception {
         mtpManager.setImportFileBytes(0, 1, HELLO_BYTES);
         final ParcelFileDescriptor descriptor = mPipeManager.readDocument(
@@ -60,60 +63,6 @@
         assertDescriptorError(descriptor);
     }
 
-    public void testWriteDocument_basic() throws Exception {
-        TestUtil.addTestDevice(mDatabase);
-        TestUtil.addTestStorage(mDatabase, "1");
-
-        final MtpObjectInfo info =
-                new MtpObjectInfo.Builder().setObjectHandle(1).setName("note.txt").build();
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] { info });
-        mDatabase.getMapper().stopAddingDocuments("2");
-        // Create a placeholder file which should be replaced by a real file later.
-        mtpManager.setObjectInfo(0, info);
-
-        // Upload testing bytes.
-        final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
-                getContext(),
-                mtpManager,
-                new Identifier(0, 0, 1, "2", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
-        final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(descriptor);
-        outputStream.write(HELLO_BYTES, 0, HELLO_BYTES.length);
-        outputStream.close();
-        mExecutor.shutdown();
-        assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
-
-        // Check if the placeholder file is removed.
-        try {
-            mtpManager.getObjectInfo(0, 1);
-            fail();  // The placeholder file has not been deleted.
-        } catch (IOException e) {
-            // Expected error, as the file is gone.
-        }
-
-        // Confirm that the target file is created.
-        final MtpObjectInfo targetDocument = mtpManager.getObjectInfo(
-                0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
-        assertTrue(targetDocument != null);
-
-        // Confirm the object handle is updated.
-        try (final Cursor cursor = mDatabase.queryDocument(
-                "2", new String[] { MtpDatabaseConstants.COLUMN_OBJECT_HANDLE })) {
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(TestMtpManager.CREATED_DOCUMENT_HANDLE, cursor.getInt(0));
-        }
-
-        // Verify uploaded bytes.
-        final byte[] uploadedBytes = mtpManager.getImportFileBytes(
-                0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
-        assertEquals(HELLO_BYTES.length, uploadedBytes.length);
-        for (int i = 0; i < HELLO_BYTES.length; i++) {
-            assertEquals(HELLO_BYTES[i], uploadedBytes[i]);
-        }
-    }
-
     public void testReadThumbnail_basic() throws Exception {
         mtpManager.setThumbnail(0, 1, HELLO_BYTES);
         final ParcelFileDescriptor descriptor = mPipeManager.readThumbnail(
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 1b46f3c..9a81489 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -22,6 +22,7 @@
 import android.util.SparseArray;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -38,6 +39,7 @@
     private final Map<String, int[]> mObjectHandles = new HashMap<>();
     private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
     private final Map<String, byte[]> mImportFileBytes = new HashMap<>();
+    private final Map<String, Long> mObjectSizeLongs = new HashMap<>();
 
     TestMtpManager(Context context) {
         super(context);
@@ -67,6 +69,10 @@
         mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
     }
 
+    void setObjectSizeLong(int deviceId, int objectHandle, int format, long value) {
+        mObjectSizeLongs.put(pack(deviceId, objectHandle, format), value);
+    }
+
     @Override
     MtpDeviceRecord[] getDevices() {
         final MtpDeviceRecord[] result = new MtpDeviceRecord[mDevices.size()];
@@ -84,28 +90,28 @@
     }
 
     @Override
-    void openDevice(int deviceId) throws IOException {
+    MtpDeviceRecord openDevice(int deviceId) throws IOException {
         final MtpDeviceRecord device = mDevices.get(deviceId);
-        if (device == null || device.opened) {
+        if (device == null) {
             throw new IOException();
         }
-        mDevices.put(
-                deviceId,
-                new MtpDeviceRecord(
-                        device.deviceId, device.name, device.deviceKey, true, device.roots, null,
-                        null));
+        final MtpDeviceRecord record = new MtpDeviceRecord(
+                device.deviceId, device.name, device.deviceKey, true, device.roots,
+                device.operationsSupported, device.eventsSupported);
+        mDevices.put(deviceId, record);
+        return record;
     }
 
     @Override
     void closeDevice(int deviceId) throws IOException {
         final MtpDeviceRecord device = mDevices.get(deviceId);
-        if (device == null || !device.opened) {
+        if (device == null) {
             throw new IOException();
         }
         mDevices.put(
                 deviceId,
                 new MtpDeviceRecord(device.deviceId, device.name, device.deviceKey, false,
-                        device.roots, null, null));
+                        device.roots, device.operationsSupported, device.eventsSupported));
     }
 
     @Override
@@ -198,19 +204,6 @@
     }
 
     @Override
-    int[] getOpenedDeviceIds() {
-        final int[] result = new int[mDevices.size()];
-        int count = 0;
-        for (int i = 0; i < mDevices.size(); i++) {
-            final MtpDeviceRecord device = mDevices.valueAt(i);
-            if (device.opened) {
-                result[count++] = device.deviceId;
-            }
-        }
-        return Arrays.copyOf(result, count);
-    }
-
-    @Override
     byte[] getObject(int deviceId, int objectHandle, int expectedSize) throws IOException {
         return mImportFileBytes.get(pack(deviceId, objectHandle));
     }
@@ -226,4 +219,14 @@
         }
         return i;
     }
+
+    @Override
+    long getObjectSizeLong(int deviceId, int objectHandle, int format) throws IOException {
+        final String key = pack(deviceId, objectHandle, format);
+        if (mObjectSizeLongs.containsKey(key)) {
+            return mObjectSizeLongs.get(key);
+        } else {
+            throw new IOException();
+        }
+    }
 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
index 34dd77b..8805d19 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
@@ -19,6 +19,7 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
 import android.os.SystemClock;
 
 import java.io.FileNotFoundException;
@@ -32,6 +33,15 @@
 final class TestUtil {
     private TestUtil() {}
 
+    static final int[] OPERATIONS_SUPPORTED = new int[] {
+            MtpConstants.OPERATION_GET_PARTIAL_OBJECT,
+            MtpConstants.OPERATION_SEND_OBJECT,
+            MtpConstants.OPERATION_SEND_OBJECT_INFO,
+            MtpConstants.OPERATION_DELETE_OBJECT,
+            MtpConstants.OPERATION_GET_OBJECT_PROP_DESC,
+            MtpConstants.OPERATION_GET_OBJECT_PROP_VALUE
+    };
+
     /**
      * Requests permission for a MTP device and returns the first MTP device that has at least one
      * storage.
@@ -59,14 +69,14 @@
     static void addTestDevice(MtpDatabase database) throws FileNotFoundException {
         database.getMapper().startAddingDocuments(null);
         database.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null,
-                null));
+                0, "Device", "device_key", /* opened is */ true, new MtpRoot[0],
+                OPERATIONS_SUPPORTED, null));
         database.getMapper().stopAddingDocuments(null);
     }
 
     static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException {
         database.getMapper().startAddingDocuments(parentId);
-        database.getMapper().putStorageDocuments(parentId, new MtpRoot[] {
+        database.getMapper().putStorageDocuments(parentId, OPERATIONS_SUPPORTED, new MtpRoot[] {
                 new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
         });
         database.getMapper().stopAddingDocuments(parentId);
diff --git a/packages/PrintServiceRecommendationService/Android.mk b/packages/PrintServiceRecommendationService/Android.mk
new file mode 100644
index 0000000..66cb057
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := PrintRecommendationService
+
+include $(BUILD_PACKAGE)
+
+LOCAL_SDK_VERSION := system_current
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintServiceRecommendationService/AndroidManifest.xml b/packages/PrintServiceRecommendationService/AndroidManifest.xml
new file mode 100644
index 0000000..0eb218c
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.printservice.recommendation">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:allowClearUserData="false"
+        android:label="@string/app_label"
+        android:allowBackup= "false">
+
+        <service
+            android:name=".RecommendationServiceImpl"
+            android:permission="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE">
+
+            <intent-filter>
+                <action android:name="android.printservice.recommendation.RecommendationService" />
+            </intent-filter>
+        </service>
+
+    </application>
+
+</manifest>
diff --git a/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2 b/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2
diff --git a/packages/PrintServiceRecommendationService/NOTICE b/packages/PrintServiceRecommendationService/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/packages/PrintServiceRecommendationService/res/values/donottranslate.xml b/packages/PrintServiceRecommendationService/res/values/donottranslate.xml
new file mode 100644
index 0000000..4cf0eaf
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/values/donottranslate.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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_label">Print Service Recommendation Service</string>
+</resources>
diff --git a/packages/PrintServiceRecommendationService/res/values/strings.xml b/packages/PrintServiceRecommendationService/res/values/strings.xml
new file mode 100644
index 0000000..07d0004
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  (c) Copyright 2016 Mopria Alliance, Inc.
+  (c) Copyright 2016 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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="plugin_vendor_hp">HP</string>
+    <string name="plugin_vendor_lexmark">Lexmark</string>
+    <string name="plugin_vendor_brother">Brother</string>
+    <string name="plugin_vendor_canon">Canon</string>
+    <string name="plugin_vendor_xerox">Xerox</string>
+    <string name="plugin_vendor_samsung">Samsung Electronics</string>
+    <string name="plugin_vendor_epson">Epson</string>
+    <string name="plugin_vendor_konika_minolta">Konika Minolta</string>
+    <string name="plugin_vendor_fuji">Fuji</string>
+</resources>
diff --git a/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
new file mode 100644
index 0000000..119943c
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  (c) Copyright 2016 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vendors>
+    <vendor>
+        <name>@string/plugin_vendor_hp</name>
+        <package>com.hp.android.printservice</package>
+        <mdns-names>
+            <mdns-name>HP</mdns-name>
+            <mdns-name>Hewlett-Packard</mdns-name>
+            <mdns-name>Hewlett Packard</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_lexmark</name>
+        <package>com.lexmark.print.plugin</package>
+        <mdns-names>
+            <mdns-name>Lexmark</mdns-name>
+            <mdns-name>Lexmark International</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_brother</name>
+        <package>com.brother.printservice</package>
+        <mdns-names>
+            <mdns-name>Brother</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_canon</name>
+        <package>jp.co.canon.android.printservice.plugin</package>
+        <mdns-names>
+            <mdns-name>Canon</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_xerox</name>
+        <package>com.xerox.printservice</package>
+        <mdns-names>
+            <mdns-name>Xerox</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_samsung</name>
+        <package>com.sec.app.samsungprintservice</package>
+        <mdns-names>
+            <mdns-name>Samsung</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_epson</name>
+        <package>com.epson.mobilephone.android.epsonprintserviceplugin</package>
+        <mdns-names>
+            <mdns-name>Epson</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_konika_minolta</name>
+        <package>com.kmbt.printservice</package>
+        <mdns-names>
+            <mdns-name>kmkmkm</mdns-name>
+            <mdns-name>Konica Minolta</mdns-name>
+            <mdns-name>Minolta</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_fuji</name>
+        <package>jp.co.fujixerox.prt.PrintUtil.PCL</package>
+        <mdns-names>
+            <mdns-name>FUJI XEROX</mdns-name>
+        </mdns-names>
+    </vendor>
+</vendors>
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
new file mode 100644
index 0000000..d604ef8
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+
+/**
+ * Interface to be implemented by each print service plugin.
+ * <p/>
+ * A print service plugin is a minimal version of a real {@link android.printservice.PrintService
+ * print service}. You cannot print using the plugin. The only functionality in the plugin is to
+ * report the number of printers that the real service would discover.
+ */
+public interface PrintServicePlugin {
+    /**
+     * Call back used by the print service plugins.
+     */
+    interface PrinterDiscoveryCallback {
+        /**
+         * Announce that something changed and the UI for this plugin should be updated.
+         *
+         * @param numDiscoveredPrinters The number of printers discovered.
+         */
+        void onChanged(@IntRange(from = 0) int numDiscoveredPrinters);
+    }
+
+    /**
+     * Get the name (a string reference) of the {@link android.printservice.PrintService print
+     * service} with the {@link #getPackageName specified package name}. This is read once, hence
+     * returning different data at different times is not allowed.
+     *
+     * @return The name of the print service as a string reference. The localization is handled
+     *         outside of the plugin.
+     */
+    @StringRes int getName();
+
+    /**
+     * The package name of the full print service.
+     *
+     * @return The package name
+     */
+    @NonNull CharSequence getPackageName();
+
+    /**
+     * Start the discovery plugin.
+     *
+     * @param callback Callbacks used by this plugin.
+     *
+     * @throws Exception If anything went wrong when starting the plugin
+     */
+    void start(@NonNull PrinterDiscoveryCallback callback) throws Exception;
+
+    /**
+     * Stop the plugin. This can only return once the plugin is completely finished and cleaned up.
+     *
+     * @throws Exception If anything went wrong while stopping plugin
+     */
+    void stop() throws Exception;
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
new file mode 100644
index 0000000..9f6dad8
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation;
+
+import android.content.res.Configuration;
+import android.printservice.recommendation.RecommendationInfo;
+import android.printservice.recommendation.RecommendationService;
+import android.printservice.PrintService;
+import android.util.Log;
+import com.android.printservice.recommendation.plugin.mdnsFilter.MDNSFilterPlugin;
+import com.android.printservice.recommendation.plugin.mdnsFilter.VendorConfig;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Service that recommends {@link PrintService print services} that might be a good idea to install.
+ */
+public class RecommendationServiceImpl extends RecommendationService
+        implements RemotePrintServicePlugin.OnChangedListener {
+    private static final String LOG_TAG = "PrintServiceRecService";
+
+    /** All registered plugins */
+    private ArrayList<RemotePrintServicePlugin> mPlugins;
+
+    @Override
+    public void onConnected() {
+        mPlugins = new ArrayList<>();
+
+        try {
+            for (VendorConfig config : VendorConfig.getAllConfigs(this)) {
+                try {
+                    mPlugins.add(new RemotePrintServicePlugin(new MDNSFilterPlugin(this,
+                            config.name, config.packageName, config.mDNSNames), this, false));
+                } catch (Exception e) {
+                    Log.e(LOG_TAG, "Could not initiate simple MDNS plugin for " +
+                            config.packageName, e);
+                }
+            }
+        } catch (IOException | XmlPullParserException e) {
+            new RuntimeException("Could not parse vendorconfig", e);
+        }
+
+        final int numPlugins = mPlugins.size();
+        for (int i = 0; i < numPlugins; i++) {
+            try {
+                mPlugins.get(i).start();
+            } catch (RemotePrintServicePlugin.PluginException e) {
+                Log.e(LOG_TAG, "Could not start plugin", e);
+            }
+        }
+    }
+
+    @Override
+    public void onDisconnected() {
+        final int numPlugins = mPlugins.size();
+        for (int i = 0; i < numPlugins; i++) {
+            try {
+                mPlugins.get(i).stop();
+            } catch (RemotePrintServicePlugin.PluginException e) {
+                Log.e(LOG_TAG, "Could not stop plugin", e);
+            }
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // Need to update plugin names as they might be localized
+        onChanged();
+    }
+
+    @Override
+    public void onChanged() {
+        ArrayList<RecommendationInfo> recommendations = new ArrayList<>();
+
+        final int numPlugins = mPlugins.size();
+        for (int i = 0; i < numPlugins; i++) {
+            RemotePrintServicePlugin plugin = mPlugins.get(i);
+
+            try {
+                int numPrinters = plugin.getNumPrinters();
+
+                if (numPrinters > 0) {
+                    recommendations.add(new RecommendationInfo(plugin.packageName,
+                            getString(plugin.name), numPrinters,
+                            plugin.recommendsMultiVendorService));
+                }
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Could not read state of plugin for " + plugin.packageName, e);
+            }
+        }
+
+        updateRecommendations(recommendations);
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
new file mode 100644
index 0000000..dbd1649
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Wrapper for a {@link PrintServicePlugin}, isolating issues with the plugin as good as possible
+ * from the {@link RecommendationServiceImpl service}.
+ */
+class RemotePrintServicePlugin implements PrintServicePlugin.PrinterDiscoveryCallback {
+    /** Lock for this object */
+    private final Object mLock = new Object();
+
+    /** The name of the print service. */
+    public final @StringRes int name;
+
+    /** If the print service if for more than a single vendor */
+    public final boolean recommendsMultiVendorService;
+
+    /** The package name of the full print service */
+    public final @NonNull CharSequence packageName;
+
+    /** Wrapped plugin */
+    private final @NonNull PrintServicePlugin mPlugin;
+
+    /** The number of printers discovered by the plugin */
+    private @IntRange(from = 0) int mNumPrinters;
+
+    /** If the plugin is started by not yet stopped */
+    private boolean isRunning;
+
+    /** Listener for changes to {@link #mNumPrinters}. */
+    private @NonNull OnChangedListener mListener;
+
+    /**
+     * Create a new remote for a {@link PrintServicePlugin plugin}.
+     *
+     * @param plugin                       The plugin to be wrapped
+     * @param listener                     The listener to be notified about changes in this plugin
+     * @param recommendsMultiVendorService If the plugin detects printers of more than a single
+     *                                     vendor
+     *
+     * @throws PluginException If the plugin has issues while caching basic stub properties
+     */
+    public RemotePrintServicePlugin(@NonNull PrintServicePlugin plugin,
+            @NonNull OnChangedListener listener, boolean recommendsMultiVendorService)
+            throws PluginException {
+        mListener = listener;
+        mPlugin = plugin;
+        this.recommendsMultiVendorService = recommendsMultiVendorService;
+
+        // We handle any throwable to isolate our self from bugs in the plugin code.
+        // Cache simple properties to avoid having to deal with exceptions later in the code.
+        try {
+            name = Preconditions.checkArgumentPositive(mPlugin.getName(), "name");
+            packageName = Preconditions.checkStringNotEmpty(mPlugin.getPackageName(),
+                    "packageName");
+        } catch (Throwable e) {
+            throw new PluginException(mPlugin, "Cannot cache simple properties ", e);
+        }
+
+        isRunning = false;
+    }
+
+    /**
+     * Start the plugin. From now on there might be callbacks to the registered listener.
+     */
+    public void start()
+            throws PluginException {
+        // We handle any throwable to isolate our self from bugs in the stub code
+        try {
+            synchronized (mLock) {
+                isRunning = true;
+                mPlugin.start(this);
+            }
+        } catch (Throwable e) {
+            throw new PluginException(mPlugin, "Cannot start", e);
+        }
+    }
+
+    /**
+     * Stop the plugin. From this call on there will not be any more callbacks.
+     */
+    public void stop() throws PluginException {
+        // We handle any throwable to isolate our self from bugs in the stub code
+        try {
+            synchronized (mLock) {
+                mPlugin.stop();
+                isRunning = false;
+            }
+        } catch (Throwable e) {
+            throw new PluginException(mPlugin, "Cannot stop", e);
+        }
+    }
+
+    /**
+     * Get the current number of printers reported by the stub.
+     *
+     * @return The number of printers reported by the stub.
+     */
+    public @IntRange(from = 0) int getNumPrinters() {
+        return mNumPrinters;
+    }
+
+    @Override
+    public void onChanged(@IntRange(from = 0) int numDiscoveredPrinters) {
+        synchronized (mLock) {
+            Preconditions.checkState(isRunning);
+
+            mNumPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters,
+                    "numDiscoveredPrinters");
+
+            if (mNumPrinters > 0) {
+                mListener.onChanged();
+            }
+        }
+    }
+
+    /**
+     * Listener to listen for changes to {@link #getNumPrinters}
+     */
+    public interface OnChangedListener {
+        void onChanged();
+    }
+
+    /**
+     * Exception thrown if the stub has any issues.
+     */
+    public class PluginException extends Exception {
+        private PluginException(PrintServicePlugin plugin, String message, Throwable e) {
+            super(plugin + ": " + message, e);
+        }
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
new file mode 100644
index 0000000..26300b1
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation.plugin.mdnsFilter;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.PrintServicePlugin;
+import com.android.printservice.recommendation.util.MDNSUtils;
+import com.android.printservice.recommendation.util.NsdResolveQueue;
+
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * A plugin listening for mDNS results and only adding the ones that {@link
+ * MDNSUtils#isVendorPrinter match} configured list
+ */
+public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.DiscoveryListener {
+    private static final String LOG_TAG = "MDNSFilterPlugin";
+
+    private static final String PRINTER_SERVICE_TYPE = "_ipp._tcp";
+
+    /** Name of the print service this plugin is for */
+    private final @StringRes int mName;
+
+    /** Package name of the print service this plugin is for */
+    private final @NonNull CharSequence mPackageName;
+
+    /** mDNS names handled by the print service this plugin is for */
+    private final @NonNull HashSet<String> mMDNSNames;
+
+    /** Printer identifiers of the mPrinters found. */
+    @GuardedBy("mLock")
+    private final @NonNull HashSet<String> mPrinters;
+
+    /** Context of the user of this plugin */
+    private final @NonNull Context mContext;
+
+    /**
+     * Call back to report the number of mPrinters found.
+     *
+     * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
+     * safe to not synchronize access to this field.
+     */
+    private @Nullable PrinterDiscoveryCallback mCallback;
+
+    /** Queue used to resolve nsd infos */
+    private final @NonNull NsdResolveQueue mResolveQueue;
+
+    /**
+     * Create new stub that assumes that a print service can be used to print on all mPrinters
+     * matching some mDNS names.
+     *
+     * @param context     The context the plugin runs in
+     * @param name        The user friendly name of the print service
+     * @param packageName The package name of the print service
+     * @param mDNSNames   The mDNS names of the printer.
+     */
+    public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
+            @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
+        mContext = Preconditions.checkNotNull(context, "context");
+        mName = mContext.getResources().getIdentifier(Preconditions.checkStringNotEmpty(name,
+                "name"), null, mContext.getPackageName());
+        mPackageName = Preconditions.checkStringNotEmpty(packageName);
+        mMDNSNames = new HashSet<>(Preconditions
+                .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(mDNSNames,
+                        "mDNSNames"), "mDNSNames"));
+
+        mResolveQueue = NsdResolveQueue.getInstance();
+        mPrinters = new HashSet<>();
+    }
+
+    @Override
+    public @NonNull CharSequence getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * @return The NDS manager
+     */
+    private NsdManager getNDSManager() {
+        return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
+    }
+
+    @Override
+    public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
+        mCallback = callback;
+
+        getNDSManager().discoverServices(PRINTER_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
+                this);
+    }
+
+    @Override
+    public @StringRes int getName() {
+        return mName;
+    }
+
+    @Override
+    public void stop() throws Exception {
+        mCallback.onChanged(0);
+        mCallback = null;
+
+        getNDSManager().stopServiceDiscovery(this);
+    }
+
+    @Override
+    public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+        Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
+                + errorCode);
+    }
+
+    @Override
+    public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+        Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": "
+                + errorCode);
+    }
+
+    @Override
+    public void onDiscoveryStarted(String serviceType) {
+        // empty
+    }
+
+    @Override
+    public void onDiscoveryStopped(String serviceType) {
+        mPrinters.clear();
+    }
+
+    @Override
+    public void onServiceFound(NsdServiceInfo serviceInfo) {
+        mResolveQueue.resolve(getNDSManager(), serviceInfo,
+                new NsdManager.ResolveListener() {
+            @Override
+            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+                Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
+                        errorCode);
+            }
+
+            @Override
+            public void onServiceResolved(NsdServiceInfo serviceInfo) {
+                if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
+                    if (mCallback != null) {
+                        boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
+
+                        if (added) {
+                            mCallback.onChanged(mPrinters.size());
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onServiceLost(NsdServiceInfo serviceInfo) {
+        mResolveQueue.resolve(getNDSManager(), serviceInfo,
+                new NsdManager.ResolveListener() {
+            @Override
+            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+                Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
+                        + errorCode);
+            }
+
+            @Override
+            public void onServiceResolved(NsdServiceInfo serviceInfo) {
+                if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
+                    if (mCallback != null) {
+                        boolean removed = mPrinters
+                                .remove(serviceInfo.getHost().getHostAddress());
+
+                        if (removed) {
+                            mCallback.onChanged(mPrinters.size());
+                        }
+                    }
+                }
+            }
+        });
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java
new file mode 100644
index 0000000..57d5c71
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation.plugin.mdnsFilter;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import com.android.internal.annotations.Immutable;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Vendor configuration as read from {@link R.xml#vendorconfigs vendorconfigs.xml}. Configuration
+ * can be read via {@link #getConfig(Context, String)}.
+ */
+@Immutable
+public class VendorConfig {
+    /** Lock for {@link #sConfigs} */
+    private static final Object sLock = new Object();
+
+    /** Strings used as XML tags */
+    private static final String VENDORS_TAG = "vendors";
+    private static final String VENDOR_TAG = "vendor";
+    private static final String NAME_TAG = "name";
+    private static final String PACKAGE_TAG = "package";
+    private static final String MDNSNAMES_TAG = "mdns-names";
+    private static final String MDNSNAME_TAG = "mdns-name";
+
+    /** Map from vendor name to config. Initialized on first {@link #getConfig use}. */
+    private static @Nullable ArrayMap<String, VendorConfig> sConfigs;
+
+    /** Localized vendor name */
+    public final @NonNull String name;
+
+    /** Package name containing the print service for this vendor */
+    public final @NonNull String packageName;
+
+    /** mDNS names used by this vendor */
+    public final @NonNull List<String> mDNSNames;
+
+    /**
+     * Create an immutable configuration.
+     */
+    private VendorConfig(@NonNull String name, @NonNull String packageName,
+            @NonNull List<String> mDNSNames) {
+        this.name = Preconditions.checkStringNotEmpty(name);
+        this.packageName = Preconditions.checkStringNotEmpty(packageName);
+        this.mDNSNames = Preconditions.checkCollectionElementsNotNull(mDNSNames, "mDNSName");
+    }
+
+    /**
+     * Get the configuration for a vendor.
+     *
+     * @param context Calling context
+     * @param name    The name of the config to read
+     *
+     * @return the config for the vendor or null if not found
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    public static @Nullable VendorConfig getConfig(@NonNull Context context, @NonNull String name)
+            throws IOException, XmlPullParserException {
+        synchronized (sLock) {
+            if (sConfigs == null) {
+                sConfigs = readVendorConfigs(context);
+            }
+
+            return sConfigs.get(name);
+        }
+    }
+
+    /**
+     * Get all known vendor configurations.
+     *
+     * @param context Calling context
+     *
+     * @return The known configurations
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    public static @NonNull Collection<VendorConfig> getAllConfigs(@NonNull Context context)
+            throws IOException, XmlPullParserException {
+        synchronized (sLock) {
+            if (sConfigs == null) {
+                sConfigs = readVendorConfigs(context);
+            }
+
+            return sConfigs.values();
+        }
+    }
+
+    /**
+     * Read the text from a XML tag.
+     *
+     * @param parser XML parser to read from
+     *
+     * @return The text or "" if no text was found
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    private static @NonNull String readText(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        String result = "";
+
+        if (parser.next() == XmlPullParser.TEXT) {
+            result = parser.getText();
+            parser.nextTag();
+        }
+
+        return result;
+    }
+
+    /**
+     * Read a tag with a text content from the parser.
+     *
+     * @param parser  XML parser to read from
+     * @param tagName The name of the tag to read
+     *
+     * @return The text content of the tag
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    private static @NonNull String readSimpleTag(@NonNull Context context,
+            @NonNull XmlPullParser parser, @NonNull String tagName, boolean resolveReferences)
+            throws IOException, XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, null, tagName);
+        String text = readText(parser);
+        parser.require(XmlPullParser.END_TAG, null, tagName);
+
+        if (resolveReferences && text.startsWith("@")) {
+            return context.getResources().getString(
+                    context.getResources().getIdentifier(text, null, context.getPackageName()));
+        } else {
+            return text;
+        }
+    }
+
+    /**
+     * Read content of a list of tags.
+     *
+     * @param parser     XML parser to read from
+     * @param tagName    The name of the list tag
+     * @param subTagName The name of the list-element tags
+     * @param tagReader  The {@link TagReader reader} to use to read the tag content
+     * @param <T>        The type of the parsed tag content
+     *
+     * @return A list of {@link T}
+     *
+     * @throws XmlPullParserException
+     * @throws IOException
+     */
+    private static @NonNull <T> ArrayList<T> readTagList(@NonNull XmlPullParser parser,
+            @NonNull String tagName, @NonNull String subTagName, @NonNull TagReader<T> tagReader)
+            throws XmlPullParserException, IOException {
+        ArrayList<T> entries = new ArrayList<>();
+
+        parser.require(XmlPullParser.START_TAG, null, tagName);
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (parser.getName().equals(subTagName)) {
+                entries.add(tagReader.readTag(parser, subTagName));
+            } else {
+                throw new XmlPullParserException(
+                        "Unexpected subtag of " + tagName + ": " + parser.getName());
+            }
+        }
+
+        return entries;
+    }
+
+    /**
+     * Read the vendor configuration file.
+     *
+     * @param context The content issuing the read
+     *
+     * @return An map pointing from vendor name to config
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    private static @NonNull ArrayMap<String, VendorConfig> readVendorConfigs(
+            @NonNull final Context context) throws IOException, XmlPullParserException {
+        try (XmlResourceParser parser = context.getResources().getXml(R.xml.vendorconfigs)) {
+            // Skip header
+            int parsingEvent;
+            do {
+                parsingEvent = parser.next();
+            } while (parsingEvent != XmlResourceParser.START_TAG);
+
+            ArrayList<VendorConfig> configs = readTagList(parser, VENDORS_TAG, VENDOR_TAG,
+                    new TagReader<VendorConfig>() {
+                        public VendorConfig readTag(XmlPullParser parser, String tagName)
+                                throws XmlPullParserException, IOException {
+                            return readVendorConfig(context, parser, tagName);
+                        }
+                    });
+
+            ArrayMap<String, VendorConfig> configMap = new ArrayMap<>(configs.size());
+            final int numConfigs = configs.size();
+            for (int i = 0; i < numConfigs; i++) {
+                VendorConfig config = configs.get(i);
+
+                configMap.put(config.name, config);
+            }
+
+            return configMap;
+        }
+    }
+
+    /**
+     * Read a single vendor configuration.
+     *
+     * @param parser  XML parser to read from
+     * @param tagName The vendor tag
+     * @param context Calling context
+     *
+     * @return A config
+     *
+     * @throws XmlPullParserException
+     * @throws IOException
+     */
+    private static VendorConfig readVendorConfig(@NonNull final Context context,
+            @NonNull XmlPullParser parser, @NonNull String tagName) throws XmlPullParserException,
+            IOException {
+        parser.require(XmlPullParser.START_TAG, null, tagName);
+
+        String name = null;
+        String packageName = null;
+        List<String> mDNSNames = null;
+
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String subTagName = parser.getName();
+
+            switch (subTagName) {
+                case NAME_TAG:
+                    name = readSimpleTag(context, parser, NAME_TAG, false);
+                    break;
+                case PACKAGE_TAG:
+                    packageName = readSimpleTag(context, parser, PACKAGE_TAG, true);
+                    break;
+                case MDNSNAMES_TAG:
+                    mDNSNames = readTagList(parser, MDNSNAMES_TAG, MDNSNAME_TAG,
+                            new TagReader<String>() {
+                                public String readTag(XmlPullParser parser, String tagName)
+                                        throws XmlPullParserException, IOException {
+                                    return readSimpleTag(context, parser, tagName, true);
+                                }
+                            }
+                    );
+                    break;
+                default:
+                    throw new XmlPullParserException("Unexpected subtag of " + tagName + ": "
+                            + subTagName);
+
+            }
+        }
+
+        if (name == null) {
+            throw new XmlPullParserException("name is required");
+        }
+
+        if (packageName == null) {
+            throw new XmlPullParserException("package is required");
+        }
+
+        if (mDNSNames == null) {
+            mDNSNames = Collections.emptyList();
+        }
+
+        // A vendor config should be immutable
+        mDNSNames = Collections.unmodifiableList(mDNSNames);
+
+        return new VendorConfig(name, packageName, mDNSNames);
+    }
+
+    @Override
+    public String toString() {
+        return name + " -> " + packageName + ", " + mDNSNames;
+    }
+
+    /**
+     * Used a a "function pointer" when reading a tag in {@link #readTagList(XmlPullParser, String,
+     * String, TagReader)}.
+     *
+     * @param <T> The type of content to read
+     */
+    private interface TagReader<T> {
+        T readTag(XmlPullParser parser, String tagName) throws XmlPullParserException, IOException;
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
new file mode 100644
index 0000000..0541c35
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
@@ -0,0 +1,98 @@
+/*
+ * (c) Copyright 2016 Mopria Alliance, Inc.
+ * (c) Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation.util;
+
+import android.annotation.NonNull;
+import android.net.nsd.NsdServiceInfo;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utils for dealing with mDNS attributes
+ */
+public class MDNSUtils {
+    public static final String ATTRIBUTE_TY = "ty";
+    public static final String ATTRIBUTE_PRODUCT = "product";
+    public static final String ATTRIBUTE_USB_MFG = "usb_mfg";
+    public static final String ATTRIBUTE_MFG = "mfg";
+
+    /**
+     * Check if the service has any of a set of vendor names.
+     *
+     * @param serviceInfo The service
+     * @param vendorNames The vendors
+     *
+     * @return true iff the has any of the set of vendor names
+     */
+    public static boolean isVendorPrinter(@NonNull NsdServiceInfo serviceInfo,
+            @NonNull Set<String> vendorNames) {
+        for (Map.Entry<String, byte[]> entry : serviceInfo.getAttributes().entrySet()) {
+            // keys are case insensitive
+            String key = entry.getKey().toLowerCase();
+
+            switch (key) {
+                case ATTRIBUTE_TY:
+                case ATTRIBUTE_PRODUCT:
+                case ATTRIBUTE_USB_MFG:
+                case ATTRIBUTE_MFG:
+                    if (entry.getValue() != null) {
+                        if (containsVendor(new String(entry.getValue(), StandardCharsets.UTF_8),
+                                vendorNames)) {
+                            return true;
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Check if the attribute matches any of the vendor names, ignoring capitalization.
+     *
+     * @param attr        The attribute
+     * @param vendorNames The vendor names
+     *
+     * @return true iff the attribute matches any of the vendor names
+     */
+    private static boolean containsVendor(@NonNull String attr, @NonNull Set<String> vendorNames) {
+        for (String name : vendorNames) {
+            if (containsString(attr.toLowerCase(), name.toLowerCase())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if a string in another string.
+     *
+     * @param container The string that contains the string
+     * @param contained The string that is contained
+     *
+     * @return true if the string is contained in the other
+     */
+    private static boolean containsString(@NonNull String container, @NonNull String contained) {
+        return container.equalsIgnoreCase(contained) || container.contains(contained + " ");
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java
new file mode 100644
index 0000000..fad50f6
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation.util;
+
+import android.annotation.NonNull;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.LinkedList;
+
+/**
+ * Nsd resolve requests for the same info cancel each other. Hence this class synchronizes the
+ * resolutions to hide this effect.
+ */
+public class NsdResolveQueue {
+    /** Lock for {@link #sInstance} */
+    private static final Object sLock = new Object();
+
+    /** Instance of this singleton */
+    @GuardedBy("sLock")
+    private static NsdResolveQueue sInstance;
+
+    /** Lock for {@link #mResolveRequests} */
+    private final Object mLock = new Object();
+
+    /** Current set of registered service info resolve attempts */
+    @GuardedBy("mLock")
+    private final LinkedList<NsdResolveRequest> mResolveRequests = new LinkedList<>();
+
+    public static NsdResolveQueue getInstance() {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                sInstance = new NsdResolveQueue();
+            }
+
+            return sInstance;
+        }
+    }
+
+    /**
+     * Container for a request to resolve a serviceInfo.
+     */
+    private static class NsdResolveRequest {
+        final @NonNull NsdManager nsdManager;
+        final @NonNull NsdServiceInfo serviceInfo;
+        final @NonNull NsdManager.ResolveListener listener;
+
+        private NsdResolveRequest(@NonNull NsdManager nsdManager,
+                @NonNull NsdServiceInfo serviceInfo, @NonNull NsdManager.ResolveListener listener) {
+            this.nsdManager = nsdManager;
+            this.serviceInfo = serviceInfo;
+            this.listener = listener;
+        }
+    }
+
+    /**
+     * Resolve a serviceInfo or queue the request if there is a request currently in flight.
+     *
+     * @param nsdManager  The nsd manager to use
+     * @param serviceInfo The service info to resolve
+     * @param listener    The listener to call back once the info is resolved.
+     */
+    public void resolve(@NonNull NsdManager nsdManager, @NonNull NsdServiceInfo serviceInfo,
+            @NonNull NsdManager.ResolveListener listener) {
+        synchronized (mLock) {
+            mResolveRequests.addLast(new NsdResolveRequest(nsdManager, serviceInfo,
+                    new ListenerWrapper(listener)));
+
+            if (mResolveRequests.size() == 1) {
+                resolveNextRequest();
+            }
+        }
+    }
+
+    /**
+     * Wrapper for a {@link NsdManager.ResolveListener}. Calls the listener and then
+     * {@link #resolveNextRequest()}.
+     */
+    private class ListenerWrapper implements NsdManager.ResolveListener {
+        private final @NonNull NsdManager.ResolveListener mListener;
+
+        private ListenerWrapper(@NonNull NsdManager.ResolveListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+            mListener.onResolveFailed(serviceInfo, errorCode);
+
+            synchronized (mLock) {
+                mResolveRequests.pop();
+                resolveNextRequest();
+            }
+        }
+
+        @Override
+        public void onServiceResolved(NsdServiceInfo serviceInfo) {
+            mListener.onServiceResolved(serviceInfo);
+
+            synchronized (mLock) {
+                mResolveRequests.pop();
+                resolveNextRequest();
+            }
+        }
+    }
+
+    /**
+     * Resolve the next request if there is one.
+     */
+    private void resolveNextRequest() {
+        if (!mResolveRequests.isEmpty()) {
+            NsdResolveRequest request = mResolveRequests.getFirst();
+
+            request.nsdManager.resolveService(request.serviceInfo, request.listener);
+        }
+    }
+
+}
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index af9d251..ed6fdb7 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -23,16 +23,12 @@
          on the device. Usually an app can access only the print jobs it created. -->
     <permission
         android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"
-        android:label="@string/permlab_accessAllPrintJobs"
-        android:description="@string/permdesc_accessAllPrintJobs"
         android:protectionLevel="signature" />
 
     <!-- May be required by the settings and add printer activities of a
          print service if the developer wants only trusted system code to
          be able to launch these activities. -->
     <permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
-        android:label="@string/permlab_startPrintServiceConfigActivity"
-        android:description="@string/permdesc_startPrintServiceConfigActivity"
         android:protectionLevel="signature" />
 
     <uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
@@ -61,9 +57,9 @@
 
         <activity
             android:name=".ui.PrintActivity"
-            android:configChanges="screenSize|smallestScreenSize|orientation"
+            android:configChanges="screenSize|smallestScreenSize|orientation|locale|keyboard|keyboardHidden|fontScale|uiMode|layoutDirection"
             android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
-            android:theme="@style/PrintActivity">
+            android:theme="@style/Theme.PrintActivity">
             <intent-filter>
                 <action android:name="android.print.PRINT_DIALOG" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -74,7 +70,14 @@
         <activity
             android:name=".ui.SelectPrinterActivity"
             android:label="@string/all_printers_label"
-            android:theme="@android:style/Theme.Material.Settings"
+            android:theme="@style/Theme.SelectPrinterActivity"
+            android:exported="false">
+        </activity>
+
+        <activity
+            android:name=".ui.AddPrinterActivity"
+            android:label="@string/print_add_printer"
+            android:theme="@style/Theme.AddPrinterActivity"
             android:exported="false">
         </activity>
 
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
index 1530a02..1ce3949 100644
--- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -50,6 +50,10 @@
     size_t remainingBytes = byteCount;
     while (remainingBytes > 0) {
         ssize_t readByteCount = read(fd, readBuffer, remainingBytes);
+
+        remainingBytes -= readByteCount;
+        readBuffer += readByteCount;
+
         if (readByteCount == -1) {
             if (errno == EINTR) {
                 continue;
@@ -57,9 +61,12 @@
             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
                     "Error reading from buffer: %d", errno);
             return false;
+        } else if (readByteCount == 0 && remainingBytes > 0) {
+            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                    "File closed before all bytes were read. %zu/%zu remaining", remainingBytes,
+                    byteCount);
+            return false;
         }
-        remainingBytes -= readByteCount;
-        readBuffer += readByteCount;
     }
     return true;
 }
diff --git a/packages/PrintSpooler/res/drawable/ic_add.xml b/packages/PrintSpooler/res/drawable/ic_add.xml
index 1442b1b..f728e7d 100644
--- a/packages/PrintSpooler/res/drawable/ic_add.xml
+++ b/packages/PrintSpooler/res/drawable/ic_add.xml
@@ -21,5 +21,5 @@
         android:viewportHeight="24.0">
     <path
         android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="?android:attr/colorAccent"/>
 </vector>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/drawable/ic_download_from_market.xml b/packages/PrintSpooler/res/drawable/ic_download_from_market.xml
new file mode 100644
index 0000000..44a5edf
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_download_from_market.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="36dp"
+        android:height="36dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+            android:pathData="M40,12h-8L32,8l-4,-4h-8l-4,4v4L8,12c-2.21,0 -3.98,1.79 -3.98,4L4,38c0,2.21 1.79,4 4,4h32c2.21,0 4,-1.79 4,-4L44,16c0,-2.21 -1.79,-4 -4,-4zM20,8h8v4h-8L20,8zM24,38L14,28h6v-8h8v8h6L24,38z"
+            android:fillColor="?android:attr/colorAccent"/>
+</vector>
diff --git a/packages/PrintSpooler/res/drawable/ic_print.xml b/packages/PrintSpooler/res/drawable/ic_print.xml
index dc6e0fb..e5e4d075 100644
--- a/packages/PrintSpooler/res/drawable/ic_print.xml
+++ b/packages/PrintSpooler/res/drawable/ic_print.xml
@@ -16,4 +16,4 @@
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
     android:src="@*android:drawable/ic_print"
-    android:tint="@color/promoted_action_background_color" />
+    android:tint="?android:attr/colorAccent" />
diff --git a/packages/PrintSpooler/res/drawable/page_selector_background.xml b/packages/PrintSpooler/res/drawable/page_selector_background.xml
index 7f1da31..4d32328 100644
--- a/packages/PrintSpooler/res/drawable/page_selector_background.xml
+++ b/packages/PrintSpooler/res/drawable/page_selector_background.xml
@@ -22,14 +22,14 @@
         android:state_selected="true">
         <bitmap
             android:src="@drawable/ic_check_circle"
-            android:tint="@color/promoted_action_background_color">
+            android:tint="?android:attr/colorAccent">
         </bitmap>
     </item>
 
     <item>
         <bitmap
             android:src="@drawable/ic_remove_circle"
-            android:tint="@color/promoted_action_background_color">
+            android:tint="?android:attr/colorAccent">
         </bitmap>
     </item>
 
diff --git a/packages/PrintSpooler/res/drawable/print_button_background.xml b/packages/PrintSpooler/res/drawable/print_button_background.xml
index aec8474..ad16547 100644
--- a/packages/PrintSpooler/res/drawable/print_button_background.xml
+++ b/packages/PrintSpooler/res/drawable/print_button_background.xml
@@ -18,7 +18,7 @@
     android:shape="oval">
 
     <solid
-        android:color="@color/promoted_action_background_color">
+        android:color="?android:attr/colorAccent">
     </solid>
 
     <size
diff --git a/packages/PrintSpooler/res/drawable/print_warning.xml b/packages/PrintSpooler/res/drawable/print_warning.xml
new file mode 100644
index 0000000..35f0fed
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/print_warning.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="96dp"
+        android:height="96dp"
+        android:viewportWidth="96.0"
+        android:viewportHeight="96.0">
+    <path
+        android:fillColor="#C8CCCE"
+        android:pathData="M4,84H92L48,8 4,84zM52,72h-8v-8h8v8zM52,56H44V40h8v16z"/>
+</vector>
diff --git a/packages/PrintSpooler/res/layout/add_printer_activity.xml b/packages/PrintSpooler/res/layout/add_printer_activity.xml
new file mode 100644
index 0000000..117bba1
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_activity.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip">
+
+    <ListView android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="-16dip"
+            android:id="@android:id/list" />
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/add_printer_list_header.xml b/packages/PrintSpooler/res/layout/add_printer_list_header.xml
new file mode 100644
index 0000000..ff342cb
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_list_header.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="?android:attr/listPreferredItemHeightSmall"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:orientation="horizontal"
+        android:gravity="start|center_vertical">
+
+    <TextView android:id="@+id/text"
+            style="?android:attr/listSeparatorTextViewStyle" />
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/add_printer_list_item.xml b/packages/PrintSpooler/res/layout/add_printer_list_item.xml
new file mode 100644
index 0000000..1a2e774
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_list_item.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="?android:attr/listPreferredItemHeightSmall"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal"
+    android:gravity="start|center_vertical">
+
+    <ImageView
+        android:layout_width="24dip"
+        android:layout_height="24dip"
+        android:layout_gravity="center_vertical"
+        android:contentDescription="@null"
+        android:layout_marginEnd="16dip"
+        android:src="@drawable/ic_add" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dip">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:text="@string/print_add_printer" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/all_print_services_list_item.xml b/packages/PrintSpooler/res/layout/all_print_services_list_item.xml
new file mode 100644
index 0000000..a2471c6
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/all_print_services_list_item.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="?android:attr/listPreferredItemHeightSmall"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal"
+    android:gravity="start|center_vertical">
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="56dip">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:text="@string/all_services_title" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml b/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml
new file mode 100644
index 0000000..73d0933
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal"
+    android:gravity="start|center_vertical">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="40dip"
+        android:layout_height="40dip"
+        android:layout_gravity="center_vertical"
+        android:contentDescription="@null" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dip">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:singleLine="true"
+            android:ellipsize="end" />
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:text="@string/enable_print_service" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml b/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml
new file mode 100644
index 0000000..c13487a
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal"
+    android:gravity="start|center_vertical">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="40dip"
+        android:layout_height="40dip"
+        android:layout_gravity="center_vertical"
+        android:contentDescription="@null" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dip">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:singleLine="true"
+            android:ellipsize="end" />
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/preview_page_error.xml b/packages/PrintSpooler/res/layout/preview_page_error.xml
new file mode 100644
index 0000000..4e9fb77
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/preview_page_error.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="fill_parent"
+        android:orientation="vertical"
+        android:gravity="center">
+
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="12dip"
+            android:src="@drawable/print_warning"
+            android:contentDescription="@null" />
+
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip"
+            android:gravity="center_horizontal"
+            android:textColor="@android:color/black"
+            android:text="@string/print_cannot_load_page" />
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/print_activity_controls.xml b/packages/PrintSpooler/res/layout/print_activity_controls.xml
index a87afe0..248d0c0 100644
--- a/packages/PrintSpooler/res/layout/print_activity_controls.xml
+++ b/packages/PrintSpooler/res/layout/print_activity_controls.xml
@@ -239,7 +239,8 @@
                     android:singleLine="true"
                     android:ellipsize="end"
                     android:visibility="visible"
-                    android:inputType="textNoSuggestions">
+                    android:inputType="number"
+                    android:digits="0123456789 ,-">
                 </com.android.printspooler.widget.CustomErrorEditText>
 
             </LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml b/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml
new file mode 100644
index 0000000..86ac26d
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal"
+    android:gravity="start|center_vertical">
+
+    <ImageView
+        android:layout_width="36dip"
+        android:layout_height="36dip"
+        android:src="@drawable/ic_download_from_market"
+        android:layout_marginRight="4dip"
+        android:layout_gravity="center_vertical"
+        android:contentDescription="@null" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dip">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:singleLine="true"
+            android:ellipsize="end" />
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:text="@string/enable_print_service" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index defbf8d..103c157 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -16,10 +16,8 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
-      android:paddingStart="8dip"
-      android:paddingEnd="8dip"
-      android:minHeight="56dip"
+      android:layout_height="?android:attr/listPreferredItemHeightSmall"
+      style="?android:attr/spinnerItemStyle"
       android:orientation="horizontal"
       android:gravity="start|center_vertical">
 
@@ -33,10 +31,9 @@
         android:visibility="invisible">
     </ImageView>
 
-    <LinearLayout
+    <RelativeLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
         android:layout_marginStart="8dip"
         android:duplicateParentState="true">
 
@@ -47,8 +44,6 @@
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:singleLine="true"
             android:ellipsize="end"
-            android:textIsSelectable="false"
-            android:gravity="top|start"
             android:textColor="?android:attr/textColorPrimary"
             android:duplicateParentState="true">
         </TextView>
@@ -57,15 +52,15 @@
             android:id="@+id/subtitle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_below="@id/title"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:singleLine="true"
             android:ellipsize="end"
-            android:textIsSelectable="false"
             android:visibility="gone"
             android:textColor="?android:attr/textColorSecondary"
             android:duplicateParentState="true">
         </TextView>
 
-    </LinearLayout>
+    </RelativeLayout>
 
 </LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml b/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
index 11fef2d..60f7088 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
@@ -16,13 +16,10 @@
 
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
+      android:layout_height="?android:attr/listPreferredItemHeightSmall"
       android:textAppearance="?android:attr/textAppearanceMedium"
-      android:textIsSelectable="false"
       android:textColor="?android:attr/textColorPrimary"
       android:paddingStart="20dip"
-      android:paddingEnd="8dip"
-      android:minHeight="56dip"
-      android:orientation="horizontal"
+      style="?android:attr/spinnerItemStyle"
       android:text="@string/destination_default_text"
       android:gravity="start|center_vertical" />
diff --git a/packages/PrintSpooler/res/layout/printer_list_item.xml b/packages/PrintSpooler/res/layout/printer_list_item.xml
index 1209aa6..0784bab 100644
--- a/packages/PrintSpooler/res/layout/printer_list_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_list_item.xml
@@ -16,10 +16,9 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
+    android:layout_height="?android:attr/listPreferredItemHeight"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:minHeight="?android:attr/listPreferredItemHeight"
     android:orientation="horizontal"
     android:gravity="start|center_vertical">
 
@@ -28,18 +27,15 @@
         android:layout_width="40dip"
         android:layout_height="40dip"
         android:layout_gravity="center_vertical"
-        android:layout_marginTop="8dip"
-        android:layout_marginBottom="8dip"
         android:duplicateParentState="true"
         android:contentDescription="@null"
         android:visibility="invisible">
     </ImageView>
 
     <RelativeLayout
-        android:layout_width="0dip"
+        android:layout_width="fill_parent"
         android:layout_weight="1"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
         android:layout_marginStart="16dip"
         android:duplicateParentState="true">
 
@@ -47,15 +43,9 @@
             android:id="@+id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textAppearance="?android:attr/textAppearanceListItem"
             android:singleLine="true"
             android:ellipsize="end"
-            android:textIsSelectable="false"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentStart="true"
-            android:fadingEdge="horizontal"
-            android:textAlignment="viewStart"
-            android:textColor="?android:attr/textColorPrimary"
             android:duplicateParentState="true">
         </TextView>
 
@@ -64,30 +54,31 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_below="@id/title"
-            android:layout_alignParentStart="true"
-            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
             android:singleLine="true"
             android:ellipsize="end"
-            android:textIsSelectable="false"
             android:visibility="gone"
-            android:textColor="?android:attr/textColorSecondary"
-            android:textAlignment="viewStart"
             android:duplicateParentState="true">
         </TextView>
 
     </RelativeLayout>
 
-    <ImageView
+    <!-- wrapper for image view to increase the touch target size -->
+    <LinearLayout
         android:id="@+id/more_info"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:paddingLeft="16dip"
-        android:contentDescription="@string/printer_info_desc"
-        android:src="@drawable/ic_info"
-        android:tint="?android:attr/colorControlNormal"
-        android:tintMode="src_in"
+        android:layout_height="fill_parent"
         android:visibility="gone">
-    </ImageView>
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:paddingLeft="16dip"
+            android:contentDescription="@string/printer_info_desc"
+            android:src="@drawable/ic_info"
+            android:tint="?android:attr/colorControlNormal"
+            android:tintMode="src_in" />
+    </LinearLayout>
 
 </LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml
index 77c500a..564802a 100644
--- a/packages/PrintSpooler/res/layout/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml
@@ -22,11 +22,7 @@
     <ListView
         android:id="@android:id/list"
         android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
-        android:scrollbarStyle="outsideOverlay"
-        android:cacheColorHint="@android:color/transparent"
-        android:scrollbarAlwaysDrawVerticalTrack="true" >
-    </ListView>
+        android:layout_height="fill_parent" />
 
     <FrameLayout
         android:id="@+id/empty_print_state"
@@ -63,9 +59,18 @@
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:indeterminate="true"
-                style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal">
+                style="?android:attr/progressBarStyleHorizontal">
             </ProgressBar>
 
+            <Button
+                    android:id="@+id/button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="?android:attr/buttonBarButtonStyle"
+                    android:textAppearance="?android:attr/textAppearanceSmall"
+                    android:text="@string/print_add_printer"
+                    android:textAllCaps="true" />
+
         </LinearLayout>
 
     </FrameLayout>
diff --git a/packages/PrintSpooler/res/menu/select_printer_activity.xml b/packages/PrintSpooler/res/menu/select_printer_activity.xml
index 15cc139..60dfdca 100644
--- a/packages/PrintSpooler/res/menu/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/menu/select_printer_activity.xml
@@ -26,12 +26,4 @@
         android:imeOptions="actionSearch">
     </item>
 
-    <item
-        android:id="@+id/action_add_printer"
-        android:title="@string/print_add_printer"
-        android:icon="@drawable/ic_add"
-        android:showAsAction="ifRoom"
-        android:alphabeticShortcut="a">
-    </item>
-
 </menu>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index 57ba2b6..fa5ec3f 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Meer inligting oor hierdie drukker"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Sommige drukdienste is gedeaktiveer."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Kies drukdiens"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Sommige drukdienste is gedeaktiveer"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Soek tans vir drukkers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Geen drukdienste is geaktiveer nie"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Geen drukkers gekry nie"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Kan nie drukkers byvoeg nie"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Kies om drukker by te voeg"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Kies om te aktiveer"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Geaktiveerde dienste"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Aanbevole dienste"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Gedeaktiveerde dienste"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Alle dienste"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Installeer om <xliff:g id="COUNT_1">%1$s</xliff:g> drukkers te ontdek</item>
+      <item quantity="one">Installeer om <xliff:g id="COUNT_0">%1$s</xliff:g> drukker ontdek</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Druk tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kanselleer tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Drukkerfout by <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Herbegin"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met drukker nie"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"onbekend"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nie beskikbaar nie"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Gebruik <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Jou dokument kan dalk deur een of meer bedieners op pad na die drukker gaan."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Jammer, dit het nie gewerk nie. Probeer weer."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Herprobeer"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Hierdie drukker is nie op die oomblik beskikbaar nie."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan nie voorskou wys nie"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Berei tans voorskou voor …"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index a2182fb..5ada8d3 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ተጨማሪ የዚህ አታሚ መረጃ"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"አንዳንድ የህትመት አገልግሎቶች ተሰናክለዋል።"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"የህትመት አገልግሎት ይምረጡ"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"አንዳንድ የህትመት አገልግሎቶች ተሰናክለዋል"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"አታሚዎችን በመፈለግ ላይ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ምንም የህትመት አገልግሎቶች አልነቁም"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ምንም አታሚዎች አልተገኙም"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"አታሚዎችን ማከል አልተቻለም"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"አታሚን ለማከል ይምረጡ"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"ለማንቃት ይምረጡ"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"የነቁ አገልግሎቶች"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"የሚመከሩ አገልግሎቶች"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"የተሰናከሉ አገልግሎቶች"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"ሁሉም አገልግሎቶች"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ለማግኘት ይጫኑ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ለማግኘት ይጫኑ</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በማተም ላይ"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በመተው ላይ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"የአታሚ ስህተት <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ይጠቀሙ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ሰነድዎ ወደ አታሚው በሚሄድበት ወቅት በአንድ ወይም ከዚያ በላይ አገልጋዮች ውስጥ ሊያልፍ ይችላል።"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"ይቅርታ፣ ያ አልሰራም። እንደገና ይሞክሩ።"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"እንደገና ይሞክሩ"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"አታሚው አሁን አይገኝም።"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"ቅድመ ዕይታን ማሳየት አይቻልም"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"ቅድመ እይታን በማዘጋጀት ላይ…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index eab1339..1208298 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -65,11 +65,25 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"مزيد من المعلومات حول هذه الطابعة"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"بعض خدمات الطباعة معطَّلة."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"اختر خدمة طباعة"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"بعض خدمات الطباعة معطَّلة"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"البحث عن طابعات"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"لم يتم تمكين أي خدمات طباعة"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"لم يتم العثور على طابعات"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"تعذرت إضافة طابعات"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"اختر لإضافة طابعة"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"حدد للتمكين"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"الخدمات الممكنة"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"الخدمات الموصى بها"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"الخدمات المعطَّلة"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"جميع الخدمات"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="zero">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+      <item quantity="two">التثبيت لاستكشاف طابعتين (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
+      <item quantity="few">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+      <item quantity="many">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعة</item>
+      <item quantity="other">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+      <item quantity="one">التثبيت لاستكشاف <xliff:g id="COUNT_0">%1$s</xliff:g> طابعة</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"جارٍ طباعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"جارٍ إلغاء <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"خطا في الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -78,7 +92,6 @@
     <string name="restart" msgid="2472034227037808749">"إعادة تشغيل"</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_service_security_warning_title" msgid="2160752291246775320">"هل تريد استخدام <xliff:g id="SERVICE">%1$s</xliff:g>؟"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"من الممكن أن يمر المستند عبر خادم أو أكثر أثناء إرساله إلى الطابعة."</string>
   <string-array name="color_mode_labels">
@@ -98,5 +111,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"عذرًا، هذا لا يعمل. أعد المحاولة."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"إعادة المحاولة"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"الطابعة ليست متوفرة في الوقت الحالي."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"يتعذر عرض المعاينة."</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"جارٍ تحضير المعاينة…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index bff477d..4404aad 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Bu printer haqqında daha ətraflı məlumat"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Bəzi çap xidmətləri deaktiv edilib."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Çap xidmətini seçin"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Bəzi çap xidmətləri deaktiv edilib."</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printer axtarılır"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Heç bir çap xidməti aktiv edilməyib"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Heç bir printer tapılmadı"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Printerlər əlavə edilmədi"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Printer əlavə etmək üçün seçin"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Aktiv etmək üçün seçin"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Aktiv edilmiş xidmətlər"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Tövsiyə olunan xidmətlər"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Deaktiv edilmiş xidmətlər"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Bütün xidmətlər"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printeri kəşf etmək üçün quraşdırın</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printeri kəşf etmək üçün quraşdırın</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> çap edilir"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ləğv edilir"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer xətası <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Yenidən başlat"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printerə heç bir bağlantı yoxdur"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"naməlum"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>– əlçatmaz"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> xidmətindən istifadə edilsin?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Sənədiniz printerə qədər bir və ya daha çox server vasitəsilə keçə bilər."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Üzr istəyirik, alınmadı. Yenidən cəhd edin."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Yenidən yoxla"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Bu printer hazırda əlçatan deyil."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Önizləmə göstərilə bilmir"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Önizləməyə hazırlıq gedir..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index b28aa29..50ce1f9 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -62,11 +62,22 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Još informacija o ovom štampaču"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Neke usluge štampanja su onemogućene."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Izaberite uslugu štampanja"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke usluge štampanja su onemogućene"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Pretraga štampača"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nijedna usluga štampanja nije omogućena"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nije pronađen nijedan štampač"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nije moguće dodati štampače"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Izaberite da biste dodali štampač"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Izaberite da biste omogućili"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Omogućene usluge"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampač</item>
+      <item quantity="few">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+      <item quantity="other">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazuje se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Greška štampača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -75,7 +86,6 @@
     <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze sa štampačem"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"nepoznato"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nedostupan"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Želite li da koristite <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokument može da prođe kroz jedan ili više servera na putu do štampača."</string>
   <string-array name="color_mode_labels">
@@ -95,5 +105,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Žao nam je, ovo nije uspelo. Pokušajte ponovo."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovo"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ovaj štampač trenutno nije dostupan."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Nije uspeo prikaz pregleda"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-be-rBY/strings.xml b/packages/PrintSpooler/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..c264f92
--- /dev/null
+++ b/packages/PrintSpooler/res/values-be-rBY/strings.xml
@@ -0,0 +1,112 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label" msgid="4469836075319831821">"Менеджар чаргі друку"</string>
+    <string name="more_options_button" msgid="2243228396432556771">"Дадатковыя параметры"</string>
+    <string name="label_destination" msgid="9132510997381599275">"Мэта"</string>
+    <string name="label_copies" msgid="3634531042822968308">"Копіі"</string>
+    <string name="label_copies_summary" msgid="3861966063536529540">"Копіі:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Памер паперы"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Памер паперы:"</string>
+    <string name="label_color" msgid="1108690305218188969">"Колер"</string>
+    <string name="label_duplex" msgid="5370037254347072243">"Двухбаковы"</string>
+    <string name="label_orientation" msgid="2853142581990496477">"Арыентацыя"</string>
+    <string name="label_pages" msgid="7768589729282182230">"Старонкі"</string>
+    <string name="destination_default_text" msgid="5422708056807065710">"Выбар прынтара"</string>
+    <string name="template_all_pages" msgid="3322235982020148762">"Усе <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+    <string name="template_page_range" msgid="428638530038286328">"У дыяпазоне <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+    <string name="pages_range_example" msgid="8558694453556945172">"напр., 1—5,8,11—13"</string>
+    <string name="print_preview" msgid="8010217796057763343">"Папярэдні прагляд"</string>
+    <string name="install_for_print_preview" msgid="6366303997385509332">"Устал. праграму прагляду PDF для папярэд. прагляду"</string>
+    <string name="printing_app_crashed" msgid="854477616686566398">"Збой праграмы друку"</string>
+    <string name="generating_print_job" msgid="3119608742651698916">"Стварэнне задання друку"</string>
+    <string name="save_as_pdf" msgid="5718454119847596853">"Захаваць як PDF"</string>
+    <string name="all_printers" msgid="5018829726861876202">"Усе прынтары..."</string>
+    <string name="print_dialog" msgid="32628687461331979">"Дыялог друку"</string>
+    <string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+    <string name="page_description_template" msgid="6831239682256197161">"Старонка <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> з <xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+    <string name="summary_template" msgid="8899734908625669193">"Зводка, копіі <xliff:g id="COPIES">%1$s</xliff:g>, памер паперы <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
+    <string name="expand_handle" msgid="7282974448109280522">"Маркер разгортвання"</string>
+    <string name="collapse_handle" msgid="6886637989442507451">"Маркер згортвання"</string>
+    <string name="print_button" msgid="645164566271246268">"Друкаваць"</string>
+    <string name="savetopdf_button" msgid="2976186791686924743">"Захаваць у PDF"</string>
+    <string name="print_options_expanded" msgid="6944679157471691859">"Параметры друку разгорнуты"</string>
+    <string name="print_options_collapsed" msgid="7455930445670414332">"Параметры друку згорнуты"</string>
+    <string name="search" msgid="5421724265322228497">"Пошук"</string>
+    <string name="all_printers_label" msgid="3178848870161526399">"Усе прынтары"</string>
+    <string name="add_print_service_label" msgid="5356702546188981940">"Дадаць службу"</string>
+    <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Паказваецца поле пошуку"</string>
+    <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Поле пошуку схавана"</string>
+    <string name="print_add_printer" msgid="1088656468360653455">"Дадаць прынтар"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Выбар прынтара"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Не запамінаць прынтар"</string>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> прынтар знойдзены</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> прынтары знойдзены</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> прынтараў знойдзена</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> прынтара знойдзена</item>
+    </plurals>
+    <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="printer_info_desc" msgid="7181988788991581654">"Больш падрабязная інфармацыя пра гэты прынтар"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Некаторыя службы друку адключаны"</string>
+    <string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук прынтараў"</string>
+    <string name="print_no_print_services" msgid="8561247706423327966">"Службы друку не ўключаны"</string>
+    <string name="print_no_printers" msgid="4869403323900054866">"Прынтараў не знойдзена"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Немагчыма дадаць прынтары"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Выберыце, каб дадаць прынтар"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Выберыце, каб уключыць"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Уключаныя службы"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Рэкамендаваныя службы"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Адключаныя службы"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Усе службы"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтар</item>
+      <item quantity="few">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтары</item>
+      <item quantity="many">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтараў</item>
+      <item quantity="other">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтара</item>
+    </plurals>
+    <string name="printing_notification_title_template" msgid="295903957762447362">"Друк <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Скасоўваецца <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <string name="failed_notification_title_template" msgid="2256217208186530973">"Памылка друку <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <string name="blocked_notification_title_template" msgid="1175435827331588646">"Прынтар заблакіраваў <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <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>
+    <string name="print_service_security_warning_title" msgid="2160752291246775320">"Выкарыстоўваць службу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
+    <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Ваш дакумент можа прайсці праз адзін ці больш сервераў перад тым, як будзе надрукаваны."</string>
+  <string-array name="color_mode_labels">
+    <item msgid="7602948745415174937">"Чорна-белая схема"</item>
+    <item msgid="2762241247228983754">"Колер"</item>
+  </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Недаступна"</item>
+    <item msgid="7296563835355641719">"Па доўгім краі"</item>
+    <item msgid="79513688117503758">"Па кароткім краі"</item>
+  </string-array>
+  <string-array name="orientation_labels">
+    <item msgid="4061931020926489228">"Кніжная арыентацыя"</item>
+    <item msgid="3199660090246166812">"Альбомная арыентацыя"</item>
+  </string-array>
+    <string name="print_write_error_message" msgid="5787642615179572543">"Не атрымалася запісаць у файл"</string>
+    <string name="print_error_default_message" msgid="8602678405502922346">"На жаль, не атрымалася. Паспрабуйце яшчэ раз."</string>
+    <string name="print_error_retry" msgid="1426421728784259538">"Паўтарыць спробу"</string>
+    <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Гэты прынтар зараз недаступны."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Папярэдні прагляд немагчымы"</string>
+    <string name="print_preparing_preview" msgid="3939930735671364712">"Падрыхтоўка папярэдняга прагляду..."</string>
+</resources>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index e8de8ea..3dd6ec5 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Още информация за този принтер"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Някои услуги за отпечатване са деактивирани."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Избиране на услуга за отпечатване"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Някои услуги за отпечатване са деактивирани"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Търсене на принтери"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Няма активирани услуги за отпечатване"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Няма намерени принтери"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Не могат да се добавят принтери"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Изберете, за да добавите принтер"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Изберете, за да активирате"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Активирани услуги"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Препоръчителни услуги"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Деактивирани услуги"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Всички услуги"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Инсталирайте, за да бъдат открити <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+      <item quantity="one">Инсталирайте, за да бъде открит <xliff:g id="COUNT_0">%1$s</xliff:g> принтер</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се отпечатва"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се анулира"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка в принтера при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Рестартиране"</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_service_security_warning_title" msgid="2160752291246775320">"Да се използва ли „<xliff:g id="SERVICE">%1$s</xliff:g>“?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"По пътя към принтера документът ви може да премине през един или повече сървъри."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"За съжаление това не проработи. Опитайте отново."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Нов опит"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"В момента този принтер не е налице."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Визуализацията не може да се покаже"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Визуализацията се подготвя…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index a1ca494..3789f21 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -16,7 +16,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="4469836075319831821">"মুদ্রণ স্পোলার"</string>
+    <string name="app_label" msgid="4469836075319831821">"প্রিন্ট স্পোলার"</string>
     <string name="more_options_button" msgid="2243228396432556771">"আরো বিকল্প"</string>
     <string name="label_destination" msgid="9132510997381599275">"গন্তব্য"</string>
     <string name="label_copies" msgid="3634531042822968308">"প্রতিলিপিগুলি"</string>
@@ -31,22 +31,22 @@
     <string name="template_all_pages" msgid="3322235982020148762">"সমস্ত <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> এর পরিসর"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"যেমন, ১—৫,৮,১১—১৩"</string>
-    <string name="print_preview" msgid="8010217796057763343">"মুদ্রণ পূর্বরূপ"</string>
+    <string name="print_preview" msgid="8010217796057763343">"প্রিন্ট পূর্বরূপ"</string>
     <string name="install_for_print_preview" msgid="6366303997385509332">"পূর্বরূপ দেখার জন্য PDF ভিউয়ার ইনস্টল করুন"</string>
-    <string name="printing_app_crashed" msgid="854477616686566398">"মুদ্রণ অ্যাপ্লিকেশান ক্র্যাশ করছে"</string>
-    <string name="generating_print_job" msgid="3119608742651698916">"মুদ্রণ কার্য তৈরি করা হচ্ছে"</string>
+    <string name="printing_app_crashed" msgid="854477616686566398">"প্রিন্ট অ্যাপ্লিকেশান ক্র্যাশ করছে"</string>
+    <string name="generating_print_job" msgid="3119608742651698916">"প্রিন্ট কার্য তৈরি করা হচ্ছে"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"PDF হিসাবে সংরক্ষণ করুন"</string>
     <string name="all_printers" msgid="5018829726861876202">"সমস্ত মুদ্রক…"</string>
-    <string name="print_dialog" msgid="32628687461331979">"মুদ্রণ ডায়লগ"</string>
+    <string name="print_dialog" msgid="32628687461331979">"প্রিন্ট ডায়লগ"</string>
     <string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> /<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
     <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g>টির মধ্যে <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> নম্বর পৃষ্ঠা"</string>
     <string name="summary_template" msgid="8899734908625669193">"সারাংশ, <xliff:g id="COPIES">%1$s</xliff:g>টি অনুলিপি, কাগজের আকার <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
     <string name="expand_handle" msgid="7282974448109280522">"প্রসারিত করার হ্যান্ডেল"</string>
     <string name="collapse_handle" msgid="6886637989442507451">"সঙ্কুচিত করার হ্যান্ডেল"</string>
-    <string name="print_button" msgid="645164566271246268">"মুদ্রণ করুন"</string>
+    <string name="print_button" msgid="645164566271246268">"প্রিন্ট করুন"</string>
     <string name="savetopdf_button" msgid="2976186791686924743">"PDF হিসাবে সংরক্ষণ করুন"</string>
-    <string name="print_options_expanded" msgid="6944679157471691859">"মুদ্রণ বিকল্প প্রসারিত হয়েছে"</string>
-    <string name="print_options_collapsed" msgid="7455930445670414332">"মুদ্রণ বিকল্প সংকুচিত হয়েছে"</string>
+    <string name="print_options_expanded" msgid="6944679157471691859">"প্রিন্ট বিকল্প প্রসারিত হয়েছে"</string>
+    <string name="print_options_collapsed" msgid="7455930445670414332">"প্রিন্ট বিকল্প সংকুচিত হয়েছে"</string>
     <string name="search" msgid="5421724265322228497">"অনুসন্ধান করুন"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"সমস্ত মুদ্রক"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"পরিষেবা যোগ করুন"</string>
@@ -61,12 +61,22 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"এই মুদ্রকটির বিষয়ে আরো তথ্য"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"কিছু মুদ্রণ পরিষেবা অক্ষম করা হয়েছে৷"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"মুদ্রণ পরিষেবা চয়ন করুন"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"কিছু মুদ্রণ পরিষেবা অক্ষম করা আছে"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"মুদ্রকগুলি অনুসন্ধান করা হচ্ছে"</string>
-    <string name="print_no_print_services" msgid="8561247706423327966">"মুদ্রণ পরিষেবা সক্ষম নেই"</string>
+    <string name="print_no_print_services" msgid="8561247706423327966">"প্রিন্ট পরিষেবা সক্ষম নেই"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"কোনো মুদ্রক পাওয়া যায়নি"</string>
-    <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রণ করা হচ্ছে"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"মুদ্রকগুলি যোগ করা যাবে না"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"মুদ্রক যোগ করতে নির্বাচন করুন"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"সক্ষম করতে নির্বাচন করুন"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"সক্ষম করা পরিষেবাগুলি"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"প্রস্তাবিত পরিষেবাগুলি"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"অক্ষম করা পরিষেবাগুলি"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"সমস্ত পরিষেবা"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
+    </plurals>
+    <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> প্রিন্ট করা হচ্ছে"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"মুদ্রক <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> অবরুদ্ধ করেছে"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"পুনর্সূচনা"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ব্যবহার করবেন?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"আপনার দস্তাবেজ মুদ্রকে যাওয়ার সময় এক বা একাধিক সার্ভারের মাধ্যমে পাস হতে পারে।"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"দুঃখিত, এটি কাজ করেনি৷ আবার চেষ্টা করুন৷"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"পুনরায় চেষ্টা করুন"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"এই মূহুর্তে প্রিন্টার উপলব্ধ নয়।"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"পূর্বরূপ প্রদর্শন করা যাবে না"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"পূর্বরূপ প্রস্তুত করছে..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..c3c9bb33
--- /dev/null
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -0,0 +1,110 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label" msgid="4469836075319831821">"Štampanje na čekanju"</string>
+    <string name="more_options_button" msgid="2243228396432556771">"Više opcija"</string>
+    <string name="label_destination" msgid="9132510997381599275">"Odredište"</string>
+    <string name="label_copies" msgid="3634531042822968308">"Kopije"</string>
+    <string name="label_copies_summary" msgid="3861966063536529540">"Primjeraka:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Veličina papira"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Veličina papira:"</string>
+    <string name="label_color" msgid="1108690305218188969">"U boji"</string>
+    <string name="label_duplex" msgid="5370037254347072243">"Dvostrano"</string>
+    <string name="label_orientation" msgid="2853142581990496477">"Orijentacija"</string>
+    <string name="label_pages" msgid="7768589729282182230">"Stranicā"</string>
+    <string name="destination_default_text" msgid="5422708056807065710">"Odaberite štampač"</string>
+    <string name="template_all_pages" msgid="3322235982020148762">"Sve stranice (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
+    <string name="template_page_range" msgid="428638530038286328">"Opseg od <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+    <string name="pages_range_example" msgid="8558694453556945172">"npr. 1—5,8,11—13"</string>
+    <string name="print_preview" msgid="8010217796057763343">"Pregled prije štampanja"</string>
+    <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF preglednik za prikaz"</string>
+    <string name="printing_app_crashed" msgid="854477616686566398">"Aplikacija za štampanje je prestala raditi"</string>
+    <string name="generating_print_job" msgid="3119608742651698916">"Kreiranje zadatka za štampu"</string>
+    <string name="save_as_pdf" msgid="5718454119847596853">"Sačuvaj kao PDF"</string>
+    <string name="all_printers" msgid="5018829726861876202">"Svi štampači…"</string>
+    <string name="print_dialog" msgid="32628687461331979">"Dijaloški okvir za štampanje"</string>
+    <string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> /<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+    <string name="page_description_template" msgid="6831239682256197161">"Strana <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> od <xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+    <string name="summary_template" msgid="8899734908625669193">"Rezime, primjeraka <xliff:g id="COPIES">%1$s</xliff:g>, veličina papira <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
+    <string name="expand_handle" msgid="7282974448109280522">"Regulator za proširivanje"</string>
+    <string name="collapse_handle" msgid="6886637989442507451">"Regulator za skupljanje"</string>
+    <string name="print_button" msgid="645164566271246268">"Štampaj"</string>
+    <string name="savetopdf_button" msgid="2976186791686924743">"Sačuvaj u PDF"</string>
+    <string name="print_options_expanded" msgid="6944679157471691859">"Opcije za štampanje su proširene"</string>
+    <string name="print_options_collapsed" msgid="7455930445670414332">"Opcije za štampanje su skupljene"</string>
+    <string name="search" msgid="5421724265322228497">"Traži"</string>
+    <string name="all_printers_label" msgid="3178848870161526399">"Svi štampači"</string>
+    <string name="add_print_service_label" msgid="5356702546188981940">"Dodaj uslugu"</string>
+    <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Okvir za pretraživanje je prikazan"</string>
+    <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Okvir za pretraživanje je skriven"</string>
+    <string name="print_add_printer" msgid="1088656468360653455">"Dodaj štampač"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Izaberite štampač"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Zaboravi ovaj štampač"</string>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> štampač je pronađen</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> štampača su pronađena</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> štampača je pronađeno</item>
+    </plurals>
+    <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="printer_info_desc" msgid="7181988788991581654">"Više informacija o ovom štampaču"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke usluge za štampanje su isključene"</string>
+    <string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje štampača"</string>
+    <string name="print_no_print_services" msgid="8561247706423327966">"Usluga za štampanje nije uključena"</string>
+    <string name="print_no_printers" msgid="4869403323900054866">"Nijedan štampač nije pronađen"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Ne mogu se dodati štampači"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Odaberite da biste dodali štampač"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Odaberite da biste uključili"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Uključene usluge"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Isključene usluge"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampač</item>
+      <item quantity="few"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+      <item quantity="other"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+    </plurals>
+    <string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <string name="failed_notification_title_template" msgid="2256217208186530973">"Greška pri štampanju <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <string name="blocked_notification_title_template" msgid="1175435827331588646">"Štampač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+    <string name="cancel" msgid="4373674107267141885">"Otkaži"</string>
+    <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
+    <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema konekcije sa štampačem"</string>
+    <string name="reason_unknown" msgid="5507940196503246139">"nepoznat"</string>
+    <string name="print_service_security_warning_title" msgid="2160752291246775320">"Zaista želite koristiti uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
+    <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Moguće je da dokument prije štampanja prođe kroz jedan ili više servera."</string>
+  <string-array name="color_mode_labels">
+    <item msgid="7602948745415174937">"Crno-bijela"</item>
+    <item msgid="2762241247228983754">"U boji"</item>
+  </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nije podržano"</item>
+    <item msgid="7296563835355641719">"Po dužoj strani"</item>
+    <item msgid="79513688117503758">"Po kraćoj strani"</item>
+  </string-array>
+  <string-array name="orientation_labels">
+    <item msgid="4061931020926489228">"Uspravno"</item>
+    <item msgid="3199660090246166812">"Vodoravno"</item>
+  </string-array>
+    <string name="print_write_error_message" msgid="5787642615179572543">"Nije moguće pisati u fajl"</string>
+    <string name="print_error_default_message" msgid="8602678405502922346">"Nažalost, nije uspjelo. Pokušajte ponovo."</string>
+    <string name="print_error_retry" msgid="1426421728784259538">"Ponovi"</string>
+    <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Štampač trenutno nije dostupan."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Pregled se ne može prikazati"</string>
+    <string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda..."</string>
+</resources>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index aa6f992..f65a63c 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Més informació sobre aquesta impressora"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Hi ha serveis d\'impressió que estan desactivats."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Selecció del servei d\'impressió"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serveis d\'impressió estan desactivats"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Cerca d\'impressores"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No hi ha cap servei d\'impressió activat"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No s\'ha trobat cap impressora"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"No poden afegir impressores"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selecciona per afegir una impressora"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selecciona\'ls per activar-los"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Serveis activats"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Serveis recomanats"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Serveis desactivats"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Tots els serveis"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Instal·la\'l per detectar <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
+      <item quantity="one">Instal·la\'l per detectar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"S\'està imprimint <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"S\'està cancel·lant <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error d\'impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Reinicia"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hi ha connexió amb la impressora"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"desconegut"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: no disponible"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Vols fer servir <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"És possible que el document passi com a mínim per un servidor abans d\'imprimir-se."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionat. Torna-ho a provar."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Torna-ho a provar"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ara mateix, aquesta impressora no està disponible."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"La previsualització no es pot mostrar"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"S\'està preparant la previsualització..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 4bc22d4..9bfa271 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Další informace o této tiskárně"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Některé tiskové služby nejsou aktivovány."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Zvolte službu tisku"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Některé tiskové služby nejsou aktivovány"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhledávání tiskáren"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nejsou aktivovány žádné tiskové služby"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nebyly nalezeny žádné tiskárny"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Tiskárny nelze přidat"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Výběrem přidáte tiskárnu"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Výběrem službu aktivujete"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Aktivované služby"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Doporučené služby"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Deaktivované služby"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Všechny služby"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="few">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskárny</item>
+      <item quantity="many">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskárny</item>
+      <item quantity="other">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskáren</item>
+      <item quantity="one">Instalací objevíte <xliff:g id="COUNT_0">%1$s</xliff:g> tiskárnu</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Tisk úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Rušení úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tiskárny u úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"Restartovat"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nelze se připojit k tiskárně"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"neznámé"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – není k dispozici"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Použít službu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokument může cestou do tiskárny projít jedním i více servery."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Litujeme, nepodařilo se. Zkuste to znovu."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Opakovat"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Tiskárna aktuálně není k dispozici."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Náhled nelze zobrazit"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Příprava náhledu…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index b8be624..75a0b56 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Flere oplysninger om denne printer"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Nogle udskrivningstjenester er deaktiveret."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Vælg udskriftstjeneste"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Nogle udskrivningstjenester er deaktiveret"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Søger efter printere"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ingen udskrivningstjenester er aktiveret"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Der blev ikke fundet nogen printere"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Der kan ikke tilføjes printere"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Vælg for at tilføje en printer"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Vælg for at aktivere"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Aktiverede tjenester"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Anbefalede tjenester"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Deaktiverede tjenester"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Installer for at finde <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+      <item quantity="other">Installer for at finde <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> udskrives"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annulleres"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Udskriften <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> mislykkedes"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Genstart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse til printer"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"ukendt"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ikke tilgængelig"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Vil du bruge <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dit dokument passerer muligvis gennem én eller flere servere på vej til printeren."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Det virkede desværre ikke. Prøv igen."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Prøv igen"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Denne printer er i øjeblikket ikke tilgængelig."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Eksempelvisning kan ikke vises"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Eksempelvisning forberedes..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index bcb7e73..8c6181d 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Weitere Informationen über diesen Drucker"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Einige Druckdienste sind deaktiviert."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Druckdienst auswählen"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Einige Druckdienste sind deaktiviert"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Suche nach Druckern"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Keine Druckdienste aktiviert"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Keine Drucker gefunden"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Hinzufügen von Druckern nicht möglich"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Auswählen, um Drucker hinzuzufügen"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Zum Aktivieren auswählen"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Aktivierte Dienste"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Empfohlene Dienste"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Deaktivierte Dienste"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Alle Dienste"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Installieren, um <xliff:g id="COUNT_1">%1$s</xliff:g> Drucker zu erkennen</item>
+      <item quantity="one">Installieren, um <xliff:g id="COUNT_0">%1$s</xliff:g> Drucker zu erkennen</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird gedruckt..."</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird abgebrochen..."</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Druckerfehler <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Neu starten"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Keine Verbindung zum Drucker"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"unbekannt"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nicht verfügbar"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> verwenden?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dein Dokument passiert bei der Übermittlung an den Drucker möglicherweise einen oder mehrere Server."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Fehler. Bitte versuche es erneut."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Erneut versuchen"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Dieser Drucker ist momentan nicht verfügbar."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Vorschau kann nicht angezeigt werden"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Vorschau wird vorbereitet…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index d9a4aeb..31d3f83 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Περισσότερες πληροφορίες σχετικά με αυτόν τον εκτυπωτή"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Κάποιες υπηρ. εκτύπωσης είναι απενεργοποιημένες."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Επιλέξτε υπηρεσία εκτύπωσης"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Ορισμένες υπηρ. εκτύπωσης είναι απενεργοποιημένες"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Αναζήτηση για εκτυπωτές"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Δεν έχουν ενεργοποιηθεί υπηρεσίες εκτύπωσης"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Δεν βρέθηκαν εκτυπωτές"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Δεν είναι δυνατή η προσθήκη εκτυπωτών"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Επιλέξτε για την προσθήκη εκτυπωτή"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Επιλέξτε για ενεργοποίηση"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Ενεργοποιημένες υπηρεσίες"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Προτεινόμενες υπηρεσίες"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Υπηρεσίες για άτομα με αναπηρία"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Όλες οι υπηρεσίες"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Κάντε εγκατάσταση για να ανακαλύψετε <xliff:g id="COUNT_1">%1$s</xliff:g> εκτυπωτές</item>
+      <item quantity="one">Κάντε εγκατάσταση για να ανακαλύψετε <xliff:g id="COUNT_0">%1$s</xliff:g> εκτυπωτή</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Εκτύπωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ακύρωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Σφάλμα εκτυπωτή <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Επανεκκίνηση"</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_service_security_warning_title" msgid="2160752291246775320">"Να χρησιμοποιηθεί η υπηρεσία <xliff:g id="SERVICE">%1$s</xliff:g>;"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Το έγγραφό σας μπορεί να περάσει από έναν ή περισσότερους διακομιστές κατά τη μετάβαση στον εκτυπωτή."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Δυστυχώς, αυτό δεν λειτούργησε. Δοκιμάστε ξανά."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Επανάληψη"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Αυτός ο εκτυπωτής δεν είναι διαθέσιμος αυτήν τη στιγμή."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Αδυναμία προβολής προεπισκόπησης"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Προετοιμασία προεπισκόπησης…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index d8a9437..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Some print services are disabled."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Some print services are disabled"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Cannot add printers"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Select to add printer"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Select to enable"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Enabled services"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+      <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Use <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Your document may pass through one or more servers on its way to the printer."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Sorry, that didn\'t work. Try again."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"This printer isn\'t available right now."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Can\'t display preview"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparing preview…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index d8a9437..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Some print services are disabled."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Some print services are disabled"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Cannot add printers"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Select to add printer"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Select to enable"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Enabled services"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+      <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Use <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Your document may pass through one or more servers on its way to the printer."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Sorry, that didn\'t work. Try again."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"This printer isn\'t available right now."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Can\'t display preview"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparing preview…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index d8a9437..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Some print services are disabled."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Some print services are disabled"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Cannot add printers"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Select to add printer"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Select to enable"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Enabled services"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+      <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Use <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Your document may pass through one or more servers on its way to the printer."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Sorry, that didn\'t work. Try again."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"This printer isn\'t available right now."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Can\'t display preview"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparing preview…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 19cbee7..a6a9f07 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Hay servicios de impresión inhabilitados."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Elegir servicio de impresión"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Hay servicios de impresión inhabilitados"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No se encontraron impresoras"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"No es posible agregar impresoras"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Seleccionar para agregar impresoras"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Seleccionar para habilitar"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Servicios habilitados"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Instala para ver <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+      <item quantity="one">Instala para ver <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora."</string>
     <string name="reason_unknown" msgid="5507940196503246139">"desconocido"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: no disponible"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"¿Deseas usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Es posible que el documento pase por uno o varios servidores antes de imprimirse."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"No funcionó. Vuelve a intentarlo."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Volver a intentar"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impresora no está disponible en este momento."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"No se puede mostrar la vista previa"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparando vista previa…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index d13ccda..4f6731d 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Algunos servicios de impresión están inhabilitados."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Seleccionar servicio de impresión"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Algunos servicios de impresión están inhabilitados"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No se encontraron impresoras"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"No se pueden añadir impresoras"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selecciona para añadir una impresora"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selecciona para habilitar"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Servicios habilitados"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Instalar para descubrir <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+      <item quantity="one">Instalar para descubrir <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Volver a empezar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"desconocido"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – no disponible"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"¿Usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Es posible que el documento pase por uno o varios servidores antes de imprimirse."</string>
   <string-array name="color_mode_labels">
@@ -91,8 +100,9 @@
     <item msgid="3199660090246166812">"Horizontal"</item>
   </string-array>
     <string name="print_write_error_message" msgid="5787642615179572543">"Error al escribir en el archivo"</string>
-    <string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionado. Repítelo."</string>
+    <string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionado. Prueba de nuevo."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impresora no está disponible en este momento."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"No se puede mostrar la vista previa"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparando vista previa…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index f03eb37..3d0516c 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Lisateave selle printeri kohta"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Mõned printimisteenused on keelatud."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Prinditeenuse valimine"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Mõned printimisteenused on keelatud"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printerite otsimine"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ühtegi printimisteenust pole lubatud"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Printereid ei leitud"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Printereid ei saa lisada"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Valige printeri lisamiseks"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Valige lubamiseks"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Lubatud teenused"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Soovitatud teenused"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Keelatud teenused"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Kõik teenused"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Installige <xliff:g id="COUNT_1">%1$s</xliff:g> printeri avastamiseks</item>
+      <item quantity="one">Installige <xliff:g id="COUNT_0">%1$s</xliff:g> printeri avastamiseks</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> printimine"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> tühistamine"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri viga: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Taaskäivita"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printeriühendus puudub"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"teadmata"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – pole saadaval"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Kas soovite kasutada teenust <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Printerini jõudmiseks võib dokument läbida ühe või mitu serverit."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Kahjuks see ei toiminud. Proovige uuesti."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Proovi uuesti"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"See printer ei ole praegu saadaval."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Eelvaadet ei õnnestu kuvada"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Eelvaate ettevalmistamine ..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index d4255e2..c56692f 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Informazio gehiago inprimagailuari buruz"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Desgaituta daude inprimatzeko zerbitzu batzuk."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Aukeratu inprimatze-zerbitzua"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Desgaituta daude inprimatzeko zerbitzu batzuk"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Inprimagailuak bilatzen"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ez dago gaituta inprimatzeko zerbitzurik"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Ez da inprimagailurik aurkitu"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Ezin da gehitu inprimagailurik"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Hautatu inprimagailua gehitzeko"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Hautatu gehitzeko"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Gaitutako zerbitzuak"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Gomendatutako zerbitzuak"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Desgaitutako zerbitzuak"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Zerbitzu guztiak"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Instalatu <xliff:g id="COUNT_1">%1$s</xliff:g> inprimagailu aurkitzeko</item>
+      <item quantity="one">Instalatu <xliff:g id="COUNT_0">%1$s</xliff:g> inprimagailu aurkitzeko</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzen"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bertan behera uzten"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Errorea <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzean"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Berrabiarazi"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Inprimagailua ez dago konektatuta"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"ezezaguna"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: ez dago erabilgarri"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> erabili nahi duzu?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Baliteke dokumentuak zerbitzari batean edo gehiagotan zehar igarotzea inprimagailurako bidean."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Horrek ez du funtzionatu. Saiatu berriro."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Saiatu berriro"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Une honetan inprimagailua ez dago erabilgarri."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Ezin da bistaratu aurrebista"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Aurrebista prestatzen…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 907123c..8a6c0dd 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"اطلاعات بیشتر درباره چاپگر"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"بعضی از خدمات چاپ غیرفعال هستند."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"انتخاب سرویس چاپ"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"بعضی از خدمات چاپ غیرفعال هستند"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"درحال جستجوی چاپگرها"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"هیچ خدمات چاپی فعال نیست"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"هیچ چاپگری یافت نشد"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"نمی‌توان چاپگر اضافه کرد"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"برای افزودن چاپگر، انتخاب کنید"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"برای فعال کردن، انتخاب کنید"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"خدمات فعال"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"خدمات توصیه‌شده"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"خدمات غیرفعال"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"همه خدمات"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">نصب کنید تا <xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر را پیدا کنید</item>
+      <item quantity="other">نصب کنید تا <xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر را پیدا کنید</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"در حال چاپ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"در حال لغو <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"خطای چاپگر <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"راه‌اندازی مجدد"</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_service_security_warning_title" msgid="2160752291246775320">"از <xliff:g id="SERVICE">%1$s</xliff:g> استفاده شود؟"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ممکن است سندتان برای رسیدن به چاپگر از یک یا چند سرور عبور کند."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"متأسفیم، تلاش ناموفق بود. دوباره امتحان کنید."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"امتحان مجدد"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"این چاپگر اکنون در دسترس نیست."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"نمایش پیش‌نمایش امکان‌پذیر نیست"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"در حال آماده‌سازی پیش‌نمایش…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index f57b884..3d6897d 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Lisätietoja tästä tulostimesta"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Osa tulostuspalveluista on poistettu käytöstä."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Valitse tulostuspalvelu"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Osa tulostuspalveluista on poistettu käytöstä."</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Etsitään tulostimia"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ei käytössä olevia tulostuspalveluita"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tulostimia ei löydy"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Tulostimien lisääminen ei onnistu."</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Valitse palvelu tulostimen lisäämistä varten."</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Valitse käyttöön otettavat palvelut."</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Käytössä olevat palvelut"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Suositellut palvelut"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Käytöstä poistetut palvelut"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Kaikki palvelut"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Asentamalla voit löytää <xliff:g id="COUNT_1">%1$s</xliff:g> tulostinta.</item>
+      <item quantity="one">Asentamalla voit löytää <xliff:g id="COUNT_0">%1$s</xliff:g> tulostimen.</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Tulostetaan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Peruutetaan työ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Tulostinvirhe työlle <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Käynnistä uudelleen"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ei yhteyttä tulostimeen"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"tuntematon"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ei käytettävissä"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Käytetäänkö palvelua <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Asiakirja saattaa kulkea yhden tai useamman palvelimen kautta matkalla tulostimeen."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Ei valitettavasti onnistunut. Yritä uudelleen."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Yritä uudelleen"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Tämä tulostin ei ole käyttävissä juuri nyt."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Esikatselua ei voi näyttää."</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Esikatselua valmistellaan…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 949ba55..6c9539a 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'information sur cette imprimante"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Certains services d\'impression sont désactivés."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Certains services d\'impression sont désactivés"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours..."</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Aucune imprimante trouvée"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Impossible d’ajouter des imprimantes"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Sélectionnez pour ajouter une imprimante"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Sélectionner pour activer"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Services activés"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+      <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Impression de <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> en cours…"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression : « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Recommencer"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"inconnu"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> — indisponible"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Utiliser <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Votre document peut passer par un ou plusieurs serveurs avant d\'arriver à l\'imprimante."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Échec de l\'action. Réessayez."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Cette imprimante n\'est pas accessible pour le moment."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Impossible d\'afficher l\'aperçu"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Préparation de l\'aperçu en cours…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 1fcc040..64add68 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'informations sur cette imprimante"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Certains services d\'impression sont désactivés."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Certains services d\'impression sont désactivés."</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Aucune imprimante trouvée"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Impossible d\'ajouter des imprimantes"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Sélectionnez pour ajouter une imprimante."</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Sélectionnez pour activer."</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Services activés"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+      <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression pour \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Redémarrer"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante."</string>
     <string name="reason_unknown" msgid="5507940196503246139">"inconnue"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – indisponible"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Utiliser <xliff:g id="SERVICE">%1$s</xliff:g> ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Votre document peut passer par un ou plusieurs serveurs avant d\'être envoyé sur l\'imprimante."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Échec de l\'opération. Veuillez réessayer."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Cette imprimante n\'est pas disponible actuellement."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Impossible d\'afficher l\'aperçu"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Préparation de l\'aperçu en cours…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index 2e60960..099159d 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Máis información sobre esta impresora"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Algúns servizos de impresión están desactivados."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Escoller servizo de impresión"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Algúns servizos de impresión están desactivados"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Busca de impresoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Non hai servizos de impresión activados"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Non se atopou ningunha impresora"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Non se poden engadir impresoras"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selecciona un servizo para engadirlle impresora"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selecciona un servizo para activalo"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Servizos activados"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Servizos recomendados"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Servizos desactivados"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Todos os servizos"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Instala o servizo para atopar <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+      <item quantity="one">Instala o servizo para atopar <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Non hai conexión coa impresora"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"descoñecido"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: non dispoñible"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Queres usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"É posible que o teu documento pase por un ou máis servidores antes de imprimirse."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Non funcionou. Téntao de novo."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Tentar de novo"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impresora non está dispoñible nestes momentos."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Non se pode mostrar a vista previa"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparando a vista previa…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 4ba969c..b42fdab 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"આ પ્રિન્ટર વિશે વધુ માહિતી"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"કેટલીક છાપ સેવાઓ અક્ષમ કરેલ છે."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"પ્રિન્ટ સેવા પસંદ કરો"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"કેટલીક છાપવાની સેવાઓ અક્ષમ કરેલ છે"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"પ્રિન્ટર્સ માટે શોધી રહ્યું છે"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"કોઈ છાપ સેવાઓ સક્ષમ કરેલ નથી"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"કોઈ પ્રિન્ટર મળ્યા નથી"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"પ્રિન્ટર્સ ઉમેરી શકતાં નથી"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"પ્રિન્ટર ઉમેરવા માટે પસંદ કરો"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"સક્ષમ કરવા માટે પસંદ કરો"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"સક્ષમ કરેલી સેવાઓ"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"ભલામણ કરેલી સેવાઓ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"અક્ષમ કરેલી સેવાઓ"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"બધી સેવાઓ"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટરની શોધ કરવા માટે ઇન્સ્ટૉલ કરો</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટરની શોધ કરવા માટે ઇન્સ્ટૉલ કરો</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> છાપી રહ્યાં છે"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ને રદ કરી રહ્યું છે"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"પ્રિન્ટર ભૂલ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"પુનઃપ્રારંભ કરો"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> નો ઉપયોગ કરીએ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"તમારો દસ્તાવેજ પ્રિન્ટર સુધીના તેના માર્ગમાં એક અથવા વધુ સર્વર્સથી પસાર થઈ શકે છે."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"માફ કરશો, તે કામ કરતું નહોતું. ફરીથી પ્રયાસ કરો."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"ફરી પ્રયાસ કરો"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"આ પ્રિન્ટર અત્યારે ઉપલબ્ધ નથી."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"પૂર્વાવલોકન પ્રદર્શિત કરી શકતાં નથી"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"પૂર્વાવલોકનની તૈયારી કરી રહ્યું છે..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 1061346..507754a0 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"इस प्रिंटर के बारे में अधिक जानकारी"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"कुछ प्रिंट सेवाएं अक्षम हैं."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"प्रिंट सेवा चुनें"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"कुछ प्रिंट सेवाएं अक्षम हैं"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर खोज रहा है"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"कोई भी प्रिंट सेवा सक्षम नहीं है"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"कोई प्रिंटर नहीं मिले"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिंटर जोड़े नहीं जा सकते"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिंटर जोड़ने के लिए चुनें"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"सक्षम करने के लिए चुनें"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"सक्षम सेवाएं"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"सुझाई गई सेवाएं"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"अक्षम सेवाएं"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"सभी सेवाएं"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर खोजने के लिए इंस्टॉल करें</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर खोजने के लिए इंस्टॉल करें</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट हो रहा है"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"पुन: आरंभ करें"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> का उपयोग करें?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"प्रिंटर पर जाते समय आपका दस्तावेज़ एक या अधिक सर्वर से गुज़र सकता है."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"क्षमा करें, उससे बात नहीं बनी. पुन: प्रयास करें."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"फिर से प्रयास करें"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"यह प्रिंटर इस समय उपलब्ध नहीं है."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"पूर्वावलोकन प्रदर्शित नहीं किया जा सकता"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"पूर्वावलोकन तैयार हो रहा है..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 4a7d29f..92c97ea 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -62,11 +62,22 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Više informacija o ovom pisaču"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Neke su usluge ispisa onemogućene."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Odaberite uslugu ispisa"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke su usluge ispisa onemogućene"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje pisača"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nije omogućena nijedna usluga ispisa"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nije pronađen nijedan pisač"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Ne možete dodati pisače"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Odaberite da biste dodali pisač"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Odaberite za omogućavanje"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Omogućene usluge"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisač</item>
+      <item quantity="few">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+      <item quantity="other">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Ispisivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje zadatka <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Pogreška pisača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -75,7 +86,6 @@
     <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze s pisačem"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"nepoznato"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – zadatak nije dostupan"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Želite li upotrijebiti uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Na putu do pisača vaš dokument može proći kroz jedan ili više poslužitelja."</string>
   <string-array name="color_mode_labels">
@@ -95,5 +105,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Nažalost, to nije uspjelo. Pokušajte ponovo."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovno"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Pisač trenutačno nije dostupan."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Pregled nije dostupan"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 5aae2e4..a2e53db 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"További információ erről a nyomtatóról"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Egyes nyomtatási szolgáltatások le vannak tiltva."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Nyomtatási szolgáltatás kiválasztása"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Egyes nyomtatási szolgáltatások le vannak tiltva"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Nyomtatók keresése"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nincs engedélyezett nyomtatási szolgáltatás"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nem található nyomtató"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nem lehet nyomtatókat hozzáadni"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Nyomtató hozzáadásához válassza ki"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Az engedélyezéshez válassza ki"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Engedélyezett szolgáltatások"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Javasolt szolgáltatások"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Letiltott szolgáltatások"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Minden szolgáltatás"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Telepítés <xliff:g id="COUNT_1">%1$s</xliff:g> nyomtató felfedezéséhez</item>
+      <item quantity="one">Telepítés <xliff:g id="COUNT_0">%1$s</xliff:g> nyomtató felfedezéséhez</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> nyomtatása"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> törlése"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Nyomtatási hiba: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Újraindítás"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nincs kapcsolat a nyomtatóval"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"ismeretlen"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nem érhető el"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Használni szeretné a következő szolgáltatást: <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"A dokumentum áthaladhat egy vagy több szerveren, mielőtt a nyomtatóhoz érne."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Sajnáljuk, de nem sikerült. Próbálja újra."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Újra"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ez a nyomtató jelenleg nem érhető el."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Nem lehet megjeleníteni az előnézetet"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Előnézet előkészítése…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 179c384..e26c244 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Հավելյալ տեղեկություններ այս տպիչի մասին"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Տպելու որոշ ծառայությունները կասեցված են:"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Ընտրեք տպելու ծառայությունը"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Տպելու որոշ ծառայությունները կասեցված են"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Տպիչների որոնում"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ակտիվացված տպման ծառայություններ չկան"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Տպիչներ չեն գտնվել"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Չեն կարող ավելացնել տպիչներ"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Ընտրեք՝ տպիչ ավելացնելու համար"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Ընտրեք՝ միացնելու համար"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Միացված ծառայությունները"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Խորհուրդ տրվող ծառայությունները"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Կասեցված ծառայությունները"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Բոլոր ծառայությունները"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Տեղադրեք՝ <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ հայտնաբերելու համար</item>
+      <item quantity="other">Տեղադրեք՝ <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ հայտնաբերելու համար</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Տպվում է՝ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը չեղարկվում է"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Տպիչի սխալ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Վերագործարկել"</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_service_security_warning_title" msgid="2160752291246775320">"Օգտագործե՞լ <xliff:g id="SERVICE">%1$s</xliff:g>-ը:"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Հնարավոր է՝ փաստաթուղթը մի քանի սերվերներով անցնի մինչ տպվելը:"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Չհաջողվեց: Նորից փորձեք:"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Կրկնել"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Տպիչն այս պահին հասանելի չէ:"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Նախադիտումը հնարավոր չէ"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Նախադիտումը պատրաստվում է…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 7286f7a..4ec0644 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Informasi selengkapnya tentang printer ini"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Beberapa layanan cetak dinonaktifkan."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Pilih layanan cetak"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Beberapa layanan cetak dinonaktifkan"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari printer"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Tidak ada layanan cetak yang aktif"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tidak ditemukan printer"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Tidak dapat menambahkan printer"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Pilih untuk menambahkan printer"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Pilih untuk mengaktifkan"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Layanan diaktifkan"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Layanan yang disarankan"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Layanan dinonaktifkan"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Semua layanan"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Pasang untuk menemukan <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+      <item quantity="one">Pasang untuk menemukan <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ada kesalahan printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Mulai Ulang"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Tidak ada sambungan ke printer"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"tak diketahui"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – tidak tersedia"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Gunakan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumen Anda dapat melewati satu atau beberapa server saat menuju printer."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Maaf, tidak berhasil. Coba lagi."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Coba lagi"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Saat ini printer ini tidak tersedia."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Tidak dapat menampilkan pratinjau"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Menyiapkan pratinjau..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 9ea49a9..e05f07f 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Frekari upplýsingar um þennan prentara"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Hluti prentþjónustunnar er óvirkur."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Veldu prentþjónustu"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Hluti prentþjónustunnar er óvirkur"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Leitar að prentara"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Engin prentþjónusta er virk"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Engir prentarar fundust"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Ekki er hægt að bæta við prenturum"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Veldu til að bæta prentara við"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Veldu til að virkja"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Virkjaðar þjónustur"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Þjónusta sem mælt er með"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Þjónusta við fatlaða"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Öll þjónusta"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Settu upp til að finna <xliff:g id="COUNT_1">%1$s</xliff:g> prentara</item>
+      <item quantity="other">Settu upp til að finna <xliff:g id="COUNT_1">%1$s</xliff:g> prentara</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Prentar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hættir við <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Prentaravilla <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Endurræsa"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Engin tenging við prentara"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"óþekkt"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ekki í boði"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Nota <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Skjalið gæti þurft að fara í gegnum einn eða fleiri þjóna á leið sinni til prentarans."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Þetta virkaði því miður ekki. Reyndu aftur."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Reyna aftur"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Þessi prentari er ekki í boði núna."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Ekki hægt að birta forskoðun"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Undirbýr forskoðun…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index c19d012..39a0a61 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Ulteriori informazioni su questa stampante"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alcuni servizi di stampa sono disattivati."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Scegli servizio di stampa"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alcuni servizi di stampa sono disattivati"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Ricerca di stampanti"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Non è stato attivato alcun servizio di stampa"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nessuna stampante trovata"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Impossibile aggiungere stampanti"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Seleziona per aggiungere stampanti"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Seleziona per attivare"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Servizi abilitati"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Servizi consigliati"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item>
+      <item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Stampa di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Errore della stampante: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Riavvia"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nessun collegamento alla stampante"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"sconosciuto"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - non disponibile"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Utilizzare <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Il tuo documento potrebbe passare da uno o più server per raggiungere la stampante."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Non ha funzionato. Riprova."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Riprova"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Al momento la stampante non è disponibile."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Impossibile visualizzare l\'anteprima"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparazione anteprima…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 00bf27c..9aa4104 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"מידע נוסף על מדפסת זו"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"שירותי הדפסה מסוימים מושבתים."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"בחר שירות הדפסה"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"שירותי הדפסה מסוימים מושבתים"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"מחפש מדפסות"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"לא הופעלו שירותי הדפסה"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"לא נמצאו מדפסות"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"לא ניתן להוסיף מדפסות"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"בחר כדי להוסיף מדפסת"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"בחר כדי להפעיל"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"שירותים מופעלים"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"שירותים מומלצים"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"שירותים מושבתים"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"כל השירותים"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="two">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+      <item quantity="many">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+      <item quantity="other">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+      <item quantity="one">התקן כדי לגלות מדפסת <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"מדפיס את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"מבטל את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"שגיאת מדפסת ב-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"הפעל מחדש"</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_service_security_warning_title" msgid="2160752291246775320">"האם להשתמש ב-<xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ייתכן שהמסמך שלך יעבור בשרת אחד או יותר בדרכו למדפסת."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"מצטערים, אך זה לא עבד. נסה שוב."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"נסה שוב"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"המדפסת הזו אינה זמינה כעת."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"לא ניתן להציג תצוגה מקדימה"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"מכין תצוגה מקדימה…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index e0fc79a..f97efc1 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"このプリンタの詳細"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"一部の印刷サービスは無効になっています。"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"印刷サービスの選択"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"一部の印刷サービスは無効になっています"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"プリンタの検索中"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"使用できる印刷サービスがありません"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"プリンタが見つかりません"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"プリンタは追加できません"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"選択してプリンタを追加"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"選択して有効にする"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"有効になっているサービス"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"推奨されているサービス"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"無効になっているサービス"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"すべてのサービス"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> 台のプリンタを検索するにはインストールします</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> 台のプリンタを検索するにはインストールします</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>を印刷しています"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をキャンセルしています"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"プリンタエラー: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"再試行"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>を利用しますか?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ドキュメントは1つ以上のサーバーを経由してプリンタに送信されることがあります。"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"エラーです。もう一度お試しください。"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"再試行"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"現在このプリンターは使用できません。"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"プレビューを表示できません"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"プレビューを準備しています…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index ad1468a..9cb8b39 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"დამატებითი ინფორმაცია ამ პრინტერის შესახებ"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"ბეჭდვის ზოგიერთი სერვისი გათიშულია."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"აირჩიეთ ბეჭდვის სერვისი"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"ბეჭდვის ზოგიერთი სერვისი გათიშულია"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"მიმდინარეობს პრინტერების ძიება"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ბეჭდვის სერვისები გააქტიურებული არ არის"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"პრინტერები ვერ მოიძებნა"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"პრინტერების დამატება ვერ მოხერხდება"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"აირჩიეთ პრინტერის დასამატებლად"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"აირჩიეთ ჩასართავად"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"ჩართული სერვისები"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"რეკომენდებული სერვისები"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"გათიშული სერვისები"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"ყველა სერვისი"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">დააინსტალირეთ <xliff:g id="COUNT_1">%1$s</xliff:g> პრინტერის აღმოსაჩენად</item>
+      <item quantity="one">დააინსტალირეთ <xliff:g id="COUNT_0">%1$s</xliff:g> პრინტერის აღმოსაჩენად</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"იბეჭდება <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"მიმდინარეობს <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ის გაუქმება"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ბეჭდვის შეცდომა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"გადატვირთვა"</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_service_security_warning_title" msgid="2160752291246775320">"გსურთ, გამოიყენოთ <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"პრინტერამდე გზად დოკუმენტმა შეიძლება ერთი ან მეტი სერვერი გაიაროს."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"უკაცრავად, ვერ მოხერხდა. სცადეთ ისევ."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"გამეორება"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"პრინტერი ამჟამად მიუწვდომელია."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"გადახედვის ჩვენება ვერ ხერხდება"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"მზადდება გადახედვა…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index d0337a6..37b2cd3 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Осы принтер туралы қосымша ақпарат"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Кейбір басып шығару қызметтері өшірілген."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Принтер қызметін таңдау"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Кейбір басып шығару қызметтері өшірілген."</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлерді іздеу"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Басып шығару қызметтері қосылмаған"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Ешқандай принтер табылмады"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Принтерлерді қосу мүмкін емес"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Принтерді қосу үшін таңдаңыз"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Қосу үшін таңдаңыз"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Қосылған қызметтер"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Ұсынылған қызметтер"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Өшірілген қызметтер"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Барлық қызметтер"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басып шығарылуда"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын тоқтатуда"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> принтер қателігі"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Қайта бастау"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> қолданылсын ба?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Құжат принтерге жеткенше бір немесе бірнеше серверден өтуі мүмкін."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Кешіріңіз, бұл нәтиже бермеді. Әрекетті қайталаңыз."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Қайталау"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Бұл принтер дәл қазір қол жетімді емес."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Бетті алдын ала қарау мүмкін емес"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Алдын ала қарау дайындалуда…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index c9431e9..12d296d 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ព័ត៌មានបន្ថែមអំពីម៉ាស៊ីបោះពុម្ពនេះ"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"សេវាកម្មបោះពុម្ពមួយចំនួនត្រូវបានបិទដំណើរការ"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"ជ្រើស​សេវា​បោះពុម្ព"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"សេវាកម្មបោះពុម្ពមួយចំនួនត្រូវបានបិទដំណើរការ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ស្វែងរក​ម៉ាស៊ីន​បោះពុម្ព"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"គ្មានការបើកដំណើរការសេវាបោះពុម្ពទេ"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"រក​មិន​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"មិនអាចបន្ថែមម៉ាស៊ីនបោះពុម្ពបានទេ"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"ជ្រើសដើម្បីបន្ថែមម៉ាស៊ីនបោះពុម្ព"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"ជ្រើសដើម្បីបើកដំណើរការ"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"សេវាកម្មដែលបើកដំណើរការ"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"សេវាកម្មដែលបានណែនាំ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"សេវាកម្មដែលបិទដំណើរការ"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"សេវាកម្មទាំងអស់"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">ដំឡើងដើម្បីរកមើលម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+      <item quantity="one">ដំឡើងដើម្បីរកមើលម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"កំពុង​​បោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ការ​បោះបង់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"កំហុស​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើម​ឡើងវិញ"</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_service_security_warning_title" msgid="2160752291246775320">"ប្រើ <xliff:g id="SERVICE">%1$s</xliff:g> ឬ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ឯកសាររបស់អ្នកអាចនឹងឆ្លងកាត់ម៉ាស៊ីនមេមួយ ឬច្រើននៅពេលដែលវាធ្វើដំណើរទៅកាន់ម៉ាស៊ីនបោះពុម្ព។"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"សូម​ទោស វា​មិន​ដំណើរ​ការ​ទេ។ ព្យាយាម​ម្ដងទៀត។"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"ព្យាយាម​ម្ដងទៀត"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ឥឡូវ​នេះ ម៉ាស៊ីន​បោះពុម្ព​នេះ​មិន​អាច​ប្រើ​បាន។"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"មិនអាចបង្ហាញការមើលជាមុនបានទេ"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"កំពុង​រៀបចំ​មើល​ជា​មុន…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index fc5149a..8b1acdd 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ಈ ಪ್ರಿಂಟರ್ ಬಗ್ಗೆ ಇನ್ನಷ್ಟು ಮಾಹಿತಿ"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"ಕೆಲವು ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"ಮುದ್ರಣ ಸೇವೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"ಕೆಲವು ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ಪ್ರಿಂಟರ್‌‌ಗಳಿಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ಯಾವುದೇ ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿಲ್ಲ"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ಯಾವುದೇ ಮುದ್ರಕಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"ಪ್ರಿಂಟರ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"ಪ್ರಿಂಟರ್ ಸೇರಿಸಲು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"ಸಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"ಸಕ್ರಿಯಗೊಳಿಸಲಾದ ಸೇವೆಗಳು"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"ಶಿಫಾರಸು ಮಾಡಲಾದ ಸೇವೆಗಳು"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾದ ಸೇವೆಗಳು"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"ಎಲ್ಲ ಸೇವೆಗಳು"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್‌ಗಳನ್ನು ಶೋಧಿಸಲು ಸ್ಥಾಪಿಸಿ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್‌ಗಳನ್ನು ಶೋಧಿಸಲು ಸ್ಥಾಪಿಸಿ</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ಮುದ್ರಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ರದ್ದು ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ಮುದ್ರಕ ದೋಷ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"ಮರುಪ್ರಾರಂಭಿಸು"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ಬಳಸುವುದೇ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ನಿಮ್ಮ ಡಾಕ್ಯುಮೆಂಟ್‌ ಪ್ರಿಂಟರ್‌ಗೆ ಹೋಗುವ ಸಂದರ್ಭದಲ್ಲಿ ಒಂದು ಅಥವಾ ಅದಕ್ಕಿಂತ ಹೆಚ್ಚು ಸರ್ವರ್‌ಗಳ ಮೂಲಕ ಹಾದು ಹೋಗಬಹುದು."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"ಕ್ಷಮಿಸಿ, ಅದು ಕೆಲಸ ಮಾಡುತ್ತಿಲ್ಲ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"ಮರುಪ್ರಯತ್ನಿಸು"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ಈ ಪ್ರಿಂಟರ್ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"ಪೂರ್ವವೀಕ್ಷಣೆ ಪ್ರದರ್ಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"ಪೂರ್ವವೀಕ್ಷಣೆ ತಯಾರಾಗುತ್ತಿದೆ…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 2faff1f..e6ca240 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"이 프린터에 대한 정보 더보기"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"프린트 서비스 일부가 사용 중지되었습니다."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"인쇄 서비스 선택"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"프린트 서비스 일부가 사용 중지되었습니다."</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"프린터 검색 중"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"사용 가능한 프린트 서비스 없음"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"프린터 없음"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"프린터를 추가할 수 없음"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"프린터를 추가하려면 선택하세요."</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"사용 설정하려면 선택하세요."</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"사용 설정된 서비스"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"권장 서비스"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"사용 중지된 서비스"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"모든 서비스"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>개 프린터를 표시하려면 설치하세요.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>개 프린터를 표시하려면 설치하세요.</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 인쇄 중"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 취소 중"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"프린터 오류: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"다시 시작"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>을(를) 사용할까요?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"문서가 프린터로 전송되는 중에 하나 이상의 서버를 통과할 수 있습니다."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"죄송합니다. 오류가 발생했습니다. 다시 시도해 보세요."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"다시 시도"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"현재 이 프린터를 사용할 수 없습니다."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"미리보기를 표시할 수 없음"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"미리보기 준비 중…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index a01e4a8..ae0b05e 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Бул принтер жөнүндө көбүрөөк маалымат"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Басып чыгаруу кызматтарынын айрымы өчүрүлгөн."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Принтер кызматын тандоо"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Басып чыгаруу кызматтарынын айрымы өчүрүлгөн"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлер изделүүдө"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Принтер-кызматтары иштетилген эмес"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Принтерлер табылган жок"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Принтерлер кошулбай жатат"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Принтер кошуу үчүн тандаңыз"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Иштетүү үчүн тандаңыз"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Иштетилген кызматтар"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Сунушталган кызматтар"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Өчүрүлгөн кызматтар"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Бардык кызматтар"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Орнотсоңуз <xliff:g id="COUNT_1">%1$s</xliff:g> принтер таап аласыз</item>
+      <item quantity="one">Орнотсоңуз <xliff:g id="COUNT_0">%1$s</xliff:g> принтер таап аласыз</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басылууда"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> токтотулууда"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерде ката кетти: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Кайра баштоо"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> колдонулсунбу?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Принтерге жеткиче документиңиз бир же андан көп серверлерден өтүшү мүмкүн."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Кечиресиз, иштеген жок. Дагы бир жолу аракет кылып көрүңүз."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Дагы бир жолу аракет кылуу"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Учурда бул принтерди колдонуу мүмкүн эмес."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Алдын ала көрүнүшү көрсөтүлбөй жатат"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Алдын-ала көрүүгө даярданууда…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index b5d13b5..2392e4a 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບເຄື່ອງພິມນີ້"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"ບາງການບໍລິການພິມຖືກປິດນຳໃຊ້."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"ເລືອກບໍລິການການພິມ"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"ບາງການບໍລິການພິມຖືກປິດການນຳໃຊ້"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ກຳລັງຊອກຫາເຄື່ອງພິມ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ບໍ່​ມີ​ການ​ບໍ​ລິ​ການ​ພິມ​ເປີດ​ໃຊ້​ງານ​ໄວ້"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ບໍ່ພົບເຄື່ອງພິມ"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"ບໍ່ສາມາດເພີ່ມເຄື່ອງພິມໄດ້"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"ເລືອກເພື່ອເພີ່ມເຄື່ອງພິມ"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"ເລືອກເພື່ອເປີດໃຊ້"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"ບໍລິການທີ່ເປີດໃຊ້"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"ບໍລິການທີ່ແນະນຳ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"ບໍລິການທີ່ຖືກປິດການນຳໃຊ້"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"ບໍລິການທັງໝົດ"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">ຕິດຕັ້ງເພື່ອຄົ້ນພົບເຄື່ອງພິມ <xliff:g id="COUNT_1">%1$s</xliff:g> ເຄື່ອງ</item>
+      <item quantity="one">ຕິດຕັ້ງເພື່ອຄົ້ນພົບເຄື່ອງພິມ <xliff:g id="COUNT_0">%1$s</xliff:g> ເຄື່ອງ</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"ກຳລັງພິມ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ກຳລັງຍົກເລີກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ເຄື່ອງພິມເກີດຂໍ້ຜິດພາດ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"ປິດເປີດໃໝ່"</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_service_security_warning_title" msgid="2160752291246775320">"ໃຊ້ <xliff:g id="SERVICE">%1$s</xliff:g> ບໍ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ເອກະສານຂອງທ່ານອາດເດີນທາງຜ່ານໜຶ່ງ ຫຼື ຫຼາຍເຊີບເວີ ເພື່ອໄປຮອດເຄື່ອງພິມ."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"ຂໍ​ອະ​ໄພ, ໃຊ້​ບໍ່​ໄດ້. ໃຫ້​ລອງ​ໃໝ່​ອີກ​ເທື່ອ​ນຶ່ງ."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"ລອງໃໝ່"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ບໍ່​ສາ​ມາດ​ໃຊ້ເຄື່ອງພິມ​ນີ້​ໃນ​ເວ​ລາ​ນີ້​ໄດ້."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"ບໍ່ສາມາດສະແດງຕົວຢ່າງໄດ້"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"ກຳ​ລັງ​ກະ​ກຽມ​ຕົວ​ຢ່າງ…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 3b8f143..65ccc2b 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"„<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g>“ – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Daugiau informacijos apie šį spausdintuvą"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Kai kurios spausdinimo paslaugos išjungtos."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Pasirinkite spausdinimo paslaugą"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Kai kurios spausdinimo paslaugos išjungtos"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Ieškoma spausdintuvų"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Neįgalinta jokių spausdinimo paslaugų"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nerasta spausdintuvų"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nepavyko pridėti spausdintuvų"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Pasirinkite, kad pridėtumėte spausdintuvą"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Pasirinkite, kad įgalintumėte"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Įgalintos paslaugos"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Rekomenduojamos paslaugos"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Išjungtos paslaugos"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Visos paslaugos"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Įdiekite, kad būtų rastas <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvas</item>
+      <item quantity="few">Įdiekite, kad būtų rasti <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvai</item>
+      <item quantity="many">Įdiekite, kad būtų rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvo</item>
+      <item quantity="other">Įdiekite, kad būtų rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvų</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Spausdinama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Atšaukiama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Spausdintuvo klaida: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"Paleisti iš naujo"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nėra ryšio su spausdintuvu"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"nežinoma"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ – nepasiekiama"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Naudoti „<xliff:g id="SERVICE">%1$s</xliff:g>“?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Kai dokumentas siunčiamas į spausdintuvą, jis gali būti perduodamas per vieną ar daugiau serverių."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Deja, tai neveikia. Bandykite dar kartą."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Bandykite dar kartą"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Šis spausdintuvas šiuo metu nepasiekiamas."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Nepavyksta pateikti peržiūros"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Ruošiama peržiūra…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 762d0bd..1bcfe78 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -62,11 +62,22 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Plašāka informācija par šo printeri"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Daži drukas pakalpojumi ir atspējoti."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Izvēlieties drukāšanas pakalpojumu"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Daži drukas pakalpojumi ir atspējoti."</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printeru meklēšana"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nav iespējots neviens drukas pakalpojums"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Netika atrasts neviens printeris."</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nevar pievienot printerus"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Atlasiet, lai pievienotu printeri"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Izvēlieties, lai iespējotu"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Iespējotie pakalpojumi"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Ieteiktie pakalpojumi"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Atspējotie pakalpojumi"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Visi pakalpojumi"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="zero">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printerus</item>
+      <item quantity="one">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
+      <item quantity="other">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printerus</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Notiek darba <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> drukāšana…"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Pārtrauc drukas darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printera kļūda ar darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -75,7 +86,6 @@
     <string name="restart" msgid="2472034227037808749">"Restartēt"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nav savienojuma ar printeri"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"nezināms"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> — nav pieejams"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Vai izmantot pakalpojumu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokuments, iespējams, tiek pārsūtīts caur vienu vai vairākiem serveriem, līdz tas nonāk līdz printerim."</string>
   <string-array name="color_mode_labels">
@@ -95,5 +105,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Diemžēl tas neizdevās. Mēģiniet vēlreiz."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Mēģināt vēlreiz"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Šis printeris šobrīd nav pieejams."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Nevar attēlot priekšskatījumu"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Notiek priekšskatījuma sagatavošana..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index de6d3e9..d29566bc 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Повеќе информации за овој печатач"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Некои услуги за печатење се оневозможени."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Избери услуга печатење"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Некои услуги за печатење се оневозможени"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Пребарување печатачи"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Нема овозможени услуги за печатење"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Не се пронајдени печатачи"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Не може да се додадат печатачи"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Изберете додавање печатач"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Изберете да се овозможи"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Овозможени услуги"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Препорачани услуги"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Оневозможени услуги"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Сите услуги"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Инсталирајте за да пронајдете <xliff:g id="COUNT_1">%1$s</xliff:g> печатач</item>
+      <item quantity="other">Инсталирајте за да пронајдете <xliff:g id="COUNT_1">%1$s</xliff:g> печатачи</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се печати"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се откажува"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка при печатење <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Рестартирај"</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_service_security_warning_title" msgid="2160752291246775320">"Користи <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"На пат до печатачот, документот може да помине преку еден или повеќе сервери."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"За жал, тоа не успеа. Обидете се повторно."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Обиди се повторно"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Овој печатач не е достапен во моментов."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Прегледот не може да се прикаже"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Се подготвува преглед…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index 7a33e14..16d654c 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ഈ പ്രിന്ററിനെ കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾ"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"ചില പ്രിന്റ് സേവനങ്ങൾ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"പ്രിന്റ് സേവനം തിരഞ്ഞെടുക്കുക"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"ചില പ്രിന്റ് സേവനങ്ങൾ പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"പ്രിന്ററുകൾക്കായി തിരയുന്നു"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"പ്രിന്റ് സേവനങ്ങളൊന്നും പ്രവർത്തനക്ഷമാക്കിയിട്ടില്ല"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"പ്രിന്ററുകളൊന്നും കണ്ടെത്തിയില്ല"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"പ്രിന്ററുകൾ ചേർക്കാൻ കഴിയില്ല"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"പ്രിന്റർ ചേർക്കാൻ തിരഞ്ഞെടുക്കുക"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"പ്രവർത്തനക്ഷമമാക്കാൻ തിരഞ്ഞെടുക്കുക"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"പ്രവർത്തനക്ഷമമാക്കിയ സേവനങ്ങൾ"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"ശുപാർശ ചെയ്യപ്പെടുന്ന സേവനങ്ങൾ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"പ്രവർത്തനരഹിതമാക്കിയ സേവനങ്ങൾ"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"എല്ലാ സേവനങ്ങളും"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> പ്രിന്ററുകൾ കണ്ടെത്തുന്നതിന് ഇൻസ്റ്റാൾ ചെയ്യുക</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> പ്രിന്റർ കണ്ടെത്തുന്നതിന് ഇൻസ്റ്റാൾ ചെയ്യുക</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> പ്രിന്റുചെയ്യുന്നു"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> റദ്ദാക്കുന്നു"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"പ്രിന്റർ പിശക് <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"പുനരാരംഭിക്കുക"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ഉപയോഗിക്കണോ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"നിങ്ങളുടെ പ്രമാണം പ്രിന്ററിലേക്ക് പോകുന്നതിനിടെ അത് ഒന്നോ അതിലധികമോ സെർവറുകളിലൂടെ കടന്നുപോകാനിടയുണ്ട്."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"ക്ഷമിക്കണം, അത് പ്രവർത്തിച്ചില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ഈ പ്രിന്ററർ ഇപ്പോൾ ലഭ്യമല്ല."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"പ്രിവ്യൂ കാണിക്കാൻ കഴിയില്ല"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"പ്രിവ്യൂ തയ്യാറാക്കുന്നു…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index c94e56d..ded0665 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Энэ хэвлэгчийн талаарх дэлгэрэнгүй мэдээлэл"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Зарим хэвлэх үйлчилгээг идэвхгүй болгосон байна."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Хэвлэх үйлчилгээг сонгох"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Зарим хэвлэх үйлчилгээг идэвхгүй болгосон байна"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Принтер хайж байна"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Хэвлэх үйлчилгээг идэвхжүүлээгүй"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Принтер олдсонгүй"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Хэвлэгч нэмэх боломжгүй байна"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Хэвлэгч нэмэхийн тулд сонгох"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Идэвхжүүлэхийн тулд сонгох"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Идэвхжүүлсэн үйлчилгээ"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Санал болгосон үйлчилгээ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Идэвхгүй болгосон үйлчилгээ"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Бүх үйлчилгээ"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$s</xliff:g> хэвлэгч олохын тулд суулгах</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$s</xliff:g> хэвлэгч олохын тулд суулгах</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Хэвлэж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Цуцлаж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерийн алдаа <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Дахин эхлүүлэх"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>-г ашиглах уу?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Таны документ хэвлэгчид иртэл нэг эсвэл хэд хэдэн серверээр дамжина."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Уучлаарай, ажилласангүй. Дахин оролдоно уу."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Дахин оролдох"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Одоо хэвлэгч ашиглах боломжгүй."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Урьдчилан үзүүлэх боломжгүй"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Урьдчилан харахыг бэлтгэж байна…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index ab25010..5436635 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"या प्रिंटर विषयी अधिक माहिती"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"काही मुद्रण सेवा अक्षम केल्या आहेत."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"मुद्रण सेवा निवडा"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"काही मुद्रण सेवा अक्षम केल्या आहेत"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही मुद्रण सेवा सक्षम केलेल्या नाहीत"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"कोणतेही प्रिंटर आढळले नाही"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिंटर जोडू शकत नाही"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिंटर जोडण्यासाठी निवडा"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"सक्षम करण्यासाठी निवडा"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"सक्षम केलेल्या सेवा"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"शिफारस केलेल्या सेवा"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"अक्षम केलल्या सेवा"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"सर्व सेवा"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी स्थापित करा</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी स्थापित करा</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करीत आहे"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"रीस्टार्ट करा"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> वापरायची?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"आपला दस्तऐवज प्रिंटरपर्यंत पोहचण्‍यापूर्वी एक किंवा अधिक सर्व्हरद्वारे जाऊ शकतो."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"क्षमस्व, त्याने कार्य केले नाही. पुन्हा प्रयत्न करा."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"पुन्हा प्रयत्न करा"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"हा प्रिंटर आत्ता उपलब्ध नाही."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"पूर्वावलोकन प्रदर्शित करू शकत नाही"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"पूर्वावलोकनाची तयारी करत आहे..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index 917ae8a..8af5232 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Maklumat lanjut tentang pencetak ini"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Sesetengah perkhidmatan cetak dilumpuhkan."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Pilih perkhidmatan cetak"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Sesetengah perkhidmatan cetak dilumpuhkan"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari pencetak"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Perkhidmatan cetak tidak didayakan"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tiada pencetak ditemui"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Tidak dapat menambahkan pencetak"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Pilih untuk menambahkan pencetak"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Pilih untuk mendayakan"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Perkhidmatan yang didayakan"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Perkhidmatan yang disyorkan"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Perkhidmatan yang dilumpuhkan"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Semua perkhidmatan"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Pasang untuk menemui <xliff:g id="COUNT_1">%1$s</xliff:g> pencetak</item>
+      <item quantity="one">Pasang untuk menemui <xliff:g id="COUNT_0">%1$s</xliff:g> pencetak</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ralat pencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Mulakan semula"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Tiada sambungan ke pencetak"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"tidak diketahui"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – tidak tersedia"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Gunakan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumen anda mungkin melalui satu atau beberapa pelayan dalam perjalanan ke pencetak."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Maaf, itu tidak berjaya. Cuba lagi."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Cuba semula"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Pencetak ini tidak tersedia sekarang."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Tidak dapat memaparkan pratonton"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Menyediakan pratonton..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index 4d4c95b..9b5f46a 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ဤပရင်တာ အကြောင်း ပိုမိုလေ့လာပါ"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"ပရင့်ထုတ်ရေး အချို့ဝန်ဆောင်မှုများကို ပိတ်ထားပါသည်။"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"စာထုတ်ရန် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"အချို့ပုံနှိပ်ဝန်ဆောင်မှုများကို ပိတ်ထားပါသည်"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"စာထုတ်စက်များကို ရှာနေပါသည်"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ပုံနှိပ်ထုတ်ယူရေး ဝန်ဆောင်မှုများ ဖွင့်မထားပါ"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"စာထုတ်စက် တစ်ခုမှ မတွေ့ရှိပါ"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"ပုံနှိပ်စက်များကို ထည့်၍မရပါ"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"ပုံနှိပ်စက်ထည့်ရန် ရွေးပါ"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"ဖွင့်ရန် ရွေးပါ"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"ဖွင့်ထားသည့် ဝန်ဆောင်မှုများ"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"အကြံပြုထားသည့် ဝန်ဆောင်မှုများ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"ပိတ်ထားသည့် ဝန်ဆောင်မှုများ"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"ဝန်ဆောင်မှုများ အားလုံး"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">ပုံနှိပ်စက် <xliff:g id="COUNT_1">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item>
+      <item quantity="one">ပုံနှိပ်စက် <xliff:g id="COUNT_0">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို စာထုတ်နေပါသည်"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"အစက ပြန်စရန်"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ကိုသုံးမလား။"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"သင်၏ စာရွက်စာတမ်းများသည် ပရင်တာထံသို့ သွားစဉ် ဆာဗာ တစ်ခု သို့မဟုတ် ပိုများပြီး ဖြတ်ကျော်နိုင်ရသည်။"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"ဆော်ရီး၊ အဲဒါ အလုပ်မဖြစ်ခဲ့ပါ။ ထပ် စမ်းပါ။"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"ထပ်စမ်း"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ဒီပရင်တာမှာ ယခုအချိန်မှာ မရနိုင်ပါ။"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"အစမ်းကြည့်ခြင်းကို ပြသ၍မရပါ"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"အစမ်းကြည့်ရန် ပြင်ဆင်နေ…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 9efa5d1..82282ba 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Mer informasjon om denne printeren"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Noen utskriftstjenester er slått av."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Velg utskriftstjeneste"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Noen utskriftstjenester er slått av"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Søker etter skrivere"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ingen utskriftstjenester er slått på"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Fant ingen skrivere"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Kan ikke legge til skrivere"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Velg for å legge til skrivere"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Velg for å slå på"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Tjenester som er slått på"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Anbefalte tjenester"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Tjenester som er slått av"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Installer for å finne <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+      <item quantity="one">Installer for å finne <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Skriverfeil <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Start på nytt"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse med skriveren"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"ukjent"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – utilgjengelig"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Vil du bruke <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumentet ditt kan gå via flere tjenere før det når skriveren."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Beklager, det fungerte ikke. Prøv på nytt."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Prøv på nytt"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Denne skriveren er ikke tilgjengelig akkurat nå."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan ikke vise forhåndsvisningen"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Forbereder forhåndsvisningen …"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 281a65d..4cf2f51 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"यस प्रिन्टरको बारेमा थप जानकारी"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"केही मुद्रण सेवाहरू असक्षम छन्।"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"प्रिन्ट सेवा छनौट गर्नुहोस्"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"केही मुद्रण सम्बन्धी सेवाहरूलाई असक्षम गरिएको छ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिन्टरहरू खोज्दै"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"कुनै पनि मुद्रण सेवाहरू सक्रिय छैनन्"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"कुनै प्रिन्टरहरू भेटाइएन"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिन्टरहरू थप्न सक्दैन"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिन्टर थप्नका लागि चयन गर्नुहोस्"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"सक्षम गर्नका लागि चयन गर्नुहोस्"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"सक्षम गरिएका सेवाहरू"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"सिफारिस गरिएका सेवाहरू"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"असक्षम गरिएका सेवाहरू"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"सबै सेवाहरू"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिन्टरहरू पत्ता लगाउनका लागि स्थापना गर्नुहोस्</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> प्रिन्टर पत्ता लगाउनका लागि स्थापना गर्नुहोस्</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"प्रिन्ट गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"रद्द गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिन्टर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"पुनःस्टार्ट गर्नुहोस्"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> प्रयोग गर्ने हो?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"तपाईँको कागजात प्रिन्टरमा जाँदा यसको मार्गमा एक वा धेरै सर्भरहरू पार हुनसक्छन्।"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"माफ गर्नुहोस्, त्यसले काम गरेन। पुनः प्रयास गर्नुहोस्।"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"पुनःप्रयास गर्नुहोस्"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"यो प्रिन्टर अहिले उपलब्ध छैन।"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"पूर्वावलोकनलाई प्रदर्शन गर्न सक्दैन"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"पूर्वावलोकन तयारी..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index eef9880..83b9a22 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Meer informatie over deze printer"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Sommige afdrukservices zijn uitgeschakeld."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Afdrukservice kiezen"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Sommige afdrukservices zijn uitgeschakeld"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printers zoeken"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Geen afdrukservices ingeschakeld"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Geen printers gevonden"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Kan geen printers toevoegen"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selecteer om printer toe te voegen"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selecteer om in te schakelen"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Ingeschakelde services"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Aanbevolen services"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Uitgeschakelde services"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Alle services"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Installeren om <xliff:g id="COUNT_1">%1$s</xliff:g> printers te vinden</item>
+      <item quantity="one">Installeren om <xliff:g id="COUNT_0">%1$s</xliff:g> printer te vinden</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> afdrukken"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annuleren"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerfout <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Opnieuw starten"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met printer"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"onbekend"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – niet beschikbaar"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> gebruiken?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Je document kan via een of meer servers naar de printer worden verzonden."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Dat werkte niet. Probeer het opnieuw."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Opnieuw proberen"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Deze printer is momenteel niet beschikbaar."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan voorbeeld niet weergeven"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Voorbeeld voorbereiden…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 7d7860c..5f3366f 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ਇਸ ਪ੍ਰਿੰਟਰ ਬਾਰੇ ਹੋਰ ਜਾਣਕਾਰੀ"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"ਕੁਝ ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ।"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"ਪ੍ਰਿੰਟ ਸੇਵਾ ਚੁਣੋ"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"ਕੁਝ ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ਪ੍ਰਿੰਟਰ ਖੋਜ ਰਿਹਾ ਹੈ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਯੋਗ ਨਹੀਂ ਬਣਾਈਆਂ ਗਈਆਂ"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ਕੋਈ ਪ੍ਰਿੰਟਰ ਨਹੀਂ ਮਿਲੇ"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"ਪ੍ਰਿੰਟਰ ਸ਼ਾਮਲ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"ਪ੍ਰਿੰਟਰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਚੁਣੋ"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"ਯੋਗ ਬਣਾਉਣ ਲਈ ਚੁਣੋ"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"ਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਸੇਵਾਵਾਂ"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀਆਂ ਸੇਵਾਵਾਂ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਸੇਵਾਵਾਂ"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"ਸਾਰੀਆਂ ਸੇਵਾਵਾਂ"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਖੋਜਣ ਲਈ ਸਥਾਪਤ ਕਰੋ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਖੋਜਣ ਲਈ ਸਥਾਪਤ ਕਰੋ</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਿੰਟ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਰੱਦ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ਪ੍ਰਿੰਟਰ ਅਸ਼ੁੱਧੀ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"ਰੀਸਟਾਰਟ ਕਰੋ"</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_service_security_warning_title" msgid="2160752291246775320">"ਕੀ <xliff:g id="SERVICE">%1$s</xliff:g> ਵਰਤਣੀ ਹੈ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ਤੁਹਾਡਾ ਦਸਤਾਵੇਜ਼ ਪ੍ਰਿੰਟਰ ਵਿੱਚ ਜਾਣ ਲਈ ਇੱਕ ਜਾਂ ਦੋ ਸਰਵਰਾਂ ਵਿੱਚੋਂ ਲੰਘਦਾ ਹੈ।"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"ਮਾਫ਼ ਕਰਨਾ, ਉਸਨੇ ਲਾਭਕਾਰੀ ਨਹੀਂ ਹੋਇਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ਇਹ ਪ੍ਰਿੰਟਰ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"ਝਲਕ ਨਹੀਂ ਵਿਖਾਈ ਜਾ ਸਕਦੀ"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"ਪ੍ਰੀਵਿਊ ਦੀ ਤਿਆਰੀ ਕਰ ਰਿਹਾ ਹੈ…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 6837edf..e7fb7b6 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Więcej informacji o tej drukarce"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Niektóre usługi drukowania są wyłączone."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Wybierz usługę drukowania"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Niektóre usługi drukowania są wyłączone"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Szukanie drukarek"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Brak włączonych usług drukowania"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nie znaleziono drukarek"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nie można dodawać drukarek"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Wybierz, by dodać drukarkę"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Wybierz, by włączyć usługę"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Włączone usługi"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Polecane usługi"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Wyłączone usługi"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Wszystkie usługi"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="few">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+      <item quantity="many">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarek</item>
+      <item quantity="other">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+      <item quantity="one">Zainstaluj, by wykryć <xliff:g id="COUNT_0">%1$s</xliff:g> drukarkę</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Drukowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Anulowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Błąd drukarki: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"Od nowa"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Brak połączenia z drukarką"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"brak informacji"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – niedostępne"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Użyć usługi <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Zanim dokument dotrze do drukarki, może przejść przez jeden lub kilka serwerów."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"To nie zadziałało. Spróbuj jeszcze raz."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Ponów próbę"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Drukarka nie jest teraz dostępna."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Nie można wyświetlić podglądu"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Przygotowuję podgląd…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index c9713c9..dd8cdb2 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alguns serviços de impressão estão desativados."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serviços de impressão estão desativados"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Não é possível adicionar impressoras"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selecione para adicionar uma impressora"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selecione para ativar"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Serviços ativados"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+      <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – não disponível"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Seu documento pode passar por um ou mais servidores até chegar à impressora."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Falhou. Tente novamente."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impressora não está disponível no momento."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Não é possível exibir a visualização"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparando visualização…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 9fabc0f..c1fe7bf 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações acerca desta impressora"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alguns serviços de impressão estão desativados."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Escolher o serviço de impressão"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serviços de impressão estão desativados"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"A procurar impressoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Não é possível adicionar impressoras"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selecione para adicionar uma impressora"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selecione para ativar"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Serviços ativados"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+      <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"A imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem ligação à impressora"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – indisponível"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Pretende utilizar o <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"O seu documento pode passar por um ou mais servidores no respetivo caminho para a impressora."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Lamentamos, mas isso não funcionou. Tente novam."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impressora não está atualmente disponível."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Não é possível apresentar a pré-visualização"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"A preparar a pré-visualização..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index c9713c9..dd8cdb2 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alguns serviços de impressão estão desativados."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serviços de impressão estão desativados"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Não é possível adicionar impressoras"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selecione para adicionar uma impressora"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selecione para ativar"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Serviços ativados"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+      <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – não disponível"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Seu documento pode passar por um ou mais servidores até chegar à impressora."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Falhou. Tente novamente."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impressora não está disponível no momento."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Não é possível exibir a visualização"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Preparando visualização…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 7364eb0..b326e09 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -62,11 +62,22 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Mai multe informații despre această imprimantă"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Unele servicii de printare sunt dezactivate."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Alegeți serviciul de printare"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Unele servicii de printare sunt dezactivate"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Se caută imprimante"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Niciun serviciu de printare activat"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nu au fost găsite imprimante"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nu pot fi adăugate imprimante"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Selectați pentru a adăuga o imprimantă"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Selectați pentru a activa"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Servicii activate"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Servicii recomandate"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Servicii dezactivate"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Toate serviciile"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="few">Instalați pentru a descoperi <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+      <item quantity="other">Instalați pentru a descoperi <xliff:g id="COUNT_1">%1$s</xliff:g> de imprimante</item>
+      <item quantity="one">Instalați pentru a descoperi <xliff:g id="COUNT_0">%1$s</xliff:g> imprimantă</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Se printează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Se anulează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Eroare de printare: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -75,7 +86,6 @@
     <string name="restart" msgid="2472034227037808749">"Reporniți"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nu există conexiune la o imprimantă"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"necunoscut"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - indisponibil"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Folosiți <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Documentul poate trece prin unul sau mai multe servere pe calea spre imprimantă."</string>
   <string-array name="color_mode_labels">
@@ -95,5 +105,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Ne pare rău, operațiunea nu a reușit. Încercați din nou."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Reîncercați"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Această imprimantă nu este disponibilă momentan."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Previzualizarea nu se poate afișa"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Se pregătește previzualizarea..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index d3d0d3f..5acadbc 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Подробные сведения о принтере"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Некоторые службы печати отключены."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Выберите службу печати"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Некоторые службы печати отключены"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Поиск принтеров…"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Службы печати недоступны"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Ничего не найдено"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Невозможно добавить принтеры"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Выберите, чтобы добавить принтер"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Выберите, чтобы включить"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Включенные службы"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Рекомендуемые службы"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Отключенные службы"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Все службы печати"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+      <item quantity="few">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+      <item quantity="many">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтеров</item>
+      <item quantity="other">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Печать задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\"…"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отмена задания <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ошибка задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"Повторить"</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_service_security_warning_title" msgid="2160752291246775320">"Использовать <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Документ может пересылаться на принтер через несколько серверов."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Ошибка. Повторите попытку."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Повторить"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Принтер не готов."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Сбой предварительного просмотра"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Подготовка изображения…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index 610442d..db4c5fd 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"මෙම මුද්‍රණ යන්ත්‍රය ගැන තවත් තොරතුරු"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"සමහර මුද්‍රණ සේවා අබලයි."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"මුද්‍රණ සේවාව තෝරන්න"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"සමහර මුද්‍රණ සේවා අබලයි"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"මුද්‍රණ යන්ත්‍ර සොයමින්"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"මුද්‍රණ සේවා සබල නැත"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"මුද්‍රණ යන්ත්‍ර සොයා නොගැනුණි"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"මුද්‍රණ යන්ත්‍ර එක් කළ නොහැකිය"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"මුද්‍රණ යන්ත්‍රය එක් කිරීමට තෝරන්න"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"සබල කිරීමට තෝරන්න"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"සබල කළ සේවා"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"නිර්දේශිත සේවා"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"අබල කළ සේවා"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"සියලු සේවා"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT_1">%1$s</xliff:g>ක් සොයා ගැනීමට ස්ථාපනය කරන්න</item>
+      <item quantity="other">මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT_1">%1$s</xliff:g>ක් සොයා ගැනීමට ස්ථාපනය කරන්න</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> මුද්‍රණය වේ"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"අවලංගු කෙරේ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"මුද්‍රණ දෝෂය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"යළි අරඹන්න"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> භාවිත කරන්නද?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ඔබගේ ලේඛනය මුද්‍රණ යන්ත්‍රයට යන අතරතුර සේවාදායක එකක් හෝ කිහිපයක් හරහා යා හැක."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"කණගාටුයි, එය වැඩ නොකරයි. නැවත උත්සහ කරන්න."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"නැවත උත්සාහ කරන්න"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"දැන් මෙම මුද්‍රණ යන්ත්‍රය නොපවතී."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"පෙරදසුන සංදර්ශනය කළ නොහැකිය"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"පෙරදසුන සූදානම් කරමින්…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 603d1d2..63ee5e2 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Ďalšie informácie o tejto tlačiarni"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Niektoré tlačové služby sú vypnuté."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Výber tlačovej služby"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Niektoré tlačové služby sú zakázané"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhľadávanie tlačiarní"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Žiadne tlačové služby nie sú aktivované"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nenašli sa žiadne tlačiarne"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nie je možné pridať tlačiarne"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Výber služby na pridanie tlačiarne"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Vyberte a povoľte"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Povolené služby"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Odporúčané služby"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Zakázané služby"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Všetky služby"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="few">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+      <item quantity="many">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+      <item quantity="other">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarní</item>
+      <item quantity="one">Nainštalujte a objavte <xliff:g id="COUNT_0">%1$s</xliff:g> tlačiareň</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Prebieha tlač úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prebieha zrušenie úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tlačiarne – úloha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"Spustiť znova"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Žiadne pripojenie k tlačiarni"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"neznáme"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nie je k dispozícii"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Použiť službu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Skôr ako sa váš dokument dostane do tlačiarne, môže prejsť jedným alebo viacerými servermi."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Je nám to ľúto, nefungovalo to. Skúste to znova."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Opakovať"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Táto tlačiareň nie je momentálne k dispozícii."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Ukážka sa nedá zobraziť"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Pripravuje sa ukážka..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index 4a08269..f7616db 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Več informacij o tem tiskalniku"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Nekatere tiskalne storitve so onemogočene."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Izberite tiskalno storitev"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Nekatere tiskalne storitve so onemogočene"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Iskanje tiskalnikov"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ni omogočenih tiskalnih storitev"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tiskalnikov ni mogoče najti"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Tiskalnikov ni mogoče dodati"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Izberite za dodajanje tiskalnika"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Izberite, če želite omogočiti"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Omogočene storitve"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Priporočene storitve"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Onemogočene storitve"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Vse storitve"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnika</item>
+      <item quantity="two">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+      <item quantity="few">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+      <item quantity="other">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Tiskanje: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Preklic: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Napaka tiskalnika: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"Začni znova"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ni povezave s tiskalnikom"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"neznano"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ni na voljo"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Želite uporabiti storitev <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokument gre lahko na poti do tiskalnika skozi enega ali več strežnikov."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"To žal ni delovalo. Poskusite znova."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Poskusi znova"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ta tiskalnik trenutno ni na voljo."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Predogleda ni mogoče prikazati"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Priprava predogleda …"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index b0902ef..f4d2817 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Më shumë informacione mbi këtë printer"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Disa shërbime printimi janë çaktivizuar."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Zgjidh shërbimin e printimit"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Disa shërbime printimi janë çaktivizuar"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Po kërkon për printerë"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nuk ka shërbime printimi të aktivizuara"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nuk u gjet asnjë printer"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Nuk mund të shtohen printerë"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Zgjidh për të shtuar printer"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Zgjidh për të aktivizuar"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Shërbimet e aktivizuara"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Shërbimet e rekomanduara"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Shërbimet e çaktivizuara"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Të gjitha shërbimet"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Instaloje për të zbuluar <xliff:g id="COUNT_1">%1$s</xliff:g> printera</item>
+      <item quantity="one">Instaloje për të zbuluar <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Po printon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Po anulon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri ndeshi në gabim gjatë punës: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Rifillo"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printeri nuk është i lidhur"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"e panjohur"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nuk mundësohet"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Përdor <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumenti mund të kalojë përmes një ose shumë serverëve deri te printeri."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Na vjen keq, nuk funksionoi! Provo përsëri."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Provo sërish"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ky printer nuk mund të përdoret tani."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Nuk mund të shfaqet paraafishimi"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Po përgatit shikimin paraprak…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index feb2940..b285044 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -62,11 +62,22 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Још информација о овом штампачу"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Неке услуге штампања су онемогућене."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Изаберите услугу штампања"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Неке услуге штампања су онемогућене"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Претрага штампача"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ниједна услуга штампања није омогућена"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Није пронађен ниједан штампач"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Није могуће додати штампаче"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Изаберите да бисте додали штампач"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Изаберите да бисте омогућили"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Омогућене услуге"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Препоручене услуге"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Онемогућене услуге"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Све услуге"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампач</item>
+      <item quantity="few">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+      <item quantity="other">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Штампа се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отказује се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка штампача <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -75,7 +86,6 @@
     <string name="restart" msgid="2472034227037808749">"Поново покрени"</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_service_security_warning_title" msgid="2160752291246775320">"Желите ли да користите <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Документ може да прође кроз један или више сервера на путу до штампача."</string>
   <string-array name="color_mode_labels">
@@ -95,5 +105,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Жао нам је, ово није успело. Покушајте поново."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Покушајте поново"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Овај штампач тренутно није доступан."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Није успео приказ прегледа"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Припрема прегледа..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index cf398c7..4a72800 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Mer information om den här skrivaren"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Några utskriftstjänster har inaktiverats."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Välj utskriftstjänst"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Några utskriftstjänster har inaktiverats"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Söker efter skrivare"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Inga utskriftstjänster har aktiverats"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Det gick inte att hitta några skrivare"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Det går inte att lägga till skrivare"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Lägg till en skrivare"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Välj om du vill aktivera"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Aktiverade tjänster"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Rekommenderade tjänster"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Inaktiverade tjänster"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Alla tjänster"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Installera och hitta <xliff:g id="COUNT_1">%1$s</xliff:g> skrivare</item>
+      <item quantity="one">Installera och hitta <xliff:g id="COUNT_0">%1$s</xliff:g> skrivare</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Skrivarfel för <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Starta om"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen anslutning till skrivaren"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"okänt"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – inte tillgänglig"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Vill du använda <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"På vägen till skrivaren kan dokumentet passera en eller flera servrar."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Det fungerade tyvärr inte. Försök igen."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Försök igen"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Den här skrivaren är inte tillgänglig just nu."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Det gick inte att visa förhandsgranskningen"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Förbereder förhandsvisning ..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index 7e00b70..34b935d 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Maelezo zaidi kuhusu printa hii"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Baadhi ya huduma za uchapishaji zimezimwa."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Chagua huduma ya printa"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Baadhi ya huduma za uchapishaji haziruhusiwi"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Inatafuta printa"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Huduma za kuchapisha hazijawashwa"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Hakuna printa zilizopatikana"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Haiwezi kuongeza printa"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Chagua printa ya kuongeza"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Chagua ili uruhusu"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Huduma zinazoruhusiwa"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Huduma zinazopendekezwa"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Huduma ambazo haziruhusiwi"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Huduma zote"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Sakinisha ili ugundue printa <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+      <item quantity="one">Sakinisha ili ugundue printa <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Inachapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Inaghairi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Hitilafu ya kuchapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Anzisha upya"</string>
     <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_service_security_warning_title" msgid="2160752291246775320">"Ungependa kutumia <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Huenda hati yako ikapitia seva moja au zaidi kabla ya kufika kwenye printa."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Samahani, hiyo haikufanya kazi. Jaribu tena."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Jaribu tena"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Printa hii haipatikani kwa sasa."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Haiwezi kupakia onyesho la kuchungulia"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Inaandaa onyesho la kuchungulia..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index ae0b774..22f41bf 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"இந்தப் பிரிண்டர் பற்றிய கூடுதல் தகவல்"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"சில அச்சுப் பொறிகள் முடக்கப்பட்டன."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"அச்சுப் பொறியைத் தேர்வுசெய்யவும்"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"சில அச்சுப் பொறிகள் முடக்கப்பட்டன"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"அச்சுப்பொறிகளைத் தேடுகிறது"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"அச்சுப் பொறிகள் இல்லை"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"பிரிண்டர்கள் எதுவுமில்லை"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"பிரிண்டர்களைச் சேர்க்க முடியவில்லை"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"பிரிண்டரைச் சேர்க்க, தேர்ந்தெடுக்கவும்"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"இயக்குவதற்குத் தேர்ந்தெடுக்கவும்"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"இயக்கப்பட்ட அச்சுப் பொறிகள்"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"பரிந்துரைக்கப்படும் அச்சுப் பொறிகள்"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"முடக்கப்பட்ட அச்சுப் பொறிகள்"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"எல்லா அச்சுப் பொறிகளும்"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> பிரிண்டர்களைக் கண்டறிய, நிறுவவும்</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> பிரிண்டரைக் கண்டறிய, நிறுவவும்</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ அச்சிடுகிறது"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ ரத்துசெய்கிறது"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"பிரிண்டர் பிழை <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"மீண்டும் தொடங்கு"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ஐப் பயன்படுத்தவா?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"உங்கள் ஆவணம் பிரிண்டருக்குச் செல்லும் வழியில் ஒன்று அல்லது அதற்கு மேற்பட்ட சேவையகங்களைக் கடந்து செல்லக்கூடும்."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"செயல்படவில்லை. மீண்டும் முயலவும்."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"மீண்டும் முயலவும்"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"இப்போது பிரிண்டர் இல்லை."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"மாதிரிக்காட்சியைக் காட்ட முடியவில்லை"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"மாதிரிக்காட்சியைத் தயார்படுத்துகிறது…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index 5fd8d60..1211cfd 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ఈ ప్రింటర్ గురించి మరింత సమాచారం"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"కొన్ని ముద్రణ సేవలు నిలిపివేయబడ్డాయి."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"ముద్రణ సేవను ఎంచుకోండి"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"కొన్ని ముద్రణ సేవలు నిలిపివేయబడ్డాయి"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ప్రింటర్‌ల కోసం శోధిస్తోంది"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ముద్రణ సేవలు ఏవీ ప్రారంభించలేదు"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ప్రింటర్‌లు కనుగొనబడలేదు"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"ప్రింటర్‌లను జోడించడం సాధ్యపడలేదు"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"ప్రింటర్‌ను జోడించడానికి ఎంచుకోండి"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"ప్రారంభించడానికి ఎంచుకోండి"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"ప్రారంభించిన సేవలు"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"సిఫార్సు చేయబడిన సేవలు"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"నిలిపివేసిన సేవలు"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"అన్ని సేవలు"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ప్రింటర్‌లను కనుగొనడానికి ఇన్‌స్టాల్ చేయండి</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ప్రింటర్‌ను కనుగొనడానికి ఇన్‌స్టాల్ చేయండి</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను ముద్రిస్తోంది"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను రద్దు చేస్తోంది"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ప్రింటర్ లోపం <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"పునఃప్రారంభించు"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ని ఉపయోగించాలా?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"మీ పత్రం ప్రింటర్‌కు వెళ్లే మార్గంలో ఒకటి లేదా అంతకంటే ఎక్కువ సర్వర్‌ల గుండా వెళ్లవచ్చు."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"క్షమించండి, అది పని చేయలేదు. మళ్లీ ప్రయత్నించండి."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"మళ్లీ ప్రయత్నించు"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ఈ ప్రింటర్ ప్రస్తుతం అందుబాటులో లేదు."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"పరిదృశ్యాన్ని ప్రదర్శించడం సాధ్యపడలేదు"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"పరిదృశ్యం సిద్ధమవుతోంది…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index ebd5e2a..7f99288 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"ข้อมูลเพิ่มเติมเกี่ยวกับเครื่องพิมพ์นี้"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"บริการพิมพ์บางอย่างถูกปิดใช้"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"เลือกบริการพิมพ์"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"บริการพิมพ์บางอย่างปิดใช้อยู่"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"กำลังค้นหาเครื่องพิมพ์"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ไม่ได้เปิดใช้บริการพิมพ์"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ไม่พบเครื่องพิมพ์"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"เพิ่มเครื่องพิมพ์ไม่ได้"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"เลือกเพื่อเพิ่มเครื่องพิมพ์"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"เลือกเพื่อเปิดใช้"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"บริการที่เปิดใช้"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"บริการที่แนะนำ"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"บริการที่ปิดใช้"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"บริการทั้งหมด"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">ติดตั้งเพื่อค้นหาเครื่องพิมพ์ <xliff:g id="COUNT_1">%1$s</xliff:g> เครื่อง</item>
+      <item quantity="one">ติดตั้งเพื่อค้นหาเครื่องพิมพ์ <xliff:g id="COUNT_0">%1$s</xliff:g> เครื่อง</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"กำลังพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"กำลังยกเลิก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ข้อผิดพลาดเครื่องพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"เริ่มต้นใหม่"</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_service_security_warning_title" msgid="2160752291246775320">"ใช้ <xliff:g id="SERVICE">%1$s</xliff:g> ไหม"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"เอกสารของคุณอาจต้องผ่านมากกว่าหนึ่งเซิร์ฟเวอร์ระหว่างส่งไปยังเครื่องพิมพ์"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"ขออภัย ไม่สามารถใช้งานได้ ลองอีกครั้ง"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"ลองอีกครั้ง"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"เครื่องพิมพ์นี้ไม่พร้อมใช้งานในขณะนี้"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"ไม่สามารถแสดงตัวอย่าง"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"กำลังเตรียมการแสดงตัวอย่าง…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index ebe869b..7b50815 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Higit pang impormasyon tungkol sa printer na ito"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Naka-disable ang ilang serbisyo sa pag-print."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Pumili ng serbisyo ng pag-print"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Naka-disable ang ilang serbisyo sa pag-print"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Naghahanap ng mga printer"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Walang mga naka-enable na serbisyo sa pag-print"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Walang mga printer na nakita"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Hindi makapagdagdag ng mga printer"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Piliin upang magdagdag ng printer"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Piliin upang i-enable"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Mga naka-enable na serbisyo"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Mga inirerekomendang serbisyo"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Mga naka-disable na serbisyo"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Lahat ng serbisyo"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">I-install upang tumuklas ng <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+      <item quantity="other">I-install upang tumuklas ng <xliff:g id="COUNT_1">%1$s</xliff:g> na printer</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Pini-print ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kinakansela ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error sa printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"I-restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Hindi nakakonekta sa printer"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"hindi alam"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – hindi available"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Gusto mo bang gamitin ang <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Bago ma-print ang iyong dokumento, maaari itong dumaan sa isa o higit pang mga server."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Paumanhin, hindi iyon gumana. Subukang muli."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Subukang muli"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Hindi available ang printer na ito sa ngayon."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Hindi maipakita ang preview"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Inihahanda ang preview…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index 9cd42ab..1ca722b 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Bu yazıcıyla ilgili daha fazla bilgi"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Bazı yazdırma hizmetleri devre dışı."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Yazdırma hizmetini seçin"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Bazı yazdırma hizmetleri devre dışı bırakıldı"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Yazıcılar aranıyor"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Etkin yazıcı hizmeti yok"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Yazıcı bulunamadı"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Yazıcı eklenemiyor"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Yazıcı eklemek için seçin"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Etkinleştirmek için seçin"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Etkin hizmetler"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Önerilen hizmetler"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Devre dışı bırakılmış hizmetler"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Tüm hizmetler"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> yazıcıyı keşfetmek için yükleyin</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> yazıcıyı keşfetmek için yükleyin</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> yazdırılıyor"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> iptal ediliyor"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Yazıcı hatası: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Yeniden başlat"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Yazıcı bağlantısı yok"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"bilinmiyor"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – kullanılamıyor"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> kullanılsın mı?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokümanınız yazıcıya giderken bir veya daha fazla sunucudan geçebilir."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Maalesef bu işe yaramadı. Tekrar deneyin."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Yeniden dene"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Bu yazı şu anda kullanılamıyor."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Önizleme gösterilemiyor"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Önizleme hazırlanıyor…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 1082147..8004639 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -63,11 +63,23 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Докладніше про цей принтер"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Деякі служби друку вимкнено."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Вибрати службу друку"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Деякі служби друку вимкнено"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук принтерів"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Немає служб друку"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Принтери не знайдено"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Не можна додати принтери"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Виберіть, щоб додати принтер"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Виберіть, щоб увімкнути"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Увімкнені служби"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Рекомендовані служби"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Вимкнені служби"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Усі служби"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+      <item quantity="few">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтери</item>
+      <item quantity="many">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
+      <item quantity="other">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" друкується"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" скасовується"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Помилка завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
@@ -76,7 +88,6 @@
     <string name="restart" msgid="2472034227037808749">"Перезапустити"</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_service_security_warning_title" msgid="2160752291246775320">"Увімкнути службу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Коли ви надсилаєте документ на принтер, він може проходити через декілька серверів."</string>
   <string-array name="color_mode_labels">
@@ -96,5 +107,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"На жаль, сталася помилка. Повторіть спробу."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Повторити"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Цей принтер зараз недоступний."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Не вдалося відкрити попередній перегляд"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Підготовка до попереднього перегляду…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index 56f1093..19e759c 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"اس پرنٹر کے بارے میں مزید معلومات"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"پرنٹ کی کچھ سروسز غیر فعال ہیں۔"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"پرنٹ سروس منتخب کریں"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"پرنٹ کی کچھ سروسز غیر فعال ہیں"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"پرنٹرز تلاش کر رہا ہے"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"کوئی پرنٹ سروس فعال نہیں"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"کوئی پرنٹرز نہيں ملے"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"پرنٹرز شامل نہیں ہو سکتے"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"پرنٹر شامل کرنے کیلئے منتخب کریں"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"فعال کرنے کیلئے منتخب کریں"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"فعال کردہ سروسز"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"تجویز کردہ سروسز"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"غیر فعال کردہ سروسز"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"تمام سروسز"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> پرنٹرز دریافت کرنے کیلئے انسٹال کریں</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> پرنٹر دریافت کرنے کیلئے انسٹال کریں</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> پرنٹ کررہا ہے"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو منسوخ کر رہا ہے"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"پرنٹر کی خرابی <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"دوبارہ شروع کریں"</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_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> استعمال کریں؟"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"آپ کی دستاویز پرنٹر تک جاتے ہوئے ممکن ہے ایک یا زیادہ سرورز سے گزرے۔"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"معذرت، اس نے کام نہیں کیا۔ دوبارہ کوشش کریں۔"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"دوبارہ کوشش کریں"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"یہ پرنٹر ابھی دستیاب نہیں ہے۔"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"پیش منظر ڈسپلے نہیں ہو سکتا"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"پیش منظر کو تیار کیا جا رہا ہے…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 30b218e..cf87a74 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Printer haqida batafsil ma’lumot"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Bir qancha chop etish xizmatlari o‘chirilgan."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Chop etish xizmatini tanlang"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Ayrim chop etish xizmatlari o‘chirib qo‘yilgan"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printerlar qidirilmoqda"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Hech qaysi chop etish xizmati yoqilmagan"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Printerlar topilmadi"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Printerlarni qo‘shib bo‘lmaydi"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Printer qo‘shish uchun tanlang"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Yoqish uchun tanlang"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Yoqilgan xizmatlar"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Tavsiya etilgan xizmatlar"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"O‘chirib qo‘yilgan xizmatlar"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Barcha xizmatlar"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ta printerni topish uchun o‘rnating</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ta printerni topish uchun o‘rnating</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Chop etilmoqda: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bekor qilinmoqda"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerda xatolik: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Qayta boshlash"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printer ulanmagan"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"noma’lum"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – mavjud emas"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> xizmatidan foydalanilsinmi?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Hujjatingiz chop etilishidan oldin bir yoki bir necha serverlardan o‘tishi mumkin."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Kechirasiz, ishlamadi. Qayta urinib ko‘ring."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Qayta urinish"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ushbu printer hozirda mavjud emas."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Oldindan ko‘rsatib bo‘lmaydi"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Dastlabki ko\'rishga tayyorlanmoqda…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 32aaf63..2c1fa27 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Thông tin khác về máy in này"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Một số dịch vụ in bị vô hiệu hóa."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Chọn dịch vụ in"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Một số dịch vụ in đã bị tắt"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Đang tìm kiếm máy in"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Chưa kích hoạt dịch vụ in nào"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Không tìm thấy máy in"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Không thể thêm máy in"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Chọn để thêm máy in"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Chọn để bật"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Dịch vụ đã bật"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Dịch vụ được đề xuất"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Dịch vụ đã tắt"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Tất cả dịch vụ"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">Cài đặt để phát hiện <xliff:g id="COUNT_1">%1$s</xliff:g> máy in</item>
+      <item quantity="one">Cài đặt để phát hiện <xliff:g id="COUNT_0">%1$s</xliff:g> máy in</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"In <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hủy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Lỗi máy in <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Bắt đầu lại"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Không có kết nối nào với máy in"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"không xác định"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – không khả dụng"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Sử dụng <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Tài liệu của bạn có thể đi qua một hoặc nhiều máy chủ trên đường đến máy in."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Rất tiếc, tính năng đó không hoạt động. Hãy thử lại."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Thử lại"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Máy in này hiện không khả dụng."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Không thể hiển thị bản xem trước"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Đang chuẩn bị xem trước…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 42cf3b1..b350051 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"部分打印服务已停用。"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"选择打印服务"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分打印服务已停用"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"未启用任何打印服务"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"找不到打印机"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"无法添加打印机"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"选择即可添加打印机"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"选择即可启用"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"已启用的服务"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"推荐的服务"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"已停用的服务"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"所有服务"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">安装即可找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台打印机</item>
+      <item quantity="one">安装即可找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"正在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"打印机在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”时出错"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"重新开始"</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_service_security_warning_title" msgid="2160752291246775320">"要使用<xliff:g id="SERVICE">%1$s</xliff:g>吗?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"您的文档可能会通过一个或多个服务器发送至打印机。"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"抱歉,操作失败。请重试。"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"重试"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"该打印机目前无法使用。"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"无法显示预览"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"即将显示预览…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 0a458ad..192b41b 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"此打印機詳情"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"已停用部分列印服務。"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分列印服務已停用"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋打印機"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"沒有已啟用的列印服務"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"找不到打印機"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"無法新增印表機"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"選擇即可新增印表機"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"選取即可啟用"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"已啟用的服務"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"推薦服務"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"已停用的服務"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"所有服務"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">安裝即可使用 <xliff:g id="COUNT_1">%1$s</xliff:g> 部印表機</item>
+      <item quantity="one">安裝即可使用 <xliff:g id="COUNT_0">%1$s</xliff:g> 部印表機</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"打印機錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"重新開始"</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_service_security_warning_title" msgid="2160752291246775320">"要使用 <xliff:g id="SERVICE">%1$s</xliff:g> 嗎?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"您的文件可能會通過一部或多部伺服器才傳送至打印機。"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"很抱歉,行不通。請再試一次。"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"這部打印機目前無法使用。"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"無法顯示預覽"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"正在準備預覽…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 7a30011..4aa5681 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"查看這台印表機的詳細資訊"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"部分列印服務已停用。"</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"已停用部分列印服務"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋印表機"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"未啟用任何列印服務"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"找不到印表機"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"無法新增印表機"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"選取即可新增印表機"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"選取即可啟用"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"已啟用的列印服務"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"建議的列印服務"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"已停用的列印服務"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"所有列印服務"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="other">安裝即可使用 <xliff:g id="COUNT_1">%1$s</xliff:g> 個印表機</item>
+      <item quantity="one">安裝即可使用 <xliff:g id="COUNT_0">%1$s</xliff:g> 個印表機</item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"印表機發生錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"重新開始"</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_service_security_warning_title" msgid="2160752291246775320">"要使用「<xliff:g id="SERVICE">%1$s</xliff:g>」嗎?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"您的文件可能會透過一或多個伺服器輾轉傳送至印表機。"</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"很抱歉,無法執行這項操作。請再試一次。"</string>
     <string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"這台印表機目前無法使用。"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"無法顯示預覽畫面"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"正在準備預覽…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index f57b58c..121022b 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -61,11 +61,21 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Olunye ulwazi mayelana nale phrinta"</string>
-    <string name="print_services_disabled_toast" msgid="1205302482388937547">"Amanye amasevisi wokuphrinta akhutshaziwe."</string>
-    <string name="choose_print_service" msgid="3740309762324459694">"Khetha isevisi yephrinta"</string>
+    <string name="print_services_disabled_toast" msgid="9089060734685174685">"Amanye amasevisi okuphrinta akhutshaziwe"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Isesha amaphrinta"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Amasevisi ephrinta akavuliwe."</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Awekho amaphrinta atholiwe"</string>
+    <string name="cannot_add_printer" msgid="7840348733668023106">"Ayikwazi ukungeza amaphrinta"</string>
+    <string name="select_to_add_printers" msgid="3800709038689830974">"Khetha ukuze ungeze iphrinta"</string>
+    <string name="enable_print_service" msgid="3482815747043533842">"Khetha ukuze unike amandla"</string>
+    <string name="enabled_services_title" msgid="7036986099096582296">"Amasevisi anikwe amandla"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"Amasevisi anconyiwe"</string>
+    <string name="disabled_services_title" msgid="7313253167968363211">"Amasevisi akhutshaziwe"</string>
+    <string name="all_services_title" msgid="5578662754874906455">"Onke amasevisi"</string>
+    <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="one">Faka ukuze uthole amaphrinta we-<xliff:g id="COUNT_1">%1$s</xliff:g></item>
+      <item quantity="other">Faka ukuze uthole amaphrinta we-<xliff:g id="COUNT_1">%1$s</xliff:g></item>
+    </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Iphrinta i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ikhansela i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Iphutha lephrinta ye-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -74,7 +84,6 @@
     <string name="restart" msgid="2472034227037808749">"Qala kabusha"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Akukho ukuxhumana kuphrinta"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"akwaziwa"</string>
-    <string name="printer_unavailable" msgid="2434170617003315690">"I-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ayitholakali"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"Sebenzisa i-<xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Idokhumenti yakho ingase idlule iseva eyodwa noma amaningi lapho iya kuphrinta."</string>
   <string-array name="color_mode_labels">
@@ -94,5 +103,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Uxolo, lokho akusebenzanga. Zama futhi."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Zama futhi"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Le phrinta ayitholakali khona manje."</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Ayikwazi ukubonisa ukubuka kuqala"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Ilungiselela ukubuka kuqala…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml
index d1bec32..47e616e 100644
--- a/packages/PrintSpooler/res/values/colors.xml
+++ b/packages/PrintSpooler/res/values/colors.xml
@@ -22,8 +22,6 @@
 
     <color name="print_preview_background_color">#F2F1F2</color>
 
-    <color name="promoted_action_background_color">#FF80CBC4</color>
-
     <color name="material_grey_500">#ffa3a3a3</color>
 
 </resources>
diff --git a/packages/PrintSpooler/res/values/donottranslate.xml b/packages/PrintSpooler/res/values/donottranslate.xml
index 8069a1d..589043b 100644
--- a/packages/PrintSpooler/res/values/donottranslate.xml
+++ b/packages/PrintSpooler/res/values/donottranslate.xml
@@ -25,4 +25,6 @@
     <string name="mediasize_default">ISO_A4</string>
     <string name="mediasize_standard">@string/mediasize_standard_iso</string>
 
+    <string name="uri_package_details">market://details?id=%1$s</string>
+
 </resources>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 76292a1..2836adb 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -129,7 +129,7 @@
     <!-- Utterance to announce that the search box is hidden. This is spoken to a blind user. [CHAR LIMIT=none] -->
     <string name="print_search_box_hidden_utterance">Search box hidden</string>
 
-    <!-- Title of the action bar button to got to add a printer. [CHAR LIMIT=25] -->
+    <!-- Label of add printers button when no printers are found. [CHAR LIMIT=25] -->
     <string name="print_add_printer">Add printer</string>
 
     <!-- Title of the menu item to select a printer. [CHAR LIMIT=25] -->
@@ -151,12 +151,7 @@
     <string name="printer_info_desc">More information about this printer</string>
 
     <!-- Notification that print services as disabled. [CHAR LIMIT=50] -->
-    <string name="print_services_disabled_toast">Some print services are disabled.</string>
-
-    <!-- Add printer dialog  -->
-
-    <!-- Title for the alert dialog for selecting a print service. [CHAR LIMIT=50] -->
-    <string name="choose_print_service">Choose print service</string>
+    <string name="print_services_disabled_toast">Some print services are disabled</string>
 
     <!-- Title for the prompt shown as a placeholder if no printers are found while not searching. [CHAR LIMIT=50] -->
     <string name="print_searching_for_printers">Searching for printers</string>
@@ -167,6 +162,35 @@
     <!-- Title for the prompt shown as a placeholder if there are no printers while searching. [CHAR LIMIT=50] -->
     <string name="print_no_printers">No printers found</string>
 
+    <!-- Add printer activity -->
+
+    <!-- Subtitle for services that cannot add printers. [CHAR LIMIT=50] -->
+    <string name="cannot_add_printer">Cannot add printers</string>
+
+    <!-- Subtitle for services that can add printers. [CHAR LIMIT=50] -->
+    <string name="select_to_add_printers">Select to add printer</string>
+
+    <!-- Subtitle for disabled services. [CHAR LIMIT=50] -->
+    <string name="enable_print_service">Select to enable</string>
+
+    <!-- Header for the list of enabled print services. [CHAR LIMIT=50] -->
+    <string name="enabled_services_title">Enabled services</string>
+
+    <!-- Header for the list of recommended print services. [CHAR LIMIT=50] -->
+    <string name="recommended_services_title">Recommended services</string>
+
+    <!-- Header for the list of disabled print services. [CHAR LIMIT=50] -->
+    <string name="disabled_services_title">Disabled services</string>
+
+    <!-- Label for the list item that links to the list of all print services. [CHAR LIMIT=50] -->
+    <string name="all_services_title">All services</string>
+
+    <!-- Subtitle for a print service recommendation. [CHAR LIMIT=50] -->
+    <plurals name="print_services_recommendation_subtitle">
+        <item quantity="one">Install to discover <xliff:g id="count" example="1">%1$s</xliff:g> printer</item>
+        <item quantity="other">Install to discover <xliff:g id="count" example="2">%1$s</xliff:g> printers</item>
+    </plurals>
+
     <!-- Notifications -->
 
     <!-- Template for the notification label for a printing print job. [CHAR LIMIT=25] -->
@@ -193,9 +217,6 @@
     <!-- Label for an unknown reason for failed or blocked print job. [CHAR LIMIT=25] -->
     <string name="reason_unknown">unknown</string>
 
-    <!-- Label for a printer that is not available. [CHAR LIMIT=25] -->
-    <string name="printer_unavailable"><xliff:g id="print_job_name" example="Canon-123GHT">%1$s</xliff:g> &#8211; unavailable</string>
-
     <!-- Title for a warning message about security implications of using a print service,
          displayed as a dialog message when the user prints using a print service that has not been
          used before. [CHAR LIMIT=NONE] -->
@@ -236,26 +257,6 @@
         <item>Landscape</item>
     </string-array>
 
-    <!-- Permissions -->
-
-    <!-- Title of an application permission, listed so the user can choose whether they want
-         to allow the application to do this. -->
-    <string name="permlab_accessAllPrintJobs" translatable="false">access all print jobs</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_accessAllPrintJobs" translatable="false">Allows the holder to access
-        print jobs created by another app. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want
-         to allow the application to do this. -->
-    <string name="permlab_startPrintServiceConfigActivity" translatable="false">start print
-        service configuration activities</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_startPrintServiceConfigActivity" translatable="false">Allows the
-        holder to start the configuration activities of a print service. Should never be needed
-        for normal apps.</string>
-
     <!-- Error messages -->
 
     <!-- Message for an error when trying to print to a PDF file. [CHAR LIMIT=50] -->
@@ -270,6 +271,10 @@
     <!-- Message for the currently selected printer being unavailable. [CHAR LIMIT=100] -->
     <string name="print_error_printer_unavailable">This printer isn\'t available right now.</string>
 
+    <!-- Message for the case when a preview of a page cannot be loaded because the printing app
+         provided a broken print preview rendering for this page. [CHAR LIMIT=50] -->
+    <string name="print_cannot_load_page">Can\'t display preview</string>
+
     <!-- Long running operations -->
 
     <!-- Message long running operation when preparing print preview. [CHAR LIMIT=50] -->
diff --git a/packages/PrintSpooler/res/values/styles.xml b/packages/PrintSpooler/res/values/styles.xml
new file mode 100644
index 0000000..1e63a67e
--- /dev/null
+++ b/packages/PrintSpooler/res/values/styles.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <!-- Preference styles -->
+    <eat-comment/>
+
+    <style name="ListItemSecondary" parent="@android:style/TextAppearance.Material.Body1">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+
+    <style name="ListSeparator">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_marginTop">16dip</item>
+        <item name="android:layout_marginBottom">16dip</item>
+        <item name="android:textColor">?android:attr/colorAccent</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+</resources>
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 05de5b7..a968ffa 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -15,8 +15,17 @@
 -->
 
 <resources>
+    <style name="Theme.AddPrinterActivity" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
+        <item name="android:listSeparatorTextViewStyle">@style/ListSeparator</item>
+        <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
+    </style>
 
-    <style name="PrintActivity" parent="@android:style/Theme.DeviceDefault">
+    <style name="Theme.SelectPrinterActivity"
+           parent="android:style/Theme.DeviceDefault.Light.DarkActionBar">
+        <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
+    </style>
+
+    <style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault">
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowContentOverlay">@null</item>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 0210693..cd1d540 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -208,7 +208,7 @@
             }
         }
 
-        CharSequence status = printJob.getStatus();
+        CharSequence status = printJob.getStatus(mContext.getPackageManager());
         if (status != null) {
             builder.setContentText(status);
         } else {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index ac97ad0..bb35917 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -75,7 +75,7 @@
     private int mState;
 
     public interface OnPageContentAvailableCallback {
-        public void onPageContentAvailable(BitmapDrawable content);
+        void onPageContentAvailable(BitmapDrawable content);
     }
 
     public PageContentRepository(Context context) {
@@ -741,6 +741,7 @@
             final RenderSpec mRenderSpec;
             OnPageContentAvailableCallback mCallback;
             RenderedPage mRenderedPage;
+            private boolean mIsFailed;
 
             public RenderPageTask(int pageIndex, RenderSpec renderSpec,
                     OnPageContentAvailableCallback callback) {
@@ -826,25 +827,24 @@
 
                 Bitmap bitmap = mRenderedPage.content.getBitmap();
 
-                ParcelFileDescriptor[] pipe = null;
+                ParcelFileDescriptor[] pipe;
                 try {
                     pipe = ParcelFileDescriptor.createPipe();
-                    ParcelFileDescriptor source = pipe[0];
-                    ParcelFileDescriptor destination = pipe[1];
 
-                    mRenderer.renderPage(mPageIndex, bitmap.getWidth(), bitmap.getHeight(),
-                            mRenderSpec.printAttributes, destination);
+                    try (ParcelFileDescriptor source = pipe[0]) {
+                        try (ParcelFileDescriptor destination = pipe[1]) {
 
-                    // We passed the file descriptor to the other side which took
-                    // ownership, so close our copy for the write to complete.
-                    destination.close();
+                            mRenderer.renderPage(mPageIndex, bitmap.getWidth(), bitmap.getHeight(),
+                                    mRenderSpec.printAttributes, destination);
+                        }
 
-                    BitmapSerializeUtils.readBitmapPixels(bitmap, source);
-                } catch (IOException|RemoteException e) {
-                    Log.e(LOG_TAG, "Error rendering page:" + mPageIndex, e);
-                } finally {
-                    IoUtils.closeQuietly(pipe[0]);
-                    IoUtils.closeQuietly(pipe[1]);
+                        BitmapSerializeUtils.readBitmapPixels(bitmap, source);
+                    }
+
+                    mIsFailed = false;
+                } catch (IOException|RemoteException|IllegalStateException e) {
+                    Log.e(LOG_TAG, "Error rendering page " + mPageIndex, e);
+                    mIsFailed = true;
                 }
 
                 return mRenderedPage;
@@ -859,12 +859,22 @@
                 // This task is done.
                 mPageToRenderTaskMap.remove(mPageIndex);
 
-                // Take a note that the content is rendered.
-                renderedPage.state = RenderedPage.STATE_RENDERED;
+                if (mIsFailed) {
+                    renderedPage.state = RenderedPage.STATE_SCRAP;
+                } else {
+                    renderedPage.state = RenderedPage.STATE_RENDERED;
+                }
+
+                // Invalidate all caches of the old state of the bitmap
+                mRenderedPage.content.invalidateSelf();
 
                 // Announce success if needed.
                 if (mCallback != null) {
-                    mCallback.onPageContentAvailable(renderedPage.content);
+                    if (mIsFailed) {
+                        mCallback.onPageContentAvailable(null);
+                    } else {
+                        mCallback.onPageContentAvailable(renderedPage.content);
+                    }
                 }
             }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 18160ff..9b1ab0e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -19,6 +19,7 @@
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Context;
@@ -575,19 +576,35 @@
         }
     }
 
-   /**
-    * Set the status for a print job.
-    *
-    * @param printJobId ID of the print job to update
-    * @param status the new status
-    */
-   public void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) {
-       synchronized (mLock) {
-           getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setStatus(status);
+    /**
+     * Set the status for a print job.
+     *
+     * @param printJobId ID of the print job to update
+     * @param status the new status
+     */
+    public void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) {
+        synchronized (mLock) {
+            getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setStatus(status);
 
-           mNotificationController.onUpdateNotifications(mPrintJobs);
-       }
-   }
+            mNotificationController.onUpdateNotifications(mPrintJobs);
+        }
+    }
+
+    /**
+     * Set the status for a print job.
+     *
+     * @param printJobId ID of the print job to update
+     * @param status the new status as a string resource
+     * @param appPackageName app package the resource belongs to
+     */
+    public void setStatus(@NonNull PrintJobId printJobId, @StringRes int status,
+            @Nullable CharSequence appPackageName) {
+        synchronized (mLock) {
+            getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setStatus(status, appPackageName);
+
+            mNotificationController.onUpdateNotifications(mPrintJobs);
+        }
+    }
 
     public boolean hasActivePrintJobsLocked() {
         final int printJobCount = mPrintJobs.size();
@@ -884,7 +901,7 @@
                         serializer.attribute(null, ATTR_PROGRESS, String.valueOf(progress));
                     }
 
-                    CharSequence status = printJob.getStatus();
+                    CharSequence status = printJob.getStatus(getPackageManager());
                     if (!TextUtils.isEmpty(status)) {
                         serializer.attribute(null, ATTR_STATUS, status.toString());
                     }
@@ -1041,7 +1058,9 @@
             try {
                 in = mStatePersistFile.openRead();
             } catch (FileNotFoundException e) {
-                Log.i(LOG_TAG, "No existing print spooler state.");
+                if (DEBUG_PERSISTENCE) {
+                    Log.d(LOG_TAG, "No existing print spooler state.");
+                }
                 return;
             }
             try {
@@ -1433,6 +1452,13 @@
             PrintSpoolerService.this.setStatus(printJobId, status);
         }
 
+        @Override
+        public void setStatusRes(@NonNull PrintJobId printJobId, @StringRes int status,
+                @NonNull CharSequence appPackageName) throws RemoteException {
+            PrintSpoolerService.this.setStatus(printJobId, status, appPackageName);
+        }
+
+
         public PrintSpoolerService getService() {
             return PrintSpoolerService.this;
         }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 2ae3ec62..99145b7b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -16,6 +16,7 @@
 
 package com.android.printspooler.model;
 
+import android.annotation.NonNull;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.net.Uri;
@@ -57,6 +58,8 @@
 
     private static final boolean DEBUG = false;
 
+    private static final long FORCE_CANCEL_TIMEOUT = 1000; // ms
+
     private static final int STATE_INITIAL = 0;
     private static final int STATE_STARTED = 1;
     private static final int STATE_UPDATING = 2;
@@ -175,6 +178,8 @@
         }
         if (mState == STATE_FAILED) {
             Log.w(LOG_TAG, "Failed before start.");
+        } else if (mState == STATE_DESTROYED) {
+            Log.w(LOG_TAG, "Destroyed before start.");
         } else {
             if (mState != STATE_INITIAL) {
                 throw new IllegalStateException("Cannot start in state:" + stateToString(mState));
@@ -212,7 +217,7 @@
             // cancellation and start over.
             if (mCurrentCommand != null && (mCurrentCommand.isRunning()
                     || mCurrentCommand.isPending())) {
-                mCurrentCommand.cancel();
+                mCurrentCommand.cancel(false);
             }
 
             // Schedule a layout command.
@@ -233,7 +238,7 @@
             // Cancel the current write as a new one is to be scheduled.
             if (mCurrentCommand instanceof WriteCommand
                     && (mCurrentCommand.isPending() || mCurrentCommand.isRunning())) {
-                mCurrentCommand.cancel();
+                mCurrentCommand.cancel(false);
             }
 
             // Schedule a write command.
@@ -264,7 +269,7 @@
         }
         if (mState != STATE_STARTED && mState != STATE_UPDATED
                 && mState != STATE_FAILED && mState != STATE_CANCELING
-                && mState != STATE_CANCELED) {
+                && mState != STATE_CANCELED && mState != STATE_DESTROYED) {
             throw new IllegalStateException("Cannot finish in state:"
                     + stateToString(mState));
         }
@@ -277,9 +282,9 @@
         }
     }
 
-    public void cancel() {
+    public void cancel(boolean force) {
         if (DEBUG) {
-            Log.i(LOG_TAG, "[CALLED] cancel()");
+            Log.i(LOG_TAG, "[CALLED] cancel(" + force + ")");
         }
 
         mNextCommand = null;
@@ -290,7 +295,7 @@
 
         mState = STATE_CANCELING;
 
-        mCurrentCommand.cancel();
+        mCurrentCommand.cancel(force);
     }
 
     public void destroy() {
@@ -441,8 +446,9 @@
         if (mCurrentCommand != null) {
             if (mCurrentCommand.isPending()) {
                 mCurrentCommand.run();
+
+                mState = STATE_UPDATING;
             }
-            mState = STATE_UPDATING;
         } else {
             mState = STATE_UPDATED;
         }
@@ -535,14 +541,17 @@
 
         protected final CommandDoneCallback mDoneCallback;
 
+        private final Handler mHandler;
+
         protected ICancellationSignal mCancellation;
 
         private CharSequence mError;
 
         private int mState = STATE_PENDING;
 
-        public AsyncCommand(IPrintDocumentAdapter adapter, RemotePrintDocumentInfo document,
+        public AsyncCommand(Looper looper, IPrintDocumentAdapter adapter, RemotePrintDocumentInfo document,
                 CommandDoneCallback doneCallback) {
+            mHandler = new AsyncCommandHandler(looper);
             mAdapter = adapter;
             mDocument = document;
             mDoneCallback = doneCallback;
@@ -556,7 +565,29 @@
             return mState == STATE_CANCELED;
         }
 
-        public final void cancel() {
+        /**
+         * If a force cancel is pending, remove it. This is usually called when a command returns
+         * and thereby does not need to be canceled anymore.
+         */
+        protected void removeForceCancel() {
+            if (DEBUG) {
+                if (mHandler.hasMessages(AsyncCommandHandler.MSG_FORCE_CANCEL)) {
+                    Log.i(LOG_TAG, "[FORCE CANCEL] Removed");
+                }
+            }
+
+            mHandler.removeMessages(AsyncCommandHandler.MSG_FORCE_CANCEL);
+        }
+
+        /**
+         * Cancel the current command.
+         *
+         * @param force If set, does not wait for the {@link PrintDocumentAdapter} to cancel. This
+         *              should only be used if this is the last command send to the as otherwise the
+         *              {@link PrintDocumentAdapter adapter} might get commands while it is still
+         *              running the old one.
+         */
+        public final void cancel(boolean force) {
             if (isRunning()) {
                 canceling();
                 if (mCancellation != null) {
@@ -566,14 +597,25 @@
                         Log.w(LOG_TAG, "Error while canceling", re);
                     }
                 }
-            } else if (isCanceling()) {
-                // Nothing to do
-            } else {
-                canceled();
-
-                // Done.
-                mDoneCallback.onDone();
             }
+
+            if (isCanceling()) {
+                if (force) {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "[FORCE CANCEL] queued");
+                    }
+                    mHandler.sendMessageDelayed(
+                            mHandler.obtainMessage(AsyncCommandHandler.MSG_FORCE_CANCEL),
+                            FORCE_CANCEL_TIMEOUT);
+                }
+
+                return;
+            }
+
+            canceled();
+
+            // Done.
+            mDoneCallback.onDone();
         }
 
         protected final void canceling() {
@@ -617,7 +659,7 @@
         }
 
         protected final void failed(CharSequence error) {
-            if (mState != STATE_RUNNING) {
+            if (mState != STATE_RUNNING && mState != STATE_CANCELING) {
                 throw new IllegalStateException("Not running.");
             }
             mState = STATE_FAILED;
@@ -632,6 +674,37 @@
         public CharSequence getError() {
             return mError;
         }
+
+        /**
+         * Handler for the async command.
+         */
+        private class AsyncCommandHandler extends Handler {
+            /** Message indicated the desire for to force cancel a command */
+            final static int MSG_FORCE_CANCEL = 0;
+
+            AsyncCommandHandler(@NonNull Looper looper) {
+                super(looper);
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_FORCE_CANCEL:
+                        if (isCanceling()) {
+                            if (DEBUG) {
+                                Log.i(LOG_TAG, "[FORCE CANCEL] executed");
+                            }
+                            failed("Command did not respond to cancellation in "
+                                    + FORCE_CANCEL_TIMEOUT + " ms");
+
+                            mDoneCallback.onDone();
+                        }
+                        break;
+                    default:
+                        // not reached;
+                }
+            }
+        }
     }
 
     private static final class LayoutCommand extends AsyncCommand {
@@ -646,7 +719,7 @@
         public LayoutCommand(Looper looper, IPrintDocumentAdapter adapter,
                 RemotePrintDocumentInfo document, PrintAttributes oldAttributes,
                 PrintAttributes newAttributes, boolean preview, CommandDoneCallback callback) {
-            super(adapter, document, callback);
+            super(looper, adapter, document, callback);
             mHandler = new LayoutHandler(looper);
             mRemoteResultCallback = new LayoutResultCallback(mHandler);
             mOldAttributes.copyFrom(oldAttributes);
@@ -795,28 +868,60 @@
 
             @Override
             public void handleMessage(Message message) {
-                switch (message.what) {
+                // The command might have been force canceled, see
+                // AsyncCommand.AsyncCommandHandler#handleMessage
+                if (isFailed()) {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "[CALLBACK] on failed layout command");
+                    }
+
+                    return;
+                }
+
+                int sequence;
+                int what = message.what;
+                switch (what) {
+                    case MSG_ON_LAYOUT_FINISHED:
+                        removeForceCancel();
+                        sequence = message.arg2;
+                        break;
+                    case MSG_ON_LAYOUT_FAILED:
+                    case MSG_ON_LAYOUT_CANCELED:
+                        removeForceCancel();
+                        // $FALL-THROUGH - message uses the same format as "started"
+                    case MSG_ON_LAYOUT_STARTED:
+                        // Don't remote force-cancel as command is still running and might need to
+                        // be canceled later
+                        sequence = message.arg1;
+                        break;
+                    default:
+                        // not reached
+                        sequence = -1;
+                }
+
+                // If we are canceling any result is treated as a cancel
+                if (isCanceling() && what != MSG_ON_LAYOUT_STARTED) {
+                    what = MSG_ON_LAYOUT_CANCELED;
+                }
+
+                switch (what) {
                     case MSG_ON_LAYOUT_STARTED: {
                         ICancellationSignal cancellation = (ICancellationSignal) message.obj;
-                        final int sequence = message.arg1;
                         handleOnLayoutStarted(cancellation, sequence);
                     } break;
 
                     case MSG_ON_LAYOUT_FINISHED: {
                         PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
                         final boolean changed = (message.arg1 == 1);
-                        final int sequence = message.arg2;
                         handleOnLayoutFinished(info, changed, sequence);
                     } break;
 
                     case MSG_ON_LAYOUT_FAILED: {
                         CharSequence error = (CharSequence) message.obj;
-                        final int sequence = message.arg1;
                         handleOnLayoutFailed(error, sequence);
                     } break;
 
                     case MSG_ON_LAYOUT_CANCELED: {
-                        final int sequence = message.arg1;
                         handleOnLayoutCanceled(sequence);
                     } break;
                 }
@@ -882,7 +987,7 @@
         public WriteCommand(Context context, Looper looper, IPrintDocumentAdapter adapter,
                 RemotePrintDocumentInfo document, int pageCount, PageRange[] pages,
                 MutexFileProvider fileProvider, CommandDoneCallback callback) {
-            super(adapter, document, callback);
+            super(looper, adapter, document, callback);
             mContext = context;
             mHandler = new WriteHandler(looper);
             mRemoteResultCallback = new WriteResultCallback(mHandler);
@@ -1052,7 +1157,34 @@
 
             @Override
             public void handleMessage(Message message) {
-                switch (message.what) {
+                // The command might have been force canceled, see
+                // AsyncCommand.AsyncCommandHandler#handleMessage
+                if (isFailed()) {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "[CALLBACK] on failed write command");
+                    }
+
+                    return;
+                }
+
+                int what = message.what;
+                switch (what) {
+                    case MSG_ON_WRITE_FINISHED:
+                    case MSG_ON_WRITE_FAILED:
+                    case MSG_ON_WRITE_CANCELED:
+                        removeForceCancel();
+                    case MSG_ON_WRITE_STARTED:
+                        // Don't remote force-cancel as command is still running and might need to
+                        // be canceled later
+                        break;
+                }
+
+                // If we are canceling any result is treated as a cancel
+                if (isCanceling() && what != MSG_ON_WRITE_STARTED) {
+                    what = MSG_ON_WRITE_CANCELED;
+                }
+
+                switch (what) {
                     case MSG_ON_WRITE_STARTED: {
                         ICancellationSignal cancellation = (ICancellationSignal) message.obj;
                         final int sequence = message.arg1;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index 7db2074..0feda92 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -108,62 +108,65 @@
                 try {
                     throwIfNotOpened();
 
-                    PdfRenderer.Page page = mRenderer.openPage(pageIndex);
+                    try (PdfRenderer.Page page = mRenderer.openPage(pageIndex)) {
+                        final int srcWidthPts = page.getWidth();
+                        final int srcHeightPts = page.getHeight();
 
-                    final int srcWidthPts = page.getWidth();
-                    final int srcHeightPts = page.getHeight();
+                        final int dstWidthPts = pointsFromMils(
+                                attributes.getMediaSize().getWidthMils());
+                        final int dstHeightPts = pointsFromMils(
+                                attributes.getMediaSize().getHeightMils());
 
-                    final int dstWidthPts = pointsFromMils(
-                            attributes.getMediaSize().getWidthMils());
-                    final int dstHeightPts = pointsFromMils(
-                            attributes.getMediaSize().getHeightMils());
+                        final boolean scaleContent = mRenderer.shouldScaleForPrinting();
+                        final boolean contentLandscape = !attributes.getMediaSize().isPortrait();
 
-                    final boolean scaleContent = mRenderer.shouldScaleForPrinting();
-                    final boolean contentLandscape = !attributes.getMediaSize().isPortrait();
+                        final float displayScale;
+                        Matrix matrix = new Matrix();
 
-                    final float displayScale;
-                    Matrix matrix = new Matrix();
-
-                    if (scaleContent) {
-                        displayScale = Math.min((float) bitmapWidth / srcWidthPts,
-                                (float) bitmapHeight / srcHeightPts);
-                    } else {
-                        if (contentLandscape) {
-                            displayScale = (float) bitmapHeight / dstHeightPts;
+                        if (scaleContent) {
+                            displayScale = Math.min((float) bitmapWidth / srcWidthPts,
+                                    (float) bitmapHeight / srcHeightPts);
                         } else {
-                            displayScale = (float) bitmapWidth / dstWidthPts;
+                            if (contentLandscape) {
+                                displayScale = (float) bitmapHeight / dstHeightPts;
+                            } else {
+                                displayScale = (float) bitmapWidth / dstWidthPts;
+                            }
                         }
+                        matrix.postScale(displayScale, displayScale);
+
+                        Configuration configuration = PdfManipulationService.this.getResources()
+                                .getConfiguration();
+                        if (configuration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+                            matrix.postTranslate(bitmapWidth - srcWidthPts * displayScale, 0);
+                        }
+
+                        Margins minMargins = attributes.getMinMargins();
+                        final int paddingLeftPts = pointsFromMils(minMargins.getLeftMils());
+                        final int paddingTopPts = pointsFromMils(minMargins.getTopMils());
+                        final int paddingRightPts = pointsFromMils(minMargins.getRightMils());
+                        final int paddingBottomPts = pointsFromMils(minMargins.getBottomMils());
+
+                        Rect clip = new Rect();
+                        clip.left = (int) (paddingLeftPts * displayScale);
+                        clip.top = (int) (paddingTopPts * displayScale);
+                        clip.right = (int) (bitmapWidth - paddingRightPts * displayScale);
+                        clip.bottom = (int) (bitmapHeight - paddingBottomPts * displayScale);
+
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "Rendering page:" + pageIndex);
+                        }
+
+                        Bitmap bitmap = getBitmapForSize(bitmapWidth, bitmapHeight);
+                        page.render(bitmap, clip, matrix, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
+
+                        BitmapSerializeUtils.writeBitmapPixels(bitmap, destination);
                     }
-                    matrix.postScale(displayScale, displayScale);
+                } catch (Throwable e) {
+                    Log.e(LOG_TAG, "Cannot render page", e);
 
-                    Configuration configuration = PdfManipulationService.this.getResources()
-                            .getConfiguration();
-                    if (configuration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
-                        matrix.postTranslate(bitmapWidth - srcWidthPts * displayScale, 0);
-                    }
-
-                    Margins minMargins = attributes.getMinMargins();
-                    final int paddingLeftPts = pointsFromMils(minMargins.getLeftMils());
-                    final int paddingTopPts = pointsFromMils(minMargins.getTopMils());
-                    final int paddingRightPts = pointsFromMils(minMargins.getRightMils());
-                    final int paddingBottomPts = pointsFromMils(minMargins.getBottomMils());
-
-                    Rect clip = new Rect();
-                    clip.left = (int) (paddingLeftPts * displayScale);
-                    clip.top = (int) (paddingTopPts * displayScale);
-                    clip.right = (int) (bitmapWidth - paddingRightPts * displayScale);
-                    clip.bottom = (int) (bitmapHeight - paddingBottomPts * displayScale);
-
-                    if (DEBUG) {
-                        Log.i(LOG_TAG, "Rendering page:" + pageIndex);
-                    }
-
-                    Bitmap bitmap = getBitmapForSize(bitmapWidth, bitmapHeight);
-                    page.render(bitmap, clip, matrix, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
-
-                    page.close();
-
-                    BitmapSerializeUtils.writeBitmapPixels(bitmap, destination);
+                    // The error is propagated to the caller when it tries to read the bitmap and
+                    // the pipe is closed prematurely
                 } finally {
                     IoUtils.closeQuietly(destination);
                 }
@@ -241,9 +244,20 @@
 
                 ranges = PageRangeUtils.normalize(ranges);
 
+                int lastPageIdx = mEditor.getPageCount() - 1;
+
                 final int rangeCount = ranges.length;
                 for (int i = rangeCount - 1; i >= 0; i--) {
                     PageRange range = ranges[i];
+
+                    // Ignore removal of pages that are outside the document
+                    if (range.getEnd() > lastPageIdx) {
+                        if (range.getStart() > lastPageIdx) {
+                            continue;
+                        }
+                        range = new PageRange(range.getStart(), lastPageIdx);
+                    }
+
                     for (int j = range.getEnd(); j >= range.getStart(); j--) {
                         mEditor.removePage(j);
                     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
new file mode 100644
index 0000000..42ef10e
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -0,0 +1,766 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.ui;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ListActivity;
+import android.app.LoaderManager;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.Loader;
+import android.database.DataSetObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
+import android.print.PrintServiceRecommendationsLoader;
+import android.print.PrintServicesLoader;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Adapter;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.printspooler.R;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * This is an activity for adding a printer or. It consists of a list fed from three adapters:
+ * <ul>
+ *     <li>{@link #mEnabledServicesAdapter} for all enabled services. If a service has an {@link
+ *         PrintServiceInfo#getAddPrintersActivityName() add printer activity} this is started
+ *         when the item is clicked.</li>
+ *     <li>{@link #mDisabledServicesAdapter} for all disabled services. Once clicked the settings page
+ *         for this service is opened.</li>
+ *     <li>{@link #mRecommendedServicesAdapter} for a link to all services. If this item is clicked
+ *         the market app is opened to show all print services.</li>
+ * </ul>
+ */
+public class AddPrinterActivity extends ListActivity implements AdapterView.OnItemClickListener {
+    private static final String LOG_TAG = "AddPrinterActivity";
+
+    /** Ids for the loaders */
+    private static final int LOADER_ID_ENABLED_SERVICES = 1;
+    private static final int LOADER_ID_DISABLED_SERVICES = 2;
+    private static final int LOADER_ID_RECOMMENDED_SERVICES = 3;
+    private static final int LOADER_ID_ALL_SERVICES = 4;
+
+    /**
+     * The enabled services list. This is filled from the {@link #LOADER_ID_ENABLED_SERVICES}
+     * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
+     */
+    private EnabledServicesAdapter mEnabledServicesAdapter;
+
+    /**
+     * The disabled services list. This is filled from the {@link #LOADER_ID_DISABLED_SERVICES}
+     * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
+     */
+    private DisabledServicesAdapter mDisabledServicesAdapter;
+
+    /**
+     * The recommended services list. This is filled from the
+     * {@link #LOADER_ID_RECOMMENDED_SERVICES} loader in
+     * {@link PrintServicePrintServiceRecommendationLoaderCallbacks#onLoadFinished}.
+     */
+    private RecommendedServicesAdapter mRecommendedServicesAdapter;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.add_printer_activity);
+
+        mEnabledServicesAdapter = new EnabledServicesAdapter();
+        mDisabledServicesAdapter = new DisabledServicesAdapter();
+        mRecommendedServicesAdapter = new RecommendedServicesAdapter();
+
+        ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
+        adapterList.add(mEnabledServicesAdapter);
+        adapterList.add(mRecommendedServicesAdapter);
+        adapterList.add(mDisabledServicesAdapter);
+
+        setListAdapter(new CombinedAdapter(adapterList));
+
+        getListView().setOnItemClickListener(this);
+
+        PrintServiceInfoLoaderCallbacks printServiceLoaderCallbacks =
+                new PrintServiceInfoLoaderCallbacks();
+
+        getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks);
+        getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks);
+        getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
+                new PrintServicePrintServiceRecommendationLoaderCallbacks());
+        getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks);
+    }
+
+    /**
+     * Callbacks for the loaders operating on list of {@link PrintServiceInfo print service infos}.
+     */
+    private class PrintServiceInfoLoaderCallbacks implements
+            LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
+        @Override
+        public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+            switch (id) {
+                case LOADER_ID_ENABLED_SERVICES:
+                    return new PrintServicesLoader(
+                            (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                            AddPrinterActivity.this, PrintManager.ENABLED_SERVICES);
+                case LOADER_ID_DISABLED_SERVICES:
+                    return new PrintServicesLoader(
+                            (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                            AddPrinterActivity.this, PrintManager.DISABLED_SERVICES);
+                case LOADER_ID_ALL_SERVICES:
+                    return new PrintServicesLoader(
+                            (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                            AddPrinterActivity.this, PrintManager.ALL_SERVICES);
+                default:
+                    // not reached
+                    return null;
+            }
+        }
+
+
+        @Override
+        public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+                List<PrintServiceInfo> data) {
+            switch (loader.getId()) {
+                case LOADER_ID_ENABLED_SERVICES:
+                    mEnabledServicesAdapter.updateData(data);
+                    break;
+                case LOADER_ID_DISABLED_SERVICES:
+                    mDisabledServicesAdapter.updateData(data);
+                    break;
+                case LOADER_ID_ALL_SERVICES:
+                    mRecommendedServicesAdapter.updateInstalledServices(data);
+                default:
+                    // not reached
+            }
+        }
+
+        @Override
+        public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+            if (!isFinishing()) {
+                switch (loader.getId()) {
+                    case LOADER_ID_ENABLED_SERVICES:
+                        mEnabledServicesAdapter.updateData(null);
+                        break;
+                    case LOADER_ID_DISABLED_SERVICES:
+                        mDisabledServicesAdapter.updateData(null);
+                        break;
+                    case LOADER_ID_ALL_SERVICES:
+                        mRecommendedServicesAdapter.updateInstalledServices(null);
+                        break;
+                    default:
+                        // not reached
+                }
+            }
+        }
+    }
+
+    /**
+     * Callbacks for the loaders operating on list of {@link RecommendationInfo print service
+     * recommendations}.
+     */
+    private class PrintServicePrintServiceRecommendationLoaderCallbacks implements
+            LoaderManager.LoaderCallbacks<List<RecommendationInfo>> {
+        @Override
+        public Loader<List<RecommendationInfo>> onCreateLoader(int id, Bundle args) {
+            return new PrintServiceRecommendationsLoader(
+                    (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                    AddPrinterActivity.this);
+        }
+
+
+        @Override
+        public void onLoadFinished(Loader<List<RecommendationInfo>> loader,
+                List<RecommendationInfo> data) {
+            mRecommendedServicesAdapter.updateRecommendations(data);
+        }
+
+        @Override
+        public void onLoaderReset(Loader<List<RecommendationInfo>> loader) {
+            if (!isFinishing()) {
+                mRecommendedServicesAdapter.updateRecommendations(null);
+            }
+        }
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        ((ActionAdapter) getListAdapter()).performAction(position);
+    }
+
+    /**
+     * Marks an adapter that can can perform an action for a position in it's list.
+     */
+    private abstract class ActionAdapter extends BaseAdapter {
+        /**
+         * Perform the action for a position in the list.
+         *
+         * @param position The position of the item
+         */
+        abstract void performAction(@IntRange(from = 0) int position);
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+    }
+
+    /**
+     * An adapter presenting multiple sub adapters as a single combined adapter.
+     */
+    private class CombinedAdapter extends ActionAdapter {
+        /** The adapters to combine */
+        private final @NonNull ArrayList<ActionAdapter> mAdapters;
+
+        /**
+         * Create a combined adapter.
+         *
+         * @param adapters the list of adapters to combine
+         */
+        CombinedAdapter(@NonNull ArrayList<ActionAdapter> adapters) {
+            mAdapters = adapters;
+
+            final int numAdapters = mAdapters.size();
+            for (int i = 0; i < numAdapters; i++) {
+                mAdapters.get(i).registerDataSetObserver(new DataSetObserver() {
+                    @Override
+                    public void onChanged() {
+                        notifyDataSetChanged();
+                    }
+
+                    @Override
+                    public void onInvalidated() {
+                        notifyDataSetChanged();
+                    }
+                });
+            }
+        }
+
+        @Override
+        public int getCount() {
+            int totalCount = 0;
+
+            final int numAdapters = mAdapters.size();
+            for (int i = 0; i < numAdapters; i++) {
+                totalCount += mAdapters.get(i).getCount();
+            }
+
+            return totalCount;
+        }
+
+        /**
+         * Find the sub adapter and the position in the sub-adapter the position in the combined
+         * adapter refers to.
+         *
+         * @param position The position in the combined adapter
+         *
+         * @return The pair of adapter and position in sub adapter
+         */
+        private @NonNull Pair<ActionAdapter, Integer> getSubAdapter(int position) {
+            final int numAdapters = mAdapters.size();
+            for (int i = 0; i < numAdapters; i++) {
+                ActionAdapter adapter = mAdapters.get(i);
+
+                if (position < adapter.getCount()) {
+                    return new Pair<>(adapter, position);
+                } else {
+                    position -= adapter.getCount();
+                }
+            }
+
+            throw new IllegalArgumentException("Invalid position");
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            int numLowerViewTypes = 0;
+
+            final int numAdapters = mAdapters.size();
+            for (int i = 0; i < numAdapters; i++) {
+                Adapter adapter = mAdapters.get(i);
+
+                if (position < adapter.getCount()) {
+                    return numLowerViewTypes + adapter.getItemViewType(position);
+                } else {
+                    numLowerViewTypes += adapter.getViewTypeCount();
+                    position -= adapter.getCount();
+                }
+            }
+
+            throw new IllegalArgumentException("Invalid position");
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            int totalViewCount = 0;
+
+            final int numAdapters = mAdapters.size();
+            for (int i = 0; i < numAdapters; i++) {
+                totalViewCount += mAdapters.get(i).getViewTypeCount();
+            }
+
+            return totalViewCount;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+            return realPosition.first.getView(realPosition.second, convertView, parent);
+        }
+
+        @Override
+        public Object getItem(int position) {
+            Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+            return realPosition.first.getItem(realPosition.second);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+            return realPosition.first.isEnabled(realPosition.second);
+        }
+
+        @Override
+        public void performAction(@IntRange(from = 0) int position) {
+            Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+            realPosition.first.performAction(realPosition.second);
+        }
+    }
+    
+    /**
+     * Superclass for all adapters that just display a list of {@link PrintServiceInfo}.
+     */
+    private abstract class PrintServiceInfoAdapter extends ActionAdapter {
+        /**
+         * Raw data of the list.
+         *
+         * @see #updateData(List)
+         */
+        private @NonNull List<PrintServiceInfo> mServices;
+
+        /**
+         * Create a new adapter.
+         */
+        PrintServiceInfoAdapter() {
+            mServices = Collections.emptyList();
+        }
+
+        /**
+         * Update the data.
+         *
+         * @param services The new raw data.
+         */
+        void updateData(@Nullable List<PrintServiceInfo> services) {
+            if (services == null || services.isEmpty()) {
+                mServices = Collections.emptyList();
+            } else {
+                mServices = services;
+            }
+
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 2;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            if (position == 0) {
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+
+        @Override
+        public int getCount() {
+            if (mServices.isEmpty()) {
+                return 0;
+            } else {
+                return mServices.size() + 1;
+            }
+        }
+
+        @Override
+        public Object getItem(int position) {
+            if (position == 0) {
+                return null;
+            } else {
+                return mServices.get(position - 1);
+            }
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return position != 0;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+    }
+
+    /**
+     * Adapter for the enabled services.
+     */
+    private class EnabledServicesAdapter extends PrintServiceInfoAdapter {
+        @Override
+        public void performAction(@IntRange(from = 0) int position) {
+            PrintServiceInfo service = (PrintServiceInfo) getItem(position);
+            String addPrinterActivityName = service.getAddPrintersActivityName();
+
+            if (!TextUtils.isEmpty(addPrinterActivityName)) {
+                Intent intent = new Intent(Intent.ACTION_MAIN);
+                intent.setComponent(new ComponentName(service.getComponentName().getPackageName(),
+                        addPrinterActivityName));
+
+                try {
+                    startActivity(intent);
+                } catch (ActivityNotFoundException e) {
+                    Log.e(LOG_TAG, "Cannot start add printers activity", e);
+                }
+            }
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (position == 0) {
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
+                            parent, false);
+                }
+
+                ((TextView) convertView.findViewById(R.id.text))
+                        .setText(R.string.enabled_services_title);
+
+                return convertView;
+            }
+
+            if (convertView == null) {
+                convertView = getLayoutInflater().inflate(R.layout.enabled_print_services_list_item,
+                        parent, false);
+            }
+
+            PrintServiceInfo service = (PrintServiceInfo) getItem(position);
+
+            TextView title = (TextView) convertView.findViewById(R.id.title);
+            ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
+            TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle);
+
+            title.setText(service.getResolveInfo().loadLabel(getPackageManager()));
+            icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager()));
+
+            if (TextUtils.isEmpty(service.getAddPrintersActivityName())) {
+                subtitle.setText(getString(R.string.cannot_add_printer));
+            } else {
+                subtitle.setText(getString(R.string.select_to_add_printers));
+            }
+
+            return convertView;
+        }
+    }
+
+    /**
+     * Adapter for the disabled services.
+     */
+    private class DisabledServicesAdapter extends PrintServiceInfoAdapter {
+        @Override
+        public void performAction(@IntRange(from = 0) int position) {
+            ((PrintManager) getSystemService(Context.PRINT_SERVICE)).setPrintServiceEnabled(
+                    ((PrintServiceInfo) getItem(position)).getComponentName(), true);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (position == 0) {
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
+                            parent, false);
+                }
+
+                ((TextView) convertView.findViewById(R.id.text))
+                        .setText(R.string.disabled_services_title);
+
+                return convertView;
+            }
+
+            if (convertView == null) {
+                convertView = getLayoutInflater().inflate(
+                        R.layout.disabled_print_services_list_item, parent, false);
+            }
+
+            PrintServiceInfo service = (PrintServiceInfo) getItem(position);
+
+            TextView title = (TextView) convertView.findViewById(R.id.title);
+            ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
+
+            title.setText(service.getResolveInfo().loadLabel(getPackageManager()));
+            icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager()));
+
+            return convertView;
+        }
+    }
+
+    /**
+     * Adapter for the recommended services.
+     */
+    private class RecommendedServicesAdapter extends ActionAdapter {
+        /** Package names of all installed print services */
+        private @NonNull final ArraySet<String> mInstalledServices;
+
+        /** All print service recommendations */
+        private @Nullable List<RecommendationInfo> mRecommendations;
+
+        /**
+         * Sorted print service recommendations for services that are not installed
+         *
+         * @see #filterRecommendations
+         */
+        private @Nullable List<RecommendationInfo> mFilteredRecommendations;
+
+        /**
+         * Create a new adapter.
+         */
+        private RecommendedServicesAdapter() {
+            mInstalledServices = new ArraySet<>();
+        }
+
+        @Override
+        public int getCount() {
+            if (mFilteredRecommendations == null) {
+                return 2;
+            } else {
+                return mFilteredRecommendations.size() + 2;
+            }
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 3;
+        }
+
+        /**
+         * @return The position the all services link is at.
+         */
+        private int getAllServicesPos() {
+            return getCount() - 1;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            if (position == 0) {
+                return 0;
+            } else if (getAllServicesPos() == position) {
+                return 1;
+            } else {
+                return 2;
+            }
+        }
+
+        @Override
+        public Object getItem(int position) {
+            if (position == 0 || position == getAllServicesPos()) {
+                return null;
+            } else {
+                return mFilteredRecommendations.get(position - 1);
+            }
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (position == 0) {
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
+                            parent, false);
+                }
+
+                ((TextView) convertView.findViewById(R.id.text))
+                        .setText(R.string.recommended_services_title);
+
+                return convertView;
+            } else if (position == getAllServicesPos()) {
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item,
+                            parent, false);
+                }
+            } else {
+                RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
+
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(
+                            R.layout.print_service_recommendations_list_item, parent, false);
+                }
+
+                ((TextView) convertView.findViewById(R.id.title)).setText(recommendation.getName());
+
+                ((TextView) convertView.findViewById(R.id.subtitle)).setText(getResources()
+                        .getQuantityString(R.plurals.print_services_recommendation_subtitle,
+                                recommendation.getNumDiscoveredPrinters(),
+                                recommendation.getNumDiscoveredPrinters()));
+
+                return convertView;
+            }
+
+            return convertView;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return position != 0;
+        }
+
+        @Override
+        public void performAction(@IntRange(from = 0) int position) {
+            if (position == getAllServicesPos()) {
+                String searchUri = Settings.Secure
+                        .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI);
+
+                if (searchUri != null) {
+                    try {
+                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
+                    } catch (ActivityNotFoundException e) {
+                        Log.e(LOG_TAG, "Cannot start market", e);
+                    }
+                }
+            } else {
+                RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
+
+                try {
+                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(
+                            R.string.uri_package_details, recommendation.getPackageName()))));
+                } catch (ActivityNotFoundException e) {
+                    Log.e(LOG_TAG, "Cannot start market", e);
+                }
+            }
+        }
+
+        /**
+         * Filter recommended services.
+         */
+        private void filterRecommendations() {
+            if (mRecommendations == null) {
+                mFilteredRecommendations = null;
+            } else {
+                mFilteredRecommendations = new ArrayList<>();
+
+                // Filter out recommendations for already installed services
+                final int numRecommendations = mRecommendations.size();
+                for (int i = 0; i < numRecommendations; i++) {
+                    RecommendationInfo recommendation = mRecommendations.get(i);
+
+                    if (!mInstalledServices.contains(recommendation.getPackageName())) {
+                        mFilteredRecommendations.add(recommendation);
+                    }
+                }
+            }
+
+            notifyDataSetChanged();
+        }
+
+        /**
+         * Update the installed print services.
+         *
+         * @param services The new set of services
+         */
+        public void updateInstalledServices(List<PrintServiceInfo> services) {
+            mInstalledServices.clear();
+
+            final int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                mInstalledServices.add(services.get(i).getComponentName().getPackageName());
+            }
+
+            filterRecommendations();
+        }
+
+        /**
+         * Update the recommended print services.
+         *
+         * @param recommendations The new set of recommendations
+         */
+        public void updateRecommendations(List<RecommendationInfo> recommendations) {
+            if (recommendations != null) {
+                final Collator collator = Collator.getInstance();
+
+                // Sort recommendations (early conditions are more important)
+                // - higher number of discovered printers first
+                // - single vendor services first
+                // - alphabetically
+                Collections.sort(recommendations,
+                        new Comparator<RecommendationInfo>() {
+                            @Override public int compare(RecommendationInfo o1,
+                                    RecommendationInfo o2) {
+                                if (o1.getNumDiscoveredPrinters() !=
+                                        o2.getNumDiscoveredPrinters()) {
+                                    return o2.getNumDiscoveredPrinters() -
+                                            o1.getNumDiscoveredPrinters();
+                                } else if (o1.recommendsMultiVendorService()
+                                        != o2.recommendsMultiVendorService()) {
+                                    if (o1.recommendsMultiVendorService()) {
+                                        return 1;
+                                    } else {
+                                        return -1;
+                                    }
+                                } else {
+                                    return collator.compare(o1.getName().toString(),
+                                            o2.getName().toString());
+                                }
+                            }
+                        });
+            }
+
+            mRecommendations = recommendations;
+
+            filterRecommendations();
+        }
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 46a2098..7935440 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -16,7 +16,10 @@
 
 package com.android.printspooler.ui;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.LoaderManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Loader;
@@ -28,9 +31,11 @@
 import android.location.LocationRequest;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
 import android.print.PrintManager;
+import android.print.PrintServicesLoader;
 import android.print.PrinterDiscoverySession;
 import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
 import android.print.PrinterId;
@@ -127,11 +132,11 @@
         }
     }
 
-    public FusedPrintersProvider(Context context) {
-        super(context);
+    public FusedPrintersProvider(Activity activity, int internalLoaderId) {
+        super(activity);
         mLocationLock = new Object();
-        mPersistenceManager = new PersistenceManager(context);
-        mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+        mPersistenceManager = new PersistenceManager(activity, internalLoaderId);
+        mLocationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
     }
 
     public void addHistoricalPrinter(PrinterInfo printer) {
@@ -262,9 +267,12 @@
 
         // The contract is that if we already have a valid,
         // result the we have to deliver it immediately.
-        if (!mPrinters.isEmpty()) {
-            deliverResult(new ArrayList<>(mPrinters));
-        }
+        (new Handler(Looper.getMainLooper())).post(new Runnable() {
+            @Override public void run() {
+                deliverResult(new ArrayList<>(mPrinters));
+            }
+        });
+
         // Always load the data to ensure discovery period is
         // started and to make sure obsolete printers are updated.
         onForceLoad();
@@ -383,7 +391,6 @@
         mPrinters.clear();
         if (mDiscoverySession != null) {
             mDiscoverySession.destroy();
-            mDiscoverySession = null;
         }
     }
 
@@ -499,7 +506,8 @@
         updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters, getCurrentLocation());
     }
 
-    private final class PersistenceManager {
+    private final class PersistenceManager implements
+            LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
         private static final String PERSIST_FILE_NAME = "printer_history.xml";
 
         private static final String TAG_PRINTERS = "printers";
@@ -520,6 +528,15 @@
 
         private final AtomicFile mStatePersistFile;
 
+        /**
+         * Whether the enabled print services have been updated since last time the history was
+         * read.
+         */
+        private boolean mAreEnabledServicesUpdated;
+
+        /** The enabled services read when they were last updated */
+        private @NonNull List<PrintServiceInfo> mEnabledServices;
+
         private List<Pair<PrinterInfo, Location>> mHistoricalPrinters = new ArrayList<>();
 
         private boolean mReadHistoryCompleted;
@@ -528,9 +545,52 @@
 
         private volatile long mLastReadHistoryTimestamp;
 
-        private PersistenceManager(Context context) {
-            mStatePersistFile = new AtomicFile(new File(context.getFilesDir(),
+        private PersistenceManager(final Activity activity, final int internalLoaderId) {
+            mStatePersistFile = new AtomicFile(new File(activity.getFilesDir(),
                     PERSIST_FILE_NAME));
+
+            // Initialize enabled services to make sure they are set are the read task might be done
+            // before the loader updated the services the first time.
+            mEnabledServices = ((PrintManager) activity
+                    .getSystemService(Context.PRINT_SERVICE))
+                    .getPrintServices(PrintManager.ENABLED_SERVICES);
+
+            mAreEnabledServicesUpdated = true;
+
+            // Cannot start a loader while starting another, hence delay this loader
+            (new Handler(activity.getMainLooper())).post(new Runnable() {
+                @Override
+                public void run() {
+                    activity.getLoaderManager().initLoader(internalLoaderId, null,
+                            PersistenceManager.this);
+                }
+            });
+        }
+
+
+        @Override
+        public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+            return new PrintServicesLoader(
+                    (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE),
+                    getContext(), PrintManager.ENABLED_SERVICES);
+        }
+
+        @Override
+        public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+                List<PrintServiceInfo> services) {
+            mAreEnabledServicesUpdated = true;
+            mEnabledServices = services;
+
+            // Ask the fused printer provider to reload which will cause the persistence manager to
+            // reload the history and reconsider the enabled services.
+            if (isStarted()) {
+                forceLoad();
+            }
+        }
+
+        @Override
+        public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+            // no data is cached
         }
 
         public boolean isReadHistoryInProgress() {
@@ -644,7 +704,8 @@
         }
 
         public boolean isHistoryChanged() {
-            return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
+            return mAreEnabledServicesUpdated ||
+                    mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
         }
 
         /**
@@ -738,19 +799,15 @@
                 }
 
                 // Ignore printer records whose target services are not enabled.
-                PrintManager printManager = (PrintManager) getContext()
-                        .getSystemService(Context.PRINT_SERVICE);
-                List<PrintServiceInfo> services = printManager
-                        .getEnabledPrintServices();
-
                 Set<ComponentName> enabledComponents = new ArraySet<>();
-                final int installedServiceCount = services.size();
+                final int installedServiceCount = mEnabledServices.size();
                 for (int i = 0; i < installedServiceCount; i++) {
-                    ServiceInfo serviceInfo = services.get(i).getResolveInfo().serviceInfo;
+                    ServiceInfo serviceInfo = mEnabledServices.get(i).getResolveInfo().serviceInfo;
                     ComponentName componentName = new ComponentName(
                             serviceInfo.packageName, serviceInfo.name);
                     enabledComponents.add(componentName);
                 }
+                mAreEnabledServicesUpdated = false;
 
                 final int printerCount = printers.size();
                 for (int i = printerCount - 1; i >= 0; i--) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 606f4eb..c1a3f86 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -20,6 +20,8 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.print.PageRange;
 import android.print.PrintAttributes.MediaSize;
@@ -91,6 +93,7 @@
     private PageRange[] mSelectedPages;
 
     private BitmapDrawable mEmptyState;
+    private BitmapDrawable mErrorState;
 
     private int mDocumentPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
     private int mSelectedPageCount;
@@ -203,6 +206,7 @@
             int documentPageCount, MediaSize mediaSize, Margins minMargins) {
         boolean documentChanged = false;
         boolean updatePreviewAreaAndPageSize = false;
+        boolean clearSelectedPages = false;
 
         // If the app does not tell how many pages are in the document we cannot
         // optimize and ask for all pages whose count we get from the renderer.
@@ -222,30 +226,41 @@
             }
         }
 
-        if (!Arrays.equals(mSelectedPages, selectedPages)) {
-            mSelectedPages = selectedPages;
-            mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
-                    mSelectedPages, documentPageCount);
-            setConfirmedPages(mSelectedPages, documentPageCount);
-            updatePreviewAreaAndPageSize = true;
-            documentChanged = true;
-        }
-
         if (mDocumentPageCount != documentPageCount) {
             mDocumentPageCount = documentPageCount;
             documentChanged = true;
+            clearSelectedPages = true;
         }
 
         if (mMediaSize == null || !mMediaSize.equals(mediaSize)) {
             mMediaSize = mediaSize;
             updatePreviewAreaAndPageSize = true;
             documentChanged = true;
+
+            clearSelectedPages = true;
         }
 
         if (mMinMargins == null || !mMinMargins.equals(minMargins)) {
             mMinMargins = minMargins;
             updatePreviewAreaAndPageSize = true;
             documentChanged = true;
+
+            clearSelectedPages = true;
+        }
+
+        if (clearSelectedPages) {
+            mSelectedPages = PageRange.ALL_PAGES_ARRAY;
+            mSelectedPageCount = documentPageCount;
+            setConfirmedPages(mSelectedPages, documentPageCount);
+            updatePreviewAreaAndPageSize = true;
+            documentChanged = true;
+        } else if (!Arrays.equals(mSelectedPages, selectedPages)) {
+            mSelectedPages = selectedPages;
+            mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
+                    mSelectedPages, documentPageCount);
+            setConfirmedPages(mSelectedPages, documentPageCount);
+            updatePreviewAreaAndPageSize = true;
+            documentChanged = true;
         }
 
         // If *all pages* is selected we need to convert that to absolute
@@ -327,7 +342,7 @@
         } else {
             onSelectedPageNotInFile(pageInDocument);
         }
-        content.init(provider, mEmptyState, mMediaSize, mMinMargins);
+        content.init(provider, mEmptyState, mErrorState, mMediaSize, mMinMargins);
 
         if (mConfirmedPagesInDocument.indexOfKey(pageInDocument) >= 0) {
             page.setSelected(true, false);
@@ -446,19 +461,35 @@
         // Now update the empty state drawable, as it depends on the page
         // size and is reused for all views for better performance.
         LayoutInflater inflater = LayoutInflater.from(mContext);
-        View content = inflater.inflate(R.layout.preview_page_loading, null, false);
-        content.measure(MeasureSpec.makeMeasureSpec(mPageContentWidth, MeasureSpec.EXACTLY),
+        View loadingContent = inflater.inflate(R.layout.preview_page_loading, null, false);
+        loadingContent.measure(MeasureSpec.makeMeasureSpec(mPageContentWidth, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(mPageContentHeight, MeasureSpec.EXACTLY));
-        content.layout(0, 0, content.getMeasuredWidth(), content.getMeasuredHeight());
+        loadingContent.layout(0, 0, loadingContent.getMeasuredWidth(),
+                loadingContent.getMeasuredHeight());
 
-        Bitmap bitmap = Bitmap.createBitmap(mPageContentWidth, mPageContentHeight,
+        Bitmap loadingBitmap = Bitmap.createBitmap(mPageContentWidth, mPageContentHeight,
                 Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        content.draw(canvas);
+        loadingContent.draw(new Canvas(loadingBitmap));
 
         // Do not recycle the old bitmap if such as it may be set as an empty
         // state to any of the page views. Just let the GC take care of it.
-        mEmptyState = new BitmapDrawable(mContext.getResources(), bitmap);
+        mEmptyState = new BitmapDrawable(mContext.getResources(), loadingBitmap);
+
+        // Now update the empty state drawable, as it depends on the page
+        // size and is reused for all views for better performance.
+        View errorContent = inflater.inflate(R.layout.preview_page_error, null, false);
+        errorContent.measure(MeasureSpec.makeMeasureSpec(mPageContentWidth, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(mPageContentHeight, MeasureSpec.EXACTLY));
+        errorContent.layout(0, 0, errorContent.getMeasuredWidth(),
+                errorContent.getMeasuredHeight());
+
+        Bitmap errorBitmap = Bitmap.createBitmap(mPageContentWidth, mPageContentHeight,
+                Bitmap.Config.ARGB_8888);
+        errorContent.draw(new Canvas(errorBitmap));
+
+        // Do not recycle the old bitmap if such as it may be set as an error
+        // state to any of the page views. Just let the GC take care of it.
+        mErrorState = new BitmapDrawable(mContext.getResources(), errorBitmap);
     }
 
     private PageRange[] computeSelectedPages() {
@@ -570,7 +601,14 @@
             if (DEBUG) {
                 Log.i(LOG_TAG, "Requesting pages: " + Arrays.toString(mRequestedPages));
             }
-            mCallbacks.onRequestContentUpdate();
+
+            // This call might come from a recylerview that is currently updating. Hence delay to
+            // after the update
+            (new Handler(Looper.getMainLooper())).post(new Runnable() {
+                @Override public void run() {
+                    mCallbacks.onRequestContentUpdate();
+                }
+            });
         }
     }
 
@@ -733,7 +771,7 @@
     private void recyclePageView(PageContentView page, int pageIndexInAdapter) {
         PageContentProvider provider = page.getPageContentProvider();
         if (provider != null) {
-            page.init(null, mEmptyState, mMediaSize, mMinMargins);
+            page.init(null, mEmptyState, mErrorState, mMediaSize, mMinMargins);
             mPageContentRepository.releasePageContentProvider(provider);
         }
         mBoundPagesInAdapter.remove(pageIndexInAdapter);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 08cd0b6..e7aebdd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -22,11 +22,13 @@
 import android.app.DialogFragment;
 import android.app.Fragment;
 import android.app.FragmentTransaction;
+import android.app.LoaderManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.Loader;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -51,14 +53,15 @@
 import android.print.PrintDocumentInfo;
 import android.print.PrintJobInfo;
 import android.print.PrintManager;
+import android.print.PrintServicesLoader;
 import android.print.PrinterCapabilitiesInfo;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintService;
+import android.printservice.PrintServiceInfo;
 import android.provider.DocumentsContract;
 import android.text.Editable;
 import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
 import android.text.TextWatcher;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -94,7 +97,6 @@
 import com.android.printspooler.util.MediaSizeUtils;
 import com.android.printspooler.util.MediaSizeUtils.MediaSizeComparator;
 import com.android.printspooler.util.PageRangeUtils;
-import com.android.printspooler.util.PrintOptionUtils;
 import com.android.printspooler.widget.PrintContentView;
 import com.android.printspooler.widget.PrintContentView.OptionsStateChangeListener;
 import com.android.printspooler.widget.PrintContentView.OptionsStateController;
@@ -113,22 +115,24 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Objects;
 
 public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
         PrintErrorFragment.OnActionListener, PageAdapter.ContentCallbacks,
-        OptionsStateChangeListener, OptionsStateController {
+        OptionsStateChangeListener, OptionsStateController,
+        LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
     private static final String LOG_TAG = "PrintActivity";
 
     private static final boolean DEBUG = false;
 
-    public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
-
     private static final String FRAGMENT_TAG = "FRAGMENT_TAG";
 
     private static final String HAS_PRINTED_PREF = "has_printed";
 
+    private static final int LOADER_ID_ENABLED_PRINT_SERVICES = 1;
+    private static final int LOADER_ID_PRINT_REGISTRY = 2;
+    private static final int LOADER_ID_PRINT_REGISTRY_INT = 3;
+
     private static final int ORIENTATION_PORTRAIT = 0;
     private static final int ORIENTATION_LANDSCAPE = 1;
 
@@ -139,7 +143,7 @@
     private static final int DEST_ADAPTER_MAX_ITEM_COUNT = 9;
 
     private static final int DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF = Integer.MAX_VALUE;
-    private static final int DEST_ADAPTER_ITEM_ID_ALL_PRINTERS = Integer.MAX_VALUE - 1;
+    private static final int DEST_ADAPTER_ITEM_ID_MORE = Integer.MAX_VALUE - 1;
 
     private static final int STATE_INITIALIZING = 0;
     private static final int STATE_CONFIGURING = 1;
@@ -158,24 +162,11 @@
     private static final int MIN_COPIES = 1;
     private static final String MIN_COPIES_STRING = String.valueOf(MIN_COPIES);
 
-    private static final Pattern PATTERN_DIGITS = Pattern.compile("[\\d]+");
-
-    private static final Pattern PATTERN_ESCAPE_SPECIAL_CHARS = Pattern.compile(
-            "(?=[]\\[+&|!(){}^\"~*?:\\\\])");
-
-    private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile(
-            "[\\s]*[0-9]+[\\-]?[\\s]*[0-9]*[\\s]*?(([,])"
-                    + "[\\s]*[0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*|[\\s]*)+");
-
-    public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES};
-
     private boolean mIsOptionsUiBound = false;
 
     private final PrinterAvailabilityDetector mPrinterAvailabilityDetector =
             new PrinterAvailabilityDetector();
 
-    private final SimpleStringSplitter mStringCommaSplitter = new SimpleStringSplitter(',');
-
     private final OnFocusChangeListener mSelectAllOnFocusListener = new SelectAllOnFocusListener();
 
     private PrintSpoolerProvider mSpoolerProvider;
@@ -236,6 +227,18 @@
 
     private int mUiState = UI_STATE_PREVIEW;
 
+    /** Observer for changes to the printers */
+    private PrintersObserver mPrintersObserver;
+
+    /** Advances options activity name for current printer */
+    private ComponentName mAdvancedPrintOptionsActivity;
+
+    /** Whether at least one print services is enabled or not */
+    private boolean mArePrintServicesEnabled;
+
+    /** Is doFinish() already in progress */
+    private boolean mIsFinishing;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -275,6 +278,8 @@
                 }
             }
         });
+
+        getLoaderManager().initLoader(LOADER_ID_ENABLED_PRINT_SERVICES, null, this);
     }
 
     private void onConnectedToPrintSpooler(final IBinder documentAdapter) {
@@ -289,7 +294,7 @@
             public void run() {
                 onPrinterRegistryReady(documentAdapter);
             }
-        });
+        }, LOADER_ID_PRINT_REGISTRY, LOADER_ID_PRINT_REGISTRY_INT);
     }
 
     private void onPrinterRegistryReady(IBinder documentAdapter) {
@@ -320,8 +325,8 @@
                 if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
                     return;
                 }
-                mPrintedDocument.cancel();
                 setState(STATE_PRINT_CANCELED);
+                mPrintedDocument.cancel(true);
                 doFinish();
             }
         }, PrintActivity.this);
@@ -457,7 +462,7 @@
     }
 
     private void onPrintDocumentError(String message) {
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensureErrorUiShown(null, PrintErrorFragment.ACTION_RETRY);
 
         setState(STATE_UPDATE_FAILED);
@@ -483,7 +488,7 @@
             Log.i(LOG_TAG, "onUpdateCanceled()");
         }
 
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensurePreviewUiShown();
 
         switch (mState) {
@@ -505,7 +510,7 @@
             Log.i(LOG_TAG, "onUpdateCompleted()");
         }
 
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensurePreviewUiShown();
 
         // Update the print job with the info for the written document. The page
@@ -553,7 +558,7 @@
             Log.i(LOG_TAG, "onUpdateFailed()");
         }
 
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensureErrorUiShown(error, PrintErrorFragment.ACTION_RETRY);
 
         if (mState == STATE_CREATE_FILE_FAILED
@@ -574,14 +579,6 @@
 
     @Override
     public void onOptionsClosed() {
-        PageRange[] selectedPages = computeSelectedPages();
-        if (!Arrays.equals(mSelectedPages, selectedPages)) {
-            mSelectedPages = selectedPages;
-
-            // Update preview.
-            updatePrintPreviewController(false);
-        }
-
         // Make sure the IME is not on the way of preview as
         // the user may have used it to type copies or range.
         InputMethodManager imm = getSystemService(InputMethodManager.class);
@@ -694,34 +691,27 @@
 
     private void onSelectPrinterActivityResult(int resultCode, Intent data) {
         if (resultCode == RESULT_OK && data != null) {
-            PrinterId printerId = data.getParcelableExtra(INTENT_EXTRA_PRINTER_ID);
-            if (printerId != null) {
-                mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerId);
-                final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
-                if (index != AdapterView.INVALID_POSITION) {
-                    mDestinationSpinner.setSelection(index);
-                    return;
-                }
+            PrinterInfo printerInfo = data.getParcelableExtra(
+                    SelectPrinterActivity.INTENT_EXTRA_PRINTER);
+            if (printerInfo != null) {
+                mCurrentPrinter = printerInfo;
+                mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerInfo);
             }
         }
 
         if (mCurrentPrinter != null) {
-            PrinterId printerId = mCurrentPrinter.getId();
-            final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
-            mDestinationSpinner.setSelection(index);
+            // Trigger PrintersObserver.onChanged() to adjust selection back to current printer
+            mDestinationSpinnerAdapter.notifyDataSetChanged();
         }
     }
 
     private void startAdvancedPrintOptionsActivity(PrinterInfo printer) {
-        ComponentName serviceName = printer.getId().getServiceName();
-
-        String activityName = PrintOptionUtils.getAdvancedOptionsActivityName(this, serviceName);
-        if (TextUtils.isEmpty(activityName)) {
+        if (mAdvancedPrintOptionsActivity == null) {
             return;
         }
 
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setComponent(new ComponentName(serviceName.getPackageName(), activityName));
+        intent.setComponent(mAdvancedPrintOptionsActivity);
 
         List<ResolveInfo> resolvedActivities = getPackageManager()
                 .queryIntentActivities(intent, 0);
@@ -731,7 +721,10 @@
 
         // The activity is a component name, therefore it is one or none.
         if (resolvedActivities.get(0).activityInfo.exported) {
-            intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, mPrintJob);
+            PrintJobInfo.Builder printJobBuilder = new PrintJobInfo.Builder(mPrintJob);
+            printJobBuilder.setPages(mSelectedPages);
+
+            intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, printJobBuilder.build());
             intent.putExtra(PrintService.EXTRA_PRINTER_INFO, printer);
             intent.putExtra(PrintService.EXTRA_PRINT_DOCUMENT_INFO,
                     mPrintedDocument.getDocumentInfo().info);
@@ -759,10 +752,14 @@
         // Take the advanced options without interpretation.
         mPrintJob.setAdvancedOptions(printJobInfo.getAdvancedOptions());
 
-        // Take copies without interpretation as the advanced print dialog
-        // cannot create a print job info with invalid copies.
-        mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
-        mPrintJob.setCopies(printJobInfo.getCopies());
+        if (printJobInfo.getCopies() < 1) {
+            Log.w(LOG_TAG, "Cannot apply return value from advanced options activity. Copies " +
+                    "must be 1 or more. Actual value is: " + printJobInfo.getCopies() + ". " +
+                    "Ignoring.");
+        } else {
+            mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
+            mPrintJob.setCopies(printJobInfo.getCopies());
+        }
 
         PrintAttributes currAttributes = mPrintJob.getAttributes();
         PrintAttributes newAttributes = printJobInfo.getAttributes();
@@ -771,7 +768,7 @@
             // Take the media size only if the current printer supports is.
             MediaSize oldMediaSize = currAttributes.getMediaSize();
             MediaSize newMediaSize = newAttributes.getMediaSize();
-            if (!oldMediaSize.equals(newMediaSize)) {
+            if (newMediaSize != null && !oldMediaSize.equals(newMediaSize)) {
                 final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount();
                 MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait();
                 for (int i = 0; i < mediaSizeCount; i++) {
@@ -923,7 +920,7 @@
         mSelectedPages = selectedPages;
         mPrintJob.setPages(selectedPages);
 
-        if (Arrays.equals(selectedPages, ALL_PAGES_ARRAY)) {
+        if (Arrays.equals(selectedPages, PageRange.ALL_PAGES_ARRAY)) {
             if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
                 mRangeOptionsSpinner.setSelection(0);
                 mPageRangeEditText.setText("");
@@ -1013,7 +1010,7 @@
     }
 
     private void requestCreatePdfFileOrFinish() {
-        mPrintedDocument.cancel();
+        mPrintedDocument.cancel(false);
 
         if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
             startCreateDocumentActivity();
@@ -1022,7 +1019,22 @@
         }
     }
 
+    /**
+     * Clear the selected page range and update the preview if needed.
+     */
+    private void clearPageRanges() {
+        mRangeOptionsSpinner.setSelection(0);
+        mPageRangeEditText.setError(null);
+        mPageRangeEditText.setText("");
+        mSelectedPages = PageRange.ALL_PAGES_ARRAY;
+
+        if (!Arrays.equals(mSelectedPages, mPrintPreviewController.getSelectedPages())) {
+            updatePrintPreviewController(false);
+        }
+    }
+
     private void updatePrintAttributesFromCapabilities(PrinterCapabilitiesInfo capabilities) {
+        boolean clearRanges = false;
         PrintAttributes defaults = capabilities.getDefaults();
 
         // Sort the media sizes based on the current locale.
@@ -1034,6 +1046,7 @@
         // Media size.
         MediaSize currMediaSize = attributes.getMediaSize();
         if (currMediaSize == null) {
+            clearRanges = true;
             attributes.setMediaSize(defaults.getMediaSize());
         } else {
             MediaSize newMediaSize = null;
@@ -1052,6 +1065,7 @@
             }
             // If we did not find the current media size fall back to default.
             if (newMediaSize == null) {
+                clearRanges = true;
                 newMediaSize = defaults.getMediaSize();
             }
 
@@ -1083,7 +1097,14 @@
         }
 
         // Margins.
+        if (!Objects.equals(attributes.getMinMargins(), defaults.getMinMargins())) {
+            clearRanges = true;
+        }
         attributes.setMinMargins(defaults.getMinMargins());
+
+        if (clearRanges) {
+            clearPageRanges();
+        }
     }
 
     private boolean updateDocument(boolean clearLastError) {
@@ -1130,10 +1151,22 @@
     private void cancelPrint() {
         setState(STATE_PRINT_CANCELED);
         updateOptionsUi();
-        mPrintedDocument.cancel();
+        mPrintedDocument.cancel(true);
         doFinish();
     }
 
+    /**
+     * Update the selected pages from the text field.
+     */
+    private void updateSelectedPagesFromTextField() {
+        PageRange[] selectedPages = computeSelectedPages();
+        if (!Arrays.equals(mSelectedPages, selectedPages)) {
+            mSelectedPages = selectedPages;
+            // Update preview.
+            updatePrintPreviewController(false);
+        }
+    }
+
     private void confirmPrint() {
         setState(STATE_PRINT_CONFIRMED);
 
@@ -1143,14 +1176,10 @@
         addCurrentPrinterToHistory();
         setUserPrinted();
 
-        PageRange[] selectedPages = computeSelectedPages();
-        if (!Arrays.equals(mSelectedPages, selectedPages)) {
-            mSelectedPages = selectedPages;
-            // Update preview.
-            updatePrintPreviewController(false);
-        }
-
+        // updateSelectedPagesFromTextField migth update the preview, hence apply the preview first
         updateSelectedPagesFromPreview();
+        updateSelectedPagesFromTextField();
+
         mPrintPreviewController.closeOptions();
 
         if (canUpdateDocument()) {
@@ -1184,7 +1213,8 @@
         mCopiesEditText.addTextChangedListener(new EditTextWatcher());
 
         // Destination.
-        mDestinationSpinnerAdapter.registerDataSetObserver(new PrintersObserver());
+        mPrintersObserver = new PrintersObserver();
+        mDestinationSpinnerAdapter.registerDataSetObserver(mPrintersObserver);
         mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
         mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
         mDestinationSpinner.setOnItemSelectedListener(itemSelectedListener);
@@ -1234,6 +1264,7 @@
         // Page range
         mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
         mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
+        mPageRangeEditText.setVisibility(View.INVISIBLE);
         mPageRangeEditText.setOnFocusChangeListener(mSelectAllOnFocusListener);
         mPageRangeEditText.addTextChangedListener(new RangeTextWatcher());
 
@@ -1272,6 +1303,59 @@
         }
     }
 
+    @Override
+    public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+        return new PrintServicesLoader((PrintManager) getSystemService(Context.PRINT_SERVICE), this,
+                PrintManager.ENABLED_SERVICES);
+    }
+
+    @Override
+    public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+            List<PrintServiceInfo> services) {
+        ComponentName newAdvancedPrintOptionsActivity = null;
+        if (mCurrentPrinter != null && services != null) {
+            final int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                PrintServiceInfo service = services.get(i);
+
+                if (service.getComponentName().equals(mCurrentPrinter.getId().getServiceName())) {
+                    String advancedOptionsActivityName = service.getAdvancedOptionsActivityName();
+
+                    if (!TextUtils.isEmpty(advancedOptionsActivityName)) {
+                        newAdvancedPrintOptionsActivity = new ComponentName(
+                                service.getComponentName().getPackageName(),
+                                advancedOptionsActivityName);
+
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (!Objects.equals(newAdvancedPrintOptionsActivity, mAdvancedPrintOptionsActivity)) {
+            mAdvancedPrintOptionsActivity = newAdvancedPrintOptionsActivity;
+            updateOptionsUi();
+        }
+
+        boolean newArePrintServicesEnabled = services != null && !services.isEmpty();
+        if (mArePrintServicesEnabled != newArePrintServicesEnabled) {
+            mArePrintServicesEnabled = newArePrintServicesEnabled;
+
+            // Reload mDestinationSpinnerAdapter as mArePrintServicesEnabled changed and the adapter
+            // reads that in DestinationAdapter#getMoreItemTitle
+            if (mDestinationSpinnerAdapter != null) {
+                mDestinationSpinnerAdapter.notifyDataSetChanged();
+            }
+        }
+    }
+
+    @Override
+    public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+        if (!isFinishing()) {
+            onLoadFinished(loader, null);
+        }
+    }
+
     /**
      * A dialog that asks the user to approve a {@link PrintService}. This dialog is automatically
      * dismissed if the same {@link PrintService} gets approved by another
@@ -1395,6 +1479,12 @@
                     cancelPrint();
                 }
             } else if (view == mMoreOptionsButton) {
+                if (mPageRangeEditText.getError() == null) {
+                    // The selected pages is only applied once the user leaves the text field. A click
+                    // on this button, does not count as leaving.
+                    updateSelectedPagesFromTextField();
+                }
+
                 if (mCurrentPrinter != null) {
                     startAdvancedPrintOptionsActivity(mCurrentPrinter);
                 }
@@ -1672,36 +1762,38 @@
         // Range options
         PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
         final int pageCount = getAdjustedPageCount(info);
-        if (info != null && pageCount > 0) {
-            if (pageCount == 1) {
-                mRangeOptionsSpinner.setEnabled(false);
-            } else {
-                mRangeOptionsSpinner.setEnabled(true);
-                if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
-                    if (!mPageRangeEditText.isEnabled()) {
-                        mPageRangeEditText.setEnabled(true);
-                        mPageRangeEditText.setVisibility(View.VISIBLE);
-                        mPageRangeTitle.setVisibility(View.VISIBLE);
-                        mPageRangeEditText.requestFocus();
-                        InputMethodManager imm = (InputMethodManager)
-                                getSystemService(Context.INPUT_METHOD_SERVICE);
-                        imm.showSoftInput(mPageRangeEditText, 0);
-                    }
+        if (pageCount > 0) {
+            if (info != null) {
+                if (pageCount == 1) {
+                    mRangeOptionsSpinner.setEnabled(false);
                 } else {
-                    mPageRangeEditText.setEnabled(false);
-                    mPageRangeEditText.setVisibility(View.INVISIBLE);
-                    mPageRangeTitle.setVisibility(View.INVISIBLE);
+                    mRangeOptionsSpinner.setEnabled(true);
+                    if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
+                        if (!mPageRangeEditText.isEnabled()) {
+                            mPageRangeEditText.setEnabled(true);
+                            mPageRangeEditText.setVisibility(View.VISIBLE);
+                            mPageRangeTitle.setVisibility(View.VISIBLE);
+                            mPageRangeEditText.requestFocus();
+                            InputMethodManager imm = (InputMethodManager)
+                                    getSystemService(Context.INPUT_METHOD_SERVICE);
+                            imm.showSoftInput(mPageRangeEditText, 0);
+                        }
+                    } else {
+                        mPageRangeEditText.setEnabled(false);
+                        mPageRangeEditText.setVisibility(View.INVISIBLE);
+                        mPageRangeTitle.setVisibility(View.INVISIBLE);
+                    }
                 }
+            } else {
+                if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
+                    mRangeOptionsSpinner.setSelection(0);
+                    mPageRangeEditText.setText("");
+                }
+                mRangeOptionsSpinner.setEnabled(false);
+                mPageRangeEditText.setEnabled(false);
+                mPageRangeEditText.setVisibility(View.INVISIBLE);
+                mPageRangeTitle.setVisibility(View.INVISIBLE);
             }
-        } else {
-            if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
-                mRangeOptionsSpinner.setSelection(0);
-                mPageRangeEditText.setText("");
-            }
-            mRangeOptionsSpinner.setEnabled(false);
-            mPageRangeEditText.setEnabled(false);
-            mPageRangeEditText.setVisibility(View.INVISIBLE);
-            mPageRangeTitle.setVisibility(View.INVISIBLE);
         }
 
         final int newPageCount = getAdjustedPageCount(info);
@@ -1711,9 +1803,7 @@
         }
 
         // Advanced print options
-        ComponentName serviceName = mCurrentPrinter.getId().getServiceName();
-        if (!TextUtils.isEmpty(PrintOptionUtils.getAdvancedOptionsActivityName(
-                this, serviceName))) {
+        if (mAdvancedPrintOptionsActivity != null) {
             mMoreOptionsButton.setVisibility(View.VISIBLE);
             mMoreOptionsButton.setEnabled(true);
         } else {
@@ -1816,45 +1906,13 @@
         }
 
         if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
-            List<PageRange> pageRanges = new ArrayList<>();
-            mStringCommaSplitter.setString(mPageRangeEditText.getText().toString());
+            PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+            final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
 
-            while (mStringCommaSplitter.hasNext()) {
-                String range = mStringCommaSplitter.next().trim();
-                if (TextUtils.isEmpty(range)) {
-                    continue;
-                }
-                final int dashIndex = range.indexOf('-');
-                final int fromIndex;
-                final int toIndex;
-
-                if (dashIndex > 0) {
-                    fromIndex = Integer.parseInt(range.substring(0, dashIndex).trim()) - 1;
-                    // It is possible that the dash is at the end since the input
-                    // verification can has to allow the user to keep entering if
-                    // this would lead to a valid input. So we handle this.
-                    if (dashIndex < range.length() - 1) {
-                        String fromString = range.substring(dashIndex + 1, range.length()).trim();
-                        toIndex = Integer.parseInt(fromString) - 1;
-                    } else {
-                        toIndex = fromIndex;
-                    }
-                } else {
-                    fromIndex = toIndex = Integer.parseInt(range) - 1;
-                }
-
-                PageRange pageRange = new PageRange(Math.min(fromIndex, toIndex),
-                        Math.max(fromIndex, toIndex));
-                pageRanges.add(pageRange);
-            }
-
-            PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
-            pageRanges.toArray(pageRangesArray);
-
-            return PageRangeUtils.normalize(pageRangesArray);
+            return PageRangeUtils.parsePageRanges(mPageRangeEditText.getText(), pageCount);
         }
 
-        return ALL_PAGES_ARRAY;
+        return PageRange.ALL_PAGES_ARRAY;
     }
 
     private int getAdjustedPageCount(PrintDocumentInfo info) {
@@ -1889,7 +1947,7 @@
     public void onPrinterUnavailable(PrinterInfo printer) {
         if (mCurrentPrinter.getId().equals(printer.getId())) {
             setState(STATE_PRINTER_UNAVAILABLE);
-            mPrintedDocument.cancel();
+            mPrintedDocument.cancel(false);
             ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
                     PrintErrorFragment.ACTION_NONE);
             updateOptionsUi();
@@ -1953,18 +2011,32 @@
     }
 
     private void doFinish() {
-        if (mPrintedDocument.isUpdating()) {
+        if (mPrintedDocument != null && mPrintedDocument.isUpdating()) {
             // The printedDocument will call doFinish() when the current command finishes
             return;
         }
 
+        if (mIsFinishing) {
+            return;
+        }
+
+        mIsFinishing = true;
+
         if (mPrinterRegistry != null) {
             mPrinterRegistry.setTrackedPrinter(null);
         }
 
-        if (mState != STATE_INITIALIZING) {
-            mProgressMessageController.cancel();
+        if (mPrintersObserver != null) {
+            mDestinationSpinnerAdapter.unregisterDataSetObserver(mPrintersObserver);
+        }
+
+        if (mSpoolerProvider != null) {
             mSpoolerProvider.destroy();
+        }
+
+        setState(mProgressMessageController.cancel());
+
+        if (mState != STATE_INITIALIZING) {
             mPrintedDocument.finish();
             mPrintedDocument.destroy();
             mPrintPreviewController.destroy(new Runnable() {
@@ -2137,23 +2209,36 @@
             return AdapterView.INVALID_POSITION;
         }
 
-        public void ensurePrinterInVisibleAdapterPosition(PrinterId printerId) {
+        public void ensurePrinterInVisibleAdapterPosition(PrinterInfo printer) {
             final int printerCount = mPrinterHolders.size();
+            boolean isKnownPrinter = false;
             for (int i = 0; i < printerCount; i++) {
                 PrinterHolder printerHolder = mPrinterHolders.get(i);
-                if (printerHolder.printer.getId().equals(printerId)) {
+
+                if (printerHolder.printer.getId().equals(printer.getId())) {
+                    isKnownPrinter = true;
+
                     // If already in the list - do nothing.
                     if (i < getCount() - 2) {
-                        return;
+                        break;
                     }
                     // Else replace the last one (two items are not printers).
                     final int lastPrinterIndex = getCount() - 3;
                     mPrinterHolders.set(i, mPrinterHolders.get(lastPrinterIndex));
                     mPrinterHolders.set(lastPrinterIndex, printerHolder);
-                    notifyDataSetChanged();
-                    return;
+                    break;
                 }
             }
+
+            if (!isKnownPrinter) {
+                PrinterHolder printerHolder = new PrinterHolder(printer);
+                printerHolder.removed = true;
+
+                mPrinterHolders.add(Math.max(0, getCount() - 3), printerHolder);
+            }
+
+            // Force reload to adjust selection in PrintersObserver.onChanged()
+            notifyDataSetChanged();
         }
 
         @Override
@@ -2201,14 +2286,14 @@
                 if (position == 0) {
                     return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
                 } else if (position == 1) {
-                    return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
+                    return DEST_ADAPTER_ITEM_ID_MORE;
                 }
             } else {
                 if (position == 1) {
                     return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
                 }
                 if (position == getCount() - 1) {
-                    return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
+                    return DEST_ADAPTER_ITEM_ID_MORE;
                 }
             }
             return position;
@@ -2221,6 +2306,14 @@
             return view;
         }
 
+        private String getMoreItemTitle() {
+            if (mArePrintServicesEnabled) {
+                return getString(R.string.all_printers);
+            } else {
+                return getString(R.string.print_add_printer);
+            }
+        }
+
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             if (mShowDestinationPrompt) {
@@ -2249,7 +2342,7 @@
                     title = printerHolder.printer.getName();
                     icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
                 } else if (position == 1) {
-                    title = getString(R.string.all_printers);
+                    title = getMoreItemTitle();
                 }
             } else {
                 if (position == 1 && getPdfPrinter() != null) {
@@ -2257,7 +2350,7 @@
                     title = printerHolder.printer.getName();
                     icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
                 } else if (position == getCount() - 1) {
-                    title = getString(R.string.all_printers);
+                    title = getMoreItemTitle();
                 } else {
                     PrinterHolder printerHolder = (PrinterHolder) getItem(position);
                     PrinterInfo printInfo = printerHolder.printer;
@@ -2292,7 +2385,7 @@
                 }
                 iconView.setImageDrawable(icon);
             } else {
-                iconView.setVisibility(View.GONE);
+                iconView.setVisibility(View.INVISIBLE);
             }
 
             return convertView;
@@ -2328,8 +2421,7 @@
             List<PrinterHolder> newPrinterHolders = new ArrayList<>();
 
             // Update printers we already have which are either updated or removed.
-            // We do not remove printers if the currently selected printer is removed
-            // to prevent the user printing to a wrong printer.
+            // We do not remove the currently selected printer.
             final int oldPrinterCount = mPrinterHolders.size();
             for (int i = 0; i < oldPrinterCount; i++) {
                 PrinterHolder printerHolder = mPrinterHolders.get(i);
@@ -2337,10 +2429,12 @@
                 PrinterInfo updatedPrinter = newPrintersMap.remove(oldPrinterId);
                 if (updatedPrinter != null) {
                     printerHolder.printer = updatedPrinter;
-                } else {
+                    printerHolder.removed = false;
+                    newPrinterHolders.add(printerHolder);
+                } else if (mCurrentPrinter != null && mCurrentPrinter.getId().equals(oldPrinterId)){
                     printerHolder.removed = true;
+                    newPrinterHolders.add(printerHolder);
                 }
-                newPrinterHolders.add(printerHolder);
             }
 
             // Add the rest of the new printers, i.e. what is left.
@@ -2372,14 +2466,25 @@
             return null;
         }
 
-        public void pruneRemovedPrinters() {
+        /**
+         * Remove a printer from the holders if it is marked as removed.
+         *
+         * @param printerId the id of the printer to remove.
+         *
+         * @return true iff the printer was removed.
+         */
+        public boolean pruneRemovedPrinter(PrinterId printerId) {
             final int holderCounts = mPrinterHolders.size();
             for (int i = holderCounts - 1; i >= 0; i--) {
                 PrinterHolder printerHolder = mPrinterHolders.get(i);
-                if (printerHolder.removed) {
+
+                if (printerHolder.printer.getId().equals(printerId) && printerHolder.removed) {
                     mPrinterHolders.remove(i);
+                    return true;
                 }
             }
+
+            return false;
         }
 
         private void addPrinters(List<PrinterHolder> list, Collection<PrinterInfo> printers) {
@@ -2424,17 +2529,17 @@
 
             PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
                     oldPrinterState.getId());
-            if (printerHolder == null) {
-                return;
-            }
             PrinterInfo newPrinterState = printerHolder.printer;
 
-            if (!printerHolder.removed) {
-                mDestinationSpinnerAdapter.pruneRemovedPrinters();
-            } else {
+            if (printerHolder.removed) {
                 onPrinterUnavailable(newPrinterState);
             }
 
+            if (mDestinationSpinner.getSelectedItem() != printerHolder) {
+                mDestinationSpinner.setSelection(
+                        mDestinationSpinnerAdapter.getPrinterIndex(newPrinterState.getId()));
+            }
+
             if (oldPrinterState.equals(newPrinterState)) {
                 return;
             }
@@ -2442,6 +2547,7 @@
             PrinterCapabilitiesInfo oldCapab = oldPrinterState.getCapabilities();
             PrinterCapabilitiesInfo newCapab = newPrinterState.getCapabilities();
 
+            final boolean hadCabab = oldCapab != null;
             final boolean hasCapab = newCapab != null;
             final boolean gotCapab = oldCapab == null && newCapab != null;
             final boolean lostCapab = oldCapab != null && newCapab == null;
@@ -2460,23 +2566,31 @@
 
             mCurrentPrinter = newPrinterState;
 
-            if ((isActive && gotCapab) || (becameActive && hasCapab)) {
-                if (hasCapab && capabChanged) {
-                    updatePrintAttributesFromCapabilities(newCapab);
-                    updatePrintPreviewController(false);
-                }
-                onPrinterAvailable(newPrinterState);
-            } else if ((becameInactive && hasCapab) || (isActive && lostCapab)) {
-                onPrinterUnavailable(newPrinterState);
-            }
-
             final boolean updateNeeded = ((capabChanged && hasCapab && isActive)
                     || (becameActive && hasCapab) || (isActive && gotCapab));
 
+            if (capabChanged && hasCapab) {
+                updatePrintAttributesFromCapabilities(newCapab);
+            }
+
+            if (updateNeeded) {
+                updatePrintPreviewController(false);
+            }
+
+            if ((isActive && gotCapab) || (becameActive && hasCapab)) {
+                onPrinterAvailable(newPrinterState);
+            } else if ((becameInactive && hadCabab) || (isActive && lostCapab)) {
+                onPrinterUnavailable(newPrinterState);
+            }
+
             if (updateNeeded && canUpdateDocument()) {
                 updateDocument(false);
             }
 
+            // Force a reload of the enabled print services to update mAdvancedPrintOptionsActivity
+            // in onLoadFinished();
+            getLoaderManager().getLoader(LOADER_ID_ENABLED_PRINT_SERVICES).forceLoad();
+
             updateOptionsUi();
             updateSummary();
         }
@@ -2497,12 +2611,14 @@
     private final class MyOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
         @Override
         public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
+            boolean clearRanges = false;
+
             if (spinner == mDestinationSpinner) {
                 if (position == AdapterView.INVALID_POSITION) {
                     return;
                 }
 
-                if (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) {
+                if (id == DEST_ADAPTER_ITEM_ID_MORE) {
                     startSelectPrinterActivity();
                     return;
                 }
@@ -2515,13 +2631,28 @@
                     return;
                 }
 
+                PrinterId oldId = null;
+                if (mCurrentPrinter != null) {
+                    oldId = mCurrentPrinter.getId();
+                }
+
                 mCurrentPrinter = currentPrinter;
 
+                if (oldId != null) {
+                    boolean printerRemoved = mDestinationSpinnerAdapter.pruneRemovedPrinter(oldId);
+
+                    if (printerRemoved) {
+                        // Trigger PrinterObserver.onChanged to adjust selection. This will call
+                        // this function again.
+                        mDestinationSpinnerAdapter.notifyDataSetChanged();
+                        return;
+                    }
+                }
+
                 PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
                         currentPrinter.getId());
                 if (!printerHolder.removed) {
                     setState(STATE_CONFIGURING);
-                    mDestinationSpinnerAdapter.pruneRemovedPrinters();
                     ensurePreviewUiShown();
                 }
 
@@ -2536,13 +2667,24 @@
                 }
 
                 mPrinterAvailabilityDetector.updatePrinter(currentPrinter);
+
+                // Force a reload of the enabled print services to update
+                // mAdvancedPrintOptionsActivity in onLoadFinished();
+                getLoaderManager().getLoader(LOADER_ID_ENABLED_PRINT_SERVICES).forceLoad();
             } else if (spinner == mMediaSizeSpinner) {
                 SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
                 PrintAttributes attributes = mPrintJob.getAttributes();
+
+                MediaSize newMediaSize;
                 if (mOrientationSpinner.getSelectedItemPosition() == 0) {
-                    attributes.setMediaSize(mediaItem.value.asPortrait());
+                    newMediaSize = mediaItem.value.asPortrait();
                 } else {
-                    attributes.setMediaSize(mediaItem.value.asLandscape());
+                    newMediaSize = mediaItem.value.asLandscape();
+                }
+
+                if (newMediaSize != attributes.getMediaSize()) {
+                    clearRanges = true;
+                    attributes.setMediaSize(newMediaSize);
                 }
             } else if (spinner == mColorModeSpinner) {
                 SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position);
@@ -2554,25 +2696,35 @@
                 SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
                 PrintAttributes attributes = mPrintJob.getAttributes();
                 if (mMediaSizeSpinner.getSelectedItem() != null) {
-                    if (orientationItem.value == ORIENTATION_PORTRAIT) {
-                        attributes.copyFrom(attributes.asPortrait());
-                    } else {
-                        attributes.copyFrom(attributes.asLandscape());
+                    boolean isPortrait = attributes.isPortrait();
+
+                    if (isPortrait != (orientationItem.value == ORIENTATION_PORTRAIT)) {
+                        clearRanges = true;
+                        if (orientationItem.value == ORIENTATION_PORTRAIT) {
+                            attributes.copyFrom(attributes.asPortrait());
+                        } else {
+                            attributes.copyFrom(attributes.asLandscape());
+                        }
                     }
                 }
             } else if (spinner == mRangeOptionsSpinner) {
                 if (mRangeOptionsSpinner.getSelectedItemPosition() == 0) {
+                    clearRanges = true;
                     mPageRangeEditText.setText("");
                 } else if (TextUtils.isEmpty(mPageRangeEditText.getText())) {
                     mPageRangeEditText.setError("");
                 }
             }
 
-            if (canUpdateDocument()) {
-                updateDocument(false);
+            if (clearRanges) {
+                clearPageRanges();
             }
 
             updateOptionsUi();
+
+            if (canUpdateDocument()) {
+                updateDocument(false);
+            }
         }
 
         @Override
@@ -2588,6 +2740,10 @@
             if (!TextUtils.isEmpty(editText.getText())) {
                 editText.setSelection(editText.getText().length());
             }
+
+            if (view == mPageRangeEditText && !hasFocus && mPageRangeEditText.getError() == null) {
+                updateSelectedPagesFromTextField();
+            }
         }
     }
 
@@ -2606,50 +2762,26 @@
         public void afterTextChanged(Editable editable) {
             final boolean hadErrors = hasErrors();
 
-            String text = editable.toString();
-
-            if (TextUtils.isEmpty(text)) {
-                mPageRangeEditText.setError("");
-                updateOptionsUi();
-                return;
-            }
-
-            String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
-            if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
-                mPageRangeEditText.setError("");
-                updateOptionsUi();
-                return;
-            }
-
             PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
             final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
+            PageRange[] ranges = PageRangeUtils.parsePageRanges(editable, pageCount);
 
-            // The range
-            Matcher matcher = PATTERN_DIGITS.matcher(text);
-            while (matcher.find()) {
-                String numericString = text.substring(matcher.start(), matcher.end()).trim();
-                if (TextUtils.isEmpty(numericString)) {
-                    continue;
-                }
-                final int pageIndex = Integer.parseInt(numericString);
-                if (pageIndex < 1 || pageIndex > pageCount) {
+            if (ranges.length == 0) {
+                if (mPageRangeEditText.getError() == null) {
                     mPageRangeEditText.setError("");
                     updateOptionsUi();
-                    return;
                 }
+                return;
             }
 
-            // We intentionally do not catch the case of the from page being
-            // greater than the to page. When computing the requested pages
-            // we just swap them if necessary.
-
-            mPageRangeEditText.setError(null);
-            mPrintButton.setEnabled(true);
-            updateOptionsUi();
-
-            if (hadErrors && !hasErrors()) {
+            if (mPageRangeEditText.getError() != null) {
+                mPageRangeEditText.setError(null);
                 updateOptionsUi();
             }
+
+            if (hadErrors && canUpdateDocument()) {
+                updateDocument(false);
+            }
         }
     }
 
@@ -2669,8 +2801,10 @@
             final boolean hadErrors = hasErrors();
 
             if (editable.length() == 0) {
-                mCopiesEditText.setError("");
-                updateOptionsUi();
+                if (mCopiesEditText.getError() == null) {
+                    mCopiesEditText.setError("");
+                    updateOptionsUi();
+                }
                 return;
             }
 
@@ -2682,16 +2816,19 @@
             }
 
             if (copies < MIN_COPIES) {
-                mCopiesEditText.setError("");
-                updateOptionsUi();
+                if (mCopiesEditText.getError() == null) {
+                    mCopiesEditText.setError("");
+                    updateOptionsUi();
+                }
                 return;
             }
 
             mPrintJob.setCopies(copies);
 
-            mCopiesEditText.setError(null);
-
-            updateOptionsUi();
+            if (mCopiesEditText.getError() != null) {
+                mCopiesEditText.setError(null);
+                updateOptionsUi();
+            }
 
             if (hadErrors && canUpdateDocument()) {
                 updateDocument(false);
@@ -2706,29 +2843,50 @@
 
         private boolean mPosted;
 
+        /** State before run was executed */
+        private int mPreviousState = -1;
+
         public ProgressMessageController(Context context) {
             mHandler = new Handler(context.getMainLooper(), null, false);
         }
 
         public void post() {
-            if (mPosted) {
+            if (mState == STATE_UPDATE_SLOW) {
+                setState(STATE_UPDATE_SLOW);
+                ensureProgressUiShown();
+                updateOptionsUi();
+
+                return;
+            } else if (mPosted) {
                 return;
             }
+            mPreviousState = -1;
             mPosted = true;
             mHandler.postDelayed(this, PROGRESS_TIMEOUT_MILLIS);
         }
 
-        public void cancel() {
+        private int getStateAfterCancel() {
+            if (mPreviousState == -1) {
+                return mState;
+            } else {
+                return mPreviousState;
+            }
+        }
+
+        public int cancel() {
             if (!mPosted) {
-                return;
+                return getStateAfterCancel();
             }
             mPosted = false;
             mHandler.removeCallbacks(this);
+
+            return getStateAfterCancel();
         }
 
         @Override
         public void run() {
             mPosted = false;
+            mPreviousState = mState;
             setState(STATE_UPDATE_SLOW);
             ensureProgressUiShown();
             updateOptionsUi();
@@ -2877,12 +3035,10 @@
             List<PageRange> rangesToShred = new ArrayList<>();
             PageRange previousRange = null;
 
-            final int pageCount = printJob.getDocumentInfo().getPageCount();
-
             PageRange[] printedPages = printJob.getPages();
             final int rangeCount = printedPages.length;
             for (int i = 0; i < rangeCount; i++) {
-                PageRange range = PageRangeUtils.asAbsoluteRange(printedPages[i], pageCount);
+                PageRange range = printedPages[i];
 
                 if (previousRange == null) {
                     final int startPageIdx = 0;
@@ -2901,11 +3057,8 @@
                 }
 
                 if (i == rangeCount - 1) {
-                    final int startPageIdx = range.getEnd() + 1;
-                    final int endPageIdx = printJob.getDocumentInfo().getPageCount() - 1;
-                    if (startPageIdx <= endPageIdx) {
-                        PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
-                        rangesToShred.add(removedRange);
+                    if (range.getEnd() != Integer.MAX_VALUE) {
+                        rangesToShred.add(new PageRange(range.getEnd() + 1, Integer.MAX_VALUE));
                     }
                 }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
index 6d60bb8..86366dd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
@@ -33,7 +33,7 @@
 
 public class PrinterRegistry {
 
-    private static final int LOADER_ID_PRINTERS_LOADER = 1;
+    private final int mLoaderId;
 
     private final Activity mActivity;
 
@@ -52,12 +52,17 @@
         public void onPrintersInvalid();
     }
 
-    public PrinterRegistry(Activity activity, Runnable readyCallback) {
+    public PrinterRegistry(Activity activity, Runnable readyCallback, int loaderId,
+            int internalLoaderId) {
+        mLoaderId = loaderId;
         mActivity = activity;
         mReadyCallback = readyCallback;
         mHandler = new MyHandler(activity.getMainLooper());
-        activity.getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER,
-                null, mLoaderCallbacks);
+
+        Bundle loaderData = new Bundle(1);
+        loaderData.putInt(null, internalLoaderId);
+
+        activity.getLoaderManager().initLoader(loaderId, loaderData, mLoaderCallbacks);
     }
 
     public void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
@@ -106,7 +111,7 @@
     }
 
     private FusedPrintersProvider getPrinterProvider() {
-        Loader<?> loader = mActivity.getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER);
+        Loader<?> loader = mActivity.getLoaderManager().getLoader(mLoaderId);
         return (FusedPrintersProvider) loader;
     }
 
@@ -114,38 +119,34 @@
             new LoaderCallbacks<List<PrinterInfo>>() {
         @Override
         public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
-            if (loader.getId() == LOADER_ID_PRINTERS_LOADER) {
-                mPrinters.clear();
-                if (mOnPrintersChangeListener != null) {
-                    // Post a message as we are in onLoadFinished and certain operations
-                    // are not allowed in this callback, such as fragment transactions.
-                    // Clients should not handle this explicitly.
-                    mHandler.obtainMessage(MyHandler.MSG_PRINTERS_INVALID,
-                            mOnPrintersChangeListener).sendToTarget();
-                }
+            mPrinters.clear();
+            if (mOnPrintersChangeListener != null) {
+                // Post a message as we are in onLoadFinished and certain operations
+                // are not allowed in this callback, such as fragment transactions.
+                // Clients should not handle this explicitly.
+                mHandler.obtainMessage(MyHandler.MSG_PRINTERS_INVALID,
+                        mOnPrintersChangeListener).sendToTarget();
             }
         }
 
         // LoaderCallbacks#onLoadFinished
         @Override
         public void onLoadFinished(Loader<List<PrinterInfo>> loader, List<PrinterInfo> printers) {
-            if (loader.getId() == LOADER_ID_PRINTERS_LOADER) {
-                mPrinters.clear();
-                mPrinters.addAll(printers);
-                if (mOnPrintersChangeListener != null) {
-                    // Post a message as we are in onLoadFinished and certain operations
-                    // are not allowed in this callback, such as fragment transactions.
-                    // Clients should not handle this explicitly.
-                    SomeArgs args = SomeArgs.obtain();
-                    args.arg1 = mOnPrintersChangeListener;
-                    args.arg2 = printers;
-                    mHandler.obtainMessage(MyHandler.MSG_PRINTERS_CHANGED, args).sendToTarget();
-                }
-                if (!mReady) {
-                    mReady = true;
-                    if (mReadyCallback != null) {
-                        mReadyCallback.run();
-                    }
+            mPrinters.clear();
+            mPrinters.addAll(printers);
+            if (mOnPrintersChangeListener != null) {
+                // Post a message as we are in onLoadFinished and certain operations
+                // are not allowed in this callback, such as fragment transactions.
+                // Clients should not handle this explicitly.
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = mOnPrintersChangeListener;
+                args.arg2 = printers;
+                mHandler.obtainMessage(MyHandler.MSG_PRINTERS_CHANGED, args).sendToTarget();
+            }
+            if (!mReady) {
+                mReady = true;
+                if (mReadyCallback != null) {
+                    mReadyCallback.run();
                 }
             }
         }
@@ -153,10 +154,7 @@
         // LoaderCallbacks#onCreateLoader
         @Override
         public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
-            if (id == LOADER_ID_PRINTERS_LOADER) {
-                return new FusedPrintersProvider(mActivity);
-            }
-            return null;
+            return new FusedPrintersProvider(mActivity, args.getInt(null));
         }
     };
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 4f7624a..fcc9f6a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -17,36 +17,23 @@
 package com.android.printspooler.ui;
 
 import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.app.FragmentTransaction;
-import android.content.ActivityNotFoundException;
+import android.app.LoaderManager;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentSender.SendIntentException;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.database.ContentObserver;
+import android.content.Loader;
 import android.database.DataSetObserver;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
 import android.print.PrintManager;
+import android.print.PrintServicesLoader;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.ContextMenu;
@@ -59,17 +46,16 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.ArrayAdapter;
 import android.widget.BaseAdapter;
 import android.widget.Filter;
 import android.widget.Filterable;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.SearchView;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.android.internal.content.PackageMonitor;
 import com.android.printspooler.R;
 
 import java.util.ArrayList;
@@ -78,25 +64,24 @@
 /**
  * This is an activity for selecting a printer.
  */
-public final class SelectPrinterActivity extends Activity {
+public final class SelectPrinterActivity extends Activity implements
+        LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
 
     private static final String LOG_TAG = "SelectPrinterFragment";
 
-    public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
+    private static final int LOADER_ID_PRINT_REGISTRY = 1;
+    private static final int LOADER_ID_PRINT_REGISTRY_INT = 2;
+    private static final int LOADER_ID_ENABLED_PRINT_SERVICES = 3;
 
-    private static final String FRAGMENT_TAG_ADD_PRINTER_DIALOG =
-            "FRAGMENT_TAG_ADD_PRINTER_DIALOG";
+    public static final String INTENT_EXTRA_PRINTER = "INTENT_EXTRA_PRINTER";
 
-    private static final String FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS =
-            "FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS";
-
+    private static final String EXTRA_PRINTER = "EXTRA_PRINTER";
     private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
 
-    /** If there are any enabled print services */
-    private boolean mHasEnabledPrintServices;
+    private static final String KEY_NOT_FIRST_CREATE = "KEY_NOT_FIRST_CREATE";
 
-    private final ArrayList<PrintServiceInfo> mAddPrinterServices =
-            new ArrayList<>();
+    /** The currently enabled print services by their ComponentName */
+    private ArrayMap<ComponentName, PrintServiceInfo> mEnabledPrintServices;
 
     private PrinterRegistry mPrinterRegistry;
 
@@ -104,9 +89,9 @@
 
     private AnnounceFilterResult mAnnounceFilterResult;
 
-    /** Monitor if new print services get enabled or disabled */
-    private ContentObserver mPrintServicesDisabledObserver;
-    private PackageMonitor mPackageObserver;
+    private void startAddPrinterActivity() {
+        startActivity(new Intent(this, AddPrinterActivity.class));
+    }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -115,7 +100,10 @@
 
         setContentView(R.layout.select_printer_activity);
 
-        mPrinterRegistry = new PrinterRegistry(this, null);
+        mEnabledPrintServices = new ArrayMap<>();
+
+        mPrinterRegistry = new PrinterRegistry(this, null, LOADER_ID_PRINT_REGISTRY,
+                LOADER_ID_PRINT_REGISTRY_INT);
 
         // Hook up the list view.
         mListView = (ListView) findViewById(android.R.id.list);
@@ -145,22 +133,67 @@
                 }
 
                 PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
-                onPrinterSelected(printer.getId());
+
+                if (printer == null) {
+                    startAddPrinterActivity();
+                } else {
+                    onPrinterSelected(printer);
+                }
+            }
+        });
+
+        findViewById(R.id.button).setOnClickListener(new OnClickListener() {
+            @Override public void onClick(View v) {
+                startAddPrinterActivity();
             }
         });
 
         registerForContextMenu(mListView);
 
-        // Display a notification about disabled services if there are disabled services
-        String disabledServicesSetting = Settings.Secure.getString(getContentResolver(),
-                Settings.Secure.DISABLED_PRINT_SERVICES);
-        if (!TextUtils.isEmpty(disabledServicesSetting)) {
-            Toast.makeText(this, getString(R.string.print_services_disabled_toast),
-                    Toast.LENGTH_LONG).show();
+        getLoaderManager().initLoader(LOADER_ID_ENABLED_PRINT_SERVICES, null, this);
+
+        // On first creation:
+        //
+        // If no services are installed, instantly open add printer dialog.
+        // If some are disabled and some are enabled show a toast to notify the user
+        if (savedInstanceState == null || !savedInstanceState.getBoolean(KEY_NOT_FIRST_CREATE)) {
+            List<PrintServiceInfo> allServices =
+                    ((PrintManager) getSystemService(Context.PRINT_SERVICE))
+                            .getPrintServices(PrintManager.ALL_SERVICES);
+            boolean hasEnabledServices = false;
+            boolean hasDisabledServices = false;
+
+            if (allServices != null) {
+                final int numServices = allServices.size();
+                for (int i = 0; i < numServices; i++) {
+                    if (allServices.get(i).isEnabled()) {
+                        hasEnabledServices = true;
+                    } else {
+                        hasDisabledServices = true;
+                    }
+                }
+            }
+
+            if (!hasEnabledServices) {
+                startAddPrinterActivity();
+            } else if (hasDisabledServices) {
+                String disabledServicesSetting = Settings.Secure.getString(getContentResolver(),
+                        Settings.Secure.DISABLED_PRINT_SERVICES);
+                if (!TextUtils.isEmpty(disabledServicesSetting)) {
+                    Toast.makeText(this, getString(R.string.print_services_disabled_toast),
+                            Toast.LENGTH_LONG).show();
+                }
+            }
         }
     }
 
     @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(KEY_NOT_FIRST_CREATE, true);
+    }
+
+    @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         super.onCreateOptionsMenu(menu);
 
@@ -214,7 +247,7 @@
                 MenuItem selectItem = menu.add(Menu.NONE, R.string.print_select_printer,
                         Menu.NONE, R.string.print_select_printer);
                 Intent intent = new Intent();
-                intent.putExtra(EXTRA_PRINTER_ID, printer.getId());
+                intent.putExtra(EXTRA_PRINTER, printer);
                 selectItem.setIntent(intent);
             }
 
@@ -233,8 +266,8 @@
     public boolean onContextItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.string.print_select_printer: {
-                PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
-                onPrinterSelected(printerId);
+                PrinterInfo printer = item.getIntent().getParcelableExtra(EXTRA_PRINTER);
+                onPrinterSelected(printer);
             } return true;
 
             case R.string.print_forget_printer: {
@@ -249,60 +282,13 @@
      * Adjust the UI if the enabled print services changed.
      */
     private synchronized void onPrintServicesUpdate() {
-        updateServicesWithAddPrinterActivity();
         updateEmptyView((DestinationAdapter)mListView.getAdapter());
         invalidateOptionsMenu();
     }
 
-    /**
-     * Register listener for changes to the enabled print services.
-     */
-    private void registerServiceMonitor() {
-        // Listen for services getting disabled
-        mPrintServicesDisabledObserver = new ContentObserver(new Handler()) {
-            @Override
-            public void onChange(boolean selfChange) {
-                onPrintServicesUpdate();
-            }
-        };
-
-        // Listen for services getting installed or uninstalled
-        mPackageObserver = new PackageMonitor() {
-            @Override
-            public void onPackageModified(String packageName) {
-                onPrintServicesUpdate();
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                onPrintServicesUpdate();
-            }
-
-            @Override
-            public void onPackageAdded(String packageName, int uid) {
-                onPrintServicesUpdate();
-            }
-        };
-
-        getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.DISABLED_PRINT_SERVICES), false,
-                mPrintServicesDisabledObserver);
-
-        mPackageObserver.register(this, getMainLooper(), false);
-    }
-
-    /**
-     * Unregister the listeners for changes to the enabled print services.
-     */
-    private void unregisterServiceMonitorIfNeeded() {
-        getContentResolver().unregisterContentObserver(mPrintServicesDisabledObserver);
-        mPackageObserver.unregister();
-    }
-
     @Override
     public void onStart() {
         super.onStart();
-        registerServiceMonitor();
         onPrintServicesUpdate();
     }
 
@@ -316,88 +302,16 @@
 
     @Override
     public void onStop() {
-        unregisterServiceMonitorIfNeeded();
         super.onStop();
     }
 
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        if (item.getItemId() == R.id.action_add_printer) {
-            showAddPrinterSelectionDialog();
-            return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    private void onPrinterSelected(PrinterId printerId) {
+    private void onPrinterSelected(PrinterInfo printer) {
         Intent intent = new Intent();
-        intent.putExtra(INTENT_EXTRA_PRINTER_ID, printerId);
+        intent.putExtra(INTENT_EXTRA_PRINTER, printer);
         setResult(RESULT_OK, intent);
         finish();
     }
 
-    private void updateServicesWithAddPrinterActivity() {
-        mHasEnabledPrintServices = true;
-        mAddPrinterServices.clear();
-
-        // Get all enabled print services.
-        PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
-        List<PrintServiceInfo> enabledServices = printManager.getEnabledPrintServices();
-
-        // No enabled print services - done.
-        if (enabledServices.isEmpty()) {
-            mHasEnabledPrintServices = false;
-            return;
-        }
-
-        // Find the services with valid add printers activities.
-        final int enabledServiceCount = enabledServices.size();
-        for (int i = 0; i < enabledServiceCount; i++) {
-            PrintServiceInfo enabledService = enabledServices.get(i);
-
-            // No add printers activity declared - next.
-            if (TextUtils.isEmpty(enabledService.getAddPrintersActivityName())) {
-                continue;
-            }
-
-            ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
-            ComponentName addPrintersComponentName = new ComponentName(
-                    serviceInfo.packageName, enabledService.getAddPrintersActivityName());
-            Intent addPritnersIntent = new Intent()
-                .setComponent(addPrintersComponentName);
-
-            // The add printers activity is valid - add it.
-            PackageManager pm = getPackageManager();
-            List<ResolveInfo> resolvedActivities = pm.queryIntentActivities(addPritnersIntent, 0);
-            if (!resolvedActivities.isEmpty()) {
-                // The activity is a component name, therefore it is one or none.
-                ActivityInfo activityInfo = resolvedActivities.get(0).activityInfo;
-                if (activityInfo.exported
-                        && (activityInfo.permission == null
-                                || pm.checkPermission(activityInfo.permission, getPackageName())
-                                        == PackageManager.PERMISSION_GRANTED)) {
-                    mAddPrinterServices.add(enabledService);
-                }
-            }
-        }
-    }
-
-    private void showAddPrinterSelectionDialog() {
-        FragmentTransaction transaction = getFragmentManager().beginTransaction();
-        Fragment oldFragment = getFragmentManager().findFragmentByTag(
-                FRAGMENT_TAG_ADD_PRINTER_DIALOG);
-        if (oldFragment != null) {
-            transaction.remove(oldFragment);
-        }
-        AddPrinterAlertDialogFragment newFragment = new AddPrinterAlertDialogFragment();
-        Bundle arguments = new Bundle();
-        arguments.putParcelableArrayList(FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS,
-                mAddPrinterServices);
-        newFragment.setArguments(arguments);
-        transaction.add(newFragment, FRAGMENT_TAG_ADD_PRINTER_DIALOG);
-        transaction.commit();
-    }
-
     public void updateEmptyView(DestinationAdapter adapter) {
         if (mListView.getEmptyView() == null) {
             View emptyView = findViewById(R.id.empty_print_state);
@@ -405,7 +319,7 @@
         }
         TextView titleView = (TextView) findViewById(R.id.title);
         View progressBar = findViewById(R.id.progress_bar);
-        if (!mHasEnabledPrintServices) {
+        if (mEnabledPrintServices.size() > 0) {
             titleView.setText(R.string.print_no_print_services);
             progressBar.setVisibility(View.GONE);
         } else if (adapter.getUnfilteredCount() <= 0) {
@@ -426,71 +340,33 @@
         }
     }
 
-    public static class AddPrinterAlertDialogFragment extends DialogFragment {
+    @Override
+    public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+        return new PrintServicesLoader((PrintManager) getSystemService(Context.PRINT_SERVICE), this,
+                PrintManager.ENABLED_SERVICES);
+    }
 
-        private String mAddPrintServiceItem;
+    @Override
+    public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+            List<PrintServiceInfo> services) {
+        mEnabledPrintServices.clear();
 
-        @Override
-        @SuppressWarnings("unchecked")
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
-                    .setTitle(R.string.choose_print_service);
+        if (services != null && !services.isEmpty()) {
+            final int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                PrintServiceInfo service = services.get(i);
 
-            final List<PrintServiceInfo> printServices = (List<PrintServiceInfo>) (List<?>)
-                    getArguments().getParcelableArrayList(FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS);
-
-            final ArrayAdapter<String> adapter = new ArrayAdapter<>(
-                    getActivity(), android.R.layout.simple_list_item_1);
-            final int printServiceCount = printServices.size();
-            for (int i = 0; i < printServiceCount; i++) {
-                PrintServiceInfo printService = printServices.get(i);
-                adapter.add(printService.getResolveInfo().loadLabel(
-                        getActivity().getPackageManager()).toString());
+                mEnabledPrintServices.put(service.getComponentName(), service);
             }
+        }
 
-            final String searchUri = Settings.Secure.getString(getActivity().getContentResolver(),
-                    Settings.Secure.PRINT_SERVICE_SEARCH_URI);
-            final Intent viewIntent;
-            if (!TextUtils.isEmpty(searchUri)) {
-                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri));
-                if (getActivity().getPackageManager().resolveActivity(intent, 0) != null) {
-                    viewIntent = intent;
-                    mAddPrintServiceItem = getString(R.string.add_print_service_label);
-                    adapter.add(mAddPrintServiceItem);
-                } else {
-                    viewIntent = null;
-                }
-            } else {
-                viewIntent = null;
-            }
+        onPrintServicesUpdate();
+    }
 
-            builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    String item = adapter.getItem(which);
-                    if (item.equals(mAddPrintServiceItem)) {
-                        try {
-                            startActivity(viewIntent);
-                        } catch (ActivityNotFoundException anfe) {
-                            Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
-                        }
-                    } else {
-                        PrintServiceInfo printService = printServices.get(which);
-                        ComponentName componentName = new ComponentName(
-                                printService.getResolveInfo().serviceInfo.packageName,
-                                printService.getAddPrintersActivityName());
-                        Intent intent = new Intent(Intent.ACTION_MAIN);
-                        intent.setComponent(componentName);
-                        try {
-                            startActivity(intent);
-                        } catch (ActivityNotFoundException anfe) {
-                            Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
-                        }
-                    }
-                }
-            });
-
-            return builder.create();
+    @Override
+    public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+        if (!isFinishing()) {
+            onLoadFinished(loader, null);
         }
     }
 
@@ -592,14 +468,40 @@
         @Override
         public int getCount() {
             synchronized (mLock) {
-                return mFilteredPrinters.size();
+                if (mFilteredPrinters.isEmpty()) {
+                    return 0;
+                } else {
+                    // Add "add printer" item to the end of the list. If the list is empty there is
+                    // a link on the empty view
+                    return mFilteredPrinters.size() + 1;
+                }
+            }
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 2;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            // Use separate view types for the "add printer" item an the items referring to printers
+            if (getItem(position) == null) {
+                return 0;
+            } else {
+                return 1;
             }
         }
 
         @Override
         public Object getItem(int position) {
             synchronized (mLock) {
-                return mFilteredPrinters.get(position);
+                if (position < mFilteredPrinters.size()) {
+                    return mFilteredPrinters.get(position);
+                } else {
+                    // Return null to mark this as the "add printer item"
+                    return null;
+                }
             }
         }
 
@@ -615,6 +517,18 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
+            final PrinterInfo printer = (PrinterInfo) getItem(position);
+
+            // Handle "add printer item"
+            if (printer == null) {
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(R.layout.add_printer_list_item,
+                            parent, false);
+                }
+
+                return convertView;
+            }
+
             if (convertView == null) {
                 convertView = getLayoutInflater().inflate(
                         R.layout.printer_list_item, parent, false);
@@ -622,19 +536,16 @@
 
             convertView.setEnabled(isActionable(position));
 
-            final PrinterInfo printer = (PrinterInfo) getItem(position);
 
             CharSequence title = printer.getName();
             Drawable icon = printer.loadIcon(SelectPrinterActivity.this);
 
-            CharSequence printServiceLabel;
-            try {
-                PackageInfo packageInfo = getPackageManager().getPackageInfo(
-                        printer.getId().getServiceName().getPackageName(), 0);
+            PrintServiceInfo service = mEnabledPrintServices.get(printer.getId().getServiceName());
 
-                printServiceLabel = packageInfo.applicationInfo.loadLabel(getPackageManager());
-            } catch (NameNotFoundException e) {
-                printServiceLabel = null;
+            CharSequence printServiceLabel = null;
+            if (service != null) {
+                printServiceLabel = service.getResolveInfo().loadLabel(getPackageManager())
+                        .toString();
             }
 
             CharSequence description = printer.getDescription();
@@ -661,7 +572,7 @@
                 subtitleView.setVisibility(View.GONE);
             }
 
-            ImageView moreInfoView = (ImageView) convertView.findViewById(R.id.more_info);
+            LinearLayout moreInfoView = (LinearLayout) convertView.findViewById(R.id.more_info);
             if (printer.getInfoIntent() != null) {
                 moreInfoView.setVisibility(View.VISIBLE);
                 moreInfoView.setOnClickListener(new OnClickListener() {
@@ -699,7 +610,12 @@
 
         public boolean isActionable(int position) {
             PrinterInfo printer =  (PrinterInfo) getItem(position);
-            return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
+
+            if (printer == null) {
+                return true;
+            } else {
+                return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
+            }
         }
     }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
index 2b317b3..7425c03 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
@@ -18,7 +18,9 @@
 
 import android.print.PageRange;
 import android.print.PrintDocumentInfo;
+import android.util.Pair;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 
@@ -155,6 +157,167 @@
     }
 
     /**
+     * Return the next position after {@code pos} that is not a space character.
+     *
+     * @param s   The string to parse
+     * @param pos The starting position
+     *
+     * @return The position of the first space character
+     */
+    private static int readWhiteSpace(CharSequence s, int pos) {
+        while (pos < s.length() && s.charAt(pos) == ' ') {
+            pos++;
+        }
+
+        return pos;
+    }
+
+    /**
+     * Read a number from a string at a certain position.
+     *
+     * @param s   The string to parse
+     * @param pos The starting position
+     *
+     * @return The position after the number + the number read or null if the number was not found
+     */
+    private static Pair<Integer, Integer> readNumber(CharSequence s, int pos) {
+        Integer result = 0;
+        while (pos < s.length() && s.charAt(pos) >= '0' && s.charAt(pos) <= '9') {
+            // Number cannot start with 0
+            if (result == 0 && s.charAt(pos) == '0') {
+                break;
+            }
+            result = result * 10 + (s.charAt(pos) - '0');
+            // Abort on overflow
+            if (result < 0) {
+                break;
+            }
+            pos++;
+        }
+
+        // 0 is not a valid page number
+        if (result == 0) {
+            return new Pair<>(pos, null);
+        } else {
+            return new Pair<>(pos, result);
+        }
+    }
+
+    /**
+     * Read a single character from a string at a certain position.
+     *
+     * @param s            The string to parse
+     * @param pos          The starting position
+     * @param expectedChar The character to read
+     *
+     * @return The position after the character + the character read or null if the character was
+     *         not found
+     */
+    private static Pair<Integer, Character> readChar(CharSequence s, int pos, char expectedChar) {
+        if (pos < s.length() && s.charAt(pos) == expectedChar) {
+            return new Pair<>(pos + 1, expectedChar);
+        } else {
+            return new Pair<>(pos, null);
+        }
+    }
+
+    /**
+     * Read a page range character from a string at a certain position.
+     *
+     * @param s             The string to parse
+     * @param pos           The starting position
+     * @param maxPageNumber The highest page number to accept.
+     *
+     * @return The position after the page range + the page range read or null if the page range was
+     *         not found
+     */
+    private static Pair<Integer, PageRange> readRange(CharSequence s, int pos, int maxPageNumber) {
+        Pair<Integer, Integer> retInt;
+        Pair<Integer, Character> retChar;
+
+        Character comma;
+        if (pos == 0) {
+            // When we reading the first range, we do not want to have a comma
+            comma = ',';
+        } else {
+            retChar = readChar(s, pos, ',');
+            pos = retChar.first;
+            comma = retChar.second;
+        }
+
+        pos = readWhiteSpace(s, pos);
+
+        retInt = readNumber(s, pos);
+        pos = retInt.first;
+        Integer start = retInt.second;
+
+        pos = readWhiteSpace(s, pos);
+
+        retChar = readChar(s, pos, '-');
+        pos = retChar.first;
+        Character separator = retChar.second;
+
+        pos = readWhiteSpace(s, pos);
+
+        retInt = readNumber(s, pos);
+        pos = retInt.first;
+        Integer end = retInt.second;
+
+        pos = readWhiteSpace(s, pos);
+
+        if (comma != null &&
+                // range, maybe unbounded
+                ((separator != null && (start != null || end != null)) ||
+                        // single page
+                        (separator == null && start != null && end == null))) {
+            if (start == null) {
+                start = 1;
+            }
+
+            if (end == null) {
+                if (separator == null) {
+                    end = start;
+                } else {
+                    end = maxPageNumber;
+                }
+            }
+
+            if (start <= end && start >= 1 && end <= maxPageNumber) {
+                return new Pair<>(pos, new PageRange(start - 1, end - 1));
+            }
+        }
+
+        return new Pair<>(pos, null);
+    }
+
+    /**
+     * Parse a string into an array of page ranges.
+     *
+     * @param s             The string to parse
+     * @param maxPageNumber The highest page number to accept.
+     *
+     * @return The parsed ranges or null if the string could not be parsed.
+     */
+    public static PageRange[] parsePageRanges(CharSequence s, int maxPageNumber) {
+        ArrayList<PageRange> ranges = new ArrayList<>();
+
+        int pos = 0;
+        while (pos < s.length()) {
+            Pair<Integer, PageRange> retRange = readRange(s, pos, maxPageNumber);
+
+            if (retRange.second == null) {
+                ranges.clear();
+                break;
+            }
+
+            ranges.add(retRange.second);
+            pos = retRange.first;
+        }
+
+        return PageRangeUtils.normalize(ranges.toArray(new PageRange[ranges.size()]));
+    }
+
+    /**
      * Offsets a the start and end of page ranges with the given value.
      *
      * @param pageRanges The page ranges to offset.
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java
deleted file mode 100644
index 446952d..0000000
--- a/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java
+++ /dev/null
@@ -1,56 +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.printspooler.util;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ServiceInfo;
-import android.print.PrintManager;
-import android.printservice.PrintServiceInfo;
-
-import java.util.List;
-
-public class PrintOptionUtils {
-
-    private PrintOptionUtils() {
-        /* ignore - hide constructor */
-    }
-
-    /**
-     * Gets the advanced options activity name for a print service.
-     *
-     * @param context Context for accessing system resources.
-     * @param serviceName The print service name.
-     * @return The advanced options activity name or null.
-     */
-    public static String getAdvancedOptionsActivityName(Context context,
-            ComponentName serviceName) {
-        PrintManager printManager = (PrintManager) context.getSystemService(
-                Context.PRINT_SERVICE);
-        List<PrintServiceInfo> printServices = printManager.getEnabledPrintServices();
-        final int printServiceCount = printServices.size();
-        for (int i = 0; i < printServiceCount; i ++) {
-            PrintServiceInfo printServiceInfo = printServices.get(i);
-            ServiceInfo serviceInfo = printServiceInfo.getResolveInfo().serviceInfo;
-            if (serviceInfo.name.equals(serviceName.getClassName())
-                    && serviceInfo.packageName.equals(serviceName.getPackageName())) {
-                return printServiceInfo.getAdvancedOptionsActivityName();
-            }
-        }
-        return null;
-    }
-}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
index b792789..7ef42d1 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
@@ -44,8 +44,12 @@
 
     private Drawable mEmptyState;
 
+    private Drawable mErrorState;
+
     private boolean mContentRequested;
 
+    private boolean mIsFailed;
+
     public PageContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -53,19 +57,26 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         mContentRequested = false;
+
         requestPageContentIfNeeded();
     }
 
     @Override
-    public void onPageContentAvailable(BitmapDrawable content) {
-        setBackground(content);
+    public void onPageContentAvailable(BitmapDrawable renderedPage) {
+        mIsFailed = (renderedPage == null);
+
+        if (mIsFailed) {
+            setBackground(mErrorState);
+        } else {
+            setBackground(renderedPage);
+        }
     }
 
     public PageContentProvider getPageContentProvider() {
         return mProvider;
     }
 
-    public void init(PageContentProvider provider, Drawable emptyState,
+    public void init(PageContentProvider provider, Drawable emptyState, Drawable errorState,
             MediaSize mediaSize, Margins minMargins) {
         final boolean providerChanged = (mProvider == null)
                 ? provider != null : !mProvider.equals(provider);
@@ -81,17 +92,21 @@
             return;
         }
 
+        mIsFailed = false;
         mProvider = provider;
         mMediaSize = mediaSize;
         mMinMargins = minMargins;
 
         mEmptyState = emptyState;
+        mErrorState = errorState;
         mContentRequested = false;
 
         // If there is no provider we want immediately to switch to
         // the empty state, so pages with no content appear blank.
-        if (mProvider == null && getBackground() != mEmptyState) {
+        if (mProvider == null) {
             setBackground(mEmptyState);
+        } else if (mIsFailed) {
+            setBackground(mErrorState);
         }
 
         requestPageContentIfNeeded();
diff --git a/packages/SettingsLib/res/drawable/ic_info.xml b/packages/SettingsLib/res/drawable/ic_info.xml
new file mode 100644
index 0000000..afe7e6b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_info.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml b/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml
deleted file mode 100644
index b3d7cf9..0000000
--- a/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="21dp"
-        android:height="21dp"
-        android:viewportWidth="21.0"
-        android:viewportHeight="21.0"
-        android:tint="?android:attr/colorAccent">
-    <path
-            android:fillColor="@android:color/white"
-            android:pathData="M8,16c1.1,0,2-0.9,2-2s-0.9-2-2-2s-2,0.9-2,2S6.9,16,8,16zM14,7h-1V5c0-2.8-2.2-5-5-5S3,2.2,3,5v2H2C0.9,7,0,7.9,0,9v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V9C16,7.9,15.1,7,14,7z M4.9,5c0-1.7,1.4-3.1,3.1-3.1s3.1,1.4,3.1,3.1v2H4.9V5z M14,19H2V9h12V19z" />
-</vector>
diff --git a/packages/SettingsLib/res/layout/restricted_icon.xml b/packages/SettingsLib/res/layout/restricted_icon.xml
new file mode 100644
index 0000000..724a524
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_icon.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/restricted_icon"
+    android:layout_width="@dimen/restricted_icon_size"
+    android:layout_height="@dimen/restricted_icon_size"
+    android:src="@drawable/ic_info" />
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
new file mode 100644
index 0000000..6183812
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/restricted_icon"
+        android:layout_width="@dimen/restricted_icon_size"
+        android:layout_height="@dimen/restricted_icon_size"
+        android:src="@drawable/ic_info"
+        android:gravity="end|center_vertical" />
+    <!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
+    <Switch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+android:id/switch_widget"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:clickable="false"
+        android:background="@null" />
+</merge>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml
index 9e5d029..67296a6 100644
--- a/packages/SettingsLib/res/layout/settings_with_drawer.xml
+++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml
@@ -17,14 +17,15 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/drawer_layout"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:background="?android:attr/colorPrimaryDark">
     <!-- The main content view -->
     <LinearLayout
         android:id="@+id/content_parent"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
-        android:fitsSystemWindows="false" >
+        android:fitsSystemWindows="true" >
         <FrameLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -36,14 +37,14 @@
                 android:layout_height="wrap_content"
                 android:navigationContentDescription="@*android:string/action_bar_up_description"
                 android:theme="?android:attr/actionBarTheme"
-                android:paddingTop="@*android:dimen/status_bar_height"
                 style="?android:attr/toolbarStyle"
                 android:background="?android:attr/colorPrimary" />
         </FrameLayout>
         <FrameLayout
             android:id="@+id/content_frame"
             android:layout_width="match_parent"
-            android:layout_height="fill_parent" />
+            android:layout_height="fill_parent"
+            android:background="?android:attr/windowBackground" />
     </LinearLayout>
     <!-- The navigation drawer -->
     <ListView android:id="@+id/left_drawer"
diff --git a/packages/SettingsLib/res/layout/usage_view.xml b/packages/SettingsLib/res/layout/usage_view.xml
index 28981f8..aa1a046 100644
--- a/packages/SettingsLib/res/layout/usage_view.xml
+++ b/packages/SettingsLib/res/layout/usage_view.xml
@@ -22,7 +22,8 @@
     <LinearLayout
         android:id="@+id/graph_label_group"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/usage_graph_area_height"
+        android:layout_height="0dp"
+        android:layout_weight="1"
         android:orientation="horizontal"
         android:clipChildren="false"
         android:clipToPadding="false">
@@ -37,6 +38,7 @@
                 layout="@layout/usage_side_label" />
 
             <Space
+                android:id="@+id/space1"
                 android:layout_width="wrap_content"
                 android:layout_height="0dp"
                 android:layout_weight="1" />
@@ -45,6 +47,7 @@
                 layout="@layout/usage_side_label" />
 
             <Space
+                android:id="@+id/space2"
                 android:layout_width="wrap_content"
                 android:layout_height="0dp"
                 android:layout_weight="1" />
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 99699b9..c44f0d0 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Teks-na-spraak-uitset"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Spraaktempo"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Spoed waarteen die teks gepraat word"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Toonhoogte"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Beïnvloed die klank van die gesintetiseerde spraak"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Taal"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Gebruik stelseltaal"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Taal nie gekies nie"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Wys alle ANRe"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Wys Program reageer nie-dialoog vir agtergrond programme"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Programme verplig ekstern toegelaat"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Laat enige program na ekstern geskryf word, ongeag manifeswaardes"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Maak dat enige program in eksterne berging geskryf kan word, ongeag manifeswaardes"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Verplig verstelbare groottes vir aktiwiteite"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Maak die groottes van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Aktiveer vormvrye-Windows"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktief. Tik om te wissel."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Lopende dienste"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Sien en beheer dienste wat tans loop"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nagmodus"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Gedeaktiveer"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Altyd aan"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Outomaties"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktiveer multiproses-WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Laat loop WebView-leweraars in \'n geïsoleerde proses."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stel WebView-implementering"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Die gekose WebView-toepassing is gedeaktiveer, maar moet geaktiveer wees om gebruik te word. Wil jy dit aktiveer?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Hierdie keuse is nie meer geldig nie. Probeer weer."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Skakel om na lêerenkripsie"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Skakel om …"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Lêerenkripsie is reeds uitgevoer"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierdie kenmerk is eksperimenteel en kan werkverrigting beïnvloed."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ongeveer <xliff:g id="TIME">%1$s</xliff:g> oor"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – sowat <xliff:g id="TIME">%2$s</xliff:g> oor"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot vol"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot vol op WS"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot vol oor USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot vol vanaf draadloos"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Laai"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Laai tans op WS"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laai tans oor USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Laai tans draadloos"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Laai nie"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Laai nie"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Vol"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Gedeaktiveer deur administrateur"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Beheer deur administrateur"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Geaktiveer deur administrateur"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Gedeaktiveer deur administrateur"</string>
     <string name="home" msgid="8263346537524314127">"Tuis"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> gelede"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> oor"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Klein"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Verstek"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Groot"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Groter"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootste"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 0e363b5..cd05135 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"የፅሁፍ- ወደ- ንግግር ውፅዓት"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">" የንግግር ደረጃ"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"የተነገረበትን ፅሁፍ አፍጥን"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"ቅላፄ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"በሲንተሲስ በተሠራው ድምፅ ላይ ተፅዕኖ ያሳድራል"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ቋንቋ"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"የስርዓት ቋንቋ ተጠቀም"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ቋንቋ አልተመረጠም"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"ሁሉንም ANRs አሳይ"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"ለዳራ መተግበሪያዎች ምላሽ የማይሰጥ መገናኛ ትግበራ አሳይ"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"በውጫዊ ላይ ሃይል ይፈቀዳል"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"አንጸባራቂ እሴቶች ግምት ውስጥ ሳይገቡ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻ ለመጻፍ ብቁ ያደርጋል።"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"የዝርዝር ሰነዶች እሴቶች ግምት ውስጥ ሳያስገባ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻው ለመጻፍ ብቁ ያደርጋል"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች መጠናቸው የሚቀየሩ እንዲሆኑ ያደርጋቸዋል።"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"ገቢር። ለመቀያየር ነካ ያድርጉ።"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"አሂድ አገልግሎቶች"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"በአሁኑጊዜ እየሄዱ ያሉ አገልግሎቶችን ተቆጣጠር እና እይ"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"የሌሊት ሁነታ"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"ተሰናክሏል"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"ሁልጊዜ ይበራል"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ራስ-ሰር"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ባለብዙ-ሂደት WebViewን አንቃ"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"የWebView ምስል ሰሪዎችን በተገለለ ሂደት ውስጥ አሂድ።"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"የWebView ትግበራ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"የWebView ትግበራን ያዘጋጁ"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"የተመረጠው WebView ትግበራ ተሰናክሏል፣ እና ጥቅም ላይ እንዲውል መንቃት አለበት፣ ሊያነቁት ይፈልጋሉ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ይህ ምርጫ ከአሁን በኋላ የሚሰራ አይደለም። እንደገና ይሞክሩ።"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ወደ ፋይል ምሥጠራ ቀይር"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ለውጥ…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ፋይል አስቀድሞ ተመስጥሯል"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ይህ ባህሪ የሙከራ ነውና አፈጻጸም ላይ ተጽዕኖ ሊኖረው ይችላል።"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g> ገደማ ቀርቷል"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ገደማ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> እስከሚሞላ ድረስ"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> በኤሲ ላይ እስከሚሞላ ድረስ"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> በዩኤስቢ ላይ እስከሚሞላ ድረስ"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> በገመድ አልባ ላይ እስከሚሞላ ድረስ"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"ያልታወቀ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ኃይል በመሙላት ላይ"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"በኤሲ ሃይል በመሙላት ላይ"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"በዩኤስቢ ሃይል በመሙላት ላይ"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"በገመድ አልባ ሃይል በመሙላት ላይ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ባትሪ እየሞላ አይደለም"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ኃይል  እየሞላ አይደለም"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ሙሉነው"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"በአስተዳዳሪ የተሰናከለ"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"በአስተዳዳሪ ቁጥጥር የተደረገበት"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"በአስተዳዳሪ የነቃ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"በአስተዳዳሪ የተሰናከለ"</string>
     <string name="home" msgid="8263346537524314127">"መነሻ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"ከ<xliff:g id="ID_1">%1$s</xliff:g> በፊት"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ቀርቷል"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ትንሽ"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ነባሪ"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ትልቅ"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ተለቅ ያለ"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"በጣም ተለቅ ያለ"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index c757b71..b3f55eb 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"إخراج تحويل النص إلى كلام"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"معدل سرعة الكلام"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"سرعة نطق الكلام"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"درجة الصوت"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"للتأثير في نبرة الكلام المُرَكَّب"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"اللغة"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"استخدام لغة النظام"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"اللغة غير محددة"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"‏عرض جميع رسائل ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"عرض مربع الحوار \"التطبيق لا يستجيب\" مع تطبيقات الخلفية"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"فرض السماح للتطبيقات على الخارجي"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"تأهيل أي تطبيق بحيث تتم كتابته على سعة تخزين خارجية، بغض النظر عن قيم البيان"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"تأهيل أي تطبيق بحيث تتم كتابته على وحدة تخزين خارجية، بغض النظر عن قيم البيان"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"فرض إمكانية تغيير على الأنشطة"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"تمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"تمكين النوافذ الحرة"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"نشط، انقر للتبديل."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"الخدمات قيد التشغيل"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"الوضع الليلي"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"معطَّل"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"التشغيل دائمًا"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"تلقائيًا"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"تمكين عرض ويب متعدد العمليات"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"تشغيل أجهزة عرض الويب في عملية منفصلة."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"‏تطبيق WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏تعيين تطبيق WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏إن تنفيذ ميزة WebView التي تم اختيارها معطَّل، ويجب تمكين هذه الميزة ليتسنى استخدامها، فهل تريد تمكينها؟"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"لم يعد هذا الاختيار صالحًا. أعد المحاولة."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"التحويل إلى تشفير ملفات"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تحويل…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"تم استخدام تشفير ملفات من قبل"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"هذه الميزة تجريبية وقد تؤثر في الأداء."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"يتبقى <xliff:g id="TIME">%1$s</xliff:g> تقريبًا"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - تبقى <xliff:g id="TIME">%2$s</xliff:g> تقريبًا"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى الاكتمال"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى الاكتمال باستخدام التيار المتردد"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"‏<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى الاكتمال عبر USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى الاكتمال بالشحن اللاسلكي"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"غير معروف"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"شحن"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"جارٍ الشحن بتيار متردد"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"‏جارٍ الشحن عبر USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"جارٍ الشحن لاسلكيًا"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"لا يتم الشحن"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"لا يتم الشحن"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ممتلئة"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"تم التعطيل بواسطة المشرف"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"إعدادات يتحكم فيها المشرف"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"تم التمكين بواسطة المشرف"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"تم التعطيل بواسطة المشرف"</string>
     <string name="home" msgid="8263346537524314127">"الشاشة الرئيسية"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"يتبقى <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"صغير"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"افتراضي"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"كبير"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"أكبر"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"أكبر مستوى"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 61008b9..9a099af 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Mətndən-nitqə çıxışı"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Nitq diapazonu"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Mətnin səsləndirilmə sürəti"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitç"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Sintez olunmuş nitqin tonuna təsir edir"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Dil"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Sistem dili işlədin"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Dil seçilməyib"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Bütün ANRları göstər"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Arxa tətbiqlər dialoquna cavab verməyən tətbiqi göstər"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Tətbiqlərə xaricdən məcburi icazə"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bəyannamə dəyərlərindən aslı olmayaraq, bütün fəaliyyətləri çoxsaylı pəncərə üçün dəyişkən ölçülü edin."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Freeform windows aktiv edin"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivdir. Keçid etmək üçün basın."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"İşləyən xidmətlər"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Hazırda prosesdə olan xidmətləri görüntüləyin və onlara nəzarət edin"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Gecə rejimi"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Qeyri-aktiv"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Həmişə aktiv"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Çox prosesli WebView\'nu aktiv edin"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView rendererləri təcrid olunmuş prosesdə işlədin."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView icrası"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView icrasını ayarlayın"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Seçilmiş WebView icrası deaktiv edildi, istifadəsi üçün aktiv edilməlidir, aktivləşdirmək istəyirsiniz?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Bu seçim artıq etibarlı deyil. Yenidən cəhd edin."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Fayl şifrələnməsinə çevirin"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Çevirin..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl artıq şifrələnib"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya eksperimentaldır və performansa təsir edə bilər."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Təxminən <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - təxminən <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> dolana qədər"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC üzərindən dolana qədər"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB üzərindən dolana qədər"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> naqilsiz üzərindən dolana qədər"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Naməlum"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Enerji doldurma"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Dəyişən cərəyanda qidalanır"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB üzərindən qidalanır"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Naqilsiz qidalanır"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Doldurulmur"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Enerji doldurulmur"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Tam"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administrator tərəfindən deaktiv edildi"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Admin tərəfindən nəzarət olunur"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Administrator tərəfindən aktiv edildi"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Administrator tərəfindən deaktiv edildi"</string>
     <string name="home" msgid="8263346537524314127">"Əsas səhifə"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> əvvəl"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qalıb"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kiçik"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Defolt"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Böyük"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Daha böyük"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ən böyük"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 7021ca6..85b6ac2 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Izlaz za pretvaranje teksta u govor"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina izgovaranja teksta"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Nivo"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utiče na ton sintetizovanog govora"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Koristi jezik sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije izabran"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Prikaži sve ANR-ove"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Prikaži dijalog Aplikacija ne reaguje za aplikacije u pozadini"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Prinudno dozvoli aplikacije u spoljnoj"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Prinudno omogući promenu veličine aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore proizvoljnog formata"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivna. Dodirnite da biste je deaktivirali."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Noćni režim"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Uvek uključeno"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogući višeprocesni WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrećite WebView prikazivače u okviru izolovanog procesa."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izabrana primena WebView-a je onemogućena, a mora da bude omogućena radi korišćenja. Želite li da je omogućite?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Pokušajte ponovo."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuj u šifrovanje datoteka"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuj..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Već se koristi šifrovanje datoteka"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna i može da utiče na performanse."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo oko <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> dok se ne napuni"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> dok se ne napuni punjačem"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> dok se ne napuni preko USB-a"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> dok se ne napuni bežično"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Punjenje"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Punjenje preko punjača"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Punjenje preko USB-a"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bežično punjenje"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ne puni se"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio je administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontroliše administrator"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio je administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio je administrator"</string>
     <string name="home" msgid="8263346537524314127">"Početni"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Pre <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mali"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Podrazumevano"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliki"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veći"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveći"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be-rBY/arrays.xml b/packages/SettingsLib/res/values-be-rBY/arrays.xml
new file mode 100644
index 0000000..63b8b9b
--- /dev/null
+++ b/packages/SettingsLib/res/values-be-rBY/arrays.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Сканаванне..."</item>
+    <item msgid="8513729475867537913">"Падлучэнне..."</item>
+    <item msgid="515055375277271756">"Аўтэнтыфікацыя..."</item>
+    <item msgid="1943354004029184381">"Атрыманне IP-адраса..."</item>
+    <item msgid="4221763391123233270">"Падлучана"</item>
+    <item msgid="624838831631122137">"Прыпынена"</item>
+    <item msgid="7979680559596111948">"Адлучэнне..."</item>
+    <item msgid="1634960474403853625">"Адключана"</item>
+    <item msgid="746097431216080650">"Няўдала"</item>
+    <item msgid="6367044185730295334">"Заблакiравана"</item>
+    <item msgid="503942654197908005">"Дрэнная сувязь часова пазбегнута"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Сканаванне..."</item>
+    <item msgid="355508996603873860">"Падключэнне да сеткі <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Аўтэнтыфікацыя ў сетцы <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Атрыманне IP-адраса ў сетцы <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Падключаны да сеткi <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Прыпынена"</item>
+    <item msgid="7698638434317271902">"Адключэнне ад сеткі <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Адключана"</item>
+    <item msgid="8578370891960825148">"Няўдала"</item>
+    <item msgid="5660739516542454527">"Заблакiравана"</item>
+    <item msgid="1805837518286731242">"Дрэнная сувязь часова пазбегнута"</item>
+  </string-array>
+  <string-array name="hdcp_checking_titles">
+    <item msgid="441827799230089869">"Ніколі не правяраць"</item>
+    <item msgid="6042769699089883931">"Праверка толькi для змесціва, абароненага DRM"</item>
+    <item msgid="9174900380056846820">"Заўсёды правяраць"</item>
+  </string-array>
+  <string-array name="hdcp_checking_summaries">
+    <item msgid="505558545611516707">"Ніколі не выкарыстоўваць праверку HDCP"</item>
+    <item msgid="3878793616631049349">"Выкарыстанне праверкі HDCP только для змесціва, абароненага DRM"</item>
+    <item msgid="45075631231212732">"Заўсёды выкарыстоўваць праверку HDCP"</item>
+  </string-array>
+  <string-array name="select_logd_size_titles">
+    <item msgid="8665206199209698501">"Выкл."</item>
+    <item msgid="1593289376502312923">"64K"</item>
+    <item msgid="487545340236145324">"256K"</item>
+    <item msgid="2423528675294333831">"1M"</item>
+    <item msgid="180883774509476541">"4M"</item>
+    <item msgid="2803199102589126938">"16M"</item>
+  </string-array>
+  <string-array name="select_logd_size_lowram_titles">
+    <item msgid="6089470720451068364">"Выкл."</item>
+    <item msgid="4622460333038586791">"64K"</item>
+    <item msgid="2212125625169582330">"256K"</item>
+    <item msgid="1704946766699242653">"1M"</item>
+  </string-array>
+  <string-array name="select_logd_size_summaries">
+    <item msgid="6921048829791179331">"Выкл."</item>
+    <item msgid="2969458029344750262">"64K на буфер журнала"</item>
+    <item msgid="1342285115665698168">"256K на буфер журнала"</item>
+    <item msgid="1314234299552254621">"1M на буфер журнала"</item>
+    <item msgid="3606047780792894151">"4M на буфер журнала"</item>
+    <item msgid="5431354956856655120">"16M на буфер журнала"</item>
+  </string-array>
+  <string-array name="window_animation_scale_entries">
+    <item msgid="8134156599370824081">"Анімацыя выключаная"</item>
+    <item msgid="6624864048416710414">"Маштаб анімацыі 0.5x"</item>
+    <item msgid="2219332261255416635">"Маштаб анімацыі 1x"</item>
+    <item msgid="3544428804137048509">"Маштаб анімацыі 1,5x"</item>
+    <item msgid="3110710404225974514">"Маштаб анімацыі 2x"</item>
+    <item msgid="4402738611528318731">"Маштаб анімацыі 5x"</item>
+    <item msgid="6189539267968330656">"Маштаб анімацыі 10x"</item>
+  </string-array>
+  <string-array name="transition_animation_scale_entries">
+    <item msgid="8464255836173039442">"Анімацыя выключана"</item>
+    <item msgid="3375781541913316411">"Маштаб анімацыі 0.5x"</item>
+    <item msgid="1991041427801869945">"Маштаб анімацыі 1x"</item>
+    <item msgid="4012689927622382874">"Маштаб анімацыі 1,5x"</item>
+    <item msgid="3289156759925947169">"Маштаб анімацыі 2x"</item>
+    <item msgid="7705857441213621835">"Маштаб анімацыі 5x"</item>
+    <item msgid="6660750935954853365">"Маштаб анімацыі 10x"</item>
+  </string-array>
+  <string-array name="animator_duration_scale_entries">
+    <item msgid="6039901060648228241">"Анімацыя выключана"</item>
+    <item msgid="1138649021950863198">"Маштаб анімацыі 0.5x"</item>
+    <item msgid="4394388961370833040">"Маштаб анімацыі 1x"</item>
+    <item msgid="8125427921655194973">"Маштаб анімацыі 1.5x"</item>
+    <item msgid="3334024790739189573">"Маштаб анімацыі 2x"</item>
+    <item msgid="3170120558236848008">"Маштаб анімацыі 5x"</item>
+    <item msgid="1069584980746680398">"Маштаб анімацыі 10x"</item>
+  </string-array>
+  <string-array name="overlay_display_devices_entries">
+    <item msgid="1606809880904982133">"Няма"</item>
+    <item msgid="9033194758688161545">"480p"</item>
+    <item msgid="1025306206556583600">"480p (бяспечны)"</item>
+    <item msgid="1853913333042744661">"720p"</item>
+    <item msgid="3414540279805870511">"720p (бяспечны)"</item>
+    <item msgid="9039818062847141551">"1080p"</item>
+    <item msgid="4939496949750174834">"1080p (бяспечны)"</item>
+    <item msgid="1833612718524903568">"4K"</item>
+    <item msgid="238303513127879234">"4K (бяспечны)"</item>
+    <item msgid="3547211260846843098">"4K (шырокамаштабны)"</item>
+    <item msgid="5411365648951414254">"4K (шырокамаштабны, бяспечны)"</item>
+    <item msgid="1311305077526792901">"720p, 1080p (два экраны)"</item>
+  </string-array>
+  <string-array name="enable_opengl_traces_entries">
+    <item msgid="3191973083884253830">"Няма"</item>
+    <item msgid="9089630089455370183">"Logcat"</item>
+    <item msgid="5397807424362304288">"Systrace (Graphics)"</item>
+    <item msgid="1340692776955662664">"Выклікаць стэк на glGetError"</item>
+  </string-array>
+  <string-array name="show_non_rect_clip_entries">
+    <item msgid="993742912147090253">"Адключана"</item>
+    <item msgid="675719912558941285">"Намаляваць непрамавугольную вобласць кліпа сінім колерам"</item>
+    <item msgid="1064373276095698656">"Вылучыце выпрабаваныя каманды малявання зялёным колерам"</item>
+  </string-array>
+  <string-array name="track_frame_time_entries">
+    <item msgid="2193584639058893150">"Адключана"</item>
+    <item msgid="2751513398307949636">"На экране ў выглядзе слупкоў"</item>
+    <item msgid="1851438178120770973">"У абалонцы adb dumpsys gfxinfo"</item>
+  </string-array>
+  <string-array name="debug_hw_overdraw_entries">
+    <item msgid="8190572633763871652">"Адключаны"</item>
+    <item msgid="7688197031296835369">"Паказаць вобласці з перабольшваннем"</item>
+    <item msgid="2290859360633824369">"Паказаць вобласці для дэйтэранамаліі"</item>
+  </string-array>
+  <string-array name="app_process_limit_entries">
+    <item msgid="3401625457385943795">"Стандартны ліміт"</item>
+    <item msgid="4071574792028999443">"Няма фонавых працэсаў"</item>
+    <item msgid="4810006996171705398">"Не больш за 1  працэс"</item>
+    <item msgid="8586370216857360863">"Не больш за 2 працэсы"</item>
+    <item msgid="836593137872605381">"Не больш за 3 працэсы"</item>
+    <item msgid="7899496259191969307">"Не больш за 4 працэсы"</item>
+  </string-array>
+  <string-array name="usb_configuration_titles">
+    <item msgid="488237561639712799">"Зарадка"</item>
+    <item msgid="5220695614993094977">"MTP (пратакол перадачы медыя)"</item>
+    <item msgid="2086000968159047375">"PTP (пратакол перадачы відарысаў)"</item>
+    <item msgid="7398830860950841822">"RNDIS (USB-Ethernet)"</item>
+    <item msgid="1718924214939774352">"Крыніца аўдыя"</item>
+    <item msgid="8126315616613006284">"MIDI"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..c8098ec
--- /dev/null
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не атрымлiваецца выканаць сканаванне для сетак"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Няма"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Захавана"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Адключаная"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Збой канфігурацыі IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Збой падлучэння Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Праблема аўтэнтыфікацыі"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Не ў зоне дасягальнасці"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Доступ да інтэрнэту не выяўлены, аўтаматычнае перападлучэнне не адбудзецца."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Хто захаваў: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Падлучана праз памочніка Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Падлучана праз %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Даступна праз %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Падлучана, няма інтэрнэту"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Адключана"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Адключэнне..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Злучэнне..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Падключаны"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Спарванне..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Падключана (без тэлефона)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Падключэнне (без носьбіта)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Падлучана (без доступу да паведамленняў)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Падключаны (без тэлефона або носьбіта)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Аўдыё медыяпрылады"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Аудыё тэлефона"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Перадача файлаў"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Прылада ўводу"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Доступ у інтэрнэт"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Абагуленне кантактаў"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Выкарыстоўваць для абагулення кантактаў"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Прадастаўленне доступу да Інтэрнэту"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Доступ да паведамленняў"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Доступ да SIM-карты"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Падключана да аўдыё медыа"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Падключана да аўдыё тэлефона"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Падключаны да серверу перадачы файлаў"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Падлучана да карты"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Падключана да SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Няма падключэння да серверу перадачы файлаў"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Падключана да прылады ўводу"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Прылада для дост. ў Iнт."</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Сумеснае выкарыстанне лакальнага падключэння да інтэрнэту з прыладай"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Выкарыстоўвайце для доступу ў Інтэрнэт"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Выкарыстоўваць для карты"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Выкарыстоўваць для доступу да SIM-карты"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Выкарыстоўваць для аўдыё-медыя"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Выкарыстоўваць для аўдыё тэлефона"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Выкарыстоўваць для перадачы файлаў"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Выкарыстоўваць для ўводу"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Падлучыць"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СПАЛУЧЫЦЬ"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Адмена"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Спалучэнне дае доступ да вашых кантактаў і гісторыі выклікаў пры падлучэнні."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не атрымалася падключыцца да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не атрымалася спалучыцца з прыладай <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, таму што PIN-код або пароль няправiльныя."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не магу размаўляць з прыладай <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Злучэнне адхілена прыладай <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi выключаны."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi адлучаны."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Адзiн слупок Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Два слупкi Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Тры слупкi Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Поўны сігнал Wi-Fi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"АС Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Выдаленыя прыкладанні"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Выдаленыя прыкладанні і карыстальнiкi"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-мадэм"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Партатыўная кропка доступу"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-мадэм"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Мадэм"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Мадэм і партатыўны хотспот"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Рабочы профіль"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Госць"</string>
+    <string name="unknown" msgid="1592123443519355854">"Невядома"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Карыстальнiк: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Некат. параметры па змаўч. усталяваныя"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Параметры па змаўчанні не ўсталяваныя"</string>
+    <string name="tts_settings" msgid="8186971894801348327">"Налады Text-to-speech"</string>
+    <string name="tts_settings_title" msgid="1237820681016639683">"Выводзіць праз Text-to-speech"</string>
+    <string name="tts_default_rate_title" msgid="6030550998379310088">"Хуткасць гаворкі"</string>
+    <string name="tts_default_rate_summary" msgid="4061815292287182801">"Хуткасць, з якой кажуць тэкст"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Тон"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Уплывае на тон сінтэзаванага маўлення"</string>
+    <string name="tts_default_lang_title" msgid="8018087612299820556">"Мова"</string>
+    <string name="tts_lang_use_system" msgid="2679252467416513208">"Выкарыстоўваць мову сістэмы"</string>
+    <string name="tts_lang_not_selected" msgid="7395787019276734765">"Мова не выбрана"</string>
+    <string name="tts_default_lang_summary" msgid="5219362163902707785">"Задае голас прамаўлення тэкту на канкрэтнай мове"</string>
+    <string name="tts_play_example_title" msgid="7094780383253097230">"Паслухайце прыклад"</string>
+    <string name="tts_play_example_summary" msgid="8029071615047894486">"Прайграць кароткую дэманстрацыю сінтэзу гаворкі"</string>
+    <string name="tts_install_data_title" msgid="4264378440508149986">"Усталяваць галасавыя дадзеныя"</string>
+    <string name="tts_install_data_summary" msgid="5742135732511822589">"Ўсталяваць галасавыя дадзеныя, неабходныя для сінтэзу гаворкі"</string>
+    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Гэты модуль сінтэзу гаворкі можа збіраць увесь тэкст, які будзе прамоўлены, у тым ліку асабістыя дадзеныя, напрыклад паролі і нумары крэдытных карт. Ён адносіцца да модуля <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Уключыць гэты модуль сінтэзу гаворкі?"</string>
+    <string name="tts_engine_network_required" msgid="1190837151485314743">"Гэта мова патрабуе актыўнага падключэння да сеткі, каб выконваць функцыю прамаўлення тэксту."</string>
+    <string name="tts_default_sample_string" msgid="4040835213373086322">"Гэта прыклад сінтэзу гаворкі"</string>
+    <string name="tts_status_title" msgid="7268566550242584413">"Статус мовы па змаўчанні"</string>
+    <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> цалкам падтрымліваецца"</string>
+    <string name="tts_status_requires_network" msgid="6042500821503226892">"Для <xliff:g id="LOCALE">%1$s</xliff:g> патрабуецца падлучэнне да сеткі"</string>
+    <string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> не падтрымліваецца"</string>
+    <string name="tts_status_checking" msgid="5339150797940483592">"Праверка..."</string>
+    <string name="tts_engine_settings_title" msgid="3499112142425680334">"Налады <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
+    <string name="tts_engine_settings_button" msgid="1030512042040722285">"Запуск налад модулю"</string>
+    <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Выбраны модуль"</string>
+    <string name="tts_general_section_title" msgid="4402572014604490502">"Агульныя"</string>
+  <string-array name="tts_rate_entries">
+    <item msgid="6695494874362656215">"Вельмі павольна"</item>
+    <item msgid="4795095314303559268">"Павольна"</item>
+    <item msgid="8903157781070679765">"Звычайна"</item>
+    <item msgid="164347302621392996">"Хутка"</item>
+    <item msgid="5794028588101562009">"Хутчэй"</item>
+    <item msgid="7163942783888652942">"Вельмі хутка"</item>
+    <item msgid="7831712693748700507">"Шпарка"</item>
+    <item msgid="5194774745031751806">"Вельмі шпарка"</item>
+    <item msgid="9085102246155045744">"Максімальна хутка"</item>
+  </string-array>
+    <string name="choose_profile" msgid="8229363046053568878">"Выбраць профіль"</string>
+    <string name="category_personal" msgid="1299663247844969448">"Асабісты"</string>
+    <string name="category_work" msgid="8699184680584175622">"Рабочы"</string>
+    <string name="development_settings_title" msgid="215179176067683667">"Опцыі распрацоўшчыка"</string>
+    <string name="development_settings_enable" msgid="542530994778109538">"Уключыць параметры распрацоўшчыка"</string>
+    <string name="development_settings_summary" msgid="1815795401632854041">"Налада параметраў для распрацоўкі прыкладанняў"</string>
+    <string name="development_settings_not_available" msgid="4308569041701535607">"Параметры распрацоўшчыка недаступныя для гэтага карыстальніка"</string>
+    <string name="vpn_settings_not_available" msgid="956841430176985598">"Налады VPN недаступныя для гэтага карыстальніка"</string>
+    <string name="tethering_settings_not_available" msgid="6765770438438291012">"Налады мадэма недаступныя для гэтага карыстальніка"</string>
+    <string name="apn_settings_not_available" msgid="7873729032165324000">"Налады Імя пункту доступу недаступныя для гэтага карыстальніка"</string>
+    <string name="enable_adb" msgid="7982306934419797485">"Адладка USB"</string>
+    <string name="enable_adb_summary" msgid="4881186971746056635">"Рэжым адладкі, калі USB падключаны"</string>
+    <string name="clear_adb_keys" msgid="4038889221503122743">"Адклікаць дазвол USB-адладкі"</string>
+    <string name="bugreport_in_power" msgid="7923901846375587241">"Ярлык для справаздачы пра памылкі"</string>
+    <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Паказаць кнопку для прыняцця справаздачы пра памылку ў меню сілкавання"</string>
+    <string name="keep_screen_on" msgid="1146389631208760344">"Прадухіляць ад пераходу ў рэжым сну"</string>
+    <string name="keep_screen_on_summary" msgid="2173114350754293009">"Экран ніколі не ўвайдзе ў рэжым сну падчас зарадкі"</string>
+    <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Уключыць журнал адсочвання Bluetooth HCI"</string>
+    <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"Захаваць усе пакеты bluetooth HCI у адным файле"</string>
+    <string name="oem_unlock_enable" msgid="6040763321967327691">"Разблакіроўка OEM"</string>
+    <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Дазволіць разблакіроўку загрузчыка"</string>
+    <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"Дазволіць разблакіроўку OEM?"</string>
+    <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"ПАПЯРЭДЖАННЕ: Пакуль гэты параметр уключаны, абарона прылады не функцыянуе."</string>
+    <string name="mock_location_app" msgid="7966220972812881854">"Выбраць дадатак эмуляцыі месцазнаходжання"</string>
+    <string name="mock_location_app_not_set" msgid="809543285495344223">"Няма дадатку эмуляцыі месцазнаходжання"</string>
+    <string name="mock_location_app_set" msgid="8966420655295102685">"Дадатак эмуляцыі месцазнаходжання: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="debug_networking_category" msgid="7044075693643009662">"Сеткі"</string>
+    <string name="wifi_display_certification" msgid="8611569543791307533">"Сертыфікацыя бесправаднога дысплея"</string>
+    <string name="wifi_verbose_logging" msgid="4203729756047242344">"Уключыць падрабязны журнал Wi‑Fi"</string>
+    <string name="wifi_aggressive_handover" msgid="9194078645887480917">"Агрэсіўны пераход з Wi‑Fi на маб. сетку"</string>
+    <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Заўсёды дазваляць роўмінгавае сканіраванне Wi‑Fi"</string>
+    <string name="legacy_dhcp_client" msgid="694426978909127287">"Выкарыстоўваць кліент DHCP ранейшых версій"</string>
+    <string name="mobile_data_always_on" msgid="7745605759775320362">"Перадача даных мабільнай сувязі заўсёды актыўна"</string>
+    <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Адключыць абсалютны гук"</string>
+    <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Паказаць опцыі сертыфікацыі бесправаднога дысплея"</string>
+    <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Падвыс. узровень дэтал-цыі журнала Wi‑Fi у залежн. ад SSID RSSI у Wi‑Fi Picker"</string>
+    <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Калі ўкл., прылада будзе больш інтэнсіўна імкнуцца перайсці з падлуч. да Wi-Fi на падлуч. да маб. сеткі, калі сігнал Wi‑Fi слабы"</string>
+    <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Дазволіць/забараніць роўмінгавае сканіраванне Wi‑Fi ў залежнасці ад аб\'ёму трафіку даных у інтэрфейсе"</string>
+    <string name="select_logd_size_title" msgid="7433137108348553508">"Памеры буфера для сродку вядзення журнала"</string>
+    <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Выберыце памеры сродку вядзення журнала для буфераў журнала"</string>
+    <string name="select_usb_configuration_title" msgid="2649938511506971843">"Выберыце канфігурацыю USB"</string>
+    <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Выберыце канфігурацыю USB"</string>
+    <string name="allow_mock_location" msgid="2787962564578664888">"Дазволіць несапраўдныя месцы"</string>
+    <string name="allow_mock_location_summary" msgid="317615105156345626">"Дазволіць несапраўдныя месцы"</string>
+    <string name="debug_view_attributes" msgid="6485448367803310384">"Уключыць прагляд атрыбутаў"</string>
+    <string name="legacy_dhcp_client_summary" msgid="163383566317652040">"Выкарыстоўвайце кліент DHCP ад Lollipop замест новага кліента Android DHCP."</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Перадача даных мабільнай сувязі заўсёды актыўна, нават калі актыўна сетка Wi‑Fi (для хуткага пераключэння паміж сеткамі)."</string>
+    <string name="adb_warning_title" msgid="6234463310896563253">"Дазволіць адладку USB?"</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"Адладка USB прызначана толькі для мэтаў распрацоўкі. Яна можа выкарыстоўвацца, каб капіяваць дадзеныя паміж кампутарам і прыладай, усталёўваць прыкладанні на прыладзе без папярэдняга апавяшчэння і чытаць дадзеныя дзённiка."</string>
+    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Адклікаць доступ да адладкі USB з усіх камп\'ютараў, на якiх вы уваходзiлi ў сiстэму?"</string>
+    <string name="dev_settings_warning_title" msgid="7244607768088540165">"Дазволiць налады распрацоўшчыка?"</string>
+    <string name="dev_settings_warning_message" msgid="2298337781139097964">"Гэтыя налады прызначаны толькi для распрацоўшыкаў. Яны могуць выклікаць збоi прылад i ўсталяваных на iх прыкладанняў, а таксама перашкаджаць iх працы."</string>
+    <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Праверце прыкладаннi па USB"</string>
+    <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Праверце прыкладаннi, усталяваныя з дапамогай ADB/ADT, на нестабiльныя паводзiны."</string>
+    <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Адключыць функцыю абсалютнага гуку Bluetooth у выпадку праблем з гукам на аддаленых прыладах, напр., пры непрымальна высокай гучнасці або адсутнасці кіравання."</string>
+    <string name="enable_terminal_title" msgid="95572094356054120">"Лакальны тэрмінал"</string>
+    <string name="enable_terminal_summary" msgid="67667852659359206">"Уключэнне прыкладання тэрмінала, якое прапануе доступ да лакальнай абалонкі"</string>
+    <string name="hdcp_checking_title" msgid="8605478913544273282">"Праверка HDCP"</string>
+    <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"Усталяваць рэжым праверкі HDCP"</string>
+    <string name="debug_debugging_category" msgid="6781250159513471316">"Адладка"</string>
+    <string name="debug_app" msgid="8349591734751384446">"Выберыце прыкладанне для адладкi"</string>
+    <string name="debug_app_not_set" msgid="718752499586403499">"Няма прыкладанняў для адладкi"</string>
+    <string name="debug_app_set" msgid="2063077997870280017">"Адладка прыкладання: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="select_application" msgid="5156029161289091703">"Выберыце прыкладанне"</string>
+    <string name="no_application" msgid="2813387563129153880">"Нічога"</string>
+    <string name="wait_for_debugger" msgid="1202370874528893091">"Пачакайце адладчык"</string>
+    <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Адладжанае прыкладанне чакае далучэння да iнструмента для адладкi перад працай"</string>
+    <string name="debug_input_category" msgid="1811069939601180246">"Увод"</string>
+    <string name="debug_drawing_category" msgid="6755716469267367852">"Чарцёж"</string>
+    <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Апаратнае паскарэнне рэндэрынгу"</string>
+    <string name="media_category" msgid="4388305075496848353">"Медыя"</string>
+    <string name="debug_monitoring_category" msgid="7640508148375798343">"Маніторынг"</string>
+    <string name="strict_mode" msgid="1938795874357830695">"Уключаны строгі рэжым"</string>
+    <string name="strict_mode_summary" msgid="142834318897332338">"Міг. экр., калі пр.. вык. працяг. апер. ў асн. пат."</string>
+    <string name="pointer_location" msgid="6084434787496938001">"Пазіцыя паказальніка"</string>
+    <string name="pointer_location_summary" msgid="840819275172753713">"Наклад на экран з бягучым выкар. сэнсар. дадзеных"</string>
+    <string name="show_touches" msgid="2642976305235070316">"Паказваць дотыкі"</string>
+    <string name="show_touches_summary" msgid="6101183132903926324">"Паказваць візуалізацыю дотыкаў"</string>
+    <string name="show_screen_updates" msgid="5470814345876056420">"Паказ. абнаўл. паверхні"</string>
+    <string name="show_screen_updates_summary" msgid="2569622766672785529">"Мігаць ўсёй паверхней акна пры абнаўленні"</string>
+    <string name="show_hw_screen_updates" msgid="5036904558145941590">"Паказ. абн. выгляду GPU"</string>
+    <string name="show_hw_screen_updates_summary" msgid="1115593565980196197">"Мігнуць вакном пры чарчэнні з дапамогай GPU"</string>
+    <string name="show_hw_layers_updates" msgid="5645728765605699821">"Паказаць абнаўленнi апаратнага пласта"</string>
+    <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Апаратныя пласты набываюць зялёны колер, калi абнаўляюцца"</string>
+    <string name="debug_hw_overdraw" msgid="2968692419951565417">"Адладка перамалёўкі GPU"</string>
+    <string name="disable_overlays" msgid="2074488440505934665">"Адкл. апаратн. накладання"</string>
+    <string name="disable_overlays_summary" msgid="3578941133710758592">"Заўсёды выкарыстоўваць GPU для экраннай кампаноўкі"</string>
+    <string name="simulate_color_space" msgid="6745847141353345872">"Сімуляцыя каляр. прасторы"</string>
+    <string name="enable_opengl_traces_title" msgid="6790444011053219871">"Уключэнне слядоў OpenGL"</string>
+    <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Адключыць аўдыёмаршрутызацыю USB"</string>
+    <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Адкл. аўт. перанакір. на перыфер. USB-прыл. аўдыё"</string>
+    <string name="debug_layout" msgid="5981361776594526155">"Паказаць межы размяшчэння"</string>
+    <string name="debug_layout_summary" msgid="2001775315258637682">"Паказаць межы кліпу, палі і г. д."</string>
+    <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Прымусовая раскладка справа налева"</string>
+    <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Прымусовая раскладка экрана справа налева для ўсіх рэгіянальных налад"</string>
+    <string name="show_cpu_usage" msgid="2389212910758076024">"Паказаць выкарыстанне ЦП"</string>
+    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Наклад на экран з бягучым выкарыстаннем працэсара"</string>
+    <string name="force_hw_ui" msgid="6426383462520888732">"Прымусовае адлюстраванне GPU"</string>
+    <string name="force_hw_ui_summary" msgid="5535991166074861515">"Прымусовае выкарыстанне GPU для 2-мерных чарцяжоў"</string>
+    <string name="force_msaa" msgid="7920323238677284387">"Прымусовае выкананне 4x MSAA"</string>
+    <string name="force_msaa_summary" msgid="9123553203895817537">"Уключыць 4x MSAA у прыкладаннях з OpenGL ES 2.0"</string>
+    <string name="show_non_rect_clip" msgid="505954950474595172">"Адладка аперацый непрамавугольнага кліпа"</string>
+    <string name="track_frame_time" msgid="6146354853663863443">"Апрацоўка профілю GPU"</string>
+    <string name="window_animation_scale_title" msgid="6162587588166114700">"Маштаб анімацыі акна"</string>
+    <string name="transition_animation_scale_title" msgid="387527540523595875">"Маштаб перадачы анімацыі"</string>
+    <string name="animator_duration_scale_title" msgid="3406722410819934083">"Шкала працягласці анiматара"</string>
+    <string name="overlay_display_devices_title" msgid="5364176287998398539">"Мадэляванне другасных дысплеяў"</string>
+    <string name="debug_applications_category" msgid="4206913653849771549">"Прыкладаннi"</string>
+    <string name="immediately_destroy_activities" msgid="1579659389568133959">"Не захоўваць дзеянні"</string>
+    <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Знішч. кож.дзеянне, як толькі карыст.пакідае яго"</string>
+    <string name="app_process_limit_title" msgid="4280600650253107163">"Ліміт фонавага працэсу"</string>
+    <string name="show_all_anrs" msgid="28462979638729082">"Паказаць усе ANRS"</string>
+    <string name="show_all_anrs_summary" msgid="641908614413544127">"Паказаць дыялогавае акно \"Праграма не адказвае\" для фонавых прыкладанняў"</string>
+    <string name="force_allow_on_external" msgid="3215759785081916381">"Прымусова дазволіць праграмы на вонкавым сховішчы"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Робіць любую праграму даступнай для запісу на вонкавае сховішча, незалежна ад значэнняў маніфеста"</string>
+    <string name="force_resizable_activities" msgid="8615764378147824985">"Зрабіць вокны дзеянняў даступнымі для змены памеру"</string>
+    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Робіць усе віды дзейнасці даступнымі для змены памеру ў рэжыме некалькіх вокнаў, незалежна ад значэнняў маніфеста."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Уключыць адвольную форму вокнаў"</string>
+    <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Уключыць падтрымку для эксперыментальнай адвольнай формы акна."</string>
+    <string name="local_backup_password_title" msgid="3860471654439418822">"Пароль для рэз. копіі ПК"</string>
+    <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Поўнае рэзервовае капіраванне працоўнага стала зараз не абаронена"</string>
+    <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Краніце, каб змяніць або выдаліць пароль для поўнага рэзервовага капіравання працоўнага стала"</string>
+    <string name="local_backup_password_toast_success" msgid="582016086228434290">"Усталяваны новы пароль для рэзервовага капіявання"</string>
+    <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новы пароль і яго пацвярджэнне не супадаюць"</string>
+    <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Збой пры ўсталёўцы паролю для рэзервовага капіявання"</string>
+  <string-array name="color_mode_names">
+    <item msgid="2425514299220523812">"Сочны (па змаўчанні)"</item>
+    <item msgid="8446070607501413455">"Натуральны"</item>
+    <item msgid="6553408765810699025">"Стандартны"</item>
+  </string-array>
+  <string-array name="color_mode_descriptions">
+    <item msgid="4979629397075120893">"Палепшаныя колеры"</item>
+    <item msgid="8280754435979370728">"Натуральныя колеры (такія, як яны ўспрымаюцца вокам)"</item>
+    <item msgid="5363960654009010371">"Колеры, аптымізаваныя для лічбавага змесціва"</item>
+  </string-array>
+    <string name="inactive_apps_title" msgid="1317817863508274533">"Неактыўныя дадаткі"</string>
+    <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактыўная. Краніце, каб пераключыць."</string>
+    <string name="inactive_app_active_summary" msgid="4174921824958516106">"Актыўная. Краніце, каб пераключыць."</string>
+    <string name="runningservices_settings_title" msgid="8097287939865165213">"Запушчаныя службы"</string>
+    <string name="runningservices_settings_summary" msgid="854608995821032748">"Прагляд запушчаных службаў i кіраванне iмi"</string>
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Уключыць шматпрацэсны WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Запусціць апрацоўшчыкі WebView у ізаляваным працэсе."</string>
+    <string name="select_webview_provider_title" msgid="4628592979751918907">"Рэалізацыя WebView"</string>
+    <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Наладзіць рэалізацыю WebView"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Гэты варыянт больш не даступны. Паспрабуйце яшчэ раз."</string>
+    <string name="convert_to_file_encryption" msgid="3060156730651061223">"Перайсці на шыфраванне файлаў"</string>
+    <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Пераход..."</string>
+    <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Шыфраванне файлаў ужо дзейнічае"</string>
+    <string name="title_convert_fbe" msgid="1263622876196444453">"Пераход на шыфраванне файлаў"</string>
+    <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Перайдзіце з шыфравання раздзелаў даных на шыфраванне файлаў.\n !!Увага!! Гэта прывядзе да выдалення ўсіх даных.\n Гэта функцыя ў альфа-версіі, яна можа працаваць няправільна.\n Каб працягнуць, націсніце «Сцерці і перайсці...»."</string>
+    <string name="button_convert_fbe" msgid="5152671181309826405">"Сцерці і перайсці..."</string>
+    <string name="picture_color_mode" msgid="4560755008730283695">"Каляровы рэжым выявы"</string>
+    <string name="picture_color_mode_desc" msgid="1141891467675548590">"Выкарыстоўваць sRGB"</string>
+    <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Выключана"</string>
+    <string name="daltonizer_mode_monochromacy" msgid="8485709880666106721">"Монахрамазія"</string>
+    <string name="daltonizer_mode_deuteranomaly" msgid="5475532989673586329">"Дэйтэранамалія (чырвоны-зялёны)"</string>
+    <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"Пратанамалія (чырвоны-зялёны)"</string>
+    <string name="daltonizer_mode_tritanomaly" msgid="481725854987912389">"Трытанамалія (сіні-жоўты)"</string>
+    <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Карэкцыя колеру"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Гэтая функцыя з\'яўляецца эксперыментальнай і можа паўплываць на прадукцыйнасць."</string>
+    <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+    <string name="power_remaining_duration_only" msgid="4400068916452346544">"Засталося прыблізна <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
+    <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – засталося прыблізна <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
+    <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+    <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўнай зарадкі"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
+    <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўнай зарадкі ад сеткі пер. току"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
+    <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўнай зарадкі па USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
+    <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўн. зарадкі бесправадным шляхам"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
+    <string name="battery_info_status_unknown" msgid="196130600938058547">"Невядома"</string>
+    <string name="battery_info_status_charging" msgid="1705179948350365604">"Зарадка"</string>
+    <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Зар. ад сеткі пер. току"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Зарадка па USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Бесправадная зарадка"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
+    <string name="battery_info_status_discharging" msgid="310932812698268588">"Не зараджаецца"</string>
+    <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не зараджаецца"</string>
+    <string name="battery_info_status_full" msgid="2824614753861462808">"Поўная"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Кантралюецца адміністратарам"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Уключана адміністратарам"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Адключана адміністратарам"</string>
+    <string name="home" msgid="8263346537524314127">"Галоўная"</string>
+    <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> таму назад"</string>
+    <string name="remaining_length_format" msgid="7886337596669190587">"Засталося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Маленькі"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Стандартны"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Вялікі"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Большы"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найвялікшы"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index df47ad9..35b24bf 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Синтезиран говор"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Скорост на речта"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Скорост, с която се изговаря текстът"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Височина"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Отразява се на тона на синтезирания говор"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Език"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Използване на системния език"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Езикът не е избран"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Всички нереагиращи прил."</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Диалог. прозорец „НП“ за приложения на заден план"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Външно хран.: Принуд. разрешаване на приложенията"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Позволява прилож. да се записват във външ. хранил. независимо от стойностите в манифеста"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Прави всички приложения да отговарят на условията да бъдат записвани във външното хранилище независимо от стойностите в манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Възможност за преоразмеряване на активностите"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Активиране на прозорците в свободна форма"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активно. Докоснете, за да превключите."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Изпълнявани услуги:"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Нощен режим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Деактивирано"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Винаги включено"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Многопроц. режим на WebView: Акт."</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Програми за визуализация на WebView: Изпъл. в изолиран процес."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Внедряване на WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Задаване на внедряването на WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Избраното внедряване на WebView е деактивирано и трябва да го активирате, за да се използва. Искате ли да го направите?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Този избор вече не е валиден. Опитайте отново."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Преобразуване към шифроване на ниво файл"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Преобразуване…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Данните вече са шифровани на ниво файл"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Тази функция е експериментална и може да се отрази на ефективността."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Прибл. оставащо време: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – приблизително оставащо време: <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане при променлив ток"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> ˜– <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане през USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно безжично зареждане"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Зарежда се"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Зареждане при AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Зареждане през USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Безжично зареждане"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Не се зарежда"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не се зарежда"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Пълна"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Деактивирано от администратора"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролира се от администратор"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Активирано от администратора"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Деактивирано от администратора"</string>
     <string name="home" msgid="8263346537524314127">"Начало"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Преди <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Оставащо време: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Малко"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"По подразбиране"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Голямо"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"По-голямо"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Най-голямо"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Персонализирано (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index e982a36..14c2c95 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"লেখিত-থেকে-ভাষ্য"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"ভাষ্য হার"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"যে গতিতে পাঠ্য উচ্চারিত হয়"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"পিচ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"সিন্থেসাইজ করা ভাষ্যের স্বরকে প্রভাবিত করে"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ভাষা"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"সিস্টেমের ভাষা ব্যবহার করুন"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ভাষা নির্বাচন করা নেই"</string>
@@ -246,9 +248,9 @@
     <string name="show_all_anrs" msgid="28462979638729082">"সব ANR দেখান"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"পশ্চাদপটের অ্যাপ্লিকেশানগুলির জন্য অ্যাপ্লিকেশান কোনো প্রতিক্রিয়া দিচ্ছে না এমন কথোপকথন দেখান"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"বহিরাগততে বলপূর্বক মঞ্জুরি"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
-    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করুন৷"</string>
+    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলির আকার পরিবর্তনযোগ্য করুন৷"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"ফ্রি-ফর্ম উইন্ডোগুলি সক্ষম করুন"</string>
     <string name="enable_freeform_support_summary" msgid="8247310463288834487">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"সক্রিয় রয়েছে৷ টগল করতে আলতো চাপুন৷"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"এখন চলছে যে পরিষেবাগুলি"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"রাতের মোড"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"অক্ষম করা রয়েছে"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"সবসময় চালু"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"স্বয়ংক্রিয়"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"বহু-প্রক্রিয়া ওয়েবভিউ সক্ষম করুন"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"একটি বিচ্ছিন্ন প্রক্রিয়ায় ওয়েবভিউ রেন্ডারারগুলি চালান৷"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"ওয়েবভিউ প্রয়োগ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ওয়েবভিউ প্রয়োগ সেট করুন"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"নির্বাচিত ওয়েবভিউ প্রয়োগটি অক্ষম করা আছে এবং ব্যবহার করার জন্য অবশ্যই সক্ষম করতে হবে, আপনি কি এটিকে সক্ষম করতে চান?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"এই পছন্দটি আর বৈধ নেই৷ আবার চেষ্টা করুন৷"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ফাইল এনক্রিপশান রূপান্তর করুন"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"রূপান্তর করুন..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ফাইল ইতিমধ্যেই এনক্রিপ্ট করা রয়েছে"</string>
@@ -301,22 +296,39 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"এই বৈশিষ্ট্যটি পরীক্ষামূলক এবং এটি কার্য-সম্পাদনা প্রভাবিত করতে পারে।"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"প্রায় <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
+    <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - আনুমানিক <xliff:g id="TIME">%2$s</xliff:g> বাকি আছে"</string>
+    <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - সম্পূর্ণ হতে <xliff:g id="TIME">%2$s</xliff:g> বাকি"</string>
+    <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - ACতে সম্পূর্ণ হতে <xliff:g id="TIME">%2$s</xliff:g> বাকি"</string>
+    <string name="power_charging_duration_ac_short" msgid="7895864687218765582">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - USB এর মাধ্যমে সম্পূর্ণ হতে <xliff:g id="TIME">%2$s</xliff:g> বাকি"</string>
+    <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> -  বেতার যোগে সম্পূর্ণ হতে <xliff:g id="TIME">%2$s</xliff:g> বাকি"</string>
+    <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"অজানা"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"চার্জ হচ্ছে"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC তে চার্জ হচ্ছে"</string>
+    <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"চার্জ হচ্ছে"</string>
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB এর মাধ্যমে চার্জ হচ্ছে"</string>
+    <string name="battery_info_status_charging_usb_short" msgid="6733371990319101366">"চার্জ হচ্ছে"</string>
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"তারবিহীনভাবে চার্জ হচ্ছে"</string>
+    <string name="battery_info_status_charging_wireless_short" msgid="752569941028903610">"চার্জ হচ্ছে"</string>
     <string name="battery_info_status_discharging" msgid="310932812698268588">"চার্জ হচ্ছে না"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"চার্জ হচ্ছে না"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"পূর্ণ"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"প্রশাসক দ্বারা অক্ষমিত"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"প্রশাসকের দ্বারা নিয়ন্ত্রিত"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"প্রশাসক সক্ষম করেছেন"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"প্রশাসক অক্ষম করেছেন"</string>
     <string name="home" msgid="8263346537524314127">"হোম"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> আগে"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> বাকী আছে"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ক্ষুদ্র"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ডিফল্ট"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"বড়"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"খুব বড়"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"বৃহত্তম"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"কাস্টম (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bs-rBA/arrays.xml b/packages/SettingsLib/res/values-bs-rBA/arrays.xml
new file mode 100644
index 0000000..32b8bc5
--- /dev/null
+++ b/packages/SettingsLib/res/values-bs-rBA/arrays.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Skeniranje…"</item>
+    <item msgid="8513729475867537913">"Povezivanje…"</item>
+    <item msgid="515055375277271756">"Autentifikacija…"</item>
+    <item msgid="1943354004029184381">"Dobivanje IP adrese…"</item>
+    <item msgid="4221763391123233270">"Povezano"</item>
+    <item msgid="624838831631122137">"Suspendiran"</item>
+    <item msgid="7979680559596111948">"Prekidanje veze…"</item>
+    <item msgid="1634960474403853625">"Isključen"</item>
+    <item msgid="746097431216080650">"Neuspješno"</item>
+    <item msgid="6367044185730295334">"Blokirano"</item>
+    <item msgid="503942654197908005">"Privremeno izbjegavaj veze lošeg kvaliteta"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Skeniranje…"</item>
+    <item msgid="355508996603873860">"Povezivanje na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Autentifikacija sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Dobivanje IP adrese iz mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Povezan na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspendiran"</item>
+    <item msgid="7698638434317271902">"Prekidanje veze sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Isključen"</item>
+    <item msgid="8578370891960825148">"Neuspješno"</item>
+    <item msgid="5660739516542454527">"Blokirano"</item>
+    <item msgid="1805837518286731242">"Privremeno izbjegavaj veze lošeg kvaliteta"</item>
+  </string-array>
+  <string-array name="hdcp_checking_titles">
+    <item msgid="441827799230089869">"Nikada ne provjeravaj"</item>
+    <item msgid="6042769699089883931">"Provjeri samo za DRM sadržaj"</item>
+    <item msgid="9174900380056846820">"Uvijek provjeri"</item>
+  </string-array>
+  <string-array name="hdcp_checking_summaries">
+    <item msgid="505558545611516707">"Nikada ne koristi HDCP provjeru"</item>
+    <item msgid="3878793616631049349">"Koristi HDCP provjeru samo za DRM sadržaj"</item>
+    <item msgid="45075631231212732">"Uvijek koristi HDCP provjeru"</item>
+  </string-array>
+  <string-array name="select_logd_size_titles">
+    <item msgid="8665206199209698501">"Isključeno"</item>
+    <item msgid="1593289376502312923">"64K"</item>
+    <item msgid="487545340236145324">"256K"</item>
+    <item msgid="2423528675294333831">"1M"</item>
+    <item msgid="180883774509476541">"4M"</item>
+    <item msgid="2803199102589126938">"16M"</item>
+  </string-array>
+  <string-array name="select_logd_size_lowram_titles">
+    <item msgid="6089470720451068364">"Isključeno"</item>
+    <item msgid="4622460333038586791">"64K"</item>
+    <item msgid="2212125625169582330">"256K"</item>
+    <item msgid="1704946766699242653">"1M"</item>
+  </string-array>
+  <string-array name="select_logd_size_summaries">
+    <item msgid="6921048829791179331">"Isključeno"</item>
+    <item msgid="2969458029344750262">"64K po međumemoriji dnevnika"</item>
+    <item msgid="1342285115665698168">"256k po međumemoriji dnevnika"</item>
+    <item msgid="1314234299552254621">"1M po međumemoriji dnevnika"</item>
+    <item msgid="3606047780792894151">"4M po međumemoriji dnevnika"</item>
+    <item msgid="5431354956856655120">"16M po međumemoriji dnevnika"</item>
+  </string-array>
+  <string-array name="window_animation_scale_entries">
+    <item msgid="8134156599370824081">"Animacija isključena"</item>
+    <item msgid="6624864048416710414">"Animacija razmjera .5x"</item>
+    <item msgid="2219332261255416635">"Animacija razmjera 1x"</item>
+    <item msgid="3544428804137048509">"Animacija razmjera 1,5x"</item>
+    <item msgid="3110710404225974514">"Animacija razmjera 2x"</item>
+    <item msgid="4402738611528318731">"Animacija razmjera 5x"</item>
+    <item msgid="6189539267968330656">"Animacija razmjera 10x"</item>
+  </string-array>
+  <string-array name="transition_animation_scale_entries">
+    <item msgid="8464255836173039442">"Animacija isključena"</item>
+    <item msgid="3375781541913316411">"Animacija razmjera .5x"</item>
+    <item msgid="1991041427801869945">"Animacija razmjera 1x"</item>
+    <item msgid="4012689927622382874">"Animacija razmjera 1,5x"</item>
+    <item msgid="3289156759925947169">"Animacija razmjera 2x"</item>
+    <item msgid="7705857441213621835">"Animacija razmjera 5x"</item>
+    <item msgid="6660750935954853365">"Animacija razmjera 10x"</item>
+  </string-array>
+  <string-array name="animator_duration_scale_entries">
+    <item msgid="6039901060648228241">"Animacija isključena"</item>
+    <item msgid="1138649021950863198">"Animacija razmjera .5x"</item>
+    <item msgid="4394388961370833040">"Animacija razmjera 1x"</item>
+    <item msgid="8125427921655194973">"Animacija razmjera 1.5x"</item>
+    <item msgid="3334024790739189573">"Animacija razmjera 2x"</item>
+    <item msgid="3170120558236848008">"Animacija razmjera 5x"</item>
+    <item msgid="1069584980746680398">"Animacija razmjera 10x"</item>
+  </string-array>
+  <string-array name="overlay_display_devices_entries">
+    <item msgid="1606809880904982133">"Nema"</item>
+    <item msgid="9033194758688161545">"480p"</item>
+    <item msgid="1025306206556583600">"480p (osiguran)"</item>
+    <item msgid="1853913333042744661">"720p"</item>
+    <item msgid="3414540279805870511">"720p (osiguran)"</item>
+    <item msgid="9039818062847141551">"1080p"</item>
+    <item msgid="4939496949750174834">"1080p (osiguran)"</item>
+    <item msgid="1833612718524903568">"4K"</item>
+    <item msgid="238303513127879234">"4K (osiguran)"</item>
+    <item msgid="3547211260846843098">"4K (povećava rezoluciju)"</item>
+    <item msgid="5411365648951414254">"4K (povećava rezoluciju, osiguran)"</item>
+    <item msgid="1311305077526792901">"720p, 1080p (dupli ekran)"</item>
+  </string-array>
+  <string-array name="enable_opengl_traces_entries">
+    <item msgid="3191973083884253830">"Nema"</item>
+    <item msgid="9089630089455370183">"Logcat"</item>
+    <item msgid="5397807424362304288">"Systrace (grafika)"</item>
+    <item msgid="1340692776955662664">"Pozovi skupinu na glGetError"</item>
+  </string-array>
+  <string-array name="show_non_rect_clip_entries">
+    <item msgid="993742912147090253">"Isključeno"</item>
+    <item msgid="675719912558941285">"Nacrtaj plavom bojom nepravougaonu oblast za isjecanje"</item>
+    <item msgid="1064373276095698656">"Označite zelenom bojom testirane komande za crtanje"</item>
+  </string-array>
+  <string-array name="track_frame_time_entries">
+    <item msgid="2193584639058893150">"Isključeno"</item>
+    <item msgid="2751513398307949636">"Na ekranu u vidu crtica"</item>
+    <item msgid="1851438178120770973">"U ADB ljuski dumpsys gfxinfo"</item>
+  </string-array>
+  <string-array name="debug_hw_overdraw_entries">
+    <item msgid="8190572633763871652">"Isključeno"</item>
+    <item msgid="7688197031296835369">"Prikaži overdraw područja"</item>
+    <item msgid="2290859360633824369">"Prikaži područja za Deuteranomaly"</item>
+  </string-array>
+  <string-array name="app_process_limit_entries">
+    <item msgid="3401625457385943795">"Standardno ograničenje"</item>
+    <item msgid="4071574792028999443">"Nema pozadinskih procesa"</item>
+    <item msgid="4810006996171705398">"Najviše 1 proces"</item>
+    <item msgid="8586370216857360863">"Najviše 2 procesa"</item>
+    <item msgid="836593137872605381">"Najviše 3 procesa"</item>
+    <item msgid="7899496259191969307">"Najviše 4 procesa"</item>
+  </string-array>
+  <string-array name="usb_configuration_titles">
+    <item msgid="488237561639712799">"Puni se"</item>
+    <item msgid="5220695614993094977">"MTP (protokol za prijenos sadržaja medija)"</item>
+    <item msgid="2086000968159047375">"PTP (protokol za prijenos slika)"</item>
+    <item msgid="7398830860950841822">"RNDIS (USB Ethernet)"</item>
+    <item msgid="1718924214939774352">"Izvor zvuka"</item>
+    <item msgid="8126315616613006284">"MIDI"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index 92c7ec8..f9c7fcad 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Izlaz za pretvaranje teksta u govor"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina kojom se izgovara tekst"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Visina"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utječe na ton sintetiziranog govora"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Koristi sistemski jezik"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije izabran"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Prikaži sve ANR-ove"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Prik. dijalog Aplikacija ne reagira za apl. u poz."</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Nametni aplikacije na vanjskoj pohrani"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Dozvoljava da bilo koja aplikacija bude upisana na vanjsku pohranu, bez obzira na vrijednosti manifesta."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Omogućava da svaka aplikacija bude pogodna za upisivanje na vanjsku pohranu, bez obzira na prikazane vrijednosti"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni aktivnostima mijenjanje veličina"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Neka sve aktivnosti budu takve da mogu mijenjati veličinu za prikaz sa više prozora, bez obzira na prikazane vrijednosti."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore nepravilnih oblika"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dodirnite za promjenu opcije."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Prikažite trenutno pokrenute usluge i upravljajte njima"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Noćni način rada"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Uvijek uključeno"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogućiti višeprocesni WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrenite WebView operatera u izolovanom procesu."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Postavljanje WebViewa"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesi WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Postavljanje izabranog WebViewa je onemogućeno. Da bi se mogao koristiti, mora biti omogućen. Želite li ga omogućiti?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više ne vrijedi. Pokušajte ponovo."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u šifrirani fajl"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvaranje…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fajl je već šifriran"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna te može utjecati na performanse."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo vreme je otprilike <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pune baterije"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do kraja punjenja na el. napajanju"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pune baterije preko USB-a"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pune baterije bežičnim punjenjem"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Puni se"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Puni se na punjaču"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Punjenje preko USB-a"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bežično punjenje"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ne puni se"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pod kontrolom administratora"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio je administrator"</string>
     <string name="home" msgid="8263346537524314127">"Početna stranica"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Još otprilike <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malo"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Zadano"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliko"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veće"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index beb909e..a070740 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Síntesi de veu"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocitat de veu"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocitat de lectura del text"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"To"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta el to de la veu sintetitzada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilitza l\'idioma del sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"No has seleccionat cap idioma"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Tots els errors sense resposta"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Informa que una aplicació en segon pla no respon"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Força permís d\'aplicacions a l\'emmagatzem. extern"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet que les aplicacions es puguin escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Activa les finestres de format lliure"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aplicació activa. Toca per desactivar-la."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Serveis en execució"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Visualitza i controla els serveis en execució"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Mode nocturn"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Desactivat"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Sempre activat"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automàtic"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activa WebView amb multiprocés"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executa els renderitzadors de WebView en un procés aïllat."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementació de WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configura la implementació de WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementació de WebView que has triat està desactivada i s\'ha d\'activar per utilitzar-la. Vols activar-la?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Aquesta opció ja no és vàlida. Torna-ho a provar."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Converteix en l\'encriptació de fitxers"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converteix…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"El fitxer ja està encriptat"</string>
@@ -301,22 +296,39 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Aquesta funció és experimental i pot afectar el rendiment."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Temps restant aproximat: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Temps restant: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g>: falten aproximadament <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g>; temps restant: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
+    <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega per CA"</string>
+    <string name="power_charging_duration_ac_short" msgid="7895864687218765582">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega per USB"</string>
+    <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega sense fil"</string>
+    <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Desconegut"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"S\'està carregant"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Càrrega: corr. alt."</string>
+    <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"S\'està carregant"</string>
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Càrrega per USB"</string>
+    <string name="battery_info_status_charging_usb_short" msgid="6733371990319101366">"S\'està carregant"</string>
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Càrrega sense fils"</string>
+    <string name="battery_info_status_charging_wireless_short" msgid="752569941028903610">"S\'està carregant"</string>
     <string name="battery_info_status_discharging" msgid="310932812698268588">"No s\'està carregant"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"No s\'està carregant"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Plena"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Opció desactivada per l\'administrador"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlat per l\'administrador"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Opció activada per l\'administrador"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Opció desactivada per l\'administrador"</string>
     <string name="home" msgid="8263346537524314127">"Inici"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Fa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Temps restant: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Petit"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminat"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Gran"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Més gran"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Màxim"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index ad01feb..040c9f0 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Převod textu na řeč"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Rychlost řeči"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Rychlost mluveného textu"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Výška"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Určuje tón syntetizované řeči"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Jazyk"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Použít jazyk systému"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Nebyl vybrán jazyk"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Zobrazit všechny ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Zobrazovat dialog „Aplikace neodpovídá“ pro aplikace na pozadí"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Vynutit povolení aplikací na externím úložišti"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Vynutit možnost změny velikosti aktivit"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Umožnit změnu velikosti všech aktivit na několik oken (bez ohledu na hodnoty manifestu)"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivovat okna s volným tvarem"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivní. Klepnutím možnost přepnete."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Spuštěné služby"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Noční režim"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Vypnuto"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuto"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Povolit WebView ve více procesech"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Spouštět moduly vykreslení WebView jako samostatné procesy."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementace WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavte implementaci WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Vybraná implementace WebView je zakázána a nelze ji použít. Chcete ji povolit a použít?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Tato volba již není platná. Zkuste to znovu."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Převést na šifrování souborů"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Převést…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Obsah je již na úrovni souborů zašifrován"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkce je experimentální a může mít vliv na výkon."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zbývající čas: <xliff:g id="TIME">%1$s</xliff:g> (přibližně)"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zbývá přibližně <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití ze zásuvky"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití přes USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití bezdrátově"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Neznámé"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Nabíjí se"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Nabíjení z adaptéru"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Nabíjení přes USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bezdrátové nabíjení"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nenabíjí se"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenabíjí se"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Zakázáno administrátorem"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Spravováno administrátorem"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Povoleno administrátorem"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Zakázáno administrátorem"</string>
     <string name="home" msgid="8263346537524314127">"Plocha"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"před <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Zbývající čas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malé"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Výchozí"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Velké"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Větší"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Největší"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index e869044..ddad673 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Oplæsning"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Talehastighed"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Oplæsningshastighed for tekst"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Toneleje"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Påvirker tonen af den syntetiserede tale"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Sprog"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Brug systemsprog"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Der er ikke valgt sprog"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Vis alle \"Appen svarer ikke\""</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Vis \"Appen svarer ikke\" for baggrundsapps"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Gennemtving tilladelse til eksternt lager"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tillad, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivér vinduer i frit format"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Tryk for at skifte."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Kørende tjenester"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Vis og kontrollér kørende tjenester"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nattilstand"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Deaktiveret"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Altid slået til"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktivér WebView i flere processer"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Kør WebView-gengivelse i en isoleret proces."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Konfigurer WebView-implementering"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valgte WebView-implementering er deaktiveret og skal aktiveres, før den kan bruges. Vil du aktivere den?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Dette valg er ikke længere gyldigt. Prøv igen."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertér til filkryptering"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertér…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Allerede filkrypteret"</string>
@@ -301,22 +296,39 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Denne funktion er eksperimentel og kan påvirke ydeevnen."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> tilbage"</string>
+    <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> tilbage"</string>
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> tilbage"</string>
+    <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tilbage"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til fuldt opladet"</string>
+    <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til fuldt opladet med adapter"</string>
+    <string name="power_charging_duration_ac_short" msgid="7895864687218765582">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til fuldt opladet med USB"</string>
+    <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til fuldt opladet med trådløs"</string>
+    <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Ukendt"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Oplader"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Opladning med AC"</string>
+    <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"Oplader"</string>
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Opladning via USB"</string>
+    <string name="battery_info_status_charging_usb_short" msgid="6733371990319101366">"Oplader"</string>
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Trådløs opladning"</string>
+    <string name="battery_info_status_charging_wireless_short" msgid="752569941028903610">"Oplader"</string>
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Oplader ikke"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Oplader ikke"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fuld"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Deaktiveret af administratoren"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolleret af administratoren"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Aktiveret af administratoren"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Deaktiveret af administratoren"</string>
     <string name="home" msgid="8263346537524314127">"Start"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> tilbage"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Lille"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standard"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stor"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Større"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 56d2543..514228f 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Text-in-Sprache-Ausgabe"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Sprechgeschwindigkeit"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Geschwindigkeit, mit der der Text gesprochen wird"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonlage"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Beeinflusst den Ton der künstlichen Sprache"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Sprache"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Systemsprache verwenden"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Keine Sprache ausgewählt"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Alle ANRS anzeigen"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Dialogfeld \"App antwortet nicht\" für Hintergrund-Apps anzeigen"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Externe Speichernutzung von Apps erlauben"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Größe aller Aktivitäten an den Mehrfenstermodus anpassen, unabhängig von den Manifestwerten."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Freiform-Fenster zulassen"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Zum Wechseln tippen."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Aktive Dienste"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nachtmodus"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Deaktiviert"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Immer an"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView-Simultanverarbeitung aktivieren"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView-Renderer isoliert ausführen."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-Implementierung"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-Implementierung festlegen"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Die ausgewählte WebView-Implementierung ist deaktiviert. Um sie nutzen zu können, muss sie aktiviert sein. Möchtest du sie aktivieren?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Diese Auswahl ist nicht mehr gültig. Versuche es erneut."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Zu Dateiverschlüsselung wechseln"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Wechseln…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dateiverschlüsselung wird bereits verwendet."</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierbei handelt es sich um eine experimentelle Funktion. Dies kann sich auf die Leistung auswirken."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Noch ca. <xliff:g id="TIME">%1$s</xliff:g> verbleibend"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noch etwa <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – bei Stromanschluss voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – über USB voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – bei kabellosem Laden voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Unbekannt"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Wird aufgeladen"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Laden über Netzteil"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laden über USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Kabelloses Laden"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Wird nicht geladen"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Wird nicht geladen"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Voll"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Vom Administrator deaktiviert"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Durch den Administrator verwaltet"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Vom Administrator aktiviert"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Vom Administrator deaktiviert"</string>
     <string name="home" msgid="8263346537524314127">"Startseite"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Vor <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Noch <xliff:g id="ID_1">%1$s</xliff:g> verbleibend"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Klein"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standard"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Groß"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Größer"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Am größten"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index e9f8661..8df693a 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Έξοδος μετατροπής κειμένου σε ομιλία"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Ταχύτητα λόγου"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Ταχύτητα με την οποία εκφωνείται το κείμενο"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Τόνος"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Επηρεάζει τον τόνο της σύνθεσης ομιλίας"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Γλώσσα"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Χρήση γλώσσας συστήματος"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Δεν έχει επιλεγεί γλώσσα"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Εμφάνιση όλων των ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Εμφ.του παραθ. \"Η εφαρμ.δεν αποκρ.\" για εφ.παρασκ."</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Να επιτρέπονται υποχρεωτικά εφαρμογές σε εξωτ.συσ."</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό χώρο αποθήκευσης, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό αποθηκευτικό χώρο, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Ενεργό. Πατήστε για εναλλαγή."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Υπηρεσίες που εκτελούνται"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Προβολή και έλεγχος των εφαρμογών που εκτελούνται αυτή τη στιγμή"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Λειτουργία νύχτας"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Ανενεργό"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Πάντα ενεργό"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Αυτόματο"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ενεργοποίηση WebView πολλαπλών διεργασιών"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Εκτέλεση λειτ.απόδοσης WebView σε μια απομονωμένη διεργασία."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Υλοποίηση WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ορισμός υλοποίησης WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Η επιλεγμένη ενσωμάτωση WebView είναι απενεργοποιημένη και θα πρέπει να ενεργοποιηθεί για να χρησιμοποιηθεί. Θέλετε να την ενεργοποιήσετε;"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Αυτή η επιλογή δεν είναι πια έγκυρη. Δοκιμάστε ξανά."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Μετατροπή σε κρυπτογράφηση αρχείου"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Μετατροπή…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Με κρυπτογράφηση αρχείου"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Αυτή η λειτουργία είναι πειραματική και ενδεχομένως να επηρεάσει τις επιδόσεις."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Απομένουν περίπου <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - απομένουν περίπου <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση με φορτιστή AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση μέσω USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη ασύρματη φόρτιση"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Άγνωστο"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Φόρτιση"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Φόρτιση με AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Φόρτιση μέσω USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Ασύρματη φόρτιση"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Δεν φορτίζει"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Δεν φορτίζει"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Πλήρης"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Απενεργοποιήθηκε από το διαχειριστή"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ελέγχονται από το διαχειριστή"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Ενεργοποιήθηκε από το διαχειριστή"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Απενεργοποιήθηκε από το διαχειριστή"</string>
     <string name="home" msgid="8263346537524314127">"Αρχική οθόνη"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Πριν από <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Απομένουν <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Μικρά"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Προεπιλογή"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Μεγάλα"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Πιο μεγάλα"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Μεγαλύτερα"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 668e0b2..466291a 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Text-to-speech output"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Speech rate"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Speed at which the text is spoken"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affects the tone of the synthesised speech"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Language"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Use system language"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Language not selected"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Show all ANRs"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Show App Not Responding dialogue for background apps"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Active. Tap to toggle."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"View and control currently running services"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Enable multi-process WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Run WebView renderers in an isolated process."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"This choice is no longer valid. Try again."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full on AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full over USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full from wireless"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Charging on AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Charging over USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Charging wirelessly"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disabled by administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Enabled by administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Disabled by administrator"</string>
     <string name="home" msgid="8263346537524314127">"Home"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Small"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Large"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 668e0b2..466291a 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Text-to-speech output"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Speech rate"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Speed at which the text is spoken"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affects the tone of the synthesised speech"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Language"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Use system language"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Language not selected"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Show all ANRs"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Show App Not Responding dialogue for background apps"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Active. Tap to toggle."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"View and control currently running services"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Enable multi-process WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Run WebView renderers in an isolated process."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"This choice is no longer valid. Try again."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full on AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full over USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full from wireless"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Charging on AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Charging over USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Charging wirelessly"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disabled by administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Enabled by administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Disabled by administrator"</string>
     <string name="home" msgid="8263346537524314127">"Home"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Small"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Large"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 668e0b2..466291a 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Text-to-speech output"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Speech rate"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Speed at which the text is spoken"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affects the tone of the synthesised speech"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Language"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Use system language"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Language not selected"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Show all ANRs"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Show App Not Responding dialogue for background apps"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Active. Tap to toggle."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"View and control currently running services"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Enable multi-process WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Run WebView renderers in an isolated process."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"This choice is no longer valid. Try again."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full on AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full over USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full from wireless"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Charging on AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Charging over USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Charging wirelessly"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disabled by administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Enabled by administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Disabled by administrator"</string>
     <string name="home" msgid="8263346537524314127">"Home"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Small"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Large"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 05ab073..9bc2cf4 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Salida de texto a voz"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidad de voz"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidad en la que se habla el texto"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Sonido"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta el tono de la voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar el idioma del sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma no seleccionado"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Errores sin respuesta"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Mostrar diálogo cuando las aplic. en 2do plano no responden"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permisos en almacenamiento externo"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Cualquier aplicación puede escribirse en una memoria externa, independientemente de los valores del manifiesto."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Cualquier app puede escribirse en un almacenamiento externo, sin importar los valores del manifiesto"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar actividades para que cambien de tamaño"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permitir que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Activa. Presiona para activar o desactivar."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"En ejecución"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Ver y controlar servicios actuales en ejecución"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Habilitar multiproceso WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ejecutar procesadores de WebView en un proceso aislado."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar la implementación de WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementación de WebView que elegiste está inhabilitada. Debes habilitarla para poder usarla. ¿Quieres hacerlo?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Esta opción ya no es válida. Vuelve a intentarlo."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a encriptación de archivo"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está encriptado"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar el rendimiento."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Falta <xliff:g id="TIME">%1$s</xliff:g> aproximadamente"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g>: alrededor de <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar la carga por CA"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar la carga por USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar la carga inalámbrica"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Cargando"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Carga en CA"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Carga con USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Carga inalámbrica"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"No se está cargando."</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"No se realiza la carga"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Cargado"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Inhabilitada por el administrador"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Habilitada por el administrador"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Inhabilitada por el administrador"</string>
     <string name="home" msgid="8263346537524314127">"Página principal"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Falta <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeño"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminado"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Más grande"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Máximo"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 5fea7554..ec0cafe 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -34,7 +34,7 @@
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
     <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conexión sin Internet"</string>
-    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectada"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
     <string name="bluetooth_connecting" msgid="8555009514614320497">"Estableciendo conexión…"</string>
     <string name="bluetooth_connected" msgid="6038755206916626419">"Conectado"</string>
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Síntesis de voz"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidad de la voz"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidad a la que se lee el texto"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tono"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta al tono de la síntesis de voz"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma del sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma no seleccionado"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Errores sin respuesta"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Informar de que una aplicación en segundo plano no responde"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permiso de aplicaciones de forma externa"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hace que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo, independientemente de los valores definidos"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Hace que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo, independientemente de los valores definidos"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar el ajuste de tamaño de las actividades"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite que se pueda ajustar el tamaño de todas las actividades para el modo multiventana, independientemente de los valores establecidos."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Activa. Toca para alternar."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Servicios en ejecución"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Ver y controlar los servicios en ejecución"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Habilitar WebView multiproceso"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ejecuta procesadores de WebView en un proceso aislado."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Establecer implementación de WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementación de WebView seleccionada está inhabilitada y debes habilitarla para utilizarla. ¿Quieres hacerlo?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Esta opción ya no está disponible. Vuelve a intentarlo."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a cifrado de archivo"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está cifrado"</string>
@@ -301,22 +296,39 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar al rendimiento."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Tiempo restante (aproximado): <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Tiempo restante: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quedan <xliff:g id="TIME">%2$s</xliff:g> aproximadamente"</string>
+    <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tiempo restante: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la batería"</string>
+    <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la batería con CA"</string>
+    <string name="power_charging_duration_ac_short" msgid="7895864687218765582">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la batería por USB"</string>
+    <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la batería con Wi-Fi"</string>
+    <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Cargando"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Cargando en CA"</string>
+    <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"Cargando"</string>
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Cargando por USB"</string>
+    <string name="battery_info_status_charging_usb_short" msgid="6733371990319101366">"Cargando"</string>
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Cargando de forma inalámbrica"</string>
+    <string name="battery_info_status_charging_wireless_short" msgid="752569941028903610">"Cargando"</string>
     <string name="battery_info_status_discharging" msgid="310932812698268588">"No se está cargando"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"No se está cargando"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Inhabilitada por el administrador"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Habilitado por el administrador"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Inhabilitado por el administrador"</string>
     <string name="home" msgid="8263346537524314127">"Inicio"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Tiempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeño"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminado"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Más grande"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lo más grande posible"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index b9d011b..29a1aea 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Kõnesünteesi väljund"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Kõnekiirus"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Teksti rääkimise kiirus"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Helikõrgus"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Mõjutab sünteesitud kõne tooni"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Keel"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Süsteemi keele kasutamine"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Keelt pole valitud"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Näita kõiki ANR-e"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Kuva taustarakendustele dial. Rakendus ei reageeri"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Luba rakendused välises salvestusruumis"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lubab rakendusi kirjutada välisesse salvestusruumi olenemata manifesti väärtustest"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Lubab mis tahes rakendusi kirjutada välisesse salvestusruumi manifesti väärtustest olenemata"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Muuda tegevuste suurused muudetavaks"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Muudetakse kõigi tegevuste suurused mitme aknaga vaates muudetavaks (manifesti väärtustest olenemata)."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Luba vabas vormis aknad"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiivne. Puudutage vahetamiseks."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Käitatud teenused"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Praegu käitatud teenuste vaatamine ja juhtimine"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Öörežiim"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Keelatud"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Alati sees"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automaatne"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Luba mitme protsessiga WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView\' renderdajad käitatakse eraldi protsessis."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView\' rakendamine"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView\' rakendamise seadistamine"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Valitud WebView\' rakendamisviis on keelatud ja see tuleb kasutamiseks lubada. Kas soovite selle lubada?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"See valik ei kehti enam. Proovige uuesti."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Teisendamine failikrüpteeringuga andmeteks"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Teisenda …"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Juba failikrüpteeringuga"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"See funktsioon on katseline ja võib mõjutada toimivust."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Umbes <xliff:g id="TIME">%1$s</xliff:g> on jäänud"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – jäänud on umbes <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, kuni aku on täis"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, kuni aku on täis (vahelduvvool)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, kuni aku on täis (USB)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, kuni aku on täis (juhtmeta laad.)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Tundmatu"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Laadimine"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Laad. vahelduvv.-v."</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laadimine USB kaudu"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Juhtmevaba laadimine"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ei lae"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ei lae"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Täis"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administraator on keelanud"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Juhib administraator"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Administraator on lubanud"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Administraator on keelanud"</string>
     <string name="home" msgid="8263346537524314127">"Avaekraan"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> tagasi"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> on jäänud"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Väike"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Vaikimisi"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Suur"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Suurem"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurim"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index c1be37f..4f55e35 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -99,8 +99,10 @@
     <string name="launch_defaults_none" msgid="4241129108140034876">"Ez dago hobespen lehenetsirik ezarrita"</string>
     <string name="tts_settings" msgid="8186971894801348327">"Testua ahots bihurtzeko eginbidearen ezarpenak"</string>
     <string name="tts_settings_title" msgid="1237820681016639683">"Testua ahots bihurtzeko eginbidearen irteera"</string>
-    <string name="tts_default_rate_title" msgid="6030550998379310088">"Hizketa-abiadura"</string>
+    <string name="tts_default_rate_title" msgid="6030550998379310088">"Hizketaren abiadura"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Testua zer abiaduran esaten den"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonua"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Hizketa sintetizatuaren tonuari eragiten dio"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Hizkuntza"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Erabili sistemaren hizkuntza"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Ez da hizkuntza hautatu"</string>
@@ -226,7 +228,7 @@
     <string name="debug_layout" msgid="5981361776594526155">"Erakutsi diseinuaren mugak"</string>
     <string name="debug_layout_summary" msgid="2001775315258637682">"Erakutsi kliparen mugak, marjinak, etab."</string>
     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Behartu eskuin-ezker norabidea."</string>
-    <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Behartu pantaila-diseinuaren norabidea eskuinetik ezkerrerakoa izatera eskualdeko ezarpen guztiekin."</string>
+    <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Behartu pantaila-diseinuaren norabidea eskuin-ezker izatera eskualdeko ezarpen guztiekin."</string>
     <string name="show_cpu_usage" msgid="2389212910758076024">"Erakutsi PUZ erabilera"</string>
     <string name="show_cpu_usage_summary" msgid="2113341923988958266">"PUZ erabilera erakusten duen pantaila-gainjartzea"</string>
     <string name="force_hw_ui" msgid="6426383462520888732">"Behartu GPU errendatzea"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Erakutsi ANR guztiak"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"\"Erantzunik ez\" mezua atz. planoko aplikazioetarako"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Behartu aplikazioak onartzea kanpoko biltegian"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikazioek kanpoko memorian idatz dezakete, manifestuaren balioak kontuan izan gabe"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Aplikazioek kanpoko memorian idatz dezakete, manifestuaren balioak kontuan izan gabe"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Behartu jardueren tamaina doitu ahal izatea"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Eman aukera jarduera guztien tamaina doitzeko, hainbat leihotan erabili ahal izan daitezen, manifestuan jartzen duena jartzen duela ere."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Gaitu estilo libreko leihoak"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktibo. Aldatzeko, sakatu hau."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Abian diren zerbitzuak"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Ikusi eta kontrolatu unean abian diren zerbitzuak"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Gau modua"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Desgaituta"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Beti aktibatuta"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatikoa"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Gaitu prozesu anitzeko WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Exekutatu WebView errendatzaileak prozesu isolatu batean."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Desgaituta dago aukeratu den WebView inplementazioa. Erabili nahi izanez gero, gaitu egin behar duzu. Gaitu nahi al duzu?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Jada ez dago erabilgarri aukera hori. Saiatu berriro."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Eman fitxategietan oinarritutako enkriptatzea"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Enkriptatu…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fitxategietan oinarritutako enkriptatzea dauka dagoeneko"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g> inguru guztiz kargatu arte"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> inguru. <xliff:g id="TIME">%2$s</xliff:g> geratzen d(ir)a"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> korrontearen bidez guztiz kargatu arte"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB bidez guztiz kargatu arte"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> haririk gabe guztiz kargatu arte"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Ezezaguna"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzea"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"KA bidez kargatzen"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB bidez kargatzen"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Hari gabe kargatzen"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ez da kargatzen ari"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ez da kargatzen ari"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Beteta"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administratzaileak desgaitu du"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administratzaileak kontrolatzen du"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Administratzaileak gaitu du"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Administratzaileak desgaitu du"</string>
     <string name="home" msgid="8263346537524314127">"Hasierako pantaila"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Duela <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> guztiz kargatu arte"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Txikia"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Lehenetsia"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Handia"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Oso handia"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Handiena"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index fc4cd7d..e9d63fd 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"خروجی تبدیل متن به گفتار"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"سرعت گفتار"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"سرعتی که متن خوانده می‌شود"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"زیر و بمی صدا"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"بر صدای متن گفته شده تأثیر می‌گذارد"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"زبان"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"استفاده از زبان سیستم"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"زبان انتخاب نشده است"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"‏نمایش تمام ANRها"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"نمایش گفتگوی \"برنامه پاسخ نمی‌دهد\" برای برنامه‌های پس‌زمینه"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"اجازه اجباری به برنامه‌های دستگاه ذخیره خارجی"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"بدون توجه به مقادیر مانیفست، هر برنامه‌ای را برای نوشتن در حافظه خارجی واجد شرایط می‌کند"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"بدون توجه به مقادیر مانیفست، هر برنامه‌ای را برای نوشتن در حافظه خارجی واجد شرایط می‌کند"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"اجبار فعالیت‌ها به قابل تغییر اندازه بودن"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"بدون توجه به مقادیر مانیفست، اندازه همه فعالیت‌ها برای حالت چند پنجره‌ای می‌تواند تغییر کند."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"فعال کردن پنجره‌های آزاد"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال. برای تغییر حالت ضربه بزنید."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"سرویس‌های در حال اجرا"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"مشاهده و کنترل سرویس‌های در حال اجرای فعلی"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"حالت شب"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"غیرفعال است"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"همیشه روشن"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
-    <string name="select_webview_provider_title" msgid="4628592979751918907">"‏اجرای WebView"</string>
-    <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏تنظیم اجرای WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏پیاده‌سازی WebView انتخاب‌شده غیرفعال شده است و برای استفاده شدن باید فعال شود؛ می‌خواهید آن را فعال کنید؟"</string>
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"فعال کردن وب‌نمای چندپردازشی"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"اجرای تولیدکننده تصویر وب‌نما در یک پردازش مجزا."</string>
+    <string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای وب‌نما"</string>
+    <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای وب‌نما"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"این انتخاب دیگر معتبر نیست. دوباره امتحان کنید."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"تبدیل به رمزگذاری برحسب فایل"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تبدیل…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"از قبل به رمزگذاری بر حسب فایل تبدیل شده است"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"این قابلیت آزمایشی است و ممکن است عملکرد را تحت تأثیر قرار دهد."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"تقریباً <xliff:g id="TIME">%1$s</xliff:g> باقی مانده است"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - تقریباً ‏<xliff:g id="TIME">%2$s</xliff:g> باقی مانده است"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل با جریان متناوب"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"‏<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل از طریق USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل به‌طور بی‌سیم"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"ناشناس"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"در حال شارژ شدن"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"شارژ با جریان متناوب"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"‏شارژ از طریق USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"شارژ به صورت بی‌سیم"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"شارژ نمی‌شود"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"شارژ نمی‌شود"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"پر"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"سرپرست آن را غیرفعال کرده است"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"توسط سرپرست سیستم کنترل می‌شود"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"سرپرست آن را فعال کرده است"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"سرپرست آن را غیرفعال کرده است"</string>
     <string name="home" msgid="8263346537524314127">"صفحه اصلی"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی مانده است"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"کوچک"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"پیش‌فرض"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"بزرگ"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"بزرگ‌تر"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"بزرگ‌ترین"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"سفارشی (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 34309c1..5531d27 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Tekstistä puheeksi -toisto"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Puheen nopeus"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Tekstin puhumisnopeus"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Äänenkorkeus"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Tämä vaikuttaa syntetisoidun puheen äänensävyyn."</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Kieli"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Käytä järjestelmän kieltä"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Kieltä ei ole valittu"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Näytä kaikki ANR:t"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Näytä Sovellus ei vastaa -ikkuna taustasovell."</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Salli aina ulkoinen tallennus"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mahdollistaa sovellusten tallentamisen ulkoiseen tall.tilaan luettelosta riippumatta"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Mahdollistaa sovelluksen tietojen tallentamisen ulkoiseen tallennustilaan luetteloarvoista riippumatta."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Pakota kaikki toiminnot hyväksymään koon muutos"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Pakota kaikki toiminnot hyväksymään koon muuttaminen usean ikkunan tilassa luettelon arvoista riippumatta."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Ota käyttöön vapaamuotoiset ikkunat"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Käytössä. Poista käytöstä koskettamalla."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Käynnissä olevat palvelut"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Tarkastele ja hallitse käynnissä olevia palveluita"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Yötila"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Ei käytössä"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Aina käytössä"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automaattinen"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView\'n usean prosessin tila"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Suorita WebView\'n hahmontajat erillisinä prosesseina."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-käyttöönotto"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Määritä WebView-käyttöönotto"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Valittu WebView-käyttöönotto on poistettu käytöstä. Haluatko ottaa sen käyttöön?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Tämä valinta ei ole enää saatavilla. Yritä uudestaan."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Muunna tiedostojen salaukseksi"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Muunna…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Tiedostot on jo salattu."</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tämä ominaisuus on kokeellinen ja voi vaikuttaa suorituskykyyn."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Noin <xliff:g id="TIME">%1$s</xliff:g> jäljellä"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä (laturilataus)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä (USB-lataus)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä (WiFi-lataus)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Tuntematon"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Ladataan"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Laturilataus"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB-lataus"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Langaton lataus"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ei laturissa"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ei laturissa"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Täynnä"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Järjestelmänvalvojan käytöstä poistama"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Järjestelmänvalvojan käyttöön ottama"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Järjestelmänvalvojan käytöstä poistama"</string>
     <string name="home" msgid="8263346537524314127">"Aloitusnäyttö"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> sitten"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> jäljellä"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pieni"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Oletus"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Suuri"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Suurempi"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurin"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 1181c2a3..df6bdc6 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Sortie de la synthèse vocale"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Cadence"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Vitesse à laquelle le texte est énoncé"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Touche le ton utilisé pour la synthèse vocale"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Langue"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Utiliser la langue du système"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Langue non sélectionnée"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Afficher tous les messages «L\'application ne répond pas»"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Afficher « L\'application ne répond plus » pour applis en arrière-plan"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forcer l\'autor. d\'applis sur stockage externe"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet enreg. d\'applis sur espace stockage externe"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Rend possible l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forcer les activités à être redimensionnables"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Application active. Touchez ici pour la désactiver."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Services en cours d\'exécution"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Afficher et contrôler les services en cours d\'exécution"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Mode Nuit"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Toujours actif"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activer WebView multiprocessus"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Exécuter moteurs de rendu WebView dans un processus isolé."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La mise en œuvre WebView sélectionnée est désactivée. Vous devez l\'activer pour l\'utiliser. Souhaitez-vous l\'activer?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ce choix n\'est plus valide. Réessayez."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir en chiffrement basé sur un fichier"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Déjà chiffré par un fichier"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut toucher les performances."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> %% – Temps restant : environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> %% (chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> %% (charge complète sur c.a. dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> %% (chargée à 100 %% par USB dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> %% (chargée à 100 %% avec chargeur sans fil dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Batterie en charge"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"En charge (c.a.)"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"En charge par USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"En charge sans fil"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"N\'est pas en charge"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"N\'est pas en charge"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Pleine"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Désactivé par l\'administrateur"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Activé par l\'administrateur"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Désactivé par l\'administrateur"</string>
     <string name="home" msgid="8263346537524314127">"Accueil"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Durée restante :<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Petite"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Par défaut"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Plus grande"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"La plus grande"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 0639f1f..ee40b2a 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Synthèse vocale"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Cadence"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Vitesse à laquelle le texte est énoncé"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affecte le ton utilisé pour la synthèse vocale"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Langue"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Utiliser la langue du système"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Langue non sélectionnée"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Afficher tous les messages ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Afficher \"L\'application ne répond plus\" pour applis en arrière-plan"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forcer disponibilité stockage externe pour applis"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rend possible enregistrement de toute appli sur espace stockage externe, indépendamment valeurs fichier manifeste."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Rend possible l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forcer possibilité de redimensionner les activités"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permettre de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Application active. Appuyez ici pour la désactiver."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Services en cours d\'exécution"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Afficher et contrôler les services en cours d\'exécution"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Mode Nuit"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Toujours activé"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activer WebView multiprocessus"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Exécuter moteurs de rendu WebView dans un processus isolé."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La mise en œuvre WebView sélectionnée est désactivée. Vous devez l\'activer pour l\'utiliser. Souhaitez-vous l\'activer ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ce choix n\'est plus valide. Réessayez."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir en chiffrement basé sur un fichier"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Déjà chiffré via un fichier"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut affecter les performances."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>."</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant : <xliff:g id="TIME">%2$s</xliff:g> environ"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> (chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> (chargée à 100 %% sur secteur dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> (chargée à 100 %% via USB dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> (chargée à 100 %% sans fil dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Batterie en charge"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"En charge sur secteur"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"En charge via USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"En charge sans fil"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Pas en charge"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Débranchée"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"pleine"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Désactivé par l\'administrateur"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Activé par l\'administrateur"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Désactivé par l\'administrateur"</string>
     <string name="home" msgid="8263346537524314127">"Accueil"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Il reste <xliff:g id="ID_1">%1$s</xliff:g>."</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Petit"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Par défaut"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grand"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Plus grand"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Le plus grand"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index 5622d63..4a0451e 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Síntese de voz"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidade da fala"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade á que se di o texto"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta ao ton da voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizar idioma do sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma non seleccionado"</string>
@@ -246,9 +248,9 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Mostrar todos os ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Informa que aplicación segundo plano non responde"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permiso de aplicacións de forma externa"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Fai que calquera aplicación se poida escribir nun almacenamento externo, independentemente dos valores expresados"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permite que calquera aplicación apta se poida escribir nun almacenamento externo, independentemente dos valores expresados"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar o axuste do tamaño das actividades"</string>
-    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, independentemente dos valores definidos."</string>
+    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite axustar o tamaño de todas as actividades para o modo multiventá, independentemente dos valores definidos."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Activar ventás de forma libre"</string>
     <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aplicación activa. Toca para alternar a configuración."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Servizos en execución"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Ver e controlar servizos actualmente en execución"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Desactivado"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Sempre activada"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activar WebView multiproceso"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executa os procesadores de WebView nun proceso illado."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementación de WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementación de WebView escollida está desactivada e, para poder usala, debe estar activada. Queres activala?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Esta opción xa non é válida. Téntao de novo."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter no encriptado baseado en ficheiros"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Xa se encriptou o ficheiro"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función é experimental e pode afectar ao rendemento."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Duración aproximada de <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - faltan aproximadamente <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar a carga con CA"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar a carga con USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar a carga co modo sen fíos"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Descoñecido"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Cargando"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Cargando con CA"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Cargando por USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Cargando sen fíos"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Non se está cargando"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Non está cargando"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desactivado polo administrador"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Opción controlada polo administrador"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Activado polo administrador"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Desactivado polo administrador"</string>
     <string name="home" msgid="8263346537524314127">"Inicio"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Hai <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Tempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeno"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminado"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Máis grande"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 2c1990f..becda28 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"ટેક્સ્ટ ટુ સ્પીચ આઉટપુટ"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"વાણી દર"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ટેક્સ્ટ બોલાયેલ છે તે ઝડપ"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"પિચ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"સિન્થેસાઇઝ કરેલ વાણીના ટોન પર અસર કરે છે"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ભાષા"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"સિસ્ટમ ભાષાનો ઉપયોગ કરો"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ભાષા પસંદ કરેલ નથી"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"બધા ANR બતાવો"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"પૃષ્ઠભૂમિ એપ્લિકેશનો માટે એપ્લિકેશન પ્રતિસાદ આપતી નથી સંવાદ બતાવો"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"બાહ્ય પર એપ્લિકેશનોને મંજૂરી આપવાની ફરજ પાડો"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ એપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ ઍપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"મૅનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવો."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"ફ્રિફોર્મ વિંડોઝ સક્ષમ કરો"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"સક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"ચાલુ સેવાઓ"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"રાત્રિ મોડ"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"અક્ષમ કરેલ"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"હંમેશાં ચાલુ"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"સ્વચલિત"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"મલ્ટિપ્રોસેસ WebView સક્ષમ કરો"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"પૃથક પ્રક્રિયામાં WebView રેંડરર્સ ચલાવો."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView અમલીકરણ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView અમલીકરણ સેટ કરો"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"પસંદ કરેલ WebView અમલીકરણ અક્ષમ કરેલ છે અને ઉપયોગ કરવા માટે સક્ષમ કરવું આવશ્યક છે, શું તમે તેને સક્ષમ કરવા માગો છો?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"આ વિકલ્પ હવે માન્ય નથી. ફરી પ્રયાસ કરો."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ફાઇલ એન્ક્રિપ્શનમાં રૂપાંતરિત કરો"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"રૂપાંતરિત કરો..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ફાઇલ પહેલેથી જ એન્ક્રિપ્ટ કરેલ છે"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"આ સુવિધા પ્રાયોગિક છે અને કામગીરી પર અસર કરી શકે છે."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"અંદાજે. <xliff:g id="TIME">%1$s</xliff:g> બાકી"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - આશરે <xliff:g id="TIME">%2$s</xliff:g> બાકી"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"સંપૂર્ણ થવામાં <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g>, AC પર પૂર્ણ ચાર્જ થયાંને <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g>, USB પર પૂર્ણ ચાર્જ થયાંને <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> વાયરલેસ દ્વારા પૂર્ણ થાય ત્યાં સુધી"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"અજાણ્યું"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ચાર્જ થઈ રહ્યું છે"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC પર ચાર્જિંગ"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB થી ચાર્જિંગ"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"વાયરલેસથી ચાર્જિંગ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ચાર્જ થઈ રહ્યું નથી"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ચાર્જ થઈ રહ્યું નથી"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"પૂર્ણ"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"વ્યવસ્થાપક દ્વારા અક્ષમ"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"વ્યવસ્થાપક દ્વારા સક્ષમ કરેલ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ"</string>
     <string name="home" msgid="8263346537524314127">"હોમ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> પહેલાં"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> બાકી"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"નાનું"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ડિફોલ્ટ"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"મોટું"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"વધુ મોટું"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"સૌથી મોટું"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 7deb05c..6dffdd9 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"लेख को सुनें"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"बोली दर"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"बोलने की गति तय करें"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"पिच"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"कृत्रिम बोली के लहजे को प्रभावित करता है"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"भाषा"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"सिस्‍टम भाषा का उपयोग करें"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"भाषा नहीं चुनी गई है"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"सभी ANR दिखाएं"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"पृष्ठभूमि ऐप्स के लिए ऐप्स प्रतिसाद नहीं दे रहा डॉयलॉग दिखाएं"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"ऐप्स को बाहरी मेमोरी पर बाध्‍य करें"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"इससे कोई भी ऐप मेनिफेस्‍ट मान अनदेखा करके, बाहरी मेमोरी पर लिखने योग्‍य बन जाता है"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"इससे कोई भी ऐप्लिकेशन, मेनिफेस्ट मानों को अनदेखा करके, बाहरी मेमोरी पर लिखने योग्य बन जाता है"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"आकार बदले जाने के लिए गतिविधियों को बाध्य करें"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"सभी गतिविधियों को एकाधिक विंडो के लिए आकार बदलने योग्य बनाएं, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो सक्षम करें"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय. टॉगल करने पर टैप करें."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"चल रही सेवाएं"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"वर्तमान में चल रही सेवाओं को देखें और नियंत्रित करें"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"रात्रि मोड"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"अक्षम"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"हमेशा चालू"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"मल्टीप्रोसेस WebView सक्षम करें"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"किसी अलग प्रक्रिया में WebView रेंडरर चलाएं."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट करें"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"चुना गया WebView कार्यान्वयन अक्षम है और उसे उपयोग करने के लिए सक्षम किया जाना आवश्यक है, क्या आप उसे सक्षम करना चाहते हैं?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"यह चयन अब मान्य नहीं है. पुनः प्रयास करें."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"फ़ाइल एन्क्रिप्शन में रूपांतरित करें"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करें..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फ़ाइल पहले से एन्क्रिप्ट की हुई है"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यह सुविधा प्रायोगिक है और निष्पादन को प्रभावित कर सकती है."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%1$s</xliff:g> शेष"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - लगभग <xliff:g id="TIME">%2$s</xliff:g> शेष"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूरी होने तक"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC पर पूरी होने तक"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB पर पूरी होने तक"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> वायरलेस से पूरी होने तक"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"चार्ज हो रही है"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC से चार्ज हो रही"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB पर चार्ज हो रही"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"वायरलेस रूप से चार्ज हो रही"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"चार्ज नहीं हो रही है"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज नहीं हो रही है"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"पूरी"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"व्यवस्थापक के द्वारा अक्षम किया गया"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"व्यवस्थापक द्वारा नियंत्रित"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"व्यवस्थापक द्वारा सक्षम किया गया"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"व्यवस्थापक द्वारा अक्षम किया गया"</string>
     <string name="home" msgid="8263346537524314127">"होम"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहले"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शेष"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"छोटा"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"डिफ़ॉल्ट"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"बड़ा"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"अधिक बड़ा"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबसे बड़ा"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index ca58584..1edb015 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Pretvaranje teksta u govor"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina kojom se izgovara tekst"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Visina glasa"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utječe na ton sintetiziranog govora"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"upotrijebi jezik sustava"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije odabran"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Prikaži sve ANR-ove"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Prikaz dijaloga o pozad. aplik. koja ne odgovara"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Prisilno dopusti aplikacije u vanjskoj pohrani"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o manifestu"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o vrijednostima manifesta"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni mogućnost promjene veličine za aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući mijenjanje veličine svih aktivnosti za više prozora, neovisno o vrijednostima manifesta."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore slobodnog oblika"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dodirnite da biste to promijenili."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Pogledajte i nadzirite pokrenute procese"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Noćni način rada"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Uvijek uključeno"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatska"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogući višeprocesni WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokreni ispunjivače WebViewa u izoliranim procesima."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacija WebViewa"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Postavi implementaciju WebViewa"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Odabrana implementacija WebViewa onemogućena je i morate je omogućiti da biste je mogli upotrebljavati. Želite li je omogućiti?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Taj izbor više nije važeći. Pokušajte ponovo."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u enkripciju datoteka"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvori…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Enkripcija datoteka već je izvršena"</string>
@@ -301,22 +296,39 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova je značajka eksperimentalna i može utjecati na performanse."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Još <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – još približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> – još <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti"</string>
+    <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti strujnim napajanjem"</string>
+    <string name="power_charging_duration_ac_short" msgid="7895864687218765582">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti putem USB-a"</string>
+    <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti bežičnim putem"</string>
+    <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Punjenje"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Punjenje punjačem"</string>
+    <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"Punjenje"</string>
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Punjenje putem USB-a"</string>
+    <string name="battery_info_status_charging_usb_short" msgid="6733371990319101366">"Punjenje"</string>
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bežično punjenje"</string>
+    <string name="battery_info_status_charging_wireless_short" msgid="752569941028903610">"Punjenje"</string>
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ne puni se"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolira administrator"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio administrator"</string>
     <string name="home" msgid="8263346537524314127">"Početni zaslon"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malo"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Zadano"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliko"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veće"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 365c409..060599c 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Szövegfelolvasás"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Beszéd sebessége"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"A szöveg kimondásának sebessége"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Hangmagasság"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Az előállított beszédhang hangszínét befolyásolja"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Nyelv"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"A rendszer nyelvének használata"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Nincs nyelv kiválasztva"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Összes ANR mutatása"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Az Alkalmazás nem válaszol ablak megjelenítése"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Külső tárhely alkalmazásainak engedélyezése"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lehetővé teszi, hogy külső tárhelyre lehessen írni"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Lehetővé teszi bármely alkalmazás külső tárhelyre való írását a jegyzékértékektől függetlenül"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tevékenységek átméretezésének kényszerítése"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Legyen az összes tevékenység átméretezhető a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Szabad formájú ablakok engedélyezése"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Bekapcsolva. Koppintson ide a váltáshoz."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Futó szolgáltatások"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"A jelenleg futó szolgáltatások megtekintése és vezérlése"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Éjszakai mód"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Kikapcsolva"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Mindig bekapcsolva"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatikus"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Többfolyamatos WebView indítása"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView-megjelenítők futtatása külön folyamatként."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-megvalósítás"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-megvalósítás beállítása"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A kiválasztott WebView-megvalósítás le van tiltva, a használathoz viszont engedélyezni kell. Szeretné engedélyezni?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ez a választás már nem érvényes. Próbálkozzon újra."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertálás fájlalapú titkosításra"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertálás…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Már fájlalapú titkosítást használ"</string>
@@ -301,22 +296,39 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ez egy kísérleti funkció, és hatással lehet a teljesítményre."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kb. <xliff:g id="TIME">%1$s</xliff:g> van hátra"</string>
+    <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> van hátra"</string>
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – kb. <xliff:g id="TIME">%2$s</xliff:g> van hátra"</string>
+    <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> van hátra"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes töltöttség eléréséig"</string>
+    <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes feltöltésig hálózatról"</string>
+    <string name="power_charging_duration_ac_short" msgid="7895864687218765582">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes feltöltésig USB-ről"</string>
+    <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a feltöltésig vezeték nélkül"</string>
+    <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Ismeretlen"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Töltés"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Hálózati töltés"</string>
+    <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"Töltés"</string>
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB-s töltés"</string>
+    <string name="battery_info_status_charging_usb_short" msgid="6733371990319101366">"Töltés"</string>
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Nem vezetékes töltés"</string>
+    <string name="battery_info_status_charging_wireless_short" msgid="752569941028903610">"Töltés"</string>
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nem tölt"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nem töltődik"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Feltöltve"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Letiltva a rendszergazda által"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Rendszergazda által irányítva"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Engedélyezve a rendszergazda által"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Letiltva a rendszergazda által"</string>
     <string name="home" msgid="8263346537524314127">"Főoldal"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Ennyi ideje: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> van hátra"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kicsi"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Alapértelmezett"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Nagy"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Nagyobb"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Legnagyobb"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index b210698..63c4336 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Գրվածքից խոսք ելք"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Խոսքի գնահատական"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Տեքստի արտասանման արագությունը"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Բարձրություն"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ազդում է սինթեզած խոսքի ձայներանգի վրա"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Լեզու"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Օգտագործել համակարգի լեզուն"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Լեզուն ընտրված չէ"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Ցույց տալ բոլոր ANR-երը"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Ցուցադրել այն ծրագիրը, որը չի արձագանքում երկխոսությունը հետնաշերտի ծրագրերի համար"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Միշտ թույլատրել ծրագրեր արտաքին պահեստում"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Թույլ է տալիս պահել հավելվածը արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Թույլ է տալիս ցանկացած հավելված պահել արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Ստիպել, որ ակտիվությունների չափերը լինեն փոփոխելի"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Ակտիվացնել կամայական ձևի պատուհանները"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Ակտիվ է: Հպեք՝ փոխելու համար:"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Աշխատեցվող ծառայություններ"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Դիտել և վերահսկել ընթացիկ աշխատեցվող ծառայությունները"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Գիշերային ռեժիմ"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Անջատված"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Միշտ միացված"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Ավտոմատ"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Միացնել բազմագործընթաց WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Գործարկել WebView-ի մշակիչները առանձնացված գործընթացում:"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-ի իրականացում"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ընտրեք WebView-ի իրականացումը"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"WebView-ի իրականացման ընտրված եղանակն անջատված է և օգտագործելու համար պետք է նախ միացվի: Միացնե՞լ:"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Այս ընտրանքն այլևս վավեր չէ: Փորձեք նորից:"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Վերածել ֆայլային գաղտնագրման"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Փոխարկել…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ֆայլային գաղտնագրումն արդեն կատարվել է"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Սա փորձնական գործառույթ է և կարող է ազդել աշխատանքի վրա:"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Մնացել է մոտ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - մնաց մոտավորապես <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը հոսանքից"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը USB-ով"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը անլար ցանցից"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Անհայտ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Լիցքավորում"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Լիցքավորում AC-ով"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Լիցքավորում USB-ով"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Անլար լիցքավորում"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Չի լիցքավորվում"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Չի լիցքավորվում"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Լիցքավորված"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Կասեցված է ադմինիստրատորի կողմից"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Միացված է ադմինիստրատորի կողմից"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Կասեցված է ադմինիստրատորի կողմից"</string>
     <string name="home" msgid="8263346537524314127">"Գլխավոր էջ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> առաջ"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Մնացել է <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Փոքր"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Կանխադրված"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Մեծ"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Ավելի մեծ"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ամենամեծ"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Հատուկ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 33e869c..c86c768 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Keluaran text-to-speech"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Laju bicara"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Kecepatan teks diucapkan"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tinggi nada"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Memengaruhi nada ucapan yang disintesis"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Bahasa"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Gunakan bahasa sistem"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Bahasa tidak dipilih"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Tampilkan semua ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Tmplkn dialog Apl Tidak Merespons utk apl ltr blkg"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Paksa izinkan aplikasi di eksternal"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksterna"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksternal, terlepas dari nilai manifes"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktivitas agar ukurannya dapat diubah"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Buat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Aktifkan jendela berformat bebas"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktif. Ketuk untuk beralih."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Layanan yang sedang berjalan"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Melihat dan mengontrol layanan yang sedang berjalan"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Mode malam"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Dinonaktifkan"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Selalu aktif"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Otomatis"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktifkan WebView multiproses"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Jalankan perender WebView dalam proses yang terisolasi."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Penerapan WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setel penerapan WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Implementasi WebView yang dipilih telah dinonaktifkan, dan harus diaktifkan agar dapat digunakan. Ingin mengaktifkannya?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Pilihan ini tidak valid lagi. Coba lagi."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konversi ke enkripsi file"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konversi..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sudah dienkripsi berbasis file"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Fitur ini bersifat eksperimental dan dapat memengaruhi kinerja."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kira-kira tersisa <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira tersisa. <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sampai penuh"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sampai penuh pada AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sampai penuh melalui USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sampai penuh dari nirkabel"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Mengisi daya"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Mengisi daya pada AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Isi daya lewat USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Isi daya nirkabel"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Tidak mengisi daya"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Tidak mengisi daya"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dinonaktifkan oleh administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikontrol oleh admin"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Diaktifkan oleh administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Dinonaktifkan oleh administrator"</string>
     <string name="home" msgid="8263346537524314127">"Layar Utama"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> lalu"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Tersisa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kecil"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Besar"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lebih besar"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index b79dcf8..1fc0dc0 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Úttak upplesturs"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Talhraði"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Hraði talaðs texta"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tónhæð"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Hefur áhrif á raddblæ talgervils"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Tungumál"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Nota tungumál kerfis"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Tungumál ekki valið"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Öll forrit sem svara ekki"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Sýna „Forrit svarar ekki“ fyrir bakgrunnsforrit"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Þvinga fram leyfi forrita í ytri geymslu"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gerir hvaða forriti sem er kleift að skrifa í ytri geymslu, burtséð frá gildum í upplýsingaskrá"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Gerir öll forrit skrifanleg í ytra geymslurými, óháð gildum í upplýsingaskrá"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Þvinga breytanlega stærð virkni"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gera stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Virkja glugga með frjálsu sniði"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Virkt. Ýttu til að breyta."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Þjónustur í gangi"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Skoða og stjórna þjónustum í gangi"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Næturstilling"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Óvirkt"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Alltaf kveikt"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Sjálfvirkt"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Virkja WebView í fjölvinnslu"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Keyra WebView teiknun í lokuðu ferli."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Innleiðing WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stilla innleiðingu WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Slökkt er á valinni innleiðingu WebView. Kveikja þarf á henni til að hægt sé að nota hana. Viltu gera það?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Þetta val er ekki lengur gilt. Reyndu aftur."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Umbreyta í dulkóðun skráa"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Umbreyta…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Þegar dulkóðað á grundvelli skráa"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Þessi eiginleiki er á tilraunastigi og getur haft áhrif á frammistöðu."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Um það bil <xliff:g id="TIME">%1$s</xliff:g> eftir"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – u.þ.b. <xliff:g id="TIME">%2$s</xliff:g> eftir"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> í fulla hleðslu"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> í fulla hleðslu með hleðslutæki"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> í fulla hleðslu í gegnum USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> í fulla hleðslu þráðlaust"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Óþekkt"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Í hleðslu"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Hleðslutæki tengt"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Hleður um USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Hleður þráðlaust"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ekki í hleðslu"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ekki í hleðslu"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fullhlaðin"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Stjórnandi gerði óvirkt"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Stjórnað af kerfisstjóra"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Virkjað af stjórnanda"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Stjórnandi gerði óvirkt"</string>
     <string name="home" msgid="8263346537524314127">"Heim"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Fyrir <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> eftir"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Lítið"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Sjálfgefið"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stórt"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Stærra"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Stærst"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index d5753c4..78cd29b 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Output sintesi vocale"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocità voce"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocità di pronuncia del testo"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tono"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Si applica al tono della sintesi vocale"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Lingua"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usa lingua di sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Lingua non selezionata"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Mostra tutti errori ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Mostra finestra ANR per applicazioni in background"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forza autorizzazione app su memoria esterna"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rende l\'app idonea all\'installaz. su mem. esterna, senza considerare i valori manifest"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Consente l\'installazione di qualsiasi app su memoria esterna, indipendentemente dai valori manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Imponi formato modificabile alle attività"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Rendi il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Attiva finestre a forma libera"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Attiva. Tocca per attivare/disattivare."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Servizi in esecuzione"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Visualizza e controlla i servizi attualmente in esecuzione"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modalità Notte"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Disattivato"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Sempre attivo"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatico"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Attiva WebView multiprocesso"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Esegui renderer WebView in un processo isolato."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementazione di WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Imposta l\'implementazione di WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"L\'implementazione di WebView selezionata non è attiva e deve essere attivata per poterla utilizzare. Vuoi attivarla?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"La selezione non è più valida. Riprova."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Converti in crittografia basata su file"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converti..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Crittografia su base file già eseguita"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Questa funzione è sperimentale e potrebbe influire sulle prestazioni."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Circa <xliff:g id="TIME">%1$s</xliff:g> rimanenti"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tempo rimanente: <xliff:g id="TIME">%2$s</xliff:g> circa"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla carica completa"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla carica completa tramite CA"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla carica completa tramite USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lla carica completa con wireless"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Sconosciuta"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"In carica"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"In carica tramite CA"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"In carica tramite USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"In carica, wireless"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Non in carica"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Non in carica"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Carica"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disattivata dall\'amministratore"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Gestita dall\'amministratore"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Attivata dall\'amministratore"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Disattivata dall\'amministratore"</string>
     <string name="home" msgid="8263346537524314127">"Home page"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Piccolo"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predefinito"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Più grande"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Massimo"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index ee2588f..16e0f44 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"פלט טקסט לדיבור"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"קצב דיבור"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"המהירות שבה הטקסט נאמר"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"גובה צליל"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"משפיע על הטון של הדיבור המסונתז"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"שפה"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"שימוש בשפת המערכת"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"לא נבחרה שפה"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"‏הצג את כל פריטי ה-ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"הצג תיבת דו-שיח של \'אפליקציה לא מגיבה\' עבור אפליקציות שפועלות ברקע"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"אילוץ הרשאה של אפליקציות באחסון חיצוני"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"אלץ יכולת קביעת גודל של הפעילויות"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"אפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"הפעל את האפשרות לשנות את הגודל והמיקום של החלונות"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"אפליקציה פעילה. הקש כדי להחליף מצב."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"שירותים פועלים"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"הצג ושלוט בשירותים הפועלים כעת"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"מצב לילה"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"מושבת"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"פועל תמיד"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"באופן אוטומטי"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"הפעל תצוגת אתר לריבוי עיבודים"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"הרץ מעבדי תצוגת אתר בהליך מבודד"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"‏יישום WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏הגדרת יישום WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏יישום ה-WebView שנבחר מושבת, ויש להפעיל אותו כדי להשתמש בו. האם ברצונך להפעיל אותו?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"אפשרות זו כבר אינה תקפה. נסה שוב."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"המר להצפנת קבצים"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"המר..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"הצפנת קבצים כבר מוגדרת"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"תכונה זו היא ניסיונית ועשויה להשפיע על הביצועים."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"נשארו <xliff:g id="TIME">%1$s</xliff:g> בערך"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="TIME">%2$s</xliff:g> בקירוב עד לסיום"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>‏ - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> ‏- <xliff:g id="TIME">%2$s</xliff:g> עד למילוי"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> ‏- <xliff:g id="TIME">%2$s</xliff:g> עד למילוי בזרם חילופין"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"‏<xliff:g id="LEVEL">%1$s</xliff:g> ‏- <xliff:g id="TIME">%2$s</xliff:g> עד למילוי ב-USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> ‏- <xliff:g id="TIME">%2$s</xliff:g> עד למילוי בטעינה אלחוטית"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"לא ידוע"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"טוען"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"טוען בזרם חילופין"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"‏טוען ב-USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"טוען באופן אלחוטי"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"לא בטעינה"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"לא טוען"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"מלא"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"הושבת על ידי מנהל המערכת"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"נמצא בשליטת מנהל מערכת"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"הופעל על ידי מנהל המערכת"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"הושבת על ידי מנהל המערכת"</string>
     <string name="home" msgid="8263346537524314127">"דף הבית"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"לפני <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"נשארו <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"קטן"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ברירת מחדל"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"גדול"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"יותר גדול"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"הכי גדול"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"מותאם אישית (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 67bf4b0..ce405df 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"テキスト読み上げの出力"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"音声の速度"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"テキストの読み上げ速度"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"音の高さ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"合成音声のトーンに影響します"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"言語"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"システムの言語を使用"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"言語が選択されていません"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"すべてのANRを表示"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"バックグラウンドアプリが応答しない場合に通知する"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"外部ストレージへのアプリの書き込みを許可"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"アクティビティをサイズ変更可能にする"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようにします。"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"フリーフォーム ウィンドウの有効化"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"有効です。タップすると切り替わります。"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"実行中のサービス"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"現在実行中のサービスを表示して制御する"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"夜間モード"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"無効"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"常にON"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"複数プロセス WebView を有効化"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"別個のプロセスで WebView レンダラを実行します。"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView の実装"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView の実装の設定"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"選択した WebView の実装は無効になっていますが、使用するには有効にする必要があります。有効にしますか?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"この選択は無効になりました。もう一度お試しください。"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ファイル暗号化に変換する"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"変換…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ファイルは既に暗号化済みです"</string>
@@ -301,24 +296,50 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"この機能は試験運用機能であり、パフォーマンスに影響することがあります。"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"あと約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 残り約<xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで<xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで<xliff:g id="TIME">%2$s</xliff:g>(AC)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで<xliff:g id="TIME">%2$s</xliff:g>(USB)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで<xliff:g id="TIME">%2$s</xliff:g>(ワイヤレス)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"不明"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"充電中"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"ACで充電しています"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USBで充電しています"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"無線で充電しています"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"充電していません"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"充電していません"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for battery_info_status_full (2824614753861462808) -->
     <skip />
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理者によって無効にされています"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"管理者により管理されています"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"管理者によって有効にされています"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"管理者によって無効にされています"</string>
     <string name="home" msgid="8263346537524314127">"ホーム"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"あと <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"デフォルト"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"特大"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"カスタム(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index f441fa0..20a1d2a 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"მეტყველების სინთეზი"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"მეტყველების ტემპი"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ტექსტის თხრობის სიჩქარე"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"სიმაღლე"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"გავლენას ახდენს სინთეზირებული ხმის სიძლიერეზე"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ენა"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"სისტემის ენის გამოყენება"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ენა არჩეული არ არის"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"ყველა ANR-ის ჩვენება"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"შეტყობინების ჩვენება, როცა ფონური აპლიკაცია არ პასუხობს"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"აპების დაშვება გარე მეხსიერებაში"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"აპები ჩაიწერ. გარე მეხს.-ზე აღწ. ფაილის მნიშვნ. მიუხედ."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"აპები ჩაიწერება გარე მეხსიერებაზე აღწერის ფაილების მნიშვნელობების მიუხედავად"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ზომაცვლადი აქტივობების იძულება"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"მანიფესტის მნიშვნელობების მიუხედავად, მრავალი ფანჯრის რეჟიმისთვის ყველა აქტივობის ზომაცვლადად გადაქცევა."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"აქტიური. შეეხეთ გადასართავად."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"მიმდინარე სერვისები"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"ღამის რეჟიმი"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"გამორთულია"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"ყოველთვის ჩართული"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ავტომატური"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"მრავალპროც. WebView-ს ჩართვა"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView ვიზუალიზატორების იზოლირებულ პროცესში გაშვება."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView რეალიზაცია"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView რეალიზაციის დაყენება"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"არჩეული WebView რეალიზაცია გათიშულია და გამოყენებამდე უნდა ჩაირთოს. გსურთ მისი ჩართვა?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"თქვენი არჩევანი აღარ მოქმედებს. ცადეთ ხელახლა."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ფაილების დაშიფვრაზე გარდაქმნა"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"გარდაქმნა…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"უკვე დაშიფრულია ფაილების დონეზე"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ეს ფუნქცია საცდელია და შეიძლება გავლენა იქონიოს შესრულებაზე."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"დარჩენილია დაახლოებით <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"დაახლ. <xliff:g id="LEVEL">%1$s</xliff:g> დარჩენილია <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> სრულ დატენვამდე"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ელკვებით სრულ დატენვამდე"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB-თი სრულ დატენვამდე"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> უსადენოდან სრულ დატენვამდე"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"უცნობი"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"იტენება"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"დატენვა ელკვებაზე"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"დატენვა USB-ზე"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"დატენვა უსადენოდ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"არ იტენება"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"არ იტენება"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ბატარეა დატენილია"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"გათიშულია ადმინისტრატორის მიერ"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"იმართება ადმინისტრატორის მიერ"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"ჩართულია ადმინისტრატორის მიერ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"გათიშულია ადმინისტრატორის მიერ"</string>
     <string name="home" msgid="8263346537524314127">"მთავარი"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"გავიდა <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"დარჩენილია <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"პატარა"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ნაგულისხმევი"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"დიდი"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"უფრო დიდი"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"უდიდესი"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index fb5ab12..e71c8d0 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Мәтінді тілге айналдыру"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Сөйлеу жылдамдығы"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Мәтіннің оқылу жылдамдығы"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Дауыс жиілігі"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Синтезделген сөйлеу үніне әсер етеді"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Тіл"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Жүйелік тілді пайдалану"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Тіл таңдалған жоқ"</string>
@@ -246,11 +248,11 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Барлық ANR (қолданба жауап бермеді) хабарларын көрсетіңіз"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Фондық қолданбалардың жауап бермегенін көрсету"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Сыртқыда қолданбаларға мәжбүрлеп рұқсат ету"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттерді өлшемін өзгертуге болатын етуге мәжбүрлеу"</string>
-    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string>
+    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест мәндеріне қарамастан бірнеше терезе режимінде барлық әрекеттердің өлшемін өзгертуге рұқсат беру."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Еркін пішіндегі терезелерді қосу"</string>
-    <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Эксперименттік еркін терезелерді қолдауды қосу."</string>
+    <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Еркін пішінді терезелерді құру эксперименттік функиясын қосу."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Компьютер үстелінің сақтық көшірмесі"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Жұмыс үстелінің сақтық көшірмелері қазір қорғалмаған"</string>
     <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Үстелдік компьютердің толық сақтық көшірмелерінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Белсенді. Ауыстырып қосу үшін түртіңіз."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Қосылып тұрған қызметтер"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Ағымдағы қосылып тұрған қызметтерді көру және басқару"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Түнгі режим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Өшірілген"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Әрқашан қосулы"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Aвтоматты"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Бірнеше процесті веб-көріністі қосу"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Веб-көрініс бейнелеушілерін оқшауланған процесте іске қосу."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ендіру"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ендіруін орнату"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Таңдалған веб-көріністі енгізу өшірілген және пайдалану үшін оны қосу керек. Оны қосу керек пе?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Бұл таңдау енді жарамды емес. Әрекетті қайталаңыз."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Файлды шифрлауға түрлендіру"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Түрлендіру..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл шифрланып қойылған"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бұл мүмкіндік эксперименттік болып табылады және өнімділікке әсер етуі мүмкін."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - шамамен <xliff:g id="TIME">%2$s</xliff:g> қалды"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - толғанша <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - айнымалы токпен толғанша <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - USB арқылы толғанша <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - сымсыз толғанша <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Белгісіз"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Зарядталуда"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Айнымалы токпен зар."</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB арқылы зарядтау"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Сымсыз зарядтау"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Зарядталу орындалып жатқан жоқ"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Зарядталып тұрған жоқ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Толық"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Әкімші өшірген"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Әкімші басқарады"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Әкімші қосқан"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Әкімші өшірген"</string>
     <string name="home" msgid="8263346537524314127">"Негізгі бет"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> бұрын"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> қалды"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Кішкентай"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Әдепкі"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Үлкен"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Үлкенірек"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ең үлкен"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Арнаулы (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index c1946c4..687b71b 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"លទ្ធផល​អត្ថបទ​ទៅ​ការ​និយាយ"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"អត្រា​និយាយ"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ល្បឿន​ពេល​អាន​​អត្ថបទ"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"ឡើង​-ចុះ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ប៉ះពាល់ដល់សំឡេងនៃការនិយាយដែលបានបម្លែង"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ភាសា"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"ប្រើ​ភាសា​ប្រព័ន្ធ"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"មិន​បាន​ជ្រើស​ភាសា"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"បង្ហាញ ANRs ទាំងអស់"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"បង្ហាញ​ប្រអប់​កម្មវិធី​មិន​ឆ្លើយតប​សម្រាប់​កម្មវិធី​ផ្ទៃ​ខាង​ក្រោយ"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"បង្ខំឲ្យអនុញ្ញាតកម្មវិធីលើឧបករណ៍ផ្ទុកខាងក្រៅ"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេស។"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"សកម្ម។ ប៉ះដើម្បីបិទ/បើក។"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"សេវាកម្ម​កំពុង​ដំណើរការ"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"មើល និង​គ្រប់គ្រង​សេវាកម្ម​កំពុង​ដំណើរការ​បច្ចុប្បន្ន"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"របៀបពេលយប់"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"បានបិទ"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"បើកជានិច្ច"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ស្វ័យប្រវត្តិ"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"បើកដំណើរការ WebView ដែលមានអង្គដំណើរការច្រើន"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ដំណើរការកម្មវិធីបំលែង WebView ក្នុងដំណើរការដាច់ដោយឡែក"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"ការប្រតិបត្តិ WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"កំណត់ការប្រតិបត្តិ WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ការប្រតិបត្តិការ WebView ដែលបានជ្រើសត្រូវបានបិទដំណើរការ ប៉ុន្តែអ្នកត្រូវបើកដំណើរការវាដើម្បីប្រើ តើអ្នកចង់បើកដំណើរការវាដែរឬទេ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ជម្រើសនេះលែងមានសុពលភាពទៀតហើយ ព្យាយាមម្តងទៀត"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"បម្លែងទៅជាការអ៊ីនគ្រីបឯកសារ"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"បម្លែង…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"បានអ៊ីនគ្រីបឯកសាររួចហើយ"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"លក្ខណៈ​នេះ​គឺ​ជា​ការ​ពិសោធន៍ ហើយ​អាច​ប៉ះពាល់​ការ​អនុវត្ត។"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"បដិសេធ​ដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"នៅសល់ប្រហែល <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅ​សល់​ប្រហែល <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូត​ដល់​ពេញ"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូត​ដល់ពេញ​រចន្ត​ឆ្លាស់"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូត​ដល់​ពេញ​តាមយូអេសប៊ី"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូត​ដល់​ពេញ​ពី​ឥតខ្សែ"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"មិន​ស្គាល់"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"កំពុងបញ្ចូល​ថ្ម"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"បញ្ចូលថ្មតាម AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"បញ្ចូលថ្មតាមយូអេសប៊ី"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"បញ្ចូលថ្មដោយ​​ឥតខ្សែ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"មិនកំពុង​បញ្ចូល​ថ្ម"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"មិន​បញ្ចូលថ្ម"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ពេញ"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"គ្រប់គ្រងដោយអ្នកគ្រប់គ្រង"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"បានបើកដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
     <string name="home" msgid="8263346537524314127">"ដើម"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> មុន"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"នៅសល់ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"តូច"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"លំនាំដើម"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ធំ"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ធំជាង"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ធំបំផុត"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ផ្ទាល់ខ្លួន (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index a6acd17..713d9b3 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"ಧ್ವನಿಗೆ-ಪಠ್ಯದ ಔಟ್‌ಪುಟ್‌"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"ಧ್ವನಿಯ ದರ"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ಪಠ್ಯವನ್ನು ಹೇಳಿದ ವೇಗ"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"ಪಿಚ್"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ಸಂಯೋಜಿತ ಧ್ವನಿಯ ಟೋನ್ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುತ್ತದೆ"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ಭಾಷೆ"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"ಸಿಸ್ಟಂ ಭಾಷೆಯನ್ನು ಬಳಸು"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ಭಾಷೆಯನ್ನು ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"ಎಲ್ಲ ANR ಗಳನ್ನು ತೋರಿಸು"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"ಹಿನ್ನೆಲೆ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ ಎಂಬ ಸಂಭಾಷಣೆ ತೋರಿಸು"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"ಬಾಹ್ಯವಾಗಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಒತ್ತಾಯವಾಗಿ ಅನುಮತಿಸಿ"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳು ಯಾವುದೇ ಆಗಿದ್ದರೂ, ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡಿ."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"ಸಕ್ರಿಯ. ಟಾಗಲ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"ಈಗ ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"ರಾತ್ರಿ ಮೋಡ್"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"ಯಾವಾಗಲೂ ಆನ್"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ಸ್ವಯಂಚಾಲಿತ"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ಬಹುಪ್ರಕ್ರಿಯೆ WebView ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ಪ್ರತ್ಯೇಕಗೊಳಿಸಿದ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ WebView ರೆಂಡರರ್‌‌ ರನ್‌ ಮಾಡಿ."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ಆಯ್ಕೆಮಾಡಲಾದ WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಮತ್ತು ಬಳಸಲು ಸಕ್ರಿಯಗೊಳಿಸಬೇಕಾಗಿದೆ, ಇದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ನೀವು ಬಯಸುತ್ತೀರಾ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ಈ ಆಯ್ಕೆಯು ಇನ್ನು ಮುಂದೆ ಮಾನ್ಯವಾಗಿರುವುದಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ಫೈಲ್ ಎನ್‌ಕ್ರಿಪ್ಶನ್‌ಗೆ ಪರಿವರ್ತಿಸು"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ಪರಿವರ್ತಿಸು…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ಫೈಲ್ ಈಗಾಗಲೇ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ಇದು ಪ್ರಾಯೋಗಿಕ ವೈಶಿಷ್ಟ್ಯವಾಗಿದೆ. ಕಾರ್ಯಕ್ಷಮತೆ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರಬಹುದು."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"ಸುಮಾರು <xliff:g id="TIME">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"ಸುಮಾರು <xliff:g id="LEVEL">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> ಉಳಿದಿದೆ"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC ನಲ್ಲಿ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB ಮೂಲಕ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ವೈರ್‌‌ಲೆಸ್‌ನಿಂದ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಜ್ಞಾತ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC ನಲ್ಲಿ ಚಾರ್ಜ್‌"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB ಮೂಲಕ ಚಾರ್ಜ್‌"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ನಿಸ್ತಂತುವಾಗಿ ಚಾರ್ಜ್‌"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ಚಾರ್ಜ್‌ ಆಗುತ್ತಿಲ್ಲ"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ಭರ್ತಿ"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ನಿರ್ವಾಹಕರಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"ನಿರ್ವಾಹಕರಿಂದ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"ನಿರ್ವಾಹಕರಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="home" msgid="8263346537524314127">"ಮುಖಪುಟ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ಹಿಂದೆ"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ಸಣ್ಣದು"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ಡಿಫಾಲ್ಟ್"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ದೊಡ್ಡದು"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ಸ್ವಲ್ಪ ದೊಡ್ಡ"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ದೊಡ್ಡ"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ಕಸ್ಟಮ್ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index c8bb2e6..348141e 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"TTS 출력"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"말하는 속도"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"텍스트를 읽어주는 속도"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"피치"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"합성 음성의 어조에 영향을 미침"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"언어"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"시스템 언어 사용"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"언어가 선택되지 않음"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"모든 ANR 보기"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"백그라운드 앱에 대해 앱 응답 없음 대화상자 표시"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"외부에서 앱 강제 허용"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"매니페스트 값에 관계없이 앱을 외부 저장소에 작성"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"매니페스트 값과 관계없이 모든 앱이 외부 저장소에 작성되도록 허용"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"활동의 크기가 조정 가능하도록 설정"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"자유 형식 창 사용"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"활성화되었습니다. 전환하려면 탭하세요."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"실행 중인 서비스"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"현재 실행 중인 서비스 보기 및 제어"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"야간 모드"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"사용 안함"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"항상 사용"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"자동"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"멀티 프로세스 WebView 사용"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"단독 프로세스 내에서 WebView 렌더러를 실행합니다."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 구현"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView 구현 설정"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"선택한 WebView 구현이 사용 중지되어 있습니다. 사용하려면 사용 설정해야 합니다. 사용 설정하시겠습니까?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"선택이 더 이상 유효하지 않습니다. 다시 시도하세요."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"파일 암호화로 변환"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"변환..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"파일이 이미 암호화됨"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"실험실 기능이며 성능에 영향을 줄 수 있습니다."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"약 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 대략 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료(AC 전원)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료(USB)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료(무선)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"알 수 없음"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"충전 중"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"충전 중(AC 전원)"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"충전 중(USB)"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"충전 중(무선)"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"충전 안함"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"충전 안함"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"충전 완료"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"관리자가 사용 중지함"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"관리자가 제어"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"관리자가 사용 설정함"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"관리자가 사용 중지함"</string>
     <string name="home" msgid="8263346537524314127">"홈"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> 전"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> 남음"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"작게"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"기본"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"크게"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"더 크게"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"가장 크게"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"맞춤(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 6f158c0..2016f04 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Текстти-оозекилөө"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Кеп ылдамдыгы"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Текст айтылчу ылдамдык"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Негизги тон"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Синтезделген кептин интонациясына таасирин тийгизет"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Тил"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Тутум тилин колдонуу"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Тил тандалган жок"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Бардык ANR\'лерди көрсөтүү"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Фондогу колдонмолорго Колдонмо Жооп Бербейт деп көрсөтүү"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Тышкы сактагычка сактоого уруксат берүү"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Аракеттердин өлчөмүн өзгөртүүнү мажбурлоо"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылуу."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Эркин формадагы терезелерди түзүүнү иштетүү"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Иштеп турат. Которуштуруу үчүн таптап коюңуз."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Иштеп жаткан кызматтар"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Учурда иштеп жаткан кызматтарды көрүү жана көзөмөлдөө"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Түнкү режим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Өчүрүлгөн"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Ар дайым күйгүзүлгөн"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Автоматтык"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Көп процесстүү WebView иштт"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView рендерерлерин корголгон процессте иштетүү."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"WebView кызматын пайдалануу үчүн аны иштетүү керек. Иштетесизби?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Тандалган нерсе жараксыз болуп калган. Кайра аракет кылыңыз."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Файл шифрлөөсүнө айландыруу"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Айландыруу…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл мурунтан эле шифрленген"</string>
@@ -300,23 +295,49 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Түсүн тууралоо"</string>
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бул сынамык мүмкүнчүлүк болгондуктан, иштин майнаптуулугуна таасир этиши мүмкүн."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
-    <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g>-чакты калды"</string>
+    <string name="power_remaining_duration_only" msgid="4400068916452346544">"Болжол менен <xliff:g id="TIME">%1$s</xliff:g> калды"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - болжол менен <xliff:g id="TIME">%2$s</xliff:g> саат калды"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> толгончо"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC аркылуу толгончо"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB аркылуу толгончо"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> зымсыз кубаттоо аркылуу толгончо"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Белгисиз"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Кубатталууда"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"ӨА кубатталууда"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB\'ден кубатталууда"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Зымсыз кубатталууда"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Кубат алган жок"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Кубатталган жок"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Толук"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Администратор өчүрүп койгон"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Администратор тарабынан көзөмөлдөнөт"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Администратор иштетип койгон"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Администратор өчүрүп койгон"</string>
     <string name="home" msgid="8263346537524314127">"Башкы бет"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> мурун"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> калды"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Кичине"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Демейки"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Чоң"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Чоңураак"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Эң чоң"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 7664212..7e6db5e 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"ການປ່ຽນຂໍ້ຄວາມເປັນສຽງ"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"ອັດຕາການເວົ້າ"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ຄວາມໄວໃນການເວົ້າຂໍ້ຄວາມ"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"ໂທນສຽງ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ມີຜົນກັບໂທນສຽງເວົ້າທີ່ສັງເຄາະ"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ພາສາ"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"​ໃຊ້​ພາ​ສາ​ຂອງ​ລະ​ບົບ"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ບໍ່ໄດ້ເລືອກພາສາ"</string>
@@ -246,9 +248,9 @@
     <string name="show_all_anrs" msgid="28462979638729082">"ສະ​ແດງ ANRs ທັງ​ຫມົດ"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"ສະແດງໜ້າຈໍແອັບຯທີ່ບໍ່ຕອບສະໜອງສຳລັບແອັບຯພື້ນຫຼັງ"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"ບັງຄັບອະນຸຍາດແອັບ​ຢູ່​ພາຍນອກ"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ເຮັດ​ໃຫ້ທຸກແອັບ​ມີ​ສິດ​ໄດ້ຮັບການຂຽນ​ໃສ່​ບ່ອນ​ຈັດ​ເກັບ​ພາຍນອກ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ເຮັດໃຫ້ທຸກແອັບມີສິດໄດ້ຮັບການຂຽນໃສ່ພື້ນທີ່ຈັດເກັບຂໍ້ມູນພາຍນອກ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ບັງ​ຄັງ​ໃຫ້​ກິດ​ຈະ​ກຳ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້"</string>
-    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ເຮັດ​ໃຫ້​ທຸກ​ກິດ​ຈະ​ກຳສາມາດປັບ​ຂະ​ໜາດ​ໄດ້​ສຳ​ລັບ​ຫຼາຍ​ໜ້າ​ຈໍ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ."</string>
+    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ເຮັດໃຫ້ທຸກກິດຈະກຳສາມາດປັບຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຈໍ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"ເປີດໃຊ້ໜ້າຕ່າງຮູບແບບອິດສະຫຼະ"</string>
     <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ເປີດໃຊ້ການຮອງຮັບໜ້າຈໍຮູບແບບອິດສະຫຼະແບບທົດລອງ."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"ນຳໃຊ້ຢູ່. ແຕະເພື່ອສັບປ່ຽນ."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"ໂໝດກາງຄືນ"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"ປິດໃຊ້ງານແລ້ວ"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"ເປີດຕະຫຼອດ"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ອັດຕະໂນມັດ"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ອະນຸຍາດໃຫ້ມີໂປຣເຊສ WebView ຫຼາຍອັນໄດ້"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ເປີດໃຊ້ຕົວປະມວນ WebView ໃນໂປຣເຊສທີ່ແຍກຈາກກັນໄດ້."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ຕັ້ງການຈັດຕັ້ງປະຕິບັດ WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ການຈັດຕັ້ງປະຕິບັດ WebView ທີ່ເລືອກຖືກປິດນຳໃຊ້, ແລະຕ້ອງຖືກເປີດນຳໃຊ້, ທ່ານຕ້ອງການເປີດນຳໃຊ້ມັນບໍ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ບໍ່ສາມາດໃຊ້ການເລືອກນີ້ໄດ້ອີກຕໍ່ໄປແລ້ວ. ກະລຸນາລອງໃໝ່."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ປ່ຽນ​ເປັນ​ການ​ເຂົ້າ​ລະ​ຫັດ​ໄຟ​ລ໌"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ປ່ຽນ..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ໄຟ​ລ໌​ເຂົ້າ​ລະ​ຫັດ​ຮຽບ​ຮ້ອຍ​ແລ້ວ"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"​ຄຸນ​ສົມ​ບັດ​ນີ້​ກຳ​ລັງ​ຢູ່​ໃນ​ການ​ທົດ​ລອງ​ແລະ​ອາດ​ມີ​ຜົນ​ຕໍ່​ປະ​ສິດ​ທິ​ພາບ."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"ຍັງເຫຼືອປະມານ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ​ເຫຼືອປະ​ມານ <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈຶ່ງ​ຈະ​ເຕັມ"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ​ຈຶ່ງ​ຈະ​ເຕັມ​ໂດຍສາກ​ດ້ວຍ​ໄຟ AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈຶ່ງ​ຈະ​ເຕັມ​ໂດຍສາກ​ດ້ວຍ USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ​ຈຶ່ງ​ຈະ​ເຕັມ​ໂດຍ​ສາກ​ແບບ​ໄຮ້​ສາຍ"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ກຳລັງສາກໄຟ"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"ກຳ​​ລັງ​ສາກ​ຜ່ານ​ໝໍ້​ໄຟ"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"ກຳ​ລັງ​ສາກ​ຜ່ານ USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ກຳ​ລັງ​ສາກ​ໄຮ້​ສາຍ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ບໍ່ໄດ້ສາກໄຟ"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ບໍ່ໄດ້ສາກໄຟ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ເຕັມ"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ຖືກປິດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ຄວບຄຸມໂດຍຜູ້ເບິ່ງແຍງ"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"ຖືກເປີດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"ຖືກປິດໄວ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
     <string name="home" msgid="8263346537524314127">"​ໜ້າຫຼັກ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ກ່ອນນີ້"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"ຍັງເຫຼືອ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ນ້ອຍ"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ຄ່າເລີ່ມຕົ້ນ"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ໃຫຍ່"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ໃຫຍ່ກວ່າ"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ໃຫຍ່ທີ່ສຸດ"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index c730dc0..d49876e 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"„Teksto į kalbą“ išvestis"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Kalbėjimo greitis"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Greitis, kuriuo sakomas tekstas"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Garso aukštis"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Daro poveikį susintetintai kalbai"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Kalba"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Naudoti sistemos kalbą"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Kalba nepasirinkta"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Rodyti visus ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Fon. programose rodyti dialogo langą „Neatsako“"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Priverstinai leisti programas išorinėje atmintin."</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Vis. pr. gal. įr. į vid. saug. nepais. apr. vert."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Nustatoma, kad visas programas būtų galima įrašyti į išorinę saugyklą, nepaisant aprašo verčių"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Nustatyti, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Įgalinti laisvos formos langus"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktyvi. Palieskite, kad perjungtumėte."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Vykdomos paslaugos"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Naktinis režimas"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Išjungta"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Visada įjungta"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatinė"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Įgal. kelių procesų „WebView“"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Paleisti „WebView“ pateikimo priemones vienam procesui."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"„WebView“ diegimas"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"„WebView“ diegimo nustatymas"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Pasirinktas „WebView“ diegimas išjungtas ir jį būtina įgalinti, kad būtų galima naudoti. Ar norite jį įgalinti?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Šios parinkties nebegalima pasirinkti. Bandykite dar kartą."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuoti į failų šifruotę"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuoti…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Jau konvertuota į failų šifruotę"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ši funkcija yra eksperimentinė ir ji gali turėti įtakos našumui."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Liko maždaug <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko maždaug <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> iki visiško įkrovimo"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> iki visiško įkrovimo naud. kint. sr."</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> iki visiško įkrovimo naudojant USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> iki visiško įkrovimo belaid. ryš."</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Nežinomas"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Kraunasi..."</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Įkr. naud. kint. sr."</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Įkraunama naud. USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Įkraunama be laidų"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nekraunama"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nekraunama"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Visiškai įkrautas"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Išjungė administratorius"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Valdo administratorius"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Įgalino administratorius"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Išjungė administratorius"</string>
     <string name="home" msgid="8263346537524314127">"Pagrindinis ekranas"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Prieš <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Liko <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mažas"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Numatytasis"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Didelis"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Didesnis"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Didžiausias"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 65e4cff..6cd9cfd5 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Teksta-runas izvade"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Runas ātrums"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Teksta ierunāšanas ātrums"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonis"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ietekmē sintezētās runas toni"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Valoda"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Izmantot sistēmas valodu"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Nav atlasīta valoda."</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Rādīt visus ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Rādīt fona lietotņu dialoglodz. Lietotne nereaģē"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Lietotņu piespiedu atļaušana ārējā krātuvē"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Pielāgot darbības"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Pielāgot visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Iespējot brīvās formas logus"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktīva. Pieskarieties, lai pārslēgtu."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Aktīvie pakalpojumi"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nakts režīms"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Atspējots"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Vienmēr ieslēgts"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automātiski"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Iespējot vairākprocesu WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Atsevišķā procesā tiek palaisti WebView renderētāji."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ieviešana"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Iestatīt WebView ieviešanu"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izvēlētā WebView ieviešana ir atspējota, un tā ir jāiespējo, lai to varētu izmantot. Vai vēlaties to iespējot?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Šī iespēja vairs nav derīga. Mēģiniet vēlreiz."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Pārvērst par failu šifrējumu"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pārvērst…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Jau šifrēts failu līmenī"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Šī funkcija ir eksperimentāla un var ietekmēt veiktspēju."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Atlikušais laiks: aptuveni <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> — aptuvenais atlikušais laiks: <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai maiņstrāvas uzlādei"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai USB uzlādei"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai bezvadu uzlādei"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Nezināms"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Uzlāde"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Maiņstrāvas uzlāde"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB uzlāde"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bezvadu uzlāde"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nenotiek uzlāde"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenotiek uzlāde"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Pilns"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Atspējojis administrators"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolē administrators"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Iespējojis administrators"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Atspējojis administrators"</string>
     <string name="home" msgid="8263346537524314127">"Sākums"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Pirms šāda laika: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Atlikušais laiks: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mazs"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Noklusējuma"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Liels"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lielāks"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Vislielākais"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 4576f3a..f8f65ec 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Излез текст-во-говор"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Брзина на говор"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Брзина со која се кажува текстот"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Интензитет"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Влијае на тонот на синтетизираниот говор"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Јазик"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Користете системски јазик"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Јазикот не е избран"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Прикажи ги сите ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Прикажи „Апл. не реагира“ за. апл. во заднина"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Принуд. дозволете апликации на надворешна меморија"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Запишува апл. во надв.меморија, незав. од манифест"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Прави секоја апликација да биде подобна за запишување на надворешна меморија, независно од вредностите на манифестот"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Принуди ги активностите да ја менуваат големината"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Направете сите активности да бидат со променлива големина за повеќе прозорци, без разлика на вредностите на манифестот."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Овозможи прозорци со слободна форма"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активно. Допрете за да смените."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Активни услуги"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Погледнете и контролирајте услуги што се моментално активни"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Ноќен режим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Оневозможено"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Секогаш вклучено"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Автоматски"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Овозможи мултипроцесен WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Активирајте ги WebView-прикажувачите во изолиран процес."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Воведување WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Поставете воведување WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Избраната примена на WebView е оневозможена, а за да се користи, мора да се овозможи. Дали сакате да ја овозможите?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овој избор веќе не важи. Обидете се повторно."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертирајте до шифрирање датотеки"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертирај..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Датотеката е веќе шифрирана"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Функцијата е експериментална и може да влијае на изведбата."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Преостанаа прибл. <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостанува приближно <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до целосно полна"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до целосно полна на AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до целосно полна преку USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до целосно полна, безжично"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Се полни"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Полнење на струја"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Полнење преку УСБ"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Безжично полнење"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Не се полни"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не се полни"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Целосна"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Оневозможено од администраторот"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролирано од администраторот"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Овозможено од администраторот"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Оневозможено од администраторот"</string>
     <string name="home" msgid="8263346537524314127">"Почетна страница"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Пред <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Преостанаа <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Мал"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Стандардно"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Голем"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Поголем"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Најголем"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 180d615..7350b7f 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"ടെക്‌സ്റ്റ്-ടു-സ്‌പീച്ച് ഔട്ട്‌പുട്ട്"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"വായന നിരക്ക്"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"വാചകം പറയുന്ന വേഗത"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"പിച്ച്"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"സിന്തസൈസ് ചെയ്ത സംസാരത്തിന്റെ സ്വരഭേദത്തെ ബാധിക്കുന്നു"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ഭാഷ"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"സി‌സ്റ്റം ഭാഷ ഉപയോഗിക്കുക"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ഭാഷ തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"എല്ലാ ANR-കളും ദൃശ്യമാക്കുക"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"പ‌ശ്ചാത്തല അപ്ലിക്കേഷനുകൾക്ക് അപ്ലിക്കേഷൻ പ്രതികരിക്കുന്നില്ല എന്ന ഡയലോഗ് കാണിക്കുക"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"ബാഹ്യമായതിൽ നിർബന്ധിച്ച് അനുവദിക്കുക"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"വലിപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ ആക്ടിവിറ്റികളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുക."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"നൈറ്റ് മോഡ്"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"പ്രവർത്തനരഹിതമാക്കി"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"എല്ലായ്‌പ്പോഴും ഓണാണ്"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ഓട്ടോമാറ്റിക്"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"മൾട്ടിപ്രോസസ്സ് WebView പ്രവർത്തനക്ഷമമാക്കൂ"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ഒറ്റപ്പെട്ടൊരു പ്രോസസ്സിൽ WebView റെൻഡററുകൾ റൺ ചെയ്യുക."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView നടപ്പാക്കൽ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView നടപ്പാക്കൽ സജ്ജമാക്കുക"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"തിരഞ്ഞെടുത്ത WebView നടപ്പാക്കൽ പ്രവർത്തനരഹിതമാക്കി, ഉപയോഗിക്കുന്നതിന് ഇത് പ്രവർത്തനക്ഷമമാക്കണം, പ്രവർത്തനക്ഷമമാക്കാൻ ആഗ്രഹിക്കുന്നുണ്ടോ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ഈ തിരഞ്ഞെടുപ്പിന് തുടർന്നങ്ങോട്ട് സാധുതയില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ഫയൽ എൻക്രിപ്ഷനിലേക്ക് പരിവർത്തിപ്പിക്കുക"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"പരിവർത്തിപ്പിക്കുക…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ഇതിനകം തന്നെ ഫയൽ എൻക്രിപ്റ്റ് ചെയ്തു"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ഈ ഫീച്ചർ പരീക്ഷണാത്മകമായതിനാൽ പ്രകടനത്തെ ബാധിച്ചേക്കാം."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ഏകദേശം <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമായും ചാർജ്ജാകുന്നതിന്, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - AC-യിൽ പൂർണ്ണമായും ചാർജ്ജാകുന്നതിന്, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - USB വഴി പൂർണ്ണമായും ചാർജ്ജാകുന്നതിന്, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - വയർലെസ് വഴി പൂർണ്ണമായും ചാർജ്ജാകുന്നതിന്, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"അജ്ഞാതം"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ചാർജ്ജുചെയ്യുന്നു"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC-യിൽ ചാർജ്ജുചെയ്യുന്നു"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB-യിലൂടെ ചാർജ്ജുചെയ്യുന്നു"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"വയർലെസ്സ് കണക്ഷനിലൂടെ ചാർജ്ജുചെയ്യുന്നു"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"നിറഞ്ഞു"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"അഡ്‌മിനിസ്ട്രേറ്റർ പ്രവർത്തനരഹിതമാക്കി"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"അഡ്‌മിൻ നിയന്ത്രിക്കുന്നത്"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"അഡ്‌മിനിസ്ട്രേറ്റർ പ്രവർത്തനക്ഷമമാക്കി"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"അഡ്‌മിനിസ്ട്രേറ്റർ പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="home" msgid="8263346537524314127">"ഹോം"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> മുമ്പ്"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ചെറുത്"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ഡിഫോൾട്ട്"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"വലുത്"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"കൂടുതൽ വലുത്"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ഏറ്റവും വലുത്"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ഇഷ്ടാനുസൃതം ( <xliff:g id="DENSITYDPI">%d</xliff:g> )"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index 8bdd880..7eeae06 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Текст-яриа гаргах"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Ярианы түвшин"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Текстийг унших хурд"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Авиа тон"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Авоматаар үүссэн ярианы дуудлаганд нөлөөлдөг"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Хэл"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Системийн хэлийг ашиглах"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Хэл сонгогдоогүй байна"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Бүх ANRs харуулах"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Далд апп-уудад Апп Хариу Өгөхгүй байна гэснийг харуулах"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Апп-ыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест утгыг нь үл хамааран дурын апп-ыг гадаад санах ойд бичих боломжтой болгодог"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Манифест утгыг нь үл хамааран дурын апп-г гадаад санах ойд бичих боломжтой болгодог"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Идэвхтэй байна. Унтраах/асаахын тулд дарна уу."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Ажиллаж байгаа үйлчилгээнүүд"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Одоо ажиллаж байгаа үйлчилгээнүүдийг харах болон хянах"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Шөнийн горим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Идэвхгүй"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Байнга асаалттай"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Автоматаар"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView-н олон боловсруулалтыг идэвхжүүлэх"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView хөрвүүлэгчийг тусдаа боловсруулалтаар ажиллуулна уу."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView хэрэгжилт"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView хэрэгжилтийг тохируулах"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Сонгосон WebView хэрэгжүүлэлтийг идэвхгүй болгосон бөгөөд хэрэглэхийн тулд заавал идэвхжүүлэх шаардлагатай. Үүнийг идэвхжүүлэх үү?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Энэ сонголт хүчингүй байна. Дахин оролдоно уу."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Файлын шифрлэлт болгон хөрвүүлэх"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Хөрвүүлэх..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Аль хэдийнэ файл шифрлэгдсэн"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Энэ функц туршилтынх бөгөөд ажиллагаанд нөлөөлж болзошгүй."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ойролцоогоор <xliff:g id="TIME">%2$s</xliff:g> үлдсэн"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"дүүртэл <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"АС-р дүүртэл <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"USB-р дүүртэл <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"утасгүй цэнэглэгчээр дүүртэл <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Тодорхойгүй"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Цэнэглэж байна"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC-р цэнэглэж байна"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB-р цэнэглэж байна"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Кабльгүйгээр цэнэглэж байна"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Цэнэглэхгүй байна"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Цэнэглэхгүй байна"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Дүүрэн"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Админ идэвхгүй болгосон"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Админ удирдсан"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Админ идэвхтэй болгосон"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Админ идэвхгүй болгосон"</string>
     <string name="home" msgid="8263346537524314127">"Нүүр"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> өмнө"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> үлдсэн"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Жижиг"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Өгөгдмөл"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Том"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Илүү том"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Хамгийн том"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Тогтмол утга (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 92247f5..0521ba1 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"टेक्स्ट-टू-स्पीच आउटपुट"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"बोलण्याचा रेट"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ज्या गतीने मजकूर बोलला जातो ती"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"पिच"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"संश्लेषित उच्चारांच्या आवाजास प्रभावित करते"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"भाषा"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"सिस्टम भाषा वापरा"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"भाषा निवडलेली नाही"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"सर्व ANR दर्शवा"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"पार्श्वभूमी अॅप्ससाठी अॅप प्रतिसाद देत नाही संवाद दर्शवा"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यवर अॅप्सना अनुमती देण्याची सक्ती करा"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य संचयनावर लेखन केले जाण्‍यासाठी पात्र बनविते"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य संचयनावर लेखन केले जाण्यासाठी पात्र बनविते"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"क्र‍ियाकलापाचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"चालू सेवा"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"सध्या चालत असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"रात्र मोड"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"अक्षम केले"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"नेहमी चालू"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"स्वयंचलित"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"एकाधिक प्रक्रिया WebView सक्षम करा"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एक वेगळ्या प्रक्रियेत WebView प्रस्तुतकर्ते चालवा."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"वेबदृश्य अंमलबजावणी"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"वेबदृश्य अंमलबजावणी सेट करा"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"निवडलेली WebView अंमलबजावणी अक्षम आहे आणि वापरण्यास सक्षम असणे आवश्यक आहे, आपण ती सक्षम करू इच्छिता?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ही निवड यापुढे वैध असणार नाही. पुन्हा प्रयत्न करा."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"फाईल कूटबद्धीकरणावर रूपांतरित करा"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करा..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फाईल आधीपासून कूटबद्ध केली"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"हे वैशिष्‍ट्य प्रायोगिक आहे आणि कदाचित कार्यप्रदर्शन प्रभावित करू शकते."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"अंदाजे. <xliff:g id="TIME">%1$s</xliff:g> शिल्लक"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - अंदाजे. <xliff:g id="TIME">%2$s</xliff:g> शिल्लक"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूर्ण होण्यात"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC वरून पूर्ण होण्यात"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB वरून पूर्ण होण्यात"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> वायरलेसवरून पूर्ण होण्यात"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"चार्ज होत आहे"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC वर चार्ज करीत आहे"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB वरून चार्ज करीत आहे"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"वायरलेस वरून चार्ज करीत आहे"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"चार्ज होत नाही"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज होत नाही"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"प्रशासकाद्वारे अक्षम केलेले"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकाने नियंत्रित केलेले"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"प्रशासकाने सक्षम केलेले"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"प्रशासकाने अक्षम केलेले"</string>
     <string name="home" msgid="8263346537524314127">"मुख्यपृष्ठ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पूर्वी"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शिल्लक"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"लहान"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"डीफॉल्ट"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"मोठा"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"आणखी मोठा"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सर्वात मोठा"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 45f5c6f..a8be0e5 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Output teks ke pertuturan"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Kadar pertuturan"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Kelajuan pertuturan teks"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pic"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Mempengaruhi nada pertuturan disintesiskan"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Bahasa"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Gunakan bahasa sistem"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Bahasa tidak dipilih"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Tunjukkan semua ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Tunjukkan dialog Aplikasi Tidak Memberi Maklum Balas untuk aplikasi latar belakang"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Benarkan apl secara paksa pada storan luaran"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Menjadikan sebarang apl layak ditulis ke storan luaran, walau apa juga nilai manifesnya"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Menjadikan sebarang apl layak ditulis ke storan luaran, tanpa mengambil kira nilai manifes"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktiviti supaya boleh diubah saiz"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bolehkan semua saiz aktiviti diubah untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Dayakan tetingkap bentuk bebas"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktif. Ketik untuk menogol."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Perkhidmatan dijalankan"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Mod malam"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Dilumpuhkan"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Sentiasa hidup"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatik"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Dayakan WebView berbilang proses"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Jalankan pemapar WebView dalam proses terpencil."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Pelaksanaan WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Tetapkan pelaksanaan WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Pelaksanaan WebView pilihan telah dilumpuhkan dan mesti didayakan untuk digunakan, adakah anda mahu mendayakannya?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Pilihan ini tidak lagi sah. Cuba lagi."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Tukar kepada penyulitan fail"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Tukar..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sudah disulitkan fail"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ciri ini adalah percubaan dan boleh menjejaskan prestasi."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kira-kira <xliff:g id="TIME">%1$s</xliff:g> lagi"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira. <xliff:g id="TIME">%2$s</xliff:g> yang tinggal"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga penuh"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga penuh di AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga penuh melalui USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga penuh dari wayarles"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Mengecas"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Mengecas pada AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Mengecas melalui USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Mengecas tanpa wayar"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Tidak mengecas"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Tidak mengecas"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dilumpuhkan oleh pentadbir"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikawal oleh pentadbir"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Didayakan oleh pentadbir"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Dilumpuhkan oleh pentadbir"</string>
     <string name="home" msgid="8263346537524314127">"Skrin Utama"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> yang lalu"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> lagi"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kecil"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Lalai"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Besar"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lebih besar"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 9d722db..220deff 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"စာသားမှ အသံထွက်စေခြင်း"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"စကားပြောနှုန်း"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"စာတမ်းအားပြောဆိုသော အမြန်နှုန်း"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"အသံအနိမ့်အမြင့်"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"စက်ဖြင့်ထုတ်လုပ်ထားသည့် စကားသံကို အကျိုးသက်ရောက်မှုရှိပါမည်။"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ဘာသာစကား"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"စနစ်၏ ဘာသာစကားကို အသုံးပြုရန်"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ဘာသာစကား မရွေးချယ်ထားပါ။"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"ANRsအားလုံးအား ပြသရန်"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"နောက်ခံအပ်ပလီကေးရှင်းအတွက်တုံ့ပြန်မှုမရှိပြရန်"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"အပြင်မှာ အတင်း ခွင့်ပြုရန်"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ပြနေတဲ့ တန်ဖိုး ဘယ်လိုပဲရှိနေနေ၊ ဘယ် appကို မဆို အပြင် သိုလှောင်ခန်းသို့ ရေးသားခွင့် ပေးတယ်"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"တိကျစွာ သတ်မှတ်ထားသည့်တန်ဖိုးများရှိသော်လည်း၊ ပြင်ပသိုလှောင်ခန်းများသို့ မည်သည့်အက်ပ်ကိုမဆို ဝင်ရောက်ခွင့်ပြုပါ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"လုပ်ဆောင်ချက်များ ဆိုက်ညှိရနိုင်ရန် လုပ်ခိုင်းပါ"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"မန်နီးဖက်စ်တန်ဖိုးများ မည်မျှပင်ရှိစေကာမူ၊ ဝင်းဒိုးများအတွက် လှုပ်ရှားမှုများအားလုံးကို အရွယ်အစားချိန်ခြင်း ပြုလုပ်ပါ။"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"အခမဲ့ပုံစံ ဝင်းဒိုးကို ဖွင့်ပါ"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"ပွင့်နေသည်။ ပြောင်းရန်တို့ပါ။"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"အလုပ်လုပ်နေသောဝန်ဆောင်မှုများ"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"ယခုအလုပ်လုပ်နေသောဝန်ဆောင်မှုကို ကြည့်ခြင်းနှင့် ထိန်းသိမ်းခြင်းအား ပြုလုပ်မည်လား?"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"ညသုံး မုဒ်"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"ပိတ်ထား"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"အမြဲတမ်း ဖွင့်ထားရန်"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"အလိုအလျောက်"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"လုပ်ငန်းဖြစ်စဉ်များစွာကြည့်နိုင်သည့် ဝဘ်မြင်ကွင်းကိုဖွင့်ပါ"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"လုပ်ငန်းဖြစ်စဉ်တစ်ခုတည်းအတွက် ဝဘ်မြင်ကွင်း အဖြစ်ပြုလုပ်ခြင်းကို ဖွင့်ပါ။"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView အကောင်အထည်ဖော်မှု"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView အကောင်အထည်ဖော်မှု သတ်မှတ်ပါ"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ရွေးချယ်ထားသည့် WebView လုပ်ဆောင်ခြင်းကို ပိတ်ထားသည်ပြီး အသုံးပြုရန်အတွက် ဖွင့်ရမည်၊ ဖွင့်လိုပါသလား။"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ဤရွေးချယ်မှု မှန်ကန်မှု မရှိတော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ဖိုင်လုံခြုံအောင်ပြုလုပ်ခြင်းသို့ ပြောင်းပါ"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ပြောင်းရန်…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ဖိုင်ကို လုံခြုံအောင်ပြုလုပ်ပြီးပါပြီ"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ဒီအင်္ဂါရပ်မှာ စမ်းသပ်မှု ဖြစ်၍ လုပ်ကိုင်မှုကို အကျိုးသက်ရောက်နိုင်သည်။"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"ခန့်မှန်းခြေ <xliff:g id="TIME">%1$s</xliff:g> ကျန်ပါသည်"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ခန့်မှန်းခြေ။ <xliff:g id="TIME">%2$s</xliff:g> ကျန်ရှိနေ"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> အပြည့်အထိ"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> လျှပ်စစ်ဖြင့် အပြည့်အထိ"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB ဖြင့် အပြည့်အထိ"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ကြိုးမဲ့ဖြင့် အပြည့်အထိ"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"အကြောင်းအရာ မသိရှိ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"အားသွင်းနေပါသည်"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"လျှပ်စစ်ဖြင့် အားသွင်းနေ"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USBဖြင့် အားသွင်းနေ"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ကြိုးမဲ့ အားသွင်းနေ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"အားသွင်းမနေပါ"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"အားသွင်းမနေပါ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"အပြည့်"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"စီမံခန့်ခွဲသူမှ ဖွင့်ထားသည်"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်"</string>
     <string name="home" msgid="8263346537524314127">"ပင်မ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"ပြီးခဲ့သည့် <xliff:g id="ID_1">%1$s</xliff:g> က"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ကျန်ပါသည်"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"သေး"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"မူရင်း"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ကြီး"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ပိုကြီး"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"အကြီးဆုံး"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"စိတ်ကြိုက် (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index ff15482..a1407ac 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Tekst-til-tale"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Talehastighet"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Hvor raskt teksten leses"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Stemmeleie"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Påvirker tonehøyden for syntetisert tale"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Språk"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Bruk systemspråk"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Språk er ikke valgt"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Vis alle ANR-er"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Vis Appen svarer ikke-dialog for bakgrunnsapper"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Tving frem tillatelse for ekstern lagring av apper"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gjør at apper kan skrives til ekstern lagring, uavhengig av manifestverdier"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Dette gjør at alle apper kan lagres på eksterne lagringsmedier – uavhengig av manifestverdier"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til å kunne endre størrelse"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gjør at alle aktivitetene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Slå på vinduer i fritt format"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Trykk for å slå av/på."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Aktive tjenester"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Se og kontrollér tjenester som kjører for øyeblikket"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nattmodus"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Slått av"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Slå på WebView for flere prosesser"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Kjør WebView-gjengivelser i en isolert prosess."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Angi WebView-implementering"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valgte implementeringen av nettvisningen er slått av – den må slås på for å brukes. Vil du slå den på?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Dette valget er ikke gyldig lenger. Prøv på nytt."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertér til kryptert fil"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertér …"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Allerede kryptert og lagret som fil"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Denne funksjonen er eksperimentell og kan påvirke ytelsen."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> gjenstår"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> igjen"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – fulladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> –  fulladet om <xliff:g id="TIME">%2$s</xliff:g> med vekselstrøm"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – fulladet om <xliff:g id="TIME">%2$s</xliff:g> via USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – fulladet om <xliff:g id="TIME">%2$s</xliff:g> via trådløs lading"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Ukjent"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Lader"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Lader via strømuttak"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Lader via USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Lader trådløst"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Lader ikke"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Lader ikke"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Avslått av administratoren"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrollert av administratoren"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Slått på av administratoren"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Avslått av administratoren"</string>
     <string name="home" msgid="8263346537524314127">"Startside"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> gjenstår"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Liten"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standard"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stor"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Større"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index f0cfdab..83e2e74 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"पाठ-बाट-वाणी उत्पादन"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"वाणी दर"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"पाठ वाचन हुने गति"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"पिच"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"संश्लेषित बोलीको टोनमा प्रभाव पार्छ"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"भाषा"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"प्रणाली भाषा प्रयोग गर्नुहोस्"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"भाषा चयन गरिएको छैन"</string>
@@ -246,9 +248,9 @@
     <string name="show_all_anrs" msgid="28462979638729082">"सबै ANRs देखाउनुहोस्"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"पृष्ठभूमि अनुप्रयोगका लागि जवाफ नदिइरहेका अनुप्रयोगहरू देखाउनुहोस्"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यमा बल प्रयोगको अनुमति प्राप्त अनुप्रयोगहरू"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"म्यानिफेेस्टको उपेक्षा गरी, कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न योग्य बनाउँछ"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"म्यानिफेेस्टका मानहरूको ख्याल नगरी कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न सकिने खाले बनाउँछ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"गतिविधिहरू रिसाइज गर्नको लागि बाध्य गर्नुहोस्"</string>
-    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string>
+    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउनुहोस्।"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"फ्रिफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
     <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रयोगात्मक फ्रिफर्म विन्डोहरूका लागि समर्थन सक्रिय गर्नुहोस्।"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटप ब्याकअप पासवर्ड"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"चलिरहेका सेवाहरू"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"रात्री मोड"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"असक्षम गरियो"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"सधैं खुल्‍ला"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"मल्टिप्रोसेस वेबभ्यु सक्षम गर्नुहोस्"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एउटा पृथक प्रक्रियामा वेबभ्यु रेन्डररहरू चलाउनुहोस्।"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट गर्नुहोस्"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"छनौट गरिएको WebView को कार्यान्वयन असक्षम गरिएको छ र प्रयोग गर्नका लागि सक्रिय गर्नुपर्छ, तपाईँ यसलाई सक्रिय गर्न चाहनुहुन्छ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"यो छनोट अब मान्य छैन। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"फाइल इन्क्रिप्सनमा रूपान्तरण गर्नुहोस्"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रुपान्तरण गर्नुहोस्…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"पहिल्यै फाइल इन्क्रिप्ट गरिएको छ"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यो सुविधा प्रयोगात्मक छ र प्रदर्शनमा असर गर्न सक्छ।"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%1$s</xliff:g> बाँकी छ"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - लगभग। <xliff:g id="TIME">%2$s</xliff:g> बायाँ"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूर्ण नभए सम्म"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC मा पूर्ण नभए सम्म"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB मा पूर्ण नभए सम्म"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> वायरलेसबाट पूर्ण नभए सम्म"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"चार्ज हुँदै"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC मा चार्ज गर्दै"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB मा चार्ज गर्दै"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"बिना तार चार्ज गर्दै"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"चार्ज भइरहेको छैन"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज हुँदै छैन"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"प्रशासकद्वारा असक्षम गरिएको"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकद्वारा नियन्त्रित"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"प्रशासकद्वारा सक्षम गरिएको छ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"प्रशासकद्वारा असक्षम गरिएको छ"</string>
     <string name="home" msgid="8263346537524314127">"गृह"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहिले"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> बाँकी"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"सानो"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"पूर्वनिर्धारित"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ठूलो"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"अझ ठूलो"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 0dbf5b9..55017d8 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Spraakuitvoer"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Spreeksnelheid"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Snelheid waarmee de tekst wordt gesproken"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Hoogte"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Is van invloed op de toon van de synthetisch gegenereerde spraak"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Taal"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Systeemtaal gebruiken"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Taal niet geselecteerd"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Alle ANR\'s weergeven"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"\'App reageert niet\' weerg. voor apps op achtergr."</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Toestaan van apps op externe opslag afdwingen"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hierdoor komt een app in aanmerking om te worden geschreven naar externe opslag, ongeacht de manifestwaarden"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Hiermee komt elke app in aanmerking voor schrijven naar externe opslag, ongeacht de manifestwaarden"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Het formaat van alle activiteiten aanpasbaar maken, ongeacht de manifestwaarden."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Vensters met vrije vorm inschakelen"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Actief. Tik om te schakelen."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Actieve services"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Services die momenteel actief zijn, weergeven en beheren"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nachtmodus"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Uitgeschakeld"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Altijd aan"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Multiproces-WebView aan"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView-weergaveprogramma\'s uitvoeren in geïsoleerd proces."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementatie"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-implementatie instellen"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"De gekozen WebView-implementatie is uitgeschakeld en moet worden ingeschakeld voor gebruik. Wil je deze inschakelen?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Deze keuze is niet meer geldig. Probeer het opnieuw."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Converteren naar versleuteling op basis van bestanden"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converteren…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Al versleuteld op basis van bestanden"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Deze functie is experimenteel en kan invloed hebben op de prestaties."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> resterend"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ca. <xliff:g id="TIME">%2$s</xliff:g> resterend"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot vol"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot vol via wisselstroom"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot vol via USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot vol via draadloos"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Opladen"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Opladen via netvoeding"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Opladen via USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Draadloos opladen"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Wordt niet opgeladen"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Wordt niet opgeladen"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Volledig"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Uitgeschakeld door beheerder"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ingesteld door beheerder"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Ingeschakeld door beheerder"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Uitgeschakeld door beheerder"</string>
     <string name="home" msgid="8263346537524314127">"Startpagina"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> geleden"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> resterend"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Klein"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standaard"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Groot"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Groter"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootst"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 2f44757..eb1eaac 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"ਟੈਕਸਟ-ਟੂ-ਸਪੀਚ ਆਉਟਪੁਟ"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"ਸਪੀਚ ਰੇਟ"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ਸਪੀਡ ਜਿਸਤੇ ਟੈਕਸਟ ਬੋਲਿਆ ਜਾਂਦਾ ਹੈ"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"ਪਿਚ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ਬਣਾਵਟੀ ਬੋਲੀ ਦੇ ਲਹਿਜੇ \'ਤੇ ਅਸਰ ਪਾਉਂਦੀ ਹੈ"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ਭਾਸ਼ਾ"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"ਸਿਸਟਮ ਭਾਸ਼ਾ ਵਰਤੋ"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ਭਾਸ਼ਾ ਨਹੀਂ ਚੁਣੀ"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"ਸਾਰੇ ANR ਦਿਖਾਓ"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"ਪਿਛੋਕੜ ਐਪਸ ਲਈ ਐਪਸ ਜਵਾਬ ਨਹੀਂ ਦੇ ਰਹੇ ਡਾਇਲੌਗ ਦਿਖਾਓ"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"ਐਪਸ ਨੂੰ ਬਾਹਰਲੇ ਤੇ ਜ਼ਬਰਦਸਤੀ ਆਗਿਆ ਦਿਓ"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ਇੱਕ ਐਪ ਨੂੰ ਬਾਹਰਲੀ ਸਟੋਰੇਜ ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ ਤੇ ਵਿਚਾਰ ਕੀਤੇ ਬਿਨਾਂ"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਕਿਸੇ ਵੀ ਐਪ ਨੂੰ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ।"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"freeform windows ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"ਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"ਰਾਤ ਮੋਡ"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"ਅਸਮਰੱਥ ਬਣਾਇਆ"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"ਹਮੇਸ਼ਾ ਚਾਲੂ"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ਆਟੋਮੈਟਿਕ"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ਬਹੁ-ਮੰਤਵ WebView ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ਕਿਸੇ ਵੱਖ ਕੀਤੀ ਗਈ ਪ੍ਰਕਿਰਿਆ ਵਿੱਚ WebView ਰੈਂਡਰਰਾਂ ਨੂੰ ਚਲਾਓ।"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ਅਮਲ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ਅਮਲ ਸੈੱਟ ਕਰੋ"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ਚੁਣਿਆ ਗਿਆ WebView ਅਮਲ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ, ਅਤੇ ਵਰਤੋਂ ਕਰਨ ਲਈ ਇਸ ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਜਾਣਾ ਜ਼ਰੂਰੀ ਹੈ, ਕੀ ਤੁਸੀਂ ਇਸ ਨੂੰ ਯੋਗ ਬਣਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ਇਹ ਚੋਣ ਹੁਣ ਵੈਧ ਨਹੀਂ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ਫ਼ਾਈਲ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਤਬਦੀਲ ਕਰੋ"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ਤਬਦੀਲ ਕਰੋ ..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ਫ਼ਾਈਲ ਪਹਿਲਾਂ ਤੋਂ ਇਨਕ੍ਰਿਪਟਡ ਹੈ"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਾਤਮਿਕ ਹੈ ਅਤੇ ਪ੍ਰਦਰਸ਼ਨ ਤੇ ਅਸਰ ਪਾ ਸਕਦੀ ਹੈ।"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਲਗਭਗ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC ਤੇ ਪੂਰਾ ਹੋਣ ਤੱਕ"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB ਤੇ ਪੂਰਾ ਹੋਣ ਤੱਕ"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਵਾਇਰਲੈਸ ਤੋਂ ਪੂਰਾ ਹੋਣ ਤੱਕ"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"ਅਗਿਆਤ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ਚਾਰਜਿੰਗ"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC ਤੇ ਚਾਰਜਿੰਗ"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB ਤੇ ਚਾਰਜਿੰਗ"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ਵਾਇਰਲੈਸ ਤੌਰ ਤੇ ਚਾਰਜਿੰਗ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ਪੂਰੀ"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਯੋਗ ਬਣਾਈ ਗਈ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਯੋਗ ਬਣਾਈ ਗਈ"</string>
     <string name="home" msgid="8263346537524314127">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ਪਹਿਲਾਂ"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ਬਾਕੀ"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ਛੋਟਾ"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ਵੱਡਾ"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ਥੋੜ੍ਹਾ ਵੱਡਾ"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ਸਭ ਤੋਂ ਵੱਡਾ"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index e30925c..1e56cfd 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Zamiana tekstu na mowę"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Szybkość mowy"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Szybkość czytania tekstu"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tony"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Wpływa na dźwięk syntezatora mowy"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Język"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Użyj języka systemu"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Nie wybrano języka"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Pokaż wszystkie ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Pokaż okno Aplikacja Nie Reaguje dla aplikacji w tle"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Wymuś zezwalanie na aplikacje w pamięci zewn."</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Pozwala na zapis aplikacji w pamięci zewn. niezależnie od wartości w pliku manifestu"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Pozwala na zapis aplikacji w pamięci zewnętrznej niezależnie od wartości w pliku manifestu"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Wymuś zmianę rozmiaru okien aktywności"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Zezwól na zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Włącz dowolny rozmiar okien"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktywna. Dotknij, by zmienić."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Uruchomione usługi"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Wyświetl obecnie uruchomione usługi i zarządzaj nimi"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Tryb nocny"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Wyłączone"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Zawsze włączone"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatycznie"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Włącz wieloprocesowy WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Uruchom WebView jako izolowany proces."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacja WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ustaw implementację WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Wybrana implementacja WebView jest wyłączona. Aby jej używać, musisz ją włączyć. Chcesz to zrobić?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ta opcja nie jest już obsługiwana. Spróbuj ponownie."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Przekształć na szyfrowanie plików"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Przekształć…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Pliki są już zaszyfrowane"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To jest funkcja eksperymentalna i może wpływać na działanie urządzenia."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Pozostało około <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostało ok. <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania z gniazdka"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania przez USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania bezprzewodowo"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Nieznane"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Ładowanie"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Ładowanie zasilaczem"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Ładowanie przez USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Ład. bezprzewodowe"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nie podłączony"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nie podłączony"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Naładowana"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Wyłączone przez administratora"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolowane przez administratora"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Włączone przez administratora"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Wyłączone przez administratora"</string>
     <string name="home" msgid="8263346537524314127">"Ekran główny"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> temu"</string>
-    <string name="remaining_length_format" msgid="7886337596669190587">"Pozostało: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="remaining_length_format" msgid="7886337596669190587">"Pozostało <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Małe"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Domyślne"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Duże"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Większe"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Największe"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index ec54e4f..93f333a 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Frequência do som"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string>
@@ -145,7 +147,7 @@
     <string name="enable_adb" msgid="7982306934419797485">"Depuração USB"</string>
     <string name="enable_adb_summary" msgid="4881186971746056635">"Modo de depuração quando o USB estiver conectado"</string>
     <string name="clear_adb_keys" msgid="4038889221503122743">"Revogar autorizações de depuração USB"</string>
-    <string name="bugreport_in_power" msgid="7923901846375587241">"Atalho para relatório de bugs"</string>
+    <string name="bugreport_in_power" msgid="7923901846375587241">"Atalho para relatório do bug"</string>
     <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostrar um botão para gerar relatórios de bugs no menu do botão liga/desliga"</string>
     <string name="keep_screen_on" msgid="1146389631208760344">"Permanecer ativo"</string>
     <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em inatividade enquanto estiver carregando."</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Mostrar todos os ANRS"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Exibir \"App não responde\" para app em 2º plano"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Qualifica apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Ativo. Tocar para alternar."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Visualizar e controlar os serviços em execução no momento"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modo noturno"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ativar WebView de vários processos"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executar renderizadores de WebView em um processo isolado."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação do WebView escolhida está desativada e deve ser ativada para ser usada. Deseja ativá-la?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Esta opção não é mais válida. Tente novamente."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para criptografia de arquivos"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Já criptografado com base em arquivos"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Aproximadamente <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir em CA"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir via USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir sem fio"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Carregando"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Carregamento CA"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Carregamento via USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Carregamento sem fio"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Não está carregando"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está carregando"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativada pelo administrador"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Ativada pelo administrador"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Desativada pelo administrador"</string>
     <string name="home" msgid="8263346537524314127">"Início"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequena"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Padrão"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Muito grande"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index ab2a5ae..dda00fe 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Saída de texto para voz"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de voz"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade a que o texto é falado"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonalidade"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizar idioma do sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Mostrar todos os ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Mostrar erro \"Aplic. não Resp.\" p/ aplic. 2º plano"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forçar perm. de aplicações no armazenamento ext."</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualquer aplic. pode ser gravada no arm. ext., independ. dos valores do manif."</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Torna qualquer aplicação elegível para ser gravada no armazenamento externo, independentemente dos valores do manifesto"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar as atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Ativo. Toque para ativar/desativar."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Ver e controlar os serviços actualmente em execução"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modo noturno"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Desativado"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativado"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ativar WebView multiprocessos"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executar renderizadores WebView num processo isolado."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementação WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação WebView escolhida foi desativada e tem de ser ativada para poder ser utilizada. Pretende ativá-la?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Esta opção já não é válida. Tente novamente."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para a encriptação de ficheiros"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Os ficheiros já estão encriptados"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta funcionalidade é experimental e pode afetar o desempenho."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Resta(m) aproximadamente <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – resta(m) aprox. <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até ficar completa"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até ficar completa através de CA"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até ficar completa através de USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até ficar compl. por rede s/ fios"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"A carregar"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"A carregar por CA"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"A carregar por USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"A carregar sem fios"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Não está a carregar"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está a carregar"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Completo"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativado pelo administrador"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlado pelo administrador"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Ativado pelo administrador"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Desativado pelo administrador"</string>
     <string name="home" msgid="8263346537524314127">"Página inicial"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Há <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Resta(m) <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeno"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predefinição"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Maior"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O maior"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index ec54e4f..93f333a 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Frequência do som"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string>
@@ -145,7 +147,7 @@
     <string name="enable_adb" msgid="7982306934419797485">"Depuração USB"</string>
     <string name="enable_adb_summary" msgid="4881186971746056635">"Modo de depuração quando o USB estiver conectado"</string>
     <string name="clear_adb_keys" msgid="4038889221503122743">"Revogar autorizações de depuração USB"</string>
-    <string name="bugreport_in_power" msgid="7923901846375587241">"Atalho para relatório de bugs"</string>
+    <string name="bugreport_in_power" msgid="7923901846375587241">"Atalho para relatório do bug"</string>
     <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostrar um botão para gerar relatórios de bugs no menu do botão liga/desliga"</string>
     <string name="keep_screen_on" msgid="1146389631208760344">"Permanecer ativo"</string>
     <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em inatividade enquanto estiver carregando."</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Mostrar todos os ANRS"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Exibir \"App não responde\" para app em 2º plano"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Qualifica apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Ativo. Tocar para alternar."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Visualizar e controlar os serviços em execução no momento"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modo noturno"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ativar WebView de vários processos"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executar renderizadores de WebView em um processo isolado."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação do WebView escolhida está desativada e deve ser ativada para ser usada. Deseja ativá-la?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Esta opção não é mais válida. Tente novamente."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para criptografia de arquivos"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Já criptografado com base em arquivos"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Aproximadamente <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir em CA"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir via USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir sem fio"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Carregando"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Carregamento CA"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Carregamento via USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Carregamento sem fio"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Não está carregando"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está carregando"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativada pelo administrador"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Ativada pelo administrador"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Desativada pelo administrador"</string>
     <string name="home" msgid="8263346537524314127">"Início"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequena"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Padrão"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Muito grande"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index 30d6cf3..1f0e05b 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -125,7 +125,7 @@
     <item msgid="3191973083884253830">"Niciuna"</item>
     <item msgid="9089630089455370183">"Logcat"</item>
     <item msgid="5397807424362304288">"Systrace (imagini)"</item>
-    <item msgid="1340692776955662664">"Apelaţi stiva pentru glGetError"</item>
+    <item msgid="1340692776955662664">"Apelați stiva pentru glGetError"</item>
   </string-array>
   <string-array name="show_non_rect_clip_entries">
     <item msgid="993742912147090253">"Dezactivat"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 0cfacd7..3c46d41 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Transformare text în vorbire"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Ritmul vorbirii"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Viteza cu care este vorbit textul"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Înălțime"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afectează tonalitatea vorbirii sintetizate"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Limbă"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizați limba sistemului"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Nu ați selectat limba"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Afișați toate elem. ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Aplicații din fundal: afișați Aplicația nu răspunde"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forțați accesul aplicațiilor la stocarea externă"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Face orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Face orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permiteți redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Activați ferestrele cu formă liberă"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Activă. Atingeți pentru a comuta."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Servicii în curs de funcționare"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Vedeți și controlați serviciile care funcționează în prezent"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modul Noapte"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Dezactivată"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Activată permanent"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automat"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activați WebView cu mai multe procese"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Rulați programele de redare WebView într-un proces izolat."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementare WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setați implementarea WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Implementarea WebView aleasă este dezactivată. Pentru a fi folosită, trebuie să fie activată. Doriți să o activați?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Această opțiune nu mai este validă. Încercați din nou."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Faceți conversia la criptarea bazată pe sistemul de fișiere"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertiți…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Criptarea bazată pe sistemul de fișiere este finalizată"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Această funcție este experimentală și poate afecta performanțele."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Timp rămas: aproximativ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – timp rămas: aproximativ <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> până la încărcare completă"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> până la încărcare completă la c.a."</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> până la încărcare completă prin USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> până la încărcare completă wireless"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Necunoscut"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Încarcă"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Se încarcă la C.A."</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Se încarcă prin USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Se încarcă fără fir"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nu se încarcă"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nu încarcă"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Complet"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dezactivată de administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlată de administrator"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Activată de administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Dezactivată de administrator"</string>
     <string name="home" msgid="8263346537524314127">"Ecranul principal"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Acum <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Timp rămas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mic"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Prestabilit"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Mare"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Mai mare"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Cel mai mare"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 4b3214a..f4929de 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Синтез речи"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Скорость речи"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Скорость чтения текста"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Тон"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Влияет на высоту синтезированной речи"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Язык"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Язык системы"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Язык не выбран"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Все ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Уведомлять о том, что приложение не отвечает"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Разрешить сохранение на внешние накопители"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Разрешает сохранение приложений на внешние накопители независимо от значения манифеста"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Разрешает сохранение приложений на внешних накопителях независимо от значений манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Изменение размера в многооконном режиме"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Разрешить изменение размера в многооконном режиме (независимо от значений манифеста)"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Разрешить создание окон произвольной формы"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Включено. Нажмите, чтобы отключить."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Работающие приложения"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Просмотр и управление работающими приложениями"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Ночной режим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Отключено"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Всегда включено"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Автоматическое переключение"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Включить многопроц. WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Выполнять обработчики WebView в изолированном процессе"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Сервис WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Настройки сервиса WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Чтобы использовать сервис WebView, включите его. Сделать это?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Вариант недействителен. Повторите попытку."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Переход к шифрованию файлов"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Перейти…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Шифрование файлов уже включено"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Это экспериментальная функция, она может снизить производительность устройства."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Осталось примерно <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – осталось около <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки (от сети)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки (через USB)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки (беспроводная)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Идет зарядка"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Зарядка от сети"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Зарядка через USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Беспроводная зарядка"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Не заряжается"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не заряжается"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Батарея заряжена"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Отключено администратором"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролируется администратором"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Включено администратором"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Отключено администратором"</string>
     <string name="home" msgid="8263346537524314127">"Главная"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> назад"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Осталось <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Мелкий"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"По умолчанию"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Крупный"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Очень крупный"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Максимальный"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Другой (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index 390e218..99f018b 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"පෙළ-සිට-කථන ප්‍රතිදානය"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"කථන ශීඝ්‍රතාව"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"පෙළ කථා කරනා වේගය"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"තාරතාව"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"සංශ්ලේෂණය කළ කථනයෙහි ස්වරයට බලපායි"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"භාෂාව"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"පද්ධති භාෂාව භාවිතා කරන්න"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"භාෂාව තෝරා ගෙන නැත"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"සියලුම ANR පෙන්වන්න"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"පසුබිම් යෙදුම් වලට යෙදුම ප්‍රතිචාර නොදක්වයි කවුළුව පෙන්වන්න"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"බාහිර මත යෙදුම් ඉඩ දීම බල කරන්න"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් අභ්‍යන්තර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් බාහිර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ක්‍රියාකාරකම් ප්‍රතිප්‍රමාණ කළ හැකි බවට බල කරන්න"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්‍රියාකාරකම් බහු-කවුළුව සඳහා ප්‍රතිප්‍රමාණ කළ හැකි බවට පත් කරන්න."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"අනියම් හැඩැති කවුළු සබල කරන්න"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"සක්‍රියයි. ටොගල කිරීමට තට්ටු කරන්න."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"ධාවනය වන සේවා"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"රාත්‍රී ප්‍රකාරය"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"අබලයි"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"සැමවිට ක්‍රියාත්මක"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"ස්වයංක්‍රීය"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"බහු සැකසීම් WebView සබල කරන්න"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"හුදකලා වූ ක්‍රියාවලියක WebView විදහා දැක්වීම් ධාවනය කරන්න."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ක්‍රියාත්මක කිරීම"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ක්‍රියාත්මක කිරීම සකසන්න"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"තෝරන ලද WebView ක්‍රියාත්මක කිරීම අබල අතර, භාවිත කිරීමට සබල කළ යුතුය, ඔබ එය සබල කිරීමට අදහස් කරන්නේද?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"මෙම තෝරා ගැනීම තව දුරටත් වලංගු නැත. නැවත උත්සාහ කරන්න."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ගොනු සංකේතනයට පරිවර්තනය කරන්න"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"පරිවර්තනය කරන්න..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"දැනටමත් ගොනුව සංකේතනය කර ඇත"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"මෙම විශේෂාංගය පරීක්ෂණාත්මක සහ ඇතැම් විට ක්‍රියාකාරිත්වයට බලපෑ හැක."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"දළ වශයෙන් <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතිරිය"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආසන්න <xliff:g id="TIME">%2$s</xliff:g> වම"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> සම්පුර්ණ වන තෙක්"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"AC හි <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> සම්පුර්ණ වන තෙක්"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"USB හරහ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> සම්පුර්ණ වන තෙක්"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"රේඩියෝව වෙතින් <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> සම්පූර්ණ වන තෙක්"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"නොදනී"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ආරෝපණය වෙමින්"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC හි ආරෝපණය වෙමින්"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB හරහා ආරෝපණය වෙමින්"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"රැහැන් රහිතව ආරෝපණය වෙමින්"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ආරෝපණය නොවේ"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ආරෝපණය නොවෙමින්"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"පූර්ණ"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"පරිපාලක විසින් අබල කරන ලදී"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"පරිපාලක විසින් සබල කරන ලදී"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"පරිපාලක විසින් අබල කරන ලදී"</string>
     <string name="home" msgid="8263346537524314127">"මුල් පිටුව"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>කට පෙර"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g>ක් ඉතිරිය"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"කුඩා"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"පෙරනිමි"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"විශාල"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"වඩා විශාල"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"විශාලතම"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"අභිරුචි (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 8bf64fa..4dffdef 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Výstup prevodu textu na reč"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Rýchlosť reči"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Rýchlosť hovoreného textu"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Výška"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Určuje zvuk syntetizovaného hlasu"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Jazyk"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Používať jazyk systému"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Nebol vybratý jazyk"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Zobrazovať všetky ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Zobrazovať dialóg „Aplikácia neodpovedá“ aj pre aplikácie na pozadí"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Vynútiť povolenie aplikácií na externom úložisku"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Povoliť okná s voľným tvarom"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktívne. Prepnite klepnutím."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Spustené služby"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Zobrazenie a ovládanie aktuálne spustených služieb"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nočný režim"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Vypnuté"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuté"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Povoliť viacprocesové moduly WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Spúšťať vykresľovacie moduly WebView v izolovanom procese."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementácia komponenta WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavenie implementácie komponenta WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Zvolená implementácia technológie WebView je zakázaná. Ak ju chcete použiť, musíte ju najprv povoliť. Chcete ju povoliť?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Táto voľba už nie je platná. Skúste to znova."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertovať na šifrovanie súborov"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertovať…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Súbory sú už šifrované"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkcia je experimentálna a môže mať vplyv na výkonnosť."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zostáva cca. <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostáva približne <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia zo zásuvky"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia cez USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia bezdrôtovo"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Neznáme"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Nabíjanie"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Nabíjanie zo zásuvky"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Nabíjanie cez USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bezdrôtové nabíjanie"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nenabíja sa"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenabíja sa"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Zakázané správcom"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ovládané správcom"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Povolené správcom"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Zakázané správcom"</string>
     <string name="home" msgid="8263346537524314127">"Domov"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"pred <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Zostáva <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malé"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predvolená"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veľké"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Väčšie"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najväčšie"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 42e589b..676a3ab 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Besedilo v govor"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Hitrost govora"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Hitrost govorjenega besedila"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Višina tona"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Vpliva na ton sintetiziranega govora"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Uporabi sistemski jezik"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik ni izbran"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Pokaži okna neodzivanj"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Prikaz pogovornega okna za neodzivanje aplikacije v ozadju"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Vsili omogočanje aplikacij v zunanji shrambi"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Vsili povečanje velikosti za aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Omogočanje oken svobodne oblike"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dotaknite se za preklop."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Zagnane storitve"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Preglejte in nadzorujte storitve, ki so trenutno zagnane"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nočni način"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Onemogočeno"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Vedno vklopljeno"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Samodejno"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogoči večprocesni WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Izvajanje upodabljalnikov za WebView v ločenem procesu."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Izvedba spletnega pogleda"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavitev izvedbe spletnega pogleda"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izbrana izvedba spletnega pogleda je onemogočena in jo morate omogočiti, če jo želite uporabljati. Ali jo želite omogočiti?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ta izbira ni več veljavna. Poskusite znova."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Preklop na šifriranje podatkov"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Preklop …"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Šifriranje podatkov je že uveljavljeno"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To je preskusna funkcija in lahko vpliva na učinkovitost delovanja."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Še približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – še približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti prek napajalnika"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti prek USB-ja"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti prek brezž. pol."</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Neznano"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Polnjenje"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Polnj. prek iz. toka"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Polnj. prek USB-ja"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Brezžično polnjenje"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Se ne polni"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Se ne polni"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Poln"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogočil skrbnik"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Nadzira skrbnik"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Omogočil skrbnik"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogočil skrbnik"</string>
     <string name="home" msgid="8263346537524314127">"Začetni zaslon"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Pred toliko časa: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Še <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Majhno"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Privzeto"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliko"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Večje"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Največje"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index 4c77a12..c18e639 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Dalja \"tekst-në-ligjërim\""</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Shpejtësia e të folurit"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Shpejtësia me të cilën thuhet teksti"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonaliteti"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ndikon te toni i ligjërimit të sintetizuar"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Gjuha"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Përdor gjuhën e sistemit"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Nuk është përzgjedhur gjuha"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Shfaq raportet ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Shfaq raportet ANR (Aplikacioni nuk përgjigjet) për aplikacionet në sfond"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Detyro lejimin në hapësirën e jashtme"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bëj që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivizo dritaret me formë të lirë"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Trokit për ta ndryshuar."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Shërbimet në ekzekutim"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Modaliteti i natës"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Çaktivizuar"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Gjithmonë aktive"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatike"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktivizo WebView të multiprocesit"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ekzekuto renderizuesit e WebView në një proces të izoluar."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Zbatimi i WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Cakto zbatimin e WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Është çaktivizuar zbatimi i zgjedhur i WebView dhe duhet të aktivizohet për t\'u përdorur, dëshiron ta aktivizosh?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Kjo zgjedhje nuk është më e vlefshme. Provo përsëri."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konverto në enkriptimin e skedarit"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konverto..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Enkriptimi i skedarit është kryer tashmë"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ky funksion është eksperimental dhe mund të ndikojë në veprimtari."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Afërsisht <xliff:g id="TIME">%1$s</xliff:g> të mbetura"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - afërsisht <xliff:g id="TIME">%2$s</xliff:g> të mbetura"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të jetë e plotë"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> deri sa të mbushet në AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> deri sa të mbushet me USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> deri sa të mbushet nga lidhja pa tel"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"I panjohur"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Po ngarkohet"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Po ngarkohet në AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Po ngarkohet me USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Po ngarkohet me valë"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Nuk po ngarkohet"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nuk po ngarkohet"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"E mbushur"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Çaktivizuar nga administratori"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolluar nga administratori"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Aktivizuar nga administratori"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Çaktivizuar nga administratori"</string>
     <string name="home" msgid="8263346537524314127">"Kreu"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> më parë"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> të mbetura"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"I vogël"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"I parazgjedhur"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"I madh"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Më i madh"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Më i madhi"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 8c47025..c0791fc 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Излаз за претварање текста у говор"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Брзина говора"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Брзина изговарања текста"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ниво"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Утиче на тон синтетизованог говора"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Језик"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Користи језик система"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Језик није изабран"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Прикажи све ANR-ове"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Прикажи дијалог Апликација не реагује за апликације у позадини"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Принудно дозволи апликације у спољној"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Принудно омогући промену величине активности"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Омогући промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Омогући прозоре произвољног формата"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активна. Додирните да бисте је деактивирали."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Покренуте услуге"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Приказ и контрола тренутно покренутих услуга"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Ноћни режим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Онемогућено"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Увек укључено"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Аутоматски"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Омогући вишепроцесни WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Покрећите WebView приказиваче у оквиру изолованог процеса."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Примена WebView-а"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Подесите примену WebView-а"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Изабрана примена WebView-а је онемогућена, а мора да буде омогућена ради коришћења. Желите ли да је омогућите?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овај избор више није важећи. Покушајте поново."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертуј у шифровање датотека"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертуј..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Већ се користи шифровање датотека"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ова функција је експериментална и може да утиче на перформансе."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Још отприлике <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостало око <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> док се не напуни"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> док се не напуни пуњачем"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> док се не напуни преко USB-а"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> док се не напуни бежично"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Пуњење"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Пуњење преко пуњача"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Пуњење преко USB-а"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Бежично пуњење"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Не пуни се"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не пуни се"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Пуно"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Онемогућио је администратор"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролише администратор"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Омогућио је администратор"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Онемогућио је администратор"</string>
     <string name="home" msgid="8263346537524314127">"Почетни"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Пре <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Још <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Мали"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Подразумевано"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Велики"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Већи"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Највећи"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index d25f9f5..60c42a5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Text-till-tal"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Talhastighet"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Talhastighet för texten"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Påverkar tonen i det syntetiska talet"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Språk"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Använd systemspråk"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Inget språk valt"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Visa alla som inte svarar"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Visa dialogrutan om att appen inte svarar för bakgrundsappar"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Tillåt appar i externt lagringsutrymme"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Appen kan skrivas till extern lagring, oavsett manifestvärden"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Allar appar kan skrivas till extern lagring, oavsett manifestvärden"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Framtvinga storleksanpassning för aktiviteter"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivera frihandsfönster"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Tryck om du vill inaktivera."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Aktiva tjänster"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Visa och styr aktiva tjänster"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Nattläge"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Inaktiverad"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Automatiskt"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktivera WebView-multibearb."</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Kör WebView-renderare i en isolerad bearbetning."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ange WebView-implementering"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valda WebView-implementeringen har inaktiverats och måste aktiveras om du ska kunna använda den. Vill du aktivera den?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Det här alternativet är inte längre giltigt. Försök igen."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertera till filkryptering"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertera …"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Filkryptering används redan"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Den här funktionen är experimentell och kan påverka prestandan."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca <xliff:g id="TIME">%1$s</xliff:g> kvar"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca <xliff:g id="TIME">%2$s</xliff:g> kvar"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till fulladdat"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till fulladdat via laddare"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till fulladdat via USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till fulladdat via trådlös laddning"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Okänd"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Laddar"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Laddas via adapter"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laddas via USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Laddas trådlöst"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Laddar inte"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Laddar inte"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Har inaktiverats av administratören"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Strys av administratören"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Har aktiverats av administratören"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Har inaktiverats av administratören"</string>
     <string name="home" msgid="8263346537524314127">"Startsida"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"för <xliff:g id="ID_1">%1$s</xliff:g> sedan"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kvar"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Små"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standardinställning"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stora"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Större"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Störst"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 3f1d26a..5de7686 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Kubadilisha maandishi hadi usemi"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Kiwango cha usemaji"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Kasi ya kutamkwa kwa maneno"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Giza"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Huathiri sauti ya matamshi yaliyounganishwa"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Lugha"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Tumia lugha ya mfumo"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Lugha haijachaguliwa"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Onyesha ANR zote"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Onyesha kisanduku kidadisi cha Programu Haiitikii kwa programu za usuli"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Lazima uruhusu programu kwenye hifadhi ya nje"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Huweka programu kwenye hifadhi ya nje, bila kujali maelezo"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Huruhusu programu yoyote iwekwe kwenye hifadhi ya nje, bila kujali thamani za faili ya maelezo"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwenye madirisha mengi, bila kuzingatia thamani za faili ya maelezo."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Washa madirisha yenye muundo huru"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Inatumika. Gonga ili ugeuze."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Huduma zinazoendeshwa"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Onyesha na dhibiti huduma zinazoendeshwa kwa sasa"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Hali ya usiku"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Imezimwa"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Imewashwa kila wakati"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Otomatiki"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Washa WebView ya michakato mingi"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Tekeleza vitoaji huduma vya WebView katika mchakato mahususi."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Utekelezaji wa WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Weka utekelezaji wa WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Kipengee ulichochagua cha utekelezaji wa WebView kimezimwa. Ni lazima ukiwashe ili kitumike. Ungependa kukiwasha?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Chaguo hili halipo tena. Jaribu tena."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Badilisha kuwa usimbaji fiche wa faili"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Badilisha..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Tayari faili imesimbwa kwa njia fiche"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Kipengele hiki ni cha majaribio na huenda kikaathiri utendaji."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zimesalia takribani <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia takriban <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia <xliff:g id="TIME">%2$s</xliff:g> hadi ijae"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia <xliff:g id="TIME">%2$s</xliff:g> hadi ijae kwa kutumia AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g>%% - imesalia <xliff:g id="TIME">%2$s</xliff:g> hadi ijae kwa kutumia USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia <xliff:g id="TIME">%2$s</xliff:g> hadi ijae kwa isiyotumia waya"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Haijulikani"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Inachaji"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Inachaji kupitia AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Inachaji kupitia USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Inachaji bila kutumia waya"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Haichaji"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Haichaji"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Imejaa"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Msimamizi amezima mapendeleo ya mipangilio"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Imedhibitiwa na msimamizi"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Msimamizi amewasha mapendeleo ya mipangilio"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Msimamizi amezima mapendeleo ya mipangilio"</string>
     <string name="home" msgid="8263346537524314127">"Mwanzo"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"Zimepita <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Zimesalia <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Ndogo"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Chaguo-msingi"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Kubwa"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Kubwa kiasi"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Kubwa zaidi"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index f06b0f9..a5f04d0 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"உரையிலிருந்து பேச்சாக மாற்றுதல்"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"பேச்சு வீதம்"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"பேசப்படும் உரையின் வேகம்"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"ஒலித்திறன்"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"உருவாக்கப்படும் பேச்சின் டோன் பாதிக்கப்படும்"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"மொழி"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"முறைமையின் மொழியைப் பயன்படுத்து"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"மொழி தேர்ந்தெடுக்கப்படவில்லை"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"எல்லா ANRகளையும் காட்டு"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"பின்புலப் பயன்பாடுகளுக்குப் பயன்பாடு பதிலளிக்கவில்லை என்ற உரையாடலைக் காட்டு"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"பயன்பாடுகளை வெளிப்புறச் சேமிப்பிடத்தில் அனுமதி"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"மேனிஃபெஸ்ட் மதிப்புகளை பொருட்படுத்தாமல், எந்தப் பயன்பாட்டையும் வெளிப்புற சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், எல்லா பயன்பாட்டையும் வெளிப்புறச் சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமை."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"செயலில் உள்ளது. மாற்ற, தட்டவும்."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"இயங்கும் சேவைகள்"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"இரவு பயன்முறை"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"முடக்கப்பட்டது"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"எப்போதும் இயக்கத்தில் வை"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"தானியங்கு"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"பல செயல்முறை WebViewஐ இயக்கு"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"தனிப்படுத்தப்பட்ட செயல்முறையில் WebView ரெண்டரர்களை இயக்கு."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView செயல்படுத்தல்"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView செயல்படுத்தலை அமை"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"தேர்வுசெய்த WebView செயல்படுத்தல் முடக்கப்பட்டுள்ளது, பயன்படுத்த வேண்டுமெனில் அதைக் கண்டிப்பாக இயக்க வேண்டும். இயக்க விரும்புகிறீர்களா?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"இனி இந்தத் தேர்வைப் பயன்படுத்த முடியாது. மீண்டும் முயலவும்."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"கோப்பு முறைமையாக்கத்திற்கு மாற்று"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"மாற்று…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ஏற்கனவே கோப்பு முறைமையாக்கப்பட்டது"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"இது சோதனை முறையிலான அம்சம், இது செயல்திறனைப் பாதிக்கலாம்."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"தோராயமாக <xliff:g id="TIME">%1$s</xliff:g> உள்ளது"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"தோராயம்: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> உள்ளது"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"முழு சார்ஜிற்கு: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"முழு AC சார்ஜிற்கு: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"முழு USB சார்ஜிற்கு: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"முழு வயர்லெஸ் சார்ஜிற்கு: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"அறியப்படாத"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"சார்ஜ் ஏற்றப்படுகிறது"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC மூலம் சார்ஜாகிறது"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB மூலம் சார்ஜாகிறது"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"வயர்லெஸில் சார்ஜாகிறது"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"சார்ஜ் செய்யப்படவில்லை"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"சார்ஜ் ஏறவில்லை"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"முழுமை"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"நிர்வாகி முடக்கியுள்ளார்"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"நிர்வாகி இயக்கியுள்ளார்"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"நிர்வாகி முடக்கியுள்ளார்"</string>
     <string name="home" msgid="8263346537524314127">"முகப்பு"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> முன்"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> உள்ளது"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"சிறியது"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"இயல்பு"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"பெரியது"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"கொஞ்சம் பெரியது"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"மிகப் பெரியது"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index e6d594b..fe40766 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"వచనం నుండి ప్రసంగం అవుట్‌పుట్"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"ప్రసంగం రేట్"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"వచనాన్ని చదివి వినిపించాల్సిన వేగం"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"పిచ్"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"సమన్వయం చేసిన ప్రసంగం యొక్క టోన్‌ను ప్రభావితం చేస్తుంది"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"భాష"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"సిస్టమ్ భాషను ఉపయోగించు"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"భాష ఎంచుకోబడలేదు"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"అన్ని ANRలను చూపు"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"నేపథ్య అనువర్తనాల కోసం అనువర్తనం ప్రతిస్పందించడం లేదు డైలాగ్‌ను చూపు"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"అనువర్తనాలను బాహ్య నిల్వలో నిర్బంధంగా అనుమతించు"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ఏ అనువర్తనాన్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో వ్రాయగలిగేలా అనుమతిస్తుంది"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ఏ అనువర్తనాన్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో వ్రాయడానికి అనుమతిస్తుంది"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"కార్యాచరణలను పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను పలు రకాల విండోల్లో సరిపోయేట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"స్వతంత్ర రూప విండోలను ప్రారంభించండి"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"సక్రియంగా ఉంది. టోగుల్ చేయడానికి నొక్కండి."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"అమలులో ఉన్న సేవలు"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"ప్రస్తుతం అమలులో ఉన్న సేవలను వీక్షించండి మరియు నియంత్రించండి"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"రాత్రి మోడ్"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"నిలిపివేయబడింది"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"ఎల్లప్పుడూ ఆన్‌లో ఉంచు"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"స్వయంచాలకం"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"మల్టీప్రాసెస్ వెబ్ వీక్షణ ఆరం."</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ప్రత్యేకప్రాసెస్‌లో వెబ్ వీక్షణ రెండెరెర్‌లను అమలుచేస్తుంది."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"వెబ్ వీక్షణ అమలు"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ఎంచుకున్న వెబ్ వీక్షణ అమలు నిలిపివేయబడింది, కానీ ఉపయోగించడానికి తప్పనిసరిగా ప్రారంభించాల్సి ఉంటుంది, మీరు దీన్ని ప్రారంభించాలనుకుంటున్నారా?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ఈ ఎంపిక ఇప్పుడు లేదు. మళ్లీ ప్రయత్నించండి."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ఫైల్ గుప్తీకరణకు మార్చు"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"మార్చండి…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ఫైల్ ఇప్పటికే గుప్తీకరించబడింది"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ఈ లక్షణం ప్రయోగాత్మకమైనది మరియు పనితీరుపై ప్రభావం చూపవచ్చు."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"సుమారు <xliff:g id="TIME">%1$s</xliff:g> మిగిలి ఉంది"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - సుమారు <xliff:g id="TIME">%2$s</xliff:g> మిగిలి ఉంది"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - పూర్తిగా నిండటానికి <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - ACలో పూర్తిగా నిండటానికి <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - USB ద్వారా పూర్తిగా నిండటానికి <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - వైర్‌లెస్ నుండి పూర్తిగా నిండటానికి <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"తెలియదు"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ఛార్జ్ అవుతోంది"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"ACలో ఛార్జ్ అవుతోంది"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB ద్వారా ఛార్జ్ అవుతోంది"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"వైర్‌లెస్‌ ద్వారా ఛార్జ్ అవుతోంది"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ఛార్జ్ కావడం లేదు"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ఛార్జ్ కావడం లేదు"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"నిండింది"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"నిర్వాహకుడు నిలిపివేసారు"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"నిర్వాహకుని ద్వారా నియంత్రించబడింది"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"నిర్వాహకులు ప్రారంభించారు"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"నిర్వాహకులు నిలిపివేసారు"</string>
     <string name="home" msgid="8263346537524314127">"హోమ్"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> క్రితం"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> మిగిలి ఉంది"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"చిన్నగా"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"డిఫాల్ట్"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"పెద్దగా"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"చాలా పెద్దగా"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"అతి పెద్దగా"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index ab428a9..c58692f 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"เอาต์พุตการอ่านออกเสียง"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"ความเร็วของคำพูด"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ความเร็วในการพูดข้อความ"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"ความสูง-ต่ำของเสียง"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"มีผลต่อโทนเสียงของข้อความสังเคราะห์"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"ภาษา"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"ใช้ภาษาของระบบ"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"ไม่ได้เลือกภาษา"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"แสดง ANR ทั้งหมด"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"แสดงหน้าต่างแอปไม่ตอบสนอง สำหรับแอปพื้นหลัง"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"บังคับให้แอปสามารถใช้ที่เก็บภายนอก"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ให้สามารถเขียนแอปต่างๆ ไปยังที่เก็บภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ทำให้สามารถเขียนแอปใดๆ ก็ตามไปยังพื้นที่เก็บข้อมูลภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"ใช้งานอยู่ แตะเพื่อสลับ"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"บริการที่ทำงานอยู่"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"ดูและควบคุมบริการที่ทำงานอยู่"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"โหมดกลางคืน"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"ปิดใช้แล้ว"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"เปิดใช้เสมอ"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"อัตโนมัติ"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"เปิดใช้ WebView แบบหลายขั้นตอน"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"เรียกใช้โหมดแสดงภาพ WebView ในการดำเนินการที่แยกออกมา"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"การใช้งาน WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ตั้งค่าการใช้งาน WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"การใช้งาน WebView ที่เลือกไว้ถูกปิดใช้อยู่ คุณต้องการเปิดใช้เพื่อที่จะใช้งานไหม"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ตัวเลือกนี้ใช้ไม่ได้อีกต่อไป โปรดลองอีกครั้ง"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"แปลงเป็นการเข้ารหัสไฟล์"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"แปลง…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"เข้ารหัสไฟล์แล้ว"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"คุณลักษณะนี้เป็นแบบทดลองและอาจส่งผลต่อประสิทธิภาพการทำงาน"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"เหลืออีกประมาณ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - เหลือประมาณ <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะเต็ม"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะเต็มเมื่อชาร์จผ่าน AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะเต็มเมื่อชาร์จผ่าน USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะเต็มเมื่อชาร์จผ่านระบบไร้สาย"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"ไม่ทราบ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"กำลังชาร์จ"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"กำลังชาร์จไฟ AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"กำลังชาร์จผ่าน USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"กำลังชาร์จแบบไร้สาย"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"ไม่ได้ชาร์จ"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"ไม่ได้ชาร์จ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"เต็ม"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ปิดใช้โดยผู้ดูแลระบบ"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ผู้ดูแลระบบเป็นผู้ควบคุม"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"เปิดใช้โดยผู้ดูแลระบบ"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"ปิดใช้โดยผู้ดูแลระบบ"</string>
     <string name="home" msgid="8263346537524314127">"หน้าแรก"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>ที่ผ่านมา"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"เหลือ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"เล็ก"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ค่าเริ่มต้น"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ใหญ่"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ใหญ่ขึ้น"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ใหญ่ที่สุด"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"กำหนดเอง (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index b21acda..093256c 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Output ng text-to-speech"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Rate ng pagsasalita"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Bilis ng pagsambit sa teksto"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Nakakaapekto sa tono ng naka-synthesize na pananalita"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Wika"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Gamitin ang wika ng system"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Walang napiling wika"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Ipakita ang lahat ng ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"App Not Responding dialog para sa background apps"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Pwersahang payagan ang mga app sa external"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mara-write na sa external storage ang anumang app, anuman ang manifest value"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Ginagawang kwalipikado ang anumang app na mailagay sa external na storage, anuman ang mga value ng manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Sapilitang gawing resizable ang mga aktibidad"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gawing nare-resize ang lahat ng aktibidad para sa multi-window, anuman ang mga value ng manifest."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"I-enable ang mga freeform window"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktibo. I-tap upang i-toggle."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Mga tumatakbong serbisyo"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Tingnan at kontrolin ang mga kasalukuyang tumatakbong serbisyo"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Naka-disable"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Palaging naka-on"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Awtomatiko"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"I-enable, multiprocess WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Tagapag-render ng WebView, patakbuhin sa hiwalay na proseso."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Pagpapatupad sa WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Itakda ang pagpapatupad sa WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Naka-disable ang napiling pagpapatupad sa WebView, at dapat itong i-enable upang magamit, gusto mo ba itong i-enable?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Wala nang bisa ang napiling ito. Subukang muli."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"I-convert at gawing pag-encrypt ng file"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"I-convert..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Na-encrypt na ang file"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ang feature na ito ay pinag-eeksperimentuhan at maaaring makaapekto sa pagganap."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Humigit-kumulang <xliff:g id="TIME">%1$s</xliff:g> na lang ang natitira"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - humigit kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> bago mapuno"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> bago mapuno sa AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> bago mapuno sa USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> bago mapuno mula sa wireless"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Hindi Kilala"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Nagcha-charge"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Nagcha-charge sa AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Nagcha-charge sa USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Wireless nag-charge"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Hindi nagcha-charge"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hindi nagkakarga"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Na-disable ng administrator"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pinapamahalaan ng admin"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Na-enable ng administrator"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Na-disable ng administrator"</string>
     <string name="home" msgid="8263346537524314127">"Home"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> na ang nakalipas"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> na lang"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Maliit"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Malaki"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Mas malaki"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Pinakamalaki"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index beca481..1947d39 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Metin-konuşma çıktısı"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Konuşma hızı"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Metnin konuşulduğu hız"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Perde"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Sentezlenmiş konuşma sesini etkiler"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Dil"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Sistemin dilini kullan"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Dil seçilmedi"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Tüm ANR\'leri göster"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Arka plan uygulamalar için Uygulama Yanıt Vermiyor mesajını göster"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Harici birimdeki uygulamalara izin vermeye zorla"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bildirilen değerlerden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Manifest değerlerinden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir yap."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Serbest biçimli pencereleri etkinleştir"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Etkin. Geçiş yapmak için hafifçe dokunun."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Çalışan hizmetler"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Gece modu"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Devre dışı"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Her zaman açık"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Otomatik"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Çoklu işlem WebView\'ı etkinleştir"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView oluşturucuları yalıtılmış bir işlemde çalıştırın."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView kullanımı"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView kullanımını ayarla"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Seçilen WebView uygulama şekli devre dışı. Bu uygulama şeklinin kullanılabilmesi için etkinleştirilmesi gerekir. Etkinleştirmek istiyor musunuz?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Bu seçenek artık geçerli değil. Tekrar deneyin."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Dosya şifrelemeye dönüştür"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Dönüştür…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dosya şifreleme zaten uygulandı"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu özellik deneyseldir ve performansı etkileyebilir."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Yaklaşık <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - yaklaşık <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - tam şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> var"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - prize takılı, tam şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> var"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - USB üzerinden şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> var"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - kablosuzdan tam şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> var"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Bilinmiyor"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Şarj oluyor"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC ile şarj oluyor"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB ile şarj oluyor"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Kablosuz şarj oluyor"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Şarj olmuyor"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Şarj etmiyor"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Dolu"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Yönetici tarafından devre dışı bırakıldı"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Yönetici tarafından denetleniyor"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Yönetici tarafından etkinleştirildi"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Yönetici tarafından devre dışı bırakıldı"</string>
     <string name="home" msgid="8263346537524314127">"Ana Ekran"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> önce"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kaldı"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Küçük"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Varsayılan"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Büyük"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Daha büyük"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"En büyük"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 9250dfd..0ed6cc0 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Вивід синтезу мовлення з тексту"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Темп мовлення"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Швидкість відтворення тексту"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Вис. зв."</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Впливає на тон синтезованого мовлення"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Мова"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Використовувати мову системи"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Мову не вибрано"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Показувати всі ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Сповіщати, коли додаток не відповідає"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Примусово записувати додатки в зовнішню пам’ять"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Додатки можна записувати на зовнішню пам’ять незалежно від значень маніфесту"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Можна записувати додатки в зовнішню пам’ять, незалежно від значень у маніфесті"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Примусово масштабувати активність"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Масштабувати активність на кілька вікон, незалежно від значень у файлі маніфесту."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Увімкнути вікна довільного формату"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активний додаток. Торкніться, щоб дезактивувати."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Запущені служби"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Перегляд і керування запущеними службами"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Нічний режим"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Вимкнено"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Завжди ввімкнено"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Увімк. багатопроцесний WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Запустити засоби обробки відео WebView окремим процесом."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Застосування WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Налаштувати застосування WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Вибране застосування WebView вимкнено. Увімкнути його?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ця опція більше не дійсна. Повторіть спробу."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертувати в зашифрований файл"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертація…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Уже конвертовано в зашифрований файл"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Це експериментальна функція. Вона може вплинути на продуктивність."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Залишилося приблизно <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – залишилось близько <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного зарядження"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного зарядження з розетки"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного зарядження через USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного з бездротового зарядження"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Невідомо"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Зарядж-ся"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Заряджання з розетки"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Заряджання через USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Заряджання без дроту"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Не заряджається"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не заряджається"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Акумулятор заряджено"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Вимкнено адміністратором"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Керується адміністратором"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Увімкнено адміністратором"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Вимкнено адміністратором"</string>
     <string name="home" msgid="8263346537524314127">"Головний екран"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> тому"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Залишилося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Малі елементи"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"За умовчанням"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Великі елементи"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Більші елементи"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найбільші елементи"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 3173b33..99a0f2b 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"ٹیکسٹ ٹو اسپیچ آؤٹ پٹ"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"اسپیچ کی شرح"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"متن بولے جانے کی رفتار"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"پچ"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"تصنعی اسپیچ کی ٹون کو متاثر کرتا ہے"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"زبان"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"سسٹم کی زبان استعمال کریں"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"زبان منتخب نہیں کی گئی"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"‏سبھی ANRs کو دکھائیں"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"پس منظر کی ایپس کیلئے ایپ جواب نہیں دے رہی ہے ڈائلاگ دکھائیں"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"بیرونی پر ایپس کو زبردستی اجازت دیں"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"‏manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"‏manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"‏manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بنائیں۔"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"‏freeform ونڈوز فعال کریں"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"چل رہی سروسز"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"رات موڈ"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"‎%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"غیر فعال"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"ہمیشہ آن"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"‏ملٹی پراسیس WebView بحال کریں"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"‏WebView رینڈررز کو ایک علیحدہ پراسیس میں چلائیں۔"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"‏WebView کا نفاذ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏WebView کا نفاذ سیٹ کریں"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏منتخب کردہ WebView کا نفاذ غیر فعال ہے اور استعمال کرنے کیلئے اسے فعال ہونا چاہئیے، کیا آپ اسے فعال کرنا چاہتے ہیں؟"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"یہ انتخاب اب درست نہیں رہا۔ دوبارہ کوشش کریں۔"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"فائل مرموز کاری میں بدلیں"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"بدلیں…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"فائل پہلے ہی مرموز شدہ ہے"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"یہ خصوصیت تجرباتی ہے اور اس کی وجہ سے کاکردگی متاثر ہو سکتی ہے۔"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"تقریبا <xliff:g id="TIME">%1$s</xliff:g> باقی ہیں"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎ - تقریبا <xliff:g id="TIME">%2$s</xliff:g> باقی"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>‎"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>‎ پورا ہونے تک"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC‎ پر پورا ہونے تک"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> USB‎ پر پورا ہونے تک"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>‎ وائرلیس سے پورا ہونے تک"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"نامعلوم"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"چارج ہو رہا ہے"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"‏AC پر چارج ہو رہی ہے"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"‏‫USB پر چارج ہورہی ہے"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"وائرلیس چارجنگ"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"چارج نہیں ہو رہا ہے"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"چارج نہیں ہو رہا ہے"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"مکمل"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"منتظم نے غیر فعال کر دیا"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"کنٹرول کردہ بذریعہ منتظم"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"منتظم نے فعال کر دیا"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"منتظم نے غیر فعال کر دیا"</string>
     <string name="home" msgid="8263346537524314127">"ہوم"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی ہیں"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"چھوٹا"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ڈیفالٹ"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"بڑا"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"قدرے بڑا"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"سب سے بڑا"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"حسب ضرورت (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index d6d8207..b9c0243 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -78,7 +78,7 @@
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Quyidagi qurilma javob bermayapti: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> biriktirish so‘rovini rad qildi."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi o‘chiq."</string>
-    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi o‘chirilgan."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi o‘chiq."</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: bitta ustun"</string>
     <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: ikkita ustun"</string>
     <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: uchta ustun"</string>
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Nutq sintezi"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Nutq tezligi"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Matnni o‘qish tezligi"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Chimdish"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Sintezlangan nutq balandligiga ta’sir qiladi"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Til"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Tizim tili"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Til tanlanmagan"</string>
@@ -246,11 +248,11 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Hamma ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Ilova javob bermayotgani haqida xabar qilish"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Tashqi xotira qurilmasidagi ilova dasturlariga majburiy ruxsat berish"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtirish."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Erkin shakldagi oynalarni yoqish"</string>
-    <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Tajribaviy erkin shakldagi oynalar ta’minotini yoqish."</string>
+    <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Erkin shakldagi oynalar yaratish uchun mo‘ljallangan tajribaviy funksiyani yoqish."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Zaxira nusxa uchun parol"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
     <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ish stoli to‘liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Faol. O‘zgartirish uchun bu yerga bosing."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Ishlab turgan ilovalar"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Tungi rejim"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"O‘chiq"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Har doim yoniq tursin"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView multiprocess’ni yoqish"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView renderlovchilarini alohida jarayonda ishga tushirish."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ta’minotchisi"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ta’minotchisini sozlash"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Tanlangan WebView ta’minotchisi o‘chirilgan va foydalanish uchun yoqilishi zarur. Yoqilsinmi?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Bu variant endi yaroqsiz. Qaytadan urining."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Faylli shifrga o‘girish"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"O‘girish…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl allaqachon shifrlangan"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya tajribaviy bo‘lib, u qurilma unumdorligiga ta’sir qilishi mumkin."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, to‘lguncha"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, o‘zgaruvchan tok orqali to‘lguncha"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, USB orqali to‘lguncha"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, simsiz quvvatlash orqali to‘lguncha"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Noma’lum"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Quvvat olmoqda"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Quvvat olmoqda (AC)"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Quvvat olmoqda (USB)"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Simsiz quvvat olmoqda"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Quvvat olmayapti"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Quvvatlanmayapti"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administrator tomonidan o‘chirib qo‘yilgan"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administrator tomonidan boshqariladi"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Administrator tomonidan yoqilgan"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Administrator tomonidan o‘chirilgan"</string>
     <string name="home" msgid="8263346537524314127">"Bosh ekran"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> oldin"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qoldi"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kichkina"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Birlamchi"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Katta"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Kattaroq"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Eng katta"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 5cc34bb..0c3dc89 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Đầu ra v.bản thành giọng nói"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Tốc độ nói"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Tốc độ đọc văn bản"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Độ cao"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ảnh hưởng đến âm điệu giọng nói được tổng hợp"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Ngôn ngữ"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Sử dụng ngôn ngữ hệ thống"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Không thể chọn ngôn ngữ"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Hiển thị tất cả ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Hiện hộp thoại Ứng dụng ko đáp ứng cho ứng dụng nền"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Buộc cho phép các ứng dụng trên bộ nhớ ngoài"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Giúp ứng dụng bất kỳ đủ điều kiện được ghi vào bộ nhớ ngoài bất kể giá trị tệp kê khai là gì"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Giúp mọi ứng dụng đủ điều kiện để được ghi vào bộ nhớ ngoài, bất kể giá trị tệp kê khai là gì"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Buộc các hoạt động có thể thay đổi kích thước"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Bật cửa sổ dạng tự do"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Hiện hoạt. Nhấn để chuyển đổi."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Các dịch vụ đang hoạt động"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Xem và kiểm soát các dịch vụ hiện đang hoạt động"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Chế độ ban đêm"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Đã tắt"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Luôn bật"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Tự động"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Bật WebView đa quy trình"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Chạy kết xuất đồ họa WebView trong quy trình tách biệt."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Triển khai WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Đặt triển khai WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Triển khai WebView đã chọn bị vô hiệu hóa và bạn phải bật để sử dụng tính năng này. Bạn có muốn bật tính năng này không?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Lựa chọn này không còn hợp lệ nữa. Hãy thử lại."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Chuyển đổi sang mã hóa tệp"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Chuyển đổi..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Đã mã hóa tệp"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tính năng này là tính năng thử nghiệm và có thể ảnh hưởng đến hoạt động."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Còn khoảng <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - còn khoảng <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> cho đến khi đầy"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> cho đến khi đầy khi cắm vào nguồn AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> cho đến khi đầy qua USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> cho đến khi đầy từ không dây"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Không xác định"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Đang sạc"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Sạc trên AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Sạc qua USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Sạc không dây"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Hiện không sạc"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hiện không sạc"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Đầy"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Bị tắt bởi quản trị viên"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Do quản trị viên kiểm soát"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Được bật bởi quản trị viên"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Bị tắt bởi quản trị viên"</string>
     <string name="home" msgid="8263346537524314127">"Màn hình chính"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> trước"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Còn <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Nhỏ"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Mặc định"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Lớn"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lớn hơn"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lớn nhất"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 4b67322..2b8ce65 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"文字转语音 (TTS) 输出"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"语速"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"文字转换成语音后的播放速度"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"音高"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"会影响合成语音的音调"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"语言"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"使用系统语言"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"未选择语言"</string>
@@ -246,13 +248,11 @@
     <string name="show_all_anrs" msgid="28462979638729082">"显示所有“应用无响应”(ANR)"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"为后台应用显示“应用无响应”对话框"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"强制允许将应用写入外部存储设备"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"强制将活动设为可调整大小"</string>
-    <!-- no translation found for force_resizable_activities_summary (6667493494706124459) -->
-    <skip />
+    <string name="force_resizable_activities_summary" msgid="6667493494706124459">"将所有 Activity 设为可配合多窗口环境调整大小(忽略清单值)。"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"启用可自由调整的窗口"</string>
-    <!-- no translation found for enable_freeform_support_summary (8247310463288834487) -->
-    <skip />
+    <string name="enable_freeform_support_summary" msgid="8247310463288834487">"启用可自由调整的窗口这一实验性功能。"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"桌面备份密码"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌面完整备份当前未设置密码保护"</string>
     <string name="local_backup_password_summary_change" msgid="5376206246809190364">"点按即可更改或移除用于保护桌面完整备份的密码"</string>
@@ -274,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"已启用。点按即可切换。"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"正在运行的服务"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"查看和控制当前正在运行的服务"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"夜间模式"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"始终开启"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"自动"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"启用多进程 WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在独立进程中运行 WebView 渲染程序。"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 实现"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"设置 WebView 实现"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"所选的 WebView 实现已停用,您必须先启用 WebView 实现才能加以使用。要启用该 WebView 实现吗?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"此选项已失效,请重试。"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"转换为文件加密"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"转换…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"文件已加密"</string>
@@ -303,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"此功能为实验性功能,可能会影响性能。"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"还剩大约 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还可用大约<xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满(交流电充电)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满(USB充电)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满(无线充电)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"未知"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"正在充电"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"正在通过交流电源充电"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"正在通过USB充电"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"正在无线充电"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"未在充电"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"未在充电"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"电量充足"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"已被管理员禁用"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"由管理员控制"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"已被管理员启用"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"已被管理员禁用"</string>
     <string name="home" msgid="8263346537524314127">"主屏幕"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"还剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"默认"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"较大"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自定义 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 301b90b..8dd0417 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"文字轉語音輸出"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"語音速率"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"文字轉語音的播放速度"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"音調"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"影響合成語音的音調"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"語言"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"使用系統語言"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"未選取語言"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"顯示所有 ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"顯示背景應用程式的「應用程式無回應」對話框"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"強制允許應用程式寫入到外部儲存空間"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將所有應用程式寫入到外部儲存完間 (所有資訊清單值)"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"在任何資訊清單值下,允許將所有符合資格的應用程式寫入到外部儲存完間"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"強制可變更活動尺寸"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"在任何資訊清單值下,允許系統配合多重視窗環境調整所有活動的尺寸。"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形態視窗"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"已啟用。輕按即可切換。"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"執行中的服務"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"查看並控制目前正在執行中的服務"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"夜間模式"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"永遠開啟"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"啟用多重處理程序 WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在獨立的處理程序中執行 WebView 轉譯器。"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 設置"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 設置"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"您選擇的 WebView 設定已停用,您必須先啟用此設定才能加以使用。要啟用此設定嗎?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"此選擇已失效,請再試一次。"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"轉換為檔案加密"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"轉換…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"已加密檔案"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是一項實驗性功能,可能會影響效能。"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"尚餘大約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 尚餘大約 <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 後完成充電"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 後完成充電 (透過插頭充電)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 後完成充電 (透過 USB 充電)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 後完成充電 (無線充電)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"未知"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"充電中"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"正在透過 AC 充電"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"正在透過 USB 充電"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"正在透過無線方式充電"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"非充電中"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"未開始充電"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"電量已滿"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理員已停用此設定"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"已由管理員啟用"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"已由管理員停用"</string>
     <string name="home" msgid="8263346537524314127">"主畫面"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"尚餘 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"預設"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index ce8303c..dd59954 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"文字轉語音輸出"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"語音速率"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"文字轉語音的播放速度"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"音調"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"會影響合成語音的音調"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"語言"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"使用系統設定"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"未選取語言"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"顯示所有無回應程式"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"為背景應用程式顯示「應用程式無回應」對話方塊"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"強制允許將應用程式寫入外部儲存空間"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"將活動強制設為可調整大小"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形式視窗"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"已啟用。輕按即可切換。"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"正在運作的服務"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"查看並管理目前正在執行的服務"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"夜間模式"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"一律開啟"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"啟用多重處理程序 WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在獨立的處理程序中執行 WebView 轉譯器。"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 實作"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 實作"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"您所選的 WebView 實作已停用,您必須先啟用 WebView 實作才能加以使用。要啟用該 WebView 實作嗎?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"這個選項已失效,請再試一次。"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"轉換成檔案加密"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"轉換..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"已將檔案加密"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是一項實驗性功能,可能會對效能造成影響。"</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"還剩大約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 大約還剩 <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽 (AC)"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽 (USB)"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽 (無線充電)"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"不明"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"充電中"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"正在透過 AC 變壓器充電"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"正在透過 USB 充電"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"正在透過無線方式充電"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"非充電中"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"非充電中"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"電力充足"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"已由管理員停用"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"已由管理員啟用"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"已由管理員停用"</string>
     <string name="home" msgid="8263346537524314127">"主畫面"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"還剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"預設"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 149011a..610cac4 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -101,6 +101,8 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Umbhalo-uya-kokukhishwa ngokukhuluma"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Ukukala izwi"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Isivinini leso umbhalo okhulunywe ngaso"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ukuphakama"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ithinta amathoni enkulumo akhiqiziwe"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Ulimi"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Sebenzisa ulimi lwesistimu"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"Ulimi alukhethwanga"</string>
@@ -246,7 +248,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Bonisa wonke ama-ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Boniso idayalogi Yohlelo Lokusebenza Olungasabeli kwizinhlelo zokusebenza zasemuva"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Phoqelela ukuvumela izinhlelo zokusebenza ngaphandle"</string>
-    <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
+    <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Yenza yonke imisebenzi ibe nosayizi abasha kumawindi amaningi, ngokunganaki amavelu e-manifest."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"Nika amandla amawindi e-freeform"</string>
@@ -272,18 +274,11 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Kuyasebenza. Thepha ukuze ushintshe."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Amasevisi asebenzayo"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Buka futhi ulawule amasevisi  asebenzayo okwamanje"</string>
-    <string name="night_mode_title" msgid="2594133148531256513">"Imodi yasebusuku"</string>
-    <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
-    <string name="night_mode_no" msgid="9171772244775838901">"Kukhutshaziwe"</string>
-    <string name="night_mode_yes" msgid="2218157265997633432">"Njalo ivuliwe"</string>
-    <string name="night_mode_auto" msgid="7508348175804304327">"Okuzenzakalelayo"</string>
-    <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
-    <skip />
-    <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
-    <skip />
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Nika amandla i-WebView kokucubungula okuningi"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Sebenzisa abasebenzeli be-WebView kwinqubo ekhethiwe."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Ukufakwa ke-WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Sesba ukufakwa kwe-WebView"</string>
-    <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Ukusetshenziswa kwe-WebView okukhethiwe kukhutshaziwe, futhi kuzomele kunikwe amandla ukuze kusetshenziswe, ingabe ufisa ukukunika amandla?"</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Lokhu kukhetha akusavumelekile. Zama futhi."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Phendulisela ekubethelweni kwefayela"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Iyaphendulela..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sekuvele kubethelwe ngefayela"</string>
@@ -301,22 +296,48 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Lesi sici esesilingo futhi singathinta ukusebenza."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="4400068916452346544">"Cishe ngu-<xliff:g id="TIME">%1$s</xliff:g> osele"</string>
+    <!-- no translation found for power_remaining_duration_only_short (5329694252258605547) -->
+    <skip />
     <string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - isilinganiso esingu-<xliff:g id="TIME">%2$s</xliff:g> esisele"</string>
+    <!-- no translation found for power_discharging_duration_short (4192244429001842403) -->
+    <skip />
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> kuze igcwale"</string>
+    <!-- no translation found for power_charging_duration_short (1098603958472207920) -->
+    <skip />
     <string name="power_charging_duration_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> kuze igcwale ku-AC"</string>
+    <!-- no translation found for power_charging_duration_ac_short (7895864687218765582) -->
+    <skip />
     <string name="power_charging_duration_usb" msgid="182405645340976546">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> kuze igcwale ngaphezulu kwe-USB"</string>
+    <!-- no translation found for power_charging_duration_usb_short (941854728040426399) -->
+    <skip />
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> kuze igcwale kusukela kokungenantambo"</string>
+    <!-- no translation found for power_charging_duration_wireless_short (1642664799869599476) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Akwaziwa"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Iyashaja"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Iyashaja ku-AC"</string>
+    <!-- no translation found for battery_info_status_charging_ac_short (7431401092096415502) -->
+    <skip />
     <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Iyashaja ngaphezulu kwe-USB"</string>
+    <!-- no translation found for battery_info_status_charging_usb_short (6733371990319101366) -->
+    <skip />
     <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Iyashaja ngaphandle kwentambo"</string>
+    <!-- no translation found for battery_info_status_charging_wireless_short (752569941028903610) -->
+    <skip />
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ayishaji"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ayishaji"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Kugcwele"</string>
-    <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Ikhutshazwe umlawuli"</string>
+    <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kulawulwa umqondisi"</string>
+    <string name="enabled_by_admin" msgid="2386503803463071894">"Kunikwe amandla umqondisi"</string>
+    <string name="disabled_by_admin" msgid="3669999613095206948">"Ikhutshazwe umlawuli"</string>
     <string name="home" msgid="8263346537524314127">"Ekhaya"</string>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> edlule"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> osele"</string>
+    <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Okuncane"</string>
+    <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Okuzenzakalelayo"</string>
+    <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Okukhulu"</string>
+    <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Okukhulu kakhulu"</string>
+    <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Okukhulu kakhulu"</string>
+    <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 1bce7f9..525d6f4 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -344,28 +344,6 @@
         <item>midi</item>
     </string-array>
 
-    <!-- Possible values for user theme in Display Settings.
-         Do not translate. -->
-    <string-array name="night_mode_entries" translatable="false">
-        <!-- Do not translate. -->
-        <item>@string/night_mode_no</item>
-        <!-- Do not translate. -->
-        <item>@string/night_mode_yes</item>
-        <!-- Do not translate. -->
-        <item>@string/night_mode_auto</item>
-    </string-array>
-
-    <!-- These values should match up with the MODE_NIGHT constants in UiModeManager.
-         Do not translate. -->
-    <string-array name="night_mode_values" translatable="false">
-        <!-- Do not translate. -->
-        <item>1</item>
-        <!-- Do not translate. -->
-        <item>2</item>
-        <!-- Do not translate. -->
-        <item>0</item>
-    </string-array>
-
     <!-- Display color space adjustment modes for developers -->
     <string-array name="simulate_color_space_entries" translatable="false">
         <item>@string/daltonizer_mode_disabled</item>
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
new file mode 100755
index 0000000..299a5b7
--- /dev/null
+++ b/packages/SettingsLib/res/values/config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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>
+    <!-- Configuration for automotive -->
+    <bool name="enable_pbap_pce_profile">false</bool>
+</resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 9f78e87..c3b3cfc 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -33,8 +33,8 @@
     <dimen name="user_spinner_item_height">56dp</dimen>
 
     <!-- Lock icon for preferences locked by admin -->
-    <dimen name="restricted_lock_icon_size">16dp</dimen>
-    <dimen name="restricted_lock_icon_padding">4dp</dimen>
+    <dimen name="restricted_icon_size">16dp</dimen>
+    <dimen name="restricted_icon_padding">4dp</dimen>
 
     <dimen name="wifi_preference_badge_padding">8dip</dimen>
 
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 57c5684..a560e3c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -236,10 +236,14 @@
     <string name="tts_settings">Text-to-speech settings</string>
     <!-- TTS option item name in the main settings screen -->
     <string name="tts_settings_title">Text-to-speech output</string>
-    <!-- On main TTS Settings screen, in default settings section, setting default speech rate for synthesized voice -->
+  <!-- On main TTS Settings screen, in default settings section, setting default speech rate for synthesized voice -->
     <string name="tts_default_rate_title">Speech rate</string>
     <!-- On main TTS Settings screen, summary for default speech rate for synthesized voice -->
     <string name="tts_default_rate_summary">Speed at which the text is spoken</string>
+    <!-- On main TTS Settings screen, in default settings section, setting default pitch for synthesized voice -->
+    <string name="tts_default_pitch_title">Pitch</string>
+    <!-- On main TTS Settings screen, summary for default pitch for synthesized voice -->
+    <string name="tts_default_pitch_summary">Affects the tone of the synthesized speech</string>
     <!-- On main TTS Settings screen, in default settings section, setting default language for synthesized voice -->
     <string name="tts_default_lang_title">Language</string>
     <!-- Entry in the TTS engine language/locale picker, when selected will try to default to the system language [CHAR LIMIT=50] -->
@@ -621,7 +625,7 @@
     <!-- UI debug setting: force allow apps on external storage [CHAR LIMIT=50] -->
     <string name="force_allow_on_external">Force allow apps on external</string>
     <!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
-    <string name="force_allow_on_external_summary">Makes any app elligible to be written to external storage, regardless of manifest values</string>
+    <string name="force_allow_on_external_summary">Makes any app eligible to be written to external storage, regardless of manifest values</string>
 
     <!-- UI debug setting: force all activites to be resizable for multiwindow [CHAR LIMIT=50] -->
     <string name="force_resizable_activities">Force activities to be resizable</string>
@@ -673,18 +677,7 @@
     <!-- Services settings screen, setting option summary for the user to go to the screen to view running services  -->
     <string name="runningservices_settings_summary">View and control currently running services</string>
 
-    <!-- Sound & display settings screen, setting option name to change the user interface theme [CHAR LIMIT=30] -->
-    <string name="night_mode_title">Night mode</string>
-    <!-- Sound & display settings screen, setting option summary to change the user interface theme [CHAR LIMIT=100] -->
-    <string name="night_mode_summary">%s</string>
-    <!-- Sound & display settings screen, theme setting value to prefer a light-colored user interface [CHAR LIMIT=30] -->
-    <string name="night_mode_no">Disabled</string>
-    <!-- Sound & display settings screen, theme setting value to prefer a dark-colored user interface [CHAR LIMIT=30] -->
-    <string name="night_mode_yes">Always on</string>
-    <!-- Sound & display settings screen, theme setting value to automatically switch between a light- or dark-colored user interface [CHAR LIMIT=30] -->
-    <string name="night_mode_auto">Automatic</string>
-
-    <!-- Developer settings: enable WebView multiprocess name [CHAR LIMIT=30] -->
+    <!-- Developer settings: enable WebView multiprocess name [CHAR LIMIT=50] -->
     <string name="enable_webview_multiprocess">Enable multiprocess WebView</string>
     <!-- Developer settings: enable WebView multiprocess summary [CHAR LIMIT=60] -->
     <string name="enable_webview_multiprocess_desc">Run WebView renderers in an isolated process.</string>
@@ -693,8 +686,8 @@
     <string name="select_webview_provider_title">WebView implementation</string>
     <!-- Developer settings: select WebView provider dialog title [CHAR LIMIT=30] -->
     <string name="select_webview_provider_dialog_title">Set WebView implementation</string>
-    <!-- Developer settings: confirmation dialog text for the WebView provider selection dialog [CHAR LIMIT=NONE] -->
-    <string name="select_webview_provider_confirmation_text">The chosen WebView implementation is disabled, and must be enabled to be used, do you wish to enable it?</string>
+    <!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
+    <string name="select_webview_provider_toast_text">This choice is no longer valid. Try again.</string>
 
     <!-- Developer settings screen, convert userdata to file encryption option name -->
     <string name="convert_to_file_encryption">Convert to file encryption</string>
@@ -740,25 +733,44 @@
     <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging/discharging -->
     <string name="power_remaining_duration_only">Approx. <xliff:g id="time">%1$s</xliff:g> left</string>
 
+    <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+    <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
+
     <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
     <string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g>
         - approx. <xliff:g id="time">%2$s</xliff:g> left</string>
 
+    <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
+    <string name="power_discharging_duration_short"><xliff:g id="level">%1$s</xliff:g>
+        - <xliff:g id="time">%2$s</xliff:g> left</string>
+
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging -->
     <string name="power_charging"><xliff:g id="level">%1$s</xliff:g> -
             <xliff:g id="state">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> -
             <xliff:g id="time">%2$s</xliff:g> until full</string>
+    <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+    <string name="power_charging_duration_short"><xliff:g id="level">%1$s</xliff:g> -
+        <xliff:g id="time">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration_ac"><xliff:g id="level">%1$s</xliff:g> -
             <xliff:g id="time">%2$s</xliff:g> until full on AC</string>
+    <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+    <string name="power_charging_duration_ac_short"><xliff:g id="level">%1$s</xliff:g> -
+        <xliff:g id="time">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration_usb"><xliff:g id="level">%1$s</xliff:g> -
             <xliff:g id="time">%2$s</xliff:g> until full over USB</string>
+    <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+    <string name="power_charging_duration_usb_short"><xliff:g id="level">%1$s</xliff:g> -
+        <xliff:g id="time">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration_wireless"><xliff:g id="level">%1$s</xliff:g> -
             <xliff:g id="time">%2$s</xliff:g> until full from wireless</string>
+    <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
+    <string name="power_charging_duration_wireless_short"><xliff:g id="level">%1$s</xliff:g> -
+        <xliff:g id="time">%2$s</xliff:g></string>
 
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_unknown">Unknown</string>
@@ -766,10 +778,16 @@
     <string name="battery_info_status_charging">Charging</string>
     <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging on AC.  -->
     <string name="battery_info_status_charging_ac">Charging on AC</string>
+    <!-- [CHAR_LIMIT=20] Battery short status label when charing on AC -->
+    <string name="battery_info_status_charging_ac_short">Charging</string>
     <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging over USB.  -->
     <string name="battery_info_status_charging_usb">Charging over USB</string>
+    <!-- [CHAR_LIMIT=20] Battery short status label when charging over USB. -->
+    <string name="battery_info_status_charging_usb_short">Charging</string>
     <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging over a wireless connection.  -->
     <string name="battery_info_status_charging_wireless">Charging wirelessly</string>
+    <!-- [CHAR_LIMIT=20] Battery short status label when charging wirelessly. -->
+    <string name="battery_info_status_charging_wireless_short">Charging</string>
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_discharging">Not charging</string>
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
@@ -780,6 +798,11 @@
     <!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
     <string name="disabled_by_admin_summary_text">Controlled by admin</string>
 
+    <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+    <string name="enabled_by_admin">Enabled by administrator</string>
+    <!-- Summary for switch preference to denote it is switched off [CHAR LIMIT=50] -->
+    <string name="disabled_by_admin">Disabled by administrator</string>
+
     <!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] -->
     <string name="home">Home</string>
 
@@ -795,4 +818,37 @@
     <!-- Label for length of time until battery is charged [CHAR LIMIT=20] -->
     <string name="remaining_length_format"><xliff:g name="time" example="3 hours">%1$s</xliff:g> left</string>
 
+    <!-- Hint text for the IP address -->
+    <string name="wifi_ip_address_hint" translatable="false">192.168.1.128</string>
+    <!-- Hint text for DNS -->
+    <string name="wifi_dns1_hint" translatable="false">8.8.8.8</string>
+    <!-- Hint text for DNS -->
+    <string name="wifi_dns2_hint" translatable="false">8.8.4.4</string>
+    <!-- Hint text for the gateway -->
+    <string name="wifi_gateway_hint" translatable="false">192.168.1.1</string>
+    <!-- Hint text for network prefix length -->
+    <string name="wifi_network_prefix_length_hint" translatable="false">24</string>
+    <!-- HTTP proxy settings. The hint text field for port. -->
+    <string name="proxy_port_hint" translatable="false">8080</string>
+    <!-- HTTP proxy settings. Hint for Proxy-Auto Config URL. -->
+    <string name="proxy_url_hint" translatable="false">https://www.example.com/proxy.pac</string>
+    <!-- HTTP proxy settings. The hint text for proxy exclusion list. -->
+    <string name="proxy_exclusionlist_hint" translatable="false">example.com,mycomp.test.com,localhost</string>
+    <!-- HTTP proxy settings. The hint text field for the hostname. -->
+    <string name="proxy_hostname_hint" translatable="false">proxy.example.com</string>
+
+    <!-- Description for the screen zoom level that makes interface elements small. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_small">Small</string>
+    <!-- Description for the device's default screen zoom level. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_default">Default</string>
+    <!-- Description for the screen zoom level that makes interface elements large. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_large">Large</string>
+    <!-- Description for the screen zoom level that makes interface elements larger. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_very_large">Larger</string>
+    <!-- Description for the screen zoom level that makes interface elements largest. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_extremely_large">Largest</string>
+    <!-- Description for a custom screen zoom level. This shows the requested display
+         density in raw pixels per inch rather than using a relative description. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
index b16b8ec..fa1f91f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
+++ b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
@@ -25,6 +25,7 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.text.format.Formatter;
+import android.util.Log;
 import android.util.SparseIntArray;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.settingslib.graph.UsageView;
@@ -39,12 +40,170 @@
     public String remainingLabel;
     private BatteryStats mStats;
     private boolean mCharging;
+    private long timePeriod;
 
     public interface Callback {
         void onBatteryInfoLoaded(BatteryInfo info);
     }
 
-    public void bindHistory(UsageView view) {
+    public void bindHistory(final UsageView view, BatteryDataParser... parsers) {
+        BatteryDataParser parser = new BatteryDataParser() {
+            SparseIntArray points = new SparseIntArray();
+
+            @Override
+            public void onParsingStarted(long startTime, long endTime) {
+                timePeriod = endTime - startTime - remainingTimeUs / 1000;
+                view.clearPaths();
+                view.configureGraph((int) (endTime - startTime), 100, remainingTimeUs != 0,
+                        mCharging);
+            }
+
+            @Override
+            public void onDataPoint(long time, HistoryItem record) {
+                points.put((int) time, record.batteryLevel);
+            }
+
+            @Override
+            public void onDataGap() {
+                if (points.size() > 1) {
+                    view.addPath(points);
+                }
+                points.clear();
+            }
+
+            @Override
+            public void onParsingDone() {
+                if (points.size() > 1) {
+                    view.addPath(points);
+                }
+            }
+        };
+        BatteryDataParser[] parserList = new BatteryDataParser[parsers.length + 1];
+        for (int i = 0; i < parsers.length; i++) {
+            parserList[i] = parsers[i];
+        }
+        parserList[parsers.length] = parser;
+        parse(mStats, remainingTimeUs, parserList);
+        final Context context = view.getContext();
+        String timeString = context.getString(R.string.charge_length_format,
+                Formatter.formatShortElapsedTime(context, timePeriod));
+        String remaining = "";
+        if (remainingTimeUs != 0) {
+            remaining = context.getString(R.string.remaining_length_format,
+                    Formatter.formatShortElapsedTime(context, remainingTimeUs / 1000));
+        }
+        view.setBottomLabels(new CharSequence[]{timeString, remaining});
+    }
+
+    public static void getBatteryInfo(final Context context, final Callback callback) {
+        BatteryInfo.getBatteryInfo(context, callback, false);
+    }
+
+    public static void getBatteryInfo(final Context context, final Callback callback,
+            boolean shortString) {
+        new AsyncTask<Void, Void, BatteryStats>() {
+            @Override
+            protected BatteryStats doInBackground(Void... params) {
+                BatteryStatsHelper statsHelper = new BatteryStatsHelper(context, true);
+                statsHelper.create((Bundle) null);
+                return statsHelper.getStats();
+            }
+
+            @Override
+            protected void onPostExecute(BatteryStats batteryStats) {
+                final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
+                Intent batteryBroadcast = context.registerReceiver(null,
+                        new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+                BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context,
+                        batteryBroadcast, batteryStats, elapsedRealtimeUs, shortString);
+                callback.onBatteryInfoLoaded(batteryInfo);
+            }
+        }.execute();
+    }
+
+    public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
+                                             BatteryStats stats, long elapsedRealtimeUs) {
+        return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs,
+                false);
+    }
+
+    public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
+            BatteryStats stats, long elapsedRealtimeUs, boolean shortString) {
+        BatteryInfo info = new BatteryInfo();
+        info.mStats = stats;
+        info.mBatteryLevel = Utils.getBatteryLevel(batteryBroadcast);
+        info.batteryPercentString = Utils.formatPercentage(info.mBatteryLevel);
+        info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+        final Resources resources = context.getResources();
+        if (!info.mCharging) {
+            final long drainTime = stats.computeBatteryTimeRemaining(elapsedRealtimeUs);
+            if (drainTime > 0) {
+                info.remainingTimeUs = drainTime;
+                String timeString = Formatter.formatShortElapsedTime(context,
+                        drainTime / 1000);
+                info.remainingLabel = resources.getString(
+                        shortString ? R.string.power_remaining_duration_only_short
+                                : R.string.power_remaining_duration_only,
+                        timeString);
+                info.mChargeLabelString = resources.getString(
+                        shortString ? R.string.power_discharging_duration_short
+                                : R.string.power_discharging_duration,
+                        info.batteryPercentString, timeString);
+            } else {
+                info.remainingLabel = null;
+                info.mChargeLabelString = info.batteryPercentString;
+            }
+        } else {
+            final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs);
+            final String statusLabel = Utils.getBatteryStatus(
+                    resources, batteryBroadcast, shortString);
+            final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
+                    BatteryManager.BATTERY_STATUS_UNKNOWN);
+            if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
+                info.mDischarging = false;
+                info.remainingTimeUs = chargeTime;
+                String timeString = Formatter.formatShortElapsedTime(context,
+                        chargeTime / 1000);
+                int plugType = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+                int resId;
+                if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
+                    resId = shortString ? R.string.power_charging_duration_ac_short
+                            : R.string.power_charging_duration_ac;
+                } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
+                    resId = shortString ? R.string.power_charging_duration_usb_short
+                            : R.string.power_charging_duration_usb;
+                } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
+                    resId = shortString ? R.string.power_charging_duration_wireless_short
+                            : R.string.power_charging_duration_wireless;
+                } else {
+                    resId = shortString ? R.string.power_charging_duration_short
+                            : R.string.power_charging_duration;
+                }
+                info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
+                        timeString);
+                info.mChargeLabelString = resources.getString(
+                        resId, info.batteryPercentString, timeString);
+            } else {
+                info.remainingLabel = statusLabel;
+                info.mChargeLabelString = resources.getString(
+                        R.string.power_charging, info.batteryPercentString, statusLabel);
+            }
+        }
+        return info;
+    }
+
+    public interface BatteryDataParser {
+        void onParsingStarted(long startTime, long endTime);
+
+        void onDataPoint(long time, HistoryItem record);
+
+        void onDataGap();
+
+        void onParsingDone();
+    }
+
+    private static void parse(BatteryStats stats, long remainingTimeUs,
+            BatteryDataParser... parsers) {
         long startWalltime = 0;
         long endDateWalltime = 0;
         long endWalltime = 0;
@@ -57,9 +216,9 @@
         int lastInteresting = 0;
         int pos = 0;
         boolean first = true;
-        if (mStats.startIteratingHistoryLocked()) {
+        if (stats.startIteratingHistoryLocked()) {
             final HistoryItem rec = new HistoryItem();
-            while (mStats.getNextHistoryLocked(rec)) {
+            while (stats.getNextHistoryLocked(rec)) {
                 pos++;
                 if (first) {
                     first = false;
@@ -75,14 +234,14 @@
                     // since the start of the history real time, then also use this new
                     // time to compute the base time, since whatever time we had before is
                     // pretty much just noise.
-                    if (rec.currentTime > (lastWallTime+(180*24*60*60*1000L))
-                            || rec.time < (historyStart+(5*60*1000L))) {
+                    if (rec.currentTime > (lastWallTime + (180 * 24 * 60 * 60 * 1000L))
+                            || rec.time < (historyStart + (5 * 60 * 1000L))) {
                         startWalltime = 0;
                     }
                     lastWallTime = rec.currentTime;
                     lastRealtime = rec.time;
                     if (startWalltime == 0) {
-                        startWalltime = lastWallTime - (lastRealtime-historyStart);
+                        startWalltime = lastWallTime - (lastRealtime - historyStart);
                     }
                 }
                 if (rec.isDeltaData()) {
@@ -94,19 +253,19 @@
                 }
             }
         }
-        mStats.finishIteratingHistoryLocked();
+        stats.finishIteratingHistoryLocked();
         endDateWalltime = lastWallTime + historyEnd - lastRealtime;
         endWalltime = endDateWalltime + (remainingTimeUs / 1000);
 
         int i = 0;
         final int N = lastInteresting;
-        SparseIntArray points = new SparseIntArray();
-        view.clearPaths();
-        view.configureGraph((int) (endWalltime - startWalltime), 100, remainingTimeUs != 0,
-                mCharging);
-        if (endDateWalltime > startWalltime && mStats.startIteratingHistoryLocked()) {
+
+        for (int j = 0; j < parsers.length; j++) {
+            parsers[j].onParsingStarted(startWalltime, endWalltime);
+        }
+        if (endDateWalltime > startWalltime && stats.startIteratingHistoryLocked()) {
             final HistoryItem rec = new HistoryItem();
-            while (mStats.getNextHistoryLocked(rec) && i < N) {
+            while (stats.getNextHistoryLocked(rec) && i < N) {
                 if (rec.isDeltaData()) {
                     curWalltime += rec.time - lastRealtime;
                     lastRealtime = rec.time;
@@ -114,7 +273,9 @@
                     if (x < 0) {
                         x = 0;
                     }
-                    points.put((int) x, rec.batteryLevel);
+                    for (int j = 0; j < parsers.length; j++) {
+                        parsers[j].onDataPoint(x, rec);
+                    }
                 } else {
                     long lastWalltime = curWalltime;
                     if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
@@ -129,108 +290,20 @@
 
                     if (rec.cmd != HistoryItem.CMD_OVERFLOW
                             && (rec.cmd != HistoryItem.CMD_CURRENT_TIME
-                                    || Math.abs(lastWalltime-curWalltime) > (60*60*1000))) {
-                        if (points.size() > 1) {
-                            view.addPath(points);
+                            || Math.abs(lastWalltime - curWalltime) > (60 * 60 * 1000))) {
+                        for (int j = 0; j < parsers.length; j++) {
+                            parsers[j].onDataGap();
                         }
-                        points.clear();
                     }
                 }
                 i++;
             }
         }
-        if (points.size() > 1) {
-            view.addPath(points);
+
+        stats.finishIteratingHistoryLocked();
+
+        for (int j = 0; j < parsers.length; j++) {
+            parsers[j].onParsingDone();
         }
-        long timePast = endDateWalltime - startWalltime;
-        final Context context = view.getContext();
-        String timeString = context.getString(R.string.charge_length_format,
-                Formatter.formatShortElapsedTime(context, timePast));
-        String remaining = "";
-        if (remainingTimeUs != 0) {
-            remaining = context.getString(R.string.remaining_length_format,
-                    Formatter.formatShortElapsedTime(context, remainingTimeUs / 1000));
-        }
-        view.setBottomLabels(new CharSequence[] { timeString, remaining});
-
-        mStats.finishIteratingHistoryLocked();
-    }
-
-    public static void getBatteryInfo(final Context context, final Callback callback) {
-        new AsyncTask<Void, Void, BatteryStats>() {
-            @Override
-            protected BatteryStats doInBackground(Void... params) {
-                BatteryStatsHelper statsHelper = new BatteryStatsHelper(context, true);
-                statsHelper.create((Bundle) null);
-                return statsHelper.getStats();
-            }
-
-            @Override
-            protected void onPostExecute(BatteryStats batteryStats) {
-                final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
-                Intent batteryBroadcast = context.registerReceiver(null,
-                        new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
-                BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context,
-                        batteryBroadcast, batteryStats, elapsedRealtimeUs);
-                callback.onBatteryInfoLoaded(batteryInfo);
-            }
-        }.execute();
-    }
-
-    public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
-            BatteryStats stats, long elapsedRealtimeUs) {
-        BatteryInfo info = new BatteryInfo();
-        info.mStats = stats;
-        info.mBatteryLevel = Utils.getBatteryLevel(batteryBroadcast);
-        info.batteryPercentString = Utils.formatPercentage(info.mBatteryLevel);
-        info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
-        final Resources resources = context.getResources();
-        if (!info.mCharging) {
-            final long drainTime = stats.computeBatteryTimeRemaining(elapsedRealtimeUs);
-            if (drainTime > 0) {
-                info.remainingTimeUs = drainTime;
-                String timeString = Formatter.formatShortElapsedTime(context,
-                        drainTime / 1000);
-                info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
-                        timeString);
-                info.mChargeLabelString = resources.getString(R.string.power_discharging_duration,
-                        info.batteryPercentString, timeString);
-            } else {
-                info.remainingLabel = null;
-                info.mChargeLabelString = info.batteryPercentString;
-            }
-        } else {
-            final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs);
-            final String statusLabel = Utils.getBatteryStatus(
-                    resources, batteryBroadcast);
-            final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
-                    BatteryManager.BATTERY_STATUS_UNKNOWN);
-            if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
-                info.mDischarging = false;
-                info.remainingTimeUs = chargeTime;
-                String timeString = Formatter.formatShortElapsedTime(context,
-                        chargeTime / 1000);
-                int plugType = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
-                int resId;
-                if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
-                    resId = R.string.power_charging_duration_ac;
-                } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
-                    resId = R.string.power_charging_duration_usb;
-                } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
-                    resId = R.string.power_charging_duration_wireless;
-                } else {
-                    resId = R.string.power_charging_duration;
-                }
-                info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
-                        timeString);
-                info.mChargeLabelString = resources.getString(
-                        resId, info.batteryPercentString, timeString);
-            } else {
-                info.remainingLabel = statusLabel;
-                info.mChargeLabelString = resources.getString(
-                        R.string.power_charging, info.batteryPercentString, statusLabel);
-            }
-        }
-        return info;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
deleted file mode 100644
index c2f885d..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.v7.preference.DropDownPreference;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
-public class RestrictedDropDownPreference extends DropDownPreference {
-    private Spinner mSpinner;
-    private final Drawable mRestrictedPadlock;
-    private final int mRestrictedPadlockPadding;
-    private List<RestrictedItem> mRestrictedItems = new ArrayList<>();
-
-    public RestrictedDropDownPreference(Context context) {
-        this(context, null);
-    }
-
-    public RestrictedDropDownPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(context);
-        mRestrictedPadlockPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
-    }
-
-    private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
-            if (position >= 0) {
-                String value = getEntryValues()[position].toString();
-                RestrictedItem item = getRestrictedItemForEntryValue(value);
-                if (item != null) {
-                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
-                            item.enforcedAdmin);
-                    mSpinner.setSelection(findIndexOfValue(getValue()));
-                } else if (!value.equals(getValue()) && callChangeListener(value)) {
-                    setValue(value);
-                }
-            }
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            // noop
-        }
-    };
-
-    @Override
-    protected ArrayAdapter createAdapter() {
-        return new RestrictedArrayItemAdapter(getContext());
-    }
-
-    @Override
-    public void setValue(String value) {
-        if (getRestrictedItemForEntryValue(value) != null) {
-            return;
-        }
-        super.setValue(value);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder view) {
-        super.onBindViewHolder(view);
-        mSpinner = (Spinner) view.itemView.findViewById(R.id.spinner);
-        mSpinner.setOnItemSelectedListener(mItemSelectedListener);
-    }
-
-    private class RestrictedArrayItemAdapter extends ArrayAdapter<String> {
-        public RestrictedArrayItemAdapter(Context context) {
-            super(context, R.layout.spinner_dropdown_restricted_item);
-        }
-
-        @Override
-        public View getDropDownView(int position, View convertView, ViewGroup parent) {
-            TextView view = (TextView) super.getView(position, convertView, parent);
-            CharSequence entry = getItem(position);
-            boolean isEntryRestricted = isRestrictedForEntry(entry);
-            RestrictedLockUtils.setTextViewPadlock(getContext(), view, isEntryRestricted);
-            view.setEnabled(!isEntryRestricted);
-            return view;
-        }
-    }
-
-    private boolean isRestrictedForEntry(CharSequence entry) {
-        if (entry == null) {
-            return false;
-        }
-        for (RestrictedItem item : mRestrictedItems) {
-            if (entry.equals(item.entry)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private RestrictedItem getRestrictedItemForEntryValue(CharSequence entryValue) {
-        if (entryValue == null) {
-            return null;
-        }
-        for (RestrictedItem item : mRestrictedItems) {
-            if (entryValue.equals(item.entryValue)) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    public void addRestrictedItem(RestrictedItem item) {
-        mRestrictedItems.add(item);
-    }
-
-    public static class RestrictedItem {
-        public CharSequence entry;
-        public CharSequence entryValue;
-        public EnforcedAdmin enforcedAdmin;
-
-        public RestrictedItem(CharSequence entry, CharSequence entryValue,
-                EnforcedAdmin enforcedAdmin) {
-            this.entry = entry;
-            this.entryValue = entryValue;
-            this.enforcedAdmin = enforcedAdmin;
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java
index e63130d..360a34c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java
@@ -36,7 +36,7 @@
 
         mContext = context;
         mExtraPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
+                R.dimen.restricted_icon_padding);
         mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
     }
 
@@ -53,7 +53,7 @@
 
         // Add extra padding before the padlock.
         float transX = x + mExtraPadding;
-        float transY = bottom - drawable.getBounds().bottom - paint.getFontMetricsInt().descent;
+        float transY = (bottom - drawable.getBounds().bottom) / 2.0f;
 
         canvas.translate(transX, transY);
         drawable.draw(canvas);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 6d29c5f..e86ca82 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -49,9 +49,9 @@
      * @return drawables for displaying with settings that are locked by a device admin.
      */
     public static Drawable getRestrictedPadlock(Context context) {
-        Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_settings_lock_outline);
+        Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_info);
         final int iconSize = context.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_size);
+                R.dimen.restricted_icon_size);
         restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
         return restrictedPadlock;
     }
@@ -78,7 +78,8 @@
         int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
         boolean enforcedByDeviceOwner = false;
         if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
-            Bundle enforcedRestrictions = dpm.getUserRestrictions(deviceOwner, deviceOwnerUserId);
+            Bundle enforcedRestrictions =
+                    dpm.getUserRestrictionsForUser(deviceOwner, deviceOwnerUserId);
             if (enforcedRestrictions != null
                     && enforcedRestrictions.getBoolean(userRestriction, false)) {
                 enforcedByDeviceOwner = true;
@@ -90,7 +91,8 @@
         if (userId != UserHandle.USER_NULL) {
             profileOwner = dpm.getProfileOwnerAsUser(userId);
             if (profileOwner != null) {
-                Bundle enforcedRestrictions = dpm.getUserRestrictions(profileOwner, userId);
+                Bundle enforcedRestrictions =
+                        dpm.getUserRestrictionsForUser(profileOwner, userId);
                 if (enforcedRestrictions != null
                         && enforcedRestrictions.getBoolean(userRestriction, false)) {
                     enforcedByProfileOwner = true;
@@ -234,7 +236,7 @@
             if (ipm.isPackageSuspendedForUser(packageName, userId)) {
                 return getProfileOrDeviceOwner(context, userId);
             }
-        } catch (RemoteException e) {
+        } catch (RemoteException | IllegalArgumentException e) {
             // Nothing to do
         }
         return null;
@@ -651,8 +653,11 @@
             final int disabledColor = context.getColor(R.color.disabled_text_color);
             sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-            final ImageSpan image = new RestrictedLockImageSpan(context);
-            sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            textView.setCompoundDrawables(null, null, getRestrictedPadlock(context), null);
+            textView.setCompoundDrawablePadding(context.getResources().getDimensionPixelSize(
+                    R.dimen.restricted_icon_padding));
+        } else {
+            textView.setCompoundDrawables(null, null, null, null);
         }
         textView.setText(sb);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index 810f6eb..e69497a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -23,6 +23,7 @@
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.util.AttributeSet;
+import android.view.View;
 
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
@@ -36,6 +37,7 @@
     public RestrictedPreference(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        setWidgetLayoutResource(R.layout.restricted_icon);
         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
     }
 
@@ -56,6 +58,10 @@
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
         mHelper.onBindViewHolder(holder);
+        final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
+        if (restrictedIcon != null) {
+            restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
+        }
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 227b1e8..d0aba22 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -22,9 +22,6 @@
 import android.os.UserHandle;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceViewHolder;
-import android.text.Spanned;
-import android.text.SpannableStringBuilder;
-import android.text.style.ImageSpan;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.View;
@@ -39,8 +36,6 @@
 public class RestrictedPreferenceHelper {
     private final Context mContext;
     private final Preference mPreference;
-    private final Drawable mRestrictedPadlock;
-    private final int mRestrictedPadlockPadding;
 
     private boolean mDisabledByAdmin;
     private EnforcedAdmin mEnforcedAdmin;
@@ -52,10 +47,6 @@
         mContext = context;
         mPreference = preference;
 
-        mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
-        mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
-
         if (attrs != null) {
             final TypedArray attributes = context.obtainStyledAttributes(attrs,
                     R.styleable.RestrictedPreference);
@@ -91,12 +82,8 @@
      * Modify PreferenceViewHolder to add padlock if restriction is disabled.
      */
     public void onBindViewHolder(PreferenceViewHolder holder) {
-        final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
-        if (titleView != null) {
-            RestrictedLockUtils.setTextViewPadlock(mContext, titleView, mDisabledByAdmin);
-            if (mDisabledByAdmin) {
-                holder.itemView.setEnabled(true);
-            }
+        if (mDisabledByAdmin) {
+            holder.itemView.setEnabled(true);
         }
         if (mUseAdminDisabledSummary) {
             final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
@@ -158,13 +145,14 @@
      */
     public boolean setDisabledByAdmin(EnforcedAdmin admin) {
         final boolean disabled = (admin != null ? true : false);
-        mEnforcedAdmin = (disabled ? admin : null);
+        mEnforcedAdmin = admin;
+        boolean changed = false;
         if (mDisabledByAdmin != disabled) {
             mDisabledByAdmin = disabled;
-            mPreference.setEnabled(!disabled);
-            return true;
+            changed = true;
         }
-        return false;
+        mPreference.setEnabled(!disabled);
+        return changed;
     }
 
     public boolean isDisabledByAdmin() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 6cae8aa..f381286 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -23,6 +23,8 @@
 import android.support.v7.preference.PreferenceViewHolder;
 import android.support.v14.preference.SwitchPreference;
 import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
 
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
@@ -36,6 +38,7 @@
     public RestrictedSwitchPreference(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        setWidgetLayoutResource(R.layout.restricted_switch_widget);
         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
     }
 
@@ -56,6 +59,20 @@
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
         mHelper.onBindViewHolder(holder);
+        final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
+        final View switchWidget = holder.findViewById(android.R.id.switch_widget);
+        if (restrictedIcon != null) {
+            restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
+        }
+        if (switchWidget != null) {
+            switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
+        }
+        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+        if (summaryView != null && isDisabledByAdmin()) {
+            summaryView.setText(
+                    isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
+            summaryView.setVisibility(View.VISIBLE);
+        }
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 1859207..741b0ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -25,6 +25,12 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Xml;
+import android.provider.Settings;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ContentValues;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.view.InflateException;
 import com.android.settingslib.drawer.Tile;
 import com.android.settingslib.drawer.TileUtils;
@@ -42,6 +48,12 @@
     // If defined, only returns this suggestion if the feature is supported.
     public static final String META_DATA_REQUIRE_FEATURE = "com.android.settings.require_feature";
 
+    // If defined, only display this optional step if an account of that type exists.
+    private static final String META_DATA_REQUIRE_ACCOUNT = "com.android.settings.require_account";
+
+    // If defined and not true, do not should optional step.
+    private static final String META_DATA_IS_SUPPORTED = "com.android.settings.is_supported";
+
     /**
      * Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
      * For instance:
@@ -110,7 +122,10 @@
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
                 addCache, null, suggestions, true, false);
         for (int i = countBefore; i < suggestions.size(); i++) {
-            if (!isAvailable(suggestions.get(i)) || isDismissed(suggestions.get(i))) {
+            if (!isAvailable(suggestions.get(i)) ||
+                    !isSupported(suggestions.get(i)) ||
+                    !satisfiesRequiredAccount(suggestions.get(i)) ||
+                    isDismissed(suggestions.get(i))) {
                 suggestions.remove(i--);
             }
         }
@@ -124,7 +139,10 @@
                     item = last;
                 }
             }
-            suggestions.add(item);
+            // If category is marked as done, do not add any item.
+            if (!isCategoryDone(category.category)) {
+                suggestions.add(item);
+            }
         }
     }
 
@@ -136,6 +154,41 @@
         return true;
     }
 
+    public boolean satisfiesRequiredAccount(Tile suggestion) {
+        String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
+        if (requiredAccountType == null) {
+            return true;
+        }
+        AccountManager accountManager = AccountManager.get(mContext);
+        Account[] accounts = accountManager.getAccountsByType(requiredAccountType);
+        return accounts.length > 0;
+    }
+
+    public boolean isSupported(Tile suggestion) {
+        int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
+        try {
+            if (suggestion.intent == null) {
+                return false;
+            }
+            final Resources res = mContext.getPackageManager().getResourcesForActivity(
+                    suggestion.intent.getComponent());
+            return isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Cannot find resources for " + suggestion.intent.getComponent());
+            return false;
+        }
+    }
+
+    public boolean isCategoryDone(String category) {
+        String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
+        return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
+    }
+
+    public void markCategoryDone(String category) {
+        String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
+        Settings.Secure.putInt(mContext.getContentResolver(), name, 1);
+    }
+
     private boolean isDismissed(Tile suggestion) {
         Object dismissObj = suggestion.metaData.get(META_DATA_DISMISS_CONTROL);
         if (dismissObj == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index fa2226d..586f269 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -112,20 +112,26 @@
     }
 
     public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
-        final Intent intent = batteryChangedIntent;
+        return Utils.getBatteryStatus(res, batteryChangedIntent, false);
+    }
 
-        int plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
-        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
+    public static String getBatteryStatus(Resources res, Intent batteryChangedIntent,
+            boolean shortString) {
+        int plugType = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+        int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
                 BatteryManager.BATTERY_STATUS_UNKNOWN);
         String statusString;
         if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
             int resId;
             if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
-                resId = R.string.battery_info_status_charging_ac;
+                resId = shortString ? R.string.battery_info_status_charging_ac_short
+                        : R.string.battery_info_status_charging_ac;
             } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
-                resId = R.string.battery_info_status_charging_usb;
+                resId = shortString ? R.string.battery_info_status_charging_usb_short
+                        : R.string.battery_info_status_charging_usb;
             } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
-                resId = R.string.battery_info_status_charging_wireless;
+                resId = shortString ? R.string.battery_info_status_charging_wireless_short
+                        : R.string.battery_info_status_charging_wireless;
             } else {
                 resId = R.string.battery_info_status_charging;
             }
@@ -151,10 +157,17 @@
         if (sSystemSignature == null) {
             sSystemSignature = new Signature[]{ getSystemSignature(pm) };
         }
-        return sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg));
+        if (sPermissionControllerPackageName == null) {
+            sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
+        }
+        return (sSystemSignature[0] != null
+                        && sSystemSignature[0].equals(getFirstSignature(pkg)))
+                || (sPermissionControllerPackageName != null
+                        && sPermissionControllerPackageName.equals(pkg.packageName));
     }
 
     private static Signature[] sSystemSignature;
+    private static String sPermissionControllerPackageName;
 
     private static Signature getFirstSignature(PackageInfo pkg) {
         if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 99bd4ad..fcff305 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -22,6 +22,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -40,12 +41,21 @@
             new TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
 
     /**
-     * @return the set of enabled accessibility services. If there are not services
-     * it returned the unmodifiable {@link Collections#emptySet()}.
+     * @return the set of enabled accessibility services. If there are no services,
+     * it returns the unmodifiable {@link Collections#emptySet()}.
      */
     public static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
-        final String enabledServicesSetting = Settings.Secure.getString(
-                context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+        return getEnabledServicesFromSettings(context, UserHandle.myUserId());
+    }
+
+    /**
+     * @return the set of enabled accessibility services for {@param userId}. If there are no
+     * services, it returns the unmodifiable {@link Collections#emptySet()}.
+     */
+    public static Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) {
+        final String enabledServicesSetting = Settings.Secure.getStringForUser(
+                context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userId);
         if (enabledServicesSetting == null) {
             return Collections.emptySet();
         }
@@ -77,11 +87,22 @@
         return langContext.getText(resId);
     }
 
+    /**
+     * Changes an accessibility component's state.
+     */
     public static void setAccessibilityServiceState(Context context, ComponentName toggledService,
             boolean enabled) {
+        setAccessibilityServiceState(context, toggledService, enabled, UserHandle.myUserId());
+    }
+
+    /**
+     * Changes an accessibility component's state for {@param userId}.
+     */
+    public static void setAccessibilityServiceState(Context context, ComponentName toggledService,
+            boolean enabled, int userId) {
         // Parse the enabled services.
         Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
-                context);
+                context, userId);
 
         if (enabledServices.isEmpty()) {
             enabledServices = new ArraySet<>(1);
@@ -121,13 +142,9 @@
         if (enabledServicesBuilderLength > 0) {
             enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
         }
-        Settings.Secure.putString(context.getContentResolver(),
+        Settings.Secure.putStringForUser(context.getContentResolver(),
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                enabledServicesBuilder.toString());
-
-        // Update accessibility enabled.
-        Settings.Secure.putInt(context.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0);
+                enabledServicesBuilder.toString(), userId);
     }
 
     private static Set<ComponentName> getInstalledServices(Context context) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 6226b23..6052ccd 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -24,12 +24,14 @@
 import android.bluetooth.BluetoothMap;
 import android.bluetooth.BluetoothInputDevice;
 import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothPbapClient;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
 import android.content.Intent;
 import android.os.ParcelUuid;
 import android.util.Log;
+import com.android.settingslib.R;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -82,7 +84,9 @@
     private final HidProfile mHidProfile;
     private OppProfile mOppProfile;
     private final PanProfile mPanProfile;
+    private PbapClientProfile mPbapClientProfile;
     private final PbapServerProfile mPbapProfile;
+    private final boolean mUsePbapPce;
 
     /**
      * Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -99,6 +103,7 @@
         mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mEventManager = eventManager;
+        mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
         // pass this reference to adapter and event manager (circular dependency)
         mLocalAdapter.setProfileManager(this);
         mEventManager.setProfileManager(this);
@@ -205,9 +210,24 @@
         } else if (mOppProfile != null) {
             Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
         }
+
+        //PBAP Client
+        if (mUsePbapPce) {
+            if (mPbapClientProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile");
+                mPbapClientProfile = new PbapClientProfile(mContext, mLocalAdapter, mDeviceManager,
+                        this);
+                addProfile(mPbapClientProfile, PbapClientProfile.NAME,
+                        BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mPbapClientProfile != null) {
+            Log.w(TAG,
+                "Warning: PBAP Client profile was previously added but the UUID is now missing.");
+        }
+
         mEventManager.registerProfileIntentReceiver();
 
-        // There is no local SDP record for HID and Settings app doesn't control PBAP
+        // There is no local SDP record for HID and Settings app doesn't control PBAP Server.
     }
 
     private final Collection<ServiceListener> mServiceListeners =
@@ -351,6 +371,10 @@
         }
     }
 
+    public PbapClientProfile getPbapClientProfile() {
+        return mPbapClientProfile;
+    }
+
     public PbapServerProfile getPbapProfile(){
         return mPbapProfile;
     }
@@ -430,6 +454,12 @@
             removedProfiles.remove(mMapProfile);
             mMapProfile.setPreferred(device, true);
         }
-    }
 
+        if (mUsePbapPce) {
+            profiles.add(mPbapClientProfile);
+            removedProfiles.remove(mPbapClientProfile);
+            profiles.remove(mPbapProfile);
+            removedProfiles.add(mPbapProfile);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
new file mode 100755
index 0000000..d7c9eab
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+final class PbapClientProfile implements LocalBluetoothProfile {
+    private static final String TAG = "PbapClientProfile";
+    private static boolean V = false;
+
+    private BluetoothPbapClient mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+
+    static final ParcelUuid[] SRC_UUIDS = {
+        BluetoothUuid.PBAP_PSE,
+    };
+
+    static final String NAME = "PbapClient";
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 6;
+
+    // These callbacks run on the main thread.
+    private final class PbapClientServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) {
+                Log.d(TAG,"Bluetooth service connected");
+            }
+            mService = (BluetoothPbapClient) proxy;
+            // We just bound to the service, so refresh the UI for any connected PBAP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "PbapClientProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(PbapClientProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady = true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) {
+                Log.d(TAG,"Bluetooth service disconnected");
+            }
+            mIsProfileReady = false;
+        }
+    }
+
+    private void refreshProfiles() {
+        Collection<CachedBluetoothDevice> cachedDevices = mDeviceManager.getCachedDevicesCopy();
+        for (CachedBluetoothDevice device : cachedDevices) {
+            device.onUuidChanged();
+        }
+    }
+
+    public boolean pbapClientExists() {
+        return (mService != null);
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    PbapClientProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new PbapClientServiceListener(),
+                BluetoothProfile.PBAP_CLIENT);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) {
+            return new ArrayList<BluetoothDevice>(0);
+        }
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (V) {
+            Log.d(TAG,"PBAPClientProfile got connect request");
+        }
+        if (mService == null) {
+            return false;
+        }
+        List<BluetoothDevice> srcs = getConnectedDevices();
+        if (srcs != null) {
+            for (BluetoothDevice src : srcs) {
+                if (src.equals(device)) {
+                    // Connect to same device, Ignore it
+                    Log.d(TAG,"Ignoring Connect");
+                    return true;
+                }
+            }
+            for (BluetoothDevice src : srcs) {
+                mService.disconnect(device);
+            }
+        }
+        Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
+
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (V) {
+            Log.d(TAG,"PBAPClientProfile got disconnect request");
+        }
+        if (mService == null) {
+            return false;
+        }
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) {
+            return false;
+        }
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.PRIORITY_OFF;
+        }
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) {
+            return;
+        }
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        // we need to have same string in UI as the server side.
+        return R.string.bluetooth_profile_pbap;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        return R.string.bluetooth_profile_pbap_summary;
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_cellphone;
+    }
+
+    protected void finalize() {
+        if (V) {
+            Log.d(TAG, "finalize()");
+        }
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
+                    BluetoothProfile.PBAP_CLIENT,mService);
+                mService = null;
+            } catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up PBAP Client proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 3b818c8..0e3e0d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -60,7 +60,7 @@
 public class StorageMeasurement {
     private static final String TAG = "StorageMeasurement";
 
-    private static final boolean LOCAL_LOGV = true;
+    private static final boolean LOCAL_LOGV = false;
     static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE);
 
     private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
new file mode 100644
index 0000000..78d7c56
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.display;
+
+import com.android.settingslib.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.util.Arrays;
+
+/**
+ * Utility methods for working with display density.
+ */
+public class DisplayDensityUtils {
+    private static final String LOG_TAG = "DisplayDensityUtils";
+
+    /** Minimum increment between density scales. */
+    private static final float MIN_SCALE_INTERVAL = 0.09f;
+
+    /** Minimum density scale. This is available on all devices. */
+    private static final float MIN_SCALE = 0.85f;
+
+    /** Maximum density scale. The actual scale used depends on the device. */
+    private static final float MAX_SCALE = 1.50f;
+
+    /** Summary used for "default" scale. */
+    public static final int SUMMARY_DEFAULT = R.string.screen_zoom_summary_default;
+
+    /** Summary used for "custom" scale. */
+    private static final int SUMMARY_CUSTOM = R.string.screen_zoom_summary_custom;
+
+    /**
+     * Summaries for scales smaller than "default" in order of smallest to
+     * largest.
+     */
+    private static final int[] SUMMARIES_SMALLER = new int[] {
+            R.string.screen_zoom_summary_small
+    };
+
+    /**
+     * Summaries for scales larger than "default" in order of smallest to
+     * largest.
+     */
+    private static final int[] SUMMARIES_LARGER = new int[] {
+            R.string.screen_zoom_summary_large,
+            R.string.screen_zoom_summary_very_large,
+            R.string.screen_zoom_summary_extremely_large,
+    };
+
+    /**
+     * Minimum allowed screen dimension, corresponds to resource qualifiers
+     * "small" or "sw320dp". This value must be at least the minimum screen
+     * size required by the CDD so that we meet developer expectations.
+     */
+    private static final int MIN_DIMENSION_DP = 320;
+
+    private final String[] mEntries;
+    private final int[] mValues;
+
+    private final int mDefaultDensity;
+    private final int mCurrentIndex;
+
+    public DisplayDensityUtils(Context context) {
+        final int defaultDensity = DisplayDensityUtils.getDefaultDisplayDensity(
+                Display.DEFAULT_DISPLAY);
+        if (defaultDensity <= 0) {
+            mEntries = null;
+            mValues = null;
+            mDefaultDensity = 0;
+            mCurrentIndex = -1;
+            return;
+        }
+
+        final Resources res = context.getResources();
+        final DisplayMetrics metrics = res.getDisplayMetrics();
+        final int currentDensity = metrics.densityDpi;
+        int currentDensityIndex = -1;
+
+        // Compute number of "larger" and "smaller" scales for this display.
+        final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
+        final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
+        final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) defaultDensity);
+        final float minScale = MIN_SCALE;
+        final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
+                0, SUMMARIES_LARGER.length);
+        final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
+                0, SUMMARIES_SMALLER.length);
+
+        String[] entries = new String[1 + numSmaller + numLarger];
+        int[] values = new int[entries.length];
+        int curIndex = 0;
+
+        if (numSmaller > 0) {
+            final float interval = (1 - minScale) / numSmaller;
+            for (int i = numSmaller - 1; i >= 0; i--) {
+                // Round down to a multiple of 2 by truncating the low bit.
+                final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1;
+                if (currentDensity == density) {
+                    currentDensityIndex = curIndex;
+                }
+                entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
+                values[curIndex] = density;
+                curIndex++;
+            }
+        }
+
+        if (currentDensity == defaultDensity) {
+            currentDensityIndex = curIndex;
+        }
+        values[curIndex] = defaultDensity;
+        entries[curIndex] = res.getString(SUMMARY_DEFAULT);
+        curIndex++;
+
+        if (numLarger > 0) {
+            final float interval = (maxScale - 1) / numLarger;
+            for (int i = 0; i < numLarger; i++) {
+                // Round down to a multiple of 2 by truncating the low bit.
+                final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1;
+                if (currentDensity == density) {
+                    currentDensityIndex = curIndex;
+                }
+                values[curIndex] = density;
+                entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
+                curIndex++;
+            }
+        }
+
+        final int displayIndex;
+        if (currentDensityIndex >= 0) {
+            displayIndex = currentDensityIndex;
+        } else {
+            // We don't understand the current density. Must have been set by
+            // someone else. Make room for another entry...
+            int newLength = values.length + 1;
+            values = Arrays.copyOf(values, newLength);
+            values[curIndex] = currentDensity;
+
+            entries = Arrays.copyOf(entries, newLength);
+            entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
+
+            displayIndex = curIndex;
+        }
+
+        mDefaultDensity = defaultDensity;
+        mCurrentIndex = displayIndex;
+        mEntries = entries;
+        mValues = values;
+    }
+
+    public String[] getEntries() {
+        return mEntries;
+    }
+
+    public int[] getValues() {
+        return mValues;
+    }
+
+    public int getCurrentIndex() {
+        return mCurrentIndex;
+    }
+
+    public int getDefaultDensity() {
+        return mDefaultDensity;
+    }
+
+    /**
+     * Returns the default density for the specified display.
+     *
+     * @param displayId the identifier of the display
+     * @return the default density of the specified display, or {@code -1} if
+     *         the display does not exist or the density could not be obtained
+     */
+    private static int getDefaultDisplayDensity(int displayId) {
+       try {
+           final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+           return wm.getInitialDisplayDensity(displayId);
+       } catch (RemoteException exc) {
+           return -1;
+       }
+    }
+
+    /**
+     * Asynchronously applies display density changes to the specified display.
+     *
+     * @param displayId the identifier of the display to modify
+     */
+    public static void clearForcedDisplayDensity(final int displayId) {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                    wm.clearForcedDisplayDensity(displayId);
+                } catch (RemoteException exc) {
+                    Log.w(LOG_TAG, "Unable to clear forced display density setting");
+                }
+            }
+        });
+    }
+
+    /**
+     * Asynchronously applies display density changes to the specified display.
+     *
+     * @param displayId the identifier of the display to modify
+     * @param density the density to force for the specified display
+     */
+    public static void setForcedDisplayDensity(final int displayId, final int density) {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                    wm.setForcedDisplayDensity(displayId, density);
+                } catch (RemoteException exc) {
+                    Log.w(LOG_TAG, "Unable to save forced display density setting");
+                }
+            }
+        });
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 1c032fa..ff70190 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -18,6 +18,7 @@
 import android.annotation.LayoutRes;
 import android.annotation.Nullable;
 import android.app.Activity;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -40,6 +41,7 @@
 import android.widget.ListView;
 import android.widget.Toolbar;
 import com.android.settingslib.R;
+import com.android.settingslib.applications.InterestingConfigChanges;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -54,6 +56,7 @@
 
     private static List<DashboardCategory> sDashboardCategories;
     private static HashMap<Pair<String, String>, Tile> sTileCache;
+    private static InterestingConfigChanges sConfigTracker;
 
     private final PackageReceiver mPackageReceiver = new PackageReceiver();
     private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
@@ -68,16 +71,18 @@
 
         long startTime = System.currentTimeMillis();
 
-        getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-        getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
-        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
+        if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
+            getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            requestWindowFeature(Window.FEATURE_NO_TITLE);
+        }
         super.setContentView(R.layout.settings_with_drawer);
         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
         if (mDrawerLayout == null) {
             return;
         }
         Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
-        TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
         if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
             toolbar.setVisibility(View.GONE);
             mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
@@ -100,16 +105,6 @@
     }
 
     @Override
-    public void onBackPressed() {
-        if (mShowingMenu) {
-            // If we are showing the menu, then we are a top level activity and the back should
-            // kick back to settings home.
-            openTile(null);
-        }
-        super.onBackPressed();
-    }
-
-    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
                 && mDrawerAdapter.getCount() != 0) {
@@ -160,8 +155,10 @@
             mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
             updateDrawer();
         } else {
-            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
-            mDrawerLayout = null;
+            if (mDrawerLayout != null) {
+                mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+                mDrawerLayout = null;
+            }
         }
     }
 
@@ -179,8 +176,11 @@
 
     @Override
     public void setContentView(@LayoutRes int layoutResID) {
-        LayoutInflater.from(this).inflate(layoutResID,
-                (ViewGroup) findViewById(R.id.content_frame));
+        final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
+        if (parent != null) {
+            parent.removeAllViews();
+        }
+        LayoutInflater.from(this).inflate(layoutResID, parent);
     }
 
     @Override
@@ -215,6 +215,7 @@
     public List<DashboardCategory> getDashboardCategories() {
         if (sDashboardCategories == null) {
             sTileCache = new HashMap<>();
+            sConfigTracker = new InterestingConfigChanges();
             sDashboardCategories = TileUtils.getCategories(this, sTileCache);
         }
         return sDashboardCategories;
@@ -235,20 +236,24 @@
                     Intent.FLAG_ACTIVITY_CLEAR_TASK));
             return true;
         }
-        int numUserHandles = tile.userHandle.size();
-        if (numUserHandles > 1) {
-            ProfileSelectDialog.show(getFragmentManager(), tile);
-            return false;
-        } else if (numUserHandles == 1) {
-            // Show menu on top level items.
-            tile.intent.putExtra(EXTRA_SHOW_MENU, true);
-            tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            startActivityAsUser(tile.intent, tile.userHandle.get(0));
-        } else {
-            // Show menu on top level items.
-            tile.intent.putExtra(EXTRA_SHOW_MENU, true);
-            tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            startActivity(tile.intent);
+        try {
+            int numUserHandles = tile.userHandle.size();
+            if (numUserHandles > 1) {
+                ProfileSelectDialog.show(getFragmentManager(), tile);
+                return false;
+            } else if (numUserHandles == 1) {
+                // Show menu on top level items.
+                tile.intent.putExtra(EXTRA_SHOW_MENU, true);
+                tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                startActivityAsUser(tile.intent, tile.userHandle.get(0));
+            } else {
+                // Show menu on top level items.
+                tile.intent.putExtra(EXTRA_SHOW_MENU, true);
+                tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                startActivity(tile.intent);
+            }
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "Couldn't find tile " + tile.intent, e);
         }
         return true;
     }
@@ -270,6 +275,9 @@
     private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
         @Override
         protected List<DashboardCategory> doInBackground(Void... params) {
+            if (sConfigTracker.applyNewConfig(getResources())) {
+                sTileCache.clear();
+            }
             return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 2dfdfda..418b138 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -41,7 +41,7 @@
 public class TileUtils {
 
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_TIMING = true;
+    private static final boolean DEBUG_TIMING = false;
 
     private static final String LOG_TAG = "TileUtils";
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
index 530ec16..1fff0fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
@@ -43,6 +43,7 @@
     private final Paint mDottedPaint;
 
     private final Drawable mDivider;
+    private final Drawable mTintedDivider;
     private final int mDividerSize;
 
     private final Path mPath = new Path();
@@ -51,6 +52,7 @@
     private final SparseIntArray mPaths = new SparseIntArray();
     // Paths in local coordinates for drawing.
     private final SparseIntArray mLocalPaths = new SparseIntArray();
+    private final int mCornerRadius;
 
     private int mAccentColor;
     private boolean mShowProjection;
@@ -59,6 +61,10 @@
     private float mMaxX = 100;
     private float mMaxY = 100;
 
+    private float mMiddleDividerLoc = .5f;
+    private int mMiddleDividerTint = -1;
+    private int mTopDividerTint = -1;
+
     public UsageGraph(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         final Resources resources = context.getResources();
@@ -68,8 +74,8 @@
         mLinePaint.setStrokeCap(Cap.ROUND);
         mLinePaint.setStrokeJoin(Join.ROUND);
         mLinePaint.setAntiAlias(true);
-        mLinePaint.setPathEffect(new CornerPathEffect(resources.getDimensionPixelSize(
-                R.dimen.usage_graph_line_corner_radius)));
+        mCornerRadius = resources.getDimensionPixelSize(R.dimen.usage_graph_line_corner_radius);
+        mLinePaint.setPathEffect(new CornerPathEffect(mCornerRadius));
         mLinePaint.setStrokeWidth(resources.getDimensionPixelSize(R.dimen.usage_graph_line_width));
 
         mFillPaint = new Paint(mLinePaint);
@@ -86,6 +92,7 @@
         TypedValue v = new TypedValue();
         context.getTheme().resolveAttribute(com.android.internal.R.attr.listDivider, v, true);
         mDivider = context.getDrawable(v.resourceId);
+        mTintedDivider = context.getDrawable(v.resourceId);
         mDividerSize = resources.getDimensionPixelSize(R.dimen.usage_graph_divider_size);
     }
 
@@ -98,6 +105,15 @@
         mMaxY = maxY;
     }
 
+    void setDividerLoc(int height) {
+        mMiddleDividerLoc = 1 - height / mMaxY;
+    }
+
+    void setDividerColors(int middleColor, int topColor) {
+        mMiddleDividerTint = middleColor;
+        mTopDividerTint = topColor;
+    }
+
     public void addPath(SparseIntArray points) {
         for (int i = 0; i < points.size(); i++) {
             mPaths.put(points.keyAt(i), points.valueAt(i));
@@ -150,7 +166,7 @@
                 if (mLocalPaths.size() > 0) {
                     int lastX = mLocalPaths.keyAt(mLocalPaths.size() - 1);
                     int lastY = mLocalPaths.valueAt(mLocalPaths.size() - 1);
-                    if (lastY != PATH_DELIM && (lastX == lx || lastY == ly)) {
+                    if (lastY != PATH_DELIM && !hasDiff(lastX, lx) && !hasDiff(lastY, ly)) {
                         pendingYLoc = ly;
                         continue;
                     }
@@ -160,6 +176,10 @@
         }
     }
 
+    private boolean hasDiff(int x1, int x2) {
+        return Math.abs(x2 - x1) >= mCornerRadius;
+    }
+
     private int getX(float x) {
         return (int) (x / mMaxX * getWidth());
     }
@@ -180,9 +200,12 @@
     @Override
     protected void onDraw(Canvas canvas) {
         // Draw lines across the top, middle, and bottom.
-        drawDivider(0, canvas);
-        drawDivider((canvas.getHeight() - mDividerSize) / 2, canvas);
-        drawDivider(canvas.getHeight() - mDividerSize, canvas);
+        if (mMiddleDividerLoc != 0) {
+            drawDivider(0, canvas, mTopDividerTint);
+        }
+        drawDivider((int) ((canvas.getHeight() - mDividerSize) * mMiddleDividerLoc), canvas,
+                mMiddleDividerTint);
+        drawDivider(canvas.getHeight() - mDividerSize, canvas, -1);
 
         if (mLocalPaths.size() == 0) {
             return;
@@ -242,8 +265,13 @@
         canvas.drawPath(mPath, mFillPaint);
     }
 
-    private void drawDivider(int y, Canvas canvas) {
-        mDivider.setBounds(0, y, canvas.getWidth(), y + mDividerSize);
-        mDivider.draw(canvas);
+    private void drawDivider(int y, Canvas canvas, int tintColor) {
+        Drawable d = mDivider;
+        if (tintColor != -1) {
+            mTintedDivider.setTint(tintColor);
+            d = mTintedDivider;
+        }
+        d.setBounds(0, y, canvas.getWidth(), y + mDividerSize);
+        d.draw(canvas);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
index f95a97a..ee1821d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
@@ -20,6 +20,7 @@
 import android.util.SparseIntArray;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -98,6 +99,26 @@
         mUsageGraph.setAccentColor(color);
     }
 
+    public void setDividerLoc(int dividerLoc) {
+        mUsageGraph.setDividerLoc(dividerLoc);
+    }
+
+    public void setDividerColors(int middleColor, int topColor) {
+        mUsageGraph.setDividerColors(middleColor, topColor);
+    }
+
+    public void setSideLabelWeights(float before, float after) {
+        setWeight(R.id.space1, before);
+        setWeight(R.id.space2, after);
+    }
+
+    private void setWeight(int id, float weight) {
+        View v = findViewById(id);
+        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) v.getLayoutParams();
+        params.weight = weight;
+        v.setLayoutParams(params);
+    }
+
     public void setSideLabels(CharSequence[] labels) {
         if (labels.length != mLabels.length) {
             throw new IllegalArgumentException("Invalid number of labels");
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 5b8ed28..380fcd4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -110,6 +110,7 @@
     private final Context mContext;
 
     private String ssid;
+    private String bssid;
     private int security;
     private int networkId = WifiConfiguration.INVALID_NETWORK_ID;
 
@@ -335,6 +336,10 @@
         return ssid;
     }
 
+    public String getBssid() {
+        return bssid;
+    }
+
     public CharSequence getSsid() {
         SpannableString str = new SpannableString(ssid);
         str.setSpan(new TtsSpan.VerbatimBuilder(ssid).build(), 0, ssid.length(),
@@ -657,6 +662,7 @@
         else
             ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
 
+        bssid = config.BSSID;
         security = getSecurity(config);
         networkId = config.networkId;
         mConfig = config;
@@ -664,6 +670,7 @@
 
     private void initWithScanResult(ScanResult result) {
         ssid = result.SSID;
+        bssid = result.BSSID;
         security = getSecurity(result);
         if (security == SECURITY_PSK)
             pskType = getPskType(result);
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index ba991fb..6c06d05 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -9,8 +9,8 @@
                  android:backupAgent="SettingsBackupAgent"
                  android:killAfterRestore="false"
                  android:icon="@mipmap/ic_launcher_settings"
-                 android:forceDeviceEncrypted="true"
-                 android:encryptionAware="true">
+                 android:defaultToDeviceProtectedStorage="true"
+                 android:directBootAware="true">
 
         <provider android:name="SettingsProvider"
                   android:authorities="settings"
diff --git a/packages/SettingsProvider/res/values-be-rBY/defaults.xml b/packages/SettingsProvider/res/values-be-rBY/defaults.xml
new file mode 100644
index 0000000..4a87a12
--- /dev/null
+++ b/packages/SettingsProvider/res/values-be-rBY/defaults.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * 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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+    <string name="def_device_name_simple" msgid="9037785625140748221">"%1$s"</string>
+    <string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-be-rBY/strings.xml b/packages/SettingsProvider/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..c164ac7
--- /dev/null
+++ b/packages/SettingsProvider/res/values-be-rBY/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label" msgid="4567566098528588863">"Захоўванне налад"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-bs-rBA/defaults.xml b/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
index 5650077..4a87a12 100644
--- a/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
+++ b/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
@@ -19,9 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- no translation found for def_device_name (6309317409634339402) -->
-    <skip />
-    <!-- no translation found for def_device_name_simple (9037785625140748221) -->
-    <skip />
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+    <string name="def_device_name_simple" msgid="9037785625140748221">"%1$s"</string>
     <string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-bs-rBA/strings.xml b/packages/SettingsProvider/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..464a29f
--- /dev/null
+++ b/packages/SettingsProvider/res/values-bs-rBA/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label" msgid="4567566098528588863">"Postavke za pohranu podataka"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 51d8ca0..978ca94 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -155,6 +155,9 @@
     <!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS -->
     <integer name="def_long_press_timeout_millis">500</integer>
 
+    <!-- Default for Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD -->
+    <bool name="def_show_ime_with_hard_keyboard">false</bool>
+
     <!-- Default for Settings.System.POINTER_SPEED -->
     <integer name="def_pointer_speed">0</integer>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index d89abf42..b79ce80 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -62,8 +62,9 @@
      */
     private static final ArraySet<String> sBroadcastOnRestore;
     static {
-        sBroadcastOnRestore = new ArraySet<String>(3);
+        sBroadcastOnRestore = new ArraySet<String>(4);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+        sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS);
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 57d495f..61c9f2b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -21,6 +21,7 @@
 import android.app.AppGlobals;
 import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentProvider;
 import android.content.ContentValues;
 import android.content.Context;
@@ -49,6 +50,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SELinux;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -62,6 +64,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.providers.settings.SettingsState.Setting;
+import com.android.server.SystemConfig;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -457,8 +460,28 @@
 
     @Override
     public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
-        throw new FileNotFoundException("Direct file access no longer supported; "
-                + "ringtone playback is available through android.media.Ringtone");
+        final String cacheName;
+        if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
+            cacheName = Settings.System.RINGTONE_CACHE;
+        } else if (Settings.System.NOTIFICATION_SOUND_CACHE_URI.equals(uri)) {
+            cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
+        } else if (Settings.System.ALARM_ALERT_CACHE_URI.equals(uri)) {
+            cacheName = Settings.System.ALARM_ALERT_CACHE;
+        } else {
+            throw new FileNotFoundException("Direct file access no longer supported; "
+                    + "ringtone playback is available through android.media.Ringtone");
+        }
+
+        final File cacheFile = new File(
+                getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
+        return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode));
+    }
+
+    private File getRingtoneCacheDir(int userId) {
+        final File cacheDir = new File(Environment.getDataSystemDeDirectory(userId), "ringtones");
+        cacheDir.mkdir();
+        SELinux.restorecon(cacheDir);
+        return cacheDir;
     }
 
     @Override
@@ -901,6 +924,21 @@
             return false;
         }
 
+        // Invalidate any relevant cache files
+        String cacheName = null;
+        if (Settings.System.RINGTONE.equals(name)) {
+            cacheName = Settings.System.RINGTONE_CACHE;
+        } else if (Settings.System.NOTIFICATION_SOUND.equals(name)) {
+            cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
+        } else if (Settings.System.ALARM_ALERT.equals(name)) {
+            cacheName = Settings.System.ALARM_ALERT_CACHE;
+        }
+        if (cacheName != null) {
+            final File cacheFile = new File(
+                    getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
+            cacheFile.delete();
+        }
+
         // Mutate the value.
         synchronized (mLock) {
             switch (operation) {
@@ -1092,10 +1130,15 @@
 
     private PackageInfo getCallingPackageInfoOrThrow(int userId) {
         try {
-            return mPackageManager.getPackageInfo(getCallingPackage(), 0, userId);
+            PackageInfo packageInfo = mPackageManager.getPackageInfo(
+                    getCallingPackage(), 0, userId);
+            if (packageInfo != null) {
+                return packageInfo;
+            }
         } catch (RemoteException e) {
-            throw new IllegalStateException("Calling package doesn't exist");
+            /* ignore */
         }
+        throw new IllegalStateException("Calling package doesn't exist");
     }
 
     private int getGroupParentLocked(int userId) {
@@ -1630,16 +1673,16 @@
 
         private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
                 SQLiteDatabase database, int userId) {
-            // Move over the global settings if owner.
-            if (userId == UserHandle.USER_SYSTEM) {
-                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
-                ensureSettingsStateLocked(globalKey);
-                SettingsState globalSettings = mSettingsStates.get(globalKey);
-                migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
-                globalSettings.persistSyncLocked();
-            }
+            // Move over the system settings.
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            ensureSettingsStateLocked(systemKey);
+            SettingsState systemSettings = mSettingsStates.get(systemKey);
+            migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
+            systemSettings.persistSyncLocked();
 
             // Move over the secure settings.
+            // Do this after System settings, since this is the first thing we check when deciding
+            // to skip over migration from db to xml for a secondary user.
             final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
             ensureSettingsStateLocked(secureKey);
             SettingsState secureSettings = mSettingsStates.get(secureKey);
@@ -1647,12 +1690,16 @@
             ensureSecureSettingAndroidIdSetLocked(secureSettings);
             secureSettings.persistSyncLocked();
 
-            // Move over the system settings.
-            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
-            ensureSettingsStateLocked(systemKey);
-            SettingsState systemSettings = mSettingsStates.get(systemKey);
-            migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
-            systemSettings.persistSyncLocked();
+            // Move over the global settings if owner.
+            // Do this last, since this is the first thing we check when deciding
+            // to skip over migration from db to xml for owner user.
+            if (userId == UserHandle.USER_SYSTEM) {
+                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
+                ensureSettingsStateLocked(globalKey);
+                SettingsState globalSettings = mSettingsStates.get(globalKey);
+                migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
+                globalSettings.persistSyncLocked();
+            }
 
             // Drop the database as now all is moved and persisted.
             if (DROP_DATABASE_ON_MIGRATION) {
@@ -1895,7 +1942,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 124;
+            private static final int SETTINGS_VERSION = 126;
 
             private final int mUserId;
 
@@ -2075,6 +2122,51 @@
                     currentVersion = 124;
                 }
 
+                if (currentVersion == 124) {
+                    // Version 124: allow OEMs to set a default value for whether IME should be
+                    // shown when a physical keyboard is connected.
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    Setting currentSetting = secureSettings.getSettingLocked(
+                            Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+                    if (currentSetting == null) {
+                        secureSettings.insertSettingLocked(
+                                Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
+                                getContext().getResources().getBoolean(
+                                        R.bool.def_show_ime_with_hard_keyboard) ? "1" : "0",
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 125;
+                }
+
+                if (currentVersion == 125) {
+                    // Version 125: Allow OEMs to set the default VR service.
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+
+                    Setting currentSetting = secureSettings.getSettingLocked(
+                            Settings.Secure.ENABLED_VR_LISTENERS);
+                    if (currentSetting == null) {
+                        ArraySet<ComponentName> l =
+                                SystemConfig.getInstance().getDefaultVrComponents();
+
+                        if (l != null && !l.isEmpty()) {
+                            StringBuilder b = new StringBuilder();
+                            boolean start = true;
+                            for (ComponentName c : l) {
+                                if (!start) {
+                                    b.append(':');
+                                }
+                                b.append(c.flattenToString());
+                                start = false;
+                            }
+                            secureSettings.insertSettingLocked(
+                                    Settings.Secure.ENABLED_VR_LISTENERS, b.toString(),
+                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                        }
+
+                    }
+                    currentVersion = 126;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 // Return the current version.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 5b865f9..b557dc4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -113,8 +113,8 @@
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
 
     <application android:label="@string/app_label"
-                 android:forceDeviceEncrypted="true"
-                 android:encryptionAware="true">
+                 android:defaultToDeviceProtectedStorage="true"
+                 android:directBootAware="true">
         <provider
             android:name="android.support.v4.content.FileProvider"
             android:authorities="com.android.shell"
@@ -139,7 +139,7 @@
 
         <activity
             android:name=".BugreportWarningActivity"
-            android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+            android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true"
             android:exported="false" />
diff --git a/packages/Shell/res/layout/dialog_bugreport_info.xml b/packages/Shell/res/layout/dialog_bugreport_info.xml
index 5d1e9f9..bb3084f 100644
--- a/packages/Shell/res/layout/dialog_bugreport_info.xml
+++ b/packages/Shell/res/layout/dialog_bugreport_info.xml
@@ -16,28 +16,44 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:paddingTop="15dp"
+    android:paddingStart="24dp"
+    android:paddingEnd="24dp"
+    android:focusableInTouchMode="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
+    <TextView
+        android:inputType="textNoSuggestions"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/bugreport_info_name"/>
     <EditText
         android:id="@+id/name"
         android:maxLength="30"
         android:singleLine="true"
         android:inputType="textNoSuggestions"
         android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+    <TextView
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:hint="@string/bugreport_info_name"/>
+        android:text="@string/bugreport_info_title"/>
     <EditText
         android:id="@+id/title"
         android:maxLength="80"
         android:singleLine="true"
+        android:inputType="textAutoCorrect|textCapSentences"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+    <TextView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:hint="@string/bugreport_info_title"/>
+        android:editable="false"
+        android:text="@string/bugreport_info_description"/>
     <EditText
         android:id="@+id/description"
         android:singleLine="false"
-        android:inputType="textMultiLine"
+        android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="@string/bugreport_info_description"/>
+        android:layout_height="wrap_content"/>
 </LinearLayout>
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index 9d399c1..8dbe3cd 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Tuisskerm"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Foutverslag <xliff:g id="ID">#%d</xliff:g> word tans geskep"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Foutverslag <xliff:g id="ID">#%d</xliff:g> is vasgevang"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Foutverslag <xliff:g id="ID">#%d</xliff:g> vasgevang, maar skermkiekie hangende"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Voeg tans besonderhede by die foutverslag"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Wag asseblief …"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swiep na links om jou foutverslag te deel"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tik om jou foutverslag te deel"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tik om jou foutverslag sonder \'n skermkiekie te deel, of wag totdat die skermkiekie gereed is"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tik om jou foutverslag sonder \'n skermkiekie te deel, of wag totdat die skermkiekie gereed is"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Foutverslae bevat data van die stelsel se verskillende loglêers af, insluitend persoonlike en private inligting. Deel foutverslae net met programme en mense wat jy vertrou."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Wys hierdie boodskap volgende keer"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Foutverslae"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Foutverslag <xliff:g id="ID">#%d</xliff:g> se besonderhede"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Lêernaam"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beskrywing"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Fouttitel"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Foutopsomming"</string>
+    <string name="save" msgid="4781509040564835759">"Stoor"</string>
 </resources>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index 2545222..b0d3de0 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"ቀፎ"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> እየተመነጨ ነው"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ተወስዷል"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ፎቶ ተነስቷል፣ ነገር ግን ቅጽበታዊ ገጽ ማያ በመጠባበቅ ላይ ነው"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ዝርዝሮችን ወደ የሳንካ ሪፖርቱ በማከል ላይ"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"እባክዎ ይጠብቁ…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"የሳንካ ሪፖርትዎን ለማጋራት ወደ ግራ ያንሸራትቱ"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"የሳንካ ሪፖርትዎን ለማጋራት መታ ያድርጉ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"የእርስዎን የሳንካ ሪፖርት ያለ ቅጽበታዊ ማያ ገጽ ለማጋራት መታ ያድርጉ ወይም ቅጽበታዊ ማያ ገጹ እስኪጨርስ ይጠብቁ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"የእርስዎን የሳንካ ሪፖርት ያለ ቅጽበታዊ ማያ ገጽ ለማጋራት መታ ያድርጉ ወይም ቅጽበታዊ ማያ ገጹ እስኪጨርስ ይጠብቁ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"የሳንካ ሪፖርቶች የግል መረጃን ጨምሮ ከበርካታ የስርዓቱ ምዝግብ ማስታወሻዎች የመጣ ውሂብን ይዟል። የሳንካ ሪፖርቶች ለሚያምኗቸው መተግበሪያዎችን እና ሰዎችን ብቻ ያጋሩ።"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ይህን መልዕክት በሚቀጥለው ጊዜ አሳይ"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"የሳንካ ሪፖርቶች"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ዝርዝሮች"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"የፋይል ስም"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ርዕስ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ዝርዝር መግለጫ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"የሳንካ ርዕስ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"የሳንካ ማጠቃለያ"</string>
+    <string name="save" msgid="4781509040564835759">"አስቀምጥ"</string>
 </resources>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index 7593110..818c368 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"جارٍ إنشاء تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>."</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"تم تسجيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>."</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"تم التقاط تقرير الأخطاء <xliff:g id="ID">#%d</xliff:g> ولكن في انتظار لقطة الشاشة"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"إضافة تفاصيل إلى تقرير الخطأ"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"الرجاء الانتظار…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"مرر بسرعة لليمين لمشاركة تقرير الخطأ"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"انقر لمشاركة تقرير الخطأ."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"انقر لمشاركة تقرير الأخطاء بدون لقطة شاشة أو انتظر حتى انتهاء لقطة الشاشة"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"انقر لمشاركة تقرير الأخطاء بدون لقطة شاشة أو انتظر حتى انتهاء لقطة الشاشة"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"تحتوي تقارير الأخطاء على بيانات من ملفات سجلات النظام المتنوعة، بما في ذلك معلومات شخصية وخاصة. لا تشارك تقارير الأخطاء إلا مع التطبيقات والأشخاص الموثوق بهم."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"إظهار هذه الرسالة في المرة القادمة"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"تقارير الأخطاء"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"تفاصيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"اسم الملف"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"العنوان"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"وصف تفصيلي"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"عنوان الخطأ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ملخص الخطأ"</string>
+    <string name="save" msgid="4781509040564835759">"حفظ"</string>
 </resources>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index 9130255..22791a6 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> yaradıldı"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> alındı"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"<xliff:g id="ID">#%d</xliff:g> baq hesabatı çəkildi, amma skrinşot hələ gözlənilir"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Detallar baq hesabatına əlavə olunur"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfən, gözləyin..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Baq raportunu paylaşmaq üçün sola sürüşdürün"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Baq hesabatınızı paylaşmaq üçün tıklayın"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"baq hesabatınızı skrinşot olmadan paylaşmaq üçün tıklayın, skrinşotun tamamlanması üçün isə gözləyin"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"baq hesabatınızı skrinşot olmadan paylaşmaq üçün tıklayın, skrinşotun tamamlanması üçün isə gözləyin"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Baq raportları sistemin müxtəlif jurnal fayllarından data içərir ki, buna şəxsi və konfidensial məlumatlar da aiddir. Yalnız inandığınız adamlarla baq raportlarını paylaşın."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bu mesajı növbəti dəfə göstər"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Baq hesabatları"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Displey görüntüsü əlçatan deyil."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> detalları"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fayl adı"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Başlıq"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Ətraflı təsvir"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Baq başlığı"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Baq xülasə"</string>
+    <string name="save" msgid="4781509040564835759">"Yadda saxlayın"</string>
 </resources>
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index 597e545..bc5ce26 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Izveštaj o grešci <xliff:g id="ID">#%d</xliff:g> se generiše"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Izveštaj o grešci <xliff:g id="ID">#%d</xliff:g> je snimljen"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Izveštaj o grešci <xliff:g id="ID">#%d</xliff:g> snimljen; snimak ekrana se čeka"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaju se detalji u izveštaj o grešci"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Sačekajte..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prevucite ulevo da biste delili izveštaj o greškama"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste delili izveštaj o grešci"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite za deljenje izveštaja o grešci bez snimka ekrana ili sačekajte da se napravi snimak ekrana"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite za deljenje izveštaja o grešci bez snimka ekrana ili sačekajte da se napravi snimak ekrana"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Izveštaji o greškama sadrže podatke iz različitih sistemskih datoteka evidencije, uključujući lične i privatne podatke. Delite izveštaje o greškama samo sa aplikacijama i ljudima u koje imate poverenja."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži ovu poruku sledeći put"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Izveštaji o greškama"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje ekrana nije uspelo."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izveštaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljni opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov greške"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Rezime greške"</string>
+    <string name="save" msgid="4781509040564835759">"Sačuvaj"</string>
 </resources>
diff --git a/packages/Shell/res/values-be-rBY/strings.xml b/packages/Shell/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..5aaa80a
--- /dev/null
+++ b/packages/Shell/res/values-be-rBY/strings.xml
@@ -0,0 +1,43 @@
+<?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.
+ -->
+
+<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">"Абалонка"</string>
+    <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Справаздача <xliff:g id="ID">#%d</xliff:g> пра памылку генерыруецца"</string>
+    <string name="bugreport_finished_title" msgid="4429132808670114081">"Справаздача <xliff:g id="ID">#%d</xliff:g> пра памылку зафіксавана"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Справ. пра памылку <xliff:g id="ID">#%d</xliff:g> зафікс., але скрыншот чакаецца"</string>
+    <string name="bugreport_updating_title" msgid="4423539949559634214">"Дадаванне падрабязнасцей да справаздачы пра памылкі"</string>
+    <string name="bugreport_updating_wait" msgid="3322151947853929470">"Калі ласка, пачакайце..."</string>
+    <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Правядзіце пальцам налева, каб абагуліць сваю справаздачу пра памылку"</string>
+    <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Дакраніцеся, каб абагуліць сваю справаздачу пра памылку"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Справаздача пра памылку ўтрымлівае дадзеныя з гiсторыi сістэмных файлаў, у тым ліку персанальную і прыватную інфармацыю. Дзялiцеся справаздачамi пра збоi толькi з праверанымi карыстальнiкамi i прыкладаннямi."</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"У наступны раз паказваць гэта паведамленне"</string>
+    <string name="bugreport_storage_title" msgid="5332488144740527109">"Справадзачы пра памылкі"</string>
+    <string name="bugreport_unreadable_text" msgid="586517851044535486">"Немагчыма прачытаць файл справаздачы пра памылкі"</string>
+    <string name="bugreport_unnamed" msgid="2800582406842092709">"без назвы"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Падрабязнасці"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Здымак экрана"</string>
+    <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Здымак экрана зроблены паспяхова."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Немагчыма зрабіць здымак экрана."</string>
+    <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Падрабязныя звесткі аб справаздачы <xliff:g id="ID">#%d</xliff:g> пра памылку"</string>
+    <string name="bugreport_info_name" msgid="4414036021935139527">"Назва файла"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Назва справаздачы пра памылкі"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Зводка справаздачы пра памылкі"</string>
+    <string name="save" msgid="4781509040564835759">"Захаваць"</string>
+</resources>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index 6ca7914..0f8676f 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Команден ред"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Сигналът за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“ се генерира"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Сигналът за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“ е заснет"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Сигналът (<xliff:g id="ID">#%d</xliff:g>) е заснет, но екр. снимка не е готова"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Подробностите се добавят към сигнала за пр. грешка"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Моля, изчакайте…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Прекарайте пръст наляво, за да споделите сигнала си за програмна грешка"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Докоснете, за да споделите сигнала си за програмна грешка"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Докоснете, за да споделите сигнала за прогр. грешка без екранна снимка, или изчакайте завършването й"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Докоснете, за да споделите сигнала за прогр. грешка без екранна снимка, или изчакайте завършването й"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Отчетите за програмни грешки съдържат данни от различни регистрационни файлове на системата, включително лична и поверителна информация. Споделяйте ги само с приложения и хора, на които имате доверие."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Това съобщение да се показва следващия път"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Отчети за прогр. грешки"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Подробности за сигнала за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Име на файла"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Заглавие"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Подробно описание"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Заглавие на сигнала за програмна грешка"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Обобщена информация за сигнала за програмна грешка"</string>
+    <string name="save" msgid="4781509040564835759">"Запазване"</string>
 </resources>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index 5390315..c632b10 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"শেল"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> তৈরি করা হচ্ছে"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> ক্যাপচার করা হয়েছে"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> ক্যাপচার করা হয়েছে কিন্তু স্ক্রীনশট নেওয়ার কাজ সম্পন্ন হয়নি"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ত্রুটির প্রতিবেদনে বিশদ বিবরণ যোগ করা হচ্ছে"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"অনুগ্রহ করে অপেক্ষা করুন..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"আপনার বাগ রিপোর্ট শেয়ার করতে বামে সোয়াইপ করুন"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"আপনার ত্রুটির প্রতিবেদন শেয়ার করতে আলতো চাপ দিন"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"কোনো স্ক্রীনশট ছাড়াই ত্রুটির প্রতিবেদন শেয়ার করতে আলতো চাপ দিন বা সম্পন্ন করতে স্ক্রীনশটের জন্য অপেক্ষা করুন"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"কোনো স্ক্রীনশট ছাড়াই ত্রুটির প্রতিবেদন শেয়ার করতে আলতো চাপ দিন বা সম্পন্ন করতে স্ক্রীনশটের জন্য অপেক্ষা করুন"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ত্রুটির প্রতিবেদনগুলিতে থাকা ডেটা, সিস্টেমের বিভিন্ন লগ ফাইলগুলি থেকে আসে, যাতে ব্যক্তিগত এবং গোপনীয় তথ্য অন্তর্ভুক্ত থাকে৷ আপনি বিশ্বাস করেন শুধুমাত্র এমন অ্যাপ্লিকেশান এবং ব্যক্তিদের সাথে ত্রুটির প্রতিবেদনগুলি ভাগ করুন৷"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"এই বার্তাটি পরের বার দেখান"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"ত্রুটির প্রতিবেদনগুলি"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> এর বিশদ বিবরণ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ফাইলের নাম"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"শীর্ষক"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"বিস্তারিত বিবরণ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ত্রুটির শীর্ষক"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ত্রুটির সারাংশ"</string>
+    <string name="save" msgid="4781509040564835759">"সংরক্ষণ করুন"</string>
 </resources>
diff --git a/packages/Shell/res/values-bs-rBA/strings.xml b/packages/Shell/res/values-bs-rBA/strings.xml
index 903c2ab..f4d71e9 100644
--- a/packages/Shell/res/values-bs-rBA/strings.xml
+++ b/packages/Shell/res/values-bs-rBA/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Ljuska"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Izvještaj o grešci <xliff:g id="ID">#%d</xliff:g> se generira"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Izvještaj o grešci <xliff:g id="ID">#%d</xliff:g> je snimljen"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Izvještaj o greškama <xliff:g id="ID">#%d</xliff:g> snimljen, čeka se snim. ekr."</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Dodavanje detalja u izvještaj o greškama"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Pričekajte..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prevucite lijevo da podijelite izvještaj o greškama"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste podijelili izvještaj o grešci"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite da podijelite izveštaj o greškama bez snimka ekrana ili sačekajte da snimak bude gotov"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite da podijelite izveštaj o greškama bez snimka ekrana ili sačekajte da snimak bude gotov"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Izvještaji o greškama sadrže podatke iz raznih zapisnika sistema, uključujući lične i privatne informacije. Podijelite izvještaje o greškama samo sa aplikacijama i osobama kojima vjerujete."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaži ovu poruku sljedeći put"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Izvještaji o greškama"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran nije moguće snimiti."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izvještaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Naziv fajla"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov greške"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sažetak greške"</string>
+    <string name="save" msgid="4781509040564835759">"Sačuvaj"</string>
 </resources>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 0836946..3efb53b 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Protecció"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"S\'està generant l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"S\'ha capturat l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"L\'informe d\'errors <xliff:g id="ID">#%d</xliff:g> s\'ha capturat (captura pendent)"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"S\'estan afegint detalls a l\'informe d\'errors"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Llisca cap a l\'esquerra per compartir l\'informe d\'errors."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca per compartir l\'informe d\'errors"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toca per compartir l\'informe d\'errors sense captura de pantalla o espera que es creï la captura"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toca per compartir l\'informe d\'errors sense captura de pantalla o espera que es creï la captura"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Els informes d\'error contenen dades dels diferents fitxers de registre del sistema, inclosa informació privada i personal. Comparteix els informes d\'error només amb les aplicacions i amb les persones en qui confies."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra aquest missatge la propera vegada"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'error"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No s\'ha pogut fer la captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalls de l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nom del fitxer"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Títol"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descripció detallada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Títol de l\'error"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resum d\'errors"</string>
+    <string name="save" msgid="4781509040564835759">"Desa"</string>
 </resources>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index 215ec87..afb6f9e 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Zpráva o chybě <xliff:g id="ID">#%d</xliff:g> se vytváří"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Zpráva o chybě <xliff:g id="ID">#%d</xliff:g> byla vytvořena"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Zpráva o chybě <xliff:g id="ID">#%d</xliff:g> byla vytvořena, čeká se na snímek"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Přidávání podrobností do zprávy o chybě"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Čekejte prosím…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Chcete-li hlášení chyby sdílet, přejeďte doleva."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Zprávu o chybě můžete sdílet klepnutím"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Klepnutím můžete zprávu o chybě sdílet bez snímku obrazovky, nebo vyčkejte, než se snímek připraví"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Klepnutím můžete zprávu o chybě sdílet bez snímku obrazovky, nebo vyčkejte, než se snímek připraví"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Chybová hlášení obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Chybová hlášení sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobrazit tuto zprávu příště"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Zprávy o chybách"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímek obrazovky se nepodařilo pořídit."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti zprávy o chybě <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Název souboru"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Název"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Název chyby"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Přehled chyby"</string>
+    <string name="save" msgid="4781509040564835759">"Uložit"</string>
 </resources>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index e956d3a..0f7b784 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Fejlrapporten <xliff:g id="ID">#%d</xliff:g> genereres"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Fejrapporten <xliff:g id="ID">#%d</xliff:g> blev gemt"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Fejlrapport <xliff:g id="ID">#%d</xliff:g> blev gemt, men skærmbilledet afventer"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Tilføjelse af oplysninger til fejlrapporten"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent et øjeblik…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Stryg til venstre for at dele din fejlrapport"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tryk for at dele din fejlrapport"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tryk for at dele din fejlrapport uden et skærmbillede, eller vent på, at skærmbilledet fuldføres"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tryk for at dele din fejlrapport uden et skærmbillede, eller vent på, at skærmbilledet fuldføres"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Fejlrapporter indeholder data fra systemets forskellige logfiler, f.eks. personlige og private oplysninger. Del kun fejlrapporter med apps og personer, du har tillid til."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne underretning næste gang"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Fejlrapporter"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Der kunne ikke tages et skærmbillede."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Oplysninger om fejlrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljeret beskrivelse"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Fejlrapportens titel"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Oversigt over fejl"</string>
+    <string name="save" msgid="4781509040564835759">"Gem"</string>
 </resources>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index 07f8898..8f87fed 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Fehlerbericht <xliff:g id="ID">#%d</xliff:g> wird generiert"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Fehlerbericht <xliff:g id="ID">#%d</xliff:g> erfasst"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Fehlerbericht <xliff:g id="ID">#%d</xliff:g> erfasst, aber Screenshot ausstehend"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Informationen werden zum Fehlerbericht hinzugefügt"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Bitte warten…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Wische nach links, um deinen Fehlerbericht zu teilen."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Zum Teilen des Fehlerberichts tippen"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tippe, um den Fehlerbericht ohne Screenshot zu teilen, oder warte auf den Screenshot"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tippe, um den Fehlerbericht ohne Screenshot zu teilen, oder warte auf den Screenshot"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Fehlerberichte enthalten Daten aus verschiedenen Protokolldateien des Systems, darunter auch personenbezogene und private Daten. Teile Fehlerberichte nur mit Apps und Personen, denen du vertraust."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Diese Nachricht nächstes Mal zeigen"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Fehlerberichte"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot konnte nicht aufgenommen werden."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details zum Fehlerbericht <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Dateiname"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaillierte Beschreibung"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titel des Programmfehlers"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Zusammenfassung des Programmfehlers"</string>
+    <string name="save" msgid="4781509040564835759">"Speichern"</string>
 </resources>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 6746976..517d83a 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Κέλυφος"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Δημιουργείται η αναφορά σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Έγινε λήψη της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Η αναφ. σφάλματος <xliff:g id="ID">#%d</xliff:g> ελήφθη, αλλά το στιγμ. εκκρεμεί"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Προσθήκη λεπτομερειών στην αναφορά σφάλματος"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Περιμένετε…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Σύρετε προς τα αριστερά για κοινή χρήση της αναφοράς σφαλμάτων"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Πατήστε για κοινή χρήση της αναφοράς σφάλματος"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Πατήστε για κοινοποίηση της αναφοράς σφάλματος χωρίς στιγμιότυπο οθόνης ή περιμένετε να ολοκληρωθεί"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Πατήστε για κοινοποίηση της αναφοράς σφάλματος χωρίς στιγμιότυπο οθόνης ή περιμένετε να ολοκληρωθεί"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Οι αναφορές σφαλμάτων περιέχουν δεδομένα από τα διάφορα αρχεία καταγραφής του συστήματος, συμπεριλαμβανομένων προσωπικών και ιδιωτικών πληροφοριών. Να μοιράζεστε αναφορές σφαλμάτων μόνο με εφαρμογές και άτομα που εμπιστεύεστε."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Εμφάνιση αυτού του μηνύματος την επόμενη φορά"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Αναφορές σφαλμάτων"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Λεπτομέρειες της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Όνομα αρχείου"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Τίτλος"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Αναλυτική περιγραφή"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Τίτλος σφάλματος"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Περίληψη σφάλματος"</string>
+    <string name="save" msgid="4781509040564835759">"Αποθήκευση"</string>
 </resources>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index ac681e2..2349ec5 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bug report <xliff:g id="ID">#%d</xliff:g> is being generated"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Bug report <xliff:g id="ID">#%d</xliff:g> captured"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Bug report <xliff:g id="ID">#%d</xliff:g> captured but screenshot pending"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tap to share your bug report"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tap to share your bug report without a screenshot or wait for the screenshot to finish"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tap to share your bug report without a screenshot or wait for the screenshot to finish"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+    <string name="save" msgid="4781509040564835759">"Save"</string>
 </resources>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index ac681e2..2349ec5 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bug report <xliff:g id="ID">#%d</xliff:g> is being generated"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Bug report <xliff:g id="ID">#%d</xliff:g> captured"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Bug report <xliff:g id="ID">#%d</xliff:g> captured but screenshot pending"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tap to share your bug report"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tap to share your bug report without a screenshot or wait for the screenshot to finish"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tap to share your bug report without a screenshot or wait for the screenshot to finish"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+    <string name="save" msgid="4781509040564835759">"Save"</string>
 </resources>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index ac681e2..2349ec5 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bug report <xliff:g id="ID">#%d</xliff:g> is being generated"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Bug report <xliff:g id="ID">#%d</xliff:g> captured"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Bug report <xliff:g id="ID">#%d</xliff:g> captured but screenshot pending"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tap to share your bug report"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tap to share your bug report without a screenshot or wait for the screenshot to finish"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tap to share your bug report without a screenshot or wait for the screenshot to finish"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+    <string name="save" msgid="4781509040564835759">"Save"</string>
 </resources>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index 96ca14c..307548a 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Se está generando el informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Se capturó el informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Informe de errores <xliff:g id="ID">#%d</xliff:g> capturado (captura pendiente)"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Agregando detalles al informe de errores"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de errores."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca para compartir el informe de errores"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toca para compartir tu informe de errores sin una captura de pantalla o espera a que finalice"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toca para compartir tu informe de errores sin una captura de pantalla o espera a que finalice"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida la información personal y privada. Comparte los informes de errores únicamente con aplicaciones y personas en las que confíes."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de errores"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se pudo tomar la captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nombre del archivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título del error"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumen del error"</string>
+    <string name="save" msgid="4781509040564835759">"Guardar"</string>
 </resources>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index 00874c6..730ae73 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Se está generando el informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Informe de errores <xliff:g id="ID">#%d</xliff:g> capturado"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Informe <xliff:g id="ID">#%d</xliff:g> registrado (captura pantalla pendiente)"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Añadiendo detalles al informe de errores"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de error"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca para compartir el informe de errores"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toca para compartir el informe de errores sin captura de pantalla o espera a que se haga la captura."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toca para compartir el informe de errores sin captura de pantalla o espera a que se haga la captura."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida información personal y privada. Comparte los informes de errores únicamente con aplicaciones y usuarios en los que confíes."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de error"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se puede realizar la captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nombre de archivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Nombre del informe de errores"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumen del informe de errores"</string>
+    <string name="save" msgid="4781509040564835759">"Guardar"</string>
 </resources>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index bc469bc..028e2bd 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Kest"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Luuakse veaaruannet <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Jäädvustati veaaruanne <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Jäädvustati veaaruanne <xliff:g id="ID">#%d</xliff:g>, kuid ekraanipilt on ootel"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Üksikasjade lisamine veaaruandesse"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Oodake …"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veaaruande jagamiseks pühkige vasakule"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Veaaruande jagamiseks puudutage"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Puudutage, et veaaruannet ilma ekraanipildita jagada, või oodake, kuni ekraanipilt tehtud saab."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Puudutage, et veaaruannet ilma ekraanipildita jagada, või oodake, kuni ekraanipilt tehtud saab."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Veaaruanded sisaldavad andmeid erinevatest süsteemi logifailidest, sh isiklikku ja privaatset teavet. Jagage veaaruandeid ainult usaldusväärsete rakenduste ja inimestega."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Kuva see sõnum järgmisel korral"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Veaaruanded"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Veaaruande <xliff:g id="ID">#%d</xliff:g> üksikasjad"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Faili nimi"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Pealkiri"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Üksikasjalik kirjeldus"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Vea pealkiri"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Vea kokkuvõte"</string>
+    <string name="save" msgid="4781509040564835759">"Salvesta"</string>
 </resources>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index 614f17e..7946f67 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell-interfazea"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostena egiten ari gara"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostena egin da"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Egin da <xliff:g id="ID">#%d</xliff:g> txostena. Pantaila-argazkia falta da."</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Akatsen txostenean xehetasunak gehitzen"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Itxaron, mesedez…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Programa-akatsen txostena partekatzeko, pasatu hatza ezkerrera"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Sakatu akatsen txostena partekatzeko"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Sakatu akatsen txostena argazkirik gabe partekatzeko edo itxaron pantaila-argazkia atera arte"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Sakatu akatsen txostena argazkirik gabe partekatzeko edo itxaron pantaila-argazkia atera arte"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Akatsen txostenek sistemaren erregistro-fitxategietako datuak dauzkate, informazio pertsonala eta pribatua barne. Akatsen txostenak partekatzen badituzu, partekatu soilik aplikazio eta pertsona fidagarriekin."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Erakutsi mezu hau hurrengoan"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Akatsen txostenak"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ezin izan da atera pantaila-argazkia."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostenaren xehetasunak"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fitxategi-izena"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Izena"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Azalpen xehatua"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Akatsaren izena"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Akatsaren laburpena"</string>
+    <string name="save" msgid="4781509040564835759">"Gorde"</string>
 </resources>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index ab00562..ecadf1a 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"گزارش اشکال <xliff:g id="ID">#%d</xliff:g> در حال ایجاد شدن است"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"گزارش اشکال <xliff:g id="ID">#%d</xliff:g> ثبت شد"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"گزارش اشکال <xliff:g id="ID">#%d</xliff:g> گرفته شد اما عکس از صفحه‌نمایش هنوز نه"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"اضافه کردن جزئیات به گزارش اشکال"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"لطفاً منتظر بمانید..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"برای اشتراک‌گذاری گزارش اشکال، به تندی آن را به چپ بکشید"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"برای به اشتراک گذاشتن گزارش اشکال، ضربه بزنید"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"برای اشتراک‌گذاری گزارش مشکل بدون عکس صفحه‌نمایش، ضربه بزنید یا صبر کنید تا عکس صفحه‌نمایش گرفته شود."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"برای اشتراک‌گذاری گزارش مشکل بدون عکس صفحه‌نمایش، ضربه بزنید یا صبر کنید تا عکس صفحه‌نمایش گرفته شود."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"گزارش‌های اشکال حاوی داده‌هایی از فایل‌های گزارش مختلف در سیستم هستند، شامل اطلاعات شخصی و خصوصی. گزارش‌های اشکال را فقط با افراد و برنامه‌های مورد اعتماد خود به اشتراک بگذارید."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"دفعه بعد این پیام نشان داده شود"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"گزارش اشکال"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمی‌توان عکس صفحه‌نمایش گرفت."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"جزئیات گزارش اشکال <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"نام فایل"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"جزئیات دقیق"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"عنوان اشکال"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"خلاصه اشکال"</string>
+    <string name="save" msgid="4781509040564835759">"ذخیره کردن"</string>
 </resources>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index be7aabd..b5ae006 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Komentotulkki"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Luodaan virheraporttia <xliff:g id="ID">#%d</xliff:g>."</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Virheraportti <xliff:g id="ID">#%d</xliff:g> tallennettu"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Virheraportti <xliff:g id="ID">#%d</xliff:g> tallennettu, kuvakaappaus odottaa."</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Lisätään tietoja virheraporttiin"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Odota…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Jaa virheraportti pyyhkäisemällä vasemmalle"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Jaa virheraportti napauttamalla."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Jaa virheraportti ilman kuvakaappausta napauttamalla tai odota, että kuvakaappaus latautuu."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Jaa virheraportti ilman kuvakaappausta napauttamalla tai odota, että kuvakaappaus latautuu."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Virheraportit sisältävät järjestelmän lokitietoja, ja niihin voi sisältyä henkilökohtaisia ja yksityisiä tietoja. Jaa virheraportteja vain luotettaville sovelluksille ja käyttäjille."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Näytä tämä viesti seuraavalla kerralla"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Virheraportit"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Virheraportin <xliff:g id="ID">#%d</xliff:g> tiedot"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Tiedostonimi"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Otsikko"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Yksityiskohtainen kuvaus"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Virheen nimi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Virheen yhteenveto"</string>
+    <string name="save" msgid="4781509040564835759">"Tallenna"</string>
 </resources>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index 7d9f97d..6c40edd 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Rapport de bogue <xliff:g id="ID">#%d</xliff:g> généré"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Rapport de bogue <xliff:g id="ID">#%d</xliff:g> enregistré"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Rap. bogue <xliff:g id="ID">#%d</xliff:g> enreg., mais attente de saisie d\'écran"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Ajout de détails au rapport de bogue"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Veuillez patienter…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport de bogue."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Touchez ici pour partager votre rapport de bogue"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Touchez pour partager le rapport de bogue sans saisie d\'écran ou attendez que la saisie soit prête"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Touchez pour partager le rapport de bogue sans saisie d\'écran ou attendez que la saisie soit prête"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bogue qu\'avec les applications et les personnes que vous estimez fiables."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports de bogues"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Une erreur s\'est produite lors de la saisie d\'écran."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Détails du rapport de bogue <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titre du bogue"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sommaire des bogues"</string>
+    <string name="save" msgid="4781509040564835759">"Enregistrer"</string>
 </resources>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index 74025d9..54f0b98 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\" est en cours de création"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\" a bien été enregistré"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Rapport bug \"<xliff:g id="ID">#%d</xliff:g>\" enregistré, mais attente capt. écran"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Ajout d\'informations au rapport de bug"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Veuillez patienter…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport d\'erreur."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Appuyer pour partager votre rapport de bug"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Appuyer pour partager rapport de bug sans capture d\'écran ou attendre finalisation capture d\'écran"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Appuyer pour partager rapport de bug sans capture d\'écran ou attendre finalisation capture d\'écran"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bug contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bug qu\'avec les applications et les personnes que vous estimez fiables."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports d\'erreur"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossible d\'effectuer une capture d\'écran."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Informations sur le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\""</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titre du bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Résumé du bug"</string>
+    <string name="save" msgid="4781509040564835759">"Enregistrer"</string>
 </resources>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index d3be7c5..d4610977b 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Estase xerando o informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Rexistrouse o informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Inf. erros <xliff:g id="ID">#%d</xliff:g> rexistrado e captura pantalla pendente"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Engadindo detalles ao informe de erro"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Agarda..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Pasa o dedo á esquerda para compartir o teu informe de erros"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca para compartir o teu informe de erros"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toca para compartir o informe de erros sen captura de pantalla ou agarda a que finalice a captura"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toca para compartir o informe de erros sen captura de pantalla ou agarda a que finalice a captura"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Os informes de erros conteñen datos dos distintos ficheiros de rexistro do sistema, incluída información persoal e privada. Comparte os informes de erros unicamente con aplicacións e persoas de confianza."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensaxe a próxima vez"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de erros"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Non se puido realizar a captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles do informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrición detallada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do informe de erros"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do informe de erros"</string>
+    <string name="save" msgid="4781509040564835759">"Gardar"</string>
 </resources>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 45df7b3..f99167d 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"શેલ"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> જનરેટ કરવામાં આવી રહી છે"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> કૅપ્ચર કરી"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> કૅપ્ચર કરી પરંતુ સ્ક્રીનશૉટ બાકી છે"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"બગ રિપોર્ટમાં વિગતો ઉમેરવી"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"કૃપા કરીને રાહ જુઓ…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"તમારી બગ રિપોર્ટ શેર કરવા માટે ડાબે સ્વાઇપ કરો"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"તમારી બગ રિપોર્ટ શેર કરવા ટૅપ કરો"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"સ્ક્રીનશૉટ વગર અથવા સ્ક્રીનશૉટ સમાપ્ત થવાની રાહ જોયા વગર તમારી બગ રિપોર્ટ શેર કરવા ટૅપ કરો"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"સ્ક્રીનશૉટ વગર અથવા સ્ક્રીનશૉટ સમાપ્ત થવાની રાહ જોયા વગર તમારી બગ રિપોર્ટ શેર કરવા ટૅપ કરો"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"બગ રિપોર્ટ્સ વ્યક્તિગત અને ખાનગી માહિતી સહિત, સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે. બગ રિપોર્ટ્સ ફક્ત તમે વિશ્વાસ કરતા હો તે એપ્લિકેશનો અને લોકો સાથે જ શેર કરો."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"આગલી વખતે આ સંદેશ બતાવો"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"બગ રિપોર્ટ્સ"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> ની વિગતો"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ફાઇલનું નામ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"શીર્ષક"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"વિગતવાર વર્ણન"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"બગનું શીર્ષક"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"બગનો સારાંશ"</string>
+    <string name="save" msgid="4781509040564835759">"સાચવો"</string>
 </resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 8858bc3..aedec04 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"शेल"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> जेनरेट की जा रही है"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैप्चर की गई"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैप्चर की गई लेकिन स्क्रीनशॉट लंबित है"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"बग रिपोर्ट में विवरण जोड़े जा रहे हैं"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करें…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"अपनी बग रिपोर्ट साझा करने के लिए बाएं स्वाइप करें"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"अपनी बग रिपोर्ट साझा करने के लिए टैप करें"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"अपनी बग रिपोर्ट को बिना स्क्रीनशॉट साझा करने हेतु टैप करें या स्क्रीनशॉट पूरा होने की प्रतीक्षा करें"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"अपनी बग रिपोर्ट को बिना स्क्रीनशॉट साझा करने हेतु टैप करें या स्क्रीनशॉट पूरा होने की प्रतीक्षा करें"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय ऐप्स  और व्यक्तियों से ही साझा करें."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यह संदेश अगली बार दिखाएं"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्ट"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> के विवरण"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"फ़ाइल नाम"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत वर्णन"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"बग शीर्षक"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"बग सारांश"</string>
+    <string name="save" msgid="4781509040564835759">"सहेजें"</string>
 </resources>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index cb03f9c..462eb2a1 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Ljuska"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generira se izvješće o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Izvješće o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g> snimljeno"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Izvješće o pogrešci <xliff:g id="ID">#%d</xliff:g> snimljeno, ali se čeka snimka"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Dodavanje pojedinosti u izvješće o progr. pogrešci"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Pričekajte..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prijeđite prstom ulijevo da biste poslali izvješće o programskim pogreškama"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste podijelili izvješće o programskoj pogrešci"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite za dijeljenje izvješća o pogrešci bez snimke zaslona ili pričekajte da se izradi snimka"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite za dijeljenje izvješća o pogrešci bez snimke zaslona ili pričekajte da se izradi snimka"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Prijave programskih pogrešaka sadržavaju podatke iz različitih datoteka zapisnika sustava, uključujući osobne i privatne informacije. Prijave programskih pogrešaka dijelite samo s aplikacijama i osobama koje smatrate pouzdanima."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži tu poruku sljedeći put"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Izvj. o prog. pogreš."</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje zaslona nije uspjelo."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Pojedinosti izvješća o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov izvješća o programskoj pogrešci"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sažetak izvješća o programskoj pogrešci"</string>
+    <string name="save" msgid="4781509040564835759">"Spremi"</string>
 </resources>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 390cd2f..1f7f1fa 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Héj"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) létrehozása folyamatban"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) rögzítve"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) rögzítve – képernyőkép függőben"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Információk hozzáadása a hibajelentéshez"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Kérjük, várjon..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Húzza ujját balra a hibajelentés megosztásához"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Koppintson a hibajelentés megosztásához"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Koppintson ide, ha képernyőkép nélkül osztaná meg a hibajelentést, vagy várjon a képernyőképre."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Koppintson ide, ha képernyőkép nélkül osztaná meg a hibajelentést, vagy várjon a képernyőképre."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"A programhiba-jelentések a rendszer különféle naplófájljaiból származó adatokat tartalmaznak, köztük személyes és magánjellegű információkat is. Csak olyan alkalmazásokkal és személyekkel osszon meg programhiba-jelentéseket, amelyekben vagy akikben megbízik."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Üzenet mutatása legközelebb"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Hibajelentések"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nem sikerült elkészíteni a képernyőképet."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) részletei"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fájlnév"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Név"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Részletes leírás"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Hibajelentés címe"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Hibajelentés összefoglalója"</string>
+    <string name="save" msgid="4781509040564835759">"Mentés"</string>
 </resources>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 68478ab..c9351c2 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Խեցի"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցը ստեղծվում է"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցը գրանցվեց"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցը ստեղծվել է, սակայն էկրանի պատկերը դեռ չի ստացվել"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Տվյալների ավելացում վրիպակի զեկույցում"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Խնդրում ենք սպասել…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Սահեցրեք ձախ՝ սխալի հաշվետվությունը համօգտագործելու համար"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Հպեք՝ վրիպակի զեկույցը տրամադրելու համար"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց էկրանի պատկերի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Հպեք՝ վրիպակի զեկույցն առանց էկրանի պատկերի ուղարկելու համար կամ սպասեք էկրանի պատկերի ստեղծմանը"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մուտքի ֆայլերից, այդ թվում նաև անհատական ​​և գաղտնի տեղեկություններ: Վրիպակի զեկույցները կիսեք միայն այն հավելվածների և մարդկանց հետ, որոնց վստահում եք:"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Այս հաղորդագրությունը ցույց տալ հաջորդ անգամ"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Վրիպակների հաշվետվություններ"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցի մանրամասները"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Ֆայլի անունը"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Անվանումը"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Մանրամասն նկարագրություն"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Վրիպակի զեկույցի վերնագիրը"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Վրիպակի զեկույցի ամփոփագիրը"</string>
+    <string name="save" msgid="4781509040564835759">"Պահել"</string>
 </resources>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index 4416fc7..4bca166 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Kerangka"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Laporan bug <xliff:g id="ID">#%d</xliff:g> sedang dibuat"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Laporan bug <xliff:g id="ID">#%d</xliff:g> dijepret"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Laporan bug <xliff:g id="ID">#%d</xliff:g> dijepret, tetapi tangkapan layar belum selesai"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Menambahkan detail ke laporan bug"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Harap tunggu..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Gesek ke kiri untuk membagikan laporan bug Anda"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ketuk untuk membagikan laporan bug"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Ketuk untuk membagikan laporan bug tanpa tangkapan layar atau menunggu tangkapan layar selesai"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Ketuk untuk membagikan laporan bug tanpa tangkapan layar atau menunggu tangkapan layar selesai"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Laporan bug berisi data dari berbagai file log sistem, termasuk informasi pribadi dan rahasia. Hanya bagikan laporan bug dengan aplikasi dan orang yang Anda percaya."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tampilkan pesan ini lain kali"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan bug"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detail laporan bug <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nama file"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Judul"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Deskripsi detail"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Judul bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Ringkasan bug"</string>
+    <string name="save" msgid="4781509040564835759">"Simpan"</string>
 </resources>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index 0d43719..aedf3bc3 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Skipanalína"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Verið er að búa til villutilkynningu <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Villutilkynning <xliff:g id="ID">#%d</xliff:g> búin til"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Villuskýrsla <xliff:g id="ID">#%d</xliff:g> tilbúin en skjámynd í vinnslu"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Bætir upplýsingum við villutilkynningu"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Augnablik..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Strjúktu til vinstri til að deila villuskýrslunni"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ýttu til að deila villutilkynningunni"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Ýttu til að deila villutilkynningunni án skjámyndar eða hinkraðu þangað til skjámyndin er tilbúin"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Ýttu til að deila villutilkynningunni án skjámyndar eða hinkraðu þangað til skjámyndin er tilbúin"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Villutilkynningar innihalda gögn úr hinum ýmsu annálsskrám kerfisins, þ. á m. persónuleg gögn og trúnaðarupplýsingar. Deildu villutilkynningum eingöngu með forritum og fólki sem þú treystir."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Sýna þessi skilaboð næst"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Villutilkynningar"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekki tókst að taka skjámynd."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Upplýsingar villutilkynningar <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Skráarheiti"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titill"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Ítarleg lýsing"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Heiti villu"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Villusamantekt"</string>
+    <string name="save" msgid="4781509040564835759">"Vista"</string>
 </resources>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index fc9383a..5c4b8d3 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generazione segnalazione di bug <xliff:g id="ID">#%d</xliff:g> in corso"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Segnalazione di bug <xliff:g id="ID">#%d</xliff:g> acquisita"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Segnalazione bug <xliff:g id="ID">#%d</xliff:g> acquisita, screenshot in attesa"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Aggiunta di dettagli alla segnalazione di bug"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Scorri verso sinistra per condividere il rapporto sui bug"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tocca per condividere la segnalazione di bug"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tocca per inviare la segnalazione del bug senza screenshot o attendi che lo screenshot sia completo"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tocca per inviare la segnalazione del bug senza screenshot o attendi che lo screenshot sia completo"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Le segnalazioni di bug contengono dati da vari file di log del sistema, incluse informazioni personali e private. Condividi le segnalazioni di bug solo con app e persone attendibili."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra questo messaggio la prossima volta"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapporti sui bug"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossibile acquisire lo screenshot."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Dettagli sulla segnalazione di bug <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome file"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titolo"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrizione dettagliata"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titolo bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Riepilogo bug"</string>
+    <string name="save" msgid="4781509040564835759">"Salva"</string>
 </resources>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 335a2e8..6589c8b 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"מעטפת"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"יצירת הדוח על הבאג <xliff:g id="ID">#%d</xliff:g> מתבצעת"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"הדוח על הבאג <xliff:g id="ID">#%d</xliff:g> צולם"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"הדוח על הבאג <xliff:g id="ID">#%d</xliff:g> נוצר, אך צילום המסך בהמתנה"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"מוסיף פרטים לדוח על הבאג"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"המתן…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"החלק שמאלה כדי לשתף את דוח הבאגים"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"הקש כדי לשתף את הדוח על הבאג"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"הקש כדי לשתף את הדוח על הבאג ללא צילום מסך, או המתן להשלמת צילום המסך"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"הקש כדי לשתף את הדוח על הבאג ללא צילום מסך, או המתן להשלמת צילום המסך"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"דוחות על באגים כוללים נתונים מקובצי היומן השונים במערכת, כולל מידע אישי ופרטי. שתף דוחות באגים רק עם אפליקציות ואנשים שאתה סומך עליהם."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"הצג את ההודעה הזו בפעם הבאה"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"דוחות באגים"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"פרטי הדוח על הבאג <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"שם קובץ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"כותרת"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"תיאור מפורט"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"כותרת הבאג"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"סיכום הבאג"</string>
+    <string name="save" msgid="4781509040564835759">"שמור"</string>
 </resources>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index b98b05f..a6ff33e 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"シェル"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"バグレポート <xliff:g id="ID">#%d</xliff:g> の生成中"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"バグレポート <xliff:g id="ID">#%d</xliff:g> の記録完了"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"バグレポート <xliff:g id="ID">#%d</xliff:g> 記録完了: スクリーンショット待ち"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"バグレポートに詳細情報を追加しています"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"お待ちください…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"バグレポートを共有するには左にスワイプ"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"バグレポートを共有するにはタップします"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"タップしてバグレポートをスクリーンショットなしで共有するか、スクリーンショット完成までお待ちください"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"タップしてバグレポートをスクリーンショットなしで共有するか、スクリーンショット完成までお待ちください"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"バグレポートには、個人の非公開情報など、システムのさまざまなログファイルのデータが含まれます。共有する場合は信頼するアプリとユーザーのみを選択してください。"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"このメッセージを次回も表示する"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"バグレポート"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"バグレポート <xliff:g id="ID">#%d</xliff:g> の詳細"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ファイル名"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"タイトル"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"詳細説明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"バグのタイトル"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"バグの概要"</string>
+    <string name="save" msgid="4781509040564835759">"保存"</string>
 </resources>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index 24d83a4..119c360 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"გარეკანი"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g> გენერირდება"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g> აღბეჭდილია"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"ხარვეზის ანგარიში <xliff:g id="ID">#%d</xliff:g> მზადაა. იქმნება ეკრანის ანაბეჭდი"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ხარვეზის შესახებ ანგარიშს დეტალები ემატება"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"გთხოვთ, მოითმინოთ..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"გაასრიალეთ მარცხნივ თქვენი ხარვეზის შეტყობინების გასაზიარებლად"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"შეეხეთ ხარვეზების შესახებ ანგარიშის გასაზიარებლად"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"შეეხეთ ხარვეზის შესახებ ანგარიშის ეკრანის ანაბეჭდის გარეშე გასაზიარებლად, ან დაელოდეთ მის შექმნას"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"შეეხეთ ხარვეზის შესახებ ანგარიშის ეკრანის ანაბეჭდის გარეშე გასაზიარებლად, ან დაელოდეთ მის შექმნას"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ხარვეზის ანგარიშები მოიცავს მონაცემებს სხვადასხვა სისტემური ჟურნალის ფაილებიდან, მათ შორის პირად და კონფიდენციალურ ინფორმაციას."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"შემდგომში აჩვენე ეს შეტყობინება"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"შეცდომების ანგარიშები"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g>-ის დეტალები"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ფაილის სახელი"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"სათაური"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"დეტალური აღწერა"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"შეცდომის სათაური"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"შეცდომის რეზიუმე"</string>
+    <string name="save" msgid="4781509040564835759">"შენახვა"</string>
 </resources>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 5878b17..90028ca 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Қабыршық"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жасалуда"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жазып алынды"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жазып алынды, бірақ скриншот әлі сақталған жоқ"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Қате туралы есепке мәліметтер қосылуда"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Күте тұрыңыз…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Қате туралы есепті бөлісу үшін солға жанаңыз"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Қате туралы есепті бөлісу үшін түртіңіз"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Қате туралы есепті скриншотсыз бөлісу үшін түртіңіз немесе скриншот сақталып болғанша күтіңіз"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Қате туралы есепті скриншотсыз бөлісу үшін түртіңіз немесе скриншот сақталып болғанша күтіңіз"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Вирус туралы баянатта жүйеде тіркелген әртүрлі файлдар туралы деректер болады, оған жеке және құпия ақпарат та кіреді. Вирус баянаттарын сенімді қолданбалар және сенімді адамдармен ғана бөлісіңіз."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бұл хабарды келесі жолы көрсетіңіз"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Қате туралы баяндамалар"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі туралы мәліметтер"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Файл атауы"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Атауы"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Егжей-тегжейлі сипаттама"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Қатенің атауы"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Қате туралы жиынтық мәліметтер"</string>
+    <string name="save" msgid="4781509040564835759">"Сақтау"</string>
 </resources>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 9c95e98..d5fc400 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"សែល"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុសកំពុងត្រូវបានបង្កើត"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុសត្រូវបានថត"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"<xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុសត្រូវបានថត ប៉ុន្តែរូបថតអេក្រង់មិនទាន់បានថតនៅឡើយទេ"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"កំពុងបន្ថែមព័ត៌មានលម្អិតទៅរបាយការណ៍កំហុស"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"សូម​រង់ចាំ…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"អូស​ទៅ​ឆ្វេង​​ ដើម្បី​ចែក​រំលែក​របាយការណ៍​កំហុស​របស់​អ្នក"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ប៉ះដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ប៉ះដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នកដោយមិនចាំបាច់មានរូបថតអេក្រង់ ឬរង់ចាំការបញ្ចប់ការថតអេក្រង់"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ប៉ះដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នកដោយមិនចាំបាច់មានរូបថតអេក្រង់ ឬរង់ចាំការបញ្ចប់ការថតអេក្រង់"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"របាយការណ៍​កំហុស​រួមមាន​ឯកសារ​កំណត់​ហេតុ​ផ្សេងៗ​របស់​ប្រព័ន្ធ រួមមាន​ព័ត៌មាន​ផ្ទាល់ខ្លួន និង​ឯកជន។ ចែករំលែក​របាយការណ៍​កំហុស​ជា​មួយ​កម្មវិធី និង​មនុស្ស​ដែល​អ្នក​ទុក​ចិត្ត។"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"បង្ហាញ​សារ​នេះ​ពេល​ក្រោយ"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"រាយការណ៍ពីកំហុស"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ព័ត៌មានលម្អិតពី <xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុស"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ឈ្មោះ​ឯកសារ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ចំណងជើង"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ការពិពណ៌នាលម្អិត"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ចំណងជើងកំហុស"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"សង្ខេបកំហុស"</string>
+    <string name="save" msgid="4781509040564835759">"រក្សាទុក"</string>
 </resources>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index ce6f3c0..1331f7e 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"ಶೆಲ್"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ಅನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ಅನ್ನು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿಕೊಳ್ಳಲಾಗಿದೆ"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ಅನ್ನು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿಕೊಳ್ಳಲಾಗಿದೆ ಆದರೆ ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ಬಗ್ ವರದಿಗೆ ವಿವರಗಳನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ನಿಮ್ಮ ದೋಷ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಎಡಕ್ಕೆ ಸ್ವೈಪ್‌ ಮಾಡಿ"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ನಿಮ್ಮ ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಇಲ್ಲದೇ ನಿಮ್ಮ ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಟ್ಯಾಪ್ ಮಾಡಿ ಅಥವಾ ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಪೂರ್ತಿಯಾಗುವವರೆಗೂ ನಿರೀಕ್ಷಿಸಿ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಇಲ್ಲದೇ ನಿಮ್ಮ ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಟ್ಯಾಪ್ ಮಾಡಿ ಅಥವಾ ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಪೂರ್ತಿಯಾಗುವವರೆಗೂ ನಿರೀಕ್ಷಿಸಿ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ವೈಯಕ್ತಿಕ ಮತ್ತು ಖಾಸಗಿ ಮಾಹಿತಿಯು ಸೇರಿದಂತೆ, ಸಿಸ್ಟಂನ ಹಲವಾರು ಲಾಗ್ ಫೈಲ್‌ಗಳಿಂದ ಡೇಟಾವನ್ನು ದೋಷದ ವರದಿಗಳು ಒಳಗೊಂಡಿವೆ. ನೀವು ನಂಬುವಂತಹ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಜನರೊಂದಿಗೆ ಮಾತ್ರ ದೋಷದ ವರದಿಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ಈ ಸಂದೇಶವನ್ನು ಮುಂದಿನ ಬಾರಿ ತೋರಿಸಿ"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"ದೋಷ ವರದಿಗಳು"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ವಿವರಗಳು"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ಫೈಲ್‌ಹೆಸರು"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ಶೀರ್ಷಿಕೆ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ವಿವರವಾದ ವಿವರಣೆ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ಬಗ್ ಶೀರ್ಷಿಕೆ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ಬಗ್ ಸಾರಾಂಶ"</string>
+    <string name="save" msgid="4781509040564835759">"ಉಳಿಸು"</string>
 </resources>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 70df8e2..4c0a169 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"셸"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 생성 중"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 캡처됨"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"버그 신고 <xliff:g id="ID">#%d</xliff:g>이(가) 캡처되었으나 스크린샷 대기 중"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"세부정보를 버그 보고서에 추가"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"잠시 기다려 주세요..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"왼쪽으로 스와이프하여 버그 신고서를 공유하세요."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"버그 신고를 공유하려면 탭하세요."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"스크린샷 없이 버그 신고서를 공유하려면 탭하고 그렇지 않으면 스크린샷이 완료될 때까지 기다려 주세요."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"스크린샷 없이 버그 신고서를 공유하려면 탭하고 그렇지 않으면 스크린샷이 완료될 때까지 기다려 주세요."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"버그 신고서는 시스템의 다양한 로그 파일 데이터(예: 개인 및 비공개 정보)를 포함합니다. 신뢰할 수 있는 앱과 사용자에게만 버그 신고서를 공유하세요."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"다음에 이 메시지 표시"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"버그 신고"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 세부정보"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"파일 이름"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"제목"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"자세한 설명"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"버그 제목"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"버그 요약"</string>
+    <string name="save" msgid="4781509040564835759">"저장"</string>
 </resources>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index 49d8d8d..16a9549 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Командалык кабык"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Мүчүлүштүк тууралуу билдирүү <xliff:g id="ID">#%d</xliff:g> түзүлүүдө"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Мүчүлүштүк тууралуу билдирүү <xliff:g id="ID">#%d</xliff:g> жаздырылды"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Мүчүлүштүк тууралуу билдирүү <xliff:g id="ID">#%d</xliff:g> даяр, скриншот күтүлүүдө"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Мүчүлүштүк жөнүндө кабардын чоо-жайы кошулууда"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Күтө туруңуз…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ката жөнүндө кабар менен бөлүшүү үчүн солго серпип коюңуз"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Мүчүлүштүк тууралуу билдирүүңүздү бөлүшүү үчүн таптап коюңуз"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Ката тууралуу билдирүүлөр системанын ар кандай лог файлдарынын берилиштерин камтыйт, аларга өздүк жана купуя маалыматтар дагы кирет. Ката тууралуу билдирүүлөрдү сиз ишенген колдонмолор жана адамдар менен гана бөлүшүңүз."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бул билдирүү кийин көрсөтүлсүн"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоолор"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Мүчүлүштүк тууралуу билдирүүнүн <xliff:g id="ID">#%d</xliff:g> чоо-жайы"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Файлдын аталышы"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Аталышы"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Кененирээк маалымат"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Мүчүлүштүктүн аталышы"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Мүчүлүштүк корутундусу"</string>
+    <string name="save" msgid="4781509040564835759">"Сактоо"</string>
 </resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index 61b06c8..2804528 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ກຳລັງສ້າງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"ບັນທຶກລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g> ແລ້ວ"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"ບັນທຶກລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g> ແລ້ວແຕ່ກຳລັງລໍຖ້າຮູບໜ້າຈໍຢູ່"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ກຳລັງເພີ່ມລາຍລະອຽດໃສ່ລາຍງານຂໍ້ຜິດພາດ"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"ກະລຸນາລໍຖ້າ..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"​ປັດ​ໄປ​ຊ້າຍ​ເພື່ອ​ສົ່ງ​ລາຍ​ງານ​ຂໍ້​ຜິດ​ພາດ​ຂອງ​ທ່ານ"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ແຕະເພື່ອແບ່ງປັນລາຍງານຂໍ້ຜິດພາດຂອງທ່ານ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ແຕະເພື່ອແບ່ງປັນລາຍງານຂໍ້ຜິດພາດຂອງທ່ານໂດຍບໍ່ໃຊ້ຮູບໜ້າຈໍ ຫຼື ລໍຖ້າໃຫ້ຮູບໜ້າຈໍແລ້ວໆ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ແຕະເພື່ອແບ່ງປັນລາຍງານຂໍ້ຜິດພາດຂອງທ່ານໂດຍບໍ່ໃຊ້ຮູບໜ້າຈໍ ຫຼື ລໍຖ້າໃຫ້ຮູບໜ້າຈໍແລ້ວໆ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ການລາຍງານຂໍ້ຜິດພາດປະກອບມີ ຂໍ້ມູນຈາກໄຟລ໌ບັນທຶກຂອງລະບົບຫຼາຍໄຟລ໌, ຮວມທັງຂໍ້ມູນສ່ວນໂຕນຳ. ທ່ານຕ້ອງແບ່ງປັນລາຍງານຂໍ້ຜິດພາດໃຫ້ແອັບຯ ແລະຄົນທີ່ທ່ານເຊື່ອຖືໄດ້ເທົ່ານັ້ນ."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ສະແດງຂໍ້ຄວາມນີ້ອີກໃນເທື່ອຕໍ່ໄປ"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"ລາຍ​ງານ​ບັນ​ຫາ"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ລາຍລະອຽດຂອງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ຊື່ໄຟລ໌"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ຊື່"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ຄຳອະທິບາຍແບບລະອຽດ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ຊື່ຂໍ້ຜິດພາດ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ສະຫຼຸບຂໍ້ຜິດພາດ"</string>
+    <string name="save" msgid="4781509040564835759">"ບັນທຶກ"</string>
 </resources>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index 3418213..a8468cf 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Apvalkalas"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Pranešimas apie riktą (<xliff:g id="ID">#%d</xliff:g>) generuojamas"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Pranešimas apie riktą (<xliff:g id="ID">#%d</xliff:g>) užfiksuotas"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Pranešimas apie riktą (<xliff:g id="ID">#%d</xliff:g>) užfiksuotas, bet laukiama ekrano kopijos"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Pridedama informacijos prie pranešimo apie riktą"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Palaukite…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Perbraukite kairėn, kad bendrintumėte rikto ataskaitą"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Palieskite, kad bendrintumėte pranešimą apie riktą"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Palieskite ir bendrinkite pranešimą apie riktą be ekrano kopijos arba palaukite, kol ji bus sukurta"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Palieskite ir bendrinkite pranešimą apie riktą be ekrano kopijos arba palaukite, kol ji bus sukurta"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Riktų ataskaitose pateikiami duomenys iš įvairių sistemos žurnalo failų, įskaitant asmeninę ir privačią informaciją. Riktų ataskaitas bendrinkite tik su patikimomis programomis ir žmonėmis."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rodyti šį pranešimą kitą kartą"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Riktų ataskaitos"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nepavyko padaryti ekrano kopijos."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Išsami informacija apie pranešimą apie riktą (<xliff:g id="ID">#%d</xliff:g>)"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Failo pavadinimas"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Pavadinimas"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Išsamus aprašas"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Rikto pavadinimas"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Rikto suvestinė"</string>
+    <string name="save" msgid="4781509040564835759">"Išsaugoti"</string>
 </resources>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 6108716..08e25be 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Aizsargs"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g> tiek ģenerēts"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g> reģistrēts"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g> izveidots; gaida ekrānuzņēmumu"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Informācijas pievienošana kļūdas pārskatam"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Lūdzu, uzgaidiet..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Velciet pa kreisi, lai kopīgotu savu kļūdu ziņojumu."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Pieskarieties, lai kopīgotu kļūdas pārskatu."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Pieskarieties, lai kopīgotu kļūdas pārskatu bez ekrānuzņēmuma vai gaidiet ekrānuzņēmumu."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Pieskarieties, lai kopīgotu kļūdas pārskatu bez ekrānuzņēmuma vai gaidiet ekrānuzņēmumu."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Kļūdu pārskatā ir iekļauti dati no dažādiem sistēmas žurnālfailiem, tostarp personas dati un privāta informācija. Kļūdu pārskatus ieteicams kopīgot tikai ar uzticamām lietotnēm un lietotājiem."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rādīt šo ziņojumu nākamajā reizē"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Kļūdu ziņojumi"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nevarēja veikt ekrānuzņēmumu."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g>: detalizēta informācija"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Faila nosaukums"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Nosaukums"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detalizēts apraksts"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Kļūdas nosaukums"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Kļūdas kopsavilkums"</string>
+    <string name="save" msgid="4781509040564835759">"Saglabāt"</string>
 </resources>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index 500196d..3f879b7e 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Обвивка"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Се генерира извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Извештајот за грешки <xliff:g id="ID">#%d</xliff:g> е снимен"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Извештајот за грешка <xliff:g id="ID">#%d</xliff:g> е снимен. Се чека на сликата"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Се додаваат детали на извештајот за грешка"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Почекајте..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Повлечете налево за да споделите пријава за грешка"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Допрете за да го споделите извештајот за грешки"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Допрете за споделување извештај за грешки без слика од екранот или почекајте да се подготви сликата"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Допрете за споделување извештај за грешки без слика од екранот или почекајте да се подготви сликата"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Извештаите за грешка содржат податоци од разни датотеки за евиденција на системот, вклучувајќи лични и приватни информации. Извештаите за грешка споделувајте ги само со апликации и луѓе на коишто им верувате."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ја поракава следниот пат"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаи за грешки"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детали за извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Име на датотека"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Детален опис"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Наслов на грешката"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Преглед на грешката"</string>
+    <string name="save" msgid="4781509040564835759">"Зачувај"</string>
 </resources>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 696aab2..3bb715d8 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"ഷെൽ"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> സൃഷ്ടിക്കുന്നു"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> ക്യാപ്ചർ ചെയ്തു"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> ക്യാപ്ചർ ചെയ്തു, എന്നാൽ സ്ക്രീൻഷോട്ട് ശേഷിക്കുന്നു"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ബഗ് റിപ്പോർട്ടിലേക്ക് വിശദാംശങ്ങൾ ചേർക്കുന്നു"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"കാത്തിരിക്കുക..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നതിന് ഇടത്തേയ്‌ക്ക് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"സ്ക്രീൻഷോട്ട് കൂടാതെയോ സ്ക്രീൻഷോട്ട് പൂർത്തിയാകുന്നതിന് കാക്കാതെയോ നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"സ്ക്രീൻഷോട്ട് കൂടാതെയോ സ്ക്രീൻഷോട്ട് പൂർത്തിയാകുന്നതിന് കാക്കാതെയോ നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"വ്യക്തിഗതവും സ്വകാര്യവുമായ വിവരങ്ങൾ ഉൾപ്പെടെ, സിസ്റ്റത്തിന്റെ നിരവധി ലോഗ് ഫയലുകളിൽ നിന്നുള്ള ഡാറ്റ, ബഗ് റിപ്പോർട്ടുകളിൽ അടങ്ങിയിരിക്കുന്നു. നിങ്ങൾ വിശ്വസിക്കുന്ന അപ്ലിക്കേഷനുകൾക്കും ആളുകൾക്കും മാത്രം ബഗ് റിപ്പോർട്ടുകൾ പങ്കിടുക."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ഈ സന്ദേശം അടുത്ത തവണ ദൃശ്യമാക്കുക"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"ബഗ് റിപ്പോർട്ടുകൾ"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> വിശദാംശങ്ങൾ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ഫയല്‍നാമം"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"പേര്"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"വിശദമായ വിവരണം"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ബഗിന്റെ പേര്"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ബഗ് സംഗ്രഹം"</string>
+    <string name="save" msgid="4781509040564835759">"സംരക്ഷിക്കുക"</string>
 </resources>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 62d83cb..296afab 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Шел"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g> үүсгэгдэж байна"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g>-г бүртгэгдлээ"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Алдааны тайлан <xliff:g id="ID">#%d</xliff:g>-г илрүүлсэн хэдий ч дэлгэцээс авсан зураг хүлээгдэж байна"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Алдааны тайланд дэлгэрэнгүй мэдээлэл нэмж байна"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Түр хүлээнэ үү..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Өөрийн согог репортыг хуваалцахын тулд зүүн шудрана уу"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Програмд гарсан алдааны мэдээллээ хуваалцах бол дарна уу"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Алдааны тайлангаа дэлгэцээс авсан зураггүйгээр хуваалцах бол дарж, эсвэл дэлгэцээс авсан зургийг бэлэн болтол нь хүлээнэ үү"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Алдааны тайлангаа дэлгэцээс авсан зураггүйгээр хуваалцах бол дарж, эсвэл дэлгэцээс авсан зургийг бэлэн болтол нь хүлээнэ үү"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Алдааны репорт нь хувийн болон нууц мэдээлэл зэргийг агуулсан системийн төрөл бүрийн лог файлын датаг агуулна. Алдааны репортыг зөвхөн итгэлтэй апп болон хүмүүст хуваалцана уу."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Энэ мессежийг дараагийн удаа харуулах"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Гэмтлийн тухай тайлан"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g>-ны дэлгэрэнгүй"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Файлын нэр"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Гарчиг"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Дэлгэрэнгүй тайлбар"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Алдааны нэр"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Алдааны хураангуй"</string>
+    <string name="save" msgid="4781509040564835759">"Хадгалах"</string>
 </resources>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index e6b2b04..8eb5686 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"शेल"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> तयार केला जात आहे"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> कॅप्चर केला"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> कॅप्चर केला परंतु स्क्रीनशॉट प्रलंबित आहे"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"दोष अहवालामध्‍ये तपशील जोडत आहे"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करा..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"आपला दोष अहवाल सामायिक करण्यासाठी डावीकडे स्वाइप करा"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"आपला दोष अहवाल सामायिक करण्यासाठी टॅप करा"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"स्क्रीनशॉट शिवाय आपला दोष अहवाल सामायिक करण्यासाठी टॅप करा किंवा समाप्त करण्यासाठी स्क्रीनशॉटची प्रतीक्षा करा"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"स्क्रीनशॉट शिवाय आपला दोष अहवाल सामायिक करण्यासाठी टॅप करा किंवा समाप्त करण्यासाठी स्क्रीनशॉटची प्रतीक्षा करा"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"दोष अहवालांमध्‍ये वैयक्तिक आणि खाजगी माहितीसह, सिस्‍टमच्‍या अनेक लॉग फायलींमधील डेटा असतो. केवळ आपला विश्वास असलेल्‍या अ‍ॅप्‍स आणि लोकांसह दोष अहवाल सामायिक करा."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"पुढील वेळी हा संदेश दर्शवा"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"दोष अहवाल"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> तपशील"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"फाईलनाव"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"तपशीलवार वर्णन"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"दोष शीर्षक"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"दोष सारांश"</string>
+    <string name="save" msgid="4781509040564835759">"जतन करा"</string>
 </resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index 1d04253..46bc1a9 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Laporan pepijat <xliff:g id="ID">#%d</xliff:g> sedang dijana"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Laporan pepijat <xliff:g id="ID">#%d</xliff:g> telah ditangkap"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Laporan pepijat <xliff:g id="ID">#%d</xliff:g> ditangkap, menunggu tngkpn skrin"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Menambahkan butiran pada laporan pepijat"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Sila tunggu…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Leret ke kiri untuk berkongsi laporan pepijat anda"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ketik untuk berkongsi laporan pepijat anda"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Ketik untuk berkongsi laporan pepijat anda tanpa tangkapan skrin atau tunggu tangkapan skrin selesai"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Ketik untuk berkongsi laporan pepijat anda tanpa tangkapan skrin atau tunggu tangkapan skrin selesai"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Laporan pepijat mengandungi data dari pelbagai fail log sistem, termasuk maklumat peribadi dan sulit. Kongsikan laporan pepijat hanya dengan apl dan orang yang anda percayai."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tunjukkan mesej ini pada masa akan datang"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan pepijat"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan skrin tidak dapat diambil."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Butiran laporan pepijat <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nama fail"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tajuk"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Perihalan terperinci"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Tajuk pepijat"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Ringkasan pepijat"</string>
+    <string name="save" msgid="4781509040564835759">"Simpan"</string>
 </resources>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index f63c8c5..6f02e70 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"အခွံ"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> ကိုထုတ်နေပါသည်"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> ကိုရယူထားပြီးပါပြီ"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"ချွတ်ယွင်းချက် အစီရင်ခံစာ <xliff:g id="ID">#%d</xliff:g> ဖမ်းယူထားသည် သို့သော် ဖန်သားပြင်ဓာတ်ပုံမှတ်တမ်းတင်ခြင်း စောင့်ဆိုင်းနေသည်"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ချွတ်ယွင်းချက်အစီရင်ခံချက်သို့ အသေးစိတ်များပေါင်းထည့်ရန်"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"ခေတ္တစောင့်ပါ..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"သင်၏ ဘာဂ် အစီရင်ခံစာကို မျှပေးရန် ဘယ်ဘက်သို့ ပွတ်ဆွဲရန်"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"သင့်ချွတ်ယွင်းမှုအစီရင်ခံချက်ကို မျှဝေရန် တို့ပါ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ချွတ်ယွင်းချက်အစီရင်ခံစာကို ဖန်သားပြင်ဓာတ်ပုံမှတ်တမ်းမပါဘဲ မျှဝေရန် တို့ပါ သို့မဟုတ် ဖန်သားပြင်ဓာတ်ပုံမှတ်တမ်းတင်ခြင်း ပြီးဆုံးသည်အထိ စောင့်ပါ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ချွတ်ယွင်းချက်အစီရင်ခံစာကို ဖန်သားပြင်ဓာတ်ပုံမှတ်တမ်းမပါဘဲ မျှဝေရန် တို့ပါ သို့မဟုတ် ဖန်သားပြင်ဓာတ်ပုံမှတ်တမ်းတင်ခြင်း ပြီးဆုံးသည်အထိ စောင့်ပါ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"အမှားအယွင်း မှတ်တမ်းမှာ ပါရှိသော အချက်အလက်များမှာ ကိုယ်ရေးကိုယ်တာ နဲ့ လုံခြုံရေး အချက်အလက်များပါဝင်သော စနစ်မှ ပြုလုပ်မှု မှတ်တမ်းများ ဖြစ်ပါသည်၊ အမှားအယွင်း မှတ်တမ်းများကို ယုံကြည်ရသော အပလီကေးရှင်းများနဲ့ လူများကိုသာ ပေးဝေပြသမှု လုပ်ပါရန်။"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ဤစာတန်းကို နောက်တစ်ခါတွင် ပြရန်"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"ချို့ယွင်းမှု အစီရင်ခံစာများ"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> အသေးစိတ်များ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ဖိုင်အမည်"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ခေါင်းစဉ်"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"အသေးစိတ် ဖော်ပြချက်"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ချွတ်ယွင်းချက် ခေါင်းစဉ်"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ချွတ်ယွင်းချက် အကျဉ်းချုပ်"</string>
+    <string name="save" msgid="4781509040564835759">"သိမ်းဆည်းပါ"</string>
 </resources>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 328e8ae..0605e0e 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Kommandoliste"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> blir generert"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> er fullført"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> er hentet. Venter på skjermdumpen"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Legger til detaljer i feilrapporten"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent litt"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Sveip til venstre for å dele feilrapporten din"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Trykk for å dele feilrapporten"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Trykk for å dele feilrapporten uten noen skjermdump, eller vent til skjermdumpen er klar"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Trykk for å dele feilrapporten uten noen skjermdump, eller vent til skjermdumpen er klar"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Feilrapporter inkluderer data fra systemets forskjellige loggfiler. Dette omfatter personlig og privat informasjon. Du bør bare dele feilrapporter med apper og folk du stoler på."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne meldingen neste gang"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Feilrapporter"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tittel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljert beskrivelse"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Navn på feil"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Oppsummering av feil"</string>
+    <string name="save" msgid="4781509040564835759">"Lagre"</string>
 </resources>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 62bfead..906d824 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"सेल"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>लाई निकालिदैछ"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>लाई कैद गरियो"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> लाई क्याप्चर गरियो तर स्क्रिनसट बाँकी रहेको छ"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"बग रिपोर्टमा विवरणहरू थप्दै"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा गर्नुहोला..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"तपाईँको बग रिपोर्ट साझेदारी गर्न बायाँ स्वाइप गर्नुहोस्"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"तपाईंको बग रिपोर्टलाई साझेदारी गर्न ट्याप गर्नुहोस्"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"तपाईँको बग रिपोर्टलाई स्क्रिनसट बिना साझेदारी गर्नका लागि ट्याप गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुन प्रतीक्षा गर्नुहोस्"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"तपाईँको बग रिपोर्टलाई स्क्रिनसट बिना साझेदारी गर्नका लागि ट्याप गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुन प्रतीक्षा गर्नुहोस्"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्टहरूमा प्रणालीका विभिन्न लग फाइलहरूबाट व्यक्तिगत तथा नीजि सूचनासहितको डेटा रहन्छ।  बग रिपोर्टहरू अनुप्रयोगहरू र तपाईँले विश्वास गरेका व्यक्तिहरूसँग मात्र साझेदारी गर्नुहोस्।"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यो सन्देश अर्को पटक देखाउनुहोस्"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्टहरू"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>का विवरणहरू"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"फाइलको नाम"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत विवरण"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"बगको शीर्षक"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"बगको सारांश"</string>
+    <string name="save" msgid="4781509040564835759">"सुरक्षित गर्नुहोस्"</string>
 </resources>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 2f4b215..3022691 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bugrapport <xliff:g id="ID">#%d</xliff:g> wordt gegenereerd"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Bugrapport <xliff:g id="ID">#%d</xliff:g> is vastgelegd"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Bugrapport <xliff:g id="ID">#%d</xliff:g> vastgelegd, screenshot in behandeling"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Details toevoegen aan het bugrapport"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Even geduld…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veeg naar links om je bugmelding te delen"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tik om je bugrapport te delen"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tik om je bugrapport te delen zonder screenshot of wacht tot het screenshot is voltooid"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tik om je bugrapport te delen zonder screenshot of wacht tot het screenshot is voltooid"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Foutenrapporten bevatten gegevens uit de verschillende logbestanden van het systeem, waaronder persoonlijke en privégegevens. Deel foutenrapporten alleen met apps en mensen die u vertrouwt."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Dit bericht de volgende keer weergeven"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Foutenrapporten"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot kan niet worden gemaakt."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details van bugrapport <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Bestandsnaam"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beschrijving"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titel van bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Overzicht van bug"</string>
+    <string name="save" msgid="4781509040564835759">"Opslaan"</string>
 </resources>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index dc2277f..d44daf7 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"ਸ਼ੈਲ"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਸਿਰਜੀ ਜਾ ਰਹੀ ਹੈ"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਕੈਪਚਰ ਕੀਤੀ ਗਈ"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਕੈਪਚਰ ਕੀਤੀ ਗਈ ਪਰ ਸਕ੍ਰੀਨਸ਼ਾਟ ਅਧੂਰਾ ਹੈ"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"ਬੱਗ ਰਿਪੋਰਟ ਵਿੱਚ ਵੇਰਵਿਆਂ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ਤੁਹਾਡੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਖੱਬੇ ਪਾਸੇ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ਆਪਣੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੇ ਬਿਨਾਂ ਆਪਣੀ ਬੱਗ ਰਿਪੋਰਟ ਨੂੰ ਸਾਂਝੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਜਾਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੇ ਪੂਰੇ ਹੋਣ ਦੀ ਉਡੀਕ ਕਰੋ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੇ ਬਿਨਾਂ ਆਪਣੀ ਬੱਗ ਰਿਪੋਰਟ ਨੂੰ ਸਾਂਝੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਜਾਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੇ ਪੂਰੇ ਹੋਣ ਦੀ ਉਡੀਕ ਕਰੋ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ਬਗ ਰਿਪੋਰਟਾਂ ਵਿੱਚ ਸਿਸਟਮ ਦੀਆਂ ਭਿੰਨ ਲੌਗ ਫਾਈਲਾਂ ਦਾ ਡਾਟਾ ਹੁੰਦਾ ਹੈ, ਨਿੱਜੀ ਅਤੇ ਪ੍ਰਾਈਵੇਟ ਜਾਣਕਾਰੀ ਸਮੇਤ। ਕੇਵਲ ਉਹਨਾਂ ਐਪਸ ਅਤੇ ਲੋਕਾਂ ਨਾਲ ਬਗ ਰਿਪੋਰਟਾਂ ਸ਼ੇਅਰ ਕਰੋ, ਜਿਹਨਾਂ ਤੇ ਤੁਸੀਂ ਭਰੋਸਾ ਕਰਦੇ ਹੋ।"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ਅਗਲੀ ਵਾਰ ਇਹ ਸੁਨੇਹਾ ਦਿਖਾਓ"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"ਬਗ ਰਿਪੋਰਟਾਂ"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਵੇਰਵੇ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ਫ਼ਾਈਲ ਨਾਮ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ਸਿਰਲੇਖ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ਵਿਸਥਾਰ ਸਹਿਤ ਵਰਣਨ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ਬੱਗ ਸਿਰਲੇਖ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ਬੱਗ ਸਾਰਾਂਸ਼"</string>
+    <string name="save" msgid="4781509040564835759">"ਰੱਖਿਅਤ ਕਰੋ"</string>
 </resources>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index c585568..b4977a4 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Powłoka"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generuję raport o błędzie <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Raport o błędzie <xliff:g id="ID">#%d</xliff:g> został zapisany"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Raport <xliff:g id="ID">#%d</xliff:g> zapisany. Zrzut nie jest jeszcze gotowy"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaję szczegóły do raportu o błędzie"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Czekaj..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Przesuń palcem w lewo, by udostępnić swoje zgłoszenie błędu"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Kliknij, by udostępnić raport o błędzie"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Kliknij, by udostępnić raport o błędzie bez zrzutu ekranu, lub poczekaj, aż zostanie on wygenerowany"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Kliknij, by udostępnić raport o błędzie bez zrzutu ekranu, lub poczekaj, aż zostanie on wygenerowany"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Raporty o błędach zawierają dane z różnych plików dzienników systemu, w tym dane osobowe i prywatne. Udostępniaj je tylko aplikacjom i osobom, którym ufasz."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaż ten komunikat następnym razem"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Raporty o błędach"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nie udało się zrobić zrzutu ekranu."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Szczegóły raportu o błędzie <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nazwa pliku"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tytuł"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Szczegółowy opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Tytuł raportu o błędzie"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Podsumowanie raportu o błędzie"</string>
+    <string name="save" msgid="4781509040564835759">"Zapisz"</string>
 </resources>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index fc6e21c..2306c39 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"O relatório do bug <xliff:g id="ID">#%d</xliff:g> está sendo gerado"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Relatório do bug <xliff:g id="ID">#%d</xliff:g> capturado"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Relatório do bug <xliff:g id="ID">#%d</xliff:g> capturado, captura pendente"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Adicionando detalhes ao relatório do bug"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toque para compartilhar seu relatório do bug"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toque para compartilhar seu relatório de bug sem captura de tela ou aguarde a conclusão"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toque para compartilhar seu relatório de bug sem captura de tela ou aguarde a conclusão"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com apps e pessoas nos quais você confia."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do bug"</string>
+    <string name="save" msgid="4781509040564835759">"Salvar"</string>
 </resources>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 252edb1..7daed8b 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"O relatório de erro <xliff:g id="ID">#%d</xliff:g> está a ser criado"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Relatório de erro <xliff:g id="ID">#%d</xliff:g> criado"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Rel. de erro <xliff:g id="ID">#%d</xliff:g> capturado, captura de ecrã pendente"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"A adicionar detalhes ao relatório de erro"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslizar rapidamente para a esquerda para partilhar o seu relatório de erros"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toque para partilhar o relatório de erro"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toque para partilhar o relatório de erro sem uma captura de ecrã ou aguarde a conclusão da mesma"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toque para partilhar o relatório de erro sem uma captura de ecrã ou aguarde a conclusão da mesma"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de erros incluem dados de vários ficheiros de registo do sistema, nomeadamente informações pessoais e privadas. Partilhe relatórios de erros apenas com aplicações e pessoas fidedignas."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de erros"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível tirar a captura de ecrã."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de erro <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do erro"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo de erros"</string>
+    <string name="save" msgid="4781509040564835759">"Guardar"</string>
 </resources>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index fc6e21c..2306c39 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"O relatório do bug <xliff:g id="ID">#%d</xliff:g> está sendo gerado"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Relatório do bug <xliff:g id="ID">#%d</xliff:g> capturado"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Relatório do bug <xliff:g id="ID">#%d</xliff:g> capturado, captura pendente"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Adicionando detalhes ao relatório do bug"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toque para compartilhar seu relatório do bug"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toque para compartilhar seu relatório de bug sem captura de tela ou aguarde a conclusão"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toque para compartilhar seu relatório de bug sem captura de tela ou aguarde a conclusão"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com apps e pessoas nos quais você confia."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do bug"</string>
+    <string name="save" msgid="4781509040564835759">"Salvar"</string>
 </resources>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index d720417..9529ade 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Raportul de eroare <xliff:g id="ID">#%d</xliff:g> se generează"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Raportul de eroare <xliff:g id="ID">#%d</xliff:g> a fost creat"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Raport eroare <xliff:g id="ID">#%d</xliff:g> creat, captură ecran în așteptare"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Se adaugă detaliile la raportul de eroare"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Așteptați…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Glisați la stânga pentru a trimite raportul de erori"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Atingeți pentru a trimite raportul de eroare"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Atingeți ca să trimiteți raportul de eroare fără captură de ecran sau așteptați finalizarea acesteia"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Atingeți ca să trimiteți raportul de eroare fără captură de ecran sau așteptați finalizarea acesteia"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Rapoartele despre erori conțin date din diferite fișiere de jurnal ale sistemului, inclusiv informații private și personale. Permiteți accesul la rapoartele despre erori numai aplicațiilor și persoanelor în care aveți încredere."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afișați acest mesaj data viitoare"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapoarte de erori"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Captura de ecran nu a putut fi făcută."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaliile raportului de eroare <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Numele fișierului"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titlu"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descriere detaliată"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titlul erorii"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Rezumat privind eroarea"</string>
+    <string name="save" msgid="4781509040564835759">"Salvați"</string>
 </resources>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index ed5ecaf..4aafbba 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Оболочка"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Создание отчета об ошибке <xliff:g id="ID">#%d</xliff:g>…"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Отчет об ошибке <xliff:g id="ID">#%d</xliff:g> сохранен"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Отчет об ошибке (<xliff:g id="ID">#%d</xliff:g>) готов, ожидается скриншот"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Добавление данных в отчет об ошибке"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Подождите…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведите влево, чтобы отправить отчет"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Нажмите, чтобы отправить отчет об ошибке."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Нажмите, чтобы отправить отчет об ошибке сразу, или подождите, пока будет сохранен скриншот."</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Нажмите, чтобы отправить отчет об ошибке сразу, или подождите, пока будет сохранен скриншот."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Отчеты об ошибках содержат данные различных системных журналов и могут включать личную информацию. Рекомендуем открывать к ним доступ только лицам и приложениям, заслуживающим доверие."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показать это сообщение в следующий раз"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Отчеты об ошибках"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Данные отчета об ошибке <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Название файла"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Название"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Подробное описание"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Название ошибки"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Описание ошибки"</string>
+    <string name="save" msgid="4781509040564835759">"Сохранить"</string>
 </resources>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index cd8fba3..1ea7586 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"ෂෙල්"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> ජනනය කරමින් පවතී"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> ග්‍රහණය කර ගන්නා ලදී"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"දෝෂ වාර්තාව <xliff:g id="ID">#%d</xliff:g> ග්‍රහණය කළ නමුත් තිර රුව පොරොත්තුව ඇත"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"දෝෂ වාර්තාව වෙත විස්තර එක් කිරීම"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"කරුණාකර රැඳී සිටින්න..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ඔබගේ දෝෂ වාර්තාව බෙදාගැනීමට වමට ස්වයිප් කරන්න"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට තට්ටු කරන්න"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"තිර රුවක් රහිතව ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට තට්ටු කරන්න නැතහොත් තිර රුව ගැනීම අවසන් වන තෙක් රැඳෙන්න"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"තිර රුවක් රහිතව ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට තට්ටු කරන්න නැතහොත් තිර රුව ගැනීම අවසන් වන තෙක් රැඳෙන්න"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"පුද්ගලික සහ පෞද්ගලික තොරතුරු ඇතුළත්ව පද්ධතියේ විවිධ ලොග් ගොනු වල දත්ත දෝෂ වාර්තාවේ අඩංගු වේ. ඔබට විශ්වාසවන්ත යෙදුම් සහ පුද්ගලයින් සමඟ පමණක් දෝෂ වාර්තා බෙදා ගන්න."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ඊළඟ වෙලාවේ මෙම පණිවිඩය පෙන්වන්න"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"දෝෂ වාර්තා"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> විස්තර"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ගොනුවේ නම"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"මාතෘකාව"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"සවිස්තර විස්තරය"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"දෝෂ මාතෘකාව"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"දෝෂ සාරාංශය"</string>
+    <string name="save" msgid="4781509040564835759">"සුරකින්න"</string>
 </resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 23e67f5..7a78c43 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Prostredie"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generuje sa hlásenie chyby <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Hlásenie chyby <xliff:g id="ID">#%d</xliff:g> bolo zaznamenané"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Chyba <xliff:g id="ID">#%d</xliff:g> bola zaznamenaná, čaká sa na snímku obrazovky"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Pridanie podrobností o hlásení chyby"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Čakajte prosím…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ak chcete hlásenie o chybe zdieľať, prejdite prstom doľava."</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hlásenie chyby môžete zdieľať klepnutím"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Klepnutím zdieľajte hlásenie chyby bez snímky obrazovky alebo počkajte na dokončenie snímky obrazovky"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Klepnutím zdieľajte hlásenie chyby bez snímky obrazovky alebo počkajte na dokončenie snímky obrazovky"</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>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia chýb"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímku obrazovky sa nepodarilo zaznamenať."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti hlásenia chyby <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Názov súboru"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Názov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Názov chyby"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Súhrn chyby"</string>
+    <string name="save" msgid="4781509040564835759">"Uložiť"</string>
 </resources>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 519f3f2..fdf3446 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Lupina"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> je v izdelavi"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> zajeto"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Poroč. o napakah <xliff:g id="ID">#%d</xliff:g> zajeto, posnetek zaslona nastaja"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Dodajanje podrobnosti v poročilo o napakah"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Počakajte ..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Povlecite v levo, če želite poslati sporočilo o napaki"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dotaknite se, če želite poročilo o napaki dati v skupno rabo"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dotaknite se za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dotaknite se za pošiljanje poročila o napakah brez posnetka zaslona ali počakajte, da se ta dokonča"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Poročila o napakah vsebujejo podatke iz različnih dnevniških datotek sistema, vključno z osebnimi in zasebnimi podatki. Poročila o napakah delite samo z aplikacijami in ljudmi, ki jim zaupate."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaži to sporočilo naslednjič"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Poročila o napakah"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Posnetka zaslon ni bilo mogoče ustvariti."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti poročila o napaki <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Ime datoteke"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Podroben opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov poročila o napakah"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Povzetek poročila o napakah"</string>
+    <string name="save" msgid="4781509040564835759">"Shrani"</string>
 </resources>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index 5e3c706..f43ce9f 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Guaska"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Raporti i defekteve në kod <xliff:g id="ID">#%d</xliff:g> po krijohet"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Raporti i defekteve në kod <xliff:g id="ID">#%d</xliff:g> u regjistrua"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Raporti i defekteve në kod <xliff:g id="ID">#%d</xliff:g> u regjistrua, por pamja e çastit është në pritje"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Po shtohen detajet te raporti i defekteve në kod"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Qëndro në pritje..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Rrëshqit majtas për të ndarë raportin e defektit në kod"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Trokit për të ndarë raportin e defekteve në kod"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Trokit për të ndarë raportin e defekteve në kod pa një pamje çasti ose prit që pamja e çastit të përfundojë"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Trokit për të ndarë raportin e defekteve në kod pa një pamje çasti ose prit që pamja e çastit të përfundojë"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Raportet e gabimeve përmbajnë të dhëna nga skedarë të ndryshëm ditarësh sistemi, përfshi informacione personale dhe private. Shpërndaji publikisht raportet e gabimeve vetëm me aplikacionet dhe personat që iu beson."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tregoje këtë mesazh herën tjetër"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Raportet e gabimeve"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Pamja e ekranit nuk mund të realizohej."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detajet e raportit të defekteve në kod <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Emri i skedarit"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titulli"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Përshkrimi i detajuar"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titulli i defektit në kod"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Përmbledhja e defekteve në kod"</string>
+    <string name="save" msgid="4781509040564835759">"Ruaj"</string>
 </resources>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index 55119b6..3bea4f3 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Извештај о грешци <xliff:g id="ID">#%d</xliff:g> се генерише"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Извештај о грешци <xliff:g id="ID">#%d</xliff:g> је снимљен"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Извештај о грешци <xliff:g id="ID">#%d</xliff:g> снимљен; снимак екрана се чека"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Додају се детаљи у извештај о грешци"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Сачекајте..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Превуците улево да бисте делили извештај о грешкама"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Додирните да бисте делили извештај о грешци"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Додирните за дељење извештаја о грешци без снимка екрана или сачекајте да се направи снимак екрана"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Додирните за дељење извештаја о грешци без снимка екрана или сачекајте да се направи снимак екрана"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Извештаји о грешкама садрже податке из различитих системских датотека евиденције, укључујући личне и приватне податке. Делите извештаје о грешкама само са апликацијама и људима у које имате поверења."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ову поруку следећи пут"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаји о грешкама"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детаљи извештаја о грешци <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Назив датотеке"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Детаљни опис"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Наслов грешке"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Резиме грешке"</string>
+    <string name="save" msgid="4781509040564835759">"Сачувај"</string>
 </resources>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index 085f57e..a8cb64d 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Skal"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Felrapporten <xliff:g id="ID">#%d</xliff:g> genereras"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Felrapporten <xliff:g id="ID">#%d</xliff:g> har skapats"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Felrapporten <xliff:g id="ID">#%d</xliff:g> har skapats, väntar på skärmdumpen"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Lägger till information i felrapporten"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Vänta …"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Svep åt vänster om du vill dela felrapporten"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tryck om du vill dela felrapporten"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Tryck om du vill dela felrapporten utan en skärmdump eller vänta tills skärmdumpen är klar"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Tryck om du vill dela felrapporten utan en skärmdump eller vänta tills skärmdumpen är klar"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Felrapporter innehåller data från systemets olika loggfiler, inklusive personliga och privata uppgifter. Dela bara felrapporter med personer du litar på."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Visa det här meddelandet nästa gång"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Felrapporter"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Det gick inte att ta skrämdump."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Information för felrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filnamn"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Namn"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljerad beskrivning"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Felets titel"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sammanfattning av felet"</string>
+    <string name="save" msgid="4781509040564835759">"Spara"</string>
 </resources>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index c5a8ef1..945bb60 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Ganda"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g> inatayarishwa"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g> imerekodiwa"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g> imerekodiwa lakini picha ya skrini bado haijakamilishwa"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Inaongeza maelezo kwenye ripoti ya hitilafu"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Tafadhali subiri…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Telezesha kidole kushoto ili ushiriki ripoti yako ya hitilafu"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Gonga ili ushiriki ripoti yako ya hitilafu"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Gonga ili ushiriki ripoti yako ya hitilafu bila picha ya skrini au usubiri picha ya skrini itayarishwe"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Gonga ili ushiriki ripoti yako ya hitilafu bila picha ya skrini au usubiri picha ya skrini itayarishwe"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Ripoti ya hitilafu ina data kutoka kwenye faili za kumbukumbu mbalimbali za mfumo, pamoja na maelezo ya kibinafsi na faragha. Shiriki ripoti ya hitilafu na programu na watu unaowaamini pekee."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Onyesha ujumbe huu wakati mwingine"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Ripoti za hitilafu"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Haikupiga picha ya skrini."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Maelezo ya ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Jina la faili"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Kichwa"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Maelezo ya kina"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Jina la hitilafu"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Muhtasari wa hitilafu"</string>
+    <string name="save" msgid="4781509040564835759">"Hifadhi"</string>
 </resources>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index 7ef89e2..a501764 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"ஷெல்"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> உருவாக்கப்படுகிறது"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> எடுக்கப்பட்டது"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> எடுக்கப்பட்டது ஆனால் ஸ்கிரீன்ஷாட் நிலுவையிலுள்ளது"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"பிழை அறிக்கையில் விவரங்களைச் சேர்க்கிறது"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"காத்திருக்கவும்…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"பிழை அறிக்கையைப் பகிர இடது புறமாகத் தேய்க்கவும்"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"பிழை அறிக்கையைப் பகிர, தட்டவும்"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ஸ்கிரீன்ஷாட் இல்லாமல் பிழை அறிக்கையைப் பகிர, தட்டவும் அல்லது ஸ்கிரீன்ஷாட் முடியும்வரை காத்திருக்கவும்"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ஸ்கிரீன்ஷாட் இல்லாமல் பிழை அறிக்கையைப் பகிர, தட்டவும் அல்லது ஸ்கிரீன்ஷாட் முடியும்வரை காத்திருக்கவும்"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"பிழை அறிக்கைகளில், சொந்த வாழ்க்கை மற்றும் தனிப்பட்ட தகவல் உள்பட கணினியின் பல்வேறு பதிவுகளில் உள்ள தரவு இருக்கும். நீங்கள் நம்பும் பயன்பாடுகள் மற்றும் நபர்களுடன் மட்டும் பிழை அறிக்கைகளைப் பகிரவும்."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"இந்தச் செய்தியை அடுத்த முறைக் காட்டு"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"பிழை அறிக்கைகள்"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> இன் விவரங்கள்"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"கோப்புப்பெயர்"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"தலைப்பு"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"விரிவான விளக்கம்"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"பிழை தலைப்பு"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"பிழை குறித்த சுருக்க விவரம்"</string>
+    <string name="save" msgid="4781509040564835759">"சேமி"</string>
 </resources>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index 6ba816b..f406869 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"షెల్"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"బగ్ నివే. <xliff:g id="ID">#%d</xliff:g> క్యాప్చ., కానీ స్క్రీన్‌షాట్ పెం. ఉంది"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ నివేదికకు వివరాలను జోడిస్తోంది"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"దయచేసి వేచి ఉండండి..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎడమవైపుకు స్వైప్ చేయండి"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి నొక్కండి"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"బగ్ నివేదికలు వ్యక్తిగతమైన మరియు రహస్యమైన సమాచారంతో సహా సిస్టమ్ యొక్క విభిన్న లాగ్ ఫైల్‌ల్లోని డేటాను కలిగి ఉంటాయి. కనుక బగ్ నివేదికలను మీరు విశ్వసించే అనువర్తనాలు మరియు వ్యక్తులతో మాత్రమే భాగస్వామ్యం చేయండి."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"తదుపరిసారి ఈ సందేశాన్ని చూపు"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ నివేదికలు"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్‌షాట్‌ను తీయడం సాధ్యపడలేదు."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ఫైల్ పేరు"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"శీర్షిక"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"సమగ్ర వివరణ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"బగ్ శీర్షిక"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"బగ్ సారాంశం"</string>
+    <string name="save" msgid="4781509040564835759">"సేవ్ చేయి"</string>
 </resources>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index d68ca26..db7f823 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"กำลังสร้างรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"บันทึกรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g> แล้ว"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"จับภาพรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g> แล้วแต่ภาพหน้าจอยังไม่เสร็จ"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"กำลังเพิ่มรายละเอียดในรายงานข้อบกพร่อง"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"โปรดรอสักครู่…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"กวาดไปทางซ้ายเพื่อแชร์รายงานข้อบกพร่อง"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณ"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณโดยไม่มีภาพหน้าจอ หรือรอให้ภาพหน้าจอเสร็จสมบูรณ์"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณโดยไม่มีภาพหน้าจอ หรือรอให้ภาพหน้าจอเสร็จสมบูรณ์"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"รายงานข้อบกพร่องมีข้อมูลจากไฟล์บันทึกต่างๆ ของระบบ รวมถึงข้อมูลส่วนตัว แชร์รายงานข้อบกพร่องกับแอปและบุคคลที่คุณไว้ใจเท่านั้น"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"แสดงข้อความนี้ในครั้งต่อไป"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"รายงานข้อบกพร่อง"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"รายละเอียดรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ชื่อไฟล์"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ชื่อ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"คำอธิบายโดยละเอียด"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ชื่อข้อบกพร่อง"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"สรุปข้อบกพร่อง"</string>
+    <string name="save" msgid="4781509040564835759">"บันทึก"</string>
 </resources>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index 432eb90..f99a1b8 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Binubuo na ang ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Na-capture ang ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Nakunan ang ulat ng bug <xliff:g id="ID">#%d</xliff:g>, nakabinbin ang screenshot"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Pagdaragdag ng mga detalye sa ulat ng bug"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Mangyaring maghintay..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Mag-swipe pakaliwa upang ibahagi ang iyong ulat ng bug"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Mag-tap upang ibahagi ang iyong ulat ng bug"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Mag-tap para ibahagi ang iyong ulat ng bug nang walang screenshot o hintaying matapos ang screenshot"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Mag-tap para ibahagi ang iyong ulat ng bug nang walang screenshot o hintaying matapos ang screenshot"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Naglalaman ang mga ulat ng bug ng data mula sa iba\'t ibang file ng log ng system, kabilang ang personal at pribadong impormasyon. Magbahagi lang ng mga ulat ng bug sa apps at mga tao na pinagkakatiwalaan mo."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ipakita ang mensaheng ito sa susunod"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Mga ulat sa bug"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Hindi makunan ng screenshot."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Mga detalye ng ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Pamagat"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detalyadong paglalarawan"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Pamagat ng bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Buod ng bug"</string>
+    <string name="save" msgid="4781509040564835759">"I-save"</string>
 </resources>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index dae377f..be448af 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Kabuk"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) oluşturuluyor"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) yakalandı"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"<xliff:g id="ID">#%d</xliff:g> hata raporu yakalandı, ekran görüntüsü bekleniyor"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Hata raporuna ayrıntılar ekleniyor"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfen bekleyin…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Hata raporunuzu paylaşmak için hızlıca sola kaydırın"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hata raporunuzu paylaşmak için hafifçe dokunun"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Hata raporunu ekran görüntüsüz paylaşmak için dokunun veya bitirmek için ekran görüntüsünü bekleyin"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Hata raporunu ekran görüntüsüz paylaşmak için dokunun veya bitirmek için ekran görüntüsünü bekleyin"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu iletiyi göster"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Hata raporları"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran görüntüsü alınamadı."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) ayrıntıları"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Dosya adı"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Başlık"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Ayrıntılı açıklama"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Hata başlığı"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Hata özeti"</string>
+    <string name="save" msgid="4781509040564835759">"Kaydet"</string>
 </resources>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index 02eeb2f..c35c61c 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Оболонка"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Генерується повідомлення про помилку <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Повідомлення про помилку <xliff:g id="ID">#%d</xliff:g> створено"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Повідомлення <xliff:g id="ID">#%d</xliff:g> створено. Очікується знімок екрана"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Додаються деталі до повідомлення про помилку"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Зачекайте…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведіть пальцем ліворуч, щоб надіслати звіт про помилки"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Торкніться, щоб надіслати повідомлення про помилку"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Торкніться, щоб надіслати повідомлення про помилку без знімка екрана або зачекайте на знімок"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Торкніться, щоб надіслати повідомлення про помилку без знімка екрана або зачекайте на знімок"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Звіти про помилки містять дані з різних файлів журналу системи, зокрема особисті та конфіденційні. Надсилайте звіт про помилки лише тим, кому довіряєте."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показати це повідомлення наступного разу"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Звіти про помилки"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Деталі повідомлення про помилку <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Назва файлу"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Назва"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Детальний опис"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Назва помилки"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Опис помилки"</string>
+    <string name="save" msgid="4781509040564835759">"Зберегти"</string>
 </resources>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index 23cada6..ef6801f 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"شیل"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> تخلیق ہو رہی ہے"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> کیپچر ہو گئی"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> کیپچر ہو گیا مگر اسکرین شاٹ زیر التواء"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"بگ رپورٹ میں تفصیلات شامل کی جا رہی ہیں"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"براہ کرم انتظار کریں…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"اپنی بگ رپورٹ کا اشتراک کرنے کیلئے بائیں سوائپ کریں"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"اپنی بگ رپورٹ کا اشتراک کرنے کیلئے تھپتھپائیں"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"بغیر اسکرین شاٹ کے بگ رپورٹ کا اشتراک کرنے کیلئے تھپتھپائیں یا اسکرین شاٹ کے ختم ہونے کا انتظار کریں"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"بغیر اسکرین شاٹ کے بگ رپورٹ کا اشتراک کرنے کیلئے تھپتھپائیں یا اسکرین شاٹ کے ختم ہونے کا انتظار کریں"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"بَگ رپورٹس میں سسٹم کی مختلف لاگ فائلوں سے ڈیٹا شامل ہوتا ہے، بشمول ذاتی اور نجی معلومات۔ بَگ رپورٹس کا اشتراک صرف اپنے بھروسے مند ایپس اور لوگوں کے ساتھ کریں۔"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"یہ پیغام اگلی بار دکھائیں"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"بگ رپورٹس"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> کی تفصیلات"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"فائل کا نام"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"تفصیلی وضاحت"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"بَگ کا عنوان"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"بَگ کا خلاصہ"</string>
+    <string name="save" msgid="4781509040564835759">"محفوظ کریں"</string>
 </resources>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index 39703a2..dd7f41b 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Terminal"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) tayyorlanmoqda"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) yozib olindi"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) tayyor, skrinshot kutilmoqda"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Xatoliklar hisobotiga tafsilotlar qo‘shilmoqda"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Iltimos, kuting…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Xatolik hisobotini yuborish uchun barmog‘ingiz bilan chapga suring"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Xatoliklar hisobotini ulashish uchun bosing"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Xatoliklar hisobotini darhol yuborish uchun shu yerga bosing yoki skrinshot saqlanguncha kuting"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Xatoliklar hisobotini darhol yuborish uchun shu yerga bosing yoki skrinshot saqlanguncha kuting"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Xatolik hisobotlari tizimdagi har xil jurnal fayllardagi ma’lumotlarni, shuningdek, shaxsiy hamda maxfiy ma’lumotlarni o‘z ichiga oladi. Xatolik hisobotlarini faqat ishonchli dasturlar va odamlar bilan bo‘lishing."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ushbu xabar keyingi safar ko‘rsatilsin"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Xatoliklar hisoboti"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) tafsilotlari"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fayl nomi"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Nomi"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Batafsil ta’rif"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Xatolik nomi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Xatolik ta’rifi"</string>
+    <string name="save" msgid="4781509040564835759">"Saqlash"</string>
 </resources>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index 16ffaff..2229991 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Báo cáo lỗi <xliff:g id="ID">#%d</xliff:g> đang được tạo"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Đã chụp báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Đã chụp báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>, đang chờ ảnh chụp màn hình"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Đang thêm thông tin chi tiết vào báo cáo lỗi"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Vui lòng đợi…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Vuốt sang trái để chia sẻ báo cáo lỗi của bạn"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Nhấn để chia sẻ báo cáo lỗi của bạn"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Bấm để chia sẻ báo cáo lỗi mà không cần ảnh chụp màn hình hoặc đợi hoàn tất ảnh chụp màn hình"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Bấm để chia sẻ báo cáo lỗi mà không cần ảnh chụp màn hình hoặc đợi hoàn tất ảnh chụp màn hình"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Các báo cáo lỗi chứa dữ liệu từ nhiều tệp nhật ký khác nhau của hệ thống, bao gồm cả thông tin cá nhân và riêng tư. Chỉ chia sẻ báo cáo lỗi với các ứng dụng và những người mà bạn tin tưởng."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Hiển thị thông báo này vào lần tới"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Báo cáo lỗi"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Không thể chụp ảnh màn hình."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Chi tiết báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Tên tệp"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tiêu đề"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Mô tả chi tiết"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Tiêu đề lỗi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Tóm tắt lỗi"</string>
+    <string name="save" msgid="4781509040564835759">"Lưu"</string>
 </resources>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index 382478e..b09a7d0 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在生成错误报告 <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"已捕获错误报告 <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"已捕获错误报告 <xliff:g id="ID">#%d</xliff:g>,但仍在等待屏幕截图完成"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"正在向错误报告添加详细信息"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"请稍候…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑动即可分享错误报告"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"点按即可分享您的错误报告"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"点按即可分享不含屏幕截图的错误报告;您也可以等待屏幕截图完成"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"点按即可分享不含屏幕截图的错误报告;您也可以等待屏幕截图完成"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"错误报告包含的数据来自于系统的各个日志文件,其中包含个人信息和隐私信息。请务必只与您信任的应用和用户分享错误报告。"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再显示这条讯息"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"错误报告"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"无法截图。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"错误报告 <xliff:g id="ID">#%d</xliff:g> 详情"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"文件名"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"标题"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"详细说明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"错误标题"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"错误摘要"</string>
+    <string name="save" msgid="4781509040564835759">"保存"</string>
 </resources>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 04b5e48..384eee7 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"命令介面"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在產生錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"已擷取錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"已擷取錯誤報告 <xliff:g id="ID">#%d</xliff:g>,但螢幕畫面仍未擷取完成"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"正在新增錯誤報告詳細資訊"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"請稍候…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"輕按即可分享錯誤報告"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"輕按以分享錯誤報告 (不包含螢幕擷圖),或等待螢幕畫面擷取完成"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"輕按以分享錯誤報告 (不包含螢幕擷圖),或等待螢幕畫面擷取完成"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告中有來自系統各個記錄檔案的資料,包括個人和私人資料。請只與您信任的應用程式和使用者分享錯誤報告。"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再顯示這則訊息"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳情"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"錯誤標題"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"錯誤摘要"</string>
+    <string name="save" msgid="4781509040564835759">"儲存"</string>
 </resources>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index 7a1ab77..2702bad 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"殼層"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在產生錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"已擷取錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 擷取成功,但螢幕畫面尚未擷取完畢"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"正在新增錯誤報告詳細資訊"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"請稍候…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"輕按即可分享錯誤報告"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"輕觸即可分享無螢幕擷圖的錯誤報告;您也可以等候螢幕畫面擷取完畢"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"輕觸即可分享無螢幕擷圖的錯誤報告;您也可以等候螢幕畫面擷取完畢"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告的資料來自系統各個紀錄檔,包括個人和私密資訊。請務必只與您信任的應用程式和使用者分享錯誤報告。"</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次仍顯示這則訊息"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳細資料"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"錯誤標題"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"錯誤摘要"</string>
+    <string name="save" msgid="4781509040564835759">"儲存"</string>
 </resources>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index 29b7dd83..561ac0a 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -19,10 +19,13 @@
     <string name="app_label" msgid="3701846017049540910">"I-Shell"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Umbiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g> uyacutshungulwa"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Umbiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g> uthwetshuliwe"</string>
+    <string name="bugreport_finished_pending_screenshot_title" msgid="5460883450679439591">"Umbiko wesiphazamisi esingu-<xliff:g id="ID">#%d</xliff:g> uthwetshuliwe kodwa isithombe-skrini silindile"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Ingeza imininingwane kumbiko wesiphazamisi"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Sicela ulinde..."</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swayiphela kwesokunxele ukuze wabelane umbiko wesiphazamiso sakho"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Thepha ukuze wabelane ngombiko wakho wesiphazamisi"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Thepha ukuze wabelane ngombiko wesiphazamisi ngaphandle kwesithombe-skrini noma ulinde isithombe-skrini ukuthi siqede"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Thepha ukuze wabelane ngombiko wesiphazamisi ngaphandle kwesithombe-skrini noma ulinde isithombe-skrini ukuthi siqede"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Imibiko yeziphazamisi iqukethe idatha yamafayela wokungena ahlukile wesistimu, afaka ulwazi lomuntu siqu noma lobumfihlo. Yabelana kuphela ngemibiko yeziphazamisi nezinhlelo zokusebenza nabantu obathembayo."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bonisa lo mlayezo ngesikhathi esilandelayo"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Imibiko yeziphazamiso"</string>
@@ -34,6 +37,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Imininingwane yombiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Igama lefayela"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Isihloko"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Incazelo enemininingwane"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Isihloko sesiphazamisi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Isifinyezo sesiphazamisi"</string>
+    <string name="save" msgid="4781509040564835759">"Londoloza"</string>
 </resources>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index c26b549..5d90189 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -20,6 +20,8 @@
     <string name="bugreport_in_progress_title">Bug report <xliff:g id="id">#%d</xliff:g> is being generated</string>
     <!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] -->
     <string name="bugreport_finished_title">Bug report <xliff:g id="id">#%d</xliff:g> captured</string>
+    <!-- Title of notification indicating a bugreport has been successfully captured, but screenshot is not finished yet. [CHAR LIMIT=50] -->
+    <string name="bugreport_finished_pending_screenshot_title">Bug report <xliff:g id="id">#%d</xliff:g> captured but screenshot pending</string>
     <!-- Title of notification indicating a bugreport is being updated before it can be shared. [CHAR LIMIT=50] -->
     <string name="bugreport_updating_title">Adding details to the bug report</string>
     <!-- Content notification indicating a bugreport is being updated before it can be shared, asking the user to wait [CHAR LIMIT=50] -->
@@ -29,7 +31,10 @@
     <string name="bugreport_finished_text" product="watch">Swipe left to share your bug report</string>
     <!-- Text of notification indicating that tapping will share the captured bugreport. [CHAR LIMIT=100] -->
     <string name="bugreport_finished_text" product="default">Tap to share your bug report</string>
-
+    <!-- Text of notification indicating that swipe left will share the captured bugreport, but giving user the option to wait for the screenshot. [CHAR LIMIT=100] -->
+    <string name="bugreport_finished_pending_screenshot_text" product="watch">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
+    <!-- Text of notification indicating that tapping will share the captured bugreport, but giving user the option to wait for the screenshot. [CHAR LIMIT=100] -->
+    <string name="bugreport_finished_pending_screenshot_text" product="default">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
 
     <!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
     <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information.  Only share bug reports with apps and people you trust.</string>
@@ -59,13 +64,16 @@
     <!--  Title of the dialog asking for user-defined bug report details like name, title, and description. -->
     <string name="bugreport_info_dialog_title">Bug report <xliff:g id="id">#%d</xliff:g> details</string>
 
-    <!-- Text of the hint asking for the bug report name, which when set will define a suffix in the
+    <!-- Text of the label identifying the bug report name, which when set will define a suffix in the
          bug report file names. [CHAR LIMIT=30] -->
     <string name="bugreport_info_name">Filename</string>
-    <!-- Text of hint asking for the bug report title, which when set will define the
+    <!-- Text of the label identifying the bug report title, which when set will define the
          Subject of the email message. [CHAR LIMIT=60] -->
-    <string name="bugreport_info_title">Title</string>
-    <!-- Text of hint asking for the bug report description, which when set will describe
+    <string name="bugreport_info_title">Bug title</string>
+    <!-- Text of the label identifying the bug report description, which when set will describe
          what the bug report is about. [CHAR LIMIT=NONE] -->
-    <string name="bugreport_info_description">Detailed description</string>
+    <string name="bugreport_info_description">Bug summary</string>
+
+    <!-- Label of button that save bugreport details.  -->
+    <string name="save">Save</string>
 </resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 9926ae5..c131fa5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -41,6 +41,8 @@
 import libcore.io.Streams;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.google.android.collect.Lists;
 
 import android.accounts.Account;
@@ -54,7 +56,6 @@
 import android.app.Service;
 import android.content.ClipData;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -119,8 +120,6 @@
     static final String INTENT_BUGREPORT_FINISHED = "android.intent.action.BUGREPORT_FINISHED";
     static final String INTENT_REMOTE_BUGREPORT_FINISHED =
             "android.intent.action.REMOTE_BUGREPORT_FINISHED";
-    static final String INTENT_REMOTE_BUGREPORT_DISPATCH =
-            "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
 
     // Internal intents used on notification actions.
     static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
@@ -147,6 +146,13 @@
     private static final int MSG_SCREENSHOT_REQUEST = 4;
     private static final int MSG_SCREENSHOT_RESPONSE = 5;
 
+    // Passed to Message.obtain() when msg.arg2 is not used.
+    private static final int UNUSED_ARG2 = -2;
+
+    // Maximum progress displayed (like 99.00%).
+    private static final int CAPPED_PROGRESS = 9900;
+    private static final int CAPPED_MAX = 10000;
+
     /**
      * Delay before a screenshot is taken.
      * <p>
@@ -203,7 +209,7 @@
         mMainHandler = new ServiceHandler("BugreportProgressServiceMainThread");
         mScreenshotHandler = new ScreenshotHandler("BugreportProgressServiceScreenshotThread");
 
-        mScreenshotsDir = new File(new ContextWrapper(mContext).getFilesDir(), SCREENSHOT_DIR);
+        mScreenshotsDir = new File(getFilesDir(), SCREENSHOT_DIR);
         if (!mScreenshotsDir.exists()) {
             Log.i(TAG, "Creating directory " + mScreenshotsDir + " to store temporary screenshots");
             if (!mScreenshotsDir.mkdir()) {
@@ -300,8 +306,7 @@
             }
             final String action = intent.getAction();
             final int pid = intent.getIntExtra(EXTRA_PID, 0);
-            // TODO: temporarily using pid as id until test cases and dumpstate are changed.
-            final int id = intent.getIntExtra(EXTRA_ID, pid);
+            final int id = intent.getIntExtra(EXTRA_ID, 0);
             final int max = intent.getIntExtra(EXTRA_MAX, -1);
             final String name = intent.getStringExtra(EXTRA_NAME);
 
@@ -404,10 +409,11 @@
 
         final BugreportInfo info = new BugreportInfo(mContext, id, pid, name, max);
         if (mProcesses.indexOfKey(id) >= 0) {
+            // BUGREPORT_STARTED intent was already received; ignore it.
             Log.w(TAG, "ID " + id + " already watched");
-        } else {
-            mProcesses.put(info.id, info);
+            return true;
         }
+        mProcesses.put(info.id, info);
         // Take initial screenshot.
         takeScreenshot(id, false);
         updateProgress(info);
@@ -426,16 +432,18 @@
         final NumberFormat nf = NumberFormat.getPercentInstance();
         nf.setMinimumFractionDigits(2);
         nf.setMaximumFractionDigits(2);
-        final String percentText = nf.format((double) info.progress / info.max);
+        final String percentageText = nf.format((double) info.progress / info.max);
         final Action cancelAction = new Action.Builder(null, mContext.getString(
                 com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
         final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
         infoIntent.setAction(INTENT_BUGREPORT_INFO_LAUNCH);
         infoIntent.putExtra(EXTRA_ID, info.id);
+        final PendingIntent infoPendingIntent =
+                PendingIntent.getService(mContext, info.id, infoIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
         final Action infoAction = new Action.Builder(null,
                 mContext.getString(R.string.bugreport_info_action),
-                PendingIntent.getService(mContext, info.id, infoIntent,
-                        PendingIntent.FLAG_UPDATE_CURRENT)).build();
+                infoPendingIntent).build();
         final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
         screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
         screenshotIntent.putExtra(EXTRA_ID, info.id);
@@ -451,20 +459,15 @@
         final String name =
                 info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
 
-        final Notification notification = new Notification.Builder(mContext)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+        final Notification notification = newBaseNotification(mContext)
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(name)
-                .setContentInfo(percentText)
+                .setContentInfo(percentageText)
                 .setProgress(info.max, info.progress, false)
                 .setOngoing(true)
-                .setLocalOnly(true)
-                .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
-                .addAction(infoAction)
-                .addAction(screenshotAction)
-                .addAction(cancelAction)
+                .setContentIntent(infoPendingIntent)
+                .setActions(infoAction, screenshotAction, cancelAction)
                 .build();
 
         if (info.finished) {
@@ -472,7 +475,10 @@
                     + info + ")");
             return;
         }
-        Log.v(TAG, "Sending 'Progress' notification for id " + info.id + ": " + percentText);
+        if (DEBUG) {
+            Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid
+                    + "): " + percentageText);
+        }
         NotificationManager.from(mContext).notify(TAG, info.id, notification);
     }
 
@@ -497,15 +503,16 @@
             Log.d(TAG, "Removing ID " + id);
             mProcesses.remove(id);
         }
-        stopSelfWhenDone();
         Log.v(TAG, "stopProgress(" + id + "): cancel notification");
         NotificationManager.from(mContext).cancel(TAG, id);
+        stopSelfWhenDone();
     }
 
     /**
      * Cancels a bugreport upon user's request.
      */
     private void cancel(int id) {
+        MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL);
         Log.v(TAG, "cancel: ID=" + id);
         final BugreportInfo info = getInfo(id);
         if (info != null && !info.finished) {
@@ -538,30 +545,52 @@
             final int pid = info.pid;
             final int id = info.id;
             if (info.finished) {
-                if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + "(id: " + id + ")");
+                if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + " (id: " + id + ")");
                 continue;
             }
             activeProcesses++;
             final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
-            final int progress = SystemProperties.getInt(progressKey, 0);
-            if (progress == 0) {
+            info.realProgress = SystemProperties.getInt(progressKey, 0);
+            if (info.realProgress == 0) {
                 Log.v(TAG, "System property " + progressKey + " is not set yet");
             }
-            final int max = SystemProperties.getInt(DUMPSTATE_PREFIX + pid + MAX_SUFFIX, 0);
-            final boolean maxChanged = max > 0 && max != info.max;
-            final boolean progressChanged = progress > 0 && progress != info.progress;
+            final String maxKey = DUMPSTATE_PREFIX + pid + MAX_SUFFIX;
+            info.realMax = SystemProperties.getInt(maxKey, info.max);
+            if (info.realMax <= 0 ) {
+                Log.w(TAG, "Property " + maxKey + " is not positive: " + info.max);
+                continue;
+            }
+            /*
+             * Checks whether the progress changed in a way that should be displayed to the user:
+             * - info.progress / info.max represents the displayed progress
+             * - info.realProgress / info.realMax represents the real progress
+             * - since the real progress can decrease, the displayed progress is only updated if it
+             *   increases
+             * - the displayed progress is capped at a maximum (like 99%)
+             */
+            final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
+            int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
+            int max = info.realMax;
+            int progress = info.realProgress;
 
-            if (progressChanged || maxChanged) {
-                if (progressChanged) {
-                    if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id
-                            + ") from " + info.progress + " to " + progress);
-                    info.progress = progress;
+            if (newPercentage > CAPPED_PROGRESS) {
+                progress = newPercentage = CAPPED_PROGRESS;
+                max = CAPPED_MAX;
+            }
+
+            if (newPercentage > oldPercentage) {
+                if (DEBUG) {
+                    if (progress != info.progress) {
+                        Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id + ") from "
+                                + info.progress + " to " + progress);
+                    }
+                    if (max != info.max) {
+                        Log.v(TAG, "Updating max progress for PID " + pid + "(id: " + id + ") from "
+                                + info.max + " to " + max);
+                    }
                 }
-                if (maxChanged) {
-                    Log.i(TAG, "Updating max progress for PID " + pid + "(id: " + id
-                            + ") from " + info.max + " to " + max);
-                    info.max = max;
-                }
+                info.progress = progress;
+                info.max = max;
                 info.lastUpdate = System.currentTimeMillis();
                 updateProgress(info);
             } else {
@@ -582,6 +611,7 @@
      * change its values.
      */
     private void launchBugreportInfoDialog(int id) {
+        MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS);
         // Copy values so it doesn't lock mProcesses while UI is being updated
         final String name, title, description;
         final BugreportInfo info = getInfo(id);
@@ -589,7 +619,8 @@
             // Most likely am killed Shell before user tapped the notification. Since system might
             // be too busy anwyays, it's better to ignore the notification and switch back to the
             // non-interactive mode (where the bugerport will be shared upon completion).
-            Log.d(TAG, "launchBugreportInfoDialog(" + id + "): cancel notification");
+            Log.w(TAG, "launchBugreportInfoDialog(): canceling notification because id " + id
+                    + " was not found");
             // TODO: add test case to make sure notification is canceled.
             NotificationManager.from(mContext).cancel(TAG, id);
             return;
@@ -610,11 +641,17 @@
      * upon receiving a {@link #INTENT_BUGREPORT_STARTED}.
      */
     private void takeScreenshot(int id, boolean delayed) {
+        if (delayed) {
+            // Only logs screenshots requested from the notification action.
+            MetricsLogger.action(this,
+                    MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT);
+        }
         if (getInfo(id) == null) {
             // Most likely am killed Shell before user tapped the notification. Since system might
             // be too busy anwyays, it's better to ignore the notification and switch back to the
             // non-interactive mode (where the bugerport will be shared upon completion).
-            Log.d(TAG, "takeScreenshot(" + id + ", " + delayed + "): cancel notification");
+            Log.w(TAG, "takeScreenshot(): canceling notification because id " + id
+                    + " was not found");
             // TODO: add test case to make sure notification is canceled.
             NotificationManager.from(mContext).cancel(TAG, id);
             return;
@@ -657,11 +694,8 @@
         final String screenshotPath =
                 new File(mScreenshotsDir, info.getPathNextScreenshot()).getAbsolutePath();
 
-        final Message requestMsg = new Message();
-        requestMsg.what = MSG_SCREENSHOT_REQUEST;
-        requestMsg.arg1 = id;
-        requestMsg.obj = screenshotPath;
-        mScreenshotHandler.sendMessage(requestMsg);
+        Message.obtain(mScreenshotHandler, MSG_SCREENSHOT_REQUEST, id, UNUSED_ARG2, screenshotPath)
+                .sendToTarget();
     }
 
     /**
@@ -687,12 +721,8 @@
         boolean taken = takeScreenshot(mContext, screenshotFile);
         setTakingScreenshot(false);
 
-        final Message resultMsg = new Message();
-        resultMsg.what = MSG_SCREENSHOT_RESPONSE;
-        resultMsg.arg1 = requestMsg.arg1;
-        resultMsg.arg2 = taken ? 1 : 0;
-        resultMsg.obj = screenshotFile;
-        mMainHandler.sendMessage(resultMsg);
+        Message.obtain(mMainHandler, MSG_SCREENSHOT_RESPONSE, requestMsg.arg1, taken ? 1 : 0,
+                screenshotFile).sendToTarget();
     }
 
     private void handleScreenshotResponse(Message resultMsg) {
@@ -703,22 +733,21 @@
         }
         final File screenshotFile = new File((String) resultMsg.obj);
 
-        final int msgId;
+        final String msg;
         if (taken) {
             info.addScreenshot(screenshotFile);
             if (info.finished) {
                 Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
                 info.renameScreenshots(mScreenshotsDir);
-                sendBugreportNotification(mContext, info);
+                sendBugreportNotification(mContext, info, mTakingScreenshot);
             }
-            msgId = R.string.bugreport_screenshot_taken;
+            msg = mContext.getString(R.string.bugreport_screenshot_taken);
         } else {
             // TODO: try again using Framework APIs instead of relying on screencap.
-            msgId = R.string.bugreport_screenshot_failed;
+            msg = mContext.getString(R.string.bugreport_screenshot_failed);
+            Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
         }
-        final String msg = mContext.getString(msgId);
         Log.d(TAG, msg);
-        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
     }
 
     /**
@@ -764,6 +793,12 @@
         info.renameScreenshots(mScreenshotsDir);
         info.bugreportFile = bugreportFile;
 
+        final int max = intent.getIntExtra(EXTRA_MAX, -1);
+        if (max != -1) {
+            MetricsLogger.histogram(this, "dumpstate_duration", max);
+            info.max = max;
+        }
+
         final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
         if (screenshot != null) {
             info.addScreenshot(screenshot);
@@ -793,10 +828,10 @@
         boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
         if (!isPlainText) {
             // Already zipped, send it right away.
-            sendBugreportNotification(context, info);
+            sendBugreportNotification(context, info, mTakingScreenshot);
         } else {
             // Asynchronously zip the file first, then send it.
-            sendZippedBugreportNotification(context, info);
+            sendZippedBugreportNotification(context, info, mTakingScreenshot);
         }
     }
 
@@ -859,12 +894,15 @@
      * intent, but issuing a warning dialog the first time.
      */
     private void shareBugreport(int id, BugreportInfo sharedInfo) {
+        MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE);
         BugreportInfo info = getInfo(id);
         if (info == null) {
             // Service was terminated but notification persisted
             info = sharedInfo;
             Log.d(TAG, "shareBugreport(): no info for ID " + id + " on managed processes ("
                     + mProcesses + "), using info from intent instead (" + info + ")");
+        } else {
+            Log.v(TAG, "shareBugReport(): id " + id + " info = " + info);
         }
 
         addDetailsToZipFile(mContext, info);
@@ -890,7 +928,8 @@
     /**
      * Sends a notification indicating the bugreport has finished so use can share it.
      */
-    private static void sendBugreportNotification(Context context, BugreportInfo info) {
+    private static void sendBugreportNotification(Context context, BugreportInfo info,
+            boolean takingScreenshot) {
 
         // Since adding the details can take a while, do it before notifying user.
         addDetailsToZipFile(context, info);
@@ -901,18 +940,22 @@
         shareIntent.putExtra(EXTRA_ID, info.id);
         shareIntent.putExtra(EXTRA_INFO, info);
 
-        final String title = context.getString(R.string.bugreport_finished_title, info.id);
-        final Notification.Builder builder = new Notification.Builder(context)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+        final String title, content;
+        if (takingScreenshot) {
+            title = context.getString(R.string.bugreport_finished_pending_screenshot_title,
+                    info.id);
+            content = context.getString(R.string.bugreport_finished_pending_screenshot_text);
+        } else {
+            title = context.getString(R.string.bugreport_finished_title, info.id);
+            content = context.getString(R.string.bugreport_finished_text);
+        }
+        final Notification.Builder builder = newBaseNotification(context)
                 .setContentTitle(title)
                 .setTicker(title)
-                .setContentText(context.getString(R.string.bugreport_finished_text))
+                .setContentText(content)
                 .setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
                         PendingIntent.FLAG_UPDATE_CURRENT))
-                .setDeleteIntent(newCancelIntent(context, info))
-                .setLocalOnly(true)
-                .setColor(context.getColor(
-                        com.android.internal.R.color.system_notification_accent_color));
+                .setDeleteIntent(newCancelIntent(context, info));
 
         if (!TextUtils.isEmpty(info.name)) {
             builder.setContentInfo(info.name);
@@ -929,28 +972,33 @@
      */
     private static void sendBugreportBeingUpdatedNotification(Context context, int id) {
         final String title = context.getString(R.string.bugreport_updating_title);
-        final Notification.Builder builder = new Notification.Builder(context)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+        final Notification.Builder builder = newBaseNotification(context)
                 .setContentTitle(title)
                 .setTicker(title)
-                .setContentText(context.getString(R.string.bugreport_updating_wait))
+                .setContentText(context.getString(R.string.bugreport_updating_wait));
+        Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
+        NotificationManager.from(context).notify(TAG, id, builder.build());
+    }
+
+    private static Notification.Builder newBaseNotification(Context context) {
+        return new Notification.Builder(context)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
                 .setLocalOnly(true)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
-        Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
-        NotificationManager.from(context).notify(TAG, id, builder.build());
     }
 
     /**
      * Sends a zipped bugreport notification.
      */
     private static void sendZippedBugreportNotification(final Context context,
-            final BugreportInfo info) {
+            final BugreportInfo info, final boolean takingScreenshot) {
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
                 zipBugreport(info);
-                sendBugreportNotification(context, info);
+                sendBugreportNotification(context, info, takingScreenshot);
                 return null;
             }
         }.execute();
@@ -1076,7 +1124,14 @@
             preferredDomain = "@" + preferredDomain;
         }
 
-        final Account[] accounts = am.getAccounts();
+        final Account[] accounts;
+        try {
+            accounts = am.getAccounts();
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Could not get accounts for preferred domain " + preferredDomain, e);
+            return null;
+        }
+        if (DEBUG) Log.d(TAG, "Number of accounts: " + accounts.length);
         Account foundAccount = null;
         for (Account account : accounts) {
             if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
@@ -1113,7 +1168,7 @@
 
     private static boolean setSystemProperty(String key, String value) {
         try {
-            if (DEBUG) Log.v(TAG, "Setting system property" + key + " to " + value);
+            if (DEBUG) Log.v(TAG, "Setting system property " + key + " to " + value);
             SystemProperties.set(key, value);
         } catch (IllegalArgumentException e) {
             Log.e(TAG, "Could not set property " + key + " to " + value, e);
@@ -1139,9 +1194,16 @@
         if (info == null) {
             return;
         }
+        if (title != null && !title.equals(info.title)) {
+            MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_TITLE_CHANGED);
+        }
         info.title = title;
+        if (description != null && !description.equals(info.description)) {
+            MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED);
+        }
         info.description = description;
         if (name != null && !name.equals(info.name)) {
+            MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_NAME_CHANGED);
             info.name = name;
             updateProgress(info);
         }
@@ -1161,14 +1223,13 @@
      * Takes a screenshot and save it to the given location.
      */
     private static boolean takeScreenshot(Context context, String screenshotFile) {
-        ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE))
-                .vibrate(150);
         final ProcessBuilder screencap = new ProcessBuilder()
                 .command("/system/bin/screencap", "-p", screenshotFile);
         Log.d(TAG, "Taking screenshot using " + screencap.command());
         try {
             final int exitValue = screencap.start().waitFor();
             if (exitValue == 0) {
+                ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150);
                 return true;
             }
             Log.e(TAG, "screencap (" + screencap.command() + ") failed: " + exitValue);
@@ -1229,7 +1290,9 @@
         /**
          * Sets its internal state and displays the dialog.
          */
-        private void initialize(Context context, BugreportInfo info) {
+        private void initialize(final Context context, BugreportInfo info) {
+            final String dialogTitle =
+                    context.getString(R.string.bugreport_info_dialog_title, info.id);
             // First initializes singleton.
             if (mDialog == null) {
                 @SuppressLint("InflateParams")
@@ -1253,9 +1316,9 @@
 
                 mDialog = new AlertDialog.Builder(context)
                         .setView(view)
-                        .setTitle(context.getString(R.string.bugreport_info_dialog_title, info.id))
+                        .setTitle(dialogTitle)
                         .setCancelable(false)
-                        .setPositiveButton(context.getString(com.android.internal.R.string.ok),
+                        .setPositiveButton(context.getString(R.string.save),
                                 null)
                         .setNegativeButton(context.getString(com.android.internal.R.string.cancel),
                                 new DialogInterface.OnClickListener()
@@ -1263,6 +1326,8 @@
                                     @Override
                                     public void onClick(DialogInterface dialog, int id)
                                     {
+                                        MetricsLogger.action(context,
+                                                MetricsEvent.ACTION_BUGREPORT_DETAILS_CANCELED);
                                         if (!mTempName.equals(mSavedName)) {
                                             // Must restore dumpstate's name since it was changed
                                             // before user clicked OK.
@@ -1276,6 +1341,12 @@
                         new WindowManager.LayoutParams(
                                 WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG));
 
+            } else {
+                // Re-use view, but reset fields first.
+                mDialog.setTitle(dialogTitle);
+                mInfoName.setText(null);
+                mInfoTitle.setText(null);
+                mInfoDescription.setText(null);
             }
 
             // Then set fields.
@@ -1307,6 +1378,7 @@
 
                     @Override
                     public void onClick(View view) {
+                        MetricsLogger.action(context, MetricsEvent.ACTION_BUGREPORT_DETAILS_SAVED);
                         sanitizeName();
                         final String name = mInfoName.getText().toString();
                         final String title = mInfoTitle.getText().toString();
@@ -1350,7 +1422,7 @@
             // Must update system property for the cases where dumpstate finishes
             // while the user is still entering other fields (like title or
             // description)
-            setBugreportNameProperty(mId, name);
+            setBugreportNameProperty(mPid, name);
         }
 
        /**
@@ -1405,16 +1477,26 @@
         String description;
 
         /**
-         * Maximum progress of the bugreport generation.
+         * Maximum progress of the bugreport generation as displayed by the UI.
          */
         int max;
 
         /**
-         * Current progress of the bugreport generation.
+         * Current progress of the bugreport generation as displayed by the UI.
          */
         int progress;
 
         /**
+         * Maximum progress of the bugreport generation as reported by dumpstate.
+         */
+        int realMax;
+
+        /**
+         * Current progress of the bugreport generation as reported by dumpstate.
+         */
+        int realProgress;
+
+        /**
          * Time of the last progress update.
          */
         long lastUpdate = System.currentTimeMillis();
@@ -1495,10 +1577,11 @@
             final List<File> renamedFiles = new ArrayList<>(screenshotFiles.size());
             for (File oldFile : screenshotFiles) {
                 final String oldName = oldFile.getName();
-                final String newName = oldName.replace(Integer.toString(pid), name);
+                final String newName = oldName.replaceFirst(Integer.toString(pid), name);
                 final File newFile;
                 if (!newName.equals(oldName)) {
                     final File renamedFile = new File(screenshotDir, newName);
+                    Log.d(TAG, "Renaming screenshot file " + oldFile + " to " + renamedFile);
                     newFile = oldFile.renameTo(renamedFile) ? renamedFile : oldFile;
                 } else {
                     Log.w(TAG, "Name didn't change: " + oldName); // Shouldn't happen.
@@ -1522,10 +1605,12 @@
         @Override
         public String toString() {
             final float percent = ((float) progress * 100 / max);
+            final float realPercent = ((float) realProgress * 100 / realMax);
             return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
                     + "\n\ttitle: " + title + "\n\tdescription: " + description
                     + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
-                    + "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
+                    + "\n\tprogress: " + progress + "/" + max + " (" + percent + ")"
+                    + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent + ")"
                     + "\n\tlast_update: " + getFormattedLastUpdate()
                     + "\naddingDetailsToZip: " + addingDetailsToZip
                     + " addedDetailsToZip: " + addedDetailsToZip;
@@ -1541,6 +1626,8 @@
             description = in.readString();
             max = in.readInt();
             progress = in.readInt();
+            realMax = in.readInt();
+            realProgress = in.readInt();
             lastUpdate = in.readLong();
             formattedLastUpdate = in.readString();
             bugreportFile = readFile(in);
@@ -1563,6 +1650,8 @@
             dest.writeString(description);
             dest.writeInt(max);
             dest.writeInt(progress);
+            dest.writeInt(realMax);
+            dest.writeInt(realProgress);
             dest.writeLong(lastUpdate);
             dest.writeString(getFormattedLastUpdate());
             writeFile(dest, bugreportFile);
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index 9afa900..cbd17bf 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -51,6 +51,7 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "onReceive: " + intent);
         // Clean up older bugreports in background
         cleanupOldFiles(this, intent, INTENT_BUGREPORT_FINISHED, MIN_KEEP_COUNT, MIN_KEEP_AGE);
 
diff --git a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
index be54b43..634c3b4 100644
--- a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
@@ -18,13 +18,13 @@
 
 import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
 import static com.android.shell.BugreportProgressService.INTENT_REMOTE_BUGREPORT_FINISHED;
-import static com.android.shell.BugreportProgressService.INTENT_REMOTE_BUGREPORT_DISPATCH;
 import static com.android.shell.BugreportProgressService.getFileExtra;
 import static com.android.shell.BugreportProgressService.getUri;
 import static com.android.shell.BugreportReceiver.cleanupOldFiles;
 
 import java.io.File;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -41,8 +41,6 @@
 public class RemoteBugreportReceiver extends BroadcastReceiver {
 
     private static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
-    private static final String EXTRA_REMOTE_BUGREPORT_HASH =
-            "android.intent.extra.REMOTE_BUGREPORT_HASH";
 
     /** Always keep just the last remote bugreport's files around. */
     private static final int REMOTE_BUGREPORT_FILES_AMOUNT = 3;
@@ -57,11 +55,12 @@
 
         final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
         final Uri bugreportUri = getUri(context, bugreportFile);
-        final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
+        final String bugreportHash = intent.getStringExtra(
+                DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
 
-        final Intent newIntent = new Intent(INTENT_REMOTE_BUGREPORT_DISPATCH);
+        final Intent newIntent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
         newIntent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
-        newIntent.putExtra(EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
+        newIntent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
         context.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM,
                 android.Manifest.permission.DUMP);
     }
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 8c62670..e1e0c3b 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -19,12 +19,14 @@
 import static android.test.MoreAsserts.assertContainsRegex;
 import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
 import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
+import static com.android.shell.BugreportProgressService.EXTRA_ID;
 import static com.android.shell.BugreportProgressService.EXTRA_MAX;
 import static com.android.shell.BugreportProgressService.EXTRA_NAME;
 import static com.android.shell.BugreportProgressService.EXTRA_PID;
 import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
+import static com.android.shell.BugreportProgressService.POLLING_FREQUENCY;
 import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
 
 import java.io.BufferedOutputStream;
@@ -60,6 +62,7 @@
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.text.TextUtils;
@@ -90,7 +93,7 @@
     private static final String TAG = "BugreportReceiverTest";
 
     // Timeout for UI operations, in milliseconds.
-    private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;
+    private static final int TIMEOUT = (int) POLLING_FREQUENCY * 4;
 
     // Timeout for when waiting for a screenshot to finish.
     private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
@@ -98,31 +101,44 @@
     private static final String BUGREPORTS_DIR = "bugreports";
     private static final String BUGREPORT_FILE = "test_bugreport.txt";
     private static final String ZIP_FILE = "test_bugreport.zip";
+    private static final String ZIP_FILE2 = "test_bugreport2.zip";
     private static final String SCREENSHOT_FILE = "test_screenshot.png";
 
     private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n";
     private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n";
 
     private static final int PID = 42;
-    private static final String PROGRESS_PROPERTY = "dumpstate.42.progress";
-    private static final String MAX_PROPERTY = "dumpstate.42.max";
-    private static final String NAME_PROPERTY = "dumpstate.42.name";
+    private static final int PID2 = 24;
+    private static final int ID = 108;
+    private static final int ID2 = 801;
+    private static final String PROGRESS_PROPERTY = "dumpstate." + PID + ".progress";
+    private static final String MAX_PROPERTY = "dumpstate." + PID + ".max";
+    private static final String NAME_PROPERTY = "dumpstate." + PID + ".name";
     private static final String NAME = "BUG, Y U NO REPORT?";
+    private static final String NAME2 = "A bugreport's life";
     private static final String NEW_NAME = "Bug_Forrest_Bug";
+    private static final String NEW_NAME2 = "BugsyReportsy";
     private static final String TITLE = "Wimbugdom Champion 2015";
+    private static final String TITLE2 = "Master of the Universe";
+    private static final String DESCRIPTION = "One's description...";
+    private static final String DESCRIPTION2 = "...is another's treasure.";
 
     private static final String NO_DESCRIPTION = null;
     private static final String NO_NAME = null;
     private static final String NO_SCREENSHOT = null;
     private static final String NO_TITLE = null;
-    private static final int NO_PID = 0;
+    private static final int NO_ID = 0;
     private static final boolean RENAMED_SCREENSHOTS = true;
     private static final boolean DIDNT_RENAME_SCREENSHOTS = false;
 
+    private static final boolean PENDING_SCREENSHOT = true;
+    private static final boolean NOT_PENDING_SCREENSHOT = false;
+
     private String mDescription;
 
     private String mPlainTextPath;
     private String mZipPath;
+    private String mZipPath2;
     private String mScreenshotPath;
 
     private Context mContext;
@@ -141,10 +157,12 @@
 
         mPlainTextPath = getPath(BUGREPORT_FILE);
         mZipPath = getPath(ZIP_FILE);
+        mZipPath2 = getPath(ZIP_FILE2);
         mScreenshotPath = getPath(SCREENSHOT_FILE);
         createTextFile(mPlainTextPath, BUGREPORT_CONTENT);
         createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
         createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
+        createZipFile(mZipPath2, BUGREPORT_FILE, BUGREPORT_CONTENT);
 
         // Creates a multi-line description.
         StringBuilder sb = new StringBuilder();
@@ -173,17 +191,58 @@
         SystemProperties.set(PROGRESS_PROPERTY, "500");
         assertProgressNotification(NAME, nf.format(0.50));
 
+        SystemProperties.set(PROGRESS_PROPERTY, "950");
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        // Make sure progress never goes back...
         SystemProperties.set(MAX_PROPERTY, "2000");
-        assertProgressNotification(NAME, nf.format(0.25));
+        Thread.sleep(POLLING_FREQUENCY + DateUtils.SECOND_IN_MILLIS);
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "1000");
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        // ...only forward...
+        SystemProperties.set(PROGRESS_PROPERTY, "1902");
+        assertProgressNotification(NAME, nf.format(0.9510));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "1960");
+        assertProgressNotification(NAME, nf.format(0.98));
+
+        // ...but never more than the capped value.
+        SystemProperties.set(PROGRESS_PROPERTY, "2000");
+        assertProgressNotification(NAME, nf.format(0.99));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "3000");
+        assertProgressNotification(NAME, nf.format(0.99));
 
         Bundle extras =
-                sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+                sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
 
         assertServiceNotRunning();
     }
 
+    public void testProgress_cancel() throws Exception {
+        resetProperties();
+        sendBugreportStarted(1000);
+        waitForScreenshotButtonEnabled(true);
+
+        final NumberFormat nf = NumberFormat.getPercentInstance();
+        nf.setMinimumFractionDigits(2);
+        nf.setMaximumFractionDigits(2);
+
+        assertProgressNotification(NAME, nf.format(0));
+
+        openProgressNotification(ID);
+        UiObject cancelButton = mUiBot.getVisibleObject(mContext.getString(
+                com.android.internal.R.string.cancel).toUpperCase());
+        mUiBot.click(cancelButton, "cancel_button");
+
+        waitForService(false);
+    }
+
     public void testProgress_takeExtraScreenshot() throws Exception {
         takeExtraScreenshotTest(false);
     }
@@ -201,15 +260,15 @@
         assertScreenshotButtonEnabled(false);
         waitForScreenshotButtonEnabled(true);
 
-        sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+        sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
 
         if (serviceDies) {
-            waitShareNotification(PID);
+            waitShareNotification(ID);
             killService();
         }
 
-        Bundle extras = acceptBugreportAndGetSharedIntent(PID);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                 NAME, NO_TITLE, NO_DESCRIPTION, 2, RENAMED_SCREENSHOTS);
 
         assertServiceNotRunning();
@@ -227,8 +286,8 @@
         resetProperties();
 
         sendBugreportStarted(1000);
-        sendBugreportFinished(PID, mPlainTextPath, NO_SCREENSHOT);
-        waitShareNotification(PID);
+        sendBugreportFinished(ID, mPlainTextPath, NO_SCREENSHOT);
+        waitShareNotification(ID);
 
         // There's no indication in the UI about the screenshot finish, so just sleep like a baby...
         Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
@@ -237,8 +296,8 @@
             killService();
         }
 
-        Bundle extras = acceptBugreportAndGetSharedIntent(PID);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, PID, ZIP_FILE,
+        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
                 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
 
         assertServiceNotRunning();
@@ -249,13 +308,13 @@
         sendBugreportStarted(1000);
         waitForScreenshotButtonEnabled(true);
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
 
         // Check initial name.
-        String actualName = detailsUi.nameField.getText().toString();
-        assertEquals("Wrong value on field 'name'", NAME, actualName);
+        detailsUi.assertName(NAME);
 
         // Change name - it should have changed system property once focus is changed.
+        detailsUi.focusOnName();
         detailsUi.nameField.setText(NEW_NAME);
         detailsUi.focusAwayFromName();
         assertPropertyValue(NAME_PROPERTY, NEW_NAME);
@@ -281,9 +340,9 @@
         assertPropertyValue(NAME_PROPERTY, NEW_NAME);
         assertProgressNotification(NEW_NAME, "0.00%");
 
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath,
                 mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
                 NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
 
         assertServiceNotRunning();
@@ -302,11 +361,10 @@
         sendBugreportStarted(1000);
         waitForScreenshotButtonEnabled(true);
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
 
         // Check initial name.
-        String actualName = detailsUi.nameField.getText().toString();
-        assertEquals("Wrong value on field 'name'", NAME, actualName);
+        detailsUi.assertName(NAME);
 
         // Change fields.
         detailsUi.reOpen();
@@ -319,33 +377,86 @@
         assertPropertyValue(NAME_PROPERTY, NEW_NAME);
         assertProgressNotification(NEW_NAME, "0.00%");
 
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID,
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID,
                 plainText? mPlainTextPath : mZipPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
                 NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
 
         assertServiceNotRunning();
     }
 
-    public void testProgress_changeJustDetails() throws Exception {
+    public void testProgress_changeJustDetailsTouchingDetails() throws Exception {
+        changeJustDetailsTest(true);
+    }
+
+    public void testProgress_changeJustDetailsTouchingNotification() throws Exception {
+        changeJustDetailsTest(false);
+    }
+
+    private void changeJustDetailsTest(boolean touchDetails) throws Exception {
         resetProperties();
         sendBugreportStarted(1000);
         waitForScreenshotButtonEnabled(true);
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, touchDetails);
 
         detailsUi.nameField.setText("");
         detailsUi.titleField.setText("");
         detailsUi.descField.setText(mDescription);
         detailsUi.clickOk();
 
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mZipPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                 NO_NAME, NO_TITLE, mDescription, 1, DIDNT_RENAME_SCREENSHOTS);
 
         assertServiceNotRunning();
     }
 
+    /*
+     * TODO: this test can be flanky because it relies in the order the notifications are displayed,
+     * since mUiBot gets the first notification.
+     * Ideally, openProgressNotification() should return the whole notification, so DetailsUi
+     * could use it and find children instead, but unfortunately the notification object hierarchy
+     * is too complex and getting it from the notification text object would be to fragile
+     * (for instance, it could require navigating many parents up in the hierarchy).
+     */
+    public void testProgress_changeJustDetailsIsClearedOnSecondBugreport() throws Exception {
+        resetProperties();
+        sendBugreportStarted(ID, PID, NAME, 1000);
+        waitForScreenshotButtonEnabled(true);
+
+        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
+        detailsUi.assertName(NAME);
+        detailsUi.assertTitle("");
+        detailsUi.assertDescription("");
+        detailsUi.nameField.setText(NEW_NAME);
+        detailsUi.titleField.setText(TITLE);
+        detailsUi.descField.setText(DESCRIPTION);
+        detailsUi.clickOk();
+
+        sendBugreportStarted(ID2, PID2, NAME2, 1000);
+
+        sendBugreportFinished(ID, mZipPath, mScreenshotPath);
+        Bundle extras = acceptBugreportAndGetSharedIntent(ID, PENDING_SCREENSHOT);
+
+        detailsUi = new DetailsUi(mUiBot, ID2);
+        detailsUi.assertName(NAME2);
+        detailsUi.assertTitle("");
+        detailsUi.assertDescription("");
+        detailsUi.nameField.setText(NEW_NAME2);
+        detailsUi.titleField.setText(TITLE2);
+        detailsUi.descField.setText(DESCRIPTION2);
+        detailsUi.clickOk();
+
+        // Must use a different zip file otherwise it will fail because zip already contains
+        // title.txt and description.txt entries.
+        extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2,
+                NEW_NAME2, TITLE2, DESCRIPTION2, 1, RENAMED_SCREENSHOTS);
+
+        assertServiceNotRunning();
+    }
+
     /**
      * Tests the scenario where the initial screenshot and dumpstate are finished while the user
      * is changing the info in the details screen.
@@ -369,14 +480,14 @@
             waitForScreenshotButtonEnabled(true);
         }
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
 
         // Finish the bugreport while user's still typing the name.
         detailsUi.nameField.setText(NEW_NAME);
-        sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+        sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
 
         // Wait until the share notification is received...
-        waitShareNotification(PID);
+        waitShareNotification(ID);
         // ...then close notification bar.
         mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
 
@@ -390,8 +501,8 @@
         detailsUi.clickOk();
 
         // Finally, share bugreport.
-        Bundle extras = acceptBugreportAndGetSharedIntent(PID);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
                 NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
 
         assertServiceNotRunning();
@@ -402,8 +513,8 @@
         BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
 
         // Send notification and click on share.
-        sendBugreportFinished(NO_PID, mPlainTextPath, null);
-        acceptBugreport(NO_PID);
+        sendBugreportFinished(NO_ID, mPlainTextPath, null);
+        acceptBugreport(NO_ID);
 
         // Handle the warning
         mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
@@ -425,9 +536,9 @@
     }
 
     public void testShareBugreportAfterServiceDies() throws Exception {
-        sendBugreportFinished(NO_PID, mPlainTextPath, NO_SCREENSHOT);
+        sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
         killService();
-        Bundle extras = acceptBugreportAndGetSharedIntent(NO_PID);
+        Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
     }
 
@@ -463,32 +574,38 @@
     private void assertProgressNotification(String name, String percent) {
         // TODO: it currently looks for 3 distinct objects, without taking advantage of their
         // relationship.
-        openProgressNotification(PID);
+        openProgressNotification(ID);
         Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'");
         mUiBot.getObject(name);
         mUiBot.getObject(percent);
     }
 
-    private void openProgressNotification(int pid) {
-        String title = mContext.getString(R.string.bugreport_in_progress_title, pid);
+    private UiObject openProgressNotification(int id) {
+        String title = mContext.getString(R.string.bugreport_in_progress_title, id);
         Log.v(TAG, "Looking for progress notification title: '" + title + "'");
-        mUiBot.getNotification(title);
+        return mUiBot.getNotification(title);
     }
 
     void resetProperties() {
         // TODO: call method to remove property instead
-        SystemProperties.set(PROGRESS_PROPERTY, "0");
-        SystemProperties.set(MAX_PROPERTY, "0");
+        SystemProperties.set(PROGRESS_PROPERTY, "Reset");
+        SystemProperties.set(MAX_PROPERTY, "Reset");
+        SystemProperties.set(NAME_PROPERTY, "Reset");
     }
 
     /**
      * Sends a "bugreport started" intent with the default values.
      */
     private void sendBugreportStarted(int max) throws Exception {
+        sendBugreportStarted(ID, PID, NAME, max);
+    }
+
+    private void sendBugreportStarted(int id, int pid, String name, int max) throws Exception {
         Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        intent.putExtra(EXTRA_PID, PID);
-        intent.putExtra(EXTRA_NAME, NAME);
+        intent.putExtra(EXTRA_ID, id);
+        intent.putExtra(EXTRA_PID, pid);
+        intent.putExtra(EXTRA_NAME, name);
         intent.putExtra(EXTRA_MAX, max);
         mContext.sendBroadcast(intent);
     }
@@ -500,7 +617,7 @@
      */
     private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath,
             String screenshotPath) {
-        return sendBugreportFinishedAndGetSharedIntent(NO_PID, bugreportPath, screenshotPath);
+        return sendBugreportFinishedAndGetSharedIntent(NO_ID, bugreportPath, screenshotPath);
     }
 
     /**
@@ -508,10 +625,10 @@
      *
      * @return extras sent in the shared intent.
      */
-    private Bundle sendBugreportFinishedAndGetSharedIntent(int pid, String bugreportPath,
+    private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
             String screenshotPath) {
-        sendBugreportFinished(pid, bugreportPath, screenshotPath);
-        return acceptBugreportAndGetSharedIntent(pid);
+        sendBugreportFinished(id, bugreportPath, screenshotPath);
+        return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT);
     }
 
     /**
@@ -519,8 +636,12 @@
      *
      * @return extras sent in the shared intent.
      */
-    private Bundle acceptBugreportAndGetSharedIntent(int pid) {
-        acceptBugreport(pid);
+    private Bundle acceptBugreportAndGetSharedIntent(int id) {
+        return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT);
+    }
+
+    private Bundle acceptBugreportAndGetSharedIntent(int id, boolean pendingScreenshot) {
+        acceptBugreport(id, pendingScreenshot);
         mUiBot.chooseActivity(UI_NAME);
         return mListener.getExtras();
     }
@@ -528,25 +649,31 @@
     /**
      * Waits for the notification to share the finished bugreport.
      */
-    private void waitShareNotification(int pid) {
-        mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, pid));
+    private void waitShareNotification(int id) {
+        mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, id));
     }
 
     /**
      * Accepts the notification to share the finished bugreport.
      */
-    private void acceptBugreport(int pid) {
-        mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, pid));
+    private void acceptBugreport(int id) {
+        acceptBugreport(id, NOT_PENDING_SCREENSHOT);
+    }
+
+    private void acceptBugreport(int id, boolean pendingScreenshot) {
+        final int res = pendingScreenshot ? R.string.bugreport_finished_pending_screenshot_title
+                : R.string.bugreport_finished_title;
+        mUiBot.clickOnNotification(mContext.getString(res, id));
     }
 
     /**
      * Sends a "bugreport finished" intent.
      */
-    private void sendBugreportFinished(int pid, String bugreportPath, String screenshotPath) {
+    private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) {
         Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        if (pid != NO_PID) {
-            intent.putExtra(EXTRA_PID, pid);
+        if (id != NO_ID) {
+            intent.putExtra(EXTRA_ID, id);
         }
         if (bugreportPath != null) {
             intent.putExtra(EXTRA_BUGREPORT, bugreportPath);
@@ -563,7 +690,7 @@
      */
     private void assertActionSendMultiple(Bundle extras, String bugreportContent,
             String screenshotContent) throws IOException {
-        assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, ZIP_FILE,
+        assertActionSendMultiple(extras, bugreportContent, screenshotContent, ID, PID, ZIP_FILE,
                 NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS);
     }
 
@@ -573,6 +700,7 @@
      * @param extras extras received in the intent
      * @param bugreportContent expected content in the bugreport file
      * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any
+     * @param id emulated dumpstate id
      * @param pid emulated dumpstate pid
      * @param name expected subject
      * @param name bugreport name as provided by the user (or received by dumpstate)
@@ -582,7 +710,7 @@
      * @param renamedScreenshots whether the screenshots are expected to be renamed
      */
     private void assertActionSendMultiple(Bundle extras, String bugreportContent,
-            String screenshotContent, int pid, String subject,
+            String screenshotContent, int id, int pid, String subject,
             String name, String title, String description,
             int numberScreenshots, boolean renamedScreenshots) throws IOException {
         String body = extras.getString(Intent.EXTRA_TEXT);
@@ -745,7 +873,7 @@
         fail("Service status didn't change to " + expectRunning);
     }
 
-    private static void createTextFile(String path, String content) throws IOException {
+    private void createTextFile(String path, String content) throws IOException {
         Log.v(TAG, "createFile(" + path + ")");
         try (Writer writer = new BufferedWriter(new OutputStreamWriter(
                 new FileOutputStream(path)))) {
@@ -781,7 +909,7 @@
      * Gets the notification button used to take a screenshot.
      */
     private UiObject getScreenshotButton() {
-        openProgressNotification(PID);
+        openProgressNotification(ID);
         return mUiBot.getVisibleObject(
                 mContext.getString(R.string.bugreport_screenshot_action).toUpperCase());
     }
@@ -833,15 +961,28 @@
         /**
          * Gets the UI objects by opening the progress notification and clicking DETAILS.
          */
-        DetailsUi(UiBot uiBot, int pid) throws UiObjectNotFoundException {
-            openProgressNotification(pid);
-            detailsButton = mUiBot.getVisibleObject(
-                    mContext.getString(R.string.bugreport_info_action).toUpperCase());
-            mUiBot.click(detailsButton, "details_button");
+        DetailsUi(UiBot uiBot, int id) throws UiObjectNotFoundException {
+            this(uiBot, id, true);
+        }
+
+        /**
+         * Gets the UI objects by opening the progress notification and clicking on DETAILS or in
+         * the notification itself.
+         */
+        DetailsUi(UiBot uiBot, int id, boolean clickDetails) throws UiObjectNotFoundException {
+            UiObject notification = openProgressNotification(id);
+            detailsButton = mUiBot.getVisibleObject(mContext.getString(
+                    R.string.bugreport_info_action).toUpperCase());
+
+            if (clickDetails) {
+                mUiBot.click(detailsButton, "details_button");
+            } else {
+                mUiBot.click(notification, "notification");
+            }
             // TODO: unhardcode resource ids
             UiObject dialogTitle = mUiBot.getVisibleObjectById("android:id/alertTitle");
             assertEquals("Wrong title", mContext.getString(R.string.bugreport_info_dialog_title,
-                    pid), dialogTitle.getText().toString());
+                    id), dialogTitle.getText().toString());
             nameField = mUiBot.getVisibleObjectById("com.android.shell:id/name");
             titleField = mUiBot.getVisibleObjectById("com.android.shell:id/title");
             descField = mUiBot.getVisibleObjectById("com.android.shell:id/description");
@@ -849,18 +990,44 @@
             cancelButton = mUiBot.getObjectById("android:id/button2");
         }
 
+        private void assertField(String name, UiObject field, String expected)
+                throws UiObjectNotFoundException {
+            String actual = field.getText().toString();
+            assertEquals("Wrong value on field '" + name + "'", expected, actual);
+        }
+
+        void assertName(String expected) throws UiObjectNotFoundException {
+            assertField("name", nameField, expected);
+        }
+
+        void assertTitle(String expected) throws UiObjectNotFoundException {
+            assertField("title", titleField, expected);
+        }
+
+        void assertDescription(String expected) throws UiObjectNotFoundException {
+            assertField("description", descField, expected);
+        }
+
+        /**
+         * Set focus on the name field so it can be validated once focus is lost.
+         */
+        void focusOnName() throws UiObjectNotFoundException {
+            mUiBot.click(nameField, "name_field");
+            assertTrue("name_field not focused", nameField.isFocused());
+        }
+
         /**
          * Takes focus away from the name field so it can be validated.
          */
-        void focusAwayFromName() {
+        void focusAwayFromName() throws UiObjectNotFoundException {
             mUiBot.click(titleField, "title_field"); // Change focus.
             mUiBot.pressBack(); // Dismiss keyboard.
+            assertFalse("name_field is focused", nameField.isFocused());
         }
 
         void reOpen() {
-            openProgressNotification(PID);
+            openProgressNotification(ID);
             mUiBot.click(detailsButton, "details_button");
-
         }
 
         void clickOk() {
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index 384c3da..5bfe1a0 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -32,7 +32,7 @@
 final class UiBot {
 
     private static final String TAG = "UiBot";
-    private static final String SYSTEMUI_PACKAGED = "com.android.systemui";
+    private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
 
     private final UiDevice mDevice;
     private final int mTimeout;
@@ -51,8 +51,8 @@
     public UiObject getNotification(String text) {
         boolean opened = mDevice.openNotification();
         Log.v(TAG, "openNotification(): " + opened);
-        boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGED)), mTimeout);
-        assertTrue("could not get system ui (" + SYSTEMUI_PACKAGED + ")", gotIt);
+        boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE)), mTimeout);
+        assertTrue("could not get system ui (" + SYSTEMUI_PACKAGE + ")", gotIt);
 
         return getObject(text);
     }
diff --git a/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java b/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
index 712347a..57809ac 100644
--- a/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
+++ b/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
@@ -106,6 +106,10 @@
                 try {
                     ArrayList<String> sourceAssets = new ArrayList<String>();
                     for (String host : hostList) {
+                        // "*.example.tld" is validated via https://example.tld
+                        if (host.startsWith("*.")) {
+                            host = host.substring(2);
+                        }
                         sourceAssets.add(createWebAssetString(scheme, host));
                     }
                     extras.putStringArrayList(DirectStatementService.EXTRA_SOURCE_ASSET_DESCRIPTORS,
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 88313bb..ad3c26b 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -1,10 +1,24 @@
 LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SystemUI-proto-tags
+
+LOCAL_SRC_FILES := $(call all-proto-files-under,src) \
+    src/com/android/systemui/EventLogTags.logtags
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# ------------------
+
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) $(call all-Iaidl-files-under, src) \
-    src/com/android/systemui/EventLogTags.logtags
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     Keyguard \
@@ -13,13 +27,12 @@
     android-support-v7-appcompat \
     android-support-v14-preference \
     android-support-v17-leanback \
-    framework-protos
+    framework-protos \
+    SystemUI-proto-tags
 
 LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUI
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9e07c6d..9e2442c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -82,6 +82,7 @@
     <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
 
     <!-- WindowManager -->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
@@ -155,6 +156,9 @@
     <!-- TV picture-in-picture -->
     <uses-permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE" />
 
+    <!-- DND access -->
+    <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
@@ -166,8 +170,8 @@
         android:process="com.android.systemui"
         android:supportsRtl="true"
         android:theme="@style/systemui_theme"
-        android:forceDeviceEncrypted="true"
-        android:encryptionAware="true">
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
         <!-- Keep theme in sync with SystemUIApplication.onCreate().
              Setting the theme on the application does not affect views inflated by services.
              The application theme is set again from onCreate to take effect for those views. -->
@@ -180,12 +184,29 @@
             android:exported="true"
             />
 
+        <!-- Recents depends on every user having their own SystemUI process, so on user switch,
+             ensure that the process is created by starting this service.
+             -->
+        <service android:name="SystemUISecondaryUserService"
+            android:exported="true"
+            android:permission="com.android.systemui.permission.SELF" />
+
+
         <!-- started from PhoneWindowManager
              TODO: Should have an android:permission attribute -->
         <service android:name=".screenshot.TakeScreenshotService"
             android:process=":screenshot"
             android:exported="false" />
 
+        <!-- Called from PhoneWindowManager -->
+        <receiver android:name=".screenshot.ScreenshotServiceErrorReceiver"
+            android:process=":screenshot"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.systemui.screenshot.SHOW_ERROR" />
+            </intent-filter>
+        </receiver>
+
         <service android:name=".LoadAverageService"
                 android:exported="true" />
 
@@ -244,12 +265,20 @@
                   android:stateNotNeeded="true"
                   android:resumeWhilePausing="true"
                   android:screenOrientation="behind"
-                  android:theme="@style/RecentsTheme.Wallpaper">
+                  android:theme="@style/RecentsTvTheme.Wallpaper">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
             </intent-filter>
         </activity>
 
+        <activity
+            android:name=".stackdivider.ForcedResizableInfoActivity"
+            android:theme="@style/ForcedResizableTheme"
+            android:excludeFromRecents="true"
+            android:stateNotNeeded="true"
+            android:exported="false">
+        </activity>
+
         <!-- Callback for dismissing screenshot notification after a share target is picked -->
         <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
                   android:process=":screenshot"
@@ -337,7 +366,7 @@
             android:launchMode="singleTop"
             android:taskAffinity=""
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
-            android:resizeable="true"
+            android:resizeableActivity="true"
             android:supportsPictureInPicture="true"
             androidprv:alwaysFocusable="true"
             android:excludeFromRecents="true" />
@@ -345,10 +374,9 @@
             android:name="com.android.systemui.tv.pip.PipOverlayActivity"
             android:exported="true"
             android:theme="@style/PipTheme"
-            android:launchMode="singleTop"
             android:taskAffinity=""
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
-            android:resizeable="true"
+            android:resizeableActivity="true"
             android:supportsPictureInPicture="true"
             android:excludeFromRecents="true" />
         <activity
diff --git a/packages/SystemUI/res/anim/forced_resizable_enter.xml b/packages/SystemUI/res/anim/forced_resizable_enter.xml
new file mode 100644
index 0000000..01b8fdb
--- /dev/null
+++ b/packages/SystemUI/res/anim/forced_resizable_enter.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fromAlpha="0.0"
+    android:toAlpha="1.0"
+    android:interpolator="@android:interpolator/linear_out_slow_in"
+    android:duration="280" />
diff --git a/packages/SystemUI/res/anim/forced_resizable_exit.xml b/packages/SystemUI/res/anim/forced_resizable_exit.xml
new file mode 100644
index 0000000..6f316a7
--- /dev/null
+++ b/packages/SystemUI/res/anim/forced_resizable_exit.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fromAlpha="1.0"
+    android:toAlpha="0.0"
+    android:duration="160"
+    android:interpolator="@android:interpolator/fast_out_linear_in"
+    android:zAdjustment="top"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/major_a_b_dot_01_animation.xml b/packages/SystemUI/res/anim/major_a_b_dot_01_animation.xml
new file mode 100644
index 0000000..b5bb4dc
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_a_b_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 3.25,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_a_b_dot_animation.xml b/packages/SystemUI/res/anim/major_a_b_dot_animation.xml
new file mode 100644
index 0000000..6443167
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_a_b_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyName="pathData"
+        android:valueFrom="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueTo="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueType="pathType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_a_dot_01_animation.xml b/packages/SystemUI/res/anim/major_b_a_dot_01_animation.xml
new file mode 100644
index 0000000..2e0a4fa
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_a_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 8.0,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_a_dot_animation.xml b/packages/SystemUI/res/anim/major_b_a_dot_animation.xml
new file mode 100644
index 0000000..731c87c
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_a_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyName="pathData"
+        android:valueFrom="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueTo="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueType="pathType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_c_dot_01_animation.xml b/packages/SystemUI/res/anim/major_b_c_dot_01_animation.xml
new file mode 100644
index 0000000..e8c2687
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_c_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 8.0,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_c_dot_animation.xml b/packages/SystemUI/res/anim/major_b_c_dot_animation.xml
new file mode 100644
index 0000000..731c87c
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_c_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyName="pathData"
+        android:valueFrom="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueTo="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueType="pathType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_c_b_dot_01_animation.xml b/packages/SystemUI/res/anim/major_c_b_dot_01_animation.xml
new file mode 100644
index 0000000..d0174bc
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_c_b_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 12.75,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_c_b_dot_animation.xml b/packages/SystemUI/res/anim/major_c_b_dot_animation.xml
new file mode 100644
index 0000000..6443167
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_c_b_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyName="pathData"
+        android:valueFrom="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueTo="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+        android:valueType="pathType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_a_b_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_a_b_dot_02_animation.xml
new file mode 100644
index 0000000..b5bb4dc
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_a_b_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 3.25,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_b_a_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_b_a_dot_02_animation.xml
new file mode 100644
index 0000000..2e0a4fa
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_b_a_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 8.0,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_b_c_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_b_c_dot_02_animation.xml
new file mode 100644
index 0000000..e8c2687
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_b_c_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 8.0,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_c_b_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_c_b_dot_02_animation.xml
new file mode 100644
index 0000000..d0174bc
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_c_b_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="250"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 12.75,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml
deleted file mode 100644
index 7de4460..0000000
--- a/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- Recents Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:shareInterpolator="false"
-     android:zAdjustment="normal">
-  <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-         android:fillEnabled="true"
-         android:fillBefore="true" android:fillAfter="true"
-         android:interpolator="@android:interpolator/linear"
-         android:duration="1"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
deleted file mode 100644
index 23cedf8..0000000
--- a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- Launcher Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:shareInterpolator="false"
-     android:zAdjustment="top">
-  <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-         android:fillEnabled="true"
-         android:fillBefore="true" android:fillAfter="true"
-         android:interpolator="@interpolator/recents_from_launcher_exit_interpolator"
-         android:duration="133"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
deleted file mode 100644
index 657b216..0000000
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- Launcher Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:shareInterpolator="false"
-     android:zAdjustment="normal">
-  <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-         android:fillEnabled="true"
-         android:fillBefore="true" android:fillAfter="true"
-         android:interpolator="@interpolator/recents_to_launcher_enter_interpolator"
-         android:duration="133"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
deleted file mode 100644
index 5182cab2..0000000
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- Recents Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:shareInterpolator="false"
-     android:zAdjustment="top">
-  <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-         android:fillEnabled="true"
-         android:fillBefore="true" android:fillAfter="true"
-         android:interpolator="@android:interpolator/linear"
-         android:duration="1"/>
-</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..ebc6a4a7
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <objectAnimator
+        android:propertyName="scaleX"
+        android:valueTo="1.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+    <objectAnimator
+        android:propertyName="scaleY"
+        android:valueTo="1.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..95499bd
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <objectAnimator
+        android:propertyName="scaleX"
+        android:valueTo="0.7"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+    <objectAnimator
+        android:propertyName="scaleY"
+        android:valueTo="0.7"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..7555bdd
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="translationY"
+    android:valueTo="0dp"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..b40ccd4
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="translationY"
+    android:valueTo="-57dp"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..681ff91
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="1"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..e6deb0f
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="0"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/color/notification_guts_buttons.xml b/packages/SystemUI/res/color/notification_guts_buttons.xml
new file mode 100644
index 0000000..f7a4ee9
--- /dev/null
+++ b/packages/SystemUI/res/color/notification_guts_buttons.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="true"
+          android:color="@*android:color/material_deep_teal_500" />
+    <item android:color="@android:color/black"
+          android:alpha=".87" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png
new file mode 100644
index 0000000..73f5116
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..0622ddc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
deleted file mode 100644
index 7b0fcc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
deleted file mode 100644
index 73e9c96..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..c03ad20
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..bfe2b4a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..5ed0ee8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..d181162
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png
new file mode 100755
index 0000000..236b70a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png
new file mode 100644
index 0000000..787e259
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..93d1905
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
deleted file mode 100644
index a02e21c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
deleted file mode 100644
index 4af2617..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 9c36b5a..5e08fcb 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2015 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,30 +14,25 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48.0dp"
-        android:height="48.0dp"
+        android:width="48dp"
+        android:height="48dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
     <path
-        android:pathData="M24.0,2.0C11.8,2.0 2.0,11.8 2.0,24.0c0.0,6.1 2.5,11.6 6.4,15.6L39.6,8.4C35.6,4.5 30.1,2.0 24.0,2.0z"
-        android:fillColor="#E91E63"/>
+        android:fillColor="#00796B"
+        android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
     <path
-        android:pathData="M39.6,8.4L8.4,39.6c4.0,4.0 9.5,6.4 15.6,6.4c12.2,0.0 22.0,-9.8 22.0,-22.0C46.0,17.9 43.5,12.4 39.6,8.4z"
-        android:fillColor="#F06292"/>
+        android:fillColor="#00796B"
+        android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
     <path
-        android:pathData="M45.9,25.9L34.0,14.0L14.0,34.0l11.9,11.9C36.5,45.0 45.0,36.5 45.9,25.9z"
-        android:fillAlpha="0.33"
-        android:fillColor="#E91E63"/>
+        android:fillColor="#40000000"
+        android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
     <path
-        android:pathData="M24.0,24.0c0.0,0.0 0.0,2.2 0.0,5.0s0.0,5.0 0.0,5.0l10.0,-10.0L34.0,14.0L24.0,24.0z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="#40000000"
+        android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
     <path
-        android:pathData="M24.0,24.0L14.0,14.0l0.0,10.0l10.0,10.0c0.0,0.0 0.0,-2.2 0.0,-5.0S24.0,24.0 24.0,24.0z"
-        android:fillColor="#EEEEEE"/>
-    <path
-        android:pathData="M14.0,34.0l10.0,0.0 -10.0,-10.0z"
-        android:fillColor="#DDDDDD"/>
-    <path
-        android:pathData="M34.0,34.0l0.0,-10.0 -10.0,10.0z"
-        android:fillColor="#DDDDDD"/>
+        android:fillColor="#4DB6AC"
+        android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
 </vector>
+
+
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png
new file mode 100644
index 0000000..6ebbc83
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..73ddde8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
deleted file mode 100644
index 24bdbb6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
deleted file mode 100644
index 6ecd2d3..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png
new file mode 100755
index 0000000..1e84732
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
deleted file mode 100644
index 5e733ef..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
deleted file mode 100644
index ecc2c83..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
old mode 100644
new mode 100755
index f3be2ee..ee3ffde
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml
index 426238c..7356772 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver.xml
@@ -20,9 +20,11 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="
-        M9.0,16.0l2.0,0.0L11.0,8.0L9.0,8.0l0.0,8.0z
-        m3.0,-14.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0z
-        m0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0z
-        m1.0,-4.0l2.0,0.0l0.0,-8.0l-2.0,0.0l0.0,8.0z"/>
+        android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
+    <path
+        android:fillColor="#4DFFFFFF"
+        android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M16.0,11.0l0.0,2.0 -3.0,0.0 0.0,3.0 -2.0,0.0 0.0,-3.0 -3.0,0.0 0.0,-2.0 3.0,0.0 0.0,-3.0 2.0,0.0 0.0,3.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
index 0713548..fd9701e 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver_off.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
@@ -17,12 +17,12 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:viewportHeight="24.0"
+        android:tint="#4DFFFFFF">
     <path
-        android:fillColor="#4DFFFFFF"
-        android:pathData="
-        M9.0,16.0l2.0,0.0L11.0,8.0L9.0,8.0l0.0,8.0z
-        m3.0,-14.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0z
-        m0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0z
-        m1.0,-4.0l2.0,0.0l0.0,-8.0l-2.0,0.0l0.0,8.0z"/>
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
new file mode 100644
index 0000000..7ddb40c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M0 0h24v24H0z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_info.xml b/packages/SystemUI/res/drawable/ic_info.xml
deleted file mode 100644
index 65e7bf5..0000000
--- a/packages/SystemUI/res/drawable/ic_info.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM13.000000,17.000000l-2.000000,0.000000l0.000000,-6.000000l2.000000,0.000000L13.000000,17.000000zM13.000000,9.000000l-2.000000,0.000000L11.000000,7.000000l2.000000,0.000000L13.000000,9.000000z"
-        android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
new file mode 100644
index 0000000..d9a4f7b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
new file mode 100644
index 0000000..b8fa99e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M8 5v14l11-7z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
new file mode 100644
index 0000000..4d2a35e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
@@ -0,0 +1,45 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="26.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M0 0h26v24H0z"
+        android:fillColor="#00000000"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M21.0,8.5
+        c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
+        C25.1,5.96 20.26,2.0 13.0,2.0
+        S0.9,5.9 0.42,6.32
+        l12.57,15.6 4.21,-5.17
+        c-0.76,-0.87 -1.22,-2.0 -1.22,-3.25
+        c0.0,-2.76 2.24,-5.0 5.0,-5.0z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M21.0,10.0
+        c-1.93,0.0 -3.5,1.57 -3.5,3.5l1.75,0.0
+        c0.0,-0.9 0.78,-1.75 1.75,-1.75s1.7,0.78 1.75,1.75
+        c0.0,0.48 -0.2,0.92 -0.51,1.24l-1.09,1.1
+        c-0.6,0.63 -1.02,1.51 -1.02,2.47l0.0,0.44l1.75,0.0
+        c0.0,-1.3 0.39,-1.84 1.03,-2.47l0.78,-0.8
+        c0.5,-0.5 0.82,-1.2 0.82,-1.97
+        C24.5,11.57 22.93,10.0 21.0,10.0z
+        m-0.95,11.95l1.9,0.0l0.0,-1.9l-1.9,0.0l0.0,1.9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_send.xml b/packages/SystemUI/res/drawable/ic_send.xml
index b1c7914..6ce3672 100644
--- a/packages/SystemUI/res/drawable/ic_send.xml
+++ b/packages/SystemUI/res/drawable/ic_send.xml
@@ -14,6 +14,7 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="48.0"
diff --git a/packages/SystemUI/res/drawable/major_a_b.xml b/packages/SystemUI/res/drawable/major_a_b.xml
new file mode 100644
index 0000000..9900048
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_a_b.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="major_a_b"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_01"
+        android:translateX="3.25"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_a_b_animation.xml b/packages/SystemUI/res/drawable/major_a_b_animation.xml
new file mode 100644
index 0000000..74d7544
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_a_b_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/major_a_b" >
+    <target
+        android:name="dot_01"
+        android:animation="@anim/major_a_b_dot_01_animation" />
+    <target
+        android:name="dot"
+        android:animation="@anim/major_a_b_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/major_b_a.xml b/packages/SystemUI/res/drawable/major_b_a.xml
new file mode 100644
index 0000000..3115887
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_a.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="major_b_a"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_01"
+        android:translateX="8"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_b_a_animation.xml b/packages/SystemUI/res/drawable/major_b_a_animation.xml
new file mode 100644
index 0000000..cf446e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_a_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/major_b_a" >
+    <target
+        android:name="dot_01"
+        android:animation="@anim/major_b_a_dot_01_animation" />
+    <target
+        android:name="dot"
+        android:animation="@anim/major_b_a_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/major_b_c.xml b/packages/SystemUI/res/drawable/major_b_c.xml
new file mode 100644
index 0000000..899109e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_c.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="major_b_c"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_01"
+        android:translateX="8"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_b_c_animation.xml b/packages/SystemUI/res/drawable/major_b_c_animation.xml
new file mode 100644
index 0000000..38e12f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_c_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/major_b_c" >
+    <target
+        android:name="dot_01"
+        android:animation="@anim/major_b_c_dot_01_animation" />
+    <target
+        android:name="dot"
+        android:animation="@anim/major_b_c_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/major_c_b.xml b/packages/SystemUI/res/drawable/major_c_b.xml
new file mode 100644
index 0000000..cc6c615
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_c_b.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="major_c_b"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_01"
+        android:translateX="12.75"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_c_b_animation.xml b/packages/SystemUI/res/drawable/major_c_b_animation.xml
new file mode 100644
index 0000000..7f7850d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_c_b_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/major_c_b" >
+    <target
+        android:name="dot_01"
+        android:animation="@anim/major_c_b_dot_01_animation" />
+    <target
+        android:name="dot"
+        android:animation="@anim/major_c_b_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_a_b.xml b/packages/SystemUI/res/drawable/minor_a_b.xml
new file mode 100644
index 0000000..c5f5c98
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_a_b.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="minor_a_b"
+    android:alpha="0.3"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_02"
+        android:translateX="3.25"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_a_b_animation.xml b/packages/SystemUI/res/drawable/minor_a_b_animation.xml
new file mode 100644
index 0000000..50e20e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_a_b_animation.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/minor_a_b" >
+    <target
+        android:name="dot_02"
+        android:animation="@anim/minor_a_b_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_a.xml b/packages/SystemUI/res/drawable/minor_b_a.xml
new file mode 100644
index 0000000..3bb08c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_a.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="minor_b_a"
+    android:alpha="0.3"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_02"
+        android:translateX="8"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_a_animation.xml b/packages/SystemUI/res/drawable/minor_b_a_animation.xml
new file mode 100644
index 0000000..460a2f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_a_animation.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/minor_b_a" >
+    <target
+        android:name="dot_02"
+        android:animation="@anim/minor_b_a_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_c.xml b/packages/SystemUI/res/drawable/minor_b_c.xml
new file mode 100644
index 0000000..95c6463
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_c.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="minor_b_c"
+    android:alpha="0.3"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_02"
+        android:translateX="8"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_c_animation.xml b/packages/SystemUI/res/drawable/minor_b_c_animation.xml
new file mode 100644
index 0000000..53b8bd6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_c_animation.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/minor_b_c" >
+    <target
+        android:name="dot_02"
+        android:animation="@anim/minor_b_c_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_c_b.xml b/packages/SystemUI/res/drawable/minor_c_b.xml
new file mode 100644
index 0000000..523afaa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_c_b.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:name="minor_c_b"
+    android:alpha="0.3"
+    android:width="16dp"
+    android:viewportWidth="16"
+    android:height="8dp"
+    android:viewportHeight="8" >
+    <group
+        android:name="dot_02"
+        android:translateX="12.75"
+        android:translateY="4" >
+        <group
+            android:name="dot_group" >
+            <path
+                android:name="dot"
+                android:fillColor="#FFFFFFFF"
+                android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_c_b_animation.xml b/packages/SystemUI/res/drawable/minor_c_b_animation.xml
new file mode 100644
index 0000000..bf5e81e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_c_b_animation.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/minor_c_b" >
+    <target
+        android:name="dot_02"
+        android:animation="@anim/minor_c_b_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_background_secondary.xml b/packages/SystemUI/res/drawable/qs_background_secondary.xml
deleted file mode 100644
index 31c0162..0000000
--- a/packages/SystemUI/res/drawable/qs_background_secondary.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/system_secondary_color" />
-    <corners
-        android:topLeftRadius="0dp"
-        android:topRightRadius="0dp" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml b/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml
new file mode 100644
index 0000000..03bfd1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml
@@ -0,0 +1,32 @@
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetTop="4dp"
+    android:insetBottom="4dp">
+    <ripple
+        android:color="?android:attr/colorControlHighlight" >
+
+        <item android:id="@android:id/mask">
+            <shape>
+                <corners android:radius="@dimen/borderless_button_radius" />
+
+                <solid android:color="@android:color/white" />
+            </shape>
+        </item>
+
+    </ripple>
+</inset>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background.xml b/packages/SystemUI/res/drawable/qs_customizer_background.xml
index 6bb27cc..d90f820 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_background.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_background.xml
@@ -15,5 +15,5 @@
 -->
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@color/qs_detail_transition" />
-    <item android:drawable="?android:attr/windowBackground" />
+    <item android:drawable="@color/system_primary_color" />
 </transition>
diff --git a/packages/SystemUI/res/drawable/recents_empty.xml b/packages/SystemUI/res/drawable/recents_empty.xml
new file mode 100644
index 0000000..5506de1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_empty.xml
@@ -0,0 +1,43 @@
+<?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:width="100dp"
+    android:height="132dp"
+    android:viewportWidth="100"
+    android:viewportHeight="132">
+
+    <path
+        android:fillColor="#5AFFFFFF"
+        android:pathData="M86.91,68.67H13.09c-4.96,0-9,4.04-9,9V119c0,4.96,4.04,9,9,9h73.82c4.96,0,9-4.04,9-9V77.67
+C95.91,72.7,91.87,68.67,86.91,68.67z M27.59,77.27h26.72v3.94H27.59V77.27z
+M18.73,74.74c2.49,0,4.5,2.01,4.5,4.5
+c0,2.49-2.01,4.5-4.5,4.5s-4.5-2.01-4.5-4.5C14.23,76.75,16.24,74.74,18.73,74.74z
+M89.91,119c0,1.65-1.35,3-3,3H13.09 c-1.65,0-3-1.35-3-3V88.67h79.82V119z" />
+    <path
+        android:fillColor="#5AFFFFFF"
+        android:pathData="M86.91,36.3H13.09c-4.96,0-9,4.04-9,9v23c1.65-1.58,3.71-2.73,6-3.28v-9.08h79.82v9.08
+c2.29,0.55,4.35,1.69,6,3.28v-23C95.91,40.34,91.87,36.3,86.91,36.3z
+M18.73,51.38c-2.49,0-4.5-2.01-4.5-4.5s2.01-4.5,4.5-4.5
+s4.5,2.01,4.5,4.5S21.22,51.38,18.73,51.38z M54.31,48.84H27.59v-3.94h26.72V48.84z" />
+    <path
+        android:fillColor="#5AFFFFFF"
+        android:pathData="M86.91,4H13.09c-4.96,0-9,4.04-9,9v22.94c1.65-1.58,3.71-2.73,6-3.28V24h79.82v8.67
+c2.29,0.55,4.35,1.69,6,3.28V13C95.91,8.04,91.87,4,86.91,4z
+M18.73,18.5c-2.49,0-4.5-2.01-4.5-4.5s2.01-4.5,4.5-4.5
+s4.5,2.01,4.5,4.5S21.22,18.5,18.73,18.5z M54.31,15.97H27.59v-3.94h26.72V15.97z" />
+    <path
+        android:pathData="M 0 0 H 100 V 132 H 0 V 0 Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
new file mode 100644
index 0000000..e98d43f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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">
+    <gradient
+            android:startColor="#99000000"
+            android:endColor="#E6000000"
+            android:angle="90"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_notify_image.xml b/packages/SystemUI/res/drawable/stat_notify_image.xml
new file mode 100644
index 0000000..c8745d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z
+M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5 L8.5,13.5z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_notify_image_error.xml b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
new file mode 100644
index 0000000..b929005
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M17,18H5l3.5-4.5l2.5,3l3.3-4.5l2.7,3.8V8h4V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h12V18z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.2,21H21v-1.8h-1.8V21z M19.2,9.9v7.4H21V9.9H19.2z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
new file mode 100644
index 0000000..c36678d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
@@ -0,0 +1,34 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+        android:width="17.0dp"
+        android:height="17.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
+        <path
+            android:fillColor="#4DFFFFFF"
+            android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M16.0,11.0l0.0,2.0 -3.0,0.0 0.0,3.0 -2.0,0.0 0.0,-3.0 -3.0,0.0 0.0,-2.0 3.0,0.0 0.0,-3.0 2.0,0.0 0.0,3.0z"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
new file mode 100644
index 0000000..405ea0c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <size
+        android:width="34dp"
+        android:height="34dp" />
+    <solid
+        android:color="#4DFFFFFF" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_close_button.xml b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
new file mode 100644
index 0000000..186a4ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:constantSize="true">
+    <item android:state_focused="true">
+        <layer-list>
+            <item android:drawable="@drawable/tv_pip_button_focused" />
+            <item android:drawable="@drawable/ic_close_white"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_close_white"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_full_button.xml b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
new file mode 100644
index 0000000..c48dc828
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:constantSize="true">
+    <item android:state_focused="true">
+        <layer-list>
+            <item android:drawable="@drawable/tv_pip_button_focused" />
+            <item android:drawable="@drawable/ic_fullscreen_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_fullscreen_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_outline.xml b/packages/SystemUI/res/drawable/tv_pip_outline.xml
new file mode 100644
index 0000000..c84438c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_outline.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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">
+    <stroke android:width="2dp" android:color="#EEEEEE" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
new file mode 100644
index 0000000..e247dec
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
@@ -0,0 +1,23 @@
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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">
+
+    <gradient
+        android:startColor="#B2000000"
+        android:endColor="#00000000"
+        android:angle="90"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
new file mode 100644
index 0000000..bcc8973
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:constantSize="true">
+    <item android:state_focused="true">
+        <layer-list>
+            <item android:drawable="@drawable/tv_pip_button_focused" />
+            <item android:drawable="@drawable/ic_pause_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_pause_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_play_button.xml b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
new file mode 100644
index 0000000..f77ea1d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:constantSize="true">
+    <item android:state_focused="true">
+        <layer-list>
+            <item android:drawable="@drawable/tv_pip_button_focused" />
+            <item android:drawable="@drawable/ic_play_arrow_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_play_arrow_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+</selector>
diff --git a/packages/SystemUI/res/layout/battery_detail.xml b/packages/SystemUI/res/layout/battery_detail.xml
index 99121a9..af3e379 100644
--- a/packages/SystemUI/res/layout/battery_detail.xml
+++ b/packages/SystemUI/res/layout/battery_detail.xml
@@ -33,7 +33,7 @@
     <com.android.settingslib.graph.UsageView
         android:id="@+id/battery_usage"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="141dp"
         android:layout_marginStart="16dp"
         android:layout_marginEnd="24dp"
         systemui:sideLabels="@array/battery_labels"
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index 7ea5027..cfaf018 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -27,6 +27,7 @@
     <com.android.systemui.stackdivider.DividerHandleView
         style="@style/DockedDividerHandle"
         android:id="@+id/docked_divider_handle"
+        android:contentDescription="@string/accessibility_divider"
         android:background="@null"/>
 
 </com.android.systemui.stackdivider.DividerView>
diff --git a/packages/SystemUI/res/layout/forced_resizable_activity.xml b/packages/SystemUI/res/layout/forced_resizable_activity.xml
new file mode 100644
index 0000000..df245bc
--- /dev/null
+++ b/packages/SystemUI/res/layout/forced_resizable_activity.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/forced_resizable_info_text"
+        android:textColor="#ffffff"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 8b337ea..c1fe1a8 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -33,4 +33,10 @@
         android:layout_height="match_parent"
         android:src="@android:color/white"
         android:visibility="gone" />
+    <com.android.systemui.screenshot.ScreenshotSelectorView
+        android:id="@+id/global_screenshot_selector"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        android:pointerShape="crosshair"/>
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/hybrid_notification.xml b/packages/SystemUI/res/layout/hybrid_notification.xml
index f667859..476f52b 100644
--- a/packages/SystemUI/res/layout/hybrid_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_notification.xml
@@ -21,7 +21,7 @@
     android:layout_height="wrap_content"
     android:paddingStart="@*android:dimen/notification_content_margin_start"
     android:paddingEnd="12dp"
-    android:gravity="bottom">
+    android:gravity="bottom|start">
     <TextView
         android:id="@+id/notification_title"
         android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/hybrid_overflow_number.xml b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
new file mode 100644
index 0000000..f3dde8d
--- /dev/null
+++ b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/notification_text"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:textAppearance="@*android:style/TextAppearance.Material.Notification"
+    android:paddingEnd="@*android:dimen/notification_content_margin_end"
+    android:gravity="end"
+    android:singleLine="true"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
index 5a6553f..9c2c0ab 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -27,29 +27,19 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:paddingEnd="12dp"
-            android:background="@android:color/white"
-            android:textColor="#D9000000"
+            android:textColor="@color/ksh_keyword_color"
             android:textSize="16sp"
             android:maxLines="5"
             android:singleLine="false"
             android:scrollHorizontally="false"
-            android:layout_alignParentStart="true"
-            android:minWidth="100dp"
-            android:maxWidth="260dp"/>
-    <!--TODO: introduce and use a layout that allows wrapping and right align -->
-    <LinearLayout
+            android:layout_alignParentStart="true"/>
+    <com.android.systemui.statusbar.KeyboardShortcutKeysLayout
             android:id="@+id/keyboard_shortcuts_item_container"
             android:layout_toEndOf="@+id/keyboard_shortcuts_keyword"
             android:orientation="horizontal"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:background="@android:color/white"
             android:layout_alignParentEnd="true"
-            android:gravity="end"
             android:textSize="14sp"
-            android:paddingStart="0dp"
-            android:paddingEnd="0dp"
-            android:scrollHorizontally="false"
-            android:minWidth="100dp"
-            android:maxWidth="260dp"/>
+            android:scrollHorizontally="false"/>
 </RelativeLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
index 80a478a..381fb16 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -16,10 +16,10 @@
   ~ limitations under the License
   -->
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
-          android:layout_width="match_parent"
+          android:layout_width="wrap_content"
           android:layout_height="match_parent"
           android:textSize="14sp"
           android:paddingStart="24dp"
           android:paddingTop="20dp"
           android:paddingEnd="24dp"
-          android:paddingBottom="13dp" />
+          android:paddingBottom="13dp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
index f73ee15..7aba1cf 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -17,7 +17,7 @@
 
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="488dp"
+    android:layout_width="@dimen/ksh_layout_width"
     android:layout_height="wrap_content">
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 4d0eb96..062ae35 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -26,20 +26,20 @@
         android:orientation="vertical"
         android:paddingStart="@*android:dimen/notification_content_margin_start"
         android:paddingEnd="8dp"
-        android:background="@color/notification_guts_bg_color" >
+        android:background="@color/notification_guts_bg_color">
 
     <!-- header -->
     <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="30dp"
-            android:paddingTop="9dp"
+            android:layout_height="wrap_content"
+            android:paddingTop="14dp"
             android:paddingEnd="8dp"
             android:id="@+id/notification_guts_header"
             android:orientation="horizontal"
-            android:layout_gravity="center_vertical|start">
+            android:layout_gravity="start">
 
         <ImageView
-                android:id="@android:id/icon"
+                android:id="@+id/app_icon"
                 android:layout_width="18dp"
                 android:layout_height="18dp"
                 android:layout_marginEnd="6dp"
@@ -58,16 +58,48 @@
                 android:layout_gravity="bottom|start"
                 android:visibility="gone" />
     </LinearLayout>
+    <!-- Importance radio buttons -->
+    <RadioGroup
+            android:id="@+id/importance_buttons"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="4dp"
+            android:paddingEnd="8dp" >
+        <RadioButton
+                android:id="@+id/silent_importance"
+                android:layout_width="wrap_content"
+                android:layout_height="48dp"
+                android:paddingStart="32dp"
+                android:text="@string/show_silently"
+                style="@style/TextAppearance.NotificationGuts.Radio"
+                android:buttonTint="@color/notification_guts_buttons" />
+        <RadioButton
+                android:id="@+id/block_importance"
+                android:layout_width="wrap_content"
+                android:layout_height="48dp"
+                android:paddingStart="32dp"
+                android:text="@string/block"
+                style="@style/TextAppearance.NotificationGuts.Radio"
+                android:buttonTint="@color/notification_guts_buttons" />
+        <RadioButton
+                android:id="@+id/reset_importance"
+                android:layout_width="wrap_content"
+                android:layout_height="48dp"
+                android:paddingStart="32dp"
+                style="@style/TextAppearance.NotificationGuts.Radio"
+                android:buttonTint="@color/notification_guts_buttons" />
+    </RadioGroup>
     <!-- Importance slider -->
     <LinearLayout
+            android:id="@+id/importance_slider"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center_vertical"
             android:orientation="vertical"
             android:clickable="false"
             android:focusable="false"
-            android:paddingBottom="8dip"
-            android:paddingEnd="8dp" >
+            android:paddingEnd="8dp"
+            android:visibility="gone">
         <TextView
                 android:id="@+id/title"
                 android:layout_width="match_parent"
@@ -132,13 +164,14 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="end"
+            android:paddingTop="16dp"
             android:paddingBottom="8dp" >
 
         <TextView
             android:id="@+id/more_settings"
             android:text="@string/notification_more_settings"
             android:layout_width="wrap_content"
-            android:layout_height="48dp"
+            android:layout_height="36dp"
             style="@style/TextAppearance.NotificationGuts.Button"
             android:background="@drawable/btn_borderless_rect"
             android:gravity="center"
@@ -150,7 +183,7 @@
             android:id="@+id/done"
             android:text="@string/notification_done"
             android:layout_width="wrap_content"
-            android:layout_height="48dp"
+            android:layout_height="36dp"
             style="@style/TextAppearance.NotificationGuts.Button"
             android:background="@drawable/btn_borderless_rect"
             android:gravity="center"
diff --git a/packages/SystemUI/res/layout/notification_settings_icon_row.xml b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
index 52d07fc..f47083a 100644
--- a/packages/SystemUI/res/layout/notification_settings_icon_row.xml
+++ b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
@@ -19,6 +19,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:visibility="invisible"
     >
 
     <com.android.systemui.statusbar.AlphaOptimizedImageView
@@ -31,7 +32,6 @@
         android:paddingBottom="@dimen/notification_gear_padding"
         android:src="@drawable/ic_settings"
         android:tint="@color/notification_gear_color"
-        android:visibility="invisible"
         android:alpha="0"
         android:background="?android:attr/selectableItemBackgroundBorderless"
         />
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 73a92d9..7af247e 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -14,66 +14,14 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+
+<!-- Height is 0 because it will be managed by the QSContainer manually -->
 <com.android.systemui.qs.customize.QSCustomizer
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="0dp"
     android:orientation="vertical"
     android:background="@drawable/qs_customizer_background"
     android:gravity="center_horizontal">
 
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="28dp"
-        android:paddingEnd="8dp">
-
-        <ImageView
-            android:id="@+id/close"
-            android:layout_width="56dp"
-            android:layout_height="56dp"
-            android:padding="16dp"
-            android:src="@drawable/ic_close_white" />
-
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
-
-        <Button
-            android:id="@+id/save"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:paddingStart="12dp"
-            android:paddingEnd="12dp"
-            android:background="?android:attr/selectableItemBackground"
-            android:textAppearance="@android:style/TextAppearance.Material.Widget.Button.Inverse"
-            android:textColor="?android:attr/colorAccent"
-            android:text="@string/save" />
-
-        <Button
-            android:id="@+id/reset"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:paddingStart="12dp"
-            android:paddingEnd="12dp"
-            android:background="?android:attr/selectableItemBackground"
-            android:textAppearance="@android:style/TextAppearance.Material.Widget.Button.Inverse"
-            android:textColor="?android:attr/colorAccent"
-            android:text="@*android:string/reset" />
-
-    </LinearLayout>
-
-    <android.support.v7.widget.RecyclerView
-        android:id="@android:id/list"
-        android:layout_width="@dimen/notification_panel_width"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/navigation_bar_size"
-        android:layout_gravity="bottom"
-        android:background="#ff000000" />
-
 </com.android.systemui.qs.customize.QSCustomizer>
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
new file mode 100644
index 0000000..6438564
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <Toolbar
+        android:id="@*android:id/action_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="28dp"
+        android:navigationContentDescription="@*android:string/action_bar_up_description"
+        style="?android:attr/toolbarStyle" />
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@android:id/list"
+        android:layout_width="@dimen/notification_panel_width"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:scrollIndicators="top"
+        android:scrollbars="vertical"
+        android:importantForAccessibility="no" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/navigation_bar_size"
+        android:layout_gravity="bottom"
+        android:background="#ff000000" />
+</merge>
diff --git a/packages/SystemUI/res/layout/qs_customize_tile_divider.xml b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
new file mode 100644
index 0000000..0d932ac
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<View
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="16dp"
+    android:layout_marginEnd="16dp"
+    android:background="?android:attr/listDivider"
+    android:importantForAccessibility="no" />
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 858f487..3358a18 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -17,7 +17,6 @@
 <!-- Extends LinearLayout -->
 <com.android.systemui.qs.QSDetail
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@drawable/qs_detail_background"
@@ -41,7 +40,6 @@
         android:background="@color/qs_detail_progress_track"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        systemui:hasOverlappingRendering="false"
         />
 
     <FrameLayout
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index df46271..c062b6d 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -30,6 +30,7 @@
         android:padding="16dp"
         android:clickable="true"
         android:background="?android:attr/selectableItemBackground"
+        android:contentDescription="@*android:string/action_bar_up_description"
         android:src="?android:attr/homeAsUpIndicator" />
 
     <TextView
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index b8f10db..ef15195 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -18,7 +18,9 @@
         android:id="@+id/quick_settings_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@drawable/qs_background_primary">
+        android:background="@drawable/qs_background_primary"
+        android:clipToPadding="false"
+        android:clipChildren="false">
 
     <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
@@ -26,12 +28,13 @@
             android:layout_marginTop="@dimen/status_bar_header_height"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingBottom="8dp"
-            android:clipToPadding="false"
-            android:clipChildren="false" />
+            android:paddingBottom="8dp" />
 
     <include layout="@layout/quick_status_bar_expanded_header" />
 
     <include android:id="@+id/qs_detail" layout="@layout/qs_detail" />
 
+    <include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
+        android:visibility="gone" />
+
 </com.android.systemui.qs.QSContainer>
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 603ebbf..b0dca9a 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -20,22 +20,22 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal">
      <TextView android:id="@+id/tile_label"
-             android:layout_width="wrap_content"
-             android:layout_height="wrap_content"
-             android:textColor="@color/qs_tile_text"
-             android:gravity="center_horizontal"
-             android:minLines="2"
-             android:padding="0dp"
-             android:fontFamily="sans-serif-condensed"
-             android:textStyle="normal"
-             android:textSize="@dimen/qs_tile_text_size"
-             android:clickable="false" />
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="@color/qs_tile_text"
+            android:gravity="center_horizontal"
+            android:minLines="2"
+            android:padding="0dp"
+            android:fontFamily="sans-serif-condensed"
+            android:textStyle="normal"
+            android:textSize="@dimen/qs_tile_text_size"
+            android:clickable="false" />
      <ImageView android:id="@+id/restricted_padlock"
-             android:layout_width="@dimen/qs_tile_text_size"
-             android:layout_height="@dimen/qs_tile_text_size"
-             android:src="@drawable/ic_settings_lock_outline"
-             android:layout_marginLeft="@dimen/restricted_padlock_pading"
-             android:baselineAlignBottom="true"
-             android:scaleType="centerInside"
-             android:visibility="gone" />
+            android:layout_width="@dimen/qs_tile_text_size"
+            android:layout_height="match_parent"
+            android:paddingBottom="@dimen/qs_tile_text_size"
+            android:src="@drawable/ic_info"
+            android:layout_marginLeft="@dimen/restricted_padlock_pading"
+            android:scaleType="centerInside"
+            android:visibility="gone" />
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index a22c360..661d74a 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -53,10 +53,10 @@
         <ImageView
                 android:id="@+id/restricted_padlock"
                 android:layout_width="@dimen/qs_detail_item_secondary_text_size"
-                android:layout_height="@dimen/qs_detail_item_secondary_text_size"
-                android:src="@drawable/ic_settings_lock_outline"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:src="@drawable/ic_info"
                 android:layout_marginLeft="@dimen/restricted_padlock_pading"
-                android:baselineAlignBottom="true"
                 android:scaleType="centerInside"
                 android:visibility="gone" />
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 8df2c280..b88846b 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -26,9 +26,6 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:baselineAligned="false"
-    android:background="@drawable/quick_header_bg"
-    android:clickable="true"
-    android:focusable="true"
     >
 
     <LinearLayout
@@ -83,6 +80,10 @@
             android:id="@+id/expand_indicator"
             android:layout_width="48dp"
             android:layout_height="48dp"
+            android:clipToPadding="false"
+            android:clickable="true"
+            android:focusable="true"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
             android:padding="12dp" />
 
     </LinearLayout>
@@ -108,7 +109,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
-        android:layout_marginTop="4dp"
+        android:layout_marginTop="8dp"
         android:layout_marginStart="16dp"
         android:gravity="start"
         android:orientation="vertical">
@@ -184,7 +185,6 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
-        systemui:hasOverlappingRendering="false"
         />
 
     <TextView
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml
index b2c0331..53d9cc5 100644
--- a/packages/SystemUI/res/layout/recents_empty.xml
+++ b/packages/SystemUI/res/layout/recents_empty.xml
@@ -16,10 +16,12 @@
 
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:gravity="center"
+    android:drawableTop="@drawable/recents_empty"
+    android:drawablePadding="25dp"
     android:textSize="16sp"
     android:textColor="#ffffffff"
     android:text="@string/recents_empty_message"
diff --git a/packages/SystemUI/res/layout/recents_history.xml b/packages/SystemUI/res/layout/recents_history.xml
deleted file mode 100644
index dc2da72..0000000
--- a/packages/SystemUI/res/layout/recents_history.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.systemui.recents.history.RecentsHistoryView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-    <android.support.v7.widget.RecyclerView
-        android:id="@+id/list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-</com.android.systemui.recents.history.RecentsHistoryView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_button.xml b/packages/SystemUI/res/layout/recents_history_button.xml
deleted file mode 100644
index 538bad1..0000000
--- a/packages/SystemUI/res/layout/recents_history_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/button"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="start|center_vertical"
-    android:paddingStart="14dp"
-    android:paddingEnd="14dp"
-    android:paddingTop="12dp"
-    android:paddingBottom="12dp"
-    android:text="@string/recents_history_button_label"
-    android:textSize="14sp"
-    android:textColor="#FFFFFF"
-    android:textAllCaps="true"
-    android:drawableStart="@drawable/ic_history"
-    android:drawablePadding="6dp"
-    android:shadowColor="#99000000"
-    android:shadowDx="0"
-    android:shadowDy="2"
-    android:shadowRadius="5"
-    android:fontFamily="sans-serif-medium"
-    android:background="?android:selectableItemBackground"
-    android:visibility="invisible" />
diff --git a/packages/SystemUI/res/layout/recents_history_clear_all_button.xml b/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
deleted file mode 100644
index 05f0979..0000000
--- a/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/button"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="start|center_vertical"
-    android:paddingStart="16dp"
-    android:paddingEnd="16dp"
-    android:paddingTop="14dp"
-    android:paddingBottom="14dp"
-    android:drawableStart="@drawable/recents_dismiss_all_history"
-    android:contentDescription="@string/recents_history_clear_all_button_label"
-    android:textSize="14sp"
-    android:textColor="#FFFFFF"
-    android:textAllCaps="true"
-    android:shadowColor="#99000000"
-    android:shadowDx="0"
-    android:shadowDy="2"
-    android:shadowRadius="5"
-    android:fontFamily="sans-serif-medium"
-    android:background="?android:selectableItemBackground"
-    android:visibility="invisible" />
diff --git a/packages/SystemUI/res/layout/recents_history_date.xml b/packages/SystemUI/res/layout/recents_history_date.xml
deleted file mode 100644
index 13c7dbe..0000000
--- a/packages/SystemUI/res/layout/recents_history_date.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:paddingStart="4dp"
-    android:paddingEnd="4dp"
-    android:paddingTop="12dp"
-    android:paddingBottom="12dp"
-    android:gravity="start"
-    android:textSize="14sp"
-    android:textColor="#009688"
-    android:textAllCaps="true"
-    android:fontFamily="sans-serif-medium"
-    android:background="?android:selectableItemBackground"
-    android:alpha="1" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_task.xml b/packages/SystemUI/res/layout/recents_history_task.xml
deleted file mode 100644
index e92c24a..0000000
--- a/packages/SystemUI/res/layout/recents_history_task.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="48dp"
-    android:orientation="horizontal"
-    android:clickable="true"
-    android:focusable="true"
-    android:background="?android:selectableItemBackground">
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="32dp"
-        android:layout_height="32dp"
-        android:layout_gravity="center"
-        android:layout_marginStart="4dp"
-        android:layout_marginEnd="12dp" />
-    <TextView
-        android:id="@+id/description"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:layout_gravity="end"
-        android:paddingStart="16dp"
-        android:gravity="start|center_vertical"
-        android:textSize="14sp"
-        android:textColor="#FFFFFF"
-        android:fontFamily="sans-serif-medium" />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index b4543bd..28ea66d 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -19,8 +19,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
-    android:clipToPadding="false" >
-
+    android:clipToPadding="false">
     <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
         android:id="@+id/task_list"
         android:layout_width="wrap_content"
@@ -28,10 +27,16 @@
         android:clipChildren="false"
         android:clipToPadding="false"
         android:descendantFocusability="beforeDescendants"
-        android:gravity="center"
-        android:paddingStart="@dimen/recents_tv_grid_row_padding"
-        android:paddingEnd="@dimen/recents_tv_grid_row_padding"
-        android:focusable="true"/>
+        android:layout_marginTop="@dimen/recents_tv_gird_row_top_margin"
+        android:focusable="true"
+        android:layoutDirection="rtl" />
+
+    <!-- Placeholder view to give focus to the PIP menus. -->
+    <View
+        android:id="@+id/pip"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:focusable="true"
+        android:visibility="gone" />
 
 </com.android.systemui.recents.tv.views.RecentsTvView>
-
diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml
new file mode 100644
index 0000000..625e9c1
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/button"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingStart="14dp"
+    android:paddingEnd="14dp"
+    android:paddingTop="12dp"
+    android:paddingBottom="12dp"
+    android:text="@string/recents_stack_action_button_label"
+    android:textSize="14sp"
+    android:textColor="#FFFFFF"
+    android:textAllCaps="true"
+    android:shadowColor="#99000000"
+    android:shadowDx="0"
+    android:shadowDy="2"
+    android:shadowRadius="5"
+    android:fontFamily="sans-serif-medium"
+    android:background="?android:selectableItemBackground"
+    android:visibility="invisible" />
diff --git a/packages/SystemUI/res/layout/recents_task_card_view.xml b/packages/SystemUI/res/layout/recents_task_card_view.xml
deleted file mode 100644
index fa1daad..0000000
--- a/packages/SystemUI/res/layout/recents_task_card_view.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT 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.recents.tv.views.TaskCardView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:focusable="true"
-    android:focusableInTouchMode="true"
-    android:layout_gravity="center"
-    android:layout_centerInParent="true">
-
-    <RelativeLayout
-            android:layout_width="@dimen/recents_tv_card_width"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            android:layout_gravity="center">
-        <ImageView
-                android:id="@+id/card_view_thumbnail"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/recents_tv_card_height"
-                android:scaleType="centerCrop"
-                android:gravity="center"
-                android:layout_alignParentTop="true"
-                android:layout_centerHorizontal="true"/>
-
-        <RelativeLayout
-                android:id="@+id/card_info_field"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/card_view_thumbnail"
-                android:background="@color/recents_tv_card_background_color" >
-            <TextView
-                    android:id="@+id/card_title_text"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentTop="false"
-                    android:includeFontPadding="true"
-                    android:minLines="1"
-                    android:maxLines="2"
-                    android:textColor="@color/recents_tv_card_title_text_color"
-                    android:ellipsize="end" />
-            <TextView
-                    android:id="@+id/card_content_text"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentStart="true"
-                    android:layout_below="@id/card_title_text"
-                    android:includeFontPadding="true"
-                    android:minLines="1"
-                    android:maxLines="2"
-                    android:textColor="@color/recents_tv_card_content_text_color"
-                    android:ellipsize="end" />
-            <ImageView
-                    android:id="@+id/card_extra_badge"
-                    android:layout_width="@dimen/recents_tv_card_extra_badge_size"
-                    android:layout_height="@dimen/recents_tv_card_extra_badge_size"
-                    android:scaleType="fitCenter"
-                    android:background="@android:color/transparent"
-                    android:contentDescription="@null"
-                    android:layout_centerVertical="true"
-                    android:layout_alignParentRight="true"/>
-        </RelativeLayout>
-    </RelativeLayout>
-</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index deb8e91..2b3c5df 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -14,51 +14,73 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<!-- The layouts params are calculated in TaskViewHeader.java -->
 <com.android.systemui.recents.views.TaskViewHeader
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/task_view_bar"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/recents_task_bar_height"
+    android:layout_height="wrap_content"
     android:layout_gravity="top|center_horizontal">
     <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/icon"
         android:contentDescription="@string/recents_app_info_button_label"
-        android:layout_width="@dimen/recents_task_view_header_icon_width"
-        android:layout_height="@dimen/recents_task_view_header_icon_height"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|start"
-        android:padding="9dp" />
-    <TextView
-        android:id="@+id/title"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="12dp" />
+    <LinearLayout
+        android:id="@+id/title_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|start"
-        android:layout_marginStart="64dp"
-        android:layout_marginEnd="112dp"
-        android:textSize="16sp"
-        android:textColor="#ffffffff"
-        android:text="@string/recents_empty_message"
-        android:fontFamily="sans-serif-medium"
-        android:singleLine="true"
-        android:maxLines="2"
-        android:ellipsize="marquee"
-        android:fadingEdge="horizontal" />
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start"
+            android:textSize="16sp"
+            android:textColor="#ffffffff"
+            android:text="@string/recents_empty_message"
+            android:fontFamily="sans-serif-medium"
+            android:singleLine="true"
+            android:maxLines="1"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+        <TextView
+            android:id="@+id/sub_title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start"
+            android:textSize="11sp"
+            android:textColor="#ffffffff"
+            android:text="@string/recents_launch_non_dockable_task_label"
+            android:fontFamily="sans-serif-medium"
+            android:singleLine="true"
+            android:maxLines="1"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            android:visibility="gone" />
+    </LinearLayout>
     <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/move_task"
-        android:layout_width="@dimen/recents_task_view_header_button_width"
-        android:layout_height="@dimen/recents_task_view_header_button_height"
-        android:layout_marginEnd="@dimen/recents_task_view_header_button_width"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|end"
-        android:padding="15dp"
+        android:padding="@dimen/recents_task_view_header_button_padding"
         android:src="@drawable/star"
         android:background="?android:selectableItemBackground"
         android:alpha="0"
         android:visibility="gone" />
     <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/dismiss_task"
-        android:layout_width="@dimen/recents_task_view_header_button_width"
-        android:layout_height="@dimen/recents_task_view_header_button_height"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|end"
-        android:padding="15dp"
+        android:padding="@dimen/recents_task_view_header_button_padding"
         android:src="@drawable/recents_dismiss_light"
         android:background="?android:selectableItemBackground"
         android:alpha="0"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
index 10659a3..cf09b1d 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
@@ -13,6 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<!-- The layouts params are calculated in TaskViewHeader.java -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
@@ -20,17 +21,18 @@
     <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/app_icon"
         android:contentDescription="@string/recents_app_info_button_label"
-        android:layout_width="@dimen/recents_task_view_header_icon_width"
-        android:layout_height="@dimen/recents_task_view_header_icon_height"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|start"
-        android:padding="9dp" />
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="12dp" />
     <TextView
         android:id="@+id/app_title"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|start"
-        android:layout_marginStart="64dp"
-        android:layout_marginEnd="112dp"
         android:textSize="16sp"
         android:textColor="#ffffffff"
         android:text="@string/recents_empty_message"
@@ -41,10 +43,10 @@
         android:fadingEdge="horizontal" />
     <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/app_info"
-        android:layout_width="@dimen/recents_task_view_header_button_width"
-        android:layout_height="@dimen/recents_task_bar_height"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|end"
-        android:padding="15dp"
+        android:padding="@dimen/recents_task_view_header_button_padding"
         android:background="?android:selectableItemBackground"
         android:src="@drawable/recents_info_light" />
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
new file mode 100644
index 0000000..766ef60
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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.recents.tv.views.TaskCardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:layout_gravity="center"
+    android:layout_centerInParent="true"
+    android:orientation="vertical"
+    android:layoutDirection="ltr">
+
+    <LinearLayout
+            android:id="@+id/recents_tv_card"
+            android:layout_width="@dimen/recents_tv_card_width"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            android:layout_gravity="center"
+            android:orientation="vertical" >
+        <LinearLayout
+                android:id="@+id/card_info_field"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+            <ImageView
+                    android:id="@+id/card_extra_badge"
+                    android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+                    android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+                    android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
+                    android:layout_marginEnd="@dimen/recents_tv_icon_padding_end"
+                    android:scaleType="fitCenter"
+                    android:layout_centerVertical="true"
+                    android:layout_alignParentRight="true" />
+            <TextView
+                    android:id="@+id/card_title_text"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentTop="false"
+                    android:includeFontPadding="true"
+                    android:minLines="1"
+                    android:maxLines="1"
+                    android:textColor="@color/recents_tv_card_title_text_color"
+                    android:fontFamily="@string/font_roboto_regular"
+                    android:textSize="@dimen/recents_tv_title_text_size"
+                    android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
+                    android:ellipsize="end"/>
+        </LinearLayout>
+        <ImageView
+                android:id="@+id/card_view_thumbnail"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/recents_tv_screenshot_height"
+                android:scaleType="centerCrop"
+                android:gravity="center"
+                android:layout_alignParentTop="true"
+                android:layout_centerHorizontal="true"
+                android:layout_below="@id/card_title_text" />
+    </LinearLayout>
+    <LinearLayout
+            android:id="@+id/card_dismiss"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_gravity="center_horizontal"
+            android:layout_below="@id/recents_tv_card"
+            android:alpha="0.0">
+        <ImageView
+                android:id="@+id/card_dismiss_icon"
+                android:layout_width="@dimen/recents_tv_dismiss_icon_size"
+                android:layout_height="@dimen/recents_tv_dismiss_icon_size"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
+                android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
+                android:src="@drawable/ic_cancel_white_24dp" />
+        <TextView
+                android:id="@+id/card_dismiss_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="@dimen/recents_tv_dismiss_text_size"
+                android:fontFamily="@string/font_roboto_light"
+                android:textColor="@color/recents_tv_dismiss_text_color"
+                android:text="@string/recents_tv_dismiss"
+                android:layout_gravity="center_horizontal" />
+    </LinearLayout>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index cce07bd..7460201 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,7 +42,9 @@
             android:background="@null"
             android:singleLine="true"
             android:ellipsize="start"
-            android:imeOptions="actionSend" />
+            android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
+            android:textIsSelectable="true"
+            android:imeOptions="actionSend|flagNoExtractUi" />
 
     <FrameLayout
             android:layout_width="wrap_content"
@@ -61,6 +63,7 @@
                 android:paddingBottom="12dp"
                 android:id="@+id/remote_input_send"
                 android:src="@drawable/ic_send"
+                android:contentDescription="@*android:string/ime_action_send"
                 android:tint="@color/remote_input_send"
                 android:tintMode="src_in"
                 android:background="@drawable/ripple_drawable" />
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
index 224a0a0..60112be 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
@@ -112,21 +112,6 @@
         <ImageView
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:scaleType="matrix"
-            android:src="@drawable/screen_pinning_light_bg_circ" />
-
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingEnd="@dimen/screen_pinning_request_inner_padding"
-            android:paddingStart="@dimen/screen_pinning_request_inner_padding"
-            android:paddingTop="@dimen/screen_pinning_request_inner_padding"
-            android:scaleType="matrix"
-            android:src="@drawable/screen_pinning_bg_circ" />
-
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
             android:paddingEnd="@dimen/screen_pinning_request_nav_side_padding"
             android:paddingStart="@dimen/screen_pinning_request_nav_side_padding"
             android:paddingTop="@dimen/screen_pinning_request_nav_icon_padding"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
index 1e5193f..ebad7a4 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
@@ -43,21 +43,6 @@
         <ImageView
             android:layout_height="match_parent"
             android:layout_width="match_parent"
-            android:scaleType="matrix"
-            android:src="@drawable/screen_pinning_light_bg_circ" />
-
-        <ImageView
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:scaleType="matrix"
-            android:paddingLeft="@dimen/screen_pinning_request_inner_padding"
-            android:paddingTop="@dimen/screen_pinning_request_inner_padding"
-            android:paddingBottom="@dimen/screen_pinning_request_inner_padding"
-            android:src="@drawable/screen_pinning_bg_circ" />
-
-        <ImageView
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
             android:scaleType="center"
             android:paddingLeft="@dimen/screen_pinning_request_nav_icon_padding"
             android:paddingTop="@dimen/screen_pinning_request_nav_side_padding"
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index c634cd6..9df5dbf 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -19,7 +19,6 @@
 <!-- extends LinearLayout -->
 <com.android.systemui.statusbar.SignalClusterView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_height="match_parent"
     android:layout_width="wrap_content"
     android:gravity="center_vertical"
@@ -43,7 +42,6 @@
             android:id="@+id/ethernet"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
-            systemui:hasOverlappingRendering="false"
             />
         <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:theme="@style/DualToneDarkTheme"
@@ -51,7 +49,6 @@
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:alpha="0.0"
-            systemui:hasOverlappingRendering="false"
             />
     </FrameLayout>
     <FrameLayout
@@ -64,7 +61,6 @@
             android:id="@+id/wifi_signal"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
-            systemui:hasOverlappingRendering="false"
             />
         <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:theme="@style/DualToneDarkTheme"
@@ -72,7 +68,6 @@
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:alpha="0.0"
-            systemui:hasOverlappingRendering="false"
             />
     </FrameLayout>
     <View
@@ -98,7 +93,6 @@
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:src="@drawable/stat_sys_no_sims"
-            systemui:hasOverlappingRendering="false"
             />
         <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:theme="@style/DualToneDarkTheme"
@@ -107,7 +101,6 @@
             android:layout_width="wrap_content"
             android:src="@drawable/stat_sys_no_sims"
             android:alpha="0.0"
-            systemui:hasOverlappingRendering="false"
             />
     </FrameLayout>
     <View
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 289b1d9..ccefb5f 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,11 +39,14 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <include
-            layout="@layout/qs_panel"
+        <com.android.systemui.DensityContainer
+            android:id="@+id/qs_density_container"
+            android:layout="@layout/qs_panel"
             android:layout_width="@dimen/notification_panel_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="@integer/notification_panel_layout_gravity" />
+            android:layout_height="match_parent"
+            android:layout_gravity="@integer/notification_panel_layout_gravity"
+            android:clipToPadding="false"
+            android:clipChildren="false" />
 
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index dd75dbf..c5cd65e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -177,7 +177,6 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
-        systemui:hasOverlappingRendering="false"
         />
 
     <TextView
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 f699fce..7df6bc6 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -22,6 +22,7 @@
     android:focusable="true"
     android:clickable="true"
     >
+
     <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundNormal"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -65,4 +66,9 @@
             />
     </com.android.keyguard.AlphaOptimizedLinearLayout>
 
+    <com.android.systemui.statusbar.notification.FakeShadowView
+        android:id="@+id/fake_shadow"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
 </com.android.systemui.statusbar.NotificationOverflowContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index c4c45bb..e456984 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -76,4 +76,9 @@
         android:layout_height="wrap_content"
         />
 
+    <com.android.systemui.statusbar.notification.FakeShadowView
+        android:id="@+id/fake_shadow"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
 </com.android.systemui.statusbar.ExpandableNotificationRow>
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
new file mode 100644
index 0000000..563441f
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Layout for {@link com.android.systemui.tv.pip.PipControlsView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="100dp"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageView android:id="@+id/full_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:focusable="true"
+            android:src="@drawable/tv_pip_full_button" />
+
+        <TextView android:id="@+id/full_desc"
+            android:layout_width="100dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="3dp"
+            android:gravity="center"
+            android:visibility="invisible"
+            android:text="@string/pip_fullscreen"
+            android:fontFamily="sans-serif"
+            android:textSize="12sp"
+            android:textColor="#EEEEEE" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="100dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="-50dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageView android:id="@+id/close_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:focusable="true"
+            android:src="@drawable/tv_pip_close_button" />
+
+        <TextView android:id="@+id/close_desc"
+            android:layout_width="100dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="3dp"
+            android:gravity="center"
+            android:visibility="invisible"
+            android:text="@string/pip_close"
+            android:fontFamily="sans-serif"
+            android:textSize="12sp"
+            android:textColor="#EEEEEE" />
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/play_pause"
+        android:layout_width="100dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="-50dp"
+        android:orientation="vertical"
+        android:gravity="center" >
+
+        <ImageView android:id="@+id/play_pause_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:focusable="true"
+            android:src="@drawable/tv_pip_pause_button" />
+
+        <TextView android:id="@+id/play_pause_desc"
+            android:layout_width="100dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="3dp"
+            android:gravity="center"
+            android:visibility="invisible"
+            android:text="@string/pip_pause"
+            android:fontFamily="sans-serif"
+            android:textSize="12sp"
+            android:textColor="#EEEEEE" />
+    </LinearLayout>
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 3562c64..2647a99 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -18,36 +18,16 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_gravity="end"
-    android:paddingStart="10dp"
-    android:paddingEnd="10dp"
-    android:background="#88FFFFFF"
-    android:gravity="center_vertical" >
+    android:orientation="horizontal"
+    android:paddingTop="350dp"
+    android:background="#CC000000"
+    android:gravity="top|center_horizontal"
+    android:clipChildren="false">
 
-    <Button android:id="@+id/full"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:text="@string/pip_fullscreen"
-        android:textSize="10sp"
-        android:focusable="true" />
-
-    <Button android:id="@+id/exit"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:text="@string/pip_exit"
-        android:textSize="10sp"
-        android:focusable="true" />
-
-    <Button android:id="@+id/cancel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:text="@string/pip_cancel"
-        android:textSize="10sp"
-        android:focusable="true" />
+    <com.android.systemui.tv.pip.PipControlsView
+        android:id="@+id/pip_controls"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
index ef39555..b0814cf 100644
--- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml
+++ b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
@@ -18,34 +18,46 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/pip_onboarding"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="#C00288D1"
-    android:gravity="center"
-    android:orientation="vertical" >
+    android:gravity="top|center_horizontal"
+    android:orientation="vertical">
 
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="30sp"
-        android:textColor="@android:color/white"
-        android:text="@string/pip_onboarding_title" />
+    <!-- A rectangle arounds the PIP.
+         Size and positions will be programatically set up
+         to comply with config_defaultPictureInPictureBounds. -->
     <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:src="@drawable/ic_sysbar_home" />
+        android:id="@+id/pip_outline"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:src="@drawable/tv_pip_outline" />
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="30dp"
-        android:textSize="13sp"
-        android:textColor="@android:color/white"
+        android:layout_marginTop="24dp"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp"
+        android:fontFamily="sans-serif"
+        android:textSize="16sp"
+        android:textColor="#EEEEEE"
+        android:lineSpacingMultiplier="1.28"
+        android:gravity="top|center_horizontal"
         android:text="@string/pip_onboarding_description" />
     <Button
         android:id="@+id/close"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="15sp"
+        android:layout_height="36dp"
+        android:layout_marginTop="24dp"
+        android:gravity="center"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp"
+        android:fontFamily="sans-serif-condensed"
+        android:textSize="16sp"
+        android:textColor="#026089"
         android:textAllCaps="true"
-        android:text="@string/pip_onboarding_button" />
+        android:text="@string/pip_onboarding_button"
+        android:background="#EEEEEE"
+        android:elevation="4dp" />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index 6d9c48d..64bf3b5 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -17,13 +17,25 @@
 */
 -->
 
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/guide_overlay"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="bottom"
-    android:padding="3dp"
-    android:textSize="13sp"
-    android:textColor="#111111"
-    android:background="#99EEEEEE"
-    android:text="@string/pip_hold_home" />
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/guide_overlay"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:paddingTop="6dp"
+        android:paddingBottom="6dp"
+        android:paddingStart="10dp"
+        android:paddingEnd="10dp"
+        android:textSize="14sp"
+        android:textColor="#EEEEEE"
+        android:fontFamily="sans-serif"
+        android:background="@drawable/tv_pip_overlay_background"
+        android:lineSpacingMultiplier="1.465"
+        android:gravity="center"
+        android:maxLines="2"
+        android:text="@string/pip_hold_home" />
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
new file mode 100644
index 0000000..1e464d8
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:gravity="top|center_horizontal">
+
+    <com.android.systemui.tv.pip.PipRecentsControlsView
+        android:id="@+id/pip_controls"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent" />
+
+    <View
+        android:id="@+id/recents"
+        android:layout_width="1dp"
+        android:layout_height="1dp"
+        android:focusable="true" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index e4effd4..baec8ef 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,25 +13,15 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/volume_dialog"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
     android:background="@drawable/volume_dialog_background"
-    android:translationZ="4dp" >
-
-    <com.android.keyguard.AlphaOptimizedImageButton
-        android:id="@+id/volume_expand_button"
-        style="@style/VolumeButtons"
-        android:layout_width="@dimen/volume_button_size"
-        android:layout_height="@dimen/volume_button_size"
-        android:layout_alignParentLeft="true"
-        android:clickable="true"
-        android:soundEffectsEnabled="false"
-        android:src="@drawable/ic_volume_collapse_animation"
-        tools:ignore="RtlHardcoded" />
+    android:translationZ="4dp"
+    android:paddingTop="8dp">
 
     <LinearLayout
         android:id="@+id/volume_dialog_content"
@@ -39,9 +29,15 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:paddingBottom="8dp"
-        android:paddingTop="8dp" >
+        android:paddingStart="8dp">
 
         <!-- volume rows added and removed here! :-) -->
+        <LinearLayout
+                android:id="@+id/volume_row_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="@dimen/volume_button_size"
+                android:orientation="vertical"/>
 
         <include layout="@layout/volume_zen_footer" />
 
@@ -49,4 +45,18 @@
         <include layout="@layout/tuner_zen_mode_panel" />
     </LinearLayout>
 
+    <com.android.keyguard.AlphaOptimizedImageButton
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            xmlns:tools="http://schemas.android.com/tools"
+            android:id="@+id/volume_expand_button"
+            style="@style/VolumeButtons"
+            android:layout_width="@dimen/volume_button_size"
+            android:layout_height="@dimen/volume_button_size"
+            android:clickable="true"
+            android:soundEffectsEnabled="false"
+            android:src="@drawable/ic_volume_collapse_animation"
+            tools:ignore="RtlHardcoded"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentTop="true"/>
+
 </RelativeLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 91e931d..57bac41 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -13,13 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:clipChildren="false"
-    android:id="@+id/volume_dialog_row"
-    android:paddingEnd="8dp"
-    android:paddingStart="8dp" >
+    android:id="@+id/volume_dialog_row" >
 
     <TextView
         android:id="@+id/volume_row_header"
@@ -31,7 +30,8 @@
         android:paddingBottom="0dp"
         android:paddingEnd="12dp"
         android:paddingStart="12dp"
-        android:paddingTop="4dp" />
+        android:paddingTop="4dp"
+        android:visibility="gone" />
 
     <com.android.keyguard.AlphaOptimizedImageButton
         android:id="@+id/volume_row_icon"
@@ -55,12 +55,4 @@
         android:paddingEnd="8dp"
         android:paddingStart="8dp" />
 
-    <com.android.keyguard.AlphaOptimizedImageButton
-        android:id="@+id/volume_settings_button"
-        style="@style/VolumeButtons"
-        android:layout_width="@dimen/volume_button_size"
-        android:layout_height="@dimen/volume_button_size"
-        android:layout_alignParentEnd="true"
-        android:layout_below="@id/volume_row_header" />
-
 </RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index 28447d7..f30023d 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -32,9 +32,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center_vertical"
-        android:orientation="horizontal"
-        android:paddingEnd="8dp"
-        android:paddingStart="8dp" >
+        android:orientation="horizontal" >
 
         <ImageView
             android:id="@+id/volume_zen_icon"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 8d37e74..3fa6245 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skermkiekie geneem."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak om jou skermkiekie te sien."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kon nie skermkiekie neem nie."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan nie skermkiekie neem nie oor beperkte bergingspasie of die program of organisasie verbied dit."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Kon nie skermkiekie stoor nie."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan weens beperkte bergingspasie nie skermkiekie stoor nie."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Die program of jou organisasie laat nie toe dat skermkiekies geneem word nie."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-lêeroordrag-opsies"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Heg as \'n mediaspeler (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Heg as \'n kamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Maak <xliff:g id="APP">%s</xliff:g> toe."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwerp."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle onlangse programme is toegemaak."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Begin tans <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Kennisgewing is toegemaak."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meer tyd."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minder tyd."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flitslig af."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Flitslig is nie beskikbaar nie."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flitslig aan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flitslig afgeskakel."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flitslig aangeskakel."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Werkmodus is aan."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Werkmodus is afgeskakel."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Werkmodus is aangeskakel."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Databespaarder is afgeskakel."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Databespaarder is aangeskakel."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skermhelderheid"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data is laat wag"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ligging deur GPS gestel"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Liggingversoeke aktief"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Verwyder alle kennisgewings."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Kennisgewingsinstellings"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>-instellings"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Die skerm sal outomaties draai."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g>-limiet"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Jou onlangse skerms verskyn hier"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Geen onlangse items nie"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Jy het alles toegemaak"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skermvaspen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kon nie <xliff:g id="APP">%s</xliff:g> begin nie."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is in veiligmodus gedeaktiveer."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Geskiedenis"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vee uit"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vee alles uit"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Hierdie program steun nie veelvuldige vensters nie"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Program steun nie veelvuldige vensters nie"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verdeel vertikaal"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Verdeel gepasmaak"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Volkome\nstilte"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Net\nprioriteit"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Net\nwekkers"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Alles"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laai tans vinnig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laai tans stadig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktiveer versneller om skerm te verdeel deur op te swiep"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktiveer die verdeling van die skerm deur op te swiep"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiveer gebaar om skerm te verdeel deur van die Oorsig-knoppie af op te swiep"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Skakel aan"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Pas toe op <xliff:g id="TOPIC_NAME">%1$s</xliff:g>-kennisgewings"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Pas toe op alle kennisgewings van hierdie program af"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Wys kennisgewings sonder klank"</string>
+    <string name="block" msgid="2734508760962682611">"Blokkeer alle kennisgewings"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Moenie stilmaak nie"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Moenie stilmaak of blokkeer nie"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Wys volledige belangrikheidinstellings"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Geblokkeer"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Onbelangrik"</string>
     <string name="low_importance" msgid="4109929986107147930">"Min belang"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normale belang"</string>
     <string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
     <string name="max_importance" msgid="5089005872719563894">"Dringende belang"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Moet nooit hierdie kennisgewings wys nie"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Wys onderaan die kennisgewinglys sonder \'n geluid"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Wys hierdie kennisgewings sonder geluide"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Wys boaan die kennisgewinglys en maak \'n geluid"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Verskyn vlugtig op die skerm en maak \'n geluid"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Wys sonder klank aan die onderkant van die kennisgewinglys"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Wys hierdie kennisgewings sonder klank"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Laat hierdie kennisgewing toe om geluide te maak"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Verskyn vlugtig op die skerm en laat klank toe"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Wys boaan die kennisgewingslys, verskyn vlugtig op die skerm en laat klank toe"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleure"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Aandkleure"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Gepasmaakte kleure"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Outo"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Onbekende kleure"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Kleurverandering"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Wys kitsinstellings-teël"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Aktiveer gepasmaakte omskepping"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-kennisgewingkontroles"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Kleur en voorkoms"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nagmodus"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibreer skerm"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Aan"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Af"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Skakel outomaties aan"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Skakel oor na Nagmodus soos gepas vir ligging en tyd van die dag"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Wanneer Nagmodus aan is"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Gebruik donkertema vir Android-bedryfstelsel"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Verstel tint"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Verstel helderheid"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Die donkertema word toegepas op kernareas van Android-bedryfstelsel wat gewoonlik in \'n ligtema gewys word, soos instellings."</string>
     <string name="color_apply" msgid="9212602012641034283">"Pas toe"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Bevestig instellings"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Sommige kleurinstellings kan hierdie toestel onbruikbaar maak. Klik OK om hierdie kleurinstellings te bevestig; andersins sal hierdie instellings ná 10 sekondes teruggestel word."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterybespaarder is nie beskikbaar wanneer gelaai word nie"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterybespaarder"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Verminder werkverrigting en agtergronddata"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Knoppie <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Op"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Af"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Links"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Regs"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Middel"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Spasie"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Syferpaneel <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Stelsel"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Tuis"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Onlangs"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Wys \'moenie steur nie\' in volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Laat volledige beheer van \'moenie steur nie\' toe in die volumedialoog."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume en Moenie steur nie"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Aktiveer \'moenie steur nie\' met volume af"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Kennisgewings"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Kortpadsleutels"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Wissel invoermetode"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programme"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bystand"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Blaaier"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakte"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pos"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Kitsboodskappe"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiek"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Wys saam met volumekontroles"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Moenie steur nie"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppieskortpad"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Verlaat \'moenie steur nie\' met volume op"</string>
     <string name="battery" msgid="7498329822413202973">"Battery"</string>
     <string name="clock" msgid="7416090374234785905">"Horlosie"</string>
     <string name="headset" msgid="4534219457597457353">"Kopstuk"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Oorfone is gekoppel"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Kopstuk is gekoppel"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Aktiveer of deaktiveer ikone om op die statusbalk gewys te word."</string>
     <string name="data_saver" msgid="5037565123367048522">"Databespaarder"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Databespaarder is aan"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Databespaarder is af"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Aan"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Af"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigasiebalk"</string>
     <string name="start" msgid="6873794757232879664">"Begin"</string>
     <string name="center" msgid="4327473927066010960">"Middel"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Kies Sleutelbordknoppie"</string>
     <string name="preview" msgid="9077832302472282938">"Voorskou"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om teëls by te voeg"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hierheen om te verwyder"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Wysig"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Tyd"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Wys ure, minute en sekondes"</item>
+    <item msgid="1427801730816895300">"Wys ure en minute (verstek)"</item>
+    <item msgid="3830170141562534721">"Moenie hierdie ikoon wys nie"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Wys altyd persentasie"</item>
+    <item msgid="2139628951880142927">"Wys persentasie wanneer gelaai word (verstek)"</item>
+    <item msgid="3327323682209964956">"Moenie hierdie ikoon wys nie"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Ander"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Skermverdeler"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Skuif af"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Skuif op"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Skuif links"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Skuif regs"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Program sal dalk nie met multivenster werk nie"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dubbeltik om te wysig."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dubbeltik om by te voeg."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>. Dubbeltik om te kies."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Skuif <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Verwyder <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is by posisie <xliff:g id="POSITION">%2$d</xliff:g> gevoeg"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verwyder"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is na posisie <xliff:g id="POSITION">%2$d</xliff:g> geskuif"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kitsinstellingswysiger."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
new file mode 100644
index 0000000..0ed4860
--- /dev/null
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Maak PIP toe"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Volskerm"</string>
+    <string name="pip_play" msgid="674145557658227044">"Speel"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Laat wag"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Hou "<b>"TUIS"</b>" om PIP te beheer"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Druk en hou die TUIS-knoppie om PIP te beheer"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Het dit"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Maak toe"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 2b31ece..eb5d256 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"በተገደበ የማከማቻ ቦታ ምክንያት ወይም በመተግበሪያው ወይም በድርጅትዎ ስለማይፈቀድ የማያ ገጽ ቅጽበታዊ እይታዎችን ማንሳት አይቻልም።"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ቅጽበታዊ ገጽ ዕይታን በማስቀመጥ ጊዜ ችግር አጋጥሟል።"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ባለው የተገደበ የማከማቻ ቦታ ምክንያት ቅጽበታዊ ገጽ ዕይታን ማስቀመጥ አይችልም።"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም።"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"የUSB ፋይል ሰደዳ አማራጮች"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"እንደ ማህደረ አጫዋች (MTP) ሰካ"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"እንደ ካሜራ (PTP) ሰካ"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> አስወግድ።"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ተሰናብቷል::"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ሁሉም የቅርብ ጊዜ ማመልከቻዎች ተሰናብተዋል።"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> በመጀመር ላይ።"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ማሳወቂያ ተወግዷል።"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ተጨማሪ ጊዜ።"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ያነሰ ጊዜ።"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"የባትሪ ብርሃን ጠፍቷል።"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"የባትሪ ብርሃን አይገኝም።"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"የባትሪ ብርሃን በርቷል።"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"የባትሪ ብርሃን ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"የባትሪ ብርሃን በርቷል።"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"የሥራ ሁነታ በርቷል።"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"የሥራ ሁነታ ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"የሥራ ሁነታ በርቷል።"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ውሂብ ቆጣቢ ጠፍቷል።"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ውሂብ ቆጣቢ በርቷል።"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ብሩህነት ያሳዩ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2ጂ-3ጂ ውሂብ ላፍታ ቆሟል"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"የአካባቢ ጥያቄዎች ነቅተዋል"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ሁሉንም ማሳወቂያዎች አጽዳ"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"የማሳወቂያ ቅንብሮች"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"የ<xliff:g id="APP_NAME">%s</xliff:g> ቅንብሮች"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ማያ ገጽ በራስ ሰር ይዞራል።"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ገደብ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"የሥራ ሁነታ"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"የቅርብ ጊዜ ማያ ገጾችዎ እዚህ ይታያሉ"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ሁሉንም ነገር አጽድተዋል"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ማያ ገጽ መሰካት"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ን መጀመር አልተቻለም።"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ታሪክ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ጥረግ"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> በጥንቃቄ ሁነታ ውስጥ ታግዷል።"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ሁሉንም አጽዳ"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ይህ መተግበሪያ ብዝሃ-መስኮትን አይደግፍም"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"መተግበሪያው ብዝሃ-መስኮትን አይደግፍም"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ቁልቁል ክፈል"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"በብጁ ክፈል"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"ሙሉ ለሙሉ\nጸጥታ"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ቅድሚያ ተሰጪ\nብቻ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ማንቂያዎች\nብቻ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"ሁሉም"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ሁሉም\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ኃይል በፍጥነት በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ኃይል በዝግታ በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"የተከፈለ ማያ ገጽ ወደላይ አንሸራትቶ ማፍጠንን ያንቁ"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"የተከፈለ ማያ ገጽ ወደ ላይ የማንሸራተት ጣት ምልክትን ያንቁ"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ከአጠቃላይ እይታ አዝራሩ ወደ ላይ በማንሸራተት ወደ የተከፈለ ማያ ገጽ የሚገቡበትን የጣት ምልክት ያንቁ"</string>
     <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"አብራ"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"በ<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ማሳወቂያዎች ላይ ተግብር"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ከዚህ መተግበሪያ በሚመጡ ሁሉም ማሳወቂያዎች ላይ ተግብር"</string>
+    <string name="show_silently" msgid="6841966539811264192">"ማሳወቂያዎችን በጸጥታ አሳይ"</string>
+    <string name="block" msgid="2734508760962682611">"ሁሉንም ማሳወቂያዎች አግድ"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ድምፅ አትዝጋ"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ድምፅ አትዝጋ ወይም አታግድ"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ሙሉ የአስፈላጊነት ቅንብሮችን አሳይ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"የታገዱ"</string>
+    <string name="min_importance" msgid="1901894910809414782">"አነስተኛ አስፈላጊነት"</string>
     <string name="low_importance" msgid="4109929986107147930">"ዝቅተኛ አስፈላጊነት"</string>
     <string name="default_importance" msgid="8192107689995742653">"መደበኛ አስፈላጊነት"</string>
     <string name="high_importance" msgid="1527066195614050263">"ከፍተኛ አስፈላጊነት"</string>
     <string name="max_importance" msgid="5089005872719563894">"አስቸኳይ አስፈላጊነት"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"እነዚህን ማሳወቂያዎች በጭራሽ አታሳይ"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"በማሳወቂያ ዝርዝሩ ታችኛውን ክፍል ላይ በጸጥታ አሳይ"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"እነዚህን ማሳወቂያዎች በጸጥታ አሳይ"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"በማሳወቂያዎች ዝርዝር ላይኛው ክፍል ላይ አሳይና ድምፅ አሰማ"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"ወደ ገጸ ማያው ይመልከቱና ድምፅ ይቅረጹ"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"በማሳወቂያ ዝርዝሩ ታችኛውን ክፍል ላይ በጸጥታ አሳይ"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"እነዚህን ማሳወቂያዎች በጸጥታ አሳይ"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"እነዚህ ማሳወቂያዎች ድምፆችን እንዲፈጥሩ ፍቀድ"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"ወደ ማያ ገጹ አስገባና ድምፅ ፍቀድ"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"በማሳወቂያዎች ዝርዝር አናት ላይ አሳይ፣ ወደ ማያ ገጹ አሳይና ድምፅ ፍቀድ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
     <string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"መደበኛ ቀለሞች"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"የለሊት ቀለሞች"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"ብጁ ቀለሞች"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"ራስ-ሰር"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"የማይታወቁ ቀለሞች"</string>
-    <string name="color_transform" msgid="6985460408079086090">"የቀለም ማሻሻያ"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"የፈጣን ቅንብሮች ሰቅን አሳይ"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"ብጁ ቅየራን አንቃ"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ማሳወቂያ ቁጥጥሮች"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"ቀለም እና መልክ"</string>
+    <string name="night_mode" msgid="3540405868248625488">"የሌሊት ሁነታ"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ማሳያን ይለኩ"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"በርቷል"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ጠፍቷል"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"በራስ-ሰር አብራ"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ለአካባቢው እና ለሰዓቱ ተገቢ በሆነ መልኩ ወደ የማታ ሁነታ ለውጥ"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"የማታ ሁነታ  ሲበራ"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"ለAndroid ስርዓተ ክወና ጨለማ ገጽታን ተጠቀም"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ቅልም አስተካክል"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ብሩህነት አስተካክል"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ጨለማ ገጽታው እንደ ቅንብሮች ያሉ በመደበኛነት በብርሃን ገጽታ በሚታዩ የAndroid ስርዓተ ክወና ዋና ክፍሎች ላይ ይተገበራል።"</string>
     <string name="color_apply" msgid="9212602012641034283">"ተግብር"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ቅንብሮችን ያረጋግጡ"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"አንዳንድ የቀለም ቅንብሮች ይህን መሣሪያ የማይጠቅም ሊያደርጉት ይችላሉ። እነዚህን የቀለም ቅንብሮች ለማረጋገጥ እሺ የሚለውን ጠቅ ያድርጉ፣ አለበለዚያ እነዚህ ቅንብሮች ከ10 ሰከንዶች በኋላ ዳግም ይጀምራሉ።"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"የባትሪ አጠቃቀም"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ኃይል በሚሞላበት ጊዜ ባትሪ ቆጣቢ አይገኝም"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ባትሪ ቆጣቢ"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"አፈጻጸምን እና የጀርባ ውሂብን ይቀንሳል"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"አዝራር <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"መነሻ"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"ተመለስ"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ላይ"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ወደታች"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ግራ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ቀኝ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"መሃል"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"ትር"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"ክፍተት"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"አስገባ"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"የኋሊት መደምሰሻ"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"አጫውት/ለአፍታ አቁም"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"አቁም"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"ቀጣይ"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ቀዳሚ"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ወደኋላ አጠንጥን"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"በፍጥነት አሳልፍ"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"ገጽ ወደ ላይ"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"ገጽ ወደ ታች"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ሰርዝ"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"መነሻ"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"መጨረሻ"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"አስገባ"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"የቁጥር ሰሌዳ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ሥርዓት"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"መነሻ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"የቅርብ ጊዜዎቹ"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ተመለስ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"በድምጽ ውስጥ አትረብሽን አሳይ"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"በድምጽ ንግግር ውስጥ አትረብሽን ሙሉ ቁጥጥር ይፍቀዱ።"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ድምጽ እና አትረብሽ"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ድምጽ ሲቀነስ አትረብሽ አስገባ"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ማሳወቂያዎች"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"የቁልፍ ሰሌዳ አቋራጮች"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"የግቤት ስልት ቀይር"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"መተግበሪያዎች"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ረዳት"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"አሳሽ"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"እውቂያዎች"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ኢሜይል"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"ፈጣን መልዕክት"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ሙዚቃ"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"የቀን መቁጠሪያ"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"ከድምፅ መቆጣጠሪያዎች ጋር አሳይ"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"አትረብሽ"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"የድምፅ አዝራሮች አቋራጭ"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ድምጽ ሲጨመር አትረብሽን ትተህ ውጣ"</string>
     <string name="battery" msgid="7498329822413202973">"ባትሪ"</string>
     <string name="clock" msgid="7416090374234785905">"ሰዓት"</string>
     <string name="headset" msgid="4534219457597457353">"ጆሮ ማዳመጫ"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"የጆር ማዳመጫዎች ተገናኝተዋል"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"የጆሮ ማዳመጫ ተገናኝቷል"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"አዶዎች በሁኔታ አሞሌ ላይ እንዲታዩ ወይም እንዳይታዩ ያንቁ ወይም ያሰናክሉ።"</string>
     <string name="data_saver" msgid="5037565123367048522">"ውሂብ ቆጣቢ"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ውሂብ ቆጣቢ በርቷል"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ውሂብ ቆጣቢ ጠፍቷል"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"በርቷል"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ጠፍቷል"</string>
     <string name="nav_bar" msgid="1993221402773877607">"የአሰሳ አሞሌ"</string>
     <string name="start" msgid="6873794757232879664">"ጀምር"</string>
     <string name="center" msgid="4327473927066010960">"መሃል"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"የቁልፍ ሰሌዳ አዝራር ይምረጡ"</string>
     <string name="preview" msgid="9077832302472282938">"ቅድመ-እይታ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ሰቆችን ለማከል ይጎትቱ"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ለማስወገድ ወደዚህ ይጎትቱ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"አርትዕ"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"ሰዓት"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"ሰዓቶችን፣ ደቂቃዎችን፣ ሴኮንዶችን አሳይ"</item>
+    <item msgid="1427801730816895300">"ሰዓቶችን እና ደቂቃዎችን አሳይ (ነባሪ)"</item>
+    <item msgid="3830170141562534721">"ይህን አዶ አታሳይ"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"ሁልጊዜ መቶኛ አሳይ"</item>
+    <item msgid="2139628951880142927">"የባትሪ ኃይል በሚሞላበት ጊዜ መቶኛ አሳይ (ነባሪ)"</item>
+    <item msgid="3327323682209964956">"ይህን አዶ አታሳይ"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"ሌላ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"የተከፈለ የማያ ገጽ ከፋይ"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ወደ ታች ሂድ"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ወደ ላይ ሂድ"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ወደ ግራ ሂድ"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ወደ ቀኝ ሂድ"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"መተግበሪያ ከብዝሃ-መስኮት ጋር ላይሠራ ይችላል"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ቦታ <xliff:g id="POSITION">%1$d</xliff:g>፣ <xliff:g id="TILE_NAME">%2$s</xliff:g>። ለማርትዕ ሁለቴ መታ ያድርጉ።"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>። ለማከል ሁለቴ መታ ያድርጉ።"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ቦታ <xliff:g id="POSITION">%1$d</xliff:g>። ለመምረጥ ሁለቴ መታ ያድርጉ።"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ን ይውሰዱ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ን ያስወግዱ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ወደ ቦታ <xliff:g id="POSITION">%2$d</xliff:g> ታክሏል"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ተወግዷል"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ወደ ቦታ <xliff:g id="POSITION">%2$d</xliff:g> ተወስዷል"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"የፈጣን ቅንብሮች አርታዒ።"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
new file mode 100644
index 0000000..9df1916
--- /dev/null
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIPን ዝጋ"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"ሙሉ ማያ ገጽ"</string>
+    <string name="pip_play" msgid="674145557658227044">"አጫውት"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"ለአፍታ አቁም"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIPን ለመቆጣጠር "<b>"መነሻ"</b>"ን ይያዙ"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIPን ለመቆጣጠር የመነሻ አዝራሩን ተጭነው ይያዙ"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"ገባኝ"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"አሰናብት"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1a1fc2b..82a772c 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -77,7 +77,9 @@
     <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="1260203058661337274">"يتعذر التقاط لقطة شاشة نظرًا لأن مساحة التخزين المتاحة محدودة، أو نظرًا لعدم سماح التطبيق أو المؤسسة بذلك."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"حدثت مشكلة أثناء حفظ لقطة الشاشة."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"يتعذر حفظ لقطة الشاشة نظرًا لأن مساحة التخزين المتاحة محدودة."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"غير مسموح بالتقاط لقطات شاشة نظرًا لإذن يتعلق بالتطبيق أو بالمؤسسة."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"‏خيارات نقل الملفات عبر USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏تحميل كمشغل وسائط (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏تحميل ككاميرا (PTP)"</string>
@@ -170,6 +172,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"إزالة <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"تمت إزالة <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"تم تجاهل كل التطبيقات المستخدمة مؤخرًا."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"جارٍ بدء <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"تم تجاهل الإشعار."</string>
@@ -210,6 +214,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"وقت أكثر."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"وقت أقل."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"إيقاف الفلاش."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"تطبيق المصباح اليدوي غير متاح."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"تشغيل الفلاش."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"تم إيقاف الفلاش."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"تم تشغيل الفلاش."</string>
@@ -222,6 +227,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"وضع العمل قيد التشغيل."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"تم تعطيل وضع العمل."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"تم تشغيل وضع العمل."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"تم تعطيل توفير البيانات."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"تم تشغيل توفير البيانات."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"سطوع الشاشة"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"بيانات شبكات الجيل الثاني والثالث متوقفة مؤقتًا"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
@@ -235,6 +242,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"‏تم تعيين الموقع بواسطة GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"طلبات الموقع نشطة"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"محو جميع الإشعارات."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"و<xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"إعدادات الإشعارات"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"إعدادات <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"سيتم تدوير الشاشة تلقائيًا."</string>
@@ -300,15 +308,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"قيد <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"تحذير <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"وضع العمل"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"تظهر شاشاتك المعروضة مؤخرًا هنا"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"لقد محوتَ كل شيء"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"تثبيت الشاشة"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"تعذر بدء <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"السجلّ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"محو"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"تم تعطيل <xliff:g id="APP">%s</xliff:g> في الوضع الآمن."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"مسح الكل"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"لا يتيح هذا التطبيق النوافذ المتعددة."</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"لا يتيح التطبيق النوافذ المتعددة."</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسيم أفقي"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسيم رأسي"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"تقسيم مخصص"</string>
@@ -338,8 +347,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"كتم الصوت\nتمامًا"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"الأولوية \nفقط"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"التنبيهات\nفقط"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"الكل"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"الكل\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"جارٍ الشحن سريعًا (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"جارٍ الشحن ببطء (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
@@ -452,61 +459,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
     <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"تمكين مسارع تقسيم الشاشة بالتمرير السريع لأعلى"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"تمكين إيماءة تقسيم الشاشة بالتمرير السريع لأعلى"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"تمكين الإيماء لإدخال تقسيم الشاشة من خلال التمرير السريع لأعلى من زر النظرة العامة"</string>
     <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"تشغيل البلوتوث؟"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"لتوصيل لوحة المفاتيح بالجهاز اللوحي، يلزمك تشغيل بلوتوث أولاً."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"تشغيل"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"التطبيق على إشعارات <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"التطبيق في جميع الإشعارات من هذا التطبيق"</string>
+    <string name="show_silently" msgid="6841966539811264192">"عرض الإشعارات بدون تنبيه صوتي"</string>
+    <string name="block" msgid="2734508760962682611">"حظر كل الإشعارات"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"عدم كتم التنبيه الصوتي"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"عدم كتم التنبيه الصوتي أو حظر الإشعار"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"عرض الإعدادات الكاملة لمدى الأهمية"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"تم الحظر"</string>
+    <string name="min_importance" msgid="1901894910809414782">"الأقل أهمية"</string>
     <string name="low_importance" msgid="4109929986107147930">"أهمية منخفضة"</string>
     <string name="default_importance" msgid="8192107689995742653">"أهمية عادية"</string>
     <string name="high_importance" msgid="1527066195614050263">"أهمية عالية"</string>
     <string name="max_importance" msgid="5089005872719563894">"أهمية ملحَّة"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"عدم عرض هذه الإشعارات"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"العرض أسفل قائمة الإشعارات بدون تنبيه صوتي"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"عرض هذه الإشعارات بدون تنبيه صوتي"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"العرض أعلى قائمة الإشعارات مع تنبيه صوتي"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"الظهور سريعًا على الشاشة مع تنبيه صوتي"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"عرض الإشعار بأسفل قائمة الإشعارات بدون تنبيه صوتي"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"عرض هذه الإشعارات بدون تنبيه صوتي"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"السماح لهذه الإشعارات بإصدار تنبيهات صوتية"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"يتم عرض الإشعار بسرعة على الشاشة مع السماح بإصدار تنبيه صوتي"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"عرض هذا الإشعار بأعلى قائمة الإشعارات وعرضه بسرعة على الشاشة مع السماح بإصدار تنبيه صوتي"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
     <string name="notification_done" msgid="5279426047273930175">"تم"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"ألوان عادية"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"ألوان ليلية"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"ألوان مخصصة"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"تلقائي"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"ألوان غير معروفة"</string>
-    <string name="color_transform" msgid="6985460408079086090">"إشعار الألوان"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"إظهار قسم الإعدادات السريعة"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"تمكين التحويل المخصص"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"عناصر التحكم في إشعارات <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"اللون والمظهر"</string>
+    <string name="night_mode" msgid="3540405868248625488">"الوضع الليلي"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"معايرة الشاشة"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"تشغيل"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"إيقاف"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"التشغيل تلقائيًا"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"التبديل إلى الوضع الليلي بما يتناسب مع الموقع والوقت من اليوم"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"عند تشغيل الوضع الليلي"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"‏استخدام مظهر معتم لنظام التشغيل Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ضبط التلوين الخفيف"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ضبط السطوع"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"‏يتم تطبيق المظهر المعتم على المناطق الأساسية في نظام التشغيل Android والتي يتم عرضها عادة في مظهر مضيء، مثل الإعدادات."</string>
     <string name="color_apply" msgid="9212602012641034283">"تطبيق"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"تأكيد الإعدادات"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"يمكن أن تتسبب بعض إعدادات الألوان في تعطيل إمكانية استخدام الجهاز. يمكنك النقر على \"موافق\" لتأكيد إعدادات الألوان هذه، وإلا فستتم إعادة تعيين هذه الإعدادات بعد 10 ثوانٍ."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"استخدام البطارية"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"وضع توفير شحن البطارية غير متاح أثناء الشحن."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"توفير شحن البطارية"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"لخفض مستوى الأداء وبيانات الخلفية"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"الزر <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"أعلى"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"أسفل"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"يسار"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"يمين"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"وسط"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"مسافة"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"تشغيل / إيقاف مؤقت"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"إيقاف"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"التالي"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"السابق"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"إرجاع"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"تقديم سريع"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"الرئيسية"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"لوحة الأرقام <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"النظام"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"الشاشة الرئيسية"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"الأحدث"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"رجوع"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"إظهار خيار \"الرجاء عدم الإزعاج\" في مستوى الصوت"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"السماح بالتحكم الكامل في خيار \"الرجاء عدم الإزعاج\" ضمن مربع حوار مستوى الصوت."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"إعدادات مستوى الصوت و\"الرجاء عدم الإزعاج\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"تشغيل \"الرجاء عدم الإزعاج\" عند خفض مستوى الصوت"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"الإشعارات"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"اختصارات لوحة المفاتيح"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"تبديل أسلوب الإدخال"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"التطبيقات"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"التطبيق المساعد"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"المتصفح"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"جهات الاتصال"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"البريد الإلكتروني"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"الرسائل الفورية"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"الموسيقى"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"التقويم"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"عرض مع عناصر التحكم في مستوى الصوت"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"الرجاء عدم الإزعاج"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"اختصار أزرار مستوى الصوت"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"تعطيل \"الرجاء عدم الإزعاج\" عند رفع مستوى الصوت"</string>
     <string name="battery" msgid="7498329822413202973">"البطارية"</string>
     <string name="clock" msgid="7416090374234785905">"ساعة"</string>
     <string name="headset" msgid="4534219457597457353">"سماعة الرأس"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"تم توصيل سماعات رأس"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"تم توصيل سماعات رأس"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"يمكنك تمكين أو تعطيل الرموز بحيث لا تظهر في شريط الحالة."</string>
     <string name="data_saver" msgid="5037565123367048522">"توفير البيانات"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"تم تشغيل توفير البيانات"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"تم تعطيل توفير البيانات"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"تشغيل"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"إيقاف"</string>
     <string name="nav_bar" msgid="1993221402773877607">"شريط التنقل"</string>
     <string name="start" msgid="6873794757232879664">"البدء"</string>
     <string name="center" msgid="4327473927066010960">"وسط"</string>
@@ -528,5 +581,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"تحديد زر لوحة المفاتيح"</string>
     <string name="preview" msgid="9077832302472282938">"معاينة"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"اسحب لإضافة مربعات"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"اسحب هنا للإزالة"</string>
     <string name="qs_edit" msgid="2232596095725105230">"تعديل"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"الوقت"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"عرض الساعات والدقائق والثواني"</item>
+    <item msgid="1427801730816895300">"عرض الساعات والدقائق (افتراضي)"</item>
+    <item msgid="3830170141562534721">"عدم عرض هذا الرمز"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"عرض النسبة المئوية دائمًا"</item>
+    <item msgid="2139628951880142927">"عرض النسبة المئوية عند الشحن (افتراضي)"</item>
+    <item msgid="3327323682209964956">"عدم عرض هذا الرمز"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"غير ذلك"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"أداة تقسيم الشاشة"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"نقل لأسفل"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"نقل لأعلى"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"نقل لليسار"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"نقل لليمين"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"يمكن ألا يعمل التطبيق مع وضع النوافذ المتعددة."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"الموضع <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>. انقر نقرًا مزدوجًا للتعديل."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. انقر نقرًا مزدوجًا للإضافة."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"الموضع <xliff:g id="POSITION">%1$d</xliff:g>. انقر نقرًا مزدوجًا للتحديد."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"نقل <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"إزالة <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"تمت إضافة <xliff:g id="TILE_NAME">%1$s</xliff:g> إلى الموضع <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"تمت إزالة <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"تم نقل <xliff:g id="TILE_NAME">%1$s</xliff:g> إلى الموضع <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"برنامج تعديل الإعدادات السريعة."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
new file mode 100644
index 0000000..e6fbffc
--- /dev/null
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"‏إغلاق PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"ملء الشاشة"</string>
+    <string name="pip_play" msgid="674145557658227044">"تشغيل"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"إيقاف مؤقت"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"‏اضغط "<b>"الرئيسية"</b>" للتحكم في PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"‏اضغط مع الاستمرار على زر الشاشة الرئيسية للتحكم في PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"حسنًا"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"رفض"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 690317f..59b3141 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skrinşot çəkildi."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Skrinşotunuza baxmaq üçün toxunun"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Skrinşot götürülə bilinmədi."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Yaddaş ehtiyatının az olması səbəbindən skrinşot çəkmək olmur və ya bunu etmək ya tətbiq, ya da şirkət tərəfindən qadağan olunub."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Skrinşot yadda saxlanarkən problem baş verdi."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Yaddaş ehtiyatının az olması səbəbindən skrinşotu yadda saxlamaq olmur."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Tətbiq və ya təşkilatınız tərəfindən skrinşot çəkməyə icazə verilmir."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB fayl transferi seçimləri"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer (MTP) kimi montaj edin"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera kimi birləşdir (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> kənarlaşdırın."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> çıxarıldı."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Bütün son tətbiqlər kənarlaşdırıldı."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlanır."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildiriş uzaqlaşdırıldı."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daha çox vaxt."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Daha az vaxt."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Fənər deaktiv."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Fənər əlçatan deyil."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Fənər aktiv."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Fənər deaktivdir."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Fənər aktivdir."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"İş rejimi aktivdir."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"İş rejimi sönülüdür."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"İş rejimi yanılıdır."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Data Qənaəti deaktiv edildi."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Data Qənaəti aktiv edildi."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G məlumatlarına fasilə verildi"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G məlumatlarına fasilə verildi"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Yer GPS tərəfindən müəyyən edildi"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Məkan sorğuları arxivi"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Bütün bildirişləri sil."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Bildiriş ayarları"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ayarları"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran avtomatik döndəriləcək."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> xəbərdarlığı"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"İş rejimi"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Son elementlər yoxdur"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hərşeyi təmizlədiniz"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Tətbiq haqqında"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sancağı"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"axtarış"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlana bilmir."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> güvənli rejimdə deaktiv edildi."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Tarixçə"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Təmizləyin"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hamısını silin"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu tətbiq çoxsaylı pəncərəni dəstəkləmir"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Bu tətbiq çoxsaylı pəncərəni dəstəkləyir"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Üfüqi Böl"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Şaquli Böl"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Fərdi Böl"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Tam\nsakitlik"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnız\nprioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnız\nalarmlar"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Bütün"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Bütün\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sürətli qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ləng qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Bölünmüş ekran sürüşdürməsi akseleratorunu aktiv edin"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bölünmüş ekran sürüşdürməsi aktiv edin"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Jestlərin icmal düyməsindən yuxarı sürüşdürərək bölünmüş ekrana daxil olmasını aktiv edin"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivləşsin?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Tabletinizlə klaviaturaya bağlanmaq üçün ilk olaraq Bluetooth\'u aktivləşdirməlisiniz."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivləşdirin"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> bildirişlərinə müraciət edin"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Bu tətbiqdən olan bütün bildirişlərə müraciət edin"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Bildirişləri səssiz göstərin"</string>
+    <string name="block" msgid="2734508760962682611">"Bütün bildirişləri blok edin"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Səssiz etməyin"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Səssiz və ya blok etməyin"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tam əhəmiyyətlilik ayarlarını göstərin"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloklanmış"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimum əhəmiyyətli"</string>
     <string name="low_importance" msgid="4109929986107147930">"Az əhəmiyyətli"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normal əhəmiyyətli"</string>
     <string name="high_importance" msgid="1527066195614050263">"Çox əhəmiyyətli"</string>
     <string name="max_importance" msgid="5089005872719563894">"Təcili əhəmiyyətli"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirişləri heç vaxt göstərməyin"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildişləri səssiz göstərin"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Bildirişlər siyahısında yuxarıda göstərin və səsli edin"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Ekranda nəzər salın və səsli edin"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildişləri səssiz göstərin"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirişi səsli edin"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Ekranda nəzər salın və səsə icazə verin"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Bildirişlər siyahısında yuxarıda göstərin, ekrana nəzər salın və səsə icazə verin"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normal rənglər"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Gecə rəngləri"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Xüsusi rənglər"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Avto"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Naməlum rəng"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Rəng modifikasiyası"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Cəld ayarlar örtüyünü göstərin"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Xüsusi dəyişikliyi aktiv edin"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildiriş nəzarəti"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Rəng və görünüş"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Gecə rejimi"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Ekranı kalibrləyin"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Aktiv"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Deaktiv"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Avtomatik aktivləşdirin"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Məkana və günün vaxtına uyğun olaraq Gecə Rejiminə keçin"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Gecə Rejimi aktiv olduqda"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS üçün tünd tema istifadə edin"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Çaları nizamlayın"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Parlaqlığı nizamlayın"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tünd tema Android OS sisteminin adətən işıqlı tema göstərilən Ayarlar kimi əsas sahələri üçün tətbiq edilir."</string>
     <string name="color_apply" msgid="9212602012641034283">"Tətbiq edin"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Ayarları təsdiq edin"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Bəzi renk ayarları bu cihazı yararsız edə bilər. Bu rənk ayarlarını təsdiq etmək üçün OK basın, əks halda bu ayarlar 10 saniyə sonra sıfırlanacaq."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Enerji Qənaəti doldurulma zamanı əlçatan deyil"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Enerji Qənaəti"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Düymə <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Əsas səhifə"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Geri"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Yuxarı"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Aşağı"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Sol"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Sağ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Mərkəz"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Boşluq"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Daxil olun"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Gerisil"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Oxut/Durdur"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Dayandırın"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Növbəti"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Öncəki"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Geri ötürmə"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"İrəli Ötürmə"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Yuxarı Səhifə"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Aşağı Səhifə"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Silin"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Əsas səhifə"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Son"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Daxil edin"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Nömrələr"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Rəqəmli düymələr <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Əsas səhifə"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Sonuncular"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Səsdə \"narahat etməyin\" rejimini göstərin"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Səs dioloqunda \"narahat etməyin\" rejiminin tam nərarətinə icazə verin."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Səs və \"narahat etməyin\" rejimi"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Aşağı səsdə \"narahat etməyin\" rejimini daxil edin"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirişlər"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klaviatura qısa yolları"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Daxiletmə metoduna keçin"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Tətbiqlər"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Yardım"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauzer"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktlar"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-poçt"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiqi"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Təqvim"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Həcm nəzarəti ilə göstərin"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Narahat etməyin"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Səs düymələri qısayolu"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Yuxarı səsdə \"narahat etməyin\" rejimini daxil edin"</string>
     <string name="battery" msgid="7498329822413202973">"Batareya"</string>
     <string name="clock" msgid="7416090374234785905">"Saat"</string>
     <string name="headset" msgid="4534219457597457353">"Qulaqlıq"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Qulaqlıq qoşulub"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Qulaqlıq qoşulub"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"İkonaların status panelində görünməsini aktiv və ya deaktiv edin."</string>
     <string name="data_saver" msgid="5037565123367048522">"Data Qənaəti"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Qənaəti aktivdir"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Qənaəti deaktivdir"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Aktiv"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Deaktiv"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Naviqasiya paneli"</string>
     <string name="start" msgid="6873794757232879664">"Başladın"</string>
     <string name="center" msgid="4327473927066010960">"Mərkəz"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Klaviatura Düyməsi Seçin"</string>
     <string name="preview" msgid="9077832302472282938">"Önizləmə"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Xanalar əlavə etmək üçün sürüşdürün"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Silmək üçün bura sürüşdürün"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Redaktə edin"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Vaxt"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Saat, dəqiqə və saniyəni göstərin"</item>
+    <item msgid="1427801730816895300">"Saat və dəqiqəni göstərin (defolt)"</item>
+    <item msgid="3830170141562534721">"Bu piktoqramı göstərməyin"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Faizi həmişə göstərin"</item>
+    <item msgid="2139628951880142927">"Enerji dolan zaman faizi göstərin (defolt)"</item>
+    <item msgid="3327323682209964956">"Bu piktoqramı göstərməyin"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Digər"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Bölünmüş ekran ayırıcısı"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Aşağıya keçin"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yuxarıya keçin"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola köçürün"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa köçürün"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Tətbiq çoxsaylı pəncərə ilə işləməyə bilər."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Redaktə etmək üçün iki dəfə tıklayın."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Əlavə etmək üçün iki dəfə tıklayın."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi. Seçmək üçün iki dəfə tıklayın."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> köçürün"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> silin"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> mövqeyinə əlavə edildi"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> silindi"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> mövqeyinə köçürüldü"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Sürətli ayarlar redaktoru."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings_tv.xml b/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
new file mode 100644
index 0000000..63fc9fd
--- /dev/null
+++ b/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP bağlayın"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Tam ekran"</string>
+    <string name="pip_play" msgid="674145557658227044">"Göstərin"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Fasilə verin"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP idarı etmək üçün "<b>"Əsas səhifəni"</b>" tutub saxlayın"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PİP nəzarət etmək üçün ƏSAS EKRAN düyməni basıb saxlayın"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Anladım"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Rədd edin"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 3ae995b..0945885 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -74,7 +74,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Snimak ekrana je napravljen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite da biste videli snimak ekrana."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nije moguće napraviti snimak ekrana."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Nije moguće snimiti ekran zbog nedovoljne memorije ili to ne dozvoljava aplikacija ili organizacija."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Došlo je do problema pri čuvanju snimka ekrana."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Čuvanje snimka ekrana nije uspelo zbog ograničenog memorijskog prostora."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikacija ili organizacija ne dozvoljavaju pravljenje snimaka ekrana."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prenosa datoteka"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Priključi kao medija plejer (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Priključi kao kameru (PTP)"</string>
@@ -167,6 +169,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacite <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je odbačena."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korišćene aplikacije su odbačene."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećemo <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obaveštenje je odbačeno."</string>
@@ -207,6 +211,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Baterijska lampa je isključena."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampa nije dostupna."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Baterijska lampa je uključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Baterijska lampa je isključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Baterijska lampa je uključena."</string>
@@ -219,6 +224,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Režim rada je uključen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Režim rada je isključen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Režim rada je uključen."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Ušteda podataka je isključena."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Ušteda podataka je uključena."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Osvetljenost ekrana"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G podaci su pauzirani"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci su pauzirani"</string>
@@ -232,6 +239,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju je podesio GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Ima aktivnih zahteva za lokaciju"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Obriši sva obaveštenja."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"i još <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Podešavanja obaveštenja"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Podešavanja za <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
@@ -297,15 +305,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje za <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Režim rada"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Nedavni ekrani se pojavljuju ovde"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Obrisali ste sve"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kačenje ekrana"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g> nije uspelo."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Istorija"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Obriši"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> je onemogućena u bezbednom režimu."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ova aplikacija ne podržava režim sa više prozora"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava režim sa više prozora"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podeli horizontalno"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podeli vertikalno"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođeno deljenje"</string>
@@ -335,8 +344,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Potpuna\ntišina"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\npriorit. prekidi"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Sve"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Svi\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (pun je za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo se puni (napuniće se za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo se puni (napuniće se za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -449,61 +456,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sekunde na satu se prikazuju na statusnoj traci. To može da utiče na trajanje baterije."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi Brza podešavanja"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvetljenost u Brzim podešavanjima"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogući ubrzavač za prevlačenje nagore za podeljeni ekran"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret za prevlačenje nagore za podeljeni ekran"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućava pokret za prelazak na podeljeni ekran prevlačenjem nagore od dugmeta Pregled"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Primeni na obaveštenja o temi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Primeni na sva obaveštenja iz ove aplikacije"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Prikazuj obaveštenja bez zvuka"</string>
+    <string name="block" msgid="2734508760962682611">"Blokiraj sva obaveštenja"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne isključuj zvuk"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne isključuju zvuk niti blokiraj"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži kompletna podešavanja važnosti"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokirana"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Veoma mala važnost"</string>
     <string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
     <string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
     <string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
     <string name="max_importance" msgid="5089005872719563894">"Važnost: hitno"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ova obaveštenja se nikada ne prikazuju"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Ova obaveštenja se prikazuju bez zvuka"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Prikazuju se u vrhu liste obaveštenja i emituje se zvuk"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Nakratko se prikazuju na ekranu i emituje se zvuk"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ova obaveštenja se prikazuju bez zvuka"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite da ova obaveštenja emituju zvuk"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Nakratko se prikazuju na ekranu i emituju zvuk"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Prikazuju se u vrhu liste obaveštenja, nakratko se prikazuju na ekranu i emituju zvuk"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normalne boje"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatski"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Nepoznate boje"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Izmena boja"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaži pločicu Brza podešavanja"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Omogući prilagođenu transformaciju"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obaveštenja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Noćni režim"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibrišite ekran"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Uključeno"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Isključeno"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Automatski uključi"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Pređite na noćni režim u zavisnosti od lokacije i doba dana"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kada je noćni režim uključen"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Koristi tamnu temu za Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Prilagodi senku"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Prilagodi osvetljenost"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tamna tema se primenjuje na ključne delove Android OS-a koji se obično prikazuju u svetloj temi, poput Podešavanja."</string>
     <string name="color_apply" msgid="9212602012641034283">"Primeni"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Potvrdite podešavanja"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Neka podešavanja boja mogu da učine uređaj neupotrebljivim. Kliknite na Potvrdi da biste potvrdili ova podešavanja boja, pošto će se u suprotnom ova podešavanja resetovati nakon 10 sekundi."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Potrošnja baterije"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije nije dostupna tokom punjenja"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje performanse i pozadinske podatke"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Taster Početna"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Taster Nazad"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Taster sa strelicom nagore"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Taster sa strelicom nadole"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Taster sa strelicom nalevo"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Taster sa strelicom nadesno"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Taster sa centralnom strelicom"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulator"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Taster za razmak"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Taster za brisanje unazad"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Taster za reprodukciju/pauziranje"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Taster za zaustavljanje"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Taster Sledeća"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Taster Prethodna"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Taster za premotavanje unazad"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Taster za premotavanje unapred"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Taster za stranicu nagore"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Taster za stranicu nadole"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Taster za brisanje"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Taster Početna"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Taster za kraj"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Taster za umetanje"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Taster <xliff:g id="NAME">%1$s</xliff:g> na numeričkoj tastaturi"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni sadržaj"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Prikaži podešavanje Ne uznemiravaj u dijalogu za jačinu zvuka"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Dozvoljava potpunu kontrolu podešavanja Ne uznemiravaj u dijalogu za jačinu zvuka."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Jačina zvuka i Ne uznemiravaj"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Uđi u režim Ne uznemiravaj kada je zvuk utišan"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obaveštenja"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tasterske prečice"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promeni metod unosa"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Aplikacija za pomoć"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Pregledač"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Imejl"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Razmena trenutnih poruka"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži sa kontrolama jačine zvuka"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za jačinu zvuka"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Izađi iz režima Ne uznemiravaj kada je zvuk pojačan"</string>
     <string name="battery" msgid="7498329822413202973">"Baterija"</string>
     <string name="clock" msgid="7416090374234785905">"Sat"</string>
     <string name="headset" msgid="4534219457597457353">"Naglavne slušalice"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalice su povezane"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Naglavne slušalice su povezane"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Omogućite ili onemogućite prikazivanje ikona na statusnoj traci."</string>
     <string name="data_saver" msgid="5037565123367048522">"Ušteda podataka"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ušteda podataka je uključena"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ušteda podataka je isključena"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Uključeno"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Isključeno"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Traka za navigaciju"</string>
     <string name="start" msgid="6873794757232879664">"Pokreni"</string>
     <string name="center" msgid="4327473927066010960">"Centar"</string>
@@ -525,5 +578,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Izaberite dugme za tastaturu"</string>
     <string name="preview" msgid="9077832302472282938">"Pregled"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Prevucite da biste dodali pločice"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovde da biste uklonili"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Izmeni"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Vreme"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Prikaži sate, minute i sekunde"</item>
+    <item msgid="1427801730816895300">"Prikaži sate i minute (podrazumevano)"</item>
+    <item msgid="3830170141562534721">"Ne prikazuj ovu ikonu"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Uvek prikazuj procenat"</item>
+    <item msgid="2139628951880142927">"Prikaži procenat tokom punjenja (podrazumevano)"</item>
+    <item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Drugo"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Razdelnik podeljenog ekrana"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomeri nadole"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomeri nagore"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomeri ulevo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomeri udesno"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće funkcionisati sa više prozora"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite da biste izmenili."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dvaput dodirnite da biste dodali."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija. Dvaput dodirnite da biste izabrali."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premesti pločicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni pločicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je dodata na <xliff:g id="POSITION">%2$d</xliff:g>. poziciju"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjena"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je premeštena na <xliff:g id="POSITION">%2$d</xliff:g>. poziciju"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivač za Brza podešavanja."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
new file mode 100644
index 0000000..d026d2c
--- /dev/null
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Zatvori PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Ceo ekran"</string>
+    <string name="pip_play" msgid="674145557658227044">"Pusti"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pauziraj"</string>
+    <string name="pip_hold_home" msgid="340086535668778109"><b>"POČETNI EKRAN"</b>" kont. PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Pritisnite i zadržite dugme POČETNI EKRAN da biste kontrolisali PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Važi"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-be-rBY-land/strings.xml b/packages/SystemUI/res/values-be-rBY-land/strings.xml
new file mode 100644
index 0000000..9b0cf06
--- /dev/null
+++ b/packages/SystemUI/res/values-be-rBY-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Цяпер экран заблакаваны ў альбомнай арыентацыі."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..726a0e7
--- /dev/null
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -0,0 +1,613 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * 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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_label" msgid="7164937344850004466">"Інтэрфейс карыстальніка сістэмы"</string>
+    <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ачысціць"</string>
+    <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Выдаліць са спісу"</string>
+    <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Звесткі аб прыкладанні"</string>
+    <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Вашы апошнія экраны з\'яўляюцца тут"</string>
+    <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Закрыць нядаўнія прыкладаннi"</string>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d экран у Аглядзе</item>
+      <item quantity="few">%d экраны ў Аглядзе</item>
+      <item quantity="many">%d экранаў у Аглядзе</item>
+      <item quantity="other">%d экрана ў Аглядзе</item>
+    </plurals>
+    <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Без апавяшчэнняў"</string>
+    <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Пастаянныя"</string>
+    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Апавяшчэнні"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Нізкі ўзровень зараду акумулятара"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>. Уключана эканомія зараду."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"USB-зарадка не падтрымліваецца.\nКарыстайцеся толькі зарадкай для прылады."</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Зарадка па USB не падтрымліваецца."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Выкарыстоўвайце толькі зарадную прыладу ў камплекце."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Налады"</string>
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Уключыць эканомію зараду?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Уключыць"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"Уключыць рэжым эканоміі зараду"</string>
+    <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налады"</string>
+    <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Аўтаматычны паварот экрана"</string>
+    <string name="status_bar_settings_mute_label" msgid="554682549917429396">"БЯЗГУЧНА"</string>
+    <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АЎТА"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Паведамленні"</string>
+    <string name="bluetooth_tethered" msgid="7094101612161133267">"Прывязаныя праз Bluetooth"</string>
+    <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Налада метадаў уводу"</string>
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Фізічная клавіятура"</string>
+    <string name="usb_device_permission_prompt" msgid="834698001271562057">"Дазволіць праыкладанню <xliff:g id="APPLICATION">%1$s</xliff:g> атрымлiваць доступ да прылады USB?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Дазволіць прыкладанню <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да прылады USB?"</string>
+    <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Адкрыць <xliff:g id="ACTIVITY">%1$s</xliff:g>, калі гэтая USB-прылада падлучаная?"</string>
+    <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Адкрыць <xliff:g id="ACTIVITY">%1$s</xliff:g>, калі гэтая USB-прылада падлучаная?"</string>
+    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Няма ўсталяв. прыкл. для працы з гэтай прыл. USB. Больш падраб. пра гэтую прыл.: <xliff:g id="URL">%1$s</xliff:g>"</string>
+    <string name="title_usb_accessory" msgid="4966265263465181372">"USB-прылада"</string>
+    <string name="label_view" msgid="6304565553218192990">"Прагляд"</string>
+    <string name="always_use_device" msgid="1450287437017315906">"Выкарыстоўваць налады па змаўчанні для дадзенай USB-прылады"</string>
+    <string name="always_use_accessory" msgid="1210954576979621596">"Выкарыстоўваць налады па змаўчанні для дадзенай USB-прылады"</string>
+    <string name="usb_debugging_title" msgid="4513918393387141949">"Дазволіць адладку USB?"</string>
+    <string name="usb_debugging_message" msgid="2220143855912376496">"Адбiтак ключа RSA на гэтым камп\'ютары:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="303335496705863070">"Заўсёды дазваляць з гэтага камп\'ютара"</string>
+    <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Адладка USB не дапускаецца"</string>
+    <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Карыстальнік, які зараз увайшоў на гэту прыладу, не можа ўключыць адладку USB. Каб выкарыстоўваць гэту функцыю, пераключыцеся на карыстальніка-адміністратара."</string>
+    <string name="compat_mode_on" msgid="6623839244840638213">"Павял. на ўвесь экран"</string>
+    <string name="compat_mode_off" msgid="4434467572461327898">"Расцягн. на ўвесь экран"</string>
+    <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_text" msgid="1152839647677558815">"Націсніце, каб прагледзець скрыншот"</string>
+    <string name="screenshot_failed_title" msgid="705781116746922771">"Не атрымалася зрабiць скрыншот."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Падчас захавання скрыншота адбылася памылка."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Немагчыма захаваць здымак экрана, бо мала месца ў памяці."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Рабіць здымкі экрана не дазваляе праграма ці ваша арганізацыя."</string>
+    <string name="usb_preference_title" msgid="6551050377388882787">"Парам. перадачы файлаў па USB"</string>
+    <string name="use_mtp_button_title" msgid="4333504413563023626">"Падлучыць як медыяпрайгравальнік (ССП)"</string>
+    <string name="use_ptp_button_title" msgid="7517127540301625751">"Падлучыць як камеру (PTP)"</string>
+    <string name="installer_cd_button_title" msgid="2312667578562201583">"Усталяваць прыклад. Android File Transfer для Mac"</string>
+    <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
+    <string name="accessibility_home" msgid="8217216074895377641">"На Галоўную старонку"</string>
+    <string name="accessibility_menu" msgid="316839303324695949">"Меню"</string>
+    <string name="accessibility_recent" msgid="5208608566793607626">"Агляд"</string>
+    <string name="accessibility_search_light" msgid="1103867596330271848">"Пошук"</string>
+    <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Тэлефон"</string>
+    <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Галасавая дапамога"</string>
+    <string name="accessibility_unlock_button" msgid="128158454631118828">"Разблакiраваць"</string>
+    <string name="accessibility_unlock_button_fingerprint" msgid="8214125623493923751">"Кнопка разблакіроўкі, чаканне адбітка пальца"</string>
+    <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Разблакіроўка без выкарыстання адбітка пальца"</string>
+    <string name="unlock_label" msgid="8779712358041029439">"разблакiраваць"</string>
+    <string name="phone_label" msgid="2320074140205331708">"адкрыць тэлефон"</string>
+    <string name="voice_assist_label" msgid="3956854378310019854">"адкрыць галасавую дапамогу"</string>
+    <string name="camera_label" msgid="7261107956054836961">"адкрыць камеру"</string>
+    <string name="recents_caption_resize" msgid="3517056471774958200">"Выберыце новы макет заданняў"</string>
+    <string name="cancel" msgid="6442560571259935130">"Адмяніць"</string>
+    <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка сумяшчальнасці маштаба."</string>
+    <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Маштабаванне малых элементаў для большага экрана."</string>
+    <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-сувязь."</string>
+    <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth адключаны."</string>
+    <string name="accessibility_no_battery" msgid="358343022352820946">"Без акумулятара."</string>
+    <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Адна планка акумулятара."</string>
+    <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"2 планкі акумулятара."</string>
+    <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Тры планкі акумулятара."</string>
+    <string name="accessibility_battery_full" msgid="8909122401720158582">"Акумулятар поўны."</string>
+    <string name="accessibility_no_phone" msgid="4894708937052611281">"Няма тэлефона."</string>
+    <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Адна планка на тэлефоне."</string>
+    <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"2 планкі тэлефона."</string>
+    <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"3 планкі тэлефона."</string>
+    <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Поўны сігнал тэлефона."</string>
+    <string name="accessibility_no_data" msgid="4791966295096867555">"Няма дадзеных."</string>
+    <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Адна планка дадзеных."</string>
+    <string name="accessibility_data_two_bars" msgid="6166018492360432091">"2 планкі дадзеных."</string>
+    <string name="accessibility_data_three_bars" msgid="9167670452395038520">"3 планкі дадзеных."</string>
+    <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Поўны сігнал перадачы дадзеных."</string>
+    <string name="accessibility_wifi_name" msgid="7202151365171148501">"Падключаны да <xliff:g id="WIFI">%s</xliff:g>."</string>
+    <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
+    <string name="accessibility_no_wimax" msgid="4329180129727630368">"Няма сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Адзiн слупок сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Два слупкi сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"Тры слупкi сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Моцны сiгнал WiMAX."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="5896059303377589469">"Ethernet адлучаны."</string>
+    <string name="accessibility_ethernet_connected" msgid="2692130313069182636">"Ethernet падлучаны."</string>
+    <string name="accessibility_no_signal" msgid="7064645320782585167">"Няма сігналу."</string>
+    <string name="accessibility_not_connected" msgid="6395326276213402883">"Няма падключэння."</string>
+    <string name="accessibility_zero_bars" msgid="3806060224467027887">"Няма."</string>
+    <string name="accessibility_one_bar" msgid="1685730113192081895">"Адзiн слупок."</string>
+    <string name="accessibility_two_bars" msgid="6437363648385206679">"Два слупкi."</string>
+    <string name="accessibility_three_bars" msgid="2648241415119396648">"Тры слупкi."</string>
+    <string name="accessibility_signal_full" msgid="9122922886519676839">"Сігнал поўны."</string>
+    <string name="accessibility_desc_on" msgid="2385254693624345265">"Уключана."</string>
+    <string name="accessibility_desc_off" msgid="6475508157786853157">"Адключана."</string>
+    <string name="accessibility_desc_connected" msgid="8366256693719499665">"Падключана."</string>
+    <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Падлучэнне."</string>
+    <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
+    <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
+    <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
+    <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
+    <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string>
+    <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
+    <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string>
+    <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
+    <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Роўмінг"</string>
+    <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
+    <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
+    <string name="accessibility_no_sim" msgid="8274017118472455155">"Няма SIM-карты."</string>
+    <string name="accessibility_cell_data_off" msgid="8000803571751407635">"Мабільная перадача даных адключана"</string>
+    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Сувязь па Bluetooth."</string>
+    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Рэжым палёту."</string>
+    <string name="accessibility_no_sims" msgid="3957997018324995781">"Няма SIM-карты."</string>
+    <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Змяненне аператара сеткі."</string>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for accessibility_battery_level (7451474187113371965) -->
+    <skip />
+    <string name="accessibility_settings_button" msgid="799583911231893380">"Сістэмныя налады."</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Апавяшчэнні."</string>
+    <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">"TeleTypewriter уключаны."</string>
+    <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Выклік з вібрацыяй."</string>
+    <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Маўклівы выклік."</string>
+    <!-- no translation found for accessibility_casting (6887382141726543668) -->
+    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Рэжым працы"</string>
+    <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Выдаліць <xliff:g id="APP">%s</xliff:g> са спіса апошніх."</string>
+    <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> выдалены."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усе апошнія праграмы адхілены."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
+    <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запускаецца <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
+    <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Апавяшчэнне прапушчана."</string>
+    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Цень апавяшчэння.."</string>
+    <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Хуткія налады."</string>
+    <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Экран блакіроўкі."</string>
+    <string name="accessibility_desc_settings" msgid="3417884241751434521">"Налады"</string>
+    <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Агляд."</string>
+    <string name="accessibility_desc_close" msgid="7479755364962766729">"Закрыць"</string>
+    <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Карыстальнік: <xliff:g id="USER">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi выключаны."</string>
+    <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wi-Fi уключаны."</string>
+    <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Мабiльны сiгнал: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Акумулятар: <xliff:g id="STATE">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Рэжым палёту выключаны."</string>
+    <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Рэжым палёту ўключаны."</string>
+    <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Рэжым палёту выключаецца."</string>
+    <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Рэжым палёту ўключаецца."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Рэжым «Не турбаваць» укл., толькі прыярытэтныя."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Рэжым «Не турбаваць» укл., поўная цішыня."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Рэжым «Не турбаваць» укл., толькі будзільнікі."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Рэжым «Не турбаваць» выкл."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Рэжым «Не турбаваць» выкл."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Рэжым «Не турбаваць» укл."</string>
+    <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth выключаны."</string>
+    <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth уключаны."</string>
+    <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth падлучаецца."</string>
+    <string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"Bluetooth падлучаны."</string>
+    <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"Bluetooth выключаны."</string>
+    <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"Bluetooth уключаны."</string>
+    <string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"Адпраўка даных аб месцазнаходжанні выключана."</string>
+    <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"Адпраўка даных аб месцазнаходжанні ўключана."</string>
+    <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"Адпраўка даных аб месцазнаходжанні выключаецца."</string>
+    <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"Адпраўка даных аб месцазнаходжанні ўключаецца."</string>
+    <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Наладжаны будзiльнiк: <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Закрыць панэль."</string>
+    <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Больш часу."</string>
+    <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Менш часу."</string>
+    <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ліхтарык выключаны."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ліхтарык недаступны."</string>
+    <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ліхтарык уключаны."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ліхтарык выключаецца."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ліхтарык уключаецца."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Інверсія колеру адключаецца."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Інверсія колеру ўключаецца."</string>
+    <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мабільны хот-спот выключаецца."</string>
+    <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мабільны хот-спот ўключаецца."</string>
+    <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Трансляцыя экрана спынена."</string>
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Рэжым працы выкл."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Рэжым працы ўкл."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Рэжым працы выключаны."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Рэжым працы ўключаны."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Эканомія трафіку адключана."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Эканомія трафіку ўключана."</string>
+    <string name="accessibility_brightness" msgid="8003681285547803095">"Яркасць дысплэя"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Перадача даных 2G-3G прыпынена"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Перадача даных 4G прыпынена"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мабільная перадача даных прыпынена"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Перадача даных прыпынена"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Быў дасягнуты ліміт перадачы даных, таму прылада прыпыніла перадачу даных на астатнюю частку гэтага цыкла.\n\nУзнаўленне перадачы можа прывесці да спагнання платы вашым аператарам."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Узнавіць"</string>
+    <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string>
+    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string>
+    <string name="gps_notification_searching_text" msgid="8574247005642736060">"Пошук GPS"</string>
+    <string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string>
+    <string name="accessibility_location_active" msgid="2427290146138169014">"Ёсць актыўныя запыты пра месцазнаходжанне"</string>
+    <string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Налады апавяшчэнняў"</string>
+    <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Налады <xliff:g id="APP_NAME">%s</xliff:g>"</string>
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран паварочваецца аўтаматычна."</string>
+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Экран заблакiраваны ў альбомнай арыентацыі."</string>
+    <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Экран заблакiраваны ў партрэтнай арыентацыі."</string>
+    <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"Цяпер экран будзе паварочвацца аўтаматычна."</string>
+    <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Цяпер экран заблакіраваны ў альбомнай арыентацыі."</string>
+    <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Цяпер экран заблакiраваны ў кніжнай арыентацыі."</string>
+    <string name="dessert_case" msgid="1295161776223959221">"Вітрына з дэсертамі"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Мроi"</string>
+    <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не турбаваць"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Толькі прыярытэтныя"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Толькі будзільнікі"</string>
+    <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Поўная цішыня"</string>
+    <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
+    <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (прылады: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
+    <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth выключаны"</string>
+    <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Няма даступных спалучаных прылад"</string>
+    <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Яркасць"</string>
+    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Аўтапаварот"</string>
+    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Паварот заблакіраваны"</string>
+    <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Кніжная арыентацыя"</string>
+    <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Альбомная арыентацыя"</string>
+    <string name="quick_settings_ime_label" msgid="7073463064369468429">"Метад уводу"</string>
+    <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>
+    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Толькі экстраныя выклікі"</string>
+    <string name="quick_settings_settings_label" msgid="5326556592578065401">"Налады"</string>
+    <string name="quick_settings_time_label" msgid="4635969182239736408">"Час"</string>
+    <string name="quick_settings_user_label" msgid="5238995632130897840">"Я"</string>
+    <string name="quick_settings_user_title" msgid="4467690427642392403">"Карыстальнік"</string>
+    <string name="quick_settings_user_new_user" msgid="9030521362023479778">"Новы карыстальнік"</string>
+    <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
+    <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Няма падключэння"</string>
+    <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма сеткi"</string>
+    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi адключаны"</string>
+    <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Няма даступнай сеткі Wi-Fi"</string>
+    <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляцыя"</string>
+    <string name="quick_settings_casting" msgid="6601710681033353316">"Ідзе перадача"</string>
+    <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Прылада без назвы"</string>
+    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Гатова для трансляцыі"</string>
+    <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Няма даступных прылад"</string>
+    <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркасць"</string>
+    <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
+    <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Інвертаваць колеры"</string>
+    <string name="quick_settings_color_space_label" msgid="853443689745584770">"Рэжым карэкцыі колеру"</string>
+    <string name="quick_settings_more_settings" msgid="326112621462813682">"Дадатковыя налады"</string>
+    <string name="quick_settings_done" msgid="3402999958839153376">"Гатова"</string>
+    <string name="quick_settings_connected" msgid="1722253542984847487">"Падлучана"</string>
+    <string name="quick_settings_connecting" msgid="47623027419264404">"Падлучэнне..."</string>
+    <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Мадэм"</string>
+    <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Хот-спот"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Апавяшчэнні"</string>
+    <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Ліхтарык"</string>
+    <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Мабільная перадача даных"</string>
+    <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Выкарыстанне трафіку"</string>
+    <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Засталося трафіку"</string>
+    <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Ліміт перавышаны"</string>
+    <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Выкарыстана <xliff:g id="DATA_USED">%s</xliff:g>"</string>
+    <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ліміт <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
+    <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Папярэджанне: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рэжым працы"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Няма апошніх элементаў"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы ачысцілі усё"</string>
+    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Звесткі аб праграме"</string>
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"замацаванне экрана"</string>
+    <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
+    <string name="recents_launch_error_message" msgid="2969287838120550506">"Не атрымалася запусціць <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> адключана ў бяспечным рэжыме."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ачысціць усё"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Гэта праграма не падтрымлівае функцыю некалькіх вокнаў"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Праграма не падтрымлівае функцыю некалькіх вокнаў"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Падзяліць гарызантальна"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Падзяліць вертыкальна"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Падзяліць іншым чынам"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зараджаны"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарадка"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> да поўнай зарадкі"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не зараджаецца"</string>
+    <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"За сеткай\nможа назіраць"</string>
+    <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
+    <string name="description_direction_up" msgid="7169032478259485180">"Правядзіце пальцам уверх, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Правядзіце пальцам улева, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="zen_priority_introduction" msgid="3070506961866919502">"Вас не будуць турбаваць гукі і вібрацыя, за выключэннем будзільнікаў, мерапрыемстваў, падзей і выбраных вамі абанентаў."</string>
+    <string name="zen_priority_customize_button" msgid="7948043278226955063">"Дапасаваць"</string>
+    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Гэта заблакіруе ЎСЕ гукі і вібрацыі, у тым ліку ад будзільнікаў, музыкі, відэа і гульняў. Вы па-ранейшаму зможаце тэлефанаваць."</string>
+    <string name="zen_silence_introduction" msgid="3137882381093271568">"Гэта заблакіруе ЎСЕ гукі і вібрацыі, у тым ліку ад будзільнікаў, музыкі, відэа і гульняў."</string>
+    <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Менш тэрміновыя апавяшчэнні ніжэй"</string>
+    <string name="notification_tap_again" msgid="8524949573675922138">"Краніце яшчэ раз, каб адкрыць"</string>
+    <string name="keyguard_unlock" msgid="8043466894212841998">"Правядзіце пальцам уверх, каб разблакіраваць"</string>
+    <string name="phone_hint" msgid="4872890986869209950">"Тэлефон: правядзіце пальцам ад значка"</string>
+    <string name="voice_hint" msgid="8939888732119726665">"Галасавая дапамога: правядзіце пальцам ад значка"</string>
+    <string name="camera_hint" msgid="7939688436797157483">"Камера: правядзіце пальцам ад значка"</string>
+    <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Поўная цішыня. Гэта таксама адключыць гук чытання з экрана."</string>
+    <string name="interruption_level_none" msgid="6000083681244492992">"Поўная цішыня"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Толькі прыярытэтныя"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Толькі будзільнікі"</string>
+    <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Поўная\nцішыня"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Толькі\nпрыярытэтныя"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Толькі\nбудзільнікі"</string>
+    <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарадка (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> да поўнай зарадкі)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Зараджаецца хутка (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> да канца)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Зараджаецца павольна (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> да канца)"</string>
+    <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Перайсці да іншага карыстальніка"</string>
+    <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Перайсці да іншага карыстальніка, бягучы карыстальнік <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+    <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Бягучы карыстальнік <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+    <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"Паказаць профіль"</string>
+    <string name="user_add_user" msgid="5110251524486079492">"Дадаць карыстальніка"</string>
+    <string name="user_new_user_name" msgid="426540612051178753">"Новы карыстальнік"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Госць"</string>
+    <string name="guest_new_guest" msgid="600537543078847803">"Дадаць госця"</string>
+    <string name="guest_exit_guest" msgid="7187359342030096885">"Выдаліць госця"</string>
+    <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"Выдаліць госця?"</string>
+    <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
+    <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Выдаліць"</string>
+    <string name="guest_wipe_session_title" msgid="6419439912885956132">"З вяртаннем, госць!"</string>
+    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Хочаце працягнуць сеанс?"</string>
+    <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Пачаць зноў"</string>
+    <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Так, працягнуць"</string>
+    <string name="guest_notification_title" msgid="1585278533840603063">"Гасцявы карыстальнік"</string>
+    <string name="guest_notification_text" msgid="335747957734796689">"Каб выдаліць праграмы і даныя, выдаліце гасцявога карыстальніка"</string>
+    <string name="guest_notification_remove_action" msgid="8820670703892101990">"ВЫДАЛІЦЬ ГОСЦЯ"</string>
+    <string name="user_logout_notification_title" msgid="1453960926437240727">"Выканаць выхад карыстальніка"</string>
+    <string name="user_logout_notification_text" msgid="3350262809611876284">"Выканаць выхад бягучага карыстальніка"</string>
+    <string name="user_logout_notification_action" msgid="1195428991423425062">"ВЫКАНАЦЬ ВЫХАД КАРЫСТАЛЬНІКА"</string>
+    <string name="user_add_user_title" msgid="4553596395824132638">"Дадаць новага карыстальніка?"</string>
+    <string name="user_add_user_message_short" msgid="2161624834066214559">"Калі вы дадаяце новага карыстальніка, ён павінен наладзіць свой раздзел.\n\nЛюбы карыстальнік можа абнаўляць праграмы для ўсіх астатніх карыстальнікаў."</string>
+    <string name="user_remove_user_title" msgid="4681256956076895559">"Выдаліць карыстальніка?"</string>
+    <string name="user_remove_user_message" msgid="1453218013959498039">"Усе праграмы і даныя гэтага карыстальніка будуць выдалены."</string>
+    <string name="user_remove_user_remove" msgid="7479275741742178297">"Выдаліць"</string>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Рэжым эканоміі зараду ўключаны"</string>
+    <string name="battery_saver_notification_text" msgid="820318788126672692">"Памяншае прадукцыйнасць і фонавую перадачу даных"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Адключыць рэжым эканоміі зараду"</string>
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> атрымае доступ да ўсяго, што адлюстроўваецца на вашым экране."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Не паказваць зноў"</string>
+    <string name="clear_all_notifications_text" msgid="814192889771462828">"Ачысціць усё"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"Пачаць зараз"</string>
+    <string name="empty_shade_text" msgid="708135716272867002">"Апавяшчэнняў няма"</string>
+    <string name="device_owned_footer" msgid="3802752663326030053">"За прыладай могуць назіраць"</string>
+    <string name="profile_owned_footer" msgid="8021888108553696069">"За профілем могуць назіраць"</string>
+    <string name="vpn_footer" msgid="2388611096129106812">"За сеткай могуць назіраць"</string>
+    <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Маніторынг прылад"</string>
+    <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Маніторынг профіляў"</string>
+    <string name="monitoring_title" msgid="169206259253048106">"Маніторынг сеткі"</string>
+    <string name="disable_vpn" msgid="4435534311510272506">"Адключыць VPN"</string>
+    <string name="disconnect_vpn" msgid="1324915059568548655">"Адлучыць VPN"</string>
+    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, карпаратыўным доступам, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне вашай прылады. Для атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
+    <string name="monitoring_description_vpn" msgid="4445150119515393526">"Вы далі праграме дазвол на наладжванне злучэння VPN.\n\nГэта праграма можа сачыць за актыўнасцю вашай прылады і вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, доступам да карпаратыўных рэсурсаў, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне прылады.\n\nВы падлучаны да VPN, які можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, доступам да карпаратыўных рэсурсаў, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне прылады.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара.\n\nВы таксама падключаны да VPN, які можа сачыць за вашай сеткавай актыўнасцю."</string>
+    <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
+    <string name="monitoring_description_app" msgid="6259179342284742878">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
+    <string name="monitoring_description_app_personal" msgid="484599052118316268">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая сачыць за вашай асабістай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
+    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
+    <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nВы таксама падлучаны да праграмы <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай актыўнасцю."</string>
+    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, доступам да карпаратыўных рэсурсаў, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне прылады.\n\nВы падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>,  якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
+    <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Прылада будзе заставацца заблакіраванай, пакуль вы не разблакіруеце яе ўручную"</string>
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Атрымлівайце апавяшчэнні хутчэй"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Праглядайце іх перад разблакіроўкай"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Не, дзякуй"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Наладзіць"</string>
+    <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
+    <string name="volume_zen_end_now" msgid="3179845345429841822">"Завяршыць зараз"</string>
+    <string name="accessibility_volume_expand" msgid="5946812790999244205">"Разгарнуць"</string>
+    <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згарнуць"</string>
+    <string name="screen_pinning_title" msgid="3273740381976175811">"Экран замацаваны"</string>
+    <string name="screen_pinning_description" msgid="3577937698406151604">"Будзе паказвацца, пакуль не адмацуеце. Дакраніцеся і ўтрымлівайце кнопку «Назад», каб адмацаваць."</string>
+    <string name="screen_pinning_positive" msgid="3783985798366751226">"Зразумела"</string>
+    <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, дзякуй"</string>
+    <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Схаваць <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
+    <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Гэта паведамленне з\'явіцца зноў у наступны раз, калі вы ўключыце яго ў наладах."</string>
+    <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Схаваць"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> хоча быць дыялогам гучнасці."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Дазволіць"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Адхiлiць"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> з\'яўляецца дыялогам гучнасці"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Націсніце, каб аднавіць арыгінал."</string>
+    <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Вы выкарыстоўваеце свой працоўны профіль"</string>
+    <string name="system_ui_tuner" msgid="708224127392452018">"Наладка сістэмнага інтэрфейсу карыстальніка"</string>
+    <string name="show_battery_percentage" msgid="5444136600512968798">"Паказваць працэнт зараду акумулятара"</string>
+    <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Паказваць працэнт узроўню акумулятара ўнутры значка панэлі стану, калі ён не зараджаецца"</string>
+    <string name="quick_settings" msgid="10042998191725428">"Хуткія налады"</string>
+    <string name="status_bar" msgid="4877645476959324760">"Панэль стану"</string>
+    <string name="overview" msgid="4018602013895926956">"Агляд"</string>
+    <string name="demo_mode" msgid="2389163018533514619">"Дэманстрацыйны рэжым"</string>
+    <string name="enable_demo_mode" msgid="4844205668718636518">"Уключыць дэманстрацыйны рэжым"</string>
+    <string name="show_demo_mode" msgid="2018336697782464029">"Паказваць дэманстрацыйны рэжым"</string>
+    <string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string>
+    <string name="status_bar_alarm" msgid="8536256753575881818">"Будзільнік"</string>
+    <string name="status_bar_work" msgid="6022553324802866373">"Працоўны профіль"</string>
+    <string name="status_bar_airplane" msgid="7057575501472249002">"Рэжым палёту"</string>
+    <string name="add_tile" msgid="2995389510240786221">"Дадаць плітку"</string>
+    <string name="broadcast_tile" msgid="3894036511763289383">"Плітка трансляцыі"</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>, пакуль папярэдне не выключыце гэты"</string>
+    <string name="zen_alarm_warning" msgid="444533119582244293">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+    <string name="alarm_template" msgid="3980063409350522735">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+    <string name="alarm_template_far" msgid="4242179982586714810">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+    <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"Хуткія налады, <xliff:g id="TITLE">%s</xliff:g>."</string>
+    <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Хот-спот"</string>
+    <string name="accessibility_managed_profile" msgid="6613641363112584120">"Працоўны профіль"</string>
+    <string name="tuner_warning_title" msgid="7094689930793031682">"Цікава для некаторых, але не для ўсіх"</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"Наладка сістэмнага інтэрфейсу карыстальніка дае вам дадатковыя спосабы наладжвання і дапасоўвання карыстальніцкага інтэрфейсу Android. Гэтыя эксперыментальныя функцыі могуць змяніцца, перастаць працаваць або знікнуць у будучых версіях. Карыстайцеся з асцярожнасцю."</string>
+    <string name="tuner_persistent_warning" msgid="8597333795565621795">"Гэтыя эксперыментальныя функцыі могуць змяніцца, перастаць працаваць або знікнуць у будучых версіях. Карыстайцеся з асцярожнасцю."</string>
+    <string name="got_it" msgid="2239653834387972602">"Зразумела"</string>
+    <string name="tuner_toast" msgid="603429811084428439">"Віншуем! Наладка сістэмнага інтэрфейсу карыстальніка была дададзена ў Налады"</string>
+    <string name="remove_from_settings" msgid="8389591916603406378">"Выдаліць з налад"</string>
+    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Выдаліць Наладку сістэмнага інтэрфейсу карыстальніка з Налад і спыніць выкарыстанне ўсіх яе функцый?"</string>
+    <string name="activity_not_found" msgid="348423244327799974">"Праграма не ўсталявана на вашым тэлефоне"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Паказваць секунды гадзінніка"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Паказваць секунды гадзінніка на панэлі стану. Можа паўплываць на рэсурс акумулятара."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Змяніць парадак Хуткіх налад"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Паказваць яркасць у Хуткіх наладах"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Уключ. пераход да рэжыму дзялення экрана правядзеннем уверх"</string>
+    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Уключыць пераход да рэжыму дзялення экрана правядзеннем пальцам уверх ад кнопкі «Агляд»"</string>
+    <string name="experimental" msgid="6198182315536726162">"Эксперыментальныя"</string>
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Уключыць Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Для падлучэння клавіятуры да планшэта трэба спачатку ўключыць Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Уключыць"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Паказваць апавяшчэнні бязгучна"</string>
+    <string name="block" msgid="2734508760962682611">"Блакіраваць усе апавяшчэнні"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Не адключаць гук"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не адключаць гук і не блакіраваць"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Паказаць поўны спіс налад важнасці"</string>
+    <string name="blocked_importance" msgid="5198578988978234161">"Заблакiравана"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Мінімальная важнасць"</string>
+    <string name="low_importance" msgid="4109929986107147930">"Нізкая важнасць"</string>
+    <string name="default_importance" msgid="8192107689995742653">"Звычайная важнасць"</string>
+    <string name="high_importance" msgid="1527066195614050263">"Высокая важнасць"</string>
+    <string name="max_importance" msgid="5089005872719563894">"Пільная важнасць"</string>
+    <string name="notification_importance_blocked" msgid="2397192642657872872">"Ніколі не паказваць гэтыя апавяшчэнні"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Бязгучна паказваць унізе спіса апавяшчэнняў"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Паказваць гэтыя апавяшчэнні бязгучна"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Дазволіць гэтым апавяшчэнням прайграваць гукі"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Хутка паказаць на экране і дазволіць прайграванне гуку"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Паказваць уверсе спіса апавяшчэнняў, хутка паказаць на экране і дазволіць прайграванне гуку"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Дадатковыя налады"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Гатова"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Элементы кантролю апавяшчэнняў <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Колер і выгляд"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Начны рэжым"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Каліброўка дысплэя"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Уключана"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Адключана"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Уключаць аўтаматычна"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Пераключэнне ў начны рэжым у залежнасці ад канкрэтнай мясцовасці і часу сутак"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Калі ўключаны Начны рэжым"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Выкарыстоўваць цёмную тэму для АС Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Рэгуляванне адценняў"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Рэгуляванне яркасці"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Цёмная тэма ўжываецца да асноўных вобласцяў АС Android, да якіх звычайна шжываецца светлая тэма, напрыклад, Налады."</string>
+    <string name="color_apply" msgid="9212602012641034283">"Ужыць"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"Пацвердзіце налады"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"Некаторыя налады колеру могуць зрабіць гэту прыладу непрыдатнай для выкарыстання. Націсніце кнопку «ОК», каб пацвердзіць гэтыя налады колеру, у адваротным выпадку гэтыя налады будуць скінуты праз 10 секунд."</string>
+    <string name="battery_panel_title" msgid="7944156115535366613">"Выкарыстанне зараду"</string>
+    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Эканомія зараду акумулятара недаступная падчас зарадкі"</string>
+    <string name="battery_detail_switch_title" msgid="6285872470260795421">"Эканомія зараду"</string>
+    <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Памяншае прадукцыйнасць і фонавую перадачу даных"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Уверх"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Уніз"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Улева"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Управа"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Цэнтр"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Прабел"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Прайграванне/Паўза"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Спыніць"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Наступны"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Папярэдні"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перамотка назад"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перамотка ўперад"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Лічбавая клавіятура: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Сістэмныя"</string>
+    <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Галоўная"</string>
+    <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Апошнія"</string>
+    <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Апавяшчэнні"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Спалучэнні клавіш для хуткага доступу"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Пераключэнне рэжыму ўводу"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Праграмы"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Памочнік"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браўзер"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Кантакты"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электронная пошта"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Iмгненныя паведамленнi"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Каляндар"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Паказаць з рэгулятарамі гучнасці"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не турбаваць"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Доступ праз кнопкі рэгулявання гучнасці"</string>
+    <string name="volume_up_silent" msgid="7141255269783588286">"Выхад з рэжыму «Не турбав.» пры націску кнопкі павел. гучн."</string>
+    <string name="battery" msgid="7498329822413202973">"Акумулятар"</string>
+    <string name="clock" msgid="7416090374234785905">"Гадзіннік"</string>
+    <string name="headset" msgid="4534219457597457353">"Гарнітура"</string>
+    <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Навушнікі падключаны"</string>
+    <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Гарнітура падлучана"</string>
+    <string name="data_saver" msgid="5037565123367048522">"Эканомія трафіку"</string>
+    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Эканомія трафіку ўключана"</string>
+    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Эканомія трафіку адключана"</string>
+    <string name="switch_bar_on" msgid="1142437840752794229">"Уключана"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Адключана"</string>
+    <string name="nav_bar" msgid="1993221402773877607">"Панэль навігацыі"</string>
+    <string name="start" msgid="6873794757232879664">"Пачатак"</string>
+    <string name="center" msgid="4327473927066010960">"Цэнтр"</string>
+    <string name="end" msgid="125797972524818282">"Завяршыць"</string>
+    <string name="space" msgid="804232271282109749">"Падзяляльнік"</string>
+    <string name="menu_ime" msgid="4943221416525250684">"Пераключальнік Меню/Клавіятура"</string>
+    <string name="select_button" msgid="1597989540662710653">"Выберыце, якую кнопку дадаць"</string>
+    <string name="add_button" msgid="4134946063432258161">"Дадаць кнопку"</string>
+    <string name="save" msgid="2311877285724540644">"Захаваць"</string>
+    <string name="reset" msgid="2448168080964209908">"Скінуць"</string>
+    <string name="no_home_title" msgid="1563808595146071549">"Кнопка гал. экр. не знойдзена"</string>
+    <string name="no_home_message" msgid="5408485011659260911">"Для навігацыі па гэтай прыладзе патрабуецца кнопка галоўнага экрана. Калі ласка, дадайце кнопку галоўнага экрана перад захаваннем."</string>
+    <string name="adjust_button_width" msgid="6138616087197632947">"Адрэгуляваць шырыню кнопкі"</string>
+    <string name="clipboard" msgid="1313879395099896312">"Буфер абмену"</string>
+    <string name="clipboard_description" msgid="3819919243940546364">"З дапамогай кнопкі Буфер абмену можна перацягваць элементы непасрэдна ў буфер абмену. Элементы можна таксама перацягваць непасрэдна з буфера абмену, калі яны там ёсць."</string>
+    <string name="accessibility_key" msgid="5701989859305675896">"Кнопка карыстальніцкай навігацыі"</string>
+    <string name="keycode" msgid="7335281375728356499">"Код клавішы"</string>
+    <string name="keycode_description" msgid="1403795192716828949">"Кнопка Код клавішы дазваляе дадаваць клавішы ў Панэль навігацыі. Пры націску гэтай кнопкі эмулюецца выбраная клавіша. Спачатку трэба выбраць клавішу для кнопкі, а потым відарыс, які будзе паказвацца на кнопцы."</string>
+    <string name="select_keycode" msgid="7413765103381924584">"Выберыце клавішу клавіятуры"</string>
+    <string name="preview" msgid="9077832302472282938">"Папярэдні прагляд"</string>
+    <string name="drag_to_add_tiles" msgid="7058945779098711293">"Перацягніце, каб дадаць пліткі"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перацягніце сюды, каб выдаліць"</string>
+    <string name="qs_edit" msgid="2232596095725105230">"Рэдагаваць"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Час"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Паказваць гадзіны, хвіліны і секунды"</item>
+    <item msgid="1427801730816895300">"Паказваць гадзіны і хвіліны (стандартна)"</item>
+    <item msgid="3830170141562534721">"Не паказваць гэты значок"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Заўсёды паказваць у працэнтах"</item>
+    <item msgid="2139628951880142927">"Паказваць працэнты падчас зарадкі (стандартна)"</item>
+    <item msgid="3327323682209964956">"Не паказваць гэты значок"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Іншае"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Раздзяляльнік падзеленага экрана"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Перамясціць уніз"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перамясціць уверх"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перамясціць улева"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перамясціць управа"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Праграма можа не працаваць у рэжыме некалькіх вокнаў"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Краніце двойчы, каб рэдагаваць."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Краніце двойчы, каб дадаць."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>. Краніце двойчы, каб выбраць."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Перамясціць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Выдаліць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Плітка <xliff:g id="TILE_NAME">%1$s</xliff:g> дададзена ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Плітка <xliff:g id="TILE_NAME">%1$s</xliff:g> выдалена"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> перамешчана ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Рэдактар хуткіх налад."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings_car.xml b/packages/SystemUI/res/values-be-rBY/strings_car.xml
new file mode 100644
index 0000000..e3ef7c6
--- /dev/null
+++ b/packages/SystemUI/res/values-be-rBY/strings_car.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Кіруйце аўтамабілем бяспечна"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Будзьце заўсёды ў курсе дарожных умоў і заўсёды прытрымлівайцеся дзеючага заканадаўства. Указанні могуць быць недакладнымі, няпоўнымі, небяспечнымі, непадыходзячымі, забароненымі ці прадугледжваць уезд на адміністрацыйныя тэрыторыі. Інфармацыя пра кампаніі таксама можа быць недакладнай ці няпоўнай. Даныя не прадстаўляюцца ў рэжыме рэальнага часу, і дакладнасць вызначэння месцазнаходжання не можа быць гарантавана. Не выкарыстоўвайце сваю мабільную прыладу або праграмы, не прызначаныя для Android Auto, падчас кіравання."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings_tv.xml b/packages/SystemUI/res/values-be-rBY/strings_tv.xml
new file mode 100644
index 0000000..6138155
--- /dev/null
+++ b/packages/SystemUI/res/values-be-rBY/strings_tv.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Закрыць PIP"</string>
+    <!-- no translation found for pip_fullscreen (8604643018538487816) -->
+    <skip />
+    <!-- no translation found for pip_play (674145557658227044) -->
+    <skip />
+    <!-- no translation found for pip_pause (8412075640017218862) -->
+    <skip />
+    <string name="pip_hold_home" msgid="340086535668778109">"Утрым. "<b>"HOME"</b>" для кір. PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Націсніце і ўтрымлівайце кнопку HOME для кіравання PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Зразумела"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Адхіліць"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index f407ac1..479087a 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"Не може да се направи екр. снимка поради недостиг на място или забрана от прилож. или организацията ви."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"При запазването на екранната снимка възникна проблем."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Екранната снимка не може да се запази поради ограничено място в хранилището."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Правенето на екранни снимки не е разрешено от приложението или организацията ви."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Опции за пренос на файлове чрез USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Свързване като медиен плейър (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Свързване като камера (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отхвърляне на <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложението <xliff:g id="APP">%s</xliff:g> е отхвърлено."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Всички скорошни приложения са отхвърлени."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> се стартира."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известието е отхвърлено."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повече време."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"По-малко време."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фенерчето е изключено."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Няма достъп до фенерчето."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фенерчето е включено."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фенерчето е изключено."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фенерчето е включено."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Работният режим е включен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Работният режим е изключен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Работният режим е включен."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Функцията „Икономия на данни“ е изключена."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Функцията „Икономия на данни“ е включена."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркост на екрана"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Данните от 2G – 3G са поставени на пауза"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Активни заявки за местоположение"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Изчистване на всички известия."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Настройки за известия"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Настройки за <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранът ще се завърта автоматично."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ограничение от <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Работен режим"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Скорошните ви екрани се показват тук"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Няма скорошни елементи"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Изчистихте всичко"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"фиксиране на екрана"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не можа да стартира."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"История"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Изчистване"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Приложението <xliff:g id="APP">%s</xliff:g> е деактивирано в безопасния режим."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Изчистване на всичко"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Това приложение не поддържа няколко прозореца"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Приложението не поддържа няколко прозореца"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хоризонтално разделяне"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Вертикално разделяне"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Персонализирано разделяне"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Пълна\nтишина"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nс приоритет"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nбудилници"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Всички"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Всички\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Зарежда се бързо (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Зарежда се бавно (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Актив. на жеста за разделен екран с прек. на пръст нагоре"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделяне на екрана с прекарване на пръст нагоре: Активиране"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Активиране на жеста за влизане в режим на разделен екран чрез прокарване на пръст нагоре от бутона за общ преглед"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включване"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Прилагане за известията на тема „<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Прилагане за всички известия от това приложение"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Показване на известията без звуков сигнал"</string>
+    <string name="block" msgid="2734508760962682611">"Блокиране на всички известия"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Без заглушаване на звуковите сигнали"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Без заглушаване на звуковите сигнали или блокиране"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показване на пълните настройки за важността"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Минимална важност"</string>
     <string name="low_importance" msgid="4109929986107147930">"Малка важност"</string>
     <string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
     <string name="high_importance" msgid="1527066195614050263">"Голяма важност"</string>
     <string name="max_importance" msgid="5089005872719563894">"Неотложна важност"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Тези известия не се показват"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Беззвучно показване най-долу в списъка с известия"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Тези известия се показват без звук"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Показване най-горе в списъка с известия и издаване на звуков сигнал"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Показване на екрана и издаване на звуков сигнал"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Показване без звуков сигнал най-долу в списъка с известия"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Показване на тези известия без звуков сигнал"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Разрешаване при тези известия да се издава звуков сигнал"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Показване на екрана и разрешаване на звуков сигнал"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Показване най-горе в списъка с известия, както и на екрана и разрешаване на звуков сигнал"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Нормални цветове"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Нощни цветове"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Персонализирани цветове"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Автоматично"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Неизвестни цветове"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Промяна на цветовете"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показване на плочката за бързи настройки"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Активиране на персонализираното трансформиране"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известията от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Цвят и облик"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Нощен режим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Калибриране на дисплея"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Вкл."</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Изкл."</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматично включване"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Превключване към нощен режим според местоположението и часа от денонощието"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"При включен нощен режим"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Ползв. на тъмната тема за опер. с-ма Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Коригиране на нюансирането"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Коригиране на яркостта"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Тъмната тема се прилага към основните области на операционната система Android, които обикновено се показват със светла тема, като например настройките."</string>
     <string name="color_apply" msgid="9212602012641034283">"Прилагане"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Потвърждаване на настройките"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Някои настройки за цветовете могат да направят това устройство неизползваемо. За да ги потвърдите, кликнете върху „OK“. В противен случай те ще бъдат нулирани след 10 секунди."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Ползв. на батерията"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режимът за запазване на батерията не е налице при зареждане"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим за запазване на батерията"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Намалява ефективността и данните на заден план"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Бутон „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Начало"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Нагоре"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Надолу"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Наляво"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Надясно"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Център"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Интервал"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Пускане/пауза"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Спиране"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Напред"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Назад"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Превъртане назад"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Превъртане напред"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Страница нагоре"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Страница надолу"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Изтриване"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Цифрова клавиатура – <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Системни"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Начало"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Скорошни"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Показване на „Не безпокойте“ в прозореца за силата на звука"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Достъп до всички опции за управление на „Не безпокойте“ в диалоговия прозорец за силата на звука."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Сила на звука и „Не безпокойте“"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Вкл. на „Не безпокойте“ при намаляване на силата на звука"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Известия"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Клавишни комбинации"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Превключване на метода на въвеждане"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Приложения"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помощно приложение"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузър"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Електронна поща"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Незабавни съобщения"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Показване с контролите за силата на звука"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не безпокойте"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Пряк път към бутоните за силата на звука"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Изкл. на „Не безпокойте“ при увеличаване на силата на звука"</string>
     <string name="battery" msgid="7498329822413202973">"Батерия"</string>
     <string name="clock" msgid="7416090374234785905">"Часовник"</string>
     <string name="headset" msgid="4534219457597457353">"Слушалки"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Слушалките (без микрофон) са свързани"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Слушалките са свързани"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Активиране или деактивиране на показването на икони в лентата на състоянието."</string>
     <string name="data_saver" msgid="5037565123367048522">"Икономия на данни"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Функцията „Икономия на данни“ е включена"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Функцията „Икономия на данни“ е изключена"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Вкл."</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Изкл."</string>
     <string name="nav_bar" msgid="1993221402773877607">"Лента за навигация"</string>
     <string name="start" msgid="6873794757232879664">"Начало"</string>
     <string name="center" msgid="4327473927066010960">"Център"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Избиране на клавиш от клавиатурата"</string>
     <string name="preview" msgid="9077832302472282938">"Визуализация"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Преместете с плъзгане, за да добавите плочки"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Преместете тук с плъзгане за премахване"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Редактиране"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Час"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Показване на часовете, минутите и секундите"</item>
+    <item msgid="1427801730816895300">"Показване на часовете и минутите (по подразбиране)"</item>
+    <item msgid="3830170141562534721">"Тази икона да не се показва"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Процентът винаги да се показва"</item>
+    <item msgid="2139628951880142927">"Процентът да се показва при зареждане (по подразбиране)"</item>
+    <item msgid="3327323682209964956">"Тази икона да не се показва"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Друго"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Разделител в режима за разделен екран"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Преместване надолу"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместване нагоре"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместване наляво"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместване надясно"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Приложението може да не работи в режим за няколко прозореца"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>, „<xliff:g id="TILE_NAME">%2$s</xliff:g>“. Докоснете двукратно, за да редактирате."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"„<xliff:g id="TILE_NAME">%1$s</xliff:g>“. Докоснете двукратно, за да добавите."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>. Докоснете двукратно, за да изберете."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Преместване на „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Премахване на „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Добавихте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ към позиция <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Премахнахте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Преместихте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ на позиция <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор за бързи настройки."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
new file mode 100644
index 0000000..38e251b
--- /dev/null
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Затваряне на PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Цял екран"</string>
+    <string name="pip_play" msgid="674145557658227044">"Пускане"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Пауза"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Контр. на PIP: Задр. "<b>"HOME"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"За контролиране на PIP натиснете и задръжте бутона „HOME“"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Разбрах"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Отхвърляне"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 988e02e..ccbcb6e 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"সঞ্চয়স্থান সীমিত হওয়ার ফলে স্ক্রীনশট নেওয়া যাবে না, অথবা এটি অ্যাপ্লিকেশানটি অথবা আপনার প্রতিষ্ঠানের দ্বারা অনুমোদিত নয়৷"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"স্ক্রীনশট সংরক্ষণের সময়ে সমস্যা হয়েছে৷"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"সঞ্চয়স্থান সীমিত থাকায় স্ক্রীনশটটি সংরক্ষণ করা যাবে না৷"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"অ্যাপ্লিকেশান বা আপনার প্রতিষ্ঠান স্ক্রীনশটগুলি নেওয়া অনুমতি দেয়নি৷"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ফাইল স্থানান্তরের বিকল্পগুলি"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"একটি মিডিয়া প্লেয়ার হিসাবে মাউন্ট করুন (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"একটি ক্যামেরা হিসাবে মাউন্ট করুন (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> খারিজ করুন।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> খারিজ করা হয়েছে৷"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"সমস্ত সাম্প্রতিক অ্যাপ্লিকেশন খারিজ করা হয়েছে।"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> তারাঙ্কিত করা হচ্ছে।"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"বেশি সময়।"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"কম সময়।"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ফ্ল্যাশলাইট বন্ধ আছে।"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ফ্ল্যাশলাইট অনুপলব্ধ৷"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ফ্ল্যাশলাইট চালু আছে।"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ফ্ল্যাশলাইট বন্ধ হয়েছে।"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ফ্ল্যাশলাইট চালু হয়েছে।"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"কাজের মোড চালু আছে"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"কাজের মোড বন্ধ আছে।"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"কাজের মোড চালু আছে"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ডেটা সেভার বন্ধ আছে।"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ডেটা সেভার চালু আছে।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"প্রদর্শনের উজ্জ্বলতা"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ডেটা বিরতি দেওয়া হয়েছে"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS এর দ্বারা সেট করা অবস্থান"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"অবস্থান অনুরোধ সক্রিয় রয়েছে"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"সমস্ত বিজ্ঞপ্তি সাফ করুন৷"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>টি"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"বিজ্ঞপ্তির সেটিংস"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> সেটিংস"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"স্ক্রীন স্বয়ংক্রিয়ভাবে ঘুরে যাবে৷"</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"সীমা <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"কাজের মোড"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"আপনার সাম্প্রতিক স্ক্রীনগুলো এখানে দেখা যাবে"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"কোনো সাম্প্রতিক আইটেম নেই"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"আপনি সবকিছু সাফ করেছেন"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"অ্যাপ্লিকেশানের তথ্য"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"স্ক্রীন পিন করা"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"অনুসন্ধান"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> শুরু করা যায়নি৷"</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"নিরাপদ মোডে <xliff:g id="APP">%s</xliff:g> অক্ষম করা হয়েছে৷"</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ইতিহাস"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"সাফ করুন"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"সবকিছু সাফ করুন"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"এই অ্যাপ্লিকেশানটি মাল্টি-উইন্ডো সমর্থন করে না"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"অ্যাপ্লিকেশানগুলি মাল্টি-উইন্ডো সমর্থন করে না"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উল্লম্ব স্প্লিট"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"কাস্টম স্প্লিট করুন"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"একদম\nনিরব"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"শুধুমাত্র\nঅগ্রাধিকার"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"শুধুমাত্র\nঅ্যালার্মগুলি"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"সমস্ত"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"সমস্ত\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"দ্রুত চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ধীরে ধীরে চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
     <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"অ্যাকসেলেটর উপরের দিকে সোয়াইপ করে বিভক্ত-স্ক্রীন সক্ষম করুন"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"উপরের দিকে সোয়াইপ করে বিভক্ত-স্ক্রীনে প্রবেশ করার অঙ্গভঙ্গি সক্ষম করুন"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\'এক নজরে\' বোতাম থেকে উপরের দিকে সোয়াইপ করে, বিভক্ত-স্ক্রীনে প্রবেশ করতে অঙ্গভঙ্গি সক্ষম করুন"</string>
     <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth চালু করবেন?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"আপনার ট্যাবলেটের সাথে আপনার কীবোর্ড সংযুক্ত করতে, আপনাকে প্রথমে Bluetooth চালু করতে হবে।"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"চালু করুন"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> বিজ্ঞপ্তিগুলিতে প্রয়োগ করুন"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"এই অ্যাপ্লিকেশনের থেকে সব বিজ্ঞপ্তিতে প্রয়োগ করুন"</string>
+    <string name="show_silently" msgid="6841966539811264192">"নীরবভাবে বিজ্ঞপ্তিগুলি দেখায়"</string>
+    <string name="block" msgid="2734508760962682611">"সমস্ত বিজ্ঞপ্তি অবরুদ্ধ করুন"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"নীরব করবেন না"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"নীরব বা অবরুদ্ধ করবেন না"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"সম্পূর্ণ গুরুত্বপূর্ণ সেটিংস দেখায়"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"অবরুদ্ধ"</string>
+    <string name="min_importance" msgid="1901894910809414782">"ন্যূনতম গুরুত্ব"</string>
     <string name="low_importance" msgid="4109929986107147930">"কম গুরুত্ব"</string>
     <string name="default_importance" msgid="8192107689995742653">"সাধারণ গুরুত্ব"</string>
     <string name="high_importance" msgid="1527066195614050263">"বেশি গুরুত্ব"</string>
     <string name="max_importance" msgid="5089005872719563894">"জরুরি গুরুত্ব"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"এই বিজ্ঞপ্তিগুলি কখনোই দেখানো হবে না"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে দেখানো হয়"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"নিঃশব্দে এই বিজ্ঞপ্তিগুলি দেখানো হয়"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং শব্দ করে"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"স্ক্রীনের উপরে দেখানো হয় এবং শব্দ করে"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে দেখানো হয়"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"নিঃশব্দে এই বিজ্ঞপ্তিগুলি দেখানো হয়"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"এই বিজ্ঞপ্তিগুলিকে শব্দ করার মঞ্জুরি দেয়"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"স্ক্রীনের উপরে প্রদর্শিত এবং শব্দ করার মঞ্জুরি দেয়"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং স্ক্রীনের উপরে প্রদর্শিত এবং শব্দ করার মঞ্জুরি দেয়"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
     <string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"স্বাভাবিক রঙ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"রাতের রঙ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"কাস্টম রঙ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"স্বয়ংক্রিয়ভাবে"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"অজানা রঙ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"রঙ সংশোধন"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"দ্রুত সেটিংস টাইল দেখান"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"কাস্টম রূপান্তর সক্ষম করুন"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"রঙ এবং চেহারা"</string>
+    <string name="night_mode" msgid="3540405868248625488">"রাতের মোড"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"প্রদর্শন ক্যালিব্রেট করুন"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"চালু আছে"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"বন্ধ আছে"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"স্বয়ংক্রিয়ভাবে চালু করুন"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"অবস্থান এবং সময়ের হিসাবে উপযুক্ত রাতের মোডে পাল্টান"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"যখন রাতের মোড চালু থাকবে"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS এর জন্য গাঢ় থিম ব্যবহার করুন"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"টিন্ট সমন্বয় করুন"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"উজ্জ্বলতা সমন্বয় করুন"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Android OS এর মূল অংশগুলিতে গাঢ় থিম প্রয়োগ করা হয়েছে যেটা সাধারণত একটি হালকা থিমে প্রদর্শিত হয়, যেমন সেটিংস৷"</string>
     <string name="color_apply" msgid="9212602012641034283">"প্রয়োগ করুন"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"সেটিংস নিশ্চিত করুন"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"কিছু রঙের সেটিংস এই ডিভাইসকে ব্যবহারের অযোগ্য করে দিতে পারে৷ এই রঙের সেটিংস নিশ্চিত করতে ওকে এ ক্লিক করুন, অন্যথায় ১০ সেকেন্ড পরে এই সেটিংস পুনরায় সেট হবে৷"</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"চার্জ করার সময় ব্যাটারি সেভার উপলব্ধ নয়"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ব্যাটারি সেভার"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> বোতাম"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"হোম"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"ফিরুন"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"উপরে"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"নীচে"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"বাম"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ডান"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"কেন্দ্র"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"ট্যাব"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"স্পেস"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"এন্টার"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"ব্যাকস্পেস"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"প্লে/বিরতি"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"থামান"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"পরবর্তী"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"পূর্ববর্তী"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"পেছনের দিকে যান"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"দ্রুত ফরওয়ার্ড"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"পেজ আপ"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"পেজ ডাউন"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"মুছুন"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"হোম"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"শেষ"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"ঢোকান"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"সংখ্যা লক"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"সংখ্যাপ্যাড <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"সিস্টেম"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"হোম"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"সাম্প্রতিকগুলি"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"পিছনে"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"ভলিউমে \'বিরক্ত করবেন না\' দেখাবেন না"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ভলিউম ডায়লগে \"বিরক্ত করবেন না\" এর পূর্ণ নিয়ন্ত্রণের মঞ্জুরি দিন৷"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ভলিউম এবং \'বিরক্ত করবেন না\'"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ভলিউম কমানোর মাধ্যেমে \'বিরক্ত করবেন না\' চালু করুন"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"বিজ্ঞপ্তিগুলি"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"কীবোর্ড শর্টকাট"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ইনপুট পদ্ধতি পাল্টান"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"অ্যাপ্লিকেশানগুলি"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"সহযোগিতা"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ব্রাউজার"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"পরিচিতি"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ইমেল"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"সংগীত"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ক্যালেন্ডার"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"ভলিউম নিয়ন্ত্রণ সহ দেখান"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"বিরক্ত করবেন না"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ভলিউম বোতামের শর্টকাট"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ভলিউম বাড়ানোর মাধ্যেমে \'বিরক্ত করবেন না\' থেকে প্রস্থান করুন"</string>
     <string name="battery" msgid="7498329822413202973">"ব্যাটারি"</string>
     <string name="clock" msgid="7416090374234785905">"ঘড়ি"</string>
     <string name="headset" msgid="4534219457597457353">"হেডসেট"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"হেডফোনগুলি সংযুক্ত হয়েছে"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"হেডসেট সংযুক্ত হয়েছে"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"স্থিতি দন্ডে দেখানোর জন্য আইকনগুলিকে সক্ষম বা অক্ষম করুন৷"</string>
     <string name="data_saver" msgid="5037565123367048522">"ডেটা সেভার"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ডেটা সেভার চালু আছে"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ডেটা সেভার বন্ধ আছে"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"চালু আছে"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"বন্ধ আছে"</string>
     <string name="nav_bar" msgid="1993221402773877607">"নেভিগেশন দন্ড"</string>
     <string name="start" msgid="6873794757232879664">"শুরু করুন"</string>
     <string name="center" msgid="4327473927066010960">"কেন্দ্র"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"কীবোর্ডের বোতাম নির্বাচন করুন"</string>
     <string name="preview" msgid="9077832302472282938">"পূর্বরূপ দেখুন"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"টাইলগুলি যোগ করার জন্য টেনে আনুন"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"সরানোর জন্য এখানে টেনে আনুন"</string>
     <string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা করুন"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"সময়"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"ঘণ্টা, মিনিট, এবং সেকেন্ড দেখান"</item>
+    <item msgid="1427801730816895300">"ঘণ্টা এবং মিনিট দেখান (ডিফল্ট)"</item>
+    <item msgid="3830170141562534721">"এই আইকনটি দেখাবেন না"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"সর্বদা শতাংশ দেখান"</item>
+    <item msgid="2139628951880142927">"চার্জ করার সময় শতাংশ দেখান (ডিফল্ট)"</item>
+    <item msgid="3327323682209964956">"এই আইকনটি দেখাবেন না"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"অন্যান্য"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"বিভক্ত-স্ক্রীন বিভাজক"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"নীচে সরান"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"উপরে সরান"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বাঁয়ে সরান"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ডানে সরান"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"একাধিক-উইন্ডো দিয়ে অ্যাপ কাজ নাও করতে পারে"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> অবস্থান, <xliff:g id="TILE_NAME">%2$s</xliff:g>৷ সম্পাদনা করতে দুবার আলতো চাপুন৷"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>৷ যোগ করতে দুবার আলতো চাপুন৷"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> অবস্থান৷ নির্বাচন করতে দুবার আলতো চাপুন৷"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> সরান"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> সরান"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> অবস্থানে <xliff:g id="TILE_NAME">%1$s</xliff:g> যোগ করা হয়েছে"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> মোছা হয়েছে"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> এ সরানো হয়েছে"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"দ্রুত সেটিংস সম্পাদক৷"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings_tv.xml b/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
new file mode 100644
index 0000000..6fa2d5b
--- /dev/null
+++ b/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP বন্ধ করুন"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"পূর্ণ স্ক্রীন"</string>
+    <string name="pip_play" msgid="674145557658227044">"চালান"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"বিরাম দিন"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP নিয়ন্ত্রণ করতে "<b>"হোম"</b>" কী ধরে রাখুন"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP নিয়ন্ত্রণ করতে HOME বোতামটিকে টিপুন ও ধরে থাকুন"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"বুঝেছি"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"খারিজ করুন"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA-land/strings.xml b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
new file mode 100644
index 0000000..bdc652a
--- /dev/null
+++ b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u pejzažnom prikazu."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 2be74a0..c5398a2 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -74,7 +74,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran snimljen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite za prikaz snimka ekrana."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Došlo je do greške prilikom snimanja ekrana."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Ekran se ne može snimiti zbog manjka prostora, ili to ne dopuštaju aplikacija ili vaša organizacija."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Došlo je do problema prilikom spašavanja snimka ekrana."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snimak ekrana se ne može sačuvati zbog manjka prostora za pohranu."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikacija ili vaša organizacija ne dopuštaju pravljenje snimaka ekrana."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa fajlova"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Reproduciranje medijskih sadržaja (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Priključiti kao kameru (PTP)"</string>
@@ -167,6 +169,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbaci aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> uklonjena."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korištene aplikacije su odbačene."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećem aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavještenje je uklonjeno."</string>
@@ -207,6 +211,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svjetiljka isključena."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svjetiljka nije dostupna."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svjetiljka uključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svjetiljka je isključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svjetiljka je uključena."</string>
@@ -219,6 +224,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Poslovni režim uključen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Poslovni režim je isključen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Poslovni režim je uključen."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Ušteda podataka je isključena."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Ušteda podataka je uključena."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Osvjetljenje ekrana"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G prijenos podataka je pauzirano"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string>
@@ -232,6 +239,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija utvrđena GPS signalom"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktiviran je zahtjev za lokaciju"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Uklanjanje svih obavještenja."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Postavke obavještenja"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Postavke aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
@@ -297,15 +305,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ograničenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Poslovni režim"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Ovdje se pojavljuju nedavno korišteni ekrani"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Sve ste obrisali"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kačenje ekrana"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraga"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historija"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Obriši"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> je onemogućena u sigurnom načinu rada."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ova aplikacija ne podržava rad sa više prozora"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava rad sa više prozora"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podjela po vertikali"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođena podjela"</string>
@@ -335,8 +344,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Potpuna\ntišina"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetni prekidi"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Svi"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Svi \n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (do kraja preostalo <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do pune baterije)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do pune baterije)"</string>
@@ -449,61 +456,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaži sekunde na statusnoj traci. Može skratiti trajanje baterije."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi \"Brze postavke\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvjetljenje u opciji \"Brze postavke\""</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Uključi akcelerator za dijeljenje ekrana prevlačenjem nagore"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogućiti potez za podjelu ekrana prevlačenjem prema gore"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Uključite pokrete prstima da biste ušli u podijeljeni ekran tako što ćete od dugmeta Pregled prevući prstom prema gore"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želiti li uključiti Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da povežete tastaturu sa tabletom, prvo morate uključiti Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Primijeni na obavještenja koja se odnose na temu <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Primijeni na sva obavještenja ove aplikacije"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Nečujno prikaži obavijesti"</string>
+    <string name="block" msgid="2734508760962682611">"Blokiraj sva obavještenja"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nemoj utišati"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nemoj utišati ili blokirati"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži kompletne postavke za određivanje značaja"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimalni značaj"</string>
     <string name="low_importance" msgid="4109929986107147930">"Mali značaj"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normalan značaj"</string>
     <string name="high_importance" msgid="1527066195614050263">"Visok značaj"</string>
     <string name="max_importance" msgid="5089005872719563894">"Hitan značaj"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikada ne prikazuj ova obavještenja"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Nečujno pokaži na dnu spiska obavještenja"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Nečujno prikaži ova obavještenja"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Pokaži na vrhu spiska obavještanja uz zvuk"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Kratki prikaz na ekranu uz zvuk"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Nečujno prikaži na dnu spiska obavještenja"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Nečujno prikaži ova obavještenja"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite zvuk na ovim obavještenjima"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Kratko prikaži na ekranu i dozvoli zvuk"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Prikaži na vrhu liste obavještenja, kratko prikaži na ekranu i dozvoli zvuk"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Standardne boje"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Boje za noćni rad"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatski"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Nepoznate boje"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Izmjena boja"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaži polje \"Brze postavke\""</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Uključi prilagođenu transformaciju"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole <xliff:g id="APP_NAME">%1$s</xliff:g> obavještenja"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Noćni način rada"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibracija zaslona"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Uključeno"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Isključeno"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Automatsko uključivanje"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Prebaciti u Noćni način rada u skladu sa lokacijom i dobom dana"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kada je Noćni režim rada uključen"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Koristiti tamne teme za OS Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Prilagođavanje nijanse"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Podešavanje osvijetljenosti"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tamna tema se primjenjuje na ključna područja OS Android koja se obično prikazuju u svijetloj temi, kao što je meni Postavke."</string>
     <string name="color_apply" msgid="9212602012641034283">"Prihvati"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Potvrdi postavke"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"S nekim postavkama boja ovaj uređaj može biti neupotrebljiv. Kliknite U redu da biste potvrdili ove postavke boja ili sačekajte 10 sekundi da se postavke vrate na početnu vrijednost."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Upotreba baterije"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije je isključena prilikom punjenja"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ograničava rad i prijenos podataka u pozadini"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Tipka za početak"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Nazad"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gore"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dolje"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Lijevo"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Desno"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Sredina"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulator"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Razmaknica"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Tipka za novi red"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tipka za brisanje"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Pokreni/pauziraj"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zaustavi"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Sljedeće"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prethodno"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Premotaj"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Ubrzaj"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Tipka Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Tipka Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Tipka za brisanje"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Tipka za početak"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Kraj"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Tipka za umetanje"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Tipka Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numerička tastatura <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početak"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni ekrani"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Prikaži režim Ne ometaj u dijalogu za jačinu zvuka."</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Dopusti punu kontrolu režima Ne ometaj u dijalogu za jačinu zvuka."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Jačina zvuka i režim Ne ometaj"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Aktiviraj režim Ne ometaj kada se zvuk utiša"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obavještenja"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Skracenice tastature"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promijeni način unosa"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoć"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Preglednik"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikazati sa kontrolama jačine zvuka"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne ometaj"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za Jačinu zvuka"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Deaktiviraj režim Ne ometaj kada se zvuk pojača"</string>
     <string name="battery" msgid="7498329822413202973">"Baterija"</string>
     <string name="clock" msgid="7416090374234785905">"Sat"</string>
     <string name="headset" msgid="4534219457597457353">"Slušalice s mikrofonom"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalice su priključene"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Slušalice s mikrofonom su priključene"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Uključite ili isključite prikaz ikona na statusnoj traci."</string>
     <string name="data_saver" msgid="5037565123367048522">"Ušteda podataka"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ušteda podataka je uključena"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ušteda podataka je isključena"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Uključeno"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Isključi"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigaciona traka"</string>
     <string name="start" msgid="6873794757232879664">"Početak"</string>
     <string name="center" msgid="4327473927066010960">"Sredina"</string>
@@ -525,5 +578,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Odaberite dugme na tastaturi"</string>
     <string name="preview" msgid="9077832302472282938">"Pregledaj"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali polja"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovdje za uklanjanje"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Vrijeme"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Prikaži sate, minute i sekunde"</item>
+    <item msgid="1427801730816895300">"Prikaži sate i minute (zadano)"</item>
+    <item msgid="3830170141562534721">"Ne prikazuj ovu ikonu"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Uvijek prikaži postotak"</item>
+    <item msgid="2139628951880142927">"Pokaži postotak u toku punjenja (zadano)"</item>
+    <item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Ostalo"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Razdjelnik ekrana"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomjeri dolje"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomjeri gore"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomjeri lijevo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomjeri desno"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće raditi s višestrukim prozorom"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite za uređivanje."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> Dvaput dodirnite za dodavanje."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>. Dvaput dodirnite za odabir."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pomjeri <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je dodan na poziciju <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjen"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je premješten na poziciju <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivanje brzih postavki"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings_tv.xml b/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
new file mode 100644
index 0000000..65c0982
--- /dev/null
+++ b/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Zatvori PIP"</string>
+    <!-- no translation found for pip_fullscreen (8604643018538487816) -->
+    <skip />
+    <!-- no translation found for pip_play (674145557658227044) -->
+    <skip />
+    <!-- no translation found for pip_pause (8412075640017218862) -->
+    <skip />
+    <string name="pip_hold_home" msgid="340086535668778109">"Za kontr. PIP držite "<b>"HOME"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Za kontrolu PIP, pritisnite i držite dugme POČETAK"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Jasno mi je"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 55ab02a..b7fffb7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"S\'ha fet una captura de pantalla."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca per veure la captura de pantalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"No s\'ha pogut fer una captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"No es pot fer la captura perquè no hi ha prou espai, o l\'organització o l\'aplicació no ho permet."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"S\'ha trobat un problema en desar la captura de pantalla."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"La captura de pantalla no es pot desar perquè no hi ha prou espai d\'emmagatzematge."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"L\'aplicació o l\'organització no permeten fer captures de pantalla."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcions transf. fitxers USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Munta com a reproductor multimèdia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Munta com a càmera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignora <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"S\'ha omès <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"S\'han descartat totes les aplicacions recents."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"S\'està iniciant <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificació omesa."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Més temps"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menys temps"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Llanterna desactivada"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La llanterna no està disponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Llanterna activada"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Llanterna desactivada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Llanterna activada."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"El mode de feina està activat."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"S\'ha desactivat el mode de feina."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"S\'ha activat el mode de feina."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"S\'ha desactivat l\'Economitzador de dades."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"S\'ha activat l\'Economitzador de dades."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillantor de la pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Les dades 2G-3G estan aturades"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Sol·licituds d\'ubicació actives"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Esborra totes les notificacions."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configuració de les notificacions"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configuració de l\'aplicació <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girarà automàticament."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode de feina"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Aquí es mostren les teves pantalles recents."</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"No hi ha cap element recent"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ho has esborrat tot"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixació de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No s\'ha pogut iniciar <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Esborra"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"En mode segur, l\'aplicació <xliff:g id="APP">%s</xliff:g> està desactivada."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Esborra-ho tot"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aquesta aplicació no admet el mode multifinestra"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'aplicació no admet el mode multifinestra"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisió vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisió personalitzada"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silenci\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Totes"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Totes\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganitza Configuració ràpida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a Configuració ràpida"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activa la pantalla dividida en lliscar amunt"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activa el gest per dividir la pantalla en lliscar cap amunt"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa el gest per entrar al mode de pantalla dividida en lliscar cap amunt des del botó Visió general"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activa"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplica a les notificacions sobre <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplica a totes les notificacions d\'aquesta aplicació"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostra les notificacions de manera silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloqueja totes les notificacions"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"No silenciïs"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciïs ni bloquegis"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostra la configuració completa per a la importància"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloquejades"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importància mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importància baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importància normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importància alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importància urgent"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostris mai aquestes notificacions"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostra de manera silenciosa a la part inferior de la llista de notificacions"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostra aquestes notificacions de manera silenciosa"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostra a la part superior de la llista de notificacions i emet un so"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mostra a la pantalla i emet un so"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Les notificacions es mostren de manera silenciosa al capdavall de la llista"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostra aquestes notificacions de manera silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permet que aquestes notificacions emetin sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Les notificacions apareixen a la pantalla i poden emetre sons"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Les notificacions es mostren al capdamunt de la llista, apareixen a la pantalla i poden emetre sons"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fet"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Colors normals"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Colors nocturns"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Colors personalitzats"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automàtica"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Colors desconeguts"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificació del color"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostra el mosaic de Configuració ràpida"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Activa la transformació personalitzada"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controls de notificació de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Color i aparença"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Mode nocturn"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibra la pantalla"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Activat"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Desactivat"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Activa automàticament"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Canvia al mode nocturn d\'acord amb la ubicació i l\'hora del dia"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Quan el mode nocturn estigui activat"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Fes servir un tema fosc per a Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajusta el color"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ajusta la brillantor"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"El tema fosc s\'aplica a les àrees clau d\'Android OS que normalment es mostren amb un tema clar, com ara Configuració."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplica"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirma la configuració"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algunes opcions de configuració de color poden deixar el dispositiu inservible. Fes clic a D\'acord per confirmar la configuració de color; en cas contrari, la configuració es restablirà al cap de 10 segons."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Ús de la bateria"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Estalvi de bateria"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Redueix el rendiment i les dades en segon pla"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botó <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Inici"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Enrere"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Amunt"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Avall"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Esquerra"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Dreta"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Pestanya"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Espai"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Retorn"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retrocés"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reprodueix/Pausa"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Atura"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Següent"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rebobina"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avança ràpidament"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pàg"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pàg"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Tecla de supressió"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inici"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Final"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Tecla d\'inserció"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueig de teclat numèric"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclat numèric <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inici"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recents"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Enrere"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostra el mode No molesteu al volum"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permet el control complet del mode No molesteu al quadre de diàleg de volum."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volum i mode No molesteu"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Activa el mode No molesteu abaixant el volum"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificacions"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tecles de drecera"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Canvia el mètode d\'introducció"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicacions"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistència"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactes"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correu electrònic"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendari"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra amb els controls de volum"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molesteu"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Drecera per als botons de volum"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Desactiva el mode No molesteu apujant el volum"</string>
     <string name="battery" msgid="7498329822413202973">"Bateria"</string>
     <string name="clock" msgid="7416090374234785905">"Rellotge"</string>
     <string name="headset" msgid="4534219457597457353">"Auriculars"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculars connectats"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculars connectats"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activa o desactiva les icones a la barra d\'estat."</string>
     <string name="data_saver" msgid="5037565123367048522">"Economitzador de dades"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"L\'extensió Economitzador de dades està activada"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"L\'extensió Economitzador de dades està desactivada"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Activat"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desactivat"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegació"</string>
     <string name="start" msgid="6873794757232879664">"Inici"</string>
     <string name="center" msgid="4327473927066010960">"Centre"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Selecciona un botó de teclat"</string>
     <string name="preview" msgid="9077832302472282938">"Previsualització"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrossega per afegir camps"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrossega\'ls aquí per suprimir-los"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Edita"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostra les hores, els minuts i els segons"</item>
+    <item msgid="1427801730816895300">"Mostra les hores i els minuts (opció predeterminada)"</item>
+    <item msgid="3830170141562534721">"No mostris aquesta icona"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Mostra sempre el percentatge"</item>
+    <item msgid="2139628951880142927">"Mostra el percentatge quan es carregui (opció predeterminada)"</item>
+    <item msgid="3327323682209964956">"No mostris aquesta icona"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Altres"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalles"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mou avall"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mou amunt"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mou a l\'esquerra"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mou a la dreta"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"És possible que l\'aplicació no funcioni amb el Mode multifinestra"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posició <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Fes doble toc per editar-la."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Fes doble toc per afegir-ho."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posició <xliff:g id="POSITION">%1$d</xliff:g>. Fes doble toc per seleccionar-la."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mou <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Suprimeix <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha afegit a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha suprimit"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha mogut a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de la configuració ràpida."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
new file mode 100644
index 0000000..8876664
--- /dev/null
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Tanca PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reprodueix"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Posa en pausa"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Prem "<b>"INICI"</b>" per controlar PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Mantén premut el botó INICI per controlar PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"D\'acord"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignora"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index a1423cb..b707ece 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -75,7 +75,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky Snímek obrazovky pořízen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímek obrazovky zobrazíte dotykem."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Snímek obrazovky se nepodařilo zachytit."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Snímek obrazovky nelze pořídit kvůli nedostatku místa, nebo to aplikace či vaše organizace zakazuje."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Při ukládání snímku obrazovky došlo k problému."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímek obrazovky nelze pořídit kvůli nedostatku místa v úložišti."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikace nebo organizace zakazuje pořizování snímků obrazovky."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti přenosu souborů pomocí rozhraní USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Připojit jako přehrávač médií (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Připojit jako fotoaparát (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zavřít aplikaci <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikace <xliff:g id="APP">%s</xliff:g> byla odebrána."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všechny naposledy použité aplikace byly odstraněny."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spouštění aplikace <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Oznámení je zavřeno."</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Delší doba"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší doba"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svítilna je vypnutá."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svítilna není k dispozici."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svítilna je zapnutá."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svítilna je vypnutá."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svítilna je zapnutá."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Pracovní režim zapnutý"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Pracovní režim je vypnutý."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Pracovní režim je zapnutý."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Spořič dat byl vypnut."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Spořič dat byl zapnut."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeje"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G a 3G jsou pozastavena"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavena pomocí systému GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktivní žádosti o polohu"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazat všechna oznámení."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"a ještě <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Nastavení oznámení"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Nastavení aplikace <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka se automaticky otočí."</string>
@@ -298,15 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornění při <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovní režim"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Zde budou zobrazeny vaše poslední obrazovky"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Žádné nedávné položky"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vše je vymazáno"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"připnutí obrazovky"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikaci <xliff:g id="APP">%s</xliff:g> nelze spustit."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historie"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vymazat"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikace <xliff:g id="APP">%s</xliff:g> je v nouzovém režimu zakázána."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vymazat vše"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Tato aplikace režim v několika oknech nepodporuje"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikace režim v několika oknech nepodporuje"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikální rozdělení"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Vlastní rozdělení"</string>
@@ -336,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Úplné\nticho"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Pouze\nprioritní"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Pouze\nbudíky"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Vše"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Všechna\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Rychlé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Pomalé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -450,61 +457,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivovat rozdělenou obrazovku přejetím prstem"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovat rozdělenou obrazovku přejetím prstem nahoru"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovat rozdělenou obrazovku přejetím prstem nahoru od tlačítka Přehled."</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnout"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Použít u oznámení z aplikace <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Použít u všech oznámení z této aplikace"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Zobrazovat oznámení tiše"</string>
+    <string name="block" msgid="2734508760962682611">"Blokovat všechna oznámení"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Bez ztlumení"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Bez ztlumení a blokování"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Zobrazit všechna nastavení důležitosti"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokováno"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimální důležitost"</string>
     <string name="low_importance" msgid="4109929986107147930">"Nízká důležitost"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normální důležitost"</string>
     <string name="high_importance" msgid="1527066195614050263">"Vysoká důležitost"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgentní důležitost"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Tato oznámení nikdy nezobrazovat"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Tato oznámení zobrazovat bez zvukového upozornění"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Tato oznámení zobrazovat na začátku seznamu a upozornit na ně zvukem"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tato oznámení zobrazovat bez zvukového upozornění"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Povolit těmto oznámením vydávat zvuky"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Tato oznámení zobrazovat na začátku seznamu, zobrazit přímo na obrazovce a upozornit na ně zvukem"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normální barvy"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Noční barvy"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastní barvy"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automaticky"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznámé barvy"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Změna barev"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Zobrazit dlaždici Rychlé nastavení"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Umožnit převod na vlastní barvy"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Nastavení oznámení aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Barva a vzhled"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Noční režim"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibrovat displej"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Zapnuto"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Vypnuto"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Zapnout automaticky"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Přejít do nočního režimu automaticky na základě místa a denní doby"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Když je noční režim zapnutý"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Použít v systému Android tmavý motiv"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Upravit tónování"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Upravit jas"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavních oblastech systému Android, které jsou běžně zobrazovány ve světlém motivu (například Nastavení), se použije tmavý motiv."</string>
     <string name="color_apply" msgid="9212602012641034283">"Použít"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Ověření nastavení"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Některá nastavení barev mohou způsobit, že zařízení nebude použitelné. Kliknutím na OK toto nastavení barev potvrdíte, v opačném případě se nastavení po 10 sekundách resetuje."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Využití baterie"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Spořič baterie při nabíjení není k dispozici."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Spořič baterie"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omezuje výkon a data na pozadí"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tlačítko <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Zpět"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Nahoru"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dolů"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vlevo"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Vpravo"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Střed"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulátor"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Mezerník"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Přehrát/Pozastavit"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zastavit"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Další"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Předchozí"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Přetočit zpět"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Přetočit vpřed"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> na numerické klávesnici"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Systém"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Plocha"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Poslední"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zpět"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Zobrazovat panel Nerušit v dialogu Hlasitost"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Umožňuje povolit úplné ovládání režimu Nerušit v dialogu Hlasitost."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hlasitost a režim Nerušit"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Při snížení hlasitosti přejít do režimu Nerušit"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Oznámení"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klávesové zkratky"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Přepnout metodu zadávání"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikace"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistence"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prohlížeč"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendář"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazit včetně ovládacích prvků hlasitosti"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušit"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Zkratka tlačítek hlasitosti"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Při zvýšení hlasitosti ukončit režim Nerušit"</string>
     <string name="battery" msgid="7498329822413202973">"Baterie"</string>
     <string name="clock" msgid="7416090374234785905">"Hodiny"</string>
     <string name="headset" msgid="4534219457597457353">"Náhlavní souprava"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Sluchátka připojena"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Náhlavní souprava připojena"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Umožňuje aktivovat nebo deaktivovat zobrazení ikon na stavovém řádku."</string>
     <string name="data_saver" msgid="5037565123367048522">"Spořič dat"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Spořič dat je zapnutý"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Spořič dat je vypnutý"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Zapnuto"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Vypnuto"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigační panel"</string>
     <string name="start" msgid="6873794757232879664">"Začátek"</string>
     <string name="center" msgid="4327473927066010960">"Střed"</string>
@@ -526,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Vyberte klávesu na klávesnici"</string>
     <string name="preview" msgid="9077832302472282938">"Náhled"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Dlaždice přidáte přetažením"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Přetažením sem tituly odstraníte"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Upravit"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Čas"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Zobrazovat hodiny, minuty a sekundy"</item>
+    <item msgid="1427801730816895300">"Zobrazovat hodiny a minuty (výchozí nastavení)"</item>
+    <item msgid="3830170141562534721">"Tuto ikonu nezobrazovat"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Vždy zobrazovat procento"</item>
+    <item msgid="2139628951880142927">"Zobrazovat procento při nabíjení (výchozí nastavení)"</item>
+    <item msgid="3327323682209964956">"Tuto ikonu nezobrazovat"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Jiné"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Čára rozdělující obrazovku"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Přesunout dolů"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Přesunout nahoru"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Přesunout vlevo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Přesunout vpravo"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikace nemusí v režimu několika oken fungovat."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvojitým klepnutím ji upravíte."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dlaždici přidáte dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>. Dvojitým klepnutím ji vyberete."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Přesunout dlaždici <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstranit dlaždici <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla přidána na pozici <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla odstraněna"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla přesunuta na pozici <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor rychlého nastavení"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
new file mode 100644
index 0000000..3ee822a
--- /dev/null
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Ukončit PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Celá obrazovka"</string>
+    <string name="pip_play" msgid="674145557658227044">"Přehrát"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pozastavit"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Funkci PIP lze ovládat podržením tlačítka "<b>"PLOCHA"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Funkci PIP lze ovládat podržením tlačítka PLOCHA"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Rozumím"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Zavřít"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index b509dfa..7a25141 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skærmbilledet er gemt."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Tryk for at se dit skærmbillede."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Skærmbilledet kunne ikke tages."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Skærmbilledet kan ikke tages pga. begrænset lagerplads, eller det tillades ikke af appen eller din organisation."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Der opstod et problem ved lagringen af skærmbilledet."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Skærmbilledet kan ikke gemmes pga. begrænset lagerplads."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Appen eller din organisation tillader ikke, at du tager skærmbilleder."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Muligheder for USB-filoverførsel"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Isæt som en medieafspiller (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Isæt som et kamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Afvis <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> er annulleret."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle de seneste applikationer er lukket."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> startes."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mere tid."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelygten er slået fra."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lommelygten er ikke tilgængelig."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelygten er slået til."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelygten er slået fra."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelygten er slået til."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbejdstilstand er slået til."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbejdstilstand er slået fra."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbejdstilstand er slået til."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Datasparefunktionen er slået fra."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Datasparefunktionen er slået til."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skærmens lysstyrke"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data er sat på pause"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle underretninger."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> mere"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Underretningsindstillinger"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Indstillinger for <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Grænse: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbejdstilstand"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Dine seneste skærme vises her"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Ingen nye elementer"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har ryddet alt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"bliv i app"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er deaktiveret i sikker tilstand."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historik"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Ryd"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ryd alle"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Denne app understøtter ikke flere vinduer"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen understøtter ikke flere vinduer"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nstilhed"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Oplader (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hurtig opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langsom opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivér bevægelsen stryg opad for at dele skærmen"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivér bevægelsen Stryg opad for at dele skærmen"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivér bevægelse for at dele skærmen ved at stryge opad fra knappen Oversigt"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Anvend for underretninger vedrørende <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Anvend for alle underretninger fra denne app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Vis underretninger lydløst"</string>
+    <string name="block" msgid="2734508760962682611">"Bloker alle underretninger"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Skal ikke sættes på lydløs"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Skal ikke sættes på lydløs eller blokeres"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vis alle indstillinger for vigtighed"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokeret"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Min vigtighed"</string>
     <string name="low_importance" msgid="4109929986107147930">"Lille vigtighed"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normal vigtighed"</string>
     <string name="high_importance" msgid="1527066195614050263">"Stor vigtighed"</string>
     <string name="max_importance" msgid="5089005872719563894">"Presserende vigtighed"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Vis aldrig disse underretninger"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Vis lydløst nederst på listen over underretninger"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse underretninger lydløst"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på listen over underretninger, og giv lyd"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Vis på skærmen, og giv lyd"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Vis lydløst nederst på listen over underretninger"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Vis disse underretninger lydløst"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Giv disse underretninger tilladelse til at give lyd"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Vis på skærmen, og tillad lyd"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Vis øverst på listen over underretninger, vis på skærmen, og tillad lyd"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Almindelige farver"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nattefarver"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Tilpassede farver"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisk"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Ukendte farver"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Farveændring"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Vis feltet Hurtige indstillinger"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Aktivér tilpasset farveændring"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Farve og udseende"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nattilstand"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibrer skærmen"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Til"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Fra"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Slå automatisk til"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Skift til natfunktion alt efter stedet og tidspunktet"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Når natfunktion er slået til"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Brug mørkt tema til Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Juster farvetonen"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Juster lysstyrken"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Det mørke tema anvendes på centrale områder i Android OS, der normalt vises med lyst tema, f.eks. Indstillinger."</string>
     <string name="color_apply" msgid="9212602012641034283">"Anvend"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Bekræft indstillingerne"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Nogle farveindstillinger kan medføre, at du ikke kan bruge enheden. Klik på OK for at bekræfte disse farveindstillinger. Ellers nulstilles disse indstillinger efter ti sekunder."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparefunktion"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reducerer ydeevne og baggrundsdata"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>-knap"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Tilbage"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Op"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ned"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Venstre"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Højre"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Midtertast"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulatortast"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Mellemrumstast"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tilbagetast"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Afspil/pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Næste"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Forrige"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spol tilbage"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Spol frem"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numerisk tastatur <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Start"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Seneste"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbage"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Vis Forstyr ikke i Lydstyrke"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Tillad fuld kontrol over Forstyr ikke i dialogboksen Lydstyrke."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Lydstyrke og Forstyr ikke"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Aktivér Forstyr ikke med Lydstyrke ned"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Underretninger"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastaturgenveje"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Skift indtastningsmetode"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applikationer"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktpersoner"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med lydstyrkeregulering"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Forstyr ikke"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Genvej til lydstyrkeknapper"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Afslut Forstyr ikke med Lydstyrke op"</string>
     <string name="battery" msgid="7498329822413202973">"Batteri"</string>
     <string name="clock" msgid="7416090374234785905">"Ur"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Hovedtelefoner er tilsluttet"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset er forbundet"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Slå visning af ikoner i statusbjælken til eller fra."</string>
     <string name="data_saver" msgid="5037565123367048522">"Datasparefunktion"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datasparefunktionen er slået til"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datasparefunktionen er slået fra"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Til"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Fra"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigationslinje"</string>
     <string name="start" msgid="6873794757232879664">"Start"</string>
     <string name="center" msgid="4327473927066010960">"I midten"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Vælg tastaturknap"</string>
     <string name="preview" msgid="9077832302472282938">"Eksempelvisning"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Træk for at tilføje felter"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Træk herhen for at fjerne"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Rediger"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Tid"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Vis timer, minutter og sekunder"</item>
+    <item msgid="1427801730816895300">"Vis timer og minutter (standard)"</item>
+    <item msgid="3830170141562534721">"Vis ikke dette ikon"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Vis altid procent"</item>
+    <item msgid="2139628951880142927">"Vis procent ved opladning (standard)"</item>
+    <item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Andet"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til delt skærm"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flyt ned"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flyt op"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flyt til venstre"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flyt til højre"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerer muligvis ikke i Multivindue"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tryk to gange for at redigere."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Tryk to gange for at tilføje."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Tryk to gange for at vælge."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flyt <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjern <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> føjes til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> fjernes"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> blev flyttet til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsværktøj for Hurtige indstillinger."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
new file mode 100644
index 0000000..45bba75
--- /dev/null
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Luk PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Fuld skærm"</string>
+    <string name="pip_play" msgid="674145557658227044">"Afspil"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pause"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Hold "<b>"HOME"</b>" nede for at styre PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Tryk på HOME-knappen, og hold den nede for at styre PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Afvis"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 541f03e..e10eb64 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot aufgenommen"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Zum Ansehen berühren"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot konnte nicht aufgenommen werden."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Screenshot nicht möglich. Entweder zu wenig Speicher oder die App/dein Unternehmen lässt dies nicht zu."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Beim Speichern des Screenshots ist ein Problem aufgetreten."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Speichern des Screenshots aufgrund von zu wenig Speicher nicht möglich."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Die App oder Ihr Unternehmen lässt das Erstellen von Screenshots nicht zu."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-Dateiübertragungsoptionen"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Als Medienplayer (MTP) bereitstellen"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Als Kamera (PTP) bereitstellen"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> beenden"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> entfernt"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle kürzlich verwendeten Apps wurden entfernt."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> wird gestartet."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Benachrichtigung geschlossen"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mehr Zeit"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Weniger Zeit"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taschenlampe deaktiviert"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taschenlampe nicht verfügbar."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taschenlampe aktiviert"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Die Taschenlampe ist deaktiviert."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Die Taschenlampe ist aktiviert."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbeitsmodus an."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbeitsmodus deaktiviert."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbeitsmodus aktiviert."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Datenkomprimierung ist deaktiviert."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Datenkomprimierung ist aktiviert."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helligkeit des Displays"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-/3G-Daten pausiert"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
@@ -231,6 +238,7 @@
     <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>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Benachrichtigungseinstellungen"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Einstellungen von <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Bildschirm wird automatisch gedreht."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> Datenlimit"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Warnung für <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeitsmodus"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Hier siehst du deine zuletzt geöffneten Apps."</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Keine kürzlich verwendeten Elemente"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du hast alles gelöscht"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Bildschirmfixierung"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Verlauf"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Löschen"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ist im abgesicherten Modus deaktiviert."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alle löschen"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Diese App unterstützt den Mehrfenstermodus nicht"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App unterstützt Mehrfenstermodus nicht"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Geteilte Schaltfläche – vertikal"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Geteilte Schaltfläche – benutzerdefiniert"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Laut-\nlos"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Nur\nwichtige"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Nur\nWecker"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Wird schnell aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wird langsam aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Teilen des Bildschirms durch Wischen nach oben aktivieren"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Teilen des Bildschirms durch Wischen nach oben aktivieren"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiviert die Bewegung zum Teilen des Bildschirms, bei der von der Schaltfläche \"Übersicht\" nach oben gewischt wird"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivieren"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Für Benachrichtigungen über <xliff:g id="TOPIC_NAME">%1$s</xliff:g> anwenden"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Auf alle Benachrichtigungen dieser App anwenden"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Benachrichtigungen ohne Ton anzeigen"</string>
+    <string name="block" msgid="2734508760962682611">"Alle Benachrichtigungen blockieren"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nicht stummschalten"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nicht stummschalten oder blockieren"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vollständige Wichtigkeitseinstellungen anzeigen"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blockiert"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimum-Wichtigkeit"</string>
     <string name="low_importance" msgid="4109929986107147930">"Geringe Wichtigkeit"</string>
     <string name="default_importance" msgid="8192107689995742653">"Reguläre Wichtigkeit"</string>
     <string name="high_importance" msgid="1527066195614050263">"Hohe Wichtigkeit"</string>
     <string name="max_importance" msgid="5089005872719563894">"Sehr hohe Wichtigkeit"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Diese Benachrichtigungen niemals anzeigen"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Ohne Ton am Ende der Benachrichtigungsliste anzeigen"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Diese Benachrichtigungen ohne Ton anzeigen"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mit Ton ganz oben in der Benachrichtigungsliste anzeigen"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mit Ton auf dem Display einblenden"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Ohne Ton am Ende der Benachrichtigungsliste anzeigen"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Diese Benachrichtigungen ohne Ton anzeigen"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Für diese Benachrichtigungen Ton zulassen"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Auf dem Display einblenden und Ton zulassen"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Ganz oben in der Benachrichtigungsliste anzeigen, auf dem Display einblenden und Ton zulassen"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Standardfarben"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nachtfarben"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Benutzerdefinierte Farben"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisch"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Unbekannte Farben"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Farben ändern"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Kachel \"Schnelleinstellungen\" anzeigen"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Benutzerdefinierte Anpassung aktivieren"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-Benachrichtigungseinstellungen"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Farbe und Darstellung"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nachtmodus"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Bildschirm kalibrieren"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"An"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Aus"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Automatisch aktivieren"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Abhängig von Standort und Tageszeit in den Nachtmodus wechseln"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Bei aktiviertem Nachtmodus"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Dunkles Design unter Android OS verwenden"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Farbton anpassen"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Helligkeit anpassen"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Das dunkle Design wird unter Android OS in allen Hauptbereichen übernommen, die normalerweise hell dargestellt werden, wie beispielsweise Einstellungen."</string>
     <string name="color_apply" msgid="9212602012641034283">"Übernehmen"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Einstellungen bestätigen"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Einige Farbeinstellungen können dazu führen, dass das Gerät nicht mehr genutzt werden kann. Klicke auf \"OK\", um diese Farbeinstellungen zu bestätigen. Anderenfalls werden diese Einstellungen in 10 Sekunden zurückgesetzt."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Akkunutzung"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Der Energiesparmodus ist beim Aufladen nicht verfügbar."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Energiesparmodus"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduzierung der Leistung und Hintergrunddaten"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Taste <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Pos1"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Zurück"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Nach oben"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Nach unten"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Nach links"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Nach rechts"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Zentrieren"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulatortaste"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Leertaste"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Eingabetaste"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Rücktaste"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Wiedergabe/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stopp"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Weiter"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Zurück"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Zurückspulen"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Vorspulen"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Nach oben"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Nach unten"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Entf"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Pos1"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Ende"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Einfg"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Ziffernblock <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startseite"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Letzte"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zurück"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"\"Bitte nicht stören\" bei der Lautstärkeregelung anzeigen"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Volle Kontrolle von \"Bitte nicht stören\" im kleinen Fenster zur Lautstärkeregelung erlauben."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Lautstärke und \"Bitte nicht stören\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"\"Bitte nicht stören\" bei \"Leiser\" aktivieren"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Benachrichtigungen"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastenkombinationen"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Eingabemethode wechseln"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apps"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistent"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakte"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-Mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Einschließlich Lautstärkeregler anzeigen"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bitte nicht stören"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Tastenkombination für Lautstärketasten"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"\"Bitte nicht stören\" bei \"Lauter\" deaktivieren"</string>
     <string name="battery" msgid="7498329822413202973">"Akku"</string>
     <string name="clock" msgid="7416090374234785905">"Uhr"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Mit Kopfhörer verbunden"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Mit Headset verbunden"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Symbole in der Statusleiste ein- bzw. ausblenden"</string>
     <string name="data_saver" msgid="5037565123367048522">"Datenkomprimierung"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datenkomprimierung aktiviert"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datenkomprimierung deaktiviert"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"An"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Aus"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigationsleiste"</string>
     <string name="start" msgid="6873794757232879664">"Beim Start"</string>
     <string name="center" msgid="4327473927066010960">"Mitte"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Taste auswählen"</string>
     <string name="preview" msgid="9077832302472282938">"Vorschau"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Zum Hinzufügen von Kacheln ziehen"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Zum Entfernen hierher ziehen"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Bearbeiten"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Uhrzeit"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Stunden, Minuten und Sekunden anzeigen"</item>
+    <item msgid="1427801730816895300">"Stunden und Minuten anzeigen (Standardeinstellung)"</item>
+    <item msgid="3830170141562534721">"Dieses Symbol nicht anzeigen"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Prozentwert immer anzeigen"</item>
+    <item msgid="2139628951880142927">"Prozentwert beim Laden anzeigen (Standardeinstellung)"</item>
+    <item msgid="3327323682209964956">"Dieses Symbol nicht anzeigen"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Sonstiges"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Bildschirmteiler"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Nach unten verschieben"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Nach oben verschieben"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Nach links verschieben"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Nach rechts verschieben"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"App funktioniert im Mehrfenstermodus möglicherweise nicht"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Zum Bearbeiten doppeltippen."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Zum Hinzufügen doppeltippen."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Zum Auswählen doppeltippen."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verschieben"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> entfernen"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ist auf Position <xliff:g id="POSITION">%2$d</xliff:g> hinzugefügt worden"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> wurde entfernt"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> an Position <xliff:g id="POSITION">%2$d</xliff:g> verschoben"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor für Schnelleinstellungen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
new file mode 100644
index 0000000..3d9c233
--- /dev/null
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP schließen"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Vollbild"</string>
+    <string name="pip_play" msgid="674145557658227044">"Wiedergeben"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausieren"</string>
+    <string name="pip_hold_home" msgid="340086535668778109"><b>"STARTBILDSCHIRMTASTE"</b>" drücken, um PIP zu steuern"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Halte die Taste für die Startseite gedrückt, um das Bild-in-Bild zu steuern"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Beenden"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index ca354dc..5ec3133 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"Αδύνατη λήψη στιγμ. οθόνης λόγω περιορισμένου αποθ.χώρου ή αποκλεισμού από εφαρμογή ή οργανισμό."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Παρουσιάστηκε πρόβλημα κατά την αποθήκευση του στιγμιότυπου οθόνης."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Δεν είναι δυνατή η αποθήκευση του στιγμιότυπου οθόνης λόγω περιορισμένου χώρου αποθήκευσης."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Η λήψη στιγμιοτύπων οθόνης δεν επιτρέπεται από την εφαρμογή ή από τον οργανισμό σας."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Επιλογές μεταφοράς αρχείων μέσω USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Προσάρτηση ως μονάδας αναπαραγωγής μέσων (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Προσάρτηση ως κάμερας (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Παράβλεψη <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Απορρίφθηκαν <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Έγινε παράβλεψη όλων των πρόσφατων εφαρμογών."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Έναρξη <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Η ειδοποίηση έχει απορριφθεί."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Περισσότερη ώρα."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Λιγότερη ώρα."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ανενεργός φακός."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ο φακός δεν είναι διαθέσιμος."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ενεργός φακός."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ο φακός απενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ο φακός ενεργοποιήθηκε."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Η λειτουργία εργασίας είναι ενεργή."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Η λειτουργία εργασίας απενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Η λειτουργία εργασίας ενεργοποιήθηκε."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Η Εξοικονόμηση δεδομένων είναι ανενεργή."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Η Εξοικονόμηση δεδομένων είναι ενεργή."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Φωτεινότητα οθόνης"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Τα δεδομένα 2G-3G τέθηκαν σε παύση"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Τα αιτήματα τοποθεσίας έχουν ενεργοποιηθεί"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Εκκαθάριση όλων των ειδοποιήσεων."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ρυθμίσεις ειδοποιήσεων"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Ρυθμίσεις <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Θα γίνεται αυτόματη περιστροφή της οθόνης."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Όριο <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Προειδοποίηση για <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Λειτουργία εργασίας"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Οι πρόσφατες οθόνες σας εμφανίζονται εδώ"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει εκκαθάριση όλων των στοιχείων"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"καρφίτσωμα οθόνης"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Δεν ήταν δυνατή η εκκίνηση της εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Ιστορικό"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Εκκαθάριση"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> έχει απενεργοποιηθεί στην ασφαλή λειτουργία."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Διαγραφή όλων"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Η εφαρμογή αυτή δεν υποστηρίζει τη λειτουργία πολλαπλών παραθύρων"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Η εφαρμογή δεν υποστηρίζει τη λειτουργία πολλαπλών παραθύρων"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Οριζόντιος διαχωρισμός"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Κάθετος διαχωρισμός"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Προσαρμοσμένος διαχωρισμός"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Πλήρης\nσίγαση"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Μόνο\nπροτεραιότητας"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Μόνο\nειδοποιήσεις"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Όλα"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Όλες\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Γρήγορη φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Αργή φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ενεργοποίηση επιτάχυνσης ολίσθησης επάνω για διαχωρισμό οθόνης"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ενεργοποίηση κίνησης ολίσθησης επάνω για διαχωρισμό οθόνης"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ενεργοποίηση κίνησης για μετάβαση σε διαχωρισμό οθόνης μέσω ολίσθησης επάνω από το κουμπί \"Επισκόπηση\""</string>
     <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ενεργοποίηση"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Να εφαρμοστεί στις ειδοποιήσεις <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Να εφαρμοστεί σε όλες τις ειδοποιήσεις από αυτήν την εφαρμογή"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Εμφάνιση ειδοποιήσεων χωρίς ήχο"</string>
+    <string name="block" msgid="2734508760962682611">"Αποκλεισμός όλων των ειδοποιήσεων"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Χωρίς σίγαση"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Χωρίς σίγαση ή αποκλεισμό"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Εμφάνιση όλων των ρυθμίσεων βαρύτητας"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Αποκλεισμένες"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Ελάχιστη βαρύτητα"</string>
     <string name="low_importance" msgid="4109929986107147930">"Μικρής βαρύτητας"</string>
     <string name="default_importance" msgid="8192107689995742653">"Κανονικής βαρύτητας"</string>
     <string name="high_importance" msgid="1527066195614050263">"Μεγάλης βαρύτητας"</string>
     <string name="max_importance" msgid="5089005872719563894">"Επείγουσες"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Να εμφανίζονται στο κάτω τμήμα της λίστας ειδοποιήσεων χωρίς τίτλο"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων με ήχο"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Να προβάλλονται στην οθόνη και να συνοδεύονται από κάποιον ήχο"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Να εμφανίζονται στο κάτω μέρος της λίστας ειδοποιήσεων χωρίς ήχο"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Να επιτρέπονται οι ήχοι από αυτές τις ειδοποιήσεις"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Να προβάλλονται στην οθόνη και να επιτρέπεται ο ήχος"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων, να προβάλλονται στην οθόνη και να επιτρέπεται ο ήχος"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
     <string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Κανονικά χρώματα"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Νυχτερινά χρώματα"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Προσαρμοσμένα χρώματα"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Αυτόματο"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Άγνωστα χρώματα"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Τροποποίηση χρωμάτων"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Εμφάνιση πλακιδίου Γρήγορων ρυθμίσεων"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Ενεργοποίηση προσαρμοσμένου μετασχηματισμού"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Στοιχεία ελέγχου κοινοποίησης <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Χρώμα και εμφάνιση"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Νυχτερινή λειτουργία"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Βαθμονόμηση οθόνης"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Ενεργή"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Ανενεργή"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Αυτόματη ενεργοποίηση"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Αλλαγή σε νυχτερινή λειτουργία όπως απαιτείται βάσει τοποθεσίας και ώρας της ημέρας"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Όταν είναι ενεργή η νυχτερινή λειτουργία"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Χρήση σκοτεινού θέματος για Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ρύθμιση απόχρωσης"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ρύθμιση φωτεινότητας"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Το σκούρο θέμα εφαρμόζεται σε βασικές περιοχές του λειτουργικού συστήματος Android οι οποίες συνήθως εμφανίζονται με φωτεινό θέμα, όπως οι Ρυθμίσεις."</string>
     <string name="color_apply" msgid="9212602012641034283">"Εφαρμογή"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Επιβεβαίωση ρυθμίσεων"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Ορισμένες ρυθμίσεις χρωμάτων μπορεί να μην επιτρέπουν τη χρήση αυτής της συσκευής. Κάντε κλικ στην επιλογή OK για να επιβεβαιώσετε αυτές τις ρυθμίσεις χρωμάτων, διαφορετικά θα γίνει επαναφορά αυτών των ρυθμίσεων μετά από 10 δευτερόλεπτα."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Χρήση της μπαταρίας"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Η εξοικονόμηση μπαταρίας δεν είναι διαθέσιμη κατά τη διάρκεια της φόρτισης"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Εξοικονόμηση μπαταρίας"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Κουμπί <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Πίσω"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Πάνω"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Κάτω"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Αριστερά"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Δεξιά"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Κέντρο"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Πλήκτρο διαστήματος"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Αναπαραγωγή/Παύση"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Διακοπή"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Επόμενο"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Προηγούμενο"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Επαναφορά"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Γρήγορη προώθηση"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Προηγούμενη σελίδα"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Επόμενη σελίδα"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Λήξη"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Αριθμητικό πληκτρολόγιο <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Σύστημα"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Αρχική οθόνη"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Πρόσφατα"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Πίσω"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Εμφάνιση λειτουργίας \"Μην ενοχλείτε\" στην ένταση ήχου"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Να επιτρέπεται ο πλήρης έλεγχος της λειτουργίας \"Μην ενοχλείτε\" στο παράθυρο διαλόγου ελέγχου έντασης."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ένταση ήχου και λειτουργία \"Μην ενοχλείτε\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Ενεργοποίηση λειτουργίας \"Μην ενοχλείτε\" κατά τη μείωση της έντασης ήχου"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ειδοποιήσεις"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Συντομεύσεις πληκτρολογίου"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Εναλλαγή μεθόδου εισαγωγής"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Εφαρμογές"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Υποβοήθηση"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Πρόγραμμα περιήγησης"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Επαφές"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Ηλεκτρονικό ταχυδρομείο"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Άμεσα μηνύματα (ΙΜ)"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Μουσική"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Ημερολόγιο"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Εμφάνιση με στοιχεία ελέγχου έντασης ήχου"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Μην ενοχλείτε"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Συντόμευση κουμπιών έντασης ήχου"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Απενεργοποίηση λειτουργίας \"Μην ενοχλείτε\" κατά την αύξηση της έντασης ήχου"</string>
     <string name="battery" msgid="7498329822413202973">"Μπαταρία"</string>
     <string name="clock" msgid="7416090374234785905">"Ρολόι"</string>
     <string name="headset" msgid="4534219457597457353">"Ακουστικά"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Τα ακουστικά συνδέθηκαν"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Τα ακουστικά συνδέθηκαν"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ενεργοποίηση ή απενεργοποίηση εμφάνιση εικονιδίων στη γραμμή κατάστασης."</string>
     <string name="data_saver" msgid="5037565123367048522">"Εξοικονόμηση δεδομένων"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Η Εξοικονόμηση δεδομένων είναι ενεργοποιημένη"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Η Εξοικονόμηση δεδομένων είναι απενεργοποιημένη"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Ενεργή"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Απενεργοποίηση"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Γραμμή πλοήγησης"</string>
     <string name="start" msgid="6873794757232879664">"Έναρξη"</string>
     <string name="center" msgid="4327473927066010960">"Κέντρο"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Επιλογή κουμπιού πληκτρολογίου"</string>
     <string name="preview" msgid="9077832302472282938">"Προεπισκόπηση"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Σύρετε για να προσθέσετε πλακίδια"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Σύρετε εδώ για κατάργηση"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Επεξεργασία"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Ώρα"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Να εμφανίζονται ώρες, λεπτά και δευτερόλεπτα"</item>
+    <item msgid="1427801730816895300">"Να εμφανίζονται ώρες και λεπτά (προεπιλογή)"</item>
+    <item msgid="3830170141562534721">"Να μην εμφανίζεται αυτό το εικονίδιο"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Να εμφανίζεται πάντα ποσοστό"</item>
+    <item msgid="2139628951880142927">"Να εμφανίζεται ποσοστό κατά τη φόρτιση (προεπιλογή)"</item>
+    <item msgid="3327323682209964956">"Να μην εμφανίζεται αυτό το εικονίδιο"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Άλλο"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Διαχωριστικό οθόνης"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Μετακίνηση προς τα κάτω"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Μετακίνηση προς τα επάνω"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Μετακίνηση αριστερά"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Μετακίνηση δεξιά"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Η εφαρμογή ενδέχεται να μη λειτουργεί με τη λειτουργία πολλαπλών παραθύρων"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Πατήστε δύο φορές για επεξεργασία."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Πατήστε δύο φορές για προσθήκη."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>. Πατήστε δύο φορές για επιλογή."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Μετακίνηση <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Κατάργηση <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> προστέθηκε στη θέση <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> καταργείται"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> μετακινήθηκε στη θέση <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Επεξεργασία γρήγορων ρυθμίσεων."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
new file mode 100644
index 0000000..c54c7be
--- /dev/null
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Κλείσιμο PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Πλήρης οθόνη"</string>
+    <string name="pip_play" msgid="674145557658227044">"Αναπαραγωγή"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Παύση"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Κρατήστε το πλήκτρο "<b>"HOME"</b>" πατημένο για έλεγχο του PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Πιέστε παρατεταμένα το κουμπί HOME, για να ελέγξετε τη λειτουργία PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Κατάλαβα"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Παράβλεψη"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 14f9301..f08894f 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organisation."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problem encountered while saving screenshot."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Can\'t save screenshot due to limited storage space."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Taking screenshots is not allowed by the app or your organisation."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"More time."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Less time."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torch off."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torch unavailable."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torch on."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torch turned off."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torch turned on."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Work mode on."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Work mode turned off."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Work mode turned on."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Data Saver turned off."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Data Saver turned on."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G data is paused"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Clear all notifications."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+<xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Notification settings"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> settings"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Screen will rotate automatically."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nsilence"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"All\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Enable split-screen swipe-up accelerator"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Show notifications silently"</string>
+    <string name="block" msgid="2734508760962682611">"Block all notifications"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Don\'t silence"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Don\'t silence or block"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Show full importance settings"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Min importance"</string>
     <string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
     <string name="high_importance" msgid="1527066195614050263">"High importance"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Silently show at the bottom of the notification list"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Silently show these notifications"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Allow these notifications to make sounds"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Peek on to the screen and allow sound"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Show at the top of the notifications list, peek on to the screen and allow sound"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
     <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> notification controls"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Colour and appearance"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrate display"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"On"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Off"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Turn on automatically"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Switch into Night Mode as appropriate for location and time of day"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"When Night Mode is on"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Use dark theme for Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Adjust tint"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Adjust brightness"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"The dark theme is applied to core areas of Android OS that are normally displayed in a light theme, such as Settings."</string>
     <string name="color_apply" msgid="9212602012641034283">"Apply"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast-Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Show Do Not Disturb in volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Allow full control of Do Not Disturb in the volume dialogue."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume and Do Not Disturb"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Enter Do Not Disturb on volume down"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Exit Do Not Disturb on volume up"</string>
     <string name="battery" msgid="7498329822413202973">"Battery"</string>
     <string name="clock" msgid="7416090374234785905">"Clock"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphones connected"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset connected"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Enable or disable icons from being shown in the status bar."</string>
     <string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver is on"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver is off"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"On"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
     <string name="start" msgid="6873794757232879664">"Start"</string>
     <string name="center" msgid="4327473927066010960">"Centre"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
     <string name="preview" msgid="9077832302472282938">"Preview"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Drag here to remove"</string>
     <string name="qs_edit" msgid="2232596095725105230">"(edit)"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Time"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Show hours, minutes and seconds"</item>
+    <item msgid="1427801730816895300">"Show hours and minutes (default)"</item>
+    <item msgid="3830170141562534721">"Don\'t show this icon"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Always show percentage"</item>
+    <item msgid="2139628951880142927">"Show percentage when charging (default)"</item>
+    <item msgid="3327323682209964956">"Don\'t show this icon"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Other"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Split screen divider"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Move down"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings_tv.xml b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
new file mode 100644
index 0000000..87255ae
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
+    <string name="pip_play" msgid="674145557658227044">"Play"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pause"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Hold "<b>"HOME"</b>" to control PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Press and hold the HOME button to control PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Understood"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Dismiss"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 14f9301..f08894f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organisation."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problem encountered while saving screenshot."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Can\'t save screenshot due to limited storage space."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Taking screenshots is not allowed by the app or your organisation."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"More time."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Less time."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torch off."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torch unavailable."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torch on."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torch turned off."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torch turned on."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Work mode on."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Work mode turned off."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Work mode turned on."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Data Saver turned off."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Data Saver turned on."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G data is paused"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Clear all notifications."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+<xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Notification settings"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> settings"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Screen will rotate automatically."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nsilence"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"All\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Enable split-screen swipe-up accelerator"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Show notifications silently"</string>
+    <string name="block" msgid="2734508760962682611">"Block all notifications"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Don\'t silence"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Don\'t silence or block"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Show full importance settings"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Min importance"</string>
     <string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
     <string name="high_importance" msgid="1527066195614050263">"High importance"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Silently show at the bottom of the notification list"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Silently show these notifications"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Allow these notifications to make sounds"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Peek on to the screen and allow sound"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Show at the top of the notifications list, peek on to the screen and allow sound"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
     <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> notification controls"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Colour and appearance"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrate display"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"On"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Off"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Turn on automatically"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Switch into Night Mode as appropriate for location and time of day"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"When Night Mode is on"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Use dark theme for Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Adjust tint"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Adjust brightness"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"The dark theme is applied to core areas of Android OS that are normally displayed in a light theme, such as Settings."</string>
     <string name="color_apply" msgid="9212602012641034283">"Apply"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast-Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Show Do Not Disturb in volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Allow full control of Do Not Disturb in the volume dialogue."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume and Do Not Disturb"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Enter Do Not Disturb on volume down"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Exit Do Not Disturb on volume up"</string>
     <string name="battery" msgid="7498329822413202973">"Battery"</string>
     <string name="clock" msgid="7416090374234785905">"Clock"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphones connected"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset connected"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Enable or disable icons from being shown in the status bar."</string>
     <string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver is on"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver is off"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"On"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
     <string name="start" msgid="6873794757232879664">"Start"</string>
     <string name="center" msgid="4327473927066010960">"Centre"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
     <string name="preview" msgid="9077832302472282938">"Preview"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Drag here to remove"</string>
     <string name="qs_edit" msgid="2232596095725105230">"(edit)"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Time"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Show hours, minutes and seconds"</item>
+    <item msgid="1427801730816895300">"Show hours and minutes (default)"</item>
+    <item msgid="3830170141562534721">"Don\'t show this icon"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Always show percentage"</item>
+    <item msgid="2139628951880142927">"Show percentage when charging (default)"</item>
+    <item msgid="3327323682209964956">"Don\'t show this icon"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Other"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Split screen divider"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Move down"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings_tv.xml b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
new file mode 100644
index 0000000..87255ae
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
+    <string name="pip_play" msgid="674145557658227044">"Play"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pause"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Hold "<b>"HOME"</b>" to control PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Press and hold the HOME button to control PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Understood"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Dismiss"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 14f9301..f08894f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organisation."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problem encountered while saving screenshot."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Can\'t save screenshot due to limited storage space."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Taking screenshots is not allowed by the app or your organisation."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"More time."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Less time."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torch off."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torch unavailable."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torch on."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torch turned off."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torch turned on."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Work mode on."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Work mode turned off."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Work mode turned on."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Data Saver turned off."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Data Saver turned on."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G data is paused"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Clear all notifications."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+<xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Notification settings"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> settings"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Screen will rotate automatically."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nsilence"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"All\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Enable split-screen swipe-up accelerator"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Show notifications silently"</string>
+    <string name="block" msgid="2734508760962682611">"Block all notifications"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Don\'t silence"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Don\'t silence or block"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Show full importance settings"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Min importance"</string>
     <string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
     <string name="high_importance" msgid="1527066195614050263">"High importance"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Silently show at the bottom of the notification list"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Silently show these notifications"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Allow these notifications to make sounds"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Peek on to the screen and allow sound"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Show at the top of the notifications list, peek on to the screen and allow sound"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
     <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> notification controls"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Colour and appearance"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrate display"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"On"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Off"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Turn on automatically"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Switch into Night Mode as appropriate for location and time of day"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"When Night Mode is on"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Use dark theme for Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Adjust tint"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Adjust brightness"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"The dark theme is applied to core areas of Android OS that are normally displayed in a light theme, such as Settings."</string>
     <string name="color_apply" msgid="9212602012641034283">"Apply"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast-Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Show Do Not Disturb in volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Allow full control of Do Not Disturb in the volume dialogue."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume and Do Not Disturb"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Enter Do Not Disturb on volume down"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Exit Do Not Disturb on volume up"</string>
     <string name="battery" msgid="7498329822413202973">"Battery"</string>
     <string name="clock" msgid="7416090374234785905">"Clock"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphones connected"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset connected"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Enable or disable icons from being shown in the status bar."</string>
     <string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver is on"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver is off"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"On"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
     <string name="start" msgid="6873794757232879664">"Start"</string>
     <string name="center" msgid="4327473927066010960">"Centre"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
     <string name="preview" msgid="9077832302472282938">"Preview"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Drag here to remove"</string>
     <string name="qs_edit" msgid="2232596095725105230">"(edit)"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Time"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Show hours, minutes and seconds"</item>
+    <item msgid="1427801730816895300">"Show hours and minutes (default)"</item>
+    <item msgid="3830170141562534721">"Don\'t show this icon"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Always show percentage"</item>
+    <item msgid="2139628951880142927">"Show percentage when charging (default)"</item>
+    <item msgid="3327323682209964956">"Don\'t show this icon"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Other"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Split screen divider"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Move down"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings_tv.xml b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
new file mode 100644
index 0000000..87255ae
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
+    <string name="pip_play" msgid="674145557658227044">"Play"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pause"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Hold "<b>"HOME"</b>" to control PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Press and hold the HOME button to control PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Understood"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Dismiss"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4031204..b5a10e1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Se guardó la captura de pantalla."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver tu captura de pantalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"No se pudo guardar la captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Error de captura por almacenamiento limitado o porque la aplicación u organización no lo permiten."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Se produjo un error al guardar la captura de pantalla."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"No se puede guardar la captura de pantalla debido al almacenamiento limitado."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"La app o tu organización no permiten las capturas de pantalla."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rechazar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartada."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se descartaron todas las aplicaciones recientes."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La linterna no está disponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabajo activado"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Se desactivó el modo de trabajo."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Se activó el modo de trabajo."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Se desactivó Reducir datos."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Se activó Reducir datos."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configuración de notificaciones"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configuración de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Las pantallas recientes aparecen aquí."</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Todo borrado"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Fijar pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> está inhabilitada en modo seguro."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Borrar todo"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta app no es compatible con el modo multiventana"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"La app no es compatible con el modo multiventana"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silencio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\nprioridad"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Todo"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todo\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carga rápida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carga lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Deslizar el dedo hacia arriba para dividir la pantalla"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar gesto de dedo hacia arriba para dividir pantalla"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Recientes para acceder al modo de pantalla dividida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a las notificaciones de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas las notificaciones de esta app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificaciones de manera silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas las notificaciones"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"No silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciar ni bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar configuración de importancia"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Poca importancia"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar nunca estas notificaciones"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar en la parte inferior de la lista de notificaciones sin emitir sonido"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de manera silenciosa"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar en la parte inferior de la lista de notificaciones sin emitir sonido"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificaciones de manera silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificaciones emitan sonidos"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Ver en la pantalla y permitir sonidos"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar en la parte superior de la lista de notificaciones, ver en la pantalla y permitir sonidos"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automático"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Colores desconocidos"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificación del color"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar el mosaico de Configuración rápida"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Habilitar la transformación personalizada"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Color y apariencia"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Activado"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Desactivado"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Activar automáticamente"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Cambiar a modo nocturno según corresponda en relación con la ubicación y hora del día"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Cuando el modo nocturno está activado"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Usar tema oscuro para el SO Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tinte"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brillo"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"El tema oscuro se aplica en las áreas principales del SO Android que suelen mostrarse con un tema claro, como Configuración."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar la configuración"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algunas opciones de configuración de color pueden provocar que el dispositivo quede inutilizable. Haz clic en Aceptar para confirmar estos parámetros de color. De lo contrario, la configuración se restablecerá en diez segundos."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no está disponible durante la carga"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y el uso de datos en segundo plano"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Página principal"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Atrás"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Arriba"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Abajo"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Izquierda"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Derecha"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centro"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulación"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Espacio"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Intro"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retroceso"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproducir/pausar"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Detener"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Siguiente"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retroceder"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avanzar rápido"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pág"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pág"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Borrar"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Página principal"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insertar"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueo numérico"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pantalla principal"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar el panel de control de No interrumpir en el volumen"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir el control total del modo No interrumpir en el cuadro de diálogo de volumen."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumen y No interrumpir"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Activar el modo No interrumpir al bajar el volumen"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificaciones"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Combinación de teclas"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar método de entrada"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicaciones"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistencia"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No interrumpir"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas de botones de volumen"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Desactivar el modo No interrumpir al subir el volumen"</string>
     <string name="battery" msgid="7498329822413202973">"Batería"</string>
     <string name="clock" msgid="7416090374234785905">"Reloj"</string>
     <string name="headset" msgid="4534219457597457353">"Auriculares"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculares conectados"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculares conectados"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Habilitar o inhabilitar la visualización de los íconos en la barra de estado"</string>
     <string name="data_saver" msgid="5037565123367048522">"Reducir datos"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Reducir datos está activada"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Reducir datos está desactivada"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Activado"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desactivar"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
     <string name="start" msgid="6873794757232879664">"Iniciar"</string>
     <string name="center" msgid="4327473927066010960">"Centro"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Selecciona un botón del teclado"</string>
     <string name="preview" msgid="9077832302472282938">"Vista previa"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastra los mosaicos para agregarlos"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra aquí para quitar"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostrar horas, minutos y segundos"</item>
+    <item msgid="1427801730816895300">"Mostrar horas y minutos (predeterminado)"</item>
+    <item msgid="3830170141562534721">"No mostrar este ícono"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Siempre mostrar el porcentaje"</item>
+    <item msgid="2139628951880142927">"Mostrar el porcentaje durante la carga (predeterminado)"</item>
+    <item msgid="3327323682209964956">"No mostrar este ícono"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Otros"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover hacia abajo"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover hacia arriba"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la app no se ejecute con la función Multiventana"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Presiona dos veces para editarla."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Presiona dos veces para agregarlo."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Presiona dos veces para seleccionarla."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Quitar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Se agregó <xliff:g id="TILE_NAME">%1$s</xliff:g> a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Se quitó <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Se movió <xliff:g id="TILE_NAME">%1$s</xliff:g> a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de Configuración rápida"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
new file mode 100644
index 0000000..72ea127
--- /dev/null
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Cerrar PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reproducir"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausar"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Mantén presionado "<b>"INICIO"</b>" para controlar PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Mantén presionado el botón INICIO para controlar PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Entendido"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Descartar"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f531294..d8affc9 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura guardada"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver la captura de pantalla"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"No se ha podido guardar la captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Error al hacer captura por límite almacenamiento o porque aplicación u organización no lo permiten."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Se ha detectado un problema al guardar la captura de pantalla."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"No se puede guardar la captura de pantalla porque no hay espacio de almacenamiento suficiente."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"La aplicación o tu organización no permiten que se realicen capturas de pantalla."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Se ha eliminado <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se han ignorado todas las aplicaciones recientes."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La linterna no está disponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabajo activado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabajo desactivado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabajo activado."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Economizador de Datos desactivado."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Economizador de Datos activado."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de la pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ubicación definida por GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ajustes de notificaciones"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Ajustes de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Aquí aparecerán tus pantallas recientes"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Ningún elemento reciente"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Has rechazado todo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fijación de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"La aplicación <xliff:g id="APP">%s</xliff:g> se ha inhabilitado en modo seguro."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Borrar todo"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicación no admite el modo multiventana."</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"La aplicación no admite el modo multiventana"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silencio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\ncon prioridad"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Todo"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todo\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Habilitar deslizar el dedo hacia arriba para dividir la pantalla"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar deslizar dedo hacia arriba para dividir pantalla"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Visión general para acceder al modo de pantalla dividida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a las notificaciones de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas las notificaciones de esta aplicación"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificaciones de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas las notificaciones"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"No silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciar ni bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar ajustes de importancia por completo"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Poco importante"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Muy importante"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar estas notificaciones"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificaciones de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificaciones reproduzcan sonidos"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar en la pantalla y permitir sonido"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar en la parte superior de la lista de notificaciones, mostrar en la pantalla y permitir sonido"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automático"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Colores desconocidos"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificación de colores"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar mosaico de Ajustes rápidos"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Habilitar transformación personalizada"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Color y aspecto"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Sí"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"No"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Activar automáticamente"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Cambiar al modo nocturno cuando proceda según la ubicación y la hora del día"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Cuando el modo nocturno esté activado"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Tema oscuro para sistema operativo Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tono"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brillo"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"El tema oscuro se aplica a las áreas principales del sistema operativo Android que normalmente se muestran con un tema claro, como la aplicación Ajustes."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configuración"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algunas opciones de configuración de color pueden hacer que el dispositivo no se pueda utilizar. Haz clic en Aceptar para confirmar esta configuración. Si no lo haces, se restablecerá esta configuración cuando transcurran 10 segundos."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y las conexiones automáticas"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Atrás"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Arriba"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Abajo"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Izquierda"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Derecha"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centro"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulador"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Espacio"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Intro"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tecla de retroceso"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproducir/Pausa"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Detener"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Siguiente"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rebobinar"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rápido"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pág"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pág"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supr"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inicio"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloq Num"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar el panel de control de No molestar en el volumen"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir un control total del modo No molestar en el cuadro de diálogo de volumen."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumen y No molestar"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Activar No molestar al bajar el volumen"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificaciones"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Combinaciones de teclas"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar método de introducción"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicaciones"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistencia"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molestar"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas para los botones de volumen"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Salir de No molestar al subir el volumen"</string>
     <string name="battery" msgid="7498329822413202973">"Batería"</string>
     <string name="clock" msgid="7416090374234785905">"Reloj"</string>
     <string name="headset" msgid="4534219457597457353">"Auriculares"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculares conectados"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculares conectados"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Permite mostrar u ocultar iconos en la barra de estado"</string>
     <string name="data_saver" msgid="5037565123367048522">"Economizador de datos"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economizador de datos activado"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Economizador de datos desactivado"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Sí"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"No"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
     <string name="start" msgid="6873794757232879664">"Inicio"</string>
     <string name="center" msgid="4327473927066010960">"Centro"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Selecciona un botón de teclado"</string>
     <string name="preview" msgid="9077832302472282938">"Vista previa"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastrar para añadir mosaicos"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastrar aquí para eliminar"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Cambiar"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostrar horas, minutos y segundos"</item>
+    <item msgid="1427801730816895300">"Mostrar horas y minutos (predeterminado)"</item>
+    <item msgid="3830170141562534721">"No mostrar este icono"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Mostrar porcentaje siempre"</item>
+    <item msgid="2139628951880142927">"Mostrar porcentaje durante la carga (predeterminado)"</item>
+    <item msgid="3327323682209964956">"No mostrar este icono"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Otros"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Dividir la pantalla"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Bajar"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la aplicación no funcione con el modo multiventana"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toca dos veces para cambiarla."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toca dos veces para añadirlo."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Toca dos veces para seleccionarla."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Quitar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha añadido a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha quitado"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha movido a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de ajustes rápidos."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
new file mode 100644
index 0000000..c0b0afe
--- /dev/null
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Cerrar PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reproducir"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausar"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Mantén el botón "<b>"INICIO"</b>" pulsado para control de PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Mantén el botón de INICIO pulsado para controlar el modo PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Entendido"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorar"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index a7e34e6..f18bf05 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekraanipilt on jäädvustatud."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Puudutage kuvatõmmise vaatamiseks."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvatõmmist ei saanud jäädvustada."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Ekraanipilti ei saa jäädvustada piiratud talletusruumi tõttu või ei luba seda rakendus/organisatsioon."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Ekraanipildi salvestamisel ilmnes probleem."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Piiratud salvestusruumi tõttu ei saa ekraanipilti salvestada."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-failiedastuse valikud"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Paigalda meediumimängijana (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Paigalda kaamerana (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rakendusest <xliff:g id="APP">%s</xliff:g> loobumine."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Loobusite rakendusest <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kõikidest hiljutistest rakendustest on loobutud"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Rakenduse <xliff:g id="APP">%s</xliff:g> käivitamine."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g>, <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Märguandest on loobutud."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Pikem aeg."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Lühem aeg."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taskulamp on väljas."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taskulamp pole saadaval."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taskulamp on sees."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Taskulamp on välja lülitatud."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Taskulamp on sisse lülitatud."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Töörežiim on sees."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Töörežiim on välja lülitatud."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Töörežiim on sisse lülitatud."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Andmemahu säästja on välja lülitatud."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Andmemahu säästja on sisse lülitatud."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekraani heledus"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G andmekasutus on peatatud"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-i määratud asukoht"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Asukoha taotlused on aktiivsed"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Kustuta kõik teatised."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Märguandeseaded"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Rakenduse <xliff:g id="APP_NAME">%s</xliff:g> seaded"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekraani pööramine toimub automaatselt."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limiit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hoiatus"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Töörežiim"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Teie viimane ekraanikuva ilmub siia"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Hiljutisi üksusi pole"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Olete kõik ära kustutanud"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekraanikuva kinnitamine"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Rakendust <xliff:g id="APP">%s</xliff:g> ei saanud käivitada."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Rakendus <xliff:g id="APP">%s</xliff:g> on turvarežiimis keelatud."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Ajalugu"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Kustuta"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Kustuta kõik"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"See rakendus ei toeta mitut akent"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Rakendus ei toeta mitut akent"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horisontaalne poolitamine"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikaalne poolitamine"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Kohandatud poolitamine"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Täielik\nvaikus"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Ainult\nprioriteetsed"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ainult\nalarmid"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Kõik"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Kõik\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Kiirlaadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Aeglane laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Luba ülespühkimise kiirendi ekraani poolitamiseks"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Luba ülespühkimise liigutus ekraani poolitamiseks"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Lubab žesti, mis poolitab ekraani, kui kasutaja pühib üles nupul Ülevaade."</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kas lülitada Bluetooth sisse?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviatuuri ühendamiseks tahvelarvutiga peate esmalt Bluetoothi sisse lülitama."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Lülita sisse"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Rakenda teema <xliff:g id="TOPIC_NAME">%1$s</xliff:g> märguannete puhul"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Rakenda selle rakenduse kõigi märguannete puhul"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Kuva märguanded vaikselt"</string>
+    <string name="block" msgid="2734508760962682611">"Blokeeri kõik märguanded"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ära vaigista"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ära vaigista ega blokeeri"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Kuva täieliku tähtsuse seaded"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokeeritud"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimaalne tähtsus"</string>
     <string name="low_importance" msgid="4109929986107147930">"Madal tähtsuse tase"</string>
     <string name="default_importance" msgid="8192107689995742653">"Tavaline tähtsuse tase"</string>
     <string name="high_importance" msgid="1527066195614050263">"Kõrge tähtsuse tase"</string>
     <string name="max_importance" msgid="5089005872719563894">"Kiireloomuline tähtsuse tase"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ära kunagi näita neid märguandeid"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Kuva märguannete loendi allosas vaikselt"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Kuva need märguanded vaikselt"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Kuva märguannete loendi ülaosas koos heliga"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Kuva ekraani servas koos heliga"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Kuva märguannete loendi allosas vaikselt"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Kuva need märguanded vaikselt"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Luba nende märguannete puhul heli"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Kuva ekraani servas ja luba heli"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Kuva märguannete loendi ülaservas, kuva ekraani servas ja luba heli"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
     <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Tavalised värvid"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Öised värvid"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Kohandatud värvid"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automaatne"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Värvid on teadmata"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Värvi muutmine"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Kuva paan Kiirseaded"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Luba kohandatud teisendamine"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtnupud"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Värv ja ilme"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Öörežiim"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Ekraani kalibreerimine"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Sees"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Väljas"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Lülita automaatselt sisse"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Lülita öörežiimile, kui see on asukoha ja kellaaja suhtes sobilik"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kui öörežiim on sees"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Kasuta Android OS-is tumedat teemat"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Reguleeri tooni"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Reguleeri heledust"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tume teema rakendatakse Android OS-i põhialadele, mis kuvatakse tavaliselt heleda teemaga (nt seaded)."</string>
     <string name="color_apply" msgid="9212602012641034283">"Rakenda"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Seadete kinnitamine"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Mõni värviseade ei saa seadet võib-olla kasutada. Nende värviseadete kinnitamiseks klõpsake OK, muidu lähtestatakse need seaded 10 sekundi pärast."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akusäästja pole laadimise ajal saadaval"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akusäästja"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vähendab jõudlust ja taustaandmeid"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Nupp <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Avaekraan"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Tagasi"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Üles"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Alla"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vasakule"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Paremale"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Keskele"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulaator"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Tühik"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Sisestusklahv"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tagasilüke"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Esita/peata"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Peata"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Järgmine"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Eelmine"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Keri tagasi"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Keri edasi"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Lehe võrra üles"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Lehe võrra alla"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Kustuta"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Avaekraan"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Lõpp"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Sisesta"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Numbrilukk"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numbriklahvistik <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Süsteem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Avaekraan"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Hiljutised"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tagasi"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Kuva helitugevuse juures funktsioon Mitte segada"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Helitugevuse dialoogis lubatakse funktsiooni Mitte segada täielik juhtimine."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Helitugevus ja funktsioon Mitte segada"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Lülita helitugevuse vähendamisel sisse funkt. Mitte segada"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Märguanded"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klaviatuuri otseteed"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Sisestusmeetodi vahetamine"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Rakendused"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Abi"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktid"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM (kiirsuhtlus)"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muusika"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Kuva koos helitugevuse juhtnuppudega"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mitte segada"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Helitugevuse nuppude otsetee"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Lülita helitugevuse suurendamisel välja funkt. Mitte segada"</string>
     <string name="battery" msgid="7498329822413202973">"Aku"</string>
     <string name="clock" msgid="7416090374234785905">"Kell"</string>
     <string name="headset" msgid="4534219457597457353">"Peakomplekt"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Kõrvaklapid on ühendatud"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Peakomplekt on ühendatud"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Lubatakse või keelatakse ikoonide kuvamine olekuribal."</string>
     <string name="data_saver" msgid="5037565123367048522">"Andmemahu säästja"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Andmemahu säästja on sisse lülitatud"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Andmemahu säästja on välja lülitatud"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Sees"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Väljas"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigeerimisriba"</string>
     <string name="start" msgid="6873794757232879664">"Algus"</string>
     <string name="center" msgid="4327473927066010960">"Keskkoht"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Klaviatuuri nupu valimine"</string>
     <string name="preview" msgid="9077832302472282938">"Eelvaade"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Lohistage paanide lisamiseks"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Lohistage eemaldamiseks siia"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Muuda"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Kellaaeg"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Kuva tunnid, minutid ja sekundid"</item>
+    <item msgid="1427801730816895300">"Kuva tunnid ja minutid (vaikimisi)"</item>
+    <item msgid="3830170141562534721">"Ära kuva seda ikooni"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Kuva alati protsent"</item>
+    <item msgid="2139628951880142927">"Kuva protsent laadimisel (vaikimisi)"</item>
+    <item msgid="3327323682209964956">"Ära kuva seda ikooni"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Muu"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Ekraanijagaja"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Liigu alla"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Liigu üles"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Liigu vasakule"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Liigu paremale"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Rakendus ei pruugi mitme akna režiimis töötada"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Asend <xliff:g id="POSITION">%1$d</xliff:g>, paan <xliff:g id="TILE_NAME">%2$s</xliff:g>. Topeltpuudutage muutmiseks."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Topeltpuudutage lisamiseks."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Asend <xliff:g id="POSITION">%1$d</xliff:g>. Topeltpuudutage valimiseks."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Paani <xliff:g id="TILE_NAME">%1$s</xliff:g> teisaldamine"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Paani <xliff:g id="TILE_NAME">%1$s</xliff:g> eemaldamine"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> lisati asendisse <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> eemaldati"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> teisaldati asendisse <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kiirseadete redigeerija."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings_tv.xml b/packages/SystemUI/res/values-et-rEE/strings_tv.xml
new file mode 100644
index 0000000..f427b80
--- /dev/null
+++ b/packages/SystemUI/res/values-et-rEE/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Sule PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Täisekraan"</string>
+    <string name="pip_play" msgid="674145557658227044">"Esita"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Peata"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP juht. hoidke all nuppu "<b>"AVAEKRAAN"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP juhtimiseks vajutage pikalt nuppu AVAEKRAAN"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Selge"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Loobu"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index dcb8ef9..575f8749 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Pantaila-argazkia atera da."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Pantaila-argazkia ikusteko, ukitu ezazu."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Ezin izan da pantaila-argazkia atera."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Ezin da atera pantaila-argazkia tokirik geratzen ez delako edo horrelakorik onartzen ez delako."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Arazo bat izan da pantaila-argazkia gordetzean."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Ezin da atera pantaila-argazkia ez delako tokirik geratzen."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikazioak edo erakundeak ez du onartzen pantaila-argazkiak ateratzea."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB fitxategiak transferitzeko aukerak"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Muntatu multimedia-erreproduzigailu gisa (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Muntatu kamera gisa (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Baztertu <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> baztertu da."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Azken aplikazio guztiak baztertu da."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> hasten."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Jakinarazpena baztertu da."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Denbora gehiago."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Denbora gutxiago."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flasha desaktibatuta dago."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Linterna ez dago erabilgarri."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flasha aktibatuta dago."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flasha desaktibatu egin da."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flasha aktibatu egin da."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Aktibatuta dago lan modua."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Desaktibatuta dago lan modua."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Aktibatuta dago lan modua."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Desaktibatuta dago datu-aurrezlea."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Aktibatuta dago datu-aurrezlea."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bistaratu distira"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G datuen erabilera eten da"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Kokapena GPS bidez ezarri da"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aplikazioen kokapen-eskaerak aktibo daude"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Garbitu jakinarazpen guztiak."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Jakinarazpen-ezarpenak"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ezarpenak"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Pantaila automatikoki biratuko da."</string>
@@ -296,18 +304,19 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Muga: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Lan modua"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Ikusitako azken pantailak erakusten dira hemen"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Ez dago azkenaldi honetako ezer"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Dena garbitu duzu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pantaila-ainguratzea"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Garbitu"</string>
-    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Banaketa horizontala"</string>
-    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Banaketa bertikala"</string>
-    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Banaketa pertsonalizatua"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> desgaituta dago modu seguruan."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Garbitu guztiak"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Zatitze horizontala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Zatitze bertikala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Zatitze pertsonalizatua"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kargatzen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> falta zaizkio guztiz kargatzeko"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Isiltasun\nosoa"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Lehentasunezkoak\nsoilik"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmak\nsoilik"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Guztiak"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Guztiak\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Bizkor kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mantso kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Gaitu hatza gora pasatuta pantaila zatitzeko bizkortzailea"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Gaitu pantaila zatitzeko keinua hatza gora pasatuta"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Sakatu Ikuspegi nagusia botoia eta gaitu hatza gora pasatuta pantaila zatitzeko keinua"</string>
     <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktibatu"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplikatu \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\" gaiari buruzko jakinarazpenei"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplikatu aplikazio honetako jakinarazpen guztiei"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Erakutsi jakinarazpenak soinurik egin gabe"</string>
+    <string name="block" msgid="2734508760962682611">"Blokeatu jakinarazpen guztiak"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ez isilarazi"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ez isilarazi edo blokeatu"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Erakutsi garrantzi handiko jakinarazpenen ezarpenak"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokeatuta"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Gutxieneko garrantzia"</string>
     <string name="low_importance" msgid="4109929986107147930">"Garrantzi txikia"</string>
     <string name="default_importance" msgid="8192107689995742653">"Garrantzi normala"</string>
     <string name="high_importance" msgid="1527066195614050263">"Garrantzi handia"</string>
     <string name="max_importance" msgid="5089005872719563894">"Premiazkoa"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ez erakutsi jakinarazpen hauek inoiz"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Erakutsi jakinarazpen hauek zerrendaren behealdean, baina soinurik egin gabe"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Erakutsi jakinarazpen hauek zerrendaren goialdean eta egin soinua"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Erakutsi jakinarazpen hauek zerrendaren behealdean, baina soinurik egin gabe"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Egin soinua jakinarazpen hauek jasotzean"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Erakutsi jakinarazpen hauek zerrendaren goialdean, agerrarazi pantailan eta egin soinua"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
     <string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Kolore normalak"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Gaueko koloreak"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Kolore pertsonalizatuak"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatikoa"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Kolore ezezagunak"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Kolore-aldaketa"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Erakutsi ezarpen bizkorren lauza"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Gaitu itxuraldaketa pertsonalizatua"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak kontrolatzeko aukerak"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Kolorea eta itxura"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Gau modua"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibratu pantaila"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Aktibatuta"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Desaktibatuta"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Aktibatu automatikoki"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Aldatu Gau modura, kokapena eta ordua kontuan izanda"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Gau modua aktibatuta dagoenean"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Erabili gai iluna Android sistema eragilean"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Doitu kolorea"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Doitu distira"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Gai iluna Android sistema eragileko eremu nagusietan aplikatzen da. Normalean gai argian bistaratzen dira eremu horiek, adibidez, Ezarpenak atalean."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplikatu"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Berretsi ezarpenak"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Baliteke gailua kolore-ezarpen batzuekin ezin erabili izatea. Kolore-ezarpenak berresteko, sakatu Ados. Bestela, hamar segundoren buruan berrezarriko dira ezarpenak."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Bateriaren erabilera"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Bateria-aurrezlea ez dago erabilgarri gailua kargatzen ari denean"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Bateria-aurrezlea"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Errendimendua eta atzeko planoko datuen erabilera murrizten ditu"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> botoia"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Hasiera"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Atzera"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gora"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Behera"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Ezkerrera"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Eskuinera"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Erdiratu"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabuladorea"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Zuriunea"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Sartu"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Atzera"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Erreproduzitu/Pausatu"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Gelditu"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Hurrengoa"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Aurrekoa"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Atzeratu"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Aurreratu"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Orria gora"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Orria behera"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ezabatu"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Hasiera"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Amaitu"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Txertatu"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Blok Zenb"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Zenbaki-teklatuko <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Hasierako pantaila"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Azkenak"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atzera"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Erakutsi \"Ez molestatu\" aukera bolumenaren leihoan"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Baimendu bolumenaren leihoan \"Ez molestatu\" aukera guztiz kontrolatzea."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Bolumena eta \"Ez molestatu\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Sartu \"Ez molestatu\" egoeran bolumena jaistean"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Jakinarazpenak"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Lasterbideak"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Aldatu idazketa-metodoa"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikazioak"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Laguntzailea"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Arakatzailea"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktuak"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Helbide elektronikoa"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Istanteko mezularitza"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musika"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Egutegia"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Erakutsi bolumena kontrolatzeko aukerekin"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ez molestatu"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Bolumen-botoietarako lasterbidea"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Irten \"Ez molestatu\" egoeratik bolumena igotzean"</string>
     <string name="battery" msgid="7498329822413202973">"Bateria"</string>
     <string name="clock" msgid="7416090374234785905">"Erlojua"</string>
     <string name="headset" msgid="4534219457597457353">"Mikrofonodun entzungailua"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Aurikularrak konektatu dira"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Mikrofonodun entzungailua konektatu da"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Gaitu edo desgaitu ikonoak egoera-barran erakusteko aukera."</string>
     <string name="data_saver" msgid="5037565123367048522">"Datu-aurrezlea"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Aktibatuta dago datu-aurrezlea"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Desaktibatuta dago datu-aurrezlea"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Aktibatuta"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desaktibatuta"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Nabigazio-barra"</string>
     <string name="start" msgid="6873794757232879664">"Hasi"</string>
     <string name="center" msgid="4327473927066010960">"Erdiratu"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Hautatu teklatuko botoia"</string>
     <string name="preview" msgid="9077832302472282938">"Aurrebista"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastatu lauzak hemen gehitzeko"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kentzeko, arrastatu hona"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editatu"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Ordua"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Erakutsi orduak, minutuak eta segundoak"</item>
+    <item msgid="1427801730816895300">"Erakutsi orduak eta minutuak (balio lehenetsia)"</item>
+    <item msgid="3830170141562534721">"Ez erakutsi ikonoa"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Erakutsi beti ehunekoa"</item>
+    <item msgid="2139628951880142927">"Erakutsi ehunekoa kargatu bitartean (balio lehenetsia)"</item>
+    <item msgid="3327323682209964956">"Ez erakutsi ikonoa"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Beste bat"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Pantaila-zatitzailea"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Eraman behera"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Eraman gora"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Eraman ezkerrera"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Eraman eskuinera"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Baliteke aplikazioak ez funtzionatzea leiho anitzetan."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. posizioa, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Editatzeko, sakatu birritan."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Gehitzeko, sakatu birritan."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. posizioa. Hautatzeko, sakatu birritan."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mugitu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Kendu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> gehitu da <xliff:g id="POSITION">%2$d</xliff:g>. posizioan"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Kendu da <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>. posiziora eraman da"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ezarpen bizkorren editorea."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings_tv.xml b/packages/SystemUI/res/values-eu-rES/strings_tv.xml
new file mode 100644
index 0000000..b812143
--- /dev/null
+++ b/packages/SystemUI/res/values-eu-rES/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Itxi PIPa"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Pantaila osoa"</string>
+    <string name="pip_play" msgid="674145557658227044">"Erreproduzitu"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausatu"</string>
+    <string name="pip_hold_home" msgid="340086535668778109"><b>"HASIERA"</b>" PIP kontrolatzeko"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Eduki sakatuta hasierako botoia pantaila txikia kontrolatzeko"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Ados"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Baztertu"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 851a6cb..322197e 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"به دلیل فضای ذخیره‌سازی کم یا عدم اجازه برنامه یا سازمانتان، نمی‌توان از صفحه عکس گرفت."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"هنگام ذخیره عکس صفحه‌نمایش مشکلی رخ داد."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"به دلیل محدود بودن فضای ذخیره‌سازی نمی‌توانید عکس صفحه‌نمایش را ذخیره کنید."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"این برنامه یا سازمان شما اجازه نمی‌دهند عکس صفحه‌نمایش بگیرید."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"‏گزینه‌های انتقال فایل USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏نصب به‌عنوان دستگاه پخش رسانه (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏تصب به‌عنوان دوربین (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"رد کردن <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> نادیده گرفته شد."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"همه برنامه‌های اخیر رد شدند."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> در حال شروع به کار است."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"اعلان ردشد."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"زمان بیشتر."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"زمان کمتر."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"چراغ قوه خاموش است."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"چراغ قوه در دسترس نیست."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"چراغ قوه روشن است."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"چراغ قوه خاموش شد."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"چراغ قوه روشن شد."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"حالت کار روشن."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"حالت کار خاموش شد."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"حالت کار روشن شد."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"صرفه‌جویی داده خاموش شد."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"صرفه‌جویی داده روشن شد."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"روشنایی نمایشگر"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏داده 2G-3G موقتاً متوقف شده است"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏داده 4G موقتاً متوقف شده است"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"‏مکان تنظیم شده توسط GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"درخواست‌های موقعیت مکانی فعال است"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"پاک کردن تمام اعلان‌ها"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"تنظیمات اعلان"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"تنظیمات <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"صفحه به صورت خودکار می‌چرخد."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> محدودیت"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"حالت کار"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"صفحه‌های اخیر شما اینجا نمایان می‌شوند"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"بدون موارد اخیر"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"همه‌چیز را پاک کرده‌اید"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"پین کردن صفحه"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> شروع نشد."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"سابقه"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"پاک کردن"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> در حالت ایمن غیرفعال است."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"پاک کردن همه"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"این برنامه از چندپنجره پشتیبانی نمی‌کند"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"برنامه از چندپنجره پشتیبانی نمی‌کند"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسیم افقی"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسیم عمودی"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"سفارشی کردن تقسیم"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"سکوت\nکامل"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"فقط\nاولویت‌دار"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"فقط\nهشدارها"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"همه"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"همه\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"در حال شارژ سریع (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"در حال شارژ آهسته (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
     <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"فعال کردن شتاب‌دهنده تقسیم صفحه با بالا کشیدن"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"فعال کردن تقسیم صفحه با اشاره بالا کشیدن"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"اشاره ورود به تقسیم صفحه با بالا کشیدن صفحه از دکمه نمای کلی را فعال می‌کند"</string>
     <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوتوث روشن شود؟"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"برای مرتبط کردن صفحه‌کلید با رایانه لوحی، ابتدا باید بلوتوث را روشن کنید."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"روشن کردن"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"اعمال بر روی اعلان‌های <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"اعمال بر روی تمام اعلان‌های این برنامه"</string>
+    <string name="show_silently" msgid="6841966539811264192">"نمایش بی‌صدای اعلان‌ها"</string>
+    <string name="block" msgid="2734508760962682611">"مسدود کردن همه اعلان‌ها"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ساکت نشود"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ساکت یا مسدود نشود"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"نمایش تنظیمات کامل اهمیت"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"مسدود شده"</string>
+    <string name="min_importance" msgid="1901894910809414782">"کمترین اهمیت"</string>
     <string name="low_importance" msgid="4109929986107147930">"اهمیت کم"</string>
     <string name="default_importance" msgid="8192107689995742653">"اهمیت معمولی"</string>
     <string name="high_importance" msgid="1527066195614050263">"اهمیت زیاد"</string>
     <string name="max_importance" msgid="5089005872719563894">"اهمیت فوری"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"هرگز این اعلان‌ها نشان داده نشوند"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"این اعلان‌ها بی‌صدا نشان داده شوند"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"در بالای فهرست اعلان‌ها و به همراه صدا نشان داده شود"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"در جلوی صفحه به همراه صدا نشان داده شود"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"این اعلان‌ها بی‌صدا نشان داده شوند"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"به این اعلان‌ها اجازه داده شود صدادار باشند"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"در صفحه نشان داده شوند و صدادار باشند"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"در بالای فهرست اعلان نشان داده شوند، در صفحه نشان داده شوند و صدادار باشند"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
     <string name="notification_done" msgid="5279426047273930175">"تمام"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"رنگ‌های عادی"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"رنگ‌های شب"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"رنگ‌های سفارشی"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"خودکار"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"رنگ‌های نامشخص"</string>
-    <string name="color_transform" msgid="6985460408079086090">"اصلاح رنگ"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"نمایش کاشی تنظیمات سریع"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"فعال کردن تبدیل سفارشی"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"کنترل‌های اعلان <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"رنگ و ظاهر"</string>
+    <string name="night_mode" msgid="3540405868248625488">"حالت شب"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"درجه‌بندی نمایشگر"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"روشن"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"خاموش"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"روشن شدن خودکار"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"تغییر به حالت شب وقتی برای مکان و زمان روز مناسب است"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"وقتی حالت شب روشن است"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"‏استفاده از زمینه تیره برای سیستم‌عامل Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"تنظیم سایه‌رنگ"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"تنظیم روشنایی"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"‏زمینه تیره بر قسمت‌های اصلی سیستم‌عامل Android که به‌طور معمول با زمینه روشن نشان داده می‌شوند (مثل «تنظیمات») اعمال می‌شود."</string>
     <string name="color_apply" msgid="9212602012641034283">"اعمال‌ کردن"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"تأیید تنظیمات"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"بعضی از تنظیمات رنگ می‌توانند این دستگاه را غیرقابل استفاده کنند. برای تأیید این تنظیمات رنگ روی «تأیید» کلیک کنید، در غیر این صورت این تغییرات بعد از ۱۰ ثانیه بازنشانی می‌شوند."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"مصرف باتری"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"هنگام شارژ شدن، «بهینه‌سازی باتری» در دسترس نیست"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"بهینه‌سازی باتری"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"عملکرد و اطلاعات پس‌زمینه را کاهش می‌دهد"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"دکمه <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"ابتدا"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"برگشت"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"بالا"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"پایین"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"چپ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"راست"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"مرکز"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"جهش"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"فاصله"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"ورود"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"پس‌بر"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"پخش/مکث"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"توقف"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"بعدی"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"قبلی"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"عقب بردن"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"جلو بردن سریع"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"صفحه بعدی"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"صفحه قبلی"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"حذف"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"ابتدا"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"انتها"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"درج"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"قفل اعداد"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"صفحه‌کلید عددی <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"سیستم"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"صفحه اصلی"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"موارد اخیر"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"برگشت"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"نمایش «مزاحم نشوید» در میزان صدا"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"به حالت «مزاحم نشوید» اجازه داده می‌شود در کادر گفتگوی میزان صدا کنترل کامل داشته باشد."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"میزان صدا و «مزاحم نشوید»"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"وارد شدن به حالت «مزاحم نشوید» در میزان صدای پایین"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"اعلان‌ها"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"میان‌برهای صفحه‌کلید"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"تغییر روش ورودی"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"برنامه‌ها"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"دستیار"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"مرورگر"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"مخاطبین"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"رایانامه"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"پیام فوری"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"موسیقی"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"تقویم"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"نمایش با کنترل‌های صدا"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"مزاحم نشوید"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"میان‌بر دکمه‌های صدا"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"خارج شدن از حالت «مزاحم نشوید» در میزان صدای بالا"</string>
     <string name="battery" msgid="7498329822413202973">"باتری"</string>
     <string name="clock" msgid="7416090374234785905">"ساعت"</string>
     <string name="headset" msgid="4534219457597457353">"هدست"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"هدفون وصل شد"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"هدست وصل شد"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"فعال یا غیرفعال کردن نمایش نمادها در نوار وضعیت."</string>
-    <string name="data_saver" msgid="5037565123367048522">"صرفه‌جویی در مصرف داده"</string>
-    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"صرفه‌جویی در مصرف داده روشن است"</string>
-    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"صرفه‌جویی در مصرف داده خاموش است"</string>
+    <string name="data_saver" msgid="5037565123367048522">"صرفه‌جویی داده"</string>
+    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"صرفه‌جویی داده روشن است"</string>
+    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"صرفه‌جویی داده خاموش است"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"روشن"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"خاموش"</string>
     <string name="nav_bar" msgid="1993221402773877607">"نوار پیمایش"</string>
     <string name="start" msgid="6873794757232879664">"شروع"</string>
     <string name="center" msgid="4327473927066010960">"وسط"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"کلید صفحه‌کلید را انتخاب کنید"</string>
     <string name="preview" msgid="9077832302472282938">"پیش‌نمایش"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"کشیدن برای افزودن کاشی‌ها"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"برای حذف، به اینجا بکشید"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ویرایش"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"زمان"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"ساعت، دقیقه و ثانیه نشان داده شود"</item>
+    <item msgid="1427801730816895300">"ساعت و دقیقه نشان داده شود (پیش‌فرض)"</item>
+    <item msgid="3830170141562534721">"این نماد نشان داده نشود"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"همیشه درصد نشان داده شود"</item>
+    <item msgid="2139628951880142927">"هنگام شارژ شدن درصد نشان داده شود (پیش‌فرض)"</item>
+    <item msgid="3327323682209964956">"این نماد نشان داده نشود"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"موارد دیگر"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"تقسیم‌کننده صفحه"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"انتقال به پایین"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"انتقال به بالا"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"انتقال به چپ"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"انتقال به راست"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"برنامه ممکن است با چندپنجره کار نکند"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>. برای ویرایش دو ضربه سریع بزنید."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. برای افزودن دو ضربه سریع بزنید."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>. برای انتخاب دو ضربه سریع بزنید."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"انتقال <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"حذف <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> به موقعیت <xliff:g id="POSITION">%2$d</xliff:g> اضافه می‌شود"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> حذف می‌شود"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> به موقعیت <xliff:g id="POSITION">%2$d</xliff:g> منتقل شد"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ویرایشگر تنظیمات سریع."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
new file mode 100644
index 0000000..0d028d8
--- /dev/null
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"‏بستن PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"تمام صفحه"</string>
+    <string name="pip_play" msgid="674145557658227044">"پخش"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"مکث"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"‏کنترل PIP ‏با نگه‌داشتن "<b>"HOME"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"‏برای کنترل PIP دکمه صفحه اصلی را فشار داده و نگه‌دارید"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"متوجه شدم"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"رد کردن"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index d44bd75..6db0a3e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvakaappaus tallennettu"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Katso kuvakaappaus koskettamalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvakaappausta ei voitu tallentaa"</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Kuvakaappaus ei onnistu, koska tila ei riitä tai koska sovellus tai organisaatiosi ei salli sitä."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Kuvakaappausta tallennettaessa tapahtui virhe."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kuvakaappauksen tallentaminen epäonnistui, sillä tallennustilaa ei ole riittävästi."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Sovellus tai organisaatiosi ei salli kuvakaappauksien tallentamista."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-tiedostonsiirtoasetukset"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Käytä mediasoittimena (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Käytä kamerana (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hylätään <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> hylättiin."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kaikki viimeisimmät sovellukset on hylätty."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Käynnistetään <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ilmoitus hylätty."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lisää aikaa."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Vähennä aikaa."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taskulamppu on pois päältä."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taskulamppu ei ole käytettävissä."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taskulamppu on päällä."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Taskulamppu poistettiin käytöstä."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Taskulamppu otettiin käyttöön."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Työtila on käytössä."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Työtila poistettiin käytöstä."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Työtila otettiin käyttöön."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Data Saver poistettiin käytöstä."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Data Saver otettiin käyttöön."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Näytön kirkkaus"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G-tiedonsiirto keskeytettiin"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Sijainti määritetty GPS:n avulla"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Sijaintipyynnöt aktiiviset"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Tyhjennä kaikki ilmoitukset."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ilmoitusasetukset"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Asetukset – <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ruutu kääntyy automaattisesti."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"kiintiö <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Työtila"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Äskettäin käytetyt ruudut näkyvät tässä"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Ei viimeaikaisia kohteita"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Kaikki on hoidettu."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"näytön kiinnitys"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tyhjennä"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> on poistettu käytöstä vikasietotilassa."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tyhjennä kaikki"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Tämä sovellus ei tue usean ikkunan tilaa."</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Sovellus ei tue usean ikkunan tilaa."</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pystysuuntainen jako"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Muokattu jako"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Täydellinen\nhiljaisuus"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vain\ntärkeät"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vain\nherätykset"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Kaikki"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Kaikki\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nopea lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Hidas lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ota jaetun näytön tilan pyyhkäisyele käyttöön"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Siirry jaetun näytön tilaan pyyhkäisemällä ylöspäin"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Voit siirtyä jaetun näytön tilaan pyyhkäisemällä Viimeisimmät-painikkeesta ylöspäin."</string>
     <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ota käyttöön"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Sovella aiheen <xliff:g id="TOPIC_NAME">%1$s</xliff:g> ilmoituksiin"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Sovella kaikkiin tämän sovelluksen ilmoituksiin"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Näytä ilmoitukset hiljennettyinä"</string>
+    <string name="block" msgid="2734508760962682611">"Estä kaikki ilmoitukset"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Älä hiljennä"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Älä hiljennä tai estä"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Näytä kaikki tärkeysasetukset"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Estetyt"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Pienin tärkeys"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ei kovin tärkeä"</string>
     <string name="default_importance" msgid="8192107689995742653">"Tärkeä"</string>
     <string name="high_importance" msgid="1527066195614050263">"Hyvin tärkeä"</string>
     <string name="max_importance" msgid="5089005872719563894">"Kiireellinen"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Älä koskaan näytä näitä ilmoituksia"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Näytä huomaamattomasti ilmoitusluettelon alaosassa"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Näytä nämä ilmoitukset huomaamattomasti"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Näytä ilmoitukset luettelon kärjessä ja toista merkkiääni"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Näytä ilmoitus näytöllä ja toista äänimerkki"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Hiljennä ilmoitukset ja näytä ne ilmoitusluettelon alaosassa."</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Näytä nämä ilmoitukset hiljennettyinä."</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Salli näiden ilmoitusten äänet."</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Näytä ilmoitukset näytöllä ja salli niiden äänet."</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Näytä ilmoitukset näytöllä ja ilmoitusluettelon yläosassa ja salli niiden äänet."</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
     <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Tavalliset värit"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Yövärit"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Muokatut värit"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automaattinen"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Tuntemattomat värit"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Muokatut värit"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Näytä pika-asetusruutu"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Ota muokatut värit käyttöön"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ilmoitusten hallinta"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Väri ja ulkoasu"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Yötila"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibroi näyttö"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Käytössä"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Pois käytöstä"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Ota käyttöön automaattisesti"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Ota yötila käyttöön sijainnin ja kellonajan perusteella."</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kun yötila on käytössä"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Käytä tummaa teemaa käyttöjärjestelmässä"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Säädä sävytystä"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Säädä kirkkautta"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tumma teema tulee käyttöön Android-käyttöjärjestelmän ydinosissa, kuten Asetuksissa, joissa käytetään tavallisesti vaaleaa teemaa."</string>
     <string name="color_apply" msgid="9212602012641034283">"Käytä"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Vahvista asetukset"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Jotkin väriasetukset voivat häiritä laitteen käyttöä. Vahvista uudet väriasetukset valitsemalla OK. Muussa tapauksessa aiemmat asetukset palautetaan 10 sekunnin kuluttua."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Akun käyttö"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Virransäästö ei ole käytettävissä latauksen aikana."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Virransäästö"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa."</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Painike <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Takaisin"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Ylös"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Alas"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vasemmalle"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Oikealle"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Keskelle"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Sarkain"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Välilyönti"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Askelpalautin"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Toisto/keskeytys"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Pysäytä"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seuraava"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Edellinen"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Kelaa taaksepäin"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Kelaa eteenpäin"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numeronäppäimistö <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Järjestelmä"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Aloitusnäyttö"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Viimeaikaiset"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Takaisin"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Näytä Älä häiritse ‑valinnat äänenvoimakkuudessa"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Näytä kaikki Älä häiritse ‑tilan säädöt äänenvoimakkuusvalinnassa."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Äänenvoimakkuus ja Älä häiritse ‑tila"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Siirry Älä häiritse -tilaan, kun äänenvoimakkuutta lasketaan"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ilmoitukset"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pikanäppäimet"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Vaihda syöttötapaa"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Sovellukset"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Apusovellus"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Selain"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Yhteystiedot"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Sähköposti"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Pikaviesti"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiikki"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalenteri"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Näytä äänenvoimakkuuden säätimien yhteydessä"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Älä häiritse"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Äänenvoimakkuuspainikkeiden pikanäppäin"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Poistu Älä häiritse -tilasta, kun äänenvoimakkuus nousee"</string>
     <string name="battery" msgid="7498329822413202973">"Akku"</string>
     <string name="clock" msgid="7416090374234785905">"Kello"</string>
     <string name="headset" msgid="4534219457597457353">"Kuulokemikrofoni"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Kuulokkeet liitetty"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Kuulokemikrofoni liitetty"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ota tilapalkin kuvakkeet käyttöön tai poista ne käytöstä."</string>
     <string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver on käytössä."</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver on pois käytöstä."</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Käytössä"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Pois käytöstä"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigointipalkki"</string>
     <string name="start" msgid="6873794757232879664">"Alussa"</string>
     <string name="center" msgid="4327473927066010960">"Keskellä"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Valitse näppäimistön näppäin"</string>
     <string name="preview" msgid="9077832302472282938">"Esikatselu"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Lisää osioita vetämällä."</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Poista vetämällä tähän."</string>
     <string name="qs_edit" msgid="2232596095725105230">"Muokkaa"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Aika"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Näytä tunnit, minuutit ja sekunnit"</item>
+    <item msgid="1427801730816895300">"Näytä tunnit ja minuutit (oletus)"</item>
+    <item msgid="3830170141562534721">"Älä näytä tätä kuvaketta"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Näytä prosenttiluku aina"</item>
+    <item msgid="2139628951880142927">"Näytä prosenttiluku latauksen aikana (oletus)"</item>
+    <item msgid="3327323682209964956">"Älä näytä tätä kuvaketta"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Muu"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Näytön jakaja"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Siirrä alaspäin"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Siirrä ylöspäin"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Siirrä vasemmalle"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Siirrä oikealle"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Sovellus ei ehkä toimi usean ikkunan tilassa."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Muokkaa kaksoisnapauttamalla."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lisää kaksoisnapauttamalla."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>. Valitse kaksoisnapauttamalla."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Siirrä <xliff:g id="TILE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Poista <xliff:g id="TILE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> lisättiin paikkaan <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> poistettiin."</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> siirrettiin paikkaan <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Pika-asetusten muokkausnäkymä"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
new file mode 100644
index 0000000..9124f67
--- /dev/null
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Sulje PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Koko näyttö"</string>
+    <string name="pip_play" msgid="674145557658227044">"Toista"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Keskeytä"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP: paina pitkään "<b>"aloituspain"</b>"."</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Hallinnoi PIP-tilaa painamalla ALOITUSNÄYTTÖ-painiketta pitkään."</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Selvä"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Hylkää"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index d34723f..89c6826 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Imposs. prendre saisie d\'écran : espace stock. limité, ou l\'appli ou votre organisation l\'interdit."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Une erreur s\'est produite lors de l\'enregistrement de la saisie d\'écran."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Impossible d\'enregistrer la saisie d\'écran, car l\'espace de stockage est limité."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"L\'application ou votre organisation n\'autorise pas les saisies d\'écran."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Installer comme un lecteur multimédia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Installer comme un appareil photo (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampe de poche indisponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mode Travail activé."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Le mode Travail est désactivé."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Le mode Travail est activé."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Mode Économiseur de données désactivé."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Mode Économiseur de données activé."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'écran"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G/3G désactivées"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Paramètres de notification"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Paramètres de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Vos écrans récents s\'affichent ici"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historique"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Effacer"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Effacer tout"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Cette application ne prend pas en charge le mode multifenêtre"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'application ne prend pas en charge le mode multifenêtre"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Aucune\ninterruption"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorités\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Tous"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tous\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activer l\'accélérateur d\'écr. partagé en balayant vers le haut"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer le geste d\'écran partagé en balayant vers le haut"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton « Aperçu »"</string>
     <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Appliquer à <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Appliquer à toutes les notifications de cette application"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Afficher les notifications en mode silencieux"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquer toutes les notifications"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne pas activer le mode silencieux"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne pas activer le mode silencieux ni bloquer"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afficher les paramètres d\'importance complets"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloquée"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importance minimale"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importance urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Afficher en mode silencieux au bas de la liste de notifications"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Afficher en mode silencieux au bas de la liste de notifications"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Afficher ces notifications en mode silencieux"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Autoriser ces notifications à émettre des sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatique"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Couleurs inconnues"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modifier la couleur"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afficher la tuile de configuration rapide"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Activer la transformation personnalisée"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Mode Nuit"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrer l\'affichage"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Activé"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Désactivé"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Activer automatiquement"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Passer en mode Nuit en fonction de la position et de l\'heure de la journée"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Lorsque le mode Nuit est activé"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Utiliser thème foncé pour Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajuster la coloration"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Régler la luminosité"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Le thème foncé est appliqué à des zones essentielles de la plateforme Android qui sont habituellement affichées dans un thème clair, comme les paramètres."</string>
     <string name="color_apply" msgid="9212602012641034283">"Appliquer"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmer les paramètres"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Certains paramètres de couleurs peuvent rendre cet appareil inutilisable. Cliquez sur « OK » pour valider ces paramètres, sinon ils seront réinitialisés après 10 secondes."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Utilisation de la pile"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Le mode Économie d\'énergie n\'est pas accessible pendant la charge"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Économie d\'énergie"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Réduit les performances et les données en arrière-plan"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Accueil"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Précédent"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Haut"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Bas"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Gauche"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Droite"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centrer"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulation"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Espace"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Entrée"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retour arrière"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Lecture/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Arrêter"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Suivant"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Précédent"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Reculer"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rapide"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page précédente"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page suivante"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supprimer"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Accueil"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insérer"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Verr num"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Pavé numérique <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Système"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Fonctionnalité Ne pas déranger dans boîte de dialogue volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Autoriser le contrôle de la fonctionnalité Ne pas déranger dans la boîte de dialogue de modification du volume"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume et fonctionnalité Ne pas déranger"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Activer fonctionnalité Ne pas déranger avec bouton Volume -"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Raccourcis clavier"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Changer de méthode d\'entrée"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navigateur"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Courriel"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musique"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Désactiver fonctionnalité Ne pas déranger avec bouton Volume +"</string>
     <string name="battery" msgid="7498329822413202973">"Pile"</string>
     <string name="clock" msgid="7416090374234785905">"Horloge"</string>
     <string name="headset" msgid="4534219457597457353">"Écouteurs"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Écouteurs connectés"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Écouteurs connectés"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activer ou désactiver l\'affichage des icônes dans la barre d\'état"</string>
     <string name="data_saver" msgid="5037565123367048522">"Économiseur de données"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"La fonction Économiseur de données est activée"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"La fonction Économiseur de données est désactivée"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Activé"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Désactivé"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barre de navigation"</string>
     <string name="start" msgid="6873794757232879664">"Démarrer"</string>
     <string name="center" msgid="4327473927066010960">"Centrer"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Sélectionnez la touche du clavier"</string>
     <string name="preview" msgid="9077832302472282938">"Aperçu"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Faites glisser des tuiles ici pour les ajouter"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Faites glisser les tuiles ici pour les supprimer"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Heure"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Afficher les heures, les minutes et les secondes"</item>
+    <item msgid="1427801730816895300">"Afficher les heures et les minutes (par défaut)"</item>
+    <item msgid="3830170141562534721">"Ne pas afficher cette icône"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Toujours afficher le pourcentage"</item>
+    <item msgid="2139628951880142927">"Montrer le pourcentage durant la charge (par défaut)"</item>
+    <item msgid="3327323682209964956">"Ne pas afficher cette icône"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Autre"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Il est possible que l\'application ne fonctionne pas en mode Multi-fenêtre."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Touchez deux fois pour modifier."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Touchez deux fois pour ajouter."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position : <xliff:g id="POSITION">%1$d</xliff:g>. Touchez deux fois pour sélectionner."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Déplacer <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Supprimer <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été ajouté à la position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été supprimé"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été déplacé à la position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Éditeur de paramètres rapides."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
new file mode 100644
index 0000000..597a588
--- /dev/null
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Fermer mode IDI"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Plein écran"</string>
+    <string name="pip_play" msgid="674145557658227044">"Lecture"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Interrompre"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Maint. enf. "<b>"ACC."</b>" pr gér. mode IDI"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Maintenez enfoncé le bouton ACCUEIL pour gérer le mode IDI."</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Fermer"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 241d34c..2f99b94 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Capture d\'écran imposs., car espace stockage limité, ou appli ou entreprise ne vous y autorise pas."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Erreur lors de l\'enregistrement de la capture d\'écran."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Impossible d\'enregistrer la capture d\'écran, car l\'espace de stockage est limité."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Les captures d\'écran ne sont pas autorisées par l\'application ou par votre organisation."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Installer en tant que lecteur multimédia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Installer en tant qu\'appareil photo (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> : <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampe de poche indisponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mode Travail activé"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Le mode Travail est désactivé."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Le mode Travail est activé."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"L\'économiseur de données est désactivé."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"L\'économiseur de données est activé."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'affichage"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G-3G désactivées"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> autres"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Paramètres de notification"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Paramètres de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> au maximum"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Vos écrans récents s\'affichent ici"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Infos application"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historique"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Effacer"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"L\'application <xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tout effacer"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Application incompatible avec le mode multifenêtre."</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Application incompatible avec le mode multifenêtre"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Aucune\ninterruption"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Toujours"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Toutes\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activer accélérateur écran partagé en balayant vers le haut"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer l\'écran partagé en balayant vers le haut"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton \"Aperçu\""</string>
     <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Appliquer aux notifications relatives au sujet \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Appliquer à toutes les notifications de cette application"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Afficher les notifications en mode silencieux"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquer toutes les notifications"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne pas activer le mode silencieux"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne pas activer le mode silencieux ni bloquer"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afficher les paramètres d\'importance complets"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloquées"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importance minimale"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgent"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Afficher au bas de la liste des notifications en mode silencieux"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Afficher au bas de la liste des notifications en mode silencieux"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Afficher ces notifications en mode silencieux"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Autoriser ces notifications à émettre des sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatique"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Couleurs inconnues"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modification des couleurs"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afficher la tuile de configuration rapide"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Activer la transformation personnalisée"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Mode Nuit"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrer l\'affichage"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Activé"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Désactivé"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Activer automatiquement"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Passer en mode Nuit en fonction de la position et de l\'heure de la journée"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Lorsque le mode Nuit est activé"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Utiliser thème foncé pour plate-forme Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajuster la coloration"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Régler la luminosité"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Le thème foncé est appliqué à des zones essentielles de la plate-forme Android qui sont habituellement affichées dans un thème clair, telles que les paramètres."</string>
     <string name="color_apply" msgid="9212602012641034283">"Appliquer"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Vérifier les paramètres"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Certains paramètres de couleurs peuvent rendre cet appareil inutilisable. Cliquez sur \"OK\" pour valider ces paramètres, sans quoi ils seront réinitialisés après 10 secondes."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Utilisation batterie"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"L\'économiseur de batterie n\'est pas disponible lorsque l\'appareil est en charge."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Économiseur de batterie"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Limite les performances et les données en arrière-plan."</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Accueil"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Précédent"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Vers le haut"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Vers le bas"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vers la gauche"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Vers la droite"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulation"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Espace"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Entrée"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retour arrière"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Lire ou suspendre la lecture"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Arrêter"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Suivant"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Précédent"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retour arrière"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rapide"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page précédente"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page suivante"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supprimer"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Accueil"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insérer"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Verr Num"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Pavé numérique <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Système"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Fonctionnalité Ne pas déranger dans boîte de dialogue volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Autoriser le contrôle de la fonctionnalité Ne pas déranger dans la boîte de dialogue de modification du volume"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume et fonctionnalité Ne pas déranger"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Activer fonctionnalité Ne pas déranger via le bouton Volume -"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Raccourcis clavier"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Changer le mode de saisie"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navigateur"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Messagerie"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Messagerie instantanée"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musique"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Désactiver fonctionnalité Ne pas déranger via bouton Volume +"</string>
     <string name="battery" msgid="7498329822413202973">"Batterie"</string>
     <string name="clock" msgid="7416090374234785905">"Horloge"</string>
     <string name="headset" msgid="4534219457597457353">"Casque"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Casque connecté"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Casque connecté"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activer ou désactiver l\'affichage des icônes dans la barre d\'état"</string>
     <string name="data_saver" msgid="5037565123367048522">"Économiseur de données"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"L\'économiseur de données est activé."</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"L\'économiseur de données est désactivé."</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Activé"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Désactivé"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barre de navigation"</string>
     <string name="start" msgid="6873794757232879664">"Début"</string>
     <string name="center" msgid="4327473927066010960">"Centre"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Sélectionner la touche du clavier"</string>
     <string name="preview" msgid="9077832302472282938">"Aperçu"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Faites glisser des tuiles ici pour les ajouter"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Faites glisser les tuiles ici pour les supprimer."</string>
     <string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Heure"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Afficher les heures, les minutes et les secondes"</item>
+    <item msgid="1427801730816895300">"Afficher les heures et les minutes (option par défaut)"</item>
+    <item msgid="3830170141562534721">"Ne plus afficher cette icône"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Toujours afficher le pourcentage"</item>
+    <item msgid="2139628951880142927">"Afficher le pourcentage lorsque l\'appareil est en charge (option par défaut)"</item>
+    <item msgid="3327323682209964956">"Ne plus afficher cette icône"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Autre"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Il est possible que l\'application ne fonctionne pas en mode multifenêtre."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, \"<xliff:g id="TILE_NAME">%2$s</xliff:g>\". Appuyer deux fois pour modifier."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Appuyer deux fois pour ajouter."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Appuyer deux fois pour sélectionner."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Déplacer \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Supprimer \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été ajouté à la position <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été supprimé."</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été déplacé à la position <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Éditeur de configuration rapide."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
new file mode 100644
index 0000000..0478eea
--- /dev/null
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Fermer mode PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Plein écran"</string>
+    <string name="pip_play" msgid="674145557658227044">"Lire"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Suspendre"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Appui long "<b>"ACCUEIL"</b>" pour contrôler PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Appuyez de manière prolongée sur le bouton ACCUEIL pour contrôler le mode PIP."</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorer"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 75e47a5..45c3626 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de pantalla gardada."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver a captura de pantalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Non se puido facer a captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Non se pode realizar a captura de pantalla porque o espazo de almacenamento está limitado ou porque non o admite a aplicación ou a túa empresa."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Produciuse un problema ao gardar a captura de pantalla."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Non se pode gardar a captura de pantalla porque o espazo de almacenamento é limitado."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"A aplicación ou a túa organización non permite realizar capturas de pantalla."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcións de transferencia USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Inserir como reprodutor multimedia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Inserir como cámara (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rexeitar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Rexeitouse <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Rexeitáronse todas as aplicacións recentes."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación rexeitada"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Máis tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desactivada."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"A lanterna non está dispoñible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna activada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Desactivouse a lanterna."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Activouse a lanterna."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de traballo activado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Desactivouse o modo de traballo."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Activouse o modo de traballo."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Desactivouse o Economizador de datos."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Activouse o Economizador de datos."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os datos 2G-3G están en pausa"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Localización establecida polo GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de localización activas"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas as notificacións."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configuración das notificacións"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configuración de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A pantalla xirará automaticamente."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de traballo"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"As túas pantallas recentes aparecen aquí"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Non hai elementos recentes"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Borraches todo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información da aplicación"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixación de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"A aplicación <xliff:g id="APP">%s</xliff:g> está desactivada no modo seguro"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Borrar todo"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicación non é compatible con varias ventás"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"A aplicación non é compatible con varias ventás"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dividir en horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dividir en vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dividir de xeito personalizado"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silencio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Só\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Só\nalarmas"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Todas"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápido (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lento (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activar acelerador de pant. div. pasando o dedo cara arriba"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activar pantalla dividida pasando o dedo cara arriba"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa o xesto de pasar o dedo cara arriba desde o botón Visión xeral para acceder ao modo de pantalla dividida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado co tablet, primeiro tes que activar o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar ás notificacións de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificacións procedentes desta aplicación"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificacións de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificacións"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Non silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Non silenciar nin bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar a configuración completa da importancia"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importancia baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importancia urxente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrar nunca estas notificacións"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificacións de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificacións e emitir son"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar na pantalla e emitir son"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificacións de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que esta notificación emita son"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar na pantalla e permitir que emita son"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificacións, amosar na pantalla e permitir que emita son"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
     <string name="notification_done" msgid="5279426047273930175">"Feito"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Cores nocturnas"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automático"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores descoñecidas"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificación de cor"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar mosaico de configuración rápida"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Activar transformación personalizada"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controis de notificacións de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspecto"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Activado"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Desactivado"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Activar automaticamente"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Cambia ao modo nocturno segundo proceda para a localización e a hora do día"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Cando o modo nocturno está activado"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Usar tema escuro para SO Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Axustar ton"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Axustar brillo"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro aplícase ás áreas principais do SO Android que se mostran normalmente nun tema claro, como a configuración."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configuración"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algunhas opcións de configuración de cor poden facer que este dispositivo sexa inutilizable. Fai clic en Aceptar para confirmar esta configuración de cor; en caso contrario, a configuración restablecerase tras 10 segundos."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Uso de batería"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"A función aforro de batería non está dispoñible durante a carga"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Aforro de batería"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce o rendemento e os datos en segundo plano"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Volver"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Arriba"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Abaixo"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Esquerda"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Dereita"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centro"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulador"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Espazo"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Intro"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retroceso"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproducir/Pausar"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Deter"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seguinte"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rebobinar"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rápido"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Páx"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Páx"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supr"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inicio"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Inserir"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueo numérico"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Volver"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar o modo Non molestar no cadro de diálogo de volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permite o control completo do modo Non molestar no cadro de diálogo de volume."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e modo Non molestar"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Activar o modo Non molestar ao baixar o volume"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificacións"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atallos de teclado"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar de método de entrada"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicacións"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistente"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar cos controis de volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non molestar"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Atallo dos botóns de volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Desactivar o modo Non molestar ao subir o volume"</string>
     <string name="battery" msgid="7498329822413202973">"Batería"</string>
     <string name="clock" msgid="7416090374234785905">"Reloxo"</string>
     <string name="headset" msgid="4534219457597457353">"Auriculares"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Conectáronse os auriculares"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Conectáronse os auriculares"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activa ou desactiva a visualización das iconas na barra de estado."</string>
     <string name="data_saver" msgid="5037565123367048522">"Economizador de datos"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"O economizador de datos está activado"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"O economizador de datos está desactivado"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Activar"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desactivar"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
     <string name="start" msgid="6873794757232879664">"Inicio"</string>
     <string name="center" msgid="4327473927066010960">"Centro"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Selecciona o botón do teclado"</string>
     <string name="preview" msgid="9077832302472282938">"Vista previa"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastrar para engadir mosaicos"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra o elemento ata aquí para eliminalo"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+    <item msgid="1427801730816895300">"Mostrar horas e minutos (predeterminado)"</item>
+    <item msgid="3830170141562534721">"Non mostrar esta icona"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Mostrar sempre porcentaxe"</item>
+    <item msgid="2139628951880142927">"Mostrar porcentaxe durante a carga (predeterminado)"</item>
+    <item msgid="3327323682209964956">"Non mostrar esta icona"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Outros"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Baixar"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover á esquerda"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover á dereita"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Pode que a aplicación non funcione con varias ventás."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toca dúas veces o elemento para editalo."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toca dúas veces o elemento para engadilo"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Toca dúas veces o elemento para seleccionalo."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Elimina <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> engadiuse á posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Eliminouse <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moveuse á posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configuración rápida."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings_tv.xml b/packages/SystemUI/res/values-gl-rES/strings_tv.xml
new file mode 100644
index 0000000..d43d8cc
--- /dev/null
+++ b/packages/SystemUI/res/values-gl-rES/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Pechar PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reproducir"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausar"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Manter premido "<b>"INICIO"</b>" para controlar PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Mantén premido o botón de INICIO para controlar PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"De acordo"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorar"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 45a4eaf..ef6a49c 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"મર્યાદિત સંગ્રહ સ્થાનને કારણે સ્ક્રીનશોટ લઈ શકાતો નથી અથવા એપ્લિકેશન અથવા તમારા સંગઠન દ્વારા તેની મંજૂરી નથી."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"સ્ક્રીનશૉટ સાચવવામાં સમસ્યા આવી."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"મર્યાદિત સંગ્રહ સ્થાનને કારણે સ્ક્રીનશોટ સાચવી શકાતો નથી."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ઍપ્લિકેશન કે તમારી સંસ્થા દ્વારા સ્ક્રીનશોટ્સ લેવાની મંજૂરી નથી."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ફાઇલ ટ્રાન્સફર વિકલ્પો"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"મીડિયા પ્લેયર તરીકે માઉન્ટ કરો (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"કૅમેરા તરીકે માઉન્ટ કરો (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખો."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખી."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"તમામ તાજેતરની એપ્લિકેશનો કાઢી નાખી."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી રહ્યું છે."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"સૂચના કાઢી નાખી."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"વધુ સમય."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ઓછો સમય."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ફ્લેશલાઇટ બંધ."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ફ્લેશલાઇટ અનુપલબ્ધ."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ફ્લેશલાઇટ ચાલુ."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ફ્લેશલાઇટ બંધ કરી."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ફ્લેશલાઇટ ચાલુ કરી."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"કાર્ય મોડ ચાલુ."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"કાર્ય મોડ બંધ કર્યો."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"કાર્ય મોડ ચાલુ કર્યો."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ડેટા સેવર બંધ કર્યું."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ડેટા સેવર ચાલુ કર્યું."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"પ્રદર્શન તેજ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ડેટા થોભાવ્યો છે"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ડેટા થોભાવ્યો છે"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS દ્વારા સ્થાન સેટ કરાયું"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"સ્થાન વિનંતીઓ સક્રિય"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"બધા સૂચનો સાફ કરો."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"સૂચનાઓની સેટિંગ્સ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> સેટિંગ્સ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"સ્ક્રીન આપમેળે ફરશે."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> મર્યાદા"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"કાર્ય મોડ"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"તમારી તાજેતરની સ્ક્રીન્સ અહીં દેખાય છે"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"કોઇ તાજેતરની આઇટમ્સ નથી"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"તમે બધું સાફ કર્યું"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"એપ્લિકેશન માહિતી"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"સ્ક્રીન પિનિંગ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"શોધ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી શકાયું નથી."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ઇતિહાસ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"સાફ કરો"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"સુરક્ષિત મોડમાં <xliff:g id="APP">%s</xliff:g> અક્ષમ કરેલ છે."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"બધું સાફ કરો"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"આ ઍપ્લિકેશન મલ્ટિ-વિંડોનું સમર્થન કરતી નથી"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ઍપ્લિકેશન મલ્ટિ-વિંડોનું સમર્થન કરતી નથી"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"આડું વિભક્ત કરો"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ઊભું વિભક્ત કરો"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"કસ્ટમ વિભક્ત કરો"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"સાવ\nશાંતિ"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ફક્ત\nપ્રાધાન્યતા"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ફક્ત\nએલાર્મ્સ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"તમામ"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"બધી\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ચાર્જ થઈ રહ્યું છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ઝડપથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ધીમેથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"સ્પ્લિટ-સ્ક્રીન સ્વાઇપ-અપ ઍક્સલરેટર સક્ષમ કરો"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"સ્પ્લિટ-સ્ક્રીન સ્વાઇપ-અપ હાવભાવ સક્ષમ કરો"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"વિહંગાવલોકન બટનમાંથી સ્વાઇપ કરીને સ્પ્લિટ-સ્ક્રીનમાં દાખલ થવા માટે હાવભાવ સક્ષમ કરો"</string>
     <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ચાલુ કરવુ છે?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં Bluetooth ચાલુ કરવાની જરૂર પડશે."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ચાલુ કરો"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> સૂચનાઓ પર લાગુ કરો"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"આ ઍપ્લિકેશનની તમામ સૂચનાઓ પર લાગુ કરો"</string>
+    <string name="show_silently" msgid="6841966539811264192">"સૂચનાઓ ચુપચાપ બતાવો"</string>
+    <string name="block" msgid="2734508760962682611">"તમામ સૂચનાઓને અવરોધિત કરો"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ચુપ કરશો નહીં"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ચુપ કે અવરોધિત કરશો નહીં"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"પૂર્ણ મહત્વ સેટિંગ્સ બતાવો"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"અવરોધિત"</string>
+    <string name="min_importance" msgid="1901894910809414782">"ન્યૂનતમ મહત્વ"</string>
     <string name="low_importance" msgid="4109929986107147930">"નિમ્ન મહત્વની"</string>
     <string name="default_importance" msgid="8192107689995742653">"સામાન્ય મહત્વની"</string>
     <string name="high_importance" msgid="1527066195614050263">"ઉચ્ચ મહત્વની"</string>
     <string name="max_importance" msgid="5089005872719563894">"તાત્કાલિક મહત્વની"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"આ સૂચનાઓ ક્યારેય બતાવશો નહીં"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"આ સૂચનાઓ ચુપચાપ બતાવો"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"સૂચનાઓની સૂચિની ટોચ પર બતાવો અને અવાજ કરો"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજ કરો"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"આ સૂચનાઓ ચુપચાપ બતાવો"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"આ સૂચનાને અવાજ કરવાની મંજૂરી આપો"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજને મંજૂરી આપો"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"સૂચનાઓની સૂચિની ટોચ પર બતાવો, સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજને મંજૂરી આપો"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
     <string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"સામાન્ય રંગો"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"રાત્રિ રંગો"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"કસ્ટમ રંગો"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"સ્વતઃ"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"અજાણ્યા રંગો"</string>
-    <string name="color_transform" msgid="6985460408079086090">"રંગ સંશોધન"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"ઝડપી સેટિંગ્સ ટાઇલ બતાવો"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"કસ્ટમ રૂપાંતરણને સક્ષમ કરો"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> સૂચના નિયંત્રણો"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"રંગ અને દેખાવ"</string>
+    <string name="night_mode" msgid="3540405868248625488">"રાત્રિ મોડ"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"પ્રદર્શન કૅલિબ્રેટ કરો"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ચાલુ"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"બંધ"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"આપમેળે ચાલુ કરો"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"સ્થાન અને દિવસના સમય માટે યોગ્ય હોય તે રાત્રિ મોડ પર સ્વિચ કરો"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"જ્યારે રાત્રિ મોડ ચાલુ હોય"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS માટે ઘાટી થીમનો ઉપયોગ કરો"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ટિંટ સમાયોજિત કરો"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"તેજ સમાયોજિત કરો"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ઘાટી થીમને Android OS ના મુખ્ય ક્ષેત્રો પર લાગુ કરે છે જે સામાન્ય રીતે સેટિંગ્સ જેવી લાઇટ થીમમાં પ્રદર્શિત કરવામાં આવે છે."</string>
     <string name="color_apply" msgid="9212602012641034283">"લાગુ કરો"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"સેટિંગ્સની પુષ્ટિ કરો"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"કેટલીક રંગ સેટિંગ્સ આ ઉપકરણને બિનઉપયોગી બનાવી શકે છે. આ રંગ સેટિંગ્સની પુષ્ટિ કરવા માટે ઑકે ક્લિક કરો, અન્યથા 10 સેકંડ પછી આ સેટિંગ્સ ફરીથી સેટ થશે."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"બૅટરી વપરાશ"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ચાર્જિંગ દરમિયાન બૅટરી બચતકર્તા ઉપલબ્ધ નથી"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"બૅટરી બચતકર્તા"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"પ્રદર્શન અને પૃષ્ઠભૂમિ ડેટા ઘટાડે છે"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"બટન <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"સિસ્ટમ"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"હોમ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"તાજેતરના"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"પાછળ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"વૉલ્યૂમમાં ખલેલ પાડશો નહીં બતાવો"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"વૉલ્યૂમ સંવાદમાં ખલેલ પાડશો નહીંના સંપૂર્ણ નિયંત્રણની મંજૂરી આપો."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"વૉલ્યૂમ અને ખલેલ પાડશો નહીં"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"વૉલ્યૂમ ઘટાડવા પર ખલેલ પાડશો નહીંમાં દાખલ થાઓ"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"સૂચનાઓ"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"કીબોર્ડ શૉર્ટકટ્સ"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ઇનપુટ પદ્ધતિ સ્વિચ કરો"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ઍપ્લિકેશનો"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"સહાય"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"બ્રાઉઝર"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"સંપર્કો"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ઇમેઇલ"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"સંગીત"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"કૅલેન્ડર"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"વૉલ્યૂમ નિયંત્રણ સાથે બતાવો"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ખલેલ પાડશો નહીં"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"વૉલ્યૂમ બટન્સ શૉર્ટકટ"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"વૉલ્યૂમ વધારવા પર ખલેલ પાડશો નહીંમાંથી બહાર નિકળો"</string>
     <string name="battery" msgid="7498329822413202973">"બૅટરી"</string>
     <string name="clock" msgid="7416090374234785905">"ઘડિયાળ"</string>
     <string name="headset" msgid="4534219457597457353">"હેડસેટ"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"હેડફોન કનેક્ટ કર્યાં"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"હેડસેટ કનેક્ટ કર્યો"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"સ્થિતિ બારમાં બતાવવામાં આવતા આઇકન્સને સક્ષમ અથવા અક્ષમ કરો."</string>
     <string name="data_saver" msgid="5037565123367048522">"ડેટા સેવર"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ડેટા સેવર ચાલુ છે"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ડેટા સેવર બંધ છે"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ચાલુ"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"બંધ"</string>
     <string name="nav_bar" msgid="1993221402773877607">"નેવિગેશન બાર"</string>
     <string name="start" msgid="6873794757232879664">"પ્રારંભ કરો"</string>
     <string name="center" msgid="4327473927066010960">"મધ્ય"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"કીબોર્ડ બટન પસંદ કરો"</string>
     <string name="preview" msgid="9077832302472282938">"પૂર્વાવલોકન કરો"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ટાઇલ્સ ઉમેરવા માટે ખેંચો"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"દૂર કરવા માટે અહીં ખેંચો"</string>
     <string name="qs_edit" msgid="2232596095725105230">"સંપાદિત કરો"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"સમય"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"કલાક, મિનિટ અને સેકંડ બતાવો"</item>
+    <item msgid="1427801730816895300">"કલાક અને મિનિટ બતાવો (ડિફોલ્ટ)"</item>
+    <item msgid="3830170141562534721">"આ આઇકન બતાવશો નહીં"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"હંમેશાં ટકાવારી બતાવો"</item>
+    <item msgid="2139628951880142927">"ચાર્જ થાય ત્યારે ટકાવારી બતાવો (ડિફોલ્ટ)"</item>
+    <item msgid="3327323682209964956">"આ આઇકન બતાવશો નહીં"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"અન્ય"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"સ્પ્લિટ-સ્ક્રીન વિભાજક"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"નીચે ખસેડો"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ઉપર ખસેડો"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ડાબે ખસેડો"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"જમણે ખસેડો"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"બહુ-વિંડો સાથે અ‍ૅપ્લિકેશન કદાચ કામ ન કરે"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"સ્થિતિ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. સંપાદિત કરવા માટે બે વાર ટૅપ કરો."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ઉમેરવા માટે બે વાર ટૅપ કરો."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"સ્થિતિ <xliff:g id="POSITION">%1$d</xliff:g>. પસંદ કરવા માટે બે વાર ટૅપ કરો."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ખસેડો"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> દૂર કરો"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> સ્થિતિ પર <xliff:g id="TILE_NAME">%1$s</xliff:g> ઉમેર્યું છે"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> દૂર કરવામાં આવ્યું છે"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ને <xliff:g id="POSITION">%2$d</xliff:g> સ્થિતિ પર ખસેડ્યું"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ઝડપી સેટિંગ્સ સંપાદક."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings_tv.xml b/packages/SystemUI/res/values-gu-rIN/strings_tv.xml
new file mode 100644
index 0000000..878e91f
--- /dev/null
+++ b/packages/SystemUI/res/values-gu-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP બંધ કરો"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"પૂર્ણ સ્ક્રીન"</string>
+    <string name="pip_play" msgid="674145557658227044">"ચલાવો"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"થોભાવો"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP નિયંત્રિત કરવા માટે "<b>"હોમ"</b>" પકડી રાખો"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP નિયંત્રિત કરવા માટે હોમ બટન દબાવો અને પકડી રાખો"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"સમજાઈ ગયું"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"છોડી દો"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 7349827..1ba0caf 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"सीमित मेमोरी स्थान के कारण स्क्रीनशॉट नहीं ले सकते, या ऐप्स या आपके संगठन द्वारा ऐसा अनुमत नहीं है."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"स्क्रीनशॉट सहेजने में समस्या आई"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"सीमित मेमोरी स्थान के कारण स्क्रीनशॉट सहेजा नहीं जा सकता."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"आपके ऐप्लिकेशन या आपके संगठन द्वारा स्क्रीनशॉट लेने की अनुमति नहीं है."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB फ़ाइल स्थानांतरण विकल्प"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेयर के रूप में माउंट करें (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"कैमरे के रूप में माउंट करें (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> को ख़ारिज करें."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खा़रिज कर दिया गया."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"हाल ही के सभी ऐप्लिकेशन ख़ारिज कर दिए गए."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ हो रहा है."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"नोटिफिकेशन खारिज की गई."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"अधिक समय."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कम समय."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"फ़्लैशलाइट बंद है."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"फ़्लैशलाइट उपलब्ध नहीं है."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"फ़्लैशलाइट चालू है."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"फ़्लैशलाइट को बंद किया गया."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"फ़्लैशलाइट को चालू किया गया."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"कार्य मोड चालू है."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"कार्य मोड बंद कर दिया गया."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"कार्य मोड चालू किया गया."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"डेटा बचतकर्ता बंद किया गया."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"डेटा बचतकर्ता चालू किया गया."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"स्क्रीन की स्क्रीन की रोशनी"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटा रोक दिया गया है"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा सेट किया गया स्‍थान"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोध सक्रिय"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"सभी सूचनाएं साफ़ करें."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"नोटिफिकेशन सेटिंग"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिंग"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्‍क्रीन स्‍वचालित रूप से घूमेगी."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"आपकी हाल की स्‍क्रीन यहां दिखाई देती हैं"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"हाल ही का कोई आइटम नहीं"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपने सब कुछ साफ़ कर दिया है"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्‍लिकेशन जानकारी"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रीन पिन करना"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ नहीं किया जा सका."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> को सुरक्षित-मोड में अक्षम किया गया."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"साफ़ करें"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"यह ऐप्लिकेशन एकाधिक विंडो का समर्थन नहीं करता है"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ऐप्लिकेशन एकाधिक विंडो का समर्थन नहीं करता है"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"लम्बवत रूप से विभाजित करें"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"कस्‍टम रूप से विभाजित करें"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"पूरी तरह\nशांत"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवल\nप्राथमिकता"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवल\nअलार्म"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"सभी"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"सभी\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूरा होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> बाकी)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"तेज़ी से चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में हो जाएगा)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"धीरे चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में पूरा हो जाएगा)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
     <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ऊपर स्वाइप करके स्क्रीन विभाजन की त्वरित सुविधा सक्षम करें"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ऊपर स्वाइप करके विभाजित स्क्रीन में जाने का जेस्चर सक्षम करें"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"अवलोकन बटन से ऊपर स्वाइप करके स्क्रीन विभाजन में आने का हावभाव सक्षम करें"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"अपने कीबोर्ड को अपने टैबलेट से कनेक्ट करने के लिए, आपको पहले ब्लूटूथ चालू करना होगा."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करें"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> नोटिफिकेशन पर लागू करें"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"इस ऐप के सभी नोटिफिकेशन पर लागू करें"</string>
+    <string name="show_silently" msgid="6841966539811264192">"नोटिफिकेशन मौन रूप से दिखाएं"</string>
+    <string name="block" msgid="2734508760962682611">"सभी नोटिफिकेशन अवरुद्ध करें"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"मौन ना करें"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"मौन या अवरुद्ध ना करें"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्व वाली सेटिंग दिखाएं"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"अवरोधित"</string>
+    <string name="min_importance" msgid="1901894910809414782">"न्यूनतम महत्व"</string>
     <string name="low_importance" msgid="4109929986107147930">"निम्न महत्व"</string>
     <string name="default_importance" msgid="8192107689995742653">"सामान्य महत्व"</string>
     <string name="high_importance" msgid="1527066195614050263">"उच्च महत्व"</string>
     <string name="max_importance" msgid="5089005872719563894">"तत्काल महत्व"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ये नोटिफिकेशन कभी ना दिखाएं"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"नोटिफिकेशन सूची में सबसे नीचे मौन रूप से दिखाएं"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"नोटिफिकेशन सूची में सबसे ऊपर दिखाएं और ध्वनि चलाएं"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"स्‍क्रीन पर एक झलक दिखाएं और ध्‍वनि चलाएं"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"नोटिफिकेशन सूची में सबसे नीचे मौन रूप से दिखाएं"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"इन नोटिफिकेशन को ध्वनि करने दें"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"स्क्रीन पर झलक दिखाएं और ध्वनि करें"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"नोटिफिकेशन सूची के शीर्ष पर दिखाएं, स्क्रीन पर झलक दिखाएं और ध्वनि करें"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"और सेटिंग"</string>
     <string name="notification_done" msgid="5279426047273930175">"हो गया"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"रात्रि के रंग"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"कस्टम रंग"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"स्वतः"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रंग"</string>
-    <string name="color_transform" msgid="6985460408079086090">"रंग परिवर्तन"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"त्‍वरित-सेटिंग टाइल दिखाएं"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"कस्टम रूपांतरण सक्षम करें"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> नोटिफ़िकेशन नियंत्रण"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"रंग और दिखावट"</string>
+    <string name="night_mode" msgid="3540405868248625488">"रात्रि मोड"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"स्क्रीन को कैलिब्रेट करें"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"चालू"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"बंद"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"अपने आप चालू करें"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"स्थान और दिन के समय के लिए उपयुक्त रात्रि मोड में बदलें"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"रात्रि मोड के चालू होने पर"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS के लिए गहरी थीम का उपयोग करें"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"टिंट समायोजित करें"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"स्क्रीन की रोशनी समायोजित करें"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"गहरी थीम को Android OS के मुख्य क्षेत्रों पर लागू किया जाता है जिन्हें सामान्यतः सेटिंग जैसी हल्की थीम में प्रदर्शित किया जाता है."</string>
     <string name="color_apply" msgid="9212602012641034283">"लागू करें"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"से‍ेटिंग की पुष्टि करें"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"कुछ रंग सेटिंग इस डिवाइस को अनुपयोगी बना सकती हैं. इन रंग सेटिंग की पुष्टि करने के लिए ठीक क्लिक करें, अन्यथा 10 सेकंड के बाद ये सेटिंग रीसेट हो जाएंगी."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज किए जाने के दौरान बैटरी सेवर उपलब्ध नहीं है"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"बैटरी सेवर"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"निष्‍पादन और पृष्ठभूमि डेटा को कम करता है"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"बटन <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ऊपर तीर"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"नीचे तीर"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"बायां तीर"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"दायां तीर"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"मध्य तीर"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"सिस्टम"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"होम"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हाल ही के"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"वापस जाएं"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"वॉल्यूम में परेशान न करें दिखाएं"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"वॉल्यूम संवाद में परेशान न करें के पूर्ण नियंत्रण की अनुमति दें."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"वॉल्यूम और परेशान न करें"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"वॉल्यूम कम करें पर परेशान न करें डालें"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"नोटिफ़िकेशन"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"कीबोर्ड शॉर्टकट"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट पद्धति‍ बदलें"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ऐप्लिकेशन"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहायक"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउज़र"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"संपर्क"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ईमेल"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"कैलेंडर"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"वॉल्यूम नियंत्रणों के साथ दिखाएं"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"परेशान न करें"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"वॉल्यूम बटन का शॉर्टकट"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"वॉल्यूम बढ़ाएं पर परेशान न करें से बाहर निकलें"</string>
     <string name="battery" msgid="7498329822413202973">"बैटरी"</string>
     <string name="clock" msgid="7416090374234785905">"घड़ी"</string>
     <string name="headset" msgid="4534219457597457353">"हैडसेट"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"हेडफ़ोन कनेक्‍ट किए गए"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"हैडसेट कनेक्‍ट किया गया"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"आइकन को स्‍थिति बार में दिखाए जाने से सक्षम या अक्षम करें."</string>
     <string name="data_saver" msgid="5037565123367048522">"डेटा बचतकर्ता"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा बचतकर्ता चालू है"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा बचतकर्ता बंद है"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"चालू"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"बंद"</string>
     <string name="nav_bar" msgid="1993221402773877607">"नेविगेशन बार"</string>
     <string name="start" msgid="6873794757232879664">"प्रारंभ करें"</string>
     <string name="center" msgid="4327473927066010960">"मध्‍य"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटन चुनें"</string>
     <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलों को जोड़ने के लिए खींचें"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"निकालने के लिए यहां खींचें"</string>
     <string name="qs_edit" msgid="2232596095725105230">"संपादित करें"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"समय"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"घंटे, मिनट और सेकंड दिखाएं"</item>
+    <item msgid="1427801730816895300">"घंटे और मिनट दिखाएं (डिफ़ॉल्ट)"</item>
+    <item msgid="3830170141562534721">"यह आइकन ना दिखाएं"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"हमेशा प्रतिशत दिखाएं"</item>
+    <item msgid="2139628951880142927">"चार्ज होते समय प्रतिशत दिखाएं (डिफ़ॉल्ट)"</item>
+    <item msgid="3327323682209964956">"यह आइकन ना दिखाएं"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"अन्य"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित स्क्रीन विभाजक"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"नीचे ले जाएं"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ऊपर ले जाएं"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाएं ले जाएं"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दाएं ले जाएं"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"हो सकता है कि ऐप्लिकेशन एकाधिक विंडो के साथ काम ना करे"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. संपादित करने के लिए डबल टैप करें."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. जोड़ने के लिए डबल टैप करें."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>. चुनने के लिए डबल टैप करें."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को ले जाएं"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> निकालें"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को <xliff:g id="POSITION">%2$d</xliff:g> स्थिति में जोड़ा गया"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> निकाल दिया गया है"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को <xliff:g id="POSITION">%2$d</xliff:g> स्थिति में ले जाया गया"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"त्वरित सेटिंग संपादक."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
new file mode 100644
index 0000000..0b4f3e5
--- /dev/null
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP बंद करें"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्‍क्रीन"</string>
+    <string name="pip_play" msgid="674145557658227044">"चलाएं"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"रोकें"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP नियंत्रण हेतु "<b>"HOME"</b>" होल्ड करें"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP नियंत्रण के लिए HOME बटन को दबाए रखें"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"समझ लिया"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"ख़ारिज करें"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 06721174..81c6276 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -74,7 +74,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Zaslon je snimljen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite za prikaz snimke zaslona."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nije bilo moguće snimiti zaslon."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Zaslon nije snimljen zbog ograničene pohrane ili zato što to ne dopušta aplikacija ili vaša organizacija."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Prilikom spremanja snimke zaslona pojavio se problem."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Zaslon nije snimljen zbog ograničenog prostora za pohranu."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Snimanje zaslona ne dopušta aplikacija ili vaša organizacija."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa datoteka"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Učitaj kao media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Učitaj kao fotoaparat (PTP)"</string>
@@ -167,6 +169,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacivanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> odbačena je."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Odbačene su sve nedavne aplikacije."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavijest je odbačena."</string>
@@ -207,6 +211,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svjetiljka isključena."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svjetiljka nije dostupna."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svjetiljka uključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svjetiljka isključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svjetiljka uključena."</string>
@@ -219,6 +224,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Način rada uključen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Način rada isključen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Način rada uključen."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Ušteda podataka isključena."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Ušteda podataka uključena."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svjetlina zaslona"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G – 3G podaci pauzirani"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
@@ -232,6 +239,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju utvrdio GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Zahtjevi za lokaciju aktivni su"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Brisanje svih obavijesti."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"još <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Postavke obavijesti"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Postavke aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon će se automatski zakrenuti."</string>
@@ -297,15 +305,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način rada"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Ovdje se pojavljuju vaši nedavni zasloni"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Izbrisali ste sve"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"prikvačivanje zaslona"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Povijest"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Izbriši"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> onemogućena je u sigurnom načinu."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Izbriši sve"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacija ne podržava više prozora"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava više prozora"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podijeli vodoravno"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podijeli okomito"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podijeli prilagođeno"</string>
@@ -335,8 +344,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Potpuna\ntišina"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetno"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Sve"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Svi\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
@@ -449,34 +456,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogući ubrzanje za podijeljen zaslon povlačenjem prema gore"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret povlačenja prema gore za podijeljen zaslon"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućivanje pokreta za otvaranje podijeljenog zaslona tako da se od gumba Pregled prstom prijeđe prema gore"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li uključiti Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tipkovnicu s tabletom, morate uključiti Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Primijeni na obavijesti za temu <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Primijeni na sve obavijesti ove aplikacije"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Prikaži obavijesti tiho"</string>
+    <string name="block" msgid="2734508760962682611">"Blokiraj sve obavijesti"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne utišavaj"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne utišavaj i ne blokiraj"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži potpune postavke važnosti"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Najmanja važnost"</string>
     <string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
     <string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
     <string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
     <string name="max_importance" msgid="5089005872719563894">"Hitno"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikad ne prikazuj te obavijesti"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Prikaži tiho pri dnu popisa obavijesti"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži te obavijesti tiho"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu popisa obavijesti i emitiraj zvučni signal"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Prikaži na zaslonu i emitiraj zvučni signal"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Prikaži tiho pri dnu popisa obavijesti"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Prikaži te obavijesti tiho"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dopusti obavijestima da emitiraju zvučne signale"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Prikaži na zaslonu i dopusti zvuk"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Prikaži pri vrhu popisa obavijesti, prikaži na zaslonu i dopusti zvuk"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Uobičajene boje"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatski"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Nepoznate boje"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Izmjena boja"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaži pločicu s brzim postavkama"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Omogući prilagođenu preobrazbu"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Noćni način rada"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibriranje zaslona"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Uključeno"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Isključeno"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Uključi automatski"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Prebacivanje na noćni način rada prema lokaciji i dobu dana"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kada je noćni način rada uključen"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Koristi tamnu temu za OS Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Prilagodi nijansu"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Prilagodi svjetlinu"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tamna se tema primjenjuje na glavna područja OS-a Android, kao što su, primjerice, postavke, koja se inače prikazuju u svijetloj temi."</string>
     <string name="color_apply" msgid="9212602012641034283">"Primijeni"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Potvrdite postavke"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Neke postavke boja mogu učiniti uređaj neupotrebljivim. Kliknite U redu da biste potvrdili postavke boja jer će se u suprotnom poništiti za 10 sekundi."</string>
@@ -484,25 +501,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Štednja baterije nije dostupna tijekom punjenja"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Štednja baterije"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje količinu rada i pozadinske podatke"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tipka <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Početak"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Natrag"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gore"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dolje"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Lijevo"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Desno"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Sredina"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulator"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Razmaknica"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Unos"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Povratna tipka"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reprodukcija/pauza"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zaustavi"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Sljedeće"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prethodno"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Unatrag"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Brzo naprijed"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Stranica prema gore"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Stranica prema dolje"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Izbriši"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Početak"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Kraj"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Umetni"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Zaključavanje brojčane tipkovnice"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Brojčana tipkovnica <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sustav"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni zaslon"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Najnovije"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Natrag"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Prikaži \"Ne uznemiravaj\" u glasnoći"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Dopušta potpunu kontrolu nad načinom \"Ne uznemiravaj\" u dijaloškom okviru glasnoće."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Glasnoća i Ne uznemiravaj"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Pokreni \"Ne uznemiravaj\" kada je zvuk stišan"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obavijesti"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tipkovni prečaci"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promjena načina unosa"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoć"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Preglednik"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Izravna poruka"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Glazba"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolama glasnoće"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečac tipki za glasnoću"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Zaustavi \"Ne uznemiravaj\" kada je zvuk pojačan"</string>
     <string name="battery" msgid="7498329822413202973">"Baterija"</string>
     <string name="clock" msgid="7416090374234785905">"Sat"</string>
     <string name="headset" msgid="4534219457597457353">"Slušalice"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalice su povezane"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Slušalice su povezane"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Omogućuje ili onemogućuje prikazivanje ikona na traci statusa."</string>
     <string name="data_saver" msgid="5037565123367048522">"Ušteda podataka"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ušteda podataka je uključena"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ušteda podataka je isključena"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Uključeno"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Isključeno"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigacijska traka"</string>
     <string name="start" msgid="6873794757232879664">"Početak"</string>
     <string name="center" msgid="4327473927066010960">"Sredina"</string>
@@ -524,5 +578,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Odaberite gumb tipkovnice"</string>
     <string name="preview" msgid="9077832302472282938">"Pregled"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali pločice"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Povucite ovdje za uklanjanje"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Vrijeme"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Prikaži sate, minute i sekunde"</item>
+    <item msgid="1427801730816895300">"Prikaži sate i minute (zadano)"</item>
+    <item msgid="3830170141562534721">"Ne prikazuj tu ikonu"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Uvijek prikazuj postotak"</item>
+    <item msgid="2139628951880142927">"Prikazuj postotak tijekom punjenja (zadano)"</item>
+    <item msgid="3327323682209964956">"Ne prikazuj tu ikonu"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Ostalo"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Razdjelnik podijeljenog zaslona"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomakni prema dolje"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomakni prema gore"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomakni ulijevo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomakni udesno"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće funkcionirati uz više prozora"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dodirnite dvaput da biste uredili."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dodirnite dvaput da biste dodali."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>. Dodirnite dvaput da biste odabrali."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premjesti <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> dodana je na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> uklonjena"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> premještena je na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivač brzih postavki."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
new file mode 100644
index 0000000..340a613
--- /dev/null
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Zatvori PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Cijeli zaslon"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reproduciraj"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pauziraj"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Držite "<b>"POČETNI"</b>" za PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Pritisnite i zadržite tipku POČETNI ZASLON da biste upravljali slikom u slici"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Shvaćam"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 0dd5d45..b7ac8a4 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Képernyőkép rögzítve."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Megérintésével megtekintheti a képernyőképet."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nem sikerült rögzíteni a képernyőképet."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Nem készíthet képernyőképet, mert kevés a tárhely, vagy az alkalmazás/szervezet nem engedélyezi azt."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Hiba történt a képernyőkép mentése során."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nem menthet képernyőképet, mert kevés a tárhely."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Az alkalmazás vagy szervezete nem engedélyezi képernyőképek készítését."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-fájlátvitel beállításai"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Csatlakoztatás médialejátszóként (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Csatlakoztatás kameraként (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"A(z) <xliff:g id="APP">%s</xliff:g> elvetése."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eltávolítva."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Az összes alkalmazás eltávolítva a nemrég használtak közül."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A(z) <xliff:g id="APP">%s</xliff:g> indítása."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Értesítés elvetve."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Több idő."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kevesebb idő."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Vaku kikapcsolva."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"A zseblámpa nem áll rendelkezésre"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Vaku bekapcsolva."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Vaku kikapcsolva."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Vaku bekapcsolva."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Munka mód be."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Munka mód kikapcsolva."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Munka mód bekapcsolva."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Adatforgalom-csökkentő kikapcsolva."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Adatforgalom-csökkentő bekapcsolva."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"A kijelző fényereje"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"A 2G és 3G adatforgalom szünetel."</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"A GPS beállította a helyet"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktív helylekérések"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Minden értesítés törlése"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Értesítési beállítások"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> beállításai"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A képernyő automatikusan forogni fog."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> korlát"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Figyelem! <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Munka mód"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"A legutóbbi képernyők itt jelennek meg"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nincsenek mostanában használt elemek"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Mindent törölt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"képernyő rögzítése"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nem lehet elindítani a következőt: <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"A(z) <xliff:g id="APP">%s</xliff:g> csökkentett módban ki van kapcsolva."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Előzmények"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Törlés"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Összes törlése"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ez az alkalmazás nem támogatja a többablakos nézetet"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Az alkalmazás nem támogatja a többablakos nézetet"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Osztott vízszintes"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Osztott függőleges"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Osztott egyéni"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Teljes\nnémítás"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Csak\nprioritás"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Csak\nriasztások"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Összes"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Összes\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Gyors töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lassú töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Osztott képernyő engedélyezése felfelé söpréssel"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Képernyőfelosztó gyors felfelé csúsztatás engedélyezése"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Kézmozdulat engedélyezése osztott képernyős nézet aktiválásához, ha az Áttekintés gombról felfelé húzza az ujját"</string>
     <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Engedélyezi a Bluetooth-kapcsolatot?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ha a billentyűzetet csatlakoztatni szeretné táblagépéhez, először engedélyeznie kell a Bluetooth-kapcsolatot."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bekapcsolás"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"A következő értesítések esetén: <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Az alkalmazás minden értesítése esetén"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Értesítések megjelenítése hangjelzés nélkül"</string>
+    <string name="block" msgid="2734508760962682611">"Minden értesítés letiltása"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nincs némítás"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nincs némítás vagy letiltás"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"A teljes fontossági beállítások megjelenítése"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Letiltva"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimális fontosságú"</string>
     <string name="low_importance" msgid="4109929986107147930">"Kevésbé fontos"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normál"</string>
     <string name="high_importance" msgid="1527066195614050263">"Fontos"</string>
     <string name="max_importance" msgid="5089005872719563894">"Sürgős"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Soha nem jelennek meg ezek az értesítések"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Hangjelzés nélkül jelennek meg az értesítési lista alján"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Hang nélkül jelennek meg ezek az értesítések"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Az értesítési lista tetején jelennek meg hangjelzéssel"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Az értesítések felugranak a képernyőn hangjelzéssel"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Hangjelzés nélkül jelennek meg az értesítési lista alján"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ezek az értesítések hangjelzés nélkül jelennek meg"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Hangjelzés engedélyezése ezeknél az értesítéseknél"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Az értesítések felugranak a képernyőn hangjelzéssel"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Az értesítési lista tetején jelennek meg, illetve felugranak a képernyőn hangjelzéssel"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"További beállítások"</string>
     <string name="notification_done" msgid="5279426047273930175">"Kész"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Hagyományos színek"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Esti színek"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Egyéni színek"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatikus"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Ismeretlen színek"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Színmódosítás"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Gyorsbeállítások mozaikjának megjelenítése"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Egyéni átalakítás engedélyezése"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-értesítések vezérlői"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Szín és megjelenés"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Éjszakai mód"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kijelző kalibrálása"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Bekapcsolva"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Kikapcsolva"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Automatikus bekapcsolás"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Váltás az Éjszakai módra a helynek és napszaknak megfelelően"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Amikor be van kapcsolva az Éjszakai mód"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Sötét téma használata az Android operációs rendszernél"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Színárnyalat módosítása"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Fényerő módosítása"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Sötét téma látható az Android operációs rendszer olyan alapterületeinél, amelyek normál állapotban világosan jelennek meg (például a Beállítások)."</string>
     <string name="color_apply" msgid="9212602012641034283">"Alkalmaz"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Beállítások megerősítése"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Bizonyos színbeállítások használhatatlanná tehetik ezt az eszközt. A színbeállítás megerősítéséhez kattintson az OK lehetőségre, máskülönben a rendszer 10 másodpercen belül visszaáll a korábbira."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Az Akkumulátorkímélő módot töltés közben nem lehet használni"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akkumulátorkímélő mód"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> gomb"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Kezdőképernyő"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Vissza"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Fel"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Le"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Balra"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Jobbra"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Középre"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Szóköz"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Visszatörlés"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Lejátszás/szünet"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Leállítás"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Következő"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Előző"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Visszatekerés"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Gyors előretekerés"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Kezdőképernyő"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numerikus: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Rendszer"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Otthon"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Legutóbbiak"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Vissza"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"A „Ne zavarjanak” funkció megjelenítése a hangvezérlőben"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"A „Ne zavarjanak” funkció teljes körű vezérlésének engedélyezése a hangerővezérlési párbeszédpanelon."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hangvezérlő és „Ne zavarjanak” funkció"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"„Ne zavarjanak” aktiválása hangerőcsökkentéskor"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Értesítések"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Billentyűkódok"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Beviteli mód váltása"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Alkalmazások"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Segédalkalmazás"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Böngésző"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Névjegyek"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Azonnali üzenetküldés"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Zene"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Naptár"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Megjelenítés hangerőszabályzóval"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne zavarjanak"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"A hangerőgombok gyorsbillentyűk"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"„Ne zavarjanak” deaktiválása hangerőnöveléskor"</string>
     <string name="battery" msgid="7498329822413202973">"Akkumulátor"</string>
     <string name="clock" msgid="7416090374234785905">"Óra"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fejhallgató csatlakoztatva"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset csatlakoztatva"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ikonok megjelenítése és elrejtése az állapotsoron."</string>
     <string name="data_saver" msgid="5037565123367048522">"Adatforgalom-csökkentő"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Az adatforgalom-csökkentő be van kapcsolva"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Az Adatforgalom-csökkentő ki van kapcsolva"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Be"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Ki"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigációs sáv"</string>
     <string name="start" msgid="6873794757232879664">"Kezdés"</string>
     <string name="center" msgid="4327473927066010960">"Igazítás középre"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Billentyűgomb kiválasztása"</string>
     <string name="preview" msgid="9077832302472282938">"Előnézet"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Húzza csempe hozzáadásához"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Húzza ide az eltávolításhoz"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Szerkesztés"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Idő"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Óra, perc és másodperc megjelenítése"</item>
+    <item msgid="1427801730816895300">"Óra és perc megjelenítése (alapértelmezett)"</item>
+    <item msgid="3830170141562534721">"Ne jelenjen meg ez az ikon"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Százalékos érték mindig látható"</item>
+    <item msgid="2139628951880142927">"Százalékos érték töltés közben látható (alapértelmezett)"</item>
+    <item msgid="3327323682209964956">"Ne jelenjen meg ez az ikon"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Egyéb"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Elválasztó az osztott nézetben"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mozgatás lefelé"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mozgatás felfelé"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mozgatás balra"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mozgatás jobbra"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Lehet, hogy az alkalmazás nem működik többablakos nézetben"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozíció: <xliff:g id="TILE_NAME">%2$s</xliff:g>. Koppintson duplán a szerkesztéshez."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Koppintson duplán a hozzáadáshoz."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozíció. Koppintson duplán a kiválasztáshoz."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> áthelyezése"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> eltávolítása"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> hozzáadva <xliff:g id="POSITION">%2$d</xliff:g>. pozícióban"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> eltávolítva"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> áthelyezve a(z) <xliff:g id="POSITION">%2$d</xliff:g>. pozícióba"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Gyorsbeállítások szerkesztője"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
new file mode 100644
index 0000000..97d6cdd
--- /dev/null
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP bezárása"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Teljes képernyő"</string>
+    <string name="pip_play" msgid="674145557658227044">"Lejátszás"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Szüneteltetés"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP vezérlése a "<b>"HOME"</b>"-mal"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"A PIP vezérléséhez tartsa nyomva a HOME gombot"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Rendben"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Elvetés"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 4f4af55..7e4e01a 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"Չենք կարող պատճենել էկրանը՝ տարածքի սահմանափակման կամ ձեր կազմակերպության կողմից արգելքի պատճառով:"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Էկրանի պատկերը պահելիս խնդիր առաջացավ:"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Չհաջողվեց պահել էկրանի պատկերը սահմանափակ հիշողության պատճառով:"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Այս հավելվածը կամ ձեր կազմակերպությունը չի թույլատրում Էկրանի պատկերի ստացումը:"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ֆայլերի փոխանցման ընտրանքներ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Միացնել որպես մեդիա նվագարկիչ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Միացնել որպես ֆոտոխցիկ (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Անտեսել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>-ը անտեսված է:"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Բոլոր վերջին հավելվածները հեռացվել են ցուցակից:"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Մեկնարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ծանուցումը անտեսվեց:"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ավելացնել ժամանակը:"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Պակասեցնել ժամանակը:"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Լապտերն անջատված է:"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Լապտերն անհասանելի է:"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Լապտերը միացված է:"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Լապտերն անջատվեց:"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Լապտերը միացավ:"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Աշխատանքային ռեժիմը միացված է:"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Աշխատանքային ռեժիմն անջատվեց:"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Աշխատանքային ռեժիմը միացվեց:"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Տվյալների խնայումն անջատվեց:"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Տվյալների խնայումը միացվեց:"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ցուցադրել պայծառությունը"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2Գ-3Գ տվյալների օգտագործումը դադարեցված է"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Տեղադրությունը կարգավորվել է GPS-ի կողմից"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Տեղադրության հարցումներն ակտիվ են"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Մաքրել բոլոր ծանուցումները:"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ծանուցման կարգավորումներ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>-ի կարգավորումներ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Էկրանը ինքնաշխատ կպտտվի:"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Սահմանաչափ՝ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Աշխատանքային ռեժիմ"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Ձեր վերջին էկրանները տեսանելի են այստեղ"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Վերջին տարրեր չկան"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Դուք ջնջել եք ամենը"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"էկրանի ամրակցում"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Հնարավոր չէ գործարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Պատմություն"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Մաքրել"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> հավելվածը անվտանգ ռեժիմում անջատված է:"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Մաքրել բոլորը"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Այս հավելվածը չի աջակցում բազմապատուհան ռեժիմը"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Հավելվածը չի աջակցում բազմապատուհան ռեժիմը"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ուղղահայաց տրոհում"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Հատուկ տրոհում"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Ընդհանուր\nլուռ վիճակը"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nզարթուցիչ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Բոլորը"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Բոլորը\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Միացնել մատը վերև սահեցնելով էկրանը տրոհելու արագացուցիչը"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ակտիվացնել մատը վերև սահեցնելով էկրանը տրոհելու ժեստը"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Միացնել Համատեսք կոճակից մատը դեպի վերև սահեցնելու միջոցով տրոհված էկրանի ռեժիմ անցնելու ժեստը"</string>
     <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Միացնել"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Կիրառել <xliff:g id="TOPIC_NAME">%1$s</xliff:g>-ի ծանուցումների նկատմամբ"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Կիրառել այս հավելվածի բոլոր ծանուցումների նկատմամբ"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Ցույց տալ ծանուցումներն առանց ձայնային ազդանշանի"</string>
+    <string name="block" msgid="2734508760962682611">"Արգելափակել բոլոր ծանուցումները"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ձայնը չանջատել"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ձայնը չանջատել և չարգելափակել"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Ցույց տալ կարևորության բոլոր կարգավորումները"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Արգելափակված"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Նվազագույն կարևորություն"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ցածր կարևորություն"</string>
     <string name="default_importance" msgid="8192107689995742653">"Սովորական կարևորություն"</string>
     <string name="high_importance" msgid="1527066195614050263">"Բարձր կարևորություն"</string>
     <string name="max_importance" msgid="5089005872719563894">"Հրատապ կարևորություն"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Երբեք չցուցադրել այս ծանուցումները"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Ցուցադրել ծանուցումների ցանկի վերևում և հնչեցնել ձայնային ազդանշան"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Ցուցադրել էկրանին և հնչեցնել ձայնային ազդանշան"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Թույլ տալ այս ծանուցումներին ձայնային ազդանշան հնչեցնել"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Թռուցիկ ցուցադրել էկրանին և թույլատրել ձայնային ազդանշանը"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Ցույց տալ ծանուցումների ցանկի վերևում, թռուցիկ ցուցադրել էկրանին և թույլատրել ձայնային ազդանշանը"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
     <string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Սովորական գույներ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Գիշերային գույներ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Հատուկ գույներ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Ավտոմատ"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Անհայտ գույներ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Գույնի փոփոխում"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ցույց տալ Արագ կարգավորումների սալիկը"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Միացնել հատուկ գունային անցումը"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ծանուցումների կառավարներ"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Գույնը և արտաքին տեսքը"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Գիշերային ռեժիմ"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Չափաբերել էկրանը"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Միացված է"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Անջատված է"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Միացնել ավտոմատ կերպով"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Անցեք Գիշերային ռեժիմի, եթե դա պահանջում է տեղը և օրվա ժամանակը"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Երբ Գիշերային ռեժիմը միացված է"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Օգտագործել մուգ թեման Android OS-ի համար"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Կարգավորել երանգը"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Կարգավորել պայծառությունը"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Մուգ թեման կիրառվում է Android OS-ի հիմնական հատվածների նկատմամբ, որոնք սովորաբար ցուցադրվում են բաց թեմայում (օրինակ՝ Կարգավորումներ):"</string>
     <string name="color_apply" msgid="9212602012641034283">"Կիրառել"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Հաստատել կարգավորումները"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Գունային որոշ կարգավորումները կարող են այս սարքը օգտագործման համար ոչ պիտանի դարձնել: Սեղմեք Լավ կոճակը՝ գունային այս կարգավորումները հաստատելու համար: Հակառակ դեպքում այս կարգավորումները կվերակայվեն 10 վայրկյան հետո:"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Մարտկոցի օգտագործում"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Մարտկոցի տնտեսումը լիցքավորման ժամանակ հասանելի չէ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Մարտկոցի տնտեսում"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> կոճակ"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Գլխավոր էջ"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Հետ"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Վերև"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ներքև"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Ձախ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Աջ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Կենտրոն"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Բացատ"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Մուտք"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Հետշարժ"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Նվագարկում/դադար"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Դադարեցնել"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Հաջորդը"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Նախորդը"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Հետ անցնել"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Արագ առաջ անցնել"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ջնջել"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Գլխավոր էջ"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Վերջ"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Տեղադրել"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Համակարգ"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Գլխավոր էջ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Վերջինները"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Հետ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ցույց տալ Չխանգարել գործառույթը ձայնի կառավարման պատուհանում"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Թույլատրել Չխանգարել գործառույթի ամբողջական վերահսկումը ձայնի կառավարման պատուհանում:"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ձայնի ուժգնություն և Չխանգարել գործառույթ"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Մտնել Չխանգարել գործառույթ ձայնի նվազեցման կոճակը սեղմելիս"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ծանուցումներ"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Ստեղնային դյուրանցումներ"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Փոխարկել մուտքագրման եղանակը"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Գործադիրներ"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Օգնություն"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Դիտարկիչ"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Կոնտակտներ"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Էլփոստ"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Երաժշտություն"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Օրացույց"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ցույց տալ ձայնի ուժգնության կառավարման տարրերի հետ"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Չընդհատել"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Ձայնի կոճակների դյուրանցում"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Ելնել Չխանգարել գործառույթից ձայնի ավելացման կոճակը սեղմելիս"</string>
     <string name="battery" msgid="7498329822413202973">"Մարտկոց"</string>
     <string name="clock" msgid="7416090374234785905">"Ժամացույց"</string>
     <string name="headset" msgid="4534219457597457353">"Ականջակալ"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Ականջակալը կապակցված է"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Ականջակալը կապակցված է"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Միացնել կամ անջատել պատկերակների ցուցադրումը կարգավիճակի գոտում:"</string>
     <string name="data_saver" msgid="5037565123367048522">"Տվյալների խնայում"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Տվյալների խնայումը միացված է"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Տվյալների խնայումն անջատված է"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Միացնել"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Անջատել"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Նավարկման գոտի"</string>
     <string name="start" msgid="6873794757232879664">"Սկսել"</string>
     <string name="center" msgid="4327473927066010960">"Կենտրոն"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Ընտրեք ստեղնաշարի կոճակը"</string>
     <string name="preview" msgid="9077832302472282938">"Նախադիտում"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Քաշեք՝ սալիկներ ավելացնելու համար"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Քաշեք այստեղ՝ հեռացնելու համար"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Փոփոխել"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Ժամ"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Ցույց տալ ժամերը, րոպեները և վայրկյանները"</item>
+    <item msgid="1427801730816895300">"Ցույց տալ ժամերը և րոպեները (կանխադրված է)"</item>
+    <item msgid="3830170141562534721">"Ցույց չտալ այս պատկերակը"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Միշտ ցույց տալ տոկոսը"</item>
+    <item msgid="2139628951880142927">"Ցույց տալ տոկոսը լիցքավորելու ժամանակ (կանխադրված է)"</item>
+    <item msgid="3327323682209964956">"Ցույց չտալ այս պատկերակը"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Այլ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Տրոհված էկրանի բաժանիչ"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Տեղափոխել ներքև"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Տեղափոխել վերև"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Տեղափոխել ձախ"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Տեղափոխել աջ"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Հավելվածը չի կարող աշխատել բազմապատուհան ռեժիմում"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>: Կրկնակի հպեք՝ փոխելու համար:"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>: Կրկնակի հպեք՝ ավելացնելու համար:"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>: Կրկնակի հպեք՝ ընտրելու համար:"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Տեղափոխել <xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Հեռացնել <xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկն ավելացվել է <xliff:g id="POSITION">%2$d</xliff:g> դիրքին"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը հեռացվել է"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը տեղափոխվել է դեպի <xliff:g id="POSITION">%2$d</xliff:g> դիրք"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Արագ կարգավորումների խմբագրիչ:"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings_tv.xml b/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
new file mode 100644
index 0000000..5f9c127
--- /dev/null
+++ b/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Փակել PIP-ն"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Լիէկրան"</string>
+    <string name="pip_play" msgid="674145557658227044">"Նվագարկել"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Դադարեցնել"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP-ն կառավարելու համար սեղմած պահեք "<b>"HOME"</b>" կոճակը"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP-ն կառավարելու համար սեղմեք և պահեք HOME կոճակը"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Պարզ է"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Փակել"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index fa359ad..2b51426 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan layar diambil."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan layar Anda."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat mengambil tangkapan layar."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Tak bisa mengambil tangkapan layar karena ruang penyimpanan terbatas/tak diizinkan aplikasi/organisasi Anda."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Terjadi masalah saat menyimpan tangkapan layar."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Tidak dapat menyimpan tangkapan layar karena ruang penyimpanan terbatas."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Mengambil tangkapan layar tidak diizinkan oleh aplikasi atau organisasi."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opsi transfer file USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pasang sebagai pemutar media (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Pasang sebagai kamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Menyingkirkan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> disingkirkan."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaru telah ditutup."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulai <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifikasi disingkirkan."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lebih lama."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Lebih cepat."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Senter nonaktif."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Senter tidak tersedia."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Senter aktif."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Senter dinonaktifkan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Senter diaktifkan."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mode kerja aktif."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Mode kerja dinonaktifkan."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Mode kerja diaktifkan."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Penghemat Data nonaktif."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Penghemat Data diaktifkan."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan tampilan"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Menghapus semua pemberitahuan."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Setelan pemberitahuan"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> setelan"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Layar akan diputar secara otomatis."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Batas <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Peringatan <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode kerja"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Layar terkini Anda muncul di sini"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Tidak ada item baru-baru ini"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda sudah menghapus semua"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pin ke layar"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulai <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Riwayat"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Hapus"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> dinonaktifkan dalam mode aman."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hapus semua"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikasi ini tidak mendukung multijendela"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikasi tidak mendukung multijendela"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Pisahkan Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pisahkan Vertikal"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pisahkan Khusus"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Senyap\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Hanya\nprioritas"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Hanya\nalarm"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Semua"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Semua\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengisi daya dengan cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengisi daya dengan lambat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktifkan akselerator gesek atas untuk layar terpisah"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktifkan isyarat gesek atas untuk layar terpisah"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktifkan isyarat untuk masuk layar terpisah dengan menggesek tombol Ringkasan ke atas"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktifkan"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Terapkan ke notifikasi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Terapkan untuk semua notifikasi dari aplikasi ini"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Tampilkan notifikasi tanpa suara"</string>
+    <string name="block" msgid="2734508760962682611">"Blokir semua notifikasi"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Jangan bisukan"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Jangan bisukan atau blokir"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tampilkan setelan lengkap nilai penting"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Diblokir"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Nilai penting min"</string>
     <string name="low_importance" msgid="4109929986107147930">"Tingkat kepentingan: rendah"</string>
     <string name="default_importance" msgid="8192107689995742653">"Tingkat kepentingan: normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Tingkat kepentingan: tinggi"</string>
     <string name="max_importance" msgid="5089005872719563894">"Tingkat kepentingan: darurat"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan pernah tunjukkan notifikasi ini"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Tunjukkan di bawah daftar notifikasi tanpa suara"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan notifikasi ini tanpa suara"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan di bagian atas daftar notifikasi dan bunyikan suara"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Muncul di layar dan bunyikan suara"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tampilkan di bagian bawah daftar notifikasi tanpa suara"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tampilkan notifikasi ini tanpa suara"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Izinkan notifikasi ini bersuara"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Muncul di layar dan izinkan suara"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Tampilkan di bagian atas daftar notifikasi, muncul di layar, dan izinkan suara"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
     <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Warna normal"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Warna khusus"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Otomatis"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Warna tidak diketahui"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Perubahan warna"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tampilkan ubin Setelan Cepat"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Aktifkan transformasi khusus"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrol notifikasi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Warna dan tampilan"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Mode malam"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibrasi layar"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Aktif"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Nonaktif"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Aktifkan secara otomatis"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Beralih ke Mode Malam yang sesuai untuk lokasi dan waktu"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Saat Mode Malam aktif"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Gunakan tema gelap untuk OS Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Sesuaikan rona"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Sesuaikan kecerahan"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema gelap diterapkan ke area inti OS Android yang biasanya ditampilkan di tema terang, seperti Setelan."</string>
     <string name="color_apply" msgid="9212602012641034283">"Terapkan"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Konfirmasi setelan"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Beberapa setelan warna dapat membuat perangkat ini tidak dapat digunakan. Klik OKE untuk mengonfirmasi setelan warna ini. Jika tidak, setelan ini akan disetel ulang setelah 10 detik."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Pemakaian baterai"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penghemat Baterai tidak tersedia selama pengisian daya"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Penghemat Baterai"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangi performa dan data latar belakang"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tombol <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Layar Utama"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaru"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Tampilkan mode jangan ganggu di volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Izinkan kontrol penuh dari mode jangan mengganggu di dialog volume."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume dan mode Jangan ganggu"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Masukkan mode jangan ganggu di tombol kecilkan volume"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifikasi"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pintasan Keyboard"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Beralih metode masukan"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikasi"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bantuan"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontak"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Tampilkan dengan kontrol volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan tombol volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Keluar dari mode jangan ganggu di tombol keraskan volume"</string>
     <string name="battery" msgid="7498329822413202973">"Baterai"</string>
     <string name="clock" msgid="7416090374234785905">"Jam"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphone terhubung"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset terhubung"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Aktifkan atau nonaktifkan ikon yang ditampilkan di bilah status."</string>
     <string name="data_saver" msgid="5037565123367048522">"Penghemat Data"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Penghemat Data aktif"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Penghemat Data nonaktif"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Aktif"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Nonaktif"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Bilah navigasi"</string>
     <string name="start" msgid="6873794757232879664">"Awal"</string>
     <string name="center" msgid="4327473927066010960">"Tengah"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Pilih Tombol Keyboard"</string>
     <string name="preview" msgid="9077832302472282938">"Pratinjau"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Seret untuk menambahkan ubin"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Seret ke sini untuk menghapus"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Waktu"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Tampilkan jam, menit, dan detik"</item>
+    <item msgid="1427801730816895300">"Tampilkan jam dan menit (default)"</item>
+    <item msgid="3830170141562534721">"Jangan tampilkan ikon ini"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Selalu tampilkan persentase"</item>
+    <item msgid="2139628951880142927">"Tampilkan persentase saat mengisi daya (default)"</item>
+    <item msgid="3327323682209964956">"Jangan tampilkan ikon ini"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Lainnya"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Pembagi layar terpisah"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Turunkan"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Naikkan"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pindahkan ke kiri"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pindahkan ke kanan"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikasi mungkin tidak berfungsi dengan multi-jendela"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Ketuk dua kali untuk mengedit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Ketuk dua kali untuk menambahkan."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>. Ketuk dua kali untuk memilih."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pindahkan <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Hapus <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ditambahkan ke posisi <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dihapus"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dpindahkan ke posisi <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor setelan cepat."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
new file mode 100644
index 0000000..7de1a78
--- /dev/null
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Tutup PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Layar penuh"</string>
+    <string name="pip_play" msgid="674145557658227044">"Putar"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Jeda"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Tahan "<b>"LAYAR UTAMA"</b>" untuk mengontrol PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Tekan dan tahan tombol LAYAR UTAMA untuk mengontrol PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Mengerti"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Tutup"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 2fca674..1dc37df 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skjámynd var tekin."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snertu til að skoða skjámyndina."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Ekki tókst að taka skjámynd."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Ekki hægt að taka skjámynd vegna takmarkaðs pláss eða forritið eða notendaskipanin leyfir það ekki."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Upp kom vandamál við að vista skjámynd."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Ekki tókst að vista skjámynd vegna takmarkaðs geymslupláss."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Forritið eða fyrirtækið þitt leyfir ekki að teknar séu skjámyndir."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Valkostir USB-skráaflutnings"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Tengja sem efnisspilara (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Tengja sem myndavél (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hunsa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> vísað frá."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Öll nýleg forrit fjarlægð."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Ræsir <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Tilkynningu lokað."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meiri tími."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minni tími."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Slökkt á vasaljósi."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Vasaljós ekki tiltækt"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Kveikt á vasaljósi."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Slökkt á vasaljósi."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Kveikt á vasaljósi."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Kveikt á vinnustillingu."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Slökkt á vinnustillingu."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Kveikt á vinnustillingu."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Slökkt var á gagnasparnaði."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Kveikt var á gagnasparnaði."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Birtustig skjás"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Slökkt er á 2G- og 3G-gögnum"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Staðsetning valin með GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Staðsetningarbeiðnir virkar"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Hreinsa allar tilkynningar."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Tilkynningastillingar"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Stillingar fyrir <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjárinn snýst sjálfkrafa."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hámark"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> viðvörun"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Vinnustilling"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Nýlegar skjámyndir birtast hér"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Engin nýleg atriði"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Þú hefur hreinsað allt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Forritsupplýsingar"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skjáfesting"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Ferill"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Hreinsa"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Slökkt er á <xliff:g id="APP">%s</xliff:g> í öruggri stillingu."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hreinsa allt"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Þetta forrit styður ekki marga glugga"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Forritið styður ekki marga glugga"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Lárétt skipting"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Lóðrétt skipting"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Sérsniðin skipting"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Algjör\nþögn"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Aðeins\nforgangur"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Aðeins\nvekjarar"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Allar"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Allar\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Í hraðri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Í hægri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Virkja skjáskiptingu með því að strjúka upp"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Virkja skjáskiptingu með því að strjúka upp"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Virkja skjáskiptingarbendingu með því að strjúka upp frá yfirlitshnappi"</string>
     <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Kveikja"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Láta gilda um tilkynningar varðandi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Láta gilda um allar tilkynningar frá þessu forriti"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Sýna tilkynningar án hljóðs"</string>
+    <string name="block" msgid="2734508760962682611">"Loka á allar tilkynningar"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ekki þagga"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Hvorki þagga né útiloka"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Sýna stillingar fyrir mikilvægi"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Útilokuð"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Lítill forgangur"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ekki svo mikilvægt"</string>
     <string name="default_importance" msgid="8192107689995742653">"Venjulegt mikilvægi"</string>
     <string name="high_importance" msgid="1527066195614050263">"Mjög mikilvægt"</string>
     <string name="max_importance" msgid="5089005872719563894">"Afar áríðandi"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Aldrei sýna þessar tilkynningar"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Sýna neðst á tilkynningalistanum án hljóðs"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Sýna þessar tilkynningar án hljóðs"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Sýna efst á tilkynningalistanum og spila hljóð"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Birta á skjánum og spila hljóð"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Sýna neðst á tilkynningalistanum án hljóðs"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Sýna þessar tilkynningar án hljóðs"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Leyfa þessum tilkynningum að spila hljóð"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Birta á skjánum og leyfa hljóð"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Sýna efst á tilkynningalistanum, birta á skjánum og leyfa hljóð"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Venjulegir litir"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Næturlitir"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Sérsniðnir litir"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Sjálfvirkt"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Óþekktir litir"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Litabreytingar"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Sýna flísar í flýtistillingum"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Kveikja á sérsniðinni umbreytingu"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Tilkynningastýringar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Litur og útlit"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Næturstilling"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kvarða skjáinn"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Kveikt"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Slökkt"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Kveikja sjálfkrafa"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Skipta í næturstillingu í samræmi við staðsetningu og tíma dags"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Þegar kveikt er á næturstillingu"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Nota dökkt þema fyrir Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Stilla litblæ"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Stilla birtustig"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Dökka þemað er notað á þeim aðalsvæðum Android OS sem venjulega eru ljós, s.s. í stillingum."</string>
     <string name="color_apply" msgid="9212602012641034283">"Nota"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Staðfesta stillingar"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Sumar litastillingar kunna að bitna á notagildi tækisins. Veldu „Í lagi“ til að staðfesta þessar litastillingar, að öðrum kosti verða litirnir endurstilltir eftir tíu sekúndur."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Rafhlöðunotkun"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ekki er hægt að nota rafhlöðusparnað meðan á hleðslu stendur"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Rafhlöðusparnaður"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Dregur úr afköstum og bakgrunnsgögnum"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Hnappur <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Til baka"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Upp"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Niður"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vinstri"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Hægri"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Miðja"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Bilslá"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Bakklykill"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Spila/gera hlé"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stöðva"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Áfram"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Fyrri"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spóla til baka"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Spóla áfram"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tölulykill <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Kerfi"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Heim"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nýlegt"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Til baka"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Sýna „Ónáðið ekki“ í hljóðstyrksvali"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Leyfa fulla stjórn á stillingunni „Ónáðið ekki“ í hljóðstyrksglugganum."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hljóðstyrkur og „Ónáðið ekki“"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Kveikja á „Ónáðið ekki“ með því að lækka"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Tilkynningar"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Flýtilyklar"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Skipta um innsláttaraðferð"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Forrit"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Aðstoð"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Vafri"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Tengiliðir"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Tölvupóstur"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Spjall"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Tónlist"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Dagatal"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Sýna með hljóðstyrksstillingum"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ónáðið ekki"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Flýtihnappar fyrir hljóðstyrk"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Slökkva á „Ónáðið ekki“ með því að hækka"</string>
     <string name="battery" msgid="7498329822413202973">"Rafhlaða"</string>
     <string name="clock" msgid="7416090374234785905">"Klukka"</string>
     <string name="headset" msgid="4534219457597457353">"Höfuðtól"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Heyrnartól tengd"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Höfuðtól tengt"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Birtu eða feldu myndtákn í stöðustikunni."</string>
     <string name="data_saver" msgid="5037565123367048522">"Gagnasparnaður"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Kveikt er á gagnasparnaði"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Slökkt er á gagnasparnaði"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Kveikt"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Slökkt"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Yfirlitsstika"</string>
     <string name="start" msgid="6873794757232879664">"Byrja"</string>
     <string name="center" msgid="4327473927066010960">"Miðja"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Veldu lyklaborðshnapp"</string>
     <string name="preview" msgid="9077832302472282938">"Forskoðun"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Dragðu til að bæta við reitum"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Dragðu hingað til að fjarlægja"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Breyta"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Tími"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Sýna klukkustundir, mínútur og sekúndur"</item>
+    <item msgid="1427801730816895300">"Sýna klukkustundir og mínútur (sjálfgefið)"</item>
+    <item msgid="3830170141562534721">"Ekki sýna þetta tákn"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Sýna alltaf hlutfall"</item>
+    <item msgid="2139628951880142927">"Sýna hlutfall meðan á hleðslu stendur (sjálfgefið)"</item>
+    <item msgid="3327323682209964956">"Ekki sýna þetta tákn"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Annað"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Skjáskipting"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Færa niður"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Færa upp"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Færa til vinstri"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Færa til hægri"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Hugsanlegt er að forritið virki ekki í mörgum gluggum"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Staða <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Ýttu tvisvar til að breyta."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Ýttu tvisvar til að bæta við."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Staða <xliff:g id="POSITION">%1$d</xliff:g>. Ýttu tvisvar til að velja."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Færa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjarlægja <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er bætt við í stöðu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> var fjarlægð"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> færð í stöðu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Flýtistillingaritill."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings_tv.xml b/packages/SystemUI/res/values-is-rIS/strings_tv.xml
new file mode 100644
index 0000000..09c67ec
--- /dev/null
+++ b/packages/SystemUI/res/values-is-rIS/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Loka mynd í mynd"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Allur skjárinn"</string>
+    <string name="pip_play" msgid="674145557658227044">"Spila"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Hlé"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Haltu "<b>"HOME"</b>"-hnappinum inni til að stjórna innfelldri mynd"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Haltu „Home“-hnappinum inni til að stjórna innfelldri mynd"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Ég skil"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Hunsa"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index c2c05b4..4a8ba99 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot acquisito."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Tocca per visualizzare il tuo screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Impossibile acquisire lo screenshot."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Imposs. acquisire screenshot per spazio archiviazione limitato o perché vietato da organizzazione o app."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Si è verificato un problema durante il salvataggio dello screenshot."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Impossibile salvare lo screenshot a causa dello spazio di archiviazione limitato."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"L\'acquisizione di screenshot non è consentita dall\'app o dall\'organizzazione."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opzioni trasferimento file USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Monta come lettore multimediale (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Monta come videocamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Elimina <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eliminata."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tutte le applicazioni recenti sono state rimosse."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Avvio di <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifica eliminata."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Più tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Meno tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torcia spenta."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torcia non disponibile."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torcia accesa."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torcia disattivata."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torcia attivata."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modalità Lavoro attiva."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modalità Lavoro disattivata."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modalità Lavoro attivata."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Funzione Risparmio dati disattivata."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Funzione Risparmio dati attivata."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosità dello schermo"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dati 2G-3G sospesi"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Posizione stabilita dal GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Richieste di accesso alla posizione attive"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Cancella tutte le notifiche."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Impostazioni di notifica"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Impostazioni di <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Lo schermo ruoterà automaticamente."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite di <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avviso <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modalità Lavoro"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Le tue schermate recenti vengono visualizzate in questa sezione"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nessun elemento recente"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hai cancellato tutto"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"blocco su schermo"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Cronologia"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Cancella"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"L\'app <xliff:g id="APP">%s</xliff:g> è stata disattivata in modalità provvisoria."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Cancella tutto"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Questa app non supporta la modalità multi-finestra"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'app non supporta la modalità multi-finestra"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisione in orizzontale"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisione in verticale"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisione personalizzata"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silenzio\ntotale"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo con\npriorità"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nsveglie"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Tutte"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tutte\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ricarica veloce (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ricarica lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Attiva Schermo diviso mediante scorrimento verso l\'alto"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Attiva Schermo diviso mediante scorrimento verso l\'alto"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Consente di attivare la modalità Schermo diviso scorrendo verso l\'alto dal pulsante Panoramica"</string>
     <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Attiva"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Applica a notifiche <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Applica a tutte le notifiche di quest\'app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostra le notifiche silenziosamente"</string>
+    <string name="block" msgid="2734508760962682611">"Blocca tutte le notifiche"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Non silenziare"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Non silenziare e non bloccare"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostra impostazioni di importanza complete"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloccata"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importanza minima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importanza scarsa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importanza normale"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importanza elevata"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importanza urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrare mai queste notifiche"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostra silenziosamente nella parte inferiore dell\'elenco delle notifiche"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostra silenziosamente queste notifiche"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostra nella parte superiore dell\'elenco delle notifiche e riproduci suono"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Apri sullo schermo e riproduci suono"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostra silenziosamente in fondo all\'elenco delle notifiche"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostra queste notifiche silenziosamente"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Attiva l\'audio per queste notifiche"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Visualizza sullo schermo e attiva l\'audio"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostra in cima all\'elenco delle notifiche, visualizza sullo schermo e attiva l\'audio"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fine"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Colori normali"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Colori per la notte"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Colori personalizzati"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatico"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Colori sconosciuti"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modifica del colore"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostra il riquadro Impostazioni rapide"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Attiva la trasformazione personalizzata"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlli di notifica per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Colore e aspetto"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modalità notturna"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibra display"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Attiva"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Disattivata"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Attiva automaticamente"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Attiva la modalità notturna in base alla località e all\'ora del giorno"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Quando la modalità notturna è attiva"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Utilizza tema scuro per sistema Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Regola tinta"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Regola luminosità"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Il tema scuro viene applicato agli elementi fondamentali del sistema operativo Android che vengono generalmente visualizzati con un tema chiaro, ad esempio le impostazioni."</string>
     <string name="color_apply" msgid="9212602012641034283">"Applica"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Conferma le impostazioni"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Alcune impostazioni relative ai colori potrebbero rendere inutilizzabile il dispositivo. Fai clic su OK per confermare queste impostazioni; in caso contrario, le impostazioni verranno reimpostate dopo 10 secondi."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Utilizzo batteria"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Risparmio energetico non disponibile durante la ricarica"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Risparmio energetico"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Riduce le prestazioni e i dati in background"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home page"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Indietro"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Su"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Giù"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Sinistra"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Destra"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Al centro"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Scheda"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Spazio"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Invio"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pausa"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Interrompi"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Avanti"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Precedente"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Riavvolgi"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avanza velocemente"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Pagina su"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Pagina giù"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Elimina"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home page"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fine"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"INS"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloc Num"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tastierino numerico <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recenti"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Indietro"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostra Non disturbare nella finestra del volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Consenti il controllo totale della funzione Non disturbare nella finestra di dialogo del volume."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e Non disturbare"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Attiva Non disturbare all\'abbassamento del volume"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifiche"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Scorciatoie da tastiera"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambia metodo di immissione"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applicazioni"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistenza"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatti"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musica"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra con controlli volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non disturbare"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Pulsanti del volume come scorciatoia"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Disattiva Non disturbare all\'aumento del volume"</string>
     <string name="battery" msgid="7498329822413202973">"Batteria"</string>
     <string name="clock" msgid="7416090374234785905">"Orologio"</string>
     <string name="headset" msgid="4534219457597457353">"Auricolare"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Cuffie collegate"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auricolare collegato"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Consente di attivare o disattivare la visualizzazione delle icone nella barra di stato."</string>
     <string name="data_saver" msgid="5037565123367048522">"Risparmio dati"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Risparmio dati attivo"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Risparmio dati disattivato"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Attiva"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Off"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra di navigazione"</string>
     <string name="start" msgid="6873794757232879664">"All\'inizio"</string>
     <string name="center" msgid="4327473927066010960">"Al centro"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Seleziona il tasto della tastiera"</string>
     <string name="preview" msgid="9077832302472282938">"Anteprima"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Trascina per aggiungere i riquadri"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Trascinali qui per rimuoverli"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Modifica"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Ora"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostra ore, minuti e secondi"</item>
+    <item msgid="1427801730816895300">"Mostra ore e minuti (opzione predefinita)"</item>
+    <item msgid="3830170141562534721">"Non mostrare questa icona"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Mostra sempre la percentuale"</item>
+    <item msgid="2139628951880142927">"Mostra la percentuale quando in carica (opzione predefinita)"</item>
+    <item msgid="3327323682209964956">"Non mostrare questa icona"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Altro"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Strumento per schermo diviso"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Sposta giù"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sposta su"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sposta a sinistra"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sposta a destra"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"L\'app potrebbe non funzionare con la modalità multi-finestra"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tocca due volte per modificare."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Tocca due volte per aggiungere."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>. Tocca due volte per selezionare."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Sposta <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Rimuovi <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato aggiunto alla posizione <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato rimosso"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato spostato nella posizione <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor di impostazioni rapide."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
new file mode 100644
index 0000000..4ea019b
--- /dev/null
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Chiudi PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Schermo intero"</string>
+    <string name="pip_play" msgid="674145557658227044">"Riproduci"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausa"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Tieni premuto "<b>"HOME"</b>" per controllare PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Tieni premuto il pulsante HOME per controllare PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignora"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2601d36..d41d50d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -75,7 +75,9 @@
     <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="1260203058661337274">"לא ניתן לצלם את המסך מפני שנפח האחסון מוגבל או מפני שהאפליקציה או הארגון שלך אינם מתירים זאת."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"התגלתה בעיה בשמירת צילום מסך."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"לא ניתן לשמור צילום מסך עקב שטח אחסון מוגבל."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"האפליקציה, או הארגון שלך, אינם מתירים לבצע צילומי מסך."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"‏אפשרויות העברת קבצים ב-USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏טען כנגן מדיה (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏טען כמצלמה (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"סגור את <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> נדחה."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"כל האפליקציות האחרונות נסגרו."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"מפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"יותר זמן."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"פחות זמן."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"הפנס כבוי."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"פנס אינו זמין."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"הפנס מופעל."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"הפנס נכבה."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"הפנס הופעל."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"מצב עבודה מופעל."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"מצב עבודה הושבת."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"מצב עבודה הופעל."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"‏חוסך הנתונים (Data Saver) כובה."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"‏חוסך הנתונים (Data Saver) הופעל."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"בהירות תצוגה"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏השימוש בנתוני 2G-3G מושהה"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏השימוש בנתוני 4G מושהה"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"‏מיקום מוגדר על ידי GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"בקשות מיקום פעילות"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"הגדרות עבור הודעות"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"הגדרות <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"המסך יסתובב באופן אוטומטי."</string>
@@ -298,15 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"הגבלה של <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"אזהרה - <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"מצב עבודה"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"המסכים האחרונים מופיעים כאן"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"אין פריטים אחרונים"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"מחקת הכול"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"הצמדת מסך"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"לא ניתן היה להפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"היסטוריה"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"נקה"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> מושבת במצב בטוח."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"נקה הכל"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"אפליקציה זו אינה תומכת בריבוי חלונות"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"האפליקציה אינה תומכת בריבוי חלונות"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"פיצול אופקי"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"פיצול אנכי"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"פיצול מותאם אישית"</string>
@@ -336,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"שקט\nמוחלט"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"התראות בעדיפות\nבלבד"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"התראות\nבלבד"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"הכל"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"הכל\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"בטעינה מהירה (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"בטעינה איטית (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
@@ -450,61 +457,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
     <string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"הפעל מאיץ מסך מפוצל על ידי החלקה כלפי מעלה"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"הפעל מסך מפוצל על ידי תנועת החלקה כלפי מעלה"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"הפעל את התנועה לכניסה למסך מפוצל על ידי החלקה כלפי מעלה מלחצן הסקירה"</string>
     <string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"‏האם להפעיל את ה-Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"הפעל"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"החל על הודעות של <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"החל על כל ההודעות מאפליקציה זו"</string>
+    <string name="show_silently" msgid="6841966539811264192">"הצג הודעות בלי להשמיע צליל"</string>
+    <string name="block" msgid="2734508760962682611">"חסום את כל ההודעות"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"לא להשתיק"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"לא להשתיק או לחסום"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"הצג את הגדרות החשיבות במלואן"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"חסום"</string>
+    <string name="min_importance" msgid="1901894910809414782">"חשיבות מינימלית"</string>
     <string name="low_importance" msgid="4109929986107147930">"חשיבות נמוכה"</string>
     <string name="default_importance" msgid="8192107689995742653">"חשיבות רגילה"</string>
     <string name="high_importance" msgid="1527066195614050263">"חשיבות גבוהה"</string>
     <string name="max_importance" msgid="5089005872719563894">"חשיבות דחופה"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"לעולם אל תציג את ההודעות האלה"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"הצג בחלק התחתון של רשימת ההודעות בלי להשמיע צליל"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"הצג את ההודעות האלה בלי להשמיע צליל"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"הצג בחלק העליון של רשימת ההודעות והשמע צליל"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"הצג לרגע על המסך והשמע צליל"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"הצג בסוף רשימת ההודעות בלי להשמיע צליל"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"הצג את ההודעות האלה בלי להשמיע צליל"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"אשר להודעות אלה להשמיע צליל"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"הצג לרגע על גבי המסך ואשר השמעת צליל"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"הצג בראש רשימת ההודעות, הצג לרגע על גבי המסך ואשר השמעת צליל"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
     <string name="notification_done" msgid="5279426047273930175">"סיום"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"צבעים רגילים"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"צבעי לילה"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"צבעים מותאמים אישית"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"אוטומטי"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"צבעים לא ידועים"</string>
-    <string name="color_transform" msgid="6985460408079086090">"שינוי צבע"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"הצגת אריח של הגדרות מהירות"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"הפעל טרנספורמציה מותאמת אישית"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> פקדי הודעות"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"צבע ומראה"</string>
+    <string name="night_mode" msgid="3540405868248625488">"מצב לילה"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"כיול תצוגה"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"פועל"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"כבוי"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"הפעל אוטומטית"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"החלף למצב לילה בהתאם למיקום ולשעה ביום"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"כאשר מצב לילה מופעל"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"‏השתמש בעיצוב כהה למערכת ההפעלה של Android."</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"התאמת גוון"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"התאמת בהירות"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"‏העיצוב הכהה מוחל על התחומים העיקריים במערכת ההפעלה Android שמוצגים בדרך כלל בעיצוב בהיר, כמו \'הגדרות\'."</string>
     <string name="color_apply" msgid="9212602012641034283">"החל"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"אישור הגדרות"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"הגדרות צבע מסוימות עלולות להפוך את המכשיר הזה לבלתי שמיש. לחץ על אישור כדי לאשר את הגדרות הצבע האלה, אחרת הגדרות אלה יתאפסו לאחר 10 שניות."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"שימוש בסוללה"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"תכונת החיסכון בסוללה אינה זמינה בעת טעינת המכשיר"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"חיסכון בסוללה"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"מפחית את רמת הביצועים ואת נתוני הרקע"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"לחצן <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"דף הבית"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"הקודם"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"למעלה"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"למטה"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"שמאלה"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ימינה"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"מרכז"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"כרטיסייה"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"רווח"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"BACKSPACE"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"הפעל/השהה"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"עצור"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"הבא"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"הקודם"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"הרץ אחורה"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"הרץ קדימה"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"דפדוף למעלה"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"דפדוף למטה"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"מחיקה"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"דף הבית"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"סיום"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"הזן"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"‏מקש Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"מקלדת נומרית <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"מערכת"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"דף הבית"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"אחרונים"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"הקודם"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"הצג את החלונית \'נא לא להפריע\' בעוצמת הקול"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"אפשר שליטה מלאה בחלונית \'נא לא להפריע\' בתיבת הדו-שיח של עוצמת הקול."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"עוצמת הקול והאפשרות \'נא לא להפריע\'"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"היכנס לאפשרות \'נא לא להפריע\' בהחלשת עוצמת הקול"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"הודעות"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"מקשי קיצור במקלדת"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"החלפת שיטת קלט"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"אפליקציות"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"מסייע"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"דפדפן"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"אנשי קשר"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"אימייל"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"שליחת הודעות מיידיות"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"מוזיקה"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"‏YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"יומן"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"הצג עם פקדי עוצמת הקול"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"נא לא להפריע"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"מקש קיצור ללחצני עוצמת קול"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"צא מהאפשרות \'נא לא להפריע\' בהגברת עוצמת הקול"</string>
     <string name="battery" msgid="7498329822413202973">"סוללה"</string>
     <string name="clock" msgid="7416090374234785905">"שעון"</string>
     <string name="headset" msgid="4534219457597457353">"אוזניות"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"אוזניות מחוברות"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"אוזניות מחוברות"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"הפעלה או השבתה של סמלים המוצגים בשורת הסטטוס."</string>
     <string name="data_saver" msgid="5037565123367048522">"‏חוסך הנתונים (Data Saver)"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"‏חוסך הנתונים (Data Saver) פועל"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"‏חוסך הנתונים (Data Saver) כבוי"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"פועל"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"כבוי"</string>
     <string name="nav_bar" msgid="1993221402773877607">"סרגל ניווט"</string>
     <string name="start" msgid="6873794757232879664">"התחלה"</string>
     <string name="center" msgid="4327473927066010960">"מרכז"</string>
@@ -526,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"בחירת לחצן מקלדת"</string>
     <string name="preview" msgid="9077832302472282938">"תצוגה מקדימה"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"גרור כדי להוסיף משבצות"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"גרור לכאן כדי להסיר"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ערוך"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"שעה"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"הצג שעות, דקות ושניות"</item>
+    <item msgid="1427801730816895300">"הצג שעות ודקות (ברירת מחדל)"</item>
+    <item msgid="3830170141562534721">"אל תציג את הסמל הזה"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"הצג תמיד באחוזים"</item>
+    <item msgid="2139628951880142927">"הצג באחוזים בזמן טעינה (ברירת מחדל)"</item>
+    <item msgid="3327323682209964956">"אל תציג את הסמל הזה"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"אחר"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"מחלק מסך מפוצל"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"הזז למטה"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"הזז למעלה"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"הזז שמאלה"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"הזז ימינה"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"ייתכן שהאפליקציה לא תפעל עם ריבוי חלונות"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. הקש פעמיים כדי לערוך."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. הקש פעמיים כדי להוסיף."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>. הקש פעמיים כדי לבחור."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"הזזת <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"הסרת <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> התווסף למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> הוסר"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> הועבר למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"עורך הגדרות מהירות."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
new file mode 100644
index 0000000..9130d53
--- /dev/null
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"‏סגור PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"מסך מלא"</string>
+    <string name="pip_play" msgid="674145557658227044">"הפעל"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"השהה"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"‏לחץ לחיצה ארוכה על "<b>"דף הבית"</b>" כדי לשלוט ב-PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"‏לחץ לחיצה ממושכת על לחצן דף הבית כדי לשלוט ב-PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"הבנתי"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"דחה"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 27b3854..83a9888 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"空き容量が足りないか、アプリまたは組織によって許可されていないため、スクリーンショットは撮れません。"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"スクリーンショットの保存中に問題が発生しました。"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"空き容量が足りないため、スクリーンショットを保存できません。"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"アプリまたは組織によって許可されていないため、スクリーンショットは撮れません。"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USBファイル転送オプション"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"メディアプレーヤー(MTP)としてマウント"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"カメラ(PTP)としてマウント"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>を削除します。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>は削除されました。"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近のアプリケーションをすべて消去しました。"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>を開始しています。"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知が削除されました。"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"長くします。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"短くします。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ライトがOFFです。"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ライトを使用できません。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ライトがONです。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ライトをOFFにしました。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ライトをONにしました。"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Work モードがオンです。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Work モードをオフにしました。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Work モードをオンにしました。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"データセーバーが OFF になりました。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"データセーバーが ON になりました。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ディスプレイの明るさ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G~3Gデータは一時停止中です"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"現在地リクエストがアクティブ"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"他 <xliff:g id="NUMBER">%s</xliff:g> 件"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"通知設定"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>の設定"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"画面は自動的に回転します。"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work モード"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"ここに最近の画面が表示されます"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"最近のタスクはありません"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"すべてのタスクを消去しました"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"画面固定"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>を開始できません。"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"履歴"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"消去"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」はセーフモードでは無効になります。"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"すべて消去"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"このアプリはマルチウィンドウに対応していません"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"アプリはマルチウィンドウに対応していません"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"横に分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"縦に分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"分割(カスタム)"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"サイレント\n"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"重要な\n通知のみ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"アラーム\nのみ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"すべて"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"すべて\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"急速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"低速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,64 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
     <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"スワイプアップ分割画面アクセラレータを有効にする"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"上にスワイプして分割画面に切り替える操作を有効にする"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"[概要] ボタンから上にスワイプして分割画面に切り替える操作を有効にします"</string>
     <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ONにする"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」の通知に適用"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"このアプリからのすべての通知に適用"</string>
+    <string name="show_silently" msgid="6841966539811264192">"通知をマナーモードで表示する"</string>
+    <string name="block" msgid="2734508760962682611">"通知をすべてブロックする"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"音声で知らせる"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"音声で知らせる / ブロックしない"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"重要度の設定をすべて表示"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"ブロック中"</string>
+    <string name="min_importance" msgid="1901894910809414782">"重要度: 最低"</string>
     <string name="low_importance" msgid="4109929986107147930">"重要度: 低"</string>
     <string name="default_importance" msgid="8192107689995742653">"重要度: 中"</string>
     <string name="high_importance" msgid="1527066195614050263">"重要度: 高"</string>
     <string name="max_importance" msgid="5089005872719563894">"重要度: 緊急"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"今後はこの通知を表示しない"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"通知リストの末尾にマナーモードで表示する"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"この通知をマナーモードで表示する"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"通知リストの先頭に表示し、音声でも知らせる"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"画面に数秒間表示し、音声でも知らせる"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"通知リストの末尾にマナーモードで表示する"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"この通知をマナーモードで表示する"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"通知を音声で知らせる"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"画面に数秒間表示し、音声でも知らせる"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"通知リストの先頭に表示し、画面に数秒間表示し、音声でも知らせる"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完了"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"標準の色"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"夜間の色"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"カスタムの色"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"自動"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"不明な色"</string>
-    <string name="color_transform" msgid="6985460408079086090">"色の変更"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"[クイック設定] タイルの表示"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"カスタム変換の有効化"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」の通知の管理"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"色と表示"</string>
+    <string name="night_mode" msgid="3540405868248625488">"夜間モード"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"表示の調整"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ON"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"OFF"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"自動的に ON"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"場所や時間に応じて夜間モードに切り替えます"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"夜間モードが ON のとき"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS でダークテーマを使用"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ティントを調整"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"明るさを調整"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"通常ライトテーマで表示される Android OS の主要領域(設定など)にダークテーマが適用されます。"</string>
     <string name="color_apply" msgid="9212602012641034283">"適用"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"設定の確認"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"一部の色設定を適用すると、この端末を使用できなくなることがあります。この色設定を確認するには、[OK] をクリックしてください。確認しない場合、10 秒後に設定はリセットされます。"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"電池の使用状況"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電中はバッテリー セーバーは利用できません"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"バッテリー セーバー"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"パフォーマンスとバックグラウンド データを制限します"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> ボタン"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"戻る"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"上"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"下"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"左"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"右"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"中央"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"再生 / 一時停止"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"次へ"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"前へ"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"巻き戻し"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"早送り"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"PageUp"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"PageDown"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"NumLock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"テンキーの <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"システム"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ホーム"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"戻る"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"音量内に [通知を非表示] を表示"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"音量ダイアログでの [通知を非表示] の管理を許可します。"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量と [通知を非表示]"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"音量下げボタンで [通知を非表示] を ON にする"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"キーボード ショートカット"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"入力方法の切り替え"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"アプリ"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"アシスト"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ブラウザ"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"連絡先"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"メール"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音楽"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"カレンダー"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"音量調節を表示"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"通知の非表示"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"音量ボタンのショートカット"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"音量上げボタンで [通知を非表示] を OFF にする"</string>
     <string name="battery" msgid="7498329822413202973">"電池"</string>
     <string name="clock" msgid="7416090374234785905">"時計"</string>
     <string name="headset" msgid="4534219457597457353">"ヘッドセット"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ヘッドホンを接続しました"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ヘッドセットを接続しました"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ステータスバーでのアイコンの表示を有効または無効にします。"</string>
-    <!-- no translation found for data_saver (5037565123367048522) -->
-    <skip />
-    <!-- no translation found for accessibility_data_saver_on (8454111686783887148) -->
-    <skip />
-    <!-- no translation found for accessibility_data_saver_off (8841582529453005337) -->
-    <skip />
+    <string name="data_saver" msgid="5037565123367048522">"データセーバー"</string>
+    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"データセーバー ON"</string>
+    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"データセーバー OFF"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ON"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"OFF"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ナビゲーション バー"</string>
     <string name="start" msgid="6873794757232879664">"最初"</string>
     <string name="center" msgid="4327473927066010960">"中央"</string>
@@ -527,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"キーボードのボタンの選択"</string>
     <string name="preview" msgid="9077832302472282938">"プレビュー"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"タイルを追加するにはドラッグしてください"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"削除するにはここにドラッグ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"編集"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"時間"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"時間、分、秒を表示"</item>
+    <item msgid="1427801730816895300">"時間、分を表示(デフォルト)"</item>
+    <item msgid="3830170141562534721">"このアイコンを表示しない"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"常に割合を表示"</item>
+    <item msgid="2139628951880142927">"変更時に割合を表示(デフォルト)"</item>
+    <item msgid="3327323682209964956">"このアイコンを表示しない"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"その他"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"分割画面の分割線"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下に移動"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上に移動"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左に移動"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右に移動"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"アプリはマルチウィンドウでは動作しないことがあります"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> の <xliff:g id="TILE_NAME">%2$s</xliff:g> を編集するにはダブルタップします。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を追加するにはダブルタップします。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に配置します。選択するにはダブルタップします。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を移動します"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を削除します"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> をポジション <xliff:g id="POSITION">%2$d</xliff:g> に追加しました"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を削除しました"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> をポジション <xliff:g id="POSITION">%2$d</xliff:g> に移動しました"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"クイック設定エディタ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
new file mode 100644
index 0000000..0f0032f
--- /dev/null
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP を閉じる"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"全画面表示"</string>
+    <string name="pip_play" msgid="674145557658227044">"再生"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"一時停止"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP を管理するには ["<b>"ホーム"</b>"] を押し続けます"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP を管理するには [ホーム] ボタンを押し続けます"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"閉じる"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"閉じる"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index dc48079..5008fe0 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"ეკრანის ანაბეჭდი ვერ შეიქმნა შეზღუდული სივრცის გამო, ან შეზღუდულია თქვენი ორგანიზაციის აპის მიერ."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ეკრანის ანაბეჭდის შენახვისას წარმოიქმნა პრობლემა."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ეკრანის ანაბეჭდის შენახვა ვერ მოხერხდა შეზღუდული მეხსიერების გამო."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ფაილის ტრანსფერის პარამეტრები"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"მედია-საკრავად (MTP) ჩართვა"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"მიუერთეთ როგორც კამერა (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-ის უგულებელყოფა."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ამოშლილია სიიდან."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ყველა ბოლო აპლიკაცია გაუქმდა."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> იწყება."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"შეტყობინება წაიშალა."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"მეტი დრო."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ნაკლები დრო."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ფანარი გამორთულია."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ფანარი მიუწვდომელია."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ფანარი ჩართულია."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ფანარი გამოირთო."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ფანარი ჩაირთო."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"სამსახურის რეჟიმი ჩართულია."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"სამსახურის რეჟიმი გამორთულია."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"სამსახურის რეჟიმი ჩართულია."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"მონაცემთა დამზოგველი გამორთულია."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"მონაცემთა დამზოგველი ჩართულია."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ეკრანის სიკაშკაშე"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G მონაცემები შეჩერებულია"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-ით დადგენილი მდებარეობა"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"მდებარეობის მოთხოვნები აქტიურია"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ყველა შეტყობინების წაშლა"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"შეტყობინების პარამეტრები"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> პარამეტრები"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ეკრანი შეტრიალდება ავტომატურად."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ლიმიტი: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> გაფრთხილება"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"სამსახურის რეჟიმი"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"თქვენი ბოლო ეკრანები აქ გამოჩნდება"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ყველაფერი გასუფთავდა"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ეკრანზე ჩამაგრება"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-ის გამოძახება ვერ მოხერხდა."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ისტორია"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"გასუფთავება"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> გათიშულია უსაფრთხო რეჟიმში."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ყველას გასუფთავება"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"მრავალი ფანჯრის რეჟიმი არ არის მხარდაჭერილი ამ აპის მიერ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"მრავალი ფანჯრის რეჟიმი არ არის მხარდაჭერილი აპის მიერ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ჰორიზონტალური გაყოფა"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ვერტიკალური გაყოფა"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ინდივიდუალური გაყობა"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"სრული\nსიჩუმე"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"მხოლოდ\nპრიორიტეტულები"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"მხოლოდ\nგაფრთხილებები"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"ყველა"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ყველა\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"იტენება სწრაფად (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"იტენება ნელა (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
     <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ზემოთ გადაფურცვლისას ეკრანის გაყოფის მაჩქარებლის ჩართვა"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ზემოთ გადაფურცვლისას ეკრანის გაყოფის ჟესტის ჩართვა"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"მიმოხილვის ღილაკიდან ზემოთ გადაფურცვლისას ეკრანის გაყოფის რეჟიმზე გადასვლის ჟესტის ჩართვა"</string>
     <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ჩართვა"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"„<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“ ტიპის შეტყობინებებისთვის მისადაგება"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ამ აპის ყველა შეტყობინებისთვის მისადაგება"</string>
+    <string name="show_silently" msgid="6841966539811264192">"შეტყობინებების უხმოდ ჩვენება"</string>
+    <string name="block" msgid="2734508760962682611">"ყველა შეტყობინების დაბლოკვა"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"არ გაჩუმდეს"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"არ გაჩუმდეს ან დაიბლოკოს"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"მნიშვნელობის დონის სრული პარამეტრების ჩვენება"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"დაბლოკილი"</string>
+    <string name="min_importance" msgid="1901894910809414782">"მინიმალური"</string>
     <string name="low_importance" msgid="4109929986107147930">"დაბალი პრიორიტეტი"</string>
     <string name="default_importance" msgid="8192107689995742653">"ჩვეულებრივი პრიორიტეტი"</string>
     <string name="high_importance" msgid="1527066195614050263">"მაღალი პრიორიტეტი"</string>
     <string name="max_importance" msgid="5089005872719563894">"გადაუდებელი"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ამ შეტყობინებების ჩვენების შეწყვეტა"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"ამ შეტყობინებების სიის ბოლოში, უხმოდ ჩვენება"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ამ შეტყობინებების უხმოდ ჩვენება"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"ამ შეტყობინებების სიის თავში, ხმოვან სიგნალთან ერთად ჩვენება"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"ამ შეტყობინებების პირდაპირ ეკრანზე, ხმოვან სიგნალთან ერთად ჩვენება"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"შეტყობინებების სიის ბოლოში, უხმოდ ჩვენება"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ამ შეტყობინებების უხმოდ ჩვენება"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ამ შეტყობინებებისთვის ხმის გამოცემის დაშვება"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"შეტყობინებების პირდაპირ ეკრანზე ჩვენება და ხმის დაშვება"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"შეტყობინებების სიის თავში ჩვენება, პირდაპირ ეკრანზე გამოჩენა და ხმის დაშვება"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
     <string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"ჩვეულებრივი ფერები"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"ღამის ფერები"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"მორგებული ფერები"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"ავტომატური"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"უცნობი ფერები"</string>
-    <string name="color_transform" msgid="6985460408079086090">"ფერების შეცვლა"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"სწრაფი პარამეტრების მოზაიკის ჩვენება"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"მორგებული გარდაქმნის ჩართვა"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეტყობინებების მართვის საშუალებები"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"ფერი და იერსახე"</string>
+    <string name="night_mode" msgid="3540405868248625488">"ღამის რეჟიმი"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ეკრანის კალიბრაცია"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ჩართული"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"გამორთული"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"ავტომატურად ჩართვა"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ღამის რეჟიმზე გადართვა მდებარეობისა და დღე-ღამის მონაკვეთის შესაბამისად."</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"ღამის რეჟიმის ჩართვისას"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS-ისთვის მუქი თემის გამოყენება"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ელფერის გასწორება"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"სიკაშკაშის გასწორება"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"მუქი თემა მიესადაგება Android OS-ის ძირითად არეებს, რომლებიც, ჩვეულებრივ, ღია თემის მეშვეობით არის ნაჩვენები. მაგალითად, პარამეტრებს."</string>
     <string name="color_apply" msgid="9212602012641034283">"გამოყენება"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"პარამეტრების დადასტურება"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"ფერთა ზოგიერთ პარამეტრს ამ მოწყობილობასთან მუშაობის გართულება შეუძლია. ფერთა ამჟამინდელი პარამეტრების დასადასტურებლად, დააწკაპუნეთ „კარგი“-ზე. წინააღმდეგ შემთხვევაში, პარამეტრები 10 წამის შემდეგ ჩამოიყრება."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"ბატარეის მოხმარება"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ბატარეის დამზოგი დატენვისას მიწვდომელია"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ბატარეის დამზოგი"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ამცირებს წარმადობას და ფონურ მონაცემებს"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"ღილაკი „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"უკან"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ზემოთ"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ქვემოთ"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"მარცხნივ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"მარჯვნივ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ცენტრში"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"შორისი"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"დაკვრა/პაუზა"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"შეწყვეტა"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"შემდეგი"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"წინა"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"უკან გადახვევა"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"წინ გადახვევა"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"რიცხვთა პანელი <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"სისტემა"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"მთავარი"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ბოლოს გამოყენებული"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"უკან"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"ხმის დიალოგში „არ შემაწუხოთ“ რეჟიმის ჩვენება"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ხმის დიალოგში „არ შემაწუხოთ“ რეჟიმის სრული კონტროლის დაშვება."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ხმა და „არ შემაწუხოთ“"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ხმის დაწევისას „არ შემაწუხოთ“ რეჟიმზე გადასვლა"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"შეტყობინებები"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"კლავიატურის მალსახმობები"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"შეყვანის მეთოდის გადართვა"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"აპლიკაციები"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"დახმარება"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ბრაუზერი"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"კონტაქტები"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ელფოსტა"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"მუსიკა"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"კალენდარი"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"ხმის მართვის საშუალებების ჩვენება"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"არ შემაწუხოთ"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ხმის ღილაკების მალსახმობი"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ხმის აწევისას „არ შემაწუხოთ“ რეჟიმიდან გამოსვლა"</string>
     <string name="battery" msgid="7498329822413202973">"ბატარეა"</string>
     <string name="clock" msgid="7416090374234785905">"საათი"</string>
     <string name="headset" msgid="4534219457597457353">"ყურსაცვამი"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ყურსასმენები დაკავშირებულია"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ყურსაცვამი დაკავშირებულია"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"სტატუსის ზოლში ხატულების ჩვენების ჩართვა ან გათიშვა."</string>
     <string name="data_saver" msgid="5037565123367048522">"მონაცემთა დამზოგველი"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"მონაცემთა დამზოგველი ჩართულია"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"მონაცემთა დამზოგველი გამორთულია"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ჩართული"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"გამორთვა"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ნავიგაციის ზოლი"</string>
     <string name="start" msgid="6873794757232879664">"თავში"</string>
     <string name="center" msgid="4327473927066010960">"ცენტრში"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"აირჩიეთ კლავიატურის ღილაკი"</string>
     <string name="preview" msgid="9077832302472282938">"გადახედვა"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ფილების დასამატებლად, გადაიტანეთ ჩავლებით"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ამოსაშლელად, ჩავლებით გადმოიტანეთ აქ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"რედაქტირება"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"დრო"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"საათების, წუთებისა და წამების ჩვენება"</item>
+    <item msgid="1427801730816895300">"საათებისა და წუთების ჩვენება (ნაგულისხმევი)"</item>
+    <item msgid="3830170141562534721">"აღარ მაჩვენო ეს ხატულა"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"პროცენტულობის ყოველთვის ჩვენება"</item>
+    <item msgid="2139628951880142927">"პროცენტულობის დატენვისას ჩვენება (ნაგულისხმევი)"</item>
+    <item msgid="3327323682209964956">"აღარ მაჩვენო ეს ხატულა"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"სხვა"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ქვემოთ გადატანა"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ზემოთ გადატანა"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"მარცხნივ გადატანა"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"მარჯვნივ გადატანა"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"აპმა შეიძლება არ იმუშაოს მრავალი ფანჯრის რეჟიმში"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. რედაქტირებისთვის, შეეხეთ ორმაგად."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. დასამატებლად, შეეხეთ ორმაგად."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>. ასარჩევად, შეეხეთ ორმაგად."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-ის გადატანა"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-ის წაშლა"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> დამატებულია პოზიციაზე <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ამოიშალა"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> გადატანილია პოზიციაზე <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"სწრაფი პარამეტრების რედაქტორი."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings_tv.xml b/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
new file mode 100644
index 0000000..7d615ba
--- /dev/null
+++ b/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP-ის დახურვა"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"სრულ ეკრანზე"</string>
+    <string name="pip_play" msgid="674145557658227044">"დაკვრა"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"პაუზა"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP-ის სამართავად, გეჭიროთ "<b>"მთავარ ღილაკზე"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP-ის სამართავად, ხანგრძლივად დააჭირეთ მთავარ ღილაკს"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"გასაგებია"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"დახურვა"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 1268e41..ff33f05 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"Шектеулі жад кеңістігіне байланысты скриншот түсіру мүмкін емес немесе бұған қолданба немесе ұйым рұқсат етпейді."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Скриншотты сақтау кезінде мәселе туындады."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Жадтағы шектеулі бос орынға байланысты скриншотты сақтау мүмкін емес."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB файлын жіберу опциялары"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойнатқыш (MTP) ретінде қосыңыз"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Камера ретінде (PTP) қосыңыз"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> қолданбасынан бас тарту."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> алынып тасталған."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Барлық жақындағы қабылданбаған қолданбалар."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> іске қосылуда."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Хабар алынып тасталды."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбірек уақыт."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азырақ уақыт."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Қол шам өшірулі."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Жарқыл қол жетімді емес."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Қол шам қосулы."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Қол шам өшірілді."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Қол шам қосылды."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Жұмыс режимі қосулы."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Жұмыс режимі өшірілді."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Жұмыс режимі қосылды."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Трафикті үнемдеу функциясы өшірілді."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Трафикті үнемдеу функциясы қосылды."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дисплей жарықтығы"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G деректері кідіртілді"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Орын GPS арқылы орнатылған"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Орын өтініштері қосылған"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Барлық хабарларды жойыңыз."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Хабарландыру параметрлері"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> параметрлері"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран автоматты түрде бұрылады."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> шегі"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Жұмыс режимі"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Мұнда жақындағы экрандар көрсетіледі"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Жақындағы элементтер жоқ"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Сіз барлығын өшірдіңіз"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Қолданба туралы ақпарат"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экранды бекіту"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Тарих"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалау"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> қауіпсіз режимде өшіріледі."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Барлығын тазалау"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бұл қолданба көп терезені қолдамайды"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Қолданба көп терезені қолдамайды"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Бөлінген тік"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Бөлінген теңшелетін"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Толық\nтыныштық"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Тек\nбасымдық"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Тек\nдабылдар"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Барлығы"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Барлығы\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Жылдам зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Баяу зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Бөлінген экранды жоғары қарай жанау жеделдеткішін қосу"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Бөлінген экранда жоғары қарай сырғыту қимылын қосу"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\"Шолу\" түймесінен жоғары қарай жанау арқылы бөлінген экранға кіру қимылын қосу"</string>
     <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Қосу"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> хабарландыруға қолдану"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Осы қолданбаның барлық хабарландыруларына қолдану"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Хабарландыруларды үнсіз көрсету"</string>
+    <string name="block" msgid="2734508760962682611">"Барлық хабарландыруларды бұғаттау"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Үнін өшірмеу"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Үнін өшірмеу немесе бұғаттамау"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Толық маңыздылық параметрлерін көрсету"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Бөгелген"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Ең аз маңыздылық"</string>
     <string name="low_importance" msgid="4109929986107147930">"Төмен маңыздылық"</string>
     <string name="default_importance" msgid="8192107689995742653">"Қалыпты маңыздылық"</string>
     <string name="high_importance" msgid="1527066195614050263">"Жоғары маңыздылық"</string>
     <string name="max_importance" msgid="5089005872719563894">"Шұғыл маңыздылық"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Осы хабарландыруларды ешқашан көрсетпеу"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Осы хабарландыруларды үнсіз көрсету"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Хабарландыруларды тізімінің жоғарғы жағында көрсету және дыбыс шығару"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Экранға бекіту және дыбыс шығару"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Осы хабарландыруларды үнсіз көрсету"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Осы хабарландыруға дыбыстар шығаруға рұқсат ету"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Экранда көрсету және дыбыс шығаруға рұқсат ету"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Хабарландырулар тізімінің жоғарғы жағында көрсету, экранда көрсету және дыбысқа рұқсат ету"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
     <string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Қалыпты түстер"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Түнгі түстер"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Арнаулы түстер"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Белгісіз түстер"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Түсті өзгерту"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Жылдам параметрлер торын көрсету"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Арнаулы түрлендіруді қосу"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> хабарландыруларды басқару элементтері"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Түс және сыртқы түрі"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Түнгі режим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Дисплейді калибрлеу"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Қосулы"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Өшірулі"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматты түрде қосу"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Орынға және күн уақытына тиісті түнгі режимге ауысу"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Түнгі режим қосулы кезде"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android ОЖ үшін күңгірт тақырыпты пайдалану"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Реңкті реттеу"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Жарықтықты реттеу"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Күңгірт тақырып Android операциялық жүйесінің әдетте \"Параметрлер\" сияқты ашық тақырыпта көрсетілетін негізгі аумақтарына қолданылады."</string>
     <string name="color_apply" msgid="9212602012641034283">"Қолдану"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Параметрлерді растау"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Кейбір түс параметрлері бұл құрылғыны пайдалану мүмкін емес етуі мүмкін. Бұл түс параметрлерін растау үшін OK түймесін басыңыз, әйтпесе параметрлер 10 секундтан кейін ысырылады."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Батареяны пайдалану"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Зарядтау кезінде Батарея үнемдегіш қол жетімді емес"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Батарея үнемдегіш"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Өнімділікті және фондық деректерді азайтады"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> түймесі"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Артқа"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Жоғары"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Төмен"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Сол"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Оң"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Орталық"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Бос орын"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Ойнату/кідірту"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Тоқтату"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Келесі"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Алдыңғы"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Кері айналдыру"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Алға айналдыру"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Сандық пернетақта <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Жүйе"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Негізгі бет"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Жақындағылар"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артқа"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Дыбыс деңгейінде \"Мазаламау\" режимін көрсету"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дыбыс деңгейі диалогтық терезесінде \"Мазаламау\" режимін толық басқаруға рұқсат ету."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Дыбыс деңгейі және \"Мазаламау\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Дыбыс деңгейін төмендеткенде \"Мазаламау\" режиміне кіру"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Хабарландырулар"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Пернелер тіркесімдері"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Енгізу әдісін ауыстыру"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Қолданбалар"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Көмекші"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузер"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контактілер"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электрондық пошта"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Mузыка"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Күнтізбе"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Дыбыс деңгейін басқару элементтерімен бірге көрсету"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Мазаламау"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Дыбыс деңгейі түймелерінің төте жолы"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Дыбыс деңгейін көтергенде \"Мазаламау\" режимінен шығу"</string>
     <string name="battery" msgid="7498329822413202973">"Батарея"</string>
     <string name="clock" msgid="7416090374234785905">"Сағат"</string>
     <string name="headset" msgid="4534219457597457353">"Құлақаспап жинағы"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Құлақаспап қосылды"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Құлақаспап жинағы қосылды"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Белгішелердің күй жолағында көрсетілуін қосу немесе өшіру"</string>
     <string name="data_saver" msgid="5037565123367048522">"Дерек сақтағыш"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Дерек сақтағыш қосулы"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Дерек сақтағышы өшірулі"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Қосулы"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Өшірулі"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Шарлау тақтасы"</string>
     <string name="start" msgid="6873794757232879664">"Бастау"</string>
     <string name="center" msgid="4327473927066010960">"Орталық"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Пернетақта түймесін таңдау"</string>
     <string name="preview" msgid="9077832302472282938">"Алдын ала қарау"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Торлар қосу үшін сүйреңіз"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Жою үшін осы жерге сүйреңіз"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Өңдеу"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Уақыт"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Сағаттарды, минуттарды және секундтарды көрсету"</item>
+    <item msgid="1427801730816895300">"Сағаттарды және минуттарды көрсету (әдепкі)"</item>
+    <item msgid="3830170141562534721">"Бұл белгішені көрсетпеу"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Әрқашан пайызды көрсету"</item>
+    <item msgid="2139628951880142927">"Зарядтау кезінде пайызды көрсету (әдепкі)"</item>
+    <item msgid="3327323682209964956">"Бұл белгішені көрсетпеу"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Басқа"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Бөлінген экран бөлгіші"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмен қарай жылжыту"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жоғары қарай жылжыту"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солға жылжыту"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңға жылжыту"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Қолданба көп тереземен жұмыс істемеуі мүмкін"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> орны, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Өңдеу үшін екі рет түртіңіз."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Қосу үшін екі рет түртіңіз."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> орны. Таңдау үшін екі рет түртіңіз."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жылжыту"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жою"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> орнына қосылды"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жойылды"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> орнына жылжытылды"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Жылдам параметрлер өңдегіші."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml b/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
new file mode 100644
index 0000000..06c84a8
--- /dev/null
+++ b/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP жабу"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Толық экран"</string>
+    <string name="pip_play" msgid="674145557658227044">"Ойнату"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Кідірту"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP басқару үшін "<b>"HOME"</b>" басып тұрыңыз"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP функциясын басқару үшін HOME түймесін басып тұрыңыз"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Түсіндім"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Жабу"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 74b1faf..b69f893 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"មិនអាចថតអេក្រង់ដោយសារតែទំហំផ្ទុកមានដែនកំណត់ ឬវាមិនត្រូវបានអនុញ្ញាត​ដោយកម្មវិធី ឬ​ស្ថាប័ន​របស់​អ្នក។"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"បានជួបប្រទះបញ្ហាខណៈពេលរក្សាទុកការថតអេក្រង់"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"មិនអាចរក្សាទុករូបថតអេក្រង់បានទេដោយសារទំហំផ្ទុកមានកម្រិត។"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ការថតរូបអេក្រង់មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធីនេះ ឬស្ថាប័នរបស់អ្នក។"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"ជម្រើស​ផ្ទេរ​ឯកសារ​តាម​យូអេសប៊ី"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ភ្ជាប់​ជា​កម្មវិធី​ចាក់​មេឌៀ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ភ្ជាប់​ជា​ម៉ាស៊ីន​ថត (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"បោះបង់ <xliff:g id="APP">%s</xliff:g> ។"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"កម្មវិធីថ្មីៗទាំងអស់ត្រូវបានបោះបង់។"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ។"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"បាន​បដិសេធ​ការ​ជូនដំណឹង"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ច្រើនជាង"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"តិច​ជាង"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"បិទ​ពិល។"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ពិលមិនអាចប្រើបានទេ"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"បើក​ពិល។"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"បាន​បិទ​ពិល។"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"បាន​បើក​ពិល។"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"បើករបៀបការងារ"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"បានបិទរបៀបការងារ"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"បានបើករបៀបការងារ"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"បានបិទកម្មវិធីសន្សំសំចៃទិន្នន័យ"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"បានបើកកម្មវិធីសន្សំសំចៃទិន្នន័យ"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ពន្លឺ​ការ​បង្ហាញ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"ទិន្នន័យ 2G-3G ត្រូវបានផ្អាក"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"ទីតាំង​​​​​កំណត់​ដោយ GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"សំណើ​ទីតាំង​សកម្ម"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"សម្អាត​ការ​ជូន​ដំណឹង​ទាំងអស់។"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"​កំណត់​ការ​ជូនដំណឹង"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"ការ​កំណត់ <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"នឹង​បង្វិល​អេក្រង់​ស្វ័យ​ប្រវត្តិ។"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ដែន​កំណត់ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ការ​ព្រមាន"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"របៀបការងារ"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"អេក្រង់​បច្ចុប្បន្ន​របស់​អ្នក​បង្ហាញ​នៅ​ទីនេះ"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"មិនមានធាតុថ្មីៗទេ"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"អ្នកបានជម្រះអ្វីៗទាំងអស់"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ការ​ភ្ជាប់​អេក្រង់"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"មិន​អាច​ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ទេ។"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ប្រវត្តិ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"សម្អាត"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ត្រូវបានបិទដំណើរការក្នុងរបៀបសុវត្ថិភាព"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ជម្រះទាំងអស់"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"កម្មវិធីនេះមិនគាំទ្រផ្ទាំងវិដូច្រើនទេ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"កម្មវិធីមិនគាំទ្រផ្ទាំងវិដូច្រើនទេ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"បំបែកផ្តេក"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"បំបែកបញ្ឈរ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"បំបែកផ្ទាល់ខ្លួន"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"ស្ងៀមស្ងាត់\nទាំងស្រុង"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"អាទិភាព\nប៉ុណ្ណោះ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"សំឡេងរោទ៍\nប៉ុណ្ណោះ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"ទាំងអស់"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ទាំងអស់\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុង​បញ្ចូល​ថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើប​ពេញ)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ថ្មកំពុងសាកលឿន (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ថ្មកំពុងសាកយឺតៗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"បើកដំណើរការឧបករណ៍បង្កើនល្បឿនការអូសទៅលើដើម្បីបំបែកអេក្រង់"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"បើកដំណើរការកាយវិការអូសទៅលើដើម្បីបំបែកអេក្រង់"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"បើកដំណើរការកាយវិការដើម្បីបំបែកអេក្រង់ដោយអូសទៅលើចាប់ពីប៊ូតុងទិដ្ឋភាព"</string>
     <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"បើកប៊្លូធូសឬ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ដើម្បីភ្ជាប់ក្តារចុចរបស់អ្នកជាមួយនឹងថេប្លេតរបស់អ្នក អ្នកត្រូវតែបើកប៊្លូធូសជាមុនសិន។"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"បើក"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"អនុវត្តចំពោះការជូនដំណឹង <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"អនុវត្តចំពោះការជូនដំណឹងទាំងអស់ពីកម្មវិធីនេះ"</string>
+    <string name="show_silently" msgid="6841966539811264192">"បង្ហាញការជូនដំណឹងស្ងាត់ៗ"</string>
+    <string name="block" msgid="2734508760962682611">"រារាំងការជូនដំណឹងទាំងអស់"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"កុំបិទសំឡេង"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"កុំបិទសំឡេង ឬរារាំង"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"បង្ហាញការកំណត់កម្រិតភាពសំខាន់ពេញលេញ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"បានរារាំង"</string>
+    <string name="min_importance" msgid="1901894910809414782">"កម្រិតសំខាន់អប្បបរមា"</string>
     <string name="low_importance" msgid="4109929986107147930">"មិនសូវសំខាន់"</string>
     <string name="default_importance" msgid="8192107689995742653">"សំខាន់មធ្យម"</string>
     <string name="high_importance" msgid="1527066195614050263">"សំខាន់ខ្លាំង"</string>
     <string name="max_importance" msgid="5089005872719563894">"សំខាន់ជាបន្ទាន់"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"កុំបង្ហាញការជូនដំណឹងទាំងនេះ"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង និងបន្លឺសំឡេង"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"លោតបង្ហាញនៅលើអេក្រង់ និងបន្លឺសំឡេង"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"អនុញ្ញាតឲ្យការជូនដំណឹងទាំងនេះបន្លឺសំឡេង"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"លោតបង្ហាញនៅលើអេក្រង់ និងអនុញ្ញាតឲ្យបន្លឺសំឡេង"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង លោតបង្ហាញនៅលើអេក្រង់ និងអនុញ្ញាតឲ្យបន្លឺសំឡេង"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
     <string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"ពណ៌ធម្មតា"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"ពណ៌ពេលយប់"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"ពណ៌ផ្ទាល់ខ្លួន"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"ស្វ័យប្រវត្តិ"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"ពណ៌មិនស្គាល់"</string>
-    <string name="color_transform" msgid="6985460408079086090">"ការកែសម្រួលពណ៌"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"បង្ហាញផ្ទាំងប្រអប់ការកំណត់រហ័ស"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"បើកដំណើរការផ្លាស់ប្តូរផ្ទាល់ខ្លួន"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"អង្គគ្រប់គ្រងការជូនដំណឹង <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"ពណ៌ និងរូបរាង"</string>
+    <string name="night_mode" msgid="3540405868248625488">"របៀបពេលយប់"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ការបង្ហាញក្រិត"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"បើក"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"បិទ"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"បើក​ដោយ​ស្វ័យ​ប្រវត្តិ"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ប្តូរទៅជារបៀបពេលយប់ដែលសមស្របទៅតាមទីកន្លែង និងពេលវេលា"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"នៅពេលបើករបៀបពេលយប់"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"ប្រើធីមងងឹតសម្រាប់ប្រព័ន្ធប្រតិបត្តិការ Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"កែសម្រួលពណ៌ព្រឿងៗ"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"កែសម្រួលពន្លឺ"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ធីមងងឹតត្រូវបានប្រើសម្រាប់ចំណុចស្នូលនៃប្រព័ន្ធប្រតិបត្តិការ Android ដែលជាទូទៅត្រូវបានបង្ហាញជាធីមភ្លឺ ដូចជាការកំណត់ជាដើម។"</string>
     <string name="color_apply" msgid="9212602012641034283">"អនុវត្ត"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"បញ្ជាក់ការកំណត់"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"ការកំណត់ពណ៌មួយចំនួនអាចធ្វើឲ្យឧបករណ៍នេះមិនអាចប្រើបាន។ សូមចុច យល់ព្រម ដើម្បីបញ្ជាក់ការកំណត់ពណ៌ទាំងនេះ បើមិនដូច្នេះទេការកំណត់ទាំងនេះនឹងកំណត់ឡើងវិញក្នុងរយៈពេល 10 វិនាទីបន្ទាប់។"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"ការប្រើប្រាស់ថ្ម"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"កម្មវិធីសន្សំថ្មមិនអាចប្រើបានអំឡុងពេលសាកថ្មទេ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"កម្មវិធីសន្សំថ្ម"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"កាត់បន្ថយប្រតិបត្តិការ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"ប៊ូតុង <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ប្រព័ន្ធ"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ដើម"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ថ្មីៗ"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ថយក្រោយ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"បង្ហាញមុខងារកុំរំខាននៅក្នុងកម្រិតសំឡេង"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"អនុញ្ញាតឲ្យមានការគ្រប់គ្រងពេញលេញចំពោះមុខងារកុំរំខាននៅក្នុងប្រអប់កម្រិតសំឡេង។"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"កម្រិតសំឡេង និងមុនងារកុំរំខាន"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ចូលមុខងារកុំរំខាននៅពេលបន្ថយសំឡេង"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ការជូនដំណឹង"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ផ្លូវកាត់ក្ដារចុច"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ប្ដូរវិធីសាស្ត្របញ្ចូល"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"កម្មវិធី"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ជំនួយ"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"កម្មវិធីរុករក"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ទំនាក់ទំនង"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"អ៊ីមែល"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"តន្ត្រី"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ប្រតិទិន"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"បង្ហាញជាមួយការគ្រប់គ្រងកម្រិតសំឡេង"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"កុំ​រំខាន"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ផ្លូវកាត់ប៊ូតុងកម្រិតសំឡេង"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ចាកចេញពីមុខងារកុំរំខាននៅពេលបង្កើនសំឡេង"</string>
     <string name="battery" msgid="7498329822413202973">"ថ្ម"</string>
     <string name="clock" msgid="7416090374234785905">"នាឡិកា"</string>
     <string name="headset" msgid="4534219457597457353">"កាស"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"បានភ្ជាប់កាស"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"បានភ្ជាប់កាស"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"បើក ឬបិទដំណើរការបង្ហាញរូបតំណាងនៅលើរបារស្ថានភាព"</string>
     <string name="data_saver" msgid="5037565123367048522">"កម្មវិធីសន្សំសំចៃទិន្នន័យ"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"កម្មវិធីសន្សំសំចៃទិន្នន័យបានបើក"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"កម្មវិធីសន្សំសំចៃទិន្នន័យបានបិទ"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"បើក"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"បិទ"</string>
     <string name="nav_bar" msgid="1993221402773877607">"របាររុករក"</string>
     <string name="start" msgid="6873794757232879664">"ចាប់ផ្ដើម"</string>
     <string name="center" msgid="4327473927066010960">"កណ្តាល"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"ជ្រើសប៊ូតុងក្តារចុច"</string>
     <string name="preview" msgid="9077832302472282938">"មើលជាមុន"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"អូសដើម្បីបន្ថែមចំណងជើង"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"អូសទីនេះដើម្បីយកចេញ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"កែសម្រួល"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"ម៉ោង"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"បង្ហាញម៉ោង នាទី និងវិនាទី"</item>
+    <item msgid="1427801730816895300">"បង្ហាញម៉ោង នាទី (លំនាំដើម)"</item>
+    <item msgid="3830170141562534721">"កុំបង្ហាញរូបតំណាងនេះ"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"បង្ហាញភាគរយជានិច្ច"</item>
+    <item msgid="2139628951880142927">"បង្ហាញភាគរយនៅពេលសាកថ្ម (លំនាំដើម)"</item>
+    <item msgid="3327323682209964956">"កុំបង្ហាញរូបតំណាងនេះ"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"ផ្សេងៗ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"កម្មវិធីចែកអេក្រង់បំបែក"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ផ្លាស់ទីចុះក្រោម"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ផ្លាស់ទីឡើងលើ"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ផ្លាស់ទីទៅឆ្វេង"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ផ្លាស់ទីទៅស្តាំ"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"កម្មវិធីអាចនឹងមិនដំណើរការជាមួយពហុវិនដូទេ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ទីតាំង <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>, ប៉ះពីរដងដើម្បីកែ"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>, ប៉ះពីរដងដើម្បីបន្ថែម"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ទីតាំង <xliff:g id="POSITION">%1$d</xliff:g>, ប៉ះពីរដងដើម្បីជ្រើស"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ផ្លាស់ទី <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"យក <xliff:g id="TILE_NAME">%1$s</xliff:g> ចេញ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ត្រូវបានបន្ថែមទៅទីតាំង <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ត្រូវបានយកចេញ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> បានផ្លាស់ទីទៅទីតាំង <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"កម្មវិធីកែការកំណត់រហ័ស"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings_tv.xml b/packages/SystemUI/res/values-km-rKH/strings_tv.xml
new file mode 100644
index 0000000..123cb76
--- /dev/null
+++ b/packages/SystemUI/res/values-km-rKH/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"បិទ PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"ពេញអេក្រង់"</string>
+    <string name="pip_play" msgid="674145557658227044">"ចាក់"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"ផ្អាក"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"សង្កត់ប៊ូតុង "<b>"ដើម"</b>" ដើម្បីគ្រប់គ្រង PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"ចុច និងសង្កត់ប៊ូតុង ដើម ដើម្បីគ្រប់គ្រង PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"យល់ហើយ"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"បដិសេធ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 5ab6e31..1ce14dd5 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"ಪರಿಮಿತ ಸಂಗ್ರಹಣೆ ಸ್ಥಳ, ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಅನುಮತಿಯಿಲ್ಲದಿರುವ ಕಾರಣ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸುವಲ್ಲಿ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ಪರಿಮಿತ ಸಂಗ್ರಹಣೆ ಸ್ಥಳದ ಕಾರಣದಿಂದಾಗಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳುವುದನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆ ಅನುಮತಿಸುವುದಿಲ್ಲ."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ಫೈಲ್ ವರ್ಗಾವಣೆ ಆಯ್ಕೆಗಳು"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ಮೀಡಿಯಾ ಪ್ಲೇಯರ್ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ಕ್ಯಾಮರಾ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸು."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ಇತ್ತೀಚಿನ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ಹೆಚ್ಚು ಸಮಯ."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ಕಡಿಮೆ ಸಮಯ."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆಫ್ ಆಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಲಭ್ಯವಿಲ್ಲ."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆನ್ ಆಗಿದೆ."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಆಗಿದೆ."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ಡೇಟಾ ಸೇವರ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ಹೊಳಪನ್ನು ಪ್ರದರ್ಶಿಸಿ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ಡೇಟಾವನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"ಸ್ಥಾನವನ್ನು GPS ಮೂಲಕ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"ಸ್ಥಾನ ವಿನಂತಿಗಳು ಸಕ್ರಿಯವಾಗಿವೆ"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸು."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ಅಧಿಸೂಚನೆ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ಪರದೆಯು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಿರುಗುತ್ತದೆ."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಮಿತಿ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ಕೆಲಸದ ಮೋಡ್"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"ನಿಮ್ಮ ಇತ್ತೀಚಿನ ಪರದೆಗಳು ಇಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ನೀವು ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿರುವಿರಿ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ಸ್ಕ್ರೀನ್ ಪಿನ್ನಿಂಗ್"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ಹುಡುಕಾಟ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲು ಸಾದ್ಯವಿಲ್ಲ."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್‌ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ಇತಿಹಾಸ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ತೆರವುಗೊಳಿಸು"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸು"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಬಹು-ವಿಂಡೊಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ಅಪ್ಲಿಕೇಶನ್ ಬಹು-ವಿಂಡೊಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ಲಂಬವಾಗಿ ವಿಭಜಿಸಿದ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ಕಸ್ಟಮ್ ವಿಭಜಿಸಿದ"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"ಸಂಪೂರ್ಣ\nನಿಶ್ಯಬ್ಧ"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ಆದ್ಯತೆ\nಮಾತ್ರ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ಅಲಾರಮ್‌ಗಳು\nಮಾತ್ರ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"ಎಲ್ಲ"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ಎಲ್ಲಾ\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ನಿಧಾನ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಸ್ವೈಪ್-ಅಪ್ ವೇಗವರ್ಧಕವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಸ್ವೈಪ್-ಅಪ್ ಗೆಶ್ಚರ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ಸಮಗ್ರ ನೋಟದ ಬಟನ್‌ನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಸ್ಪ್ಲಿಟ್‌-ಸ್ಕ್ರೀನ್ ನಮೂದಿಸಲು ಗೆಸ್ಚರ್‌ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಟ್ಯಾಬ್ಲೆಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು, ನೀವು ಮೊದಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ಆನ್ ಮಾಡು"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆಗಳಿಗೆ ಅನ್ವಯಿಸಿ"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ಈ ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳಿಗೆ ಅನ್ವಯಿಸಿ"</string>
+    <string name="show_silently" msgid="6841966539811264192">"ಸ್ಥಬ್ಧವಾಗಿ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string>
+    <string name="block" msgid="2734508760962682611">"ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ಮೌನವಾಗಿಸಬೇಡಿ"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ಸ್ಥಬ್ದ ಅಥವಾ ನಿರ್ಬಂಧಿಸಬೇಡಿ"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ಪೂರ್ಣ ಪ್ರಾಮುಖ್ಯತೆ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
+    <string name="min_importance" msgid="1901894910809414782">"ಕನಿಷ್ಟ ಪ್ರಾಮುಖ್ಯತೆ"</string>
     <string name="low_importance" msgid="4109929986107147930">"ಕಡಿಮೆ ಪ್ರಾಮುಖ್ಯತೆ"</string>
     <string name="default_importance" msgid="8192107689995742653">"ಸಾಮಾನ್ಯ ಪ್ರಾಮುಖ್ಯತೆ"</string>
     <string name="high_importance" msgid="1527066195614050263">"ಉನ್ನತ ಪ್ರಾಮುಖ್ಯತೆ"</string>
     <string name="max_importance" msgid="5089005872719563894">"ತುರ್ತು ಪ್ರಾಮುಖ್ಯತೆ"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಎಂದಿಗೂ ತೋರಿಸಬೇಡ"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ಈ ಅಧಿಸೂಚನೆಯು ಧ್ವನಿಗಳನ್ನು ಮಾಡಲು ಅನುಮತಿಸಿ"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಅನುಮತಿಸಿ ಮತ್ತು ಧ್ವನಿ ಅನುಮತಿಸಿ"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು, ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಅನುಮತಿಸಿ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"ಸಾಮಾನ್ಯ ಬಣ್ಣಗಳು"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"ರಾತ್ರಿ ಬಣ್ಣಗಳು"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"ಕಸ್ಟಮ್ ಬಣ್ಣಗಳು"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"ಸ್ವಯಂ"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"ಅಪರಿಚಿತ ಬಣ್ಣಗಳು"</string>
-    <string name="color_transform" msgid="6985460408079086090">"ಬಣ್ಣ ಬದಲಾವಣೆ"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಟೈಲ್ ತೋರಿಸು"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"ಕಸ್ಟಮ್ ಪರಿವರ್ತನೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"ಬಣ್ಣ ಮತ್ತು ಗೋಚರತೆ"</string>
+    <string name="night_mode" msgid="3540405868248625488">"ರಾತ್ರಿ ಮೋಡ್"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ಅಣಿಗೊಳಿಸುವ ಪ್ರದರ್ಶನ"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ಆನ್"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ಆಫ್"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಆನ್ ಮಾಡು"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ಸ್ಥಳ ಮತ್ತು ದಿನದ ಸಮಯಕ್ಕೆ ಸೂಕ್ತವಾಗುವಂತೆ ರಾತ್ರಿ ಮೋಡ್‌ ಅನ್ನು ಬದಲಾಯಿಸಿ"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"ರಾತ್ರಿ ಮೋಡ್‌ ಆನ್‌ ಆಗಿರುವಾಗ"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS ಗೆ ಕಪ್ಪು ಥೀಮ್‌ ಬಳಸಿ"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ಟಿಂಟ್‌ ಸರಿಹೊಂದಿಸು"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ಪ್ರಖರತೆಯನ್ನು ಸರಿಹೊಂದಿಸು"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ಕಪ್ಪು ಥೀಮ್‌ ಅನ್ನು Android OS ನ ಕೋರ್‌ ಪ್ರದೇಶಗಳಿಗೆ ಅನ್ವಯಿಸಲಾಗಿರುತ್ತದೆ. ಇದನ್ನು ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಂತಹ ತಿಳಿಯಾದ ಥೀಮ್‌ನಲ್ಲಿ ಸಾಮಾನ್ಯವಾಗಿ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="color_apply" msgid="9212602012641034283">"ಅನ್ವಯಿಸು"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಖಚಿತಪಡಿಸಿ"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"ಕೆಲವು ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಈ ಸಾಧನವನ್ನು ಅನುಪಯುಕ್ತಗೊಳಿಸಬಹುದು. ಈ ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಖಚಿತಪಡಿಸಲು ಸರಿ ಕ್ಲಿಕ್ ಮಾಡಿ, ಇಲ್ಲವಾದರೆ ಈ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು 10 ಸೆಕೆಂಡುಗಳ ನಂತರ ಮರುಹೊಂದಿಸಿ."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ಚಾರ್ಜಿಂಗ್ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಸೇವರ್‌‌ ಲಭ್ಯವಿರುವುದಿಲ್ಲ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ಬ್ಯಾಟರಿ ಸೇವರ್‌‌"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> ಬಟನ್"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"ಹಿಂದೆ"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ಮೇಲೆ"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ಕೆಳಗೆ"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ಎಡ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ಬಲ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ಮಧ್ಯ"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"ಸ್ಪೇಸ್"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"ಮುಂದೆ"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ಹಿಂದೆ"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ಫಾಸ್ಟ್ ಫಾರ್ವರ್ಡ್"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> ಸಂಖ್ಯೆಪ್ಯಾಡ್"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ಸಿಸ್ಟಂ"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ಮುಖಪುಟ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ಇತ್ತೀಚಿನವುಗಳು"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ಹಿಂದೆ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"ವಾಲ್ಯೂಮ್‌ನಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\" ಅನ್ನು ತೋರಿಸಿ"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ವಾಲ್ಯೂಮ್ ಸಂವಾದದಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\"ಯ ಸಂಪೂರ್ಣ ನಿಯಂತ್ರಣವನ್ನು ಅನುಮತಿಸಿ."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ವಾಲ್ಯೂಮ್‌ ಮತ್ತು ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ವಾಲ್ಯೂಮ್ ಕಡಿಮೆಯಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\" ನಮೂದಿಸಿ"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ಅಧಿಸೂಚನೆಗಳು"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ಇನ್‌ಪುಟ್‌‌ ವಿಧಾನ ಬದಲಿಸಿ"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ಸಹಾಯ ಮಾಡು"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ಬ್ರೌಸರ್"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ಸಂಪರ್ಕಗಳು"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ಇಮೇಲ್"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ಸಂಗೀತ"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ಕ್ಯಾಲೆಂಡರ್"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"ವಾಲ್ಯೂಮ್ ನಿಯಂತ್ರಣಗಳ ಜೊತೆಗೆ ತೋರಿಸು"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ವಾಲ್ಯೂಮ್ ಬಟನ್‌ಗಳ ಶಾರ್ಟ್‌ಕಟ್‌"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ವಾಲ್ಯೂಮ್ ಹೆಚ್ಚಳದಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\"ಯನ್ನು ತೊರೆಯಿರಿ"</string>
     <string name="battery" msgid="7498329822413202973">"ಬ್ಯಾಟರಿ"</string>
     <string name="clock" msgid="7416090374234785905">"ಗಡಿಯಾರ"</string>
     <string name="headset" msgid="4534219457597457353">"ಹೆಡ್‌ಸೆಟ್"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ಹೆಡ್‌ಫೋನ್ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ಹೆಡ್‌ಸೆಟ್ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಐಕಾನ್‌ಗಳು ತೋರಿಸುವುದನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ."</string>
     <string name="data_saver" msgid="5037565123367048522">"ಡೇಟಾ ಉಳಿಸುವಿಕೆ"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ಡೇಟಾ ಉಳಿಸುವಿಕೆ ಆನ್ ಆಗಿದೆ"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ಡೇಟಾ ಉಳಿಸುವಿಕೆ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ಆನ್"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ಆಫ್"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
     <string name="start" msgid="6873794757232879664">"ಪ್ರಾರಂಭ"</string>
     <string name="center" msgid="4327473927066010960">"ಮಧ್ಯ"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"ಕೀಬೋರ್ಡ್ ಬಟನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="preview" msgid="9077832302472282938">"ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ಟೈಲ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ತೆಗೆದುಹಾಕಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ಸಂಪಾದಿಸು"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"ಸಮಯ"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"ಗಂಟೆಗಳು, ನಿಮಿಷಗಳು, ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು"</item>
+    <item msgid="1427801730816895300">"ಗಂಟೆಗಳು ಮತ್ತು ನಿಮಿಷಗಳನ್ನು ತೋರಿಸು (ಡಿಫಾಲ್ಟ್‌)"</item>
+    <item msgid="3830170141562534721">"ಈ ಐಕಾನ್ ತೋರಿಸಬೇಡ"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"ಯಾವಾಗಲೂ ಪ್ರತಿಶತವನ್ನು ತೋರಿಸು"</item>
+    <item msgid="2139628951880142927">"ಚಾರ್ಜ್‌ ಮಾಡುವಾಗ ಪ್ರತಿಶತವನ್ನು ತೋರಿಸು (ಡಿಫಾಲ್ಟ್‌)"</item>
+    <item msgid="3327323682209964956">"ಈ ಐಕಾನ್ ತೋರಿಸಬೇಡ"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"ಇತರ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ಕೆಳಗೆ ಸರಿಸಿ"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ಮೇಲೆ ಸರಿಸಿ"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"ಬಹು ವಿಂಡೋದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. ಸಂಪಾದಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ಸೇರಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>. ಆಯ್ಕೆಮಾಡಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ಸರಿಸಿ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ತೆಗೆದುಹಾಕಿ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ <xliff:g id="TILE_NAME">%1$s</xliff:g> ಸೇರಿಸಲಾಗಿದೆ"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="POSITION">%2$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ <xliff:g id="TILE_NAME">%1$s</xliff:g> ಸೇರಿಸಲಾಗಿದೆ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳ ಸಂಪಾದಕ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
new file mode 100644
index 0000000..6491587
--- /dev/null
+++ b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP ಮುಚ್ಚಿ"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"ಪೂರ್ಣ ಪರದೆ"</string>
+    <string name="pip_play" msgid="674145557658227044">"ಪ್ಲೇ"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"ವಿರಾಮ"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP ನಿಯಂತ್ರಿಸಲು "<b>"HOME"</b>" ಕೀಯನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP ನಿಯಂತ್ರಿಸಲು HOME ಬಟನ್ ಒತ್ತಿರಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"ಅರ್ಥವಾಯಿತು"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"ವಜಾಗೊಳಿಸಿ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 5e6f65a..a8a2a0a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"저장 공간이 부족하거나 앱 또는 소속 조직에서 허용하지 않아 스크린샷을 찍을 수 없습니다."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"스크린샷을 저장하는 중 문제가 발생했습니다."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"저장용량이 부족하여 스크린샷을 저장할 수 없습니다."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"앱이나 조직에서 스크린샷 촬영을 허용하지 않습니다."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 파일 전송 옵션"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"미디어 플레이어로 마운트(MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"카메라로 마운트(PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>을(를) 숨깁니다."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>이(가) 제거되었습니다."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"최근 사용한 애플리케이션을 모두 닫았습니다."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>을(를) 시작하는 중입니다."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"알림이 제거되었습니다."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"시간 늘리기"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"시간 줄이기"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"손전등: 사용 중지"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"손전등을 사용할 수 없습니다."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"손전등: 사용"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"손전등이 사용 중지되었습니다."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"손전등을 사용합니다."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"작업 모드가 사용 설정되었습니다."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"작업 모드가 사용 중지되었습니다."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"작업 모드가 사용 설정되었습니다."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"데이터 세이버를 사용 중지했습니다."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"데이터 세이버를 사용 설정했습니다."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"디스플레이 밝기"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 데이터 사용 중지됨"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"위치 요청 있음"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"모든 알림 지우기"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g>개 더보기"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"알림 설정"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> 설정"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"화면이 자동으로 회전됩니다."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"한도: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 경고"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"작업 모드"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"여기에 최근 화면이 표시됩니다."</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"최근 항목이 없습니다."</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"모든 항목을 삭제했습니다."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"화면 고정"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>을(를) 시작할 수 없습니다."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"기록"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"삭제"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>은(는) 안전 모드에서 사용 중지됩니다."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"모두 지우기"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"이 앱은 다중 창을 지원하지 않습니다."</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"앱이 다중 창을 지원하지 않습니다."</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"수평 분할"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"수직 분할"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"맞춤 분할"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"모두\n차단"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"중요 알림만\n허용"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"알람만\n"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"모두 수신"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"모두\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"고속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"저속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
     <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"위로 스와이프하여 창 분할하기 사용 설정"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"화면 분할 위로 스와이프 동작 사용"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"최근 사용 버튼에서 위로 스와이프하기 동작으로 창 분할 모드를 사용 설정합니다."</string>
     <string name="experimental" msgid="6198182315536726162">"베타"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"블루투스를 켜시겠습니까?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"키보드를 태블릿에 연결하려면 먼저 블루투스를 켜야 합니다."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"사용"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> 알림에 적용"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"이 앱의 전체 알림에 적용"</string>
+    <string name="show_silently" msgid="6841966539811264192">"무음으로 알림 표시"</string>
+    <string name="block" msgid="2734508760962682611">"모든 알림 차단"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"무음 모드 사용 안함"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"무음 모드 또는 차단 사용 안함"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"전체 중요도 설정 표시"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"차단됨"</string>
+    <string name="min_importance" msgid="1901894910809414782">"중요도 최소"</string>
     <string name="low_importance" msgid="4109929986107147930">"중요도 낮음"</string>
     <string name="default_importance" msgid="8192107689995742653">"중요도 보통"</string>
     <string name="high_importance" msgid="1527066195614050263">"중요도 높음"</string>
     <string name="max_importance" msgid="5089005872719563894">"중요도 긴급"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"알림 다시 표시 안함"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"알림 목록 하단에 무음으로 표시"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"무음으로 알림 표시"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"알림 목록 상단에 표시하고 소리로 알림"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"화면에 표시하고 소리로 알림"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"알림 목록 맨 아래에 무음으로 표시"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"무음으로 알림 표시"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"알림을 소리로 알리도록 허용"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"화면에 표시하고 소리로 알림"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"알림 목록 맨 위에 표시, 화면에 표시하고 소리로 알림"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
     <string name="notification_done" msgid="5279426047273930175">"완료"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"일반 색상"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"야간 색상"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"맞춤 색상"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"자동"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"알 수 없는 색상"</string>
-    <string name="color_transform" msgid="6985460408079086090">"색상 수정"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"빠른 설정 타일 표시"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"맞춤 변환 사용"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 관리"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"색상 및 모양"</string>
+    <string name="night_mode" msgid="3540405868248625488">"야간 모드"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"디스플레이 보정"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"사용"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"사용 안함"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"자동으로 사용 설정"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"위치 및 시간대에 맞게 야간 모드로 전환"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"야간 모드 사용 중일 때"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS용 어두운 테마 사용"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"농담 효과 조정"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"밝기 조정"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"설정 등 밝은 테마에서 일반적으로 표시되는 Android OS의 핵심 영역에 어두운 테마가 적용됩니다."</string>
     <string name="color_apply" msgid="9212602012641034283">"적용"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"설정 확인"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"일부 색상 설정으로 인해 이 기기를 사용하지 못할 수 있습니다. 확인을 클릭하여 이러한 색상 설정을 확인하지 않으면 10초 후에 설정이 초기화됩니다."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"배터리 사용량"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"충전하는 동안 배터리 세이버는 사용할 수 없습니다."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"배터리 세이버"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"성능 및 백그라운드 데이터를 줄입니다."</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 버튼"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"뒤로"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"위쪽"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"아래쪽"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"왼쪽"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"오른쪽"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"중앙"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"재생/일시중지"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"중지"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"다음"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"이전"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"되감기"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"빨리 감기"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"숫자 패드 <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"시스템"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"홈"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"최근"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"뒤로"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"볼륨에 알림 일시중지 표시"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"볼륨 대화상자에서 알림 일시중지에 대한 전체 컨트롤을 허용합니다."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"볼륨 및 알림 일시중지"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"볼륨 작게 시 알림 일시중지 사용"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"알림"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"단축키"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"입력 방법 전환"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"애플리케이션"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"지원"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"브라우저"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"주소록"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"이메일"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"메신저"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"음악"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"캘린더"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"볼륨 컨트롤과 함께 표시"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"알림 일시중지"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"볼륨 버튼 단축키"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"볼륨 크게 시 알림 일시중지 종료"</string>
     <string name="battery" msgid="7498329822413202973">"배터리"</string>
     <string name="clock" msgid="7416090374234785905">"시계"</string>
     <string name="headset" msgid="4534219457597457353">"헤드셋"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"헤드폰 연결됨"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"헤드셋 연결됨"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"아이콘이 상태 표시줄에 표시되도록 사용 설정 또는 중지합니다."</string>
     <string name="data_saver" msgid="5037565123367048522">"데이터 세이버"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"데이터 세이버 사용"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"데이터 세이버 사용 안함"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"사용"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"사용 안함"</string>
     <string name="nav_bar" msgid="1993221402773877607">"탐색 메뉴"</string>
     <string name="start" msgid="6873794757232879664">"시작"</string>
     <string name="center" msgid="4327473927066010960">"중앙"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"키보드 버튼 선택"</string>
     <string name="preview" msgid="9077832302472282938">"미리보기"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"드래그하여 타일 추가"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"삭제하려면 여기를 드래그"</string>
     <string name="qs_edit" msgid="2232596095725105230">"수정"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"시간"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"시간, 분, 초 표시"</item>
+    <item msgid="1427801730816895300">"시간, 분 표시(기본값)"</item>
+    <item msgid="3830170141562534721">"이 아이콘 표시 안함"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"항상 퍼센트 표시"</item>
+    <item msgid="2139628951880142927">"충전할 때 퍼센트 표시(기본값)"</item>
+    <item msgid="3327323682209964956">"이 아이콘 표시 안함"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"기타"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"화면 분할기"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"아래로 이동"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"위로 이동"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"왼쪽으로 이동"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"오른쪽으로 이동"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"앱이 멀티 윈도우에서 작동하지 않을 수 있습니다."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"위치 <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. 수정하려면 두 번 탭하세요."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. 추가하려면 두 번 탭하세요."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"위치 <xliff:g id="POSITION">%1$d</xliff:g>. 선택하려면 두 번 탭하세요."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 이동"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 삭제"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일이 위치 <xliff:g id="POSITION">%2$d</xliff:g>에 추가됩니다."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일이 삭제되었습니다."</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일을 위치 <xliff:g id="POSITION">%2$d</xliff:g>(으)로 이동함"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"빠른 설정 편집기"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
new file mode 100644
index 0000000..da3ab9e
--- /dev/null
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP 닫기"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"전체화면"</string>
+    <string name="pip_play" msgid="674145557658227044">"재생"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"일시중지"</string>
+    <string name="pip_hold_home" msgid="340086535668778109"><b>"HOME"</b>"을 눌러 PIP 제어"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"홈 버튼을 길게 눌러 PIP 제어"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"확인"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"닫기"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 7819f40..6a2d77f 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"Сактагыч орду чектелүү болгондуктан скриншот тарта албайт, же буга колдонмо же ишканаңыз тарабынан уруксат жок."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Скриншотту сактоо учурунда көйгөй пайда болду."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Сактагычта бош орун аз болгондуктан скриншот сакталбай жатат."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Скриншот тартууга колдонмо же ишканаңыз уруксат бербейт."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB менен файл өткөрүү мүмкүнчүлүктөрү"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойноткуч катары кошуу (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Камера катары кошуу (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> этибарга албоо."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> жок болду."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Акыркы колдонмолордун баары көз жаздымда калтырылды."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> иштеп баштоодо."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Эскертме жок кылынды."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбүрөөк убакыт."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азыраак убакыт."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Колчырак өчүк."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Кол чырак жок."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Колчырак күйүк."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Колчырак өчүрүлдү."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Колчырак күйгүзүлдү."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Иштөө режими күйүк."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Иштөө режими өчүрүлдү."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Иштөө режими күйгүзүлдү."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Дайындарды үнөмдөгүч өчүрүлдү."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Дайындарды үнөмдөгүч күйгүзүлдү."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Жарыктыгын көрсөтүү"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дайындары тындырылды."</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS боюнча аныкталган жайгашуу"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Жайгаштыруу талаптары иштелүүдө"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Бардык эскертмелерди тазалоо."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Эскертме жөндөөлөрү"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> жөндөөлөрү"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран автоматтык түрдө бурулат."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> чектөө"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Иштөө режими"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Акыркы экрандарыңыз бул жерден көрүнөт"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Акыркы нерселер жок"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Баарын тазаладыңыз"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Колдонмо жөнүндө маалымат"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экран кадоо"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"издөө"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> баштай алган жок."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Таржымал"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалоо"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> коопсуз режиминде өчүрүлдү."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Баарын тазалоо"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бул колдонмодо бир нече терезе режими колдоого алынбайт"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Колдонмодо бир нече терезе режими колдоого алынбайт"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Тым-\nтырс"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Артыкчылыктуу\nгана"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ойготкучтар\nгана"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Бардыгы"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Бардык\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Тез кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Жай кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Өйдө серпип экранды бөлгүчтү иштетүү"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Өйдө серпип экранды бөлүү жаңсоосун иштетүү"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Сереп баскычынан өйдө серпип, экранды бөлүү режимин киргизүү үчүн жаңсоону иштетиңиз"</string>
     <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Күйгүзүү"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> эскертмелерине колдонулсун"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Ушул колдонмодон алынган бардык эскертмелерге колдонулсун"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Эскертмелер үнсүз көрсөтүлсүн"</string>
+    <string name="block" msgid="2734508760962682611">"Бардык эскертмелерди бөгөттөө"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Үнү менен көрсөтүлсүн"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Үнү менен көрсөтүлүп бөгөттөлбөсүн"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Маанилүүлүк жөндөөлөрү толук көрсөтүлсүн"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Бөгөттөлгөн"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Маанилүүлүгү эң төмөн"</string>
     <string name="low_importance" msgid="4109929986107147930">"Маанилүүлүгү төмөн"</string>
     <string name="default_importance" msgid="8192107689995742653">"Маанилүүлүгү орточо"</string>
     <string name="high_importance" msgid="1527066195614050263">"Маанилүүлүгү жогору"</string>
     <string name="max_importance" msgid="5089005872719563894">"Маанилүүлүгү шашылыш"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Эскертмелер тизмесинин эң ылдыйында үнсүз көрсөтүлсүн"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Бул эскертмелер үнсүз көрсөтүлсүн"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Эскертмелер тизмесинин эң жогорусунда үн чыгарып көрсөтүлсүн"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Үн менен коштолуп, экранга чыгарылсын"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Эскертмелер тизмесинин соңунда үнсүз көрсөтүлсүн"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Бул эскертмелер үнсүз көрсөтүлсүн"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Бул эскертмелер үнү менен көрсөтүлсүн"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Үн менен коштолуп, экранга чыгарылсын"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Эскертмелер тизмесинин эң башында көрсөтүлүп, үн менен коштолуп, экранга чыгарылсын"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
     <string name="notification_done" msgid="5279426047273930175">"Аткарылды"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Кадимки түстөр"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Түнкү түстөр"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Ыңгайлаштырылган түстөр"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Белгисиз түстөр"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Түсүн өзгөртүү"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ыкчам жөндөөлөр тактасын көрсөтүү"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Ыңгайлаштырылган өзгөртүүнү иштетүү"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> эскертмесин башкаруу каражаттары"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Түсү жана көрүнүшү"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Түнкү режим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Дисплейди калибрлөө"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Күйүк"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Өчүк"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматтык түрдө күйгүзүү"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Жайгашкан жерге жана убакытка жараша түнкү режимге которулуңуз"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Түнкү режим күйүп турганда"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS үчүн караңгы тема колдонуу"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Кошумча түсүн тууралоо"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Жарыктыгын тууралоо"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Адатта жарык темада көрсөтүлүүчү Android тутумунун негизги элементтерине (Жөндөөлөр сыяктуу) колдонула турган караңгы тема."</string>
     <string name="color_apply" msgid="9212602012641034283">"Колдонуу"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Жөндөөлөрдү ырастоо"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Айрым түс жөндөөлөрү бул түзмөктү колдонулгус кылып коюшу мүмкүн. Бул түс жөндөөлөрүн ырастоо үчүн OK баскычын чыкылдатыңыз, болбосо бул жөндөөлөр 10 секунддан кийин баштапкы абалына келтирилет."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Батарея колдонулушу"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Батареяны үнөмдөгүч түзмөк кубатталып жатканда иштебейт"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Батареяны үнөмдөгүч"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> баскычы"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Башкы бет"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Артка"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Өйдө"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Төмөн"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Солго"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Оңго"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Ортолотуу"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Өтмөк"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Боштук"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Киргизүү"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Артка өчүрүү"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Ойнотуу/Тындыруу"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Токтотуу"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Кийинки"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Мурунку"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Артка түрүү"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Алдыга түрүү"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Жок кылуу"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Башкы бет"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Бүтүрүү"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Тутум"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Башкы бет"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Акыркылар"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артка"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"\"Тынчымды алба\" режимин үн көзөмөлдөгүчүндө көрсөтүү"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Үндү катуулатып/акырындатуу диалогунда \"Тынчымды алба\" режимин толук көзөмөлдөөгө уруксат берүү."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Үн көзөмөлдөгүчү жана \"Тынчымды алба\" режими"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Үн акырындатылганда \"Тынчымды алба\" режимине кирүү"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Эскертмелер"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Баскычтоптун кыска жолдору"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Киргизүү ыкмасын которуштуруу"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Колдонмолор"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Көмөкчү"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Серепчи"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Байланыштар"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электрондук почта"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Жылнаама"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Үн көзөмөлдөгүчтөрү менен көрсөтүлсүн"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Тынчымды алба"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Үндү көзөмөлдөөчү баскычтардын кыска жолдору"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Үн катуулатылганда \"Тынчымды алба\" режиминен чыгуу"</string>
     <string name="battery" msgid="7498329822413202973">"Батарея"</string>
     <string name="clock" msgid="7416090374234785905">"Саат"</string>
     <string name="headset" msgid="4534219457597457353">"Гарнитура"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Гарнитуралар туташкан"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Гарнитура туташты"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Абал тилкесиндеги сүрөтчөнү иштетүү же өчүрүү."</string>
     <string name="data_saver" msgid="5037565123367048522">"Дайындарды үнөмдөгүч"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Дайындарды үнөмдөгүч күйүк"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Дайындарды үнөмдөгүч өчүрүлгөн"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Күйүк"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Өчүк"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Чабыттоо тилкеси"</string>
     <string name="start" msgid="6873794757232879664">"Баштоо"</string>
     <string name="center" msgid="4327473927066010960">"Экрандын ортосунда"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Баскычтоптогу баскычты тандоо"</string>
     <string name="preview" msgid="9077832302472282938">"Алдын ала көрүү"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Керектүү нерселерди сүйрөп кошуңуз"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Түзөтүү"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Убакыт"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Сааттар, мүнөттөр жана секунддар көрсөтүлсүн"</item>
+    <item msgid="1427801730816895300">"Сааттар жана мүнөттөр көрсөтүлсүн (демейки)"</item>
+    <item msgid="3830170141562534721">"Бул сөлөкөт көрсөтүлбөсүн"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Ар дайым пайызы көрсөтүлсүн"</item>
+    <item msgid="2139628951880142927">"Кубаттоо учурунда пайызы көрсөтүлсүн (демейки)"</item>
+    <item msgid="3327323682209964956">"Бул сөлөкөт көрсөтүлбөсүн"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Башка"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Экранды бөлгүч"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмөн жылдыруу"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жогору жылдыруу"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солго жылдыруу"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңго жылдыруу"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Бир нече терезе режиминде колдонмо иштебей калышы мүмкүн"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Түзөтүү үчүн эки жолу таптаңыз."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Кошуу үчүн эки жолу таптаңыз."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>. Тандоо үчүн эки жолу таптаңыз."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дегенди жылдыруу"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дегенди алып салуу"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> деген <xliff:g id="POSITION">%2$d</xliff:g>-орунга кошулду"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> алынып салынды"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> деген <xliff:g id="POSITION">%2$d</xliff:g>-орунга жылдырылды"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ыкчам жөндөөлөр түзөткүчү."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings_tv.xml b/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
new file mode 100644
index 0000000..b030542
--- /dev/null
+++ b/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP\'ти жабуу"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Толук экран"</string>
+    <string name="pip_play" msgid="674145557658227044">"Ойнотуу"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Тындыруу"</string>
+    <string name="pip_hold_home" msgid="340086535668778109"><b>"БАШКЫ БЕТ"</b>" басып туруп PIP\'ти башкарыңыз"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP башкаруу үчүн БАШКЫ БЕТ баскычын басып, кармап туруңуз"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Түшүндүм"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Көз жаздымда калтыруу"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 43e7bac..f7e2344 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -28,14 +28,4 @@
 
     <!-- We have only space for one notification on phone landscape layouts. -->
     <integer name="keyguard_max_notification_count">1</integer>
-
-    <!-- Recents: The relative range of visible tasks from the current scroll position
-         while the stack is focused. -->
-    <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
-    <item name="recents_layout_focused_range_max" format="float" type="integer">2</item>
-
-    <!-- Recents: The relative range of visible tasks from the current scroll position
-         while the stack is not focused. -->
-    <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item>
-    <item name="recents_layout_unfocused_range_max" format="float" type="integer">1.5</item>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 622e1e5..601cc2a 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"ບໍ່​ສາມາດ​ຖ່າຍ​ຮູບ​ໜ້າ​ຈໍ​ໄດ້​ເນື່ອງ​ຈາກ​ບ່ອນ​ຈັດ​ເກັບ​ຂໍ້ມູນ​ທີ່​ຈຳກັດ ຫຼື​ແອັບຯ ຫຼື​ອົງກອນ​ຂອງ​ທ່ານ​ບໍ່​ອະນຸຍາດ​ໃຫ້​ເຮັດ​ໄດ້."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ເກີດບັນຫາໃນການບັນທຶກພາບໜ້າຈໍຂອງທ່ານ."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້ເນື່ອງຈາກພື້ນທີ່ຈັດເກັບຂໍ້ມູນມີຈຳກັດ."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ແອັບ ຫຼື ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ມີການຖ່າຍຮູບໜ້າຈໍ."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ໂຕເລືອກການຍ້າຍໄຟລ໌"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ເຊື່ອມຕໍ່ເປັນ media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ເຊື່ອມຕໍ່ເປັນກ້ອງຖ່າຍຮູບ (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ປິດ <xliff:g id="APP">%s</xliff:g> ໄວ້."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"ປິດ <xliff:g id="APP">%s</xliff:g> ແລ້ວ."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ທຸກ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ບໍ່​ດົນ​ມາ​ນີ້​ຖືກ​ປ່ອຍ​ໄປ."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ກຳ​ລັງ​ເປີດ <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"​ເພີ່ມ​ເວ​ລາ."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ຫຼຸດ​ເວ​ລາ."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ໄຟ​ສາຍ​ປິດ."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ບໍ່ສາມາດໃຊ້ໄຟສາຍໄດ້"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ໄຟ​ສາຍ​ເປີດ."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ປິດ​ໄຟ​ສາຍ​ແລ້ວ."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"​ເປີດ​ໄຟ​ສາຍ​ແລ້ວ."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"ໂໝດການເຮັດວຽກເປີດຢູ່."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ໂໝດການເຮັດວຽກປິດຢູ່."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"ໂໝດການເຮັດວຽກເປີດຢູ່."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ປິດຕົວປະຢັດຂໍ້ມູນແລ້ວ."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ເປີດຕົວປະຢັດຂໍ້ມູນແລ້ວ."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"​ຄວາມ​ແຈ້ງ​​ຂອງ​ຈໍ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"ຂໍ້​ມູນ 2G​-3G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້​ມູນ 4G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"ສະຖານທີ່ກຳນົດໂດຍ GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"ການຮ້ອງຂໍສະຖານທີ່ທີ່ເຮັດວຽກຢູ່"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ລຶບການແຈ້ງເຕືອນທັງໝົດ."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"​ການ​ຕັ້ງ​ຄ່າ​ການ​ແຈ້ງ​ເຕືອນ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"ການ​ຕັ້ງ​ຄ່າ <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ໜ້າຈໍຈະໝຸນໂດຍອັດຕະໂນມັດ."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ຈຳ​ກັດ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"ຄຳ​ເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ໂໝດການເຮັດວຽກ"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ທ່ານລຶບລ້າງທຸກຢ່າງແລ້ວ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"ບໍ່​ສາ​ມາດ​ເລີ່ມ <xliff:g id="APP">%s</xliff:g> ໄດ້."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ປະຫວັດ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ລຶບ"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ຖືກປິດໃຊ້ໃນໂໝດຄວາມມປອດໄພ."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ລຶບລ້າງທັງໝົດ"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ແອັບນີ້ບໍ່ຮອງຮັບຫຼາຍໜ້າຈໍ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ແອັບບໍ່ຮອງຮັບຫຼາຍໜ້າຈໍ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການ​ແຍກ​ລວງ​ຂວາງ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ການ​ແຍກ​ລວງ​ຕັ້ງ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ການ​ແຍກ​ກຳ​ນົດ​ເອງ"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"ຄວາມ​ງຽບ\nທັງ​ໝົດ"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ບຸ​ລິ​ມະ​ສິດ\nເທົ່າ​ນັ້ນ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ໂມງ​ປຸກ\nເທົ່າ​ນັ້ນ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"ທັງໝົດ"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ທັງໝົດ\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ເປີດໃຊ້ຕົວເລັ່ງຄວາມໄວການປັດຂຶ້ນຂອງໜ້າຈໍແບບແຍກກັນ"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ເປີດໃຊ້ທ່າທາງການປັດຂຶ້ນເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບຮວມ"</string>
     <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດ​ໃຊ້ Bluetooth ບໍ່?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອ​ເຊື່ອມ​ຕໍ່​ແປ້ນ​ພິມ​ຂອງ​ທ່ານ​ກັບ​ແທັບ​ເລັດ​ຂອງ​ທ່ານ, ກ່ອນ​ອື່ນ​ໝົດ​ທ່ານ​ຕ້ອງ​ເປີດ Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ເປີດ​"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"ນຳໃຊ້ກັບການແຈ້ງເຕືອນ <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ນຳໃຊ້ກັບທຸກການແຈ້ງເຕືອນຈາກແອັບນີ້"</string>
+    <string name="show_silently" msgid="6841966539811264192">"ສະແດງການແຈ້ງເຕືອນແບບບໍ່ມີສຽງ"</string>
+    <string name="block" msgid="2734508760962682611">"ບລັອກການແຈ້ງເຕືອນທັງໝົດ"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ຢ່າງຽບ"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ຢ່າງຽບ ຫຼື ບລັອກ"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ສະແດງການຕັ້ງຄ່າຄວາມສຳຄັນແບບເຕັມ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"ບລັອກໄວ້​ແລ້ວ"</string>
+    <string name="min_importance" msgid="1901894910809414782">"ຄວາມສຳຄັນໜ້ອຍສຸດ"</string>
     <string name="low_importance" msgid="4109929986107147930">"ຄວາມ​ສໍາ​ຄັນ​ຕໍ່າ"</string>
     <string name="default_importance" msgid="8192107689995742653">"ຄວາມສຳຄັນປົກກະຕິ"</string>
     <string name="high_importance" msgid="1527066195614050263">"ຄວາມ​ສໍາ​ຄັນ​ສູງ"</string>
     <string name="max_importance" msgid="5089005872719563894">"ຄວາມ​ສໍາ​ຄັນ​ຮີບ​ດ່ວນ"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ຢ່າ​ສະ​ແດງ​ການ​ແຈ້ງ​ເຕືອນ​ເຫຼົ່າ​ນີ້"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"ສະແດງຢູ່ສ່ວນລຸ່ມຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"ສະແດງຢູ່ສ່ວນເທິງຂອງລາຍການແຈ້ງເຕືອນ ແລະສົ່ງສຽງດັງ"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"ເດັ້ງຂຶ້ນເທິງຫນ້າຈໍ ແລະສົ່ງສຽງດັງ"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"ສະແດງຢູ່ລຸ່ມສຸດຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ອະນຸຍາດໃຫ້ການແຈ້ງເຕືອນເຫຼົ່ານີ້ໃຊ້ສຽງໄດ້"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"ແຈ້ງໄປໜ້າຈໍ ແລະ ອະນຸຍາດໃຫ້ໃຊ້ສຽງໄດ້"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ, ແຈ້ງໄປໜ້າຈໍ ແລະ ອະນຸຍາດໃຫ້ໃຊ້ສຽງໄດ້"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"ສີ​ປົກ​ກະ​ຕິ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"ສີ​ຕອນ​ກາງ​ຄືນ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"ສີແບບກຳນົດເອງ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"ອັດຕະໂນມັດ"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"ສີທີ່ບໍ່ຮູ້ຈັກ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"ການ​ດັດ​ແປງສີ"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"ສະແດງໄທລ໌ການຕັ້ງຄ່າດ່ວນ"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"ເປີດໃຊ້ການປ່ຽນສີແບບກຳນົດເອງ"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"ການຄວບຄຸມການແຈ້ງເຕືອນ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"ສີ ແລະ ລັກສະນະ"</string>
+    <string name="night_mode" msgid="3540405868248625488">"ໂໝດກາງຄືນ"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ປັບໜ້າຈໍ"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ເປີດ"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ປິດ"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"ເປີດ​ໃຊ້​ອັດ​ຕະ​ໂນ​ມັດ"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ສະລັບໄປໃຊ້ໂໝດກາງຄືນຕາມຄວາມເໝາະສົມກັບສະຖານທີ່ ແລະ ເວລາໃນແຕ່ລະມື້"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"ເມື່ອເປີດໂໝດກາງຄືນ"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"ໃຊ້ຮູບແບບສີສັນແບບມືດສຳລັບ Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ປັບແຕ່ງໂທນສີ"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ປັບແຕ່ງຄວາມສະຫວ່າງ"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ຮູບແບບສີສັນມືດແມ່ນນຳໃຊ້ກັບພື້ນທີ່ຫຼັກຂອງ Android OS ທີ່ປົກກະຕິຈະສະແດງເປັນຮູບແບບສີສັນແຈ້ງ ເຊັ່ນ: ການຕັ້ງຄ່າ."</string>
     <string name="color_apply" msgid="9212602012641034283">"ນຳໃຊ້"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ຢືນ​ຢັນ​ການ​ຕັ້ງ​ຄ່າ"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"ບາງການຕັ້ງຄ່າສີສາມາດເຮັດໃຫ້ອຸປະກອນນີ້ບໍ່ສາມາດໃຊ້ໄດ້. ຄລິກ ຕົກລົງ ເພື່ອຢືນຢັນການຕັ້ງຄ່າສີເຫຼົ່ານີ້, ຖ້າບໍ່ດັ່ງນັ້ນ ການຕັ້ງຄ່າເຫຼົ່ານີ້ຈະຕັ້ງຄືນໃໝ່ ຫຼັງຈາກ 10 ວິນາທີ."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"ການໃຊ້ແບັດເຕີຣີ"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ຕົວປະຢັດແບັດເຕີຣີບໍ່ມີໃຫ້ນຳໃຊ້ໃນລະຫວ່າງການສາກ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ຕົວປະຢັດ​ແບັດເຕີຣີ"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ຫຼຸດ​ປະ​ສິ​ທິ​ພາບ​ການໃຊ້ງານ ແລະ ​ຂໍ້​ມູນ​ພື້ນຫຼັງ"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"ປຸ່ມ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"ກັບຄືນ"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ຂຶ້ນ"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ລົງ"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ຊ້າຍ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ຂວາ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ເຄິ່ງກາງ"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ຫຼິ້ນ/ຢຸດຊົ່ວຄາວ"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ຢຸດ"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"ຕໍ່ໄປ"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ກ່ອນໜ້າ"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ຣີວາຍກັບ"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ເລື່ອນໄປໜ້າ"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ລະບົບ"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"​ໜ້າຫຼັກ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ຫາ​ກໍ​ໃຊ້"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ກັບຄືນ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"ສະແດງ ຫ້າມລົບກວນ ໃນລະດັບສຽງ"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ອະນຸຍາດການຄວບຄຸມເຕັມສ່ວນຂອງ ຫ້າມລົບກວນ ໃນກ່ອງປັບລະດັບສຽງ."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ລະດັບສຽງ ແລະ ຫ້າມລົບກວນ"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ເປີດໃຊ້ໂໝດ ຫ້າມລົບກວນ ເມື່ອປັບສຽງໃຫ້ຄ່ອຍລົງ"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ການແຈ້ງເຕືອນ"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ປຸ່ມລັດແປ້ນພິມ"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ແອັບພລິເຄຊັນ"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ຕົວຊ່ວຍ"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ໂປຣແກຣມທ່ອງເວັບ"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ລາຍຊື່ຜູ້ຕິດຕໍ່"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ອີເມວ"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ດົນຕີ"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ປະຕິທິນ"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"ສະແດງສ່ວນຄວບຄຸມສຽງ"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ຫ້າມ​ລົບ​ກວນ"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ທາງລັດປຸ່ມສຽງ"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ອອກຈາກໂໝດ ຫ້າມລົບກວນ ເມື່ອປັບສຽງໃຫ້ດັງຂຶ້ນ"</string>
     <string name="battery" msgid="7498329822413202973">"ແບັດເຕີຣີ"</string>
     <string name="clock" msgid="7416090374234785905">"ໂມງ"</string>
     <string name="headset" msgid="4534219457597457353">"​ຊຸດ​ຫູ​ຟັງ"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ເຊື່ອມຕໍ່ຊຸດຫູຟັງແລ້ວ"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ເຊື່ອມ​ຕໍ່ຊຸດ​ຫູ​ຟັງແລ້ວ"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ເປີດ ຫຼື ປິດໄອຄອນຕ່າງໆຈາກການສະແດງໃນແຖບສະຖານະ."</string>
     <string name="data_saver" msgid="5037565123367048522">"ຕົວປະຢັດຂໍ້ມູນ"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ຕົວປະຢັດຂໍ້ມູນເປີດຢູ່"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ຕົວປະຢັດຂໍ້ມູນປິດຢູ່"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ເປີດ"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ປິດ"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ແຖບນຳທາງ"</string>
     <string name="start" msgid="6873794757232879664">"ເລີ່ມຕົ້ນ"</string>
     <string name="center" msgid="4327473927066010960">"ເຄິ່ງກາງ"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"ເລືອກປຸ່ມແປ້ນພິມ"</string>
     <string name="preview" msgid="9077832302472282938">"ສະແດງຕົວຢ່າງ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ລາກເພື່ອເພີ່ມໄທລ໌"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ລາກມາບ່ອນນີ້ເພື່ອລຶບອອກ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ແກ້ໄຂ"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"ເວລາ"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"ສະແດງຊົ່ວໂມງ, ນາທີ ແລະ ວິນາທີ"</item>
+    <item msgid="1427801730816895300">"ສະແດງຊົ່ວໂມງ ແລະ ນາທີ (ຄ່າເລີ່ມຕົ້ນ)"</item>
+    <item msgid="3830170141562534721">"ຢ່າສະແດງໄອຄອນນີ້"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"ສະແດງເປີເຊັນຕະຫຼອດເວລາ"</item>
+    <item msgid="2139628951880142927">"ສະແດງເປີເຊັນເມື່ອກຳລັງສາກໄຟ (ຄ່າເລີ່ມຕົ້ນ)"</item>
+    <item msgid="3327323682209964956">"ຢ່າສະແດງໄອຄອນນີ້"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"ອື່ນໆ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ເລື່ອນລົງ"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ເລື່ອນຂຶ້ນ"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ເລື່ອນຊ້າຍ"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ເລື່ອນຂວາ"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ກັບຫຼາຍໜ້າຈໍ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. ແຕະສອງເທື່ອເພື່ອແກ້ໄຂ."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ແຕະສອງເທື່ອເພື່ອເພີ່ມ."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>. ແຕະສອງເທື່ອເພື່ອເລືອກ."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ຍ້າຍ <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"ລຶບ <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ຖືກເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%2$d</xliff:g> ແລ້ວ"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"ລຶບ <xliff:g id="TILE_NAME">%1$s</xliff:g> ອອກແລ້ວ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ຍ້າຍໄປຕຳແໜ່ງ <xliff:g id="POSITION">%2$d</xliff:g> ແລ້ວ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ຕົວແກ້ໄຂການຕັ້ງຄ່າດ່ວນ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings_tv.xml b/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
new file mode 100644
index 0000000..6e36d3f
--- /dev/null
+++ b/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"ປິດ PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"ເຕັມໜ້າຈໍ"</string>
+    <string name="pip_play" msgid="674145557658227044">"ຫຼິ້ນ"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"ຢຸດຊົ່ວຄາວ"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"ກົດ "<b>"HOME"</b>" ຄ້າງໄວ້ເພື່ອຄວບຄຸມ PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"ແຕະປຸ່ມ HOME ຄ້າງໄວ້ເພື່ອຄວບຄຸມຮູບນ້ອຍ"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"ເຂົ້າໃຈແລ້ວ"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"ປິດໄວ້"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 34decce7..866abf3 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -75,7 +75,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrano kopija užfiksuota."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Palieskite, kad peržiūrėtumėte ekrano kopiją."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nepavyko užfiksuoti ekrano kopijos."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Neg. daryti ekr. kopijų dėl ribotos saugyklos vietos arba to atlikti neleidžia progr. ar organiz."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Išsaugant ekrano kopiją iškilo problemų."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Negalima išsaugoti ekrano kopijos dėl ribotos saugyklos vietos."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Jūsų organizacijoje arba naudojant šią programą neleidžiama daryti ekrano kopijų"</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_ptp_button_title" msgid="7517127540301625751">"Įmontuoti kaip fotoaparatą (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Atsisakyti <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Atsisakyta programos „<xliff:g id="APP">%s</xliff:g>“."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Atsisakyta visų naujausių programų."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Paleidžiama <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"„<xliff:g id="APP">%1$s</xliff:g>“ <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pranešimo atsisakyta."</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daugiau laiko."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mažiau laiko."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Blykstė išjungta."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Blykstė nepasiekiama."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Blykstė įjungta."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Blykstė išjungta."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Blykstė įjungta."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Darbo režimas įjungtas."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Darbo režimas išjungtas."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Darbo režimas įjungtas."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Duomenų taupymo priemonė išjungta."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Duomenų taupymo priemonė įjungta."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrano šviesumas"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G duomenys pristabdyti"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Vietovės užklausos aktyvios"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Išvalyti visus pranešimus."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"Dar <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Pranešimų nustatymai"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"„<xliff:g id="APP_NAME">%s</xliff:g>“ nustatymai"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string>
@@ -298,15 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limitas: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> įspėjimas"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darbo režimas"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Čia rodomi naujausi ekranai"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nėra jokių naujausių elementų"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Viską išvalėte"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekrano prisegimas"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Istorija"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Išvalyti"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Programa „<xliff:g id="APP">%s</xliff:g>“ išjungta saugos režimu."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Išvalyti viską"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ši programa nepalaiko kelių langų režimo"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Programa nepalaiko kelių langų režimo"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontalus skaidymas"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikalus skaidymas"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tinkintas skaidymas"</string>
@@ -336,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Visiška\ntyla"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tik\nprioritetiniai"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tik\nsignalai"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Visi"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Visi\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Greitai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lėtai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
@@ -450,61 +457,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Įgalinti skaidyto ekrano perbrauk. aukštyn spartinimo įrankį"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Įgalinti ekrano skaidymo perbraukimo aukštyn gestą"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Įgalinti gestą, kuriuo galima įjungti skaidytą ekraną, perbraukiant aukštyn nuo apžvalgos mygtuko"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Įjungti"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Taikyti „<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“ pranešimams"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Taikyti visiems pranešimams iš šios programos"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Tyliai rodyti pranešimus"</string>
+    <string name="block" msgid="2734508760962682611">"Blokuoti visus pranešimus"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Netylėti"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Netylėti arba blokuoti"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Rodyti visos svarbos nustatymus"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Užblokuota"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Min. svarba"</string>
     <string name="low_importance" msgid="4109929986107147930">"Maža svarba"</string>
     <string name="default_importance" msgid="8192107689995742653">"Įprasta svarba"</string>
     <string name="high_importance" msgid="1527066195614050263">"Didelė svarba"</string>
     <string name="max_importance" msgid="5089005872719563894">"Skubi svarba"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Niekada nerodyti šių pranešimų"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Tyliai rodyti pranešimų sąrašo apačioje"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Tyliai rodyti šiuos pranešimus"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Rodyti pranešimų sąrašo viršuje ir skambėti"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Rodyti ekrane ir skambėti"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tyliai rodyti pranešimų sąrašo apačioje"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tyliai rodyti šiuos pranešimus"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Leisti šiems pranešimams skambėti"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Rodyti ekrane ir leisti skambėti"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Rodyti pranešimų sąrašo viršuje, rodyti ekrane ir leisti skambėti"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
     <string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Įprastos spalvos"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nakties spalvos"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Tinkintos spalvos"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatinis"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Nežinomos spalvos"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Spalvų keitimas"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Rodyti Sparčiųjų nustatymų išklotinės elementą"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Įgalinti tinkintą transformavimą"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų valdikliai"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Spalva ir išvaizda"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Naktinis režimas"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibruoti ekraną"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Įjungta"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Išjungta"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Įjungti automatiškai"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Perjungti į naktinį režimą pagal vietovę ir dienos laiką"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kai įjungtas naktinis režimas"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Naudoti tamsią „Android“ OS temą"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Koreguoti atspalvį"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Koreguoti šviesumą"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Pagrindinėms „Android“ OS dalims, kurioms paprastai taikoma šviesi tema, pvz., skilčiai „Nustatymai“, bus pritaikyta tamsi tema."</string>
     <string name="color_apply" msgid="9212602012641034283">"Taikyti"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Nustatymų patvirtinimas"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Dėl kai kurių spalvų nustatymų įrenginys gali būti netinkamas naudoti. Spustelėkite „Gerai“, kad patvirtintumėte šiuos spalvų nustatymus. Kitaip šie nustatymai bus nustatyti iš naujo po 10 sekundžių."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Akum. energ. vartoj."</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumuliatoriaus tausojimo priemonė nepasiekiama įkraunant"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumuliatoriaus tausojimo priemonė"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Mygtukas <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Pagrindinis"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Atgal"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Aukštyn"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Žemyn"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Kairėn"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Dešinėn"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centras"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabuliavimo klavišas"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Tarpas"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Įvesti"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Naikinimo klavišas"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Leisti / pristabdyti"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Sustabdyti"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Kitas"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Ankstesnis"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Sukti atgal"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Sukti pirmyn"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Ankstesnis puslapis"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Tolesnis puslapis"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ištrinti"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Pagrindinis"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Baigti"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Įterpti"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Skaičių režimas"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Klaviatūros skaitmenų sritis <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pagrindinis ekranas"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Naujausios veiklos ekranas"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atgal"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Rodyti netrukdymo režimą garsumo dialogo lange"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Leisti visiškai valdyti netrukdymo režimą garsumo dialogo lange."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Garsumas ir netrukdymo režimas"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Įjungti netrukdymo režimą mažinant garsumą"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Pranešimai"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Spartieji klavišai"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Perjungti įvesties metodą"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programos"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pagalbinė programa"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Naršyklė"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktai"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"El. paštas"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"TP"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendorius"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Rodyti su garsumo valdikliais"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netrukdymo režimas"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Garsumo mygtukų spartusis klavišas"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Išjungti netrukdymo režimą didinant garsumą"</string>
     <string name="battery" msgid="7498329822413202973">"Akumuliatorius"</string>
     <string name="clock" msgid="7416090374234785905">"Laikrodis"</string>
     <string name="headset" msgid="4534219457597457353">"Ausinės"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Ausinės prijungtos"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Ausinės prijungtos"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Įgalinti arba išjungti piktogramų rodymą būsenos juostoje."</string>
     <string name="data_saver" msgid="5037565123367048522">"Duomenų taupymo priemonė"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Duomenų taupymo priemonė įjungta"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Duomenų taupymo priemonė išjungta"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Įjungti"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Išjungta"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Naršymo juosta"</string>
     <string name="start" msgid="6873794757232879664">"Pradėti"</string>
     <string name="center" msgid="4327473927066010960">"Centre"</string>
@@ -526,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Klaviatūros mygtuko pasirinkimas"</string>
     <string name="preview" msgid="9077832302472282938">"Peržiūrėti"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Nuvilkite, kad pridėtumėte išklotinės elementų"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Vilkite čia, jei norite pašalinti"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Redaguoti"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Laikas"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Rodyti valandas, minutes ir sekundes"</item>
+    <item msgid="1427801730816895300">"Rodyti valandas ir minutes (numatytasis nustatymas)"</item>
+    <item msgid="3830170141562534721">"Nerodyti šios piktogramos"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Visada rodyti procentus"</item>
+    <item msgid="2139628951880142927">"Rodyti procentus kraunant (numatytasis nustatymas)"</item>
+    <item msgid="3327323682209964956">"Nerodyti šios piktogramos"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Kita"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Skaidyto ekrano daliklis"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Perkelti žemyn"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Perkelti aukštyn"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Perkelti kairėn"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Perkelti dešinėn"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Naudojant kelių langų funkciją programa gali neveikti"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> padėtis, išklotinės elementas „<xliff:g id="TILE_NAME">%2$s</xliff:g>“. Dukart palieskite, kad redaguotumėte."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“. Dukart palieskite, kad pridėtumėte."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> padėtis. Dukart palieskite, kad pasirinktumėte."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Perkelti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Pašalinti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pridėtas prie <xliff:g id="POSITION">%2$d</xliff:g> padėties"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pašalintas"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ perkeltas į <xliff:g id="POSITION">%2$d</xliff:g> padėtį"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Sparčiųjų nustatymų redagavimo priemonė."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
new file mode 100644
index 0000000..c8fce8a
--- /dev/null
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Uždaryti PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Visas ekranas"</string>
+    <string name="pip_play" msgid="674145557658227044">"Leisti"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pristabdyti"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Kad vald. PIP, pal. pasp. m. "<b>"PAGRINDINIS"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Jei norite valdyti PIP, paspauskite ir palaikykite pagrindinio puslapio mygtuką"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Supratau"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Atsisakyti"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c667f35..9c32b31 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -74,7 +74,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrānuzņēmums ir uzņemts."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Pieskarieties, lai skatītu ekrānuzņēmumu."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nevarēja uzņemt ekrānuzņēmumu."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Nevar veikt ekrānuzņēmumu (krātuvē nepietiek vietas, vai to neļauj lietotne vai jūsu organizācija)."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Saglabājot ekrānuzņēmumu, radās problēma."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nevar saglabāt ekrānuzņēmumu, jo krātuvē nepietiek vietas."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Lietotne vai jūsu organizācija neatļauj veikt ekrānuzņēmumus."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB failu pārsūtīšanas opcijas"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pievienot kā multivides atskaņotāju (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Pievienot kā kameru (PTP)"</string>
@@ -167,6 +169,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Nerādīt lietotni <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Lietotne <xliff:g id="APP">%s</xliff:g> vairs netiek rādīta."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Visas nesen izmantotās lietojumprogrammas tika noņemtas."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Notiek lietotnes <xliff:g id="APP">%s</xliff:g> palaišana."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Paziņojums netiek rādīts."</string>
@@ -207,6 +211,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Vairāk laika."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mazāk laika."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Apgaismojums ir izslēgts."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Zibspuldze nav pieejama."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Apgaismojums ir ieslēgts."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Apgaismojums ir izslēgts."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Apgaismojums ir ieslēgts."</string>
@@ -219,6 +224,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Darba režīms ir ieslēgts."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Darba režīms ir izslēgts."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Darba režīms ir ieslēgts."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Datu lietojuma samazinātājs ir izslēgts."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Datu lietojuma samazinātājs ir ieslēgts."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrāna spilgtums"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G datu lietojums ir apturēts"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
@@ -232,6 +239,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS iestatītā atrašanās vieta"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktīvi atrašanās vietu pieprasījumi"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Notīrīt visus paziņojumus"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"vēl <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Paziņojumu iestatījumi"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> iestatījumi"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrāns tiks pagriezts automātiski."</string>
@@ -297,15 +305,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ierobežojums: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> brīdinājums"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darba režīms"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Jūsu pēdējie ekrāni tiek rādīti šeit."</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nav nesenu vienumu"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Visi uzdevumi ir notīrīti"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Piespraust ekrānu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Vēsture"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Notīrīt"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Lietotne <xliff:g id="APP">%s</xliff:g> ir atspējota drošajā režīmā."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Notīrīt visu"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Šajā lietotnē netiek atbalstīts vairāku logu režīms."</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Lietotnē netiek atbalstīts vairāku logu režīms"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontāls dalījums"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikāls dalījums"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pielāgots dalījums"</string>
@@ -335,8 +344,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Pilnīgs\nklusums"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tikai\nprioritārie"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tikai\nsignāli"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Visi"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Visi\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ātra uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lēna uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
@@ -449,61 +456,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Iespējot ekrāna sadalīšanu, izmantojot vilkšanu augšup"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Iespējot vilkšanu augšup, lai sadalītu ekrānu"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Iespējot žestu ekrāna sadalīšanai, velkot augšup no pogas Pārskats"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ieslēgt"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Lietot paziņojumiem “<xliff:g id="TOPIC_NAME">%1$s</xliff:g>”"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Lietot visiem šīs lietotnes paziņojumiem"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Rādīt paziņojumus bez skaņas signāla"</string>
+    <string name="block" msgid="2734508760962682611">"Bloķēt visus paziņojumus"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Neizslēgt skaņu"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Neizslēgt skaņu vai nebloķēt"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Rādīt ļoti svarīgu paziņojumu iestatījumus"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloķēts"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimāls svarīguma līmenis"</string>
     <string name="low_importance" msgid="4109929986107147930">"Nav svarīgs"</string>
     <string name="default_importance" msgid="8192107689995742653">"Parasts"</string>
     <string name="high_importance" msgid="1527066195614050263">"Ļoti svarīgs"</string>
     <string name="max_importance" msgid="5089005872719563894">"Steidzams"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nekad nerādīt šos paziņojumus"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Rādīt šos paziņojumus bez skaņas signāla"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Rādīt paziņojumu saraksta augšdaļā un ar skaņas signālu"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Rādīt ekrānā ar skaņas signālu"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Rādīt šos paziņojumus bez skaņas signāla"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Atļaut skaņas signālu šiem paziņojumiem"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Rādīt ekrānā un atļaut skaņas signālu"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Rādīt paziņojumu saraksta augšdaļā, rādīt ekrānā ar skaņas signālu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Parastas krāsas"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nakts krāsas"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Pielāgotas krāsas"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automātiski"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Nezināmas krāsas"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Krāsu pārveidošana"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ātro iestatījumu elementa rādīšana"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Pielāgotās pārveidošanas iespējošana"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumu vadīklas"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Krāsas un izskats"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nakts režīms"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Ekrāna kalibrēšana"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Ieslēgts"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Izslēgts"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Ieslēgt automātiski"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Pārslēgt uz nakts režīmu atbilstoši atrašanās vietai un diennakts laikam"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Ja ir ieslēgts nakts režīms"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Izmantot tumšo motīvu operētājsistēmai Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Regulēt toni"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Regulēt spilgtumu"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tumšais motīvs tiek lietots galvenajos operētājsistēmas Android elementos, kas parasti tiek rādīti ar gaišu motīvu, piemēram, lietotnē Iestatījumi."</string>
     <string name="color_apply" msgid="9212602012641034283">"Lietot"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Iestatījumu apstiprināšana"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Noteiktu krāsu iestatījumu dēļ šī ierīce var kļūt nelietojama. Lai apstiprinātu šos krāsu iestatījumus, noklikšķiniet uz Labi. Ja to neizdarīsiet, pēc 10 sekundēm šie iestatījumi tiks atiestatīti."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Akumulatora lietojums"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumulatora jaudas taupīšanas režīms uzlādes laikā nav pieejams."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumulatora jaudas taupīšanas režīms"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Samazina veiktspēju un fona datus."</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Poga <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Sākumvietas taustiņš"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Atpakaļ"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Uz augšu"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Uz leju"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Pa kreisi"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Pa labi"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centrā"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulēšanas taustiņš"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Atstarpe"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Ievadīšanas taustiņš"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Atpakaļatkāpes taustiņš"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Atskaņot/apturēt"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Apturēt"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Nākamais"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Iepriekšējais"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Attīt atpakaļ"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Pārtīt uz priekšu"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Lapa uz augšu"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Lapa uz leju"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Dzēšanas taustiņš"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Sākumvietas taustiņš"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Beigvietas taustiņš"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Ievietošanas taustiņš"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Ciparslēga taustiņš"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Cipartastatūra <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistēma"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Sākums"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Pēdējie"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atpakaļ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Rādīt režīmu “Netraucēt” skaļuma regulēšanas dialoglodziņā"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Atļaujiet pilnu režīma “Netraucēt” kontroli skaļuma regulēšanas dialoglodziņā."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Skaļums un režīms “Netraucēt”"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Ieslēgt režīmu “Netraucēt”, samazinot skaļumu"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Paziņojumi"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Īsinājumtaustiņi"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Pārslēgt ievades metodi"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Lietojumprogrammas"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Palīgs"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Pārlūkprogramma"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktpersonas"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pasts"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Tūlītējā ziņojumapmaiņa"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Mūzika"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendārs"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Rādīt ar skaļuma vadīklām"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netraucēt"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Skaļuma pogu saīsne"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Izslēgt režīmu “Netraucēt”, palielinot skaļumu"</string>
     <string name="battery" msgid="7498329822413202973">"Akumulators"</string>
     <string name="clock" msgid="7416090374234785905">"Pulkstenis"</string>
     <string name="headset" msgid="4534219457597457353">"Austiņas"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Austiņas ir pievienotas"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Austiņas ar mikrofonu ir pievienotas"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Iespējojiet vai atspējojiet ikonu rādīšanu statusa joslā."</string>
     <string name="data_saver" msgid="5037565123367048522">"Datu lietojuma samazinātājs"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datu lietojuma samazinātājs ieslēgts"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datu lietojuma samazinātājs ir izslēgts."</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Ieslēgts"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Izslēgts"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigācijas josla"</string>
     <string name="start" msgid="6873794757232879664">"Sākums"</string>
     <string name="center" msgid="4327473927066010960">"Centrs"</string>
@@ -525,5 +578,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Tastatūras pogas atlase"</string>
     <string name="preview" msgid="9077832302472282938">"Priekšskatījums"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Velciet elementus, lai tos pievienotu"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Lai noņemtu vienumus, velciet tos šeit."</string>
     <string name="qs_edit" msgid="2232596095725105230">"Rediģēt"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Laiks"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Rādīt stundas, minūtes un sekundes"</item>
+    <item msgid="1427801730816895300">"Rādīt stundas un minūtes (noklusējums)"</item>
+    <item msgid="3830170141562534721">"Nerādīt šo ikonu"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Vienmēr rādīt procentuālo vērtību"</item>
+    <item msgid="2139628951880142927">"Rādīt procentuālo vērtību uzlādes laikā (noklusējums)"</item>
+    <item msgid="3327323682209964956">"Nerādīt šo ikonu"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Citi"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Ekrāna sadalītājs"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pārvietot uz leju"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pārvietot uz augšu"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pārvietot pa kreisi"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pārvietot pa labi"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Iespējams, lietotnē nedarbosies vairāku logu režīms."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozīcija, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Lai rediģētu, veiciet dubultskārienu."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lai pievienotu, veiciet dubultskārienu."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozīcija. Lai atlasītu, veiciet dubultskārienu."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pārvietot elementu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Noņemt elementu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir pievienots <xliff:g id="POSITION">%2$d</xliff:g>. pozīcijā"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir noņemts"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir pārvietots uz <xliff:g id="POSITION">%2$d</xliff:g>. pozīciju"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ātro iestatījumu redaktors."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
new file mode 100644
index 0000000..9e4b236
--- /dev/null
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Aizvērt PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Pilnekrāna režīms"</string>
+    <string name="pip_play" msgid="674145557658227044">"Atskaņot"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Apturēt"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Turiet taustiņu "<b>"SĀKUMS"</b>", lai kontrolētu PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Nospiediet un turiet pogu SĀKUMS, lai kontrolētu PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Labi"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Nerādīt"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 8051ec0..7f2fc15 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"Не може да направи слика на екран поради огран. простор или не дозволува аплика. или организацијата."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Се појави проблем при зачувување на сликата од екранот."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Сликата од екранот не може да се зачува поради ограничена меморија."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Апликацијата или вашата организација не дозволува создавање слики од екранот."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Пренос на датотека со УСБ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Монтирај како мултимедијален плеер (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Монтирај како фотоапарат (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отфрли <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> е отфрлена."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Сите неодамнешни апликации се отфрлени."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Се стартува <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известувањето е отфрлено."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повеќе време."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Помалку време."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Блицот е исклучен."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Светилката е недостапна."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Блицот е вклучен."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Блицот е исклучен."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Блицот е вклучен."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Режимот на работа е вклучен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Режимот на работа е исклучен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Режимот на работа е вклучен."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Штедачот на интернет е исклучен."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Штедачот на интернет е вклучен."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветленост на екранот"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Податоците 2G-3G се паузирани"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Локацијата е поставена со ГПС"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Активни барања за локација"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Исчисти ги сите известувања."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Поставки на известувања"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Поставки на <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранот ќе ротира автоматски."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Лимит: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупредување за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим на работа"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Вашите неодамнешни екрани се појавуваат тука"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Нема неодамнешни ставки"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Исчистивте сѐ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информации за апликацијата"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"прикачување екран"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пребарај"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не може да се вклучи."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> е оневозможен во безбеден режим."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Историја"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Исчисти"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Исчисти ги сите"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Апликацијава не поддржува повеќе прозорци"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апликацијата не поддржува повеќе прозорци"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Раздели хоризонтално"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Раздели вертикално"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Раздели прилагодено"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Целосна\nтишина"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприоритетни"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Сѐ"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Сите\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Бавно полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Овозможете забрзувач за повлекување нагоре поделен екран"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Овозможи го гестот повлекување нагоре за поделен екран"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Овозможете гест за отворање поделен екран со повлекување нагоре од копчето Краток преглед"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се вклучи Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да ја поврзете тастатурата со таблетот, најпрво треба да вклучите Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Вклучи"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Важи за известувањата за <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Важи за сите известувања од оваа апликација"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Тивко прикажувај ги известувањата"</string>
+    <string name="block" msgid="2734508760962682611">"Блокирај ги сите известувања"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Не стишувај"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не стишувај или блокирај"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Прикажи ги поставките со целосна важност"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Минимална важност"</string>
     <string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
     <string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
     <string name="high_importance" msgid="1527066195614050263">"Голема важност"</string>
     <string name="max_importance" msgid="5089005872719563894">"Итна важност"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Никогаш не ги прикажувај известувањава"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Тивко прикажувај ги на дното на списокот со известувања"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Тивко прикажувај ги известувањава"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Прикажувај ги на врвот на списокот со известувања и дај звучен сигнал"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Појави се на екранот и дај звучен сигнал"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Тивко прикажувај ги на дното на списокот со известувања"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Тивко прикажувај ги известувањава"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Овозможи им на известувањава да прават звуци"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Ѕиркање на екранот и овозможен звук и овозможен звук"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Прикажувај ги на врвот на списокот со известувања, ѕиркање на екранот и овозможи звук"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Нормални бои"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Ноќни бои"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Приспособени бои"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Автоматски"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Непознати бои"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Промена на бојата"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Прикажи плочка Брзи поставки"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Овозможи приспособено трансформирање"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известувања на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Ноќен режим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Калибрирај го екранот"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Вклучено"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Исклучено"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Вклучи автоматски"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Префрли во Ноќен режим како што е соодветно за локацијата и времето во денот"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Кога Ноќниот режим е вклучен"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Користете ја темната тема за ОС Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Приспособи ја бојата"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Приспособи ја осветленоста"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Темната тема се применува на основните области на Android OS што обично се прикажуваат во светла тема, како Поставки."</string>
     <string name="color_apply" msgid="9212602012641034283">"Примени"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Потврдете ги поставките"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Некои поставки на боите може да го направат уредот неупотреблив. Кликнете на Во ред за да ги потврдите овие поставки на боите, инаку тие поставки ќе се ресетираат по 10 секунди."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Штедачот на батерија не е достапен при полнење"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Штедач на батерија"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ја намалува изведбата и податоците во заднина"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Копче <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Почетна страница"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Стрелка нагоре"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Стрелка надолу"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Стрелка налево"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Стрелка надесно"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Центар"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Картичка"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Празно место"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Внеси"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Бришење наназад"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Пушти/Паузирај"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Сопри"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Следно"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Претходно"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Премотување наназад"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Брзо премотување нанапред"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Страница нагоре"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Страница надолу"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Избриши"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Почетна страница"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Крај"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Вметни"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Систем"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетна страница"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Неодамнешни"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Прикажи „Не вознемирувај“ во јачината на звукот"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дозволете целосна контрола на „Не вознемирувај“ во дијалогот за јачина на звукот."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Јачина на звук и „Не вознемирувај“"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Премини во „Не вознемирувај“ при намалена јачина на звукот"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Известувања"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Кратенки на тастатурата"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Префрли метод за внесување"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апликации"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помош"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Прелистувач"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Е-пошта"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи со контроли за јачина на звук"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не вознемирувај"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Кратенка за копчињата за јачина на звук"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Излези од „Не вознемирувај“ при зголемена јачина на звукот"</string>
     <string name="battery" msgid="7498329822413202973">"Батерија"</string>
     <string name="clock" msgid="7416090374234785905">"Часовник"</string>
     <string name="headset" msgid="4534219457597457353">"Слушалки"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Слушалките се поврзани"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Слушалките се поврзани"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Овозможете или оневозможете прикажување на иконите во статусната лента."</string>
     <string name="data_saver" msgid="5037565123367048522">"Штедач на интернет"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Штедачот на интернет е вклучен"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Штедачот на интернет е исклучен"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Вклучено"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Исклучено"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Лента за навигација"</string>
     <string name="start" msgid="6873794757232879664">"Почеток"</string>
     <string name="center" msgid="4327473927066010960">"Центар"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Изберете копче за тастатура"</string>
     <string name="preview" msgid="9077832302472282938">"Преглед"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Повлечете за додавање плочки"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Повлечете тука за да се отстрани"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Уреди"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Време"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Прикажи часови, минути и секунди"</item>
+    <item msgid="1427801730816895300">"Прикажи часови и минути (стандардно)"</item>
+    <item msgid="3830170141562534721">"Не прикажувај ја иконава"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Секогаш прикажувај процент"</item>
+    <item msgid="2139628951880142927">"Прикажи процент кога се полни (стандардно)"</item>
+    <item msgid="3327323682209964956">"Не прикажувај ја иконава"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Друго"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Разделник на поделен екран"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Преместете надолу"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместете нагоре"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместете налево"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместете надесно"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Апликацијата може да не работи со повеќе прозорци"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Место <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Допрете двапати за уредување."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Допрете двапати за додавање."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Место <xliff:g id="POSITION">%1$d</xliff:g>. Допрете двапати за избирање."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Преместете <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Отстранете <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е додадена на место <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е отстранета"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е преместена на место <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Уредник за брзи поставки."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings_tv.xml b/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
new file mode 100644
index 0000000..2d6da0c
--- /dev/null
+++ b/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Затвори PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Цел екран"</string>
+    <string name="pip_play" msgid="674145557658227044">"Пушти"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Пауза"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Задржете "<b>"ДОМА"</b>" за кон. PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Притиснете и задржете го копчето ДОМА за контролирање PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Разбрав"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Отфрли"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 4cb8c2e..dfe992c 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"സംഭരണ ഇടം പരിമിതമായതിനാൽ സ്‌ക്രീൻഷോട്ട് എടുക്കാനാകില്ല, അല്ലെങ്കിൽ ഇത് അപ്ലിക്കേഷനോ നിങ്ങളുടെ ഓർഗനൈസേഷനോ അനുവദിക്കുന്നില്ല."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്ന സമയത്ത് പ്രശ്നം നേരിട്ടു."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"സ്റ്റോറേജ് ഇടം പരിമിതമായതിനാൽ സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കാൻ കഴിയില്ല."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"സ്ക്രീൻഷോട്ടുകൾ എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ഫയൽ കൈമാറൽ ഓപ്‌ഷനുകൾ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ഒരു മീഡിയ പ്ലേയറായി (MTP) മൗണ്ടുചെയ്യുക"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ഒരു ക്യാമറയായി (PTP) മൗണ്ടുചെയ്യുക"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> നിരസിക്കുക."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> നിരസിച്ചു."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"അടുത്തിടെയുള്ള എല്ലാ അപ്ലിക്കേഷനും നിരസിച്ചു."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കുന്നു."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"അറിയിപ്പ് നിരസിച്ചു."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"കൂടുതൽ സമയം."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"സമയം കുറയ്‌ക്കുക."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ടോർച്ച് ഓഫാണ്."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ടോർച്ച് ലഭ്യമല്ല."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ടോർച്ച് ഓണാണ്."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ടോർച്ച് ഓഫാക്കി."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ടോർച്ച് ഓണാക്കി."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"പ്രവർത്തന മോഡ് ഓണാണ്."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"പ്രവർത്തന മോഡ് ഓഫാക്കി."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"പ്രവർത്തന മോഡ് ഓണാക്കി."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ഡാറ്റ സേവർ ഓഫാക്കി."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ഡാറ്റ സേവർ ഓണാക്കി."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ഡിസ്പ്ലേ തെളിച്ചം"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"ലൊക്കേഷൻ സജ്ജീകരിച്ചത് GPS ആണ്"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"ലൊക്കേഷൻ അഭ്യർത്ഥനകൾ സജീവമാണ്"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"എല്ലാ വിവരങ്ങളും മായ്‌ക്കുക."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"അറിയിപ്പ് ക്രമീകരണങ്ങൾ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ക്രമീകരണങ്ങൾ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"സ്‌ക്രീൻ യാന്ത്രികമായി തിരിയും."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> പരിധി"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"പ്രവർത്തന മോഡ്"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"നിങ്ങളുടെ പുതിയ സ്ക്രീനുകൾ ഇവിടെ ദൃശ്യമാകുന്നു"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"നിങ്ങൾ എല്ലാം മായ്ച്ചിരിക്കുന്നു"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ആപ്പ് വിവരം"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"സ്ക്രീൻ പിൻ ചെയ്യൽ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"തിരയുക"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കാനായില്ല."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"സുരക്ഷിത മോഡിൽ <xliff:g id="APP">%s</xliff:g> പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ചരിത്രം"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"മായ്‌ക്കുക"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"എല്ലാം മായ്‌ക്കുക"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ഒന്നിലധികം വിൻഡോകളെ ഈ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ഒന്നിലധികം വിൻഡോകളെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ലംബമായി വേർതിരിക്കുക"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ഇഷ്‌ടാനുസൃതമായി വേർതിരിക്കുക"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"പൂർണ്ണ\nനിശബ്‌ദത"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"മുൻഗണന\nമാത്രം"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"അലാറങ്ങൾ\nമാത്രം"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"എല്ലാം"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"എല്ലാം\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"വേഗത്തിൽ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"പതുക്കെ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"സ്പ്ലിറ്റ്-സ്ക്രീൻ സ്വൈപ്പ്-അപ്പ് ആക്‌സിലറേറ്റർ പ്രവർത്തനക്ഷമമാക്കൂ"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"സ്പ്ലിറ്റ്-സ്ക്രീൻ സ്വൈപ്പ്-അപ്പ് ജെസ്റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ചുരുക്കവിവരണ ബട്ടണിൽ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്തുകൊണ്ട് സ്പ്ലിറ്റ്-സ്ക്രീനിലേക്ക് പ്രവേശിക്കാൻ ജെസ്‌റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ഓണാക്കണോ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"നിങ്ങളുടെ ടാബ്‌ലെറ്റുമായി കീബോർഡ് കണക്റ്റുചെയ്യുന്നതിന്, ആദ്യം Bluetooth ഓണാക്കേണ്ടതുണ്ട്."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ഓണാക്കുക"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> അറിയിപ്പുകളിലേക്ക് പ്രയോഗിക്കുക"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ഈ ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളിലേക്കും പ്രയോഗിക്കുക"</string>
+    <string name="show_silently" msgid="6841966539811264192">"അറിയിപ്പുകൾ നിശ്ശബ്ദമായി കാണിക്കുക"</string>
+    <string name="block" msgid="2734508760962682611">"എല്ലാ അറിയിപ്പുകളും ബ്ലോക്കുചെയ്യുക"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"നിശബ്ദമാക്കരുത്"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"നിശബ്ദമാക്കുകയോ ബ്ലോക്കുചെയ്യുകയോ അരുത്"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"പൂർണ്ണ പ്രാധാന്യ ക്രമീകരണം കാണിക്കുക"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"ബ്ലോക്കുചെയ്തു"</string>
+    <string name="min_importance" msgid="1901894910809414782">"കുറഞ്ഞ പ്രാധാന്യം"</string>
     <string name="low_importance" msgid="4109929986107147930">"താഴ്ന്ന പ്രാധാന്യം"</string>
     <string name="default_importance" msgid="8192107689995742653">"സാധാരണ പ്രാധാന്യം"</string>
     <string name="high_importance" msgid="1527066195614050263">"ഉയർന്ന പ്രാധാന്യം"</string>
     <string name="max_importance" msgid="5089005872719563894">"അടിയന്തര പ്രാധാന്യം"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ഈ അറിയിപ്പുകൾ ഒരിക്കലും കാണിക്കരുത്"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ശബ്ദമുണ്ടാക്കാൻ ഈ അറിയിപ്പുകളെ അനുവദിക്കുക"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
     <string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"സാധാരണ വര്‍ണ്ണങ്ങൾ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"രാത്രി വര്‍ണ്ണങ്ങൾ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"ഇഷ്ടാനുസൃത വര്‍ണ്ണങ്ങൾ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"യാന്ത്രികം"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"തിരിച്ചറിയാനാകാത്ത വർണ്ണങ്ങൾ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"വർണ്ണ പരിഷ്കരണം"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"ദ്രുത ക്രമീകരണ ടൈൽ കാണിക്കുക"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"ഇഷ്ടാനുസൃത പരിവർത്തനം പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"വർണ്ണവും രൂപഭാവവും"</string>
+    <string name="night_mode" msgid="3540405868248625488">"നൈറ്റ് മോഡ്"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ഡിസ്പ്ലേ കാലിബ്രേറ്റുചെയ്യുക"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ഓൺ"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ഓഫ്"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"സ്വയമേവ ഓണാക്കുക"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ലൊക്കേഷനും ദിവസത്തിലെ സമയത്തിനും അനുയോജ്യമായ തരത്തിൽ നൈറ്റ് മോഡിലേക്ക് സ്വിച്ചുചെയ്യുക"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"നൈറ്റ് മോഡ് ഓണായിരിക്കുമ്പോൾ"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS-നുള്ള ഇരുണ്ട തീം ഉപയോഗിക്കുക"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ടിന്റ് ക്രമപ്പെടുത്തുക"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"തെളിച്ചം ക്രമപ്പെടുത്തുക"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ക്രമീകരണം പോലെയുള്ള, ഒരു ലൈറ്റ് തീമിൽ സാധാരണ ഗതിയിൽ പ്രദർശിപ്പിക്കപ്പെടുന്ന Android OS-ന്റെ അടിസ്ഥാന ഇടങ്ങളിലേക്ക്, ഇരുണ്ട തീം പ്രയോഗിക്കുന്നു."</string>
     <string name="color_apply" msgid="9212602012641034283">"ബാധകമാക്കുക"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ക്രമീകരണം സ്ഥിരീകരിക്കുക"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"ചില വർണ്ണ ക്രമീകരണത്തിന് ഈ ഉപകരണത്തെ ഉപയോഗരഹിതമാക്കാനാകും. ഈ വർണ്ണ ക്രമീകരണം സ്ഥിരീകരിക്കുന്നതിന് ശരി എന്നതിൽ ക്ലിക്കുചെയ്യുക, അല്ലെങ്കിൽ 10 സെക്കൻഡിന് ശേഷം ഈ ക്രമീകരണം പുനഃക്രമീകരിക്കപ്പെടും."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ചാർജുചെയ്യുന്ന സമയത്ത് ബാറ്ററി സേവർ ലഭ്യമല്ല"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ബാറ്ററി സേവർ"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്‌ക്കുന്നു"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"ബട്ടൺ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"ഹോം"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"ബാക്ക്"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"മുകളിലേക്ക്"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"താഴേക്ക്"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ഇടത്"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"വലത്"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"മധ്യം"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"ടാബ്"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"സ്പെയ്സ്"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"എന്റർ"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"ബാക്ക്‌സ്‍പെയ്‍സ്"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"പ്ലേ ചെയ്യുക/താൽക്കാലികമായി നിർത്തുക"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"നിർത്തുക"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"അടുത്തത്"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"മുമ്പത്തേത്"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"റിവൈൻഡ്"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ഫാസ്റ്റ് ഫോർവേഡ്"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"പേജ് അപ്പ്"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"പേജ് ഡൗൺ"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ഡിലീറ്റ്"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"ഹോം"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"എൻഡ്"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"ഇൻസേർട്ട്"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"നം ലോക്ക്"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"നംപാഡ് <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"സിസ്‌റ്റം"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"വീട്"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"പുതിയവ"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"മടങ്ങുക"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"വോളിയത്തിൽ \'ശല്യപ്പെടുത്തരുത്\' കാണിക്കുക"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"വോളിയം ഡയലോഗിൽ \'ശല്യപ്പെടുത്തരുത്\' എന്നത് പൂർണ്ണമായി നിയന്ത്രിക്കാൻ അനുവദിക്കുക."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"വോളിയവും \'ശല്യപ്പെടുത്തരുത്\' എന്നതും"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"വോളിയം താഴുമ്പോൾ \'ശല്യപ്പെടുത്തരുത്\' പ്രവർത്തിപ്പിക്കുക"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"അറിയിപ്പുകൾ"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"കീബോർഡ് കുറുക്കുവഴികൾ"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ടൈപ്പിംഗ് രീതി മാറുക"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"അപ്ലിക്കേഷനുകൾ"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"അസിസ്റ്റ്"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ബ്രൗസർ"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"കോൺടാക്റ്റുകൾ"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ഇമെയിൽ"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"സംഗീതം"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"കലണ്ടർ"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"വോളിയം നിയന്ത്രണങ്ങളോടൊപ്പം കാണിക്കുക"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ശല്യപ്പെടുത്തരുത്"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"വോളിയം ബട്ടൺ കുറുക്കുവഴി"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"വോളിയം ഉയരുമ്പോൾ \'ശല്യപ്പെടുത്തരുത്\' നിർത്തുക"</string>
     <string name="battery" msgid="7498329822413202973">"ബാറ്ററി"</string>
     <string name="clock" msgid="7416090374234785905">"ക്ലോക്ക്"</string>
     <string name="headset" msgid="4534219457597457353">"ഹെഡ്‌സെറ്റ്"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ഹെഡ്ഫോണുകൾ കണക്റ്റുചെയ്തു"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ഹെഡ്‌സെറ്റ് കണക്‌റ്റുചെയ്‌തു"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"സ്റ്റാറ്റസ് ബാറിൽ കാണിക്കുന്നതിൽ നിന്ന് ഐക്കണുകളെ പ്രവർത്തനക്ഷമമാക്കുകയോ പ്രവർത്തനരഹിതമാക്കുകയോ ചെയ്യുക"</string>
     <string name="data_saver" msgid="5037565123367048522">"ഡാറ്റ സേവർ"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ഡാറ്റാ സേവർ ഓണാണ്"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ഡാറ്റാ സേവർ ഓഫാണ്"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ഓൺ"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ഓഫ്"</string>
     <string name="nav_bar" msgid="1993221402773877607">"നാവിഗേഷൻ ബാർ"</string>
     <string name="start" msgid="6873794757232879664">"ആരംഭിക്കൂ"</string>
     <string name="center" msgid="4327473927066010960">"മധ്യം"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"കീബോർഡ് ബട്ടൺ തിരഞ്ഞെടുക്കൂ"</string>
     <string name="preview" msgid="9077832302472282938">"പ്രിവ്യു നടത്തുക"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ടൈലുകൾ ചേർക്കുന്നതിന് വലിച്ചിടുക"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"നീക്കംചെയ്യുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
     <string name="qs_edit" msgid="2232596095725105230">"എഡിറ്റുചെയ്യുക"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"സമയം"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"മണിക്കൂറും മിനിറ്റും സെക്കൻഡും കാണിക്കുക"</item>
+    <item msgid="1427801730816895300">"മണിക്കൂറും മിനിറ്റും കാണിക്കുക (ഡിഫോൾട്ട്)"</item>
+    <item msgid="3830170141562534721">"ഈ ഐക്കൺ കാണിക്കരുത്"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"എല്ലായ്പ്പോഴും ശതമാനം കാണിക്കുക"</item>
+    <item msgid="2139628951880142927">"ചാർജ്ജുചെയ്യുമ്പോൾ ശതമാനം കാണിക്കുക (ഡിഫോൾട്ട്)"</item>
+    <item msgid="3327323682209964956">"ഈ ഐക്കൺ കാണിക്കരുത്"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"മറ്റുള്ളവ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"സ്പ്ലിറ്റ്-സ്ക്രീൻ ഡിവൈഡർ"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"താഴേക്ക് നീക്കുക"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"മുകളിലേക്ക് നീക്കുക"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ഇടത്തേക്ക് നീക്കുക"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"വലത്തേക്ക് നീക്കുക"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"മൾട്ടി-വിൻഡോയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. എഡിറ്റുചെയ്യുന്നതിന് രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ചേർക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>. തിരഞ്ഞെടുക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കുക"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കംചെയ്യുക"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"സ്ഥാനം <xliff:g id="POSITION">%2$d</xliff:g>-ലേക്ക് <xliff:g id="TILE_NAME">%1$s</xliff:g> ചേർക്കുന്നു"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കംചെയ്യുന്നു"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"സ്ഥാനം <xliff:g id="POSITION">%2$d</xliff:g>-ലേക്ക് <xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കി"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings_tv.xml b/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
new file mode 100644
index 0000000..09fe4ce
--- /dev/null
+++ b/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP അടയ്ക്കുക"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"പൂര്‍ണ്ണ സ്ക്രീന്‍"</string>
+    <string name="pip_play" msgid="674145557658227044">"പ്ലേ ചെയ്യുക"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"തൽക്കാലം നിർത്തൂ"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP നിയന്ത്രിക്കാൻ "<b>"ഹോം"</b>" പിടിക്കുക"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP നിയന്ത്രിക്കാൻ ഹോം ബട്ടൺ അമർത്തിപ്പിടിക്കുക"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"മനസ്സിലായി"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"ഡിസ്മിസ് ചെയ്യുക"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index f22e315..80cb8f2 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -71,7 +71,9 @@
     <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="1260203058661337274">"Хадгалах сан хязгаартай эсхүл таны байгууллага буюу апп-с зөвшөөрөөгүй учир дэлгэцийн зургийг авах боломжгүй."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Дэлгэцийн агшинг хадгалахад алдаа гарлаа."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Хадгалах сангийн багтаамж бага байгаа тул дэлгэцийн авсан зургийг хадгалах боломжгүй байна."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Дэлгэцийн зураг авахыг апп эсвэл танай байгууллагаас зөвшөөрөөгүй байна."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB файл шилжүүлэх сонголт"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа тоглуулагч(MTP) болгон залгах"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Камер болгон(PTP) залгах"</string>
@@ -164,6 +166,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-г хаах."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> байхгүй."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Хамгийн сүүлийн бүх програмыг арилгасан байна."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж байна."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Мэдэгдэл хаагдсан."</string>
@@ -204,6 +208,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Хугацаа нэмэх."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Хугацаа хасах."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Флаш гэрэл унтарсан."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Гэрэлтүүлэгч боломжгүй байна."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Флаш гэрэл ассан."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Флаш гэрлийг унтраасан."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Флаш гэрлийг асаасан."</string>
@@ -216,6 +221,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Ажлын горимыг асаасан."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Ажлын горимыг унтраасан."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Ажлын горимыг асаасан."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Өгөгдөл хамгаалагчийг унтраасан."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Өгөгдөл хамгаалагчийг асаасан."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дэлгэцийн гэрэлтэлт"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дата-г түр зогсоосон байна"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
@@ -229,6 +236,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS байршил"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Байршлын хүсэлтүүд идэвхтэй"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Бүх мэдэгдлийг цэвэрлэх."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Мэдэгдлийн тохиргоо"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> тохиргоо"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Дэлгэц автоматаар эргэнэ."</string>
@@ -294,15 +302,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> хязгаар"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> анхааруулга"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ажлын горим"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Таны саяхны дэлгэц энд харагдах болно"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Сүүлийн үеийн зүйл байхгүй"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Та бүгдийг нь устгасан"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"дэлгэц тогтоох"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж чадсангүй."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Түүх"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Устгах"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>-г аюулгүй горимд идэвхгүй болгосон."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Бүгдийг арилгах"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Энэ апп олон цонхыг дэмждэггүй"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апп олон цонхыг дэмждэггүй"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хэвтээ чиглэлд хуваах"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Босоо чиглэлд хуваах"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Хүссэн хэлбэрээр хуваах"</string>
@@ -332,8 +341,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Дуугүй\nболгох"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Зөвхөн\nхамгийн чухлыг"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Зөвхөн\nсэрүүлэг"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Бүгд"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Бүх\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
@@ -446,61 +453,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Дэлгэц хуваах дээш шудрах хурдасгуурыг идэвхжүүлэх"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Дэлгэц хуваах дээш шудрах дохиог идэвхжүүлэх"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Тойм товчлуурыг дээш шударч, хуваагдсан дэлгэцэд зангаагаар орох тохиргоог идэвхжүүлэх"</string>
     <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Асаах"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> мэдэгдэлд хэрэгжүүлэх"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Энэ апп-н бүх мэдэгдэлд хэрэгжүүлэх"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Мэдэгдлийг чимээгүй харуулах"</string>
+    <string name="block" msgid="2734508760962682611">"Бүх мэдэгдлийг блоклох"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Дуугүй болгох хэрэггүй"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Дууг нь хаах эсвэл блоклох хэрэггүй"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Бүрэн ач холбогдлын тохиргоог харуулах"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блоклосон"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Хамгийн бага ач холбогдол"</string>
     <string name="low_importance" msgid="4109929986107147930">"Бага ач холбогдолтой"</string>
     <string name="default_importance" msgid="8192107689995742653">"Энгийн ач холбогдолтой"</string>
     <string name="high_importance" msgid="1527066195614050263">"Өндөр ач холбогдолтой"</string>
     <string name="max_importance" msgid="5089005872719563894">"Яаралтай ач холбогдолтой"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Мэдэгдлийг жагсаалтын эхэнд дуутай харуулах"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Дэлгэцэнд яаралтайгаар дуутай гаргах"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Эдгээр мэдэгдлийг дуу гаргахыг зөвшөөрөх"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Дэлгэцэд яаралтайгаар дуутай гаргах"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Мэдэгдлийг жагсаалтын эхэнд яаралтай дуутай харуулах"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
     <string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Хэвийн өнгө"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Шөнийн өнгө"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Өгөгдмөл өнгө"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Автомат"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Үл мэдэгдэх өнгө"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Өнгөний өөрчлөлт"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Түргэн тохиргооны хэсгийг харуулах"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Өгөгдмөл өөрчлөлтийг идэвхжүүлэх"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> мэдэгдлийн хяналт"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Өнгө, харагдах байдал"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Шөнийн горим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Дэлгэцийг тохируулах"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Идэвхтэй"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Идэвхгүй"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматаар асаах"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Тухайн өдрийн байршил, цагийн тохиромжтой үед Шөнийн горимд шилжүүлэх"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Шөнийн горим идэвхтэй үед"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android-н үйлдлийн системд бараан загварыг ашиглах"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Өнгөний нягтаршилыг тохируулах"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Гэрэлтүүлгийг тохируулах"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Тохиргоо зэрэг тогтмол цайвар загварт харуулдаг Android үйлдлийн системийн гол хэсгийг бараан загварт харуулна."</string>
     <string name="color_apply" msgid="9212602012641034283">"Хэрэгжүүлэх"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Тохиргоог баталгаажуулах"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Зарим өнгөний тохиргоо энэ төхөөрөмжийг ашиглах боломжгүй болгож болзошгүй. OK товчлуурыг дарж эдгээр өнгөний тохиргоог зөвшөөрөхгүй бол энэ тохиргоо нь 10 секундын дараа шинэчлэгдэх болно."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Тэжээл ашиглалт"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Цэнэглэх үед тэжээл хэмнэгч ажиллахгүй"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Тэжээл хэмнэгч"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Гүйцэтгэл болон дэвсгэрийн датаг багасгадаг"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> товчлуур"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Нүүр хуудас"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Буцах"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Дээш"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Доош"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Зүүн"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Баруун"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Гол хэсэг"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Чихтэй хуудас"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Зай"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Оруулах"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Арилгах"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Тоглуулах/Түр зогсоох"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Зогсоох"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Дараах"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Өмнөх"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Буцааж хураах"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Хурдан урагшлуулах"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Хуудас дээш"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Хуудас доош"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Устгах"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Нүүр хуудас"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Төгсгөл"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Оруулах"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Тоо бичих горим"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Тоо бичих товчлуур <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Систем"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Нүүр хуудас"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Саяхны"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Буцах"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Бүү саад бол тохиргоог дууны түвшинд харуулах"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Бүү саад бол тохиргооны бүрэн хяналтыг дууны түвшний харилцах цонхонд зөвшөөрнө үү."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Дууны түвшин болон бүү саад бол тохиргоо"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Бүү саад бол тохиргоог оруулахын тулд дууны түвшинг бууруулах"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Мэдэгдэл"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Гарын товчлол"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Оролтын аргыг солих"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апп"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Дэмжлэг"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Хөтөч"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Харилцагчид"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Имэйл"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Хөгжим"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Хуанли"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Түвшний хяналттай харуулах"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Бүү саад бол"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Түвшний товчлуурын товчлол"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Бүү саад бол тохиргооноос гарахын тулд дууны түвшинг нэмэх"</string>
     <string name="battery" msgid="7498329822413202973">"Зай"</string>
     <string name="clock" msgid="7416090374234785905">"Цаг"</string>
     <string name="headset" msgid="4534219457597457353">"Чихэвч"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Чихэвч холбогдсон"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Чихэвч холбогдсон"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Статусын самбарт харагдах дүрс тэмдгийг идэвхжүүлэх эсвэл идэвхгүй болгоно уу."</string>
     <string name="data_saver" msgid="5037565123367048522">"Өгөгдөл хамгаалагч"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Өгөгдөл хамгаалагчийг асаасан байна"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Өгөгдөл хамгаалагчийг унтраасан байна"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Идэвхтэй"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Идэвхгүй"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Навигацийн самбар"</string>
     <string name="start" msgid="6873794757232879664">"Эхлэх"</string>
     <string name="center" msgid="4327473927066010960">"Гол хэсэг"</string>
@@ -522,5 +575,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Гарын товчлуур сонгох"</string>
     <string name="preview" msgid="9077832302472282938">"Урьдчилж харах"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Дөрвөлж нэмэхийн тулд чирнэ үү"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Устгахын тулд энд зөөнө үү"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Засах"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Цаг"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Цаг, минут, секундийг харуулах"</item>
+    <item msgid="1427801730816895300">"Цаг, минутыг харуулах (өгөгдмөл)"</item>
+    <item msgid="3830170141562534721">"Энэ дүрс тэмдгийг бүү үзүүл"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Хувийг тогтмол харуулах"</item>
+    <item msgid="2139628951880142927">"Цэнэглэх үед хувийг тогтмол харуулах (өгөгдмөл)"</item>
+    <item msgid="3327323682209964956">"Энэ дүрс тэмдгийг бүү үзүүл"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Бусад"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"\"Дэлгэц хуваах\" хуваагч"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Доош зөөх"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Дээш зөөх"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Зүүн тийш зөөх"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Баруун тийш зөөх"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Олон цонхтой үед апп ажиллахгүй байж болзошгүй"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Байршил <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Засахын тулд 2 удаа дарна уу."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Нэмэхийн тулд 2 удаа дарна уу."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Албан тушаал <xliff:g id="POSITION">%1$d</xliff:g>. Сонгохын тулд 2 удаа дарна уу."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г зөөх"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г устгах"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г <xliff:g id="POSITION">%2$d</xliff:g> байршилд нэмсэн"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г устгасан"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г <xliff:g id="POSITION">%2$d</xliff:g> байршилд зөөсөн"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Түргэн тохиргоо засварлагч."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings_tv.xml b/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
new file mode 100644
index 0000000..ca522d3
--- /dev/null
+++ b/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP-г хаах"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Бүтэн дэлгэц"</string>
+    <string name="pip_play" msgid="674145557658227044">"Тоглуулах"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Түр зогсоох"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP-г удирдахын тулд "<b>"HOME"</b>" товчлуурыг дарна уу"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP-г удирдахын тулд НҮҮР ХУУДАС товчлуурыг дараад хүлээнэ үү"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Ойлголоо"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Хаах"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index ff36be2..76dfcd5 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"मर्यादित संचयन स्‍थानामुळे किंवा अ‍ॅपद्वारे किंवा आपल्‍या संस्‍थेद्वारे त्याची अनुमती नसल्‍यामुळे स्‍क्रीनशॉट घेऊ शकत नाही."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"स्क्रीनशॉट जतन करताना समस्या आली."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"मर्यादित संचय जागेमुळे स्क्रीनशॉट जतन करू शकत नाही."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"अॅप किंवा आपल्या संस्थेद्वारे स्क्रीनशॉट घेण्यास अनुमती नाही."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB फाईल स्थानांतरण पर्याय"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेअर म्हणून माउंट करा (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"कॅमेरा म्हणून माउंट करा (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> डिसमिस करा."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> डिसमिस केला."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"अलीकडील सर्व अनुप्रयोग डिसमिस झाले."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करीत आहे."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना डिसमिस केल्या."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"अधिक वेळ."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कमी वेळ."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"फ्लॅशलाइट बंद."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"फ्लॅशलाइट अनुपलब्ध आहे."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"फ्लॅशलाइट चालू."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"फ्लॅशलाइट बंद केला."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"फ्लॅशलाइट चालू केला."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"कार्य मोड चालू."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"कार्य मोड बंद केला."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"कार्य मोड चालू केला."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"डेटा सर्व्हर बंद केला."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"डेटा सर्व्हर चालू केला."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटास विराम दिला आहे"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारे स्थान सेट केले"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"स्थान विनंत्या सक्रिय"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"सर्व सूचना साफ करा."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"सूचना सेटिंग्ज"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिंग्ज"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रीन स्वयंचलितपणे फिरेल."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> मर्यादा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"आपल्या अलीकडील स्क्रीन येथे दिसतात"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"अलीकडील कोणतेही आयटम नाहीत"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपण सर्वकाही साफ केले"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग माहिती"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्‍क्रीन पिन करणे"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"शोधा"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करणे शक्य झाले नाही."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> सुरक्षित-मोडमध्ये अक्षम केला आहे."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"साफ करा"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"सर्व साफ करा"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"हा अॅप एकाधिक-विंडोला समर्थन देत नाही"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"अॅप एकाधिक-विंडोला समर्थन देत नाही"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"अनुलंब विभाजित करा"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"सानुकूल विभाजित करा"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"संपूर्ण\nशांतता"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवळ\nप्राधान्य"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवळ\nअलार्म"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"सर्व"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"सर्व\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) वेगाने चार्ज होत आहे"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) हळूहळू चार्ज होत आहे"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"विभाजित-स्क्रीन स्वाइप-अप त्वरक सक्षम करा"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रीन स्वाइप-अप जेश्चर सक्षम करा"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"विहंगावलोकन बटणावरून वर स्वाइप करून विभाजित-स्क्रीन प्रविष्ट करण्यासाठी जेश्चर सक्षम करा"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करा"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> सूचनांवर लागू करा"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"या अॅपमधील सर्व सूचनांवर लागू करा"</string>
+    <string name="show_silently" msgid="6841966539811264192">"सूचना शांतपणे दर्शवा"</string>
+    <string name="block" msgid="2734508760962682611">"सर्व सूचना अवरोधित करा"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"शांत करू नका"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"शांत किंवा अवरोधित करू नका"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्त्व सेटिंग्ज दर्शवा"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"अवरोधित केले"</string>
+    <string name="min_importance" msgid="1901894910809414782">"किमान महत्त्व"</string>
     <string name="low_importance" msgid="4109929986107147930">"कमी महत्त्व"</string>
     <string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
     <string name="high_importance" msgid="1527066195614050263">"सर्वाधिक महत्व"</string>
     <string name="max_importance" msgid="5089005872719563894">"त्वरित महत्त्व"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"या सूचना कधीही दर्शवू नका"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"सूचना सूचीच्या तळाशी शांतपणे दर्शवा"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"या सूचना शांतपणे दर्शवा"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीच्या शीर्षस्थानी दर्शवा आणि ध्वनी चालू करा"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रीनवर डोकावून पहा आणि ध्वनी चालू करा"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"सूचना सूचीच्या तळाशी शांतपणे दर्शवा"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"या सूचना शांतपणे दर्शवा"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"या सूचनांना ध्वनी चालू करण्याची अनुमती द्या"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"स्क्रीनवर पहा आणि ध्वनीस अनुमती द्या ध्वनीस अनुमती द्या"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"सूचनांच्या शीर्षस्थानी दर्शवा, स्क्रीनवर पहा आणि ध्वनीस अनुमती द्या"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
     <string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"रात्रीचे रंग"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"सानुकूल रंग"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"स्वयं"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रंग"</string>
-    <string name="color_transform" msgid="6985460408079086090">"रंग सुधारणा"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"द्रुत सेटिंग्ज टाइल दर्शवा"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"सानुकूल रूपांतरण सक्षम करा"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> सूचना नियंत्रणे"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"रंग आणि स्वरूप"</string>
+    <string name="night_mode" msgid="3540405868248625488">"रात्र मोड"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"प्रदर्शनाचे मापन करा"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"चालू"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"बंद"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"स्वयंचलितपणे चालू करा"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"स्थान आणि दिवसाच्या वेळेसाठी योग्य असल्यानुसार रात्र मोड मध्ये स्विच करा"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"रात्र मोड चालू असताना"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS साठी गडद थीमचा वापर करा"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"रंगाची छटा समायोजित करा"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"चकाकी समायोजित करा"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"सेटिंग्ज सारख्या प्रकाश थीममध्ये प्रदर्शित केल्या जाणाऱ्या Android OS च्या मुख्य क्षेत्रांवर गडद थीम लागू केली जाते."</string>
     <string name="color_apply" msgid="9212602012641034283">"लागू करा"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"सेटिंग्जची पुष्टी करा"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"काही रंग सेटिंग्ज या डिव्हाइसला निरुपयोगी करू शकतात. या रंग सेटिंग्जची पुष्टी करण्‍यासाठी ठीक आहे दाबा अन्यथा या सेटिंग्ज 10 सेकंदांनंतर रीसेट होतील."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज करताना बॅटरी बचतकर्ता उपलब्ध नाही"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"बॅटरी बचतकर्ता"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"कार्यप्रदर्शन आणि पार्श्वभूमी डेटा कमी करते"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"बटण <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"परत"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"वर"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"खाली"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"डावा"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"उजवा"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"मध्यवर्ती"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"टॅब"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"प्ले करा/विराम द्या"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"थांबा"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"पुढील"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"मागील"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"मागे न्या"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"पुढे करा"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"हटवा"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"घाला"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"सिस्टीम"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"मुख्यपृष्ठ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"अलीकडील"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"परत"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"आवाजामध्‍ये व्यत्यय आणू नका दर्शवा"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"आवाज संवादामधील व्यत्यय आणू नका च्या पूर्ण नियंत्रणास अनुमती द्या."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"आवाज आणि व्यत्यय आणू नका"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"आवाज कमी केल्यावर व्यत्यय आणू नका प्रविष्‍ट करा"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचना"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"कीबोर्ड शॉर्टकट"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट पद्धत स्विच करा"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"अनुप्रयोग"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहाय्य"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउझर"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"संपर्क"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ईमेल"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"कॅलेंडर"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"आवाज नियंत्रणांसह दर्शवा"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"व्यत्यय आणू नका"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"आवाजाच्या बटणांचा शार्टकट"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"आवाज वाढविल्यावर व्यत्यय आणू नका मधून बाहेर पडा"</string>
     <string name="battery" msgid="7498329822413202973">"बॅटरी"</string>
     <string name="clock" msgid="7416090374234785905">"घड्याळ"</string>
     <string name="headset" msgid="4534219457597457353">"हेडसेट"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"हेडफोन कनेक्ट केले"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"हेडसेट कनेक्ट केला"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"चिन्हे स्टेटस बारमध्ये दर्शविले जाण्‍यापासून प्रतिबंधित करण्‍यासाठी ती सक्षम किंवा अक्षम करा."</string>
     <string name="data_saver" msgid="5037565123367048522">"डेटा बचतकर्ता"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा बचतकर्ता चालू आहे"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा बचतकर्ता बंद आहे"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"चालू"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"बंद"</string>
     <string name="nav_bar" msgid="1993221402773877607">"नॅव्हिगेशन बार"</string>
     <string name="start" msgid="6873794757232879664">"प्रारंभ"</string>
     <string name="center" msgid="4327473927066010960">"मध्यवर्ती"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटण निवडा"</string>
     <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइल जोडण्यासाठी ड्रॅग करा"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"काढण्यासाठी येथे ड्रॅग करा"</string>
     <string name="qs_edit" msgid="2232596095725105230">"संपादित करा"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"वेळ"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"तास, मिनिटे आणि सेकंद दर्शवा"</item>
+    <item msgid="1427801730816895300">"तास आणि मिनिटे दर्शवा (डीफॉल्ट)"</item>
+    <item msgid="3830170141562534721">"हे चिन्ह दर्शवू नका"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"नेहमी टक्केवारी दर्शवा"</item>
+    <item msgid="2139628951880142927">"चार्ज करताना टक्केवारी दर्शवा (डीफॉल्ट)"</item>
+    <item msgid="3327323682209964956">"हे चिन्ह दर्शवू नका"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"अन्य"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित-स्क्रीन विभाजक"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"खाली हलवा"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"वर हलवा"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"डावीकडे हलवा"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"उजवीकडे हलवा"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"एकाधिक-विंडो सह अॅप कार्य करू शकत नाही"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिती <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. संपादित करण्यासाठी दोनदा टॅप करा."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> . जोडण्यासाठी दोनदा टॅप करा."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिती <xliff:g id="POSITION">%1$d</xliff:g>. निवडण्यासाठी दोनदा टॅप करा."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> हलवा"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> काढा"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला <xliff:g id="POSITION">%2$d</xliff:g> स्थितीवर जोडले आहे"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला काढले आहे"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला <xliff:g id="POSITION">%2$d</xliff:g> स्थितीवर हलविले"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"द्रुत सेटिंग्ज संपादक."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings_tv.xml b/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
new file mode 100644
index 0000000..318e3e9
--- /dev/null
+++ b/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP बंद करा"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्क्रीन"</string>
+    <string name="pip_play" msgid="674145557658227044">"प्ले करा"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"विराम द्या"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP नियंत्रित करण्यासाठी "<b>"मुख्यपृष्ठ"</b>" धरून ठेवा"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP नियंत्रित करण्यासाठी मुख्यपृष्ठ बटण दाबा आणि धरून ठेवा"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"समजले"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"डिसमिस करा"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 13a1f00..9401198 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan skrin ditangkap."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan skrin anda."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat menangkap tangkapan skrin."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Tdk dpt mngmbil tgkapn skrin krn ruang storan trhad atau tdk dibenarkn olh apl atau organisasi anda."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Berlaku masalah semasa menyimpan tangkapan skrin."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Tidak dapat menyimpan tangkapan skrin kerana ruang storan terhad."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Apl atau organisasi anda tidak membenarkan pengambilan tangkapan skrin."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Pilihan pemindahan fail USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Lekapkan sebagai pemain media (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Lekapkan sebagai kamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ketepikan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ditolak."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaharu diketepikan."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulakan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan diketepikan."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lagi masa."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kurang masa."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampu suluh dimatikan."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampu suluh tidak tersedia."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampu suluh dihidupkan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampu suluh dimatikan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampu suluh dihidupkan."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mod kerja hidup."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Mod kerja dimatikan."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Mod kerja dihidupkan."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Penjimat Data dimatikan."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Penjimat Data dihidupkan."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan paparan"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi ditetapkan oleh GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Padamkan semua pemberitahuan."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Tetapan pemberitahuan"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> tetapan"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrin akan berputar secara automatik."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> had"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mod kerja"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Skrin terbaru anda terpapar di sini"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Tiada item terbaharu"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda telah mengetepikan semua item"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"penyematan skrin"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Sejarah"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Kosongkan"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> dilumpuhkan dalam mod selamat."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Kosongkan semua"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Apl ini tidak menyokong berbilang tetingkap"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Apl tidak menyokong berbilang tetingkap"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Mendatar Terpisah"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Menegak Terpisah"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tersuai Terpisah"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Senyap\nsepenuhnya"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Keutamaan\nsahaja"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Penggera\nsahaja"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Semua"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Semua\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengecas cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengecas perlahan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Dayakan pemecut leret ke atas untuk memasuki skrin terpisah"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Dayakan gerak isyarat leret ke atas utk masuk skrin terpisah"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Dayakan gerak isyarat untuk memasuki skrin terpisah dengan meleret ke atas daripada butang Ikhtisar"</string>
     <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Hidupkan"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Gunakan untuk pemberitahuan <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Gunakan untuk semua pemberitahuan daripada apl ini"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Tunjukkan pemberitahuan secara senyap"</string>
+    <string name="block" msgid="2734508760962682611">"Sekat semua pemberitahuan"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Jangan senyapkan"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Jangan senyapkan atau sekat"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tunjukkan tetapan kepentingan penuh"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Disekat"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Kurang penting"</string>
     <string name="low_importance" msgid="4109929986107147930">"Kepentingan rendah"</string>
     <string name="default_importance" msgid="8192107689995742653">"Kepentingan biasa"</string>
     <string name="high_importance" msgid="1527066195614050263">"Kepentingan tinggi"</string>
     <string name="max_importance" msgid="5089005872719563894">"Kepentingan segera"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan pemberitahuan ini secara senyap"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan pada bahagian atas senarai pemberitahuan dan bunyikan"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Intai pada skrin dan bunyikan"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tunjukkan pemberitahuan ini secara senyap"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Benarkan pemberitahuan ini berbunyi"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Intai pada skrin dan benarkan bunyi"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Tunjukkan pada bahagian atas senarai pemberitahuan, intai pada skrin dan benarkan bunyi"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
     <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Warna biasa"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Warna tersuai"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Warna tidak diketahui"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Pengubahsuaian warna"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tunjukkan jubin Tetapan Pantas"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Dayakan jelmaan tersuai"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kawalan pemberitahuan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Warna dan penampilan"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Mod malam"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Tentukur paparan"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Hidup"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Mati"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Hidupkan secara automatik"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Beralih ke Mod Malam sebagaimana sesuai untuk lokasi dan masa"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Apabila Mod Malam dihidupkan"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Gunakan tema gelap untuk OS Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Laraskan seri warna"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Laraskan kecerahan"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema gelap digunakan pada bahagian teras OS Android yang biasanya dipaparkan dalam tema cerah, seperti Tetapan."</string>
     <string name="color_apply" msgid="9212602012641034283">"Gunakan"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Sahkan tetapan"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Sesetengah tetapan warna boleh menjadikan peranti ini tidak dapat digunakan. Klik OK untuk mengesahkan tetapan warna ini, jika tidak, tetapan ini akan ditetapkan semula selepas 10 saat."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Penggunaan bateri"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penjimat Bateri tidak tersedia semasa mengecas"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Penjimat Bateri"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangkan prestasi dan data latar belakang"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Butang <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Skrin Utama"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Kembali"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Ke atas"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ke bawah"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Ke kiri"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Ke kanan"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Tengah"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Undur ruang"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Main/Jeda"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Berhenti"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seterusnya"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Sebelumnya"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Mandir"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Mara Laju"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Pad nombor <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Skrin Utama"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaharu"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Tunjukkan jangan ganggu dalam kelantangan"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Benarkan kawalan penuh jangan ganggu dalam dialog kelantangan."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Kelantangan dan Jangan Ganggu"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Masuki mod jangan ganggu apabila kelantangan direndahkan"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Pemberitahuan"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pintasan Papan Kekunci"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Tukar kaedah input"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikasi"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bantu"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Penyemak imbas"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kenalan"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mel"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzik"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Tunjukkan dengan kawalan kelantangan"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan butang kelantangan"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Keluar drp mod jangan ganggu apabila kelantangan ditinggikan"</string>
     <string name="battery" msgid="7498329822413202973">"Bateri"</string>
     <string name="clock" msgid="7416090374234785905">"Jam"</string>
     <string name="headset" msgid="4534219457597457353">"Set Kepala"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fon kepala disambungkan"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Set kepala disambungkan"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Dayakan atau lumpuhkan ikon daripada dipaparkan dalam bar status."</string>
     <string name="data_saver" msgid="5037565123367048522">"Penjimat Data"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Penjimat Data dihidupkan"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Penjimat Data dimatikan"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Hidup"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Mati"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Bar navigasi"</string>
     <string name="start" msgid="6873794757232879664">"Mula"</string>
     <string name="center" msgid="4327473927066010960">"Tengah"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Pilih Butang Papan Kekunci"</string>
     <string name="preview" msgid="9077832302472282938">"Pratonton"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Seret untuk menambahkan jubin"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Seret ke sini untuk mengalih keluar"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Masa"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Tunjukkan jam, minit dan saat"</item>
+    <item msgid="1427801730816895300">"Tunjukkan jam dan minit (lalai)"</item>
+    <item msgid="3830170141562534721">"Jangan tunjukkan ikon ini"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Sentiasa tunjukkan peratusan"</item>
+    <item msgid="2139628951880142927">"Tunjukkan peratusan semasa mengecas (lalai)"</item>
+    <item msgid="3327323682209964956">"Jangan tunjukkan ikon ini"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Lain-lain"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Pembahagi skrin pisah"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Alih ke bawah"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Alih ke atas"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Alih ke kiri"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Alih ke kanan"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Apl mungkin tidak berfungsi dengan berbilang tetingkap"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dwiketik untuk mengedit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dwiketik untuk menambah."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>. Dwiketik untuk memilih."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Alihkan <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Alih keluar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ditambahkan pada kedudukan <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dialih keluar"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dialihkan ke kedudukan <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor tetapan pantas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings_tv.xml b/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
new file mode 100644
index 0000000..eb5af9e3
--- /dev/null
+++ b/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Tutup PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Skrin penuh"</string>
+    <string name="pip_play" msgid="674145557658227044">"Main"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Jeda"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Thn "<b>"SKRN UTMA"</b>" utk kwl PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Tekan dan tahan butang SKRIN UTAMA untuk mengawal PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ketepikan"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 60e2812..6964750 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"မျက်နှာပြင်လျှပ်တပြက်ပုံကို မရုက်နိုင်ခဲ့ပါ၊ သိုလှောင်မှု နေရာ အကန့်အသတ် ရှိနေ၍ သို့မဟုတ် app သို့မဟုတ် သင်၏ အဖွဲ့အစည်းက ခွင့်မပြု၍ ဖြစ်နိုင်သည်။"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ဖန်သားပြင်ဓာတ်ပုံဖမ်းယူမှုကို သိမ်းဆည်းရာတွင် ပြဿနာကြုံခဲ့သည်။"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"သိုလှောင်ခန်းနေရာ အကန့်အသတ်ရှိသောကြောင့် ဖန်သားပြင်ဓာတ်ပုံကို သိမ်းဆည်း၍မရပါ။"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ဖန်သားပြင်ဓာတ်ပုံရိုက်ကူးခြင်းကို အက်ပ်မှ သို့မဟုတ် သင့်အဖွဲ့အစည်းမှ ခွင့်မပြုပါ။"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ဖိုင်ပြောင်း ရွေးမှုများ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"မီဒီယာပလေရာအနေဖြင့် တပ်ဆင်ရန် (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ကင်မရာအနေဖြင့် တပ်ဆင်ရန် (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ကို ပယ်လိုက်ရန်"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ထုတ်ထားသည်။"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"မကြာသေးမီက အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်ပြီးပါပြီ။"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ကို စတင်နေသည်။"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"အကြောင်းကြားချက်ကိုဖယ်ရှားပြီး"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"အချိန် တိုး"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"အချိန် လျှော့"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ဖလက်ရှမီး ပိတ်ထား"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ဓာတ်မီးမရသေးပါ။"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ဖလက်ရှမီး ဖွင့်ထား။"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ဖလက်ရှမီး ပိတ်ထားသည်။"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ဖလက်ရှမီး ဖွင့်ထားသည်။"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"အလုပ် မုဒ်ကို ဖွင့်ထားပါသည်။"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"အလုပ် မုဒ်ကို ပိတ်ထားပါသည်။"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"အလုပ် မုဒ်ကို ဖွင့်ထားပါသည်။"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ဒေတာချွေတာမှု ပိတ်ထားသည်။"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ဒေတာချွေတာမှု ဖွင့်ထားသည်။"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"တောက်ပမှုကို ပြရန်"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPSမှတည်နေရာကိုအတည်ပြုသည်"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"တည်နေရာပြ တောင်းဆိုချက်များ အသက်ဝင်ရန်"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"သတိပေးချက်အားလုံးအား ဖယ်ရှားခြင်း။"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"အကြောင်းကြားချက် ဆက်တင်များ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ဆက်တင်များ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ဖန်သားပြင်ပေါ်မှာ ပြသမှုက အလိုအလျောက် လှည့်သွားပါမည်"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ကန့်သတ်ချက်"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> သတိပေးချက်"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"အလုပ် မုဒ်"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"သင်၏ မကြာမီက မျက်နှာပြင်များ ဒီမှာ ပေါ်လာကြမည်"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"သင်အားလုံးကို ရှင်းလင်းပြီးပါပြီ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"အပလီကေးရှင်း အင်ဖို"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"မျက်နှာပြင် ပင်ထိုးမှု"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ရှာဖွေရန်"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ကို မစနိုင်ပါ။"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"မှတ်တမ်း"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ရှင်းလင်းပါ"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ကို ဘေးကင်းလုံခြုံသည့်မုဒ်တွင် ပိတ်ထားပါသည်။"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"အားလုံး ရှင်းလင်းပါ"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ဤအက်ပ်သည် ဝင်းဒိုးများစွာဖွင့်ခြင်းကို ပံ့ပိုးမထားပါ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"အက်ပ်သည် ဝင်းဒိုးများစွာဖွင့်ခြင်းကို ပံ့ပိုးမထားပါ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"လုံးဝ\nတိတ်ဆိတ်ခြင်း"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ဦးစားပေးမှု\nသာ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"နှိုးစက်များ\nသာ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"အားလုံး"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"အားလုံး\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"လျှင်မြန်စွာအားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"နှေးကွေးစွာ အားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
     <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း လုပ်ဆောင်ချက်ကိုဖွင့်ပါ"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း အမူအရာကိုဖွင့်ပါ"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်ဟန်ကိုဖွင့်ပါ"</string>
     <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ဖွင့်ပါ"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"သတိပေးချက် <xliff:g id="TOPIC_NAME">%1$s</xliff:g> ခုသို့သက်ရောက်စေပါ"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ဤအက်ပ်မှ သတိပေးချက်များအားလုံးသို့ သက်ရောက်စေပါ"</string>
+    <string name="show_silently" msgid="6841966539811264192">"သတိပေးချက်များကို တိတ်ဆိတ်စွာပြပါ"</string>
+    <string name="block" msgid="2734508760962682611">"သတိပေးချက်များအားလုံးကို ပိတ်ဆို့ပါ"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"အသံ မတိတ်ပါနှင့်"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"အသံ မတိတ်ပါနှင့် သို့မဟုတ် မပိတ်ဆို့ပါနှင့်"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"အပြည့်အဝအရေးပါသည့် ဆက်တင်များကိုပြပါ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"ပိတ်ဆို့ထားသည်"</string>
+    <string name="min_importance" msgid="1901894910809414782">"အနည်းဆုံး အရေးပါမှု"</string>
     <string name="low_importance" msgid="4109929986107147930">"အနည်းငယ်သာ အရေးပါသည်"</string>
     <string name="default_importance" msgid="8192107689995742653">"သာမန်သာ အရေးပါသည်"</string>
     <string name="high_importance" msgid="1527066195614050263">"အလွန်အရေးပါသည်"</string>
     <string name="max_importance" msgid="5089005872719563894">"အရေးတကြီး အရေးပါသည်"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ဤသတိပေးချက်များကို ဘယ်တော့မှမပြပါနှင့်"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"သတိပေးချက်စာရင်း၏ အောက်ဆုံးတွင် တိတ်တဆိတ်ပြပါ"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ဤသတိပေးချက်များကို တိတ်တဆိတ်ပြပါ"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"သတိပေးချက်စာရင်းများ၏ ထိပ်တွင်ပြကာ အသံဖွင့်ပါ"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"မျက်နှာပြင်ပေါ်သို့ ဖော်ပြကာ အသံဖွင့်ပါ"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"သတိပေးချက်စာရင်း၏ အောက်ဆုံးတွင် တိတ်ဆိတ်စွာပြပါ"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ဤသတိပေးချက်များကို တိတ်ဆိတ်စွာပြပါ"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ဤသတိပေးချက်များကို အသံထွက်ခွင့်ပြုပါ"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"ဖန်သားပြင်ပေါ်တွင် ပေါ်စေပြီး အသံထွက်ခွင့်ပြုပါ"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"သတိပေးချက်စာရင်း၏ ထိပ်ဆုံးတွင်ပြပြီး ဖန်သားပြင်ပေါ်တွင် ပေါ်စေကာ အသံထွက်ခွင့်ပြုပါ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"နောက်ထပ် ဆက်တင်များ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ပြီးပါပြီ"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"ပုံမှန် အရောင်များ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"ည အရောင်များ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"စိတ်ကြိုက် အရောင်များ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"အလိုအလျောက်"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"မသိသည့် အရောင်များ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"အရောင် မွမ်းမံမှု"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"အမြန် ဆက်တင် လေးထောင့်ကွက်ကို ပြပါ"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"စိတ်ကြိုက် ပြောင်းလဲမှုကို ဖွင့်ပါ"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"အရောင်နှင့် အပြင်အဆင်"</string>
+    <string name="night_mode" msgid="3540405868248625488">"ညသုံးမုဒ်"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ပြသမှုအချိန်အဆကို ညှိပါ"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ဖွင့်ပါ"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ပိတ်ပါ"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"အလိုအလျောက် ဖွင့်ပါ"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"တည်နေရာနှင့် တစ်ရက်တာအချိန်နှင့် သင့်လျော်သလို ညသုံးမုဒ်သို့ ပြောင်းပါ"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"ညသုံမုဒ်ဖွင့်ထားစဉ်"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS အတွက်အရောင်ရင့်အပြင်အဆင်ကို သုံးပါ"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"အရောင်မွဲမှုကို ချိန်ပါ"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"အလင်းအမှောင်ချိန်ပါ"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"အရောင်ရင့်အပြင်အဆင်သည် ဆက်တင်များကဲ့သို့ ပုံမှန်အားဖြင့် အရောင်ဖျော့အပြင်အဆင်အဖြစ်ရှိသည့် Android OS ၏အဓိကနေရာများကို ပြောင်းလဲပေးပါသည်။"</string>
     <string name="color_apply" msgid="9212602012641034283">"အသုံးပြုပါ"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ဆက်တင်များကို အတည်ပြုပါ"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"အချို့သော အရောင်ဆက်တက်များက ဤကိရိယာကို သုံးမရအောင် လုပ်ပစ်နိုင်ပါသည်။ ဤအရောင် ဆက်တင်များကို အတည်ပြုရန် အိုကေကို နှိပ်ပါ၊ သို့မဟုတ် ဤဆက်တင်များကို ၁၀ စက္ကန့် အကြာတွင် ပြန်ညှိလိုက်ပါမည်။"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"ဘက်ထရီ အသုံးပြုမှု"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"အားသွင်းနေချိန်မှာ Battery Saver ကို သုံးမရပါ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"လုပ်ဆောင်မှု နှင့် နောက်ခံ ​ဒေတာကို လျော့နည်းစေပါသည်"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"ခလုတ် <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"ပင်မ"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"နောက်သို့"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"အပေါ်"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"အောက်"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ဘယ်"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ညာ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ဌာန"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"တဘ်"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"နေရာခြားပါ"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter ခလုတ်"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"နောက်ပြန်ဖျက်ပါ"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ဖွင့်ပါ/ခဏရပ်ပါ"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ရပ်ပါ"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"ရှေ့သို့"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ယခင်"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"နောက်သို့ရစ်ပါ"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ရှေ့သို့ရစ်ပါ"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"အပေါ်စာမျက်နှာသို့သွားပါ"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"အောက်စာမျက်နှာသို့သွားပါ"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ဖျက်ပါ"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"ပင်မ"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"ပြီးပါပြီ"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"ထည့်ပါ"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"ဂဏန်းကွက်<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"စနစ်"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"နောက်သို့"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"အသံအတိုးအလျှော့တွင် မနှောက်ယှက်ရကို ပြပါ"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"အသံအတိုးအလျှော့အကွက်ထဲတွင် မနှောက်ယှက်ရကို အပြည့်အဝထိန်းချုပ်ခွင့် ပြုပါ။"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"အသံအတိုးအလျှော့နှင့် မနှောက်ယှက်ရ"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"အသံလျှော့သည်နှင့် မနှောက်ယှက်ရသို့ ပြောင်းလဲပါ"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"အကြောင်းကြားချက်များ"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ကီးဘုတ် ဖြတ်လမ်းများ"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ထည့်သွင်းမှုနည်းလမ်းကို ပြောင်းလဲပါ"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"အက်ပ်များ"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"အထောက်အကူ"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ဘရောင်ဇာ"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"အဆက်အသွယ်များ"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"အီးမေးလ်"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"အမြန်စာတိုစနစ်"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ပြက္ခဒိန်"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"အသံထိန်းချုပ်သည့်ခလုတ်များဖြင့် ပြပါ"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"မနှောက်ယှက်ပါနှင့်"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"အသံထိန်းချုပ်သည့်ခလုတ် ဖြတ်လမ်း"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"အသံချဲ့သည်နှင့် မနှောက်ယှက်ရမှ ထွက်ပါ"</string>
     <string name="battery" msgid="7498329822413202973">"ဘတ်ထရီ"</string>
     <string name="clock" msgid="7416090374234785905">"နာရီ"</string>
     <string name="headset" msgid="4534219457597457353">"မိုက်ခွက်ပါနားကြပ်"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"နားကြပ်တပ်ဆင်ပြီးပါပြီ"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"မိုက်ခွက်ပါနားကြပ်တပ်ဆင်ပြီးပါပြီ"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"အခြေအနေဘားတန်းတွင် သင်္ကေတပုံပြခြင်းကို ဖွင့်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
     <string name="data_saver" msgid="5037565123367048522">"ဒေတာချွေတာမှု"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ဒေတာချွေတာမှု ဖွင့်ထားသည်"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ဒေတာချွေတာမှု ပိတ်ထားသည်"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ဖွင့်ပါ"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ပိတ်ပါ"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ရွှေ့လျားရန်ဘားတန်း"</string>
     <string name="start" msgid="6873794757232879664">"စတင်ပါ"</string>
     <string name="center" msgid="4327473927066010960">"ဌာန"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"ကီးဘုတ်ခလုတ်ကို ရွေးချယ်ပါ"</string>
     <string name="preview" msgid="9077832302472282938">"အစမ်းကြည့်ပါ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"အချပ်များကိုထည့်ရန် ဖိဆွဲပါ"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ဖယ်ရှားရန် ဤနေရာသို့ဖိဆွဲပါ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"တည်းဖြတ်ပါ"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"အချိန်"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"နာရီ၊ မိနစ်နှင့် စက္ကန့်ကိုပြပါ"</item>
+    <item msgid="1427801730816895300">"နာရီနှင့် မိနစ်ကိုပြပါ (ပုံသေ)"</item>
+    <item msgid="3830170141562534721">"ဤသင်္ကေတပုံကို မပြပါနှင့်"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"ရာခိုင်နှုန်းကို အမြဲတမ်းပြပါ"</item>
+    <item msgid="2139628951880142927">"အားသွင်းနေစဉ်တွင် ရာခိုင်နှုန်းကိုပြပါ (ပုံသေ)"</item>
+    <item msgid="3327323682209964956">"ဤသင်္ကေတပုံကို မပြပါနှင့်"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"အခြား"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"မျက်နှာပြင်ခွဲခြမ်း ပိုင်းခြားပေးသည့်စနစ်"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"အောက်သို့ရွှေ့ပါ"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"အပေါ်သို့ရွှေ့ပါ"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ဘယ်ဘက်သို့ရွှေ့ပါ"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ညာဘက်သို့ရွှေ့ပါ"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"အက်ပ်သည် ဝင်းဒိုးများတပြိုင်နက်ဖွင့်ခြင်းကို မပံ့ပိုးပါ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>၊ <xliff:g id="TILE_NAME">%2$s</xliff:g> နေရာ။ တည်းဖြတ်ရန် နှစ်ချက်တို့ပါ။"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>။ ပေါင်းထည့်ရန် နှစ်ချက်တို့ပါ။"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> နေရာ။ ရွေးချယ်ရန် နှစ်ချက်တို့ပါ။"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုရွှေ့ပါ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုဖယ်ရှားပါ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကို <xliff:g id="POSITION">%2$d</xliff:g> နေရာသို့ ပေါင်းထည့်ထားပါသည်"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုဖယ်ရှားလိုက်ပါပြီ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကို <xliff:g id="POSITION">%2$d</xliff:g> နေရာသို့ ရွှေ့လိုက်ပါပြီ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"မြန်ဆန်သည့် ဆက်တင်တည်းဖြတ်စနစ်"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings_tv.xml b/packages/SystemUI/res/values-my-rMM/strings_tv.xml
new file mode 100644
index 0000000..ffb0d90
--- /dev/null
+++ b/packages/SystemUI/res/values-my-rMM/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP ကိုပိတ်ပါ"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"မျက်နှာပြင် အပြည့်"</string>
+    <string name="pip_play" msgid="674145557658227044">"ဖွင့်ပါ"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"ဆိုင်းငံ့ပါ"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP ကိုထိန်းချုပ်ရန် "<b>"ပင်မ"</b>" ခလုတ်ကို ဖိထားပါ"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP ကိုထိန်းချုပ်ရန် ပင်မခလုတ်ကို နှိပ်ပြီးဖိထားပါ"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"ရပါပြီ"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"ပယ်ပါ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index f326a01..eed5f36 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skjermdumpen er lagret."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Trykk for å se skjermdumpen."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kan ikke lagre skjermdumpen."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan ikke ta skjermdump grunnet plassbegrensning, app- eller organisasjonstillatelser."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Det oppsto et problem under lagring av skjermdumpen."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan ikke lagre skjermdumpen på grunn av begrenset lagringsplass."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Appen eller organisasjonen din tillater ikke at du tar skjermdumper."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Altern. for USB-filoverføring"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Sett inn som mediespiller (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Sett inn som kamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Avvis <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> avvist."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle nylig brukte apper er avvist."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starter <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Varselet ble skjult."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mer tid."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelykten er av."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lommelykt er ikke tilgjengelig."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelykten er på."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelykten er slått av."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelykten er slått på."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbeidsmodusen er på."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbeidsmodusen er slått av."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbeidsmodusen er slått på."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Datasparing er slått av."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Datasparing er slått på."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Lysstyrken på skjermen"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- og 3G-data er satt på pause"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Posisjon angitt av GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive stedsforespørsler"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Fjern alle varslinger."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Varselinnstillinger"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>-innstillinger"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjermen roterer automatisk."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Grense på <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeidsmodus"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"De sist brukte skjermene dine vises her"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Ingen nylige elementer"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har fjernet alt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"én-appsmodus"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Logg"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tøm"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er slått av i sikker modus."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tøm alt"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Denne appen har ikke støtte for flervindusmodus"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen har ikke støtte for flervindusmodus"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Del vertikalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Del tilpasset"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nstillhet"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Bare\nPrioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Bare\nalarmer"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Lader raskt (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lader sakte (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -395,7 +402,7 @@
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheten forblir låst til du låser den opp manuelt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Motta varsler raskere"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem før du låser opp"</string>
-    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nei, takk"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nei takk"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"Konfigurer"</string>
     <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="volume_zen_end_now" msgid="3179845345429841822">"Avslutt nå"</string>
@@ -404,7 +411,7 @@
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjermen er låst"</string>
     <string name="screen_pinning_description" msgid="3577937698406151604">"På denne måten blir skjermen synlig frem til du låser den opp. Trykk og hold inne Tilbake for å låse opp."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Skjønner"</string>
-    <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei, takk"</string>
+    <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igjen neste gang du slår den på i innstillingene."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Slå på delt skjerm ved å sveipe opp med akseleratoren"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Slå på delt skjerm ved å sveipe opp"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Slå på bevegelsen for å åpne delt skjerm ved å sveipe opp fra Oversikt-knappen"</string>
     <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå på"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Bruk for varsler for <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Bruk for alle varslene fra denne appen"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Vis varsler uten lyd"</string>
+    <string name="block" msgid="2734508760962682611">"Blokkér alle varsler"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ikke slå av lyden"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ikke slå av lyden eller blokkér anrop"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vis alle viktighetsinnstillingene"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokkert"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Laveste prioritet"</string>
     <string name="low_importance" msgid="4109929986107147930">"Lav viktighet"</string>
     <string name="default_importance" msgid="8192107689995742653">"Vanlig viktighet"</string>
     <string name="high_importance" msgid="1527066195614050263">"Høy viktighet"</string>
     <string name="max_importance" msgid="5089005872719563894">"Svært høy viktighet"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Aldri vis disse varslene"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Vis nederst på varsellisten uten lyd"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse varslene uten lyd"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på varsellisten med lyd"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Vis fort på skjermen med lyd"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Vis nederst på varsellisten uten lyd"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Vis disse varslene uten lyd"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Tillat at disse varslene vises med lyd"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Vis fort på skjermen og tillat lyd"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Vis øverst på varsellisten, vis fort på skjermen og tillat lyd"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normale farger"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nattfarger"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Spesialtilpassede farger"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisk"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Ukjente farger"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Fargemodifisering"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Vis ruten for hurtiginnstillinger"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Slå på spesialtilpasset forvandling"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Varselinnstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Farge og utseende"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nattmodus"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibrer skjermen"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"På"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Av"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Slå på automatisk"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Bytt til nattmodus avhengig av tid og sted"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Når nattmodus er på"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Bruk et mørkt tema for Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Juster fargen"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Juster lysstyrken"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Det mørke temaet brukes på kjerneområdene i Android OS som vanligvis vises i et lyst tema, for eksempel Innstillinger."</string>
     <string name="color_apply" msgid="9212602012641034283">"Bruk"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Bekreft innstillingene"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Noen fargeinnstillinger kan gjøre denne enheten ubrukelig. Klikk på OK for å bekrefte disse fargeinnstillingene, ellers blir de tilbakestilt etter ti sekunder."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Batteribruk"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparing er ikke tilgjengelig under lading"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparing"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>-knappen"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Startskjerm"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Tilbake"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Opp"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ned"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Venstre"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Høyre"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Midttasten"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Mellomrom"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tilbaketasten"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Spill av / sett på pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stopp"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Neste"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Forrige"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spol tilbake"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Spol fremover"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Startskjerm"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> på talltastaturet"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startside"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nylige"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbake"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Vis «Ikke forstyrr» i volumkontrollene"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Tillat full kontroll over «Ikke forstyrr» i volumdialogen."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volum og «Ikke forstyrr»"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Åpne «Ikke forstyrr» med volum ned-knappen"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Varsler"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Hurtigtaster"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Bytt inndatametode"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apper"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Nettleser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakter"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musikk"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med volumkontrollene"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ikke forstyrr"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Hurtigtast for volumknappene"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Lukk «Ikke forstyrr» med volum opp-knappen"</string>
     <string name="battery" msgid="7498329822413202973">"Batteri"</string>
     <string name="clock" msgid="7416090374234785905">"Klokke"</string>
     <string name="headset" msgid="4534219457597457353">"Hodetelefoner"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Øretelefoner er tilkoblet"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Hodetelefoner er tilkoblet"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Vis eller skjul ikoner i statusfeltet."</string>
     <string name="data_saver" msgid="5037565123367048522">"Datasparing"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datasparing er på"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datasparing er av"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"På"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Av"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigasjonsrad"</string>
     <string name="start" msgid="6873794757232879664">"Start"</string>
     <string name="center" msgid="4327473927066010960">"Midtstilt"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Velg tastaturtast"</string>
     <string name="preview" msgid="9077832302472282938">"Forhåndsvisning"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Dra for å legge til fliser"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Dra hit for å fjerne"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Endre"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Tid"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Vis timer, minutter og sekunder"</item>
+    <item msgid="1427801730816895300">"Vis timer og minutter (standard)"</item>
+    <item msgid="3830170141562534721">"Ikke vis dette ikonet"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Vis alltid prosentandel"</item>
+    <item msgid="2139628951880142927">"Vis prosentandel under lading (standard)"</item>
+    <item msgid="3327323682209964956">"Ikke vis dette ikonet"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Annet"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Skilleelement for delt skjerm"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytt ned"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytt opp"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytt mot venstre"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytt mot høyre"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerer kanskje ikke i Flervindusmodus"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Plassering <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dobbelttrykk for å endre."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dobbelttrykk for å legge til."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Plassering <xliff:g id="POSITION">%1$d</xliff:g>. Dobbelttrykk for å velge."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flytt <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjern <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er lagt til i plassering <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er fjernet"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er flyttet til plassering <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsvindu for hurtiginnstillinger."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
new file mode 100644
index 0000000..33bd1aa
--- /dev/null
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Lukk PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Fullskjerm"</string>
+    <string name="pip_play" msgid="674145557658227044">"Spill av"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Sett på pause"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Hold inne "<b>"STARTSIDE"</b>" for å kontrollere PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Trykk og hold inne STARTSIDE-knappen for å kontrollere PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Greit"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Avvis"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 9b67d9c..836dc4b 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"सीमित भण्डारण ठाउँको कारणले स्क्रिनसट लिन सकिएन, वा यो अनुप्रयोग वा आफ्नो संगठन द्वारा अनुमति छैन।"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"स्क्रिनसटलाई सुरक्षित गर्दा समस्या भयो।"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"सीमित भण्डारण स्थान उपलब्ध रहेको हुनाले स्क्रिनसटलाई सुरक्षित गर्न सकिँदैन।"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"अनुप्रयोग वा तपाईँको संगठनले स्क्रिनसट लिन अनुमति दॅिंदैन।"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB फाइल सार्ने विकल्पहरू"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"मिडिया प्लेयर(MTP)को रूपमा माउन्ट गर्नुहोस्"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"क्यामेराको रूपमा माउन्ट गर्नुहोस् (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> खारेज गर्नुहोस्।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खारेज गरिएको छ।"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"सबै हालका अनुप्रयोगहरू खारेज गरियो।"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>सुरु गर्दै।"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारेज।"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"थप समय।"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कम समय।"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"टर्च बन्द छ।"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"फ्ल्यासलाइट उपलब्ध छैन।"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"टर्च खुला छ।"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"टर्च बन्द गरियो।"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"टर्च खुला गरियो।"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"कार्य मोड अन।"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"कार्य मोड बन्द भयो।"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"कार्य मोड सक्रिय भयो।"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"डेटा सेभरलाई निष्क्रिय पारियो।"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"डेटा सेभरलाई सक्रिय गरियो।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटा रोकिएको छ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा स्थान सेट गरिएको"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोधहरू सक्रिय"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"सबै सूचनाहरू हटाउनुहोस्।"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"अधिसूचना सेटिङ्हरू"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिङ्हरू"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रिन स्वतः घुम्ने छ।"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"तपाईँको हालको स्क्रिन यहाँ प्रकट हुन्छ"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"हालका कुनै पनि वस्तुहरू छैनन्"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"तपाईँले सबै कुरा खाली गर्नुभएको छ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग जानकारी"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रिन पिन गर्दै"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोजी गर्नुहोस्"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"सुरु गर्न सकिएन <xliff:g id="APP">%s</xliff:g>।"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"मेटाउनुहोस्"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> लाई सुरक्षित-मोडमा असक्षम गरिएको छ।"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"सबै हटाउनुहोस्"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"यस अनुप्रयोगले बहु-विन्डोलाई समर्थन गर्दैन"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"अनुप्रयोगले बहु-विन्डोलाई समर्थन गर्दैन"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"अनुकूलन विभाजन गर्नुहोस्"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"पूरै\nशान्त"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"प्राथमिकता \nमात्र"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"अलार्महरू \nमात्र"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"सबै"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"सबै\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"छिटो चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"बिस्तारै चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
@@ -448,60 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"विभाजित-स्क्रिनको स्वाइप-अप एक्सेलेटर सक्रिय गर्नुहोस्"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रिन स्वाइप-अप इशारा सक्षम गर्नुहोस्"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न इसारालाई सक्रिय गर्नुहोस्"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"सक्रिय पार्नुहोस्"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> सूचनाहरूमा लागू गर्नुहोस्"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"यो अनुप्रयोगका सबै सूचनाहरूमा लागू गर्नुहोस्"</string>
+    <string name="show_silently" msgid="6841966539811264192">"सूचनाहरूलाई बिना आवाज देखाउने"</string>
+    <string name="block" msgid="2734508760962682611">"सबै सूचनाहरूलाई रोक्नुहोस्"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"मौन नगर्नुहोस्"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"मौन नगर्नुहोस् वा नरोक्नुहोस्"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्त्व सेटिङहरू देखाउने"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"रोकियो"</string>
+    <string name="min_importance" msgid="1901894910809414782">"न्यूनतम महत्त्व"</string>
     <string name="low_importance" msgid="4109929986107147930">"न्यून महत्त्व"</string>
     <string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
     <string name="high_importance" msgid="1527066195614050263">"उच्च महत्त्व"</string>
     <string name="max_importance" msgid="5089005872719563894">"जरूरी महत्त्व"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"यी सूचनाहरू कहिल्यै नदेखाउनुहोस्"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"सूचीको फेदमा बिना आवाज देखाउनुहोस्"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"यी सूचनाहरू बिना आवाज देखाउनुहोस्"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीको शीर्षमा देखाउनुहोस् र आवाज निकाल्नुहोस्"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रिनमा हेर्नुहोस् र आवाज निकाल्नुहोस्"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"सूचना सूचीको फेदमा बिना आवाज देखाउने"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"यी सूचनाहरूलाई बिना आवाज देखाउने"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"यी सूचनाहरूलाई ध्वनि निकाल्न अनुमति दिने"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"स्क्रिनमा चियाउने र ध्वनि निकाल्न अनुमति दिने"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"सूचना सूचीको शीर्षमा देखाउने, स्क्रिनमा चियाउने र ध्वनि निकाल्न अनुमति दिने"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
     <string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रङहरू"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"रात्री रङहरू"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"अनुकूलन रङहरू"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"स्वतः"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रङहरू"</string>
-    <string name="color_transform" msgid="6985460408079086090">"रङ परिमार्जन"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"द्रुत सेटिङ टाइल देखाउनुहोस्"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"अनुकूलन रूपान्तरण सक्रिय गर्नुहोस्"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचनाका लागि नियन्त्रणहरू"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"रंग र रूप"</string>
+    <string name="night_mode" msgid="3540405868248625488">"रात्री मोड"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"प्रदर्शनको स्तर  मिलाउनुहोस्"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"सक्रिय"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"निष्क्रिय"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"स्वतः सक्रिय पार्नुहोस्"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"स्थान र दिनको समयको लागि उपयुक्त रात्री मोडमा स्विच गर्नुहोस्"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"रात्री मोड सक्रिय हुँदा"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS का लागि गाढा रंगको विषयवस्तु प्रयोग गर्नुहोस्"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"रङ्गलाई समायोजन गर्नुहोस्"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"चमकलाई समायोजन गर्नुहोस्"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"गहिरो रंगको विषयवस्तुलाई Android OS का त्यस्ता मुख्य क्षेत्रहरूमा लागू गरिन्छ जसलाई सामान्यतया हल्का रंगमा देखाइन्छ, जस्तै सेटिङहरू।"</string>
     <string name="color_apply" msgid="9212602012641034283">"लागू गर्नुहोस्"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"सेटिङहरूको पुष्टि गर्नुहोस्"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"केही रङ सेटिङहरूले यस यन्त्रलाई अनुपयोगी बनाउन सक्छन्। यी रङ सेटिङहरू पुष्टि गर्न ठीक छ मा क्लिक गर्नुहोस्, अन्यथा यी सेटिङहरू १० सेकेण्डपछि रिसेट हुनेछन्।"</string>
-    <string name="battery_panel_title" msgid="7944156115535366613">"ब्याट्रि उपयोग"</string>
+    <string name="battery_panel_title" msgid="7944156115535366613">"ब्याट्री उपयोग"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज गर्ने समयमा ब्याट्री सेभर उपलब्ध छैन"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ब्याट्री सेभर"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"कार्यसम्पादन र पृष्ठभूमि डेटा घटाउँछ"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> बटन"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"पछाडि"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"माथि"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"तल"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"बायाँ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"दायाँ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"केन्द्र"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"स्पेस"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"ब्याकस्पेस"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"प्ले गर्नुहोस्/पज गर्नुहोस्"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"रोक्नुहोस्"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"अर्को"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"अघिल्लो"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"रिवाइन्ड गर्नुहोस्"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"फास्ट फर्वार्ड"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"नमप्याड <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"प्रणाली"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"गृह"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हालैका"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"पछाडि"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"भोल्युममा बाधा नपुर्याउनुहोस् देखाउनुहोस्"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"भोल्युमको संवादमा बाधा नपुर्याउनुहोस् को पूर्ण नियन्त्रणलाई अनुमति दिनुहोस्"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"भोल्युम र बाधा नपुर्याउनुहोस्"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"भोल्युम कम गर्नेमा बाधा नपुर्याउनुहोस् प्रविष्ट गर्नुहोस्"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचनाहरू"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"किबोर्ड सर्टकटहरू"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट विधिलाई स्विच गर्नुहोस्"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"अनुप्रयोगहरू"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहायता"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउजर"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"सम्पर्कहरू"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"इमेल"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"पात्रो"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"भोल्युम नियन्त्रणसहित देखाउनुहोस्"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"बाधा नपुर्याउनुहोस्"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"भोल्युम बटनका सर्टकट"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"भोल्युम बढाउनेमा बाधा नपुर्याउनुहोस् प्रविष्ट गर्नुहोस्"</string>
     <string name="battery" msgid="7498329822413202973">"ब्याट्री"</string>
     <string name="clock" msgid="7416090374234785905">"घडी"</string>
     <string name="headset" msgid="4534219457597457353">"हेडसेट"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"हेडफोनहरू जडान गरियो"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"हेडसेट जडान गरियो"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"वस्तुस्थिति पट्टीमा देखाइनको लागि आइकनहरू सक्रिय वा निष्क्रिय गर्नुहोस्।"</string>
     <string name="data_saver" msgid="5037565123367048522">"डेटा सेभर"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा सेभर अन छ"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा सेभर बन्द छ"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"सक्रिय गर्नुहोस्"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"निष्क्रिय"</string>
     <string name="nav_bar" msgid="1993221402773877607">"नेभिगेशन पट्टी"</string>
     <string name="start" msgid="6873794757232879664">"सुरु गर्नुहोस्"</string>
     <string name="center" msgid="4327473927066010960">"केन्द्र"</string>
@@ -523,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"किबोर्ड बटन चयन गर्नुहोस्"</string>
     <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलहरू थप्न तान्नुहोस्"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"हटाउनका लागि यहाँ तान्नुहोस्"</string>
     <string name="qs_edit" msgid="2232596095725105230">"सम्पादन गर्नुहोस्"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"समय"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"घण्टा, मिनेट, र सेकेन्ड देखाउनुहोस्"</item>
+    <item msgid="1427801730816895300">"घण्टा र मिनेट (पूर्वनिर्धारित) देखाउनुहोस्"</item>
+    <item msgid="3830170141562534721">"यो आइकन नदेखाउनुहोस्"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"सधैं प्रतिशत देखाउनुहोस्"</item>
+    <item msgid="2139628951880142927">"चार्ज गर्दा प्रतिशत देखाउनुहोस् (पूर्वनिर्धारित)"</item>
+    <item msgid="3327323682209964956">"यो आइकन नदेखाउनुहोस्"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"अन्य"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित-स्क्रिन छुट्याउने"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"तल सार्नुहोस्"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"माथि सार्नुहोस्"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाँया सार्नुहोस्"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दायाँ सार्नुहोस्"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"अनुप्रयोग बहु-विन्डोमा काम नगर्न सक्छ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। सम्पादन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। थप्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>। चयन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई सार्नुहोस्"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई हटाउनुहोस्"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई स्थिति <xliff:g id="POSITION">%2$d</xliff:g> मा थपियो"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई हटाइयो"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई स्थिति <xliff:g id="POSITION">%2$d</xliff:g> मा सारियो"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"द्रुत सेटिङ सम्पादक।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings_tv.xml b/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
new file mode 100644
index 0000000..d9245d2
--- /dev/null
+++ b/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP लाई बन्द गर्नुहोस्"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्क्रिन"</string>
+    <string name="pip_play" msgid="674145557658227044">"प्ले गर्नुहोस्"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"रोक्नुहोस्"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP लाई नियन्त्रण गर्न "<b>"गृह"</b>" कुञ्जीलाई थिचिरहनुहोस्"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"IP लाई नियन्त्रण गर्न गृह बटनलाई थिची होल्ड गर्नुहोस्"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"बुझेँ"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"खारेज गर्नुहोस्"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 23455d8..41075e3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om je screenshot te bekijken."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan geen screenshot maken wegens beperkte opslagruimte of omdat de app of je organisatie dit niet toestaat."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Er is een probleem opgetreden bij het opslaan van het screenshot."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan screenshot niet opslaan vanwege beperkte opslagruimte."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Het maken van screenshots wordt niet toegestaan door de app of je organisatie."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Koppelen als camera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> sluiten."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwijderd."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle recente apps gesloten."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> starten."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Melding verwijderd."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meer tijd."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minder tijd."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Zaklamp uit."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Zaklamp niet beschikbaar."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Zaklamp aan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Zaklamp uitgeschakeld."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Zaklamp ingeschakeld."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Werkmodus aan."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Werkmodus uitgeschakeld."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Werkmodus ingeschakeld."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Databesparing is uitgeschakeld."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Databesparing is ingeschakeld."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helderheid van het scherm"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G/3G-data zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Locatie bepaald met GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Locatieverzoeken actief"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle meldingen wissen."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Instellingen voor meldingen"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>-instellingen"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Scherm wordt automatisch geroteerd."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limiet van <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Je recente schermen worden hier weergegeven"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Geen recente items"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Je hebt alles gewist"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"scherm vastzetten"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kan <xliff:g id="APP">%s</xliff:g> niet starten."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is uitgeschakeld in de veilige modus"</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Geschiedenis"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Wissen"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alles wissen"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Deze app ondersteunt de modus voor meerdere vensters niet"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App ondersteunt meerdere vensters niet"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontaal splitsen"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verticaal splitsen"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Aangepast splitsen"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Totale\nstilte"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Alleen\nprioriteit"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alleen\nalarmen"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Snel opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langzaam opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omhoog vegen voor gesplitst scherm inschakelen"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omhoog vegen voor gesplitst scherm inschakelen"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Gebaar inschakelen om gesplitst scherm te openen door vanaf de knop Overzicht omhoog te vegen"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth inschakelen?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Als je je toetsenbord wilt verbinden met je tablet, moet je eerst Bluetooth inschakelen."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Inschakelen"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Toepassen op meldingen voor <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Toepassen op alle meldingen van deze app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Meldingen zonder geluid weergeven"</string>
+    <string name="block" msgid="2734508760962682611">"Alle meldingen blokkeren"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Niet zonder geluid weergeven"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Niet zonder geluid weergeven of blokkeren"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Volledige instellingen voor belang weergeven"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Geblokkeerd"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimaal belang"</string>
     <string name="low_importance" msgid="4109929986107147930">"Klein belang"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normaal belang"</string>
     <string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgent belang"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Deze meldingen nooit weergeven"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Onder aan de lijst met meldingen weergeven zonder geluid"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Deze meldingen zonder geluid weergeven"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Boven aan de lijst met meldingen weergeven en geluid laten horen"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Op het scherm weergeven en geluid laten horen"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Onder aan de lijst met meldingen weergeven zonder geluid"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Deze meldingen zonder geluid weergeven"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Toestaan dat deze meldingen geluid laten horen"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Op het scherm weergeven en geluid toestaan"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Boven aan de lijst met meldingen weergeven, op het scherm weergeven en geluid toestaan"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleuren"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nachtkleuren"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Aangepaste kleuren"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisch"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Onbekende kleuren"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Kleuraanpassing"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tegel voor \'Snelle instellingen\' weergeven"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Aangepast transformeren inschakelen"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Beheeropties voor <xliff:g id="APP_NAME">%1$s</xliff:g>-meldingen"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Kleur en uiterlijk"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nachtmodus"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Display kalibreren"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Aan"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Uit"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Automatisch inschakelen"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Overschakelen naar nachtmodus indien van toepassing voor locatie en tijd van de dag"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Als nachtmodus is ingeschakeld"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Donker thema gebruiken voor Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Tint aanpassen"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Helderheid aanpassen"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Het donkere thema wordt toegepast op kerngedeelten van het Android-besturingssysteem die normaal gesproken worden weergegeven met een licht thema, zoals Instellingen."</string>
     <string name="color_apply" msgid="9212602012641034283">"Toepassen"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Instellingen bevestigen"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Bij sommige kleurinstellingen kan het apparaat onbruikbaar worden. Klik op OK om deze kleurinstellingen te bevestigen, anders worden deze instellingen na tien seconden gereset."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Accubesparing niet beschikbaar tijdens opladen"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Accubesparing"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vermindert de prestaties en achtergrondgegevens"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Knop <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Terug"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Omhoog"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Omlaag"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Links"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Rechts"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Midden"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Spatiebalk"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Afspelen/Onderbreken"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stoppen"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Volgende"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Vorige"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Terugspoelen"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Vooruitspoelen"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> op numeriek toetsenblok"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Systeem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startpagina"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"\'Niet storen\' weergeven in volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Volledig beheer van \'Niet storen\' in het volumedialoogvenster toestaan."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume en \'Niet storen\'"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"\'Niet storen\' activeren bij volume omlaag"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Meldingen"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Sneltoetsen"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Invoermethode schakelen"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apps"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistentie"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacten"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muziek"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Weergeven met volumeknoppen"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Niet storen"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppen als sneltoets"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"\'Niet storen\' afsluiten bij volume omhoog"</string>
     <string name="battery" msgid="7498329822413202973">"Accu"</string>
     <string name="clock" msgid="7416090374234785905">"Klok"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Hoofdtelefoon aangesloten"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset aangesloten"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"De weergave van pictogrammen in de statusbalk in- of uitschakelen."</string>
     <string name="data_saver" msgid="5037565123367048522">"Databesparing"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Databesparing is ingeschakeld"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Databesparing is uitgeschakeld"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Aan"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Uit"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigatiebalk"</string>
     <string name="start" msgid="6873794757232879664">"Begin"</string>
     <string name="center" msgid="4327473927066010960">"Midden"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Toetsenbordknop selecteren"</string>
     <string name="preview" msgid="9077832302472282938">"Voorbeeld"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om tegels toe te voegen"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hier naartoe om te verwijderen"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Bewerken"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Tijd"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Uren, minuten en seconden weergeven"</item>
+    <item msgid="1427801730816895300">"Uren en minuten weergeven (standaard)"</item>
+    <item msgid="3830170141562534721">"Dit pictogram niet weergeven"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Percentage altijd weergeven"</item>
+    <item msgid="2139628951880142927">"Percentage weergeven tijdens opladen (standaard)"</item>
+    <item msgid="3327323682209964956">"Dit pictogram niet weergeven"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Overig"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Scheiding voor gesplitst scherm"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Omlaag"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Omhoog"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Naar links"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Naar rechts"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"De app werkt mogelijk niet met meerdere vensters"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Positie <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dubbeltik om te bewerken."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dubbeltik om toe te voegen."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Positie <xliff:g id="POSITION">%1$d</xliff:g>. Dubbeltik om te selecteren."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verplaatsen"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verwijderen"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is toegevoegd op positie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verwijderd"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verplaatst naar positie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor voor \'Snelle instellingen\'."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
new file mode 100644
index 0000000..62c364e
--- /dev/null
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP sluiten"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Volledig scherm"</string>
+    <string name="pip_play" msgid="674145557658227044">"Afspelen"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Onderbreken"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Bedien PIP met "<b>"HOME"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Houd HOME ingedrukt om PIP te bedienen"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Sluiten"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 0d8ab19..1703a2f 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"ਸੀਮਿਤ ਸਟੋਰੇਜ ਸਪੇਸ ਦੇ ਕਾਰਨ ਸਕ੍ਰੀਨਸ਼ੌਟ ਨਹੀਂ ਲੈ ਸਕਦਾ ਜਾਂ ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਕੰਪਨੀ ਵੱਲੋਂ ਇਸਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ।"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਕਰਨ ਦੌਰਾਨ ਸਮੱਸਿਆ ਆਈ।"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ਸੀਮਿਤ ਸਟੋਰੇਜ ਥਾਂ ਦੇ ਕਾਰਨ ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਸਕਦਾ।"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਦੁਆਰਾ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ ਦੀ ਮਨਜ਼ੂਰੀ ਨਹੀਂ ਹੈ।"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਚੋਣਾਂ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ਇੱਕ ਮੀਡੀਆ ਪਲੇਅਰ (MTP) ਦੇ ਤੌਰ ਤੇ ਮਾਊਂਟ ਕਰੋ"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ਇੱਕ ਕੈਮਰੇ (PTP) ਦੇ ਤੌਰ ਤੇ ਮਾਊਂਟ ਕਰੋ"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਰੱਦ ਕਰੋ।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ਰੱਦ ਕੀਤਾ।"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ਸਾਰੀਆਂ ਹਾਲੀਆ ਐਪਲੀਕੇਸ਼ਨਾਂ ਰੱਦ ਕੀਤੀਆਂ।"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ਚਾਲੂ ਕਰ ਰਿਹਾ ਹੈ।"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ਸੂਚਨਾ ਰੱਦ ਕੀਤੀ।"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ਹੋਰ ਸਮਾਂ।"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ਘੱਟ ਸਮਾਂ।"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ਫਲੈਸ਼ਲਾਈਟ ਬੰਦ।"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ਫਲੈਸ਼ਲਾਈਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ਫਲੈਸ਼ਲਾਈਟ ਚਾਲੂ।"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ਫਲੈਸ਼ਲਾਈਟ ਬੰਦ ਕੀਤਾ।"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ਫਲੈਸ਼ਲਾਈਟ ਚਾਲੂ ਕੀਤੀ।"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"ਕੰਮ ਮੋਡ ਚਾਲੂ ਹੈ।"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ਕੰਮ ਮੋਡ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"ਕੰਮ ਮੋਡ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ਡੈਟਾ ਸੇਵਰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ਡੈਟਾ ਸੇਵਰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ਡਿਸਪਲੇ ਚਮਕ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ਡਾਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ਡਾਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS ਵੱਲੋਂ ਸੈਟ ਕੀਤਾ ਨਿਰਧਾਰਿਤ ਸਥਾਨ"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾ ਬੇਨਤੀਆਂ ਸਕਿਰਿਆ"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਹਟਾਓ।"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ਸੂਚਨਾ ਸੈਟਿੰਗਾਂ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ਸੈਟਿੰਗਾਂ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ਸਕ੍ਰੀਨ ਆਟੋਮੈਟਿਕਲੀ ਰੋਟੇਟ ਕਰੇਗੀ।"</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਸੀਮਾ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ਕੰਮ ਮੋਡ"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"ਤੁਹਾਡੀਆਂ ਹਾਲੀਆ ਸਕ੍ਰੀਨਾਂ ਇੱਥੇ ਪ੍ਰਗਟ ਹੋਣਗੀਆਂ"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ਤੁਸੀਂ ਸਭ ਕੁਝ ਸਾਫ਼ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ਐਪਲੀਕੇਸ਼ਨ ਜਾਣਕਾਰੀ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ਸਕ੍ਰੀਨ ਪਿਨਿੰਗ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ਖੋਜੋ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਚਾਲੂ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਸੁਰੱਖਿਅਤ-ਮੋਡ ਵਿੱਚ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ।"</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ਇਤਿਹਾਸ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ਸਾਫ਼ ਕਰੋ"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ਸਭ ਸਾਫ਼ ਕਰੋ"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ਇਹ ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ਹੌਰੀਜ਼ੌਂਟਲ ਸਪਲਿਟ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ਵਰਟੀਕਲ ਸਪਲਿਟ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ਕਸਟਮ ਸਪਲਿਟ"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"ਕੁਲ \n ਚੁੱਪੀ"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ਕੇਵਲ\nਤਰਜੀਹੀ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ਕੇਵਲ\nਅਲਾਰਮ"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"ਸਭ"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ਸਾਰੀਆਂ\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ਚਾਰਜਿੰਗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰਾ ਹੋਣ ਤੱਕ)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਸਵਾਈਪ-ਅੱਪ ਐਕਸੇਲਰੇਟਰ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਸਵਾਈਪ-ਅੱਪ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ਰੂਪ-ਰੇਖਾ ਬਟਨ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਨ ਦੁਆਰਾ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਣ ਲਈ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
     <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ਚਾਲੂ ਕਰੋ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ਆਪਣੇ ਟੈਬਲੇਟ ਨਾਲ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ Bluetooth ਚਾਲੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ।"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ਚਾਲੂ ਕਰੋ"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ਸੂਚਨਾਵਾਂ \'ਤੇ ਲਾਗੂ ਕਰੋ"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ਇਸ ਐਪ ਦੀਆਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ \'ਤੇ ਲਾਗੂ ਕਰੋ"</string>
+    <string name="show_silently" msgid="6841966539811264192">"ਸੂਚਨਾਵਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+    <string name="block" msgid="2734508760962682611">"ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬਲੌਕ ਕਰੋ"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ਚੁੱਪ ਨਾ ਕਰਵਾਓ"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ਚੁੱਪ ਨਾ ਕਰਵਾਓ ਜਾਂ ਬਲੌਕ ਨਾ ਕਰੋ"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ਪੂਰੀ ਮਹੱਤਤਾ ਵਾਲੀਆਂ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵਿਖਾਓ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"ਬਲੌਕ ਕੀਤਾ"</string>
+    <string name="min_importance" msgid="1901894910809414782">"ਨਿਊਨਤਮ ਮਹੱਤਤਾ"</string>
     <string name="low_importance" msgid="4109929986107147930">"ਘੱਟ ਮਹੱਤਤਾ"</string>
     <string name="default_importance" msgid="8192107689995742653">"ਸਧਾਰਨ ਮਹੱਤਤਾ"</string>
     <string name="high_importance" msgid="1527066195614050263">"ਵੱਧ ਮਹੱਤਤਾ"</string>
     <string name="max_importance" msgid="5089005872719563894">"ਜ਼ਰੂਰੀ ਮਹੱਤਤਾ"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਕਦੇ ਨਾ ਵਿਖਾਓ"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"ਸਕਰੀਨ \'ਤੇ ਝਾਤੀ ਮਾਰੋ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਧੁਨੀ ਪੈਦਾ ਕਰਨ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"ਸਕ੍ਰੀਨ \'ਤੇ ਝਲਕ ਵਿਖਾਉਣ ਅਤੇ ਧੁਨੀ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ, ਸਕ੍ਰੀਨ \'ਤੇ ਝਲਕ ਵਿਖਾਉਣ ਅਤੇ ਧੁਨੀ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"ਸਧਾਰਨ ਰੰਗ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"ਰਾਤ ਦੇ ਰੰਗ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"ਕਸਟਮ ਰੰਗ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"ਸਵੈ"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"ਅਗਿਆਤ ਰੰਗ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"ਰੰਗ ਸੋਧ"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਟਾਇਲ ਵਿਖਾਓ"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"ਕਸਟਮ ਤਬਦੀਲੀ ਯੋਗ ਬਣਾਓ"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਸੂਚਨਾ ਕੰਟਰੋਲ"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"ਰੰਗ ਅਤੇ ਵਿਖਾਲਾ"</string>
+    <string name="night_mode" msgid="3540405868248625488">"ਰਾਤ ਮੋਡ"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ਡਿਸਪਲੇ ਨੂੰ ਕੈਲੀਬ੍ਰੇਟ ਕਰੋ"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ਚਾਲੂ"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ਬੰਦ"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"ਸਵੈਚਾਲਿਤ ਤੌਰ \'ਤੇ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ਟਿਕਾਣੇ ਅਤੇ ਦਿਨ ਦੇ ਸਮੇਂ ਲਈ ਢੁਕਵੇਂ ਰਾਤ ਮੋਡ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"ਜਦੋਂ ਰਾਤ ਮੋਡ ਚਾਲੂ ਹੋਵੇ"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS ਲਈ ਗੂੜ੍ਹੇ ਥੀਮ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ਟਿੰਟ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ਚਮਕ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ Android OS ਦੇ ਉਹਨਾਂ ਮੁੱਖ ਖੇਤਰਾਂ \'ਤੇ ਲਾਗੂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਜੋ ਆਮ ਤੌਰ \'ਤੇ ਇੱਕ ਹਲਕੇ ਥੀਮ ਵਿੱਚ ਵਿਖਾਏ ਜਾਂਦੇ ਹਨ, ਜਿਵੇਂ ਕਿ ਸੈਟਿੰਗਾਂ।"</string>
     <string name="color_apply" msgid="9212602012641034283">"ਲਾਗੂ ਕਰੋ"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"ਕੁਝ ਰੰਗ ਸੈਟਿੰਗਾਂ ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬੇਕਾਰ ਕਰ ਸਕਦੀਆਂ ਹਨ। ਇਹਨਾਂ ਰੰਗ ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਠੀਕ \'ਤੇ ਕਲਿੱਕ ਕਰੋ, ਨਹੀਂ ਤਾਂ ਇਹ ਸੈਟਿੰਗਾਂ 10 ਸਕਿੰਟ ਬਾਅਦ ਮੁੜ-ਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ।"</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ਬੈਟਰੀ ਸੇਵਰ"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ਕਾਰਗੁਜ਼ਾਰੀ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਡੈਟੇ ਨੂੰ ਘਟਾਉਂਦਾ ਹੈ"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"ਬਟਨ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ਸਿਸਟਮ"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ਹਾਲੀਆ"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ਪਿੱਛੇ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"ਵੌਲਯੂਮ ਵਿੱਚ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਵਿਖਾਓ"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ਵੌਲਯੂਮ ਡਾਇਲੌਗ ਵਿੱਚ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਦੇ ਪੂਰੇ ਨਿਯੰਤ੍ਰਣ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ।"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ਵੌਲਯੂਮ ਅਤੇ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ਵੌਲਯੂਮ ਘੱਟ ਹੋਣ \'ਤੇ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ਸੂਚਨਾਵਾਂ"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ਵਾਪਸ ਇਨਪੁੱਟ ਵਿਧੀ \'ਤੇ ਬਦਲੋ"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ਐਪਲੀਕੇਸ਼ਨਾਂ"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ਸਹਾਇਕ"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ਬ੍ਰਾਊਜ਼ਰ"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ਸੰਪਰਕ"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ਈਮੇਲ"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ਸੰਗੀਤ"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ਕੈਲੰਡਰ"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"ਵੌਲਯੂਮ ਕੰਟਰੋਲਾਂ ਨਾਲ ਵਿਖਾਓ"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ਵੌਲਯੂਮ ਬਟਨ ਸ਼ਾਰਟਕੱਟ"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ਵੌਲਯੂਮ ਉੱਚੀ ਹੋਣ \'ਤੇ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
     <string name="battery" msgid="7498329822413202973">"ਬੈਟਰੀ"</string>
     <string name="clock" msgid="7416090374234785905">"ਘੜੀ"</string>
     <string name="headset" msgid="4534219457597457353">"ਹੈੱਡਸੈੱਟ"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ਹੈੱਡਫੋਨਾਂ ਨੂੰ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ਹੈੱਡਸੈੱਟ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ਚਿੰਨ੍ਹਾਂ ਦੇ ਸਥਿਤੀ ਪੱਟੀ ਵਿੱਚ ਵਿਖਾਏ ਜਾਣ ਨੂੰ ਯੋਗ ਜਾਂ ਅਯੋਗ ਬਣਾਓ।"</string>
     <string name="data_saver" msgid="5037565123367048522">"ਡੈਟਾ ਸੇਵਰ"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ਡੈਟਾ ਸੇਵਰ ਚਾਲੂ ਹੈ"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ਡੈਟਾ ਸੇਵਰ ਬੰਦ ਹੈ"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ਚਾਲੂ"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ਬੰਦ"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ਆਵਾਗੌਣ ਪੱਟੀ"</string>
     <string name="start" msgid="6873794757232879664">"ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="center" msgid="4327473927066010960">"ਕੇਂਦਰ"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"ਕੀ-ਬੋਰਡ ਬਟਨ ਚੁਣੋ"</string>
     <string name="preview" msgid="9077832302472282938">"ਝਲਕ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ਟਾਇਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਘਸੀਟੋ"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ਸੰਪਾਦਨ ਕਰੋ"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"ਸਮਾਂ"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"ਘੰਟੇ, ਮਿੰਟ, ਅਤੇ ਸਕਿੰਟ ਵਿਖਾਓ"</item>
+    <item msgid="1427801730816895300">"ਘੰਟੇ ਅਤੇ ਮਿੰਟ ਵਿਖਾਓ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+    <item msgid="3830170141562534721">"ਇਸ ਚਿੰਨ੍ਹ ਨੂੰ ਨਾ ਵਿਖਾਓ"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"ਹਮੇਸ਼ਾਂ ਪ੍ਰਤੀਸ਼ਤਤਾ ਵਿਖਾਓ"</item>
+    <item msgid="2139628951880142927">"ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਪ੍ਰਤੀਸ਼ਤਤਾ ਵਿਖਾਓ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+    <item msgid="3327323682209964956">"ਇਸ ਚਿੰਨ੍ਹ ਨੂੰ ਨਾ ਵਿਖਾਓ"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"ਹੋਰ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਡਿਵਾਈਡਰ"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ਹੇਠਾਂ ਲੈ ਜਾਓ"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ਉੱਪਰ ਲੈ ਜਾਓ"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ਖੱਬੇ ਲੈ ਜਾਓ"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ਸੱਜੇ ਲੈ ਜਾਓ"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ਸਥਿਤੀ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। ਸੰਪਾਦਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ਸਥਿਤੀ <xliff:g id="POSITION">%1$d</xliff:g>। ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ ਤਬਦੀਲ ਕਰੋ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਹਟਾਓ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ <xliff:g id="POSITION">%2$d</xliff:g> ਸਥਿਤੀ \'ਤੇ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ ਹਟਾਇਆ ਗਿਆ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ <xliff:g id="POSITION">%2$d</xliff:g> ਸਥਿਤੀ \'ਤੇ ਤਬਦੀਲ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਸੰਪਾਦਕ।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings_tv.xml b/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
new file mode 100644
index 0000000..7cbda258
--- /dev/null
+++ b/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP ਬੰਦ ਕਰੋ"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
+    <string name="pip_play" msgid="674145557658227044">"ਚਲਾਓ"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"ਰੋਕੋ"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP ਕੰਟਰੋਲ ਕਰਨ ਲਈ "<b>"ਹੋਮ"</b>" ਦਬਾਈ ਰੱਖੋ"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਹੋਮ ਬਟਨ ਨੂੰ ਦੱਬੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"ਸਮਝ ਲਿਆ"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"ਖ਼ਾਰਜ ਕਰੋ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 2eae56a..297b849 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -75,7 +75,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Wykonano zrzut ekranu."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dotknij, aby wyświetlić zrzut ekranu."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nie udało się wykonać zrzutu ekranu."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Nie można wykonać zrzutu ekranu, bo brak miejsca albo nie zezwala na to aplikacja lub Twoja organizacja."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Podczas zapisywania zrzutu ekranu wystąpił błąd."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nie można zapisać zrzutu ekranu, bo brakuje miejsca w pamięci."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Nie możesz wykonać zrzutu ekranu, bo nie zezwala na to aplikacja lub Twoja organizacja."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB – opcje przesyłania plików"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Podłącz jako odtwarzacz multimedialny (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Podłącz jako aparat (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Usuń stąd <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>: zamknięto."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Wszystkie ostatnie aplikacje zostały zamknięte."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Uruchamiam <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Zamknięto powiadomienie."</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Więcej czasu."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mniej czasu."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Latarka wyłączona."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Latarka niedostępna."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Latarka włączona."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Latarka została wyłączona."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Latarka została włączona."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Tryb pracy włączony."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Tryb pracy wyłączony."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Tryb pracy włączony."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Oszczędzanie danych jest wyłączone."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Oszczędzanie danych jest włączone."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jasność wyświetlacza"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Transmisja danych 2G-3G została wstrzymana"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Prośby o lokalizację są aktywne"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ustawienia powiadomień"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Ustawienia aplikacji <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran zostanie obrócony automatycznie."</string>
@@ -276,7 +284,7 @@
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Przesyłanie"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Przesyłam"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Urządzenie bez nazwy"</string>
-    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Wszystko gotowe do przesyłania"</string>
+    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gotowy do działania"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Brak dostępnych urządzeń"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
@@ -298,15 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limit <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Tryb pracy"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Tutaj pojawią się ostatnie ekrany"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Brak ostatnich elementów"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Wszystko zostało wyczyszczone"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"przypinanie ekranu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Wyczyść"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacja <xliff:g id="APP">%s</xliff:g> została wyłączona w trybie bezpiecznym."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Wyczyść wszystko"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacja nie obsługuje trybu wielu okien"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacja nie obsługuje trybu wielu okien"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podziel poziomo"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podziel pionowo"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podziel niestandardowo"</string>
@@ -336,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Całkowita\ncisza"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tylko\npriorytetowe"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tylko\nalarmy"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Wszystkie"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Wszystkie\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Szybkie ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wolne ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
@@ -450,61 +457,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Włącz przyspieszenie dzielenia ekranu przesunięciem w górę"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Włącz dzielenie ekranu gestem przesunięcia w górę"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Włącz dzielenie ekranu po wykonaniu gestu przesunięcia palcem w górę od przycisku Przegląd"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Włącz"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Zastosuj do powiadomień typu <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Zastosuj do wszystkich powiadomień z tej aplikacji"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Pokazuj powiadomienia bez sygnału dźwiękowego"</string>
+    <string name="block" msgid="2734508760962682611">"Blokuj wszystkie powiadomienia"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nie ignoruj"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nie ignoruj ani nie blokuj"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Pokaż pełne ustawienia ważności"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Zablokowane"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Najmniejsza ważność"</string>
     <string name="low_importance" msgid="4109929986107147930">"Mało ważne"</string>
     <string name="default_importance" msgid="8192107689995742653">"Ważne"</string>
     <string name="high_importance" msgid="1527066195614050263">"Bardzo ważne"</string>
     <string name="max_importance" msgid="5089005872719563894">"Pilne"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nigdy nie pokazuj tych powiadomień"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Pokazuj na dole listy powiadomień bez sygnału dźwiękowego"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Pokazuj na górze listy powiadomień i sygnalizuj dźwiękiem"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Wyświetlaj na ekranie i odtwarzaj dźwięk"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Pokazuj na końcu listy powiadomień bez sygnału dźwiękowego"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Zezwól na sygnalizowanie tych powiadomień dźwiękiem"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Wyświetlaj na ekranie i sygnalizuj dźwiękiem"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Pokazuj na początku listy powiadomień, wyświetlaj na ekranie i sygnalizuj dźwiękiem"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Kolory standardowe"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Kolory nocne"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Kolory niestandardowe"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatycznie"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Nieznane kolory"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Zmiana koloru"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Pokazuj kafelek szybkich ustawień"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Włącz przekształcenie niestandardowe"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> – ustawienia powiadomień"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Kolor i wygląd"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Tryb nocny"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibracja wyświetlacza"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Wł."</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Wył."</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Włącz automatycznie"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Przełączaj na tryb nocny odpowiednio do lokalizacji i pory dnia"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Gdy jest włączony tryb nocny"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Użyj motywu ciemnego dla Androida"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Dostosuj odcień"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Dostosuj jasność"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Motyw ciemny zostanie zastosowany do głównych obszarów Androida, które normalnie są jasne, takich jak Ustawienia."</string>
     <string name="color_apply" msgid="9212602012641034283">"Zastosuj"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Potwierdź ustawienia"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Niektóre ustawienia kolorów mogą utrudniać korzystanie z urządzenia. Kliknij OK, by potwierdzić te ustawienia kolorów. Jeśli tego nie zrobisz, zostaną one zresetowane po 10 sekundach."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Wykorzystanie baterii"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Oszczędzanie baterii nie jest dostępne podczas ładowania"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Oszczędzanie baterii"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Zmniejsza wydajność i ogranicza dane w tle"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Przycisk <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Wstecz"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"W górę"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"W dół"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"W lewo"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"W prawo"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Do środka"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Spacja"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Odtwórz/wstrzymaj"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zatrzymaj"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Następny"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Poprzedni"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Przewiń do tyłu"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Przewiń do przodu"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Klawiatura numeryczna <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekran główny"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Ostatnie"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Wstecz"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Pokaż panel Nie przeszkadzać w oknie sterowania głośnością"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Pokaż cały panel Nie przeszkadzać w oknie sterowania głośnością."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Głośność i tryb Nie przeszkadzać"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Włącz tryb Nie przeszkadzać przy zmniejszaniu głośności"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Powiadomienia"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Skróty klawiszowe"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Przełącz metodę wprowadzania"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacje"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoc"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Przeglądarka"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Komunikator"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzyka"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendarz"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Pokazuj z regulacją głośności"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nie przeszkadzać"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Wł./wył. przyciskami głośności"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Wyłącz tryb Nie przeszkadzać przy zwiększaniu głośności"</string>
     <string name="battery" msgid="7498329822413202973">"Bateria"</string>
     <string name="clock" msgid="7416090374234785905">"Zegar"</string>
     <string name="headset" msgid="4534219457597457353">"Zestaw słuchawkowy"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Słuchawki są podłączone"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Zestaw słuchawkowy jest podłączony"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Włącz lub wyłącz wyświetlanie ikon na pasku stanu."</string>
     <string name="data_saver" msgid="5037565123367048522">"Oszczędzanie danych"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Oszczędzanie danych jest włączone"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Oszczędzanie danych jest wyłączone"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Wł."</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Wył."</string>
     <string name="nav_bar" msgid="1993221402773877607">"Pasek nawigacji"</string>
     <string name="start" msgid="6873794757232879664">"Na początku"</string>
     <string name="center" msgid="4327473927066010960">"Na środku"</string>
@@ -526,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Wybierz przycisk klawiatury"</string>
     <string name="preview" msgid="9077832302472282938">"Podgląd"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Przeciągnij, aby dodać kafelki"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Przeciągnij tutaj, by usunąć"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Edytuj"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Godzina"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Pokazuj godziny, minuty i sekundy"</item>
+    <item msgid="1427801730816895300">"Pokazuj godziny i minuty (domyślnie)"</item>
+    <item msgid="3830170141562534721">"Nie pokazuj tej ikony"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Zawsze pokazuj procent"</item>
+    <item msgid="2139628951880142927">"Pokazuj procent podczas ładowania (domyślnie)"</item>
+    <item msgid="3327323682209964956">"Nie pokazuj tej ikony"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Inne"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Linia dzielenia ekranu"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Przesuń w dół"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Przesuń w górę"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Przesuń w lewo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Przesuń w prawo"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacja może nie działać w trybie wielu okien"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Położenie <xliff:g id="POSITION">%1$d</xliff:g>, kafelek <xliff:g id="TILE_NAME">%2$s</xliff:g>. Kliknij dwukrotnie, by edytować."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>. Kliknij dwukrotnie, by dodać."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Położenie <xliff:g id="POSITION">%1$d</xliff:g>. Kliknij dwukrotnie, by wybrać."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Przenieś kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Usuń kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> został dodany w położeniu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> został usunięty"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> przeniesiony w położenie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Edytor szybkich ustawień."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
new file mode 100644
index 0000000..70be3d9
--- /dev/null
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Zamknij PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Pełny ekran"</string>
+    <string name="pip_play" msgid="674145557658227044">"Odtwórz"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Wstrzymaj"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Przytrzymaj "<b>"EKRAN GŁÓWNY"</b>", by sterować PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Przytrzymaj przycisk EKRAN GŁÓWNY, by sterować PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Zamknij"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 5219454..eb08d99 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de tela obtida."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para visualizar a captura de tela."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter a captura de tela."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Não é possível capturar a tela porque não há espaço suficiente ou o app ou organização não permite."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problema encontrado ao salvar captura de tela."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Não é possível salvar a captura de tela, porque não há espaço suficiente."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Capturas de tela não são permitidas pelo app ou por sua organização."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opções transf. arq. por USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Conectar como media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como uma câmera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabalho ativado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabalho desativado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabalho ativado."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Economia de dados desativada."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Economia de dados ativada."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho da tela"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os dados 2G e 3G foram pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configurações de notificação"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configurações de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Suas telas recentes aparecem aqui"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"O app <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Limpar tudo"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"O app não é compatível com o modo de várias janelas"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silêncio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ativar acelerador para dividir a tela ao deslizar para cima"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações deste app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar ou bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar todas as configurações de importância"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importância mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar essas notificações de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que essas notificações emitam sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar parcialmente na tela e permitir som"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automáticas"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar bloco de configurações rápidas"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrar tela"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Ativado"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Desativado"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Ativar automaticamente"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Alternar para o modo noturno conforme apropriado para o local e hora do dia"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Quando o modo noturno está ativado"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como as configurações."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Uso da bateria"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Voltar"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Para cima"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Para baixo"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Para a esquerda"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Para a direita"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centralizar"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Barra de espaço"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproduzir/pausar"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Parar"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Avançar"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retroceder"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avançar rapidamente"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar \"Não perturbe\" nas opções de volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir controle total do recurso \"Não perturbe\" na caixa de diálogo de volume."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e \"Não perturbe\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Entre no modo \"Não perturbe\" abaixando o volume"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos do teclado"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alterar o método de entrada"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicativos"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistente"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatos"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mensagens instantâneas"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Saia do modo \"Não perturbe\" aumentando o volume"</string>
     <string name="battery" msgid="7498329822413202973">"Bateria"</string>
     <string name="clock" msgid="7416090374234785905">"Relógio"</string>
     <string name="headset" msgid="4534219457597457353">"Fone de ouvido"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fones de ouvido conectados"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Fone de ouvido conectado"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ativar ou desativar a exibição de ícones na barra de status."</string>
     <string name="data_saver" msgid="5037565123367048522">"Economia de dados"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economia de dados ativada"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"A Economia de dados está desativada"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Ativado"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desativado"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegação"</string>
     <string name="start" msgid="6873794757232879664">"Iniciar"</string>
     <string name="center" msgid="4327473927066010960">"Centralizar"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Escolha um botão do teclado"</string>
     <string name="preview" msgid="9077832302472282938">"Visualização"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar blocos"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arraste aqui para remover"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Horas"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+    <item msgid="1427801730816895300">"Mostrar horas e minutos (padrão)"</item>
+    <item msgid="3830170141562534721">"Não mostrar este ícone"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Sempre mostrar porcentagem"</item>
+    <item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
+    <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Outros"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"É possível que o app não funcione com várias janelas"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é removido"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configurações rápidas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
new file mode 100644
index 0000000..0827f9c7
--- /dev/null
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Fechar PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Tela cheia"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reproduzir"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausar"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Mantenha "<b>"INÍCIO"</b>" pressionado para controlar o PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Mantenha a tecla \"HOME\" pressionada para controlar o PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Entendi"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Dispensar"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 064e565..bba2f3e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de ecrã efetuada"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para ver a captura de ecrã"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter captura de ecrã."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Imp. tirar capt. ecrã devido ao espaço de armaz. limit. ou isso não é permitido pela aplic. da sua ent."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problema encontrado ao guardar a captura de ecrã."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Não é possível guardar a captura de ecrã devido a espaço de armazenamento limitado."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"A aplicação ou a sua entidade não tem autorização para tirar capturas de ecrã."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opções de transm. de fich. USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Montar como leitor de multimédia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como câmara (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ignorado."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todas as aplicações recentes foram ignoradas."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação ignorada."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desligada."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ligada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna desligada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna ligada."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabalho ativado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"O modo de trabalho foi desativado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"O modo de trabalho foi ativado."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Poupança de dados desativada."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Poupança de dados ativada."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho do visor"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dados 2G-3G em pausa"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Pedidos de localização ativos"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Definições de notificação"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Definições do <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Os ecrãs recentes aparecem aqui"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Limpou tudo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação no ecrã"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar o <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"O <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Limpar tudo"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicação não é compatível com várias janelas"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"A aplicação não é compatível com várias janelas"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silêncio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Apenas\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Apenas\nalarmes"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"A carregar rapid. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"A carregar lentam. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ativar acelerador de deslize ráp. para cima do ecrã dividido"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto de deslize rápido para cima do ecrã dividido"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativar o gesto para aceder ao ecrã dividido ao deslizar rapidamente para cima a partir do botão Vista geral"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações desta aplicação"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações sem som"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar nem bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar definições de importância completas"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importância mín."</string>
     <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importância alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar estas notificações"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações sem som"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificações sem som"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar no ecrã e emitir som"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações sem som"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificações sem som"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificações emitam sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar no ecrã e permitir som"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar no ecrã e permitir som"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automáticas"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar o mosaico de Definições rápidas"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlos de notificações do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspeto"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrar ecrã"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Ativado"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Desativado"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Ligar automaticamente"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Alternar para o Modo noturno consoante a localização e a hora do dia"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Quando o Modo noturno está ativado"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Utilizar o tema escuro para o SO Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas essenciais do SO Android que são normalmente apresentadas num tema claro, como as Definições."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar as definições"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algumas definições de cor podem tornar este dispositivo instável. Clique em OK para confirmar estas definições de cor. Caso contrário, estas definições serão repostas após 10 segundos."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Poupança de bateria não disponível durante o carregamento"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Poupança de bateria"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados de segundo plano"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Início"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Anterior"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Para cima"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Para baixo"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Para a esquerda"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Para a direita"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Ao centro"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulação"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Espaço"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retrocesso"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproduzir/interromper"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Parar"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seguinte"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Recuar"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avançar"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Página para cima"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Página para baixo"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Eliminar"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Início"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fim"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Inserir"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Página inicial"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Anterior"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar Não incomodar no volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir o controlo total de Não incomodar na caixa de diálogo do volume."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e Não incomodar"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Ativar Não incomodar ao diminuir o volume"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos de teclado"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alternar o método de introdução"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicações"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistência"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendário"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controlos de volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não incomodar"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho dos botões de volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Desativar Não incomodar ao aumentar o volume"</string>
     <string name="battery" msgid="7498329822413202973">"Bateria"</string>
     <string name="clock" msgid="7416090374234785905">"Relógio"</string>
     <string name="headset" msgid="4534219457597457353">"Ausc. com microfone integrado"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auscultadores ligados"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auscultadores com microfone integrado ligados"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ativar ou desativar a apresentação de ícones na barra de estado."</string>
     <string name="data_saver" msgid="5037565123367048522">"Poupança de dados"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Poupança de dados ativada"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Poupança de dados desativada"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Ativado"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desativado"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegação"</string>
     <string name="start" msgid="6873794757232879664">"Início"</string>
     <string name="center" msgid="4327473927066010960">"Centro"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Selecionar o botão do teclado"</string>
     <string name="preview" msgid="9077832302472282938">"Pré-visualizar"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar mosaicos"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastar para aqui para remover"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+    <item msgid="1427801730816895300">"Mostrar horas e minutos (predefinição)"</item>
+    <item msgid="3830170141562534721">"Não mostrar este ícone"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Mostrar sempre a percentagem"</item>
+    <item msgid="2139628951880142927">"Mostrar a percentagem durante o carregamento (predefinição)"</item>
+    <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Outro"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Divisor do ecrã dividido"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"A aplicação pode não funcionar com multijanelas"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> removido"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de definições rápidas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
new file mode 100644
index 0000000..2f465d2
--- /dev/null
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Fechar PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Ecrã inteiro"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reproduzir"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Interromper"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Prima sem soltar o botão "<b>"HOME"</b>" para controlar o PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Prima sem soltar o botão HOME para controlar o PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Compreendi"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorar"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5219454..eb08d99 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de tela obtida."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para visualizar a captura de tela."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter a captura de tela."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Não é possível capturar a tela porque não há espaço suficiente ou o app ou organização não permite."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problema encontrado ao salvar captura de tela."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Não é possível salvar a captura de tela, porque não há espaço suficiente."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Capturas de tela não são permitidas pelo app ou por sua organização."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opções transf. arq. por USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Conectar como media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como uma câmera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabalho ativado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabalho desativado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabalho ativado."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Economia de dados desativada."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Economia de dados ativada."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho da tela"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os dados 2G e 3G foram pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configurações de notificação"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configurações de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Suas telas recentes aparecem aqui"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"O app <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Limpar tudo"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"O app não é compatível com o modo de várias janelas"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silêncio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ativar acelerador para dividir a tela ao deslizar para cima"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações deste app"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar ou bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar todas as configurações de importância"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importância mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar essas notificações de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que essas notificações emitam sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar parcialmente na tela e permitir som"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automáticas"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar bloco de configurações rápidas"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrar tela"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Ativado"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Desativado"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Ativar automaticamente"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Alternar para o modo noturno conforme apropriado para o local e hora do dia"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Quando o modo noturno está ativado"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como as configurações."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Uso da bateria"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Voltar"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Para cima"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Para baixo"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Para a esquerda"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Para a direita"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centralizar"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Barra de espaço"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproduzir/pausar"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Parar"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Avançar"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retroceder"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avançar rapidamente"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar \"Não perturbe\" nas opções de volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir controle total do recurso \"Não perturbe\" na caixa de diálogo de volume."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e \"Não perturbe\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Entre no modo \"Não perturbe\" abaixando o volume"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos do teclado"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alterar o método de entrada"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicativos"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistente"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatos"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mensagens instantâneas"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Saia do modo \"Não perturbe\" aumentando o volume"</string>
     <string name="battery" msgid="7498329822413202973">"Bateria"</string>
     <string name="clock" msgid="7416090374234785905">"Relógio"</string>
     <string name="headset" msgid="4534219457597457353">"Fone de ouvido"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fones de ouvido conectados"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Fone de ouvido conectado"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ativar ou desativar a exibição de ícones na barra de status."</string>
     <string name="data_saver" msgid="5037565123367048522">"Economia de dados"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economia de dados ativada"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"A Economia de dados está desativada"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Ativado"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desativado"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegação"</string>
     <string name="start" msgid="6873794757232879664">"Iniciar"</string>
     <string name="center" msgid="4327473927066010960">"Centralizar"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Escolha um botão do teclado"</string>
     <string name="preview" msgid="9077832302472282938">"Visualização"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar blocos"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arraste aqui para remover"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Horas"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+    <item msgid="1427801730816895300">"Mostrar horas e minutos (padrão)"</item>
+    <item msgid="3830170141562534721">"Não mostrar este ícone"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Sempre mostrar porcentagem"</item>
+    <item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
+    <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Outros"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"É possível que o app não funcione com várias janelas"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é removido"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configurações rápidas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings_tv.xml b/packages/SystemUI/res/values-pt/strings_tv.xml
new file mode 100644
index 0000000..0827f9c7
--- /dev/null
+++ b/packages/SystemUI/res/values-pt/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Fechar PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Tela cheia"</string>
+    <string name="pip_play" msgid="674145557658227044">"Reproduzir"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausar"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Mantenha "<b>"INÍCIO"</b>" pressionado para controlar o PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Mantenha a tecla \"HOME\" pressionada para controlar o PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Entendi"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Dispensar"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 1af5b42..81d0456 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -21,10 +21,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"UI sistem"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ștergeți"</string>
-    <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminaţi din listă"</string>
+    <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminați din listă"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informații despre aplicație"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ecranele dvs. recente apar aici"</string>
-    <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Renunţaţi la aplicațiile recente"</string>
+    <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Renunțați la aplicațiile recente"</string>
     <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
       <item quantity="few">%d ecrane în Recente</item>
       <item quantity="other">%d de ecrane în Recente</item>
@@ -36,7 +36,7 @@
     <string name="battery_low_title" msgid="6456385927409742437">"Bateria este aproape descărcată"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>. Economisirea bateriei este activată."</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizaţi numai încărcătorul furnizat."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizați numai încărcătorul furnizat."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Încărcarea prin USB nu este acceptată."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizați numai încărcătorul furnizat."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Setări"</string>
@@ -50,16 +50,16 @@
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificări"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
-    <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Setaţi metode introducere text"</string>
+    <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Setați metode introducere text"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastatură fizică"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze dispozitivul USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze accesoriul USB?"</string>
-    <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
-    <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui accesoriu USB?"</string>
-    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aplic. instal. nu funcţ. cu acest acces. USB. Aflați despre acest accesoriu la <xliff:g id="URL">%1$s</xliff:g>"</string>
+    <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideți <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
+    <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Deschideți <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui accesoriu USB?"</string>
+    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aplic. instal. nu funcț. cu acest acces. USB. Aflați despre acest accesoriu la <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"Accesoriu USB"</string>
     <string name="label_view" msgid="6304565553218192990">"Afișați"</string>
-    <string name="always_use_device" msgid="1450287437017315906">"Utilizaţi în mod prestabilit pt. acest dispoz. USB"</string>
+    <string name="always_use_device" msgid="1450287437017315906">"Utilizați în mod prestabilit pt. acest dispoz. USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
     <string name="usb_debugging_title" msgid="4513918393387141949">"Permiteți depanarea USB?"</string>
     <string name="usb_debugging_message" msgid="2220143855912376496">"Amprenta digitală din cheia RSA a computerului este:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
@@ -74,10 +74,12 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captură de ecran realizată."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Atingeți pentru a vedea captura de ecran."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Captura de ecran nu a putut fi realizată."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Captură de ecran impos. de realizat: spațiu de stoc. limitat sau nu este permisă de apl. sau de organiz."</string>
-    <string name="usb_preference_title" msgid="6551050377388882787">"Opţiuni pentru transferul de fișiere prin USB"</string>
-    <string name="use_mtp_button_title" msgid="4333504413563023626">"Montaţi ca player media (MTP)"</string>
-    <string name="use_ptp_button_title" msgid="7517127540301625751">"Montaţi drept cameră foto (PTP)"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Problemă întâmpinată la salvarea capturii de ecran."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Captura de ecran nu poate fi salvată din cauza spațiului de stocare limitat."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Crearea capturilor de ecran nu este permisă de aplicație sau de organizația dvs."</string>
+    <string name="usb_preference_title" msgid="6551050377388882787">"Opțiuni pentru transferul de fișiere prin USB"</string>
+    <string name="use_mtp_button_title" msgid="4333504413563023626">"Montați ca player media (MTP)"</string>
+    <string name="use_ptp_button_title" msgid="7517127540301625751">"Montați drept cameră foto (PTP)"</string>
     <string name="installer_cd_button_title" msgid="2312667578562201583">"Instal. aplic. Transfer de fișiere Android pt. Mac"</string>
     <string name="accessibility_back" msgid="567011538994429120">"Înapoi"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Ecranul de pornire"</string>
@@ -97,7 +99,7 @@
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selectați noul aspect pentru activitate"</string>
     <string name="cancel" msgid="6442560571259935130">"Anulați"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
-    <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
+    <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceți zoom de la o imagine mai mică la una mai mare."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string>
     <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Deconectat de la Bluetooth."</string>
     <string name="accessibility_no_battery" msgid="358343022352820946">"Nu există baterie."</string>
@@ -157,7 +159,7 @@
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificări."</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ștergeți notificarea."</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS activat."</string>
-    <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Se obţine GPS."</string>
+    <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Se obține GPS."</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter activat."</string>
     <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Vibrare sonerie."</string>
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Sonerie silențioasă."</string>
@@ -167,6 +169,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Închideți <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> a fost eliminată."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toate aplicațiile recente au fost închise."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Se inițiază <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificarea a fost închisă."</string>
@@ -207,6 +211,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mai mult timp."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mai puțin timp."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna este dezactivată."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna nu este disponibilă."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna este activată."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna este dezactivată."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna este activată."</string>
@@ -219,6 +224,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modul de lucru este activat."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modul de lucru a fost dezactivat."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modul de lucru a fost activat."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Economizorul de date a fost dezactivat."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Economizorul de date a fost activat."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminozitatea ecranului"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Conexiunea de date 2G – 3G este întreruptă"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
@@ -232,6 +239,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Locație setată prin GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitări locație active"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Ștergeți toate notificările."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Setări pentru notificări"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Setări <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string>
@@ -297,15 +305,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limită de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertizare: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modul de lucru"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Ecranele dvs. recente apar aici"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Niciun element recent"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ați șters tot"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Istoric"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Ștergeți"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplicația <xliff:g id="APP">%s</xliff:g> este dezactivată în modul sigur."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ștergeți-le pe toate"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Această aplicație nu acceptă ferestre multiple"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplicația nu acceptă ferestre multiple"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divizare pe orizontală"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divizare pe verticală"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divizare personalizată"</string>
@@ -315,8 +324,8 @@
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nu se încarcă"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Căutați"</string>
-    <string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Glisaţi spre stânga pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_up" msgid="7169032478259485180">"Glisați în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"Glisați spre stânga pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="zen_priority_introduction" msgid="3070506961866919502">"Nu veți fi deranjat(ă) de sunete și vibrații, exceptând alarmele, mementourile, evenimentele și apelanții pe care îi menționați."</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"Personalizați"</string>
     <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Această opțiune blochează TOATE sunetele și vibrațiile, inclusiv cele ale alarmelor, muzicii, videoclipurilor și jocurilor. Totuși, veți putea iniția apeluri."</string>
@@ -335,8 +344,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Niciun\nsunet"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Numai\ncu prioritate"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Numai\nalarme"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Toate"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Toate\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Se încarcă rapid (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Se încarcă lent (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
@@ -449,61 +456,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activați acceleratorul pentru accesarea ecranului împărțit prin glisarea în sus"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activați gestul de accesare a ecranului împărțit prin glisare în sus"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activați gestul de accesare a ecranului împărțit prin glisarea în sus de la butonul Recente"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activați"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Aplicați notificărilor de tip <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Aplicați tuturor notificărilor de la această aplicație"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Notificările se afișează fără a se emite un sunet"</string>
+    <string name="block" msgid="2734508760962682611">"Blocați toate notificările"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nu dezactivați sunetul"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nu dezactivați sunetul și nu blocați"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afișați toate setările privind importanța"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blocate"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Importanță minimă"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importanță redusă"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importanță normală"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importanță ridicată"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importanță: urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Aceste notificări nu se afișează niciodată"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Aceste notificări se afișează fără a se emite un sunet"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Se afișează în partea de sus a listei cu notificări și se emite un sunet"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Se afișează pentru o scurtă durată pe ecran și se emite un sunet"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Aceste notificări se afișează fără a se emite un sunet"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permiteți acestor notificări să emită sunete"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Se afișează pentru o scurtă durată pe ecran și se permite un sunet"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Apar în partea de sus a listei cu notificări, se afișează pentru scurt timp pe ecran și se permite un sunet"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Culori normale"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Culori de noapte"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Culori personalizate"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automat"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Culori necunoscute"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modificarea culorilor"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afișați caseta cu Setările rapide"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Activați transformarea personalizată"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Opțiuni privind notificările pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Culoare și aspect"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modul Noapte"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Calibrați afișarea"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Activat"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Dezactivat"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Activați automat"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Comutați la modul Noapte în funcție de locație și de momentul zilei"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Când modul Noapte este activat"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Folosiți tema întunecată pentru SO Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Ajustați culoarea"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Ajustați luminozitatea"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema întunecată se aplică zonelor principale ale sistemului de operare Android care sunt de obicei afișate cu o temă deschisă la culoare, cum ar fi Setările."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicați"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmați setările"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Unele setări pentru culori pot face dispozitivul să nu mai funcționeze. Dați clic pe OK pentru a confirma aceste setări pentru culori. În caz contrar, acestea se vor reseta după 10 secunde."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Utilizarea bateriei"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Economisirea bateriei nu este disponibilă pe durata încărcării"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Economisirea bateriei"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce performanța și datele de fundal"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Butonul <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"La început"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Înapoi"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"În sus"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"În jos"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"La stânga"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"La dreapta"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"În centru"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Spațiu"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Redați/Întrerupeți"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Opriți"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Înainte"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Înapoi"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Derulați înapoi"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Derulați rapid înainte"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"O pagină mai sus"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"O pagină mai jos"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ștergeți"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"La început"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"La final"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Inserați"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tasta numerică <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ecran de pornire"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recente"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Înapoi"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Afișați opțiunile pentru Nu deranjați în dialogul de volum"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permiteți controlul complet al modului Nu deranjați din dialogul pentru volum."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumul și Nu deranjați"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Accesați Nu deranjați la reducerea volumului"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificări"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Comenzi rapide de la tastatură"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Comutați metoda de introducere a textului"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicații"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistent"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Agendă"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzică"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Afișează cu comenzile de volum"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nu deranja"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Comandă rapidă din butoanele de volum"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Ieșiți din Nu deranjați la creșterea volumului"</string>
     <string name="battery" msgid="7498329822413202973">"Baterie"</string>
     <string name="clock" msgid="7416090374234785905">"Ceas"</string>
     <string name="headset" msgid="4534219457597457353">"Set căști-microfon"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Căștile sunt conectate"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Setul căști-microfon este conectat"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activați sau dezactivați afișarea pictogramelor în bara de stare."</string>
     <string name="data_saver" msgid="5037565123367048522">"Economizor de date"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economizorul de date este activat"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Economizorul de date este dezactivat"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Activați"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Dezactivați"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Bară de navigare"</string>
     <string name="start" msgid="6873794757232879664">"La început"</string>
     <string name="center" msgid="4327473927066010960">"În centru"</string>
@@ -513,7 +566,7 @@
     <string name="select_button" msgid="1597989540662710653">"Selectați butonul de adăugat"</string>
     <string name="add_button" msgid="4134946063432258161">"Adăugați un buton"</string>
     <string name="save" msgid="2311877285724540644">"Salvați"</string>
-    <string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
+    <string name="reset" msgid="2448168080964209908">"Resetați"</string>
     <string name="no_home_title" msgid="1563808595146071549">"Nu s-a găsit niciun buton Ecran de pornire"</string>
     <string name="no_home_message" msgid="5408485011659260911">"Pentru a naviga pe acest dispozitiv este necesar un buton Ecran de pornire. Adăugați un buton Ecran de pornire înainte să salvați."</string>
     <string name="adjust_button_width" msgid="6138616087197632947">"Ajustați lățimea butonului"</string>
@@ -525,5 +578,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Selectați butonul de la tastatură"</string>
     <string name="preview" msgid="9077832302472282938">"Previzualizare"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Trageți pentru a adăuga sectoare"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Trageți aici pentru a elimina"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editați"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Oră"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Afișează orele, minutele și secundele"</item>
+    <item msgid="1427801730816895300">"Afișează orele și minutele (prestabilit)"</item>
+    <item msgid="3830170141562534721">"Nu afișa această pictogramă"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Afișează întotdeauna procentajul"</item>
+    <item msgid="2139628951880142927">"Afișează procentajul când se încarcă (prestabilit)"</item>
+    <item msgid="3327323682209964956">"Nu afișa această pictogramă"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Altele"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Separator pentru ecranul împărțit"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mutați în jos"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mutați în sus"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mutați spre stânga"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mutați spre dreapta"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Este posibil ca aplicația să nu funcționeze cu ferestre multiple"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Atingeți de două ori pentru a edita."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Atingeți de două ori pentru a adăuga."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>. Atingeți de două ori pentru a selecta."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mutați <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Eliminați <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> este adăugată pe poziția <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> este eliminată"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> a fost mutată pe poziția <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editorul pentru setări rapide."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
new file mode 100644
index 0000000..9ef90dd
--- /dev/null
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Închideți PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Ecran complet"</string>
+    <string name="pip_play" msgid="674145557658227044">"Redați"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Întrerupeți"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Apăsați lung "<b>"ACASĂ"</b>" pentru a controla PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Apăsați lung butonul ECRAN DE PORNIRE pentru a controla PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Am înțeles"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Închideți"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ba1373f..86f0ec4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -75,7 +75,9 @@
     <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="1260203058661337274">"Не удается сделать скриншот: не хватает памяти или нет разрешения от приложения или организации."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Не удалось сохранить скриншот."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Не удалось сохранить скриншот: недостаточно места."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Не удалось сделать скриншот: нет разрешения от приложения или организации."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Параметры передачи через USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Подключить как мультимедийный проигрыватель (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Установить как камеру (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Удаление приложения <xliff:g id="APP">%s</xliff:g> из списка."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" удалено из списка."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Все недавние приложения закрыты."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск приложения <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Уведомление закрыто"</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Увеличить время."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Уменьшить время."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фонарик отключен."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Фонарик недоступен."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фонарик включен."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фонарик отключен."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фонарик включен."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Рабочий режим включен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Рабочий режим отключен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Рабочий режим включен."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Режим экономии трафика отключен."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Режим экономии трафика включен."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркость экрана"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передача данных 2G и 3G приостановлена"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Координаты по GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Есть активные запросы на определение местоположения"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Удалить все уведомления"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Настройки уведомлений"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Настройки приложения \"<xliff:g id="APP_NAME">%s</xliff:g>\""</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран будет поворачиваться автоматически."</string>
@@ -298,15 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ограничение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рабочий режим"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Здесь будут показаны недавние приложения"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Недавних приложений нет"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы очистили всё"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Заблокировать в приложении"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не удалось запустить приложение \"<xliff:g id="APP">%s</xliff:g>\""</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Журнал"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Очистить"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" отключено в безопасном режиме."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Очистить все"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Приложение не поддерживает многооконный режим"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Приложение не поддерживает многооконный режим"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Разделить по вертикали"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Разделить по-другому"</string>
@@ -336,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Полная\nтишина"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Только\nважные"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Только\nбудильник"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Все"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Все\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Быстрая зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Медленная зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -450,61 +457,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Разделять экран пролистыванием вверх"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделять экран пролистыванием вверх"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Включить разделение экрана пролистыванием вверх с кнопки \"Обзор\""</string>
     <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включить"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Применить к уведомлениям на тему \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Применить ко всем уведомлениям этого приложения"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Показывать без звука"</string>
+    <string name="block" msgid="2734508760962682611">"Блокировать все уведомления"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Показывать со звуком"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не блокировать, показывать со звуком"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показывать все настройки важности"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блокировка"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Наименьшая важность"</string>
     <string name="low_importance" msgid="4109929986107147930">"Низкая важность"</string>
     <string name="default_importance" msgid="8192107689995742653">"Средняя важность"</string>
     <string name="high_importance" msgid="1527066195614050263">"Высокая важность"</string>
     <string name="max_importance" msgid="5089005872719563894">"Крайняя важность"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Не показывать эти уведомления."</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Показывать без звука в конце списка уведомлений."</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Показывать уведомления без звука."</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Показывать со звуком в начале списка уведомлений."</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Показывать со звуком поверх всех окон."</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Показывать без звука в конце списка уведомлений"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Показывать без звука"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Показывать со звуком"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Показывать со звуком поверх всех окон"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Показывать со звуком в начале списка уведомлений и поверх всех окон"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Обычные цвета"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Ночные цвета"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Собственные цвета"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Неизвестные цвета"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Цветовые настройки"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показывать панель быстрых настроек"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Включить собственные настройки"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Управление уведомлениями (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Цвета и стиль"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Ночной режим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Калибровка дисплея"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Включен"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Отключен"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Включать автоматически"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Включать ночной режим с учетом местоположения и времени суток"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"В ночном режиме"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Использовать темное оформление для Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Изменять оттенок"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Яркость"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Темное оформление применяется к основным элементам системы Android (таким, как приложение \"Настройки\"), которые обычно показываются в светлом."</string>
     <string name="color_apply" msgid="9212602012641034283">"Применить"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Подтвердите настройки"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Некоторые цветовые настройки могут затруднить работу с устройством. Чтобы применить выбранные параметры, нажмите \"ОК\". В противном случае они будут сброшены через 10 секунд."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Уровень заряда"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим энергосбережения нельзя включить во время зарядки"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим энергосбережения"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ограничивает производительность и фоновую передачу данных"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Главный экран"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Стрелка вверх"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Стрелка вниз"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Стрелка влево"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Стрелка вправо"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Центральная стрелка"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Пробел"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Ввод"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Воспроизведение/пауза"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Стоп"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Следующий трек"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Предыдущий трек"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перемотка назад"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перемотка вперед"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> на цифровой панели"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Система"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Главный экран"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавние"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Показать панель \"Не беспокоить\" в окне регулировки звука"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Позволяет управлять режимом \"Не беспокоить\" в окне регулировки громкости."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Регулировка громкости и режим \"Не беспокоить\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Включать режим \"Не беспокоить\" при уменьшении громкости"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Уведомления"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Быстрые клавиши"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Сменить способ ввода"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Приложения"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помощник"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузер"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакты"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Эл. почта"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Чат"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка."</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календарь"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Показывать при нажатии кнопок регулировки громкости"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не беспокоить"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки регулировки громкости"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Отключать режим \"Не беспокоить\" при увеличении громкости"</string>
     <string name="battery" msgid="7498329822413202973">"Батарея"</string>
     <string name="clock" msgid="7416090374234785905">"Часы"</string>
     <string name="headset" msgid="4534219457597457353">"Гарнитура"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Наушники подключены"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Гарнитура подключена"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Включение и отключение показа значков в строке состояния"</string>
     <string name="data_saver" msgid="5037565123367048522">"Экономия трафика"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Режим экономии трафика включен"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Режим экономии трафика отключен"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Включено"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Отключено"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Панель навигации"</string>
     <string name="start" msgid="6873794757232879664">"Вверху"</string>
     <string name="center" msgid="4327473927066010960">"В центре"</string>
@@ -526,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Выберите клавишу"</string>
     <string name="preview" msgid="9077832302472282938">"Просмотр"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Перетащите нужные элементы"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Чтобы удалить, перетащите сюда"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Изменить"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Время"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Часы, минуты и секунды"</item>
+    <item msgid="1427801730816895300">"Часы и минуты (по умолчанию)"</item>
+    <item msgid="3830170141562534721">"Не показывать этот значок"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Всегда показывать процент заряда"</item>
+    <item msgid="2139628951880142927">"Показывать процент во время зарядки (по умолчанию)"</item>
+    <item msgid="3327323682209964956">"Не показывать этот значок"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Другое"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Разделитель экрана"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Опустить"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Поднять"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Сдвинуть влево"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Сдвинуть вправо"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Приложение не поддерживает многооконный режим"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>, кнопка \"<xliff:g id="TILE_NAME">%2$s</xliff:g>\". Чтобы изменить, нажмите дважды."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\". Чтобы добавить, нажмите дважды."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>. Чтобы выбрать, нажмите дважды."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Переместить кнопку \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Удалить кнопку \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" теперь занимает позицию <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" удалена"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" теперь занимает позицию <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор быстрых настроек."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
new file mode 100644
index 0000000..027cb1f
--- /dev/null
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"\"Кадр в кадре\" – выйти"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Во весь экран"</string>
+    <string name="pip_play" msgid="674145557658227044">"Воспроизвести"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Приостановить"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Управляйте кадром в кадре, удерживая кнопку "<b>"ГЛАВНАЯ"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Управляйте режимом \"Кадр в кадре\", удерживая кнопку ГЛАВНАЯ"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"ОК"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Закрыть"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index b15137e..5a2f849 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"සීමිත ආචයනය ඉඩ හේතුවෙන් තිර රුව ලබාගත නොහැක, හෝ ඔබගේ යෙදුම හෝ ඔබගේ සංවිධානය විසින් එය ඉඩ නොදී තිබේ."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"තිර රුව සුරකින අතරතුර ගැටලුවක් ඇති විය."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"සීමිත ගබඩා ඉඩ නිසා තිර රුව සුරැකිය නොහැකිය."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"තිර රූ ගැනීමට යෙදුම හෝ ඔබගේ සංවිධානය ඉඩ නොදේ."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ගොනු හුවමාරු විකල්ප"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"මධ්‍ය ධාවකයක් (MTP) ලෙස සවි කරන්න"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"කැමරාවක් (PTP) ලෙස සවි කරන්න"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ඉවතලන්න."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> අස් කර ඇත."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"සියලුම මෑත යෙඳුම් අස් කරන ලදි."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කරමින්."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"දැනුම්දීම නිෂ්ප්‍රභා කරඇත."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"වේලාව වැඩියෙන්."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"වේලාව අඩුවෙන්."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"සැණෙළි ආලෝකය අක්‍රිය කරන ලදි."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"සැණෙළි ආලෝකය ලබා ගත නොහැකිය."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"සැණෙළි ආලෝකය සක්‍රිය කරන ලදි."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"සැණෙළි ආලෝකය අක්‍රිය කරන ලදි."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"සැණෙළි ආලෝකය සක්‍රිය කරන ලදි."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"වැඩ ප්‍රකාරය ක්‍රියාත්මකයි."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"වැඩ ප්‍රකාරය ක්‍රියාවිරහිත කරන ලදී."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"වැඩ ප්‍රකාරය ක්‍රියාත්මක කරන ලදී."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"දත්ත සුරැකුම ක්‍රියාවිරහිත කරන ලදී."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"දත්ත සුරැකුම ක්‍රියාත්මක කරන ලදී."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"දීප්තිය දර්ශනය කරන්න"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G දත්ත විරාම කර ඇත"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS මඟින් ස්ථානය සකසා ඇත"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"පිහිටීම් ඉල්ලීම් සක්‍රියයි"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"සියලු දැනුම්දීම් හිස් කරන්න."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"දැනුම්දීම් සැකසීම්"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> සැකසීම්"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"තිරය ස්වයංක්‍රීයව කරකැවේ."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> සීමිත"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> අවවාද කිරීම"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"වැඩ ප්‍රකාරය"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"මෙහි ඔබගේ මෑතක තිර පෙන්නුම් කරයි"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"මෑත අයිතම නැත"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ඔබ සියලු දේ හිස් කර ඇත"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"යෙදුම් තොරතුරු"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"තිර ඇමිණීම"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"සෙවීම"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කළ නොහැක."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ඉතිහාසය"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"හිස් කරන්න"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ආරක්ෂිත ප්‍රකාරය තුළ අබලයි."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"සියල්ල හිස් කරන්න"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"මෙම යෙදුම බහු-කවුළුව සඳහා සහාය නොදක්වයි"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"යෙදුම බහු-කවුළුව සඳහා සහාය නොදක්වයි"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"තිරස්ව වෙන් කරන්න"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"සිරස්ව වෙන් කරන්න"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"අභිමත ලෙස වෙන් කරන්න"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"සම්පූර්ණ\nනිහඬතාව"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්‍රමුඛතා\nපමණි"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"සියලු"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"සියලු\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ඉක්මනින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"සෙමින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"බෙදුම්-තිර ඉහළට-ස්වයිප් කිරීමේ ත්වරකය සබල කරන්න"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"බෙදුම්-තිරය ඉහළට-ස්වයිප් කිරීමේ අභිනය සබල කරන්න"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"දළ විශ්ලේෂණ බොත්තම හරහා ඉහළට ස්වයිප් කිරීමෙන් බෙදුම් තිරයට ඇතුළු වීමට ඉඟිය සබල කිරීම"</string>
     <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"බ්ලූටූත් ක්‍රියාත්මක කරන්නද?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ඔබේ යතුරු පුවරුව ඔබේ ටැබ්ලට් පරිගණකයට සම්බන්ධ කිරීමට, ඔබ පළමුව බ්ලූටූත් ක්‍රියාත්මක කළ යුතුය."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ක්‍රියාත්මක කරන්න"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> දැනුම්දීම් වෙත යොදන්න"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"මෙම යෙදුම වෙතින් වන සියලු දැනුම්දීම් සඳහා යොදන්න"</string>
+    <string name="show_silently" msgid="6841966539811264192">"නිශ්ශබ්දව දැනුම්දීම් පෙන්වන්න"</string>
+    <string name="block" msgid="2734508760962682611">"සියලු දැනුම්දීම් අවහිර කරන්න"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"නිශ්ශබ්ද නොකරන්න"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"නිශ්ශබ්ද හෝ අවහිර නොකරන්න"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"පූර්ණ වැදගත්කම් සැකසීම් පෙන්වන්න"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"අවහිර කරන ලදි"</string>
+    <string name="min_importance" msgid="1901894910809414782">"අවම වැදගත්කම"</string>
     <string name="low_importance" msgid="4109929986107147930">"අඩු වැදගත්කම"</string>
     <string name="default_importance" msgid="8192107689995742653">"සාමාන්‍ය වැදගත්කම"</string>
     <string name="high_importance" msgid="1527066195614050263">"වැඩි වැදගත්කම"</string>
     <string name="max_importance" msgid="5089005872719563894">"හදිසි වැදගත්කම"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"මෙම දැනුම්දීම් කිසිදා නොපෙන්වන්න"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න සහ ශබ්ද කරන්න"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"තිරයට පැමිණ ශබ්ද කරන්න"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"මෙම දැනුම්දීම්වලට ශබ්ද නැගීමට ඉඩ දෙන්න"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"තිරයට එබිකම් කර ශබ්දයට ඉඩ දෙන්න සහ ශබ්දයට ඉඩ දෙන්න"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න, තිරයට එබිකම් කර ශබ්දයට ඉඩ දෙන්න"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"තව සැකසීම්"</string>
     <string name="notification_done" msgid="5279426047273930175">"නිමයි"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"සාමාන්‍ය වර්ණ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"රාත්‍රී වර්ණ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"අභිරුචි වර්ණ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"ස්වයංක්‍රිය"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"නොදන්නා වර්ණ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"වර්ණ වෙනස් කිරීම"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"ඉක්මන් සැකසීම් ටයිලය පෙන්වන්න"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"අභිරුචි පරිවර්තනය සබල කරන්න"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> දැනුම්දීම් පාලන"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"වර්ණය සහ පෙනුම"</string>
+    <string name="night_mode" msgid="3540405868248625488">"රාත්‍රී ප්‍රකාරය"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"සංදර්ශකය ක්‍රමාංකනය කරන්න"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ක්‍රියාත්මකයි"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ක්‍රියාවිරහිතයි"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"ස්වයංක්‍රියව ක්‍රියාත්මක කරන්න"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"ස්ථානය සහ දවසේ වේලාවට ගැළපෙන ලෙස රාත්‍රී ප්‍රකාරයට මාරු වන්න"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"රාත්‍රී ප්‍රකාරය ක්‍රියාත්මක විට"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS සඳහා අඳුරු තේමාව භාවිත කරන්න"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"පැහැය සීරුමාරු කරන්න"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"දීප්තිය සීරුමාරු කරන්න"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"සැකසීම් වැනි, සාමාන්‍යයෙන් ලා පැහැ තේමාවක සංදර්ශනය වන Android OS හි මූලික ප්‍රදේශවලට අඳුරු තේමාව යෙදේ."</string>
     <string name="color_apply" msgid="9212602012641034283">"යොදන්න"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"සැකසීම් තහවුරු කරන්න"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"සමහර වර්ණ සැකසීම් මෙම උපාංගය භාවිත කළ නොහැකි තත්ත්වයට පත් කළ හැකිය. මෙම වර්ණ සැකසීම් තහවුරු කිරීමට හරි ක්ලික් කරන්න, නැතහොත් මෙම සැකසීම් තත්පර 10කට පසුව යළි සකසනු ඇත."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"බැටරි භාවිතය"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ආරෝපණය අතරතුර බැටරි සුරැකුම ලබා ගත නොහැකිය."</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"බැටරි සුරැකුම"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ක්‍රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> බොත්තම"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home යතුර"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"ආපසු"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"උඩු"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"යටි"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"වම්"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"දකුණු"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"මැද"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab යතුර"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"ඉඩ යතුර"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter යතුර"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace යතුර"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ධාවනය කරන්න/විරාම කරන්න"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"නතර කරන්න"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"ඊළඟ"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"පෙර"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"නැවත ඔතන්න"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"වේගයෙන් ඉදිරියට යන"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up යතුර"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down යතුර"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete යතුර"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home යතුර"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End යතුර"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert යතුර"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock යතුර"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> අංක පෑඩය"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"පද්ධතිය"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"මුල් පිටුව"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"මෑත"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ආපසු"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"හඩ පරිමාව තුළ බාධා නොකරන්න පුවරුව පෙන්වන්න"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"හඬ පරිමා සංවාදය තුළ බාධා නොකරන්න පුවරුවට පූර්ණ පාලනය ඉඩ දෙන්න."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"හඬ පරිමාව සහ බාධා නොකරන්න"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"හඬ පරිමාව අඩු කරන්න මත බාධා නොකරන්න වෙත ඇතුළු වන්න"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"දැනුම්දීම්"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"යතුරු පුවරු කෙටිමං"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ආදාන ක්‍රමය මාරු කිරීම"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"යෙදුම්"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"සහාය"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"බ්‍රවුසරය"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"සම්බන්ධතා"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ඊ-තැපෑල"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"සංගීතය"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"දින දර්ශනය"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"හඩ පරිමා පාලන සහිතව පෙන්වන්න"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"බාධා නොකරන්න"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"හඩ පරිමා බොත්තම් කෙටිමග"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"හඬ පරිමාව වැඩි කරන්න මත බාධා නොකරන්න වෙතින් ඉවත් වන්න"</string>
     <string name="battery" msgid="7498329822413202973">"බැටරිය"</string>
     <string name="clock" msgid="7416090374234785905">"ඔරලෝසුව"</string>
     <string name="headset" msgid="4534219457597457353">"හෙඩ්සෙට්"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"හෙඩ්ෆෝන් සම්බන්ධ කළ"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"හෙඩ්සෙට් සම්බන්ධ කළ"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"තත්ත්ව තීරුව මත අයිකන පෙන්වීම සබල හෝ අබල කරන්න."</string>
     <string name="data_saver" msgid="5037565123367048522">"දත්ත සුරැකුම"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"දත්ත සුරැකුම ක්‍රියාත්මකයි"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"දත්ත සුරැකුම ක්‍රියාවිරහිතයි"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ක්‍රියාත්මකයි"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ක්‍රියාවිරහිතයි"</string>
     <string name="nav_bar" msgid="1993221402773877607">"සංචලන තීරුව"</string>
     <string name="start" msgid="6873794757232879664">"ආරම්භ කරන්න"</string>
     <string name="center" msgid="4327473927066010960">"මධ්‍ය"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"යතුරු පුවරු බොත්තම තෝරන්න"</string>
     <string name="preview" msgid="9077832302472282938">"පෙරදසුන"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ටයිල් එක් කිරීමට අදින්න"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
     <string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය කරන්න"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"වේලාව"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"පැය, මිනිත්තු, සහ තත්පර පෙන්වන්න"</item>
+    <item msgid="1427801730816895300">"පැය සහ මිනිත්තු පෙන්වන්න (පෙරනිමි)"</item>
+    <item msgid="3830170141562534721">"මෙම නිරූපකය නොපෙන්වන්න"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"සෑම විටම ප්‍රතිශතය පෙන්වන්න"</item>
+    <item msgid="2139628951880142927">"ආරෝපණය වන විට ප්‍රතිශතය පෙන්වන්න (පෙරනිමි)"</item>
+    <item msgid="3327323682209964956">"මෙම නිරූපකය නොපෙන්වන්න"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"වෙනත්"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"බෙදුම්-තිර වෙන්කරණය"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"පහළට ගෙන යන්න"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ඉහළට ගෙන යන්න"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"වමට ගෙන යන්න"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"දකුණට ගෙන යන්න"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"යෙදුම බහු-කවුළුව සමඟ ක්‍රියා නොකළ හැකිය."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. වෙනස් කිරීමට දෙවරක් තට්ටු කරන්න."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. එක් කිරීමට දෙවරක් තට්ටු කරන්න."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>. තෝරා ගැනීමට දෙවරක් තට්ටු කරන්න."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ගෙන යන්න"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ඉවත් කරන්න"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> වන ස්ථානයට එක් කරන ලදි"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ඉවත් කරන ලදි"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> වන ස්ථානයට ගෙන යන ලදි"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ඉක්මන් සැකසුම් සංස්කාරකය."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings_tv.xml b/packages/SystemUI/res/values-si-rLK/strings_tv.xml
new file mode 100644
index 0000000..3380754
--- /dev/null
+++ b/packages/SystemUI/res/values-si-rLK/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP වසන්න"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"සම්පූර්ණ තිරය"</string>
+    <string name="pip_play" msgid="674145557658227044">"ධාවනය කරන්න"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"විරාමය"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP පාලනයට "<b>"HOME"</b>" අල්ලාගන්න"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP පාලනය කිරීමට HOME බොත්තම ඔබා අල්ලාගෙන සිටින්න"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"හරි, තේරුණා"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"අස් කරන්න"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 199bd90..9468fcf 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -75,7 +75,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímka obrazovky bola zaznamenaná."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímku obrazovky zobrazíte dotykom."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Snímku obrazovky sa nepodarilo zachytiť."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Nie je možné vytvoriť viac sním. obraz. pre obmedz. úlož. priestor alebo to nie je povolené apl. či vašou organiz."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Pri ukladaní snímky obrazovky sa vyskytol problém."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímku obrazovky nie je možné vytvoriť z dôvodu nedostatku miesta v úložisku."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosu súborov USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pripojiť ako prehrávač médií (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Pripojiť ako fotoaparát (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zrušiť aplikáciu <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikácia <xliff:g id="APP">%s</xliff:g> bola zrušená."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všetky nedávne aplikácie boli odmietnuté."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spúšťa sa aplikácia <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Upozornenie bolo zrušené."</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Dlhší čas"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší čas"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svietidlo je vypnuté."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svietidlo nie je k dispozícii."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svietidlo je zapnuté."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svietidlo je vypnuté."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svietidlo je zapnuté."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Pracovný režim – zap."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Pracovný režim je vypnutý."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Pracovný režim je zapnutý."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Šetrič dát bol vypnutý."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Šetrič dát bol zapnutý."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeja"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dátové prenosy 2G a 3G sú pozastavené"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Žiadosti o polohu sú aktívne"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazať všetky upozornenia."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Nastavenia upozornení"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Nastavenia aplikácie <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka sa automaticky otočí."</string>
@@ -298,15 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornenie pri <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovný režim"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Vaše nedávne obrazovky sa zobrazia tu."</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Žiadne nedávne položky"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vymazali ste všetko"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripnutie k obrazovke"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikáciu <xliff:g id="APP">%s</xliff:g> sa nepodarilo spustiť"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"História"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vymazať"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikácia <xliff:g id="APP">%s</xliff:g> je v núdzovom režime zakázaná."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vymazať všetko"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Táto aplikácia nepodporuje režim viacerých okien"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikácia nepodporuje režim viacerých okien"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Rozdeliť vodorovné"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Rozdeliť zvislé"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Rozdeliť vlastné"</string>
@@ -336,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Úplné\nticho"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Iba\nprioritné"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Iba\nbudíky"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Všetky"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Všetky\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nabíja sa rýchlo (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Nabíja sa pomaly (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -450,61 +457,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivovať rozdelenú obrazovku prejdením prstom"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovať rozdelenú obrazovku prejdením prstom"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovať rozdelenú obrazovku prejdením prstom nahor od tlačidla Prehľad"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnúť"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Použiť na upozornenia týkajúce sa témy <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Použiť na všetky upozornenia z tejto aplikácie"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Zobrazovať upozornenia bez zvukového signálu"</string>
+    <string name="block" msgid="2734508760962682611">"Blokovať všetky upozornenia"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nestíšiť"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nestíšiť ani neblokovať"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Zobraziť nastavenia vysokej dôležitosti"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Zablokované"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimálna dôležitosť"</string>
     <string name="low_importance" msgid="4109929986107147930">"Nízka dôležitosť"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normálna dôležitosť"</string>
     <string name="high_importance" msgid="1527066195614050263">"Vysoká dôležitosť"</string>
     <string name="max_importance" msgid="5089005872719563894">"Neodkladná dôležitosť"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Tieto upozornenia nikdy nezobrazovať"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Tieto upozornenia zobrazovať bez zvukového signálu"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Zobrazovať v hornej časti zoznamu upozornení so zvukovým signálom"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Zobrazovať cez obrazovku so zvukovým signálom"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tieto upozornenia zobrazovať bez zvukového signálu"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Umožniť týmto upozorneniam vydávať zvukové signály"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Zobrazovať cez obrazovku a povoliť zvukový signál"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Zobrazovať v hornej časti zoznamu upozornení, zobrazovať cez obrazovku a povoliť zvukový signál"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normálne farby"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nočné farby"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastné farby"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatické"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznáme farby"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Úprava farieb"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Zobraziť dlaždicu Rýchle nastavenia"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Povoliť vlastnú transformáciu"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Ovládacie prvky pre upozornenia z aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Farba a vzhľad"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nočný režim"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibrovať obrazovku"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Zapnutý"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Vypnutý"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Zapínať automaticky"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Prepnúť do Nočného režimu podľa miesta a času dňa"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Keď je zapnutý Nočný režim"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Použiť tmavý motív pre systém Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Upraviť tónovanie"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Upraviť jas"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavných oblastiach systému Android OS (ako sú Nastavenia), ktoré sú obyčajne zobrazené vo svetlom motíve, je použitý tmavý motív."</string>
     <string name="color_apply" msgid="9212602012641034283">"Použiť"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Potvrdenie nastavení"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Niektoré nastavenia farieb môžu toto zariadenie znefunkčniť. Tieto nastavenia farieb potvrdíte kliknutím na tlačidlo OK, ináč sa tieto nastavenia o 10 sekúnd obnovia."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Využitie batérie"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Počas nabíjania nie je Šetrič batérie k dispozícii"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Šetrič batérie"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Obmedzí výkonnosť a údaje na pozadí"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tlačidlo <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Domov"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Späť"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Nahor"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Nadol"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Doľava"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Doprava"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Do stredu"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulátor"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Medzerník"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Prehrať/pozastaviť"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zastaviť"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Nasledujúce"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Predchádzajúce"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Pretočiť späť"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Pretočiť dopredu"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Posunúť o stranu vyššie"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Posunúť o stranu nižšie"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Odstrániť"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Domov"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Ukončiť"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Vložiť"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Číselná klávesnica <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Systém"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Domovská stránka"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedávne"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Späť"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Zobrazovať panel Nerušiť v dialógu Hlasitosť"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Umožňuje povoliť úplné ovládanie režimu nerušiť v dialógu Hlasitosť."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hlasitosť a režim Nerušiť"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Pri znížení hlasitosti prejsť do režimu Nerušiť"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Upozornenia"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klávesové skratky"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Prepnúť metódu vstupu"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikácie"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomocná aplikácia"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prehliadač"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Okamžité správy"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendár"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazovať s ovládacími prvkami hlasitosti"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušiť"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Skratka tlačidiel hlasitosti"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Pri zvýšení hlasitosti ukončiť režim Nerušiť"</string>
     <string name="battery" msgid="7498329822413202973">"Batéria"</string>
     <string name="clock" msgid="7416090374234785905">"Hodiny"</string>
     <string name="headset" msgid="4534219457597457353">"Náhlavná súprava"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slúchadlá pripojené"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Náhlavná súprava pripojená"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Umožňuje aktivovať alebo deaktivovať zobrazenie ikon v stavovom riadku."</string>
     <string name="data_saver" msgid="5037565123367048522">"Šetrič dát"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Šetrič dát je zapnutý"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Šetrič dát je vypnutý"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Zapnuté"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Vypnuté"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigačný panel"</string>
     <string name="start" msgid="6873794757232879664">"Začiatok"</string>
     <string name="center" msgid="4327473927066010960">"Stred"</string>
@@ -526,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Výber tlačidla klávesnice"</string>
     <string name="preview" msgid="9077832302472282938">"Ukážka"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Dlaždice pridáte presunutím"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Presunutím sem odstránite"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Upraviť"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Čas"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Zobrazovať hodiny, minúty a sekundy"</item>
+    <item msgid="1427801730816895300">"Zobrazovať hodiny a minúty (predvolené)"</item>
+    <item msgid="3830170141562534721">"Nezobrazovať túto ikonu"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Vždy zobrazovať percentá"</item>
+    <item msgid="2139628951880142927">"Zobrazovať percentá počas nabíjania (predvolené)"</item>
+    <item msgid="3327323682209964956">"Nezobrazovať túto ikonu"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Ďalšie"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Rozdeľovač obrazovky"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Posunúť nadol"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Posunúť nahor"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Posunúť doľava"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Posunúť doprava"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikácia nemusí fungovať v režime viacerých okien"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozícia <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Upravíte ju dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Pridáte ju dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozícia <xliff:g id="POSITION">%1$d</xliff:g>. Vyberiete ju dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Presunúť dlaždicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstrániť dlaždicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola pridaná na pozíciu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola odstránená"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola presunutá na pozíciu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor rýchlych nastavení"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
new file mode 100644
index 0000000..cc48e07
--- /dev/null
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Zavrieť režim PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Celá obrazovka"</string>
+    <string name="pip_play" msgid="674145557658227044">"Prehrať"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pozastaviť"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Režim PIP ovládajte pomocou tlačidla "<b>"PLOCHA"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Režim PIP ovládajte stlačením a podržaním tlačidla PLOCHA"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Dobre"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odmietnuť"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 9ebb19d..c5a43f9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -75,7 +75,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Posnetek zaslona je shranjen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dotaknite se, če si želite ogledati posnetek zaslona."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Posnetka zaslona ni bilo mogoče shraniti."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Izdelava posnetka zaslona ni mogoča zaradi omejenega prostora za shranjevanje ali pa tega ne dovoli aplikacija ali vaša organizacija."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Pri shranjevanju posnetka zaslona je prišlo do težave."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Shranjevanje posnetka zaslona ni mogoče zaradi omejenega prostora za shranjevanje."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikacija ali organizacija ne dovoljuje posnetkov zaslona."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosa datotek prek USB-ja"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Vpni kot predvajalnik (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Vpni kot fotoaparat (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Opusti aplikacijo <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je bila odstranjena."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Vse nedavne aplikacije so bile opuščene."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Zaganjanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obvestilo je bilo odstranjeno."</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daljši čas."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Krajši čas."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svetilka je izklopljena."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svetilka ni na voljo."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svetilka je vklopljena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svetilka je izklopljena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svetilka je vklopljena."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Način za delo vklopljen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Način za delo je izklopljen."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Način za delo je vklopljen."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Varčevanje s podatki je izklopljeno."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Varčevanje s podatki je vklopljeno."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svetlost zaslona"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Prenos podatkov v omrežju 2G/3G je zaustavljen"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktivne zahteve za lokacijo"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Izbriši vsa obvestila."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"in <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Nastavitve obvestil"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Nastavitve aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon se bo samodejno zasukal."</string>
@@ -298,14 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Omejitev: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način za delo"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Vaši nedavni zasloni so prikazani tu"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Ni nedavnih elementov"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vse te počistili"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripenjanje zaslona"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacije <xliff:g id="APP">%s</xliff:g> ni bilo mogoče zagnati."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> je v varnem načinu onemogočena."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Zgodovina"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Izbriši"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Izbriši vse"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacija ne podpira načina z več okni"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podpira načina z več okni"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Razdeli vodoravno"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Razdeli navpično"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Razdeli po meri"</string>
@@ -335,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Popolna\ntišina"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprednostno"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Vse"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Vse\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hitro polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Počasno polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
@@ -449,34 +457,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogočanje vklopa razdeljenega zaslona z vlečenjem navzgor"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogočanje poteze za razdeljen zaslon z vlečenjem navzgor"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za vklop razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
     <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vklop"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Uporabi za obvestila za temo <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Uporabi za vsa obvestila za to aplikacijo"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Prikaži obvestila brez zvoka"</string>
+    <string name="block" msgid="2734508760962682611">"Blokiraj vsa obvestila"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne utišaj"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne utišaj ali blokiraj"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaz celotnih nastavitev za pomembnost"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Najmanjša pomembnost"</string>
     <string name="low_importance" msgid="4109929986107147930">"Nizka pomembnost"</string>
     <string name="default_importance" msgid="8192107689995742653">"Običajna pomembnost"</string>
     <string name="high_importance" msgid="1527066195614050263">"Visoka pomembnost"</string>
     <string name="max_importance" msgid="5089005872719563894">"Nujna pomembnost"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikoli ne prikaži teh obvestil"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Prikaži na dnu seznama obvestil brez zvoka"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži ta obvestila brez zvoka"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu seznama obvestil in predvajaj zvok"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Za hip pokaži predogled na zaslonu in predvajaj zvok"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Prikaži na dnu seznama obvestil brez zvoka"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Prikaži ta obvestila brez zvoka"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dovoli zvoke za ta obvestila"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Za hip pokaži predogled na zaslonu in dovoli zvok"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Prikaži na vrhu seznama obvestil, za hip pokaži predogled na zaslonu in dovoli zvok"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
     <string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Običajne barve"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nočne barve"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Barve po meri"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Samodejno"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznane barve"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Spreminjanje barv"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaz ploščice s hitrimi nastavitvami"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Omogočanje spremembe po meri"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolniki obvestil za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Barva in videz"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nočni način"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Umerjanje zaslona"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Vklopljeno"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Izklopljeno"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Samodejni vklop"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Preklop v nočni način, kot je ustrezno glede na lokacijo in uro v dnevu"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Ko je vklopljen nočni način"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Uporaba temne teme za sistem Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Prilagodi odtenek"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Prilagodi svetlost"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Za osrednja področja sistema Android, ki so običajno prikazana v svetli temi, na primer nastavitve, je uporabljena temna tema."</string>
     <string name="color_apply" msgid="9212602012641034283">"Uporabi"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Potrditev nastavitev"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Zaradi nekaterih barvnih nastavitev lahko postane ta naprava neuporabna. Kliknite »V redu«, če želite potrditi te barvne nastavitve. V nasprotnem primeru se bodo čez 10 sekund ponastavile na prvotno vrednost."</string>
@@ -484,25 +502,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Varčevanje z energijo akumulatorja med polnjenjem ni na voljo"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Varčevanje z energijo akumulatorja"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Gumb <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Začetek"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Nazaj"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gor"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dol"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Levo"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Desno"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Sredina"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulatorka"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Preslednica"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Vnesi"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Premik nazaj"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Predvajaj/zaustavi"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Ustavi"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Naslednji"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prejšnji"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Previj nazaj"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Previj naprej"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Stran gor"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Stran dol"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Izbriši"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Začetek"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Konec"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Vstavi"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Številska tipkovnica <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Začetni zaslon"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazaj"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Pokaži način »ne moti« v nadzoru glasnosti"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Omogoča popoln nadzor načina »ne moti« v pogovornem oknu za glasnost."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Nadzor glasnosti in način »ne moti«"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Odpiranje načina »ne moti« pri zmanjšanju glasnosti"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obvestila"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Bližnjične tipke"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Preklop načina vnosa"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoč"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brskalnik"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Stiki"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Neposredno sporočanje"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Glasba"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Koledar"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolniki glasnosti"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne moti"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Bližnjica z gumboma za glasnost"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Zapustitev načina »ne moti« pri povečanju glasnosti"</string>
     <string name="battery" msgid="7498329822413202973">"Akumulator"</string>
     <string name="clock" msgid="7416090374234785905">"Ura"</string>
     <string name="headset" msgid="4534219457597457353">"Slušalke z mikrofonom"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalke priključene"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Slušalke z mikrofonom priključene"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Omogoči ali onemogoči prikaz ikon v vrstici stanja."</string>
     <string name="data_saver" msgid="5037565123367048522">"Varčevanje s podatki"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Varčevanje s podatki je vklopljeno"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Varčevanje s podatki je izklopljeno"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Vklopljeno"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Izklop"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Vrstica za krmarjenje"</string>
     <string name="start" msgid="6873794757232879664">"Začetek"</string>
     <string name="center" msgid="4327473927066010960">"Sredina"</string>
@@ -524,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Izbira gumba tipkovnice"</string>
     <string name="preview" msgid="9077832302472282938">"Predogled"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Povlecite, če želite dodati ploščice"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Če želite odstraniti, povlecite sem"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Ura"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Prikaži ure, minute in sekunde"</item>
+    <item msgid="1427801730816895300">"Prikaži ure in minute (privzeto)"</item>
+    <item msgid="3830170141562534721">"Ne prikaži te ikone"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Vedno prikaži odstotek"</item>
+    <item msgid="2139628951880142927">"Prikaži odstotek med polnjenjem (privzeto)"</item>
+    <item msgid="3327323682209964956">"Ne prikaži te ikone"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Drugo"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Razdelilnik zaslonov"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Premakni navzdol"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Premakni navzgor"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Premakni levo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Premakni desno"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija morda ne deluje v načinu z več okni"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Če želite urediti, se dvakrat dotaknite."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Če želite dodati, se dvakrat dotaknite."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Položaj: <xliff:g id="POSITION">%1$d</xliff:g>. Če želite izbrati, se dvakrat dotaknite."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premik tega: <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstranitev tega: <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je dodano na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je odstranjeno"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> premaknjeno na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Urejevalnik hitrih nastavitev."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
new file mode 100644
index 0000000..38f9e8e
--- /dev/null
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Zapri način PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Celozaslonsko"</string>
+    <string name="pip_play" msgid="674145557658227044">"Predvajanje"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Zaustavitev"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Pridr. "<b>"HOME"</b>" za up. n. PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Pridržite gumb HOME za upravljanje načina PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Razumem"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Opusti"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 3f25e7d..0188e5b 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Pamja e ekranit u kap."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Prek për të parë pamjen e ekranit tënd."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nuk mundi të kapte pamjen e ekranit."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Nuk pranon pamje ekrani për shkak të hapësirës së kufizuar ruajtëse, ose një gjë e tillë nuk lejohet nga aplikacioni apo organizata jote."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"U has problem gjatë ruajtjes së pamjes së ekranit."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Pamja e ekranit nuk mund të ruhet për shkak të hapësirës ruajtëse të kufizuar."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Nxjerrja e pamjeve të ekranit nuk lejohet nga aplikacioni ose organizata jote."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opsionet e transferimit të dosjeve të USB-së"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Lidh si një lexues \"media\" (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montoje si kamerë (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Largo <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> është hequr."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Të gjitha aplikacionet e fundit u larguan."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Po nis <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Njoftimi është hequr."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Më shumë kohë."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Më pak kohë."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Elektriku është i çaktivizuar."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Blici është i padisponueshëm"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Elektriku u aktivizua."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Elektriku u çaktivizua."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Elektriku është i aktivizuar."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modaliteti i punës është i aktivizuar."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modaliteti i punës është i çaktivizuar."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modaliteti i punës është i aktivizuar."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Kursyesi i të dhënave është çaktivizuar."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Kursyesi i të dhënave është aktivizuar."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ndriçimi i ekranit"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Të dhënat 2G-3G janë ndërprerë"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Të dhënat 4G janë ndërprerë"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Vendndodhja është caktuar nga GPS-ja"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Kërkesat për vendodhje janë aktive"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Pastro të gjitha njoftimet."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Cilësimet e njoftimeve"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Cilësimet e <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrani do të rrotullohet automatikisht."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Kufiri: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Paralajmërim për kufirin prej <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modaliteti i punës"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Ekranet e tua të fundit shfaqen këtu"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Nuk ka asnjë artikull të fundit"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"I ke pastruar të gjitha"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacioni i aplikacionit"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"gozhdimi i ekranit"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"kërko"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nuk mundi të nisej."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> është i çaktivizuar në modalitetin e sigurt."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historiku"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Pastro"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Pastroji të gjitha"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ky aplikacion nuk e mbështet modalitetin me shumë dritare"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacioni nuk e mbështet modalitetin me shumë dritare"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Ndaje horizontalisht"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ndaj vertikalisht"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ndaj të personalizuarën"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Heshtje\ne plotë"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vetëm\nme prioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vetëm\nalarmet"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Të gjitha"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Të gjitha\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Po ngarkohet (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> deri sa të mbushet)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Po ngarkon me shpejtësi (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Po ngarkon me ngadalë (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivizo përshpejtuesin e rrëshqitjes lart për ekranin e ndarë"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivizo gjestin e rrëshqitjes lart për ekranin e ndarë"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivizo gjestin për të hyrë tek ekrani i ndarë duke rrëshqitur lart nga butoni \"Përmbledhja\""</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Të aktivizohet \"bluetooth-i\"?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Për të lidhur tastierën me tabletin, në fillim duhet të aktivizosh \"bluetooth-in\"."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivizo"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Zbatoje për njoftimet nga <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Zbatoje për të gjitha njoftimet nga ky aplikacion"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Shfaqi njoftimet në heshtje"</string>
+    <string name="block" msgid="2734508760962682611">"Blloko të gjitha njoftimet"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Mos e vendos në heshtje"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Mos e vendos në heshtje ose mos e blloko"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Shfaq cilësimet e plota të rëndësisë"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"I bllokuar"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Rëndësi minimale"</string>
     <string name="low_importance" msgid="4109929986107147930">"Rëndësi e ulët"</string>
     <string name="default_importance" msgid="8192107689995742653">"Rëndësi normale"</string>
     <string name="high_importance" msgid="1527066195614050263">"Rëndësi e lartë"</string>
     <string name="max_importance" msgid="5089005872719563894">"Rëndësi urgjente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Mos i shfaq asnjëherë këto njoftime"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Shfaqi në heshtje në fund të listës së njoftimeve"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Shfaqi këto njoftime në heshtje"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Shfaqi në krye të listës së njoftimeve dhe lësho tingull"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Shfaq një vështrim të shpejtë në ekran dhe lësho tingull"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Shfaqi në heshtje në fund të listës së njoftimeve"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Shfaqi këto njoftime në heshtje"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Lejoji këto njoftime të nxjerrin tinguj"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Shfaq një vështrim të shpejtë në ekran dhe lësho një tingull"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Shfaqi në krye të listës së njoftimeve, shfaq vështrim të shpejtë në ekran dhe lësho një tingull"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
     <string name="notification_done" msgid="5279426047273930175">"U krye"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Ngjyrat normale"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Ngjyrat e natës"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Ngjyrat e personalizuara"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatike"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Ngjyra të panjohura"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Modifikimi i ngjyrës"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Pllakëza Shfaq cilësimet e shpejta"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Zbato transformimin e personalizuar"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrollet e njoftimeve të <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Ngjyra dhe pamja"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Modaliteti i natës"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibro ekranin"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Aktiv"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Joaktiv"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Aktivizoje automatikisht"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Kalo në \"Modalitetin e natës\" sipas përshtatshmërisë për vendin dhe kohën e ditës"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kur \"Modaliteti i natës\" është aktiv"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Përdor temën e errët për Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Rregullo nuancën"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Rregullo ndriçimin"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema e errët zbatohet në zonat kryesore të Android OS që shfaqen zakonisht në një temë të çelur, siç janë \"Cilësimet\"."</string>
     <string name="color_apply" msgid="9212602012641034283">"Zbato"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Konfirmo cilësimet"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Disa cilësime ngjyrash mund ta bëjnë këtë pajisje të papërdorshme. Kliko OK për të konfirmuar këto cilësime ngjyrash, përndryshe këto cilësime do të rivendosen pas 10 sekondash."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"\"Kursyesi i baterisë\" nuk është i disponueshëm gjatë karikimit"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Kursyesi i baterisë"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Butoni <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Kreu"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Prapa"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Lart"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Poshtë"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Majtas"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Djathtas"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Qendror"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Skedë"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Hapësirë"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Kthim prapa"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Luaj/pauzë"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Ndalo"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Përpara"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prapa"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rikthe me shpejtësi"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Përparo me shpejtësi"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Faqja lart"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Faqja poshtë"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Fshi"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Kreu"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fundi"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Fut"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Kyçja e numrave"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tastiera numerike <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistemi"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Kreu"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Të fundit"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Prapa"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Shfaq \"Mos shqetëso\" te volumi"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Lejo kontrollin e plotë të opsionit \"Mos shqetëso\" në dialogun e volumit."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumi dhe \"Mos shqetëso\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Vendos \"Mos shqetëso\" me volumin poshtë"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Njoftimet"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Shkurtoret e tastierës"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Ndërro metodën e hyrjes"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacionet"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistenti"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Shfletuesi"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktet"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Mail-i"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mesazh i çastit"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzikë"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendari"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Shfaq me kontrollet e volumit"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mos shqetëso"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Shkurtorja e butonave të volumit"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Dil nga \"Mos shqetëso\" me volumin lart"</string>
     <string name="battery" msgid="7498329822413202973">"Bateria"</string>
     <string name="clock" msgid="7416090374234785905">"Ora"</string>
     <string name="headset" msgid="4534219457597457353">"Kufjet me mikrofon"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Kufjet u lidhën"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Kufjet me mikrofon u lidhën"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Aktivizo ose çaktivizo shfaqjen e ikonave në shiritin e statusit."</string>
     <string name="data_saver" msgid="5037565123367048522">"Kursyesi i të dhënave"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Kursyesi i të dhënave është aktiv"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Kursyesi i të dhënave është joaktiv"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Aktiv"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Joaktiv"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Shiriti i navigimit"</string>
     <string name="start" msgid="6873794757232879664">"Nis"</string>
     <string name="center" msgid="4327473927066010960">"Qendror"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Zgjidh butonin e tastierës"</string>
     <string name="preview" msgid="9077832302472282938">"Pamja paraprake"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Zvarrit për të shtuar pllakëzat"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Zvarrit këtu për ta hequr"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Redakto"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Ora"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Shfaq orët, minutat dhe sekondat"</item>
+    <item msgid="1427801730816895300">"Shfaq orët dhe minutat (e parazgjedhur)"</item>
+    <item msgid="3830170141562534721">"Mos e shfaq këtë ikonë"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Shfaq gjithmonë përqindjen"</item>
+    <item msgid="2139628951880142927">"Shfaq përqindjen gjatë ngarkimit (e parazgjedhur)"</item>
+    <item msgid="3327323682209964956">"Mos e shfaq këtë ikonë"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Të tjera"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Ndarësi i ekranit të ndarë"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Lëviz poshtë"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Lëviz lart"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Lëviz majtas"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Lëviz djathtas"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacioni mund të mos punojë me funksionin me shumë dritare."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Trokit dy herë për ta redaktuar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Trokit dy herë për ta shtuar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>. Trokit dy herë për ta zgjedhur."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Zhvendose <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Hiqe <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> është shtuar te pozicioni <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> u hoq"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> u zhvendos te pozicioni <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redaktori i cilësimeve të shpejta."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings_tv.xml b/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
new file mode 100644
index 0000000..672a119
--- /dev/null
+++ b/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Mbyll PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Ekrani i plotë"</string>
+    <string name="pip_play" msgid="674145557658227044">"Luaj"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pauzë"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Mbaj shtypur "<b>"HOME"</b>" për të kontrolluar PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Shtyp dhe mbaj shtypur butonin HOME për të kontrolluar PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"E kuptova"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Hiqe"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 8d54ca2..501a3e3 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -74,7 +74,9 @@
     <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="1260203058661337274">"Није могуће снимити екран због недовољне меморије или то не дозвољава апликација или организација."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Дошло је до проблема при чувању снимка екрана."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Чување снимка екрана није успело због ограниченог меморијског простора."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Апликација или организација не дозвољавају прављење снимака екрана."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Опције USB преноса датотека"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Прикључи као медија плејер (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Прикључи као камеру (PTP)"</string>
@@ -167,6 +169,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Одбаците <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Апликација <xliff:g id="APP">%s</xliff:g> је одбачена."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Све недавно коришћене апликације су одбачене."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Покрећемо <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Обавештење је одбачено."</string>
@@ -207,6 +211,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Више времена."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Мање времена."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Батеријска лампа је искључена."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Лампа није доступна."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Батеријска лампа је укључена."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Батеријска лампа је искључена."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Батеријска лампа је укључена."</string>
@@ -219,6 +224,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Режим рада је укључен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Режим рада је искључен."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Режим рада је укључен."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Уштеда података је искључена."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Уштеда података је укључена."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветљеност екрана"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G подаци су паузирани"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
@@ -232,6 +239,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Локацију је подесио GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Има активних захтева за локацију"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Обриши сва обавештења."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"и још <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Подешавања обавештења"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Подешавања за <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран ће се аутоматски ротирати."</string>
@@ -297,15 +305,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ограничење од <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим рада"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Недавни екрани се појављују овде"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Нема недавних ставки"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Обрисали сте све"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"качење екрана"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Покретање апликације <xliff:g id="APP">%s</xliff:g> није успело."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Историја"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Обриши"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Апликација <xliff:g id="APP">%s</xliff:g> је онемогућена у безбедном режиму."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Обриши све"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ова апликација не подржава режим са више прозора"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апликација не подржава режим са више прозора"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Подели хоризонтално"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Подели вертикално"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Прилагођено дељење"</string>
@@ -335,8 +344,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Потпуна\nтишина"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприорит. прекиди"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Све"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Сви\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Споро се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -449,61 +456,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Омогући убрзавач за превлачење нагоре за подељени екран"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Омогући покрет за превлачење нагоре за подељени екран"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Омогућава покрет за прелазак на подељени екран превлачењем нагоре од дугмета Преглед"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Укључи"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Примени на обавештења о теми <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Примени на сва обавештења из ове апликације"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Приказуј обавештења без звука"</string>
+    <string name="block" msgid="2734508760962682611">"Блокирај сва обавештења"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Не искључуј звук"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не искључују звук нити блокирај"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Прикажи комплетна подешавања важности"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блокирана"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Веома мала важност"</string>
     <string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
     <string name="default_importance" msgid="8192107689995742653">"Уобичајена важност"</string>
     <string name="high_importance" msgid="1527066195614050263">"Велика важност"</string>
     <string name="max_importance" msgid="5089005872719563894">"Важност: хитно"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ова обавештења се никада не приказују"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Приказују се у дну листе обавештења без звука"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Ова обавештења се приказују без звука"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Приказују се у врху листе обавештења и емитује се звук"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Накратко се приказују на екрану и емитује се звук"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Приказују се у дну листе обавештења без звука"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ова обавештења се приказују без звука"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Дозволите да ова обавештења емитују звук"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Накратко се приказују на екрану и емитују звук"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Приказују се у врху листе обавештења, накратко се приказују на екрану и емитују звук"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Нормалне боје"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Ноћне боје"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Прилагођене боје"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Аутоматски"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Непознате боје"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Измена боја"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Прикажи плочицу Брза подешавања"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Омогући прилагођену трансформацију"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроле обавештења за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Ноћни режим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Калибришите екран"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Укључено"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Искључено"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Аутоматски укључи"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Пређите на ноћни режим у зависности од локације и доба дана"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Када је ноћни режим укључен"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Користи тамну тему за Android ОС"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Прилагоди сенку"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Прилагоди осветљеност"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Тамна тема се примењује на кључне делове Android ОС-а који се обично приказују у светлој теми, попут Подешавања."</string>
     <string name="color_apply" msgid="9212602012641034283">"Примени"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Потврдите подешавања"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Нека подешавања боја могу да учине уређај неупотребљивим. Кликните на Потврди да бисте потврдили ова подешавања боја, пошто ће се у супротном ова подешавања ресетовати након 10 секунди."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Потрошња батерије"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Уштеда батерије није доступна током пуњења"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Уштеда батерије"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Смањује перформансе и позадинске податке"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Дугме <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Тастер Почетна"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Тастер Назад"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Тастер са стрелицом нагоре"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Тастер са стрелицом надоле"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Тастер са стрелицом налево"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Тастер са стрелицом надесно"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Тастер са централном стрелицом"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Табулатор"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Тастер за размак"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Тастер за брисање уназад"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Тастер за репродукцију/паузирање"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Тастер за заустављање"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Тастер Следећа"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Тастер Претходна"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Тастер за премотавање уназад"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Тастер за премотавање унапред"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Тастер за страницу нагоре"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Тастер за страницу надоле"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Тастер за брисање"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Тастер Почетна"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Тастер за крај"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Тастер за уметање"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Тастер <xliff:g id="NAME">%1$s</xliff:g> на нумеричкој тастатури"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Систем"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетни"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавни садржај"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Прикажи подешавање Не узнемиравај у дијалогу за јачину звука"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дозвољава потпуну контролу подешавања Не узнемиравај у дијалогу за јачину звука."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Јачина звука и Не узнемиравај"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Уђи у режим Не узнемиравај када је звук утишан"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Обавештења"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Тастерске пречице"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Промени метод уноса"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апликације"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Апликација за помоћ"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Прегледач"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Имејл"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Размена тренутних порука"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи са контролама јачине звука"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не узнемиравај"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Пречица за дугмад за јачину звука"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Изађи из режима Не узнемиравај када је звук појачан"</string>
     <string name="battery" msgid="7498329822413202973">"Батерија"</string>
     <string name="clock" msgid="7416090374234785905">"Сат"</string>
     <string name="headset" msgid="4534219457597457353">"Наглавне слушалице"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Слушалице су повезане"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Наглавне слушалице су повезане"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Омогућите или онемогућите приказивање икона на статусној траци."</string>
     <string name="data_saver" msgid="5037565123367048522">"Уштеда података"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Уштеда података је укључена"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Уштеда података је искључена"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Укључено"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Искључено"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Трака за навигацију"</string>
     <string name="start" msgid="6873794757232879664">"Покрени"</string>
     <string name="center" msgid="4327473927066010960">"Центар"</string>
@@ -525,5 +578,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Изаберите дугме за тастатуру"</string>
     <string name="preview" msgid="9077832302472282938">"Преглед"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Превуците да бисте додали плочице"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Превуците овде да бисте уклонили"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Измени"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Време"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Прикажи сате, минуте и секунде"</item>
+    <item msgid="1427801730816895300">"Прикажи сате и минуте (подразумевано)"</item>
+    <item msgid="3830170141562534721">"Не приказуј ову икону"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Увек приказуј проценат"</item>
+    <item msgid="2139628951880142927">"Прикажи проценат током пуњења (подразумевано)"</item>
+    <item msgid="3327323682209964956">"Не приказуј ову икону"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Друго"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Разделник подељеног екрана"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Помери надоле"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Помери нагоре"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Помери улево"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Помери удесно"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Апликација можда неће функционисати са више прозора"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Двапут додирните да бисте изменили."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Двапут додирните да бисте додали."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција. Двапут додирните да бисте изабрали."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Премести плочицу <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Уклони плочицу <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је додата на <xliff:g id="POSITION">%2$d</xliff:g>. позицију"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је уклоњена"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је премештена на <xliff:g id="POSITION">%2$d</xliff:g>. позицију"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Уређивач за Брза подешавања."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
new file mode 100644
index 0000000..d822e4e
--- /dev/null
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Затвори PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Цео екран"</string>
+    <string name="pip_play" msgid="674145557658227044">"Пусти"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Паузирај"</string>
+    <string name="pip_hold_home" msgid="340086535668778109"><b>"ПОЧЕТНИ ЕКРАН"</b>" конт. PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Притисните и задржите дугме ПОЧЕТНИ ЕКРАН да бисте контролисали PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Важи"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Одбаци"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 2a91962..959128e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skärmdumpen har tagits."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Tryck här om du vill visa skärmdumpen."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Det gick inte att ta någon skärmdump."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Skärmdump misslyckades. Lagringsutrymmet räcker inte eller appen/organisationen tillåter det inte."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Det gick inte att spara skärmdumpen."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Det går inte att spara skärmdumpen eftersom lagringsutrymmet inte räcker."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Appen eller organisationen tillåter inte att du tar skärmdumpar."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Överföringsalternativ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Montera som mediaspelare (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montera som kamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ta bort <xliff:g id="APP">%s</xliff:g> från listan."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> togs bort permanent."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alla appar har tagits bort från listan Senaste."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Startar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Meddelandet ignorerades."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Längre tid."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kortare tid."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ficklampa av."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ficklampan är inte tillgänglig."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ficklampa på."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ficklampan har inaktiverats."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ficklampan har aktiverats."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbetsläget aktiverat."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbetsläget har inaktiverats."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbetsläget har aktiverats."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Databesparing har inaktiverats."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Databesparing har aktiverats."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skärmens ljusstyrka"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- och 3G-data har pausats"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Det finns aktiva platsbegäranden"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> till"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Aviseringsinställningar"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Inställningar för <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skärmen roteras automatiskt."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Gräns: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Varning <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbetsläge"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Dina senaste skärmar visas här"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Listan med de senaste åtgärderna är tom"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har tömt listan"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fästa skärmen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historik"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Rensa"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> är inaktiverad i säkert läge."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Rensa alla"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Den här appen har inte stöd för flera fönster"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen har inte stöd för flera fönster"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Helt\ntyst"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Endast\nprioriterade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Endast\nalarm"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Alla"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alla\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laddas snabbt (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laddas sakta (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivera accelerator för delad skärm när du sveper uppåt"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivera delad skärm när du sveper uppåt"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivera en rörelse som delar skärmen när du sveper uppåt från knappen Översikt"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivera"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Ändra för alla aviseringar för <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Ändra för alla aviseringar från den här appen"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Visa aviseringar utan ljud"</string>
+    <string name="block" msgid="2734508760962682611">"Blockera alla aviseringar"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Stäng inte av ljudet"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Stäng inte av ljudet och blockera inte"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Visa alla relevansinställningarna"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blockerad"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Oviktig avisering"</string>
     <string name="low_importance" msgid="4109929986107147930">"Oviktig avisering"</string>
     <string name="default_importance" msgid="8192107689995742653">"Vanlig avisering"</string>
     <string name="high_importance" msgid="1527066195614050263">"Viktig avisering"</string>
     <string name="max_importance" msgid="5089005872719563894">"Brådskande avisering"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Visa aldrig de här aviseringarna"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Visa längst ned på listan, utan ljud"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Visa aviseringarna utan ljud"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Visa högst upp på listan, med ljud"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Visa på skärmen, med ljud"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Visa längst ned i listan, utan ljud"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Visa aviseringarna utan ljud"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Tillåt ljud för de här aviseringarna"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Visa med snabbtitt på skärmen och tillåt ljud"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Visa högst upp i aviseringslistan och med snabbtitt på skärmen samt tillåt ljud"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klar"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normala färger"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Nattfärger"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Anpassade färger"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Automatiskt"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Okända färger"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Färgändring"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Visa rutan Snabbinställningar"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Aktivera anpassad omvandling"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-aviseringar"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Färg och utseende"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Nattläge"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Kalibrera skärmen"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Aktiverat"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Inaktiverat"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Aktivera automatiskt"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Byt till Nattläge vid passande platser och tider på dygnet"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"När Nattläget är aktiverat"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Använd mörkt tema för Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Justera ton"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Justera ljusstyrka"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Det mörka temat används för kärnfunktioner i Android OS som brukar visas med ett ljust tema, t.ex. inställningarna."</string>
     <string name="color_apply" msgid="9212602012641034283">"Verkställ"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Bekräfta inställningarna"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Vissa färginställningar kan göra den här enheten oanvändbar. Klicka på OK om du vill bekräfta färginställningarna, annars återställs inställningarna efter 10 sekunder."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Batteriförbrukning"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparläget är inte tillgängligt vid laddning"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparläge"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Minskar prestanda och bakgrundsdata"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Knappen <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Start"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Tillbaka"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Upp"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ned"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vänster"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Höger"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centrera"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Flik"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Blanksteg"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Retur"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backsteg"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Spela upp/Pausa"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Avsluta"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Nästa"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Föregående"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spola tillbaka"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Snabbspola framåt"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Sida upp"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Sida ned"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Radera"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Start"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Slut"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Infoga"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numeriskt tangentbord <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startsida"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Senaste"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tillbaka"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Visa Stör ej i volymkontrollen"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Tillåt full kontroll över Stör ej i volymkontrollen"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volym och Stör ej"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Aktivera Stör ej när volymen sänks"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Aviseringar"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Kortkommandon"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Byt inmatningsmetod"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Appar"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Hjälp"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Webbläsare"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakter"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Snabbmeddelanden"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Visa med volymkontroller"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Stör ej"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Genväg till volymknappar"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Inaktivera Stör ej när volymen höjs"</string>
     <string name="battery" msgid="7498329822413202973">"Batteri"</string>
     <string name="clock" msgid="7416090374234785905">"Klocka"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Hörlurar anslutna"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset anslutet"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Visa eller dölj ikoner i statusfältet."</string>
     <string name="data_saver" msgid="5037565123367048522">"Databesparing"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Databesparing är aktiverat"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Databesparing är inaktiverat"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"På"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Inaktiverat"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigeringsfält"</string>
     <string name="start" msgid="6873794757232879664">"Början"</string>
     <string name="center" msgid="4327473927066010960">"Centrera"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Välj tangentbordsknapp"</string>
     <string name="preview" msgid="9077832302472282938">"Förhandsgranskning"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Lägg till rutor genom att dra"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Ta bort genom att dra här"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Redigera"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Tid"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Visa timmar, minuter och sekunder"</item>
+    <item msgid="1427801730816895300">"Visa timmar och minuter (standard)"</item>
+    <item msgid="3830170141562534721">"Visa inte den här ikonen"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Visa alltid procent"</item>
+    <item msgid="2139628951880142927">"Visa procent under laddning (standard)"</item>
+    <item msgid="3327323682209964956">"Visa inte den här ikonen"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Annat"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Avdelare för delad skärm"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytta nedåt"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytta uppåt"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytta åt vänster"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytta åt höger"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerar eventuellt inte i flerfönsterläge"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tryck snabbt två gånger om du vill redigera positionen."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lägg till genom att trycka snabbt två gånger."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Välj den genom att trycka snabbt två gånger."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flytta <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ta bort <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har lagts till på position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har tagits bort"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har flyttats till position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigerare för snabbinställningar."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
new file mode 100644
index 0000000..0c0afc3
--- /dev/null
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Stäng PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Helskärm"</string>
+    <string name="pip_play" msgid="674145557658227044">"Spela upp"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pausa"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Styr PIP med "<b>"startknappen"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Styr bild-i-bild genom att hålla ned startsideknappen"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorera"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 55f0213..4b936c9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Picha ya skrini imenaswa."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Gusa ili kuona picha yako ya skrini."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Haikuweza kunasa picha ya skrini"</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Haiwezi kupiga picha ya skrini kwa sababu nafasi ya hifadhi haitoshi, au hairuhusiwi na programu yako au ya shirika."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Hitilafu imetokea wakati wa kuhifadhi picha ya skrini."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Haina nafasi ya kutosha kuhifadhi picha ya skrini."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Shirika au programu yako haikuruhusu upige picha za skrini."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Machaguo ya uhamisho wa faili la USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Angika kama kichezeshi cha midia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Angika kama kamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ondoa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> imeondolewa."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Programu za hivi majuzi zimeondolewa."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Inaanzisha <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Arifa imetupwa."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Muda zaidi."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Muda kidogo"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Tochi imezimwa."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Tochi haipatikani."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Tochi inawaka."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Tochi imezimwa."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Tochi imewashwa."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Hali ya kazi imewashwa."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Hali ya kazi imezimwa."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Hali ya kazi imewashwa."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Kiokoa Data kimezimwa."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Kiokoa Data kimewashwa."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ung\'aavu wa skrini"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data ya 2G-3G imesitishwa"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Mahali pamewekwa na GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Maombi ya eneo yanatumika"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Futa arifa zote."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Mipangilio ya arifa"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Mipangilio ya <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrini itazunguka kiotomatiki."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"kikomo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Hali ya kazi"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Skrini zako za hivi majuzi huonekana hapa"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Hakuna vipengee vya hivi karibuni"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Umeondoa vipengee vyote"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kudumisha programu moja"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Futa"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> imezimwa katika hali salama."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Futa zote"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Programu hii haitumiki katika hali ya madirisha mengi"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Programu haitumiki katika hali ya madirisha mengi"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Gawanya Wima"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Maalum Iliyogawanywa"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Kimya\nkabisa"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kipaumbele\npekee"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kengele\npekee"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Zote"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Zote\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ijae)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Inachaji kwa kasi (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Inachaji pole pole (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Washa kiakibishaji cha skrini inayogawanywa kwa kutelezesha kidole juu"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ruhusu kugawanya skrini kwa ishara ya kutelezesha kidole juu"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Washa kipengele cha ishara ili utumie skrini iliyogawanywa kwa kutelezesha kidole juu kutoka kitufe cha Muhtasari"</string>
     <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Je, ungependa kuwasha Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ili uunganishe Kibodi yako kwenye kompyuta yako kibao, lazima kwanza uwashe Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Washa"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Tumia katika arifa za <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Tumia katika arifa zote kutoka programu hii"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Onyesha arifa bila sauti"</string>
+    <string name="block" msgid="2734508760962682611">"Zuia arifa zote"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Usinyamazishe"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Usinyamazishe wala kuzuia"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Onyesha mipangilio kamili ya umuhimu"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Amezuiwa"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Umuhimu wa kiwango cha chini"</string>
     <string name="low_importance" msgid="4109929986107147930">"Umuhimu kiwango cha chini"</string>
     <string name="default_importance" msgid="8192107689995742653">"Umuhimu wa kiwango cha kawaida"</string>
     <string name="high_importance" msgid="1527066195614050263">"Umuhimu wa kiwango cha juu"</string>
     <string name="max_importance" msgid="5089005872719563894">"Umuhimu wa hali ya dharura"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Usionyeshe arifa hizi kamwe"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Onyesha katika sehemu ya chini ya orodha ya arifa bila sauti"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Onyesha arifa hizi bila sauti"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Onyesha katika sehemu ya juu ya orodha ya arifa na itoe sauti"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Weka onyesho la kuchungulia kwenye skrini na itoe sauti"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Onyesha katika sehemu ya chini ya orodha ya arifa bila sauti"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Onyesha arifa hizi bila sauti"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Ruhusu arifa hizi zitoe sauti"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Chungulia kwenye skrini na uruhusu sauti"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Onyesha katika sehemu ya juu ya orodha ya arifa, chungulia kwenye skrini na uruhusu sauti"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Rangi za kawaida"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Rangi za usiku"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Rangi maalum"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Otomatiki"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Rangi zisizojulikana"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Ubadilishaji wa rangi"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Onyesha kigae cha Mipangilio ya Haraka"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Washa ubadilishaji maalum"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Vidhibiti vya arifa za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Rangi na mwonekano"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Hali ya usiku"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Rekebisha onyesho"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Imewashwa"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Imezimwa"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Washa kiotomatiki"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Badilisha kuwa Hali ya Usiku kulingana na mahali na wakati"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Hali ya Usiku inapowashwa"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Tumia mandhari ya giza katika Mfumo wa Uendeshaji wa Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Rekebisha kivulivuli"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Rekebisha mwangaza"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Mandhari yenye giza yametumika katika maeneo muhimu ya Mfumo wa Uendeshaji wa Android ambayo kwa kawaida huonyeshwa katika mandhari yenye mwangaza, kama vile Mipangilio."</string>
     <string name="color_apply" msgid="9212602012641034283">"Tumia"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Thibitisha mipangilio"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Baadhi ya mipangilio ya rangi inaweza kufanya kifaa hiki kisitumike. Bofya Sawa ili uthibitishe mipangilio hii ya rangi, vinginevyo, mipangilio hii itajiweka upya baada ya sekunde 10."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Matumizi ya betri"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Kiokoa Betri hakipatikani unapochaji betri"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Kiokoa Betri"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Hupunguza data ya chini chini na utendaji"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Kitufe cha <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Mwanzo"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Nyuma"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Juu"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Chini"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Kushoto"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Kulia"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Katikati"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Sogeza"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Nafasi"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Nafasinyuma"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Cheza/Sitisha"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Simamisha"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Inayofuata"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Iliyotangulia"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rudisha nyuma"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Sogeza mbele Haraka"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Futa"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Mwanzo"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Mwisho"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Ingiza"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Mfumo"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Mwanzo"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Zilizotumika majuzi"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nyuma"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Onyesha hali ya usinisumbue katika sauti"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Ruhusu udhibiti kamili wa hali ya usinisumbue katika kidirisha cha sauti."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Sauti na Usinisumbue"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Weka hali ya usinisumbue sauti inapopunguzwa"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Arifa"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Mikato ya Kibodi"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Badilisha mbinu ya kuingiza data"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programu"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Programu ya maagizo ya sauti"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Kivinjari"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Anwani"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Barua pepe"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Ujumbe wa papo kwa papo"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muziki"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalenda"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Onyesha katika vidhibiti vya sauti"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Usinisumbue"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Njia ya mkato ya vitufe vya sauti"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Ondoa hali ya usinisumbue sauti inapoongezwa"</string>
     <string name="battery" msgid="7498329822413202973">"Betri"</string>
     <string name="clock" msgid="7416090374234785905">"Saa"</string>
     <string name="headset" msgid="4534219457597457353">"Vifaa vya sauti"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Imeunganisha spika za masikioni"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Imeunganisha vifaa vya sauti"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Washa au uzime aikoni ili zisionekane kwenye sehemu ya arifa"</string>
     <string name="data_saver" msgid="5037565123367048522">"Kiokoa Data"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Kiokoa Data kimewashwa"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Kiokoa Data kimezimwa"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Imewashwa"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Imezimwa"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Sehemu ya viungo muhimu"</string>
     <string name="start" msgid="6873794757232879664">"Anza"</string>
     <string name="center" msgid="4327473927066010960">"Weka katikati"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Chagua Kitufe cha Kibodi"</string>
     <string name="preview" msgid="9077832302472282938">"Onyesho la kuchungulia"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Buruta ili uongeze vigae"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Buruta hapa ili uondoe"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Badilisha"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Wakati"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Onyesha saa, dakika na sekunde"</item>
+    <item msgid="1427801730816895300">"Onyesha saa na dakika (chaguo-msingi)"</item>
+    <item msgid="3830170141562534721">"Usionyeshe aikoni hii"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Onyesha asilimia kila wakati"</item>
+    <item msgid="2139628951880142927">"Onyesha asilimia wakati inachaji (chaguo-msingi)"</item>
+    <item msgid="3327323682209964956">"Usionyeshe aikoni hii"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Nyingine"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Kitenganishi cha skrini inayogawanywa"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Sogeza chini"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sogeza juu"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sogeza kushoto"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sogeza kulia"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Huenda programu isifanye kazi kwenye madirisha mengi"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Gonga mara mbili ili ubadilishe."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Gonga mara mbili ili uongeze."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>. Gonga mara mbili ili uchague."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Hamisha <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ondoa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imeongezwa kwenye nafasi ya <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imeondolewa"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imehamishiwa kwenye nafasi ya <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kihariri cha Mipangilio ya haraka."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
new file mode 100644
index 0000000..4875f73
--- /dev/null
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Funga PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Skrini nzima"</string>
+    <string name="pip_play" msgid="674145557658227044">"Cheza"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Sitisha"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Shikilia kitufe cha "<b>"HOME"</b>" ili udhibiti PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Bonyeza na ushikilie kitufe cha HOME ili kudhibiti PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Nimeelewa"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ondoa"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index db4da10..1f6bbd3 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -33,16 +33,6 @@
     <!-- Set to true to enable the user switcher on the keyguard. -->
     <bool name="config_keyguardUserSwitcher">true</bool>
 
-    <!-- Recents: The relative range of visible tasks from the current scroll position
-         while the stack is focused. -->
-    <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
-    <item name="recents_layout_focused_range_max" format="float" type="integer">3</item>
-
-    <!-- Recents: The relative range of visible tasks from the current scroll position
-         while the stack is not focused. -->
-    <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item>
-    <item name="recents_layout_unfocused_range_max" format="float" type="integer">2.5</item>
-
     <!-- Nav bar button default ordering/layout -->
     <string name="config_navBarLayout" translatable="false">space;back,home,recent;menu_ime</string>
 
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 122413d..a2010be 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -96,9 +96,6 @@
 
     <dimen name="qs_expand_margin">0dp</dimen>
 
-    <!-- The top padding for the task stack. -->
-    <dimen name="recents_stack_top_padding">40dp</dimen>
-
-    <!-- The side padding for the task stack. -->
-    <dimen name="recents_stack_left_right_padding">64dp</dimen>
+    <!-- Keyboard shortcuts helper -->
+    <dimen name="ksh_layout_width">488dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 4d7d6b5..791d761 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
-        <item name="android:layout_width">480dp</item>
+        <item name="android:layout_width">@dimen/standard_notification_panel_width</item>
     </style>
 
     <style name="UserDetailView">
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 8fe6be9..25e96c8 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -29,11 +29,6 @@
     <!-- Bottom margin (from display edge) for status bar panels -->
     <dimen name="panel_float">56dp</dimen>
 
-    <!-- The radius of the rounded corners on a task view. -->
-    <dimen name="recents_task_view_rounded_corners_radius">3dp</dimen>
-    <!-- The radius of the rounded corners on a task view's shadow. -->
-    <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen>
-
     <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
      max value is used when no notifications are displaying, and the min value is when the
      highest possible number of notifications are showing. -->
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index ecfc446..5489be9 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"குறைந்த சேமிப்பகம் காரணமாக ஸ்கிரீன்ஷாட் எடுக்க முடியவில்லை, அல்லது பயன்பாடு அல்லது உங்கள் நிறுவனத்தால் அனுமதிக்கப்படவில்லை."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ஸ்க்ரீன்ஷாட்டைச் சேமிக்கும் போது, பிழை ஏற்பட்டது."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன்ஷாட்டைச் சேமிக்க முடியவில்லை."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"பயன்பாடு அல்லது உங்கள் நிறுவனம் ஸ்கிரீன்ஷாட்டுகளை எடுக்க அனுமதிக்கவில்லை."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"(MTP) மீடியா பிளேயராக ஏற்று"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"(PTP) கேமராவாக ஏற்று"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ஐ நிராகரி."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> விலக்கப்பட்டது."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"எல்லா சமீபத்திய பயன்பாடுகளும் விலக்கப்பட்டன."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ஐத் தொடங்குகிறது."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"நேரத்தை அதிகரி."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"நேரத்தைக் குறை."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ஃபிளாஷ்லைட் முடக்கத்தில்."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ஃபிளாஷ்லைட் இல்லை."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ஃபிளாஷ்லைட் இயக்கத்தில்."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ஃபிளாஷ்லைட் முடக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ஃபிளாஷ்லைட் இயக்கப்பட்டது."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"பணிப் பயன்முறை இயக்கப்பட்டுள்ளது."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"பணிப் பயன்முறை முடக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"பணிப் பயன்முறை இயக்கப்பட்டது."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"தரவுச் சேமிப்பான் முடக்கப்பட்டது."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"தரவுச் சேமிப்பான் இயக்கப்பட்டது."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"திரை பிரகாசம்"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G டேட்டா இடைநிறுத்தப்பட்டது"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS அமைத்த இருப்பிடம்"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"இருப்பிடக் கோரிக்கைகள் இயக்கப்பட்டன"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"எல்லா அறிவிப்புகளையும் அழி."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"அறிவிப்பு அமைப்புகள்"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> அமைப்புகள்"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"திரை தானாகச் சுழலும்."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> வரம்பு"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"பணிப் பயன்முறை"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"சமீபத்திய திரைகள் இங்கு தோன்றும்"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"சமீபத்திய பணிகள் இல்லை"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"எல்லாவற்றையும் அழித்துவிட்டீர்கள்"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"பயன்பாட்டு தகவல்"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"திரையை பின் செய்தல்"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"தேடு"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ஐத் தொடங்க முடியவில்லை."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"வரலாறு"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"அழி"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"பாதுகாப்புப் பயன்முறையில் <xliff:g id="APP">%s</xliff:g> முடக்கப்பட்டது."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"அனைத்தையும் அழி"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"இந்தப் பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்கவில்லை"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்காது"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"தனிவிருப்பத்தில் பிரி"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"அறிவிப்புகள்\nவேண்டாம்"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"முன்னுரிமைகள்\nமட்டும்"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"அலாரங்கள்\nமட்டும்"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"எல்லாம்"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"எல்லாம்\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"வேகமாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"மெதுவாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
     <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"மேலே ஸ்வைப் செய்வதன் மூலம் திரைப் பிரிப்பை இயக்கு"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"மேலே ஸ்வைப் செய்வதன் மூலம் திரையைப் பிரிக்கும் சைகையை இயக்கு"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"மேலோட்டப் பார்வை பொத்தானிலிருந்து மேலே ஸ்வைப் செய்வதன் மூலம், திரைப் பிரிப்பைச் செயலாக்குவதற்கான சைகையை இயக்கும்"</string>
     <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"புளூடூத்தை இயக்கவா?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"உங்கள் டேப்லெட்டுடன் விசைப்பலகையை இணைக்க, முதலில் புளூடூத்தை இயக்க வேண்டும்."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"இயக்கு"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> அறிவிப்புகளுக்குப் பயன்படுத்து"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"இந்தப் பயன்பாட்டிலிருந்து வரும் எல்லா அறிவிப்புகளுக்கும் பயன்படுத்து"</string>
+    <string name="show_silently" msgid="6841966539811264192">"ஒலியின்றி அறிவிப்புகளைக் காட்டு"</string>
+    <string name="block" msgid="2734508760962682611">"எல்லா அறிவிப்புகளையும் தடு"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ஒலியை அனுமதி"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ஒலி அல்லது அறிவிப்பைத் தடுக்காதே"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"முக்கியத்துவ அமைப்புகள் முழுவதையும் காட்டு"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"தடுக்கப்பட்டது"</string>
+    <string name="min_importance" msgid="1901894910809414782">"குறைந்தபட்ச முக்கியத்துவம்"</string>
     <string name="low_importance" msgid="4109929986107147930">"முக்கியத்துவம் (குறைவு)"</string>
     <string name="default_importance" msgid="8192107689995742653">"முக்கியத்துவம் (இயல்பு)"</string>
     <string name="high_importance" msgid="1527066195614050263">"முக்கியத்துவம் (அதிகம்)"</string>
     <string name="max_importance" msgid="5089005872719563894">"முக்கியத்துவம் (அவசரம்)"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"இந்த அறிவிப்புகளை ஒருபோதும் காட்டாதே"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டு"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டு"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"அறிவிப்புகள் பட்டியலின் மேல் பகுதியில் ஒலியுடன் காட்டு"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"ஒலியுடன் திரையில் காட்டு"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டு"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டு"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"இந்த அறிவிப்புகளுக்கு ஒலியை அனுமதி"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"சில வினாடிகளுக்கு ஒலியுடன் திரையில் காட்டு"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"அறிவிப்புகள் பட்டியலின் மேற்பகுதியில், சில வினாடிகளுக்கு ஒலியுடன் திரையில் காட்டு"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
     <string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"இயல்பான வண்ணங்கள்"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"இரவுநேர வண்ணங்கள்"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"தனிப்பயன் வண்ணங்கள்"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"தானியங்கு"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"அறியப்படாத வண்ணங்கள்"</string>
-    <string name="color_transform" msgid="6985460408079086090">"வண்ண மாற்றம்"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"விரைவு அமைப்புகள் டைலைக் காட்டு"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"தனிப்பயன் வண்ண மாற்றத்தை இயக்கு"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> அறிவிப்புக் கட்டுப்பாடுகள்"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"வண்ணமும் தோற்றமும்"</string>
+    <string name="night_mode" msgid="3540405868248625488">"இரவுப் பயன்முறை"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"திரையை அளவுத்திருத்தம் செய்"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"இயக்கத்தில்"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"முடக்கத்தில்"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"தானாகவே இயக்கு"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"இருப்பிடம் மற்றும் நேரத்தின்படி இரவுப் பயன்முறைக்கு மாற்று"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"இரவுப் பயன்முறை இயக்கப்பட்டிருக்கும் போது"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OSக்காக அடர் தீமினைப் பயன்படுத்து"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"டிண்ட்டைச் சரிசெய்"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ஒளிர்வைச் சரிசெய்"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"வழக்கமாக வெளிர் தீமில் காட்டப்படுகிற Android OS இன் முக்கிய பகுதிகளில் (எ.கா. அமைப்புகள்) அடர் தீம் பயன்படுத்தப்படுகிறது."</string>
     <string name="color_apply" msgid="9212602012641034283">"பயன்படுத்து"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"அமைப்புகளை உறுதிப்படுத்து"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"சில வண்ண அமைப்புகள் இந்தச் சாதனத்தைப் பயன்படுத்த முடியாதபடி செய்யலாம். இந்த வண்ண அமைப்புகளை உறுதிப்படுத்த, சரி என்பதைக் கிளிக் செய்யவும், இல்லையெனில் இந்த அமைப்புகள் 10 வினாடிகளுக்குப் பின் மீட்டமைக்கப்படும்."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"பேட்டரி உபயோகம்"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"சார்ஜ் செய்யும் போது பேட்டரி சேமிப்பானைப் பயன்படுத்த முடியாது"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"பேட்டரி சேமிப்பான்"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"செயல்திறனையும் பின்புலத்தில் தரவு செயலாக்கப்படுவதையும் குறைக்கும்"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> பொத்தான்"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"ஹோம்"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"பேக்"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"மேலே"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"கீழே"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"இடது"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"வலது"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"நடு"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"டேப்"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"ஸ்பேஸ்"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"என்டர்"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"பேக்ஸ்பேஸ்"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"பிளே/பாஸ்"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ஸ்டாப்"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"நெக்ஸ்ட்"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ப்ரீவியஸ்"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ரீவைன்ட்"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ஃபாஸ்ட் பார்வேர்டு"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"பேஜ் அப்"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"பேஜ் டவுன்"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"டெலிட்"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"ஹோம்"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"என்ட்"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"இன்சர்ட்"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"நம்பர் லாக்"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"நம்பர் பேடு <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"முறைமை"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"முகப்பு"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"சமீபத்தியவை"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"முந்தையது"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"ஒலி உரையாடலில் தொந்தரவு செய்ய வேண்டாம் என்பதைக் காட்டு"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ஒலி உரையாடலில் தொந்தரவு செய்ய வேண்டாம் என்பதன் முழுக் கட்டுப்பாட்டையும் அனுமதி."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ஒலி மற்றும் தொந்தரவு செய்ய வேண்டாம்"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"ஒலியைக் குறைக்கும்போது தொந்தரவு செய்ய வேண்டாம் என்பதை இயக்கு"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"அறிவிப்புகள்"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"விசைப்பலகைக் குறுக்குவழிகள்"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"உள்ளீட்டு முறையை மாற்று"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"பயன்பாடுகள்"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"அசிஸ்ட்"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"உலாவி"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"தொடர்புகள்"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"மின்னஞ்சல்"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"மியூசிக்"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"கேலெண்டர்"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"ஒலிக் கட்டுப்பாடுகளுடன் காட்டு"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"தொந்தரவு செய்ய வேண்டாம்"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ஒலியளவுப் பொத்தான்களுக்கான குறுக்குவழி"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ஒலியைக் கூட்டும் போது தொந்தரவு செய்ய வேண்டாம் என்பதை முடக்கு"</string>
     <string name="battery" msgid="7498329822413202973">"பேட்டரி"</string>
     <string name="clock" msgid="7416090374234785905">"கடிகாரம்"</string>
     <string name="headset" msgid="4534219457597457353">"ஹெட்செட்"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ஹெட்ஃபோன்கள் இணைக்கப்பட்டன"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ஹெட்செட் இணைக்கப்பட்டது"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"நிலைப் பட்டியில் ஐகான்களைக் காட்டுவதை இயக்கும் அல்லது முடக்கும்."</string>
     <string name="data_saver" msgid="5037565123367048522">"தரவுச்சேமிப்பான்"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"தரவு சேமிப்பான் இயக்கப்பட்டது"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"தரவு சேமிப்பான் முடக்கப்பட்டது"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"இயக்கு"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"முடக்கு"</string>
     <string name="nav_bar" msgid="1993221402773877607">"வழிசெலுத்தல் பட்டி"</string>
     <string name="start" msgid="6873794757232879664">"தொடங்கு"</string>
     <string name="center" msgid="4327473927066010960">"மையம்"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"விசைப்பலகைப் பொத்தானைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="preview" msgid="9077832302472282938">"மாதிரிக்காட்சி"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"கட்டங்களைச் சேர்க்க, இழுக்கவும்"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"அகற்ற, இங்கே இழுக்கவும்"</string>
     <string name="qs_edit" msgid="2232596095725105230">"மாற்று"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"நேரம்"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"மணிநேரம், நிமிடங்கள், வினாடிகளைக் காட்டு"</item>
+    <item msgid="1427801730816895300">"மணிநேரம், நிமிடங்களைக் காட்டு (இயல்பு)"</item>
+    <item msgid="3830170141562534721">"இந்த ஐகானைக் காட்டாதே"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"எப்போதும் சதவீதத்தைக் காட்டு"</item>
+    <item msgid="2139628951880142927">"சார்ஜ் செய்யும் போது சதவீதத்தைக் காட்டு (இயல்பு)"</item>
+    <item msgid="3327323682209964956">"இந்த ஐகானைக் காட்டாதே"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"மற்றவை"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"திரையைப் பிரிக்கும் பிரிப்பான்"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"கீழே நகர்த்து"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"மேலே நகர்த்து"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"இடப்புறம் நகர்த்து"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"வலப்புறம் நகர்த்து"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"பல சாளர அம்சத்தில் பயன்பாடு வேலைசெய்யாமல் போகக்கூடும்"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"நிலை <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. திருத்த, இருமுறை தட்டவும்."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. சேர்க்க, இருமுறை தட்டவும்."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"நிலை <xliff:g id="POSITION">%1$d</xliff:g>. தேர்ந்தெடுக்க, இருமுறை தட்டவும்."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ஐ நகர்த்தவும்"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ஐ அகற்றவும்"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> நிலை <xliff:g id="POSITION">%2$d</xliff:g> இல் சேர்க்கப்பட்டது"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> அகற்றப்பட்டது"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> நிலை <xliff:g id="POSITION">%2$d</xliff:g>க்கு நகர்த்தப்பட்டது"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"விரைவு அமைப்புகள் திருத்தி."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings_tv.xml b/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
new file mode 100644
index 0000000..7412e27
--- /dev/null
+++ b/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIPஐ மூடு"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"முழுத்திரை"</string>
+    <string name="pip_play" msgid="674145557658227044">"இயக்கு"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"இடைநிறுத்து"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIPஐக் கட்டுப்படுத்த, "<b>"முகப்பைப்"</b>" பிடித்திருக்கவும்"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIPஐக் கட்டுப்படுத்த, முகப்புப் பொத்தானை அழுத்திப் பிடிக்கவும்"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"சரி"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"நிராகரி"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 4f702b6..3a72809 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"పరిమిత నిల్వ స్థలం కారణంగా స్క్రీన్‌షాట్‌‌ను తీయడం సాధ్యపడదు లేదా దీన్ని మీ అనువర్తనం లేదా మీ సంస్థ అనుమతించలేదు."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"స్క్రీన్‌షాట్‌ని సేవ్ చేస్తున్నప్పుడు సమస్య సంభవించింది."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"పరిమిత నిల్వ స్థలం కారణంగా స్క్రీన్‌షాట్‌ను సేవ్ చేయడం సాధ్యపడదు."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"స్క్రీన్‌షాట్‌లు తీయడానికి అనువర్తనం లేదా మీ సంస్థ అనుమతించలేదు."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ఫైల్ బదిలీ ఎంపికలు"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"మీడియా ప్లేయర్‌గా (MTP) మౌంట్ చేయి"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"కెమెరాగా (PTP) మౌంట్ చేయి"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ని తీసివేయండి."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> తీసివేయబడింది."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"అన్ని ఇటీవలి అనువర్తనాలు తీసివేయబడ్డాయి."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభిస్తోంది."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"నోటిఫికేషన్ తీసివేయబడింది."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ఎక్కువ సమయం."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"తక్కువ సమయం."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ఫ్లాష్‌లైట్ ఆఫ్‌లో ఉంది."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ఫ్లాష్‌లైట్ అందుబాటులో లేదు."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ఫ్లాష్‌లైట్ ఆన్‌లో ఉంది."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ఫ్లాష్‌లైట్ ఆఫ్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ఫ్లాష్‌లైట్ ఆన్ చేయబడింది."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"పని మోడ్ ఆన్‌లో ఉంది."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"పని మోడ్ ఆఫ్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"పని మోడ్ ఆన్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"డేటా సేవర్ ఆఫ్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"డేటా సేవర్ ఆన్ చేయబడింది."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ప్రదర్శన ప్రకాశం"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G డేటా పాజ్ చేయబడింది"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"స్థానం GPS ద్వారా సెట్ చేయబడింది"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"స్థాన అభ్యర్థనలు సక్రియంగా ఉన్నాయి"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"అన్ని నోటిఫికేషన్‌లను క్లియర్ చేయండి."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"నోటిఫికేషన్ సెట్టింగ్‌లు"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> సెట్టింగ్‌లు"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"స్క్రీన్ స్వయంచాలకంగా తిప్పబడుతుంది."</string>
@@ -296,14 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> పరిమితి"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"పని మోడ్"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"మీ ఇటీవలి స్క్రీన్‌లు ఇక్కడ కనిపిస్తాయి"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"మీరు అన్నింటినీ తీసివేసారు"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"అనువర్తన సమాచారం"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"స్క్రీన్ పిన్నింగ్"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"శోధించు"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభించడం సాధ్యపడలేదు."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> సురక్షిత-మోడ్‌లో నిలిపివేయబడింది."</string>
-    <string name="recents_history_button_label" msgid="5153358867807604821">"చరిత్ర"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"తీసివేయి"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"అన్నీ తీసివేయి"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ఈ అనువర్తనం బహుళ విండోలకు మద్దతు ఇవ్వదు"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"అనువర్తనం బహుళ విండోలకు మద్దతు ఇవ్వదు"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"లంబంగా విభజించు"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"అనుకూలంగా విభజించు"</string>
@@ -333,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"మొత్తం\nనిశ్శబ్దం"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ప్రాధాన్యమైనవి\nమాత్రమే"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"అలారాలు\nమాత్రమే"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"అన్నిటికీ"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"అన్నీ\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"వేగంగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"నెమ్మదిగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -447,34 +455,44 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
     <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజన యాక్సిలరేటర్‌ను ప్రారంభించు"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజన సంజ్ఞను ప్రారంభించు"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"స్థూలదృష్టి బటన్ నుండి పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజనలోకి ప్రవేశించడానికి సంజ్ఞను ప్రారంభిస్తుంది"</string>
     <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"బ్లూటూత్ ఆన్ చేయాలా?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"మీ కీబోర్డ్‌ను మీ టాబ్లెట్‌తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ఆన్ చేయి"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> నోటిఫికేషన్‌లకు వర్తింపజేయి"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"ఈ అనువర్తనం నుండి అందించబడే అన్ని నోటిఫికేషన్‌లకు వర్తింపజేయి"</string>
+    <string name="show_silently" msgid="6841966539811264192">"నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపు"</string>
+    <string name="block" msgid="2734508760962682611">"అన్ని నోటిఫికేషన్‌లను బ్లాక్ చేయి"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"నిశ్శబ్దం చేయవద్దు"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"నిశ్శబ్దం చేయవద్దు లేదా బ్లాక్ చేయవద్దు"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"పూర్తి ప్రాముఖ్యత సెట్టింగ్‌లను చూపండి"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"బ్లాక్ చేయబడింది"</string>
+    <string name="min_importance" msgid="1901894910809414782">"కని. ప్రాముఖ్యత"</string>
     <string name="low_importance" msgid="4109929986107147930">"తక్కువ ప్రాముఖ్యత"</string>
     <string name="default_importance" msgid="8192107689995742653">"సాధారణ ప్రాముఖ్యత"</string>
     <string name="high_importance" msgid="1527066195614050263">"అధిక ప్రాముఖ్యత"</string>
     <string name="max_importance" msgid="5089005872719563894">"అత్యవసర ప్రాముఖ్యత"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ఈ నోటిఫికేషన్‌లను ఎప్పుడూ చూపదు"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"నోటిఫికేషన్‌ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"ఈ నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపుతుంది"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"నోటిఫికేషన్‌ల జాబితా ఎగువ భాగంలో శబ్దంతో చూపుతుంది"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"నోటిఫికేషన్‌ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ఈ నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపుతుంది"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ఈ నోటిఫికేషన్‌లను శబ్దంతో చూపేలా అనుమతిస్తుంది"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"నోటిఫికేషన్‌ల జాబితా అగ్ర భాగాన, స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"మరిన్ని సెట్టింగ్‌లు"</string>
     <string name="notification_done" msgid="5279426047273930175">"పూర్తయింది"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"సాధారణ రంగులు"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"రాత్రి రంగులు"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"అనుకూల రంగులు"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"స్వయంచాలకం"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"తెలియని రంగులు"</string>
-    <string name="color_transform" msgid="6985460408079086090">"రంగు సవరణ"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"శీఘ్ర సెట్టింగ్‌ల టైల్‌ను చూపండి"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"అనుకూల పరివర్తనను ప్రారంభించండి"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> నోటిఫికేషన్ నియంత్రణలు"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"రంగు మరియు కనిపించే తీరు"</string>
+    <string name="night_mode" msgid="3540405868248625488">"రాత్రి మోడ్"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"డిస్‌ప్లేని క్రమాంకనం చేయండి"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"ఆన్‌లో ఉంది"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ఆఫ్‌లో ఉంది"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"స్వయంచాలకంగా ఆన్ చేయి"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"స్థానం మరియు రోజులో సమయానికి తగినట్లుగా రాత్రి మోడ్‌కి మారుస్తుంది"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"రాత్రి మోడ్ ఆన్‌లో ఉన్నప్పుడు"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS కోసం ముదురు రంగు థీమ్ ఉపయోగించండి"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"లేత రంగును సర్దుబాటు చేయండి"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ప్రకాశాన్ని సర్దుబాటు చేయండి"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"సాధారణంగా లేత రంగు థీమ్‌లో ప్రదర్శించబడే సెట్టింగ్‌ల వంటి Android OS ప్రధాన అంశాలకు ముదురు రంగు థీమ్ వర్తింపజేయబడుతుంది."</string>
     <string name="color_apply" msgid="9212602012641034283">"వర్తింపజేయి"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"సెట్టింగ్‌లను నిర్ధారించండి"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"కొన్ని రంగు సెట్టింగ్‌ల వలన ఈ పరికరం ఉపయోగించలేని విధంగా అయిపోవచ్చు. ఈ రంగు సెట్టింగ్‌లను నిర్ధారించడానికి సరే క్లిక్ చేయండి లేదంటే ఈ సెట్టింగ్‌లు 10 సెకన్ల తర్వాత రీసెట్ చేయబడతాయి."</string>
@@ -482,25 +500,62 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ఛార్జ్ అవుతున్న సమయంలో బ్యాటరీ సేవర్ అందుబాటులో ఉండదు"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"బ్యాటరీ సేవర్"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"బటన్ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"వెనుకకు"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"పైకి"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"కిందికి"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ఎడమ"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"కుడి"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"మధ్య"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"అంతరం"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ప్లే చేయి/పాజ్ చేయి"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ఆపివేయి"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"తదుపరి"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"మునుపటి"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"రివైండ్ చేయి"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"వేగంగా ఫార్వార్డ్ చేయి"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"నంబర్ ప్యాడ్ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"సిస్టమ్"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"హోమ్"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ఇటీవలివి"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"వెనుకకు"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"వాల్యూమ్‌లో అంతరాయం కలిగించవద్దు ప్యానెల్‌ను చూపు"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"వాల్యూమ్‌ డైలాగ్‌లో అంతరాయం కలిగించవద్దు ప్యానెల్ పూర్తి నియంత్రణను అనుమతిస్తుంది."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"వాల్యూమ్ మరియు అంతరాయం కలిగించవద్దు"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"వాల్యూమ్ తగ్గిస్తే అంతరాయం కలిగించవద్దులోకి ప్రవేశిస్తుంది"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"నోటిఫికేషన్‌లు"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"కీబోర్డ్ సత్వరమార్గాలు"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ఇన్‌పుట్ పద్ధతిని మార్చండి"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"అనువర్తనాలు"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"సహాయకం"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"బ్రౌజర్"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"పరిచయాలు"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ఇమెయిల్"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"సంగీతం"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"క్యాలెండర్"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"వాల్యూమ్ నియంత్రణలతో చూపు"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"అంతరాయం కలిగించవద్దు"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"వాల్యూమ్ బటన్‌ల సత్వరమార్గం"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"వాల్యూమ్ పెంచితే అంతరాయం కలిగించవద్దు నుండి నిష్క్రమిస్తుంది"</string>
     <string name="battery" msgid="7498329822413202973">"బ్యాటరీ"</string>
     <string name="clock" msgid="7416090374234785905">"గడియారం"</string>
     <string name="headset" msgid="4534219457597457353">"హెడ్‌సెట్"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"హెడ్‌ఫోన్‌లు కనెక్ట్ చేయబడ్డాయి"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"హెడ్‌సెట్ కనెక్ట్ చేయబడింది"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"స్థితి పట్టీలో చిహ్నాలు ప్రదర్శించడాన్ని ప్రారంభించండి లేదా నిలిపివేయండి."</string>
     <string name="data_saver" msgid="5037565123367048522">"డేటా సేవర్"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"డేటా సేవర్ ఆన్‌లో ఉంది"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"డేటా సేవర్ ఆఫ్‌లో ఉంది"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"ఆన్"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ఆఫ్ చేయి"</string>
     <string name="nav_bar" msgid="1993221402773877607">"నావిగేషన్ బార్"</string>
     <string name="start" msgid="6873794757232879664">"ప్రారంభం"</string>
     <string name="center" msgid="4327473927066010960">"మధ్య"</string>
@@ -522,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"కీబోర్డ్ బటన్‌ను ఎంచుకోండి"</string>
     <string name="preview" msgid="9077832302472282938">"పరిదృశ్యం"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"టైల్‌లను జోడించడానికి లాగండి"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"తీసివేయడానికి ఇక్కడికి లాగండి"</string>
     <string name="qs_edit" msgid="2232596095725105230">"సవరించు"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"సమయం"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"గంటలు, నిమిషాలు మరియు సెకన్లను చూపు"</item>
+    <item msgid="1427801730816895300">"గంటలు మరియు నిమిషాలను చూపు (డిఫాల్ట్)"</item>
+    <item msgid="3830170141562534721">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"ఎల్లప్పుడూ శాతాన్ని చూపు"</item>
+    <item msgid="2139628951880142927">"ఛార్జ్ అవుతున్నప్పుడు శాతాన్ని చూపు (డిఫాల్ట్)"</item>
+    <item msgid="3327323682209964956">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"ఇతరం"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"విభజన స్క్రీన్ విభాగిని"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"క్రిందికి తరలించు"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"పైకి తరలించు"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ఎడమవైపుకు తరలించు"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"కుడివైపుకు తరలించు"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"అనువర్తనం బహుళ విండోల రూపంలో పని చేయకపోవచ్చు"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. సవరించడానికి రెండుసార్లు నొక్కండి."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. జోడించడానికి రెండుసార్లు నొక్కండి."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>. ఎంచుకోవడానికి రెండుసార్లు నొక్కండి."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తరలిస్తుంది"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తీసివేస్తుంది"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>వ స్థానానికి జోడించబడింది"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> తీసివేయబడింది"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>వ స్థానానికి తరలించబడింది"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"శీఘ్ర సెట్టింగ్‌ల ఎడిటర్."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings_tv.xml b/packages/SystemUI/res/values-te-rIN/strings_tv.xml
new file mode 100644
index 0000000..32820c3
--- /dev/null
+++ b/packages/SystemUI/res/values-te-rIN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIPని మూసివేయి"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"పూర్తి స్క్రీన్"</string>
+    <string name="pip_play" msgid="674145557658227044">"ప్లే చేయి"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"పాజ్ చేయి"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP నియం. "<b>"HOME"</b>"నొక్కిఉంచండి"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIPని నియంత్రించడానికి హోమ్ బటన్‌ను నొక్కి పట్టుకోండి"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"అర్థమైంది"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"తీసివేస్తుంది"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index bc7e26f..4844c84 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"ไม่สามารถจับภาพหน้าจอได้ เนื่องจากพื้นที่ว่างมีจำกัด หรือไม่ได้รับอนุญาตจากแอปหรือองค์กรของคุณ"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"พบปัญหาขณะกำลังบันทึกภาพหน้าจอ"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ไม่สามารถบันทึกภาพหน้าจอเนื่องจากพื้นที่เก็บข้อมูลมีจำกัด"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"แอปหรือองค์กรของคุณไม่อนุญาตให้จับภาพหน้าจอ"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"ตัวเลือกการถ่ายโอนไฟล์ USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ต่อเชื่อมเป็นโปรแกรมเล่นสื่อ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ต่อเชื่อมเป็นกล้องถ่ายรูป (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ยกเลิก <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ถูกลบไปแล้ว"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ปิดแอปพลิเคชันล่าสุดทั้งหมดแล้ว"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"กำลังเริ่มต้น <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ปิดการแจ้งเตือนแล้ว"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"เวลามากขึ้น"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"เวลาน้อยลง"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ไฟฉายปิดอยู่"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ไฟฉายไม่พร้อมใช้งาน"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ไฟฉายเปิดอยู่"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ปิดไฟฉายแล้ว"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"เปิดไฟฉายแล้ว"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"โหมดการทำงานเปิดอยู่"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ปิดโหมดการทำงานแล้ว"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"เปิดโหมดการทำงานแล้ว"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ปิดโปรแกรมประหยัดอินเทอร์เน็ตแล้ว"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"เปิดโปรแกรมประหยัดอินเทอร์เน็ตแล้ว"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ความสว่างของหน้าจอ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"หยุดการใช้ข้อมูล 2G-3G ชั่วคราวแล้ว"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"ตำแหน่งที่กำหนดโดย GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"คำขอตำแหน่งที่มีการใช้งาน"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ล้างการแจ้งเตือนทั้งหมด"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"การตั้งค่าการแจ้งเตือน"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"การตั้งค่า <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"หน้าจอจะหมุนโดยอัตโนมัติ"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ขีดจำกัด <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"คำเตือน <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"โหมดการทำงาน"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"หน้าจอล่าสุดของคุณแสดงที่นี่"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"ไม่มีรายการล่าสุด"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"คุณได้ล้างทุกอย่างแล้ว"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"การตรึงหน้าจอ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"ไม่สามารถเริ่มใช้ <xliff:g id="APP">%s</xliff:g>"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"ประวัติ"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ล้าง"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ปิดใช้ในโหมดปลอดภัย"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ล้างทั้งหมด"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"แอปนี้ไม่สนับสนุนหลายหน้าต่าง"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"แอปไม่สนับสนุนหลายหน้าต่าง"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"แยกในแนวนอน"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"แยกในแนวตั้ง"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"แยกแบบกำหนดเอง"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"ปิดเสียง\nทั้งหมด"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"เฉพาะเรื่อง\nสำคัญ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"เฉพาะปลุก\nเท่านั้น"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"ทั้งหมด"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ทั้งหมด\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"กำลังชาร์จอย่างรวดเร็ว (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"กำลังชาร์จอย่างช้าๆ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
     <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"เปิดใช้ตัวเร่งการเลื่อนขึ้นเพื่อแยกหน้าจอ"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"เปิดใช้ท่าทางสัมผัสการเลื่อนขึ้นเพื่อแยกหน้าจอ"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยเลื่อนขึ้นจากปุ่มภาพรวม"</string>
     <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"เปิด"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"นำไปใช้กับการแจ้งเตือน <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"นำไปใช้กับการแจ้งเตือนทั้งหมดจากแอปนี้"</string>
+    <string name="show_silently" msgid="6841966539811264192">"แสดงการแจ้งเตือนโดยไม่ส่งเสียง"</string>
+    <string name="block" msgid="2734508760962682611">"บล็อกการแจ้งเตือนทั้งหมด"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ไม่ปิดเสียง"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ไม่ปิดเสียงหรือบล็อก"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"แสดงการตั้งค่าความสำคัญแบบเต็ม"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"บล็อกแล้ว"</string>
+    <string name="min_importance" msgid="1901894910809414782">"ความสำคัญน้อย"</string>
     <string name="low_importance" msgid="4109929986107147930">"ความสำคัญต่ำ"</string>
     <string name="default_importance" msgid="8192107689995742653">"ความสำคัญปกติ"</string>
     <string name="high_importance" msgid="1527066195614050263">"ความสำคัญสูง"</string>
     <string name="max_importance" msgid="5089005872719563894">"ความสำคัญเร่งด่วน"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ไม่ต้องแสดงการแจ้งเตือนเหล่านี้"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"แสดงที่ด้านบนของรายการแจ้งเตือนและส่งเสียง"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"แสดงบนหน้าจอในช่วงเวลาสั้นๆ และส่งเสียง"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ให้การแจ้งเตือนเหล่านี้ส่งเสียงได้"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"แสดงบนหน้าจอและให้ส่งเสียงได้"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"แสดงที่ด้านบนของรายการการแจ้งเตือน แสดงบนหน้าจอและให้ส่งเสียงได้"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
     <string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"สีปกติ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"สียามค่ำคืน"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"สีที่กำหนดเอง"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"อัตโนมัติ"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"สีที่ไม่รู้จัก"</string>
-    <string name="color_transform" msgid="6985460408079086090">"การปรับเปลี่ยนสี"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"แสดงไทล์การตั้งค่าด่วน"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"เปิดใช้การเปลี่ยนที่กำหนดเอง"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"ส่วนควบคุมการแจ้งเตือนของ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"สีและลักษณะที่ปรากฏ"</string>
+    <string name="night_mode" msgid="3540405868248625488">"โหมดกลางคืน"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"ปรับเทียบการแสดงผล"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"เปิด"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"ปิด"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"เปิดอัตโนมัติ"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"เปลี่ยนเป็นโหมดกลางคืนตามความเหมาะสมกับสถานที่และเวลาของวัน"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"เมื่อเปิดโหมดกลางคืน"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"ใช้ธีมสีเข้มสำหรับ Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ปรับการแต้มสี"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"ปรับความสว่าง"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"ใช้ธีมสีเข้มในบริเวณสำคัญของระบบปฏิบัติการ Android ซึ่งปกติแล้วจะแสดงด้วยธีมสีอ่อน เช่น การตั้งค่า"</string>
     <string name="color_apply" msgid="9212602012641034283">"ใช้"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ยืนยันการตั้งค่า"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"การตั้งค่าสีบางอย่างอาจทำให้อุปกรณ์นี้ใช้งานไม่ได้ คลิกตกลงเพื่อยืนยันการตั้งค่าสีเหล่านี้ มิฉะนั้นระบบจะรีเซ็ตการตั้งค่าหลังจาก 10 วินาที"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"การใช้งานแบตเตอรี่"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ไม่สามารถใช้โหมดประหยัดแบตเตอรี่ระหว่างการชาร์จ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"โหมดประหยัดแบตเตอรี่"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ลดประสิทธิภาพการทำงานและข้อมูลแบ็กกราวด์"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"ปุ่ม <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"กลับ"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ขึ้น"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ลง"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ซ้าย"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ขวา"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"กึ่งกลาง"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"แท็บ"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"วรรค"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"ลบถอยหลัง"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"เล่น/หยุดชั่วคราว"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"หยุด"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"ถัดไป"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ก่อนหน้า"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"กรอกลับ"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"กรอไปข้างหน้า"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"เลื่อนหน้าขึ้น"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"เลื่อนหน้าลง"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ลบ"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"แทรก"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"แผงตัวเลข <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ระบบ"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"หน้าแรก"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ล่าสุด"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"กลับ"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"แสดงโหมดห้ามรบกวนในระดับเสียง"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"อนุญาตให้ควบคุมโหมดห้ามรบกวนได้อย่างสมบูรณ์ในกล่องโต้ตอบระดับเสียง"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ระดับเสียงและโหมดห้ามรบกวน"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"เข้าสู่โหมดห้ามรบกวนเมื่อลดระดับเสียง"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"การแจ้งเตือน"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"แป้นพิมพ์ลัด"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"สลับวิธีการป้อนข้อมูล"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"แอปพลิเคชัน"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"การสนับสนุน"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"เบราว์เซอร์"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"รายชื่อติดต่อ"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"อีเมล"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"เพลง"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ปฏิทิน"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"แสดงพร้อมการควบคุมระดับเสียง"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ห้ามรบกวน"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"ทางลัดปุ่มปรับระดับเสียง"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"ออกจากโหมดห้ามรบกวนเมื่อเพิ่มระดับเสียง"</string>
     <string name="battery" msgid="7498329822413202973">"แบตเตอรี่"</string>
     <string name="clock" msgid="7416090374234785905">"นาฬิกา"</string>
     <string name="headset" msgid="4534219457597457353">"ชุดหูฟัง"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"เชื่อมต่อหูฟังแล้ว"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"เชื่อมต่อชุดหูฟังแล้ว"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"เปิดหรือปิดไอคอนจากการแสดงในแถบสถานะ"</string>
     <string name="data_saver" msgid="5037565123367048522">"โปรแกรมประหยัดอินเทอร์เน็ต"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"โปรแกรมประหยัดอินเทอร์เน็ตเปิดอยู่"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"โปรแกรมประหยัดอินเทอร์เน็ตปิดอยู่"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"เปิด"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"ปิด"</string>
     <string name="nav_bar" msgid="1993221402773877607">"แถบนำทาง"</string>
     <string name="start" msgid="6873794757232879664">"บนสุด"</string>
     <string name="center" msgid="4327473927066010960">"กึ่งกลาง"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"เลือกปุ่มแป้นพิมพ์"</string>
     <string name="preview" msgid="9077832302472282938">"ดูตัวอย่าง"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ลากเพื่อเพิ่มชิ้นส่วน"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ลากมาที่นี่เพื่อนำออก"</string>
     <string name="qs_edit" msgid="2232596095725105230">"แก้ไข"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"เวลา"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"แสดงชั่วโมง นาที และวินาที"</item>
+    <item msgid="1427801730816895300">"แสดงชั่วโมงและนาที (ค่าเริ่มต้น)"</item>
+    <item msgid="3830170141562534721">"อย่าแสดงไอคอนนี้"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"แสดงเปอร์เซ็นต์เสมอ"</item>
+    <item msgid="2139628951880142927">"แสดงเปอร์เซ็นต์เมื่อชาร์จ (ค่าเริ่มต้น)"</item>
+    <item msgid="3327323682209964956">"อย่าแสดงไอคอนนี้"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"อื่นๆ"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"เส้นแบ่งหน้าจอ"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"เลื่อนลง"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"เลื่อนขึ้น"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"เลื่อนไปทางซ้าย"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"เลื่อนไปทางขวา"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"แอปอาจทำงานกับหลายหน้าต่างไม่ได้"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g> <xliff:g id="TILE_NAME">%2$s</xliff:g> แตะ 2 ครั้งเพื่อแก้ไข"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> แตะ 2 ครั้งเพื่อเพิ่ม"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g> แตะ 2 ครั้งเพื่อเลือก"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ย้าย <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"นำ <xliff:g id="TILE_NAME">%1$s</xliff:g> ออก"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"เพิ่ม <xliff:g id="TILE_NAME">%1$s</xliff:g> ลงในตำแหน่ง <xliff:g id="POSITION">%2$d</xliff:g> แล้ว"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"นำ <xliff:g id="TILE_NAME">%1$s</xliff:g> ออกแล้ว"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"ย้าย <xliff:g id="TILE_NAME">%1$s</xliff:g> ไปยังตำแหน่ง <xliff:g id="POSITION">%2$d</xliff:g> แล้ว"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ตัวแก้ไขการตั้งค่าด่วน"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
new file mode 100644
index 0000000..d7b26687
--- /dev/null
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"ปิด PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"เต็มหน้าจอ"</string>
+    <string name="pip_play" msgid="674145557658227044">"เล่น"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"หยุดชั่วคราว"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"กด "<b>"HOME"</b>" ค้างไว้เพื่อควบคุม PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"กดปุ่ม HOME ค้างไว้เพื่อควบคุม PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"รับทราบ"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"ปิด"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index ab800d4..0672959 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Nakuha ang screenshot."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Pindutin upang tingnan ang iyong screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Hindi makuha ang screenshot."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Di makapag-screenshot dahil sa limitadong storage space o di ito pinapayagan ng app o organisasyon."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Nagkaroon ng problema habang sine-save ang screenshot."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Hindi ma-save ang screenshot dahil sa limitadong espasyo ng storage."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkuha ng mga screenshot."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opsyon paglipat ng USB file"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"I-mount bilang isang media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"I-mount bilang camera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"I-dismiss ang <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Hindi pinansin ang <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Na-dismiss ang lahat ng kamakailang application."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Sinisimulan ang <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Na-dismiss ang notification."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Higit pang oras."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mas kaunting oras."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Naka-off ang flashlight."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Hindi available ang flashlight."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Naka-on ang flashlight."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Na-off ang flashlight."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Na-on ang flashlight."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Naka-on ang work mode."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Na-off ang work mode."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Na-on ang work mode."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Na-off ang Data Saver."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Na-on ang Data Saver."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Liwanag ng display"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Naka-pause ang 2G-3G data"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasyong itinatakda ng GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktibo ang mga kahilingan ng lokasyon"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"I-clear ang lahat ng notification."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Mga setting ng notification"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Mg setting ng <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Awtomatikong iikot ang screen."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ang limitasyon"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Babala sa <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Lumalabas dito ang iyong mga kamakailang screen"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Walang mga kamakailang item"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Na-clear mo ang lahat"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pagpi-pin sa screen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Hindi masimulan <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"I-clear"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Naka-disable ang <xliff:g id="APP">%s</xliff:g> sa safe-mode."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"I-clear lahat"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Hindi sinusuportahan ng app na ito ang multi-window"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Hindi sinusuportahan ng app na ito ang multi-window"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Custom"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Ganap na\nkatahimikan"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priyoridad\nlang"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Mga alarm\nlang"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Lahat"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Lahat\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mabilis mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mabagal mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"I-enable ang split-screen na swipe-up accelerator"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"I-enable ang pag-swipe pataas na galaw para sa split-screen"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"I-enable ang gesture upang makapasok sa split-screen sa pamamagitan ng pagsa-swipe pataas mula sa button ng Pangkalahatang-ideya"</string>
     <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"I-on"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Naaangkop sa mga notification tungkol sa <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Naaangkop sa lahat ng notification mula sa app na ito"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Tahimik na ipakita ang mga notification"</string>
+    <string name="block" msgid="2734508760962682611">"I-block ang lahat ng notification"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Huwag i-silent"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Huwag i-silent o i-block"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Ipakita ang kumpletong mga setting ng kahalagahan"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Na-block"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Hindi masyadong mahalaga"</string>
     <string name="low_importance" msgid="4109929986107147930">"Hindi masyadong mahalaga"</string>
     <string name="default_importance" msgid="8192107689995742653">"Mahalaga"</string>
     <string name="high_importance" msgid="1527066195614050263">"Napakahalaga"</string>
     <string name="max_importance" msgid="5089005872719563894">"Mahalagang-mahalaga"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Huwag kailanman ipakita ang mga notification na ito"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Tahimik na ipakita sa ibaba ng listahan ng notification"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Tahimik na ipakita ang mga notification na ito"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Ipakita sa itaas ng listahan ng mga notification at mag-play ng tunog"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Ipasilip sa screen at mag-play ng tunog"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tahimik na ipakita sa ibaba ng listahan ng notification"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tahimik na ipakita ang mga notification na ito"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Payagan ang mga notification na ito na tumunog"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Palitawin sa screen at payagang tumunog"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Ipakita sa itaas ng listahan ng mga notification, palitawin sa screen at payagang tumunog"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
     <string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Mga karaniwang kulay"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Madidilim na kulay"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Mga custom na kulay"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Mga hindi kilalang kulay"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Pagbago sa kulay"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ipakita ang tile ng Mga Mabilisang Setting"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"I-enable ang custom na pagpalit"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Mga kontrol sa notification ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Kulay at hitsura"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"I-calibrate ang display"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Naka-on"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Naka-off"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Awtomatikong i-on"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Lumipat sa Night Mode kapag naaangkop sa lokasyon at oras"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Kapag naka-on ang Night Mode"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Gumamit ng madilim na tema para sa Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Isaayos ang tint"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Isaayos ang liwanag"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Ilalapat ang madilim na tema sa mga mahalagang bahagi ng Android OS na karaniwang ipinapakita nang may maliwanag na tema, gaya ng Mga Setting."</string>
     <string name="color_apply" msgid="9212602012641034283">"Ilapat"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Kumpirmahin ang mga setting"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Maaaring hindi magamit ang device na ito dahil sa ilang setting ng kulay. I-click ang OK upang kumpirmahin ang mga setting ng kulay na ito, kung hindi ay mare-reset ang mga setting na ito pagkatapos ng 10 segundo."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Paggamit ng baterya"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Hindi available ang Pangtipid sa Baterya kapag nagcha-charge"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Pangtipid sa Baterya"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Binabawasan ang pagganap at data sa background"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button na <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Mga Kamakailang Ginamit"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Bumalik"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ipakita ang huwag istorbohin sa volume"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Payagang ganap na makontrol ang huwag istorbohin sa dialog ng volume."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume at Huwag istorbohin"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Gamitin ang huwag istorbohin nang mahina ang volume"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Mga Notification"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Mga Keyboard Shortcut"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Magpalit ng pamamaraan ng pag-input"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Mga Application"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Tulong"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Mga Contact"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendaryo"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ipakita nang may mga kontrol ng volume"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Huwag istorbohin"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Shortcut ng mga button ng volume"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Umalis sa huwag istorbohin nang malakas ang volume"</string>
     <string name="battery" msgid="7498329822413202973">"Baterya"</string>
     <string name="clock" msgid="7416090374234785905">"Orasan"</string>
     <string name="headset" msgid="4534219457597457353">"Headset"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Nakakonekta ang mga headphone"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Nakakonekta ang headset"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"I-enable o i-disable ang pagpapakita sa mga icon sa status bar."</string>
     <string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Naka-on ang Data Saver"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Naka-off ang Data Saver"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"I-on"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"I-off"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigation bar"</string>
     <string name="start" msgid="6873794757232879664">"Simula"</string>
     <string name="center" msgid="4327473927066010960">"Gitna"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Pumili ng Button na Keyboard"</string>
     <string name="preview" msgid="9077832302472282938">"I-preview"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Mag-drag upang magdagdag ng mga tile"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"I-drag dito upang alisin"</string>
     <string name="qs_edit" msgid="2232596095725105230">"I-edit"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Oras"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Ipakita ang oras, minuto at segundo"</item>
+    <item msgid="1427801730816895300">"Ipakita ang oras at minuto (default)"</item>
+    <item msgid="3830170141562534721">"Huwag ipakita ang icon na ito"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Palaging ipakita ang porsyento"</item>
+    <item msgid="2139628951880142927">"Ipakita ang porsyento kapag nagcha-charge (default)"</item>
+    <item msgid="3327323682209964956">"Huwag ipakita ang icon na ito"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Iba pa"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Divider ng split-screen"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Ilipat pababa"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Ilipat pataas"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Ilipat pakaliwa"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Ilipat pakanan"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Maaaring hindi gumana ang app sa maraming window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. I-double tap upang i-edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. I-double tap upang idagdag."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>. I-double tap upang piliin."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Ilipat ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Alisin ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Idinagdag ang <xliff:g id="TILE_NAME">%1$s</xliff:g> sa posisyon <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Inalis ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Inilipat ang <xliff:g id="TILE_NAME">%1$s</xliff:g> sa posisyon <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor ng Mga mabilisang setting."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
new file mode 100644
index 0000000..74fe314
--- /dev/null
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Isara ang PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
+    <string name="pip_play" msgid="674145557658227044">"I-play"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"I-pause"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"I-hold ang "<b>"HOME"</b>" para makontrol ang PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Pindutin nang matagal ang button ng HOME upang makontrol ang PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"I-dismiss"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 1acffad..58d488c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran görüntüsü alındı."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Ekran görüntünüzü izlemek için dokunun."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran görüntüsü alınamadı."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Depolama alanı sınırlı olduğundan veya uygulamanız ya da kuruluşunuz tarafından izin verilmediğinden ekran görüntüsü alınamıyor."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Ekran görüntüsü kaydedilirken sorun oluştu."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Depolama alanı sınırlı olduğundan ekran görüntüsü kaydedilemiyor."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB dosya aktarım seçenekleri"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Medya oynatıcı olarak ekle (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera olarak ekle (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> uygulamasını kapat."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> kaldırıldı."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tüm son uygulamalar kapatıldı."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlatılıyor."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildirim kapatıldı."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daha uzun süre."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Daha kısa süre."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"El feneri kapalı."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"El feneri kullanılamıyor."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"El feneri açık."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"El feneri kapatıldı."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"El feneri açıldı."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Çalışma modu açık."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Çalışma modu kapatıldı."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Çalışma modu açıldı."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Veri Tasarrufu kapatıldı."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Veri Tasarrufu açıldı."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran parlaklığı"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G veri kullanımı duraklatıldı"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Konum bilgisi istekleri etkin"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Bildirim ayarları"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ayarları"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Sınır: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Çalışma modu"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Son ekranlarınız burada görünür"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Yeni öğe yok"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Her şeyi sildiniz"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sabitleme"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Geçmiş"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Sil"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>, güvenli modda devre dışıdır."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tümünü temizle"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu uygulama, çoklu pencere kullanımını desteklemiyor"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Uygulama, çoklu pencere kullanımını desteklemiyor"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dikey Ayırma"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Özel Ayırma"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Tamamen\nsessiz"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnızca\nöncelik"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnızca\nalarmlar"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Tümü"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tümü\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hızlı şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Yavaş şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ekranı bölmek için yukarı hızlıca kaydırmayı etkinleştir"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Hızlıca yukarı kaydırma hareketiyle ekran bölm. etkinleştir"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Genel bakış düğmesinden yukarı hızlıca kaydırarak bölünmüş ekrana geçme hareketini etkinleştir"</string>
     <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aç"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> bildirimlerine uygula"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Bu uygulamadan gelen tüm bildirimlere uygulansın mı?"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Bildirimleri sessizce göster"</string>
+    <string name="block" msgid="2734508760962682611">"Tüm bildirimleri engelle"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Sessiz moda alma"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Sessiz moda alma veya engelleme"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tüm önem ayarlarını göster"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Engellendi"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Önemi en düşük"</string>
     <string name="low_importance" msgid="4109929986107147930">"Önem düzeyi düşük"</string>
     <string name="default_importance" msgid="8192107689995742653">"Önem düzeyi normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Önem düzeyi yüksek"</string>
     <string name="max_importance" msgid="5089005872719563894">"Önem düzeyi acil"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirimleri hiçbir zaman gösterme"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Bildirim listesinin en altında sessizce göster"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirimleri sessizce göster"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Bildirim listesinin en üstünde göster ve ses çıkar"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Ekrana getir ve ses çıkar"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Bildirim listesinin en altında sessizce göster"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildirimleri sessizce göster"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirimlerin ses çıkarmasına izin ver"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Ekrana getir ve sesli bildirime izin ver"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Bildirim listesinin üstünde göster, ekrana getir ve sesli bildirime izin ver"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Normal renkler"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Gece renkleri"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Özel renkler"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Otomatik"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Bilinmeyen renkler"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Renk değişikliği"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Hızlı Ayarlar kutusunu göster"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Özel dönüşümü etkinleştir"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirim denetimleri"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Renk ve görünüm"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Gece modu"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Ekranı kalibre et"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Açık"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Kapalı"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Otomatik olarak aç"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Konuma ve günün saatine uygun şekilde Gece Modu\'na geç"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Gece Modu açık olduğunda"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android OS için koyu renk tema kullan"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Tonu ayarla"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Parlaklığı ayarla"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Koyu renk tema, Android OS\'nin normalde Ayarlar gibi açık renk bir temayla görüntülenen temel alanlarına uygulanır."</string>
     <string name="color_apply" msgid="9212602012641034283">"Uygula"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Ayarları onaylayın"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Bazı renkler bu cihazı kullanılmaz yapabilir. Bu renkleri onaylamak için Tamam\'ı tıklayın. Tıklamazsanız bu ayarlar 10 saniye sonra sıfırlanacaktır."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Pil kullanımı"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Şarj sırasında Pil Tasarrufu özelliği kullanılamaz"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Pil Tasarrufu"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı ve arka plan verilerini azaltır"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> düğmesi"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Geri"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Yukarı"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Aşağı"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Sol"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Sağ"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Orta"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Sekme"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Boşluk"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Geri tuşu"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Oynat/Duraklat"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Durdur"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Sonraki"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Önceki"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Geri Sar"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"İleri Sar"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Sayfa Yukarı"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Sayfa Aşağı"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> (Sayısal Tuş Takımında)"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ana ekran"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Son çağrılar"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ses iletişim kutusunda rahatsız etmeyin modunu göster"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Ses iletişim kutusunda rahatsız etmeyin modunu tam olarak denetlemeye izin ver."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ses ve Rahatsız etmeyin"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Ses kısıldığında rahatsız etmeyin moduna geç"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirimler"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klavye Kısayolları"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Giriş yöntemini değiştir"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Uygulamalar"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asist"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Tarayıcı"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kişiler"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-posta"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Müzik"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Takvim"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ses seviyesi kontrolleriyle göster"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Rahatsız etmeyin"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Ses düğmeleri kısayolu"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Ses açıldığında rahatsız etmeyin modundan çık"</string>
     <string name="battery" msgid="7498329822413202973">"Pil"</string>
     <string name="clock" msgid="7416090374234785905">"Saat"</string>
     <string name="headset" msgid="4534219457597457353">"Mikrofonlu kulaklık"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Mikrofonlu kulaklık bağlı"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Mikrofonlu kulaklık bağlı"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Simgelerin durum çubuğunda görüntülenmesini etkinleştir veya devre dışı bırak"</string>
     <string name="data_saver" msgid="5037565123367048522">"Veri Tasarrufu"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Veri Tasarrufu açık"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Veri Tasarrufu kapalı"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Açık"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Kapalı"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Gezinme çubuğu"</string>
     <string name="start" msgid="6873794757232879664">"Başlangıç"</string>
     <string name="center" msgid="4327473927066010960">"Merkez"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Klavye Düğmesini Seçin"</string>
     <string name="preview" msgid="9077832302472282938">"Önizle"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Blok eklemek için sürükleyin"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kaldırmak için buraya sürükleyin"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Düzenle"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Saat"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Saati, dakikayı ve saniyeyi göster"</item>
+    <item msgid="1427801730816895300">"Saati ve dakikayı göster (varsayılan)"</item>
+    <item msgid="3830170141562534721">"Bu simgeyi gösterme"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Her zaman yüzdeyi göster"</item>
+    <item msgid="2139628951880142927">"Şarj olurken yüzdeyi göster (varsayılan)"</item>
+    <item msgid="3327323682209964956">"Bu simgeyi gösterme"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Diğer"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Bölünmüş ekran ayırıcı"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Aşağı taşı"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yukarı taşı"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola taşı"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa taşı"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Uygulama birden fazla pencerede çalışmayabilir"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. konum, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Düzenlemek için iki kez hafifçe dokunun."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Eklemek için iki kez hafifçe dokunun."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. konum. Seçmek için iki kez hafifçe dokunun."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusunu taşı"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusunu kaldır"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusu <xliff:g id="POSITION">%2$d</xliff:g>. konuma eklendi"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kaldırıldı"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>. konumuna taşındı"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Hızlı ayar düzenleyicisi."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
new file mode 100644
index 0000000..57da7fb
--- /dev/null
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"PIP\'yi kapat"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Tam ekran"</string>
+    <string name="pip_play" msgid="674145557658227044">"Oynat"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Duraklat"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"PIP\'yi kontrol etmek için "<b>"ANA EKRAN"</b>"\'ı basılı tutun"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"PIP\'yi kontrol etmek için ANA EKRAN düğmesini basılı tutun"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Anladım"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Kapat"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 0a00467..c75891c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -75,7 +75,9 @@
     <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="1260203058661337274">"Не вдається зробити знімок екрана через обмежений обсяг пам’яті або заборону додатка чи організації."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Не вдалося зберегти знімок екрана."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Не вдалося зберегти знімок екрана через обмежений обсяг пам’яті."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Додаток або ваша організація не дозволяють робити знімки екрана."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Парам.передав.файлів через USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Підключити як медіапрогравач (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Підключити як камеру (PTP)"</string>
@@ -168,6 +170,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Видалити додаток <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Програму <xliff:g id="APP">%s</xliff:g> закрито."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усі останні додатки закрито."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск додатка <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Сповіщення відхилено."</string>
@@ -208,6 +212,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Більше часу."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Менше часу."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ліхтарик вимк."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ліхтарик недоступний."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ліхтарик увімк."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ліхтарик вимкнено."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ліхтарик увімкнено."</string>
@@ -220,6 +225,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Робочий режим увімкнено."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Робочий режим вимкнено."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Робочий режим увімкнено."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Заощадження трафіку вимкнено."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Заощадження трафіку ввімкнено."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яскравість дисплея"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передавання даних 2G–3G призупинено"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
@@ -233,6 +240,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Місцезнаходження встановлено за допомогою GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Запити про місцезнаходження активні"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Очистити всі сповіщення."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Налаштування сповіщень"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Налаштування додатка <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран обертатиметься автоматично."</string>
@@ -298,15 +306,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Обмеження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Робочий режим"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Ваші останні екрани відображаються тут"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Немає нещодавніх завдань"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ви очистили все"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"закріпити екран"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не вдалося запустити <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Історія"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Очистити"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Додаток <xliff:g id="APP">%s</xliff:g> вимкнено в безпечному режимі."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Очистити все"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Цей додаток не підтримує багатоекранний режим"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Додаток не підтримує багатоекранний режим"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Розділити вертикально"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Розділити (власний варіант)"</string>
@@ -336,8 +345,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Без\nсигналів"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Лише\nприорітетні"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Лише\nсигнали"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Усі"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Усі\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Швидке заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Повільне заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
@@ -450,61 +457,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Увімкнути акселератор розділення екрана рухом пальця вгору"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Увімкнути розділення екрана рухом пальця вгору"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Увімкнути жест розділення екрана рухом пальця вгору від кнопки \"Огляд\""</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Увімкнути"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Застосувати до сповіщень на тему \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Застосувати до всіх сповіщень із цього додатка"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Показувати сповіщення без звукового сигналу"</string>
+    <string name="block" msgid="2734508760962682611">"Блокувати всі сповіщення"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Не вимикати звуковий сигнал"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не вимикати звуковий сигнал і не блокувати"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показати налаштування пріоритетності"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Заблоковано"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Низький пріоритет"</string>
     <string name="low_importance" msgid="4109929986107147930">"Низький пріоритет"</string>
     <string name="default_importance" msgid="8192107689995742653">"Стандартний пріоритет"</string>
     <string name="high_importance" msgid="1527066195614050263">"Високий пріоритет"</string>
     <string name="max_importance" msgid="5089005872719563894">"Терміново"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ніколи не показувати ці сповіщення"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Показувати сповіщення внизу списку без звукового сигналу"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Показувати ці сповіщення без звукового сигналу"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Показувати сповіщення вгорі списку зі звуковим сигналом"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Показувати сповіщення на екрані зі звуковим сигналом"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Показувати сповіщення внизу списку без звукового сигналу"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Показувати ці сповіщення без звукового сигналу"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Увімкнути звуковий сигнал для цих сповіщень"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Показувати сповіщення на екрані зі звуковим сигналом"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Показувати сповіщення вгорі списку, на екрані та зі звуковим сигналом"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Стандартні кольори"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Нічні кольори"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Користувацькі кольори"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Невідомі кольори"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Змінення кольорів"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показати опцію швидких налаштувань"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Увімкнути користувацьке перетворення"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Елементи керування сповіщеннями додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Колір і вигляд"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Нічний режим"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Калібрувати дисплей"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Увімкнено"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Вимкнено"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Вмикати автоматично"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Переходити на нічний режим відповідно до місцезнаходження та часу доби"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Коли нічний режим увімкнено"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Використати нічну тему для ОС Android"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Налаштувати відтінок"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Регулювати яскравість"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Темна тема застосовується в основних областях ОС Android, які зазвичай відображаються у світлій темі, як-от у налаштуваннях."</string>
     <string name="color_apply" msgid="9212602012641034283">"Застосувати"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Підтвердити налаштування"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Деякі налаштування кольорів можуть зробити цей пристрій непридатним для використання. Натисніть OK, щоб підтвердити налаштування, інакше їх буде скинуто через 10 секунд."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Використання заряду"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим економії заряду акумулятора недоступний під час заряджання"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим економії заряду акумулятора"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Знижується продуктивність і обмежується обмін даними у фоновому режимі"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Стрілка вгору"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Стрілка вниз"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Стрілка вліво"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Стрілка вправо"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Центр"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Пробіл"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Відтворити/призупинити"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Зупинити"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Далі"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Назад"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перемотати назад"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перемотати вперед"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Сторінка вгору"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Сторінка вниз"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Система"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Головний екран"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Останні"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Показувати режим \"Не турбувати\" у вікні регулятора гучності"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дозволити керувати режимом \"Не турбувати\" у вікні регулятора гучності."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Регулятор гучності та режим \"Не турбувати\""</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Вмикати режим \"Не турбувати\" під час зменшення гучності"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Сповіщення"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Комбінації клавіш"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Змінити метод введення"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Додатки"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помічник"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Веб-переглядач"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Електронна пошта"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Чат"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Показувати регулятори гучності"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не турбувати"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки гучності на корпусі"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Вимикати режим \"Не турбувати\" під час збільшення гучності"</string>
     <string name="battery" msgid="7498329822413202973">"Акумулятор"</string>
     <string name="clock" msgid="7416090374234785905">"Годинник"</string>
     <string name="headset" msgid="4534219457597457353">"Гарнітура"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Навушники під’єднано"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Гарнітуру під’єднано"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Показати або сховати значки в рядку стану."</string>
     <string name="data_saver" msgid="5037565123367048522">"Заощадження трафіку"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Заощадження трафіку ввімкнено"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Заощадження трафіку вимкнено"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Увімкнено"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Вимкнути"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Панель навігації"</string>
     <string name="start" msgid="6873794757232879664">"На початку"</string>
     <string name="center" msgid="4327473927066010960">"У центрі"</string>
@@ -526,5 +579,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Вибрати кнопку клавіатури"</string>
     <string name="preview" msgid="9077832302472282938">"Переглянути"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Перетягуйте фрагменти, щоб додавати їх"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перетягніть сюди, щоб видалити"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Редагувати"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Час"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Показувати години, хвилини та секунди"</item>
+    <item msgid="1427801730816895300">"Показувати години та хвилини (за умовчанням)"</item>
+    <item msgid="3830170141562534721">"Не показувати цей значок"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Завжди показувати відсотки"</item>
+    <item msgid="2139628951880142927">"Показувати відсотки під час заряджання (за умовчанням)"</item>
+    <item msgid="3327323682209964956">"Не показувати цей значок"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Інше"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Розділювач екрана"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Перемістити вниз"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перемістити вгору"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перемістити ліворуч"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перемістити праворуч"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Додаток може не працювати в багатовіконному режимі"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Двічі торкніться, щоб змінити."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Двічі торкніться, щоб додати."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>. Двічі торкніться, щоб вибрати."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Перемістити <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Видалити <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> додано на позицію <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> видалено"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> переміщено на позицію <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор швидких налаштувань."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
new file mode 100644
index 0000000..1091547
--- /dev/null
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Закрити PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"На весь екран"</string>
+    <string name="pip_play" msgid="674145557658227044">"Відтворити"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Призупинити"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Щоб керувати PIP, утримуйте кнопку "<b>"ГОЛОВНИЙ ЕКРАН"</b></string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Щоб керувати PIP, утримуйте кнопку \"ГОЛОВНИЙ ЕКРАН\""</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Закрити"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 0e1d78f..807a923 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"اسٹوریج کی محدود جگہ کی وجہ سے اسکرین شاٹ نہیں لے سکتے، یا ایپ یا آپکی تنظیم کے ذریعے یہ مجاز نہیں ہے۔"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"اسکرین شاٹ محفوظ کرتے وقت مسئلہ پیش آ گیا۔"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"محدود اسٹوریج جگہ کی وجہ سے اسکرین شاٹس نہیں لئے جا سکتے۔"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ایپ یا آپ کی تنظیم کی جانب سے اسکرین شاٹس لینے کی اجازت نہیں ہے۔"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"‏USB فائل منتقل کرنیکے اختیارات"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏ایک میڈیا پلیئر (MTP) کے بطور ماؤنٹ کریں"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏ایک کیمرہ (PTP) کے بطور ماؤنٹ کریں"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> کو مسترد کریں۔"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> کو ہٹا دیا گیا۔"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"سبھی حالیہ ایپلیکیشنز کو برخاست کر دیا گیا۔"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> شروع ہو رہی ہے۔"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"اطلاع مسترد ہوگئی۔"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"مزید وقت۔"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"کم وقت۔"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"فلیش لائٹ آف ہے۔"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"فلیش لائٹ دستیاب نہیں ہے"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"فلیش لائٹ آن ہے۔"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"فلیش لائٹ کو آف کر دیا گیا۔"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"فلیش لائٹ کو آن کر دیا گیا۔"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"کام موڈ آن ہے۔"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"کام موڈ آف ہو گیا۔"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"کام موڈ آن ہو گیا۔"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"ڈیٹا سیور آف ہو گیا۔"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"ڈیٹا سرور آن ہو گیا۔"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ڈسپلے کی چمک"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏2G-3G ڈیٹا موقوف کر دیا گیا"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏4G ڈیٹا موقوف کر دیا گیا"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"‏مقام متعین کیا گیا بذریعہ GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"مقام کی درخواستیں فعال ہیں"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"سبھی اطلاعات صاف کریں۔"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> +"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"اطلاع کی ترتیبات"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ترتیبات"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"اسکرین خود بخود گردش کرے گی۔"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> حد"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"کام موڈ"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"آپ کی حالیہ اسکرینز یہاں ظاہر ہوتی ہیں"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"کوئی حالیہ آئٹم نہیں"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"آپ نے سب کچھ صاف کر دیا ہے"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ایپلیکیشن کی معلومات"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"اسکرین کو پن کرنا"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"تلاش کریں"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> کو شروع نہیں کیا جا سکا۔"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"سرگزشت"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"صاف کریں"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"محفوظ موڈ میں <xliff:g id="APP">%s</xliff:g> غیر فعال ہوتی ہے۔"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"سبھی کو صاف کریں"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"یہ ایپ ملٹی ونڈو کی معاونت نہیں کرتی"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ایپ ملٹی ونڈز کی معاونت نہیں کرتی"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"بلحاظ عمودی الگ کریں"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"بلحاظ حسب ضرورت الگ کریں"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"مکمل\nخاموشی"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"صرف\nترجیحی"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"صرف\nالارمز"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"سبھی"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"تمام\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"تیزی سے چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"آہستہ چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
     <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"سپلٹ اسکرین کیلئے سوائپ اپ ایکسلریٹر فعال کریں"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"سپلٹ اسکرین کیلئے سوائپ اپ اشارہ فعال کریں"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"مجموعی جائزہ بٹن سے سوائپ اپ کرکے سپلٹ اسکرین میں داخل ہونے کیلئے اشارہ فعال کریں"</string>
     <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"آن کریں"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> اطلاعات پر لاگو کریں"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"اس ایپ سے تمام اطلاعات پر لاگو کریں"</string>
+    <string name="show_silently" msgid="6841966539811264192">"اطلاعات خاموشی سے دکھائیں"</string>
+    <string name="block" msgid="2734508760962682611">"تمام اطلاعات کو مسدود کریں"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"خاموش نہ کریں"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"خاموش یا مسدود نہ کریں"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"اہمیت کی پوری ترتیبات دکھائیں"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"مسدود کردہ"</string>
+    <string name="min_importance" msgid="1901894910809414782">"کم سے کم اہمیت"</string>
     <string name="low_importance" msgid="4109929986107147930">"کم اہمیت"</string>
     <string name="default_importance" msgid="8192107689995742653">"عمومی اہمیت"</string>
     <string name="high_importance" msgid="1527066195614050263">"زیادہ اہمیت"</string>
     <string name="max_importance" msgid="5089005872719563894">"فوری اہمیت"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"یہ اطلاعات کبھی مت دکھائیں"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"اطلاعات کی فہرست کے سب سے نیچے خاموشی سے دکھائیں"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"خاموشی سے یہ اطلاعات دکھائیں"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں اور آواز چلائیں"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"اسکرین پر دکھائیں اور آواز چلائیں"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"اطلاعات کی فہرست کے سب سے نیچے خاموشی سے دکھائیں"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"خاموشی سے یہ اطلاعات دکھائیں"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ان اطلاعات کو آواز نکالنے کی اجازت دیں"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"اسکرین پر دکھائیں اور آواز کی اجازت دیں"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں، اسکرین پر دکھائیں اور آواز کی اجازت دیں"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
     <string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"عام رنگ"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"رات کے رنگ"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"حسب ضرورت رنگ"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"خودکار"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"نامعلوم رنگ"</string>
-    <string name="color_transform" msgid="6985460408079086090">"رنگوں کی تبدیلی"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"فوری ترتیبات والی ٹائل دکھائیں"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"حسب ضرورت ٹرانسفارم فعال کریں"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے نوٹیفکیشن کنٹرولز"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"رنگ اور ظہور"</string>
+    <string name="night_mode" msgid="3540405868248625488">"رات موڈ"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"نشان زد ڈسپلے"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"آن"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"آف"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"خودکار طور پر آن کریں"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"مقام اور دن کے وقت کی مناسبت سے نائٹ موڈ میں سوئچ کریں"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"جب نائٹ موڈ آن ہو"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"‏Android OS کیلئے ڈارک تھیم استعمال کریں"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"ٹنٹ ایڈجسٹ کریں"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"چمک کو ایڈجسٹ کریں"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"‏ڈارک تھیم Android OS کی بنیادی جگہوں پر لاگو کی جاتی ہے جو عام طور لائٹ تھیم میں ڈسپلے ہوتے ہیں، جیسے ترتیبات۔"</string>
     <string name="color_apply" msgid="9212602012641034283">"لاگو کریں"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"ترتیبات کی توثیق کریں"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"رنگوں کی کچھ ترتیبات اس آلے کو ناقابل استعمال بنا سکتی ہیں۔ رنگوں کی ان ترتیبات کی توثیق کرنے کیلئے ٹھیک ہے پر کلک کریں، بصورت دیگر 10 سیکنڈ بعد یہ ترتیبات ری سیٹ ہو جائیں گی۔"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"بیٹری کا استعمال"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"چارجنگ کے دوران بیٹری سیور دستیاب نہیں ہے"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"بیٹری سیور"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"بٹن <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"پیچھے"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"اوپر"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"نیچے"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"بائیں"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"دائیں"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"سینٹر"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"چلائیں/موقوف کریں"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"روکیں"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"اگلا"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"گزشتہ"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ریوائینڈ کریں"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"تیزی سے فارورڈ کریں"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"نمبر پیڈ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"سسٹم"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ہوم"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"حالیہ"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"پیچھے"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"والیوم میں ڈسٹرب نہ کریں دکھائیں"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"والیوم ڈائیلاگ میں ڈسٹرب نہ کریں کے مکمل کنٹرول کی اجازت دیں۔"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"والیوم اور ڈسٹرب نہ کریں"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"کم والیوم پر \'ڈسٹرب نہ کریں\' میں داخل ہوں"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"اطلاعات"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"کی بورڈ شارٹ کٹس"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"اندراج کا طریقہ سوئچ کریں"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ایپلیکیشنز"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"اسسٹ"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"براؤزر"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"رابطے"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ای میل"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"موسیقی"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"کیلنڈر"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"والیوم کنٹرولز کے ساتھ دکھائیں"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ڈسٹرب نہ کریں"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"والیوم بٹنز کے شارٹ کٹ"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"زیادہ والیوم پر \'ڈسٹرب نہ کریں\' سے خارج ہوں"</string>
     <string name="battery" msgid="7498329822413202973">"بیٹری"</string>
     <string name="clock" msgid="7416090374234785905">"گھڑی"</string>
     <string name="headset" msgid="4534219457597457353">"ہیڈ سیٹ"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ہیڈ فونز منسلک ہیں"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ہیڈ سیٹ منسلک ہے"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"اسٹیٹس بار میں دکھائے جانے کیلئے آئیکنز فعال یا غیر فعال کریں۔"</string>
     <string name="data_saver" msgid="5037565123367048522">"ڈیٹا سیور"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"ڈیٹا سیور آن ہے"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"ڈیٹا سیور آف ہے"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"آن"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"آف"</string>
     <string name="nav_bar" msgid="1993221402773877607">"نیویگیشن بار"</string>
     <string name="start" msgid="6873794757232879664">"شروع کریں"</string>
     <string name="center" msgid="4327473927066010960">"مرکز"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"کی بورڈ بٹن منتخب کریں"</string>
     <string name="preview" msgid="9077832302472282938">"پیش منظر"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ٹائٹلز شامل کرنے کیلئے گھسیٹیں"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ہٹانے کیلئے یہاں گھسیٹیں؟"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ترمیم کریں"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"وقت"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"گھنٹے، منٹ اور سیکنڈ دکھائیں"</item>
+    <item msgid="1427801730816895300">"گھنٹے اور منٹ دکھائیں (ڈیفالٹ)"</item>
+    <item msgid="3830170141562534721">"یہ آئیکن نہ دکھائیں"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"ہمیشہ شرح فیصد دکھائیں"</item>
+    <item msgid="2139628951880142927">"چارج ہوتے وقت فیصد دکھائیں (ڈیفالٹ)"</item>
+    <item msgid="3327323682209964956">"یہ آئیکن نہ دکھائیں"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"دیگر"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"سپلٹ اسکرین تقسیم کار"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"نیچے منتقل کریں"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"اوپر منتقل کریں"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"بائیں منتقل کریں"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"دائیں منتقل کریں"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"ایپ شاید ملٹی ونڈو کے ساتھ کام نہ کرے"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>۔ ترمیم کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>۔ شامل کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>۔ منتخب کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> کو منتقل کریں"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ہٹائیں"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> شامل ہو گیا ہے"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ہٹا دیا گیا"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> منتقل ہو گیا ہے"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"فوری ترتیبات کا ایڈیٹر۔"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings_tv.xml b/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
new file mode 100644
index 0000000..78de898
--- /dev/null
+++ b/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"‏PIP بند کریں"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"فُل اسکرین"</string>
+    <string name="pip_play" msgid="674145557658227044">"چلائیں"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"موقوف کریں"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"‏PIP کنٹرول کرنے کیلئے "<b>"ہوم"</b>" پکڑے رکھیں"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"‏PIP کنٹرول کرنے کیلئے ہوم بٹن دبائیں اور پکڑے رکھیں"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"سمجھ آ گئی"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"برخاست کریں"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 68393ff..fe67b52 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skrinshot saqlandi."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Ko‘rish uchun bu yerga bosing."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Skrinshot saqlanmadi."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Ekrandan suratga olib bo‘lmadi: xotirada joy kam yoki ilova/tashkilot bunga ruxsat bermagan."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Skrinshotni saqlashda muammo yuz berdi."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Xotirada joy kamligi uchun skrinshotni saqlab bo‘lmadi."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Ilova yoki tashkilotingiz skrinshot olishni taqiqlagan."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB fayl ko‘chirish moslamalari"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer sifatida ulash (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera sifatida ulash (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Olib tashlash: <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> olib tashlangan."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Yaqinda ishlatilgan barcha ilovalar olib tashlandi."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ishga tushirilmoqda."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Xabarnoma e‘tiborsiz qoldirildi."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ko‘proq vaqt."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kamroq vaqt."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Fonar o‘chirilgan."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Bu yerda fonar yo‘q."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Fonar yoqilgan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Fonar o‘chirildi."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Fonar yoqildi."</string>
@@ -217,7 +222,9 @@
     <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Ish rejimi o‘chiq."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Ish rejimi yoniq."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Ish rejimi o‘chirib qo‘yildi."</string>
-    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Ish rejimi yoqildi."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Ishchi rejim yoqildi."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Trafik tejash rejimi o‘chirib qo‘yildi."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Trafik tejash rejimi yoqildi."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran yorqinligi"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G internet to‘xtatib qo‘yildi"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS yordamida manzilni o‘rnatish"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Joylashuv so‘rovlari yoniq"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Barcha eslatmalarni tozalash."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Bildirishnoma sozlamalari"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> sozlamalari"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran avtomatik buriladi."</string>
@@ -269,7 +277,7 @@
     <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ulanmagan"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tarmoq mavjud emas"</string>
-    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi o‘chirilgan"</string>
+    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi o‘chiq"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Hech qanday Wi-Fi tarmog‘i mavjud emas"</string>
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Wi-Fi monitor"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Translatsiya qilinmoqda"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Cheklov: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ish rejimi"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Bu yerda yaqinda ishlatilgan ilovalar ko‘rsatiladi"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Hozircha hech narsa yo‘q"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hammasi o‘chirildi"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ilova haqida ma’lumot"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"o‘zgarmas ekran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Jurnal"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tozalash"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Xavfsiz rejimda <xliff:g id="APP">%s</xliff:g> ilovasi o‘chirib qo‘yildi."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hammasini tozalash"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Tinchlik\nsaqlansin"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Faqat\nmuhimlar"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Faqat\nsignallar"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Barchasi"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Barcha\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Tez quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sekin quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
@@ -367,8 +374,8 @@
     <string name="user_remove_user_message" msgid="1453218013959498039">"Ushbu foydalanuvchining barcha ilovalari va ma’lumotlari o‘chirib tashlanadi."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Olib tashlash"</string>
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Quvvat tejash rejimi yoqildi"</string>
-    <string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlikni pasaytiradi va fonda int-dan foyd-ni cheklaydi"</string>
-    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash funksiyasini o‘chiring"</string>
+    <string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlik pasayadi va fonda internetdan foydalanish cheklanadi"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash rejimidan chiqish"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi qurilma ekranidagi har qanday tasvirni ko‘rishni boshlaydi."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Boshqa ko‘rsatilmasin"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Barchasini tozalash"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Tepaga surib, ekranni bo‘lish uchun tezlatkichni yoqish"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Tepaga surish orqali ekranni ikkiga bo‘lish"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umumiy ma’lumot tugmasini tepaga surish orqali ekranni bo‘lish ishorasini yoqish"</string>
     <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Yoqish"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"“<xliff:g id="TOPIC_NAME">%1$s</xliff:g>” bildirishnomalariga qo‘llash"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Ushbu ilovaning barcha bildirishnomalariga qo‘llash"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+    <string name="block" msgid="2734508760962682611">"Barcha bildirishnomalar bloklansin"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ovozi o‘chirilmasin"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ovozi o‘chirilmasin yoki bloklanmasin"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Barcha muhimlik sozlamalarini ko‘rsatish"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloklangan"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Kamroq muhim"</string>
     <string name="low_importance" msgid="4109929986107147930">"Kamroq muhim"</string>
     <string name="default_importance" msgid="8192107689995742653">"O‘rtacha muhim"</string>
     <string name="high_importance" msgid="1527066195614050263">"Juda muhim"</string>
     <string name="max_importance" msgid="5089005872719563894">"Favqulodda muhim"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Bildirishnomalar ro‘yxatining boshida ovoz bilan ko‘rsatilsin"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Barcha oynalar ustida signal ovozi bilan ko‘rsatilsin"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirishnomalar ovoz bilan ko‘rsatilsin"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Barcha oynalar ustida ovoz bilan ko‘rsatilsin"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Bildirishnomalar ro‘yxatining boshida va barcha oynalar ustida ovoz bilan ko‘rsatilsin"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Odatiy ranglar"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Qoramtir ranglar"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Foydalanuvchi rangi"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Avtomatik"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Noma’lum ranglar"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Rang sozlamalari"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tezkor sozlamalar panelini ko‘rsatish"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Foydalanuvchi sozlamalarini yoqish"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalarini boshqarish"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Rang va ko‘rinishi"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Tungi rejim"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Ekranni kalibrlash"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Yoniq"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"O‘chiq"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Avtomatik yoqish"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Joylashuv va vaqtga mos ravishda tungi rejimga o‘tish"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Agar tungi rejim yoniq bo‘lsa"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Android uchun to‘q rangli mavzudan foydalanish"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Rang tusini o‘zgartirish"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Yorqinlikni o‘zgartirish"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"To‘q rangli mavzu Android tizimining odatda och rangda ko‘rsatiladigan o‘zak sahifalariga (masalan, Sozlamalar) nisbatan qo‘llaniladi."</string>
     <string name="color_apply" msgid="9212602012641034283">"Qo‘llash"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Sozlamalarni tasdiqlang"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Ba’zi rang sozlamalari qurilmadan foydalanishni qiyinlashtirish mumkin. Tanlgan parametrlarni tasdiqlash uchun “OK” tugmasini bosing. Aks holda, ular 10 soniyadan so‘ng qayta tiklanadi."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Batareya sarfi"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Quvvat tejash rejimidan quvvatlash vaqtida foydalanib bo‘lmaydi"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Quvvat tejash rejimi"</string>
-    <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Unumdorlikni pasaytiradi va fonda internetdan foydalanishni cheklaydi"</string>
+    <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Unumdorlik pasayadi va fonda internetdan foydalanish cheklanadi"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> tugmasi"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Bosh ekran"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Orqaga"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Tepaga qaragan ko‘rsatkichli chiziq"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Pastga qaragan ko‘rsatkichli chiziq"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Chapga qaragan ko‘rsatkichli chiziq"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"O‘ngga qaragan ko‘rsatkichli chiziq"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Markaziy ko‘rsatkichli chiziq"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Bo‘sh joy"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Ijro/Pauza"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"To‘xtatish"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Keyingi"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Avvalgi"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Orqaga qaytarish"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Oldinga o‘tkazish"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Raqamli klaviatura (<xliff:g id="NAME">%1$s</xliff:g>)"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Tizim"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Bosh ekran"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"So‘nggi ishlatilganlar"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Orqaga"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ovoz boshqarish oynasida “Bezovta qilinmasin” panelini ko‘rsatish"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Ovoz balandligini boshqarish oynasida “Bezovta qilinmasin” rejimini to‘liq boshqarishga ruxsat beradi."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ovoz balandligini boshqarish va “Bezovta qilinmasin” rejimi"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Ovozni pasaytirganda “Bezovta qilinmasin” rejimini yoqish"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirishnomalar"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tezkor tugmalar"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Matn kiritish usulini o‘zgartirish"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Ilovalar"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Yordamchi"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauzer"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktlar"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pochta"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiqa"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Taqvim"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ovoz balandligini boshqarish tugmalari bilan ko‘rsatish"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bezovta qilinmasin"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Ovoz balandligini boshqarish tugmalari"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Ovozni ko‘targanda “Bezovta qilinmasin” rejimini o‘chirish"</string>
     <string name="battery" msgid="7498329822413202973">"Batareya"</string>
     <string name="clock" msgid="7416090374234785905">"Soat"</string>
     <string name="headset" msgid="4534219457597457353">"Audio moslama"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Quloqchinlar ulandi"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Audio moslama ulandi"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Holat qatorida begilarning ko‘rsatilishini yoqish yoki o‘chirish."</string>
     <string name="data_saver" msgid="5037565123367048522">"Trafik tejash"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Trafik tejash yoniq"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Trafik tejash o‘chiq"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Yoniq"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"O‘chiq"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigatsiya paneli"</string>
     <string name="start" msgid="6873794757232879664">"Boshlash"</string>
     <string name="center" msgid="4327473927066010960">"Markazda"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Klaviatura tugmasini tanlang"</string>
     <string name="preview" msgid="9077832302472282938">"Oldindan ko‘rish"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Fragmentlar qo‘shish uchun torting"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"O‘chirish uchun bu yerga torting"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Tahrirlash"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Vaqt"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Soat, daqiqa va soniyalar ko‘rsatilsin"</item>
+    <item msgid="1427801730816895300">"Soat va daqiqalar ko‘rsatilsin (birlamchi)"</item>
+    <item msgid="3830170141562534721">"Bu belgi boshqa ko‘rsatilmasin"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Har doim foizda ko‘rsatilsin"</item>
+    <item msgid="2139628951880142927">"Quvvat olayotganda foizda ko‘rsatilsin (birlamchi)"</item>
+    <item msgid="3327323682209964956">"Bu belgi boshqa ko‘rsatilmasin"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Boshqa"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Ekranni ikkiga bo‘lish chizig‘i"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pastga siljitish"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Tepaga siljitish"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Chapga siljitish"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"O‘ngga siljitish"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>-joy, “<xliff:g id="TILE_NAME">%2$s</xliff:g>” tugmasi. Tahrirlash uchun ustiga ikki marta bosing."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi. Qo‘shish uchun ustiga ikki marta bosing."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>. Belgilash uchun ustiga ikki marta bosing."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasini ko‘chirish"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasini o‘chirish"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi endi <xliff:g id="POSITION">%2$d</xliff:g>-joyni egallamoqda"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi o‘chirildi"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi endi <xliff:g id="POSITION">%2$d</xliff:g>-joyni egallanmoqda"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Tezkor sozlamalar muharriri"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml b/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
new file mode 100644
index 0000000..9300aaa
--- /dev/null
+++ b/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Kadr ichida kadr – chiqish"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"To‘liq ekran"</string>
+    <string name="pip_play" msgid="674145557658227044">"Ijro"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Pauza"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"“Kadr ichida kadr” rejimini boshqarish uchun "<b>"BOSHI"</b>" tugmasini bosib turing"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"“Kadr ichida kadr” rejimini boshqarish uchun BOSHIGA tugmasini bosib turing"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Yopish"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d4c7317..ca7c59b 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Đã chụp ảnh màn hình."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Chạm để xem ảnh chụp màn hình của bạn."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Không thể chụp ảnh màn hình."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Ko thể chụp ảnh màn hình do dung lượng bộ nhớ hạn chế hoặc ứng dụng hay tổ chức của bạn ko cho phép."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Đã gặp phải sự cố khi đang lưu ảnh chụp màn hình."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Không thể lưu ảnh chụp màn hình do giới hạn dung lượng bộ nhớ."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Ứng dụng hoặc tổ chức của bạn không cho phép chụp ảnh màn hình."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Tùy chọn truyền tệp USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Gắn như một trình phát đa phương tiện (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Gắn như một máy ảnh (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Xóa bỏ <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> đã bị loại bỏ."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Đã bỏ qua tất cả các ứng dụng gần đây."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Bắt đầu <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Đã loại bỏ thông báo."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Nhiều thời gian hơn."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Ít thời gian hơn."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Đèn pin tắt."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Đèn flash không khả dụng."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Đèn pin bật."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Đã tắt đèn pin."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Đã bật đèn pin."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Chế độ làm việc bật."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Chế độ làm việc đã tắt."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Chế độ làm việc đã bật."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Đã tắt Trình tiết kiệm dữ liệu."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Đã bật Trình tiết kiệm dữ liệu."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Độ sáng màn hình"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Đã tạm dừng dữ liệu 2G-3G"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Yêu cầu về thông tin vị trí đang hoạt động"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Xóa tất cả thông báo."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Cài đặt thông báo"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Cài đặt <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hình sẽ xoay tự động."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Giới hạn <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Chế độ làm việc"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Màn hình gần đây của bạn sẽ xuất hiện tại đây"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Không có mục gần đây nào"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Bạn đã xóa mọi nội dung"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"khóa màn hình"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Lịch sử"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Xóa"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> bị tắt ở chế độ an toàn."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Xóa tất cả"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ứng dụng này không hỗ trợ chế độ nhiều cửa sổ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Ứng dụng không hỗ trợ chế độ nhiều cửa sổ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Phân tách ngang"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Phân tách dọc"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tùy chỉnh phân tách"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Hoàn toàn\ntắt tiếng"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Chỉ\nưu tiên"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Chỉ\nbáo thức"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Tất cả"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tất cả\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sạc nhanh (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sạc chậm (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Bật trình tăng tốc vuốt lên ở chế độ chia đôi màn hình"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bật cử chỉ vuốt lên ở chế độ chia đôi màn hình"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Cho phép cử chỉ truy cập chế độ chia đôi màn hình bằng cách vuốt lên từ nút Tổng quan"</string>
     <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bật Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Để kết nối bàn phím với máy tính bảng, trước tiên, bạn phải bật Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bật"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Áp dụng cho thông báo <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Áp dụng cho tất cả thông báo từ ứng dụng này"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Hiển thị im lặng các thông báo"</string>
+    <string name="block" msgid="2734508760962682611">"Chặn tất cả thông báo"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Không im lặng"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Không im lặng hoặc chặn"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Hiển thị cài đặt tầm quan trọng đầy đủ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bị chặn"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Tầm quan trọng thấp nhất"</string>
     <string name="low_importance" msgid="4109929986107147930">"Tầm quan trọng thấp"</string>
     <string name="default_importance" msgid="8192107689995742653">"Tầm quan trọng bình thường"</string>
     <string name="high_importance" msgid="1527066195614050263">"Tầm quan trọng cao"</string>
     <string name="max_importance" msgid="5089005872719563894">"Tầm quan trọng khẩn cấp"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Không bao giờ hiển thị các thông báo này"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Hiển thị im lặng ở cuối danh sách thông báo"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Hiển thị im lặng các thông báo này"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Hiển thị ở đầu danh sách thông báo và phát ra âm thanh"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Hiển thị trên màn hình và phát ra âm thanh"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Hiển thị im lặng ở cuối danh sách thông báo"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Hiển thị im lặng các thông báo này"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Cho phép các thông báo này phát ra âm thanh"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Hiển thị trên màn hình và phát ra âm thanh"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Hiển thị ở đầu danh sách thông báo, hiển thị trên màn hình và phát ra âm thanh"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
     <string name="notification_done" msgid="5279426047273930175">"Xong"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Màu thông thường"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Màu tối"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Màu tùy chỉnh"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Tự động"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Màu không xác định"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Sửa đổi màu"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Hiển thị ô Cài đặt nhanh"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Bật chuyển đổi tùy chỉnh"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Điều khiển thông báo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Màu sắc và giao diện"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Chế độ ban đêm"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Hiệu chỉnh hiển thị"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Bật"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Tắt"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Tự động bật"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Chuyển sang Chế bộ ban đêm khi thích hợp cho vị trí và thời gian trong ngày"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Khi Chế độ ban đêm đang bật"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Sử dụng chủ đề sẫm màu cho Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Điều chỉnh phủ màu"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Điều chỉnh độ sáng"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Chủ đề sẫm màu được áp dụng cho các vùng chính của Android OS được hiển thị bình thường trong chủ đề sáng màu, chẳng hạn như Cài đặt."</string>
     <string name="color_apply" msgid="9212602012641034283">"Áp dụng"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Xác nhận cài đặt"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Một số cài đặt màu có thể khiến thiết bị này không sử dụng được. Hãy nhấp vào OK để xác nhận các cài đặt màu này, nếu không những cài đặt này sẽ được đặt lại sau 10 giây."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Mức sử dụng pin"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Trình tiết kiệm pin không khả dụng trong khi sạc"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Trình tiết kiệm pin"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Giảm hiệu suất và dữ liệu nền"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Nút <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Quay lại"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Lên"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Xuống"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Trái"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Phải"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Giữa"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Dấu cách"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Phát/Tạm dừng"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Dừng"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Tiếp theo"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Trước"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Tua lại"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Tua nhanh"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Cuối"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Bàn phím số <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Hệ thống"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Màn hình chính"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Gần đây"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Quay lại"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Hiển thị không làm phiền theo âm lượng"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Cho phép kiểm soát toàn bộ tính năng không làm phiền trong hộp thoại âm lượng."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Âm lượng và Không làm phiền"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Truy cập không làm phiền khi giảm âm lượng"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Thông báo"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Phím tắt"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Chuyển phương thức nhập"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Ứng dụng"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Trợ lý"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Trình duyệt"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Danh bạ"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Nhắn tin nhanh"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Âm nhạc"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Lịch"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Hiển thị với các điều khiển âm lượng"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Không làm phiền"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Phím tắt các nút âm lượng"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Thoát không làm phiền khi tăng âm lượng"</string>
     <string name="battery" msgid="7498329822413202973">"Pin"</string>
     <string name="clock" msgid="7416090374234785905">"Đồng hồ"</string>
     <string name="headset" msgid="4534219457597457353">"Tai nghe"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Đã kết nối tai nghe"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Đã kết nối tai nghe"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Bật hoặc tắt biểu tượng hiển thị trong thanh trạng thái."</string>
     <string name="data_saver" msgid="5037565123367048522">"Trình tiết kiệm dữ liệu"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Trình tiết kiệm dữ liệu đang bật"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Trình tiết kiệm dữ liệu đang tắt"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Bật"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Tắt"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Thanh điều hướng"</string>
     <string name="start" msgid="6873794757232879664">"Đầu"</string>
     <string name="center" msgid="4327473927066010960">"Căn giữa"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Chọn nút trên bàn phím"</string>
     <string name="preview" msgid="9077832302472282938">"Xem trước"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Kéo để thêm ô"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kéo vào đây để xóa"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Chỉnh sửa"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Thời gian"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Hiển thị giờ, phút và giây"</item>
+    <item msgid="1427801730816895300">"Hiển thị giờ và phút (mặc định)"</item>
+    <item msgid="3830170141562534721">"Không hiển thị biểu tượng này"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Luôn hiển thị phần trăm"</item>
+    <item msgid="2139628951880142927">"Hiển thị phần trăm khi sạc (mặc định)"</item>
+    <item msgid="3327323682209964956">"Không hiển thị biểu tượng này"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Khác"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Bộ chia chia đôi màn hình"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Chuyển xuống"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Chuyển lên"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Di chuyển sang trái"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Di chuyển sang phải"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Ứng dụng có thể không hoạt động với nhiều cửa sổ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Nhấn đúp để chỉnh sửa."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Nhấn đúp để thêm."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>. Nhấn đúp để chọn."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Di chuyển <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Xóa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được thêm vào vị trí <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được di chuyển"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được di chuyển sang vị trí <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Trình chỉnh sửa cài đặt nhanh."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
new file mode 100644
index 0000000..b781503
--- /dev/null
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Đóng PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Toàn màn hình"</string>
+    <string name="pip_play" msgid="674145557658227044">"Phát"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Tạm dừng"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Giữ "<b>"HOME"</b>" để đ.khiển PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Bấm và giữ nút HOME để điều khiển PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Loại bỏ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 8a3723a..a25b9f1 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -34,14 +34,14 @@
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>。节电助手已开启。"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>。省电模式已开启。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支持USB充电功能。\n只能使用随附的充电器充电。"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电。"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"仅限使用设备随附的充电器。"</string>
     <string name="battery_low_why" msgid="4553600287639198111">"设置"</string>
-    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"要开启节电助手吗?"</string>
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"要开启省电模式吗?"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"开启"</string>
-    <string name="battery_saver_start_action" msgid="5576697451677486320">"开启节电助手"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"开启省电模式"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自动旋转屏幕"</string>
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"无法进行屏幕截图,原因可能是存储空间不足,或者该应用或您所属的单位不允许执行此操作。"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"保存屏幕截图时出现问题。"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由于存储空间有限,无法保存屏幕截图。"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"此应用或贵单位不允许进行屏幕截图。"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB文件传输选项"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"作为媒体播放器(MTP)装载"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"作为相机(PTP)装载"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"移除<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"已删除<xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"已关闭所有最近用过的应用。"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在启动<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已关闭通知。"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"延长时间。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"缩短时间。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"手电筒关闭。"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"无法使用手电筒。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"手电筒打开。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"手电筒已关闭。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"手电筒已打开。"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"工作模式开启。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"工作模式已关闭。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"工作模式已开启。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"流量节省程序已关闭。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"流量节省程序已开启。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"屏幕亮度"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 数据网络已暂停使用"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"已通过GPS确定位置"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"应用发出了有效位置信息请求"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"通知设置"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>设置"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕会自动旋转。"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限为<xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"您最近浏览过的屏幕会显示在此处"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"近期没有任何内容"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有内容"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"固定屏幕"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"历史记录"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>已在安全模式下停用。"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"此应用不支持多窗口模式"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"应用不支持多窗口模式"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自定义分割"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"完全\n静音"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"仅限\n优先打扰"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"仅限\n闹钟"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"全部\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在慢速充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
@@ -366,9 +373,9 @@
     <string name="user_remove_user_title" msgid="4681256956076895559">"是否移除用户?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"此用户的所有应用和数据均将被删除。"</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
-    <string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已开启"</string>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"省电模式已开启"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"降低性能并限制后台流量"</string>
-    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭节电助手"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭省电模式"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>将开始截取您的屏幕上显示的所有内容。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"不再显示"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"启用分屏向上滑动加速器"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"启用分屏上滑手势"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"启用通过从“概览”按钮向上滑动的手势进入分屏模式"</string>
     <string name="experimental" msgid="6198182315536726162">"实验性"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"开启"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"应用于<xliff:g id="TOPIC_NAME">%1$s</xliff:g>通知"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"应用于来自此应用的所有通知"</string>
+    <string name="show_silently" msgid="6841966539811264192">"显示通知,但不发出提示音"</string>
+    <string name="block" msgid="2734508760962682611">"屏蔽所有通知"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"不静音"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"不静音也不屏蔽"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"显示完整的重要性设置"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"屏蔽"</string>
+    <string name="min_importance" msgid="1901894910809414782">"重要性最低"</string>
     <string name="low_importance" msgid="4109929986107147930">"重要性:低"</string>
     <string name="default_importance" msgid="8192107689995742653">"重要性:一般"</string>
     <string name="high_importance" msgid="1527066195614050263">"重要性:高"</string>
     <string name="max_importance" msgid="5089005872719563894">"重要性:紧急"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"一律不显示这些通知"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"在通知列表底部显示,但不发出提示音"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"显示这些通知,但不发出提示音"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"在通知列表顶部显示,并发出提示音"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"在屏幕上持续显示,并发出提示音"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"在通知列表底部显示,但不发出提示音"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"显示这些通知,但不发出提示音"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"允许这些通知发出提示音"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"在屏幕上短暂显示,并允许发出提示音"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"在通知列表顶部显示,同时在屏幕上短暂显示,并允许发出提示音"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"常规颜色"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"夜间颜色"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"自定义颜色"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"自动"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"未知颜色"</string>
-    <string name="color_transform" msgid="6985460408079086090">"颜色修改"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"显示“快捷设置”图块"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"启用自定义转换"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>通知设置"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"颜色和外观"</string>
+    <string name="night_mode" msgid="3540405868248625488">"夜间模式"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"校准显示画面"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"开启"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"关闭"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"自动开启"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"根据地点和时间适时切换到夜间模式"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"夜间模式开启时"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"对 Android 操作系统使用深色主题背景"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"调整色调"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"调整亮度"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"系统会将深色主题背景应用于 Android 操作系统的核心区域(通常以浅色主题背景显示),例如“设置”部分。"</string>
     <string name="color_apply" msgid="9212602012641034283">"应用"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"确认设置"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"部分颜色设置可能会导致此设备无法使用。请点击“确定”确认这些颜色设置,否则,系统将在 10 秒后重置这些设置。"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
-    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用节电助手"</string>
-    <string name="battery_detail_switch_title" msgid="6285872470260795421">"节电助手"</string>
+    <string name="battery_panel_title" msgid="7944156115535366613">"电池使用情况"</string>
+    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用省电模式"</string>
+    <string name="battery_detail_switch_title" msgid="6285872470260795421">"省电模式"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低性能并限制后台流量"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>按钮"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"返回"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"向上"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"中心"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"空格"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"退格"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"播放/暂停"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"下一曲"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"上一曲"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"快退"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"快进"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"向上翻页"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"向下翻页"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"删除"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"数字键盘 <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"系统"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主屏幕"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"在音量对话框中显示“请勿打扰”模式"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"允许在音量对话框中完全控制“请勿打扰”模式。"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量和“请勿打扰”设置"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"按音量调低键时进入“请勿打扰”模式"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"键盘快捷键"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切换输入法"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"应用"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"辅助应用"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"浏览器"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"通讯录"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"电子邮件"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即时通讯"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音乐"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日历"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"与音量控件一起显示"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"请勿打扰"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"音量按钮快捷键"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"按音量调高键时退出“请勿打扰”模式"</string>
     <string name="battery" msgid="7498329822413202973">"电池"</string>
     <string name="clock" msgid="7416090374234785905">"时钟"</string>
     <string name="headset" msgid="4534219457597457353">"耳机"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"已连接到耳机"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"已连接到耳机"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"指定在状态栏中显示或隐藏图标。"</string>
     <string name="data_saver" msgid="5037565123367048522">"流量节省程序"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"流量节省程序已开启"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"流量节省程序已关闭"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"开启"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"关闭"</string>
     <string name="nav_bar" msgid="1993221402773877607">"导航栏"</string>
     <string name="start" msgid="6873794757232879664">"顶部"</string>
     <string name="center" msgid="4327473927066010960">"中心位置"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"选择键盘按钮"</string>
     <string name="preview" msgid="9077832302472282938">"预览"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"拖动即可添加图块"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖动到此处即可移除"</string>
     <string name="qs_edit" msgid="2232596095725105230">"修改"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"时间"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"显示小时、分钟和秒"</item>
+    <item msgid="1427801730816895300">"显示小时和分钟(默认)"</item>
+    <item msgid="3830170141562534721">"不显示此图标"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"一律显示百分比"</item>
+    <item msgid="2139628951880142927">"充电时显示百分比(默认)"</item>
+    <item msgid="3327323682209964956">"不显示此图标"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"其他"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"分屏分隔线"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下移"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上移"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左移"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右移"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"应用可能无法在多窗口模式下正常运行"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。点按两次即可修改。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。点按两次即可添加。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。点按两次即可选择。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移动<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>添加到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"已移除<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>移至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快捷设置编辑器。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
new file mode 100644
index 0000000..77d3bff
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"关闭画中画"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"全屏"</string>
+    <string name="pip_play" msgid="674145557658227044">"播放"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"暂停"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"按住"<b>"主屏幕"</b>"按钮即可控制画中画功能"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"按住主屏幕按钮即可控制画中画功能"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"知道了"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"关闭"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 675d0f3..083cd5e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"由於儲存空間有限,或被應用程式或貴機構禁止,因此無法擷取螢幕擷圖。"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"儲存螢幕擷圖時發生問題。"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由於儲存空間有限,因此無法儲存螢幕擷取畫面。"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"此應用程式或您的機構禁止擷取螢幕畫面。"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"所有最近使用的應用程式均已關閉。"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知已關閉。"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"無法使用手電筒。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"工作模式已開啟。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"已關閉工作模式。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"已開啟工作模式。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"已關閉數據節省模式。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"已開啟數據節省模式。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"顯示光暗度"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"位置要求啟動中"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"通知設定"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>設定"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"螢幕會自動旋轉。"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限為 <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"您最近的螢幕顯示在這裡"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"沒有最近項目"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有項目"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"記錄"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」已在安全模式中停用。"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"此應用程式不支援多視窗模式"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"應用程式不支援多視窗模式"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"完全\n靜音"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅限\n優先"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅限\n鬧鐘"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"全部\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在緩慢充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"啟用分割畫面向上滑動加速工具"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上快速滑動手勢"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"從 [概覽] 按鈕向上快速滑動,即可使用手勢功能進入分割畫面模式"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"套用到「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」通知"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"套用到此應用程式的所有通知"</string>
+    <string name="show_silently" msgid="6841966539811264192">"顯示通知,但不發出音效"</string>
+    <string name="block" msgid="2734508760962682611">"封鎖所有通知"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"不設為靜音"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"不設為靜音或封鎖"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"顯示所有重要性設定"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"已封鎖"</string>
+    <string name="min_importance" msgid="1901894910809414782">"最低重要性"</string>
     <string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
     <string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
     <string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
     <string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"永不顯示這些通知"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"顯示在通知清單底部但不發出音效"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知但不發出音效"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂部並發出音效"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"不時於螢幕出現並發出音效"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"在通知清單底部顯示但不發出音效"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"顯示這些通知但不發出音效"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"允許這些通知發出音效"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"不時於螢幕出現並發出音效"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"在通知清單頂部顯示,並不時於螢幕出現及發出音效"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"一般色系"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"深沉色系"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"自動"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"不明色系"</string>
-    <string name="color_transform" msgid="6985460408079086090">"顏色修改"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"顯示「快速設定」圖塊"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"啟用自訂變色功能"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知控制項"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
+    <string name="night_mode" msgid="3540405868248625488">"夜間模式"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"校準螢幕"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"已開啟"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"已關閉"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"自動開啟"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"在適當的位置和時間切換至「夜間模式」"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"「夜間模式」開啟時"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"在 Android OS 中使用深色主題背景"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"調整色調"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"調整亮度"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"系統會將深色主題背景套用至 Android OS 核心區域 (一般以淺色主題背景顯示),例如「設定」。"</string>
     <string name="color_apply" msgid="9212602012641034283">"套用"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定會令此裝置無法使用。請按一下 [確定] 加以確認,否則這些顏色設定將於 10 秒後重設。"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"電池用量"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用「省電模式」"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"省電模式"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景數據傳輸"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 鍵"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"返回"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"向上"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"箭咀中央"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"空格"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"輸入 (Enter)"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"播放/暫停"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"下一首"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"上一首"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"倒帶"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"向前快轉"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"上一頁"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"下一頁"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"刪除"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"插入"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"數字鎖定"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"數字鍵盤 <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"系統"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近的活動"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"在音量對話框中顯示「請勿騷擾」設定"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"允許在音量對話框中全面控制「請勿騷擾」功能。"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量和「請勿騷擾」設定"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"調低音量時啟用「請勿騷擾」模式"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"鍵盤快速鍵"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切換輸入法"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"應用程式"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"輔助"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"瀏覽器"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"通訊錄"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"電郵"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即時通訊"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音樂"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日曆"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制一起顯示"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"請勿騷擾"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"調高音量時停用「請勿騷擾」模式"</string>
     <string name="battery" msgid="7498329822413202973">"電池"</string>
     <string name="clock" msgid="7416090374234785905">"時鐘"</string>
     <string name="headset" msgid="4534219457597457353">"耳機"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"已連接至耳機"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"已連接至耳機"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"顯示或隱藏狀態列上的圖示。"</string>
-    <string name="data_saver" msgid="5037565123367048522">"數據節省程式"</string>
-    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"數據節省程式已開啟"</string>
-    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"數據節省程式已關閉"</string>
+    <string name="data_saver" msgid="5037565123367048522">"數據節省模式"</string>
+    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"數據節省模式已開啟"</string>
+    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"數據節省模式已關閉"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"開啟"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"關閉"</string>
     <string name="nav_bar" msgid="1993221402773877607">"導覽列"</string>
     <string name="start" msgid="6873794757232879664">"畫面頂部"</string>
     <string name="center" msgid="4327473927066010960">"畫面中央"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"選取鍵盤按鈕"</string>
     <string name="preview" msgid="9077832302472282938">"預覽"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"拖曳即可新增圖塊"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖曳這裡即可移除"</string>
     <string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"時間"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"顯示小時、分鐘和秒"</item>
+    <item msgid="1427801730816895300">"顯示小時和分鐘 (預設)"</item>
+    <item msgid="3830170141562534721">"不顯示這個圖示"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"永遠顯示百分比"</item>
+    <item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
+    <item msgid="3327323682209964956">"不顯示這個圖示"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"其他"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"應用程式可能無法在多重視窗下運作"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。輕按兩下即可編輯。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。輕按兩下即可新增。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。輕按兩下即可選取。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移動 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已新增至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已移除"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已移至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速設定編輯工具。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
new file mode 100644
index 0000000..10c3141
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"關閉 PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"全螢幕"</string>
+    <string name="pip_play" msgid="674145557658227044">"播放"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"暫停"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"按住"<b>"主按鈕"</b>"即可控制 PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"按住主按鈕即可控制 PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"知道了"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"關閉"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 08cbb17..3c95a93 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -73,7 +73,9 @@
     <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="1260203058661337274">"由於儲存空間有限,或是遭到應用程式或貴機構禁止,因此無法擷取螢幕畫面。"</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"儲存螢幕擷圖時發生問題。"</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由於儲存空間有限,因此無法儲存螢幕擷取畫面。"</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"這個應用程式或貴機構禁止擷取螢幕畫面。"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近使用的應用程式已全部關閉。"</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已關閉通知。"</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"無法使用手電筒。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"工作模式已開啟。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"工作模式已關閉。"</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"工作模式已開啟。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Data Saver 已關閉。"</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Data Saver 已開啟。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"螢幕亮度"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據連線"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"有位置資訊要求"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"通知設定"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>設定"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"螢幕會自動旋轉。"</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限為 <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"您最近的螢幕會顯示在這裡"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"最近沒有任何項目"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有工作"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"紀錄"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」在安全模式中為停用狀態。"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"這個應用程式不支援多視窗模式"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"應用程式不支援多視窗模式"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"完全\n靜音"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅允許\n優先通知"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅允許\n鬧鐘"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"全部\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"快速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"慢速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"啟用分割畫面向上滑動加速工具"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上滑動手勢"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"啟用透過從 [總覽] 按鈕向上滑動的手勢進入分割畫面"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"套用到「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」通知"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"套用到這個應用程式的所有通知"</string>
+    <string name="show_silently" msgid="6841966539811264192">"顯示通知,但不發出任何音效"</string>
+    <string name="block" msgid="2734508760962682611">"封鎖所有通知"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"不設定靜音"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"不設定靜音或封鎖"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"顯示完整的重要性設定"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"封鎖"</string>
+    <string name="min_importance" msgid="1901894910809414782">"最低重要性"</string>
     <string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
     <string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
     <string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
     <string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"一律不顯示這些通知"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"顯示在通知清單底部且不發出任何音效"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知且不發出任何音效"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂端並發出音效"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"短暫顯示在螢幕上並發出音效"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"顯示在通知清單底端,但不發出任何音效"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"顯示這些通知,但不發出任何音效"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"允許這些通知發出音效"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"短暫顯示在畫面上並發出音效"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"顯示在通知清單頂端,同時短暫顯示在畫面上並發出音效"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"一般顏色"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"夜間顏色"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"自動"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"不明顏色"</string>
-    <string name="color_transform" msgid="6985460408079086090">"顏色修改"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"顯示快速設定圖塊"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"啟用自訂顏色變換"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知控制項"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
+    <string name="night_mode" msgid="3540405868248625488">"夜間模式"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"校正顯示畫面"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"開啟"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"關閉"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"自動開啟"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"根據地點和時段適時切換到「夜間模式」"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"「夜間模式」開啟時"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"針對 Android 作業系統使用深色主題"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"調整色調"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"調整亮度"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"深色主題會套用到 Android 作業系統的核心區塊 (一般是以淺色主題顯示),例如「設定」區塊。"</string>
     <string name="color_apply" msgid="9212602012641034283">"套用"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定可能會造成這部裝置無法使用。請按一下 [確定] 來確認您要使用這類顏色設定,否則系統將在 10 秒後重設這些設定。"</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"電池用量"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用節約耗電量模式"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"節約耗電量"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景資料傳輸"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 按鈕"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home 鍵"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"返回"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"向上鍵"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下鍵"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左鍵"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右鍵"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"中央鍵"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab 鍵"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"空格鍵"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter 鍵"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace 鍵"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"播放/暫停"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"下一個"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"上一個"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"倒轉"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"快轉"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up 鍵"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down 鍵"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete 鍵"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home 鍵"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End 鍵"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert 鍵"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock 鍵"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"數字鍵 <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"系統"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"近期活動"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"在音量對話方塊中顯示「零打擾」設定"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"在音量對話方塊中顯示完整的「零打擾」設定。"</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量和「零打擾」設定"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"按下調低音量鍵時啟用「零打擾」模式"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"鍵盤快速鍵"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切換輸入法"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"應用程式"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"小幫手"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"瀏覽器"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"聯絡人"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"電子郵件"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即時訊息"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音樂"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日曆"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制項一起顯示"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"零打擾"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"按下調高音量鍵時停用「零打擾」模式"</string>
     <string name="battery" msgid="7498329822413202973">"電池"</string>
     <string name="clock" msgid="7416090374234785905">"時鐘"</string>
     <string name="headset" msgid="4534219457597457353">"耳機"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"已與耳機連線"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"已與耳機連線"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"指定在狀態列中顯示或隱藏圖示。"</string>
     <string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver 已開啟"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver 已關閉"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"開啟"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"關閉"</string>
     <string name="nav_bar" msgid="1993221402773877607">"導覽列"</string>
     <string name="start" msgid="6873794757232879664">"畫面頂端"</string>
     <string name="center" msgid="4327473927066010960">"畫面中央"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"選取鍵盤按鍵"</string>
     <string name="preview" msgid="9077832302472282938">"預覽"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"拖曳即可新增圖塊"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖曳到這裡即可移除"</string>
     <string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"時間"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"顯示小時、分鐘和秒"</item>
+    <item msgid="1427801730816895300">"顯示小時和分鐘 (預設)"</item>
+    <item msgid="3830170141562534721">"不顯示這個圖示"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"一律顯示百分比"</item>
+    <item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
+    <item msgid="3327323682209964956">"不顯示這個圖示"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"其他"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"應用程式可能無法在多視窗模式下運作"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。輕按兩下即可編輯。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。輕按兩下即可新增。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。輕按兩下即可選取。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移動 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"已將 <xliff:g id="TILE_NAME">%1$s</xliff:g> 新增到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"已移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"已將 <xliff:g id="TILE_NAME">%1$s</xliff:g> 移到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速設定編輯器。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
new file mode 100644
index 0000000..4420d87
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"關閉子母畫面"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"全螢幕"</string>
+    <string name="pip_play" msgid="674145557658227044">"播放"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"暫停"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"按住「主畫面」"<b></b>"按鈕即可控制子母畫面"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"按住「主畫面」按鈕即可控制子母畫面"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"我知道了"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"關閉"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index df58a62..e03e642 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -73,7 +73,9 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Umfanekiso weskrini uqoshiwe"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Thinta ukubona imifanekiso yakho yeskrini"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Yehlulekile ukulondoloza umfanekiso weskrini."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Ayikwazi ukuthatha izithombe zesikrini ngenxa yesikhala sesitoreji esikhawulelwe ngohlelo lokusebenza noma inhlangano yakho."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Inkinga ivelile ngenkathi ilondoloza isithombe sikrini."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Ayikwazi ukulondoloza isithombe-skrini ngenxa yesikhala sesitoreji esikhawulelwe."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Ukuthatha izithombe-skrini akuvunyelwe uhlelo lokusebenza noma inhlangano yakho."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Okukhethwa kokudluliswa kwefayela ye-USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Lengisa njengesidlali semediya (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Lengisa ikhamera (PTP)"</string>
@@ -166,6 +168,8 @@
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Cashisa i-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ivaliwe."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Zonke izinhlelo zokusebenza zakamuva zicashisiwe."</string>
+    <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+    <skip />
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iqala i-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Isaziso sichithiwe."</string>
@@ -206,6 +210,7 @@
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Isikhathi esiningi."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Isikhathi esincane."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"I-Flashlight ivaliwe."</string>
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"I-Flashlight ayitholakali."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"I-Flashlight ivuliwe."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"I-Flashlight ivaliwe."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"I-Flashlight ivuliwe."</string>
@@ -218,6 +223,8 @@
     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Imodi yomsebenzi ivuliwe."</string>
     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Imodi yomsebenzi ivaliwe."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Imodi yomsebenzi ivuliwe."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Iseva yedatha ivaliwe."</string>
+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Iseva yedatha ivuliwe."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bonisa ukukhanya"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G idatha imisiwe"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
@@ -231,6 +238,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Indawo ihlelwe i-GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Izicelo zendawo ziyasebenza"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Susa zonke izaziso."</string>
+    <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Izilungiselelo zesaziso"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> izilungiselelo"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Isikrini sizophenduka ngokuzenzakalela."</string>
@@ -296,15 +304,16 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> umkhawulo"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Imodi yomsebenzi"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Izikrini zakho zakamuva zivela lapha"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Azikho izinto zakamuva"</string>
+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Usule yonke into"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ukuphina isikrini"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ayikwazanga ukuqala i-<xliff:g id="APP">%s</xliff:g>."</string>
-    <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
-    <skip />
-    <string name="recents_history_button_label" msgid="5153358867807604821">"Umlando"</string>
-    <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Sula"</string>
+    <string name="recents_launch_disabled_message" msgid="1624523193008871793">"I-<xliff:g id="APP">%s</xliff:g> ikhutshaziwe kumodi yokuphepha."</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Sula konke"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Lolu hlelo lokusebenza alusekeli amawindi amaningi"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Uhlelo lokusebenza alusekeli amawindi amaningi"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Hlukanisa okumile"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Hlukanisa kwezifiso"</string>
@@ -334,8 +343,6 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Ukuthula\niokuphelele"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Okubalulekile\nkuphela"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ama-alamu\nkuphela"</string>
-    <string name="interruption_level_all" msgid="1330581184930945764">"Konke"</string>
-    <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Konke\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Iyashaja ngokushesha (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Iyashaja kancane (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
@@ -448,61 +455,107 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
-    <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Nika amandla isisheshisi sokuhlukanisa isikrini sokuswayiphela phezulu"</string>
+    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Nika amandla ukuthinta kokuswayiphela phezulu ukuhlukanisa isikrini"</string>
     <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Nika amandla ukuthinta ukuze ungene ekuhlukaniseni isikrini ngokuswayiphela phezulu kusukela kunkinobho yokubuka konke"</string>
     <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vula"</string>
-    <string name="apply_to_topic" msgid="3641403489318659666">"Sebenzisa kuzaziso ze-<xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
-    <string name="apply_to_app" msgid="363016783939815960">"Sebenzisa kuzo zonke izaziso ezivela kulolu hlelo lokusebenza"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Bonisa izaziso ngokuthulile"</string>
+    <string name="block" msgid="2734508760962682611">"Vimbela zonke izaziso"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ungathulisi"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ungathulisi noma uvimbele"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Bonisa izilungiselelo ezibalulekile ezigcwele"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Kuvinjelwe"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Okubaluleke kancane"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ukubaluleka okuphansi"</string>
     <string name="default_importance" msgid="8192107689995742653">"Ukubaluleka okujwayelekile"</string>
     <string name="high_importance" msgid="1527066195614050263">"Ukubaluleka okuphezulu"</string>
     <string name="max_importance" msgid="5089005872719563894">"Ukubaluleka okusheshayo"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ungalokothi ubonise lezi zaziso"</string>
-    <string name="notification_importance_low" msgid="4383563267370859725">"Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
-    <string name="notification_importance_default" msgid="4926529615920610817">"Bonisa ngokuthulile lezi zaziso"</string>
-    <string name="notification_importance_high" msgid="3222680136612408223">"Bonisa ngaphezulu kohlu lwezaziso uphinde wenze umsindo"</string>
-    <string name="notification_importance_max" msgid="5236987171904756134">"Bheka kusikrini uphinde wenze umsindo"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Bonisa ngokuthulile lezi zaziso"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Vumela lezi zaziso ukwenza umsindo"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Beka kusikrini futhi uvumele umsindo"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Bonisa phezulu kohlu lwezaziso, beka phezu kwesikrini futhi uvumele umsindo"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
-    <string name="color_matrix_none" msgid="2121957926040543148">"Imibala ejwayelekile"</string>
-    <string name="color_matrix_night" msgid="5943817622105307072">"Imibala yasebusuku"</string>
-    <string name="color_matrix_custom" msgid="3655576492322298713">"Imibala yangokwezifiso"</string>
-    <string name="color_matrix_auto" msgid="4896624757412029265">"Okuzenzakalelayo"</string>
-    <string name="color_matrix_unknown" msgid="2709202104256265107">"Imibala engaziwa"</string>
-    <string name="color_transform" msgid="6985460408079086090">"Ukulungiswa kombala"</string>
-    <string name="color_matrix_show_qs" msgid="1763244354399276679">"Bonisa ithayili lezilungiselelo ezisheshayo"</string>
-    <string name="color_enable_custom" msgid="6729001308217347501">"Nika amandla ukuguqulwa kwangokwezifiso"</string>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> izilawuli zasaziso"</string>
+    <string name="color_and_appearance" msgid="1254323855964993144">"Umbala nokubonakala"</string>
+    <string name="night_mode" msgid="3540405868248625488">"Imodi yasebusuku"</string>
+    <string name="calibrate_display" msgid="5974642573432039217">"Sika isibonisi"</string>
+    <string name="night_mode_on" msgid="5597545513026541108">"Vuliwe"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Valiwe"</string>
+    <string name="turn_on_automatically" msgid="4167565356762016083">"Vula ngokuzenzakalela"</string>
+    <string name="turn_on_auto_summary" msgid="2190994512406701520">"Shintshela kwimodi yasebusuku njengokuqondile ngendawo nesikhathi sosuku"</string>
+    <string name="when_night_mode_on" msgid="2969436026899172821">"Uma imodi yasebusuku ivulekile"</string>
+    <string name="use_dark_theme" msgid="2900938704964299312">"Sebenzisa ingqikithi emnyama ku-Android OS"</string>
+    <string name="adjust_tint" msgid="3398569573231409878">"Lungisa i-tint"</string>
+    <string name="adjust_brightness" msgid="980039329808178246">"Lungisa ukukhanya"</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Itimu emnyama isetshenziswa ezindaweni eziqinile ze-Android OS ezivamise ukuoniswa ngetimu ekhanyayo, efana nezilungiselelo."</string>
     <string name="color_apply" msgid="9212602012641034283">"Sebenzisa"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Qinisekisa izilungiselelo"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Ezinye izilungiselelo zombala zingenza le divayisi ingasebenziseki. Chofoza ku-KULUNGILE ukuze uqinisekise lezi zilungiselelo zombala, uma kungenjalo lezi zilungiselelo zizosethwa kabusha ngemuva kwamasekhondi angu-10."</string>
-    <!-- no translation found for battery_panel_title (7944156115535366613) -->
-    <skip />
+    <string name="battery_panel_title" msgid="7944156115535366613">"Ukusetshenziswa kwebhethri"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Isilondolozi sebhethri asitholakali ngesikhathi sokushaja"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Isilondolozi sebhethri"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sehlisa ukusebenza nedatha yasemuva"</string>
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"Inkinobho <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Ekhaya"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Emuva"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Phezulu"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Phansi"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Kwesobunxele"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Kwesokudla"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Maphakathi"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Ithebhu"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Isikhala"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Faka"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Isikhala"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Dlala/Misa okwesikhashana"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Misa"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Okulandelayo"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Okwangaphambilini"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Buyisela emuva"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Iya phambili ngokushesha"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Ikhasi phezulu"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Ikhasi phansi"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Susa"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Ekhaya"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Phelisa"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Faka"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Izinombolo"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Phedi yezinombolo <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Isistimu"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekhaya"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Okwakamuva"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Emuva"</string>
-    <string name="tuner_full_zen_title" msgid="5905081395132280054">"Bonisa ukungaphazamisi kuvolumu"</string>
-    <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Vumela ulawulo olugcwele lokungaphazamisi kungxoxo yevolumu."</string>
-    <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ivolumu nokungaphazamisi"</string>
-    <string name="volume_down_silent" msgid="66962568467719591">"Faka ukungaphazamisi ekwehliseni ivolumu"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Izaziso"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Izinqamulelo Zekhibhodi"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Shintsha indlela yokufaka"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Izinhlelo zokusebenza"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Siza"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Isiphequluli"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Oxhumana nabo"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"I-imeyili"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"I-IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Umculo"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"I-YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Ikhalenda"</string>
+    <string name="tuner_full_zen_title" msgid="4540823317772234308">"Bonisa ngezilawuli zevolomu"</string>
+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ungaphazamisi"</string>
+    <string name="volume_dnd_silent" msgid="4363882330723050727">"Izinqamuleli zezinkinobho zevolomu"</string>
     <string name="volume_up_silent" msgid="7141255269783588286">"Phuma kokuthi ungaphazamisi ekukhuphuleni ivolumu"</string>
     <string name="battery" msgid="7498329822413202973">"Ibhethri"</string>
     <string name="clock" msgid="7416090374234785905">"Iwashi"</string>
     <string name="headset" msgid="4534219457597457353">"Ama-earphone"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Amahedfoni axhunyiwe"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Ama-earphone axhunyiwe"</string>
-    <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Nika amandla noma khubaza izithonjana kusukela ekubonisweni kubha yesimo."</string>
     <string name="data_saver" msgid="5037565123367048522">"Iseva yedatha"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Iseva yedatha ivuliwe"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Iseva yedatha ivaliwe"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Vuliwe"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Valiwe"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Ibha yokuzula"</string>
     <string name="start" msgid="6873794757232879664">"Qala"</string>
     <string name="center" msgid="4327473927066010960">"Maphakathi"</string>
@@ -524,5 +577,33 @@
     <string name="select_keycode" msgid="7413765103381924584">"Khetha inkinobho yekhibhodi"</string>
     <string name="preview" msgid="9077832302472282938">"Hlola kuqala"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Hudula ukuze ungeze amathayili"</string>
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Hudulela lapha ukuze ususe"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Hlela"</string>
+    <string name="tuner_time" msgid="6572217313285536011">"Isikhathi"</string>
+  <string-array name="clock_options">
+    <item msgid="5965318737560463480">"Bonisa amahora, amaminithi, namasekhondi"</item>
+    <item msgid="1427801730816895300">"Bonisa amahora namaminithi (okuzenzakalelayo)"</item>
+    <item msgid="3830170141562534721">"Ungabonisi lesi sithonjana"</item>
+  </string-array>
+  <string-array name="battery_options">
+    <item msgid="3160236755818672034">"Njlalo bonisa iphesentheji"</item>
+    <item msgid="2139628951880142927">"Bonisa iphesentheji uma ishaja (okuzenzakalelayo)"</item>
+    <item msgid="3327323682209964956">"Ungabonisi lesi sithonjana"</item>
+  </string-array>
+    <string name="other" msgid="4060683095962566764">"Okunye"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Isihlukanisi sokuhlukanisa isikrini"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Iya phansi"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Iya phezulu"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Iya kwesokunxele"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Iya kwesokudla"</string>
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Uhlelo lokusebenza kungenzeka lungasebenzi namawindi amaningi"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Isimo esingu-<xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Thepha kabili ukuze uhlele."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Thepha kabili ukuze ungeze."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Isimo esingu-<xliff:g id="POSITION">%1$d</xliff:g>. Thepha kabili ukuze ukhethe."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Hambisa i-<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Susa i-<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> ingezwe kusimo esingu-<xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> isusiwe"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> ihanjiswe kusimo esingu-<xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Isihleli sezilungiselelo ezisheshayo."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
new file mode 100644
index 0000000..1904237
--- /dev/null
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_close" msgid="3480680679023423574">"Vala i-PIP"</string>
+    <string name="pip_fullscreen" msgid="8604643018538487816">"Iskrini esigcwele"</string>
+    <string name="pip_play" msgid="674145557658227044">"Dlala"</string>
+    <string name="pip_pause" msgid="8412075640017218862">"Misa isikhashana"</string>
+    <string name="pip_hold_home" msgid="340086535668778109">"Bamba "<b>"IKHAYA"</b>" ukuze ulawule i-PIP"</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Cindezela futhi ubambe inkinobho EKHAYA ukuze ulawule i-PIP"</string>
+    <string name="pip_onboarding_button" msgid="3957426748484904611">"Ngiyezwa"</string>
+    <string name="recents_tv_dismiss" msgid="3555093879593377731">"Cashisa"</string>
+</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 19bc755..1e979fd 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -85,12 +85,17 @@
         <attr name="ignoreRightInset" format="boolean" />
     </declare-styleable>
 
-    <declare-styleable name="AlphaOptimizedImageView">
+    <declare-styleable name="AnimatedImageView">
         <attr name="hasOverlappingRendering" format="boolean" />
     </declare-styleable>
 
     <declare-styleable name="TunerSwitch">
         <attr name="defValue" format="boolean" />
+        <attr name="metricsAction" format="integer" />
+    </declare-styleable>
+
+    <declare-styleable name="DensityContainer">
+        <attr name="android:layout" />
     </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 8f69bbb..b9aa26b 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -31,7 +31,7 @@
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
     <color name="system_primary_color">#ff263238</color><!-- blue grey 900 -->
-    <color name="system_secondary_color">#ff384248</color>
+    <color name="system_secondary_color">#ff37474F</color><!-- blue grey 800 -->
     <color name="system_accent_color">#ff80CBC4</color><!-- deep teal 200 -->
     <color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
     <color name="qs_text">#FFFFFFFF</color>
@@ -63,7 +63,7 @@
     <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
     <color name="recents_task_bar_dark_text_color">#cc000000</color>
     <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
-    <color name="recents_task_bar_light_icon_color">#ffeeeeee</color>
+    <color name="recents_task_bar_light_icon_color">#ccffffff</color>
     <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
     <color name="recents_task_bar_dark_icon_color">#99000000</color>
     <!-- The lock to task button background color. -->
@@ -79,7 +79,7 @@
     <color name="notification_legacy_background_color">#ff1a1a1a</color>
 
     <!-- The color of the material notification background -->
-    <color name="notification_material_background_color">#ffffffff</color>
+    <color name="notification_material_background_color">@*android:color/notification_material_background_color</color>
 
     <!-- The color of the material notification background when dimmed -->
     <color name="notification_material_background_dimmed_color">#ccffffff</color>
@@ -151,9 +151,12 @@
 
     <color name="docked_divider_background">#ff000000</color>
     <color name="docked_divider_handle">#ffffff</color>
+    <drawable name="forced_resizable_background">#80000000</drawable>
 
     <color name="default_remote_input_background">@*android:color/notification_default_color</color>
-    <color name="remote_input_hint">#4dffffff</color>
+    <color name="remote_input_hint">#99ffffff</color>
+
+    <color name="remote_input_accent">#eeeeee</color>
 
     <color name="qs_tile_tint_unavailable">#40ffffff</color>
     <color name="qs_tile_tint_inactive">#4dffffff</color>
@@ -165,4 +168,8 @@
     <!-- Keyboard shortcuts colors -->
     <color name="ksh_system_group_color">#ff00bcd4</color>
     <color name="ksh_application_group_color">#fff44336</color>
+    <color name="ksh_keyword_color">#d9000000</color>
+
+    <!-- Background color of edit overflow -->
+    <color name="qs_edit_overflow_bg">#455A64</color>
 </resources>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 6f4c983..4126d3c 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -18,7 +18,6 @@
 -->
 <resources>
     <color name="recents_tv_card_background_color">#FF37474F</color>
-    <color name="recents_tv_card_title_text_color">#FFEEEEEE</color>
-    <color name="recents_tv_card_content_text_color">#99EEEEEE</color>
-    <color name="recents_tv_card_source_text_color">#99EEEEEE</color>
+    <color name="recents_tv_card_title_text_color">#CCEEEEEE</color>
+    <color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 4e1680d..6ce2a5d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -86,9 +86,6 @@
 
     <bool name="config_dead_zone_flash">false</bool>
 
-    <!-- Min alpha % that recent items will fade to while being dismissed -->
-    <integer name="config_recent_item_min_alpha">3</integer>
-
     <!-- Whether QuickSettings is in a phone landscape -->
     <bool name="quick_settings_wide">false</bool>
 
@@ -156,6 +153,9 @@
     <!-- The animation duration for animating the removal of a task view. -->
     <integer name="recents_animate_task_view_remove_duration">175</integer>
 
+    <!-- The base animation duration for animating the removal of all task views. -->
+    <integer name="recents_animate_task_views_remove_all_duration">300</integer>
+
     <!-- The animation duration for scrolling the stack to a particular item. -->
     <integer name="recents_animate_task_stack_scroll_duration">200</integer>
 
@@ -165,9 +165,6 @@
     <!-- The animation duration for subsequent scrolling the stack to a particular item. -->
     <integer name="recents_subsequent_auto_advance_duration">1000</integer>
 
-    <!-- The animation duration for entering and exiting the history. -->
-    <integer name="recents_history_transition_duration">250</integer>
-
     <!-- The delay to enforce between each alt-tab key press. -->
     <integer name="recents_alt_tab_key_delay">200</integer>
 
@@ -181,7 +178,7 @@
     <!-- Recents: The relative range of visible tasks from the current scroll position
          while the stack is focused. -->
     <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
-    <item name="recents_layout_focused_range_max" format="float" type="integer">3</item>
+    <item name="recents_layout_focused_range_max" format="float" type="integer">2</item>
 
     <!-- Recents: The relative range of visible tasks from the current scroll position
          while the stack is not focused. -->
diff --git a/packages/SystemUI/res/values/config_tv.xml b/packages/SystemUI/res/values/config_tv.xml
new file mode 100644
index 0000000..22b7578
--- /dev/null
+++ b/packages/SystemUI/res/values/config_tv.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+         when the PIP menu is shown in center. -->
+    <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
+
+    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+         when the PIP is shown in Recents without focus. -->
+    <string translatable="false" name="pip_recents_bounds">"800 54 1120 234"</string>
+
+    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+         when the PIP is shown in Recents with focus. -->
+    <string translatable="false" name="pip_recents_focused_bounds">"775 54 1145 262"</string>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ee61e00..c094da9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -58,19 +58,19 @@
     <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
 
     <!-- Height of a small notification in the status bar-->
-    <dimen name="notification_min_height">86dp</dimen>
+    <dimen name="notification_min_height">92dp</dimen>
 
     <!-- Height of a small notification in the status bar which was used before android N -->
     <dimen name="notification_min_height_legacy">64dp</dimen>
 
     <!-- Height of a large notification in the status bar -->
-    <dimen name="notification_max_height">276dp</dimen>
+    <dimen name="notification_max_height">284dp</dimen>
 
     <!-- Height of a heads up notification in the status bar for legacy custom views -->
     <dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
 
     <!-- Height of a heads up notification in the status bar -->
-    <dimen name="notification_max_heads_up_height">141dp</dimen>
+    <dimen name="notification_max_heads_up_height">148dp</dimen>
 
     <!-- Height of a the summary ("more card") notification on keyguard. -->
     <dimen name="notification_summary_height">44dp</dimen>
@@ -174,12 +174,13 @@
     <dimen name="qs_tile_margin">16dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
-    <dimen name="qs_date_anim_translation">36dp</dimen>
-    <dimen name="qs_date_alarm_anim_translation">26dp</dimen>
+    <dimen name="qs_date_anim_translation">32dp</dimen>
+    <dimen name="qs_date_alarm_anim_translation">22dp</dimen>
     <dimen name="qs_date_collapsed_text_size">14sp</dimen>
     <dimen name="qs_date_text_size">16sp</dimen>
-    <dimen name="qs_header_gear_translation">150dp</dimen>
-    <dimen name="qs_page_indicator_size">12dp</dimen>
+    <dimen name="qs_header_gear_translation">16dp</dimen>
+    <dimen name="qs_page_indicator_width">16dp</dimen>
+    <dimen name="qs_page_indicator_height">8dp</dimen>
     <dimen name="qs_tile_icon_size">24dp</dimen>
     <dimen name="qs_tile_text_size">12sp</dimen>
     <dimen name="qs_tile_divider_height">1dp</dimen>
@@ -203,6 +204,7 @@
     <dimen name="qs_data_usage_text_size">14sp</dimen>
     <dimen name="qs_data_usage_usage_text_size">36sp</dimen>
     <dimen name="qs_expand_margin">0dp</dimen>
+    <dimen name="qs_battery_padding">2dp</dimen>
 
     <dimen name="segmented_button_spacing">0dp</dimen>
     <dimen name="borderless_button_radius">2dp</dimen>
@@ -233,76 +235,6 @@
     <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
     <dimen name="glowpadview_inner_radius">15dip</dimen>
 
-    <!-- The size of the icon in the recents task view header. -->
-    <dimen name="recents_task_view_header_icon_width">64dp</dimen>
-    <dimen name="recents_task_view_header_icon_height">@dimen/recents_task_bar_height</dimen>
-
-    <!-- The size of a button in the recents task view header. -->
-    <dimen name="recents_task_view_header_button_width">@dimen/recents_task_bar_height</dimen>
-    <dimen name="recents_task_view_header_button_height">@dimen/recents_task_bar_height</dimen>
-
-    <!-- The radius of the rounded corners on a task view. -->
-    <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
-    <!-- The radius of the rounded corners on a task view's shadow. -->
-    <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen>
-
-    <!-- The min translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_min">3dp</dimen>
-
-    <!-- The max translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_max">24dp</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 highlight to make on each task view. -->
-    <dimen name="recents_task_view_highlight">1dp</dimen>
-
-    <!-- The amount to offset when animating into an affiliate group. -->
-    <dimen name="recents_task_view_affiliate_group_enter_offset">32dp</dimen>
-
-    <!-- The height of a task view bar. -->
-    <dimen name="recents_task_bar_height">56dp</dimen>
-
-    <!-- The height of the search bar space. -->
-    <dimen name="recents_search_bar_space_height">64dp</dimen>
-
-    <!-- The overscroll percentage allowed on the stack. -->
-    <item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item>
-
-    <!-- The top padding for the task stack. -->
-    <dimen name="recents_stack_top_padding">16dp</dimen>
-
-    <!-- The side padding for the task stack. -->
-    <dimen name="recents_stack_left_right_padding">16dp</dimen>
-
-    <!-- The dimesnsions of the dismiss all recents button. -->
-    <dimen name="recents_dismiss_all_button_size">48dp</dimen>
-
-    <!-- The min alpha to apply to a task affiliation group color. -->
-    <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
-
-    <!-- The size of the lock-to-app button. -->
-    <dimen name="recents_lock_to_app_size">56dp</dimen>
-
-    <!-- The size of the lock-to-app button icon. -->
-    <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
-
-    <!-- The amount to allow the stack to overscroll. -->
-    <dimen name="recents_stack_overscroll">24dp</dimen>
-
-    <!-- The size of the peek area at the top of the stack (below the status bar). -->
-    <dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen>
-
-    <!-- The size of each task peek area at the bottom of the stack (above the nav bar). -->
-    <dimen name="recents_layout_focused_bottom_task_peek_size">16dp</dimen>
-
-    <!-- The height of the history button. -->
-    <dimen name="recents_history_button_height">48dp</dimen>
-
-    <!-- The padding between freeform workspace tasks -->
-    <dimen name="recents_freeform_workspace_task_padding">8dp</dimen>
-
     <!-- Space reserved for the cards behind the top card in the bottom stack -->
     <dimen name="bottom_stack_peek_amount">12dp</dimen>
 
@@ -325,9 +257,6 @@
     <!-- The minimum amount of top overscroll to go to the quick settings. -->
     <dimen name="min_top_overscroll_to_qs">36dp</dimen>
 
-    <!-- The padding to the second card when the notifications collapse. -->
-    <dimen name="notification_collapse_second_card_padding">8dp</dimen>
-
     <!-- The height of the speed bump view. -->
     <dimen name="speed_bump_height">16dp</dimen>
 
@@ -351,8 +280,8 @@
 
     <!-- The margin between the clock and the notifications on Keyguard. See
          keyguard_clock_height_fraction_* for the difference between min and max.-->
-    <dimen name="keyguard_clock_notifications_margin_min">24dp</dimen>
-    <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_min">30dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_max">42dp</dimen>
     <dimen name="heads_up_scrim_height">250dp</dimen>
 
     <!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
@@ -390,9 +319,6 @@
     <!-- The padding on top of the first notification to the children container -->
     <dimen name="notification_children_container_top_padding">8dp</dimen>
 
-    <!-- The vertical distance from which the notification appear when children are expanded -->
-    <dimen name="notification_appear_distance">140dp</dimen>
-
     <!-- end margin for multi user switch in expanded quick settings -->
     <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
 
@@ -528,6 +454,13 @@
 
     <dimen name="battery_margin_bottom">0dp</dimen>
 
+    <!-- Padding at the end of the view that displays the mobile signal icons. If the view is
+         empty, then this padding will not be added to that view. -->
+    <dimen name="mobile_signal_group_end_padding">0dp</dimen>
+
+    <!-- Padding between the mobile data type and the strength indicator. -->
+    <dimen name="mobile_data_icon_start_padding">0dp</dimen>
+
     <!-- Extra padding between the mobile data type icon and the strength indicator when the data
          type icon is wide. -->
     <dimen name="wide_type_icon_start_padding">2dp</dimen>
@@ -625,4 +558,88 @@
 
     <dimen name="battery_detail_graph_space_top">27dp</dimen>
     <dimen name="battery_detail_graph_space_bottom">27dp</dimen>
+
+    <!-- Keyboard shortcuts helper -->
+    <dimen name="ksh_layout_width">@dimen/match_parent</dimen>
+
+<!-- Recents Layout -->
+
+    <!-- The amount to inset the stack, specifically at the top and the other sides.  We also
+         don't want this to change across configurations that Recents can be opened in, so we
+         define them statically for all display sizes. -->
+    <dimen name="recents_layout_min_margin">16dp</dimen>
+    <dimen name="recents_layout_top_margin_phone">16dp</dimen>
+    <dimen name="recents_layout_top_margin_tablet">32dp</dimen>
+    <dimen name="recents_layout_top_margin_tablet_xlarge">40dp</dimen>
+    <dimen name="recents_layout_bottom_margin">16dp</dimen>
+    <dimen name="recents_layout_side_margin_phone">16dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet">48dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet_docked">16dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet_xlarge">64dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet_xlarge_docked">16dp</dimen>
+
+    <!-- The height between the top margin and the top of the focused task. -->
+    <dimen name="recents_layout_top_peek_size">48dp</dimen>
+    <!-- The height between the bottom margin and the top of task in front of the focused task. -->
+    <dimen name="recents_layout_bottom_peek_size">56dp</dimen>
+
+    <!-- The offset from the top and bottom of the stack of the focused task.  The bottom offset
+         will be additionally offset by the bottom system insets since it goes under the nav bar
+         in certain orientations. -->
+    <dimen name="recents_layout_initial_top_offset_phone_port">128dp</dimen>
+    <dimen name="recents_layout_initial_bottom_offset_phone_port">80dp</dimen>
+    <dimen name="recents_layout_initial_top_offset_phone_land">72dp</dimen>
+    <dimen name="recents_layout_initial_bottom_offset_phone_land">72dp</dimen>
+    <dimen name="recents_layout_initial_top_offset_tablet">160dp</dimen>
+    <dimen name="recents_layout_initial_bottom_offset_tablet">112dp</dimen>
+
+    <!-- The min/max translationZ for the tasks in the stack. -->
+    <dimen name="recents_layout_z_min">3dp</dimen>
+    <dimen name="recents_layout_z_max">24dp</dimen>
+
+    <!-- The margin between the freeform and stack.  We also don't want this to change across 
+         configurations that Recents can be opened in, so we define them statically for all 
+         display sizes. -->
+    <dimen name="recents_freeform_layout_bottom_margin">16dp</dimen>
+
+    <!-- The padding between each freeform task. -->
+    <dimen name="recents_freeform_layout_task_padding">8dp</dimen>
+
+<!-- Recents Views -->
+
+    <!-- The height of a task view bar.  This has to be large enough to cover the action bar
+         height in either orientation at this smallest width. -->
+    <dimen name="recents_task_view_header_height">56dp</dimen>
+    <dimen name="recents_task_view_header_height_tablet_land">64dp</dimen>
+
+    <!-- The padding of a button in the recents task view header. -->
+    <dimen name="recents_task_view_header_button_padding">16dp</dimen>
+    <dimen name="recents_task_view_header_button_padding_tablet_land">20dp</dimen>
+
+    <!-- The radius of the rounded corners on a task view and its shadow (which can be larger
+         to create a softer corner effect. -->
+    <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
+    <dimen name="recents_task_view_shadow_rounded_corners_radius">6dp</dimen>
+
+    <!-- The amount of highlight to make on each task view. -->
+    <dimen name="recents_task_view_highlight">1dp</dimen>
+
+    <!-- The size of the lock-to-app button and its icon. -->
+    <dimen name="recents_lock_to_app_size">56dp</dimen>
+    <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
+
+    <!-- The amount of overscroll allowed when flinging to the end of the stack. -->
+    <dimen name="recents_fling_overscroll_distance">24dp</dimen>
+
+    <!-- The min alpha to apply to a task affiliation group color. -->
+    <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
+
+    <!-- The amount to offset when animating into an affiliate group. -->
+    <dimen name="recents_task_stack_animation_affiliate_enter_offset">32dp</dimen>
+
+    <!-- The offsets the tasks animate from when recents is launched while docking -->
+    <dimen name="recents_task_stack_animation_launched_while_docking_offset">144dp</dimen>
+
+    <!-- The amount to translate when animating the removal of a task. -->
+    <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 77605bd..4e6a4b1 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -18,17 +18,43 @@
 -->
 <resources>
     <!-- Dimens for recents card in the recents view on tv -->
-    <dimen name="recents_tv_card_width">150dip</dimen>
-    <dimen name="recents_tv_card_height">85dip</dimen>
-    <dimen name="recents_tv_card_extra_badge_size">16dip</dimen>
+    <dimen name="recents_tv_card_width">240dip</dimen>
+    <dimen name="recents_tv_screenshot_height">135dip</dimen>
+    <dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
+    <dimen name="recents_tv_banner_width">114dip</dimen>
+    <dimen name="recents_tv_banner_height">64dip</dimen>
+    <dimen name="recents_tv_banner_margin_top">16dip</dimen>
+    <dimen name="recents_tv_icon_padding_bottom">8dip</dimen>
+    <dimen name="recents_tv_icon_padding_end">12dip</dimen>
+    <dimen name="recents_tv_text_padding_bottom">12dip</dimen>
 
     <!-- Padding for grid view in recents view on tv -->
-    <dimen name="recents_tv_grid_row_padding">56dip</dimen>
-    <dimen name="recents_tv_gird_row_top_padding">57dip</dimen>
-    <dimen name="recents_tv_grid_max_row_height">200dip</dimen>
+    <dimen name="recents_tv_gird_row_top_margin">215dip</dimen>
+    <dimen name="recents_tv_grid_max_row_height">268dip</dimen>
     <dimen name="recents_tv_gird_card_spacing">8dip</dimen>
+    <dimen name="recents_tv_gird_focused_card_delta">44dip</dimen>
 
     <!-- Values for focus animation -->
     <dimen name="recents_tv_unselected_item_z">6dp</dimen>
     <dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
-</resources>
\ No newline at end of file
+
+    <!-- Values for text on recents cards on tv -->
+    <dimen name="recents_tv_title_text_size">12sp</dimen>
+
+    <!-- Values for card dismiss state -->
+    <dimen name="recents_tv_dismiss_shift_down">48dip</dimen>
+    <dimen name="recents_tv_dismiss_top_margin">356dip</dimen>
+    <dimen name="recents_tv_dismiss_icon_size">24dip</dimen>
+    <dimen name="recents_tv_dismiss_icon_top_margin">38dip</dimen>
+    <dimen name="recents_tv_dismiss_icon_bottom_margin">1dip</dimen>
+    <dimen name="recents_tv_dismiss_text_size">12sp</dimen>
+
+    <!-- Values for PIP in recents -->
+    <dimen name="recents_tv_pip_controls_margin_top">10dp</dimen>
+
+    <!-- Extra space around the PIP and its outline in PIP onboarding activity  -->
+    <dimen name="tv_pip_bounds_space">3dp</dimen>
+    <!-- Extra space around the PIP control button icon to match with the focused circle -->
+    <dimen name="tv_pip_button_icon_padding">5dp</dimen>
+
+</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 87aedab..9697ea6 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -44,6 +44,11 @@
     <item type="id" name="notification_screenshot"/>
     <item type="id" name="notification_hidden"/>
     <item type="id" name="notification_volumeui"/>
+    <item type="id" name="transformation_start_x_tag"/>
+    <item type="id" name="transformation_start_y_tag"/>
+    <item type="id" name="transformation_start_scale_x_tag"/>
+    <item type="id" name="transformation_start_scale_y_tag"/>
+    <item type="id" name="custom_background_color"/>
 
     <!-- Whether the icon is from a notification for which targetSdk < L -->
     <item type="id" name="icon_is_pre_L"/>
@@ -56,5 +61,11 @@
     <item type="id" name="image_icon_tag" />
     <item type="id" name="contains_transformed_view" />
     <item type="id" name="is_clicked_heads_up_tag" />
+
+    <!-- Accessibility actions for the docked stack divider -->
+    <item type="id" name="action_move_left" />
+    <item type="id" name="action_move_right" />
+    <item type="id" name="action_move_up" />
+    <item type="id" name="action_move_down" />
 </resources>
 
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
index bfd8f8b..20cd330 100644
--- a/packages/SystemUI/res/values/integers_tv.xml
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -15,4 +15,7 @@
 -->
 <resources>
     <integer name="item_scale_anim_duration">150</integer>
-</resources>
\ No newline at end of file
+    <integer name="dismiss_short_duration">200</integer>
+    <integer name="dismiss_long_duration">400</integer>
+    <integer name="recents_tv_pip_focus_anim_duration">200</integer>
+</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0bd7c4e..060e050 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -185,8 +185,12 @@
     <string name="screenshot_saved_text">Touch to view your screenshot.</string>
     <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
     <string name="screenshot_failed_title">Couldn\'t capture screenshot.</string>
+    <!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] -->
+    <string name="screenshot_failed_to_save_unknown_text">Problem encountered while saving screenshot.</string>
+    <!-- Notification text displayed when we fail to save a screenshot. [CHAR LIMIT=100] -->
+    <string name="screenshot_failed_to_save_text">Can\'t save screenshot due to limited storage space.</string>
     <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
-    <string name="screenshot_failed_text">Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organization.</string>
+    <string name="screenshot_failed_to_capture_text">Taking screenshots is not allowed by the app or your organization.</string>
 
     <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
     <string name="usb_preference_title">USB file transfer options</string>
@@ -413,6 +417,8 @@
     <string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
     <!-- Content description to tell the user all applications has been removed from recents -->
     <string name="accessibility_recents_all_items_dismissed">All recent applications dismissed.</string>
+    <!-- Content description to tell the user that this button will open application info for an application in recents -->
+    <string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string>
     <!-- Content description to tell the user an application has been launched from recents -->
     <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Content description of individual recents task. -->
@@ -495,6 +501,8 @@
     <string name="accessibility_quick_settings_less_time">Less time.</string>
     <!-- Content description of the flashlight tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_flashlight_off">Flashlight off.</string>
+    <!-- Content description of the flashlight tile in quick settings when unavailable (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_flashlight_unavailable">Flashlight unavailable.</string>
     <!-- Content description of the flashlight tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_flashlight_on">Flashlight on.</string>
     <!-- Announcement made when the flashlight state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -519,6 +527,10 @@
     <string name="accessibility_quick_settings_work_mode_changed_off">Work mode turned off.</string>
     <!-- Announcement made when the work mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_work_mode_changed_on">Work mode turned on.</string>
+    <!-- Announcement made when the Data Saver changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_data_saver_changed_off">Data Saver turned off.</string>
+    <!-- Announcement made when the Data Saver changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_data_saver_changed_on">Data Saver turned on.</string>
 
     <!-- Content description of the display brightness slider (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_brightness">Display brightness</string>
@@ -560,6 +572,9 @@
     <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_clear_all">Clear all notifications.</string>
 
+    <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "+ 3" [CHAR LIMIT=5] -->
+    <string name="notification_group_overflow_indicator">+ <xliff:g id="number" example="3">%s</xliff:g></string>
+
     <!-- Content description of button in notification inspector for system settings relating to
          notifications from this application [CHAR LIMIT=NONE] -->
     <string name="status_bar_notification_inspect_item_title">Notification settings</string>
@@ -705,7 +720,9 @@
     <string name="quick_settings_work_mode_label">Work mode</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
-    <string name="recents_empty_message">Your recent screens appear here</string>
+    <string name="recents_empty_message">No recent items</string>
+    <!-- Recents: The empty recents string after dismissing all tasks. [CHAR LIMIT=NONE] -->
+    <string name="recents_empty_message_dismissed_all">You\'ve cleared everything</string>
     <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
     <string name="recents_app_info_button_label">Application Info</string>
     <!-- Recents: The screen pinning button. [CHAR LIMIT=NONE] -->
@@ -716,10 +733,12 @@
     <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Recents: Launch disabled string. [CHAR LIMIT=NONE] -->
     <string name="recents_launch_disabled_message"><xliff:g id="app" example="Calendar">%s</xliff:g> is disabled in safe-mode.</string>
-    <!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
-    <string name="recents_history_button_label">History</string>
-    <!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
-    <string name="recents_history_clear_all_button_label">Clear</string>
+    <!-- Recents: Stack action button string. [CHAR LIMIT=NONE] -->
+    <string name="recents_stack_action_button_label">Clear all</string>
+    <!-- Recents: Non-dockable task drag message. [CHAR LIMIT=NONE] -->
+    <string name="recents_drag_non_dockable_task_message">This app does not support multi-window</string>
+    <!-- Recents: Non-dockable task launch sub header. [CHAR LIMIT=NONE] -->
+    <string name="recents_launch_non_dockable_task_label">App does not support multi-window</string>
 
     <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
     <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
@@ -1170,11 +1189,6 @@
     <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
     <string name="qs_paging" translatable="false">Use the new Quick Settings</string>
 
-    <!-- Disables fast-toggling recents via the recents button. DO NOT TRANSLATE -->
-    <string name="overview_disable_fast_toggle_via_button">Disable fast toggle</string>
-    <!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
-    <string name="overview_disable_fast_toggle_via_button_desc">Disable launch timeout while paging</string>
-
     <!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
     <string name="overview_nav_bar_gesture">Enable split-screen swipe-up gesture</string>
     <!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]-->
@@ -1199,12 +1213,22 @@
     <!-- Bluetooth enablement ok text [CHAR LIMIT=40] -->
     <string name="enable_bluetooth_confirmation_ok">Turn on</string>
 
-    <!-- Apply notification importance setting to a topic [CHAR LIMIT=NONE] -->
-    <string name="apply_to_topic">Apply to <xliff:g id="topic_name" example="Friend Request">%1$s</xliff:g> notifications</string>
-    <!-- Apply notification importance setting to an app [CHAR LIMIT=NONE] -->
-    <string name="apply_to_app">Apply to all notifications from this app</string>
+    <!-- [CHAR LIMIT=100] Notification importance option -->
+    <string name="show_silently">Show notifications silently</string>
+    <!-- [CHAR LIMIT=100] Notification importance option -->
+    <string name="block">Block all notifications</string>
+    <!-- [CHAR LIMIT=100] Notification importance option -->
+    <string name="do_not_silence">Don\'t silence</string>
+    <!-- [CHAR LIMIT=100] Notification importance option -->
+    <string name="do_not_silence_block">Don\'t silence or block</string>
+
+    <!-- [CHAR LIMIT=NONE] Importance Tuner setting title -->
+    <string name="tuner_full_importance_settings">Show full importance settings</string>
+
     <!-- Notification importance title, blocked status-->
     <string name="blocked_importance">Blocked</string>
+    <!-- Notification importance title, min status-->
+    <string name="min_importance">Min importance</string>
     <!-- Notification importance title, low status-->
     <string name="low_importance">Low importance</string>
     <!-- Notification importance title, normal status-->
@@ -1217,23 +1241,29 @@
     <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
     <string name="notification_importance_blocked">Never show these notifications</string>
 
+    <!-- [CHAR LIMIT=100] Notification Importance slider: min importance level description -->
+    <string name="notification_importance_min">Silently show at the bottom of the notification list</string>
+
     <!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
-    <string name="notification_importance_low">Silently show at the bottom of the notification list</string>
+    <string name="notification_importance_low">Silently show these notifications</string>
 
     <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
-    <string name="notification_importance_default">Silently show these notifications</string>
+    <string name="notification_importance_default">Allow these notification to make sounds</string>
 
     <!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
-    <string name="notification_importance_high">Show at the top of the notifications list and make sound</string>
+    <string name="notification_importance_high">Peek onto the screen and allow sound and allow sound</string>
 
     <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
-    <string name="notification_importance_max">Peek onto the screen and make sound</string>
+    <string name="notification_importance_max">Show at the top of the notifications list, peek onto the screen and allow sound</string>
 
     <!-- Notification: Control panel: Label for button that launches notification settings. [CHAR LIMIT=NONE] -->
     <string name="notification_more_settings">More settings</string>
     <!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
     <string name="notification_done">Done</string>
 
+    <!-- Notification: Gear: Content description for the gear. [CHAR LIMIT=NONE] -->
+    <string name="notification_gear_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> notification controls</string>
+
     <!-- SysUI Tuner: Color and appearance screen title [CHAR LIMIT=50] -->
     <string name="color_and_appearance">Color and appearance</string>
 
@@ -1270,7 +1300,7 @@
     <!-- SysUI Tuner: Disclaimer about using dark theme with night mode [CHAR LIMIT=NONE] -->
     <string name="night_mode_disclaimer">The dark theme is applied to
         core areas of Android OS that are normally displayed in a light theme,
-        such as Settings and notifications.</string>
+        such as Settings.</string>
 
     <!-- Button to apply settings [CHAR LIMIT=30] -->
     <string name="color_apply">Apply</string>
@@ -1299,6 +1329,59 @@
     <!-- Summary of switch for battery saver [CHAR LIMIT=NONE] -->
     <string name="battery_detail_switch_summary">Reduces performance and background data</string>
 
+    <!-- Name used for certain Keyboard keys on gamepads, e.g. "Button L1". -->
+    <string name="keyboard_key_button_template">Button <xliff:g id="name">%1$s</xliff:g></string>
+    <!-- Name used to refer to the "Home" key on the keyboard. -->
+    <string name="keyboard_key_home">Home</string>
+    <!-- Name used to refer to the "Back" key on the keyboard. -->
+    <string name="keyboard_key_back">Back</string>
+    <!-- Name used to refer to the "Up" arrow key on the keyboard. -->
+    <string name="keyboard_key_dpad_up">Up</string>
+    <!-- Name used to refer to the "Down" arrow key on the keyboard. -->
+    <string name="keyboard_key_dpad_down">Down</string>
+    <!-- Name used to refer to the "Left" arrow key on the keyboard. -->
+    <string name="keyboard_key_dpad_left">Left</string>
+    <!-- Name used to refer to the "Right" arrow key on the keyboard. -->
+    <string name="keyboard_key_dpad_right">Right</string>
+    <!-- Name used to refer to the "Center" arrow key on the keyboard. -->
+    <string name="keyboard_key_dpad_center">Center</string>
+    <!-- Name used to refer to the "Tab" key on the keyboard. -->
+    <string name="keyboard_key_tab">Tab</string>
+    <!-- Name used to refer to the "Space" key on the keyboard. -->
+    <string name="keyboard_key_space">Space</string>
+    <!-- Name used to refer to the "Enter" key on the keyboard. -->
+    <string name="keyboard_key_enter">Enter</string>
+    <!-- Name used to refer to the "Backspace" key on the keyboard. -->
+    <string name="keyboard_key_backspace">Backspace</string>
+    <!-- Name used to refer to the "Play/Pause" media key on the keyboard. -->
+    <string name="keyboard_key_media_play_pause">Play/Pause</string>
+    <!-- Name used to refer to the "Stop" media key on the keyboard. -->
+    <string name="keyboard_key_media_stop">Stop</string>
+    <!-- Name used to refer to the "Next" media key on the keyboard. -->
+    <string name="keyboard_key_media_next">Next</string>
+    <!-- Name used to refer to the "Previous" media key on the keyboard. -->
+    <string name="keyboard_key_media_previous">Previous</string>
+    <!-- Name used to refer to the "Rewind" media key on the keyboard. -->
+    <string name="keyboard_key_media_rewind">Rewind</string>
+    <!-- Name used to refer to the "Fast Forward" media key on the keyboard. -->
+    <string name="keyboard_key_media_fast_forward">Fast Forward</string>
+    <!-- Name used to refer to the "Page Up" key on the keyboard. -->
+    <string name="keyboard_key_page_up">Page Up</string>
+    <!-- Name used to refer to the "Page Down" key on the keyboard. -->
+    <string name="keyboard_key_page_down">Page Down</string>
+    <!-- Name used to refer to the "Delete" key on the keyboard. -->
+    <string name="keyboard_key_forward_del">Delete</string>
+    <!-- Name used to refer to the "Home" move key on the keyboard. -->
+    <string name="keyboard_key_move_home">Home</string>
+    <!-- Name used to refer to the "End" move key on the keyboard. -->
+    <string name="keyboard_key_move_end">End</string>
+    <!-- Name used to refer to the "Insert" key on the keyboard. -->
+    <string name="keyboard_key_insert">Insert</string>
+    <!-- Name used to refer to the "Num Lock" key on the keyboard. -->
+    <string name="keyboard_key_num_lock">Num Lock</string>
+    <!-- Name used to refer to keys on the numeric pad of the keyboard, e.g. "Numpad 9". -->
+    <string name="keyboard_key_numpad_template">Numpad <xliff:g id="name">%1$s</xliff:g></string>
+
     <!-- User visible title for the system-wide keyboard shortcuts list. -->
     <string name="keyboard_shortcut_group_system">System</string>
     <!-- User visible title for the keyboard shortcut that takes the user to the home screen. -->
@@ -1307,6 +1390,31 @@
     <string name="keyboard_shortcut_group_system_recents">Recents</string>
     <!-- User visible title for the the keyboard shortcut that triggers the back action. -->
     <string name="keyboard_shortcut_group_system_back">Back</string>
+    <!-- User visible title for the the keyboard shortcut that triggers the notification shade. -->
+    <string name="keyboard_shortcut_group_system_notifications">Notifications</string>
+    <!-- User visible title for the the keyboard shortcut that triggers the keyboard shortcuts helper. -->
+    <string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
+    <!-- User visible title for the the keyboard shortcut that switches input methods. -->
+    <string name="keyboard_shortcut_group_system_switch_input">Switch input method</string>
+
+    <!-- User visible title for the system-wide applications keyboard shortcuts list. -->
+    <string name="keyboard_shortcut_group_applications">Applications</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the assist app. -->
+    <string name="keyboard_shortcut_group_applications_assist">Assist</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the browser app. -->
+    <string name="keyboard_shortcut_group_applications_browser">Browser</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. -->
+    <string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
+    <string name="keyboard_shortcut_group_applications_email">Email</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the instant messaging app. -->
+    <string name="keyboard_shortcut_group_applications_im">IM</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
+    <string name="keyboard_shortcut_group_applications_music">Music</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
+    <string name="keyboard_shortcut_group_applications_youtube">YouTube</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
+    <string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
 
     <!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
     <string name="tuner_full_zen_title">Show with volume controls</string>
@@ -1408,6 +1516,9 @@
     <!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
     <string name="drag_to_add_tiles">Drag to add tiles</string>
 
+    <!-- Label for area where tiles can be dragged in to [CHAR LIMIT=60] -->
+    <string name="drag_to_remove_tiles">Drag here to remove</string>
+
     <!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
     <string name="qs_edit">Edit</string>
 
@@ -1428,4 +1539,52 @@
         <item>Don\'t show this icon</item>
     </string-array>
 
+    <!-- SysUI Tuner: Other section -->
+    <string name="other">Other</string>
+
+    <!-- Accessibility label for the divider that separates the windows in split-screen mode [CHAR LIMIT=NONE] -->
+    <string name="accessibility_divider">Split-screen divider</string>
+
+    <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+    <string name="accessibility_action_divider_move_down">Move down</string>
+
+    <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+    <string name="accessibility_action_divider_move_up">Move up</string>
+
+    <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+    <string name="accessibility_action_divider_move_left">Move left</string>
+
+    <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+    <string name="accessibility_action_divider_move_right">Move right</string>
+
+    <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity and that things might crash/not work properly [CHAR LIMIT=NONE] -->
+    <string name="forced_resizable_info_text">App may not work with multi-window</string>
+
+    <!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_tile_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>, <xliff:g id="tile_name" example="Wi-Fi">%2$s</xliff:g>. Double tap to edit.</string>
+
+    <!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_add_tile_label"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g>. Double tap to add.</string>
+
+    <!-- Accessibility description of a place to drop a tile while editing positions [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_position_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>. Double tap to select.</string>
+
+    <!-- Accessibility description of option to move QS tile [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_move_tile">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
+
+    <!-- Accessibility description of option to remove QS tile [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_remove_tile">Remove <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
+
+    <!-- Accessibility action when QS tile is added [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_tile_added"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> is added to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
+
+    <!-- Accessibility action when QS tile is removed [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_tile_removed"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> is removed</string>
+
+    <!-- Accessibility action when QS tile is moved [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_tile_moved"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> moved to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
+
+    <!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
+    <string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 7c4768d..52aba0d 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -17,27 +17,29 @@
  */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Picture-in-Picture menu -->
+    <!-- Picture-in-Picture (PIP) menu -->
     <eat-comment />
-    <!-- Button to close PIP on PIP UI -->
-    <string name="pip_exit" translatable="false">Close PIP</string>
-    <!-- Button to move PIP screen to the fullscreen on PIP UI -->
-    <string name="pip_fullscreen" translatable="false">Full screen</string>
-    <!-- Button to play the current media on PIP UI -->
-    <string name="pip_play" translatable="false">Play</string>
-    <!-- Button to pause the current media on PIP UI -->
-    <string name="pip_pause" translatable="false">Pause</string>
-    <!-- Button to close PIP overlay menu on PIP UI -->
-    <string name="pip_cancel" translatable="false">Cancel</string>
-    <!-- Overlay text on PIP -->
-    <string name="pip_hold_home" translatable="false">Hold HOME to control PIP</string>
-
-    <!-- Picture-in-Picture onboarding screen -->
+    <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
+    <string name="pip_close">Close PIP</string>
+    <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
+    <string name="pip_fullscreen">Full screen</string>
+    <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+    <string name="pip_play">Play</string>
+    <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+    <string name="pip_pause">Pause</string>
+    <!-- Overlay text on picture-in-picture (PIP) to indicate that longpress HOME key to control PIP [CHAR LIMIT=52] -->
+    <string name="pip_hold_home">Hold <b>HOME</b> to control PIP</string>
+    <!-- Picture-in-Picture (PIP) onboarding screen -->
     <eat-comment />
-    <!-- Title for onboarding screen. -->
-    <string name="pip_onboarding_title" translatable="false">Picture-in-picture</string>
-    <!-- Description for onboarding screen. -->
-    <string name="pip_onboarding_description" translatable="false">Press and hold the HOME\nbutton to close or control it</string>
-    <!-- Button to close onboarding screen. -->
-    <string name="pip_onboarding_button" translatable="false">Got it</string>
+    <!-- Description for picture-in-picture (PIP) onboarding screen to indicate that longpress HOME key to control PIP. [CHAR LIMIT=NONE] -->
+    <string name="pip_onboarding_description">Press and hold the HOME button to control PIP</string>
+    <!-- Button to close picture-in-picture (PIP) onboarding screen. -->
+    <string name="pip_onboarding_button">Got it</string>
+    <!-- Dismiss icon description -->
+    <string name="recents_tv_dismiss">Dismiss</string>
+    <!-- Font for Recents -->
+    <!-- DO NOT TRANSLATE -->
+    <string name="font_roboto_regular" translatable="false">sans-serif</string>
+    <!-- DO NOT TRANSLATE -->
+    <string name="font_roboto_light" translatable="false">sans-serif-light</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index a51b931..2b134af 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -40,6 +40,18 @@
         <item name="android:windowBackground">@android:color/black</item>
     </style>
 
+    <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
+    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+        <item name="android:windowBackground">@drawable/forced_resizable_background</item>
+        <item name="android:statusBarColor">@color/transparent</item>
+        <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
+    </style>
+
+    <style name="Animation.ForcedResizable" parent="@android:style/Animation">
+        <item name="android:activityOpenEnterAnimation">@anim/forced_resizable_enter</item>
+        <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
+    </style>
+
     <style name="TextAppearance.StatusBar.HeadsUp"
         parent="@*android:style/TextAppearance.StatusBar">
     </style>
@@ -201,8 +213,8 @@
         <item name="android:colorControlActivated">@color/system_accent_color</item>
     </style>
 
-    <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault">
-        <item name="android:colorControlActivated">@android:color/white</item>
+    <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
+        <item name="android:colorAccent">@color/remote_input_accent</item>
     </style>
 
     <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
@@ -214,7 +226,7 @@
 
     <style name="QSBorderlessButton">
         <item name="android:padding">12dp</item>
-        <item name="android:background">@drawable/btn_borderless_rect</item>
+        <item name="android:background">@drawable/qs_btn_borderless_rect</item>
         <item name="android:gravity">center</item>
     </style>
 
@@ -305,7 +317,7 @@
 
     <style name="TextAppearance.NotificationGuts">
         <item name="android:textSize">14sp</item>
-        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:fontFamily">roboto-regular</item>
         <item name="android:textColor">@android:color/black</item>
     </style>
 
@@ -323,6 +335,10 @@
         <item name="android:textSize">16sp</item>
     </style>
 
+    <style name="TextAppearance.NotificationGuts.Radio">
+        <item name="android:alpha">.87</item>
+    </style>
+
     <style name="TextAppearance.NotificationGuts.Button">
         <item name="android:textSize">14sp</item>
         <item name="android:textAllCaps">true</item>
@@ -335,4 +351,8 @@
         <item name="android:colorAccent">@color/switch_accent_color</item>
     </style>
 
+    <style name="edit_theme" parent="@android:style/Theme.Material">
+        <item name="android:colorBackground">@color/qs_edit_overflow_bg</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml
index 3f0caab..263e1a4 100644
--- a/packages/SystemUI/res/values/styles_tv.xml
+++ b/packages/SystemUI/res/values/styles_tv.xml
@@ -22,4 +22,11 @@
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:backgroundDimEnabled">false</item>
      </style>
+
+    <style name="RecentsTvTheme.Wallpaper" parent="@android:style/Theme.Material.NoActionBar.Overscan">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowIsTranslucent">true</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
index 1fcc9e4..bd72c51 100644
--- a/packages/SystemUI/res/values/values_tv.xml
+++ b/packages/SystemUI/res/values/values_tv.xml
@@ -15,4 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <item format="float" type="integer" name="unselected_scale">1.0</item>
+    <item format="float" type="integer" name="selected_scale">1.259</item>
 </resources>
diff --git a/packages/SystemUI/res/xml/night_mode.xml b/packages/SystemUI/res/xml/night_mode.xml
index d5f5333..34af820 100644
--- a/packages/SystemUI/res/xml/night_mode.xml
+++ b/packages/SystemUI/res/xml/night_mode.xml
@@ -27,10 +27,6 @@
         android:title="@string/when_night_mode_on">
 
         <SwitchPreference
-            android:key="dark_theme"
-            android:title="@string/use_dark_theme" />
-
-        <SwitchPreference
             android:key="adjust_tint"
             android:title="@string/adjust_tint" />
 
@@ -40,8 +36,4 @@
 
     </PreferenceCategory>
 
-    <Preference
-        android:selectable="false"
-        android:summary="@string/night_mode_disclaimer" />
-
 </PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 023a3f0..a130cf9 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -109,36 +109,44 @@
         android:key="volume_and_do_not_disturb"
         android:title="@string/volume_and_do_not_disturb">
 
+        <!-- Action for this is
+             MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_PANEL -->
         <com.android.systemui.tuner.TunerSwitch
             android:key="sysui_show_full_zen"
-            android:title="@string/tuner_full_zen_title" />
+            android:title="@string/tuner_full_zen_title"
+            sysui:metricsAction="314" />
 
+        <!-- Action for this is
+             MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_SHORTCUT -->
         <com.android.systemui.tuner.TunerSwitch
             android:key="sysui_volume_down_silent,sysui_volume_up_silent"
             android:title="@string/volume_dnd_silent"
-            sysui:defValue="true" />
+            sysui:defValue="true"
+            sysui:metricsAction="315" />
 
     </PreferenceScreen>
 
+    <!--
     <Preference
         android:key="nav_bar"
         android:title="@string/nav_bar"
         android:fragment="com.android.systemui.tuner.NavBarTuner" />
+    -->
 
     <PreferenceScreen
-        android:key="overview"
-        android:title="@string/overview" >
-
-        <com.android.systemui.tuner.TunerSwitch
-            android:key="overview_disable_fast_toggle_via_button"
-            android:title="@string/overview_disable_fast_toggle_via_button"
-            android:summary="@string/overview_disable_fast_toggle_via_button_desc" />
+        android:key="other"
+        android:title="@string/other" >
 
         <com.android.systemui.tuner.TunerSwitch
             android:key="overview_nav_bar_gesture"
             android:title="@string/overview_nav_bar_gesture"
             android:summary="@string/overview_nav_bar_gesture_desc" />
 
+        <!-- importance -->
+        <com.android.systemui.tuner.TunerSwitch
+                android:key="show_importance_slider"
+                android:title="@string/tuner_full_importance_settings" />
+
     </PreferenceScreen>
 
     <!-- Warning, this goes last. -->
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 4845425..087f61e 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -452,7 +452,7 @@
         boolean pctOpaque = false;
         float pctX = 0, pctY = 0;
         String pctText = null;
-        if (!mPluggedIn && level > mCriticalLevel && mShowPercent) {
+        if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
             mTextPaint.setColor(getColorForLevel(level));
             mTextPaint.setTextSize(height *
                     (SINGLE_DIGIT_PERCENT ? 0.75f
@@ -480,7 +480,7 @@
         mShapePath.op(mClipPath, Path.Op.INTERSECT);
         c.drawPath(mShapePath, mBatteryPaint);
 
-        if (!mPluggedIn) {
+        if (!mPluggedIn && !mPowerSaveEnabled) {
             if (level <= mCriticalLevel) {
                 // draw the warning text
                 final float x = mWidth * 0.5f;
diff --git a/packages/SystemUI/src/com/android/systemui/DensityContainer.java b/packages/SystemUI/src/com/android/systemui/DensityContainer.java
new file mode 100644
index 0000000..2e3cb49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DensityContainer.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DensityContainer extends FrameLayout {
+
+    private final List<InflateListener> mInflateListeners = new ArrayList<>();
+    private final int mLayout;
+    private int mDensity;
+
+    public DensityContainer(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+
+        mDensity = context.getResources().getConfiguration().densityDpi;
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DensityContainer);
+        if (!a.hasValue(R.styleable.DensityContainer_android_layout)) {
+            throw new IllegalArgumentException("DensityContainer must contain a layout");
+        }
+        mLayout = a.getResourceId(R.styleable.DensityContainer_android_layout, 0);
+        inflateLayout();
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        int density = newConfig.densityDpi;
+        if (density != mDensity) {
+            mDensity = density;
+            inflateLayout();
+        }
+    }
+
+    private void inflateLayout() {
+        removeAllViews();
+        LayoutInflater.from(getContext()).inflate(mLayout, this);
+        final int N = mInflateListeners.size();
+        for (int i = 0; i < N; i++) {
+            mInflateListeners.get(i).onInflated(getChildAt(0));
+        }
+    }
+
+    public void addInflateListener(InflateListener listener) {
+        mInflateListeners.add(listener);
+        listener.onInflated(getChildAt(0));
+    }
+
+    public interface InflateListener {
+        /**
+         * Called whenever a new view is inflated.
+         */
+        void onInflated(View v);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 051921a..d12ab29 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -78,6 +78,7 @@
     private float mOldHeight;
     private float mNaturalHeight;
     private float mInitialTouchFocusY;
+    private float mInitialTouchX;
     private float mInitialTouchY;
     private float mInitialTouchSpan;
     private float mLastFocusY;
@@ -291,7 +292,8 @@
                 }
                 if (mWatchingForPull) {
                     final float yDiff = ev.getRawY() - mInitialTouchY;
-                    if (yDiff > mTouchSlop) {
+                    final float xDiff = ev.getRawX() - mInitialTouchX;
+                    if (yDiff > mTouchSlop && yDiff > Math.abs(xDiff)) {
                         if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
                         mWatchingForPull = false;
                         if (mResizedView != null && !isFullyExpanded(mResizedView)) {
@@ -316,6 +318,7 @@
                     mWatchingForPull = false;
                 }
                 mInitialTouchY = ev.getY();
+                mInitialTouchX = ev.getX();
                 break;
 
             case MotionEvent.ACTION_CANCEL:
@@ -409,12 +412,14 @@
                 mWatchingForPull = mScrollAdapter != null &&
                         isInside(mScrollAdapter.getHostView(), x, y);
                 mResizedView = findView(x, y);
+                mInitialTouchX = ev.getX();
                 mInitialTouchY = ev.getY();
                 break;
             case MotionEvent.ACTION_MOVE: {
                 if (mWatchingForPull) {
                     final float yDiff = ev.getRawY() - mInitialTouchY;
-                    if (yDiff > mTouchSlop) {
+                    final float xDiff = ev.getRawX() - mInitialTouchX;
+                    if (yDiff > mTouchSlop && yDiff > Math.abs(xDiff)) {
                         if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
                         mWatchingForPull = false;
                         if (mResizedView != null && !isFullyExpanded(mResizedView)) {
@@ -509,7 +514,7 @@
         if (canBeExpanded) {
             if (DEBUG) Log.d(TAG, "working on an expandable child");
             mNaturalHeight = mScaler.getNaturalHeight();
-            mSmallSize = v.getMinExpandHeight();
+            mSmallSize = v.getCollapsedHeight();
         } else {
             if (DEBUG) Log.d(TAG, "working on a non-expandable child");
             mNaturalHeight = mOldHeight;
@@ -530,31 +535,43 @@
         boolean nowExpanded;
         int naturalHeight = mScaler.getNaturalHeight();
         if (wasClosed) {
-            nowExpanded = (force || currentHeight > mOldHeight);
+            nowExpanded = (force || currentHeight > mOldHeight && velocity >= 0);
         } else {
-            nowExpanded = !force && currentHeight >= mOldHeight;
+            nowExpanded = !force && (currentHeight >= mOldHeight || velocity > 0);
         }
         nowExpanded |= mNaturalHeight == mSmallSize;
         if (mScaleAnimation.isRunning()) {
             mScaleAnimation.cancel();
         }
-        mCallback.setUserExpandedChild(mResizedView, nowExpanded);
         mCallback.expansionStateChanged(false);
         float targetHeight = nowExpanded ? naturalHeight : mSmallSize;
         if (targetHeight != currentHeight) {
             mScaleAnimation.setFloatValues(targetHeight);
             mScaleAnimation.setupStartValues();
             final View scaledView = mResizedView;
+            final boolean expand = nowExpanded;
             mScaleAnimation.addListener(new AnimatorListenerAdapter() {
+                public boolean mCancelled;
+
                 @Override
                 public void onAnimationEnd(Animator animation) {
+                    if (!mCancelled) {
+                        mCallback.setUserExpandedChild(scaledView, expand);
+                    }
                     mCallback.setUserLockedChild(scaledView, false);
                     mScaleAnimation.removeListener(this);
                 }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    mCancelled = true;
+                }
             });
+            velocity = nowExpanded == velocity >= 0 ? velocity : 0;
             mFlingAnimationUtils.apply(mScaleAnimation, currentHeight, targetHeight, velocity);
             mScaleAnimation.start();
         } else {
+            mCallback.setUserExpandedChild(mResizedView, nowExpanded);
             mCallback.setUserLockedChild(mResizedView, false);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index 5e33a9f..17f4dab 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -17,6 +17,7 @@
 package com.android.systemui;
 
 import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
@@ -32,6 +33,7 @@
     public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
     public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
     public static final Interpolator LINEAR = new LinearInterpolator();
+    public static final Interpolator ACCELERATE = new AccelerateInterpolator();
     public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
     public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
 
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 1471622..28ed84f 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -30,8 +30,6 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @StringDef({
-        Key.OVERVIEW_SEARCH_APP_WIDGET_ID,
-        Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE,
         Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
         Key.DEBUG_MODE_ENABLED,
         Key.HOTSPOT_TILE_LAST_USED,
@@ -48,10 +46,9 @@
         Key.QS_DATA_SAVER_ADDED,
         Key.QS_INVERT_COLORS_ADDED,
         Key.QS_WORK_ADDED,
+        Key.QS_NIGHT_ADDED,
     })
     public @interface Key {
-        String OVERVIEW_SEARCH_APP_WIDGET_ID = "searchAppWidgetId";
-        String OVERVIEW_SEARCH_APP_WIDGET_PACKAGE = "searchAppWidgetPackage";
         String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime";
         String DEBUG_MODE_ENABLED = "debugModeEnabled";
         String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed";
@@ -68,6 +65,7 @@
         String QS_DATA_SAVER_ADDED = "QsDataSaverAdded";
         String QS_INVERT_COLORS_ADDED = "QsInvertColorsAdded";
         String QS_WORK_ADDED = "QsWorkAdded";
+        String QS_NIGHT_ADDED = "QsNightAdded";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33f3c30..c0a565db 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -32,6 +32,9 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.FlingAnimationUtils;
+
+import java.util.HashMap;
 
 public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
@@ -58,6 +61,7 @@
     private float mMinSwipeProgress = 0f;
     private float mMaxSwipeProgress = 1f;
 
+    private FlingAnimationUtils mFlingAnimationUtils;
     private float mPagingTouchSlop;
     private Callback mCallback;
     private Handler mHandler;
@@ -68,6 +72,7 @@
     private float mInitialTouchPos;
     private float mPerpendicularInitialTouchPos;
     private boolean mDragging;
+    private boolean mSnappingChild;
     private View mCurrView;
     private boolean mCanCurrViewBeDimissed;
     private float mDensityScale;
@@ -83,6 +88,8 @@
     private boolean mTouchAboveFalsingThreshold;
     private boolean mDisableHwLayers;
 
+    private HashMap<View, Animator> mDismissPendingMap = new HashMap<>();
+
     public SwipeHelper(int swipeDirection, Callback callback, Context context) {
         mCallback = callback;
         mHandler = new Handler();
@@ -95,6 +102,8 @@
         mFalsingThreshold = context.getResources().getDimensionPixelSize(
                 R.dimen.swipe_helper_falsing_threshold);
         mFalsingManager = FalsingManager.getInstance(context);
+        mFlingAnimationUtils = new FlingAnimationUtils(context,
+                MAX_ESCAPE_ANIMATION_DURATION / 1000f /* maxLengthSeconds */);
     }
 
     public void setLongPressListener(LongPressListener listener) {
@@ -144,7 +153,9 @@
     protected Animator getViewTranslationAnimator(View v, float target,
             AnimatorUpdateListener listener) {
         ObjectAnimator anim = createTranslationAnimation(v, target);
-        anim.addUpdateListener(listener);
+        if (listener != null) {
+            anim.addUpdateListener(listener);
+        }
         return anim;
     }
 
@@ -246,6 +257,7 @@
             case MotionEvent.ACTION_DOWN:
                 mTouchAboveFalsingThreshold = false;
                 mDragging = false;
+                mSnappingChild = false;
                 mLongPressSent = false;
                 mVelocityTracker.clear();
                 mCurrView = mCallback.getChildAtPosition(ev);
@@ -262,10 +274,7 @@
                             mWatchLongPress = new Runnable() {
                                 @Override
                                 public void run() {
-                                    float pos = getPos(ev);
-                                    float delta = pos - mInitialTouchPos;
-                                    if (mCurrView != null && !mLongPressSent
-                                            && Math.abs(delta) < mPagingTouchSlop) {
+                                    if (mCurrView != null && !mLongPressSent) {
                                         mLongPressSent = true;
                                         mCurrView.sendAccessibilityEvent(
                                                 AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
@@ -316,9 +325,11 @@
     /**
      * @param view The view to be dismissed
      * @param velocity The desired pixels/second speed at which the view should move
+     * @param useAccelerateInterpolator Should an accelerating Interpolator be used
      */
-    public void dismissChild(final View view, float velocity) {
-        dismissChild(view, velocity, null, 0, false, 0);
+    public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
+        dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
+                useAccelerateInterpolator, 0 /* fixedDuration */);
     }
 
     /**
@@ -370,19 +381,32 @@
         };
 
         Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
+        if (anim == null) {
+            return;
+        }
         if (useAccelerateInterpolator) {
             anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+            anim.setDuration(duration);
         } else {
-            anim.setInterpolator(Interpolators.LINEAR);
+            mFlingAnimationUtils.applyDismissing(anim, getTranslation(animView),
+                    newPos, velocity, getSize(animView));
         }
-        anim.setDuration(duration);
         if (delay > 0) {
             anim.setStartDelay(delay);
         }
         anim.addListener(new AnimatorListenerAdapter() {
+            private boolean mCancelled;
+
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
             public void onAnimationEnd(Animator animation) {
                 updateSwipeProgressFromOffset(animView, canBeDismissed);
-                mCallback.onChildDismissed(animView);
+                mDismissPendingMap.remove(animView);
+                if (!mCancelled) {
+                    mCallback.onChildDismissed(animView);
+                }
                 if (endAction != null) {
                     endAction.run();
                 }
@@ -391,7 +415,9 @@
                 }
             }
         });
+
         prepareDismissAnimation(animView, anim);
+        mDismissPendingMap.put(animView, anim);
         anim.start();
     }
 
@@ -411,15 +437,20 @@
         };
 
         Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
+        if (anim == null) {
+            return;
+        }
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
         anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animator) {
+                mSnappingChild = false;
                 updateSwipeProgressFromOffset(animView, canBeDismissed);
                 mCallback.onChildSnappedBack(animView, targetLeft);
             }
         });
         prepareSnapBackAnimation(animView, anim);
+        mSnappingChild = true;
         anim.start();
     }
 
@@ -452,6 +483,33 @@
         updateSwipeProgressFromOffset(animView, canBeDismissed);
     }
 
+    private void snapChildInstantly(final View view) {
+        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
+        setTranslation(view, 0);
+        updateSwipeProgressFromOffset(view, canAnimViewBeDismissed);
+    }
+
+    public void snapChildIfNeeded(final View view, boolean animate) {
+        if ((mDragging && mCurrView == view) || mSnappingChild) {
+            return;
+        }
+        boolean needToSnap = false;
+        Animator dismissPendingAnim = mDismissPendingMap.get(view);
+        if (dismissPendingAnim != null) {
+            needToSnap = true;
+            dismissPendingAnim.cancel();
+        } else if (getTranslation(view) != 0) {
+            needToSnap = true;
+        }
+        if (needToSnap) {
+            if (animate) {
+                snapChild(view, 0 /* targetLeft */, 0.0f /* velocity */);
+            } else {
+                snapChildInstantly(view);
+            }
+        }
+    }
+
     public boolean onTouchEvent(MotionEvent ev) {
         if (mLongPressSent) {
             return true;
@@ -503,41 +561,25 @@
                 break;
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
-                if (mCurrView != null) {
-                    float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale;
-                    mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity);
-                    float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
-                    float velocity = getVelocity(mVelocityTracker);
-                    float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
+                if (mCurrView == null) {
+                    break;
+                }
+                mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, getMaxVelocity());
+                float velocity = getVelocity(mVelocityTracker);
 
-                    float translation = getTranslation(mCurrView);
-                    // Decide whether to dismiss the current view
-                    boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
-                            Math.abs(translation) > 0.4 * getSize(mCurrView);
-                    boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
-                            (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
-                            (velocity > 0) == (translation > 0);
-                    boolean falsingDetected = mCallback.isAntiFalsingNeeded();
-
-                    if (mFalsingManager.isClassiferEnabled()) {
-                        falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
-                    } else {
-                        falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
-                    }
-
-                    boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
-                            && !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough)
-                            && ev.getActionMasked() == MotionEvent.ACTION_UP;
-
-                    if (dismissChild) {
+                if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
+                    if (isDismissGesture(ev)) {
                         // flingadingy
-                        dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
+                        dismissChild(mCurrView, velocity,
+                                !swipedFastEnough() /* useAccelerateInterpolator */);
                     } else {
                         // snappity
                         mCallback.onDragCancelled(mCurrView);
                         snapChild(mCurrView, 0 /* leftTarget */, velocity);
                     }
+                    mCurrView = null;
                 }
+                mDragging = false;
                 break;
         }
         return true;
@@ -548,6 +590,44 @@
         return (int) (mFalsingThreshold * factor);
     }
 
+    private float getMaxVelocity() {
+        return MAX_DISMISS_VELOCITY * mDensityScale;
+    }
+
+    protected float getEscapeVelocity() {
+        return SWIPE_ESCAPE_VELOCITY * mDensityScale;
+    }
+
+    protected boolean swipedFarEnough() {
+        float translation = getTranslation(mCurrView);
+        return DISMISS_IF_SWIPED_FAR_ENOUGH && Math.abs(translation) > 0.4 * getSize(mCurrView);
+    }
+
+    protected boolean isDismissGesture(MotionEvent ev) {
+        boolean falsingDetected = mCallback.isAntiFalsingNeeded();
+        if (mFalsingManager.isClassiferEnabled()) {
+            falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
+        } else {
+            falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
+        }
+        return !falsingDetected && (swipedFastEnough() || swipedFarEnough())
+                && ev.getActionMasked() == MotionEvent.ACTION_UP
+                && mCallback.canChildBeDismissed(mCurrView);
+    }
+
+    protected boolean swipedFastEnough() {
+        float velocity = getVelocity(mVelocityTracker);
+        float translation = getTranslation(mCurrView);
+        boolean ret = (Math.abs(velocity) > getEscapeVelocity())
+                && (velocity > 0) == (translation > 0);
+        return ret;
+    }
+
+    protected boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
+            float translation) {
+        return false;
+    }
+
     public interface Callback {
         View getChildAtPosition(MotionEvent ev);
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 472648a..455a69f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -54,7 +54,8 @@
             com.android.systemui.power.PowerUI.class,
             com.android.systemui.media.RingtonePlayer.class,
             com.android.systemui.keyboard.KeyboardUI.class,
-            com.android.systemui.tv.pip.PipUI.class
+            com.android.systemui.tv.pip.PipUI.class,
+            com.android.systemui.shortcut.ShortcutKeyDispatcher.class
     };
 
     /**
@@ -122,6 +123,17 @@
         startServicesIfNeeded(SERVICES);
     }
 
+    /**
+     * Ensures that all the Secondary user SystemUI services are running. If they are already
+     * running, this is a no-op. This is needed to conditinally start all the services, as we only
+     * need to have it in the main process.
+     *
+     * <p>This method must only be called from the main thread.</p>
+     */
+    void startSecondaryUserServicesIfNeeded() {
+        startServicesIfNeeded(SERVICES_PER_USER);
+    }
+
     private void startServicesIfNeeded(Class<?>[] services) {
         if (mServicesStarted) {
             return;
@@ -143,12 +155,14 @@
             Class<?> cl = services[i];
             if (DEBUG) Log.d(TAG, "loading: " + cl);
             try {
-                mServices[i] = (SystemUI) cl.newInstance();
+                Object newService = SystemUIFactory.getInstance().createInstance(cl);
+                mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
             } catch (IllegalAccessException ex) {
                 throw new RuntimeException(ex);
             } catch (InstantiationException ex) {
                 throw new RuntimeException(ex);
             }
+
             mServices[i].mContext = this;
             mServices[i].mComponents = mComponents;
             if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 681b39e..53c2233 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -18,13 +18,34 @@
 
 import android.content.Context;
 import android.util.Log;
+import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 
 /**
  * Class factory to provide customizable SystemUI components.
@@ -66,4 +87,32 @@
             ViewGroup container) {
         return new KeyguardBouncer(context, callback, lockPatternUtils, windowManager, container);
     }
+
+    public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
+            View headsUpScrim) {
+        return new ScrimController(scrimBehind, scrimInFront, headsUpScrim);
+    }
+
+    public NotificationIconAreaController createNotificationIconAreaController(Context context,
+            PhoneStatusBar phoneStatusBar) {
+        return new NotificationIconAreaController(context, phoneStatusBar);
+    }
+
+    public QSTileHost createQSTileHost(Context context, PhoneStatusBar statusBar,
+            BluetoothController bluetooth, LocationController location,
+            RotationLockController rotation, NetworkController network,
+            ZenModeController zen, HotspotController hotspot,
+            CastController cast, FlashlightController flashlight,
+            UserSwitcherController userSwitcher, UserInfoController userInfo,
+            KeyguardMonitor keyguard, SecurityController security,
+            BatteryController battery, StatusBarIconController iconController,
+            NextAlarmController nextAlarmController) {
+        return new QSTileHost(context, statusBar, bluetooth, location, rotation, network, zen,
+                hotspot, cast, flashlight, userSwitcher, userInfo, keyguard, security, battery,
+                iconController, nextAlarmController);
+    }
+
+    public <T> T createInstance(Class<T> classType) {
+        return null;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUISecondaryUserService.java b/packages/SystemUI/src/com/android/systemui/SystemUISecondaryUserService.java
new file mode 100644
index 0000000..f619bfb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUISecondaryUserService.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.app.ActivityManager;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class SystemUISecondaryUserService extends Service {
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        ((SystemUIApplication) getApplication()).startSecondaryUserServicesIfNeeded();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
+        if (args == null || args.length == 0) {
+            for (SystemUI ui: services) {
+                pw.println("dumping service: " + ui.getClass().getName());
+                ui.dump(fd, pw, args);
+            }
+        } else {
+            String svc = args[0];
+            for (SystemUI ui: services) {
+                String name = ui.getClass().getName();
+                if (name.endsWith(svc)) {
+                    ui.dump(fd, pw, args);
+                }
+            }
+        }
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
index 86bea87..bad739fd 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
@@ -36,6 +36,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "ACC";
+    }
+
+    @Override
     public void onTouchEvent(MotionEvent event) {
         int action = event.getActionMasked();
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index dba731a..526e5fa 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -54,6 +54,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "ANG";
+    }
+
+    @Override
     public void onTouchEvent(MotionEvent event) {
         int action = event.getActionMasked();
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index 89d20de..cb761a9 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -48,4 +48,6 @@
      */
     public void onSensorChanged(SensorEvent event) {
     }
+
+    public abstract String getTag();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
index 299d0e3..610e219 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
@@ -25,6 +25,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "DIR";
+    }
+
+    @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         Point firstPoint = stroke.getPoints().get(0);
         Point lastPoint = stroke.getPoints().get(stroke.getPoints().size() - 1);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
index 8924694..77fda20 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
@@ -25,6 +25,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "DUR";
+    }
+
+    @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         return DurationCountEvaluator.evaluate(stroke.getDurationSeconds() / stroke.getCount());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
index 78bc0dd..de8a188 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
@@ -24,6 +24,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "END_LNGTH";
+    }
+
+    @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         return EndPointLengthEvaluator.evaluate(stroke.getEndPointLength());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
index 652d969..9b6ddc8 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
@@ -26,6 +26,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "END_RTIO";
+    }
+
+    @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         float ratio;
         if (stroke.getTotalLength() == 0.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java
new file mode 100644
index 0000000..1338d9d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.classifier;
+
+import android.app.ActivityThread;
+import android.app.Application;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Keeps track of interesting falsing data.
+ *
+ * By default the log only gets collected on userdebug builds. To turn it on on user:
+ *  adb shell setprop debug.falsing_log true
+ *
+ * The log gets dumped as part of the SystemUI services. To dump on demand:
+ *  adb shell dumpsys activity service com.android.systemui SystemBars | grep -A 999 FALSING | less
+ *
+ * To dump into logcat:
+ *  adb shell setprop debug.falsing_logcat true
+ *
+ * To adjust the log buffer size:
+ *  adb shell setprop debug.falsing_log_size 200
+ */
+public class FalsingLog {
+    public static final boolean ENABLED = SystemProperties.getBoolean("debug.falsing_log",
+            Build.IS_DEBUGGABLE);
+    private static final boolean LOGCAT = SystemProperties.getBoolean("debug.falsing_logcat",
+            false);
+
+    public static final boolean VERBOSE = false;
+
+    private static final int MAX_SIZE = SystemProperties.getInt("debug.falsing_log_size", 100);
+
+    private static final String TAG = "FalsingLog";
+
+    private final ArrayDeque<String> mLog = new ArrayDeque<>(MAX_SIZE);
+    private final SimpleDateFormat mFormat = new SimpleDateFormat("MM-dd HH:mm:ss", Locale.US);
+
+    private static FalsingLog sInstance;
+
+    private FalsingLog() {
+    }
+
+    public static void v(String tag, String s) {
+        if (!VERBOSE) {
+            return;
+        }
+        if (LOGCAT) {
+            Log.v(TAG, tag + "\t" + s);
+        }
+        log("V", tag, s);
+    }
+
+    public static void i(String tag, String s) {
+        if (LOGCAT) {
+            Log.i(TAG, tag + "\t" + s);
+        }
+        log("I", tag, s);
+    }
+
+    public static void w(String tag, String s) {
+        if (LOGCAT) {
+            Log.w(TAG, tag + "\t" + s);
+        }
+        log("W", tag, s);
+    }
+
+    public static void e(String tag, String s) {
+        if (LOGCAT) {
+            Log.e(TAG, tag + "\t" + s);
+        }
+        log("E", tag, s);
+    }
+
+    public static synchronized void log(String level, String tag, String s) {
+        if (!ENABLED) {
+            return;
+        }
+        if (sInstance == null) {
+            sInstance = new FalsingLog();
+        }
+
+        if (sInstance.mLog.size() >= MAX_SIZE) {
+            sInstance.mLog.removeFirst();
+        }
+        String entry = new StringBuilder().append(sInstance.mFormat.format(new Date()))
+            .append(" ").append(level).append(" ")
+            .append(tag).append(" ").append(s).toString();
+        sInstance.mLog.add(entry);
+    }
+
+    public static synchronized void dump(PrintWriter pw) {
+        pw.println("FALSING LOG:");
+        if (!ENABLED) {
+            pw.println("Disabled, to enable: setprop debug.falsing_log 1");
+            pw.println();
+            return;
+        }
+        if (sInstance == null || sInstance.mLog.isEmpty()) {
+            pw.println("<empty>");
+            pw.println();
+            return;
+        }
+        for (String s : sInstance.mLog) {
+            pw.println(s);
+        }
+        pw.println();
+    }
+
+    public static synchronized void wtf(String tag, String s) {
+        if (!ENABLED) {
+            return;
+        }
+        e(tag, s);
+
+        Application application = ActivityThread.currentApplication();
+        String fileMessage = "";
+        if (Build.IS_DEBUGGABLE && application != null) {
+            File f = new File(application.getDataDir(), "falsing-"
+                    + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + ".txt");
+            PrintWriter pw = null;
+            try {
+                pw = new PrintWriter(f);
+                dump(pw);
+                pw.close();
+                fileMessage = "Log written to " + f.getAbsolutePath();
+            } catch (IOException e) {
+                Log.e(TAG, "Unable to write falsing log", e);
+            } finally {
+                if (pw != null) {
+                    pw.close();
+                }
+            }
+        } else {
+            Log.e(TAG, "Unable to write log, build must be debuggable.");
+        }
+
+        Log.wtf(TAG, tag + " " + s + "; " + fileMessage);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 735a7c4..0d822cb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -23,6 +23,7 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.os.Handler;
+import android.os.PowerManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.view.MotionEvent;
@@ -30,6 +31,8 @@
 import com.android.systemui.analytics.DataCollector;
 import com.android.systemui.statusbar.StatusBarState;
 
+import java.io.PrintWriter;
+
 /**
  * When the phone is locked, listens to touch, sensor and phone events and sends them to
  * DataCollector and HumanInteractionClassifier.
@@ -64,6 +67,7 @@
     private boolean mBouncerOn = false;
     private boolean mSessionActive = false;
     private int mState = StatusBarState.SHADE;
+    private boolean mScreenOn;
 
     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
@@ -77,6 +81,7 @@
         mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
         mDataCollector = DataCollector.getInstance(mContext);
         mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext);
+        mScreenOn = context.getSystemService(PowerManager.class).isInteractive();
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
@@ -98,23 +103,36 @@
                 ENFORCE_BOUNCER, 0);
     }
 
+    private boolean shouldSessionBeActive() {
+        if (FalsingLog.ENABLED && FalsingLog.VERBOSE)
+            FalsingLog.v("shouldBeActive", new StringBuilder()
+                    .append("enabled=").append(isEnabled() ? 1 : 0)
+                    .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
+                    .append(" mState=").append(StatusBarState.toShortString(mState))
+                    .toString()
+            );
+        return isEnabled() && mScreenOn && (mState == StatusBarState.KEYGUARD);
+    }
+
     private boolean sessionEntrypoint() {
-        if (!mSessionActive && isEnabled() &&
-                (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
+        if (!mSessionActive && shouldSessionBeActive()) {
             onSessionStart();
             return true;
         }
         return false;
     }
 
-    private void sessionExitpoint() {
-        if (mSessionActive) {
+    private void sessionExitpoint(boolean force) {
+        if (mSessionActive && (force || !shouldSessionBeActive())) {
             mSessionActive = false;
             mSensorManager.unregisterListener(this);
         }
     }
 
     private void onSessionStart() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onSessionStart", "classifierEnabled=" + isClassiferEnabled());
+        }
         mBouncerOn = false;
         mSessionActive = true;
 
@@ -147,6 +165,18 @@
      * @return true if the classifier determined that this is not a human interacting with the phone
      */
     public boolean isFalseTouch() {
+        if (FalsingLog.ENABLED) {
+            // We're getting some false wtfs from touches that happen after the device went
+            // to sleep. Only report missing sessions that happen when the device is interactive.
+            if (!mSessionActive && mContext.getSystemService(PowerManager.class).isInteractive()) {
+                FalsingLog.wtf("isFalseTouch", new StringBuilder()
+                        .append("Session is not active, yet there's a query for a false touch.")
+                        .append(" enabled=").append(isEnabled() ? 1 : 0)
+                        .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
+                        .append(" mState=").append(StatusBarState.toShortString(mState))
+                        .toString());
+            }
+        }
         return mHumanInteractionClassifier.isFalseTouch();
     }
 
@@ -166,32 +196,69 @@
     }
 
     public void setStatusBarState(int state) {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("setStatusBarState", new StringBuilder()
+                    .append("from=").append(StatusBarState.toShortString(mState))
+                    .append(" to=").append(StatusBarState.toShortString(state))
+                    .toString());
+        }
         mState = state;
+        if (shouldSessionBeActive()) {
+            sessionEntrypoint();
+        } else {
+            sessionExitpoint(false /* force */);
+        }
     }
 
     public void onScreenTurningOn() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onScreenTurningOn", new StringBuilder()
+                    .append("from=").append(mScreenOn ? 1 : 0)
+                    .toString());
+        }
+        mScreenOn = true;
         if (sessionEntrypoint()) {
             mDataCollector.onScreenTurningOn();
         }
     }
 
     public void onScreenOnFromTouch() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onScreenOnFromTouch", new StringBuilder()
+                    .append("from=").append(mScreenOn ? 1 : 0)
+                    .toString());
+        }
+        mScreenOn = true;
         if (sessionEntrypoint()) {
             mDataCollector.onScreenOnFromTouch();
         }
     }
 
     public void onScreenOff() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onScreenOff", new StringBuilder()
+                    .append("from=").append(mScreenOn ? 1 : 0)
+                    .toString());
+        }
         mDataCollector.onScreenOff();
-        sessionExitpoint();
+        mScreenOn = false;
+        sessionExitpoint(false /* force */);
     }
 
     public void onSucccessfulUnlock() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onSucccessfulUnlock", "");
+        }
         mDataCollector.onSucccessfulUnlock();
-        sessionExitpoint();
+        sessionExitpoint(true /* force */);
     }
 
     public void onBouncerShown() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onBouncerShown", new StringBuilder()
+                    .append("from=").append(mBouncerOn ? 1 : 0)
+                    .toString());
+        }
         if (!mBouncerOn) {
             mBouncerOn = true;
             mDataCollector.onBouncerShown();
@@ -199,6 +266,11 @@
     }
 
     public void onBouncerHidden() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onBouncerHidden", new StringBuilder()
+                    .append("from=").append(mBouncerOn ? 1 : 0)
+                    .toString());
+        }
         if (mBouncerOn) {
             mBouncerOn = false;
             mDataCollector.onBouncerHidden();
@@ -206,6 +278,9 @@
     }
 
     public void onQsDown() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onQsDown", "");
+        }
         mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS);
         mDataCollector.onQsDown();
     }
@@ -215,6 +290,9 @@
     }
 
     public void onTrackingStarted() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onTrackingStarted", "");
+        }
         mHumanInteractionClassifier.setType(Classifier.UNLOCK);
         mDataCollector.onTrackingStarted();
     }
@@ -236,6 +314,9 @@
     }
 
     public void onNotificatonStartDraggingDown() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onNotificatonStartDraggingDown", "");
+        }
         mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN);
         mDataCollector.onNotificatonStartDraggingDown();
     }
@@ -249,6 +330,9 @@
     }
 
     public void onNotificatonStartDismissing() {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onNotificatonStartDismissing", "");
+        }
         mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS);
         mDataCollector.onNotificatonStartDismissing();
     }
@@ -266,6 +350,9 @@
     }
 
     public void onAffordanceSwipingStarted(boolean rightCorner) {
+        if (FalsingLog.ENABLED) {
+            FalsingLog.i("onAffordanceSwipingStarted", "");
+        }
         if (rightCorner) {
             mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE);
         } else {
@@ -296,4 +383,14 @@
             mHumanInteractionClassifier.onTouchEvent(event);
         }
     }
+
+    public void dump(PrintWriter pw) {
+        pw.println("FALSING MANAGER");
+        pw.print("classifierEnabled="); pw.println(isClassiferEnabled() ? 1 : 0);
+        pw.print("mSessionActive="); pw.println(mSessionActive ? 1 : 0);
+        pw.print("mBouncerOn="); pw.println(mSessionActive ? 1 : 0);
+        pw.print("mState="); pw.println(StatusBarState.toShortString(mState));
+        pw.print("mScreenOn="); pw.println(mScreenOn ? 1 : 0);
+        pw.println();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 7ddbdf0..5e35d76 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -23,6 +23,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.MotionEvent;
 
 import java.util.ArrayDeque;
@@ -43,14 +44,12 @@
     private final Handler mHandler = new Handler();
     private final Context mContext;
 
-    private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>();
-    private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>();
-    private ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>();
-    private final int mStrokeClassifiersSize;
-    private final int mGestureClassifiersSize;
+    private final StrokeClassifier[] mStrokeClassifiers;
+    private final GestureClassifier[] mGestureClassifiers;
+    private final ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>();
+    private final HistoryEvaluator mHistoryEvaluator;
     private final float mDpi;
 
-    private HistoryEvaluator mHistoryEvaluator;
     private boolean mEnableClassifier = false;
     private int mCurrentType = Classifier.GENERIC;
 
@@ -68,25 +67,27 @@
         // If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi
         // were to be used separately. Due negligible differences in xdpi and ydpi we can just
         // take the average.
+        // TODO: make this respect DPI changes.
         mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f;
         mClassifierData = new ClassifierData(mDpi);
         mHistoryEvaluator = new HistoryEvaluator();
 
-        mStrokeClassifiers.add(new AnglesClassifier(mClassifierData));
-        mStrokeClassifiers.add(new SpeedClassifier(mClassifierData));
-        mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData));
-        mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData));
-        mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData));
-        mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData));
-        mStrokeClassifiers.add(new SpeedAnglesClassifier(mClassifierData));
-        mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData));
-        mStrokeClassifiers.add(new DirectionClassifier(mClassifierData));
+        mStrokeClassifiers = new StrokeClassifier[]{
+                new AnglesClassifier(mClassifierData),
+                new SpeedClassifier(mClassifierData),
+                new DurationCountClassifier(mClassifierData),
+                new EndPointRatioClassifier(mClassifierData),
+                new EndPointLengthClassifier(mClassifierData),
+                new AccelerationClassifier(mClassifierData),
+                new SpeedAnglesClassifier(mClassifierData),
+                new LengthCountClassifier(mClassifierData),
+                new DirectionClassifier(mClassifierData),
+        };
 
-        mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));
-        mGestureClassifiers.add(new ProximityClassifier(mClassifierData));
-
-        mStrokeClassifiersSize = mStrokeClassifiers.size();
-        mGestureClassifiersSize = mGestureClassifiers.size();
+        mGestureClassifiers = new GestureClassifier[] {
+                new PointerCountClassifier(mClassifierData),
+                new ProximityClassifier(mClassifierData)
+        };
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(HIC_ENABLE), false,
@@ -119,7 +120,7 @@
             return;
         }
 
-        // If the user is dragging down the notification, he might want to drag it down
+        // If the user is dragging down the notification, they might want to drag it down
         // enough to see the content, read it for a while and then lift the finger to open
         // the notification. This kind of motion scores very bad in the Classifier so the
         // MotionEvents which are close to the current position of the finger are not
@@ -150,21 +151,30 @@
     private void addTouchEvent(MotionEvent event) {
         mClassifierData.update(event);
 
-        for (int i = 0; i < mStrokeClassifiersSize; i++) {
-            mStrokeClassifiers.get(i).onTouchEvent(event);
+        for (StrokeClassifier c : mStrokeClassifiers) {
+            c.onTouchEvent(event);
         }
 
-        for (int i = 0; i < mGestureClassifiersSize; i++) {
-            mGestureClassifiers.get(i).onTouchEvent(event);
+        for (GestureClassifier c : mGestureClassifiers) {
+            c.onTouchEvent(event);
         }
 
         int size = mClassifierData.getEndingStrokes().size();
         for (int i = 0; i < size; i++) {
             Stroke stroke = mClassifierData.getEndingStrokes().get(i);
             float evaluation = 0.0f;
-            for (int j = 0; j < mStrokeClassifiersSize; j++) {
-                evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation(
-                        mCurrentType, stroke);
+            StringBuilder sb = FalsingLog.ENABLED ? new StringBuilder("stroke") : null;
+            for (StrokeClassifier c : mStrokeClassifiers) {
+                float e = c.getFalseTouchEvaluation(mCurrentType, stroke);
+                if (FalsingLog.ENABLED) {
+                    String tag = c.getTag();
+                    sb.append(" ").append(e >= 1f ? tag : tag.toLowerCase()).append("=").append(e);
+                }
+                evaluation += e;
+            }
+
+            if (FalsingLog.ENABLED) {
+                FalsingLog.i(" addTouchEvent", sb.toString());
             }
             mHistoryEvaluator.addStroke(evaluation);
         }
@@ -172,8 +182,17 @@
         int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
             float evaluation = 0.0f;
-            for (int i = 0; i < mGestureClassifiersSize; i++) {
-                evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType);
+            StringBuilder sb = FalsingLog.ENABLED ? new StringBuilder("gesture") : null;
+            for (GestureClassifier c : mGestureClassifiers) {
+                float e = c.getFalseTouchEvaluation(mCurrentType);
+                if (FalsingLog.ENABLED) {
+                    String tag = c.getTag();
+                    sb.append(" ").append(e >= 1f ? tag : tag.toLowerCase()).append("=").append(e);
+                }
+                evaluation += e;
+            }
+            if (FalsingLog.ENABLED) {
+                FalsingLog.i(" addTouchEvent", sb.toString());
             }
             mHistoryEvaluator.addGesture(evaluation);
             setType(Classifier.GENERIC);
@@ -184,18 +203,25 @@
 
     @Override
     public void onSensorChanged(SensorEvent event) {
-        for (int i = 0; i < mStrokeClassifiers.size(); i++) {
-            mStrokeClassifiers.get(i).onSensorChanged(event);
+        for (Classifier c : mStrokeClassifiers) {
+            c.onSensorChanged(event);
         }
 
-        for (int i = 0; i < mGestureClassifiers.size(); i++) {
-            mGestureClassifiers.get(i).onSensorChanged(event);
+        for (Classifier c : mGestureClassifiers) {
+            c.onSensorChanged(event);
         }
     }
 
     public boolean isFalseTouch() {
         if (mEnableClassifier) {
-            return mHistoryEvaluator.getEvaluation() >= 5.0f;
+            float evaluation = mHistoryEvaluator.getEvaluation();
+            boolean result = evaluation >= 5.0f;
+            if (FalsingLog.ENABLED) {
+                FalsingLog.i("isFalseTouch", new StringBuilder()
+                        .append("eval=").append(evaluation).append(" result=")
+                        .append(result ? 1 : 0).toString());
+            }
+            return result;
         }
         return false;
     }
@@ -203,4 +229,9 @@
     public boolean isEnabled() {
         return mEnableClassifier;
     }
+
+    @Override
+    public String getTag() {
+        return "HIC";
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
index cedf467..53678a6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
@@ -28,6 +28,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "LEN_CNT";
+    }
+
+    @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         return LengthCountEvaluator.evaluate(stroke.getTotalLength()
                 / Math.max(1.0f, stroke.getCount() - 2));
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
index 5097b63..136c433 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -29,6 +29,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "PTR_CNT";
+    }
+
+    @Override
     public void onTouchEvent(MotionEvent event) {
         int action = event.getActionMasked();
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 6995064..62adfc8 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -35,6 +35,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "PROX";
+    }
+
+    @Override
     public void onSensorChanged(SensorEvent event) {
         if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
             update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
index d58274d..6df72b1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -41,6 +41,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "SPD_ANG";
+    }
+
+    @Override
     public void onTouchEvent(MotionEvent event) {
         int action = event.getActionMasked();
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
index 81b78c7..01fcc37 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
@@ -27,6 +27,11 @@
     }
 
     @Override
+    public String getTag() {
+        return "SPD";
+    }
+
+    @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         float duration = (float) stroke.getDurationNanos() / NANOS_TO_SECONDS;
         if (duration == 0.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index ea7270d..4b775a5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -38,7 +38,9 @@
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.text.TextUtils;
+import android.util.Pair;
 import android.util.Slog;
+import android.widget.Toast;
 
 import com.android.settingslib.bluetooth.BluetoothCallback;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -46,6 +48,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.bluetooth.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 
@@ -76,8 +79,9 @@
     private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
     private static final int STATE_PAIRING = 5;
     private static final int STATE_PAIRED = 6;
-    private static final int STATE_USER_CANCELLED = 7;
-    private static final int STATE_DEVICE_NOT_FOUND = 8;
+    private static final int STATE_PAIRING_FAILED = 7;
+    private static final int STATE_USER_CANCELLED = 8;
+    private static final int STATE_DEVICE_NOT_FOUND = 9;
 
     private static final int MSG_INIT = 0;
     private static final int MSG_ON_BOOT_COMPLETED = 1;
@@ -90,6 +94,7 @@
     private static final int MSG_SHOW_BLUETOOTH_DIALOG = 8;
     private static final int MSG_DISMISS_BLUETOOTH_DIALOG = 9;
     private static final int MSG_BLE_ABORT_SCAN = 10;
+    private static final int MSG_SHOW_ERROR = 11;
 
     private volatile KeyboardHandler mHandler;
     private volatile KeyboardUIHandler mUIHandler;
@@ -178,6 +183,7 @@
         mLocalBluetoothAdapter = bluetoothManager.getBluetoothAdapter();
         mProfileManager = bluetoothManager.getProfileManager();
         bluetoothManager.getEventManager().registerCallback(new BluetoothCallbackHandler());
+        Utils.setErrorListener(new BluetoothErrorListener());
 
         InputManager im = context.getSystemService(InputManager.class);
         im.registerOnTabletModeChangedListener(this, mHandler);
@@ -204,13 +210,15 @@
         if (mInTabletMode != InputManager.SWITCH_STATE_OFF) {
             if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY) {
                 stopScanning();
+            } else if (mState == STATE_WAITING_FOR_BLUETOOTH) {
+                mUIHandler.sendEmptyMessage(MSG_DISMISS_BLUETOOTH_DIALOG);
             }
             mState = STATE_WAITING_FOR_TABLET_MODE_EXIT;
             return;
         }
 
         final int btState = mLocalBluetoothAdapter.getState();
-        if (btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON
+        if ((btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON)
                 && mState == STATE_WAITING_FOR_BLUETOOTH) {
             // If we're waiting for bluetooth but it has come on in the meantime, or is coming
             // on, just dismiss the dialog. This frequently happens during device startup.
@@ -334,7 +342,10 @@
 
     private void stopScanning() {
         if (mScanCallback != null) {
-            mLocalBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
+            BluetoothLeScanner scanner = mLocalBluetoothAdapter.getBluetoothLeScanner();
+            if (scanner != null) {
+                scanner.stopScan(mScanCallback);
+            }
             mScanCallback = null;
         }
     }
@@ -370,10 +381,14 @@
 
     // Should only be called on the handler thread
     private void onDeviceBondStateChangedInternal(CachedBluetoothDevice d, int bondState) {
-        if (d.getName().equals(mKeyboardName) && bondState == BluetoothDevice.BOND_BONDED) {
-            // We don't need to manually connect to the device here because it will automatically
-            // try to connect after it has been paired.
-            mState = STATE_PAIRED;
+        if (mState == STATE_PAIRING && d.getName().equals(mKeyboardName)) {
+            if (bondState == BluetoothDevice.BOND_BONDED) {
+                // We don't need to manually connect to the device here because it will
+                // automatically try to connect after it has been paired.
+                mState = STATE_PAIRED;
+            } else if (bondState == BluetoothDevice.BOND_NONE) {
+                mState = STATE_PAIRING_FAILED;
+            }
         }
     }
 
@@ -385,6 +400,17 @@
         }
     }
 
+    // Should only be called on the handler thread. We want to be careful not to show errors for
+    // pairings not initiated by this UI, so we only pop up the toast when we're at an appropriate
+    // point in our pairing flow and it's the expected device.
+    private void onShowErrorInternal(Context context, String name, int messageResId) {
+        if ((mState == STATE_PAIRING || mState == STATE_PAIRING_FAILED)
+                && mKeyboardName.equals(name)) {
+            String message = context.getString(messageResId, name);
+            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
+        }
+    }
+
     private final class KeyboardUIHandler extends Handler {
         public KeyboardUIHandler() {
             super(Looper.getMainLooper(), null, true /*async*/);
@@ -393,19 +419,27 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_SHOW_BLUETOOTH_DIALOG: {
-                    DialogInterface.OnClickListener listener = new BluetoothDialogClickListener();
+                    if (mDialog != null) {
+                        // Don't show another dialog if one is already present
+                        break;
+                    }
+                    DialogInterface.OnClickListener clickListener =
+                            new BluetoothDialogClickListener();
+                    DialogInterface.OnDismissListener dismissListener =
+                            new BluetoothDialogDismissListener();
                     mDialog = new BluetoothDialog(mContext);
                     mDialog.setTitle(R.string.enable_bluetooth_title);
                     mDialog.setMessage(R.string.enable_bluetooth_message);
-                    mDialog.setPositiveButton(R.string.enable_bluetooth_confirmation_ok, listener);
-                    mDialog.setNegativeButton(android.R.string.cancel, listener);
+                    mDialog.setPositiveButton(
+                            R.string.enable_bluetooth_confirmation_ok, clickListener);
+                    mDialog.setNegativeButton(android.R.string.cancel, clickListener);
+                    mDialog.setOnDismissListener(dismissListener);
                     mDialog.show();
                     break;
                 }
                 case MSG_DISMISS_BLUETOOTH_DIALOG: {
                     if (mDialog != null) {
                         mDialog.dismiss();
-                        mDialog = null;
                     }
                     break;
                 }
@@ -469,6 +503,10 @@
                     onBleScanFailedInternal();
                     break;
                 }
+                case MSG_SHOW_ERROR: {
+                    Pair<Context, String> p = (Pair<Context, String>) msg.obj;
+                    onShowErrorInternal(p.first, p.second, msg.arg1);
+                }
             }
         }
     }
@@ -482,6 +520,14 @@
         }
     }
 
+    private final class BluetoothDialogDismissListener
+            implements DialogInterface.OnDismissListener {
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            mDialog = null;
+        }
+    }
+
     private final class KeyboardScanCallback extends ScanCallback {
 
         private boolean isDeviceDiscoverable(ScanResult result) {
@@ -564,6 +610,13 @@
         public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
     }
 
+    private final class BluetoothErrorListener implements Utils.ErrorListener {
+        public void onShowError(Context context, String name, int messageResId) {
+            mHandler.obtainMessage(MSG_SHOW_ERROR, messageResId, 0 /*unused*/,
+                    new Pair<>(context, name)).sendToTarget();
+        }
+    }
+
     private static String stateToString(int state) {
         switch (state) {
             case STATE_NOT_ENABLED:
@@ -580,13 +633,15 @@
                 return "STATE_PAIRING";
             case STATE_PAIRED:
                 return "STATE_PAIRED";
+            case STATE_PAIRING_FAILED:
+                return "STATE_PAIRING_FAILED";
             case STATE_USER_CANCELLED:
                 return "STATE_USER_CANCELLED";
             case STATE_DEVICE_NOT_FOUND:
                 return "STATE_DEVICE_NOT_FOUND";
             case STATE_UNKNOWN:
             default:
-                return "STATE_UNKNOWN";
+                return "STATE_UNKNOWN (" + state + ")";
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6029c23..a5dfc4b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard;
 
+import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -253,6 +254,11 @@
     private int mDelayedShowingSequence;
 
     /**
+     * Simiar to {@link #mDelayedProfileShowingSequence}, but it is for profile case.
+     */
+    private int mDelayedProfileShowingSequence;
+
+    /**
      * If the user has disabled the keyguard, then requests to exit, this is
      * how we'll ultimately let them know whether it was successful.  We use this
      * var being non-null as an indicator that there is an in progress request.
@@ -327,6 +333,8 @@
      */
     private boolean mPendingLock;
 
+    private boolean mLockLater;
+
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
 
@@ -684,7 +692,7 @@
             doKeyguardLocked(null);
             mUpdateMonitor.registerCallback(mUpdateCallback);
         }
-        mIsPerUserLock = StorageManager.isFileBasedEncryptionEnabled();
+        mIsPerUserLock = StorageManager.isFileEncryptedNativeOrEmulated();
         // Most services aren't available until the system reaches the ready state, so we
         // send it here when the device first boots.
         maybeSendUserPresentBroadcast();
@@ -709,7 +717,7 @@
                     mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)
                             || !mLockPatternUtils.isSecure(currentUser);
             long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser());
-
+            mLockLater = false;
             if (mExitSecureCallback != null) {
                 if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
                 try {
@@ -726,6 +734,7 @@
             } else if ((why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)
                     || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
                 doKeyguardLaterLocked(timeout);
+                mLockLater = true;
             } else if (!mLockPatternUtils.isLockScreenDisabled(currentUser)) {
                 mPendingLock = true;
             }
@@ -753,12 +762,20 @@
                 resetStateLocked();
                 mPendingReset = false;
             }
+
             if (mPendingLock) {
                 doKeyguardLocked(null);
                 mPendingLock = false;
             }
+
+            // We do not have timeout and power button instant lock setting for profile lock.
+            // So we use the personal setting if there is any. But if there is no device
+            // we need to make sure we lock it immediately when the screen is off.
+            if (!mLockLater) {
+                doKeyguardForChildProfilesLocked();
+            }
+
         }
-        doKeyguardForChildProfilesLocked();
         KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
     }
 
@@ -791,6 +808,7 @@
             // policy in effect. Make sure we don't go beyond policy limit.
             displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
             timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
+            timeout = Math.max(timeout, 0);
         }
         return timeout;
     }
@@ -811,7 +829,7 @@
         intent.putExtra("seq", mDelayedShowingSequence);
         PendingIntent sender = PendingIntent.getBroadcast(mContext,
                 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
+        mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
         if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
                          + mDelayedShowingSequence);
         doKeyguardLaterForChildProfilesLocked();
@@ -823,12 +841,18 @@
         for (UserInfo info : profiles) {
             if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
                 long userTimeout = getLockTimeout(info.id);
-                long userWhen = SystemClock.elapsedRealtime() + userTimeout;
-                Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
-                lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
-                PendingIntent lockSender = PendingIntent.getBroadcast(
-                        mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
-                mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
+                if (userTimeout == 0) {
+                    doKeyguardForChildProfilesLocked();
+                } else {
+                    long userWhen = SystemClock.elapsedRealtime() + userTimeout;
+                    Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
+                    lockIntent.putExtra("seq", mDelayedProfileShowingSequence);
+                    lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
+                    PendingIntent lockSender = PendingIntent.getBroadcast(
+                            mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+                    mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                            userWhen, lockSender);
+                }
             }
         }
     }
@@ -847,6 +871,10 @@
         mDelayedShowingSequence++;
     }
 
+    private void cancelDoKeyguardForChildProfilesLocked() {
+        mDelayedProfileShowingSequence++;
+    }
+
     /**
      * Let's us know when the device is waking up.
      */
@@ -856,6 +884,7 @@
         synchronized (this) {
             mDeviceInteractive = true;
             cancelDoKeyguardLaterLocked();
+            cancelDoKeyguardForChildProfilesLocked();
             if (DEBUG) Log.d(TAG, "onStartedWakingUp, seq = " + mDelayedShowingSequence);
             notifyStartedWakingUp();
         }
@@ -1178,6 +1207,7 @@
 
     private void lockProfile(int userId) {
         mTrustManager.setDeviceLockedForUser(userId, true);
+        notifyLockedProfile(userId);
     }
 
     private boolean shouldWaitForProvisioning() {
@@ -1299,10 +1329,13 @@
                     }
                 }
             } else if (DELAYED_LOCK_PROFILE_ACTION.equals(intent.getAction())) {
+                final int sequence = intent.getIntExtra("seq", 0);
                 int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
                 if (userId != 0) {
                     synchronized (KeyguardViewMediator.this) {
-                        lockProfile(userId);
+                        if (mDelayedProfileShowingSequence == sequence) {
+                            lockProfile(userId);
+                        }
                     }
                 }
             }
@@ -1504,6 +1537,13 @@
         }
     }
 
+    private void notifyLockedProfile(@UserIdInt int userId) {
+        try {
+            ActivityManagerNative.getDefault().notifyLockedProfile(userId);
+        } catch (RemoteException e) {
+        }
+    }
+
     /**
      * Handle message sent by {@link #showLocked}.
      * @see #SHOW
@@ -1542,13 +1582,22 @@
             try {
                 mStatusBarKeyguardViewManager.keyguardGoingAway();
 
+                int flags = 0;
+                if (mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()
+                        || mWakeAndUnlocking) {
+                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+                }
+                if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()) {
+                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
+                }
+                if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) {
+                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+                }
+
                 // Don't actually hide the Keyguard at the moment, wait for window
                 // manager until it tells us it's safe to do so with
                 // startKeyguardExitAnimation.
-                ActivityManagerNative.getDefault().keyguardGoingAway(
-                        mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()
-                                || mWakeAndUnlocking,
-                        mStatusBarKeyguardViewManager.isGoingToNotificationShade());
+                ActivityManagerNative.getDefault().keyguardGoingAway(flags);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error while calling WindowManager", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index f39f302..ab612dd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.media;
 
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
 import android.media.AudioAttributes;
 import android.media.IAudioService;
 import android.media.IRingtonePlayer;
@@ -25,15 +27,20 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Audio.AudioColumns;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
 import com.android.systemui.SystemUI;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 
@@ -180,6 +187,34 @@
             return Ringtone.getTitle(getContextForUser(user), uri,
                     false /*followSettingsUri*/, false /*allowRemote*/);
         }
+
+        @Override
+        public ParcelFileDescriptor openRingtone(Uri uri) {
+            final UserHandle user = Binder.getCallingUserHandle();
+            final ContentResolver resolver = getContextForUser(user).getContentResolver();
+
+            // Only open the requested Uri if it's a well-known ringtone or
+            // other sound from the platform media store, otherwise this opens
+            // up arbitrary access to any file on external storage.
+            if (uri.toString().startsWith(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString())) {
+                try (Cursor c = resolver.query(uri, new String[] {
+                        MediaStore.Audio.AudioColumns.IS_RINGTONE,
+                        MediaStore.Audio.AudioColumns.IS_ALARM,
+                        MediaStore.Audio.AudioColumns.IS_NOTIFICATION
+                }, null, null, null)) {
+                    if (c.moveToFirst()) {
+                        if (c.getInt(0) != 0 || c.getInt(1) != 0 || c.getInt(2) != 0) {
+                            try {
+                                return resolver.openFileDescriptor(uri, "r");
+                            } catch (IOException e) {
+                                throw new SecurityException(e);
+                            }
+                        }
+                    }
+                }
+            }
+            throw new SecurityException("Uri is not ringtone, alarm, or notification: " + uri);
+        }
     };
 
     private Context getContextForUser(UserHandle user) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 522d533..109a456 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -183,14 +183,16 @@
                     return;
                 }
 
+                boolean isPowerSaver = mPowerManager.isPowerSaveMode();
                 if (!plugged
+                        && !isPowerSaver
                         && (bucket < oldBucket || oldPlugged)
                         && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
                         && bucket < 0) {
                     // only play SFX when the dialog comes up or the bucket changes
                     final boolean playSound = bucket != oldBucket || oldPlugged;
                     mWarnings.showLowBatteryWarning(playSound);
-                } else if (plugged || (bucket > oldBucket && bucket > 0)) {
+                } else if (isPowerSaver || plugged || (bucket > oldBucket && bucket > 0)) {
                     mWarnings.dismissLowBatteryWarning();
                 } else {
                     mWarnings.updateLowBatteryWarning();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 1200266..ba07bf4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -1,86 +1,219 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
+import android.graphics.drawable.AnimatedVectorDrawable;
 import android.util.AttributeSet;
-import android.view.Gravity;
+import android.util.Log;
 import android.view.View;
-import android.widget.LinearLayout;
-
+import android.view.ViewGroup;
+import android.widget.ImageView;
 import com.android.systemui.R;
 
-public class PageIndicator extends LinearLayout {
+import java.util.ArrayList;
 
-    private final int mPageIndicatorSize;
+public class PageIndicator extends ViewGroup {
+
+    private static final String TAG = "PageIndicator";
+    private static final boolean DEBUG = false;
+
+    private static final long ANIMATION_DURATION = 250;
+
+    // The size of a single dot in relation to the whole animation.
+    private static final float SINGLE_SCALE = .4f;
+
+    private static final float MINOR_ALPHA = .3f;
+
+    private final ArrayList<Integer> mQueuedPositions = new ArrayList<>();
+
+    private final int mPageIndicatorWidth;
+    private final int mPageIndicatorHeight;
+    private final int mPageDotWidth;
+
+    private int mPosition = -1;
+    private boolean mAnimating;
 
     public PageIndicator(Context context, AttributeSet attrs) {
         super(context, attrs);
-        setGravity(Gravity.CENTER);
-        mPageIndicatorSize =
-                (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_size);
+        mPageIndicatorWidth =
+                (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_width);
+        mPageIndicatorHeight =
+                (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_height);
+        mPageDotWidth = (int) (mPageIndicatorWidth * SINGLE_SCALE);
     }
 
     public void setNumPages(int numPages) {
+        setVisibility(numPages > 1 ? View.VISIBLE : View.INVISIBLE);
+        if (mAnimating) {
+            Log.w(TAG, "setNumPages during animation");
+        }
         while (numPages < getChildCount()) {
             removeViewAt(getChildCount() - 1);
         }
         while (numPages > getChildCount()) {
-            SinglePageIndicator v = new SinglePageIndicator(mContext);
-            v.setAmount(0);
-            addView(v, new LayoutParams(mPageIndicatorSize, mPageIndicatorSize));
+            ImageView v = new ImageView(mContext);
+            v.setImageResource(R.drawable.minor_a_b);
+            addView(v, new LayoutParams(mPageIndicatorWidth, mPageIndicatorHeight));
         }
+        // Refresh state.
+        setIndex(mPosition >> 1);
     }
 
     public void setLocation(float location) {
         int index = (int) location;
-        location -= index;
+        int position = index << 1 | ((location != index) ? 1 : 0);
+        if (DEBUG) Log.d(TAG, "setLocation " + location + " " + index + " " + position);
 
+        int lastPosition = mPosition;
+        if (mQueuedPositions.size() != 0) {
+            lastPosition = mQueuedPositions.get(mQueuedPositions.size() - 1);
+        }
+        if (position == lastPosition) return;
+        if (mAnimating) {
+            if (DEBUG) Log.d(TAG, "Queueing transition to " + Integer.toHexString(position));
+            mQueuedPositions.add(position);
+            return;
+        }
+
+        setPosition(position);
+    }
+
+    private void setPosition(int position) {
+        if (isVisibleToUser() && Math.abs(mPosition - position) == 1) {
+            animate(mPosition, position);
+        } else {
+            if (DEBUG) Log.d(TAG, "Skipping animation " + isVisibleToUser() + " " + mPosition
+                    + " " + position);
+            setIndex(position >> 1);
+        }
+        mPosition = position;
+    }
+
+    private void setIndex(int index) {
         final int N = getChildCount();
         for (int i = 0; i < N; i++) {
-            float amount = 0;
-            if (i == index) {
-                amount = 1 - location;
-            } else if (i == index + 1) {
-                amount = location;
+            ImageView v = (ImageView) getChildAt(i);
+            // Clear out any animation positioning.
+            v.setTranslationX(0);
+            v.setImageResource(R.drawable.major_a_b);
+            v.setAlpha(getAlpha(i == index));
+        }
+    }
+
+    private void animate(int from, int to) {
+        if (DEBUG) Log.d(TAG, "Animating from " + Integer.toHexString(from) + " to "
+                + Integer.toHexString(to));
+        int fromIndex = from >> 1;
+        int toIndex = to >> 1;
+
+        // Set the position of everything, then we will manually control the two views involved
+        // in the animation.
+        setIndex(fromIndex);
+
+        boolean fromTransition = (from & 1) != 0;
+        boolean isAState = fromTransition ? from > to : from < to;
+        int firstIndex = Math.min(fromIndex, toIndex);
+        int secondIndex = Math.max(fromIndex, toIndex);
+        if (secondIndex == firstIndex) {
+            secondIndex++;
+        }
+        ImageView first = (ImageView) getChildAt(firstIndex);
+        ImageView second = (ImageView) getChildAt(secondIndex);
+        // Lay the two views on top of each other.
+        second.setTranslationX(first.getX() - second.getX());
+
+        playAnimation(first, getTransition(fromTransition, isAState, false));
+        first.setAlpha(getAlpha(false));
+
+        playAnimation(second, getTransition(fromTransition, isAState, true));
+        second.setAlpha(getAlpha(true));
+
+        mAnimating = true;
+    }
+
+    private float getAlpha(boolean isMajor) {
+        return isMajor ? 1 : MINOR_ALPHA;
+    }
+
+    private void playAnimation(ImageView imageView, int res) {
+        final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext().getDrawable(res);
+        imageView.setImageDrawable(avd);
+        avd.forceAnimationOnUI();
+        avd.start();
+        // TODO: Figure out how to user an AVD animation callback instead, which doesn't
+        // seem to be working right now...
+        postDelayed(mAnimationDone, ANIMATION_DURATION);
+    }
+
+    private int getTransition(boolean fromB, boolean isMajorAState, boolean isMajor) {
+        if (isMajor) {
+            if (fromB) {
+                if (isMajorAState) {
+                    return R.drawable.major_b_a_animation;
+                } else {
+                    return R.drawable.major_b_c_animation;
+                }
+            } else {
+                if (isMajorAState) {
+                    return R.drawable.major_a_b_animation;
+                } else {
+                    return R.drawable.major_c_b_animation;
+                }
             }
-            ((SinglePageIndicator) getChildAt(i)).setAmount(amount);
+        } else {
+            if (fromB) {
+                if (isMajorAState) {
+                    return R.drawable.minor_b_c_animation;
+                } else {
+                    return R.drawable.minor_b_a_animation;
+                }
+            } else {
+                if (isMajorAState) {
+                    return R.drawable.minor_c_b_animation;
+                } else {
+                    return R.drawable.minor_a_b_animation;
+                }
+            }
         }
     }
 
-    // This could be done with a circle drawable and an ImageView, but this seems
-    // easier for now.
-    public static class SinglePageIndicator extends View {
-        private static final int MIN_ALPHA = 0x4d;
-        private static final int MAX_ALPHA = 0xff;
-
-        private static final float MIN_SIZE = .55f;
-        private static final float MAX_SIZE = .7f;
-
-        private final Paint mPaint;
-        private float mSize;
-
-        public SinglePageIndicator(Context context) {
-            super(context);
-            mPaint = new Paint();
-            mPaint.setColor(0xffffffff);
-            mPaint.setAlpha(MAX_ALPHA);
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int N = getChildCount();
+        if (N == 0) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
         }
-
-        public void setAmount(float amount) {
-            mSize = amount * (MAX_SIZE - MIN_SIZE) + MIN_SIZE;
-            int alpha = (int) (amount * (MAX_ALPHA - MIN_ALPHA)) + MIN_ALPHA;
-            mPaint.setAlpha(alpha);
-            postInvalidate();
+        final int widthChildSpec = MeasureSpec.makeMeasureSpec(mPageIndicatorWidth,
+                MeasureSpec.EXACTLY);
+        final int heightChildSpec = MeasureSpec.makeMeasureSpec(mPageIndicatorHeight,
+                MeasureSpec.EXACTLY);
+        for (int i = 0; i < N; i++) {
+            getChildAt(i).measure(widthChildSpec, heightChildSpec);
         }
+        int width = (mPageIndicatorWidth - mPageDotWidth) * N + mPageDotWidth;
+        setMeasuredDimension(width, mPageIndicatorHeight);
+    }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int N = getChildCount();
+        if (N == 0) {
+            return;
+        }
+        for (int i = 0; i < N; i++) {
+            int left = (mPageIndicatorWidth - mPageDotWidth) * i;
+            getChildAt(i).layout(left, 0, mPageIndicatorWidth + left, mPageIndicatorHeight);
+        }
+    }
+
+    private final Runnable mAnimationDone = new Runnable() {
         @Override
-        public void draw(Canvas canvas) {
-            int minDimen = Math.min(getWidth(), getHeight()) / 2;
-            float radius = mSize * minDimen;
-            float x = getWidth() / 2f;
-            float y = getHeight() / 2f;
-            canvas.drawCircle(x, y, radius, mPaint);
+        public void run() {
+            if (DEBUG) Log.d(TAG, "onAnimationEnd - queued: " + mQueuedPositions.size());
+            mAnimating = false;
+            if (mQueuedPositions.size() != 0) {
+                setPosition(mQueuedPositions.remove(0));
+            }
         }
-    }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 0915ee1..115c9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -1,13 +1,13 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import com.android.internal.widget.PagerAdapter;
-import com.android.internal.widget.ViewPager;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSPanel.TileRecord;
@@ -36,9 +36,9 @@
             @Override
             public void onPageSelected(int position) {
                 if (mPageIndicator == null) return;
-                mPageIndicator.setLocation(position);
                 if (mPageListener != null) {
-                    mPageListener.onPageChanged(position);
+                    mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
+                            : position == 0);
                 }
             }
 
@@ -47,6 +47,10 @@
                     int positionOffsetPixels) {
                 if (mPageIndicator == null) return;
                 mPageIndicator.setLocation(position + positionOffset);
+                if (mPageListener != null) {
+                    mPageListener.onPageChanged(positionOffsetPixels == 0 &&
+                            (isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
+                }
             }
 
             @Override
@@ -57,6 +61,26 @@
     }
 
     @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        setAdapter(mAdapter);
+        setCurrentItem(0, false);
+    }
+
+    @Override
+    public void setCurrentItem(int item, boolean smoothScroll) {
+        if (isLayoutRtl()) {
+            item = mPages.size() - 1 - item;
+        }
+        super.setCurrentItem(item, smoothScroll);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
@@ -69,7 +93,9 @@
 
     @Override
     public int getOffsetTop(TileRecord tile) {
-        return ((ViewGroup) tile.tileView.getParent()).getTop() + getTop();
+        final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
+        if (parent == null) return 0;
+        return parent.getTop() + getTop();
     }
 
     @Override
@@ -119,6 +145,7 @@
             mNumPages = index + 1;
             mPageIndicator.setNumPages(mNumPages);
             mAdapter.notifyDataSetChanged();
+            setCurrentItem(0, false);
         }
     }
 
@@ -157,6 +184,11 @@
         }
     };
 
+    public int getColumnCount() {
+        if (mPages.size() == 0) return 0;
+        return mPages.get(0).mColumns;
+    }
+
     public static class TilePage extends TileLayout {
         private int mMaxRows = 3;
 
@@ -192,6 +224,9 @@
 
         public Object instantiateItem(ViewGroup container, int position) {
             if (DEBUG) Log.d(TAG, "Instantiating " + position);
+            if (isLayoutRtl()) {
+                position = mPages.size() - 1 - position;
+            }
             ViewGroup view = mPages.get(position);
             container.addView(view);
             return view;
@@ -209,6 +244,6 @@
     };
 
     public interface PageListener {
-        void onPageChanged(int page);
+        void onPageChanged(boolean isFirst);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PathInterpolatorBuilder.java b/packages/SystemUI/src/com/android/systemui/qs/PathInterpolatorBuilder.java
new file mode 100644
index 0000000..b8cb92a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/PathInterpolatorBuilder.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.Path;
+import android.view.animation.BaseInterpolator;
+import android.view.animation.Interpolator;
+
+public class PathInterpolatorBuilder {
+
+    // This governs how accurate the approximation of the Path is.
+    private static final float PRECISION = 0.002f;
+
+    private float[] mX; // x coordinates in the line
+    private float[] mY; // y coordinates in the line
+    private float[] mDist; // Cumulative percentage length of the line
+
+    public PathInterpolatorBuilder(Path path) {
+        initPath(path);
+    }
+
+    public PathInterpolatorBuilder(float controlX, float controlY) {
+        initQuad(controlX, controlY);
+    }
+
+    public PathInterpolatorBuilder(float controlX1, float controlY1, float controlX2,
+            float controlY2) {
+        initCubic(controlX1, controlY1, controlX2, controlY2);
+    }
+
+    private void initQuad(float controlX, float controlY) {
+        Path path = new Path();
+        path.moveTo(0, 0);
+        path.quadTo(controlX, controlY, 1f, 1f);
+        initPath(path);
+    }
+
+    private void initCubic(float x1, float y1, float x2, float y2) {
+        Path path = new Path();
+        path.moveTo(0, 0);
+        path.cubicTo(x1, y1, x2, y2, 1f, 1f);
+        initPath(path);
+    }
+
+    private void initPath(Path path) {
+        float[] pointComponents = path.approximate(PRECISION);
+
+        int numPoints = pointComponents.length / 3;
+        if (pointComponents[1] != 0 || pointComponents[2] != 0
+                || pointComponents[pointComponents.length - 2] != 1
+                || pointComponents[pointComponents.length - 1] != 1) {
+            throw new IllegalArgumentException("The Path must start at (0,0) and end at (1,1)");
+        }
+
+        mX = new float[numPoints];
+        mY = new float[numPoints];
+        mDist = new float[numPoints];
+        float prevX = 0;
+        float prevFraction = 0;
+        int componentIndex = 0;
+        for (int i = 0; i < numPoints; i++) {
+            float fraction = pointComponents[componentIndex++];
+            float x = pointComponents[componentIndex++];
+            float y = pointComponents[componentIndex++];
+            if (fraction == prevFraction && x != prevX) {
+                throw new IllegalArgumentException(
+                        "The Path cannot have discontinuity in the X axis.");
+            }
+            if (x < prevX) {
+                throw new IllegalArgumentException("The Path cannot loop back on itself.");
+            }
+            mX[i] = x;
+            mY[i] = y;
+            if (i > 0) {
+                float dx = mX[i] - mX[i - 1];
+                float dy = mY[i] - mY[i - 1];
+                float dist = (float) Math.sqrt(dx * dx + dy * dy);
+                mDist[i] = mDist[i - 1] + dist;
+            }
+            prevX = x;
+            prevFraction = fraction;
+        }
+        // Scale down dist to 0-1.
+        float max = mDist[mDist.length - 1];
+        for (int i = 0; i < numPoints; i++) {
+            mDist[i] /= max;
+        }
+    }
+
+    public Interpolator getXInterpolator() {
+        return new PathInterpolator(mDist, mX);
+    }
+
+    public Interpolator getYInterpolator() {
+        return new PathInterpolator(mDist, mY);
+    }
+
+    private static class PathInterpolator extends BaseInterpolator {
+        private final float[] mX; // x coordinates in the line
+        private final float[] mY; // y coordinates in the line
+
+        private PathInterpolator(float[] xs, float[] ys) {
+            mX = xs;
+            mY = ys;
+        }
+
+        @Override
+        public float getInterpolation(float t) {
+            if (t <= 0) {
+                return 0;
+            } else if (t >= 1) {
+                return 1;
+            }
+            // Do a binary search for the correct x to interpolate between.
+            int startIndex = 0;
+            int endIndex = mX.length - 1;
+
+            while (endIndex - startIndex > 1) {
+                int midIndex = (startIndex + endIndex) / 2;
+                if (t < mX[midIndex]) {
+                    endIndex = midIndex;
+                } else {
+                    startIndex = midIndex;
+                }
+            }
+
+            float xRange = mX[endIndex] - mX[startIndex];
+            if (xRange == 0) {
+                return mY[startIndex];
+            }
+
+            float tInRange = t - mX[startIndex];
+            float fraction = tInRange / xRange;
+
+            float startY = mY[startIndex];
+            float endY = mY[endIndex];
+            return startY + (fraction * (endY - startY));
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 6479b0c..de8eec4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,127 +14,235 @@
 
 package com.android.systemui.qs;
 
+import android.graphics.Path;
 import android.util.Log;
 import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnLayoutChangeListener;
-import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.PathInterpolator;
 import android.widget.TextView;
-import com.android.systemui.Interpolators;
 import com.android.systemui.qs.PagedTileLayout.PageListener;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
-public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener {
+public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener,
+        OnAttachStateChangeListener, Tunable {
 
     private static final String TAG = "QSAnimator";
 
-    public static final PathInterpolator TRANSLATION_Y_INTERPOLATOR =
-            new PathInterpolator(.1f, .3f, 1, 1);
+    private static final String ALLOW_FANCY_ANIMATION = "sysui_qs_fancy_anim";
+    private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
 
     public static final float EXPANDED_TILE_DELAY = .7f;
+    private static final float LAST_ROW_EXPANDED_DELAY = .86f;
 
     private final ArrayList<View> mAllViews = new ArrayList<>();
+    private final ArrayList<View> mTopFiveQs = new ArrayList<>();
     private final QuickQSPanel mQuickQsPanel;
     private final QSPanel mQsPanel;
     private final QSContainer mQsContainer;
 
+    private PagedTileLayout mPagedLayout;
+
     private boolean mOnFirstPage = true;
     private TouchAnimator mFirstPageAnimator;
     private TouchAnimator mFirstPageDelayedAnimator;
+    private TouchAnimator mTranslationXAnimator;
     private TouchAnimator mTranslationYAnimator;
     private TouchAnimator mNonfirstPageAnimator;
+    private TouchAnimator mLastRowAnimator;
+
+    private boolean mOnKeyguard;
+
+    private boolean mAllowFancy;
+    private boolean mFullRows;
+    private int mNumQuickTiles;
+    private float mLastPosition;
 
     public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
         mQsContainer = container;
         mQuickQsPanel = quickPanel;
         mQsPanel = panel;
-        mQuickQsPanel.addOnLayoutChangeListener(this);
-        mQsPanel.addOnLayoutChangeListener(this);
+        mQsPanel.addOnAttachStateChangeListener(this);
+        container.addOnLayoutChangeListener(this);
         QSTileLayout tileLayout = mQsPanel.getTileLayout();
         if (tileLayout instanceof PagedTileLayout) {
-            ((PagedTileLayout) tileLayout).setPageListener(this);
+            mPagedLayout = ((PagedTileLayout) tileLayout);
+            mPagedLayout.setPageListener(this);
         } else {
             Log.w(TAG, "QS Not using page layout");
         }
     }
 
-    public void setHost(QSTileHost qsh) {
-        qsh.addCallback(this);
+    public void onRtlChanged() {
+        updateAnimators();
     }
 
-    @Override
-    public void onPageChanged(int page) {
-        mOnFirstPage = page == 0;
-        if (!mOnFirstPage) {
+    public void setOnKeyguard(boolean onKeyguard) {
+        mOnKeyguard = onKeyguard;
+        if (mOnKeyguard) {
             clearAnimationState();
         }
     }
 
+    public void setHost(QSTileHost qsh) {
+        qsh.addCallback(this);
+        updateAnimators();
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View v) {
+        TunerService.get(mQsContainer.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
+                MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        TunerService.get(mQsContainer.getContext()).removeTunable(this);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (ALLOW_FANCY_ANIMATION.equals(key)) {
+            mAllowFancy = newValue == null || Integer.parseInt(newValue) != 0;
+            if (!mAllowFancy) {
+                clearAnimationState();
+            }
+        } else if (MOVE_FULL_ROWS.equals(key)) {
+            mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
+        } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
+            mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQsContainer.getContext());
+            clearAnimationState();
+        }
+        updateAnimators();
+    }
+
+    @Override
+    public void onPageChanged(boolean isFirst) {
+        if (mOnFirstPage == isFirst) return;
+        if (!isFirst) {
+            clearAnimationState();
+        }
+        mOnFirstPage = isFirst;
+    }
+
     private void updateAnimators() {
         TouchAnimator.Builder firstPageBuilder = new Builder();
+        TouchAnimator.Builder translationXBuilder = new Builder();
         TouchAnimator.Builder translationYBuilder = new Builder();
-        TouchAnimator.Builder firstPageDelayedBuilder = new Builder();
+        TouchAnimator.Builder lastRowBuilder = new Builder();
+
+        if (mQsPanel.getHost() == null) return;
         Collection<QSTile<?>> tiles = mQsPanel.getHost().getTiles();
         int count = 0;
         int[] loc1 = new int[2];
         int[] loc2 = new int[2];
-        firstPageDelayedBuilder.setStartDelay(EXPANDED_TILE_DELAY);
-        firstPageBuilder.setListener(this);
-        translationYBuilder.setInterpolator(TRANSLATION_Y_INTERPOLATOR);
+        int lastXDiff = 0;
+        int lastYDiff = 0;
+        int lastX = 0;
+
+        clearAnimationState();
         mAllViews.clear();
+        mTopFiveQs.clear();
+
+        mAllViews.add((View) mQsPanel.getTileLayout());
+
         for (QSTile<?> tile : tiles) {
             QSTileBaseView tileView = mQsPanel.getTileView(tile);
             final TextView label = ((QSTileView) tileView).getLabel();
-            if (count++ < 5) {
+            final View tileIcon = tileView.getIcon();
+            if (count < mNumQuickTiles && mAllowFancy) {
                 // Quick tiles.
                 QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
-                final View tileIcon = tileView.getIcon();
 
+                lastX = loc1[0];
                 getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
                 getRelativePosition(loc2, tileIcon, mQsContainer);
                 final int xDiff = loc2[0] - loc1[0];
                 final int yDiff = loc2[1] - loc1[1];
+                lastXDiff = loc1[0] - lastX;
+                lastYDiff = yDiff;
                 // Move the quick tile right from its location to the new one.
-                firstPageBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
+                translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
                 translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
 
                 // Counteract the parent translation on the tile. So we have a static base to
-                // animate off from.
+                // animate the label position off from.
                 firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
 
-                // Move the real tile's icon and label from the quick tile position to its final
+                // Move the real tile's label from the quick tile position to its final
                 // location.
-                firstPageBuilder.addFloat(tileIcon, "translationX", -xDiff, 0);
-                translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
-                firstPageBuilder.addFloat(label, "translationX", -xDiff, 0);
+                translationXBuilder.addFloat(label, "translationX", -xDiff, 0);
                 translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
 
-                // Fade in the label as we reach the final position.
-                firstPageDelayedBuilder.addFloat(label, "alpha", 0, 1);
+                mTopFiveQs.add(tileIcon);
+                mAllViews.add(tileIcon);
                 mAllViews.add(quickTileView);
+            } else if (mFullRows && isIconInAnimatedRow(count)) {
+                // TODO: Refactor some of this, it shares a lot with the above block.
+                // Move the last tile position over by the last difference between quick tiles.
+                // This makes the extra icons seems as if they are coming from positions in the
+                // quick panel.
+                loc1[0] += lastXDiff;
+                getRelativePosition(loc2, tileIcon, mQsContainer);
+                final int xDiff = loc2[0] - loc1[0];
+                final int yDiff = loc2[1] - loc1[1];
+
+                firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+                translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
+                translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
+                translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
+
+                mAllViews.add(tileIcon);
             } else {
-                firstPageDelayedBuilder.addFloat(tileView, "alpha", 0, 1);
+                lastRowBuilder.addFloat(tileView, "alpha", 0, 1);
             }
             mAllViews.add(tileView);
             mAllViews.add(label);
+            count++;
         }
-        mFirstPageAnimator = firstPageBuilder.build();
-        mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
-        mTranslationYAnimator = translationYBuilder.build();
+        if (mAllowFancy) {
+            mFirstPageAnimator = firstPageBuilder
+                    .setListener(this)
+                    .build();
+            // Fade in the tiles/labels as we reach the final position.
+            mFirstPageDelayedAnimator = new TouchAnimator.Builder()
+                    .setStartDelay(EXPANDED_TILE_DELAY)
+                    .addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1).build();
+            mLastRowAnimator = lastRowBuilder
+                    .setStartDelay(LAST_ROW_EXPANDED_DELAY)
+                    .build();
+            Path path = new Path();
+            path.moveTo(0, 0);
+            path.cubicTo(0, 0, 0, 1, 1, 1);
+            PathInterpolatorBuilder interpolatorBuilder = new PathInterpolatorBuilder(0, 0, 0, 1);
+            translationXBuilder.setInterpolator(interpolatorBuilder.getXInterpolator());
+            translationYBuilder.setInterpolator(interpolatorBuilder.getYInterpolator());
+            mTranslationXAnimator = translationXBuilder.build();
+            mTranslationYAnimator = translationYBuilder.build();
+        }
         mNonfirstPageAnimator = new TouchAnimator.Builder()
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
+                .setListener(mNonFirstPageListener)
                 .setEndDelay(.5f)
                 .build();
     }
 
+    private boolean isIconInAnimatedRow(int count) {
+        if (mPagedLayout == null) {
+            return false;
+        }
+        final int columnCount = mPagedLayout.getColumnCount();
+        return count < ((mNumQuickTiles + columnCount - 1) / columnCount) * columnCount;
+    }
+
     private void getRelativePosition(int[] loc1, View view, View parent) {
         loc1[0] = 0 + view.getWidth() / 2;
         loc1[1] = 0;
@@ -143,18 +251,24 @@
 
     private void getRelativePositionInt(int[] loc1, View view, View parent) {
         if(view == parent || view == null) return;
-        loc1[0] += view.getLeft();
+        loc1[0] += view.getX();
         loc1[1] += view.getTop();
         getRelativePositionInt(loc1, (View) view.getParent(), parent);
     }
 
     public void setPosition(float position) {
         if (mFirstPageAnimator == null) return;
-        if (mOnFirstPage) {
+        if (mOnKeyguard) {
+            return;
+        }
+        mLastPosition = position;
+        if (mOnFirstPage && mAllowFancy) {
             mQuickQsPanel.setAlpha(1);
             mFirstPageAnimator.setPosition(position);
             mFirstPageDelayedAnimator.setPosition(position);
+            mTranslationXAnimator.setPosition(position);
             mTranslationYAnimator.setPosition(position);
+            mLastRowAnimator.setPosition(position);
         } else {
             mNonfirstPageAnimator.setPosition(position);
         }
@@ -162,34 +276,49 @@
 
     @Override
     public void onAnimationAtStart() {
-
+        mQuickQsPanel.setVisibility(View.VISIBLE);
     }
 
     @Override
     public void onAnimationAtEnd() {
         mQuickQsPanel.setVisibility(View.INVISIBLE);
+        final int N = mTopFiveQs.size();
+        for (int i = 0; i < N; i++) {
+            mTopFiveQs.get(i).setVisibility(View.VISIBLE);
+        }
     }
 
     @Override
     public void onAnimationStarted() {
         mQuickQsPanel.setVisibility(View.VISIBLE);
+        if (mOnFirstPage) {
+            final int N = mTopFiveQs.size();
+            for (int i = 0; i < N; i++) {
+                mTopFiveQs.get(i).setVisibility(View.INVISIBLE);
+            }
+        }
     }
 
     private void clearAnimationState() {
         final int N = mAllViews.size();
         mQuickQsPanel.setAlpha(0);
+        mQuickQsPanel.setVisibility(View.VISIBLE);
         for (int i = 0; i < N; i++) {
             View v = mAllViews.get(i);
             v.setAlpha(1);
             v.setTranslationX(1);
             v.setTranslationY(1);
         }
+        final int N2 = mTopFiveQs.size();
+        for (int i = 0; i < N2; i++) {
+            mTopFiveQs.get(i).setVisibility(View.VISIBLE);
+        }
     }
 
     @Override
     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
             int oldTop, int oldRight, int oldBottom) {
-        updateAnimators();
+        mQsPanel.post(mUpdateAnimators);
     }
 
     @Override
@@ -199,10 +328,19 @@
         mQsPanel.post(mUpdateAnimators);
     }
 
+    private final TouchAnimator.Listener mNonFirstPageListener =
+            new TouchAnimator.ListenerAdapter() {
+                @Override
+                public void onAnimationStarted() {
+                    mQuickQsPanel.setVisibility(View.VISIBLE);
+                }
+            };
+
     private Runnable mUpdateAnimators = new Runnable() {
         @Override
         public void run() {
             updateAnimators();
+            setPosition(mLastPosition);
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index c59da8d..5d06aeb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -19,6 +19,8 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
@@ -26,7 +28,9 @@
 import android.widget.FrameLayout;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
@@ -39,6 +43,9 @@
     private static final String TAG = "QSContainer";
     private static final boolean DEBUG = false;
 
+    private final Point mSizePoint = new Point();
+    private final Rect mQsBounds = new Rect();
+
     private int mHeightOverride = -1;
     private QSPanel mQSPanel;
     private QSDetail mQSDetail;
@@ -51,6 +58,8 @@
 
     private long mDelay;
     private QSAnimator mQSAnimator;
+    private QSCustomizer mQSCustomizer;
+    private NotificationPanelView mPanelView;
 
     public QSContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -65,21 +74,39 @@
         mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
         mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
                 mQSPanel);
+        mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
+        mQSCustomizer.setQsContainer(this);
+    }
+
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        mQSAnimator.onRtlChanged();
     }
 
     public void setHost(QSTileHost qsh) {
-        mQSPanel.setHost(qsh);
+        mQSPanel.setHost(qsh, mQSCustomizer);
         mHeader.setQSPanel(mQSPanel);
         mQSDetail.setHost(qsh);
         mQSAnimator.setHost(qsh);
     }
 
+    public void setPanelView(NotificationPanelView panelView) {
+        mPanelView = panelView;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Since we control our own bottom, be whatever size we want.
         // Otherwise the QSPanel ends up with 0 height when the window is only the
         // size of the status bar.
         super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
+
+        // QSCustomizer is always be the height of the screen, but do this after
+        // other measuring to avoid changing the height of the QSContainer.
+        getDisplay().getRealSize(mSizePoint);
+        mQSCustomizer.measure(widthMeasureSpec,
+                MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
     }
 
     @Override
@@ -88,6 +115,10 @@
         updateBottom();
     }
 
+    public boolean isCustomizing() {
+        return mQSCustomizer.isCustomizing();
+    }
+
     /**
      * Overrides the height of this view (post-layout), so that the content is clipped to that
      * height and the background is set to that height.
@@ -104,6 +135,9 @@
      * during closing the detail panel, this already returns the smaller height.
      */
     public int getDesiredHeight() {
+        if (isCustomizing()) {
+            return getHeight();
+        }
         if (mQSDetail.isClosingDetail()) {
             return mQSPanel.getGridHeight() + mHeader.getCollapsedHeight() + getPaddingBottom();
         } else {
@@ -111,9 +145,20 @@
         }
     }
 
+    public void notifyCustomizeChanged() {
+        // The customize state changed, so our height changed.
+        updateBottom();
+        mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        // Let the panel know the position changed and it needs to update where notifications
+        // and whatnot are.
+        mPanelView.onQsHeightChanged();
+    }
+
     private void updateBottom() {
         int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
-        int height = (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+        int height = mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
+                : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
                 + mHeader.getCollapsedHeight();
         setBottom(getTop() + height);
         mQSDetail.setBottom(getTop() + height);
@@ -138,6 +183,10 @@
         return mQSPanel;
     }
 
+    public QSCustomizer getCustomizer() {
+        return mQSCustomizer;
+    }
+
     public boolean isShowingDetail() {
         return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
     }
@@ -156,6 +205,7 @@
     public void setKeyguardShowing(boolean keyguardShowing) {
         if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
         mKeyguardShowing = keyguardShowing;
+        mQSAnimator.setOnKeyguard(keyguardShowing);
         updateQsState();
     }
 
@@ -184,6 +234,12 @@
         mQSDetail.setFullyExpanded(expansion == 1);
         mQSAnimator.setPosition(expansion);
         updateBottom();
+
+        // Set bounds on the QS panel so it doesn't run over the header.
+        mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
+        mQsBounds.right = mQSPanel.getWidth();
+        mQsBounds.bottom = mQSPanel.getHeight();
+        mQSPanel.setClipBounds(mQsBounds);
     }
 
     public void animateHeaderSlidingIn(long delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 6d8b476..51efbf0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -36,12 +36,12 @@
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.SecurityController;
 
+import static android.provider.Settings.ACTION_VPN_SETTINGS;
+
 public class QSFooter implements OnClickListener, DialogInterface.OnClickListener {
     protected static final String TAG = "QSFooter";
     protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
-
     private final View mRootView;
     private final TextView mFooterText;
     private final ImageView mFooterIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index 1df372b..546f8c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -23,7 +23,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
-
 import android.widget.ImageView.ScaleType;
 import com.android.systemui.R;
 
@@ -34,6 +33,7 @@
     private final View mIcon;
     private final int mIconSizePx;
     private final int mTilePaddingBelowIconPx;
+    private boolean mAnimationEnabled = true;
 
     public QSIconView(Context context) {
         super(context);
@@ -46,6 +46,10 @@
         addView(mIcon);
     }
 
+    public void disableAnimation() {
+        mAnimationEnabled = false;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int w = MeasureSpec.getSize(widthMeasureSpec);
@@ -69,13 +73,17 @@
 
     protected void setIcon(ImageView iv, QSTile.State state) {
         if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
-            Drawable d = state.icon != null ? state.icon.getDrawable(mContext) : null;
+            Drawable d = state.icon != null
+                    ? iv.isShown() && mAnimationEnabled ? state.icon.getDrawable(mContext)
+                    : state.icon.getInvisibleDrawable(mContext) : null;
+            int padding = state.icon != null ? state.icon.getPadding() : null;
             if (d != null && state.autoMirrorDrawable) {
                 d.setAutoMirrored(true);
             }
             iv.setImageDrawable(d);
             iv.setTag(R.id.qs_icon_tag, state.icon);
-            if (d instanceof Animatable) {
+            iv.setPadding(0, padding, 0, padding);
+            if (d instanceof Animatable && iv.isShown()) {
                 Animatable a = (Animatable) d;
                 a.start();
                 if (!iv.isShown()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 30a9850..a05818a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -31,6 +31,7 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile.DetailAdapter;
+import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.settings.BrightnessController;
@@ -44,7 +45,7 @@
 import java.util.Collection;
 
 /** View that represents the quick settings tile panel. **/
-public class QSPanel extends LinearLayout implements Tunable {
+public class QSPanel extends LinearLayout implements Tunable, Callback {
 
     public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
 
@@ -118,15 +119,27 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         TunerService.get(mContext).addTunable(this, QS_SHOW_BRIGHTNESS);
+        if (mHost != null) {
+            setTiles(mHost.getTiles());
+        }
     }
 
     @Override
     protected void onDetachedFromWindow() {
         TunerService.get(mContext).removeTunable(this);
+        mHost.removeCallback(this);
+        for (TileRecord record : mRecords) {
+            record.tile.removeCallbacks();
+        }
         super.onDetachedFromWindow();
     }
 
     @Override
+    public void onTilesChanged() {
+        setTiles(mHost.getTiles());
+    }
+
+    @Override
     public void onTuningChanged(String key, String newValue) {
         if (QS_SHOW_BRIGHTNESS.equals(key)) {
             mBrightnessView.setVisibility(newValue == null || Integer.parseInt(newValue) != 0
@@ -148,12 +161,6 @@
         return mHost.createTile(subPanel);
     }
 
-    protected void createCustomizePanel() {
-        mCustomizePanel = (QSCustomizer) LayoutInflater.from(mContext)
-                .inflate(R.layout.qs_customize_panel, null);
-        mCustomizePanel.setHost(mHost);
-    }
-
     public void setBrightnessMirror(BrightnessMirrorController c) {
         super.onFinishInflate();
         ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
@@ -166,10 +173,15 @@
         mCallback = callback;
     }
 
-    public void setHost(QSTileHost host) {
+    public void setHost(QSTileHost host, QSCustomizer customizer) {
         mHost = host;
+        mHost.addCallback(this);
+        setTiles(mHost.getTiles());
         mFooter.setHost(host);
-        createCustomizePanel();
+        mCustomizePanel = customizer;
+        if (mCustomizePanel != null) {
+            mCustomizePanel.setHost(mHost);
+        }
     }
 
     public QSTileHost getHost() {
@@ -272,7 +284,7 @@
         }
     }
 
-    private void drawTile(TileRecord r, QSTile.State state) {
+    protected void drawTile(TileRecord r, QSTile.State state) {
         r.tileView.onStateChanged(state);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index f02424b..3e32905 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -29,6 +29,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.qs.external.TileServices;
@@ -212,6 +214,7 @@
     }
 
     protected void handleLongClick() {
+        MetricsLogger.action(mContext, MetricsEvent.ACTION_QS_LONG_PRESS, getTileSpec());
         mHost.startActivityDismissingKeyguard(getLongClickIntent());
     }
 
@@ -294,6 +297,8 @@
         }
     }
 
+    public abstract CharSequence getTileLabel();
+
     protected final class H extends Handler {
         private static final int ADD_CALLBACK = 1;
         private static final int CLICK = 2;
@@ -390,6 +395,7 @@
         Context getContext();
         Collection<QSTile<?>> getTiles();
         void addCallback(Callback callback);
+        void removeCallback(Callback callback);
         BluetoothController getBluetoothController();
         LocationController getLocationController();
         RotationLockController getRotationLockController();
@@ -416,10 +422,18 @@
     public static abstract class Icon {
         abstract public Drawable getDrawable(Context context);
 
+        public Drawable getInvisibleDrawable(Context context) {
+            return getDrawable(context);
+        }
+
         @Override
         public int hashCode() {
             return Icon.class.hashCode();
         }
+
+        public int getPadding() {
+            return 0;
+        }
     }
 
     public static class DrawableIcon extends Icon {
@@ -433,6 +447,11 @@
         public Drawable getDrawable(Context context) {
             return mDrawable;
         }
+
+        @Override
+        public Drawable getInvisibleDrawable(Context context) {
+            return mDrawable;
+        }
     }
 
     public static class ResourceIcon extends Icon {
@@ -459,6 +478,11 @@
         }
 
         @Override
+        public Drawable getInvisibleDrawable(Context context) {
+            return context.getDrawable(mResId);
+        }
+
+        @Override
         public boolean equals(Object o) {
             return o instanceof ResourceIcon && ((ResourceIcon) o).mResId == mResId;
         }
@@ -470,14 +494,17 @@
     }
 
     protected class AnimationIcon extends ResourceIcon {
-        public AnimationIcon(int resId) {
-            super(resId);
+        private final int mAnimatedResId;
+
+        public AnimationIcon(int resId, int staticResId) {
+            super(staticResId);
+            mAnimatedResId = resId;
         }
 
         @Override
         public Drawable getDrawable(Context context) {
             // workaround: get a clean state for every new AVD
-            return context.getDrawable(mResId).getConstantState().newDrawable();
+            return context.getDrawable(mAnimatedResId).getConstantState().newDrawable();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index f35aacf..9e40cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -48,7 +48,7 @@
 
         // Default to Quick Tile padding, and QSTileView will specify its own padding.
         int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
-        setPadding(padding, padding, padding, padding);
+        setPadding(0, padding, 0, padding);
         setClipChildren(false);
         setClipToPadding(false);
     }
@@ -113,7 +113,7 @@
         setContentDescription(state.contentDescription);
     }
 
-    View getIcon() {
+    public QSIconView getIcon() {
         return mIcon;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 98a1c23..57a1a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -37,7 +37,7 @@
     private final int mTileSpacingPx;
     private int mTilePaddingTopPx;
 
-    private TextView mLabel;
+    protected TextView mLabel;
     private ImageView mPadLock;
 
     public QSTileView(Context context, QSIconView icon) {
@@ -81,7 +81,7 @@
         FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
     }
 
-    private void createLabel() {
+    protected void createLabel() {
         final Resources res = mContext.getResources();
         View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
         mLabel = (TextView) view.findViewById(R.id.tile_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index abe4c77..2ef3672 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -24,6 +24,12 @@
 import android.widget.LinearLayout;
 import android.widget.Space;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.SignalState;
+import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -33,6 +39,8 @@
  */
 public class QuickQSPanel extends QSPanel {
 
+    public static final String NUM_QUICK_TILES = "sysui_qqs_count";
+
     private int mMaxTiles;
     private QSPanel mFullPanel;
     private View mHeader;
@@ -50,8 +58,15 @@
     }
 
     @Override
-    protected void createCustomizePanel() {
-        // No customizing from the header.
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        TunerService.get(mContext).addTunable(mNumTiles, NUM_QUICK_TILES);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        TunerService.get(mContext).removeTunable(mNumTiles);
     }
 
     public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
@@ -60,6 +75,19 @@
     }
 
     @Override
+    protected void drawTile(TileRecord r, State state) {
+        if (state instanceof SignalState) {
+            State copy = r.tile.newTileState();
+            state.copyTo(copy);
+            // No activity shown in the quick panel.
+            ((SignalState) copy).activityIn = false;
+            ((SignalState) copy).activityOut = false;
+            state = copy;
+        }
+        super.drawTile(r, state);
+    }
+
+    @Override
     protected void showDetail(boolean show, Record r) {
         // Do nothing, will be handled by the QSPanel.
     }
@@ -69,8 +97,17 @@
         return new QSTileBaseView(mContext, tile.createTileView(mContext));
     }
 
+    @Override
+    public void setHost(QSTileHost host, QSCustomizer customizer) {
+        super.setHost(host, customizer);
+        setTiles(mHost.getTiles());
+    }
+
     public void setMaxTiles(int maxTiles) {
         mMaxTiles = maxTiles;
+        if (mHost != null) {
+            setTiles(mHost.getTiles());
+        }
     }
 
     @Override
@@ -99,6 +136,17 @@
         super.setTiles(quickTiles);
     }
 
+    private final Tunable mNumTiles = new Tunable() {
+        @Override
+        public void onTuningChanged(String key, String newValue) {
+            setMaxTiles(getNumQuickTiles(mContext));
+        }
+    };
+
+    public int getNumQuickTiles(Context context) {
+        return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
+    }
+
     private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
 
         private final Space mEndSpacer;
@@ -183,5 +231,10 @@
             // No resources here.
             return false;
         }
+
+        @Override
+        public boolean hasOverlappingRendering() {
+            return false;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index b33d31d..37f2528 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -14,8 +14,7 @@
 
 package com.android.systemui.qs;
 
-import android.animation.Keyframe;
-import android.util.Log;
+import android.util.FloatProperty;
 import android.util.MathUtils;
 import android.util.Property;
 import android.view.View;
@@ -34,19 +33,17 @@
 public class TouchAnimator {
 
     private final Object[] mTargets;
-    private final Property[] mProperties;
     private final KeyframeSet[] mKeyframeSets;
     private final float mStartDelay;
     private final float mEndDelay;
     private final float mSpan;
     private final Interpolator mInterpolator;
     private final Listener mListener;
-    private float mLastT;
+    private float mLastT = -1;
 
-    private TouchAnimator(Object[] targets, Property[] properties, KeyframeSet[] keyframeSets,
+    private TouchAnimator(Object[] targets, KeyframeSet[] keyframeSets,
             float startDelay, float endDelay, Interpolator interpolator, Listener listener) {
         mTargets = targets;
-        mProperties = properties;
         mKeyframeSets = keyframeSets;
         mStartDelay = startDelay;
         mEndDelay = endDelay;
@@ -60,24 +57,37 @@
         if (mInterpolator != null) {
             t = mInterpolator.getInterpolation(t);
         }
+        if (t == mLastT) {
+            return;
+        }
         if (mListener != null) {
-            if (mLastT == 0 || mLastT == 1) {
-                if (t != 0) {
-                    mListener.onAnimationStarted();
-                }
-            } else if (t == 1) {
+            if (t == 1) {
                 mListener.onAnimationAtEnd();
             } else if (t == 0) {
                 mListener.onAnimationAtStart();
+            } else if (mLastT <= 0 || mLastT == 1) {
+                mListener.onAnimationStarted();
             }
             mLastT = t;
         }
         for (int i = 0; i < mTargets.length; i++) {
-            Object value = mKeyframeSets[i].getValue(t);
-            mProperties[i].set(mTargets[i], value);
+            mKeyframeSets[i].setValue(t, mTargets[i]);
         }
     }
 
+    private static final FloatProperty<TouchAnimator> POSITION =
+            new FloatProperty<TouchAnimator>("position") {
+        @Override
+        public void setValue(TouchAnimator touchAnimator, float value) {
+            touchAnimator.setPosition(value);
+        }
+
+        @Override
+        public Float get(TouchAnimator touchAnimator) {
+            return touchAnimator.mLastT;
+        }
+    };
+
     public static class ListenerAdapter implements Listener {
         @Override
         public void onAnimationAtStart() { }
@@ -111,7 +121,6 @@
 
     public static class Builder {
         private List<Object> mTargets = new ArrayList<>();
-        private List<Property> mProperties = new ArrayList<>();
         private List<KeyframeSet> mValues = new ArrayList<>();
 
         private float mStartDelay;
@@ -120,22 +129,21 @@
         private Listener mListener;
 
         public Builder addFloat(Object target, String property, float... values) {
-            add(target, property, KeyframeSet.ofFloat(values));
+            add(target, KeyframeSet.ofFloat(getProperty(target, property, float.class), values));
             return this;
         }
 
         public Builder addInt(Object target, String property, int... values) {
-            add(target, property, KeyframeSet.ofInt(values));
+            add(target, KeyframeSet.ofInt(getProperty(target, property, int.class), values));
             return this;
         }
 
-        private void add(Object target, String property, KeyframeSet keyframeSet) {
+        private void add(Object target, KeyframeSet keyframeSet) {
             mTargets.add(target);
-            mProperties.add(getProperty(target, property));
             mValues.add(keyframeSet);
         }
 
-        private static Property getProperty(Object target, String property) {
+        private static Property getProperty(Object target, String property, Class<?> cls) {
             if (target instanceof View) {
                 switch (property) {
                     case "translationX":
@@ -158,7 +166,10 @@
                         return View.SCALE_Y;
                 }
             }
-            return Property.of(target.getClass(), float.class, property);
+            if (target instanceof TouchAnimator && "position".equals(property)) {
+                return POSITION;
+            }
+            return Property.of(target.getClass(), cls, property);
         }
 
         public Builder setStartDelay(float startDelay) {
@@ -183,7 +194,6 @@
 
         public TouchAnimator build() {
             return new TouchAnimator(mTargets.toArray(new Object[mTargets.size()]),
-                    mProperties.toArray(new Property[mProperties.size()]),
                     mValues.toArray(new KeyframeSet[mValues.size()]),
                     mStartDelay, mEndDelay, mInterpolator, mListener);
         }
@@ -199,54 +209,57 @@
             mFrameWidth = 1 / (float) (size - 1);
         }
 
-        Object getValue(float fraction) {
+        void setValue(float fraction, Object target) {
             int i;
             for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++);
             float amount = fraction / mFrameWidth;
-            return interpolate(i, amount);
+            interpolate(i, amount, target);
         }
 
-        protected abstract Object interpolate(int index, float amount);
+        protected abstract void interpolate(int index, float amount, Object target);
 
-        public static KeyframeSet ofInt(int... values) {
-            return new IntKeyframeSet(values);
+        public static KeyframeSet ofInt(Property property, int... values) {
+            return new IntKeyframeSet((Property<?, Integer>) property, values);
         }
 
-        public static KeyframeSet ofFloat(float... values) {
-            return new FloatKeyframeSet(values);
+        public static KeyframeSet ofFloat(Property property, float... values) {
+            return new FloatKeyframeSet((Property<?, Float>) property, values);
         }
     }
 
-    private static class FloatKeyframeSet extends KeyframeSet {
+    private static class FloatKeyframeSet<T> extends KeyframeSet {
         private final float[] mValues;
+        private final Property<T, Float> mProperty;
 
-        public FloatKeyframeSet(float[] values) {
+        public FloatKeyframeSet(Property<T, Float> property, float[] values) {
             super(values.length);
+            mProperty = property;
             mValues = values;
         }
 
         @Override
-        protected Object interpolate(int index, float amount) {
+        protected void interpolate(int index, float amount, Object target) {
             float firstFloat = mValues[index - 1];
             float secondFloat = mValues[index];
-            return firstFloat + (secondFloat - firstFloat) * amount;
+            mProperty.set((T) target, firstFloat + (secondFloat - firstFloat) * amount);
         }
     }
 
-    private static class IntKeyframeSet extends KeyframeSet {
-
+    private static class IntKeyframeSet<T> extends KeyframeSet {
         private final int[] mValues;
+        private final Property<T, Integer> mProperty;
 
-        public IntKeyframeSet(int[] values) {
+        public IntKeyframeSet(Property<T, Integer> property, int[] values) {
             super(values.length);
+            mProperty = property;
             mValues = values;
         }
 
         @Override
-        protected Object interpolate(int index, float amount) {
+        protected void interpolate(int index, float amount, Object target) {
             int firstFloat = mValues[index - 1];
             int secondFloat = mValues[index];
-            return (int) (firstFloat + (secondFloat - firstFloat) * amount);
+            mProperty.set((T) target, (int) (firstFloat + (secondFloat - firstFloat) * amount));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
new file mode 100644
index 0000000..e512f93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.customize;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSIconView;
+import com.android.systemui.qs.QSTileView;
+import libcore.util.Objects;
+
+public class CustomizeTileView extends QSTileView {
+
+    private TextView mAppLabel;
+
+    public CustomizeTileView(Context context, QSIconView icon) {
+        super(context, icon);
+    }
+
+    @Override
+    protected void createLabel() {
+        super.createLabel();
+        View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+        mAppLabel = (TextView) view.findViewById(R.id.tile_label);
+        mAppLabel.setAlpha(.6f);
+        mAppLabel.setSingleLine(true);
+        addView(view);
+    }
+
+    public void setShowAppLabel(boolean showAppLabel) {
+        mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
+        mLabel.setSingleLine(showAppLabel);
+    }
+
+    public void setAppLabel(CharSequence label) {
+        if (!Objects.equal(label, mAppLabel.getText())) {
+            mAppLabel.setText(label);
+        }
+    }
+
+    public TextView getAppLabel() {
+        return mAppLabel;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 81e1581..716185f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -17,19 +17,28 @@
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.LinearLayout;
+import android.widget.Toolbar;
+import android.widget.Toolbar.OnMenuItemClickListener;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSContainer;
 import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
@@ -42,7 +51,9 @@
  * This adds itself to the status bar window, so it can appear on top of quick settings and
  * *someday* do fancy animations to get into/out of it.
  */
-public class QSCustomizer extends LinearLayout implements AnimatorListener, OnClickListener {
+public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
+
+    private static final int MENU_RESET = Menu.FIRST;
 
     private final QSDetailClipper mClipper;
 
@@ -52,34 +63,37 @@
     private QSTileHost mHost;
     private RecyclerView mRecyclerView;
     private TileAdapter mTileAdapter;
-    private View mClose;
-    private View mSave;
-    private View mReset;
+    private Toolbar mToolbar;
+    private boolean mCustomizing;
+    private NotificationsQuickSettingsContainer mNotifQsContainer;
+    private QSContainer mQsContainer;
 
     public QSCustomizer(Context context, AttributeSet attrs) {
-        super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
+        super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
         mClipper = new QSDetailClipper(this);
-    }
 
-    public void setHost(QSTileHost host) {
-        mHost = host;
-        mPhoneStatusBar = host.getPhoneStatusBar();
-    }
+        LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
 
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mClose = findViewById(R.id.close);
-        mSave = findViewById(R.id.save);
-        mReset = findViewById(R.id.reset);
-        mClose.setOnClickListener(this);
-        mSave.setOnClickListener(this);
-        mReset.setOnClickListener(this);
+        mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar);
+        TypedValue value = new TypedValue();
+        mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
+        mToolbar.setNavigationIcon(
+                getResources().getDrawable(value.resourceId, mContext.getTheme()));
+        mToolbar.setNavigationOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                hide((int) v.getX() + v.getWidth() / 2, (int) v.getY() + v.getHeight() / 2);
+            }
+        });
+        mToolbar.setOnMenuItemClickListener(this);
+        mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
+                mContext.getString(com.android.internal.R.string.reset));
+        mToolbar.setTitle(R.string.qs_edit);
 
         mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
         mTileAdapter = new TileAdapter(getContext());
         mRecyclerView.setAdapter(mTileAdapter);
-        new ItemTouchHelper(mTileAdapter.getCallback()).attachToRecyclerView(mRecyclerView);
+        mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
         GridLayoutManager layout = new GridLayoutManager(getContext(), 3);
         layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
         mRecyclerView.setLayoutManager(layout);
@@ -89,25 +103,63 @@
         mRecyclerView.setItemAnimator(animator);
     }
 
+    public void setHost(QSTileHost host) {
+        mHost = host;
+        mPhoneStatusBar = host.getPhoneStatusBar();
+    }
+
+    public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
+        mNotifQsContainer = notificationsQsContainer;
+    }
+
+    public void setQsContainer(QSContainer qsContainer) {
+        mQsContainer = qsContainer;
+    }
+
     public void show(int x, int y) {
         if (!isShown) {
+            MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
             isShown = true;
-            mPhoneStatusBar.getStatusBarWindow().addView(this);
             setTileSpecs();
-            mClipper.animateCircularClip(x, y, true, this);
+            setVisibility(View.VISIBLE);
+            mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
             new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
+            mNotifQsContainer.setCustomizerAnimating(true);
+            mNotifQsContainer.setCustomizerShowing(true);
         }
     }
 
     public void hide(int x, int y) {
         if (isShown) {
+            MetricsLogger.hidden(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
             isShown = false;
-            mClipper.animateCircularClip(x, y, false, this);
+            mToolbar.dismissPopupMenus();
+            setCustomizing(false);
+            save();
+            mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
+            mNotifQsContainer.setCustomizerAnimating(true);
+            mNotifQsContainer.setCustomizerShowing(false);
         }
     }
 
+    private void setCustomizing(boolean customizing) {
+        mCustomizing = customizing;
+        mQsContainer.notifyCustomizeChanged();
+    }
+
     public boolean isCustomizing() {
-        return isShown;
+        return mCustomizing;
+    }
+
+    @Override
+    public boolean onMenuItemClick(MenuItem item) {
+        switch (item.getItemId()) {
+            case MENU_RESET:
+                MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_QS_EDIT_RESET);
+                reset();
+                break;
+        }
+        return false;
     }
 
     private void reset() {
@@ -125,46 +177,41 @@
             specs.add(tile.getTileSpec());
         }
         mTileAdapter.setTileSpecs(specs);
+        mRecyclerView.setAdapter(mTileAdapter);
     }
 
     private void save() {
         mTileAdapter.saveSpecs(mHost);
-        hide((int) mSave.getX() + mSave.getWidth() / 2, (int) mSave.getY() + mSave.getHeight() / 2);
     }
 
-    @Override
-    public void onClick(View v) {
-        if (v == mClose) {
-            hide((int) mClose.getX() + mClose.getWidth() / 2,
-                    (int) mClose.getY() + mClose.getHeight() / 2);
-        } else if (v == mSave) {
-            save();
-        } else if (v == mReset) {
-            reset();
+    private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            setCustomizing(true);
+            mNotifQsContainer.setCustomizerAnimating(false);
         }
-    }
 
-    @Override
-    public void onAnimationEnd(Animator animation) {
-        if (!isShown) {
-            mPhoneStatusBar.getStatusBarWindow().removeView(this);
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mNotifQsContainer.setCustomizerAnimating(false);
         }
-    }
+    };
 
-    @Override
-    public void onAnimationCancel(Animator animation) {
-        if (!isShown) {
-            mPhoneStatusBar.getStatusBarWindow().removeView(this);
+    private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (!isShown) {
+                setVisibility(View.GONE);
+            }
+            mNotifQsContainer.setCustomizerAnimating(false);
         }
-    }
 
-    @Override
-    public void onAnimationStart(Animator animation) {
-        // Don't care.
-    }
-
-    @Override
-    public void onAnimationRepeat(Animator animation) {
-        // Don't care.
-    }
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            if (!isShown) {
+                setVisibility(View.GONE);
+            }
+            mNotifQsContainer.setCustomizerAnimating(false);
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index fb3818c..e8e17b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,9 +14,14 @@
 
 package com.android.systemui.qs.customize;
 
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.graphics.Canvas;
 import android.graphics.drawable.ColorDrawable;
+import android.os.Handler;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
 import android.support.v7.widget.RecyclerView;
@@ -24,18 +29,24 @@
 import android.support.v7.widget.RecyclerView.State;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.support.v7.widget.helper.ItemTouchHelper;
-import android.support.v7.widget.helper.ItemTouchHelper.Callback;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLayoutChangeListener;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
+import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSIconView;
-import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.customize.TileAdapter.Holder;
 import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
 import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
+import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -48,29 +59,44 @@
 
     private static final int TYPE_TILE = 0;
     private static final int TYPE_EDIT = 1;
+    private static final int TYPE_ACCESSIBLE_DROP = 2;
+    private static final int TYPE_DIVIDER = 4;
+
+    private static final long EDIT_ID = 10000;
+    private static final long DIVIDER_ID = 20000;
 
     private final Context mContext;
 
+    private final Handler mHandler = new Handler();
     private final List<TileInfo> mTiles = new ArrayList<>();
-    private int mDividerIndex;
+    private final ItemTouchHelper mItemTouchHelper;
+    private final AccessibilityManager mAccessibilityManager;
+    private int mEditIndex;
+    private int mTileDividerIndex;
+    private boolean mNeedsFocus;
     private List<String> mCurrentSpecs;
     private List<TileInfo> mOtherTiles;
     private List<TileInfo> mAllTiles;
 
     private Holder mCurrentDrag;
+    private boolean mAccessibilityMoving;
+    private int mAccessibilityFromIndex;
 
     public TileAdapter(Context context) {
         mContext = context;
+        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+        mItemTouchHelper = new ItemTouchHelper(mCallbacks);
         setHasStableIds(true);
     }
 
     @Override
     public long getItemId(int position) {
-        return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
+        return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position))
+                : position == mEditIndex ? EDIT_ID : DIVIDER_ID;
     }
 
-    public Callback getCallback() {
-        return mCallbacks;
+    public ItemTouchHelper getItemTouchHelper() {
+        return mItemTouchHelper;
     }
 
     public ItemDecoration getItemDecoration() {
@@ -79,7 +105,7 @@
 
     public void saveSpecs(QSTileHost host) {
         List<String> newSpecs = new ArrayList<>();
-        for (int i = 0; mTiles.get(i) != null; i++) {
+        for (int i = 0; i < mTiles.size() && mTiles.get(i) != null; i++) {
             newSpecs.add(mTiles.get(i).spec);
         }
         host.changeTiles(mCurrentSpecs, newSpecs);
@@ -104,11 +130,25 @@
         mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
         mTiles.clear();
         for (int i = 0; i < mCurrentSpecs.size(); i++) {
-            mTiles.add(getAndRemoveOther(mCurrentSpecs.get(i)));
+            final TileInfo tile = getAndRemoveOther(mCurrentSpecs.get(i));
+            if (tile != null) {
+                mTiles.add(tile);
+            }
         }
         mTiles.add(null);
+        for (int i = 0; i < mOtherTiles.size(); i++) {
+            final TileInfo tile = mOtherTiles.get(i);
+            if (tile.isSystem) {
+                mOtherTiles.remove(i--);
+                mTiles.add(tile);
+            }
+        }
+        if (mOtherTiles.size() != 0) {
+            mTileDividerIndex = mTiles.size();
+            mTiles.add(null);
+        }
         mTiles.addAll(mOtherTiles);
-        mDividerIndex = mTiles.indexOf(null);
+        mEditIndex = mTiles.indexOf(null);
         notifyDataSetChanged();
     }
 
@@ -123,6 +163,12 @@
 
     @Override
     public int getItemViewType(int position) {
+        if (mAccessibilityMoving && position == mEditIndex - 1) {
+            return TYPE_ACCESSIBLE_DROP;
+        }
+        if (position == mTileDividerIndex) {
+            return TYPE_DIVIDER;
+        }
         if (mTiles.get(position) == null) {
             return TYPE_EDIT;
         }
@@ -133,12 +179,15 @@
     public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
         final Context context = parent.getContext();
         LayoutInflater inflater = LayoutInflater.from(context);
-        if (viewType == 1) {
+        if (viewType == TYPE_DIVIDER) {
+            return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
+        }
+        if (viewType == TYPE_EDIT) {
             return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
         }
         FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
                 false);
-        frame.addView(new QSTileView(context, new QSIconView(context)));
+        frame.addView(new CustomizeTileView(context, new QSIconView(context)));
         return new Holder(frame);
     }
 
@@ -148,24 +197,224 @@
     }
 
     @Override
-    public void onBindViewHolder(Holder holder, int position) {
-        if (holder.getItemViewType() == TYPE_EDIT) return;
+    public void onBindViewHolder(final Holder holder, final int position) {
+        if (holder.getItemViewType() == TYPE_DIVIDER) {
+            return;
+        }
+        if (holder.getItemViewType() == TYPE_EDIT) {
+            ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
+                    mCurrentDrag != null ? R.string.drag_to_remove_tiles
+                    : R.string.drag_to_add_tiles);
+            return;
+        }
+        if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
+            holder.mTileView.setClickable(true);
+            holder.mTileView.setFocusable(true);
+            holder.mTileView.setFocusableInTouchMode(true);
+            holder.mTileView.setVisibility(View.VISIBLE);
+            holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+            holder.mTileView.setContentDescription(mContext.getString(
+                    R.string.accessibility_qs_edit_position_label, position + 1));
+            holder.mTileView.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    selectPosition(position, v);
+                }
+            });
+            if (mNeedsFocus) {
+                // Wait for this to get laid out then set its focus.
+                holder.mTileView.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) {
+                        holder.mTileView.removeOnLayoutChangeListener(this);
+                        holder.mTileView.requestFocus();
+                    }
+                });
+                mNeedsFocus = false;
+            }
+            return;
+        }
 
         TileInfo info = mTiles.get(position);
+
+        if (position > mEditIndex) {
+            info.state.contentDescription = mContext.getString(
+                    R.string.accessibility_qs_edit_add_tile_label, info.state.label);
+        } else if (mAccessibilityMoving) {
+            info.state.contentDescription = mContext.getString(
+                    R.string.accessibility_qs_edit_position_label, position + 1);
+        } else {
+            info.state.contentDescription = mContext.getString(
+                    R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
+        }
         holder.mTileView.onStateChanged(info.state);
+        holder.mTileView.setAppLabel(info.appLabel);
+        holder.mTileView.setShowAppLabel(position > mTileDividerIndex);
+
+        if (mAccessibilityManager.isTouchExplorationEnabled()) {
+            final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
+            holder.mTileView.setClickable(selectable);
+            holder.mTileView.setFocusable(selectable);
+            holder.mTileView.setImportantForAccessibility(selectable
+                    ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+                    : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            if (selectable) {
+                holder.mTileView.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        if (mAccessibilityMoving) {
+                            selectPosition(position, v);
+                        } else {
+                            if (position < mEditIndex) {
+                                showAccessibilityDialog(position, v);
+                            } else {
+                                startAccessibleDrag(position);
+                            }
+                        }
+                    }
+                });
+            }
+        }
+    }
+
+    private void selectPosition(int position, View v) {
+        // Remove the placeholder.
+        mTiles.remove(mEditIndex--);
+        mAccessibilityMoving = false;
+        move(mAccessibilityFromIndex, position, v);
+        notifyDataSetChanged();
+    }
+
+    private void showAccessibilityDialog(final int position, final View v) {
+        TileInfo info = mTiles.get(position);
+        CharSequence[] options = new CharSequence[] {
+                mContext.getString(R.string.accessibility_qs_edit_move_tile, info.state.label),
+                mContext.getString(R.string.accessibility_qs_edit_remove_tile, info.state.label),
+        };
+        AlertDialog dialog = new Builder(mContext)
+                .setItems(options, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        if (which == 0) {
+                            startAccessibleDrag(position);
+                        } else {
+                            move(position, mEditIndex, v);
+                        }
+                    }
+                }).setNegativeButton(android.R.string.cancel, null)
+                .create();
+        SystemUIDialog.setShowForAllUsers(dialog, true);
+        SystemUIDialog.applyFlags(dialog);
+        dialog.show();
+    }
+
+    private void startAccessibleDrag(int position) {
+        mAccessibilityMoving = true;
+        mNeedsFocus = true;
+        mAccessibilityFromIndex = position;
+        // Add placeholder for last slot.
+        mTiles.add(mEditIndex++, null);
+        notifyDataSetChanged();
     }
 
     public SpanSizeLookup getSizeLookup() {
         return mSizeLookup;
     }
 
+    private boolean move(int from, int to, View v) {
+        if (to >= mEditIndex) {
+            if (from >= mEditIndex) {
+                return false;
+            }
+            // Sort tiles into system/non-system groups.
+            TileInfo tile = mTiles.get(from);
+            if (tile.isSystem) {
+                if (to > mTileDividerIndex) {
+                    to = mTileDividerIndex;
+                }
+            } else {
+                if (mTileDividerIndex == mTiles.size()) {
+                    mTiles.add(null);
+                }
+                if (to <= mTileDividerIndex) {
+                    to = mTileDividerIndex;
+                }
+            }
+        }
+        CharSequence fromLabel = mTiles.get(from).state.label;
+        move(from, to, mTiles);
+        notifyDataSetChanged();
+        updateDividerLocations();
+        CharSequence announcement;
+        if (to >= mEditIndex) {
+            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
+                    strip(mTiles.get(to)));
+            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE,
+                    from);
+            announcement = mContext.getString(R.string.accessibility_qs_edit_tile_removed,
+                    fromLabel);
+        } else if (from >= mEditIndex) {
+            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC,
+                    strip(mTiles.get(to)));
+            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
+                    to);
+            announcement = mContext.getString(R.string.accessibility_qs_edit_tile_added,
+                    fromLabel, (to + 1));
+        } else {
+            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE_SPEC,
+                    strip(mTiles.get(to)));
+            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE,
+                    to);
+            announcement = mContext.getString(R.string.accessibility_qs_edit_tile_moved,
+                    fromLabel, (to + 1));
+        }
+        v.announceForAccessibility(announcement);
+        return true;
+    }
+
+    private void updateDividerLocations() {
+        // The first null is the edit tiles label, the second null is the tile divider.
+        // If there is no second null, then there are no non-system tiles.
+        mEditIndex = -1;
+        mTileDividerIndex = mTiles.size();
+        for (int i = 0; i < mTiles.size(); i++) {
+            if (mTiles.get(i) == null) {
+                if (mEditIndex == -1) {
+                    mEditIndex = i;
+                } else {
+                    mTileDividerIndex = i;
+                }
+            }
+        }
+        if (mTiles.get(mTiles.size() - 1) == null) {
+            mTiles.remove(mTiles.size() - 1);
+        }
+    }
+
+    private String strip(TileInfo tileInfo) {
+        String spec = tileInfo.spec;
+        if (spec.startsWith(CustomTile.PREFIX)) {
+            ComponentName component = CustomTile.getComponentFromSpec(spec);
+            return component.getPackageName();
+        }
+        return spec;
+    }
+
+    private <T> void move(int from, int to, List<T> list) {
+        list.add(from > to ? to : to + 1, list.get(from));
+        list.remove(from > to ? from + 1 : from);
+    }
+
     public class Holder extends ViewHolder {
-        private QSTileView mTileView;
+        private CustomizeTileView mTileView;
 
         public Holder(View itemView) {
             super(itemView);
             if (itemView instanceof FrameLayout) {
-                mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+                mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
+                mTileView.setBackground(null);
+                mTileView.getIcon().disableAnimation();
             }
         }
 
@@ -177,6 +426,9 @@
             mTileView.findViewById(R.id.tile_label).animate()
                     .setDuration(DRAG_LENGTH)
                     .alpha(0);
+            mTileView.getAppLabel().animate()
+                    .setDuration(DRAG_LENGTH)
+                    .alpha(0);
         }
 
         public void stopDrag() {
@@ -187,13 +439,17 @@
             mTileView.findViewById(R.id.tile_label).animate()
                     .setDuration(DRAG_LENGTH)
                     .alpha(1);
+            mTileView.getAppLabel().animate()
+                    .setDuration(DRAG_LENGTH)
+                    .alpha(.6f);
         }
     }
 
     private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
         @Override
         public int getSpanSize(int position) {
-            return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
+            final int type = getItemViewType(position);
+            return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
         }
     };
 
@@ -211,7 +467,7 @@
             for (int i = 0; i < childCount; i++) {
                 final View child = parent.getChildAt(i);
                 final ViewHolder holder = parent.getChildViewHolder(child);
-                if (holder.getAdapterPosition() < mDividerIndex) {
+                if (holder.getAdapterPosition() < mEditIndex) {
                     continue;
                 }
 
@@ -244,11 +500,18 @@
             super.onSelectedChanged(viewHolder, actionState);
             if (mCurrentDrag != null) {
                 mCurrentDrag.stopDrag();
+                mCurrentDrag = null;
             }
             if (viewHolder != null) {
                 mCurrentDrag = (Holder) viewHolder;
                 mCurrentDrag.startDrag();
             }
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    notifyItemChanged(mEditIndex);
+                }
+            });
         }
 
         @Override
@@ -265,25 +528,7 @@
         public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
             int from = viewHolder.getAdapterPosition();
             int to = target.getAdapterPosition();
-            if (to > mDividerIndex) {
-                if (from < mDividerIndex) {
-                    to = mDividerIndex;
-                } else {
-                    return false;
-                }
-            }
-            if (target.getItemViewType() == TYPE_EDIT && from < mDividerIndex) {
-                to++;
-            }
-            move(from, to, mTiles);
-            mDividerIndex = mTiles.indexOf(null);
-            notifyItemMoved(from, to);
-            return true;
-        }
-
-        private <T> void move(int from, int to, List<T> list) {
-            list.add(from > to ? to : to + 1, list.get(from));
-            list.remove(from > to ? from + 1 : from);
+            return move(from, to, target.itemView);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 45f2d75..d04a2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.customize;
 
+import android.Manifest.permission;
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -30,6 +31,7 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DrawableIcon;
+import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
@@ -53,9 +55,8 @@
     }
 
     private void addSystemTiles(QSTileHost host) {
-        boolean hasColorMod = host.getNightModeController().isEnabled();
         String possible = mContext.getString(R.string.quick_settings_tiles_default)
-                + ",hotspot,inversion,saver,work,cast" + (hasColorMod ? ",night" : "");
+                + ",hotspot,inversion,saver,work,cast,night";
         String[] possibleTiles = possible.split(",");
         final Handler qsHandler = new Handler(host.getLooper());
         final Handler mainHandler = new Handler(Looper.getMainLooper());
@@ -74,10 +75,12 @@
                 public void run() {
                     final QSTile.State state = tile.newTileState();
                     tile.getState().copyTo(state);
+                    // Ignore the current state and get the generic label instead.
+                    state.label = tile.getTileLabel();
                     mainHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            addTile(spec, state);
+                            addTile(spec, null, state, true);
                             mListener.onTilesChanged(mTiles);
                         }
                     });
@@ -87,7 +90,12 @@
         qsHandler.post(new Runnable() {
             @Override
             public void run() {
-                new QueryTilesTask().execute();
+                mainHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        new QueryTilesTask().execute();
+                    }
+                });
             }
         });
     }
@@ -96,28 +104,33 @@
         mListener = listener;
     }
 
-    private void addTile(String spec, QSTile.State state) {
+    private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
         if (mSpecs.contains(spec)) {
             return;
         }
         TileInfo info = new TileInfo();
         info.state = state;
         info.spec = spec;
+        info.appLabel = appLabel;
+        info.isSystem = isSystem;
         mTiles.add(info);
         mSpecs.add(spec);
     }
 
-    private void addTile(String spec, Drawable drawable, CharSequence label, Context context) {
+    private void addTile(String spec, Drawable drawable, CharSequence label, CharSequence appLabel,
+            Context context) {
         QSTile.State state = new QSTile.State();
         state.label = label;
         state.contentDescription = label;
         state.icon = new DrawableIcon(drawable);
-        addTile(spec, state);
+        addTile(spec, appLabel, state, false);
     }
 
     public static class TileInfo {
         public String spec;
+        public CharSequence appLabel;
         public QSTile.State state;
+        public boolean isSystem;
     }
 
     private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
@@ -132,12 +145,16 @@
                 ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);
                 String spec = CustomTile.toSpec(componentName);
                 Drawable icon = info.serviceInfo.loadIcon(pm);
+                if (!permission.BIND_QUICK_SETTINGS_TILE.equals(info.serviceInfo.permission)) {
+                    continue;
+                }
                 if (icon != null) {
                     icon.mutate();
                     icon.setTint(mContext.getColor(android.R.color.white));
                 }
                 CharSequence label = info.serviceInfo.loadLabel(pm);
-                addTile(spec, icon, label != null ? label.toString() : "null", mContext);
+                final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
+                addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
             }
             return tiles;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 0709992..6114573 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -58,6 +58,7 @@
     private final IBinder mToken = new Binder();
     private final IQSTileService mService;
     private final TileServiceManager mServiceManager;
+    private final int mUser;
 
     private boolean mListening;
     private boolean mBound;
@@ -71,9 +72,11 @@
         mServiceManager = host.getTileServices().getTileWrapper(this);
         mService = mServiceManager.getTileService();
         mTile = new Tile(mComponent);
+        mUser = ActivityManager.getCurrentUser();
         try {
             PackageManager pm = mContext.getPackageManager();
-            ServiceInfo info = pm.getServiceInfo(mComponent, 0);
+            ServiceInfo info = pm.getServiceInfo(mComponent,
+                    PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
             mTile.setIcon(android.graphics.drawable.Icon
                     .createWithResource(mComponent.getPackageName(), info.icon));
             mTile.setLabel(info.loadLabel(pm));
@@ -86,6 +89,21 @@
         }
     }
 
+    @Override
+    public boolean isAvailable() {
+        try {
+            ServiceInfo info = mContext.getPackageManager().getServiceInfo(mComponent,
+                    PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    public int getUser() {
+        return mUser;
+    }
+
     public ComponentName getComponent() {
         return mComponent;
     }
@@ -203,13 +221,22 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return getState().label;
+    }
+
+    @Override
     protected void handleUpdateState(State state, Object arg) {
         Drawable drawable = mTile.getIcon().loadDrawable(mContext);
-        int color = mContext.getColor(getColor(mTile.getState()));
+        int tileState = mTile.getState();
+        if (mServiceManager.hasPendingBind()) {
+            tileState = Tile.STATE_UNAVAILABLE;
+        }
+        int color = mContext.getColor(getColor(tileState));
         drawable.setTint(color);
         state.icon = new DrawableIcon(drawable);
         state.label = mTile.getLabel();
-        if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
+        if (tileState == Tile.STATE_UNAVAILABLE) {
             state.label = new SpannableStringBuilder().append(state.label,
                     new ForegroundColorSpan(color),
                     SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index c4436f4..8910d44 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -85,6 +85,7 @@
         mHandler = handler;
         mIntent = intent;
         mUser = user;
+        if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
     }
 
     public ComponentName getComponent() {
@@ -116,13 +117,13 @@
             if (!checkComponentState()) {
                 return;
             }
-            if (DEBUG) Log.d(TAG, "Binding service " + mIntent);
+            if (DEBUG) Log.d(TAG, "Binding service " + mIntent + " " + mUser);
             mBindTryCount++;
             mContext.bindServiceAsUser(mIntent, this,
                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                     mUser);
         } else {
-            if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent);
+            if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent + " " + mUser);
             // Give it another chance next time it needs to be bound, out of kindness.
             mBindTryCount = 0;
             mWrapper = null;
@@ -248,6 +249,8 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
         mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+        filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
+        mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
         mReceiverRegistered = true;
     }
 
@@ -260,10 +263,12 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (DEBUG) Log.d(TAG, "onReceive: " + intent);
-        Uri data = intent.getData();
-        String pkgName = data.getEncodedSchemeSpecificPart();
-        if (!Objects.equal(pkgName, mIntent.getComponent().getPackageName())) {
-            return;
+        if (!Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+            Uri data = intent.getData();
+            String pkgName = data.getEncodedSchemeSpecificPart();
+            if (!Objects.equal(pkgName, mIntent.getComponent().getPackageName())) {
+                return;
+            }
         }
         stopPackageListening();
         if (mBound) {
@@ -350,7 +355,7 @@
 
     @Override
     public void onClick(IBinder iBinder) {
-        if (DEBUG) Log.d(TAG, "onClick " + iBinder);
+        if (DEBUG) Log.d(TAG, "onClick " + iBinder + " " + mUser);
         if (mWrapper == null || !mWrapper.onClick(iBinder)) {
             mClickBinder = iBinder;
             queueMessage(MSG_ON_CLICK);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 5cf1e21..664ddd6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -53,6 +53,9 @@
     private long mLastUpdate;
     private int mType;
     private boolean mShowingDialog;
+    // Whether we have a pending bind going out to the service without a response yet.
+    // This defaults to true to ensure tiles start out unavailable.
+    private boolean mPendingBind = true;
 
     TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) {
         this(tileServices, handler, new TileLifecycleManager(handler,
@@ -132,11 +135,20 @@
         }
     }
 
+    public boolean hasPendingBind() {
+        return mPendingBind;
+    }
+
+    public void clearPendingBind() {
+        mPendingBind = false;
+    }
+
     private void bindService() {
         if (mBound) {
             Log.e(TAG, "Service already bound");
             return;
         }
+        mPendingBind = true;
         mBound = true;
         mJustBound = true;
         mHandler.postDelayed(mJustBoundOver, MIN_BIND_TIME);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index bfa4a32..5bb2a35 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -182,7 +182,9 @@
         CustomTile customTile = getTileForComponent(componentName);
         if (customTile != null) {
             synchronized (mServices) {
-                mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
+                final TileServiceManager tileServiceManager = mServices.get(customTile);
+                tileServiceManager.clearPendingBind();
+                tileServiceManager.setLastUpdate(System.currentTimeMillis());
             }
             customTile.updateState(tile);
             customTile.refreshState();
@@ -190,6 +192,20 @@
     }
 
     @Override
+    public void onStartSuccessful(Tile tile) {
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            synchronized (mServices) {
+                final TileServiceManager tileServiceManager = mServices.get(customTile);
+                tileServiceManager.clearPendingBind();
+            }
+            customTile.refreshState();
+        }
+    }
+
+    @Override
     public void onShowDialog(Tile tile) {
         ComponentName componentName = tile.getComponentName();
         verifyCaller(componentName.getPackageName());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index f0860fe..5f5a87e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -33,9 +33,11 @@
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation);
+            new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation,
+                    R.drawable.ic_signal_airplane_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_airplane_disable_animation);
+            new AnimationIcon(R.drawable.ic_signal_airplane_disable_animation,
+                    R.drawable.ic_signal_airplane_enable);
     private final GlobalSetting mSetting;
 
     private boolean mListening;
@@ -74,6 +76,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.airplane_mode);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
         final boolean airplaneMode = value != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 93e075d..2032783 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -15,16 +15,20 @@
  */
 package com.android.systemui.qs.tiles;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.provider.Settings;
+import android.os.Looper;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.RelativeSizeSpan;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.Checkable;
 import android.widget.ImageView;
@@ -41,20 +45,18 @@
 
 public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
 
-    private final BatteryMeterDrawable mDrawable;
     private final BatteryController mBatteryController;
     private final BatteryDetail mBatteryDetail = new BatteryDetail();
 
     private int mLevel;
     private boolean mPowerSave;
     private boolean mCharging;
+    private boolean mDetailShown;
+    private boolean mPluggedIn;
 
     public BatteryTile(Host host) {
         super(host);
         mBatteryController = host.getBatteryController();
-        mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(),
-                host.getContext().getColor(R.color.batterymeter_frame_color));
-        mDrawable.setBatteryController(mBatteryController);
     }
 
     @Override
@@ -75,10 +77,8 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mDrawable.startListening();
             mBatteryController.addStateChangedCallback(this);
         } else {
-            mDrawable.stopListening();
             mBatteryController.removeStateChangedCallback(this);
         }
     }
@@ -102,6 +102,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.battery);
+    }
+
+    @Override
     protected void handleUpdateState(State state, Object arg) {
         int level = (arg != null) ? (Integer) arg : mLevel;
         String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
@@ -109,7 +114,18 @@
         state.icon = new Icon() {
             @Override
             public Drawable getDrawable(Context context) {
-                return mDrawable;
+                BatteryMeterDrawable drawable =
+                        new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
+                        context.getColor(R.color.batterymeter_frame_color));
+                drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
+                drawable.onPowerSaveChanged(mPowerSave);
+                return drawable;
+            }
+
+            @Override
+            public int getPadding() {
+                return mHost.getContext().getResources().getDimensionPixelSize(
+                        R.dimen.qs_battery_padding);
             }
         };
         state.label = percentage;
@@ -118,22 +134,25 @@
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         mLevel = level;
+        mPluggedIn = pluggedIn;
         mCharging = charging;
         refreshState((Integer) level);
-        if (mBatteryDetail.mCurrentView != null) {
-            mBatteryDetail.bindView();
+        if (mDetailShown) {
+            mBatteryDetail.postBindView();
         }
     }
 
     @Override
     public void onPowerSaveChanged(boolean isPowerSave) {
         mPowerSave = isPowerSave;
-        if (mBatteryDetail.mCurrentView != null) {
-            mBatteryDetail.bindView();
+        refreshState(null);
+        if (mDetailShown) {
+            mBatteryDetail.postBindView();
         }
     }
 
-    private final class BatteryDetail implements DetailAdapter, View.OnClickListener {
+    private final class BatteryDetail implements DetailAdapter, OnClickListener,
+            OnAttachStateChangeListener {
         private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
                 new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
         private View mCurrentView;
@@ -155,26 +174,40 @@
                         false);
             }
             mCurrentView = convertView;
+            mCurrentView.addOnAttachStateChangeListener(this);
             bindView();
             return convertView;
         }
 
+        private void postBindView() {
+            if (mCurrentView == null) return;
+            mCurrentView.post(new Runnable() {
+                @Override
+                public void run() {
+                    bindView();
+                }
+            });
+        }
+
         private void bindView() {
+            if (mCurrentView == null) {
+                return;
+            }
             mDrawable.onBatteryLevelChanged(100, false, false);
             mDrawable.onPowerSaveChanged(true);
             mDrawable.disableShowPercent();
             ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
             Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
             checkbox.setChecked(mPowerSave);
-            if (mCharging) {
-                BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() {
-                    @Override
-                    public void onBatteryInfoLoaded(BatteryInfo info) {
-                        if (mCurrentView != null) {
-                            bindBatteryInfo(info);
-                        }
+            BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() {
+                @Override
+                public void onBatteryInfoLoaded(BatteryInfo info) {
+                    if (mCurrentView != null) {
+                        bindBatteryInfo(info);
                     }
-                });
+                }
+            });
+            if (mCharging) {
                 ((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
                         R.string.battery_detail_charging_summary);
                 mCurrentView.findViewById(android.R.id.icon).setVisibility(View.INVISIBLE);
@@ -228,5 +261,29 @@
         public int getMetricsCategory() {
             return MetricsEvent.QS_BATTERY_DETAIL;
         }
+
+        @Override
+        public void onViewAttachedToWindow(View v) {
+            if (!mDetailShown) {
+                mDetailShown = true;
+                v.getContext().registerReceiver(mReceiver,
+                        new IntentFilter(Intent.ACTION_TIME_TICK));
+            }
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            if (mDetailShown) {
+                mDetailShown = false;
+                v.getContext().unregisterReceiver(mReceiver);
+            }
+        }
+
+        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                postBindView();
+            }
+        };
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 80f667c..1fef8f1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -96,6 +96,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_bluetooth_label);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         final boolean enabled = mController.isBluetoothEnabled();
         final boolean connected = mController.isBluetoothConnected();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index e0ad002..bea1e15 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -108,6 +108,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_cast_title);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mContext.getString(R.string.quick_settings_cast_title);
         state.value = false;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 5f87741..55b00b5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -101,6 +101,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_cellular_detail_title);
+    }
+
+    @Override
     protected void handleUpdateState(SignalState state, Object arg) {
         CallbackInfo cb = (CallbackInfo) arg;
         if (cb == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 42ce69c..416132e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -30,9 +30,11 @@
 public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
 
     private final AnimationIcon mEnable
-            = new AnimationIcon(R.drawable.ic_invert_colors_enable_animation);
+            = new AnimationIcon(R.drawable.ic_invert_colors_enable_animation,
+            R.drawable.ic_invert_colors_disable);
     private final AnimationIcon mDisable
-            = new AnimationIcon(R.drawable.ic_invert_colors_disable_animation);
+            = new AnimationIcon(R.drawable.ic_invert_colors_disable_animation,
+            R.drawable.ic_invert_colors_enable);
     private final SecureSetting mSetting;
 
     private boolean mListening;
@@ -83,6 +85,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_inversion_label);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
         final boolean enabled = value != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index a1789a5..35aff21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -57,12 +57,17 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.data_saver);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.value = arg instanceof Boolean ? (Boolean) arg
                 : mDataSaverController.isDataSaverEnabled();
         state.label = mContext.getString(R.string.data_saver);
-        state.contentDescription = mContext.getString(state.value ?
-                R.string.accessibility_data_saver_on : R.string.accessibility_data_saver_off);
+        state.contentDescription = mContext.getString(state.value
+                ? R.string.accessibility_data_saver_on : R.string.accessibility_data_saver_off);
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_data_saver
                 : R.drawable.ic_data_saver_off);
     }
@@ -73,6 +78,15 @@
     }
 
     @Override
+    protected String composeChangeAnnouncement() {
+        if (mState.value) {
+            return mContext.getString(R.string.accessibility_quick_settings_data_saver_changed_on);
+        } else {
+            return mContext.getString(R.string.accessibility_quick_settings_data_saver_changed_off);
+        }
+    }
+
+    @Override
     public void onDataSaverChanged(boolean isDataSaving) {
         refreshState(isDataSaving);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 8982b3e..11efd56 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -56,9 +56,11 @@
             ResourceIcon.get(R.drawable.ic_qs_dnd_on_total_silence);
 
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_dnd_disable_animation);
+            new AnimationIcon(R.drawable.ic_dnd_disable_animation,
+                    R.drawable.ic_qs_dnd_off);
     private final AnimationIcon mDisableTotalSilence =
-            new AnimationIcon(R.drawable.ic_dnd_total_silence_disable_animation);
+            new AnimationIcon(R.drawable.ic_dnd_total_silence_disable_animation,
+                    R.drawable.ic_qs_dnd_off);
 
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
@@ -126,6 +128,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_dnd_label);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
         final boolean newValue = zen != Global.ZEN_MODE_OFF;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index c10843a..69e71bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -17,9 +17,11 @@
 package com.android.systemui.qs.tiles;
 
 import android.app.ActivityManager;
-
 import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.provider.MediaStore;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -31,9 +33,11 @@
         FlashlightController.FlashlightListener {
 
     private final AnimationIcon mEnable
-            = new AnimationIcon(R.drawable.ic_signal_flashlight_enable_animation);
+            = new AnimationIcon(R.drawable.ic_signal_flashlight_enable_animation,
+            R.drawable.ic_signal_flashlight_disable);
     private final AnimationIcon mDisable
-            = new AnimationIcon(R.drawable.ic_signal_flashlight_disable_animation);
+            = new AnimationIcon(R.drawable.ic_signal_flashlight_disable_animation,
+            R.drawable.ic_signal_flashlight_enable);
     private final FlashlightController mFlashlightController;
 
     public FlashlightTile(Host host) {
@@ -67,6 +71,11 @@
     }
 
     @Override
+    public boolean isAvailable() {
+        return mFlashlightController.hasFlashlight();
+    }
+
+    @Override
     protected void handleClick() {
         if (ActivityManager.isUserAMonkey()) {
             return;
@@ -78,10 +87,30 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_flashlight_label);
+    }
+
+    @Override
+    protected void handleLongClick() {
+        handleClick();
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
-        // TODO: Flashlight available handling...
-//        state.visible = mFlashlightController.isAvailable();
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
+        if (!mFlashlightController.isAvailable()) {
+            Drawable icon = mHost.getContext().getDrawable(R.drawable.ic_signal_flashlight_disable);
+            final int disabledColor = mHost.getContext().getColor(R.color.qs_tile_tint_unavailable);
+            icon.setTint(disabledColor);
+            state.icon = new DrawableIcon(icon);
+            state.label = new SpannableStringBuilder().append(state.label,
+                    new ForegroundColorSpan(disabledColor),
+                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
+            state.contentDescription = mContext.getString(
+                    R.string.accessibility_quick_settings_flashlight_unavailable);
+            return;
+        }
         if (arg instanceof Boolean) {
             boolean value = (Boolean) arg;
             if (value == state.value) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index ad1c7a0..bf5b22c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -29,9 +29,11 @@
 /** Quick settings tile: Hotspot **/
 public class HotspotTile extends QSTile<QSTile.BooleanState> {
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_hotspot_enable_animation);
+            new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
+                    R.drawable.ic_hotspot_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_hotspot_disable_animation);
+            new AnimationIcon(R.drawable.ic_hotspot_disable_animation,
+                    R.drawable.ic_hotspot_enable);
     private final HotspotController mController;
     private final Callback mCallback = new Callback();
 
@@ -72,6 +74,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_hotspot_label);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index bb5ff8e..2a2cc46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -119,6 +119,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return getState().label;
+    }
+
+    @Override
     protected void handleUpdateState(State state, Object arg) {
         Intent intent = (Intent) arg;
         if (intent == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 6533252..6286f5e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -32,9 +32,11 @@
 public class LocationTile extends QSTile<QSTile.BooleanState> {
 
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_location_enable_animation);
+            new AnimationIcon(R.drawable.ic_signal_location_enable_animation,
+                    R.drawable.ic_signal_location_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_location_disable_animation);
+            new AnimationIcon(R.drawable.ic_signal_location_disable_animation,
+                    R.drawable.ic_signal_location_enable);
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
@@ -87,6 +89,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_location_label);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         final boolean locationEnabled =  mController.isLocationEnabled();
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index b267ccd..38b3706 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -31,14 +31,18 @@
 /** Quick settings tile: Rotation **/
 public class RotationLockTile extends QSTile<QSTile.BooleanState> {
     private final AnimationIcon mPortraitToAuto
-            = new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation,
+            R.drawable.ic_portrait_from_auto_rotate);
     private final AnimationIcon mAutoToPortrait
-            = new AnimationIcon(R.drawable.ic_portrait_from_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_portrait_from_auto_rotate_animation,
+            R.drawable.ic_portrait_to_auto_rotate);
 
     private final AnimationIcon mLandscapeToAuto
-            = new AnimationIcon(R.drawable.ic_landscape_to_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_landscape_to_auto_rotate_animation,
+            R.drawable.ic_landscape_from_auto_rotate);
     private final AnimationIcon mAutoToLandscape
-            = new AnimationIcon(R.drawable.ic_landscape_from_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_landscape_from_auto_rotate_animation,
+            R.drawable.ic_landscape_to_auto_rotate);
 
     private final RotationLockController mController;
 
@@ -76,6 +80,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return getState().label;
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         if (mController == null) return;
         final boolean rotationLocked = arg != null ? (Boolean) arg
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 33befd0..fcf758b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -103,6 +103,11 @@
         mAvatar.setDisabled(disabled);
     }
 
+    public void setEnabled(boolean enabled) {
+        mName.setEnabled(enabled);
+        mAvatar.setDisabled(!enabled);
+    }
+
     @Override
     protected void onFinishInflate() {
         mAvatar = (UserAvatarView) findViewById(R.id.user_picture);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 2c8a478..da98762 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -82,6 +82,9 @@
             }
             v.setActivated(item.isCurrent);
             v.setDisabledByAdmin(item.isDisabledByAdmin);
+            if (!item.isSwitchToEnabled) {
+                v.setEnabled(false);
+            }
             v.setTag(item);
             return v;
         }
@@ -94,7 +97,7 @@
                 final Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
                         mContext, tag.enforcedAdmin);
                 mController.startActivity(intent);
-            } else {
+            } else if (tag.isSwitchToEnabled) {
                 MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
                 switchTo(tag);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index f1066c1..5b4279c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -73,6 +73,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return getState().label;
+    }
+
+    @Override
     protected void handleUpdateState(State state, Object arg) {
         final Pair<String, Drawable> p = arg != null ? (Pair<String, Drawable>) arg : mLastUpdate;
         if (p != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 7ee795f..c72bbf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -119,6 +119,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_wifi_label);
+    }
+
+    @Override
     protected void handleUpdateState(SignalState state, Object arg) {
         if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
         CallbackInfo cb = (CallbackInfo) arg;
@@ -149,7 +154,7 @@
             state.label = removeDoubleQuotes(cb.enabledDesc);
             signalContentDescription = cb.wifiSignalContentDescription;
         } else if (wifiNotConnected) {
-            state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_full_0);
+            state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
             state.label = r.getString(R.string.quick_settings_wifi_label);
             signalContentDescription = r.getString(R.string.accessibility_no_wifi);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 003e9c1..2c5f7d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -28,9 +28,11 @@
 public class WorkModeTile extends QSTile<QSTile.BooleanState> implements
         ManagedProfileController.Callback {
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_workmode_enable_animation);
+            new AnimationIcon(R.drawable.ic_signal_workmode_enable_animation,
+                    R.drawable.ic_signal_workmode_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_workmode_disable_animation);
+            new AnimationIcon(R.drawable.ic_signal_workmode_disable_animation,
+                    R.drawable.ic_signal_workmode_enable);
 
     private final ManagedProfileController mProfileController;
 
@@ -80,6 +82,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_work_mode_label);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         if (arg instanceof Boolean) {
             state.value = (Boolean) arg;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 070b395..003379f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -27,6 +27,7 @@
         public static final int DismissSourceKeyboard = 0;
         public static final int DismissSourceSwipeGesture = 1;
         public static final int DismissSourceHeaderButton = 2;
+        @Deprecated
         public static final int DismissSourceHistorySwipeGesture = 3;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index cb8f0e7..9a00d95 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -16,6 +16,8 @@
 
 package com.android.systemui.recents;
 
+import android.graphics.Rect;
+
 /**
  * Due to the fact that RecentsActivity is per-user, we need to establish an
  * interface (this) for the non-system user to register itself for callbacks and to
@@ -27,6 +29,6 @@
     void updateRecentsVisibility(boolean visible);
     void startScreenPinning();
     void sendRecentsDrawnEvent();
-    void sendDockingTopTaskEvent(int dragMode);
+    void sendDockingTopTaskEvent(int dragMode, in Rect initialRect);
     void sendLaunchRecentsEvent();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index f5ae351..287bb22 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -17,13 +17,16 @@
 package com.android.systemui.recents;
 
 import android.app.ActivityManager;
+import android.app.UiModeManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.res.Configuration;
+import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -35,19 +38,23 @@
 import android.util.Log;
 import android.view.Display;
 import android.view.View;
+import android.widget.Toast;
 
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.tv.RecentsTvImpl;
 
 import java.util.ArrayList;
 
@@ -173,11 +180,17 @@
     @Override
     public void start() {
         sDebugFlags = new RecentsDebugFlags(mContext);
-        sSystemServicesProxy = new SystemServicesProxy(mContext);
+        sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
         sTaskLoader = new RecentsTaskLoader(mContext);
         sConfiguration = new RecentsConfiguration(mContext);
         mHandler = new Handler();
-        mImpl = new RecentsImpl(mContext);
+        UiModeManager uiModeManager = (UiModeManager) mContext.
+                getSystemService(Context.UI_MODE_SERVICE);
+        if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
+            mImpl = new RecentsTvImpl(mContext);
+        } else {
+            mImpl = new RecentsImpl(mContext);
+        }
 
         // Check if there is a recents override package
         if ("userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE)) {
@@ -387,34 +400,48 @@
             return false;
         }
 
+        Point realSize = new Point();
+        if (initialBounds == null) {
+            mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+                    .getRealSize(realSize);
+            initialBounds = new Rect(0, 0, realSize.x, realSize.y);
+        }
+
         int currentUser = sSystemServicesProxy.getCurrentUser();
         SystemServicesProxy ssp = Recents.getSystemServices();
         ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
         boolean screenPinningActive = ssp.isScreenPinningActive();
         boolean isTopTaskHome = topTask != null && SystemServicesProxy.isHomeStack(topTask.stackId);
         if (topTask != null && !isTopTaskHome && !screenPinningActive) {
-            if (sSystemServicesProxy.isSystemUser(currentUser)) {
-                mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
-            } else {
-                if (mSystemToUserCallbacks != null) {
-                    IRecentsNonSystemUserCallbacks callbacks =
-                            mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                    if (callbacks != null) {
-                        try {
-                            callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
-                                    initialBounds);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Callback failed", e);
+            if (topTask.isDockable) {
+                if (sSystemServicesProxy.isSystemUser(currentUser)) {
+                    mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
+                } else {
+                    if (mSystemToUserCallbacks != null) {
+                        IRecentsNonSystemUserCallbacks callbacks =
+                                mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        if (callbacks != null) {
+                            try {
+                                callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
+                                        initialBounds);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Callback failed", e);
+                            }
+                        } else {
+                            Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
                         }
-                    } else {
-                        Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
                     }
                 }
+                mDraggingInRecentsCurrentUser = currentUser;
+                return true;
+            } else {
+                Toast.makeText(mContext, R.string.recents_drag_non_dockable_task_message,
+                        Toast.LENGTH_SHORT).show();
+                return false;
             }
-            mDraggingInRecentsCurrentUser = currentUser;
-            return true;
+        } else {
+            return false;
         }
-        return false;
     }
 
     @Override
@@ -513,8 +540,9 @@
      * Handle Recents activity visibility changed.
      */
     public final void onBusEvent(final RecentsVisibilityChangedEvent event) {
-        int processUser = event.systemServicesProxy.getProcessUser();
-        if (event.systemServicesProxy.isSystemUser(processUser)) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        int processUser = ssp.getProcessUser();
+        if (ssp.isSystemUser(processUser)) {
             mImpl.onVisibilityChanged(event.applicationContext, event.visible);
         } else {
             postToSystemUser(new Runnable() {
@@ -567,14 +595,15 @@
         }
     }
 
-    public final void onBusEvent(final DockingTopTaskEvent event) {
+    public final void onBusEvent(final DockedTopTaskEvent event) {
         int processUser = sSystemServicesProxy.getProcessUser();
         if (!sSystemServicesProxy.isSystemUser(processUser)) {
             postToSystemUser(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode);
+                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode,
+                                event.initialRect);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Callback failed", e);
                     }
@@ -599,6 +628,12 @@
         }
     }
 
+    public final void onBusEvent(ConfigurationChangedEvent event) {
+        // Update the configuration for the Recents component when the activity configuration
+        // changes as well
+        mImpl.onConfigurationChanged();
+    }
+
     /**
      * Attempts to register with the system user.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c2a6108..8060e07 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -18,14 +18,12 @@
 
 import android.app.Activity;
 import android.app.ActivityOptions;
-import android.app.SearchManager;
 import android.app.TaskStackBuilder;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -36,25 +34,25 @@
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -75,6 +73,7 @@
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.AnimationProps;
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -87,27 +86,21 @@
     private final static String TAG = "RecentsActivity";
     private final static boolean DEBUG = false;
 
-    private final static String KEY_SAVED_STATE_HISTORY_VISIBLE =
-            "saved_instance_state_history_visible";
-
     public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
 
     private RecentsPackageMonitor mPackageMonitor;
     private long mLastTabKeyEventTime;
+    private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
     private boolean mFinishedOnStartup;
     private boolean mIgnoreAltTabRelease;
+    private boolean mIsVisible;
 
     // Top level views
     private RecentsView mRecentsView;
     private SystemBarScrimViews mScrimViews;
 
-    // Search AppWidget
-    private AppWidgetProviderInfo mSearchWidgetInfo;
-    private RecentsAppWidgetHost mAppWidgetHost;
-    private RecentsAppWidgetHostView mSearchWidgetHostView;
-
     // Runnables to finish the Recents activity
-    private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+    private Intent mHomeIntent;
 
     // The trigger to automatically launch the current task
     private int mFocusTimerDuration;
@@ -119,7 +112,7 @@
      * last activity launch state. Generally we always launch home when we exit Recents rather than
      * just finishing the activity since we don't know what is behind Recents in the task stack.
      */
-    class FinishRecentsRunnable implements Runnable {
+    class LaunchHomeRunnable implements Runnable {
 
         Intent mLaunchIntent;
         ActivityOptions mOpts;
@@ -127,7 +120,7 @@
         /**
          * Creates a finish runnable that starts the specified intent.
          */
-        public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
+        public LaunchHomeRunnable(Intent launchIntent, ActivityOptions opts) {
             mLaunchIntent = launchIntent;
             mOpts = opts;
         }
@@ -135,17 +128,10 @@
         @Override
         public void run() {
             try {
-                RecentsActivityLaunchState launchState =
-                        Recents.getConfiguration().getLaunchState();
                 ActivityOptions opts = mOpts;
                 if (opts == null) {
                     opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
-                            launchState.launchedFromSearchHome ?
-                                    R.anim.recents_to_search_launcher_enter :
-                                    R.anim.recents_to_launcher_enter,
-                            launchState.launchedFromSearchHome ?
-                                    R.anim.recents_to_search_launcher_exit :
-                                    R.anim.recents_to_launcher_exit);
+                            R.anim.recents_to_launcher_enter, R.anim.recents_to_launcher_exit);
                 }
                 startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
             } catch (Exception e) {
@@ -164,79 +150,10 @@
             if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 // When the screen turns off, dismiss Recents to Home
                 dismissRecentsToHomeIfVisible(false);
-            } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
-                // When the search activity changes, update the search widget view
-                SystemServicesProxy ssp = Recents.getSystemServices();
-                mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(context, mAppWidgetHost);
-                refreshSearchWidgetView();
             }
         }
     };
 
-    /** Updates the set of recent tasks */
-    void updateRecentsTasks() {
-        // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
-        // reconstructing the task stack
-        RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
-        if (plan == null) {
-            plan = loader.createLoadPlan(this);
-        }
-
-        // Start loading tasks according to the load plan
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
-        if (!plan.hasTasks()) {
-            loader.preloadTasks(plan, -1, launchState.launchedFromHome);
-        }
-        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
-        loadOpts.runningTaskId = launchState.launchedToTaskId;
-        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
-        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
-        loader.loadTasks(this, plan, loadOpts);
-
-        TaskStack stack = plan.getTaskStack();
-        mRecentsView.setTaskStack(stack);
-
-        // Animate the SystemUI scrims into view
-        Task launchTarget = stack.getLaunchTarget();
-        int taskCount = stack.getTaskCount();
-        int launchTaskIndexInStack = launchTarget != null
-                ? stack.indexOfStackTask(launchTarget)
-                : 0;
-        boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
-        boolean animateNavBarScrim = !launchState.launchedWhileDocking;
-        mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
-
-        // Keep track of whether we launched from the nav bar button or via alt-tab
-        if (launchState.launchedWithAltTab) {
-            MetricsLogger.count(this, "overview_trigger_alttab", 1);
-        } else {
-            MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
-        }
-        // Keep track of whether we launched from an app or from home
-        if (launchState.launchedFromAppWithThumbnail) {
-            MetricsLogger.count(this, "overview_source_app", 1);
-            // If from an app, track the stack index of the app in the stack (for affiliated tasks)
-            MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
-        } else {
-            MetricsLogger.count(this, "overview_source_home", 1);
-        }
-        // Keep track of the total stack task count
-        MetricsLogger.histogram(this, "overview_task_count", taskCount);
-    }
-
-    /**
-     * Dismisses the history view back into the stack view.
-     */
-    boolean dismissHistory() {
-        if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
-            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
-            return true;
-        }
-        return false;
-    }
-
     /**
      * Dismisses recents if we are already visible and the intent is to toggle the recents view.
      */
@@ -294,12 +211,8 @@
     void dismissRecentsToHome(boolean animateTaskViews, ActivityOptions overrideAnimation) {
         DismissRecentsToHomeAnimationStarted dismissEvent =
                 new DismissRecentsToHomeAnimationStarted(animateTaskViews);
-        if (overrideAnimation != null) {
-            dismissEvent.addPostAnimationCallback(new FinishRecentsRunnable(
-                    mFinishLaunchHomeRunnable.mLaunchIntent, overrideAnimation));
-        } else {
-            dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
-        }
+        dismissEvent.addPostAnimationCallback(new LaunchHomeRunnable(mHomeIntent,
+                overrideAnimation));
         dismissEvent.addPostAnimationCallback(new Runnable() {
             @Override
             public void run() {
@@ -339,15 +252,13 @@
         // Register this activity with the event bus
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
 
-        // Initialize the widget host (the host id is static and does not change)
-        if (RecentsDebugFlags.Static.EnableSearchBar) {
-            mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID);
-        }
+        // Initialize the package monitor
         mPackageMonitor = new RecentsPackageMonitor();
         mPackageMonitor.register(this);
 
         // Set the Recents layout
         setContentView(R.layout.recents);
+        takeKeyEvents(true);
         mRecentsView = (RecentsView) findViewById(R.id.recents_view);
         mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
@@ -356,6 +267,7 @@
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 
+        mLastOrientation = getResources().getConfiguration().orientation;
         mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
         mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
             @Override
@@ -364,67 +276,110 @@
             }
         });
 
-        // Create the home intent runnable
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
-        homeIntent.addCategory(Intent.CATEGORY_HOME);
-        homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-        mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, null);
+        // Set the window background
+        getWindow().setBackgroundDrawable(mRecentsView.getBackgroundScrim());
 
-        // Bind the search app widget when we first start up
-        if (RecentsDebugFlags.Static.EnableSearchBar) {
-            mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
-        }
+        // Create the home intent runnable
+        mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
+        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
+        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
 
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        if (RecentsDebugFlags.Static.EnableSearchBar) {
-            filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
-        }
         registerReceiver(mSystemBroadcastReceiver, filter);
-    }
 
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        setIntent(intent);
+        getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
+
+        // Reload the stack view
+        reloadStackView();
     }
 
     @Override
     protected void onStart() {
         super.onStart();
 
-        // Update the recent tasks
-        updateRecentsTasks();
+        // Notify that recents is now visible
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
+        MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
+    }
 
-        // If this is a new instance from a configuration change, then we have to manually trigger
-        // the enter animation state, or if recents was relaunched by AM, without going through
-        // the normal mechanisms
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+
+        // Reload the stack view
+        reloadStackView();
+    }
+
+    /**
+     * Reloads the stack views upon launching Recents.
+     */
+    private void reloadStackView() {
+        // If the Recents component has preloaded a load plan, then use that to prevent
+        // reconstructing the task stack
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
+        if (loadPlan == null) {
+            loadPlan = loader.createLoadPlan(this);
+        }
+
+        // Start loading tasks according to the load plan
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
+        if (!loadPlan.hasTasks()) {
+            loader.preloadTasks(loadPlan, launchState.launchedToTaskId,
+                    launchState.launchedFromHome);
+        }
+
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.runningTaskId = launchState.launchedToTaskId;
+        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+        loader.loadTasks(this, loadPlan, loadOpts);
+        TaskStack stack = loadPlan.getTaskStack();
+        mRecentsView.onReload(mIsVisible, stack.getTaskCount() == 0);
+        mRecentsView.updateStack(stack);
+
+        // Update the nav bar scrim, but defer the animation until the enter-window event
+        boolean animateNavBarScrim = !launchState.launchedViaDockGesture;
+        mScrimViews.updateNavBarScrim(animateNavBarScrim, stack.getTaskCount() > 0, null);
+
+        // If this is a new instance relaunched by AM, without going through the normal mechanisms,
+        // then we have to manually trigger the enter animation state
         boolean wasLaunchedByAm = !launchState.launchedFromHome &&
-                !launchState.launchedFromAppWithThumbnail;
-        if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+                !launchState.launchedFromApp;
+        if (wasLaunchedByAm) {
             EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
         }
 
-        // Notify that recents is now visible
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+        // Keep track of whether we launched from the nav bar button or via alt-tab
+        if (launchState.launchedWithAltTab) {
+            MetricsLogger.count(this, "overview_trigger_alttab", 1);
+        } else {
+            MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
+        }
 
-        MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
+        // Keep track of whether we launched from an app or from home
+        if (launchState.launchedFromApp) {
+            Task launchTarget = stack.getLaunchTarget();
+            int launchTaskIndexInStack = launchTarget != null
+                    ? stack.indexOfStackTask(launchTarget)
+                    : 0;
+            MetricsLogger.count(this, "overview_source_app", 1);
+            // If from an app, track the stack index of the app in the stack (for affiliated tasks)
+            MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
+        } else {
+            MetricsLogger.count(this, "overview_source_home", 1);
+        }
 
-        mRecentsView.getViewTreeObserver().addOnPreDrawListener(
-                new ViewTreeObserver.OnPreDrawListener() {
+        // Keep track of the total stack task count
+        int taskCount = mRecentsView.getStack().getTaskCount();
+        MetricsLogger.histogram(this, "overview_task_count", taskCount);
 
-            @Override
-            public boolean onPreDraw() {
-                mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
-                EventBus.getDefault().post(new RecentsDrawnEvent());
-                return true;
-            }
-        });
+        // After we have resumed, set the visible state until the next onStop() call
+        mIsVisible = true;
     }
 
     @Override
@@ -434,26 +389,81 @@
     }
 
     @Override
+    protected void onResume() {
+        super.onResume();
+
+        // Notify of the next draw
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+
+                    @Override
+                    public boolean onPreDraw() {
+                        mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+                        EventBus.getDefault().post(new RecentsDrawnEvent());
+                        return true;
+                    }
+                });
+    }
+
+    @Override
     protected void onPause() {
         super.onPause();
 
-        // Stop the fast-toggle dozer
+        mIgnoreAltTabRelease = false;
         mIterateTrigger.stopDozing();
     }
 
     @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+
+        // Notify of the config change
+        int newOrientation = getResources().getConfiguration().orientation;
+        int numStackTasks = mRecentsView.getStack().getStackTaskCount();
+        EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
+                (mLastOrientation != newOrientation), numStackTasks > 0));
+        mLastOrientation = newOrientation;
+    }
+
+    @Override
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
+        super.onMultiWindowModeChanged(isInMultiWindowMode);
+
+        // Reload the task stack completely
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+        loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+        loader.loadTasks(this, loadPlan, loadOpts);
+
+        TaskStack stack = loadPlan.getTaskStack();
+        int numStackTasks = stack.getStackTaskCount();
+
+        EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
+                false /* fromOrientationChange */, numStackTasks > 0));
+
+        if (mRecentsView != null) {
+            mRecentsView.updateStack(stack);
+        }
+
+        EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode,
+                numStackTasks > 0));
+    }
+
+    @Override
     protected void onStop() {
         super.onStop();
 
-        // Reset some states
-        mIgnoreAltTabRelease = false;
-        if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
-            EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
-        }
-
         // Notify that recents is now hidden
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+        mIsVisible = false;
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
+        MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
 
         // Workaround for b/22542869, if the RecentsActivity is started again, but without going
         // through SystemUI, we need to reset the config launch flags to ensure that we do not
@@ -461,8 +471,6 @@
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         launchState.reset();
-
-        MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
     }
 
     @Override
@@ -480,11 +488,6 @@
         // Unregister any broadcast receivers for the task loader
         mPackageMonitor.unregister();
 
-        // Stop listening for widget package changes if there was one bound
-        if (RecentsDebugFlags.Static.EnableSearchBar) {
-            mAppWidgetHost.stopListening();
-        }
-
         EventBus.getDefault().unregister(this);
     }
 
@@ -501,23 +504,6 @@
     }
 
     @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        if (RecentsDebugFlags.Static.EnableHistory) {
-            outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
-        }
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Bundle savedInstanceState) {
-        super.onRestoreInstanceState(savedInstanceState);
-        if (RecentsDebugFlags.Static.EnableHistory &&
-                savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
-            EventBus.getDefault().send(new ShowHistoryEvent());
-        }
-    }
-
-    @Override
     public void onTrimMemory(int level) {
         RecentsTaskLoader loader = Recents.getTaskLoader();
         if (loader != null) {
@@ -526,22 +512,6 @@
     }
 
     @Override
-    public void onMultiWindowChanged(boolean inMultiWindow) {
-        super.onMultiWindowChanged(inMultiWindow);
-        if (!inMultiWindow) {
-            RecentsTaskLoader loader = Recents.getTaskLoader();
-            RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
-            launchOpts.loadIcons = false;
-            launchOpts.loadThumbnails = false;
-            launchOpts.onlyLoadForCache = true;
-            RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
-            loader.preloadTasks(loadPlan, -1, false);
-            loader.loadTasks(this, loadPlan, launchOpts);
-            EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack()));
-        }
-    }
-
-    @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_TAB: {
@@ -606,39 +576,35 @@
     /**** EventBus events ****/
 
     public final void onBusEvent(ToggleRecentsEvent event) {
-        if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
-            RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-            if (launchState.launchedFromHome) {
-                dismissRecentsToHome(true /* animateTaskViews */);
-            } else {
-                dismissRecentsToLaunchTargetTaskOrHome();
-            }
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (launchState.launchedFromHome) {
+            dismissRecentsToHome(true /* animateTaskViews */);
+        } else {
+            dismissRecentsToLaunchTargetTaskOrHome();
         }
     }
 
     public final void onBusEvent(IterateRecentsEvent event) {
-        if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
-            final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
 
-            // Start dozing after the recents button is clicked
-            int timerIndicatorDuration = 0;
-            if (debugFlags.isFastToggleRecentsEnabled()) {
-                timerIndicatorDuration = getResources().getInteger(
-                        R.integer.recents_subsequent_auto_advance_duration);
+        // Start dozing after the recents button is clicked
+        int timerIndicatorDuration = 0;
+        if (debugFlags.isFastToggleRecentsEnabled()) {
+            timerIndicatorDuration = getResources().getInteger(
+                    R.integer.recents_subsequent_auto_advance_duration);
 
-                mIterateTrigger.setDozeDuration(timerIndicatorDuration);
-                if (!mIterateTrigger.isDozing()) {
-                    mIterateTrigger.startDozing();
-                } else {
-                    mIterateTrigger.poke();
-                }
+            mIterateTrigger.setDozeDuration(timerIndicatorDuration);
+            if (!mIterateTrigger.isDozing()) {
+                mIterateTrigger.startDozing();
+            } else {
+                mIterateTrigger.poke();
             }
-
-            // Focus the next task
-            EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
-
-            MetricsLogger.action(this, MetricsEvent.OVERVIEW_PAGE);
         }
+
+        // Focus the next task
+        EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
+
+        MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
     }
 
     public final void onBusEvent(UserInteractionEvent event) {
@@ -653,17 +619,7 @@
                 dismissRecentsToFocusedTaskOrHome();
             }
         } else if (event.triggeredFromHomeKey) {
-            // Otherwise, dismiss Recents to Home
-            if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
-                // If the history view is visible, then just cross-fade home
-                ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
-                                R.anim.recents_to_launcher_enter,
-                                R.anim.recents_to_launcher_exit);
-                dismissRecentsToHome(false /* animate */, opts);
-
-            } else {
-                dismissRecentsToHome(true /* animateTaskViews */);
-            }
+            dismissRecentsToHome(true /* animateTaskViews */);
 
             // Cancel any pending dozes
             EventBus.getDefault().send(mUserInteractionEvent);
@@ -672,23 +628,6 @@
         }
     }
 
-    public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
-        // Try and start the enter animation (or restart it on configuration changed)
-        if (RecentsDebugFlags.Static.EnableSearchBar) {
-            if (mSearchWidgetInfo != null) {
-                event.addPostAnimationCallback(new Runnable() {
-                    @Override
-                    public void run() {
-                        // Start listening for widget package changes if there is one bound
-                        if (mAppWidgetHost != null) {
-                            mAppWidgetHost.startListening();
-                        }
-                    }
-                });
-            }
-        }
-    }
-
     public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
         EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
         mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
@@ -703,6 +642,11 @@
         mRecentsView.invalidate();
     }
 
+    public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+        mRecentsView.invalidate();
+    }
+
     public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
         int launchToTaskId = launchState.launchedToTaskId;
@@ -714,10 +658,6 @@
         }
     }
 
-    public final void onBusEvent(AppWidgetProviderChangedEvent event) {
-        refreshSearchWidgetView();
-    }
-
     public final void onBusEvent(ShowApplicationInfoEvent event) {
         // Create a new task stack with the application info details activity
         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
@@ -744,7 +684,7 @@
     public final void onBusEvent(AllTaskViewsDismissedEvent event) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.hasDockedTask()) {
-            mRecentsView.showEmptyView();
+            mRecentsView.showEmptyView(event.msgResId);
         } else {
             // Just go straight home (no animation necessary because there are no more task views)
             dismissRecentsToHome(false /* animateTaskViews */);
@@ -780,24 +720,6 @@
         mIgnoreAltTabRelease = true;
     }
 
-    private void refreshSearchWidgetView() {
-        if (mSearchWidgetInfo != null) {
-            SystemServicesProxy ssp = Recents.getSystemServices();
-            int searchWidgetId = ssp.getSearchAppWidgetId(this);
-            mSearchWidgetHostView = (RecentsAppWidgetHostView) mAppWidgetHost.createView(
-                    this, searchWidgetId, mSearchWidgetInfo);
-            Bundle opts = new Bundle();
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                    AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
-            mSearchWidgetHostView.updateAppWidgetOptions(opts);
-            // Set the padding to 0 for this search widget
-            mSearchWidgetHostView.setPadding(0, 0, 0, 0);
-            mRecentsView.setSearchBar(mSearchWidgetHostView);
-        } else {
-            mRecentsView.setSearchBar(null);
-        }
-    }
-
     @Override
     public boolean onPreDraw() {
         mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index aa1437b..7161053 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -28,37 +28,21 @@
 public class RecentsActivityLaunchState {
 
     public boolean launchedWithAltTab;
-    public boolean launchedFromAppWithThumbnail;
+    public boolean launchedFromApp;
     public boolean launchedFromHome;
-    public boolean launchedFromSearchHome;
-    public boolean launchedReuseTaskStackViews;
-    public boolean launchedHasConfigurationChanged;
     public boolean launchedViaDragGesture;
-    public boolean launchedWhileDocking;
+    public boolean launchedViaDockGesture;
     public int launchedToTaskId;
     public int launchedNumVisibleTasks;
     public int launchedNumVisibleThumbnails;
 
     public void reset() {
         launchedFromHome = false;
-        launchedFromSearchHome = false;
-        launchedFromAppWithThumbnail = false;
+        launchedFromApp = false;
         launchedToTaskId = -1;
         launchedWithAltTab = false;
-        launchedHasConfigurationChanged = false;
         launchedViaDragGesture = false;
-        launchedWhileDocking = false;
-    }
-
-    /** Called when the configuration has changed, and we want to reset any configuration specific
-     * members. */
-    public void updateOnConfigurationChange() {
-        // Reset this flag on configuration change to ensure that we recreate new task views
-        launchedReuseTaskStackViews = false;
-        // Set this flag to indicate that the configuration has changed since Recents last launched
-        launchedHasConfigurationChanged = true;
-        launchedViaDragGesture = false;
-        launchedWhileDocking = false;
+        launchedViaDockGesture = false;
     }
 
     /**
@@ -67,7 +51,7 @@
     public int getInitialFocusTaskIndex(int numTasks) {
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-        if (launchedFromAppWithThumbnail) {
+        if (launchedFromApp) {
             if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled()) {
                 // If fast toggling, focus the front most task so that the next tap will focus the
                 // N-1 task
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
deleted file mode 100644
index 318c69f..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents;
-
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
-
-/** Our special app widget host for the Search widget */
-public class RecentsAppWidgetHost extends AppWidgetHost {
-
-    public static final int HOST_ID = 1024;
-
-    boolean mIsListening;
-
-    public RecentsAppWidgetHost(Context context, int hostId) {
-        super(context, hostId);
-    }
-
-    public void startListening() {
-        if (!mIsListening) {
-            mIsListening = true;
-            super.startListening();
-        }
-    }
-
-    @Override
-    public void stopListening() {
-        if (mIsListening) {
-            mIsListening = false;
-            super.stopListening();
-        }
-    }
-
-    @Override
-    protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
-                                             AppWidgetProviderInfo appWidget) {
-        return new RecentsAppWidgetHostView(context);
-    }
-
-    /**
-     * Note: this is only called for packages that have updated, not removed.
-     */
-    @Override
-    protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
-        super.onProviderChanged(appWidgetId, appWidgetInfo);
-        if (mIsListening) {
-            EventBus.getDefault().send(new AppWidgetProviderChangedEvent());
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
deleted file mode 100644
index 672d602..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents;
-
-import android.appwidget.AppWidgetHostView;
-import android.content.Context;
-import android.view.View;
-import android.widget.RemoteViews;
-
-public class RecentsAppWidgetHostView extends AppWidgetHostView {
-
-    private Context mContext;
-    private int mPreviousOrientation;
-
-    public RecentsAppWidgetHostView(Context context) {
-        super(context);
-        mContext = context;
-    }
-
-    @Override
-    public void updateAppWidget(RemoteViews remoteViews) {
-        // Store the orientation in which the widget was inflated
-        updateLastInflationOrientation();
-        super.updateAppWidget(remoteViews);
-    }
-
-    @Override
-    protected View getErrorView() {
-        // Just return an empty view as the error view when failing to inflate the Recents search
-        // bar widget (this is mainly to catch the case where we try and inflate the widget view
-        // while the search provider is updating)
-        return new View(mContext);
-    }
-
-    /**
-     * Updates the last orientation that this widget was inflated.
-     */
-    private void updateLastInflationOrientation() {
-        mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
-    }
-
-    /**
-     * @return whether the search widget was updated while Recents was in a different orientation
-     *         in the background.
-     */
-    public boolean isReinflateRequired() {
-        // Re-inflate is required if the orientation has changed since last inflated.
-        int orientation = mContext.getResources().getConfiguration().orientation;
-        if (mPreviousOrientation != orientation) {
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 9e43bb4..73c6e6e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -32,13 +32,6 @@
     private static final int LARGE_SCREEN_MIN_DP = 600;
     private static final int XLARGE_SCREEN_MIN_DP = 720;
 
-    // Variables that are used for global calculations
-    private static final float STACK_SIDE_PADDING_PHONES_PCT = 0.03333f;
-    private static final float STACK_SIZE_PADDING_TABLETS_PCT = 0.075f;
-    private static final float STACK_SIZE_PADDING_LARGE_TABLETS_PCT = 0.15f;
-    private static final int SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS = 64;
-    private static final int SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS = 72;
-
     /** Levels of svelte in increasing severity/austerity. */
     // No svelting.
     public static final int SVELTE_NONE = 0;
@@ -54,13 +47,6 @@
     // Launch states
     public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState();
 
-    // TODO: Values determined by the current context, needs to be refactored into something that is
-    //       agnostic of the activity context, but still calculable from the Recents component for
-    //       the transition into recents
-    boolean hasTransposedSearchBar;
-    boolean hasTransposedNavBar;
-    public float taskStackWidthPaddingPct;
-
     // Since the positions in Recents has to be calculated globally (before the RecentsActivity
     // starts), we need to calculate some resource values ourselves, instead of relying on framework
     // resources.
@@ -69,10 +55,8 @@
     public final int smallestWidth;
 
     /** Misc **/
-    public boolean useHardwareLayers;
     public boolean fakeShadows;
     public int svelteLevel;
-    public int searchBarSpaceHeightPx;
 
     public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
@@ -80,32 +64,13 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         Context appContext = context.getApplicationContext();
         Resources res = appContext.getResources();
-        useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
         fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
         svelteLevel = res.getInteger(R.integer.recents_svelte_level);
 
-        float density = context.getResources().getDisplayMetrics().density;
+        float screenDensity = context.getResources().getDisplayMetrics().density;
         smallestWidth = ssp.getDeviceSmallestWidth();
-        isLargeScreen = smallestWidth >= (int) (density * LARGE_SCREEN_MIN_DP);
-        isXLargeScreen = smallestWidth >= (int) (density * XLARGE_SCREEN_MIN_DP);
-        searchBarSpaceHeightPx = isLargeScreen ?
-                (int) (density * SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS) :
-                (int) (density * SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS);
-        if (isLargeScreen) {
-            taskStackWidthPaddingPct = STACK_SIZE_PADDING_TABLETS_PCT;
-        } else if (isXLargeScreen) {
-            taskStackWidthPaddingPct = STACK_SIZE_PADDING_LARGE_TABLETS_PCT;
-        } else {
-            taskStackWidthPaddingPct = STACK_SIDE_PADDING_PHONES_PCT;
-        }
-    }
-
-    /**
-     * Updates the configuration based on the current state of the system
-     */
-    void update(Rect systemInsets) {
-        hasTransposedNavBar = systemInsets.right > 0;
-        hasTransposedSearchBar = systemInsets.right > 0;
+        isLargeScreen = smallestWidth >= (int) (screenDensity * LARGE_SCREEN_MIN_DP);
+        isXLargeScreen = smallestWidth >= (int) (screenDensity * XLARGE_SCREEN_MIN_DP);
     }
 
     /**
@@ -115,48 +80,4 @@
     public RecentsActivityLaunchState getLaunchState() {
         return mLaunchState;
     }
-
-    /**
-     * Called when the configuration has changed, and we want to reset any configuration specific
-     * members.
-     */
-    public void updateOnConfigurationChange() {
-        mLaunchState.updateOnConfigurationChange();
-    }
-
-    /**
-     * Returns the task stack bounds in the current orientation. These bounds do not account for
-     * the system insets.
-     */
-    public void getTaskStackBounds(Rect windowBounds, int topInset,
-            int rightInset, Rect searchBarBounds, Rect taskStackBounds) {
-        if (hasTransposedNavBar) {
-            // In landscape phones, the search bar appears on the left, but we overlay it on top
-            taskStackBounds.set(windowBounds.left, windowBounds.top + topInset,
-                    windowBounds.right - rightInset, windowBounds.bottom);
-        } else {
-            // In portrait, the search bar appears on the top (which already has the inset)
-            int top = searchBarBounds.isEmpty() ? topInset : 0;
-            taskStackBounds.set(windowBounds.left, windowBounds.top + searchBarBounds.bottom + top,
-                    windowBounds.right - rightInset, windowBounds.bottom);
-        }
-    }
-
-    /**
-     * Returns the search bar bounds in the current orientation.  These bounds do not account for
-     * the system insets.
-     */
-    public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) {
-        // Return empty rects if search is not enabled
-        int searchBarSize = searchBarSpaceHeightPx;
-        if (hasTransposedSearchBar) {
-            // In landscape phones, the search bar appears on the left
-            searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
-                    windowBounds.left + searchBarSize, windowBounds.bottom);
-        } else {
-            // In portrait, the search bar appears on the top
-            searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
-                    windowBounds.right, windowBounds.top + topInset + searchBarSize);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index cd64323..1715356 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -31,16 +31,16 @@
     public static class Static {
         // Enables debug drawing for the transition thumbnail
         public static final boolean EnableTransitionThumbnailDebugMode = false;
-        // This enables the search bar integration
-        public static final boolean EnableSearchBar = false;
         // This disables the bitmap and icon caches
         public static final boolean DisableBackgroundCache = false;
         // Enables the task affiliations
-        public static final boolean EnableAffiliatedTaskGroups = true;
-        // Enables the history
-        public static final boolean EnableHistory = false;
-        // Overrides the Tuner flags and enables the fast toggle and timeout
-        public static final boolean EnableFastToggleTimeoutOverride = true;
+        public static final boolean EnableAffiliatedTaskGroups = false;
+        // TODO: To be repurposed
+        public static final boolean EnableStackActionButton = true;
+        // Overrides the Tuner flags and enables the timeout
+        private static final boolean EnableFastToggleTimeout = false;
+        // Overrides the Tuner flags and enables the paging via the Recents button
+        private static final boolean EnablePaging = false;
 
         // Enables us to create mock recents tasks
         public static final boolean EnableMockTasks = false;
@@ -54,10 +54,6 @@
         public static final int MockTaskGroupsTaskCount = 12;
     }
 
-    private static final String KEY_DISABLE_FAST_TOGGLE = "overview_disable_fast_toggle_via_button";
-
-    private boolean mDisableFastToggleRecents;
-
     /**
      * We read the prefs once when we start the activity, then update them as the tuner changes
      * the flags.
@@ -65,33 +61,28 @@
     public RecentsDebugFlags(Context context) {
         // Register all our flags, this will also call onTuningChanged() for each key, which will
         // initialize the current state of each flag
-        TunerService.get(context).addTunable(this, KEY_DISABLE_FAST_TOGGLE);
     }
 
     /**
      * @return whether we are enabling fast toggling.
      */
     public boolean isFastToggleRecentsEnabled() {
-        // These checks EnableFastToggleTimeoutOverride
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (mDisableFastToggleRecents || ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask()
-                || ssp.isTouchExplorationEnabled()) {
+        if (ssp.hasFreeformWorkspaceSupport() || ssp.isTouchExplorationEnabled()) {
             return false;
         }
-        if (Static.EnableFastToggleTimeoutOverride) {
-            return true;
-        }
-        return true;
+        return Static.EnableFastToggleTimeout;
+    }
+
+    /**
+     * @return whether we are enabling paging.
+     */
+    public boolean isPagingEnabled() {
+        return Static.EnablePaging;
     }
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        switch (key) {
-            case KEY_DISABLE_FAST_TOGGLE:
-                mDisableFastToggleRecents = (newValue != null) &&
-                        (Integer.parseInt(newValue) != 0);
-                break;
-        }
         EventBus.getDefault().send(new DebugFlagsChangedEvent());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 8de964b..aba05aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -16,20 +16,19 @@
 
 package com.android.systemui.recents;
 
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
-import android.app.ITaskStackListener;
-import android.app.UiModeManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -41,12 +40,12 @@
 import android.view.ViewConfiguration;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.ForcedResizableEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
@@ -59,6 +58,7 @@
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ForegroundThread;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
@@ -66,6 +66,7 @@
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskStackView;
+import com.android.systemui.recents.views.TaskStackViewScroller;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -74,8 +75,6 @@
 
 import java.util.ArrayList;
 
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-
 /**
  * An implementation of the Recents component for the current user.  For secondary users, this can
  * be called remotely from the system user.
@@ -94,42 +93,15 @@
 
     public final static String RECENTS_PACKAGE = "com.android.systemui";
     public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
-    public final static String RECENTS_TV_ACTIVITY = "com.android.systemui.recents.tv.RecentsTvActivity";
 
-    //Used to store tv or non-tv activty for use in creating intents.
-    private final String mRecentsIntentActivityName;
     /**
-     * An implementation of ITaskStackListener, that allows us to listen for changes to the system
+     * An implementation of TaskStackListener, that allows us to listen for changes to the system
      * task stacks and update recents accordingly.
      */
-    class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
-        Handler mHandler;
-
-        public TaskStackListenerImpl(Handler handler) {
-            mHandler = handler;
-        }
-
+    class TaskStackListenerImpl extends TaskStackListener {
         @Override
         public void onTaskStackChanged() {
-            // Debounce any task stack changes
-            mHandler.removeCallbacks(this);
-            mHandler.post(this);
-        }
-
-        @Override
-        public void onActivityPinned() {
-        }
-
-        @Override
-        public void onPinnedActivityRestartAttempt() {
-        }
-
-        @Override
-        public void onPinnedStackAnimationEnded() {
-        }
-
-        /** Preloads the next task */
-        public void run() {
+            // Preloads the next task
             RecentsConfiguration config = Recents.getConfiguration();
             if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
                 RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -153,24 +125,25 @@
                 loader.loadTasks(mContext, plan, launchOpts);
             }
         }
+
+        @Override
+        public void onActivityForcedResizable(String packageName, int taskId) {
+            EventBus.getDefault().sendOntoMainThread(
+                    new ForcedResizableEvent(packageName, taskId));
+
+        }
     }
 
-    private static RecentsTaskLoadPlan sInstanceLoadPlan;
+    protected static RecentsTaskLoadPlan sInstanceLoadPlan;
 
-    Context mContext;
-    Handler mHandler;
+    protected Context mContext;
+    protected Handler mHandler;
     TaskStackListenerImpl mTaskStackListener;
-    RecentsAppWidgetHost mAppWidgetHost;
-    boolean mBootCompleted;
-    boolean mCanReuseTaskStackViews = true;
     boolean mDraggingInRecents;
-    boolean mReloadTasks;
     boolean mLaunchedWhileDocking;
 
     // Task launching
-    Rect mSearchBarBounds = new Rect();
     Rect mTaskStackBounds = new Rect();
-    Rect mLastTaskViewBounds = new Rect();
     TaskViewTransform mTmpTransform = new TaskViewTransform();
     int mStatusBarHeight;
     int mNavBarHeight;
@@ -180,11 +153,11 @@
     // Header (for transition)
     TaskViewHeader mHeaderBar;
     final Object mHeaderBarLock = new Object();
-    TaskStackView mDummyStackView;
+    protected TaskStackView mDummyStackView;
 
     // Variables to keep track of if we need to start recents after binding
-    boolean mTriggeredFromAltTab;
-    long mLastToggleTime;
+    protected boolean mTriggeredFromAltTab;
+    protected long mLastToggleTime;
     DozeTrigger mFastAltTabTrigger = new DozeTrigger(FAST_ALT_TAB_DELAY_MS, new Runnable() {
         @Override
         public void run() {
@@ -195,25 +168,22 @@
         }
     });
 
-    Bitmap mThumbnailTransitionBitmapCache;
-    Task mThumbnailTransitionBitmapCacheKey;
+    protected Bitmap mThumbTransitionBitmapCache;
 
     public RecentsImpl(Context context) {
         mContext = context;
         mHandler = new Handler();
-        mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID);
 
         // Initialize the static foreground thread
         ForegroundThread.get();
 
         // Register the task stack listener
-        mTaskStackListener = new TaskStackListenerImpl(mHandler);
+        mTaskStackListener = new TaskStackListenerImpl();
         SystemServicesProxy ssp = Recents.getSystemServices();
         ssp.registerTaskStackListener(mTaskStackListener);
 
         // Initialize the static configuration resources
         reloadHeaderBarLayout();
-        updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
 
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
@@ -225,27 +195,14 @@
         launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
         launchOpts.onlyLoadForCache = true;
         loader.loadTasks(mContext, plan, launchOpts);
-
-        //Manager used to determine if we are running on tv or not
-        UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
-        if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
-            mRecentsIntentActivityName = RECENTS_TV_ACTIVITY;
-        } else {
-            mRecentsIntentActivityName = RECENTS_ACTIVITY;
-        }
     }
 
     public void onBootCompleted() {
-        mBootCompleted = true;
-        updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
+        // Do nothing
     }
 
     public void onConfigurationChanged() {
         reloadHeaderBarLayout();
-        updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
-        // Don't reuse task stack views if the configuration changes
-        mCanReuseTaskStackViews = false;
-        Recents.getConfiguration().updateOnConfigurationChange();
     }
 
     /**
@@ -279,28 +236,24 @@
         mTriggeredFromAltTab = triggeredFromAltTab;
         mDraggingInRecents = draggingInRecents;
         mLaunchedWhileDocking = launchedWhileDockingTask;
-        if (mFastAltTabTrigger.hasTriggered()) {
-            // We are calling this from the doze trigger, so just fall through to show Recents
-            mFastAltTabTrigger.resetTrigger();
+        if (mFastAltTabTrigger.isAsleep()) {
+            // Fast alt-tab duration has elapsed, fall through to showing Recents and reset
+            mFastAltTabTrigger.stopDozing();
         } else if (mFastAltTabTrigger.isDozing()) {
-            // We are dozing but haven't yet triggered, ignore this if this is not another alt-tab,
-            // otherwise, this is an additional tab (alt-tab*), which means that we should trigger
-            // immediately (fall through and disable the pending trigger)
-            // TODO: This is tricky, we need to handle the tab key, but Recents has not yet started
-            //       so we may actually additional signal to handle multiple quick tab cases.  The
-            //       severity of this is inversely proportional to the FAST_ALT_TAB_DELAY_MS
-            //       duration though
+            // Fast alt-tab duration has not elapsed.  If this is triggered by a different
+            // showRecents() call, then ignore that call for now.
+            // TODO: We can not handle quick tabs that happen between the initial showRecents() call
+            //       that started the activity and the activity starting up.  The severity of this
+            //       is inversely proportional to the FAST_ALT_TAB_DELAY_MS duration though.
             if (!triggeredFromAltTab) {
                 return;
             }
             mFastAltTabTrigger.stopDozing();
-        } else {
-            // Otherwise, the doze trigger is not running, and if this is an alt tab, we should
-            // start the trigger and then wait for the hide (or for it to elapse)
-            if (triggeredFromAltTab) {
-                mFastAltTabTrigger.startDozing();
-                return;
-            }
+        } else if (triggeredFromAltTab) {
+            // The fast alt-tab detector is not yet running, so start the trigger and wait for the
+            // hideRecents() call, or for the fast alt-tab duration to elapse
+            mFastAltTabTrigger.startDozing();
+            return;
         }
 
         try {
@@ -317,23 +270,20 @@
     }
 
     public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        if (mBootCompleted) {
-            if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
-                // The user has released alt-tab before the trigger has run, so just show the next
-                // task immediately
-                showNextTask();
+        if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
+            // The user has released alt-tab before the trigger has run, so just show the next
+            // task immediately
+            showNextTask();
 
-                // Cancel the fast alt-tab trigger
-                mFastAltTabTrigger.stopDozing();
-                mFastAltTabTrigger.resetTrigger();
-                return;
-            }
-
-            // Defer to the activity to handle hiding recents, if it handles it, then it must still
-            // be visible
-            EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
-                    triggeredFromHomeKey));
+            // Cancel the fast alt-tab trigger
+            mFastAltTabTrigger.stopDozing();
+            return;
         }
+
+        // Defer to the activity to handle hiding recents, if it handles it, then it must still
+        // be visible
+        EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
+                triggeredFromHomeKey));
     }
 
     public void toggleRecents() {
@@ -347,19 +297,20 @@
         mTriggeredFromAltTab = false;
 
         try {
-            ViewConfiguration viewConfig = ViewConfiguration.get(mContext);
             SystemServicesProxy ssp = Recents.getSystemServices();
             ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
             MutableBoolean isTopTaskHome = new MutableBoolean(true);
             long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
 
             if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
+                RecentsDebugFlags debugFlags = Recents.getDebugFlags();
                 RecentsConfiguration config = Recents.getConfiguration();
                 RecentsActivityLaunchState launchState = config.getLaunchState();
                 if (!launchState.launchedWithAltTab) {
                     // If the user taps quickly
-                    if (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
-                            elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
+                    if (!debugFlags.isPagingEnabled() ||
+                            (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
+                                    elapsedTime < ViewConfiguration.getDoubleTapTimeout())) {
                         // Launch the next focused task
                         EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
                     } else {
@@ -413,9 +364,14 @@
             loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value);
             TaskStack stack = sInstanceLoadPlan.getTaskStack();
             if (stack.getTaskCount() > 0) {
-                // We try and draw the thumbnail transition bitmap in parallel before
-                // toggle/show recents is called
-                preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView);
+                // Only preload the icon (but not the thumbnail since it may not have been taken for
+                // the pausing activity)
+                preloadIcon(topTask);
+
+                // At this point, we don't know anything about the stack state.  So only calculate
+                // the dimensions of the thumbnail that we need for the transition into Recents, but
+                // do not draw it until we construct the activity options when we start Recents
+                updateHeaderBarLayout(stack);
             }
         }
     }
@@ -481,7 +437,7 @@
         }
 
         // Launch the task
-        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
+        ssp.startActivityFromRecents(mContext, toTask.key, toTask.title, launchOpts);
     }
 
     /**
@@ -553,7 +509,7 @@
         MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
 
         // Launch the task
-        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
+        ssp.startActivityFromRecents(mContext, toTask.key, toTask.title, launchOpts);
     }
 
     public void showNextAffiliatedTask() {
@@ -574,11 +530,14 @@
 
         // Make sure we inform DividerView before we actually start the activity so we can change
         // the resize mode already.
-        EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
-        ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds);
-        showRecents(false /* triggeredFromAltTab */,
-                dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */,
-                true /* reloadTasks*/);
+        if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {
+            EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
+            showRecents(
+                    false /* triggeredFromAltTab */,
+                    dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
+                    false /* animate */,
+                    true /* launchedWhileDockingTask*/);
+        }
     }
 
     /**
@@ -603,9 +562,14 @@
                 com.android.internal.R.dimen.navigation_bar_height);
         mNavBarWidth = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.navigation_bar_width);
-        mTaskBarHeight = res.getDimensionPixelSize(
-                R.dimen.recents_task_bar_height);
-        mDummyStackView = new TaskStackView(mContext, new TaskStack());
+        mTaskBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land);
+        mDummyStackView = new TaskStackView(mContext);
         mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
                 null, false);
     }
@@ -614,53 +578,54 @@
      * Prepares the header bar layout for the next transition, if the task view bounds has changed
      * since the last call, it will attempt to re-measure and layout the header bar to the new size.
      *
-     * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
-     *                               is not already bound (can be expensive)
      * @param stack the stack to initialize the stack layout with
      */
-    private void updateHeaderBarLayout(boolean tryAndBindSearchWidget,
-            TaskStack stack) {
-        RecentsConfiguration config = Recents.getConfiguration();
+    private void updateHeaderBarLayout(TaskStack stack) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         Rect systemInsets = new Rect();
         ssp.getStableInsets(systemInsets);
         Rect windowRect = ssp.getWindowRect();
+        // When docked, the nav bar insets are consumed and the activity is measured without insets.
+        // However, the window bounds include the insets, so we need to subtract them here to make
+        // them identical.
+        if (ssp.hasDockedTask()) {
+            windowRect.bottom -= systemInsets.bottom;
+            systemInsets.bottom = 0;
+        }
         calculateWindowStableInsets(systemInsets, windowRect);
         windowRect.offsetTo(0, 0);
 
-        // Update the configuration for the current state
-        config.update(systemInsets);
-
-        if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) {
-            // Try and pre-emptively bind the search widget on startup to ensure that we
-            // have the right thumbnail bounds to animate to.
-            // Note: We have to reload the widget id before we get the task stack bounds below
-            if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
-                config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds);
-            }
-        }
-        config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
-                mSearchBarBounds, mTaskStackBounds);
+        TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
 
         // Rebind the header bar and draw it for the transition
-        TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
-        Rect taskStackBounds = new Rect(mTaskStackBounds);
-        algo.setSystemInsets(systemInsets);
+        stackLayout.setSystemInsets(systemInsets);
         if (stack != null) {
-            algo.initialize(taskStackBounds,
+            stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
+                    mTaskStackBounds);
+            stackLayout.reset();
+            stackLayout.initialize(windowRect, mTaskStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
-        }
-        Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
-        if (!taskViewBounds.equals(mLastTaskViewBounds)) {
-            mLastTaskViewBounds.set(taskViewBounds);
+            mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
 
+            Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
             int taskViewWidth = taskViewBounds.width();
             synchronized (mHeaderBarLock) {
-                mHeaderBar.measure(
-                    View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
-                    View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
+                if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
+                        mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
+                    mHeaderBar.measure(
+                        View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
+                        View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
+                }
                 mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
             }
+
+            // Update the transition bitmap to match the new header bar height
+            if (mThumbTransitionBitmapCache == null ||
+                    (mThumbTransitionBitmapCache.getWidth() != taskViewWidth) ||
+                    (mThumbTransitionBitmapCache.getHeight() != mTaskBarHeight)) {
+                mThumbTransitionBitmapCache = Bitmap.createBitmap(taskViewWidth,
+                        mTaskBarHeight, Bitmap.Config.ARGB_8888);
+            }
         }
     }
 
@@ -697,40 +662,9 @@
     }
 
     /**
-     * Caches the header thumbnail used for a window animation asynchronously into
-     * {@link #mThumbnailTransitionBitmapCache}.
-     */
-    private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask,
-            TaskStack stack, TaskStackView stackView) {
-        preloadIcon(topTask);
-
-        // Update the header bar if necessary
-        updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
-
-        // Update the destination rect
-        mDummyStackView.updateLayoutForStack(stack);
-        final Task toTask = new Task();
-        final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                toTask);
-        ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() {
-            @Override
-            public void run() {
-                final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform);
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        mThumbnailTransitionBitmapCache = transitionBitmap;
-                        mThumbnailTransitionBitmapCacheKey = toTask;
-                    }
-                });
-            }
-        });
-    }
-
-    /**
      * Creates the activity options for a unknown state->recents transition.
      */
-    private ActivityOptions getUnknownTransitionActivityOptions() {
+    protected ActivityOptions getUnknownTransitionActivityOptions() {
         return ActivityOptions.makeCustomAnimation(mContext,
                 R.anim.recents_from_unknown_enter,
                 R.anim.recents_from_unknown_exit,
@@ -740,13 +674,7 @@
     /**
      * Creates the activity options for a home->recents transition.
      */
-    private ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
-        if (fromSearchHome) {
-            return ActivityOptions.makeCustomAnimation(mContext,
-                    R.anim.recents_from_search_launcher_enter,
-                    R.anim.recents_from_search_launcher_exit,
-                    mHandler, null);
-        }
+    protected ActivityOptions getHomeTransitionActivityOptions() {
         return ActivityOptions.makeCustomAnimation(mContext,
                 R.anim.recents_from_launcher_enter,
                 R.anim.recents_from_launcher_exit,
@@ -757,20 +685,25 @@
      * Creates the activity options for an app->recents transition.
      */
     private ActivityOptions getThumbnailTransitionActivityOptions(
-            ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
+            ActivityManager.RunningTaskInfo topTask, TaskStackView stackView) {
         if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
             ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
-            stackView.getScroller().setStackScrollToInitialState();
-            ArrayList<Task> tasks = stack.getStackTasks();
+            ArrayList<Task> tasks = stackView.getStack().getStackTasks();
+            TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
+            TaskStackViewScroller stackScroller = stackView.getScroller();
+
+            stackView.updateLayoutAlgorithm(true /* boundScroll */);
+            stackView.updateToInitialState(true /* scrollToInitialState */);
+
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 Task task = tasks.get(i);
                 if (task.isFreeformTask()) {
-                    mTmpTransform = stackView.getStackAlgorithm()
-                            .getStackTransformScreenCoordinates(task,
-                                    stackView.getScroller().getStackScroll(), mTmpTransform, null);
+                    mTmpTransform = stackLayout.getStackTransformScreenCoordinates(task,
+                                    stackScroller.getStackScroll(), mTmpTransform, null);
+                    Bitmap thumbnail = drawThumbnailTransitionBitmap(task, mTmpTransform,
+                            mThumbTransitionBitmapCache);
                     Rect toTaskRect = new Rect();
                     mTmpTransform.rect.round(toTaskRect);
-                    Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
                     specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect));
                 }
             }
@@ -781,11 +714,11 @@
         } else {
             // Update the destination rect
             Task toTask = new Task();
-            TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                    toTask);
-            RectF toTaskRect = toTransform.rect;
-            Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
+            TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask);
+            Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
+                    mThumbTransitionBitmapCache);
             if (thumbnail != null) {
+                RectF toTaskRect = toTransform.rect;
                 return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
                         thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
                         (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null);
@@ -795,28 +728,13 @@
         }
     }
 
-    private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask,
-            TaskViewTransform toTransform) {
-        Bitmap thumbnail;
-        if (mThumbnailTransitionBitmapCacheKey != null
-                && mThumbnailTransitionBitmapCacheKey.key != null
-                && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) {
-            thumbnail = mThumbnailTransitionBitmapCache;
-            mThumbnailTransitionBitmapCacheKey = null;
-            mThumbnailTransitionBitmapCache = null;
-        } else {
-            preloadIcon(topTask);
-            thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
-        }
-        return thumbnail;
-    }
-
     /**
      * Returns the transition rect for the given task id.
      */
-    private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack,
-            TaskStackView stackView, Task runningTaskOut) {
+    private TaskViewTransform getThumbnailTransitionTransform(TaskStackView stackView,
+            Task runningTaskOut) {
         // Find the running task in the TaskStack
+        TaskStack stack = stackView.getStack();
         Task launchTask = stack.getLaunchTarget();
         if (launchTask != null) {
             runningTaskOut.copyFrom(launchTask);
@@ -827,8 +745,9 @@
         }
 
         // Get the transform for the running task
-        stackView.getScroller().setStackScrollToInitialState();
-        mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
+        stackView.updateLayoutAlgorithm(true /* boundScroll */);
+        stackView.updateToInitialState(true /* scrollToInitialState */);
+        stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null);
         return mTmpTransform;
     }
@@ -836,25 +755,28 @@
     /**
      * Draws the header of a task used for the window animation into a bitmap.
      */
-    private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
+    private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform,
+            Bitmap thumbnail) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (toTransform != null && toTask.key != null) {
-            Bitmap thumbnail;
             synchronized (mHeaderBarLock) {
-                int toHeaderWidth = (int) toTransform.rect.width();
-                int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
                 boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
                 mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
                         (int) toTransform.rect.height());
-                thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
-                        Bitmap.Config.ARGB_8888);
                 if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
                     thumbnail.eraseColor(0xFFff0000);
                 } else {
+                    thumbnail.eraseColor(0);
                     Canvas c = new Canvas(thumbnail);
-                    c.scale(toTransform.scale, toTransform.scale);
+                    // Workaround for b/27815919, reset the callback so that we do not trigger an
+                    // invalidate on the header bar as a result of updating the icon
+                    Drawable icon = mHeaderBar.getIconView().getDrawable();
+                    if (icon != null) {
+                        icon.setCallback(null);
+                    }
                     mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
                             disabledInSafeMode);
+                    mHeaderBar.setDimAlpha(toTransform.dimAlpha);
                     mHeaderBar.draw(c);
                     c.setBitmap(null);
                 }
@@ -867,9 +789,10 @@
     /**
      * Shows the recents activity
      */
-    private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+    protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
             boolean isTopTaskHome, boolean animate) {
         RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
 
         // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
         // should always preload the tasks now. If we are dragging in recents, reload them as
@@ -881,95 +804,60 @@
         if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
             loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
         }
+
         TaskStack stack = sInstanceLoadPlan.getTaskStack();
-
-        // Update the header bar if necessary
-        updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
-
-        // Prepare the dummy stack for the transition
-        mDummyStackView.updateLayoutForStack(stack);
-        TaskStackLayoutAlgorithm.VisibilityReport stackVr =
-                mDummyStackView.computeStackVisibilityReport();
-
-        if (!animate) {
-            ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
-            startRecentsActivity(topTask, opts, false /* fromHome */,
-                    false /* fromSearchHome */, false /* fromThumbnail*/, stackVr);
-            return;
-        }
-
         boolean hasRecentTasks = stack.getTaskCount() > 0;
         boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
 
+        // Update the launch state that we need in updateHeaderBarLayout()
+        launchState.launchedFromHome = !useThumbnailTransition;
+        launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking;
+        launchState.launchedViaDockGesture = mLaunchedWhileDocking;
+        launchState.launchedViaDragGesture = mDraggingInRecents;
+        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        launchState.launchedWithAltTab = mTriggeredFromAltTab;
+
+        // Preload the icon (this will be a null-op if we have preloaded the icon already in
+        // preloadRecents())
+        preloadIcon(topTask);
+
+        // Update the header bar if necessary
+        updateHeaderBarLayout(stack);
+
+        // Prepare the dummy stack for the transition
+        TaskStackLayoutAlgorithm.VisibilityReport stackVr =
+                mDummyStackView.computeStackVisibilityReport();
+
+        // Update the remaining launch state
+        launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks;
+        launchState.launchedNumVisibleThumbnails = stackVr.numVisibleThumbnails;
+
+        if (!animate) {
+            startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1));
+            return;
+        }
+
+        ActivityOptions opts;
         if (useThumbnailTransition) {
             // Try starting with a thumbnail transition
-            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
-                    mDummyStackView);
-            if (opts != null) {
-                startRecentsActivity(topTask, opts, false /* fromHome */,
-                        false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
-            } else {
-                // Fall through below to the non-thumbnail transition
-                useThumbnailTransition = false;
-            }
-        }
-
-        if (!useThumbnailTransition) {
+            opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView);
+        } else {
             // If there is no thumbnail transition, but is launching from home into recents, then
-            // use a quick home transition and do the animation from home
-            if (hasRecentTasks) {
-                SystemServicesProxy ssp = Recents.getSystemServices();
-                String homeActivityPackage = ssp.getHomeActivityPackageName();
-                String searchWidgetPackage = null;
-                if (RecentsDebugFlags.Static.EnableSearchBar) {
-                    searchWidgetPackage = Prefs.getString(mContext,
-                            Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
-                } else {
-                    AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget();
-                    if (searchWidgetInfo != null) {
-                        searchWidgetPackage = searchWidgetInfo.provider.getPackageName();
-                    }
-                }
-
-                // Determine whether we are coming from a search owned home activity
-                boolean fromSearchHome = (homeActivityPackage != null) &&
-                        homeActivityPackage.equals(searchWidgetPackage);
-                ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
-                startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
-                        false /* fromThumbnail */, stackVr);
-            } else {
-                // Otherwise we do the normal fade from an unknown source
-                ActivityOptions opts = getUnknownTransitionActivityOptions();
-                startRecentsActivity(topTask, opts, true /* fromHome */,
-                        false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
-            }
+            // use a quick home transition
+            opts = hasRecentTasks
+                ? getHomeTransitionActivityOptions()
+                : getUnknownTransitionActivityOptions();
         }
+        startRecentsActivity(opts);
         mLastToggleTime = SystemClock.elapsedRealtime();
     }
 
     /**
      * Starts the recents activity.
      */
-    private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
-              ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
-              TaskStackLayoutAlgorithm.VisibilityReport vr) {
-        // Update the configuration based on the launch options
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
-        launchState.launchedFromHome = fromSearchHome || fromHome;
-        launchState.launchedFromSearchHome = fromSearchHome;
-        launchState.launchedFromAppWithThumbnail = fromThumbnail;
-        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
-        launchState.launchedWithAltTab = mTriggeredFromAltTab;
-        launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
-        launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
-        launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
-        launchState.launchedHasConfigurationChanged = false;
-        launchState.launchedViaDragGesture = mDraggingInRecents;
-        launchState.launchedWhileDocking = mLaunchedWhileDocking;
-
+    private void startRecentsActivity(ActivityOptions opts) {
         Intent intent = new Intent();
-        intent.setClassName(RECENTS_PACKAGE, mRecentsIntentActivityName);
+        intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
@@ -979,7 +867,6 @@
         } else {
             mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         }
-        mCanReuseTaskStackViews = true;
         EventBus.getDefault().send(new RecentsActivityStartingEvent());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index f8000b8..ffeb4a1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.EventLog;
@@ -26,7 +27,7 @@
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 
@@ -91,8 +92,8 @@
     }
 
     @Override
-    public void sendDockingTopTaskEvent(int dragMode) throws RemoteException {
-        EventBus.getDefault().post(new DockingTopTaskEvent(dragMode));
+    public void sendDockingTopTaskEvent(int dragMode, Rect initialRect) throws RemoteException {
+        EventBus.getDefault().post(new DockedTopTaskEvent(dragMode, initialRect));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java
new file mode 100644
index 0000000..4738eed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when an app transition has finished playing.
+ */
+public class AppTransitionFinishedEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
deleted file mode 100644
index 52cfe18..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.events.activity;
-
-import com.android.systemui.recents.RecentsAppWidgetHost;
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent by the {@link RecentsAppWidgetHost} whenever the search provider widget changes, and
- * subscribers can update accordingly.
- */
-public class AppWidgetProviderChangedEvent extends EventBus.Event {
-    // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
deleted file mode 100644
index 98c0a69..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history is to be cleared
- */
-public class ClearHistoryEvent extends EventBus.AnimatedEvent {
-    // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
new file mode 100644
index 0000000..e3bc2a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the Recents activity configuration has changed.
+ */
+public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
+
+    public final boolean fromMultiWindow;
+    public final boolean fromOrientationChange;
+    public final boolean hasStackTasks;
+
+    public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange,
+            boolean hasStackTasks) {
+        this.fromMultiWindow = fromMultiWindow;
+        this.fromOrientationChange = fromOrientationChange;
+        this.hasStackTasks = hasStackTasks;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java
new file mode 100644
index 0000000..32d9a70
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus.Event;
+
+/**
+ * Sent when the window animation has started when docking a task
+ */
+public class DockedFirstAnimationFrameEvent extends Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
new file mode 100644
index 0000000..f1bc214
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
+
+import android.graphics.Rect;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Fires when the user invoked the gesture to dock the top/left task after we called into window
+ * manager and before we start recents.
+ */
+public class DockedTopTaskEvent extends EventBus.Event {
+
+    public int dragMode;
+    public Rect initialRect;
+
+    public DockedTopTaskEvent(int dragMode, Rect initialRect) {
+        this.dragMode = dragMode;
+        this.initialRect = initialRect;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
deleted file mode 100644
index 264c2c4..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * Fires when the user invoked the gesture to dock the top/left task.
- */
-public class DockingTopTaskEvent extends EventBus.Event {
-
-    public int dragMode;
-
-    public DockingTopTaskEvent(int dragMode) {
-        this.dragMode = dragMode;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ForcedResizableEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ForcedResizableEvent.java
new file mode 100644
index 0000000..cdcabf0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ForcedResizableEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when recents received the information that an activity got forced resizable, and we need
+ * to inform the user about that.
+ */
+public class ForcedResizableEvent extends EventBus.Event {
+
+    public final String packageName;
+    public final int taskId;
+
+    public ForcedResizableEvent(String packageName, int taskId) {
+        this.packageName = packageName;
+        this.taskId = taskId;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java
deleted file mode 100644
index 6c767e4..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view button should be hidden.
- */
-public class HideHistoryButtonEvent extends EventBus.Event {
-    // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
deleted file mode 100644
index bacf3bd..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view will be closed.
- */
-public class HideHistoryEvent extends EventBus.Event {
-
-    public final boolean animate;
-
-    public HideHistoryEvent(boolean animate) {
-        this.animate = animate;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
new file mode 100644
index 0000000..e02fb14
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the stack action button should be hidden.
+ */
+public class HideStackActionButtonEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java
new file mode 100644
index 0000000..04ca68f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
+
+
+import android.graphics.Rect;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+public class LaunchTvTaskEvent extends EventBus.Event {
+
+    public final TaskCardView taskView;
+    public final Task task;
+    public final Rect targetTaskBounds;
+    public final int targetTaskStack;
+
+    public LaunchTvTaskEvent(TaskCardView taskView, Task task, Rect targetTaskBounds,
+            int targetTaskStack) {
+        this.taskView = taskView;
+        this.task = task;
+        this.targetTaskBounds = targetTaskBounds;
+        this.targetTaskStack = targetTaskStack;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskStartedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskStartedEvent.java
new file mode 100644
index 0000000..75d3efa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskStartedEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+/**
+ * This event is sent following {@link LaunchTvTaskEvent} after the call to the system is made to
+ * start the task, only used on TV.
+ */
+public class LaunchTvTaskStartedEvent extends EventBus.AnimatedEvent {
+
+    public final TaskCardView taskView;
+
+    public LaunchTvTaskStartedEvent(TaskCardView taskView) {
+        this.taskView = taskView;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
new file mode 100644
index 0000000..cf2a68e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent by the activity whenever the multi-window state has changed.
+ */
+public class MultiWindowStateChangedEvent extends EventBus.Event {
+
+    public final boolean inMultiWindow;
+    public final boolean hasStackTasks;
+
+    public MultiWindowStateChangedEvent(boolean inMultiWindow, boolean hasStackTasks) {
+        this.inMultiWindow = inMultiWindow;
+        this.hasStackTasks = hasStackTasks;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
deleted file mode 100644
index ae803ea..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view button should be shown.
- */
-public class ShowHistoryButtonEvent extends EventBus.Event {
-
-    // Whether or not to translate the history button when showing it
-    public final boolean translate;
-
-    public ShowHistoryButtonEvent(boolean translate) {
-        this.translate = translate;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
deleted file mode 100644
index 469f336..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view button is clicked.
- */
-public class ShowHistoryEvent extends EventBus.Event {
-
-    // Simple event
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
new file mode 100644
index 0000000..d81f89c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the stack action view button should be shown.
+ */
+public class ShowStackActionButtonEvent extends EventBus.Event {
+
+    // Whether or not to translate the stack action button when showing it
+    public final boolean translate;
+
+    public ShowStackActionButtonEvent(boolean translate) {
+        this.translate = translate;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
index f87f6de..0d614e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -28,8 +28,10 @@
      * A new TaskStack instance representing the latest stack state.
      */
     public final TaskStack stack;
+    public final boolean inMultiWindow;
 
-    public TaskStackUpdatedEvent(TaskStack stack) {
+    public TaskStackUpdatedEvent(TaskStack stack, boolean inMultiWindow) {
         this.stack = stack;
+        this.inMultiWindow = inMultiWindow;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java
deleted file mode 100644
index aaf77af..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view button is clicked.
- */
-public class ToggleHistoryEvent extends EventBus.AnimatedEvent {
-
-    // Simple event
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
index 4140bcd..8843eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
@@ -19,21 +19,18 @@
 import android.content.Context;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 
 /**
- * This is sent when the visibility of the RecentsActivity for the current user changes.
+ * This is sent when the visibility of the RecentsActivity for the current user changes.  Handlers
+ * of this event should not alter the UI, as the activity may still be visible.
  */
 public class RecentsVisibilityChangedEvent extends EventBus.Event {
 
     public final Context applicationContext;
-    public final SystemServicesProxy systemServicesProxy;
     public final boolean visible;
 
-    public RecentsVisibilityChangedEvent(Context context, SystemServicesProxy systemServicesProxy,
-            boolean visible) {
+    public RecentsVisibilityChangedEvent(Context context, boolean visible) {
         this.applicationContext = context.getApplicationContext();
-        this.systemServicesProxy = systemServicesProxy;
         this.visible = visible;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
index cf74519..0352161 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
@@ -22,5 +22,10 @@
  * This is sent whenever all the task views in a stack have been dismissed.
  */
 public class AllTaskViewsDismissedEvent extends EventBus.Event {
-    // Simple event
+
+    public final int msgResId;
+
+    public AllTaskViewsDismissedEvent(int msgResId) {
+        this.msgResId = msgResId;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
new file mode 100644
index 0000000..f8b59c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.views.TaskView;
+
+/**
+ * This event is sent to request that all the {@link TaskView}s are dismissed.
+ */
+public class DismissAllTaskViewsEvent extends EventBus.AnimatedEvent {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
index 1165f4e..1f8c644 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents.events.ui;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.views.TaskView;
 
 /**
@@ -26,10 +25,8 @@
 public class DismissTaskViewEvent extends EventBus.AnimatedEvent {
 
     public final TaskView taskView;
-    public final Task task;
 
-    public DismissTaskViewEvent(TaskView taskView, Task task) {
+    public DismissTaskViewEvent(TaskView taskView) {
         this.taskView = taskView;
-        this.task = task;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
deleted file mode 100644
index 863f40b..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.events.ui;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent to reset the background scrim back to the initial state.
- */
-public class ResetBackgroundScrimEvent extends EventBus.Event {
-    // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java
deleted file mode 100644
index fdd4c67..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.events.ui;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent to request an update to the background scrim.
- */
-public class UpdateBackgroundScrimEvent extends EventBus.Event {
-
-    public final float alpha;
-
-    public UpdateBackgroundScrimEvent(float alpha) {
-        this.alpha = alpha;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
index b85ddac..216be61 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
@@ -23,7 +23,7 @@
 /**
  * This event is sent when a user drags in/out of a drop target.
  */
-public class DragDropTargetChangedEvent extends EventBus.Event {
+public class DragDropTargetChangedEvent extends EventBus.AnimatedEvent {
 
     // The task that is currently being dragged
     public final Task task;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
deleted file mode 100644
index d7b9b9e..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.history;
-
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.support.v7.widget.RecyclerView;
-import android.text.format.DateFormat;
-import android.util.SparseIntArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
-import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.AnimationProps;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-
-
-/**
- * An adapter for the list of recent tasks in the history view.
- */
-public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAdapter.ViewHolder> {
-
-    private static final String TAG = "RecentsHistoryView";
-    private static final boolean DEBUG = false;
-
-    static final int DATE_ROW_VIEW_TYPE = 0;
-    static final int TASK_ROW_VIEW_TYPE = 1;
-
-    /**
-     * View holder implementation. The {@param TaskCallbacks} are only called for TaskRow view
-     * holders.
-     */
-    public static class ViewHolder extends RecyclerView.ViewHolder implements Task.TaskCallbacks {
-        public final View content;
-
-        private Task mTask;
-
-        public ViewHolder(View content) {
-            super(content);
-            this.content = content;
-        }
-
-        /**
-         * Binds this view holder to the given task.
-         */
-        public void bindToTask(Task newTask) {
-            unbindFromTask();
-            mTask = newTask;
-            mTask.addCallback(this);
-        }
-
-        /**
-         * Unbinds this view holder from the
-         */
-        public void unbindFromTask() {
-            if (mTask != null) {
-                mTask.removeCallback(this);
-                mTask = null;
-            }
-        }
-
-        @Override
-        public void onTaskDataLoaded(Task task) {
-            // This callback is only made for TaskRow view holders
-            ImageView iv = (ImageView) content.findViewById(R.id.icon);
-            iv.setImageDrawable(task.icon);
-            iv.animate()
-                    .alpha(1f)
-                    .setDuration(100)
-                    .start();
-        }
-
-        @Override
-        public void onTaskDataUnloaded() {
-            // This callback is only made for TaskRow view holders
-            ImageView iv = (ImageView) content.findViewById(R.id.icon);
-            iv.setImageBitmap(null);
-            iv.animate().cancel();
-        }
-
-        @Override
-        public void onTaskStackIdChanged() {
-            // Do nothing, this callback is only made for TaskRow view holders
-        }
-    }
-
-    /**
-     * A single row of content.
-     */
-    interface Row {
-        int getViewType();
-    }
-
-    /**
-     * A date row.
-     */
-    static class DateRow implements Row {
-
-        public final String date;
-
-        public DateRow(String date) {
-            this.date = date;
-        }
-
-        @Override
-        public int getViewType() {
-            return RecentsHistoryAdapter.DATE_ROW_VIEW_TYPE;
-        }
-    }
-
-    /**
-     * A task row.
-     */
-    static class TaskRow implements Row, View.OnClickListener {
-
-        public final Task task;
-        public final int dateKey;
-
-        public TaskRow(Task task, int dateKey) {
-            this.task = task;
-            this.dateKey = dateKey;
-        }
-
-        @Override
-        public void onClick(View v) {
-            SystemServicesProxy ssp = Recents.getSystemServices();
-            ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
-                    ActivityOptions.makeBasic());
-
-            MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
-                    task.key.getComponent().toString());
-        }
-
-        @Override
-        public int getViewType() {
-            return RecentsHistoryAdapter.TASK_ROW_VIEW_TYPE;
-        }
-    }
-
-    private Context mContext;
-    private LayoutInflater mLayoutInflater;
-    private final List<Row> mRows = new ArrayList<>();
-    private final SparseIntArray mTaskRowCount = new SparseIntArray();
-    private TaskStack mStack;
-
-    public RecentsHistoryAdapter(Context context) {
-        mLayoutInflater = LayoutInflater.from(context);
-    }
-
-    /**
-     * Updates this adapter with the given tasks.
-     */
-    public void updateTasks(Context context, TaskStack stack) {
-        mContext = context;
-        mStack = stack;
-
-        final Locale l = context.getResources().getConfiguration().locale;
-        final String dateFormatStr = DateFormat.getBestDateTimePattern(l, "EEEEMMMMd");
-        final List<Task> tasksMostRecent = new ArrayList<>(stack.getHistoricalTasks());
-        Collections.reverse(tasksMostRecent);
-        int prevDateKey = -1;
-        int taskCount = tasksMostRecent.size();
-        mRows.clear();
-        mTaskRowCount.clear();
-        Calendar cal = Calendar.getInstance(l);
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasksMostRecent.get(i);
-            if (task.isFreeformTask()) {
-                continue;
-            }
-
-            cal.setTimeInMillis(task.key.lastActiveTime);
-            int dateKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
-            if (dateKey != prevDateKey) {
-                prevDateKey = dateKey;
-                mRows.add(new DateRow(DateFormat.format(dateFormatStr, cal).toString()));
-            }
-            mRows.add(new TaskRow(task, dateKey));
-            mTaskRowCount.put(dateKey, mTaskRowCount.get(dateKey, 0) + 1);
-        }
-        notifyDataSetChanged();
-    }
-
-    /**
-     * Removes historical tasks belonging to the specified package and user. We do not need to
-     * remove the task from the TaskStack since the TaskStackView will also receive this event.
-     */
-    public void removeTasks(String packageName, int userId) {
-        for (int i = mRows.size() - 1; i >= 0; i--) {
-            Row row = mRows.get(i);
-            if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
-                TaskRow taskRow = (TaskRow) row;
-                Task task = taskRow.task;
-                String taskPackage = task.key.getComponent().getPackageName();
-                if (task.key.userId == userId && taskPackage.equals(packageName)) {
-                    i = removeTaskRow(i);
-                }
-            }
-        }
-        if (mRows.isEmpty()) {
-            dismissHistory();
-        }
-    }
-
-    /**
-     * Removes all historical tasks.
-     */
-    public void removeAllTasks() {
-        for (int i = mRows.size() - 1; i >= 0; i--) {
-            Row row = mRows.get(i);
-            if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
-                TaskRow taskRow = (TaskRow) row;
-                Task task = taskRow.task;
-                mStack.removeTask(task, AnimationProps.IMMEDIATE);
-                EventBus.getDefault().send(new DeleteTaskDataEvent(task));
-                i = removeTaskRow(i);
-            }
-        }
-        dismissHistory();
-    }
-
-    /**
-     * Returns the row at the given {@param position}.
-     */
-    public Row getRow(int position) {
-        return mRows.get(position);
-    }
-
-    @Override
-    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        switch (viewType) {
-            case DATE_ROW_VIEW_TYPE:
-                return new ViewHolder(mLayoutInflater.inflate(R.layout.recents_history_date, parent,
-                        false));
-            case TASK_ROW_VIEW_TYPE:
-                return new ViewHolder(mLayoutInflater.inflate(R.layout.recents_history_task, parent,
-                        false));
-            default:
-                return new ViewHolder(null);
-        }
-    }
-
-    @Override
-    public void onBindViewHolder(ViewHolder holder, int position) {
-        RecentsTaskLoader loader = Recents.getTaskLoader();
-
-        Row row = mRows.get(position);
-        int viewType = row.getViewType();
-        switch (viewType) {
-            case DATE_ROW_VIEW_TYPE: {
-                TextView tv = (TextView) holder.content;
-                tv.setText(((DateRow) row).date);
-                break;
-            }
-            case TASK_ROW_VIEW_TYPE: {
-                TaskRow taskRow = (TaskRow) row;
-                TextView tv = (TextView) holder.content.findViewById(R.id.description);
-                tv.setText(taskRow.task.title);
-                ImageView iv = (ImageView) holder.content.findViewById(R.id.icon);
-                iv.setAlpha(0f);
-                holder.content.setOnClickListener(taskRow);
-
-                holder.bindToTask(taskRow.task);
-                loader.loadTaskData(taskRow.task, false /* fetchAndInvalidateThumbnails */);
-                break;
-            }
-        }
-    }
-
-    @Override
-    public void onViewRecycled(ViewHolder holder) {
-        RecentsTaskLoader loader = Recents.getTaskLoader();
-        int position = holder.getAdapterPosition();
-        if (position != RecyclerView.NO_POSITION) {
-            Row row = mRows.get(position);
-            int viewType = row.getViewType();
-            if (viewType == TASK_ROW_VIEW_TYPE) {
-                TaskRow taskRow = (TaskRow) row;
-                loader.unloadTaskData(taskRow.task);
-                holder.unbindFromTask();
-            }
-        }
-    }
-
-    @Override
-    public boolean onFailedToRecycleView(ViewHolder holder) {
-        // Always recycle views, even if it is animating
-        onViewRecycled(holder);
-        return true;
-    }
-
-    public void onTaskRemoved(Task task, int position) {
-        // Since this is removed from the history, we need to update the stack as well to ensure
-        // that the model is correct. Since the stack is hidden, we can update it immediately.
-        mStack.removeTask(task, AnimationProps.IMMEDIATE);
-        removeTaskRow(position);
-        if (mRows.isEmpty()) {
-            dismissHistory();
-        }
-    }
-
-    @Override
-    public int getItemCount() {
-        return mRows.size();
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        return mRows.get(position).getViewType();
-    }
-
-    /**
-     * Removes a task row, also removing the associated {@link DateRow} if there are no more tasks
-     * in that date group.
-     *
-     * @param position an adapter position of a task row such that 0 < position < num rows.
-     * @return the index of the last removed row
-     */
-    private int removeTaskRow(int position) {
-        // Remove the task at that row
-        TaskRow taskRow = (TaskRow) mRows.remove(position);
-        int numTasks = mTaskRowCount.get(taskRow.dateKey) - 1;
-        mTaskRowCount.put(taskRow.dateKey, numTasks);
-        notifyItemRemoved(position);
-
-        if (numTasks == 0) {
-            // If that was the last task row in the group, then remove the date as well
-            mRows.remove(position - 1);
-            mTaskRowCount.removeAt(mTaskRowCount.indexOfKey(taskRow.dateKey));
-            notifyItemRemoved(position - 1);
-            return position - 1;
-        } else {
-            return position;
-        }
-    }
-
-    /**
-     * Dismisses history back to the stack view.
-     */
-    private void dismissHistory() {
-        EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
-        EventBus.getDefault().send(new HideHistoryButtonEvent());
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
deleted file mode 100644
index 3d1ea8e..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.history;
-
-import android.content.Context;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
-
-
-/**
- * An item touch handler for items in the history view.
- */
-public class RecentsHistoryItemTouchCallbacks extends ItemTouchHelper.SimpleCallback {
-
-    private Context mContext;
-    private RecentsHistoryAdapter mAdapter;
-
-    public RecentsHistoryItemTouchCallbacks(Context context, RecentsHistoryAdapter adapter) {
-        super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
-        mContext = context;
-        mAdapter = adapter;
-    }
-
-    @Override
-    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
-            RecyclerView.ViewHolder target) {
-        return false;
-    }
-
-    @Override
-    public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
-        int viewType = mAdapter.getItemViewType(viewHolder.getAdapterPosition());
-        switch (viewType) {
-            case RecentsHistoryAdapter.DATE_ROW_VIEW_TYPE:
-                // Disallow swiping
-                return 0;
-            default:
-                return super.getSwipeDirs(recyclerView, viewHolder);
-        }
-    }
-
-    @Override
-    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
-        int position = viewHolder.getAdapterPosition();
-        if (position != RecyclerView.NO_POSITION) {
-            RecentsHistoryAdapter.Row row = mAdapter.getRow(position);
-            RecentsHistoryAdapter.TaskRow taskRow = (RecentsHistoryAdapter.TaskRow) row;
-
-            // Remove the task from the system
-            EventBus.getDefault().send(new DeleteTaskDataEvent(taskRow.task));
-            mAdapter.onTaskRemoved(taskRow.task, position);
-
-            // Keep track of deletions by swiping within history
-            MetricsLogger.histogram(mContext, "overview_task_dismissed_source",
-                    Constants.Metrics.DismissSourceHistorySwipeGesture);
-            MetricsLogger.action(mContext, MetricsEvent.OVERVIEW_DISMISS,
-                    taskRow.task.key.getComponent().toString());
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
deleted file mode 100644
index 3c4adb2..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.history;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowInsets;
-import android.widget.LinearLayout;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsActivity;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.ClearHistoryEvent;
-import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
-import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.AnimateableViewBounds;
-
-/**
- * A list of the recent tasks that are not in the stack.
- */
-public class RecentsHistoryView extends LinearLayout
-        implements ValueAnimator.AnimatorUpdateListener {
-
-    private static final float TRANSLATION_Y_PCT = 0.25f;
-    private static final float BG_SCRIM_ALPHA = 0.625f;
-
-    private RecyclerView mRecyclerView;
-    private RecentsHistoryAdapter mAdapter;
-    private RecentsHistoryItemTouchCallbacks mItemTouchHandler;
-    private AnimateableViewBounds mViewBounds;
-    private boolean mIsVisible;
-    private Rect mSystemInsets = new Rect();
-    private int mHeaderHeight;
-
-    private int mHistoryTransitionDuration;
-
-    public RecentsHistoryView(Context context) {
-        super(context);
-    }
-
-    public RecentsHistoryView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public RecentsHistoryView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public RecentsHistoryView(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        Resources res = context.getResources();
-        mAdapter = new RecentsHistoryAdapter(context);
-        mItemTouchHandler = new RecentsHistoryItemTouchCallbacks(context, mAdapter);
-        mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
-        mViewBounds = new AnimateableViewBounds(this, 0);
-        setOutlineProvider(mViewBounds);
-    }
-
-    /**
-     * Updates this history view with the recent tasks, and then shows it.
-     */
-    public void show(TaskStack stack, int stackHeight, View clearAllButton) {
-        setVisibility(View.VISIBLE);
-        setAlpha(0f);
-        setTranslationY(-stackHeight * TRANSLATION_Y_PCT);
-        animate()
-                .alpha(1f)
-                .translationY(0f)
-                .setDuration(mHistoryTransitionDuration)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .setUpdateListener(this)
-                .start();
-        clearAllButton.setVisibility(View.VISIBLE);
-        clearAllButton.setAlpha(0f);
-        clearAllButton.animate()
-                .alpha(1f)
-                .setDuration(mHistoryTransitionDuration)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .withLayer()
-                .start();
-        mAdapter.updateTasks(getContext(), stack);
-        mIsVisible = true;
-        EventBus.getDefault().send(new UpdateBackgroundScrimEvent(BG_SCRIM_ALPHA));
-
-        MetricsLogger.visible(mRecyclerView.getContext(), MetricsEvent.OVERVIEW_HISTORY);
-    }
-
-    /**
-     * Hides this history view.
-     */
-    public void hide(boolean animate, int stackHeight, final View clearAllButton) {
-        if (animate) {
-            animate()
-                    .alpha(0f)
-                    .translationY(-stackHeight * TRANSLATION_Y_PCT)
-                    .setDuration(mHistoryTransitionDuration)
-                    .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
-                    .setUpdateListener(this)
-                    .withEndAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            setVisibility(View.INVISIBLE);
-                        }
-                    })
-                    .start();
-            clearAllButton.animate()
-                    .alpha(0f)
-                    .translationY(0f)
-                    .setDuration(mHistoryTransitionDuration)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .withEndAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            clearAllButton.setVisibility(View.INVISIBLE);
-                        }
-                    })
-                    .withLayer()
-                    .start();
-        } else {
-            setAlpha(0f);
-            setVisibility(View.INVISIBLE);
-            clearAllButton.setAlpha(0f);
-            clearAllButton.setVisibility(View.INVISIBLE);
-        }
-        mIsVisible = false;
-        EventBus.getDefault().send(new ResetBackgroundScrimEvent());
-
-        MetricsLogger.hidden(mRecyclerView.getContext(), MetricsEvent.OVERVIEW_HISTORY);
-    }
-
-    /**
-     * Updates the system insets of this history view to the provided values.
-     */
-    public void setSystemInsets(Rect systemInsets) {
-        mSystemInsets.set(systemInsets);
-        requestLayout();
-    }
-
-    /**
-     * Updates the header height to account for the history button bar.
-     */
-    public void setHeaderHeight(int height) {
-        mHeaderHeight = height;
-        requestLayout();
-    }
-
-    /**
-     * Returns whether this view is visible.
-     */
-    public boolean isVisible() {
-        return mIsVisible;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mRecyclerView = (RecyclerView) findViewById(R.id.list);
-        mRecyclerView.setAdapter(mAdapter);
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        mRecyclerView.getItemAnimator().setRemoveDuration(100);
-        ItemTouchHelper touchHelper = new ItemTouchHelper(mItemTouchHandler);
-        touchHelper.attachToRecyclerView(mRecyclerView);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        RecentsConfiguration config = Recents.getConfiguration();
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        int height = MeasureSpec.getSize(heightMeasureSpec);
-
-        // Pad the view to align the history with the stack layout
-        Rect taskStackBounds = new Rect();
-        config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
-                mSystemInsets.right, new Rect() /* searchBarSpaceBounds */, taskStackBounds);
-        int stackWidthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
-        int stackHeightPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.recents_stack_top_padding);
-        mRecyclerView.setPadding(stackWidthPadding + mSystemInsets.left,
-                stackHeightPadding + mSystemInsets.top + mHeaderHeight,
-                stackWidthPadding + mSystemInsets.right, mSystemInsets.bottom);
-
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
-        super.onAttachedToWindow();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        EventBus.getDefault().unregister(this);
-    }
-
-    @Override
-    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        setSystemInsets(insets.getSystemWindowInsets());
-        return insets;
-    }
-
-    @Override
-    public void onAnimationUpdate(ValueAnimator animation) {
-        // Clip the top of the view by the header bar height
-        int top = Math.max(0, (int) -getTranslationY()) + mSystemInsets.top + mHeaderHeight;
-        mViewBounds.setClipTop(top);
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    /**** EventBus Events ****/
-
-    public final void onBusEvent(PackagesChangedEvent event) {
-        mAdapter.removeTasks(event.packageName, event.userId);
-    }
-
-    public final void onBusEvent(ClearHistoryEvent event) {
-        mAdapter.removeAllTasks();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 95aa10f..574ea03 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -30,7 +30,7 @@
     @ViewDebug.ExportedProperty(category="recents")
     boolean mIsDozing;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mHasTriggered;
+    boolean mIsAsleep;
     @ViewDebug.ExportedProperty(category="recents")
     int mDozeDurationMilliseconds;
     Runnable mOnSleepRunnable;
@@ -40,7 +40,7 @@
         @Override
         public void run() {
             mIsDozing = false;
-            mHasTriggered = true;
+            mIsAsleep = true;
             mOnSleepRunnable.run();
         }
     };
@@ -56,7 +56,7 @@
      */
     public void startDozing() {
         forcePoke();
-        mHasTriggered = false;
+        mIsAsleep = false;
     }
 
     /**
@@ -65,6 +65,7 @@
     public void stopDozing() {
         mHandler.removeCallbacks(mDozeRunnable);
         mIsDozing = false;
+        mIsAsleep = false;
     }
 
     /**
@@ -99,12 +100,7 @@
     }
 
     /** Returns whether the trigger has fired at least once. */
-    public boolean hasTriggered() {
-        return mHasTriggered;
-    }
-
-    /** Resets the doze trigger state. */
-    public void resetTrigger() {
-        mHasTriggered = false;
+    public boolean isAsleep() {
+        return mIsAsleep;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 8b4474f..1a4b40f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -16,15 +16,19 @@
 
 package com.android.systemui.recents.misc;
 
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
 import android.app.ITaskStackListener;
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -34,6 +38,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -47,8 +52,10 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
-import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.Looper;
+import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -58,10 +65,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.MutableBoolean;
-import android.util.Pair;
 import android.view.Display;
+import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IDockedStackListener;
-import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager.KeyboardShortcutsReceiver;
 import android.view.WindowManagerGlobal;
@@ -69,10 +75,12 @@
 
 import com.android.internal.app.AssistUtils;
 import com.android.internal.os.BackgroundThread;
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.tv.RecentsTvImpl;
+import com.android.systemui.recents.model.ThumbnailData;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -80,12 +88,6 @@
 import java.util.List;
 import java.util.Random;
 
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
-
 /**
  * Acts as a shim around the real system services that we need to access data from, and provides
  * a point of injection when testing UI.
@@ -94,16 +96,23 @@
     final static String TAG = "SystemServicesProxy";
 
     final static BitmapFactory.Options sBitmapOptions;
-
     static {
         sBitmapOptions = new BitmapFactory.Options();
         sBitmapOptions.inMutable = true;
     }
 
+    final static List<String> sRecentsBlacklist;
+    static {
+        sRecentsBlacklist = new ArrayList<>();
+        sRecentsBlacklist.add("com.android.systemui.tv.pip.PipOnboardingActivity");
+        sRecentsBlacklist.add("com.android.systemui.tv.pip.PipMenuActivity");
+    }
+
+    private static SystemServicesProxy sSystemServicesProxy;
+
     AccessibilityManager mAccm;
     ActivityManager mAm;
     IActivityManager mIam;
-    AppWidgetManager mAwm;
     PackageManager mPm;
     IPackageManager mIpm;
     AssistUtils mAssistUtils;
@@ -122,12 +131,69 @@
     Paint mBgProtectionPaint;
     Canvas mBgProtectionCanvas;
 
+    private final Handler mHandler = new H();
+
+    /**
+     * An abstract class to track task stack changes.
+     * Classes should implement this instead of {@link android.app.ITaskStackListener}
+     * to reduce IPC calls from system services. These callbacks will be called on the main thread.
+     */
+    public abstract static class TaskStackListener {
+        public void onTaskStackChanged() { }
+        public void onActivityPinned() { }
+        public void onPinnedActivityRestartAttempt() { }
+        public void onPinnedStackAnimationEnded() { }
+        public void onActivityForcedResizable(String packageName, int taskId) { }
+    }
+
+    /**
+     * Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from
+     * ActivityManagerNative.
+     * This simply passes callbacks to listeners through {@link H}.
+     * */
+    private ITaskStackListener.Stub mTaskStackListener = new ITaskStackListener.Stub() {
+        @Override
+        public void onTaskStackChanged() throws RemoteException {
+            mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
+            mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
+        }
+
+        @Override
+        public void onActivityPinned() throws RemoteException {
+            mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
+            mHandler.sendEmptyMessage(H.ON_ACTIVITY_PINNED);
+        }
+
+        @Override
+        public void onPinnedActivityRestartAttempt() throws RemoteException{
+            mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
+            mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
+        }
+
+        @Override
+        public void onPinnedStackAnimationEnded() throws RemoteException {
+            mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
+            mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
+        }
+
+        @Override
+        public void onActivityForcedResizable(String packageName, int taskId)
+                throws RemoteException {
+            mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, 0, packageName)
+                    .sendToTarget();
+        }
+    };
+
+    /**
+     * List of {@link TaskStackListener} registered from {@link #registerTaskStackListener}.
+     */
+    private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
+
     /** Private constructor */
-    public SystemServicesProxy(Context context) {
+    private SystemServicesProxy(Context context) {
         mAccm = AccessibilityManager.getInstance(context);
         mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         mIam = ActivityManagerNative.getDefault();
-        mAwm = AppWidgetManager.getInstance(context);
         mPm = context.getPackageManager();
         mIpm = AppGlobals.getPackageManager();
         mAssistUtils = new AssistUtils(context);
@@ -164,6 +230,20 @@
         }
     }
 
+    /**
+     * Returns the single instance of the {@link SystemServicesProxy}.
+     * This should only be called on the main thread.
+     */
+    public static SystemServicesProxy getInstance(Context context) {
+        if (!Looper.getMainLooper().isCurrentThread()) {
+            throw new RuntimeException("Must be called on the UI thread");
+        }
+        if (sSystemServicesProxy == null) {
+            sSystemServicesProxy = new SystemServicesProxy(context);
+        }
+        return sSystemServicesProxy;
+    }
+
     /** Returns a list of the recents tasks */
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
             boolean isTopTaskHome, ArraySet<Integer> quietProfileIds) {
@@ -206,7 +286,7 @@
         int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
         List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
                 ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
-                ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS |
+                ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK |
                 ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
                 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
                 ActivityManager.RECENT_INCLUDE_PROFILES |
@@ -227,12 +307,13 @@
 
             // Check the first non-recents task, include this task even if it is marked as excluded
             // from recents if we are currently in the app.  In other words, only remove excluded
-            // tasks if it is not the first active task.
+            // tasks if it is not the first active task, and not in the blacklist.
             boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                     == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+            boolean isBlackListed = sRecentsBlacklist.contains(t.realActivity.getClassName());
             // Filter out recent tasks from managed profiles which are in quiet mode.
             isExcluded |= quietProfileIds.contains(t.userId);
-            if (isExcluded && (isTopTaskHome || !isFirstValidTask)) {
+            if (isBlackListed || (isExcluded && (isTopTaskHome || !isFirstValidTask))) {
                 iter.remove();
                 continue;
             }
@@ -280,7 +361,7 @@
             // Check if the front most activity is recents
             if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
                     (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
-                    topActivity.getClassName().equals(RecentsImpl.RECENTS_TV_ACTIVITY)))) {
+                    topActivity.getClassName().equals(RecentsTvImpl.RECENTS_TV_ACTIVITY)))) {
                 if (isHomeTopMost != null) {
                     isHomeTopMost.value = false;
                 }
@@ -322,13 +403,12 @@
     }
 
     /** Docks a task to the side of the screen and starts it. */
-    public void startTaskInDockedMode(Context context, View view, int taskId, int createMode) {
+    public void startTaskInDockedMode(int taskId, int createMode) {
         if (mIam == null) return;
 
         try {
             // TODO: Determine what animation we want for the incoming task
-            final ActivityOptions options = ActivityOptions.makeThumbnailAspectScaleUpAnimation(
-                    view, null, 0, 0, view.getWidth(), view.getHeight(), null, null);
+            final ActivityOptions options = ActivityOptions.makeBasic();
             options.setDockCreateMode(createMode);
             options.setLaunchStackId(DOCKED_STACK_ID);
             mIam.startActivityFromRecents(taskId, options.toBundle());
@@ -338,15 +418,18 @@
     }
 
     /** Docks an already resumed task to the side of the screen. */
-    public void moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
-        if (mIam == null) return;
+    public boolean moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
+        if (mIam == null) {
+            return false;
+        }
 
         try {
-            mIam.moveTaskToDockedStack(taskId, createMode, true /* onTop */, false /* animate */,
-                    initialBounds);
+            return mIam.moveTaskToDockedStack(
+                    taskId, createMode, true /* onTop */, false /* animate */, initialBounds);
         } catch (RemoteException e) {
             e.printStackTrace();
         }
+        return false;
     }
 
     /** Returns the focused stack id. */
@@ -440,44 +523,47 @@
     }
 
     /** Returns the top task thumbnail for the given task id */
-    public Bitmap getTaskThumbnail(int taskId) {
+    public ThumbnailData getTaskThumbnail(int taskId) {
         if (mAm == null) return null;
+        ThumbnailData thumbnailData = new ThumbnailData();
 
         // If we are mocking, then just return a dummy thumbnail
         if (RecentsDebugFlags.Static.EnableMockTasks) {
-            Bitmap thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, mDummyThumbnailHeight,
-                    Bitmap.Config.ARGB_8888);
-            thumbnail.eraseColor(0xff333333);
-            return thumbnail;
+            thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth,
+                    mDummyThumbnailHeight, Bitmap.Config.ARGB_8888);
+            thumbnailData.thumbnail.eraseColor(0xff333333);
+            return thumbnailData;
         }
 
-        Bitmap thumbnail = getThumbnail(taskId);
-        if (thumbnail != null) {
-            thumbnail.setHasAlpha(false);
+        getThumbnail(taskId, thumbnailData);
+        if (thumbnailData.thumbnail != null) {
+            thumbnailData.thumbnail.setHasAlpha(false);
             // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
             // left pixel, then assume the whole thumbnail is transparent. Generally, proper
             // screenshots are always composed onto a bitmap that has no alpha.
-            if (Color.alpha(thumbnail.getPixel(0, 0)) == 0) {
-                mBgProtectionCanvas.setBitmap(thumbnail);
-                mBgProtectionCanvas.drawRect(0, 0, thumbnail.getWidth(), thumbnail.getHeight(),
-                        mBgProtectionPaint);
+            if (Color.alpha(thumbnailData.thumbnail.getPixel(0, 0)) == 0) {
+                mBgProtectionCanvas.setBitmap(thumbnailData.thumbnail);
+                mBgProtectionCanvas.drawRect(0, 0, thumbnailData.thumbnail.getWidth(),
+                        thumbnailData.thumbnail.getHeight(), mBgProtectionPaint);
                 mBgProtectionCanvas.setBitmap(null);
                 Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()");
             }
         }
-        return thumbnail;
+        return thumbnailData;
     }
 
     /**
      * Returns a task thumbnail from the activity manager
      */
-    public Bitmap getThumbnail(int taskId) {
+    public void getThumbnail(int taskId, ThumbnailData thumbnailDataOut) {
         if (mAm == null) {
-            return null;
+            return;
         }
 
         ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
-        if (taskThumbnail == null) return null;
+        if (taskThumbnail == null) {
+            return;
+        }
 
         Bitmap thumbnail = taskThumbnail.mainThumbnail;
         ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
@@ -491,7 +577,8 @@
             } catch (IOException e) {
             }
         }
-        return thumbnail;
+        thumbnailDataOut.thumbnail = thumbnail;
+        thumbnailDataOut.thumbnailInfo = taskThumbnail.thumbnailInfo;
     }
 
     /**
@@ -692,6 +779,37 @@
     }
 
     /**
+     * Returns a banner used on TV for the specified Activity.
+     */
+    public Drawable getActivityBanner(ActivityInfo info) {
+        if (mPm == null) return null;
+
+        // If we are mocking, then return a mock banner
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return new ColorDrawable(0xFF666666);
+        }
+
+        Drawable banner = info.loadBanner(mPm);
+        return banner;
+    }
+
+    /**
+     * Returns a logo used on TV for the specified Activity.
+     */
+    public Drawable getActivityLogo(ActivityInfo info) {
+        if (mPm == null) return null;
+
+        // If we are mocking, then return a mock logo
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return new ColorDrawable(0xFF666666);
+        }
+
+        Drawable logo = info.loadLogo(mPm);
+        return logo;
+    }
+
+
+    /**
      * Returns the given label for a user, badging if necessary.
      */
     private String getBadgedLabel(String label, int userId) {
@@ -744,89 +862,6 @@
     }
 
     /**
-     * Returns the current search widget id.
-     */
-    public int getSearchAppWidgetId(Context context) {
-        return Prefs.getInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, -1);
-    }
-
-    /**
-     * Returns the current search widget info, binding a new one if necessary.
-     */
-    public AppWidgetProviderInfo getOrBindSearchAppWidget(Context context, AppWidgetHost host) {
-        int searchWidgetId = Prefs.getInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, -1);
-        AppWidgetProviderInfo searchWidgetInfo = mAwm.getAppWidgetInfo(searchWidgetId);
-        AppWidgetProviderInfo resolvedSearchWidgetInfo = resolveSearchAppWidget();
-
-        // Return the search widget info if it hasn't changed
-        if (searchWidgetInfo != null && resolvedSearchWidgetInfo != null &&
-                searchWidgetInfo.provider.equals(resolvedSearchWidgetInfo.provider)) {
-            if (Prefs.getString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null) == null) {
-                Prefs.putString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE,
-                        searchWidgetInfo.provider.getPackageName());
-            }
-            return searchWidgetInfo;
-        }
-
-        // Delete the old widget
-        if (searchWidgetId != -1) {
-            host.deleteAppWidgetId(searchWidgetId);
-        }
-
-        // And rebind a new search widget
-        if (resolvedSearchWidgetInfo != null) {
-            Pair<Integer, AppWidgetProviderInfo> widgetInfo = bindSearchAppWidget(host,
-                    resolvedSearchWidgetInfo);
-            if (widgetInfo != null) {
-                Prefs.putInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, widgetInfo.first);
-                Prefs.putString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE,
-                        widgetInfo.second.provider.getPackageName());
-                return widgetInfo.second;
-            }
-        }
-
-        // If we fall through here, then there is no resolved search widget, so clear the state
-        Prefs.remove(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID);
-        Prefs.remove(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE);
-        return null;
-    }
-
-    /**
-     * Returns the first Recents widget from the same package as the global assist activity.
-     */
-    public AppWidgetProviderInfo resolveSearchAppWidget() {
-        if (mAssistComponent == null) return null;
-        List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
-                AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
-        for (AppWidgetProviderInfo info : widgets) {
-            if (info.provider.getPackageName().equals(mAssistComponent.getPackageName())) {
-                return info;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Resolves and binds the search app widget that is to appear in the recents.
-     */
-    private Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host,
-            AppWidgetProviderInfo resolvedSearchWidgetInfo) {
-        if (mAwm == null) return null;
-        if (mAssistComponent == 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_SEARCHBOX);
-        if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, resolvedSearchWidgetInfo.provider, opts)) {
-            host.deleteAppWidgetId(searchWidgetId);
-            return null;
-        }
-        return new Pair<>(searchWidgetId, resolvedSearchWidgetInfo);
-    }
-
-    /**
      * Returns whether touch exploration is currently enabled.
      */
     public boolean isTouchExplorationEnabled() {
@@ -875,28 +910,40 @@
      * Returns the smallest width/height.
      */
     public int getDeviceSmallestWidth() {
-        if (mWm == null) return 0;
+        if (mDisplay == null) return 0;
 
         Point smallestSizeRange = new Point();
         Point largestSizeRange = new Point();
-        mWm.getDefaultDisplay().getCurrentSizeRange(smallestSizeRange, largestSizeRange);
+        mDisplay.getCurrentSizeRange(smallestSizeRange, largestSizeRange);
         return smallestSizeRange.x;
     }
 
     /**
-     * Returns the display rect.
+     * Returns the current display rect in the current display orientation.
      */
     public Rect getDisplayRect() {
         Rect displayRect = new Rect();
-        if (mWm == null) return displayRect;
+        if (mDisplay == null) return displayRect;
 
         Point p = new Point();
-        mWm.getDefaultDisplay().getRealSize(p);
+        mDisplay.getRealSize(p);
         displayRect.set(0, 0, p.x, p.y);
         return displayRect;
     }
 
     /**
+     * Returns the current display orientation.
+     */
+    public int getDisplayOrientation() {
+        // Because of multi-window, the configuration orientation does not necessarily reflect the
+        // orientation of the display, instead we just use the display's real-size.
+        Rect displayRect = getDisplayRect();
+        return displayRect.width() > displayRect.height()
+                ? Configuration.ORIENTATION_LANDSCAPE
+                : Configuration.ORIENTATION_PORTRAIT;
+    }
+
+    /**
      * Returns the window rect for the RecentsActivity, based on the dimensions of the home stack.
      */
     public Rect getWindowRect() {
@@ -917,11 +964,20 @@
     }
 
     /** Starts an activity from recents. */
-    public boolean startActivityFromRecents(Context context, int taskId, String taskName,
+    public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
             ActivityOptions options) {
         if (mIam != null) {
             try {
-                mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
+                if (taskKey.stackId == DOCKED_STACK_ID) {
+                    // We show non-visible docked tasks in Recents, but we always want to launch
+                    // them in the fullscreen stack.
+                    if (options == null) {
+                        options = ActivityOptions.makeBasic();
+                    }
+                    options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
+                }
+                mIam.startActivityFromRecents(
+                        taskKey.id, options == null ? null : options.toBundle());
                 return true;
             } catch (Exception e) {
                 Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
@@ -941,14 +997,21 @@
         }
     }
 
-    /** Registers a task stack listener with the system. */
-    public void registerTaskStackListener(ITaskStackListener listener) {
+    /**
+     * Registers a task stack listener with the system.
+     * This should be called on the main thread.
+     */
+    public void registerTaskStackListener(TaskStackListener listener) {
         if (mIam == null) return;
 
-        try {
-            mIam.registerTaskStackListener(listener);
-        } catch (Exception e) {
-            e.printStackTrace();
+        mTaskStackListeners.add(listener);
+        if (mTaskStackListeners.size() == 1) {
+            // Register mTaskStackListener to IActivityManager only once if needed.
+            try {
+                mIam.registerTaskStackListener(mTaskStackListener);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to call registerTaskStackListener", e);
+            }
         }
     }
 
@@ -985,8 +1048,9 @@
         return dividerWindowWidth - 2 * dividerInsets;
     }
 
-    public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
-        mWm.requestAppKeyboardShortcuts(receiver);
+    public void requestKeyboardShortcuts(
+            Context context, KeyboardShortcutsReceiver receiver, int deviceId) {
+        mWm.requestAppKeyboardShortcuts(receiver, deviceId);
     }
 
     public void getStableInsets(Rect outStableInsets) {
@@ -998,20 +1062,71 @@
             e.printStackTrace();
         }
     }
-    
-    public void focusPinnedStack() {
+
+    public void overridePendingAppTransitionMultiThumbFuture(
+            IAppTransitionAnimationSpecsFuture future, IRemoteCallback animStartedListener,
+            boolean scaleUp) {
         try {
-            mIam.setFocusedStack(PINNED_STACK_ID);
+            WindowManagerGlobal.getWindowManagerService()
+                    .overridePendingAppTransitionMultiThumbFuture(future, animStartedListener,
+                            scaleUp);
         } catch (RemoteException e) {
-            e.printStackTrace();
+            Log.w(TAG, "Failed to override transition: " + e);
         }
     }
 
-    public void focusHomeStack() {
-        try {
-            mIam.setFocusedStack(HOME_STACK_ID);
-        } catch (RemoteException e) {
-            e.printStackTrace();
+    /**
+     * Returns whether the device has a transposed nav bar (on the right of the screen) in the
+     * current display orientation.
+     */
+    public boolean hasTransposedNavBar() {
+        Rect insets = new Rect();
+        getStableInsets(insets);
+        return insets.right > 0;
+    }
+
+    private final class H extends Handler {
+        private static final int ON_TASK_STACK_CHANGED = 1;
+        private static final int ON_ACTIVITY_PINNED = 2;
+        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3;
+        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;
+        private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case ON_TASK_STACK_CHANGED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskStackChanged();
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_PINNED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityPinned();
+                    }
+                    break;
+                }
+                case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
+                    }
+                    break;
+                }
+                case ON_PINNED_STACK_ANIMATION_ENDED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_FORCED_RESIZABLE: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityForcedResizable(
+                                (String) msg.obj, msg.arg1);
+                    }
+                    break;
+                }
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index e86b92d..e28612a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.annotation.FloatRange;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -26,6 +27,7 @@
 import android.util.ArraySet;
 import android.util.IntProperty;
 import android.util.Property;
+import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewParent;
 
@@ -67,6 +69,8 @@
 
     public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
 
+    public static final Rect EMPTY_RECT = new Rect();
+
     /**
      * @return the first parent walking up the view hierarchy that has the given class type.
      *
@@ -196,7 +200,7 @@
      * are not called.
      */
     public static void cancelAnimationWithoutCallbacks(Animator animator) {
-        if (animator != null) {
+        if (animator != null && animator.isStarted()) {
             removeAnimationListenersRecursive(animator);
             animator.cancel();
         }
@@ -232,4 +236,11 @@
             transforms.subList(taskCount, taskTransformCount).clear();
         }
     }
+
+    /**
+     * Used for debugging, converts DP to PX.
+     */
+    public static float dpToPx(Resources res, float dp) {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 824231a..7aeff1f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -39,7 +39,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Formatter;
 import java.util.List;
 
 
@@ -133,7 +132,8 @@
         SparseIntArray affiliatedTaskCounts = new SparseIntArray();
         String dismissDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_will_be_dismissed);
-        Formatter dismissDescFormatter = new Formatter();
+        String appInfoDescFormat = mContext.getString(
+                R.string.accessibility_recents_item_open_app_info);
         long lastStackActiveTime = Prefs.getLong(mContext,
                 Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
         if (RecentsDebugFlags.Static.EnableMockTasks) {
@@ -162,8 +162,15 @@
                 long parentTaskLastActiveTime = parentTask != null
                         ? parentTask.lastActiveTime
                         : prevLastActiveTime;
-                t.lastActiveTime = parentTaskLastActiveTime +
-                        affiliatedTaskCounts.get(t.affiliatedTaskId, 0) + 1;
+                if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
+                    t.lastActiveTime = parentTaskLastActiveTime +
+                            affiliatedTaskCounts.get(t.affiliatedTaskId, 0) + 1;
+                } else {
+                    if (t.lastActiveTime == 0) {
+                        t.lastActiveTime = parentTaskLastActiveTime -
+                                affiliatedTaskCounts.get(t.affiliatedTaskId, 0) - 1;
+                    }
+                }
             }
 
             // Compose the task key
@@ -183,9 +190,9 @@
             // Load the title, icon, and color
             ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
             String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
-            String contentDescription = loader.getAndUpdateContentDescription(taskKey, res);
-            String dismissDescription = dismissDescFormatter.format(dismissDescFormat,
-                    contentDescription).toString();
+            String titleDescription = loader.getAndUpdateContentDescription(taskKey, res);
+            String dismissDescription = String.format(dismissDescFormat, titleDescription);
+            String appInfoDescription = String.format(appInfoDescFormat, titleDescription);
             Drawable icon = isStackTask
                     ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                     : null;
@@ -197,14 +204,13 @@
 
             // Add the task to the stack
             Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
-                    thumbnail, title, contentDescription, dismissDescription, activityColor,
-                    backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.bounds,
-                    t.taskDescription);
+                    thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
+                    activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
+                    t.isDockable, t.bounds, t.taskDescription);
 
             allTasks.add(task);
             affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
             affiliatedTasks.put(taskKey.id, taskKey);
-
             prevLastActiveTime = t.lastActiveTime;
         }
         if (newLastStackActiveTime != -1) {
@@ -214,8 +220,7 @@
 
         // Initialize the stacks
         mStack = new TaskStack();
-        mStack.setTasks(allTasks, false /* notifyStackChanges */);
-        mStack.createAffiliatedGroupings(mContext);
+        mStack.setTasks(mContext, allTasks, false /* notifyStackChanges */);
     }
 
     /**
@@ -244,8 +249,8 @@
 
             if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
                 if (task.icon == null) {
-                    task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription,
-                            res, true);
+                    task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription, res,
+                            true);
                 }
             }
             if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
@@ -276,7 +281,7 @@
     }
 
     /**
-     * Returns whether this task is considered a task to be shown in the history.
+     * Returns whether this task is too old to be shown.
      */
     private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) {
         return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 5e1af12..82c81ae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -95,7 +95,7 @@
 
     TaskResourceLoadQueue mLoadQueue;
     TaskKeyLruCache<Drawable> mIconCache;
-    TaskKeyLruCache<Bitmap> mThumbnailCache;
+    TaskKeyLruCache<ThumbnailData> mThumbnailCache;
     Bitmap mDefaultThumbnail;
     BitmapDrawable mDefaultIcon;
 
@@ -104,7 +104,7 @@
 
     /** Constructor, creates a new loading thread that loads task resources in the background */
     public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
-            TaskKeyLruCache<Drawable> iconCache, TaskKeyLruCache<Bitmap> thumbnailCache,
+            TaskKeyLruCache<Drawable> iconCache, TaskKeyLruCache<ThumbnailData> thumbnailCache,
             Bitmap defaultThumbnail, BitmapDrawable defaultIcon) {
         mLoadQueue = loadQueue;
         mIconCache = iconCache;
@@ -165,7 +165,7 @@
                     final Task t = mLoadQueue.nextTask();
                     if (t != null) {
                         Drawable cachedIcon = mIconCache.get(t.key);
-                        Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
+                        ThumbnailData cachedThumbnailData = mThumbnailCache.get(t.key);
 
                         // Load the icon if it is stale or we haven't cached one yet
                         if (cachedIcon == null) {
@@ -190,30 +190,32 @@
                             mIconCache.put(t.key, cachedIcon);
                         }
                         // Load the thumbnail if it is stale or we haven't cached one yet
-                        if (cachedThumbnail == null) {
+                        if (cachedThumbnailData == null) {
                             if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
                                 if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
-                                cachedThumbnail = ssp.getTaskThumbnail(t.key.id);
+                                cachedThumbnailData = ssp.getTaskThumbnail(t.key.id);
                             }
-                            if (cachedThumbnail == null) {
-                                cachedThumbnail = mDefaultThumbnail;
+
+                            if (cachedThumbnailData.thumbnail == null) {
+                                cachedThumbnailData.thumbnail = mDefaultThumbnail;
                             }
+
                             // When svelte, we trim the memory to just the visible thumbnails when
                             // leaving, so don't thrash the cache as the user scrolls (just load
                             // them from scratch each time)
                             if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) {
-                                mThumbnailCache.put(t.key, cachedThumbnail);
+                                mThumbnailCache.put(t.key, cachedThumbnailData);
                             }
                         }
                         if (!mCancelled) {
                             // Notify that the task data has changed
                             final Drawable newIcon = cachedIcon;
-                            final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail
-                                    ? null : cachedThumbnail;
+                            final ThumbnailData newThumbnailData = cachedThumbnailData;
                             mMainThreadHandler.post(new Runnable() {
                                 @Override
                                 public void run() {
-                                    t.notifyTaskDataLoaded(newThumbnail, newIcon);
+                                    t.notifyTaskDataLoaded(newThumbnailData.thumbnail, newIcon,
+                                            newThumbnailData.thumbnailInfo);
                                 }
                             });
                         }
@@ -252,7 +254,7 @@
     // package in the cache has been updated, so that we may remove it.
     private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
     private final TaskKeyLruCache<Drawable> mIconCache;
-    private final TaskKeyLruCache<Bitmap> mThumbnailCache;
+    private final TaskKeyLruCache<ThumbnailData> mThumbnailCache;
     private final TaskKeyLruCache<String> mActivityLabelCache;
     private final TaskKeyLruCache<String> mContentDescriptionCache;
     private final TaskResourceLoadQueue mLoadQueue;
@@ -268,6 +270,16 @@
     BitmapDrawable mDefaultIcon;
     Bitmap mDefaultThumbnail;
 
+    private TaskKeyLruCache.EvictionCallback mClearActivityInfoOnEviction =
+            new TaskKeyLruCache.EvictionCallback() {
+        @Override
+        public void onEntryEvicted(Task.TaskKey key) {
+            if (key != null) {
+                mActivityInfoCache.remove(key.getComponent());
+            }
+        }
+    };
+
     public RecentsTaskLoader(Context context) {
         Resources res = context.getResources();
         mDefaultTaskBarBackgroundColor =
@@ -292,10 +304,11 @@
         // Initialize the proxy, cache and loaders
         int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
         mLoadQueue = new TaskResourceLoadQueue();
-        mIconCache = new TaskKeyLruCache<>(iconCacheSize);
+        mIconCache = new TaskKeyLruCache<>(iconCacheSize, mClearActivityInfoOnEviction);
         mThumbnailCache = new TaskKeyLruCache<>(thumbnailCacheSize);
-        mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks);
-        mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks);
+        mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
+        mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
+                mClearActivityInfoOnEviction);
         mActivityInfoCache = new LruCache(numRecentTasks);
         mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mThumbnailCache,
                 mDefaultThumbnail, mDefaultIcon);
@@ -347,9 +360,16 @@
      */
     public void loadTaskData(Task t, boolean fetchAndInvalidateThumbnails) {
         Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
-        Bitmap thumbnail = mDefaultThumbnail;
+        Bitmap thumbnail = null;
+        ActivityManager.TaskThumbnailInfo thumbnailInfo = null;
         if (fetchAndInvalidateThumbnails) {
-            thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+            ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(t.key);
+            if (thumbnailData != null) {
+                thumbnail = thumbnailData.thumbnail;
+                thumbnailInfo = thumbnailData.thumbnailInfo;
+            }
+        } else {
+            thumbnail = mDefaultThumbnail;
         }
 
         // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
@@ -359,7 +379,8 @@
         if (requiresLoad) {
             mLoadQueue.addTask(t);
         }
-        t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon);
+        t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon,
+                thumbnailInfo);
     }
 
     /** Releases the task resource data back into the pool. */
@@ -375,7 +396,6 @@
         mIconCache.remove(t.key);
         mActivityLabelCache.remove(t.key);
         mContentDescriptionCache.remove(t.key);
-        mActivityInfoCache.remove(t.key.getComponent());
         if (notifyTaskDataUnloaded) {
             t.notifyTaskDataUnloaded(null, mDefaultIcon);
         }
@@ -527,19 +547,19 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the cached thumbnail if it exists
-        Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
-        if (thumbnail != null) {
-            return thumbnail;
+        ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(taskKey);
+        if (thumbnailData != null) {
+            return thumbnailData.thumbnail;
         }
 
         if (loadIfNotCached) {
             RecentsConfiguration config = Recents.getConfiguration();
             if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
                 // Load the thumbnail from the system
-                thumbnail = ssp.getTaskThumbnail(taskKey.id);
-                if (thumbnail != null) {
-                    mThumbnailCache.put(taskKey, thumbnail);
-                    return thumbnail;
+                thumbnailData = ssp.getTaskThumbnail(taskKey.id);
+                if (thumbnailData.thumbnail != null) {
+                    mThumbnailCache.put(taskKey, thumbnailData);
+                    return thumbnailData.thumbnail;
                 }
             }
         }
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 8ed6dd7..6668079 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -40,7 +40,7 @@
     /* Task callbacks */
     public interface TaskCallbacks {
         /* Notifies when a task has been bound */
-        public void onTaskDataLoaded(Task task);
+        public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo);
         /* Notifies when a task has been unbound */
         public void onTaskDataUnloaded();
         /* Notifies when a task's stack id has changed. */
@@ -100,11 +100,7 @@
 
         @Override
         public String toString() {
-            return "Task.Key: " + id + ", "
-                    + "s: " + stackId + ", "
-                    + "u: " + userId + ", "
-                    + "lat: " + lastActiveTime + ", "
-                    + getComponent().getPackageName();
+            return "t" + id + ", s" + stackId + ", u" + userId;
         }
 
         private void updateHashCode() {
@@ -138,10 +134,12 @@
     @ViewDebug.ExportedProperty(category="recents")
     public String title;
     @ViewDebug.ExportedProperty(category="recents")
-    public String contentDescription;
+    public String titleDescription;
     @ViewDebug.ExportedProperty(category="recents")
     public String dismissDescription;
     @ViewDebug.ExportedProperty(category="recents")
+    public String appInfoDescription;
+    @ViewDebug.ExportedProperty(category="recents")
     public int colorPrimary;
     @ViewDebug.ExportedProperty(category="recents")
     public int colorBackground;
@@ -165,9 +163,11 @@
     @ViewDebug.ExportedProperty(category="recents")
     public boolean isLaunchTarget;
     @ViewDebug.ExportedProperty(category="recents")
-    public boolean isHistorical;
+    public boolean isStackTask;
     @ViewDebug.ExportedProperty(category="recents")
     public boolean isSystemApp;
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isDockable;
 
     private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
 
@@ -176,10 +176,10 @@
     }
 
     public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
-                Bitmap thumbnail, String title, String contentDescription,
-                String dismissDescription, int colorPrimary, int colorBackground,
-                boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp, Rect bounds,
-                ActivityManager.TaskDescription taskDescription) {
+                Bitmap thumbnail, String title, String titleDescription, String dismissDescription,
+                String appInfoDescription, int colorPrimary, int colorBackground,
+                boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
+                boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) {
         boolean isInAffiliationGroup = (affiliationTaskId != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
         this.key = key;
@@ -188,8 +188,9 @@
         this.icon = icon;
         this.thumbnail = thumbnail;
         this.title = title;
-        this.contentDescription = contentDescription;
+        this.titleDescription = titleDescription;
         this.dismissDescription = dismissDescription;
+        this.appInfoDescription = appInfoDescription;
         this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
         this.colorBackground = colorBackground;
         this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
@@ -197,11 +198,14 @@
         this.bounds = bounds;
         this.taskDescription = taskDescription;
         this.isLaunchTarget = isLaunchTarget;
-        this.isHistorical = isHistorical;
+        this.isStackTask = isStackTask;
         this.isSystemApp = isSystemApp;
+        this.isDockable = isDockable;
     }
 
-    /** Copies the other task. */
+    /**
+     * Copies the metadata from another task, but retains the current callbacks.
+     */
     public void copyFrom(Task o) {
         this.key = o.key;
         this.group = o.group;
@@ -210,15 +214,18 @@
         this.icon = o.icon;
         this.thumbnail = o.thumbnail;
         this.title = o.title;
-        this.contentDescription = o.contentDescription;
+        this.titleDescription = o.titleDescription;
         this.dismissDescription = o.dismissDescription;
+        this.appInfoDescription = o.appInfoDescription;
         this.colorPrimary = o.colorPrimary;
         this.colorBackground = o.colorBackground;
         this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
         this.bounds = o.bounds;
+        this.taskDescription = o.taskDescription;
         this.isLaunchTarget = o.isLaunchTarget;
-        this.isHistorical = o.isHistorical;
+        this.isStackTask = o.isStackTask;
         this.isSystemApp = o.isSystemApp;
+        this.isDockable = o.isDockable;
     }
 
     /**
@@ -262,12 +269,13 @@
     }
 
     /** Notifies the callback listeners that this task has been loaded */
-    public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
+    public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon,
+            ActivityManager.TaskThumbnailInfo thumbnailInfo) {
         this.icon = applicationIcon;
         this.thumbnail = thumbnail;
         int callbackCount = mCallbacks.size();
         for (int i = 0; i < callbackCount; i++) {
-            mCallbacks.get(i).onTaskDataLoaded(this);
+            mCallbacks.get(i).onTaskDataLoaded(this, thumbnailInfo);
         }
     }
 
@@ -296,11 +304,6 @@
 
     @Override
     public String toString() {
-        String groupAffiliation = "no group";
-        if (group != null) {
-            groupAffiliation = Integer.toString(group.affiliation);
-        }
-        return "Task (" + groupAffiliation + "): " + key +
-                " [" + super.toString() + "]";
+        return "[" + key.toString() + "] " + title;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
index d433b6c..748d8ed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
@@ -30,16 +30,29 @@
  */
 public class TaskKeyLruCache<V> {
 
+    public interface EvictionCallback {
+        public void onEntryEvicted(Task.TaskKey key);
+    }
+
     private static final String TAG = "TaskKeyLruCache";
 
     private final SparseArray<Task.TaskKey> mKeys = new SparseArray<>();
     private final LruCache<Integer, V> mCache;
+    private final EvictionCallback mEvictionCallback;
 
     public TaskKeyLruCache(int cacheSize) {
+        this(cacheSize, null);
+    }
+
+    public TaskKeyLruCache(int cacheSize, EvictionCallback evictionCallback) {
+        mEvictionCallback = evictionCallback;
         mCache = new LruCache<Integer, V>(cacheSize) {
 
             @Override
             protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
+                if (mEvictionCallback != null) {
+                    mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
+                }
                 mKeys.remove(taskId);
             }
         };
@@ -84,8 +97,9 @@
 
     /** Removes a cache entry for a specific key. */
     final void remove(Task.TaskKey key) {
-        mKeys.remove(key.id);
+        // Remove the key after the cache value because we need it to make the callback
         mCache.remove(key.id);
+        mKeys.remove(key.id);
     }
 
     /** Removes all the entries in the cache. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 1f91dce..df3f56c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -16,6 +16,16 @@
 
 package com.android.systemui.recents.model;
 
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
@@ -37,13 +47,13 @@
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.misc.NamedCounter;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.views.DropTarget;
 import com.android.systemui.recents.views.AnimationProps;
+import com.android.systemui.recents.views.DropTarget;
+import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -51,16 +61,6 @@
 import java.util.List;
 import java.util.Random;
 
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-
 
 /**
  * An interface for a task filter to query whether a particular task should show in a stack.
@@ -92,15 +92,6 @@
         }
     }
 
-    /**
-     * Resets the task list, but does not remove the filter.
-     */
-    void reset() {
-        mTasks.clear();
-        mFilteredTasks.clear();
-        mTaskIndices.clear();
-    }
-
     /** Removes the task filter and returns the previous touch state */
     void removeFilter() {
         mFilter = null;
@@ -228,12 +219,17 @@
          * Notifies when a task has been removed from the stack.
          */
         void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
-            Task newFrontMostTask, AnimationProps animation);
+            Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture);
 
         /**
-         * Notifies when a task has been removed from the history.
+         * Notifies when all tasks have been removed from the stack.
          */
-        void onHistoryTaskRemoved(TaskStack stack, Task removedTask, AnimationProps animation);
+        void onStackTasksRemoved(TaskStack stack);
+
+        /**
+         * Notifies when tasks in the stack have been updated.
+         */
+        void onStackTasksUpdated(TaskStack stack);
     }
 
     /**
@@ -384,29 +380,24 @@
          * {@param height}.
          */
         public Rect getDockedTaskStackBounds(int width, int height, int dividerSize, Rect insets,
-                Resources res) {
-            RecentsConfiguration config = Recents.getConfiguration();
-
+                TaskStackLayoutAlgorithm layoutAlgorithm, Resources res, Rect windowRectOut) {
             // Calculate the inverse docked task bounds
             boolean isHorizontalDivision =
                     res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
             int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
                     insets, width, height, dividerSize);
-            Rect newWindowBounds = new Rect();
             DockedDividerUtils.calculateBoundsForPosition(position,
-                    DockedDividerUtils.invertDockSide(dockSide), newWindowBounds, width, height,
+                    DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height,
                     dividerSize);
 
             // Calculate the task stack bounds from the new window bounds
-            Rect searchBarSpaceBounds = new Rect();
             Rect taskStackBounds = new Rect();
             // If the task stack bounds is specifically under the dock area, then ignore the top
             // inset
             int top = dockArea.bottom < 1f
                     ? 0
                     : insets.top;
-            config.getTaskStackBounds(newWindowBounds, top, insets.right,
-                    searchBarSpaceBounds, taskStackBounds);
+            layoutAlgorithm.getTaskStackBounds(windowRectOut, top, insets.right, taskStackBounds);
             return taskStackBounds;
         }
     }
@@ -438,7 +429,6 @@
 
     ArrayList<Task> mRawTaskList = new ArrayList<>();
     FilteredTaskList mStackTaskList = new FilteredTaskList();
-    FilteredTaskList mHistoryTaskList = new FilteredTaskList();
     TaskStackCallbacks mCb;
 
     ArrayList<TaskGrouping> mGroups = new ArrayList<>();
@@ -449,29 +439,17 @@
         mStackTaskList.setFilter(new TaskFilter() {
             @Override
             public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
-                if (t.isAffiliatedTask()) {
-                    // If this task is affiliated with another parent in the stack, then the
-                    // historical state of this task depends on the state of the parent task
-                    Task parentTask = taskIdMap.get(t.affiliationTaskId);
-                    if (parentTask != null) {
-                        t = parentTask;
+                if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
+                    if (t.isAffiliatedTask()) {
+                        // If this task is affiliated with another parent in the stack, then the
+                        // historical state of this task depends on the state of the parent task
+                        Task parentTask = taskIdMap.get(t.affiliationTaskId);
+                        if (parentTask != null) {
+                            t = parentTask;
+                        }
                     }
                 }
-                return !t.isHistorical;
-            }
-        });
-        mHistoryTaskList.setFilter(new TaskFilter() {
-            @Override
-            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
-                if (t.isAffiliatedTask()) {
-                    // If this task is affiliated with another parent in the stack, then the
-                    // historical state of this task depends on the state of the parent task
-                    Task parentTask = taskIdMap.get(t.affiliationTaskId);
-                    if (parentTask != null) {
-                        t = parentTask;
-                    }
-                }
-                return t.isHistorical;
+                return t.isStackTask;
             }
         });
     }
@@ -481,15 +459,6 @@
         mCb = cb;
     }
 
-    /** Resets this TaskStack. */
-    public void reset() {
-        mCb = null;
-        mStackTaskList.reset();
-        mHistoryTaskList.reset();
-        mGroups.clear();
-        mAffinitiesGroups.clear();
-    }
-
     /**
      * Moves the given task to either the front of the freeform workspace or the stack.
      */
@@ -531,37 +500,48 @@
      * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
      * how they should update themselves.
      */
-    public void removeTask(Task t, AnimationProps animation) {
+    public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
         if (mStackTaskList.contains(t)) {
             boolean wasFrontMostTask = (getStackFrontMostTask(false /* includeFreeform */) == t);
             removeTaskImpl(mStackTaskList, t);
             Task newFrontMostTask = getStackFrontMostTask(false  /* includeFreeform */);
             if (mCb != null) {
                 // Notify that a task has been removed
-                mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask, animation);
-            }
-        } else if (mHistoryTaskList.contains(t)) {
-            removeTaskImpl(mHistoryTaskList, t);
-            if (mCb != null) {
-                // Notify that a task has been removed
-                mCb.onHistoryTaskRemoved(this, t, animation);
+                mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask, animation,
+                        fromDockGesture);
             }
         }
         mRawTaskList.remove(t);
     }
 
     /**
+     * Removes all tasks from the stack.
+     */
+    public void removeAllTasks() {
+        ArrayList<Task> tasks = mStackTaskList.getTasks();
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            Task t = tasks.get(i);
+            removeTaskImpl(mStackTaskList, t);
+            mRawTaskList.remove(t);
+        }
+        if (mCb != null) {
+            // Notify that all tasks have been removed
+            mCb.onStackTasksRemoved(this);
+        }
+    }
+
+    /**
      * Sets a few tasks in one go, without calling any callbacks.
      *
      * @param tasks the new set of tasks to replace the current set.
      * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
      */
-    public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
+    public void setTasks(Context context, List<Task> tasks, boolean notifyStackChanges) {
         // Compute a has set for each of the tasks
         ArrayMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
         ArrayMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
-
-        ArrayList<Task> newTasks = new ArrayList<>();
+        ArrayList<Task> addedTasks = new ArrayList<>();
+        ArrayList<Task> allTasks = new ArrayList<>();
 
         // Disable notifications if there are no callbacks
         if (mCb == null) {
@@ -570,12 +550,15 @@
 
         // Remove any tasks that no longer exist
         int taskCount = mRawTaskList.size();
-        for (int i = 0; i < taskCount; i++) {
+        for (int i = taskCount - 1; i >= 0; i--) {
             Task task = mRawTaskList.get(i);
             if (!newTasksMap.containsKey(task.key)) {
                 if (notifyStackChanges) {
+                    // If we are notifying, then remove the task now, otherwise the raw task list
+                    // will be reset at the end of this method
+                    removeTask(task, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
                     mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null,
-                            AnimationProps.IMMEDIATE);
+                            AnimationProps.IMMEDIATE, false /* fromDockGesture */);
                 }
             }
             task.setGroup(null);
@@ -584,39 +567,38 @@
         // Add any new tasks
         taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (!currentTasksMap.containsKey(task.key)) {
-                if (notifyStackChanges) {
-                    mCb.onStackTaskAdded(this, task);
-                }
-                newTasks.add(task);
-            } else {
-                newTasks.add(currentTasksMap.get(task.key));
+            Task newTask = tasks.get(i);
+            Task currentTask = currentTasksMap.get(newTask.key);
+            if (currentTask == null && notifyStackChanges) {
+                addedTasks.add(newTask);
+            } else if (currentTask != null) {
+                // The current task has bound callbacks, so just copy the data from the new task
+                // state and add it back into the list
+                currentTask.copyFrom(newTask);
+                newTask = currentTask;
             }
+            allTasks.add(newTask);
         }
 
         // Sort all the tasks to ensure they are ordered correctly
-        Collections.sort(newTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
+        Collections.sort(allTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
 
-        // Filter out the historical tasks from this new list
-        ArrayList<Task> stackTasks = new ArrayList<>();
-        ArrayList<Task> historyTasks = new ArrayList<>();
-        int newTaskCount = newTasks.size();
-        for (int i = 0; i < newTaskCount; i++) {
-            Task task = newTasks.get(i);
-            if (task.isHistorical) {
-                historyTasks.add(task);
-            } else {
-                stackTasks.add(task);
-            }
+        mStackTaskList.set(allTasks);
+        mRawTaskList = allTasks;
+
+        // Update the affiliated groupings
+        createAffiliatedGroupings(context);
+
+        // Only callback for the newly added tasks after this stack has been updated
+        int addedTaskCount = addedTasks.size();
+        for (int i = 0; i < addedTaskCount; i++) {
+            mCb.onStackTaskAdded(this, addedTasks.get(i));
         }
 
-        mStackTaskList.set(stackTasks);
-        mHistoryTaskList.set(historyTasks);
-        mRawTaskList.clear();
-        mRawTaskList.addAll(newTasks);
-        mGroups.clear();
-        mAffinitiesGroups.clear();
+        // Notify that the task stack has been updated
+        if (notifyStackChanges) {
+            mCb.onStackTasksUpdated(this);
+        }
     }
 
     /**
@@ -656,14 +638,6 @@
     }
 
     /**
-     * Returns the set of tasks that are inactive. These tasks will be presented in a separate
-     * history view.
-     */
-    public ArrayList<Task> getHistoricalTasks() {
-        return mHistoryTaskList.getTasks();
-    }
-
-    /**
      * Returns the set of "freeform" tasks in the stack.
      */
     public ArrayList<Task> getFreeformTasks() {
@@ -685,7 +659,6 @@
     public ArrayList<Task> computeAllTasksList() {
         ArrayList<Task> tasks = new ArrayList<>();
         tasks.addAll(mStackTaskList.getTasks());
-        tasks.addAll(mHistoryTaskList.getTasks());
         Collections.sort(tasks, LAST_ACTIVE_TIME_COMPARATOR);
         return tasks;
     }
@@ -779,9 +752,12 @@
     }
 
     /**
-     * Temporary: This method will simulate affiliation groups by
+     * Temporary: This method will simulate affiliation groups
      */
-    public void createAffiliatedGroupings(Context context) {
+    void createAffiliatedGroupings(Context context) {
+        mGroups.clear();
+        mAffinitiesGroups.clear();
+
         if (RecentsDebugFlags.Static.EnableMockTaskGroups) {
             ArrayMap<Task.TaskKey, Task> taskMap = new ArrayMap<>();
             // Sort all tasks by increasing firstActiveTime of the task
@@ -926,13 +902,9 @@
 
     @Override
     public String toString() {
-        String str = "Stack Tasks:\n";
+        String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
         for (Task t : mStackTaskList.getTasks()) {
-            str += "  " + t.toString() + "\n";
-        }
-        str += "Historical Tasks:\n";
-        for (Task t : mHistoryTaskList.getTasks()) {
-            str += "  " + t.toString() + "\n";
+            str += "    " + t.toString() + "\n";
         }
         return str;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
new file mode 100644
index 0000000..d0cdae5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.model;
+
+import android.app.ActivityManager;
+import android.graphics.Bitmap;
+
+/**
+ * Data for a single thumbnail.
+ */
+public class ThumbnailData {
+    public Bitmap thumbnail;
+    public ActivityManager.TaskThumbnailInfo thumbnailInfo;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index f3201d0..f9f851a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -18,6 +18,7 @@
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.content.Intent;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
@@ -25,6 +26,7 @@
 import android.view.View;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.view.WindowManager;
+import android.widget.FrameLayout.LayoutParams;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
@@ -38,7 +40,6 @@
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
@@ -56,8 +57,12 @@
 import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.tv.pip.PipManager;
+import com.android.systemui.tv.pip.PipRecentsOverlayManager;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * The main TV recents activity started by the RecentsImpl.
  */
@@ -73,9 +78,62 @@
     private boolean mIgnoreAltTabRelease;
 
     private RecentsTvView mRecentsView;
+    private View mPipView;
     private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
     private FinishRecentsRunnable mFinishLaunchHomeRunnable;
 
+    private final PipManager mPipManager = PipManager.getInstance();
+    private final PipManager.Listener mPipListener = new PipManager.Listener() {
+        @Override
+        public void onPipEntered() {
+            updatePipUI();
+        }
+
+        @Override
+        public void onPipActivityClosed() {
+            updatePipUI();
+        }
+
+        @Override
+        public void onShowPipMenu() {
+            updatePipUI();
+        }
+
+        @Override
+        public void onMoveToFullscreen() {
+            // Recents should be dismissed when PIP moves to fullscreen. If not, Recents will
+            // be unnecessarily shown in the scenario: PIP->Fullscreen->PIP.
+            dismissRecentsToLaunchTargetTaskOrHome();
+        }
+
+        @Override
+        public void onPipResizeAboutToStart() { }
+    };
+    private PipRecentsOverlayManager mPipRecentsOverlayManager;
+    private final PipRecentsOverlayManager.Callback mPipRecentsOverlayManagerCallback =
+            new PipRecentsOverlayManager.Callback() {
+                @Override
+                public void onClosed() {
+                    dismissRecentsToLaunchTargetTaskOrHome();
+                }
+
+                @Override
+                public void onBackPressed() {
+                    RecentsTvActivity.this.onBackPressed();
+                }
+
+                @Override
+                public void onRecentsFocused() {
+                    mRecentsView.requestFocus();
+                }
+            };
+    private final View.OnFocusChangeListener mPipViewFocusChangeListener =
+            new View.OnFocusChangeListener() {
+                @Override
+                public void onFocusChange(View v, boolean hasFocus) {
+                    handlePipViewFocusChange(hasFocus);
+                }
+            };
 
     /**
      * A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -95,15 +153,8 @@
         @Override
         public void run() {
             try {
-                RecentsActivityLaunchState launchState =
-                        Recents.getConfiguration().getLaunchState();
                 ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsTvActivity.this,
-                        launchState.launchedFromSearchHome ?
-                                R.anim.recents_to_search_launcher_enter :
-                                R.anim.recents_to_launcher_enter,
-                        launchState.launchedFromSearchHome ?
-                                R.anim.recents_to_search_launcher_exit :
-                                R.anim.recents_to_launcher_exit);
+                        R.anim.recents_to_launcher_enter, R.anim.recents_to_launcher_exit);
                 startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
             } catch (Exception e) {
                 Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
@@ -132,11 +183,13 @@
 
 
         mRecentsView.setTaskStack(stack);
+        List stackTasks = stack.getStackTasks();
+        Collections.reverse(stackTasks);
         if (mTaskStackViewAdapter == null) {
-            mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+            mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stackTasks);
             mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
         } else {
-            mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+            mTaskStackViewAdapter.setNewStackTasks(stackTasks);
         }
 
         if (launchState.launchedToTaskId != -1) {
@@ -212,6 +265,7 @@
             finish();
             return;
         }
+        mPipRecentsOverlayManager = PipManager.getInstance().getPipRecentsOverlayManager();
 
         // Register this activity with the event bus
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -227,6 +281,18 @@
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
 
+        mPipView = findViewById(R.id.pip);
+        // Place mPipView at the PIP bounds for fine tuned focus handling.
+        Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
+        LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
+        lp.width = pipBounds.width();
+        lp.height = pipBounds.height();
+        lp.leftMargin = pipBounds.left;
+        lp.topMargin = pipBounds.top;
+        mPipView.setLayoutParams(lp);
+
+        mPipRecentsOverlayManager.setCallback(mPipRecentsOverlayManagerCallback);
+
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 
@@ -236,6 +302,8 @@
         homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+
+        mPipManager.addListener(mPipListener);
     }
 
     @Override
@@ -257,14 +325,16 @@
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         boolean wasLaunchedByAm = !launchState.launchedFromHome &&
-                !launchState.launchedFromAppWithThumbnail;
-        if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+                !launchState.launchedFromApp;
+        if (wasLaunchedByAm) {
             EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
         }
 
         // Notify that recents is now visible
         SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
+
+        updatePipUI();
     }
 
     @Override
@@ -274,13 +344,24 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        mPipRecentsOverlayManager.onRecentsResumed();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mPipRecentsOverlayManager.onRecentsPaused();
+    }
+
+    @Override
     protected void onStop() {
         super.onStop();
 
         mIgnoreAltTabRelease = false;
         // Notify that recents is now hidden
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
 
         // Workaround for b/22542869, if the RecentsActivity is started again, but without going
         // through SystemUI, we need to reset the config launch flags to ensure that we do not
@@ -294,6 +375,7 @@
     protected void onDestroy() {
         super.onDestroy();
 
+        mPipManager.removeListener(mPipListener);
         // In the case that the activity finished on startup, just skip the unregistration below
         if (mFinishedOnStartup) {
             return;
@@ -316,18 +398,6 @@
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_UP: {
-                SystemServicesProxy ssp = Recents.getSystemServices();
-                PipManager.getInstance().resizePinnedStack(PipManager.STATE_PIP_MENU);
-                ssp.focusPinnedStack();
-                return true;
-            }
-            case KeyEvent.KEYCODE_DPAD_DOWN: {
-                SystemServicesProxy ssp = Recents.getSystemServices();
-                PipManager.getInstance().resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
-                ssp.focusHomeStack();
-                return true;
-            }
             case KeyEvent.KEYCODE_DEL:
             case KeyEvent.KEYCODE_FORWARD_DEL: {
                 EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
@@ -429,4 +499,35 @@
         });
         return true;
     }
+
+    private void updatePipUI() {
+        if (mPipManager.isPipShown()) {
+            mPipView.setVisibility(View.VISIBLE);
+            mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
+            if (mPipView.hasFocus()) {
+                // This can happen only if the activity is resumed. Ask for reset.
+                handlePipViewFocusChange(true);
+            } else {
+                mPipView.requestFocus();
+            }
+        } else {
+            mPipView.setVisibility(View.GONE);
+            mPipRecentsOverlayManager.removePipRecentsOverlayView();
+        }
+    }
+
+    /**
+     * Handles the PIP view's focus change.
+     * This starts the relevant recents row animation
+     * and give focus to the recents overlay if needed.
+     */
+    private void handlePipViewFocusChange(boolean hasFocus) {
+        mRecentsView.startRecentsRowFocusAnimation(!hasFocus);
+        if (hasFocus) {
+            // When PIP view has focus, recents overlay view will takes the focus
+            // as if it's the part of the Recents UI.
+            mPipRecentsOverlayManager.requestFocus(
+                    mTaskStackViewAdapter.getItemCount() > 0);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
new file mode 100644
index 0000000..fb62aff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tv;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.os.UserHandle;
+
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+public class RecentsTvImpl extends RecentsImpl{
+    public final static String RECENTS_TV_ACTIVITY =
+            "com.android.systemui.recents.tv.RecentsTvActivity";
+
+    public RecentsTvImpl(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+            boolean isTopTaskHome, boolean animate) {
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+
+        // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
+        // should always preload the tasks now. If we are dragging in recents, reload them as
+        // the stacks might have changed.
+        if (mTriggeredFromAltTab || sInstanceLoadPlan == null) {
+            // Create a new load plan if preloadRecents() was never triggered
+            sInstanceLoadPlan = loader.createLoadPlan(mContext);
+        }
+        if (mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
+            loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
+        }
+        TaskStack stack = sInstanceLoadPlan.getTaskStack();
+
+        if (!animate) {
+            ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
+            startRecentsActivity(topTask, opts, false /* fromHome */, false /* fromThumbnail*/);
+            return;
+        }
+
+        boolean hasRecentTasks = stack.getTaskCount() > 0;
+        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
+
+        if (useThumbnailTransition) {
+            // Try starting with a thumbnail transition
+            ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask);
+            if (opts != null) {
+                startRecentsActivity(topTask, opts, false /* fromHome */, true /* fromThumbnail */);
+            } else {
+                // Fall through below to the non-thumbnail transition
+                useThumbnailTransition = false;
+            }
+        }
+
+        if (!useThumbnailTransition) {
+            // If there is no thumbnail transition, but is launching from home into recents, then
+            // use a quick home transition and do the animation from home
+            if (hasRecentTasks) {
+                ActivityOptions opts = getHomeTransitionActivityOptions();
+                startRecentsActivity(topTask, opts, true /* fromHome */, false /* fromThumbnail */);
+            } else {
+                // Otherwise we do the normal fade from an unknown source
+                ActivityOptions opts = getUnknownTransitionActivityOptions();
+                startRecentsActivity(topTask, opts, true /* fromHome */, false /* fromThumbnail */);
+            }
+        }
+        mLastToggleTime = SystemClock.elapsedRealtime();
+    }
+
+    protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+            ActivityOptions opts, boolean fromHome, boolean fromThumbnail) {
+        // Update the configuration based on the launch options
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        launchState.launchedFromHome = fromHome;
+        launchState.launchedFromApp = fromThumbnail;
+        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        launchState.launchedWithAltTab = mTriggeredFromAltTab;
+
+        Intent intent = new Intent();
+        intent.setClassName(RECENTS_PACKAGE, RECENTS_TV_ACTIVITY);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+
+        if (opts != null) {
+            mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
+        } else {
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        }
+        EventBus.getDefault().send(new RecentsActivityStartingEvent());
+    }
+
+    /**
+     * Creates the activity options for an app->recents transition on TV.
+     */
+    private ActivityOptions getThumbnailTransitionActivityOptionsForTV(
+            ActivityManager.RunningTaskInfo topTask) {
+        Bitmap thumbnail = mThumbTransitionBitmapCache;
+        Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext);
+        if (thumbnail != null) {
+            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+                    null, (int) rect.left, (int) rect.top,
+                    (int) rect.width(), (int) rect.height(), mHandler, null);
+        }
+        // If both the screenshot and thumbnail fails, then just fall back to the default transition
+        return getUnknownTransitionActivityOptions();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
new file mode 100644
index 0000000..8996d0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tv.animations;
+
+
+import android.animation.Animator;
+import android.content.res.Resources;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.view.View;
+import android.widget.LinearLayout;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+import com.android.systemui.R;
+
+public class DismissAnimationsHolder {
+    private LinearLayout mDismissArea;
+    private LinearLayout mTaskCardView;
+    private FastOutSlowInInterpolator mFastOutSlowIn;
+    private int mCardYDelta;
+    private long mShortDuration;
+    private long mLongDuration;
+
+    public DismissAnimationsHolder(TaskCardView taskCardView) {
+        mTaskCardView = (LinearLayout) taskCardView.findViewById(R.id.recents_tv_card);
+        mDismissArea = (LinearLayout) taskCardView.findViewById(R.id.card_dismiss);
+        mFastOutSlowIn = new FastOutSlowInInterpolator();
+
+        Resources res = taskCardView.getResources();
+        mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+        mShortDuration =  res.getInteger(R.integer.dismiss_short_duration);
+        mLongDuration =  res.getInteger(R.integer.dismiss_long_duration);
+    }
+
+    public void startEnterAnimation() {
+        mDismissArea.animate().setDuration(mShortDuration);
+        mDismissArea.animate().setInterpolator(mFastOutSlowIn);
+        mDismissArea.animate().alpha(1.0f);
+
+        mTaskCardView.animate().setDuration(mShortDuration);
+        mTaskCardView.animate().setInterpolator(mFastOutSlowIn);
+        mTaskCardView.animate().translationYBy(mCardYDelta);
+        mTaskCardView.animate().alpha(0.5f);
+    }
+
+    public void startExitAnimation() {
+        mDismissArea.animate().setDuration(mShortDuration);
+        mDismissArea.animate().setInterpolator(mFastOutSlowIn);
+        mDismissArea.animate().alpha(0.0f);
+
+        mTaskCardView.animate().setDuration(mShortDuration);
+        mTaskCardView.animate().setInterpolator(mFastOutSlowIn);
+        mTaskCardView.animate().translationYBy(-mCardYDelta);
+        mTaskCardView.animate().alpha(1.0f);
+    }
+
+    public void startDismissAnimation(Animator.AnimatorListener listener) {
+        mDismissArea.animate().setDuration(mShortDuration);
+        mDismissArea.animate().setInterpolator(mFastOutSlowIn);
+        mDismissArea.animate().alpha(0.0f);
+
+        mTaskCardView.animate().setDuration(mLongDuration);
+        mTaskCardView.animate().setInterpolator(mFastOutSlowIn);
+        mTaskCardView.animate().translationYBy(mCardYDelta);
+        mTaskCardView.animate().alpha(0.0f);
+        mTaskCardView.animate().setListener(listener);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
new file mode 100644
index 0000000..28abc34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tv.animations;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.view.View;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+/**
+ * Recents row's focus animation with PIP controls.
+ */
+public class RecentsRowFocusAnimationHolder {
+    private static final float DIM_ALPHA = 0.5f;
+
+    private View mView;
+    private View mTitleView;
+
+    private AnimatorSet mFocusGainAnimatorSet;
+    private AnimatorSet mFocusLoseAnimatorSet;
+
+    public RecentsRowFocusAnimationHolder(View view, View titleView) {
+        mView = view;
+        mTitleView = titleView;
+
+        Resources res = view.getResources();
+        int duration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+
+        mFocusGainAnimatorSet = new AnimatorSet();
+        mFocusGainAnimatorSet.playTogether(
+                ObjectAnimator.ofFloat(mView, "alpha", 1f),
+                ObjectAnimator.ofFloat(mTitleView, "alpha", 1f));
+        mFocusGainAnimatorSet.setDuration(duration);
+        mFocusGainAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+
+        mFocusLoseAnimatorSet = new AnimatorSet();
+        mFocusLoseAnimatorSet.playTogether(
+                ObjectAnimator.ofFloat(mView, "alpha", DIM_ALPHA),
+                ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
+        mFocusLoseAnimatorSet.setDuration(duration);
+        mFocusLoseAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+    }
+
+    /**
+     * Returns the Recents row's focus change animation.
+     */
+    public Animator getFocusChangeAnimator(boolean hasFocus) {
+        return hasFocus ? mFocusGainAnimatorSet : mFocusLoseAnimatorSet;
+    }
+
+    /**
+     * Resets the views to the initial state immediately.
+     */
+    public void reset() {
+        mView.setAlpha(1f);
+        mTitleView.setAlpha(1f);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
index 48a1904..888561c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -29,9 +29,12 @@
 
 public class ViewFocusAnimator implements View.OnFocusChangeListener {
     private final float mUnselectedScale;
+    private final float mSelectedScale;
     private final float mSelectedScaleDelta;
     private final float mUnselectedZ;
     private final float mSelectedZDelta;
+    private final float mUnselectedSpacing;
+    private final float mSelectedSpacingDelta;
     private final int mAnimDuration;
     private final Interpolator mFocusInterpolator;
 
@@ -49,12 +52,16 @@
         TypedValue out = new TypedValue();
         res.getValue(R.integer.unselected_scale, out, true);
         mUnselectedScale = out.getFloat();
-        mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
-                mUnselectedScale;
+        res.getValue(R.integer.selected_scale, out, true);
+        mSelectedScale = out.getFloat();
+        mSelectedScaleDelta = mSelectedScale - mUnselectedScale;
 
         mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
         mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);
 
+        mUnselectedSpacing = res.getDimensionPixelOffset(R.dimen.recents_tv_gird_card_spacing);
+        mSelectedSpacingDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_gird_focused_card_delta);
+
         mAnimDuration = res.getInteger(R.integer.item_scale_anim_duration);
 
         mFocusInterpolator = new AccelerateDecelerateInterpolator();
@@ -83,10 +90,14 @@
 
         float scale = mUnselectedScale + (level * mSelectedScaleDelta);
         float z = mUnselectedZ + (level * mSelectedZDelta);
+        float spacing = mUnselectedSpacing + (level * mSelectedSpacingDelta);
 
         mTargetView.setScaleX(scale);
         mTargetView.setScaleY(scale);
         mTargetView.setZ(z);
+
+        mTargetView.setPadding((int) spacing, mTargetView.getPaddingTop(),
+                (int) spacing, mTargetView.getPaddingBottom());
     }
 
     public float getFocusProgress() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
new file mode 100644
index 0000000..a69f8a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tv.views;
+
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.*;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+
+public class RecentsTvTransitionHelper {
+    private static final String TAG = "RecentsTvTransitionHelper";
+
+    private Context mContext;
+    private Handler mHandler;
+
+    public RecentsTvTransitionHelper(Context context, Handler handler) {
+        mContext = context;
+        mHandler = handler;
+    }
+
+    public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
+            final TaskStackHorizontalGridView stackView, final TaskCardView taskView,
+            final Rect bounds, int destinationStack) {
+        final ActivityOptions opts = ActivityOptions.makeBasic();
+        if (bounds != null) {
+            opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
+        }
+
+        final ActivityOptions.OnAnimationStartedListener animStartedListener;
+        if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
+                task.thumbnail.getHeight() > 0) {
+            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+                @Override
+                public void onAnimationStarted() {
+                    // If we are launching into another task, cancel the previous task's
+                    // window transition
+                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+                }
+            };
+        } else {
+            // This is only the case if the task is not on screen (scrolled offscreen for example)
+            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+                @Override
+                public void onAnimationStarted() {
+                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+                }
+            };
+        }
+
+        if (taskView == null) {
+            // If there is no task view, then we do not need to worry about animating out occluding
+            // task views, and we can launch immediately
+            startTaskActivity(stack, task, taskView, opts, animStartedListener);
+        } else {
+            LaunchTvTaskStartedEvent launchStartedEvent = new LaunchTvTaskStartedEvent(taskView);
+            EventBus.getDefault().send(launchStartedEvent);
+            startTaskActivity(stack, task, taskView, opts, animStartedListener);
+        }
+    }
+
+    private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskCardView taskView,
+            ActivityOptions opts,final ActivityOptions.OnAnimationStartedListener animStartedListener) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) {
+            // Keep track of the index of the task launch
+            int taskIndexFromFront = 0;
+            int taskIndex = stack.indexOfStackTask(task);
+            if (taskIndex > -1) {
+                taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
+            }
+            EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
+        } else {
+            // Keep track of failed launches
+            EventBus.getDefault().send(new LaunchTaskFailedEvent());
+        }
+
+        IRemoteCallback.Stub callback = null;
+        if (animStartedListener != null) {
+            callback = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (animStartedListener != null) {
+                                animStartedListener.onAnimationStarted();
+                            }
+                        }
+                    });
+                }
+            };
+        }
+        try {
+            Rect taskRect = taskView.getFocusedThumbnailRect();
+            WindowManagerGlobal.getWindowManagerService()
+                    .overridePendingAppTransitionAspectScaledThumb(task.thumbnail, taskRect.left,
+                            taskRect.top, taskRect.width(), taskRect.height(), callback, true);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to override transition: " + e);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index b175855..9da8eed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.Handler;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -31,11 +32,12 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -51,9 +53,11 @@
     private TaskStack mStack;
     private TaskStackHorizontalGridView mTaskStackHorizontalView;
     private View mEmptyView;
+    private RecentsRowFocusAnimationHolder mEmptyViewFocusAnimationHolder;
     private boolean mAwaitingFirstLayout = true;
     private Rect mSystemInsets = new Rect();
-
+    private RecentsTvTransitionHelper mTransitionHelper;
+    private Handler mHandler;
 
     public RecentsTvView(Context context) {
         this(context, null);
@@ -75,6 +79,10 @@
         LayoutInflater inflater = LayoutInflater.from(context);
         mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
+        mEmptyViewFocusAnimationHolder = new RecentsRowFocusAnimationHolder(mEmptyView, null);
+
+        mHandler = new Handler();
+        mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
     }
 
     public void setTaskStack(TaskStack stack) {
@@ -90,7 +98,6 @@
             mTaskStackHorizontalView.setStack(stack);
         }
 
-
         if (stack.getStackTaskCount() > 0) {
             hideEmptyView();
         } else {
@@ -100,34 +107,12 @@
         requestLayout();
     }
 
-    public Task getNextTaskOrTopTask(Task taskToSearch) {
-        Task returnTask = null;
-        boolean found = false;
-        if (mTaskStackHorizontalView != null) {
-            TaskStack stack = mTaskStackHorizontalView.getStack();
-            ArrayList<Task> taskList = stack.getStackTasks();
-            // Iterate the stack views and try and find the focused task
-            for (int j = taskList.size() - 1; j >= 0; --j) {
-                Task task = taskList.get(j);
-                // Return the next task in the line.
-                if (found)
-                    return task;
-                // Remember the first possible task as the top task.
-                if (returnTask == null)
-                    returnTask = task;
-                if (task == taskToSearch)
-                    found = true;
-            }
-        }
-        return returnTask;
-    }
-
     public boolean launchFocusedTask() {
         if (mTaskStackHorizontalView != null) {
             Task task = mTaskStackHorizontalView.getFocusedTask();
             if (task != null) {
                 SystemServicesProxy ssp = Recents.getSystemServices();
-                ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+                ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
                 return true;
             }
         }
@@ -141,7 +126,7 @@
             Task task = stack.getLaunchTarget();
             if (task != null) {
                 SystemServicesProxy ssp = Recents.getSystemServices();
-                ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+                ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
                 return true;
             }
         }
@@ -152,33 +137,40 @@
     public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
         if (mTaskStackHorizontalView != null) {
             // Iterate the stack views and try and find the given task.
-            List<TaskCardView> taskViews = mTaskStackHorizontalView.getTaskViews();
-            int taskViewCount = taskViews.size();
-            for (int j = 0; j < taskViewCount; j++) {
-                TaskCardView tv = taskViews.get(j);
-                if (tv.getTask() == task) {
-                    SystemServicesProxy ssp = Recents.getSystemServices();
-                    ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
-                    return true;
-                }
+            if (mTaskStackHorizontalView.getChildViewForTask(task) != null) {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
+                return true;
             }
         }
         return false;
     }
 
     /**
+     * Starts the focus change animation.
+     */
+    public void startRecentsRowFocusAnimation(boolean hasFocus) {
+        if (mEmptyView.getVisibility() == View.VISIBLE) {
+            mEmptyViewFocusAnimationHolder.getFocusChangeAnimator(hasFocus).start();
+        } else {
+            mTaskStackHorizontalView.startRecentsRowFocusAnimation(hasFocus);
+        }
+    }
+
+    /**
      * Hides the task stack and shows the empty view.
      */
     public void showEmptyView() {
         mEmptyView.setVisibility(View.VISIBLE);
-        mEmptyView.bringToFront();
+        mTaskStackHorizontalView.setVisibility(View.GONE);
     }
 
     /**
      * Shows the task stack and hides the empty view.
      */
     public void hideEmptyView() {
-        mEmptyView.setVisibility(View.INVISIBLE);
+        mEmptyView.setVisibility(View.GONE);
+        mTaskStackHorizontalView.setVisibility(View.VISIBLE);
     }
 
     /**
@@ -200,19 +192,6 @@
         EventBus.getDefault().unregister(this);
     }
 
-    /**
-     * 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) {
-        if (mTaskStackHorizontalView != null && mTaskStackHorizontalView.getVisibility() != GONE) {
-            mTaskStackHorizontalView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
-        }
-
-        // Layout the empty view
-        mEmptyView.layout(left, top, right, bottom);
-    }
-
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mSystemInsets.set(insets.getSystemWindowInsets());
@@ -222,6 +201,11 @@
 
     /**** EventBus Events ****/
 
+    public final void onBusEvent(LaunchTvTaskEvent event) {
+        mTransitionHelper.launchTaskFromRecents(mStack, event.task, mTaskStackHorizontalView,
+                event.taskView, event.targetTaskBounds, event.targetTaskStack);
+    }
+
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
         // If we are going home, cancel the previous task's window transition
         EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index e275f22..d605748 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -15,25 +15,38 @@
  */
 package com.android.systemui.recents.tv.views;
 
+import android.animation.Animator;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
 import android.widget.ImageView;
-import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.tv.animations.DismissAnimationsHolder;
+import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
 import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+import com.android.systemui.recents.model.Task;
 
-public class TaskCardView extends RelativeLayout {
+public class TaskCardView extends LinearLayout {
 
     private ImageView mThumbnailView;
     private TextView mTitleTextView;
-    private TextView mContentTextView;
     private ImageView mBadgeView;
     private Task mTask;
+    private boolean mDismissState;
 
     private ViewFocusAnimator mViewFocusAnimator;
+    private DismissAnimationsHolder mDismissAnimationsHolder;
+    private RecentsRowFocusAnimationHolder mRecentsRowFocusAnimationHolder;
 
     public TaskCardView(Context context) {
         this(context, null);
@@ -46,25 +59,152 @@
     public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mViewFocusAnimator = new ViewFocusAnimator(this);
+        mDismissState = false;
     }
 
     @Override
     protected void onFinishInflate() {
         mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
         mTitleTextView = (TextView) findViewById(R.id.card_title_text);
-        mContentTextView = (TextView) findViewById(R.id.card_content_text);
         mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
+        mDismissAnimationsHolder = new DismissAnimationsHolder(this);
+        View title = findViewById(R.id.card_info_field);
+        mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, title);
     }
 
     public void init(Task task) {
         mTask = task;
         mThumbnailView.setImageBitmap(task.thumbnail);
         mTitleTextView.setText(task.title);
-        mContentTextView.setText(task.contentDescription);
         mBadgeView.setImageDrawable(task.icon);
     }
 
     public Task getTask() {
         return mTask;
     }
+
+    @Override
+    public void getFocusedRect(Rect r) {
+        mThumbnailView.getFocusedRect(r);
+    }
+
+    public Rect getFocusedThumbnailRect() {
+        Rect r = new Rect();
+        mThumbnailView.getGlobalVisibleRect(r);
+        TypedValue out = new TypedValue();
+        getContext().getResources().getValue(R.integer.selected_scale, out, true);
+        float deltaScale = (out.getFloat() - 1.0f) / 2;
+        r.set((int) (r.left - r.left * deltaScale),
+                (int) (r.top - r.top * deltaScale),
+                (int) (r.right + r.right * deltaScale),
+                (int) (r.bottom + r.bottom * deltaScale));
+        return r;
+    }
+
+    public static Rect getStartingCardThumbnailRect(Context context) {
+        Resources res = context.getResources();
+
+        TypedValue out = new TypedValue();
+        res.getValue(R.integer.selected_scale, out, true);
+        float scale = out.getFloat();
+
+        int width = res.getDimensionPixelOffset(R.dimen.recents_tv_card_width);
+        int widthDelta = (int) (width * scale - width);
+        int height = res.getDimensionPixelOffset(R.dimen.recents_tv_screenshot_height);
+        int heightDelta = (int) (height * scale - height);
+        int topMargin = res.getDimensionPixelOffset(R.dimen.recents_tv_gird_row_top_margin);
+
+        int headerHeight = res.getDimensionPixelOffset(R.dimen.recents_tv_card_extra_badge_size) +
+                res.getDimensionPixelOffset(R.dimen.recents_tv_icon_padding_bottom);
+        int headerHeightDelta = (int) (headerHeight * scale - headerHeight);
+
+        int dismissAreaHeight =
+                res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_icon_top_margin) +
+                res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_icon_bottom_margin) +
+                res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_icon_size) +
+                res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_text_size);
+
+        int dismissAreaHeightDelta = (int) (dismissAreaHeight * scale - dismissAreaHeight);
+
+        int totalHeightDelta = heightDelta + headerHeightDelta + dismissAreaHeightDelta;
+
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display display = wm.getDefaultDisplay();
+        Point size = new Point();
+        display.getSize(size);
+        int screenWidth = size.x;
+        int screenHeight = size.y;
+
+        return new Rect(screenWidth / 2 - width / 2 - widthDelta / 2,
+                topMargin - totalHeightDelta / 2 + (int) (headerHeight * scale),
+                screenWidth / 2 + width / 2 + widthDelta / 2,
+                topMargin - totalHeightDelta / 2 + (int) (headerHeight * scale) +
+                        (int) (height * scale));
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_DOWN : {
+                if (!isInDismissState()) {
+                    setDismissState(true);
+                    return true;
+                }
+                break;
+            }
+            case KeyEvent.KEYCODE_DPAD_UP : {
+                if (isInDismissState()) {
+                    setDismissState(false);
+                    return true;
+                }
+                break;
+            }
+
+            //Eat right and left key presses when we are in dismiss state
+            case KeyEvent.KEYCODE_DPAD_LEFT : {
+                if (isInDismissState()) {
+                    return true;
+                }
+                break;
+            }
+            case KeyEvent.KEYCODE_DPAD_RIGHT : {
+                if (isInDismissState()) {
+                    return true;
+                }
+                break;
+            }
+            default:
+                break;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    private void setDismissState(boolean dismissState) {
+        if (mDismissState != dismissState) {
+            mDismissState = dismissState;
+            if (dismissState) {
+                mDismissAnimationsHolder.startEnterAnimation();
+            } else {
+                mDismissAnimationsHolder.startExitAnimation();
+            }
+        }
+    }
+
+    public boolean isInDismissState() {
+        return mDismissState;
+    }
+
+    public void startDismissTaskAnimation(Animator.AnimatorListener listener) {
+        mDismissAnimationsHolder.startDismissAnimation(listener);
+    }
+
+    public RecentsRowFocusAnimationHolder getRecentsRowFocusAnimationHolder() {
+        return mRecentsRowFocusAnimationHolder;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        setDismissState(false);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 58ec852..603721a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -15,8 +15,11 @@
  */
 package com.android.systemui.recents.tv.views;
 
-
+import android.animation.Animator;
+import android.animation.AnimatorSet;
 import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
 import android.support.v17.leanback.widget.HorizontalGridView;
 import android.util.AttributeSet;
 import android.view.View;
@@ -36,12 +39,24 @@
 /**
  * Horizontal Grid View Implementation to show the Task Stack for TV.
  */
-public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
-
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks {
+    private static final int ANIMATION_DELAY_MS = 50;
+    private static final int MSG_START_RECENT_ROW_FOCUS_ANIMATION = 100;
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == MSG_START_RECENT_ROW_FOCUS_ANIMATION) {
+                startRecentsRowFocusAnimation(msg.arg1 == 1);
+            }
+        }
+    };
     private TaskStack mStack;
-    private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
     private Task mFocusedTask;
+    private AnimatorSet mRecentsRowFocusAnimation;
 
+    public TaskStackHorizontalGridView(Context context) {
+        this(context, null);
+    }
 
     public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -50,7 +65,7 @@
     @Override
     protected void onAttachedToWindow() {
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
-        setItemMargin((int) getResources().getDimension(R.dimen.recents_tv_gird_card_spacing));
+        setWindowAlignment(WINDOW_ALIGN_NO_EDGE);
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         super.onAttachedToWindow();
     }
@@ -60,12 +75,18 @@
         super.onDetachedFromWindow();
         EventBus.getDefault().unregister(this);
     }
+
     /**
      * Resets this view for reuse.
      */
     public void reset() {
-        // Reset the focused task
-        resetFocusedTask(getFocusedTask());
+        for (int i = 0; i < getChildCount(); i++) {
+            ((TaskCardView) getChildAt(i)).getRecentsRowFocusAnimationHolder().reset();
+        }
+        if (mRecentsRowFocusAnimation != null && mRecentsRowFocusAnimation.isStarted()) {
+            mRecentsRowFocusAnimation.cancel();
+        }
+        mHandler.removeCallbacksAndMessages(null);
         requestLayout();
     }
 
@@ -73,12 +94,6 @@
      * @param task - Task to reset
      */
     private void resetFocusedTask(Task task) {
-        if (task != null) {
-            TaskCardView tv = getChildViewForTask(task);
-            if (tv != null) {
-                tv.requestFocus();
-            }
-        }
         mFocusedTask = null;
     }
 
@@ -107,18 +122,26 @@
      * @return - The focused task.
      */
     public Task getFocusedTask() {
+        if (findFocus() != null) {
+            mFocusedTask = ((TaskCardView)findFocus()).getTask();
+        }
         return mFocusedTask;
     }
 
     /**
+     * @return - The focused task card view.
+     */
+    public TaskCardView getFocusedTaskCardView() {
+        return ((TaskCardView)findFocus());
+    }
+
+    /**
      * @param task
      * @return Child view for given task
      */
     public TaskCardView getChildViewForTask(Task task) {
-        List<TaskCardView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = 0; i < taskViewCount; i++) {
-            TaskCardView tv = taskViews.get(i);
+        for (int i = 0; i < getChildCount(); i++) {
+            TaskCardView tv = (TaskCardView) getChildAt(i);
             if (tv.getTask() == task) {
                 return tv;
             }
@@ -126,18 +149,42 @@
         return null;
     }
 
-    public List<TaskCardView> getTaskViews() {
-        return mTaskViews;
+    /**
+     * Starts the focus change animation.
+     */
+    public void startRecentsRowFocusAnimation(final boolean hasFocus) {
+        if (getChildCount() == 0) {
+            // Animation request may happen before view is attached.
+            // Post again with small dealy so animation can be run again later.
+            if (getAdapter().getItemCount() > 0) {
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                        MSG_START_RECENT_ROW_FOCUS_ANIMATION, hasFocus ? 1 : 0),
+                        ANIMATION_DELAY_MS);
+            }
+            return;
+        }
+        if (mRecentsRowFocusAnimation != null && mRecentsRowFocusAnimation.isStarted()) {
+            mRecentsRowFocusAnimation.cancel();
+        }
+        Animator animator = ((TaskCardView) getChildAt(0)).getRecentsRowFocusAnimationHolder()
+                .getFocusChangeAnimator(hasFocus);
+        mRecentsRowFocusAnimation = new AnimatorSet();
+        AnimatorSet.Builder builder = mRecentsRowFocusAnimation.play(animator);
+        for (int i = 1; i < getChildCount(); i++) {
+            builder.with(((TaskCardView) getChildAt(i)).getRecentsRowFocusAnimationHolder()
+                    .getFocusChangeAnimator(hasFocus));
+        }
+        mRecentsRowFocusAnimation.start();
     }
 
     @Override
-    public void onStackTaskAdded(TaskStack stack, Task newTask){
+    public void onStackTaskAdded(TaskStack stack, Task newTask) {
         getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask));
     }
 
     @Override
     public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
-            Task newFrontMostTask, AnimationProps animation) {
+            Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture) {
         getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
         if (mFocusedTask == removedTask) {
             resetFocusedTask(removedTask);
@@ -146,13 +193,20 @@
         if (mStack.getStackTaskCount() == 0) {
             boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
             if (shouldFinishActivity) {
-                EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+                EventBus.getDefault().send(new AllTaskViewsDismissedEvent(fromDockGesture
+                        ? R.string.recents_empty_message
+                        : R.string.recents_empty_message_dismissed_all));
             }
         }
     }
 
     @Override
-    public void onHistoryTaskRemoved(TaskStack stack, Task removedTask, AnimationProps animation) {
-        //No history task on tv
+    public void onStackTasksRemoved(TaskStack stack) {
+        // Do nothing
+    }
+
+    @Override
+    public void onStackTasksUpdated(TaskStack stack) {
+        // Do nothing
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
index f154331..3788719 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.recents.tv.views;
 
+import android.animation.Animator;
 import android.app.Activity;
-import android.app.ActivityManagerNative;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -24,18 +24,24 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
 import com.android.systemui.recents.model.Task;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
 public class TaskStackHorizontalViewAdapter extends
         RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
 
-    private static final String TAG = "TaskStackHorizontalViewAdapter";
+    //Full class name is 30 characters
+    private static final String TAG = "TaskStackViewAdapter";
     private List<Task> mTaskList;
 
-    static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
+    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
         private TaskCardView mTaskCardView;
         private Task mTask;
         public ViewHolder(View v) {
@@ -54,8 +60,14 @@
         @Override
         public void onClick(View v) {
             try {
-                ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
-                ((Activity)(v.getContext())).finish();
+                if (mTaskCardView.isInDismissState()) {
+                    mTaskCardView.startDismissTaskAnimation(
+                            getRemoveAtListener(getAdapterPosition(), mTaskCardView));
+                } else {
+                    EventBus.getDefault().send(new LaunchTvTaskEvent(mTaskCardView, mTask,
+                            null, INVALID_STACK_ID));
+                    ((Activity) (v.getContext())).finish();
+                }
             } catch (Exception e) {
                 Log.e(TAG, v.getContext()
                         .getString(R.string.recents_launch_error_message, mTask.title), e);
@@ -73,11 +85,12 @@
         mTaskList.addAll(tasks);
         notifyDataSetChanged();
     }
+
     @Override
     public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
             int viewType) {
         View view = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.recents_task_card_view, parent, false);
+                .inflate(R.layout.recents_tv_task_card_view, parent, false);
         ViewHolder viewHolder = new ViewHolder(view);
         return viewHolder;
     }
@@ -91,4 +104,31 @@
     public int getItemCount() {
         return mTaskList.size();
     }
+
+    private Animator.AnimatorListener getRemoveAtListener(final int position,
+                                                          final TaskCardView taskCardView) {
+        return new Animator.AnimatorListener() {
+
+            @Override
+            public void onAnimationStart(Animator animation) { }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                removeAt(position);
+                EventBus.getDefault().send(new DeleteTaskDataEvent(taskCardView.getTask()));
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) { }
+
+            @Override
+            public void onAnimationRepeat(Animator animation) { }
+        };
+
+    }
+
+    private void removeAt(int position) {
+        mTaskList.remove(position);
+        notifyItemRemoved(position);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 4359101..035c058 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -37,9 +37,16 @@
     private int mTaskPadding;
 
     public FreeformWorkspaceLayoutAlgorithm(Context context) {
+        reloadOnConfigurationChange(context);
+    }
+
+    /**
+     * Reloads the layout for the current configuration.
+     */
+    public void reloadOnConfigurationChange(Context context) {
         // This is applied to the edges of each task
         mTaskPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.recents_freeform_workspace_task_padding) / 2;
+                R.dimen.recents_freeform_layout_task_padding) / 2;
     }
 
     /**
@@ -72,8 +79,7 @@
                 }
                 // Bound the task width to the workspace width so that at the worst case, it will
                 // fit its own row
-                normalizedTaskWidths[i] = Math.min(rowTaskWidth,
-                        normalizedWorkspaceWidth);
+                normalizedTaskWidths[i] = Math.min(rowTaskWidth, normalizedWorkspaceWidth);
             }
 
             // Determine the scale to best fit each of the tasks in the workspace
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 37b2859..9eec2ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -16,12 +16,19 @@
 
 package com.android.systemui.recents.views;
 
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
+import android.app.ActivityOptions.OnAnimationStartedListener;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,7 +37,6 @@
 import android.util.Log;
 import android.view.AppTransitionAnimationSpec;
 import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.WindowManagerGlobal;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.systemui.recents.Recents;
@@ -47,13 +53,9 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
 /**
  * A helper class to create transitions to/from Recents
  */
@@ -82,9 +84,9 @@
         }
     };
 
-    public RecentsTransitionHelper(Context context, Handler handler) {
+    public RecentsTransitionHelper(Context context) {
         mContext = context;
-        mHandler = handler;
+        mHandler = new Handler();
     }
 
     /**
@@ -92,7 +94,7 @@
      */
     public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
             final TaskStackView stackView, final TaskView taskView,
-            final boolean screenPinningRequested, final Rect bounds, int destinationStack) {
+            final boolean screenPinningRequested, final Rect bounds, final int destinationStack) {
         final ActivityOptions opts = ActivityOptions.makeBasic();
         if (bounds != null) {
             opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
@@ -101,7 +103,12 @@
         final ActivityOptions.OnAnimationStartedListener animStartedListener;
         final IAppTransitionAnimationSpecsFuture transitionFuture;
         if (taskView != null) {
-            transitionFuture = getAppTransitionFuture(task, stackView, destinationStack);
+            transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() {
+                @Override
+                public List<AppTransitionAnimationSpec> composeSpecs() {
+                    return composeAnimationSpecs(task, stackView, destinationStack);
+                }
+            });
             animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
                 @Override
                 public void onAnimationStarted() {
@@ -122,6 +129,9 @@
             animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
                 @Override
                 public void onAnimationStarted() {
+                    // If we are launching into another task, cancel the previous task's
+                    // window transition
+                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                     EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
                 }
             };
@@ -151,6 +161,23 @@
         }
     }
 
+    public IRemoteCallback wrapStartedListener(final OnAnimationStartedListener listener) {
+        if (listener == null) {
+            return null;
+        }
+        return new IRemoteCallback.Stub() {
+            @Override
+            public void sendResult(Bundle data) throws RemoteException {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        listener.onAnimationStarted();
+                    }
+                });
+            }
+        };
+    }
+
     /**
      * Starts the activity for the launch task.
      *
@@ -161,7 +188,7 @@
             ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
             final ActivityOptions.OnAnimationStartedListener animStartedListener) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.startActivityFromRecents(mContext, task.key.id, task.title, opts)) {
+        if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) {
             // Keep track of the index of the task launch
             int taskIndexFromFront = 0;
             int taskIndex = stack.indexOfStackTask(task);
@@ -176,41 +203,23 @@
             // Keep track of failed launches
             EventBus.getDefault().send(new LaunchTaskFailedEvent());
         }
+
         if (transitionFuture != null) {
-            IRemoteCallback.Stub callback = null;
-            if (animStartedListener != null) {
-                callback = new IRemoteCallback.Stub() {
-                    @Override
-                    public void sendResult(Bundle data) throws RemoteException {
-                        mHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                if (animStartedListener != null) {
-                                    animStartedListener.onAnimationStarted();
-                                }
-                            }
-                        });
-                    }
-                };
-            }
-            try {
-                synchronized (this) {
-                    mAppTransitionAnimationSpecs = SPECS_WAITING;
-                }
-                WindowManagerGlobal.getWindowManagerService()
-                        .overridePendingAppTransitionMultiThumbFuture(transitionFuture,
-                                callback, true /* scaleUp */);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to override transition: " + e);
-            }
+            ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture,
+                    wrapStartedListener(animStartedListener), true /* scaleUp */);
         }
     }
 
     /**
      * Creates a future which will later be queried for animation specs for this current transition.
+     *
+     * @param composer The implementation that composes the specs on the UI thread.
      */
-    private IAppTransitionAnimationSpecsFuture getAppTransitionFuture(final Task task,
-            final TaskStackView stackView, final int destinationStack) {
+    public IAppTransitionAnimationSpecsFuture getAppTransitionFuture(
+            final AnimationSpecComposer composer) {
+        synchronized (this) {
+            mAppTransitionAnimationSpecs = SPECS_WAITING;
+        }
         return new IAppTransitionAnimationSpecsFuture.Stub() {
             @Override
             public AppTransitionAnimationSpec[] get() throws RemoteException {
@@ -218,8 +227,7 @@
                     @Override
                     public void run() {
                         synchronized (RecentsTransitionHelper.this) {
-                            mAppTransitionAnimationSpecs = composeAnimationSpecs(task, stackView,
-                                    destinationStack);
+                            mAppTransitionAnimationSpecs = composer.composeSpecs();
                             RecentsTransitionHelper.this.notifyAll();
                         }
                     }
@@ -244,6 +252,18 @@
     }
 
     /**
+     * Composes the transition spec when docking a task, which includes a full task bitmap.
+     */
+    public List<AppTransitionAnimationSpec> composeDockAnimationSpec(TaskView taskView,
+            Rect bounds) {
+        mTmpTransform.fillIn(taskView);
+        Task task = taskView.getTask();
+        Bitmap thumbnail = RecentsTransitionHelper.composeTaskBitmap(taskView, mTmpTransform);
+        return Collections.singletonList(new AppTransitionAnimationSpec(task.key.id, thumbnail,
+                bounds));
+    }
+
+    /**
      * Composes the animation specs for all the tasks in the target stack.
      */
     private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
@@ -276,7 +296,8 @@
             } else {
                 layoutAlgorithm.getStackTransformScreenCoordinates(task, stackScroll, mTmpTransform,
                         null);
-                specs.add(composeAnimationSpec(taskView, mTmpTransform, true /* addHeaderBitmap */));
+                specs.add(composeAnimationSpec(stackView, taskView, mTmpTransform,
+                        true /* addHeaderBitmap */));
             }
             return specs;
         }
@@ -297,7 +318,8 @@
                 } else {
                     layoutAlgorithm.getStackTransformScreenCoordinates(t, stackScroll,
                             mTmpTransform, null);
-                    specs.add(composeAnimationSpec(tv, mTmpTransform, true /* addHeaderBitmap */));
+                    specs.add(composeAnimationSpec(stackView, tv, mTmpTransform,
+                            true /* addHeaderBitmap */));
                 }
             }
         }
@@ -313,17 +335,19 @@
         return new AppTransitionAnimationSpec(task.key.id, null, taskRect);
     }
 
-    /**
-     * Composes a single animation spec for the given {@link TaskView}
-     */
-    private static AppTransitionAnimationSpec composeAnimationSpec(TaskView taskView,
-            TaskViewTransform transform, boolean addHeaderBitmap) {
-        Bitmap b = null;
-        if (addHeaderBitmap) {
-            float scale = transform.scale;
-            int fromHeaderWidth = (int) (transform.rect.width());
-            int fromHeaderHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
-            b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
+    public static Bitmap composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
+        float scale = transform.scale;
+        int fromWidth = (int) (transform.rect.width() * scale);
+        int fromHeight = (int) (transform.rect.height() * scale);
+        if (fromWidth == 0 || fromHeight == 0) {
+            Log.e(TAG, "Could not compose thumbnail for task: " + taskView.getTask() +
+                    " at transform: " + transform);
+
+            Bitmap b = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+            b.eraseColor(Color.TRANSPARENT);
+            return b;
+        } else {
+            Bitmap b = Bitmap.createBitmap(fromWidth, fromHeight,
                     Bitmap.Config.ARGB_8888);
 
             if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
@@ -331,14 +355,52 @@
             } else {
                 Canvas c = new Canvas(b);
                 c.scale(scale, scale);
-                taskView.mHeaderView.draw(c);
+                taskView.draw(c);
                 c.setBitmap(null);
             }
-            b = b.createAshmemBitmap();
+            return b.createAshmemBitmap();
+        }
+    }
+
+    private static Bitmap composeHeaderBitmap(TaskView taskView,
+            TaskViewTransform transform) {
+        float scale = transform.scale;
+        int fromHeaderWidth = (int) (transform.rect.width());
+        int fromHeaderHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
+        Bitmap b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
+                Bitmap.Config.ARGB_8888);
+
+        if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
+            b.eraseColor(0xFFff0000);
+        } else {
+            Canvas c = new Canvas(b);
+            c.scale(scale, scale);
+            taskView.mHeaderView.draw(c);
+            c.setBitmap(null);
+        }
+        return b.createAshmemBitmap();
+    }
+
+    /**
+     * Composes a single animation spec for the given {@link TaskView}
+     */
+    private static AppTransitionAnimationSpec composeAnimationSpec(TaskStackView stackView,
+            TaskView taskView, TaskViewTransform transform, boolean addHeaderBitmap) {
+        Bitmap b = null;
+        if (addHeaderBitmap) {
+            b = composeHeaderBitmap(taskView, transform);
         }
 
         Rect taskRect = new Rect();
         transform.rect.round(taskRect);
+        if (stackView.getStack().getStackFrontMostTask(false /* includeFreeformTasks */) !=
+                taskView.getTask()) {
+            taskRect.bottom = 2 * Recents.getSystemServices().getDisplayRect().height();
+        }
         return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
     }
+
+    public interface AnimationSpecComposer {
+        List<AppTransitionAnimationSpec> composeSpecs();
+    }
 }
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 2e45627..ef81f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -19,8 +19,8 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.app.ActivityOptions.OnAnimationStartedListener;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -28,9 +28,10 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
 import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.view.AppTransitionAnimationSpec;
+import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -48,34 +49,28 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
-import com.android.systemui.recents.RecentsAppWidgetHostView;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.ClearHistoryEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
-import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
-import com.android.systemui.recents.events.activity.ToggleHistoryEvent;
-import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
-import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
-import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
-import com.android.systemui.recents.history.RecentsHistoryView;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
 import com.android.systemui.stackdivider.WindowManagerProxy;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
@@ -92,15 +87,13 @@
     private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
     private static final float DEFAULT_SCRIM_ALPHA = 0.33f;
 
-    private final Handler mHandler;
+    private static final int SHOW_STACK_ACTION_BUTTON_DURATION = 150;
+    private static final int HIDE_STACK_ACTION_BUTTON_DURATION = 100;
 
     private TaskStack mStack;
     private TaskStackView mTaskStackView;
-    private RecentsAppWidgetHostView mSearchBar;
-    private TextView mHistoryButton;
-    private TextView mHistoryClearAllButton;
-    private View mEmptyView;
-    private RecentsHistoryView mHistoryView;
+    private TextView mStackActionButton;
+    private TextView mEmptyView;
 
     private boolean mAwaitingFirstLayout = true;
     private boolean mLastTaskLaunchedWasFreeform;
@@ -109,7 +102,8 @@
     private Rect mSystemInsets = new Rect();
     private int mDividerSize;
 
-    private ColorDrawable mBackgroundScrim = new ColorDrawable(Color.BLACK);
+    private Drawable mBackgroundScrim = new ColorDrawable(
+            Color.argb((int) (DEFAULT_SCRIM_ALPHA * 255), 0, 0, 0)).mutate();
     private Animator mBackgroundScrimAnimator;
 
     private RecentsTransitionHelper mTransitionHelper;
@@ -134,80 +128,101 @@
         setWillNotDraw(false);
 
         SystemServicesProxy ssp = Recents.getSystemServices();
-        mHandler = new Handler();
-        mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler);
+        mTransitionHelper = new RecentsTransitionHelper(getContext());
         mDividerSize = ssp.getDockedDividerSize(context);
         mTouchHandler = new RecentsViewTouchHandler(this);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
 
-        final float cornerRadius = context.getResources().getDimensionPixelSize(
-                R.dimen.recents_task_view_rounded_corners_radius);
         LayoutInflater inflater = LayoutInflater.from(context);
-        if (RecentsDebugFlags.Static.EnableHistory) {
-            mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this,
-                    false);
-            mHistoryButton.setOnClickListener(new View.OnClickListener() {
+        if (RecentsDebugFlags.Static.EnableStackActionButton) {
+            float cornerRadius = context.getResources().getDimensionPixelSize(
+                    R.dimen.recents_task_view_rounded_corners_radius);
+            mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button,
+                    this, false);
+            mStackActionButton.forceHasOverlappingRendering(false);
+            mStackActionButton.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    EventBus.getDefault().send(new ToggleHistoryEvent());
+                    EventBus.getDefault().send(new DismissAllTaskViewsEvent());
                 }
             });
-            addView(mHistoryButton);
-            mHistoryButton.setClipToOutline(true);
-            mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
+            addView(mStackActionButton);
+            mStackActionButton.setClipToOutline(true);
+            mStackActionButton.setOutlineProvider(new ViewOutlineProvider() {
                 @Override
                 public void getOutline(View view, Outline outline) {
                     outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
                 }
             });
         }
-        mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+        mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
-
-        setBackground(mBackgroundScrim);
     }
 
-    /** Set/get the bsp root node */
-    public void setTaskStack(TaskStack stack) {
+    /**
+     * Called from RecentsActivity when it is relaunched.
+     */
+    public void onReload(boolean isResumingFromVisible, boolean isTaskStackEmpty) {
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
-        mStack = stack;
-        if (launchState.launchedReuseTaskStackViews) {
-            if (mTaskStackView != null) {
-                // If onRecentsHidden is not triggered, we need to the stack view again here
-                mTaskStackView.reset();
-                mTaskStackView.setStack(stack);
-            } else {
-                mTaskStackView = new TaskStackView(getContext(), stack);
-                addView(mTaskStackView);
-            }
-        } else {
-            if (mTaskStackView != null) {
-                removeView(mTaskStackView);
-            }
-            mTaskStackView = new TaskStackView(getContext(), stack);
+
+        if (mTaskStackView == null) {
+            isResumingFromVisible = false;
+            mTaskStackView = new TaskStackView(getContext());
+            mTaskStackView.setSystemInsets(mSystemInsets);
             addView(mTaskStackView);
         }
 
-        // If we are already occluded by the app, then just set the default background scrim now.
-        // Otherwise, defer until the enter animation completes to animate the scrim with the
-        // tasks for the home animation.
-        if (launchState.launchedWhileDocking || launchState.launchedFromAppWithThumbnail
-                || mStack.getTaskCount() == 0) {
-            mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+        // Reset the state
+        mAwaitingFirstLayout = !isResumingFromVisible;
+        mLastTaskLaunchedWasFreeform = false;
+
+        // Update the stack
+        mTaskStackView.onReload(isResumingFromVisible);
+
+        if (isResumingFromVisible) {
+            // If we are already visible, then restore the background scrim
+            animateBackgroundScrim(1f, DEFAULT_UPDATE_SCRIM_DURATION);
         } else {
-            mBackgroundScrim.setAlpha(0);
+            // If we are already occluded by the app, then set the final background scrim alpha now.
+            // Otherwise, defer until the enter animation completes to animate the scrim alpha with
+            // the tasks for the home animation.
+            if (launchState.launchedViaDockGesture || launchState.launchedFromApp
+                    || isTaskStackEmpty) {
+                mBackgroundScrim.setAlpha(255);
+            } else {
+                mBackgroundScrim.setAlpha(0);
+            }
         }
+    }
+
+    /**
+     * Called from RecentsActivity when the task stack is updated.
+     */
+    public void updateStack(TaskStack stack) {
+        mStack = stack;
+        mTaskStackView.setTasks(stack, true /* allowNotifyStackChanges */);
 
         // Update the top level view's visibilities
         if (stack.getTaskCount() > 0) {
             hideEmptyView();
         } else {
-            showEmptyView();
+            showEmptyView(R.string.recents_empty_message);
         }
+    }
 
-        // Trigger a new layout
-        requestLayout();
+    /**
+     * Returns the current TaskStack.
+     */
+    public TaskStack getStack() {
+        return mStack;
+    }
+
+    /*
+     * Returns the window background scrim.
+     */
+    public Drawable getBackgroundScrim() {
+        return mBackgroundScrim;
     }
 
     /**
@@ -217,43 +232,6 @@
         return mLastTaskLaunchedWasFreeform;
     }
 
-    /**
-     * Returns whether the history is visible or not.
-     */
-    public boolean isHistoryVisible() {
-        return mHistoryView != null && mHistoryView.isVisible();
-    }
-
-    /**
-     * Returns the currently set task stack.
-     */
-    public TaskStack getTaskStack() {
-        return mStack;
-    }
-
-    /** Gets the next task in the stack - or if the last - the top task */
-    public Task getNextTaskOrTopTask(Task taskToSearch) {
-        Task returnTask = null;
-        boolean found = false;
-        if (mTaskStackView != null) {
-            TaskStack stack = mTaskStackView.getStack();
-            ArrayList<Task> taskList = stack.getStackTasks();
-            // Iterate the stack views and try and find the focused task
-            for (int j = taskList.size() - 1; j >= 0; --j) {
-                Task task = taskList.get(j);
-                // Return the next task in the line.
-                if (found)
-                    return task;
-                // Remember the first possible task as the top task.
-                if (returnTask == null)
-                    returnTask = task;
-                if (task == taskToSearch)
-                    found = true;
-            }
-        }
-        return returnTask;
-    }
-
     /** Launches the focused task from the first stack if possible */
     public boolean launchFocusedTask(int logEvent) {
         if (mTaskStackView != null) {
@@ -306,36 +284,16 @@
         return false;
     }
 
-    /** Adds the search bar */
-    public void setSearchBar(RecentsAppWidgetHostView searchBar) {
-        // Remove the previous search bar if one exists
-        if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
-            removeView(mSearchBar);
-        }
-        // Add the new search bar
-        if (searchBar != null) {
-            mSearchBar = searchBar;
-            addView(mSearchBar);
-        }
-    }
-
-    /** Returns whether there is currently a search bar */
-    public boolean hasValidSearchBar() {
-        return mSearchBar != null && !mSearchBar.isReinflateRequired();
-    }
-
     /**
      * Hides the task stack and shows the empty view.
      */
-    public void showEmptyView() {
-        if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
-            mSearchBar.setVisibility(View.INVISIBLE);
-        }
+    public void showEmptyView(int msgResId) {
         mTaskStackView.setVisibility(View.INVISIBLE);
+        mEmptyView.setText(msgResId);
         mEmptyView.setVisibility(View.VISIBLE);
         mEmptyView.bringToFront();
-        if (RecentsDebugFlags.Static.EnableHistory) {
-            mHistoryButton.bringToFront();
+        if (RecentsDebugFlags.Static.EnableStackActionButton) {
+            mStackActionButton.bringToFront();
         }
     }
 
@@ -345,15 +303,9 @@
     public void hideEmptyView() {
         mEmptyView.setVisibility(View.INVISIBLE);
         mTaskStackView.setVisibility(View.VISIBLE);
-        if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
-            mSearchBar.setVisibility(View.VISIBLE);
-        }
         mTaskStackView.bringToFront();
-        if (mSearchBar != null) {
-            mSearchBar.bringToFront();
-        }
-        if (RecentsDebugFlags.Static.EnableHistory) {
-            mHistoryButton.bringToFront();
+        if (RecentsDebugFlags.Static.EnableStackActionButton) {
+            mStackActionButton.bringToFront();
         }
     }
 
@@ -376,51 +328,25 @@
      */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        RecentsConfiguration config = Recents.getConfiguration();
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
-        // Get the search bar bounds and measure the search bar layout
-        Rect searchBarSpaceBounds = new Rect();
-        if (mSearchBar != null) {
-            config.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
-                    searchBarSpaceBounds);
-            mSearchBar.measure(
-                    MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
-        }
-
-        Rect taskStackBounds = new Rect();
-        config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
-                mSystemInsets.right, searchBarSpaceBounds, taskStackBounds);
-        if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
-            mTaskStackView.setTaskStackBounds(taskStackBounds, mSystemInsets);
+        if (mTaskStackView.getVisibility() != GONE) {
             mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
         }
 
         // Measure the empty view to the full size of the screen
         if (mEmptyView.getVisibility() != GONE) {
-            measureChild(mEmptyView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+            measureChild(mEmptyView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
         }
 
-        if (RecentsDebugFlags.Static.EnableHistory) {
-            // Measure the history view
-            if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
-                measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-            }
-
-            // Measure the history button within the constraints of the space above the stack
-            Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
-            measureChild(mHistoryButton,
-                    MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
-                    MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
-            if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
-                measureChild(mHistoryClearAllButton,
-                    MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
-                    MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
-            }
+        if (RecentsDebugFlags.Static.EnableStackActionButton) {
+            // Measure the stack action button within the constraints of the space above the stack
+            Rect buttonBounds = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
+            measureChild(mStackActionButton,
+                    MeasureSpec.makeMeasureSpec(buttonBounds.width(), MeasureSpec.AT_MOST),
+                    MeasureSpec.makeMeasureSpec(buttonBounds.height(), MeasureSpec.AT_MOST));
         }
 
         setMeasuredDimension(width, height);
@@ -431,60 +357,29 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        RecentsConfiguration config = Recents.getConfiguration();
-
-        // Get the search bar bounds so that we lay it out
-        Rect measuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
-        Rect searchBarSpaceBounds = new Rect();
-        if (mSearchBar != null) {
-            config.getSearchBarBounds(measuredRect,
-                    mSystemInsets.top, searchBarSpaceBounds);
-            mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
-                    searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
-        }
-
-        if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
+        if (mTaskStackView.getVisibility() != GONE) {
             mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
         }
 
         // Layout the empty view
         if (mEmptyView.getVisibility() != GONE) {
-            mEmptyView.layout(left, top, right, bottom);
+            int leftRightInsets = mSystemInsets.left + mSystemInsets.right;
+            int topBottomInsets = mSystemInsets.top + mSystemInsets.bottom;
+            int childWidth = mEmptyView.getMeasuredWidth();
+            int childHeight = mEmptyView.getMeasuredHeight();
+            int childLeft = left + mSystemInsets.left +
+                    Math.max(0, (right - left - leftRightInsets - childWidth)) / 2;
+            int childTop = top + mSystemInsets.top +
+                    Math.max(0, (bottom - top - topBottomInsets - childHeight)) / 2;
+            mEmptyView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
         }
 
-        if (RecentsDebugFlags.Static.EnableHistory) {
-            // Layout the history view
-            if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
-                mHistoryView.layout(left, top, right, bottom);
-            }
-
-            // Layout the history button such that its drawable is start-aligned with the stack,
-            // vertically centered in the available space above the stack
-            Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
-            int historyLeft = isLayoutRtl()
-                    ? historyButtonRect.right + mHistoryButton.getPaddingStart()
-                    - mHistoryButton.getMeasuredWidth()
-                    : historyButtonRect.left - mHistoryButton.getPaddingStart();
-            int historyTop = historyButtonRect.top +
-                    (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
-            mHistoryButton.layout(historyLeft, historyTop,
-                    historyLeft + mHistoryButton.getMeasuredWidth(),
-                    historyTop + mHistoryButton.getMeasuredHeight());
-
-            // Layout the history clear all button such that it is end-aligned with the stack,
-            // vertically centered in the available space above the stack
-            if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
-                int clearAllLeft = isLayoutRtl()
-                        ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
-                        : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
-                        - mHistoryClearAllButton.getMeasuredWidth();
-                int clearAllTop = historyButtonRect.top +
-                        (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) /
-                                2;
-                mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
-                        clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
-                        clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
-            }
+        if (RecentsDebugFlags.Static.EnableStackActionButton) {
+            // Layout the stack action button such that its drawable is start-aligned with the
+            // stack, vertically centered in the available space above the stack
+            Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+            mStackActionButton.layout(buttonBounds.left, buttonBounds.top, buttonBounds.right,
+                    buttonBounds.bottom);
         }
 
         if (mAwaitingFirstLayout) {
@@ -504,6 +399,7 @@
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mSystemInsets.set(insets.getSystemWindowInsets());
+        mTaskStackView.setSystemInsets(mSystemInsets);
         requestLayout();
         return insets;
     }
@@ -553,9 +449,9 @@
 
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
         int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
-        if (RecentsDebugFlags.Static.EnableHistory) {
-            // Hide the history button
-            hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+        if (RecentsDebugFlags.Static.EnableStackActionButton) {
+            // Hide the stack action button
+            hideStackActionButton(taskViewExitToHomeDuration, false /* translate */);
         }
         animateBackgroundScrim(0f, taskViewExitToHomeDuration);
     }
@@ -577,6 +473,17 @@
                     false /* isDefaultDockState */, -1, true /* animateAlpha */,
                     true /* animateBounds */);
         }
+        if (mStackActionButton != null) {
+            event.addPostAnimationCallback(new Runnable() {
+                @Override
+                public void run() {
+                    // Move the clear all button to its new position
+                    Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+                    mStackActionButton.setLeftTopRightBottom(buttonBounds.left, buttonBounds.top,
+                            buttonBounds.right, buttonBounds.bottom);
+                }
+            });
+        }
     }
 
     public final void onBusEvent(final DragEndEvent event) {
@@ -604,30 +511,30 @@
             event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
                     taskViewRect.right, taskViewRect.bottom);
 
-            // Remove the task view after it is docked
-            mTaskStackView.updateLayoutAlgorithm(false /* boundScroll */);
-            stackLayout.getStackTransform(event.task, stackScroller.getStackScroll(), tmpTransform,
-                    null);
-            tmpTransform.alpha = 0;
-            tmpTransform.scale = 1f;
-            tmpTransform.rect.set(taskViewRect);
-            mTaskStackView.updateTaskViewToTransform(event.taskView, tmpTransform,
-                    new AnimationProps(125, Interpolators.ALPHA_OUT,
-                            new AnimatorListenerAdapter() {
-                                @Override
-                                public void onAnimationEnd(Animator animation) {
-                                    // Dock the task and launch it
-                                    SystemServicesProxy ssp = Recents.getSystemServices();
-                                    ssp.startTaskInDockedMode(getContext(), event.taskView,
-                                            event.task.key.id, dockState.createMode);
+            final OnAnimationStartedListener startedListener = new OnAnimationStartedListener() {
+                @Override
+                public void onAnimationStarted() {
+                    EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
+                    mTaskStackView.getStack().removeTask(event.task, AnimationProps.IMMEDIATE,
+                            true /* fromDockGesture */);
+                }
+            };
 
-                                    // Animate the stack accordingly
-                                    AnimationProps stackAnim = new AnimationProps(
-                                            TaskStackView.DEFAULT_SYNC_STACK_DURATION,
-                                            Interpolators.FAST_OUT_SLOW_IN);
-                                    mTaskStackView.getStack().removeTask(event.task, stackAnim);
-                                }
-                            }));
+            // Dock the task and launch it
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode);
+            final Rect taskRect = getTaskRect(event.taskView);
+            IAppTransitionAnimationSpecsFuture future = mTransitionHelper.getAppTransitionFuture(
+                    new AnimationSpecComposer() {
+                        @Override
+                        public List<AppTransitionAnimationSpec> composeSpecs() {
+                            return mTransitionHelper.composeDockAnimationSpec(
+                                    event.taskView, taskRect);
+                        }
+                    });
+            ssp.overridePendingAppTransitionMultiThumbFuture(future,
+                    mTransitionHelper.wrapStartedListener(startedListener),
+                    true /* scaleUp */);
 
             MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP);
         } else {
@@ -637,6 +544,15 @@
         }
     }
 
+    private Rect getTaskRect(TaskView taskView) {
+        int[] location = taskView.getLocationOnScreen();
+        int viewX = location[0];
+        int viewY = location[1];
+        return new Rect(viewX, viewY,
+                (int) (viewX + taskView.getWidth() * taskView.getScaleX()),
+                (int) (viewY + taskView.getHeight() * taskView.getScaleY()));
+    }
+
     public final void onBusEvent(DraggingInRecentsEvent event) {
         if (mTaskStackView.getTaskViews().size() > 0) {
             setTranslationY(event.distanceFromTop - mTaskStackView.getTaskViews().get(0).getY());
@@ -662,181 +578,71 @@
         animator.start();
     }
 
-    public final void onBusEvent(TaskStackUpdatedEvent event) {
-        mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
-        mStack.createAffiliatedGroupings(getContext());
-    }
-
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-        if (!launchState.launchedWhileDocking && !launchState.launchedFromAppWithThumbnail
+        if (!launchState.launchedViaDockGesture && !launchState.launchedFromApp
                 && mStack.getTaskCount() > 0) {
-            animateBackgroundScrim(DEFAULT_SCRIM_ALPHA,
+            animateBackgroundScrim(1f,
                     TaskStackAnimationHelper.ENTER_FROM_HOME_TRANSLATION_DURATION);
         }
     }
 
-    public final void onBusEvent(UpdateBackgroundScrimEvent event) {
-        animateBackgroundScrim(event.alpha, DEFAULT_UPDATE_SCRIM_DURATION);
+    public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+        hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */);
     }
 
-    public final void onBusEvent(ResetBackgroundScrimEvent event) {
-        animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
-    }
-
-    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
-        if (!event.visible) {
-            // Reset the view state
-            mAwaitingFirstLayout = true;
-            mLastTaskLaunchedWasFreeform = false;
-            if (RecentsDebugFlags.Static.EnableHistory) {
-                hideHistoryButton(0, false /* translate */);
-            }
+    public final void onBusEvent(DismissAllTaskViewsEvent event) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (!ssp.hasDockedTask()) {
+            // Animate the background away only if we are dismissing Recents to home
+            animateBackgroundScrim(0f, DEFAULT_UPDATE_SCRIM_DURATION);
         }
     }
 
-    public final void onBusEvent(ToggleHistoryEvent event) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
+    public final void onBusEvent(ShowStackActionButtonEvent event) {
+        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
             return;
         }
 
-        if (mHistoryView != null && mHistoryView.isVisible()) {
-            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
-        } else {
-            EventBus.getDefault().send(new ShowHistoryEvent());
-        }
+        showStackActionButton(SHOW_STACK_ACTION_BUTTON_DURATION, event.translate);
     }
 
-    public final void onBusEvent(ShowHistoryEvent event) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
+    public final void onBusEvent(HideStackActionButtonEvent event) {
+        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
             return;
         }
 
-        if (mHistoryView == null) {
-            LayoutInflater inflater = LayoutInflater.from(getContext());
-            mHistoryView = (RecentsHistoryView) inflater.inflate(R.layout.recents_history, this,
-                    false);
-            addView(mHistoryView);
-
-            final float cornerRadius = getResources().getDimensionPixelSize(
-                    R.dimen.recents_task_view_rounded_corners_radius);
-            mHistoryClearAllButton = (TextView) inflater.inflate(
-                    R.layout.recents_history_clear_all_button, this, false);
-            mHistoryClearAllButton.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    EventBus.getDefault().send(new ClearHistoryEvent());
-                }
-            });
-            mHistoryClearAllButton.setClipToOutline(true);
-            mHistoryClearAllButton.setOutlineProvider(new ViewOutlineProvider() {
-                @Override
-                public void getOutline(View view, Outline outline) {
-                    outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
-                }
-            });
-            addView(mHistoryClearAllButton);
-
-            // Since this history view is inflated by a view stub after the insets have already
-            // been applied, we have to set them ourselves initial from the insets that were last
-            // provided.
-            mHistoryView.setSystemInsets(mSystemInsets);
-            mHistoryView.setHeaderHeight(mHistoryButton.getMeasuredHeight());
-            mHistoryButton.bringToFront();
-            mHistoryClearAllButton.bringToFront();
-        }
-
-        // Animate the empty view in parallel with the history view (the task view animations are
-        // handled in TaskStackView)
-        Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
-        if (mEmptyView.getVisibility() == View.VISIBLE) {
-            int historyTransitionDuration = getResources().getInteger(
-                    R.integer.recents_history_transition_duration);
-            mEmptyView.animate()
-                    .alpha(0f)
-                    .translationY(stackRect.height() / 2)
-                    .setDuration(historyTransitionDuration)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .withEndAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mEmptyView.setVisibility(View.INVISIBLE);
-                        }
-                    })
-                    .start();
-        }
-
-        mHistoryView.show(mStack, stackRect.height(), mHistoryClearAllButton);
-    }
-
-    public final void onBusEvent(HideHistoryEvent event) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
-            return;
-        }
-
-        // Animate the empty view in parallel with the history view (the task view animations are
-        // handled in TaskStackView)
-        Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
-        if (mStack.getTaskCount() == 0) {
-            int historyTransitionDuration = getResources().getInteger(
-                    R.integer.recents_history_transition_duration);
-            mEmptyView.setVisibility(View.VISIBLE);
-            mEmptyView.animate()
-                    .alpha(1f)
-                    .translationY(0)
-                    .setDuration(historyTransitionDuration)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .start();
-        }
-
-        mHistoryView.hide(event.animate, stackRect.height(), mHistoryClearAllButton);
-    }
-
-    public final void onBusEvent(ShowHistoryButtonEvent event) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
-            return;
-        }
-
-        showHistoryButton(150, event.translate);
-    }
-
-    public final void onBusEvent(HideHistoryButtonEvent event) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
-            return;
-        }
-
-        hideHistoryButton(100, true /* translate */);
+        hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */);
     }
 
     /**
-     * Shows the history button.
+     * Shows the stack action button.
      */
-    private void showHistoryButton(final int duration, final boolean translate) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
+    private void showStackActionButton(final int duration, final boolean translate) {
+        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
             return;
         }
 
         final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
-        if (mHistoryButton.getVisibility() == View.INVISIBLE) {
-            mHistoryButton.setVisibility(View.VISIBLE);
-            mHistoryButton.setAlpha(0f);
+        if (mStackActionButton.getVisibility() == View.INVISIBLE) {
+            mStackActionButton.setVisibility(View.VISIBLE);
+            mStackActionButton.setAlpha(0f);
             if (translate) {
-                mHistoryButton.setTranslationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+                mStackActionButton.setTranslationY(-mStackActionButton.getMeasuredHeight() * 0.25f);
             } else {
-                mHistoryButton.setTranslationY(0f);
+                mStackActionButton.setTranslationY(0f);
             }
             postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
                 @Override
                 public void run() {
                     if (translate) {
-                        mHistoryButton.animate()
+                        mStackActionButton.animate()
                             .translationY(0f);
                     }
-                    mHistoryButton.animate()
+                    mStackActionButton.animate()
                             .alpha(1f)
                             .setDuration(duration)
                             .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                            .withLayer()
                             .start();
                 }
             });
@@ -845,44 +651,43 @@
     }
 
     /**
-     * Hides the history button.
+     * Hides the stack action button.
      */
-    private void hideHistoryButton(int duration, boolean translate) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
+    private void hideStackActionButton(int duration, boolean translate) {
+        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
             return;
         }
 
         final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
-        hideHistoryButton(duration, translate, postAnimationTrigger);
+        hideStackActionButton(duration, translate, postAnimationTrigger);
         postAnimationTrigger.flushLastDecrementRunnables();
     }
 
     /**
-     * Hides the history button.
+     * Hides the stack action button.
      */
-    private void hideHistoryButton(int duration, boolean translate,
-            final ReferenceCountedTrigger postAnimationTrigger) {
-        if (!RecentsDebugFlags.Static.EnableHistory) {
+    private void hideStackActionButton(int duration, boolean translate,
+                                       final ReferenceCountedTrigger postAnimationTrigger) {
+        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
             return;
         }
 
-        if (mHistoryButton.getVisibility() == View.VISIBLE) {
+        if (mStackActionButton.getVisibility() == View.VISIBLE) {
             if (translate) {
-                mHistoryButton.animate()
-                    .translationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+                mStackActionButton.animate()
+                    .translationY(-mStackActionButton.getMeasuredHeight() * 0.25f);
             }
-            mHistoryButton.animate()
+            mStackActionButton.animate()
                     .alpha(0f)
                     .setDuration(duration)
                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                     .withEndAction(new Runnable() {
                         @Override
                         public void run() {
-                            mHistoryButton.setVisibility(View.INVISIBLE);
+                            mStackActionButton.setVisibility(View.INVISIBLE);
                             postAnimationTrigger.decrement();
                         }
                     })
-                    .withLayer()
                     .start();
             postAnimationTrigger.increment();
         }
@@ -926,13 +731,31 @@
      */
     private void animateBackgroundScrim(float alpha, int duration) {
         Utilities.cancelAnimationWithoutCallbacks(mBackgroundScrimAnimator);
-        int alphaInt = (int) (alpha * 255);
+        // Calculate the absolute alpha to animate from
+        int fromAlpha = (int) ((mBackgroundScrim.getAlpha() / (DEFAULT_SCRIM_ALPHA * 255)) * 255);
+        int toAlpha = (int) (alpha * 255);
         mBackgroundScrimAnimator = ObjectAnimator.ofInt(mBackgroundScrim, Utilities.DRAWABLE_ALPHA,
-                mBackgroundScrim.getAlpha(), alphaInt);
+                fromAlpha, toAlpha);
         mBackgroundScrimAnimator.setDuration(duration);
-        mBackgroundScrimAnimator.setInterpolator(alphaInt > mBackgroundScrim.getAlpha()
-                ? Interpolators.ALPHA_OUT
-                : Interpolators.ALPHA_IN);
+        mBackgroundScrimAnimator.setInterpolator(toAlpha > fromAlpha
+                ? Interpolators.ALPHA_IN
+                : Interpolators.ALPHA_OUT);
         mBackgroundScrimAnimator.start();
     }
+
+    /**
+     * @return the bounds of the stack action button.
+     */
+    private Rect getStackActionButtonBoundsFromStackLayout() {
+        Rect actionButtonRect = new Rect(mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect);
+        int left = isLayoutRtl()
+                ? actionButtonRect.left - mStackActionButton.getPaddingLeft()
+                : actionButtonRect.right + mStackActionButton.getPaddingRight()
+                        - mStackActionButton.getMeasuredWidth();
+        int top = actionButtonRect.top +
+                (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
+        actionButtonRect.set(left, top, left + mStackActionButton.getMeasuredWidth(),
+                top + mStackActionButton.getMeasuredHeight());
+        return actionButtonRect;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 016d937..33d5bb7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.recents.views;
 
+import android.app.ActivityManager;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
+import android.widget.Toast;
 
+import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
@@ -147,12 +150,17 @@
         mTaskView.setTranslationY(y);
 
         mVisibleDockStates.clear();
-        if (!ssp.hasDockedTask() && mRv.getTaskStack().getTaskCount() > 1) {
-            // Add the dock state drop targets (these take priority)
-            TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
-            for (TaskStack.DockState dockState : dockStates) {
-                registerDropTargetForCurrentDrag(dockState);
-                mVisibleDockStates.add(dockState);
+        if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()) {
+            if (!event.task.isDockable) {
+                Toast.makeText(mRv.getContext(), R.string.recents_drag_non_dockable_task_message,
+                        Toast.LENGTH_SHORT).show();
+            } else {
+                // Add the dock state drop targets (these take priority)
+                TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
+                for (TaskStack.DockState dockState : dockStates) {
+                    registerDropTargetForCurrentDrag(dockState);
+                    mVisibleDockStates.add(dockState);
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 1cd0850..07a1d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -16,39 +16,58 @@
 
 package com.android.systemui.recents.views;
 
-import android.app.Activity;
 import android.content.Context;
 import android.view.View;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 
 /** Manages the scrims for the various system bars. */
 public class SystemBarScrimViews {
 
-    Context mContext;
+    private static final int DEFAULT_ANIMATION_DURATION = 150;
 
-    View mNavBarScrimView;
+    private Context mContext;
 
-    boolean mHasNavBarScrim;
-    boolean mShouldAnimateNavBarScrim;
+    private View mNavBarScrimView;
 
-    int mNavBarScrimEnterDuration;
+    private boolean mHasNavBarScrim;
+    private boolean mShouldAnimateNavBarScrim;
 
-    public SystemBarScrimViews(Activity activity) {
+    private int mNavBarScrimEnterDuration;
+
+    public SystemBarScrimViews(RecentsActivity activity) {
         mContext = activity;
         mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
+        mNavBarScrimView.forceHasOverlappingRendering(false);
         mNavBarScrimEnterDuration = activity.getResources().getInteger(
                 R.integer.recents_nav_bar_scrim_enter_duration);
     }
 
     /**
-     * Prepares the scrim views for animating when entering Recents. This will be called before
-     * the first draw.
+     * Updates the nav bar scrim.
      */
-    public void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
+    public void updateNavBarScrim(boolean animateNavBarScrim, boolean hasStackTasks,
+            AnimationProps animation) {
+        prepareEnterRecentsAnimation(isNavBarScrimRequired(hasStackTasks), animateNavBarScrim);
+        if (animateNavBarScrim && animation != null) {
+            animateNavBarScrimVisibility(true, animation);
+        }
+    }
+
+    /**
+     * Prepares the scrim views for animating when entering Recents. This will be called before
+     * the first draw, unless we are updating the scrim on configuration change.
+     */
+    private void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
         mHasNavBarScrim = hasNavBarScrim;
         mShouldAnimateNavBarScrim = animateNavBarScrim;
 
@@ -56,25 +75,49 @@
                 View.VISIBLE : View.INVISIBLE);
     }
 
+    /**
+     * Animates the nav bar scrim visibility.
+     */
+    private void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
+        int toY = 0;
+        if (visible) {
+            mNavBarScrimView.setVisibility(View.VISIBLE);
+            mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
+        } else {
+            toY = mNavBarScrimView.getMeasuredHeight();
+        }
+        if (animation != AnimationProps.IMMEDIATE) {
+            mNavBarScrimView.animate()
+                    .translationY(toY)
+                    .setDuration(animation.getDuration(AnimationProps.BOUNDS))
+                    .setInterpolator(animation.getInterpolator(AnimationProps.BOUNDS))
+                    .start();
+        } else {
+            mNavBarScrimView.setTranslationY(toY);
+        }
+    }
+
+    /**
+     * @return Whether to show the nav bar scrim.
+     */
+    private boolean isNavBarScrimRequired(boolean hasStackTasks) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        return hasStackTasks && !ssp.hasTransposedNavBar() && !ssp.hasDockedTask();
+    }
+
     /**** EventBus events ****/
 
     /**
      * Starts animating the scrim views when entering Recents.
      */
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
-        if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
-            mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
-            mNavBarScrimView.animate()
-                    .translationY(0)
-                    .setDuration(mNavBarScrimEnterDuration)
-                    .setInterpolator(Interpolators.DECELERATE_QUINT)
-                    .withStartAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mNavBarScrimView.setVisibility(View.VISIBLE);
-                        }
-                    })
-                    .start();
+        if (mHasNavBarScrim) {
+            AnimationProps animation = mShouldAnimateNavBarScrim
+                    ? new AnimationProps()
+                            .setDuration(AnimationProps.BOUNDS, mNavBarScrimEnterDuration)
+                            .setInterpolator(AnimationProps.BOUNDS, Interpolators.DECELERATE_QUINT)
+                    : AnimationProps.IMMEDIATE;
+            animateNavBarScrimVisibility(true, animation);
         }
     }
 
@@ -83,13 +126,49 @@
      * going home).
      */
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
-        if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
-            mNavBarScrimView.animate()
-                    .translationY(mNavBarScrimView.getMeasuredHeight())
-                    .setStartDelay(0)
-                    .setDuration(TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .start();
+        if (mHasNavBarScrim) {
+            AnimationProps animation = createBoundsAnimation(
+                    TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
+            animateNavBarScrimVisibility(false, animation);
         }
     }
+
+    public final void onBusEvent(DismissAllTaskViewsEvent event) {
+        if (mHasNavBarScrim) {
+            AnimationProps animation = createBoundsAnimation(
+                    TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
+            animateNavBarScrimVisibility(false, animation);
+        }
+    }
+
+    public final void onBusEvent(ConfigurationChangedEvent event) {
+        animateScrimToCurrentNavBarState(event.hasStackTasks);
+    }
+
+    public final void onBusEvent(MultiWindowStateChangedEvent event) {
+        animateScrimToCurrentNavBarState(event.hasStackTasks);
+    }
+
+    /**
+     * Animates the scrim to match the state of the current nav bar.
+     */
+    private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+        boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
+        if (mHasNavBarScrim != hasNavBarScrim) {
+            AnimationProps animation = hasNavBarScrim
+                    ? createBoundsAnimation(DEFAULT_ANIMATION_DURATION)
+                    : AnimationProps.IMMEDIATE;
+            animateNavBarScrimVisibility(hasNavBarScrim, animation);
+        }
+        mHasNavBarScrim = hasNavBarScrim;
+    }
+
+    /**
+     * @return a default animation to aniamte the bounds of the scrim.
+     */
+    private AnimationProps createBoundsAnimation(int duration) {
+        return new AnimationProps()
+                .setDuration(AnimationProps.BOUNDS, duration)
+                .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 2cd0c19..fe91f42 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -20,8 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Path;
-import android.graphics.RectF;
+import android.util.Log;
 import android.view.View;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
@@ -32,6 +31,7 @@
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
@@ -56,8 +56,8 @@
         /**
          * Callback to start the animation for the launch target {@link TaskView}.
          */
-        void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
-                ReferenceCountedTrigger postAnimationTrigger);
+        void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration,
+                boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger);
 
         /**
          * Callback to start the animation for the launch target {@link TaskView} when it is
@@ -65,12 +65,20 @@
          */
         void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
                 ReferenceCountedTrigger postAnimationTrigger);
+
+        /**
+         * Callback to start the animation for the front {@link TaskView} if there is no launch
+         * target.
+         */
+        void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled);
     }
 
     private static final int FRAME_OFFSET_MS = 16;
 
     public static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
     public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 333;
+    public static final int ENTER_WHILE_DOCKING_DURATION = 150;
+
     private static final PathInterpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
             new PathInterpolator(0, 0, 0, 1f);
     private static final PathInterpolator ENTER_FROM_HOME_ALPHA_INTERPOLATOR =
@@ -90,6 +98,9 @@
     private static final PathInterpolator FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR =
             new PathInterpolator(0.4f, 0, 0.2f, 1f);
 
+    private static final PathInterpolator ENTER_WHILE_DOCKING_INTERPOLATOR =
+            new PathInterpolator(0, 0, 0.2f, 1f);
+
     private TaskStackView mStackView;
 
     private TaskViewTransform mTmpTransform = new TaskViewTransform();
@@ -121,7 +132,9 @@
 
         int offscreenYOffset = stackLayout.mStackRect.height();
         int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
-                R.dimen.recents_task_view_affiliate_group_enter_offset);
+                R.dimen.recents_task_stack_animation_affiliate_enter_offset);
+        int launchedWhileDockingOffset = res.getDimensionPixelSize(
+                R.dimen.recents_task_stack_animation_launched_while_docking_offset);
 
         // Prepare each of the task views for their enter animation from front to back
         List<TaskView> taskViews = mStackView.getTaskViews();
@@ -139,26 +152,26 @@
 
             if (hideTask) {
                 tv.setVisibility(View.INVISIBLE);
-            } else if (launchState.launchedHasConfigurationChanged) {
-                // Just load the views as-is
-            } else if (launchState.launchedFromAppWithThumbnail) {
+            } else if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
                 if (task.isLaunchTarget) {
                     tv.onPrepareLaunchTargetForEnterAnimation();
                 } else if (currentTaskOccludesLaunchTarget) {
                     // Move the task view slightly lower so we can animate it in
-                    RectF bounds = new RectF(mTmpTransform.rect);
-                    bounds.offset(0, taskViewAffiliateGroupEnterOffset);
+                    mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset);
+                    mTmpTransform.alpha = 0f;
+                    mStackView.updateTaskViewToTransform(tv, mTmpTransform,
+                            AnimationProps.IMMEDIATE);
                     tv.setClipViewInStack(false);
-                    tv.setAlpha(0f);
-                    tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top,
-                            (int) bounds.right, (int) bounds.bottom);
                 }
             } else if (launchState.launchedFromHome) {
                 // Move the task view off screen (below) so we can animate it in
-                RectF bounds = new RectF(mTmpTransform.rect);
-                bounds.offset(0, offscreenYOffset);
-                tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
-                        (int) bounds.bottom);
+                mTmpTransform.rect.offset(0, offscreenYOffset);
+                mTmpTransform.alpha = 0f;
+                mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
+            } else if (launchState.launchedViaDockGesture) {
+                mTmpTransform.rect.offset(0, launchedWhileDockingOffset);
+                mTmpTransform.alpha = 0f;
+                mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
             }
         }
     }
@@ -192,6 +205,7 @@
         int taskViewCount = taskViews.size();
         for (int i = taskViewCount - 1; i >= 0; i--) {
             int taskIndexFromFront = taskViewCount - i - 1;
+            int taskIndexFromBack = i;
             final TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
             boolean currentTaskOccludesLaunchTarget = false;
@@ -205,10 +219,11 @@
             stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
                     null);
 
-            if (launchState.launchedFromAppWithThumbnail) {
+            if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
                 if (task.isLaunchTarget) {
-                    tv.onStartLaunchTargetEnterAnimation(taskViewEnterFromAppDuration,
-                            mStackView.mScreenPinningEnabled, postAnimationTrigger);
+                    tv.onStartLaunchTargetEnterAnimation(mTmpTransform,
+                            taskViewEnterFromAppDuration, mStackView.mScreenPinningEnabled,
+                            postAnimationTrigger);
                 } else {
                     // Animate the task up if it was occluding the launch target
                     if (currentTaskOccludesLaunchTarget) {
@@ -218,7 +233,7 @@
                                     @Override
                                     public void onAnimationEnd(Animator animation) {
                                         postAnimationTrigger.decrement();
-                                        tv.setClipViewInStack(false);
+                                        tv.setClipViewInStack(true);
                                     }
                                 });
                         postAnimationTrigger.increment();
@@ -240,6 +255,19 @@
                         .setListener(postAnimationTrigger.decrementOnAnimationEnd());
                 postAnimationTrigger.increment();
                 mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+                if (i == taskViewCount - 1) {
+                    tv.onStartFrontTaskEnterAnimation(mStackView.mScreenPinningEnabled);
+                }
+            } else if (launchState.launchedViaDockGesture) {
+                // Animate the tasks up
+                AnimationProps taskAnimation = new AnimationProps()
+                        .setDuration(AnimationProps.BOUNDS, (int) (ENTER_WHILE_DOCKING_DURATION +
+                                                        (taskIndexFromBack * 2f * FRAME_OFFSET_MS)))
+                        .setInterpolator(AnimationProps.BOUNDS,
+                                ENTER_WHILE_DOCKING_INTERPOLATOR)
+                        .setListener(postAnimationTrigger.decrementOnAnimationEnd());
+                postAnimationTrigger.increment();
+                mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
             }
         }
     }
@@ -250,7 +278,6 @@
     public void startExitToHomeAnimation(boolean animated,
             ReferenceCountedTrigger postAnimationTrigger) {
         TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
-        TaskStackViewScroller stackScroller = mStackView.getScroller();
         TaskStack stack = mStackView.getStack();
 
         // Break early if there are no tasks
@@ -286,8 +313,8 @@
                 taskAnimation = AnimationProps.IMMEDIATE;
             }
 
-            stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
-                    null);
+            mTmpTransform.fillIn(tv);
+            mTmpTransform.alpha = 0f;
             mTmpTransform.rect.offset(0, offscreenYOffset);
             mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
         }
@@ -300,13 +327,11 @@
     public void startLaunchTaskAnimation(TaskView launchingTaskView, boolean screenPinningRequested,
             final ReferenceCountedTrigger postAnimationTrigger) {
         Resources res = mStackView.getResources();
-        TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
-        TaskStackViewScroller stackScroller = mStackView.getScroller();
 
         int taskViewExitToAppDuration = res.getInteger(
                 R.integer.recents_task_exit_to_app_duration);
         int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
-                R.dimen.recents_task_view_affiliate_group_enter_offset);
+                R.dimen.recents_task_stack_animation_affiliate_enter_offset);
 
         Task launchingTask = launchingTaskView.getTask();
         List<TaskView> taskViews = mStackView.getTaskViews();
@@ -319,6 +344,12 @@
 
             if (tv == launchingTaskView) {
                 tv.setClipViewInStack(false);
+                postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+                    @Override
+                    public void run() {
+                        tv.setClipViewInStack(true);
+                    }
+                });
                 tv.onStartLaunchTargetLaunchAnimation(taskViewExitToAppDuration,
                         screenPinningRequested, postAnimationTrigger);
             } else if (currentTaskOccludesLaunchTarget) {
@@ -328,8 +359,7 @@
                         postAnimationTrigger.decrementOnAnimationEnd());
                 postAnimationTrigger.increment();
 
-                stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
-                        null);
+                mTmpTransform.fillIn(tv);
                 mTmpTransform.alpha = 0f;
                 mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset);
                 mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
@@ -340,18 +370,17 @@
     /**
      * Starts the delete animation for the specified {@link TaskView}.
      */
-    public void startDeleteTaskAnimation(Task deleteTask, final TaskView deleteTaskView,
+    public void startDeleteTaskAnimation(final TaskView deleteTaskView,
             final ReferenceCountedTrigger postAnimationTrigger) {
         Resources res = mStackView.getResources();
         TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
-        TaskStackViewScroller stackScroller = mStackView.getScroller();
 
         int taskViewRemoveAnimDuration = res.getInteger(
                 R.integer.recents_animate_task_view_remove_duration);
-        int taskViewRemoveAnimTranslationXPx = res.getDimensionPixelSize(
-                R.dimen.recents_task_view_remove_anim_translation_x);
+        int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
 
-        // Disabling clipping with the stack while the view is animating away
+        // Disabling clipping with the stack while the view is animating away, this will get
+        // restored when the task is next picked up from the view pool
         deleteTaskView.setClipViewInStack(false);
 
         // Compose the new animation and transform and star the animation
@@ -360,72 +389,57 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 postAnimationTrigger.decrement();
-
-                // Re-enable clipping with the stack (we will reuse this view)
-                deleteTaskView.setClipViewInStack(true);
             }
         });
         postAnimationTrigger.increment();
 
-        stackLayout.getStackTransform(deleteTask, stackScroller.getStackScroll(), mTmpTransform,
-                null);
+        mTmpTransform.fillIn(deleteTaskView);
         mTmpTransform.alpha = 0f;
-        mTmpTransform.rect.offset(taskViewRemoveAnimTranslationXPx, 0);
+        mTmpTransform.rect.offset(offscreenXOffset, 0);
         mStackView.updateTaskViewToTransform(deleteTaskView, mTmpTransform, taskAnimation);
     }
 
     /**
-     * Starts the animation to hide the {@link TaskView}s when the history is shown.
+     * Starts the delete animation for all the {@link TaskView}s.
      */
-    public void startShowHistoryAnimation(ReferenceCountedTrigger postAnimationTrigger) {
+    public void startDeleteAllTasksAnimation(final List<TaskView> taskViews,
+                                             final ReferenceCountedTrigger postAnimationTrigger) {
         Resources res = mStackView.getResources();
         TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
-        TaskStackViewScroller stackScroller = mStackView.getScroller();
 
-        int offscreenY = stackLayout.mStackRect.bottom;
-        int historyTransitionDuration = res.getInteger(
-                R.integer.recents_history_transition_duration);
-        int startDelayIncr = 16;
+        int taskViewRemoveAnimDuration = res.getInteger(
+                R.integer.recents_animate_task_views_remove_all_duration);
+        int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
 
-        List<TaskView> taskViews = mStackView.getTaskViews();
         int taskViewCount = taskViews.size();
+        int startDelayMax = 125;
+
         for (int i = taskViewCount - 1; i >= 0; i--) {
             TaskView tv = taskViews.get(i);
-            Task task = tv.getTask();
-            AnimationProps taskAnimation = new AnimationProps(startDelayIncr * i,
-                    historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN,
-                    postAnimationTrigger.decrementOnAnimationEnd());
+            int indexFromFront = taskViewCount - i - 1;
+            float x = Interpolators.ACCELERATE.getInterpolation((float) indexFromFront /
+                    taskViewCount);
+            int startDelay = (int) Utilities.mapRange(x, 0, startDelayMax);
+
+            // Disabling clipping with the stack while the view is animating away
+            tv.setClipViewInStack(false);
+
+            // Compose the new animation and transform and star the animation
+            AnimationProps taskAnimation = new AnimationProps(startDelay,
+                    taskViewRemoveAnimDuration, Interpolators.FAST_OUT_LINEAR_IN,
+                    new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    postAnimationTrigger.decrement();
+
+                    // Re-enable clipping with the stack (we will reuse this view)
+                    tv.setClipViewInStack(true);
+                }
+            });
             postAnimationTrigger.increment();
 
-            stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
-                    null);
-            mTmpTransform.alpha = 0f;
-            mTmpTransform.rect.offsetTo(mTmpTransform.rect.left, offscreenY);
-            mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
-        }
-    }
-
-    /**
-     * Starts the animation to show the {@link TaskView}s when the history is hidden.
-     */
-    public void startHideHistoryAnimation() {
-        Resources res = mStackView.getResources();
-        TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
-        TaskStackViewScroller stackScroller = mStackView.getScroller();
-
-        int historyTransitionDuration = res.getInteger(
-                R.integer.recents_history_transition_duration);
-        int startDelayIncr = 16;
-
-        List<TaskView> taskViews = mStackView.getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            TaskView tv = taskViews.get(i);
-            AnimationProps taskAnimation = new AnimationProps(startDelayIncr * i,
-                    historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN);
-            stackLayout.getStackTransform(tv.getTask(), stackScroller.getStackScroll(),
-                    mTmpTransform, null);
-            mTmpTransform.alpha = 1f;
+            mTmpTransform.fillIn(tv);
+            mTmpTransform.rect.offset(offscreenXOffset, 0);
             mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
         }
     }
@@ -441,11 +455,14 @@
         TaskStackViewScroller stackScroller = mStackView.getScroller();
         TaskStack stack = mStackView.getStack();
 
-        final float newScroll = stackLayout.getStackScrollForTask(newFocusedTask);
-        boolean willScrollToFront = newScroll > stackScroller.getStackScroll();
-        boolean willScroll = Float.compare(newScroll, stackScroller.getStackScroll()) != 0;
+        final float curScroll = stackScroller.getStackScroll();
+        final float newScroll = stackScroller.getBoundedStackScroll(
+                stackLayout.getStackScrollForTask(newFocusedTask));
+        boolean willScrollToFront = newScroll > curScroll;
+        boolean willScroll = Float.compare(newScroll, curScroll) != 0;
 
         // Get the current set of task transforms
+        int taskViewCount = mStackView.getTaskViews().size();
         ArrayList<Task> stackTasks = stack.getStackTasks();
         mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms);
 
@@ -463,6 +480,13 @@
 
         // Focus the task view
         TaskView newFocusedTaskView = mStackView.getChildViewForTask(newFocusedTask);
+        if (newFocusedTaskView == null) {
+            // Log the error if we have no task view, and skip the animation
+            Log.e("TaskStackAnimationHelper", "b/27389156 null-task-view prebind:" + taskViewCount +
+                    " postbind:" + mStackView.getTaskViews().size() + " prescroll:" + curScroll +
+                    " postscroll: " + newScroll);
+            return false;
+        }
         newFocusedTaskView.setFocusedState(true, requestViewFocus);
 
         // Setup the end listener to return all the hidden views to the view pool after the
@@ -476,7 +500,7 @@
         });
 
         List<TaskView> taskViews = mStackView.getTaskViews();
-        int taskViewCount = taskViews.size();
+        taskViewCount = taskViews.size();
         int newFocusTaskViewIndex = taskViews.indexOf(newFocusedTaskView);
         for (int i = 0; i < taskViewCount; i++) {
             TaskView tv = taskViews.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 88bebdb..c16a9be4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -16,31 +16,33 @@
 
 package com.android.systemui.recents.views;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
+import android.annotation.IntDef;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Path;
 import android.graphics.Rect;
-import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.FloatProperty;
-import android.util.Property;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.view.ViewDebug;
 
-import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.misc.FreePathInterpolator;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Used to describe a visible range that can be normalized to [0, 1].
@@ -100,46 +102,42 @@
 }
 
 /**
- * The layout logic for a TaskStackView.  This layout can have two states focused and unfocused,
- * and in the focused state, there is a task that is displayed more prominently in the stack.
+ * The layout logic for a TaskStackView.  This layout needs to be able to calculate the stack layout
+ * without an activity-specific context only with the information passed in.  This layout can have
+ * two states focused and unfocused, and in the focused state, there is a task that is displayed
+ * more prominently in the stack.
  */
 public class TaskStackLayoutAlgorithm {
 
-    // The scale factor to apply to the user movement in the stack to unfocus it
-    private static final float UNFOCUS_MULTIPLIER = 0.8f;
-
     // The distribution of view bounds alpha
     // XXX: This is a hack because you can currently set the max alpha to be > 1f
     public static final float OUTLINE_ALPHA_MIN_VALUE = 0f;
     public static final float OUTLINE_ALPHA_MAX_VALUE = 2f;
 
-    // The distribution of dim to apply to tasks in the stack
-    private static final float DIM_MAX_VALUE = 0.35f;
-    private static final Path UNFOCUSED_DIM_PATH = new Path();
-    private static final Path FOCUSED_DIM_PATH = new Path();
-    static {
-        // The unfocused dim interpolator peaks to 1 at 0.5 (the focused task), then slowly drops
-        // back to 0.5 at the front of the stack
-        UNFOCUSED_DIM_PATH.moveTo(0f, 0f);
-        UNFOCUSED_DIM_PATH.cubicTo(0f, 0.1f, 0.4f, 0.8f, 0.5f, 1f);
-        UNFOCUSED_DIM_PATH.cubicTo(0.6f, 1f, 0.9f, 0.6f, 1f, 0.5f);
-        // The focused dim interpolator peaks to 1 at 0.5 (the focused task), then drops back to 0
-        // at the front of the stack
-        FOCUSED_DIM_PATH.moveTo(0f, 0f);
-        FOCUSED_DIM_PATH.cubicTo(0.1f, 0f, 0.4f, 1f, 0.5f, 1f);
-        FOCUSED_DIM_PATH.cubicTo(0.6f, 1f, 0.9f, 0f, 1f, 0f);
-    }
-    private static final FreePathInterpolator UNFOCUSED_DIM_INTERPOLATOR =
-            new FreePathInterpolator(UNFOCUSED_DIM_PATH);
-    private static final FreePathInterpolator FOCUSED_DIM_INTERPOLATOR =
-            new FreePathInterpolator(FOCUSED_DIM_PATH);
+    // The medium/maximum dim on the tasks
+    private static final float MED_DIM = 0.15f;
+    private static final float MAX_DIM = 0.25f;
 
     // The various focus states
-    public static final float STATE_FOCUSED = 1f;
-    public static final float STATE_UNFOCUSED = 0f;
+    public static final int STATE_FOCUSED = 1;
+    public static final int STATE_UNFOCUSED = 0;
+
+    // The side that an offset is anchored
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FROM_TOP, FROM_BOTTOM})
+    public @interface AnchorSide {}
+    private static final int FROM_TOP = 0;
+    private static final int FROM_BOTTOM = 1;
+
+    // The extent that we care about when calculating fractions
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({WIDTH, HEIGHT})
+    public @interface Extent {}
+    private static final int WIDTH = 0;
+    private static final int HEIGHT = 1;
 
     public interface TaskStackLayoutAlgorithmCallbacks {
-        void onFocusStateChanged(float prevFocusState, float curFocusState);
+        void onFocusStateChanged(int prevFocusState, int curFocusState);
     }
 
     /**
@@ -189,44 +187,28 @@
          * @param taskStackBounds the full rect that the freeform rect can take up
          */
         public void computeRects(Rect freeformRectOut, Rect stackRectOut,
-                Rect taskStackBounds, int widthPadding, int heightPadding, int stackBottomOffset) {
-            int availableHeight = taskStackBounds.height() - stackBottomOffset;
+                Rect taskStackBounds, int topMargin, int freeformGap, int stackBottomOffset) {
+            // The freeform height is the visible height (not including system insets) - padding
+            // above freeform and below stack - gap between the freeform and stack
+            int availableHeight = taskStackBounds.height() - topMargin - stackBottomOffset;
             int ffPaddedHeight = (int) (availableHeight * freeformHeightPct);
-            int ffHeight = Math.max(0, ffPaddedHeight - (2 * heightPadding));
-            freeformRectOut.set(taskStackBounds.left + widthPadding,
-                    taskStackBounds.top + heightPadding,
-                    taskStackBounds.right - widthPadding,
-                    taskStackBounds.top + heightPadding + ffHeight);
-            stackRectOut.set(taskStackBounds.left + widthPadding,
+            int ffHeight = Math.max(0, ffPaddedHeight - freeformGap);
+            freeformRectOut.set(taskStackBounds.left,
+                    taskStackBounds.top + topMargin,
+                    taskStackBounds.right,
+                    taskStackBounds.top + topMargin + ffHeight);
+            stackRectOut.set(taskStackBounds.left,
                     taskStackBounds.top,
-                    taskStackBounds.right - widthPadding,
+                    taskStackBounds.right,
                     taskStackBounds.bottom);
             if (ffPaddedHeight > 0) {
                 stackRectOut.top += ffPaddedHeight;
             } else {
-                stackRectOut.top += heightPadding;
+                stackRectOut.top += topMargin;
             }
         }
     }
 
-    /**
-     * A Property wrapper around the <code>focusState</code> functionality handled by the
-     * {@link TaskStackLayoutAlgorithm#setFocusState(float)} and
-     * {@link TaskStackLayoutAlgorithm#getFocusState()} methods.
-     */
-    private static final Property<TaskStackLayoutAlgorithm, Float> FOCUS_STATE =
-            new FloatProperty<TaskStackLayoutAlgorithm>("focusState") {
-        @Override
-        public void setValue(TaskStackLayoutAlgorithm object, float value) {
-            object.setFocusState(value);
-        }
-
-        @Override
-        public Float get(TaskStackLayoutAlgorithm object) {
-            return object.getFocusState();
-        }
-    };
-
     // A report of the visibility state of the stack
     public class VisibilityReport {
         public int numVisibleTasks;
@@ -246,34 +228,53 @@
     // The task bounds (untransformed) for layout.  This rect is anchored at mTaskRoot.
     @ViewDebug.ExportedProperty(category="recents")
     public Rect mTaskRect = new Rect();
-    // The freeform workspace bounds, inset from the top by the search bar, and is a fixed height
+    // The freeform workspace bounds, inset by the top system insets and is a fixed height
     @ViewDebug.ExportedProperty(category="recents")
     public Rect mFreeformRect = new Rect();
-    // The stack bounds, inset from the top by the search bar, and runs to
-    // the bottom of the screen
+    // The stack bounds, inset from the top system insets, and runs to the bottom of the screen
     @ViewDebug.ExportedProperty(category="recents")
     public Rect mStackRect = new Rect();
     // This is the current system insets
     @ViewDebug.ExportedProperty(category="recents")
     public Rect mSystemInsets = new Rect();
-    // This is the bounds of the history button above the stack rect
+    // This is the bounds of the stack action above the stack rect
     @ViewDebug.ExportedProperty(category="recents")
-    public Rect mHistoryButtonRect = new Rect();
+    public Rect mStackActionButtonRect = new Rect();
 
     // The visible ranges when the stack is focused and unfocused
     private Range mUnfocusedRange;
     private Range mFocusedRange;
 
-    // The offset from the top when scrolled to the top of the stack
+    // The base top margin for the stack from the system insets
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mBaseTopMargin;
+    // The base side margin for the stack from the system insets
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mBaseSideMargin;
+    // The base bottom margin for the stack from the system insets
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mBaseBottomMargin;
+    private int mMinMargin;
+
+    // The gap between the freeform and stack layouts
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mFreeformStackGap;
+
+    // The initial offset that the focused task is from the top
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mInitialTopOffset;
+    private int mBaseInitialTopOffset;
+    // The initial offset that the launch-from task is from the bottom
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mInitialBottomOffset;
+    private int mBaseInitialBottomOffset;
+
+    // The height between the top margin and the top of the focused task
     @ViewDebug.ExportedProperty(category="recents")
     private int mFocusedTopPeekHeight;
+    // The height between the bottom margin and the top of task in front of the focused task
     @ViewDebug.ExportedProperty(category="recents")
-    private int mFocusedBottomTaskPeekHeight;
-
-    // The offset from the top of the stack to the top of the bounds when the stack is scrolled to
-    // the end
-    @ViewDebug.ExportedProperty(category="recents")
-    private int mStackTopOffset;
+    private int mFocusedBottomPeekHeight;
 
     // The offset from the bottom of the stack to the bottom of the bounds when the stack is
     // scrolled to the front
@@ -286,13 +287,20 @@
     private FreePathInterpolator mUnfocusedCurveInterpolator;
     private FreePathInterpolator mFocusedCurveInterpolator;
 
+    // The paths defining the distribution of the dim to apply to tasks in the stack when focused
+    // and unfocused
+    private Path mUnfocusedDimCurve;
+    private Path mFocusedDimCurve;
+    private FreePathInterpolator mUnfocusedDimCurveInterpolator;
+    private FreePathInterpolator mFocusedDimCurveInterpolator;
+
+    // Indexed from the front of the stack, the normalized x in the unfocused range for each task
+    private float[] mInitialNormX;
+
     // The state of the stack focus (0..1), which controls the transition of the stack from the
     // focused to non-focused state
     @ViewDebug.ExportedProperty(category="recents")
-    private float mFocusState;
-
-    // The animator used to reset the focused state
-    private ObjectAnimator mFocusStateAnimator;
+    private int mFocusState;
 
     // The smallest scroll progress, at this value, the back most task will be visible
     @ViewDebug.ExportedProperty(category="recents")
@@ -321,7 +329,8 @@
     int mMaxTranslationZ;
 
     // Optimization, allows for quick lookup of task -> index
-    private ArrayMap<Task.TaskKey, Integer> mTaskIndexMap = new ArrayMap<>();
+    private SparseIntArray mTaskIndexMap = new SparseIntArray();
+    private SparseArray<Float> mTaskIndexOverrideMap = new SparseArray<>();
 
     // The freeform workspace layout
     FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm;
@@ -334,27 +343,61 @@
         Resources res = context.getResources();
         mContext = context;
         mCb = cb;
+        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+        mMinMargin = res.getDimensionPixelSize(R.dimen.recents_layout_min_margin);
+        mBaseTopMargin = getDimensionForDevice(res,
+                R.dimen.recents_layout_top_margin_phone,
+                R.dimen.recents_layout_top_margin_tablet,
+                R.dimen.recents_layout_top_margin_tablet_xlarge);
+        mBaseSideMargin = getDimensionForDevice(res,
+                R.dimen.recents_layout_side_margin_phone,
+                R.dimen.recents_layout_side_margin_tablet,
+                R.dimen.recents_layout_side_margin_tablet_xlarge);
+        mBaseBottomMargin = res.getDimensionPixelSize(R.dimen.recents_layout_bottom_margin);
+        mFreeformStackGap =
+                res.getDimensionPixelSize(R.dimen.recents_freeform_layout_bottom_margin);
 
+        reloadOnConfigurationChange(context);
+    }
+
+    /**
+     * Reloads the layout for the current configuration.
+     */
+    public void reloadOnConfigurationChange(Context context) {
+        Resources res = context.getResources();
         mFocusedRange = new Range(res.getFloat(R.integer.recents_layout_focused_range_min),
                 res.getFloat(R.integer.recents_layout_focused_range_max));
         mUnfocusedRange = new Range(res.getFloat(R.integer.recents_layout_unfocused_range_min),
                 res.getFloat(R.integer.recents_layout_unfocused_range_max));
-        mFocusState = getDefaultFocusState();
-        mFocusedTopPeekHeight =
-                res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size);
-        mFocusedBottomTaskPeekHeight =
-                res.getDimensionPixelSize(R.dimen.recents_layout_focused_bottom_task_peek_size);
-
-        mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
-        mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
-        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+        mFocusState = getInitialFocusState();
+        mFocusedTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_layout_top_peek_size);
+        mFocusedBottomPeekHeight =
+                res.getDimensionPixelSize(R.dimen.recents_layout_bottom_peek_size);
+        mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_layout_z_min);
+        mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_layout_z_max);
+        mBaseInitialTopOffset = getDimensionForDevice(res,
+                R.dimen.recents_layout_initial_top_offset_phone_port,
+                R.dimen.recents_layout_initial_top_offset_phone_land,
+                R.dimen.recents_layout_initial_top_offset_tablet,
+                R.dimen.recents_layout_initial_top_offset_tablet,
+                R.dimen.recents_layout_initial_top_offset_tablet,
+                R.dimen.recents_layout_initial_top_offset_tablet);
+        mBaseInitialBottomOffset = getDimensionForDevice(res,
+                R.dimen.recents_layout_initial_bottom_offset_phone_port,
+                R.dimen.recents_layout_initial_bottom_offset_phone_land,
+                R.dimen.recents_layout_initial_bottom_offset_tablet,
+                R.dimen.recents_layout_initial_bottom_offset_tablet,
+                R.dimen.recents_layout_initial_bottom_offset_tablet,
+                R.dimen.recents_layout_initial_bottom_offset_tablet);
+        mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context);
     }
 
     /**
      * Resets this layout when the stack view is reset.
      */
     public void reset() {
-        setFocusState(getDefaultFocusState());
+        mTaskIndexOverrideMap.clear();
+        setFocusState(getInitialFocusState());
     }
 
     /**
@@ -367,8 +410,8 @@
     /**
      * Sets the focused state.
      */
-    public void setFocusState(float focusState) {
-        float prevFocusState = mFocusState;
+    public void setFocusState(int focusState) {
+        int prevFocusState = mFocusState;
         mFocusState = focusState;
         updateFrontBackTransforms();
         if (mCb != null) {
@@ -379,52 +422,57 @@
     /**
      * Gets the focused state.
      */
-    public float getFocusState() {
+    public int getFocusState() {
         return mFocusState;
     }
 
     /**
-     * Computes the stack and task rects.  The given task stack bounds is the whole bounds not
-     * including the search bar.
+     * Computes the stack and task rects.  The given task stack bounds already has the top/right
+     * insets and left/right padding already applied.
      */
-    public void initialize(Rect taskStackBounds, StackState state) {
-        RecentsConfiguration config = Recents.getConfiguration();
-        int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
-        int heightPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.recents_stack_top_padding);
+    public void initialize(Rect windowRect, Rect taskStackBounds, StackState state) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
         Rect lastStackRect = new Rect(mStackRect);
+        Rect displayRect = ssp.getDisplayRect();
 
-        // The freeform height is the visible height (not including system insets) - padding above
-        // freeform and below stack - gap between the freeform and stack
+        int topMargin = getScaleForExtent(windowRect, displayRect, mBaseTopMargin, mMinMargin, HEIGHT);
+        int bottomMargin = getScaleForExtent(windowRect, displayRect, mBaseBottomMargin, mMinMargin,
+                HEIGHT);
+        mInitialTopOffset = getScaleForExtent(windowRect, displayRect, mBaseInitialTopOffset,
+                mMinMargin, HEIGHT);
+        mInitialBottomOffset = mBaseInitialBottomOffset;
+
+        // Compute the stack bounds
         mState = state;
-        mStackTopOffset = mFocusedTopPeekHeight + heightPadding;
-        mStackBottomOffset = mSystemInsets.bottom + heightPadding;
-        state.computeRects(mFreeformRect, mStackRect, taskStackBounds, widthPadding, heightPadding,
-                mStackBottomOffset);
-        // The history button will take the full un-padded header space above the stack
-        mHistoryButtonRect.set(mStackRect.left, mStackRect.top - heightPadding,
+        mStackBottomOffset = mSystemInsets.bottom + bottomMargin;
+        state.computeRects(mFreeformRect, mStackRect, taskStackBounds, topMargin,
+                mFreeformStackGap, mStackBottomOffset);
+
+        // The stack action button will take the full un-padded header space above the stack
+        mStackActionButtonRect.set(mStackRect.left, mStackRect.top - topMargin,
                 mStackRect.right, mStackRect.top + mFocusedTopPeekHeight);
 
-        // Anchor the task rect to the top-center of the non-freeform stack rect
-        float aspect = (float) (taskStackBounds.width() - mSystemInsets.left - mSystemInsets.right)
-                / (taskStackBounds.height() - mSystemInsets.bottom);
-        int width = mStackRect.width();
-        int minHeight = mStackRect.height() - mFocusedTopPeekHeight - mStackBottomOffset;
-        int height = (int) Math.min(width / aspect, minHeight);
-        mTaskRect.set(mStackRect.left, mStackRect.top,
-                mStackRect.left + width, mStackRect.top + height);
+        // Anchor the task rect top aligned to the non-freeform stack rect
+        float aspect = (float) (windowRect.width() - (mSystemInsets.left + mSystemInsets.right)) /
+                (windowRect.height() - (mSystemInsets.top + mSystemInsets.bottom));
+        int minHeight = mStackRect.height() - mInitialTopOffset - mStackBottomOffset;
+        int height = (int) Math.min(mStackRect.width() / aspect, minHeight);
+        mTaskRect.set(mStackRect.left, mStackRect.top, mStackRect.right, mStackRect.top + height);
 
         // Short circuit here if the stack rects haven't changed so we don't do all the work below
-        if (lastStackRect.equals(mStackRect)) {
-            return;
-        }
+        if (!lastStackRect.equals(mStackRect)) {
+            // Reinitialize the focused and unfocused curves
+            mUnfocusedCurve = constructUnfocusedCurve();
+            mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve);
+            mFocusedCurve = constructFocusedCurve();
+            mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve);
+            mUnfocusedDimCurve = constructUnfocusedDimCurve();
+            mUnfocusedDimCurveInterpolator = new FreePathInterpolator(mUnfocusedDimCurve);
+            mFocusedDimCurve = constructFocusedDimCurve();
+            mFocusedDimCurveInterpolator = new FreePathInterpolator(mFocusedDimCurve);
 
-        // Reinitialize the focused and unfocused curves
-        mUnfocusedCurve = constructUnfocusedCurve();
-        mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve);
-        mFocusedCurve = constructFocusedCurve();
-        mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve);
-        updateFrontBackTransforms();
+            updateFrontBackTransforms();
+        }
     }
 
     /**
@@ -442,7 +490,7 @@
         ArrayList<Task> tasks = stack.getStackTasks();
         if (tasks.isEmpty()) {
             mFrontMostTaskP = 0;
-            mMinScrollP = mMaxScrollP = 0;
+            mMinScrollP = mMaxScrollP = mInitialScrollP = 0;
             mNumStackTasks = mNumFreeformTasks = 0;
             return;
         }
@@ -469,83 +517,156 @@
         int taskCount = stackTasks.size();
         for (int i = 0; i < taskCount; i++) {
             Task task = stackTasks.get(i);
-            mTaskIndexMap.put(task.key, i);
+            mTaskIndexMap.put(task.key.id, i);
         }
 
-        // Calculate the min/max scroll
-        if (getDefaultFocusState() > 0f) {
-            mMinScrollP = 0;
-            mMaxScrollP = Math.max(mMinScrollP, mNumStackTasks - 1);
-        } else {
-            if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
-                mMinScrollP = mMaxScrollP = 0;
-            } else {
-                float bottomOffsetPct = (float) (mStackBottomOffset + mTaskRect.height()) /
-                        mStackRect.height();
-                float normX = mUnfocusedCurveInterpolator.getX(bottomOffsetPct);
-                mMinScrollP = 0;
-                mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
-                        Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
-            }
-        }
-
+        // Update the freeform tasks
         if (!freeformTasks.isEmpty()) {
             mFreeformLayoutAlgorithm.update(freeformTasks, this);
-            mInitialScrollP = mMaxScrollP;
-        } else {
-            Task launchTask = stack.getLaunchTarget();
-            int launchTaskIndex = launchTask != null
-                    ? stack.indexOfStackTask(launchTask)
-                    : mNumStackTasks - 1;
-            if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
-                mInitialScrollP = mMinScrollP;
-            } else if (getDefaultFocusState() > 0f) {
-                if (launchState.launchedFromHome) {
-                    mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
-                } else {
-                    mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP,
-                            mMaxScrollP);
-                }
+        }
+
+        // Calculate the min/max/initial scroll
+        Task launchTask = stack.getLaunchTarget();
+        int launchTaskIndex = launchTask != null
+                ? stack.indexOfStackTask(launchTask)
+                : mNumStackTasks - 1;
+        if (getInitialFocusState() == STATE_FOCUSED) {
+            int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
+            float maxBottomNormX = getNormalizedXFromFocusedY(maxBottomOffset, FROM_BOTTOM);
+            mFocusedRange.offset(0f);
+            mMinScrollP = 0;
+            mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
+                    Math.max(0, mFocusedRange.getAbsoluteX(maxBottomNormX)));
+            if (launchState.launchedFromHome) {
+                mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
             } else {
-                float offsetPct = (float) (mTaskRect.height() / 3) / mStackRect.height();
-                float normX = mUnfocusedCurveInterpolator.getX(offsetPct);
-                mInitialScrollP = Utilities.clamp(launchTaskIndex -
-                        mUnfocusedRange.getAbsoluteX(normX), mMinScrollP, mMaxScrollP);
+                mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
+            }
+            mInitialNormX = null;
+        } else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
+            // If there is one stack task, ignore the min/max/initial scroll positions
+            mMinScrollP = 0;
+            mMaxScrollP = 0;
+            mInitialScrollP = 0;
+            mInitialNormX = null;
+        } else {
+            // Set the max scroll to be the point where the front most task is visible with the
+            // stack bottom offset
+            int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
+            float maxBottomNormX = getNormalizedXFromUnfocusedY(maxBottomOffset, FROM_BOTTOM);
+            mUnfocusedRange.offset(0f);
+            mMinScrollP = 0;
+            mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
+                    Math.max(0, mUnfocusedRange.getAbsoluteX(maxBottomNormX)));
+            boolean scrollToFront = launchState.launchedFromHome ||
+                    launchState.launchedViaDockGesture;
+            if (launchState.launchedWithAltTab) {
+                mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
+                mInitialNormX = null;
+            } else if (scrollToFront) {
+                mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
+                mInitialNormX = null;
+            } else {
+                // We are overriding the initial two task positions, so set the initial scroll
+                // position to match the second task (aka focused task) position
+                float initialTopNormX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
+                mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2))
+                        - Math.max(0, mUnfocusedRange.getAbsoluteX(initialTopNormX)));
+
+                // Set the initial scroll to the predefined state (which differs from the stack)
+                mInitialNormX = new float[] {
+                        getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
+                                FROM_BOTTOM),
+                        initialTopNormX
+                };
             }
         }
     }
 
+    public void updateToInitialState(List<Task> tasks) {
+        if (mInitialNormX == null) {
+            return;
+        }
+
+        mUnfocusedRange.offset(0f);
+        int taskCount = tasks.size();
+        for (int i = taskCount - 1; i >= 0; i--) {
+            int indexFromFront = taskCount - i - 1;
+            if (indexFromFront >= mInitialNormX.length) {
+                break;
+            }
+            float newTaskProgress = mInitialScrollP +
+                    mUnfocusedRange.getAbsoluteX(mInitialNormX[indexFromFront]);
+            mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
+        }
+    }
+
+    /**
+     * Adds and override task progress for the given task when transitioning from focused to
+     * unfocused state.
+     */
+    public void addUnfocusedTaskOverride(Task task, float stackScroll) {
+        if (mFocusState != STATE_UNFOCUSED) {
+            mFocusedRange.offset(stackScroll);
+            mUnfocusedRange.offset(stackScroll);
+            float focusedRangeX = mFocusedRange.getNormalizedX(mTaskIndexMap.get(task.key.id));
+            float focusedY = mFocusedCurveInterpolator.getInterpolation(focusedRangeX);
+            float unfocusedRangeX = mUnfocusedCurveInterpolator.getX(focusedY);
+            float unfocusedTaskProgress = stackScroll + mUnfocusedRange.getAbsoluteX(unfocusedRangeX);
+            if (Float.compare(focusedRangeX, unfocusedRangeX) != 0) {
+                mTaskIndexOverrideMap.put(task.key.id, unfocusedTaskProgress);
+            }
+        }
+    }
+
+    public void clearUnfocusedTaskOverrides() {
+        mTaskIndexOverrideMap.clear();
+    }
+
     /**
      * Updates this stack when a scroll happens.
      */
-    public void updateFocusStateOnScroll(int yMovement) {
-        Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator);
-        if (mFocusState > STATE_UNFOCUSED) {
-            float delta = (float) yMovement / (UNFOCUS_MULTIPLIER * mStackRect.height());
-            setFocusState(mFocusState - Math.min(mFocusState, Math.abs(delta)));
+    public void updateFocusStateOnScroll(float stackScroll, float deltaScroll) {
+        if (deltaScroll == 0f) {
+            return;
         }
-    }
 
-    /**
-     * Aniamtes the focused state back to its orginal state.
-     */
-    public void animateFocusState(float newState) {
-        Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator);
-        if (Float.compare(newState, getFocusState()) != 0) {
-            mFocusStateAnimator = ObjectAnimator.ofFloat(this, FOCUS_STATE, getFocusState(),
-                    newState);
-            mFocusStateAnimator.setDuration(mContext.getResources().getInteger(
-                    R.integer.recents_animate_task_stack_scroll_duration));
-            mFocusStateAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-            mFocusStateAnimator.start();
+        for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) {
+            int taskId = mTaskIndexOverrideMap.keyAt(i);
+            float x = mTaskIndexMap.get(taskId);
+            float overrideX = mTaskIndexOverrideMap.get(taskId, 0f);
+            float newOverrideX = overrideX + deltaScroll;
+            mUnfocusedRange.offset(stackScroll);
+            boolean outOfBounds = mUnfocusedRange.getNormalizedX(newOverrideX) < 0f ||
+                    mUnfocusedRange.getNormalizedX(newOverrideX) > 1f;
+            if (outOfBounds || (overrideX >= x && x >= newOverrideX) ||
+                    (overrideX <= x && x <= newOverrideX)) {
+                // Remove the override once we reach the original task index
+                mTaskIndexOverrideMap.removeAt(i);
+            } else if ((overrideX >= x && deltaScroll <= 0f) ||
+                    (overrideX <= x && deltaScroll >= 0f)) {
+                // Scrolling from override x towards x, then lock the task in place
+                mTaskIndexOverrideMap.put(taskId, newOverrideX);
+            } else {
+                // Scrolling override x away from x, we should still move the scroll towards x
+                float deltaX = overrideX - x;
+                newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - Math.abs(deltaScroll));
+                mTaskIndexOverrideMap.put(taskId, x + newOverrideX);
+            }
         }
     }
 
     /**
      * Returns the default focus state.
      */
-    public float getDefaultFocusState() {
-        return STATE_FOCUSED;
+    public int getInitialFocusState() {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        if (debugFlags.isPagingEnabled() || launchState.launchedWithAltTab) {
+            return STATE_FOCUSED;
+        } else {
+            return STATE_UNFOCUSED;
+        }
     }
 
     /**
@@ -571,6 +692,13 @@
     }
 
     /**
+     * Returns whether this stack layout has been initialized.
+     */
+    public boolean isInitialized() {
+        return !mStackRect.isEmpty();
+    }
+
+    /**
      * Computes the maximum number of visible tasks and thumbnails when the scroll is at the initial
      * stack scroll.  Requires that update() is called first.
      */
@@ -589,10 +717,10 @@
         // Otherwise, walk backwards in the stack and count the number of tasks and visible
         // thumbnails and add that to the total freeform task count
         TaskViewTransform tmpTransform = new TaskViewTransform();
-        Range currentRange = getDefaultFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
+        Range currentRange = getInitialFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
         currentRange.offset(mInitialScrollP);
         int taskBarHeight = mContext.getResources().getDimensionPixelSize(
-                R.dimen.recents_task_bar_height);
+                R.dimen.recents_task_view_header_height);
         int numVisibleTasks = Math.max(mNumFreeformTasks, 1);
         int numVisibleThumbnails = Math.max(mNumFreeformTasks, 1);
         float prevScreenY = Integer.MAX_VALUE;
@@ -612,8 +740,9 @@
 
             boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
             if (isFrontMostTaskInGroup) {
-                getStackTransform(taskProgress, mInitialScrollP, mFocusState, tmpTransform, null,
-                        false /* ignoreSingleTaskCase */, false /* forceUpdate */);
+                getStackTransform(taskProgress, taskProgress, mInitialScrollP, mFocusState,
+                        tmpTransform, null, false /* ignoreSingleTaskCase */,
+                        false /* forceUpdate */);
                 float screenY = tmpTransform.rect.top;
                 boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
                 if (hasVisibleThumbnail) {
@@ -647,22 +776,34 @@
     public TaskViewTransform getStackTransform(Task task, float stackScroll,
             TaskViewTransform transformOut, TaskViewTransform frontTransform) {
         return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
-                false /* forceUpdate */);
+                false /* forceUpdate */, false /* ignoreTaskOverrides */);
     }
 
-    public TaskViewTransform getStackTransform(Task task, float stackScroll, float focusState,
-        TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate) {
+    public TaskViewTransform getStackTransform(Task task, float stackScroll,
+            TaskViewTransform transformOut, TaskViewTransform frontTransform,
+            boolean ignoreTaskOverrides) {
+        return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
+                false /* forceUpdate */, ignoreTaskOverrides);
+    }
+
+    public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState,
+            TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate,
+            boolean ignoreTaskOverrides) {
         if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
             mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
             return transformOut;
         } else {
             // Return early if we have an invalid index
-            if (task == null || !mTaskIndexMap.containsKey(task.key)) {
+            int nonOverrideTaskProgress = mTaskIndexMap.get(task.key.id, -1);
+            if (task == null || nonOverrideTaskProgress == -1) {
                 transformOut.reset();
                 return transformOut;
             }
-            getStackTransform(mTaskIndexMap.get(task.key), stackScroll, focusState, transformOut,
-                    frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
+            float taskProgress = ignoreTaskOverrides
+                    ? nonOverrideTaskProgress
+                    : getStackScrollForTask(task);
+            getStackTransform(taskProgress, nonOverrideTaskProgress, stackScroll, focusState,
+                    transformOut, frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
             return transformOut;
         }
     }
@@ -673,8 +814,9 @@
     public TaskViewTransform getStackTransformScreenCoordinates(Task task, float stackScroll,
             TaskViewTransform transformOut, TaskViewTransform frontTransform) {
         Rect windowRect = Recents.getSystemServices().getWindowRect();
-        TaskViewTransform transform = getStackTransform(task, stackScroll, transformOut,
-                frontTransform);
+        TaskViewTransform transform = getStackTransform(task, stackScroll, mFocusState,
+                transformOut, frontTransform, true /* forceUpdate */,
+                false /* ignoreTaskOverrides */);
         transform.rect.offset(windowRect.left, windowRect.top);
         return transform;
     }
@@ -687,9 +829,9 @@
      *                             internally to ensure that we can calculate the transform for any
      *                             position in the stack.
      */
-    public void getStackTransform(float taskProgress, float stackScroll, float focusState,
-            TaskViewTransform transformOut, TaskViewTransform frontTransform,
-            boolean ignoreSingleTaskCase, boolean forceUpdate) {
+    public void getStackTransform(float taskProgress, float nonOverrideTaskProgress,
+            float stackScroll, int focusState, TaskViewTransform transformOut,
+            TaskViewTransform frontTransform, boolean ignoreSingleTaskCase, boolean forceUpdate) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Compute the focused and unfocused offset
@@ -698,6 +840,8 @@
         mFocusedRange.offset(boundedStackScroll);
         float boundedScrollUnfocusedRangeX = mUnfocusedRange.getNormalizedX(taskProgress);
         float boundedScrollFocusedRangeX = mFocusedRange.getNormalizedX(taskProgress);
+        float boundedScrollUnfocusedNonOverrideRangeX =
+                mUnfocusedRange.getNormalizedX(nonOverrideTaskProgress);
         mUnfocusedRange.offset(stackScroll);
         mFocusedRange.offset(stackScroll);
         boolean unfocusedVisible = mUnfocusedRange.isInRange(taskProgress);
@@ -722,7 +866,7 @@
             // in screen space
             float tmpP = (mMinScrollP - stackScroll) / mNumStackTasks;
             int centerYOffset = (mStackRect.top - mTaskRect.top) +
-                    (mStackRect.height() - mTaskRect.height()) / 2;
+                    (mStackRect.height() - mSystemInsets.bottom - mTaskRect.height()) / 2;
             y = centerYOffset + getYForDeltaP(tmpP, 0);
             z = mMaxTranslationZ;
             dimAlpha = 0f;
@@ -734,16 +878,16 @@
                     unfocusedRangeX)) * mStackRect.height());
             int focusedY = (int) ((1f - mFocusedCurveInterpolator.getInterpolation(
                     focusedRangeX)) * mStackRect.height());
-            float unfocusedDim = 1f - UNFOCUSED_DIM_INTERPOLATOR.getInterpolation(
+            float unfocusedDim = mUnfocusedDimCurveInterpolator.getInterpolation(
                     boundedScrollUnfocusedRangeX);
-            float focusedDim = 1f - FOCUSED_DIM_INTERPOLATOR.getInterpolation(
+            float focusedDim = mFocusedDimCurveInterpolator.getInterpolation(
                     boundedScrollFocusedRangeX);
 
             y = (mStackRect.top - mTaskRect.top) +
                     (int) Utilities.mapRange(focusState, unfocusedY, focusedY);
-            z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
+            z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedNonOverrideRangeX),
                     mMinTranslationZ, mMaxTranslationZ);
-            dimAlpha = DIM_MAX_VALUE * Utilities.mapRange(focusState, unfocusedDim, focusedDim);
+            dimAlpha = Utilities.mapRange(focusState, unfocusedDim, focusedDim);
             viewOutlineAlpha = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
                     OUTLINE_ALPHA_MIN_VALUE, OUTLINE_ALPHA_MAX_VALUE);
         }
@@ -773,8 +917,26 @@
      * stack.
      */
     float getStackScrollForTask(Task t) {
-        if (!mTaskIndexMap.containsKey(t.key)) return 0f;
-        return mTaskIndexMap.get(t.key);
+        return mTaskIndexOverrideMap.get(t.key.id, (float) mTaskIndexMap.get(t.key.id, 0));
+    }
+
+    /**
+     * Returns the original scroll progress to scroll to such that the top of the task is at the top
+     * of the stack.
+     */
+    float getStackScrollForTaskIgnoreOverrides(Task t) {
+        return (float) mTaskIndexMap.get(t.key.id, 0);
+    }
+
+    /**
+     * Returns the scroll progress to scroll to such that the top of the task at the initial top
+     * offset (which is at the task's brightest point).
+     */
+    float getStackScrollForTaskAtInitialOffset(Task t) {
+        float normX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
+        mUnfocusedRange.offset(0f);
+        return Utilities.clamp((float) mTaskIndexMap.get(t.key.id, 0) - Math.max(0,
+                mUnfocusedRange.getAbsoluteX(normX)), mMinScrollP, mMaxScrollP);
     }
 
     /**
@@ -799,6 +961,93 @@
     }
 
     /**
+     * Returns the task stack bounds in the current orientation.  This rect takes into account the
+     * top and right system insets (but not the bottom inset) and left/right paddings, but _not_
+     * the top/bottom padding or insets.
+     */
+    public void getTaskStackBounds(Rect windowRect, int topInset, int rightInset,
+            Rect taskStackBounds) {
+        taskStackBounds.set(windowRect.left, windowRect.top + topInset,
+                windowRect.right - rightInset, windowRect.bottom);
+
+        // Ensure that the new width is at most the smaller display edge size
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        Rect displayRect = ssp.getDisplayRect();
+        int sideMargin = getScaleForExtent(windowRect, displayRect, mBaseSideMargin, mMinMargin,
+                WIDTH);
+        int targetStackWidth = taskStackBounds.width() - 2 * sideMargin;
+        if (ssp.getDisplayOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+            // If we are in landscape, calculate the width of the stack in portrait and ensure that
+            // we are not larger than that size
+            Rect portraitDisplayRect = new Rect(0, 0,
+                    Math.min(displayRect.width(), displayRect.height()),
+                    Math.max(displayRect.width(), displayRect.height()));
+            int portraitSideMargin = getScaleForExtent(portraitDisplayRect, portraitDisplayRect,
+                    mBaseSideMargin, mMinMargin, WIDTH);
+            targetStackWidth = Math.min(targetStackWidth,
+                    portraitDisplayRect.width() - 2 * portraitSideMargin);
+        }
+        taskStackBounds.inset((taskStackBounds.width() - targetStackWidth) / 2, 0);
+    }
+
+    /**
+     * Retrieves resources that are constant regardless of the current configuration of the device.
+     */
+    public static int getDimensionForDevice(Resources res, int phoneResId,
+            int tabletResId, int xlargeTabletResId) {
+        return getDimensionForDevice(res, phoneResId, phoneResId, tabletResId, tabletResId,
+                xlargeTabletResId, xlargeTabletResId);
+    }
+
+    /**
+     * Retrieves resources that are constant regardless of the current configuration of the device.
+     */
+    public static int getDimensionForDevice(Resources res, int phonePortResId, int phoneLandResId,
+            int tabletPortResId, int tabletLandResId, int xlargeTabletPortResId,
+            int xlargeTabletLandResId) {
+        RecentsConfiguration config = Recents.getConfiguration();
+        boolean isLandscape = Recents.getSystemServices().getDisplayOrientation() ==
+                Configuration.ORIENTATION_LANDSCAPE;
+        if (config.isXLargeScreen) {
+            return res.getDimensionPixelSize(isLandscape
+                    ? xlargeTabletLandResId
+                    : xlargeTabletPortResId);
+        } else if (config.isLargeScreen) {
+            return res.getDimensionPixelSize(isLandscape
+                    ? tabletLandResId
+                    : tabletPortResId);
+        } else {
+            return res.getDimensionPixelSize(isLandscape
+                    ? phoneLandResId
+                    : phonePortResId);
+        }
+    }
+
+    /**
+     * Returns the normalized x on the unfocused curve given an absolute Y position (relative to the
+     * stack height).
+     */
+    private float getNormalizedXFromUnfocusedY(float y, @AnchorSide int fromSide) {
+        float offset = (fromSide == FROM_TOP)
+                ? mStackRect.height() - y
+                : y;
+        float offsetPct = offset / mStackRect.height();
+        return mUnfocusedCurveInterpolator.getX(offsetPct);
+    }
+
+    /**
+     * Returns the normalized x on the focused curve given an absolute Y position (relative to the
+     * stack height).
+     */
+    private float getNormalizedXFromFocusedY(float y, @AnchorSide int fromSide) {
+        float offset = (fromSide == FROM_TOP)
+                ? mStackRect.height() - y
+                : y;
+        float offsetPct = offset / mStackRect.height();
+        return mFocusedCurveInterpolator.getX(offsetPct);
+    }
+
+    /**
      * Creates a new path for the focused curve.
      */
     private Path constructFocusedCurve() {
@@ -806,13 +1055,15 @@
         // linear pieces that goes from (0,1) through (0.5, peek height offset),
         // (0.5, bottom task offsets), and (1,0).
         float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
-        float bottomPeekHeightPct = Math.max(
-                mSystemInsets.bottom + mFocusedRange.relativeMax * mFocusedBottomTaskPeekHeight,
-                mStackBottomOffset + mFocusedBottomTaskPeekHeight) / mStackRect.height();
+        float bottomPeekHeightPct = (float) (mStackBottomOffset + mFocusedBottomPeekHeight) /
+                mStackRect.height();
+        float minBottomPeekHeightPct = (float) (mFocusedTopPeekHeight + mTaskRect.height() -
+                mMinMargin) / mStackRect.height();
         Path p = new Path();
         p.moveTo(0f, 1f);
         p.lineTo(0.5f, 1f - topPeekHeightPct);
-        p.lineTo(0.5f + (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct);
+        p.lineTo(1f - (0.5f / mFocusedRange.relativeMax), Math.max(1f - minBottomPeekHeightPct,
+                bottomPeekHeightPct));
         p.lineTo(1f, 0f);
         return p;
     }
@@ -828,20 +1079,65 @@
         // the control point of the second bezier such that between it and a first known point,
         // there is a tangent at (0.5, peek height offset).
         float cpoint1X = 0.4f;
-        float cpoint1Y = 1f;
-        float peekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
-        float slope = ((1f - peekHeightPct) - cpoint1Y) / (0.5f - cpoint1X);
+        float cpoint1Y = 0.975f;
+        float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
+        float slope = ((1f - topPeekHeightPct) - cpoint1Y) / (0.5f - cpoint1X);
         float b = 1f - slope * cpoint1X;
-        float cpoint2X = 0.75f;
+        float cpoint2X = 0.65f;
         float cpoint2Y = slope * cpoint2X + b;
         Path p = new Path();
         p.moveTo(0f, 1f);
-        p.cubicTo(0f, 1f, cpoint1X, 1f, 0.5f, 1f - peekHeightPct);
-        p.cubicTo(0.5f, 1f - peekHeightPct, cpoint2X, cpoint2Y, 1f, 0f);
+        p.cubicTo(0f, 1f, cpoint1X, cpoint1Y, 0.5f, 1f - topPeekHeightPct);
+        p.cubicTo(0.5f, 1f - topPeekHeightPct, cpoint2X, cpoint2Y, 1f, 0f);
         return p;
     }
 
     /**
+     * Creates a new path for the focused dim curve.
+     */
+    private Path constructFocusedDimCurve() {
+        Path p = new Path();
+        // The focused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused
+        // task), then goes back to max dim at the next task
+        p.moveTo(0f, MAX_DIM);
+        p.lineTo(0.5f, 0f);
+        p.lineTo(0.5f + (0.5f / mFocusedRange.relativeMax), MAX_DIM);
+        p.lineTo(1f, MAX_DIM);
+        return p;
+    }
+
+    /**
+     * Creates a new path for the unfocused dim curve.
+     */
+    private Path constructUnfocusedDimCurve() {
+        float focusX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
+        float cpoint2X = focusX + (1f - focusX) / 2;
+        Path p = new Path();
+        // The unfocused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused
+        // task), then goes back to max dim towards the front of the stack
+        p.moveTo(0f, MAX_DIM);
+        p.cubicTo(focusX * 0.5f, MAX_DIM, focusX * 0.75f, MAX_DIM * 0.75f, focusX, 0f);
+        p.cubicTo(cpoint2X, 0f, cpoint2X, MED_DIM, 1f, MED_DIM);
+        return p;
+    }
+
+    /**
+     * Scales the given {@param value} to the scale of the {@param instance} rect relative to the
+     * {@param other} rect in the {@param extent} side.
+     */
+    private int getScaleForExtent(Rect instance, Rect other, int value, int minValue,
+                                  @Extent int extent) {
+        if (extent == WIDTH) {
+            float scale = Utilities.clamp01((float) instance.width() / other.width());
+            return Math.max(minValue, (int) (scale * value));
+        } else if (extent == HEIGHT) {
+            float scale = Utilities.clamp01((float) instance.height() / other.height());
+            return Math.max(minValue, (int) (scale * value));
+        }
+        return value;
+    }
+
+    /**
      * Updates the current transforms that would put a TaskView at the front and back of the stack.
      */
     private void updateFrontBackTransforms() {
@@ -854,9 +1150,9 @@
                 mFocusedRange.relativeMin);
         float max = Utilities.mapRange(mFocusState, mUnfocusedRange.relativeMax,
                 mFocusedRange.relativeMax);
-        getStackTransform(min, 0f, mFocusState, mBackOfStackTransform, null,
+        getStackTransform(min, min, 0f, mFocusState, mBackOfStackTransform, null,
                 true /* ignoreSingleTaskCase */, true /* forceUpdate */);
-        getStackTransform(max, 0f, mFocusState, mFrontOfStackTransform, null,
+        getStackTransform(max, max, 0f, mFocusState, mFrontOfStackTransform, null,
                 true /* ignoreSingleTaskCase */, true /* forceUpdate */);
         mBackOfStackTransform.visible = true;
         mFrontOfStackTransform.visible = true;
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 1707c4f..5416a48 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -22,11 +22,13 @@
 
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.annotation.IntDef;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
@@ -55,24 +57,23 @@
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
-import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
-import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
 import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
-import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
 import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
@@ -84,12 +85,13 @@
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
 import com.android.systemui.recents.misc.DozeTrigger;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -106,20 +108,34 @@
     private final static String KEY_SAVED_STATE_LAYOUT_STACK_SCROLL =
             "saved_instance_state_layout_stack_scroll";
 
-    // The thresholds at which to show/hide the history button.
-    private static final float SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
-    private static final float HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
+    // The thresholds at which to show/hide the stack action button.
+    private static final float SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
+    private static final float HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
 
     public static final int DEFAULT_SYNC_STACK_DURATION = 200;
     private static final int DRAG_SCALE_DURATION = 175;
-    private static final float DRAG_SCALE_FACTOR = 1.05f;
+    static final float DRAG_SCALE_FACTOR = 1.05f;
 
-    private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
+    private static final int LAUNCH_NEXT_SCROLL_BASE_DURATION = 216;
+    private static final int LAUNCH_NEXT_SCROLL_INCR_DURATION = 32;
+
+    // The actions to perform when resetting to initial state,
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({INITIAL_STATE_UPDATE_NONE, INITIAL_STATE_UPDATE_ALL, INITIAL_STATE_UPDATE_LAYOUT_ONLY})
+    public @interface InitialStateAction {}
+    /** Do not update the stack and layout to the initial state. */
+    private static final int INITIAL_STATE_UPDATE_NONE = 0;
+    /** Update both the stack and layout to the initial state. */
+    private static final int INITIAL_STATE_UPDATE_ALL = 1;
+    /** Update only the layout to the initial state. */
+    private static final int INITIAL_STATE_UPDATE_LAYOUT_ONLY = 2;
 
     LayoutInflater mInflater;
-    TaskStack mStack;
+    TaskStack mStack = new TaskStack();
     @ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
     TaskStackLayoutAlgorithm mLayoutAlgorithm;
+    // The stable layout algorithm is only used to calculate the task rect with the stable bounds
+    TaskStackLayoutAlgorithm mStableLayoutAlgorithm;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
     TaskStackViewScroller mStackScroller;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
@@ -148,6 +164,9 @@
     @ViewDebug.ExportedProperty(category="recents")
     boolean mAwaitingFirstLayout = true;
     @ViewDebug.ExportedProperty(category="recents")
+    @InitialStateAction
+    int mInitialState = INITIAL_STATE_UPDATE_ALL;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mInMeasureLayout = false;
     @ViewDebug.ExportedProperty(category="recents")
     boolean mEnterAnimationComplete = false;
@@ -162,13 +181,19 @@
     // The current stack bounds are dynamic and may change as the user drags and drops
     @ViewDebug.ExportedProperty(category="recents")
     private Rect mStackBounds = new Rect();
-
+    // The current window bounds at the point we were measured
     @ViewDebug.ExportedProperty(category="recents")
-    private int[] mTmpVisibleRange = new int[2];
+    private Rect mStableWindowRect = new Rect();
+    // The current window bounds are dynamic and may change as the user drags and drops
+    @ViewDebug.ExportedProperty(category="recents")
+    private Rect mWindowRect = new Rect();
+
     private Rect mTmpRect = new Rect();
     private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
     private List<TaskView> mTmpTaskViews = new ArrayList<>();
     private TaskViewTransform mTmpTransform = new TaskViewTransform();
+    private ArrayList<TaskViewTransform> mTmpTaskTransforms = new ArrayList<>();
+    private int[] mTmpIntPair = new int[2];
 
     // A convenience update listener to request updating clipping of tasks
     private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
@@ -207,16 +232,17 @@
         }
     };
 
-    public TaskStackView(Context context, TaskStack stack) {
+    public TaskStackView(Context context) {
         super(context);
         SystemServicesProxy ssp = Recents.getSystemServices();
         Resources res = context.getResources();
 
         // Set the stack first
-        setStack(stack);
+        mStack.setCallbacks(this);
         mViewPool = new ViewPool<>(context, this);
         mInflater = LayoutInflater.from(context);
         mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this);
+        mStableLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, null);
         mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
         mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
         mAnimationHelper = new TaskStackAnimationHelper(context, this);
@@ -262,22 +288,72 @@
         EventBus.getDefault().unregister(this);
     }
 
-    /** Sets the task stack */
-    void setStack(TaskStack stack) {
-        // Set the new stack
-        mStack = stack;
-        if (mStack != null) {
-            mStack.setCallbacks(this);
+    /**
+     * Called from RecentsActivity when it is relaunched.
+     */
+    void onReload(boolean isResumingFromVisible) {
+        if (!isResumingFromVisible) {
+            // Reset the focused task
+            resetFocusedTask(getFocusedTask());
         }
-        // Layout again with the new stack
+
+        // Reset the state of each of the task views
+        List<TaskView> taskViews = new ArrayList<>();
+        taskViews.addAll(getTaskViews());
+        taskViews.addAll(mViewPool.getViews());
+        for (int i = taskViews.size() - 1; i >= 0; i--) {
+            taskViews.get(i).onReload(isResumingFromVisible);
+        }
+
+        // Reset the stack state
+        readSystemFlags();
+        mTaskViewsClipDirty = true;
+        mEnterAnimationComplete = false;
+        mUIDozeTrigger.stopDozing();
+        if (isResumingFromVisible) {
+            // Animate in the freeform workspace
+            int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
+            animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
+                    Interpolators.FAST_OUT_SLOW_IN));
+        } else {
+            mStackScroller.reset();
+            mStableLayoutAlgorithm.reset();
+            mLayoutAlgorithm.reset();
+        }
+
+        // Since we always animate to the same place in (the initial state), always reset the stack
+        // to the initial state when resuming
+        mAwaitingFirstLayout = true;
+        mInitialState = INITIAL_STATE_UPDATE_ALL;
         requestLayout();
     }
 
+    /**
+     * Sets the stack tasks of this TaskStackView from the given TaskStack.
+     */
+    public void setTasks(TaskStack stack, boolean allowNotifyStackChanges) {
+        boolean isInitialized = mLayoutAlgorithm.isInitialized();
+        // Only notify if we are already initialized, otherwise, everything will pick up all the
+        // new and old tasks when we next layout
+        mStack.setTasks(getContext(), stack.computeAllTasksList(),
+                allowNotifyStackChanges && isInitialized);
+    }
+
     /** Returns the task stack. */
-    TaskStack getStack() {
+    public TaskStack getStack() {
         return mStack;
     }
 
+    /**
+     * Updates this TaskStackView to the initial state.
+     */
+    public void updateToInitialState(boolean scrollToInitialState) {
+        if (scrollToInitialState) {
+            mStackScroller.setStackScrollToInitialState();
+        }
+        mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
+    }
+
     /** Updates the list of task views */
     void updateTaskViewsList() {
         mTaskViews.clear();
@@ -331,37 +407,6 @@
         return null;
     }
 
-    /** Resets this TaskStackView for reuse. */
-    void reset() {
-        // Reset the focused task
-        resetFocusedTask(getFocusedTask());
-
-        // Return all the views to the pool
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            mViewPool.returnViewToPool(taskViews.get(i));
-        }
-
-        // Mark each task view for relayout
-        List<TaskView> poolViews = mViewPool.getViews();
-        for (TaskView tv : poolViews) {
-            tv.reset();
-        }
-
-        // Reset the stack state
-        mStack.reset();
-        mTaskViewsClipDirty = true;
-        mAwaitingFirstLayout = true;
-        mEnterAnimationComplete = false;
-        mUIDozeTrigger.stopDozing();
-        mUIDozeTrigger.resetTrigger();
-        mStackScroller.reset();
-        mLayoutAlgorithm.reset();
-        readSystemFlags();
-        requestLayout();
-    }
-
     /** Returns the stack algorithm for this task stack. */
     public TaskStackLayoutAlgorithm getStackAlgorithm() {
         return mLayoutAlgorithm;
@@ -405,15 +450,17 @@
      *                          target stack scrolls will be returned.
      * @param ignoreTasksSet The set of tasks to skip for purposes of calculaing the visible range.
      *                       Transforms will still be calculated for the ignore tasks.
+     * @return the front and back most visible task indices (there may be non visible tasks in
+     *         between this range)
      */
-    boolean computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
+    int[] computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
             ArrayList<Task> tasks, float curStackScroll, float targetStackScroll,
-            int[] visibleRangeOut, ArraySet<Task.TaskKey> ignoreTasksSet) {
+            ArraySet<Task.TaskKey> ignoreTasksSet, boolean ignoreTaskOverrides) {
         int taskCount = tasks.size();
-        int frontMostVisibleIndex = -1;
-        int backMostVisibleIndex = -1;
+        int[] visibleTaskRange = mTmpIntPair;
+        visibleTaskRange[0] = -1;
+        visibleTaskRange[1] = -1;
         boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0;
-        boolean targetScrollIsInFront = targetStackScroll > curStackScroll;
 
         // We can reuse the task transforms where possible to reduce object allocation
         Utilities.matchTaskListSize(tasks, taskTransforms);
@@ -428,7 +475,7 @@
 
             // Calculate the current and (if necessary) the target transform for the task
             transform = mLayoutAlgorithm.getStackTransform(task, curStackScroll,
-                    taskTransforms.get(i), frontTransform);
+                    taskTransforms.get(i), frontTransform, ignoreTaskOverrides);
             if (useTargetStackScroll && !transform.visible) {
                 // If we have a target stack scroll and the task is not currently visible, then we
                 // just update the transform at the new scroll
@@ -452,40 +499,27 @@
                 continue;
             }
 
-            if (transform.visible) {
-                if (frontMostVisibleIndex < 0) {
-                    frontMostVisibleIndex = i;
-                }
-                backMostVisibleIndex = i;
-            } else if (!targetScrollIsInFront) {
-                if (backMostVisibleIndex != -1) {
-                    // We've reached the end of the visible range, so going down the rest of the
-                    // stack, we can just reset the transforms accordingly
-                    while (i >= 0) {
-                        taskTransforms.get(i).reset();
-                        i--;
-                    }
-                    break;
-                }
-            }
-
             frontTransform = transform;
             frontTransformAtTarget = transformAtTarget;
+            if (transform.visible) {
+                if (visibleTaskRange[0] < 0) {
+                    visibleTaskRange[0] = i;
+                }
+                visibleTaskRange[1] = i;
+            }
         }
-        if (visibleRangeOut != null) {
-            visibleRangeOut[0] = frontMostVisibleIndex;
-            visibleRangeOut[1] = backMostVisibleIndex;
-        }
-        return frontMostVisibleIndex != -1 && backMostVisibleIndex != -1;
+        return visibleTaskRange;
     }
 
     /**
      * Binds the visible {@link TaskView}s at the given target scroll.
-     *
-     * @see #bindVisibleTaskViews(float, ArraySet<Task.TaskKey>)
      */
     void bindVisibleTaskViews(float targetStackScroll) {
-        bindVisibleTaskViews(targetStackScroll, mIgnoreTasks);
+        bindVisibleTaskViews(targetStackScroll, mIgnoreTasks, false /* ignoreTaskOverrides */);
+    }
+
+    void bindVisibleTaskViews(float targetStackScroll, boolean ignoreTaskOverrides) {
+        bindVisibleTaskViews(targetStackScroll, mIgnoreTasks, ignoreTaskOverrides);
     }
 
     /**
@@ -500,15 +534,16 @@
      *                          target stack scroll.
      * @param ignoreTasksSet The set of tasks to ignore in this rebinding of the visible
      *                       {@link TaskView}s
+     * @param ignoreTaskOverrides If set, the visible task computation will get the transforms for
+     *                            tasks at their non-overridden task progress
      */
-    void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet) {
-        final int[] visibleStackRange = mTmpVisibleRange;
-
+    void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet,
+            boolean ignoreTaskOverrides) {
         // Get all the task transforms
-        final ArrayList<Task> tasks = mStack.getStackTasks();
-        final boolean isValidVisibleRange = computeVisibleTaskTransforms(mCurrentTaskTransforms,
-                tasks, mStackScroller.getStackScroll(), targetStackScroll, visibleStackRange,
-                ignoreTasksSet);
+        ArrayList<Task> tasks = mStack.getStackTasks();
+        int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
+                mStackScroller.getStackScroll(), targetStackScroll, ignoreTasksSet,
+                ignoreTaskOverrides);
 
         // Return all the invisible children to the pool
         mTmpTaskViewMap.clear();
@@ -518,15 +553,22 @@
         for (int i = taskViewCount - 1; i >= 0; i--) {
             TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
-            int taskIndex = mStack.indexOfStackTask(task);
 
             // Skip ignored tasks
             if (ignoreTasksSet.contains(task.key)) {
                 continue;
             }
 
-            if (task.isFreeformTask() ||
-                    visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) {
+            // It is possible for the set of lingering TaskViews to differ from the stack if the
+            // stack was updated before the relayout.  If the task view is no longer in the stack,
+            // then just return it back to the view pool.
+            int taskIndex = mStack.indexOfStackTask(task);
+            TaskViewTransform transform = null;
+            if (taskIndex != -1) {
+                transform = mCurrentTaskTransforms.get(taskIndex);
+            }
+
+            if (task.isFreeformTask() || (transform != null && transform.visible)) {
                 mTmpTaskViewMap.put(task.key, tv);
             } else {
                 if (mTouchExplorationEnabled) {
@@ -538,8 +580,7 @@
         }
 
         // Pick up all the newly visible children
-        int lastVisStackIndex = isValidVisibleRange ? visibleStackRange[1] : 0;
-        for (int i = tasks.size() - 1; i >= lastVisStackIndex; i--) {
+        for (int i = tasks.size() - 1; i >= 0; i--) {
             Task task = tasks.get(i);
             TaskViewTransform transform = mCurrentTaskTransforms.get(i);
 
@@ -557,17 +598,14 @@
             if (tv == null) {
                 tv = mViewPool.pickUpViewFromPool(task, task);
                 if (task.isFreeformTask()) {
-                    tv.updateViewPropertiesToTaskTransform(transform, AnimationProps.IMMEDIATE,
-                            mRequestUpdateClippingListener);
+                    updateTaskViewToTransform(tv, transform, AnimationProps.IMMEDIATE);
                 } else {
                     if (transform.rect.top <= mLayoutAlgorithm.mStackRect.top) {
-                        tv.updateViewPropertiesToTaskTransform(
-                                mLayoutAlgorithm.getBackOfStackTransform(),
-                                AnimationProps.IMMEDIATE, mRequestUpdateClippingListener);
+                        updateTaskViewToTransform(tv, mLayoutAlgorithm.getBackOfStackTransform(),
+                                AnimationProps.IMMEDIATE);
                     } else {
-                        tv.updateViewPropertiesToTaskTransform(
-                                mLayoutAlgorithm.getFrontOfStackTransform(),
-                                AnimationProps.IMMEDIATE, mRequestUpdateClippingListener);
+                        updateTaskViewToTransform(tv, mLayoutAlgorithm.getFrontOfStackTransform(),
+                                AnimationProps.IMMEDIATE);
                     }
                 }
             } else {
@@ -584,26 +622,28 @@
 
         // Update the focus if the previous focused task was returned to the view pool
         if (lastFocusedTaskIndex != -1) {
-            if (lastFocusedTaskIndex < visibleStackRange[1]) {
-                setFocusedTask(visibleStackRange[1], false /* scrollToTask */,
+            if (lastFocusedTaskIndex < visibleTaskRange[1]) {
+                setFocusedTask(visibleTaskRange[1], false /* scrollToTask */,
                         true /* requestViewFocus */);
             } else {
-                setFocusedTask(visibleStackRange[0], false /* scrollToTask */,
+                setFocusedTask(visibleTaskRange[0], false /* scrollToTask */,
                         true /* requestViewFocus */);
             }
         }
     }
 
     /**
-     * Relayout the the visible {@link TaskView}s to their current transforms as specified by the
-     * {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any
-     * animations that are current running on those task views, and will ensure that the children
-     * {@link TaskView}s will match the set of visible tasks in the stack.
-     *
-     * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>)
+     * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
      */
     void relayoutTaskViews(AnimationProps animation) {
-        relayoutTaskViews(animation, mIgnoreTasks);
+        relayoutTaskViews(animation, mIgnoreTasks, false /* ignoreTaskOverrides */);
+    }
+
+    /**
+     * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
+     */
+    void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) {
+        relayoutTaskViews(animation, ignoreTasksSet, false /* ignoreTaskOverrides */);
     }
 
     /**
@@ -614,23 +654,22 @@
      *
      * @param ignoreTasksSet the set of tasks to ignore in the relayout
      */
-    void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) {
+    void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
+            boolean ignoreTaskOverrides) {
         // If we had a deferred animation, cancel that
         mDeferredTaskViewLayoutAnimation = null;
 
-        // Cancel all task view animations
-        cancelAllTaskViewAnimations();
-
         // Synchronize the current set of TaskViews
-        bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet);
+        bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet,
+                ignoreTaskOverrides /* ignoreTaskOverrides */);
 
         // Animate them to their final transforms with the given animation
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
         for (int i = 0; i < taskViewCount; i++) {
-            final TaskView tv = taskViews.get(i);
-            final int taskIndex = mStack.indexOfStackTask(tv.getTask());
-            final TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
+            TaskView tv = taskViews.get(i);
+            int taskIndex = mStack.indexOfStackTask(tv.getTask());
+            TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
 
             if (ignoreTasksSet.contains(tv.getTask().key)) {
                 continue;
@@ -654,6 +693,10 @@
      */
     public void updateTaskViewToTransform(TaskView taskView, TaskViewTransform transform,
             AnimationProps animation) {
+        if (taskView.isAnimatingTo(transform)) {
+            return;
+        }
+        taskView.cancelTransformAnimation();
         taskView.updateViewPropertiesToTaskTransform(transform, animation,
                 mRequestUpdateClippingListener);
     }
@@ -665,7 +708,7 @@
     public void getCurrentTaskTransforms(ArrayList<Task> tasks,
             ArrayList<TaskViewTransform> transformsOut) {
         Utilities.matchTaskListSize(tasks, transformsOut);
-        float focusState = mLayoutAlgorithm.getFocusState();
+        int focusState = mLayoutAlgorithm.getFocusState();
         for (int i = tasks.size() - 1; i >= 0; i--) {
             Task task = tasks.get(i);
             TaskViewTransform transform = transformsOut.get(i);
@@ -674,7 +717,8 @@
                 transform.fillIn(tv);
             } else {
                 mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
-                        focusState, transform, null, true /* forceUpdate */);
+                        focusState, transform, null, true /* forceUpdate */,
+                        false /* ignoreTaskOverrides */);
             }
             transform.visible = true;
         }
@@ -684,14 +728,14 @@
      * Returns the task transforms for all the tasks in the stack if the stack was at the given
      * {@param stackScroll} and {@param focusState}.
      */
-    public void getLayoutTaskTransforms(float stackScroll, float focusState, ArrayList<Task> tasks,
+    public void getLayoutTaskTransforms(float stackScroll, int focusState, ArrayList<Task> tasks,
             ArrayList<TaskViewTransform> transformsOut) {
         Utilities.matchTaskListSize(tasks, transformsOut);
         for (int i = tasks.size() - 1; i >= 0; i--) {
             Task task = tasks.get(i);
             TaskViewTransform transform = transformsOut.get(i);
             mLayoutAlgorithm.getStackTransform(task, stackScroll, focusState, transform, null,
-                    true /* forceUpdate */);
+                    true /* forceUpdate */, true /* ignoreTaskOverrides */);
             transform.visible = true;
         }
     }
@@ -731,8 +775,6 @@
      * Updates the clip for each of the task views from back to front.
      */
     private void clipTaskViews() {
-        RecentsConfiguration config = Recents.getConfiguration();
-
         // Update the clip on each task child
         List<TaskView> taskViews = getTaskViews();
         TaskView tmpTv = null;
@@ -776,9 +818,7 @@
                 }
             }
             tv.getViewBounds().setClipBottom(clipBottom);
-            if (!config.useHardwareLayers) {
-                tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
-            }
+            tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
             prevVisibleTv = tv;
         }
         mTaskViewsClipDirty = false;
@@ -789,7 +829,7 @@
      *
      * @see #updateLayoutAlgorithm(boolean, ArraySet<Task.TaskKey>)
      */
-    void updateLayoutAlgorithm(boolean boundScrollToNewMinMax) {
+   public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax) {
         updateLayoutAlgorithm(boundScrollToNewMinMax, mIgnoreTasks);
     }
 
@@ -798,7 +838,7 @@
      *
      * @param ignoreTasksSet the set of tasks to ignore in the relayout
      */
-    void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
+    public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
             ArraySet<Task.TaskKey> ignoreTasksSet) {
         // Compute the min and max scroll values
         mLayoutAlgorithm.update(mStack, ignoreTasksSet);
@@ -877,6 +917,7 @@
                     cancelAllTaskViewAnimations();
                 }
 
+                mLayoutAlgorithm.clearUnfocusedTaskOverrides();
                 willScroll = mAnimationHelper.startScrollToFocusedTaskAnimation(newFocusedTask,
                         requestViewFocus);
             } else {
@@ -1030,8 +1071,10 @@
             event.setContentDescription(frontMostTask.getTask().title);
         }
         event.setItemCount(mStack.getTaskCount());
-        event.setScrollY(mStackScroller.mScroller.getCurrY());
-        event.setMaxScrollY(mStackScroller.progressToScrollRange(mLayoutAlgorithm.mMaxScrollP));
+
+        int stackHeight = mLayoutAlgorithm.mStackRect.height();
+        event.setScrollY((int) (mStackScroller.getStackScroll() * stackHeight));
+        event.setMaxScrollY((int) (mLayoutAlgorithm.mMaxScrollP * stackHeight));
     }
 
     @Override
@@ -1055,7 +1098,7 @@
     protected Parcelable onSaveInstanceState() {
         Bundle savedState = new Bundle();
         savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState());
-        savedState.putFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
+        savedState.putInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
         savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll());
         return super.onSaveInstanceState();
     }
@@ -1065,7 +1108,7 @@
         Bundle savedState = (Bundle) state;
         super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER));
 
-        mLayoutAlgorithm.setFocusState(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
+        mLayoutAlgorithm.setFocusState(savedState.getInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
         mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL));
     }
 
@@ -1124,15 +1167,6 @@
     }
 
     /**
-     * This is ONLY used from the Recents component to update the dummy stack view for purposes
-     * of getting the task rect to animate to.
-     */
-    public void updateLayoutForStack(TaskStack stack) {
-        mStack = stack;
-        updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
-    }
-
-    /**
      * Computes the maximum number of visible tasks and thumbnails. Requires that
      * updateLayoutForStack() is called first.
      */
@@ -1141,23 +1175,12 @@
     }
 
     /**
-     * Updates the expected task stack bounds for this stack view.
+     * Updates the system insets.
      */
-    public void setTaskStackBounds(Rect taskStackBounds, Rect systemInsets) {
-        // We can get spurious measure passes with the old bounds when docking, and since we are
-        // using the current stack bounds during drag and drop, don't overwrite them until we
-        // actually get new bounds
-        boolean requiresLayout = false;
-        if (!taskStackBounds.equals(mStableStackBounds)) {
-            mStableStackBounds.set(taskStackBounds);
-            mStackBounds.set(taskStackBounds);
-            requiresLayout = true;
-        }
+    public void setSystemInsets(Rect systemInsets) {
         if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
+            mStableLayoutAlgorithm.setSystemInsets(systemInsets);
             mLayoutAlgorithm.setSystemInsets(systemInsets);
-            requiresLayout = true;
-        }
-        if (requiresLayout) {
             requestLayout();
         }
     }
@@ -1172,18 +1195,35 @@
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
+        // Update the stable stack bounds, but only update the current stack bounds if the stable
+        // bounds have changed.  This is because we may get spurious measures while dragging where
+        // our current stack bounds reflect the target drop region.
+        mLayoutAlgorithm.getTaskStackBounds(new Rect(0, 0, width, height),
+                mLayoutAlgorithm.mSystemInsets.top, mLayoutAlgorithm.mSystemInsets.right, mTmpRect);
+        if (!mTmpRect.equals(mStableStackBounds)) {
+            mStableStackBounds.set(mTmpRect);
+            mStackBounds.set(mTmpRect);
+            mStableWindowRect.set(0, 0, width, height);
+            mWindowRect.set(0, 0, width, height);
+        }
+
         // Compute the rects in the stack algorithm
-        mLayoutAlgorithm.initialize(mStackBounds,
+        mStableLayoutAlgorithm.initialize(mStableWindowRect, mStableStackBounds,
                 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
-        updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
+        mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
+                TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+        updateLayoutAlgorithm(false /* boundScroll */, mIgnoreTasks);
 
         // If this is the first layout, then scroll to the front of the stack, then update the
         // TaskViews with the stack so that we can lay them out
-        if (mAwaitingFirstLayout) {
-            mStackScroller.setStackScrollToInitialState();
+        if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE) {
+            updateToInitialState(mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY);
+            mInitialState = INITIAL_STATE_UPDATE_NONE;
         }
+
         // Rebind all the views, including the ignore ones
-        bindVisibleTaskViews(mStackScroller.getStackScroll(), EMPTY_TASK_SET);
+        bindVisibleTaskViews(mStackScroller.getStackScroll(), mIgnoreTasks,
+                false /* ignoreTaskOverrides */);
 
         // Measure each of the TaskViews
         mTmpTaskViews.clear();
@@ -1207,20 +1247,14 @@
         } else {
             mTmpRect.setEmpty();
         }
+        Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
         tv.measure(
-                MeasureSpec.makeMeasureSpec(
-                        mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
+                MeasureSpec.makeMeasureSpec(taskRect.width() + mTmpRect.left + mTmpRect.right,
                         MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(
-                        mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
+                MeasureSpec.makeMeasureSpec(taskRect.height() + mTmpRect.top + mTmpRect.bottom,
                         MeasureSpec.EXACTLY));
     }
 
-    /**
-     * 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) {
         // Layout each of the TaskViews
@@ -1229,7 +1263,7 @@
         mTmpTaskViews.addAll(mViewPool.getViews());
         int taskViewCount = mTmpTaskViews.size();
         for (int i = 0; i < taskViewCount; i++) {
-            layoutTaskView(mTmpTaskViews.get(i));
+            layoutTaskView(changed, mTmpTaskViews.get(i));
         }
 
         if (changed) {
@@ -1237,8 +1271,9 @@
                 mStackScroller.boundScroll();
             }
         }
+
         // Relayout all of the task views including the ignored ones
-        relayoutTaskViews(AnimationProps.IMMEDIATE, EMPTY_TASK_SET);
+        relayoutTaskViews(AnimationProps.IMMEDIATE, mIgnoreTasks);
         clipTaskViews();
 
         if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
@@ -1250,15 +1285,21 @@
     /**
      * Lays out a TaskView.
      */
-    private void layoutTaskView(TaskView tv) {
-        if (tv.getBackground() != null) {
-            tv.getBackground().getPadding(mTmpRect);
+    private void layoutTaskView(boolean changed, TaskView tv) {
+        if (changed) {
+            if (tv.getBackground() != null) {
+                tv.getBackground().getPadding(mTmpRect);
+            } else {
+                mTmpRect.setEmpty();
+            }
+            Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+            tv.cancelTransformAnimation();
+            tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
+                    taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
         } else {
-            mTmpRect.setEmpty();
+            // If the layout has not changed, then just lay it out again in-place
+            tv.layout(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
         }
-        Rect taskRect = mLayoutAlgorithm.mTaskRect;
-        tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
-                taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
     }
 
     /** Handler for the first layout. */
@@ -1281,12 +1322,12 @@
                     false /* requestViewFocus */);
         }
 
-        // Update the history button visibility
-        if (shouldShowHistoryButton() &&
-                mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
-            EventBus.getDefault().send(new ShowHistoryButtonEvent(false /* translate */));
+        // Update the stack action button visibility
+        if (mStackScroller.getStackScroll() < SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+                mStack.getTaskCount() > 0) {
+            EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */));
         } else {
-            EventBus.getDefault().send(new HideHistoryButtonEvent());
+            EventBus.getDefault().send(new HideStackActionButtonEvent());
         }
     }
 
@@ -1370,7 +1411,7 @@
      */
     @Override
     public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
-            Task newFrontMostTask, AnimationProps animation) {
+            Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture) {
         if (mFocusedTask == removedTask) {
             resetFocusedTask(removedTask);
         }
@@ -1401,14 +1442,46 @@
 
         // If there are no remaining tasks, then just close recents
         if (mStack.getTaskCount() == 0) {
-            EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+            EventBus.getDefault().send(new AllTaskViewsDismissedEvent(fromDockGesture
+                    ? R.string.recents_empty_message
+                    : R.string.recents_empty_message_dismissed_all));
         }
     }
 
     @Override
-    public void onHistoryTaskRemoved(TaskStack stack, Task removedTask,
-            AnimationProps animation) {
-        // To be implemented
+    public void onStackTasksRemoved(TaskStack stack) {
+        // Reset the focused task
+        resetFocusedTask(getFocusedTask());
+
+        // Return all the views to the pool
+        List<TaskView> taskViews = new ArrayList<>();
+        taskViews.addAll(getTaskViews());
+        for (int i = taskViews.size() - 1; i >= 0; i--) {
+            mViewPool.returnViewToPool(taskViews.get(i));
+        }
+
+        // Remove all the ignore tasks
+        mIgnoreTasks.clear();
+
+        // If there are no remaining tasks, then just close recents
+        EventBus.getDefault().send(new AllTaskViewsDismissedEvent(
+                R.string.recents_empty_message_dismissed_all));
+    }
+
+    @Override
+    public void onStackTasksUpdated(TaskStack stack) {
+        // Update the layout and immediately layout
+        updateLayoutAlgorithm(false /* boundScroll */);
+        relayoutTaskViews(AnimationProps.IMMEDIATE);
+
+        // Rebind all the task views.  This will not trigger new resources to be loaded
+        // unless they have actually changed
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
+            bindTaskView(tv, tv.getTask());
+        }
     }
 
     /**** ViewPoolConsumer Implementation ****/
@@ -1422,8 +1495,8 @@
     public void onReturnViewToPool(TaskView tv) {
         final Task task = tv.getTask();
 
-        // Report that this tasks's data is no longer being used
-        Recents.getTaskLoader().unloadTaskData(task);
+        // Unbind the task from the task view
+        unbindTaskView(tv, task);
 
         // Reset the view properties and view state
         tv.resetViewProperties();
@@ -1460,7 +1533,7 @@
                 }
                 addViewInLayout(tv, insertIndex, params, true /* preventRequestLayout */);
                 measureTaskView(tv);
-                layoutTaskView(tv);
+                layoutTaskView(true /* changed */, tv);
             }
         } else {
             attachViewToParent(tv, insertIndex, tv.getLayoutParams());
@@ -1468,14 +1541,11 @@
         // Update the task views list after adding the new task view
         updateTaskViewsList();
 
-        // Rebind the task and request that this task's data be filled into the TaskView
-        tv.onTaskBound(task);
-
-        // Load the task data
-        Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
+        // Bind the task view to the new task
+        bindTaskView(tv, task);
 
         // If the doze trigger has already fired, then update the state for this task view
-        if (mUIDozeTrigger.hasTriggered()) {
+        if (mUIDozeTrigger.isAsleep()) {
             tv.setNoUserInteractionState();
         }
 
@@ -1504,6 +1574,19 @@
         return (tv.getTask() == preferredData);
     }
 
+    private void bindTaskView(TaskView tv, Task task) {
+        // Rebind the task and request that this task's data be filled into the TaskView
+        tv.onTaskBound(task);
+
+        // Load the task data
+        Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
+    }
+
+    private void unbindTaskView(TaskView tv, Task task) {
+        // Report that this task's data is no longer being used
+        Recents.getTaskLoader().unloadTaskData(task);
+    }
+
     /**** TaskViewCallbacks Implementation ****/
 
     @Override
@@ -1517,7 +1600,7 @@
     /**** TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks ****/
 
     @Override
-    public void onFocusStateChanged(float prevFocusState, float curFocusState) {
+    public void onFocusStateChanged(int prevFocusState, int curFocusState) {
         if (mDeferredTaskViewLayoutAnimation == null) {
             mUIDozeTrigger.poke();
             relayoutTaskViewsOnNextFrame(AnimationProps.IMMEDIATE);
@@ -1532,15 +1615,16 @@
         if (animation != null) {
             relayoutTaskViewsOnNextFrame(animation);
         }
+        mLayoutAlgorithm.updateFocusStateOnScroll(curScroll, curScroll - prevScroll);
 
         if (mEnterAnimationComplete) {
-            if (shouldShowHistoryButton() &&
-                    prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
-                    curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
-                EventBus.getDefault().send(new ShowHistoryButtonEvent(true /* translate */));
-            } else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
-                    curScroll >= HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD) {
-                EventBus.getDefault().send(new HideHistoryButtonEvent());
+            if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+                    curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+                    mStack.getTaskCount() > 0) {
+                EventBus.getDefault().send(new ShowStackActionButtonEvent(true /* translate */));
+            } else if (prevScroll < HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+                    curScroll >= HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
+                EventBus.getDefault().send(new HideStackActionButtonEvent());
             }
         }
     }
@@ -1563,7 +1647,7 @@
                     tv.dismissTask();
                 } else {
                     // Otherwise, remove the task from the stack immediately
-                    mStack.removeTask(t, AnimationProps.IMMEDIATE);
+                    mStack.removeTask(t, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
                 }
             }
         }
@@ -1586,9 +1670,32 @@
             mUIDozeTrigger.stopDozing();
             cancelAllTaskViewAnimations();
 
-            Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
-            EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask),
-                    launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+            final Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
+            float curScroll = mStackScroller.getStackScroll();
+            float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(launchTask);
+            float absScrollDiff = Math.abs(targetScroll - curScroll);
+            if (getChildViewForTask(launchTask) == null || absScrollDiff > 0.35f) {
+                int duration = (int) (LAUNCH_NEXT_SCROLL_BASE_DURATION +
+                        absScrollDiff * LAUNCH_NEXT_SCROLL_INCR_DURATION);
+                mStackScroller.animateScroll(targetScroll,
+                        duration, new Runnable() {
+                            @Override
+                            public void run() {
+                                EventBus.getDefault().send(new LaunchTaskEvent(
+                                        getChildViewForTask(launchTask), launchTask, null,
+                                        INVALID_STACK_ID, false /* screenPinningRequested */));
+                            }
+                        });
+            } else {
+                EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask),
+                        launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+            }
+
+            MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
+                    launchTask.key.getComponent().toString());
+        } else if (mStack.getTaskCount() == 0) {
+            // If there are no tasks, then just hide recents back to home.
+            EventBus.getDefault().send(new HideRecentsEvent(false, true));
         }
     }
 
@@ -1621,14 +1728,42 @@
         }
     }
 
-    public final void onBusEvent(final DismissTaskViewEvent event) {
+    public final void onBusEvent(DismissTaskViewEvent event) {
         // For visible children, defer removing the task until after the animation
-        mAnimationHelper.startDeleteTaskAnimation(event.task, event.taskView,
-                event.getAnimationTrigger());
+        mAnimationHelper.startDeleteTaskAnimation(event.taskView, event.getAnimationTrigger());
+    }
+
+    public final void onBusEvent(final DismissAllTaskViewsEvent event) {
+        // Keep track of the tasks which will have their data removed
+        ArrayList<Task> tasks = new ArrayList<>(mStack.getStackTasks());
+        mAnimationHelper.startDeleteAllTasksAnimation(getTaskViews(), event.getAnimationTrigger());
+        event.addPostAnimationCallback(new Runnable() {
+            @Override
+            public void run() {
+                // Announce for accessibility
+                announceForAccessibility(getContext().getString(
+                        R.string.accessibility_recents_all_items_dismissed));
+
+                // Remove all tasks and delete the task data for all tasks
+                mStack.removeAllTasks();
+                for (int i = tasks.size() - 1; i >= 0; i--) {
+                    EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
+                }
+
+                MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS_ALL);
+            }
+        });
+
     }
 
     public final void onBusEvent(TaskViewDismissedEvent event) {
-        removeTaskViewFromStack(event.taskView, event.task);
+        // Announce for accessibility
+        announceForAccessibility(getContext().getString(
+                R.string.accessibility_recents_item_dismissed, event.task.title));
+
+        // Remove the task from the stack
+        mStack.removeTask(event.task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
+                Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */);
         EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
 
         MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
@@ -1636,11 +1771,19 @@
     }
 
     public final void onBusEvent(FocusNextTaskViewEvent event) {
+        // Stop any scrolling
+        mStackScroller.stopScroller();
+        mStackScroller.stopBoundScrollAnimation();
+
         setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false,
                 event.timerIndicatorDuration);
     }
 
     public final void onBusEvent(FocusPreviousTaskViewEvent event) {
+        // Stop any scrolling
+        mStackScroller.stopScroller();
+        mStackScroller.stopBoundScrollAnimation();
+
         setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */);
     }
 
@@ -1657,12 +1800,6 @@
         }
     }
 
-    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
-        if (!event.visible) {
-            reset();
-        }
-    }
-
     public final void onBusEvent(DragStartEvent event) {
         // Ensure that the drag task is not animated
         addIgnoreTask(event.task);
@@ -1692,32 +1829,38 @@
 
     public final void onBusEvent(DragDropTargetChangedEvent event) {
         AnimationProps animation = new AnimationProps(250, Interpolators.FAST_OUT_SLOW_IN);
+        boolean ignoreTaskOverrides = false;
         if (event.dropTarget instanceof TaskStack.DockState) {
             // Calculate the new task stack bounds that matches the window size that Recents will
             // have after the drop
             final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
             mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
                     getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets,
-                    getResources()));
-            mLayoutAlgorithm.initialize(mStackBounds,
+                    mLayoutAlgorithm, getResources(), mWindowRect));
+            mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
             updateLayoutAlgorithm(true /* boundScroll */);
+            ignoreTaskOverrides = true;
         } else {
             // Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging
             // task view, so add it back to the ignore set after updating the layout
+            mWindowRect.set(mStableWindowRect);
             mStackBounds.set(mStableStackBounds);
             removeIgnoreTask(event.task);
-            mLayoutAlgorithm.initialize(mStackBounds,
+            mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
             updateLayoutAlgorithm(true /* boundScroll */);
             addIgnoreTask(event.task);
         }
-        relayoutTaskViews(animation);
+        relayoutTaskViews(animation, mIgnoreTasks, ignoreTaskOverrides);
     }
 
     public final void onBusEvent(final DragEndEvent event) {
         // We don't handle drops on the dock regions
         if (event.dropTarget instanceof TaskStack.DockState) {
+            // However, we do need to reset the overrides, since the last state of this task stack
+            // view layout was ignoring task overrides (see DragDropTargetChangedEvent handler)
+            mLayoutAlgorithm.clearUnfocusedTaskOverrides();
             return;
         }
 
@@ -1759,22 +1902,20 @@
         event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
                 taskViewRect.right, taskViewRect.bottom);
 
-        // Animate all the TaskViews back into position
+        // Animate the non-drag TaskViews back into position
         mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
                 mTmpTransform, null);
         event.getAnimationTrigger().increment();
         relayoutTaskViews(new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
                 Interpolators.FAST_OUT_SLOW_IN));
+
+        // Animate the drag TaskView back into position
         updateTaskViewToTransform(event.taskView, mTmpTransform,
                 new AnimationProps(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN,
                         event.getAnimationTrigger().decrementOnAnimationEnd()));
         removeIgnoreTask(event.task);
     }
 
-    public final void onBusEvent(StackViewScrolledEvent event) {
-        mLayoutAlgorithm.updateFocusStateOnScroll(event.yMovement.value);
-    }
-
     public final void onBusEvent(IterateRecentsEvent event) {
         if (!mEnterAnimationComplete) {
             // Cancel the previous task's window transition before animating the focused state
@@ -1825,45 +1966,46 @@
         }
     }
 
-    public final void onBusEvent(ShowHistoryEvent event) {
-        ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger();
-        postAnimTrigger.addLastDecrementRunnable(new Runnable() {
-            @Override
-            public void run() {
-                setVisibility(View.INVISIBLE);
+    public final void onBusEvent(MultiWindowStateChangedEvent event) {
+        if (!event.inMultiWindow) {
+            // Scroll the stack to the front to see the undocked task
+            mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
+                @Override
+                public void run() {
+                    List<TaskView> taskViews = getTaskViews();
+                    int taskViewCount = taskViews.size();
+                    for (int i = 0; i < taskViewCount; i++) {
+                        TaskView tv = taskViews.get(i);
+                        tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
+                                tv.mIsDisabledInSafeMode);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(ConfigurationChangedEvent event) {
+        mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+        mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+
+        // Notify the task views of the configuration change so they can reload their resources
+        if (!event.fromMultiWindow) {
+            mTmpTaskViews.clear();
+            mTmpTaskViews.addAll(getTaskViews());
+            mTmpTaskViews.addAll(mViewPool.getViews());
+            int taskViewCount = mTmpTaskViews.size();
+            for (int i = 0; i < taskViewCount; i++) {
+                mTmpTaskViews.get(i).onConfigurationChanged();
             }
-        });
-        mAnimationHelper.startShowHistoryAnimation(postAnimTrigger);
-    }
+        }
 
-    public final void onBusEvent(HideHistoryEvent event) {
-        setVisibility(View.VISIBLE);
-        mAnimationHelper.startHideHistoryAnimation();
-    }
-
-    public final void onBusEvent(TaskStackUpdatedEvent event) {
-        // Scroll the stack to the front after it has been updated
-        event.addPostAnimationCallback(new Runnable() {
-            @Override
-            public void run() {
-                mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
-                        null /* postScrollRunnable */);
-            }
-        });
-    }
-
-    /**
-     * Removes the task from the stack, and updates the focus to the next task in the stack if the
-     * removed TaskView was focused.
-     */
-    private void removeTaskViewFromStack(TaskView tv, Task task) {
-        // Announce for accessibility
-        tv.announceForAccessibility(getContext().getString(
-                R.string.accessibility_recents_item_dismissed, task.title));
-
-        // Remove the task from the stack
-        mStack.removeTask(task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
-                Interpolators.FAST_OUT_SLOW_IN));
+        // Trigger a new layout and update to the initial state if necessary
+        if (event.fromMultiWindow) {
+            mInitialState = INITIAL_STATE_UPDATE_ALL;
+        } else if (event.fromOrientationChange) {
+            mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
+        }
+        requestLayout();
     }
 
     /**
@@ -1917,13 +2059,6 @@
     }
 
     /**
-     * @return whether the history button should be visible
-     */
-    private boolean shouldShowHistoryButton() {
-        return !mStack.getHistoricalTasks().isEmpty();
-    }
-
-    /**
      * Reads current system flags related to accessibility and screen pinning.
      */
     private void readSystemFlags() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 333df9d..583fb88 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -28,8 +28,6 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 
 /* The scrolling logic for a TaskStackView */
@@ -115,13 +113,8 @@
      * @return whether the stack progress changed.
      */
     public boolean setStackScrollToInitialState() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
         float prevStackScrollP = mStackScrollP;
-        if (ssp.hasDockedTask()) {
-            setStackScroll(mLayoutAlgorithm.mMaxScrollP);
-        } else {
-            setStackScroll(mLayoutAlgorithm.mInitialScrollP);
-        }
+        setStackScroll(mLayoutAlgorithm.mInitialScrollP);
         return Float.compare(prevStackScrollP, mStackScrollP) != 0;
     }
 
@@ -184,10 +177,17 @@
 
     /** Animates the stack scroll */
     void animateScroll(float newScroll, final Runnable postRunnable) {
+        int duration = mContext.getResources().getInteger(
+                R.integer.recents_animate_task_stack_scroll_duration);
+        animateScroll(newScroll, duration, postRunnable);
+    }
+
+    /** Animates the stack scroll */
+    void animateScroll(float newScroll, int duration, final Runnable postRunnable) {
         // Finish any current scrolling animations
         if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
             setStackScroll(mFinalAnimatedScroll);
-            mScroller.startScroll(0, progressToScrollRange(mFinalAnimatedScroll), 0, 0, 0);
+            mScroller.forceFinished(true);
         }
         stopScroller();
         stopBoundScrollAnimation();
@@ -195,8 +195,7 @@
         if (Float.compare(mStackScrollP, newScroll) != 0) {
             mFinalAnimatedScroll = newScroll;
             mScrollAnimator = ObjectAnimator.ofFloat(this, STACK_SCROLL, getStackScroll(), newScroll);
-            mScrollAnimator.setDuration(mContext.getResources().getInteger(
-                    R.integer.recents_animate_task_stack_scroll_duration));
+            mScrollAnimator.setDuration(duration);
             mScrollAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
             mScrollAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
@@ -222,12 +221,6 @@
 
     /**** OverScroller ****/
 
-    // TODO: Remove
-    @Deprecated
-    int progressToScrollRange(float p) {
-        return (int) (p * mLayoutAlgorithm.mStackRect.height());
-    }
-
     /** Called from the view draw, computes the next scroll. */
     boolean computeScroll() {
         if (mScroller.computeScrollOffset()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 3f0630d..ee0de1a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -20,6 +20,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Path;
 import android.graphics.Rect;
 import android.util.ArrayMap;
 import android.util.MutableBoolean;
@@ -44,6 +45,7 @@
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
+import com.android.systemui.recents.misc.FreePathInterpolator;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
@@ -60,6 +62,16 @@
     private static final int INACTIVE_POINTER_ID = -1;
     private static final Interpolator STACK_TRANSFORM_INTERPOLATOR =
             new PathInterpolator(0.73f, 0.33f, 0.42f, 0.85f);
+    // The min overscroll is the amount of task progress overscroll we want / the max overscroll
+    // curve value below
+    private static final float MAX_OVERSCROLL = 0.7f / 0.3f;
+    private static final Interpolator OVERSCROLL_INTERP;
+    static {
+        Path OVERSCROLL_PATH = new Path();
+        OVERSCROLL_PATH.moveTo(0, 0);
+        OVERSCROLL_PATH.cubicTo(0.2f, 0.175f, 0.25f, 0.3f, 1f, 0.3f);
+        OVERSCROLL_INTERP = new FreePathInterpolator(OVERSCROLL_PATH);
+    }
 
     Context mContext;
     TaskStackView mSv;
@@ -109,7 +121,7 @@
         mScrollTouchSlop = configuration.getScaledTouchSlop();
         mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
         mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f);
-        mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll);
+        mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_fling_overscroll_distance);
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context) {
             @Override
             protected float getSize(View v) {
@@ -223,6 +235,13 @@
                     int xDiff = Math.abs(x - mDownX);
                     if (Math.abs(y - mDownY) > mScrollTouchSlop && yDiff > xDiff) {
                         mIsScrolling = true;
+                        float stackScroll = mScroller.getStackScroll();
+                        List<TaskView> taskViews = mSv.getTaskViews();
+                        for (int i = taskViews.size() - 1; i >= 0; i--) {
+                            layoutAlgorithm.addUnfocusedTaskOverride(taskViews.get(i).getTask(),
+                                    stackScroll);
+                        }
+                        layoutAlgorithm.setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
 
                         // Disallow parents from intercepting touch events
                         final ViewParent parent = mSv.getParent();
@@ -238,6 +257,18 @@
                     // of the curve, so just move the scroll proportional to that
                     float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
                     float curScrollP = mDownScrollP + deltaP;
+
+                    // Modulate the overscroll to prevent users from pulling the stack too far
+                    float minScrollP = layoutAlgorithm.mMinScrollP;
+                    float maxScrollP = layoutAlgorithm.mMaxScrollP;
+                    if (curScrollP < minScrollP || curScrollP > maxScrollP) {
+                        float clampedScrollP = Utilities.clamp(curScrollP, minScrollP, maxScrollP);
+                        float overscrollP = (curScrollP - clampedScrollP);
+                        float overscrollX = Math.abs(overscrollP) / MAX_OVERSCROLL;
+                        curScrollP = clampedScrollP + (Math.signum(overscrollP) *
+                                (OVERSCROLL_INTERP.getInterpolation(overscrollX) * MAX_OVERSCROLL));
+                    }
+
                     mScroller.setStackScroll(curScrollP);
                     mStackViewScrolledEvent.updateY(y - mLastY);
                     EventBus.getDefault().send(mStackViewScrolledEvent);
@@ -325,6 +356,11 @@
             return;
         }
 
+        // Disallow tapping above and below the stack to dismiss recents
+        if (x > mSv.mLayoutAlgorithm.mStackRect.left && x < mSv.mLayoutAlgorithm.mStackRect.right) {
+            return;
+        }
+
         // If tapping on the freeform workspace background, just launch the first freeform task
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.hasFreeformWorkspaceSupport()) {
@@ -427,20 +463,20 @@
                 newStackScroll = stackScroller.getBoundedStackScroll(newStackScroll);
             } else if (pullStackForward) {
                 // Otherwise, offset the scroll by the movement of the anchor task
-                float anchorTaskScroll = layoutAlgorithm.getStackScrollForTask(anchorTask);
+                float anchorTaskScroll =
+                        layoutAlgorithm.getStackScrollForTaskIgnoreOverrides(anchorTask);
                 float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll);
-                if (layoutAlgorithm.getFocusState() !=
-                        TaskStackLayoutAlgorithm.STATE_FOCUSED) {
+                if (layoutAlgorithm.getFocusState() != TaskStackLayoutAlgorithm.STATE_FOCUSED) {
                     // If we are focused, we don't want the front task to move, but otherwise, we
                     // allow the back task to move up, and the front task to move back
-                    stackScrollOffset /= 2;
+                    stackScrollOffset *= 0.75f;
                 }
                 newStackScroll = stackScroller.getBoundedStackScroll(stackScroller.getStackScroll()
                         + stackScrollOffset);
             }
 
             // Pick up the newly visible views, not including the deleting tasks
-            mSv.bindVisibleTaskViews(newStackScroll);
+            mSv.bindVisibleTaskViews(newStackScroll, true /* ignoreTaskOverrides */);
 
             // Get the final set of task transforms (with task removed)
             mSv.getLayoutTaskTransforms(newStackScroll, TaskStackLayoutAlgorithm.STATE_UNFOCUSED,
@@ -476,12 +512,13 @@
         tv.setClipViewInStack(true);
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
+        // Remove the task view from the stack
+        EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
         // Update the scroll to the final scroll position from onBeginDrag()
         mSv.getScroller().setStackScroll(mTargetStackScroll, null);
         // Update the focus state to the final focus state
         mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
-        // Remove the task view from the stack
-        EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
+        mSv.getStackAlgorithm().clearUnfocusedTaskOverrides();
         // Stop tracking this deletion animation
         mSwipeHelperAnimations.remove(v);
         // Keep track of deletions by keyboard
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 0c78e6a..f8ed700 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,13 +16,16 @@
 
 package com.android.systemui.recents.views;
 
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Color;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.Point;
@@ -59,8 +62,6 @@
 
 import java.util.ArrayList;
 
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
 /**
  * A {@link TaskView} represents a fixed view of a task. Because the TaskView's layout is directed
  * solely by the {@link TaskStackView}, we make it a fixed size layout which allows relayouts down
@@ -77,6 +78,24 @@
 
     /**
      * The dim overlay is generally calculated from the task progress, but occasionally (like when
+     * launching) needs to be animated independently of the task progress.  This call is only used
+     * when animating the task into Recents, when the header dim is already applied
+     */
+    public static final Property<TaskView, Float> DIM_ALPHA_WITHOUT_HEADER =
+            new FloatProperty<TaskView>("dimAlphaWithoutHeader") {
+                @Override
+                public void setValue(TaskView tv, float dimAlpha) {
+                    tv.setDimAlphaWithoutHeader(dimAlpha);
+                }
+
+                @Override
+                public Float get(TaskView tv) {
+                    return tv.getDimAlpha();
+                }
+            };
+
+    /**
+     * The dim overlay is generally calculated from the task progress, but occasionally (like when
      * launching) needs to be animated independently of the task progress.
      */
     public static final Property<TaskView, Float> DIM_ALPHA =
@@ -111,8 +130,6 @@
 
     @ViewDebug.ExportedProperty(category="recents")
     float mDimAlpha;
-    PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
-    Paint mDimLayerPaint = new Paint();
     float mActionButtonTranslationZ;
 
     @ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
@@ -129,6 +146,7 @@
     AnimateableViewBounds mViewBounds;
 
     private AnimatorSet mTransformAnimation;
+    private final TaskViewTransform mTargetAnimationTransform = new TaskViewTransform();
     private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
 
     View mContent;
@@ -174,13 +192,15 @@
         mCb = cb;
     }
 
-    /** Resets this TaskView for reuse. */
-    void reset() {
-        resetViewProperties();
+    /**
+     * Called from RecentsActivity when it is relaunched.
+     */
+    void onReload(boolean isResumingFromVisible) {
         resetNoUserInteractionState();
         readSystemFlags();
-        setClipViewInStack(false);
-        setCallbacks(null);
+        if (!isResumingFromVisible) {
+            resetViewProperties();
+        }
     }
 
     /** Gets the task */
@@ -218,6 +238,13 @@
         mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
     }
 
+    /**
+     * Update the task view when the configuration changes.
+     */
+    void onConfigurationChanged() {
+        mHeaderView.onConfigurationChanged();
+    }
+
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
@@ -299,6 +326,7 @@
             // Create the animator
             mTransformAnimation = toAnimation.createAnimator(mTmpAnimators);
             mTransformAnimation.start();
+            mTargetAnimationTransform.copyFrom(toTransform);
         }
     }
 
@@ -318,6 +346,14 @@
     }
 
     /**
+     * @return whether we are animating towards {@param transform}
+     */
+    boolean isAnimatingTo(TaskViewTransform transform) {
+        return mTransformAnimation != null && mTransformAnimation.isStarted()
+                && mTargetAnimationTransform.isSame(transform);
+    }
+
+    /**
      * Cancels any current transform animations.
      */
     public void cancelTransformAnimation() {
@@ -348,7 +384,7 @@
     void dismissTask() {
         // Animate out the view and call the callback
         final TaskView tv = this;
-        DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv, mTask);
+        DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv);
         dismissEvent.addPostAnimationCallback(new Runnable() {
             @Override
             public void run() {
@@ -388,21 +424,17 @@
      * Sets the current dim.
      */
     public void setDimAlpha(float dimAlpha) {
-        RecentsConfiguration config = Recents.getConfiguration();
-
-        int dimAlphaInt = (int) (dimAlpha * 255);
         mDimAlpha = dimAlpha;
-        if (config.useHardwareLayers) {
-            // Defer setting hardware layers if we have not yet measured, or there is no dim to draw
-            if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
-                mDimColorFilter.setColor(Color.argb(dimAlphaInt, 0, 0, 0));
-                mDimLayerPaint.setColorFilter(mDimColorFilter);
-                mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
-            }
-        } else {
-            mThumbnailView.setDimAlpha(dimAlpha);
-            mHeaderView.setDimAlpha(dimAlpha);
-        }
+        mThumbnailView.setDimAlpha(dimAlpha);
+        mHeaderView.setDimAlpha(dimAlpha);
+    }
+
+    /**
+     * Sets the current dim without updating the header's dim.
+     */
+    public void setDimAlphaWithoutHeader(float dimAlpha) {
+        mDimAlpha = dimAlpha;
+        mThumbnailView.setDimAlpha(dimAlpha);
     }
 
     /**
@@ -413,25 +445,6 @@
     }
 
     /**
-     * Animates the dim to the given value.
-     */
-    void animateDimAlpha(float toDimAlpha, AnimationProps animation) {
-        // Animate the dim into view as well
-        if (Float.compare(toDimAlpha, getDimAlpha()) != 0) {
-            Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
-                    DIM_ALPHA, getDimAlpha(), toDimAlpha));
-            if (animation.getListener() != null) {
-                anim.addListener(animation.getListener());
-            }
-            anim.start();
-        } else {
-            if (animation.getListener() != null) {
-                animation.getListener().onAnimationEnd(null);
-            }
-        }
-    }
-
-    /**
      * Explicitly sets the focused state of this task.
      */
     public void setFocusedState(boolean isFocused, boolean requestViewFocus) {
@@ -517,18 +530,20 @@
     @Override
     public void onPrepareLaunchTargetForEnterAnimation() {
         // These values will be animated in when onStartLaunchTargetEnterAnimation() is called
-        setDimAlpha(0);
+        setDimAlphaWithoutHeader(0);
         mActionButtonView.setAlpha(0f);
     }
 
     @Override
-    public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
-            ReferenceCountedTrigger postAnimationTrigger) {
-        // Un-dim the view before/while launching the target
-        AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT)
-                .setListener(postAnimationTrigger.decrementOnAnimationEnd());
+    public void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration,
+            boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger) {
+        // Dim the view after the app window transitions down into recents
         postAnimationTrigger.increment();
-        animateDimAlpha(0, animation);
+        AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
+        Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+                DIM_ALPHA_WITHOUT_HEADER, getDimAlpha(), transform.dimAlpha));
+        anim.addListener(postAnimationTrigger.decrementOnAnimationEnd());
+        anim.start();
 
         if (screenPinningEnabled) {
             showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
@@ -540,7 +555,9 @@
             ReferenceCountedTrigger postAnimationTrigger) {
         // Un-dim the view before/while launching the target
         AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
-        animateDimAlpha(0, animation);
+        Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+                DIM_ALPHA, getDimAlpha(), 0));
+        anim.start();
 
         postAnimationTrigger.increment();
         hideActionButton(true /* fadeOut */, duration,
@@ -548,6 +565,13 @@
                 postAnimationTrigger.decrementOnAnimationEnd());
     }
 
+    @Override
+    public void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled) {
+        if (screenPinningEnabled) {
+            showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
+        }
+    }
+
     /**** TaskCallbacks Implementation ****/
 
     public void onTaskBound(Task t) {
@@ -558,9 +582,9 @@
     }
 
     @Override
-    public void onTaskDataLoaded(Task task) {
+    public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
         // Bind each of the views to the new task data
-        mThumbnailView.rebindToTask(mTask, mIsDisabledInSafeMode);
+        mThumbnailView.rebindToTask(mTask, thumbnailInfo, mIsDisabledInSafeMode);
         mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
         mTaskDataLoaded = true;
     }
@@ -603,7 +627,7 @@
         EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
                 screenPinningRequested));
 
-        MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
+        MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
                 mTask.key.getComponent().toString());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index bb56a52..570ff8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -34,9 +34,11 @@
 import android.os.CountDownTimer;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewAnimationUtils;
 import android.view.ViewDebug;
+import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -63,7 +65,7 @@
 public class TaskViewHeader extends FrameLayout
         implements View.OnClickListener, View.OnLongClickListener {
 
-    private static final float HIGHLIGHT_LIGHTNESS_INCREMENT = 0.125f;
+    private static final float HIGHLIGHT_LIGHTNESS_INCREMENT = 0.075f;
     private static final float OVERLAY_LIGHTNESS_INCREMENT = -0.0625f;
     private static final int OVERLAY_REVEAL_DURATION = 250;
     private static final long FOCUS_INDICATOR_INTERVAL_MS = 30;
@@ -139,6 +141,7 @@
     // Header views
     ImageView mIconView;
     TextView mTitleView;
+    TextView mSubTitleView;
     ImageView mMoveTaskButton;
     ImageView mDismissButton;
     ViewStub mAppOverlayViewStub;
@@ -152,6 +155,8 @@
     // Header drawables
     @ViewDebug.ExportedProperty(category="recents")
     Rect mTaskViewRect = new Rect();
+    int mHeaderBarHeight;
+    int mHeaderButtonPadding;
     int mCornerRadius;
     int mHighlightHeight;
     @ViewDebug.ExportedProperty(category="recents")
@@ -237,12 +242,74 @@
         mIconView.setClickable(false);
         mIconView.setOnLongClickListener(this);
         mTitleView = (TextView) findViewById(R.id.title);
+        mSubTitleView = (TextView) findViewById(R.id.sub_title);
         mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
         if (ssp.hasFreeformWorkspaceSupport()) {
             mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
         }
         mFocusTimerIndicatorStub = (ViewStub) findViewById(R.id.focus_timer_indicator_stub);
         mAppOverlayViewStub = (ViewStub) findViewById(R.id.app_overlay_stub);
+
+        onConfigurationChanged();
+    }
+
+    /**
+     * Programmatically sets the layout params for a header bar layout.  This is necessary because
+     * we can't get resources based on the current configuration, but instead need to get them
+     * based on the device configuration.
+     */
+    private void updateLayoutParams(View icon, View title, View secondaryButton, View button) {
+        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, mHeaderBarHeight, Gravity.TOP);
+        setLayoutParams(lp);
+        lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.START);
+        icon.setLayoutParams(lp);
+        lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
+        lp.setMarginStart(mHeaderBarHeight);
+        lp.setMarginEnd(mMoveTaskButton != null
+                ? 2 * mHeaderBarHeight
+                : mHeaderBarHeight);
+        title.setLayoutParams(lp);
+        if (secondaryButton != null) {
+            lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
+            lp.setMarginEnd(mHeaderBarHeight);
+            secondaryButton.setLayoutParams(lp);
+            secondaryButton.setPadding(mHeaderButtonPadding, mHeaderButtonPadding,
+                    mHeaderButtonPadding, mHeaderButtonPadding);
+        }
+        lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
+        button.setLayoutParams(lp);
+        button.setPadding(mHeaderButtonPadding, mHeaderButtonPadding, mHeaderButtonPadding,
+                mHeaderButtonPadding);
+    }
+
+    /**
+     * Update the header view when the configuration changes.
+     */
+    void onConfigurationChanged() {
+        // Update the dimensions of everything in the header. We do this because we need to use
+        // resources for the display, and not the current configuration.
+        Resources res = getResources();
+        mHeaderBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land);
+        mHeaderButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+                R.dimen.recents_task_view_header_button_padding,
+                R.dimen.recents_task_view_header_button_padding,
+                R.dimen.recents_task_view_header_button_padding,
+                R.dimen.recents_task_view_header_button_padding_tablet_land,
+                R.dimen.recents_task_view_header_button_padding,
+                R.dimen.recents_task_view_header_button_padding_tablet_land);
+        updateLayoutParams(mIconView, findViewById(R.id.title_container), mMoveTaskButton,
+                mDismissButton);
+        if (mAppOverlayView != null) {
+            updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
+        }
     }
 
     @Override
@@ -335,6 +402,11 @@
         }
     }
 
+    /** Only exposed for the workaround for b/27815919. */
+    public ImageView getIconView() {
+        return mIconView;
+    }
+
     /** Returns the secondary color for a primary color. */
     int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) {
         int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK;
@@ -345,9 +417,12 @@
      * Sets the dim alpha, only used when we are not using hardware layers.
      * (see RecentsConfiguration.useHardwareLayers)
      */
-    void setDimAlpha(float dimAlpha) {
-        mDimAlpha = dimAlpha;
-        updateBackgroundColor(mBackground.getColor(), dimAlpha);
+    public void setDimAlpha(float dimAlpha) {
+        if (Float.compare(mDimAlpha, dimAlpha) != 0) {
+            mDimAlpha = dimAlpha;
+            mTitleView.setAlpha(1f - dimAlpha);
+            updateBackgroundColor(mBackground.getColor(), dimAlpha);
+        }
     }
 
     /**
@@ -367,6 +442,7 @@
 
     /** Binds the bar view to the task */
     public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
         mTask = t;
 
         // If an activity icon is defined, then we use that as the primary icon to show in the bar,
@@ -374,16 +450,25 @@
         int primaryColor = disabledInSafeMode
                 ? mDisabledTaskBarBackgroundColor
                 : t.colorPrimary;
-        updateBackgroundColor(primaryColor, mDimAlpha);
+        if (mBackground.getColor() != primaryColor) {
+            updateBackgroundColor(primaryColor, mDimAlpha);
+        }
         if (t.icon != null) {
             mIconView.setImageDrawable(t.icon);
         }
         if (!mTitleView.getText().toString().equals(t.title)) {
             mTitleView.setText(t.title);
         }
-        mTitleView.setContentDescription(t.contentDescription);
+        mTitleView.setContentDescription(t.titleDescription);
         mTitleView.setTextColor(t.useLightOnPrimaryColor ?
                 mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
+        if (!t.isDockable && ssp.hasDockedTask()) {
+            mSubTitleView.setVisibility(View.VISIBLE);
+            mSubTitleView.setTextColor(t.useLightOnPrimaryColor ?
+                    mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
+        } else {
+            mSubTitleView.setVisibility(View.GONE);
+        }
         mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
                 mLightDismissDrawable : mDarkDismissDrawable);
         mDismissButton.setContentDescription(t.dismissDescription);
@@ -416,6 +501,7 @@
 
         // In accessibility, a single click on the focused app info button will show it
         if (touchExplorationEnabled) {
+            mIconView.setContentDescription(t.appInfoDescription);
             mIconView.setOnClickListener(this);
         }
     }
@@ -559,6 +645,7 @@
             mAppInfoView = (ImageView) mAppOverlayView.findViewById(R.id.app_info);
             mAppInfoView.setOnClickListener(this);
             mAppTitleView = (TextView) mAppOverlayView.findViewById(R.id.app_title);
+            updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
         }
 
         // Update the overlay contents for the current app
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 0fec9c3..e5ac0d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.recents.views;
 
+import android.app.ActivityManager;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
@@ -34,6 +36,8 @@
 import android.view.ViewDebug;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
 
 
@@ -43,17 +47,24 @@
  */
 public class TaskViewThumbnail extends View {
 
-
     private static final ColorMatrix TMP_FILTER_COLOR_MATRIX = new ColorMatrix();
     private static final ColorMatrix TMP_BRIGHTNESS_COLOR_MATRIX = new ColorMatrix();
 
     private Task mTask;
 
+    private Rect mDisplayRect = new Rect();
+    private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
+
     // Drawing
     @ViewDebug.ExportedProperty(category="recents")
+    Rect mTaskViewRect = new Rect();
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mThumbnailRect = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    Rect mTaskViewRect = new Rect();
+    float mThumbnailScale;
+    float mFullscreenThumbnailScale;
+    ActivityManager.TaskThumbnailInfo mThumbnailInfo;
+
     int mCornerRadius;
     @ViewDebug.ExportedProperty(category="recents")
     float mDimAlpha;
@@ -97,6 +108,8 @@
         mCornerRadius = getResources().getDimensionPixelSize(
                 R.dimen.recents_task_view_rounded_corners_radius);
         mBgFillPaint.setColor(Color.WHITE);
+        mFullscreenThumbnailScale = context.getResources().getFraction(
+                com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
     }
 
     /**
@@ -114,57 +127,78 @@
     }
 
     @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        mOrientation = ssp.getDisplayOrientation();
+        mDisplayRect = ssp.getDisplayRect();
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         if (mInvisible) {
             return;
         }
 
-        int thumbnailHeight = (int) (((float) mTaskViewRect.width() / mThumbnailRect.width()) *
-                mThumbnailRect.height());
-        if (thumbnailHeight >= mTaskViewRect.height()) {
-            // The thumbnail fills the full task view bounds, so just draw it
-            canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
-                    mCornerRadius, mCornerRadius, mDrawPaint);
-        } else {
-            int count = 0;
-            if (thumbnailHeight > 0) {
-                // The thumbnail only covers part of the task view bounds, so fill in the
-                // non-thumbnail space with the default background color.  This is the equivalent of
-                // the GL border texture mode.
-                count = canvas.save();
+        int viewWidth = mTaskViewRect.width();
+        int viewHeight = mTaskViewRect.height();
+        if (mBitmapShader != null) {
+
+            // We are drawing the thumbnail in the same orientation, so just fit the width
+            int thumbnailWidth = (int) (mThumbnailRect.width() * mThumbnailScale);
+            int thumbnailHeight = (int) (mThumbnailRect.height() * mThumbnailScale);
+
+            if (thumbnailWidth >= viewWidth && thumbnailHeight >= viewHeight) {
+                // Thumbnail fills the full task view bounds, so just draw it
+                canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
+                        mDrawPaint);
+            } else {
+                // Thumbnail does not fill the full task view bounds, so just draw it and fill the
+                // empty areas with the background color
+                int count = canvas.save();
 
                 // Since we only want the top corners to be rounded, draw slightly beyond the
                 // thumbnail height, but clip to the thumbnail height
-                canvas.clipRect(0, 0, mTaskViewRect.width(), thumbnailHeight, Region.Op.REPLACE);
-                canvas.drawRoundRect(0, 0, mTaskViewRect.width(), thumbnailHeight + mCornerRadius,
+                canvas.clipRect(0, 0, thumbnailWidth, thumbnailHeight, Region.Op.REPLACE);
+                canvas.drawRoundRect(0, 0,
+                        thumbnailWidth + (thumbnailWidth < viewWidth ? mCornerRadius : 0),
+                        thumbnailHeight + (thumbnailHeight < viewHeight ? mCornerRadius : 0),
                         mCornerRadius, mCornerRadius, mDrawPaint);
-            }
 
-            // In the remaining space, draw the background color
-            canvas.clipRect(0, thumbnailHeight, mTaskViewRect.width(), mTaskViewRect.height(),
-                    Region.Op.REPLACE);
-            canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
-                    mTaskViewRect.width(), mTaskViewRect.height(), mCornerRadius, mCornerRadius,
-                    mBgFillPaint);
+                // In the remaining space, draw the background color
+                if (thumbnailWidth < viewWidth) {
+                    canvas.clipRect(thumbnailWidth, 0, viewWidth, viewHeight, Region.Op.REPLACE);
+                    canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0,
+                            viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint);
+                }
+                if (thumbnailWidth > 0 && thumbnailHeight < viewHeight) {
+                    canvas.clipRect(0, thumbnailHeight, viewWidth, viewHeight, Region.Op.REPLACE);
+                    canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+                            viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint);
+                }
 
-            if (thumbnailHeight > 0) {
                 canvas.restoreToCount(count);
             }
+        } else {
+            canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
+                    mBgFillPaint);
         }
     }
 
     /** Sets the thumbnail to a given bitmap. */
-    void setThumbnail(Bitmap bm) {
+    void setThumbnail(Bitmap bm, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
         if (bm != null) {
-            mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP,
-                    Shader.TileMode.CLAMP);
+            mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
             mDrawPaint.setShader(mBitmapShader);
             mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight());
+            mThumbnailInfo = thumbnailInfo;
             updateThumbnailScale();
         } else {
             mBitmapShader = null;
             mDrawPaint.setShader(null);
             mThumbnailRect.setEmpty();
+            mThumbnailInfo = null;
         }
     }
 
@@ -183,9 +217,9 @@
                 mat[0] = scale;
                 mat[6] = scale;
                 mat[12] = scale;
-                mat[4] = mDimAlpha;
-                mat[9] = mDimAlpha;
-                mat[14] = mDimAlpha;
+                mat[4] = mDimAlpha * 255f;
+                mat[9] = mDimAlpha * 255f;
+                mat[14] = mDimAlpha * 255f;
                 TMP_FILTER_COLOR_MATRIX.preConcat(TMP_BRIGHTNESS_COLOR_MATRIX);
                 ColorMatrixColorFilter filter = new ColorMatrixColorFilter(TMP_FILTER_COLOR_MATRIX);
                 mDrawPaint.setColorFilter(filter);
@@ -210,20 +244,41 @@
      * Updates the scale of the bitmap relative to this view.
      */
     public void updateThumbnailScale() {
+        mThumbnailScale = 1f;
         if (mBitmapShader != null) {
-            float thumbnailScale;
-            if (!mTask.isFreeformTask() || mTask.bounds == null) {
-                // If this is a stack task, or a stack task moved into the freeform workspace, then
-                // just scale this thumbnail to fit the width of the view
-                thumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width();
+            // We consider this a stack task if it is not freeform (ie. has no bounds) or has been
+            // dragged into the stack from the freeform workspace
+            boolean isStackTask = !mTask.isFreeformTask() || mTask.bounds == null;
+            if (mTaskViewRect.isEmpty() || mThumbnailInfo == null ||
+                    mThumbnailInfo.taskWidth == 0 || mThumbnailInfo.taskHeight == 0) {
+                // If we haven't measured or the thumbnail is invalid, skip the thumbnail drawing
+                // and only draw the background color
+                mThumbnailScale = 0f;
+            } else if (isStackTask) {
+                float invThumbnailScale = 1f / mFullscreenThumbnailScale;
+                if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
+                    if (mThumbnailInfo.screenOrientation == Configuration.ORIENTATION_PORTRAIT) {
+                        // If we are in the same orientation as the screenshot, just scale it to the
+                        // width of the task view
+                        mThumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width();
+                    } else {
+                        // Scale the landscape thumbnail up to app size, then scale that to the task
+                        // view size to match other portrait screenshots
+                        mThumbnailScale = invThumbnailScale *
+                                ((float) mTaskViewRect.width() / mDisplayRect.width());
+                    }
+                } else {
+                    // Otherwise, scale the screenshot to fit 1:1 in the current orientation
+                    mThumbnailScale = invThumbnailScale;
+                }
             } else {
                 // Otherwise, if this is a freeform task with task bounds, then scale the thumbnail
                 // to fit the entire bitmap into the task bounds
-                thumbnailScale = Math.min(
+                mThumbnailScale = Math.min(
                         (float) mTaskViewRect.width() / mThumbnailRect.width(),
                         (float) mTaskViewRect.height() / mThumbnailRect.height());
             }
-            mScaleMatrix.setScale(thumbnailScale, thumbnailScale);
+            mScaleMatrix.setScale(mThumbnailScale, mThumbnailScale);
             mBitmapShader.setLocalMatrix(mScaleMatrix);
         }
         if (!mInvisible) {
@@ -261,22 +316,23 @@
     }
 
     /** Binds the thumbnail view to the task */
-    void rebindToTask(Task t, boolean disabledInSafeMode) {
+    void rebindToTask(Task t, ActivityManager.TaskThumbnailInfo thumbnailInfo,
+            boolean disabledInSafeMode) {
         mTask = t;
         mDisabledInSafeMode = disabledInSafeMode;
         if (t.thumbnail != null) {
-            setThumbnail(t.thumbnail);
-            if (t.colorBackground != 0) {
-                mBgFillPaint.setColor(t.colorBackground);
-            }
+            setThumbnail(t.thumbnail, thumbnailInfo);
         } else {
-            setThumbnail(null);
+            setThumbnail(null, null);
+        }
+        if (t.colorBackground != 0) {
+            mBgFillPaint.setColor(t.colorBackground);
         }
     }
 
     /** Unbinds the thumbnail view from the task */
     void unbindFromTask() {
         mTask = null;
-        setThumbnail(null);
+        setThumbnail(null, null);
     }
 }
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 0d16a79..b512393 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -121,6 +121,18 @@
     }
 
     /**
+     * @return whether {@param other} is the same transform as this
+     */
+    public boolean isSame(TaskViewTransform other) {
+        return translationZ == other.translationZ
+                && scale == other.scale
+                && other.alpha == alpha
+                && dimAlpha == other.dimAlpha
+                && visible == other.visible
+                && rect.equals(other.rect);
+    }
+
+    /**
      * Resets the current transform.
      */
     public void reset() {
@@ -214,4 +226,9 @@
         v.getViewBounds().setClipBottom(0);
         v.setLeftTopRightBottom(0, 0, 0, 0);
     }
+
+    @Override
+    public String toString() {
+        return "R: " + rect + " V: " + visible;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index e6a291c..eb08947 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -39,6 +39,7 @@
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.media.MediaActionSound;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -75,9 +76,9 @@
     Uri imageUri;
     Runnable finisher;
     int iconSize;
-    int result;
     int previewWidth;
     int previewheight;
+    int errorMsgResId;
 
     void clearImage() {
         image = null;
@@ -92,15 +93,13 @@
 /**
  * An AsyncTask that saves an image to the media store in the background.
  */
-class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
-        SaveImageInBackgroundData> {
-    private static final String TAG = "SaveImageInBackgroundTask";
+class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
 
     private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
     private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
     private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
 
-    private final int mNotificationId;
+    private final SaveImageInBackgroundData mParams;
     private final NotificationManager mNotificationManager;
     private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder;
     private final File mScreenshotDir;
@@ -119,10 +118,11 @@
     private static boolean mTickerAddSpace;
 
     SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data,
-            NotificationManager nManager, int nId) {
+            NotificationManager nManager) {
         Resources r = context.getResources();
 
         // Prepare all the output metadata
+        mParams = data;
         mImageTime = System.currentTimeMillis();
         String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
         mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);
@@ -166,25 +166,14 @@
 
         // Show the intermediate notification
         mTickerAddSpace = !mTickerAddSpace;
-        mNotificationId = nId;
         mNotificationManager = nManager;
         final long now = System.currentTimeMillis();
 
-        mNotificationBuilder = new Notification.Builder(context)
-            .setTicker(r.getString(R.string.screenshot_saving_ticker)
-                    + (mTickerAddSpace ? " " : ""))
-            .setContentTitle(r.getString(R.string.screenshot_saving_title))
-            .setContentText(r.getString(R.string.screenshot_saving_text))
-            .setSmallIcon(R.drawable.stat_notify_image)
-            .setWhen(now)
-            .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color));
-
+        // Setup the notification
         mNotificationStyle = new Notification.BigPictureStyle()
-            .bigPicture(picture.createAshmemBitmap());
-        mNotificationBuilder.setStyle(mNotificationStyle);
+                .bigPicture(picture.createAshmemBitmap());
 
-        // For "public" situations we want to show all the same info but
-        // omit the actual screenshot image.
+        // The public notification will show similar info but with the actual screenshot omitted
         mPublicNotificationBuilder = new Notification.Builder(context)
                 .setContentTitle(r.getString(R.string.screenshot_saving_title))
                 .setContentText(r.getString(R.string.screenshot_saving_text))
@@ -194,11 +183,24 @@
                 .setColor(r.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
 
-        mNotificationBuilder.setPublicVersion(mPublicNotificationBuilder.build());
+        mNotificationBuilder = new Notification.Builder(context)
+            .setTicker(r.getString(R.string.screenshot_saving_ticker)
+                    + (mTickerAddSpace ? " " : ""))
+            .setContentTitle(r.getString(R.string.screenshot_saving_title))
+            .setContentText(r.getString(R.string.screenshot_saving_text))
+            .setSmallIcon(R.drawable.stat_notify_image)
+            .setWhen(now)
+            .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color))
+            .setStyle(mNotificationStyle)
+            .setPublicVersion(mPublicNotificationBuilder.build());
+        mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
 
-        Notification n = mNotificationBuilder.build();
-        n.flags |= Notification.FLAG_NO_CLEAR;
-        mNotificationManager.notify(nId, n);
+        mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
+
+        /**
+         * NOTE: The following code prepares the notification builder for updating the notification
+         * after the screenshot has been written to disk.
+         */
 
         // On the tablet, the large icon makes the notification appear as if it is clickable (and
         // on small devices, the large icon is not shown) so defer showing the large icon until
@@ -209,11 +211,8 @@
     }
 
     @Override
-    protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
-        if (params.length != 1) return null;
+    protected Void doInBackground(Void... params) {
         if (isCancelled()) {
-            params[0].clearImage();
-            params[0].clearContext();
             return null;
         }
 
@@ -221,8 +220,8 @@
         // it back up so that we save a little quicker.
         Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
 
-        Context context = params[0].context;
-        Bitmap image = params[0].image;
+        Context context = mParams.context;
+        Bitmap image = mParams.image;
         Resources r = context.getResources();
 
         try {
@@ -263,36 +262,37 @@
             sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
 
             // Create a share action for the notification
-            final PendingIntent callback = PendingIntent.getBroadcast(context, 0,
-                    new Intent(context, GlobalScreenshot.TargetChosenReceiver.class)
-                            .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId),
+            PendingIntent chooseAction = PendingIntent.getBroadcast(context, 0,
+                    new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
                     PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
             Intent chooserIntent = Intent.createChooser(sharingIntent, null,
-                    callback.getIntentSender());
-            chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
-                    | Intent.FLAG_ACTIVITY_NEW_TASK);
-            mNotificationBuilder.addAction(R.drawable.ic_screenshot_share,
-                    r.getString(com.android.internal.R.string.share),
-                    PendingIntent.getActivity(context, 0, chooserIntent,
-                            PendingIntent.FLAG_CANCEL_CURRENT));
+                    chooseAction.getIntentSender())
+                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+            PendingIntent shareAction = PendingIntent.getActivity(context, 0, chooserIntent,
+                    PendingIntent.FLAG_CANCEL_CURRENT);
+            Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
+                    R.drawable.ic_screenshot_share,
+                    r.getString(com.android.internal.R.string.share), shareAction);
+            mNotificationBuilder.addAction(shareActionBuilder.build());
 
             // Create a delete action for the notification
-            final PendingIntent deleteAction = PendingIntent.getBroadcast(context,  0,
+            PendingIntent deleteAction = PendingIntent.getBroadcast(context,  0,
                     new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
-                            .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId)
                             .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
                     PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
-            mNotificationBuilder.addAction(R.drawable.ic_screenshot_delete,
+            Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
+                    R.drawable.ic_screenshot_delete,
                     r.getString(com.android.internal.R.string.delete), deleteAction);
+            mNotificationBuilder.addAction(deleteActionBuilder.build());
 
-            params[0].imageUri = uri;
-            params[0].image = null;
-            params[0].result = 0;
+            mParams.imageUri = uri;
+            mParams.image = null;
+            mParams.errorMsgResId = 0;
         } catch (Exception e) {
             // IOException/UnsupportedOperationException may be thrown if external storage is not
             // mounted
-            params[0].clearImage();
-            params[0].result = 1;
+            mParams.clearImage();
+            mParams.errorMsgResId = R.string.screenshot_failed_to_save_text;
         }
 
         // Recycle the bitmap data
@@ -300,59 +300,64 @@
             image.recycle();
         }
 
-        return params[0];
+        return null;
     }
 
     @Override
-    protected void onPostExecute(SaveImageInBackgroundData params) {
-        if (isCancelled()) {
-            params.finisher.run();
-            params.clearImage();
-            params.clearContext();
-            return;
-        }
-
-        if (params.result > 0) {
+    protected void onPostExecute(Void params) {
+        if (mParams.errorMsgResId != 0) {
             // Show a message that we've failed to save the image to disk
-            GlobalScreenshot.notifyScreenshotError(params.context, mNotificationManager);
+            GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager,
+                    mParams.errorMsgResId);
         } else {
             // Show the final notification to indicate screenshot saved
-            Resources r = params.context.getResources();
+            Context context = mParams.context;
+            Resources r = context.getResources();
 
             // Create the intent to show the screenshot in gallery
             Intent launchIntent = new Intent(Intent.ACTION_VIEW);
-            launchIntent.setDataAndType(params.imageUri, "image/png");
+            launchIntent.setDataAndType(mParams.imageUri, "image/png");
             launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
             final long now = System.currentTimeMillis();
 
+            // Update the text and the icon for the existing notification
+            mPublicNotificationBuilder
+                    .setContentTitle(r.getString(R.string.screenshot_saved_title))
+                    .setContentText(r.getString(R.string.screenshot_saved_text))
+                    .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
+                    .setWhen(now)
+                    .setAutoCancel(true)
+                    .setColor(context.getColor(
+                            com.android.internal.R.color.system_notification_accent_color));
             mNotificationBuilder
                 .setContentTitle(r.getString(R.string.screenshot_saved_title))
                 .setContentText(r.getString(R.string.screenshot_saved_text))
-                .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
+                .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
                 .setWhen(now)
                 .setAutoCancel(true)
-                .setColor(r.getColor(
-                        com.android.internal.R.color.system_notification_accent_color));;
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setPublicVersion(mPublicNotificationBuilder.build())
+                .setFlag(Notification.FLAG_NO_CLEAR, false);
 
-            // Update the text in the public version as well
-            mPublicNotificationBuilder
-                .setContentTitle(r.getString(R.string.screenshot_saved_title))
-                .setContentText(r.getString(R.string.screenshot_saved_text))
-                .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
-                .setWhen(now)
-                .setAutoCancel(true)
-                .setColor(r.getColor(
-                        com.android.internal.R.color.system_notification_accent_color));
-
-            mNotificationBuilder.setPublicVersion(mPublicNotificationBuilder.build());
-
-            Notification n = mNotificationBuilder.build();
-            n.flags &= ~Notification.FLAG_NO_CLEAR;
-            mNotificationManager.notify(mNotificationId, n);
+            mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
         }
-        params.finisher.run();
-        params.clearContext();
+        mParams.finisher.run();
+        mParams.clearContext();
+    }
+
+    @Override
+    protected void onCancelled(Void params) {
+        // If we are cancelled while the task is running in the background, we may get null params.
+        // The finisher is expected to always be called back, so just use the baked-in params from
+        // the ctor in any case.
+        mParams.finisher.run();
+        mParams.clearImage();
+        mParams.clearContext();
+
+        // Cancel the posted notification
+        mNotificationManager.cancel(R.id.notification_screenshot);
     }
 }
 
@@ -379,16 +384,7 @@
     }
 }
 
-/**
- * TODO:
- *   - Performance when over gl surfaces? Ie. Gallery
- *   - what do we say in the Toast? Which icon do we get if the user uses another
- *     type of gallery?
- */
 class GlobalScreenshot {
-    private static final String TAG = "GlobalScreenshot";
-
-    static final String CANCEL_ID = "android:cancel_id";
     static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
 
     private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
@@ -416,6 +412,7 @@
 
     private Bitmap mScreenBitmap;
     private View mScreenshotLayout;
+    private ScreenshotSelectorView mScreenshotSelectorView;
     private ImageView mBackgroundView;
     private ImageView mScreenshotView;
     private ImageView mScreenshotFlash;
@@ -426,7 +423,7 @@
     private float mBgPadding;
     private float mBgPaddingScale;
 
-    private AsyncTask<SaveImageInBackgroundData, Void, SaveImageInBackgroundData> mSaveInBgTask;
+    private AsyncTask<Void, Void, Void> mSaveInBgTask;
 
     private MediaActionSound mCameraSound;
 
@@ -446,7 +443,11 @@
         mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
         mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
         mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
+        mScreenshotSelectorView = (ScreenshotSelectorView) mScreenshotLayout.findViewById(
+                R.id.global_screenshot_selector);
         mScreenshotLayout.setFocusable(true);
+        mScreenshotSelectorView.setFocusable(true);
+        mScreenshotSelectorView.setFocusableInTouchMode(true);
         mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
@@ -458,7 +459,7 @@
         // Setup the window that we are going to use
         mWindowLayoutParams = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
-                WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+                WindowManager.LayoutParams.TYPE_SCREENSHOT,
                 WindowManager.LayoutParams.FLAG_FULLSCREEN
                     | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                     | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
@@ -512,8 +513,8 @@
         if (mSaveInBgTask != null) {
             mSaveInBgTask.cancel(false);
         }
-        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager,
-                R.id.notification_screenshot).execute(data);
+        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager)
+                .execute();
     }
 
     /**
@@ -534,7 +535,8 @@
     /**
      * Takes a screenshot of the current display and shows an animation.
      */
-    void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
+    void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible,
+            int x, int y, int width, int height) {
         // We need to orient the screenshot correctly (and the Surface api seems to take screenshots
         // only in the natural orientation of the device :!)
         mDisplay.getRealMetrics(mDisplayMetrics);
@@ -553,7 +555,8 @@
         // Take the screenshot
         mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
         if (mScreenBitmap == null) {
-            notifyScreenshotError(mContext, mNotificationManager);
+            notifyScreenshotError(mContext, mNotificationManager,
+                    R.string.screenshot_failed_to_capture_text);
             finisher.run();
             return;
         }
@@ -573,6 +576,13 @@
             mScreenBitmap = ss;
         }
 
+        if (width != mDisplayMetrics.widthPixels || height != mDisplayMetrics.heightPixels) {
+            // Crop the screenshot to selected region
+            Bitmap cropped = Bitmap.createBitmap(mScreenBitmap, x, y, width, height);
+            mScreenBitmap.recycle();
+            mScreenBitmap = cropped;
+        }
+
         // Optimizations
         mScreenBitmap.setHasAlpha(false);
         mScreenBitmap.prepareToDraw();
@@ -582,6 +592,71 @@
                 statusBarVisible, navBarVisible);
     }
 
+    void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
+        mDisplay.getRealMetrics(mDisplayMetrics);
+        takeScreenshot(finisher, statusBarVisible, navBarVisible, 0, 0, mDisplayMetrics.widthPixels,
+                mDisplayMetrics.heightPixels);
+    }
+
+    /**
+     * Displays a screenshot selector
+     */
+    void takeScreenshotPartial(final Runnable finisher, final boolean statusBarVisible,
+            final boolean navBarVisible) {
+        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+        mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                ScreenshotSelectorView view = (ScreenshotSelectorView) v;
+                switch (event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        view.startSelection((int) event.getX(), (int) event.getY());
+                        return true;
+                    case MotionEvent.ACTION_MOVE:
+                        view.updateSelection((int) event.getX(), (int) event.getY());
+                        return true;
+                    case MotionEvent.ACTION_UP:
+                        view.setVisibility(View.GONE);
+                        mWindowManager.removeView(mScreenshotLayout);
+                        final Rect rect = view.getSelectionRect();
+                        if (rect != null) {
+                            if (rect.width() != 0 && rect.height() != 0) {
+                                // Need mScreenshotLayout to handle it after the view disappears
+                                mScreenshotLayout.post(new Runnable() {
+                                    public void run() {
+                                        takeScreenshot(finisher, statusBarVisible, navBarVisible,
+                                                rect.left, rect.top, rect.width(), rect.height());
+                                    }
+                                });
+                            }
+                        }
+
+                        view.stopSelection();
+                        return true;
+                }
+
+                return false;
+            }
+        });
+        mScreenshotLayout.post(new Runnable() {
+            @Override
+            public void run() {
+                mScreenshotSelectorView.setVisibility(View.VISIBLE);
+                mScreenshotSelectorView.requestFocus();
+            }
+        });
+    }
+
+    /**
+     * Cancels screenshot request
+     */
+    void stopScreenshot() {
+        // If the selector layer still presents on screen, we remove it and resets its state.
+        if (mScreenshotSelectorView.getSelectionRect() != null) {
+            mWindowManager.removeView(mScreenshotLayout);
+            mScreenshotSelectorView.stopSelection();
+        }
+    }
 
     /**
      * Starts the animation after taking the screenshot
@@ -763,14 +838,15 @@
         return anim;
     }
 
-    static void notifyScreenshotError(Context context, NotificationManager nManager) {
+    static void notifyScreenshotError(Context context, NotificationManager nManager, int msgResId) {
         Resources r = context.getResources();
+        String errorMsg = r.getString(msgResId);
 
-        // Clear all existing notification, compose the new notification and show it
+        // Repurpose the existing notification to notify the user of the error
         Notification.Builder b = new Notification.Builder(context)
             .setTicker(r.getString(R.string.screenshot_failed_title))
             .setContentTitle(r.getString(R.string.screenshot_failed_title))
-            .setContentText(r.getString(R.string.screenshot_failed_text))
+            .setContentText(errorMsg)
             .setSmallIcon(R.drawable.stat_notify_image_error)
             .setWhen(System.currentTimeMillis())
             .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
@@ -778,9 +854,9 @@
             .setAutoCancel(true)
             .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
-        Notification n =
-            new Notification.BigTextStyle(b)
-                .bigText(r.getString(R.string.screenshot_failed_text))
+
+        Notification n = new Notification.BigTextStyle(b)
+                .bigText(errorMsg)
                 .build();
         nManager.notify(R.id.notification_screenshot, n);
     }
@@ -791,15 +867,10 @@
     public static class TargetChosenReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (!intent.hasExtra(CANCEL_ID)) {
-                return;
-            }
-
             // Clear the notification
             final NotificationManager nm =
                     (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-            final int id = intent.getIntExtra(CANCEL_ID, 0);
-            nm.cancel(id);
+            nm.cancel(R.id.notification_screenshot);
         }
     }
 
@@ -809,16 +880,15 @@
     public static class DeleteScreenshotReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (!intent.hasExtra(CANCEL_ID) || !intent.hasExtra(SCREENSHOT_URI_ID)) {
+            if (!intent.hasExtra(SCREENSHOT_URI_ID)) {
                 return;
             }
 
             // Clear the notification
             final NotificationManager nm =
                     (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-            final int id = intent.getIntExtra(CANCEL_ID, 0);
             final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
-            nm.cancel(id);
+            nm.cancel(R.id.notification_screenshot);
 
             // And delete the image from the media store
             new DeleteImageInBackgroundTask(context).execute(uri);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java
new file mode 100644
index 0000000..07a9246
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.screenshot;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Draws a selection rectangle while taking screenshot
+ */
+public class ScreenshotSelectorView extends View {
+    private Point mStartPoint;
+    private Rect mSelectionRect;
+    private final Paint mPaintSelection, mPaintBackground;
+
+    public ScreenshotSelectorView(Context context) {
+        this(context, null);
+    }
+
+    public ScreenshotSelectorView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mPaintBackground = new Paint(Color.BLACK);
+        mPaintBackground.setAlpha(160);
+        mPaintSelection = new Paint(Color.TRANSPARENT);
+        mPaintSelection.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+    }
+
+    public void startSelection(int x, int y) {
+        mStartPoint = new Point(x, y);
+        mSelectionRect = new Rect(x, y, x, y);
+    }
+
+    public void updateSelection(int x, int y) {
+        if (mSelectionRect != null) {
+            mSelectionRect.left = Math.min(mStartPoint.x, x);
+            mSelectionRect.right = Math.max(mStartPoint.x, x);
+            mSelectionRect.top = Math.min(mStartPoint.y, y);
+            mSelectionRect.bottom = Math.max(mStartPoint.y, y);
+            invalidate();
+        }
+    }
+
+    public Rect getSelectionRect() {
+        return mSelectionRect;
+    }
+
+    public void stopSelection() {
+        mStartPoint = null;
+        mSelectionRect = null;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.drawRect(mLeft, mTop, mRight, mBottom, mPaintBackground);
+        if (mSelectionRect != null) {
+            canvas.drawRect(mSelectionRect, mPaintSelection);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotServiceErrorReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotServiceErrorReceiver.java
new file mode 100644
index 0000000..fc2a1e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotServiceErrorReceiver.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.screenshot;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.systemui.R;
+
+/**
+ * Performs a number of miscellaneous, non-system-critical actions
+ * after the system has finished booting.
+ */
+public class ScreenshotServiceErrorReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        // Show a message that we've failed to save the image to disk
+        NotificationManager nm = (NotificationManager)
+                context.getSystemService(Context.NOTIFICATION_SERVICE);
+        GlobalScreenshot.notifyScreenshotError(context, nm,
+                R.string.screenshot_failed_to_save_unknown_text);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 456b5fa..4badc42 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.view.WindowManager;
 
 public class TakeScreenshotService extends Service {
     private static final String TAG = "TakeScreenshotService";
@@ -32,21 +33,28 @@
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case 1:
-                    final Messenger callback = msg.replyTo;
-                    if (mScreenshot == null) {
-                        mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
+            final Messenger callback = msg.replyTo;
+            Runnable finisher = new Runnable() {
+                @Override
+                public void run() {
+                    Message reply = Message.obtain(null, 1);
+                    try {
+                        callback.send(reply);
+                    } catch (RemoteException e) {
                     }
-                    mScreenshot.takeScreenshot(new Runnable() {
-                        @Override public void run() {
-                            Message reply = Message.obtain(null, 1);
-                            try {
-                                callback.send(reply);
-                            } catch (RemoteException e) {
-                            }
-                        }
-                    }, msg.arg1 > 0, msg.arg2 > 0);
+                }
+            };
+            if (mScreenshot == null) {
+                mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
+            }
+
+            switch (msg.what) {
+                case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
+                    mScreenshot.takeScreenshot(finisher, msg.arg1 > 0, msg.arg2 > 0);
+                    break;
+                case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
+                    mScreenshot.takeScreenshotPartial(finisher, msg.arg1 > 0, msg.arg2 > 0);
+                    break;
             }
         }
     };
@@ -55,4 +63,10 @@
     public IBinder onBind(Intent intent) {
         return new Messenger(mHandler).getBinder();
     }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        if (mScreenshot != null) mScreenshot.stopScreenshot();
+        return true;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
new file mode 100644
index 0000000..69dcabe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.shortcut;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.KeyEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityManager;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.settingslib.accessibility.AccessibilityUtils;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.DividerView;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Dispatches shortcut to System UI components
+ */
+public class ShortcutKeyDispatcher extends SystemUI
+        implements ShortcutKeyServiceProxy.Callbacks {
+
+    private static final String TAG = "ShortcutKeyDispatcher";
+
+    private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
+    private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
+    private IActivityManager mActivityManager = ActivityManagerNative.getDefault();
+
+    protected final long META_MASK = ((long) KeyEvent.META_META_ON) << Integer.SIZE;
+    protected final long ALT_MASK = ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
+    protected final long CTRL_MASK = ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
+    protected final long SHIFT_MASK = ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
+
+    protected final long SC_DOCK_LEFT = META_MASK | KeyEvent.KEYCODE_LEFT_BRACKET;
+    protected final long SC_DOCK_RIGHT = META_MASK | KeyEvent.KEYCODE_RIGHT_BRACKET;
+
+    /**
+     * Registers a shortcut key to window manager.
+     * @param shortcutCode packed representation of shortcut key code and meta information
+     */
+    public void registerShortcutKey(long shortcutCode) {
+        try {
+            mWindowManagerService.registerShortcutKey(shortcutCode, mShortcutKeyServiceProxy);
+        } catch (RemoteException e) {
+            // Do nothing
+        }
+    }
+
+    @Override
+    public void onShortcutKeyPressed(long shortcutCode) {
+        int orientation = mContext.getResources().getConfiguration().orientation;
+        if ((shortcutCode == SC_DOCK_LEFT || shortcutCode == SC_DOCK_RIGHT)
+                && orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            handleDockKey(shortcutCode);
+        }
+    }
+
+    @Override
+    public void start() {
+        registerShortcutKey(SC_DOCK_LEFT);
+        registerShortcutKey(SC_DOCK_RIGHT);
+    }
+
+    private void handleDockKey(long shortcutCode) {
+        try {
+            int dockSide = mWindowManagerService.getDockedStackSide();
+            if (dockSide == WindowManager.DOCKED_INVALID) {
+                // If there is no window docked, we dock the top-most window.
+                Recents recents = getComponent(Recents.class);
+                int dockMode = (shortcutCode == SC_DOCK_LEFT)
+                        ? ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
+                        : ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+                recents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, dockMode, null);
+                MetricsLogger.action(mContext, MetricsEvent.WINDOW_DOCK_SHORTCUTS);
+            } else {
+                // If there is already a docked window, we respond by resizing the docking pane.
+                DividerView dividerView = getComponent(Divider.class).getView();
+                DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
+                int dividerPosition = dividerView.getCurrentPosition();
+                DividerSnapAlgorithm.SnapTarget currentTarget =
+                        snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
+                int increment = (shortcutCode == SC_DOCK_LEFT) ? -1 : 1;
+                DividerSnapAlgorithm.SnapTarget target = snapAlgorithm.cycleNonDismissTarget(
+                        currentTarget, increment);
+                dividerView.startDragging(true /* animate */, false /* touching */);
+                dividerView.stopDragging(target.position, 0f, true /* avoidDismissStart */);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "handleDockKey() failed.");
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyServiceProxy.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyServiceProxy.java
new file mode 100644
index 0000000..8ec862e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyServiceProxy.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.shortcut;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import com.android.internal.policy.IShortcutService;
+
+/**
+ * This class takes functions from IShortcutService that come in binder pool threads and
+ * post them onto shortcut handlers.
+ */
+public class ShortcutKeyServiceProxy extends IShortcutService.Stub {
+    private static final int MSG_SHORTCUT_RECEIVED = 1;
+
+    private final Object mLock = new Object();
+    private Callbacks mCallbacks;
+    private final Handler mHandler = new H();
+
+    public interface Callbacks {
+        void onShortcutKeyPressed(long shortcutCode);
+    }
+
+    public ShortcutKeyServiceProxy(Callbacks callbacks) { mCallbacks = callbacks; }
+
+    @Override
+    public void notifyShortcutKeyPressed(long shortcutCode) throws RemoteException {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_SHORTCUT_RECEIVED, shortcutCode).sendToTarget();
+        }
+    }
+
+    private final class H extends Handler {
+        public void handleMessage(Message msg) {
+            final int what = msg.what;
+            switch (what) {
+                case MSG_SHORTCUT_RECEIVED:
+                    mCallbacks.onShortcutKeyPressed((Long)msg.obj);
+                    break;
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index dd59fac..ddd3ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -41,6 +41,7 @@
     private DockDividerVisibilityListener mDockDividerVisibilityListener;
     private boolean mVisible = false;
     private boolean mMinimized = false;
+    private ForcedResizableInfoActivityController mForcedResizableController;
 
     @Override
     public void start() {
@@ -52,6 +53,7 @@
         mDockDividerVisibilityListener = new DockDividerVisibilityListener();
         SystemServicesProxy ssp = Recents.getSystemServices();
         ssp.registerDockedStackListener(mDockDividerVisibilityListener);
+        mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
     }
 
     @Override
@@ -95,6 +97,9 @@
                 if (mVisible != visible) {
                     mVisible = visible;
                     mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+
+                    // Update state because animations won't finish.
+                    mView.setMinimizedDockStack(mMinimized);
                 }
             }
         });
@@ -117,6 +122,15 @@
         });
     }
 
+    private void notifyDockedStackExistsChanged(final boolean exists) {
+        mView.post(new Runnable() {
+            @Override
+            public void run() {
+                mForcedResizableController.notifyDockedStackExistsChanged(exists);
+            }
+        });
+    }
+
     class DockDividerVisibilityListener extends IDockedStackListener.Stub {
 
         @Override
@@ -126,6 +140,7 @@
 
         @Override
         public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
+            notifyDockedStackExistsChanged(exists);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
index 9118e9c..d5f7b39 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -26,7 +26,7 @@
 import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.util.Property;
-import android.widget.ImageButton;
+import android.view.View;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -34,7 +34,7 @@
 /**
  * View for the handle in the docked stack divider.
  */
-public class DividerHandleView extends ImageButton {
+public class DividerHandleView extends View {
 
     private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
             = new Property<DividerHandleView, Integer>(Integer.class, "width") {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 65a2f8f..3005535 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.stackdivider;
 
+import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW;
+import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -27,9 +30,13 @@
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.hardware.display.DisplayManager;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.GestureDetector;
+import android.view.GestureDetector.OnDoubleTapListener;
+import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.MotionEvent;
 import android.view.PointerIcon;
 import android.view.VelocityTracker;
@@ -38,8 +45,11 @@
 import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver.InternalInsetsInfo;
 import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.WindowInsets;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
@@ -49,17 +59,18 @@
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.stackdivider.events.StartedDragingEvent;
+import com.android.systemui.stackdivider.events.StoppedDragingEvent;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 
-import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW;
-import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW;
-
 /**
  * Docked stack divider.
  */
@@ -72,18 +83,7 @@
     private static final String TAG = "DividerView";
 
     private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
-
-    /**
-     * Fraction of the divider position between two snap targets to switch to the full-screen
-     * target.
-     */
-    private static final float SWITCH_FULLSCREEN_FRACTION = 0.12f;
-
-    /**
-     * Fraction of the divider position between two snap targets to switch to the larger target
-     * for the bottom/right app layout.
-     */
-    private static final float BOTTOM_RIGHT_SWITCH_BIGGER_FRACTION = 0.2f;
+    private static final boolean SWAPPING_ENABLED = false;
 
     /**
      * How much the background gets scaled when we are in the minimized dock state.
@@ -120,6 +120,7 @@
     private final Rect mDockedInsetRect = new Rect();
     private final Rect mOtherInsetRect = new Rect();
     private final Rect mLastResizeRect = new Rect();
+    private final Rect mDisplayRect = new Rect();
     private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
     private DividerWindowManager mWindowManager;
     private VelocityTracker mVelocityTracker;
@@ -130,7 +131,53 @@
     private boolean mAnimateAfterRecentsDrawn;
     private boolean mGrowAfterRecentsDrawn;
     private boolean mGrowRecents;
-    private Animator mCurrentAnimator;
+    private ValueAnimator mCurrentAnimator;
+    private boolean mEntranceAnimationRunning;
+    private GestureDetector mGestureDetector;
+    private boolean mDockedStackMinimized;
+
+    private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(host, info);
+            if (isHorizontalDivision()) {
+                info.addAction(new AccessibilityAction(R.id.action_move_up,
+                        mContext.getString(R.string.accessibility_action_divider_move_up)));
+                info.addAction(new AccessibilityAction(R.id.action_move_down,
+                        mContext.getString(R.string.accessibility_action_divider_move_down)));
+            } else {
+                info.addAction(new AccessibilityAction(R.id.action_move_left,
+                        mContext.getString(R.string.accessibility_action_divider_move_left)));
+                info.addAction(new AccessibilityAction(R.id.action_move_right,
+                        mContext.getString(R.string.accessibility_action_divider_move_right)));
+            }
+        }
+
+        @Override
+        public boolean performAccessibilityAction(View host, int action, Bundle args) {
+            if (action == R.id.action_move_up || action == R.id.action_move_down
+                    || action == R.id.action_move_left || action == R.id.action_move_right) {
+                int position = getCurrentPosition();
+                SnapTarget currentTarget = mSnapAlgorithm.calculateSnapTarget(
+                        position, 0 /* velocity */);
+                SnapTarget nextTarget =
+                        action == R.id.action_move_up || action == R.id.action_move_left
+                                ? mSnapAlgorithm.getPreviousTarget(currentTarget)
+                                : mSnapAlgorithm.getNextTarget(currentTarget);
+                startDragging(true /* animate */, false /* touching */);
+                stopDragging(getCurrentPosition(), nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN);
+                return true;
+            }
+            return super.performAccessibilityAction(host, action, args);
+        }
+    };
+
+    private final Runnable mResetBackgroundRunnable = new Runnable() {
+        @Override
+        public void run() {
+            resetBackground();
+        }
+    };
 
     public DividerView(Context context) {
         super(context);
@@ -171,6 +218,22 @@
         mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
                 landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW));
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+        mHandle.setAccessibilityDelegate(mHandleDelegate);
+        mGestureDetector = new GestureDetector(mContext, new SimpleOnGestureListener() {
+            @Override
+            public boolean onSingleTapUp(MotionEvent e) {
+                if (SWAPPING_ENABLED) {
+                    updateDockSide();
+                    SystemServicesProxy ssp = Recents.getSystemServices();
+                    if (mDockSide != WindowManager.DOCKED_INVALID
+                            && !ssp.isRecentsTopMost(ssp.getTopMostTask(), null /* isTopHome */)) {
+                        mWindowManagerProxy.swapTasks();
+                        return true;
+                    }
+                }
+                return false;
+            }
+        });
     }
 
     @Override
@@ -201,6 +264,15 @@
         return super.onApplyWindowInsets(insets);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (changed) {
+            mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
+                    mHandle.getRight(), mHandle.getBottom()));
+        }
+    }
+
     public void setWindowManager(DividerWindowManager windowManager) {
         mWindowManager = windowManager;
     }
@@ -221,6 +293,7 @@
             mWindowManager.setSlippery(false);
             liftBackground();
         }
+        EventBus.getDefault().send(new StartedDragingEvent());
         return mDockSide != WindowManager.DOCKED_INVALID;
     }
 
@@ -278,6 +351,7 @@
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         convertToScreenCoordinates(event);
+        mGestureDetector.onTouchEvent(event);
         final int action = event.getAction() & MotionEvent.ACTION_MASK;
         switch (action) {
             case MotionEvent.ACTION_DOWN:
@@ -307,10 +381,9 @@
                     mMoving = true;
                 }
                 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
-                    int position = calculatePosition(x, y);
-                    SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
-                            0 /* velocity */, false /* hardDismiss */);
-                    resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
+                    SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(
+                            mStartPosition, 0 /* velocity */, false /* hardDismiss */);
+                    resizeStack(calculatePosition(x, y), mStartPosition, snapTarget);
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -371,6 +444,8 @@
                 mWindowManagerProxy.setResizing(false);
                 mDockSide = WindowManager.DOCKED_INVALID;
                 mCurrentAnimator = null;
+                mEntranceAnimationRunning = false;
+                EventBus.getDefault().send(new StoppedDragingEvent());
             }
         });
         mCurrentAnimator = anim;
@@ -451,16 +526,19 @@
     public void setMinimizedDockStack(boolean minimized) {
         updateDockSide();
         mHandle.setAlpha(minimized ? 0f : 1f);
-        if (mDockSide == WindowManager.DOCKED_TOP) {
+        if (!minimized) {
+            resetBackground();
+        } else if (mDockSide == WindowManager.DOCKED_TOP) {
             mBackground.setPivotY(0);
-            mBackground.setScaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+            mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
         } else if (mDockSide == WindowManager.DOCKED_LEFT
                 || mDockSide == WindowManager.DOCKED_RIGHT) {
             mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
                     ? 0
                     : mBackground.getWidth());
-            mBackground.setScaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+            mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
         }
+        mDockedStackMinimized = minimized;
     }
 
     public void setMinimizedDockStack(boolean minimized, long animDuration) {
@@ -482,10 +560,21 @@
             mBackground.animate()
                     .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
         }
+        if (!minimized) {
+            mBackground.animate().withEndAction(mResetBackgroundRunnable);
+        }
         mBackground.animate()
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .setDuration(animDuration)
                 .start();
+        mDockedStackMinimized = minimized;
+    }
+
+    private void resetBackground() {
+        mBackground.setPivotX(mBackground.getWidth() / 2);
+        mBackground.setPivotY(mBackground.getHeight() / 2);
+        mBackground.setScaleX(1f);
+        mBackground.setScaleY(1f);
     }
 
     @Override
@@ -554,7 +643,18 @@
         }
 
         mLastResizeRect.set(mDockedRect);
-        if (taskPosition != TASK_POSITION_SAME) {
+        if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
+            if (mCurrentAnimator != null) {
+                calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
+            } else {
+                calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
+                        mDockSide, mDockedTaskRect);
+            }
+            calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
+                    mOtherTaskRect);
+            mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
+                    mOtherTaskRect, null);
+        } else if (taskPosition != TASK_POSITION_SAME) {
             calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
                     mOtherRect);
             int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
@@ -562,24 +662,19 @@
                     restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
             int taskPositionOther =
                     restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
-
-            taskPositionDocked = minimizeHoles(position, taskPositionDocked, mDockSide,
-                    taskSnapTarget);
-            taskPositionOther = minimizeHoles(position, taskPositionOther, dockSideInverted,
-                    taskSnapTarget);
-
             calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
             calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
+            mDisplayRect.set(0, 0, mDisplayWidth, mDisplayHeight);
             alignTopLeft(mDockedRect, mDockedTaskRect);
             alignTopLeft(mOtherRect, mOtherTaskRect);
             mDockedInsetRect.set(mDockedTaskRect);
             mOtherInsetRect.set(mOtherTaskRect);
             if (dockSideTopLeft(mDockSide)) {
-                alignTopLeft(mDockedRect, mDockedInsetRect);
-                alignBottomRight(mOtherRect, mOtherInsetRect);
+                alignTopLeft(mDisplayRect, mDockedInsetRect);
+                alignBottomRight(mDisplayRect, mOtherInsetRect);
             } else {
-                alignBottomRight(mDockedRect, mDockedInsetRect);
-                alignTopLeft(mOtherRect, mOtherInsetRect);
+                alignBottomRight(mDisplayRect, mDockedInsetRect);
+                alignTopLeft(mDisplayRect, mOtherInsetRect);
             }
             applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
                     taskPositionDocked);
@@ -598,6 +693,9 @@
     }
 
     private float getDimFraction(int position, SnapTarget dismissTarget) {
+        if (mEntranceAnimationRunning) {
+            return 0f;
+        }
         float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
         fraction = Math.max(0, Math.min(fraction, 1f));
         fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
@@ -629,51 +727,6 @@
     }
 
     /**
-     * Given the current split position and the task position calculated by dragging, this
-     * method calculates a "better" task position in a sense so holes get smaller while dragging.
-     *
-     * @return the new task position
-     */
-    private int minimizeHoles(int position, int taskPosition, int dockSide,
-            SnapTarget taskSnapTarget) {
-        if (dockSideTopLeft(dockSide)) {
-            if (position > taskPosition) {
-                SnapTarget nextTarget = mSnapAlgorithm.getNextTarget(taskSnapTarget);
-
-                // If the next target is the dismiss end target, switch earlier to make the hole
-                // smaller.
-                if (nextTarget != taskSnapTarget
-                        && nextTarget == mSnapAlgorithm.getDismissEndTarget()) {
-                    float t = (float) (position - taskPosition)
-                            / (nextTarget.position - taskPosition);
-                    if (t > SWITCH_FULLSCREEN_FRACTION) {
-                        return nextTarget.position;
-                    }
-                }
-            }
-        } else if (dockSideBottomRight(dockSide)) {
-            if (position < taskPosition) {
-                SnapTarget previousTarget = mSnapAlgorithm.getPreviousTarget(taskSnapTarget);
-                if (previousTarget != taskSnapTarget) {
-                    float t = (float) (taskPosition - position)
-                            / (taskPosition - previousTarget.position);
-
-                    // In general, switch a bit earlier (at 20% instead of 50%), but if we are
-                    // dismissing the top, switch really early.
-                    float threshold = previousTarget == mSnapAlgorithm.getDismissStartTarget()
-                            ? SWITCH_FULLSCREEN_FRACTION
-                            : BOTTOM_RIGHT_SWITCH_BIGGER_FRACTION;
-                    if (t > threshold) {
-                        return previousTarget.position;
-                    }
-
-                }
-            }
-        }
-        return taskPosition;
-    }
-
-    /**
      * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
      * 0 size.
      */
@@ -698,21 +751,22 @@
                 mSnapAlgorithm.calculateDismissingFraction(position)));
         SnapTarget dismissTarget = null;
         SnapTarget splitTarget = null;
-        if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
-                || snapTarget == mSnapAlgorithm.getFirstSplitTarget())
+        int start = 0;
+        if (position <= mSnapAlgorithm.getLastSplitTarget().position
                 && dockSideTopLeft(dockSide)) {
             dismissTarget = mSnapAlgorithm.getDismissStartTarget();
             splitTarget = mSnapAlgorithm.getFirstSplitTarget();
-        } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
-                || snapTarget == mSnapAlgorithm.getLastSplitTarget())
+            start = taskPosition;
+        } else if (position >= mSnapAlgorithm.getLastSplitTarget().position
                 && dockSideBottomRight(dockSide)) {
             dismissTarget = mSnapAlgorithm.getDismissEndTarget();
             splitTarget = mSnapAlgorithm.getLastSplitTarget();
+            start = splitTarget.position;
         }
         if (dismissTarget != null && fraction > 0f
                 && isDismissing(splitTarget, position, dockSide)) {
             fraction = calculateParallaxDismissingFraction(fraction, dockSide);
-            int offsetPosition = (int) (taskPosition +
+            int offsetPosition = (int) (start +
                     fraction * (dismissTarget.position - splitTarget.position));
             int width = taskRect.width();
             int height = taskRect.height();
@@ -760,11 +814,12 @@
     }
 
     private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
-        if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
-                (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
+        if ((dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
+                || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
+                        && dockSideBottomRight(mDockSide))) {
             return StackId.DOCKED_STACK_ID;
         } else {
-            return StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+            return StackId.HOME_STACK_ID;
         }
     }
 
@@ -799,12 +854,18 @@
         }
     }
 
-    public final void onBusEvent(DockingTopTaskEvent dockingEvent) {
-        if (dockingEvent.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
+    public final void onBusEvent(DockedTopTaskEvent event) {
+        if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
             mGrowAfterRecentsDrawn = false;
             mAnimateAfterRecentsDrawn = true;
             startDragging(false /* animate */, false /* touching */);
         }
+        updateDockSide();
+        int position = DockedDividerUtils.calculatePositionForBounds(event.initialRect,
+                mDockSide, mDividerSize);
+        mEntranceAnimationRunning = true;
+        resizeStack(position, mSnapAlgorithm.getMiddleTarget().position,
+                mSnapAlgorithm.getMiddleTarget());
     }
 
     public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
@@ -824,7 +885,7 @@
 
     public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
         int dockSide = mWindowManagerProxy.getDockSide();
-        if (dockSide != WindowManager.DOCKED_INVALID) {
+        if (dockSide != WindowManager.DOCKED_INVALID && !mDockedStackMinimized) {
             startDragging(false /* animate */, false /* touching */);
             SnapTarget target = dockSideTopLeft(dockSide)
                     ? mSnapAlgorithm.getDismissEndTarget()
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
new file mode 100644
index 0000000..f728dab
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.stackdivider;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+
+import com.android.systemui.R;
+
+/**
+ * Translucent activity that gets started on top of a task in multi-window to inform the user that
+ * we forced the activity below to be resizable.
+ */
+public class ForcedResizableInfoActivity extends Activity implements OnTouchListener {
+
+    private static final long DISMISS_DELAY = 2500;
+
+    private final Runnable mFinishRunnable = new Runnable() {
+        @Override
+        public void run() {
+            finish();
+        }
+    };
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.forced_resizable_activity);
+        getWindow().getDecorView().setOnTouchListener(this);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        getWindow().getDecorView().postDelayed(mFinishRunnable, DISMISS_DELAY);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        finish();
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        finish();
+        return true;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        finish();
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
new file mode 100644
index 0000000..9b56037
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.stackdivider;
+
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
+import com.android.systemui.recents.events.activity.ForcedResizableEvent;
+import com.android.systemui.stackdivider.events.StartedDragingEvent;
+import com.android.systemui.stackdivider.events.StoppedDragingEvent;
+
+/**
+ * Controller that decides when to show the {@link ForcedResizableInfoActivity}.
+ */
+public class ForcedResizableInfoActivityController {
+
+    private static final String SELF_PACKAGE_NAME = "com.android.systemui";
+
+    private static final int TIMEOUT = 1000;
+    private final Context mContext;
+    private final Handler mHandler = new Handler();
+    private final ArraySet<Integer> mPendingTaskIds = new ArraySet<>();
+    private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
+    private boolean mDividerDraging;
+
+    private final Runnable mTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            showPending();
+        }
+    };
+
+    public ForcedResizableInfoActivityController(Context context) {
+        mContext = context;
+        EventBus.getDefault().register(this);
+    }
+
+    public void notifyDockedStackExistsChanged(boolean exists) {
+        if (!exists) {
+            mPackagesShownInSession.clear();
+        }
+    }
+
+    public final void onBusEvent(ForcedResizableEvent forcedResizableEvent) {
+        if (debounce(forcedResizableEvent.packageName)) {
+            return;
+        }
+        mPendingTaskIds.add(forcedResizableEvent.taskId);
+        postTimeout();
+    }
+
+    public final void onBusEvent(AppTransitionFinishedEvent event) {
+        if (!mDividerDraging) {
+            showPending();
+        }
+    }
+
+    public final void onBusEvent(StartedDragingEvent event) {
+        mDividerDraging = true;
+        mHandler.removeCallbacks(mTimeoutRunnable);
+    }
+
+    public final void onBusEvent(StoppedDragingEvent event) {
+        mDividerDraging = false;
+        showPending();
+    }
+
+    private void showPending() {
+        mHandler.removeCallbacks(mTimeoutRunnable);
+        for (int i = mPendingTaskIds.size() - 1; i >= 0; i--) {
+            Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
+            ActivityOptions options = ActivityOptions.makeBasic();
+            options.setLaunchTaskId(mPendingTaskIds.valueAt(i));
+            mContext.startActivity(intent, options.toBundle());
+        }
+        mPendingTaskIds.clear();
+    }
+
+    private void postTimeout() {
+        mHandler.removeCallbacks(mTimeoutRunnable);
+        mHandler.postDelayed(mTimeoutRunnable, TIMEOUT);
+    }
+
+    private boolean debounce(String packageName) {
+        if (packageName == null) {
+            return false;
+        }
+
+        // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that
+        // triggers another notification. So ignore our own activity.
+        if (SELF_PACKAGE_NAME.equals(packageName)) {
+            return true;
+        }
+        boolean debounce = mPackagesShownInSession.contains(packageName);
+        mPackagesShownInSession.add(packageName);
+        return debounce;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 15bcaf8..ef32f7e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.stackdivider;
 
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.view.WindowManager.DOCKED_INVALID;
+
 import android.app.ActivityManagerNative;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -27,9 +30,6 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.view.WindowManager.DOCKED_INVALID;
-
 /**
  * Proxy to simplify calls into window manager/activity manager
  */
@@ -39,7 +39,7 @@
 
     private static final WindowManagerProxy sInstance = new WindowManagerProxy();
 
-    @GuardedBy("mResizeRect")
+    @GuardedBy("mDockedRect")
     private final Rect mDockedRect = new Rect();
     private final Rect mTempDockedTaskRect = new Rect();
     private final Rect mTempDockedInsetRect = new Rect();
@@ -52,6 +52,9 @@
     private final Rect mTmpRect4 = new Rect();
     private final Rect mTmpRect5 = new Rect();
 
+    @GuardedBy("mDockedRect")
+    private final Rect mTouchableRegion = new Rect();
+
     private boolean mDimLayerVisible;
     private int mDimLayerTargetStack;
     private float mDimLayerAlpha;
@@ -97,8 +100,8 @@
         @Override
         public void run() {
             try {
-                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, true,
-                        false);
+                ActivityManagerNative.getDefault().resizeStack(
+                        DOCKED_STACK_ID, null, true, true, false, -1);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to resize stack: " + e);
             }
@@ -117,6 +120,32 @@
         }
     };
 
+    private final Runnable mSwapRunnable = new Runnable() {
+        @Override
+        public void run() {
+            try {
+                ActivityManagerNative.getDefault().swapDockedAndFullscreenStack();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to resize stack: " + e);
+            }
+        }
+    };
+
+    private final Runnable mSetTouchableRegionRunnable = new Runnable() {
+        @Override
+        public void run() {
+            try {
+                synchronized (mDockedRect) {
+                    mTmpRect1.set(mTouchableRegion);
+                }
+                WindowManagerGlobal.getWindowManagerService().setDockedStackDividerTouchRegion(
+                        mTmpRect1);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to set touchable region: " + e);
+            }
+        }
+    };
+
     private WindowManagerProxy() {
     }
 
@@ -188,4 +217,15 @@
         mDimLayerAlpha = alpha;
         mExecutor.execute(mDimLayerRunnable);
     }
+
+    public void swapTasks() {
+        mExecutor.execute(mSwapRunnable);
+    }
+
+    public void setTouchRegion(Rect region) {
+        synchronized (mDockedRect) {
+            mTouchableRegion.set(region);
+        }
+        mExecutor.execute(mSetTouchableRegionRunnable);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
new file mode 100644
index 0000000..5d19851
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.stackdivider.events;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when the divider is being draged either manually or by an animation.
+ */
+public class StartedDragingEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
new file mode 100644
index 0000000..c50d6d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.stackdivider.events;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when the divider isn't draging anymore.
+ */
+public class StoppedDragingEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 315c509..71f74cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -35,7 +35,10 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
  * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -120,6 +123,7 @@
     private float mAnimationTranslationY;
     private boolean mDrawingAppearAnimation;
     private ValueAnimator mAppearAnimator;
+    private ValueAnimator mBackgroundColorAnimator;
     private float mAppearAnimationFraction = -1.0f;
     private float mAppearAnimationTranslation;
     private boolean mShowingLegacyBackground;
@@ -144,7 +148,7 @@
         public void onAnimationEnd(Animator animation) {
             super.onAnimationEnd(animation);
             mFadeInFromDarkAnimator = null;
-            updateOutlineAlpha();
+            updateBackground();
         }
     };
     private ValueAnimator.AnimatorUpdateListener mUpdateOutlineListener
@@ -155,6 +159,10 @@
         }
     };
     private float mShadowAlpha = 1.0f;
+    private FakeShadowView mFakeShadow;
+    private int mCurrentBackgroundTint;
+    private int mTargetTint;
+    private int mStartTint;
 
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -180,6 +188,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
+        mFakeShadow = (FakeShadowView) findViewById(R.id.fake_shadow);
         mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
         mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
         mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
@@ -331,9 +340,7 @@
             animator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    if (mDimmed) {
-                        mBackgroundNormal.setVisibility(View.INVISIBLE);
-                    }
+                    updateBackground();
                 }
             });
             animator.start();
@@ -362,14 +369,14 @@
      */
     public void makeInactive(boolean animate) {
         if (mActivated) {
+            mActivated = false;
             if (mDimmed) {
                 if (animate) {
                     startActivateAnimation(true /* reverse */);
                 } else {
-                    mBackgroundNormal.setVisibility(View.INVISIBLE);
+                    updateBackground();
                 }
             }
-            mActivated = false;
         }
         if (mOnActivatedListener != null) {
             mOnActivatedListener.onActivationReset(this);
@@ -399,20 +406,9 @@
             return;
         }
         mDark = dark;
+        updateBackground();
         if (!dark && fade && !shouldHideBackground()) {
-            if (mActivated) {
-                mBackgroundDimmed.setVisibility(View.VISIBLE);
-                mBackgroundNormal.setVisibility(View.VISIBLE);
-            } else if (mDimmed) {
-                mBackgroundDimmed.setVisibility(View.VISIBLE);
-                mBackgroundNormal.setVisibility(View.INVISIBLE);
-            } else {
-                mBackgroundDimmed.setVisibility(View.INVISIBLE);
-                mBackgroundNormal.setVisibility(View.VISIBLE);
-            }
             fadeInFromDark(delay);
-        } else {
-            updateBackground();
         }
         updateOutlineAlpha();
     }
@@ -454,21 +450,63 @@
      * Sets the tint color of the background
      */
     public void setTintColor(int color) {
+        setTintColor(color, false);
+    }
+
+    /**
+     * Sets the tint color of the background
+     */
+    public void setTintColor(int color, boolean animated) {
         mBgTint = color;
-        updateBackgroundTint();
+        updateBackgroundTint(animated);
     }
 
     protected void updateBackgroundTint() {
-        int color = getBgColor();
+        updateBackgroundTint(false /* animated */);
+    }
+
+    private void updateBackgroundTint(boolean animated) {
+        if (mBackgroundColorAnimator != null) {
+            mBackgroundColorAnimator.cancel();
+        }
         int rippleColor = getRippleColor();
+        mBackgroundDimmed.setRippleColor(rippleColor);
+        mBackgroundNormal.setRippleColor(rippleColor);
+        int color = calculateBgColor();
+        if (!animated) {
+            setBackgroundTintColor(color);
+        } else if (color != mCurrentBackgroundTint) {
+            mStartTint = mCurrentBackgroundTint;
+            mTargetTint = color;
+            mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
+            mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
+                            animation.getAnimatedFraction());
+                    setBackgroundTintColor(newColor);
+                }
+            });
+            mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
+            mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mBackgroundColorAnimator = null;
+                }
+            });
+            mBackgroundColorAnimator.start();
+        }
+    }
+
+    private void setBackgroundTintColor(int color) {
+        mCurrentBackgroundTint = color;
         if (color == mNormalColor) {
             // We don't need to tint a normal notification
             color = 0;
         }
         mBackgroundDimmed.setTint(color);
         mBackgroundNormal.setTint(color);
-        mBackgroundDimmed.setRippleColor(rippleColor);
-        mBackgroundNormal.setRippleColor(rippleColor);
     }
 
     /**
@@ -477,6 +515,7 @@
     private void fadeInFromDark(long delay) {
         final View background = mDimmed ? mBackgroundDimmed : mBackgroundNormal;
         background.setAlpha(0f);
+        mBackgroundVisibilityUpdater.onAnimationUpdate(null);
         background.setPivotX(mBackgroundDimmed.getWidth() / 2f);
         background.setPivotY(getActualHeight() / 2f);
         background.setScaleX(DARK_EXIT_SCALE_START);
@@ -514,6 +553,10 @@
     private void fadeDimmedBackground() {
         mBackgroundDimmed.animate().cancel();
         mBackgroundNormal.animate().cancel();
+        if (mActivated) {
+            updateBackground();
+            return;
+        }
         if (!shouldHideBackground()) {
             if (mDimmed) {
                 mBackgroundDimmed.setVisibility(View.VISIBLE);
@@ -543,11 +586,7 @@
         mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                if (mDimmed) {
-                    mBackgroundNormal.setVisibility(View.INVISIBLE);
-                } else {
-                    mBackgroundDimmed.setVisibility(View.INVISIBLE);
-                }
+                updateBackground();
                 mBackgroundAnimator = null;
             }
         });
@@ -562,12 +601,14 @@
             mBackgroundNormal.setVisibility(View.INVISIBLE);
         } else if (mDimmed) {
             mBackgroundDimmed.setVisibility(View.VISIBLE);
-            mBackgroundNormal.setVisibility(View.INVISIBLE);
+            mBackgroundNormal.setVisibility(mActivated ? View.VISIBLE : View.INVISIBLE);
         } else {
             mBackgroundDimmed.setVisibility(View.INVISIBLE);
             mBackgroundNormal.setVisibility(View.VISIBLE);
             mBackgroundNormal.setAlpha(1f);
             removeCallbacks(mTapTimeoutRunnable);
+            // make in inactive to avoid it sticking around active
+            makeInactive(false /* animate */);
         }
         setNormalBackgroundVisibilityAmount(
                 mBackgroundNormal.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
@@ -770,8 +811,12 @@
 
     protected abstract View getContentView();
 
-    public int getBgColor() {
-        if (mBgTint != 0) {
+    public int calculateBgColor() {
+        return calculateBgColor(true /* withTint */);
+    }
+
+    private int calculateBgColor(boolean withTint) {
+        if (withTint && mBgTint != 0) {
             return mBgTint;
         } else if (mShowingLegacyBackground) {
             return mLegacyColor;
@@ -836,7 +881,7 @@
     }
 
     public boolean hasSameBgColor(ActivatableNotificationView otherView) {
-        return getBgColor() == otherView.getBgColor();
+        return calculateBgColor() == otherView.calculateBgColor();
     }
 
     @Override
@@ -852,6 +897,18 @@
         }
     }
 
+    @Override
+    public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
+            int outlineTranslation) {
+        mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
+                + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
+                outlineTranslation);
+    }
+
+    public int getBackgroundColorWithoutTint() {
+        return calculateBgColor(false /* withTint */);
+    }
+
     public interface OnActivatedListener {
         void onActivated(ActivatableNotificationView view);
         void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
index 700ea34..ef03d5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
@@ -17,18 +17,14 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.widget.ImageView;
 
-import com.android.systemui.R;
-
 /**
  * An ImageView which supports an attribute specifying whether it has overlapping rendering
  * commands and therefore does not need a layer when alpha is changed.
  */
 public class AlphaOptimizedImageView extends ImageView {
-    private final boolean mHasOverlappingRendering;
 
     public AlphaOptimizedImageView(Context context) {
         this(context, null /* attrs */);
@@ -45,21 +41,10 @@
     public AlphaOptimizedImageView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-
-        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
-                R.styleable.AlphaOptimizedImageView, 0, 0);
-
-        try {
-            // Default to true, which is what View.java defaults to
-            mHasOverlappingRendering = a.getBoolean(
-                    R.styleable.AlphaOptimizedImageView_hasOverlappingRendering, true);
-        } finally {
-            a.recycle();
-        }
     }
 
     @Override
     public boolean hasOverlappingRendering() {
-        return mHasOverlappingRendering;
+        return false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 7670223..ae665c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -17,14 +17,19 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
+import android.widget.ImageView;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.systemui.R;
+
 @RemoteView
-public class AnimatedImageView extends AlphaOptimizedImageView {
+public class AnimatedImageView extends ImageView {
+    private final boolean mHasOverlappingRendering;
     AnimationDrawable mAnim;
     boolean mAttached;
 
@@ -34,11 +39,21 @@
     int mDrawableId;
 
     public AnimatedImageView(Context context) {
-        super(context);
+        this(context, null);
     }
 
     public AnimatedImageView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
+                R.styleable.AnimatedImageView, 0, 0);
+
+        try {
+            // Default to true, which is what View.java defaults toA
+            mHasOverlappingRendering = a.getBoolean(
+                    R.styleable.AnimatedImageView_hasOverlappingRendering, true);
+        } finally {
+            a.recycle();
+        }
     }
 
     private void updateAnim() {
@@ -106,5 +121,10 @@
             }
         }
     }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return mHasOverlappingRendering;
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ea8b75e..8102fae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -19,7 +19,10 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -31,6 +34,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -103,20 +107,19 @@
 import com.android.systemui.statusbar.policy.PreviewInflater;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.GearDisplayedListener;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 
 public abstract class BaseStatusBar extends SystemUI implements
         CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
         ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
-        ExpandableNotificationRow.OnExpandClickListener, GearDisplayedListener {
+        ExpandableNotificationRow.OnExpandClickListener {
     public static final String TAG = "StatusBar";
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
@@ -125,6 +128,8 @@
             SystemProperties.getBoolean("debug.enable_remote_input", true);
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
             = SystemProperties.getBoolean("debug.child_notifs", true);
+    public static final boolean FORCE_REMOTE_INPUT_HISTORY =
+            SystemProperties.getBoolean("debug.force_remoteinput_history", false);
 
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -138,6 +143,8 @@
     protected static final boolean ENABLE_HEADS_UP = true;
     protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
+    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
     // Should match the values in PhoneWindowManager
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
@@ -146,6 +153,8 @@
             "com.android.systemui.statusbar.banner_action_cancel";
     private static final String BANNER_ACTION_SETUP =
             "com.android.systemui.statusbar.banner_action_setup";
+    private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
+            = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
 
     protected CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
@@ -176,6 +185,13 @@
     protected boolean mVisible;
     protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
 
+    /**
+     * Notifications with keys in this set are not actually around anymore. We kept them around
+     * when they were canceled in response to a remote input interaction. This allows us to show
+     * what you replied and allows you to continue typing into it.
+     */
+    protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
     // mScreenOnFromKeyguard && mVisible.
     private boolean mVisibleToUser;
 
@@ -194,10 +210,14 @@
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
+    private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
 
     private UserManager mUserManager;
     private int mDensity;
 
+    private KeyguardManager mKeyguardManager;
+    private LockPatternUtils mLockPatternUtils;
+
     // UI-specific methods
 
     /**
@@ -221,7 +241,6 @@
 
     // which notification is currently being longpress-examined by the user
     private NotificationGuts mNotificationGutsExposed;
-    private ExpandableNotificationRow mNotificationGearDisplayed;
 
     private KeyboardShortcuts mKeyboardShortcuts;
 
@@ -328,7 +347,7 @@
                 }, afterKeyguardGone);
                 return true;
             } else {
-                return super.onClickHandler(view, pendingIntent, fillInIntent);
+                return superOnClickHandler(view, pendingIntent, fillInIntent);
             }
         }
 
@@ -365,7 +384,8 @@
 
         private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
-            return super.onClickHandler(view, pendingIntent, fillInIntent);
+            return super.onClickHandler(view, pendingIntent, fillInIntent,
+                    StackId.FULLSCREEN_WORKSPACE_STACK_ID);
         }
 
         private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -498,6 +518,20 @@
 
                     );
                 }
+            } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
+                final IntentSender intentSender = (IntentSender) intent
+                        .getParcelableExtra(Intent.EXTRA_INTENT);
+                final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+                try {
+                    mContext.startIntentSender(intentSender, null, 0, 0, 0);
+                } catch (IntentSender.SendIntentException e) {
+                    /* ignore */
+                }
+                try {
+                    mBarService.onNotificationClick(notificationKey);
+                } catch (RemoteException e) {
+                    /* ignore */
+                }
             }
         }
     };
@@ -542,6 +576,7 @@
                     public void run() {
                         processForRemoteInput(sbn.getNotification());
                         String key = sbn.getKey();
+                        mKeysKeptForRemoteInput.remove(key);
                         boolean isUpdate = mNotificationData.get(key) != null;
                         // In case we don't allow child notifications, we ignore children of
                         // notifications that have a summary, since we're not going to show them
@@ -660,6 +695,8 @@
         mDensity = currentConfig.densityDpi;
 
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mLockPatternUtils = new LockPatternUtils(mContext);
 
         // Connect in to the status bar manager service
         mCommandQueue = new CommandQueue(this);
@@ -722,10 +759,14 @@
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_PRESENT);
-        filter.addAction(BANNER_ACTION_CANCEL);
-        filter.addAction(BANNER_ACTION_SETUP);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
+        IntentFilter internalFilter = new IntentFilter();
+        internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+        internalFilter.addAction(BANNER_ACTION_CANCEL);
+        internalFilter.addAction(BANNER_ACTION_SETUP);
+        mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
+
         IntentFilter allUsersFilter = new IntentFilter();
         allUsersFilter.addAction(
                 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -738,8 +779,7 @@
         if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
             Log.d(TAG, "user hasn't seen notification about hidden notifications");
-            final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
-            if (!lockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+            if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
                 Log.d(TAG, "insecure lockscreen, skipping notification");
                 Settings.Secure.putInt(mContext.getContentResolver(),
                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -875,7 +915,7 @@
         }
     }
 
-    protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
+    protected View bindVetoButtonClickListener(View row, final StatusBarNotification n) {
         View vetoButton = row.findViewById(R.id.veto);
         final String _pkg = n.getPackageName();
         final String _tag = n.getTag();
@@ -888,6 +928,11 @@
                         mContext.getString(R.string.accessibility_notification_dismissed));
                 try {
                     mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
+                    if (FORCE_REMOTE_INPUT_HISTORY
+                            && mKeysKeptForRemoteInput.contains(n.getKey())) {
+                        removeNotification(n.getKey(), null);
+                        mKeysKeptForRemoteInput.remove(n.getKey());
+                    }
 
                 } catch (RemoteException ex) {
                     // system process is dead if we're here.
@@ -946,7 +991,7 @@
                             }
                             TaskStackBuilder.create(mContext)
                                     .addNextIntentWithParentStack(intent)
-                                    .startActivities(null,
+                                    .startActivities(getActivityOptions(),
                                             new UserHandle(UserHandle.getUserId(appUid)));
                             overrideActivityPendingAppTransition(keyguardShowing);
                         } catch (RemoteException e) {
@@ -959,7 +1004,7 @@
         }, false /* afterKeyguardGone */);
     }
 
-    private void bindGuts(ExpandableNotificationRow row) {
+    private void bindGuts(final ExpandableNotificationRow row) {
         row.inflateGuts();
         final StatusBarNotification sbn = row.getStatusBarNotification();
         PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
@@ -983,7 +1028,7 @@
             pkgicon = pmUser.getDefaultActivityIcon();
         }
 
-        ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
+        ((ImageView) row.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
         ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
 
         final View settingsButton = guts.findViewById(R.id.more_settings);
@@ -1003,15 +1048,21 @@
             @Override
             public void onClick(View v) {
                 guts.saveImportance(sbn);
-                dismissPopups();
+
+                int[] rowLocation = new int[2];
+                int[] doneLocation = new int[2];
+                row.getLocationOnScreen(rowLocation);
+                v.getLocationOnScreen(doneLocation);
+
+                final int centerX = v.getWidth() / 2;
+                final int centerY = v.getHeight() / 2;
+                final int x = doneLocation[0] - rowLocation[0] + centerX;
+                final int y = doneLocation[1] - rowLocation[1] + centerY;
+                dismissPopups(x, y);
             }
         });
 
-        guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
-    }
-
-    protected GearDisplayedListener getGearDisplayedListener() {
-        return this;
+        guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
     }
 
     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
@@ -1044,12 +1095,13 @@
 
                 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
 
-                // ensure that it's layouted but not visible until actually laid out
+                // ensure that it's laid but not visible until actually laid out
                 guts.setVisibility(View.INVISIBLE);
-                // Post to ensure the the guts are properly layed out.
+                // Post to ensure the the guts are properly laid out.
                 guts.post(new Runnable() {
                     public void run() {
-                        dismissPopups();
+                        dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
+                                false /* animate */);
                         guts.setVisibility(View.VISIBLE);
                         final double horz = Math.max(guts.getWidth() - x, x);
                         final double vert = Math.max(guts.getHeight() - y, y);
@@ -1068,6 +1120,7 @@
                         });
                         a.start();
                         guts.setExposed(true);
+                        row.closeRemoteInput();
                         mStackScroller.onHeightChanged(null, true /* needsAnimation */);
                         mNotificationGutsExposed = guts;
                     }
@@ -1077,16 +1130,22 @@
         };
     }
 
-    @Override
-    public void onGearDisplayed(ExpandableNotificationRow row) {
-        mNotificationGearDisplayed = row;
+    /**
+     * Returns the exposed NotificationGuts or null if none are exposed.
+     */
+    public NotificationGuts getExposedGuts() {
+        return mNotificationGutsExposed;
     }
 
     public void dismissPopups() {
-        dismissPopups(-1, -1);
+        dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */);
     }
 
     private void dismissPopups(int x, int y) {
+        dismissPopups(x, y, true /* resetGear */, false /* animate */);
+    }
+
+    public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
         if (mNotificationGutsExposed != null) {
             final NotificationGuts v = mNotificationGutsExposed;
             mNotificationGutsExposed = null;
@@ -1114,10 +1173,8 @@
             v.setExposed(false);
             mStackScroller.onHeightChanged(null, true /* needsAnimation */);
         }
-
-        if (mNotificationGearDisplayed != null) {
-            mNotificationGearDisplayed.resetTranslation();
-            mNotificationGearDisplayed = null;
+        if (resetGear) {
+            mStackScroller.resetExposedGearView(animate, true /* force */);
         }
     }
 
@@ -1142,6 +1199,11 @@
     }
 
     @Override
+    public void toggleSplitScreen() {
+        toggleSplitScreenMode();
+    }
+
+    @Override
     public void preloadRecentApps() {
         int msg = MSG_PRELOAD_RECENT_APPS;
         mHandler.removeMessages(msg);
@@ -1156,10 +1218,10 @@
     }
 
     @Override
-    public void toggleKeyboardShortcutsMenu() {
+    public void toggleKeyboardShortcutsMenu(int deviceId) {
         int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
         mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
+        mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
     }
 
     /** Jumps to the next affiliated task in the group. */
@@ -1211,6 +1273,13 @@
         }
     };
 
+    /**
+     * Toggle docking the app window
+     *
+     * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise.
+     */
+    protected abstract boolean toggleSplitScreenMode();
+
     /** Proxy for RecentsComponent */
 
     protected void showRecents(boolean triggeredFromAltTab) {
@@ -1238,8 +1307,8 @@
         }
     }
 
-    protected void toggleKeyboardShortcuts() {
-        getKeyboardShortcuts().toggleKeyboardShortcuts();
+    protected void toggleKeyboardShortcuts(int deviceId) {
+        getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
     }
 
     protected void cancelPreloadingRecents() {
@@ -1277,6 +1346,26 @@
     }
 
     /**
+     * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+     * "public" (secure & locked) mode?
+     */
+    public boolean userAllowsNotificationsInPublic(int userHandle) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+
+        if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
+            final boolean allowed = 0 != Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+            mUsersAllowingNotifications.append(userHandle, allowed);
+            return allowed;
+        }
+
+        return mUsersAllowingNotifications.get(userHandle);
+    }
+
+    /**
      * Has the given user chosen to allow their private (full) notifications to be shown even
      * when the lockscreen is in "public" (secure & locked) mode?
      */
@@ -1308,13 +1397,30 @@
     }
 
     /**
-     * Returns true if we're on a secure lockscreen and the user wants to hide "sensitive"
-     * notification data. If so, private notifications should show their (possibly
-     * auto-generated) publicVersion, and secret notifications should be totally invisible.
+     * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
+     * If so, notifications should be hidden.
      */
     @Override  // NotificationData.Environment
-    public boolean shouldHideSensitiveContents(int userid) {
-        return isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(userid);
+    public boolean shouldHideNotifications(int userid) {
+        return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
+    }
+
+    /**
+     * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
+     * package-specific override.
+     */
+    @Override // NotificationDate.Environment
+    public boolean shouldHideNotifications(String key) {
+        return isLockscreenPublicMode()
+                && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
+    }
+
+    /**
+     * Returns true if we're on a secure lockscreen.
+     */
+    @Override  // NotificationData.Environment
+    public boolean onSecureLockScreen() {
+        return isLockscreenPublicMode();
     }
 
     public void onNotificationClear(StatusBarNotification notification) {
@@ -1375,7 +1481,7 @@
                   showRecentsPreviousAffiliatedTask();
                   break;
              case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
-                  toggleKeyboardShortcuts();
+                  toggleKeyboardShortcuts(m.arg1);
                   break;
             }
         }
@@ -1433,6 +1539,21 @@
             row.setHeadsUpManager(mHeadsUpManager);
             row.setRemoteInputController(mRemoteInputController);
             row.setOnExpandClickListener(this);
+
+            // Get the app name
+            final String pkg = sbn.getPackageName();
+            String appname = pkg;
+            try {
+                final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+                        PackageManager.GET_UNINSTALLED_PACKAGES
+                                | PackageManager.GET_DISABLED_COMPONENTS);
+                if (info != null) {
+                    appname = String.valueOf(pmUser.getApplicationLabel(info));
+                }
+            } catch (NameNotFoundException e) {
+                // Do nothing
+            }
+            row.setAppName(appname);
         }
 
         workAroundBadLayerDrawableOpacity(row);
@@ -1615,9 +1736,8 @@
                             ActivityManagerNative.getDefault().resumeAppSwitches();
                         } catch (RemoteException e) {
                         }
-
                         try {
-                            intent.send();
+                            intent.send(null, 0, null, null, null, null, getActivityOptions());
                         } catch (PendingIntent.CanceledException e) {
                             // the stack trace isn't very helpful here.
                             // Just log the exception message.
@@ -1708,10 +1828,26 @@
                                 ActivityManagerNative.getDefault().resumeAppSwitches();
                             } catch (RemoteException e) {
                             }
-
                             if (intent != null) {
+                                // If we are launching a work activity and require to launch
+                                // separate work challenge, we defer the activity action and cancel
+                                // notification until work challenge is unlocked.
+                                if (intent.isActivity()) {
+                                    final int userId = intent.getCreatorUserHandle()
+                                            .getIdentifier();
+                                    if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+                                            && mKeyguardManager.isDeviceLocked(userId)) {
+                                        if (startWorkChallengeIfNecessary(userId,
+                                                intent.getIntentSender(), notificationKey)) {
+                                            // Show work challenge, do not run pendingintent and
+                                            // remove notification
+                                            return;
+                                        }
+                                    }
+                                }
                                 try {
-                                    intent.send();
+                                    intent.send(null, 0, null, null, null, null,
+                                            getActivityOptions());
                                 } catch (PendingIntent.CanceledException e) {
                                     // the stack trace isn't very helpful here.
                                     // Just log the exception message.
@@ -1744,6 +1880,27 @@
             }, afterKeyguardGone);
         }
 
+        public boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
+                String notificationKey) {
+            final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
+                    null, userId);
+            if (newIntent == null) {
+                return false;
+            }
+            final Intent callBackIntent = new Intent(
+                    WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+            callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
+            callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
+            callBackIntent.setPackage(mContext.getPackageName());
+
+            newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
+                    .getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
+            mContext.startActivity(newIntent);
+            return true;
+        }
+
         public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
             Notification notification = sbn.getNotification();
             if (notification.contentIntent != null || notification.fullScreenIntent != null) {
@@ -1770,6 +1927,14 @@
         }
     }
 
+    protected Bundle getActivityOptions() {
+        // Anything launched from the notification shade should always go into the
+        // fullscreen stack.
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+        return options.toBundle();
+    }
+
     protected void visibilityChanged(boolean visible) {
         if (mVisible != visible) {
             mVisible = visible;
@@ -1791,15 +1956,16 @@
 
     /**
      * The LEDs are turned off when the notification panel is shown, even just a little bit.
+     * See also NotificationStackScrollLayout.setIsExpanded() for another place where we
+     * attempt to do this.
      */
     protected void handleVisibleToUserChanged(boolean visibleToUser) {
         try {
             if (visibleToUser) {
                 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
                 boolean clearNotificationEffects =
-                    ((mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD) ||
-                            (!pinnedHeadsUp && (mState == StatusBarState.SHADE
-                                    || mState == StatusBarState.SHADE_LOCKED)));
+                        !isPanelFullyCollapsed() &&
+                        (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
                 int notificationLoad = mNotificationData.getActiveNotifications().size();
                 if (pinnedHeadsUp && isPanelFullyCollapsed())  {
                     notificationLoad = 1;
@@ -1826,7 +1992,7 @@
         }
     }
 
-    protected abstract boolean isPanelFullyCollapsed();
+    public abstract boolean isPanelFullyCollapsed();
 
     /**
      * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
@@ -1872,7 +2038,7 @@
         return entry;
     }
 
-    protected StatusBarIconView createIcon(StatusBarNotification sbn) {
+    public StatusBarIconView createIcon(StatusBarNotification sbn) {
         // Construct the icon.
         Notification n = sbn.getNotification();
         final StatusBarIconView iconView = new StatusBarIconView(mContext,
@@ -1931,24 +2097,24 @@
         }
         for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = activeNotifications.get(i);
+            boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
             if (onKeyguard) {
                 entry.row.setOnKeyguard(true);
             } else {
                 entry.row.setOnKeyguard(false);
-                boolean top = (i == 0);
-                entry.row.setSystemExpanded(top);
+                entry.row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
             }
-            boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
+            boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(entry.notification);
             boolean childWithVisibleSummary = childNotification
                     && mGroupManager.getGroupSummary(entry.notification).getVisibility()
                     == View.VISIBLE;
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
-            if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
+            if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
                     (onKeyguard && (visibleNotifications >= maxNotifications
                             && !childWithVisibleSummary
                             || !showOnKeyguard))) {
                 entry.row.setVisibility(View.GONE);
-                if (onKeyguard && showOnKeyguard && !childNotification) {
+                if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
                     mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
                 }
             } else {
@@ -1957,7 +2123,8 @@
                 if (!childNotification) {
                     if (wasGone) {
                         // notify the scroller of a child addition
-                        mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
+                        mStackScroller.generateAddAnimation(entry.row,
+                                !showOnKeyguard /* fromMoreCard */);
                     }
                     visibleNotifications++;
                 }
@@ -2095,6 +2262,12 @@
         // swipe-dismissable)
         bindVetoButtonClickListener(entry.row, notification);
 
+        if (!notification.isClearable()) {
+            // The user may have performed a dismiss action on the notification, since it's
+            // not clearable we should snap it back.
+            mStackScroller.snapViewIfNeeded(entry.row);
+        }
+
         if (DEBUG) {
             // Is this for you?
             boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
@@ -2139,15 +2312,21 @@
     protected void updatePublicContentView(Entry entry,
             StatusBarNotification sbn) {
         final RemoteViews publicContentView = entry.cachedPublicContentView;
-        if (publicContentView != null && entry.getPublicContentView() != null) {
+        View inflatedView = entry.getPublicContentView();
+        if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
             final boolean disabledByPolicy =
                     !adminAllowsUnredactedNotifications(entry.notification.getUserId());
-            publicContentView.setTextViewText(android.R.id.title,
-                    mContext.getString(disabledByPolicy
-                            ? com.android.internal.R.string.notification_hidden_by_policy_text
-                            : com.android.internal.R.string.notification_hidden_text));
-            publicContentView.reapply(sbn.getPackageContext(mContext),
-                    entry.getPublicContentView(), mOnClickHandler);
+            String notificationHiddenText = mContext.getString(disabledByPolicy
+                    ? com.android.internal.R.string.notification_hidden_by_policy_text
+                    : com.android.internal.R.string.notification_hidden_text);
+            TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
+            if (titleView != null
+                    && !titleView.getText().toString().equals(notificationHiddenText)) {
+                publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
+                publicContentView.reapply(sbn.getPackageContext(mContext),
+                        inflatedView, mOnClickHandler);
+                entry.row.onNotificationUpdated(entry);
+            }
         }
     }
 
@@ -2197,6 +2376,16 @@
             return false;
         }
 
+        if (isSnoozedPackage(sbn)) {
+            if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
+            return false;
+        }
+
+        if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
+            if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
+            return false;
+        }
+
         if (sbn.getNotification().fullScreenIntent != null) {
             if (mAccessibilityManager.isTouchExplorationEnabled()) {
                 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
@@ -2206,16 +2395,6 @@
             }
         }
 
-        if (isSnoozedPackage(sbn)) {
-            if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
-            return false;
-        }
-
-        if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_MAX) {
-            if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
-            return false;
-        }
-
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 3b960ee..99b6397 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -72,6 +72,8 @@
     private static final int MSG_ADD_QS_TILE                   = 27 << MSG_SHIFT;
     private static final int MSG_REMOVE_QS_TILE                = 28 << MSG_SHIFT;
     private static final int MSG_CLICK_QS_TILE                 = 29 << MSG_SHIFT;
+    private static final int MSG_TOGGLE_APP_SPLIT_SCREEN       = 30 << MSG_SHIFT;
+    private static final int MSG_APP_TRANSITION_FINISHED       = 31 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -90,35 +92,37 @@
      * These methods are called back on the main thread.
      */
     public interface Callbacks {
-        public void setIcon(String slot, StatusBarIcon icon);
-        public void removeIcon(String slot);
-        public void disable(int state1, int state2, boolean animate);
-        public void animateExpandNotificationsPanel();
-        public void animateCollapsePanels(int flags);
-        public void animateExpandSettingsPanel(String obj);
-        public void setSystemUiVisibility(int vis, int fullscreenStackVis,
+        void setIcon(String slot, StatusBarIcon icon);
+        void removeIcon(String slot);
+        void disable(int state1, int state2, boolean animate);
+        void animateExpandNotificationsPanel();
+        void animateCollapsePanels(int flags);
+        void animateExpandSettingsPanel(String obj);
+        void setSystemUiVisibility(int vis, int fullscreenStackVis,
                 int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds);
-        public void topAppWindowChanged(boolean visible);
-        public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+        void topAppWindowChanged(boolean visible);
+        void setImeWindowStatus(IBinder token, int vis, int backDisposition,
                 boolean showImeSwitcher);
-        public void showRecentApps(boolean triggeredFromAltTab);
-        public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
-        public void toggleRecentApps();
-        public void preloadRecentApps();
-        public void toggleKeyboardShortcutsMenu();
-        public void cancelPreloadRecentApps();
-        public void setWindowState(int window, int state);
-        public void buzzBeepBlinked();
-        public void notificationLightOff();
-        public void notificationLightPulse(int argb, int onMillis, int offMillis);
-        public void showScreenPinningRequest();
-        public void appTransitionPending();
-        public void appTransitionCancelled();
-        public void appTransitionStarting(long startTime, long duration);
-        public void showAssistDisclosure();
-        public void startAssist(Bundle args);
-        public void onCameraLaunchGestureDetected(int source);
-        public void requestTvPictureInPicture();
+        void showRecentApps(boolean triggeredFromAltTab);
+        void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+        void toggleRecentApps();
+        void toggleSplitScreen();
+        void preloadRecentApps();
+        void toggleKeyboardShortcutsMenu(int deviceId);
+        void cancelPreloadRecentApps();
+        void setWindowState(int window, int state);
+        void buzzBeepBlinked();
+        void notificationLightOff();
+        void notificationLightPulse(int argb, int onMillis, int offMillis);
+        void showScreenPinningRequest();
+        void appTransitionPending();
+        void appTransitionCancelled();
+        void appTransitionStarting(long startTime, long duration);
+        void appTransitionFinished();
+        void showAssistDisclosure();
+        void startAssist(Bundle args);
+        void onCameraLaunchGestureDetected(int source);
+        void requestTvPictureInPicture();
 
         void addQsTile(ComponentName tile);
         void remQsTile(ComponentName tile);
@@ -223,6 +227,13 @@
         }
     }
 
+    public void toggleSplitScreen() {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_TOGGLE_APP_SPLIT_SCREEN);
+            mHandler.obtainMessage(MSG_TOGGLE_APP_SPLIT_SCREEN, 0, 0, null).sendToTarget();
+        }
+    }
+
     public void toggleRecentApps() {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
@@ -245,10 +256,10 @@
     }
 
     @Override
-    public void toggleKeyboardShortcutsMenu() {
+    public void toggleKeyboardShortcutsMenu(int deviceId) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS);
-            mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS).sendToTarget();
+            mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS, deviceId, 0).sendToTarget();
         }
     }
 
@@ -315,6 +326,14 @@
         }
     }
 
+    @Override
+    public void appTransitionFinished() {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_APP_TRANSITION_FINISHED);
+            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
+        }
+    }
+
     public void showAssistDisclosure() {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_ASSIST_DISCLOSURE);
@@ -416,7 +435,7 @@
                     mCallbacks.cancelPreloadRecentApps();
                     break;
                 case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
-                    mCallbacks.toggleKeyboardShortcutsMenu();
+                    mCallbacks.toggleKeyboardShortcutsMenu(msg.arg1);
                     break;
                 case MSG_SET_WINDOW_STATE:
                     mCallbacks.setWindowState(msg.arg1, msg.arg2);
@@ -443,6 +462,9 @@
                     Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
                     mCallbacks.appTransitionStarting(data.first, data.second);
                     break;
+                case MSG_APP_TRANSITION_FINISHED:
+                    mCallbacks.appTransitionFinished();
+                    break;
                 case MSG_ASSIST_DISCLOSURE:
                     mCallbacks.showAssistDisclosure();
                     break;
@@ -464,6 +486,9 @@
                 case MSG_CLICK_QS_TILE:
                     mCallbacks.clickTile((ComponentName) msg.obj);
                     break;
+                case MSG_TOGGLE_APP_SPLIT_SCREEN:
+                    mCallbacks.toggleSplitScreen();
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 212d290..123dc69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -19,6 +19,7 @@
 import android.view.View;
 
 import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
  * A helper to fade views in and out.
@@ -44,7 +45,34 @@
         if (view.hasOverlappingRendering()) {
             view.animate().withLayer();
         }
+    }
 
+    public static void fadeOut(View view, float fadeOutAmount) {
+        view.animate().cancel();
+        if (fadeOutAmount == 1.0f) {
+            view.setVisibility(View.INVISIBLE);
+        } else if (view.getVisibility() == View.INVISIBLE) {
+            view.setVisibility(View.VISIBLE);
+        }
+        fadeOutAmount = mapToFadeDuration(fadeOutAmount);
+        float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
+        view.setAlpha(alpha);
+        updateLayerType(view, alpha);
+    }
+
+    private static float mapToFadeDuration(float fadeOutAmount) {
+        // Assuming a linear interpolator, we can easily map it to our new duration
+        float endPoint = (float) ANIMATION_DURATION_LENGTH
+                / (float) StackStateAnimator.ANIMATION_DURATION_STANDARD;
+        return Math.min(fadeOutAmount / endPoint, 1.0f);
+    }
+
+    private static void updateLayerType(View view, float alpha) {
+        if (view.hasOverlappingRendering() && alpha > 0.0f && alpha < 1.0f) {
+            view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE) {
+            view.setLayerType(View.LAYER_TYPE_NONE, null);
+        }
     }
 
     public static void fadeIn(final View view) {
@@ -62,4 +90,15 @@
             view.animate().withLayer();
         }
     }
+
+    public static void fadeIn(View view, float fadeInAmount) {
+        view.animate().cancel();
+        if (view.getVisibility() == View.INVISIBLE) {
+            view.setVisibility(View.VISIBLE);
+        }
+        fadeInAmount = mapToFadeDuration(fadeInAmount);
+        float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
+        view.setAlpha(alpha);
+        updateLayerType(view, alpha);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index b326552..2dabf5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -169,21 +169,23 @@
                 ? RUBBERBAND_FACTOR_EXPANDABLE
                 : RUBBERBAND_FACTOR_STATIC;
         float rubberband = heightDelta * rubberbandFactor;
-        if (expandable && (rubberband + child.getMinHeight()) > child.getMaxContentHeight()) {
-            float overshoot = (rubberband + child.getMinHeight()) - child.getMaxContentHeight();
+        if (expandable
+                && (rubberband + child.getCollapsedHeight()) > child.getMaxContentHeight()) {
+            float overshoot =
+                    (rubberband + child.getCollapsedHeight()) - child.getMaxContentHeight();
             overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
             rubberband -= overshoot;
         }
-        child.setActualHeight((int) (child.getMinHeight() + rubberband));
+        child.setActualHeight((int) (child.getCollapsedHeight() + rubberband));
     }
 
     private void cancelExpansion(final ExpandableView child) {
-        if (child.getActualHeight() == child.getMinHeight()) {
+        if (child.getActualHeight() == child.getCollapsedHeight()) {
             mCallback.setUserLockedChild(child, false);
             return;
         }
         ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
-                child.getActualHeight(), child.getMinHeight());
+                child.getActualHeight(), child.getCollapsedHeight());
         anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
         anim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index c73e115..7ca7d12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -43,6 +43,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.notification.HybridNotificationView;
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -80,6 +81,7 @@
     /** Are we showing the "public" version */
     private boolean mShowingPublic;
     private boolean mSensitive;
+    private boolean mSensitiveHiddenInGeneral;
     private boolean mShowingPublicInitialized;
     private boolean mHideSensitiveForIntrinsicHeight;
 
@@ -104,11 +106,11 @@
     private boolean mClearable;
     private ExpansionLogger mLogger;
     private String mLoggingKey;
-    private boolean mWasReset;
     private NotificationSettingsIconRow mSettingsIconRow;
     private NotificationGuts mGuts;
     private NotificationData.Entry mEntry;
     private StatusBarNotification mStatusBarNotification;
+    private String mAppName;
     private boolean mIsHeadsUp;
     private boolean mLastChronometerRunning = true;
     private NotificationHeaderView mNotificationHeader;
@@ -227,6 +229,7 @@
         updateClearability();
         if (mIsSummaryWithChildren) {
             recreateNotificationHeader();
+            mChildrenContainer.onNotificationUpdated();
         }
         if (mIconAnimationRunning) {
             setIconAnimationRunning(true);
@@ -241,18 +244,22 @@
     }
 
     private void updateLimits() {
-        boolean customView = getPrivateLayout().getContractedChild().getId()
+        updateLimitsForView(mPrivateLayout);
+        updateLimitsForView(mPublicLayout);
+    }
+
+    private void updateLimitsForView(NotificationContentView layout) {
+        boolean customView = layout.getContractedChild().getId()
                 != com.android.internal.R.id.status_bar_latest_event_content;
         boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
         int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
                 mNotificationMinHeightLegacy : mNotificationMinHeight;
-        boolean headsUpCustom = getPrivateLayout().getHeadsUpChild() != null &&
-                getPrivateLayout().getHeadsUpChild().getId()
-                != com.android.internal.R.id.status_bar_latest_event_content;
+        boolean headsUpCustom = layout.getHeadsUpChild() != null &&
+                layout.getHeadsUpChild().getId()
+                        != com.android.internal.R.id.status_bar_latest_event_content;
         int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
                 : mMaxHeadsUpHeight;
-        mPrivateLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
-        mPublicLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
+        layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -281,6 +288,13 @@
         mPrivateLayout.setRemoteInputController(r);
     }
 
+    public void setAppName(String appName) {
+        mAppName = appName;
+        if (mSettingsIconRow != null) {
+            mSettingsIconRow.setAppName(mAppName);
+        }
+    }
+
     public void addChildNotification(ExpandableNotificationRow row) {
         addChildNotification(row, -1);
     }
@@ -456,7 +470,7 @@
         if(mExpandedWhenPinned) {
             return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
         } else if (atLeastMinHeight) {
-            return Math.max(getMinHeight(), mHeadsUpHeight);
+            return Math.max(getCollapsedHeight(), mHeadsUpHeight);
         } else {
             return mHeadsUpHeight;
         }
@@ -560,6 +574,7 @@
             mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
                     R.layout.notification_settings_icon_row, this, false);
             mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
+            mSettingsIconRow.setAppName(mAppName);
             mSettingsIconRow.setVisibility(oldSettings.getVisibility());
             addView(mSettingsIconRow, settingsIndex);
 
@@ -568,6 +583,41 @@
         mPublicLayout.reInflateViews();
     }
 
+    public void setContentBackground(int customBackgroundColor, boolean animate,
+            NotificationContentView notificationContentView) {
+        if (getShowingLayout() == notificationContentView) {
+            setTintColor(customBackgroundColor, animate);
+        }
+    }
+
+    public void closeRemoteInput() {
+        mPrivateLayout.closeRemoteInput();
+        mPublicLayout.closeRemoteInput();
+    }
+
+    /**
+     * Set by how much the single line view should be indented.
+     */
+    public void setSingleLineWidthIndention(int indention) {
+        mPrivateLayout.setSingleLineWidthIndention(indention);
+    }
+
+    public int getNotificationColor() {
+        int color = getStatusBarNotification().getNotification().color;
+        if (color == Notification.COLOR_DEFAULT) {
+            return mContext.getColor(com.android.internal.R.color.notification_icon_default_color);
+        }
+        return color;
+    }
+
+    public HybridNotificationView getSingleLineView() {
+        return mPrivateLayout.getSingleLineView();
+    }
+
+    public boolean isOnKeyguard() {
+        return mOnKeyguard;
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -613,20 +663,16 @@
         mShowingPublicInitialized = false;
         mIsSystemExpanded = false;
         mOnKeyguard = false;
-        mPublicLayout.reset(mIsHeadsUp);
-        mPrivateLayout.reset(mIsHeadsUp);
+        mPublicLayout.reset();
+        mPrivateLayout.reset();
         resetHeight();
         resetTranslation();
         logExpansionEvent(false, wasExpanded);
     }
 
     public void resetHeight() {
-        if (mIsHeadsUp) {
-            resetActualHeight();
-        }
         mMaxExpandHeight = 0;
         mHeadsUpHeight = 0;
-        mWasReset = true;
         onHeightReset();
         requestLayout();
     }
@@ -646,6 +692,7 @@
             public void onInflate(ViewStub stub, View inflated) {
                 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
                 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
+                mSettingsIconRow.setAppName(mAppName);
             }
         });
         mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
@@ -655,7 +702,6 @@
                 mGuts = (NotificationGuts) inflated;
                 mGuts.setClipTopAmount(getClipTopAmount());
                 mGuts.setActualHeight(getActualHeight());
-                mTranslateableViews.add(mGuts);
                 mGutsStub = null;
             }
         });
@@ -666,6 +712,7 @@
             public void onInflate(ViewStub stub, View inflated) {
                 mChildrenContainer = (NotificationChildrenContainer) inflated;
                 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
+                mChildrenContainer.onNotificationUpdated();
                 mTranslateableViews.add(mChildrenContainer);
             }
         });
@@ -683,7 +730,7 @@
         mTranslateableViews.remove(mGutsStub);
     }
 
-    public void setTranslationForOutline(float translationX) {
+    private void setTranslationForOutline(float translationX) {
         setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
     }
 
@@ -703,6 +750,49 @@
         if (mTranslateAnim != null) {
             mTranslateAnim.cancel();
         }
+        mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget,
+                null /* updateListener */);
+        if (mTranslateAnim != null) {
+            mTranslateAnim.start();
+        }
+    }
+
+    @Override
+    public void setTranslation(float translationX) {
+        if (areGutsExposed()) {
+            // Don't translate if guts are showing.
+            return;
+        }
+        // Translate the group of views
+        for (int i = 0; i < mTranslateableViews.size(); i++) {
+            if (mTranslateableViews.get(i) != null) {
+                mTranslateableViews.get(i).setTranslationX(translationX);
+            }
+        }
+        setTranslationForOutline(translationX);
+        if (mSettingsIconRow != null) {
+            mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
+        }
+    }
+
+    @Override
+    public float getTranslation() {
+        if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
+            // All of the views in the list should have same translation, just use first one.
+            return mTranslateableViews.get(0).getTranslationX();
+        }
+        return 0;
+    }
+
+    public Animator getTranslateViewAnimator(final float leftTarget,
+            AnimatorUpdateListener listener) {
+        if (mTranslateAnim != null) {
+            mTranslateAnim.cancel();
+        }
+        if (areGutsExposed()) {
+            // No translation if guts are exposed.
+            return null;
+        }
         AnimatorSet set = new AnimatorSet();
         if (mTranslateableViews != null) {
             for (int i = 0; i < mTranslateableViews.size(); i++) {
@@ -714,23 +804,37 @@
                         @Override
                         public void onAnimationUpdate(ValueAnimator animation) {
                             setTranslationForOutline((float) animation.getAnimatedValue());
+                            if (mSettingsIconRow != null) {
+                                mSettingsIconRow.updateSettingsIcons(
+                                        (float) animation.getAnimatedValue(), getMeasuredWidth());
+                            }
+                        }
+                    });
+                    if (listener != null) {
+                        translateAnim.addUpdateListener(listener);
+                    }
+                    translateAnim.addListener(new AnimatorListenerAdapter() {
+                        boolean cancelled = false;
+
+                        @Override
+                        public void onAnimationCancel(Animator anim) {
+                            cancelled = true;
+                        }
+
+                        @Override
+                        public void onAnimationEnd(Animator anim) {
+                            if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
+                                mSettingsIconRow.resetState();
+                                mTranslateAnim = null;
+                            }
                         }
                     });
                 }
-                translateAnim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator anim) {
-                        if (mSettingsIconRow != null && leftTarget == 0) {
-                            mSettingsIconRow.resetState();
-                        }
-                        mTranslateAnim = null;
-                    }
-                });
                 set.play(translateAnim);
             }
         }
         mTranslateAnim = set;
-        set.start();
+        return set;
     }
 
     public float getSpaceForGear() {
@@ -747,10 +851,6 @@
         return mSettingsIconRow;
     }
 
-    public ArrayList<View> getContentViews() {
-        return mTranslateableViews;
-    }
-
     public void inflateGuts() {
         if (mGuts == null) {
             mGutsStub.inflate();
@@ -867,6 +967,10 @@
 
     public void setUserLocked(boolean userLocked) {
         mUserLocked = userLocked;
+        mPrivateLayout.setUserExpanding(userLocked);
+        if (mIsSummaryWithChildren) {
+            mChildrenContainer.setUserLocked(userLocked);
+        }
     }
 
     /**
@@ -917,18 +1021,6 @@
         return mStatusBarNotification != null && mStatusBarNotification.isClearable();
     }
 
-    /**
-     * Apply an expansion state to the layout.
-     */
-    public void applyExpansionToLayout() {
-        boolean expand = isExpanded();
-        if (expand && mExpandable) {
-            setActualHeight(mMaxExpandHeight);
-        } else {
-            setActualHeight(getMinHeight());
-        }
-    }
-
     @Override
     public int getIntrinsicHeight() {
         if (isUserLocked()) {
@@ -948,12 +1040,12 @@
             } else if (isExpanded()) {
                 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
             } else {
-                return Math.max(getMinHeight(), mHeadsUpHeight);
+                return Math.max(getCollapsedHeight(), mHeadsUpHeight);
             }
         } else if (isExpanded()) {
             return getMaxExpandHeight();
         } else {
-            return getMinHeight();
+            return getCollapsedHeight();
         }
     }
 
@@ -970,18 +1062,14 @@
 
     private void onChildrenCountChanged() {
         mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
-                && mGroupManager.hasGroupChildren(mStatusBarNotification);
+                && mChildrenContainer != null && mChildrenContainer.getChildCount() > 0;
         if (mIsSummaryWithChildren) {
-            if (mChildrenContainer == null) {
-                mChildrenContainerStub.inflate();
-            }
             if (mNotificationHeader == null) {
                 recreateNotificationHeader();
             }
         }
         mPrivateLayout.updateExpandButtons(isExpandable());
         updateChildrenHeaderAppearance();
-        updateHeaderChildCount();
         updateChildrenVisibility();
     }
 
@@ -994,7 +1082,11 @@
      * @return whether the view state is currently expanded.
      */
     public boolean isExpanded() {
-        return !mOnKeyguard
+        return isExpanded(false /* allowOnKeyguard */);
+    }
+
+    public boolean isExpanded(boolean allowOnKeyguard) {
+        return (!mOnKeyguard || allowOnKeyguard)
                 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
                 || isUserExpanded());
     }
@@ -1010,12 +1102,7 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
         updateMaxHeights();
-        if (updateExpandHeight) {
-            applyExpansionToLayout();
-        }
-        mWasReset = false;
     }
 
     private void updateMaxHeights() {
@@ -1041,12 +1128,21 @@
         getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
     }
 
-    public void setSensitive(boolean sensitive) {
+    public void setSensitive(boolean sensitive, boolean hideSensitive) {
         mSensitive = sensitive;
+        mSensitiveHiddenInGeneral = hideSensitive;
     }
 
     public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
         mHideSensitiveForIntrinsicHeight = hideSensitive;
+        if (mIsSummaryWithChildren) {
+            List<ExpandableNotificationRow> notificationChildren =
+                    mChildrenContainer.getNotificationChildren();
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow child = notificationChildren.get(i);
+                child.setHideSensitiveForIntrinsicHeight(hideSensitive);
+            }
+        }
     }
 
     public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
@@ -1070,7 +1166,8 @@
         } else {
             animateShowingPublic(delay, duration);
         }
-
+        NotificationContentView showingLayout = getShowingLayout();
+        showingLayout.updateBackgroundColor(animated);
         mPrivateLayout.updateExpandButtons(isExpandable());
         updateClearability();
         mShowingPublicInitialized = true;
@@ -1114,7 +1211,8 @@
 
     private void updateClearability() {
         // public versions cannot be dismissed
-        mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
+        mVetoButton.setVisibility(isClearable() && (!mShowingPublic
+                || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
     }
 
     public void setChildrenExpanded(boolean expanded, boolean animate) {
@@ -1127,13 +1225,6 @@
         }
     }
 
-    public void updateHeaderChildCount() {
-        if (mIsSummaryWithChildren) {
-            mNotificationHeader.setChildCount(
-                    mChildrenContainer.getNotificationChildren().size());
-        }
-    }
-
     public static void applyTint(View v, int color) {
         int alpha;
         if (color != 0) {
@@ -1154,6 +1245,10 @@
         return mMaxExpandHeight;
     }
 
+    public boolean areGutsExposed() {
+        return (mGuts != null && mGuts.areGutsExposed());
+    }
+
     @Override
     public boolean isContentExpandable() {
         NotificationContentView showingLayout = getShowingLayout();
@@ -1168,13 +1263,19 @@
     @Override
     public void setActualHeight(int height, boolean notifyListeners) {
         super.setActualHeight(height, notifyListeners);
+        if (mGuts != null && mGuts.areGutsExposed()) {
+            mGuts.setActualHeight(height);
+            return;
+        }
         int contentHeight = Math.max(getMinHeight(), height);
         mPrivateLayout.setContentHeight(contentHeight);
         mPublicLayout.setContentHeight(contentHeight);
+        if (mIsSummaryWithChildren) {
+            mChildrenContainer.setActualHeight(height);
+        }
         if (mGuts != null) {
             mGuts.setActualHeight(height);
         }
-        invalidate();
     }
 
     @Override
@@ -1200,9 +1301,9 @@
     }
 
     @Override
-    public int getMinExpandHeight() {
-        if (mIsSummaryWithChildren && !mOnKeyguard) {
-            return mChildrenContainer.getMinExpandHeight();
+    public int getCollapsedHeight() {
+        if (mIsSummaryWithChildren && !mShowingPublic) {
+            return mChildrenContainer.getCollapsedHeight();
         }
         return getMinHeight();
     }
@@ -1235,15 +1336,7 @@
             header.reapply(getContext(), mNotificationHeader);
             mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
         }
-        updateHeaderExpandButton();
         updateChildrenHeaderAppearance();
-        updateHeaderChildCount();
-    }
-
-    private void updateHeaderExpandButton() {
-        if (mIsSummaryWithChildren) {
-            mNotificationHeader.setIsGroupHeader(true /* isGroupHeader*/);
-        }
     }
 
     public void updateChildrenHeaderAppearance() {
@@ -1256,7 +1349,7 @@
         return mMaxExpandHeight != 0;
     }
 
-    private NotificationContentView getShowingLayout() {
+    public NotificationContentView getShowingLayout() {
         return mShowingPublic ? mPublicLayout : mPrivateLayout;
     }
 
@@ -1292,8 +1385,15 @@
     }
 
     @Override
-    public boolean needsIncreasedPadding() {
-        return mIsSummaryWithChildren && isGroupExpanded();
+    public float getIncreasedPaddingAmount() {
+        if (mIsSummaryWithChildren) {
+            if (isGroupExpanded()) {
+                return 1.0f;
+            } else if (isUserLocked()) {
+                return mChildrenContainer.getGroupExpandFraction();
+            }
+        }
+        return 0.0f;
     }
 
     @Override
@@ -1302,7 +1402,7 @@
         float y = event.getY();
         NotificationHeaderView header = getVisibleNotificationHeader();
         if (header != null) {
-            return header.isInTouchRect(x, y);
+            return header.isInTouchRect(x - getTranslation(), y);
         }
         return super.disallowSingleClick(event);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 782a38c..f98e87d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -70,6 +70,11 @@
         }
     }
 
+    @Override
+    public float getOutlineAlpha() {
+        return mOutlineAlpha;
+    }
+
     protected void setOutlineRect(RectF rect) {
         if (rect != null) {
             setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
@@ -80,6 +85,11 @@
         }
     }
 
+    @Override
+    public int getOutlineTranslation() {
+        return mCustomOutline ? mOutlineRect.left : 0;
+    }
+
     protected void setOutlineRect(float left, float top, float right, float bottom) {
         setOutlineRect(true, left, top, right, bottom);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 3176e2e..6dcd61f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -36,7 +36,6 @@
     protected OnHeightChangedListener mOnHeightChangedListener;
     private int mActualHeight;
     protected int mClipTopAmount;
-    private boolean mActualHeightInitialized;
     private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
     private int mClipTopOptimization;
@@ -44,6 +43,7 @@
     private boolean mWillBeGone;
     private int mMinClipTopAmount = 0;
     private boolean mClipToActualHeight = true;
+    private boolean mChangingPosition = false;
 
     public ExpandableView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -99,28 +99,9 @@
     @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) {
-            int initialHeight = getInitialHeight();
-            if (initialHeight != 0) {
-                setActualHeight(initialHeight);
-            }
-        }
         updateClipping();
     }
 
-    /**
-     * Resets the height of the view on the next layout pass
-     */
-    protected void resetActualHeight() {
-        mActualHeight = 0;
-        mActualHeightInitialized = false;
-        requestLayout();
-    }
-
-    protected int getInitialHeight() {
-        return getHeight();
-    }
-
     @Override
     public boolean pointInView(float localX, float localY, float slop) {
         float top = mClipTopAmount;
@@ -137,7 +118,6 @@
      * @param notifyListeners Whether the listener should be informed about the change.
      */
     public void setActualHeight(int actualHeight, boolean notifyListeners) {
-        mActualHeightInitialized = true;
         mActualHeight = actualHeight;
         updateClipping();
         if (notifyListeners) {
@@ -173,11 +153,11 @@
     }
 
     /**
-     * @return The minimum height this child chan be expanded to. Note that this might be different
-     * than {@link #getMinHeight()} because some elements can't be collapsed by an expand gesture
-     * to it's absolute minimal height
+     * @return The collapsed height of this view. Note that this might be different
+     * than {@link #getMinHeight()} because some elements like groups may have different sizes when
+     * they are system expanded.
      */
-    public int getMinExpandHeight() {
+    public int getCollapsedHeight() {
         return getHeight();
     }
 
@@ -283,6 +263,20 @@
     public void setBelowSpeedBump(boolean below) {
     }
 
+    /**
+     * Sets the translation of the view.
+     */
+    public void setTranslation(float translation) {
+        setTranslationX(translation);
+    }
+
+    /**
+     * Gets the translation of the view.
+     */
+    public float getTranslation() {
+        return getTranslationX();
+    }
+
     public void onHeightReset() {
         if (mOnHeightChangedListener != null) {
             mOnHeightChangedListener.onReset(this);
@@ -391,14 +385,37 @@
     public void setShadowAlpha(float shadowAlpha) {
     }
 
-    public boolean needsIncreasedPadding() {
-        return false;
+    /**
+     * @return an amount between 0 and 1 of increased padding that this child needs
+     */
+    public float getIncreasedPaddingAmount() {
+        return 0.0f;
     }
 
     public boolean mustStayOnScreen() {
         return false;
     }
 
+    public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
+            int outlineTranslation) {
+    }
+
+    public float getOutlineAlpha() {
+        return 0.0f;
+    }
+
+    public int getOutlineTranslation() {
+        return 0;
+    }
+
+    public void setChangingPosition(boolean changingPosition) {
+        mChangingPosition = changingPosition;
+    }
+
+    public boolean isChangingPosition() {
+        return mChangingPosition;
+    }
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java
new file mode 100644
index 0000000..6746a67
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Layout used as a container for keyboard shortcut keys. It's children are wrapped and right
+ * aligned.
+ */
+public final class KeyboardShortcutKeysLayout extends ViewGroup {
+    private int mLineHeight;
+    private final Context mContext;
+
+    public KeyboardShortcutKeysLayout(Context context) {
+        super(context);
+        this.mContext = context;
+    }
+
+    public KeyboardShortcutKeysLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        this.mContext = context;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
+        int childCount = getChildCount();
+        int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
+        int lineHeight = 0;
+        int xPos = getPaddingLeft();
+        int yPos = getPaddingTop();
+
+        int childHeightMeasureSpec;
+        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+        } else {
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        }
+
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
+                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+                        childHeightMeasureSpec);
+                int childWidth = child.getMeasuredWidth();
+                lineHeight = Math.max(lineHeight,
+                        child.getMeasuredHeight() + layoutParams.mVerticalSpacing);
+
+                if (xPos + childWidth > width) {
+                    xPos = getPaddingLeft();
+                    yPos += lineHeight;
+                }
+                xPos += childWidth + layoutParams.mHorizontalSpacing;
+            }
+        }
+        this.mLineHeight = lineHeight;
+
+        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+            height = yPos + lineHeight;
+        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+            if (yPos + lineHeight < height) {
+                height = yPos + lineHeight;
+            }
+        }
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        int spacing = getHorizontalVerticalSpacing();
+        return new LayoutParams(spacing, spacing);
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams layoutParams) {
+        int spacing = getHorizontalVerticalSpacing();
+        return new LayoutParams(spacing, spacing, layoutParams);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return (p instanceof LayoutParams);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int childCount = getChildCount();
+        int fullRowWidth = r - l;
+        int xPos = isRTL()
+                ? fullRowWidth - getPaddingRight()
+                : getPaddingLeft();
+        int yPos = getPaddingTop();
+        int lastHorizontalSpacing = 0;
+        // The index of the child which starts the current row.
+        int rowStartIdx = 0;
+
+        // Go through all the children.
+        for (int i = 0; i < childCount; i++) {
+            View currentChild = getChildAt(i);
+            if (currentChild.getVisibility() != GONE) {
+                int currentChildWidth = currentChild.getMeasuredWidth();
+                LayoutParams lp = (LayoutParams) currentChild.getLayoutParams();
+
+                boolean childDoesNotFitOnRow = isRTL()
+                        ? xPos - getPaddingLeft() - currentChildWidth < 0
+                        : xPos + currentChildWidth > fullRowWidth;
+
+                if (childDoesNotFitOnRow) {
+                    // Layout all the children on this row but the current one.
+                    layoutChildrenOnRow(rowStartIdx, i, fullRowWidth, xPos, yPos,
+                            lastHorizontalSpacing);
+                    // Update the positions for starting on the new row.
+                    xPos = isRTL()
+                            ? fullRowWidth - getPaddingRight()
+                            : getPaddingLeft();
+                    yPos += mLineHeight;
+                    rowStartIdx = i;
+                }
+
+                xPos = isRTL()
+                        ? xPos - currentChildWidth - lp.mHorizontalSpacing
+                        : xPos + currentChildWidth + lp.mHorizontalSpacing;
+                lastHorizontalSpacing = lp.mHorizontalSpacing;
+            }
+        }
+
+        // Lay out the children on the last row.
+        if (rowStartIdx < childCount) {
+            layoutChildrenOnRow(rowStartIdx, childCount, fullRowWidth, xPos, yPos,
+                    lastHorizontalSpacing);
+        }
+    }
+
+    private int getHorizontalVerticalSpacing() {
+        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+        return (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, 4, displayMetrics);
+    }
+
+    private void layoutChildrenOnRow(int startIndex, int endIndex, int fullRowWidth, int xPos,
+            int yPos, int lastHorizontalSpacing) {
+        if (!isRTL()) {
+            xPos = getPaddingLeft() + fullRowWidth - xPos + lastHorizontalSpacing;
+        }
+
+        for (int j = startIndex; j < endIndex; ++j) {
+            View currentChild = getChildAt(j);
+            int currentChildWidth = currentChild.getMeasuredWidth();
+            LayoutParams lp = (LayoutParams) currentChild.getLayoutParams();
+            if (isRTL() && j == startIndex) {
+                xPos = fullRowWidth - xPos - getPaddingRight() - currentChildWidth
+                        - lp.mHorizontalSpacing;
+            }
+
+            currentChild.layout(
+                    xPos,
+                    yPos,
+                    xPos + currentChildWidth,
+                    yPos + currentChild.getMeasuredHeight());
+
+            if (isRTL()) {
+                int nextChildWidth = j < endIndex - 1
+                        ? getChildAt(j + 1).getMeasuredWidth()
+                        : 0;
+                xPos -= nextChildWidth + lp.mHorizontalSpacing;
+            } else {
+                xPos += currentChildWidth + lp.mHorizontalSpacing;
+            }
+        }
+    }
+
+    private boolean isRTL() {
+        return mContext.getResources().getConfiguration().getLayoutDirection()
+                == View.LAYOUT_DIRECTION_RTL;
+    }
+
+    public static class LayoutParams extends ViewGroup.LayoutParams {
+        public final int mHorizontalSpacing;
+        public final int mVerticalSpacing;
+
+        public LayoutParams(int horizontalSpacing, int verticalSpacing,
+                ViewGroup.LayoutParams viewGroupLayout) {
+            super(viewGroupLayout);
+            this.mHorizontalSpacing = horizontalSpacing;
+            this.mVerticalSpacing = verticalSpacing;
+        }
+
+        public LayoutParams(int mHorizontalSpacing, int verticalSpacing) {
+            super(0, 0);
+            this.mHorizontalSpacing = mHorizontalSpacing;
+            this.mVerticalSpacing = verticalSpacing;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 0b7bfa8..2b365dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -21,14 +21,20 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
+import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.Looper;
+import android.util.Log;
+import android.util.SparseArray;
 import android.view.ContextThemeWrapper;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
 import android.view.KeyboardShortcutInfo;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager.KeyboardShortcutsReceiver;
 import android.widget.LinearLayout;
@@ -41,16 +47,163 @@
 import java.util.List;
 
 import static android.content.Context.LAYOUT_INFLATER_SERVICE;
-import static android.view.Gravity.TOP;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 
 /**
  * Contains functionality for handling keyboard shortcuts.
  */
 public class KeyboardShortcuts {
-    private static final char SYSTEM_HOME_BASE_CHARACTER = '\u2386';
-    private static final char SYSTEM_BACK_BASE_CHARACTER = '\u007F';
-    private static final char SYSTEM_RECENTS_BASE_CHARACTER = '\u0009';
+    private static final String TAG = KeyboardShortcuts.class.getSimpleName();
+
+    private static final SparseArray<String> SPECIAL_CHARACTER_NAMES = new SparseArray<>();
+    private static final SparseArray<String> MODIFIER_NAMES = new SparseArray<>();
+
+    private static void loadSpecialCharacterNames(Context context) {
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_BACK, context.getString(R.string.keyboard_key_back));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_DPAD_UP, context.getString(R.string.keyboard_key_dpad_up));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_DPAD_DOWN, context.getString(R.string.keyboard_key_dpad_down));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_DPAD_LEFT, context.getString(R.string.keyboard_key_dpad_left));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_DPAD_RIGHT, context.getString(R.string.keyboard_key_dpad_right));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_DPAD_CENTER, context.getString(R.string.keyboard_key_dpad_center));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_PERIOD, ".");
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_TAB, context.getString(R.string.keyboard_key_tab));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_SPACE, context.getString(R.string.keyboard_key_space));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_ENTER, context.getString(R.string.keyboard_key_enter));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_DEL, context.getString(R.string.keyboard_key_backspace));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+                context.getString(R.string.keyboard_key_media_play_pause));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_MEDIA_STOP, context.getString(R.string.keyboard_key_media_stop));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_MEDIA_NEXT, context.getString(R.string.keyboard_key_media_next));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS,
+                context.getString(R.string.keyboard_key_media_previous));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_REWIND,
+                context.getString(R.string.keyboard_key_media_rewind));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD,
+                context.getString(R.string.keyboard_key_media_fast_forward));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_PAGE_UP, context.getString(R.string.keyboard_key_page_up));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_PAGE_DOWN, context.getString(R.string.keyboard_key_page_down));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_A,
+                context.getString(R.string.keyboard_key_button_template, "A"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_B,
+                context.getString(R.string.keyboard_key_button_template, "B"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_C,
+                context.getString(R.string.keyboard_key_button_template, "C"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_X,
+                context.getString(R.string.keyboard_key_button_template, "X"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_Y,
+                context.getString(R.string.keyboard_key_button_template, "Y"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_Z,
+                context.getString(R.string.keyboard_key_button_template, "Z"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_L1,
+                context.getString(R.string.keyboard_key_button_template, "L1"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_R1,
+                context.getString(R.string.keyboard_key_button_template, "R1"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_L2,
+                context.getString(R.string.keyboard_key_button_template, "L2"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_R2,
+                context.getString(R.string.keyboard_key_button_template, "R2"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_START,
+                context.getString(R.string.keyboard_key_button_template, "Start"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_SELECT,
+                context.getString(R.string.keyboard_key_button_template, "Select"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_MODE,
+                context.getString(R.string.keyboard_key_button_template, "Mode"));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_FORWARD_DEL, context.getString(R.string.keyboard_key_forward_del));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_ESCAPE, "Esc");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_SYSRQ, "SysRq");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BREAK, "Break");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_SCROLL_LOCK, "Scroll Lock");
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_MOVE_HOME, context.getString(R.string.keyboard_key_move_home));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_MOVE_END, context.getString(R.string.keyboard_key_move_end));
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_INSERT, context.getString(R.string.keyboard_key_insert));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F1, "F1");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F2, "F2");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F3, "F3");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F4, "F4");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F5, "F5");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F6, "F6");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F7, "F7");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F8, "F8");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F9, "F9");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F10, "F10");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F11, "F11");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F12, "F12");
+        SPECIAL_CHARACTER_NAMES.put(
+                KeyEvent.KEYCODE_NUM_LOCK, context.getString(R.string.keyboard_key_num_lock));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_0,
+                context.getString(R.string.keyboard_key_numpad_template, "0"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_1,
+                context.getString(R.string.keyboard_key_numpad_template, "1"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_2,
+                context.getString(R.string.keyboard_key_numpad_template, "2"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_3,
+                context.getString(R.string.keyboard_key_numpad_template, "3"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_4,
+                context.getString(R.string.keyboard_key_numpad_template, "4"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_5,
+                context.getString(R.string.keyboard_key_numpad_template, "5"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_6,
+                context.getString(R.string.keyboard_key_numpad_template, "6"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_7,
+                context.getString(R.string.keyboard_key_numpad_template, "7"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_8,
+                context.getString(R.string.keyboard_key_numpad_template, "8"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_9,
+                context.getString(R.string.keyboard_key_numpad_template, "9"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE,
+                context.getString(R.string.keyboard_key_numpad_template, "/"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
+                context.getString(R.string.keyboard_key_numpad_template, "*"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
+                context.getString(R.string.keyboard_key_numpad_template, "-"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_ADD,
+                context.getString(R.string.keyboard_key_numpad_template, "+"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_DOT,
+                context.getString(R.string.keyboard_key_numpad_template, "."));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_COMMA,
+                context.getString(R.string.keyboard_key_numpad_template, ","));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_ENTER,
+                context.getString(R.string.keyboard_key_numpad_template,
+                        context.getString(R.string.keyboard_key_enter)));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_EQUALS,
+                context.getString(R.string.keyboard_key_numpad_template, "="));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN,
+                context.getString(R.string.keyboard_key_numpad_template, "("));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN,
+                context.getString(R.string.keyboard_key_numpad_template, ")"));
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_ZENKAKU_HANKAKU, "半角/全角");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_EISU, "英数");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MUHENKAN, "無変換");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_HENKAN, "変換");
+        SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_KATAKANA_HIRAGANA, "かな");
+
+        MODIFIER_NAMES.put(KeyEvent.META_META_ON, "Meta");
+        MODIFIER_NAMES.put(KeyEvent.META_CTRL_ON, "Ctrl");
+        MODIFIER_NAMES.put(KeyEvent.META_ALT_ON, "Alt");
+        MODIFIER_NAMES.put(KeyEvent.META_SHIFT_ON, "Shift");
+        MODIFIER_NAMES.put(KeyEvent.META_SYM_ON, "Sym");
+        MODIFIER_NAMES.put(KeyEvent.META_FUNCTION_ON, "Fn");
+    }
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final Context mContext;
@@ -61,12 +214,20 @@
     };
 
     private Dialog mKeyboardShortcutsDialog;
+    private KeyCharacterMap mKeyCharacterMap;
 
     public KeyboardShortcuts(Context context) {
         this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light);
+        if (SPECIAL_CHARACTER_NAMES.size() == 0) {
+            loadSpecialCharacterNames(context);
+        }
     }
 
-    public void toggleKeyboardShortcuts() {
+    public void toggleKeyboardShortcuts(int deviceId) {
+        InputDevice inputDevice = InputManager.getInstance().getInputDevice(deviceId);
+        if (inputDevice != null) {
+            mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+        }
         if (mKeyboardShortcutsDialog == null) {
             Recents.getSystemServices().requestKeyboardShortcuts(mContext,
                 new KeyboardShortcutsReceiver() {
@@ -74,20 +235,70 @@
                     public void onKeyboardShortcutsReceived(
                             final List<KeyboardShortcutGroup> result) {
                         KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup(
-                            mContext.getString(R.string.keyboard_shortcut_group_system), true);
+                                mContext.getString(R.string.keyboard_shortcut_group_system), true);
                         systemGroup.addItem(new KeyboardShortcutInfo(
-                            mContext.getString(R.string.keyboard_shortcut_group_system_home),
-                            SYSTEM_HOME_BASE_CHARACTER, KeyEvent.META_META_ON));
+                                mContext.getString(R.string.keyboard_shortcut_group_system_home),
+                                KeyEvent.KEYCODE_ENTER, KeyEvent.META_META_ON));
                         systemGroup.addItem(new KeyboardShortcutInfo(
-                            mContext.getString(R.string.keyboard_shortcut_group_system_back),
-                            SYSTEM_BACK_BASE_CHARACTER, KeyEvent.META_META_ON));
+                                mContext.getString(R.string.keyboard_shortcut_group_system_back),
+                                KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON));
                         systemGroup.addItem(new KeyboardShortcutInfo(
-                            mContext.getString(R.string.keyboard_shortcut_group_system_recents),
-                            SYSTEM_RECENTS_BASE_CHARACTER, KeyEvent.META_ALT_ON));
+                                mContext.getString(R.string.keyboard_shortcut_group_system_recents),
+                                KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON));
+                        systemGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_system_notifications),
+                                KeyEvent.KEYCODE_N, KeyEvent.META_META_ON));
+                        systemGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_system_shortcuts_helper),
+                                KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON));
+                        systemGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_system_switch_input),
+                                KeyEvent.KEYCODE_SPACE, KeyEvent.META_META_ON));
                         result.add(systemGroup);
+
+                        KeyboardShortcutGroup applicationGroup = new KeyboardShortcutGroup(
+                                mContext.getString(R.string.keyboard_shortcut_group_applications),
+                                true);
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_assist),
+                                KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_browser),
+                                KeyEvent.KEYCODE_B, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_contacts),
+                                KeyEvent.KEYCODE_C, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_email),
+                                KeyEvent.KEYCODE_E, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_im),
+                                KeyEvent.KEYCODE_T, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_music),
+                                KeyEvent.KEYCODE_P, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_youtube),
+                                KeyEvent.KEYCODE_Y, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_calendar),
+                                KeyEvent.KEYCODE_L, KeyEvent.META_META_ON));
+                        result.add(applicationGroup);
+
                         showKeyboardShortcutsDialog(result);
                     }
-                });
+                }, deviceId);
         } else {
             dismissKeyboardShortcutsDialog();
         }
@@ -147,15 +358,26 @@
             final int itemsSize = group.getItems().size();
             for (int j = 0; j < itemsSize; j++) {
                 KeyboardShortcutInfo info = group.getItems().get(j);
+                if (info.getKeycode() != KeyEvent.KEYCODE_UNKNOWN
+                        && !KeyCharacterMap.deviceHasKey(info.getKeycode())) {
+                    // The user can't achieve this shortcut, so skipping.
+                    Log.w(TAG, "Keyboard Shortcut contains key not on device, skipping.");
+                    continue;
+                }
+                List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
+                if (shortcutKeys == null) {
+                    // Ignore shortcuts we can't display keys for.
+                    Log.w(TAG, "Keyboard Shortcut contains unsupported keys, skipping.");
+                    continue;
+                }
                 View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item,
                         shortcutContainer, false);
                 TextView textView = (TextView) shortcutView
                         .findViewById(R.id.keyboard_shortcuts_keyword);
                 textView.setText(info.getLabel());
 
-                LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
+                ViewGroup shortcutItemsContainer = (ViewGroup) shortcutView
                         .findViewById(R.id.keyboard_shortcuts_item_container);
-                List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
                 final int shortcutKeysSize = shortcutKeys.size();
                 for (int k = 0; k < shortcutKeysSize; k++) {
                     String shortcutKey = shortcutKeys.get(k);
@@ -177,11 +399,50 @@
     }
 
     private List<String> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
-        // TODO: fix the shortcuts. Find or build an util which can produce human readable
-        // names of the baseCharacter and the modifiers.
-        List<String> shortcutKeys = new ArrayList<>();
-        shortcutKeys.add(KeyEvent.metaStateToString(info.getModifiers()).toUpperCase());
-        shortcutKeys.add(Character.getName(info.getBaseCharacter()).toUpperCase());
+        List<String> shortcutKeys = getHumanReadableModifiers(info);
+        if (shortcutKeys == null) {
+            return null;
+        }
+        String displayLabelString;
+        if (info.getBaseCharacter() > Character.MIN_VALUE) {
+            displayLabelString = String.valueOf(info.getBaseCharacter());
+        } else if (SPECIAL_CHARACTER_NAMES.get(info.getKeycode()) != null) {
+            displayLabelString = SPECIAL_CHARACTER_NAMES.get(info.getKeycode());
+        } else {
+            // Special case for shortcuts with no base key or keycode.
+            if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+                return shortcutKeys;
+            }
+            // TODO: Have a generic map for when we don't have the device's.
+            char displayLabel = mKeyCharacterMap == null
+                    ? 0 : mKeyCharacterMap.getDisplayLabel(info.getKeycode());
+            if (displayLabel != 0) {
+                displayLabelString = String.valueOf(displayLabel);
+            } else {
+                return null;
+            }
+        }
+        shortcutKeys.add(displayLabelString.toUpperCase());
+        return shortcutKeys;
+    }
+
+    private List<String> getHumanReadableModifiers(KeyboardShortcutInfo info) {
+        final List<String> shortcutKeys = new ArrayList<>();
+        int modifiers = info.getModifiers();
+        if (modifiers == 0) {
+            return shortcutKeys;
+        }
+        for(int i = 0; i < MODIFIER_NAMES.size(); ++i) {
+            final int supportedModifier = MODIFIER_NAMES.keyAt(i);
+            if ((modifiers & supportedModifier) != 0) {
+                shortcutKeys.add(MODIFIER_NAMES.get(supportedModifier).toUpperCase());
+                modifiers &= ~supportedModifier;
+            }
+        }
+        if (modifiers != 0) {
+            // Remaining unsupported modifiers, don't show anything.
+            return null;
+        }
         return shortcutKeys;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 647f0bf..5b00523 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -29,10 +29,12 @@
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
-import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.notification.HybridGroupManager;
 import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -48,6 +50,7 @@
     private static final int VISIBLE_TYPE_EXPANDED = 1;
     private static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
+    public static final int UNDEFINED = -1;
 
     private final Rect mClipBounds = new Rect();
     private final int mMinContractedHeight;
@@ -67,10 +70,13 @@
     private View mHeadsUpChild;
     private HybridNotificationView mSingleLineView;
 
+    private RemoteInputView mExpandedRemoteInput;
+    private RemoteInputView mHeadsUpRemoteInput;
+
     private NotificationViewWrapper mContractedWrapper;
     private NotificationViewWrapper mExpandedWrapper;
     private NotificationViewWrapper mHeadsUpWrapper;
-    private HybridNotificationViewManager mHybridViewManager;
+    private HybridGroupManager mHybridGroupManager;
     private int mClipTopAmount;
     private int mContentHeight;
     private int mUnrestrictedContentHeight;
@@ -91,7 +97,14 @@
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
-            mAnimate = true;
+            // We need to post since we don't want the notification to animate on the very first
+            // frame
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    mAnimate = true;
+                }
+            });
             getViewTreeObserver().removeOnPreDrawListener(this);
             return true;
         }
@@ -102,15 +115,18 @@
     private boolean mExpandable;
     private boolean mClipToActualHeight = true;
     private ExpandableNotificationRow mContainingNotification;
+    private int mTransformationStartVisibleType;
+    private boolean mUserExpanding;
+    private int mSingleLineWidthIndention;
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
+        mHybridGroupManager = new HybridGroupManager(getContext(), this);
         mMinContractedHeight = getResources().getDimensionPixelSize(
                 R.dimen.min_notification_layout_height);
         mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_end);
-        reset(true);
+        reset();
     }
 
     public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -125,6 +141,7 @@
         boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
         boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
         int maxSize = Integer.MAX_VALUE;
+        int width = MeasureSpec.getSize(widthMeasureSpec);
         if (hasFixedHeight || isHeightLimited) {
             maxSize = MeasureSpec.getSize(heightMeasureSpec);
         }
@@ -173,12 +190,18 @@
             maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
         }
         if (mSingleLineView != null) {
-            mSingleLineView.measure(widthMeasureSpec,
+            int singleLineWidthSpec = widthMeasureSpec;
+            if (mSingleLineWidthIndention != 0
+                    && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
+                singleLineWidthSpec = MeasureSpec.makeMeasureSpec(
+                        width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(),
+                        MeasureSpec.AT_MOST);
+            }
+            mSingleLineView.measure(singleLineWidthSpec,
                     MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
         }
         int ownHeight = Math.min(maxChildHeight, maxSize);
-        int width = MeasureSpec.getSize(widthMeasureSpec);
         setMeasuredDimension(width, ownHeight);
     }
 
@@ -245,7 +268,7 @@
         updateVisibility();
     }
 
-    public void reset(boolean resetActualHeight) {
+    public void reset() {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
             removeView(mContractedChild);
@@ -261,10 +284,6 @@
         mContractedChild = null;
         mExpandedChild = null;
         mHeadsUpChild = null;
-        mVisibleType = VISIBLE_TYPE_CONTRACTED;
-        if (resetActualHeight) {
-            mContentHeight = mSmallHeight;
-        }
     }
 
     public View getContractedChild() {
@@ -349,6 +368,60 @@
         invalidateOutline();
     }
 
+    private void updateContentTransformation() {
+        int visibleType = calculateVisibleType();
+        if (visibleType != mVisibleType) {
+            // A new transformation starts
+            mTransformationStartVisibleType = mVisibleType;
+            final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
+            final TransformableView hiddenView = getTransformableViewForVisibleType(
+                    mTransformationStartVisibleType);
+            shownView.transformFrom(hiddenView, 0.0f);
+            getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
+            hiddenView.transformTo(shownView, 0.0f);
+            mVisibleType = visibleType;
+            updateBackgroundColor(true /* animate */);
+        }
+        if (mTransformationStartVisibleType != UNDEFINED
+                && mVisibleType != mTransformationStartVisibleType) {
+            final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType);
+            final TransformableView hiddenView = getTransformableViewForVisibleType(
+                    mTransformationStartVisibleType);
+            float transformationAmount = calculateTransformationAmount();
+            shownView.transformFrom(hiddenView, transformationAmount);
+            hiddenView.transformTo(shownView, transformationAmount);
+            updateBackgroundTransformation(transformationAmount);
+        } else {
+            updateViewVisibilities(visibleType);
+            updateBackgroundColor(false);
+        }
+    }
+
+    private void updateBackgroundTransformation(float transformationAmount) {
+        int endColor = getBackgroundColor(mVisibleType);
+        int startColor = getBackgroundColor(mTransformationStartVisibleType);
+        if (endColor != startColor) {
+            if (startColor == 0) {
+                startColor = mContainingNotification.getBackgroundColorWithoutTint();
+            }
+            if (endColor == 0) {
+                endColor = mContainingNotification.getBackgroundColorWithoutTint();
+            }
+            endColor = NotificationUtils.interpolateColors(startColor, endColor,
+                    transformationAmount);
+        }
+        mContainingNotification.setContentBackground(endColor, false, this);
+    }
+
+    private float calculateTransformationAmount() {
+        int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
+        int endHeight = getViewForVisibleType(mVisibleType).getHeight();
+        int progress = Math.abs(mContentHeight - startHeight);
+        int totalDistance = Math.abs(endHeight - startHeight);
+        float amount = (float) progress / (float) totalDistance;
+        return Math.min(1.0f, amount);
+    }
+
     public int getContentHeight() {
         return mContentHeight;
     }
@@ -363,10 +436,14 @@
     }
 
     public int getMinHeight() {
-        if (mIsChildInGroup && !isGroupExpanded()) {
-            return mSingleLineView.getHeight();
-        } else {
+        return getMinHeight(false /* likeGroupExpanded */);
+    }
+
+    public int getMinHeight(boolean likeGroupExpanded) {
+        if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
             return mContractedChild.getHeight();
+        } else {
+            return mSingleLineView.getHeight();
         }
     }
 
@@ -397,6 +474,10 @@
         if (mContractedChild == null) {
             return;
         }
+        if (mUserExpanding) {
+            updateContentTransformation();
+            return;
+        }
         int visibleType = calculateVisibleType();
         if (visibleType != mVisibleType || force) {
             if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
@@ -408,9 +489,24 @@
                 updateViewVisibilities(visibleType);
             }
             mVisibleType = visibleType;
+            updateBackgroundColor(animate);
         }
     }
 
+    public void updateBackgroundColor(boolean animate) {
+        int customBackgroundColor = getBackgroundColor(mVisibleType);
+        mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
+    }
+
+    private int getBackgroundColor(int visibleType) {
+        NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
+        int customBackgroundColor = 0;
+        if (currentVisibleWrapper != null) {
+            customBackgroundColor = currentVisibleWrapper.getCustomBackgroundColor();
+        }
+        return customBackgroundColor;
+    }
+
     private void updateViewVisibilities(int visibleType) {
         boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
         mContractedWrapper.setVisible(contractedVisible);
@@ -431,12 +527,18 @@
     private void animateToVisibleType(int visibleType) {
         final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
         final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
+        if (shownView == hiddenView) {
+            shownView.setVisible(true);
+            return;
+        }
         shownView.transformFrom(hiddenView);
         getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
         hiddenView.transformTo(shownView, new Runnable() {
             @Override
             public void run() {
-                hiddenView.setVisible(false);
+                if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
+                    hiddenView.setVisible(false);
+                }
             }
         });
     }
@@ -475,8 +577,8 @@
         }
     }
 
-    private NotificationViewWrapper getCurrentVisibleWrapper() {
-        switch (mVisibleType) {
+    private NotificationViewWrapper getVisibleWrapper(int visibleType) {
+        switch (visibleType) {
             case VISIBLE_TYPE_EXPANDED:
                 return mExpandedWrapper;
             case VISIBLE_TYPE_HEADSUP:
@@ -492,13 +594,36 @@
      * @return one of the static enum types in this view, calculated form the current state
      */
     private int calculateVisibleType() {
-        boolean noExpandedChild = mExpandedChild == null;
+        if (mUserExpanding) {
+            int height = !mIsChildInGroup || isGroupExpanded()
+                    || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
+                    ? mContainingNotification.getMaxContentHeight()
+                    : mContainingNotification.getShowingLayout().getMinHeight();
+            if (height == 0) {
+                height = mContentHeight;
+            }
+            int expandedVisualType = getVisualTypeForHeight(height);
+            int collapsedVisualType = getVisualTypeForHeight(
+                    mContainingNotification.getCollapsedHeight());
+            return mTransformationStartVisibleType == collapsedVisualType
+                    ? expandedVisualType
+                    : collapsedVisualType;
+        }
+        int intrinsicHeight = mContainingNotification.getIntrinsicHeight();
+        int viewHeight = mContentHeight;
+        if (intrinsicHeight != 0) {
+            // the intrinsicHeight might be 0 because it was just reset.
+            viewHeight = Math.min(mContentHeight, intrinsicHeight);
+        }
+        return getVisualTypeForHeight(viewHeight);
+    }
 
-        int viewHeight = Math.min(mContentHeight, mContainingNotification.getIntrinsicHeight());
+    private int getVisualTypeForHeight(float viewHeight) {
+        boolean noExpandedChild = mExpandedChild == null;
         if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
             return VISIBLE_TYPE_EXPANDED;
         }
-        if (mIsChildInGroup && !isGroupExpanded()) {
+        if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
             return VISIBLE_TYPE_SINGLELINE;
         }
 
@@ -510,7 +635,8 @@
             }
         } else {
             if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
-                    && (!mIsChildInGroup || !mContainingNotification.isExpanded()))) {
+                    && (!mIsChildInGroup
+                            || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
                 return VISIBLE_TYPE_CONTRACTED;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
@@ -523,9 +649,10 @@
     }
 
     public void setDark(boolean dark, boolean fade, long delay) {
-        if (mDark == dark || mContractedChild == null) return;
+        if (mContractedChild == null) {
+            return;
+        }
         mDark = dark;
-        dark = dark && !mShowingLegacyBackground;
         if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
             mContractedWrapper.setDark(dark, fade, delay);
         }
@@ -556,6 +683,19 @@
 
     public void setShowingLegacyBackground(boolean showing) {
         mShowingLegacyBackground = showing;
+        updateShowingLegacyBackground();
+    }
+
+    private void updateShowingLegacyBackground() {
+        if (mContractedChild != null) {
+            mContractedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+        }
+        if (mExpandedChild != null) {
+            mExpandedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+        }
+        if (mHeadsUpChild != null) {
+            mHeadsUpWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+        }
     }
 
     public void setIsChildInGroup(boolean isChildInGroup) {
@@ -568,10 +708,8 @@
         mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
         updateSingleLineView();
         applyRemoteInput(entry);
-        selectLayout(false /* animate */, true /* force */);
         if (mContractedChild != null) {
             mContractedWrapper.notifyContentUpdated(entry.notification);
-            mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
         }
         if (mExpandedChild != null) {
             mExpandedWrapper.notifyContentUpdated(entry.notification);
@@ -579,11 +717,14 @@
         if (mHeadsUpChild != null) {
             mHeadsUpWrapper.notifyContentUpdated(entry.notification);
         }
+        updateShowingLegacyBackground();
+        selectLayout(false /* animate */, true /* force */);
+        setDark(mDark, false /* animate */, 0 /* delay */);
     }
 
     private void updateSingleLineView() {
         if (mIsChildInGroup) {
-            mSingleLineView = mHybridViewManager.bindFromNotification(
+            mSingleLineView = mHybridGroupManager.bindFromNotification(
                     mSingleLineView, mStatusBarNotification.getNotification());
         } else if (mSingleLineView != null) {
             removeView(mSingleLineView);
@@ -614,15 +755,19 @@
 
         View bigContentView = mExpandedChild;
         if (bigContentView != null) {
-            applyRemoteInput(bigContentView, entry, hasRemoteInput);
+            mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput);
+        } else {
+            mExpandedRemoteInput = null;
         }
         View headsUpContentView = mHeadsUpChild;
         if (headsUpContentView != null) {
-            applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+            mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+        } else {
+            mHeadsUpRemoteInput = null;
         }
     }
 
-    private void applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
+    private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
         View actionContainerCandidate = view.findViewById(
                 com.android.internal.R.id.actions_container);
         if (actionContainerCandidate instanceof FrameLayout) {
@@ -643,12 +788,28 @@
                         ViewGroup.LayoutParams.MATCH_PARENT,
                         ViewGroup.LayoutParams.MATCH_PARENT)
                 );
+                existing = riv;
+            }
+            if (hasRemoteInput) {
                 int color = entry.notification.getNotification().color;
                 if (color == Notification.COLOR_DEFAULT) {
                     color = mContext.getColor(R.color.default_remote_input_background);
                 }
-                riv.setBackgroundColor(color);
+                existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color,
+                        mContext.getColor(R.color.remote_input_text),
+                        mContext.getColor(R.color.remote_input_hint)));
             }
+            return existing;
+        }
+        return null;
+    }
+
+    public void closeRemoteInput() {
+        if (mHeadsUpRemoteInput != null) {
+            mHeadsUpRemoteInput.close();
+        }
+        if (mExpandedRemoteInput != null) {
+            mExpandedRemoteInput.close();
         }
     }
 
@@ -698,7 +859,7 @@
     }
 
     public NotificationHeaderView getVisibleNotificationHeader() {
-        NotificationViewWrapper wrapper = getCurrentVisibleWrapper();
+        NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
         return wrapper == null ? null : wrapper.getNotificationHeader();
     }
 
@@ -717,4 +878,32 @@
             updateSingleLineView();
         }
     }
+
+    public void setUserExpanding(boolean userExpanding) {
+        mUserExpanding = userExpanding;
+        if (userExpanding) {
+            mTransformationStartVisibleType = mVisibleType;
+        } else {
+            mTransformationStartVisibleType = UNDEFINED;
+            mVisibleType = calculateVisibleType();
+            updateViewVisibilities(mVisibleType);
+            updateBackgroundColor(false);
+        }
+    }
+
+    /**
+     * Set by how much the single line view should be indented. Used when a overflow indicator is
+     * present and only during measuring
+     */
+    public void setSingleLineWidthIndention(int singleLineWidthIndention) {
+        if (singleLineWidthIndention != mSingleLineWidthIndention) {
+            mSingleLineWidthIndention = singleLineWidthIndention;
+            mContainingNotification.forceLayout();
+            forceLayout();
+        }
+    }
+
+    public HybridNotificationView getSingleLineView() {
+        return mSingleLineView;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index ccd0ad8..c9fe2bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -111,11 +111,11 @@
             if (updatedNotification != null) {
                 final Notification.Builder updatedNotificationBuilder
                         = Notification.Builder.recoverBuilder(ctx, updatedNotification);
-                final RemoteViews newContentView = updatedNotificationBuilder.makeContentView();
+                final RemoteViews newContentView = updatedNotificationBuilder.createContentView();
                 final RemoteViews newBigContentView =
-                        updatedNotificationBuilder.makeBigContentView();
+                        updatedNotificationBuilder.createBigContentView();
                 final RemoteViews newHeadsUpContentView =
-                        updatedNotificationBuilder.makeHeadsUpContentView();
+                        updatedNotificationBuilder.createHeadsUpContentView();
                 final RemoteViews newPublicNotification
                         = updatedNotificationBuilder.makePublicContentView();
 
@@ -137,9 +137,9 @@
                 final Notification.Builder builder
                         = Notification.Builder.recoverBuilder(ctx, notification.getNotification());
 
-                cachedContentView = builder.makeContentView();
-                cachedBigContentView = builder.makeBigContentView();
-                cachedHeadsUpContentView = builder.makeHeadsUpContentView();
+                cachedContentView = builder.createContentView();
+                cachedBigContentView = builder.createBigContentView();
+                cachedHeadsUpContentView = builder.createHeadsUpContentView();
                 cachedPublicContentView = builder.makePublicContentView();
 
                 applyInPlace = false;
@@ -203,11 +203,11 @@
 
             String mediaNotification = mEnvironment.getCurrentMediaNotificationKey();
 
-            // PRIORITY_MIN media streams are allowed to drift to the bottom
+            // IMPORTANCE_MIN media streams are allowed to drift to the bottom
             final boolean aMedia = a.key.equals(mediaNotification)
-                    && aImportance > Ranking.IMPORTANCE_LOW;
+                    && aImportance > Ranking.IMPORTANCE_MIN;
             final boolean bMedia = b.key.equals(mediaNotification)
-                    && bImportance > Ranking.IMPORTANCE_LOW;
+                    && bImportance > Ranking.IMPORTANCE_MIN;
 
             boolean aSystemMax = aImportance >= Ranking.IMPORTANCE_MAX &&
                     isSystemNotification(na);
@@ -353,8 +353,10 @@
             return true;
         }
 
-        if (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET &&
-                mEnvironment.shouldHideSensitiveContents(sbn.getUserId())) {
+        if (mEnvironment.onSecureLockScreen() &&
+                (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
+                        || mEnvironment.shouldHideNotifications(sbn.getUserId())
+                        || mEnvironment.shouldHideNotifications(sbn.getKey()))) {
             return true;
         }
 
@@ -433,7 +435,9 @@
      * Provides access to keyguard state and user settings dependent data.
      */
     public interface Environment {
-        public boolean shouldHideSensitiveContents(int userid);
+        public boolean onSecureLockScreen();
+        public boolean shouldHideNotifications(int userid);
+        public boolean shouldHideNotifications(String key);
         public boolean isDeviceProvisioned();
         public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
         public String getCurrentMediaNotificationKey();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index fe84d813..45a24a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar;
 
 import android.app.INotificationManager;
-import android.app.Notification;
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -39,23 +38,31 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
+import com.android.systemui.tuner.TunerService;
 
 /**
  * The guts of a notification revealed when performing a long press.
  */
-public class NotificationGuts extends LinearLayout {
+public class NotificationGuts extends LinearLayout implements TunerService.Tunable {
+    public static final String SHOW_SLIDER = "show_importance_slider";
 
     private Drawable mBackground;
     private int mClipTopAmount;
     private int mActualHeight;
     private boolean mExposed;
-    private SeekBar mSeekBar;
     private INotificationManager mINotificationManager;
     private int mStartingImportance;
+    private boolean mShowSlider;
+
+    private SeekBar mSeekBar;
+    private RadioButton mBlock;
+    private RadioButton mSilent;
+    private RadioButton mReset;
 
     public NotificationGuts(Context context, AttributeSet attrs) {
         super(context, attrs);
         setWillNotDraw(false);
+        TunerService.get(mContext).addTunable(this, SHOW_SLIDER);
     }
 
     @Override
@@ -102,31 +109,90 @@
         }
     }
 
-    void bindImportance(final StatusBarNotification sbn, final ExpandableNotificationRow row,
-            final int importance) {
+    void bindImportance(final PackageManager pm, final StatusBarNotification sbn,
+            final ExpandableNotificationRow row, final int importance) {
         mStartingImportance = importance;
         mINotificationManager = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-
-        final TextView importanceSummary = ((TextView) row.findViewById(R.id.summary));
-        final TextView importanceTitle = ((TextView) row.findViewById(R.id.title));
-        mSeekBar = (SeekBar) row.findViewById(R.id.seekbar);
         boolean systemApp = false;
         try {
-            final PackageManager pm = BaseStatusBar.getPackageManagerForUser(
-                    getContext(), sbn.getUser().getIdentifier());
             final PackageInfo info =
                     pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
             systemApp = Utils.isSystemPackage(pm, info);
         } catch (PackageManager.NameNotFoundException e) {
             // unlikely.
         }
+
+        final View importanceSlider = row.findViewById(R.id.importance_slider);
+        final View importanceButtons = row.findViewById(R.id.importance_buttons);
+        if (mShowSlider) {
+            bindSlider(importanceSlider, sbn, systemApp);
+            importanceSlider.setVisibility(View.VISIBLE);
+            importanceButtons.setVisibility(View.GONE);
+        } else {
+            int userImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+            try {
+                userImportance =
+                        mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
+            } catch (RemoteException e) {}
+            bindToggles(importanceButtons, userImportance, systemApp);
+            importanceButtons.setVisibility(View.VISIBLE);
+            importanceSlider.setVisibility(View.GONE);
+        }
+    }
+
+    void saveImportance(final StatusBarNotification sbn) {
+        int progress;
+        if (mSeekBar!= null && mSeekBar.isShown()) {
+            progress = mSeekBar.getProgress();
+        } else {
+            if (mBlock.isChecked()) {
+                progress = NotificationListenerService.Ranking.IMPORTANCE_NONE;
+            } else if (mSilent.isChecked()) {
+                progress = NotificationListenerService.Ranking.IMPORTANCE_LOW;
+            } else {
+                progress = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+            }
+        }
+        MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
+                progress - mStartingImportance);
+        try {
+            mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(), progress);
+        } catch (RemoteException e) {
+            // :(
+        }
+    }
+
+    private void bindToggles(final View importanceButtons, final int importance,
+            final boolean systemApp) {
+        mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
+        mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
+        mReset = (RadioButton) importanceButtons.findViewById(R.id.reset_importance);
         if (systemApp) {
-            ((ImageView) row.findViewById(R.id.low_importance)).getDrawable().setTint(
+            mBlock.setVisibility(View.GONE);
+            mReset.setText(mContext.getString(R.string.do_not_silence));
+        } else {
+            mReset.setText(mContext.getString(R.string.do_not_silence_block));
+        }
+        if (importance == NotificationListenerService.Ranking.IMPORTANCE_LOW) {
+            mSilent.setChecked(true);
+        } else {
+            mReset.setChecked(true);
+        }
+    }
+
+    private void bindSlider(final View importanceSlider, final StatusBarNotification sbn,
+            final boolean systemApp) {
+        final TextView importanceSummary = ((TextView) importanceSlider.findViewById(R.id.summary));
+        final TextView importanceTitle = ((TextView) importanceSlider.findViewById(R.id.title));
+        mSeekBar = (SeekBar) importanceSlider.findViewById(R.id.seekbar);
+
+        if (systemApp) {
+            ((ImageView) importanceSlider.findViewById(R.id.low_importance)).getDrawable().setTint(
                     mContext.getColor(R.color.notification_guts_disabled_icon_tint));
         }
         final int minProgress = systemApp ?
-                NotificationListenerService.Ranking.IMPORTANCE_LOW
+                NotificationListenerService.Ranking.IMPORTANCE_MIN
                 : NotificationListenerService.Ranking.IMPORTANCE_NONE;
         mSeekBar.setMax(NotificationListenerService.Ranking.IMPORTANCE_MAX);
         mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@@ -159,6 +225,11 @@
                                 R.string.notification_importance_blocked));
                         importanceTitle.setText(mContext.getString(R.string.blocked_importance));
                         break;
+                    case NotificationListenerService.Ranking.IMPORTANCE_MIN:
+                        importanceSummary.setText(mContext.getString(
+                                R.string.notification_importance_min));
+                        importanceTitle.setText(mContext.getString(R.string.min_importance));
+                        break;
                     case NotificationListenerService.Ranking.IMPORTANCE_LOW:
                         importanceSummary.setText(mContext.getString(
                                 R.string.notification_importance_low));
@@ -182,18 +253,7 @@
                 }
             }
         });
-        mSeekBar.setProgress(importance);
-    }
-
-    void saveImportance(final StatusBarNotification sbn) {
-        int progress = mSeekBar.getProgress();
-        MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
-                progress - mStartingImportance);
-        try {
-            mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(), progress);
-        } catch (RemoteException e) {
-            // :(
-        }
+        mSeekBar.setProgress(mStartingImportance);
     }
 
     public void setActualHeight(int actualHeight) {
@@ -224,4 +284,11 @@
     public boolean areGutsExposed() {
         return mExposed;
     }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (SHOW_SLIDER.equals(key)) {
+            mShowSlider = newValue != null && Integer.parseInt(newValue) != 0;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
index 4491ebd..a5ebbba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -29,11 +30,18 @@
 
 public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
 
+    private static final int GEAR_ALPHA_ANIM_DURATION = 200;
+
     public interface SettingsIconRowListener {
         /**
          * Called when the gear behind a notification is touched.
          */
-        public void onGearTouched(ExpandableNotificationRow row);
+        public void onGearTouched(ExpandableNotificationRow row, int x, int y);
+
+        /**
+         * Called when a notification is slid back over the gear.
+         */
+        public void onSettingsIconRowReset(ExpandableNotificationRow row);
     }
 
     private ExpandableNotificationRow mParent;
@@ -45,6 +53,10 @@
     private boolean mSettingsFadedIn = false;
     private boolean mAnimating = false;
     private boolean mOnLeft = true;
+    private boolean mDismissing = false;
+    private boolean mSnapping = false;
+    private int[] mGearLocation = new int[2];
+    private int[] mParentLocation = new int[2];
 
     public NotificationSettingsIconRow(Context context) {
         this(context, null);
@@ -74,38 +86,56 @@
         resetState();
     }
 
+    public void resetState() {
+        setGearAlpha(0f);
+        mSettingsFadedIn = false;
+        mAnimating = false;
+        mSnapping = false;
+        mDismissing = false;
+        setIconLocation(true /* on left */, true /* force */);
+        if (mListener != null) {
+            mListener.onSettingsIconRowReset(mParent);
+        }
+    }
+
     public void setGearListener(SettingsIconRowListener listener) {
         mListener = listener;
     }
 
     public void setNotificationRowParent(ExpandableNotificationRow parent) {
         mParent = parent;
+        setIconLocation(mOnLeft, true /* force */);
+    }
+
+    public void setAppName(String appName) {
+        Resources res = getResources();
+        String description = String.format(res.getString(R.string.notification_gear_accessibility),
+                appName);
+        mGearIcon.setContentDescription(description);
     }
 
     public ExpandableNotificationRow getNotificationParent() {
         return mParent;
     }
 
-    public void resetState() {
-        setGearAlpha(0f);
-        mAnimating = false;
-        setIconLocation(true /* on left */);
-    }
-
-    private void setGearAlpha(float alpha) {
+    public void setGearAlpha(float alpha) {
         if (alpha == 0) {
             mSettingsFadedIn = false; // Can fade in again once it's gone.
-            mGearIcon.setVisibility(View.INVISIBLE);
+            setVisibility(View.INVISIBLE);
         } else {
-            if (alpha == 1) {
-                mSettingsFadedIn = true;
-            }
-            mGearIcon.setVisibility(View.VISIBLE);
+            setVisibility(View.VISIBLE);
         }
         mGearIcon.setAlpha(alpha);
     }
 
     /**
+     * Returns whether the icon is on the left side of the view or not.
+     */
+    public boolean isIconOnLeft() {
+        return mOnLeft;
+    }
+
+    /**
      * Returns the horizontal space in pixels required to display the gear behind a notification.
      */
     public float getSpaceForGear() {
@@ -117,7 +147,7 @@
      * if entire view is visible.
      */
     public boolean isVisible() {
-        return mSettingsFadedIn;
+        return mGearIcon.getAlpha() > 0;
     }
 
     public void cancelFadeAnimator() {
@@ -127,16 +157,18 @@
     }
 
     public void updateSettingsIcons(final float transX, final float size) {
-        if (mAnimating || (mGearIcon.getAlpha() == 0)) {
-            // Don't adjust when animating or settings aren't visible
+        if (mAnimating || !mSettingsFadedIn) {
+            // Don't adjust when animating, or if the gear hasn't been shown yet.
             return;
         }
-        setIconLocation(transX > 0 /* fromLeft */);
+
         final float fadeThreshold = size * 0.3f;
         final float absTrans = Math.abs(transX);
         float desiredAlpha = 0;
 
-        if (absTrans <= fadeThreshold) {
+        if (absTrans == 0) {
+            desiredAlpha = 0;
+        } else if (absTrans <= fadeThreshold) {
             desiredAlpha = 1;
         } else {
             desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
@@ -146,7 +178,13 @@
 
     public void fadeInSettings(final boolean fromLeft, final float transX,
             final float notiThreshold) {
-        setIconLocation(transX > 0 /* fromLeft */);
+        if (mDismissing || mAnimating) {
+            return;
+        }
+        if (isIconLocationChange(transX)) {
+            setGearAlpha(0f);
+        }
+        setIconLocation(transX > 0 /* fromLeft */, false /* force */);
         mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
         mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
@@ -162,45 +200,75 @@
         });
         mFadeAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
-            public void onAnimationCancel(Animator animation) {
-                super.onAnimationCancel(animation);
-                mAnimating = false;
-                mSettingsFadedIn = false;
-            }
-
-            @Override
             public void onAnimationStart(Animator animation) {
-                super.onAnimationStart(animation);
                 mAnimating = true;
             }
 
             @Override
+            public void onAnimationCancel(Animator animation) {
+                // TODO should animate back to 0f from current alpha
+                mGearIcon.setAlpha(0f);
+            }
+
+            @Override
             public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
                 mAnimating = false;
-                mSettingsFadedIn = true;
+                mSettingsFadedIn = mGearIcon.getAlpha() == 1;
             }
         });
         mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
-        mFadeAnimator.setDuration(200);
+        mFadeAnimator.setDuration(GEAR_ALPHA_ANIM_DURATION);
         mFadeAnimator.start();
     }
 
-    private void setIconLocation(boolean onLeft) {
-        if (onLeft == mOnLeft) {
-            // Same side? Do nothing.
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        setIconLocation(mOnLeft, true /* force */);
+    }
+
+    public void setIconLocation(boolean onLeft, boolean force) {
+        if ((!force && onLeft == mOnLeft) || mSnapping || mParent == null) {
+            // Do nothing
             return;
         }
-
-        setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
+        final boolean isRtl = mParent.isLayoutRtl();
+        final float left = isRtl ? -(mParent.getWidth() - mHorizSpaceForGear) : 0;
+        final float right = isRtl ? 0 : (mParent.getWidth() - mHorizSpaceForGear);
+        setTranslationX(onLeft ? left : right);
         mOnLeft = onLeft;
     }
 
+    public boolean isIconLocationChange(float translation) {
+        boolean onLeft = translation > mGearIcon.getPaddingStart();
+        boolean onRight = translation < -mGearIcon.getPaddingStart();
+        if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
+            return true;
+        }
+        return false;
+    }
+
+    public void setDismissing() {
+        mDismissing = true;
+    }
+
+    public void setSnapping(boolean snapping) {
+        mSnapping = snapping;
+    }
+
     @Override
     public void onClick(View v) {
         if (v.getId() == R.id.gear_icon) {
             if (mListener != null) {
-                mListener.onGearTouched(mParent);
+                mGearIcon.getLocationOnScreen(mGearLocation);
+                mParent.getLocationOnScreen(mParentLocation);
+
+                final int centerX = (int) (mHorizSpaceForGear / 2);
+                // Top / bottom padding are not equal, need to subtract them to get center of gear.
+                final int centerY = (int) (mGearIcon.getHeight() - mGearIcon.getPaddingTop()
+                        - mGearIcon.getPaddingBottom()) / 2 + mGearIcon.getPaddingTop();
+                final int x = mGearLocation[0] - mParentLocation[0] + centerX;
+                final int y = mGearLocation[1] - mParentLocation[1] + centerY;
+                mListener.onGearTouched(mParent, x, y);
             }
         } else {
             // Do nothing when the background is touched.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index d7e47c2..5fea674 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -21,6 +21,8 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
+import android.util.ArraySet;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
@@ -29,7 +31,8 @@
  */
 public class RemoteInputController {
 
-    private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>();
+    private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
+    private final ArraySet<String> mSpinning = new ArraySet<>();
     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
     private final HeadsUpManager mHeadsUpManager;
 
@@ -44,7 +47,7 @@
         boolean found = pruneWeakThenRemoveAndContains(
                 entry /* contains */, null /* remove */);
         if (!found) {
-            mRemoteInputs.add(new WeakReference<>(entry));
+            mOpen.add(new WeakReference<>(entry));
         }
 
         apply(entry);
@@ -58,6 +61,18 @@
         apply(entry);
     }
 
+    public void addSpinning(String key) {
+        mSpinning.add(key);
+    }
+
+    public void removeSpinning(String key) {
+        mSpinning.remove(key);
+    }
+
+    public boolean isSpinning(String key) {
+        return mSpinning.contains(key);
+    }
+
     private void apply(NotificationData.Entry entry) {
         mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
         boolean remoteInputActive = isRemoteInputActive();
@@ -79,7 +94,7 @@
      */
     public boolean isRemoteInputActive() {
         pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
-        return !mRemoteInputs.isEmpty();
+        return !mOpen.isEmpty();
     }
 
     /**
@@ -91,10 +106,10 @@
     private boolean pruneWeakThenRemoveAndContains(
             NotificationData.Entry contains, NotificationData.Entry remove) {
         boolean found = false;
-        for (int i = mRemoteInputs.size() - 1; i >= 0; i--) {
-            NotificationData.Entry item = mRemoteInputs.get(i).get();
+        for (int i = mOpen.size() - 1; i >= 0; i--) {
+            NotificationData.Entry item = mOpen.get(i).get();
             if (item == null || item == remove) {
-                mRemoteInputs.remove(i);
+                mOpen.remove(i);
             } else if (item == contains) {
                 found = true;
             }
@@ -108,7 +123,16 @@
         mCallbacks.add(callback);
     }
 
+    public void remoteInputSent(NotificationData.Entry entry) {
+        int N = mCallbacks.size();
+        for (int i = 0; i < N; i++) {
+            mCallbacks.get(i).onRemoteInputSent(entry);
+        }
+    }
+
     public interface Callback {
-        void onRemoteInputActive(boolean active);
+        default void onRemoteInputActive(boolean active) {}
+
+        default void onRemoteInputSent(NotificationData.Entry entry) {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 9aa5ea0..988d537 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -23,6 +23,7 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
+import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.telephony.SubscriptionInfo;
 import android.util.ArraySet;
@@ -90,6 +91,8 @@
     View mWifiSignalSpacer;
     LinearLayout mMobileSignalGroup;
 
+    private final int mMobileSignalGroupEndPadding;
+    private final int mMobileDataIconStartPadding;
     private final int mWideTypeIconStartPadding;
     private final int mSecondaryTelephonyPadding;
     private final int mEndPadding;
@@ -113,6 +116,10 @@
         super(context, attrs, defStyle);
 
         Resources res = getResources();
+        mMobileSignalGroupEndPadding =
+                res.getDimensionPixelSize(R.dimen.mobile_signal_group_end_padding);
+        mMobileDataIconStartPadding =
+                res.getDimensionPixelSize(R.dimen.mobile_data_icon_start_padding);
         mWideTypeIconStartPadding = res.getDimensionPixelSize(R.dimen.wide_type_icon_start_padding);
         mSecondaryTelephonyPadding = res.getDimensionPixelSize(R.dimen.secondary_telephony_padding);
         mEndPadding = res.getDimensionPixelSize(R.dimen.signal_cluster_battery_padding);
@@ -206,16 +213,23 @@
         for (PhoneState state : mPhoneStates) {
             mMobileSignalGroup.addView(state.mMobileGroup);
         }
+
+        int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
+        mMobileSignalGroup.setPaddingRelative(0, 0, endPadding, 0);
+
         TunerService.get(mContext).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
 
         apply();
         applyIconTint();
+        mNC.addSignalCallback(this);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         mMobileSignalGroup.removeAllViews();
         TunerService.get(mContext).removeTunable(this);
+        mSC.removeCallback(this);
+        mNC.removeSignalCallback(this);
 
         super.onDetachedFromWindow();
     }
@@ -577,9 +591,11 @@
             // When this isn't next to wifi, give it some extra padding between the signals.
             mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,
                     0, 0, 0);
-            mMobile.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
+            mMobile.setPaddingRelative(
+                    mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
                     0, 0, 0);
-            mMobileDark.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
+            mMobileDark.setPaddingRelative(
+                    mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
                     0, 0, 0);
 
             if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
@@ -592,12 +608,19 @@
 
         private void updateAnimatableIcon(ImageView view, int resId) {
             maybeStopAnimatableDrawable(view);
-            view.setImageResource(resId);
+            setIconForView(view, resId);
             maybeStartAnimatableDrawable(view);
         }
 
         private void maybeStopAnimatableDrawable(ImageView view) {
             Drawable drawable = view.getDrawable();
+
+            // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
+            // wrapper.
+            if (drawable instanceof ScalingDrawableWrapper) {
+                drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
+            }
+
             if (drawable instanceof Animatable) {
                 Animatable ad = (Animatable) drawable;
                 if (ad.isRunning()) {
@@ -608,8 +631,18 @@
 
         private void maybeStartAnimatableDrawable(ImageView view) {
             Drawable drawable = view.getDrawable();
+
+            // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
+            // wrapper.
+            if (drawable instanceof ScalingDrawableWrapper) {
+                drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
+            }
+
             if (drawable instanceof Animatable) {
                 Animatable ad = (Animatable) drawable;
+                if (ad instanceof AnimatedVectorDrawable) {
+                    ((AnimatedVectorDrawable) ad).forceAnimationOnUI();
+                }
                 if (!ad.isRunning()) {
                     ad.start();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
index 7e7fc3a..c0148c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
@@ -41,4 +41,20 @@
      * Status bar is locked and shows the full screen user switcher.
      */
     public static final int FULLSCREEN_USER_SWITCHER = 3;
+
+
+    public static String toShortString(int x) {
+        switch (x) {
+            case SHADE:
+                return "SHD";
+            case SHADE_LOCKED:
+                return "SHD_LCK";
+            case KEYGUARD:
+                return "KGRD";
+            case FULLSCREEN_USER_SWITCHER:
+                return "FS_USRSW";
+            default:
+                return "bad_value_" + x;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
index 38b6497..dd7c4c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
@@ -27,9 +27,11 @@
     int TRANSFORMING_VIEW_TEXT = 2;
     int TRANSFORMING_VIEW_IMAGE = 3;
     int TRANSFORMING_VIEW_PROGRESS = 4;
+    int TRANSFORMING_VIEW_ACTIONS = 5;
 
     /**
      * Get the current state of a view in a transform animation
+     *
      * @param fadingView which view we are interested in
      * @return the current transform state of this viewtype
      */
@@ -37,18 +39,37 @@
 
     /**
      * Transform to the given view
+     *
      * @param notification the view to transform to
      */
     void transformTo(TransformableView notification, Runnable endRunnable);
 
     /**
+     * Transform to the given view by a specified amount.
+     *
+     * @param notification the view to transform to
+     * @param transformationAmount how much transformation should be done
+     */
+    void transformTo(TransformableView notification, float transformationAmount);
+
+    /**
      * Transform to this view from the given view
+     *
      * @param notification the view to transform from
      */
     void transformFrom(TransformableView notification);
 
     /**
+     * Transform to this view from the given view by a specified amount.
+     *
+     * @param notification the view to transform from
+     * @param transformationAmount how much transformation should be done
+     */
+    void transformFrom(TransformableView notification, float transformationAmount);
+
+    /**
      * Set this view to be fully visible or gone
+     *
      * @param visible
      */
     void setVisible(boolean visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 63ff5aa..f75f3574 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -16,13 +16,17 @@
 
 package com.android.systemui.statusbar;
 
-import android.os.Handler;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.util.ArrayMap;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.TransformState;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 import java.util.Stack;
 
@@ -33,9 +37,9 @@
 
     private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view;
 
-    private final Handler mHandler = new Handler();
     private ArrayMap<Integer, View> mTransformedViews = new ArrayMap<>();
     private ArrayMap<Integer, CustomTransformation> mCustomTransformations = new ArrayMap<>();
+    private ValueAnimator mViewTransformationAnimation;
 
     public void addTransformedView(int key, View transformedView) {
         mTransformedViews.put(key, transformedView);
@@ -59,61 +63,123 @@
     }
 
     @Override
-    public void transformTo(TransformableView notification, Runnable endRunnable) {
-        Runnable runnable = endRunnable;
+    public void transformTo(final TransformableView notification, final Runnable endRunnable) {
+        if (mViewTransformationAnimation != null) {
+            mViewTransformationAnimation.cancel();
+        }
+        mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
+        mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                transformTo(notification, animation.getAnimatedFraction());
+            }
+        });
+        mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
+        mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
+            public boolean mCancelled;
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!mCancelled) {
+                    if (endRunnable != null) {
+                        endRunnable.run();
+                    }
+                    setVisible(false);
+                } else {
+                    abortTransformations();
+                }
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+        });
+        mViewTransformationAnimation.start();
+    }
+
+    @Override
+    public void transformTo(TransformableView notification, float transformationAmount) {
         for (Integer viewType : mTransformedViews.keySet()) {
             TransformState ownState = getCurrentState(viewType);
             if (ownState != null) {
                 CustomTransformation customTransformation = mCustomTransformations.get(viewType);
                 if (customTransformation != null && customTransformation.transformTo(
-                        ownState, notification, runnable)) {
+                        ownState, notification, transformationAmount)) {
                     ownState.recycle();
-                    runnable = null;
                     continue;
                 }
                 TransformState otherState = notification.getCurrentState(viewType);
                 if (otherState != null) {
-                    boolean run = ownState.transformViewTo(otherState, runnable);
+                    ownState.transformViewTo(otherState, transformationAmount);
                     otherState.recycle();
-                    if (run) {
-                        runnable = null;
-                    }
                 } else {
                     // there's no other view available
-                    CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), runnable);
-                    runnable = null;
+                    CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount);
                 }
                 ownState.recycle();
             }
         }
-        if (runnable != null) {
-            // We need to post, since the visible type is only set after the transformation is
-            // started
-            mHandler.post(runnable);
-        }
     }
 
     @Override
-    public void transformFrom(TransformableView notification) {
+    public void transformFrom(final TransformableView notification) {
+        if (mViewTransformationAnimation != null) {
+            mViewTransformationAnimation.cancel();
+        }
+        mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
+        mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                transformFrom(notification, animation.getAnimatedFraction());
+            }
+        });
+        mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
+            public boolean mCancelled;
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!mCancelled) {
+                    setVisible(true);
+                } else {
+                    abortTransformations();
+                }
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+        });
+        mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
+        mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        mViewTransformationAnimation.start();
+    }
+
+    @Override
+    public void transformFrom(TransformableView notification, float transformationAmount) {
         for (Integer viewType : mTransformedViews.keySet()) {
             TransformState ownState = getCurrentState(viewType);
             if (ownState != null) {
                 CustomTransformation customTransformation = mCustomTransformations.get(viewType);
                 if (customTransformation != null && customTransformation.transformFrom(
-                        ownState, notification)) {
+                        ownState, notification, transformationAmount)) {
                     ownState.recycle();
                     continue;
                 }
                 TransformState otherState = notification.getCurrentState(viewType);
                 if (otherState != null) {
-                    ownState.transformViewFrom(otherState);
+                    ownState.transformViewFrom(otherState, transformationAmount);
                     otherState.recycle();
                 } else {
                     // There's no other view, lets fade us in
                     // Certain views need to prepare the fade in and make sure its children are
                     // completely visible. An example is the notification header.
-                    ownState.prepareFadeIn();
-                    CrossFadeHelper.fadeIn(mTransformedViews.get(viewType));
+                    if (transformationAmount == 0.0f) {
+                        ownState.prepareFadeIn();
+                    }
+                    CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount);
                 }
                 ownState.recycle();
             }
@@ -122,6 +188,9 @@
 
     @Override
     public void setVisible(boolean visible) {
+        if (mViewTransformationAnimation != null) {
+            mViewTransformationAnimation.cancel();
+        }
         for (Integer viewType : mTransformedViews.keySet()) {
             TransformState ownState = getCurrentState(viewType);
             if (ownState != null) {
@@ -131,6 +200,16 @@
         }
     }
 
+    private void abortTransformations() {
+        for (Integer viewType : mTransformedViews.keySet()) {
+            TransformState ownState = getCurrentState(viewType);
+            if (ownState != null) {
+                ownState.abortTransformation();
+                ownState.recycle();
+            }
+        }
+    }
+
     /**
      * Add the remaining transformation views such that all views are being transformed correctly
      * @param viewRoot the root below which all elements need to be transformed
@@ -173,22 +252,44 @@
         }
     }
 
-    public interface CustomTransformation {
+    public static abstract class CustomTransformation {
         /**
          * Transform a state to the given view
          * @param ownState the state to transform
          * @param notification the view to transform to
+         * @param transformationAmount how much transformation should be done
          * @return whether a custom transformation is performed
          */
-        boolean transformTo(TransformState ownState, TransformableView notification,
-                Runnable endRunnable);
+        public abstract boolean transformTo(TransformState ownState,
+                TransformableView notification,
+                float transformationAmount);
 
         /**
          * Transform to this state from the given view
          * @param ownState the state to transform to
          * @param notification the view to transform from
+         * @param transformationAmount how much transformation should be done
          * @return whether a custom transformation is performed
          */
-        boolean transformFrom(TransformState ownState, TransformableView notification);
+        public abstract boolean transformFrom(TransformState ownState,
+                TransformableView notification,
+                float transformationAmount);
+
+        /**
+         * Perform a custom initialisation before transforming.
+         *
+         * @param ownState our own state
+         * @param otherState the other state
+         * @return whether a custom initialization is done
+         */
+        public boolean initTransformation(TransformState ownState,
+                TransformState otherState) {
+            return false;
+        }
+
+        public boolean customTransformTarget(TransformState ownState,
+                TransformState otherState) {
+            return false;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index 8a93c5b..d9bf539 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -71,7 +71,6 @@
     private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
 
     private int mCurrentFacetIndex;
-    private String mCurrentPackageName;
     private SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
 
     public CarNavigationBarController(Context context,
@@ -84,7 +83,6 @@
     }
 
     public void taskChanged(String packageName) {
-        mCurrentPackageName = packageName;
         // If the package name belongs to a filter, then highlight appropriate button in
         // the navigation bar.
         if (mFacetPackageMap.containsKey(packageName)) {
@@ -108,7 +106,7 @@
 
         String category = getPackageCategory(packageName);
         if (mFacetCategoryMap.containsKey(category)) {
-            int index = mFacetCategoryMap.get(packageName);
+            int index = mFacetCategoryMap.get(category);
             mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
         }
     }
@@ -298,12 +296,6 @@
             return;
         }
 
-        // Don't launch the lens picker if it's already running and the
-        // user clicks the same facet
-        if (packageName.equals(mCurrentPackageName) && index == mCurrentFacetIndex) {
-            return;
-        }
-
         intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories.get(index));
         intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages.get(index));
         // The facet is identified by the index in which it was added to the nav bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index c32ef0e..4add3cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.car;
 
 import android.app.ActivityManager;
-import android.app.ITaskStackListener;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -25,6 +24,7 @@
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewStub;
@@ -33,6 +33,7 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
@@ -40,9 +41,7 @@
  * A status bar (and navigation bar) tailored for the automotive use case.
  */
 public class CarStatusBar extends PhoneStatusBar {
-    private SystemServicesProxy mSystemServicesProxy;
     private TaskStackListenerImpl mTaskStackListener;
-    private Handler mHandler;
 
     private CarNavigationBarView mCarNavigationBar;
     private CarNavigationBarController mController;
@@ -51,10 +50,8 @@
     @Override
     public void start() {
         super.start();
-        mHandler = new Handler();
-        mTaskStackListener = new TaskStackListenerImpl(mHandler);
-        mSystemServicesProxy = new SystemServicesProxy(mContext);
-        mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+        mTaskStackListener = new TaskStackListenerImpl();
+        SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
         registerPackageChangeReceivers();
     }
 
@@ -114,47 +111,16 @@
     }
 
     /**
-     * An implementation of ITaskStackListener, that listens for changes in the system task
+     * An implementation of TaskStackListener, that listens for changes in the system task
      * stack and notifies the navigation bar.
      */
-    private class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
-        private Handler mHandler;
-
-        public TaskStackListenerImpl(Handler handler) {
-            this.mHandler = handler;
-        }
-
-        @Override
-        public void onActivityPinned() {
-        }
-
-        @Override
-        public void onPinnedActivityRestartAttempt() {
-        }
-
-        @Override
-        public void onPinnedStackAnimationEnded() {
-        }
-
+    private class TaskStackListenerImpl extends TaskStackListener {
         @Override
         public void onTaskStackChanged() {
-            mHandler.removeCallbacks(this);
-            mHandler.post(this);
-        }
-
-        @Override
-        public void run() {
-            ensureMainThread();
             SystemServicesProxy ssp = Recents.getSystemServices();
             ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
             mController.taskChanged(runningTaskInfo.baseActivity.getPackageName());
         }
-
-        private void ensureMainThread() {
-            if (!Looper.getMainLooper().isCurrentThread()) {
-                throw new RuntimeException("Must be called on the UI thread");
-            }
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/FakeShadowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/FakeShadowView.java
new file mode 100644
index 0000000..32c26ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/FakeShadowView.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.notification;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Outline;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.widget.LinearLayout;
+
+import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
+
+/**
+ * A view used to cast a shadow of a certain size on another view
+ */
+public class FakeShadowView extends AlphaOptimizedFrameLayout {
+    public static final float SHADOW_SIBLING_TRESHOLD = 0.1f;
+
+    private View mFakeShadow;
+    private float mOutlineAlpha;
+
+    public FakeShadowView(Context context) {
+        this(context, null);
+    }
+
+    public FakeShadowView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FakeShadowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public FakeShadowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mFakeShadow = new View(context);
+        mFakeShadow.setVisibility(INVISIBLE);
+        mFakeShadow.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                (int) (48 * getResources().getDisplayMetrics().density)));
+        mFakeShadow.setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRect(0, 0, getWidth(), mFakeShadow.getHeight());
+                outline.setAlpha(mOutlineAlpha);
+            }
+        });
+        addView(mFakeShadow);
+    }
+
+    public void setFakeShadowTranslationZ(float fakeShadowTranslationZ, float outlineAlpha,
+            int shadowYEnd, int outlineTranslation) {
+        if (fakeShadowTranslationZ == 0.0f) {
+            mFakeShadow.setVisibility(INVISIBLE);
+        } else {
+            mFakeShadow.setVisibility(VISIBLE);
+            mFakeShadow.setTranslationZ(fakeShadowTranslationZ);
+            mFakeShadow.setTranslationX(outlineTranslation);
+            mFakeShadow.setTranslationY(shadowYEnd - mFakeShadow.getHeight());
+            if (outlineAlpha != mOutlineAlpha) {
+                mOutlineAlpha = outlineAlpha;
+                mFakeShadow.invalidateOutline();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
index 81483c6..b66e9f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public boolean transformViewTo(TransformState otherState, Runnable endRunnable) {
+    public boolean transformViewTo(TransformState otherState, float transformationAmount) {
         // if the transforming notification has a header, we have ensured that it looks the same
         // but the expand button, so lets fade just that one and transform the work profile icon.
         if (!(mTransformedView instanceof NotificationHeaderView)) {
@@ -62,14 +62,14 @@
             if (headerChild != mExpandButton) {
                 headerChild.setVisibility(View.INVISIBLE);
             } else {
-                CrossFadeHelper.fadeOut(mExpandButton, endRunnable);
+                CrossFadeHelper.fadeOut(mExpandButton, transformationAmount);
             }
         }
         return true;
     }
 
     @Override
-    public void transformViewFrom(TransformState otherState) {
+    public void transformViewFrom(TransformState otherState, float transformationAmount) {
         // if the transforming notification has a header, we have ensured that it looks the same
         // but the expand button, so lets fade just that one and transform the work profile icon.
         if (!(mTransformedView instanceof NotificationHeaderView)) {
@@ -85,12 +85,13 @@
                 continue;
             }
             if (headerChild == mExpandButton) {
-                CrossFadeHelper.fadeIn(mExpandButton);
+                CrossFadeHelper.fadeIn(mExpandButton, transformationAmount);
             } else {
                 headerChild.setVisibility(View.VISIBLE);
                 if (headerChild == mWorkProfileIcon) {
-                    mWorkProfileState.animateViewFrom(
-                            ((HeaderTransformState) otherState).mWorkProfileState);
+                    mWorkProfileState.transformViewFullyFrom(
+                            ((HeaderTransformState) otherState).mWorkProfileState,
+                            transformationAmount);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
new file mode 100644
index 0000000..8f2c81f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.text.BidiFormatter;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+
+import java.util.List;
+
+/**
+ * A class managing hybrid groups that include {@link HybridNotificationView} and the notification
+ * group overflow.
+ */
+public class HybridGroupManager {
+
+    private final Context mContext;
+    private ViewGroup mParent;
+    private int mOverflowNumberColor;
+
+    public HybridGroupManager(Context ctx, ViewGroup parent) {
+        mContext = ctx;
+        mParent = parent;
+    }
+
+    private HybridNotificationView inflateHybridView() {
+        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+        HybridNotificationView hybrid = (HybridNotificationView) inflater.inflate(
+                R.layout.hybrid_notification, mParent, false);
+        mParent.addView(hybrid);
+        return hybrid;
+    }
+
+    private TextView inflateOverflowNumber() {
+        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+        TextView numberView = (TextView) inflater.inflate(
+                R.layout.hybrid_overflow_number, mParent, false);
+        mParent.addView(numberView);
+        updateOverFlowNumberColor(numberView);
+        return numberView;
+    }
+
+    private void updateOverFlowNumberColor(TextView numberView) {
+        numberView.setTextColor(mOverflowNumberColor);
+    }
+
+    public void setOverflowNumberColor(TextView numberView, int overflowNumberColor) {
+        mOverflowNumberColor = overflowNumberColor;
+        if (numberView != null) {
+            updateOverFlowNumberColor(numberView);
+        }
+    }
+
+    public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
+            Notification notification) {
+        if (reusableView == null) {
+            reusableView = inflateHybridView();
+        }
+        CharSequence titleText = resolveTitle(notification);
+        CharSequence contentText = resolveText(notification);
+        reusableView.bind(titleText, contentText);
+        return reusableView;
+    }
+
+    private CharSequence resolveText(Notification notification) {
+        CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
+        if (contentText == null) {
+            contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
+        }
+        return contentText;
+    }
+
+    private CharSequence resolveTitle(Notification notification) {
+        CharSequence titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
+        if (titleText == null) {
+            titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
+        }
+        return titleText;
+    }
+
+    public TextView bindOverflowNumber(TextView reusableView, int number) {
+        if (reusableView == null) {
+            reusableView = inflateOverflowNumber();
+        }
+        String text = mContext.getResources().getString(
+                R.string.notification_group_overflow_indicator, number);
+        if (!text.equals(reusableView.getText())) {
+            reusableView.setText(text);
+        }
+        return reusableView;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
index 81144d5..0a1795f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -60,6 +60,14 @@
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
+    public TextView getTitleView() {
+        return mTitleView;
+    }
+
+    public TextView getTextView() {
+        return mTextView;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -71,13 +79,13 @@
                 new ViewTransformationHelper.CustomTransformation() {
                     @Override
                     public boolean transformTo(TransformState ownState, TransformableView notification,
-                            Runnable endRunnable) {
+                            float transformationAmount) {
                         // We want to transform to the same y location as the title
                         TransformState otherState = notification.getCurrentState(
                                 TRANSFORMING_VIEW_TITLE);
-                        CrossFadeHelper.fadeOut(mTextView, endRunnable);
+                        CrossFadeHelper.fadeOut(mTextView, transformationAmount);
                         if (otherState != null) {
-                            ownState.animateViewVerticalTo(otherState, endRunnable);
+                            ownState.transformViewVerticalTo(otherState, transformationAmount);
                             otherState.recycle();
                         }
                         return true;
@@ -85,13 +93,13 @@
 
                     @Override
                     public boolean transformFrom(TransformState ownState,
-                            TransformableView notification) {
+                            TransformableView notification, float transformationAmount) {
                         // We want to transform from the same y location as the title
                         TransformState otherState = notification.getCurrentState(
                                 TRANSFORMING_VIEW_TITLE);
-                        CrossFadeHelper.fadeIn(mTextView);
+                        CrossFadeHelper.fadeIn(mTextView, transformationAmount);
                         if (otherState != null) {
-                            ownState.animateViewVerticalFrom(otherState);
+                            ownState.transformViewVerticalFrom(otherState, transformationAmount);
                             otherState.recycle();
                         }
                         return true;
@@ -133,11 +141,21 @@
     }
 
     @Override
+    public void transformTo(TransformableView notification, float transformationAmount) {
+        mTransformationHelper.transformTo(notification, transformationAmount);
+    }
+
+    @Override
     public void transformFrom(TransformableView notification) {
         mTransformationHelper.transformFrom(notification);
     }
 
     @Override
+    public void transformFrom(TransformableView notification, float transformationAmount) {
+        mTransformationHelper.transformFrom(notification, transformationAmount);
+    }
+
+    @Override
     public void setVisible(boolean visible) {
         setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
         mTransformationHelper.setVisible(visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
deleted file mode 100644
index 28bb66f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import android.app.Notification;
-import android.content.Context;
-import android.text.BidiFormatter;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
-import android.text.style.TextAppearanceSpan;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
-
-import java.util.List;
-
-/**
- * A class managing {@link HybridNotificationView} views
- */
-public class HybridNotificationViewManager {
-
-    private final Context mContext;
-    private ViewGroup mParent;
-    private String mDivider;
-
-    public HybridNotificationViewManager(Context ctx, ViewGroup parent) {
-        mContext = ctx;
-        mParent = parent;
-        mDivider = " • ";
-    }
-
-    private HybridNotificationView inflateHybridView() {
-        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
-        HybridNotificationView hybrid = (HybridNotificationView) inflater.inflate(
-                R.layout.hybrid_notification, mParent, false);
-        mParent.addView(hybrid);
-        return hybrid;
-    }
-
-    public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
-            Notification notification) {
-        if (reusableView == null) {
-            reusableView = inflateHybridView();
-        }
-        CharSequence titleText = resolveTitle(notification);
-        CharSequence contentText = resolveText(notification);
-        reusableView.bind(titleText, contentText);
-        return reusableView;
-    }
-
-    private CharSequence resolveText(Notification notification) {
-        CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
-        if (contentText == null) {
-            contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
-        }
-        return contentText;
-    }
-
-    private CharSequence resolveTitle(Notification notification) {
-        CharSequence titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
-        if (titleText == null) {
-            titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
-        }
-        return titleText;
-    }
-
-    public HybridNotificationView bindFromNotificationGroup(
-            HybridNotificationView reusableView,
-            List<ExpandableNotificationRow> group, int startIndex) {
-        if (reusableView == null) {
-            reusableView = inflateHybridView();
-        }
-        SpannableStringBuilder summary = new SpannableStringBuilder();
-        int childCount = group.size();
-        for (int i = startIndex; i < childCount; i++) {
-            ExpandableNotificationRow child = group.get(i);
-            CharSequence titleText = resolveTitle(
-                    child.getStatusBarNotification().getNotification());
-            if (titleText == null) {
-                continue;
-            }
-            if (!TextUtils.isEmpty(summary)) {
-                summary.append(mDivider,
-                        new TextAppearanceSpan(mContext, R.style.
-                                TextAppearance_Material_Notification_HybridNotificationDivider),
-                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            }
-            summary.append(BidiFormatter.getInstance().unicodeWrap(titleText));
-        }
-        // We want to force the same orientation as the layout RTL mode
-        BidiFormatter formater = BidiFormatter.getInstance(
-                reusableView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
-        reusableView.bind(formater.unicodeWrap(summary));
-        return reusableView;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index e891a97..45027c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -62,7 +62,7 @@
     }
 
     @Override
-    protected boolean animateScale() {
+    protected boolean transformScale() {
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index aa001ed..49e4ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -16,8 +16,19 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.support.v4.graphics.ColorUtils;
 import android.view.View;
 
+import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 
@@ -27,6 +38,11 @@
 public class NotificationCustomViewWrapper extends NotificationViewWrapper {
 
     private final ViewInvertHelper mInvertHelper;
+    private final Paint mGreyPaint = new Paint();
+    private int mBackgroundColor = 0;
+    private static final int CUSTOM_BACKGROUND_TAG = R.id.custom_background_color;
+    private boolean mShouldInvertDark;
+    private boolean mShowingLegacyBackground;
 
     protected NotificationCustomViewWrapper(View view) {
         super(view);
@@ -35,14 +51,50 @@
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
-        if (dark == mDark) {
+        if (dark == mDark && mDarkInitialized) {
             return;
         }
         super.setDark(dark, fade, delay);
-        if (fade) {
-            mInvertHelper.fade(dark, delay);
+        if (!mShowingLegacyBackground && mShouldInvertDark) {
+            if (fade) {
+                mInvertHelper.fade(dark, delay);
+            } else {
+                mInvertHelper.update(dark);
+            }
         } else {
-            mInvertHelper.update(dark);
+            mView.setLayerType(dark ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
+            if (fade) {
+                fadeGrayscale(dark, delay);
+            } else {
+                updateGrayscale(dark);
+            }
+        }
+    }
+
+    protected void fadeGrayscale(final boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateGrayscaleMatrix((float) animation.getAnimatedValue());
+                mGreyPaint.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+                mView.setLayerPaint(mGreyPaint);
+            }
+        }, dark, delay, new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!dark) {
+                    mView.setLayerType(View.LAYER_TYPE_NONE, null);
+                }
+            }
+        });
+    }
+
+    protected void updateGrayscale(boolean dark) {
+        if (dark) {
+            updateGrayscaleMatrix(1f);
+            mGreyPaint.setColorFilter(
+                    new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+            mView.setLayerPaint(mGreyPaint);
         }
     }
 
@@ -51,4 +103,35 @@
         super.setVisible(visible);
         mView.setAlpha(visible ? 1.0f : 0.0f);
     }
+
+    @Override
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        super.notifyContentUpdated(notification);
+        Drawable background = mView.getBackground();
+        mBackgroundColor = 0;
+        if (background instanceof ColorDrawable) {
+            mBackgroundColor = ((ColorDrawable) background).getColor();
+            mView.setBackground(null);
+            mView.setTag(CUSTOM_BACKGROUND_TAG, mBackgroundColor);
+        } else if (mView.getTag(CUSTOM_BACKGROUND_TAG) != null) {
+            mBackgroundColor = (int) mView.getTag(CUSTOM_BACKGROUND_TAG);
+        }
+        mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
+    }
+
+    private boolean isColorLight(int backgroundColor) {
+        return Color.alpha(backgroundColor) == 0
+                || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
+    }
+
+    @Override
+    public int getCustomBackgroundColor() {
+        return mBackgroundColor;
+    }
+
+    @Override
+    public void setShowingLegacyBackground(boolean showing) {
+        super.setShowingLegacyBackground(showing);
+        mShowingLegacyBackground = showing;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 5a71caf..b201d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -47,7 +47,6 @@
  */
 public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
 
-    private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
     private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
             0, PorterDuff.Mode.SRC_ATOP);
     private final int mIconDarkAlpha;
@@ -142,12 +141,13 @@
 
     protected void updateTransformedTypes() {
         mTransformationHelper.reset();
-        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER, mNotificationHeader);
+        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER,
+                mNotificationHeader);
     }
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
-        if (dark == mDark) {
+        if (dark == mDark && mDarkInitialized) {
             return;
         }
         super.setDark(dark, fade, delay);
@@ -177,21 +177,6 @@
         }
     }
 
-    protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
-            boolean dark, long delay, Animator.AnimatorListener listener) {
-        float startIntensity = dark ? 0f : 1f;
-        float endIntensity = dark ? 1f : 0f;
-        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
-        animator.addUpdateListener(updateListener);
-        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
-        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-        animator.setStartDelay(delay);
-        if (listener != null) {
-            animator.addListener(listener);
-        }
-        animator.start();
-    }
-
     private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
         startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
             @Override
@@ -263,10 +248,6 @@
         mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
     }
 
-    private void updateGrayscaleMatrix(float intensity) {
-        mGrayscaleColorMatrix.setSaturation(1 - intensity);
-    }
-
     private static int interpolateColor(int source, int target, float t) {
         int aSource = Color.alpha(source);
         int rSource = Color.red(source);
@@ -299,11 +280,21 @@
     }
 
     @Override
+    public void transformTo(TransformableView notification, float transformationAmount) {
+        mTransformationHelper.transformTo(notification, transformationAmount);
+    }
+
+    @Override
     public void transformFrom(TransformableView notification) {
         mTransformationHelper.transformFrom(notification);
     }
 
     @Override
+    public void transformFrom(TransformableView notification, float transformationAmount) {
+        mTransformationHelper.transformFrom(notification, transformationAmount);
+    }
+
+    @Override
     public void setVisible(boolean visible) {
         super.setVisible(visible);
         mTransformationHelper.setVisible(visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
new file mode 100644
index 0000000..30698e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.notification;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+
+import com.android.systemui.statusbar.TransformableView;
+
+/**
+ * Wraps a notification containing a media template
+ */
+public class NotificationMediaTemplateViewWrapper extends NotificationTemplateViewWrapper {
+
+    protected NotificationMediaTemplateViewWrapper(Context ctx, View view) {
+        super(ctx, view);
+    }
+
+    View mActions;
+
+    private void resolveViews(StatusBarNotification notification) {
+        mActions = mView.findViewById(com.android.internal.R.id.media_actions);
+    }
+
+    @Override
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        // Reinspect the notification. Before the super call, because the super call also updates
+        // the transformation types and we need to have our values set by then.
+        resolveViews(notification);
+        super.notifyContentUpdated(notification);
+    }
+
+    @Override
+    protected void updateTransformedTypes() {
+        // This also clears the existing types
+        super.updateTransformedTypes();
+        if (mActions != null) {
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
+                    mActions);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 0c21f0b..78e23fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -49,76 +49,65 @@
                 new ViewTransformationHelper.CustomTransformation() {
                     @Override
                     public boolean transformTo(TransformState ownState,
-                            TransformableView notification, final Runnable endRunnable) {
+                            TransformableView notification, final float transformationAmount) {
                         if (!(notification instanceof HybridNotificationView)) {
                             return false;
                         }
                         TransformState otherState = notification.getCurrentState(
                                 TRANSFORMING_VIEW_TITLE);
                         final View text = ownState.getTransformedView();
-                        CrossFadeHelper.fadeOut(text, endRunnable);
+                        CrossFadeHelper.fadeOut(text, transformationAmount);
                         if (otherState != null) {
-                            int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
-                            int[] ownPosition = ownState.getLaidOutLocationOnScreen();
-                            text.animate()
-                                    .translationY((otherStablePosition[1]
-                                            + otherState.getTransformedView().getHeight()
-                                            - ownPosition[1]) * 0.33f)
-                                    .setDuration(
-                                            StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                                    .withEndAction(new Runnable() {
-                                        @Override
-                                        public void run() {
-                                            if (endRunnable != null) {
-                                                endRunnable.run();
-                                            }
-                                            TransformState.setClippingDeactivated(text,
-                                                    false);
-                                        }
-                                    });
-                            TransformState.setClippingDeactivated(text, true);
+                            ownState.transformViewVerticalTo(otherState, this,
+                                    transformationAmount);
                             otherState.recycle();
                         }
                         return true;
                     }
 
                     @Override
+                    public boolean customTransformTarget(TransformState ownState,
+                            TransformState otherState) {
+                        float endY = getTransformationY(ownState, otherState);
+                        ownState.setTransformationEndY(endY);
+                        return true;
+                    }
+
+                    @Override
                     public boolean transformFrom(TransformState ownState,
-                            TransformableView notification) {
+                            TransformableView notification, float transformationAmount) {
                         if (!(notification instanceof HybridNotificationView)) {
                             return false;
                         }
                         TransformState otherState = notification.getCurrentState(
                                 TRANSFORMING_VIEW_TITLE);
                         final View text = ownState.getTransformedView();
-                        boolean isVisible = text.getVisibility() == View.VISIBLE;
-                        CrossFadeHelper.fadeIn(text);
+                        CrossFadeHelper.fadeIn(text, transformationAmount);
                         if (otherState != null) {
-                            int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
-                            int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
-                            if (!isVisible) {
-                                text.setTranslationY((otherStablePosition[1]
-                                        + otherState.getTransformedView().getHeight()
-                                        - ownStablePosition[1]) * 0.33f);
-                            }
-                            text.animate()
-                                    .translationY(0)
-                                    .setDuration(
-                                            StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                                    .withEndAction(new Runnable() {
-                                        @Override
-                                        public void run() {
-                                            TransformState.setClippingDeactivated(text,
-                                                    false);
-                                        }
-                                    });
-                            TransformState.setClippingDeactivated(text, true);
+                            ownState.transformViewVerticalFrom(otherState, this,
+                                    transformationAmount);
                             otherState.recycle();
                         }
                         return true;
                     }
+
+                    @Override
+                    public boolean initTransformation(TransformState ownState,
+                            TransformState otherState) {
+                        float startY = getTransformationY(ownState, otherState);
+                        ownState.setTransformationStartY(startY);
+                        return true;
+                    }
+
+                    private float getTransformationY(TransformState ownState,
+                            TransformState otherState) {
+                        int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
+                        int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
+                        return (otherStablePosition[1]
+                                + otherState.getTransformedView().getHeight()
+                                - ownStablePosition[1]) * 0.33f;
+                    }
+
                 }, TRANSFORMING_VIEW_TEXT);
     }
 
@@ -174,7 +163,7 @@
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
-        if (dark == mDark) {
+        if (dark == mDark && mDarkInitialized) {
             return;
         }
         super.setDark(dark, fade, delay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 7089b78..844a2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,15 +16,20 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.graphics.Color;
+import android.view.View;
 import android.widget.ImageView;
 
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
 
 /**
  * A util class for various reusable functions
  */
 public class NotificationUtils {
+    private static final int[] sLocationBase = new int[2];
+    private static final int[] sLocationOffset = new int[2];
     public static boolean isGrayscale(ImageView v, NotificationColorUtil colorUtil) {
         Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
         if (isGrayscale != null) {
@@ -34,4 +39,22 @@
         v.setTag(R.id.icon_is_grayscale, grayscale);
         return grayscale;
     }
+
+    public static float interpolate(float start, float end, float amount) {
+        return start * (1.0f - amount) + end * amount;
+    }
+
+    public static int interpolateColors(int startColor, int endColor, float amount) {
+        return Color.argb(
+                (int) interpolate(Color.alpha(startColor), Color.alpha(endColor), amount),
+                (int) interpolate(Color.red(startColor), Color.red(endColor), amount),
+                (int) interpolate(Color.green(startColor), Color.green(endColor), amount),
+                (int) interpolate(Color.blue(startColor), Color.blue(endColor), amount));
+    }
+
+    public static float getRelativeYOffset(View offsetView, View baseView) {
+        baseView.getLocationOnScreen(sLocationBase);
+        offsetView.getLocationOnScreen(sLocationOffset);
+        return sLocationOffset[1] - sLocationBase[1];
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 328f8b5..ebff69d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -16,13 +16,19 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.animation.Animator;
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.graphics.ColorMatrix;
 import android.service.notification.StatusBarNotification;
 import android.view.NotificationHeaderView;
 import android.view.View;
 
+import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.NotificationContentView;
 import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 /**
  * Wraps the actual notification content view; used to implement behaviors which are different for
@@ -30,8 +36,10 @@
  */
 public abstract class NotificationViewWrapper implements TransformableView {
 
+    protected final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
     protected final View mView;
     protected boolean mDark;
+    protected boolean mDarkInitialized = false;
 
     public static NotificationViewWrapper wrap(Context ctx, View v) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -39,6 +47,8 @@
                 return new NotificationBigPictureTemplateViewWrapper(ctx, v);
             } else if ("bigText".equals(v.getTag())) {
                 return new NotificationBigTextTemplateViewWrapper(ctx, v);
+            } else if ("media".equals(v.getTag()) || "bigMediaNarrow".equals(v.getTag())) {
+                return new NotificationMediaTemplateViewWrapper(ctx, v);
             }
             return new NotificationTemplateViewWrapper(ctx, v);
         } else if (v instanceof NotificationHeaderView) {
@@ -61,6 +71,7 @@
      */
     public void setDark(boolean dark, boolean fade, long delay) {
         mDark = dark;
+        mDarkInitialized = true;
     }
 
     /**
@@ -68,9 +79,29 @@
      * @param notification
      */
     public void notifyContentUpdated(StatusBarNotification notification) {
-        mDark = false;
+        mDarkInitialized = false;
     };
 
+
+    protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+            boolean dark, long delay, Animator.AnimatorListener listener) {
+        float startIntensity = dark ? 0f : 1f;
+        float endIntensity = dark ? 1f : 0f;
+        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+        animator.addUpdateListener(updateListener);
+        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        animator.setStartDelay(delay);
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        animator.start();
+    }
+
+    protected void updateGrayscaleMatrix(float intensity) {
+        mGrayscaleColorMatrix.setSaturation(1 - intensity);
+    }
+
     /**
      * Update the appearance of the expand button.
      *
@@ -98,14 +129,31 @@
     }
 
     @Override
+    public void transformTo(TransformableView notification, float transformationAmount) {
+        CrossFadeHelper.fadeOut(mView, transformationAmount);
+    }
+
+    @Override
     public void transformFrom(TransformableView notification) {
         // By default we are fading in completely
         CrossFadeHelper.fadeIn(mView);
     }
 
     @Override
+    public void transformFrom(TransformableView notification, float transformationAmount) {
+        CrossFadeHelper.fadeIn(mView, transformationAmount);
+    }
+
+    @Override
     public void setVisible(boolean visible) {
         mView.animate().cancel();
         mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
     }
+
+    public int getCustomBackgroundColor() {
+        return 0;
+    }
+
+    public void setShowingLegacyBackground(boolean showing) {
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
index 5ab441d..20dbc4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.text.Layout;
 import android.text.TextUtils;
 import android.util.Pools;
 import android.view.View;
@@ -28,14 +29,13 @@
 
     private static Pools.SimplePool<TextViewTransformState> sInstancePool
             = new Pools.SimplePool<>(40);
-    private CharSequence mText;
+    private TextView mText;
 
     @Override
     public void initFrom(View view) {
         super.initFrom(view);
         if (view instanceof TextView) {
-            TextView txt = (TextView) view;
-            mText = txt.getText();
+            mText = (TextView) view;
         }
     }
 
@@ -43,11 +43,28 @@
     protected boolean sameAs(TransformState otherState) {
         if (otherState instanceof TextViewTransformState) {
             TextViewTransformState otherTvs = (TextViewTransformState) otherState;
-            return TextUtils.equals(otherTvs.mText, mText);
+            if(TextUtils.equals(otherTvs.mText.getText(), mText.getText())) {
+                int ownEllipsized = getEllipsisCount();
+                int otherEllipsized = otherTvs.getEllipsisCount();
+                return ownEllipsized == otherEllipsized
+                        && mText.getHeight() == otherTvs.mText.getHeight();
+            }
         }
         return super.sameAs(otherState);
     }
 
+    private int getEllipsisCount() {
+        Layout l = mText.getLayout();
+        if (l != null) {
+            int lines = l.getLineCount();
+            if (lines > 0) {
+                // we only care about the first line
+                return l.getEllipsisCount(0);
+            }
+        }
+        return 0;
+    }
+
     public static TextViewTransformState obtain() {
         TextViewTransformState instance = sInstancePool.acquire();
         if (instance != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 67d31be..f04fe5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -30,23 +30,30 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
+import com.android.systemui.statusbar.ViewTransformationHelper;
 
 /**
  * A transform state of a view.
 */
 public class TransformState {
 
-    private static final int ANIMATE_X = 0x1;
-    private static final int ANIMATE_Y = 0x10;
-    private static final int ANIMATE_ALL = ANIMATE_X | ANIMATE_Y;
+    private static final float UNDEFINED = -1f;
+    private static final int TRANSOFORM_X = 0x1;
+    private static final int TRANSOFORM_Y = 0x10;
+    private static final int TRANSOFORM_ALL = TRANSOFORM_X | TRANSOFORM_Y;
     private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
     private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
     private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
+    private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag;
+    private static final int TRANSFORMATION_START_Y = R.id.transformation_start_y_tag;
+    private static final int TRANSFORMATION_START_SCLALE_X = R.id.transformation_start_scale_x_tag;
+    private static final int TRANSFORMATION_START_SCLALE_Y = R.id.transformation_start_scale_y_tag;
     private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40);
 
     protected View mTransformedView;
     private int[] mOwnPosition = new int[2];
+    private float mTransformationEndY = UNDEFINED;
+    private float mTransformationEndX = UNDEFINED;
 
     public void initFrom(View view) {
         mTransformedView = view;
@@ -55,129 +62,233 @@
     /**
      * Transforms the {@link #mTransformedView} from the given transformviewstate
      * @param otherState the state to transform from
+     * @param transformationAmount how much to transform
      */
-    public void transformViewFrom(TransformState otherState) {
+    public void transformViewFrom(TransformState otherState, float transformationAmount) {
         mTransformedView.animate().cancel();
         if (sameAs(otherState)) {
-            // We have the same content, lets show ourselves
-            mTransformedView.setAlpha(1.0f);
-            mTransformedView.setVisibility(View.VISIBLE);
+            if (mTransformedView.getVisibility() == View.INVISIBLE) {
+                // We have the same content, lets show ourselves
+                mTransformedView.setAlpha(1.0f);
+                mTransformedView.setVisibility(View.VISIBLE);
+            }
         } else {
-            CrossFadeHelper.fadeIn(mTransformedView);
+            CrossFadeHelper.fadeIn(mTransformedView, transformationAmount);
         }
-        animateViewFrom(otherState);
+        transformViewFullyFrom(otherState, transformationAmount);
     }
 
-    public void animateViewFrom(TransformState otherState) {
-        animateViewFrom(otherState, ANIMATE_ALL);
+    public void transformViewFullyFrom(TransformState otherState, float transformationAmount) {
+        transformViewFrom(otherState, TRANSOFORM_ALL, null, transformationAmount);
     }
 
-    public void animateViewVerticalFrom(TransformState otherState) {
-        animateViewFrom(otherState, ANIMATE_Y);
+    public void transformViewVerticalFrom(TransformState otherState,
+            ViewTransformationHelper.CustomTransformation customTransformation,
+            float transformationAmount) {
+        transformViewFrom(otherState, TRANSOFORM_Y, customTransformation, transformationAmount);
     }
 
-    private void animateViewFrom(TransformState otherState, int animationFlags) {
+    public void transformViewVerticalFrom(TransformState otherState, float transformationAmount) {
+        transformViewFrom(otherState, TRANSOFORM_Y, null, transformationAmount);
+    }
+
+    private void transformViewFrom(TransformState otherState, int transformationFlags,
+            ViewTransformationHelper.CustomTransformation customTransformation,
+            float transformationAmount) {
         final View transformedView = mTransformedView;
+        boolean transformX = (transformationFlags & TRANSOFORM_X) != 0;
+        boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0;
+        boolean transformScale = transformScale();
         // lets animate the positions correctly
-        int[] otherPosition = otherState.getLocationOnScreen();
-        int[] ownStablePosition = getLaidOutLocationOnScreen();
-        if ((animationFlags & ANIMATE_X) != 0) {
-            transformedView.setTranslationX(otherPosition[0] - ownStablePosition[0]);
-            transformedView.animate().translationX(0);
-        }
-        if ((animationFlags & ANIMATE_Y) != 0) {
-            transformedView.setTranslationY(otherPosition[1] - ownStablePosition[1]);
-            transformedView.animate().translationY(0);
-        }
-        if (animateScale()) {
-            // we also want to animate the scale if we're the same
-            View otherView = otherState.getTransformedView();
-            if (otherView.getWidth() != transformedView.getWidth()) {
-                float scaleX = (otherView.getWidth() * otherView.getScaleX()
-                        / (float) transformedView.getWidth());
-                transformedView.setScaleX(scaleX);
-                transformedView.setPivotX(0);
-                transformedView.animate().scaleX(1.0f);
+        if (transformationAmount == 0.0f) {
+            int[] otherPosition = otherState.getLocationOnScreen();
+            int[] ownStablePosition = getLaidOutLocationOnScreen();
+            if (customTransformation == null
+                    || !customTransformation.initTransformation(this, otherState)) {
+                if (transformX) {
+                    setTransformationStartX(otherPosition[0] - ownStablePosition[0]);
+                }
+                if (transformY) {
+                    setTransformationStartY(otherPosition[1] - ownStablePosition[1]);
+                }
+                // we also want to animate the scale if we're the same
+                View otherView = otherState.getTransformedView();
+                if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
+                    setTransformationStartScaleX(otherView.getWidth() * otherView.getScaleX()
+                            / (float) transformedView.getWidth());
+                    transformedView.setPivotX(0);
+                } else {
+                    setTransformationStartScaleX(UNDEFINED);
+                }
+                if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
+                    setTransformationStartScaleY(otherView.getHeight() * otherView.getScaleY()
+                            / (float) transformedView.getHeight());
+                    transformedView.setPivotY(0);
+                } else {
+                    setTransformationStartScaleY(UNDEFINED);
+                }
             }
-            if (otherView.getHeight() != transformedView.getHeight()) {
-                float scaleY = (otherView.getHeight() * otherView.getScaleY()
-                        / (float) transformedView.getHeight());
-                transformedView.setScaleY(scaleY);
-                transformedView.setPivotY(0);
-                transformedView.animate().scaleY(1.0f);
+            if (!transformX) {
+                setTransformationStartX(UNDEFINED);
+            }
+            if (!transformY) {
+                setTransformationStartY(UNDEFINED);
+            }
+            if (!transformScale) {
+                setTransformationStartScaleX(UNDEFINED);
+                setTransformationStartScaleY(UNDEFINED);
+            }
+            setClippingDeactivated(transformedView, true);
+        }
+        float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+                transformationAmount);
+        if (transformX) {
+            transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(),
+                    0.0f,
+                    interpolatedValue));
+        }
+        if (transformY) {
+            transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(),
+                    0.0f,
+                    interpolatedValue));
+        }
+        if (transformScale) {
+            float transformationStartScaleX = getTransformationStartScaleX();
+            if (transformationStartScaleX != UNDEFINED) {
+                transformedView.setScaleX(
+                        NotificationUtils.interpolate(transformationStartScaleX,
+                                1.0f,
+                                interpolatedValue));
+            }
+            float transformationStartScaleY = getTransformationStartScaleY();
+            if (transformationStartScaleY != UNDEFINED) {
+                transformedView.setScaleY(
+                        NotificationUtils.interpolate(transformationStartScaleY,
+                                1.0f,
+                                interpolatedValue));
             }
         }
-        transformedView.animate()
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        setClippingDeactivated(transformedView, false);
-                    }
-                });
-        setClippingDeactivated(transformedView, true);
     }
 
-    protected boolean animateScale() {
+    protected boolean transformScale() {
         return false;
     }
 
     /**
      * Transforms the {@link #mTransformedView} to the given transformviewstate
      * @param otherState the state to transform from
-     * @param endRunnable a runnable to run at the end of the animation
+     * @param transformationAmount how much to transform
      * @return whether an animation was started
      */
-    public boolean transformViewTo(TransformState otherState, final Runnable endRunnable) {
+    public boolean transformViewTo(TransformState otherState, float transformationAmount) {
         mTransformedView.animate().cancel();
         if (sameAs(otherState)) {
             // We have the same text, lets show ourselfs
-            mTransformedView.setAlpha(0.0f);
-            mTransformedView.setVisibility(View.INVISIBLE);
+            if (mTransformedView.getVisibility() == View.VISIBLE) {
+                mTransformedView.setAlpha(0.0f);
+                mTransformedView.setVisibility(View.INVISIBLE);
+            }
             return false;
         } else {
-            CrossFadeHelper.fadeOut(mTransformedView, endRunnable);
+            CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
         }
-        animateViewTo(otherState, endRunnable);
+        transformViewFullyTo(otherState, transformationAmount);
         return true;
     }
 
-    public void animateViewTo(TransformState otherState, Runnable endRunnable) {
-        animateViewTo(otherState, endRunnable, ANIMATE_ALL);
+    public void transformViewFullyTo(TransformState otherState, float transformationAmount) {
+        transformViewTo(otherState, TRANSOFORM_ALL, null, transformationAmount);
     }
 
-    public void animateViewVerticalTo(TransformState otherState, Runnable endRunnable) {
-        animateViewTo(otherState, endRunnable, ANIMATE_Y);
+    public void transformViewVerticalTo(TransformState otherState,
+            ViewTransformationHelper.CustomTransformation customTransformation,
+            float transformationAmount) {
+        transformViewTo(otherState, TRANSOFORM_Y, customTransformation, transformationAmount);
     }
 
-    private void animateViewTo(TransformState otherState, final Runnable endRunnable,
-            int animationFlags) {
+    public void transformViewVerticalTo(TransformState otherState, float transformationAmount) {
+        transformViewTo(otherState, TRANSOFORM_Y, null, transformationAmount);
+    }
+
+    private void transformViewTo(TransformState otherState, int transformationFlags,
+            ViewTransformationHelper.CustomTransformation customTransformation,
+            float transformationAmount) {
         // lets animate the positions correctly
+
+        final View transformedView = mTransformedView;
+        boolean transformX = (transformationFlags & TRANSOFORM_X) != 0;
+        boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0;
+        boolean transformScale = transformScale();
+        // lets animate the positions correctly
+        if (transformationAmount == 0.0f) {
+            if (transformX) {
+                float transformationStartX = getTransformationStartX();
+                float start = transformationStartX != UNDEFINED ? transformationStartX
+                        : transformedView.getTranslationX();
+                setTransformationStartX(start);
+            }
+            if (transformY) {
+                float transformationStartY = getTransformationStartY();
+                float start = transformationStartY != UNDEFINED ? transformationStartY
+                        : transformedView.getTranslationY();
+                setTransformationStartY(start);
+            }
+            View otherView = otherState.getTransformedView();
+            if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
+                setTransformationStartScaleX(transformedView.getScaleX());
+                transformedView.setPivotX(0);
+            } else {
+                setTransformationStartScaleX(UNDEFINED);
+            }
+            if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
+                setTransformationStartScaleY(transformedView.getScaleY());
+                transformedView.setPivotY(0);
+            } else {
+                setTransformationStartScaleY(UNDEFINED);
+            }
+            setClippingDeactivated(transformedView, true);
+        }
+        float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+                transformationAmount);
         int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
         int[] ownPosition = getLaidOutLocationOnScreen();
-        final View transformedView = mTransformedView;
-        if ((animationFlags & ANIMATE_X) != 0) {
-            transformedView.animate()
-                    .translationX(otherStablePosition[0] - ownPosition[0]);
+        if (transformX) {
+            float endX = otherStablePosition[0] - ownPosition[0];
+            if (customTransformation != null
+                    && customTransformation.customTransformTarget(this, otherState)) {
+                endX = mTransformationEndX;
+            }
+            transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(),
+                    endX,
+                    interpolatedValue));
         }
-        if ((animationFlags & ANIMATE_Y) != 0) {
-            transformedView.animate()
-                    .translationY(otherStablePosition[1] - ownPosition[1]);
+        if (transformY) {
+            float endY = otherStablePosition[1] - ownPosition[1];
+            if (customTransformation != null
+                    && customTransformation.customTransformTarget(this, otherState)) {
+                endY = mTransformationEndY;
+            }
+            transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(),
+                    endY,
+                    interpolatedValue));
         }
-        transformedView.animate()
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (endRunnable != null) {
-                            endRunnable.run();
-                        }
-                        setClippingDeactivated(transformedView, false);
-                    }
-                });
-        setClippingDeactivated(transformedView, true);
+        if (transformScale) {
+            View otherView = otherState.getTransformedView();
+            float transformationStartScaleX = getTransformationStartScaleX();
+            if (transformationStartScaleX != UNDEFINED) {
+                transformedView.setScaleX(
+                        NotificationUtils.interpolate(transformationStartScaleX,
+                                (otherView.getWidth() / (float) transformedView.getWidth()),
+                                interpolatedValue));
+            }
+            float transformationStartScaleY = getTransformationStartScaleY();
+            if (transformationStartScaleY != UNDEFINED) {
+                transformedView.setScaleY(
+                        NotificationUtils.interpolate(transformationStartScaleY,
+                                (otherView.getHeight() / (float) transformedView.getHeight()),
+                                interpolatedValue));
+            }
+        }
     }
 
     public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
@@ -281,8 +392,54 @@
         }
     }
 
+    public void setTransformationEndY(float transformationEndY) {
+        mTransformationEndY = transformationEndY;
+    }
+
+    public void setTransformationEndX(float transformationEndX) {
+        mTransformationEndX = transformationEndX;
+    }
+
+    public float getTransformationStartX() {
+        Object tag = mTransformedView.getTag(TRANSFORMATION_START_X);
+        return tag == null ? UNDEFINED : (float) tag;
+    }
+
+    public float getTransformationStartY() {
+        Object tag = mTransformedView.getTag(TRANSFORMATION_START_Y);
+        return tag == null ? UNDEFINED : (float) tag;
+    }
+
+    public float getTransformationStartScaleX() {
+        Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_X);
+        return tag == null ? UNDEFINED : (float) tag;
+    }
+
+    public float getTransformationStartScaleY() {
+        Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_Y);
+        return tag == null ? UNDEFINED : (float) tag;
+    }
+
+    public void setTransformationStartX(float transformationStartX) {
+        mTransformedView.setTag(TRANSFORMATION_START_X, transformationStartX);
+    }
+
+    public void setTransformationStartY(float transformationStartY) {
+        mTransformedView.setTag(TRANSFORMATION_START_Y, transformationStartY);
+    }
+
+    private void setTransformationStartScaleX(float startScaleX) {
+        mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, startScaleX);
+    }
+
+    private void setTransformationStartScaleY(float startScaleY) {
+        mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, startScaleY);
+    }
+
     protected void reset() {
         mTransformedView = null;
+        mTransformationEndX = UNDEFINED;
+        mTransformationEndY = UNDEFINED;
     }
 
     public void setVisible(boolean visible) {
@@ -306,6 +463,15 @@
         mTransformedView.setTranslationY(0);
         mTransformedView.setScaleX(1.0f);
         mTransformedView.setScaleY(1.0f);
+        setClippingDeactivated(mTransformedView, false);
+        abortTransformation();
+    }
+
+    public void abortTransformation() {
+        mTransformedView.setTag(TRANSFORMATION_START_X, UNDEFINED);
+        mTransformedView.setTag(TRANSFORMATION_START_Y, UNDEFINED);
+        mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, UNDEFINED);
+        mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, UNDEFINED);
     }
 
     public static TransformState obtain() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index b742479..6d0fbb15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -24,6 +24,7 @@
 import com.android.systemui.statusbar.policy.DataSaverController.Listener;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.HotspotController.Callback;
+import com.android.systemui.statusbar.policy.NightModeController;
 
 /**
  * Manages which tiles should be automatically added to QS.
@@ -66,12 +67,33 @@
         if (!Prefs.getBoolean(context, Key.QS_WORK_ADDED, false)) {
             host.getManagedProfileController().addCallback(mProfileCallback);
         }
+        if (!Prefs.getBoolean(context, Key.QS_NIGHT_ADDED, false)) {
+            host.getNightModeController().addListener(mNightModeListener);
+        }
     }
 
     public void destroy() {
         // TODO: Remove any registered listeners.
     }
 
+    private final NightModeController.Listener mNightModeListener =
+            new NightModeController.Listener() {
+        @Override
+        public void onNightModeChanged() {
+            mHost.addTile("night");
+            Prefs.putBoolean(mContext, Key.QS_NIGHT_ADDED, true);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mHost.getNightModeController().removeListener(mNightModeListener);
+                }
+            });
+        }
+
+        @Override
+        public void onTwilightAutoChanged() { }
+    };
+
     private final ManagedProfileController.Callback mProfileCallback =
             new ManagedProfileController.Callback() {
                 @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 5796edb..ed71e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -22,8 +22,12 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
 import android.util.Log;
@@ -55,6 +59,7 @@
     private final BarBackgroundDrawable mBarBackground;
 
     private int mMode;
+    private boolean mAlwaysOpaque = false;
 
     public BarTransitions(View view, int gradientResourceId) {
         mTag = "BarTransitions." + view.getClass().getSimpleName();
@@ -69,13 +74,25 @@
         return mMode;
     }
 
+    /**
+     * @param alwaysOpaque if {@code true}, the bar's background will always be opaque, regardless
+     *         of what mode it is currently set to.
+     */
+    public void setAlwaysOpaque(boolean alwaysOpaque) {
+        mAlwaysOpaque = alwaysOpaque;
+    }
+
+    public boolean isAlwaysOpaque() {
+        // Low-end devices do not support translucent modes, fallback to opaque
+        return !HIGH_END || mAlwaysOpaque;
+    }
+
     public void transitionTo(int mode, boolean animate) {
-        // low-end devices do not support translucent modes, fallback to opaque
-        if (!HIGH_END && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
+        if (isAlwaysOpaque() && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
                 || mode == MODE_TRANSPARENT)) {
             mode = MODE_OPAQUE;
         }
-        if (!HIGH_END && (mode == MODE_LIGHTS_OUT_TRANSPARENT)) {
+        if (isAlwaysOpaque() && (mode == MODE_LIGHTS_OUT_TRANSPARENT)) {
             mode = MODE_LIGHTS_OUT;
         }
         if (mMode == mode) return;
@@ -131,10 +148,13 @@
 
         private int mGradientAlpha;
         private int mColor;
+        private PorterDuffColorFilter mTintFilter;
+        private Paint mPaint = new Paint();
 
         private int mGradientAlphaStart;
         private int mColorStart;
 
+
         public BarBackgroundDrawable(Context context, int gradientResourceId) {
             final Resources res = context.getResources();
             if (DEBUG_COLORS) {
@@ -163,6 +183,26 @@
         }
 
         @Override
+        public void setTint(int color) {
+            if (mTintFilter == null) {
+                mTintFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN);
+            } else {
+                mTintFilter.setColor(color);
+            }
+            invalidateSelf();
+        }
+
+        @Override
+        public void setTintMode(Mode tintMode) {
+            if (mTintFilter == null) {
+                mTintFilter = new PorterDuffColorFilter(0, tintMode);
+            } else {
+                mTintFilter.setMode(tintMode);
+            }
+            invalidateSelf();
+        }
+
+        @Override
         protected void onBoundsChange(Rect bounds) {
             super.onBoundsChange(bounds);
             mGradient.setBounds(bounds);
@@ -208,6 +248,7 @@
             } else {
                 targetColor = mOpaque;
             }
+
             if (!mAnimating) {
                 mColor = targetColor;
                 mGradientAlpha = targetGradientAlpha;
@@ -234,7 +275,11 @@
                 mGradient.draw(canvas);
             }
             if (Color.alpha(mColor) > 0) {
-                canvas.drawColor(mColor);
+                mPaint.setColor(mColor);
+                if (mTintFilter != null) {
+                    mPaint.setColorFilter(mTintFilter);
+                }
+                canvas.drawPaint(mPaint);
             }
             if (mAnimating) {
                 invalidateSelf();  // keep going
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
index eade2a8..6e1c862 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.widget.RelativeLayout;
-
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
index 8c7c71f..3fdc35c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
@@ -23,6 +23,7 @@
 public class ExpandableIndicator extends ImageView {
 
     private boolean mExpanded;
+    private boolean mIsDefaultDirection = true;
 
     public ExpandableIndicator(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -31,20 +32,34 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
-                : R.drawable.ic_volume_expand_animation;
+        final int res = getDrawableResourceId(mExpanded);
         setImageResource(res);
     }
 
     public void setExpanded(boolean expanded) {
         if (expanded == mExpanded) return;
         mExpanded = expanded;
-        final int res = mExpanded ? R.drawable.ic_volume_expand_animation
-                : R.drawable.ic_volume_collapse_animation;
+        final int res = getDrawableResourceId(!mExpanded);
         // workaround to reset drawable
         final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext()
                 .getDrawable(res).getConstantState().newDrawable();
         setImageDrawable(avd);
+        avd.forceAnimationOnUI();
         avd.start();
     }
+
+    /** Whether the icons are using the default direction or the opposite */
+    public void setDefaultDirection(boolean isDefaultDirection) {
+        mIsDefaultDirection = isDefaultDirection;
+    }
+
+    private int getDrawableResourceId(boolean expanded) {
+        if (mIsDefaultDirection) {
+            return expanded ? R.drawable.ic_volume_collapse_animation
+                    : R.drawable.ic_volume_expand_animation;
+        } else {
+            return expanded ? R.drawable.ic_volume_expand_animation
+                    : R.drawable.ic_volume_collapse_animation;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
index 50ead3d..225751a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -27,14 +28,17 @@
     private static final String TAG = "IconMerger";
     private static final boolean DEBUG = false;
 
-    private int mIconSize;
+    private final int mIconSize;
+    private final int mIconHPadding;
+
     private View mMoreView;
 
     public IconMerger(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mIconSize = context.getResources().getDimensionPixelSize(
-                R.dimen.status_bar_icon_size);
+        Resources res = context.getResources();
+        mIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
+        mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
 
         if (DEBUG) {
             setBackgroundColor(0x800099FF);
@@ -45,12 +49,16 @@
         mMoreView = v;
     }
 
+    private int getFullIconWidth() {
+        return mIconSize + 2 * mIconHPadding;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         // we need to constrain this to an integral multiple of our children
         int width = getMeasuredWidth();
-        setMeasuredDimension(width - (width % mIconSize), getMeasuredHeight());
+        setMeasuredDimension(width - (width % getFullIconWidth()), getMeasuredHeight());
     }
 
     @Override
@@ -70,7 +78,7 @@
         final boolean overflowShown = (mMoreView.getVisibility() == View.VISIBLE);
         // let's assume we have one more slot if the more icon is already showing
         if (overflowShown) visibleChildren --;
-        final boolean moreRequired = visibleChildren * mIconSize > width;
+        final boolean moreRequired = visibleChildren * getFullIconWidth() > width;
         if (moreRequired != overflowShown) {
             post(new Runnable() {
                 @Override
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 b9e1ad2..ee88b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -16,7 +16,11 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.ActivityManager;
 import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -42,6 +46,8 @@
  */
 public class KeyguardBouncer {
 
+    final static private String TAG = "KeyguardBouncer";
+
     protected Context mContext;
     protected ViewMediatorCallback mCallback;
     protected LockPatternUtils mLockPatternUtils;
@@ -73,6 +79,11 @@
     }
 
     public void show(boolean resetSecuritySelection) {
+        final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
+        if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
+            // In split system user mode, we never unlock system user.
+            return;
+        }
         mFalsingManager.onBouncerShown();
         ensureView();
         if (resetSecuritySelection) {
@@ -84,14 +95,25 @@
             return;
         }
 
-        // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
-        // Keyguard. If we need to authenticate, show the bouncer.
-        if (!mKeyguardView.dismiss()) {
-            mShowingSoon = true;
-
-            // Split up the work over multiple frames.
-            DejankUtils.postAfterTraversal(mShowRunnable);
+        final int activeUserId = ActivityManager.getCurrentUser();
+        final boolean allowDismissKeyguard =
+                !(UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM)
+                && activeUserId == keyguardUserId;
+        // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
+        // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
+        if (allowDismissKeyguard && mKeyguardView.dismiss()) {
+            return;
         }
+
+        // This condition may indicate an error on Android, so log it.
+        if (!allowDismissKeyguard) {
+            Slog.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
+        }
+
+        mShowingSoon = true;
+
+        // Split up the work over multiple frames.
+        DejankUtils.postAfterTraversal(mShowRunnable);
     }
 
     private final Runnable mShowRunnable = new Runnable() {
@@ -258,19 +280,8 @@
         return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
     }
 
-    public boolean onMenuPressed() {
-        ensureView();
-        if (mKeyguardView.handleMenuKey()) {
-
-            // We need to show it in case it is secure. If not, it will get dismissed in any case.
-            mRoot.setVisibility(View.VISIBLE);
-            mFalsingManager.onBouncerShown();
-            mKeyguardView.requestFocus();
-            mKeyguardView.onResume();
-            return true;
-        } else {
-            return false;
-        }
+    public boolean shouldDismissOnMenuPressed() {
+        return mKeyguardView.shouldEnableMenuKey();
     }
 
     public boolean interceptMediaKey(KeyEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 4f3c61e..3812429 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -28,10 +28,13 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Log;
 
 import libcore.io.IoUtils;
 
+import java.util.Objects;
+
 /**
  * Manages the lockscreen wallpaper.
  */
@@ -42,11 +45,15 @@
     private final Context mContext;
     private final PhoneStatusBar mBar;
     private final IWallpaperManager mService;
+    private final WallpaperManager mWallpaperManager;
     private final Handler mH;
 
     private boolean mCached;
     private Bitmap mCache;
-    private int mUserId;
+    private int mCurrentUserId;
+    // The user selected in the UI, or null if no user is selected or UI doesn't support selecting
+    // users.
+    private UserHandle mSelectedUser;
 
     public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) {
         mContext = ctx;
@@ -54,7 +61,8 @@
         mH = h;
         mService = IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
-        mUserId = ActivityManager.getCurrentUser();
+        mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
+        mCurrentUserId = ActivityManager.getCurrentUser();
 
         try {
             mService.setLockWallpaperCallback(this);
@@ -73,8 +81,12 @@
                 mCache = null;
                 return null;
             }
-            ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_SET_LOCK,
-                    new Bundle(), mUserId);
+            // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
+            // wallpaper.
+            final int lockWallpaperUserId =
+                    mSelectedUser != null ? mSelectedUser.getIdentifier() : mCurrentUserId;
+            ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_LOCK,
+                    new Bundle(), lockWallpaperUserId);
             if (fd != null) {
                 try {
                     BitmapFactory.Options options = new BitmapFactory.Options();
@@ -90,8 +102,16 @@
                 }
             } else {
                 mCached = true;
-                mCache = null;
-                return null;
+                if (mSelectedUser != null && mSelectedUser.getIdentifier() != mCurrentUserId) {
+                    // When selected user is different from the current user, show the selected
+                    // user's static wallpaper.
+                    mCache = mWallpaperManager.getBitmapAsUser(mSelectedUser.getIdentifier());
+                } else {
+                    // When there is no selected user, or it's same as the current user, show the
+                    // system (possibly dynamic) wallpaper for the selected user.
+                    mCache = null;
+                }
+                return mCache;
             }
         } catch (RemoteException e) {
             Log.e(TAG, "System dead?" + e);
@@ -99,13 +119,23 @@
         }
     }
 
-    public void setUser(int user) {
-        if (user != mUserId) {
+    public void setCurrentUser(int user) {
+        if (user != mCurrentUserId) {
             mCached = false;
-            mUserId = user;
+            mCurrentUserId = user;
         }
     }
 
+    public void setSelectedUser(UserHandle selectedUser) {
+        if (Objects.equals(selectedUser, mSelectedUser)) {
+            return;
+        }
+        mSelectedUser = selectedUser;
+
+        mH.removeCallbacks(this);
+        mH.post(this);
+    }
+
     @Override
     public void onWallpaperChanged() {
         // Called on Binder thread.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
index 63ee0c0..41eed56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
@@ -113,7 +113,8 @@
             filter.addAction(Intent.ACTION_USER_SWITCHED);
             filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
             filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-            filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+            filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+            filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
             mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
         } else {
             mContext.unregisterReceiver(mReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 03dd25e3c..54af684 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -130,7 +130,9 @@
             Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
                     getContext(), v, ContactsContract.Profile.CONTENT_URI,
                     ContactsContract.QuickContact.MODE_LARGE, null);
-            getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+            if (mQsPanel != null) {
+                mQsPanel.getHost().startActivityDismissingKeyguard(intent);
+            }
         }
     }
 
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 e53f044..56a7dbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -25,7 +25,6 @@
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -36,7 +35,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
-import android.view.Gravity;
 import android.view.IDockedStackListener.Stub;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -46,7 +44,6 @@
 import android.view.WindowManagerGlobal;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.LinearLayout;
-
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.stackdivider.Divider;
@@ -54,7 +51,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
 public class NavigationBarView extends LinearLayout {
     final static boolean DEBUG = false;
@@ -93,13 +89,13 @@
     private final NavTransitionListener mTransitionListener = new NavTransitionListener();
 
     private OnVerticalChangedListener mOnVerticalChangedListener;
-    private boolean mIsLayoutRtl;
     private boolean mLayoutTransitionsEnabled = true;
     private boolean mWakeAndUnlocking;
     private boolean mCarMode = false;
     private boolean mDockedStackExists;
 
     private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
+    private Configuration mConfiguration;
 
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
@@ -185,12 +181,13 @@
         mDisplay = ((WindowManager) context.getSystemService(
                 Context.WINDOW_SERVICE)).getDefaultDisplay();
 
-        final Resources res = getContext().getResources();
         mVertical = false;
         mShowMenu = false;
         mGestureHelper = new NavigationBarGestureHelper(context);
 
-        getIcons(context);
+        mConfiguration = new Configuration();
+        mConfiguration.updateFrom(context.getResources().getConfiguration());
+        updateIcons(context, Configuration.EMPTY, mConfiguration);
 
         mBarTransitions = new NavigationBarTransitions(this);
 
@@ -264,7 +261,7 @@
         return mButtonDisatchers.get(R.id.ime_switcher);
     }
 
-    private void getCarModeIcons(Context ctx) {
+    private void updateCarModeIcons(Context ctx) {
         mBackCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_carmode);
         mBackLandCarModeIcon = mBackCarModeIcon;
         mBackAltCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime_carmode);
@@ -272,22 +269,27 @@
         mHomeCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_home_carmode);
     }
 
-    private void getIcons(Context ctx) {
-        mBackIcon = ctx.getDrawable(R.drawable.ic_sysbar_back);
-        mBackLandIcon = mBackIcon;
-        mBackAltIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime);
-        mBackAltLandIcon = mBackAltIcon;
+    private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
+        if (oldConfig.orientation != newConfig.orientation) {
+            mDockedIcon = ctx.getDrawable(R.drawable.ic_sysbar_docked);
+        }
+        if (oldConfig.densityDpi != newConfig.densityDpi) {
+            mBackIcon = ctx.getDrawable(R.drawable.ic_sysbar_back);
+            mBackLandIcon = mBackIcon;
+            mBackAltIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime);
+            mBackAltLandIcon = mBackAltIcon;
 
-        mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
+            mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
 
-        mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
-        mDockedIcon = ctx.getDrawable(R.drawable.ic_sysbar_docked);
-        getCarModeIcons(ctx);
+            mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
+            updateCarModeIcons(ctx);
+        }
     }
 
     @Override
     public void setLayoutDirection(int layoutDirection) {
-        getIcons(getContext());
+        // Reload all the icons
+        updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
 
         super.setLayoutDirection(layoutDirection);
     }
@@ -599,6 +601,9 @@
             // we are switching to.
             setNavigationIconHints(mNavigationIconHints, true);
         }
+        updateIcons(getContext(), mConfiguration, newConfig);
+        updateRecentsIcon();
+        mConfiguration.updateFrom(newConfig);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index d3681b7..f7a6b271 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import android.service.notification.StatusBarNotification;
-import android.util.ArraySet;
+import android.support.annotation.Nullable;
 
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
@@ -35,7 +35,7 @@
     private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
     private OnGroupChangeListener mListener;
     private int mBarState = -1;
-    private ArraySet<String> mHeadsUpedEntries = new ArraySet<>();
+    private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
 
     public void setOnGroupChangeListener(OnGroupChangeListener listener) {
         mListener = listener;
@@ -91,6 +91,7 @@
         } else {
             group.summary = null;
         }
+        updateSuppression(group);
         if (group.children.isEmpty()) {
             if (group.summary == null) {
                 mGroupMap.remove(groupKey);
@@ -109,43 +110,81 @@
         }
         if (isGroupChild) {
             group.children.add(added);
+            updateSuppression(group);
         } else {
             group.summary = added;
             group.expanded = added.row.areChildrenExpanded();
+            updateSuppression(group);
             if (!group.children.isEmpty()) {
                 mListener.onGroupCreatedFromChildren(group);
             }
         }
     }
 
+    private void updateSuppression(NotificationGroup group) {
+        if (group == null) {
+            return;
+        }
+        boolean prevSuppressed = group.suppressed;
+        group.suppressed = group.summary != null && !group.expanded
+                && (group.children.size() == 1
+                || (group.children.size() == 0
+                        && !group.summary.notification.getNotification().isGroupChild()
+                        && hasIsolatedChildren(group)));
+        if (prevSuppressed != group.suppressed) {
+            mListener.onGroupsChanged();
+        }
+    }
+
+    private boolean hasIsolatedChildren(NotificationGroup group) {
+        return getNumberOfIsolatedChildren(group.summary.notification.getGroupKey()) != 0;
+    }
+
+    private int getNumberOfIsolatedChildren(String groupKey) {
+        int count = 0;
+        for (StatusBarNotification sbn : mIsolatedEntries.values()) {
+            if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn)) {
+                count++;
+            }
+        }
+        return count;
+    }
+
     public void onEntryUpdated(NotificationData.Entry entry,
             StatusBarNotification oldNotification) {
         if (mGroupMap.get(getGroupKey(oldNotification)) != null) {
             onEntryRemovedInternal(entry, oldNotification);
         }
         onEntryAdded(entry);
+        if (isIsolated(entry.notification)) {
+            mIsolatedEntries.put(entry.key, entry.notification);
+            String oldKey = oldNotification.getGroupKey();
+            String newKey = entry.notification.getGroupKey();
+            if (!oldKey.equals(newKey)) {
+                updateSuppression(mGroupMap.get(oldKey));
+                updateSuppression(mGroupMap.get(newKey));
+            }
+        }
     }
 
-    public boolean isVisible(StatusBarNotification sbn) {
-        if (!isGroupChild(sbn)) {
-            return true;
-        }
-        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
-        if (group != null && (group.expanded || group.summary == null)) {
-            return true;
-        }
-        return false;
+    public boolean isSummaryOfSuppressedGroup(StatusBarNotification sbn) {
+        return isGroupSuppressed(getGroupKey(sbn)) && sbn.getNotification().isGroupSummary();
     }
 
-    public boolean hasGroupChildren(StatusBarNotification sbn) {
-        if (!isGroupSummary(sbn)) {
-            return false;
-        }
-        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
-        if (group == null) {
-            return false;
-        }
-        return !group.children.isEmpty();
+    public boolean isOnlyChildInSuppressedGroup(StatusBarNotification sbn) {
+        return isGroupSuppressed(sbn.getGroupKey())
+                && sbn.getNotification().isGroupChild()
+                && getTotalNumberOfChildren(sbn) == 1;
+    }
+
+    private int getTotalNumberOfChildren(StatusBarNotification sbn) {
+        return getNumberOfIsolatedChildren(sbn.getGroupKey())
+                + mGroupMap.get(sbn.getGroupKey()).children.size();
+    }
+
+    private boolean isGroupSuppressed(String groupKey) {
+        NotificationGroup group = mGroupMap.get(groupKey);
+        return group != null && group.suppressed;
     }
 
     public void setStatusBarState(int newState) {
@@ -163,6 +202,7 @@
             if (group.expanded) {
                 setGroupExpanded(group, false);
             }
+            updateSuppression(group);
         }
     }
 
@@ -174,7 +214,7 @@
             return false;
         }
         NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
-        if (group == null || group.summary == null) {
+        if (group == null || group.summary == null || group.suppressed) {
             return false;
         }
         return true;
@@ -194,11 +234,30 @@
         return !group.children.isEmpty();
     }
 
+    /**
+     * Get the summary of a specified status bar notification. For isolated notification this return
+     * itself.
+     */
     public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) {
-        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
+        return getGroupSummary(getGroupKey(sbn));
+    }
+
+    /**
+     * Similar to {@link #getGroupSummary(StatusBarNotification)} but doesn't get the visual summary
+     * but the logical summary, i.e when a child is isolated, it still returns the summary as if
+     * it wasn't isolated.
+     */
+    public ExpandableNotificationRow getLogicalGroupSummary(
+            StatusBarNotification sbn) {
+        return getGroupSummary(sbn.getGroupKey());
+    }
+
+    @Nullable
+    private ExpandableNotificationRow getGroupSummary(String groupKey) {
+        NotificationGroup group = mGroupMap.get(groupKey);
         return group == null ? null
                 : group.summary == null ? null
-                : group.summary.row;
+                        : group.summary.row;
     }
 
     public void toggleGroupExpansion(StatusBarNotification sbn) {
@@ -210,7 +269,7 @@
     }
 
     private boolean isIsolated(StatusBarNotification sbn) {
-        return mHeadsUpedEntries.contains(sbn.getKey()) && sbn.getNotification().isGroupChild();
+        return mIsolatedEntries.containsKey(sbn.getKey());
     }
 
     private boolean isGroupSummary(StatusBarNotification sbn) {
@@ -249,38 +308,55 @@
     public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
         final StatusBarNotification sbn = entry.notification;
         if (entry.row.isHeadsUp()) {
-            if (!mHeadsUpedEntries.contains(sbn.getKey())) {
-                final boolean groupChild = sbn.getNotification().isGroupChild();
-                if (groupChild) {
-                    // We will be isolated now, so lets update the groups
-                    onEntryRemovedInternal(entry, entry.notification);
-                }
-                mHeadsUpedEntries.add(sbn.getKey());
-                if (groupChild) {
-                    onEntryAdded(entry);
-                    mListener.onChildIsolationChanged();
-                }
+            if (shouldIsolate(sbn)) {
+                // We will be isolated now, so lets update the groups
+                onEntryRemovedInternal(entry, entry.notification);
+
+                mIsolatedEntries.put(sbn.getKey(), sbn);
+
+                onEntryAdded(entry);
+                // We also need to update the suppression of the old group, because this call comes
+                // even before the groupManager knows about the notification at all.
+                // When the notification gets added afterwards it is already isolated and therefore
+                // it doesn't lead to an update.
+                updateSuppression(mGroupMap.get(entry.notification.getGroupKey()));
+                mListener.onGroupsChanged();
             }
         } else {
-            if (mHeadsUpedEntries.contains(sbn.getKey())) {
-                boolean isolatedBefore = isIsolated(sbn);
-                if (isolatedBefore) {
-                    // not isolated anymore, we need to update the groups
-                    onEntryRemovedInternal(entry, entry.notification);
-                }
-                mHeadsUpedEntries.remove(sbn.getKey());
-                if (isolatedBefore) {
-                    onEntryAdded(entry);
-                    mListener.onChildIsolationChanged();
-                }
+            if (mIsolatedEntries.containsKey(sbn.getKey())) {
+                // not isolated anymore, we need to update the groups
+                onEntryRemovedInternal(entry, entry.notification);
+                mIsolatedEntries.remove(sbn.getKey());
+                onEntryAdded(entry);
+                mListener.onGroupsChanged();
             }
         }
     }
 
+    private boolean shouldIsolate(StatusBarNotification sbn) {
+        NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
+        return sbn.getNotification().isGroupChild()
+                && (sbn.getNotification().fullScreenIntent != null
+                        || notificationGroup == null
+                        || !notificationGroup.expanded
+                        || isGroupNotFullyVisible(notificationGroup));
+    }
+
+    private boolean isGroupNotFullyVisible(NotificationGroup notificationGroup) {
+        return notificationGroup.summary == null
+                || notificationGroup.summary.row.getClipTopOptimization() > 0
+                || notificationGroup.summary.row.getClipTopAmount() > 0
+                || notificationGroup.summary.row.getTranslationY() < 0;
+    }
+
     public static class NotificationGroup {
         public final HashSet<NotificationData.Entry> children = new HashSet<>();
         public NotificationData.Entry summary;
         public boolean expanded;
+        /**
+         * Is this notification group suppressed, i.e its summary is hidden
+         */
+        public boolean suppressed;
     }
 
     public interface OnGroupChangeListener {
@@ -301,8 +377,9 @@
         void onGroupCreatedFromChildren(NotificationGroup group);
 
         /**
-         * The isolation of a child has changed i.e it's group changes.
+         * The groups have changed. This can happen if the isolation of a child has changes or if a
+         * group became suppressed / unsuppressed
          */
-        void onChildIsolationChanged();
+        void onGroupsChanged();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 6e345f0..c4917a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -17,6 +17,7 @@
 import com.android.systemui.statusbar.notification.NotificationUtils;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * A controller for the space in the status bar to the left of the system icons. This area is
@@ -42,6 +43,10 @@
         initializeNotificationAreaViews(context);
     }
 
+    protected View inflateIconArea(LayoutInflater inflater) {
+        return inflater.inflate(R.layout.notification_icon_area, null);
+    }
+
     /**
      * Initializes the views that will represent the notification area.
      */
@@ -51,14 +56,16 @@
         mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
 
         LayoutInflater layoutInflater = LayoutInflater.from(context);
-        mNotificationIconArea = layoutInflater.inflate(R.layout.notification_icon_area, null);
-
-        mMoreIcon = (ImageView) mNotificationIconArea.findViewById(R.id.moreIcon);
-        mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+        mNotificationIconArea = inflateIconArea(layoutInflater);
 
         mNotificationIcons =
                 (IconMerger) mNotificationIconArea.findViewById(R.id.notificationIcons);
-        mNotificationIcons.setOverflowIndicator(mMoreIcon);
+
+        mMoreIcon = (ImageView) mNotificationIconArea.findViewById(R.id.moreIcon);
+        if (mMoreIcon != null) {
+            mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+            mNotificationIcons.setOverflowIndicator(mMoreIcon);
+        }
     }
 
     /**
@@ -88,16 +95,38 @@
      */
     public void setIconTint(int iconTint) {
         mIconTint = iconTint;
-        mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+        if (mMoreIcon != null) {
+            mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+        }
         applyNotificationIconsTint();
     }
 
+    protected int getHeight() {
+        return mPhoneStatusBar.getStatusBarHeight();
+    }
+
+    protected boolean shouldShowNotification(NotificationData.Entry entry,
+            NotificationData notificationData) {
+        if (notificationData.isAmbient(entry.key)
+                && !NotificationData.showNotificationEvenIfUnprovisioned(entry.notification)) {
+            return false;
+        }
+        if (!PhoneStatusBar.isTopLevelChild(entry)) {
+            return false;
+        }
+        if (entry.row.getVisibility() == View.GONE) {
+            return false;
+        }
+
+        return true;
+    }
+
     /**
      * Updates the notifications with the given list of notifications to display.
      */
     public void updateNotificationIcons(NotificationData notificationData) {
         final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
-                mIconSize + 2 * mIconHPadding, mPhoneStatusBar.getStatusBarHeight());
+                mIconSize + 2 * mIconHPadding, getHeight());
 
         ArrayList<NotificationData.Entry> activeNotifications =
                 notificationData.getActiveNotifications();
@@ -107,14 +136,9 @@
         // Filter out ambient notifications and notification children.
         for (int i = 0; i < size; i++) {
             NotificationData.Entry ent = activeNotifications.get(i);
-            if (notificationData.isAmbient(ent.key)
-                    && !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
-                continue;
+            if (shouldShowNotification(ent, notificationData)) {
+                toShow.add(ent.icon);
             }
-            if (!PhoneStatusBar.isTopLevelChild(ent)) {
-                continue;
-            }
-            toShow.add(ent.icon);
         }
 
         ArrayList<View> toRemove = new ArrayList<>();
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 1a0acbe..45e94f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -42,6 +42,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.DensityContainer;
+import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
@@ -63,7 +65,7 @@
 import java.util.List;
 
 public class NotificationPanelView extends PanelView implements
-        ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+        ExpandableView.OnHeightChangedListener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
         KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
         HeadsUpManager.OnHeadsUpChangedListener {
@@ -90,11 +92,12 @@
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
     protected QSContainer mQsContainer;
+    private DensityContainer mQsDensityContainer;
     private KeyguardStatusView mKeyguardStatusView;
     private TextView mClockView;
     private View mReserveNotificationSpace;
     private View mQsNavbarScrim;
-    private NotificationsQuickSettingsContainer mNotificationContainerParent;
+    protected NotificationsQuickSettingsContainer mNotificationContainerParent;
     protected NotificationStackScrollLayout mNotificationStackScroller;
     private boolean mAnimateNextTopPaddingChange;
 
@@ -133,7 +136,7 @@
     private boolean mStackScrollerOverscrolling;
     private boolean mQsExpansionFromOverscroll;
     private float mLastOverscroll;
-    private boolean mQsExpansionEnabled = true;
+    protected boolean mQsExpansionEnabled = true;
     private ValueAnimator mQsExpansionAnimator;
     private FlingAnimationUtils mFlingAnimationUtils;
     private int mStatusBarMinHeight;
@@ -199,6 +202,7 @@
             notifyBarPanelExpansionChanged();
         }
     };
+    private NotificationGroupManager mGroupManager;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -215,8 +219,16 @@
         super.onFinishInflate();
         mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
         mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
-        mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container);
-        mQsContainer.getHeader().setOnClickListener(this);
+        mQsDensityContainer = (DensityContainer) findViewById(R.id.qs_density_container);
+        mQsDensityContainer.addInflateListener(new InflateListener() {
+            @Override
+            public void onInflated(View v) {
+                mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
+                mQsContainer.setPanelView(NotificationPanelView.this);
+                mQsContainer.getHeader().findViewById(R.id.expand_indicator)
+                        .setOnClickListener(NotificationPanelView.this);
+            }
+        });
         mClockView = (TextView) findViewById(R.id.clock_view);
         mNotificationContainerParent = (NotificationsQuickSettingsContainer)
                 findViewById(R.id.notification_container_parent);
@@ -239,7 +251,7 @@
                 final int height = bottom - top;
                 final int oldHeight = oldBottom - oldTop;
                 if (height != oldHeight) {
-                    onScrollChanged();
+                    onQsHeightChanged();
                 }
             }
         });
@@ -267,11 +279,12 @@
     public void updateResources() {
         int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
         int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mQsContainer.getLayoutParams();
+        FrameLayout.LayoutParams lp =
+                (FrameLayout.LayoutParams) mQsDensityContainer.getLayoutParams();
         if (lp.width != panelWidth) {
             lp.width = panelWidth;
             lp.gravity = panelGravity;
-            mQsContainer.setLayoutParams(lp);
+            mQsDensityContainer.setLayoutParams(lp);
             mQsContainer.post(mUpdateHeader);
         }
 
@@ -404,6 +417,11 @@
             if (!(child instanceof ExpandableNotificationRow)) {
                 continue;
             }
+            boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
+                    ((ExpandableNotificationRow) child).getStatusBarNotification());
+            if (suppressedSummary) {
+                continue;
+            }
             availableSpace -= child.getMinHeight() + notificationPadding;
             if (availableSpace >= 0 && count < maximum) {
                 count++;
@@ -539,7 +557,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mBlockTouches) {
+        if (mBlockTouches || mQsContainer.isCustomizing()) {
             return false;
         }
         initDownStates(event);
@@ -699,7 +717,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (mBlockTouches) {
+        if (mBlockTouches || mQsContainer.isCustomizing()) {
             return false;
         }
         initDownStates(event);
@@ -772,8 +790,9 @@
     }
 
     private boolean isInQsArea(float x, float y) {
-        return (x >= mQsContainer.getX() && x <= mQsContainer.getX() + mQsContainer.getWidth()) &&
-                (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
+        return (x >= mQsDensityContainer.getX()
+                && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth())
+                && (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
                 || y <= mQsContainer.getY() + mQsContainer.getHeight());
     }
 
@@ -879,7 +898,11 @@
                 mQsTracking = false;
                 mTrackingPointer = -1;
                 trackMovement(event);
-                flingQsWithCurrentVelocity(y, event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+                float fraction = getQsExpansionFraction();
+                if (fraction != 0f || y >= mInitialTouchY) {
+                    flingQsWithCurrentVelocity(y,
+                            event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+                }
                 if (mVelocityTracker != null) {
                     mVelocityTracker.recycle();
                     mVelocityTracker = null;
@@ -894,18 +917,6 @@
     }
 
     @Override
-    public void onOverscrolled(float lastTouchX, float lastTouchY, int amount) {
-        if (mIntercepting && shouldQuickSettingsIntercept(lastTouchX, lastTouchY,
-                -1 /* yDiff: Not relevant here */)) {
-            mQsTracking = true;
-            onQsExpansionStarted(amount);
-            mInitialHeightOnTouch = mQsExpansionHeight;
-            mInitialTouchY = mLastTouchY;
-            mInitialTouchX = mLastTouchX;
-        }
-    }
-
-    @Override
     public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
         cancelQsAnimation();
         if (!mQsExpansionEnabled) {
@@ -1199,7 +1210,9 @@
     }
 
     private String getKeyguardOrLockScreenString() {
-        if (mStatusBarState == StatusBarState.KEYGUARD) {
+        if (mQsContainer.isCustomizing()) {
+            return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
+        } else if (mStatusBarState == StatusBarState.KEYGUARD) {
             return getContext().getString(R.string.accessibility_desc_lock_screen);
         } else {
             return getContext().getString(R.string.accessibility_desc_notification_shade);
@@ -1326,7 +1339,8 @@
             return false;
         }
         View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
-        boolean onHeader = x >= header.getX() && x <= header.getX() + header.getWidth()
+        boolean onHeader = x >= mQsDensityContainer.getX()
+                && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth()
                 && y >= header.getTop() && y <= header.getBottom();
         if (mQsExpanded) {
             return onHeader || (yDiff < 0 && isInQsArea(x, y));
@@ -1385,7 +1399,7 @@
                 // In Shade, interpolate linearly such that QS is closed whenever panel height is
                 // minimum QS expansion + minStackHeight
                 float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
-                        + mNotificationStackScroller.getMinStackHeight();
+                        + mNotificationStackScroller.getLayoutMinHeight();
                 float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
                 t = (expandedHeight - panelHeightQsCollapsed)
                         / (panelHeightQsExpanded - panelHeightQsCollapsed);
@@ -1441,7 +1455,7 @@
                 && mShadeEmpty) {
             notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
                     + mNotificationStackScroller.getBottomStackPeekSize()
-                    + mNotificationStackScroller.getCollapseSecondCardPadding();
+                    + mNotificationStackScroller.getBottomStackSlowDownHeight();
         }
         int maxQsHeight = mQsMaxExpansionHeight;
 
@@ -1456,7 +1470,7 @@
                 + notificationHeight;
         if (totalHeight > mNotificationStackScroller.getHeight()) {
             float fullyCollapsedHeight = maxQsHeight
-                    + mNotificationStackScroller.getMinStackHeight();
+                    + mNotificationStackScroller.getLayoutMinHeight();
             totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
         }
         return (int) totalHeight;
@@ -1473,7 +1487,7 @@
     private float getFadeoutAlpha() {
         float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
                 / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
-                - mNotificationStackScroller.getCollapseSecondCardPadding());
+                - mNotificationStackScroller.getBottomStackSlowDownHeight());
         alpha = Math.max(0, Math.min(alpha, 1));
         alpha = (float) Math.pow(alpha, 0.75);
         return alpha;
@@ -1707,9 +1721,10 @@
     public void onReset(ExpandableView view) {
     }
 
-    @Override
-    public void onScrollChanged() {
+    public void onQsHeightChanged() {
+        mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
         if (mQsExpanded) {
+            mQsExpansionHeight = mQsMaxExpansionHeight;
             requestScrollerTopPaddingUpdate(false /* animate */);
             requestPanelHeightUpdate();
         }
@@ -1727,7 +1742,7 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        mNavigationBarBottomHeight = insets.getSystemWindowInsetBottom();
+        mNavigationBarBottomHeight = insets.getStableInsetBottom();
         updateMaxHeadsUpTranslation();
         return insets;
     }
@@ -1746,7 +1761,7 @@
 
     @Override
     public void onClick(View v) {
-        if (v == mQsContainer.getHeader()) {
+        if (v.getId() == R.id.expand_indicator) {
             onQsExpansionStarted();
             if (mQsExpanded) {
                 flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
@@ -2207,7 +2222,7 @@
 
     protected void setVerticalPanelTranslation(float translation) {
         mNotificationStackScroller.setTranslationX(translation);
-        mQsContainer.setTranslationX(translation);
+        mQsDensityContainer.setTranslationX(translation);
     }
 
     protected void updateStackHeight(float stackHeight) {
@@ -2294,4 +2309,8 @@
         List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
         return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
     }
+
+    public void setGroupManager(NotificationGroupManager groupManager) {
+        mGroupManager = groupManager;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 7cc720d..35fb2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -24,21 +24,28 @@
 import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
-
+import com.android.systemui.DensityContainer;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSContainer;
+import com.android.systemui.qs.customize.QSCustomizer;
 
 /**
  * The container with notification stack scroller and quick settings inside.
  */
 public class NotificationsQuickSettingsContainer extends FrameLayout
-        implements ViewStub.OnInflateListener {
+        implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
 
-    private View mQsContainer;
+
+    private DensityContainer mQsContainer;
     private View mUserSwitcher;
     private View mStackScroller;
     private View mKeyguardStatusBar;
     private boolean mInflated;
     private boolean mQsExpanded;
+    private boolean mCustomizerAnimating;
+
+    private int mBottomPadding;
+    private int mStackScrollerMargin;
 
     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -47,8 +54,10 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQsContainer = findViewById(R.id.quick_settings_container);
+        mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
+        mQsContainer.addInflateListener(this);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
+        mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
         ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
         userSwitcher.setOnInflateListener(this);
@@ -71,7 +80,8 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
+        mBottomPadding = insets.getStableInsetBottom();
+        setPadding(0, 0, 0, mBottomPadding);
         return insets;
     }
 
@@ -80,8 +90,9 @@
         boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
         boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
 
-        View stackQsTop = mQsExpanded ? mStackScroller : mQsContainer;
-        View stackQsBottom = !mQsExpanded ? mStackScroller : mQsContainer;
+        final boolean qsBottom = mQsExpanded && !mCustomizerAnimating;
+        View stackQsTop = qsBottom ? mStackScroller : mQsContainer;
+        View stackQsBottom = !qsBottom ? mStackScroller : mQsContainer;
         // Invert the order of the scroll view and user switcher such that the notifications receive
         // touches first but the panel gets drawn above.
         if (child == mQsContainer) {
@@ -117,10 +128,41 @@
         }
     }
 
+    @Override
+    public void onInflated(View v) {
+        QSCustomizer customizer = ((QSContainer) v).getCustomizer();
+        customizer.setContainer(this);
+    }
+
     public void setQsExpanded(boolean expanded) {
         if (mQsExpanded != expanded) {
             mQsExpanded = expanded;
             invalidate();
         }
     }
+
+    public void setCustomizerAnimating(boolean isAnimating) {
+        if (mCustomizerAnimating != isAnimating) {
+            mCustomizerAnimating = isAnimating;
+            invalidate();
+        }
+    }
+
+    public void setCustomizerShowing(boolean isShowing) {
+        if (isShowing) {
+            // Clear out bottom paddings/margins so the qs customization can be full height.
+            setPadding(0, 0, 0, 0);
+            setBottomMargin(mStackScroller, 0);
+        } else {
+            setPadding(0, 0, 0, mBottomPadding);
+            setBottomMargin(mStackScroller, mStackScrollerMargin);
+        }
+
+    }
+
+    private void setBottomMargin(View v, int bottomMargin) {
+        LayoutParams params = (LayoutParams) v.getLayoutParams();
+        params.bottomMargin = bottomMargin;
+        v.setLayoutParams(params);
+    }
 }
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 1089852..fce893e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -21,13 +21,13 @@
 import android.animation.AnimatorListenerAdapter;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
 import android.app.IActivityManager;
-import android.app.IWallpaperManagerCallback;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
-import android.app.WallpaperManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
@@ -50,7 +50,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
 import android.inputmethodservice.InputMethodService;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
@@ -69,7 +68,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
@@ -106,12 +104,16 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
+import com.android.systemui.DensityContainer;
+import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
@@ -120,6 +122,7 @@
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.WindowManagerProxy;
@@ -283,7 +286,7 @@
     HotspotControllerImpl mHotspotController;
     RotationLockControllerImpl mRotationLockController;
     UserInfoController mUserInfoController;
-    ZenModeController mZenModeController;
+    protected ZenModeController mZenModeController;
     CastControllerImpl mCastController;
     VolumeComponent mVolumeComponent;
     KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -295,7 +298,7 @@
     AccessibilityController mAccessibilityController;
     FingerprintUnlockController mFingerprintUnlockController;
     LightStatusBarController mLightStatusBarController;
-    private LockscreenWallpaper mLockscreenWallpaper;
+    protected LockscreenWallpaper mLockscreenWallpaper;
 
     int mNaturalBarHeight = -1;
 
@@ -303,7 +306,7 @@
     Point mCurrentDisplaySize = new Point();
 
     protected StatusBarWindowView mStatusBarWindow;
-    PhoneStatusBarView mStatusBarView;
+    protected PhoneStatusBarView mStatusBarView;
     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
     protected StatusBarWindowManager mStatusBarWindowManager;
     private UnlockMethodCache mUnlockMethodCache;
@@ -315,7 +318,7 @@
     int mPixelFormat;
     Object mQueueLock = new Object();
 
-    StatusBarIconController mIconController;
+    protected StatusBarIconController mIconController;
 
     // expanded notifications
     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -327,7 +330,7 @@
 
     // top bar
     BaseStatusBarHeader mHeader;
-    KeyguardStatusBarView mKeyguardStatusBar;
+    protected KeyguardStatusBarView mKeyguardStatusBar;
     View mKeyguardStatusView;
     KeyguardBottomAreaView mKeyguardBottomArea;
     boolean mLeaveOpenOnKeyguardHide;
@@ -646,7 +649,7 @@
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
                 mHotspotController, mUserInfoController, mBluetoothController,
-                mRotationLockController);
+                mRotationLockController, mNetworkController.getDataSaverController());
         mIconPolicy.setCurrentUserSetup(mUserSetup);
         mSettingsObserver.onChange(false); // set up
 
@@ -676,6 +679,11 @@
         mFalsingManager = FalsingManager.getInstance(mContext);
     }
 
+    protected void createIconController() {
+        mIconController = new StatusBarIconController(
+                mContext, mStatusBarView, mKeyguardStatusBar, this);
+    }
+
     // ================================================================================
     // Constructing the view
     // ================================================================================
@@ -703,6 +711,7 @@
         mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
                 R.id.notification_panel);
         mNotificationPanel.setStatusBar(this);
+        mNotificationPanel.setGroupManager(mGroupManager);
 
         mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
         mStatusBarView.setBar(this);
@@ -746,7 +755,6 @@
         mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                 R.id.notification_stack_scroller);
         mStackScroller.setLongPressListener(getNotificationLongClicker());
-        mStackScroller.setGearDisplayedListener(getGearDisplayedListener());
         mStackScroller.setPhoneStatusBar(this);
         mStackScroller.setGroupManager(mGroupManager);
         mStackScroller.setHeadsUpManager(mHeadsUpManager);
@@ -771,16 +779,25 @@
         ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
         ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
         View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
-        mScrimController = new ScrimController(scrimBehind, scrimInFront, headsUpScrim,
-                mScrimSrcModeEnabled);
+        mScrimController = SystemUIFactory.getInstance().createScrimController(
+                scrimBehind, scrimInFront, headsUpScrim);
+        if (mScrimSrcModeEnabled) {
+            Runnable runnable = new Runnable() {
+                @Override
+                public void run() {
+                    boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
+                    mScrimController.setDrawBehindAsSrc(asSrc);
+                    mStackScroller.setDrawBackgroundAsSrc(asSrc);
+                }
+            };
+            mBackdrop.setOnVisibilityChangedRunnable(runnable);
+            runnable.run();
+        }
         mHeadsUpManager.addListener(mScrimController);
         mStackScroller.setScrimController(mScrimController);
-        mScrimController.setBackDropView(mBackdrop);
         mStatusBarView.setScrimController(mScrimController);
         mDozeScrimController = new DozeScrimController(mScrimController, context);
 
-        mHeader = (BaseStatusBarHeader) mStatusBarWindow.findViewById(R.id.header);
-        mHeader.setActivityStarter(this);
         mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
         mKeyguardBottomArea =
@@ -800,8 +817,7 @@
         // set the initial view visibility
         setAreThereNotifications();
 
-        mIconController = new StatusBarIconController(
-                mContext, mStatusBarView, mKeyguardStatusBar, this);
+        createIconController();
 
         // Background thread for any controllers that need it.
         mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
@@ -840,12 +856,6 @@
 
         initSignalCluster(mStatusBarView);
         initSignalCluster(mKeyguardStatusBar);
-        initSignalCluster(mHeader);
-
-        final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
-        if (isAPhone) {
-            mNetworkController.addEmergencyListener(mHeader);
-        }
 
         mFlashlightController = new FlashlightController(mContext);
         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
@@ -864,39 +874,40 @@
         }
 
         // 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,
+        DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
+                R.id.qs_density_container);
+        if (container != null) {
+            final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
                     mNetworkController, mZenModeController, mHotspotController,
                     mCastController, mFlashlightController,
                     mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
-                    mSecurityController, mBatteryController, mIconController);
-            mQSPanel.setTiles(qsh.getTiles());
+                    mSecurityController, mBatteryController, mIconController,
+                    mNextAlarmController);
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
-            mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
-            QSContainer qsContainer = (QSContainer) mStatusBarWindow.findViewById(
-                    R.id.quick_settings_container);
-            qsContainer.setHost(qsh);
-            qsh.addCallback(new QSTileHost.Callback() {
+            container.addInflateListener(new InflateListener() {
                 @Override
-                public void onTilesChanged() {
-                    mQSPanel.setTiles(qsh.getTiles());
+                public void onInflated(View v) {
+                    QSContainer qsContainer = (QSContainer) v.findViewById(
+                            R.id.quick_settings_container);
+                    qsContainer.setHost(qsh);
+                    mQSPanel = qsContainer.getQsPanel();
+                    mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+                    mHeader = qsContainer.getHeader();
+                    initSignalCluster(mHeader);
+                    mHeader.setActivityStarter(PhoneStatusBar.this);
                 }
             });
         }
 
         // User info. Trigger first load.
-        mHeader.setUserInfoController(mUserInfoController);
         mKeyguardStatusBar.setUserInfoController(mUserInfoController);
         mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
         mUserInfoController.reloadUserInfo();
 
-        mHeader.setBatteryController(mBatteryController);
         ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
                 mBatteryController);
         mKeyguardStatusBar.setBatteryController(mBatteryController);
-        mHeader.setNextAlarmController(mNextAlarmController);
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mBroadcastReceiver.onReceive(mContext,
@@ -1002,13 +1013,12 @@
         SignalClusterView signalCluster =
                 (SignalClusterView) containerView.findViewById(R.id.signal_cluster);
         if (signalCluster != null) {
-            mNetworkController.addSignalCallback(signalCluster);
             signalCluster.setSecurityController(mSecurityController);
             signalCluster.setNetworkController(mNetworkController);
         }
     }
 
-    private void clearAllNotifications() {
+    public void clearAllNotifications() {
 
         // animate-swipe all dismissable notifications, then animate the shade closed
         int numChildren = mStackScroller.getChildCount();
@@ -1101,6 +1111,18 @@
                 mStatusBarKeyguardViewManager);
         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
+
+        if (FORCE_REMOTE_INPUT_HISTORY) {
+            mRemoteInputController.addCallback(new RemoteInputController.Callback() {
+                @Override
+                public void onRemoteInputSent(Entry entry) {
+                    if (mKeysKeptForRemoteInput.contains(entry.key)) {
+                        removeNotification(entry.key, null);
+                    }
+                }
+            });
+        }
+
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
         mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
     }
@@ -1145,31 +1167,38 @@
 
         @Override
         public boolean onLongClick(View v) {
-            if (mRecents != null) {
-                int dockSide = WindowManagerProxy.getInstance().getDockSide();
-                if (dockSide == WindowManager.DOCKED_INVALID) {
-                    Point realSize = new Point();
-                    mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
-                            .getRealSize(realSize);
-                    Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y);
-                    boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
-                            ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
-                            initialBounds);
-                    if (docked) {
-                        MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS);
-                        return true;
-                    }
-                } else {
-                    EventBus.getDefault().send(new UndockingTaskEvent());
-                    MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
-                    return true;
-                }
+            if (mRecents == null || !ActivityManager.supportsMultiWindow()) {
+                return false;
+            }
 
+            boolean initiallyDocked = WindowManagerProxy.getInstance().getDockSide()
+                    == WindowManager.DOCKED_INVALID;
+            boolean dockedAtEnd = toggleSplitScreenMode();
+            if (dockedAtEnd != initiallyDocked) {
+                int logAction = dockedAtEnd ? MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS
+                        : MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS;
+                MetricsLogger.action(mContext, logAction);
+                return true;
             }
             return false;
         }
     };
 
+    @Override
+    protected boolean toggleSplitScreenMode() {
+        if (mRecents == null) {
+            return false;
+        }
+        int dockSide = WindowManagerProxy.getInstance().getDockSide();
+        if (dockSide == WindowManager.DOCKED_INVALID) {
+            return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
+                    ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null);
+        } else {
+            EventBus.getDefault().send(new UndockingTaskEvent());
+            return false;
+        }
+    }
+
     private final View.OnLongClickListener mLongPressHomeListener
             = new View.OnLongClickListener() {
         @Override
@@ -1309,6 +1338,12 @@
                 if (DEBUG) {
                     Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
                 }
+            } else if (mNotificationData.getImportance(notification.getKey())
+                    < NotificationListenerService.Ranking.IMPORTANCE_MAX) {
+                if (DEBUG) {
+                    Log.d(TAG, "No Fullscreen intent: not important enough: "
+                            + notification.getKey());
+                }
             } else {
                 // Stop screensaver if the notification has a full-screen intent.
                 // (like an incoming phone call)
@@ -1356,6 +1391,42 @@
             clearCurrentMediaNotification();
             updateMediaMetaData(true, true);
         }
+        if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
+            Entry entry = mNotificationData.get(key);
+            StatusBarNotification sbn = entry.notification;
+
+            Notification.Builder b = Notification.Builder
+                    .recoverBuilder(mContext, sbn.getNotification().clone());
+            CharSequence[] oldHistory = sbn.getNotification().extras
+                    .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+            CharSequence[] newHistory;
+            if (oldHistory == null) {
+                newHistory = new CharSequence[1];
+            } else {
+                newHistory = new CharSequence[oldHistory.length + 1];
+                for (int i = 0; i < oldHistory.length; i++) {
+                    newHistory[i + 1] = oldHistory[i];
+                }
+            }
+            newHistory[0] = String.valueOf(entry.remoteInputText);
+            b.setRemoteInputHistory(newHistory);
+
+            Notification newNotification = b.build();
+
+            // Undo any compatibility view inflation
+            newNotification.contentView = sbn.getNotification().contentView;
+            newNotification.bigContentView = sbn.getNotification().bigContentView;
+            newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
+
+            StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
+                    sbn.getOpPkg(),
+                    sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
+                    0, newNotification, sbn.getUser(), sbn.getPostTime());
+
+            updateNotification(newSbn, null);
+            mKeysKeptForRemoteInput.add(entry.key);
+            return;
+        }
         if (deferRemoval) {
             mLatestRankingMap = ranking;
             mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
@@ -1415,7 +1486,7 @@
             if (showingPublic) {
                 updatePublicContentView(ent, ent.notification);
             }
-            ent.row.setSensitive(sensitive);
+            ent.row.setSensitive(sensitive, hideSensitive);
             if (ent.autoRedacted && ent.legacy) {
                 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
                 // for legacy auto redacted notifications.
@@ -1457,6 +1528,9 @@
             mStackScroller.removeView(remove);
             mStackScroller.setChildTransferInProgress(false);
         }
+
+        removeNotificationChildren();
+
         for (int i=0; i<toShow.size(); i++) {
             View v = toShow.get(i);
             if (v.getParent() == null) {
@@ -1464,6 +1538,8 @@
             }
         }
 
+        addNotificationChildrenAndSort();
+
         // So after all this work notifications still aren't sorted correctly.
         // Let's do that now by advancing through toShow and mStackScroller in
         // lock-step, making sure mStackScroller matches what we see in toShow.
@@ -1485,9 +1561,6 @@
 
         }
 
-        // lets handle the child notifications now
-        updateNotificationShadeForChildren();
-
         // clear the map again for the next usage
         mTmpChildOrderMap.clear();
 
@@ -1513,34 +1586,7 @@
                 && !ONLY_CORE_APPS);
     }
 
-    private void updateNotificationShadeForChildren() {
-        // First let's remove all children which don't belong in the parents
-        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
-        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
-            View view = mStackScroller.getChildAt(i);
-            if (!(view instanceof ExpandableNotificationRow)) {
-                // We don't care about non-notification views.
-                continue;
-            }
-
-            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
-            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
-            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
-
-            if (children != null) {
-                toRemove.clear();
-                for (ExpandableNotificationRow childRow : children) {
-                    if (orderedChildren == null || !orderedChildren.contains(childRow)) {
-                        toRemove.add(childRow);
-                    }
-                }
-                for (ExpandableNotificationRow remove : toRemove) {
-                    parent.removeChildNotification(remove);
-                    mStackScroller.notifyGroupChildRemoved(remove);
-                }
-            }
-        }
-
+    private void addNotificationChildrenAndSort() {
         // Let's now add all notification children which are missing
         boolean orderChanged = false;
         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
@@ -1571,6 +1617,39 @@
         }
     }
 
+    private void removeNotificationChildren() {
+        // First let's remove all children which don't belong in the parents
+        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
+        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+            View view = mStackScroller.getChildAt(i);
+            if (!(view instanceof ExpandableNotificationRow)) {
+                // We don't care about non-notification views.
+                continue;
+            }
+
+            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
+            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+
+            if (children != null) {
+                toRemove.clear();
+                for (ExpandableNotificationRow childRow : children) {
+                    if (orderedChildren == null || !orderedChildren.contains(childRow)) {
+                        toRemove.add(childRow);
+                    }
+                }
+                for (ExpandableNotificationRow remove : toRemove) {
+                    parent.removeChildNotification(remove);
+                    if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) {
+                        // We only want to add an animation if the view is completely removed
+                        // otherwise it's just a transfer
+                        mStackScroller.notifyGroupChildRemoved(remove);
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public void addQsTile(ComponentName tile) {
         mQSPanel.getHost().addTile(tile);
@@ -1587,8 +1666,7 @@
     }
 
     private boolean packageHasVisibilityOverride(String key) {
-        return mNotificationData.getVisibilityOverride(key)
-                != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+        return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
     }
 
     private void updateClearAll() {
@@ -1608,16 +1686,14 @@
     private void updateSpeedbump() {
         int speedbumpIndex = -1;
         int currentIndex = 0;
-        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
-        final int N = activeNotifications.size();
+        final int N = mStackScroller.getChildCount();
         for (int i = 0; i < N; i++) {
-            Entry entry = activeNotifications.get(i);
-            boolean isChild = !isTopLevelChild(entry);
-            if (isChild) {
+            View view = mStackScroller.getChildAt(i);
+            if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
                 continue;
             }
-            if (entry.row.getVisibility() != View.GONE &&
-                    mNotificationData.isAmbient(entry.key)) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            if (mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
                 speedbumpIndex = currentIndex;
                 break;
             }
@@ -1863,10 +1939,16 @@
             if (mBackdrop.getVisibility() != View.VISIBLE) {
                 mBackdrop.setVisibility(View.VISIBLE);
                 if (allowEnterAnimation) {
-                    mBackdrop.animate().alpha(1f);
+                    mBackdrop.animate().alpha(1f).withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mStatusBarWindowManager.setBackdropShowing(true);
+                        }
+                    });
                 } else {
                     mBackdrop.animate().cancel();
                     mBackdrop.setAlpha(1f);
+                    mStatusBarWindowManager.setBackdropShowing(true);
                 }
                 metaDataChanged = true;
                 if (DEBUG_MEDIA) {
@@ -1923,7 +2005,10 @@
 
                     // We are unlocking directly - no animation!
                     mBackdrop.setVisibility(View.GONE);
+                    mBackdropBack.setImageDrawable(null);
+                    mStatusBarWindowManager.setBackdropShowing(false);
                 } else {
+                    mStatusBarWindowManager.setBackdropShowing(false);
                     mBackdrop.animate()
                             // Never let the alpha become zero - otherwise the RenderNode
                             // won't draw anything and uninitialized memory will show through
@@ -1938,7 +2023,7 @@
                                 public void run() {
                                     mBackdrop.setVisibility(View.GONE);
                                     mBackdropFront.animate().cancel();
-                                    mBackdropBack.animate().cancel();
+                                    mBackdropBack.setImageDrawable(null);
                                     mHandler.post(mHideBackdropFront);
                                 }
                             });
@@ -1957,7 +2042,7 @@
         }
     }
 
-    private int adjustDisableFlags(int state) {
+    protected int adjustDisableFlags(int state) {
         if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
                 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
@@ -2236,6 +2321,10 @@
         mStatusBarWindowManager.setPanelExpanded(isExpanded);
     }
 
+    public void onScreenTurnedOff() {
+        mFalsingManager.onScreenOff();
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -2939,18 +3028,15 @@
             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
         }
 
+        FalsingManager.getInstance(mContext).dump(pw);
+        FalsingLog.dump(pw);
+
         pw.println("SharedPreferences:");
         for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
             pw.print("  "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
         }
     }
 
-    private String hunStateToString(Entry entry) {
-        if (entry == null) return "null";
-        if (entry.notification == null) return "corrupt";
-        return entry.notification.getPackageName();
-    }
-
     private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
         pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
         pw.println(BarTransitions.modeToString(transitions.getMode()));
@@ -3006,8 +3092,8 @@
                             null, mContext.getBasePackageName(),
                             intent,
                             intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                            null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
-                            UserHandle.CURRENT.getIdentifier());
+                            null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
+                            getActivityOptions(), UserHandle.CURRENT.getIdentifier());
                 } catch (RemoteException e) {
                     Log.w(TAG, "Unable to start activity", e);
                 }
@@ -3112,7 +3198,7 @@
         }
     };
 
-    private void resetUserExpandedStates() {
+    public void resetUserExpandedStates() {
         ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
         final int notificationCount = activeNotifications.size();
         for (int i = 0; i < notificationCount; i++) {
@@ -3170,7 +3256,7 @@
         resetUserSetupObserver();
         setControllerUsers();
         clearCurrentMediaNotification();
-        mLockscreenWallpaper.setUser(newUserId);
+        mLockscreenWallpaper.setCurrentUser(newUserId);
         updateMediaMetaData(true, false);
     }
 
@@ -3546,7 +3632,7 @@
     }
 
     @Override
-    protected boolean isPanelFullyCollapsed() {
+    public boolean isPanelFullyCollapsed() {
         return mNotificationPanel.isFullyCollapsed();
     }
 
@@ -3878,7 +3964,13 @@
     }
 
     public boolean onMenuPressed() {
-        return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
+        if (mDeviceInteractive && mState != StatusBarState.SHADE
+                && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed()) {
+            animateCollapsePanels(
+                    CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
+            return true;
+        }
+        return false;
     }
 
     public void endAffordanceLaunch() {
@@ -4084,7 +4176,7 @@
         ExpandableNotificationRow row = null;
         if (expandView instanceof ExpandableNotificationRow) {
             row = (ExpandableNotificationRow) expandView;
-            row.setUserExpanded(true);
+            row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
         }
         boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
                 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
@@ -4153,7 +4245,6 @@
         mDeviceInteractive = false;
         mWakeUpComingFromTouch = false;
         mWakeUpTouchLocation = null;
-        mFalsingManager.onScreenOff();
         mStackScroller.setAnimationsEnabled(false);
         updateVisibleToUser();
         if (mLaunchCameraOnFinishedGoingToSleep) {
@@ -4269,6 +4360,7 @@
     @Override
     public void appTransitionCancelled() {
         mIconController.appTransitionCancelled();
+        EventBus.getDefault().send(new AppTransitionFinishedEvent());
     }
 
     @Override
@@ -4285,6 +4377,11 @@
     }
 
     @Override
+    public void appTransitionFinished() {
+        EventBus.getDefault().send(new AppTransitionFinishedEvent());
+    }
+
+    @Override
     public void onCameraLaunchGestureDetected(int source) {
         mLastCameraLaunchSource = source;
         if (mStartedGoingToSleep) {
@@ -4460,7 +4557,20 @@
         }
 
         private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) {
-            mDozeScrimController.pulse(callback, reason);
+            mDozeScrimController.pulse(new PulseCallback() {
+
+                @Override
+                public void onPulseStarted() {
+                    callback.onPulseStarted();
+                    mStackScroller.setPulsing(true);
+                }
+
+                @Override
+                public void onPulseFinished() {
+                    callback.onPulseFinished();
+                    mStackScroller.setPulsing(false);
+                }
+            }, reason);
         }
 
         private void handleStopDozing() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 6550c87..0ac2e7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.policy.BluetoothController.Callback;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
+import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -53,7 +54,7 @@
  * bar at boot time.  It goes through the normal API for icons, even though it probably
  * strictly doesn't need to.
  */
-public class PhoneStatusBarPolicy implements Callback, RotationLockController.RotationLockControllerCallback {
+public class PhoneStatusBarPolicy implements Callback, RotationLockController.RotationLockControllerCallback, DataSaverController.Listener {
     private static final String TAG = "PhoneStatusBarPolicy";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -67,6 +68,7 @@
     private final String mSlotManagedProfile;
     private final String mSlotRotate;
     private final String mSlotHeadset;
+    private final String mSlotDataSaver;
 
     private final Context mContext;
     private final Handler mHandler = new Handler();
@@ -77,6 +79,7 @@
     private final UserManager mUserManager;
     private final StatusBarIconController mIconController;
     private final RotationLockController mRotationLockController;
+    private final DataSaverController mDataSaver;
 
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
@@ -97,7 +100,8 @@
 
     public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController,
             CastController cast, HotspotController hotspot, UserInfoController userInfoController,
-            BluetoothController bluetooth, RotationLockController rotationLockController) {
+            BluetoothController bluetooth, RotationLockController rotationLockController,
+            DataSaverController dataSaver) {
         mContext = context;
         mIconController = iconController;
         mCast = cast;
@@ -108,6 +112,7 @@
         mUserInfoController = userInfoController;
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mRotationLockController = rotationLockController;
+        mDataSaver = dataSaver;
 
         mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
         mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -120,6 +125,7 @@
                 com.android.internal.R.string.status_bar_managed_profile);
         mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate);
         mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
+        mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
 
         mRotationLockController.addRotationLockControllerCallback(this);
 
@@ -131,7 +137,8 @@
         filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
-        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
 
         // listen for user / profile change.
@@ -176,6 +183,12 @@
         mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
                 mContext.getString(R.string.accessibility_managed_profile));
         mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);
+
+        // data saver
+        mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
+                context.getString(R.string.accessibility_data_saver_on));
+        mIconController.setIconVisibility(mSlotDataSaver, false);
+        mDataSaver.addListener(this);
     }
 
     public void setZenMode(int zen) {
@@ -477,6 +490,11 @@
         }
     }
 
+    @Override
+    public void onDataSaverChanged(boolean isDataSaving) {
+        mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
+    }
+
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -490,7 +508,8 @@
                 updateSimState(intent);
             } else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
                 updateTTY(intent);
-            } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
+            } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) ||
+                    action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
                 updateQuietState();
                 updateManagedProfile();
             } else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 80afb9a..82496ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -57,6 +57,7 @@
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NightModeController;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -80,7 +81,7 @@
 import java.util.Map;
 
 /** Platform implementation of the quick settings tile host **/
-public final class QSTileHost implements QSTile.Host, Tunable {
+public class QSTileHost implements QSTile.Host, Tunable {
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -111,16 +112,19 @@
     private final NightModeController mNightModeController;
     private final AutoTileManager mAutoTiles;
     private final ManagedProfileController mProfileController;
+    private final NextAlarmController mNextAlarmController;
     private View mHeader;
+    private int mCurrentUser;
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
-                      BluetoothController bluetooth, LocationController location,
-                      RotationLockController rotation, NetworkController network,
-                      ZenModeController zen, HotspotController hotspot,
-                      CastController cast, FlashlightController flashlight,
-                      UserSwitcherController userSwitcher, UserInfoController userInfo,
-                      KeyguardMonitor keyguard, SecurityController security,
-                      BatteryController battery, StatusBarIconController iconController) {
+            BluetoothController bluetooth, LocationController location,
+            RotationLockController rotation, NetworkController network,
+            ZenModeController zen, HotspotController hotspot,
+            CastController cast, FlashlightController flashlight,
+            UserSwitcherController userSwitcher, UserInfoController userInfo,
+            KeyguardMonitor keyguard, SecurityController security,
+            BatteryController battery, StatusBarIconController iconController,
+            NextAlarmController nextAlarmController) {
         mContext = context;
         mStatusBar = statusBar;
         mBluetooth = bluetooth;
@@ -137,6 +141,7 @@
         mSecurity = security;
         mBattery = battery;
         mIconController = iconController;
+        mNextAlarmController = nextAlarmController;
         mNightModeController = new NightModeController(mContext, true);
         mProfileController = new ManagedProfileController(this);
 
@@ -152,6 +157,10 @@
         mAutoTiles = new AutoTileManager(context, this);
     }
 
+    public NextAlarmController getNextAlarmController() {
+        return mNextAlarmController;
+    }
+
     public void setHeaderView(View view) {
         mHeader = view;
     }
@@ -171,6 +180,11 @@
     }
 
     @Override
+    public void removeCallback(Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    @Override
     public Collection<QSTile<?>> getTiles() {
         return mTiles.values();
     }
@@ -307,7 +321,8 @@
         }
         if (DEBUG) Log.d(TAG, "Recreating tiles");
         final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
-        if (tileSpecs.equals(mTileSpecs)) return;
+        int currentUser = ActivityManager.getCurrentUser();
+        if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;
         for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
             if (!tileSpecs.contains(tile.getKey())) {
                 if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
@@ -316,15 +331,16 @@
         }
         final LinkedHashMap<String, QSTile<?>> newTiles = new LinkedHashMap<>();
         for (String tileSpec : tileSpecs) {
-            if (mTiles.containsKey(tileSpec)) {
-                QSTile<?> tile = mTiles.get(tileSpec);
+            QSTile<?> tile = mTiles.get(tileSpec);
+            if (tile != null && (!(tile instanceof CustomTile)
+                    || ((CustomTile) tile).getUser() == currentUser)) {
                 if (DEBUG) Log.d(TAG, "Adding " + tile);
                 tile.removeCallbacks();
                 newTiles.put(tileSpec, tile);
             } else {
                 if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
                 try {
-                    QSTile<?> tile = createTile(tileSpec);
+                    tile = createTile(tileSpec);
                     if (tile != null && tile.isAvailable()) {
                         tile.setTileSpec(tileSpec);
                         newTiles.put(tileSpec, tile);
@@ -334,6 +350,7 @@
                 }
             }
         }
+        mCurrentUser = currentUser;
         mTileSpecs.clear();
         mTileSpecs.addAll(tileSpecs);
         mTiles.clear();
@@ -433,7 +450,7 @@
         }
     }
 
-    public static List<String> loadTileSpecs(Context context, String tileList) {
+    protected List<String> loadTileSpecs(Context context, String tileList) {
         final Resources res = context.getResources();
         final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
         if (tileList == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index ab8067d..f3aba4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
@@ -36,18 +35,17 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSAnimator;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.TouchAnimator;
-import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
 import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 import com.android.systemui.tuner.TunerService;
 
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
-        NextAlarmChangeCallback, OnClickListener, Listener {
+        NextAlarmChangeCallback, OnClickListener {
 
     private static final String TAG = "QuickStatusBarHeader";
 
@@ -70,7 +68,7 @@
     private ViewGroup mDateTimeAlarmGroup;
     private TextView mEmergencyOnly;
 
-    private ExpandableIndicator mExpandIndicator;
+    protected ExpandableIndicator mExpandIndicator;
 
     private boolean mListening;
     private AlarmManager.AlarmClockInfo mNextAlarm;
@@ -85,13 +83,13 @@
     private float mDateScaleFactor;
     private float mGearTranslation;
 
-    private TouchAnimator mAnimator;
     private TouchAnimator mSecondHalfAnimator;
     private TouchAnimator mFirstHalfAnimator;
     private TouchAnimator mDateSizeAnimator;
     private TouchAnimator mAlarmTranslation;
     private TouchAnimator mSettingsAlpha;
     private float mExpansionAmount;
+    private QSTileHost mHost;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -126,17 +124,8 @@
 
         // RenderThread is doing more harm than good when touching the header (to expand quick
         // settings), so disable it for this view
-        ((RippleDrawable) getBackground()).setForceSoftware(true);
         ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
 
-        addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-            @Override
-            public void onLayoutChange(View v, int left, int top, int right,
-                    int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                setClipBounds(new Rect(getPaddingLeft(), 0, getWidth() - getPaddingRight(),
-                        getHeight()));
-            }
-        });
         updateResources();
     }
 
@@ -146,6 +135,12 @@
         updateResources();
     }
 
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        updateResources();
+    }
+
     private void updateResources() {
         FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
         FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size);
@@ -163,13 +158,7 @@
         mDateScaleFactor = dateExpandedSize / dateCollapsedSize;
         updateDateTimePosition();
 
-        mAnimator = new TouchAnimator.Builder()
-                .addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0)
-                .addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0)
-                .setListener(this)
-                .build();
         mSecondHalfAnimator = new TouchAnimator.Builder()
-                .addFloat(mSettingsButton, "rotation", -180, 0)
                 .addFloat(mAlarmStatus, "alpha", 0, 1)
                 .addFloat(mEmergencyOnly, "alpha", 0, 1)
                 .setStartDelay(.5f)
@@ -184,10 +173,27 @@
                 .setStartDelay(.36f)
                 .build();
         mSettingsAlpha = new TouchAnimator.Builder()
+                .addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0)
+                .addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0)
+                .addFloat(mSettingsButton, "rotation", -90, 0)
                 .addFloat(mSettingsContainer, "alpha", 0, 1)
                 .addFloat(mMultiUserSwitch, "alpha", 0, 1)
                 .setStartDelay(QSAnimator.EXPANDED_TILE_DELAY)
                 .build();
+
+        final boolean isRtl = isLayoutRtl();
+        if (isRtl && mDateTimeGroup.getWidth() == 0) {
+            mDateTimeGroup.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) {
+                    mDateTimeGroup.setPivotX(getWidth());
+                    mDateTimeGroup.removeOnLayoutChangeListener(this);
+                }
+            });
+        } else {
+            mDateTimeGroup.setPivotX(isRtl ? mDateTimeGroup.getWidth() : 0);
+        }
     }
 
     @Override
@@ -221,7 +227,6 @@
     @Override
     public void setExpansion(float headerExpansionFraction) {
         mExpansionAmount = headerExpansionFraction;
-        mAnimator.setPosition(headerExpansionFraction);
         mSecondHalfAnimator.setPosition(headerExpansionFraction);
         mFirstHalfAnimator.setPosition(headerExpansionFraction);
         mDateSizeAnimator.setPosition(headerExpansionFraction);
@@ -234,17 +239,11 @@
     }
 
     @Override
-    public void onAnimationAtStart() {
-    }
-
-    @Override
-    public void onAnimationAtEnd() {
-        mHeaderQsPanel.setVisibility(View.INVISIBLE);
-    }
-
-    @Override
-    public void onAnimationStarted() {
-        mHeaderQsPanel.setVisibility(View.VISIBLE);
+    protected void onDetachedFromWindow() {
+        setListening(false);
+        mHost.getUserInfoController().remListener(mUserListener);
+        mHost.getNetworkController().removeEmergencyListener(this);
+        super.onDetachedFromWindow();
     }
 
     private void updateAlarmVisibilities() {
@@ -309,17 +308,18 @@
     }
 
     public void setupHost(final QSTileHost host) {
+        mHost = host;
         host.setHeaderView(this);
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
-        mHeaderQsPanel.setHost(host);
-        mHeaderQsPanel.setMaxTiles(5);
-        mHeaderQsPanel.setTiles(host.getTiles());
-        host.addCallback(new QSTile.Host.Callback() {
-            @Override
-            public void onTilesChanged() {
-                mHeaderQsPanel.setTiles(host.getTiles());
-            }
-        });
+        mHeaderQsPanel.setHost(host, null /* No customization in header */);
+        setUserInfoController(host.getUserInfoController());
+        setBatteryController(host.getBatteryController());
+        setNextAlarmController(host.getNextAlarmController());
+
+        final boolean isAPhone = mHost.getNetworkController().hasVoiceCallingFeature();
+        if (isAPhone) {
+            mHost.getNetworkController().addEmergencyListener(this);
+        }
     }
 
     @Override
@@ -365,12 +365,7 @@
 
     @Override
     public void setUserInfoController(UserInfoController userInfoController) {
-        userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
-            @Override
-            public void onUserInfoChanged(String name, Drawable picture) {
-                mMultiUserAvatar.setImageDrawable(picture);
-            }
-        });
+        userInfoController.addListener(mUserListener);
     }
 
     @Override
@@ -383,4 +378,11 @@
             }
         }
     }
+
+    private final OnUserInfoChangedListener mUserListener = new OnUserInfoChangedListener() {
+        @Override
+        public void onUserInfoChanged(String name, Drawable picture) {
+            mMultiUserAvatar.setImageDrawable(picture);
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f310c2c2..3eda320 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -30,7 +30,6 @@
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.ScrimView;
@@ -46,7 +45,6 @@
     public static final long ANIMATION_DURATION = 220;
     public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
             = new PathInterpolator(0f, 0, 0.7f, 1f);
-
     private static final float SCRIM_BEHIND_ALPHA = 0.62f;
     private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
     private static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
@@ -56,16 +54,20 @@
     private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
     private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
 
-    private final ScrimView mScrimBehind;
+    protected final ScrimView mScrimBehind;
     private final ScrimView mScrimInFront;
     private final UnlockMethodCache mUnlockMethodCache;
     private final View mHeadsUpScrim;
 
-    private boolean mKeyguardShowing;
+    private float mScrimBehindAlpha = SCRIM_BEHIND_ALPHA;
+    private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
+    private float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
+
+    protected boolean mKeyguardShowing;
     private float mFraction;
 
     private boolean mDarkenWhileDragging;
-    private boolean mBouncerShowing;
+    protected boolean mBouncerShowing;
     private boolean mWakeAndUnlocking;
     private boolean mAnimateChange;
     private boolean mUpdatePending;
@@ -75,8 +77,6 @@
     private long mAnimationDelay;
     private Runnable mOnAnimationFinished;
     private final Interpolator mInterpolator = new DecelerateInterpolator();
-    private BackDropView mBackDropView;
-    private boolean mScrimSrcEnabled;
     private boolean mDozing;
     private float mDozeInFrontAlpha;
     private float mDozeBehindAlpha;
@@ -89,15 +89,14 @@
     private boolean mForceHideScrims;
     private boolean mSkipFirstFrame;
     private boolean mDontAnimateBouncerChanges;
+    private boolean mKeyguardFadingOutInProgress;
 
-    public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
-            boolean scrimSrcEnabled) {
+    public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim) {
         mScrimBehind = scrimBehind;
         mScrimInFront = scrimInFront;
         mHeadsUpScrim = headsUpScrim;
         final Context context = scrimBehind.getContext();
         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
-        mScrimSrcEnabled = scrimSrcEnabled;
         updateHeadsUpScrim(false);
     }
 
@@ -106,6 +105,19 @@
         scheduleUpdate();
     }
 
+    public void setShowScrimBehind(boolean show) {
+        if (show) {
+            mScrimBehindAlpha = SCRIM_BEHIND_ALPHA;
+            mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
+            mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
+        } else {
+            mScrimBehindAlpha = 0;
+            mScrimBehindAlphaKeyguard = 0;
+            mScrimBehindAlphaUnlocking = 0;
+        }
+        scheduleUpdate();
+    }
+
     public void onTrackingStarted() {
         mExpanding = true;
         mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
@@ -203,7 +215,7 @@
         mUpdatePending = true;
     }
 
-    private void updateScrims() {
+    protected void updateScrims() {
         if (mAnimateKeyguardFadingOut || mForceHideScrims) {
             setScrimInFrontColor(0f);
             setScrimBehindColor(0f);
@@ -234,7 +246,7 @@
             fraction = (float) Math.pow(fraction, 0.8f);
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
             setScrimInFrontColor(fraction * SCRIM_IN_FRONT_ALPHA);
-            setScrimBehindColor(behindFraction * SCRIM_BEHIND_ALPHA_KEYGUARD);
+            setScrimBehindColor(behindFraction * mScrimBehindAlphaKeyguard);
         } else if (mBouncerShowing) {
             setScrimInFrontColor(SCRIM_IN_FRONT_ALPHA);
             setScrimBehindColor(0f);
@@ -242,8 +254,8 @@
             float fraction = Math.max(0, Math.min(mFraction, 1));
             setScrimInFrontColor(0f);
             setScrimBehindColor(fraction
-                    * (SCRIM_BEHIND_ALPHA_KEYGUARD - SCRIM_BEHIND_ALPHA_UNLOCKING)
-                    + SCRIM_BEHIND_ALPHA_UNLOCKING);
+                    * (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking)
+                    + mScrimBehindAlphaUnlocking);
         }
     }
 
@@ -256,7 +268,7 @@
         } else {
             // woo, special effects
             final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
-            setScrimBehindColor(k * SCRIM_BEHIND_ALPHA);
+            setScrimBehindColor(k * mScrimBehindAlpha);
         }
     }
 
@@ -331,12 +343,16 @@
                 if (mOnAnimationFinished != null) {
                     mOnAnimationFinished.run();
                     mOnAnimationFinished = null;
+                    mKeyguardFadingOutInProgress = false;
                 }
                 scrim.setTag(TAG_KEY_ANIM, null);
                 scrim.setTag(TAG_KEY_ANIM_TARGET, null);
             }
         });
         anim.start();
+        if (mAnimateKeyguardFadingOut) {
+            mKeyguardFadingOutInProgress = true;
+        }
         if (mSkipFirstFrame) {
             anim.setCurrentPlayTime(16);
         }
@@ -371,6 +387,7 @@
                 && mOnAnimationFinished != null) {
             mOnAnimationFinished.run();
             mOnAnimationFinished = null;
+            mKeyguardFadingOutInProgress = false;
         }
     }
 
@@ -378,19 +395,7 @@
         return scrim.getTag(TAG_KEY_ANIM) != null;
     }
 
-    public void setBackDropView(BackDropView backDropView) {
-        mBackDropView = backDropView;
-        mBackDropView.setOnVisibilityChangedRunnable(new Runnable() {
-            @Override
-            public void run() {
-                updateScrimBehindDrawingMode();
-            }
-        });
-        updateScrimBehindDrawingMode();
-    }
-
-    private void updateScrimBehindDrawingMode() {
-        boolean asSrc = mBackDropView.getVisibility() != View.VISIBLE && mScrimSrcEnabled;
+    public void setDrawBehindAsSrc(boolean asSrc) {
         mScrimBehind.setDrawAsSrc(asSrc);
     }
 
@@ -423,6 +428,10 @@
     }
 
     private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
+        if (mKeyguardFadingOutInProgress) {
+            return;
+        }
+
         ValueAnimator previousAnimator = StackStateAnimator.getChildTag(scrim,
                 TAG_KEY_ANIM);
         float animEndValue = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 3e3b169..a051973 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -39,7 +39,6 @@
 import android.widget.Switch;
 import android.widget.TextView;
 import android.widget.Toast;
-
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.FontSizeUtils;
@@ -48,7 +47,7 @@
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DetailAdapter;
 import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index f61f31e..a40aa83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -42,6 +42,7 @@
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
@@ -116,8 +117,8 @@
         mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
         mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
 
-        mNotificationIconAreaController =
-                new NotificationIconAreaController(context, phoneStatusBar);
+        mNotificationIconAreaController = SystemUIFactory.getInstance()
+                .createNotificationIconAreaController(context, phoneStatusBar);
         mNotificationIconAreaInner =
                 mNotificationIconAreaController.getNotificationInnerAreaView();
 
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 7a05b8f..117e2b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -212,6 +212,7 @@
 
     public void onScreenTurnedOff() {
         mScreenTurnedOn = false;
+        mPhoneStatusBar.onScreenTurnedOff();
     }
 
     public void notifyDeviceWakeUpRequested() {
@@ -226,6 +227,10 @@
         mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
     }
 
+    public boolean isUnlockWithWallpaper() {
+        return mStatusBarWindowManager.isShowingWallpaper();
+    }
+
     public void setOccluded(boolean occluded) {
         if (occluded && !mOccluded && mShowing) {
             if (mPhoneStatusBar.isInLaunchTransition()) {
@@ -509,8 +514,8 @@
         return !(mLastShowing && !mLastOccluded) || mLastBouncerShowing || mLastRemoteInputActive;
     }
 
-    public boolean onMenuPressed() {
-        return mBouncer.onMenuPressed();
+    public boolean shouldDismissOnMenuPressed() {
+        return mBouncer.shouldDismissOnMenuPressed();
     }
 
     public boolean interceptMediaKey(KeyEvent 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 fcaf050..b271380 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -100,12 +100,16 @@
 
     private void applyKeyguardFlags(State state) {
         if (state.keyguardShowing) {
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
             mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
         } else {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
             mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
         }
+
+        if (state.keyguardShowing && !state.backdropShowing) {
+            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+        } else {
+            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+        }
     }
 
     private void adjustScreenOrientation(State state) {
@@ -134,11 +138,7 @@
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         }
 
-        if (state.remoteInputActive) {
-            mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
-        } else {
-            mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-        }
+        mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
     }
 
     private void applyHeight(State state) {
@@ -173,7 +173,7 @@
     private void applyInputFeatures(State state) {
         if (state.isKeyguardShowingAndNotOccluded()
                 && state.statusBarState == StatusBarState.KEYGUARD
-                && !state.qsExpanded) {
+                && !state.qsExpanded && !state.forceUserActivity) {
             mLpChanged.inputFeatures |=
                     WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
         } else {
@@ -255,6 +255,11 @@
         apply(mCurrentState);
     }
 
+    public void setBackdropShowing(boolean showing) {
+        mCurrentState.backdropShowing = showing;
+        apply(mCurrentState);
+    }
+
     public void setKeyguardFadingAway(boolean keyguardFadingAway) {
         mCurrentState.keyguardFadingAway = keyguardFadingAway;
         apply(mCurrentState);
@@ -265,6 +270,11 @@
         apply(mCurrentState);
     }
 
+    public void setForceUserActivity(boolean forceUserActivity) {
+        mCurrentState.forceUserActivity = forceUserActivity;
+        apply(mCurrentState);
+    }
+
     public void setHeadsUpShowing(boolean showing) {
         mCurrentState.headsUpShowing = showing;
         apply(mCurrentState);
@@ -318,6 +328,10 @@
         pw.println(mCurrentState);
     }
 
+    public boolean isShowingWallpaper() {
+        return !mCurrentState.backdropShowing;
+    }
+
     private static class State {
         boolean keyguardShowing;
         boolean keyguardOccluded;
@@ -332,6 +346,8 @@
         boolean forceStatusBarVisible;
         boolean forceCollapsed;
         boolean forceDozeBrightness;
+        boolean forceUserActivity;
+        boolean backdropShowing;
 
         /**
          * The {@link BaseStatusBar} state from the status bar.
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 eb5b57e..ebfa018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -16,24 +16,42 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.LayoutRes;
 import android.app.StatusBarManager;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.media.session.MediaSessionLegacyHelper;
+import android.net.Uri;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.util.AttributeSet;
+import android.view.ActionMode;
+import android.view.InputQueue;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.SurfaceHolder;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.widget.FrameLayout;
 
+import com.android.internal.view.FloatingActionMode;
+import com.android.internal.widget.FloatingToolbar;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -57,6 +75,13 @@
     private final Paint mTransparentSrcPaint = new Paint();
     private FalsingManager mFalsingManager;
 
+    // Implements the floating action mode for TextView's Cut/Copy/Past menu. Normally provided by
+    // DecorView, but since this is a special window we have to roll our own.
+    private View mFloatingActionModeOriginatingView;
+    private ActionMode mFloatingActionMode;
+    private FloatingToolbar mFloatingToolbar;
+    private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
+
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setMotionEventSplittingEnabled(false);
@@ -201,6 +226,10 @@
                 return false;
             }
         }
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mStackScrollLayout.closeControlsIfOutsideTouch(ev);
+        }
+
         return super.dispatchTouchEvent(ev);
     }
 
@@ -301,5 +330,341 @@
             a.recycle();
         }
     }
+
+    @Override
+    public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback,
+            int type) {
+        if (type == ActionMode.TYPE_FLOATING) {
+            return startActionMode(originalView, callback, type);
+        }
+        return super.startActionModeForChild(originalView, callback, type);
+    }
+
+    private ActionMode createFloatingActionMode(
+            View originatingView, ActionMode.Callback2 callback) {
+        if (mFloatingActionMode != null) {
+            mFloatingActionMode.finish();
+        }
+        cleanupFloatingActionModeViews();
+        final FloatingActionMode mode =
+                new FloatingActionMode(mContext, callback, originatingView);
+        mFloatingActionModeOriginatingView = originatingView;
+        mFloatingToolbarPreDrawListener =
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        mode.updateViewLocationInWindow();
+                        return true;
+                    }
+                };
+        return mode;
+    }
+
+    private void setHandledFloatingActionMode(ActionMode mode) {
+        mFloatingActionMode = mode;
+        mFloatingToolbar = new FloatingToolbar(mContext, mFakeWindow);
+        ((FloatingActionMode) mFloatingActionMode).setFloatingToolbar(mFloatingToolbar);
+        mFloatingActionMode.invalidate();  // Will show the floating toolbar if necessary.
+        mFloatingActionModeOriginatingView.getViewTreeObserver()
+                .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
+    }
+
+    private void cleanupFloatingActionModeViews() {
+        if (mFloatingToolbar != null) {
+            mFloatingToolbar.dismiss();
+            mFloatingToolbar = null;
+        }
+        if (mFloatingActionModeOriginatingView != null) {
+            if (mFloatingToolbarPreDrawListener != null) {
+                mFloatingActionModeOriginatingView.getViewTreeObserver()
+                        .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
+                mFloatingToolbarPreDrawListener = null;
+            }
+            mFloatingActionModeOriginatingView = null;
+        }
+    }
+
+    private ActionMode startActionMode(
+            View originatingView, ActionMode.Callback callback, int type) {
+        ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
+        ActionMode mode = createFloatingActionMode(originatingView, wrappedCallback);
+        if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
+            setHandledFloatingActionMode(mode);
+        } else {
+            mode = null;
+        }
+        return mode;
+    }
+
+    private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
+        private final ActionMode.Callback mWrapped;
+
+        public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
+            mWrapped = wrapped;
+        }
+
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            return mWrapped.onCreateActionMode(mode, menu);
+        }
+
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            requestFitSystemWindows();
+            return mWrapped.onPrepareActionMode(mode, menu);
+        }
+
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            return mWrapped.onActionItemClicked(mode, item);
+        }
+
+        public void onDestroyActionMode(ActionMode mode) {
+            mWrapped.onDestroyActionMode(mode);
+            if (mode == mFloatingActionMode) {
+                cleanupFloatingActionModeViews();
+                mFloatingActionMode = null;
+            }
+            requestFitSystemWindows();
+        }
+
+        @Override
+        public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
+            if (mWrapped instanceof ActionMode.Callback2) {
+                ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
+            } else {
+                super.onGetContentRect(mode, view, outRect);
+            }
+        }
+    }
+
+    /**
+     * Minimal window to satisfy FloatingToolbar.
+     */
+    private Window mFakeWindow = new Window(mContext) {
+        @Override
+        public void takeSurface(SurfaceHolder.Callback2 callback) {
+        }
+
+        @Override
+        public void takeInputQueue(InputQueue.Callback callback) {
+        }
+
+        @Override
+        public boolean isFloating() {
+            return false;
+        }
+
+        @Override
+        public void alwaysReadCloseOnTouchAttr() {
+        }
+
+        @Override
+        public void setContentView(@LayoutRes int layoutResID) {
+        }
+
+        @Override
+        public void setContentView(View view) {
+        }
+
+        @Override
+        public void setContentView(View view, ViewGroup.LayoutParams params) {
+        }
+
+        @Override
+        public void addContentView(View view, ViewGroup.LayoutParams params) {
+        }
+
+        @Override
+        public void clearContentView() {
+        }
+
+        @Override
+        public View getCurrentFocus() {
+            return null;
+        }
+
+        @Override
+        public LayoutInflater getLayoutInflater() {
+            return null;
+        }
+
+        @Override
+        public void setTitle(CharSequence title) {
+        }
+
+        @Override
+        public void setTitleColor(@ColorInt int textColor) {
+        }
+
+        @Override
+        public void openPanel(int featureId, KeyEvent event) {
+        }
+
+        @Override
+        public void closePanel(int featureId) {
+        }
+
+        @Override
+        public void togglePanel(int featureId, KeyEvent event) {
+        }
+
+        @Override
+        public void invalidatePanelMenu(int featureId) {
+        }
+
+        @Override
+        public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
+            return false;
+        }
+
+        @Override
+        public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
+            return false;
+        }
+
+        @Override
+        public void closeAllPanels() {
+        }
+
+        @Override
+        public boolean performContextMenuIdentifierAction(int id, int flags) {
+            return false;
+        }
+
+        @Override
+        public void onConfigurationChanged(Configuration newConfig) {
+        }
+
+        @Override
+        public void setBackgroundDrawable(Drawable drawable) {
+        }
+
+        @Override
+        public void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
+        }
+
+        @Override
+        public void setFeatureDrawableUri(int featureId, Uri uri) {
+        }
+
+        @Override
+        public void setFeatureDrawable(int featureId, Drawable drawable) {
+        }
+
+        @Override
+        public void setFeatureDrawableAlpha(int featureId, int alpha) {
+        }
+
+        @Override
+        public void setFeatureInt(int featureId, int value) {
+        }
+
+        @Override
+        public void takeKeyEvents(boolean get) {
+        }
+
+        @Override
+        public boolean superDispatchKeyEvent(KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean superDispatchTouchEvent(MotionEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean superDispatchTrackballEvent(MotionEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean superDispatchGenericMotionEvent(MotionEvent event) {
+            return false;
+        }
+
+        @Override
+        public View getDecorView() {
+            return StatusBarWindowView.this;
+        }
+
+        @Override
+        public View peekDecorView() {
+            return null;
+        }
+
+        @Override
+        public Bundle saveHierarchyState() {
+            return null;
+        }
+
+        @Override
+        public void restoreHierarchyState(Bundle savedInstanceState) {
+        }
+
+        @Override
+        protected void onActive() {
+        }
+
+        @Override
+        public void setChildDrawable(int featureId, Drawable drawable) {
+        }
+
+        @Override
+        public void setChildInt(int featureId, int value) {
+        }
+
+        @Override
+        public boolean isShortcutKey(int keyCode, KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public void setVolumeControlStream(int streamType) {
+        }
+
+        @Override
+        public int getVolumeControlStream() {
+            return 0;
+        }
+
+        @Override
+        public int getStatusBarColor() {
+            return 0;
+        }
+
+        @Override
+        public void setStatusBarColor(@ColorInt int color) {
+        }
+
+        @Override
+        public int getNavigationBarColor() {
+            return 0;
+        }
+
+        @Override
+        public void setNavigationBarColor(@ColorInt int color) {
+        }
+
+        @Override
+        public void setDecorCaptionShade(int decorCaptionShade) {
+        }
+
+        @Override
+        public void setResizingCaptionDrawable(Drawable drawable) {
+        }
+
+        @Override
+        public void onMultiWindowModeChanged() {
+        }
+
+        @Override
+        public void reportActivityRelaunched() {
+        }
+    };
+
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 0442ac3..2783ec5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -37,22 +37,14 @@
         super(context, theme);
         mContext = context;
 
-        getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        applyFlags(this);
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
         attrs.setTitle(getClass().getSimpleName());
         getWindow().setAttributes(attrs);
     }
 
     public void setShowForAllUsers(boolean show) {
-        if (show) {
-            getWindow().getAttributes().privateFlags |=
-                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-        } else {
-            getWindow().getAttributes().privateFlags &=
-                    ~WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-        }
+        setShowForAllUsers(this, show);
     }
 
     public void setMessage(int resId) {
@@ -66,4 +58,20 @@
     public void setNegativeButton(int resId, OnClickListener onClick) {
         setButton(BUTTON_NEGATIVE, mContext.getString(resId), onClick);
     }
+
+    public static void setShowForAllUsers(AlertDialog dialog, boolean show) {
+        if (show) {
+            dialog.getWindow().getAttributes().privateFlags |=
+                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        } else {
+            dialog.getWindow().getAttributes().privateFlags &=
+                    ~WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        }
+    }
+
+    public static void applyFlags(AlertDialog dialog) {
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
+        dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 3bd68a9..ab34768 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -80,13 +80,13 @@
 
         // Original is slightly larger than the mirror, so make sure to use the center for the
         // positioning.
-        int originalX = mInt2Cache[0] + original.getWidth()/2;
-        int originalY = mInt2Cache[1];
+        int originalX = mInt2Cache[0] + original.getWidth() / 2;
+        int originalY = mInt2Cache[1] + original.getHeight() / 2;
         mBrightnessMirror.setTranslationX(0);
         mBrightnessMirror.setTranslationY(0);
         mBrightnessMirror.getLocationInWindow(mInt2Cache);
-        int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth()/2;
-        int mirrorY = mInt2Cache[1];
+        int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth() / 2;
+        int mirrorY = mInt2Cache[1] + mBrightnessMirror.getHeight() / 2;
         mBrightnessMirror.setTranslationX(originalX - mirrorX);
         mBrightnessMirror.setTranslationY(originalY - mirrorY);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index e618cb8..3142ddf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -19,11 +19,10 @@
 import android.os.Looper;
 import android.os.Message;
 import android.telephony.SubscriptionInfo;
-
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
index 186e8b5..6dd196b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
@@ -60,6 +60,10 @@
 
     public void setDataSaverEnabled(boolean enabled) {
         mPolicyManager.setRestrictBackground(enabled);
+        try {
+            mPolicyListener.onRestrictBackgroundChanged(enabled);
+        } catch (RemoteException e) {
+        }
     }
 
     private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
index bd36462..159bd41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
@@ -19,6 +19,7 @@
 import android.net.NetworkCapabilities;
 
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.util.BitSet;
 
@@ -46,12 +47,12 @@
     }
 
     @Override
-    public void notifyListeners() {
+    public void notifyListeners(SignalCallback callback) {
         boolean ethernetVisible = mCurrentState.connected;
         String contentDescription = getStringIfExists(getContentDescription());
 
         // TODO: wire up data transfer using WifiSignalPoller.
-        mCallbackHandler.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
+        callback.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
                 contentDescription));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 29a8f67..9a21a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -93,6 +93,10 @@
         }
     }
 
+    public boolean hasFlashlight() {
+        return mCameraId != null;
+    }
+
     public synchronized boolean isEnabled() {
         return mFlashlightEnabled;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index f03d9e9..c6b1cdf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -69,18 +69,22 @@
 
     @Override
     public void addCallback(Callback callback) {
-        if (callback == null || mCallbacks.contains(callback)) return;
-        if (DEBUG) Log.d(TAG, "addCallback " + callback);
-        mCallbacks.add(callback);
-        mReceiver.setListening(!mCallbacks.isEmpty());
+        synchronized (mCallbacks) {
+            if (callback == null || mCallbacks.contains(callback)) return;
+            if (DEBUG) Log.d(TAG, "addCallback " + callback);
+            mCallbacks.add(callback);
+            mReceiver.setListening(!mCallbacks.isEmpty());
+        }
     }
 
     @Override
     public void removeCallback(Callback callback) {
         if (callback == null) return;
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
-        mCallbacks.remove(callback);
-        mReceiver.setListening(!mCallbacks.isEmpty());
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
+            mReceiver.setListening(!mCallbacks.isEmpty());
+        }
     }
 
     @Override
@@ -110,8 +114,10 @@
     }
 
     private void fireCallback(boolean isEnabled) {
-        for (Callback callback : mCallbacks) {
-            callback.onHotspotChanged(isEnabled);
+        synchronized (mCallbacks) {
+            for (Callback callback : mCallbacks) {
+                callback.onHotspotChanged(isEnabled);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 867a8a3..fb310a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -21,6 +21,8 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.database.DataSetObserver;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -242,7 +244,6 @@
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             UserSwitcherController.UserRecord item = getItem(position);
-
             if (!(convertView instanceof UserDetailItemView)
                     || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
                 convertView = LayoutInflater.from(mContext).inflate(
@@ -252,11 +253,17 @@
             UserDetailItemView v = (UserDetailItemView) convertView;
 
             String name = getName(mContext, item);
+            Drawable drawable;
             if (item.picture == null) {
-                v.bind(name, getDrawable(mContext, item));
+                drawable = getDrawable(mContext, item).mutate();
             } else {
-                v.bind(name, item.picture);
+                drawable = new BitmapDrawable(mContext.getResources(), item.picture);
             }
+            // Disable the icon if switching is disabled
+            if (!item.isSwitchToEnabled) {
+                drawable.setTint(mContext.getColor(R.color.qs_tile_disabled_color));
+            }
+            v.bind(name, drawable);
             convertView.setActivated(item.isCurrent);
             convertView.setTag(item);
             return convertView;
@@ -269,7 +276,7 @@
                 // Close the switcher if tapping the current user. Guest is excluded because
                 // tapping the guest user while it's current clears the session.
                 mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
-            } else {
+            } else if (user.isSwitchToEnabled) {
                 switchTo(user);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 8fd4d9c..80dcfb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -34,6 +34,7 @@
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
 
@@ -198,7 +199,7 @@
     }
 
     @Override
-    public void notifyListeners() {
+    public void notifyListeners(SignalCallback callback) {
         MobileIconGroup icons = getIcons();
 
         String contentDescription = getStringIfExists(getContentDescription());
@@ -231,7 +232,7 @@
                 || mCurrentState.iconGroup == TelephonyIcons.ROAMING
                 || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
         int typeIcon = showDataIcon ? icons.mDataType : 0;
-        mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+        callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
                 activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
                 mSubscriptionInfo.getSubscriptionId());
     }
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 93c7322..348e0b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.telephony.SubscriptionInfo;
-
 import com.android.settingslib.net.DataUsageController;
 import com.android.settingslib.wifi.AccessPoint;
 
@@ -36,6 +35,11 @@
     DataUsageController getMobileDataController();
     DataSaverController getDataSaverController();
 
+    boolean hasVoiceCallingFeature();
+
+    void addEmergencyListener(EmergencyListener listener);
+    void removeEmergencyListener(EmergencyListener listener);
+
     public interface SignalCallback {
         void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
                 boolean activityIn, boolean activityOut, String description);
@@ -53,6 +57,10 @@
         void setMobileDataEnabled(boolean enabled);
     }
 
+    public interface EmergencyListener {
+        void setEmergencyCallsOnly(boolean emergencyOnly);
+    }
+
     public static class IconState {
         public final boolean visible;
         public final int icon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index eecf8c2..40eb71d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -252,6 +252,10 @@
         mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
     }
 
+    public void removeEmergencyListener(EmergencyListener listener) {
+        mCallbackHandler.setListening(listener, false);
+    }
+
     public boolean hasMobileDataFeature() {
         return mHasMobileDataFeature;
     }
@@ -318,16 +322,16 @@
     }
 
     public void addSignalCallback(SignalCallback cb) {
-        mCallbackHandler.setListening(cb, true);
-        mCallbackHandler.setSubs(mCurrentSubscriptions);
-        mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
+        cb.setSubs(mCurrentSubscriptions);
+        cb.setIsAirplaneMode(new IconState(mAirplaneMode,
                 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
-        mCallbackHandler.setNoSims(mHasNoSims);
-        mWifiSignalController.notifyListeners();
-        mEthernetSignalController.notifyListeners();
+        cb.setNoSims(mHasNoSims);
+        mWifiSignalController.notifyListeners(cb);
+        mEthernetSignalController.notifyListeners(cb);
         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
-            mobileSignalController.notifyListeners();
+            mobileSignalController.notifyListeners(cb);
         }
+        mCallbackHandler.setListening(cb, true);
     }
 
     @Override
@@ -812,10 +816,6 @@
         }
     };
 
-    public interface EmergencyListener {
-        void setEmergencyCallsOnly(boolean emergencyOnly);
-    }
-
     public static class SubscriptionDefaults {
         public int getDefaultVoiceSubId() {
             return SubscriptionManager.getDefaultVoiceSubscriptionId();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
index 0b1911b..4611ef9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
@@ -14,17 +14,13 @@
 
 package com.android.systemui.statusbar.policy;
 
-import libcore.util.Objects;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.opengl.Matrix;
-import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.util.MathUtils;
-
 import com.android.systemui.tuner.TunerService;
 
 import java.util.ArrayList;
@@ -189,8 +185,8 @@
     }
 
     private void updateNightMode(Intent intent) {
-        mIsNight = intent.getBooleanExtra(EXTRA_IS_NIGHT, false);
-        mAmount = intent.getFloatExtra(EXTRA_AMOUNT, 0);
+        mIsNight = intent != null && intent.getBooleanExtra(EXTRA_IS_NIGHT, false);
+        mAmount = intent != null ? intent.getFloatExtra(EXTRA_AMOUNT, 0) : 0;
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index c6659d1..557f166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -29,8 +29,10 @@
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -44,6 +46,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.stack.ScrollContainer;
 
 /**
  * Host for the remote input.
@@ -65,6 +68,9 @@
 
     private NotificationData.Entry mEntry;
 
+    private ScrollContainer mScrollContainer;
+    private View mScrollContainerChild;
+
     public RemoteInputView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -102,7 +108,7 @@
         mEditText.setOnClickListener(this);
         mEditText.addTextChangedListener(this);
         mEditText.setInnerFocusable(false);
-        mEditText.mDefocusListener = this;
+        mEditText.mRemoteInputView = this;
     }
 
     private void sendRemoteInput() {
@@ -115,8 +121,11 @@
         mEditText.setEnabled(false);
         mSendButton.setVisibility(INVISIBLE);
         mProgressBar.setVisibility(VISIBLE);
+        mEntry.remoteInputText = mEditText.getText();
+        mController.addSpinning(mEntry.key);
         mController.removeRemoteInput(mEntry);
         mEditText.mShowImeOnInputConnection = false;
+        mController.remoteInputSent(mEntry);
 
         try {
             mPendingIntent.send(mContext, 0, fillInIntent);
@@ -155,9 +164,23 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (mEntry.row.isChangingPosition()) {
+            if (getVisibility() == VISIBLE && mEditText.isFocusable()) {
+                mEditText.requestFocus();
+            }
+        }
+    }
+
+    @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
+        if (mEntry.row.isChangingPosition()) {
+            return;
+        }
         mController.removeRemoteInput(mEntry);
+        mController.removeSpinning(mEntry.key);
     }
 
     public void setPendingIntent(PendingIntent pendingIntent) {
@@ -194,6 +217,7 @@
         mEditText.setEnabled(true);
         mSendButton.setVisibility(VISIBLE);
         mProgressBar.setVisibility(INVISIBLE);
+        mController.removeSpinning(mEntry.key);
         updateSendButton();
         onDefocus();
     }
@@ -213,6 +237,41 @@
         updateSendButton();
     }
 
+    public void close() {
+        mEditText.defocusIfNeeded();
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            findScrollContainer();
+            if (mScrollContainer != null) {
+                mScrollContainer.requestDisallowLongPress();
+            }
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+
+    public boolean requestScrollTo() {
+        findScrollContainer();
+        mScrollContainer.scrollTo(mScrollContainerChild);
+        return true;
+    }
+
+    private void findScrollContainer() {
+        if (mScrollContainer == null) {
+            ViewParent p = this;
+            while (p != null) {
+                if (p.getParent() instanceof ScrollContainer) {
+                    mScrollContainer = (ScrollContainer) p.getParent();
+                    mScrollContainerChild = (View) p;
+                    break;
+                }
+                p = p.getParent();
+            }
+        }
+    }
+
     /**
      * An EditText that changes appearance based on whether it's focusable and becomes
      * un-focusable whenever the user navigates away from it or it becomes invisible.
@@ -220,7 +279,7 @@
     public static class RemoteEditText extends EditText {
 
         private final Drawable mBackground;
-        private RemoteInputView mDefocusListener;
+        private RemoteInputView mRemoteInputView;
         boolean mShowImeOnInputConnection;
 
         public RemoteEditText(Context context, AttributeSet attrs) {
@@ -229,10 +288,13 @@
         }
 
         private void defocusIfNeeded() {
+            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) {
+                return;
+            }
             if (isFocusable() && isEnabled()) {
                 setInnerFocusable(false);
-                if (mDefocusListener != null) {
-                    mDefocusListener.onDefocus();
+                if (mRemoteInputView != null) {
+                    mRemoteInputView.onDefocus();
                 }
                 mShowImeOnInputConnection = false;
             }
@@ -248,16 +310,11 @@
         }
 
         @Override
-        protected void onFocusLost() {
-            super.onFocusLost();
-            defocusIfNeeded();
-        }
-
-        @Override
-        public boolean requestRectangleOnScreen(Rect r) {
-            r.top = mScrollY;
-            r.bottom = mScrollY + (mBottom - mTop);
-            return super.requestRectangleOnScreen(r);
+        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+            super.onFocusChanged(focused, direction, previouslyFocusedRect);
+            if (!focused) {
+                defocusIfNeeded();
+            }
         }
 
         @Override
@@ -268,6 +325,11 @@
         }
 
         @Override
+        public boolean requestRectangleOnScreen(Rect rectangle) {
+            return mRemoteInputView.requestScrollTo();
+        }
+
+        @Override
         public boolean onKeyPreIme(int keyCode, KeyEvent event) {
             if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
                 defocusIfNeeded();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index c954d08..4cfd1c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.text.format.DateFormat;
 import android.util.Log;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.io.PrintWriter;
 import java.util.BitSet;
@@ -48,7 +49,7 @@
     // is aware of current state.
     protected final NetworkControllerImpl mNetworkController;
 
-    protected final CallbackHandler mCallbackHandler;
+    private final CallbackHandler mCallbackHandler;
 
     // Save the previous HISTORY_SIZE states for logging.
     private final State[] mHistory;
@@ -198,12 +199,16 @@
         }
     }
 
+    public final void notifyListeners() {
+        notifyListeners(mCallbackHandler);
+    }
+
     /**
      * Trigger callbacks based on current state.  The callbacks should be completely
      * based on current state, and only need to be called in the scenario where
      * mCurrentState != mLastState.
      */
-    public abstract void notifyListeners();
+    public abstract void notifyListeners(SignalCallback callback);
 
     /**
      * Generate a blank T.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 13369f2..ea0bdf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -23,6 +23,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -37,6 +38,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -50,6 +53,7 @@
 import com.android.systemui.BitmapHelper;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.R;
+import com.android.systemui.SystemUISecondaryUserService;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.tiles.UserDetailView;
 import com.android.systemui.statusbar.phone.ActivityStarter;
@@ -99,6 +103,8 @@
     private boolean mSimpleUserSwitcher;
     private boolean mAddUsersWhenLocked;
     private boolean mPauseRefreshUsers;
+    private int mSecondaryUser = UserHandle.USER_NULL;
+    private Intent mSecondaryUserServiceIntent;
     private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
 
     public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
@@ -115,9 +121,12 @@
         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_STOPPING);
+        filter.addAction(Intent.ACTION_USER_UNLOCKED);
         mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
                 null /* permission */, null /* scheduler */);
 
+        mSecondaryUserServiceIntent = new Intent(context, SystemUISecondaryUserService.class);
+
         filter = new IntentFilter();
         filter.addAction(ACTION_REMOVE_GUEST);
         filter.addAction(ACTION_LOGOUT_USER);
@@ -130,10 +139,15 @@
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
                 mSettingsObserver);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(
+                        Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED),
+                true, mSettingsObserver);
         // Fetch initial values.
         mSettingsObserver.onChange(false);
 
         keyguardMonitor.addCallback(mCallback);
+        listenForCallState();
 
         refreshUsers(UserHandle.USER_NULL);
     }
@@ -180,6 +194,7 @@
                 }
                 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
                 int currentId = ActivityManager.getCurrentUser();
+                boolean canSwitchUsers = mUserManager.canSwitchUsers();
                 UserInfo currentUserInfo = null;
                 UserRecord guestRecord = null;
                 int avatarSize = mContext.getResources()
@@ -190,23 +205,29 @@
                     if (isCurrent) {
                         currentUserInfo = info;
                     }
-                    if (info.isGuest()) {
-                        guestRecord = new UserRecord(info, null /* picture */,
-                                true /* isGuest */, isCurrent, false /* isAddUser */,
-                                false /* isRestricted */);
-                    } else if (info.isEnabled() && info.supportsSwitchToByUser()) {
-                        Bitmap picture = bitmaps.get(info.id);
-                        if (picture == null) {
-                            picture = mUserManager.getUserIcon(info.id);
+                    boolean switchToEnabled = canSwitchUsers || isCurrent;
+                    if (info.isEnabled()) {
+                        if (info.isGuest()) {
+                            // Tapping guest icon triggers remove and a user switch therefore
+                            // the icon shouldn't be enabled even if the user is current
+                            guestRecord = new UserRecord(info, null /* picture */,
+                                    true /* isGuest */, isCurrent, false /* isAddUser */,
+                                    false /* isRestricted */, canSwitchUsers);
+                        } else if (info.supportsSwitchToByUser()) {
+                            Bitmap picture = bitmaps.get(info.id);
+                            if (picture == null) {
+                                picture = mUserManager.getUserIcon(info.id);
 
-                            if (picture != null) {
-                                picture = BitmapHelper.createCircularClip(
-                                        picture, avatarSize, avatarSize);
+                                if (picture != null) {
+                                    picture = BitmapHelper.createCircularClip(
+                                            picture, avatarSize, avatarSize);
+                                }
                             }
+                            int index = isCurrent ? 0 : records.size();
+                            records.add(index, new UserRecord(info, picture, false /* isGuest */,
+                                    isCurrent, false /* isAddUser */, false /* isRestricted */,
+                                    switchToEnabled));
                         }
-                        int index = isCurrent ? 0 : records.size();
-                        records.add(index, new UserRecord(info, picture, false /* isGuest */,
-                                isCurrent, false /* isAddUser */, false /* isRestricted */));
                     }
                 }
 
@@ -228,7 +249,7 @@
                         if (canCreateGuest) {
                             guestRecord = new UserRecord(null /* info */, null /* picture */,
                                     true /* isGuest */, false /* isCurrent */,
-                                    false /* isAddUser */, createIsRestricted);
+                                    false /* isAddUser */, createIsRestricted, canSwitchUsers);
                             checkIfAddUserDisallowedByAdminOnly(guestRecord);
                             records.add(guestRecord);
                         }
@@ -241,7 +262,7 @@
                 if (!mSimpleUserSwitcher && canCreateUser) {
                     UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
                             false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
-                            createIsRestricted);
+                            createIsRestricted, canSwitchUsers);
                     checkIfAddUserDisallowedByAdminOnly(addUserRecord);
                     records.add(addUserRecord);
                 }
@@ -300,8 +321,8 @@
     public void logoutCurrentUser() {
         int currentUser = ActivityManager.getCurrentUser();
         if (currentUser != UserHandle.USER_SYSTEM) {
-            switchToUserId(UserHandle.USER_SYSTEM);
-            stopUserId(currentUser);
+            pauseRefreshUsers();
+            ActivityManager.logoutCurrentUser();
         }
     }
 
@@ -369,14 +390,6 @@
         }
     }
 
-    private void stopUserId(int id) {
-        try {
-            ActivityManagerNative.getDefault().stopUser(id, /* force= */ false, null);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't stop user.", e);
-        }
-    }
-
     private void showExitGuestDialog(int id) {
         if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
             mExitGuestDialog.cancel();
@@ -405,6 +418,24 @@
         mUserManager.removeUser(id);
     }
 
+    private void listenForCallState() {
+        TelephonyManager.from(mContext).listen(new PhoneStateListener() {
+            private int mCallState;
+            @Override
+            public void onCallStateChanged(int state, String incomingNumber) {
+                if (mCallState == state) return;
+                if (DEBUG) Log.v(TAG, "Call state changed: " + state);
+                mCallState = state;
+                int currentUserId = ActivityManager.getCurrentUser();
+                UserInfo userInfo = mUserManager.getUserInfo(currentUserId);
+                if (userInfo != null && userInfo.isGuest()) {
+                    showGuestNotification(currentUserId);
+                }
+                refreshUsers(UserHandle.USER_NULL);
+            }
+        }, PhoneStateListener.LISTEN_CALL_STATE);
+    }
+
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -452,6 +483,20 @@
                 }
                 notifyAdapters();
 
+                // Disconnect from the old secondary user's service
+                if (mSecondaryUser != UserHandle.USER_NULL) {
+                    context.stopServiceAsUser(mSecondaryUserServiceIntent,
+                            UserHandle.of(mSecondaryUser));
+                    mSecondaryUser = UserHandle.USER_NULL;
+                }
+                // Connect to the new secondary user's service (purely to ensure that a persistent
+                // SystemUI application is created for that user)
+                if (userInfo != null && !userInfo.isPrimary()) {
+                    context.startServiceAsUser(mSecondaryUserServiceIntent,
+                            UserHandle.of(userInfo.id));
+                    mSecondaryUser = userInfo.id;
+                }
+
                 if (UserManager.isSplitSystemUser() && userInfo != null && !userInfo.isGuest()
                         && userInfo.id != UserHandle.USER_SYSTEM) {
                     showLogoutNotification(currentId);
@@ -463,6 +508,12 @@
             } else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
                 forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                         UserHandle.USER_NULL);
+            } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+                // Unlocking the system user may require a refresh
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                if (userId != UserHandle.USER_SYSTEM) {
+                    return;
+                }
             }
             refreshUsers(forcePictureLoadForId);
             if (unpauseRefreshUsers) {
@@ -470,25 +521,6 @@
             }
         }
 
-        private void showGuestNotification(int guestUserId) {
-            PendingIntent removeGuestPI = PendingIntent.getBroadcastAsUser(mContext,
-                    0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM);
-            Notification notification = new Notification.Builder(mContext)
-                    .setVisibility(Notification.VISIBILITY_SECRET)
-                    .setPriority(Notification.PRIORITY_MIN)
-                    .setSmallIcon(R.drawable.ic_person)
-                    .setContentTitle(mContext.getString(R.string.guest_notification_title))
-                    .setContentText(mContext.getString(R.string.guest_notification_text))
-                    .setContentIntent(removeGuestPI)
-                    .setShowWhen(false)
-                    .addAction(R.drawable.ic_delete,
-                            mContext.getString(R.string.guest_notification_remove_action),
-                            removeGuestPI)
-                    .build();
-            NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
-                    notification, new UserHandle(guestUserId));
-        }
-
         private void showLogoutNotification(int userId) {
             PendingIntent logoutPI = PendingIntent.getBroadcastAsUser(mContext,
                     0, new Intent(ACTION_LOGOUT_USER), 0, UserHandle.SYSTEM);
@@ -510,6 +542,28 @@
         }
     };
 
+    private void showGuestNotification(int guestUserId) {
+        boolean canSwitchUsers = mUserManager.canSwitchUsers();
+        // Disable 'Remove guest' action if cannot switch users right now
+        PendingIntent removeGuestPI = canSwitchUsers ? PendingIntent.getBroadcastAsUser(mContext,
+                0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM) : null;
+
+        Notification notification = new Notification.Builder(mContext)
+                .setVisibility(Notification.VISIBILITY_SECRET)
+                .setPriority(Notification.PRIORITY_MIN)
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle(mContext.getString(R.string.guest_notification_title))
+                .setContentText(mContext.getString(R.string.guest_notification_text))
+                .setContentIntent(removeGuestPI)
+                .setShowWhen(false)
+                .addAction(R.drawable.ic_delete,
+                        mContext.getString(R.string.guest_notification_remove_action),
+                        removeGuestPI)
+                .build();
+        NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
+                notification, new UserHandle(guestUserId));
+    }
+
     private final Runnable mUnpauseRefreshUsers = new Runnable() {
         @Override
         public void run() {
@@ -646,26 +700,29 @@
         public final boolean isRestricted;
         public boolean isDisabledByAdmin;
         public EnforcedAdmin enforcedAdmin;
+        public boolean isSwitchToEnabled;
 
         public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
-                boolean isAddUser, boolean isRestricted) {
+                boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) {
             this.info = info;
             this.picture = picture;
             this.isGuest = isGuest;
             this.isCurrent = isCurrent;
             this.isAddUser = isAddUser;
             this.isRestricted = isRestricted;
+            this.isSwitchToEnabled = isSwitchToEnabled;
         }
 
         public UserRecord copyWithIsCurrent(boolean _isCurrent) {
-            return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
+            return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
+                    isSwitchToEnabled);
         }
 
         public String toString() {
             StringBuilder sb = new StringBuilder();
             sb.append("UserRecord(");
             if (info != null) {
-                sb.append("name=\"" + info.name + "\" id=" + info.id);
+                sb.append("name=\"").append(info.name).append("\" id=").append(info.id);
             } else {
                 if (isGuest) {
                     sb.append("<add guest placeholder>");
@@ -680,7 +737,10 @@
             if (isRestricted) sb.append(" <isRestricted>");
             if (isDisabledByAdmin) {
                 sb.append(" <isDisabledByAdmin>");
-                sb.append(" enforcedAdmin=" + enforcedAdmin);
+                sb.append(" enforcedAdmin=").append(enforcedAdmin);
+            }
+            if (isSwitchToEnabled) {
+                sb.append(" <isSwitchToEnabled>");
             }
             sb.append(')');
             return sb.toString();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index cc98eb6..a6ed04f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -28,6 +28,7 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.settingslib.wifi.WifiStatusTracker;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.util.Objects;
 
@@ -72,7 +73,7 @@
     }
 
     @Override
-    public void notifyListeners() {
+    public void notifyListeners(SignalCallback callback) {
         // only show wifi in the cluster if connected or if wifi-only
         boolean wifiVisible = mCurrentState.enabled
                 && (mCurrentState.connected || !mHasMobileData);
@@ -83,7 +84,7 @@
         IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
         IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
                 contentDescription);
-        mCallbackHandler.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+        callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
                 ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
                 wifiDesc);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 49aec42..ee483e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -22,13 +22,15 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.HybridGroupManager;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
-import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 import java.util.ArrayList;
@@ -45,21 +47,22 @@
 
     private final List<View> mDividers = new ArrayList<>();
     private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
-    private final HybridNotificationViewManager mHybridViewManager;
+    private final HybridGroupManager mHybridGroupManager;
     private int mChildPadding;
     private int mDividerHeight;
     private int mMaxNotificationHeight;
     private int mNotificationHeaderHeight;
-    private int mNotificationAppearDistance;
     private int mNotificatonTopPadding;
     private float mCollapsedBottompadding;
     private ViewInvertHelper mOverflowInvertHelper;
     private boolean mChildrenExpanded;
     private ExpandableNotificationRow mNotificationParent;
-    private HybridNotificationView mGroupOverflowContainer;
+    private TextView mOverflowNumber;
     private ViewState mGroupOverFlowState;
     private int mRealHeight;
-    private int mLayoutDirection = LAYOUT_DIRECTION_UNDEFINED;
+    private boolean mUserLocked;
+    private int mActualHeight;
+    private boolean mNeverAppliedGroupState;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -77,7 +80,7 @@
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         initDimens();
-        mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
+        mHybridGroupManager = new HybridGroupManager(getContext(), this);
     }
 
     private void initDimens() {
@@ -87,13 +90,12 @@
                 R.dimen.notification_divider_height));
         mMaxNotificationHeight = getResources().getDimensionPixelSize(
                 R.dimen.notification_max_height);
-        mNotificationAppearDistance = getResources().getDimensionPixelSize(
-                R.dimen.notification_appear_distance);
         mNotificationHeaderHeight = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_top);
         mNotificatonTopPadding = getResources().getDimensionPixelSize(
                 R.dimen.notification_children_container_top_padding);
-        mCollapsedBottompadding = 11.5f * getResources().getDisplayMetrics().density;
+        mCollapsedBottompadding = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_margin_bottom);
     }
 
     @Override
@@ -104,12 +106,12 @@
             if (child.getVisibility() == View.GONE) {
                 continue;
             }
-            child.layout(0, 0, getWidth(), child.getMeasuredHeight());
+            child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
             mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight);
         }
-        if (mGroupOverflowContainer != null) {
-            mGroupOverflowContainer.layout(0, 0, getWidth(),
-                    mGroupOverflowContainer.getMeasuredHeight());
+        if (mOverflowNumber != null) {
+            mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(),
+                    mOverflowNumber.getMeasuredHeight());
         }
     }
 
@@ -124,11 +126,20 @@
             ownMaxHeight = Math.min(ownMaxHeight, size);
         }
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        if (mOverflowNumber != null) {
+            mOverflowNumber.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+                    newHeightSpec);
+        }
         int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY);
         int height = mNotificationHeaderHeight + mNotificatonTopPadding;
         int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+        int collapsedChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
+        int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1;
         for (int i = 0; i < childCount; i++) {
-            View child = mChildren.get(i);
+            ExpandableNotificationRow child = mChildren.get(i);
+            boolean isOverflow = i == overflowIndex;
+            child.setSingleLineWidthIndention(isOverflow ? mOverflowNumber.getMeasuredWidth() : 0);
             child.measure(widthMeasureSpec, newHeightSpec);
             height += child.getMeasuredHeight();
 
@@ -137,10 +148,6 @@
             divider.measure(widthMeasureSpec, dividerHeightSpec);
             height += mDividerHeight;
         }
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        if (mGroupOverflowContainer != null) {
-            mGroupOverflowContainer.measure(widthMeasureSpec, newHeightSpec);
-        }
         mRealHeight = height;
         if (heightMode != MeasureSpec.UNSPECIFIED) {
             height = Math.min(height, size);
@@ -164,6 +171,7 @@
         int newIndex = childIndex < 0 ? mChildren.size() : childIndex;
         mChildren.add(newIndex, row);
         addView(row);
+        row.setUserLocked(mUserLocked);
 
         View divider = inflateDivider();
         addView(divider);
@@ -188,28 +196,37 @@
         });
 
         row.setSystemChildExpanded(false);
+        row.setUserLocked(false);
         updateGroupOverflow();
     }
 
     public void updateGroupOverflow() {
         int childCount = mChildren.size();
         int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
-        boolean hasOverflow = childCount > maxAllowedVisibleChildren;
-        int lastVisibleIndex = hasOverflow ? maxAllowedVisibleChildren - 2
-                : maxAllowedVisibleChildren - 1;
-        if (hasOverflow) {
-            mGroupOverflowContainer = mHybridViewManager.bindFromNotificationGroup(
-                    mGroupOverflowContainer, mChildren, lastVisibleIndex + 1);
+        if (childCount > maxAllowedVisibleChildren) {
+            mOverflowNumber = mHybridGroupManager.bindOverflowNumber(
+                    mOverflowNumber, childCount - maxAllowedVisibleChildren);
             if (mOverflowInvertHelper == null) {
-                mOverflowInvertHelper= new ViewInvertHelper(mGroupOverflowContainer,
+                mOverflowInvertHelper= new ViewInvertHelper(mOverflowNumber,
                         NotificationPanelView.DOZE_ANIMATION_DURATION);
             }
             if (mGroupOverFlowState == null) {
                 mGroupOverFlowState = new ViewState();
+                mNeverAppliedGroupState = true;
             }
-        } else if (mGroupOverflowContainer != null) {
-            removeView(mGroupOverflowContainer);
-            mGroupOverflowContainer = null;
+        } else if (mOverflowNumber != null) {
+            removeView(mOverflowNumber);
+            if (isShown()) {
+                final View removedOverflowNumber = mOverflowNumber;
+                addTransientView(removedOverflowNumber, getTransientViewCount());
+                CrossFadeHelper.fadeOut(removedOverflowNumber, new Runnable() {
+                    @Override
+                    public void run() {
+                        removeTransientView(removedOverflowNumber);
+                    }
+                });
+            }
+            mOverflowNumber = null;
             mOverflowInvertHelper = null;
             mGroupOverFlowState = null;
         }
@@ -218,11 +235,7 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        int layoutDirection = getLayoutDirection();
-        if (layoutDirection != mLayoutDirection) {
-            updateGroupOverflow();
-            mLayoutDirection = layoutDirection;
-        }
+        updateGroupOverflow();
     }
 
     private View inflateDivider() {
@@ -259,10 +272,14 @@
     }
 
     private void updateExpansionStates() {
-        // Let's make the first child expanded if the parent is
-        for (int i = 0; i < mChildren.size(); i++) {
+        if (mChildrenExpanded || mUserLocked) {
+            // we don't modify it the group is expanded or if we are expanding it
+            return;
+        }
+        int size = mChildren.size();
+        for (int i = 0; i < size; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
-            child.setSystemChildExpanded(false);
+            child.setSystemChildExpanded(i == 0 && size == 1);
         }
     }
 
@@ -281,27 +298,45 @@
      */
     private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
         int intrinsicHeight = mNotificationHeaderHeight;
-        if (mChildrenExpanded) {
-            intrinsicHeight += mNotificatonTopPadding;
-        }
         int visibleChildren = 0;
         int childCount = mChildren.size();
+        boolean firstChild = true;
+        float expandFactor = 0;
+        if (mUserLocked) {
+            expandFactor = getGroupExpandFraction();
+        }
         for (int i = 0; i < childCount; i++) {
             if (visibleChildren >= maxAllowedVisibleChildren) {
                 break;
             }
+            if (!firstChild) {
+                if (mUserLocked) {
+                    intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
+                            expandFactor);
+                } else {
+                    intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding;
+                }
+            } else {
+                if (mUserLocked) {
+                    intrinsicHeight += NotificationUtils.interpolate(
+                            0,
+                            mNotificatonTopPadding + mDividerHeight,
+                            expandFactor);
+                } else {
+                    intrinsicHeight += mChildrenExpanded
+                            ? mNotificatonTopPadding + mDividerHeight
+                            : 0;
+                }
+                firstChild = false;
+            }
             ExpandableNotificationRow child = mChildren.get(i);
             intrinsicHeight += child.getIntrinsicHeight();
             visibleChildren++;
         }
-        if (visibleChildren > 0) {
-            if (mChildrenExpanded) {
-                intrinsicHeight += visibleChildren * mDividerHeight;
-            } else {
-                intrinsicHeight += (visibleChildren - 1) * mChildPadding;
-            }
-        }
-        if (!mChildrenExpanded) {
+        if (mUserLocked) {
+            intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f,
+                    expandFactor);
+        } else if (!mChildrenExpanded) {
             intrinsicHeight += mCollapsedBottompadding;
         }
         return intrinsicHeight;
@@ -318,17 +353,31 @@
         int yPosition = mNotificationHeaderHeight;
         boolean firstChild = true;
         int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
-        boolean hasOverflow = !mChildrenExpanded && childCount > maxAllowedVisibleChildren
-                && maxAllowedVisibleChildren != NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
-        int lastVisibleIndex = hasOverflow
-                ? maxAllowedVisibleChildren - 2
-                : maxAllowedVisibleChildren - 1;
+        int lastVisibleIndex = maxAllowedVisibleChildren - 1;
+        int firstOverflowIndex = lastVisibleIndex + 1;
+        float expandFactor = 0;
+        if (mUserLocked) {
+            expandFactor = getGroupExpandFraction();
+            firstOverflowIndex = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
+        }
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             if (!firstChild) {
-                yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+                if (mUserLocked) {
+                     yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
+                             expandFactor);
+                } else {
+                    yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+                }
             } else {
-                yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+                if (mUserLocked) {
+                    yPosition += NotificationUtils.interpolate(
+                            0,
+                            mNotificatonTopPadding + mDividerHeight,
+                            expandFactor);
+                } else {
+                    yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+                }
                 firstChild = false;
             }
             StackViewState childState = resultState.getViewStateForView(child);
@@ -342,19 +391,38 @@
             childState.belowSpeedBump = parentState.belowSpeedBump;
             childState.clipTopAmount = 0;
             childState.topOverLap = 0;
-            boolean visible = i <= lastVisibleIndex;
-            childState.alpha = visible ? 1 : 0;
+            childState.alpha = 0;
+            if (i < firstOverflowIndex) {
+                childState.alpha = 1;
+            } else if (expandFactor == 1.0f && i <= lastVisibleIndex) {
+                childState.alpha = (mActualHeight - childState.yTranslation) / childState.height;
+                childState.alpha = Math.max(0.0f, Math.min(1.0f, childState.alpha));
+            }
             childState.location = parentState.location;
             yPosition += intrinsicHeight;
         }
-        if (mGroupOverflowContainer != null) {
-            mGroupOverFlowState.initFrom(mGroupOverflowContainer);
-            if (hasOverflow) {
-                StackViewState firstOverflowState =
-                        resultState.getViewStateForView(mChildren.get(lastVisibleIndex + 1));
-                mGroupOverFlowState.yTranslation = firstOverflowState.yTranslation;
+        if (mOverflowNumber != null) {
+            ExpandableNotificationRow overflowView = mChildren.get(Math.min(
+                    getMaxAllowedVisibleChildren(true /* likeCollpased */), childCount) - 1);
+            mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
+            if (!mChildrenExpanded) {
+                if (mUserLocked) {
+                    HybridNotificationView singleLineView = overflowView.getSingleLineView();
+                    View mirrorView = singleLineView.getTextView();
+                    if (mirrorView.getVisibility() == GONE) {
+                        mirrorView = singleLineView.getTitleView();
+                    }
+                    if (mirrorView.getVisibility() == GONE) {
+                        mirrorView = singleLineView;
+                    }
+                    mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(
+                            mirrorView, overflowView);
+                    mGroupOverFlowState.alpha = mirrorView.getAlpha();
+                }
+            } else {
+                mGroupOverFlowState.yTranslation += mNotificationHeaderHeight;
+                mGroupOverFlowState.alpha = 0.0f;
             }
-            mGroupOverFlowState.alpha = mChildrenExpanded || !hasOverflow ? 0.0f : 1.0f;
         }
     }
 
@@ -366,7 +434,8 @@
         if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) {
             return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
         }
-        if (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp()) {
+        if (!mNotificationParent.isOnKeyguard()
+                && (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp())) {
             return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
         }
         return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
@@ -375,6 +444,10 @@
     public void applyState(StackScrollState state) {
         int childCount = mChildren.size();
         ViewState tmpState = new ViewState();
+        float expandFraction = 0.0f;
+        if (mUserLocked) {
+            expandFraction = getGroupExpandFraction();
+        }
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             StackViewState viewState = state.getViewStateForView(child);
@@ -384,11 +457,19 @@
             View divider = mDividers.get(i);
             tmpState.initFrom(divider);
             tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
-            tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+            float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+            if (mUserLocked && viewState.alpha != 0) {
+                alpha = NotificationUtils.interpolate(0, 0.5f,
+                        Math.min(viewState.alpha, expandFraction));
+            }
+            tmpState.alpha = alpha;
             state.applyViewState(divider, tmpState);
+            // There is no fake shadow to be drawn on the children
+            child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
         }
-        if (mGroupOverflowContainer != null) {
-            state.applyViewState(mGroupOverflowContainer, mGroupOverFlowState);
+        if (mOverflowNumber != null) {
+            state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+            mNeverAppliedGroupState = false;
         }
     }
 
@@ -407,6 +488,7 @@
             long baseDelay, long duration) {
         int childCount = mChildren.size();
         ViewState tmpState = new ViewState();
+        float expandFraction = getGroupExpandFraction();
         for (int i = childCount - 1; i >= 0; i--) {
             ExpandableNotificationRow child = mChildren.get(i);
             StackViewState viewState = state.getViewStateForView(child);
@@ -416,11 +498,25 @@
             View divider = mDividers.get(i);
             tmpState.initFrom(divider);
             tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
-            tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+            float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+            if (mUserLocked && viewState.alpha != 0) {
+                alpha = NotificationUtils.interpolate(0, 0.5f,
+                        Math.min(viewState.alpha, expandFraction));
+            }
+            tmpState.alpha = alpha;
             stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
+            // There is no fake shadow to be drawn on the children
+            child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
         }
-        if (mGroupOverflowContainer != null) {
-            stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState,
+        if (mOverflowNumber != null) {
+            if (mNeverAppliedGroupState) {
+                float alpha = mGroupOverFlowState.alpha;
+                mGroupOverFlowState.alpha = 0;
+                state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+                mGroupOverFlowState.alpha = alpha;
+                mNeverAppliedGroupState = false;
+            }
+            stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState,
                     baseDelay, duration);
         }
     }
@@ -442,6 +538,7 @@
 
     public void setChildrenExpanded(boolean childrenExpanded) {
         mChildrenExpanded = childrenExpanded;
+        updateExpansionStates();
     }
 
     public void setNotificationParent(ExpandableNotificationRow parent) {
@@ -449,19 +546,109 @@
     }
 
     public int getMaxContentHeight() {
-        return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+        int maxContentHeight = mNotificationHeaderHeight + mNotificatonTopPadding;
+        int visibleChildren = 0;
+        int childCount = mChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) {
+                break;
+            }
+            ExpandableNotificationRow child = mChildren.get(i);
+            float childHeight = child.isExpanded(true /* allowOnKeyguard */)
+                    ? child.getMaxExpandHeight()
+                    : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+            maxContentHeight += childHeight;
+            visibleChildren++;
+        }
+        if (visibleChildren > 0) {
+            maxContentHeight += visibleChildren * mDividerHeight;
+        }
+        return maxContentHeight;
+    }
+
+    public void setActualHeight(int actualHeight) {
+        if (!mUserLocked) {
+            return;
+        }
+        mActualHeight = actualHeight;
+        float fraction = getGroupExpandFraction();
+        int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
+        int childCount = mChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            float childHeight = child.isExpanded(true /* allowOnKeyguard */)
+                    ? child.getMaxExpandHeight()
+                    : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+            if (i < maxAllowedVisibleChildren) {
+                float singleLineHeight = child.getShowingLayout().getMinHeight(
+                        false /* likeGroupExpanded */);
+                child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight,
+                        childHeight, fraction), false);
+            } else {
+                child.setActualHeight((int) childHeight, false);
+            }
+        }
+    }
+
+    public float getGroupExpandFraction() {
+        int visibleChildrenExpandedHeight = getVisibleChildrenExpandHeight();
+        int minExpandHeight = getCollapsedHeight();
+        float factor = (mActualHeight - minExpandHeight)
+                / (float) (visibleChildrenExpandedHeight - minExpandHeight);
+        return Math.max(0.0f, Math.min(1.0f, factor));
+    }
+
+    private int getVisibleChildrenExpandHeight() {
+        int intrinsicHeight = mNotificationHeaderHeight + mNotificatonTopPadding + mDividerHeight;
+        int visibleChildren = 0;
+        int childCount = mChildren.size();
+        int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
+        for (int i = 0; i < childCount; i++) {
+            if (visibleChildren >= maxAllowedVisibleChildren) {
+                break;
+            }
+            ExpandableNotificationRow child = mChildren.get(i);
+            float childHeight = child.isExpanded(true /* allowOnKeyguard */)
+                    ? child.getMaxExpandHeight()
+                    : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+            intrinsicHeight += childHeight;
+            visibleChildren++;
+        }
+        return intrinsicHeight;
     }
 
     public int getMinHeight() {
-        return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
+        return getMinHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
     }
 
-    public int getMinExpandHeight() {
-        return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
+    public int getCollapsedHeight() {
+        return getMinHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
+    }
+
+    private int getMinHeight(int maxAllowedVisibleChildren) {
+        int minExpandHeight = mNotificationHeaderHeight;
+        int visibleChildren = 0;
+        boolean firstChild = true;
+        int childCount = mChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            if (visibleChildren >= maxAllowedVisibleChildren) {
+                break;
+            }
+            if (!firstChild) {
+                minExpandHeight += mChildPadding;
+            } else {
+                firstChild = false;
+            }
+            ExpandableNotificationRow child = mChildren.get(i);
+            minExpandHeight += child.getSingleLineView().getHeight();
+            visibleChildren++;
+        }
+        minExpandHeight += mCollapsedBottompadding;
+        return minExpandHeight;
     }
 
     public void setDark(boolean dark, boolean fade, long delay) {
-        if (mGroupOverflowContainer != null) {
+        if (mOverflowNumber != null) {
             mOverflowInvertHelper.setInverted(dark, fade, delay);
         }
     }
@@ -477,4 +664,18 @@
             mDividers.set(i, divider);
         }
     }
+
+    public void setUserLocked(boolean userLocked) {
+        mUserLocked = userLocked;
+        int childCount = mChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            child.setUserLocked(userLocked);
+        }
+    }
+
+    public void onNotificationUpdated() {
+        mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
+                mNotificationParent.getNotificationColor());
+    }
 }
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 f078b53..46a49ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -18,7 +18,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeAnimator;
@@ -44,10 +43,13 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.OverScroller;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -58,11 +60,14 @@
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.NotificationGuts;
 import com.android.systemui.statusbar.NotificationOverflowContainer;
 import com.android.systemui.statusbar.NotificationSettingsIconRow;
 import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -70,6 +75,8 @@
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 
 /**
@@ -78,7 +85,7 @@
 public class NotificationStackScrollLayout extends ViewGroup
         implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
         ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
-        SettingsIconRowListener {
+        SettingsIconRowListener, ScrollContainer {
 
     public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
     private static final String TAG = "StackScroller";
@@ -93,7 +100,7 @@
     private static final int INVALID_POINTER = -1;
 
     private ExpandHelper mExpandHelper;
-    private SwipeHelper mSwipeHelper;
+    private NotificationSwipeHelper mSwipeHelper;
     private boolean mSwipingInProgress;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
     private final Paint mBackgroundPaint = new Paint();
@@ -129,7 +136,7 @@
     private int mPaddingBetweenElements;
     private int mIncreasedPaddingBetweenElements;
     private int mTopPadding;
-    private int mCollapseSecondCardPadding;
+    private int mBottomInset = 0;
 
     /**
      * The algorithm which calculates the properties for our children
@@ -201,6 +208,7 @@
     private float mStackTranslation;
     private float mTopPaddingOverflow;
     private boolean mDontReportNextOverScroll;
+    private boolean mDontClampNextScroll;
     private boolean mRequestViewResizeAnimationOnLayout;
     private boolean mNeedViewResizeAnimation;
     private View mExpandedGroupView;
@@ -213,7 +221,6 @@
      */
     private int mMaxScrollAfterExpand;
     private SwipeHelper.LongPressListener mLongPressListener;
-    private GearDisplayedListener mGearDisplayedListener;
 
     private NotificationSettingsIconRow mCurrIconRow;
     private View mTranslatingParentView;
@@ -277,6 +284,7 @@
     private int mBgColor;
     private float mDimAmount;
     private ValueAnimator mDimAnimator;
+    private ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
     private Animator.AnimatorListener mDimEndListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
@@ -292,6 +300,33 @@
         }
     };
     private ViewGroup mQsContainer;
+    private boolean mContinuousShadowUpdate;
+    private ViewTreeObserver.OnPreDrawListener mShadowUpdater
+            = new ViewTreeObserver.OnPreDrawListener() {
+
+        @Override
+        public boolean onPreDraw() {
+            updateViewShadows();
+            return true;
+        }
+    };
+    private Comparator<ExpandableView> mViewPositionComparator = new Comparator<ExpandableView>() {
+        @Override
+        public int compare(ExpandableView view, ExpandableView otherView) {
+            float endY = view.getTranslationY() + view.getActualHeight();
+            float otherEndY = otherView.getTranslationY() + otherView.getActualHeight();
+            if (endY < otherEndY) {
+                return -1;
+            } else if (endY > otherEndY) {
+                return 1;
+            } else {
+                // The two notifications end at the same location
+                return 0;
+            }
+        }
+    };
+    private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
+    private boolean mPulsing;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -327,13 +362,23 @@
             mDebugPaint.setStyle(Paint.Style.STROKE);
         }
         mFalsingManager = FalsingManager.getInstance(context);
-        mBackgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
     }
 
     @Override
-    public void onGearTouched(ExpandableNotificationRow row) {
+    public void onGearTouched(ExpandableNotificationRow row, int x, int y) {
         if (mLongPressListener != null) {
-            mLongPressListener.onLongPress(row, 0, 0);
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
+                    row.getStatusBarNotification().getPackageName());
+            mLongPressListener.onLongPress(row, x, y);
+        }
+    }
+
+    @Override
+    public void onSettingsIconRowReset(ExpandableNotificationRow row) {
+        if (mTranslatingParentView != null && row == mTranslatingParentView) {
+            mSwipeHelper.setSnappedToGear(false);
+            mGearExposedView = null;
+            mTranslatingParentView = null;
         }
     }
 
@@ -388,12 +433,14 @@
                 .getDimensionPixelSize(R.dimen.notification_divider_height));
         mIncreasedPaddingBetweenElements = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
-
         mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
         mMinTopOverScrollToEscape = getResources().getDimensionPixelSize(
                 R.dimen.min_top_overscroll_to_qs);
-        mCollapseSecondCardPadding = getResources().getDimensionPixelSize(
-                R.dimen.notification_collapse_second_card_padding);
+    }
+
+    public void setDrawBackgroundAsSrc(boolean asSrc) {
+        mBackgroundPaint.setXfermode(asSrc ? mSrcMode : null);
+        invalidate();
     }
 
     private void notifyHeightChangeListener(ExpandableView view) {
@@ -479,14 +526,6 @@
     }
 
     /**
-     * @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() {
-        return getNotGoneChildCount() > 1;
-    }
-
-    /**
      * 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.
      */
@@ -509,7 +548,7 @@
             ExpandableView child = (ExpandableView) getChildAt(i);
             if (mChildrenToAddAnimated.contains(child)) {
                 int startingPosition = getPositionInLinearLayout(child);
-                int padding = child.needsIncreasedPadding()
+                int padding = child.getIncreasedPaddingAmount() == 1.0f
                         ? mIncreasedPaddingBetweenElements :
                         mPaddingBetweenElements;
                 int childHeight = getIntrinsicHeight(child) + padding;
@@ -569,7 +608,7 @@
         mLastSetStackHeight = height;
         setIsExpanded(height > 0.0f);
         int newStackHeight = (int) height;
-        int minStackHeight = getMinStackHeight();
+        int minStackHeight = getLayoutMinHeight();
         int stackHeight;
         float paddingOffset;
         boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
@@ -582,20 +621,7 @@
             stackHeight = newStackHeight;
         } else {
             int translationY;
-            if (!trackingHeadsUp) {
-                // We did not reach the position yet where we actually start growing,
-                // so we translate the stack upwards.
-                translationY = (newStackHeight - minStackHeight);
-                // A slight parallax effect is introduced in order for the stack to catch up with
-                // the top card.
-                float partiallyThere = (newStackHeight - mTopPadding - mTopPaddingOverflow)
-                        / minStackHeight;
-                partiallyThere = Math.max(0, partiallyThere);
-                translationY += (1 - partiallyThere) * (mBottomStackPeekSize +
-                        mCollapseSecondCardPadding);
-            } else {
-                translationY = (int) (height - normalUnfoldPositionStart);
-            }
+            translationY = newStackHeight - normalUnfoldPositionStart;
             paddingOffset = translationY - mTopPadding;
             stackHeight = (int) (height - (translationY - mTopPadding));
         }
@@ -638,8 +664,8 @@
         return mBottomStackPeekSize;
     }
 
-    public int getCollapseSecondCardPadding() {
-        return mCollapseSecondCardPadding;
+    public int getBottomStackSlowDownHeight() {
+        return mBottomStackSlowDownHeight;
     }
 
     public void setLongPressListener(SwipeHelper.LongPressListener listener) {
@@ -647,10 +673,6 @@
         mLongPressListener = listener;
     }
 
-    public void setGearDisplayedListener(GearDisplayedListener listener) {
-        mGearDisplayedListener = listener;
-    }
-
     public void setQsContainer(ViewGroup qsContainer) {
         mQsContainer = qsContainer;
     }
@@ -667,17 +689,14 @@
         }
         mSwipedOutViews.add(v);
         mAmbientState.onDragFinished(v);
+        updateContinuousShadowDrawing();
         if (v instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) v;
             if (row.isHeadsUp()) {
                 mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
             }
         }
-        final View veto = v.findViewById(R.id.veto);
-        if (veto != null && veto.getVisibility() != View.GONE) {
-            veto.performClick();
-        }
-        if (DEBUG) Log.v(TAG, "onChildDismissed: " + v);
+        performDismiss(v);
 
         mFalsingManager.onNotificationDismissed();
         if (mFalsingManager.shouldEnforceBouncer()) {
@@ -686,9 +705,28 @@
         }
     }
 
+    private void performDismiss(View v) {
+        if (v instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+            if (mGroupManager.isOnlyChildInSuppressedGroup(row.getStatusBarNotification())) {
+                ExpandableNotificationRow groupSummary =
+                        mGroupManager.getLogicalGroupSummary(row.getStatusBarNotification());
+                if (groupSummary.isClearable()) {
+                    performDismiss(groupSummary);
+                }
+            }
+        }
+        final View veto = v.findViewById(R.id.veto);
+        if (veto != null && veto.getVisibility() != View.GONE) {
+            veto.performClick();
+        }
+        if (DEBUG) Log.v(TAG, "onChildDismissed: " + v);
+    }
+
     @Override
     public void onChildSnappedBack(View animView, float targetLeft) {
         mAmbientState.onDragFinished(animView);
+        updateContinuousShadowDrawing();
         if (!mDragAnimPendingChildren.contains(animView)) {
             if (mAnimationsEnabled) {
                 mSnappedBackChildren.add(animView);
@@ -699,12 +737,9 @@
             // We start the swipe and snap back in the same frame, we don't want any animation
             mDragAnimPendingChildren.remove(animView);
         }
-
-        if (targetLeft == 0 && mCurrIconRow != null) {
+        if (mCurrIconRow != null && targetLeft == 0) {
             mCurrIconRow.resetState();
-            if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
-                mGearExposedView = null;
-            }
+            mCurrIconRow = null;
         }
     }
 
@@ -721,6 +756,7 @@
         mFalsingManager.onNotificatonStartDismissing();
         setSwipingInProgress(true);
         mAmbientState.onBeginDrag(v);
+        updateContinuousShadowDrawing();
         if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
             mDragAnimPendingChildren.add(v);
             mNeedsAnimation = true;
@@ -760,12 +796,15 @@
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
             ExpandableNotificationRow parent = row.getNotificationParent();
-            if (mGearExposedView != null && parent != null
-                    && parent.areChildrenExpanded() && mGearExposedView == parent) {
+            if (parent != null && parent.areChildrenExpanded()
+                    && (mGearExposedView == parent
+                        || (parent.getNotificationChildren().size() == 1
+                                && parent.isClearable()))) {
                 // In this case the group is expanded and showing the gear for the
                 // group, further interaction should apply to the group, not any
-                // child notifications so we use the parent of the child.
-                child = row.getNotificationParent();
+                // child notifications so we use the parent of the child. We also do the same
+                // if we only have a single child.
+                child = parent;
             }
         }
         return child;
@@ -843,7 +882,7 @@
     public boolean canChildBeExpanded(View v) {
         return v instanceof ExpandableNotificationRow
                 && ((ExpandableNotificationRow) v).isExpandable()
-                && !((ExpandableNotificationRow) v).isHeadsUp();
+                && (mIsExpanded || !((ExpandableNotificationRow) v).isPinned());
     }
 
     public void setUserExpandedChild(View v, boolean userExpanded) {
@@ -874,6 +913,45 @@
         mScrollingEnabled = enable;
     }
 
+    public void scrollTo(View v) {
+        ExpandableView expandableView = (ExpandableView) v;
+        int positionInLinearLayout = getPositionInLinearLayout(v);
+
+        int targetScroll = positionInLinearLayout + expandableView.getActualHeight() +
+                mBottomInset - getHeight() + getTopPadding();
+        if (mOwnScrollY < targetScroll) {
+            mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScroll - mOwnScrollY);
+            mDontReportNextOverScroll = true;
+            postInvalidateOnAnimation();
+        }
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        mBottomInset = Math.max(0, insets.getSystemWindowInsetBottom()
+                - (getRootView().getHeight() - getHeight()));
+
+        int range = getScrollRange();
+        if (mOwnScrollY > range) {
+            // HACK: We're repeatedly getting staggered insets here while the IME is
+            // animating away. To work around that we'll wait until things have settled.
+            removeCallbacks(mReclamp);
+            postDelayed(mReclamp, 50);
+        }
+        return insets;
+    }
+
+    private Runnable mReclamp = new Runnable() {
+        @Override
+        public void run() {
+            int range = getScrollRange();
+            mScroller.startScroll(mScrollX, mOwnScrollY, 0, range - mOwnScrollY);
+            mDontReportNextOverScroll = true;
+            mDontClampNextScroll = true;
+            postInvalidateOnAnimation();
+        }
+    };
+
     public void setExpandingEnabled(boolean enable) {
         mExpandHelper.setEnabled(enable);
     }
@@ -912,6 +990,11 @@
         mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration);
     }
 
+    public void snapViewIfNeeded(View child) {
+        boolean animate = mIsExpanded || isPinnedHeadsUp(child);
+        mSwipeHelper.snapChildIfNeeded(child, animate);
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
@@ -1206,7 +1289,7 @@
             int y = mScroller.getCurrY();
 
             if (oldX != x || oldY != y) {
-                final int range = getScrollRange();
+                int range = getScrollRange();
                 if (y < 0 && oldY >= 0 || y > range && oldY <= range) {
                     float currVelocity = mScroller.getCurrVelocity();
                     if (currVelocity >= mMinimumVelocity) {
@@ -1214,6 +1297,9 @@
                     }
                 }
 
+                if (mDontClampNextScroll) {
+                    range = Math.max(range, oldY);
+                }
                 overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range,
                         0, (int) (mMaxOverScroll), false);
                 onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
@@ -1221,6 +1307,8 @@
 
             // Keep on drawing until the animation has finished.
             postInvalidateOnAnimation();
+        } else {
+            mDontClampNextScroll = false;
         }
     }
 
@@ -1424,7 +1512,9 @@
                         - firstChild.getMinHeight());
             }
         }
-        return scrollRange;
+        int imeOverlap = Math.max(0,
+                getContentHeight() - (getHeight() - mBottomInset));
+        return scrollRange + imeOverlap;
     }
 
     /**
@@ -1499,18 +1589,18 @@
 
     private void updateContentHeight() {
         int height = 0;
-        boolean previousNeedsIncreasedPaddings = false;
+        float previousIncreasedAmount = 0.0f;
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView expandableView = (ExpandableView) getChildAt(i);
             if (expandableView.getVisibility() != View.GONE) {
-                boolean needsIncreasedPaddings = expandableView.needsIncreasedPadding();
+                float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
                 if (height != 0) {
-                    int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
-                            ? mIncreasedPaddingBetweenElements
-                            : mPaddingBetweenElements;
-                    height += padding;
+                    height += (int) NotificationUtils.interpolate(
+                            mPaddingBetweenElements,
+                            mIncreasedPaddingBetweenElements,
+                            Math.max(previousIncreasedAmount, increasedPaddingAmount));
                 }
-                previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+                previousIncreasedAmount = increasedPaddingAmount;
                 height += expandableView.getIntrinsicHeight();
             }
         }
@@ -1781,8 +1871,12 @@
                 // it will be set once we reach the boundary
                 mMaxOverScroll = 0.0f;
             }
+            int minScrollY = Math.max(0, scrollRange);
+            if (mExpandedInThisMotion) {
+                minScrollY = Math.min(minScrollY, mMaxScrollAfterExpand);
+            }
             mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0,
-                    Math.max(0, scrollRange), 0, Integer.MAX_VALUE / 2);
+                    minScrollY, 0, mExpandedInThisMotion && mOwnScrollY >= 0 ? 0 : Integer.MAX_VALUE / 2);
 
             postInvalidateOnAnimation();
         }
@@ -1813,7 +1907,7 @@
             boolean ignoreIntrinsicPadding) {
         float start = qsHeight;
         float stackHeight = getHeight() - start;
-        int minStackHeight = getMinStackHeight();
+        int minStackHeight = getLayoutMinHeight();
         if (stackHeight <= minStackHeight) {
             float overflow = minStackHeight - stackHeight;
             stackHeight = minStackHeight;
@@ -1827,11 +1921,16 @@
         setStackHeight(mLastSetStackHeight);
     }
 
-    public int getMinStackHeight() {
+    public int getLayoutMinHeight() {
         final ExpandableView firstChild = getFirstChildNotGone();
-        final int firstChildMinHeight = firstChild != null ? firstChild.getMinHeight()
+        int firstChildMinHeight = firstChild != null
+                ? firstChild.getIntrinsicHeight()
                 : mCollapsedSize;
-        return firstChildMinHeight + mBottomStackPeekSize + mCollapseSecondCardPadding;
+        if (mOwnScrollY > 0) {
+            firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
+        }
+        return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
+                mMaxLayoutHeight - mTopPadding);
     }
 
     public float getTopPaddingOverflow() {
@@ -1840,10 +1939,10 @@
 
     public int getPeekHeight() {
         final ExpandableView firstChild = getFirstChildNotGone();
-        final int firstChildMinHeight = firstChild != null ? (int) firstChild.getMinHeight()
+        final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight()
                 : mCollapsedSize;
         return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
-                + mCollapseSecondCardPadding;
+                + mBottomStackSlowDownHeight;
     }
 
     private int clampPadding(int desiredPadding) {
@@ -1956,8 +2055,15 @@
         }
     }
 
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        if (disallowIntercept) {
+            mSwipeHelper.removeLongPressCallback();
+        }
+    }
+
     private void onViewRemovedInternal(View child) {
-        mStackScrollAlgorithm.notifyChildrenChanged(this);
         if (mChangePositionInProgress) {
             // This is only a position change, don't do anything special
             return;
@@ -2065,9 +2171,10 @@
      */
     private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
         int startingPosition = getPositionInLinearLayout(removedChild);
-        int padding = removedChild.needsIncreasedPadding()
-                ? mIncreasedPaddingBetweenElements :
-                mPaddingBetweenElements;
+        int padding = (int) NotificationUtils.interpolate(
+                mPaddingBetweenElements,
+                mIncreasedPaddingBetweenElements,
+                removedChild.getIncreasedPaddingAmount());
         int childHeight = getIntrinsicHeight(removedChild) + padding;
         int endPosition = startingPosition + childHeight;
         if (endPosition <= mOwnScrollY) {
@@ -2091,19 +2198,19 @@
 
     private int getPositionInLinearLayout(View requestedChild) {
         int position = 0;
-        boolean previousNeedsIncreasedPaddings = false;
+        float previousIncreasedAmount = 0.0f;
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
             boolean notGone = child.getVisibility() != View.GONE;
             if (notGone) {
-                boolean needsIncreasedPaddings = child.needsIncreasedPadding();
+                float increasedPaddingAmount = child.getIncreasedPaddingAmount();
                 if (position != 0) {
-                    int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
-                            ? mIncreasedPaddingBetweenElements :
-                            mPaddingBetweenElements;
-                    position += padding;
+                    position += (int) NotificationUtils.interpolate(
+                            mPaddingBetweenElements,
+                            mIncreasedPaddingBetweenElements,
+                            Math.max(previousIncreasedAmount, increasedPaddingAmount));
                 }
-                previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+                previousIncreasedAmount = increasedPaddingAmount;
             }
             if (child == requestedChild) {
                 return position;
@@ -2137,7 +2244,6 @@
 
     private void onViewAddedInternal(View child) {
         updateHideSensitiveForChild(child);
-        mStackScrollAlgorithm.notifyChildrenChanged(this);
         ((ExpandableView) child).setOnHeightChangedListener(this);
         generateAddAnimation(child, false /* fromMoreCard */);
         updateAnimationState(child);
@@ -2165,7 +2271,7 @@
     }
 
     private void updateNotificationAnimationStates() {
-        boolean running = mAnimationsEnabled;
+        boolean running = mAnimationsEnabled || mPulsing;
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -2175,7 +2281,8 @@
     }
 
     private void updateAnimationState(View child) {
-        updateAnimationState(mAnimationsEnabled && (mIsExpanded || isPinnedHeadsUp(child)), child);
+        updateAnimationState((mAnimationsEnabled || mPulsing)
+                && (mIsExpanded || isPinnedHeadsUp(child)), child);
     }
 
 
@@ -2221,8 +2328,10 @@
         int currentIndex = indexOfChild(child);
         if (child != null && child.getParent() == this && currentIndex != newIndex) {
             mChangePositionInProgress = true;
+            ((ExpandableView)child).setChangingPosition(true);
             removeView(child);
             addView(child, newIndex);
+            ((ExpandableView)child).setChangingPosition(false);
             mChangePositionInProgress = false;
             if (mIsExpanded && mAnimationsEnabled && child.getVisibility() != View.GONE) {
                 mChildrenChangingPositions.add(child);
@@ -2242,6 +2351,7 @@
             setAnimationRunning(true);
             mAnimationEvents.clear();
             updateBackground();
+            updateViewShadows();
         } else {
             applyCurrentState();
         }
@@ -2584,6 +2694,11 @@
         }
     }
 
+    @Override
+    public void requestDisallowLongPress() {
+        removeLongPressCallback();
+    }
+
     public void removeLongPressCallback() {
         mSwipeHelper.removeLongPressCallback();
     }
@@ -2604,12 +2719,8 @@
     }
 
     public int getEmptyBottomMargin() {
-        int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize;
-        if (needsHeightAdaption()) {
-            emptyMargin -= mBottomStackSlowDownHeight;
-        } else {
-            emptyMargin -= mCollapseSecondCardPadding;
-        }
+        int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize
+                - mBottomStackSlowDownHeight;
         return Math.max(emptyMargin, 0);
     }
 
@@ -2620,14 +2731,13 @@
 
     public void onExpansionStarted() {
         mIsExpansionChanging = true;
-        mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
     }
 
     public void onExpansionStopped() {
         mIsExpansionChanging = false;
-        mStackScrollAlgorithm.onExpansionStopped();
         if (!mIsExpanded) {
             mOwnScrollY = 0;
+            mPhoneStatusBar.resetUserExpandedStates();
 
             // lets make sure nothing is in the overlay anymore
             getOverlay().clear();
@@ -2653,6 +2763,16 @@
         if (changed) {
             if (!mIsExpanded) {
                 mGroupManager.collapseAllGroups();
+            } else {
+                // XXX: HACK: we should not be clearing notification effects from way down here.
+                // But at the moment we don't have a reliable way to know when the window is
+                // actually exposed to the air, so
+                if (mPhoneStatusBar.getBarState() != StatusBarState.KEYGUARD) {
+                    if (DEBUG) {
+                        Log.v(TAG, "clearing notification effects from scroller");
+                    }
+                    mPhoneStatusBar.clearNotificationEffects();
+                }
             }
             updateNotificationAnimationStates();
             updateChronometers();
@@ -2693,7 +2813,6 @@
         if (mIsExpanded && mAnimationsEnabled) {
             mRequestViewResizeAnimationOnLayout = true;
         }
-        mStackScrollAlgorithm.onReset(view);
         updateAnimationState(view);
         updateChronometerForChild(view);
     }
@@ -2702,13 +2821,13 @@
         if (view instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
             if (row.isUserLocked() && row != getFirstChildNotGone()) {
+                if (row.isSummaryWithChildren()) {
+                    return;
+                }
                 // We are actually expanding this view
-                float endPosition;
+                float endPosition = row.getTranslationY() + row.getActualHeight();
                 if (row.isChildInGroup()) {
-                    ExpandableNotificationRow parent = row.getNotificationParent();
-                    endPosition = parent.getTranslationY() + parent.getActualHeight();
-                } else {
-                    endPosition = row.getTranslationY() + row.getActualHeight();
+                    endPosition += row.getNotificationParent().getTranslationY();
                 }
                 int stackEnd = mMaxLayoutHeight - mBottomStackPeekSize -
                         mBottomStackSlowDownHeight + (int) mStackTranslation;
@@ -2824,6 +2943,43 @@
         }
         runAnimationFinishedRunnables();
         updateBackground();
+        updateViewShadows();
+    }
+
+    private void updateViewShadows() {
+        // we need to work around an issue where the shadow would not cast between siblings when
+        // their z difference is between 0 and 0.1
+
+        // Lefts first sort by Z difference
+        for (int i = 0; i < getChildCount(); i++) {
+            ExpandableView child = (ExpandableView) getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                mTmpSortedChildren.add(child);
+            }
+        }
+        Collections.sort(mTmpSortedChildren, mViewPositionComparator);
+
+        // Now lets update the shadow for the views
+        ExpandableView previous = null;
+        for (int i = 0; i < mTmpSortedChildren.size(); i++) {
+            ExpandableView expandableView = mTmpSortedChildren.get(i);
+            float translationZ = expandableView.getTranslationZ();
+            float otherZ = previous == null ? translationZ : previous.getTranslationZ();
+            float diff = otherZ - translationZ;
+            if (diff <= 0.0f || diff >= FakeShadowView.SHADOW_SIBLING_TRESHOLD) {
+                // There is no fake shadow to be drawn
+                expandableView.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
+            } else {
+                float yLocation = previous.getTranslationY() + previous.getActualHeight() -
+                        expandableView.getTranslationY();
+                expandableView.setFakeShadowIntensity(diff / FakeShadowView.SHADOW_SIBLING_TRESHOLD,
+                        previous.getOutlineAlpha(), (int) yLocation,
+                        previous.getOutlineTranslation());
+            }
+            previous = expandableView;
+        }
+
+        mTmpSortedChildren.clear();
     }
 
     public void goToFullShade(long delay) {
@@ -3045,7 +3201,7 @@
             disableClipOptimization();
         }
         handleDismissAllClipping();
-        if (mCurrIconRow != null & mCurrIconRow.isVisible()) {
+        if (mCurrIconRow != null && mCurrIconRow.isVisible()) {
             mCurrIconRow.getNotificationParent().animateTranslateNotification(0 /* left target */);
         }
     }
@@ -3087,15 +3243,7 @@
     }
 
     public int getDismissViewHeight() {
-        int height = mDismissView.getHeight() + mPaddingBetweenElements;
-
-        // Hack: Accommodate for additional distance when we only have one notification and the
-        // dismiss all button.
-        if (getNotGoneChildCount() == 2 && getLastChildNotGone() == mDismissView
-                && getFirstChildNotGone() instanceof ActivatableNotificationView) {
-            height += mCollapseSecondCardPadding;
-        }
-        return height;
+        return mDismissView.getHeight() + mPaddingBetweenElements;
     }
 
     public int getEmptyShadeViewHeight() {
@@ -3184,7 +3332,7 @@
     }
 
     @Override
-    public void onChildIsolationChanged() {
+    public void onGroupsChanged() {
         mPhoneStatusBar.requestNotificationUpdate();
     }
 
@@ -3262,6 +3410,7 @@
                 getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
             }
             mAnimationRunning = animationRunning;
+            updateContinuousShadowDrawing();
         }
     }
 
@@ -3269,6 +3418,11 @@
         return mIsExpanded;
     }
 
+    public void setPulsing(boolean pulsing) {
+        mPulsing = pulsing;
+        updateNotificationAnimationStates();
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
@@ -3308,24 +3462,12 @@
         public void flingTopOverscroll(float velocity, boolean open);
     }
 
-    /**
-     * A listener that is notified when the gear is shown behind a notification.
-     */
-    public interface GearDisplayedListener {
-        void onGearDisplayed(ExpandableNotificationRow row);
-    }
-
     private class NotificationSwipeHelper extends SwipeHelper {
-        private static final int MOVE_STATE_LEFT = -1;
-        private static final int MOVE_STATE_UNDEFINED = 0;
-        private static final int MOVE_STATE_RIGHT = 1;
-
         private static final long GEAR_SHOW_DELAY = 60;
-
-        private ArrayList<View> mTranslatingViews = new ArrayList<>();
         private CheckForDrag mCheckForDrag;
         private Handler mHandler;
-        private int mMoveState = MOVE_STATE_UNDEFINED;
+        private boolean mGearSnappedTo;
+        private boolean mGearSnappedOnLeft;
 
         public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
             super(swipeDirection, callback, context);
@@ -3338,89 +3480,167 @@
             mTranslatingParentView = currView;
 
             // Reset check for drag gesture
+            cancelCheckForDrag();
+            if (mCurrIconRow != null) {
+                mCurrIconRow.setSnapping(false);
+            }
             mCheckForDrag = null;
+            mCurrIconRow = null;
 
             // Slide back any notifications that might be showing a gear
-            resetExposedGearView();
+            resetExposedGearView(true /* animate */, false /* force */);
 
             if (currView instanceof ExpandableNotificationRow) {
                 // Set the listener for the current row's gear
                 mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
                 mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
-
-                // And the translating children
-                mTranslatingViews = ((ExpandableNotificationRow) currView).getContentViews();
             }
-            mMoveState = MOVE_STATE_UNDEFINED;
         }
 
         @Override
         public void onMoveUpdate(View view, float translation, float delta) {
-            final int newMoveState = (delta < 0) ? MOVE_STATE_RIGHT : MOVE_STATE_LEFT;
-            if (mMoveState != MOVE_STATE_UNDEFINED && mMoveState != newMoveState) {
-                // Changed directions, make sure we check for drag again.
-                mCheckForDrag = null;
-            }
-            mMoveState = newMoveState;
+            if (mCurrIconRow != null) {
+                mCurrIconRow.setSnapping(false); // If we're moving, we're not snapping.
 
-            if (view instanceof ExpandableNotificationRow) {
-                ((ExpandableNotificationRow) view).setTranslationForOutline(translation);
-                if (!isPinnedHeadsUp(view)) {
-                    // Only show the gear if we're not a heads up view.
-                    checkForDrag();
-                    if (mCurrIconRow != null) {
-                        mCurrIconRow.updateSettingsIcons(translation, getSize(view));
+                // If the gear is visible and the movement is towards it it's not a location change.
+                boolean onLeft = mGearSnappedTo ? mGearSnappedOnLeft : mCurrIconRow.isIconOnLeft();
+                boolean locationChange = isTowardsGear(translation, onLeft)
+                        ? false : mCurrIconRow.isIconLocationChange(translation);
+                if (locationChange) {
+                    // Don't consider it "snapped" if location has changed.
+                    setSnappedToGear(false);
+
+                    // Changed directions, make sure we check to fade in icon again.
+                    if (!mHandler.hasCallbacks(mCheckForDrag)) {
+                        // No check scheduled, set null to schedule a new one.
+                        mCheckForDrag = null;
+                    } else {
+                        // Check scheduled, reset alpha and update location; check will fade it in
+                        mCurrIconRow.setGearAlpha(0f);
+                        mCurrIconRow.setIconLocation(translation > 0 /* onLeft */,
+                                false /* force */);
                     }
                 }
             }
+
+            final boolean gutsExposed = (view instanceof ExpandableNotificationRow)
+                    && ((ExpandableNotificationRow) view).areGutsExposed();
+
+            if (!isPinnedHeadsUp(view) && !gutsExposed) {
+                // Only show the gear if we're not a heads up view and guts aren't exposed.
+                checkForDrag();
+            }
         }
 
         @Override
-        public void dismissChild(final View view, float velocity) {
-            cancelCheckForDrag();
-            super.dismissChild(view, velocity);
+        public void dismissChild(final View view, float velocity,
+                boolean useAccelerateInterpolator) {
+            super.dismissChild(view, velocity, useAccelerateInterpolator);
+            handleGearCoveredOrDismissed();
         }
 
         @Override
         public void snapChild(final View animView, final float targetLeft, float velocity) {
+            super.snapChild(animView, targetLeft, velocity);
+            onDragCancelled(animView);
+            if (targetLeft == 0) {
+                handleGearCoveredOrDismissed();
+            }
+        }
+
+        private void handleGearCoveredOrDismissed() {
+            cancelCheckForDrag();
+            setSnappedToGear(false);
+            if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
+                mGearExposedView = null;
+            }
+        }
+
+        @Override
+        public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
+                float translation) {
+            if (mCurrIconRow == null) {
+                cancelCheckForDrag();
+                return false; // Let SwipeHelper handle it.
+            }
+
+            boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft());
+            boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity();
+
+            if (mGearSnappedTo && mCurrIconRow.isVisible()) {
+                if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) {
+                    boolean coveringGear =
+                            Math.abs(getTranslation(animView)) <= getSpaceForGear(animView) * 0.6f;
+                    if (gestureTowardsGear || coveringGear) {
+                        // Gesture is towards or covering the gear
+                        snapChild(animView, 0 /* leftTarget */, velocity);
+                    } else if (isDismissGesture(ev)) {
+                        // Gesture is a dismiss that's not towards the gear
+                        dismissChild(animView, velocity,
+                                !swipedFastEnough() /* useAccelerateInterpolator */);
+                    } else {
+                        // Didn't move enough to dismiss or cover, snap to the gear
+                        snapToGear(animView, velocity);
+                    }
+                } else if ((!gestureFastEnough && swipedEnoughToShowGear(animView))
+                        || (gestureTowardsGear && !swipedFarEnough())) {
+                    // The gear has been snapped to previously, however, the gear is now on the
+                    // other side. If gesture is towards gear and not too far snap to the gear.
+                    snapToGear(animView, velocity);
+                } else {
+                    dismissOrSnapBack(animView, velocity, ev);
+                }
+            } else if ((!gestureFastEnough && swipedEnoughToShowGear(animView))
+                    || gestureTowardsGear) {
+                // Gear has not been snapped to previously and this is gear revealing gesture
+                snapToGear(animView, velocity);
+            } else {
+                dismissOrSnapBack(animView, velocity, ev);
+            }
+            return true;
+        }
+
+        private void dismissOrSnapBack(View animView, float velocity, MotionEvent ev) {
+            if (isDismissGesture(ev)) {
+                dismissChild(animView, velocity,
+                        !swipedFastEnough() /* useAccelerateInterpolator */);
+            } else {
+                snapChild(animView, 0 /* leftTarget */, velocity);
+            }
+        }
+
+        private void snapToGear(View animView, float velocity) {
+            final float snapBackThreshold = getSpaceForGear(animView);
+            final float target = mCurrIconRow.isIconOnLeft() ? snapBackThreshold
+                    : -snapBackThreshold;
+            mGearExposedView = mTranslatingParentView;
+            if (animView instanceof ExpandableNotificationRow) {
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
+                        ((ExpandableNotificationRow) animView).getStatusBarNotification()
+                                .getPackageName());
+            }
+            if (mCurrIconRow != null) {
+                mCurrIconRow.setSnapping(true);
+                setSnappedToGear(true);
+            }
+            onDragCancelled(animView);
+            super.snapChild(animView, target, velocity);
+        }
+
+        private boolean swipedEnoughToShowGear(View animView) {
+            if (mTranslatingParentView == null) {
+                return false;
+            }
             final float snapBackThreshold = getSpaceForGear(animView);
             final float translation = getTranslation(animView);
             final boolean fromLeft = translation > 0;
             final float absTrans = Math.abs(translation);
             final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
 
-            boolean pastGear = (fromLeft && translation >= snapBackThreshold * 0.4f
-                    && translation <= notiThreshold) ||
-                    (!fromLeft && absTrans >= snapBackThreshold * 0.4f
-                            && absTrans <= notiThreshold);
-
-            if (pastGear && !isPinnedHeadsUp(animView)) {
-                // bouncity
-                final float target = fromLeft ? snapBackThreshold : -snapBackThreshold;
-                mGearExposedView = mTranslatingParentView;
-                if (mGearDisplayedListener != null
-                        && (animView instanceof ExpandableNotificationRow)) {
-                    mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
-                }
-                super.snapChild(animView, target, velocity);
-            } else {
-                super.snapChild(animView, 0, velocity);
-            }
-        }
-
-        @Override
-        public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
-            if (mDismissAllInProgress) {
-                // When dismissing all, we translate the entire view instead.
-                super.onTranslationUpdate(animView, value, canBeDismissed);
-                return;
-            }
-            if (animView instanceof ExpandableNotificationRow) {
-                ((ExpandableNotificationRow) animView).setTranslationForOutline(value);
-            }
-            if (mCurrIconRow != null) {
-                mCurrIconRow.updateSettingsIcons(value, getSize(animView));
-            }
+            // If the notification can't be dismissed then how far it can move is
+            // restricted -- reduce the distance it needs to move in this case.
+            final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f;
+            return absTrans >= snapBackThreshold * 0.4f && absTrans <= notiThreshold;
         }
 
         @Override
@@ -3429,18 +3649,11 @@
             if (mDismissAllInProgress) {
                 // When dismissing all, we translate the entire view instead.
                 return super.getViewTranslationAnimator(v, target, listener);
+            } else if (v instanceof ExpandableNotificationRow) {
+                return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
+            } else {
+                return super.getViewTranslationAnimator(v, target, listener);
             }
-            ArrayList<Animator> animators = new ArrayList<Animator>();
-            for (int i = 0; i < mTranslatingViews.size(); i++) {
-                ObjectAnimator anim = createTranslationAnimation(mTranslatingViews.get(i), target);
-                animators.add(anim);
-                if (i == 0 && listener != null) {
-                    anim.addUpdateListener(listener);
-                }
-            }
-            AnimatorSet set = new AnimatorSet();
-            set.playTogether(animators);
-            return set;
         }
 
         @Override
@@ -3448,13 +3661,8 @@
             if (mDismissAllInProgress) {
                 // When dismissing all, we translate the entire view instead.
                 super.setTranslation(v, translate);
-                return;
-            }
-            // Translate the group of views
-            for (int i = 0; i < mTranslatingViews.size(); i++) {
-                if (mTranslatingViews.get(i) != null) {
-                    super.setTranslation(mTranslatingViews.get(i), translate);
-                }
+            } else {
+                ((ExpandableView) v).setTranslation(translate);
             }
         }
 
@@ -3463,14 +3671,60 @@
             if (mDismissAllInProgress) {
                 // When dismissing all, we translate the entire view instead.
                 return super.getTranslation(v);
+            } else {
+                return ((ExpandableView) v).getTranslation();
             }
-            // All of the views in the list should have same translation, just use first one.
-            if (mTranslatingViews.size() > 0) {
-                return super.getTranslation(mTranslatingViews.get(0));
-            }
-            return 0;
         }
 
+        public void closeControlsIfOutsideTouch(MotionEvent ev) {
+            NotificationGuts guts = mPhoneStatusBar.getExposedGuts();
+            View view = null;
+            int height = 0;
+            if (guts != null) {
+                // Checking guts
+                view = guts;
+                height = guts.getActualHeight();
+            } else if (mCurrIconRow != null && mCurrIconRow.isVisible()
+                    && mTranslatingParentView != null) {
+                // Checking gear
+                view = mTranslatingParentView;
+                height = ((ExpandableView) mTranslatingParentView).getActualHeight();
+            }
+            if (view != null) {
+                final int rx = (int) ev.getRawX();
+                final int ry = (int) ev.getRawY();
+
+                getLocationOnScreen(mTempInt2);
+                int[] location = new int[2];
+                view.getLocationOnScreen(location);
+                final int x = location[0] - mTempInt2[0];
+                final int y = location[1] - mTempInt2[1];
+                Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
+                if (!rect.contains((int) rx, (int) ry)) {
+                    // Touch was outside visible guts / gear notification, close what's visible
+                    mPhoneStatusBar.dismissPopups(-1, -1, true /* resetGear */, true /* animate */);
+                }
+            }
+        }
+
+        /**
+         * Returns whether the gesture is towards the gear location or not.
+         */
+        private boolean isTowardsGear(float velocity, boolean onLeft) {
+            if (mCurrIconRow == null) {
+                return false;
+            }
+            return mCurrIconRow.isVisible()
+                    && ((onLeft && velocity <= 0) || (!onLeft && velocity >= 0));
+        }
+
+        /**
+         * Indicates the the gear has been snapped to.
+         */
+        private void setSnappedToGear(boolean snapped) {
+            mGearSnappedOnLeft = (mCurrIconRow != null) ? mCurrIconRow.isIconOnLeft() : false;
+            mGearSnappedTo = snapped && mCurrIconRow != null;
+        }
 
         /**
          * Returns the horizontal space in pixels required to display the gear behind a
@@ -3484,7 +3738,7 @@
         }
 
         private void checkForDrag() {
-            if (mCheckForDrag == null) {
+            if (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag)) {
                 mCheckForDrag = new CheckForDrag();
                 mHandler.postDelayed(mCheckForDrag, GEAR_SHOW_DELAY);
             }
@@ -3495,60 +3749,70 @@
                 mCurrIconRow.cancelFadeAnimator();
             }
             mHandler.removeCallbacks(mCheckForDrag);
-            mCheckForDrag = null;
         }
 
         private final class CheckForDrag implements Runnable {
             @Override
             public void run() {
+                if (mTranslatingParentView == null) {
+                    return;
+                }
                 final float translation = getTranslation(mTranslatingParentView);
                 final float absTransX = Math.abs(translation);
                 final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
                 final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
-                if (mCurrIconRow != null && absTransX >= bounceBackToGearWidth * 0.4
+                if ((mCurrIconRow != null && (!mCurrIconRow.isVisible()
+                        || mCurrIconRow.isIconLocationChange(translation)))
+                        && absTransX >= bounceBackToGearWidth * 0.4
                         && absTransX < notiThreshold) {
-                    // Show icon
+                    // Fade in the gear
                     mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
                             notiThreshold);
-                } else {
-                    // Allow more to be posted if this wasn't a drag.
-                    mCheckForDrag = null;
                 }
             }
         }
 
-        private void resetExposedGearView() {
-            if (mGearExposedView == null || mGearExposedView == mTranslatingParentView) {
+        public void resetExposedGearView(boolean animate, boolean force) {
+            if (mGearExposedView == null
+                    || (!force && mGearExposedView == mTranslatingParentView)) {
                 // If no gear is showing or it's showing for this view we do nothing.
                 return;
             }
-
             final View prevGearExposedView = mGearExposedView;
+            if (animate) {
+                Animator anim = getViewTranslationAnimator(prevGearExposedView,
+                        0 /* leftTarget */, null /* updateListener */);
+                if (anim != null) {
+                    anim.start();
+                }
+            } else if (mGearExposedView instanceof ExpandableNotificationRow) {
+                ((ExpandableNotificationRow) mGearExposedView).resetTranslation();
+            }
             mGearExposedView = null;
-
-            AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
-                public void onAnimationEnd(Animator animator) {
-                    if (prevGearExposedView instanceof ExpandableNotificationRow) {
-                        ((ExpandableNotificationRow) prevGearExposedView).getSettingsRow()
-                                .resetState();
-                    }
-                }
-            };
-            AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    if (prevGearExposedView instanceof ExpandableNotificationRow) {
-                        ((ExpandableNotificationRow) prevGearExposedView)
-                                .setTranslationForOutline((float) animation.getAnimatedValue());
-                    }
-                }
-            };
-            Animator set = getViewTranslationAnimator(prevGearExposedView, 0, updateListener);
-            set.addListener(listener);
-            set.start();
+            mGearSnappedTo = false;
         }
     }
 
+    private void updateContinuousShadowDrawing() {
+        boolean continuousShadowUpdate = mAnimationRunning
+                || !mAmbientState.getDraggedViews().isEmpty();
+        if (continuousShadowUpdate != mContinuousShadowUpdate) {
+            if (continuousShadowUpdate) {
+                getViewTreeObserver().addOnPreDrawListener(mShadowUpdater);
+            } else {
+                getViewTreeObserver().removeOnPreDrawListener(mShadowUpdater);
+            }
+        }
+    }
+
+    public void resetExposedGearView(boolean animate, boolean force) {
+        mSwipeHelper.resetExposedGearView(animate, force);
+    }
+
+    public void closeControlsIfOutsideTouch(MotionEvent ev) {
+        mSwipeHelper.closeControlsIfOutsideTouch(ev);
+    }
+
     static class AnimationEvent {
 
         static AnimationFilter[] FILTERS = new AnimationFilter[] {
@@ -3604,7 +3868,6 @@
 
                 // ANIMATION_TYPE_DIMMED
                 new AnimationFilter()
-                        .animateY()
                         .animateDimmed(),
 
                 // ANIMATION_TYPE_CHANGE_POSITION
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
new file mode 100644
index 0000000..a35465e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+/**
+ * Interface for container layouts that scroll and listen for long presses. A child that
+ * wants to handle long press can use this to cancel the parents long press logic or request
+ * to be made visible by scrolling to it.
+ */
+public interface ScrollContainer {
+    /**
+     * Request that the view does not perform long press for the current touch.
+     */
+    void requestDisallowLongPress();
+
+    /**
+     * Request that the view is made visible by scrolling to it.
+     */
+    void scrollTo(View v);
+}
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 e87b363..c7333c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -24,9 +24,11 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -50,13 +52,8 @@
     private StackIndentationFunctor mBottomStackIndentationFunctor;
 
     private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
-    private boolean mIsExpansionChanging;
-    private int mFirstChildMaxHeight;
     private boolean mIsExpanded;
-    private ExpandableView mFirstChildWhileExpanding;
-    private boolean mExpandedOnStart;
     private int mBottomStackSlowDownLength;
-    private int mCollapseSecondCardPadding;
 
     public StackScrollAlgorithm(Context context) {
         initView(context);
@@ -84,8 +81,6 @@
         mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
         mBottomStackSlowDownLength = context.getResources()
                 .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
-        mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.notification_collapse_second_card_padding);
         mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
                 MAX_ITEMS_IN_BOTTOM_STACK,
                 mBottomStackPeekSize,
@@ -296,18 +291,22 @@
         int childCount = hostView.getChildCount();
         state.visibleChildren.clear();
         state.visibleChildren.ensureCapacity(childCount);
-        state.increasedPaddingSet.clear();
+        state.increasedPaddingMap.clear();
         int notGoneIndex = 0;
         ExpandableView lastView = null;
         for (int i = 0; i < childCount; i++) {
             ExpandableView v = (ExpandableView) hostView.getChildAt(i);
             if (v.getVisibility() != View.GONE) {
                 notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
-                boolean needsIncreasedPadding = v.needsIncreasedPadding();
-                if (needsIncreasedPadding) {
-                    state.increasedPaddingSet.add(v);
+                float increasedPadding = v.getIncreasedPaddingAmount();
+                if (increasedPadding != 0.0f) {
+                    state.increasedPaddingMap.put(v, increasedPadding);
                     if (lastView != null) {
-                        state.increasedPaddingSet.add(lastView);
+                        Float prevValue = state.increasedPaddingMap.get(lastView);
+                        float newValue = prevValue != null
+                                ? Math.max(prevValue, increasedPadding)
+                                : increasedPadding;
+                        state.increasedPaddingMap.put(lastView, newValue);
                     }
                 }
                 if (v instanceof ExpandableNotificationRow) {
@@ -369,7 +368,7 @@
             childViewState.location = StackViewState.LOCATION_UNKNOWN;
             paddingAfterChild = getPaddingAfterChild(algorithmState, child);
             int childHeight = getMaxAllowedChildHeight(child);
-            int minHeight = child.getMinHeight();
+            int collapsedHeight = child.getCollapsedHeight();
             childViewState.yTranslation = currentYPosition;
             if (i == 0) {
                 updateFirstChildHeight(child, childViewState, childHeight, ambientState);
@@ -385,7 +384,7 @@
                     // According to the regular scroll view we are fully translated out of the
                     // bottom of the screen so we are fully in the bottom stack
                     updateStateForChildFullyInBottomStack(algorithmState,
-                            bottomStackStart, childViewState, minHeight, ambientState, child);
+                            bottomStackStart, childViewState, collapsedHeight, ambientState, child);
                 } else {
                     // According to the regular scroll view we are currently translating out of /
                     // into the bottom of the screen
@@ -422,9 +421,12 @@
 
     private int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
             ExpandableView child) {
-        return algorithmState.increasedPaddingSet.contains(child)
-                ? mIncreasedPaddingBetweenElements
-                : mPaddingBetweenElements;
+        Float paddingValue = algorithmState.increasedPaddingMap.get(child);
+        return paddingValue == null
+                ? mPaddingBetweenElements
+                : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
+                        mIncreasedPaddingBetweenElements,
+                        paddingValue);
     }
 
     private void updateHeadsUpStates(StackScrollState resultState,
@@ -473,17 +475,17 @@
         float newTranslation = Math.max(ambientState.getTopPadding()
                 + ambientState.getStackTranslation(), childState.yTranslation);
         childState.height = (int) Math.max(childState.height - (newTranslation
-                - childState.yTranslation), row.getMinHeight());
+                - childState.yTranslation), row.getCollapsedHeight());
         childState.yTranslation = newTranslation;
     }
 
     private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
             StackViewState childState) {
         float newTranslation;
-        float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getMinHeight();
+        float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getCollapsedHeight();
         newTranslation = Math.min(childState.yTranslation, bottomPosition);
         childState.height = (int) Math.max(childState.height
-                - (childState.yTranslation - newTranslation), row.getMinHeight());
+                - (childState.yTranslation - newTranslation), row.getCollapsedHeight());
         childState.yTranslation = newTranslation;
     }
 
@@ -499,7 +501,7 @@
             int childHeight, int minHeight, AmbientState ambientState) {
 
         int bottomStackStart = ambientState.getInnerHeight()
-                - mBottomStackPeekSize - mCollapseSecondCardPadding;
+                - mBottomStackPeekSize - mBottomStackSlowDownLength;
         int childStart = bottomStackStart - childHeight;
         if (childStart < childViewState.yTranslation) {
             float newHeight = bottomStackStart - childViewState.yTranslation;
@@ -532,10 +534,10 @@
         float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
         algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
         int newHeight = childHeight;
-        if (childHeight > child.getMinHeight()) {
+        if (childHeight > child.getCollapsedHeight()) {
             newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
                     getPaddingAfterChild(algorithmState, child) - currentYPosition, childHeight),
-                    child.getMinHeight());
+                    child.getCollapsedHeight());
             childViewState.height = newHeight;
         }
         childViewState.yTranslation = transitioningPositionStart + offset - newHeight
@@ -545,7 +547,7 @@
 
     private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
             float transitioningPositionStart, StackViewState childViewState,
-            int minHeight, AmbientState ambientState, ExpandableView child) {
+            int collapsedHeight, AmbientState ambientState, ExpandableView child) {
         float currentYPosition;
         algorithmState.itemsInBottomStack += 1.0f;
         if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
@@ -566,16 +568,14 @@
             childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
             currentYPosition = ambientState.getInnerHeight();
         }
-        childViewState.height = minHeight;
-        childViewState.yTranslation = currentYPosition - minHeight;
+        childViewState.height = collapsedHeight;
+        childViewState.yTranslation = currentYPosition - collapsedHeight;
     }
 
 
     /**
      * Update the height of the first child i.e clamp it to the bottom stack
      *
-     *
-
      * @param child the child to update
      * @param childViewState the viewstate of the child
      * @param childHeight the height of the child
@@ -586,13 +586,10 @@
 
             // The starting position of the bottom stack peek
             int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
-                    mCollapseSecondCardPadding + ambientState.getScrollY();
+                    mBottomStackSlowDownLength + ambientState.getScrollY();
             // Collapse and expand the first child while the shade is being expanded
-            float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
-                    ? mFirstChildMaxHeight
-                    : childHeight;
-            childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
-                    child.getMinHeight());
+        childViewState.height = (int) Math.max(Math.min(bottomPeekStart, (float) childHeight),
+                    child.getCollapsedHeight());
     }
 
     /**
@@ -605,20 +602,40 @@
     private void updateZValuesForState(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
         int childCount = algorithmState.visibleChildren.size();
-        int childrenOnTop = 0;
+        float childrenOnTop = 0.0f;
         for (int i = childCount - 1; i >= 0; i--) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             StackViewState childViewState = resultState.getViewStateForView(child);
             if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
                 // We are in the bottom stack
                 float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack);
-                childViewState.zTranslation = mZBasicHeight
-                        - numItemsAbove * mZDistanceBetweenElements;
+                float zSubtraction;
+                if (numItemsAbove <= 1.0f) {
+                    float factor = 0.2f;
+                    // Lets fade in slower to the threshold to make the shadow fade in look nicer
+                    if (numItemsAbove <= factor) {
+                        zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
+                                * numItemsAbove * (1.0f / factor);
+                    } else {
+                        zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
+                                + (numItemsAbove - factor) * (1.0f / (1.0f - factor))
+                                        * (mZDistanceBetweenElements
+                                                - FakeShadowView.SHADOW_SIBLING_TRESHOLD);
+                    }
+                } else {
+                    zSubtraction = numItemsAbove * mZDistanceBetweenElements;
+                }
+                childViewState.zTranslation = mZBasicHeight - zSubtraction;
             } else if (child.mustStayOnScreen()
                     && childViewState.yTranslation < ambientState.getTopPadding()
                     + ambientState.getStackTranslation()) {
-                // TODO; do this more cleanly
-                childrenOnTop++;
+                if (childrenOnTop != 0.0f) {
+                    childrenOnTop++;
+                } else {
+                    float overlap = ambientState.getTopPadding()
+                            + ambientState.getStackTranslation() - childViewState.yTranslation;
+                    childrenOnTop += Math.min(1.0f, overlap / childViewState.height);
+                }
                 childViewState.zTranslation = mZBasicHeight
                         + childrenOnTop * mZDistanceBetweenElements;
             } else {
@@ -627,55 +644,6 @@
         }
     }
 
-    public void onExpansionStarted(StackScrollState currentState) {
-        mIsExpansionChanging = true;
-        mExpandedOnStart = mIsExpanded;
-        ViewGroup hostView = currentState.getHostView();
-        updateFirstChildHeightWhileExpanding(hostView);
-    }
-
-    private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) {
-        mFirstChildWhileExpanding = (ExpandableView) findFirstVisibleChild(hostView);
-        if (mFirstChildWhileExpanding != null) {
-            if (mExpandedOnStart) {
-
-                // We are collapsing the shade, so the first child can get as most as high as the
-                // current height or the end value of the animation.
-                mFirstChildMaxHeight = StackStateAnimator.getFinalActualHeight(
-                        mFirstChildWhileExpanding);
-            } else {
-                updateFirstChildMaxSizeToMaxHeight();
-            }
-        } else {
-            mFirstChildMaxHeight = 0;
-        }
-    }
-
-    private void updateFirstChildMaxSizeToMaxHeight() {
-        // We are expanding the shade, expand it to its full height.
-        if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
-
-            // This child was not layouted yet, wait for a layout pass
-            mFirstChildWhileExpanding
-                    .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-                        @Override
-                        public void onLayoutChange(View v, int left, int top, int right,
-                                int bottom, int oldLeft, int oldTop, int oldRight,
-                                int oldBottom) {
-                            if (mFirstChildWhileExpanding != null) {
-                                mFirstChildMaxHeight = getMaxAllowedChildHeight(
-                                        mFirstChildWhileExpanding);
-                            } else {
-                                mFirstChildMaxHeight = 0;
-                            }
-                            v.removeOnLayoutChangeListener(this);
-                        }
-                    });
-        } else {
-            mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
-        }
-    }
-
     private boolean isMaxSizeInitialized(ExpandableView child) {
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -695,32 +663,10 @@
         return null;
     }
 
-    public void onExpansionStopped() {
-        mIsExpansionChanging = false;
-        mFirstChildWhileExpanding = null;
-    }
-
     public void setIsExpanded(boolean isExpanded) {
         this.mIsExpanded = isExpanded;
     }
 
-    public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) {
-        if (mIsExpansionChanging) {
-            hostView.post(new Runnable() {
-                @Override
-                public void run() {
-                    updateFirstChildHeightWhileExpanding(hostView);
-                }
-            });
-        }
-    }
-
-    public void onReset(ExpandableView view) {
-        if (view.equals(mFirstChildWhileExpanding)) {
-            updateFirstChildMaxSizeToMaxHeight();
-        }
-    }
-
     class StackScrollAlgorithmState {
 
         /**
@@ -744,9 +690,10 @@
         public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
 
         /**
-         * The children from the host that need an increased padding after them.
+         * The children from the host that need an increased padding after them. A value of 0 means
+         * no increased padding, a value of 1 means full padding.
          */
-        public final HashSet<ExpandableView> increasedPaddingSet = new HashSet<>();
+        public final HashMap<ExpandableView, Float> increasedPaddingMap = new HashMap<>();
     }
 
 }
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 cf4802d..dba5bbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -972,10 +972,10 @@
     }
 
     /**
-     * Get the end value of the height animation running on a view or the actualHeight
+     * Get the end value of the yTranslation animation running on a view or the yTranslation
      * if no animation is running.
      */
-    public static float getFinalTranslationY(ExpandableView view) {
+    public static float getFinalTranslationY(View view) {
         if (view == null) {
             return 0;
         }
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 110258c..f9bb5e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -116,11 +116,16 @@
     }
 
     @Override
+    protected boolean toggleSplitScreenMode() {
+        return false;
+    }
+
+    @Override
     public void maybeEscalateHeadsUp() {
     }
 
     @Override
-    protected boolean isPanelFullyCollapsed() {
+    public boolean isPanelFullyCollapsed() {
         return false;
     }
 
@@ -166,6 +171,10 @@
     }
 
     @Override
+    public void appTransitionFinished() {
+    }
+
+    @Override
     public void onCameraLaunchGestureDetected(int source) {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java
index 9f11325..af95cf9 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java
@@ -28,6 +28,8 @@
 import android.view.View;
 import android.widget.SeekBar;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.NightModeController;
 
@@ -54,6 +56,7 @@
     @Override
     public void onResume() {
         super.onResume();
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_COLOR_AND_APPEARANCE, true);
         // TODO: Figure out better title model for Tuner, to avoid any more of this.
         getActivity().setTitle(R.string.color_and_appearance);
 
@@ -63,6 +66,12 @@
     }
 
     @Override
+    public void onPause() {
+        super.onPause();
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_COLOR_AND_APPEARANCE, false);
+    }
+
+    @Override
     public void onDisplayPreferenceDialog(Preference preference) {
         if (preference instanceof CalibratePreference) {
             CalibrateDialog.show(this);
@@ -76,6 +85,7 @@
     }
 
     private void onApply() {
+        MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_CALIBRATE_DISPLAY_CHANGED);
         mNightModeController.setCustomValues(Settings.Secure.getString(
                 getContext().getContentResolver(), Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX));
         getView().removeCallbacks(mResetColorMatrix);
@@ -125,6 +135,7 @@
             bindView(v.findViewById(R.id.r_group), 0);
             bindView(v.findViewById(R.id.g_group), 5);
             bindView(v.findViewById(R.id.b_group), 10);
+            MetricsLogger.visible(getContext(), MetricsEvent.TUNER_CALIBRATE_DISPLAY);
             return new AlertDialog.Builder(getContext())
                     .setTitle(R.string.calibrate_display)
                     .setView(v)
@@ -133,6 +144,12 @@
                     .create();
         }
 
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            super.onDismiss(dialog);
+            MetricsLogger.hidden(getContext(), MetricsEvent.TUNER_CALIBRATE_DISPLAY);
+        }
+
         private void bindView(View view, final int index) {
             SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
             seekBar.setMax(1000);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
index e9650ea..ae2856c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
@@ -17,23 +17,20 @@
 
 import android.annotation.Nullable;
 import android.app.UiModeManager;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.support.v14.preference.PreferenceFragment;
 import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Switch;
-
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.policy.NightModeController;
 import com.android.systemui.statusbar.policy.NightModeController.Listener;
 import com.android.systemui.tuner.TunerService.Tunable;
@@ -46,7 +43,6 @@
     public static final String EXTRA_SHOW_NIGHT_MODE = "show_night_mode";
 
     private static final CharSequence KEY_AUTO = "auto";
-    private static final CharSequence KEY_DARK_THEME = "dark_theme";
     private static final CharSequence KEY_ADJUST_TINT = "adjust_tint";
     private static final CharSequence KEY_ADJUST_BRIGHTNESS = "adjust_brightness";
 
@@ -54,7 +50,6 @@
 
     private NightModeController mNightModeController;
     private SwitchPreference mAutoSwitch;
-    private SwitchPreference mDarkTheme;
     private SwitchPreference mAdjustTint;
     private SwitchPreference mAdjustBrightness;
     private UiModeManager mUiModeManager;
@@ -82,8 +77,6 @@
         addPreferencesFromResource(R.xml.night_mode);
         mAutoSwitch = (SwitchPreference) findPreference(KEY_AUTO);
         mAutoSwitch.setOnPreferenceChangeListener(this);
-        mDarkTheme = (SwitchPreference) findPreference(KEY_DARK_THEME);
-        mDarkTheme.setOnPreferenceChangeListener(this);
         mAdjustTint = (SwitchPreference) findPreference(KEY_ADJUST_TINT);
         mAdjustTint.setOnPreferenceChangeListener(this);
         mAdjustBrightness = (SwitchPreference) findPreference(KEY_ADJUST_BRIGHTNESS);
@@ -100,6 +93,7 @@
             @Override
             public void onClick(View v) {
                 boolean newState = !mNightModeController.isEnabled();
+                MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_NIGHT_MODE, newState);
                 mNightModeController.setNightMode(newState);
                 mSwitch.setChecked(newState);
             }
@@ -109,34 +103,37 @@
     @Override
     public void onResume() {
         super.onResume();
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_NIGHT_MODE, true);
         mNightModeController.addListener(this);
         TunerService.get(getContext()).addTunable(this, Secure.BRIGHTNESS_USE_TWILIGHT,
                 NightModeController.NIGHT_MODE_ADJUST_TINT);
-        mDarkTheme.setChecked(mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO);
         calculateDisabled();
     }
 
     @Override
     public void onPause() {
         super.onPause();
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_NIGHT_MODE, false);
         mNightModeController.removeListener(this);
         TunerService.get(getContext()).removeTunable(this);
     }
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final Boolean value = (Boolean) newValue;
         if (mAutoSwitch == preference) {
-            mNightModeController.setAuto((Boolean) newValue);
-        } else if (mDarkTheme == preference) {
-            mUiModeManager.setNightMode(((Boolean) newValue) ? UiModeManager.MODE_NIGHT_AUTO
-                    : UiModeManager.MODE_NIGHT_NO);
-            postCalculateDisabled();
+            MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_NIGHT_MODE_AUTO, value);
+            mNightModeController.setAuto(value);
         } else if (mAdjustTint == preference) {
-            mNightModeController.setAdjustTint((Boolean) newValue);
+            MetricsLogger.action(getContext(),
+                    MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_TINT, value);
+            mNightModeController.setAdjustTint(value);
             postCalculateDisabled();
         } else if (mAdjustBrightness == preference) {
+            MetricsLogger.action(getContext(),
+                    MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_BRIGHTNESS, value);
             TunerService.get(getContext()).setValue(Secure.BRIGHTNESS_USE_TWILIGHT,
-                    ((Boolean) newValue) ? 1 : 0);
+                    value ? 1 : 0);
             postCalculateDisabled();
         } else {
             return false;
@@ -155,19 +152,15 @@
     }
 
     private void calculateDisabled() {
-        int enabledCount = (mDarkTheme.isChecked() ? 1 : 0)
-                + (mAdjustTint.isChecked() ? 1 : 0)
+        int enabledCount = (mAdjustTint.isChecked() ? 1 : 0)
                 + (mAdjustBrightness.isChecked() ? 1 : 0);
         if (enabledCount == 1) {
-            if (mDarkTheme.isChecked()) {
-                mDarkTheme.setEnabled(false);
-            } else if (mAdjustTint.isChecked()) {
+            if (mAdjustTint.isChecked()) {
                 mAdjustTint.setEnabled(false);
             } else {
                 mAdjustBrightness.setEnabled(false);
             }
         } else {
-            mDarkTheme.setEnabled(true);
             mAdjustTint.setEnabled(true);
             mAdjustBrightness.setEnabled(true);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
index 61135bd..fe44502 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
@@ -15,17 +15,14 @@
  */
 package com.android.systemui.tuner;
 
-import android.app.ActivityManager;
 import android.content.Intent;
-import android.provider.Settings;
-
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.NightModeController;
 
-import java.util.Objects;
-
 
 public class NightModeTile extends QSTile<QSTile.State> implements NightModeController.Listener {
 
@@ -46,6 +43,12 @@
     }
 
     @Override
+    public boolean isAvailable() {
+        return Prefs.getBoolean(mContext, Key.QS_NIGHT_ADDED, false)
+                && TunerService.isTunerEnabled(mContext);
+    }
+
+    @Override
     public void setListening(boolean listening) {
         if (listening) {
             mNightModeController.addListener(this);
@@ -73,6 +76,11 @@
     }
 
     @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.night_mode);
+    }
+
+    @Override
     protected void handleUpdateState(State state, Object arg) {
         // TODO: Right now this is just a dropper, needs an actual night icon.
         boolean enabled = mNightModeController.isEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index def597d..748ee97 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -45,6 +45,13 @@
     }
 
     @Override
+    public void onBackPressed() {
+        if (!getFragmentManager().popBackStackImmediate()) {
+            super.onBackPressed();
+        }
+    }
+
+    @Override
     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
         try {
             Class<?> cls = Class.forName(pref.getFragment());
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index b738136..5b9ebd7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -6,18 +6,21 @@
 import android.support.v14.preference.SwitchPreference;
 import android.util.AttributeSet;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.tuner.TunerService.Tunable;
 
 public class TunerSwitch extends SwitchPreference implements Tunable {
 
     private final boolean mDefault;
+    private final int mAction;
 
     public TunerSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TunerSwitch);
         mDefault = a.getBoolean(R.styleable.TunerSwitch_defValue, false);
+        mAction = a.getInt(R.styleable.TunerSwitch_metricsAction, -1);
     }
 
     @Override
@@ -38,6 +41,14 @@
     }
 
     @Override
+    protected void onClick() {
+        super.onClick();
+        if (mAction != -1) {
+            MetricsLogger.action(getContext(), mAction, isChecked());
+        }
+    }
+
+    @Override
     protected boolean persistBoolean(boolean value) {
         for (String key : getKey().split(",")) {
             Settings.Secure.putString(getContext().getContentResolver(), key, value ? "1" : "0");
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
new file mode 100644
index 0000000..3f87611
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tv.pip;
+
+import android.content.Context;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
+import android.view.View;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View.OnFocusChangeListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.LinearLayout;
+import android.util.AttributeSet;
+
+import com.android.systemui.R;
+
+import static android.media.session.PlaybackState.ACTION_PAUSE;
+import static android.media.session.PlaybackState.ACTION_PLAY;
+
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PLAYING;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PAUSED;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_UNAVAILABLE;
+
+
+/**
+ * A view containing PIP controls including fullscreen, close, and media controls.
+ */
+public class PipControlsView extends LinearLayout {
+    /**
+     * An interface to listen user action.
+     */
+    public abstract static interface Listener {
+        /**
+         * Called when an user clicks close PIP button.
+         */
+        public abstract void onClosed();
+    };
+
+    private MediaController mMediaController;
+
+    final PipManager mPipManager = PipManager.getInstance();
+    Listener mListener;
+
+    View mFullButtonView;
+    View mFullDescriptionView;
+    View mPlayPauseView;
+    ImageView mPlayPauseButtonImageView;
+    TextView mPlayPauseDescriptionTextView;
+    View mCloseButtonView;
+    View mCloseDescriptionView;
+
+    private boolean mHasFocus;
+    private OnFocusChangeListener mOnChildFocusChangeListener;
+
+    private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            updatePlayPauseView();
+        }
+    };
+
+    private PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+        @Override
+        public void onMediaControllerChanged() {
+            updateMediaController();
+        }
+    };
+
+    public PipControlsView(Context context) {
+        this(context, null, 0, 0);
+    }
+
+    public PipControlsView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0, 0);
+    }
+
+    public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        LayoutInflater inflater = (LayoutInflater) getContext()
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.tv_pip_controls, this);
+
+        setOrientation(LinearLayout.HORIZONTAL);
+        setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+
+        mFullButtonView = findViewById(R.id.full_button);
+        mFullDescriptionView = findViewById(R.id.full_desc);
+        mFullButtonView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mPipManager.movePipToFullscreen();
+            }
+        });
+        mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+                onChildViewFocusChanged();
+            }
+        });
+
+        mPlayPauseView = findViewById(R.id.play_pause);
+        mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
+        mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
+        mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mMediaController == null || mMediaController.getPlaybackState() == null) {
+                    return;
+                }
+                long actions = mMediaController.getPlaybackState().getActions();
+                int state = mMediaController.getPlaybackState().getState();
+                if (mPipManager.getPlaybackState() == PLAYBACK_STATE_PAUSED) {
+                    mMediaController.getTransportControls().play();
+                } else if (mPipManager.getPlaybackState() == PLAYBACK_STATE_PLAYING) {
+                    mMediaController.getTransportControls().pause();
+                }
+                // View will be updated later in {@link mMediaControllerCallback}
+            }
+        });
+        mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                mPlayPauseDescriptionTextView.setVisibility(
+                        hasFocus ? View.VISIBLE : View.INVISIBLE);
+                onChildViewFocusChanged();
+            }
+        });
+
+        mCloseButtonView = findViewById(R.id.close_button);
+        mCloseDescriptionView = findViewById(R.id.close_desc);
+        mCloseButtonView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mPipManager.closePip();
+                if (mListener != null) {
+                    mListener.onClosed();
+                }
+            }
+        });
+        mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+                onChildViewFocusChanged();
+            }
+        });
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        updateMediaController();
+        mPipManager.addMediaListener(mPipMediaListener);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mPipManager.removeMediaListener(mPipMediaListener);
+        if (mMediaController != null) {
+            mMediaController.unregisterCallback(mMediaControllerCallback);
+        }
+    }
+
+    private void updateMediaController() {
+        MediaController newController = mPipManager.getMediaController();
+        if (mMediaController == newController) {
+            return;
+        }
+        if (mMediaController != null) {
+            mMediaController.unregisterCallback(mMediaControllerCallback);
+        }
+        mMediaController = newController;
+        if (mMediaController != null) {
+            mMediaController.registerCallback(mMediaControllerCallback);
+        }
+        updatePlayPauseView();
+    }
+
+    private void updatePlayPauseView() {
+        int state = mPipManager.getPlaybackState();
+        if (state == PLAYBACK_STATE_UNAVAILABLE) {
+            mPlayPauseView.setVisibility(View.GONE);
+        } else {
+            mPlayPauseView.setVisibility(View.VISIBLE);
+            if (state == PLAYBACK_STATE_PLAYING) {
+                mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
+                mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
+            } else {
+                mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
+                mPlayPauseDescriptionTextView.setText(R.string.pip_play);
+            }
+        }
+    }
+
+    /**
+     * Sets a listener to be invoked when {@link android.view.View.hasFocus()} is changed.
+     */
+    public void setOnChildFocusChangeListener(OnFocusChangeListener listener) {
+        mOnChildFocusChangeListener = listener;
+    }
+
+    private void onChildViewFocusChanged() {
+        // At this moment, hasFocus() returns true although there's no focused child.
+        boolean hasFocus = (mFullButtonView != null && mFullButtonView.isFocused())
+                || (mPlayPauseButtonImageView != null && mPlayPauseButtonImageView.isFocused())
+                || (mCloseButtonView != null && mCloseButtonView.isFocused());
+        if (mHasFocus != hasFocus) {
+            mHasFocus = hasFocus;
+            if (mOnChildFocusChangeListener != null) {
+                mOnChildFocusChangeListener.onFocusChange(getFocusedChild(), mHasFocus);
+            }
+        }
+    }
+
+    /**
+     * Sets the {@link Listener} to listen user actions.
+     */
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index fac6338..fe54090 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -21,19 +21,26 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
-import android.app.ITaskStackListener;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.util.Log;
 
 import com.android.systemui.Prefs;
+import com.android.systemui.R;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -48,86 +55,90 @@
 public class PipManager {
     private static final String TAG = "PipManager";
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_FORCE_ONBOARDING = false;
+    private static final boolean DEBUG_FORCE_ONBOARDING =
+            SystemProperties.getBoolean("debug.tv.pip_force_onboarding", false);
 
     private static PipManager sPipManager;
 
     private static final int MAX_RUNNING_TASKS_COUNT = 10;
 
+    /**
+     * State when there's no PIP.
+     */
     public static final int STATE_NO_PIP = 0;
+    /**
+     * State when PIP is shown with an overlay message on top of it.
+     * This is used as default PIP state.
+     */
     public static final int STATE_PIP_OVERLAY = 1;
+    /**
+     * State when PIP menu dialog is shown.
+     */
     public static final int STATE_PIP_MENU = 2;
+    /**
+     * State when PIP is shown in Recents.
+     */
+    public static final int STATE_PIP_RECENTS = 3;
+    /**
+     * State when PIP is shown in Recents and it's focused to allow an user to control.
+     */
+    public static final int STATE_PIP_RECENTS_FOCUSED = 4;
 
     private static final int TASK_ID_NO_PIP = -1;
     private static final int INVALID_RESOURCE_TYPE = -1;
 
     public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH = 0x1;
     public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH = 0x2;
+
+    /**
+     * PIPed activity is playing a media and it can be paused.
+     */
+    static final int PLAYBACK_STATE_PLAYING = 0;
+    /**
+     * PIPed activity has a paused media and it can be played.
+     */
+    static final int PLAYBACK_STATE_PAUSED = 1;
+    /**
+     * Users are unable to control PIPed activity's media playback.
+     */
+    static final int PLAYBACK_STATE_UNAVAILABLE = 2;
+
+    private static final int CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS = 3000;
+
     private int mSuspendPipResizingReason;
 
     private Context mContext;
+    private PipRecentsOverlayManager mPipRecentsOverlayManager;
     private IActivityManager mActivityManager;
+    private MediaSessionManager mMediaSessionManager;
     private int mState = STATE_NO_PIP;
     private final Handler mHandler = new Handler();
     private List<Listener> mListeners = new ArrayList<>();
-    private Rect mPipBound;
-    private Rect mMenuModePipBound;
+    private List<MediaListener> mMediaListeners = new ArrayList<>();
+    private Rect mCurrentPipBounds;
+    private Rect mPipBounds;
+    private Rect mMenuModePipBounds;
+    private Rect mRecentsPipBounds;
+    private Rect mRecentsFocusedPipBounds;
+    private int mRecentsFocusChangedAnimationDurationMs;
     private boolean mInitialized;
     private int mPipTaskId = TASK_ID_NO_PIP;
+    private ComponentName mPipComponentName;
+    private MediaController mPipMediaController;
     private boolean mOnboardingShown;
 
-    private final Runnable mOnActivityPinnedRunnable = new Runnable() {
-        @Override
-        public void run() {
-            StackInfo stackInfo = null;
-            try {
-                stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
-                if (stackInfo == null) {
-                    Log.w(TAG, "There is no pinned stack");
-                    return;
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "getStackInfo failed", e);
-                return;
-            }
-            if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
-            mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
-            // Set state to overlay so we show it when the pinned stack animation ends.
-            mState = STATE_PIP_OVERLAY;
-            launchPipOnboardingActivityIfNeeded();
-        }
-    };
-    private final Runnable mOnTaskStackChanged = new Runnable() {
-        @Override
-        public void run() {
-            if (mState != STATE_NO_PIP) {
-                // TODO: check whether PIP task is closed.
-            }
-        }
-    };
-    private final Runnable mOnPinnedActivityRestartAttempt = new Runnable() {
-        @Override
-        public void run() {
-            movePipToFullscreen();
-        }
-    };
-    private final Runnable mOnPinnedStackAnimationEnded = new Runnable() {
-        @Override
-        public void run() {
-            if (mState == STATE_PIP_OVERLAY) {
-                showPipOverlay();
-            } else if (mState == STATE_PIP_MENU) {
-                showPipMenu();
-            }
-        }
-    };
-
     private final Runnable mResizePinnedStackRunnable = new Runnable() {
         @Override
         public void run() {
             resizePinnedStack(mState);
         }
     };
+    private final Runnable mClosePipRunnable = new Runnable() {
+        @Override
+        public void run() {
+            closePip();
+        }
+    };
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -145,6 +156,13 @@
 
         }
     };
+    private final MediaSessionManager.OnActiveSessionsChangedListener mActiveMediaSessionListener =
+            new MediaSessionManager.OnActiveSessionsChangedListener() {
+                @Override
+                public void onActiveSessionsChanged(List<MediaController> controllers) {
+                    updateMediaController(controllers);
+                }
+            };
 
     private PipManager() { }
 
@@ -158,24 +176,28 @@
         mInitialized = true;
         mContext = context;
         Resources res = context.getResources();
-        mPipBound = Rect.unflattenFromString(res.getString(
+        mPipBounds = Rect.unflattenFromString(res.getString(
                 com.android.internal.R.string.config_defaultPictureInPictureBounds));
-        mMenuModePipBound = Rect.unflattenFromString(res.getString(
-                com.android.internal.R.string.config_centeredPictureInPictureBounds));
+        mMenuModePipBounds = Rect.unflattenFromString(res.getString(
+                R.string.pip_menu_bounds));
+        mRecentsPipBounds = Rect.unflattenFromString(res.getString(
+                R.string.pip_recents_bounds));
+        mRecentsFocusedPipBounds = Rect.unflattenFromString(res.getString(
+                R.string.pip_recents_focused_bounds));
+        mRecentsFocusChangedAnimationDurationMs = res.getInteger(
+                R.integer.recents_tv_pip_focus_anim_duration);
 
         mActivityManager = ActivityManagerNative.getDefault();
-        TaskStackListener taskStackListener = new TaskStackListener();
-        IActivityManager iam = ActivityManagerNative.getDefault();
-        try {
-            iam.registerTaskStackListener(taskStackListener);
-        } catch (RemoteException e) {
-            Log.e(TAG, "registerTaskStackListener failed", e);
-        }
+        SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
         mContext.registerReceiver(mBroadcastReceiver, intentFilter);
         mOnboardingShown = Prefs.getBoolean(
                 mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
+
+        mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
+        mMediaSessionManager =
+                (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
     }
 
     /**
@@ -184,7 +206,7 @@
      */
     public void requestTvPictureInPicture() {
         if (DEBUG) Log.d(TAG, "requestTvPictureInPicture()");
-        if (!hasPipTasks()) {
+        if (!isPipShown()) {
             startPip();
         } else if (mState == STATE_PIP_OVERLAY) {
             resizePinnedStack(STATE_PIP_MENU);
@@ -193,7 +215,7 @@
 
     private void startPip() {
         try {
-            mActivityManager.moveTopActivityToPinnedStack(FULLSCREEN_WORKSPACE_STACK_ID, mPipBound);
+            mActivityManager.moveTopActivityToPinnedStack(FULLSCREEN_WORKSPACE_STACK_ID, mPipBounds);
         } catch (RemoteException|IllegalArgumentException e) {
             Log.e(TAG, "moveTopActivityToPinnedStack failed", e);
         }
@@ -203,19 +225,31 @@
      * Closes PIP (PIPed activity and PIP system UI).
      */
     public void closePip() {
+        closePipInternal(true);
+    }
+
+    private void closePipInternal(boolean removePipStack) {
         mState = STATE_NO_PIP;
         mPipTaskId = TASK_ID_NO_PIP;
-        try {
-            mActivityManager.removeStack(PINNED_STACK_ID);
-        } catch (RemoteException e) {
-            Log.e(TAG, "removeStack failed", e);
+        mPipMediaController = null;
+        mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener);
+        if (removePipStack) {
+            try {
+                mActivityManager.removeStack(PINNED_STACK_ID);
+            } catch (RemoteException e) {
+                Log.e(TAG, "removeStack failed", e);
+            }
         }
+        for (int i = mListeners.size() - 1; i >= 0; --i) {
+            mListeners.get(i).onPipActivityClosed();
+        }
+        mHandler.removeCallbacks(mClosePipRunnable);
     }
 
     /**
      * Moves the PIPed activity to the fullscreen and closes PIP system UI.
      */
-    public void movePipToFullscreen() {
+    void movePipToFullscreen() {
         mState = STATE_NO_PIP;
         mPipTaskId = TASK_ID_NO_PIP;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -231,12 +265,7 @@
      */
     private void showPipOverlay() {
         if (DEBUG) Log.d(TAG, "showPipOverlay()");
-        mState = STATE_PIP_OVERLAY;
-        Intent intent = new Intent(mContext, PipOverlayActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchStackId(PINNED_STACK_ID);
-        mContext.startActivity(intent, options.toBundle());
+        PipOverlayActivity.showPipOverlay(mContext);
     }
 
     /**
@@ -267,65 +296,115 @@
      * Resize the Pip to the appropriate size for the input state.
      * @param state In Pip state also used to determine the new size for the Pip.
      */
-    public void resizePinnedStack(int state) {
+    void resizePinnedStack(int state) {
         if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+        boolean wasRecentsShown =
+                (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED);
         mState = state;
-        Rect bounds;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onPipResizeAboutToStart();
         }
-        switch (mState) {
-            case STATE_PIP_MENU:
-                bounds = mMenuModePipBound;
-                break;
-            case STATE_NO_PIP:
-                bounds = null;
-                break;
-            default:
-                bounds = mPipBound;
-                break;
-        }
-
         if (mSuspendPipResizingReason != 0) {
             if (DEBUG) Log.d(TAG,
                     "resizePinnedStack() deferring mSuspendPipResizingReason=" +
                             mSuspendPipResizingReason);
             return;
         }
-
+        switch (mState) {
+            case STATE_NO_PIP:
+                mCurrentPipBounds = null;
+                break;
+            case STATE_PIP_MENU:
+                mCurrentPipBounds = mMenuModePipBounds;
+                break;
+            case STATE_PIP_OVERLAY:
+                mCurrentPipBounds = mPipBounds;
+                break;
+            case STATE_PIP_RECENTS:
+                mCurrentPipBounds = mRecentsPipBounds;
+                break;
+            case STATE_PIP_RECENTS_FOCUSED:
+                mCurrentPipBounds = mRecentsFocusedPipBounds;
+                break;
+            default:
+                mCurrentPipBounds = mPipBounds;
+                break;
+        }
         try {
-            mActivityManager.resizeStack(PINNED_STACK_ID, bounds, true, true, true);
+            int animationDurationMs = -1;
+            if (wasRecentsShown
+                    && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+                animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+            }
+            mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
+                    true, true, true, animationDurationMs);
         } catch (RemoteException e) {
-            Log.e(TAG, "showPipMenu failed", e);
+            Log.e(TAG, "resizeStack failed", e);
         }
     }
 
     /**
+     * Returns the default PIP bound.
+     */
+    public Rect getPipBounds() {
+        return mPipBounds;
+    }
+
+    /**
+     * Returns the focused PIP bound while Recents is shown.
+     * This is used to place PIP controls in Recents.
+     */
+    public Rect getRecentsFocusedPipBounds() {
+        return mRecentsFocusedPipBounds;
+    }
+
+    /**
      * Shows PIP menu UI by launching {@link PipMenuActivity}. It also locates the pinned
-     * stack to the centered PIP bound {@link com.android.internal.R.string
-     * .config_centeredPictureInPictureBounds}.
+     * stack to the centered PIP bound {@link R.config_centeredPictureInPictureBounds}.
      */
     private void showPipMenu() {
         if (DEBUG) Log.d(TAG, "showPipMenu()");
+        if (mPipRecentsOverlayManager.isRecentsShown()) {
+            if (DEBUG) Log.d(TAG, "Ignore showing PIP menu");
+            return;
+        }
         mState = STATE_PIP_MENU;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onShowPipMenu();
         }
         Intent intent = new Intent(mContext, PipMenuActivity.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchStackId(PINNED_STACK_ID);
-        mContext.startActivity(intent, options.toBundle());
+        mContext.startActivity(intent);
     }
 
+    /**
+     * Adds a {@link Listener} to PipManager.
+     */
     public void addListener(Listener listener) {
         mListeners.add(listener);
     }
 
+    /**
+     * Removes a {@link Listener} from PipManager.
+     */
     public void removeListener(Listener listener) {
         mListeners.remove(listener);
     }
 
+    /**
+     * Adds a {@link MediaListener} to PipManager.
+     */
+    public void addMediaListener(MediaListener listener) {
+        mMediaListeners.add(listener);
+    }
+
+    /**
+     * Removes a {@link MediaListener} from PipManager.
+     */
+    public void removeMediaListener(MediaListener listener) {
+        mMediaListeners.remove(listener);
+    }
+
     private void launchPipOnboardingActivityIfNeeded() {
         if (DEBUG_FORCE_ONBOARDING || !mOnboardingShown) {
             mOnboardingShown = true;
@@ -337,14 +416,11 @@
         }
     }
 
-    private boolean hasPipTasks() {
-        try {
-            StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
-            return stackInfo != null;
-        } catch (RemoteException e) {
-            Log.e(TAG, "getStackInfo failed", e);
-            return false;
-        }
+    /**
+     * Returns {@code true} if PIP is shown.
+     */
+    public boolean isPipShown() {
+        return mState != STATE_NO_PIP;
     }
 
     private void handleMediaResourceGranted(String[] packageNames) {
@@ -386,49 +462,190 @@
         }
     }
 
-    private class TaskStackListener extends ITaskStackListener.Stub {
+    private void updateMediaController(List<MediaController> controllers) {
+        MediaController mediaController = null;
+        if (controllers != null && mState != STATE_NO_PIP && mPipComponentName != null) {
+            for (int i = controllers.size() - 1; i >= 0; i--) {
+                MediaController controller = controllers.get(i);
+                // We assumes that an app with PIPable activity
+                // keeps the single instance of media controller especially when PIP is on.
+                if (controller.getPackageName().equals(mPipComponentName.getPackageName())) {
+                    mediaController = controller;
+                    break;
+                }
+            }
+        }
+        if (mPipMediaController != mediaController) {
+            mPipMediaController = mediaController;
+            for (int i = mMediaListeners.size() - 1; i >= 0; i--) {
+                mMediaListeners.get(i).onMediaControllerChanged();
+            }
+            if (mPipMediaController == null) {
+                mHandler.postDelayed(mClosePipRunnable,
+                        CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS);
+            } else {
+                mHandler.removeCallbacks(mClosePipRunnable);
+            }
+        }
+    }
+
+    /**
+     * Gets the {@link android.media.session.MediaController} for the PIPed activity.
+     */
+    MediaController getMediaController() {
+        return mPipMediaController;
+    }
+
+    /**
+     * Returns the PIPed activity's playback state.
+     * This returns one of {@link PLAYBACK_STATE_PLAYING}, {@link PLAYBACK_STATE_PAUSED},
+     * or {@link PLAYBACK_STATE_UNAVAILABLE}.
+     */
+    int getPlaybackState() {
+        if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) {
+            return PLAYBACK_STATE_UNAVAILABLE;
+        }
+        int state = mPipMediaController.getPlaybackState().getState();
+        boolean isPlaying = (state == PlaybackState.STATE_BUFFERING
+                || state == PlaybackState.STATE_CONNECTING
+                || state == PlaybackState.STATE_PLAYING
+                || state == PlaybackState.STATE_FAST_FORWARDING
+                || state == PlaybackState.STATE_REWINDING
+                || state == PlaybackState.STATE_SKIPPING_TO_PREVIOUS
+                || state == PlaybackState.STATE_SKIPPING_TO_NEXT);
+        long actions = mPipMediaController.getPlaybackState().getActions();
+        if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) {
+            return PLAYBACK_STATE_PAUSED;
+        } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) {
+            return PLAYBACK_STATE_PLAYING;
+        }
+        return PLAYBACK_STATE_UNAVAILABLE;
+    }
+
+    private TaskStackListener mTaskStackListener = new TaskStackListener() {
         @Override
-        public void onTaskStackChanged() throws RemoteException {
-            // Post the message back to the UI thread.
-            mHandler.post(mOnTaskStackChanged);
+        public void onTaskStackChanged() {
+            if (mState != STATE_NO_PIP) {
+                StackInfo stackInfo = null;
+                try {
+                    stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+                    if (stackInfo == null) {
+                        Log.w(TAG, "There is no pinned stack");
+                        closePipInternal(false);
+                        return;
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "getStackInfo failed", e);
+                    return;
+                }
+                for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) {
+                    if (stackInfo.taskIds[i] == mPipTaskId) {
+                        // PIP task is still alive.
+                        return;
+                    }
+                }
+                // PIP task doesn't exist anymore in PINNED_STACK.
+                closePipInternal(true);
+            }
         }
 
         @Override
-        public void onActivityPinned()  throws RemoteException {
-            // Post the message back to the UI thread.
+        public void onActivityPinned() {
             if (DEBUG) Log.d(TAG, "onActivityPinned()");
-            mHandler.post(mOnActivityPinnedRunnable);
+            StackInfo stackInfo = null;
+            try {
+                stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+                if (stackInfo == null) {
+                    Log.w(TAG, "Cannot find pinned stack");
+                    return;
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "getStackInfo failed", e);
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
+            mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
+            mPipComponentName = ComponentName.unflattenFromString(
+                    stackInfo.taskNames[stackInfo.taskNames.length - 1]);
+            // Set state to overlay so we show it when the pinned stack animation ends.
+            mState = STATE_PIP_OVERLAY;
+            mCurrentPipBounds = mPipBounds;
+            launchPipOnboardingActivityIfNeeded();
+            mMediaSessionManager.addOnActiveSessionsChangedListener(
+                    mActiveMediaSessionListener, null);
+            updateMediaController(mMediaSessionManager.getActiveSessions(null));
+            if (mPipRecentsOverlayManager.isRecentsShown()) {
+                // If an activity becomes PIPed again after the fullscreen, the Recents is shown
+                // behind so we need to resize the pinned stack and show the correct overlay.
+                resizePinnedStack(STATE_PIP_RECENTS);
+            }
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                mListeners.get(i).onPipEntered();
+            }
         }
 
         @Override
         public void onPinnedActivityRestartAttempt() {
-            // Post the message back to the UI thread.
             if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
-            mHandler.post(mOnPinnedActivityRestartAttempt);
+            // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
+            movePipToFullscreen();
         }
 
         @Override
         public void onPinnedStackAnimationEnded() {
             if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
-            mHandler.post(mOnPinnedStackAnimationEnded);
+            switch (mState) {
+                case STATE_PIP_OVERLAY:
+                    if (!mPipRecentsOverlayManager.isRecentsShown()) {
+                        showPipOverlay();
+                        break;
+                    } else {
+                        // This happens only if an activity is PIPed after the Recents is shown.
+                        // See {@link PipRecentsOverlayManager.requestFocus} for more details.
+                        resizePinnedStack(mState);
+                        break;
+                    }
+                case STATE_PIP_RECENTS:
+                case STATE_PIP_RECENTS_FOCUSED:
+                    mPipRecentsOverlayManager.addPipRecentsOverlayView();
+                    break;
+                case STATE_PIP_MENU:
+                    showPipMenu();
+                    break;
+            }
         }
-    }
+    };
 
     /**
      * A listener interface to receive notification on changes in PIP.
      */
     public interface Listener {
+        /**
+         * Invoked when an activity is pinned and PIP manager is set corresponding information.
+         * Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
+         * because there's no guarantee for the PIP manager be return relavent information
+         * correctly. (e.g. {@link isPipShown}).
+         */
+        void onPipEntered();
         /** Invoked when a PIPed activity is closed. */
         void onPipActivityClosed();
         /** Invoked when the PIP menu gets shown. */
         void onShowPipMenu();
-        /** Invoked when the PIPed activity is returned back to the fullscreen. */
+        /** Invoked when the PIPed activity is about to return back to the fullscreen. */
         void onMoveToFullscreen();
         /** Invoked when we are above to start resizing the Pip. */
         void onPipResizeAboutToStart();
     }
 
     /**
+     * A listener interface to receive change in PIP's media controller
+     */
+    public interface MediaListener {
+        /** Invoked when the MediaController on PIPed activity is changed. */
+        void onMediaControllerChanged();
+    }
+
+    /**
      * Gets an instance of {@link PipManager}.
      */
     public static PipManager getInstance() {
@@ -437,4 +654,11 @@
         }
         return sPipManager;
     }
+
+    /**
+     * Gets an instance of {@link PipRecentsOverlayManager}.
+     */
+    public PipRecentsOverlayManager getPipRecentsOverlayManager() {
+        return mPipRecentsOverlayManager;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 7e229d4..854e09d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -17,9 +17,7 @@
 package com.android.systemui.tv.pip;
 
 import android.app.Activity;
-import android.media.session.MediaController;
 import android.os.Bundle;
-import android.view.View;
 
 import com.android.systemui.R;
 
@@ -28,36 +26,34 @@
  */
 public class PipMenuActivity extends Activity implements PipManager.Listener {
     private static final String TAG = "PipMenuActivity";
-    private static final boolean DEBUG = false;
 
     private final PipManager mPipManager = PipManager.getInstance();
-    private MediaController mMediaController;
+
+    private PipControlsView mPipControlsView;
+    private boolean mRestorePipSizeWhenClose;
 
     @Override
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
         setContentView(R.layout.tv_pip_menu);
         mPipManager.addListener(this);
-        findViewById(R.id.full).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mPipManager.movePipToFullscreen();
-            }
-        });
-        findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mPipManager.closePip();
-                finish();
-            }
-        });
-        findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
-                finish();
-            }
-        });
+
+        mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
+        mRestorePipSizeWhenClose = true;
+    }
+
+    private void restorePipAndFinish() {
+        if (mRestorePipSizeWhenClose) {
+            // When PIP menu activity is closed, restore to the default position.
+            mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+        }
+        finish();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        restorePipAndFinish();
     }
 
     @Override
@@ -70,11 +66,13 @@
 
     @Override
     public void onBackPressed() {
-        mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
-        finish();
+        restorePipAndFinish();
     }
 
     @Override
+    public void onPipEntered() { }
+
+    @Override
     public void onPipActivityClosed() {
         finish();
     }
@@ -84,6 +82,9 @@
 
     @Override
     public void onMoveToFullscreen() {
+        // Moving PIP to fullscreen is implemented by resizing PINNED_STACK with null bounds.
+        // This conflicts with restoring PIP position, so disable it.
+        mRestorePipSizeWhenClose = false;
         finish();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index 6f71c92..86ceff4 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -17,9 +17,11 @@
 package com.android.systemui.tv.pip;
 
 import android.app.Activity;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup.LayoutParams;
 
 import com.android.systemui.R;
 
@@ -33,6 +35,8 @@
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
         setContentView(R.layout.tv_pip_onboarding);
+        View pipOnboardingView = findViewById(R.id.pip_onboarding);
+        View pipOutlineView = findViewById(R.id.pip_outline);
         mPipManager.addListener(this);
         findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
             @Override
@@ -40,6 +44,20 @@
                 finish();
             }
         });
+
+        int pipOutlineSpace = getResources().getDimensionPixelSize(R.dimen.tv_pip_bounds_space);
+        int screenWidth = getResources().getDisplayMetrics().widthPixels;
+        Rect pipBounds = mPipManager.getPipBounds();
+        pipOnboardingView.setPadding(
+                pipBounds.left - pipOutlineSpace,
+                pipBounds.top - pipOutlineSpace,
+                screenWidth - pipBounds.right - pipOutlineSpace, 0);
+
+        // Set width and height for outline view to enclose the PIP.
+        LayoutParams lp = pipOutlineView.getLayoutParams();
+        lp.width = pipBounds.width() + pipOutlineSpace * 2;
+        lp.height = pipBounds.height() + pipOutlineSpace * 2;
+        pipOutlineView.setLayoutParams(lp);
     }
 
     @Override
@@ -49,6 +67,9 @@
     }
 
     @Override
+    public void onPipEntered() { }
+
+    @Override
     public void onPipActivityClosed() {
         finish();
     }
@@ -64,6 +85,5 @@
     }
 
     @Override
-    public void onPipResizeAboutToStart() {
-    }
+    public void onPipResizeAboutToStart() { }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 56a604d..e205ff5 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -17,34 +17,60 @@
 package com.android.systemui.tv.pip;
 
 import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
-
 import android.view.View;
+import android.widget.ImageView;
+
 import com.android.systemui.R;
 
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+
 /**
  * Activity to show an overlay on top of PIP activity to show how to pop up PIP menu.
  */
 public class PipOverlayActivity extends Activity implements PipManager.Listener {
-    private static final String TAG = "PipOverlayActivity";
-    private static final boolean DEBUG = false;
-
     private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000;
 
+    /**
+     * A flag to ensure the single instance of PipOverlayActivity to prevent it from restarting.
+     * Note that {@link PipManager} moves the PIPed activity to fullscreen if the activity is
+     * restarted. It's because the activity may be started by the Launcher or an intent again,
+     * but we don't want do so for the PipOverlayActivity.
+     */
+    private static boolean sActivityCreated;
+
     private final PipManager mPipManager = PipManager.getInstance();
     private final Handler mHandler = new Handler();
     private View mGuideOverlayView;
+    private View mGuideButtonsView;
+    private ImageView mGuideButtonPlayPauseImageView;
     private final Runnable mHideGuideOverlayRunnable = new Runnable() {
         public void run() {
-            // TODO: Uncomment this after the b/27224884 is fixed.
-            //mGuideOverlayView.setVisibility(View.INVISIBLE);
+            mGuideOverlayView.setVisibility(View.GONE);
         }
     };
 
+    /**
+     * Shows PIP overlay UI only if it's not there.
+     */
+    static void showPipOverlay(Context context) {
+        if (!sActivityCreated) {
+            Intent intent = new Intent(context, PipOverlayActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            final ActivityOptions options = ActivityOptions.makeBasic();
+            options.setLaunchStackId(PINNED_STACK_ID);
+            context.startActivity(intent, options.toBundle());
+        }
+    }
+
     @Override
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
+        sActivityCreated = true;
         setContentView(R.layout.tv_pip_overlay);
         mGuideOverlayView = findViewById(R.id.guide_overlay);
         mPipManager.addListener(this);
@@ -53,7 +79,6 @@
     @Override
     protected void onResume() {
         super.onResume();
-        mGuideOverlayView.setVisibility(View.VISIBLE);
         mHandler.removeCallbacks(mHideGuideOverlayRunnable);
         mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
     }
@@ -68,6 +93,7 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
+        sActivityCreated = false;
         mHandler.removeCallbacksAndMessages(null);
         mPipManager.removeListener(this);
         mPipManager.resumePipResizing(
@@ -75,6 +101,9 @@
     }
 
     @Override
+    public void onPipEntered() { }
+
+    @Override
     public void onPipActivityClosed() {
         finish();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
new file mode 100644
index 0000000..8b8c105
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tv.pip;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PLAYING;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PAUSED;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_UNAVAILABLE;
+
+/**
+ * An extended version of {@link PipControlsView} that supports animation in Recents.
+ */
+public class PipRecentsControlsView extends PipControlsView {
+    /**
+     * An interface to listen user action.
+     */
+    public interface Listener extends PipControlsView.Listener {
+        /**
+         * Called when an user presses BACK key and up.
+         */
+        abstract void onBackPressed();
+    }
+
+    private AnimatorSet mFocusGainAnimatorSet;
+    private AnimatorSet mFocusLoseAnimatorSet;
+
+    public PipRecentsControlsView(Context context) {
+        this(context, null, 0, 0);
+    }
+
+    public PipRecentsControlsView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0, 0);
+    }
+
+    public PipRecentsControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public PipRecentsControlsView(
+            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+
+        int buttonsFocusGainAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_gain_animation;
+        int textFocusGainAnim = R.anim.tv_pip_controls_text_in_recents_focus_gain_animation;
+        mFocusGainAnimatorSet = new AnimatorSet();
+        mFocusGainAnimatorSet.playTogether(
+                loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_gain_animation),
+                loadAnimator(mFullButtonView,buttonsFocusGainAnim),
+                loadAnimator(mPlayPauseButtonImageView, buttonsFocusGainAnim),
+                loadAnimator(mCloseButtonView, buttonsFocusGainAnim),
+                loadAnimator(mFullDescriptionView, textFocusGainAnim),
+                loadAnimator(mPlayPauseDescriptionTextView, textFocusGainAnim),
+                loadAnimator(mCloseDescriptionView, textFocusGainAnim));
+
+        int buttonsFocusLoseAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_lose_animation;
+        int textFocusLoseAnim = R.anim.tv_pip_controls_text_in_recents_focus_lose_animation;
+        mFocusLoseAnimatorSet = new AnimatorSet();
+        mFocusLoseAnimatorSet.playTogether(
+                loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_lose_animation),
+                loadAnimator(mFullButtonView, buttonsFocusLoseAnim),
+                loadAnimator(mPlayPauseButtonImageView, buttonsFocusLoseAnim),
+                loadAnimator(mCloseButtonView, buttonsFocusLoseAnim),
+                loadAnimator(mFullDescriptionView, textFocusLoseAnim),
+                loadAnimator(mPlayPauseDescriptionTextView, textFocusLoseAnim),
+                loadAnimator(mCloseDescriptionView, textFocusLoseAnim));
+
+        Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
+        int pipControlsMarginTop = getContext().getResources().getDimensionPixelSize(
+                R.dimen.recents_tv_pip_controls_margin_top);
+        setPadding(0, pipBounds.bottom + pipControlsMarginTop, 0, 0);
+    }
+
+    private Animator loadAnimator(View view, int animatorResId) {
+        Animator animator = AnimatorInflater.loadAnimator(getContext(), animatorResId);
+        animator.setTarget(view);
+        return animator;
+    }
+
+    /**
+     * Starts focus gaining animation.
+     */
+    public void startFocusGainAnimation() {
+        if (mFocusLoseAnimatorSet.isStarted()) {
+            mFocusLoseAnimatorSet.cancel();
+        }
+        mFocusGainAnimatorSet.start();
+    }
+
+    /**
+     * Starts focus losing animation.
+     */
+    public void startFocusLoseAnimation() {
+        if (mFocusGainAnimatorSet.isStarted()) {
+            mFocusGainAnimatorSet.cancel();
+        }
+        mFocusLoseAnimatorSet.start();
+    }
+
+    /**
+     * Resets the view to the initial state. (i.e. end of the focus gain)
+     */
+    public void reset() {
+        if (mFocusGainAnimatorSet.isStarted()) {
+            mFocusGainAnimatorSet.cancel();
+        }
+        if (mFocusLoseAnimatorSet.isStarted()) {
+            mFocusLoseAnimatorSet.cancel();
+        }
+
+        // Reset to initial state (i.e. end of focused)
+        requestFocus();
+        setTranslationY(0);
+        setScaleXY(mFullButtonView, 1);
+        setScaleXY(mPlayPauseButtonImageView, 1);
+        setScaleXY(mCloseButtonView, 1);
+        mFullDescriptionView.setAlpha(1);
+        mPlayPauseDescriptionTextView.setAlpha(1);
+        mCloseDescriptionView.setAlpha(1);
+    }
+
+    private void setScaleXY(View view, float scale) {
+        view.setScaleX(scale);
+        view.setScaleY(scale);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (!event.isCanceled()
+                && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+                && event.getAction() == KeyEvent.ACTION_UP) {
+            if (mListener != null) {
+                ((PipRecentsControlsView.Listener) mListener).onBackPressed();
+            }
+            return true;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
new file mode 100644
index 0000000..47cd8e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tv.pip;
+
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_OVERLAY;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS_FOCUSED;
+
+public class PipRecentsOverlayManager {
+    private static final String TAG = "PipRecentsOverlayManager";
+
+    public interface Callback {
+        void onClosed();
+        void onBackPressed();
+        void onRecentsFocused();
+    }
+
+    private final PipManager mPipManager = PipManager.getInstance();
+    private final WindowManager mWindowManager;
+    private final View mOverlayView;
+    private final PipRecentsControlsView mPipControlsView;
+    private final View mRecentsView;
+
+    private final LayoutParams mPipRecentsControlsViewLayoutParams;
+    private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
+
+    private boolean mIsPipRecentsOverlayShown;
+    private boolean mIsRecentsShown;
+    private boolean mIsPipFocusedInRecent;
+    private Callback mCallback;
+    private PipRecentsControlsView.Listener mPipControlsViewListener =
+            new PipRecentsControlsView.Listener() {
+                @Override
+                public void onClosed() {
+                    if (mCallback != null) {
+                        mCallback.onClosed();
+                    }
+                }
+
+                @Override
+                public void onBackPressed() {
+                    if (mCallback != null) {
+                        mCallback.onBackPressed();
+                    }
+                }
+            };
+
+    PipRecentsOverlayManager(Context context) {
+        mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
+
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mOverlayView = inflater.inflate(R.layout.tv_pip_recents_overlay, null);
+        mPipControlsView = (PipRecentsControlsView) mOverlayView.findViewById(R.id.pip_controls);
+        mRecentsView = mOverlayView.findViewById(R.id.recents);
+        mRecentsView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (hasFocus) {
+                    clearFocus();
+                }
+            }
+        });
+
+        mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                LayoutParams.TYPE_SYSTEM_DIALOG,
+                LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
+                PixelFormat.TRANSLUCENT);
+        mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                LayoutParams.TYPE_SYSTEM_DIALOG,
+                0,
+                PixelFormat.TRANSLUCENT);
+    }
+
+    /**
+     * Add Recents overlay view.
+     * This is expected to be called after the PIP animation is over.
+     */
+    void addPipRecentsOverlayView() {
+        if (mIsPipRecentsOverlayShown) {
+            return;
+        }
+        mIsPipRecentsOverlayShown = true;
+        mIsPipFocusedInRecent = true;
+        mPipControlsView.reset();
+        mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+    }
+
+    /**
+     * Remove Recents overlay view.
+     * This should be called when Recents or PIP is closed.
+     */
+    public void removePipRecentsOverlayView() {
+        if (!mIsPipRecentsOverlayShown) {
+            return;
+        }
+        mWindowManager.removeView(mOverlayView);
+        mIsPipRecentsOverlayShown = false;
+    }
+
+    /**
+     * Request focus to the PIP Recents overlay.
+     * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+     * is focused.
+     * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+     * @param allowRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
+     */
+    public void requestFocus(boolean allowRecentsFocusable) {
+        if (!mIsRecentsShown || mIsPipFocusedInRecent) {
+            return;
+        }
+        mIsPipFocusedInRecent = true;
+        mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+
+        mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+        mPipControlsView.requestFocus();
+        mPipControlsView.startFocusGainAnimation();
+        mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Request focus to the PIP Recents overlay.
+     * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+     * is focused.
+     * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+     */
+    private void clearFocus() {
+        if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
+            return;
+        }
+        mIsPipFocusedInRecent = false;
+        mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
+        mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
+        mPipControlsView.startFocusLoseAnimation();
+        if (mCallback != null) {
+            mCallback.onRecentsFocused();
+        }
+    }
+
+    public void setCallback(Callback listener) {
+        mCallback = listener;
+        mPipControlsView.setListener(mCallback != null ? mPipControlsViewListener : null);
+    }
+
+    /**
+     * Called when Recents is resumed.
+     * PIPed activity will be resized accordingly and overlay will show available buttons.
+     */
+    public void onRecentsResumed() {
+        if (!mPipManager.isPipShown()) {
+            return;
+        }
+        mIsRecentsShown = true;
+        mIsPipFocusedInRecent = true;
+        mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+        // Overlay view will be added after the resize animation ends, if any.
+    }
+
+    /**
+     * Called when Recents is paused.
+     * PIPed activity will be resized accordingly and overlay will hide available buttons.
+     */
+    public void onRecentsPaused() {
+        mIsRecentsShown = false;
+        mIsPipFocusedInRecent = false;
+        removePipRecentsOverlayView();
+
+        if (mPipManager.isPipShown()) {
+            mPipManager.resizePinnedStack(STATE_PIP_OVERLAY);
+        }
+    }
+
+    /**
+     * Returns {@code true} if recents is shown.
+     */
+    boolean isRecentsShown() {
+        return mIsRecentsShown;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index f432808..c6e4356 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -35,11 +35,11 @@
     private static final Typeface MEDIUM = Typeface.create("sans-serif-medium", Typeface.NORMAL);
 
     private final Context mContext;
-    private final LayoutInflater mInflater;
+    protected final LayoutInflater mInflater;
     private final SpTexts mSpTexts;
 
     private Callback mCallback;
-    private Object mSelectedValue;
+    protected Object mSelectedValue;
 
     public SegmentedButtons(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -65,13 +65,21 @@
             final Object tag = c.getTag();
             final boolean selected = Objects.equals(mSelectedValue, tag);
             c.setSelected(selected);
-            c.setTypeface(selected ? MEDIUM : REGULAR);
+            setSelectedStyle(c, selected);
         }
         fireOnSelected(fromClick);
     }
 
+    protected void setSelectedStyle(TextView textView, boolean selected) {
+        textView.setTypeface(selected ? MEDIUM : REGULAR);
+    }
+
+    public Button inflateButton() {
+        return (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+    }
+
     public void addButton(int labelResId, int contentDescriptionResId, Object value) {
-        final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+        final Button b = inflateButton();
         b.setTag(LABEL_RES_KEY, labelResId);
         b.setText(labelResId);
         b.setContentDescription(getResources().getString(contentDescriptionResId));
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 1810c1c..1d5ca04 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
@@ -42,6 +43,7 @@
 import android.provider.Settings.Global;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -49,7 +51,6 @@
 import android.view.View.AccessibilityDelegate;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnClickListener;
-import android.view.View.OnLayoutChangeListener;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
@@ -91,39 +92,40 @@
     public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
 
     private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
-    private static final int WAIT_FOR_RIPPLE = 200;
 
     private final Context mContext;
     private final H mHandler = new H();
     private final VolumeDialogController mController;
 
-    private final CustomDialog mDialog;
-    private final ViewGroup mDialogView;
-    private final ViewGroup mDialogContentView;
-    private final ImageButton mExpandButton;
-    private final View mSettingsButton;
-    private final List<VolumeRow> mRows = new ArrayList<VolumeRow>();
+    private CustomDialog mDialog;
+    private ViewGroup mDialogView;
+    private ViewGroup mDialogContentView;
+    private ViewGroup mVolumeRowContainer;
+    private ImageButton mExpandButton;
+    private final List<VolumeRow> mRows = new ArrayList<>();
     private final SpTexts mSpTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
     private final KeyguardManager mKeyguard;
     private final AudioManager mAudioManager;
-    private final int mExpandButtonAnimationDuration;
-    private final ZenFooter mZenFooter;
+    private int mExpandButtonAnimationDuration;
+    private ZenFooter mZenFooter;
     private final LayoutTransition mLayoutTransition;
     private final Object mSafetyWarningLock = new Object();
     private final Accessibility mAccessibility = new Accessibility();
     private final ColorStateList mActiveSliderTint;
     private final ColorStateList mInactiveSliderTint;
-    private final VolumeDialogMotion mMotion;
+    private VolumeDialogMotion mMotion;
+    private final int mWindowType;
+    private final ZenModeController mZenModeController;
 
     private boolean mShowing;
     private boolean mExpanded;
+
     private int mActiveStream;
     private boolean mShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
     private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
     private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
     private State mState;
-    private int mExpandButtonRes;
     private boolean mExpandButtonAnimationRunning;
     private SafetyWarningDialog mSafetyWarning;
     private Callback mCallback;
@@ -131,22 +133,43 @@
     private boolean mPendingRecheckAll;
     private long mCollapseTime;
     private boolean mHovering = false;
-    private int mLastActiveStream;
+    private int mDensity;
 
     private boolean mShowFullZen;
-    private final TunerZenModePanel mZenPanel;
+    private TunerZenModePanel mZenPanel;
 
     public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
             ZenModeController zenModeController, Callback callback) {
         mContext = context;
         mController = controller;
         mCallback = callback;
+        mWindowType = windowType;
+        mZenModeController = zenModeController;
         mSpTexts = new SpTexts(mContext);
         mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
+        mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+        mLayoutTransition = new LayoutTransition();
+        mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
 
+        initDialog();
+
+        mAccessibility.init();
+
+        controller.addCallback(mControllerCallbackH, mHandler);
+        controller.getState();
+        TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
+
+        final Configuration currentConfig = mContext.getResources().getConfiguration();
+        mDensity = currentConfig.densityDpi;
+    }
+
+    private void initDialog() {
         mDialog = new CustomDialog(mContext);
 
+        mHovering = false;
+        mShowing = false;
         final Window window = mDialog.getWindow();
         window.requestFeature(Window.FEATURE_NO_TITLE);
         window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
@@ -160,7 +183,7 @@
         mDialog.setCanceledOnTouchOutside(true);
         final Resources res = mContext.getResources();
         final WindowManager.LayoutParams lp = window.getAttributes();
-        lp.type = windowType;
+        lp.type = mWindowType;
         lp.format = PixelFormat.TRANSLUCENT;
         lp.setTitle(VolumeDialog.class.getSimpleName());
         lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
@@ -170,8 +193,7 @@
         window.setAttributes(lp);
         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
 
-        mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
-        mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+
         mDialog.setContentView(R.layout.volume_dialog);
         mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
         mDialogView.setOnHoverListener(new View.OnHoverListener() {
@@ -185,56 +207,53 @@
             }
         });
         mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
+        mVolumeRowContainer =
+                (ViewGroup) mDialogContentView.findViewById(R.id.volume_row_container);
+        mExpanded = false;
         mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
         mExpandButton.setOnClickListener(mClickExpand);
         updateWindowWidthH();
         updateExpandButtonH();
-        mLayoutTransition = new LayoutTransition();
-        mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
+
         mDialogContentView.setLayoutTransition(mLayoutTransition);
         mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton,
                 new VolumeDialogMotion.Callback() {
-            @Override
-            public void onAnimatingChanged(boolean animating) {
-                if (animating) return;
-                if (mPendingStateChanged) {
-                    mHandler.sendEmptyMessage(H.STATE_CHANGED);
-                    mPendingStateChanged = false;
-                }
-                if (mPendingRecheckAll) {
-                    mHandler.sendEmptyMessage(H.RECHECK_ALL);
-                    mPendingRecheckAll = false;
-                }
-            }
-        });
+                    @Override
+                    public void onAnimatingChanged(boolean animating) {
+                        if (animating) return;
+                        if (mPendingStateChanged) {
+                            mHandler.sendEmptyMessage(H.STATE_CHANGED);
+                            mPendingStateChanged = false;
+                        }
+                        if (mPendingRecheckAll) {
+                            mHandler.sendEmptyMessage(H.RECHECK_ALL);
+                            mPendingRecheckAll = false;
+                        }
+                    }
+                });
 
-        addRow(AudioManager.STREAM_RING,
-                R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
-        addRow(AudioManager.STREAM_MUSIC,
-                R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
-        addRow(AudioManager.STREAM_ALARM,
-                R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
-        addRow(AudioManager.STREAM_VOICE_CALL,
-                R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
-        addRow(AudioManager.STREAM_BLUETOOTH_SCO,
-                R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
-        addRow(AudioManager.STREAM_SYSTEM,
-                R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
-
-        mSettingsButton = mDialog.findViewById(R.id.volume_settings_button);
-        mSettingsButton.setOnClickListener(mClickSettings);
+        if (mRows.isEmpty()) {
+            addRow(AudioManager.STREAM_RING,
+                    R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
+            addRow(AudioManager.STREAM_MUSIC,
+                    R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
+            addRow(AudioManager.STREAM_ALARM,
+                    R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
+            addRow(AudioManager.STREAM_VOICE_CALL,
+                    R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
+            addRow(AudioManager.STREAM_BLUETOOTH_SCO,
+                    R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
+            addRow(AudioManager.STREAM_SYSTEM,
+                    R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
+        } else {
+            addExistingRows();
+        }
         mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
         mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
-        mZenFooter.init(zenModeController);
+        mZenFooter.init(mZenModeController);
         mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
-        mZenPanel.init(zenModeController);
+        mZenPanel.init(mZenModeController);
         mZenPanel.setCallback(mZenPanelCallback);
-
-        mAccessibility.init();
-
-        controller.addCallback(mControllerCallbackH, mHandler);
-        controller.getState();
-        TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
     }
 
     @Override
@@ -285,46 +304,38 @@
     }
 
     private void addRow(int stream, int iconRes, int iconMuteRes, boolean important) {
-        final VolumeRow row = initRow(stream, iconRes, iconMuteRes, important);
+        VolumeRow row = new VolumeRow();
+        initRow(row, stream, iconRes, iconMuteRes, important);
         if (!mRows.isEmpty()) {
-            final View v = new View(mContext);
-            v.setId(android.R.id.background);
-            final int h = mContext.getResources()
-                    .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
-            final LinearLayout.LayoutParams lp =
-                    new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
-            mDialogContentView.addView(v, mDialogContentView.getChildCount() - 2, lp);
-            row.space = v;
+            addSpacer(row);
         }
-        row.settingsButton.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) {
-                final boolean moved = mLastActiveStream != mActiveStream ||
-                        oldLeft != left || oldTop != top;
-                if (D.BUG) Log.d(TAG, "onLayoutChange moved=" + moved
-                        + " old=" + new Rect(oldLeft, oldTop, oldRight, oldBottom).toShortString()
-                        + "," + mLastActiveStream
-                        + " new=" + new Rect(left,top,right,bottom).toShortString()
-                        + "," + mActiveStream);
-                mLastActiveStream = mActiveStream;
-                if (moved) {
-                    for (int i = 0; i < mDialogContentView.getChildCount(); i++) {
-                        final View c = mDialogContentView.getChildAt(i);
-                        if (!c.isShown()) continue;
-                        if (c == row.view) {
-                            repositionExpandAnim(row);
-                        }
-                        return;
-                    }
-                }
-            }
-        });
-        // add new row just before the footer
-        mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
+        mVolumeRowContainer.addView(row.view);
         mRows.add(row);
     }
 
+    private void addExistingRows() {
+        int N = mRows.size();
+        for (int i = 0; i < N; i++) {
+            final VolumeRow row = mRows.get(i);
+            initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important);
+            if (i > 0) {
+                addSpacer(row);
+            }
+            mVolumeRowContainer.addView(row.view);
+        }
+    }
+
+    private void addSpacer(VolumeRow row) {
+        final View v = new View(mContext);
+        v.setId(android.R.id.background);
+        final int h = mContext.getResources()
+                .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
+        final LinearLayout.LayoutParams lp =
+                new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
+        mVolumeRowContainer.addView(v, lp);
+        row.space = v;
+    }
+
     private boolean isAttached() {
         return mDialogContentView != null && mDialogContentView.isAttachedToWindow();
     }
@@ -345,18 +356,6 @@
         return null;
     }
 
-    private void repositionExpandAnim(VolumeRow row) {
-        final int[] loc = new int[2];
-        row.settingsButton.getLocationInWindow(loc);
-        final MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams();
-        final int x = loc[0] - mlp.leftMargin;
-        final int y = loc[1] - mlp.topMargin;
-        if (D.BUG) Log.d(TAG, "repositionExpandAnim x=" + x + " y=" + y);
-        mExpandButton.setTranslationX(x);
-        mExpandButton.setTranslationY(y);
-        mExpandButton.setTag((Integer) y);
-    }
-
     public void dump(PrintWriter writer) {
         writer.println(VolumeDialog.class.getSimpleName() + " state:");
         writer.print("  mShowing: "); writer.println(mShowing);
@@ -374,8 +373,8 @@
     }
 
     @SuppressLint("InflateParams")
-    private VolumeRow initRow(final int stream, int iconRes, int iconMuteRes, boolean important) {
-        final VolumeRow row = new VolumeRow();
+    private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
+            boolean important) {
         row.stream = stream;
         row.iconRes = iconRes;
         row.iconMuteRes = iconMuteRes;
@@ -442,9 +441,6 @@
                 row.userAttempt = 0;  // reset the grace period, slider should update immediately
             }
         });
-        row.settingsButton = (ImageButton) row.view.findViewById(R.id.volume_settings_button);
-        row.settingsButton.setOnClickListener(mClickSettings);
-        return row;
     }
 
     public void destroy() {
@@ -573,8 +569,6 @@
         if (mExpandButtonAnimationRunning && isAttached()) return;
         final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
                 : R.drawable.ic_volume_expand_animation;
-        if (res == mExpandButtonRes) return;
-        mExpandButtonRes = res;
         if (hasTouchFeature()) {
             mExpandButton.setImageResource(res);
         } else {
@@ -606,16 +600,6 @@
             final boolean visible = isVisibleH(row, isActive);
             Util.setVisOrGone(row.view, visible);
             Util.setVisOrGone(row.space, visible && mExpanded);
-            final int expandButtonRes = mExpanded ? R.drawable.ic_volume_settings : 0;
-            if (expandButtonRes != row.cachedExpandButtonRes) {
-                row.cachedExpandButtonRes = expandButtonRes;
-                if (expandButtonRes == 0) {
-                    row.settingsButton.setImageDrawable(null);
-                } else {
-                    row.settingsButton.setImageResource(expandButtonRes);
-                }
-            }
-            Util.setVisOrInvis(row.settingsButton, false);
             updateVolumeRowHeaderVisibleH(row);
             row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f);
             updateVolumeRowSliderTintH(row, isActive);
@@ -629,8 +613,8 @@
             if (row.ss == null || !row.ss.dynamic) continue;
             if (!mDynamic.get(row.stream)) {
                 mRows.remove(i);
-                mDialogContentView.removeView(row.view);
-                mDialogContentView.removeView(row.space);
+                mVolumeRowContainer.removeView(row.view);
+                mVolumeRowContainer.removeView(row.space);
             }
         }
     }
@@ -911,6 +895,12 @@
 
         @Override
         public void onConfigurationChanged() {
+            Configuration newConfig = mContext.getResources().getConfiguration();
+            final int density = newConfig.densityDpi;
+            if (density != mDensity) {
+                mDialog.dismiss();
+                initDialog();
+            }
             updateWindowWidthH();
             mSpTexts.update();
             mZenFooter.onConfigurationChanged();
@@ -963,21 +953,6 @@
         }
     };
 
-    private final OnClickListener mClickSettings = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            mSettingsButton.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    Events.writeEvent(mContext, Events.EVENT_SETTINGS_CLICK);
-                    if (mCallback != null) {
-                        mCallback.onSettingsClicked();
-                    }
-                }
-            }, WAIT_FOR_RIPPLE);
-        }
-    };
-
     private final class H extends Handler {
         private static final int SHOW = 1;
         private static final int DISMISS = 2;
@@ -1155,7 +1130,6 @@
         private TextView header;
         private ImageButton icon;
         private SeekBar slider;
-        private ImageButton settingsButton;
         private int stream;
         private StreamState ss;
         private long userAttempt;  // last user-driven slider change
@@ -1168,12 +1142,10 @@
         private ColorStateList cachedSliderTint;
         private int iconState;  // from Events
         private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
-        private int cachedExpandButtonRes;
         private int lastAudibleLevel = 1;
     }
 
     public interface Callback {
-        void onSettingsClicked();
         void onZenSettingsClicked();
         void onZenPrioritySettingsClicked();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index d7635ad..3d33809 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -168,11 +168,6 @@
 
     private final VolumeDialog.Callback mVolumeDialogCallback = new VolumeDialog.Callback() {
         @Override
-        public void onSettingsClicked() {
-            startSettings(new Intent(Settings.ACTION_NOTIFICATION_SETTINGS));
-        }
-
-        @Override
         public void onZenSettingsClicked() {
             startSettings(ZenModePanel.ZEN_SETTINGS);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
index 04339eb..bbb70ed 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
@@ -43,7 +43,7 @@
     public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms";
     public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
 
-    public static final boolean DEFAULT_SHOW_HEADERS = true;
+    public static final boolean DEFAULT_SHOW_HEADERS = false;
     public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
     public static final boolean DEFAULT_ENABLE_SILENT_MODE = true;
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index a03e7f7..005767f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -131,7 +131,7 @@
 
         final boolean isForever = mConfig != null && mConfig.manualRule != null
                 && mConfig.manualRule.conditionId == null;
-        final String line2 =
+        final CharSequence line2 =
                 isForever ? mContext.getString(com.android.internal.R.string.zen_mode_forever_dnd)
                 : ZenModeConfig.getConditionSummary(mContext, mConfig, mController.getCurrentUser(),
                         true /*shortVersion*/);
@@ -139,9 +139,8 @@
     }
 
     public void onConfigurationChanged() {
-        mEndNowButton.setText(mContext.getString(R.string.volume_zen_end_now));
-        mSpTexts.update();
         Util.setText(mEndNowButton, mContext.getString(R.string.volume_zen_end_now));
+        mSpTexts.update();
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 6976c0b..e3ed92c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -86,7 +86,7 @@
             = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
 
     private final Context mContext;
-    private final LayoutInflater mInflater;
+    protected final LayoutInflater mInflater;
     private final H mHandler = new H();
     private final ZenPrefs mPrefs;
     private final TransitionHelper mTransitionHelper = new TransitionHelper();
@@ -95,12 +95,12 @@
 
     private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
 
-    private SegmentedButtons mZenButtons;
+    protected SegmentedButtons mZenButtons;
     private View mZenIntroduction;
     private TextView mZenIntroductionMessage;
     private View mZenIntroductionConfirm;
     private TextView mZenIntroductionCustomize;
-    private LinearLayout mZenConditions;
+    protected LinearLayout mZenConditions;
     private TextView mZenAlarmWarning;
 
     private Callback mCallback;
@@ -148,10 +148,7 @@
         mTransitionHelper.dump(fd, pw, args);
     }
 
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
+    protected void createZenButtons() {
         mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
         mZenButtons.addButton(R.string.interruption_level_none_twoline,
                 R.string.interruption_level_none_with_warning,
@@ -163,7 +160,12 @@
                 R.string.interruption_level_priority,
                 Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
         mZenButtons.setCallback(mZenButtonsCallback);
+    }
 
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        createZenButtons();
         mZenIntroduction = findViewById(R.id.zen_introduction);
         mZenIntroductionMessage = (TextView) findViewById(R.id.zen_introduction_message);
         mSpTexts.add(mZenIntroductionMessage);
@@ -302,14 +304,18 @@
         }
     }
 
+    protected void addZenConditions(int count) {
+        for (int i = 0; i < count; i++) {
+            mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
+        }
+    }
+
     public void init(ZenModeController controller) {
         mController = controller;
         mCountdownConditionSupported = mController.isCountdownConditionSupported();
         final int countdownDelta = mCountdownConditionSupported ? COUNTDOWN_CONDITION_COUNT : 0;
         final int minConditions = 1 /*forever*/ + countdownDelta;
-        for (int i = 0; i < minConditions; i++) {
-            mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
-        }
+        addZenConditions(minConditions);
         mSessionZen = getSelectedZen(-1);
         handleUpdateManualRule(mController.getManualRule());
         if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
@@ -917,7 +923,7 @@
         }
     }
 
-    private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
+    protected final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
         @Override
         public void onSelected(final Object value, boolean fromClick) {
             if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 964688b..c9c5805 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -29,9 +29,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-Iaidl-files-under, src) \
-    $(call all-java-files-under, ../src) \
-    $(call all-proto-files-under, ../src) \
-    src/com/android/systemui/EventLogTags.logtags
+    $(call all-java-files-under, ../src)
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
     frameworks/support/v7/preference/res \
@@ -53,7 +51,8 @@
     android-support-v7-preference \
     android-support-v7-appcompat \
     android-support-v14-preference \
-    android-support-v17-leanback
+    android-support-v17-leanback \
+    SystemUI-proto-tags
 
 # sign this with platform cert, so this test is allowed to inject key events into
 # UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 2825601..53a9976 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -20,7 +20,11 @@
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags
deleted file mode 120000
index 2f243d7..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/com/android/systemui/EventLogTags.logtags
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
new file mode 100644
index 0000000..e9b85b9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import org.mockito.Mockito;
+
+@SmallTest
+public class TouchAnimatorTests extends SysuiTestCase {
+
+    private Listener mTouchListener;
+    private View mTestView;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mTestView = new View(getContext());
+        mTouchListener = Mockito.mock(Listener.class);
+    }
+
+    public void testSetValueFloat() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addFloat(mTestView, "x", 0, 50)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.5f);
+        assertEquals(25f, mTestView.getX());
+
+        animator.setPosition(1);
+        assertEquals(50f, mTestView.getX());
+    }
+
+    public void testSetValueInt() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addInt(mTestView, "top", 0, 50)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0, mTestView.getTop());
+
+        animator.setPosition(.5f);
+        assertEquals(25, mTestView.getTop());
+
+        animator.setPosition(1);
+        assertEquals(50, mTestView.getTop());
+    }
+
+    public void testStartDelay() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addFloat(mTestView, "x", 0, 50)
+                .setStartDelay(.5f)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.5f);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.75f);
+        assertEquals(25f, mTestView.getX());
+
+        animator.setPosition(1);
+        assertEquals(50f, mTestView.getX());
+    }
+
+    public void testEndDelay() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addFloat(mTestView, "x", 0, 50)
+                .setEndDelay(.5f)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.25f);
+        assertEquals(25f, mTestView.getX());
+
+        animator.setPosition(.5f);
+        assertEquals(50f, mTestView.getX());
+
+        animator.setPosition(1);
+        assertEquals(50f, mTestView.getX());
+    }
+
+    public void testOnAnimationAtStartCallback() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .setListener(mTouchListener)
+                .build();
+
+        // Called on init.
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(1);
+
+        // Not called from same state.
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(1);
+
+        // Called after starting and moving back to start.
+        animator.setPosition(.5f);
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(2);
+
+        // Called when move from end to end.
+        animator.setPosition(1);
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(3);
+    }
+
+    public void testOnAnimationAtEndCallback() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .setListener(mTouchListener)
+                .build();
+
+        // Called on init.
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(1);
+
+        // Not called from same state.
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(1);
+
+        // Called after starting and moving back to end.
+        animator.setPosition(.5f);
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(2);
+
+        // Called when move from end to end.
+        animator.setPosition(0);
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(3);
+    }
+
+    public void testOnAnimationStartedCallback() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .setListener(mTouchListener)
+                .build();
+
+        // Called on init.
+        animator.setPosition(.5f);
+        verifyOnAnimationStarted(1);
+
+        // Not called from same state.
+        animator.setPosition(.6f);
+        verifyOnAnimationStarted(1);
+
+        // Called after going to end then moving again.
+        animator.setPosition(1);
+        animator.setPosition(.5f);
+        verifyOnAnimationStarted(2);
+
+        // Called after moving to start then moving again.
+        animator.setPosition(0);
+        animator.setPosition(.5f);
+        verifyOnAnimationStarted(3);
+    }
+
+    // TODO: Add test for interpolator.
+
+    private void verifyOnAnimationAtStart(int times) {
+        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtStart();
+    }
+
+    private void verifyOnAnimationAtEnd(int times) {
+        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtEnd();
+    }
+
+    private void verifyOnAnimationStarted(int times) {
+        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationStarted();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
index f86c6a4..a30f507 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -32,9 +32,11 @@
 import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.Tile;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 import android.util.Log;
 
+@SmallTest
 public class TileLifecycleManagerTests extends AndroidTestCase {
     public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
     public static final String EXTRA_CALLBACK = "callback";
@@ -196,7 +198,7 @@
     }
 
     private void waitForCallback(String callback) {
-        for (int i = 0; i < 25; i++) {
+        for (int i = 0; i < 50; i++) {
             if (mCallbacks.contains(callback)) {
                 mCallbacks.remove(callback);
                 return;
@@ -227,7 +229,7 @@
                 }
             });
             try {
-                lock.wait(5000);
+                lock.wait(10000);
             } catch (InterruptedException e) {
             }
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
index efdb50d..f24b541 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
@@ -19,10 +19,12 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.service.quicksettings.TileService;
+import android.test.suitebuilder.annotation.SmallTest;
 import com.android.systemui.SysuiTestCase;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
+@SmallTest
 public class TileServiceManagerTests extends SysuiTestCase {
 
     private TileServices mTileServices;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
index c4ca039..94c98d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -17,13 +17,18 @@
 
 import android.content.ComponentName;
 import android.os.Looper;
+import android.test.suitebuilder.annotation.SmallTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.NetworkController;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
 
+@SmallTest
 public class TileServicesTests extends SysuiTestCase {
     private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
 
@@ -34,8 +39,13 @@
     protected void setUp() throws Exception {
         super.setUp();
         mManagers = new ArrayList<>();
-        QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
-                null, null, null, null, null, null, null);
+        final NetworkController networkController = Mockito.mock(NetworkController.class);
+        Mockito.when(networkController.getDataSaverController()).thenReturn(
+                Mockito.mock(DataSaverController.class));
+        QSTileHost host = new QSTileHost(mContext, null, null, null, null,
+                networkController, null,
+                Mockito.mock(HotspotController.class), null,
+                null, null, null, null, null, null, null, null);
         mTileService = new TestTileServices(host, Looper.myLooper());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 00b8de2..19cb243 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -19,12 +19,10 @@
 import android.telephony.SubscriptionInfo;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
-
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 5cf3767..60d33fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
@@ -31,14 +28,13 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
-
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
-
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
@@ -47,6 +43,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 public class NetworkControllerBaseTest extends SysuiTestCase {
     private static final String TAG = "NetworkControllerBaseTest";
     protected static final int DEFAULT_LEVEL = 2;
@@ -102,13 +101,14 @@
 
         // Trigger blank callbacks to always get the current state (some tests don't trigger
         // changes from default state).
-        mNetworkController.addSignalCallback(null);
+        mNetworkController.addSignalCallback(mock(SignalCallback.class));
         mNetworkController.addEmergencyListener(null);
     }
 
     protected void setupNetworkController() {
         // For now just pretend to be the data sim, so we can test that too.
         mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+        when(mMockTm.getDataEnabled(mSubId)).thenReturn(true);
         setDefaultSubId(mSubId);
         setSubscriptions(mSubId);
         mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 32e1e6d..08257b6 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -24,7 +24,7 @@
     <application android:label="VpnDialogs"
             android:allowBackup="false" >
         <activity android:name=".ConfirmDialog"
-                android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert">
+                android:theme="@android:style/Theme.Material.Light.Dialog.Alert">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.DEFAULT"/>
@@ -32,7 +32,7 @@
         </activity>
 
         <activity android:name=".ManageDialog"
-                android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+                android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
                 android:noHistory="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/packages/VpnDialogs/res/values-be-rBY/strings.xml b/packages/VpnDialogs/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..d96a172
--- /dev/null
+++ b/packages/VpnDialogs/res/values-be-rBY/strings.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="prompt" msgid="3183836924226407828">"Запыт на падлучэнне"</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> спрабуе наладзіць падлучэнне VPN, якое дазваляе сачыць за сеткавым трафікам. Прымайце толькі тады, калі вы давяраеце гэтай крыніцы. Калі VPN актыўны, у верхняй частцы экрана адлюстроўваецца &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="legacy_title" msgid="192936250066580964">"VPN падключаны"</string>
+    <string name="configure" msgid="4905518375574791375">"Наладзіць"</string>
+    <string name="disconnect" msgid="971412338304200056">"Адключыцца"</string>
+    <string name="session" msgid="6470628549473641030">"Сессія"</string>
+    <string name="duration" msgid="3584782459928719435">"Працягласць:"</string>
+    <string name="data_transmitted" msgid="7988167672982199061">"Адпраўлена:"</string>
+    <string name="data_received" msgid="4062776929376067820">"Атрымана:"</string>
+    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> байт / <xliff:g id="NUMBER_1">%2$s</xliff:g> пакеты"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-bs-rBA/strings.xml b/packages/VpnDialogs/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..899908c
--- /dev/null
+++ b/packages/VpnDialogs/res/values-bs-rBA/strings.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="prompt" msgid="3183836924226407828">"Zahtjev za povezivanje"</string>
+    <string name="warning" msgid="809658604548412033">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi podesiti VPN vezu koja joj omogućava praćenje mrežnog saobraćaja. Prihvatite samo ako je izvor pouzdan. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; se pojavi na vrhu ekrana kada je VPN aktivna."</string>
+    <string name="legacy_title" msgid="192936250066580964">"VPN veza uspostavljena"</string>
+    <string name="configure" msgid="4905518375574791375">"Konfiguriraj"</string>
+    <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
+    <string name="session" msgid="6470628549473641030">"Sesija:"</string>
+    <string name="duration" msgid="3584782459928719435">"Trajanje:"</string>
+    <string name="data_transmitted" msgid="7988167672982199061">"Poslano:"</string>
+    <string name="data_received" msgid="4062776929376067820">"Primljeno:"</string>
+    <string name="data_value_format" msgid="2192466557826897580">"Broj bajtova: <xliff:g id="NUMBER_0">%1$s</xliff:g>/Broj paketa: <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
index a77ef03..4865e96 100644
--- a/packages/VpnDialogs/res/values-ro/strings.xml
+++ b/packages/VpnDialogs/res/values-ro/strings.xml
@@ -20,10 +20,10 @@
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> dorește să configureze o conexiune VPN care să îi permită să monitorizeze traficul în rețea. Acceptați numai dacă aveți încredere în sursă. Atunci când conexiunea VPN este activă, &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; se afișează în partea de sus a ecranului."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN este conectat"</string>
     <string name="configure" msgid="4905518375574791375">"Configurați"</string>
-    <string name="disconnect" msgid="971412338304200056">"Deconectaţi"</string>
+    <string name="disconnect" msgid="971412338304200056">"Deconectați"</string>
     <string name="session" msgid="6470628549473641030">"Sesiune:"</string>
     <string name="duration" msgid="3584782459928719435">"Durată:"</string>
     <string name="data_transmitted" msgid="7988167672982199061">"Trimise:"</string>
     <string name="data_received" msgid="4062776929376067820">"Primite:"</string>
-    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> (de) octeţi/<xliff:g id="NUMBER_1">%2$s</xliff:g> (de) pachete"</string>
+    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> (de) octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g> (de) pachete"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-uz-rUZ/strings.xml b/packages/VpnDialogs/res/values-uz-rUZ/strings.xml
index 9185297..69e3e29 100644
--- a/packages/VpnDialogs/res/values-uz-rUZ/strings.xml
+++ b/packages/VpnDialogs/res/values-uz-rUZ/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="prompt" msgid="3183836924226407828">"Ulanish uchun so‘rov"</string>
-    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ilovasi tarmoq trafigini kuzatish uchun VPN ulanishini o‘rnatmoqchi. Agar ilova manbasiga ishonsangiz, unga rozi bo‘ling. VPN faol bo‘lsa, ekran tepasida &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; paydo bo‘ladi."</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ilovasi trafikni kuzatish uchun VPN tarmog‘iga ulanmoqchi. Agar ilovaga ishonsangiz, so‘rovga rozi bo‘ling.&lt;br /&gt; &lt;br /&gt;VPN faol bo‘lsa, ekranning yuqori qismida &lt;img src=vpn_icon /&gt; belgisi paydo bo‘ladi."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ulangan"</string>
     <string name="configure" msgid="4905518375574791375">"Moslash"</string>
     <string name="disconnect" msgid="971412338304200056">"Aloqani uzish"</string>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index 0f9e247..6a56afd 100644
--- a/packages/WallpaperCropper/res/values/styles.xml
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -15,7 +15,7 @@
 -->
 
 <resources>
-    <style name="Theme.WallpaperCropper" parent="@*android:style/Theme.Material.DayNight">
+    <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Material.Light">
         <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowActionBarOverlay">true</item>
diff --git a/packages/services/Proxy/AndroidManifest.xml b/packages/services/Proxy/AndroidManifest.xml
index 88f8381..51531e3 100644
--- a/packages/services/Proxy/AndroidManifest.xml
+++ b/packages/services/Proxy/AndroidManifest.xml
@@ -8,8 +8,8 @@
     <application
         android:label="@string/app_label"
         android:process="com.android.proxyhandler"
-        android:forceDeviceEncrypted="true"
-        android:encryptionAware="true">
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
 
         <service android:name=".ProxyService"
             android:exported="true">
diff --git a/preloaded-classes b/preloaded-classes
index 9535cc2..be645d2 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -907,7 +907,7 @@
 android.graphics.drawable.AnimatedVectorDrawable$1
 android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState
 android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator
-android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator
+android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT
 android.graphics.drawable.AnimationDrawable
 android.graphics.drawable.AnimationDrawable$AnimationState
 android.graphics.drawable.BitmapDrawable
diff --git a/proto/jarjar-rules.txt b/proto/jarjar-rules.txt
index 0c77c2a..50220b4 100644
--- a/proto/jarjar-rules.txt
+++ b/proto/jarjar-rules.txt
@@ -1 +1,2 @@
-rule com.google.** com.android.@1
+rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
+
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 3f3f851..b3613df 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -24,334 +24,1734 @@
 
   // Known visual elements: views or controls.
   enum View {
+    // Unknown view
     VIEW_UNKNOWN = 0;
+
+    // OBSOLETE
     MAIN_SETTINGS = 1;
+
+    // OPEN: Settings > Accessibility
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY = 2;
+
+    // OPEN: Settings > Accessibility > Captions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_CAPTION_PROPERTIES = 3;
+
+    // OPEN: Settings > Accessibility > [Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_SERVICE = 4;
+
+    // OPEN: Settings > Accessibility > Color correction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
+
+    // OPEN: Settings > Accessibility > Accessibility shortcut
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
+
+    // OPEN: Settings > Accessibility > Magnification gestures
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
+
+    // OPEN: Settings > Accounts
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNT = 8;
+
+    // OPEN: Settings > Accounts > [Single Account Sync Settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNTS_ACCOUNT_SYNC = 9;
+
+    // OPEN: Settings > Accounts > Add an account
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
+
+    // OPEN: Settings > Accounts > [List of accounts when more than one]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNTS_MANAGE_ACCOUNTS = 11;
+
+    // OPEN: Settings > Cellular network settings > APNs
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APN = 12;
+
+    // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APN_EDITOR = 13;
+
+    // OBSOLETE
     APP_OPS_DETAILS = 14;
+
+    // OBSOLETE
     APP_OPS_SUMMARY = 15;
+
+    // OBSOLETE
     APPLICATION = 16;
+
+    // OPEN: Settings > Apps > Configure apps > App links > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_APP_LAUNCH = 17;
+
+    // OBSOLETE
     APPLICATIONS_APP_PERMISSION = 18;
+
+    // OPEN: Settings > Internal storage > Apps storage > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_APP_STORAGE = 19;
+
+    // OPEN: Settings > Apps > [App info]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_INSTALLED_APP_DETAILS = 20;
+
+    // OPEN: Settings > Memory > App usage > [App Memory usage]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_PROCESS_STATS_DETAIL = 21;
+
+    // OBSOLETE
     APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22;
+
+    // OPEN: Settings > Memory > App usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_PROCESS_STATS_UI = 23;
+
+    // OPEN: Settings > Bluetooth
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     BLUETOOTH = 24;
+
+    // OPEN: Choose Bluetooth device (ex: when sharing)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     BLUETOOTH_DEVICE_PICKER = 25;
+
+    // OBSOLETE
     BLUETOOTH_DEVICE_PROFILES = 26;
+
+    // OPEN: Settings > Security > Choose screen lock
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CHOOSE_LOCK_GENERIC = 27;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CHOOSE_LOCK_PASSWORD = 28;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CHOOSE_LOCK_PATTERN = 29;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CONFIRM_LOCK_PASSWORD = 30;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CONFIRM_LOCK_PATTERN = 31;
+
+    // OPEN: Settings > Security > Encrypt phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CRYPT_KEEPER = 32;
+
+    // OPEN: Settings > Security > Encrypt phone > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CRYPT_KEEPER_CONFIRM = 33;
+
+    // OPEN: Settings > Search results
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DASHBOARD_SEARCH_RESULTS = 34;
+
+    // OPEN: Settings (Root page)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DASHBOARD_SUMMARY = 35;
+
+    // OBSOLETE
     DATA_USAGE = 36;
+
+    // OPEN: Settings > Data usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DATA_USAGE_SUMMARY = 37;
+
+    // OPEN: Settings > Date & time
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DATE_TIME = 38;
+
+    // OPEN: Settings > Developer options
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVELOPMENT = 39;
+
+    // OPEN: Settings > About phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO = 40;
+
+    // OPEN: Settings > About phone > Status > IMEI information
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_IMEI_INFORMATION = 41;
+
+    // OPEN: Settings > Internal storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_STORAGE = 42;
+
+    // OPEN: Settings > About phone > Status > SIM status
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_SIM_STATUS = 43;
+
+    // OPEN: Settings > About phone > Status
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_STATUS = 44;
+
+    // OBSOLETE
     DEVICEINFO_USB = 45;
+
+    // OPEN: Settings > Display
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DISPLAY = 46;
+
+    // OPEN: Settings > Display > Daydream
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DREAM = 47;
+
+    // OPEN: Settings > Security > Screen lock > Secure start-up
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ENCRYPTION = 48;
+
+    // OPEN: Settings > Security > Nexus Imprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FINGERPRINT = 49;
+
+    // OBSOLETE
     FINGERPRINT_ENROLL = 50;
+
+    // OPEN: Settings > Battery > History details
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
+
+    // OPEN: Settings > Battery > Battery saver
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_BATTERY_SAVER = 52;
+
+    // OPEN: Settings > Battery > [App Use details]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_POWER_USAGE_DETAIL = 53;
+
+    // OPEN: Settings > Battery
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_POWER_USAGE_SUMMARY = 54;
+
+    // OPEN: Settings > Home
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     HOME = 55;
+
+    // OPEN: Settings > Security > SIM card lock settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ICC_LOCK = 56;
+
+    // OPEN: Settings > Language & input
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_LANGUAGE = 57;
+
+    // OPEN: Settings > Language & input > Physical keyboard
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_KEYBOARD = 58;
+
+    // OPEN: Settings > Language & input > Spell checker
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_SPELL_CHECKERS = 59;
+
+    // OBSOLETE
     INPUTMETHOD_SUBTYPE_ENABLER = 60;
+
+    // OPEN: Settings > Language & input > Personal dictionary
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_USER_DICTIONARY = 61;
+
+    // OPEN: Settings > Language & input > Add word
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
+
+    // OPEN: Settings > Location
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     LOCATION = 63;
+
+    // OPEN: Settings > Location > Location mode
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     LOCATION_MODE = 64;
+
+    // OPEN: Settings > Apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MANAGE_APPLICATIONS = 65;
+
+    // OPEN: Settings > Backup & reset > Factory data reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MASTER_CLEAR = 66;
+
+    // OPEN: Settings > Backup & reset > Factory data reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MASTER_CLEAR_CONFIRM = 67;
+
+    // OPEN: Settings > Data usage > Network restrictions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NET_DATA_USAGE_METERED = 68;
+
+    // OPEN: Settings > More > Android Beam
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NFC_BEAM = 69;
+
+    // OPEN: Settings > Tap & pay
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NFC_PAYMENT = 70;
+
+    // OPEN: Settings > Sound & notification
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION = 71;
+
+    // OPEN: Settings > Sound & notification > App notifications > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_APP_NOTIFICATION = 72;
+
+    // OPEN: Settings > Sound & notification > Other sounds
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_OTHER_SOUND = 73;
+
+    // OBSOLETE
     NOTIFICATION_REDACTION = 74;
+
+    // OPEN: Settings Widget > Notification log
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_STATION = 75;
+
+    // OPEN: Settings > Sound & notification > Do not disturb
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE = 76;
+
+    // OPEN: OBSOLETE
     OWNER_INFO = 77;
+
+    // OPEN: Print job notification > Print job settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRINT_JOB_SETTINGS = 78;
+
+    // OPEN: Settings > Printing > [Print Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRINT_SERVICE_SETTINGS = 79;
+
+    // OPEN: Settings > Printing
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRINT_SETTINGS = 80;
+
+    // OPEN: Settings > Backup & reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRIVACY = 81;
+
+    //OBSOLETE
     PROXY_SELECTOR = 82;
+
+    // OPEN: Settings > Backup & reset > Network settings reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     RESET_NETWORK = 83;
+
+    // OPEN: Settings > Backup & reset > Network settings reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     RESET_NETWORK_CONFIRM = 84;
+
+    // OPEN: Settings > Developer Options > Running Services
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     RUNNING_SERVICE_DETAILS = 85;
+
+    // OPEN: Settings > Security > Screen pinning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SCREEN_PINNING = 86;
+
+    // OPEN: Settings > Security
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SECURITY = 87;
+
+    // OPEN: Settings > SIM cards
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SIM = 88;
+
+    // OBSOLETE
     TESTING = 89;
+
+    // OPEN: Settings > More > Tethering & portable hotspot
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TETHER = 90;
+
+    // OPEN: Settings > Security > Trust agents
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TRUST_AGENT = 91;
+
+    // OPEN: Settings > Security > Trusted credentials
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TRUSTED_CREDENTIALS = 92;
+
+    // OPEN: Settings > Language & input > TTS output > [Engine] > Settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TTS_ENGINE_SETTINGS = 93;
+
+    // OPEN: Settings > Language & input > Text-to-speech output
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TTS_TEXT_TO_SPEECH = 94;
+
+    // OPEN: Settings > Security > Apps with usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USAGE_ACCESS = 95;
+
+    // OPEN: Settings > Users
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USER = 96;
+
+    // OPEN: Settings > Users > [Restricted profile app & content access]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USERS_APP_RESTRICTIONS = 97;
+
+    // OPEN: Settings > Users > [User settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USER_DETAILS = 98;
+
+    // OBSOLETE
     VOICE_INPUT = 99;
+
+    // OPEN: Settings > More > VPN
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     VPN = 100;
+
+    // OPEN: Settings > Display > Choose wallpaper from
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WALLPAPER_TYPE = 101;
+
+    // OPEN: Settings > Display > Cast
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WFD_WIFI_DISPLAY = 102;
+
+    // OPEN: Settings > Wi-Fi
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI = 103;
+
+    // OPEN: Settings > Wi-Fi > Advanced Wi-Fi
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_ADVANCED = 104;
+
+    // OPEN: Settings > More > Wi-Fi Calling
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_CALLING = 105;
+
+    // OPEN: Settings > Wi-Fi > Saved networks
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_SAVED_ACCESS_POINTS = 106;
+
+    // OBSOLETE
     WIFI_APITEST = 107;
+
+    // OBSOLETE
     WIFI_INFO = 108;
+
+    // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_P2P = 109;
+
+    // OPEN: Settings > More
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIRELESS = 110;
+
+    // OPEN: Quick Settings Panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_PANEL = 111;
+
+    // OPEN: QS Airplane mode tile shown
+    // ACTION: QS Airplane mode tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_AIRPLANEMODE = 112;
+
+    // OPEN: QS Bluetooth tile shown
+    // ACTION: QS Bluetooth tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_BLUETOOTH = 113;
+
+    // OPEN: QS Cast tile shown
+    // ACTION: QS Cast tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_CAST = 114;
+
+    // OPEN: QS Cellular tile shown
+    // ACTION: QS Cellular tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_CELLULAR = 115;
+
+    // OPEN: QS Color inversion tile shown
+    // ACTION: QS Color inversion tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_COLORINVERSION = 116;
+
+    // OPEN: QS Cellular tile > Cellular detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_DATAUSAGEDETAIL = 117;
+
+    // OPEN: QS Do not disturb tile shown
+    // ACTION: QS Do not disturb tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_DND = 118;
+
+    // OPEN: QS Flashlight tile shown
+    // ACTION: QS Flashlight tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_FLASHLIGHT = 119;
+
+    // OPEN: QS Hotspot tile shown
+    // ACTION: QS Hotspot tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_HOTSPOT = 120;
+
+    // OPEN: QS 3P tile shown
+    // ACTION: QS 3P tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_INTENT = 121;
+
+    // OPEN: QS Location tile shown
+    // ACTION: QS Location tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_LOCATION = 122;
+
+    // OPEN: QS Rotation tile shown
+    // ACTION: QS Rotation tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_ROTATIONLOCK = 123;
+
+    // OBSOLETE
     QS_USERDETAILITE = 124;
+
+    // OPEN: QS User list panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_USERDETAIL = 125;
+
+    // OPEN: QS WiFi tile shown
+    // ACTION: QS WiFi tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_WIFI = 126;
+
+    // OPEN: Notification Panel (including lockscreen)
+    // CATEGORY: NOTIFICATION
+    // OS: 5.1.1
+    // GMS: 7.5.26
     NOTIFICATION_PANEL = 127;
+
+    // OPEN: Notification in panel became visible.
+    //   PACKAGE: App that posted the notification.
+    // ACTION: Notification is tapped.
+    //   PACKAGE: App that posted the notification
+    // DETAIL: Notification is expanded by user.
+    //   PACKAGE: App that posted the notification
+    // DISMISS: Notification is dismissed.
+    //   PACKAGE: App that posted the notification
+    //   SUBTYPE: Dismiss reason from NotificationManagerService.java
+    // CATEGORY: NOTIFICATION
+    // OS: 5.1.1
+    // GMS: 7.5.26
     NOTIFICATION_ITEM = 128;
+
+    // ACTION: User tapped notification action
+    //   PACKAGE: App that posted the notification
+    //   SUBTYPE: Index of action on notification
+    // CATEGORY: NOTIFICATION
+    // OS: 5.0
+    // GMS: 7.5.26
     NOTIFICATION_ITEM_ACTION = 129;
+
+    // OPEN: Settings > Apps > Configure apps > App permissions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_ADVANCED = 130;
+
+    // OPEN: Settings > Location > Scanning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     LOCATION_SCANNING = 131;
+
+    // OBSOLETE
     MANAGE_APPLICATIONS_ALL = 132;
+
+    // OPEN: Settings > Sound & notification > App notifications
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
+
+    // ACTION: Settings > Wi-Fi > Overflow > Add Network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_ADD_NETWORK = 134;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_CONNECT = 135;
+
+    // ACTION: Settings > Wi-Fi > Overflow > Refresh
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_FORCE_SCAN = 136;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Forget network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_FORGET = 137;
+
+    // ACTION: Settings > Wi-Fi > Toggle off
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_OFF = 138;
+
+    // ACTION: Settings > Wi-Fi > Toggle on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_ON = 139;
+
+    // OBSOLETE
     MANAGE_PERMISSIONS = 140;
+
+    // OPEN: Settings > Sound & notification > DND > Priority only allows
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_PRIORITY = 141;
+
+    // OPEN: Settings > Sound & notification > DND > Automatic rules
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
+
+    // OPEN: Settings > Apps > Configure apps > App links
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MANAGE_DOMAIN_URLS = 143;
+
+    // OPEN: Settings > Sound & notification > DND > [Time based rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+
+    // OPEN: Settings > Sound & notification > DND > [External rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
+
+    // OPEN: Settings > Sound & notification > DND > [Event rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
+
+    // ACTION: App notification settings > Block Notifications
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BAN_APP_NOTES = 147;
+
+    // ACTION: Notification shade > Dismiss all button
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_DISMISS_ALL_NOTES = 148;
+
+    // OPEN: QS Do Not Disturb detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_DETAILS = 149;
+
+    // OPEN: QS Bluetooth detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_BLUETOOTH_DETAILS = 150;
+
+    // OPEN: QS Cast detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CAST_DETAILS = 151;
+
+    // OPEN: QS Wi-Fi detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_WIFI_DETAILS = 152;
+
+    // ACTION: QS Wi-Fi detail panel > Wi-Fi toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_WIFI_TOGGLE = 153;
+
+    // ACTION: QS Bluetooth detail panel > Bluetooth toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_BLUETOOTH_TOGGLE = 154;
+
+    // ACTION: QS Cellular detail panel > Cellular toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CELLULAR_TOGGLE = 155;
+
+    // ACTION: QS User list panel > Select different user
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_SWITCH_USER = 156;
+
+    // ACTION: QS Cast detail panel > Select cast device
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CAST_SELECT = 157;
+
+    // ACTION: QS Cast detail panel > Disconnect cast device
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CAST_DISCONNECT = 158;
+
+    // ACTION: Settings > Bluetooth > Toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_TOGGLE = 159;
+
+    // ACTION: Settings > Bluetooth > Overflow > Refresh
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_SCAN = 160;
+
+    // ACTION: Settings > Bluetooth > Overflow > Rename this device
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_RENAME = 161;
+
+    // ACTION: Settings > Bluetooth > Overflow > Show received files
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_FILES = 162;
+
+    // ACTION: QS DND details panel > Increase / Decrease exit time
+    //   SUBTYPE: true is increase, false is decrease
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_TIME = 163;
+
+    // ACTION: QS DND details panel > [Exit condition]
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_CONDITION_SELECT = 164;
+
+    // ACTION: QS DND details panel > [DND mode]
+    //  SUBTYPE: 1 is priority, 2 is silence, 3 is alarms only
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_ZEN_SELECT = 165;
+
+    // ACTION: QS DND detail panel > DND toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_TOGGLE = 166;
+
+    // ACTION: DND Settings > Priority only allows > Reminder toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_REMINDERS = 167;
+
+    // ACTION: DND Settings > Priority only allows > Event toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_EVENTS = 168;
+
+    // ACTION: DND Settings > Priority only allows > Messages
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_MESSAGES = 169;
+
+    // ACTION: DND Settings > Priority only allows > Calls
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_CALLS = 170;
+
+    // ACTION: DND Settings > Priority only allows > Repeat callers toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
+
+    // ACTION: DND Settings > Automatic rules > Add rule
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ADD_RULE = 172;
+
+    // ACTION: DND Settings > Automatic rules > Add rule > OK
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ADD_RULE_OK = 173;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_DELETE_RULE = 174;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_DELETE_RULE_OK = 175;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ENABLE_RULE = 176;
+
+    // ACTION: Settings > More > Airplane mode toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_AIRPLANE_TOGGLE = 177;
+
+    // ACTION: Settings > Data usage > Cellular data toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_CELL_DATA_TOGGLE = 178;
+
+    // OPEN: Settings > Sound & notification > Notification access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ACCESS = 179;
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_ACCESS = 180;
+
+    // OPEN: Settings > Apps > Configure apps > Default Apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_DEFAULT_APPS = 181;
+
+    // OPEN: Settings > Internal storage > Apps storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_STORAGE_APPS = 182;
+
+    // OPEN: Settings > Security > Usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
+
+    // OPEN: Settings > Battery > Battery optimization
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_HIGH_POWER_APPS = 184;
+
+    // OBSOLETE
     FUELGAUGE_HIGH_POWER_DETAILS = 185;
+
+    // ACTION: Lockscreen > Unlock gesture
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_UNLOCK = 186;
+
+    // ACTION: Lockscreen > Pull shade open
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_SHADE = 187;
+
+    // ACTION: Lockscreen > Tap on lock, shows hint
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_HINT = 188;
+
+    // ACTION: Lockscreen > Camera
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_CAMERA = 189;
+
+    // ACTION: Lockscreen > Dialer
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_DIALER = 190;
+
+    // ACTION: Lockscreen > Tap on lock, locks phone
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_LOCK = 191;
+
+    // ACTION: Lockscreen > Tap on notification, false touch rejection
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_NOTE = 192;
+
+    // ACTION: Lockscreen > Swipe down to open quick settings
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.22
     ACTION_LS_QS = 193;
+
+    // ACTION: Swipe down to open quick settings when unlocked
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.22
     ACTION_SHADE_QS_PULL = 194;
+
+    // ACTION: Notification shade > Tap to open quick settings
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.22
     ACTION_SHADE_QS_TAP = 195;
+
+    // OPEN: Lockscreen
+    //   SUBTYPE: 0 is unsecure, 1 is secured by password / pattern / PIN
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     LOCKSCREEN = 196;
+
+    // OPEN: Lockscreen > Screen to enter password / pattern / PIN
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     BOUNCER = 197;
+
+    // OPEN: Screen turned on
+    //   SUBTYPE: 2 is user action
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     SCREEN = 198;
+
+    // OPEN: Notification caused sound, vibration, and/or LED blink
+    //   SUBTYPE: 1 is buzz, 2 is beep, blink is 4, or'd together
+    // CATEGORY: NOTIFICATION
+    // OS: 5.1.1
+    // GMS: 7.8.53
     NOTIFICATION_ALERT = 199;
+
+    // ACTION: Lockscreen > Emergency Call button
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.5.26
     ACTION_EMERGENCY_CALL = 200;
+
+    // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_MANAGE_ASSIST = 201;
+
+    // OPEN: Settings > Memory
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PROCESS_STATS_SUMMARY = 202;
+
+    // ACTION: Settings > Display > When device is rotated
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ROTATION_LOCK = 203;
+
+    // ACTION: Long press on notification to view controls
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_NOTE_CONTROLS = 204;
+
+    // ACTION: Notificatoin controls > Info button
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_NOTE_INFO = 205;
+
+    // ACTION: Notification controls > Settings button
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_APP_NOTE_SETTINGS = 206;
+
+    // OPEN: Volume Dialog (with hardware buttons)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     VOLUME_DIALOG = 207;
+
+    // OPEN: Volume dialog > Expanded volume dialog (multiple sliders)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     VOLUME_DIALOG_DETAILS = 208;
+
+    // ACTION: Volume dialog > Adjust volume slider
+    //   SUBTYPE: volume level (0-7)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_SLIDER = 209;
+
+    // ACTION: Volume dialog > Select non-active stream
+    //   SUBTYPE: stream (defined in AudioSystem.java)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_STREAM = 210;
+
+    // ACTION: Adjust volume with hardware key
+    //   SUBTYPE: volume level (0-7)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_KEY = 211;
+
+    // ACTION: Volume dialog > Mute a stream by tapping icon
+    //   SUBTYPE: mute is 1, audible is 2
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_ICON = 212;
+
+    // ACTION: Volume dialog > Change ringer mode by tapping icon
+    //   SUBTYPE: 2 is audible, 3 is vibrate
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_RINGER_MODE = 213;
+
+    // ACTION: Chooser shown (share target, file open, etc.)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_SHOWN = 214;
+
+    // ACTION: Chooser > User taps an app target
+    //   SUBTYPE: Index of target
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
+
+    // ACTION: Chooser > User taps a service target
+    //   SUBTYPE: Index of target
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
+
+    // ACTION: Chooser > User taps a standard target
+    //   SUBTYPE: Index of target
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
+
+    // ACTION: QS Brightness Slider (with auto brightness disabled)
+    //   SUBTYPE: slider value
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BRIGHTNESS = 218;
+
+    // ACTION: QS Brightness Slider (with auto brightness enabled)
+    //   SUBTYPE: slider value
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BRIGHTNESS_AUTO = 219;
+
+    // OPEN: Settings > Display > Brightness Slider
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     BRIGHTNESS_DIALOG = 220;
+
+    // OPEN: Settings > Apps > Configure Apps > Draw over other apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SYSTEM_ALERT_WINDOW_APPS = 221;
+
+    // OPEN: Display has entered dream mode
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     DREAMING = 222;
+
+    // OPEN: Display has entered ambient notification mode
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     DOZING = 223;
+
+    // OPEN: Overview
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     OVERVIEW_ACTIVITY = 224;
+
+    // OPEN: Settings > About phone > Legal information
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ABOUT_LEGAL_SETTINGS = 225;
+
+    // OPEN: Settings > Search > Perform search
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_SEARCH_RESULTS = 226;
+
+    // OPEN: Settings > System UI Tuner
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER = 227;
+
+    // OPEN: Settings > System UI Tuner > Quick Settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS = 228;
+
+    // OPEN: Settings > System UI Tuner > Demo mode
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_DEMO_MODE = 229;
+
+    // ACTION: Settings > System UI Tuner > Quick Settings > Move tile
+    //   PACKAGE: Tile
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS_REORDER = 230;
+
+    // ACTION: Settings > System UI Tuner > Quick Settings > Add tile
+    //   PACKAGE: Tile
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS_ADD = 231;
+
+    // ACTION: Settings > System UI Tuner > Quick Settings > Remove tile
+    //   PACKAGE: Tile
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS_REMOVE = 232;
+
+    // ACTION: Settings > System UI Tuner > Status bar > Enable icon
+    //   PACKAGE: Icon
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_STATUS_BAR_ENABLE = 233;
+
+    // ACTION: Settings > System UI Tuner > Status bar > Disable icon
+    //   PACKAGE: Icon
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_STATUS_BAR_DISABLE = 234;
+
+    // ACTION: Settings > System UI Tuner > Demo mode > Enable demo mode
+    //   SUBTYPE: false is disabled, true is enabled
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_DEMO_MODE_ENABLED = 235;
+
+    // ACTION: Settings > System UI Tuner > Demo mode > Show demo mode
+    //   SUBTYPE: false is disabled, true is enabled
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_DEMO_MODE_ON = 236;
+
+    // ACTION: Settings > System UI Tuner > Show embedded battery percentage
+    //   SUBTYPE: 0 is disabled, 1 is enabled
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_BATTERY_PERCENTAGE = 237;
+
+    // OPEN: Settings > Developer options > Inactive apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_INACTIVE_APPS = 238;
+
+    // ACTION: Long press home to bring up assistant
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ASSIST_LONG_PRESS = 239;
+
+    // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLLING = 240;
+
+    // OPEN: Fingerprint Enroll > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_FIND_SENSOR = 241;
+
+    // OPEN: Fingerprint Enroll > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_FINISH = 242;
+
+    // OPEN: Fingerprint Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_INTRO = 243;
+
+    // OPEN: Fingerprint Enroll onboarding
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_ONBOARD = 244;
+
+    // OPEN: Fingerprint Enroll > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_SIDECAR = 245;
+
+    // OPEN: Fingerprint Enroll SUW > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLLING_SETUP = 246;
+
+    // OPEN: Fingerprint Enroll SUW > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_FIND_SENSOR_SETUP = 247;
+
+    // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_FINISH_SETUP = 248;
+
+    // OPEN: Fingerprint Enroll SUW introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_INTRO_SETUP = 249;
+
+    // OPEN: Fingerprint Enroll SUW onboarding
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_ONBOARD_SETUP = 250;
+
+    // ACTION: Add fingerprint > Enroll fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_ENROLL = 251;
+
+    // ACTION: Authenticate using fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_AUTH = 252;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_DELETE = 253;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_RENAME = 254;
+
+    // ACTION: Double tap camera shortcut
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
+
+    // ACTION: Double twist camera shortcut
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_WIGGLE_CAMERA_GESTURE = 256;
+
+    // OPEN: QS Work Mode tile shown
+    // ACTION: QS Work Mode tile tapped
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_WORKMODE = 257;
+
+    // OPEN: Settings > Developer Options > Background Check
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     BACKGROUND_CHECK_SUMMARY = 258;
+
+    // OPEN: QS Lock tile shown
+    // ACTION: QS Lock tile tapped
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_LOCK_TILE = 259;
+
+    // OPEN: QS User Tile shown
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_USER_TILE = 260;
+
+    // OPEN: QS Battery tile shown
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_BATTERY_TILE = 261;
+
+    // OPEN: Settings > Sound > Do not disturb > Visual interruptions
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 262;
+
+    // ACTION: Visual interruptions > No screen interuptions toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ZEN_ALLOW_WHEN_SCREEN_OFF = 263;
-    // Dead
+
+    // ACTION: Visual interruptions > No notification light toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ZEN_ALLOW_LIGHTS = 264;
+
+    // OPEN: Settings > Notifications > [App] > Topic Notifications
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     NOTIFICATION_TOPIC_NOTIFICATION = 265;
+
+    // ACTION: Settings > Apps > Default Apps > Select different SMS app
+    //   PACKAGE: Selected SMS app
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_DEFAULT_SMS_APP_CHANGED = 266;
+
+    // OPEN: QS Color modification tile shown
+    // ACTION: QS Color modification tile tapped
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_COLOR_MATRIX = 267;
+
+    // OPEN: QS Custom tile shown
+    // ACTION: QS Work Mode tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_CUSTOM = 268;
+
+    // ACTION: Visual interruptions > Never turn off the screen toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ZEN_ALLOW_WHEN_SCREEN_ON = 269;
 
-    // Logged when the user docks a window from recents by
-    // longpressing a task and dragging it to the dock area.
+    // ACTION: Overview > Long-press task, drag to enter split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_DOCK_DRAG_DROP = 270;
 
-    // Logged when the user docks a fullscreen window by long pressing
-    // recents which also opens recents on the lower/right side.
+    // ACTION: In App > Long-press Overview button to enter split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_DOCK_LONGPRESS = 271;
 
-    // Logged when the user docks a window by dragging from the navbar
-    // which also opens recents on the lower/right side.
+    // ACTION: In App > Swipe Overview button to enter split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_DOCK_SWIPE = 272;
 
-    // Logged when the user launches a profile-specific app and we
-    // intercept it with the confirm credentials UI.
+    // ACTION: Launch profile-specific app > Confirm credentials
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     PROFILE_CHALLENGE = 273;
 
+    // OPEN: QS Battery detail panel
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     QS_BATTERY_DETAIL = 274;
 
-    // Logged when the user goes into the overview history.
+    // OPEN: Overview > History
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     OVERVIEW_HISTORY = 275;
 
-    // Logged when the user pages through overview.
-    OVERVIEW_PAGE = 276;
+    // ACTION: Overview > Page by tapping Overview button
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_OVERVIEW_PAGE = 276;
 
-    // Logged when the user launches a task from overview.
-    OVERVIEW_SELECT = 277;
+    // ACTION: Overview > Select app
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_OVERVIEW_SELECT = 277;
 
-    // Logged when the user views the emergency info.
+    // ACTION: View emergency info
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_VIEW_EMERGENCY_INFO = 278;
 
-    // Logged when the user views the edit emergency info activity.
+    // ACTION: Edit emergency info activity
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_EDIT_EMERGENCY_INFO = 279;
 
-    // Logged when the user edits an emergency info field.
+    // ACTION: Edit emergency info field
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_EDIT_EMERGENCY_INFO_FIELD = 280;
 
-    // Logged when the user adds a new emergency contact.
+    // ACTION: Add emergency contact
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ADD_EMERGENCY_CONTACT = 281;
 
-    // Logged when the user deletes an emergency contact.
+    // ACTION: Delete emergency contact
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_DELETE_EMERGENCY_CONTACT = 282;
 
-    // Logged when the user calls an emergency contact.
+    // ACTION: Call emergency contact
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_CALL_EMERGENCY_CONTACT = 283;
 
-    // QS Tile for Data Saver.
+    // OPEN: QS Data Saver tile shown
+    // ACTION: QS Data Saver tile tapped
+    // CATEGORY: QUICK_SETTINGS
     QS_DATA_SAVER = 284;
 
     // OPEN: Settings > Security > User credentials
     // CATEGORY: Settings
-    // OS: 6.1
+    // OS: N
     // GMS: 7.8.99
     USER_CREDENTIALS = 285;
 
-    // Logged when the user undocks a previously docked window by long pressing recents while in
-    // docked mode.
+    // ACTION: In App (splitscreen) > Long-press Overview to exit split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_UNDOCK_LONGPRESS = 286;
 
     // Logged when the user scrolls through overview manually
@@ -369,5 +1769,373 @@
     // Logged when the user saves a modification to notification importance. Negative numbers
     // indicate the user lowered the importance; positive means they increased it.
     ACTION_SAVE_IMPORTANCE = 291;
+
+    // ACTION: Long-press power button, then tap "Take bug report" option.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE = 292;
+
+    // ACTION: Long-press power button, then long-press "Take bug report" option.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_FROM_POWER_MENU_FULL = 293;
+
+    // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
+    // Interactive bug report initiated from Settings.
+    ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
+
+    // ACTION: Settings -> Developer Options -> Take bug report -> Full report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
+    // Interactive bug report initiated from Settings.
+    ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
+
+    // ACTION: User tapped notification action to cancel a bug report
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296;
+
+    // ACTION: User tapped notification action to launch bug report details screen
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS = 297;
+
+    // ACTION: User tapped notification action to take adition screenshot on bug report
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT = 298;
+
+    // ACTION: User tapped notification to share bug report
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299;
+
+    // ACTION: User changed bug report name using the details screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_DETAILS_NAME_CHANGED = 300;
+
+    // ACTION: User changed bug report title using the details screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_DETAILS_TITLE_CHANGED = 301;
+
+    // ACTION: User changed bug report description using the details screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED = 302;
+
+    // ACTION: User tapped Save in the bug report details screen.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_DETAILS_SAVED = 303;
+
+    // ACTION: User tapped Cancel in the bug report details screen.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_BUGREPORT_DETAILS_CANCELED = 304;
+
+    // Tuner: Open/close calibrate dialog.
+    TUNER_CALIBRATE_DISPLAY = 305;
+
+    // Tuner: Open/close color and appearance.
+    TUNER_COLOR_AND_APPEARANCE = 306;
+
+    // Tuner: Apply calibrate dialog.
+    ACTION_TUNER_CALIBRATE_DISPLAY_CHANGED = 307;
+
+    // Tuner: Open/close night mode.
+    TUNER_NIGHT_MODE = 308;
+
+    // Tuner: Change night mode.
+    ACTION_TUNER_NIGHT_MODE = 309;
+
+    // Tuner: Change night mode auto.
+    ACTION_TUNER_NIGHT_MODE_AUTO = 310;
+
+    // Tuner: Change night mode adjust dark theme.
+    ACTION_TUNER_NIGHT_MODE_ADJUST_DARK_THEME = 311;
+
+    // Tuner: Change night mode adjust tint.
+    ACTION_TUNER_NIGHT_MODE_ADJUST_TINT = 312;
+
+    // Tuner: Change night mode adjust brightness.
+    ACTION_TUNER_NIGHT_MODE_ADJUST_BRIGHTNESS = 313;
+
+    // Tuner: Change do not disturb in volume panel.
+    ACTION_TUNER_DO_NOT_DISTURB_VOLUME_PANEL = 314;
+
+    // Tuner: Change do not disturb volume buttons shortcut.
+    ACTION_TUNER_DO_NOT_DISTURB_VOLUME_SHORTCUT = 315;
+
+    // Logs the action the user takes when an app crashed.
+    ACTION_APP_CRASH = 316;
+
+    // Logs the action the user takes when an app ANR'd.
+    ACTION_APP_ANR = 317;
+
+    // Logged when a user double taps the overview button to launch the previous task
+    OVERVIEW_LAUNCH_PREVIOUS_TASK = 318;
+
+    // Logged when we execute an app transition. This indicates the total delay from startActivity
+    // until the app transition is starting to animate, in milliseconds.
+    APP_TRANSITION_DELAY_MS = 319;
+
+    // Logged when we execute an app transition. This indicates the reason why the transition
+    // started. Must be one of ActivityManagerInternal.APP_TRANSITION_* reasons.
+    APP_TRANSITION_REASON = 320;
+
+    // Logged when we execute an app transition and we drew a starting window. This indicates the
+    // delay from startActivity until the starting window was drawn.
+    APP_TRANSITION_STARTING_WINDOW_DELAY_MS = 321;
+
+    // Logged when we execute an app transition and all windows of the app got drawn. This indicates
+    // the delay from startActivity until all windows have been drawn.
+    APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS = 322;
+
+    // Logged when we execute an app transition. This indicates the component name of the current
+    // transition.
+    APP_TRANSITION_COMPONENT_NAME = 323;
+
+    // Logged when we execute an app transition. This indicates whether the process was already
+    // running.
+    APP_TRANSITION_PROCESS_RUNNING = 324;
+
+    // Logged when we execute an app transition. This indicates the device uptime in seconds when
+    // the transition was executed.
+    APP_TRANSITION_DEVICE_UPTIME_SECONDS = 325;
+
+    // User granted access to the request folder; action takes an integer
+    // representing the folder's index on Environment.STANDARD_DIRECTORIES
+    // (or -2 for root access, or -1 or unknown directory).
+    ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER = 326;
+
+    // User denied access to the request folder; action takes an integer
+    // representing the folder's index on Environment.STANDARD_DIRECTORIES
+    // (or -2 for root access, or -1 or unknown directory).
+    ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER = 327;
+
+    // User granted access to the request folder; action pass package name
+    // of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE = 328;
+
+    // User denied access to the request folder; action pass package name
+    // of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE = 329;
+
+    // App requested access to a directory it has already been granted
+    // access before; action takes an integer representing the folder's
+    // index on Environment.STANDARD_DIRECTORIES
+    // (or -2 for root access, or -1 or unknown directory).
+    ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER = 330;
+
+    // App requested access to a directory it has already been granted
+    // access before; action pass package name of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE = 331;
+
+    // Logged when the user slides a notification and
+    // reveals the gear beneath it.
+    ACTION_REVEAL_GEAR = 332;
+
+    // Logged when the user taps on the gear beneath
+    // a notification.
+    ACTION_TOUCH_GEAR = 333;
+
+    // Logs that the user has edited the enabled VR listeners.
+    VR_MANAGE_LISTENERS = 334;
+
+    // Settings -> Accessibility -> Click after pointer stops moving
+    ACCESSIBILITY_TOGGLE_AUTOCLICK = 335;
+    // Settings -> Sound
+    SOUND = 336;
+    // Settings -> Notifications -> Gear
+    CONFIGURE_NOTIFICATION = 337;
+    // Settings -> Wi-Fi -> Gear
+    CONFIGURE_WIFI = 338;
+    // Settings -> Display -> Display size
+    DISPLAY_SCREEN_ZOOM = 339;
+    // Settings -> Display -> Font size
+    ACCESSIBILITY_FONT_SIZE = 340;
+    // Settings -> Data usage -> Cellular/Wi-Fi data usage
+    DATA_USAGE_LIST = 341;
+    // Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear
+    BILLING_CYCLE = 342;
+    // DATA_USAGE_LIST -> Any item or App info -> Data usage
+    APP_DATA_USAGE = 343;
+    // Settings -> Language & input -> Language
+    USER_LOCALE_LIST = 344;
+    // Settings -> Language & input -> Virtual keyboard
+    VIRTUAL_KEYBOARDS = 345;
+    // Settings -> Language & input -> Physical keyboard
+    PHYSICAL_KEYBOARDS = 346;
+    // Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard
+    ENABLE_VIRTUAL_KEYBOARDS = 347;
+    // Settings -> Data usage -> Data Saver
+    DATA_SAVER_SUMMARY = 348;
+    // Settings -> Data usage -> Data Saver -> Unrestricted data access
+    DATA_USAGE_UNRESTRICTED_ACCESS = 349;
+
+    // Used for generic logging of Settings Preference Persistence, should not be used
+    // outside SharedPreferencesLogger.
+    ACTION_GENERIC_PACKAGE = 350;
+    // Settings -> Apps -> Gear -> Special access
+    SPECIAL_ACCESS = 351;
+
+    // Logs that the user docks window via shortcut key.
+    WINDOW_DOCK_SHORTCUTS = 352;
+
+    // User already denied access to the request folder; action takes an integer
+    // representing the folder's index on Environment.STANDARD_DIRECTORIES
+    // (or -2 for root access, or -1 or unknown directory).
+    ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_FOLDER = 353;
+
+    // User already denied access to the request folder; action pass package name
+    // of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_PACKAGE = 354;
+
+    // User denied access to the request folder and checked 'Do not ask again';
+    // action takes an integer representing the folder's index on Environment.STANDARD_DIRECTORIES
+    // (or -2 for root access, or -1 or unknown directory).
+    ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_FOLDER = 355;
+
+    // User denied access to the request folder and checked 'Do not ask again';
+    // action pass package name of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_PACKAGE = 356;
+
+    // Logged when a user dismisses all task in overview
+    OVERVIEW_DISMISS_ALL = 357;
+
+    // Quick Settings -> Edit
+    QS_EDIT = 358;
+
+    // Quick Settings -> Edit -> Overflow -> Reset
+    ACTION_QS_EDIT_RESET = 359;
+
+    // QS -> Edit - Drag a tile out of the active tiles.
+    // The _SPEC contains either the spec of the tile or
+    // the package of the 3rd party app in the PKG field.
+    ACTION_QS_EDIT_REMOVE_SPEC = 360;
+    ACTION_QS_EDIT_REMOVE = 361;
+
+    // QS -> Edit - Drag a tile into the active tiles.
+    // The _SPEC contains either the spec of the tile or
+    // the package of the 3rd party app in the PKG field.
+    ACTION_QS_EDIT_ADD_SPEC = 362;
+    ACTION_QS_EDIT_ADD = 363;
+
+    // QS -> Edit - Drag a tile within the active tiles.
+    // The _SPEC contains either the spec of the tile or
+    // the package of the 3rd party app in the PKG field.
+    ACTION_QS_EDIT_MOVE_SPEC = 364;
+    ACTION_QS_EDIT_MOVE = 365;
+
+    // Long-press on a QS tile. Tile spec in package field.
+    ACTION_QS_LONG_PRESS = 366;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY = 367;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification gesture
+    // ACTION: New magnification gesture configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 368;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Font size
+    // ACTION: New font size is chosen
+    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is largest
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_FONT_SIZE = 369;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Display size
+    // ACTION: New display size is chosen
+    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is larger, 4 is largest
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_DISPLAY_SIZE = 370;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> TalkBack
+    // ACTION: New screen reader configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER = 371;
+
+    // ------- Begin N Settings conditionals -----
+    // Conditionals are the green bars at the top of the settings dashboard
+    // All conditionals will have visible/hide events onResume/onPause
+    // but they will also be used as extra ints in the
+    // dismiss/expand/collapse/click/button events
+
+    // swipe away conditional
+    ACTION_SETTINGS_CONDITION_DISMISS = 372;
+
+    // click on collapsed conditional or clicks expand button
+    ACTION_SETTINGS_CONDITION_EXPAND = 373;
+
+    // click collapse button on expanded conditional
+    ACTION_SETTINGS_CONDITION_COLLAPSE = 374;
+
+    // click main area of expanded conditional
+    ACTION_SETTINGS_CONDITION_CLICK = 375;
+
+    // click a direct button on expanded conditional
+    ACTION_SETTINGS_CONDITION_BUTTON = 376;
+
+    // Airplane mode on
+    SETTINGS_CONDITION_AIRPLANE_MODE = 377;
+    // AKA Data saver on
+    SETTINGS_CONDITION_BACKGROUND_DATA = 378;
+    // Battery saver on
+    SETTINGS_CONDITION_BATTERY_SAVER = 379;
+    // Cellular data off
+    SETTINGS_CONDITION_CELLULAR_DATA = 380;
+    // Do not disturb on
+    SETTINGS_CONDITION_DND = 381;
+    // Hotspot on
+    SETTINGS_CONDITION_HOTSPOT = 382;
+    // Work profile off
+    SETTINGS_CONDITION_WORK_MODE = 383;
+
+    // ------- Begin N Settings suggestions -----
+    // Since suggestions come from system apps, suggestions will
+    // have generic constants and the package providing the suggestion
+    // will be put in the package field.  For suggestions in the Settings
+    // package, the class name will be filled in instead (since settings
+    // provides several suggetions).
+
+    // Settings shown/hidden on main settings dashboard.
+    // These are actually visibility events, but visible/hidden doesn't
+    // take a package, so these are being logged as actions.
+    ACTION_SHOW_SETTINGS_SUGGESTION = 384;
+    ACTION_HIDE_SETTINGS_SUGGESTION = 385;
+
+    // Click on a suggestion.
+    ACTION_SETTINGS_SUGGESTION = 386;
+
+    // Suggestion -> Overflow -> Remove.
+    ACTION_SETTINGS_DISMISS_SUGGESTION = 387;
+
+    // Add new aosp constants above this line.
+    // END OF AOSP CONSTANTS
   }
 }
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 8c78a3a..9ec6e8d 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -115,7 +115,7 @@
 
         if (cmp == Short.TYPE) {
             if (checkType) {
-                validateIsInt16();
+                validateIsInt16OrFloat16();
                 return mType.mElement.mType;
             }
             return Element.DataType.SIGNED_16;
@@ -142,7 +142,10 @@
             }
             return Element.DataType.FLOAT_64;
         }
-        return null;
+
+        throw new RSIllegalArgumentException("Parameter of type " + cmp.getSimpleName() +
+            "[] is not compatible with data type " + mType.mElement.mType.name() +
+            " of allocation");
     }
 
 
@@ -293,8 +296,13 @@
     }
 
     /**
-     * Enable/Disable AutoPadding for Vec3 elements.
-     * By default: Diabled.
+     * Enable/Disable AutoPadding for Vec3 Elements.
+     *
+     * <p> Vec3 Elements, such as {@link Element#U8_3} are treated as Vec4 Elements
+     * with the fourth vector element used as padding. Enabling the AutoPadding feature
+     * will automatically add/remove the padding when you copy to/from an Allocation
+     * with a Vec3 Element.
+     * <p> By default: Disabled.
      *
      * @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
      *
@@ -372,6 +380,7 @@
             Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
             throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
         }
+        guard.open("destroy");
     }
 
     Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) {
@@ -402,9 +411,10 @@
             "32 bit integer source does not match allocation type " + mType.mElement.mType);
     }
 
-    private void validateIsInt16() {
+    private void validateIsInt16OrFloat16() {
         if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
+            (mType.mElement.mType == Element.DataType.UNSIGNED_16) ||
+            (mType.mElement.mType == Element.DataType.FLOAT_16)) {
             return;
         }
         throw new RSIllegalArgumentException(
@@ -751,7 +761,7 @@
      * @param d the source data array
      */
     public void copyFrom(short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1060,7 +1070,7 @@
      * @param d the source data array
      */
     public void copy1DRangeFrom(int off, int count, short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1204,7 +1214,7 @@
      * @param data to be placed into the Allocation
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
                                  Element.DataType.SIGNED_16, data.length);
     }
@@ -1473,7 +1483,7 @@
      * @param d The array to be set from the Allocation.
      */
     public void copyTo(short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copyTo(d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1693,7 +1703,7 @@
      * @param d the source data array
      */
     public void copy1DRangeTo(int off, int count, short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1794,7 +1804,7 @@
      * @param data Dest Array to be copied into
      */
     public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy2DRangeToUnchecked(xoff, yoff, w, h, data,
                                Element.DataType.SIGNED_16, data.length);
     }
@@ -1906,6 +1916,7 @@
             if (type.getID(rs) == 0) {
                 throw new RSInvalidStateException("Bad Type");
             }
+            // TODO: What if there is an exception after this? The native allocation would leak.
             long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
             if (id == 0) {
                 throw new RSRuntimeException("Allocation creation failed.");
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index 1372ab7..f95af16 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -16,6 +16,7 @@
 
 package android.renderscript;
 
+import dalvik.system.CloseGuard;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
@@ -69,6 +70,7 @@
     }
 
     private long mID;
+    final CloseGuard guard = CloseGuard.get();
     private boolean mDestroyed;
     private String mName;
     RenderScript mRS;
@@ -119,6 +121,7 @@
         }
 
         if (shouldDestroy) {
+            guard.close();
             // must include nObjDestroy in the critical section
             ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
             rlock.lock();
@@ -133,8 +136,14 @@
     }
 
     protected void finalize() throws Throwable {
-        helpDestroy();
-        super.finalize();
+        try {
+            if (guard != null) {
+                guard.warnIfOpen();
+            }
+            helpDestroy();
+        } finally {
+            super.finalize();
+        }
     }
 
     /**
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 6efb6d6..50226ac 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -808,6 +808,7 @@
             mSize += mElements[ct].mSize * mArraySizes[ct];
         }
         updateVisibleSubElements();
+        guard.open("destroy");
     }
 
     Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -827,6 +828,7 @@
         mKind = dk;
         mNormalized = norm;
         mVectorSize = size;
+        guard.open("destroy");
     }
 
     Element(long id, RenderScript rs) {
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 9d8f162..278d309 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -170,6 +170,7 @@
     FileA3D(long id, RenderScript rs, InputStream stream) {
         super(id, rs);
         mInputStream = stream;
+        guard.open("destroy");
     }
 
     private void initEntries() {
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 4318b9d..d5ca31e 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -150,6 +150,7 @@
 
     Font(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 13c8e1c..9e4f905 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -91,6 +91,7 @@
 
     Mesh(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java
index 3eb9b75..772021c 100644
--- a/rs/java/android/renderscript/Program.java
+++ b/rs/java/android/renderscript/Program.java
@@ -76,6 +76,7 @@
 
     Program(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 425569c..2650e5a 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1031,7 +1031,6 @@
 
 
 
-    long     mDev;
     long     mContext;
     private boolean mDestroyed = false;
 
@@ -1387,6 +1386,27 @@
     }
 
     /**
+     * Name of the file that holds the object cache.
+     */
+    private static String mCachePath;
+
+    /**
+     * Gets the path to the code cache.
+     */
+    static synchronized String getCachePath() {
+        if (mCachePath == null) {
+            final String CACHE_PATH = "com.android.renderscript.cache";
+            if (RenderScriptCacheDir.mCacheDir == null) {
+                throw new RSRuntimeException("RenderScript code cache directory uninitialized.");
+            }
+            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
+            mCachePath = f.getAbsolutePath();
+            f.mkdirs();
+        }
+        return mCachePath;
+    }
+
+    /**
      * Create a RenderScript context.
      *
      * @param ctx The context.
@@ -1405,8 +1425,8 @@
 
         RenderScript rs = new RenderScript(ctx);
 
-        rs.mDev = rs.nDeviceCreate();
-        rs.mContext = rs.nContextCreate(rs.mDev, flags, sdkVersion, ct.mID);
+        long device = rs.nDeviceCreate();
+        rs.mContext = rs.nContextCreate(device, flags, sdkVersion, ct.mID);
         rs.mContextType = ct;
         rs.mContextFlags = flags;
         rs.mContextSdkVersion = sdkVersion;
@@ -1415,11 +1435,7 @@
         }
 
         // set up cache directory for entire context
-        final String CACHE_PATH = "com.android.renderscript.cache";
-        File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
-        String mCachePath = f.getAbsolutePath();
-        f.mkdirs();
-        rs.nContextSetCacheDir(mCachePath);
+        rs.nContextSetCacheDir(RenderScript.getCachePath());
 
         rs.mMessageThread = new MessageThread(rs);
         rs.mMessageThread.start();
@@ -1618,9 +1634,6 @@
             }
 
             nContextDestroy();
-
-            nDeviceDestroy(mDev);
-            mDev = 0;
         }
     }
 
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index 6178994..be1f899 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -177,9 +177,9 @@
 
         mWidth = 0;
         mHeight = 0;
-        mDev = nDeviceCreate();
+        long device = nDeviceCreate();
         int dpi = ctx.getResources().getDisplayMetrics().densityDpi;
-        mContext = nContextCreateGL(mDev, 0, sdkVersion,
+        mContext = nContextCreateGL(device, 0, sdkVersion,
                                     mSurfaceConfig.mColorMin, mSurfaceConfig.mColorPref,
                                     mSurfaceConfig.mAlphaMin, mSurfaceConfig.mAlphaPref,
                                     mSurfaceConfig.mDepthMin, mSurfaceConfig.mDepthPref,
diff --git a/rs/java/android/renderscript/Sampler.java b/rs/java/android/renderscript/Sampler.java
index a4edbb5..5c4bae9 100644
--- a/rs/java/android/renderscript/Sampler.java
+++ b/rs/java/android/renderscript/Sampler.java
@@ -51,6 +51,7 @@
 
     Sampler(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index 2b06780..fc3280b 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -41,6 +41,7 @@
             mScript = s;
             mSlot = slot;
             mSig = sig;
+            guard.open("destroy");
         }
     }
 
@@ -118,6 +119,7 @@
             super(id, rs);
             mScript = s;
             mSlot = slot;
+            guard.open("destroy");
         }
     }
 
@@ -357,6 +359,19 @@
         super(id, rs);
 
         mInIdsBuffer = new long[1];
+
+        /* The constructors for the derived classes (including ScriptIntrinsic
+         * derived classes and ScriptC derived classes generated by Slang
+         * reflection) seem to be simple enough, so we just put the guard.open()
+         * call here, rather than in the end of the constructor for the derived
+         * class. This, of course, assumes the derived constructor would not
+         * throw any exception after calling this constructor.
+         *
+         * If new derived classes are added with more complicated constructors
+         * that throw exceptions, this call has to be (duplicated and) moved
+         * to the end of each derived class constructor.
+         */
+        guard.open("destroy");
     }
 
     /**
@@ -541,21 +556,22 @@
 
     /**
      * Class for specifying the specifics about how a kernel will be
-     * launched
+     * launched.
      *
      * This class can specify a potential range of cells on which to
      * run a kernel.  If no set is called for a dimension then this
      * class will have no impact on that dimension when the kernel
      * is executed.
      *
-     * The forEach launch will operate over the intersection of the
-     * dimensions.
+     * The forEach kernel launch will operate over the intersection of
+     * the dimensions.
      *
      * Example:
      * LaunchOptions with setX(5, 15)
      * Allocation with dimension X=10, Y=10
-     * The resulting forEach run would execute over x = 5 to 10 and
-     * y = 0 to 10.
+     * The resulting forEach run would execute over:
+     * x = 5 to 9 (inclusive) and
+     * y = 0 to 9 (inclusive).
      *
      *
      */
@@ -569,11 +585,11 @@
         private int strategy;
 
         /**
-         * Set the X range.  If the end value is set to 0 the X dimension is not
-         * clipped.
+         * Set the X range. xstartArg is the lowest coordinate of the range,
+         * and xendArg-1 is the highest coordinate of the range.
          *
          * @param xstartArg Must be >= 0
-         * @param xendArg Must be >= xstartArg
+         * @param xendArg Must be > xstartArg
          *
          * @return LaunchOptions
          */
@@ -587,11 +603,11 @@
         }
 
         /**
-         * Set the Y range.  If the end value is set to 0 the Y dimension is not
-         * clipped.
+         * Set the Y range. ystartArg is the lowest coordinate of the range,
+         * and yendArg-1 is the highest coordinate of the range.
          *
          * @param ystartArg Must be >= 0
-         * @param yendArg Must be >= ystartArg
+         * @param yendArg Must be > ystartArg
          *
          * @return LaunchOptions
          */
@@ -605,11 +621,11 @@
         }
 
         /**
-         * Set the Z range.  If the end value is set to 0 the Z dimension is not
-         * clipped.
+         * Set the Z range. zstartArg is the lowest coordinate of the range,
+         * and zendArg-1 is the highest coordinate of the range.
          *
          * @param zstartArg Must be >= 0
-         * @param zendArg Must be >= zstartArg
+         * @param zendArg Must be > zstartArg
          *
          * @return LaunchOptions
          */
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index bf706c1..00ebe57 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -84,13 +84,6 @@
         setID(id);
     }
 
-    /**
-     * Name of the file that holds the object cache.
-     */
-    private static final String CACHE_PATH = "com.android.renderscript.cache";
-
-    static String mCachePath;
-
     private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
         byte[] pgm;
         int pgmLength;
@@ -122,26 +115,12 @@
 
         String resName = resources.getResourceEntryName(resourceID);
 
-        // Create the RS cache path if we haven't done so already.
-        if (mCachePath == null) {
-            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
-            mCachePath = f.getAbsolutePath();
-            f.mkdirs();
-        }
         //        Log.v(TAG, "Create script for resource = " + resName);
-        return rs.nScriptCCreate(resName, mCachePath, pgm, pgmLength);
+        return rs.nScriptCCreate(resName, RenderScript.getCachePath(), pgm, pgmLength);
     }
 
     private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
-        // Create the RS cache path if we haven't done so already.
-        if (mCachePath == null) {
-            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
-            mCachePath = f.getAbsolutePath();
-            f.mkdirs();
-        }
         //        Log.v(TAG, "Create script for resource = " + resName);
-        return rs.nScriptCCreate(resName, mCachePath, bitcode, bitcode.length);
+        return rs.nScriptCCreate(resName, RenderScript.getCachePath(), bitcode, bitcode.length);
     }
-
-
 }
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 9bbacbc..219f16b 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -148,6 +148,8 @@
                                         fieldIDs, values, sizes, depClosures, depFieldIDs);
 
             setID(id);
+
+            guard.open("destroy");
         }
 
         Closure(RenderScript rs, Script.InvokeID invokeID,
@@ -181,6 +183,8 @@
                                               values, sizes);
 
             setID(id);
+
+            guard.open("destroy");
         }
 
         private void retrieveValueAndDependenceInfo(RenderScript rs,
@@ -382,6 +386,7 @@
 
     ScriptGroup(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     ScriptGroup(RenderScript rs, String name, List<Closure> closures,
@@ -396,8 +401,9 @@
         for (int i = 0; i < closureIDs.length; i++) {
             closureIDs[i] = closures.get(i).getID(rs);
         }
-        long id = rs.nScriptGroup2Create(name, ScriptC.mCachePath, closureIDs);
+        long id = rs.nScriptGroup2Create(name, RenderScript.getCachePath(), closureIDs);
         setID(id);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
index 76da781..339e0e9 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -32,10 +32,9 @@
      * Supported elements types are {@link Element#U8}, {@link
      * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
      * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, and {@link Element#F32_4}
+     * Element#F32_3}, and {@link Element#F32_4}.
      *
-     * The default coefficients are.
-     *
+     * <p> The default coefficients are:
      * <code>
      * <p> [ 0,  0,  0 ]
      * <p> [ 0,  1,  0 ]
@@ -67,7 +66,7 @@
     }
 
     /**
-     * Set the input of the blur.
+     * Set the input of the 3x3 convolve.
      * Must match the element type supplied during create.
      *
      * @param ain The input allocation.
@@ -80,7 +79,7 @@
     /**
      * Set the coefficients for the convolve.
      *
-     * The convolve layout is
+     * <p> The convolve layout is:
      * <code>
      * <p> [ 0,  1,  2 ]
      * <p> [ 3,  4,  5 ]
diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
index 2d37600..a288cee 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
@@ -32,9 +32,9 @@
      * Supported elements types are {@link Element#U8}, {@link
      * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
      * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, and {@link Element#F32_4}
+     * Element#F32_3}, and {@link Element#F32_4}.
      *
-     * The default coefficients are.
+     * <p> The default coefficients are:
      * <code>
      * <p> [ 0,  0,  0,  0,  0  ]
      * <p> [ 0,  0,  0,  0,  0  ]
@@ -66,7 +66,7 @@
     }
 
     /**
-     * Set the input of the blur.
+     * Set the input of the 5x5 convolve.
      * Must match the element type supplied during create.
      *
      * @param ain The input allocation.
@@ -79,7 +79,7 @@
     /**
     * Set the coefficients for the convolve.
     *
-    * The convolve layout is
+    * <p> The convolve layout is:
     * <code>
     * <p> [ 0,  1,  2,  3,  4  ]
     * <p> [ 5,  6,  7,  8,  9  ]
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index dc23785..9252898 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -227,6 +227,7 @@
 
     Type(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     @Override
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 3bef19e..e0f5934 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -151,6 +151,7 @@
         return;                                                                         \
     case RS_TYPE_SIGNED_16:                                                             \
     case RS_TYPE_UNSIGNED_16:                                                           \
+    case RS_TYPE_FLOAT_16:                                                              \
         len = _env->GetArrayLength((jshortArray)data);                                  \
         ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
         if (ptr == nullptr) {                                                           \
@@ -2070,6 +2071,8 @@
         sc.array4End = 0;
 
         sca = &sc;
+        // sc_size is required, but unused, by the runtime and drivers.
+        sc_size = sizeof(sc);
     }
 
     rsScriptForEachMulti((RsContext)con, (RsScript)script, slot,
diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk
index d98fc28..ce89aa7 100644
--- a/services/accessibility/Android.mk
+++ b/services/accessibility/Android.mk
@@ -7,4 +7,6 @@
 LOCAL_SRC_FILES += \
       $(call all-java-files-under,java)
 
+LOCAL_JAVA_LIBRARIES := services.core
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index ad70853..562d950 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -37,7 +37,8 @@
 
 /**
  * This class handles gesture detection for the Touch Explorer.  It collects
- * touch events, and sends events to mListener as gestures are recognized.
+ * touch events and determines when they match a gesture, as well as when they
+ * won't match a gesture.  These state changes are then surfaced to mListener.
  */
 class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListener {
 
@@ -46,12 +47,58 @@
     // Tag for logging received events.
     private static final String LOG_TAG = "AccessibilityGestureDetector";
 
+    /**
+     * Listener functions are called as a result of onMoveEvent().  The current
+     * MotionEvent in the context of these functions is the event passed into
+     * onMotionEvent.
+     */
     public interface Listener {
-        public void onDoubleTapAndHold(MotionEvent event, int policyFlags);
-        public boolean onDoubleTap(MotionEvent event, int policyFlags);
-        public boolean onGestureCompleted(int gestureId);
-        public void onGestureStarted();
-        public void onGestureCancelled(MotionEvent event, int policyFlags);
+        /**
+         * Called when the user has performed a double tap and then held down
+         * the second tap.
+         *
+         * @param event The most recent MotionEvent received.
+         * @param policyFlags The policy flags of the most recent event.
+         */
+        void onDoubleTapAndHold(MotionEvent event, int policyFlags);
+
+        /**
+         * Called when the user lifts their finger on the second tap of a double
+         * tap.
+         *
+         * @param event The most recent MotionEvent received.
+         * @param policyFlags The policy flags of the most recent event.
+         *
+         * @return true if the event is consumed, else false
+         */
+        boolean onDoubleTap(MotionEvent event, int policyFlags);
+
+        /**
+         * Called when the system has decided the event stream is a gesture.
+         *
+         * @return true if the event is consumed, else false
+         */
+        boolean onGestureStarted();
+
+        /**
+         * Called when an event stream is recognized as a gesture.
+         *
+         * @param gestureId ID of the gesture that was recognized.
+         *
+         * @return true if the event is consumed, else false
+         */
+        boolean onGestureCompleted(int gestureId);
+
+        /**
+         * Called when the system has decided an event stream doesn't match any
+         * known gesture.
+         *
+         * @param event The most recent MotionEvent received.
+         * @param policyFlags The policy flags of the most recent event.
+         *
+         * @return true if the event is consumed, else false
+         */
+        public boolean onGestureCancelled(MotionEvent event, int policyFlags);
     }
 
     private final Listener mListener;
@@ -121,9 +168,9 @@
     // movement when gesturing, and touch exploring.  Based on user testing,
     // all gestures started with the initial movement taking less than 100ms.
     // When touch exploring, the first movement almost always takes longer than
-    // 200ms.  From this data, 150ms seems the best value to decide what
+    // 200ms.  From this data, 200ms seems the best value to decide what
     // kind of interaction it is.
-    private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+    private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 200;
 
     // Time threshold used to determine if a gesture should be cancelled.  If
     // the finger pauses for longer than this delay, the ongoing gesture is
@@ -145,6 +192,18 @@
                 context.getResources().getDisplayMetrics()) * GESTURE_CONFIRM_MM;
     }
 
+    /**
+     * Handle a motion event.  If an action is completed, the appropriate
+     * callback on mListener is called, and the return value of the callback is
+     * passed to the caller.
+     *
+     * @param event The raw motion event.  It's important that this be the raw
+     * event, before any transformations have been applied, so that measurements
+     * can be made in physical units.
+     * @param policyFlags Policy flags for the event.
+     *
+     * @return true if the event is consumed, else false
+     */
     public boolean onMotionEvent(MotionEvent event, int policyFlags) {
         final float x = event.getX();
         final float y = event.getY();
@@ -179,13 +238,20 @@
                         mBaseY = y;
                         mBaseTime = time;
 
+                        // Since the pointer has moved, this is not a double
+                        // tap.
+                        mFirstTapDetected = false;
+                        mDoubleTapDetected = false;
+
                         // If this hasn't been confirmed as a gesture yet, send
                         // the event.
                         if (!mGestureStarted) {
                             mGestureStarted = true;
-                            mListener.onGestureStarted();
+                            return mListener.onGestureStarted();
                         }
-                    } else {
+                    } else if (!mFirstTapDetected) {
+                        // The finger may not move if they are double tapping.
+                        // In that case, we shouldn't cancel the gesture.
                         final long timeDelta = time - mBaseTime;
                         final long threshold = mGestureStarted ?
                             CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS :
@@ -195,8 +261,7 @@
                         // timeout, cancel gesture detection.
                         if (timeDelta > threshold) {
                             cancelGesture();
-                            mListener.onGestureCancelled(event, policyFlags);
-                            return false;
+                            return mListener.onGestureCancelled(event, policyFlags);
                         }
                     }
 
@@ -211,16 +276,13 @@
                 break;
 
             case MotionEvent.ACTION_UP:
-                if (maybeFinishDoubleTap(event, policyFlags)) {
-                    return true;
+                if (mDoubleTapDetected) {
+                    return finishDoubleTap(event, policyFlags);
                 }
                 if (mGestureStarted) {
                     mStrokeBuffer.add(new GesturePoint(x, y, time));
 
-                    if (!recognizeGesture()) {
-                        mListener.onGestureCancelled(event, policyFlags);
-                    }
-                    return true;
+                    return recognizeGesture(event, policyFlags);
                 }
                 break;
 
@@ -244,8 +306,8 @@
             case MotionEvent.ACTION_POINTER_UP:
                 // If we're detecting taps on the second finger, see if we
                 // should finish the double tap.
-                if (mSecondFingerDoubleTap && maybeFinishDoubleTap(event, policyFlags)) {
-                    return true;
+                if (mSecondFingerDoubleTap && mDoubleTapDetected) {
+                    return finishDoubleTap(event, policyFlags);
                 }
                 break;
 
@@ -308,7 +370,7 @@
         // The processing of the double tap is deferred until the finger is
         // lifted, so that we can detect a long press on the second tap.
         mDoubleTapDetected = true;
-        return true;
+        return false;
     }
 
     private void maybeSendLongPress(MotionEvent event, int policyFlags) {
@@ -321,11 +383,7 @@
         mListener.onDoubleTapAndHold(event, policyFlags);
     }
 
-    private boolean maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
-        if (!mDoubleTapDetected) {
-            return false;
-        }
-
+    private boolean finishDoubleTap(MotionEvent event, int policyFlags) {
         clear();
 
         return mListener.onDoubleTap(event, policyFlags);
@@ -337,7 +395,7 @@
         mStrokeBuffer.clear();
     }
 
-    private boolean recognizeGesture() {
+    private boolean recognizeGesture(MotionEvent event, int policyFlags) {
         Gesture gesture = new Gesture();
         gesture.addStroke(new GestureStroke(mStrokeBuffer));
 
@@ -351,16 +409,14 @@
                 }
                 try {
                     final int gestureId = Integer.parseInt(bestPrediction.name);
-                    if (mListener.onGestureCompleted(gestureId)) {
-                        return true;
-                    }
+                    return mListener.onGestureCompleted(gestureId);
                 } catch (NumberFormatException nfe) {
                     Slog.w(LOG_TAG, "Non numeric gesture id:" + bestPrediction.name);
                 }
             }
         }
 
-        return false;
+        return mListener.onGestureCancelled(event, policyFlags);
     }
 
     private MotionEvent mapSecondPointerToFirstPointer(MotionEvent event) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 388c8b7..2741733 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -56,6 +56,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -94,6 +95,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.server.LocalServices;
 
+import com.android.server.statusbar.StatusBarManagerInternal;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.FileDescriptor;
@@ -173,6 +175,8 @@
 
     private final PackageManager mPackageManager;
 
+    private final PowerManager mPowerManager;
+
     private final WindowManagerInternal mWindowManagerService;
 
     private final SecurityPolicy mSecurityPolicy;
@@ -231,6 +235,7 @@
     public AccessibilityManagerService(Context context) {
         mContext = context;
         mPackageManager = mContext.getPackageManager();
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
@@ -351,6 +356,7 @@
         // user change and unlock
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
         intentFilter.addAction(Intent.ACTION_USER_PRESENT);
         intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
@@ -361,6 +367,8 @@
                 String action = intent.getAction();
                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                    unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                     removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
@@ -651,10 +659,9 @@
             userState.mUiAutomationServiceOwner = owner;
             userState.mUiAutomationServiceClient = serviceClient;
             userState.mUiAutomationFlags = flags;
-            userState.mIsAccessibilityEnabled = true;
             userState.mInstalledServices.add(accessibilityServiceInfo);
             if ((flags & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0) {
-                // Set the temporary state.
+                // Set the temporary state, and use it instead of settings
                 userState.mIsTouchExplorationEnabled = false;
                 userState.mIsEnhancedWebAccessibilityEnabled = false;
                 userState.mIsDisplayMagnificationEnabled = false;
@@ -705,7 +712,6 @@
                 return;
             }
 
-            userState.mIsAccessibilityEnabled = true;
             userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
             userState.mIsEnhancedWebAccessibilityEnabled = false;
             userState.mIsDisplayMagnificationEnabled = false;
@@ -900,6 +906,13 @@
         }
     }
 
+    private void unlockUser(int userId) {
+        synchronized (mLock) {
+            UserState userState = getUserStateLocked(userId);
+            onUserStateChangedLocked(userState);
+        }
+    }
+
     private void removeUser(int userId) {
         synchronized (mLock) {
             mUserStates.remove(userId);
@@ -1002,8 +1015,10 @@
         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
                 new Intent(AccessibilityService.SERVICE_INTERFACE),
                 PackageManager.GET_SERVICES
-                  | PackageManager.GET_META_DATA
-                  | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+                        | PackageManager.GET_META_DATA
+                        | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 mCurrentUserId);
 
         for (int i = 0, count = installedServices.size(); i < count; i++) {
@@ -1233,56 +1248,44 @@
         }
     }
 
-    private void manageServicesLocked(UserState userState) {
+    private void updateServicesLocked(UserState userState) {
         Map<ComponentName, Service> componentNameToServiceMap =
                 userState.mComponentNameToServiceMap;
-        boolean isEnabled = userState.mIsAccessibilityEnabled;
+        boolean isUnlocked = mContext.getSystemService(UserManager.class)
+                .isUserUnlocked(userState.mUserId);
 
         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
             ComponentName componentName = ComponentName.unflattenFromString(
                     installedService.getId());
+
             Service service = componentNameToServiceMap.get(componentName);
 
-            if (isEnabled) {
-                // Wait for the binding if it is in process.
-                if (userState.mBindingServices.contains(componentName)) {
+            // Ignore non-encryption-aware services until user is unlocked
+            if (!isUnlocked && !installedService.isDirectBootAware()) {
+                Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
+                continue;
+            }
+
+            // Wait for the binding if it is in process.
+            if (userState.mBindingServices.contains(componentName)) {
+                continue;
+            }
+            if (userState.mEnabledServices.contains(componentName)) {
+                if (service == null) {
+                    service = new Service(userState.mUserId, componentName, installedService);
+                } else if (userState.mBoundServices.contains(service)) {
                     continue;
                 }
-                if (userState.mEnabledServices.contains(componentName)) {
-                    if (service == null) {
-                        service = new Service(userState.mUserId, componentName, installedService);
-                    } else if (userState.mBoundServices.contains(service)) {
-                        continue;
-                    }
-                    service.bindLocked();
-                } else {
-                    if (service != null) {
-                        service.unbindLocked();
-                    }
-                }
+                service.bindLocked();
             } else {
                 if (service != null) {
                     service.unbindLocked();
-                } else {
-                    userState.mBindingServices.remove(componentName);
                 }
             }
         }
 
-        // No enabled installed services => disable accessibility to avoid
-        // sending accessibility events with no recipient across processes.
-        if (isEnabled && userState.mBoundServices.isEmpty()
-                && userState.mBindingServices.isEmpty()) {
-            userState.mIsAccessibilityEnabled = false;
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
+        updateAccessibilityEnabledSetting(userState);
     }
 
     private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
@@ -1309,7 +1312,8 @@
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
             }
             // Touch exploration without accessibility makes no sense.
-            if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
+            if (userState.isHandlingAccessibilityEvents()
+                    && userState.mIsTouchExplorationEnabled) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
             }
             if (userState.mIsFilterKeyEventsEnabled) {
@@ -1448,25 +1452,17 @@
     }
 
     private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
-        if (userState.mIsAccessibilityEnabled) {
-            // We observe windows for accessibility only if there is at least
-            // one bound service that can retrieve window content that specified
-            // it is interested in accessing such windows. For services that are
-            // binding we do an update pass after each bind event, so we run this
-            // code and register the callback if needed.
-            boolean boundServiceCanRetrieveInteractiveWindows = false;
+        // We observe windows for accessibility only if there is at least
+        // one bound service that can retrieve window content that specified
+        // it is interested in accessing such windows. For services that are
+        // binding we do an update pass after each bind event, so we run this
+        // code and register the callback if needed.
 
-            List<Service> boundServices = userState.mBoundServices;
-            final int boundServiceCount = boundServices.size();
-            for (int i = 0; i < boundServiceCount; i++) {
-                Service boundService = boundServices.get(i);
-                if (boundService.canRetrieveInteractiveWindowsLocked()) {
-                    boundServiceCanRetrieveInteractiveWindows = true;
-                    break;
-                }
-            }
-
-            if (boundServiceCanRetrieveInteractiveWindows) {
+        List<Service> boundServices = userState.mBoundServices;
+        final int boundServiceCount = boundServices.size();
+        for (int i = 0; i < boundServiceCount; i++) {
+            Service boundService = boundServices.get(i);
+            if (boundService.canRetrieveInteractiveWindowsLocked()) {
                 if (mWindowsForAccessibilityCallback == null) {
                     mWindowsForAccessibilityCallback = new WindowsForAccessibilityCallback();
                     mWindowManagerService.setWindowsForAccessibilityCallback(
@@ -1534,37 +1530,30 @@
         userState.mIsFilterKeyEventsEnabled = false;
     }
 
-    private void updateServicesLocked(UserState userState) {
-        if (userState.mIsAccessibilityEnabled) {
-            manageServicesLocked(userState);
-        } else {
-            unbindAllServicesLocked(userState);
-        }
-    }
-
     private boolean readConfigurationForUserStateLocked(UserState userState) {
-        boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState);
-        somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
-        somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
-        somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
-        somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
-        somthingChanged |= readHighTextContrastEnabledSettingLocked(userState);
-        somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
-        somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
-        somthingChanged |= readAutoclickEnabledSettingLocked(userState);
-        somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
-        return somthingChanged;
+        boolean somethingChanged = readInstalledAccessibilityServiceLocked(userState);
+        somethingChanged |= readEnabledAccessibilityServicesLocked(userState);
+        somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
+        somethingChanged |= readTouchExplorationEnabledSettingLocked(userState);
+        somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
+        somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
+        somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+        somethingChanged |= readAutoclickEnabledSettingLocked(userState);
+        somethingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
+
+        return somethingChanged;
     }
 
-    private boolean readAccessibilityEnabledSettingLocked(UserState userState) {
-        final boolean accessibilityEnabled = Settings.Secure.getIntForUser(
-               mContext.getContentResolver(),
-               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
-        if (accessibilityEnabled != userState.mIsAccessibilityEnabled) {
-            userState.mIsAccessibilityEnabled = accessibilityEnabled;
-            return true;
+    private void updateAccessibilityEnabledSetting(UserState userState) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_ENABLED,
+                    userState.isHandlingAccessibilityEvents() ? 1 : 0,
+                    userState.mUserId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
-        return false;
     }
 
     private boolean readTouchExplorationEnabledSettingLocked(UserState userState) {
@@ -1748,14 +1737,14 @@
     private void updateMagnificationLocked(UserState userState) {
         final int userId = userState.mUserId;
         if (userId == mCurrentUserId && mMagnificationController != null) {
-            if (userHasMagnificationServicesLocked(userState)) {
+            if (userState.mIsDisplayMagnificationEnabled ||
+                    userHasMagnificationServicesLocked(userState)) {
                 mMagnificationController.setUserId(userState.mUserId);
             } else {
                 // If the user no longer has any magnification-controlling
                 // services and is not using magnification gestures, then
                 // reset the state to normal.
-                if (!userState.mIsDisplayMagnificationEnabled
-                        && mMagnificationController.resetIfNeeded(true)) {
+                if (mMagnificationController.resetIfNeeded(true)) {
                     // Animations are still running, so wait until we receive a
                     // callback verifying that we've reset magnification.
                     mUnregisterMagnificationOnReset = true;
@@ -1785,17 +1774,27 @@
 
     private void updateSoftKeyboardShowModeLocked(UserState userState) {
         final int userId = userState.mUserId;
-        if (userId == mCurrentUserId) {
-            // Check whether any Accessibility Services are still enabled and, if not, remove flag
-            // requesting no soft keyboard
-            final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
-            if (accessibilityRequestingNoIme && !userState.mIsAccessibilityEnabled) {
-                // No active Accessibility Services can be requesting the soft keyboard to be hidden
-                Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
-                        0,
-                        userState.mUserId);
+        // Only check whether we need to reset the soft keyboard mode if it is not set to the
+        // default.
+        if ((userId == mCurrentUserId) && (userState.mSoftKeyboardShowMode != 0)) {
+            // Check whether the last Accessibility Service that changed the soft keyboard mode to
+            // something other than the default is still enabled and, if not, remove flag and
+            // reset to the default soft keyboard behavior.
+            boolean serviceChangingSoftKeyboardModeIsEnabled =
+                    userState.mEnabledServices.contains(userState.mServiceChangingSoftKeyboardMode);
+
+            if (!serviceChangingSoftKeyboardModeIsEnabled) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+                            0,
+                            userState.mUserId);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
                 userState.mSoftKeyboardShowMode = 0;
+                userState.mServiceChangingSoftKeyboardMode = null;
             }
 
             notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
@@ -1817,11 +1816,93 @@
     private KeyEventDispatcher getKeyEventDispatcher() {
         if (mKeyEventDispatcher == null) {
             mKeyEventDispatcher = new KeyEventDispatcher(
-                    mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock);
+                    mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock,
+                    mPowerManager);
         }
         return mKeyEventDispatcher;
     }
 
+    /**
+     * Enables accessibility service specified by {@param componentName} for the {@param userId}.
+     */
+    public void enableAccessibilityService(ComponentName componentName, int userId) {
+        synchronized(mLock) {
+            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                throw new SecurityException("only SYSTEM can call enableAccessibilityService.");
+            }
+
+            SettingsStringHelper settingsHelper = new SettingsStringHelper(
+                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+            settingsHelper.addService(componentName);
+            settingsHelper.writeToSettings();
+
+            UserState userState = getUserStateLocked(userId);
+            if (userState.mEnabledServices.add(componentName)) {
+                onUserStateChangedLocked(userState);
+            }
+        }
+    }
+
+    /**
+     * Disables accessibility service specified by {@param componentName} for the {@param userId}.
+     */
+    public void disableAccessibilityService(ComponentName componentName, int userId) {
+        synchronized(mLock) {
+            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                throw new SecurityException("only SYSTEM can call disableAccessibility");
+            }
+
+            SettingsStringHelper settingsHelper = new SettingsStringHelper(
+                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+            settingsHelper.deleteService(componentName);
+            settingsHelper.writeToSettings();
+
+            UserState userState = getUserStateLocked(userId);
+            if (userState.mEnabledServices.remove(componentName)) {
+                onUserStateChangedLocked(userState);
+            }
+        }
+    }
+
+    private class SettingsStringHelper {
+        private static final String SETTINGS_DELIMITER = ":";
+        private ContentResolver mContentResolver;
+        private final String mSettingsName;
+        private Set<String> mServices;
+        private final int mUserId;
+
+        public SettingsStringHelper(String name, int userId) {
+            mUserId = userId;
+            mSettingsName = name;
+            mContentResolver = mContext.getContentResolver();
+            String servicesString = Settings.Secure.getStringForUser(
+                    mContentResolver, mSettingsName, userId);
+            mServices = new HashSet();
+            if (!TextUtils.isEmpty(servicesString)) {
+                final TextUtils.SimpleStringSplitter colonSplitter =
+                        new TextUtils.SimpleStringSplitter(SETTINGS_DELIMITER.charAt(0));
+                colonSplitter.setString(servicesString);
+                while (colonSplitter.hasNext()) {
+                    final String serviceName = colonSplitter.next();
+                    mServices.add(serviceName);
+                }
+            }
+        }
+
+        public void addService(ComponentName component) {
+            mServices.add(component.flattenToString());
+        }
+
+        public void deleteService(ComponentName component) {
+            mServices.remove(component.flattenToString());
+        }
+
+        public void writeToSettings() {
+            Settings.Secure.putStringForUser(mContentResolver, mSettingsName,
+                    TextUtils.join(SETTINGS_DELIMITER, mServices), mUserId);
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
@@ -1833,7 +1914,6 @@
                 UserState userState = mUserStates.valueAt(i);
                 pw.append("User state[attributes:{id=" + userState.mUserId);
                 pw.append(", currentUser=" + (userState.mUserId == mCurrentUserId));
-                pw.append(", accessibilityEnabled=" + userState.mIsAccessibilityEnabled);
                 pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
                 pw.append(", displayMagnificationEnabled="
                         + userState.mIsDisplayMagnificationEnabled);
@@ -1983,7 +2063,7 @@
         private void announceNewUserIfNeeded() {
             synchronized (mLock) {
                 UserState userState = getCurrentUserStateLocked();
-                if (userState.mIsAccessibilityEnabled) {
+                if (userState.isHandlingAccessibilityEvents()) {
                     UserManager userManager = (UserManager) mContext.getSystemService(
                             Context.USER_SERVICE);
                     String message = mContext.getString(R.string.user_switched,
@@ -2071,7 +2151,7 @@
     MagnificationController getMagnificationController() {
         synchronized (mLock) {
             if (mMagnificationController == null) {
-                mMagnificationController = new MagnificationController(mContext, this);
+                mMagnificationController = new MagnificationController(mContext, this, mLock);
                 mMagnificationController.register();
                 mMagnificationController.setUserId(mCurrentUserId);
             }
@@ -2719,6 +2799,11 @@
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
+                // Regardless of whether or not the action succeeds, it was generated by an
+                // accessibility service that is driven by user actions, so note user activity.
+                mPowerManager.userActivity(SystemClock.uptimeMillis(),
+                        PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
+
                 connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
                         interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
@@ -2740,6 +2825,8 @@
             }
             final long identity = Binder.clearCallingIdentity();
             try {
+                mPowerManager.userActivity(SystemClock.uptimeMillis(),
+                        PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
                 switch (action) {
                     case AccessibilityService.GLOBAL_ACTION_BACK: {
                         sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
@@ -2759,6 +2846,9 @@
                     case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: {
                         showGlobalActions();
                     } return true;
+                    case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN: {
+                        toggleSplitScreen();
+                    } return true;
                 }
                 return false;
             } finally {
@@ -2886,6 +2976,14 @@
 
             final long identity = Binder.clearCallingIdentity();
             try {
+                // Keep track of the last service to request a non-default show mode. The show mode
+                // should be restored to default should this service be disabled.
+                if (showMode == Settings.Secure.SHOW_MODE_AUTO) {
+                    userState.mServiceChangingSoftKeyboardMode = null;
+                } else {
+                    userState.mServiceChangingSoftKeyboardMode = mComponentName;
+                }
+
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
                         Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, showMode,
                         userState.mUserId);
@@ -3230,6 +3328,10 @@
             mWindowManagerService.showGlobalActions();
         }
 
+        private void toggleSplitScreen() {
+            LocalServices.getService(StatusBarManagerInternal.class).toggleSplitScreen();
+        }
+
         private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
@@ -3394,6 +3496,8 @@
             reportedWindow.setLayer(window.layer);
             reportedWindow.setFocused(window.focused);
             reportedWindow.setBoundsInScreen(window.boundsInScreen);
+            reportedWindow.setTitle(window.title);
+            reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
 
             final int parentId = findWindowIdLocked(window.parentToken);
             if (parentId >= 0) {
@@ -3447,10 +3551,14 @@
                 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
-                case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
+                case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
                     return AccessibilityWindowInfo.TYPE_SYSTEM;
                 }
 
+                case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
+                    return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER;
+                }
+
                 case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: {
                     return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
                 }
@@ -4027,11 +4135,12 @@
         public final Set<ComponentName> mTouchExplorationGrantedServices =
                 new HashSet<>();
 
+        public ComponentName mServiceChangingSoftKeyboardMode;
+
         public int mLastSentClientState = -1;
 
         public int mSoftKeyboardShowMode = 0;
 
-        public boolean mIsAccessibilityEnabled;
         public boolean mIsTouchExplorationEnabled;
         public boolean mIsTextHighContrastEnabled;
         public boolean mIsEnhancedWebAccessibilityEnabled;
@@ -4066,11 +4175,11 @@
 
         public int getClientState() {
             int clientState = 0;
-            if (mIsAccessibilityEnabled) {
+            if (isHandlingAccessibilityEvents()) {
                 clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
             }
             // Touch exploration relies on enabled accessibility.
-            if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
+            if (isHandlingAccessibilityEvents() && mIsTouchExplorationEnabled) {
                 clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
             }
             if (mIsTextHighContrastEnabled) {
@@ -4079,6 +4188,10 @@
             return clientState;
         }
 
+        public boolean isHandlingAccessibilityEvents() {
+            return !mBoundServices.isEmpty() || !mBindingServices.isEmpty();
+        }
+
         public void onSwitchToAnotherUser() {
             // Clear UI test automation state.
             if (mUiAutomationService != null) {
@@ -4098,7 +4211,6 @@
             // Clear state persisted in settings.
             mEnabledServices.clear();
             mTouchExplorationGrantedServices.clear();
-            mIsAccessibilityEnabled = false;
             mIsTouchExplorationEnabled = false;
             mIsEnhancedWebAccessibilityEnabled = false;
             mIsDisplayMagnificationEnabled = false;
@@ -4125,9 +4237,6 @@
 
     private final class AccessibilityContentObserver extends ContentObserver {
 
-        private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_ENABLED);
-
         private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
                 Settings.Secure.TOUCH_EXPLORATION_ENABLED);
 
@@ -4169,8 +4278,6 @@
         }
 
         public void register(ContentResolver contentResolver) {
-            contentResolver.registerContentObserver(mAccessibilityEnabledUri,
-                    false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
@@ -4210,11 +4317,7 @@
                     return;
                 }
 
-                if (mAccessibilityEnabledUri.equals(uri)) {
-                    if (readAccessibilityEnabledSettingLocked(userState)) {
-                        onUserStateChangedLocked(userState);
-                    }
-                } else if (mTouchExplorationEnabledUri.equals(uri)) {
+                if (mTouchExplorationEnabledUri.equals(uri)) {
                     if (readTouchExplorationEnabledSettingLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
diff --git a/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java
index 3469565..e03c16e 100644
--- a/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/KeyEventDispatcher.java
@@ -17,8 +17,10 @@
 package com.android.server.accessibility;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Pools;
@@ -69,6 +71,7 @@
     private final Handler mHandlerToSendKeyEventsToInputFilter;
     private final int mMessageTypeForSendKeyEvent;
     private final Handler mKeyEventTimeoutHandler;
+    private final PowerManager mPowerManager;
 
     /**
      * @param handlerToSendKeyEventsToInputFilter The handler to which to post {@code KeyEvent}s
@@ -77,9 +80,12 @@
      * message that carries a {@code KeyEvent} to be sent to the input filter
      * @param lock The lock used for all synchronization in this package. This lock must be held
      * when calling {@code notifyKeyEventLocked}
+     * @param powerManager The power manager to alert to user activity if a KeyEvent is processed
+     * by a service
      */
     public KeyEventDispatcher(Handler handlerToSendKeyEventsToInputFilter,
-                              int messageTypeForSendKeyEvent, Object lock) {
+            int messageTypeForSendKeyEvent, Object lock,
+            PowerManager powerManager) {
         if (InputEventConsistencyVerifier.isInstrumentationEnabled()) {
             mSentEventsVerifier = new InputEventConsistencyVerifier(
                     this, 0, KeyEventDispatcher.class.getSimpleName());
@@ -91,6 +97,7 @@
         mKeyEventTimeoutHandler =
                 new Handler(mHandlerToSendKeyEventsToInputFilter.getLooper(), new Callback());
         mLock = lock;
+        mPowerManager = powerManager;
     }
 
     /**
@@ -165,7 +172,16 @@
             PendingKeyEvent pendingEvent =
                     removeEventFromListLocked(mPendingEventsMap.get(service), sequence);
             if (pendingEvent != null) {
-                pendingEvent.handled |= handled;
+                if (handled && !pendingEvent.handled) {
+                    pendingEvent.handled = handled;
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        mPowerManager.userActivity(pendingEvent.event.getEventTime(),
+                                PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                }
                 removeReferenceToPendingEventLocked(pendingEvent);
             }
         }
@@ -241,7 +257,7 @@
             int policyFlags = pendingEvent.policyFlags | WindowManagerPolicy.FLAG_PASS_TO_USER;
             mHandlerToSendKeyEventsToInputFilter
                     .obtainMessage(mMessageTypeForSendKeyEvent, policyFlags, 0, pendingEvent.event)
-                            .sendToTarget();
+                    .sendToTarget();
         } else {
             pendingEvent.event.recycle();
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index a093d92..b2196bf 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -72,7 +72,7 @@
      */
     private static final float MIN_PERSISTED_SCALE = 2.0f;
 
-    private final Object mLock = new Object();
+    private final Object mLock;
 
     /**
      * The current magnification spec. If an animation is running, this
@@ -97,12 +97,13 @@
 
     private int mUserId;
 
-    public MagnificationController(Context context, AccessibilityManagerService ams) {
+    public MagnificationController(Context context, AccessibilityManagerService ams, Object lock) {
         mAms = ams;
         mContentResolver = context.getContentResolver();
         mScreenStateObserver = new ScreenStateObserver(context, this);
         mWindowStateObserver = new WindowStateObserver(context, this);
         mSpecAnimationBridge = new SpecAnimationBridge(context);
+        mLock = lock;
     }
 
     /**
@@ -111,12 +112,18 @@
     public void register() {
         mScreenStateObserver.register();
         mWindowStateObserver.register();
+
+        // Obtain initial state.
+        mWindowStateObserver.getRegions(mMagnifiedRegion, mAvailableRegion);
+        mMagnifiedRegion.getBounds(mMagnifiedBounds);
     }
 
     /**
      * Unregisters magnification-related observers.
      */
     public void unregister() {
+        mSpecAnimationBridge.cancel();
+
         mScreenStateObserver.unregister();
         mWindowStateObserver.unregister();
     }
@@ -149,8 +156,10 @@
             final float offsetY = sentSpec.offsetY;
 
             // Compute the new center and update spec as needed.
-            final float centerX = (mMagnifiedBounds.width() / 2.0f - offsetX) / scale;
-            final float centerY = (mMagnifiedBounds.height() / 2.0f - offsetY) / scale;
+            final float centerX = (mMagnifiedBounds.width() / 2.0f
+                    + mMagnifiedBounds.left - offsetX) / scale;
+            final float centerY = (mMagnifiedBounds.height() / 2.0f
+                    + mMagnifiedBounds.top - offsetY) / scale;
             if (updateSpec) {
                 setScaleAndCenter(scale, centerX, centerY, false);
             } else {
@@ -246,7 +255,8 @@
      */
     public float getCenterX() {
         synchronized (mLock) {
-            return  (mMagnifiedBounds.width() / 2.0f - getOffsetX()) / getScale();
+            return  (mMagnifiedBounds.width() / 2.0f
+                    + mMagnifiedBounds.left - getOffsetX()) / getScale();
         }
     }
 
@@ -268,7 +278,8 @@
      */
     public float getCenterY() {
         synchronized (mLock) {
-            return (mMagnifiedBounds.height() / 2.0f - getOffsetY()) / getScale();
+            return (mMagnifiedBounds.height() / 2.0f
+                    + mMagnifiedBounds.top - getOffsetY()) / getScale();
         }
     }
 
@@ -471,18 +482,25 @@
      *         otherwise
      */
     private boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY) {
+        // Handle defaults.
+        if (Float.isNaN(centerX)) {
+            centerX = getCenterX();
+        }
+        if (Float.isNaN(centerY)) {
+            centerY = getCenterY();
+        }
+        if (Float.isNaN(scale)) {
+            scale = getScale();
+        }
+
+        // Ensure requested center is within the available region.
         if (!availableRegionContains(centerX, centerY)) {
             return false;
         }
 
-        boolean changed = false;
-
+        // Compute changes.
         final MagnificationSpec currSpec = mCurrentMagnificationSpec;
-
-        // Handle scale.
-        if (Float.isNaN(scale)) {
-            scale = getScale();
-        }
+        boolean changed = false;
 
         final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
         if (Float.compare(currSpec.scale, normScale) != 0) {
@@ -490,24 +508,16 @@
             changed = true;
         }
 
-        // Handle X offset.
-        if (Float.isNaN(centerX)) {
-            centerX = getCenterX();
-        }
-
-        final float nonNormOffsetX = mMagnifiedBounds.width() / 2.0f - centerX * scale;
+        final float nonNormOffsetX = mMagnifiedBounds.width() / 2.0f
+                + mMagnifiedBounds.left - centerX * scale;
         final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
         if (Float.compare(currSpec.offsetX, offsetX) != 0) {
             currSpec.offsetX = offsetX;
             changed = true;
         }
 
-        // Handle Y offset.
-        if (Float.isNaN(centerY)) {
-            centerY = getCenterY();
-        }
-
-        final float nonNormOffsetY = mMagnifiedBounds.height() / 2.0f - centerY * scale;
+        final float nonNormOffsetY = mMagnifiedBounds.height() / 2.0f
+                + mMagnifiedBounds.top - centerY * scale;
         final float offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
         if (Float.compare(currSpec.offsetY, offsetY) != 0) {
             currSpec.offsetY = offsetY;
@@ -661,6 +671,12 @@
             mTransformationAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
         }
 
+        public void cancel() {
+            if (mTransformationAnimator != null && mTransformationAnimator.isRunning()) {
+                mTransformationAnimator.cancel();
+            }
+        }
+
         public void updateSentSpec(MagnificationSpec spec, boolean animate) {
             if (Thread.currentThread().getId() == mMainThreadId) {
                 // Already on the main thread, don't bother proxying.
@@ -811,9 +827,6 @@
         private static final int MESSAGE_ON_USER_CONTEXT_CHANGED = 3;
         private static final int MESSAGE_ON_ROTATION_CHANGED = 4;
 
-        private final Rect mTempRect = new Rect();
-        private final Rect mTempRect1 = new Rect();
-
         private final MagnificationController mController;
         private final WindowManagerInternal mWindowManager;
         private final Handler mHandler;
@@ -884,6 +897,10 @@
             mController.resetIfNeeded(true);
         }
 
+        public void getRegions(@NonNull Region outMagnified, @NonNull Region outAvailable) {
+            mWindowManager.getMagnificationRegions(outMagnified, outAvailable);
+        }
+
         private class CallbackHandler extends Handler {
             public CallbackHandler(Context context) {
                 super(context.getMainLooper());
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 3ecff40..3cc991c 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -437,6 +437,20 @@
     }
 
     @Override
+    public boolean onGestureStarted() {
+      // We have to perform gesture detection, so
+      // clear the current state and try to detect.
+      mCurrentState = STATE_GESTURE_DETECTING;
+      mSendHoverEnterAndMoveDelayed.cancel();
+      mSendHoverExitDelayed.cancel();
+      mExitGestureDetectionModeDelayed.post();
+      // Send accessibility event to announce the start
+      // of gesture recognition.
+      sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_START);
+      return false;
+    }
+
+    @Override
     public boolean onGestureCompleted(int gestureId) {
         if (mCurrentState != STATE_GESTURE_DETECTING) {
             return false;
@@ -450,36 +464,26 @@
     }
 
     @Override
-    public void onGestureStarted() {
-      // We have to perform gesture detection, so
-      // clear the current state and try to detect.
-      mCurrentState = STATE_GESTURE_DETECTING;
-      mSendHoverEnterAndMoveDelayed.cancel();
-      mSendHoverExitDelayed.cancel();
-      mExitGestureDetectionModeDelayed.post();
-      // Send accessibility event to announce the start
-      // of gesture recognition.
-      sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_START);
-    }
+    public boolean onGestureCancelled(MotionEvent event, int policyFlags) {
+        if (mCurrentState == STATE_GESTURE_DETECTING) {
+            endGestureDetection();
+            return true;
+        } else if (mCurrentState == STATE_TOUCH_EXPLORING) {
+            // If the finger is still moving, pass the event on.
+            if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+                final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
+                final int pointerIdBits = (1 << pointerId);
 
-    @Override
-    public void onGestureCancelled(MotionEvent event, int policyFlags) {
-      if (mCurrentState == STATE_GESTURE_DETECTING) {
-          endGestureDetection();
-      } else if (mCurrentState == STATE_TOUCH_EXPLORING) {
-          // If the finger is still moving, pass the event on.
-          if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
-              final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
-              final int pointerIdBits = (1 << pointerId);
-
-              // We have just decided that the user is touch,
-              // exploring so start sending events.
-              mSendHoverEnterAndMoveDelayed.addEvent(event);
-              mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
-              mSendHoverExitDelayed.cancel();
-              sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
-          }
-      }
+                // We have just decided that the user is touch,
+                // exploring so start sending events.
+                mSendHoverEnterAndMoveDelayed.addEvent(event);
+                mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
+                mSendHoverExitDelayed.cancel();
+                sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 2b52799..f93fb1b 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,9 +16,14 @@
 
 package com.android.server.appwidget;
 
+import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
@@ -72,10 +77,12 @@
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.Display;
+import android.view.View;
 import android.view.WindowManager;
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
+import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.os.BackgroundThread;
@@ -146,7 +153,7 @@
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
 
             if (DEBUG) {
-                Slog.i(TAG, "Received broadcast: " + action);
+                Slog.i(TAG, "Received broadcast: " + action + " on user " + userId);
             }
 
             if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
@@ -156,10 +163,11 @@
             } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                 onUserStopped(userId);
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                reloadWidgetsMaskedStateForUser(userId);
-            } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
+                reloadWidgetsMaskedStateForGroup(userId);
+            } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+                    || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
                 synchronized (mLock) {
-                    reloadWidgetProfileUnavailableMaskedStateLocked(userId);
+                    reloadWidgetsMaskedState(userId);
                 }
             } else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
                 String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -202,6 +210,8 @@
     private final AlarmManager mAlarmManager;
     private final UserManager mUserManager;
     private final AppOpsManager mAppOpsManager;
+    private final KeyguardManager mKeyguardManager;
+    private final DevicePolicyManagerInternal mDevicePolicyManagerInternal;
 
     private final SecurityPolicy mSecurityPolicy;
 
@@ -223,6 +233,8 @@
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
+        mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
         mSaveStateHandler = BackgroundThread.getHandler();
         mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
         mBackupRestoreController = new BackupRestoreController();
@@ -277,7 +289,8 @@
                 userFilter, null, null);
 
         IntentFilter offModeFilter = new IntentFilter();
-        offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+        offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+        offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
                 offModeFilter, null, null);
 
@@ -289,11 +302,9 @@
     }
 
     private void registerOnCrossProfileProvidersChangedListener() {
-        DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
-                DevicePolicyManagerInternal.class);
         // The device policy is an optional component.
-        if (devicePolicyManager != null) {
-            devicePolicyManager.addOnCrossProfileWidgetProvidersChangeListener(this);
+        if (mDevicePolicyManagerInternal != null) {
+            mDevicePolicyManagerInternal.addOnCrossProfileWidgetProvidersChangeListener(this);
         }
     }
 
@@ -323,7 +334,12 @@
                 for (int i = N - 1; i >= 0; i--) {
                     Provider provider = installedProviders.get(i);
 
-                    ensureGroupStateLoadedLocked(provider.getUserId());
+                    final int userId = provider.getUserId();
+                    if (!mUserManager.isUserUnlocked(userId) ||
+                            isProfileWithLockedParent(userId)) {
+                        continue;
+                    }
+                    ensureGroupStateLoadedLocked(userId);
 
                     if (!removedProviders.contains(provider.id)) {
                         final boolean changed = updateProvidersForPackageLocked(
@@ -353,7 +369,10 @@
     }
 
     private void onPackageBroadcastReceived(Intent intent, int userId) {
-        if (!mUserManager.isUserUnlocked(userId)) return;
+        if (!mUserManager.isUserUnlocked(userId) ||
+                isProfileWithLockedParent(userId)) {
+            return;
+        }
 
         final String action = intent.getAction();
         boolean added = false;
@@ -433,45 +452,57 @@
     /**
      * Reload all widgets' masked state for the given user and its associated profiles, including
      * due to user not being available and package suspension.
+     * userId must be the group parent.
      */
-    private void reloadWidgetsMaskedStateForUser(int userId) {
-        if (!mUserManager.isUserUnlocked(userId)) return;
+    private void reloadWidgetsMaskedStateForGroup(int userId) {
+        if (!mUserManager.isUserUnlocked(userId)) {
+            return;
+        }
         synchronized (mLock) {
-            reloadWidgetPackageSuspensionMaskedStateLocked(userId);
+            reloadWidgetsMaskedState(userId);
             List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
             if (profiles != null) {
                 for (int i = 0; i < profiles.size(); i++) {
                     UserInfo user  = profiles.get(i);
-                    reloadWidgetProfileUnavailableMaskedStateLocked(user.id);
-                    reloadWidgetPackageSuspensionMaskedStateLocked(user.id);
+                    reloadWidgetsMaskedState(user.id);
                 }
             }
         }
     }
 
-    /**
-     * Mask/unmask widgets in the given profile, depending on the quiet state
-     * or locked state of the profile.
-     */
-    private void reloadWidgetProfileUnavailableMaskedStateLocked(int profileId) {
+    private void reloadWidgetsMaskedState(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            if (!isProfileWithUnlockedParent(profileId)) {
-                return;
-            }
-            UserInfo user  = mUserManager.getUserInfo(profileId);
-            boolean shouldMask = user.isQuietModeEnabled() ||
-                    !mUserManager.isUserUnlocked(user.getUserHandle());
+            UserInfo user  = mUserManager.getUserInfo(userId);
+
+            boolean lockedProfile = !mUserManager.isUserUnlocked(userId);
+            boolean quietProfile = user.isQuietModeEnabled();
             final int N = mProviders.size();
             for (int i = 0; i < N; i++) {
                 Provider provider = mProviders.get(i);
                 int providerUserId = provider.getUserId();
-                if (providerUserId != profileId) {
+                if (providerUserId != userId) {
                     continue;
                 }
-                if (provider.setMaskedByProfileUnavailabledLocked(shouldMask)) {
+
+                boolean changed = provider.setMaskedByLockedProfileLocked(lockedProfile);
+                changed |= provider.setMaskedByQuietProfileLocked(quietProfile);
+                try {
+                    boolean suspended;
+                    try {
+                        suspended = mPackageManager.isPackageSuspendedForUser(
+                                provider.info.provider.getPackageName(), provider.getUserId());
+                    } catch (IllegalArgumentException ex) {
+                        // Package not found.
+                        suspended = false;
+                    }
+                    changed |= provider.setMaskedBySuspendedPackageLocked(suspended);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to query application info", e);
+                }
+                if (changed) {
                     if (provider.isMaskedLocked()) {
-                        maskWidgetsViewsLocked(provider);
+                        maskWidgetsViewsLocked(provider, null);
                     } else {
                         unmaskWidgetsViewsLocked(provider);
                     }
@@ -483,33 +514,6 @@
     }
 
     /**
-     * Reload widget's masked state due to package suspension state.
-     */
-    private void reloadWidgetPackageSuspensionMaskedStateLocked(int profileId) {
-        final int N = mProviders.size();
-        for (int i = 0; i < N; i++) {
-            Provider provider = mProviders.get(i);
-            int providerUserId = provider.getUserId();
-            if (providerUserId != profileId) {
-                continue;
-            }
-            try {
-                boolean suspended = mPackageManager.isPackageSuspendedForUser(
-                        provider.info.provider.getPackageName(), provider.getUserId());
-                if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
-                    if (provider.isMaskedLocked()) {
-                        maskWidgetsViewsLocked(provider);
-                    } else {
-                        unmaskWidgetsViewsLocked(provider);
-                    }
-                }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to query application info", e);
-            }
-        }
-    }
-
-    /**
      * Incrementally update the masked state due to package suspension state.
      */
     private void updateWidgetPackageSuspensionMaskedState(String[] packagesArray, boolean suspended,
@@ -529,7 +533,7 @@
                 }
                 if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
                     if (provider.isMaskedLocked()) {
-                        maskWidgetsViewsLocked(provider);
+                        maskWidgetsViewsLocked(provider, null);
                     } else {
                         unmaskWidgetsViewsLocked(provider);
                     }
@@ -538,14 +542,13 @@
         }
     }
 
-    private Bitmap createMaskedWidgetBitmap(Provider provider) {
+    private Bitmap createMaskedWidgetBitmap(String providerPackage, int providerUserId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             // Load the unbadged application icon and pass it to the widget to appear on
             // the masked view.
-            final String providerPackage = provider.info.provider.getPackageName();
             Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
-                    UserHandle.of(provider.getUserId()));
+                    UserHandle.of(providerUserId));
             PackageManager pm = userContext.getPackageManager();
             Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
             // Create a bitmap of the icon which is what the widget's remoteview requires.
@@ -560,18 +563,74 @@
         }
     }
 
-    private void maskWidgetsViewsLocked(Provider provider) {
-        Bitmap iconBitmap = createMaskedWidgetBitmap(provider);
+    private RemoteViews createMaskedWidgetRemoteViews(Bitmap icon, boolean showBadge,
+            PendingIntent onClickIntent) {
+        RemoteViews views = new RemoteViews(mContext.getPackageName(),
+                R.layout.work_widget_mask_view);
+        if (icon != null) {
+            views.setImageViewBitmap(R.id.work_widget_app_icon, icon);
+        }
+        if (!showBadge) {
+            views.setViewVisibility(R.id.work_widget_badge_icon, View.INVISIBLE);
+        }
+        if (onClickIntent != null) {
+            views.setOnClickPendingIntent(R.id.work_widget_mask_frame, onClickIntent);
+        }
+        return views;
+    }
+
+    /**
+     * Mask the target widget belonging to the specified provider, or all active widgets
+     * of the provider if target widget == null.
+     */
+    private void maskWidgetsViewsLocked(Provider provider, Widget targetWidget) {
+        final int widgetCount = provider.widgets.size();
+        if (widgetCount == 0) {
+            return;
+        }
+        final String providerPackage = provider.info.provider.getPackageName();
+        final int providerUserId = provider.getUserId();
+        Bitmap iconBitmap = createMaskedWidgetBitmap(providerPackage, providerUserId);
         if (iconBitmap == null) {
             return;
         }
+        final boolean showBadge;
+        final Intent onClickIntent;
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (provider.maskedBySuspendedPackage) {
+                UserInfo userInfo = mUserManager.getUserInfo(providerUserId);
+                showBadge = userInfo.isManagedProfile();
+                onClickIntent = mDevicePolicyManagerInternal.createPackageSuspendedDialogIntent(
+                        providerPackage, providerUserId);
+            } else if (provider.maskedByQuietProfile) {
+                showBadge = true;
+                onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
+                        providerUserId);
+            } else /* provider.maskedByLockedProfile */ {
+                showBadge = true;
+                onClickIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
+                        providerUserId);
+                if (onClickIntent != null) {
+                    onClickIntent.setFlags(FLAG_ACTIVITY_NEW_TASK
+                            | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
 
-        final int widgetCount = provider.widgets.size();
         for (int j = 0; j < widgetCount; j++) {
             Widget widget = provider.widgets.get(j);
-            if (widget.replaceWithMaskedViewsLocked(mContext, iconBitmap)) {
-                scheduleNotifyUpdateAppWidgetLocked(widget,
-                        widget.getEffectiveViewsLocked());
+            if (targetWidget != null && targetWidget != widget) continue;
+            PendingIntent intent = null;
+            if (onClickIntent != null) {
+                intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
+                        onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+            }
+            RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
+            if (widget.replaceWithMaskedViewsLocked(views)) {
+                scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
             }
         }
     }
@@ -581,8 +640,7 @@
         for (int j = 0; j < widgetCount; j++) {
             Widget widget = provider.widgets.get(j);
             if (widget.clearMaskedViewsLocked()) {
-                scheduleNotifyUpdateAppWidgetLocked(widget,
-                        widget.getEffectiveViewsLocked());
+                scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
             }
         }
     }
@@ -606,7 +664,10 @@
             throw new IllegalStateException(
                     "User " + userId + " must be unlocked for widgets to be available");
         }
-
+        if (isProfileWithLockedParent(userId)) {
+            throw new IllegalStateException(
+                    "Profile " + userId + " must have unlocked parent");
+        }
         final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
 
         // Careful lad, we may have already loaded the state for some
@@ -684,8 +745,8 @@
     }
 
     @Override
-    public int[] startListening(IAppWidgetHost callbacks, String callingPackage,
-            int hostId, List<RemoteViews> updatedViews) {
+    public ParceledListSlice<RemoteViews> startListening(IAppWidgetHost callbacks,
+            String callingPackage, int hostId, int[] appWidgetIds, int[] updatedIds) {
         final int userId = UserHandle.getCallingUserId();
 
         if (DEBUG) {
@@ -702,21 +763,21 @@
             // sure the caller can only access hosts it owns.
             HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
             Host host = lookupOrAddHostLocked(id);
-
             host.callbacks = callbacks;
 
-            updatedViews.clear();
-
-            ArrayList<Widget> instances = host.widgets;
-            int N = instances.size();
-            int[] updatedIds = new int[N];
+            int N = appWidgetIds.length;
+            ArrayList<RemoteViews> outViews = new ArrayList<>(N);
+            RemoteViews rv;
+            int added = 0;
             for (int i = 0; i < N; i++) {
-                Widget widget = instances.get(i);
-                updatedIds[i] = widget.appWidgetId;
-                updatedViews.add(cloneIfLocalBinder(widget.getEffectiveViewsLocked()));
+                rv = host.getPendingViewsForId(appWidgetIds[i]);
+                if (rv != null) {
+                    updatedIds[added] = appWidgetIds[i];
+                    outViews.add(rv);
+                    added++;
+                }
             }
-
-            return updatedIds;
+            return new ParceledListSlice<>(outViews);
         }
     }
 
@@ -1824,6 +1885,10 @@
     }
 
     private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
+        long requestTime = SystemClock.uptimeMillis();
+        if (widget != null) {
+            widget.lastUpdateTime = requestTime;
+        }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
             return;
@@ -1833,6 +1898,7 @@
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
         args.arg3 = updateViews;
+        args.arg4 = requestTime;
         args.argi1 = widget.appWidgetId;
 
         mCallbackHandler.obtainMessage(
@@ -1841,9 +1907,10 @@
     }
 
     private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, RemoteViews views) {
+            int appWidgetId, RemoteViews views, long requestTime) {
         try {
             callbacks.updateAppWidget(appWidgetId, views);
+            host.lastWidgetUpdateTime = requestTime;
         } catch (RemoteException re) {
             synchronized (mLock) {
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -2440,7 +2507,8 @@
             // from a profile that is still locked, so let them see those
             // widgets.
             if (isProfileWithUnlockedParent(userId)) {
-                flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+                flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
             }
 
             // Widgets referencing shared libraries need to have their
@@ -2449,7 +2517,7 @@
 
             return mPackageManager.queryIntentReceivers(intent,
                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                    flags, userId);
+                    flags, userId).getList();
         } catch (RemoteException re) {
             return Collections.emptyList();
         } finally {
@@ -2458,9 +2526,12 @@
     }
 
     private void onUserUnlocked(int userId) {
+        if (isProfileWithLockedParent(userId)) {
+            return;
+        }
         synchronized (mLock) {
             ensureGroupStateLoadedLocked(userId);
-            reloadWidgetsMaskedStateForUser(userId);
+            reloadWidgetsMaskedStateForGroup(mSecurityPolicy.getGroupParent(userId));
 
             final int N = mProviders.size();
             for (int i = 0; i < N; i++) {
@@ -2602,10 +2673,7 @@
         // If we are adding a widget it might be for a provider that
         // is currently masked, if so mask the widget.
         if (widget.provider.isMaskedLocked()) {
-            Bitmap bitmap = createMaskedWidgetBitmap(widget.provider);
-            if (bitmap != null) {
-                widget.replaceWithMaskedViewsLocked(mContext, bitmap);
-            }
+            maskWidgetsViewsLocked(widget.provider, widget);
         } else {
             widget.clearMaskedViewsLocked();
         }
@@ -3002,7 +3070,6 @@
 
     private void onUserStopped(int userId) {
         synchronized (mLock) {
-            boolean providersChanged = false;
             boolean crossProfileWidgetsChanged = false;
 
             // Remove widgets that have both host and provider in the user.
@@ -3038,16 +3105,8 @@
                 }
             }
 
-            // Remove the providers and notify hosts in other profiles.
-            final int providerCount = mProviders.size();
-            for (int i = providerCount - 1; i >= 0; i--) {
-                Provider provider = mProviders.get(i);
-                if (provider.getUserId() == userId) {
-                    crossProfileWidgetsChanged |= !provider.widgets.isEmpty();
-                    providersChanged = true;
-                    deleteProviderLocked(provider);
-                }
-            }
+            // Leave the providers present as hosts will show the widgets
+            // masked while the user is stopped.
 
             // Remove grants for this user.
             final int grantCount = mPackagesWithBindWidgetPermission.size();
@@ -3070,11 +3129,6 @@
                 mNextAppWidgetIds.removeAt(nextIdIndex);
             }
 
-            // Announce removed provider changes to all hosts in the group.
-            if (providersChanged) {
-                scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
-            }
-
             // Save state if removing a profile changed the group state.
             // Nothing will be saved if the group parent was removed.
             if (crossProfileWidgetsChanged) {
@@ -3306,6 +3360,23 @@
         }
     }
 
+    private boolean isProfileWithLockedParent(int userId) {
+        long token = Binder.clearCallingIdentity();
+        try {
+            UserInfo userInfo = mUserManager.getUserInfo(userId);
+            if (userInfo != null && userInfo.isManagedProfile()) {
+                UserInfo parentInfo = mUserManager.getProfileParent(userId);
+                if (parentInfo != null
+                        && !mUserManager.isUserUnlocked(parentInfo.getUserHandle())) {
+                    return true;
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return false;
+    }
+
     private boolean isProfileWithUnlockedParent(int userId) {
         UserInfo userInfo = mUserManager.getUserInfo(userId);
         if (userInfo != null && userInfo.isManagedProfile()) {
@@ -3336,10 +3407,11 @@
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
                     RemoteViews views = (RemoteViews) args.arg3;
+                    long requestTime = (Long) args.arg4;
                     final int appWidgetId = args.argi1;
                     args.recycle();
 
-                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views);
+                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views, requestTime);
                 } break;
 
                 case MSG_NOTIFY_PROVIDER_CHANGED: {
@@ -3524,15 +3596,12 @@
         }
 
         public boolean isProviderWhiteListed(String packageName, int profileId) {
-            DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
-                    DevicePolicyManagerInternal.class);
-
             // If the policy manager is not available on the device we deny it all.
-            if (devicePolicyManager == null) {
+            if (mDevicePolicyManagerInternal == null) {
                 return false;
             }
 
-            List<String> crossProfilePackages = devicePolicyManager
+            List<String> crossProfilePackages = mDevicePolicyManagerInternal
                     .getCrossProfileWidgetProviders(profileId);
 
             return crossProfilePackages.contains(packageName);
@@ -3595,7 +3664,8 @@
         PendingIntent broadcast;
         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
 
-        boolean maskedByProfileUnavailable;
+        boolean maskedByLockedProfile;
+        boolean maskedByQuietProfile;
         boolean maskedBySuspendedPackage;
 
         int tag = TAG_UNDEFINED; // for use while saving state (the index)
@@ -3627,22 +3697,29 @@
             return "Provider{" + id + (zombie ? " Z" : "") + '}';
         }
 
-        // returns true if the provider's masked state is changed as a result
-        public boolean setMaskedByProfileUnavailabledLocked(boolean masked) {
-            boolean oldMaskedState = isMaskedLocked();
-            maskedByProfileUnavailable = masked;
-            return isMaskedLocked() != oldMaskedState;
+        // returns true if it's different from previous state.
+        public boolean setMaskedByQuietProfileLocked(boolean masked) {
+            boolean oldState = maskedByQuietProfile;
+            maskedByQuietProfile = masked;
+            return masked != oldState;
         }
 
-        // returns true if the provider's masked state is changed as a result
+        // returns true if it's different from previous state.
+        public boolean setMaskedByLockedProfileLocked(boolean masked) {
+            boolean oldState = maskedByLockedProfile;
+            maskedByLockedProfile = masked;
+            return masked != oldState;
+        }
+
+        // returns true if it's different from previous state.
         public boolean setMaskedBySuspendedPackageLocked(boolean masked) {
-            boolean oldMaskedState = isMaskedLocked();
+            boolean oldState = maskedBySuspendedPackage;
             maskedBySuspendedPackage = masked;
-            return isMaskedLocked() != oldMaskedState;
+            return masked != oldState;
         }
 
         public boolean isMaskedLocked() {
-            return maskedByProfileUnavailable || maskedBySuspendedPackage;
+            return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage;
         }
     }
 
@@ -3702,6 +3779,7 @@
         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
 
         int tag = TAG_UNDEFINED; // for use while saving state (the index)
+        long lastWidgetUpdateTime; // last time we were successfully able to send an update.
 
         public int getUserId() {
             return UserHandle.getUserId(id.uid);
@@ -3723,6 +3801,23 @@
             return false;
         }
 
+        /**
+         * Returns the RemoveViews for the provided widget id if an update is pending
+         * for that widget.
+         */
+        public RemoteViews getPendingViewsForId(int appWidgetId) {
+            long updateTime = lastWidgetUpdateTime;
+            int N = widgets.size();
+            for (int i = 0; i < N; i++) {
+                Widget widget = widgets.get(i);
+                if (widget.appWidgetId == appWidgetId
+                        && widget.lastUpdateTime > updateTime) {
+                    return cloneIfLocalBinder(widget.getEffectiveViewsLocked());
+                }
+            }
+            return null;
+        }
+
         @Override
         public String toString() {
             return "Host{" + id + (zombie ? " Z" : "") + '}';
@@ -3793,20 +3888,15 @@
         RemoteViews maskedViews;
         Bundle options;
         Host host;
+        long lastUpdateTime;
 
         @Override
         public String toString() {
             return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
         }
 
-        private boolean replaceWithMaskedViewsLocked(Context context, Bitmap icon) {
-            if (maskedViews != null) {
-                return false;
-            }
-            maskedViews = new RemoteViews(context.getPackageName(), R.layout.work_widget_mask_view);
-            if (icon != null) {
-                maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, icon);
-            }
+        private boolean replaceWithMaskedViewsLocked(RemoteViews views) {
+            maskedViews = views;
             return true;
         }
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index e32d89c..6288b56 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -171,6 +171,10 @@
     static final boolean MORE_DEBUG = false;
     static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
 
+    // File containing backup-enabled state.  Contains a single byte;
+    // nonzero == enabled.  File missing or contains a zero byte == disabled.
+    static final String BACKUP_ENABLE_FILE = "backup_enabled";
+
     // System-private key used for backing up an app's widget state.  Must
     // begin with U+FFxx by convention (we reserve all keys starting
     // with U+FF00 or higher for system use).
@@ -354,11 +358,30 @@
             if (userId == UserHandle.USER_SYSTEM) {
                 sInstance.initialize(userId);
 
-                ContentResolver r = sInstance.mContext.getContentResolver();
-                boolean areEnabled = Settings.Secure.getIntForUser(r,
-                        Settings.Secure.BACKUP_ENABLED, 0, userId) != 0;
+                // Migrate legacy setting
+                if (!backupSettingMigrated(userId)) {
+                    if (DEBUG) {
+                        Slog.i(TAG, "Backup enable apparently not migrated");
+                    }
+                    final ContentResolver r = sInstance.mContext.getContentResolver();
+                    final int enableState = Settings.Secure.getIntForUser(r,
+                            Settings.Secure.BACKUP_ENABLED, -1, userId);
+                    if (enableState >= 0) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "Migrating enable state " + (enableState != 0));
+                        }
+                        writeBackupEnableState(enableState != 0, userId);
+                        Settings.Secure.putStringForUser(r,
+                                Settings.Secure.BACKUP_ENABLED, null, userId);
+                    } else {
+                        if (DEBUG) {
+                            Slog.i(TAG, "Backup not yet configured; retaining null enable state");
+                        }
+                    }
+                }
+
                 try {
-                    sInstance.setBackupEnabled(areEnabled);
+                    sInstance.setBackupEnabled(readBackupEnableState(userId));
                 } catch (RemoteException e) {
                     // can't happen; it's a local object
                 }
@@ -1795,7 +1818,7 @@
             File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
             if (initSentinel.exists()) {
                 synchronized (mQueueLock) {
-                    mPendingInits.add(transportName);
+                    mPendingInits.add(name);
 
                     // TODO: pick a better starting time than now + 1 minute
                     long delay = 1000 * 60; // one minute, in milliseconds
@@ -2293,6 +2316,25 @@
         }
     }
 
+    // What name is this transport registered under...?
+    private String getTransportName(IBackupTransport transport) {
+        if (MORE_DEBUG) {
+            Slog.v(TAG, "Searching for transport name of " + transport);
+        }
+        synchronized (mTransports) {
+            final int N = mTransports.size();
+            for (int i = 0; i < N; i++) {
+                if (mTransports.valueAt(i).equals(transport)) {
+                    if (MORE_DEBUG) {
+                        Slog.v(TAG, "  Name found: " + mTransports.keyAt(i));
+                    }
+                    return mTransports.keyAt(i);
+                }
+            }
+        }
+        return null;
+    }
+
     // fire off a backup agent, blocking until it attaches or times out
     IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
         IBackupAgent agent = null;
@@ -2895,9 +2937,23 @@
                 mBackupRunning = false;
                 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
                     // Make sure we back up everything and perform the one-time init
-                    clearMetadata();
                     if (MORE_DEBUG) Slog.d(TAG, "Server requires init; rerunning");
                     addBackupTrace("init required; rerunning");
+                    try {
+                        final String name = getTransportName(mTransport);
+                        if (name != null) {
+                            mPendingInits.add(name);
+                        } else {
+                            if (DEBUG) {
+                                Slog.w(TAG, "Couldn't find name of transport " + mTransport
+                                        + " for init");
+                            }
+                        }
+                    } catch (Exception e) {
+                        Slog.w(TAG, "Failed to query transport name heading for init", e);
+                        // swallow it and proceed; we don't rely on this
+                    }
+                    clearMetadata();
                     backupNow();
                 }
             }
@@ -3472,9 +3528,8 @@
             // The agent was running with a stub Application object, so shut it down.
             // !!! We hardcode the confirmation UI's package name here rather than use a
             //     manifest flag!  TODO something less direct.
-            if (app.uid != Process.SYSTEM_UID
-                    && !app.packageName.equals("com.android.backupconfirm")
-                    && app.uid != Process.PHONE_UID) {
+            if (app.uid >= Process.FIRST_APPLICATION_UID
+                    && !app.packageName.equals("com.android.backupconfirm")) {
                 if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process");
                 mActivityManager.killApplicationProcess(app.processName, app.uid);
             } else {
@@ -4429,13 +4484,21 @@
                             }
                         }
 
-                        // We still could fail in backup runner thread, getting result from there.
-                        int backupRunnerResult = backupRunner.getBackupResultBlocking();
-                        if (backupPackageStatus != BackupTransport.TRANSPORT_ERROR
-                                && backupRunnerResult != BackupTransport.TRANSPORT_OK) {
-                            // If there was an error in runner thread and
-                            // not TRANSPORT_ERROR here, overwrite it.
-                            backupPackageStatus = backupRunnerResult;
+                        // TRANSPORT_ERROR here means that we've hit an error that the runner
+                        // doesn't know about, so it's still moving data but we're pulling the
+                        // rug out from under it.  Don't ask for its result:  we already know better
+                        // and we'll hang if we block waiting for it, since it relies on us to
+                        // read back the data it's writing into the engine.  Just proceed with
+                        // a graceful failure.  The runner/engine mechanism will tear itself
+                        // down cleanly when we close the pipes from this end.
+                        if (backupPackageStatus != BackupTransport.TRANSPORT_ERROR) {
+                            // We still could fail in backup runner thread, getting result from there.
+                            int backupRunnerResult = backupRunner.getBackupResultBlocking();
+                            if (backupRunnerResult != BackupTransport.TRANSPORT_OK) {
+                                // If there was an error in runner thread and
+                                // not TRANSPORT_ERROR here, overwrite it.
+                                backupPackageStatus = backupRunnerResult;
+                            }
                         }
 
                         if (MORE_DEBUG) {
@@ -6858,7 +6921,7 @@
                     // The agent was running with a stub Application object, so shut it down.
                     // !!! We hardcode the confirmation UI's package name here rather than use a
                     //     manifest flag!  TODO something less direct.
-                    if (app.uid != Process.SYSTEM_UID
+                    if (app.uid >= Process.FIRST_APPLICATION_UID
                             && !app.packageName.equals("com.android.backupconfirm")) {
                         if (DEBUG) Slog.d(TAG, "Killing host process");
                         mActivityManager.killApplicationProcess(app.processName, app.uid);
@@ -7554,77 +7617,6 @@
 
     // ----- Restore handling -----
 
-    // new style: we only store the SHA-1 hashes of each sig, not the full block
-    static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
-        if (target == null) {
-            return false;
-        }
-
-        // If the target resides on the system partition, we allow it to restore
-        // data from the like-named package in a restore set even if the signatures
-        // do not match.  (Unlike general applications, those flashed to the system
-        // partition will be signed with the device's platform certificate, so on
-        // different phones the same system app will have different signatures.)
-        if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-            if (MORE_DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
-            return true;
-        }
-
-        // Allow unsigned apps, but not signed on one device and unsigned on the other
-        // !!! TODO: is this the right policy?
-        Signature[] deviceSigs = target.signatures;
-        if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
-                + " device=" + deviceSigs);
-        if ((storedSigHashes == null || storedSigHashes.size() == 0)
-                && (deviceSigs == null || deviceSigs.length == 0)) {
-            return true;
-        }
-        if (storedSigHashes == null || deviceSigs == null) {
-            return false;
-        }
-
-        // !!! TODO: this demands that every stored signature match one
-        // that is present on device, and does not demand the converse.
-        // Is this this right policy?
-        final int nStored = storedSigHashes.size();
-        final int nDevice = deviceSigs.length;
-
-        // hash each on-device signature
-        ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
-        for (int i = 0; i < nDevice; i++) {
-            deviceHashes.add(hashSignature(deviceSigs[i]));
-        }
-
-        // now ensure that each stored sig (hash) matches an on-device sig (hash)
-        for (int n = 0; n < nStored; n++) {
-            boolean match = false;
-            final byte[] storedHash = storedSigHashes.get(n);
-            for (int i = 0; i < nDevice; i++) {
-                if (Arrays.equals(storedHash, deviceHashes.get(i))) {
-                    match = true;
-                    break;
-                }
-            }
-            // match is false when no on-device sig matched one of the stored ones
-            if (!match) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    static byte[] hashSignature(Signature sig) {
-        try {
-            MessageDigest digest = MessageDigest.getInstance("SHA-256");
-            digest.update(sig.toByteArray());
-            return digest.digest();
-        } catch (NoSuchAlgorithmException e) {
-            Slog.w(TAG, "No SHA-256 algorithm found!");
-        }
-        return null;
-    }
-
     // Old style: directly match the stored vs on device signature blocks
     static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
         if (target == null) {
@@ -8137,7 +8129,7 @@
             }
 
             Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
-            if (!signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
+            if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
                 Slog.w(TAG, "Signature mismatch restoring " + packageName);
                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
                         "Signature mismatch");
@@ -8602,13 +8594,15 @@
                     // it is explicitly not killed following that operation.
                     //
                     // We execute this kill when these conditions hold:
-                    //    1. the app did not request its own restore (mTargetPackage == null), and either
-                    //    2a. the app is a full-data target (TYPE_FULL_STREAM) or
+                    //    1. it's not a system-uid process,
+                    //    2. the app did not request its own restore (mTargetPackage == null), and either
+                    //    3a. the app is a full-data target (TYPE_FULL_STREAM) or
                     //     b. the app does not state android:killAfterRestore="false" in its manifest
                     final int appFlags = mCurrentPackage.applicationInfo.flags;
                     final boolean killAfterRestore =
-                            (mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
-                            || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0);
+                            (mCurrentPackage.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
+                            && ((mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
+                                    || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0));
 
                     if (mTargetPackage == null && killAfterRestore) {
                         if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
@@ -9314,6 +9308,58 @@
         }
     }
 
+    private static boolean backupSettingMigrated(int userId) {
+        File base = new File(Environment.getDataDirectory(), "backup");
+        File enableFile = new File(base, BACKUP_ENABLE_FILE);
+        return enableFile.exists();
+    }
+
+    private static boolean readBackupEnableState(int userId) {
+        File base = new File(Environment.getDataDirectory(), "backup");
+        File enableFile = new File(base, BACKUP_ENABLE_FILE);
+        if (enableFile.exists()) {
+            try (FileInputStream fin = new FileInputStream(enableFile)) {
+                int state = fin.read();
+                return state != 0;
+            } catch (IOException e) {
+                // can't read the file; fall through to assume disabled
+                Slog.e(TAG, "Cannot read enable state; assuming disabled");
+            }
+        } else {
+            if (DEBUG) {
+                Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
+            }
+        }
+        return false;
+    }
+
+    private static void writeBackupEnableState(boolean enable, int userId) {
+        File base = new File(Environment.getDataDirectory(), "backup");
+        File enableFile = new File(base, BACKUP_ENABLE_FILE);
+        File stage = new File(base, BACKUP_ENABLE_FILE + "-stage");
+        FileOutputStream fout = null;
+        try {
+            fout = new FileOutputStream(stage);
+            fout.write(enable ? 1 : 0);
+            fout.close();
+            stage.renameTo(enableFile);
+            // will be synced immediately by the try-with-resources call to close()
+        } catch (IOException|RuntimeException e) {
+            // Whoops; looks like we're doomed.  Roll everything out, disabled,
+            // including the legacy state.
+            Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: "
+                    + e.getMessage());
+
+            final ContentResolver r = sInstance.mContext.getContentResolver();
+            Settings.Secure.putStringForUser(r,
+                    Settings.Secure.BACKUP_ENABLED, null, userId);
+            enableFile.delete();
+            stage.delete();
+        } finally {
+            IoUtils.closeQuietly(fout);
+        }
+    }
+
     // Enable/disable backups
     public void setBackupEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
@@ -9325,8 +9371,7 @@
         try {
             boolean wasEnabled = mEnabled;
             synchronized (this) {
-                Settings.Secure.putInt(mContext.getContentResolver(),
-                        Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
+                writeBackupEnableState(enable, UserHandle.USER_SYSTEM);
                 mEnabled = enable;
             }
 
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index f197c1e..09f240f 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -205,7 +205,7 @@
                         PackageManager.GET_SIGNATURES);
                 homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
                 homeVersion = homeInfo.versionCode;
-                homeSigHashes = hashSignatureArray(homeInfo.signatures);
+                homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures);
             } catch (NameNotFoundException e) {
                 Slog.w(TAG, "Can't access preferred home info");
                 // proceed as though there were no preferred home set
@@ -222,7 +222,7 @@
             final boolean needHomeBackup = (homeVersion != mStoredHomeVersion)
                     || !Objects.equals(home, mStoredHomeComponent)
                     || (home != null
-                        && !BackupManagerService.signaturesMatch(mStoredHomeSigHashes, homeInfo));
+                        && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo));
             if (needHomeBackup) {
                 if (DEBUG) {
                     Slog.i(TAG, "Home preference changed; backing up new state " + home);
@@ -309,7 +309,7 @@
                     outputBuffer.reset();
                     outputBufferStream.writeInt(info.versionCode);
                     writeSignatureHashArray(outputBufferStream,
-                            hashSignatureArray(info.signatures));
+                            BackupUtils.hashSignatureArray(info.signatures));
 
                     if (DEBUG) {
                         Slog.v(TAG, "+ writing metadata for " + packName
@@ -432,18 +432,6 @@
         mRestoredSignatures = sigMap;
     }
 
-    private static ArrayList<byte[]> hashSignatureArray(Signature[] sigs) {
-        if (sigs == null) {
-            return null;
-        }
-
-        ArrayList<byte[]> hashes = new ArrayList<byte[]>(sigs.length);
-        for (Signature s : sigs) {
-            hashes.add(BackupManagerService.hashSignature(s));
-        }
-        return hashes;
-    }
-
     private static void writeSignatureHashArray(DataOutputStream out, ArrayList<byte[]> hashes)
             throws IOException {
         // the number of entries in the array
@@ -492,13 +480,8 @@
             }
 
             if (nonHashFound) {
-                ArrayList<byte[]> hashes =
-                        new ArrayList<byte[]>(sigs.size());
-                for (int i = 0; i < sigs.size(); i++) {
-                    Signature s = new Signature(sigs.get(i));
-                    hashes.add(BackupManagerService.hashSignature(s));
-                }
-                sigs = hashes;
+                // Replace with the hashes.
+                sigs = BackupUtils.hashSignatureArray(sigs);
             }
 
             return sigs;
diff --git a/services/core/Android.mk b/services/core/Android.mk
index aaa2211..99c5dd6 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -7,7 +7,8 @@
 LOCAL_SRC_FILES += \
     $(call all-java-files-under,java) \
     java/com/android/server/EventLogTags.logtags \
-    java/com/android/server/am/EventLogTags.logtags
+    java/com/android/server/am/EventLogTags.logtags \
+    ../../../../system/netd/server/binder/android/net/INetd.aidl
 
 LOCAL_JAVA_LIBRARIES := services.net telephony-common
 LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4667172..7da247a 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -150,6 +150,12 @@
     int mNumTimeChanged;
 
     /**
+     * The current set of user whitelisted apps for device idle mode, meaning these are allowed
+     * to freely schedule alarms.
+     */
+    int[] mDeviceIdleUserWhitelist = new int[0];
+
+    /**
      * For each uid, this is the last time we dispatched an "allow while idle" alarm,
      * used to determine the earliest we can dispatch the next such alarm.
      */
@@ -936,6 +942,7 @@
         }
 
         publishBinderService(Context.ALARM_SERVICE, mService);
+        publishLocalService(LocalService.class, new LocalService());
     }
 
     @Override
@@ -1251,14 +1258,6 @@
                 flags &= ~AlarmManager.FLAG_IDLE_UNTIL;
             }
 
-            // If the caller is a core system component, and not calling to do work on behalf
-            // of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED.  This means we
-            // will allow these alarms to go off as normal even while idle, with no timing
-            // restrictions.
-            if (callingUid < Process.FIRST_APPLICATION_UID && workSource == null) {
-                flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
-            }
-
             // If this is an exact time alarm, then it can't be batched with other alarms.
             if (windowLength == AlarmManager.WINDOW_EXACT) {
                 flags |= AlarmManager.FLAG_STANDALONE;
@@ -1268,6 +1267,16 @@
             // use it to wake early from idle if needed.
             if (alarmClock != null) {
                 flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
+
+            // If the caller is a core system component or on the user's whitelist, and not calling
+            // to do work on behalf of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED.
+            // This means we will allow these alarms to go off as normal even while idle, with no
+            // timing restrictions.
+            } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
+                    || Arrays.binarySearch(mDeviceIdleUserWhitelist,
+                            UserHandle.getAppId(callingUid)) >= 0)) {
+                flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+                flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
             }
 
             setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
@@ -1344,6 +1353,12 @@
         }
     };
 
+    public final class LocalService {
+        public void setDeviceIdleUserWhitelist(int[] appids) {
+            setDeviceIdleUserWhitelistImpl(appids);
+        }
+    }
+
     void dumpImpl(PrintWriter pw) {
         synchronized (mLock) {
             pw.println("Current Alarm Manager state:");
@@ -1386,6 +1401,7 @@
             pw.print("  Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
             pw.print("  Num time change events: "); pw.println(mNumTimeChanged);
+            pw.println("  mDeviceIdleUserWhitelist=" + Arrays.toString(mDeviceIdleUserWhitelist));
 
             pw.println();
             pw.println("  Next alarm clock information: ");
@@ -1678,6 +1694,12 @@
         }
     }
 
+    void setDeviceIdleUserWhitelistImpl(int[] appids) {
+        synchronized (mLock) {
+            mDeviceIdleUserWhitelist = appids;
+        }
+    }
+
     AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
         synchronized (mLock) {
             return mNextAlarmClockForUser.get(userId);
@@ -2275,7 +2297,7 @@
             if (operation != null) {
                 sb.append(operation.getTargetPackage());
             } else {
-                sb.append(listener.asBinder().toString());
+                sb.append(packageName);
             }
             sb.append('}');
             return sb.toString();
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 32f2d59..0a2153e 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -57,6 +57,7 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -107,8 +108,23 @@
 
     private final SparseArray<UidState> mUidStates = new SparseArray<>();
 
-    /** These are app op restrictions imposed per user from various parties */
-    private final ArrayMap<IBinder, SparseArray<boolean[]>> mOpUserRestrictions = new ArrayMap<>();
+    /*
+     * These are app op restrictions imposed per user from various parties.
+     *
+     * This is organized as follows:
+     *
+     * ArrayMap w/ mapping:
+     *  IBinder (for client imposing restriction) --> SparseArray w/ mapping:
+     *    User handle --> Pair containing:
+     *       - Array w/ index = AppOp code, value = restricted status boolean
+     *       - SparseArray w/ mapping:
+     *          AppOp code --> Set of packages that are not restricted for this code
+     *
+     * For efficiency, a core assumption here is that the number of per-package exemptions stored
+     * here will be relatively small.  If this changes, this data structure should be revisited.
+     */
+    private final ArrayMap<IBinder, SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>>
+            mOpUserRestrictions = new ArrayMap<>();
 
     private static final class UidState {
         public final int uid;
@@ -430,8 +446,12 @@
             int[] ops) {
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return Collections.emptyList();
+        }
         synchronized (this) {
-            Ops pkgOps = getOpsLocked(uid, packageName, false);
+            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
             if (pkgOps == null) {
                 return null;
             }
@@ -449,7 +469,7 @@
 
     private void pruneOp(Op op, int uid, String packageName) {
         if (op.time == 0 && op.rejectTime == 0) {
-            Ops ops = getOpsLocked(uid, packageName, false);
+            Ops ops = getOpsRawLocked(uid, packageName, false);
             if (ops != null) {
                 ops.remove(op.op);
                 if (ops.size() <= 0) {
@@ -863,8 +883,12 @@
     public int checkOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
         synchronized (this) {
-            if (isOpRestricted(uid, code, packageName)) {
+            if (isOpRestricted(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             code = AppOpsManager.opToSwitch(code);
@@ -875,7 +899,7 @@
                     return uidMode;
                 }
             }
-            Op op = getOpLocked(code, uid, packageName, false);
+            Op op = getOpLocked(code, uid, resolvedPackageName, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
@@ -885,7 +909,15 @@
 
     @Override
     public int checkAudioOperation(int code, int usage, int uid, String packageName) {
-        if (isPackageSuspendedForUser(packageName, uid)) {
+        boolean suspended;
+        try {
+            suspended = isPackageSuspendedForUser(packageName, uid);
+        } catch (IllegalArgumentException ex) {
+            // Package not found.
+            suspended = false;
+        }
+
+        if (suspended) {
             Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
             return AppOpsManager.MODE_IGNORED;
         }
@@ -947,10 +979,12 @@
                 usageRestrictions.put(usage, r);
             }
         }
+        notifyWatchersOfChange(code);
     }
 
     @Override
     public int checkPackage(int uid, String packageName) {
+        Preconditions.checkNotNull(packageName);
         synchronized (this) {
             if (getOpsRawLocked(uid, packageName, true) != null) {
                 return AppOpsManager.MODE_ALLOWED;
@@ -964,26 +998,39 @@
     public int noteProxyOperation(int code, String proxyPackageName,
             int proxiedUid, String proxiedPackageName) {
         verifyIncomingOp(code);
-        final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
-                proxyPackageName, -1, null);
+        final int proxyUid = Binder.getCallingUid();
+        String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+        if (resolveProxyPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        final int proxyMode = noteOperationUnchecked(code, proxyUid,
+                resolveProxyPackageName, -1, null);
         if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
             return proxyMode;
         }
-        return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
-                Binder.getCallingUid(), proxyPackageName);
+        String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+        if (resolveProxiedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
+                proxyMode, resolveProxyPackageName);
     }
 
     @Override
     public int noteOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        return noteOperationUnchecked(code, uid, packageName, 0, null);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
     }
 
     private int noteOperationUnchecked(int code, int uid, String packageName,
             int proxyUid, String proxyPackageName) {
         synchronized (this) {
-            Ops ops = getOpsLocked(uid, packageName, true);
+            Ops ops = getOpsRawLocked(uid, packageName, true);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName);
@@ -1000,7 +1047,9 @@
             op.duration = 0;
             final int switchCode = AppOpsManager.opToSwitch(code);
             UidState uidState = ops.uidState;
-            if (uidState.opModes != null) {
+            // If there is a non-default per UID policy (we set UID op mode only if
+            // non-default) it takes over, otherwise use the per package policy.
+            if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
                 final int uidMode = uidState.opModes.get(switchCode);
                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
@@ -1009,13 +1058,15 @@
                     op.rejectTime = System.currentTimeMillis();
                     return uidMode;
                 }
-            }
-            final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
-            if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
-                if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
-                        + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
-                op.rejectTime = System.currentTimeMillis();
-                return switchOp.mode;
+            } else {
+                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
+                if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
+                    if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+                            + switchCode + " (" + code + ") uid " + uid + " package "
+                            + packageName);
+                    op.rejectTime = System.currentTimeMillis();
+                    return switchOp.mode;
+                }
             }
             if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
                     + " package " + packageName);
@@ -1031,16 +1082,20 @@
     public int startOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return  AppOpsManager.MODE_IGNORED;
+        }
         ClientState client = (ClientState)token;
         synchronized (this) {
-            Ops ops = getOpsLocked(uid, packageName, true);
+            Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
-                        + " package " + packageName);
+                        + " package " + resolvedPackageName);
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
-            if (isOpRestricted(uid, code, packageName)) {
+            if (isOpRestricted(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1050,7 +1105,7 @@
                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
-                            + packageName);
+                            + resolvedPackageName);
                     op.rejectTime = System.currentTimeMillis();
                     return uidMode;
                 }
@@ -1058,12 +1113,13 @@
             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
                 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
-                        + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
+                        + switchCode + " (" + code + ") uid " + uid + " package "
+                        + resolvedPackageName);
                 op.rejectTime = System.currentTimeMillis();
                 return switchOp.mode;
             }
             if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
-                    + " package " + packageName);
+                    + " package " + resolvedPackageName);
             if (op.nesting == 0) {
                 op.time = System.currentTimeMillis();
                 op.rejectTime = 0;
@@ -1081,9 +1137,16 @@
     public void finishOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        ClientState client = (ClientState)token;
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return;
+        }
+        if (!(token instanceof ClientState)) {
+            return;
+        }
+        ClientState client = (ClientState) token;
         synchronized (this) {
-            Op op = getOpLocked(code, uid, packageName, true);
+            Op op = getOpLocked(code, uid, resolvedPackageName, true);
             if (op == null) {
                 return;
             }
@@ -1099,6 +1162,9 @@
 
     @Override
     public int permissionToOpCode(String permission) {
+        if (permission == null) {
+            return AppOpsManager.OP_NONE;
+        }
         return AppOpsManager.permissionToOpCode(permission);
     }
 
@@ -1148,15 +1214,6 @@
         return uidState;
     }
 
-    private Ops getOpsLocked(int uid, String packageName, boolean edit) {
-        if (uid == 0) {
-            packageName = "root";
-        } else if (uid == Process.SHELL_UID) {
-            packageName = "com.android.shell";
-        }
-        return getOpsRawLocked(uid, packageName, edit);
-    }
-
     private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
         UidState uidState = getUidStateLocked(uid, edit);
         if (uidState == null) {
@@ -1242,7 +1299,7 @@
     }
 
     private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
-        Ops ops = getOpsLocked(uid, packageName, edit);
+        Ops ops = getOpsRawLocked(uid, packageName, edit);
         if (ops == null) {
             return null;
         }
@@ -1267,18 +1324,46 @@
     private boolean isOpRestricted(int uid, int code, String packageName) {
         int userHandle = UserHandle.getUserId(uid);
         final int restrictionSetCount = mOpUserRestrictions.size();
+
         for (int i = 0; i < restrictionSetCount; i++) {
-            SparseArray<boolean[]> perUserRestrictions = mOpUserRestrictions.valueAt(i);
-            boolean[] opRestrictions = perUserRestrictions.get(userHandle);
-            if (opRestrictions != null && opRestrictions[code]) {
+            // For each client, check that the given op is not restricted, or that the given
+            // package is exempt from the restriction.
+
+            SparseArray<Pair<boolean[],SparseArray<ArraySet<String>>>> perUserRestrictions =
+                    mOpUserRestrictions.valueAt(i);
+
+            Pair<boolean[],SparseArray<ArraySet<String>>> restrictions =
+                    perUserRestrictions.get(userHandle);
+            if (restrictions == null) {
+                continue; // No restrictions set by this client
+            }
+
+            boolean[] opRestrictions = restrictions.first;
+            SparseArray<ArraySet<String>> opExceptions = restrictions.second;
+
+            if (opRestrictions == null) {
+                continue; // No restrictions set by this client
+            }
+
+            if (opRestrictions[code]) {
+
+                if (opExceptions != null) {
+                    ArraySet<String> ex = opExceptions.get(code);
+                    if (ex != null && ex.contains(packageName)) {
+                        continue; // AppOps code is restricted, but this package is exempt
+                    }
+                }
+
                 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
+                    // If we are the system, bypass user restrictions for certain codes
                     synchronized (this) {
-                        Ops ops = getOpsLocked(uid, packageName, true);
+                        Ops ops = getOpsRawLocked(uid, packageName, true);
                         if ((ops != null) && ops.isPrivileged) {
                             return false;
                         }
                     }
                 }
+
                 return true;
             }
         }
@@ -1537,7 +1622,7 @@
                         out.startTag(null, "uid");
                         out.attribute(null, "n", Integer.toString(pkg.getUid()));
                         synchronized (this) {
-                            Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
+                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
                             // Should always be present as the list of PackageOps is generated
                             // from Ops.
                             if (ops != null) {
@@ -1600,7 +1685,9 @@
         int userId = UserHandle.USER_SYSTEM;
         String packageName;
         String opStr;
+        String modeStr;
         int op;
+        int mode;
         int packageUid;
 
         Shell(IAppOpsService iface, AppOpsService internal) {
@@ -1636,6 +1723,59 @@
             }
         }
 
+        int strModeToMode(String modeStr, PrintWriter err) {
+            switch (modeStr) {
+                case "allow":
+                    return AppOpsManager.MODE_ALLOWED;
+                case "deny":
+                    return AppOpsManager.MODE_ERRORED;
+                case "ignore":
+                    return AppOpsManager.MODE_IGNORED;
+                case "default":
+                    return AppOpsManager.MODE_DEFAULT;
+            }
+            try {
+                return Integer.parseInt(modeStr);
+            } catch (NumberFormatException e) {
+            }
+            err.println("Error: Mode " + modeStr + " is not valid");
+            return -1;
+        }
+
+        int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
+            userId = UserHandle.USER_CURRENT;
+            opStr = null;
+            modeStr = null;
+            for (String argument; (argument = getNextArg()) != null;) {
+                if ("--user".equals(argument)) {
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                } else {
+                    if (opStr == null) {
+                        opStr = argument;
+                    } else if (modeStr == null) {
+                        modeStr = argument;
+                        break;
+                    }
+                }
+            }
+            if (opStr == null) {
+                err.println("Error: Operation not specified.");
+                return -1;
+            }
+            op = strOpToOp(opStr, err);
+            if (op < 0) {
+                return -1;
+            }
+            if (modeStr != null) {
+                if ((mode=strModeToMode(modeStr, err)) < 0) {
+                    return -1;
+                }
+            } else {
+                mode = defMode;
+            }
+            return 0;
+        }
+
         int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
             userId = UserHandle.USER_CURRENT;
             packageName = null;
@@ -1697,6 +1837,8 @@
         pw.println("    Set the mode for a particular application and operation.");
         pw.println("  get [--user <USER_ID>] <PACKAGE> [<OP>]");
         pw.println("    Return the mode for a particular application and optional operation.");
+        pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
+        pw.println("    Print all packages that currently have the given op in the given mode.");
         pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
         pw.println("    Reset the given application or all applications to default modes.");
         pw.println("  write-settings");
@@ -1730,23 +1872,9 @@
                         return -1;
                     }
 
-                    final int mode;
-                    switch (modeStr) {
-                        case "allow":
-                            mode = AppOpsManager.MODE_ALLOWED;
-                            break;
-                        case "deny":
-                            mode = AppOpsManager.MODE_ERRORED;
-                            break;
-                        case "ignore":
-                            mode = AppOpsManager.MODE_IGNORED;
-                            break;
-                        case "default":
-                            mode = AppOpsManager.MODE_DEFAULT;
-                            break;
-                        default:
-                            err.println("Error: Mode " + modeStr + " is not valid,");
-                            return -1;
+                    final int mode = shell.strModeToMode(modeStr, err);
+                    if (mode < 0) {
+                        return -1;
                     }
 
                     shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode);
@@ -1811,6 +1939,34 @@
                     }
                     return 0;
                 }
+                case "query-op": {
+                    int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
+                    if (res < 0) {
+                        return res;
+                    }
+                    List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
+                            new int[] {shell.op});
+                    if (ops == null || ops.size() <= 0) {
+                        pw.println("No operations.");
+                        return 0;
+                    }
+                    for (int i=0; i<ops.size(); i++) {
+                        final AppOpsManager.PackageOps pkg = ops.get(i);
+                        boolean hasMatch = false;
+                        final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
+                        for (int j=0; j<entries.size(); j++) {
+                            AppOpsManager.OpEntry ent = entries.get(j);
+                            if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
+                                hasMatch = true;
+                                break;
+                            }
+                        }
+                        if (hasMatch) {
+                            pw.println(pkg.getPackageName());
+                        }
+                    }
+                    return 0;
+                }
                 case "reset": {
                     String packageName = null;
                     int userId = UserHandle.USER_CURRENT;
@@ -2058,6 +2214,7 @@
     @Override
     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
         checkSystemUid("setUserRestrictions");
+        Preconditions.checkNotNull(restrictions);
         Preconditions.checkNotNull(token);
         final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
         for (int i = 0; i < opRestrictions.length; ++i) {
@@ -2069,7 +2226,8 @@
     }
 
     @Override
-    public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle) {
+    public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
+            String[] exceptionPackages) {
         if (Binder.getCallingPid() != Process.myPid()) {
             mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
                     Binder.getCallingPid(), Binder.getCallingUid(), null);
@@ -2085,12 +2243,40 @@
         }
         verifyIncomingOp(code);
         Preconditions.checkNotNull(token);
-        setUserRestrictionNoCheck(code, restricted, token, userHandle);
+        setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
     }
 
     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
             int userHandle) {
+        setUserRestrictionNoCheck(code, restricted, token, userHandle, /*exceptionPackages*/null);
+    }
+
+    private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
+            int userHandle, String[] exceptionPackages) {
+
         final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
+
+        if (restricted) {
+            final SparseArray<ArraySet<String>> opExceptions =
+                    getUserPackageExemptionsForToken(token, userHandle);
+
+            ArraySet<String> exceptions = opExceptions.get(code);
+            if (exceptionPackages != null && exceptionPackages.length > 0) {
+                if (exceptions == null) {
+                    exceptions = new ArraySet<>(exceptionPackages.length);
+                    opExceptions.put(code, exceptions);
+                } else {
+                    exceptions.clear();
+                }
+
+                for (String p : exceptionPackages) {
+                    exceptions.add(p);
+                }
+            } else {
+                opExceptions.remove(code);
+            }
+        }
+
         if (opRestrictions[code] == restricted) {
             return;
         }
@@ -2099,6 +2285,10 @@
             pruneUserRestrictionsForToken(token, userHandle);
         }
 
+        notifyWatchersOfChange(code);
+    }
+
+    private void notifyWatchersOfChange(int code) {
         final ArrayList<Callback> clonedCallbacks;
         synchronized (this) {
             ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
@@ -2132,7 +2322,8 @@
         checkSystemUid("removeUser");
         final int tokenCount = mOpUserRestrictions.size();
         for (int i = tokenCount - 1; i >= 0; i--) {
-            SparseArray<boolean[]> opRestrictions = mOpUserRestrictions.valueAt(i);
+            SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> opRestrictions =
+                    mOpUserRestrictions.valueAt(i);
             if (opRestrictions != null) {
                 opRestrictions.remove(userHandle);
                 if (opRestrictions.size() <= 0) {
@@ -2144,15 +2335,32 @@
 
 
     private void pruneUserRestrictionsForToken(IBinder token, int userHandle) {
-        SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token);
+        SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions =
+                mOpUserRestrictions.get(token);
         if (perTokenRestrictions != null) {
-            final boolean[] opRestrictions = perTokenRestrictions.get(userHandle);
-            if (opRestrictions != null) {
-                for (boolean restriction : opRestrictions) {
-                    if (restriction) {
-                        return;
+            final Pair<boolean[], SparseArray<ArraySet<String>>> restrictions =
+                    perTokenRestrictions.get(userHandle);
+
+            if (restrictions != null) {
+                final boolean[] opRestrictions = restrictions.first;
+                final SparseArray<ArraySet<String>> opExceptions = restrictions.second;
+                boolean stillHasRestrictions = false;
+                if (opRestrictions != null) {
+                    for (int i = 0; i < opRestrictions.length; i++) {
+                        boolean restriction = opRestrictions[i];
+                        if (restriction) {
+                            stillHasRestrictions = true;
+                        } else {
+                            opExceptions.remove(i);
+                        }
                     }
                 }
+
+                if (stillHasRestrictions) {
+                    return;
+                }
+
+                // No restrictions set for this client
                 perTokenRestrictions.remove(userHandle);
                 if (perTokenRestrictions.size() <= 0) {
                     mOpUserRestrictions.remove(token);
@@ -2161,18 +2369,61 @@
         }
     }
 
+    /**
+     * Get or create the user restrictions array for a given client if it doesn't already exist.
+     *
+     * @param token the binder client creating the restriction.
+     * @param userHandle the user handle to create a restriction for.
+     *
+     * @return the array of restriction states for each AppOps code.
+     */
     private boolean[] getOrCreateUserRestrictionsForToken(IBinder token, int userHandle) {
-        SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token);
+        SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions =
+                mOpUserRestrictions.get(token);
+
         if (perTokenRestrictions == null) {
-            perTokenRestrictions = new SparseArray<>();
+            perTokenRestrictions =
+                    new SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>();
             mOpUserRestrictions.put(token, perTokenRestrictions);
         }
-        boolean[] opRestrictions = perTokenRestrictions.get(userHandle);
-        if (opRestrictions == null) {
-            opRestrictions = new boolean[AppOpsManager._NUM_OP];
-            perTokenRestrictions.put(userHandle, opRestrictions);
+
+        Pair<boolean[], SparseArray<ArraySet<String>>> restrictions =
+                perTokenRestrictions.get(userHandle);
+
+        if (restrictions == null) {
+            restrictions = new Pair<boolean[], SparseArray<ArraySet<String>>>(
+                    new boolean[AppOpsManager._NUM_OP], new SparseArray<ArraySet<String>>());
+            perTokenRestrictions.put(userHandle, restrictions);
         }
-        return opRestrictions;
+
+        return restrictions.first;
+    }
+
+    /**
+     * Get the per-package exemptions for each AppOps code for a given client and userHandle.
+     *
+     * @param token the binder client to get the exemptions for.
+     * @param userHandle the user handle to get the exemptions for.
+     *
+     * @return a mapping from the AppOps code to a set of packages exempt for that code.
+     */
+    private SparseArray<ArraySet<String>> getUserPackageExemptionsForToken(IBinder token,
+            int userHandle) {
+        SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>> perTokenRestrictions =
+                mOpUserRestrictions.get(token);
+
+        if (perTokenRestrictions == null) {
+            return null; // Don't create user restrictions accidentally
+        }
+
+        Pair<boolean[], SparseArray<ArraySet<String>>> restrictions =
+                perTokenRestrictions.get(userHandle);
+
+        if (restrictions == null) {
+            return null; // Don't create user restrictions accidentally
+        }
+
+        return restrictions.second;
     }
 
     private void checkSystemUid(String function) {
@@ -2182,6 +2433,17 @@
         }
     }
 
+    private static String resolvePackageName(int uid, String packageName)  {
+        if (uid == 0) {
+            return "root";
+        } else if (uid == Process.SHELL_UID) {
+            return "com.android.shell";
+        } else if (uid == Process.SYSTEM_UID && packageName == null) {
+            return "android";
+        }
+        return packageName;
+    }
+
     private static String[] getPackagesForUid(int uid) {
         String[] packageNames = null;
         try {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 6d0d9e9..0a814ab 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -19,7 +19,6 @@
 import android.Manifest;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.IBluetooth;
 import android.bluetooth.IBluetoothCallback;
@@ -44,7 +43,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -53,10 +51,9 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
-import android.util.Log;
+import android.util.Slog;
 
 import java.io.FileDescriptor;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.Map;
@@ -92,14 +89,16 @@
     private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
     private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
     private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
-    private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
-    private static final int MESSAGE_TIMEOUT_BIND =100;
-    private static final int MESSAGE_TIMEOUT_UNBIND =101;
+    private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
+    private static final int MESSAGE_TIMEOUT_BIND = 100;
+    private static final int MESSAGE_TIMEOUT_UNBIND = 101;
+    private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200;
     private static final int MESSAGE_USER_SWITCHED = 300;
+    private static final int MESSAGE_USER_UNLOCKED = 301;
     private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
     private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
-    private static final int MAX_SAVE_RETRIES=3;
-    private static final int MAX_ERROR_RESTART_RETRIES=6;
+    private static final int MAX_SAVE_RETRIES = 3;
+    private static final int MAX_ERROR_RESTART_RETRIES = 6;
 
     // Bluetooth persisted setting is off
     private static final int BLUETOOTH_OFF=0;
@@ -176,7 +175,7 @@
             String action = intent.getAction();
             if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
                 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
-                if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
+                if (DBG) Slog.d(TAG, "Bluetooth Adapter name changed to " + newName);
                 if (newName != null) {
                     storeNameAndAddress(newName, null);
                 }
@@ -195,10 +194,10 @@
                         try {
                             st = mBluetooth.getState();
                         } catch (RemoteException e) {
-                            Log.e(TAG,"Unable to call getState", e);
+                            Slog.e(TAG,"Unable to call getState", e);
                         }
                     }
-                    Log.d(TAG, "state" + st);
+                    Slog.d(TAG, "state" + st);
 
                     if (isAirplaneModeOn()) {
                         // Clear registered LE apps to force shut-off
@@ -214,16 +213,16 @@
                                     mEnableExternal = false;
                                 }
                             } catch(RemoteException e) {
-                                Log.e(TAG,"Unable to call onBrEdrDown", e);
+                                Slog.e(TAG,"Unable to call onBrEdrDown", e);
                             }
                         } else if (st == BluetoothAdapter.STATE_ON){
                             // disable without persisting the setting
-                            Log.d(TAG, "Calling disable");
+                            Slog.d(TAG, "Calling disable");
                             sendDisableMsg();
                         }
                     } else if (mEnableExternal) {
                         // enable without persisting the setting
-                        Log.d(TAG, "Calling enable");
+                        Slog.d(TAG, "Calling enable");
                         sendEnableMsg(mQuietEnableExternal);
                     }
                 }
@@ -267,7 +266,7 @@
                     PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
         } catch (PackageManager.NameNotFoundException e) {
             // Some platforms, such as wearables do not have a system ui.
-            Log.w(TAG, "Unable to resolve SystemUI's UID.", e);
+            Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
         }
         mSystemUiUid = sysUiUid;
     }
@@ -320,17 +319,17 @@
      * in the local cache
      */
     private void loadStoredNameAndAddress() {
-        if (DBG) Log.d(TAG, "Loading stored name and address");
+        if (DBG) Slog.d(TAG, "Loading stored name and address");
         if (mContext.getResources().getBoolean
             (com.android.internal.R.bool.config_bluetooth_address_validation) &&
              Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
             // if the valid flag is not set, don't load the address and name
-            if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
+            if (DBG) Slog.d(TAG, "invalid bluetooth name and address stored");
             return;
         }
         mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
         mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
-        if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
+        if (DBG) Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
     }
 
     /**
@@ -343,14 +342,14 @@
         if (name != null) {
             Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
             mName = name;
-            if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
+            if (DBG) Slog.d(TAG,"Stored Bluetooth name: " +
                 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
         }
 
         if (address != null) {
             Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
             mAddress=address;
-            if (DBG)  Log.d(TAG,"Stored Bluetoothaddress: " +
+            if (DBG)  Slog.d(TAG,"Stored Bluetoothaddress: " +
                 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
         }
 
@@ -361,7 +360,7 @@
 
     public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
         if (callback == null) {
-            Log.w(TAG, "Callback is null in registerAdapter");
+            Slog.w(TAG, "Callback is null in registerAdapter");
             return null;
         }
         Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
@@ -374,7 +373,7 @@
 
     public void unregisterAdapter(IBluetoothManagerCallback callback) {
         if (callback == null) {
-            Log.w(TAG, "Callback is null in unregisterAdapter");
+            Slog.w(TAG, "Callback is null in unregisterAdapter");
             return;
         }
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
@@ -403,7 +402,7 @@
     public boolean isEnabled() {
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
             (!checkIfCallerIsForegroundUser())) {
-            Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
+            Slog.w(TAG,"isEnabled(): not allowed for non-active and non system user");
             return false;
         }
 
@@ -411,7 +410,7 @@
             try {
                 return (mBluetooth != null && mBluetooth.isEnabled());
             } catch (RemoteException e) {
-                Log.e(TAG, "isEnabled()", e);
+                Slog.e(TAG, "isEnabled()", e);
             }
         }
         return false;
@@ -419,17 +418,17 @@
 
     class ClientDeathRecipient implements IBinder.DeathRecipient {
         public void binderDied() {
-            if (DBG) Log.d(TAG, "Binder is dead -  unregister Ble App");
+            if (DBG) Slog.d(TAG, "Binder is dead -  unregister Ble App");
             if (mBleAppCount > 0) --mBleAppCount;
 
             if (mBleAppCount == 0) {
-                if (DBG) Log.d(TAG, "Disabling LE only mode after application crash");
+                if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
                 try {
                     if (mBluetooth != null) {
                         mBluetooth.onBrEdrDown();
                     }
                 } catch(RemoteException e) {
-                     Log.e(TAG,"Unable to call onBrEdrDown", e);
+                     Slog.e(TAG,"Unable to call onBrEdrDown", e);
                 }
             }
         }
@@ -459,7 +458,7 @@
                     try {
                         if (mBluetooth != null) mBluetooth.onBrEdrDown();
                     } catch (RemoteException e) {
-                        Log.e(TAG, "error when disabling bluetooth", e);
+                        Slog.e(TAG, "error when disabling bluetooth", e);
                     }
                 }
             }
@@ -474,11 +473,11 @@
     private void disableBleScanMode() {
         try {
             if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
-                if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
+                if (DBG) Slog.d(TAG, "Reseting the mEnable flag for clean disable");
                 mEnable = false;
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "getState()", e);
+            Slog.e(TAG, "getState()", e);
         }
     }
 
@@ -496,7 +495,7 @@
                 synchronized (this) {
                     ++mBleAppCount;
                 }
-                if (DBG) Log.d(TAG, "Registered for death Notification");
+                if (DBG) Slog.d(TAG, "Registered for death Notification");
             }
 
         } else  {
@@ -508,10 +507,10 @@
                 synchronized (this) {
                     if (mBleAppCount > 0) --mBleAppCount;
                 }
-                if (DBG) Log.d(TAG, "Unregistered for death Notification");
+                if (DBG) Slog.d(TAG, "Unregistered for death Notification");
             }
         }
-        if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
+        if (DBG) Slog.d(TAG, "Updated BleAppCount" + mBleAppCount);
         if (mBleAppCount == 0 && mEnable) {
             disableBleScanMode();
         }
@@ -528,7 +527,7 @@
 
     /** @hide*/
     public boolean isBleAppPresent() {
-        if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
+        if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
         return (mBleAppCount > 0);
     }
 
@@ -536,7 +535,7 @@
      * Action taken when GattService is turned off
      */
     private void onBluetoothGattServiceUp() {
-        if (DBG) Log.d(TAG,"BluetoothGatt Service is Up");
+        if (DBG) Slog.d(TAG,"BluetoothGatt Service is Up");
         try{
             if (isBleAppPresent() == false && mBluetooth != null
                   && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
@@ -548,7 +547,7 @@
                 Binder.restoreCallingIdentity(callingIdentity);
             }
         } catch(RemoteException e) {
-                Log.e(TAG,"Unable to call onServiceUp", e);
+                Slog.e(TAG,"Unable to call onServiceUp", e);
         }
     }
 
@@ -557,10 +556,10 @@
      * and turn off all service and stack if no LE app needs it
      */
     private void sendBrEdrDownCallback() {
-        if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks");
+        if (DBG) Slog.d(TAG,"Calling sendBrEdrDownCallback callbacks");
 
         if(mBluetooth == null) {
-            Log.w(TAG, "Bluetooth handle is null");
+            Slog.w(TAG, "Bluetooth handle is null");
             return;
         }
 
@@ -568,14 +567,14 @@
             try {
                 mBluetooth.onBrEdrDown();
             } catch(RemoteException e) {
-                Log.e(TAG, "Call to onBrEdrDown() failed.", e);
+                Slog.e(TAG, "Call to onBrEdrDown() failed.", e);
             }
         } else {
             // Need to stay at BLE ON. Disconnect all Gatt connections
             try{
                 mBluetoothGatt.unregAll();
             } catch(RemoteException e) {
-                Log.e(TAG, "Unable to disconnect all apps.", e);
+                Slog.e(TAG, "Unable to disconnect all apps.", e);
             }
         }
     }
@@ -586,7 +585,7 @@
                                                 "Need BLUETOOTH ADMIN permission");
 
         if (DBG) {
-            Log.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
+            Slog.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
                     " mBinding = " + mBinding);
         }
         int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
@@ -601,19 +600,19 @@
             sendEnableMsg(true);
         }
         return true;
-
     }
+
     public boolean enable() {
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
             (!checkIfCallerIsForegroundUser())) {
-            Log.w(TAG,"enable(): not allowed for non-active and non system user");
+            Slog.w(TAG,"enable(): not allowed for non-active and non system user");
             return false;
         }
 
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH ADMIN permission");
         if (DBG) {
-            Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
+            Slog.d(TAG,"enable():  mBluetooth =" + mBluetooth +
                     " mBinding = " + mBinding);
         }
 
@@ -623,7 +622,7 @@
             // waive WRITE_SECURE_SETTINGS permission check
             sendEnableMsg(false);
         }
-        if (DBG) Log.d(TAG, "enable returning");
+        if (DBG) Slog.d(TAG, "enable returning");
         return true;
     }
 
@@ -633,12 +632,12 @@
 
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
             (!checkIfCallerIsForegroundUser())) {
-            Log.w(TAG,"disable(): not allowed for non-active and non system user");
+            Slog.w(TAG,"disable(): not allowed for non-active and non system user");
             return false;
         }
 
         if (DBG) {
-            Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
+            Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth +
                 " mBinding = " + mBinding);
         }
 
@@ -657,7 +656,7 @@
 
     public void unbindAndFinish() {
         if (DBG) {
-            Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
+            Slog.d(TAG,"unbindAndFinish(): " + mBluetooth +
                 " mBinding = " + mBinding);
         }
 
@@ -669,10 +668,10 @@
                 try {
                     mBluetooth.unregisterCallback(mBluetoothCallback);
                 } catch (RemoteException re) {
-                    Log.e(TAG, "Unable to unregister BluetoothCallback",re);
+                    Slog.e(TAG, "Unable to unregister BluetoothCallback",re);
                 }
 
-                if (DBG) Log.d(TAG, "Sending unbind request.");
+                if (DBG) Slog.d(TAG, "Sending unbind request.");
                 mBluetoothBinder = null;
                 mBluetooth = null;
                 //Unbind
@@ -696,7 +695,7 @@
             IBluetoothProfileServiceConnection proxy) {
         if (!mEnable) {
             if (DBG) {
-                Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
+                Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
                         ", while Bluetooth was disabled");
             }
             return false;
@@ -705,7 +704,7 @@
             ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
             if (psc == null) {
                 if (DBG) {
-                    Log.d(TAG, "Creating new ProfileServiceConnections object for"
+                    Slog.d(TAG, "Creating new ProfileServiceConnections object for"
                             + " profile: " + bluetoothProfile);
                 }
 
@@ -746,7 +745,7 @@
                 try {
                     mContext.unbindService(psc);
                 } catch (IllegalArgumentException e) {
-                    Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
+                    Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
                 }
                 psc.removeAllProxies();
             }
@@ -759,10 +758,14 @@
      * PHASE_SYSTEM_SERVICES_READY.
      */
     public void handleOnBootPhase() {
-        if (DBG) Log.d(TAG, "Bluetooth boot completed");
+        if (DBG) Slog.d(TAG, "Bluetooth boot completed");
         if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
-            if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
+            if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
             sendEnableMsg(mQuietEnableExternal);
+        } else if (!isNameAndAddressSet()) {
+            if (DBG) Slog.d(TAG, "Getting adapter name and address");
+            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+            mHandler.sendMessage(getMsg);
         }
     }
 
@@ -770,8 +773,16 @@
      * Called when switching to a different foreground user.
      */
     public void handleOnSwitchUser(int userHandle) {
-        if (DBG) Log.d(TAG, "Bluetooth user switched");
-        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0));
+        if (DBG) Slog.d(TAG, "User " + userHandle + " switched");
+        mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget();
+    }
+
+    /**
+     * Called when user is unlocked.
+     */
+    public void handleOnUnlockUser(int userHandle) {
+        if (DBG) Slog.d(TAG, "User " + userHandle + " unlocked");
+        mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget();
     }
 
     /**
@@ -801,7 +812,7 @@
                 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
                 return true;
             }
-            Log.w(TAG, "Unable to bind with intent: " + mIntent);
+            Slog.w(TAG, "Unable to bind with intent: " + mIntent);
             return false;
         }
 
@@ -811,7 +822,7 @@
                 try{
                     proxy.onServiceConnected(mClassName, mService);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Unable to connect to proxy", e);
+                    Slog.e(TAG, "Unable to connect to proxy", e);
                 }
             } else {
                 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
@@ -828,11 +839,11 @@
                     try {
                         proxy.onServiceDisconnected(mClassName);
                     } catch (RemoteException e) {
-                        Log.e(TAG, "Unable to disconnect proxy", e);
+                        Slog.e(TAG, "Unable to disconnect proxy", e);
                     }
                 }
             } else {
-                Log.w(TAG, "Trying to remove a null proxy");
+                Slog.w(TAG, "Trying to remove a null proxy");
             }
         }
 
@@ -850,11 +861,11 @@
             try {
                 mService.linkToDeath(this, 0);
             } catch (RemoteException e) {
-                Log.e(TAG, "Unable to linkToDeath", e);
+                Slog.e(TAG, "Unable to linkToDeath", e);
             }
 
             if (mInvokingProxyCallbacks) {
-                Log.e(TAG, "Proxy callbacks already in progress.");
+                Slog.e(TAG, "Proxy callbacks already in progress.");
                 return;
             }
             mInvokingProxyCallbacks = true;
@@ -865,7 +876,7 @@
                     try {
                         mProxies.getBroadcastItem(i).onServiceConnected(className, service);
                     } catch (RemoteException e) {
-                        Log.e(TAG, "Unable to connect to proxy", e);
+                        Slog.e(TAG, "Unable to connect to proxy", e);
                     }
                 }
             } finally {
@@ -882,7 +893,7 @@
             mClassName = null;
 
             if (mInvokingProxyCallbacks) {
-                Log.e(TAG, "Proxy callbacks already in progress.");
+                Slog.e(TAG, "Proxy callbacks already in progress.");
                 return;
             }
             mInvokingProxyCallbacks = true;
@@ -893,7 +904,7 @@
                     try {
                         mProxies.getBroadcastItem(i).onServiceDisconnected(className);
                     } catch (RemoteException e) {
-                        Log.e(TAG, "Unable to disconnect from proxy", e);
+                        Slog.e(TAG, "Unable to disconnect from proxy", e);
                     }
                 }
             } finally {
@@ -905,7 +916,7 @@
         @Override
         public void binderDied() {
             if (DBG) {
-                Log.w(TAG, "Profile service for profile: " + mClassName
+                Slog.w(TAG, "Profile service for profile: " + mClassName
                         + " died.");
             }
             onServiceDisconnected(mClassName);
@@ -919,12 +930,12 @@
     private void sendBluetoothStateCallback(boolean isUp) {
         try {
             int n = mStateChangeCallbacks.beginBroadcast();
-            if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
+            if (DBG) Slog.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
             for (int i=0; i <n;i++) {
                 try {
                     mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
+                    Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
                 }
             }
         } finally {
@@ -936,15 +947,15 @@
      * Inform BluetoothAdapter instances that Adapter service is up
      */
     private void sendBluetoothServiceUpCallback() {
-        if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
+        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceUp callbacks");
         try {
             int n = mCallbacks.beginBroadcast();
-            Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
+            Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
             for (int i=0; i <n;i++) {
                 try {
                     mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
                 }  catch (RemoteException e) {
-                    Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
+                    Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
                 }
             }
         } finally {
@@ -955,15 +966,15 @@
      * Inform BluetoothAdapter instances that Adapter service is down
      */
     private void sendBluetoothServiceDownCallback() {
-        if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
+        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceDown callbacks");
         try {
             int n = mCallbacks.beginBroadcast();
-            Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
+            Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
             for (int i=0; i <n;i++) {
                 try {
                     mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
                 }  catch (RemoteException e) {
-                    Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
+                    Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
                 }
             }
         } finally {
@@ -977,7 +988,7 @@
 
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
                 (!checkIfCallerIsForegroundUser())) {
-            Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
+            Slog.w(TAG,"getAddress(): not allowed for non-active and non system user");
             return null;
         }
 
@@ -991,10 +1002,11 @@
                 try {
                     return mBluetooth.getAddress();
                 } catch (RemoteException e) {
-                    Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
+                    Slog.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
                 }
             }
         }
+
         // mAddress is accessed from outside.
         // It is alright without a lock. Here, bluetooth is off, no other thread is
         // changing mAddress
@@ -1007,7 +1019,7 @@
 
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
             (!checkIfCallerIsForegroundUser())) {
-            Log.w(TAG,"getName(): not allowed for non-active and non system user");
+            Slog.w(TAG,"getName(): not allowed for non-active and non system user");
             return null;
         }
 
@@ -1016,7 +1028,7 @@
                 try {
                     return mBluetooth.getName();
                 } catch (RemoteException e) {
-                    Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
+                    Slog.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
                 }
             }
         }
@@ -1028,7 +1040,7 @@
 
     private class BluetoothServiceConnection implements ServiceConnection {
         public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
+            if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
             // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
             if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
@@ -1037,7 +1049,7 @@
             } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
                 msg.arg1 = SERVICE_IBLUETOOTHGATT;
             } else {
-                Log.e(TAG, "Unknown service connected: " + className.getClassName());
+                Slog.e(TAG, "Unknown service connected: " + className.getClassName());
                 return;
             }
             msg.obj = service;
@@ -1046,7 +1058,7 @@
 
         public void onServiceDisconnected(ComponentName className) {
             // Called if we unexpected disconnected.
-            if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
+            if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " +
                            className.getClassName());
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
             if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
@@ -1054,7 +1066,7 @@
             } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
                 msg.arg1 = SERVICE_IBLUETOOTHGATT;
             } else {
-                Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
+                Slog.e(TAG, "Unknown service disconnected: " + className.getClassName());
                 return;
             }
             mHandler.sendMessage(msg);
@@ -1064,17 +1076,50 @@
     private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
 
     private class BluetoothHandler extends Handler {
+        boolean mGetNameAddressOnly = false;
+
         public BluetoothHandler(Looper looper) {
             super(looper);
         }
 
         @Override
         public void handleMessage(Message msg) {
-            if (DBG) Log.d (TAG, "Message: " + msg.what);
+            if (DBG) Slog.d (TAG, "Message: " + msg.what);
             switch (msg.what) {
+                case MESSAGE_GET_NAME_AND_ADDRESS:
+                    if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
+                    synchronized(mConnection) {
+                        if ((mBluetooth == null) && (!mBinding)) {
+                            if (DBG) Slog.d(TAG, "Binding to service to get name and address");
+                            mGetNameAddressOnly = true;
+                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
+                            mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
+                            Intent i = new Intent(IBluetooth.class.getName());
+                            if (!doBind(i, mConnection,
+                                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+                                UserHandle.CURRENT)) {
+                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+                            } else {
+                                mBinding = true;
+                            }
+                        } else if (mBluetooth != null) {
+                            try {
+                                storeNameAndAddress(mBluetooth.getName(),
+                                                    mBluetooth.getAddress());
+                            } catch (RemoteException re) {
+                                Slog.e(TAG, "Unable to grab names", re);
+                            }
+                            if (mGetNameAddressOnly && !mEnable) {
+                                unbindAndFinish();
+                            }
+                            mGetNameAddressOnly = false;
+                        }
+                    }
+                    break;
+
                 case MESSAGE_ENABLE:
                     if (DBG) {
-                        Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
+                        Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
                     }
                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                     mEnable = true;
@@ -1098,14 +1143,14 @@
                 {
                     IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
                     boolean added = mCallbacks.register(callback);
-                    Log.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
+                    Slog.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
                 }
                     break;
                 case MESSAGE_UNREGISTER_ADAPTER:
                 {
                     IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
                     boolean removed = mCallbacks.unregister(callback);
-                    Log.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
+                    Slog.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
                     break;
                 }
                 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
@@ -1148,7 +1193,7 @@
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
                 {
-                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
+                    if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
 
                     IBinder service = (IBinder) msg.obj;
                     synchronized(mConnection) {
@@ -1165,21 +1210,27 @@
                         mBluetoothBinder = service;
                         mBluetooth = IBluetooth.Stub.asInterface(service);
 
+                        if (!isNameAndAddressSet()) {
+                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+                            mHandler.sendMessage(getMsg);
+                            if (mGetNameAddressOnly) return;
+                        }
+
                         try {
                             boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
                                 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
                             if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
-                                Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
+                                Slog.e(TAG,"IBluetooth.configHciSnoopLog return false");
                             }
                         } catch (RemoteException e) {
-                            Log.e(TAG,"Unable to call configHciSnoopLog", e);
+                            Slog.e(TAG,"Unable to call configHciSnoopLog", e);
                         }
 
                         //Register callback object
                         try {
                             mBluetooth.registerCallback(mBluetoothCallback);
                         } catch (RemoteException re) {
-                            Log.e(TAG, "Unable to register BluetoothCallback",re);
+                            Slog.e(TAG, "Unable to register BluetoothCallback",re);
                         }
                         //Inform BluetoothAdapter instances that service is up
                         sendBluetoothServiceUpCallback();
@@ -1188,17 +1239,17 @@
                         try {
                             if (mQuietEnable == false) {
                                 if(!mBluetooth.enable()) {
-                                    Log.e(TAG,"IBluetooth.enable() returned false");
+                                    Slog.e(TAG,"IBluetooth.enable() returned false");
                                 }
                             }
                             else
                             {
                                 if(!mBluetooth.enableNoAutoConnect()) {
-                                    Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+                                    Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
                                 }
                             }
                         } catch (RemoteException e) {
-                            Log.e(TAG,"Unable to call enable()",e);
+                            Slog.e(TAG,"Unable to call enable()",e);
                         }
                     }
 
@@ -1210,7 +1261,7 @@
                     break;
                 }
                 case MESSAGE_TIMEOUT_BIND: {
-                    Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
+                    Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
                     synchronized(mConnection) {
                         mBinding = false;
                     }
@@ -1220,7 +1271,7 @@
                 {
                     int prevState = msg.arg1;
                     int newState = msg.arg2;
-                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
+                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
                     mState = newState;
                     bluetoothStateChangeHandler(prevState, newState);
                     // handle error state transition case from TURNING_ON to OFF
@@ -1239,7 +1290,7 @@
                         newState == BluetoothAdapter.STATE_BLE_ON) {
                         // bluetooth is working, reset the counter
                         if (mErrorRecoveryRetryCounter != 0) {
-                            Log.w(TAG, "bluetooth is recovered from error");
+                            Slog.w(TAG, "bluetooth is recovered from error");
                             mErrorRecoveryRetryCounter = 0;
                         }
                     }
@@ -1247,7 +1298,7 @@
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
                 {
-                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
+                    Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
                     synchronized(mConnection) {
                         if (msg.arg1 == SERVICE_IBLUETOOTH) {
                             // if service is unbinded already, do nothing and return
@@ -1257,7 +1308,7 @@
                             mBluetoothGatt = null;
                             break;
                         } else {
-                            Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
+                            Slog.e(TAG, "Bad msg.arg1: " + msg.arg1);
                             break;
                         }
                     }
@@ -1292,7 +1343,7 @@
                 }
                 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
                 {
-                    Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
+                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
                         +" Restart IBluetooth service");
                     /* Enable without persisting the setting as
                      it doesnt change when IBluetooth
@@ -1304,19 +1355,17 @@
 
                 case MESSAGE_TIMEOUT_UNBIND:
                 {
-                    Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
+                    Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
                     synchronized(mConnection) {
                         mUnbinding = false;
                     }
                     break;
                 }
 
-                case MESSAGE_USER_SWITCHED:
-                {
-                    if (DBG) {
-                        Log.d(TAG, "MESSAGE_USER_SWITCHED");
-                    }
+                case MESSAGE_USER_SWITCHED: {
+                    if (DBG) Slog.d(TAG, "MESSAGE_USER_SWITCHED");
                     mHandler.removeMessages(MESSAGE_USER_SWITCHED);
+
                     /* disable and enable BT when detect a user switch */
                     if (mEnable && mBluetooth != null) {
                         synchronized (mConnection) {
@@ -1325,7 +1374,7 @@
                                 try {
                                     mBluetooth.unregisterCallback(mBluetoothCallback);
                                 } catch (RemoteException re) {
-                                    Log.e(TAG, "Unable to unregister",re);
+                                    Slog.e(TAG, "Unable to unregister",re);
                                 }
                             }
                         }
@@ -1379,11 +1428,25 @@
                         // delay sending MESSAGE_USER_SWITCHED
                         mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
                         if (DBG) {
-                            Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
+                            Slog.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
                         }
                     }
                     break;
                 }
+                case MESSAGE_USER_UNLOCKED: {
+                    if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
+                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
+
+                    synchronized (mConnection) {
+                        if (mEnable && !mBinding && (mBluetooth == null)) {
+                            // We should be connected, but we gave up for some
+                            // reason; maybe the Bluetooth service wasn't encryption
+                            // aware, so try binding again.
+                            if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
+                            handleEnable(mQuietEnable);
+                        }
+                    }
+                }
             }
         }
     }
@@ -1408,16 +1471,16 @@
                 try {
                     if (!mQuietEnable) {
                         if(!mBluetooth.enable()) {
-                            Log.e(TAG,"IBluetooth.enable() returned false");
+                            Slog.e(TAG,"IBluetooth.enable() returned false");
                         }
                     }
                     else {
                         if(!mBluetooth.enableNoAutoConnect()) {
-                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+                            Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
                         }
                     }
                 } catch (RemoteException e) {
-                    Log.e(TAG,"Unable to call enable()",e);
+                    Slog.e(TAG,"Unable to call enable()",e);
                 }
             }
         }
@@ -1427,7 +1490,7 @@
         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
         intent.setComponent(comp);
         if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
-            Log.e(TAG, "Fail to bind to: " + intent);
+            Slog.e(TAG, "Fail to bind to: " + intent);
             return false;
         }
         return true;
@@ -1436,14 +1499,14 @@
     private void handleDisable() {
         synchronized(mConnection) {
             if (mBluetooth != null) {
-                if (DBG) Log.d(TAG,"Sending off request.");
+                if (DBG) Slog.d(TAG,"Sending off request.");
 
                 try {
                     if(!mBluetooth.disable()) {
-                        Log.e(TAG,"IBluetooth.disable() returned false");
+                        Slog.e(TAG,"IBluetooth.disable() returned false");
                     }
                 } catch (RemoteException e) {
-                    Log.e(TAG,"Unable to call disable()",e);
+                    Slog.e(TAG,"Unable to call disable()",e);
                 }
             }
         }
@@ -1466,7 +1529,7 @@
                     callingAppId == Process.NFC_UID ||
                     callingAppId == mSystemUiUid;
             if (DBG) {
-                Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
+                Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
                     + " callingUser=" + callingUser
                     + " parentUser=" + parentUser
                     + " foregroundUser=" + foregroundUser);
@@ -1478,7 +1541,7 @@
     }
 
     private void sendBleStateChanged(int prevState, int newState) {
-        if (DBG) Log.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
+        if (DBG) Slog.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
         // Send broadcast message to everyone else
         Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
         intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
@@ -1498,9 +1561,9 @@
 
                 if (newState == BluetoothAdapter.STATE_OFF) {
                     // If Bluetooth is off, send service down event to proxy objects, and unbind
-                    if (DBG) Log.d(TAG, "Bluetooth is complete turn off");
+                    if (DBG) Slog.d(TAG, "Bluetooth is complete turn off");
                     if (canUnbindBluetoothService()) {
-                        if (DBG) Log.d(TAG, "Good to unbind!");
+                        if (DBG) Slog.d(TAG, "Good to unbind!");
                         sendBluetoothServiceDownCallback();
                         unbindAndFinish();
                         sendBleStateChanged(prevState, newState);
@@ -1510,12 +1573,12 @@
 
                 } else if (!intermediate_off) {
                     // connect to GattService
-                    if (DBG) Log.d(TAG, "Bluetooth is in LE only mode");
+                    if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
                     if (mBluetoothGatt != null) {
-                        if (DBG) Log.d(TAG, "Calling BluetoothGattServiceUp");
+                        if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
                         onBluetoothGattServiceUp();
                     } else {
-                        if (DBG) Log.d(TAG, "Binding Bluetooth GATT service");
+                        if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
                         if (mContext.getPackageManager().hasSystemFeature(
                                                         PackageManager.FEATURE_BLUETOOTH_LE)) {
                             Intent i = new Intent(IBluetoothGatt.class.getName());
@@ -1527,7 +1590,7 @@
                     isStandardBroadcast = false;
 
                 } else if (intermediate_off){
-                    if (DBG) Log.d(TAG, "Intermediate off, back to LE only mode");
+                    if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
                     // For LE only mode, broadcast as is
                     sendBleStateChanged(prevState, newState);
                     sendBluetoothStateCallback(false); // BT is OFF for general users
@@ -1583,7 +1646,7 @@
                         if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
                     }
                 } catch (RemoteException e) {
-                    Log.e(TAG, "getState()", e);
+                    Slog.e(TAG, "getState()", e);
                     break;
                 }
             }
@@ -1594,7 +1657,7 @@
             }
             i++;
         }
-        Log.e(TAG,"waitForOnOff time out");
+        Slog.e(TAG,"waitForOnOff time out");
         return false;
     }
 
@@ -1619,21 +1682,21 @@
                 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
                 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
             } catch (RemoteException e) {
-                Log.e(TAG, "getState()", e);
+                Slog.e(TAG, "getState()", e);
             }
         }
         return false;
     }
 
     private void recoverBluetoothServiceFromError() {
-        Log.e(TAG,"recoverBluetoothServiceFromError");
+        Slog.e(TAG,"recoverBluetoothServiceFromError");
         synchronized (mConnection) {
             if (mBluetooth != null) {
                 //Unregister callback object
                 try {
                     mBluetooth.unregisterCallback(mBluetoothCallback);
                 } catch (RemoteException re) {
-                    Log.e(TAG, "Unable to unregister",re);
+                    Slog.e(TAG, "Unable to unregister",re);
                 }
             }
         }
@@ -1671,16 +1734,23 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter writer, String args[]) {
-      mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-      if (mBluetoothBinder == null) {
-        writer.println("Bluetooth Service not connected");
-      } else {
-        try {
-          mBluetoothBinder.dump(fd, args);
-        } catch (RemoteException re) {
-          writer.println("RemoteException while calling Bluetooth Service");
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+        String errorMsg = null;
+        if (mBluetoothBinder == null) {
+            errorMsg = "Bluetooth Service not connected";
+        } else {
+            try {
+                mBluetoothBinder.dump(fd, args);
+            } catch (RemoteException re) {
+                errorMsg = "RemoteException while calling Bluetooth Service";
+            }
         }
-      }
+        if (errorMsg != null) {
+            // Silently return if we are extracting metrics in Protobuf format
+            if ((args.length > 0) && args[0].startsWith("--proto"))
+                return;
+            writer.println(errorMsg);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 019d03d..1bf4e3a 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -18,10 +18,8 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
-import android.util.Log;
 
 class BluetoothService extends SystemService {
-    private static final String TAG = "BluetoothService";
     private BluetoothManagerService mBluetoothManagerService;
 
     public BluetoothService(Context context) {
@@ -36,17 +34,20 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
-            Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
-            publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService);
+            publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
+                    mBluetoothManagerService);
         } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
-            Log.d(TAG, "onBootPhase: PHASE_ACTIVITY_MANAGER_READY");
             mBluetoothManagerService.handleOnBootPhase();
         }
     }
 
     @Override
     public void onSwitchUser(int userHandle) {
-        Log.d(TAG, "onSwitchUser: switching to user " + userHandle);
         mBluetoothManagerService.handleOnSwitchUser(userHandle);
     }
+
+    @Override
+    public void onUnlockUser(int userHandle) {
+        mBluetoothManagerService.handleOnUnlockUser(userHandle);
+    }
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4300920..82a36b4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -71,6 +71,7 @@
 import android.net.RouteInfo;
 import android.net.UidRange;
 import android.net.Uri;
+import android.net.metrics.ConnectivityServiceChangeEvent;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -163,7 +164,7 @@
         implements PendingIntent.OnFinished {
     private static final String TAG = "ConnectivityService";
 
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
     private static final boolean LOGD_RULES = false;
@@ -370,8 +371,6 @@
     private int mNetTransitionWakeLockTimeout;
     private final PowerManager.WakeLock mPendingIntentWakeLock;
 
-    private InetAddress mDefaultDns;
-
     // used in DBG mode to track inet condition reports
     private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
     private ArrayList mInetLog;
@@ -447,7 +446,7 @@
      */
     private class LegacyTypeTracker {
 
-        private static final boolean DBG = true;
+        private static final boolean DBG = false;
         private static final boolean VDBG = false;
         private static final String TAG = "CSLegacyTypeTracker";
 
@@ -622,7 +621,7 @@
 
         mDefaultRequest = createInternetRequestForTransport(-1);
         NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest,
-                new Binder(), NetworkRequestInfo.REQUEST);
+                new Binder(), NetworkRequestType.REQUEST);
         mNetworkRequests.put(mDefaultRequest, defaultNRI);
         mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
 
@@ -644,19 +643,6 @@
             }
         }
 
-        // read our default dns server ip
-        String dns = Settings.Global.getString(context.getContentResolver(),
-                Settings.Global.DEFAULT_DNS_SERVER);
-        if (dns == null || dns.length() == 0) {
-            dns = context.getResources().getString(
-                    com.android.internal.R.string.config_default_dns_server);
-        }
-        try {
-            mDefaultDns = NetworkUtils.numericToInetAddress(dns);
-        } catch (IllegalArgumentException e) {
-            loge("Error setting defaultDns using " + dns);
-        }
-
         mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
 
@@ -750,7 +736,7 @@
         intentFilter.addAction(Intent.ACTION_USER_STOPPING);
         intentFilter.addAction(Intent.ACTION_USER_ADDED);
         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
-        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
+        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
         mContext.registerReceiverAsUser(
                 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
 
@@ -798,7 +784,7 @@
 
         if (enable) {
             handleRegisterNetworkRequest(new NetworkRequestInfo(
-                    null, mDefaultMobileDataRequest, new Binder(), NetworkRequestInfo.REQUEST));
+                    null, mDefaultMobileDataRequest, new Binder(), NetworkRequestType.REQUEST));
         } else {
             handleReleaseNetworkRequest(mDefaultMobileDataRequest, Process.SYSTEM_UID);
         }
@@ -1776,6 +1762,24 @@
         return false;
     }
 
+    private void dumpNetworkDiagnostics(IndentingPrintWriter pw) {
+        final List<NetworkDiagnostics> netDiags = new ArrayList<NetworkDiagnostics>();
+        final long DIAG_TIME_MS = 5000;
+        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            // Start gathering diagnostic information.
+            netDiags.add(new NetworkDiagnostics(
+                    nai.network,
+                    new LinkProperties(nai.linkProperties),  // Must be a copy.
+                    DIAG_TIME_MS));
+        }
+
+        for (NetworkDiagnostics netDiag : netDiags) {
+            pw.println();
+            netDiag.waitForMeasurements();
+            netDiag.dump(pw);
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
@@ -1788,23 +1792,8 @@
             return;
         }
 
-        final List<NetworkDiagnostics> netDiags = new ArrayList<NetworkDiagnostics>();
         if (argsContain(args, "--diag")) {
-            final long DIAG_TIME_MS = 5000;
-            for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                // Start gathering diagnostic information.
-                netDiags.add(new NetworkDiagnostics(
-                        nai.network,
-                        new LinkProperties(nai.linkProperties),  // Must be a copy.
-                        DIAG_TIME_MS));
-            }
-
-            for (NetworkDiagnostics netDiag : netDiags) {
-                pw.println();
-                netDiag.waitForMeasurements();
-                netDiag.dump(pw);
-            }
-
+            dumpNetworkDiagnostics(pw);
             return;
         }
 
@@ -1870,6 +1859,8 @@
         pw.println();
         mKeepaliveTracker.dump(pw);
 
+        pw.println();
+
         if (mInetLog != null && mInetLog.size() > 0) {
             pw.println();
             pw.println("Inet condition reports:");
@@ -1912,7 +1903,7 @@
     }
 
     private boolean isRequest(NetworkRequest request) {
-        return mNetworkRequests.get(request).isRequest;
+        return mNetworkRequests.get(request).isRequest();
     }
 
     // must be stateless - things change under us.
@@ -2131,7 +2122,7 @@
                 if (VDBG) log("NetworkFactory connected");
                 // A network factory has connected.  Send it all current NetworkRequests.
                 for (NetworkRequestInfo nri : mNetworkRequests.values()) {
-                    if (nri.isRequest == false) continue;
+                    if (!nri.isRequest()) continue;
                     NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
                     ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
                             (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
@@ -2267,7 +2258,7 @@
     private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
         mNetworkRequests.put(nri.request, nri);
         mNetworkRequestInfoLogs.log("REGISTER " + nri);
-        if (!nri.isRequest) {
+        if (!nri.isRequest()) {
             for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
                 if (nri.request.networkCapabilities.hasSignalStrength() &&
                         network.satisfiesImmutableCapabilitiesOf(nri.request)) {
@@ -2276,7 +2267,7 @@
             }
         }
         rematchAllNetworksAndRequests(null, 0);
-        if (nri.isRequest && mNetworkForRequestId.get(nri.request.requestId) == null) {
+        if (nri.isRequest() && mNetworkForRequestId.get(nri.request.requestId) == null) {
             sendUpdatedScoreToFactories(nri.request, 0);
         }
     }
@@ -2297,7 +2288,7 @@
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
             // If this Network is already the highest scoring Network for a request, or if
             // there is hope for it to become one if it validated, then it is needed.
-            if (nri.isRequest && nai.satisfies(nri.request) &&
+            if (nri.isRequest() && nai.satisfies(nri.request) &&
                     (nai.networkRequests.get(nri.request.requestId) != null ||
                     // Note that this catches two important cases:
                     // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
@@ -2325,7 +2316,7 @@
             nri.unlinkDeathRecipient();
             mNetworkRequests.remove(request);
             mNetworkRequestInfoLogs.log("RELEASE " + nri);
-            if (nri.isRequest) {
+            if (nri.isRequest()) {
                 // Find all networks that are satisfying this request and remove the request
                 // from their request lists.
                 // TODO - it's my understanding that for a request there is only a single
@@ -3227,8 +3218,12 @@
             }
             int user = UserHandle.getUserId(Binder.getCallingUid());
             synchronized(mVpns) {
-                setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user),
-                            profile));
+                Vpn vpn = mVpns.get(user);
+                if (vpn == null) {
+                    Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
+                    return false;
+                }
+                setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, vpn, profile));
             }
         } else {
             setLockdownTracker(null);
@@ -3633,7 +3628,7 @@
         }
     }
 
-    private void onUserPresent(int userId) {
+    private void onUserUnlocked(int userId) {
         // User present may be sent because of an unlock, which might mean an unlocked keystore.
         if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
             updateLockdownVpn();
@@ -3657,8 +3652,8 @@
                 onUserAdded(userId);
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 onUserRemoved(userId);
-            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
-                onUserPresent(userId);
+            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                onUserUnlocked(userId);
             }
         }
     };
@@ -3681,13 +3676,36 @@
     }
 
     /**
+     * A NetworkRequest as registered by an application can be one of three
+     * types:
+     *
+     *     - "listen", for which the framework will issue callbacks about any
+     *       and all networks that match the specified NetworkCapabilities,
+     *
+     *     - "request", capable of causing a specific network to be created
+     *       first (e.g. a telephony DUN request), the framework will issue
+     *       callbacks about the single, highest scoring current network
+     *       (if any) that matches the specified NetworkCapabilities, or
+     *
+     *     - "track the default network", a hybrid of the two designed such
+     *       that the framework will issue callbacks for the single, highest
+     *       scoring current network (if any) that matches the capabilities of
+     *       the default Internet request (mDefaultRequest), but which cannot
+     *       cause the framework to either create or retain the existence of
+     *       any specific network.
+     *
+     */
+    private static enum NetworkRequestType {
+        LISTEN,
+        TRACK_DEFAULT,
+        REQUEST
+    };
+
+    /**
      * Tracks info about the requester.
      * Also used to notice when the calling process dies so we can self-expire
      */
     private class NetworkRequestInfo implements IBinder.DeathRecipient {
-        static final boolean REQUEST = true;
-        static final boolean LISTEN = false;
-
         final NetworkRequest request;
         final PendingIntent mPendingIntent;
         boolean mPendingIntentSent;
@@ -3695,26 +3713,26 @@
         final int mPid;
         final int mUid;
         final Messenger messenger;
-        final boolean isRequest;
+        private final NetworkRequestType mType;
 
-        NetworkRequestInfo(NetworkRequest r, PendingIntent pi, boolean isRequest) {
+        NetworkRequestInfo(NetworkRequest r, PendingIntent pi, NetworkRequestType type) {
             request = r;
             mPendingIntent = pi;
             messenger = null;
             mBinder = null;
             mPid = getCallingPid();
             mUid = getCallingUid();
-            this.isRequest = isRequest;
+            mType = type;
         }
 
-        NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) {
+        NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, NetworkRequestType type) {
             super();
             messenger = m;
             request = r;
             mBinder = binder;
             mPid = getCallingPid();
             mUid = getCallingUid();
-            this.isRequest = isRequest;
+            mType = type;
             mPendingIntent = null;
 
             try {
@@ -3724,6 +3742,16 @@
             }
         }
 
+        private String typeString() {
+            switch (mType) {
+                case LISTEN: return "Listen";
+                case REQUEST: return "Request";
+                case TRACK_DEFAULT: return "Track default";
+                default:
+                    return "unknown type";
+            }
+        }
+
         void unlinkDeathRecipient() {
             if (mBinder != null) {
                 mBinder.unlinkToDeath(this, 0);
@@ -3736,8 +3764,27 @@
             releaseNetworkRequest(request);
         }
 
+        /**
+         * Returns true iff. the contained NetworkRequest is one that:
+         *
+         *     - should be associated with at most one satisfying network
+         *       at a time;
+         *
+         *     - should cause a network to be kept up if it is the only network
+         *       which can satisfy the NetworkReqeust.
+         *
+         * For full detail of how isRequest() is used for pairing Networks with
+         * NetworkRequests read rematchNetworkAndRequests().
+         *
+         * TODO: Rename to something more properly descriptive.
+         */
+        public boolean isRequest() {
+            return (mType == NetworkRequestType.TRACK_DEFAULT) ||
+                   (mType == NetworkRequestType.REQUEST);
+        }
+
         public String toString() {
-            return (isRequest ? "Request" : "Listen") +
+            return typeString() +
                     " from uid/pid:" + mUid + "/" + mPid +
                     " for " + request +
                     (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
@@ -3790,8 +3837,19 @@
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
             Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
-        networkCapabilities = new NetworkCapabilities(networkCapabilities);
-        enforceNetworkRequestPermissions(networkCapabilities);
+        final NetworkRequestType type = (networkCapabilities == null)
+                ? NetworkRequestType.TRACK_DEFAULT
+                : NetworkRequestType.REQUEST;
+        // If the requested networkCapabilities is null, take them instead from
+        // the default network request. This allows callers to keep track of
+        // the system default network.
+        if (type == NetworkRequestType.TRACK_DEFAULT) {
+            networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
+            enforceAccessPermission();
+        } else {
+            networkCapabilities = new NetworkCapabilities(networkCapabilities);
+            enforceNetworkRequestPermissions(networkCapabilities);
+        }
         enforceMeteredApnPolicy(networkCapabilities);
         ensureRequestableCapabilities(networkCapabilities);
 
@@ -3807,8 +3865,7 @@
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId());
-        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
-                NetworkRequestInfo.REQUEST);
+        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, type);
         if (DBG) log("requestNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
@@ -3873,7 +3930,7 @@
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
                 nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation,
-                NetworkRequestInfo.REQUEST);
+                NetworkRequestType.REQUEST);
         if (DBG) log("pendingRequest for " + nri);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
                 nri));
@@ -3925,7 +3982,7 @@
         NetworkRequest networkRequest = new NetworkRequest(
                 new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
-                NetworkRequestInfo.LISTEN);
+                NetworkRequestType.LISTEN);
         if (DBG) log("listenForNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -3943,7 +4000,7 @@
         NetworkRequest networkRequest = new NetworkRequest(
                 new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation,
-                NetworkRequestInfo.LISTEN);
+                NetworkRequestType.LISTEN);
         if (DBG) log("pendingListenForNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -4077,14 +4134,8 @@
 //        }
         updateTcpBufferSizes(networkAgent);
 
-        // TODO: deprecate and remove mDefaultDns when we can do so safely. See http://b/18327075
-        // In L, we used it only when the network had Internet access but provided no DNS servers.
-        // For now, just disable it, and if disabling it doesn't break things, remove it.
-        // final boolean useDefaultDns = networkAgent.networkCapabilities.hasCapability(
-        //        NET_CAPABILITY_INTERNET);
-        final boolean useDefaultDns = false;
-        final boolean flushDns = updateRoutes(newLp, oldLp, netId);
-        updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);
+        updateRoutes(newLp, oldLp, netId);
+        updateDnses(newLp, oldLp, netId);
 
         updateClat(newLp, oldLp, networkAgent);
         if (isDefaultNetwork(networkAgent)) {
@@ -4187,37 +4238,24 @@
         return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty();
     }
 
-    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId,
-                             boolean flush, boolean useDefaultDns) {
-        if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
-            Collection<InetAddress> dnses = newLp.getDnsServers();
-            if (dnses.size() == 0 && mDefaultDns != null && useDefaultDns) {
-                dnses = new ArrayList();
-                dnses.add(mDefaultDns);
-                if (DBG) {
-                    loge("no dns provided for netId " + netId + ", so using defaults");
-                }
-            }
-            if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
-            try {
-                mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
-                    newLp.getDomains());
-            } catch (Exception e) {
-                loge("Exception in setDnsServersForNetwork: " + e);
-            }
-            final NetworkAgentInfo defaultNai = getDefaultNetwork();
-            if (defaultNai != null && defaultNai.network.netId == netId) {
-                setDefaultDnsSystemProperties(dnses);
-            }
-            flushVmDnsCache();
-        } else if (flush) {
-            try {
-                mNetd.flushNetworkDnsCache(netId);
-            } catch (Exception e) {
-                loge("Exception in flushNetworkDnsCache: " + e);
-            }
-            flushVmDnsCache();
+    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
+        if (oldLp != null && newLp.isIdenticalDnses(oldLp)) {
+            return;  // no updating necessary
         }
+
+        Collection<InetAddress> dnses = newLp.getDnsServers();
+        if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
+        try {
+            mNetd.setDnsServersForNetwork(
+                    netId, NetworkUtils.makeStrings(dnses), newLp.getDomains());
+        } catch (Exception e) {
+            loge("Exception in setDnsServersForNetwork: " + e);
+        }
+        final NetworkAgentInfo defaultNai = getDefaultNetwork();
+        if (defaultNai != null && defaultNai.network.netId == netId) {
+            setDefaultDnsSystemProperties(dnses);
+        }
+        flushVmDnsCache();
     }
 
     private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
@@ -4391,6 +4429,7 @@
 
     private void makeDefault(NetworkAgentInfo newNetwork) {
         if (DBG) log("Switching to new default network: " + newNetwork);
+        ConnectivityServiceChangeEvent.logEvent(newNetwork.network.netId);
         setupDataActivityTracking(newNetwork);
         try {
             mNetd.setDefaultNetId(newNetwork.network.netId);
@@ -4457,7 +4496,7 @@
             // check if it satisfies the NetworkCapabilities
             if (VDBG) log("  checking if request is satisfied: " + nri.request);
             if (satisfies) {
-                if (!nri.isRequest) {
+                if (!nri.isRequest()) {
                     // This is not a request, it's a callback listener.
                     // Add it to newNetwork regardless of score.
                     if (newNetwork.addRequest(nri.request)) addedRequests.add(nri);
@@ -4517,7 +4556,7 @@
                     mNetworkForRequestId.remove(nri.request.requestId);
                     sendUpdatedScoreToFactories(nri.request, 0);
                 } else {
-                    if (nri.isRequest == true) {
+                    if (nri.isRequest()) {
                         Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
                                 newNetwork.name() +
                                 " without updating mNetworkForRequestId or factories!");
@@ -5021,5 +5060,4 @@
             NetworkAgentInfo nai, NetworkRequest defaultRequest) {
         return new NetworkMonitor(context, handler, nai, defaultRequest);
     }
-
 }
diff --git a/services/core/java/com/android/server/ContextHubSystemService.java b/services/core/java/com/android/server/ContextHubSystemService.java
new file mode 100644
index 0000000..1b85632
--- /dev/null
+++ b/services/core/java/com/android/server/ContextHubSystemService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.hardware.location.ContextHubService;
+import android.content.Context;
+import android.util.Log;
+
+class ContextHubSystemService extends SystemService {
+    private static final String TAG = "ContextHubSystemService";
+    private final ContextHubService mContextHubService;
+
+    public ContextHubSystemService(Context context) {
+        super(context);
+        mContextHubService = new ContextHubService(context);
+    }
+
+    @Override
+    public void onStart() {
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+            publishBinderService(ContextHubService.CONTEXTHUB_SERVICE, mContextHubService);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 6c19c38..423f945 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -19,7 +19,6 @@
 import android.Manifest;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -109,30 +108,25 @@
 
     private static final boolean COMPRESS_TIME = false;
 
-    private static final int EVENT_BUFFER_SIZE = 40;
-
-    private static final String ACTION_STEP_IDLE_STATE =
-            "com.android.server.device_idle.STEP_IDLE_STATE";
-
-    private static final String ACTION_STEP_LIGHT_IDLE_STATE =
-            "com.android.server.device_idle.STEP_LIGHT_IDLE_STATE";
+    private static final int EVENT_BUFFER_SIZE = 100;
 
     private AlarmManager mAlarmManager;
     private IBatteryStats mBatteryStats;
     private PowerManagerInternal mLocalPowerManager;
+    private PowerManager mPowerManager;
+    private AlarmManagerService.LocalService mLocalAlarmManager;
     private INetworkPolicyManager mNetworkPolicyManager;
     private DisplayManager mDisplayManager;
     private SensorManager mSensorManager;
     private Sensor mMotionSensor;
     private LocationManager mLocationManager;
     private LocationRequest mLocationRequest;
-    private PendingIntent mAlarmIntent;
-    private PendingIntent mLightAlarmIntent;
     private Intent mIdleIntent;
     private Intent mLightIdleIntent;
     private Display mCurDisplay;
     private AnyMotionDetector mAnyMotionDetector;
-    private boolean mEnabled;
+    private boolean mLightEnabled;
+    private boolean mDeepEnabled;
     private boolean mForceIdle;
     private boolean mScreenOn;
     private boolean mCharging;
@@ -175,16 +169,19 @@
     private static final int LIGHT_STATE_ACTIVE = 0;
     /** Device is inactive (screen off) and we are waiting to for the first light idle. */
     private static final int LIGHT_STATE_INACTIVE = 1;
+    /** Device is about to go idle for the first time, wait for current work to complete. */
+    private static final int LIGHT_STATE_PRE_IDLE = 3;
     /** Device is in the light idle state, trying to stay asleep as much as possible. */
-    private static final int LIGHT_STATE_IDLE = 2;
+    private static final int LIGHT_STATE_IDLE = 4;
     /** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
-    private static final int LIGHT_STATE_IDLE_MAINTENANCE = 3;
-    /** Device light idle state is overriden, now applying full doze state. */
-    private static final int LIGHT_STATE_OVERRIDE = 4;
+    private static final int LIGHT_STATE_IDLE_MAINTENANCE = 5;
+    /** Device light idle state is overriden, now applying deep doze state. */
+    private static final int LIGHT_STATE_OVERRIDE = 6;
     private static String lightStateToString(int state) {
         switch (state) {
             case LIGHT_STATE_ACTIVE: return "ACTIVE";
             case LIGHT_STATE_INACTIVE: return "INACTIVE";
+            case LIGHT_STATE_PRE_IDLE: return "PRE_IDLE";
             case LIGHT_STATE_IDLE: return "IDLE";
             case LIGHT_STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
             case LIGHT_STATE_OVERRIDE: return "OVERRIDE";
@@ -199,13 +196,14 @@
     private long mNextAlarmTime;
     private long mNextIdlePendingDelay;
     private long mNextIdleDelay;
+    private long mNextLightIdleDelay;
     private long mNextLightAlarmTime;
     private long mCurIdleBudget;
     private long mMaintenanceStartTime;
 
     private int mActiveIdleOpCount;
+    private PowerManager.WakeLock mActiveIdleWakeLock;
     private IBinder mDownloadServiceActive;
-    private boolean mSyncActive;
     private boolean mJobsActive;
     private boolean mAlarmsActive;
     private boolean mReportedMaintenanceActivity;
@@ -268,6 +266,17 @@
     private int[] mPowerSaveWhitelistAllAppIdArray = new int[0];
 
     /**
+     * App IDs that have been white-listed by the user to opt out of power save restrictions.
+     */
+    private final SparseBooleanArray mPowerSaveWhitelistUserAppIds = new SparseBooleanArray();
+
+    /**
+     * Current app IDs that are in the user power save white list.  This array can
+     * be shared with others because it will not be modified once set.
+     */
+    private int[] mPowerSaveWhitelistUserAppIdArray = new int[0];
+
+    /**
      * List of end times for UIDs that are temporarily marked as being allowed to access
      * the network and acquire wakelocks. Times are in milliseconds.
      */
@@ -288,8 +297,8 @@
     private static final int EVENT_NORMAL = 1;
     private static final int EVENT_LIGHT_IDLE = 2;
     private static final int EVENT_LIGHT_MAINTENANCE = 3;
-    private static final int EVENT_FULL_IDLE = 4;
-    private static final int EVENT_FULL_MAINTENANCE = 5;
+    private static final int EVENT_DEEP_IDLE = 4;
+    private static final int EVENT_DEEP_MAINTENANCE = 5;
 
     private int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
     private long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
@@ -316,21 +325,42 @@
                         removePowerSaveWhitelistAppInternal(ssp);
                     }
                 }
-            } else if (ACTION_STEP_LIGHT_IDLE_STATE.equals(intent.getAction())) {
-                synchronized (DeviceIdleController.this) {
-                    stepLightIdleStateLocked("s:alarm");
-                }
-            } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
-                synchronized (DeviceIdleController.this) {
-                    stepIdleStateLocked("s:alarm");
-                }
+            }
+        }
+    };
+
+    private final AlarmManager.OnAlarmListener mLightAlarmListener
+            = new AlarmManager.OnAlarmListener() {
+        @Override
+        public void onAlarm() {
+            synchronized (DeviceIdleController.this) {
+                stepLightIdleStateLocked("s:alarm");
+            }
+        }
+    };
+
+    private final AlarmManager.OnAlarmListener mDeepAlarmListener
+            = new AlarmManager.OnAlarmListener() {
+        @Override
+        public void onAlarm() {
+            synchronized (DeviceIdleController.this) {
+                stepIdleStateLocked("s:alarm");
             }
         }
     };
 
     private final BroadcastReceiver mIdleStartedDoneReceiver = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
-            decActiveIdleOps();
+            // When coming out of a deep idle, we will add in some delay before we allow
+            // the system to settle down and finish the maintenance window.  This is
+            // to give a chance for any pending work to be scheduled.
+            if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+                mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
+                        mConstants.MIN_DEEP_MAINTENANCE_TIME);
+            } else {
+                mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
+                        mConstants.MIN_LIGHT_MAINTENANCE_TIME);
+            }
         }
     };
 
@@ -452,11 +482,18 @@
      */
     private final class Constants extends ContentObserver {
         // Key names stored in the settings value.
+        private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
+                = "light_after_inactive_to";
+        private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
         private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
+        private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
+        private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
         private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
                 = "light_idle_maintenance_min_budget";
         private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
                 = "light_idle_maintenance_max_budget";
+        private static final String KEY_MIN_LIGHT_MAINTENANCE_TIME = "min_light_maintenance_time";
+        private static final String KEY_MIN_DEEP_MAINTENANCE_TIME = "min_deep_maintenance_time";
         private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
         private static final String KEY_SENSING_TIMEOUT = "sensing_to";
         private static final String KEY_LOCATING_TIMEOUT = "locating_to";
@@ -478,14 +515,44 @@
                 "sms_temp_app_whitelist_duration";
 
         /**
-         * This is the time, after becoming inactive, that we will start going
-         * in to light-weight idle mode.
+         * This is the time, after becoming inactive, that we go in to the first
+         * light-weight idle mode.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
+         */
+        public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+
+        /**
+         * This is amount of time we will wait from the point where we decide we would
+         * like to go idle until we actually do, while waiting for jobs and other current
+         * activity to finish.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_LIGHT_PRE_IDLE_TIMEOUT
+         */
+        public long LIGHT_PRE_IDLE_TIMEOUT;
+
+        /**
+         * This is the initial time that we will run in idle maintenance mode.
          * @see Settings.Global#DEVICE_IDLE_CONSTANTS
          * @see #KEY_LIGHT_IDLE_TIMEOUT
          */
         public long LIGHT_IDLE_TIMEOUT;
 
         /**
+         * Scaling factor to apply to the light idle mode time each time we complete a cycle.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_LIGHT_IDLE_FACTOR
+         */
+        public float LIGHT_IDLE_FACTOR;
+
+        /**
+         * This is the maximum time we will run in idle maintenence mode.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
+         */
+        public long LIGHT_MAX_IDLE_TIMEOUT;
+
+        /**
          * This is the minimum amount of time we want to make available for maintenance mode
          * when lightly idling.  That is, we will always have at least this amount of time
          * available maintenance before timing out and cutting off maintenance mode.
@@ -506,6 +573,28 @@
         public long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
 
         /**
+         * This is the minimum amount of time that we will stay in maintenance mode after
+         * a light doze.  We have this minimum to allow various things to respond to switching
+         * in to maintenance mode and scheduling their work -- otherwise we may
+         * see there is nothing to do (no jobs or downloads pending) and go out of maintenance
+         * mode immediately.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_MIN_LIGHT_MAINTENANCE_TIME
+         */
+        public long MIN_LIGHT_MAINTENANCE_TIME;
+
+        /**
+         * This is the minimum amount of time that we will stay in maintenance mode after
+         * a full doze.  We have this minimum to allow various things to respond to switching
+         * in to maintenance mode and scheduling their work -- otherwise we may
+         * see there is nothing to do (no jobs or downloads pending) and go out of maintenance
+         * mode immediately.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_MIN_DEEP_MAINTENANCE_TIME
+         */
+        public long MIN_DEEP_MAINTENANCE_TIME;
+
+        /**
          * This is the time, after becoming inactive, at which we start looking at the
          * motion sensor to determine if the device is being left alone.  We don't do this
          * immediately after going inactive just because we don't want to be continually running
@@ -635,13 +724,18 @@
         public long SMS_TEMP_APP_WHITELIST_DURATION;
 
         private final ContentResolver mResolver;
+        private final boolean mHasWatch;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
         public Constants(Handler handler, ContentResolver resolver) {
             super(handler);
             mResolver = resolver;
-            mResolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS), false, this);
+            mHasWatch = getContext().getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_WATCH);
+            mResolver.registerContentObserver(Settings.Global.getUriFor(
+                    mHasWatch ? Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH
+                              : Settings.Global.DEVICE_IDLE_CONSTANTS),
+                    false, this);
             updateConstants();
         }
 
@@ -654,14 +748,24 @@
             synchronized (DeviceIdleController.this) {
                 try {
                     mParser.setString(Settings.Global.getString(mResolver,
-                            Settings.Global.DEVICE_IDLE_CONSTANTS));
+                            mHasWatch ? Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH
+                                      : Settings.Global.DEVICE_IDLE_CONSTANTS));
                 } catch (IllegalArgumentException e) {
                     // Failed to parse the settings string, log this and move on
                     // with defaults.
                     Slog.e(TAG, "Bad device idle settings", e);
                 }
 
+                LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(
+                        KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
+                        !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
+                LIGHT_PRE_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_PRE_IDLE_TIMEOUT,
+                        !COMPRESS_TIME ? 10 * 60 * 1000L : 30 * 1000L);
                 LIGHT_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_IDLE_TIMEOUT,
+                        !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
+                LIGHT_IDLE_FACTOR = mParser.getFloat(KEY_LIGHT_IDLE_FACTOR,
+                        2f);
+                LIGHT_MAX_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_MAX_IDLE_TIMEOUT,
                         !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L);
                 LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mParser.getLong(
                         KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,
@@ -669,8 +773,15 @@
                 LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mParser.getLong(
                         KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET,
                         !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
+                MIN_LIGHT_MAINTENANCE_TIME = mParser.getLong(
+                        KEY_MIN_LIGHT_MAINTENANCE_TIME,
+                        !COMPRESS_TIME ? 5 * 1000L : 1 * 1000L);
+                MIN_DEEP_MAINTENANCE_TIME = mParser.getLong(
+                        KEY_MIN_DEEP_MAINTENANCE_TIME,
+                        !COMPRESS_TIME ? 30 * 1000L : 5 * 1000L);
+                long inactiveTimeoutDefault = (mHasWatch ? 15 : 30) * 60 * 1000L;
                 INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,
-                        !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+                        !COMPRESS_TIME ? inactiveTimeoutDefault : (inactiveTimeoutDefault / 10));
                 SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,
                         !DEBUG ? 4 * 60 * 1000L : 60 * 1000L);
                 LOCATING_TIMEOUT = mParser.getLong(KEY_LOCATING_TIMEOUT,
@@ -678,8 +789,10 @@
                 LOCATION_ACCURACY = mParser.getFloat(KEY_LOCATION_ACCURACY, 20);
                 MOTION_INACTIVE_TIMEOUT = mParser.getLong(KEY_MOTION_INACTIVE_TIMEOUT,
                         !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
+                long idleAfterInactiveTimeout = (mHasWatch ? 15 : 30) * 60 * 1000L;
                 IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
-                        !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+                        !COMPRESS_TIME ? idleAfterInactiveTimeout
+                                       : (idleAfterInactiveTimeout / 10));
                 IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_IDLE_PENDING_TIMEOUT,
                         !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
                 MAX_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_PENDING_TIMEOUT,
@@ -706,10 +819,26 @@
         void dump(PrintWriter pw) {
             pw.println("  Settings:");
 
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("=");
+            TimeUtils.formatDuration(LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_LIGHT_PRE_IDLE_TIMEOUT); pw.print("=");
+            TimeUtils.formatDuration(LIGHT_PRE_IDLE_TIMEOUT, pw);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_LIGHT_IDLE_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
             pw.println();
 
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
+            pw.print(LIGHT_IDLE_FACTOR);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT); pw.print("=");
+            TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT, pw);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET); pw.print("=");
             TimeUtils.formatDuration(LIGHT_IDLE_MAINTENANCE_MIN_BUDGET, pw);
             pw.println();
@@ -718,6 +847,14 @@
             TimeUtils.formatDuration(LIGHT_IDLE_MAINTENANCE_MAX_BUDGET, pw);
             pw.println();
 
+            pw.print("    "); pw.print(KEY_MIN_LIGHT_MAINTENANCE_TIME); pw.print("=");
+            TimeUtils.formatDuration(MIN_LIGHT_MAINTENANCE_TIME, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_MIN_DEEP_MAINTENANCE_TIME); pw.print("=");
+            TimeUtils.formatDuration(MIN_DEEP_MAINTENANCE_TIME, pw);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_INACTIVE_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(INACTIVE_TIMEOUT, pw);
             pw.println();
@@ -820,6 +957,7 @@
     static final int MSG_REPORT_ACTIVE = 5;
     static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6;
     static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;
+    static final int MSG_FINISH_IDLE_OP = 8;
 
     final class MyHandler extends Handler {
         MyHandler(Looper looper) {
@@ -835,23 +973,23 @@
                 case MSG_REPORT_IDLE_ON:
                 case MSG_REPORT_IDLE_ON_LIGHT: {
                     EventLogTags.writeDeviceIdleOnStart();
-                    final boolean fullChanged;
+                    final boolean deepChanged;
                     final boolean lightChanged;
                     if (msg.what == MSG_REPORT_IDLE_ON) {
-                        fullChanged = mLocalPowerManager.setDeviceIdleMode(true);
+                        deepChanged = mLocalPowerManager.setDeviceIdleMode(true);
                         lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
                     } else {
-                        fullChanged = mLocalPowerManager.setDeviceIdleMode(false);
+                        deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
                         lightChanged = mLocalPowerManager.setLightDeviceIdleMode(true);
                     }
                     try {
                         mNetworkPolicyManager.setDeviceIdleMode(true);
                         mBatteryStats.noteDeviceIdleMode(msg.what == MSG_REPORT_IDLE_ON
-                                ? BatteryStats.DEVICE_IDLE_MODE_FULL
+                                ? BatteryStats.DEVICE_IDLE_MODE_DEEP
                                 : BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());
                     } catch (RemoteException e) {
                     }
-                    if (fullChanged) {
+                    if (deepChanged) {
                         getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                     }
                     if (lightChanged) {
@@ -861,7 +999,7 @@
                 } break;
                 case MSG_REPORT_IDLE_OFF: {
                     EventLogTags.writeDeviceIdleOffStart("unknown");
-                    final boolean fullChanged = mLocalPowerManager.setDeviceIdleMode(false);
+                    final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
                     final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
                     try {
                         mNetworkPolicyManager.setDeviceIdleMode(false);
@@ -869,7 +1007,7 @@
                                 null, Process.myUid());
                     } catch (RemoteException e) {
                     }
-                    if (fullChanged) {
+                    if (deepChanged) {
                         incActiveIdleOps();
                         getContext().sendOrderedBroadcastAsUser(mIdleIntent, UserHandle.ALL,
                                 null, mIdleStartedDoneReceiver, null, 0, null, null);
@@ -880,7 +1018,7 @@
                                 null, mIdleStartedDoneReceiver, null, 0, null, null);
                     }
                     // Always start with one active op for the message being sent here.
-                    // Now we we done!
+                    // Now we are done!
                     decActiveIdleOps();
                     EventLogTags.writeDeviceIdleOffComplete();
                 } break;
@@ -889,7 +1027,7 @@
                     int activeUid = msg.arg1;
                     EventLogTags.writeDeviceIdleOffStart(
                             activeReason != null ? activeReason : "unknown");
-                    final boolean fullChanged = mLocalPowerManager.setDeviceIdleMode(false);
+                    final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
                     final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
                     try {
                         mNetworkPolicyManager.setDeviceIdleMode(false);
@@ -897,7 +1035,7 @@
                                 activeReason, activeUid);
                     } catch (RemoteException e) {
                     }
-                    if (fullChanged) {
+                    if (deepChanged) {
                         getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                     }
                     if (lightChanged) {
@@ -924,6 +1062,9 @@
                         mMaintenanceActivityListeners.finishBroadcast();
                     }
                 } break;
+                case MSG_FINISH_IDLE_OP: {
+                    decActiveIdleOps();
+                } break;
             }
         }
     }
@@ -963,6 +1104,10 @@
             return getSystemPowerWhitelistInternal();
         }
 
+        @Override public String[] getUserPowerWhitelist() {
+            return getUserPowerWhitelistInternal();
+        }
+
         @Override public String[] getFullPowerWhitelistExceptIdle() {
             return getFullPowerWhitelistExceptIdleInternal();
         }
@@ -979,6 +1124,10 @@
             return getAppIdWhitelistInternal();
         }
 
+        @Override public int[] getAppIdUserWhitelist() {
+            return getAppIdUserWhitelistInternal();
+        }
+
         @Override public int[] getAppIdTempWhitelist() {
             return getAppIdTempWhitelistInternal();
         }
@@ -1073,10 +1222,6 @@
             setNetworkPolicyTempWhitelistCallbackInternal(callback);
         }
 
-        public void setSyncActive(boolean active) {
-            DeviceIdleController.this.setSyncActive(active);
-        }
-
         public void setJobsActive(boolean active) {
             DeviceIdleController.this.setJobsActive(active);
         }
@@ -1085,6 +1230,16 @@
         public void setAlarmsActive(boolean active) {
             DeviceIdleController.this.setAlarmsActive(active);
         }
+
+        /**
+         * Returns the array of app ids whitelisted by user. Take care not to
+         * modify this, as it is a reference to the original copy. But the reference
+         * can change when the list changes, so it needs to be re-acquired when
+         * {@link PowerManager#ACTION_POWER_SAVE_WHITELIST_CHANGED} is sent.
+         */
+        public int[] getPowerSaveWhitelistUserAppIds() {
+            return DeviceIdleController.this.getPowerSaveWhitelistUserAppIds();
+        }
     }
 
     public DeviceIdleController(Context context) {
@@ -1093,6 +1248,12 @@
         mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
     }
 
+    int[] getPowerSaveWhitelistUserAppIds() {
+        synchronized (this) {
+            return mPowerSaveWhitelistUserAppIdArray;
+        }
+    }
+
     private static File getSystemDir() {
         return new File(Environment.getDataDirectory(), "system");
     }
@@ -1102,7 +1263,7 @@
         final PackageManager pm = getContext().getPackageManager();
 
         synchronized (this) {
-            mEnabled = getContext().getResources().getBoolean(
+            mLightEnabled = mDeepEnabled = getContext().getResources().getBoolean(
                     com.android.internal.R.bool.config_enableAutoPowerModes);
             SystemConfig sysConfig = SystemConfig.getInstance();
             ArraySet<String> allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle();
@@ -1160,6 +1321,11 @@
                 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
                 mBatteryStats = BatteryStatsService.getService();
                 mLocalPowerManager = getLocalService(PowerManagerInternal.class);
+                mPowerManager = getContext().getSystemService(PowerManager.class);
+                mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                        "deviceidle_maint");
+                mActiveIdleWakeLock.setReferenceCounted(false);
+                mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
                 mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
                         ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
                 mDisplayManager = (DisplayManager) getContext().getSystemService(
@@ -1198,16 +1364,6 @@
                         (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
                         mHandler, mSensorManager, this, angleThreshold);
 
-                Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
-                        .setPackage("android")
-                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
-
-                Intent intentLight = new Intent(ACTION_STEP_LIGHT_IDLE_STATE)
-                        .setPackage("android")
-                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                mLightAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intentLight, 0);
-
                 mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
                 mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -1217,8 +1373,6 @@
 
                 IntentFilter filter = new IntentFilter();
                 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-                filter.addAction(ACTION_STEP_IDLE_STATE);
-                filter.addAction(ACTION_STEP_LIGHT_IDLE_STATE);
                 getContext().registerReceiver(mReceiver, filter);
                 filter = new IntentFilter();
                 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -1226,7 +1380,7 @@
                 getContext().registerReceiver(mReceiver, filter);
 
                 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
-
+                mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
                 mDisplayManager.registerDisplayListener(mDisplayListener, null);
                 updateDisplayLocked();
             }
@@ -1290,6 +1444,17 @@
         }
     }
 
+    public String[] getUserPowerWhitelistInternal() {
+        synchronized (this) {
+            int size = mPowerSaveWhitelistUserApps.size();
+            String[] apps = new String[size];
+            for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
+                apps[i] = mPowerSaveWhitelistUserApps.keyAt(i);
+            }
+            return apps;
+        }
+    }
+
     public String[] getFullPowerWhitelistExceptIdleInternal() {
         synchronized (this) {
             int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
@@ -1350,6 +1515,12 @@
         }
     }
 
+    public int[] getAppIdUserWhitelistInternal() {
+        synchronized (this) {
+            return mPowerSaveWhitelistUserAppIdArray;
+        }
+    }
+
     public int[] getAppIdTempWhitelistInternal() {
         synchronized (this) {
             return mTempWhitelistAppIdArray;
@@ -1550,21 +1721,21 @@
 
     void becomeInactiveIfAppropriateLocked() {
         if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
-        if (((!mScreenOn && !mCharging) || mForceIdle) && mEnabled) {
+        if ((!mScreenOn && !mCharging) || mForceIdle) {
             // Screen has turned off; we are now going to become inactive and start
             // waiting to see if we will ultimately go idle.
-            if (mState == STATE_ACTIVE) {
+            if (mState == STATE_ACTIVE && mDeepEnabled) {
                 mState = STATE_INACTIVE;
                 if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
                 resetIdleManagementLocked();
                 scheduleAlarmLocked(mInactiveTimeout, false);
                 EventLogTags.writeDeviceIdle(mState, "no activity");
             }
-            if (mLightState == LIGHT_STATE_ACTIVE) {
+            if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
                 mLightState = LIGHT_STATE_INACTIVE;
                 if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
                 resetLightIdleManagementLocked();
-                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_TIMEOUT);
+                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
                 EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
             }
         }
@@ -1573,6 +1744,7 @@
     void resetIdleManagementLocked() {
         mNextIdlePendingDelay = 0;
         mNextIdleDelay = 0;
+        mNextLightIdleDelay = 0;
         cancelAlarmLocked();
         cancelLocatingLocked();
         stopMonitoringMotionLocked();
@@ -1594,7 +1766,7 @@
 
     void stepLightIdleStateLocked(String reason) {
         if (mLightState == LIGHT_STATE_OVERRIDE) {
-            // If we are already in full device idle mode, then
+            // If we are already in deep device idle mode, then
             // there is nothing left to do for light mode.
             return;
         }
@@ -1605,7 +1777,19 @@
         switch (mLightState) {
             case LIGHT_STATE_INACTIVE:
                 mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+                // Reset the upcoming idle delays.
+                mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
                 mMaintenanceStartTime = 0;
+                if (!isOpsInactiveLocked()) {
+                    // We have some active ops going on...  give them a chance to finish
+                    // before going in to our first idle.
+                    mLightState = LIGHT_STATE_PRE_IDLE;
+                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
+                    scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
+                    break;
+                }
+                // Nothing active, fall through to immediately idle.
+            case LIGHT_STATE_PRE_IDLE:
             case LIGHT_STATE_IDLE_MAINTENANCE:
                 if (mMaintenanceStartTime != 0) {
                     long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
@@ -1618,7 +1802,12 @@
                     }
                 }
                 mMaintenanceStartTime = 0;
-                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_TIMEOUT);
+                scheduleLightAlarmLocked(mNextLightIdleDelay);
+                mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
+                        (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
+                if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) {
+                    mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
+                }
                 if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
                 mLightState = LIGHT_STATE_IDLE;
                 EventLogTags.writeDeviceIdleLight(mLightState, reason);
@@ -1628,13 +1817,13 @@
             case LIGHT_STATE_IDLE:
                 // We have been idling long enough, now it is time to do some work.
                 mActiveIdleOpCount = 1;
+                mActiveIdleWakeLock.acquire();
                 mMaintenanceStartTime = SystemClock.elapsedRealtime();
                 if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
                     mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
                 } else if (mCurIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
                     mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
                 }
-                mMaintenanceStartTime = SystemClock.elapsedRealtime();
                 scheduleLightAlarmLocked(mCurIdleBudget);
                 if (DEBUG) Slog.d(TAG,
                         "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
@@ -1718,6 +1907,7 @@
                 cancelAlarmLocked();
                 cancelLocatingLocked();
                 mAnyMotionDetector.stop();
+
             case STATE_IDLE_MAINTENANCE:
                 scheduleAlarmLocked(mNextIdleDelay, true);
                 if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
@@ -1725,26 +1915,34 @@
                 mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
                 if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
                 mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
+                if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
+                    mNextIdleDelay = mConstants.IDLE_TIMEOUT;
+                }
                 mState = STATE_IDLE;
                 if (mLightState != LIGHT_STATE_OVERRIDE) {
                     mLightState = LIGHT_STATE_OVERRIDE;
                     cancelLightAlarmLocked();
                 }
                 EventLogTags.writeDeviceIdle(mState, reason);
-                addEvent(EVENT_FULL_IDLE);
+                addEvent(EVENT_DEEP_IDLE);
                 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
                 break;
             case STATE_IDLE:
                 // We have been idling long enough, now it is time to do some work.
                 mActiveIdleOpCount = 1;
+                mActiveIdleWakeLock.acquire();
                 scheduleAlarmLocked(mNextIdlePendingDelay, false);
                 if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
                         "Next alarm in " + mNextIdlePendingDelay + " ms.");
+                mMaintenanceStartTime = SystemClock.elapsedRealtime();
                 mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
                         (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
+                if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
+                    mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
+                }
                 mState = STATE_IDLE_MAINTENANCE;
                 EventLogTags.writeDeviceIdle(mState, reason);
-                addEvent(EVENT_FULL_MAINTENANCE);
+                addEvent(EVENT_DEEP_MAINTENANCE);
                 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
                 break;
         }
@@ -1761,6 +1959,7 @@
             mActiveIdleOpCount--;
             if (mActiveIdleOpCount <= 0) {
                 exitMaintenanceEarlyIfNeededLocked();
+                mActiveIdleWakeLock.release();
             }
         }
     }
@@ -1789,16 +1988,6 @@
         }
     }
 
-    void setSyncActive(boolean active) {
-        synchronized (this) {
-            mSyncActive = active;
-            reportMaintenanceActivityIfNeededLocked();
-            if (!active) {
-                exitMaintenanceEarlyIfNeededLocked();
-            }
-        }
-    }
-
     void setJobsActive(boolean active) {
         synchronized (this) {
             mJobsActive = active;
@@ -1832,7 +2021,7 @@
     }
 
     void reportMaintenanceActivityIfNeededLocked() {
-        boolean active = mJobsActive | mSyncActive | (mDownloadServiceActive != null);
+        boolean active = mJobsActive | (mDownloadServiceActive != null);
         if (active == mReportedMaintenanceActivity) {
             return;
         }
@@ -1842,12 +2031,28 @@
         mHandler.sendMessage(msg);
     }
 
+    boolean isOpsInactiveLocked() {
+        return mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
+                && !mJobsActive && !mAlarmsActive;
+    }
+
     void exitMaintenanceEarlyIfNeededLocked() {
-        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
-            if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
-                    && !mSyncActive && !mJobsActive && !mAlarmsActive) {
+        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE
+                || mLightState == LIGHT_STATE_PRE_IDLE) {
+            if (isOpsInactiveLocked()) {
+                final long now = SystemClock.elapsedRealtime();
+                if (DEBUG) {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("Exit: start=");
+                    TimeUtils.formatDuration(mMaintenanceStartTime, sb);
+                    sb.append(" now=");
+                    TimeUtils.formatDuration(now, sb);
+                    Slog.d(TAG, sb.toString());
+                }
                 if (mState == STATE_IDLE_MAINTENANCE) {
                     stepIdleStateLocked("s:early");
+                } else if (mLightState == LIGHT_STATE_PRE_IDLE) {
+                    stepLightIdleStateLocked("s:predone");
                 } else {
                     stepLightIdleStateLocked("s:early");
                 }
@@ -1877,7 +2082,7 @@
             becomeInactive = true;
         }
         if (mLightState == LIGHT_STATE_OVERRIDE) {
-            // We went out of light idle mode because we had started full idle mode...  let's
+            // We went out of light idle mode because we had started deep idle mode...  let's
             // now go back and reset things so we resume light idling if appropriate.
             mLightState = STATE_ACTIVE;
             EventLogTags.writeDeviceIdleLight(mLightState, type);
@@ -1937,14 +2142,14 @@
     void cancelAlarmLocked() {
         if (mNextAlarmTime != 0) {
             mNextAlarmTime = 0;
-            mAlarmManager.cancel(mAlarmIntent);
+            mAlarmManager.cancel(mDeepAlarmListener);
         }
     }
 
     void cancelLightAlarmLocked() {
         if (mNextLightAlarmTime != 0) {
             mNextLightAlarmTime = 0;
-            mAlarmManager.cancel(mLightAlarmIntent);
+            mAlarmManager.cancel(mLightAlarmListener);
         }
     }
 
@@ -1968,10 +2173,10 @@
         mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
         if (idleUntil) {
             mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    mNextAlarmTime, mAlarmIntent);
+                    mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
         } else {
             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    mNextAlarmTime, mAlarmIntent);
+                    mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
         }
     }
 
@@ -1986,17 +2191,21 @@
         }
         mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                mNextLightAlarmTime, mLightAlarmIntent);
+                mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
     }
 
     private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
             ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) {
         outAppIds.clear();
-        for (int i=0; i<systemApps.size(); i++) {
-            outAppIds.put(systemApps.valueAt(i), true);
+        if (systemApps != null) {
+            for (int i = 0; i < systemApps.size(); i++) {
+                outAppIds.put(systemApps.valueAt(i), true);
+            }
         }
-        for (int i=0; i<userApps.size(); i++) {
-            outAppIds.put(userApps.valueAt(i), true);
+        if (userApps != null) {
+            for (int i = 0; i < userApps.size(); i++) {
+                outAppIds.put(userApps.valueAt(i), true);
+            }
         }
         int size = outAppIds.size();
         int[] appids = new int[size];
@@ -2011,6 +2220,8 @@
                 mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
         mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
                 mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
+        mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
+                mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
         if (mLocalPowerManager != null) {
             if (DEBUG) {
                 Slog.d(TAG, "Setting wakelock whitelist to "
@@ -2018,6 +2229,13 @@
             }
             mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
         }
+        if (mLocalAlarmManager != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting alarm whitelist to "
+                        + Arrays.toString(mPowerSaveWhitelistUserAppIdArray));
+            }
+            mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
+        }
     }
 
     private void updateTempWhitelistAppIdsLocked() {
@@ -2176,18 +2394,16 @@
         pw.println("Device idle controller (deviceidle) commands:");
         pw.println("  help");
         pw.println("    Print this help text.");
-        pw.println("  step");
+        pw.println("  step [light|deep]");
         pw.println("    Immediately step to next state, without waiting for alarm.");
-        pw.println("  light-step");
-        pw.println("    Immediately step to next light idle state, without waiting for alarm.");
         pw.println("  force-idle");
         pw.println("    Force directly into idle mode, regardless of other device state.");
         pw.println("    Use \"step\" to get out.");
-        pw.println("  disable");
+        pw.println("  disable [light|deep|all]");
         pw.println("    Completely disable device idle mode.");
-        pw.println("  enable");
+        pw.println("  enable [light|deep|all]");
         pw.println("    Re-enable device idle mode after it had previously been disabled.");
-        pw.println("  enabled");
+        pw.println("  enabled [light|deep|all]");
         pw.println("    Print 1 if device idle mode is currently enabled, else 0.");
         pw.println("  whitelist");
         pw.println("    Print currently whitelisted apps.");
@@ -2219,24 +2435,20 @@
                     null);
             synchronized (this) {
                 long token = Binder.clearCallingIdentity();
+                String arg = shell.getNextArg();
                 try {
-                    exitForceIdleLocked();
-                    stepIdleStateLocked("s:shell");
-                    pw.print("Stepped to: ");
-                    pw.println(stateToString(mState));
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        } else if ("light-step".equals(cmd)) {
-            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
-                    null);
-            synchronized (this) {
-                long token = Binder.clearCallingIdentity();
-                try {
-                    exitForceIdleLocked();
-                    stepLightIdleStateLocked("s:shell");
-                    pw.print("Stepped to: "); pw.println(lightStateToString(mLightState));
+                    if (arg == null || "deep".equals(arg)) {
+                        exitForceIdleLocked();
+                        stepIdleStateLocked("s:shell");
+                        pw.print("Stepped to deep: ");
+                        pw.println(stateToString(mState));
+                    } else if ("light".equals(arg)) {
+                        exitForceIdleLocked();
+                        stepLightIdleStateLocked("s:shell");
+                        pw.print("Stepped to light: "); pw.println(lightStateToString(mLightState));
+                    } else {
+                        pw.println("Unknown idle mode: " + arg);
+                    }
                 } finally {
                     Binder.restoreCallingIdentity(token);
                 }
@@ -2247,7 +2459,7 @@
             synchronized (this) {
                 long token = Binder.clearCallingIdentity();
                 try {
-                    if (!mEnabled) {
+                    if (!mDeepEnabled) {
                         pw.println("Unable to go idle; not enabled");
                         return -1;
                     }
@@ -2274,11 +2486,32 @@
                     null);
             synchronized (this) {
                 long token = Binder.clearCallingIdentity();
+                String arg = shell.getNextArg();
                 try {
-                    if (mEnabled) {
-                        mEnabled = false;
-                        becomeActiveLocked("disabled", Process.myUid());
-                        pw.println("Idle mode disabled");
+                    boolean becomeActive = false;
+                    boolean valid = false;
+                    if (arg == null || "deep".equals(arg) || "all".equals(arg)) {
+                        valid = true;
+                        if (mDeepEnabled) {
+                            mDeepEnabled = false;
+                            becomeActive = true;
+                            pw.println("Deep idle mode disabled");
+                        }
+                    }
+                    if (arg == null || "light".equals(arg) || "all".equals(arg)) {
+                        valid = true;
+                        if (mLightEnabled) {
+                            mLightEnabled = false;
+                            becomeActive = true;
+                            pw.println("Light idle mode disabled");
+                        }
+                    }
+                    if (becomeActive) {
+                        becomeActiveLocked((arg == null ? "all" : arg) + "-disabled",
+                                Process.myUid());
+                    }
+                    if (!valid) {
+                        pw.println("Unknown idle mode: " + arg);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(token);
@@ -2289,12 +2522,31 @@
                     null);
             synchronized (this) {
                 long token = Binder.clearCallingIdentity();
+                String arg = shell.getNextArg();
                 try {
-                    exitForceIdleLocked();
-                    if (!mEnabled) {
-                        mEnabled = true;
+                    boolean becomeInactive = false;
+                    boolean valid = false;
+                    if (arg == null || "deep".equals(arg) || "all".equals(arg)) {
+                        valid = true;
+                        if (!mDeepEnabled) {
+                            mDeepEnabled = true;
+                            becomeInactive = true;
+                            pw.println("Deep idle mode enabled");
+                        }
+                    }
+                    if (arg == null || "light".equals(arg) || "all".equals(arg)) {
+                        valid = true;
+                        if (!mLightEnabled) {
+                            mLightEnabled = true;
+                            becomeInactive = true;
+                            pw.println("Light idle mode enable");
+                        }
+                    }
+                    if (becomeInactive) {
                         becomeInactiveIfAppropriateLocked();
-                        pw.println("Idle mode enabled");
+                    }
+                    if (!valid) {
+                        pw.println("Unknown idle mode: " + arg);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(token);
@@ -2302,7 +2554,16 @@
             }
         } else if ("enabled".equals(cmd)) {
             synchronized (this) {
-                pw.println(mEnabled ? "1" : " 0");
+                String arg = shell.getNextArg();
+                if (arg == null || "all".equals(arg)) {
+                    pw.println(mDeepEnabled && mLightEnabled ? "1" : 0);
+                } else if ("deep".equals(arg)) {
+                    pw.println(mDeepEnabled ? "1" : 0);
+                } else if ("light".equals(arg)) {
+                    pw.println(mLightEnabled ? "1" : 0);
+                } else {
+                    pw.println("Unknown idle mode: " + arg);
+                }
             }
         } else if ("whitelist".equals(cmd)) {
             long token = Binder.clearCallingIdentity();
@@ -2441,8 +2702,8 @@
                         case EVENT_NORMAL:              label = "     normal"; break;
                         case EVENT_LIGHT_IDLE:          label = " light-idle"; break;
                         case EVENT_LIGHT_MAINTENANCE:   label = "light-maint"; break;
-                        case EVENT_FULL_IDLE:           label = "  full-idle"; break;
-                        case EVENT_FULL_MAINTENANCE:    label = " full-maint"; break;
+                        case EVENT_DEEP_IDLE:           label = "  deep-idle"; break;
+                        case EVENT_DEEP_MAINTENANCE:    label = " deep-maint"; break;
                         default:                        label = "         ??"; break;
                     }
                     pw.print("    ");
@@ -2486,6 +2747,15 @@
                     pw.println();
                 }
             }
+            size = mPowerSaveWhitelistUserAppIds.size();
+            if (size > 0) {
+                pw.println("  Whitelist user app ids:");
+                for (int i = 0; i < size; i++) {
+                    pw.print("    ");
+                    pw.print(mPowerSaveWhitelistUserAppIds.keyAt(i));
+                    pw.println();
+                }
+            }
             size = mPowerSaveWhitelistAllAppIds.size();
             if (size > 0) {
                 pw.println("  Whitelist all app ids:");
@@ -2519,7 +2789,8 @@
                 }
             }
 
-            pw.print("  mEnabled="); pw.println(mEnabled);
+            pw.print("  mLightEnabled="); pw.print(mLightEnabled);
+            pw.print(" mDeepEnabled="); pw.println(mDeepEnabled);
             pw.print("  mForceIdle="); pw.println(mForceIdle);
             pw.print("  mMotionSensor="); pw.println(mMotionSensor);
             pw.print("  mCurDisplay="); pw.println(mCurDisplay);
@@ -2559,6 +2830,11 @@
                 TimeUtils.formatDuration(mNextIdleDelay, pw);
                 pw.println();
             }
+            if (mNextLightIdleDelay != 0) {
+                pw.print("  mNextIdleDelay=");
+                TimeUtils.formatDuration(mNextLightIdleDelay, pw);
+                pw.println();
+            }
             if (mNextLightAlarmTime != 0) {
                 pw.print("  mNextLightAlarmTime=");
                 TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
@@ -2574,9 +2850,6 @@
                 TimeUtils.formatDuration(mMaintenanceStartTime, SystemClock.elapsedRealtime(), pw);
                 pw.println();
             }
-            if (mSyncActive) {
-                pw.print("  mSyncActive="); pw.println(mSyncActive);
-            }
             if (mJobsActive) {
                 pw.print("  mJobsActive="); pw.println(mJobsActive);
             }
diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
index 9313148..8ca675a 100644
--- a/services/core/java/com/android/server/DiskStatsService.java
+++ b/services/core/java/com/android/server/DiskStatsService.java
@@ -80,7 +80,7 @@
         reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
         reportFreeSpace(new File("/system"), "System", pw);
 
-        if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+        if (StorageManager.isFileEncryptedNativeOnly()) {
             pw.println("File-based Encryption: true");
         }
 
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index 044bb04..ecbe1ca 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -51,17 +51,15 @@
  * 2) ASHMEM_SIZE (for scratch space used during dumping)
  * 3) ASHMEM_SIZE * HISTORY_SIZE
  *
- * Currently ASHMEM_SIZE is 256 bytes and HISTORY_SIZE is 20. Assuming
- * the system then also has 10 active rendering processes in the worst case
- * this would end up using under 14KiB (12KiB for the buffers, plus some overhead
- * for userId, pid, package name, and a couple other objects)
+ * This is currently under 20KiB total memory in the worst case of
+ * 20 processes in history + 10 unique active processes.
  *
  *  @hide */
 public class GraphicsStatsService extends IGraphicsStats.Stub {
     public static final String GRAPHICS_STATS_SERVICE = "graphicsstats";
 
     private static final String TAG = "GraphicsStatsService";
-    private static final int ASHMEM_SIZE = 256;
+    private static final int ASHMEM_SIZE = 464;
     private static final int HISTORY_SIZE = 20;
 
     private final Context mContext;
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index cc21e99..23cf64a 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -22,6 +22,9 @@
 import android.os.Binder;
 import android.os.CpuUsageInfo;
 import android.os.IHardwarePropertiesManager;
+import android.os.Process;
+import android.os.UserHandle;
+import com.android.server.vr.VrManagerInternal;
 
 import java.util.Arrays;
 
@@ -33,7 +36,7 @@
     private static native void nativeInit();
 
     private static native float[] nativeGetFanSpeeds();
-    private static native float[] nativeGetDeviceTemperatures(int type);
+    private static native float[] nativeGetDeviceTemperatures(int type, int source);
     private static native CpuUsageInfo[] nativeGetCpuUsages();
 
     private final Context mContext;
@@ -47,10 +50,11 @@
     }
 
     @Override
-    public float[] getDeviceTemperatures(String callingPackage, int type) throws SecurityException {
+    public float[] getDeviceTemperatures(String callingPackage, int type, int source)
+            throws SecurityException {
         enforceHardwarePropertiesRetrievalAllowed(callingPackage);
         synchronized (mLock) {
-            return nativeGetDeviceTemperatures(type);
+            return nativeGetDeviceTemperatures(type, source);
         }
     }
 
@@ -76,14 +80,15 @@
      *
      * @param callingPackage The calling package name.
      *
-     * @throws SecurityException if a non profile or device owner tries to retrieve information
-     * provided by the service.
+     * @throws SecurityException if something other than the profile or device owner, or the
+     *        current VR service tries to retrieve information provided by this service.
      */
     private void enforceHardwarePropertiesRetrievalAllowed(String callingPackage)
             throws SecurityException {
         final PackageManager pm = mContext.getPackageManager();
+        int uid = 0;
         try {
-            final int uid = pm.getPackageUid(callingPackage, 0);
+            uid = pm.getPackageUid(callingPackage, 0);
             if (Binder.getCallingUid() != uid) {
                 throw new SecurityException("The caller has faked the package name.");
             }
@@ -91,9 +96,13 @@
             throw new SecurityException("The caller has faked the package name.");
         }
 
+        final int userId = UserHandle.getUserId(uid);
+        final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
         final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        if (!dpm.isDeviceOwnerApp(callingPackage) && !dpm.isProfileOwnerApp(callingPackage)) {
-            throw new SecurityException("The caller is not a device or profile owner.");
+        if (!dpm.isDeviceOwnerApp(callingPackage) && !dpm.isProfileOwnerApp(callingPackage)
+                && !vrService.isCurrentVrListener(callingPackage, userId)) {
+            throw new SecurityException("The caller is not a device or profile owner or bound "
+                + "VrListenerService.");
         }
     }
 }
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index d1de7e5..ac7872a 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -15,6 +15,8 @@
 
 package com.android.server;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -37,8 +39,10 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.AppGlobals;
@@ -47,7 +51,6 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.SynchronousUserSwitchObserver;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -95,6 +98,7 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.EventLog;
+import android.util.LocaleList;
 import android.util.LruCache;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
@@ -111,6 +115,7 @@
 import android.view.WindowManagerInternal;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnectionInspector;
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -123,6 +128,7 @@
 import android.widget.RadioButton;
 import android.widget.Switch;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -130,12 +136,12 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Locale;
 
 /**
  * This class provides a system service that manages input methods.
@@ -176,6 +182,12 @@
     private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
     private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
 
+    @Retention(SOURCE)
+    @IntDef({HardKeyboardBehavior.WIRELESS_AFFORDANCE, HardKeyboardBehavior.WIRED_AFFORDANCE})
+    private @interface  HardKeyboardBehavior {
+        int WIRELESS_AFFORDANCE = 0;
+        int WIRED_AFFORDANCE = 1;
+    }
 
     final Context mContext;
     final Resources mRes;
@@ -214,7 +226,7 @@
     // Ongoing notification
     private NotificationManager mNotificationManager;
     private KeyguardManager mKeyguardManager;
-    private StatusBarManagerService mStatusBar;
+    private @Nullable StatusBarManagerService mStatusBar;
     private Notification.Builder mImeSwitcherNotification;
     private PendingIntent mImeSwitchPendingIntent;
     private boolean mShowOngoingImeSwitcherForPhones;
@@ -327,6 +339,13 @@
     IInputContext mCurInputContext;
 
     /**
+     * The missing method flags for the input context last provided by the current client.
+     *
+     * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
+     */
+    int mCurInputContextMissingMethods;
+
+    /**
      * The attributes last provided by the current client.
      */
     EditorInfo mCurAttribute;
@@ -444,18 +463,22 @@
     private AlertDialog.Builder mDialogBuilder;
     private AlertDialog mSwitchingDialog;
     private View mSwitchingDialogTitleView;
+    private Toast mSubtypeSwitchedByShortCutToast;
     private InputMethodInfo[] mIms;
     private int[] mSubtypeIds;
-    private Locale mLastSystemLocale;
+    private LocaleList mLastSystemLocales;
     private boolean mShowImeWithHardKeyboard;
     private boolean mAccessibilityRequestingNoSoftKeyboard;
     private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
     private final IPackageManager mIPackageManager;
     private final String mSlotIme;
+    @HardKeyboardBehavior
+    private final int mHardKeyboardBehavior;
 
     class SettingsObserver extends ContentObserver {
         int mUserId;
         boolean mRegistered = false;
+        @NonNull
         String mLastEnabled = "";
 
         /**
@@ -465,7 +488,7 @@
             super(handler);
         }
 
-        public void registerContentObserverLocked(int userId) {
+        public void registerContentObserverLocked(@UserIdInt int userId) {
             if (mRegistered && mUserId == userId) {
                 return;
             }
@@ -774,7 +797,16 @@
         }
 
         @Override
+        public void onSwitchUser(@UserIdInt int userHandle) {
+            // Called on the system server's main looper thread.
+            // TODO: Dispatch this to a worker thread as needed.
+            mService.onSwitchUser(userHandle);
+        }
+
+        @Override
         public void onBootPhase(int phase) {
+            // Called on the system server's main looper thread.
+            // TODO: Dispatch this to a worker thread as needed.
             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
                         .getService(Context.STATUS_BAR_SERVICE);
@@ -783,12 +815,14 @@
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
+        public void onUnlockUser(@UserIdInt int userHandle) {
+            // Called on the system server's main looper thread.
+            // TODO: Dispatch this to a worker thread as needed.
             mService.onUnlockUser(userHandle);
         }
     }
 
-    public void onUnlockUser(int userId) {
+    void onUnlockUser(@UserIdInt int userId) {
         synchronized(mMethodMap) {
             final int currentUserId = mSettings.getCurrentUserId();
             if (DEBUG) {
@@ -804,6 +838,12 @@
         }
     }
 
+    void onSwitchUser(@UserIdInt int userId) {
+        synchronized (mMethodMap) {
+            switchUserLocked(userId);
+        }
+    }
+
     public InputMethodManagerService(Context context) {
         mIPackageManager = AppGlobals.getPackageManager();
         mContext = context;
@@ -826,6 +866,8 @@
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS);
         mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
+        mHardKeyboardBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_externalHardKeyboardBehavior);
 
         Bundle extras = new Bundle();
         extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
@@ -852,25 +894,6 @@
         mNotificationShown = false;
         int userId = 0;
         try {
-            ActivityManagerNative.getDefault().registerUserSwitchObserver(
-                    new SynchronousUserSwitchObserver() {
-                        @Override
-                        public void onUserSwitching(int newUserId)
-                                throws RemoteException {
-                            synchronized(mMethodMap) {
-                                switchUserLocked(newUserId);
-                            }
-                        }
-
-                        @Override
-                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
-                        }
-
-                        @Override
-                        public void onForegroundProfileSwitch(int newProfileId) {
-                            // Ignore.
-                        }
-                    });
             userId = ActivityManagerNative.getDefault().getCurrentUser().id;
         } catch (RemoteException e) {
             Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
@@ -949,15 +972,15 @@
             // not system ready
             return;
         }
-        final Locale newLocale = mRes.getConfiguration().locale;
+        final LocaleList newLocales = mRes.getConfiguration().getLocales();
         if (!updateOnlyWhenLocaleChanged
-                || (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
+                || (newLocales != null && !newLocales.equals(mLastSystemLocales))) {
             if (!updateOnlyWhenLocaleChanged) {
                 hideCurrentInputLocked(0, null);
                 resetCurrentMethodAndClient(InputMethodClient.UNBIND_REASON_RESET_IME);
             }
             if (DEBUG) {
-                Slog.i(TAG, "Locale has been changed to " + newLocale);
+                Slog.i(TAG, "LocaleList has been changed to " + newLocales);
             }
             buildInputMethodListLocked(resetDefaultEnabledIme);
             if (!updateOnlyWhenLocaleChanged) {
@@ -972,7 +995,7 @@
                 resetDefaultImeLocked(mContext);
             }
             updateFromSettingsLocked(true);
-            mLastSystemLocale = newLocale;
+            mLastSystemLocales = newLocales;
             if (!updateOnlyWhenLocaleChanged) {
                 try {
                     startInputInnerLocked();
@@ -1063,7 +1086,9 @@
                 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
                 mNotificationManager = mContext.getSystemService(NotificationManager.class);
                 mStatusBar = statusBar;
-                statusBar.setIconVisibility(mSlotIme, false);
+                if (mStatusBar != null) {
+                    mStatusBar.setIconVisibility(mSlotIme, false);
+                }
                 updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
                 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                         com.android.internal.R.bool.show_ongoing_ime_switcher);
@@ -1079,7 +1104,7 @@
                             mSettings.getEnabledInputMethodListLocked(),
                             mSettings.getCurrentUserId(), mContext.getBasePackageName());
                 }
-                mLastSystemLocale = mRes.getConfiguration().locale;
+                mLastSystemLocales = mRes.getConfiguration().getLocales();
                 try {
                     startInputInnerLocked();
                 } catch (RuntimeException e) {
@@ -1290,11 +1315,13 @@
         }
         final SessionState session = mCurClient.curSession;
         if (initial) {
-            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
-                    MSG_START_INPUT, session, mCurInputContext, mCurAttribute));
+            executeOrSendMessage(session.method, mCaller.obtainMessageIOOO(
+                    MSG_START_INPUT, mCurInputContextMissingMethods, session, mCurInputContext,
+                    mCurAttribute));
         } else {
-            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
-                    MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));
+            executeOrSendMessage(session.method, mCaller.obtainMessageIOOO(
+                    MSG_RESTART_INPUT, mCurInputContextMissingMethods, session, mCurInputContext,
+                    mCurAttribute));
         }
         if (mShowRequested) {
             if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
@@ -1307,8 +1334,9 @@
 
     InputBindResult startInputLocked(
             /* @InputMethodClient.StartInputReason */ final int startInputReason,
-            IInputMethodClient client, IInputContext inputContext, EditorInfo attribute,
-            int controlFlags) {
+            IInputMethodClient client, IInputContext inputContext,
+            /* @InputConnectionInspector.missingMethods */ final int missingMethods,
+            @Nullable EditorInfo attribute, int controlFlags) {
         // If no method is currently selected, do nothing.
         if (mCurMethodId == null) {
             return mNoBinding;
@@ -1320,6 +1348,12 @@
                     + client.asBinder());
         }
 
+        if (attribute == null) {
+            Slog.w(TAG, "Ignoring startInput with null EditorInfo."
+                    + " uid=" + cs.uid + " pid=" + cs.pid);
+            return null;
+        }
+
         try {
             if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
                 // Check with the window manager to make sure this client actually
@@ -1334,10 +1368,12 @@
         } catch (RemoteException e) {
         }
 
-        return startInputUncheckedLocked(cs, inputContext, attribute, controlFlags);
+        return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
+                controlFlags);
     }
 
     InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
+            /* @InputConnectionInspector.missingMethods */ final int missingMethods,
             @NonNull EditorInfo attribute, int controlFlags) {
         // If no method is currently selected, do nothing.
         if (mCurMethodId == null) {
@@ -1372,6 +1408,7 @@
         if (mCurSeq <= 0) mCurSeq = 1;
         mCurClient = cs;
         mCurInputContext = inputContext;
+        mCurInputContextMissingMethods = missingMethods;
         mCurAttribute = attribute;
 
         // Check if the input method is changing.
@@ -1458,11 +1495,11 @@
         return null;
     }
 
-    @Override
-    public InputBindResult startInput(
+    private InputBindResult startInput(
             /* @InputMethodClient.StartInputReason */ final int startInputReason,
-            IInputMethodClient client, IInputContext inputContext, EditorInfo attribute,
-            int controlFlags) {
+            IInputMethodClient client, IInputContext inputContext,
+            /* @InputConnectionInspector.missingMethods */ final int missingMethods,
+            @Nullable EditorInfo attribute, int controlFlags) {
         if (!calledFromValidUser()) {
             return null;
         }
@@ -1472,13 +1509,15 @@
                         + InputMethodClient.getStartInputReason(startInputReason)
                         + " client = " + client.asBinder()
                         + " inputContext=" + inputContext
+                        + " missingMethods="
+                        + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
                         + " attribute=" + attribute
                         + " controlFlags=#" + Integer.toHexString(controlFlags));
             }
             final long ident = Binder.clearCallingIdentity();
             try {
-                return startInputLocked(startInputReason, client, inputContext, attribute,
-                        controlFlags);
+                return startInputLocked(startInputReason, client, inputContext, missingMethods,
+                        attribute, controlFlags);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -1687,13 +1726,16 @@
         if (isScreenLocked()) return false;
         if ((visibility & InputMethodService.IME_ACTIVE) == 0) return false;
         if (mWindowManagerInternal.isHardKeyboardAvailable()) {
-            // When physical keyboard is attached, we show the ime switcher (or notification if
-            // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
-            // exists in the IME switcher dialog.  Might be OK to remove this condition once
-            // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
-            return true;
+            if (mHardKeyboardBehavior == HardKeyboardBehavior.WIRELESS_AFFORDANCE) {
+                // When physical keyboard is attached, we show the ime switcher (or notification if
+                // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
+                // exists in the IME switcher dialog.  Might be OK to remove this condition once
+                // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
+                return true;
+            }
+        } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
+            return false;
         }
-        if ((visibility & InputMethodService.IME_VISIBLE) == 0) return false;
 
         List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
         final int N = imis.size();
@@ -1961,14 +2003,6 @@
             throw new IllegalArgumentException("Unknown id: " + id);
         }
 
-        if (mCurClient != null && mCurAttribute != null) {
-            // We have already made sure that the package name belongs to the application's UID.
-            // No further UID check is required.
-            if (SystemConfig.getInstance().getFixedImeApps().contains(mCurAttribute.packageName)) {
-                return;
-            }
-        }
-
         // See if we need to notify a subtype change within the same IME.
         if (id.equals(mCurMethodId)) {
             final int subtypeCount = info.getSubtypeCount();
@@ -2197,10 +2231,25 @@
     }
 
     @Override
-    public InputBindResult windowGainedFocus(
+    public InputBindResult startInputOrWindowGainedFocus(
             /* @InputMethodClient.StartInputReason */ final int startInputReason,
             IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
-            int windowFlags, EditorInfo attribute, IInputContext inputContext) {
+            int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
+            /* @InputConnectionInspector.missingMethods */ final int missingMethods) {
+        if (windowToken != null) {
+            return windowGainedFocus(startInputReason, client, windowToken, controlFlags,
+                    softInputMode, windowFlags, attribute, inputContext, missingMethods);
+        } else {
+            return startInput(startInputReason, client, inputContext, missingMethods, attribute,
+                    controlFlags);
+        }
+    }
+
+    private InputBindResult windowGainedFocus(
+            /* @InputMethodClient.StartInputReason */ final int startInputReason,
+            IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
+            int windowFlags, EditorInfo attribute, IInputContext inputContext,
+            /* @InputConnectionInspector.missingMethods */  final int missingMethods) {
         // Needs to check the validity before clearing calling identity
         final boolean calledFromValidUser = calledFromValidUser();
         InputBindResult res = null;
@@ -2211,6 +2260,8 @@
                         + InputMethodClient.getStartInputReason(startInputReason)
                         + " client=" + client.asBinder()
                         + " inputContext=" + inputContext
+                        + " missingMethods="
+                        + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
                         + " attribute=" + attribute
                         + " controlFlags=#" + Integer.toHexString(controlFlags)
                         + " softInputMode=#" + Integer.toHexString(softInputMode)
@@ -2248,8 +2299,8 @@
                     Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
                             + " attribute=" + attribute + ", token = " + windowToken);
                     if (attribute != null) {
-                        return startInputUncheckedLocked(cs, inputContext, attribute,
-                                controlFlags);
+                        return startInputUncheckedLocked(cs, inputContext, missingMethods,
+                                attribute, controlFlags);
                     }
                     return null;
                 }
@@ -2298,8 +2349,8 @@
                             // is more room for the target window + IME.
                             if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
                             if (attribute != null) {
-                                res = startInputUncheckedLocked(cs, inputContext, attribute,
-                                        controlFlags);
+                                res = startInputUncheckedLocked(cs, inputContext,
+                                        missingMethods, attribute, controlFlags);
                                 didStart = true;
                             }
                             showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2324,8 +2375,8 @@
                                 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                             if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
                             if (attribute != null) {
-                                res = startInputUncheckedLocked(cs, inputContext, attribute,
-                                        controlFlags);
+                                res = startInputUncheckedLocked(cs, inputContext,
+                                        missingMethods, attribute, controlFlags);
                                 didStart = true;
                             }
                             showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2334,8 +2385,8 @@
                     case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
                         if (DEBUG) Slog.v(TAG, "Window asks to always show input");
                         if (attribute != null) {
-                            res = startInputUncheckedLocked(cs, inputContext, attribute,
-                                    controlFlags);
+                            res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+                                    attribute, controlFlags);
                             didStart = true;
                         }
                         showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2343,7 +2394,7 @@
                 }
 
                 if (!didStart && attribute != null) {
-                    res = startInputUncheckedLocked(cs, inputContext, attribute,
+                    res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
                             controlFlags);
                 }
             }
@@ -2805,28 +2856,32 @@
             }
             // ---------------------------------------------------------
 
-            case MSG_START_INPUT:
-                args = (SomeArgs)msg.obj;
+            case MSG_START_INPUT: {
+                int missingMethods = msg.arg1;
+                args = (SomeArgs) msg.obj;
                 try {
-                    SessionState session = (SessionState)args.arg1;
+                    SessionState session = (SessionState) args.arg1;
                     setEnabledSessionInMainThread(session);
-                    session.method.startInput((IInputContext)args.arg2,
-                            (EditorInfo)args.arg3);
+                    session.method.startInput((IInputContext) args.arg2, missingMethods,
+                            (EditorInfo) args.arg3);
                 } catch (RemoteException e) {
                 }
                 args.recycle();
                 return true;
-            case MSG_RESTART_INPUT:
-                args = (SomeArgs)msg.obj;
+            }
+            case MSG_RESTART_INPUT: {
+                int missingMethods = msg.arg1;
+                args = (SomeArgs) msg.obj;
                 try {
-                    SessionState session = (SessionState)args.arg1;
+                    SessionState session = (SessionState) args.arg1;
                     setEnabledSessionInMainThread(session);
-                    session.method.restartInput((IInputContext)args.arg2,
-                            (EditorInfo)args.arg3);
+                    session.method.restartInput((IInputContext) args.arg2, missingMethods,
+                            (EditorInfo) args.arg3);
                 } catch (RemoteException e) {
                 }
                 args.recycle();
                 return true;
+            }
 
             // ---------------------------------------------------------
 
@@ -2915,6 +2970,27 @@
                 return;
             }
             setInputMethodLocked(nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+            if (mSubtypeSwitchedByShortCutToast != null) {
+                mSubtypeSwitchedByShortCutToast.cancel();
+                mSubtypeSwitchedByShortCutToast = null;
+            }
+            if ((mImeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+                // IME window is shown.  The user should be able to visually understand that the
+                // subtype is changed in most of cases.  To avoid UI overlap, we do not show a toast
+                // in this case.
+                return;
+            }
+            final InputMethodInfo newInputMethodInfo = mMethodMap.get(mCurMethodId);
+            if (newInputMethodInfo == null) {
+                return;
+            }
+            final CharSequence toastText = InputMethodUtils.getImeAndSubtypeDisplayName(mContext,
+                    newInputMethodInfo, mCurrentSubtype);
+            if (!TextUtils.isEmpty(toastText)) {
+                mSubtypeSwitchedByShortCutToast = Toast.makeText(mContext, toastText.toString(),
+                        Toast.LENGTH_SHORT);
+                mSubtypeSwitchedByShortCutToast.show();
+            }
         }
     }
 
@@ -3184,16 +3260,6 @@
             };
             mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
 
-            if (!isScreenLocked) {
-                final OnClickListener positiveListener = new OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int whichButton) {
-                        showConfigureInputMethods();
-                    }
-                };
-                mDialogBuilder.setPositiveButton(
-                        com.android.internal.R.string.configure_input_methods, positiveListener);
-            }
             mSwitchingDialog = mDialogBuilder.create();
             mSwitchingDialog.setCanceledOnTouchOutside(true);
             mSwitchingDialog.getWindow().setType(
@@ -3587,6 +3653,7 @@
         private static final String ATTR_IME_SUBTYPE_MODE = "imeSubtypeMode";
         private static final String ATTR_IME_SUBTYPE_EXTRA_VALUE = "imeSubtypeExtraValue";
         private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
+        private static final String ATTR_IS_ASCII_CAPABLE = "isAsciiCapable";
         private final AtomicFile mAdditionalInputMethodSubtypeFile;
         private final HashMap<String, InputMethodInfo> mMethodMap;
         private final HashMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
@@ -3683,6 +3750,8 @@
                         out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
                         out.attribute(null, ATTR_IS_AUXILIARY,
                                 String.valueOf(subtype.isAuxiliary() ? 1 : 0));
+                        out.attribute(null, ATTR_IS_ASCII_CAPABLE,
+                                String.valueOf(subtype.isAsciiCapable() ? 1 : 0));
                         out.endTag(null, NODE_SUBTYPE);
                     }
                     out.endTag(null, NODE_IMI);
@@ -3748,6 +3817,8 @@
                                 parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
                         final boolean isAuxiliary = "1".equals(String.valueOf(
                                 parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
+                        final boolean isAsciiCapable = "1".equals(String.valueOf(
+                                parser.getAttributeValue(null, ATTR_IS_ASCII_CAPABLE)));
                         final InputMethodSubtype subtype = new InputMethodSubtypeBuilder()
                                 .setSubtypeNameResId(label)
                                 .setSubtypeIconResId(icon)
@@ -3756,6 +3827,7 @@
                                 .setSubtypeMode(imeSubtypeMode)
                                 .setSubtypeExtraValue(imeSubtypeExtraValue)
                                 .setIsAuxiliary(isAuxiliary)
+                                .setIsAsciiCapable(isAsciiCapable)
                                 .build();
                         tempSubtypesArray.add(subtype);
                     }
@@ -3790,6 +3862,22 @@
         }
     }
 
+    private static String imeWindowStatusToString(final int imeWindowVis) {
+        final StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        if ((imeWindowVis & InputMethodService.IME_ACTIVE) != 0) {
+            sb.append("Active");
+            first = false;
+        }
+        if ((imeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+            if (!first) {
+                sb.append("|");
+            }
+            sb.append("Visible");
+        }
+        return sb.toString();
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -3837,6 +3925,7 @@
             method = mCurMethod;
             p.println("  mCurMethod=" + mCurMethod);
             p.println("  mEnabledSession=" + mEnabledSession);
+            p.println("  mImeWindowVis=" + imeWindowStatusToString(mImeWindowVis));
             p.println("  mShowRequested=" + mShowRequested
                     + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
                     + " mShowForced=" + mShowForced
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 43d10c7..3fdcceb 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -779,11 +779,11 @@
             }
         }
 
-        if (hasNonDefaults) {
+        if (debug && hasNonDefaults) {
             if (dest.size() == 0) {
-                Slog.w(TAG, "resolveIntent failed: found match, but none with CATEGORY_DEFAULT");
+                Slog.v(TAG, "resolveIntent failed: found match, but none with CATEGORY_DEFAULT");
             } else if (dest.size() > 1) {
-                Slog.w(TAG, "resolveIntent: multiple matches, only some with CATEGORY_DEFAULT");
+                Slog.v(TAG, "resolveIntent: multiple matches, only some with CATEGORY_DEFAULT");
             }
         }
     }
diff --git a/services/core/java/com/android/server/LockGuard.java b/services/core/java/com/android/server/LockGuard.java
new file mode 100644
index 0000000..3a381ae
--- /dev/null
+++ b/services/core/java/com/android/server/LockGuard.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * LockGuard is a mechanism to help detect lock inversions inside the system
+ * server. It works by requiring each lock acquisition site to follow this
+ * pattern:
+ *
+ * <pre>
+ * synchronized (LockGuard.guard(lock)) {
+ * }
+ * </pre>
+ *
+ * <pre>
+ * $ find services/ -name "*.java" -exec sed -i -r \
+ *     's/synchronized.?\((.+?)\)/synchronized \(com.android.server.LockGuard.guard\(\1\)\)/' {} \;
+ * </pre>
+ *
+ * The {@link #guard(Object)} method internally verifies that all locking is
+ * done in a consistent order, and will log if any inversion is detected. For
+ * example, if the calling thread is trying to acquire the
+ * {@code ActivityManager} lock while holding the {@code PackageManager} lock,
+ * it will yell.
+ * <p>
+ * This class requires no prior knowledge of locks or their ordering; it derives
+ * all of this data at runtime. However, this means the overhead is
+ * <em>substantial</em> and it should not be enabled by default. For example,
+ * here are some benchmarked timings:
+ * <ul>
+ * <li>An unguarded synchronized block takes 40ns.
+ * <li>A guarded synchronized block takes 50ns when disabled.
+ * <li>A guarded synchronized block takes 460ns per lock checked when enabled.
+ * </ul>
+ */
+public class LockGuard {
+    private static final String TAG = "LockGuard";
+
+    private static ArrayMap<Object, LockInfo> sKnown = new ArrayMap<>(0, true);
+
+    private static class LockInfo {
+        /** Friendly label to describe this lock */
+        public String label;
+
+        /** Child locks that can be acquired while this lock is already held */
+        public ArraySet<Object> children = new ArraySet<>(0, true);
+    }
+
+    private static LockInfo findOrCreateLockInfo(Object lock) {
+        LockInfo info = sKnown.get(lock);
+        if (info == null) {
+            info = new LockInfo();
+            info.label = "0x" + Integer.toHexString(System.identityHashCode(lock)) + " ["
+                    + new Throwable().getStackTrace()[2].toString() + "]";
+            sKnown.put(lock, info);
+        }
+        return info;
+    }
+
+    /**
+     * Check if the calling thread is holding any locks in an inverted order.
+     *
+     * @param lock The lock the calling thread is attempting to acquire.
+     */
+    public static Object guard(Object lock) {
+        // If we already hold this lock, ignore
+        if (lock == null || Thread.holdsLock(lock)) return lock;
+
+        // Check to see if we're already holding any child locks
+        boolean triggered = false;
+        final LockInfo info = findOrCreateLockInfo(lock);
+        for (int i = 0; i < info.children.size(); i++) {
+            final Object child = info.children.valueAt(i);
+            if (child == null) continue;
+
+            if (Thread.holdsLock(child)) {
+                Slog.w(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding "
+                      + lockToString(child) + " while trying to acquire "
+                      + lockToString(lock), new Throwable());
+                triggered = true;
+            }
+        }
+
+        if (!triggered) {
+            // If no trouble found above, record this lock as being a valid
+            // child of all locks currently being held
+            for (int i = 0; i < sKnown.size(); i++) {
+                final Object test = sKnown.keyAt(i);
+                if (test == null || test == lock) continue;
+
+                if (Thread.holdsLock(test)) {
+                    sKnown.valueAt(i).children.add(lock);
+                }
+            }
+        }
+
+        return lock;
+    }
+
+    /**
+     * Report the given lock with a well-known label.
+     */
+    public static void installLock(Object lock, String label) {
+        final LockInfo info = findOrCreateLockInfo(lock);
+        info.label = label;
+    }
+
+    private static String lockToString(Object lock) {
+        final LockInfo info = sKnown.get(lock);
+        if (info != null) {
+            return info.label;
+        } else {
+            return "0x" + Integer.toHexString(System.identityHashCode(lock));
+        }
+    }
+
+    public static void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        for (int i = 0; i < sKnown.size(); i++) {
+            final Object lock = sKnown.keyAt(i);
+            final LockInfo info = sKnown.valueAt(i);
+            pw.println("Lock " + lockToString(lock) + ":");
+            for (int j = 0; j < info.children.size(); j++) {
+                pw.println("  Child " + lockToString(info.children.valueAt(j)));
+            }
+            pw.println();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index c318140..ed16af51 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -42,7 +42,10 @@
 
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IProgressListener;
+import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.storage.IMountService;
 import android.os.ServiceManager;
@@ -56,6 +59,7 @@
 import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
@@ -70,6 +74,8 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Keeps the lock pattern/password data and related settings for each user.
@@ -345,9 +351,9 @@
                     final int userId = users.get(user).id;
                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
-                    if (ownerInfo != null) {
+                    if (!TextUtils.isEmpty(ownerInfo)) {
                         setString(OWNER_INFO, ownerInfo, userId);
-                        Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
+                        Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
                     }
 
                     // Migrate owner info enabled.  Note there was a bug where older platforms only
@@ -545,9 +551,23 @@
         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
         final KeyStore ks = KeyStore.getInstance();
 
-        final List<UserInfo> profiles = um.getProfiles(userHandle);
-        for (UserInfo pi : profiles) {
-            ks.onUserPasswordChanged(pi.id, password);
+        if (um.getUserInfo(userHandle).isManagedProfile()) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
+                ks.onUserPasswordChanged(userHandle, password);
+            } else {
+                throw new RuntimeException("Can't set keystore password on a profile that "
+                        + "doesn't have a profile challenge.");
+            }
+        } else {
+            final List<UserInfo> profiles = um.getProfiles(userHandle);
+            for (UserInfo pi : profiles) {
+                // Change password on the given user and all its profiles that don't have
+                // their own profile challenge enabled.
+                if (pi.id == userHandle || (pi.isManagedProfile()
+                        && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
+                    ks.onUserPasswordChanged(pi.id, password);
+                }
+            }
         }
     }
 
@@ -555,18 +575,58 @@
         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
         final KeyStore ks = KeyStore.getInstance();
 
-        final List<UserInfo> profiles = um.getProfiles(userHandle);
-        for (UserInfo pi : profiles) {
-            ks.unlock(pi.id, password);
+        if (um.getUserInfo(userHandle).isManagedProfile()) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
+                ks.unlock(userHandle, password);
+            } else {
+                throw new RuntimeException("Can't unlock a profile explicitly if it "
+                        + "doesn't have a profile challenge.");
+            }
+        } else {
+            final List<UserInfo> profiles = um.getProfiles(userHandle);
+            for (UserInfo pi : profiles) {
+                // Unlock the given user and all its profiles that don't have
+                // their own profile challenge enabled.
+                if (pi.id == userHandle || (pi.isManagedProfile()
+                        && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
+                    ks.unlock(pi.id, password);
+                }
+            }
         }
     }
 
     private void unlockUser(int userId, byte[] token, byte[] secret) {
+        // TODO: make this method fully async so we can update UI with progress strings
+        final CountDownLatch latch = new CountDownLatch(1);
+        final IProgressListener listener = new IProgressListener.Stub() {
+            @Override
+            public void onStarted(int id, Bundle extras) throws RemoteException {
+                // Ignored
+            }
+
+            @Override
+            public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
+                // Ignored
+            }
+
+            @Override
+            public void onFinished(int id, Bundle extras) throws RemoteException {
+                Log.d(TAG, "unlockUser finished!");
+                latch.countDown();
+            }
+        };
+
         try {
-            ActivityManagerNative.getDefault().unlockUser(userId, token, secret);
+            ActivityManagerNative.getDefault().unlockUser(userId, token, secret, listener);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
+
+        try {
+            latch.await(15, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
     }
 
     private byte[] getCurrentHandle(int userId) {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 53923ba..440d8b7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -165,6 +165,7 @@
         public void onStart() {
             mMountService = new MountService(getContext());
             publishBinderService("mount", mMountService);
+            mMountService.start();
         }
 
         @Override
@@ -430,9 +431,13 @@
         = { "password", "default", "pattern", "pin" };
 
     private final Context mContext;
+
     private final NativeDaemonConnector mConnector;
     private final NativeDaemonConnector mCryptConnector;
 
+    private final Thread mConnectorThread;
+    private final Thread mCryptConnectorThread;
+
     private volatile boolean mSystemReady = false;
     private volatile boolean mBootCompleted = false;
     private volatile boolean mDaemonConnected = false;
@@ -809,7 +814,9 @@
                 if (user.isSystemOnly()) continue;
 
                 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.id);
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.id);
                 if (provider != null) {
                     final IActivityManager am = ActivityManagerNative.getDefault();
                     try {
@@ -839,11 +846,11 @@
         Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
                 + ", mDaemonConnected=" + mDaemonConnected);
         if (mSystemReady && mDaemonConnected
-                && !StorageManager.isNativeFileBasedEncryptionEnabled()) {
+                && !StorageManager.isFileEncryptedNativeOnly()) {
             // When booting a device without native support, make sure that our
             // user directories are locked or unlocked based on the current
             // emulation status.
-            final boolean initLocked = StorageManager.isEmulatedFileBasedEncryptionEnabled();
+            final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
             Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
             final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
             for (UserInfo user : users) {
@@ -1224,7 +1231,8 @@
         }
 
         final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
         intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
         mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
@@ -1239,6 +1247,11 @@
     }
 
     private void onVolumeCreatedLocked(VolumeInfo vol) {
+        if (mPms.isOnlyCoreApps()) {
+            Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
+            return;
+        }
+
         if (vol.type == VolumeInfo.TYPE_EMULATED) {
             final StorageManager storage = mContext.getSystemService(StorageManager.class);
             final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
@@ -1340,7 +1353,8 @@
             intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
             intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
             intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
             mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
         }
 
@@ -1492,17 +1506,13 @@
                 null);
         mConnector.setDebug(true);
         mConnector.setWarnIfHeld(mLock);
-
-        Thread thread = new Thread(mConnector, VOLD_TAG);
-        thread.start();
+        mConnectorThread = new Thread(mConnector, VOLD_TAG);
 
         // Reuse parameters from first connector since they are tested and safe
         mCryptConnector = new NativeDaemonConnector(this, "cryptd",
                 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
         mCryptConnector.setDebug(true);
-
-        Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
-        crypt_thread.start();
+        mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
 
         final IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_ADDED);
@@ -1519,6 +1529,11 @@
         }
     }
 
+    private void start() {
+        mConnectorThread.start();
+        mCryptConnectorThread.start();
+    }
+
     private void systemReady() {
         mSystemReady = true;
         mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
@@ -1940,16 +1955,25 @@
         waitForReady();
 
         if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
-            if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+            if (StorageManager.isFileEncryptedNativeOnly()) {
                 throw new IllegalStateException(
                         "Emulation not available on device with native FBE");
             }
+            if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
+                throw new IllegalStateException(
+                        "Emulation requires disabling 'Secure start-up' in Settings > Security");
+            }
 
-            final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
-            SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
+                SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
 
-            // Perform hard reboot to kick policy into place
-            mContext.getSystemService(PowerManager.class).reboot(null);
+                // Perform hard reboot to kick policy into place
+                mContext.getSystemService(PowerManager.class).reboot(null);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
@@ -2806,7 +2830,7 @@
 
     @Override
     public boolean isUserKeyUnlocked(int userId) {
-        if (StorageManager.isFileBasedEncryptionEnabled()) {
+        if (StorageManager.isFileEncryptedNativeOrEmulated()) {
             synchronized (mLock) {
                 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
             }
@@ -2901,36 +2925,57 @@
     @Override
     public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
         final int userId = UserHandle.getUserId(uid);
+
         final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
+        final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
+        final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
 
-        boolean reportUnmounted = false;
-        boolean foundPrimary = false;
-
-        final long identity = Binder.clearCallingIdentity();
+        final boolean userKeyUnlocked;
+        final boolean storagePermission;
+        final long token = Binder.clearCallingIdentity();
         try {
-            if (!mMountServiceInternal.hasExternalStorage(uid, packageName)) {
-                reportUnmounted = true;
-            }
-            if (!isUserKeyUnlocked(userId)) {
-                reportUnmounted = true;
-            }
+            userKeyUnlocked = isUserKeyUnlocked(userId);
+            storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName);
         } finally {
-            Binder.restoreCallingIdentity(identity);
+            Binder.restoreCallingIdentity(token);
         }
 
+        boolean foundPrimary = false;
+
         final ArrayList<StorageVolume> res = new ArrayList<>();
         synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
-                if (forWrite ? vol.isVisibleForWrite(userId) : vol.isVisibleForRead(userId)) {
-                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
-                            reportUnmounted);
-                    if (vol.isPrimary()) {
-                        res.add(0, userVol);
-                        foundPrimary = true;
-                    } else {
-                        res.add(userVol);
-                    }
+                switch (vol.getType()) {
+                    case VolumeInfo.TYPE_PUBLIC:
+                    case VolumeInfo.TYPE_EMULATED:
+                        break;
+                    default:
+                        continue;
+                }
+
+                boolean match = false;
+                if (forWrite) {
+                    match = vol.isVisibleForWrite(userId);
+                } else {
+                    match = vol.isVisibleForRead(userId) || includeInvisible;
+                }
+                if (!match) continue;
+
+                boolean reportUnmounted = false;
+                if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
+                    reportUnmounted = true;
+                } else if (!storagePermission && !realState) {
+                    reportUnmounted = true;
+                }
+
+                final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
+                        reportUnmounted);
+                if (vol.isPrimary()) {
+                    res.add(0, userVol);
+                    foundPrimary = true;
+                } else {
+                    res.add(userVol);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 799d0bd..bf4df94 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -22,8 +22,10 @@
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
@@ -43,11 +45,11 @@
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-
 import android.annotation.NonNull;
 import android.app.ActivityManagerNative;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.INetd;
 import android.net.INetworkManagementEventObserver;
 import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
@@ -121,7 +123,7 @@
     private static final String TAG = "NetworkManagement";
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private static final String NETD_TAG = "NetdConnector";
-    private static final String NETD_SOCKET_NAME = "netd";
+    private static final String NETD_SERVICE_NAME = "netd";
 
     private static final int MAX_UID_RANGES_PER_COMMAND = 10;
 
@@ -187,6 +189,8 @@
     private final Handler mFgHandler;
     private final Handler mDaemonHandler;
 
+    private INetd mNetdService;
+
     private IBatteryStats mBatteryStats;
 
     private final Thread mThread;
@@ -205,9 +209,12 @@
     /** Set of interfaces with active alerts. */
     @GuardedBy("mQuotaLock")
     private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
-    /** Set of UIDs with active reject rules. */
+    /** Set of UIDs blacklisted on metered networks. */
     @GuardedBy("mQuotaLock")
-    private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
+    private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray();
+    /** Set of UIDs whitelisted on metered networks. */
+    @GuardedBy("mQuotaLock")
+    private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray();
     /** Set of UIDs with cleartext penalties. */
     @GuardedBy("mQuotaLock")
     private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
@@ -226,10 +233,19 @@
      */
     @GuardedBy("mQuotaLock")
     private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+    /**
+     * Set of UIDs that are to be blocked/allowed by firewall controller.  This set of Ids matches
+     * to device on power-save mode.
+     */
+    @GuardedBy("mQuotaLock")
+    private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
     /** Set of states for the child firewall chains. True if the chain is active. */
     @GuardedBy("mQuotaLock")
     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
 
+    @GuardedBy("mQuotaLock")
+    private boolean mDataSaverMode;
+
     private Object mIdleTimerLock = new Object();
     /** Set of interfaces with active idle timers. */
     private static class IdleTimerParams {
@@ -286,8 +302,8 @@
         Watchdog.getInstance().addMonitor(this);
     }
 
-    static NetworkManagementService create(Context context,
-            String socket) throws InterruptedException {
+    static NetworkManagementService create(Context context, String socket)
+            throws InterruptedException {
         final NetworkManagementService service = new NetworkManagementService(context, socket);
         final CountDownLatch connectedSignal = service.mConnectedSignal;
         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
@@ -299,12 +315,19 @@
     }
 
     public static NetworkManagementService create(Context context) throws InterruptedException {
-        return create(context, NETD_SOCKET_NAME);
+        return create(context, NETD_SERVICE_NAME);
     }
 
     public void systemReady() {
-        prepareNativeDaemon();
-        if (DBG) Slog.d(TAG, "Prepared");
+        if (DBG) {
+            final long start = System.currentTimeMillis();
+            prepareNativeDaemon();
+            final long delta = System.currentTimeMillis() - start;
+            Slog.d(TAG, "Prepared in " + delta + "ms");
+            return;
+        } else {
+            prepareNativeDaemon();
+        }
     }
 
     private IBatteryStats getBatteryStats() {
@@ -339,8 +362,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -358,8 +380,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -376,8 +397,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceAdded(iface);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -399,8 +419,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceRemoved(iface);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -417,8 +436,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).limitReached(limitName, iface);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -476,8 +494,7 @@
                     try {
                         mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
                                 Integer.toString(type), isActive, tsNanos);
-                    } catch (RemoteException e) {
-                    } catch (RuntimeException e) {
+                    } catch (RemoteException | RuntimeException e) {
                     }
                 }
             } finally {
@@ -502,11 +519,42 @@
         }
     }
 
+    // Sync the state of the given chain with the native daemon.
+    private void syncFirewallChainLocked(int chain, SparseIntArray uidFirewallRules, String name) {
+        int size = uidFirewallRules.size();
+        if (size > 0) {
+            // Make a copy of the current rules, and then clear them. This is because
+            // setFirewallUidRuleInternal only pushes down rules to the native daemon if they are
+            // different from the current rules stored in the mUidFirewall*Rules array for the
+            // specified chain. If we don't clear the rules, setFirewallUidRuleInternal will do
+            // nothing.
+            final SparseIntArray rules = uidFirewallRules.clone();
+            uidFirewallRules.clear();
+
+            // Now push the rules. setFirewallUidRuleInternal will push each of these down to the
+            // native daemon, and also add them to the mUidFirewall*Rules array for the specified
+            // chain.
+            if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall " + name + "UID rules");
+            for (int i = 0; i < rules.size(); i++) {
+                setFirewallUidRuleInternal(chain, rules.keyAt(i), rules.valueAt(i));
+            }
+        }
+    }
+
     /**
      * Prepare native daemon once connected, enabling modules and pushing any
      * existing in-memory rules.
      */
     private void prepareNativeDaemon() {
+        boolean nativeServiceAvailable = false;
+        try {
+            mNetdService = INetd.Stub.asInterface(ServiceManager.getService(NETD_SERVICE_NAME));
+            nativeServiceAvailable = mNetdService.isAlive();
+        } catch (RemoteException e) {}
+        if (!nativeServiceAvailable) {
+            Slog.wtf(TAG, "Can't connect to NativeNetdService " + NETD_SERVICE_NAME);
+        }
+
         mBandwidthControlEnabled = false;
 
         // only enable bandwidth control when support exists
@@ -520,7 +568,7 @@
                 Log.wtf(TAG, "problem enabling bandwidth controls", e);
             }
         } else {
-            Slog.d(TAG, "not enabling bandwidth control");
+            Slog.i(TAG, "not enabling bandwidth control");
         }
 
         SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
@@ -541,9 +589,12 @@
 
         // push any existing quota or UID rules
         synchronized (mQuotaLock) {
+
+            setDataSaverModeEnabled(mDataSaverMode);
+
             int size = mActiveQuotas.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active quota rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active quota rules");
                 final HashMap<String, Long> activeQuotas = mActiveQuotas;
                 mActiveQuotas = Maps.newHashMap();
                 for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
@@ -553,7 +604,7 @@
 
             size = mActiveAlerts.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active alert rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active alert rules");
                 final HashMap<String, Long> activeAlerts = mActiveAlerts;
                 mActiveAlerts = Maps.newHashMap();
                 for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
@@ -561,19 +612,31 @@
                 }
             }
 
-            size = mUidRejectOnQuota.size();
+            size = mUidRejectOnMetered.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active UID rules");
-                final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
-                mUidRejectOnQuota = new SparseBooleanArray();
+                if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered whitelist rules");
+                final SparseBooleanArray uidRejectOnQuota = mUidRejectOnMetered;
+                mUidRejectOnMetered = new SparseBooleanArray();
                 for (int i = 0; i < uidRejectOnQuota.size(); i++) {
-                    setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
+                    setUidMeteredNetworkBlacklist(uidRejectOnQuota.keyAt(i),
+                            uidRejectOnQuota.valueAt(i));
+                }
+            }
+
+            size = mUidAllowOnMetered.size();
+            if (size > 0) {
+                if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered blacklist rules");
+                final SparseBooleanArray uidAcceptOnQuota = mUidAllowOnMetered;
+                mUidAllowOnMetered = new SparseBooleanArray();
+                for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
+                    setUidMeteredNetworkWhitelist(uidAcceptOnQuota.keyAt(i),
+                            uidAcceptOnQuota.valueAt(i));
                 }
             }
 
             size = mUidCleartextPolicy.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
                 final SparseIntArray local = mUidCleartextPolicy;
                 mUidCleartextPolicy = new SparseIntArray();
                 for (int i = 0; i < local.size(); i++) {
@@ -583,44 +646,21 @@
 
             setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
 
-            size = mUidFirewallRules.size();
-            if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
-                final SparseIntArray uidFirewallRules = mUidFirewallRules;
-                mUidFirewallRules = new SparseIntArray();
-                for (int i = 0; i < uidFirewallRules.size(); i++) {
-                    setFirewallUidRuleInternal(FIREWALL_CHAIN_NONE, uidFirewallRules.keyAt(i),
-                            uidFirewallRules.valueAt(i));
-                }
-            }
+            syncFirewallChainLocked(FIREWALL_CHAIN_NONE, mUidFirewallRules, "");
+            syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, mUidFirewallStandbyRules, "standby ");
+            syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mUidFirewallDozableRules, "dozable ");
+            syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, mUidFirewallPowerSaveRules,
+                    "powersave ");
 
-            size = mUidFirewallStandbyRules.size();
-            if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules");
-                final SparseIntArray uidFirewallRules = mUidFirewallStandbyRules;
-                mUidFirewallStandbyRules = new SparseIntArray();
-                for (int i = 0; i < uidFirewallRules.size(); i++) {
-                    setFirewallUidRuleInternal(FIREWALL_CHAIN_STANDBY, uidFirewallRules.keyAt(i),
-                            uidFirewallRules.valueAt(i));
-                }
-            }
             if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)) {
                 setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
             }
-
-            size = mUidFirewallDozableRules.size();
-            if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules");
-                final SparseIntArray uidFirewallRules = mUidFirewallDozableRules;
-                mUidFirewallDozableRules = new SparseIntArray();
-                for (int i = 0; i < uidFirewallRules.size(); i++) {
-                    setFirewallUidRuleInternal(FIREWALL_CHAIN_DOZABLE, uidFirewallRules.keyAt(i),
-                            uidFirewallRules.valueAt(i));
-                }
-            }
             if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
                 setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
             }
+            if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)) {
+                setFirewallChainEnabled(FIREWALL_CHAIN_POWERSAVE, true);
+            }
         }
     }
 
@@ -633,8 +673,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).addressUpdated(iface, address);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -651,8 +690,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).addressRemoved(iface, address);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -670,8 +708,7 @@
                 try {
                     mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
                         addresses);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -692,8 +729,7 @@
                     } else {
                         mObservers.getBroadcastItem(i).routeRemoved(route);
                     }
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -708,6 +744,7 @@
     private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
         @Override
         public void onDaemonConnected() {
+            Slog.i(TAG, "onDaemonConnected()");
             // event is dispatched from internal NDC thread, so we prepare the
             // daemon back on main thread.
             if (mConnectedSignal != null) {
@@ -1119,81 +1156,6 @@
     }
 
     @Override
-    public RouteInfo[] getRoutes(String interfaceName) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
-
-        // v4 routes listed as:
-        // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
-        for (String s : readRouteList("/proc/net/route")) {
-            String[] fields = s.split("\t");
-
-            if (fields.length > 7) {
-                String iface = fields[0];
-
-                if (interfaceName.equals(iface)) {
-                    String dest = fields[1];
-                    String gate = fields[2];
-                    String flags = fields[3]; // future use?
-                    String mask = fields[7];
-                    try {
-                        // address stored as a hex string, ex: 0014A8C0
-                        InetAddress destAddr =
-                                NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
-                        int prefixLength =
-                                NetworkUtils.netmaskIntToPrefixLength(
-                                (int)Long.parseLong(mask, 16));
-                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
-
-                        // address stored as a hex string, ex 0014A8C0
-                        InetAddress gatewayAddr =
-                                NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
-
-                        RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
-                        routes.add(route);
-                    } catch (Exception e) {
-                        Log.e(TAG, "Error parsing route " + s + " : " + e);
-                        continue;
-                    }
-                }
-            }
-        }
-
-        // v6 routes listed as:
-        // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
-        for (String s : readRouteList("/proc/net/ipv6_route")) {
-            String[]fields = s.split("\\s+");
-            if (fields.length > 9) {
-                String iface = fields[9].trim();
-                if (interfaceName.equals(iface)) {
-                    String dest = fields[0];
-                    String prefix = fields[1];
-                    String gate = fields[4];
-
-                    try {
-                        // prefix length stored as a hex string, ex 40
-                        int prefixLength = Integer.parseInt(prefix, 16);
-
-                        // address stored as a 32 char hex string
-                        // ex fe800000000000000000000000000000
-                        InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
-                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
-
-                        InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
-
-                        RouteInfo route = new RouteInfo(linkAddress, gateAddr);
-                        routes.add(route);
-                    } catch (Exception e) {
-                        Log.e(TAG, "Error parsing route " + s + " : " + e);
-                        continue;
-                    }
-                }
-            }
-        }
-        return routes.toArray(new RouteInfo[routes.size()]);
-    }
-
-    @Override
     public void setMtu(String iface, int mtu) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
@@ -1210,7 +1172,7 @@
         // TODO: remove from aidl if nobody calls externally
         mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
 
-        Slog.d(TAG, "Shutting down");
+        Slog.i(TAG, "Shutting down");
     }
 
     @Override
@@ -1743,28 +1705,30 @@
         }
     }
 
-    @Override
-    public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+    private void setUidOnMeteredNetworkList(SparseBooleanArray quotaList, int uid,
+            boolean blacklist, boolean enable) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         // silently discard when control disabled
         // TODO: eventually migrate to be always enabled
         if (!mBandwidthControlEnabled) return;
 
+        final String chain = blacklist ? "naughtyapps" : "niceapps";
+        final String suffix = enable ? "add" : "remove";
+
         synchronized (mQuotaLock) {
-            final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
-            if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
+            final boolean oldEnable = quotaList.get(uid, false);
+            if (oldEnable == enable) {
                 // TODO: eventually consider throwing
                 return;
             }
 
             try {
-                mConnector.execute("bandwidth",
-                        rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
-                if (rejectOnQuotaInterfaces) {
-                    mUidRejectOnQuota.put(uid, true);
+                mConnector.execute("bandwidth", suffix + chain, uid);
+                if (enable) {
+                    quotaList.put(uid, true);
                 } else {
-                    mUidRejectOnQuota.delete(uid);
+                    quotaList.delete(uid);
                 }
             } catch (NativeDaemonConnectorException e) {
                 throw e.rethrowAsParcelableException();
@@ -1773,6 +1737,39 @@
     }
 
     @Override
+    public void setUidMeteredNetworkBlacklist(int uid, boolean enable) {
+        setUidOnMeteredNetworkList(mUidRejectOnMetered, uid, true, enable);
+    }
+
+    @Override
+    public void setUidMeteredNetworkWhitelist(int uid, boolean enable) {
+        setUidOnMeteredNetworkList(mUidAllowOnMetered, uid, false, enable);
+    }
+
+    @Override
+    public boolean setDataSaverModeEnabled(boolean enable) {
+        if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
+        synchronized (mQuotaLock) {
+            if (mDataSaverMode == enable) {
+                Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
+                return true;
+            }
+            try {
+                final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
+                if (changed) {
+                    mDataSaverMode = enable;
+                } else {
+                    Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed");
+                }
+                return changed;
+            } catch (RemoteException e) {
+                Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
+                return false;
+            }
+        }
+    }
+
+    @Override
     public void setUidCleartextNetworkPolicy(int uid, int policy) {
         if (Binder.getCallingUid() != uid) {
             mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1940,16 +1937,6 @@
     }
 
     @Override
-    public void flushNetworkDnsCache(int netId) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "flushnet", netId);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
     public void setFirewallEnabled(boolean enabled) {
         enforceSystemUid();
         try {
@@ -2023,6 +2010,9 @@
                     case FIREWALL_CHAIN_DOZABLE:
                         chainName = FIREWALL_CHAIN_NAME_DOZABLE;
                         break;
+                    case FIREWALL_CHAIN_POWERSAVE:
+                        chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
+                        break;
                     default:
                         throw new IllegalArgumentException("Bad child chain: " + chain);
                 }
@@ -2039,6 +2029,8 @@
                 return FIREWALL_TYPE_BLACKLIST;
             case FIREWALL_CHAIN_DOZABLE:
                 return FIREWALL_TYPE_WHITELIST;
+            case FIREWALL_CHAIN_POWERSAVE:
+                return FIREWALL_TYPE_WHITELIST;
             default:
                 return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
         }
@@ -2138,6 +2130,8 @@
                 return mUidFirewallStandbyRules;
             case FIREWALL_CHAIN_DOZABLE:
                 return mUidFirewallDozableRules;
+            case FIREWALL_CHAIN_POWERSAVE:
+                return mUidFirewallPowerSaveRules;
             case FIREWALL_CHAIN_NONE:
                 return mUidFirewallRules;
             default:
@@ -2151,6 +2145,8 @@
                 return FIREWALL_CHAIN_NAME_STANDBY;
             case FIREWALL_CHAIN_DOZABLE:
                 return FIREWALL_CHAIN_NAME_DOZABLE;
+            case FIREWALL_CHAIN_POWERSAVE:
+                return FIREWALL_CHAIN_NAME_POWERSAVE;
             case FIREWALL_CHAIN_NONE:
                 return FIREWALL_CHAIN_NAME_NONE;
             default:
@@ -2225,8 +2221,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -2258,56 +2253,31 @@
         synchronized (mQuotaLock) {
             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
             pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
-        }
-
-        synchronized (mUidRejectOnQuota) {
-            pw.print("UID reject on quota ifaces: [");
-            final int size = mUidRejectOnQuota.size();
-            for (int i = 0; i < size; i++) {
-                pw.print(mUidRejectOnQuota.keyAt(i));
-                if (i < size - 1) pw.print(",");
-            }
-            pw.println("]");
+            pw.print("Data saver mode: "); pw.println(mDataSaverMode);
+            dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered);
+            dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered);
         }
 
         synchronized (mUidFirewallRules) {
-            pw.print("UID firewall rule: [");
-            final int size = mUidFirewallRules.size();
-            for (int i = 0; i < size; i++) {
-                pw.print(mUidFirewallRules.keyAt(i));
-                pw.print(":");
-                pw.print(mUidFirewallRules.valueAt(i));
-                if (i < size - 1) pw.print(",");
-            }
-            pw.println("]");
+            dumpUidFirewallRule(pw, "", mUidFirewallRules);
         }
 
-        pw.println("UID firewall standby chain enabled: " +
+        pw.print("UID firewall standby chain enabled: "); pw.println(
                 mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
         synchronized (mUidFirewallStandbyRules) {
-            pw.print("UID firewall standby rule: [");
-            final int size = mUidFirewallStandbyRules.size();
-            for (int i = 0; i < size; i++) {
-                pw.print(mUidFirewallStandbyRules.keyAt(i));
-                pw.print(":");
-                pw.print(mUidFirewallStandbyRules.valueAt(i));
-                if (i < size - 1) pw.print(",");
-            }
-            pw.println("]");
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
         }
 
-        pw.println("UID firewall dozable chain enabled: " +
+        pw.print("UID firewall dozable chain enabled: "); pw.println(
                 mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
         synchronized (mUidFirewallDozableRules) {
-            pw.print("UID firewall dozable rule: [");
-            final int size = mUidFirewallDozableRules.size();
-            for (int i = 0; i < size; i++) {
-                pw.print(mUidFirewallDozableRules.keyAt(i));
-                pw.print(":");
-                pw.print(mUidFirewallDozableRules.valueAt(i));
-                if (i < size - 1) pw.print(",");
-            }
-            pw.println("]");
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
+        }
+
+        pw.println("UID firewall powersave chain enabled: " +
+                mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE));
+        synchronized (mUidFirewallPowerSaveRules) {
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
         }
 
         synchronized (mIdleTimerLock) {
@@ -2322,6 +2292,43 @@
         }
 
         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
+        pw.print("Netd service status: " );
+        if (mNetdService == null) {
+            pw.println("disconnected");
+        } else {
+            try {
+                final boolean alive = mNetdService.isAlive();
+                pw.println(alive ? "alive": "dead");
+            } catch (RemoteException e) {
+                pw.println("unreachable");
+            }
+        }
+    }
+
+    private void dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list) {
+        pw.print("UID bandwith control ");
+        pw.print(name);
+        pw.print(" rule: [");
+        final int size = list.size();
+        for (int i = 0; i < size; i++) {
+            pw.print(list.keyAt(i));
+            if (i < size - 1) pw.print(",");
+        }
+        pw.println("]");
+    }
+
+    private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
+        pw.print("UID firewall");
+        pw.print(name);
+        pw.print(" rule: [");
+        final int size = rules.size();
+        for (int i = 0; i < size; i++) {
+            pw.print(rules.keyAt(i));
+            pw.print(":");
+            pw.print(rules.valueAt(i));
+            if (i < size - 1) pw.print(",");
+        }
+        pw.println("]");
     }
 
     @Override
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 879bb6f..2a78f90 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -18,10 +18,12 @@
 
 import android.Manifest.permission;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.net.INetworkScoreCache;
 import android.net.INetworkScoreService;
@@ -30,6 +32,7 @@
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.net.ScoredNetwork;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -55,17 +58,17 @@
  */
 public class NetworkScoreService extends INetworkScoreService.Stub {
     private static final String TAG = "NetworkScoreService";
+    private static final boolean DBG = false;
 
     private final Context mContext;
-
     private final Map<Integer, INetworkScoreCache> mScoreCaches;
-
     /** Lock used to update mReceiver when scorer package changes occur. */
-    private Object mReceiverLock = new Object[0];
+    private final Object mReceiverLock = new Object[0];
 
     /** Clears scores when the active scorer package is no longer valid. */
     @GuardedBy("mReceiverLock")
     private ScorerChangedReceiver mReceiver;
+    private ScoringServiceConnection mServiceConnection;
 
     private class ScorerChangedReceiver extends BroadcastReceiver {
         final String mRegisteredPackage;
@@ -77,14 +80,23 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if ((Intent.ACTION_PACKAGE_CHANGED.equals(action) ||
-                    Intent.ACTION_PACKAGE_REPLACED.equals(action) ||
-                    Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) &&
-                    NetworkScorerAppManager.getActiveScorer(mContext) == null) {
-                // Package change has invalidated a scorer.
-                Log.i(TAG, "Package " + mRegisteredPackage +
-                        " is no longer valid, disabling scoring");
-                setScorerInternal(null);
+            if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
+                    || Intent.ACTION_PACKAGE_REPLACED.equals(action)
+                    || Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
+                NetworkScorerAppData activeScorer =
+                        NetworkScorerAppManager.getActiveScorer(mContext);
+                if (activeScorer == null) {
+                    // Package change has invalidated a scorer.
+                    Log.i(TAG, "Package " + mRegisteredPackage +
+                            " is no longer valid, disabling scoring.");
+                    setScorerInternal(null);
+                } else if (activeScorer.mScoringServiceClassName == null) {
+                    // The scoring service is not available, make sure it's unbound.
+                    unbindFromScoringServiceIfNeeded();
+                } else {
+                    // The scoring service may have changed or been added.
+                    bindToScoringServiceIfNeeded(activeScorer);
+                }
             }
         }
     }
@@ -96,6 +108,7 @@
 
     /** Called when the system is ready to run third-party code but before it actually does so. */
     void systemReady() {
+        if (DBG) Log.d(TAG, "systemReady");
         ContentResolver cr = mContext.getContentResolver();
         if (Settings.Global.getInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 0) == 0) {
             // On first run, we try to initialize the scorer to the one configured at build time.
@@ -111,7 +124,14 @@
         registerPackageReceiverIfNeeded();
     }
 
+    /** Called when the system is ready for us to start third-party code. */
+    void systemRunning() {
+        if (DBG) Log.d(TAG, "systemRunning");
+        bindToScoringServiceIfNeeded();
+    }
+
     private void registerPackageReceiverIfNeeded() {
+        if (DBG) Log.d(TAG, "registerPackageReceiverIfNeeded");
         NetworkScorerAppData scorer = NetworkScorerAppManager.getActiveScorer(mContext);
         synchronized (mReceiverLock) {
             // Unregister the receiver if the current scorer has changed since last registration.
@@ -142,6 +162,41 @@
         }
     }
 
+    private void bindToScoringServiceIfNeeded() {
+        if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded");
+        NetworkScorerAppData scorerData = NetworkScorerAppManager.getActiveScorer(mContext);
+        bindToScoringServiceIfNeeded(scorerData);
+    }
+
+    private void bindToScoringServiceIfNeeded(NetworkScorerAppData scorerData) {
+        if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + scorerData + ")");
+        if (scorerData != null && scorerData.mScoringServiceClassName != null) {
+            ComponentName componentName =
+                    new ComponentName(scorerData.mPackageName, scorerData.mScoringServiceClassName);
+            // If we're connected to a different component then drop it.
+            if (mServiceConnection != null
+                    && !mServiceConnection.mComponentName.equals(componentName)) {
+                unbindFromScoringServiceIfNeeded();
+            }
+
+            // If we're not connected at all then create a new connection.
+            if (mServiceConnection == null) {
+                mServiceConnection = new ScoringServiceConnection(componentName);
+            }
+
+            // Make sure the connection is connected (idempotent)
+            mServiceConnection.connect(mContext);
+        }
+    }
+
+    private void unbindFromScoringServiceIfNeeded() {
+        if (DBG) Log.d(TAG, "unbindFromScoringServiceIfNeeded");
+        if (mServiceConnection != null) {
+            mServiceConnection.disconnect(mContext);
+        }
+        mServiceConnection = null;
+    }
+
     @Override
     public boolean updateScores(ScoredNetwork[] networks) {
         if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) {
@@ -228,8 +283,10 @@
 
     /** Set the active scorer. Callers are responsible for checking permissions as appropriate. */
     private boolean setScorerInternal(String packageName) {
+        if (DBG) Log.d(TAG, "setScorerInternal(" + packageName + ")");
         long token = Binder.clearCallingIdentity();
         try {
+            unbindFromScoringServiceIfNeeded();
             // Preemptively clear scores even though the set operation could fail. We do this for
             // safety as scores should never be compared across apps; in practice, Settings should
             // only be allowing valid apps to be set as scorers, so failure here should be rare.
@@ -237,8 +294,13 @@
             // Get the scorer that is about to be replaced, if any, so we can notify it directly.
             NetworkScorerAppData prevScorer = NetworkScorerAppManager.getActiveScorer(mContext);
             boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
+            // Unconditionally attempt to bind to the current scorer. If setActiveScorer() failed
+            // then we'll attempt to restore the previous binding (if any), otherwise an attempt
+            // will be made to bind to the new scorer.
+            bindToScoringServiceIfNeeded();
             if (result) { // new scorer successfully set
                 registerPackageReceiverIfNeeded();
+
                 Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
                 if (prevScorer != null) { // Directly notify the old scorer.
                     intent.setPackage(prevScorer.mPackageName);
@@ -295,7 +357,6 @@
             return;
         }
         writer.println("Current scorer: " + currentScorer.mPackageName);
-        writer.flush();
 
         for (INetworkScoreCache scoreCache : getScoreCaches()) {
             try {
@@ -307,6 +368,12 @@
                 }
             }
         }
+        if (mServiceConnection != null) {
+            mServiceConnection.dump(fd, writer, args);
+        } else {
+            writer.println("ScoringServiceConnection: null");
+        }
+        writer.flush();
     }
 
     /**
@@ -320,4 +387,50 @@
             return new HashSet<>(mScoreCaches.values());
         }
     }
+
+    private static class ScoringServiceConnection implements ServiceConnection {
+        private final ComponentName mComponentName;
+        private boolean mBound = false;
+
+        ScoringServiceConnection(ComponentName componentName) {
+            mComponentName = componentName;
+        }
+
+        void connect(Context context) {
+            disconnect(context);
+            Intent service = new Intent();
+            service.setComponent(mComponentName);
+            mBound = context.bindServiceAsUser(service, this,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                    UserHandle.SYSTEM);
+            if (!mBound) {
+                Log.w(TAG, "Bind call failed for " + service);
+            }
+        }
+
+        void disconnect(Context context) {
+            try {
+                if (mBound) {
+                    mBound = false;
+                    context.unbindService(this);
+                }
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Unbind failed.", e);
+            }
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DBG) Log.d(TAG, "ScoringServiceConnection: " + name.flattenToString());
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DBG) Log.d(TAG, "ScoringServiceConnection, disconnected: " + name.flattenToString());
+        }
+
+        public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+            writer.println("ScoringServiceConnection: " + mComponentName + ", bound: " + mBound);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 3f0664d..b64c65d 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -23,8 +23,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -34,10 +36,14 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
 import android.util.TrustedTime;
 
 import com.android.internal.telephony.TelephonyIntents;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * Monitors the network time and updates the system time if it is out of sync
  * and there hasn't been any NITZ update from the carrier recently.
@@ -48,7 +54,7 @@
  * available.
  * </p>
  */
-public class NetworkTimeUpdateService {
+public class NetworkTimeUpdateService extends Binder {
 
     private static final String TAG = "NetworkTimeUpdateService";
     private static final boolean DBG = false;
@@ -59,6 +65,8 @@
 
     private static final String ACTION_POLL =
             "com.android.server.NetworkTimeUpdateService.action.POLL";
+
+    private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000;
     private static int POLL_REQUEST = 0;
 
     private static final long NOT_SET = -1;
@@ -245,6 +253,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            if (DBG) Log.d(TAG, "Received " + action);
             if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
                 mNitzTimeSetTime = SystemClock.elapsedRealtime();
             } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
@@ -260,8 +269,11 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
+                if (DBG) Log.d(TAG, "Received CONNECTIVITY_ACTION ");
                 // Don't bother checking if we have connectivity, NtpTrustedTime does that for us.
-                mHandler.obtainMessage(EVENT_NETWORK_CHANGED).sendToTarget();
+                Message message = mHandler.obtainMessage(EVENT_NETWORK_CHANGED);
+                // Send with a short delay to make sure the network is ready for use
+                mHandler.sendMessageDelayed(message, NETWORK_CHANGE_EVENT_DELAY_MS);
             }
         }
     };
@@ -308,4 +320,28 @@
             mHandler.obtainMessage(mMsg).sendToTarget();
         }
     }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump NetworkTimeUpdateService from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " without permission "
+                    + android.Manifest.permission.DUMP);
+            return;
+        }
+        pw.print("PollingIntervalMs: ");
+        TimeUtils.formatDuration(mPollingIntervalMs, pw);
+        pw.print("\nPollingIntervalShorterMs: ");
+        TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+        pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+        pw.print("TimeErrorThresholdMs: ");
+        TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
+        pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+        pw.print("LastNtpFetchTime: ");
+        TimeUtils.formatDuration(mLastNtpFetchTime, pw);
+        pw.println();
+    }
 }
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index f4c6225..a44b065 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -30,16 +30,14 @@
 import android.os.Messenger;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.Base64;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
 import com.android.internal.util.AsyncChannel;
@@ -58,7 +56,7 @@
     private static final String TAG = "NsdService";
     private static final String MDNS_TAG = "mDnsConnector";
 
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     private Context mContext;
     private ContentResolver mContentResolver;
@@ -492,6 +490,7 @@
                         clientInfo.mResolvedService.setServiceName(name);
                         clientInfo.mResolvedService.setServiceType(type);
                         clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
+                        clientInfo.mResolvedService.setTxtRecords(cooked[6]);
 
                         stopResolveService(id);
                         removeRequestMap(clientId, id, clientInfo);
@@ -708,20 +707,9 @@
         if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
         try {
             Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
-                    service.getServiceType(), service.getPort());
-
-            // Add TXT records as additional arguments.
-            Map<String, byte[]> txtRecords = service.getAttributes();
-            for (String key : txtRecords.keySet()) {
-                try {
-                    // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
-                    byte[] recordValue = txtRecords.get(key);
-                    cmd.appendArg(String.format(Locale.US, "%s=%s", key,
-                            recordValue != null ? new String(recordValue, "UTF_8") : ""));
-                } catch (UnsupportedEncodingException e) {
-                    Slog.e(TAG, "Failed to encode txtRecord " + e);
-                }
-            }
+                    service.getServiceType(), service.getPort(),
+                    Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT)
+                            .replace("\n", ""));
 
             mNativeConnector.execute(cmd);
         } catch(NativeDaemonConnectorException e) {
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index a291cc7..2085f32 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -27,6 +27,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.persistentdata.IPersistentDataBlockService;
+import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -72,6 +73,9 @@
     private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
     public static final int DIGEST_SIZE_BYTES = 32;
     private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed";
+    private static final String FLASH_LOCK_PROP = "ro.boot.flash.locked";
+    private static final String FLASH_LOCK_LOCKED = "1";
+    private static final String FLASH_LOCK_UNLOCKED = "0";
 
     private final Context mContext;
     private final String mDataBlockFile;
@@ -454,6 +458,20 @@
         }
 
         @Override
+        public int getFlashLockState() {
+            enforceOemUnlockPermission();
+            String locked = SystemProperties.get(FLASH_LOCK_PROP);
+            switch (locked) {
+                case FLASH_LOCK_LOCKED:
+                    return PersistentDataBlockManager.FLASH_LOCK_LOCKED;
+                case FLASH_LOCK_UNLOCKED:
+                    return PersistentDataBlockManager.FLASH_LOCK_UNLOCKED;
+                default:
+                    return PersistentDataBlockManager.FLASH_LOCK_UNKNOWN;
+            }
+        }
+
+        @Override
         public int getDataBlockSize() {
             enforcePersistentDataBlockAccess();
 
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
new file mode 100644
index 0000000..276687f
--- /dev/null
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.os.IRecoverySystem;
+import android.os.IRecoverySystemProgressListener;
+import android.os.RecoverySystem;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Slog;
+
+import libcore.io.IoUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * The recovery system service is responsible for coordinating recovery related
+ * functions on the device. It sets up (or clears) the bootloader control block
+ * (BCB), which will be read by the bootloader and the recovery image. It also
+ * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the
+ * /data partition so that it can be accessed under the recovery image.
+ */
+public final class RecoverySystemService extends SystemService {
+    private static final String TAG = "RecoverySystemService";
+    private static final boolean DEBUG = false;
+
+    // The socket at /dev/socket/uncrypt to communicate with uncrypt.
+    private static final String UNCRYPT_SOCKET = "uncrypt";
+
+    private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
+
+    private Context mContext;
+
+    public RecoverySystemService(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.RECOVERY_SERVICE, new BinderService());
+    }
+
+    private final class BinderService extends IRecoverySystem.Stub {
+        @Override // Binder call
+        public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
+            if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
+
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+            // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
+            // uncrypt.
+            RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+
+            try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
+                uncryptFile.write(filename + "\n");
+            } catch (IOException e) {
+                Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
+                        "\": ", e);
+                return false;
+            }
+
+            // Trigger uncrypt via init.
+            SystemProperties.set("ctl.start", "uncrypt");
+
+            // Connect to the uncrypt service socket.
+            LocalSocket socket = connectService();
+            if (socket == null) {
+                Slog.e(TAG, "Failed to connect to uncrypt socket");
+                return false;
+            }
+
+            // Read the status from the socket.
+            DataInputStream dis = null;
+            DataOutputStream dos = null;
+            try {
+                dis = new DataInputStream(socket.getInputStream());
+                dos = new DataOutputStream(socket.getOutputStream());
+                int lastStatus = Integer.MIN_VALUE;
+                while (true) {
+                    int status = dis.readInt();
+                    // Avoid flooding the log with the same message.
+                    if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+                        continue;
+                    }
+                    lastStatus = status;
+
+                    if (status >= 0 && status <= 100) {
+                        // Update status
+                        Slog.i(TAG, "uncrypt read status: " + status);
+                        if (listener != null) {
+                            try {
+                                listener.onProgress(status);
+                            } catch (RemoteException ignored) {
+                                Slog.w(TAG, "RemoteException when posting progress");
+                            }
+                        }
+                        if (status == 100) {
+                            Slog.i(TAG, "uncrypt successfully finished.");
+                            // Ack receipt of the final status code. uncrypt
+                            // waits for the ack so the socket won't be
+                            // destroyed before we receive the code.
+                            dos.writeInt(0);
+                            break;
+                        }
+                    } else {
+                        // Error in /system/bin/uncrypt.
+                        Slog.e(TAG, "uncrypt failed with status: " + status);
+                        // Ack receipt of the final status code. uncrypt waits
+                        // for the ack so the socket won't be destroyed before
+                        // we receive the code.
+                        dos.writeInt(0);
+                        return false;
+                    }
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "IOException when reading status: ", e);
+                return false;
+            } finally {
+                IoUtils.closeQuietly(dis);
+                IoUtils.closeQuietly(dos);
+                IoUtils.closeQuietly(socket);
+            }
+
+            return true;
+        }
+
+        @Override // Binder call
+        public boolean clearBcb() {
+            if (DEBUG) Slog.d(TAG, "clearBcb");
+            return setupOrClearBcb(false, null);
+        }
+
+        @Override // Binder call
+        public boolean setupBcb(String command) {
+            if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
+            return setupOrClearBcb(true, command);
+        }
+
+        private LocalSocket connectService() {
+            LocalSocket socket = new LocalSocket();
+            boolean done = false;
+            // The uncrypt socket will be created by init upon receiving the
+            // service request. It may not be ready by this point. So we will
+            // keep retrying until success or reaching timeout.
+            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+                try {
+                    socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
+                            LocalSocketAddress.Namespace.RESERVED));
+                    done = true;
+                    break;
+                } catch (IOException ignored) {
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        Slog.w(TAG, "Interrupted: ", e);
+                    }
+                }
+            }
+            if (!done) {
+                Slog.e(TAG, "Timed out connecting to uncrypt socket");
+                return null;
+            }
+            return socket;
+        }
+
+        private boolean setupOrClearBcb(boolean isSetup, String command) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+            if (isSetup) {
+                SystemProperties.set("ctl.start", "setup-bcb");
+            } else {
+                SystemProperties.set("ctl.start", "clear-bcb");
+            }
+
+            // Connect to the uncrypt service socket.
+            LocalSocket socket = connectService();
+            if (socket == null) {
+                Slog.e(TAG, "Failed to connect to uncrypt socket");
+                return false;
+            }
+
+            DataInputStream dis = null;
+            DataOutputStream dos = null;
+            try {
+                dis = new DataInputStream(socket.getInputStream());
+                dos = new DataOutputStream(socket.getOutputStream());
+
+                // Send the BCB commands if it's to setup BCB.
+                if (isSetup) {
+                    dos.writeInt(command.length());
+                    dos.writeBytes(command);
+                    dos.flush();
+                }
+
+                // Read the status from the socket.
+                int status = dis.readInt();
+
+                // Ack receipt of the status code. uncrypt waits for the ack so
+                // the socket won't be destroyed before we receive the code.
+                dos.writeInt(0);
+
+                if (status == 100) {
+                    Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
+                            " bcb successfully finished.");
+                } else {
+                    // Error in /system/bin/uncrypt.
+                    Slog.e(TAG, "uncrypt failed with status: " + status);
+                    return false;
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "IOException when communicating with uncrypt: ", e);
+                return false;
+            } finally {
+                IoUtils.closeQuietly(dis);
+                IoUtils.closeQuietly(dos);
+                IoUtils.closeQuietly(socket);
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
deleted file mode 100644
index 7bdd3e2..0000000
--- a/services/core/java/com/android/server/SystemConfig.java
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static com.android.internal.util.ArrayUtils.appendInt;
-
-import android.app.ActivityManager;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageManager;
-import android.os.Environment;
-import android.os.Process;
-import android.os.storage.StorageManager;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.Xml;
-
-import com.android.internal.util.XmlUtils;
-
-import libcore.io.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-
-/**
- * Loads global system configuration info.
- */
-public class SystemConfig {
-    static final String TAG = "SystemConfig";
-
-    static SystemConfig sInstance;
-
-    // permission flag, determines which types of configuration are allowed to be read
-    private static final int ALLOW_FEATURES = 0x01;
-    private static final int ALLOW_LIBS = 0x02;
-    private static final int ALLOW_PERMISSIONS = 0x04;
-    private static final int ALLOW_APP_CONFIGS = 0x08;
-    private static final int ALLOW_ALL = ~0;
-
-    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
-    int[] mGlobalGids;
-
-    // These are the built-in uid -> permission mappings that were read from the
-    // system configuration files.
-    final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
-
-    // These are the built-in shared libraries that were read from the
-    // system configuration files.  Keys are the library names; strings are the
-    // paths to the libraries.
-    final ArrayMap<String, String> mSharedLibraries  = new ArrayMap<>();
-
-    // These are the features this devices supports that were read from the
-    // system configuration files.
-    final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
-
-    // These are the features which this device doesn't support; the OEM
-    // partition uses these to opt-out of features from the system image.
-    final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
-
-    public static final class PermissionEntry {
-        public final String name;
-        public int[] gids;
-        public boolean perUser;
-
-        PermissionEntry(String name, boolean perUser) {
-            this.name = name;
-            this.perUser = perUser;
-        }
-    }
-
-    // These are the permission -> gid mappings that were read from the
-    // system configuration files.
-    final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
-
-    // These are the packages that are white-listed to be able to run in the
-    // background while in power save mode (but not whitelisted from device idle modes),
-    // as read from the configuration files.
-    final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>();
-
-    // These are the packages that are white-listed to be able to run in the
-    // background while in power save mode, as read from the configuration files.
-    final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
-
-    // These are the app package names that should not allow IME switching.
-    final ArraySet<String> mFixedImeApps = new ArraySet<>();
-
-    // These are the package names of apps which should be in the 'always'
-    // URL-handling state upon factory reset.
-    final ArraySet<String> mLinkedApps = new ArraySet<>();
-
-    // These are the packages that are whitelisted to be able to run as system user
-    final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>();
-
-    // These are the packages that should not run under system user
-    final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
-
-    public static SystemConfig getInstance() {
-        synchronized (SystemConfig.class) {
-            if (sInstance == null) {
-                sInstance = new SystemConfig();
-            }
-            return sInstance;
-        }
-    }
-
-    public int[] getGlobalGids() {
-        return mGlobalGids;
-    }
-
-    public SparseArray<ArraySet<String>> getSystemPermissions() {
-        return mSystemPermissions;
-    }
-
-    public ArrayMap<String, String> getSharedLibraries() {
-        return mSharedLibraries;
-    }
-
-    public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
-        return mAvailableFeatures;
-    }
-
-    public ArrayMap<String, PermissionEntry> getPermissions() {
-        return mPermissions;
-    }
-
-    public ArraySet<String> getAllowInPowerSaveExceptIdle() {
-        return mAllowInPowerSaveExceptIdle;
-    }
-
-    public ArraySet<String> getAllowInPowerSave() {
-        return mAllowInPowerSave;
-    }
-
-    public ArraySet<String> getFixedImeApps() {
-        return mFixedImeApps;
-    }
-
-    public ArraySet<String> getLinkedApps() {
-        return mLinkedApps;
-    }
-
-    public ArraySet<String> getSystemUserWhitelistedApps() {
-        return mSystemUserWhitelistedApps;
-    }
-
-    public ArraySet<String> getSystemUserBlacklistedApps() {
-        return mSystemUserBlacklistedApps;
-    }
-
-    SystemConfig() {
-        // Read configuration from system
-        readPermissions(Environment.buildPath(
-                Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
-        // Read configuration from the old permissions dir
-        readPermissions(Environment.buildPath(
-                Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
-        // Allow ODM to customize system configs around libs, features and apps
-        int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
-        readPermissions(Environment.buildPath(
-                Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
-        readPermissions(Environment.buildPath(
-                Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
-        // Only allow OEM to customize features
-        readPermissions(Environment.buildPath(
-                Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
-        readPermissions(Environment.buildPath(
-                Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
-    }
-
-    void readPermissions(File libraryDir, int permissionFlag) {
-        // Read permissions from given directory.
-        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
-            if (permissionFlag == ALLOW_ALL) {
-                Slog.w(TAG, "No directory " + libraryDir + ", skipping");
-            }
-            return;
-        }
-        if (!libraryDir.canRead()) {
-            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
-            return;
-        }
-
-        // Iterate over the files in the directory and scan .xml files
-        File platformFile = null;
-        for (File f : libraryDir.listFiles()) {
-            // We'll read platform.xml last
-            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
-                platformFile = f;
-                continue;
-            }
-
-            if (!f.getPath().endsWith(".xml")) {
-                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
-                continue;
-            }
-            if (!f.canRead()) {
-                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
-                continue;
-            }
-
-            readPermissionsFromXml(f, permissionFlag);
-        }
-
-        // Read platform permissions last so it will take precedence
-        if (platformFile != null) {
-            readPermissionsFromXml(platformFile, permissionFlag);
-        }
-    }
-
-    private void readPermissionsFromXml(File permFile, int permissionFlag) {
-        FileReader permReader = null;
-        try {
-            permReader = new FileReader(permFile);
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
-            return;
-        }
-
-        final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
-
-        try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(permReader);
-
-            int type;
-            while ((type=parser.next()) != parser.START_TAG
-                       && type != parser.END_DOCUMENT) {
-                ;
-            }
-
-            if (type != parser.START_TAG) {
-                throw new XmlPullParserException("No start tag found");
-            }
-
-            if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
-                throw new XmlPullParserException("Unexpected start tag in " + permFile
-                        + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
-            }
-
-            boolean allowAll = permissionFlag == ALLOW_ALL;
-            boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
-            boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
-            boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
-            boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
-                    break;
-                }
-
-                String name = parser.getName();
-                if ("group".equals(name) && allowAll) {
-                    String gidStr = parser.getAttributeValue(null, "gid");
-                    if (gidStr != null) {
-                        int gid = android.os.Process.getGidForName(gidStr);
-                        mGlobalGids = appendInt(mGlobalGids, gid);
-                    } else {
-                        Slog.w(TAG, "<group> without gid in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    }
-
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else if ("permission".equals(name) && allowPermissions) {
-                    String perm = parser.getAttributeValue(null, "name");
-                    if (perm == null) {
-                        Slog.w(TAG, "<permission> without name in " + permFile + " at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    perm = perm.intern();
-                    readPermission(parser, perm);
-
-                } else if ("assign-permission".equals(name) && allowPermissions) {
-                    String perm = parser.getAttributeValue(null, "name");
-                    if (perm == null) {
-                        Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    String uidStr = parser.getAttributeValue(null, "uid");
-                    if (uidStr == null) {
-                        Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    int uid = Process.getUidForName(uidStr);
-                    if (uid < 0) {
-                        Slog.w(TAG, "<assign-permission> with unknown uid \""
-                                + uidStr + "  in " + permFile + " at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    perm = perm.intern();
-                    ArraySet<String> perms = mSystemPermissions.get(uid);
-                    if (perms == null) {
-                        perms = new ArraySet<String>();
-                        mSystemPermissions.put(uid, perms);
-                    }
-                    perms.add(perm);
-                    XmlUtils.skipCurrentTag(parser);
-
-                } else if ("library".equals(name) && allowLibs) {
-                    String lname = parser.getAttributeValue(null, "name");
-                    String lfile = parser.getAttributeValue(null, "file");
-                    if (lname == null) {
-                        Slog.w(TAG, "<library> without name in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else if (lfile == null) {
-                        Slog.w(TAG, "<library> without file in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else {
-                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
-                        mSharedLibraries.put(lname, lfile);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("feature".equals(name) && allowFeatures) {
-                    String fname = parser.getAttributeValue(null, "name");
-                    int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
-                    boolean allowed;
-                    if (!lowRam) {
-                        allowed = true;
-                    } else {
-                        String notLowRam = parser.getAttributeValue(null, "notLowRam");
-                        allowed = !"true".equals(notLowRam);
-                    }
-                    if (fname == null) {
-                        Slog.w(TAG, "<feature> without name in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else if (allowed) {
-                        addFeature(fname, fversion);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("unavailable-feature".equals(name) && allowFeatures) {
-                    String fname = parser.getAttributeValue(null, "name");
-                    if (fname == null) {
-                        Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else {
-                        mUnavailableFeatures.add(fname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {
-                    String pkgname = parser.getAttributeValue(null, "package");
-                    if (pkgname == null) {
-                        Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
-                                + permFile + " at " + parser.getPositionDescription());
-                    } else {
-                        mAllowInPowerSaveExceptIdle.add(pkgname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("allow-in-power-save".equals(name) && allowAll) {
-                    String pkgname = parser.getAttributeValue(null, "package");
-                    if (pkgname == null) {
-                        Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else {
-                        mAllowInPowerSave.add(pkgname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("fixed-ime-app".equals(name) && allowAll) {
-                    String pkgname = parser.getAttributeValue(null, "package");
-                    if (pkgname == null) {
-                        Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else {
-                        mFixedImeApps.add(pkgname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("app-link".equals(name) && allowAppConfigs) {
-                    String pkgname = parser.getAttributeValue(null, "package");
-                    if (pkgname == null) {
-                        Slog.w(TAG, "<app-link> without package in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else {
-                        mLinkedApps.add(pkgname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
-                    String pkgname = parser.getAttributeValue(null, "package");
-                    if (pkgname == null) {
-                        Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
-                                + " at " + parser.getPositionDescription());
-                    } else {
-                        mSystemUserWhitelistedApps.add(pkgname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
-                    String pkgname = parser.getAttributeValue(null, "package");
-                    if (pkgname == null) {
-                        Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
-                                + " at " + parser.getPositionDescription());
-                    } else {
-                        mSystemUserBlacklistedApps.add(pkgname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                } else {
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                }
-            }
-        } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Got exception parsing permissions.", e);
-        } catch (IOException e) {
-            Slog.w(TAG, "Got exception parsing permissions.", e);
-        } finally {
-            IoUtils.closeQuietly(permReader);
-        }
-
-        // Some devices can be field-converted to FBE, so offer to splice in
-        // those features if not already defined by the static config
-        if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
-            addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
-            addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
-        }
-
-        for (String featureName : mUnavailableFeatures) {
-            removeFeature(featureName);
-        }
-    }
-
-    private void addFeature(String name, int version) {
-        FeatureInfo fi = mAvailableFeatures.get(name);
-        if (fi == null) {
-            fi = new FeatureInfo();
-            fi.name = name;
-            fi.version = version;
-            mAvailableFeatures.put(name, fi);
-        } else {
-            fi.version = Math.max(fi.version, version);
-        }
-    }
-
-    private void removeFeature(String name) {
-        if (mAvailableFeatures.remove(name) != null) {
-            Slog.d(TAG, "Removed unavailable feature " + name);
-        }
-    }
-
-    void readPermission(XmlPullParser parser, String name)
-            throws IOException, XmlPullParserException {
-        if (mPermissions.containsKey(name)) {
-            throw new IllegalStateException("Duplicate permission definition for " + name);
-        }
-
-        final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false);
-        final PermissionEntry perm = new PermissionEntry(name, perUser);
-        mPermissions.put(name, perm);
-
-        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 ("group".equals(tagName)) {
-                String gidStr = parser.getAttributeValue(null, "gid");
-                if (gidStr != null) {
-                    int gid = Process.getGidForName(gidStr);
-                    perm.gids = appendInt(perm.gids, gid);
-                } else {
-                    Slog.w(TAG, "<group> without gid at "
-                            + parser.getPositionDescription());
-                }
-            }
-            XmlUtils.skipCurrentTag(parser);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index c4b4cbe..3eb20a0 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -27,9 +27,11 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
-import android.app.SynchronousUserSwitchObserver;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -76,16 +78,72 @@
     private final Context mContext;
     private boolean mSystemReady;
     private final TextServicesMonitor mMonitor;
-    private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap =
-            new HashMap<String, SpellCheckerInfo>();
-    private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>();
-    private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups =
-            new HashMap<String, SpellCheckerBindGroup>();
+    private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = new HashMap<>();
+    private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<>();
+    private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = new HashMap<>();
     private final TextServicesSettings mSettings;
+    @NonNull
+    private final UserManager mUserManager;
 
-    public void systemRunning() {
-        if (!mSystemReady) {
-            mSystemReady = true;
+    public static final class Lifecycle extends SystemService {
+        private TextServicesManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new TextServicesManagerService(context);
+        }
+
+        @Override
+        public void onStart() {
+            publishBinderService(Context.TEXT_SERVICES_MANAGER_SERVICE, mService);
+        }
+
+        @Override
+        public void onSwitchUser(@UserIdInt int userHandle) {
+            // Called on the system server's main looper thread.
+            // TODO: Dispatch this to a worker thread as needed.
+            mService.onSwitchUser(userHandle);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            // Called on the system server's main looper thread.
+            // TODO: Dispatch this to a worker thread as needed.
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                mService.systemRunning();
+            }
+        }
+
+        @Override
+        public void onUnlockUser(@UserIdInt int userHandle) {
+            // Called on the system server's main looper thread.
+            // TODO: Dispatch this to a worker thread as needed.
+            mService.onUnlockUser(userHandle);
+        }
+    }
+
+    void systemRunning() {
+        synchronized (mSpellCheckerMap) {
+            if (!mSystemReady) {
+                mSystemReady = true;
+                resetInternalState(mSettings.getCurrentUserId());
+            }
+        }
+    }
+
+    void onSwitchUser(@UserIdInt int userId) {
+        synchronized (mSpellCheckerMap) {
+            resetInternalState(userId);
+        }
+    }
+
+    void onUnlockUser(@UserIdInt int userId) {
+        synchronized(mSpellCheckerMap) {
+            final int currentUserId = mSettings.getCurrentUserId();
+            if (userId != currentUserId) {
+                return;
+            }
+            resetInternalState(currentUserId);
         }
     }
 
@@ -93,6 +151,8 @@
         mSystemReady = false;
         mContext = context;
 
+        mUserManager = mContext.getSystemService(UserManager.class);
+
         final IntentFilter broadcastFilter = new IntentFilter();
         broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
         broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
@@ -100,38 +160,25 @@
 
         int userId = UserHandle.USER_SYSTEM;
         try {
-            ActivityManagerNative.getDefault().registerUserSwitchObserver(
-                    new SynchronousUserSwitchObserver() {
-                        @Override
-                        public void onUserSwitching(int newUserId) throws RemoteException {
-                            synchronized(mSpellCheckerMap) {
-                                switchUserLocked(newUserId);
-                            }
-                        }
-
-                        @Override
-                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
-                        }
-
-                        @Override
-                        public void onForegroundProfileSwitch(int newProfileId) {
-                            // Ignore.
-                        }
-                    });
             userId = ActivityManagerNative.getDefault().getCurrentUser().id;
         } catch (RemoteException e) {
             Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
         }
         mMonitor = new TextServicesMonitor();
         mMonitor.register(context, null, true);
-        mSettings = new TextServicesSettings(context.getContentResolver(), userId);
+        final boolean useCopyOnWriteSettings =
+                !mSystemReady || !mUserManager.isUserUnlocked(userId);
+        mSettings = new TextServicesSettings(context.getContentResolver(), userId,
+                useCopyOnWriteSettings);
 
-        // "switchUserLocked" initializes the states for the foreground user
-        switchUserLocked(userId);
+        // "resetInternalState" initializes the states for the foreground user
+        resetInternalState(userId);
     }
 
-    private void switchUserLocked(int userId) {
-        mSettings.setCurrentUserId(userId);
+    private void resetInternalState(@UserIdInt int userId) {
+        final boolean useCopyOnWriteSettings =
+                !mSystemReady || !mUserManager.isUserUnlocked(userId);
+        mSettings.switchCurrentUser(userId, useCopyOnWriteSettings);
         updateCurrentProfileIds();
         unbindServiceLocked();
         buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
@@ -148,8 +195,7 @@
     }
 
     void updateCurrentProfileIds() {
-        List<UserInfo> profiles =
-                UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+        final List<UserInfo> profiles = mUserManager.getProfiles(mSettings.getCurrentUserId());
         int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
         for (int i = 0; i < currentProfileIds.length; i++) {
             currentProfileIds[i] = profiles.get(i).id;
@@ -214,6 +260,9 @@
         list.clear();
         map.clear();
         final PackageManager pm = context.getPackageManager();
+        // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
+        // behavior of PackageManager is exactly what we want.  It by default picks up appropriate
+        // services depending on the unlock state for the specified user.
         final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
                 new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA,
                 settings.getCurrentUserId());
@@ -416,9 +465,10 @@
             return null;
         }
         synchronized (mSpellCheckerMap) {
-            final String subtypeHashCodeStr = mSettings.getSelectedSpellCheckerSubtype();
+            final int subtypeHashCode =
+                    mSettings.getSelectedSpellCheckerSubtype(SpellCheckerSubtype.SUBTYPE_ID_NONE);
             if (DBG) {
-                Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr);
+                Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCode);
             }
             final SpellCheckerInfo sci = getCurrentSpellChecker(null);
             if (sci == null || sci.getSubtypeCount() == 0) {
@@ -427,17 +477,12 @@
                 }
                 return null;
             }
-            final int hashCode;
-            if (!TextUtils.isEmpty(subtypeHashCodeStr)) {
-                hashCode = Integer.valueOf(subtypeHashCodeStr);
-            } else {
-                hashCode = 0;
-            }
-            if (hashCode == 0 && !allowImplicitlySelectedSubtype) {
+            if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
+                    && !allowImplicitlySelectedSubtype) {
                 return null;
             }
             String candidateLocale = null;
-            if (hashCode == 0) {
+            if (subtypeHashCode == 0) {
                 // Spell checker language settings == "auto"
                 final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
                 if (imm != null) {
@@ -459,7 +504,7 @@
             SpellCheckerSubtype candidate = null;
             for (int i = 0; i < sci.getSubtypeCount(); ++i) {
                 final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
-                if (hashCode == 0) {
+                if (subtypeHashCode == 0) {
                     final String scsLocale = scs.getLocale();
                     if (candidateLocale.equals(scsLocale)) {
                         return scs;
@@ -470,7 +515,7 @@
                             candidate = scs;
                         }
                     }
-                } else if (scs.hashCode() == hashCode) {
+                } else if (scs.hashCode() == subtypeHashCode) {
                     if (DBG) {
                         Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
                                 + ", " + scs.getLocale());
@@ -615,8 +660,7 @@
             Slog.d(TAG, "FinishSpellCheckerService");
         }
         synchronized(mSpellCheckerMap) {
-            final ArrayList<SpellCheckerBindGroup> removeList =
-                    new ArrayList<SpellCheckerBindGroup>();
+            final ArrayList<SpellCheckerBindGroup> removeList = new ArrayList<>();
             for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) {
                 if (group == null) continue;
                 // Use removeList to avoid modifying mSpellCheckerBindGroups in this loop.
@@ -757,50 +801,36 @@
 
         synchronized(mSpellCheckerMap) {
             pw.println("Current Text Services Manager state:");
-            pw.println("  Spell Checker Map:");
-            for (Map.Entry<String, SpellCheckerInfo> ent : mSpellCheckerMap.entrySet()) {
-                pw.print("    "); pw.print(ent.getKey()); pw.println(":");
-                SpellCheckerInfo info = ent.getValue();
-                pw.print("      "); pw.print("id="); pw.println(info.getId());
-                pw.print("      "); pw.print("comp=");
-                        pw.println(info.getComponent().toShortString());
-                int NS = info.getSubtypeCount();
-                for (int i=0; i<NS; i++) {
-                    SpellCheckerSubtype st = info.getSubtypeAt(i);
-                    pw.print("      "); pw.print("Subtype #"); pw.print(i); pw.println(":");
-                    pw.print("        "); pw.print("locale="); pw.println(st.getLocale());
-                    pw.print("        "); pw.print("extraValue=");
-                            pw.println(st.getExtraValue());
-                }
+            pw.println("  Spell Checkers:");
+            int spellCheckerIndex = 0;
+            for (final SpellCheckerInfo info : mSpellCheckerMap.values()) {
+                pw.println("  Spell Checker #" + spellCheckerIndex);
+                info.dump(pw, "    ");
+                ++spellCheckerIndex;
             }
             pw.println("");
             pw.println("  Spell Checker Bind Groups:");
-            for (Map.Entry<String, SpellCheckerBindGroup> ent
+            for (final Map.Entry<String, SpellCheckerBindGroup> ent
                     : mSpellCheckerBindGroups.entrySet()) {
-                SpellCheckerBindGroup grp = ent.getValue();
-                pw.print("    "); pw.print(ent.getKey()); pw.print(" ");
-                        pw.print(grp); pw.println(":");
-                pw.print("      "); pw.print("mInternalConnection=");
-                        pw.println(grp.mInternalConnection);
-                pw.print("      "); pw.print("mSpellChecker=");
-                        pw.println(grp.mSpellChecker);
-                pw.print("      "); pw.print("mBound="); pw.print(grp.mBound);
-                        pw.print(" mConnected="); pw.println(grp.mConnected);
-                int NL = grp.mListeners.size();
-                for (int i=0; i<NL; i++) {
-                    InternalDeathRecipient listener = grp.mListeners.get(i);
-                    pw.print("      "); pw.print("Listener #"); pw.print(i); pw.println(":");
-                    pw.print("        "); pw.print("mTsListener=");
-                            pw.println(listener.mTsListener);
-                    pw.print("        "); pw.print("mScListener=");
-                            pw.println(listener.mScListener);
-                    pw.print("        "); pw.print("mGroup=");
-                            pw.println(listener.mGroup);
-                    pw.print("        "); pw.print("mScLocale=");
-                            pw.print(listener.mScLocale);
-                            pw.print(" mUid="); pw.println(listener.mUid);
+                final SpellCheckerBindGroup grp = ent.getValue();
+                pw.println("    " + ent.getKey() + " " + grp + ":");
+                pw.println("      " + "mInternalConnection=" + grp.mInternalConnection);
+                pw.println("      " + "mSpellChecker=" + grp.mSpellChecker);
+                pw.println("      " + "mBound=" + grp.mBound + " mConnected=" + grp.mConnected);
+                final int N = grp.mListeners.size();
+                for (int i = 0; i < N; i++) {
+                    final InternalDeathRecipient listener = grp.mListeners.get(i);
+                    pw.println("      " + "Listener #" + i + ":");
+                    pw.println("        " + "mTsListener=" + listener.mTsListener);
+                    pw.println("        " + "mScListener=" + listener.mScListener);
+                    pw.println("        " + "mGroup=" + listener.mGroup);
+                    pw.println("        " + "mScLocale=" + listener.mScLocale
+                            + " mUid=" + listener.mUid);
                 }
             }
+            pw.println("");
+            pw.println("  mSettings:");
+            mSettings.dumpLocked(pw, "    ");
         }
     }
 
@@ -811,7 +841,7 @@
         private final String TAG = SpellCheckerBindGroup.class.getSimpleName();
         private final InternalServiceConnection mInternalConnection;
         private final CopyOnWriteArrayList<InternalDeathRecipient> mListeners =
-                new CopyOnWriteArrayList<InternalDeathRecipient>();
+                new CopyOnWriteArrayList<>();
         public boolean mBound;
         public ISpellCheckerService mSpellChecker;
         public boolean mConnected;
@@ -885,8 +915,7 @@
             }
             synchronized(mSpellCheckerMap) {
                 final int size = mListeners.size();
-                final ArrayList<InternalDeathRecipient> removeList =
-                        new ArrayList<InternalDeathRecipient>();
+                final ArrayList<InternalDeathRecipient> removeList = new ArrayList<>();
                 for (int i = 0; i < size; ++i) {
                     final InternalDeathRecipient tempRecipient = mListeners.get(i);
                     if(tempRecipient.hasSpellCheckerListener(listener)) {
@@ -1015,23 +1044,88 @@
 
     private static class TextServicesSettings {
         private final ContentResolver mResolver;
+        @UserIdInt
         private int mCurrentUserId;
         @GuardedBy("mLock")
         private int[] mCurrentProfileIds = new int[0];
         private Object mLock = new Object();
 
-        public TextServicesSettings(ContentResolver resolver, int userId) {
+        /**
+         * On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}.
+         */
+        private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>();
+        private boolean mCopyOnWrite = false;
+
+        public TextServicesSettings(ContentResolver resolver, @UserIdInt int userId,
+                boolean copyOnWrite) {
             mResolver = resolver;
-            mCurrentUserId = userId;
+            switchCurrentUser(userId, copyOnWrite);
         }
 
-        public void setCurrentUserId(int userId) {
+        /**
+         * Must be called when the current user is changed.
+         *
+         * @param userId The user ID.
+         * @param copyOnWrite If {@code true}, for each settings key
+         * (e.g. {@link Settings.Secure#SELECTED_SPELL_CHECKER}) we use the actual settings on the
+         * {@link Settings.Secure} until we do the first write operation.
+         */
+        public void switchCurrentUser(@UserIdInt int userId, boolean copyOnWrite) {
             if (DBG) {
                 Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
                         + userId + ", new ime = " + getSelectedSpellChecker());
             }
+            if (mCurrentUserId != userId || mCopyOnWrite != copyOnWrite) {
+                mCopyOnWriteDataStore.clear();
+                // TODO: mCurrentProfileIds should be cleared here.
+            }
             // TSMS settings are kept per user, so keep track of current user
             mCurrentUserId = userId;
+            mCopyOnWrite = copyOnWrite;
+            // TODO: mCurrentProfileIds should be updated here.
+        }
+
+        private void putString(final String key, final String str) {
+            if (mCopyOnWrite) {
+                mCopyOnWriteDataStore.put(key, str);
+            } else {
+                Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+            }
+        }
+
+        @Nullable
+        private String getString(@NonNull final String key, @Nullable final String defaultValue) {
+            final String result;
+            if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
+                result = mCopyOnWriteDataStore.get(key);
+            } else {
+                result = Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
+            }
+            return result != null ? result : defaultValue;
+        }
+
+        private void putInt(final String key, final int value) {
+            if (mCopyOnWrite) {
+                mCopyOnWriteDataStore.put(key, String.valueOf(value));
+            } else {
+                Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+            }
+        }
+
+        private int getInt(final String key, final int defaultValue) {
+            if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
+                final String result = mCopyOnWriteDataStore.get(key);
+                return result != null ? Integer.valueOf(result) : 0;
+            }
+            return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
+        }
+
+        private void putBoolean(final String key, final boolean value) {
+            putInt(key, value ? 1 : 0);
+        }
+
+        private boolean getBoolean(final String key, final boolean defaultValue) {
+            return getInt(key, defaultValue ? 1 : 0) == 1;
         }
 
         public void setCurrentProfileIds(int[] currentProfileIds) {
@@ -1040,7 +1134,7 @@
             }
         }
 
-        public boolean isCurrentProfile(int userId) {
+        public boolean isCurrentProfile(@UserIdInt int userId) {
             synchronized (mLock) {
                 if (userId == mCurrentUserId) return true;
                 for (int i = 0; i < mCurrentProfileIds.length; i++) {
@@ -1050,39 +1144,46 @@
             }
         }
 
+        @UserIdInt
         public int getCurrentUserId() {
             return mCurrentUserId;
         }
 
-        public void putSelectedSpellChecker(String sciId) {
-            Settings.Secure.putStringForUser(mResolver,
-                    Settings.Secure.SELECTED_SPELL_CHECKER, sciId, mCurrentUserId);
+        public void putSelectedSpellChecker(@Nullable String sciId) {
+            if (TextUtils.isEmpty(sciId)) {
+                // OK to coalesce to null, since getSelectedSpellChecker() can take care of the
+                // empty data scenario.
+                putString(Settings.Secure.SELECTED_SPELL_CHECKER, null);
+            } else {
+                putString(Settings.Secure.SELECTED_SPELL_CHECKER, sciId);
+            }
         }
 
         public void putSelectedSpellCheckerSubtype(int hashCode) {
-            Settings.Secure.putStringForUser(mResolver,
-                    Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode),
-                    mCurrentUserId);
+            putInt(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, hashCode);
         }
 
         public void setSpellCheckerEnabled(boolean enabled) {
-            Settings.Secure.putIntForUser(mResolver,
-                    Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0, mCurrentUserId);
+            putBoolean(Settings.Secure.SPELL_CHECKER_ENABLED, enabled);
         }
 
+        @NonNull
         public String getSelectedSpellChecker() {
-            return Settings.Secure.getStringForUser(mResolver,
-                    Settings.Secure.SELECTED_SPELL_CHECKER, mCurrentUserId);
+            return getString(Settings.Secure.SELECTED_SPELL_CHECKER, "");
         }
 
-        public String getSelectedSpellCheckerSubtype() {
-            return Settings.Secure.getStringForUser(mResolver,
-                    Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, mCurrentUserId);
+        public int getSelectedSpellCheckerSubtype(final int defaultValue) {
+            return getInt(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, defaultValue);
         }
 
         public boolean isSpellCheckerEnabled() {
-            return Settings.Secure.getIntForUser(mResolver,
-                    Settings.Secure.SPELL_CHECKER_ENABLED, 1, mCurrentUserId) == 1;
+            return getBoolean(Settings.Secure.SPELL_CHECKER_ENABLED, true);
+        }
+
+        public void dumpLocked(final PrintWriter pw, final String prefix) {
+            pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
+            pw.println(prefix + "mCurrentProfileIds=" + Arrays.toString(mCurrentProfileIds));
+            pw.println(prefix + "mCopyOnWrite=" + mCopyOnWrite);
         }
     }
 
diff --git a/services/core/java/com/android/server/ThermalObserver.java b/services/core/java/com/android/server/ThermalObserver.java
deleted file mode 100644
index aee28fb..0000000
--- a/services/core/java/com/android/server/ThermalObserver.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.UEventObserver;
-import android.os.UserHandle;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * ThermalObserver for monitoring temperature changes.
- */
-public class ThermalObserver extends SystemService {
-    private static final String TAG = "ThermalObserver";
-
-    private static final String CALLSTATE_UEVENT_MATCH =
-            "DEVPATH=/devices/virtual/switch/thermalstate";
-
-    private static final int MSG_THERMAL_STATE_CHANGED = 0;
-
-    private static final int SWITCH_STATE_NORMAL = 0;
-    private static final int SWITCH_STATE_WARNING = 1;
-    private static final int SWITCH_STATE_EXCEEDED = 2;
-
-    private final PowerManager mPowerManager;
-    private final PowerManager.WakeLock mWakeLock;
-
-    private final Object mLock = new Object();
-    private Integer mLastState;
-
-    private final UEventObserver mThermalWarningObserver = new UEventObserver() {
-        @Override
-        public void onUEvent(UEventObserver.UEvent event) {
-            updateLocked(Integer.parseInt(event.get("SWITCH_STATE")));
-        }
-    };
-
-    private final Handler mHandler = new Handler(true /*async*/) {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_THERMAL_STATE_CHANGED:
-                    handleThermalStateChange(msg.arg1);
-                    mWakeLock.release();
-                    break;
-            }
-        }
-    };
-
-    public ThermalObserver(Context context) {
-        super(context);
-        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
-        mThermalWarningObserver.startObserving(CALLSTATE_UEVENT_MATCH);
-    }
-
-    private void updateLocked(int state) {
-        Message message = new Message();
-        message.what = MSG_THERMAL_STATE_CHANGED;
-        message.arg1 = state;
-
-        mWakeLock.acquire();
-        mHandler.sendMessage(message);
-    }
-
-    private void handleThermalStateChange(int state) {
-        synchronized (mLock) {
-            mLastState = state;
-            Intent intent = new Intent(Intent.ACTION_THERMAL_EVENT);
-            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-
-            final int thermalState;
-
-            switch (state) {
-                case SWITCH_STATE_WARNING:
-                    thermalState = Intent.EXTRA_THERMAL_STATE_WARNING;
-                    break;
-                case SWITCH_STATE_EXCEEDED:
-                    thermalState = Intent.EXTRA_THERMAL_STATE_EXCEEDED;
-                    break;
-                case SWITCH_STATE_NORMAL:
-                default:
-                    thermalState = Intent.EXTRA_THERMAL_STATE_NORMAL;
-                    break;
-            }
-
-            intent.putExtra(Intent.EXTRA_THERMAL_STATE, thermalState);
-
-            getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
-        }
-    }
-
-    @Override
-    public void onStart() {
-        publishBinderService(TAG, new BinderService());
-    }
-
-    private final class BinderService extends Binder {
-        @Override
-        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                    != PackageManager.PERMISSION_GRANTED) {
-                pw.println("Permission Denial: can't dump thermal observer service from from pid="
-                        + Binder.getCallingPid()
-                        + ", uid=" + Binder.getCallingUid());
-                return;
-            }
-
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    if (args == null || args.length == 0 || "-a".equals(args[0])) {
-                        pw.println("Current Thermal Observer Service state:");
-                        pw.println("  last state change: "
-                                + (mLastState != null ? mLastState : "none"));
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 772a15c..4198af9 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -64,9 +64,11 @@
 
     // Which native processes to dump into dropbox's stack traces
     public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
+        "/system/bin/audioserver",
         "/system/bin/mediaserver",
         "/system/bin/sdcard",
-        "/system/bin/surfaceflinger"
+        "/system/bin/surfaceflinger",
+        "media.log"
     };
 
     static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 163b9be..8a0a62a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -47,6 +47,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -64,6 +65,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -74,11 +76,13 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
@@ -90,6 +94,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
@@ -101,9 +106,11 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -122,7 +129,9 @@
     private static final String TAG = "AccountManagerService";
 
     private static final String DATABASE_NAME = "accounts.db";
-    private static final int DATABASE_VERSION = 8;
+    private static final int PRE_N_DATABASE_VERSION = 9;
+    private static final int CE_DATABASE_VERSION = 10;
+    private static final int DE_DATABASE_VERSION = 1;
 
     private static final int MAX_DEBUG_DB_SIZE = 64;
 
@@ -172,6 +181,15 @@
     private static final String META_VALUE = "value";
 
     private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
+    private static final String SHARED_ACCOUNTS_ID = "_id";
+
+    private static final String PRE_N_DATABASE_NAME = "accounts.db";
+    private static final String CE_DATABASE_NAME = "accounts_ce.db";
+    private static final String DE_DATABASE_NAME = "accounts_de.db";
+    private static final String CE_DB_PREFIX = "ceDb.";
+    private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
+    private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
+    private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
 
     private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
             new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
@@ -200,12 +218,17 @@
             EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
     private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
 
+    private static final String META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX =
+            "auth_uid_for_type:";
+    private static final String META_KEY_DELIMITER = ":";
+    private static final String SELECTION_META_BY_AUTHENTICATOR_TYPE = META_KEY + " LIKE ?";
+
     private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
     private final AtomicInteger mNotificationIds = new AtomicInteger(1);
 
     static class UserAccounts {
         private final int userId;
-        private final DatabaseHelper openHelper;
+        private final DeDatabaseHelper openHelper;
         private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
                 credentialsPermissionNotificationIds =
                 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
@@ -246,15 +269,15 @@
         UserAccounts(Context context, int userId) {
             this.userId = userId;
             synchronized (cacheLock) {
-                openHelper = new DatabaseHelper(context, userId);
+                openHelper = DeDatabaseHelper.create(context, userId);
             }
         }
     }
 
-    private final SparseArray<UserAccounts> mUsers = new SparseArray<UserAccounts>();
+    private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
+    private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
 
-    private static AtomicReference<AccountManagerService> sThis =
-            new AtomicReference<AccountManagerService>();
+    private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
 
     /**
@@ -315,15 +338,15 @@
 
         IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        userFilter.addAction(Intent.ACTION_USER_STARTED);
+        userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 String action = intent.getAction();
                 if (Intent.ACTION_USER_REMOVED.equals(action)) {
                     onUserRemoved(intent);
-                } else if (Intent.ACTION_USER_STARTED.equals(action)) {
-                    onUserStarted(intent);
+                } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                    onUserUnlocked(intent);
                 }
             }
         }, UserHandle.ALL, userFilter, null, null);
@@ -372,34 +395,92 @@
      */
     private void validateAccountsInternal(
             UserAccounts accounts, boolean invalidateAuthenticatorCache) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "validateAccountsInternal " + accounts.userId
+                    + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached()
+                    + " userLocked=" + mUnlockedUsers.get(accounts.userId));
+        }
         if (invalidateAuthenticatorCache) {
             mAuthenticatorCache.invalidateCache(accounts.userId);
         }
 
-        final HashSet<AuthenticatorDescription> knownAuth = Sets.newHashSet();
+        final HashMap<String, Integer> knownAuth = new HashMap<>();
         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service :
                 mAuthenticatorCache.getAllServices(accounts.userId)) {
-            knownAuth.add(service.type);
+            knownAuth.put(service.type.type, service.uid);
         }
 
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
             boolean accountDeleted = false;
+
+            // Get a list of stored authenticator type and UID
+            Cursor metaCursor = db.query(
+                    TABLE_META,
+                    new String[] {META_KEY, META_VALUE},
+                    SELECTION_META_BY_AUTHENTICATOR_TYPE,
+                    new String[] {META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
+                    null /* groupBy */,
+                    null /* having */,
+                    META_KEY);
+            // Create a list of authenticator type whose previous uid no longer exists
+            HashSet<String> obsoleteAuthType = Sets.newHashSet();
+            try {
+                while (metaCursor.moveToNext()) {
+                    String type = TextUtils.split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
+                    String uid = metaCursor.getString(1);
+                    if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uid)) {
+                        // Should never happen.
+                        Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
+                                + ", uid empty: " + TextUtils.isEmpty(uid));
+                        continue;
+                    }
+                    Integer knownUid = knownAuth.get(type);
+                    if (knownUid != null && uid.equals(knownUid.toString())) {
+                        // Remove it from the knownAuth list if it's unchanged.
+                        knownAuth.remove(type);
+                    } else {
+                        // Only add it to the list if it no longer exists or uid different
+                        obsoleteAuthType.add(type);
+                        // And delete it from the TABLE_META
+                        db.delete(
+                                TABLE_META,
+                                META_KEY + "=? AND " + META_VALUE + "=?",
+                                new String[] {
+                                        META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
+                                        uid}
+                                );
+                    }
+                }
+            } finally {
+                metaCursor.close();
+            }
+
+            // Add the newly registered authenticator to TABLE_META
+            Iterator<Entry<String, Integer>> iterator = knownAuth.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Entry<String, Integer> entry = iterator.next();
+                ContentValues values = new ContentValues();
+                values.put(META_KEY,
+                        META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey());
+                values.put(META_VALUE, entry.getValue());
+                db.insert(TABLE_META, null, values);
+            }
+
             Cursor cursor = db.query(TABLE_ACCOUNTS,
                     new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
                     null, null, null, null, ACCOUNTS_ID);
             try {
                 accounts.accountCache.clear();
-                final HashMap<String, ArrayList<String>> accountNamesByType =
-                        new LinkedHashMap<String, ArrayList<String>>();
+                final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
                 while (cursor.moveToNext()) {
                     final long accountId = cursor.getLong(0);
                     final String accountType = cursor.getString(1);
                     final String accountName = cursor.getString(2);
 
-                    if (!knownAuth.contains(AuthenticatorDescription.newKey(accountType))) {
+                    if (obsoleteAuthType.contains(accountType)) {
                         Slog.w(TAG, "deleting account " + accountName + " because type "
-                                + accountType + " no longer has a registered authenticator");
+                                + accountType + "'s registered authenticator no longer exist.");
                         db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
                         accountDeleted = true;
 
@@ -419,15 +500,12 @@
                         accountNames.add(accountName);
                     }
                 }
-                for (Map.Entry<String, ArrayList<String>> cur
-                        : accountNamesByType.entrySet()) {
+                for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
                     final String accountType = cur.getKey();
                     final ArrayList<String> accountNames = cur.getValue();
                     final Account[] accountsForType = new Account[accountNames.size()];
-                    int i = 0;
-                    for (String accountName : accountNames) {
-                        accountsForType[i] = new Account(accountName, accountType);
-                        ++i;
+                    for (int i = 0; i < accountsForType.length; i++) {
+                        accountsForType[i] = new Account(accountNames.get(i), accountType);
                     }
                     accounts.accountCache.put(accountType, accountsForType);
                 }
@@ -440,6 +518,18 @@
         }
     }
 
+    private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
+            Context context,
+            int userId) {
+        AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
+        HashMap<String, Integer> knownAuth = new HashMap<>();
+        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
+                .getAllServices(userId)) {
+            knownAuth.put(service.type.type, service.uid);
+        }
+        return knownAuth;
+    }
+
     private UserAccounts getUserAccountsForCaller() {
         return getUserAccounts(UserHandle.getCallingUserId());
     }
@@ -447,12 +537,25 @@
     protected UserAccounts getUserAccounts(int userId) {
         synchronized (mUsers) {
             UserAccounts accounts = mUsers.get(userId);
+            boolean validateAccounts = false;
             if (accounts == null) {
                 accounts = new UserAccounts(mContext, userId);
                 initializeDebugDbSizeAndCompileSqlStatementForLogging(
                         accounts.openHelper.getWritableDatabase(), accounts);
                 mUsers.append(userId, accounts);
                 purgeOldGrants(accounts);
+                validateAccounts = true;
+            }
+            // open CE database if necessary
+            if (!accounts.openHelper.isCeDatabaseAttached() && mUnlockedUsers.get(userId)) {
+                Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
+                synchronized (accounts.cacheLock) {
+                    CeDatabaseHelper.create(mContext, userId);
+                    accounts.openHelper.attachCeDatabase();
+                }
+                // TODO Synchronize accounts by removing CE account not available in DE
+            }
+            if (validateAccounts) {
                 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
             }
             return accounts;
@@ -496,33 +599,57 @@
         if (userId < 1) return;
 
         UserAccounts accounts;
+        boolean userUnlocked;
         synchronized (mUsers) {
             accounts = mUsers.get(userId);
             mUsers.remove(userId);
+            userUnlocked = mUnlockedUsers.get(userId);
+            mUnlockedUsers.delete(userId);
         }
-        if (accounts == null) {
-            File dbFile = new File(getDatabaseName(userId));
-            dbFile.delete();
-            return;
+        if (accounts != null) {
+            synchronized (accounts.cacheLock) {
+                accounts.openHelper.close();
+            }
         }
+        Log.i(TAG, "Removing database files for user " + userId);
+        File dbFile = new File(getDeDatabaseName(userId));
 
-        synchronized (accounts.cacheLock) {
-            accounts.openHelper.close();
-            File dbFile = new File(getDatabaseName(userId));
-            dbFile.delete();
+        deleteDbFileWarnIfFailed(dbFile);
+        // Remove CE file if user is unlocked, or FBE is not enabled
+        boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
+        if (!fbeEnabled || userUnlocked) {
+            File ceDb = new File(getCeDatabaseName(userId));
+            if (ceDb.exists()) {
+                deleteDbFileWarnIfFailed(ceDb);
+            }
         }
     }
 
-    private void onUserStarted(Intent intent) {
-        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-        if (userId < 1) return;
+    private static void deleteDbFileWarnIfFailed(File dbFile) {
+        if (!SQLiteDatabase.deleteDatabase(dbFile)) {
+            Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
+        }
+    }
 
+    private void onUserUnlocked(Intent intent) {
+        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "onUserUnlocked " + userId);
+        }
+        synchronized (mUsers) {
+            mUnlockedUsers.put(userId, true);
+        }
+        if (userId < 1) return;
+        syncSharedAccounts(userId);
+    }
+
+    private void syncSharedAccounts(int userId) {
         // Check if there's a shared account that needs to be created as an account
         Account[] sharedAccounts = getSharedAccountsAsUser(userId);
         if (sharedAccounts == null || sharedAccounts.length == 0) return;
         Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
         int parentUserId = UserManager.isSplitSystemUser()
-                ? mUserManager.getUserInfo(userId).restrictedProfileParentId
+                ? getUserManager().getUserInfo(userId).restrictedProfileParentId
                 : UserHandle.USER_SYSTEM;
         if (parentUserId < 0) {
             Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
@@ -570,20 +697,15 @@
         if (account == null) {
             return null;
         }
+        if (!isUserUnlocked(accounts.userId)) {
+            Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
+            return null;
+        }
 
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-            Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
-                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                    new String[]{account.name, account.type}, null, null, null);
-            try {
-                if (cursor.moveToNext()) {
-                    return cursor.getString(0);
-                }
-                return null;
-            } finally {
-                cursor.close();
-            }
+            final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
+            return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
+                    account.type);
         }
     }
 
@@ -624,7 +746,7 @@
                 try {
                     if (cursor.moveToNext()) {
                         String previousName = cursor.getString(0);
-                        previousNameRef = new AtomicReference<String>(previousName);
+                        previousNameRef = new AtomicReference<>(previousName);
                         accounts.previousNameCache.put(account, previousNameRef);
                         return previousName;
                     } else {
@@ -727,6 +849,7 @@
 
     @Override
     public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
+        Bundle.setDefusable(extras, true);
         final int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "addAccountExplicitly: " + account
@@ -754,7 +877,7 @@
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
-            return addAccountInternal(accounts, account, password, extras, false, callingUid);
+            return addAccountInternal(accounts, account, password, extras, callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -803,6 +926,7 @@
 
                 @Override
                 public void onResult(Bundle result) {
+                    Bundle.setDefusable(result, true);
                     if (result != null
                             && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                         // Create a Session for the target user and pass in the bundle
@@ -876,6 +1000,7 @@
     private void completeCloningAccount(IAccountManagerResponse response,
             final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
             final int parentUserId){
+        Bundle.setDefusable(accountCredentials, true);
         long id = clearCallingIdentity();
         try {
             new Session(targetUser, response, account.type, false,
@@ -905,6 +1030,7 @@
 
                 @Override
                 public void onResult(Bundle result) {
+                    Bundle.setDefusable(result, true);
                     // TODO: Anything to do if if succedded?
                     // TODO: If it failed: Show error notification? Should we remove the shadow
                     // account to avoid retries?
@@ -925,16 +1051,22 @@
     }
 
     private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
-            Bundle extras, boolean restricted, int callingUid) {
+            Bundle extras, int callingUid) {
+        Bundle.setDefusable(extras, true);
         if (account == null) {
             return false;
         }
+        if (!isUserUnlocked(accounts.userId)) {
+            Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
+                    + " is locked. callingUid=" + callingUid);
+            return false;
+        }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
                 long numMatches = DatabaseUtils.longForQuery(db,
-                        "select count(*) from " + TABLE_ACCOUNTS
+                        "select count(*) from " + CE_TABLE_ACCOUNTS
                                 + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
                         new String[]{account.name, account.type});
                 if (numMatches > 0) {
@@ -946,13 +1078,24 @@
                 values.put(ACCOUNTS_NAME, account.name);
                 values.put(ACCOUNTS_TYPE, account.type);
                 values.put(ACCOUNTS_PASSWORD, password);
-                values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
-                long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+                long accountId = db.insert(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
                 if (accountId < 0) {
                     Log.w(TAG, "insertAccountIntoDatabase: " + account
                             + ", skipping the DB insert failed");
                     return false;
                 }
+                // Insert into DE table
+                values = new ContentValues();
+                values.put(ACCOUNTS_ID, accountId);
+                values.put(ACCOUNTS_NAME, account.name);
+                values.put(ACCOUNTS_TYPE, account.type);
+                values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS,
+                        System.currentTimeMillis());
+                if (db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values) < 0) {
+                    Log.w(TAG, "insertAccountIntoDatabase: " + account
+                            + ", skipping the DB insert failed");
+                    return false;
+                }
                 if (extras != null) {
                     for (String key : extras.keySet()) {
                         final String value = extras.getString(key);
@@ -980,6 +1123,12 @@
         return true;
     }
 
+    private boolean isUserUnlocked(int userId) {
+        synchronized (mUsers) {
+            return mUnlockedUsers.get(userId);
+        }
+    }
+
     /**
      * Adds the account to all linked restricted users as shared accounts. If the user is currently
      * running, then clone the account too.
@@ -991,13 +1140,9 @@
         for (UserInfo user : users) {
             if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
                 addSharedAccountAsUser(account, user.id);
-                try {
-                    if (ActivityManagerNative.getDefault().isUserRunning(user.id, 0)) {
-                        mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
-                                MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
-                    }
-                } catch (RemoteException re) {
-                    // Shouldn't happen
+                if (getUserManager().isUserUnlocked(user.id)) {
+                    mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
+                            MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
                 }
             }
         }
@@ -1008,7 +1153,7 @@
         values.put(EXTRAS_KEY, key);
         values.put(EXTRAS_ACCOUNTS_ID, accountId);
         values.put(EXTRAS_VALUE, value);
-        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
+        return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
     }
 
     @Override
@@ -1062,6 +1207,7 @@
 
         @Override
         public void onResult(Bundle result) {
+            Bundle.setDefusable(result, true);
             IAccountManagerResponse response = getResponseAndClose();
             if (response != null) {
                 try {
@@ -1154,17 +1300,19 @@
             }
         }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             boolean isSuccessful = false;
             Account renamedAccount = new Account(newName, accountToRename.type);
             try {
-                final ContentValues values = new ContentValues();
-                values.put(ACCOUNTS_NAME, newName);
-                values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
                 final long accountId = getAccountIdLocked(db, accountToRename);
                 if (accountId >= 0) {
+                    final ContentValues values = new ContentValues();
+                    values.put(ACCOUNTS_NAME, newName);
                     final String[] argsAccountId = { String.valueOf(accountId) };
+                    db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+                    // Update NAME/PREVIOUS_NAME in DE accounts table
+                    values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
                     db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
                     db.setTransactionSuccessful();
                     isSuccessful = true;
@@ -1204,7 +1352,7 @@
                          * Owner or system user account was renamed, rename the account for
                          * those users with which the account was shared.
                          */
-                        List<UserInfo> users = mUserManager.getUsers(true);
+                        List<UserInfo> users = getUserManager().getUsers(true);
                         for (UserInfo user : users) {
                             if (user.isRestricted()
                                     && (user.restrictedProfileParentId == parentUserId)) {
@@ -1220,7 +1368,7 @@
     }
 
     private boolean canHaveProfile(final int parentUserId) {
-        final UserInfo userInfo = mUserManager.getUserInfo(parentUserId);
+        final UserInfo userInfo = getUserManager().getUserInfo(parentUserId);
         return userInfo != null && userInfo.canHaveProfile();
     }
 
@@ -1260,7 +1408,7 @@
          * authenticator.  This will let users remove accounts (via Settings in the system) but not
          * arbitrary applications (like competing authenticators).
          */
-        UserHandle user = new UserHandle(userId);
+        UserHandle user = UserHandle.of(userId);
         if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
                 && !isSystemUid(callingUid)) {
             String msg = String.format(
@@ -1363,6 +1511,7 @@
 
         @Override
         public void onResult(Bundle result) {
+            Bundle.setDefusable(result, true);
             if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
                     && !result.containsKey(AccountManager.KEY_INTENT)) {
                 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
@@ -1394,13 +1543,17 @@
     }
 
     private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
+        // For now user is required to be unlocked. TODO: Handle both cases in the future
         int deleted;
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             final long accountId = getAccountIdLocked(db, account);
             deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
                     + "=?",
                     new String[]{account.name, account.type});
+            // Delete from CE table
+            db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                    new String[]{account.name, account.type});
             removeAccountFromCacheLocked(accounts, account);
             sendAccountsChangedBroadcast(accounts.userId);
 
@@ -1411,7 +1564,7 @@
             int parentUserId = accounts.userId;
             if (canHaveProfile(parentUserId)) {
                 // Remove from any restricted profiles that are sharing this account.
-                List<UserInfo> users = mUserManager.getUsers(true);
+                List<UserInfo> users = getUserManager().getUsers(true);
                 for (UserInfo user : users) {
                     if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
                         removeSharedAccountAsUser(account, user.id, callingUid);
@@ -1439,7 +1592,7 @@
         try {
             UserAccounts accounts = getUserAccounts(userId);
             synchronized (accounts.cacheLock) {
-                final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+                final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
                 db.beginTransaction();
                 try {
                     invalidateAuthTokenLocked(accounts, db, accountType, authToken);
@@ -1471,22 +1624,22 @@
             return;
         }
         Cursor cursor = db.rawQuery(
-                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
-                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
-                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
-                        + " FROM " + TABLE_ACCOUNTS
-                        + " JOIN " + TABLE_AUTHTOKENS
-                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
-                        + " = " + AUTHTOKENS_ACCOUNTS_ID
-                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
-                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+                "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+                        + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+                        + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+                        + " FROM " + CE_TABLE_ACCOUNTS
+                        + " JOIN " + CE_TABLE_AUTHTOKENS
+                        + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+                        + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
+                        + " WHERE " + CE_TABLE_AUTHTOKENS + "."  + AUTHTOKENS_AUTHTOKEN
+                        + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
                 new String[]{authToken, accountType});
         try {
             while (cursor.moveToNext()) {
                 long authTokenId = cursor.getLong(0);
                 String accountName = cursor.getString(1);
                 String authTokenType = cursor.getString(2);
-                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+                db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
                 writeAuthTokenIntoCacheLocked(
                         accounts,
                         db,
@@ -1512,7 +1665,7 @@
             return;
         }
         cancelNotification(getSigninRequiredNotificationId(accounts, account),
-                new UserHandle(accounts.userId));
+                UserHandle.of(accounts.userId));
         synchronized (accounts.cacheLock) {
             accounts.accountTokenCaches.put(
                     account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
@@ -1525,23 +1678,23 @@
             return false;
         }
         cancelNotification(getSigninRequiredNotificationId(accounts, account),
-                new UserHandle(accounts.userId));
+                UserHandle.of(accounts.userId));
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
                 long accountId = getAccountIdLocked(db, account);
                 if (accountId < 0) {
                     return false;
                 }
-                db.delete(TABLE_AUTHTOKENS,
+                db.delete(CE_TABLE_AUTHTOKENS,
                         AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
                         new String[]{type});
                 ContentValues values = new ContentValues();
                 values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
                 values.put(AUTHTOKENS_TYPE, type);
                 values.put(AUTHTOKENS_AUTHTOKEN, authToken);
-                if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+                if (db.insert(CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
                     db.setTransactionSuccessful();
                     writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
                     return true;
@@ -1641,7 +1794,7 @@
             return;
         }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
                 final ContentValues values = new ContentValues();
@@ -1649,8 +1802,8 @@
                 final long accountId = getAccountIdLocked(db, account);
                 if (accountId >= 0) {
                     final String[] argsAccountId = {String.valueOf(accountId)};
-                    db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
-                    db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+                    db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+                    db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
                     accounts.authTokenCache.remove(account);
                     accounts.accountTokenCaches.remove(account);
                     db.setTransactionSuccessful();
@@ -1734,7 +1887,7 @@
 
     private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
         if (accounts.accountCache.containsKey(account.type)) {
-            for (Account acc : getUserAccountsForCaller().accountCache.get(account.type)) {
+            for (Account acc : accounts.accountCache.get(account.type)) {
                 if (acc.name.equals(account.name)) {
                     return true;
                 }
@@ -1767,7 +1920,6 @@
                 if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
                     return;
                 }
-
             }
             writeUserDataIntoCacheLocked(accounts, db, account, key, value);
             db.setTransactionSuccessful();
@@ -1828,6 +1980,7 @@
 
                 @Override
                 public void onResult(Bundle result) {
+                    Bundle.setDefusable(result, true);
                     if (result != null) {
                         String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
                         Bundle bundle = new Bundle();
@@ -1852,6 +2005,7 @@
             final boolean notifyOnAuthFailure,
             final boolean expectActivityLaunch,
             final Bundle loginOptions) {
+        Bundle.setDefusable(loginOptions, true);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAuthToken: " + account
                     + ", response " + response
@@ -1992,6 +2146,7 @@
 
                 @Override
                 public void onResult(Bundle result) {
+                    Bundle.setDefusable(result, true);
                     if (result != null) {
                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
                             Intent intent = newGrantCredentialsPermissionIntent(
@@ -2154,6 +2309,7 @@
     public void addAccount(final IAccountManagerResponse response, final String accountType,
             final String authTokenType, final String[] requiredFeatures,
             final boolean expectActivityLaunch, final Bundle optionsIn) {
+        Bundle.setDefusable(optionsIn, true);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "addAccount: accountType " + accountType
                     + ", response " + response
@@ -2228,6 +2384,7 @@
     public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
             final String authTokenType, final String[] requiredFeatures,
             final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
+        Bundle.setDefusable(optionsIn, true);
         int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "addAccount: accountType " + accountType
@@ -2314,6 +2471,7 @@
             final String[] requiredFeatures,
             final boolean expectActivityLaunch,
             final Bundle optionsIn) {
+        Bundle.setDefusable(optionsIn, true);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG,
                     "startAddAccountSession: accountType " + accountType
@@ -2360,21 +2518,31 @@
                     userId);
             return;
         }
-
         final int pid = Binder.getCallingPid();
         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
         options.putInt(AccountManager.KEY_CALLER_UID, uid);
         options.putInt(AccountManager.KEY_CALLER_PID, pid);
 
+        // Check to see if the Password should be included to the caller.
+        String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+        boolean isPasswordForwardingAllowed = isPermitted(
+                callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
         int usrId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(usrId);
             logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
                     TABLE_ACCOUNTS, uid);
-            new StartAccountSession(accounts, response, accountType, expectActivityLaunch,
-                    null /* accountName */, false /* authDetailsRequired */,
-                    true /* updateLastAuthenticationTime */) {
+            new StartAccountSession(
+                    accounts,
+                    response,
+                    accountType,
+                    expectActivityLaunch,
+                    null /* accountName */,
+                    false /* authDetailsRequired */,
+                    true /* updateLastAuthenticationTime */,
+                    isPasswordForwardingAllowed) {
                 @Override
                 public void run() throws RemoteException {
                     mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
@@ -2397,43 +2565,38 @@
     /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
     private abstract class StartAccountSession extends Session {
 
-        public StartAccountSession(UserAccounts accounts, IAccountManagerResponse response,
-                String accountType, boolean expectActivityLaunch, String accountName,
-                boolean authDetailsRequired, boolean updateLastAuthenticationTime) {
+        private final boolean mIsPasswordForwardingAllowed;
+
+        public StartAccountSession(
+                UserAccounts accounts,
+                IAccountManagerResponse response,
+                String accountType,
+                boolean expectActivityLaunch,
+                String accountName,
+                boolean authDetailsRequired,
+                boolean updateLastAuthenticationTime,
+                boolean isPasswordForwardingAllowed) {
             super(accounts, response, accountType, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
                     updateLastAuthenticationTime);
+            mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
         }
 
         @Override
         public void onResult(Bundle result) {
+            Bundle.setDefusable(result, true);
             mNumResults++;
             Intent intent = null;
-
             if (result != null
                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
-                /*
-                 * The Authenticator API allows third party authenticators to
-                 * supply arbitrary intents to other apps that they can run,
-                 * this can be very bad when those apps are in the system like
-                 * the System Settings.
-                 */
-                int authenticatorUid = Binder.getCallingUid();
-                long bid = Binder.clearCallingIdentity();
-                try {
-                    PackageManager pm = mContext.getPackageManager();
-                    ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
-                    int targetUid = resolveInfo.activityInfo.applicationInfo.uid;
-                    if (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authenticatorUid,
-                            targetUid)) {
-                        throw new SecurityException("Activity to be started with KEY_INTENT must "
-                                + "share Authenticator's signatures");
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(bid);
+                checkKeyIntent(
+                        Binder.getCallingUid(),
+                        intent);
+                // Omit passwords if the caller isn't permitted to see them.
+                if (!mIsPasswordForwardingAllowed) {
+                    result.remove(AccountManager.KEY_PASSWORD);
                 }
             }
-
             IAccountManagerResponse response;
             if (mExpectActivityLaunch && result != null
                     && result.containsKey(AccountManager.KEY_INTENT)) {
@@ -2510,6 +2673,7 @@
             boolean expectActivityLaunch,
             Bundle appInfo,
             int userId) {
+        Bundle.setDefusable(sessionBundle, true);
         int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG,
@@ -2665,6 +2829,7 @@
             final Bundle options,
             final boolean expectActivityLaunch,
             int userId) {
+        Bundle.setDefusable(options, true);
         int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "confirmCredentials: " + account
@@ -2708,6 +2873,7 @@
     public void updateCredentials(IAccountManagerResponse response, final Account account,
             final String authTokenType, final boolean expectActivityLaunch,
             final Bundle loginOptions) {
+        Bundle.setDefusable(loginOptions, true);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "updateCredentials: " + account
                     + ", response " + response
@@ -2751,6 +2917,7 @@
             final String authTokenType,
             final boolean expectActivityLaunch,
             final Bundle loginOptions) {
+        Bundle.setDefusable(loginOptions, true);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG,
                     "startUpdateCredentialsSession: " + account + ", response " + response
@@ -2775,6 +2942,12 @@
         }
 
         int userId = UserHandle.getCallingUserId();
+
+        // Check to see if the Password should be included to the caller.
+        String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+        boolean isPasswordForwardingAllowed = isPermitted(
+                callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -2785,7 +2958,8 @@
                     expectActivityLaunch,
                     account.name,
                     false /* authDetailsRequired */,
-                    true /* updateLastCredentialTime */) {
+                    true /* updateLastCredentialTime */,
+                    isPasswordForwardingAllowed) {
                 @Override
                 public void run() throws RemoteException {
                     mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
@@ -2858,6 +3032,7 @@
 
                 @Override
                 public void onResult(Bundle result) {
+                    Bundle.setDefusable(result, true);
                     IAccountManagerResponse response = getResponseAndClose();
                     if (response == null) {
                         return;
@@ -3018,6 +3193,7 @@
 
         @Override
         public void onResult(Bundle result) {
+            Bundle.setDefusable(result, true);
             mNumResults++;
             if (result == null) {
                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
@@ -3254,7 +3430,6 @@
         long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
         final ContentValues values = new ContentValues();
         values.put(ACCOUNTS_NAME, newName);
-        values.put(ACCOUNTS_PREVIOUS_NAME, account.name);
         int r = db.update(
                 TABLE_SHARED_ACCOUNTS,
                 values,
@@ -3294,7 +3469,7 @@
     public Account[] getSharedAccountsAsUser(int userId) {
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
-        ArrayList<Account> accountList = new ArrayList<Account>();
+        ArrayList<Account> accountList = new ArrayList<>();
         Cursor cursor = null;
         try {
             cursor = accounts.openHelper.getReadableDatabase()
@@ -3435,7 +3610,7 @@
     }
 
     private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
-        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
+        Cursor cursor = db.query(CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
                 EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
                 new String[]{key}, null, null, null);
         try {
@@ -3518,6 +3693,36 @@
             return response;
         }
 
+        /**
+         * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
+         * security policy.
+         *
+         * In particular we want to make sure that the Authenticator doesn't try to trick users
+         * into launching aribtrary intents on the device via by tricking to click authenticator
+         * supplied entries in the system Settings app.
+         */
+        protected void checkKeyIntent(
+                int authUid,
+                Intent intent) throws SecurityException {
+            long bid = Binder.clearCallingIdentity();
+            try {
+                PackageManager pm = mContext.getPackageManager();
+                ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
+                ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
+                int targetUid = targetActivityInfo.applicationInfo.uid;
+                if (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authUid, targetUid)) {
+                    String pkgName = targetActivityInfo.packageName;
+                    String activityName = targetActivityInfo.name;
+                    String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
+                            + "does not share a signature with the supplying authenticator (%s).";
+                    throw new SecurityException(
+                            String.format(tmpl, activityName, pkgName, mAccountType));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(bid);
+            }
+        }
+
         private void close() {
             synchronized (mSessions) {
                 if (mSessions.remove(toString()) == null) {
@@ -3622,6 +3827,7 @@
 
         @Override
         public void onResult(Bundle result) {
+            Bundle.setDefusable(result, true);
             mNumResults++;
             Intent intent = null;
             if (result != null) {
@@ -3645,8 +3851,8 @@
                         if (accountPresent) {
                             lastAuthenticatedTime = DatabaseUtils.longForQuery(
                                     mAccounts.openHelper.getReadableDatabase(),
-                                    "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
-                                            + " from " +
+                                    "SELECT " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                                            + " FROM " +
                                             TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
                                             + ACCOUNTS_TYPE + "=?",
                                     new String[] {
@@ -3660,27 +3866,9 @@
             }
             if (result != null
                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
-                /*
-                 * The Authenticator API allows third party authenticators to
-                 * supply arbitrary intents to other apps that they can run,
-                 * this can be very bad when those apps are in the system like
-                 * the System Settings.
-                 */
-                int authenticatorUid = Binder.getCallingUid();
-                long bid = Binder.clearCallingIdentity();
-                try {
-                    PackageManager pm = mContext.getPackageManager();
-                    ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
-                    int targetUid = resolveInfo.activityInfo.applicationInfo.uid;
-                    if (PackageManager.SIGNATURE_MATCH !=
-                            pm.checkSignatures(authenticatorUid, targetUid)) {
-                        throw new SecurityException(
-                                "Activity to be started with KEY_INTENT must " +
-                               "share Authenticator's signatures");
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(bid);
-                }
+                checkKeyIntent(
+                        Binder.getCallingUid(),
+                        intent);
             }
             if (result != null
                     && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
@@ -3780,7 +3968,7 @@
 
             final ActivityManager am = mContext.getSystemService(ActivityManager.class);
             if (am.isUserRunningAndLocked(mAccounts.userId)
-                    && !authenticatorInfo.componentInfo.encryptionAware) {
+                    && !authenticatorInfo.componentInfo.directBootAware) {
                 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
                         + " which isn't encryption aware");
                 return false;
@@ -3793,7 +3981,7 @@
                 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
             }
             if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
-                    new UserHandle(mAccounts.userId))) {
+                    UserHandle.of(mAccounts.userId))) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
                     Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
                 }
@@ -3827,15 +4015,16 @@
         }
     }
 
-    private static String getDatabaseName(int userId) {
+    static String getPreNDatabaseName(int userId) {
         File systemDir = Environment.getDataSystemDirectory();
-        File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
+        File databaseFile = new File(Environment.getUserSystemDirectory(userId),
+                PRE_N_DATABASE_NAME);
         if (userId == 0) {
             // Migrate old file, if it exists, to the new location.
             // Make sure the new file doesn't already exist. A dummy file could have been
             // accidentally created in the old location, causing the new one to become corrupted
             // as well.
-            File oldFile = new File(systemDir, DATABASE_NAME);
+            File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
             if (oldFile.exists() && !databaseFile.exists()) {
                 // Check for use directory; create if it doesn't exist, else renameTo will fail
                 File userDir = Environment.getUserSystemDirectory(userId);
@@ -3852,6 +4041,18 @@
         return databaseFile.getPath();
     }
 
+    static String getDeDatabaseName(int userId) {
+        File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
+                DE_DATABASE_NAME);
+        return databaseFile.getPath();
+    }
+
+    static String getCeDatabaseName(int userId) {
+        File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
+                CE_DATABASE_NAME);
+        return databaseFile.getPath();
+    }
+
     private static class DebugDbHelper{
         private DebugDbHelper() {
         }
@@ -3984,53 +4185,22 @@
         return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
     }
 
-    static class DatabaseHelper extends SQLiteOpenHelper {
+    static class PreNDatabaseHelper extends SQLiteOpenHelper {
 
-        public DatabaseHelper(Context context, int userId) {
-            super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
+        private final Context mContext;
+        private final int mUserId;
+
+        public PreNDatabaseHelper(Context context, int userId) {
+            super(context, AccountManagerService.getPreNDatabaseName(userId), null,
+                    PRE_N_DATABASE_VERSION);
+            mContext = context;
+            mUserId = userId;
         }
 
-        /**
-         * This call needs to be made while the mCacheLock is held. The way to
-         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
-         * @param db The database.
-         */
         @Override
         public void onCreate(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
-                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
-                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
-                    + ACCOUNTS_PASSWORD + " TEXT, "
-                    + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
-                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
-                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
-            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
-                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
-                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
-                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
-                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
-                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
-
-            createGrantsTable(db);
-
-            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
-                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
-                    + EXTRAS_KEY + " TEXT NOT NULL, "
-                    + EXTRAS_VALUE + " TEXT, "
-                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
-
-            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
-                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
-                    + META_VALUE + " TEXT)");
-
-            createSharedAccountsTable(db);
-
-            createAccountsDeletionTrigger(db);
-
-            DebugDbHelper.createDebugTable(db);
+            // We use PreNDatabaseHelper only if pre-N db exists
+            throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
         }
 
         private void createSharedAccountsTable(SQLiteDatabase db) {
@@ -4076,6 +4246,23 @@
                     +   "," + GRANTS_GRANTEE_UID + "))");
         }
 
+        private void populateMetaTableWithAuthTypeAndUID(
+                SQLiteDatabase db,
+                Map<String, Integer> authTypeAndUIDMap) {
+            Iterator<Entry<String, Integer>> iterator = authTypeAndUIDMap.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Entry<String, Integer> entry = iterator.next();
+                ContentValues values = new ContentValues();
+                values.put(META_KEY,
+                        META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey());
+                values.put(META_VALUE, entry.getValue());
+                db.insert(TABLE_META, null, values);
+            }
+        }
+
+        /**
+         * Pre-N database may need an upgrade before splitting
+         */
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
             Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
@@ -4119,6 +4306,13 @@
                 oldVersion++;
             }
 
+            if (oldVersion == 8) {
+                populateMetaTableWithAuthTypeAndUID(
+                        db,
+                        AccountManagerService.getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
+                oldVersion++;
+            }
+
             if (oldVersion != newVersion) {
                 Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
             }
@@ -4130,6 +4324,315 @@
         }
     }
 
+    static class DeDatabaseHelper extends SQLiteOpenHelper {
+
+        private final int mUserId;
+        private volatile boolean mCeAttached;
+
+        private DeDatabaseHelper(Context context, int userId) {
+            super(context, getDeDatabaseName(userId), null, DE_DATABASE_VERSION);
+            mUserId = userId;
+        }
+
+        /**
+         * This call needs to be made while the mCacheLock is held. The way to
+         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
+         * @param db The database.
+         */
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            Log.i(TAG, "Creating DE database for user " + mUserId);
+            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
+                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+                    + META_VALUE + " TEXT)");
+
+            createGrantsTable(db);
+            createSharedAccountsTable(db);
+            createAccountsDeletionTrigger(db);
+            DebugDbHelper.createDebugTable(db);
+        }
+
+        private void createSharedAccountsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+        }
+
+        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_GRANTS
+                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        private void createGrantsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
+                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
+                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
+                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+                    +   "," + GRANTS_GRANTEE_UID + "))");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
+        }
+
+        public void attachCeDatabase() {
+            File ceDbFile = new File(getCeDatabaseName(mUserId));
+            SQLiteDatabase db = getWritableDatabase();
+            db.execSQL("ATTACH DATABASE '" +  ceDbFile.getPath()+ "' AS ceDb");
+            mCeAttached = true;
+        }
+
+        public boolean isCeDatabaseAttached() {
+            return mCeAttached;
+        }
+
+
+        public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
+            if(!mCeAttached) {
+                Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user "
+                        + mUserId + " is still locked ", new Throwable());
+            }
+            return super.getReadableDatabase();
+        }
+
+        public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
+            if(!mCeAttached) {
+                Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
+                        + " is still locked ", new Throwable());
+            }
+            return super.getWritableDatabase();
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
+        }
+
+        private void migratePreNDbToDe(File preNDbFile) {
+            Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
+            SQLiteDatabase db = getWritableDatabase();
+            db.execSQL("ATTACH DATABASE '" +  preNDbFile.getPath() + "' AS preNDb");
+            db.beginTransaction();
+            // Copy accounts fields
+            db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
+                    + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                    + ") "
+                    + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                    + " FROM preNDb." + TABLE_ACCOUNTS);
+            // Copy SHARED_ACCOUNTS
+            db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
+                    + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
+                    "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+                    + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
+            // Copy DEBUG_TABLE
+            db.execSQL("INSERT INTO " + DebugDbHelper.TABLE_DEBUG
+                    + "(" + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+                    + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+                    + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY + ") " +
+                    "SELECT " + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+                    + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+                    + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY
+                    + " FROM preNDb." + DebugDbHelper.TABLE_DEBUG);
+            // Copy GRANTS
+            db.execSQL("INSERT INTO " + TABLE_GRANTS
+                    + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+                    + GRANTS_GRANTEE_UID + ") " +
+                    "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+                    + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
+            // Copy META
+            db.execSQL("INSERT INTO " + TABLE_META
+                    + "(" + META_KEY + "," + META_VALUE + ") "
+                    + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
+            db.setTransactionSuccessful();
+            db.endTransaction();
+
+            db.execSQL("DETACH DATABASE preNDb");
+        }
+
+        static DeDatabaseHelper create(Context context, int userId) {
+            File oldDb = new File(getPreNDatabaseName(userId));
+            File newDb = new File(getDeDatabaseName(userId));
+            boolean newDbExists = newDb.exists();
+            DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId);
+            // If the db just created, and there is a legacy db, migrate it
+            if (!newDbExists && oldDb.exists()) {
+                // Migrate legacy db to the latest version -  PRE_N_DATABASE_VERSION
+                PreNDatabaseHelper preNDatabaseHelper = new PreNDatabaseHelper(context, userId);
+                // Open the database to force upgrade if required
+                preNDatabaseHelper.getWritableDatabase();
+                preNDatabaseHelper.close();
+                // Move data without SPII to DE
+                deDatabaseHelper.migratePreNDbToDe(oldDb);
+            }
+            return deDatabaseHelper;
+        }
+    }
+
+    static class CeDatabaseHelper extends SQLiteOpenHelper {
+
+        public CeDatabaseHelper(Context context, int userId) {
+            super(context, getCeDatabaseName(userId), null, CE_DATABASE_VERSION);
+        }
+
+        /**
+         * This call needs to be made while the mCacheLock is held.
+         * @param db The database.
+         */
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            Log.i(TAG, "Creating CE database " + getDatabaseName());
+            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + ACCOUNTS_PASSWORD + " TEXT, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
+                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
+                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
+                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
+                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+                    + EXTRAS_KEY + " TEXT NOT NULL, "
+                    + EXTRAS_VALUE + " TEXT, "
+                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+            createAccountsDeletionTrigger(db);
+        }
+
+        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_AUTHTOKENS
+                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + "   DELETE FROM " + TABLE_EXTRAS
+                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion == 9) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "onUpgrade upgrading to v10");
+                }
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
+                // Recreate the trigger, since the old one references the table to be removed
+                db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
+                createAccountsDeletionTrigger(db);
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
+                db.execSQL("DROP TABLE IF EXISTS " + DebugDbHelper.TABLE_DEBUG);
+                oldVersion ++;
+            }
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
+        }
+
+        static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
+                String type) {
+            Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                    new String[]{name, type}, null, null, null);
+            try {
+                if (cursor.moveToNext()) {
+                    return cursor.getString(0);
+                }
+                return null;
+            } finally {
+                cursor.close();
+            }
+        }
+
+        /**
+         * Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
+         * it also performs migration to the new CE database.
+         * @param context
+         * @param userId id of the user where the database is located
+         */
+        static CeDatabaseHelper create(Context context, int userId) {
+
+            File oldDatabaseFile = new File(getPreNDatabaseName(userId));
+            File ceDatabaseFile = new File(getCeDatabaseName(userId));
+            boolean newDbExists = ceDatabaseFile.exists();
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
+                        + oldDatabaseFile.exists() + " newDbExists=" + newDbExists);
+            }
+            boolean removeOldDb = false;
+            if (!newDbExists && oldDatabaseFile.exists()) {
+                removeOldDb = migratePreNDbToCe(oldDatabaseFile, ceDatabaseFile);
+            }
+            // Try to open and upgrade if necessary
+            CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, userId);
+            ceHelper.getWritableDatabase();
+            ceHelper.close();
+            if (removeOldDb) {
+                // TODO STOPSHIP - backup file during testing. Remove file before the release
+                Log.i(TAG, "Migration complete - creating backup of old db " + oldDatabaseFile);
+                renameToBakFile(oldDatabaseFile);
+            }
+            return ceHelper;
+        }
+
+        private static void renameToBakFile(File file) {
+            File bakFile = new File(file.getPath() + ".bak");
+            if (!file.renameTo(bakFile)) {
+                Log.e(TAG, "Cannot move file to " + bakFile);
+            }
+        }
+
+        private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
+            Log.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
+            try {
+                FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
+            } catch (IOException e) {
+                Log.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
+                // Try to remove potentially damaged file if I/O error occurred
+                deleteDbFileWarnIfFailed(ceDbFile);
+                return false;
+            }
+            return true;
+        }
+    }
+
     public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
         return asBinder();
     }
@@ -4574,7 +5077,7 @@
                 db.endTransaction();
             }
             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
-                    new UserHandle(accounts.userId));
+                    UserHandle.of(accounts.userId));
         }
     }
 
@@ -4659,7 +5162,7 @@
                 || callingUid == Process.myUid()) {
             return unfiltered;
         }
-        UserInfo user = mUserManager.getUserInfo(userAccounts.userId);
+        UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
         if (user != null && user.isRestricted()) {
             String[] packages = mPackageManager.getPackagesForUid(callingUid);
             // If any of the packages is a white listed package, return the full set,
@@ -4799,7 +5302,7 @@
             HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
             if (authTokensForAccount == null) {
                 // need to populate the cache for this account
-                final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+                final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
                 authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
                 accounts.authTokenCache.put(account, authTokensForAccount);
             }
@@ -4821,8 +5324,8 @@
 
     protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
             final SQLiteDatabase db, Account account) {
-        HashMap<String, String> userDataForAccount = new HashMap<String, String>();
-        Cursor cursor = db.query(TABLE_EXTRAS,
+        HashMap<String, String> userDataForAccount = new HashMap<>();
+        Cursor cursor = db.query(CE_TABLE_EXTRAS,
                 COLUMNS_EXTRAS_KEY_AND_VALUE,
                 SELECTION_USERDATA_BY_ACCOUNT,
                 new String[]{account.name, account.type},
@@ -4841,8 +5344,8 @@
 
     protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
             final SQLiteDatabase db, Account account) {
-        HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
-        Cursor cursor = db.query(TABLE_AUTHTOKENS,
+        HashMap<String, String> authTokensForAccount = new HashMap<>();
+        Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
                 COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
                 SELECTION_AUTHTOKENS_BY_ACCOUNT,
                 new String[]{account.name, account.type},
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 8c0ec78..5d1cb8a 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -43,7 +43,8 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
@@ -61,7 +62,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -319,7 +319,7 @@
                         + " (pid=" + Binder.getCallingPid()
                         + ") when starting service " + service);
             }
-            callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
         } else {
             callerFg = true;
         }
@@ -343,6 +343,25 @@
             return null;
         }
 
+        if (!r.startRequested) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Before going further -- if this app is not allowed to run in the
+                // background, then at this point we aren't going to let it period.
+                final int allowed = mAm.checkAllowBackgroundLocked(
+                        r.appInfo.uid, r.packageName, callingPid, true);
+                if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
+                    Slog.w(TAG, "Background start not allowed: service "
+                            + service + " to " + r.name.flattenToShortString()
+                            + " from pid=" + callingPid + " uid=" + callingUid
+                            + " pkg=" + callingPackage);
+                    return null;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                 callingUid, r.packageName, service, service.getFlags(), null, r.userId);
 
@@ -480,7 +499,7 @@
 
     ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
             boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
-        ProcessStats.ServiceState stracker = r.getTracker();
+        ServiceState stracker = r.getTracker();
         if (stracker != null) {
             stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
         }
@@ -811,10 +830,8 @@
             // Hacky kind of thing -- allow system stuff to tell us
             // what they are, so we can report this elsewhere for
             // others to know why certain services are running.
-            try {
-                clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT);
-            } catch (RuntimeException e) {
-            }
+            service.setDefusable(true);
+            clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT);
             if (clientIntent != null) {
                 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
                 if (clientLabel != 0) {
@@ -831,7 +848,7 @@
                     "BIND_TREAT_LIKE_ACTIVITY");
         }
 
-        final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+        final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
         final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
 
         ServiceLookupResult res =
@@ -934,7 +951,7 @@
                 s.lastActivity = SystemClock.uptimeMillis();
                 if (!s.hasAutoCreateConnections()) {
                     // This is the first binding, let the tracker know.
-                    ProcessStats.ServiceState stracker = s.getTracker();
+                    ServiceState stracker = s.getTracker();
                     if (stracker != null) {
                         stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
                                 s.lastActivity);
@@ -942,7 +959,7 @@
                 }
             }
 
-            mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
+            mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
                     s.appInfo.uid, s.name, s.processName);
 
             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
@@ -1138,7 +1155,7 @@
                         for (int i=b.apps.size()-1; i>=0; i--) {
                             ProcessRecord client = b.apps.valueAt(i).client;
                             if (client != null && client.setSchedGroup
-                                    != Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+                                    != ProcessList.SCHED_GROUP_BACKGROUND) {
                                 inFg = true;
                                 break;
                             }
@@ -1276,23 +1293,6 @@
                 }
                 r = smap.mServicesByName.get(name);
                 if (r == null && createIfNeeded) {
-                    final long token = Binder.clearCallingIdentity();
-                    try {
-                        // Before going further -- if this app is not allowed to run in the
-                        // background, then at this point we aren't going to let it period.
-                        final int allowed = mAm.checkAllowBackgroundLocked(
-                                sInfo.applicationInfo.uid, sInfo.packageName, callingPid);
-                        if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
-                            Slog.w(TAG, "Background execution not allowed: service "
-                                    + service + " to " + name.flattenToShortString()
-                                    + " from pid=" + callingPid + " uid=" + callingUid
-                                    + " pkg=" + callingPackage);
-                            return null;
-                        }
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                    }
-
                     Intent.FilterComparison filter
                             = new Intent.FilterComparison(service.cloneFilter());
                     ServiceRestarter res = new ServiceRestarter();
@@ -1367,7 +1367,7 @@
         long now = SystemClock.uptimeMillis();
         if (r.executeNesting == 0) {
             r.executeFg = fg;
-            ProcessStats.ServiceState stracker = r.getTracker();
+            ServiceState stracker = r.getTracker();
             if (stracker != null) {
                 stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 4f0d4d9..f2bf4f9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -46,6 +46,7 @@
 
     // Available log categories in the activity manager package.
     static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
+    static final boolean DEBUG_ANR = false;
     static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
     static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8c04fbc..1587516 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,8 +26,8 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
-import com.android.internal.app.ProcessStats;
 import com.android.internal.app.SystemUserHomeActivity;
+import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.IResultReceiver;
@@ -40,11 +40,13 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.MemInfoReader;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.ProgressReporter;
 import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
 import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
+import com.android.server.LockGuard;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
@@ -54,7 +56,6 @@
 import com.android.server.pm.Installer;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.vr.VrManagerInternal;
-import com.android.server.wm.AppTransition;
 import com.android.server.wm.WindowManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -62,6 +63,7 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import android.Manifest;
+import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
@@ -100,6 +102,7 @@
 import android.app.PendingIntent;
 import android.app.ProfilerInfo;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.IBackupManager;
@@ -163,6 +166,7 @@
 import android.os.IBinder;
 import android.os.IPermissionController;
 import android.os.IProcessInfoService;
+import android.os.IProgressListener;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -212,10 +216,6 @@
 import android.view.View;
 import android.view.WindowManager;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -264,7 +264,7 @@
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.GET_PROVIDERS;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -283,6 +283,7 @@
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
@@ -348,15 +349,17 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 public final class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
-    // File that stores last updated system version and called preboot receivers
-    static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
-
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
     private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
     private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
@@ -491,8 +494,6 @@
     static final int ALLOW_NON_FULL_IN_PROFILE = 1;
     static final int ALLOW_FULL_ONLY = 2;
 
-    static final int LAST_PREBOOT_DELIVERED_FILE_VERSION = 10000;
-
     // Delay in notifying task stack change listeners (in millis)
     static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
 
@@ -516,6 +517,7 @@
 
     // Determines whether to take full screen screenshots
     static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
+    public static final float FULLSCREEN_SCREENSHOT_SCALE = 0.6f;
 
     private static native int nativeMigrateToBoost();
     private static native int nativeMigrateFromBoost();
@@ -533,9 +535,11 @@
     final ActivityStarter mActivityStarter;
 
     /** Task stack change listeners. */
-    private RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
+    private final RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
             new RemoteCallbackList<ITaskStackListener>();
 
+    final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter();
+
     public IntentFirewall mIntentFirewall;
 
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
@@ -887,6 +891,12 @@
         int mNesting;
         long mStartTime;
 
+        // states of the source process when the bind occurred.
+        int mLastState = ActivityManager.MAX_PROCESS_STATE + 1;
+        long mLastStateUptime;
+        long[] mStateTimes = new long[ActivityManager.MAX_PROCESS_STATE
+                - ActivityManager.MIN_PROCESS_STATE+1];
+
         Association(int sourceUid, String sourceProcess, int targetUid,
                 ComponentName targetComponent, String targetProcess) {
             mSourceUid = sourceUid;
@@ -1095,22 +1105,20 @@
     ComponentName mTopComponent;
     String mTopAction = Intent.ACTION_MAIN;
     String mTopData;
-    boolean mProcessesReady = false;
-    boolean mSystemReady = false;
-    boolean mBooting = false;
-    boolean mCallFinishBooting = false;
-    boolean mBootAnimationComplete = false;
-    boolean mWaitingUpdate = false;
-    boolean mDidUpdate = false;
-    boolean mOnBattery = false;
-    boolean mLaunchWarningShown = false;
+
+    volatile boolean mProcessesReady = false;
+    volatile boolean mSystemReady = false;
+    volatile boolean mOnBattery = false;
+    volatile int mFactoryTest;
+
+    @GuardedBy("this") boolean mBooting = false;
+    @GuardedBy("this") boolean mCallFinishBooting = false;
+    @GuardedBy("this") boolean mBootAnimationComplete = false;
+    @GuardedBy("this") boolean mLaunchWarningShown = false;
+    @GuardedBy("this") boolean mCheckedForSetup = false;
 
     Context mContext;
 
-    int mFactoryTest;
-
-    boolean mCheckedForSetup;
-
     /**
      * The time at which we will allow normal application switches again,
      * after a call to {@link #stopAppSwitches()}.
@@ -1293,10 +1301,12 @@
     boolean mAlwaysFinishActivities = false;
     boolean mLenientBackgroundCheck = false;
     boolean mForceResizableActivities;
+    boolean mSupportsMultiWindow;
     boolean mSupportsFreeformWindowManagement;
     boolean mSupportsPictureInPicture;
     Rect mDefaultPinnedStackBounds;
     IActivityController mController = null;
+    boolean mControllerIsAMonkey = false;
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
     String mProfileFile;
@@ -1371,7 +1381,6 @@
     int mProcessLimitOverride = -1;
 
     WindowManagerService mWindowManager;
-
     final ActivityThread mSystemThread;
 
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1457,12 +1466,16 @@
     static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
     static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 65;
     static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66;
+    static final int NOTIFY_FORCED_RESIZABLE_MSG = 67;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
     static final int FIRST_COMPAT_MODE_MSG = 300;
     static final int FIRST_SUPERVISOR_STACK_MSG = 100;
 
+    static ServiceThread sKillThread = null;
+    static KillHandler sKillHandler = null;
+
     CompatModeDialog mCompatModeDialog;
     long mLastMemUsageReportTime = 0;
 
@@ -1478,14 +1491,38 @@
     /** The dimensions of the thumbnails in the Recents UI. */
     int mThumbnailWidth;
     int mThumbnailHeight;
+    float mFullscreenThumbnailScale;
 
     final ServiceThread mHandlerThread;
     final MainHandler mHandler;
     final UiHandler mUiHandler;
-    final ProcessStartLogger mProcessStartLogger;
 
     PackageManagerInternal mPackageManagerInt;
 
+    final class KillHandler extends Handler {
+        static final int KILL_PROCESS_GROUP_MSG = 4000;
+
+        public KillHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case KILL_PROCESS_GROUP_MSG:
+                {
+                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "killProcessGroup");
+                    Process.killProcessGroup(msg.arg1 /* uid */, msg.arg2 /* pid */);
+                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+                }
+                break;
+
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    }
+
     final class UiHandler extends Handler {
         public UiHandler() {
             super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -1894,7 +1931,12 @@
             case SYSTEM_USER_UNLOCK_MSG: {
                 final int userId = msg.arg1;
                 mSystemServiceManager.unlockUser(userId);
-                mRecentTasks.cleanupLocked(userId);
+                synchronized (ActivityManagerService.this) {
+                    mRecentTasks.loadUserRecentsLocked(userId);
+                }
+                if (userId == UserHandle.USER_SYSTEM) {
+                    startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+                }
                 installEncryptionUnawareProviders(userId);
                 break;
             }
@@ -1999,6 +2041,21 @@
                 }
                 break;
             }
+            case NOTIFY_FORCED_RESIZABLE_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
+                        try {
+                            // Make a one-way callback to the listener
+                            mTaskStackListeners.getBroadcastItem(i).onActivityForcedResizable(
+                                    (String) msg.obj, msg.arg1);
+                        } catch (RemoteException e){
+                            // Handled by the RemoteCallbackList
+                        }
+                    }
+                    mTaskStackListeners.finishBroadcast();
+                }
+                break;
+            }
             case NOTIFY_CLEARTEXT_NETWORK_MSG: {
                 final int uid = msg.arg1;
                 final byte[] firstPacket = (byte[]) msg.obj;
@@ -2148,15 +2205,22 @@
             } break;
             case VR_MODE_CHANGE_MSG: {
                 VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
-                final boolean vrMode = msg.arg1 != 0;
-                vrService.setVrMode(vrMode);
-
-                if (mInVrMode != vrMode) {
-                    synchronized (ActivityManagerService.this) {
+                final ActivityRecord r = (ActivityRecord) msg.obj;
+                boolean vrMode;
+                ComponentName requestedPackage;
+                ComponentName callingPackage;
+                int userId;
+                synchronized (ActivityManagerService.this) {
+                    vrMode = r.requestedVrComponent != null;
+                    requestedPackage = r.requestedVrComponent;
+                    userId = r.userId;
+                    callingPackage = r.info.getComponentName();
+                    if (mInVrMode != vrMode) {
                         mInVrMode = vrMode;
                         mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
                     }
                 }
+                vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
             } break;
             }
         }
@@ -2427,7 +2491,13 @@
         mHandler = new MainHandler(mHandlerThread.getLooper());
         mUiHandler = new UiHandler();
 
-        mProcessStartLogger = new ProcessStartLogger();
+        /* static; one-time init here */
+        if (sKillHandler == null) {
+            sKillThread = new ServiceThread(TAG + ":kill",
+                    android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+            sKillThread.start();
+            sKillHandler = new KillHandler(sKillThread.getLooper());
+        }
 
         mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                 "foreground", BROADCAST_FG_TIMEOUT, false);
@@ -2487,7 +2557,6 @@
         mActivityStarter = new ActivityStarter(this, mStackSupervisor);
         mRecentTasks = new RecentTasks(this, mStackSupervisor);
 
-
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
             public void run() {
@@ -2541,7 +2610,7 @@
     }
 
     void onUserStoppedLocked(int userId) {
-        mRecentTasks.unloadUserRecentsLocked(userId);
+        mRecentTasks.unloadUserDataFromMemoryLocked(userId);
     }
 
     public void initPowerManagement() {
@@ -2930,7 +2999,7 @@
 
     final void applyUpdateVrModeLocked(ActivityRecord r) {
         mHandler.sendMessage(
-                mHandler.obtainMessage(VR_MODE_CHANGE_MSG, (r.isVrActivity) ? 1 : 0, 0));
+                mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
     }
 
     final void showAskCompatModeDialogLocked(ActivityRecord r) {
@@ -2978,9 +3047,13 @@
     }
 
     static void killProcessGroup(int uid, int pid) {
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "killProcessGroup");
-        Process.killProcessGroup(uid, pid);
-        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+        if (sKillHandler != null) {
+            sKillHandler.sendMessage(
+                    sKillHandler.obtainMessage(KillHandler.KILL_PROCESS_GROUP_MSG, uid, pid));
+        } else {
+            Slog.w(TAG, "Asked to kill process group before system bringup!");
+            Process.killProcessGroup(uid, pid);
+        }
     }
 
     final void removeLruProcessLocked(ProcessRecord app) {
@@ -2989,7 +3062,7 @@
             if (!app.killed) {
                 Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
                 Process.killProcessQuiet(app.pid);
-                killProcessGroup(app.info.uid, app.pid);
+                killProcessGroup(app.uid, app.pid);
             }
             if (lrui <= mLruProcessActivityStart) {
                 mLruProcessActivityStart--;
@@ -3246,9 +3319,9 @@
 
     boolean isNextTransitionForward() {
         int transit = mWindowManager.getPendingAppTransition();
-        return transit == AppTransition.TRANSIT_ACTIVITY_OPEN
-                || transit == AppTransition.TRANSIT_TASK_OPEN
-                || transit == AppTransition.TRANSIT_TASK_TO_FRONT;
+        return transit == TRANSIT_ACTIVITY_OPEN
+                || transit == TRANSIT_TASK_OPEN
+                || transit == TRANSIT_TASK_TO_FRONT;
     }
 
     int startIsolatedProcess(String entryPoint, String[] entryPointArgs,
@@ -3362,7 +3435,7 @@
             // clean it up now.
             if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
             checkTime(startTime, "startProcess: bad proc running, killing");
-            killProcessGroup(app.info.uid, app.pid);
+            killProcessGroup(app.uid, app.pid);
             handleAppDiedLocked(app, true, true);
             checkTime(startTime, "startProcess: done killing old proc");
         }
@@ -3562,7 +3635,12 @@
                     app.processName, hostingType,
                     hostingNameStr != null ? hostingNameStr : "");
 
-            mProcessStartLogger.logIfNeededLocked(app, startResult);
+            try {
+                AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
+                        app.info.seinfo, app.info.sourceDir, startResult.pid);
+            } catch (RemoteException ex) {
+                // Ignore
+            }
 
             if (app.persistent) {
                 Watchdog.getInstance().processStarted(app.processName, startResult.pid);
@@ -4369,7 +4447,7 @@
                     AppGlobals.getPackageManager().queryIntentActivities(
                             intent, r.resolvedType,
                             PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS,
-                            UserHandle.getCallingUserId());
+                            UserHandle.getCallingUserId()).getList();
 
                 // Look for the original activity in the list...
                 final int N = resolves != null ? resolves.size() : 0;
@@ -4453,63 +4531,14 @@
         }
         final long origId = Binder.clearCallingIdentity();
         try {
-            return startActivityFromRecentsInner(taskId, bOptions);
+            synchronized (this) {
+                return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions);
+            }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
-    final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
-        final TaskRecord task;
-        final int callingUid;
-        final String callingPackage;
-        final Intent intent;
-        final int userId;
-        synchronized (this) {
-            final ActivityOptions activityOptions = (bOptions != null)
-                    ? new ActivityOptions(bOptions) : null;
-            final int launchStackId = (activityOptions != null)
-                    ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
-
-            if (launchStackId == HOME_STACK_ID) {
-                throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
-                        + taskId + " can't be launch in the home stack.");
-            }
-            task = mStackSupervisor.anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
-            if (task == null) {
-                throw new IllegalArgumentException(
-                        "startActivityFromRecentsInner: Task " + taskId + " not found.");
-            }
-
-            if (launchStackId != INVALID_STACK_ID) {
-                if (launchStackId == DOCKED_STACK_ID && activityOptions != null) {
-                    mWindowManager.setDockedStackCreateState(
-                            activityOptions.getDockCreateMode(), null /* initialBounds */);
-                }
-                if (task.stack.mStackId != launchStackId) {
-                    mStackSupervisor.moveTaskToStackLocked(
-                            taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
-                            ANIMATE);
-                }
-            }
-
-            // If the user must confirm credentials (e.g. when first launching a work app and the
-            // Work Challenge is present) let startActivityInPackage handle the intercepting.
-            if (!mUserController.shouldConfirmCredentials(task.userId)
-                    && task.getRootActivity() != null) {
-                moveTaskToFrontLocked(task.taskId, 0, bOptions);
-                return ActivityManager.START_TASK_TO_FRONT;
-            }
-            callingUid = task.mCallingUid;
-            callingPackage = task.mCallingPackage;
-            intent = task.intent;
-            intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
-            userId = task.userId;
-        }
-        return startActivityInPackage(callingUid, callingPackage, intent, null, null, null, 0, 0,
-                bOptions, userId, null, task);
-    }
-
     final int startActivityInPackage(int uid, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
@@ -4997,7 +5026,7 @@
             if (!fromBinderDied) {
                 Process.killProcessQuiet(pid);
             }
-            killProcessGroup(app.info.uid, pid);
+            killProcessGroup(app.uid, pid);
             app.killed = true;
         }
 
@@ -5087,8 +5116,13 @@
                     int num = firstPids.size();
                     for (int i = 0; i < num; i++) {
                         synchronized (observer) {
+                            if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
+                                    + firstPids.get(i));
+                            final long sime = SystemClock.elapsedRealtime();
                             Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
-                            observer.wait(200);  // Wait for write-close, give up after 200msec
+                            observer.wait(1000);  // Wait for write-close, give up after 1 sec
+                            if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
+                                    + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                         }
                     }
                 } catch (InterruptedException e) {
@@ -5101,7 +5135,11 @@
                 int[] pids = Process.getPidsForCommands(nativeProcs);
                 if (pids != null) {
                     for (int pid : pids) {
+                        if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
+                        final long sime = SystemClock.elapsedRealtime();
                         Debug.dumpNativeBacktraceToFile(pid, tracesPath);
+                        if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
+                                + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                     }
                 }
             }
@@ -5128,13 +5166,20 @@
                         numProcs++;
                         try {
                             synchronized (observer) {
+                                if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
+                                        + stats.pid);
+                                final long stime = SystemClock.elapsedRealtime();
                                 Process.sendSignal(stats.pid, Process.SIGNAL_QUIT);
-                                observer.wait(200);  // Wait for write-close, give up after 200msec
+                                observer.wait(1000);  // Wait for write-close, give up after 1 sec
+                                if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
+                                        + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
                             }
                         } catch (InterruptedException e) {
                             Slog.wtf(TAG, e);
                         }
-
+                    } else if (DEBUG_ANR) {
+                        Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
+                                + stats.pid);
                     }
                 }
             }
@@ -5240,13 +5285,17 @@
     public boolean clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, int userId) {
         enforceNotIsolatedCaller("clearApplicationUserData");
-        if (packageName != null && packageName.equals(mDeviceOwnerName)) {
-            throw new SecurityException("Clearing DeviceOwner data is forbidden.");
-        }
         int uid = Binder.getCallingUid();
         int pid = Binder.getCallingPid();
         userId = mUserController.handleIncomingUser(pid, uid, userId, false,
                 ALLOW_FULL_ONLY, "clearApplicationUserData", null);
+
+        final DevicePolicyManagerInternal dpmi = LocalServices
+                .getService(DevicePolicyManagerInternal.class);
+        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+            throw new SecurityException("Cannot clear data for a device owner or a profile owner");
+        }
+
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -5306,6 +5355,7 @@
                 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
                         Uri.fromParts("package", packageName, null));
                 intent.putExtra(Intent.EXTRA_UID, pkgUid);
+                intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUid));
                 broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
                         null, null, 0, null, null, null, null, false, false, userId);
             } catch (RemoteException e) {
@@ -5356,17 +5406,6 @@
 
     @Override
     public void killAllBackgroundProcesses() {
-        killAllBackgroundProcesses(-1);
-    }
-
-    /**
-     * Kills all background processes with targetSdkVersion below the specified
-     * target SDK version.
-     *
-     * @param targetSdkVersion the target SDK version below which to kill
-     *                         processes, or {@code -1} to kill all processes
-     */
-    private void killAllBackgroundProcesses(int targetSdkVersion) {
         if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
                 != PackageManager.PERMISSION_GRANTED) {
             final String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
@@ -5390,10 +5429,6 @@
                             // We don't kill persistent processes.
                             continue;
                         }
-                        if (targetSdkVersion > 0
-                                && app.info.targetSdkVersion >= targetSdkVersion) {
-                            continue;
-                        }
                         if (app.removed) {
                             procs.add(app);
                         } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
@@ -5418,6 +5453,55 @@
         }
     }
 
+    /**
+     * Kills all background processes, except those matching any of the
+     * specified properties.
+     *
+     * @param minTargetSdk the target SDK version at or above which to preserve
+     *                     processes, or {@code -1} to ignore the target SDK
+     * @param maxProcState the process state at or below which to preserve
+     *                     processes, or {@code -1} to ignore the process state
+     */
+    private void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
+        if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+                != PackageManager.PERMISSION_GRANTED) {
+            final String msg = "Permission Denial: killAllBackgroundProcessesExcept() from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final ArrayList<ProcessRecord> procs = new ArrayList<>();
+                final int NP = mProcessNames.getMap().size();
+                for (int ip = 0; ip < NP; ip++) {
+                    final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+                    final int NA = apps.size();
+                    for (int ia = 0; ia < NA; ia++) {
+                        final ProcessRecord app = apps.valueAt(ia);
+                        if (app.removed) {
+                            procs.add(app);
+                        } else if ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk)
+                                && (maxProcState < 0 || app.setProcState > maxProcState)) {
+                            app.removed = true;
+                            procs.add(app);
+                        }
+                    }
+                }
+
+                final int N = procs.size();
+                for (int i = 0; i < N; i++) {
+                    removeProcessLocked(procs.get(i), false, true, "kill all background except");
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     @Override
     public void forceStopPackage(final String packageName, int userId) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
@@ -5978,8 +6062,7 @@
                         "No more processes in " + old.uidRecord);
                 enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
                 mActiveUids.remove(uid);
-                mBatteryStatsService.noteUidProcessState(uid,
-                        ActivityManager.PROCESS_STATE_NONEXISTENT);
+                noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
             }
             old.uidRecord = null;
         }
@@ -6004,7 +6087,7 @@
             if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                     "Creating new process uid: " + uidRec);
             mActiveUids.put(proc.uid, uidRec);
-            mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+            noteUidProcessState(uidRec.uid, uidRec.curProcState);
             enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
         }
         proc.uidRecord = uidRec;
@@ -6174,13 +6257,14 @@
 
         app.makeActive(thread, mProcessStats);
         app.curAdj = app.setAdj = ProcessList.INVALID_ADJ;
-        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
+        app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
         app.forcingToForeground = null;
         updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
         app.debugging = false;
         app.cached = false;
         app.killedByAm = false;
+        app.unlocked = mContext.getSystemService(UserManager.class).isUserUnlocked(app.userId);
 
         mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
 
@@ -6232,9 +6316,10 @@
             // If the app is being launched for restore or full backup, set it up specially
             boolean isRestrictedBackupMode = false;
             if (mBackupTarget != null && mBackupAppName.equals(processName)) {
-                isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
-                        || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
-                        || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
+                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
+                        && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
+                                || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
+                                || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
             notifyPackageUse(app.instrumentationInfo != null
@@ -6420,15 +6505,13 @@
     }
 
     @Override
-    public void keyguardGoingAway(boolean disableWindowAnimations,
-            boolean keyguardGoingToNotificationShade) {
+    public void keyguardGoingAway(int flags) {
         enforceNotIsolatedCaller("keyguardGoingAway");
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
                 if (DEBUG_LOCKSCREEN) logLockScreen("");
-                mWindowManager.keyguardGoingAway(disableWindowAnimations,
-                        keyguardGoingToNotificationShade);
+                mWindowManager.keyguardGoingAway(flags);
                 if (mLockScreenShown == LOCK_SCREEN_SHOWN) {
                     mLockScreenShown = LOCK_SCREEN_HIDDEN;
                     updateSleepIfNeededLocked();
@@ -6499,8 +6582,6 @@
             }
         }, dumpheapFilter);
 
-        mProcessStartLogger.registerListener(mContext);
-
         // Let system services know.
         mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -6588,7 +6669,7 @@
         synchronized(this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
-                ActivityRecord.activityResumedLocked(token);
+                stack.activityResumedLocked(token);
             }
         }
         Binder.restoreCallingIdentity(origId);
@@ -6838,6 +6919,15 @@
             }
         }
 
+        // We're going to be splicing together extras before sending, so we're
+        // okay poking into any contained extras.
+        if (intents != null) {
+            for (int i = 0; i < intents.length; i++) {
+                intents[i].setDefusable(true);
+            }
+        }
+        Bundle.setDefusable(bOptions, true);
+
         final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
         final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
         final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
@@ -6985,6 +7075,8 @@
 
     @Override
     public Intent getIntentForIntentSender(IIntentSender pendingResult) {
+        enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
+                "getIntentForIntentSender()");
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return null;
         }
@@ -7133,8 +7225,17 @@
         }
     }
 
+    // NOTE: this is an internal method used by the OnShellCommand implementation only and should
+    // be guarded by permission checking.
+    int getUidState(int uid) {
+        synchronized (this) {
+            UidRecord uidRec = mActiveUids.get(uid);
+            return uidRec == null ? ActivityManager.PROCESS_STATE_NONEXISTENT : uidRec.curProcState;
+        }
+    }
+
     @Override
-    public boolean inMultiWindow(IBinder token) {
+    public boolean isInMultiWindowMode(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
@@ -7151,7 +7252,7 @@
     }
 
     @Override
-    public boolean inPictureInPicture(IBinder token) {
+    public boolean isInPictureInPictureMode(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
@@ -7167,24 +7268,24 @@
     }
 
     @Override
-    public void enterPictureInPicture(IBinder token) {
+    public void enterPictureInPictureMode(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
                 if (!mSupportsPictureInPicture) {
-                    throw new IllegalStateException("enterPictureInPicture: "
+                    throw new IllegalStateException("enterPictureInPictureMode: "
                             + "Device doesn't support picture-in-picture mode.");
                 }
 
                 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
 
                 if (r == null) {
-                    throw new IllegalStateException("enterPictureInPicture: "
+                    throw new IllegalStateException("enterPictureInPictureMode: "
                             + "Can't find activity for token=" + token);
                 }
 
                 if (!r.supportsPictureInPicture()) {
-                    throw new IllegalArgumentException("enterPictureInPicture: "
+                    throw new IllegalArgumentException("enterPictureInPictureMode: "
                             + "Picture-In-Picture not supported for r=" + r);
                 }
 
@@ -7193,7 +7294,7 @@
                         ? mDefaultPinnedStackBounds : null;
 
                 mStackSupervisor.moveActivityToPinnedStackLocked(
-                        r, "enterPictureInPicture", bounds);
+                        r, "enterPictureInPictureMode", bounds);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -7486,14 +7587,15 @@
 
     public int getAppStartMode(int uid, String packageName) {
         synchronized (this) {
-            return checkAllowBackgroundLocked(uid, packageName, -1);
+            return checkAllowBackgroundLocked(uid, packageName, -1, true);
         }
     }
 
-    int checkAllowBackgroundLocked(int uid, String packageName, int callingPid) {
+    int checkAllowBackgroundLocked(int uid, String packageName, int callingPid,
+            boolean allowWhenForeground) {
         UidRecord uidRec = mActiveUids.get(uid);
         if (!mLenientBackgroundCheck) {
-            if (uidRec == null
+            if (!allowWhenForeground || uidRec == null
                     || uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
                 if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
                         packageName) != AppOpsManager.MODE_ALLOWED) {
@@ -8739,6 +8841,10 @@
                     android.Manifest.permission.GET_DETAILED_TASKS)
                     == PackageManager.PERMISSION_GRANTED;
 
+            if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
+                Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
+                return Collections.emptyList();
+            }
             mRecentTasks.loadUserRecentsLocked(userId);
 
             final int recentsCount = mRecentTasks.size();
@@ -8792,10 +8898,11 @@
                             continue;
                         }
                     }
-                    if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS) != 0) {
-                        if (tr.stack != null && tr.stack.isDockedStack()) {
+                    if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
+                        final ActivityStack stack = tr.stack;
+                        if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {
                             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                    "Skipping, docked stack task: " + tr);
+                                    "Skipping, top task in docked stack: " + tr);
                             continue;
                         }
                     }
@@ -9025,7 +9132,8 @@
                     preserveWindow = false;
                 }
 
-                mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode, preserveWindow);
+                mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode, preserveWindow,
+                        false /* deferResume */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -9090,7 +9198,7 @@
             throw new IllegalArgumentException("Expected in-place ActivityOption " +
                     "with valid animation");
         }
-        mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_IN_PLACE, false);
+        mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
         mWindowManager.overridePendingAppTransitionInPlace(opts.getPackageName(),
                 opts.getCustomInPlaceResId());
         mWindowManager.executeAppTransition();
@@ -9159,7 +9267,7 @@
         // Kill the running processes.
         for (int i = 0; i < procsToKill.size(); i++) {
             ProcessRecord pr = procsToKill.get(i);
-            if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+            if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                     && pr.curReceiver == null) {
                 pr.kill("remove task", true);
             } else {
@@ -9469,6 +9577,55 @@
         }
     }
 
+    @Override
+    public void swapDockedAndFullscreenStack() throws RemoteException {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "swapDockedAndFullscreenStack()");
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                final ActivityStack fullscreenStack = mStackSupervisor.getStack(
+                        FULLSCREEN_WORKSPACE_STACK_ID);
+                final TaskRecord topTask = fullscreenStack != null ? fullscreenStack.topTask()
+                        : null;
+                final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
+                final ArrayList<TaskRecord> tasks = dockedStack != null ? dockedStack.getAllTasks()
+                        : null;
+                if (topTask == null || tasks == null || tasks.size() == 0) {
+                    Slog.w(TAG,
+                            "Unable to swap tasks, either docked or fullscreen stack is empty.");
+                    return;
+                }
+
+                // TODO: App transition
+                mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_RELAUNCH, false);
+
+                // Defer the resume so resume/pausing while moving stacks is dangerous.
+                mStackSupervisor.moveTaskToStackLocked(topTask.taskId, DOCKED_STACK_ID,
+                        false /* toTop */, !FORCE_FOCUS, "swapDockedAndFullscreenStack",
+                        ANIMATE, true /* deferResume */);
+                final int size = tasks.size();
+                for (int i = 0; i < size; i++) {
+                    final int id = tasks.get(i).taskId;
+                    if (id == topTask.taskId) {
+                        continue;
+                    }
+                    mStackSupervisor.moveTaskToStackLocked(id,
+                            FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */, !FORCE_FOCUS,
+                            "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */);
+                }
+
+                // Because we deferred the resume, to avoid conflicts with stack switches while
+                // resuming, we need to do it after all the tasks are moved.
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
+
+                mWindowManager.executeAppTransition();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
     /**
      * Moves the input task to the docked stack.
      *
@@ -9484,7 +9641,7 @@
      *                      docked stack. Pass {@code null} to use default bounds.
      */
     @Override
-    public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
         synchronized (this) {
@@ -9493,7 +9650,8 @@
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId
                         + " to createMode=" + createMode + " toTop=" + toTop);
                 mWindowManager.setDockedStackCreateState(createMode, initialBounds);
-                mStackSupervisor.moveTaskToStackLocked(taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS,
+                return mStackSupervisor.moveTaskToStackLocked(
+                        taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS,
                         "moveTaskToDockedStack", animate);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -9530,14 +9688,14 @@
 
     @Override
     public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
-            boolean preserveWindows, boolean animate) {
+            boolean preserveWindows, boolean animate, int animationDuration) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
                 if (animate) {
                     if (stackId == PINNED_STACK_ID) {
-                        mWindowManager.animateResizePinnedStack(bounds);
+                        mWindowManager.animateResizePinnedStack(bounds, animationDuration);
                     } else {
                         throw new IllegalArgumentException("Stack: " + stackId
                                 + " doesn't support animated resize.");
@@ -9572,6 +9730,20 @@
     }
 
     @Override
+    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "resizePinnedStack()");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                mStackSupervisor.resizePinnedStackLocked(pinnedBounds, tempPinnedTaskBounds);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public void positionTaskInStack(int taskId, int stackId, int position) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
         if (stackId == HOME_STACK_ID) {
@@ -9655,7 +9827,8 @@
     public void updateLockTaskPackages(int userId, String[] packages) {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
-            throw new SecurityException("updateLockTaskPackage called from non-system process");
+            enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+                    "updateLockTaskPackages()");
         }
         synchronized (this) {
             if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
@@ -9825,11 +9998,11 @@
     private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
         List<ProviderInfo> providers = null;
         try {
-            ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager()
+            providers = AppGlobals.getPackageManager()
                     .queryContentProviders(app.processName, app.uid,
                             STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
-                                    | MATCH_DEBUG_TRIAGED_MISSING);
-            providers = slice != null ? slice.getList() : null;
+                                    | MATCH_DEBUG_TRIAGED_MISSING)
+                    .getList();
         } catch (RemoteException ex) {
         }
         if (DEBUG_MU) Slog.v(TAG_MU,
@@ -10023,7 +10196,8 @@
             }
             cpr.connections.add(conn);
             r.conProviders.add(conn);
-            startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);
+            startAssociationLocked(r.uid, r.processName, r.curProcState,
+                    cpr.uid, cpr.name, cpr.info.processName);
             return conn;
         }
         cpr.addExternalProcessHandleLocked(externalProcessToken);
@@ -10225,7 +10399,7 @@
                 }
                 checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
 
-                if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
+                if (!mProcessesReady
                         && !cpi.processName.equals("system")) {
                     // If this content provider does not run in the system
                     // process, and the system is not yet ready to run other
@@ -10419,7 +10593,7 @@
                 cpi.packageName, r.userId)) {
 
             final boolean callerForeground = r != null ? r.setSchedGroup
-                    != Process.THREAD_GROUP_BG_NONINTERACTIVE : true;
+                    != ProcessList.SCHED_GROUP_BACKGROUND : true;
 
             // Show a permission review UI only for starting from a foreground app
             if (!callerForeground) {
@@ -10739,12 +10913,13 @@
             return;
         }
 
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mAppErrors.appNotResponding(host, null, null, false, "ContentProvider not responding");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppErrors.appNotResponding(host, null, null, false,
+                        "ContentProvider not responding");
+            }
+        });
     }
 
     public final void installSystemProviders() {
@@ -10773,12 +10948,29 @@
         //mUsageStatsService.monitorPackages();
     }
 
+    private void startPersistentApps(int matchFlags) {
+        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
+
+        synchronized (this) {
+            try {
+                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
+                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
+                for (ApplicationInfo app : apps) {
+                    if (!"android".equals(app.packageName)) {
+                        addAppLocked(app, false, null /* ABI override */);
+                    }
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
     /**
      * When a user is unlocked, we need to install encryption-unaware providers
      * belonging to any running apps.
      */
     private void installEncryptionUnawareProviders(int userId) {
-        if (!StorageManager.isFileBasedEncryptionEnabled()) {
+        if (!StorageManager.isFileEncryptedNativeOrEmulated()) {
             // TODO: eventually pivot this back to look at current user state,
             // similar to the comment in UserManager.isUserUnlocked(), but for
             // now, if we started apps when "unlocked" then unaware providers
@@ -10789,8 +10981,7 @@
         // We're only interested in providers that are encryption unaware, and
         // we don't care about uninstalled apps, since there's no way they're
         // running at this point.
-        final int matchFlags = GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE
-                | MATCH_DEBUG_TRIAGED_MISSING;
+        final int matchFlags = GET_PROVIDERS | MATCH_DIRECT_BOOT_UNAWARE;
 
         synchronized (this) {
             final int NP = mProcessNames.getMap().size();
@@ -10799,7 +10990,7 @@
                 final int NA = apps.size();
                 for (int ia = 0; ia < NA; ia++) {
                     final ProcessRecord app = apps.valueAt(ia);
-                    if (app.userId != userId || app.thread == null) continue;
+                    if (app.userId != userId || app.thread == null || app.unlocked) continue;
 
                     final int NG = app.pkgList.size();
                     for (int ig = 0; ig < NG; ig++) {
@@ -11033,7 +11224,6 @@
     }
 
     void finishRunningVoiceLocked() {
-        Slog.d(TAG, "finishRunningVoiceLocked()  >>>>");
         if (mRunningVoice != null) {
             mRunningVoice = null;
             mVoiceWakeLock.release();
@@ -11220,13 +11410,9 @@
                     + android.Manifest.permission.DEVICE_POWER);
         }
 
-        final int user = UserHandle.myUserId();
         synchronized(this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (!shown && mStackSupervisor.isFocusedUserLockedProfile()) {
-                    startHomeActivityLocked(user, "setLockScreenShown");
-                }
                 if (DEBUG_LOCKSCREEN) logLockScreen(" shown=" + shown);
                 mLockScreenShown = shown ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN;
                 updateSleepIfNeededLocked();
@@ -11237,6 +11423,42 @@
     }
 
     @Override
+    public void notifyLockedProfile(@UserIdInt int userId) {
+        try {
+            if (!AppGlobals.getPackageManager().isUidPrivileged(Binder.getCallingUid())) {
+                throw new SecurityException("Only privileged app can call notifyLockedProfile");
+            }
+        } catch (RemoteException ex) {
+            throw new SecurityException("Fail to check is caller a privileged app", ex);
+        }
+
+        synchronized (this) {
+            if (mStackSupervisor.isFocusedUserLockedProfile()) {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    final int currentUserId = mUserController.getCurrentUserIdLocked();
+                    // Get the focused task before launching launcher.
+
+                    if (mUserController.isLockScreenDisabled(currentUserId)) {
+
+                        // If there is no device lock, we will show the profile's credential page.
+                        // startActivityFromRecentsInner is intercepted and will forward user to it.
+                        if (mFocusedActivity != null) {
+                            mStackSupervisor.startActivityFromRecentsInner(
+                                    mFocusedActivity.task.taskId, null);
+                        }
+                    } else {
+                        // Showing launcher to avoid user entering credential twice.
+                        startHomeActivityLocked(currentUserId, "notifyLockedProfile");
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+
+    @Override
     public void stopAppSwitches() {
         if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -11421,11 +11643,12 @@
     }
 
     @Override
-    public void setActivityController(IActivityController controller) {
+    public void setActivityController(IActivityController controller, boolean imAMonkey) {
         enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "setActivityController()");
         synchronized (this) {
             mController = controller;
+            mControllerIsAMonkey = imAMonkey;
             Watchdog.getInstance().setActivityController(controller);
         }
     }
@@ -11452,7 +11675,7 @@
     public boolean isUserAMonkey() {
         synchronized (this) {
             // If there is a controller also implies the user is a monkey.
-            return (mUserIsMonkey || mController != null);
+            return (mUserIsMonkey || (mController != null && mControllerIsAMonkey));
         }
     }
 
@@ -11929,25 +12152,51 @@
     }
 
     @Override
-    public void setVrMode(IBinder token, boolean enabled) {
+    public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
             throw new UnsupportedOperationException("VR mode not supported on this device!");
         }
 
+        final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+
+        ActivityRecord r;
+        synchronized (this) {
+            r = ActivityRecord.isInStackLocked(token);
+        }
+
+        if (r == null) {
+            throw new IllegalArgumentException();
+        }
+
+        int err;
+        if ((err = vrService.hasVrPackage(packageName, r.userId)) !=
+                VrManagerInternal.NO_ERROR) {
+            return err;
+        }
+
         synchronized(this) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                throw new IllegalArgumentException();
-            }
-            r.isVrActivity = enabled;
+            r.requestedVrComponent = (enabled) ? packageName : null;
 
             // Update associated state if this activity is currently focused
             if (r == mFocusedActivity) {
                 applyUpdateVrModeLocked(r);
             }
+            return 0;
         }
     }
 
+    @Override
+    public boolean isVrModePackageEnabled(ComponentName packageName) {
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+            throw new UnsupportedOperationException("VR mode not supported on this device!");
+        }
+
+        final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+
+        return vrService.hasVrPackage(packageName, UserHandle.getCallingUserId()) ==
+                VrManagerInternal.NO_ERROR;
+    }
+
     public boolean isTopActivityImmersive() {
         enforceNotIsolatedCaller("startActivity");
         synchronized (this) {
@@ -12287,10 +12536,11 @@
                                     + " from " + proc.initialIdlePss + ")", true);
                         }
                     }
-                } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) {
+                } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME
+                        && proc.setProcState > ActivityManager.PROCESS_STATE_NONEXISTENT) {
                     proc.notCachedSinceIdle = true;
                     proc.initialIdlePss = 0;
-                    proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true,
+                    proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true,
                             mTestPssMode, isSleeping(), now);
                 }
             }
@@ -12309,6 +12559,7 @@
         final boolean supportsPictureInPicture =
                 mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
 
+        final boolean supportsMultiWindow = ActivityManager.supportsMultiWindow();
         final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
         final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
         final boolean alwaysFinishActivities =
@@ -12335,8 +12586,15 @@
             mLenientBackgroundCheck = lenientBackgroundCheck;
             mForceResizableActivities = forceResizable;
             mWindowManager.setForceResizableTasks(mForceResizableActivities);
-            mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
-            mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
+            if (supportsMultiWindow || forceResizable) {
+                mSupportsMultiWindow = true;
+                mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
+                mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
+            } else {
+                mSupportsMultiWindow = false;
+                mSupportsFreeformWindowManagement = false;
+                mSupportsPictureInPicture = false;
+            }
             // This happens before any activities are started, so we can
             // change mConfiguration in-place.
             updateConfigurationLocked(configuration, null, true);
@@ -12350,6 +12608,8 @@
                     com.android.internal.R.dimen.thumbnail_width);
             mThumbnailHeight = res.getDimensionPixelSize(
                     com.android.internal.R.dimen.thumbnail_height);
+            mFullscreenThumbnailScale = res.getFraction(
+                    com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
             mDefaultPinnedStackBounds = Rect.unflattenFromString(res.getString(
                     com.android.internal.R.string.config_defaultPictureInPictureBounds));
             mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
@@ -12362,187 +12622,6 @@
         return mSystemReady;
     }
 
-    private static File getCalledPreBootReceiversFile() {
-        File dataDir = Environment.getDataDirectory();
-        File systemDir = new File(dataDir, "system");
-        File fname = new File(systemDir, CALLED_PRE_BOOTS_FILENAME);
-        return fname;
-    }
-
-    private static ArrayList<ComponentName> readLastDonePreBootReceivers() {
-        ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>();
-        File file = getCalledPreBootReceiversFile();
-        FileInputStream fis = null;
-        try {
-            fis = new FileInputStream(file);
-            DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048));
-            int fvers = dis.readInt();
-            if (fvers == LAST_PREBOOT_DELIVERED_FILE_VERSION) {
-                String vers = dis.readUTF();
-                String codename = dis.readUTF();
-                String build = dis.readUTF();
-                if (android.os.Build.VERSION.RELEASE.equals(vers)
-                        && android.os.Build.VERSION.CODENAME.equals(codename)
-                        && android.os.Build.VERSION.INCREMENTAL.equals(build)) {
-                    int num = dis.readInt();
-                    while (num > 0) {
-                        num--;
-                        String pkg = dis.readUTF();
-                        String cls = dis.readUTF();
-                        lastDoneReceivers.add(new ComponentName(pkg, cls));
-                    }
-                }
-            }
-        } catch (FileNotFoundException e) {
-        } catch (IOException e) {
-            Slog.w(TAG, "Failure reading last done pre-boot receivers", e);
-        } finally {
-            if (fis != null) {
-                try {
-                    fis.close();
-                } catch (IOException e) {
-                }
-            }
-        }
-        return lastDoneReceivers;
-    }
-
-    private static void writeLastDonePreBootReceivers(ArrayList<ComponentName> list) {
-        File file = getCalledPreBootReceiversFile();
-        FileOutputStream fos = null;
-        DataOutputStream dos = null;
-        try {
-            fos = new FileOutputStream(file);
-            dos = new DataOutputStream(new BufferedOutputStream(fos, 2048));
-            dos.writeInt(LAST_PREBOOT_DELIVERED_FILE_VERSION);
-            dos.writeUTF(android.os.Build.VERSION.RELEASE);
-            dos.writeUTF(android.os.Build.VERSION.CODENAME);
-            dos.writeUTF(android.os.Build.VERSION.INCREMENTAL);
-            dos.writeInt(list.size());
-            for (int i=0; i<list.size(); i++) {
-                dos.writeUTF(list.get(i).getPackageName());
-                dos.writeUTF(list.get(i).getClassName());
-            }
-        } catch (IOException e) {
-            Slog.w(TAG, "Failure writing last done pre-boot receivers", e);
-            file.delete();
-        } finally {
-            FileUtils.sync(fos);
-            if (dos != null) {
-                try {
-                    dos.close();
-                } catch (IOException e) {
-                    // TODO Auto-generated catch block
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
-    final class PreBootContinuation extends IIntentReceiver.Stub {
-        final Intent intent;
-        final Runnable onFinishCallback;
-        final ArrayList<ComponentName> doneReceivers;
-        final List<ResolveInfo> ris;
-        final int[] users;
-        int lastRi = -1;
-        int curRi = 0;
-        int curUser = 0;
-
-        PreBootContinuation(Intent _intent, Runnable _onFinishCallback,
-                ArrayList<ComponentName> _doneReceivers, List<ResolveInfo> _ris, int[] _users) {
-            intent = _intent;
-            onFinishCallback = _onFinishCallback;
-            doneReceivers = _doneReceivers;
-            ris = _ris;
-            users = _users;
-        }
-
-        void go() {
-            if (lastRi != curRi) {
-                ActivityInfo ai = ris.get(curRi).activityInfo;
-                ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                intent.setComponent(comp);
-                doneReceivers.add(comp);
-                lastRi = curRi;
-                CharSequence label = ai.loadLabel(mContext.getPackageManager());
-                showBootMessage(mContext.getString(R.string.android_preparing_apk, label), false);
-            }
-            Slog.i(TAG, "Pre-boot of " + intent.getComponent().toShortString()
-                    + " for user " + users[curUser]);
-            EventLogTags.writeAmPreBoot(users[curUser], intent.getComponent().getPackageName());
-            broadcastIntentLocked(null, null, intent, null, this,
-                    0, null, null, null, AppOpsManager.OP_NONE,
-                    null, true, false, MY_PID, Process.SYSTEM_UID, users[curUser]);
-        }
-
-        public void performReceive(Intent intent, int resultCode,
-                String data, Bundle extras, boolean ordered,
-                boolean sticky, int sendingUser) {
-            curUser++;
-            if (curUser >= users.length) {
-                curUser = 0;
-                curRi++;
-                if (curRi >= ris.size()) {
-                    // All done sending broadcasts!
-                    if (onFinishCallback != null) {
-                        // The raw IIntentReceiver interface is called
-                        // with the AM lock held, so redispatch to
-                        // execute our code without the lock.
-                        mHandler.post(onFinishCallback);
-                    }
-                    return;
-                }
-            }
-            go();
-        }
-    }
-
-    private boolean deliverPreBootCompleted(final Runnable onFinishCallback,
-            ArrayList<ComponentName> doneReceivers) {
-        Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
-        List<ResolveInfo> ris = null;
-        try {
-            ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                    intent, null, MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
-        } catch (RemoteException e) {
-        }
-        if (ris == null) {
-            return false;
-        }
-        intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE | Intent.FLAG_DEBUG_TRIAGED_MISSING);
-
-        ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
-        for (int i=0; i<ris.size(); i++) {
-            ActivityInfo ai = ris.get(i).activityInfo;
-            ComponentName comp = new ComponentName(ai.packageName, ai.name);
-            if (lastDoneReceivers.contains(comp)) {
-                // We already did the pre boot receiver for this app with the current
-                // platform version, so don't do it again...
-                ris.remove(i);
-                i--;
-                // ...however, do keep it as one that has been done, so we don't
-                // forget about it when rewriting the file of last done receivers.
-                doneReceivers.add(comp);
-            }
-        }
-
-        if (ris.size() <= 0) {
-            return false;
-        }
-
-        // TODO: can we still do this with per user encryption?
-        final int[] users = mUserController.getUsers();
-        if (users.length <= 0) {
-            return false;
-        }
-
-        PreBootContinuation cont = new PreBootContinuation(intent, onFinishCallback, doneReceivers,
-                ris, users);
-        cont.go();
-        return true;
-    }
-
     public void systemReady(final Runnable goingCallback) {
         synchronized(this) {
             if (mSystemReady) {
@@ -12559,33 +12638,7 @@
 
             // Make sure we have the current profile info, since it is needed for security checks.
             mUserController.onSystemReady();
-
-            mRecentTasks.onSystemReady();
-            // Check to see if there are any update receivers to run.
-            if (!mDidUpdate) {
-                if (mWaitingUpdate) {
-                    return;
-                }
-                final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
-                mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
-                    public void run() {
-                        synchronized (ActivityManagerService.this) {
-                            mDidUpdate = true;
-                        }
-                        showBootMessage(mContext.getText(
-                                R.string.android_upgrading_complete),
-                                false);
-                        writeLastDonePreBootReceivers(doneReceivers);
-                        systemReady(goingCallback);
-                    }
-                }, doneReceivers);
-
-                if (mWaitingUpdate) {
-                    return;
-                }
-                mDidUpdate = true;
-            }
-
+            mRecentTasks.onSystemReadyLocked();
             mAppOpsService.systemReady();
             mSystemReady = true;
         }
@@ -12674,26 +12727,9 @@
         mSystemServiceManager.startUser(currentUserId);
 
         synchronized (this) {
-            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
-                try {
-                    List apps = AppGlobals.getPackageManager().
-                        getPersistentApplications(STOCK_PM_FLAGS);
-                    if (apps != null) {
-                        int N = apps.size();
-                        int i;
-                        for (i=0; i<N; i++) {
-                            ApplicationInfo info
-                                = (ApplicationInfo)apps.get(i);
-                            if (info != null &&
-                                    !info.packageName.equals("android")) {
-                                addAppLocked(info, false, null /* ABI override */);
-                            }
-                        }
-                    }
-                } catch (RemoteException ex) {
-                    // pm is in same process, this will never happen.
-                }
-            }
+            // Only start up encryption-aware persistent apps; once user is
+            // unlocked we'll come back around and start unaware apps
+            startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
 
             // Start up initial activity.
             mBooting = true;
@@ -12705,7 +12741,7 @@
                             PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
                             UserHandle.USER_SYSTEM);
                 } catch (RemoteException e) {
-                    e.rethrowAsRuntimeException();
+                    throw e.rethrowAsRuntimeException();
                 }
             }
             startHomeActivityLocked(currentUserId, "systemReady");
@@ -13191,10 +13227,11 @@
                     // Merge several logcat streams, and take the last N lines
                     InputStreamReader input = null;
                     try {
-                        java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
-                                "-v", "time", "-b", "events", "-b", "system", "-b", "main",
-                                "-b", "crash",
-                                "-t", String.valueOf(lines)).redirectErrorStream(true).start();
+                        java.lang.Process logcat = new ProcessBuilder(
+                                "/system/bin/timeout", "-k", "15s", "10s",
+                                "/system/bin/logcat", "-v", "time", "-b", "events", "-b", "system",
+                                "-b", "main", "-b", "crash", "-t", String.valueOf(lines))
+                                        .redirectErrorStream(true).start();
 
                         try { logcat.getOutputStream().close(); } catch (IOException e) {}
                         try { logcat.getErrorStream().close(); } catch (IOException e) {}
@@ -13223,6 +13260,7 @@
         }
     }
 
+    @Override
     public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
         enforceNotIsolatedCaller("getProcessesInErrorState");
         // assume our apps are happy - lazy create the list
@@ -13299,6 +13337,7 @@
         outInfo.processState = app.curProcState;
     }
 
+    @Override
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
         enforceNotIsolatedCaller("getRunningAppProcesses");
 
@@ -13350,6 +13389,7 @@
         return runList;
     }
 
+    @Override
     public List<ApplicationInfo> getRunningExternalApplications() {
         enforceNotIsolatedCaller("getRunningExternalApplications");
         List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
@@ -13390,6 +13430,14 @@
     }
 
     @Override
+    public int getMemoryTrimLevel() {
+        enforceNotIsolatedCaller("getMyMemoryState");
+        synchronized (this) {
+            return mLastMemoryLevel;
+        }
+    }
+
+    @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
         (new ActivityManagerShellCommand(this, false)).exec(
@@ -13570,6 +13618,8 @@
                 synchronized (this) {
                     mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
                 }
+            } else if ("locks".equals(cmd)) {
+                LockGuard.dump(fd, pw, args);
             } else {
                 // Dumping a single activity?
                 if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
@@ -13755,10 +13805,27 @@
                         TimeUtils.formatDuration(dur, pw);
                         pw.print(" (");
                         pw.print(ass.mCount);
-                        pw.println(" times)");
+                        pw.print(" times)");
+                        pw.print("  ");
+                        for (int i=0; i<ass.mStateTimes.length; i++) {
+                            long amt = ass.mStateTimes[i];
+                            if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+                                amt += now - ass.mLastStateUptime;
+                            }
+                            if (amt != 0) {
+                                pw.print(" ");
+                                pw.print(ProcessList.makeProcStateString(
+                                            i + ActivityManager.MIN_PROCESS_STATE));
+                                pw.print("=");
+                                TimeUtils.formatDuration(amt, pw);
+                                if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+                                    pw.print("*");
+                                }
+                            }
+                        }
+                        pw.println();
                         if (ass.mNesting > 0) {
-                            pw.print("    ");
-                            pw.print(" Currently active: ");
+                            pw.print("    Currently active: ");
                             TimeUtils.formatDuration(now - ass.mStartTime, pw);
                             pw.println();
                         }
@@ -14112,10 +14179,13 @@
             }
         }
         if (dumpPackage == null) {
-            if (mAlwaysFinishActivities || mLenientBackgroundCheck || mController != null) {
+            if (mAlwaysFinishActivities || mLenientBackgroundCheck) {
                 pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities
-                        + " mLenientBackgroundCheck=" + mLenientBackgroundCheck
-                        + " mController=" + mController);
+                        + " mLenientBackgroundCheck=" + mLenientBackgroundCheck);
+            }
+            if (mController != null) {
+                pw.println("  mController=" + mController
+                        + " mControllerIsAMonkey=" + mControllerIsAMonkey);
             }
             if (dumpAll) {
                 pw.println("  Total persistent processes: " + numPers);
@@ -14713,13 +14783,13 @@
             String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
             char schedGroup;
             switch (r.setSchedGroup) {
-                case Process.THREAD_GROUP_BG_NONINTERACTIVE:
+                case ProcessList.SCHED_GROUP_BACKGROUND:
                     schedGroup = 'B';
                     break;
-                case Process.THREAD_GROUP_DEFAULT:
+                case ProcessList.SCHED_GROUP_DEFAULT:
                     schedGroup = 'F';
                     break;
-                case Process.THREAD_GROUP_TOP_APP:
+                case ProcessList.SCHED_GROUP_TOP_APP:
                     schedGroup = 'T';
                     break;
                 default:
@@ -15139,6 +15209,7 @@
         boolean dumpFullDetails = false;
         boolean dumpDalvik = false;
         boolean dumpSummaryOnly = false;
+        boolean dumpUnreachable = false;
         boolean oomOnly = false;
         boolean isCompact = false;
         boolean localOnly = false;
@@ -15167,6 +15238,8 @@
                 dumpSummaryOnly = true;
             } else if ("-S".equals(opt)) {
                 dumpSwapPss = true;
+            } else if ("--unreachable".equals(opt)) {
+                dumpUnreachable = true;
             } else if ("--oom".equals(opt)) {
                 oomOnly = true;
             } else if ("--local".equals(opt)) {
@@ -15328,7 +15401,7 @@
                         try {
                             pw.flush();
                             thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
-                                    dumpDalvik, dumpSummaryOnly, innerArgs);
+                                    dumpDalvik, dumpSummaryOnly, dumpUnreachable, innerArgs);
                         } catch (RemoteException e) {
                             if (!isCheckinRequest) {
                                 pw.println("Got RemoteException!");
@@ -15384,8 +15457,9 @@
                     }
 
                     for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
-                        if (oomAdj <= DUMP_MEM_OOM_ADJ[oomIndex]
-                                || oomIndex == (oomPss.length-1)) {
+                        if (oomIndex == (oomPss.length - 1)
+                                || (oomAdj >= DUMP_MEM_OOM_ADJ[oomIndex]
+                                        && oomAdj < DUMP_MEM_OOM_ADJ[oomIndex + 1])) {
                             oomPss[oomIndex] += myTotalPss;
                             oomSwapPss[oomIndex] += myTotalSwapPss;
                             if (oomProcs[oomIndex] == null) {
@@ -16854,7 +16928,7 @@
                     continue;
                 }
                 List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
-                        .queryIntentReceivers(intent, resolvedType, pmFlags, user);
+                        .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
                 if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
                     // If this is not the system user, we need to check for
                     // any receivers that should be filtered out.
@@ -17124,10 +17198,11 @@
                             String ssp;
                             if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                                 boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
-                                boolean fullUninstall = removed &&
-                                        !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+                                final boolean replacing =
+                                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                                 final boolean killProcess =
                                         !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
+                                final boolean fullUninstall = removed && !replacing;
                                 if (killProcess) {
                                     forceStopPackageLocked(ssp, UserHandle.getAppId(
                                             intent.getIntExtra(Intent.EXTRA_UID, -1)),
@@ -17135,7 +17210,10 @@
                                             removed ? "pkg removed" : "pkg changed");
                                 }
                                 if (removed) {
-                                    sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
+                                    final int cmd = killProcess
+                                            ? IApplicationThread.PACKAGE_REMOVED
+                                            : IApplicationThread.PACKAGE_REMOVED_DONT_KILL;
+                                    sendPackageBroadcastLocked(cmd,
                                             new String[] {ssp}, userId);
                                     if (fullUninstall) {
                                         mAppOpsService.packageRemoved(
@@ -17170,7 +17248,23 @@
                             break;
                     }
                     break;
+                case Intent.ACTION_PACKAGE_REPLACED:
+                {
+                    final Uri data = intent.getData();
+                    final String ssp;
+                    if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
+                        final ApplicationInfo aInfo =
+                                getPackageManagerInternalLocked().getApplicationInfo(
+                                        ssp,
+                                        userId);
+                        mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
+                        sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REPLACED,
+                                new String[] {ssp}, userId);
+                    }
+                    break;
+                }
                 case Intent.ACTION_PACKAGE_ADDED:
+                {
                     // Special case for adding a package: by default turn on compatibility mode.
                     Uri data = intent.getData();
                     String ssp;
@@ -17188,6 +17282,7 @@
                         }
                     }
                     break;
+                }
                 case Intent.ACTION_TIMEZONE_CHANGED:
                     // If this is the time zone changed action, queue up a message that will reset
                     // the timezone of all currently running processes. This message will get
@@ -17212,6 +17307,15 @@
                     ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
                     mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
                     break;
+                case android.hardware.Camera.ACTION_NEW_PICTURE:
+                case android.hardware.Camera.ACTION_NEW_VIDEO:
+                    // These broadcasts are no longer allowed by the system, since they can
+                    // cause significant thrashing at a crictical point (using the camera).
+                    // Apps should use JobScehduler to monitor for media provider changes.
+                    Slog.w(TAG, action + " no longer allowed; dropping from "
+                            + UserHandle.formatUid(callingUid));
+                    // Lie; we don't want to crash the app.
+                    return ActivityManager.BROADCAST_SUCCESS;
             }
         }
 
@@ -17624,17 +17728,17 @@
             } catch (RemoteException e) {
             }
             if (ii == null) {
-                reportStartInstrumentationFailure(watcher, className,
+                reportStartInstrumentationFailureLocked(watcher, className,
                         "Unable to find instrumentation info for: " + className);
                 return false;
             }
             if (ai == null) {
-                reportStartInstrumentationFailure(watcher, className,
+                reportStartInstrumentationFailureLocked(watcher, className,
                         "Unable to find instrumentation target package: " + ii.targetPackage);
                 return false;
             }
             if (!ai.hasCode()) {
-                reportStartInstrumentationFailure(watcher, className,
+                reportStartInstrumentationFailureLocked(watcher, className,
                         "Instrumentation target has no code: " + ii.targetPackage);
                 return false;
             }
@@ -17649,7 +17753,7 @@
                         + " not allowed because package " + ii.packageName
                         + " does not have a signature matching the target "
                         + ii.targetPackage;
-                reportStartInstrumentationFailure(watcher, className, msg);
+                reportStartInstrumentationFailureLocked(watcher, className, msg);
                 throw new SecurityException(msg);
             }
 
@@ -17680,31 +17784,21 @@
      * @param cn The component name of the instrumentation.
      * @param report The error report.
      */
-    private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
+    private void reportStartInstrumentationFailureLocked(IInstrumentationWatcher watcher,
             ComponentName cn, String report) {
         Slog.w(TAG, report);
-        try {
-            if (watcher != null) {
-                Bundle results = new Bundle();
-                results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
-                results.putString("Error", report);
-                watcher.instrumentationStatus(cn, -1, results);
-            }
-        } catch (RemoteException e) {
-            Slog.w(TAG, e);
+        if (watcher != null) {
+            Bundle results = new Bundle();
+            results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
+            results.putString("Error", report);
+            mInstrumentationReporter.reportStatus(watcher, cn, -1, results);
         }
     }
 
     void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
         if (app.instrumentationWatcher != null) {
-            try {
-                // NOTE:  IInstrumentationWatcher *must* be oneway here
-                app.instrumentationWatcher.instrumentationFinished(
-                    app.instrumentationClass,
-                    resultCode,
-                    results);
-            } catch (RemoteException e) {
-            }
+            mInstrumentationReporter.reportFinished(app.instrumentationWatcher,
+                    app.instrumentationClass, resultCode, results);
         }
 
         // Can't call out of the system process with a lock held, so post a message.
@@ -17807,36 +17901,42 @@
             final long origId = Binder.clearCallingIdentity();
             final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
             if (stack != null) {
-                if (fromStackId == DOCKED_STACK_ID) {
+                mWindowManager.deferSurfaceLayout();
+                try {
+                    if (fromStackId == DOCKED_STACK_ID) {
 
-                    // We are moving all tasks from the docked stack to the fullscreen stack, which
-                    // is dismissing the docked stack, so resize all other stacks to fullscreen here
-                    // already so we don't end up with resize trashing.
-                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                        if (StackId.isResizeableByDockedStack(i)) {
-                            ActivityStack otherStack = mStackSupervisor.getStack(i);
-                            if (otherStack != null) {
-                                mStackSupervisor.resizeStackLocked(i,
-                                        null, null, null, PRESERVE_WINDOWS,
-                                        true /* allowResizeInDockedMode */);
+                        // We are moving all tasks from the docked stack to the fullscreen stack,
+                        // which is dismissing the docked stack, so resize all other stacks to
+                        // fullscreen here already so we don't end up with resize trashing.
+                        for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                            if (StackId.isResizeableByDockedStack(i)) {
+                                ActivityStack otherStack = mStackSupervisor.getStack(i);
+                                if (otherStack != null) {
+                                    mStackSupervisor.resizeStackLocked(i,
+                                            null, null, null, PRESERVE_WINDOWS,
+                                            true /* allowResizeInDockedMode */);
+                                }
                             }
                         }
                     }
-                }
-                final ArrayList<TaskRecord> tasks = stack.getAllTasks();
-                final int size = tasks.size();
-                if (onTop) {
-                    for (int i = 0; i < size; i++) {
-                        mStackSupervisor.moveTaskToStackLocked(tasks.get(i).taskId,
-                                FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, !FORCE_FOCUS,
-                                "moveTasksToFullscreenStack", ANIMATE);
+                    final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+                    final int size = tasks.size();
+                    if (onTop) {
+                        for (int i = 0; i < size; i++) {
+                            mStackSupervisor.moveTaskToStackLocked(tasks.get(i).taskId,
+                                    FULLSCREEN_WORKSPACE_STACK_ID, onTop, !FORCE_FOCUS,
+                                    "moveTasksToFullscreenStack", ANIMATE);
+                        }
+                    } else {
+                        for (int i = size - 1; i >= 0; i--) {
+                            mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
+                                    FULLSCREEN_WORKSPACE_STACK_ID, 0);
+                        }
                     }
-                } else {
-                    for (int i = size - 1; i >= 0; i--) {
-                        mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
-                                FULLSCREEN_WORKSPACE_STACK_ID, 0);
-                    }
+                } finally {
+                    mWindowManager.continueSurfaceLayout();
                 }
+
             }
             Binder.restoreCallingIdentity(origId);
         }
@@ -17947,6 +18047,9 @@
             ActivityRecord starting, boolean initLocale, boolean persistent, int userId) {
         int changes = 0;
 
+        if (mWindowManager != null) {
+            mWindowManager.deferSurfaceLayout();
+        }
         if (values != null) {
             Configuration newConfig = new Configuration(mConfiguration);
             changes = newConfig.updateFrom(values);
@@ -18014,7 +18117,8 @@
 
                 final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
                 if (isDensityChange) {
-                    killAllBackgroundProcesses(Build.VERSION_CODES.N);
+                    killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
+                            ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
                 }
 
                 for (int i=mLruProcesses.size()-1; i>=0; i--) {
@@ -18046,6 +18150,20 @@
                             null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
                 }
             }
+            // Update the configuration with WM first and check if any of the stacks need to be
+            // resized due to the configuration change. If so, resize the stacks now and do any
+            // relaunches if necessary. This way we don't need to relaunch again below in
+            // ensureActivityConfigurationLocked().
+            if (mWindowManager != null) {
+                final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration);
+                if (resizedStacks != null) {
+                    for (int stackId : resizedStacks) {
+                        final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
+                        mStackSupervisor.resizeStackLocked(
+                                stackId, newBounds, null, null, false, false);
+                    }
+                }
+            }
         }
 
         boolean kept = true;
@@ -18067,11 +18185,9 @@
                         !PRESERVE_WINDOWS);
             }
         }
-
-        if (values != null && mWindowManager != null) {
-            mWindowManager.setNewConfiguration(mConfiguration);
+        if (mWindowManager != null) {
+            mWindowManager.continueSurfaceLayout();
         }
-
         return kept;
     }
 
@@ -18163,8 +18279,8 @@
         return null;
     }
 
-    Association startAssociationLocked(int sourceUid, String sourceProcess, int targetUid,
-            ComponentName targetComponent, String targetProcess) {
+    Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
+            int targetUid, ComponentName targetComponent, String targetProcess) {
         if (!mTrackingAssociations) {
             return null;
         }
@@ -18193,7 +18309,8 @@
         ass.mCount++;
         ass.mNesting++;
         if (ass.mNesting == 1) {
-            ass.mStartTime = SystemClock.uptimeMillis();
+            ass.mStartTime = ass.mLastStateUptime = SystemClock.uptimeMillis();
+            ass.mLastState = sourceState;
         }
         return ass;
     }
@@ -18222,7 +18339,39 @@
         }
         ass.mNesting--;
         if (ass.mNesting == 0) {
-            ass.mTime += SystemClock.uptimeMillis() - ass.mStartTime;
+            long uptime = SystemClock.uptimeMillis();
+            ass.mTime += uptime - ass.mStartTime;
+            ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+                    += uptime - ass.mLastStateUptime;
+            ass.mLastState = ActivityManager.MAX_PROCESS_STATE + 2;
+        }
+    }
+
+    private void noteUidProcessState(final int uid, final int state) {
+        mBatteryStatsService.noteUidProcessState(uid, state);
+        if (mTrackingAssociations) {
+            for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
+                ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
+                        = mAssociations.valueAt(i1);
+                for (int i2=0, N2=targetComponents.size(); i2<N2; i2++) {
+                    SparseArray<ArrayMap<String, Association>> sourceUids
+                            = targetComponents.valueAt(i2);
+                    ArrayMap<String, Association> sourceProcesses = sourceUids.get(uid);
+                    if (sourceProcesses != null) {
+                        for (int i4=0, N4=sourceProcesses.size(); i4<N4; i4++) {
+                            Association ass = sourceProcesses.valueAt(i4);
+                            if (ass.mNesting >= 1) {
+                                // currently associated
+                                long uptime = SystemClock.uptimeMillis();
+                                ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+                                        += uptime - ass.mLastStateUptime;
+                                ass.mLastState = state;
+                                ass.mLastStateUptime = uptime;
+                            }
+                        }
+                    }
+                }
+            }
         }
     }
 
@@ -18235,7 +18384,7 @@
 
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
-            app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
             app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
             return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
         }
@@ -18255,7 +18404,7 @@
             app.adjSeq = mAdjSeq;
             app.curRawAdj = app.maxAdj;
             app.foregroundActivities = false;
-            app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
+            app.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
             // System processes can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
@@ -18292,14 +18441,14 @@
         if (app == TOP_APP) {
             // The last app on the list is the foreground app.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_TOP_APP;
+            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
             app.adjType = "top-activity";
             foregroundActivities = true;
             procState = PROCESS_STATE_CUR_TOP;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_DEFAULT;
+            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             app.adjType = "instrumentation";
             procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
         } else if ((queue = isReceivingBroadcast(app)) != null) {
@@ -18309,7 +18458,7 @@
             // broadcast as reflected by which queue it's active in.
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = (queue == mFgBroadcastQueue)
-                    ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                    ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
             app.adjType = "broadcast";
             procState = ActivityManager.PROCESS_STATE_RECEIVER;
         } else if (app.executingServices.size() > 0) {
@@ -18317,13 +18466,13 @@
             // counts as being in the foreground.
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = app.execServicesFg ?
-                    Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                    ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
             app.adjType = "exec-service";
             procState = ActivityManager.PROCESS_STATE_SERVICE;
             //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
         } else {
             // As far as we know the process is empty.  We may change our mind later.
-            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
             // At this point we don't actually know the adjustment.  Use the cached adj
             // value that the caller wants us to.
             adj = cachedAdj;
@@ -18339,9 +18488,14 @@
             for (int j = 0; j < activitiesSize; j++) {
                 final ActivityRecord r = app.activities.get(j);
                 if (r.app != app) {
-                    Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "
-                            + app + "?!? Using " + r.app + " instead.");
-                    continue;
+                    Log.wtf(TAG, "Found activity " + r + " in proc activity list using " + r.app
+                            + " instead of expected " + app);
+                    if (r.app == null || (r.app.uid == app.uid)) {
+                        // Only fix things up when they look sane
+                        r.app = app;
+                    } else {
+                        continue;
+                    }
                 }
                 if (r.visible) {
                     // App has a visible activity; only upgrade adjustment.
@@ -18352,7 +18506,7 @@
                     if (procState > PROCESS_STATE_CUR_TOP) {
                         procState = PROCESS_STATE_CUR_TOP;
                     }
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                     app.cached = false;
                     app.empty = false;
                     foregroundActivities = true;
@@ -18371,7 +18525,7 @@
                     if (procState > PROCESS_STATE_CUR_TOP) {
                         procState = PROCESS_STATE_CUR_TOP;
                     }
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                     app.cached = false;
                     app.empty = false;
                     foregroundActivities = true;
@@ -18415,7 +18569,7 @@
                 procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
                 app.cached = false;
                 app.adjType = "fg-service";
-                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             } else if (app.forcingToForeground != null) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
@@ -18423,7 +18577,7 @@
                 app.cached = false;
                 app.adjType = "force-fg";
                 app.adjSource = app.forcingToForeground;
-                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             }
         }
 
@@ -18431,7 +18585,7 @@
             if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                 // We don't want to kill the current heavy-weight process.
                 adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "heavy";
             }
@@ -18445,7 +18599,7 @@
                 // This process is hosting what we currently consider to be the
                 // home app, so we don't want to let it go into the background.
                 adj = ProcessList.HOME_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "home";
             }
@@ -18460,7 +18614,7 @@
                 // We want to try to keep it around more aggressively, to give
                 // a good experience around switching between two apps.
                 adj = ProcessList.PREVIOUS_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "previous";
             }
@@ -18500,7 +18654,7 @@
 
         for (int is = app.services.size()-1;
                 is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                         || procState > ActivityManager.PROCESS_STATE_TOP);
                 is--) {
             ServiceRecord s = app.services.valueAt(is);
@@ -18538,13 +18692,13 @@
             }
             for (int conni = s.connections.size()-1;
                     conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                             || procState > ActivityManager.PROCESS_STATE_TOP);
                     conni--) {
                 ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
                 for (int i = 0;
                         i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
-                                || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                                || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                                 || procState > ActivityManager.PROCESS_STATE_TOP);
                         i++) {
                     // XXX should compute this based on the max of
@@ -18629,8 +18783,15 @@
                             }
                         }
                         if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
-                            if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
-                                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                            // This will treat important bound services identically to
+                            // the top app, which may behave differently than generic
+                            // foreground work.
+                            if (client.curSchedGroup > schedGroup) {
+                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
+                                    schedGroup = client.curSchedGroup;
+                                } else {
+                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                                }
                             }
                             if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
                                 if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
@@ -18694,11 +18855,15 @@
                     final ActivityRecord a = cr.activity;
                     if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
                         if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
-                                (a.visible || a.state == ActivityState.RESUMED
-                                 || a.state == ActivityState.PAUSING)) {
+                            (a.visible || a.state == ActivityState.RESUMED ||
+                             a.state == ActivityState.PAUSING)) {
                             adj = ProcessList.FOREGROUND_APP_ADJ;
                             if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
-                                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
+                                    schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+                                } else {
+                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                                }
                             }
                             app.cached = false;
                             app.adjType = "service";
@@ -18715,13 +18880,13 @@
 
         for (int provi = app.pubProviders.size()-1;
                 provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                         || procState > ActivityManager.PROCESS_STATE_TOP);
                 provi--) {
             ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
             for (int i = cpr.connections.size()-1;
                     i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                             || procState > ActivityManager.PROCESS_STATE_TOP);
                     i--) {
                 ContentProviderConnection conn = cpr.connections.get(i);
@@ -18778,8 +18943,8 @@
                 if (procState > clientProcState) {
                     procState = clientProcState;
                 }
-                if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                if (client.curSchedGroup > schedGroup) {
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                 }
             }
             // If the provider has external (non-framework) process
@@ -18788,7 +18953,7 @@
             if (cpr.hasExternalProcessHandles()) {
                 if (adj > ProcessList.FOREGROUND_APP_ADJ) {
                     adj = ProcessList.FOREGROUND_APP_ADJ;
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                     app.cached = false;
                     app.adjType = "provider";
                     app.adjTarget = cpr.name;
@@ -18802,7 +18967,7 @@
         if (app.lastProviderTime > 0 && (app.lastProviderTime+CONTENT_PROVIDER_RETAIN_TIME) > now) {
             if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                 adj = ProcessList.PREVIOUS_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "provider";
             }
@@ -18881,7 +19046,7 @@
         if (adj > app.maxAdj) {
             adj = app.maxAdj;
             if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             }
         }
 
@@ -19297,17 +19462,29 @@
         if (app.setSchedGroup != app.curSchedGroup) {
             app.setSchedGroup = app.curSchedGroup;
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
-                    "Setting process group of " + app.processName
+                    "Setting sched group of " + app.processName
                     + " to " + app.curSchedGroup);
             if (app.waitingToKill != null && app.curReceiver == null
-                    && app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                 app.kill(app.waitingToKill, true);
                 success = false;
             } else {
+                int processGroup;
+                switch (app.curSchedGroup) {
+                    case ProcessList.SCHED_GROUP_BACKGROUND:
+                        processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                        break;
+                    case ProcessList.SCHED_GROUP_TOP_APP:
+                        processGroup = Process.THREAD_GROUP_TOP_APP;
+                        break;
+                    default:
+                        processGroup = Process.THREAD_GROUP_DEFAULT;
+                        break;
+                }
                 if (true) {
                     long oldId = Binder.clearCallingIdentity();
                     try {
-                        Process.setProcessGroup(app.pid, app.curSchedGroup);
+                        Process.setProcessGroup(app.pid, processGroup);
                     } catch (Exception e) {
                         Slog.w(TAG, "Failed setting process group of " + app.pid
                                 + " to " + app.curSchedGroup);
@@ -19318,7 +19495,7 @@
                 } else {
                     if (app.thread != null) {
                         try {
-                            app.thread.setSchedulingGroup(app.curSchedGroup);
+                            app.thread.setSchedulingGroup(processGroup);
                         } catch (RemoteException e) {
                         }
                     }
@@ -20073,7 +20250,7 @@
                 }
                 uidRec.setProcState = uidRec.curProcState;
                 enqueueUidChangeLocked(uidRec, -1, uidChange);
-                mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+                noteUidProcessState(uidRec.uid, uidRec.curProcState);
             }
         }
 
@@ -20464,8 +20641,8 @@
     }
 
     @Override
-    public boolean unlockUser(int userId, byte[] token, byte[] secret) {
-        return mUserController.unlockUser(userId, token, secret);
+    public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener) {
+        return mUserController.unlockUser(userId, token, secret, new ProgressReporter(0, listener));
     }
 
     @Override
@@ -20481,6 +20658,10 @@
                 Slog.w(TAG, "No user info for user #" + targetUserId);
                 return false;
             }
+            if (!targetUserInfo.supportsSwitchTo()) {
+                Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
+                return false;
+            }
             if (targetUserInfo.isManagedProfile()) {
                 Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
                 return false;
@@ -20722,6 +20903,34 @@
                         voiceSession, voiceInteractor);
             }
         }
+
+        @Override
+        public void notifyStartingWindowDrawn() {
+            synchronized (ActivityManagerService.this) {
+                mStackSupervisor.mActivityMetricsLogger.notifyStartingWindowDrawn();
+            }
+        }
+
+        @Override
+        public void notifyAppTransitionStarting(int reason) {
+            synchronized (ActivityManagerService.this) {
+                mStackSupervisor.mActivityMetricsLogger.notifyTransitionStarting(reason);
+            }
+        }
+
+        @Override
+        public void notifyAppTransitionFinished() {
+            synchronized (ActivityManagerService.this) {
+                mStackSupervisor.notifyAppTransitionDone();
+            }
+        }
+
+        @Override
+        public void notifyAppTransitionCancelled() {
+            synchronized (ActivityManagerService.this) {
+                mStackSupervisor.notifyAppTransitionDone();
+            }
+        }
     }
 
     private final class SleepTokenImpl extends SleepToken {
@@ -20810,7 +21019,9 @@
             // Will bring task to front if it already has a root activity.
             final long origId = Binder.clearCallingIdentity();
             try {
-                startActivityFromRecentsInner(mTaskId, null);
+                synchronized (this) {
+                    mStackSupervisor.startActivityFromRecentsInner(mTaskId, null);
+                }
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 0253976..9be6b43 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -16,12 +16,12 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
-
-import com.android.internal.util.ArrayUtils;
+import android.util.DebugUtils;
 
 import java.io.PrintWriter;
 
@@ -64,6 +64,8 @@
                     return runIsUserStopped(pw);
                 case "lenient-background-check":
                     return runLenientBackgroundCheck(pw);
+                case "get-uid-state":
+                    return getUidState(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -170,6 +172,17 @@
         return 0;
     }
 
+    int getUidState(PrintWriter pw) throws RemoteException {
+        mInternal.enforceCallingPermission(android.Manifest.permission.DUMP,
+                "getUidState()");
+        int state = mInternal.getUidState(Integer.parseInt(getNextArgRequired()));
+        pw.print(state);
+        pw.print(" (");
+        pw.printf(DebugUtils.valueToString(ActivityManager.class, "PROCESS_STATE_", state));
+        pw.println(")");
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -212,7 +225,7 @@
             pw.println("  kill [--user <USER_ID> | all | current] <PACKAGE>");
             pw.println("    Kill all processes associated with the given application.");
             pw.println("  kill-all");
-            pw.println("    Kill all processes that are safe to kill (cached, etc)");
+            pw.println("    Kill all processes that are safe to kill (cached, etc).");
             pw.println("  write");
             pw.println("    Write all pending state to storage.");
             pw.println("  track-associations");
@@ -220,9 +233,11 @@
             pw.println("  untrack-associations");
             pw.println("    Disable and clear association tracking.");
             pw.println("  is-user-stopped <USER_ID>");
-            pw.println("    returns whether <USER_ID> has been stopped or not");
+            pw.println("    Returns whether <USER_ID> has been stopped or not.");
             pw.println("  lenient-background-check [<true|false>]");
-            pw.println("    optionally controls lenient background check mode, returns current mode.");
+            pw.println("    Optionally controls lenient background check mode, returns current mode.");
+            pw.println("  get-uid-state <UID>");
+            pw.println("    Gets the process state of an app given its <UID>.");
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index ffb2fc4..43e1bdf 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -7,11 +7,13 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager.StackId;
 import android.content.Context;
 import android.os.SystemClock;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 
 /**
  * Handles logging into Tron.
@@ -24,6 +26,8 @@
     private static final int WINDOW_STATE_FREEFORM = 2;
     private static final int WINDOW_STATE_INVALID = -1;
 
+    private static final long INVALID_START_TIME = -1;
+
     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
     // time we log.
     private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
@@ -34,6 +38,11 @@
     private final ActivityStackSupervisor mSupervisor;
     private final Context mContext;
 
+    private long mCurrentTransitionStartTime = INVALID_START_TIME;
+    private boolean mLoggedWindowsDrawn;
+    private boolean mLoggedStartingWindowDrawn;
+    private boolean mLoggedTransitionStarting;
+
     ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) {
         mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
         mSupervisor = supervisor;
@@ -52,7 +61,7 @@
         mLastLogTimeSecs = now;
 
         ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
-        if (stack != null && stack.getStackVisibilityLocked() != STACK_INVISIBLE) {
+        if (stack != null && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
             mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
             return;
         }
@@ -73,4 +82,101 @@
             throw new IllegalStateException("Unknown stack=" + stack);
         }
     }
+
+    /**
+     * Notifies the tracker at the earliest possible point when we are starting to launch an
+     * activity.
+     */
+    void notifyActivityLaunching() {
+        mCurrentTransitionStartTime = System.currentTimeMillis();
+    }
+
+    /**
+     * Notifies the tracker the the activity is actually launching.
+     *
+     * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
+     *                   launch
+     * @param componentName the component name of the activity being launched
+     * @param processRunning whether the process that will contains the activity is already running
+     */
+    void notifyActivityLaunched(int resultCode, @Nullable String componentName,
+            boolean processRunning) {
+
+        if (resultCode < 0 || componentName == null) {
+
+            // Failed to launch, don't track anything.
+            reset();
+            return;
+        }
+
+        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_COMPONENT_NAME,
+                componentName);
+        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_PROCESS_RUNNING,
+                processRunning);
+        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
+                (int) (SystemClock.uptimeMillis() / 1000));
+    }
+
+    /**
+     * Notifies the tracker that all windows of the app have been drawn.
+     */
+    void notifyWindowsDrawn() {
+        if (!isTransitionActive() || mLoggedWindowsDrawn) {
+            return;
+        }
+        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS,
+                calculateCurrentDelay());
+        mLoggedWindowsDrawn = true;
+        if (mLoggedTransitionStarting) {
+            reset();
+        }
+    }
+
+    /**
+     * Notifies the tracker that the starting window was drawn.
+     */
+    void notifyStartingWindowDrawn() {
+        if (!isTransitionActive() || mLoggedStartingWindowDrawn) {
+            return;
+        }
+        mLoggedStartingWindowDrawn = true;
+        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
+                calculateCurrentDelay());
+    }
+
+    /**
+     * Notifies the tracker that the app transition is starting.
+     *
+     * @param reason The reason why we started it. Must be on of
+     *               ActivityManagerInternal.APP_TRANSITION_* reasons.
+     */
+    void notifyTransitionStarting(int reason) {
+        if (!isTransitionActive() || mLoggedTransitionStarting) {
+            return;
+        }
+        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_REASON, reason);
+        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DELAY_MS,
+                calculateCurrentDelay());
+        mLoggedTransitionStarting = true;
+        if (mLoggedWindowsDrawn) {
+            reset();
+        }
+    }
+
+    private boolean isTransitionActive() {
+        return mCurrentTransitionStartTime != INVALID_START_TIME;
+    }
+
+    private void reset() {
+        mCurrentTransitionStartTime = INVALID_START_TIME;
+        mLoggedWindowsDrawn = false;
+        mLoggedTransitionStarting = false;
+        mLoggedStartingWindowDrawn = false;
+    }
+
+    private int calculateCurrentDelay() {
+
+        // Shouldn't take more than 25 days to launch an app, so int is fine here.
+        return (int) (System.currentTimeMillis() - mCurrentTransitionStartTime);
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 90a7da9..48f87b6 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -23,7 +23,6 @@
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
@@ -76,6 +75,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Objects;
 
@@ -122,7 +122,7 @@
     final boolean stateNotNeeded; // As per ActivityInfo.flags
     boolean fullscreen; // covers the full screen?
     final boolean noDisplay;  // activity is not displayed?
-    final boolean componentSpecified;  // did caller specifiy an explicit component?
+    final boolean componentSpecified;  // did caller specify an explicit component?
     final boolean rootVoiceInteraction;  // was this the root activity of a voice interaction?
 
     static final int APPLICATION_ACTIVITY_TYPE = 0;
@@ -189,14 +189,19 @@
     boolean forceNewConfig; // force re-create with new config next time
     int launchCount;        // count of launches since last state
     long lastLaunchTime;    // time of last launch of this activity
-    boolean isVrActivity;   // is the activity running in VR mode?
+    ComponentName requestedVrComponent; // the requested component for handling VR mode.
     ArrayList<ActivityContainer> mChildContainers = new ArrayList<>();
 
     String stringName;      // for caching of toString().
 
     private boolean inHistory;  // are we in the history stack?
     final ActivityStackSupervisor mStackSupervisor;
-    boolean mStartingWindowShown = false;
+
+    static final int STARTING_WINDOW_NOT_SHOWN = 0;
+    static final int STARTING_WINDOW_SHOWN = 1;
+    static final int STARTING_WINDOW_REMOVED = 2;
+    int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
+
     boolean mUpdateTaskThumbnailWhenHidden;
     ActivityContainer mInitialActivityContainer;
 
@@ -214,6 +219,19 @@
     boolean pendingVoiceInteractionStart;   // Waiting for activity-invoked voice session
     IVoiceInteractionSession voiceSession;  // Voice interaction session for this activity
 
+    private static String startingWindowStateToString(int state) {
+        switch (state) {
+            case STARTING_WINDOW_NOT_SHOWN:
+                return "STARTING_WINDOW_NOT_SHOWN";
+            case STARTING_WINDOW_SHOWN:
+                return "STARTING_WINDOW_SHOWN";
+            case STARTING_WINDOW_REMOVED:
+                return "STARTING_WINDOW_REMOVED";
+            default:
+                return "unknown state=" + state;
+        }
+    }
+
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
         pw.print(prefix); pw.print("packageName="); pw.print(packageName);
@@ -234,6 +252,10 @@
                 pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
             }
             pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
+            if (appInfo.splitSourceDirs != null) {
+                pw.print(prefix); pw.print("splitDir=");
+                        pw.println(Arrays.toString(appInfo.splitSourceDirs));
+            }
         }
         pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
                 pw.print(" componentSpecified="); pw.print(componentSpecified);
@@ -320,7 +342,9 @@
                 pw.print(" inHistory="); pw.print(inHistory);
                 pw.print(" visible="); pw.print(visible);
                 pw.print(" sleeping="); pw.print(sleeping);
-                pw.print(" idle="); pw.println(idle);
+                pw.print(" idle="); pw.print(idle);
+                pw.print(" mStartingWindowState=");
+                pw.println(startingWindowStateToString(mStartingWindowState));
         pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
                 pw.print(" noDisplay="); pw.print(noDisplay);
                 pw.print(" immersive="); pw.print(immersive);
@@ -329,7 +353,11 @@
                 pw.print(" forceNewConfig="); pw.println(forceNewConfig);
         pw.print(prefix); pw.print("mActivityType=");
                 pw.println(activityTypeToString(mActivityType));
-        pw.print(prefix); pw.print("vrMode="); pw.println(isVrActivity);
+        if (requestedVrComponent != null) {
+            pw.print(prefix);
+            pw.print("requestedVrComponent=");
+            pw.println(requestedVrComponent);
+        }
         if (displayStartTime != 0 || startTime != 0) {
             pw.print(prefix); pw.print("displayStartTime=");
                     if (displayStartTime == 0) pw.print("0");
@@ -423,24 +451,24 @@
         }
     }
 
-    void scheduleMultiWindowChanged() {
+    void scheduleMultiWindowModeChanged() {
         if (task == null || task.stack == null || app == null || app.thread == null) {
             return;
         }
         try {
             // An activity is considered to be in multi-window mode if its task isn't fullscreen.
-            app.thread.scheduleMultiWindowChanged(appToken, !task.mFullscreen);
+            app.thread.scheduleMultiWindowModeChanged(appToken, !task.mFullscreen);
         } catch (Exception e) {
             // If process died, I don't care.
         }
     }
 
-    void schedulePictureInPictureChanged() {
+    void schedulePictureInPictureModeChanged() {
         if (task == null || task.stack == null || app == null || app.thread == null) {
             return;
         }
         try {
-            app.thread.schedulePictureInPictureChanged(
+            app.thread.schedulePictureInPictureModeChanged(
                     appToken, task.stack.mStackId == PINNED_STACK_ID);
         } catch (Exception e) {
             // If process died, no one cares.
@@ -693,7 +721,6 @@
             }
 
             immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
-            isVrActivity = (aInfo.flags & ActivityInfo.FLAG_ENABLE_VR_MODE) != 0;
         } else {
             realActivity = null;
             taskAffinity = null;
@@ -705,7 +732,6 @@
             noDisplay = false;
             mActivityType = APPLICATION_ACTIVITY_TYPE;
             immersive = false;
-            isVrActivity = false;
         }
     }
 
@@ -1166,6 +1192,7 @@
     }
 
     void windowsDrawnLocked() {
+        mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
         if (displayStartTime != 0) {
             reportLaunchTimeLocked(SystemClock.uptimeMillis());
         }
@@ -1249,13 +1276,6 @@
         }
     }
 
-    static void activityResumedLocked(IBinder token) {
-        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-        if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
-        r.icicle = null;
-        r.haveState = false;
-    }
-
     static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r == null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index acde10f..4ec1f61 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
@@ -34,6 +35,8 @@
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 
+import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
+import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
 import static com.android.server.am.ActivityStackSupervisor.MOVING;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -63,7 +66,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -183,7 +186,7 @@
      * The back history of all previous (and possibly still
      * running) activities.  It contains #TaskRecord objects.
      */
-    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
+    private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
 
     /**
      * Used for validating app tokens with window manager.
@@ -255,6 +258,12 @@
     // Current bounds of the stack or null if fullscreen.
     Rect mBounds = null;
 
+    boolean mUpdateBoundsDeferred;
+    boolean mUpdateBoundsDeferredCalled;
+    final Rect mDeferredBounds = new Rect();
+    final Rect mDeferredTaskBounds = new Rect();
+    final Rect mDeferredTaskInsetBounds = new Rect();
+
     long mLaunchStartTime = 0;
     long mFullyDrawnStartTime = 0;
 
@@ -412,12 +421,69 @@
             mTaskPositioner.reset();
         }
         mWindowManager.detachStack(mStackId);
+        if (mStackId == DOCKED_STACK_ID) {
+            // If we removed a docked stack we want to resize it so it resizes all other stacks
+            // in the system to fullscreen.
+            mStackSupervisor.resizeDockedStackLocked(
+                    null, null, null, null, null, PRESERVE_WINDOWS);
+        }
     }
 
     public void getDisplaySize(Point out) {
         mActivityContainer.mActivityDisplay.mDisplay.getSize(out);
     }
 
+    /**
+     * Defers updating the bounds of the stack. If the stack was resized/repositioned while
+     * deferring, the bounds will update in {@link #continueUpdateBounds()}.
+     */
+    void deferUpdateBounds() {
+        if (!mUpdateBoundsDeferred) {
+            mUpdateBoundsDeferred = true;
+            mUpdateBoundsDeferredCalled = false;
+        }
+    }
+
+    /**
+     * Continues updating bounds after updates have been deferred. If there was a resize attempt
+     * between {@link #deferUpdateBounds()} and {@link #continueUpdateBounds()}, the stack will
+     * be resized to that bounds.
+     */
+    void continueUpdateBounds() {
+        final boolean wasDeferred = mUpdateBoundsDeferred;
+        mUpdateBoundsDeferred = false;
+        if (wasDeferred && mUpdateBoundsDeferredCalled) {
+            mStackSupervisor.resizeStackUncheckedLocked(this,
+                    mDeferredBounds.isEmpty() ? null : mDeferredBounds,
+                    mDeferredTaskBounds.isEmpty() ? null : mDeferredTaskBounds,
+                    mDeferredTaskInsetBounds.isEmpty() ? null : mDeferredTaskInsetBounds);
+        }
+    }
+
+    boolean updateBoundsAllowed(Rect bounds, Rect tempTaskBounds,
+            Rect tempTaskInsetBounds) {
+        if (!mUpdateBoundsDeferred) {
+            return true;
+        }
+        if (bounds != null) {
+            mDeferredBounds.set(bounds);
+        } else {
+            mDeferredBounds.setEmpty();
+        }
+        if (tempTaskBounds != null) {
+            mDeferredTaskBounds.set(tempTaskBounds);
+        } else {
+            mDeferredTaskBounds.setEmpty();
+        }
+        if (tempTaskInsetBounds != null) {
+            mDeferredTaskInsetBounds.set(tempTaskInsetBounds);
+        } else {
+            mDeferredTaskInsetBounds.setEmpty();
+        }
+        mUpdateBoundsDeferredCalled = true;
+        return false;
+    }
+
     void setBounds(Rect bounds) {
         mBounds = mFullscreen ? null : new Rect(bounds);
         if (mTaskPositioner != null) {
@@ -838,6 +904,18 @@
         }
     }
 
+    void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
+        final String packageName = aInfo.packageName;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final List<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                if (packageName.equals(activities.get(activityNdx).packageName)) {
+                    activities.get(activityNdx).info.applicationInfo = aInfo;
+                }
+            }
+        }
+    }
+
     /**
      * @return true if something must be done before going to sleep.
      */
@@ -908,7 +986,7 @@
             // use within SystemUI while keeping memory usage low.
             if (ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS) {
                 w = h = -1;
-                scale = 0.5f;
+                scale = mService.mFullscreenThumbnailScale;
             }
             return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY,
                     w, h, scale);
@@ -1074,6 +1152,13 @@
         mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
     }
 
+    final void activityResumedLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+        if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
+        r.icicle = null;
+        r.haveState = false;
+    }
+
     final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
             PersistableBundle persistentState, CharSequence description) {
         if (r.state != ActivityState.STOPPING) {
@@ -1100,7 +1185,7 @@
             r.stopped = true;
             r.state = ActivityState.STOPPED;
 
-            mWindowManager.notifyAppStopped(r.appToken);
+            mWindowManager.notifyAppStopped(r.appToken, true);
 
             if (getVisibleBehindActivity() == r) {
                 mStackSupervisor.requestVisibleBehindLocked(r, false);
@@ -1353,7 +1438,7 @@
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 ActivityStack stack = stacks.get(i);
                 if (stack != this && stack.isFocusable()
-                        && stack.getStackVisibilityLocked() != STACK_INVISIBLE) {
+                        && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
                     return stack;
                 }
             }
@@ -1372,22 +1457,42 @@
         return false;
     }
 
-    private boolean hasTranslucentActivity(ActivityStack stack) {
-        final ArrayList<TaskRecord> tasks = stack.getAllTasks();
-        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = tasks.get(taskNdx);
+    /**
+     * Returns true if the stack is translucent and can have other contents visible behind it if
+     * needed. A stack is considered translucent if it don't contain a visible or
+     * starting (about to be visible) activity that is fullscreen (opaque).
+     * @param starting The currently starting activity or null if there is none.
+     * @param stackBehindId The id of the stack directly behind this one.
+     */
+    private boolean isStackTranslucent(ActivityRecord starting, int stackBehindId) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
             final ArrayList<ActivityRecord> activities = task.mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
 
-                // Conditions for an activity to obscure the stack we're
-                // 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 && task.isOverHomeStack()))) {
+                if (r.finishing) {
+                    // We don't factor in finishing activities when determining translucency since
+                    // they will be gone soon.
+                    continue;
+                }
+
+                if (!r.visible && r != starting) {
+                    // Also ignore invisible activities that are not the currently starting
+                    // activity (about to be visible).
+                    continue;
+                }
+
+                if (r.fullscreen) {
+                    // Stack isn't translucent if it has at least one fullscreen activity
+                    // that is visible.
+                    return false;
+                }
+
+                if (!isHomeStack() && r.frontOfTask
+                        && task.isOverHomeStack() && stackBehindId != HOME_STACK_ID) {
+                    // Stack isn't translucent if it's top activity should have the home stack
+                    // behind it and the stack currently behind it isn't the home stack.
                     return false;
                 }
             }
@@ -1398,8 +1503,9 @@
     /**
      * Returns stack's visibility: {@link #STACK_INVISIBLE}, {@link #STACK_VISIBLE} or
      * {@link #STACK_VISIBLE_ACTIVITY_BEHIND}.
+     * @param starting The currently starting activity or null if there is none.
      */
-    int getStackVisibilityLocked() {
+    int getStackVisibilityLocked(ActivityRecord starting) {
         if (!isAttached()) {
             return STACK_INVISIBLE;
         }
@@ -1442,30 +1548,33 @@
                     : STACK_INVISIBLE;
         }
 
-        // Find the first stack below focused stack that actually got something visible.
-        int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
-        while (belowFocusedIndex >= 0 &&
-                mStacks.get(belowFocusedIndex).topRunningActivityLocked() == null) {
-            belowFocusedIndex--;
+        // Find the first stack behind focused stack that actually got something visible.
+        int stackBehindFocusedIndex = mStacks.indexOf(focusedStack) - 1;
+        while (stackBehindFocusedIndex >= 0 &&
+                mStacks.get(stackBehindFocusedIndex).topRunningActivityLocked() == null) {
+            stackBehindFocusedIndex--;
         }
         if ((focusedStackId == DOCKED_STACK_ID || focusedStackId == PINNED_STACK_ID)
-                && stackIndex == belowFocusedIndex) {
+                && stackIndex == stackBehindFocusedIndex) {
             // Stacks directly behind the docked or pinned stack are always visible.
             return STACK_VISIBLE;
         }
 
+        final int stackBehindFocusedId = (stackBehindFocusedIndex >= 0)
+                ? mStacks.get(stackBehindFocusedIndex).mStackId : INVALID_STACK_ID;
+
         if (focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
-                && hasTranslucentActivity(focusedStack)) {
+                && focusedStack.isStackTranslucent(starting, stackBehindFocusedId)) {
             // Stacks behind the fullscreen stack with a translucent activity are always
             // visible so they can act as a backdrop to the translucent activity.
             // For example, dialog activities
-            if (stackIndex == belowFocusedIndex) {
+            if (stackIndex == stackBehindFocusedIndex) {
                 return STACK_VISIBLE;
             }
-            if (belowFocusedIndex >= 0) {
-                final ActivityStack stack = mStacks.get(belowFocusedIndex);
-                if ((stack.mStackId == DOCKED_STACK_ID || stack.mStackId == PINNED_STACK_ID)
-                        && stackIndex == (belowFocusedIndex - 1)) {
+            if (stackBehindFocusedIndex >= 0) {
+                if ((stackBehindFocusedId == DOCKED_STACK_ID
+                        || stackBehindFocusedId == PINNED_STACK_ID)
+                        && stackIndex == (stackBehindFocusedIndex - 1)) {
                     // The stack behind the docked or pinned stack is also visible so we can have a
                     // complete backdrop to the translucent activity when the docked stack is up.
                     return STACK_VISIBLE;
@@ -1490,7 +1599,7 @@
                 return STACK_INVISIBLE;
             }
 
-            if (!hasTranslucentActivity(stack)) {
+            if (!stack.isStackTranslucent(starting, INVALID_STACK_ID)) {
                 return STACK_INVISIBLE;
             }
         }
@@ -1528,7 +1637,7 @@
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
         boolean aboveTop = top != null;
-        final int stackVisibility = getStackVisibilityLocked();
+        final int stackVisibility = getStackVisibilityLocked(starting);
         final boolean stackInvisible = stackVisibility != STACK_VISIBLE;
         final boolean stackVisibleBehind = stackVisibility == STACK_VISIBLE_ACTIVITY_BEHIND;
         boolean behindFullscreenActivity = stackInvisible;
@@ -1757,6 +1866,11 @@
             r.app.pendingUiClean = true;
             r.app.thread.scheduleWindowVisibility(r.appToken, true);
             r.stopFreezingScreenLocked(false);
+
+            // The activity may be waiting for stop, but that is no longer
+            // appropriate for it.
+            mStackSupervisor.mStoppingActivities.remove(r);
+            mStackSupervisor.mGoingToSleepActivities.remove(r);
         } catch (Exception e) {
             // Just skip on any failure; we'll make it
             // visible when it next restarts.
@@ -1845,10 +1959,11 @@
                     continue;
                 }
 
-                if (r.state == ActivityState.INITIALIZING && r.mStartingWindowShown) {
+                if (r.state == ActivityState.INITIALIZING
+                        && r.mStartingWindowState == STARTING_WINDOW_SHOWN) {
                     if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
                             "Found orphaned starting window " + r);
-                    r.mStartingWindowShown = false;
+                    r.mStartingWindowState = STARTING_WINDOW_REMOVED;
                     mWindowManager.removeAppStartingWindow(r.appToken);
                 }
             }
@@ -1921,7 +2036,9 @@
         if (next == null) {
             // There are no more activities!
             final String reason = "noMoreActivities";
-            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
+            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
+                    ? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
+            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
                 // Try to move focus to the next visible stack with a running activity if this
                 // stack is not covering the entire screen.
                 return mStackSupervisor.resumeFocusedStackTopActivityLocked(
@@ -1934,8 +2051,6 @@
                     "resumeTopActivityLocked: No more activities go home");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             // Only resume home if on home display
-            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
-                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
             return isOnHomeDisplay() &&
                     mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
         }
@@ -2154,10 +2269,11 @@
 
         ActivityStack lastStack = mStackSupervisor.getLastStack();
         if (next.app != null && next.app.thread != null) {
-            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);
+            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
+                    + " stopped=" + next.stopped + " visible=" + next.visible);
 
             // This activity is now becoming visible.
-            if (!next.visible) {
+            if (!next.visible || next.stopped) {
                 mWindowManager.setAppVisibility(next.appToken, true);
             }
 
@@ -2231,6 +2347,10 @@
                     next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
                 }
 
+                // Well the app will no longer be stopped.
+                // Clear app token stopped state in window manager if needed.
+                mWindowManager.notifyAppStopped(next.appToken, false);
+
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                         System.identityHashCode(next), next.task.taskId, next.shortComponentName);
 
@@ -2263,6 +2383,7 @@
                             mService.compatibilityInfoForPackageLocked(next.info.applicationInfo),
                             next.nonLocalizedLabel, next.labelRes, next.icon, next.logo,
                             next.windowFlags, null, true);
+                    next.mStartingWindowState = STARTING_WINDOW_SHOWN;
                 }
                 mStackSupervisor.startSpecificActivityLocked(next, true, false);
                 if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2295,6 +2416,7 @@
                             next.nonLocalizedLabel,
                             next.labelRes, next.icon, next.logo, next.windowFlags,
                             null, true);
+                    next.mStartingWindowState = STARTING_WINDOW_SHOWN;
                 }
                 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
             }
@@ -2527,7 +2649,7 @@
                                 r.info.applicationInfo), r.nonLocalizedLabel,
                         r.labelRes, r.icon, r.logo, r.windowFlags,
                         prev != null ? prev.appToken : null, showStartingIcon);
-                r.mStartingWindowShown = true;
+                r.mStartingWindowState = STARTING_WINDOW_SHOWN;
             }
         } else {
             // If this is the first activity, don't do any fancy animations,
@@ -2938,16 +3060,18 @@
             } else {
                 final TaskRecord task = r.task;
                 if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
+                    final int taskToReturnTo = task.getTaskToReturnTo();
+
                     // For non-fullscreen stack, we want to move the focus to the next visible
                     // stack to prevent the home screen from moving to the top and obscuring
                     // other visible stacks.
-                    if (!mFullscreen && adjustFocusToNextFocusableStackLocked(myReason)) {
+                    if (!mFullscreen
+                            && adjustFocusToNextFocusableStackLocked(taskToReturnTo, myReason)) {
                         return;
                     }
                     // Move the home stack to the top if this stack is fullscreen or there is no
                     // other visible stack.
-                    if (mStackSupervisor.moveHomeStackTaskToTop(
-                            task.getTaskToReturnTo(), myReason)) {
+                    if (mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, myReason)) {
                         // Activity focus was already adjusted. Nothing else to do...
                         return;
                     }
@@ -2958,13 +3082,21 @@
         mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
     }
 
-    private boolean adjustFocusToNextFocusableStackLocked(String reason) {
+    private boolean adjustFocusToNextFocusableStackLocked(int taskToReturnTo, String reason) {
         final ActivityStack stack = getNextFocusableStackLocked();
         final String myReason = reason + " adjustFocusToNextFocusableStack";
         if (stack == null) {
             return false;
         }
-        return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
+
+        final ActivityRecord top = stack.topRunningActivityLocked();
+
+        if (stack.isHomeStack() && (top == null || !top.visible)) {
+            // If we will be focusing on the home stack next and its current top activity isn't
+            // visible, then use the task return to value to determine the home task to display next.
+            return mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, reason);
+        }
+        return mService.setFocusedActivityLocked(top, myReason);
     }
 
     final void stopActivityLocked(ActivityRecord r) {
@@ -3001,6 +3133,8 @@
                 if (!r.visible) {
                     mWindowManager.setAppVisibility(r.appToken, false);
                 }
+                EventLogTags.writeAmStopActivity(
+                        r.userId, System.identityHashCode(r), r.shortComponentName);
                 r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
                 if (mService.isSleepingOrShuttingDown()) {
                     r.setSleeping(true);
@@ -3782,7 +3916,8 @@
     void releaseBackgroundResources(ActivityRecord r) {
         if (hasVisibleBehindActivity() &&
                 !mHandler.hasMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG)) {
-            if (r == topRunningActivityLocked() && getStackVisibilityLocked() == STACK_VISIBLE) {
+            if (r == topRunningActivityLocked()
+                    && getStackVisibilityLocked(null) == STACK_VISIBLE) {
                 // Don't release the top activity if it has requested to run behind the next
                 // activity and the stack is currently visible.
                 return;
@@ -4406,10 +4541,10 @@
                     "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r
                     + " callers=" + Debug.getCallers(6));
             r.forceNewConfig = false;
+            mStackSupervisor.activityRelaunchingLocked(r);
             r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
                     !andResume, new Configuration(mService.mConfiguration),
                     new Configuration(r.task.mOverrideConfig), preserveWindow);
-            mStackSupervisor.activityRelaunchingLocked(r);
             // Note: don't need to call pauseIfSleepingLocked() here, because
             // the caller will only pass in 'andResume' if this activity is
             // currently resumed, which implies we aren't sleeping.
@@ -4439,6 +4574,8 @@
         }
 
         r.configChangeFlags = 0;
+        r.deferRelaunchUntilPaused = false;
+        r.preserveWindowOnDeferredRelaunch = false;
     }
 
     boolean willActivityBeVisibleLocked(IBinder token) {
@@ -4652,6 +4789,8 @@
                     "    Task id #" + task.taskId + "\n" +
                     "    mFullscreen=" + task.mFullscreen + "\n" +
                     "    mBounds=" + task.mBounds + "\n" +
+                    "    mMinimalWidth=" + task.mMinimalWidth + "\n" +
+                    "    mMinimalHeight=" + task.mMinimalHeight + "\n" +
                     "    mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
             if (printed) {
                 header = null;
@@ -4774,7 +4913,9 @@
             // We only need to adjust focused stack if this stack is in focus.
             if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
                 String myReason = reason + " leftTaskHistoryEmpty";
-                if (mFullscreen || !adjustFocusToNextFocusableStackLocked(myReason)) {
+                if (mFullscreen
+                        || !adjustFocusToNextFocusableStackLocked(
+                        task.getTaskToReturnTo(), myReason)) {
                     mStackSupervisor.moveHomeStackToFront(myReason);
                 }
             }
@@ -4798,18 +4939,18 @@
         // add the task to stack first, mTaskPositioner might need the stack association
         addTask(task, toTop, "createTaskRecord");
         final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
-        if (!layoutTaskInStack(task, info.layout) && mBounds != null && task.isResizeable()
+        if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
                 && !isLockscreenShown) {
             task.updateOverrideConfiguration(mBounds);
         }
         return task;
     }
 
-    boolean layoutTaskInStack(TaskRecord task, ActivityInfo.Layout layout) {
+    boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) {
         if (mTaskPositioner == null) {
             return false;
         }
-        mTaskPositioner.updateDefaultBounds(task, mTaskHistory, layout);
+        mTaskPositioner.updateDefaultBounds(task, mTaskHistory, windowLayout);
         return true;
     }
 
@@ -4847,7 +4988,7 @@
 
     private void postAddTask(TaskRecord task, ActivityStack prevStack) {
         if (prevStack != null) {
-            mStackSupervisor.scheduleReportPictureInPictureChangedIfNeeded(task, prevStack);
+            mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
         } else if (task.voiceSession != null) {
             try {
                 task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -4906,7 +5047,7 @@
         r.setTask(task, null);
         task.addActivityToTop(r);
         setAppTask(r, task);
-        mStackSupervisor.scheduleReportPictureInPictureChangedIfNeeded(task, prevStack);
+        mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
         moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
         if (wasResumed) {
             prevStack.mResumedActivity = null;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9562f94..f659bde 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -52,6 +52,7 @@
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -102,6 +103,7 @@
 import java.util.Set;
 
 import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
@@ -119,7 +121,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
@@ -150,6 +152,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.ANIMATE;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
+import static com.android.server.am.ActivityManagerService.NOTIFY_FORCED_RESIZABLE_MSG;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
@@ -166,6 +169,7 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
 
 public final class ActivityStackSupervisor implements DisplayListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
@@ -405,7 +409,7 @@
     // Whether tasks have moved and we need to rank the tasks before next OOM scoring
     private boolean mTaskLayersChanged = true;
 
-    private final ActivityMetricsLogger mActivityMetricsLogger;
+    final ActivityMetricsLogger mActivityMetricsLogger;
 
     private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
 
@@ -422,6 +426,11 @@
     boolean mAppVisibilitiesChangedSinceLastPause;
 
     /**
+     * Set of tasks that are in resizing mode during an app transition to fill the "void".
+     */
+    private final ArraySet<Integer> mResizingTasksDuringAnimation = new ArraySet<>();
+
+    /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
      */
@@ -719,14 +728,14 @@
     }
 
     int getNextTaskIdForUserLocked(int userId) {
-        mRecentTasks.loadUserRecentsLocked(userId);
         final int currentTaskId = mCurTaskIdForUser.get(userId, userId * MAX_TASK_IDS_PER_USER);
         // for a userId u, a taskId can only be in the range
         // [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER
         // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on.
         int candidateTaskId = currentTaskId;
-        while (anyTaskForIdLocked(candidateTaskId, !RESTORE_FROM_RECENTS,
-                INVALID_STACK_ID) != null) {
+        while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId)
+                || anyTaskForIdLocked(candidateTaskId, !RESTORE_FROM_RECENTS,
+                        INVALID_STACK_ID) != null) {
             candidateTaskId++;
             if (candidateTaskId == (userId + 1) * MAX_TASK_IDS_PER_USER) {
                 // Wrap around as there will be smaller task ids that are available now.
@@ -1303,7 +1312,7 @@
     boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
             String resultWho, int requestCode, int callingPid, int callingUid,
             String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp,
-            ActivityRecord resultRecord, ActivityStack resultStack) {
+            ActivityRecord resultRecord, ActivityStack resultStack, ActivityOptions options) {
         final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid,
                 callingUid);
         if (startAnyPerm ==  PERMISSION_GRANTED) {
@@ -1357,6 +1366,19 @@
             Slog.w(TAG, message);
             return false;
         }
+        if (options != null && options.getLaunchTaskId() != -1) {
+            final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS,
+                    callingPid, callingUid);
+            if (startInTaskPerm != PERMISSION_GRANTED) {
+                final String msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ") with launchTaskId="
+                        + options.getLaunchTaskId();
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+        }
+
         return true;
     }
 
@@ -1699,6 +1721,15 @@
         return false;
     }
 
+    void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                stacks.get(stackNdx).updateActivityApplicationInfoLocked(aInfo);
+            }
+        }
+    }
+
     TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) {
         TaskRecord finishedTask = null;
         ActivityStack focusedStack = getFocusedStack();
@@ -1766,7 +1797,7 @@
                     // WM resizeTask must be done after the task is moved to the correct stack,
                     // because Task's setBounds() also updates dim layer's bounds, but that has
                     // dependency on the stack.
-                    mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig,
+                    mWindowManager.resizeTask(task.taskId, task.mBounds, task.mOverrideConfig,
                             false /* relayout */, false /* forced */);
                 }
             }
@@ -1778,6 +1809,8 @@
 
         if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
+
+        showNonResizeableDockToastIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId);
     }
 
     boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
@@ -1914,14 +1947,45 @@
         }
     }
 
-    private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
+    void deferUpdateBounds(int stackId) {
+        final ActivityStack stack = getStack(stackId);
+        if (stack != null) {
+            stack.deferUpdateBounds();
+        }
+    }
+
+    void continueUpdateBounds(int stackId) {
+        final ActivityStack stack = getStack(stackId);
+        if (stack != null) {
+            stack.continueUpdateBounds();
+        }
+    }
+
+    void notifyAppTransitionDone() {
+        continueUpdateBounds(HOME_STACK_ID);
+        for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
+            final int taskId = mResizingTasksDuringAnimation.valueAt(i);
+            if (anyTaskForIdLocked(taskId) != null) {
+                mWindowManager.setTaskDockedResizing(taskId, false);
+            }
+        }
+        mResizingTasksDuringAnimation.clear();
+    }
+
+    void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
             Rect tempTaskInsetBounds) {
         bounds = TaskRecord.validateBounds(bounds);
 
+        if (!stack.updateBoundsAllowed(bounds, tempTaskBounds, tempTaskInsetBounds)) {
+            return;
+        }
+
         mTmpBounds.clear();
         mTmpConfigs.clear();
         mTmpInsetBounds.clear();
         final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
+        final Rect insetBounds = tempTaskInsetBounds != null ? tempTaskInsetBounds : taskBounds;
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final TaskRecord task = tasks.get(i);
             if (task.isResizeable()) {
@@ -1933,9 +1997,7 @@
                     fitWithinBounds(tempRect2, bounds);
                     task.updateOverrideConfiguration(tempRect2);
                 } else {
-                    task.updateOverrideConfiguration(
-                            tempTaskBounds != null ? tempTaskBounds : bounds,
-                            tempTaskInsetBounds != null ? tempTaskInsetBounds : bounds);
+                    task.updateOverrideConfiguration(taskBounds, insetBounds);
                 }
             }
 
@@ -2007,14 +2069,16 @@
                 // static stacks need to be adjusted so they don't overlap with the docked stack.
                 // We get the bounds to use from window manager which has been adjusted for any
                 // screen controls and is also the same for all stacks.
-                mWindowManager.getStackDockedModeBounds(
-                        HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+                if (dockedBounds != null) {
+                    mWindowManager.getStackDockedModeBounds(
+                            HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+                }
                 for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
                     if (StackId.isResizeableByDockedStack(i)) {
                         ActivityStack otherStack = getStack(i);
                         if (otherStack != null) {
-                            resizeStackLocked(i, tempRect, tempOtherTaskBounds,
-                                    tempOtherTaskInsetBounds, preserveWindows,
+                            resizeStackLocked(i, dockedBounds != null ? tempRect : null,
+                                    tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows,
                                     true /* allowResizeInDockedMode */);
                         }
                     }
@@ -2033,7 +2097,27 @@
                 || tempOtherTaskInsetBounds != null);
     }
 
-    boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
+    void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+        final ActivityStack stack = getStack(PINNED_STACK_ID);
+        if (stack == null) {
+            Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
+            return;
+        }
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizePinnedStack");
+        mWindowManager.deferSurfaceLayout();
+        try {
+            ActivityRecord r = stack.topRunningActivityLocked();
+            resizeStackUncheckedLocked(stack, pinnedBounds, tempPinnedTaskBounds,
+                    null);
+            ensureConfigurationAndResume(stack, r, false);
+        } finally {
+            mWindowManager.continueSurfaceLayout();
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+        }
+    }
+
+    boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow,
+            boolean deferResume) {
         if (!task.isResizeable()) {
             Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
             return true;
@@ -2076,10 +2160,14 @@
             if (r != null) {
                 final ActivityStack stack = task.stack;
                 kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
-                // All other activities must be made visible with their correct configuration.
-                ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
-                if (!kept) {
-                    resumeFocusedStackTopActivityLocked();
+
+                if (!deferResume) {
+
+                    // All other activities must be made visible with their correct configuration.
+                    ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
+                    if (!kept) {
+                        resumeFocusedStackTopActivityLocked();
+                    }
                 }
             }
         }
@@ -2173,6 +2261,12 @@
      */
     ActivityStack moveTaskToStackUncheckedLocked(
             TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
+
+        if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) {
+            throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't "
+                    + "support multi-window task=" + task + " to stackId=" + stackId);
+        }
+
         final ActivityRecord r = task.getTopActivity();
         final ActivityStack prevStack = task.stack;
         final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
@@ -2183,9 +2277,7 @@
         final boolean wasFront = isFrontStack(prevStack)
                 && (prevStack.topRunningActivityLocked() == r);
 
-        final int resizeMode = task.mResizeMode;
-
-        if (stackId == DOCKED_STACK_ID && resizeMode == RESIZE_MODE_UNRESIZEABLE) {
+        if (stackId == DOCKED_STACK_ID && !task.isResizeable()) {
             // We don't allow moving a unresizeable task to the docked stack since the docked
             // stack is used for split-screen mode and will cause things like the docked divider to
             // show up. We instead leave the task in its current stack or move it to the fullscreen
@@ -2212,18 +2304,29 @@
         return stack;
     }
 
-    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
+    boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
             String reason, boolean animate) {
+        return moveTaskToStackLocked(taskId, stackId, toTop, forceFocus, reason, animate,
+                false /* deferResume */);
+    }
+
+    boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
+            String reason, boolean animate, boolean deferResume) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
-            return;
+            return false;
         }
 
         if (task.stack != null && task.stack.mStackId == stackId) {
             // You are already in the right stack silly...
             Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId);
-            return;
+            return true;
+        }
+
+        if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
+            throw new IllegalArgumentException("moveTaskToStack:"
+                    + "Attempt to move task " + taskId + " to unsupported freeform stack");
         }
 
         final ActivityRecord topActivity = task.getTopActivity();
@@ -2259,13 +2362,19 @@
 
             // Make sure the task has the appropriate bounds/size for the stack it is in.
             if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
-                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow);
-            } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
-                    && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
-                kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds,
-                        RESIZE_MODE_SYSTEM, !mightReplaceWindow);
+                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,
+                        !mightReplaceWindow, deferResume);
+            } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
+                Rect bounds = task.getLaunchBounds();
+                if (bounds == null) {
+                    stack.layoutTaskInStack(task, null);
+                    bounds = task.mBounds;
+                }
+                kept = resizeTaskLocked(task, bounds, RESIZE_MODE_FORCED, !mightReplaceWindow,
+                        deferResume);
             } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
-                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow);
+                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,
+                        !mightReplaceWindow, deferResume);
             }
         } finally {
             mWindowManager.continueSurfaceLayout();
@@ -2278,12 +2387,17 @@
             mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
         }
 
-        // The task might have already been running and its visibility needs to be synchronized with
-        // the visibility of the stack / windows.
-        ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow);
-        resumeFocusedStackTopActivityLocked();
+        if (!deferResume) {
+
+            // The task might have already been running and its visibility needs to be synchronized with
+            // the visibility of the stack / windows.
+            ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow);
+            resumeFocusedStackTopActivityLocked();
+        }
 
         showNonResizeableDockToastIfNeeded(task, preferredLaunchStackId, stackId);
+
+        return (preferredLaunchStackId == stackId);
     }
 
     boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) {
@@ -2329,6 +2443,11 @@
             if (task.mActivities.size() == 1) {
                 // There is only one activity in the task. So, we can just move the task over to
                 // the stack without re-parenting the activity in a different task.
+                if (task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE) {
+                    // Move the home stack forward if the task we just moved to the pinned stack
+                    // was launched from home so home should be visible behind it.
+                    moveHomeStackToFront(reason);
+                }
                 moveTaskToStackLocked(
                         task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS, reason, !ANIMATE);
             } else {
@@ -2343,7 +2462,7 @@
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         resumeFocusedStackTopActivityLocked();
 
-        mWindowManager.animateResizePinnedStack(bounds);
+        mWindowManager.animateResizePinnedStack(bounds, -1);
         mService.notifyActivityPinnedLocked();
     }
 
@@ -2362,6 +2481,8 @@
         stack.positionTask(task, position);
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
+        stack.ensureActivityConfigurationLocked(task.topRunningActivityLocked(), 0,
+                !PRESERVE_WINDOWS);
         stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         resumeFocusedStackTopActivityLocked();
     }
@@ -2619,12 +2740,21 @@
 
     // Called when WindowManager has finished animating the launchingBehind activity to the back.
     void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
-        r.mLaunchTaskBehind = false;
         final TaskRecord task = r.task;
-        task.setLastThumbnailLocked(task.stack.screenshotActivitiesLocked(r));
+        final ActivityStack stack = task.stack;
+
+        r.mLaunchTaskBehind = false;
+        task.setLastThumbnailLocked(stack.screenshotActivitiesLocked(r));
         mRecentTasks.addLocked(task);
         mService.notifyTaskStackChangedLocked();
         mWindowManager.setAppVisibility(r.appToken, false);
+
+        // When launching tasks behind, update the last active time of the top task after the new
+        // task has been shown briefly
+        final ActivityRecord top = stack.topActivity();
+        if (top != null) {
+            top.task.touchActiveTime();
+        }
     }
 
     void scheduleLaunchTaskBehindComplete(IBinder token) {
@@ -3242,10 +3372,14 @@
             return;
         }
 
-        if (!task.canGoInDockedStack() || task.inCropWindowsResizeMode()) {
-            // Display warning toast if we tried to put a non-dockable task in the docked stack or
-            // the task is running in cropped window mode.
+        if (!task.canGoInDockedStack()) {
+            // Display a warning toast that we tried to put a non-dockable task in the docked stack.
             mWindowManager.scheduleShowNonResizeableDockToast(task.taskId);
+        } else if (task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
+            String packageName = task.getTopActivity() != null
+                    ? task.getTopActivity().appInfo.packageName : null;
+            mService.mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, task.taskId, 0,
+                    packageName).sendToTarget();
         }
     }
 
@@ -3400,7 +3534,7 @@
         mActivityMetricsLogger.logWindowState();
     }
 
-    void scheduleReportMultiWindowChanged(TaskRecord task) {
+    void scheduleReportMultiWindowModeChanged(TaskRecord task) {
         for (int i = task.mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = task.mActivities.get(i);
             if (r.app != null && r.app.thread != null) {
@@ -3413,7 +3547,7 @@
         }
     }
 
-    void scheduleReportPictureInPictureChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
+    void scheduleReportPictureInPictureModeChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
         final ActivityStack stack = task.stack;
         if (prevStack == null || prevStack == stack
                 || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
@@ -3451,7 +3585,7 @@
                     synchronized (mService) {
                         for (int i = mMultiWindowModeChangedActivities.size() - 1; i >= 0; i--) {
                             final ActivityRecord r = mMultiWindowModeChangedActivities.remove(i);
-                            r.scheduleMultiWindowChanged();
+                            r.scheduleMultiWindowModeChanged();
                         }
                     }
                 } break;
@@ -3459,7 +3593,7 @@
                     synchronized (mService) {
                         for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
                             final ActivityRecord r = mPipModeChangedActivities.remove(i);
-                            r.schedulePictureInPictureChanged();
+                            r.schedulePictureInPictureModeChanged();
                         }
                     }
                 } break;
@@ -4062,4 +4196,80 @@
         throw new IllegalStateException("Failed to find a stack behind stack=" + stack
                 + " in=" + stacks);
     }
+
+    /**
+     * Puts a task into resizing mode during the next app transition.
+     *
+     * @param taskId the id of the task to put into resizing mode
+     */
+    private void setResizingDuringAnimation(int taskId) {
+        mResizingTasksDuringAnimation.add(taskId);
+        mWindowManager.setTaskDockedResizing(taskId, true);
+    }
+
+    final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
+        final TaskRecord task;
+        final int callingUid;
+        final String callingPackage;
+        final Intent intent;
+        final int userId;
+        final ActivityOptions activityOptions = (bOptions != null)
+                ? new ActivityOptions(bOptions) : null;
+        final int launchStackId = (activityOptions != null)
+                ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
+
+        if (launchStackId == HOME_STACK_ID) {
+            throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
+                    + taskId + " can't be launch in the home stack.");
+        }
+        task = anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
+        if (task == null) {
+            throw new IllegalArgumentException(
+                    "startActivityFromRecentsInner: Task " + taskId + " not found.");
+        }
+
+        if (launchStackId != INVALID_STACK_ID) {
+            if (launchStackId == DOCKED_STACK_ID) {
+                mWindowManager.setDockedStackCreateState(
+                        activityOptions.getDockCreateMode(), null /* initialBounds */);
+
+                // Defer updating the stack in which recents is until the app transition is done, to
+                // not run into issues where we still need to draw the task in recents but the
+                // docked stack is already created.
+                deferUpdateBounds(HOME_STACK_ID);
+                mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
+            }
+            if (task.stack.mStackId != launchStackId) {
+                moveTaskToStackLocked(
+                        taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
+                        ANIMATE);
+            }
+        }
+
+        // If the user must confirm credentials (e.g. when first launching a work app and the
+        // Work Challenge is present) let startActivityInPackage handle the intercepting.
+        if (!mService.mUserController.shouldConfirmCredentials(task.userId)
+                && task.getRootActivity() != null) {
+            mService.moveTaskToFrontLocked(task.taskId, 0, bOptions);
+
+            // If we are launching the task in the docked stack, put it into resizing mode so
+            // the window renders full-screen with the background filling the void. Also only
+            // call this at the end to make sure that tasks exists on the window manager side.
+            if (launchStackId == DOCKED_STACK_ID) {
+                setResizingDuringAnimation(taskId);
+            }
+            return ActivityManager.START_TASK_TO_FRONT;
+        }
+        callingUid = task.mCallingUid;
+        callingPackage = task.mCallingPackage;
+        intent = task.intent;
+        intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+        userId = task.userId;
+            int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
+                    null, null, 0, 0, bOptions, userId, null, task);
+            if (launchStackId == DOCKED_STACK_ID) {
+                setResizingDuringAnimation(task.taskId);
+            }
+            return result;
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 9b2bca0..76dfd01 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -26,9 +26,11 @@
 import static android.content.Intent.EXTRA_TASK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
 
 import android.app.KeyguardManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -40,6 +42,7 @@
 import android.os.UserManager;
 
 import com.android.internal.app.UnlaunchableAppActivity;
+import com.android.server.LocalServices;
 
 /**
  * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
@@ -98,15 +101,23 @@
         mAInfo = aInfo;
         mResolvedType = resolvedType;
         mInTask = inTask;
-        interceptQuietProfileIfNeeded();
-        interceptSuspendPackageIfNeed();
+        if (interceptSuspendPackageIfNeed()) {
+            // Skip the rest of interceptions as the package is suspended by device admin so
+            // no user action can undo this.
+            return;
+        }
+        if (interceptQuietProfileIfNeeded()) {
+            // If work profile is turned off, skip the work challenge since the profile can only
+            // be unlocked when profile's user is running.
+            return;
+        }
         interceptWorkProfileChallengeIfNeeded();
     }
 
-    private void interceptQuietProfileIfNeeded() {
+    private boolean interceptQuietProfileIfNeeded() {
         // Do not intercept if the user has not turned off the profile
         if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
-            return;
+            return false;
         }
         mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId);
         mCallingPid = mRealCallingPid;
@@ -115,18 +126,20 @@
 
         final UserInfo parent = mUserManager.getProfileParent(mUserId);
         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
-        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
-                null /*profilerInfo*/);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+        return true;
     }
 
-    private void interceptSuspendPackageIfNeed() {
+    private boolean interceptSuspendPackageIfNeed() {
         // Do not intercept if the admin did not suspend the package
         if (mAInfo == null || mAInfo.applicationInfo == null ||
                 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
-            return;
+            return false;
         }
-        mIntent = UnlaunchableAppActivity.createPackageSuspendedDialogIntent(mAInfo.packageName,
-                mUserId);
+        DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
+                DevicePolicyManagerInternal.class);
+        mIntent = devicePolicyManager.createPackageSuspendedDialogIntent(
+                mAInfo.packageName, mUserId);
         mCallingPid = mRealCallingPid;
         mCallingUid = mRealCallingUid;
         mResolvedType = null;
@@ -137,15 +150,15 @@
         } else {
             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
         }
-        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
-                null /*profilerInfo*/);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+        return true;
     }
 
-    private void interceptWorkProfileChallengeIfNeeded() {
+    private boolean interceptWorkProfileChallengeIfNeeded() {
         final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
                 mResolvedType, mAInfo, mCallingPackage, mUserId);
         if (interceptingIntent == null) {
-            return;
+            return false;
         }
         mIntent = interceptingIntent;
         mCallingPid = mRealCallingPid;
@@ -161,8 +174,8 @@
 
         final UserInfo parent = mUserManager.getProfileParent(mUserId);
         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
-        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
-                null /*profilerInfo*/);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+        return true;
     }
 
     /**
@@ -180,14 +193,14 @@
                 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
                 new String[]{ resolvedType },
                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
-        final int flags = intent.getFlags();
         final KeyguardManager km = (KeyguardManager) mService.mContext
                 .getSystemService(KEYGUARD_SERVICE);
         final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
         if (newIntent == null) {
             return null;
         }
-        newIntent.setFlags(flags | FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+                FLAG_ACTIVITY_TASK_ON_HOME);
         newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
         newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
         return newIntent;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 1166ae1..3bbc452 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -362,7 +362,7 @@
 
         boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                 requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
-                resultRecord, resultStack);
+                resultRecord, resultStack, options);
         abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                 callingPid, resolvedType, aInfo.applicationInfo);
 
@@ -547,12 +547,18 @@
         }
 
         if (startedActivityStackId == DOCKED_STACK_ID && prevFocusedStackId == HOME_STACK_ID) {
-            // We launch an activity while being in home stack, which means either launcher or
-            // recents into docked stack. We don't want the launched activity to be alone in a
-            // docked stack, so we want to immediately launch recents too.
-            if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
-            mWindowManager.showRecentApps();
-            return;
+            final ActivityStack homeStack = mSupervisor.getStack(HOME_STACK_ID);
+            final ActivityRecord topActivityHomeStack = homeStack != null
+                    ? homeStack.topRunningActivityLocked() : null;
+            if (topActivityHomeStack == null
+                    || topActivityHomeStack.mActivityType != RECENTS_ACTIVITY_TYPE) {
+                // We launch an activity while being in home stack, which means either launcher or
+                // recents into docked stack. We don't want the launched activity to be alone in a
+                // docked stack, so we want to immediately launch recents too.
+                if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
+                mWindowManager.showRecentApps();
+                return;
+            }
         }
 
         if (startedActivityStackId == PINNED_STACK_ID
@@ -593,6 +599,7 @@
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
+        mSupervisor.mActivityMetricsLogger.notifyActivityLaunching();
         boolean componentSpecified = intent.getComponent() != null;
 
         // Save a copy in case ephemeral needs it
@@ -608,12 +615,19 @@
                 // app in a locked managed profile from an unlocked parent allow it to resolve
                 // as user will be sent via confirm credentials to unlock the profile.
                 UserManager userManager = UserManager.get(mService.mContext);
-                UserInfo parent = userManager.getProfileParent(userId);
+                UserInfo parent = null;
+                long token = Binder.clearCallingIdentity();
+                try {
+                    parent = userManager.getProfileParent(userId);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
                 if (parent != null
                         && userManager.isUserUnlocked(parent.getUserHandle())
                         && !userManager.isUserUnlocked(userInfo.getUserHandle())) {
                     rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
-                            PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+                            PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
                 }
             }
         }
@@ -716,11 +730,13 @@
                 }
             }
 
+            final ActivityRecord[] outRecord = new ActivityRecord[1];
             int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                     aInfo, rInfo, voiceSession, voiceInteractor,
                     resultTo, resultWho, requestCode, callingPid,
                     callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
-                    options, ignoreTargetSecurity, componentSpecified, null, container, inTask);
+                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
+                    inTask);
 
             Binder.restoreCallingIdentity(origId);
 
@@ -767,6 +783,13 @@
                 }
             }
 
+            final String componentName = outRecord[0] != null ? outRecord[0].shortComponentName
+                    : null;
+            final boolean processRunning = outRecord[0] != null &&
+                    mService.mProcessNames.get(outRecord[0].processName,
+                            outRecord[0].appInfo.uid) != null;
+            mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, componentName,
+                    processRunning);
             return res;
         }
     }
@@ -862,6 +885,9 @@
 
         ActivityRecord intentActivity = getReusableIntentActivity();
 
+        final int preferredLaunchStackId =
+                (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
+
         if (intentActivity != null) {
             // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
             // still needs to be a lock task mode violation since the task gets cleared out and
@@ -960,6 +986,8 @@
             }
             top.deliverNewIntentLocked(
                     mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+            mSupervisor.showNonResizeableDockToastIfNeeded(mStartActivity.task,
+                    preferredLaunchStackId, topStack.mStackId);
             return START_DELIVERED_TO_TOP;
         }
 
@@ -1037,14 +1065,15 @@
                 // make sure it becomes visible as it starts (this will also trigger entry
                 // animation). An example of this are PIP activities.
                 mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                // Go ahead and tell window manager to execute app transition for this activity
+                // since the app transition will not be triggered through the resume channel.
+                mWindowManager.executeAppTransition();
             }
         } else {
             mTargetStack.addRecentActivityLocked(mStartActivity);
         }
         mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
 
-        final int preferredLaunchStackId =
-                (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
         mSupervisor.showNonResizeableDockToastIfNeeded(
                 mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);
 
@@ -1277,7 +1306,10 @@
         // same component, then instead of launching bring that one to the front.
         putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
         ActivityRecord intentActivity = null;
-        if (putIntoExistingTask) {
+        if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
+            final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
+            intentActivity = task != null ? task.getTopActivity() : null;
+        } else if (putIntoExistingTask) {
             // See if there is a task to bring to the front.  If this is a SINGLE_INSTANCE
             // activity, there can be one and only one instance of it in the history, and it is
             // always in its own unique task, so we do a special search.
@@ -1308,19 +1340,40 @@
                     intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
                 }
                 mMovedHome = true;
-                final ActivityStack launchStack =
-                        getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
-                                mOptions, true);
-                if (launchStack == null || launchStack == mTargetStack) {
-                    // We only want to move to the front, if we aren't going to launch on a
-                    // different stack. If we launch on a different stack, we will put the
-                    // task on top there.
-                    mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
-                            mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
-                    mMovedToFront = true;
+
+                // If the launch flags carry both NEW_TASK and CLEAR_TASK, the task's activities
+                // will be cleared soon by ActivityStarter in setTaskFromIntentActivity().
+                // So no point resuming any of the activities here, it just wastes one extra
+                // resuming, plus enter AND exit transitions.
+                // Here we only want to bring the target stack forward. Transition will be applied
+                // to the new activity that's started after the old ones are gone.
+                final boolean willClearTask =
+                        (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+                if (!willClearTask) {
+                    final ActivityStack launchStack = getLaunchStack(
+                            mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, true);
+                    if (launchStack == null || launchStack == mTargetStack) {
+                        // We only want to move to the front, if we aren't going to launch on a
+                        // different stack. If we launch on a different stack, we will put the
+                        // task on top there.
+                        mTargetStack.moveTaskToFrontLocked(
+                                intentActivity.task, mNoAnimation, mOptions,
+                                mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
+                        mMovedToFront = true;
+                    } else if ((launchStack.mStackId == DOCKED_STACK_ID
+                            || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID)
+                            && (mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
+                        // If we want to launch adjacent and mTargetStack is not the computed
+                        // launch stack - move task to top of computed stack.
+                        mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
+                                launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
+                                ANIMATE);
+                        mMovedToFront = true;
+                    }
+                    mOptions = null;
                 }
                 updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
-                mOptions = null;
             }
         }
         if (!mMovedToFront && mDoResume) {
@@ -1397,7 +1450,7 @@
                 }
                 intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                         mStartActivity.launchedFromPackage);
-            } else if (!mStartActivity.intent.filterEquals(intentActivity.intent)) {
+            } else if (!intentActivity.task.isSameIntentResolution(mStartActivity)) {
                 // In this case we are launching the root activity of the task, but with a
                 // different intent. We should start a new instance on top.
                 mAddingToTask = true;
@@ -1451,7 +1504,8 @@
             if (mLaunchBounds != null) {
                 final int stackId = mTargetStack.mStackId;
                 if (StackId.resizeStackWithLaunchBounds(stackId)) {
-                    mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE);
+                    mService.resizeStack(
+                            stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
                 } else {
                     mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
                 }
@@ -1539,7 +1593,7 @@
                 stackId = stack.mStackId;
             }
             if (StackId.resizeStackWithLaunchBounds(stackId)) {
-                mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE);
+                mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
             }
         }
         mTargetStack = mInTask.stack;
@@ -1723,26 +1777,41 @@
         if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
             return null;
         }
+        // Otherwise handle adjacent launch.
 
         // The parent activity doesn't want to launch the activity on top of itself, but
         // instead tries to put it onto other side in side-by-side mode.
         final ActivityStack parentStack = task != null ? task.stack
                 : r.mInitialActivityContainer != null ? r.mInitialActivityContainer.mStack
                 : mSupervisor.mFocusedStack;
-        if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) {
-            // If parent was in docked stack, the natural place to launch another activity
-            // will be fullscreen, so it can appear alongside the docked window.
-            return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+
+        if (parentStack != mSupervisor.mFocusedStack) {
+            // If task's parent stack is not focused - use it during adjacent launch.
+            return parentStack;
         } else {
-            // If the parent is not in the docked stack, we check if there is docked window
-            // and if yes, we will launch into that stack. If not, we just put the new
-            // activity into parent's stack, because we can't find a better place.
-            final ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
-            if (stack != null && stack.getStackVisibilityLocked() == STACK_INVISIBLE) {
-                // There is a docked stack, but it isn't visible, so we can't launch into that.
-                return null;
+            if (mSupervisor.mFocusedStack != null && task == mSupervisor.mFocusedStack.topTask()) {
+                // If task is already on top of focused stack - use it. We don't want to move the
+                // existing focused task to adjacent stack, just deliver new intent in this case.
+                return mSupervisor.mFocusedStack;
+            }
+
+            if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) {
+                // If parent was in docked stack, the natural place to launch another activity
+                // will be fullscreen, so it can appear alongside the docked window.
+                return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED,
+                        ON_TOP);
             } else {
-                return stack;
+                // If the parent is not in the docked stack, we check if there is docked window
+                // and if yes, we will launch into that stack. If not, we just put the new
+                // activity into parent's stack, because we can't find a better place.
+                final ActivityStack dockedStack = mSupervisor.getStack(DOCKED_STACK_ID);
+                if (dockedStack != null
+                        && dockedStack.getStackVisibilityLocked(r) == STACK_INVISIBLE) {
+                    // There is a docked stack, but it isn't visible, so we can't launch into that.
+                    return null;
+                } else {
+                    return dockedStack;
+                }
             }
         }
     }
@@ -1753,12 +1822,13 @@
             return false;
         }
 
-        if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
-            return true;
+        if (stackId != FULLSCREEN_WORKSPACE_STACK_ID
+                && (!mService.mSupportsMultiWindow || !r.isResizeableOrForced())) {
+            return false;
         }
 
-        if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !r.isResizeableOrForced()) {
-            return false;
+        if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
+            return true;
         }
 
         if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index b746a4b..ddfab4d 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -25,6 +25,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.text.BidiFormatter;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -37,6 +38,7 @@
 import static com.android.server.am.ActivityManagerService.IS_USER_BUILD;
 
 final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListener {
+
     private final ActivityManagerService mService;
     private final AppErrorResult mResult;
     private final ProcessRecord mProc;
@@ -44,12 +46,17 @@
 
     private CharSequence mName;
 
+    static int CANT_SHOW = -1;
+    static int BACKGROUND_USER = -2;
+    static int ALREADY_SHOWING = -3;
+
     // Event 'what' codes
     static final int FORCE_QUIT = 1;
     static final int FORCE_QUIT_AND_REPORT = 2;
     static final int RESTART = 3;
     static final int RESET = 4;
     static final int MUTE = 5;
+    static final int TIMEOUT = 6;
 
     // 5-minute timeout, then we automatically dismiss the crash dialog
     static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
@@ -62,18 +69,21 @@
         mProc = data.proc;
         mResult = data.result;
         mRepeating = data.repeating;
+        BidiFormatter bidi = BidiFormatter.getInstance();
+
         if ((mProc.pkgList.size() == 1) &&
                 (mName = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
             setTitle(res.getString(
                     mRepeating ? com.android.internal.R.string.aerr_application_repeated
                             : com.android.internal.R.string.aerr_application,
-                    mName.toString(), mProc.info.processName));
+                    bidi.unicodeWrap(mName.toString()),
+                    bidi.unicodeWrap(mProc.info.processName)));
         } else {
             mName = mProc.processName;
             setTitle(res.getString(
                     mRepeating ? com.android.internal.R.string.aerr_process_repeated
                             : com.android.internal.R.string.aerr_process,
-                    mName.toString()));
+                    bidi.unicodeWrap(mName.toString())));
         }
 
         setCancelable(false);
@@ -89,7 +99,7 @@
 
         // After the timeout, pretend the user clicked the quit button
         mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(FORCE_QUIT),
+                mHandler.obtainMessage(TIMEOUT),
                 DISMISS_TIMEOUT);
     }
 
@@ -132,7 +142,7 @@
             mResult.set(result);
 
             // Make sure we don't have time timeout still hanging around.
-            removeMessages(FORCE_QUIT);
+            removeMessages(TIMEOUT);
 
             dismiss();
         }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 190e9e1..68bd2fd 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -17,6 +17,8 @@
 package com.android.server.am;
 
 import com.android.internal.app.ProcessMap;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.server.Watchdog;
 
@@ -59,6 +61,7 @@
 import java.util.concurrent.Semaphore;
 
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -403,6 +406,10 @@
         Intent appErrorIntent = null;
         final long ident = Binder.clearCallingIdentity();
         try {
+            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
+            if (res == AppErrorDialog.TIMEOUT) {
+                res = AppErrorDialog.FORCE_QUIT;
+            }
             if (res == AppErrorDialog.RESET) {
                 String[] packageList = r.getPackageList();
                 if (packageList != null) {
@@ -697,7 +704,7 @@
             if (proc != null && proc.crashDialog != null) {
                 Slog.e(TAG, "App already has crash dialog: " + proc);
                 if (res != null) {
-                    res.set(0);
+                    res.set(AppErrorDialog.ALREADY_SHOWING);
                 }
                 return;
             }
@@ -710,24 +717,26 @@
             if (isBackground && !showBackground) {
                 Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
                 if (res != null) {
-                    res.set(0);
+                    res.set(AppErrorDialog.BACKGROUND_USER);
                 }
                 return;
             }
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
             if (mService.canShowErrorDialogs() && !crashSilenced) {
-                Dialog d = new AppErrorDialog(mContext, mService, data);
-                d.show();
-                proc.crashDialog = d;
+                proc.crashDialog = new AppErrorDialog(mContext, mService, data);
             } else {
                 // The device is asleep, so just pretend that the user
                 // saw a crash dialog and hit "force quit".
                 if (res != null) {
-                    res.set(0);
+                    res.set(AppErrorDialog.CANT_SHOW);
                 }
             }
         }
+        // If we've created a crash dialog, show it without the lock held
+        if(data.proc.crashDialog != null) {
+            data.proc.crashDialog.show();
+        }
     }
 
     void stopReportingCrashesLocked(ProcessRecord proc) {
@@ -800,8 +809,10 @@
                     if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
                         if (r.persistent) {
                             firstPids.add(pid);
+                            if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
                         } else {
                             lastPids.put(pid, Boolean.TRUE);
+                            if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
                         }
                     }
                 }
@@ -915,11 +926,14 @@
     }
 
     void handleShowAnrUi(Message msg) {
+        Dialog d = null;
         synchronized (mService) {
             HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
             ProcessRecord proc = (ProcessRecord)data.get("app");
             if (proc != null && proc.anrDialog != null) {
                 Slog.e(TAG, "App already has anr dialog: " + proc);
+                MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
+                        AppNotRespondingDialog.ALREADY_SHOWING);
                 return;
             }
 
@@ -933,16 +947,21 @@
                     null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
 
             if (mService.canShowErrorDialogs()) {
-                Dialog d = new AppNotRespondingDialog(mService,
+                d = new AppNotRespondingDialog(mService,
                         mContext, proc, (ActivityRecord)data.get("activity"),
                         msg.arg1 != 0);
-                d.show();
                 proc.anrDialog = d;
             } else {
+                MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
+                        AppNotRespondingDialog.CANT_SHOW);
                 // Just kill the app if there is no dialog to be shown.
                 mService.killAppAtUsersRequest(proc, null);
             }
         }
+        // If we've created a crash dialog, show it without the lock held
+        if (d != null) {
+            d.show();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 9875887..c6befd7 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
+
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -24,6 +27,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.text.BidiFormatter;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -41,6 +45,9 @@
     static final int WAIT = 2;
     static final int WAIT_AND_REPORT = 3;
 
+    public static final int CANT_SHOW = -1;
+    public static final int ALREADY_SHOWING = -2;
+
     private final ActivityManagerService mService;
     private final ProcessRecord mProc;
 
@@ -78,9 +85,11 @@
             }
         }
 
+        BidiFormatter bidi = BidiFormatter.getInstance();
+
         setTitle(name2 != null
-                ? res.getString(resid, name1.toString(), name2.toString())
-                : res.getString(resid, name1.toString()));
+                ? res.getString(resid, bidi.unicodeWrap(name1.toString()), bidi.unicodeWrap(name2.toString()))
+                : res.getString(resid, bidi.unicodeWrap(name1.toString())));
 
         if (aboveSystem) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
@@ -132,6 +141,10 @@
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             Intent appErrorIntent = null;
+
+            MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_APP_ANR,
+                    msg.what);
+
             switch (msg.what) {
                 case FORCE_CLOSE:
                     // Kill the application.
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 28882de..3d42047 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -32,6 +32,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelFormatException;
+import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
@@ -39,6 +40,9 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.os.health.HealthStatsParceler;
+import android.os.health.HealthStatsWriter;
+import android.os.health.UidHealthStats;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ModemActivityInfo;
 import android.telephony.SignalStrength;
@@ -65,7 +69,9 @@
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 
 /**
  * All information we are collecting about things that can happen that impact
@@ -1164,7 +1170,8 @@
         }
 
         if (useCheckinFormat) {
-            List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
+            List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL);
             if (isRealCheckin) {
                 // For a real checkin, first we want to prefer to use the last complete checkin
                 // file if there is one.
@@ -1217,7 +1224,8 @@
     // WiFi keeps an accumulated total of stats, unlike Bluetooth.
     // Keep the last WiFi stats so we can compute a delta.
     @GuardedBy("mExternalStatsLock")
-    private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
+    private WifiActivityEnergyInfo mLastInfo =
+            new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0);
 
     @GuardedBy("mExternalStatsLock")
     private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() {
@@ -1419,4 +1427,88 @@
             }
         }
     }
+
+    /**
+     * Gets a snapshot of the system health for a particular uid.
+     */
+    @Override
+    public HealthStatsParceler takeUidSnapshot(int requestUid) {
+        if (requestUid != Binder.getCallingUid()) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.BATTERY_STATS, null);
+        }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            updateExternalStats("get-health-stats-for-uid",
+                    BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
+            synchronized (mStats) {
+                return getHealthStatsForUidLocked(requestUid);
+            }
+        } catch (Exception ex) {
+            Slog.d(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex);
+            throw ex;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Gets a snapshot of the system health for a number of uids.
+     */
+    @Override
+    public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) {
+        if (!onlyCaller(requestUids)) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.BATTERY_STATS, null);
+        }
+        long ident = Binder.clearCallingIdentity();
+        int i=-1;
+        try {
+            updateExternalStats("get-health-stats-for-uids",
+                    BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
+            synchronized (mStats) {
+                final int N = requestUids.length;
+                final HealthStatsParceler[] results = new HealthStatsParceler[N];
+                for (i=0; i<N; i++) {
+                    results[i] = getHealthStatsForUidLocked(requestUids[i]);
+                }
+                return results;
+            }
+        } catch (Exception ex) {
+            Slog.d(TAG, "Crashed while writing for takeUidSnapshots("
+                    + Arrays.toString(requestUids) + ") i=" + i, ex);
+            throw ex;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Returns whether the Binder.getCallingUid is the only thing in requestUids.
+     */
+    private static boolean onlyCaller(int[] requestUids) {
+        final int caller = Binder.getCallingUid();
+        final int N = requestUids.length;
+        for (int i=0; i<N; i++) {
+            if (requestUids[i] != caller) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets a HealthStatsParceler for the given uid. You should probably call
+     * updateExternalStats first.
+     */
+    HealthStatsParceler getHealthStatsForUidLocked(int requestUid) {
+        final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter();
+        final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS);
+        final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid);
+        if (uid != null) {
+            writer.writeUid(uidWriter, mStats, uid);
+        }
+        return new HealthStatsParceler(uidWriter);
+    }
+
 }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 37b0af1..37c7765 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -50,7 +50,6 @@
 import android.util.Slog;
 import android.util.TimeUtils;
 import com.android.server.DeviceIdleController;
-import com.android.server.LocalServices;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 
@@ -563,7 +562,7 @@
         }
         if (!skip) {
             final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid,
-                    filter.packageName, -1);
+                    filter.packageName, -1, true);
             if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                 Slog.w(TAG, "Background execution not allowed: receiving "
                         + r.intent
@@ -654,7 +653,7 @@
         }
 
         final boolean callerForeground = receiverRecord.callerApp != null
-                ? receiverRecord.callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE
+                ? receiverRecord.callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND
                 : true;
 
         // Show a permission review UI only for explicit broadcast from a foreground app
@@ -1102,21 +1101,21 @@
 
             if (!skip) {
                 final int allowed = mService.checkAllowBackgroundLocked(
-                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1);
+                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1,
+                        false);
                 if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                     // We won't allow this receiver to be launched if the app has been
-                    // completely disabled from launches, or it is delayed and the broadcast
-                    // was not explicitly sent to it and this would result in a new process
-                    // for it being created.
+                    // completely disabled from launches, or it was not explicitly sent
+                    // to it and the app is in a state that should not receive it
+                    // (depending on how checkAllowBackgroundLocked has determined that).
                     if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                         Slog.w(TAG, "Background execution disabled: receiving "
                                 + r.intent + " to "
                                 + component.flattenToShortString());
                         skip = true;
-                    }
-                    if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
+                    } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
                             || (r.intent.getComponent() == null
-                                && r.intent.getPackage() == null && app == null
+                                && r.intent.getPackage() == null
                                 && ((r.intent.getFlags()
                                         & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0))) {
                         Slog.w(TAG, "Background execution not allowed: receiving "
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index f2e8d09..2329b2f 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -54,9 +54,9 @@
 # An activity has been relaunched:
 30020 am_relaunch_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
 # The activity's onPause has been called.
-30021 am_on_paused_called (User|1|5),(Component Name|3)
+30021 am_on_paused_called (User|1|5),(Component Name|3),(Reason|3)
 # The activity's onResume has been called.
-30022 am_on_resume_called (User|1|5),(Component Name|3)
+30022 am_on_resume_called (User|1|5),(Component Name|3),(Reason|3)
 # Kill a process to reclaim memory.
 30023 am_kill (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
 # Discard an undelivered serialized broadcast (timeout/ANR/crash)
@@ -103,3 +103,8 @@
 30046 am_meminfo (Cached|2|2),(Free|2|2),(Zram|2|2),(Kernel|2|2),(Native|2|2)
 # Report collection of memory used by a process
 30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2)
+
+# Attempting to stop an activity
+30048 am_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
+# The activity's onStop has been called.
+30049 am_on_stop_called (User|1|5),(Component Name|3),(Reason|3)
diff --git a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
new file mode 100644
index 0000000..9fb51c1
--- /dev/null
+++ b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.os.BatteryStats;
+import static android.os.BatteryStats.STATS_SINCE_UNPLUGGED;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.health.HealthKeys;
+import android.os.health.HealthStatsParceler;
+import android.os.health.HealthStatsWriter;
+import android.os.health.PackageHealthStats;
+import android.os.health.ProcessHealthStats;
+import android.os.health.PidHealthStats;
+import android.os.health.ServiceHealthStats;
+import android.os.health.TimerStat;
+import android.os.health.UidHealthStats;
+import android.util.SparseArray;
+
+import java.util.Map;
+
+public class HealthStatsBatteryStatsWriter {
+
+    private final long mNowRealtime;
+    private final long mNowUptime;
+
+    public HealthStatsBatteryStatsWriter() {
+        mNowRealtime = SystemClock.elapsedRealtime();
+        mNowUptime = SystemClock.uptimeMillis();
+    }
+
+    /**
+     * Writes the contents of a BatteryStats.Uid into a HealthStatsWriter.
+     */
+    public void writeUid(HealthStatsWriter uidWriter, BatteryStats bs, BatteryStats.Uid uid) {
+        int N;
+        BatteryStats.Timer timer;
+        SparseArray<? extends BatteryStats.Uid.Sensor> sensors;
+        SparseArray<? extends BatteryStats.Uid.Pid> pids;
+        BatteryStats.ControllerActivityCounter controller;
+        long sum;
+
+        //
+        // It's a little odd for these first four to be here but it's not the end of the
+        // world. It would be easy enough to duplicate them somewhere else if this API
+        // grows.
+        //
+
+        // MEASUREMENT_REALTIME_BATTERY_MS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS,
+                bs.computeBatteryRealtime(mNowRealtime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+        // MEASUREMENT_UPTIME_BATTERY_MS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS,
+                bs.computeBatteryUptime(mNowUptime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+        // MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS,
+                bs.computeBatteryScreenOffRealtime(mNowRealtime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+        // MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS,
+                bs.computeBatteryScreenOffUptime(mNowUptime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+        //
+        // Now on to the real per-uid stats...
+        //
+
+        for (final Map.Entry<String,? extends BatteryStats.Uid.Wakelock> entry:
+                uid.getWakelockStats().entrySet()) {
+            final String key = entry.getKey();
+            final BatteryStats.Uid.Wakelock wakelock = entry.getValue();
+
+            // TIMERS_WAKELOCKS_FULL
+            timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_FULL);
+            addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_FULL, key, timer);
+
+            // TIMERS_WAKELOCKS_PARTIAL
+            timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
+            addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_PARTIAL, key, timer);
+            
+            // TIMERS_WAKELOCKS_WINDOW
+            timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_WINDOW);
+            addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_WINDOW, key, timer);
+            
+            // TIMERS_WAKELOCKS_DRAW
+            timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_DRAW);
+            addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_DRAW, key, timer);
+        }
+        
+        // TIMERS_SYNCS
+        for (final Map.Entry<String,? extends BatteryStats.Timer> entry:
+                uid.getSyncStats().entrySet()) {
+            addTimers(uidWriter, UidHealthStats.TIMERS_SYNCS, entry.getKey(), entry.getValue());
+        }
+
+        // TIMERS_JOBS
+        for (final Map.Entry<String,? extends BatteryStats.Timer> entry:
+                uid.getJobStats().entrySet()) {
+            addTimers(uidWriter, UidHealthStats.TIMERS_JOBS, entry.getKey(), entry.getValue());
+        }
+
+        // TIMERS_SENSORS
+        sensors = uid.getSensorStats();
+        N = sensors.size();
+        for (int i=0; i<N; i++) {
+            int sensorId = sensors.keyAt(i);
+            // Battery Stats stores the GPS sensors with a bogus key in this API. Pull it out
+            // as a separate metric here so as to not expose that in the API.
+            if (sensorId == BatteryStats.Uid.Sensor.GPS) {
+                addTimer(uidWriter, UidHealthStats.TIMER_GPS_SENSOR,
+                        sensors.valueAt(i).getSensorTime());
+            } else {
+                addTimers(uidWriter, UidHealthStats.TIMERS_SENSORS, Integer.toString(sensorId),
+                        sensors.valueAt(i).getSensorTime());
+            }
+        }
+
+        // STATS_PIDS
+        pids = uid.getPidStats();
+        N = pids.size();
+        for (int i=0; i<N; i++) {
+            final HealthStatsWriter writer = new HealthStatsWriter(PidHealthStats.CONSTANTS);
+            writePid(writer, pids.valueAt(i));
+            uidWriter.addStats(UidHealthStats.STATS_PIDS, Integer.toString(pids.keyAt(i)), writer);
+        }
+
+        // STATS_PROCESSES
+        for (final Map.Entry<String,? extends BatteryStats.Uid.Proc> entry:
+                uid.getProcessStats().entrySet()) {
+            final HealthStatsWriter writer = new HealthStatsWriter(ProcessHealthStats.CONSTANTS);
+            writeProc(writer, entry.getValue());
+            uidWriter.addStats(UidHealthStats.STATS_PROCESSES, entry.getKey(), writer);
+        }
+
+        // STATS_PACKAGES
+        for (final Map.Entry<String,? extends BatteryStats.Uid.Pkg> entry:
+                uid.getPackageStats().entrySet()) {
+            final HealthStatsWriter writer = new HealthStatsWriter(PackageHealthStats.CONSTANTS);
+            writePkg(writer, entry.getValue());
+            uidWriter.addStats(UidHealthStats.STATS_PACKAGES, entry.getKey(), writer);
+        }
+
+        controller = uid.getWifiControllerActivity();
+        if (controller != null) {
+            // MEASUREMENT_WIFI_IDLE_MS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS,
+                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+            // MEASUREMENT_WIFI_RX_MS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS,
+                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+            // MEASUREMENT_WIFI_TX_MS
+            sum = 0;
+            for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
+                sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+            }
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS, sum);
+            // MEASUREMENT_WIFI_POWER_MAMS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS,
+                    controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+        }
+
+        controller = uid.getBluetoothControllerActivity();
+        if (controller != null) {
+            // MEASUREMENT_BLUETOOTH_IDLE_MS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS,
+                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+            // MEASUREMENT_BLUETOOTH_RX_MS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS,
+                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+            // MEASUREMENT_BLUETOOTH_TX_MS
+            sum = 0;
+            for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
+                sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+            }
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS, sum);
+            // MEASUREMENT_BLUETOOTH_POWER_MAMS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS,
+                    controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+        }
+
+        controller = uid.getModemControllerActivity();
+        if (controller != null) {
+            // MEASUREMENT_MOBILE_IDLE_MS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS,
+                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+            // MEASUREMENT_MOBILE_RX_MS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS,
+                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+            // MEASUREMENT_MOBILE_TX_MS
+            sum = 0;
+            for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
+                sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+            }
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS, sum);
+            // MEASUREMENT_MOBILE_POWER_MAMS
+            uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS,
+                    controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+        }
+
+        // MEASUREMENT_WIFI_RUNNING_MS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS,
+                uid.getWifiRunningTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_WIFI_FULL_LOCK_MS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_FULL_LOCK_MS,
+                uid.getFullWifiLockTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+        // TIMER_WIFI_SCAN
+        uidWriter.addTimer(UidHealthStats.TIMER_WIFI_SCAN,
+                uid.getWifiScanCount(STATS_SINCE_UNPLUGGED),
+                uid.getWifiScanTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_WIFI_MULTICAST_MS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_MULTICAST_MS,
+                uid.getWifiMulticastTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+        // TIMER_AUDIO
+        addTimer(uidWriter, UidHealthStats.TIMER_AUDIO, uid.getAudioTurnedOnTimer());
+
+        // TIMER_VIDEO
+        addTimer(uidWriter, UidHealthStats.TIMER_VIDEO, uid.getVideoTurnedOnTimer());
+
+        // TIMER_FLASHLIGHT
+        addTimer(uidWriter, UidHealthStats.TIMER_FLASHLIGHT, uid.getFlashlightTurnedOnTimer());
+
+        // TIMER_CAMERA
+        addTimer(uidWriter, UidHealthStats.TIMER_CAMERA, uid.getCameraTurnedOnTimer());
+
+        // TIMER_FOREGROUND_ACTIVITY
+        addTimer(uidWriter, UidHealthStats.TIMER_FOREGROUND_ACTIVITY,
+                uid.getForegroundActivityTimer());
+
+        // TIMER_BLUETOOTH_SCAN
+        addTimer(uidWriter, UidHealthStats.TIMER_BLUETOOTH_SCAN, uid.getBluetoothScanTimer());
+
+        // TIMER_PROCESS_STATE_TOP_MS
+        addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_TOP_MS,
+                uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_TOP));
+
+        // TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS
+        addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS,
+                uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE));
+
+        // TIMER_PROCESS_STATE_TOP_SLEEPING_MS
+        addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_TOP_SLEEPING_MS,
+                uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING));
+
+        // TIMER_PROCESS_STATE_FOREGROUND_MS
+        addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_FOREGROUND_MS,
+                uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_FOREGROUND));
+
+        // TIMER_PROCESS_STATE_BACKGROUND_MS
+        addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_BACKGROUND_MS,
+                uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_BACKGROUND));
+
+        // TIMER_PROCESS_STATE_CACHED_MS
+        addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_CACHED_MS,
+                uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_CACHED));
+
+        // TIMER_VIBRATOR
+        addTimer(uidWriter, UidHealthStats.TIMER_VIBRATOR, uid.getVibratorOnTimer());
+
+        // MEASUREMENT_OTHER_USER_ACTIVITY_COUNT
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_OTHER_USER_ACTIVITY_COUNT,
+                uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_OTHER,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT,
+                uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_BUTTON,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT,
+                uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_MOBILE_RX_BYTES
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_BYTES,
+                uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_MOBILE_TX_BYTES
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_BYTES,
+                uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_WIFI_RX_BYTES
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_BYTES,
+                uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_WIFI_TX_BYTES
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_BYTES,
+                uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_BLUETOOTH_RX_BYTES
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_BYTES,
+                uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_BLUETOOTH_TX_BYTES
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_BYTES,
+                uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_MOBILE_RX_PACKETS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS,
+                uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_MOBILE_TX_PACKETS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_PACKETS,
+                uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_WIFI_RX_PACKETS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS,
+                uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_WIFI_TX_PACKETS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS,
+                uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_BLUETOOTH_RX_PACKETS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_PACKETS,
+                uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_RX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_BLUETOOTH_TX_PACKETS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_PACKETS,
+                uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_TX_DATA,
+                    STATS_SINCE_UNPLUGGED));
+
+        // TIMER_MOBILE_RADIO_ACTIVE
+        uidWriter.addTimer(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE,
+                uid.getMobileRadioActiveCount(STATS_SINCE_UNPLUGGED),
+                uid.getMobileRadioActiveTime(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_USER_CPU_TIME_US
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_US,
+                uid.getUserCpuTimeUs(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_SYSTEM_CPU_TIME_US
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_US,
+                uid.getSystemCpuTimeUs(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_CPU_POWER_MAUS
+        uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAUS,
+                uid.getCpuPowerMaUs(STATS_SINCE_UNPLUGGED));
+    }
+
+    /**
+     * Writes the contents of a BatteryStats.Uid.Pid into a HealthStatsWriter.
+     */
+    public void writePid(HealthStatsWriter pidWriter, BatteryStats.Uid.Pid pid) {
+        if (pid == null) {
+            return;
+        }
+
+        // MEASUREMENT_WAKE_NESTING_COUNT
+        pidWriter.addMeasurement(PidHealthStats.MEASUREMENT_WAKE_NESTING_COUNT, pid.mWakeNesting);
+
+        // MEASUREMENT_WAKE_SUM_MS
+        pidWriter.addMeasurement(PidHealthStats.MEASUREMENT_WAKE_SUM_MS, pid.mWakeSumMs);
+
+        // MEASUREMENT_WAKE_START_MS
+        pidWriter.addMeasurement(PidHealthStats.MEASUREMENT_WAKE_SUM_MS, pid.mWakeStartMs);
+    }
+
+    /**
+     * Writes the contents of a BatteryStats.Uid.Proc into a HealthStatsWriter.
+     */
+    public void writeProc(HealthStatsWriter procWriter, BatteryStats.Uid.Proc proc) {
+        // MEASUREMENT_USER_TIME_MS
+        procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_USER_TIME_MS,
+                proc.getUserTime(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_SYSTEM_TIME_MS
+        procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_SYSTEM_TIME_MS,
+                proc.getSystemTime(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_STARTS_COUNT
+        procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_STARTS_COUNT,
+                proc.getStarts(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_CRASHES_COUNT
+        procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_CRASHES_COUNT,
+                proc.getNumCrashes(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_ANR_COUNT
+        procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_ANR_COUNT,
+                proc.getNumAnrs(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_FOREGROUND_MS
+        procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_FOREGROUND_MS,
+                proc.getForegroundTime(STATS_SINCE_UNPLUGGED));
+    }
+
+    /**
+     * Writes the contents of a BatteryStats.Uid.Pkg into a HealthStatsWriter.
+     */
+    public void writePkg(HealthStatsWriter pkgWriter, BatteryStats.Uid.Pkg pkg) {
+        // STATS_SERVICES
+        for (final Map.Entry<String,? extends BatteryStats.Uid.Pkg.Serv> entry:
+                pkg.getServiceStats().entrySet()) {
+            final HealthStatsWriter writer = new HealthStatsWriter(ServiceHealthStats.CONSTANTS);
+            writeServ(writer, entry.getValue());
+            pkgWriter.addStats(PackageHealthStats.STATS_SERVICES, entry.getKey(), writer);
+        }
+
+        // MEASUREMENTS_WAKEUP_ALARMS_COUNT
+        for (final Map.Entry<String,? extends BatteryStats.Counter> entry:
+                pkg.getWakeupAlarmStats().entrySet()) {
+            final BatteryStats.Counter counter = entry.getValue();
+            if (counter != null) {
+                pkgWriter.addMeasurements(PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT,
+                        entry.getKey(), counter.getCountLocked(STATS_SINCE_UNPLUGGED));
+            }
+        }
+    }
+
+    /**
+     * Writes the contents of a BatteryStats.Uid.Pkg.Serv into a HealthStatsWriter.
+     */
+    public void writeServ(HealthStatsWriter servWriter, BatteryStats.Uid.Pkg.Serv serv) {
+        // MEASUREMENT_START_SERVICE_COUNT
+        servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_START_SERVICE_COUNT,
+                serv.getStarts(STATS_SINCE_UNPLUGGED));
+
+        // MEASUREMENT_LAUNCH_COUNT
+        servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_LAUNCH_COUNT,
+                serv.getLaunches(STATS_SINCE_UNPLUGGED));
+    }
+
+    /**
+     * Adds a BatteryStats.Timer into a HealthStatsWriter. Safe to pass a null timer.
+     */
+    private void addTimer(HealthStatsWriter writer, int key, BatteryStats.Timer timer) {
+        if (timer != null) {
+            writer.addTimer(key, timer.getCountLocked(STATS_SINCE_UNPLUGGED),
+                    timer.getTotalTimeLocked(mNowRealtime, STATS_SINCE_UNPLUGGED));
+        }
+    }
+
+    /**
+     * Adds a named BatteryStats.Timer into a HealthStatsWriter. Safe to pass a null timer.
+     */
+    private void addTimers(HealthStatsWriter writer, int key, String name,
+            BatteryStats.Timer timer) {
+        if (timer != null) {
+            writer.addTimers(key, name, new TimerStat(timer.getCountLocked(STATS_SINCE_UNPLUGGED),
+                    timer.getTotalTimeLocked(mNowRealtime, STATS_SINCE_UNPLUGGED)));
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/am/InstrumentationReporter.java b/services/core/java/com/android/server/am/InstrumentationReporter.java
new file mode 100644
index 0000000..fdbb73e
--- /dev/null
+++ b/services/core/java/com/android/server/am/InstrumentationReporter.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.IInstrumentationWatcher;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.ArrayList;
+
+public class InstrumentationReporter {
+    static final boolean DEBUG = false;
+    static final String TAG = ActivityManagerDebugConfig.TAG_AM;
+
+    static final int REPORT_TYPE_STATUS = 0;
+    static final int REPORT_TYPE_FINISHED = 1;
+
+    final Object mLock = new Object();
+    ArrayList<Report> mPendingReports;
+    Thread mThread;
+
+    final class MyThread extends Thread {
+        public MyThread() {
+            super("InstrumentationReporter");
+            if (DEBUG) Slog.d(TAG, "Starting InstrumentationReporter: " + this);
+        }
+
+        @Override
+        public void run() {
+            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+            boolean waited = false;
+            while (true) {
+                ArrayList<Report> reports;
+                synchronized (mLock) {
+                    reports = mPendingReports;
+                    mPendingReports = null;
+                    if (reports == null || reports.isEmpty()) {
+                        if (!waited) {
+                            // Sleep for a little bit, to avoid thrashing through threads.
+                            try {
+                                mLock.wait(10000); // 10 seconds
+                            } catch (InterruptedException e) {
+                            }
+                            waited = true;
+                            continue;
+                        } else {
+                            mThread = null;
+                            if (DEBUG) Slog.d(TAG, "Exiting InstrumentationReporter: " + this);
+                            return;
+                        }
+                    }
+                }
+
+                waited = false;
+
+                for (int i=0; i<reports.size(); i++) {
+                    final Report rep = reports.get(i);
+                    try {
+                        if (rep.mType == REPORT_TYPE_STATUS) {
+                            if (DEBUG) Slog.d(TAG, "Dispatch status to " + rep.mWatcher
+                                    + ": " + rep.mName.flattenToShortString()
+                                    + " code=" + rep.mResultCode + " result=" + rep.mResults);
+                            rep.mWatcher.instrumentationStatus(rep.mName, rep.mResultCode,
+                                    rep.mResults);
+                        } else {
+                            if (DEBUG) Slog.d(TAG, "Dispatch finished to " + rep.mWatcher
+                                    + ": " + rep.mName.flattenToShortString()
+                                    + " code=" + rep.mResultCode + " result=" + rep.mResults);
+                            rep.mWatcher.instrumentationFinished(rep.mName, rep.mResultCode,
+                                    rep.mResults);
+                        }
+                    } catch (RemoteException e) {
+                        Slog.i(TAG, "Failure reporting to instrumentation watcher: comp="
+                                + rep.mName + " results=" + rep.mResults);
+                    }
+                }
+            }
+        }
+    }
+
+    final class Report {
+        final int mType;
+        final IInstrumentationWatcher mWatcher;
+        final ComponentName mName;
+        final int mResultCode;
+        final Bundle mResults;
+
+        Report(int type, IInstrumentationWatcher watcher, ComponentName name, int resultCode,
+                Bundle results) {
+            mType = type;
+            mWatcher = watcher;
+            mName = name;
+            mResultCode = resultCode;
+            mResults = results;
+        }
+    }
+
+    public void reportStatus(IInstrumentationWatcher watcher, ComponentName name, int resultCode,
+            Bundle results) {
+        if (DEBUG) Slog.d(TAG, "Report status to " + watcher
+                + ": " + name.flattenToShortString()
+                + " code=" + resultCode + " result=" + results);
+        report(new Report(REPORT_TYPE_STATUS, watcher, name, resultCode, results));
+    }
+
+    public void reportFinished(IInstrumentationWatcher watcher, ComponentName name, int resultCode,
+            Bundle results) {
+        if (DEBUG) Slog.d(TAG, "Report finished to " + watcher
+                + ": " + name.flattenToShortString()
+                + " code=" + resultCode + " result=" + results);
+        report(new Report(REPORT_TYPE_FINISHED, watcher, name, resultCode, results));
+    }
+
+    private void report(Report report) {
+        synchronized (mLock) {
+            if (mThread == null) {
+                mThread = new MyThread();
+                mThread.start();
+            }
+            if (mPendingReports == null) {
+                mPendingReports = new ArrayList<>();
+            }
+            mPendingReports.add(report);
+            mLock.notifyAll();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 4ba1d0d..d652341 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -109,22 +109,22 @@
      *
      * @param task Task for which we want to find bounds that won't collide with other.
      * @param tasks Existing tasks with which we don't want to collide.
-     * @param layout Optional information from the client about how it would like to be sized
+     * @param windowLayout Optional information from the client about how it would like to be sized
      *                      and positioned.
      */
     void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
-            @Nullable ActivityInfo.Layout layout) {
+            @Nullable ActivityInfo.WindowLayout windowLayout) {
         if (!mDefaultStartBoundsConfigurationSet) {
             return;
         }
-        if (layout == null) {
+        if (windowLayout == null) {
             positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight);
             return;
         }
-        int width = getFinalWidth(layout);
-        int height = getFinalHeight(layout);
-        int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
-        int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        int width = getFinalWidth(windowLayout);
+        int height = getFinalHeight(windowLayout);
+        int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (verticalGravity == Gravity.TOP) {
             if (horizontalGravity == Gravity.RIGHT) {
                 positionTopRight(task, tasks, width, height);
@@ -140,30 +140,30 @@
         } else {
             // Some fancy gravity setting that we don't support yet. We just put the activity in the
             // center.
-            Slog.w(TAG, "Received unsupported gravity: " + layout.gravity
+            Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity
                     + ", positioning in the center instead.");
             positionCenter(task, tasks, width, height);
         }
     }
 
-    private int getFinalWidth(ActivityInfo.Layout layout) {
+    private int getFinalWidth(ActivityInfo.WindowLayout windowLayout) {
         int width = mDefaultFreeformWidth;
-        if (layout.width > 0) {
-            width = layout.width;
+        if (windowLayout.width > 0) {
+            width = windowLayout.width;
         }
-        if (layout.widthFraction > 0) {
-            width = (int) (mAvailableRect.width() * layout.widthFraction);
+        if (windowLayout.widthFraction > 0) {
+            width = (int) (mAvailableRect.width() * windowLayout.widthFraction);
         }
         return width;
     }
 
-    private int getFinalHeight(ActivityInfo.Layout layout) {
+    private int getFinalHeight(ActivityInfo.WindowLayout windowLayout) {
         int height = mDefaultFreeformHeight;
-        if (layout.height > 0) {
-            height = layout.height;
+        if (windowLayout.height > 0) {
+            height = windowLayout.height;
         }
-        if (layout.heightFraction > 0) {
-            height = (int) (mAvailableRect.height() * layout.heightFraction);
+        if (windowLayout.heightFraction > 0) {
+            height = (int) (mAvailableRect.height() * windowLayout.heightFraction);
         }
         return height;
     }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 8039072..b8f45bc 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -208,7 +208,10 @@
             String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues, Bundle options, IActivityContainer container)
             throws TransactionTooLargeException {
-        synchronized(owner) {
+        if (intent != null) intent.setDefusable(true);
+        if (options != null) options.setDefusable(true);
+
+        synchronized (owner) {
             final ActivityContainer activityContainer = (ActivityContainer)container;
             if (activityContainer != null && activityContainer.mParentActivity != null &&
                     activityContainer.mParentActivity.state
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
new file mode 100644
index 0000000..1825c88
--- /dev/null
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
+import android.app.AppOpsManager;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.util.ProgressReporter;
+
+import java.util.List;
+
+/**
+ * Simple broadcaster that sends {@link Intent#ACTION_PRE_BOOT_COMPLETED} to all
+ * system apps that register for it. Override {@link #onFinished()} to handle
+ * when all broadcasts are finished.
+ */
+public abstract class PreBootBroadcaster extends IIntentReceiver.Stub {
+    private static final String TAG = "PreBootBroadcaster";
+
+    private final ActivityManagerService mService;
+    private final int mUserId;
+    private final ProgressReporter mProgress;
+
+    private final Intent mIntent;
+    private final List<ResolveInfo> mTargets;
+
+    private int mIndex = 0;
+
+    public PreBootBroadcaster(ActivityManagerService service, int userId,
+            ProgressReporter progress) {
+        mService = service;
+        mUserId = userId;
+        mProgress = progress;
+
+        mIntent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+        mIntent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE | Intent.FLAG_DEBUG_TRIAGED_MISSING);
+
+        mTargets = mService.mContext.getPackageManager().queryBroadcastReceiversAsUser(mIntent,
+                MATCH_SYSTEM_ONLY, UserHandle.of(userId));
+    }
+
+    public void sendNext() {
+        if (mIndex >= mTargets.size()) {
+            onFinished();
+            return;
+        }
+
+        final ResolveInfo ri = mTargets.get(mIndex++);
+        final ComponentName componentName = ri.activityInfo.getComponentName();
+
+        final CharSequence label = ri.activityInfo.loadLabel(mService.mContext.getPackageManager());
+        mProgress.setProgress(mIndex, mTargets.size(),
+                mService.mContext.getString(R.string.android_preparing_apk, label));
+
+        Slog.i(TAG, "Pre-boot of " + componentName.toShortString() + " for user " + mUserId);
+        EventLogTags.writeAmPreBoot(mUserId, componentName.getPackageName());
+
+        mIntent.setComponent(componentName);
+        mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
+                AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
+                Process.SYSTEM_UID, mUserId);
+    }
+
+    @Override
+    public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+            boolean ordered, boolean sticky, int sendingUser) {
+        sendNext();
+    }
+
+    public abstract void onFinished();
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b49370b..f073e5c 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -124,6 +124,13 @@
     // Memory pages are 4K.
     static final int PAGE_SIZE = 4*1024;
 
+    // Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE
+    static final int SCHED_GROUP_BACKGROUND = 0;
+    // Activity manager's version of Process.THREAD_GROUP_DEFAULT
+    static final int SCHED_GROUP_DEFAULT = 1;
+    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
+    static final int SCHED_GROUP_TOP_APP = 2;
+
     // The minimum number of cached apps we want to be able to keep around,
     // without empty apps being able to push them out of memory.
     static final int MIN_CACHED_APPS = 2;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b4aa4cf..93d4060 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -24,7 +24,8 @@
 import android.util.DebugUtils;
 import android.util.EventLog;
 import android.util.Slog;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ProcessState;
 import com.android.internal.os.BatteryStatsImpl;
 
 import android.app.ActivityManager;
@@ -69,7 +70,7 @@
     IApplicationThread thread;  // the actual proc...  may be null only if
                                 // 'persistent' is true (in which case we
                                 // are in the process of launching the app)
-    ProcessStats.ProcessState baseProcessTracker;
+    ProcessState baseProcessTracker;
     BatteryStatsImpl.Uid.Proc curProcBatteryStats;
     int pid;                    // The process of this application; 0 if none
     int[] gids;                 // The gids this process was launched with
@@ -116,6 +117,7 @@
     boolean killed;             // True once we know the process has been killed
     boolean procStateChanged;   // Keep track of whether we changed 'setAdj'.
     boolean reportedInteraction;// Whether we have told usage stats about it being an interaction
+    boolean unlocked;           // True when proc was started in user unlocked state
     long interactionEventTime;  // The time we sent the last interaction event
     long fgInteractionTime;     // When we became foreground for interaction purposes
     String waitingToKill;       // Process is waiting to be killed when in the bg, and reason
@@ -443,7 +445,7 @@
 
     public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
         if (thread == null) {
-            final ProcessStats.ProcessState origBase = baseProcessTracker;
+            final ProcessState origBase = baseProcessTracker;
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
                         tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
@@ -469,7 +471,7 @@
 
     public void makeInactive(ProcessStatsService tracker) {
         thread = null;
-        final ProcessStats.ProcessState origBase = baseProcessTracker;
+        final ProcessState origBase = baseProcessTracker;
         if (origBase != null) {
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
@@ -558,7 +560,7 @@
             }
             EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
             Process.killProcessQuiet(pid);
-            Process.killProcessGroup(info.uid, pid);
+            ActivityManagerService.killProcessGroup(uid, pid);
             if (!persistent) {
                 killed = true;
                 killedByAm = true;
@@ -695,7 +697,7 @@
 
                 }
                 pkgList.clear();
-                ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+                ProcessState ps = tracker.getProcessStateLocked(
                         info.packageName, uid, info.versionCode, processName);
                 ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
                         info.versionCode);
diff --git a/services/core/java/com/android/server/am/ProcessStartLogger.java b/services/core/java/com/android/server/am/ProcessStartLogger.java
deleted file mode 100644
index d2aa966..0000000
--- a/services/core/java/com/android/server/am/ProcessStartLogger.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.android.server.am;
-
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-
-import android.app.AppGlobals;
-import android.auditing.SecurityLog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.Process.ProcessStartResult;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-
-/**
- * A class that logs process start information (including APK hash) to the security log.
- */
-class ProcessStartLogger {
-    private static final String CLASS_NAME = "ProcessStartLogger";
-    private static final String TAG = TAG_WITH_CLASS_NAME ? CLASS_NAME : TAG_AM;
-
-    final HandlerThread mHandlerProcessLoggingThread;
-    Handler mHandlerProcessLogging;
-    // Should only access in mHandlerProcessLoggingThread
-    final HashMap<String, String> mProcessLoggingApkHashes;
-
-    ProcessStartLogger() {
-        mHandlerProcessLoggingThread = new HandlerThread(CLASS_NAME,
-                Process.THREAD_PRIORITY_BACKGROUND);
-        mProcessLoggingApkHashes = new HashMap();
-    }
-
-    void logIfNeededLocked(ProcessRecord app, ProcessStartResult startResult) {
-        if (!SecurityLog.isLoggingEnabled()) {
-            return;
-        }
-        if (!mHandlerProcessLoggingThread.isAlive()) {
-            mHandlerProcessLoggingThread.start();
-            mHandlerProcessLogging = new Handler(mHandlerProcessLoggingThread.getLooper());
-        }
-        mHandlerProcessLogging.post(new ProcessLoggingRunnable(app, startResult,
-                System.currentTimeMillis()));
-    }
-
-    void registerListener(Context context) {
-        IntentFilter packageChangedFilter = new IntentFilter();
-        packageChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        packageChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        context.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
-                        || Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
-                    int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                            getSendingUserId());
-                    String packageName = intent.getData().getSchemeSpecificPart();
-                    try {
-                        ApplicationInfo info = AppGlobals.getPackageManager().getApplicationInfo(
-                                packageName, 0, userHandle);
-                        invaildateCache(info.sourceDir);
-                    } catch (RemoteException e) {
-                    }
-                }
-            }
-        }, packageChangedFilter);
-    }
-
-    private void invaildateCache(final String apkPath) {
-        if (mHandlerProcessLogging != null) {
-            mHandlerProcessLogging.post(new Runnable() {
-                @Override
-                public void run() {
-                    mProcessLoggingApkHashes.remove(apkPath);
-                }
-            });
-        }
-    }
-
-    private class ProcessLoggingRunnable implements Runnable {
-
-        private final ProcessRecord app;
-        private final Process.ProcessStartResult startResult;
-        private final long startTimestamp;
-
-        public ProcessLoggingRunnable(ProcessRecord app, Process.ProcessStartResult startResult,
-                long startTimestamp){
-            this.app = app;
-            this.startResult = startResult;
-            this.startTimestamp = startTimestamp;
-        }
-
-        @Override
-        public void run() {
-            String apkHash = computeStringHashOfApk(app);
-            SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START,
-                    app.processName,
-                    startTimestamp,
-                    app.uid,
-                    startResult.pid,
-                    app.info.seinfo,
-                    apkHash);
-        }
-
-        private String computeStringHashOfApk(ProcessRecord app){
-            final String apkFile = app.info.sourceDir;
-            if(apkFile == null) {
-                return "No APK";
-            }
-            String apkHash = mProcessLoggingApkHashes.get(apkFile);
-            if (apkHash == null) {
-                try {
-                    byte[] hash = computeHashOfApkFile(apkFile);
-                    StringBuilder sb = new StringBuilder();
-                    for (int i = 0; i < hash.length; i++) {
-                        sb.append(String.format("%02x", hash[i]));
-                    }
-                    apkHash = sb.toString();
-                    mProcessLoggingApkHashes.put(apkFile, apkHash);
-                } catch (IOException | NoSuchAlgorithmException e) {
-                    Slog.w(TAG, "computeStringHashOfApk() failed", e);
-                }
-            }
-            return apkHash != null ? apkHash : "Failed to count APK hash";
-        }
-
-        private byte[] computeHashOfApkFile(String packageArchiveLocation)
-                throws IOException, NoSuchAlgorithmException {
-            MessageDigest md = MessageDigest.getInstance("SHA-256");
-            FileInputStream input = new FileInputStream(new File(packageArchiveLocation));
-            byte[] buffer = new byte[65536];
-            int size;
-            while((size = input.read(buffer)) > 0) {
-                md.update(buffer, 0, size);
-            }
-            input.close();
-            return md.digest();
-        }
-    }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 9634dff..8d2b1c2 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -28,8 +28,11 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
-import com.android.internal.app.IProcessStats;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.DumpUtils;
+import com.android.internal.app.procstats.IProcessStats;
+import com.android.internal.app.procstats.ProcessState;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.os.BackgroundThread;
 
 import java.io.File;
@@ -107,12 +110,12 @@
         }
     }
 
-    public ProcessStats.ProcessState getProcessStateLocked(String packageName,
+    public ProcessState getProcessStateLocked(String packageName,
             int uid, int versionCode, String processName) {
         return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName);
     }
 
-    public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid,
+    public ServiceState getServiceStateLocked(String packageName, int uid,
             int versionCode, String processName, String className) {
         return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
                 className);
@@ -143,22 +146,10 @@
                     final SparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid);
                     for (int iver=vers.size()-1; iver>=0; iver--) {
                         final ProcessStats.PackageState pkg = vers.valueAt(iver);
-                        final ArrayMap<String, ProcessStats.ServiceState> services = pkg.mServices;
+                        final ArrayMap<String, ServiceState> services = pkg.mServices;
                         for (int isvc=services.size()-1; isvc>=0; isvc--) {
-                            final ProcessStats.ServiceState service = services.valueAt(isvc);
-                            if (service.isRestarting()) {
-                                service.setRestarting(true, memFactor, now);
-                            } else if (service.isInUse()) {
-                                if (service.mStartedState != ProcessStats.STATE_NOTHING) {
-                                    service.setStarted(true, memFactor, now);
-                                }
-                                if (service.mBoundState != ProcessStats.STATE_NOTHING) {
-                                    service.setBound(true, memFactor, now);
-                                }
-                                if (service.mExecState != ProcessStats.STATE_NOTHING) {
-                                    service.setExecuting(true, memFactor, now);
-                                }
-                            }
+                            final ServiceState service = services.valueAt(isvc);
+                            service.setMemFactor(memFactor, now);
                         }
                     }
                 }
@@ -294,12 +285,11 @@
             if (stats.mReadError != null) {
                 Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError);
                 if (DEBUG) {
-                    ArrayMap<String, SparseArray<ProcessStats.ProcessState>> procMap
-                            = stats.mProcesses.getMap();
+                    ArrayMap<String, SparseArray<ProcessState>> procMap = stats.mProcesses.getMap();
                     final int NPROC = procMap.size();
                     for (int ip=0; ip<NPROC; ip++) {
                         Slog.w(TAG, "Process: " + procMap.keyAt(ip));
-                        SparseArray<ProcessStats.ProcessState> uids = procMap.valueAt(ip);
+                        SparseArray<ProcessState> uids = procMap.valueAt(ip);
                         final int NUID = uids.size();
                         for (int iu=0; iu<NUID; iu++) {
                             Slog.w(TAG, "  Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
@@ -387,13 +377,13 @@
     boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
             boolean sepProcStates, int[] procStates, long now, String reqPackage) {
-        ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked(
+        ArrayList<ProcessState> procs = mProcessStats.collectProcessesLocked(
                 screenStates, memStates, procStates, procStates, now, reqPackage, false);
         if (procs.size() > 0) {
             if (header != null) {
                 pw.println(header);
             }
-            ProcessStats.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
+            DumpUtils.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
                     sepMemStates, memStates, sepProcStates, procStates, now);
             return true;
         }
@@ -668,8 +658,8 @@
                     }
                     boolean[] sep = new boolean[1];
                     String[] error = new String[1];
-                    csvScreenStats = parseStateList(ProcessStats.ADJ_SCREEN_NAMES_CSV, ProcessStats.ADJ_SCREEN_MOD,
-                            args[i], sep, error);
+                    csvScreenStats = parseStateList(DumpUtils.ADJ_SCREEN_NAMES_CSV,
+                            ProcessStats.ADJ_SCREEN_MOD, args[i], sep, error);
                     if (csvScreenStats == null) {
                         pw.println("Error in \"" + args[i] + "\": " + error[0]);
                         dumpHelp(pw);
@@ -685,7 +675,8 @@
                     }
                     boolean[] sep = new boolean[1];
                     String[] error = new String[1];
-                    csvMemStats = parseStateList(ProcessStats.ADJ_MEM_NAMES_CSV, 1, args[i], sep, error);
+                    csvMemStats = parseStateList(DumpUtils.ADJ_MEM_NAMES_CSV, 1, args[i],
+                            sep, error);
                     if (csvMemStats == null) {
                         pw.println("Error in \"" + args[i] + "\": " + error[0]);
                         dumpHelp(pw);
@@ -701,7 +692,8 @@
                     }
                     boolean[] sep = new boolean[1];
                     String[] error = new String[1];
-                    csvProcStats = parseStateList(ProcessStats.STATE_NAMES_CSV, 1, args[i], sep, error);
+                    csvProcStats = parseStateList(DumpUtils.STATE_NAMES_CSV, 1, args[i],
+                            sep, error);
                     if (csvProcStats == null) {
                         pw.println("Error in \"" + args[i] + "\": " + error[0]);
                         dumpHelp(pw);
@@ -839,19 +831,19 @@
             if (!csvSepScreenStats) {
                 for (int i=0; i<csvScreenStats.length; i++) {
                     pw.print(" ");
-                    ProcessStats.printScreenLabelCsv(pw, csvScreenStats[i]);
+                    DumpUtils.printScreenLabelCsv(pw, csvScreenStats[i]);
                 }
             }
             if (!csvSepMemStats) {
                 for (int i=0; i<csvMemStats.length; i++) {
                     pw.print(" ");
-                    ProcessStats.printMemLabelCsv(pw, csvMemStats[i]);
+                    DumpUtils.printMemLabelCsv(pw, csvMemStats[i]);
                 }
             }
             if (!csvSepProcStats) {
                 for (int i=0; i<csvProcStats.length; i++) {
                     pw.print(" ");
-                    pw.print(ProcessStats.STATE_NAMES_CSV[csvProcStats[i]]);
+                    pw.print(DumpUtils.STATE_NAMES_CSV[csvProcStats[i]]);
                 }
             }
             pw.println();
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 9c139d5..fb1cda7 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -39,6 +39,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
 import java.io.File;
@@ -59,12 +60,22 @@
 
     // Maximum number recent bitmaps to keep in memory.
     private static final int MAX_RECENT_BITMAPS = 3;
+    private static final int DEFAULT_INITIAL_CAPACITY = 5;
 
     /**
      * Save recent tasks information across reboots.
      */
     private final TaskPersister mTaskPersister;
-    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(5);
+    private final ActivityManagerService mService;
+    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
+            DEFAULT_INITIAL_CAPACITY);
+
+    /**
+     * Stores for each user task ids that are taken by tasks residing in persistent storage. These
+     * tasks may or may not currently be in memory.
+     */
+    final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>(
+            DEFAULT_INITIAL_CAPACITY);
 
     // Mainly to avoid object recreation on multiple calls.
     private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
@@ -75,6 +86,7 @@
 
     RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) {
         File systemDir = Environment.getDataSystemDirectory();
+        mService = service;
         mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, service, this);
         mStackSupervisor.setRecentTasks(this);
     }
@@ -87,6 +99,8 @@
      */
     void loadUserRecentsLocked(int userId) {
         if (!mUsersWithRecentsLoaded.get(userId)) {
+            // Load the task ids if not loaded.
+            loadPersistedTaskIdsForUserLocked(userId);
             Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
             addAll(mTaskPersister.restoreTasksForUserLocked(userId));
             cleanupLocked(userId);
@@ -94,21 +108,56 @@
         }
     }
 
+    private void loadPersistedTaskIdsForUserLocked(int userId) {
+        // An empty instead of a null set here means that no persistent taskIds were present
+        // on file when we loaded them.
+        if (mPersistedTaskIds.get(userId) == null) {
+            mPersistedTaskIds.put(userId, mTaskPersister.loadPersistedTaskIdsForUser(userId));
+            Slog.i(TAG, "Loaded persisted task ids for user " + userId);
+        }
+    }
+
+    boolean taskIdTakenForUserLocked(int taskId, int userId) {
+        loadPersistedTaskIdsForUserLocked(userId);
+        return mPersistedTaskIds.get(userId).get(taskId);
+    }
+
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
         if (task != null && task.stack != null && task.stack.isHomeStack()) {
             // Never persist the home stack.
             return;
         }
+        syncPersistentTaskIdsLocked();
         mTaskPersister.wakeup(task, flush);
     }
 
-    void onSystemReady() {
-        clear();
-        loadUserRecentsLocked(UserHandle.USER_SYSTEM);
-        startPersisting();
+    private void syncPersistentTaskIdsLocked() {
+        for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) {
+            int userId = mPersistedTaskIds.keyAt(i);
+            if (mUsersWithRecentsLoaded.get(userId)) {
+                // Recents are loaded only after task ids are loaded. Therefore, the set of taskids
+                // referenced here should not be null.
+                mPersistedTaskIds.valueAt(i).clear();
+            }
+        }
+        for (int i = size() - 1; i >= 0; i--) {
+            TaskRecord task = get(i);
+            if (task.isPersistable && (task.stack == null || !task.stack.isHomeStack())) {
+                // Set of persisted taskIds for task.userId should not be null here
+                // TODO Investigate why it can happen. For now initialize with an empty set
+                if (mPersistedTaskIds.get(task.userId) == null) {
+                    Slog.wtf(TAG, "No task ids found for userId " + task.userId + ". task=" + task
+                            + " mPersistedTaskIds=" + mPersistedTaskIds);
+                    mPersistedTaskIds.put(task.userId, new SparseBooleanArray());
+                }
+                mPersistedTaskIds.get(task.userId).put(task.taskId, true);
+            }
+        }
     }
 
-    void startPersisting() {
+
+    void onSystemReadyLocked() {
+        clear();
         mTaskPersister.startPersisting();
     }
 
@@ -125,11 +174,14 @@
     }
 
     void flush() {
+        synchronized (mService) {
+            syncPersistentTaskIdsLocked();
+        }
         mTaskPersister.flush();
     }
 
     /**
-     * Returns all userIds for which recents from storage are loaded
+     * Returns all userIds for which recents from persistent storage are loaded into this list.
      *
      * @return an array of userIds.
      */
@@ -149,12 +201,7 @@
         return usersWithRecentsLoaded;
     }
 
-    /**
-     * Removes recent tasks for this user if they are loaded, does not do anything otherwise.
-     *
-     * @param userId the user id.
-     */
-    void unloadUserRecentsLocked(int userId) {
+    private void unloadUserRecentsLocked(int userId) {
         if (mUsersWithRecentsLoaded.get(userId)) {
             Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
             mUsersWithRecentsLoaded.delete(userId);
@@ -162,6 +209,18 @@
         }
     }
 
+    /**
+     * Removes recent tasks and any other state kept in memory for the passed in user. Does not
+     * touch the information present on persistent storage.
+     *
+     * @param userId the id of the user
+     */
+    void unloadUserDataFromMemoryLocked(int userId) {
+        unloadUserRecentsLocked(userId);
+        mPersistedTaskIds.delete(userId);
+        mTaskPersister.unloadUserDataFromMemory(userId);
+    }
+
     TaskRecord taskForIdLocked(int id) {
         final int recentsCount = size();
         for (int i = 0; i < recentsCount; i++) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 87cb40e..5075c3a 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -16,7 +16,7 @@
 
 package com.android.server.am;
 
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.LocalServices;
 import com.android.server.notification.NotificationManagerInternal;
@@ -88,8 +88,8 @@
 
     ProcessRecord app;      // where this service is running or null.
     ProcessRecord isolatedProc; // keep track of isolated process, if requested
-    ProcessStats.ServiceState tracker; // tracking service execution, may be null
-    ProcessStats.ServiceState restartTracker; // tracking service restart
+    ServiceState tracker; // tracking service execution, may be null
+    ServiceState restartTracker; // tracking service restart
     boolean delayed;        // are we waiting to start this service in the background?
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
@@ -326,7 +326,7 @@
         createdFromFg = callerIsFg;
     }
 
-    public ProcessStats.ServiceState getTracker() {
+    public ServiceState getTracker() {
         if (tracker != null) {
             return tracker;
         }
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 283939e..ceb7db6 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Debug;
@@ -26,11 +29,13 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.Xml;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
-
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -38,9 +43,12 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.util.ArrayList;
@@ -71,6 +79,7 @@
     private static final String TASKS_DIRNAME = "recent_tasks";
     private static final String TASK_EXTENSION = ".xml";
     private static final String IMAGES_DIRNAME = "recent_images";
+    private static final String PERSISTED_TASK_IDS_FILENAME = "persisted_taskIds.txt";
     static final String IMAGE_EXTENSION = ".png";
 
     private static final String TAG_TASK = "task";
@@ -78,6 +87,8 @@
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private final RecentTasks mRecentTasks;
+    private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
+    private final File mTaskIdsDir;
 
     /**
      * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
@@ -129,12 +140,22 @@
             }
         }
 
+        mTaskIdsDir = new File(Environment.getDataDirectory(), "system_de");
         mStackSupervisor = stackSupervisor;
         mService = service;
         mRecentTasks = recentTasks;
         mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThread");
     }
 
+    @VisibleForTesting
+    TaskPersister(File workingDir) {
+        mTaskIdsDir = workingDir;
+        mStackSupervisor = null;
+        mService = null;
+        mRecentTasks = null;
+        mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThreadTest");
+    }
+
     void startPersisting() {
         if (!mLazyTaskWriterThread.isAlive()) {
             mLazyTaskWriterThread.start();
@@ -170,6 +191,64 @@
         }
     }
 
+    @NonNull
+    SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
+        if (mTaskIdsInFile.get(userId) != null) {
+            return mTaskIdsInFile.get(userId).clone();
+        }
+        final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
+        BufferedReader reader = null;
+        String line;
+        try {
+            reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
+            while ((line = reader.readLine()) != null) {
+                for (String taskIdString : line.split("\\s+")) {
+                    int id = Integer.parseInt(taskIdString);
+                    persistedTaskIds.put(id, true);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // File doesn't exist. Ignore.
+        } catch (Exception e) {
+            Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
+        } finally {
+            IoUtils.closeQuietly(reader);
+        }
+        mTaskIdsInFile.put(userId, persistedTaskIds);
+        return persistedTaskIds.clone();
+    }
+
+    @VisibleForTesting
+    void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
+        if (userId < 0) {
+            return;
+        }
+        SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
+        if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
+            return;
+        }
+        final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
+        BufferedWriter writer = null;
+        try {
+            writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
+            for (int i = 0; i < taskIds.size(); i++) {
+                if (taskIds.valueAt(i)) {
+                    writer.write(String.valueOf(taskIds.keyAt(i)));
+                    writer.newLine();
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
+        } finally {
+            IoUtils.closeQuietly(writer);
+        }
+        mTaskIdsInFile.put(userId, taskIds.clone());
+    }
+
+    void unloadUserDataFromMemory(int userId) {
+        mTaskIdsInFile.delete(userId);
+    }
+
     void wakeup(TaskRecord task, boolean flush) {
         synchronized (this) {
             if (task != null) {
@@ -336,14 +415,16 @@
 
         File[] recentFiles = userTasksDir.listFiles();
         if (recentFiles == null) {
-            Slog.e(TAG, "restoreTasksForUser: Unable to list files from " + userTasksDir);
+            Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);
             return tasks;
         }
 
         for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
             File taskFile = recentFiles[taskNdx];
-            if (DEBUG) Slog.d(TAG, "restoreTasksForUser: userId=" + userId
-                    + ", taskFile=" + taskFile.getName());
+            if (DEBUG) {
+                Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
+                        + ", taskFile=" + taskFile.getName());
+            }
             BufferedReader reader = null;
             boolean deleteFile = false;
             try {
@@ -366,20 +447,29 @@
                                 // out the stuff we just read, if we don't write it we will
                                 // read the same thing again.
                                 // mWriteQueue.add(new TaskWriteQueueItem(task));
+
                                 final int taskId = task.taskId;
-                                mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
-                                // Check if it's a valid user id. Don't add tasks for removed users.
-                                if (userId == task.userId) {
+                                if (mStackSupervisor.anyTaskForIdLocked(taskId,
+                                        /* restoreFromRecents= */ false, 0) != null) {
+                                    // Should not happen.
+                                    Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
+                                } else if (userId != task.userId) {
+                                    // Should not happen.
+                                    Slog.wtf(TAG, "Task with userId " + task.userId + " found in "
+                                            + userTasksDir.getAbsolutePath());
+                                } else {
+                                    // Looks fine.
+                                    mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
                                     task.isPersistable = true;
                                     tasks.add(task);
                                     recoveredTaskIds.add(taskId);
                                 }
                             } else {
-                                Slog.e(TAG, "restoreTasksForUser: Unable to restore taskFile="
+                                Slog.e(TAG, "restoreTasksForUserLocked: Unable to restore taskFile="
                                         + taskFile + ": " + fileToString(taskFile));
                             }
                         } else {
-                            Slog.wtf(TAG, "restoreTasksForUser: Unknown xml event=" + event
+                            Slog.wtf(TAG, "restoreTasksForUserLocked: Unknown xml event=" + event
                                     + " name=" + name);
                         }
                     }
@@ -454,6 +544,20 @@
         }
     }
 
+    private void writeTaskIdsFiles() {
+        int candidateUserIds[];
+        synchronized (mService) {
+            candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
+        }
+        SparseBooleanArray taskIdsToSave;
+        for (int userId : candidateUserIds) {
+            synchronized (mService) {
+                taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
+            }
+            maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
+        }
+    }
+
     private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) {
         int[] candidateUserIds;
         synchronized (mService) {
@@ -472,8 +576,16 @@
         return BitmapFactory.decodeFile(filename);
     }
 
+    private File getUserPersistedTaskIdsFile(int userId) {
+        File userTaskIdsDir = new File(mTaskIdsDir, String.valueOf(userId));
+        if (!userTaskIdsDir.exists() && !userTaskIdsDir.mkdirs()) {
+            Slog.e(TAG, "Error while creating user directory: " + userTaskIdsDir);
+        }
+        return new File(userTaskIdsDir, PERSISTED_TASK_IDS_FILENAME);
+    }
+
     static File getUserTasksDir(int userId) {
-        File userTasksDir = new File(Environment.getUserSystemDirectory(userId), TASKS_DIRNAME);
+        File userTasksDir = new File(Environment.getDataSystemCeDirectory(userId), TASKS_DIRNAME);
 
         if (!userTasksDir.exists()) {
             if (!userTasksDir.mkdir()) {
@@ -485,7 +597,7 @@
     }
 
     static File getUserImagesDir(int userId) {
-        File userImagesDir = new File(Environment.getUserSystemDirectory(userId), IMAGES_DIRNAME);
+        File userImagesDir = new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
 
         if (!userImagesDir.exists()) {
             if (!userImagesDir.mkdir()) {
@@ -535,6 +647,7 @@
                     }
                     removeObsoleteFiles(persistentTaskIds);
                 }
+                writeTaskIdsFiles();
 
                 // If mNextWriteTime, then don't delay between each call to saveToXml().
                 final WriteQueueItem item;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 37a549a..e32d1d1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -40,6 +40,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.DisplayMetrics;
 import android.util.Slog;
@@ -71,9 +72,8 @@
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
@@ -126,10 +126,14 @@
     private static final String ATTR_RESIZE_MODE = "resize_mode";
     private static final String ATTR_PRIVILEGED = "privileged";
     private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
+    private static final String ATTR_MINIMAL_WIDTH = "minimal_width";
+    private static final String ATTR_MINIMAL_HEIGHT = "minimal_height";
+
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
     static final int INVALID_TASK_ID = -1;
+    static final int INVALID_MINIMAL_SIZE = -1;
 
     final int taskId;       // Unique identifier for this task.
     String affinity;        // The affinity name for this task, or null; may change identity.
@@ -252,9 +256,10 @@
     // The information is persisted and used to determine the appropriate stack to launch the
     // task into on restore.
     Rect mLastNonFullscreenBounds = null;
-    // Minimal size for width/height of this task when it's resizeable. -1 means it should use the
-    // default minimal size.
-    final int mMinimalSize;
+    // Minimal width and height of this task when it's resizeable. -1 means it should use the
+    // default minimal width/height.
+    int mMinimalWidth;
+    int mMinimalHeight;
 
     // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
     // This number will be assigned when we evaluate OOM scores for all visible tasks.
@@ -279,7 +284,8 @@
         mCallingUid = info.applicationInfo.uid;
         mCallingPackage = info.packageName;
         setIntent(_intent, info);
-        mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
+        setMinDimensions(info);
+        touchActiveTime();
     }
 
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
@@ -299,6 +305,7 @@
         mCallingUid = info.applicationInfo.uid;
         mCallingPackage = info.packageName;
         setIntent(_intent, info);
+        setMinDimensions(info);
 
         taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
         isPersistable = true;
@@ -309,7 +316,7 @@
         taskType = APPLICATION_ACTIVITY_TYPE;
         mTaskToReturnTo = HOME_ACTIVITY_TYPE;
         lastTaskDescription = _taskDescription;
-        mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
+        touchActiveTime();
     }
 
     private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
@@ -322,7 +329,7 @@
             TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
             int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
             int resizeMode, boolean privileged, boolean _realActivitySuspended,
-            boolean userSetupComplete) {
+            boolean userSetupComplete, int minimalWidth, int minimalHeight) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -362,8 +369,8 @@
         mCallingPackage = callingPackage;
         mResizeMode = resizeMode;
         mPrivileged = privileged;
-        ActivityInfo info = (mActivities.size() > 0) ? mActivities.get(0).info : null;
-        mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
+        mMinimalWidth = minimalWidth;
+        mMinimalHeight = minimalHeight;
     }
 
     void touchActiveTime() {
@@ -444,9 +451,9 @@
             // task as having a true root activity.
             rootWasReset = true;
         }
-
         userId = UserHandle.getUserId(info.applicationInfo.uid);
-        mUserSetupComplete = mService.mUserController.isUserSetupCompleteLocked(userId);
+        mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
+                USER_SETUP_COMPLETE, 0, userId) != 0;
         if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
             // If the activity itself has requested auto-remove, then just always do it.
             autoRemoveRecents = true;
@@ -469,6 +476,30 @@
         setLockTaskAuth();
     }
 
+    /** Sets the original minimal width and height. */
+    private void setMinDimensions(ActivityInfo info) {
+        if (info != null && info.windowLayout != null) {
+            mMinimalWidth = info.windowLayout.minimalWidth;
+            mMinimalHeight = info.windowLayout.minimalHeight;
+        } else {
+            mMinimalWidth = INVALID_MINIMAL_SIZE;
+            mMinimalHeight = INVALID_MINIMAL_SIZE;
+        }
+    }
+
+    /**
+     * Return true if the input activity has the same intent resolution as the intent this task
+     * record is based on (normally the root activity intent).
+     */
+    boolean isSameIntentResolution(ActivityRecord r) {
+        final Intent intent = new Intent(r.intent);
+        // Correct the activity intent for aliasing. The task record intent will always be based on
+        // the real activity that will be launched not the alias, so we need to use an intent with
+        // the component name pointing to the real activity not the alias in the activity record.
+        intent.setComponent(r.realActivity);
+        return this.intent.filterEquals(intent);
+    }
+
     void setTaskToReturnTo(int taskToReturnTo) {
         mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
                 ? HOME_ACTIVITY_TYPE : taskToReturnTo;
@@ -744,6 +775,14 @@
         if (r.isPersistable()) {
             mService.notifyTaskPersisterLocked(this, false);
         }
+
+        if (stack != null && stack.mStackId == PINNED_STACK_ID) {
+            // We normally notify listeners of task stack changes on pause, however pinned stack
+            // activities are normally in the paused state so no notification will be sent there
+            // before the activity is removed. We send it here so instead.
+            mService.notifyTaskStackChangedLocked();
+        }
+
         if (mActivities.isEmpty()) {
             return !mReuseTask;
         }
@@ -1113,6 +1152,8 @@
             out.attribute(
                     null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
         }
+        out.attribute(null, ATTR_MINIMAL_WIDTH, String.valueOf(mMinimalWidth));
+        out.attribute(null, ATTR_MINIMAL_HEIGHT, String.valueOf(mMinimalHeight));
 
         if (affinityIntent != null) {
             out.startTag(null, TAG_AFFINITYINTENT);
@@ -1177,6 +1218,8 @@
         int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
         boolean privileged = false;
         Rect bounds = null;
+        int minimalWidth = INVALID_MINIMAL_SIZE;
+        int minimalHeight = INVALID_MINIMAL_SIZE;
 
         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
             final String attrName = in.getAttributeName(attrNdx);
@@ -1244,6 +1287,10 @@
                 privileged = Boolean.valueOf(attrValue);
             } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
                 bounds = Rect.unflattenFromString(attrValue);
+            } else if (ATTR_MINIMAL_WIDTH.equals(attrName)) {
+                minimalWidth = Integer.valueOf(attrValue);
+            } else if (ATTR_MINIMAL_HEIGHT.equals(attrName)) {
+                minimalHeight = Integer.valueOf(attrValue);
             } else {
                 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
             }
@@ -1304,7 +1351,7 @@
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
                 taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
                 taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
-                realActivitySuspended, userSetupComplete);
+                realActivitySuspended, userSetupComplete, minimalWidth, minimalHeight);
         task.updateOverrideConfiguration(bounds);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
@@ -1319,30 +1366,41 @@
         if (bounds == null) {
             return;
         }
-        final int minimalSize = mMinimalSize == -1
-                ? mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask : mMinimalSize;
-        final boolean adjustWidth = minimalSize > bounds.width();
-        final boolean adjustHeight = minimalSize > bounds.height();
+        int minimalWidth = mMinimalWidth;
+        int minimalHeight = mMinimalHeight;
+        // If the task has no requested minimal size, we'd like to enforce a minimal size
+        // so that the user can not render the task too small to manipulate. We don't need
+        // to do this for the pinned stack as the bounds are controlled by the system.
+        if (stack.mStackId != PINNED_STACK_ID) {
+            if (minimalWidth == INVALID_MINIMAL_SIZE) {
+                minimalWidth = mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask;
+            }
+            if (minimalHeight == INVALID_MINIMAL_SIZE) {
+                minimalHeight = mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask;
+            }
+        }
+        final boolean adjustWidth = minimalWidth > bounds.width();
+        final boolean adjustHeight = minimalHeight > bounds.height();
         if (!(adjustWidth || adjustHeight)) {
             return;
         }
 
         if (adjustWidth) {
             if (mBounds != null && bounds.right == mBounds.right) {
-                bounds.left = bounds.right - minimalSize;
+                bounds.left = bounds.right - minimalWidth;
             } else {
                 // Either left bounds match, or neither match, or the previous bounds were
                 // fullscreen and we default to keeping left.
-                bounds.right = bounds.left + minimalSize;
+                bounds.right = bounds.left + minimalWidth;
             }
         }
         if (adjustHeight) {
             if (mBounds != null && bounds.bottom == mBounds.bottom) {
-                bounds.top = bounds.bottom - minimalSize;
+                bounds.top = bounds.bottom - minimalHeight;
             } else {
                 // Either top bounds match, or neither match, or the previous bounds were
                 // fullscreen and we default to keeping top.
-                bounds.bottom = bounds.top + minimalSize;
+                bounds.bottom = bounds.top + minimalHeight;
             }
         }
     }
@@ -1393,7 +1451,7 @@
         }
 
         if (mFullscreen != oldFullscreen) {
-            mService.mStackSupervisor.scheduleReportMultiWindowChanged(this);
+            mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this);
         }
 
         return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
@@ -1474,6 +1532,9 @@
     Rect updateOverrideConfigurationFromLaunchBounds() {
         final Rect bounds = validateBounds(getLaunchBounds());
         updateOverrideConfiguration(bounds);
+        if (bounds != null) {
+            bounds.set(mBounds);
+        }
         return bounds;
     }
 
@@ -1557,6 +1618,7 @@
         pw.print(prefix); pw.print("userId="); pw.print(userId);
                 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
                 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
+                pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
                 pw.print(" mCallingPackage="); pw.println(mCallingPackage);
         if (affinity != null || rootAffinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.print(affinity);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4e6dc3a..aef454e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -24,7 +24,7 @@
 import static android.app.ActivityManager.USER_OP_SUCCESS;
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.os.Process.SYSTEM_UID;
-import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -38,24 +38,27 @@
 import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
 import static com.android.server.am.ActivityManagerService.SYSTEM_USER_UNLOCK_MSG;
 import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
+import static com.android.server.am.UserState.STATE_BOOTING;
+import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
+import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKED;
+import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKING;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.Dialog;
 import android.app.IStopUserCallback;
 import android.app.IUserSwitchObserver;
 import android.app.KeyguardManager;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -68,20 +71,21 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
-import android.provider.Settings;
 import android.util.IntArray;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ProgressReporter;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerService;
 
 import java.io.PrintWriter;
@@ -89,6 +93,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -151,34 +156,6 @@
 
     private final LockPatternUtils mLockPatternUtils;
 
-    // Set of users who have completed the set-up process.
-    private final SparseBooleanArray mSetupCompletedUsers = new SparseBooleanArray();
-    private final UserSetupCompleteContentObserver mUserSetupCompleteContentObserver;
-
-    private class UserSetupCompleteContentObserver extends ContentObserver {
-        private final Uri mUserSetupComplete = Settings.Secure.getUriFor(USER_SETUP_COMPLETE);
-
-        public UserSetupCompleteContentObserver(Handler handler) {
-            super(handler);
-        }
-
-        void register(ContentResolver resolver) {
-            resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
-            synchronized (mService) {
-                updateUserSetupCompleteLocked(UserHandle.USER_ALL);
-            }
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri, int userId) {
-            if (mUserSetupComplete.equals(uri)) {
-                synchronized (mService) {
-                    updateUserSetupCompleteLocked(userId);
-                }
-            }
-        }
-    }
-
     UserController(ActivityManagerService service) {
         mService = service;
         mHandler = mService.mHandler;
@@ -188,7 +165,6 @@
         mUserLru.add(UserHandle.USER_SYSTEM);
         mLockPatternUtils = new LockPatternUtils(mService.mContext);
         updateStartedUserArrayLocked();
-        mUserSetupCompleteContentObserver = new UserSetupCompleteContentObserver(mHandler);
     }
 
     void finishUserSwitch(UserState uss) {
@@ -251,9 +227,7 @@
             // consistent developer events. We step into RUNNING_LOCKED here,
             // but we might immediately step into RUNNING below if the user
             // storage is already unlocked.
-            if (uss.state == UserState.STATE_BOOTING) {
-                uss.setState(UserState.STATE_RUNNING_LOCKED);
-
+            if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
                 Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -268,11 +242,10 @@
     }
 
     /**
-     * Consider stepping from {@link UserState#STATE_RUNNING_LOCKED} into
-     * {@link UserState#STATE_RUNNING}, which only occurs if the user storage is
-     * actually unlocked.
+     * Step from {@link UserState#STATE_RUNNING_LOCKED} to
+     * {@link UserState#STATE_RUNNING_UNLOCKING}.
      */
-    void finishUserUnlock(UserState uss) {
+    void finishUserUnlocking(final UserState uss, final ProgressReporter progress) {
         final int userId = uss.mHandle.getIdentifier();
         synchronized (mService) {
             // Bail if we ended up with a stale user
@@ -281,14 +254,58 @@
             // Only keep marching forward if user is actually unlocked
             if (!isUserKeyUnlocked(userId)) return;
 
-            if (uss.state == UserState.STATE_RUNNING_LOCKED) {
-                uss.setState(UserState.STATE_RUNNING);
-
-                // Give user manager a chance to prepare app storage
+            if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
+                // Prepare app storage before we go any further
+                progress.setProgress(5, mService.mContext.getString(R.string.android_start_title));
                 mUserManager.onBeforeUnlockUser(userId);
+                progress.setProgress(20);
 
+                // Send PRE_BOOT broadcasts if fingerprint changed
+                final UserInfo info = getUserInfo(userId);
+                if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
+                    progress.startSegment(80);
+                    new PreBootBroadcaster(mService, userId, progress) {
+                        @Override
+                        public void onFinished() {
+                            finishUserUnlocked(uss, progress);
+                        }
+                    }.sendNext();
+                } else {
+                    finishUserUnlocked(uss, progress);
+                }
+            }
+        }
+    }
+
+    /**
+     * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to
+     * {@link UserState#STATE_RUNNING_UNLOCKED}.
+     */
+    void finishUserUnlocked(UserState uss, ProgressReporter progress) {
+        try {
+            finishUserUnlockedInternal(uss);
+        } finally {
+            progress.finish();
+        }
+    }
+
+    void finishUserUnlockedInternal(UserState uss) {
+        final int userId = uss.mHandle.getIdentifier();
+        synchronized (mService) {
+            // Bail if we ended up with a stale user
+            if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
+
+            // Only keep marching forward if user is actually unlocked
+            if (!isUserKeyUnlocked(userId)) return;
+
+            if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) {
+                // Remember that we logged in
+                mUserManager.onUserLoggedIn(userId);
+
+                // Dispatch unlocked to system services
                 mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0));
 
+                // Dispatch unlocked to external apps
                 final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
                 unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 unlockedIntent.addFlags(
@@ -417,35 +434,17 @@
                 stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                 stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
-                final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
-                // This is the result receiver for the final shutdown broadcast.
-                final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
-                    @Override
-                    public void performReceive(Intent intent, int resultCode, String data,
-                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-                        finishUserStop(uss);
-                    }
-                };
                 // This is the result receiver for the initial stopping broadcast.
                 final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
                     @Override
                     public void performReceive(Intent intent, int resultCode, String data,
                             Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-                        // On to the next.
-                        synchronized (mService) {
-                            if (uss.state != UserState.STATE_STOPPING) {
-                                // Whoops, we are being started back up.  Abort, abort!
-                                return;
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                finishUserStopping(userId, uss);
                             }
-                            uss.setState(UserState.STATE_SHUTDOWN);
-                        }
-                        mService.mBatteryStatsService.noteEvent(
-                                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
-                                Integer.toString(userId), userId);
-                        mService.mSystemServiceManager.stopUser(userId);
-                        mService.broadcastIntentLocked(null, null, shutdownIntent,
-                                null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
-                                null, true, false, MY_PID, SYSTEM_UID, userId);
+                        });
                     }
                 };
                 // Kick things off.
@@ -459,7 +458,45 @@
         }
     }
 
-    void finishUserStop(UserState uss) {
+    void finishUserStopping(final int userId, final UserState uss) {
+        // On to the next.
+        final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+        // This is the result receiver for the final shutdown broadcast.
+        final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
+            @Override
+            public void performReceive(Intent intent, int resultCode, String data,
+                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        finishUserStopped(uss);
+                    }
+                });
+            }
+        };
+
+        synchronized (mService) {
+            if (uss.state != UserState.STATE_STOPPING) {
+                // Whoops, we are being started back up.  Abort, abort!
+                return;
+            }
+            uss.setState(UserState.STATE_SHUTDOWN);
+        }
+
+        mService.mBatteryStatsService.noteEvent(
+                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
+                Integer.toString(userId), userId);
+        mService.mSystemServiceManager.stopUser(userId);
+
+        synchronized (mService) {
+            mService.broadcastIntentLocked(null, null, shutdownIntent,
+                    null, shutdownReceiver, 0, null, null, null,
+                    AppOpsManager.OP_NONE,
+                    null, true, false, MY_PID, SYSTEM_UID, userId);
+        }
+    }
+
+    void finishUserStopped(UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
         boolean stopped;
         ArrayList<IStopUserCallback> callbacks;
@@ -475,7 +512,6 @@
                 mStartedUsers.remove(userId);
                 mUserLru.remove(Integer.valueOf(userId));
                 updateStartedUserArrayLocked();
-                mSetupCompletedUsers.delete(userId);
 
                 mService.onUserStoppedLocked(userId);
                 // Clean up all state and processes associated with the user.
@@ -561,6 +597,10 @@
                     continue;
                 }
                 UserInfo userInfo = getUserInfo(oldUserId);
+                if (userInfo.isEphemeral()) {
+                    LocalServices.getService(UserManagerInternal.class)
+                            .onEphemeralUserStop(oldUserId);
+                }
                 if (userInfo.isGuest() || userInfo.isEphemeral()) {
                     // This is a user to be stopped.
                     stopUsersLocked(oldUserId, true, null);
@@ -614,7 +654,7 @@
             }
         } else {
             Slog.w(TAG, "Mount service not published; guessing locked state based on property");
-            return !StorageManager.isFileBasedEncryptionEnabled();
+            return !StorageManager.isFileEncryptedNativeOrEmulated();
         }
     }
 
@@ -671,7 +711,6 @@
                 final Integer userIdInt = userId;
                 mUserLru.remove(userIdInt);
                 mUserLru.add(userIdInt);
-                updateUserSetupCompleteLocked(userId);
 
                 if (foreground) {
                     mCurrentUserId = userId;
@@ -746,10 +785,17 @@
                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         mService.broadcastIntentLocked(null, null, intent, null,
                                 new IIntentReceiver.Stub() {
+                                    @Override
                                     public void performReceive(Intent intent, int resultCode,
                                             String data, Bundle extras, boolean ordered,
                                             boolean sticky, int sendingUser) {
-                                        onUserInitialized(uss, foreground, oldUserId, userId);
+                                        mHandler.post(new Runnable() {
+                                            @Override
+                                            public void run() {
+                                                onUserInitialized(uss, foreground,
+                                                        oldUserId, userId);
+                                            }
+                                        });
                                     }
                                 }, 0, null, null, null, AppOpsManager.OP_NONE,
                                 null, true, false, MY_PID, SYSTEM_UID, userId);
@@ -799,7 +845,7 @@
         return result;
     }
 
-    boolean unlockUser(final int userId, byte[] token, byte[] secret) {
+    boolean unlockUser(final int userId, byte[] token, byte[] secret, ProgressReporter progress) {
         if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: unlockUser() from pid="
@@ -812,7 +858,7 @@
 
         final long binderToken = Binder.clearCallingIdentity();
         try {
-            return unlockUserCleared(userId, token, secret);
+            return unlockUserCleared(userId, token, secret, progress);
         } finally {
             Binder.restoreCallingIdentity(binderToken);
         }
@@ -826,14 +872,20 @@
      */
     boolean maybeUnlockUser(final int userId) {
         // Try unlocking storage using empty token
-        return unlockUserCleared(userId, null, null);
+        return unlockUserCleared(userId, null, null, ProgressReporter.NO_OP);
     }
 
-    boolean unlockUserCleared(final int userId, byte[] token, byte[] secret) {
+    boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
+            ProgressReporter progress) {
         synchronized (mService) {
             // Bail if already running unlocked
             final UserState uss = mStartedUsers.get(userId);
-            if (uss.state == UserState.STATE_RUNNING) return true;
+            switch (uss.state) {
+                case STATE_RUNNING_UNLOCKING:
+                case STATE_RUNNING_UNLOCKED:
+                    progress.finish();
+                    return true;
+            }
         }
 
         if (!isUserKeyUnlocked(userId)) {
@@ -843,13 +895,14 @@
                 mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret);
             } catch (RemoteException | RuntimeException e) {
                 Slog.w(TAG, "Failed to unlock: " + e.getMessage());
+                progress.finish();
                 return false;
             }
         }
 
         synchronized (mService) {
             final UserState uss = mStartedUsers.get(userId);
-            finishUserUnlock(uss);
+            finishUserUnlocking(uss, progress);
         }
 
         return true;
@@ -886,22 +939,6 @@
         mUserSwitchObservers.finishBroadcast();
     }
 
-    void updateUserSetupCompleteLocked(int userId) {
-        final ContentResolver cr = mService.mContext.getContentResolver();
-        for (int i = mStartedUsers.size() - 1; i >= 0; i--) {
-            int startedUser = mStartedUsers.keyAt(i);
-            if (startedUser == userId || userId == UserHandle.USER_ALL) {
-                final boolean setupComplete =
-                        Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, startedUser) != 0;
-                mSetupCompletedUsers.put(startedUser, setupComplete);
-            }
-        }
-    }
-
-    boolean isUserSetupCompleteLocked(int userId) {
-        return mSetupCompletedUsers.get(userId);
-    }
-
     private void stopBackgroundUsersIfEnforced(int oldUserId) {
         // Never stop system user
         if (oldUserId == UserHandle.USER_SYSTEM) {
@@ -1017,7 +1054,6 @@
             mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
         }
         EventLogTags.writeAmSwitchUser(newUserId);
-        getUserManager().onUserForeground(newUserId);
         sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
     }
 
@@ -1212,7 +1248,6 @@
 
     void onSystemReady() {
         updateCurrentProfileIdsLocked();
-        mUserSetupCompleteContentObserver.register(mService.mContext.getContentResolver());
     }
 
     /**
@@ -1266,7 +1301,8 @@
                 unlocked = false;
                 break;
 
-            case UserState.STATE_RUNNING:
+            case UserState.STATE_RUNNING_UNLOCKING:
+            case UserState.STATE_RUNNING_UNLOCKED:
                 unlocked = true;
                 break;
         }
@@ -1375,6 +1411,11 @@
      * intercept activity launches for work apps when the Work Challenge is present.
      */
     boolean shouldConfirmCredentials(int userId) {
+        synchronized (mService) {
+            if (mStartedUsers.get(userId) == null) {
+                return false;
+            }
+        }
         if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
             return false;
         }
@@ -1383,6 +1424,10 @@
         return km.isDeviceLocked(userId);
     }
 
+    boolean isLockScreenDisabled(@UserIdInt int userId) {
+        return mLockPatternUtils.isLockScreenDisabled(userId);
+    }
+
     void dump(PrintWriter pw, boolean dumpAll) {
         pw.println("  mStartedUsers:");
         for (int i = 0; i < mStartedUsers.size(); i++) {
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 7b18a17..6e2342b 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -33,14 +33,16 @@
 
     // User is first coming up.
     public final static int STATE_BOOTING = 0;
-    // User is in the locked running state.
+    // User is in the locked state.
     public final static int STATE_RUNNING_LOCKED = 1;
-    // User is in the normal running state.
-    public final static int STATE_RUNNING = 2;
+    // User is in the unlocking state.
+    public final static int STATE_RUNNING_UNLOCKING = 2;
+    // User is in the running state.
+    public final static int STATE_RUNNING_UNLOCKED = 3;
     // User is in the initial process of being stopped.
-    public final static int STATE_STOPPING = 3;
+    public final static int STATE_STOPPING = 4;
     // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
-    public final static int STATE_SHUTDOWN = 4;
+    public final static int STATE_SHUTDOWN = 5;
 
     public final UserHandle mHandle;
     public final ArrayList<IStopUserCallback> mStopCallbacks
@@ -61,6 +63,17 @@
         mHandle = handle;
     }
 
+    public boolean setState(int oldState, int newState) {
+        if (state == oldState) {
+            setState(newState);
+            return true;
+        } else {
+            Slog.w(TAG, "Expected user " + mHandle.getIdentifier() + " in state "
+                    + stateToString(oldState) + " but was in state " + stateToString(state));
+            return false;
+        }
+    }
+
     public void setState(int newState) {
         if (DEBUG_MU) {
             Slog.i(TAG, "User " + mHandle.getIdentifier() + " state changed from "
@@ -74,7 +87,8 @@
         switch (state) {
             case STATE_BOOTING: return "BOOTING";
             case STATE_RUNNING_LOCKED: return "RUNNING_LOCKED";
-            case STATE_RUNNING: return "RUNNING";
+            case STATE_RUNNING_UNLOCKING: return "RUNNING_UNLOCKING";
+            case STATE_RUNNING_UNLOCKED: return "RUNNING_UNLOCKED";
             case STATE_STOPPING: return "STOPPING";
             case STATE_SHUTDOWN: return "SHUTDOWN";
             default: return Integer.toString(state);
@@ -84,7 +98,6 @@
     void dump(String prefix, PrintWriter pw) {
         pw.print(prefix);
         pw.print("state="); pw.print(stateToString(state));
-        pw.print(" lastState="); pw.print(stateToString(lastState));
         if (switching) pw.print(" SWITCHING");
         if (initializing) pw.print(" INITIALIZING");
         pw.println();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 548f563..f471af6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -28,6 +28,7 @@
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.NotificationManager;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
@@ -40,6 +41,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
@@ -58,7 +60,7 @@
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.AudioPort;
-import android.media.AudioRecordConfiguration;
+import android.media.AudioRecordingConfiguration;
 import android.media.AudioRoutesInfo;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioRoutesObserver;
@@ -105,9 +107,6 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.view.KeyEvent;
-import android.view.OrientationEventListener;
-import android.view.Surface;
-import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.util.XmlUtils;
@@ -206,7 +205,6 @@
     private static final int MSG_SET_FORCE_USE = 8;
     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
     private static final int MSG_SET_ALL_VOLUMES = 10;
-    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
     private static final int MSG_REPORT_NEW_ROUTES = 12;
     private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
     private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
@@ -218,11 +216,9 @@
     private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
     private static final int MSG_SYSTEM_READY = 21;
     private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
-    private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
     private static final int MSG_UNMUTE_STREAM = 24;
     private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
     private static final int MSG_INDICATE_SYSTEM_READY = 26;
-    private static final int MSG_PERSIST_MASTER_MONO = 27;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -558,6 +554,7 @@
 
     private static Long mLastDeviceConnectMsgTime = new Long(0);
 
+    private NotificationManager mNm;
     private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
     private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
     private long mLoweredFromNormalToVibrateTime;
@@ -666,6 +663,7 @@
         // array initialized by updateStreamVolumeAlias()
         updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
         readPersistedSettings();
+        readUserRestrictions();
         mSettingsObserver = new SettingsObserver();
         createStreamStates();
 
@@ -752,6 +750,8 @@
             }
         }
 
+        mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+
         sendMsg(mAudioHandler,
                 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
                 SENDMSG_REPLACE,
@@ -827,10 +827,7 @@
         }
 
         // Restore mono mode
-        final boolean masterMono = System.getIntForUser(
-                mContentResolver, System.MASTER_MONO,
-                0 /* default */, UserHandle.USER_CURRENT) == 1;
-        AudioSystem.setMasterMono(masterMono);
+        updateMasterMono(mContentResolver);
 
         // Restore ringer mode
         setRingerModeInt(getRingerModeInternal(), false);
@@ -853,6 +850,7 @@
             AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
                     mDockAudioMediaEnabled ?
                             AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
+            sendEncodedSurroundMode(mContentResolver);
         }
         if (mHdmiManager != null) {
             synchronized (mHdmiManager) {
@@ -1015,6 +1013,55 @@
                 0);
     }
 
+
+    private void updateMasterMono(ContentResolver cr)
+    {
+        final boolean masterMono = System.getIntForUser(
+                cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
+        if (DEBUG_VOL) {
+            Log.d(TAG, String.format("Master mono %b", masterMono));
+        }
+        AudioSystem.setMasterMono(masterMono);
+    }
+
+    private void sendEncodedSurroundMode(ContentResolver cr)
+    {
+        int encodedSurroundMode = Settings.Global.getInt(
+                cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
+                Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+        sendEncodedSurroundMode(encodedSurroundMode);
+    }
+
+    private void sendEncodedSurroundMode(int encodedSurroundMode)
+    {
+        // initialize to guaranteed bad value
+        int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
+        switch (encodedSurroundMode) {
+            case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
+                forceSetting = AudioSystem.FORCE_NONE;
+                break;
+            case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
+                forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
+                break;
+            case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
+                forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
+                break;
+            default:
+                Log.e(TAG, "updateSurroundSoundSettings: illegal value "
+                        + encodedSurroundMode);
+                break;
+        }
+        if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
+            sendMsg(mAudioHandler,
+                    MSG_SET_FORCE_USE,
+                    SENDMSG_QUEUE,
+                    AudioSystem.FOR_ENCODED_SURROUND,
+                    forceSetting,
+                    null,
+                    0);
+        }
+    }
+
     private void readPersistedSettings() {
         final ContentResolver cr = mContentResolver;
 
@@ -1056,48 +1103,14 @@
 
             updateRingerModeAffectedStreams();
             readDockAudioSettings(cr);
+            sendEncodedSurroundMode(cr);
         }
 
         mMuteAffectedStreams = System.getIntForUser(cr,
                 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
                 UserHandle.USER_CURRENT);
 
-        final int currentUser = getCurrentUserId();
-
-        // In addition to checking the system setting, also check the current user restriction.
-        // Because of the delay before persisting VOLUME_MASTER_MUTE, there's a window where
-        // DISALLOW_ADJUST_VOLUME will be ignored when it's set right before switching users.
-        boolean masterMute = (System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
-                0, UserHandle.USER_CURRENT) == 1)
-                || mUserManagerInternal.getUserRestriction(
-                    currentUser, UserManager.DISALLOW_ADJUST_VOLUME);
-        if (mUseFixedVolume) {
-            masterMute = false;
-            AudioSystem.setMasterVolume(1.0f);
-        }
-        if (DEBUG_VOL) {
-            Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
-        }
-        setSystemAudioMute(masterMute);
-        AudioSystem.setMasterMute(masterMute);
-        broadcastMasterMuteStatus(masterMute);
-
-        boolean microphoneMute =
-                (System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1)
-                || mUserManagerInternal.getUserRestriction(
-                        currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
-        if (DEBUG_VOL) {
-            Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
-        }
-        AudioSystem.muteMicrophone(microphoneMute);
-
-        final boolean masterMono = System.getIntForUser(
-                cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
-        if (DEBUG_VOL) {
-            Log.d(TAG, String.format("Master mono %b, user=%d", masterMono, currentUser));
-        }
-        AudioSystem.setMasterMono(masterMono);
-        broadcastMasterMonoStatus(masterMono);
+        updateMasterMono(cr);
 
         // Each stream will read its own persisted settings
 
@@ -1113,6 +1126,31 @@
         mVolumeController.loadSettings(cr);
     }
 
+    private void readUserRestrictions() {
+        final int currentUser = getCurrentUserId();
+
+        // Check the current user restriction.
+        boolean masterMute = mUserManagerInternal.getUserRestriction(
+                    currentUser, UserManager.DISALLOW_ADJUST_VOLUME);
+        if (mUseFixedVolume) {
+            masterMute = false;
+            AudioSystem.setMasterVolume(1.0f);
+        }
+        if (DEBUG_VOL) {
+            Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
+        }
+        setSystemAudioMute(masterMute);
+        AudioSystem.setMasterMute(masterMute);
+        broadcastMasterMuteStatus(masterMute);
+
+        boolean microphoneMute = mUserManagerInternal.getUserRestriction(
+                currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+        if (DEBUG_VOL) {
+            Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
+        }
+        AudioSystem.muteMicrophone(microphoneMute);
+    }
+
     private int rescaleIndex(int index, int srcStream, int dstStream) {
         return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
     }
@@ -1268,7 +1306,6 @@
                 && (mRingerModeMutedStreams & (1 << AudioSystem.STREAM_MUSIC)) != 0) {
             adjustVolume = false;
         }
-
         int oldIndex = mStreamStates[streamType].getIndex(device);
 
         if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
@@ -1347,8 +1384,13 @@
                         synchronized (mHdmiPlaybackClient) {
                             int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
                                     KeyEvent.KEYCODE_VOLUME_UP;
-                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
-                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
+                            final long ident = Binder.clearCallingIdentity();
+                            try {
+                                mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
+                                mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
+                            } finally {
+                                Binder.restoreCallingIdentity(ident);
+                            }
                         }
                     }
                 }
@@ -1412,10 +1454,7 @@
         }
     };
 
-    private void onSetStreamVolume(int streamType, int index, int flags, int device,
-            String caller) {
-        final int stream = mStreamVolumeAlias[streamType];
-        setStreamVolumeInt(stream, index, device, false, caller);
+    private int getNewRingerMode(int stream, int index, int flags) {
         // setting volume on ui sounds stream type also controls silent mode
         if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                 (stream == getUiSoundsStreamType())) {
@@ -1423,11 +1462,49 @@
             if (index == 0) {
                 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
                         : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
-                        : AudioManager.RINGER_MODE_NORMAL;
+                                : AudioManager.RINGER_MODE_NORMAL;
             } else {
                 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
             }
-            setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
+            return newRingerMode;
+        }
+        return getRingerModeExternal();
+    }
+
+    private boolean isAndroidNPlus(String caller) {
+        try {
+            final ApplicationInfo applicationInfo =
+                    mContext.getPackageManager().getApplicationInfoAsUser(
+                            caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
+            if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+                return true;
+            }
+            return false;
+        } catch (PackageManager.NameNotFoundException e) {
+            return true;
+        }
+    }
+
+    private boolean wouldToggleZenMode(int newMode) {
+        if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
+                && newMode != AudioManager.RINGER_MODE_SILENT) {
+            return true;
+        } else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
+                && newMode == AudioManager.RINGER_MODE_SILENT) {
+            return true;
+        }
+        return false;
+    }
+
+    private void onSetStreamVolume(int streamType, int index, int flags, int device,
+            String caller) {
+        final int stream = mStreamVolumeAlias[streamType];
+        setStreamVolumeInt(stream, index, device, false, caller);
+        // setting volume on ui sounds stream type also controls silent mode
+        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
+                (stream == getUiSoundsStreamType())) {
+            setRingerMode(getNewRingerMode(stream, index, flags),
+                    TAG + ".onSetStreamVolume", false /*external*/);
         }
         // setting non-zero volume for a muted stream unmutes the stream and vice versa
         mStreamStates[stream].mute(index == 0);
@@ -1468,6 +1545,12 @@
             return;
         }
 
+        if (isAndroidNPlus(callingPackage)
+                && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
+                && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
+            throw new SecurityException("Not allowed to change Do Not Disturb state");
+        }
+
         synchronized (mSafeMediaVolumeState) {
             // reset any pending volume command
             mPendingVolumeCommand = null;
@@ -1828,20 +1911,12 @@
             if (mute != AudioSystem.getMasterMute()) {
                 setSystemAudioMute(mute);
                 AudioSystem.setMasterMute(mute);
-                // Post a persist master volume msg
-                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
-                        : 0, userId, null, PERSIST_DELAY);
                 sendMasterMuteUpdate(mute, flags);
 
                 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
                 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
                 sendBroadcastToAll(intent);
             }
-        } else {
-            // If not the current user just persist the setting which will be loaded
-            // on user switch.
-            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
-                    : 0, userId, null, PERSIST_DELAY);
         }
     }
 
@@ -1855,52 +1930,6 @@
                 userId);
     }
 
-    /** @hide */
-    public boolean isMasterMono() {
-        return AudioSystem.getMasterMono();
-    }
-
-    /** @hide */
-    public void setMasterMono(boolean mono, String callingPackage, int userId) {
-        int callingUid = Binder.getCallingUid();
-        // If we are being called by the system check for user we are going to change
-        // so we handle user restrictions correctly.
-        if (callingUid == android.os.Process.SYSTEM_UID) {
-            callingUid = UserHandle.getUid(userId, UserHandle.getAppId(callingUid));
-        }
-
-        if (userId != UserHandle.getCallingUserId() &&
-                mContext.checkCallingOrSelfPermission(
-                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                != PackageManager.PERMISSION_GRANTED) {
-            return;
-        }
-        if (DEBUG_VOL) {
-            Log.d(TAG, String.format("Master mono %b, user=%d", mono, userId));
-        }
-
-        if (getCurrentUserId() == userId) {
-            if (mono != AudioSystem.getMasterMono()) {
-                AudioSystem.setMasterMono(mono);
-                // Post a persist master mono msg
-                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
-                        : 0 /* value */, userId, null /* obj */, 0 /* delay */);
-                // notify apps and settings
-                broadcastMasterMonoStatus(mono);
-            }
-        } else {
-            // Post a persist master mono msg
-            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
-                    : 0 /* value */, userId, null /* obj */, 0 /* delay */);
-        }
-    }
-
-    private void broadcastMasterMonoStatus(boolean mono) {
-        Intent intent = new Intent(AudioManager.MASTER_MONO_CHANGED_ACTION);
-        intent.putExtra(AudioManager.EXTRA_MASTER_MONO, mono);
-        sendBroadcastToAll(intent);
-    }
-
     /** @see AudioManager#getStreamVolume(int) */
     public int getStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
@@ -1980,8 +2009,6 @@
             AudioSystem.muteMicrophone(on);
         }
         // Post a persist microphone msg.
-        sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
-                : 0, userId, null, PERSIST_DELAY);
     }
 
     @Override
@@ -2010,6 +2037,11 @@
     }
 
     public void setRingerModeExternal(int ringerMode, String caller) {
+        if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
+                && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
+            throw new SecurityException("Not allowed to change Do Not Disturb state");
+        }
+
         setRingerMode(ringerMode, caller, true /*external*/);
     }
 
@@ -2565,6 +2597,7 @@
     private void readAudioSettings(boolean userSwitch) {
         // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
         readPersistedSettings();
+        readUserRestrictions();
 
         // restore volume settings
         int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -4497,16 +4530,6 @@
                     persistVolume((VolumeStreamState) msg.obj, msg.arg1);
                     break;
 
-                case MSG_PERSIST_MASTER_VOLUME_MUTE:
-                    if (mUseFixedVolume) {
-                        return;
-                    }
-                    Settings.System.putIntForUser(mContentResolver,
-                                                 Settings.System.VOLUME_MASTER_MUTE,
-                                                 msg.arg1,
-                                                 msg.arg2);
-                    break;
-
                 case MSG_PERSIST_RINGER_MODE:
                     // note that the value persisted is the current ringer mode, not the
                     // value of ringer mode as of the time the request was made to persist
@@ -4629,37 +4652,36 @@
                             Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
                             UserHandle.USER_CURRENT);
                     break;
-                case MSG_PERSIST_MICROPHONE_MUTE:
-                    Settings.System.putIntForUser(mContentResolver,
-                                                 Settings.System.MICROPHONE_MUTE,
-                                                 msg.arg1,
-                                                 msg.arg2);
-                    break;
+
                 case MSG_UNMUTE_STREAM:
                     onUnmuteStream(msg.arg1, msg.arg2);
                     break;
+
                 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
                     onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
                     break;
-
-                case MSG_PERSIST_MASTER_MONO:
-                    Settings.System.putIntForUser(mContentResolver,
-                                                 Settings.System.MASTER_MONO,
-                                                 msg.arg1 /* value */,
-                                                 msg.arg2 /* userHandle */);
-                    break;
             }
         }
     }
 
     private class SettingsObserver extends ContentObserver {
 
+        private int mEncodedSurroundMode;
+
         SettingsObserver() {
             super(new Handler());
             mContentResolver.registerContentObserver(Settings.System.getUriFor(
                 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
             mContentResolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
+            mContentResolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.MASTER_MONO), false, this);
+
+            mEncodedSurroundMode = Settings.Global.getInt(
+                    mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
+                    Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
         }
 
         @Override
@@ -4678,6 +4700,34 @@
                     setRingerModeInt(getRingerModeInternal(), false);
                 }
                 readDockAudioSettings(mContentResolver);
+                updateMasterMono(mContentResolver);
+                updateEncodedSurroundOutput();
+            }
+        }
+
+        private void updateEncodedSurroundOutput() {
+            int newSurroundMode = Settings.Global.getInt(
+                mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
+                Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+            // Did it change?
+            if (mEncodedSurroundMode != newSurroundMode) {
+                // Send to AudioPolicyManager
+                sendEncodedSurroundMode(newSurroundMode);
+                synchronized(mConnectedDevices) {
+                    // Is HDMI connected?
+                    String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
+                    DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+                    if (deviceSpec != null) {
+                        // Toggle HDMI to retrigger broadcast with proper formats.
+                        setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
+                                AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
+                                "android"); // disconnect
+                        setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
+                                AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
+                                "android"); // reconnect
+                    }
+                }
+                mEncodedSurroundMode = newSurroundMode;
             }
         }
     }
@@ -6261,8 +6311,8 @@
         mRecordMonitor.unregisterRecordingCallback(rcdb);
     }
 
-    public AudioRecordConfiguration[] getActiveRecordConfigurations() {
-        return mRecordMonitor.getActiveRecordConfigurations();
+    public AudioRecordingConfiguration[] getActiveRecordingConfigurations() {
+        return mRecordMonitor.getActiveRecordingConfigurations();
     }
 
     //======================
@@ -6365,4 +6415,4 @@
             if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index a6325a4..7a085e1 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -16,8 +16,9 @@
 
 package com.android.server.audio;
 
+import android.media.AudioFormat;
 import android.media.AudioManager;
-import android.media.AudioRecordConfiguration;
+import android.media.AudioRecordingConfiguration;
 import android.media.AudioSystem;
 import android.media.IRecordingConfigDispatcher;
 import android.media.MediaRecorder;
@@ -38,8 +39,8 @@
 
     private ArrayList<RecMonitorClient> mClients = new ArrayList<RecMonitorClient>();
 
-    private HashMap<Integer, AudioRecordConfiguration> mRecordConfigs =
-            new HashMap<Integer, AudioRecordConfiguration>();
+    private HashMap<Integer, AudioRecordingConfiguration> mRecordConfigs =
+            new HashMap<Integer, AudioRecordingConfiguration>();
 
     RecordingActivityMonitor() {
         RecMonitorClient.sMonitor = this;
@@ -48,16 +49,20 @@
     /**
      * Implementation of android.media.AudioSystem.AudioRecordingCallback
      */
-    public void onRecordingConfigurationChanged(int event, int session, int source) {
+    public void onRecordingConfigurationChanged(int event, int session, int source,
+            int[] recordingInfo) {
         if (MediaRecorder.isSystemOnlyAudioSource(source)) {
             return;
         }
-        if (updateSnapshot(event, session, source)) {
-            final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+        final AudioRecordingConfiguration[] configs =
+                updateSnapshot(event, session, source, recordingInfo);
+        if (configs != null){
             synchronized(mClients) {
+                final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
                 while (clientIterator.hasNext()) {
                     try {
-                        clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange();
+                        clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange(
+                                configs);
                     } catch (RemoteException e) {
                         Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
                     }
@@ -99,9 +104,9 @@
         }
     }
 
-    AudioRecordConfiguration[] getActiveRecordConfigurations() {
+    AudioRecordingConfiguration[] getActiveRecordingConfigurations() {
         synchronized(mRecordConfigs) {
-            return mRecordConfigs.values().toArray(new AudioRecordConfiguration[0]);
+            return mRecordConfigs.values().toArray(new AudioRecordingConfiguration[0]);
         }
     }
 
@@ -110,31 +115,68 @@
      * @param event
      * @param session
      * @param source
-     * @return true if the list of active recording sessions has been modified, false otherwise.
+     * @param recordingFormat see
+     *     {@link AudioSystem.AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])}
+     *     for the definition of the contents of the array
+     * @return null if the list of active recording sessions has not been modified, an array
+     *     with the current active configurations otherwise.
      */
-    private boolean updateSnapshot(int event, int session, int source) {
+    private AudioRecordingConfiguration[] updateSnapshot(int event, int session, int source,
+            int[] recordingInfo) {
+        final boolean configChanged;
+        final AudioRecordingConfiguration[] configs;
         synchronized(mRecordConfigs) {
             switch (event) {
             case AudioManager.RECORD_CONFIG_EVENT_STOP:
                 // return failure if an unknown recording session stopped
-                return (mRecordConfigs.remove(new Integer(session)) != null);
+                configChanged = (mRecordConfigs.remove(new Integer(session)) != null);
+                break;
             case AudioManager.RECORD_CONFIG_EVENT_START:
-                if (mRecordConfigs.containsKey(new Integer(session))) {
-                    // start of session that's already tracked, not worth an update
-                    // TO DO in the future when tracking record format: there might be a record
-                    //       format change during a recording that requires reporting
-                    return false;
+                final AudioFormat clientFormat = new AudioFormat.Builder()
+                        .setEncoding(recordingInfo[0])
+                        // FIXME this doesn't support index-based masks
+                        .setChannelMask(recordingInfo[1])
+                        .setSampleRate(recordingInfo[2])
+                        .build();
+                final AudioFormat deviceFormat = new AudioFormat.Builder()
+                        .setEncoding(recordingInfo[3])
+                        // FIXME this doesn't support index-based masks
+                        .setChannelMask(recordingInfo[4])
+                        .setSampleRate(recordingInfo[5])
+                        .build();
+                final int patchHandle = recordingInfo[6];
+                final Integer sessionKey = new Integer(session);
+                if (mRecordConfigs.containsKey(sessionKey)) {
+                    final AudioRecordingConfiguration updatedConfig =
+                            new AudioRecordingConfiguration(session, source,
+                                    clientFormat, deviceFormat, patchHandle);
+                    if (updatedConfig.equals(mRecordConfigs.get(sessionKey))) {
+                        configChanged = false;
+                    } else {
+                        // config exists but has been modified
+                        mRecordConfigs.remove(sessionKey);
+                        mRecordConfigs.put(sessionKey, updatedConfig);
+                        configChanged = true;
+                    }
                 } else {
-                    mRecordConfigs.put(new Integer(session),
-                            new AudioRecordConfiguration(session, source));
-                    return true;
+                    mRecordConfigs.put(sessionKey,
+                            new AudioRecordingConfiguration(session, source,
+                                    clientFormat, deviceFormat, patchHandle));
+                    configChanged = true;
                 }
+                break;
             default:
                 Log.e(TAG, String.format("Unknown event %d for session %d, source %d",
                         event, session, source));
-                return false;
+                configChanged = false;
+            }
+            if (configChanged) {
+                configs = mRecordConfigs.values().toArray(new AudioRecordingConfiguration[0]);
+            } else {
+                configs = null;
             }
         }
+        return configs;
     }
 
     /**
diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java
new file mode 100644
index 0000000..e5d564d
--- /dev/null
+++ b/services/core/java/com/android/server/backup/BackupUtils.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.Signature;
+import android.util.Slog;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class BackupUtils {
+    private static final String TAG = "BackupUtils";
+
+    private static final boolean DEBUG = false; // STOPSHIP if true
+
+    public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
+        if (target == null) {
+            return false;
+        }
+
+        // If the target resides on the system partition, we allow it to restore
+        // data from the like-named package in a restore set even if the signatures
+        // do not match.  (Unlike general applications, those flashed to the system
+        // partition will be signed with the device's platform certificate, so on
+        // different phones the same system app will have different signatures.)
+        if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+            if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
+            return true;
+        }
+
+        // Allow unsigned apps, but not signed on one device and unsigned on the other
+        // !!! TODO: is this the right policy?
+        Signature[] deviceSigs = target.signatures;
+        if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
+                + " device=" + deviceSigs);
+        if ((storedSigHashes == null || storedSigHashes.size() == 0)
+                && (deviceSigs == null || deviceSigs.length == 0)) {
+            return true;
+        }
+        if (storedSigHashes == null || deviceSigs == null) {
+            return false;
+        }
+
+        // !!! TODO: this demands that every stored signature match one
+        // that is present on device, and does not demand the converse.
+        // Is this this right policy?
+        final int nStored = storedSigHashes.size();
+        final int nDevice = deviceSigs.length;
+
+        // hash each on-device signature
+        ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
+        for (int i = 0; i < nDevice; i++) {
+            deviceHashes.add(hashSignature(deviceSigs[i]));
+        }
+
+        // now ensure that each stored sig (hash) matches an on-device sig (hash)
+        for (int n = 0; n < nStored; n++) {
+            boolean match = false;
+            final byte[] storedHash = storedSigHashes.get(n);
+            for (int i = 0; i < nDevice; i++) {
+                if (Arrays.equals(storedHash, deviceHashes.get(i))) {
+                    match = true;
+                    break;
+                }
+            }
+            // match is false when no on-device sig matched one of the stored ones
+            if (!match) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static byte[] hashSignature(byte[] signature) {
+        try {
+            MessageDigest digest = MessageDigest.getInstance("SHA-256");
+            digest.update(signature);
+            return digest.digest();
+        } catch (NoSuchAlgorithmException e) {
+            Slog.w(TAG, "No SHA-256 algorithm found!");
+        }
+        return null;
+    }
+
+    public static byte[] hashSignature(Signature signature) {
+        return hashSignature(signature.toByteArray());
+    }
+
+    public static ArrayList<byte[]> hashSignatureArray(Signature[] sigs) {
+        if (sigs == null) {
+            return null;
+        }
+
+        ArrayList<byte[]> hashes = new ArrayList<>(sigs.length);
+        for (Signature s : sigs) {
+            hashes.add(hashSignature(s));
+        }
+        return hashes;
+    }
+
+    public static ArrayList<byte[]> hashSignatureArray(List<byte[]> sigs) {
+        if (sigs == null) {
+            return null;
+        }
+
+        ArrayList<byte[]> hashes = new ArrayList<>(sigs.size());
+        for (byte[] s : sigs) {
+            hashes.add(hashSignature(s));
+        }
+        return hashes;
+    }
+}
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
index f82454a..cd8eb4e 100644
--- a/services/core/java/com/android/server/camera/CameraService.java
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -60,10 +60,6 @@
 
     public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
 
-    // Event arguments to use with the camera service notifySystemEvent call:
-    public static final int NO_EVENT = 0; // NOOP
-    public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
-
     // State arguments to use with the notifyCameraState call from camera service:
     public static final int CAMERA_STATE_OPEN = 0;
     public static final int CAMERA_STATE_ACTIVE = 1;
@@ -224,7 +220,7 @@
         if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
             // Some user handles have been added or removed, update mediaserver.
             mEnabledCameraUsers = currentUserHandles;
-            notifyMediaserverLocked(USER_SWITCHED, currentUserHandles);
+            notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, currentUserHandles);
         }
     }
 
@@ -244,7 +240,7 @@
             if (mEnabledCameraUsers == null) {
                 return;
             }
-            if (notifyMediaserverLocked(USER_SWITCHED, mEnabledCameraUsers)) {
+            if (notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) {
                 retries = 0;
             }
         }
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 90c9ddf..9e1f6b8 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -60,7 +60,7 @@
 public class KeepaliveTracker {
 
     private static final String TAG = "KeepaliveTracker";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
 
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
new file mode 100644
index 0000000..f91db78
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.android.server.SystemService;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityMetricsEvent;
+import android.net.ConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLogger;
+import android.os.Binder;
+import android.os.Parcel;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+
+/** {@hide} */
+public class MetricsLoggerService extends SystemService {
+    private static String TAG = "ConnectivityMetricsLoggerService";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    public MetricsLoggerService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        resetThrottlingCounters(System.currentTimeMillis());
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+            publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
+                    mBinder);
+        }
+    }
+
+    // TODO: read from system property
+    private final int MAX_NUMBER_OF_EVENTS = 1000;
+
+    // TODO: read from system property
+    private final int EVENTS_NOTIFICATION_THRESHOLD = 300;
+
+    // TODO: read from system property
+    private final int THROTTLING_TIME_INTERVAL_MILLIS = 60 * 60 * 1000; // 1 hour
+
+    // TODO: read from system property
+    private final int THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT = 1000;
+
+    private int mEventCounter = 0;
+
+    /**
+     * Reference of the last event in the list of cached events.
+     *
+     * When client of this service retrieves events by calling getEvents, it is passing
+     * ConnectivityMetricsEvent.Reference object. After getEvents returns, that object will
+     * contain this reference. The client can save it and use next time it calls getEvents.
+     * This way only new events will be returned.
+     */
+    private long mLastEventReference = 0;
+
+    private final int mThrottlingCounters[] =
+            new int[ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS];
+
+    private long mThrottlingIntervalBoundaryMillis;
+
+    private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
+
+    private void enforceConnectivityInternalPermission() {
+        getContext().enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONNECTIVITY_INTERNAL,
+                "MetricsLoggerService");
+    }
+
+    private void enforceDumpPermission() {
+        getContext().enforceCallingOrSelfPermission(
+                android.Manifest.permission.DUMP,
+                "MetricsLoggerService");
+    }
+
+    private void resetThrottlingCounters(long currentTimeMillis) {
+        for (int i = 0; i < mThrottlingCounters.length; i++) {
+            mThrottlingCounters[i] = 0;
+        }
+        mThrottlingIntervalBoundaryMillis =
+                currentTimeMillis + THROTTLING_TIME_INTERVAL_MILLIS;
+    }
+
+    private void addEvent(ConnectivityMetricsEvent e) {
+        if (VDBG) {
+            Log.v(TAG, "writeEvent(" + e.toString() + ")");
+        }
+
+        while (mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
+            mEvents.removeFirst();
+        }
+
+        mEvents.addLast(e);
+    }
+
+    /**
+     * Implementation of the IConnectivityMetricsLogger interface.
+     */
+    private final IConnectivityMetricsLogger.Stub mBinder = new IConnectivityMetricsLogger.Stub() {
+
+        private final ArrayList<PendingIntent> mPendingIntents = new ArrayList<>();
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump ConnectivityMetricsLoggerService " +
+                        "from from pid=" + Binder.getCallingPid() + ", uid=" +
+                        Binder.getCallingUid());
+                return;
+            }
+
+            boolean dumpSerializedSize = false;
+            boolean dumpEvents = false;
+            for (String arg : args) {
+                switch (arg) {
+                    case "--events":
+                        dumpEvents = true;
+                        break;
+
+                    case "--size":
+                        dumpSerializedSize = true;
+                        break;
+
+                    case "--all":
+                        dumpEvents = true;
+                        dumpSerializedSize = true;
+                        break;
+                }
+            }
+
+            synchronized (mEvents) {
+                pw.println("Number of events: " + mEvents.size());
+                pw.println("Time span: " +
+                        DateUtils.formatElapsedTime(
+                                (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
+                                        / 1000));
+
+                if (dumpSerializedSize) {
+                    long dataSize = 0;
+                    Parcel p = Parcel.obtain();
+                    for (ConnectivityMetricsEvent e : mEvents) {
+                        dataSize += 16; // timestamp and 2 stamps
+
+                        p.writeParcelable(e.data, 0);
+                    }
+                    dataSize += p.dataSize();
+                    p.recycle();
+                    pw.println("Serialized data size: " + dataSize);
+                }
+
+                if (dumpEvents) {
+                    pw.println();
+                    pw.println("Events:");
+                    for (ConnectivityMetricsEvent e : mEvents) {
+                        pw.println(e.toString());
+                    }
+                }
+            }
+
+            if (!mPendingIntents.isEmpty()) {
+                pw.println();
+                pw.println("Pending intents:");
+                for (PendingIntent pi : mPendingIntents) {
+                    pw.println(pi.toString());
+                }
+            }
+        }
+
+        public long logEvent(ConnectivityMetricsEvent event) {
+            ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
+            return logEvents(events);
+        }
+
+        /**
+         * @param events
+         *
+         * Note: All events must belong to the same component.
+         *
+         * @return 0 on success
+         *        <0 if error happened
+         *        >0 timestamp after which new events will be accepted
+         */
+        public long logEvents(ConnectivityMetricsEvent[] events) {
+            enforceConnectivityInternalPermission();
+
+            if (events == null || events.length == 0) {
+                Log.wtf(TAG, "No events passed to logEvents()");
+                return -1;
+            }
+
+            int componentTag = events[0].componentTag;
+            if (componentTag < 0 ||
+                    componentTag >= ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS) {
+                Log.wtf(TAG, "Unexpected tag: " + componentTag);
+                return -1;
+            }
+
+            synchronized (mThrottlingCounters) {
+                long currentTimeMillis = System.currentTimeMillis();
+                if (currentTimeMillis > mThrottlingIntervalBoundaryMillis) {
+                    resetThrottlingCounters(currentTimeMillis);
+                }
+
+                mThrottlingCounters[componentTag] += events.length;
+
+                if (mThrottlingCounters[componentTag] >
+                        THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT) {
+                    Log.w(TAG, "Too many events from #" + componentTag +
+                            ". Block until " + mThrottlingIntervalBoundaryMillis);
+
+                    return mThrottlingIntervalBoundaryMillis;
+                }
+            }
+
+            boolean sendPendingIntents = false;
+
+            synchronized (mEvents) {
+                for (ConnectivityMetricsEvent e : events) {
+                    if (e.componentTag != componentTag) {
+                        Log.wtf(TAG, "Unexpected tag: " + e.componentTag);
+                        return -1;
+                    }
+
+                    addEvent(e);
+                }
+
+                mLastEventReference += events.length;
+
+                mEventCounter += events.length;
+                if (mEventCounter >= EVENTS_NOTIFICATION_THRESHOLD) {
+                    mEventCounter = 0;
+                    sendPendingIntents = true;
+                }
+            }
+
+            if (sendPendingIntents) {
+                synchronized (mPendingIntents) {
+                    for (PendingIntent pi : mPendingIntents) {
+                        if (VDBG) Log.v(TAG, "Send pending intent");
+                        try {
+                            pi.send(getContext(), 0, null, null, null);
+                        } catch (PendingIntent.CanceledException e) {
+                            Log.e(TAG, "Pending intent canceled: " + pi);
+                            mPendingIntents.remove(pi);
+                        }
+                    }
+                }
+            }
+
+            return 0;
+        }
+
+        /**
+         * Retrieve events
+         *
+         * @param reference of the last event previously returned. The function will return
+         *                  events following it.
+         *                  If 0 then all events will be returned.
+         *                  After the function call it will contain reference of the
+         *                  last returned event.
+         * @return events
+         */
+        public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
+            enforceDumpPermission();
+            long ref = reference.value;
+            if (VDBG) Log.v(TAG, "getEvents(" + ref + ")");
+
+            ConnectivityMetricsEvent[] result;
+            synchronized (mEvents) {
+                if (ref > mLastEventReference) {
+                    Log.e(TAG, "Invalid reference");
+                    reference.value = mLastEventReference;
+                    return null;
+                }
+                if (ref < mLastEventReference - mEvents.size()) {
+                    ref = mLastEventReference - mEvents.size();
+                }
+
+                int numEventsToSkip =
+                        mEvents.size() // Total number of events
+                        - (int)(mLastEventReference - ref); // Number of events to return
+
+                result = new ConnectivityMetricsEvent[mEvents.size() - numEventsToSkip];
+                int i = 0;
+                for (ConnectivityMetricsEvent e : mEvents) {
+                    if (numEventsToSkip > 0) {
+                        numEventsToSkip--;
+                    } else {
+                        result[i++] = e;
+                    }
+                }
+            }
+
+            reference.value = mLastEventReference;
+
+            return result;
+        }
+
+        public boolean register(PendingIntent newEventsIntent) {
+            enforceDumpPermission();
+            if (VDBG) Log.v(TAG, "register(" + newEventsIntent + ")");
+
+            synchronized (mPendingIntents) {
+                if (mPendingIntents.remove(newEventsIntent)) {
+                    Log.w(TAG, "Replacing registered pending intent");
+                }
+                mPendingIntents.add(newEventsIntent);
+            }
+
+            return true;
+        }
+
+        public void unregister(PendingIntent newEventsIntent) {
+            enforceDumpPermission();
+            if (VDBG) Log.v(TAG, "unregister(" + newEventsIntent + ")");
+
+            synchronized (mPendingIntents) {
+                if (!mPendingIntents.remove(newEventsIntent)) {
+                    Log.e(TAG, "Pending intent is not registered");
+                }
+            }
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index a9eaeee..b390884 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,13 +16,11 @@
 
 package com.android.server.connectivity;
 
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-
 import java.net.Inet4Address;
 
 import android.content.Context;
 import android.net.InterfaceConfiguration;
+import android.net.ConnectivityManager;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkAgent;
@@ -34,6 +32,7 @@
 import android.util.Slog;
 
 import com.android.server.net.BaseNetworkObserver;
+import com.android.internal.util.ArrayUtils;
 
 /**
  * @hide
@@ -46,6 +45,13 @@
     // This must match the interface prefix in clatd.c.
     private static final String CLAT_PREFIX = "v4-";
 
+    // The network types we will start clatd on.
+    private static final int[] NETWORK_TYPES = {
+            ConnectivityManager.TYPE_MOBILE,
+            ConnectivityManager.TYPE_WIFI,
+            ConnectivityManager.TYPE_ETHERNET,
+    };
+
     private final INetworkManagementService mNMService;
 
     // ConnectivityService Handler for LinkProperties updates.
@@ -90,7 +96,7 @@
                 (nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false;
         // Only support clat on mobile and wifi for now, because these are the only IPv6-only
         // networks we can connect to.
-        return connected && !hasIPv4Address && (netType == TYPE_MOBILE || netType == TYPE_WIFI);
+        return connected && !hasIPv4Address && ArrayUtils.contains(NETWORK_TYPES, netType);
     }
 
     /**
@@ -221,7 +227,7 @@
     }
 
     private void maybeSetIpv6NdOffload(String iface, boolean on) {
-        if (mNetwork.networkInfo.getType() != TYPE_WIFI) {
+        if (mNetwork.networkInfo.getType() != ConnectivityManager.TYPE_WIFI) {
             return;
         }
         try {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 4504bdb..bbb162e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -34,6 +34,8 @@
 import android.net.ProxyInfo;
 import android.net.TrafficStats;
 import android.net.Uri;
+import android.net.metrics.CaptivePortalCheckResultEvent;
+import android.net.metrics.CaptivePortalStateChangeEvent;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
@@ -76,7 +78,7 @@
  * {@hide}
  */
 public class NetworkMonitor extends StateMachine {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "NetworkMonitor";
     private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
     private static final int SOCKET_TIMEOUT_MS = 10000;
@@ -297,9 +299,13 @@
                     transitionTo(mLingeringState);
                     return HANDLED;
                 case CMD_NETWORK_CONNECTED:
+                    CaptivePortalStateChangeEvent.logEvent(
+                            CaptivePortalStateChangeEvent.NETWORK_MONITOR_CONNECTED);
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_NETWORK_DISCONNECTED:
+                    CaptivePortalStateChangeEvent.logEvent(
+                            CaptivePortalStateChangeEvent.NETWORK_MONITOR_DISCONNECTED);
                     if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
                         mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
                         mLaunchCaptivePortalAppBroadcastReceiver = null;
@@ -349,6 +355,8 @@
     private class ValidatedState extends State {
         @Override
         public void enter() {
+            CaptivePortalStateChangeEvent.logEvent(
+                   CaptivePortalStateChangeEvent.NETWORK_MONITOR_VALIDATED);
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_VALID, 0, mNetworkAgentInfo));
         }
@@ -457,6 +465,8 @@
                     // will be unresponsive. isCaptivePortal() could be executed on another Thread
                     // if this is found to cause problems.
                     int httpResponseCode = isCaptivePortal();
+                    CaptivePortalCheckResultEvent.logEvent(mNetworkAgentInfo.network.netId,
+                            httpResponseCode);
                     if (httpResponseCode == 204) {
                         transitionTo(mValidatedState);
                     } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
@@ -566,7 +576,7 @@
         @Override
         public void enter() {
             final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetworkAgentInfo.network.netId;
-            mWakeupMessage = new WakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
+            mWakeupMessage = makeWakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
             long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs;
             mWakeupMessage.schedule(wakeupTime);
         }
@@ -688,12 +698,11 @@
             // Time how long it takes to get a response to our request
             long requestTimestamp = SystemClock.elapsedRealtime();
 
-            urlConnection.getInputStream();
+            httpResponseCode = urlConnection.getResponseCode();
 
             // Time how long it takes to get a response to our request
             long responseTimestamp = SystemClock.elapsedRealtime();
 
-            httpResponseCode = urlConnection.getResponseCode();
             validationLog("isCaptivePortal: ret=" + httpResponseCode +
                     " headers=" + urlConnection.getHeaderFields());
             // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive
@@ -823,4 +832,9 @@
         }
         DEFAULT_LINGER_DELAY_MS = time_ms;
     }
+
+    @VisibleForTesting
+    protected WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int i) {
+        return new WakeupMessage(c, h, s, i);
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index debda14..22cefd1 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -54,7 +54,7 @@
  */
 public class PermissionMonitor {
     private static final String TAG = "PermissionMonitor";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean SYSTEM = true;
     private static final boolean NETWORK = false;
 
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 760b218..2cba93fd 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -32,6 +32,7 @@
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
@@ -40,6 +41,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
+import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.wifi.WifiManager;
@@ -88,9 +90,9 @@
  */
 public class Tethering extends BaseNetworkObserver {
 
-    private Context mContext;
+    private final Context mContext;
     private final static String TAG = "Tethering";
-    private final static boolean DBG = true;
+    private final static boolean DBG = false;
     private final static boolean VDBG = false;
 
     // TODO - remove both of these - should be part of interface inspection/selection stuff
@@ -100,7 +102,7 @@
     private Collection<Integer> mUpstreamIfaceTypes;
 
     // used to synchronize public access to members
-    private Object mPublicSync;
+    private final Object mPublicSync;
 
     private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
     private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
@@ -112,7 +114,7 @@
 
     private final INetworkManagementService mNMService;
     private final INetworkStatsService mStatsService;
-    private Looper mLooper;
+    private final Looper mLooper;
 
     private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
 
@@ -143,7 +145,9 @@
     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
     private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
 
-    private StateMachine mTetherMasterSM;
+    private final StateMachine mTetherMasterSM;
+    private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
+    private String mCurrentUpstreamIface;
 
     private Notification.Builder mTetheredNotificationBuilder;
     private int mLastNotificationId;
@@ -167,6 +171,8 @@
         mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
         mTetherMasterSM.start();
 
+        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor();
+
         mStateReceiver = new StateReceiver();
         IntentFilter filter = new IntentFilter();
         filter.addAction(UsbManager.ACTION_USB_STATE);
@@ -255,6 +261,9 @@
                     // ignore usb0 down after enabling RNDIS
                     // we will handle disconnect in interfaceRemoved instead
                     if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
+                } else if (isWifi(iface)) {
+                    // handle disconnect in interfaceRemoved
+                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
                 } else if (sm != null) {
                     sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
                     mIfaces.remove(iface);
@@ -502,7 +511,7 @@
         };
 
         // The following is necessary to avoid unmarshalling issues when sending the receiver
-        // across proccesses.
+        // across processes.
         Parcel parcel = Parcel.obtain();
         rr.writeToParcel(parcel,0);
         parcel.setDataPosition(0);
@@ -556,6 +565,7 @@
             }
         }
     }
+
     public int tether(String iface) {
         if (DBG) Log.d(TAG, "Tethering " + iface);
         TetherInterfaceSM sm = null;
@@ -1201,6 +1211,11 @@
                     Log.e(TAG, "Error Tethering: " + e.toString());
                     setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
 
+                    try {
+                        mNMService.untetherInterface(mIfaceName);
+                    } catch (Exception ee) {
+                        Log.e(TAG, "Error untethering after failure!" + ee.toString());
+                    }
                     transitionTo(mInitialState);
                     return;
                 }
@@ -1368,15 +1383,115 @@
 
     }
 
+    /**
+     * A NetworkCallback class that relays information of interest to the
+     * tethering master state machine thread for subsequent processing.
+     */
+    class UpstreamNetworkCallback extends NetworkCallback {
+        @Override
+        public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
+            mTetherMasterSM.sendMessage(
+                    TetherMasterSM.EVENT_UPSTREAM_LINKPROPERTIES_CHANGED,
+                    new NetworkState(null, newLp, null, network, null, null));
+        }
+
+        @Override
+        public void onLost(Network network) {
+            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_LOST, network);
+        }
+    }
+
+    /**
+     * A class to centralize all the network and link properties information
+     * pertaining to the current and any potential upstream network.
+     *
+     * Calling #start() registers two callbacks: one to track the system default
+     * network and a second to specifically observe TYPE_MOBILE_DUN networks.
+     *
+     * The methods and data members of this class are only to be accessed and
+     * modified from the tethering master state machine thread. Any other
+     * access semantics would necessitate the addition of locking.
+     *
+     * TODO: Investigate whether more "upstream-specific" logic/functionality
+     * could/should be moved here.
+     */
+    class UpstreamNetworkMonitor {
+        final HashMap<Network, NetworkState> mNetworkMap = new HashMap();
+        NetworkCallback mDefaultNetworkCallback;
+        NetworkCallback mDunTetheringCallback;
+
+        void start() {
+            stop();
+
+            mDefaultNetworkCallback = new UpstreamNetworkCallback();
+            getConnectivityManager().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+
+            final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
+                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
+                    .build();
+            mDunTetheringCallback = new UpstreamNetworkCallback();
+            getConnectivityManager().registerNetworkCallback(
+                    dunTetheringRequest, mDunTetheringCallback);
+        }
+
+        void stop() {
+            if (mDefaultNetworkCallback != null) {
+                getConnectivityManager().unregisterNetworkCallback(mDefaultNetworkCallback);
+                mDefaultNetworkCallback = null;
+            }
+
+            if (mDunTetheringCallback != null) {
+                getConnectivityManager().unregisterNetworkCallback(mDunTetheringCallback);
+                mDunTetheringCallback = null;
+            }
+
+            mNetworkMap.clear();
+        }
+
+        // Returns true if these updated LinkProperties pertain to the current
+        // upstream network interface, false otherwise (or if there is not
+        // currently any upstream tethering interface).
+        boolean processLinkPropertiesChanged(NetworkState networkState) {
+            if (networkState == null ||
+                    networkState.network == null ||
+                    networkState.linkProperties == null) {
+                return false;
+            }
+
+            mNetworkMap.put(networkState.network, networkState);
+
+            if (mCurrentUpstreamIface != null) {
+                for (String ifname : networkState.linkProperties.getAllInterfaceNames()) {
+                    if (mCurrentUpstreamIface.equals(ifname)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        void processNetworkLost(Network network) {
+            if (network != null) {
+                mNetworkMap.remove(network);
+            }
+        }
+    }
+
     class TetherMasterSM extends StateMachine {
         // an interface SM has requested Tethering
-        static final int CMD_TETHER_MODE_REQUESTED   = 1;
+        static final int CMD_TETHER_MODE_REQUESTED              = 1;
         // an interface SM has unrequested Tethering
-        static final int CMD_TETHER_MODE_UNREQUESTED = 2;
+        static final int CMD_TETHER_MODE_UNREQUESTED            = 2;
         // upstream connection change - do the right thing
-        static final int CMD_UPSTREAM_CHANGED        = 3;
+        static final int CMD_UPSTREAM_CHANGED                   = 3;
         // we don't have a valid upstream conn, check again after a delay
-        static final int CMD_RETRY_UPSTREAM          = 4;
+        static final int CMD_RETRY_UPSTREAM                     = 4;
+        // Events from NetworkCallbacks that we process on the master state
+        // machine thread on behalf of the UpstreamNetworkMonitor.
+        static final int EVENT_UPSTREAM_LINKPROPERTIES_CHANGED  = 5;
+        static final int EVENT_UPSTREAM_LOST                    = 6;
 
         // This indicates what a timeout event relates to.  A state that
         // sends itself a delayed timeout event and handles incoming timeout events
@@ -1396,9 +1511,7 @@
         private ArrayList<TetherInterfaceSM> mNotifyList;
 
         private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
-        private ConnectivityManager.NetworkCallback mMobileUpstreamCallback;
-
-        private String mUpstreamIfaceName = null;
+        private NetworkCallback mMobileUpstreamCallback;
 
         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
 
@@ -1427,8 +1540,6 @@
         }
 
         class TetherMasterUtilState extends State {
-            protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE     = false;
-
             @Override
             public boolean processMessage(Message m) {
                 return false;
@@ -1458,27 +1569,27 @@
                         return false;
                 }
 
-                NetworkRequest.Builder builder = new NetworkRequest.Builder()
+                final NetworkRequest.Builder builder = new NetworkRequest.Builder()
                         .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
                 if (apnType == ConnectivityManager.TYPE_MOBILE_DUN) {
-                    builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
-                           .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+                    builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                           .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
                 } else {
                     builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
                 }
-                NetworkRequest mobileUpstreamRequest = builder.build();
-                // Other mechanisms notice network and interface changes and act upon them.
-                // TODO, imminently: replace with a proper NetworkCallback-based scheme.
-                //
+                final NetworkRequest mobileUpstreamRequest = builder.build();
+
+                // The UpstreamNetworkMonitor's callback will be notified.
+                // Therefore, to avoid duplicate notifications, we only register a no-op.
+                mMobileUpstreamCallback = new NetworkCallback();
+
                 // TODO: Change the timeout from 0 (no onUnavailable callback) to use some
                 // moderate callback time (once timeout callbacks are implemented). This might
                 // be useful for updating some UI. Additionally, we should definitely log a
-                // message to aid in any subsequent debugging.
-                mMobileUpstreamCallback = new ConnectivityManager.NetworkCallback();
+                // message to aid in any subsequent debugging
                 if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
                 getConnectivityManager().requestNetwork(
                         mobileUpstreamRequest, mMobileUpstreamCallback, 0, apnType);
-
                 return true;
             }
 
@@ -1510,6 +1621,7 @@
                 }
                 return true;
             }
+
             protected boolean turnOffMasterTetherSettings() {
                 try {
                     mNMService.stopTethering();
@@ -1603,34 +1715,41 @@
                     }
 
                     if (iface != null) {
-                        String[] dnsServers = mDefaultDnsServers;
-                        Collection<InetAddress> dnses = linkProperties.getDnsServers();
-                        if (dnses != null && !dnses.isEmpty()) {
-                            // TODO: remove this invocation of NetworkUtils.makeStrings().
-                            dnsServers = NetworkUtils.makeStrings(dnses);
+                        Network network = getConnectivityManager().getNetworkForType(upType);
+                        if (network == null) {
+                            Log.e(TAG, "No Network for upstream type " + upType + "!");
                         }
-                        try {
-                            Network network = getConnectivityManager().getNetworkForType(upType);
-                            if (network == null) {
-                                Log.e(TAG, "No Network for upstream type " + upType + "!");
-                            }
-                            if (VDBG) {
-                                Log.d(TAG, "Setting DNS forwarders: Network=" + network +
-                                       ", dnsServers=" + Arrays.toString(dnsServers));
-                            }
-                            mNMService.setDnsForwarders(network, dnsServers);
-                        } catch (Exception e) {
-                            Log.e(TAG, "Setting DNS forwarders failed!");
-                            transitionTo(mSetDnsForwardersErrorState);
-                        }
+                        setDnsForwarders(network, linkProperties);
                     }
                 }
                 notifyTetheredOfNewUpstreamIface(iface);
             }
 
+            protected void setDnsForwarders(final Network network, final LinkProperties lp) {
+                String[] dnsServers = mDefaultDnsServers;
+                final Collection<InetAddress> dnses = lp.getDnsServers();
+                // TODO: Properly support the absence of DNS servers.
+                if (dnses != null && !dnses.isEmpty()) {
+                    // TODO: remove this invocation of NetworkUtils.makeStrings().
+                    dnsServers = NetworkUtils.makeStrings(dnses);
+                }
+                if (VDBG) {
+                    Log.d(TAG, "Setting DNS forwarders: Network=" + network +
+                           ", dnsServers=" + Arrays.toString(dnsServers));
+                }
+                try {
+                    mNMService.setDnsForwarders(network, dnsServers);
+                } catch (Exception e) {
+                    // TODO: Investigate how this can fail and what exactly
+                    // happens if/when such failures occur.
+                    Log.e(TAG, "Setting DNS forwarders failed!");
+                    transitionTo(mSetDnsForwardersErrorState);
+                }
+            }
+
             protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
                 if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
-                mUpstreamIfaceName = ifaceName;
+                mCurrentUpstreamIface = ifaceName;
                 for (TetherInterfaceSM sm : mNotifyList) {
                     sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
                             ifaceName);
@@ -1769,20 +1888,23 @@
         }
 
         class TetherModeAliveState extends TetherMasterUtilState {
-            boolean mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
+            boolean mTryCell = true;
             @Override
             public void enter() {
+                // TODO: examine if we should check the return value.
                 turnOnMasterTetherSettings(); // may transition us out
                 startListeningForSimChanges();
+                mUpstreamNetworkMonitor.start();
 
-                mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE; // better try something first pass
-                                                        // or crazy tests cases will fail
+                mTryCell = true;  // better try something first pass or crazy tests cases will fail
                 chooseUpstreamType(mTryCell);
                 mTryCell = !mTryCell;
             }
             @Override
             public void exit() {
+                // TODO: examine if we should check the return value.
                 turnOffUpstreamMobileConnection();
+                mUpstreamNetworkMonitor.stop();
                 stopListeningForSimChanges();
                 notifyTetheredOfNewUpstreamIface(null);
             }
@@ -1796,7 +1918,7 @@
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         mNotifyList.add(who);
                         who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
-                                mUpstreamIfaceName);
+                                mCurrentUpstreamIface);
                         break;
                     case CMD_TETHER_MODE_UNREQUESTED:
                         who = (TetherInterfaceSM)message.obj;
@@ -1820,7 +1942,7 @@
                         break;
                     case CMD_UPSTREAM_CHANGED:
                         // need to try DUN immediately if Wifi goes down
-                        mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
+                        mTryCell = true;
                         chooseUpstreamType(mTryCell);
                         mTryCell = !mTryCell;
                         break;
@@ -1828,6 +1950,24 @@
                         chooseUpstreamType(mTryCell);
                         mTryCell = !mTryCell;
                         break;
+                    case EVENT_UPSTREAM_LINKPROPERTIES_CHANGED:
+                        NetworkState state = (NetworkState) message.obj;
+                        if (mUpstreamNetworkMonitor.processLinkPropertiesChanged(state)) {
+                            setDnsForwarders(state.network, state.linkProperties);
+                        } else if (mCurrentUpstreamIface == null) {
+                            // If we have no upstream interface, try to run through upstream
+                            // selection again.  If, for example, IPv4 connectivity has shown up
+                            // after IPv6 (e.g., 464xlat became available) we want the chance to
+                            // notice and act accordingly.
+                            chooseUpstreamType(false);
+                        }
+                        break;
+                    case EVENT_UPSTREAM_LOST:
+                        // TODO: Re-evaluate possible upstreams. Currently upstream reevaluation
+                        // is triggered via received CONNECTIVITY_ACTION broadcasts that result
+                        // in being passed a TetherMasterSM.CMD_UPSTREAM_CHANGED.
+                        mUpstreamNetworkMonitor.processNetworkLost((Network) message.obj);
+                        break;
                     default:
                         retValue = false;
                         break;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e87a2b5..a111bf9 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -723,7 +723,8 @@
     public void onUserAdded(int userHandle) {
         // If the user is restricted tie them to the parent user's VPN
         UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
-        if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+        if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle
+                && mVpnUsers != null) {
             synchronized(Vpn.this) {
                 try {
                     addVpnUserLocked(userHandle);
@@ -741,7 +742,8 @@
     public void onUserRemoved(int userHandle) {
         // clean up if restricted
         UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
-        if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+        if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle
+                && mVpnUsers != null) {
             synchronized(Vpn.this) {
                 try {
                     removeVpnUserLocked(userHandle);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 212e077..e9d9628 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -18,13 +18,17 @@
 
 import android.Manifest;
 import android.accounts.Account;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IContentService;
-import android.content.Intent;
 import android.content.ISyncStatusObserver;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.PeriodicSync;
 import android.content.SyncAdapterType;
 import android.content.SyncInfo;
@@ -32,22 +36,30 @@
 import android.content.SyncStatusInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.ProviderInfo;
 import android.database.IContentObserver;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.FactoryTest;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
+import com.android.server.SystemService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -62,12 +74,66 @@
  */
 public final class ContentService extends IContentService.Stub {
     private static final String TAG = "ContentService";
+
+    public static class Lifecycle extends SystemService {
+        private ContentService mContentService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            final boolean factoryTest = (FactoryTest
+                    .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL);
+            mContentService = new ContentService(getContext(), factoryTest);
+            publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mContentService);
+        }
+
+        @Override
+        public void onCleanupUser(int userHandle) {
+            synchronized (mContentService.mCache) {
+                mContentService.mCache.remove(userHandle);
+            }
+        }
+    }
+
     private Context mContext;
     private boolean mFactoryTest;
+
     private final ObserverNode mRootNode = new ObserverNode("");
+
     private SyncManager mSyncManager = null;
     private final Object mSyncManagerLock = new Object();
 
+    /**
+     * Map from userId to providerPackageName to [clientPackageName, uri] to
+     * value. This structure is carefully optimized to keep invalidation logic
+     * as cheap as possible.
+     */
+    @GuardedBy("mCache")
+    private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>>
+            mCache = new SparseArray<>();
+
+    private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mCache) {
+                if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+                    mCache.clear();
+                } else {
+                    final Uri data = intent.getData();
+                    if (data != null) {
+                        final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                                UserHandle.USER_NULL);
+                        final String packageName = data.getSchemeSpecificPart();
+                        invalidateCacheLocked(userId, packageName, null);
+                    }
+                }
+            }
+        }
+    };
+
     private SyncManager getSyncManager() {
         if (SystemProperties.getBoolean("config.disable_network", false)) {
             return null;
@@ -85,13 +151,15 @@
     }
 
     @Override
-    protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP,
                 "caller doesn't have the DUMP permission");
 
+        final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, "  ");
+
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
-        long identityToken = clearCallingIdentity();
+        final long identityToken = clearCallingIdentity();
         try {
             if (mSyncManager == null) {
                 pw.println("No SyncManager created!  (Disk full?)");
@@ -132,6 +200,19 @@
                 pw.print(" Total number of nodes: "); pw.println(counts[0]);
                 pw.print(" Total number of observers: "); pw.println(counts[1]);
             }
+
+            synchronized (mCache) {
+                pw.println();
+                pw.println("Cached content:");
+                pw.increaseIndent();
+                for (int i = 0; i < mCache.size(); i++) {
+                    pw.println("User " + mCache.keyAt(i) + ":");
+                    pw.increaseIndent();
+                    pw.println(mCache.valueAt(i));
+                    pw.decreaseIndent();
+                }
+                pw.decreaseIndent();
+            }
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -167,6 +248,20 @@
                         return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
                     }
                 });
+
+        final IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+        packageFilter.addDataScheme("package");
+        mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
+                packageFilter, null, null);
+
+        final IntentFilter localeFilter = new IntentFilter();
+        localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+        mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
+                localeFilter, null, null);
     }
 
     public void systemReady() {
@@ -223,6 +318,7 @@
                 UserHandle.getCallingUserId());
     }
 
+    @Override
     public void unregisterContentObserver(IContentObserver observer) {
         if (observer == null) {
             throw new IllegalArgumentException("You must pass a valid observer");
@@ -312,6 +408,11 @@
                             uri.getAuthority());
                 }
             }
+
+            synchronized (mCache) {
+                final String providerPackageName = getProviderPackageName(uri);
+                invalidateCacheLocked(userHandle, providerPackageName, uri);
+            }
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -341,7 +442,9 @@
         }
     }
 
+    @Override
     public void requestSync(Account account, String authority, Bundle extras) {
+        Bundle.setDefusable(extras, true);
         ContentResolver.validateSyncExtrasBundle(extras);
         int userId = UserHandle.getCallingUserId();
         int uId = Binder.getCallingUid();
@@ -370,6 +473,7 @@
      * Depending on the request, we enqueue to suit in the SyncManager.
      * @param request The request object. Validation of this object is done by its builder.
      */
+    @Override
     public void sync(SyncRequest request) {
         syncAsUser(request, UserHandle.getCallingUserId());
     }
@@ -378,6 +482,7 @@
      * If the user id supplied is different to the calling user, the caller must hold the
      * INTERACT_ACROSS_USERS_FULL permission.
      */
+    @Override
     public void syncAsUser(SyncRequest request, int userId) {
         enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
         int callerUid = Binder.getCallingUid();
@@ -476,6 +581,7 @@
         }
     }
 
+    @Override
     public void cancelRequest(SyncRequest request) {
         SyncManager syncManager = getSyncManager();
         if (syncManager == null) return;
@@ -610,6 +716,7 @@
     @Override
     public void addPeriodicSync(Account account, String authority, Bundle extras,
                                 long pollFrequency) {
+        Bundle.setDefusable(extras, true);
         if (account == null) {
             throw new IllegalArgumentException("Account must not be null");
         }
@@ -638,7 +745,9 @@
         }
     }
 
+    @Override
     public void removePeriodicSync(Account account, String authority, Bundle extras) {
+        Bundle.setDefusable(extras, true);
         if (account == null) {
             throw new IllegalArgumentException("Account must not be null");
         }
@@ -660,7 +769,7 @@
         }
     }
 
-
+    @Override
     public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
                                                ComponentName cname) {
         if (account == null) {
@@ -682,6 +791,7 @@
         }
     }
 
+    @Override
     public int getIsSyncable(Account account, String providerName) {
         return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
     }
@@ -690,6 +800,7 @@
      * If the user id supplied is different to the calling user, the caller must hold the
      * INTERACT_ACROSS_USERS_FULL permission.
      */
+    @Override
     public int getIsSyncableAsUser(Account account, String providerName, int userId) {
         enforceCrossUserPermission(userId,
                 "no permission to read the sync settings for user " + userId);
@@ -709,6 +820,7 @@
         return -1;
     }
 
+    @Override
     public void setIsSyncable(Account account, String providerName, int syncable) {
         if (TextUtils.isEmpty(providerName)) {
             throw new IllegalArgumentException("Authority must not be empty");
@@ -780,11 +892,11 @@
         }
     }
 
+    @Override
     public boolean isSyncActive(Account account, String authority, ComponentName cname) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
         int userId = UserHandle.getCallingUserId();
-        int callingUid = Binder.getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
             SyncManager syncManager = getSyncManager();
@@ -798,6 +910,7 @@
         }
     }
 
+    @Override
     public List<SyncInfo> getCurrentSyncs() {
         return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
     }
@@ -806,6 +919,7 @@
      * If the user id supplied is different to the calling user, the caller must hold the
      * INTERACT_ACROSS_USERS_FULL permission.
      */
+    @Override
     public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
         enforceCrossUserPermission(userId,
                 "no permission to read the sync settings for user " + userId);
@@ -824,6 +938,7 @@
         }
     }
 
+    @Override
     public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
         return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
     }
@@ -832,6 +947,7 @@
      * If the user id supplied is different to the calling user, the caller must hold the
      * INTERACT_ACROSS_USERS_FULL permission.
      */
+    @Override
     public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
                                               ComponentName cname, int userId) {
         if (TextUtils.isEmpty(authority)) {
@@ -843,7 +959,6 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
 
-        int callerUid = Binder.getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
             SyncManager syncManager = getSyncManager();
@@ -862,6 +977,7 @@
         }
     }
 
+    @Override
     public boolean isSyncPending(Account account, String authority, ComponentName cname) {
         return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
     }
@@ -873,7 +989,6 @@
                 "no permission to read the sync stats");
         enforceCrossUserPermission(userId,
                 "no permission to retrieve the sync settings for user " + userId);
-        int callerUid = Binder.getCallingUid();
         long identityToken = clearCallingIdentity();
         SyncManager syncManager = getSyncManager();
         if (syncManager == null) return false;
@@ -891,6 +1006,7 @@
         }
     }
 
+    @Override
     public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
         long identityToken = clearCallingIdentity();
         try {
@@ -903,6 +1019,7 @@
         }
     }
 
+    @Override
     public void removeStatusChangeListener(ISyncStatusObserver callback) {
         long identityToken = clearCallingIdentity();
         try {
@@ -915,10 +1032,87 @@
         }
     }
 
-    public static ContentService main(Context context, boolean factoryTest) {
-        ContentService service = new ContentService(context, factoryTest);
-        ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
-        return service;
+    private @Nullable String getProviderPackageName(Uri uri) {
+        final ProviderInfo pi = mContext.getPackageManager()
+                .resolveContentProvider(uri.getAuthority(), 0);
+        return (pi != null) ? pi.packageName : null;
+    }
+
+    private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
+            String providerPackageName) {
+        ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
+        if (userCache == null) {
+            userCache = new ArrayMap<>();
+            mCache.put(userId, userCache);
+        }
+        ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
+        if (packageCache == null) {
+            packageCache = new ArrayMap<>();
+            userCache.put(providerPackageName, packageCache);
+        }
+        return packageCache;
+    }
+
+    private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
+        ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
+        if (userCache == null) return;
+
+        ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
+        if (packageCache == null) return;
+
+        if (uri != null) {
+            for (int i = 0; i < packageCache.size();) {
+                final Pair<String, Uri> key = packageCache.keyAt(i);
+                if (key.second != null && key.second.toString().startsWith(uri.toString())) {
+                    Slog.d(TAG, "Invalidating cache for key " + key);
+                    packageCache.removeAt(i);
+                } else {
+                    i++;
+                }
+            }
+        } else {
+            Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
+            packageCache.clear();
+        }
+    }
+
+    @Override
+    public void putCache(String packageName, Uri key, Bundle value, int userId) {
+        Bundle.setDefusable(value, true);
+        enforceCrossUserPermission(userId, TAG);
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
+        mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
+                packageName);
+
+        final String providerPackageName = getProviderPackageName(key);
+        final Pair<String, Uri> fullKey = Pair.create(packageName, key);
+
+        synchronized (mCache) {
+            final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
+                    providerPackageName);
+            if (value != null) {
+                cache.put(fullKey, value);
+            } else {
+                cache.remove(fullKey);
+            }
+        }
+    }
+
+    @Override
+    public Bundle getCache(String packageName, Uri key, int userId) {
+        enforceCrossUserPermission(userId, TAG);
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
+        mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
+                packageName);
+
+        final String providerPackageName = getProviderPackageName(key);
+        final Pair<String, Uri> fullKey = Pair.create(packageName, key);
+
+        synchronized (mCache) {
+            final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
+                    providerPackageName);
+            return cache.get(fullKey);
+        }
     }
 
     /**
@@ -965,6 +1159,7 @@
                 }
             }
 
+            @Override
             public void binderDied() {
                 synchronized (observersLock) {
                     removeObserverLocked(observer);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 0d97434..e5342ce 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -78,8 +78,9 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
-import android.util.SparseArray;
 
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerInternal;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -113,9 +114,7 @@
  * All scheduled syncs will be passed on to JobScheduler as jobs
  * (See {@link #scheduleSyncOperationH(SyncOperation, long)}. This function schedules a job
  * with JobScheduler with appropriate delay and constraints (according to backoffs and extras).
- * A local copy of each scheduled SyncOperation object is stored in {@link mScheduledSyncs}.This
- * acts as a cache, so that we don't have to query JobScheduler every time we want to get a list of
- * all scheduled operations. The scheduleSyncOperationH function also assigns a unique jobId to each
+ * The scheduleSyncOperationH function also assigns a unique jobId to each
  * SyncOperation.
  *
  * Periodic Syncs:
@@ -129,14 +128,6 @@
  * run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
  * are rescheduled. A rescheduled sync will get a new jobId.
  *
- * State of {@link mScheduledSyncs}:
- * Every one-off SyncOperation will be put into this SparseArray when it is scheduled with
- * JobScheduler. And it will be removed once JobScheduler has started the job. Periodic syncs work
- * differently. They will always be present in mScheduledSyncs until the periodic sync is removed.
- * This is to ensure that if a request to add a periodic sync comes in, we add a new one only if a
- * duplicate doesn't exist. At every point of time, mScheduledSyncs and JobScheduler will show the
- * same pending syncs.
- *
  * @hide
  */
 public class SyncManager {
@@ -192,6 +183,13 @@
      */
     private static final long SYNC_DELAY_ON_CONFLICT = 10*1000; // 10 seconds
 
+    /**
+     * Generate job ids in the range [MIN_SYNC_JOB_ID, MAX_SYNC_JOB_ID) to avoid conflicts with
+     * other jobs scheduled by the system process.
+     */
+    private static final int MIN_SYNC_JOB_ID = 100000;
+    private static final int MAX_SYNC_JOB_ID = 110000;
+
     private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/";
     private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
     private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
@@ -213,6 +211,7 @@
     private final NotificationManager mNotificationMgr;
     private final IBatteryStats mBatteryStats;
     private JobScheduler mJobScheduler;
+    private JobSchedulerInternal mJobSchedulerInternal;
     private SyncJobService mSyncJobService;
 
     private SyncStorageEngine mSyncStorageEngine;
@@ -228,14 +227,13 @@
 
     protected SyncAdaptersCache mSyncAdapters;
 
-    // Cache of all operations scheduled on the JobScheduler so that JobScheduler doesn't have
-    // to be queried often.
-    private SparseArray<SyncOperation> mScheduledSyncs = new SparseArray<SyncOperation>(32);
     private final Random mRand;
 
-    private boolean isJobIdInUseLockedH(int jobId) {
-        if (mScheduledSyncs.indexOfKey(jobId) >= 0) {
-            return true;
+    private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
+        for (JobInfo job: pendingJobs) {
+            if (job.getId() == jobId) {
+                return true;
+            }
         }
         for (ActiveSyncContext asc: mActiveSyncContexts) {
             if (asc.mSyncOperation.jobId == jobId) {
@@ -246,35 +244,25 @@
     }
 
     private int getUnusedJobIdH() {
-        synchronized (mScheduledSyncs) {
-            int newJobId;
-            do {
-                newJobId = mRand.nextInt(Integer.MAX_VALUE);
-            } while (isJobIdInUseLockedH(newJobId));
-            return newJobId;
-        }
+        int newJobId;
+        do {
+            newJobId = MIN_SYNC_JOB_ID + mRand.nextInt(MAX_SYNC_JOB_ID - MIN_SYNC_JOB_ID);
+        } while (isJobIdInUseLockedH(newJobId,
+                mJobSchedulerInternal.getSystemScheduledPendingJobs()));
+        return newJobId;
     }
 
-    private void addSyncOperationToCache(SyncOperation op) {
-        synchronized (mScheduledSyncs) {
-            mScheduledSyncs.put(op.jobId, op);
-        }
-    }
-
-    private void removeSyncOperationFromCache(int jobId) {
-        synchronized (mScheduledSyncs) {
-            mScheduledSyncs.remove(jobId);
-        }
-    }
-
-    private List<SyncOperation> getAllPendingSyncsFromCache() {
-        synchronized (mScheduledSyncs) {
-            List<SyncOperation> pending = new ArrayList<SyncOperation>(mScheduledSyncs.size());
-            for (int i=0; i<mScheduledSyncs.size(); i++) {
-                pending.add(mScheduledSyncs.valueAt(i));
+    private List<SyncOperation> getAllPendingSyncs() {
+        verifyJobScheduler();
+        List<JobInfo> pendingJobs = mJobSchedulerInternal.getSystemScheduledPendingJobs();
+        List<SyncOperation> pendingSyncs = new ArrayList<SyncOperation>(pendingJobs.size());
+        for (JobInfo job: pendingJobs) {
+            SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
+            if (op != null) {
+                pendingSyncs.add(op);
             }
-            return pending;
         }
+        return pendingSyncs;
     }
 
     private final BroadcastReceiver mStorageIntentReceiver =
@@ -436,7 +424,7 @@
         mSyncHandler.postAtFrontOfQueue(new Runnable() {
             @Override
             public void run() {
-                List<SyncOperation> ops = getAllPendingSyncsFromCache();
+                List<SyncOperation> ops = getAllPendingSyncs();
                 Set<String> cleanedKeys = new HashSet<String>();
                 for (SyncOperation opx: ops) {
                     if (cleanedKeys.contains(opx.key)) {
@@ -448,53 +436,14 @@
                             continue;
                         }
                         if (opx.key.equals(opy.key)) {
-                            removeSyncOperationFromCache(opy.jobId);
                             mJobScheduler.cancel(opy.jobId);
                         }
                     }
                 }
-                ensureDefaultPeriodicSyncsH();
             }
         });
     }
 
-    private void ensureDefaultPeriodicSyncsH() {
-
-        long defaultPeriod = SyncStorageEngine.DEFAULT_POLL_FREQUENCY_SECONDS;
-        long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(defaultPeriod);
-
-        List<AuthorityInfo> authorities = mSyncStorageEngine.getAllAuthorities();
-        List<SyncOperation> syncs = getAllPendingSyncsFromCache();
-        for (AuthorityInfo authority: authorities) {
-            boolean foundPeriodicSync = false;
-            for (SyncOperation op: syncs) {
-                if (op.isPeriodic && authority.target.matchesSpec(op.target)) {
-                    foundPeriodicSync = true;
-                    break;
-                }
-            }
-            if (!foundPeriodicSync) {
-                EndPoint target = authority.target;
-                final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
-                        syncAdapterInfo = mSyncAdapters.getServiceInfo(
-                        SyncAdapterType.newKey(
-                                target.provider, target.account.type),
-                        target.userId);
-                if (syncAdapterInfo == null) {
-                    continue;
-                }
-                scheduleSyncOperationH(
-                    new SyncOperation(target, syncAdapterInfo.uid,
-                            syncAdapterInfo.componentName.getPackageName(),
-                            SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_PERIODIC,
-                            new Bundle(), syncAdapterInfo.type.allowParallelSyncs(),
-                            true /* periodic */, SyncOperation.NO_JOB_ID, defaultPeriod * 1000L,
-                            defaultFlex * 1000L)
-                );
-            }
-        }
-    }
-
     private synchronized void verifyJobScheduler() {
         if (mJobScheduler != null) {
             return;
@@ -504,18 +453,16 @@
         }
         mJobScheduler = (JobScheduler) mContext.getSystemService(
                 Context.JOB_SCHEDULER_SERVICE);
+        mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
         // Get all persisted syncs from JobScheduler
         List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
-        synchronized (mScheduledSyncs) {
-            for (JobInfo job : pendingJobs) {
-                SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
-                if (op != null) {
-                    mScheduledSyncs.put(op.jobId, op);
-                    if (!op.isPeriodic) {
-                        // Set the pending status of this EndPoint to true. Pending icon is
-                        // shown on the settings activity.
-                        mSyncStorageEngine.markPending(op.target, true);
-                    }
+        for (JobInfo job : pendingJobs) {
+            SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
+            if (op != null) {
+                if (!op.isPeriodic) {
+                    // Set the pending status of this EndPoint to true. Pending icon is
+                    // shown on the settings activity.
+                    mSyncStorageEngine.markPending(op.target, true);
                 }
             }
         }
@@ -738,7 +685,7 @@
     }
 
     private void setAuthorityPendingState(EndPoint info) {
-        List<SyncOperation> ops = getAllPendingSyncsFromCache();
+        List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (!op.isPeriodic && op.target.matchesSpec(info)) {
                 getSyncStorageEngine().markPending(info, true);
@@ -958,11 +905,10 @@
 
     private void removeSyncsForAuthority(EndPoint info) {
         verifyJobScheduler();
-        List<SyncOperation> ops = getAllPendingSyncsFromCache();
+        List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (op.target.matchesSpec(info)) {
-                removeSyncOperationFromCache(op.jobId);
-                getJobScheduler().cancel(op.jobId);
+                 getJobScheduler().cancel(op.jobId);
             }
         }
     }
@@ -992,7 +938,7 @@
      * Get a list of periodic syncs corresponding to the given target.
      */
     public List<PeriodicSync> getPeriodicSyncs(EndPoint target) {
-        List<SyncOperation> ops = getAllPendingSyncsFromCache();
+        List<SyncOperation> ops = getAllPendingSyncs();
         List<PeriodicSync> periodicSyncs = new ArrayList<PeriodicSync>();
 
         for (SyncOperation op: ops) {
@@ -1176,12 +1122,11 @@
      * to current backoff and delayUntil values of this EndPoint.
      */
     private void rescheduleSyncs(EndPoint target) {
-        List<SyncOperation> ops = getAllPendingSyncsFromCache();
+        List<SyncOperation> ops = getAllPendingSyncs();
         int count = 0;
         for (SyncOperation op: ops) {
             if (!op.isPeriodic && op.target.matchesSpec(target)) {
                 count++;
-                removeSyncOperationFromCache(op.jobId);
                 getJobScheduler().cancel(op.jobId);
                 postScheduleSyncMessage(op);
             }
@@ -1282,7 +1227,7 @@
             int duplicatesCount = 0;
             long now = SystemClock.elapsedRealtime();
             syncOperation.expectedRuntime = now + minDelay;
-            List<SyncOperation> pending = getAllPendingSyncsFromCache();
+            List<SyncOperation> pending = getAllPendingSyncs();
             SyncOperation opWithLeastExpectedRuntime = syncOperation;
             for (SyncOperation op : pending) {
                 if (op.isPeriodic) {
@@ -1307,7 +1252,6 @@
                         if (isLoggable) {
                             Slog.v(TAG, "Cancelling duplicate sync " + op);
                         }
-                        removeSyncOperationFromCache(op.jobId);
                         getJobScheduler().cancel(op.jobId);
                     }
                 }
@@ -1325,7 +1269,6 @@
         if (syncOperation.jobId == SyncOperation.NO_JOB_ID) {
             syncOperation.jobId = getUnusedJobIdH();
         }
-        addSyncOperationToCache(syncOperation);
 
         if (isLoggable) {
             Slog.v(TAG, "scheduling sync operation " + syncOperation.toString());
@@ -1357,7 +1300,7 @@
         }
 
         getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
-                syncOperation.target.userId);
+                syncOperation.target.userId, "sync");
     }
 
     /**
@@ -1366,10 +1309,9 @@
      * have null account/provider info to specify all accounts/providers.
      */
     public void clearScheduledSyncOperations(SyncStorageEngine.EndPoint info) {
-        List<SyncOperation> ops = getAllPendingSyncsFromCache();
+        List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (!op.isPeriodic && op.target.matchesSpec(info)) {
-                removeSyncOperationFromCache(op.jobId);
                 getJobScheduler().cancel(op.jobId);
                 getSyncStorageEngine().markPending(op.target, false);
             }
@@ -1384,11 +1326,10 @@
      * @param extras extras bundle to uniquely identify sync.
      */
     public void cancelScheduledSyncOperation(SyncStorageEngine.EndPoint info, Bundle extras) {
-        List<SyncOperation> ops = getAllPendingSyncsFromCache();
+        List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (!op.isPeriodic && op.target.matchesSpec(info)
                     && syncExtrasEquals(extras, op.extras, false)) {
-                removeSyncOperationFromCache(op.jobId);
                 getJobScheduler().cancel(op.jobId);
             }
         }
@@ -1497,10 +1438,9 @@
 
         // Clean up the storage engine database
         mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
-        List<SyncOperation> ops = getAllPendingSyncsFromCache();
+        List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (op.target.userId == userId) {
-                removeSyncOperationFromCache(op.jobId);
                 getJobScheduler().cancel(op.jobId);
             }
         }
@@ -1666,7 +1606,7 @@
 
     protected void dumpPendingSyncs(PrintWriter pw) {
         pw.println("Pending Syncs:");
-        List<SyncOperation> pendingSyncs = getAllPendingSyncsFromCache();
+        List<SyncOperation> pendingSyncs = getAllPendingSyncs();
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (!op.isPeriodic) {
@@ -1680,7 +1620,7 @@
 
     protected void dumpPeriodicSyncs(PrintWriter pw) {
         pw.println("Periodic Syncs:");
-        List<SyncOperation> pendingSyncs = getAllPendingSyncsFromCache();
+        List<SyncOperation> pendingSyncs = getAllPendingSyncs();
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (op.isPeriodic) {
@@ -2271,6 +2211,7 @@
         void checkIfDeviceReady() {
             if (mProvisioned && mBootCompleted) {
                 synchronized(this) {
+                    mSyncStorageEngine.restoreAllPeriodicSyncs();
                     // Dispatch any stashed messages.
                     obtainMessage(MESSAGE_RELEASE_MESSAGES_FROM_QUEUE).sendToTarget();
                 }
@@ -2289,10 +2230,6 @@
         private boolean tryEnqueueMessageUntilReadyToRun(Message msg) {
             synchronized (this) {
                 if (!mBootCompleted || !mProvisioned) {
-                    if (msg.what == MESSAGE_START_SYNC) {
-                        SyncOperation op = (SyncOperation) msg.obj;
-                        addSyncOperationToCache(op);
-                    }
                     // Need to copy the message bc looper will recycle it.
                     Message m = Message.obtain(msg);
                     mUnreadyQueue.add(m);
@@ -2509,7 +2446,6 @@
             if (op.isPeriodic) {
                 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
             } else {
-                removeSyncOperationFromCache(op.jobId);
                 scheduleSyncOperationH(op, delay);
             }
         }
@@ -2519,7 +2455,6 @@
             if (op.isPeriodic) {
                 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
             } else {
-                removeSyncOperationFromCache(op.jobId);
                 scheduleSyncOperationH(op, delay);
             }
         }
@@ -2545,7 +2480,7 @@
             if (op.isPeriodic) {
                 // Don't allow this periodic to run if a previous instance failed and is currently
                 // scheduled according to some backoff criteria.
-                List<SyncOperation> ops = getAllPendingSyncsFromCache();
+                List<SyncOperation> ops = getAllPendingSyncs();
                 for (SyncOperation syncOperation: ops) {
                     if (syncOperation.sourcePeriodicId == op.jobId) {
                         mSyncJobService.callJobFinished(op.jobId, false);
@@ -2565,9 +2500,6 @@
                     deferSyncH(op, 0 /* No minimum delay */);
                     return;
                 }
-            } else {
-                // Remove SyncOperation entry from mScheduledSyncs cache for non periodic jobs.
-                removeSyncOperationFromCache(op.jobId);
             }
 
             // Check for conflicting syncs.
@@ -2622,7 +2554,6 @@
             }
             if (mBootCompleted) {
                 doDatabaseCleanup();
-                mSyncStorageEngine.restoreAllPeriodicSyncs();
             }
 
             AccountAndUser[] accounts = mRunningAccounts;
@@ -2647,10 +2578,9 @@
                 }
             }
 
-            List<SyncOperation> ops = getAllPendingSyncsFromCache();
+            List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
                 if (!containsAccountAndUser(accounts, op.target.account, op.target.userId)) {
-                    removeSyncOperationFromCache(op.jobId);
                     getJobScheduler().cancel(op.jobId);
                 }
             }
@@ -2696,7 +2626,7 @@
                         + " flexMillis: " + flex
                         + " extras: " + extras.toString());
             }
-            List<SyncOperation> ops = getAllPendingSyncsFromCache();
+            List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
                 if (op.isPeriodic && op.target.matchesSpec(target)
                         && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
@@ -2735,7 +2665,7 @@
          */
         private void removePeriodicSyncInternalH(SyncOperation syncOperation) {
             // Remove this periodic sync and all one-off syncs initiated by it.
-            List<SyncOperation> ops = getAllPendingSyncsFromCache();
+            List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
                 if (op.sourcePeriodicId == syncOperation.jobId || op.jobId == syncOperation.jobId) {
                     ActiveSyncContext asc = findActiveSyncContextH(syncOperation.jobId);
@@ -2743,7 +2673,6 @@
                         mSyncJobService.callJobFinished(syncOperation.jobId, false);
                         runSyncFinishedOrCanceledH(null, asc);
                     }
-                    removeSyncOperationFromCache(op.jobId);
                     getJobScheduler().cancel(op.jobId);
                 }
             }
@@ -2751,7 +2680,7 @@
 
         private void removePeriodicSyncH(EndPoint target, Bundle extras) {
             verifyJobScheduler();
-            List<SyncOperation> ops = getAllPendingSyncsFromCache();
+            List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
                 if (op.isPeriodic && op.target.matchesSpec(target)
                         && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
@@ -2927,7 +2856,7 @@
         private void reschedulePeriodicSyncH(SyncOperation syncOperation) {
             // Ensure that the periodic sync wasn't removed.
             SyncOperation periodicSync = null;
-            List<SyncOperation> ops = getAllPendingSyncsFromCache();
+            List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
                 if (op.isPeriodic && syncOperation.matchesPeriodicOperation(op)) {
                     periodicSync = op;
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 957b087..804be4e 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -17,6 +17,7 @@
 package com.android.server.content;
 
 import android.accounts.Account;
+import android.app.job.JobInfo;
 import android.content.pm.PackageManager;
 import android.content.ContentResolver;
 import android.os.Bundle;
@@ -320,11 +321,11 @@
 
     int findPriority() {
         if (isInitialization()) {
-            return 2;
+            return JobInfo.PRIORITY_SYNC_INITIALIZATION;
         } else if (isExpedited()) {
-            return 1;
+            return JobInfo.PRIORITY_SYNC_EXPEDITED;
         }
-        return 0;
+        return JobInfo.PRIORITY_DEFAULT;
     }
 
     private String toKey() {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 05aabf1..bc3fc6a 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -80,7 +80,7 @@
     private static final String XML_TAG_LISTEN_FOR_TICKLES = "listenForTickles";
 
     /** Default time for a periodic sync. */
-    static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
+    private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
 
     /** Percentage of period that is flex by default, if no flexMillis is set. */
     private static final double DEFAULT_FLEX_PERCENT_SYNC = 0.04;
@@ -857,16 +857,6 @@
         }
     }
 
-    List<AuthorityInfo> getAllAuthorities() {
-        List<AuthorityInfo> authorities = new ArrayList<AuthorityInfo>();
-        synchronized (mAuthorities) {
-            for (int i = 0; i < mAuthorities.size(); i++) {
-                authorities.add(mAuthorities.valueAt(i));
-            }
-        }
-        return authorities;
-    }
-
     /**
      * Returns true if there is currently a sync operation being actively processed for the given
      * target.
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1ed7070..8f8afd5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -103,7 +103,6 @@
     private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
 
     // Brightness animation ramp rate in brightness units per second.
-    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
     private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
 
     private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
@@ -244,6 +243,9 @@
     private boolean mAppliedDimming;
     private boolean mAppliedLowPower;
 
+    // Brightness ramp rate fast.
+    private final int mBrightnessRampRateFast;
+
     // The controller for the automatic brightness level.
     private AutomaticBrightnessController mAutomaticBrightnessController;
 
@@ -303,6 +305,9 @@
         mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
 
+        mBrightnessRampRateFast = resources.getInteger(
+                com.android.internal.R.integer.config_brightness_ramp_rate_fast);
+
         int lightSensorRate = resources.getInteger(
                 com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
         long brighteningLightDebounce = resources.getInteger(
@@ -698,7 +703,7 @@
         if (!mPendingScreenOff) {
             if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
                 animateScreenBrightness(brightness,
-                        slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
+                        slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : mBrightnessRampRateFast);
             } else {
                 animateScreenBrightness(brightness, 0);
             }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 088d96e..715d2d8 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -17,12 +17,12 @@
 package com.android.server.display;
 
 import android.content.res.Resources;
-import android.os.Build;
 import com.android.server.LocalServices;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
 
 import android.content.Context;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -31,7 +31,6 @@
 import android.os.Trace;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.view.Display;
 import android.view.DisplayEventReceiver;
 import android.view.Surface;
@@ -381,14 +380,14 @@
                             | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
                 }
 
+                final Resources res = getContext().getResources();
                 if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
-                    final Resources res = getContext().getResources();
                     mInfo.name = res.getString(
                             com.android.internal.R.string.display_manager_built_in_display_name);
                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
                             | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
                     if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)
-                            || (Build.HARDWARE.contains("goldfish")
+                            || (Build.IS_EMULATOR
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
@@ -416,6 +415,11 @@
                     if (SystemProperties.getBoolean("persist.demo.hdmirotates", false)) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
                     }
+
+                    if (!res.getBoolean(
+                                com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
+                        mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+                    }
                 }
             }
             return mInfo;
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 8813a61..1f6616e 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -335,7 +335,8 @@
 
     private ServiceInfo getServiceInfo(ComponentName name) {
         try {
-            return name != null ? mContext.getPackageManager().getServiceInfo(name, 0) : null;
+            return name != null ? mContext.getPackageManager().getServiceInfo(name,
+                    PackageManager.MATCH_DEBUG_TRIAGED_MISSING) : null;
         } catch (NameNotFoundException e) {
             return null;
         }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 13e7648..7b134ca 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -62,6 +62,7 @@
 import android.hardware.fingerprint.IFingerprintDaemonCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
@@ -504,6 +505,9 @@
     }
 
     public boolean hasEnrolledFingerprints(int userId) {
+        if (userId != UserHandle.getCallingUserId()) {
+            checkPermission(INTERACT_ACROSS_USERS);
+        }
         return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
     }
 
@@ -901,13 +905,15 @@
 
             // Group ID is arbitrarily set to parent profile user ID. It just represents
             // the default fingerprints for the user.
-            final int effectiveGroupId = getEffectiveUserId(groupId);
+            if (!isCurrentUserOrProfile(groupId)) {
+                return;
+            }
 
             final boolean restricted = isRestricted();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    startEnrollment(token, cryptoClone, effectiveGroupId, receiver, flags, restricted);
+                    startEnrollment(token, cryptoClone, groupId, receiver, flags, restricted);
                 }
             });
         }
@@ -1007,15 +1013,14 @@
         @Override // Binder call
         public void rename(final int fingerId, final int groupId, final String name) {
             checkPermission(MANAGE_FINGERPRINT);
-
-            // Group ID is arbitrarily set to parent profile user ID. It just represents
-            // the default fingerprints for the user.
-            final int effectiveGroupId = getEffectiveUserId(groupId);
+            if (!isCurrentUserOrProfile(groupId)) {
+                return;
+            }
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
-                            effectiveGroupId, name);
+                            groupId, name);
                 }
             });
         }
@@ -1025,9 +1030,11 @@
             if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return Collections.emptyList();
             }
-            int effectiveUserId = getEffectiveUserId(userId);
+            if (!isCurrentUserOrProfile(userId)) {
+                return Collections.emptyList();
+            }
 
-            return FingerprintService.this.getEnrolledFingerprints(effectiveUserId);
+            return FingerprintService.this.getEnrolledFingerprints(userId);
         }
 
         @Override // Binder call
@@ -1036,8 +1043,10 @@
                 return false;
             }
 
-            int effectiveUserId  = getEffectiveUserId(userId);
-            return FingerprintService.this.hasEnrolledFingerprints(effectiveUserId);
+            if (!isCurrentUserOrProfile(userId)) {
+                return false;
+            }
+            return FingerprintService.this.hasEnrolledFingerprints(userId);
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 8c12060..603402e 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -218,6 +218,9 @@
     //            True by default.
     static final String PROPERTY_WAKE_ON_HOTPLUG = "ro.hdmi.wake_on_hotplug";
 
+    // TODO(OEM): Set this to true to enable 'Set Menu Language' feature. False by default.
+    static final String PROPERTY_SET_MENU_LANGUAGE = "ro.hdmi.set_menu_language";
+
     // Set to false to allow playback device to go to suspend mode even
     // when it's an active source. True by default.
     static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 39c6732..69c012e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -46,6 +46,9 @@
     private static final boolean WAKE_ON_HOTPLUG =
             SystemProperties.getBoolean(Constants.PROPERTY_WAKE_ON_HOTPLUG, true);
 
+    private static final boolean SET_MENU_LANGUAGE =
+            SystemProperties.getBoolean(Constants.PROPERTY_SET_MENU_LANGUAGE, false);
+
     private boolean mIsActiveSource = false;
 
     // Used to keep the device awake while it is the active source. For devices that
@@ -162,15 +165,13 @@
     @ServiceThreadOnly
     protected void onStandby(boolean initiatedByCec, int standbyAction) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled() || initiatedByCec) {
+        if (!mService.isControlEnabled() || initiatedByCec || !mAutoTvOff) {
             return;
         }
         switch (standbyAction) {
             case HdmiControlService.STANDBY_SCREEN_OFF:
-                if (mAutoTvOff) {
-                    mService.sendCecCommand(
-                            HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
-                }
+                mService.sendCecCommand(
+                        HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
                 break;
             case HdmiControlService.STANDBY_SHUTDOWN:
                 // ACTION_SHUTDOWN is taken as a signal to power off all the devices.
@@ -316,6 +317,9 @@
     @ServiceThreadOnly
     protected boolean handleSetMenuLanguage(HdmiCecMessage message) {
         assertRunOnServiceThread();
+        if (!SET_MENU_LANGUAGE) {
+            return false;
+        }
 
         try {
             String iso3Language = new String(message.getParams(), 0, 3, "US-ASCII");
@@ -345,6 +349,7 @@
             Slog.w(TAG, "Can't handle <Set Menu Language> of " + iso3Language);
             return false;
         } catch (UnsupportedEncodingException e) {
+            Slog.w(TAG, "Can't handle <Set Menu Language>", e);
             return false;
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 459c47f..fed7e4b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -419,6 +419,7 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_SCREEN_OFF);
             filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(Intent.ACTION_SHUTDOWN);
             filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
             getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter);
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
index 0b201710..537df81 100644
--- a/services/core/java/com/android/server/hdmi/HdmiLogger.java
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -21,6 +21,7 @@
 import android.os.SystemClock;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.Log;
 
 import java.util.HashMap;
 
@@ -42,6 +43,7 @@
     // Logging duration for same error message.
     private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000;  // 20s
 
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
 
     private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
@@ -83,10 +85,9 @@
     }
 
     private void debugInternal(String logMessage) {
-        if (true || IS_USER_BUILD) {
-            return;
+        if (DEBUG) {
+            Slog.d(TAG, logMessage);
         }
-        Slog.d(TAG, logMessage);
     }
 
     private static final String toLogString(String logMessage, Object[] objs) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 033a243..e73beaa 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -948,7 +948,7 @@
     // Must be called on handler.
     private void showMissingKeyboardLayoutNotification(InputDevice device) {
         if (!mKeyboardLayoutNotificationShown) {
-            final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
+            final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
             if (device != null) {
                 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
             }
@@ -1109,7 +1109,8 @@
         final PackageManager pm = mContext.getPackageManager();
         Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
         for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE)) {
+                PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
             final int priority = resolveInfo.priority;
             visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
@@ -1125,7 +1126,8 @@
                 ActivityInfo receiver = pm.getReceiverInfo(
                         new ComponentName(d.packageName, d.receiverName),
                         PackageManager.GET_META_DATA
-                                | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+                                | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
                 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
             } catch (NameNotFoundException ex) {
             }
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java
new file mode 100644
index 0000000..75170ec
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job;
+
+import android.app.job.JobInfo;
+
+import java.util.List;
+
+/**
+ * JobScheduler local system service interface.
+ * {@hide} Only for use within the system server.
+ */
+public interface JobSchedulerInternal {
+
+    /**
+     * Returns a list of pending jobs scheduled by the system service.
+     */
+    List<JobInfo> getSystemScheduledPendingJobs();
+}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 811c947..fa8620f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -19,6 +19,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
@@ -44,28 +45,36 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.Process;
-import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.TimeUtils;
 
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
+import com.android.server.job.JobStore.JobStatusFunctor;
 import com.android.server.job.controllers.AppIdleController;
 import com.android.server.job.controllers.BatteryController;
 import com.android.server.job.controllers.ConnectivityController;
 import com.android.server.job.controllers.ContentObserverController;
+import com.android.server.job.controllers.DeviceIdleJobsController;
 import com.android.server.job.controllers.IdleController;
 import com.android.server.job.controllers.JobStatus;
 import com.android.server.job.controllers.StateController;
 import com.android.server.job.controllers.TimeController;
 
+import libcore.util.EmptyArray;
+
 /**
  * Responsible for taking jobs representing work to be performed by a client app, and determining
  * based on the criteria specified when that job should be run against the client application's
@@ -80,11 +89,16 @@
  */
 public final class JobSchedulerService extends com.android.server.SystemService
         implements StateChangedListener, JobCompletedListener {
-    public static final boolean DEBUG = false;
-    /** The number of concurrent jobs we run at one time. */
-    private static final int MAX_JOB_CONTEXTS_COUNT
-            = ActivityManager.isLowRamDeviceStatic() ? 3 : 6;
     static final String TAG = "JobSchedulerService";
+    public static final boolean DEBUG = false;
+
+    /** The maximum number of concurrent jobs we run at one time. */
+    private static final int MAX_JOB_CONTEXTS_COUNT = 8;
+    /** Enforce a per-app limit on scheduled jobs? */
+    private static final boolean ENFORCE_MAX_JOBS = true;
+    /** The maximum number of jobs that we allow an unprivileged app to schedule */
+    private static final int MAX_JOBS_PER_APP = 100;
+
     /** Global local for all job scheduler state. */
     final Object mLock = new Object();
     /** Master list of jobs. */
@@ -136,7 +150,7 @@
      */
     final ArrayList<JobStatus> mPendingJobs = new ArrayList<>();
 
-    final ArrayList<Integer> mStartedUsers = new ArrayList<>();
+    int[] mStartedUsers = EmptyArray.INT;
 
     final JobHandler mHandler;
     final JobSchedulerStub mJobSchedulerStub;
@@ -151,23 +165,49 @@
     boolean mReadyToRock;
 
     /**
-     * True when in device idle mode, so we don't want to schedule any jobs.
-     */
-    boolean mDeviceIdleMode;
-
-    /**
-     * What we last reported to DeviceIdleController about wheter we are active.
+     * What we last reported to DeviceIdleController about whether we are active.
      */
     boolean mReportedActive;
 
     /**
+     * Current limit on the number of concurrent JobServiceContext entries we want to
+     * keep actively running a job.
+     */
+    int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+
+    /**
+     * Which uids are currently in the foreground.
+     */
+    final SparseIntArray mUidPriorityOverride = new SparseIntArray();
+
+    // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked --
+
+    /**
+     * This array essentially stores the state of mActiveServices array.
+     * The ith index stores the job present on the ith JobServiceContext.
+     * We manipulate this array until we arrive at what jobs should be running on
+     * what JobServiceContext.
+     */
+    JobStatus[] mTmpAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
+    /**
+     * Indicates whether we need to act on this jobContext id
+     */
+    boolean[] mTmpAssignAct = new boolean[MAX_JOB_CONTEXTS_COUNT];
+    /**
+     * The uid whose jobs we would like to assign to a context.
+     */
+    int[] mTmpAssignPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
+
+    /**
      * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
      * still clean up. On reinstall the package will have a new uid.
      */
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            Slog.d(TAG, "Receieved: " + intent.getAction());
+            if (DEBUG) {
+                Slog.d(TAG, "Receieved: " + intent.getAction());
+            }
             if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                 // If this is an outright uninstall rather than the first half of an
                 // app update sequence, cancel the jobs associated with the app.
@@ -184,21 +224,17 @@
                     Slog.d(TAG, "Removing jobs for user: " + userId);
                 }
                 cancelJobsForUser(userId);
-            } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())
-                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
-                updateIdleMode(mPowerManager != null
-                        ? (mPowerManager.isDeviceIdleMode()
-                        || mPowerManager.isLightDeviceIdleMode())
-                        : false);
             }
         }
     };
 
     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
+            updateUidState(uid, procState);
         }
 
         @Override public void onUidGone(int uid) throws RemoteException {
+            updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         }
 
         @Override public void onUidActive(int uid) throws RemoteException {
@@ -215,14 +251,20 @@
 
     @Override
     public void onStartUser(int userHandle) {
-        mStartedUsers.add(userHandle);
+        mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
+        // Let's kick any outstanding jobs for this user.
+        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+    }
+
+    @Override
+    public void onUnlockUser(int userHandle) {
         // Let's kick any outstanding jobs for this user.
         mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
     }
 
     @Override
     public void onStopUser(int userHandle) {
-        mStartedUsers.remove(Integer.valueOf(userHandle));
+        mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userHandle);
     }
 
     /**
@@ -233,11 +275,12 @@
      * @return Result of this operation. See <code>JobScheduler#RESULT_*</code> return codes.
      */
     public int schedule(JobInfo job, int uId) {
-        return scheduleAsPackage(job, uId, null, -1);
+        return scheduleAsPackage(job, uId, null, -1, null);
     }
 
-    public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
-        JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId);
+    public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId,
+            String tag) {
+        JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
         try {
             if (ActivityManagerNative.getDefault().getAppStartMode(uId,
                     job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
@@ -250,28 +293,35 @@
         if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
         JobStatus toCancel;
         synchronized (mLock) {
+            // Jobs on behalf of others don't apply to the per-app job cap
+            if (ENFORCE_MAX_JOBS && packageName == null) {
+                if (mJobs.countJobsForUid(uId) > MAX_JOBS_PER_APP) {
+                    Slog.w(TAG, "Too many jobs for uid " + uId);
+                    throw new IllegalStateException("Apps may not schedule more than "
+                                + MAX_JOBS_PER_APP + " distinct jobs");
+                }
+            }
+
             toCancel = mJobs.getJobByUidAndJobId(uId, job.getId());
-        }
-        startTrackingJob(jobStatus, toCancel);
-        if (toCancel != null) {
-            cancelJobImpl(toCancel);
+            if (toCancel != null) {
+                cancelJobImpl(toCancel);
+            }
+            startTrackingJob(jobStatus, toCancel);
         }
         mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
         return JobScheduler.RESULT_SUCCESS;
     }
 
     public List<JobInfo> getPendingJobs(int uid) {
-        ArrayList<JobInfo> outList = new ArrayList<JobInfo>();
         synchronized (mLock) {
-            ArraySet<JobStatus> jobs = mJobs.getJobs();
-            for (int i=0; i<jobs.size(); i++) {
-                JobStatus job = jobs.valueAt(i);
-                if (job.getUid() == uid) {
-                    outList.add(job.getJob());
-                }
+            List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+            ArrayList<JobInfo> outList = new ArrayList<JobInfo>(jobs.size());
+            for (int i = jobs.size() - 1; i >= 0; i--) {
+                JobStatus job = jobs.get(i);
+                outList.add(job.getJob());
             }
+            return outList;
         }
-        return outList;
     }
 
     void cancelJobsForUser(int userHandle) {
@@ -343,44 +393,44 @@
         }
     }
 
-    void updateIdleMode(boolean enabled) {
-        boolean changed = false;
-        boolean rocking;
+    void updateUidState(int uid, int procState) {
         synchronized (mLock) {
-            if (mDeviceIdleMode != enabled) {
-                changed = true;
+            if (procState == ActivityManager.PROCESS_STATE_TOP) {
+                // Only use this if we are exactly the top app.  All others can live
+                // with just the foreground priority.  This means that persistent processes
+                // can never be the top app priority...  that is fine.
+                mUidPriorityOverride.put(uid, JobInfo.PRIORITY_TOP_APP);
+            } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                mUidPriorityOverride.put(uid, JobInfo.PRIORITY_FOREGROUND_APP);
+            } else {
+                mUidPriorityOverride.delete(uid);
             }
-            rocking = mReadyToRock;
         }
-        if (changed) {
-            if (rocking) {
-                for (int i=0; i<mControllers.size(); i++) {
-                    mControllers.get(i).deviceIdleModeChanged(enabled);
+    }
+
+    @Override
+    public void onDeviceIdleStateChanged(boolean deviceIdle) {
+        synchronized (mLock) {
+            if (deviceIdle) {
+                // When becoming idle, make sure no jobs are actively running.
+                for (int i=0; i<mActiveServices.size(); i++) {
+                    JobServiceContext jsc = mActiveServices.get(i);
+                    final JobStatus executing = jsc.getRunningJob();
+                    if (executing != null) {
+                        jsc.cancelExecutingJob(JobParameters.REASON_DEVICE_IDLE);
+                    }
                 }
-            }
-            synchronized (mLock) {
-                mDeviceIdleMode = enabled;
-                if (enabled) {
-                    // When becoming idle, make sure no jobs are actively running.
-                    for (int i=0; i<mActiveServices.size(); i++) {
-                        JobServiceContext jsc = mActiveServices.get(i);
-                        final JobStatus executing = jsc.getRunningJob();
-                        if (executing != null) {
-                            jsc.cancelExecutingJob(JobParameters.REASON_DEVICE_IDLE);
+            } else {
+                // When coming out of idle, allow thing to start back up.
+                if (mReadyToRock) {
+                    if (mLocalDeviceIdleController != null) {
+                        if (!mReportedActive) {
+                            mReportedActive = true;
+                            mLocalDeviceIdleController.setJobsActive(true);
                         }
                     }
-                } else {
-                    // When coming out of idle, allow thing to start back up.
-                    if (rocking) {
-                        if (mLocalDeviceIdleController != null) {
-                            if (!mReportedActive) {
-                                mReportedActive = true;
-                                mLocalDeviceIdleController.setJobsActive(true);
-                            }
-                        }
-                    }
-                    mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
                 }
+                mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
             }
         }
     }
@@ -425,6 +475,7 @@
         mControllers.add(BatteryController.get(this));
         mControllers.add(AppIdleController.get(this));
         mControllers.add(ContentObserverController.get(this));
+        mControllers.add(DeviceIdleJobsController.get(this));
 
         mHandler = new JobHandler(context.getMainLooper());
         mJobSchedulerStub = new JobSchedulerStub();
@@ -433,6 +484,7 @@
 
     @Override
     public void onStart() {
+        publishLocalService(JobSchedulerInternal.class, new LocalService());
         publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
     }
 
@@ -445,14 +497,13 @@
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, filter, null, null);
             final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
-            userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
-            userFilter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
             mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
             try {
                 ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
-                        ActivityManager.UID_OBSERVER_IDLE);
+                        ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
+                        | ActivityManager.UID_OBSERVER_IDLE);
             } catch (RemoteException e) {
                 // ignored; both services live in system_server
             }
@@ -471,14 +522,15 @@
                                     getContext().getMainLooper()));
                 }
                 // Attach jobs to their controllers.
-                ArraySet<JobStatus> jobs = mJobs.getJobs();
-                for (int i=0; i<jobs.size(); i++) {
-                    JobStatus job = jobs.valueAt(i);
-                    for (int controller=0; controller<mControllers.size(); controller++) {
-                        mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
-                        mControllers.get(controller).maybeStartTrackingJobLocked(job, null);
+                mJobs.forEachJob(new JobStatusFunctor() {
+                    @Override
+                    public void process(JobStatus job) {
+                        for (int controller = 0; controller < mControllers.size(); controller++) {
+                            final StateController sc = mControllers.get(controller);
+                            sc.maybeStartTrackingJobLocked(job, null);
+                        }
                     }
-                }
+                });
                 // GO GO GO!
                 mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
             }
@@ -741,23 +793,13 @@
          * as many as we can.
          */
         private void queueReadyJobsForExecutionLockedH() {
-            ArraySet<JobStatus> jobs = mJobs.getJobs();
-            mPendingJobs.clear();
             if (DEBUG) {
                 Slog.d(TAG, "queuing all ready jobs for execution:");
             }
-            for (int i=0; i<jobs.size(); i++) {
-                JobStatus job = jobs.valueAt(i);
-                if (isReadyToBeExecutedLocked(job)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "    queued " + job.toShortString());
-                    }
-                    mPendingJobs.add(job);
-                } else if (areJobConstraintsNotSatisfiedLocked(job)) {
-                    stopJobOnServiceContextLocked(job,
-                            JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
-                }
-            }
+            mPendingJobs.clear();
+            mJobs.forEachJob(mReadyQueueFunctor);
+            mReadyQueueFunctor.postProcess();
+
             if (DEBUG) {
                 final int queuedJobs = mPendingJobs.size();
                 if (queuedJobs == 0) {
@@ -768,6 +810,34 @@
             }
         }
 
+        class ReadyJobQueueFunctor implements JobStatusFunctor {
+            ArrayList<JobStatus> newReadyJobs;
+
+            @Override
+            public void process(JobStatus job) {
+                if (isReadyToBeExecutedLocked(job)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "    queued " + job.toShortString());
+                    }
+                    if (newReadyJobs == null) {
+                        newReadyJobs = new ArrayList<JobStatus>();
+                    }
+                    newReadyJobs.add(job);
+                } else if (areJobConstraintsNotSatisfiedLocked(job)) {
+                    stopJobOnServiceContextLocked(job,
+                            JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
+                }
+            }
+
+            public void postProcess() {
+                if (newReadyJobs != null) {
+                    mPendingJobs.addAll(newReadyJobs);
+                }
+                newReadyJobs = null;
+            }
+        }
+        private final ReadyJobQueueFunctor mReadyQueueFunctor = new ReadyJobQueueFunctor();
+
         /**
          * The state of at least one job has changed. Here is where we could enforce various
          * policies on when we want to execute jobs.
@@ -777,18 +847,21 @@
          * If more than 4 jobs total are ready we send them all off.
          * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
          */
-        private void maybeQueueReadyJobsForExecutionLockedH() {
-            mPendingJobs.clear();
-            int chargingCount = 0;
-            int idleCount =  0;
-            int backoffCount = 0;
-            int connectivityCount = 0;
-            int contentCount = 0;
-            List<JobStatus> runnableJobs = null;
-            ArraySet<JobStatus> jobs = mJobs.getJobs();
-            if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
-            for (int i=0; i<jobs.size(); i++) {
-                JobStatus job = jobs.valueAt(i);
+        class MaybeReadyJobQueueFunctor implements JobStatusFunctor {
+            int chargingCount;
+            int idleCount;
+            int backoffCount;
+            int connectivityCount;
+            int contentCount;
+            List<JobStatus> runnableJobs;
+
+            public MaybeReadyJobQueueFunctor() {
+                reset();
+            }
+
+            // Functor method invoked for each job via JobStore.forEachJob()
+            @Override
+            public void process(JobStatus job) {
                 if (isReadyToBeExecutedLocked(job)) {
                     try {
                         if (ActivityManagerNative.getDefault().getAppStartMode(job.getUid(),
@@ -797,7 +870,7 @@
                             Slog.w(TAG, "Aborting job " + job.getUid() + ":"
                                     + job.getJob().toString() + " -- package not allowed to start");
                             mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget();
-                            continue;
+                            return;
                         }
                     } catch (RemoteException e) {
                     }
@@ -825,23 +898,45 @@
                             JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
                 }
             }
-            if (backoffCount > 0 ||
-                    idleCount >= MIN_IDLE_COUNT ||
-                    connectivityCount >= MIN_CONNECTIVITY_COUNT ||
-                    chargingCount >= MIN_CHARGING_COUNT ||
-                    contentCount  >= MIN_CONTENT_COUNT ||
-                    (runnableJobs != null && runnableJobs.size() >= MIN_READY_JOBS_COUNT)) {
-                if (DEBUG) {
-                    Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
+
+            public void postProcess() {
+                if (backoffCount > 0 ||
+                        idleCount >= MIN_IDLE_COUNT ||
+                        connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+                        chargingCount >= MIN_CHARGING_COUNT ||
+                        contentCount  >= MIN_CONTENT_COUNT ||
+                        (runnableJobs != null && runnableJobs.size() >= MIN_READY_JOBS_COUNT)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
+                    }
+                    mPendingJobs.addAll(runnableJobs);
+                } else {
+                    if (DEBUG) {
+                        Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
+                    }
                 }
-                for (int i=0; i<runnableJobs.size(); i++) {
-                    mPendingJobs.add(runnableJobs.get(i));
-                }
-            } else {
-                if (DEBUG) {
-                    Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
-                }
+
+                // Be ready for next time
+                reset();
             }
+
+            private void reset() {
+                chargingCount = 0;
+                idleCount =  0;
+                backoffCount = 0;
+                connectivityCount = 0;
+                contentCount = 0;
+                runnableJobs = null;
+            }
+        }
+        private final MaybeReadyJobQueueFunctor mMaybeQueueFunctor = new MaybeReadyJobQueueFunctor();
+
+        private void maybeQueueReadyJobsForExecutionLockedH() {
+            if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
+
+            mPendingJobs.clear();
+            mJobs.forEachJob(mMaybeQueueFunctor);
+            mMaybeQueueFunctor.postProcess();
         }
 
         /**
@@ -850,18 +945,31 @@
          *      - It's not pending.
          *      - It's not already running on a JSC.
          *      - The user that requested the job is running.
+         *      - The component is enabled and runnable.
          */
         private boolean isReadyToBeExecutedLocked(JobStatus job) {
             final boolean jobReady = job.isReady();
             final boolean jobPending = mPendingJobs.contains(job);
             final boolean jobActive = isCurrentlyActiveLocked(job);
-            final boolean userRunning = mStartedUsers.contains(job.getUserId());
+
+            final int userId = job.getUserId();
+            final boolean userStarted = ArrayUtils.contains(mStartedUsers, userId);
+            final boolean componentPresent;
+            try {
+                componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
+                        job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+                        userId) != null);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+
             if (DEBUG) {
                 Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
                         + " ready=" + jobReady + " pending=" + jobPending
-                        + " active=" + jobActive + " userRunning=" + userRunning);
+                        + " active=" + jobActive + " userStarted=" + userStarted
+                        + " componentPresent=" + componentPresent);
             }
-            return userRunning && jobReady && !jobPending && !jobActive;
+            return userStarted && componentPresent && jobReady && !jobPending && !jobActive;
         }
 
         /**
@@ -880,10 +988,6 @@
          */
         private void maybeRunPendingJobsH() {
             synchronized (mLock) {
-                if (mDeviceIdleMode) {
-                    // If device is idle, we will not schedule jobs to run.
-                    return;
-                }
                 if (DEBUG) {
                     Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
                 }
@@ -893,6 +997,18 @@
         }
     }
 
+    private int evaluateJobPriorityLocked(JobStatus job) {
+        int priority = job.getPriority();
+        if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
+            return priority;
+        }
+        int override = mUidPriorityOverride.get(job.getSourceUid(), 0);
+        if (override != 0) {
+            return override;
+        }
+        return priority;
+    }
+
     /**
      * Takes jobs from pending queue and runs them on available contexts.
      * If no contexts are available, preempts lower priority jobs to
@@ -904,24 +1020,44 @@
             Slog.d(TAG, printPendingQueue());
         }
 
-        // This array essentially stores the state of mActiveServices array.
-        // ith index stores the job present on the ith JobServiceContext.
-        // We manipulate this array until we arrive at what jobs should be running on
-        // what JobServiceContext.
-        JobStatus[] contextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
-        // Indicates whether we need to act on this jobContext id
-        boolean[] act = new boolean[MAX_JOB_CONTEXTS_COUNT];
-        int[] preferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
-        for (int i=0; i<mActiveServices.size(); i++) {
-            contextIdToJobMap[i] = mActiveServices.get(i).getRunningJob();
-            preferredUidForContext[i] = mActiveServices.get(i).getPreferredUid();
+        int memLevel;
+        try {
+            memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel();
+        } catch (RemoteException e) {
+            memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+        }
+        switch (memLevel) {
+            case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+                mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3;
+                break;
+            case ProcessStats.ADJ_MEM_FACTOR_LOW:
+                mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3;
+                break;
+            case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+                mMaxActiveJobs = 1;
+                break;
+            default:
+                mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+                break;
+        }
+
+        JobStatus[] contextIdToJobMap = mTmpAssignContextIdToJobMap;
+        boolean[] act = mTmpAssignAct;
+        int[] preferredUidForContext = mTmpAssignPreferredUidForContext;
+        int numActive = 0;
+        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
+            final JobServiceContext js = mActiveServices.get(i);
+            if ((contextIdToJobMap[i] = js.getRunningJob()) != null) {
+                numActive++;
+            }
+            act[i] = false;
+            preferredUidForContext[i] = js.getPreferredUid();
         }
         if (DEBUG) {
             Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
         }
-        Iterator<JobStatus> it = mPendingJobs.iterator();
-        while (it.hasNext()) {
-            JobStatus nextPending = it.next();
+        for (int i=0; i<mPendingJobs.size(); i++) {
+            JobStatus nextPending = mPendingJobs.get(i);
 
             // If job is already running, go to next job.
             int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);
@@ -929,33 +1065,41 @@
                 continue;
             }
 
+            final int priority = evaluateJobPriorityLocked(nextPending);
+            nextPending.lastEvaluatedPriority = priority;
+
             // Find a context for nextPending. The context should be available OR
             // it should have lowest priority among all running jobs
             // (sharing the same Uid as nextPending)
             int minPriority = Integer.MAX_VALUE;
             int minPriorityContextId = -1;
-            for (int i=0; i<mActiveServices.size(); i++) {
-                JobStatus job = contextIdToJobMap[i];
-                int preferredUid = preferredUidForContext[i];
-                if (job == null && (preferredUid == nextPending.getUid() ||
-                        preferredUid == JobServiceContext.NO_PREFERRED_UID) ) {
-                    minPriorityContextId = i;
-                    break;
-                }
+            for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) {
+                JobStatus job = contextIdToJobMap[j];
+                int preferredUid = preferredUidForContext[j];
                 if (job == null) {
+                    if ((numActive < mMaxActiveJobs || priority >= JobInfo.PRIORITY_TOP_APP) &&
+                            (preferredUid == nextPending.getUid() ||
+                                    preferredUid == JobServiceContext.NO_PREFERRED_UID)) {
+                        // This slot is free, and we haven't yet hit the limit on
+                        // concurrent jobs...  we can just throw the job in to here.
+                        minPriorityContextId = j;
+                        numActive++;
+                        break;
+                    }
                     // No job on this context, but nextPending can't run here because
-                    // the context has a preferred Uid.
+                    // the context has a preferred Uid or we have reached the limit on
+                    // concurrent jobs.
                     continue;
                 }
                 if (job.getUid() != nextPending.getUid()) {
                     continue;
                 }
-                if (job.getPriority() >= nextPending.getPriority()) {
+                if (evaluateJobPriorityLocked(job) >= nextPending.lastEvaluatedPriority) {
                     continue;
                 }
-                if (minPriority > nextPending.getPriority()) {
-                    minPriority = nextPending.getPriority();
-                    minPriorityContextId = i;
+                if (minPriority > nextPending.lastEvaluatedPriority) {
+                    minPriority = nextPending.lastEvaluatedPriority;
+                    minPriorityContextId = j;
                 }
             }
             if (minPriorityContextId != -1) {
@@ -966,7 +1110,7 @@
         if (DEBUG) {
             Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
         }
-        for (int i=0; i<mActiveServices.size(); i++) {
+        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
             boolean preservePreferredUid = false;
             if (act[i]) {
                 JobStatus js = mActiveServices.get(i).getRunningJob();
@@ -978,18 +1122,18 @@
                     mActiveServices.get(i).preemptExecutingJob();
                     preservePreferredUid = true;
                 } else {
+                    final JobStatus pendingJob = contextIdToJobMap[i];
                     if (DEBUG) {
                         Slog.d(TAG, "About to run job on context "
-                                + String.valueOf(i) + ", job: " + contextIdToJobMap[i]);
+                                + String.valueOf(i) + ", job: " + pendingJob);
                     }
                     for (int ic=0; ic<mControllers.size(); ic++) {
-                        StateController controller = mControllers.get(ic);
-                        controller.prepareForExecutionLocked(contextIdToJobMap[i]);
+                        mControllers.get(ic).prepareForExecutionLocked(pendingJob);
                     }
-                    if (!mActiveServices.get(i).executeRunnableJob(contextIdToJobMap[i])) {
-                        Slog.d(TAG, "Error executing " + contextIdToJobMap[i]);
+                    if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {
+                        Slog.d(TAG, "Error executing " + pendingJob);
                     }
-                    mPendingJobs.remove(contextIdToJobMap[i]);
+                    mPendingJobs.remove(pendingJob);
                 }
             }
             if (!preservePreferredUid) {
@@ -1007,6 +1151,29 @@
         return -1;
     }
 
+    final class LocalService implements JobSchedulerInternal {
+
+        /**
+         * Returns a list of all pending jobs. A running job is not considered pending. Periodic
+         * jobs are always considered pending.
+         */
+        @Override
+        public List<JobInfo> getSystemScheduledPendingJobs() {
+            synchronized (mLock) {
+                final List<JobInfo> pendingJobs = new ArrayList<JobInfo>();
+                mJobs.forEachJob(Process.SYSTEM_UID, new JobStatusFunctor() {
+                    @Override
+                    public void process(JobStatus job) {
+                        if (job.getJob().isPeriodic() || !isCurrentlyActiveLocked(job)) {
+                            pendingJobs.add(job.getJob());
+                        }
+                    }
+                });
+                return pendingJobs;
+            }
+        }
+    }
+
     /**
      * Binder stub trampoline implementation
      */
@@ -1024,7 +1191,9 @@
             final ComponentName service = job.getService();
             try {
                 ServiceInfo si = pm.getServiceInfo(service,
-                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid));
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        UserHandle.getUserId(uid));
                 if (si == null) {
                     throw new IllegalArgumentException("No such service " + service);
                 }
@@ -1088,19 +1257,29 @@
         }
 
         @Override
-        public int scheduleAsPackage(JobInfo job, String packageName, int userId)
+        public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag)
                 throws RemoteException {
+            final int callerUid = Binder.getCallingUid();
             if (DEBUG) {
-                Slog.d(TAG, "Scheduling job: " + job.toString() + " on behalf of " + packageName);
+                Slog.d(TAG, "Caller uid " + callerUid + " scheduling job: " + job.toString()
+                        + " on behalf of " + packageName);
             }
-            final int uid = Binder.getCallingUid();
-            if (uid != Process.SYSTEM_UID) {
-                throw new IllegalArgumentException("Only system process is allowed"
-                        + "to set packageName");
+
+            if (packageName == null) {
+                throw new NullPointerException("Must specify a package for scheduleAsPackage()");
             }
+
+            int mayScheduleForOthers = getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.UPDATE_DEVICE_STATS);
+            if (mayScheduleForOthers != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Caller uid " + callerUid
+                        + " not permitted to schedule jobs for other apps");
+            }
+
             long ident = Binder.clearCallingIdentity();
             try {
-                return JobSchedulerService.this.scheduleAsPackage(job, uid, packageName, userId);
+                return JobSchedulerService.this.scheduleAsPackage(job, callerUid,
+                        packageName, userId, tag);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -1156,8 +1335,48 @@
                 Binder.restoreCallingIdentity(identityToken);
             }
         }
+
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ResultReceiver resultReceiver) throws RemoteException {
+                (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
+                        this, in, out, err, args, resultReceiver);
+        }
     };
 
+    // Shell command infrastructure: run the given job immediately
+    int executeRunCommand(String pkgName, int userId, int jobId, boolean force) {
+        if (DEBUG) {
+            Slog.v(TAG, "executeRunCommand(): " + pkgName + "/" + userId
+                    + " " + jobId + " f=" + force);
+        }
+
+        try {
+            final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0, userId);
+            if (uid < 0) {
+                return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
+            }
+
+            synchronized (mLock) {
+                final JobStatus js = mJobs.getJobByUidAndJobId(uid, jobId);
+                if (js == null) {
+                    return JobSchedulerShellCommand.CMD_ERR_NO_JOB;
+                }
+
+                js.overrideState = (force) ? JobStatus.OVERRIDE_FULL : JobStatus.OVERRIDE_SOFT;
+                if (!js.isConstraintsSatisfied()) {
+                    js.overrideState = 0;
+                    return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS;
+                }
+
+                mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
+            }
+        } catch (RemoteException e) {
+            // can't happen
+        }
+        return 0;
+    }
+
     private String printContextIdToJobMap(JobStatus[] map, String initial) {
         StringBuilder s = new StringBuilder(initial + ": ");
         for (int i=0; i<map.length; i++) {
@@ -1183,34 +1402,33 @@
         return s.toString();
     }
 
-    void dumpInternal(PrintWriter pw) {
+    void dumpInternal(final PrintWriter pw) {
         final long now = SystemClock.elapsedRealtime();
         synchronized (mLock) {
-            pw.print("Started users: ");
-            for (int i=0; i<mStartedUsers.size(); i++) {
-                pw.print("u" + mStartedUsers.get(i) + " ");
-            }
-            pw.println();
+            pw.println("Started users: " + Arrays.toString(mStartedUsers));
             pw.println("Registered jobs:");
             if (mJobs.size() > 0) {
-                ArraySet<JobStatus> jobs = mJobs.getJobs();
-                for (int i=0; i<jobs.size(); i++) {
-                    JobStatus job = jobs.valueAt(i);
-                    pw.print("  Job #"); pw.print(i); pw.print(": ");
-                    pw.println(job.toShortString());
-                    job.dump(pw, "    ");
-                    pw.print("    Ready: ");
-                    pw.print(mHandler.isReadyToBeExecutedLocked(job));
-                    pw.print(" (job=");
-                    pw.print(job.isReady());
-                    pw.print(" pending=");
-                    pw.print(mPendingJobs.contains(job));
-                    pw.print(" active=");
-                    pw.print(isCurrentlyActiveLocked(job));
-                    pw.print(" user=");
-                    pw.print(mStartedUsers.contains(job.getUserId()));
-                    pw.println(")");
-                }
+                mJobs.forEachJob(new JobStatusFunctor() {
+                    private int index = 0;
+
+                    @Override
+                    public void process(JobStatus job) {
+                        pw.print("  Job #"); pw.print(index++); pw.print(": ");
+                        pw.println(job.toShortString());
+                        job.dump(pw, "    ", true);
+                        pw.print("    Ready: ");
+                        pw.print(mHandler.isReadyToBeExecutedLocked(job));
+                        pw.print(" (job=");
+                        pw.print(job.isReady());
+                        pw.print(" pending=");
+                        pw.print(mPendingJobs.contains(job));
+                        pw.print(" active=");
+                        pw.print(isCurrentlyActiveLocked(job));
+                        pw.print(" user=");
+                        pw.print(ArrayUtils.contains(mStartedUsers, job.getUserId()));
+                        pw.println(")");
+                    }
+                });
             } else {
                 pw.println("  None.");
             }
@@ -1219,28 +1437,50 @@
                 mControllers.get(i).dumpControllerStateLocked(pw);
             }
             pw.println();
-            pw.println(printPendingQueue());
+            pw.println("Uid priority overrides:");
+            for (int i=0; i< mUidPriorityOverride.size(); i++) {
+                pw.print("  "); pw.print(UserHandle.formatUid(mUidPriorityOverride.keyAt(i)));
+                pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i));
+            }
+            pw.println();
+            pw.println("Pending queue:");
+            for (int i=0; i<mPendingJobs.size(); i++) {
+                JobStatus job = mPendingJobs.get(i);
+                pw.print("  Pending #"); pw.print(i); pw.print(": ");
+                pw.println(job.toShortString());
+                job.dump(pw, "    ", false);
+                int priority = evaluateJobPriorityLocked(job);
+                if (priority != JobInfo.PRIORITY_DEFAULT) {
+                    pw.print("    Evaluated priority: "); pw.println(priority);
+                }
+                pw.print("    Tag: "); pw.println(job.getTag());
+            }
             pw.println();
             pw.println("Active jobs:");
             for (int i=0; i<mActiveServices.size(); i++) {
                 JobServiceContext jsc = mActiveServices.get(i);
+                pw.print("  Slot #"); pw.print(i); pw.print(": ");
                 if (jsc.getRunningJob() == null) {
+                    pw.println("inactive");
                     continue;
                 } else {
-                    final long timeout = jsc.getTimeoutElapsed();
-                    pw.print("Running for: ");
-                    pw.print((now - jsc.getExecutionStartTimeElapsed())/1000);
-                    pw.print("s timeout=");
-                    pw.print(timeout);
-                    pw.print(" fromnow=");
-                    pw.println(timeout-now);
-                    jsc.getRunningJob().dump(pw, "  ");
+                    pw.println(jsc.getRunningJob().toShortString());
+                    pw.print("    Running for: ");
+                    TimeUtils.formatDuration(now - jsc.getExecutionStartTimeElapsed(), pw);
+                    pw.print(", timeout at: ");
+                    TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
+                    pw.println();
+                    jsc.getRunningJob().dump(pw, "    ", false);
+                    int priority = evaluateJobPriorityLocked(jsc.getRunningJob());
+                    if (priority != JobInfo.PRIORITY_DEFAULT) {
+                        pw.print("    Evaluated priority: "); pw.println(priority);
+                    }
                 }
             }
             pw.println();
             pw.print("mReadyToRock="); pw.println(mReadyToRock);
-            pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode);
             pw.print("mReportedActive="); pw.println(mReportedActive);
+            pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs);
         }
         pw.println();
     }
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
new file mode 100644
index 0000000..2d62c1c
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job;
+
+import android.app.AppGlobals;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+public class JobSchedulerShellCommand extends ShellCommand {
+    public static final int CMD_ERR_NO_PACKAGE = -1000;
+    public static final int CMD_ERR_NO_JOB = -1001;
+    public static final int CMD_ERR_CONSTRAINTS = -1002;
+
+    JobSchedulerService mInternal;
+    IPackageManager mPM;
+
+    JobSchedulerShellCommand(JobSchedulerService service) {
+        mInternal = service;
+        mPM = AppGlobals.getPackageManager();
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            if ("run".equals(cmd)) {
+                return runJob();
+            } else {
+                return handleDefaultCommands(cmd);
+            }
+        } catch (Exception e) {
+            pw.println("Exception: " + e);
+        }
+        return -1;
+    }
+
+    private int runJob() {
+        try {
+            final int uid = Binder.getCallingUid();
+            final int perm = mPM.checkUidPermission(
+                    "android.permission.CHANGE_APP_IDLE_STATE", uid);
+            if (perm != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Uid " + uid
+                        + " not permitted to force scheduled jobs");
+            }
+        } catch (RemoteException e) {
+            // Can't happen
+        }
+
+        final PrintWriter pw = getOutPrintWriter();
+        boolean force = false;
+        int userId = UserHandle.USER_SYSTEM;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-f":
+                case "--force":
+                    force = true;
+                    break;
+
+                case "-u":
+                case "--user":
+                    userId = Integer.parseInt(getNextArgRequired());
+                    break;
+
+                default:
+                    pw.println("Error: unknown option '" + opt + "'");
+                    return -1;
+            }
+        }
+
+        final String pkgName = getNextArgRequired();
+        final int jobId = Integer.parseInt(getNextArgRequired());
+
+        int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
+        switch (ret) {
+            case CMD_ERR_NO_PACKAGE:
+                pw.print("Package not found: ");
+                pw.print(pkgName);
+                pw.print(" / user ");
+                pw.println(userId);
+                break;
+
+            case CMD_ERR_NO_JOB:
+                pw.print("Could not find job ");
+                pw.print(jobId);
+                pw.print(" in package ");
+                pw.print(pkgName);
+                pw.print(" / user ");
+                pw.println(userId);
+                break;
+
+            case CMD_ERR_CONSTRAINTS:
+                pw.print("Job ");
+                pw.print(jobId);
+                pw.print(" in package ");
+                pw.print(pkgName);
+                pw.print(" / user ");
+                pw.print(userId);
+                pw.println(" has functional constraints but --force not specified");
+                break;
+
+            default:
+                // success!
+                pw.print("Running job");
+                if (force) {
+                    pw.print(" [FORCED]");
+                }
+                pw.println();
+                break;
+        }
+        return ret;
+    }
+
+    @Override
+    public void onHelp() {
+        final PrintWriter pw = getOutPrintWriter();
+
+        pw.println("Job scheduler (jobscheduler) commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println();
+        pw.println("  run [-f | --force] [-u | --user USER_ID] PACKAGE JOB_ID");
+        pw.println("    Trigger immediate execution of a specific scheduled job.");
+        pw.println("    Options:");
+        pw.println("      -f or --force: run the job even if technical constraints such as");
+        pw.println("         connectivity are not currently met");
+        pw.println("      -u or --user: specify which user's job is to be run; the default is");
+        pw.println("         the primary or system user");
+        pw.println();
+    }
+
+}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 48549ce..4239248 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -204,7 +204,7 @@
                 return false;
             }
             try {
-                mBatteryStats.noteJobStart(job.getName(), job.getSourceUid());
+                mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
             } catch (RemoteException e) {
                 // Whatever.
             }
@@ -369,6 +369,13 @@
                     }
                     break;
                 case MSG_CANCEL:
+                    if (mVerb == VERB_FINISHED) {
+                        if (DEBUG) {
+                            Slog.d(TAG,
+                                   "Trying to process cancel for torn-down context, ignoring.");
+                        }
+                        return;
+                    }
                     mParams.setStopReason(message.arg1);
                     if (message.arg1 == JobParameters.REASON_PREEMPT) {
                         mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
@@ -478,12 +485,6 @@
          *     _ENDING     -> No point in doing anything here, so we ignore.
          */
         private void handleCancelH() {
-            if (mRunningJob == null) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Trying to process cancel for torn-down context, ignoring.");
-                }
-                return;
-            }
             if (JobSchedulerService.DEBUG) {
                 Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
                         + VERB_STRINGS[mVerb]);
@@ -511,7 +512,6 @@
 
         /** Process MSG_TIMEOUT here. */
         private void handleOpTimeoutH() {
-            mParams.setStopReason(JobParameters.REASON_TIMEOUT);
             switch (mVerb) {
                 case VERB_BINDING:
                     Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
@@ -536,6 +536,7 @@
                     // Not an error - client ran out of time.
                     Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
                             " sending onStop. "  + mRunningJob.toShortString());
+                    mParams.setStopReason(JobParameters.REASON_TIMEOUT);
                     sendStopMessageH();
                     break;
                 default:
@@ -580,7 +581,8 @@
                 }
                 completedJob = mRunningJob;
                 try {
-                    mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getSourceUid());
+                    mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
+                            mRunningJob.getSourceUid());
                 } catch (RemoteException e) {
                     // Whatever.
                 }
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 6020247..55f37b8 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -29,6 +29,7 @@
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -68,8 +69,8 @@
 
     /** Threshold to adjust how often we want to write to the db. */
     private static final int MAX_OPS_BEFORE_WRITE = 1;
-    final ArraySet<JobStatus> mJobSet;
     final Object mLock;
+    final JobSet mJobSet; // per-caller-uid tracking
     final Context mContext;
 
     private int mDirtyOperations;
@@ -114,7 +115,7 @@
         jobDir.mkdirs();
         mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
 
-        mJobSet = new ArraySet<JobStatus>();
+        mJobSet = new JobSet();
 
         readJobMapFromDisk(mJobSet);
     }
@@ -137,19 +138,6 @@
         return replaced;
     }
 
-    /**
-     * Whether this jobStatus object already exists in the JobStore.
-     */
-    public boolean containsJobIdForUid(int jobId, int uId) {
-        for (int i=mJobSet.size()-1; i>=0; i--) {
-            JobStatus ts = mJobSet.valueAt(i);
-            if (ts.getUid() == uId && ts.getJobId() == jobId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     boolean containsJob(JobStatus jobStatus) {
         return mJobSet.contains(jobStatus);
     }
@@ -158,6 +146,10 @@
         return mJobSet.size();
     }
 
+    public int countJobsForUid(int uid) {
+        return mJobSet.countJobsForUid(uid);
+    }
+
     /**
      * Remove the provided job. Will also delete the job if it was persisted.
      * @param writeBack If true, the job will be deleted (if it was persisted) immediately.
@@ -188,14 +180,7 @@
      * @return A list of all the jobs scheduled by the provided user. Never null.
      */
     public List<JobStatus> getJobsByUser(int userHandle) {
-        List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
-        for (int i=mJobSet.size()-1; i>=0; i--) {
-            JobStatus ts = mJobSet.valueAt(i);
-            if (UserHandle.getUserId(ts.getUid()) == userHandle) {
-                matchingJobs.add(ts);
-            }
-        }
-        return matchingJobs;
+        return mJobSet.getJobsByUser(userHandle);
     }
 
     /**
@@ -203,14 +188,7 @@
      * @return All JobStatus objects for a given uid from the master list. Never null.
      */
     public List<JobStatus> getJobsByUid(int uid) {
-        List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
-        for (int i=mJobSet.size()-1; i>=0; i--) {
-            JobStatus ts = mJobSet.valueAt(i);
-            if (ts.getUid() == uid) {
-                matchingJobs.add(ts);
-            }
-        }
-        return matchingJobs;
+        return mJobSet.getJobsByUid(uid);
     }
 
     /**
@@ -219,20 +197,25 @@
      * @return the JobStatus that matches the provided uId and jobId, or null if none found.
      */
     public JobStatus getJobByUidAndJobId(int uid, int jobId) {
-        for (int i=mJobSet.size()-1; i>=0; i--) {
-            JobStatus ts = mJobSet.valueAt(i);
-            if (ts.getUid() == uid && ts.getJobId() == jobId) {
-                return ts;
-            }
-        }
-        return null;
+        return mJobSet.get(uid, jobId);
     }
 
     /**
-     * @return The live array of JobStatus objects.
+     * Iterate over the set of all jobs, invoking the supplied functor on each.  This is for
+     * customers who need to examine each job; we'd much rather not have to generate
+     * transient unified collections for them to iterate over and then discard, or creating
+     * iterators every time a client needs to perform a sweep.
      */
-    public ArraySet<JobStatus> getJobs() {
-        return mJobSet;
+    public void forEachJob(JobStatusFunctor functor) {
+        mJobSet.forEachJob(functor);
+    }
+
+    public void forEachJob(int uid, JobStatusFunctor functor) {
+        mJobSet.forEachJob(uid, functor);
+    }
+
+    public interface JobStatusFunctor {
+        public void process(JobStatus jobStatus);
     }
 
     /** Version of the db schema. */
@@ -261,7 +244,7 @@
     }
 
     @VisibleForTesting
-    public void readJobMapFromDisk(ArraySet<JobStatus> jobSet) {
+    public void readJobMapFromDisk(JobSet jobSet) {
         new ReadJobMapFromDiskRunnable(jobSet).run();
     }
 
@@ -273,21 +256,19 @@
         @Override
         public void run() {
             final long startElapsed = SystemClock.elapsedRealtime();
-            List<JobStatus> mStoreCopy = new ArrayList<JobStatus>();
+            final List<JobStatus> storeCopy = new ArrayList<JobStatus>();
             synchronized (mLock) {
-                // Copy over the jobs so we can release the lock before writing.
-                for (int i=0; i<mJobSet.size(); i++) {
-                    JobStatus jobStatus = mJobSet.valueAt(i);
-
-                    if (!jobStatus.isPersisted()){
-                        continue;
+                // Clone the jobs so we can release the lock before writing.
+                mJobSet.forEachJob(new JobStatusFunctor() {
+                    @Override
+                    public void process(JobStatus job) {
+                        if (job.isPersisted()) {
+                            storeCopy.add(new JobStatus(job));
+                        }
                     }
-
-                    JobStatus copy = new JobStatus(jobStatus);
-                    mStoreCopy.add(copy);
-                }
+                });
             }
-            writeJobsMapImpl(mStoreCopy);
+            writeJobsMapImpl(storeCopy);
             if (JobSchedulerService.DEBUG) {
                 Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
                         - startElapsed) + "ms");
@@ -346,6 +327,9 @@
             if (jobStatus.getSourcePackageName() != null) {
                 out.attribute(null, "sourcePackageName", jobStatus.getSourcePackageName());
             }
+            if (jobStatus.getSourceTag() != null) {
+                out.attribute(null, "sourceTag", jobStatus.getSourceTag());
+            }
             out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
             out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
             out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
@@ -440,13 +424,13 @@
      * need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}.
      */
     private class ReadJobMapFromDiskRunnable implements Runnable {
-        private final ArraySet<JobStatus> jobSet;
+        private final JobSet jobSet;
 
         /**
          * @param jobSet Reference to the (empty) set of JobStatus objects that back the JobStore,
          *               so that after disk read we can populate it directly.
          */
-        ReadJobMapFromDiskRunnable(ArraySet<JobStatus> jobSet) {
+        ReadJobMapFromDiskRunnable(JobSet jobSet) {
             this.jobSet = jobSet;
         }
 
@@ -563,7 +547,9 @@
                 return null;
             }
 
-            final String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
+            String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
+
+            final String sourceTag = parser.getAttributeValue(null, "sourceTag");
 
             int eventType;
             // Read out constraints tag.
@@ -678,8 +664,20 @@
             jobBuilder.setExtras(extras);
             parser.nextTag(); // Consume </extras>
 
+            // Migrate sync jobs forward from earlier, incomplete representation
+            if ("android".equals(sourcePackageName)
+                    && extras != null
+                    && extras.getBoolean("SyncManagerJob", false)) {
+                sourcePackageName = extras.getString("owningPackage", sourcePackageName);
+                if (DEBUG) {
+                    Slog.i(TAG, "Fixing up sync job source package name from 'android' to '"
+                            + sourcePackageName + "'");
+                }
+            }
+
+            // And now we're done
             JobStatus js = new JobStatus(
-                    jobBuilder.build(), uid, sourcePackageName, sourceUserId,
+                    jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
                     elapsedRuntimes.first, elapsedRuntimes.second);
             return js;
         }
@@ -759,4 +757,131 @@
             return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed);
         }
     }
+
+    static class JobSet {
+        // Key is the getUid() originator of the jobs in each sheaf
+        private SparseArray<ArraySet<JobStatus>> mJobs;
+
+        public JobSet() {
+            mJobs = new SparseArray<ArraySet<JobStatus>>();
+        }
+
+        public List<JobStatus> getJobsByUid(int uid) {
+            ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+            ArraySet<JobStatus> jobs = mJobs.get(uid);
+            if (jobs != null) {
+                matchingJobs.addAll(jobs);
+            }
+            return matchingJobs;
+        }
+
+        // By user, not by uid, so we need to traverse by key and check
+        public List<JobStatus> getJobsByUser(int userId) {
+            ArrayList<JobStatus> result = new ArrayList<JobStatus>();
+            for (int i = mJobs.size() - 1; i >= 0; i--) {
+                if (UserHandle.getUserId(mJobs.keyAt(i)) == userId) {
+                    ArraySet<JobStatus> jobs = mJobs.get(i);
+                    if (jobs != null) {
+                        result.addAll(jobs);
+                    }
+                }
+            }
+            return result;
+        }
+
+        public boolean add(JobStatus job) {
+            final int uid = job.getUid();
+            ArraySet<JobStatus> jobs = mJobs.get(uid);
+            if (jobs == null) {
+                jobs = new ArraySet<JobStatus>();
+                mJobs.put(uid, jobs);
+            }
+            return jobs.add(job);
+        }
+
+        public boolean remove(JobStatus job) {
+            final int uid = job.getUid();
+            ArraySet<JobStatus> jobs = mJobs.get(uid);
+            boolean didRemove = (jobs != null) ? jobs.remove(job) : false;
+            if (didRemove && jobs.size() == 0) {
+                // no more jobs for this uid; let the now-empty set object be GC'd.
+                mJobs.remove(uid);
+            }
+            return didRemove;
+        }
+
+        public boolean contains(JobStatus job) {
+            final int uid = job.getUid();
+            ArraySet<JobStatus> jobs = mJobs.get(uid);
+            return jobs != null && jobs.contains(job);
+        }
+
+        public JobStatus get(int uid, int jobId) {
+            ArraySet<JobStatus> jobs = mJobs.get(uid);
+            if (jobs != null) {
+                for (int i = jobs.size() - 1; i >= 0; i--) {
+                    JobStatus job = jobs.valueAt(i);
+                    if (job.getJobId() == jobId) {
+                        return job;
+                    }
+                }
+            }
+            return null;
+        }
+
+        // Inefficient; use only for testing
+        public List<JobStatus> getAllJobs() {
+            ArrayList<JobStatus> allJobs = new ArrayList<JobStatus>(size());
+            for (int i = mJobs.size(); i >= 0; i--) {
+                allJobs.addAll(mJobs.valueAt(i));
+            }
+            return allJobs;
+        }
+
+        public void clear() {
+            mJobs.clear();
+        }
+
+        public int size() {
+            int total = 0;
+            for (int i = mJobs.size() - 1; i >= 0; i--) {
+                total += mJobs.valueAt(i).size();
+            }
+            return total;
+        }
+
+        // We only want to count the jobs that this uid has scheduled on its own
+        // behalf, not those that the app has scheduled on someone else's behalf.
+        public int countJobsForUid(int uid) {
+            int total = 0;
+            ArraySet<JobStatus> jobs = mJobs.get(uid);
+            if (jobs != null) {
+                for (int i = jobs.size() - 1; i >= 0; i--) {
+                    JobStatus job = jobs.valueAt(i);
+                    if (job.getUid() == job.getSourceUid()) {
+                        total++;
+                    }
+                }
+            }
+            return total;
+        }
+
+        public void forEachJob(JobStatusFunctor functor) {
+            for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) {
+                ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex);
+                for (int i = jobs.size() - 1; i >= 0; i--) {
+                    functor.process(jobs.valueAt(i));
+                }
+            }
+        }
+
+        public void forEachJob(int uid, JobStatusFunctor functor) {
+            ArraySet<JobStatus> jobs = mJobs.get(uid);
+            if (jobs != null) {
+                for (int i = jobs.size() - 1; i >= 0; i--) {
+                    functor.process(jobs.valueAt(i));
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/services/core/java/com/android/server/job/StateChangedListener.java
index 97dfad3..87bfc27 100644
--- a/services/core/java/com/android/server/job/StateChangedListener.java
+++ b/services/core/java/com/android/server/job/StateChangedListener.java
@@ -37,4 +37,6 @@
      *                  indicates to the scheduler that any ready jobs should be flushed.</strong>
      */
     public void onRunJobNow(JobStatus jobStatus);
+
+    public void onDeviceIdleStateChanged(boolean deviceIdle);
 }
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index f0c579f..2114fc3 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -87,7 +87,7 @@
         pw.println("Parole On: " + mAppIdleParoleOn);
         for (JobStatus task : mTrackedTasks) {
             pw.print(task.getSourcePackageName());
-            pw.print(":idle="
+            pw.print(":runnable="
                     + ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
             pw.print(", ");
         }
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index bd06645..6ef425a 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -185,7 +185,7 @@
         pw.println("Conn.");
         pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
         for (JobStatus js: mTrackedJobs) {
-            pw.println(String.valueOf(js.hashCode()).substring(0, 3) + ".."
+            pw.println(String.valueOf(js.getJobId() + "," + js.getUid())
                     + ": C=" + js.hasConnectivityConstraint()
                     + ", UM=" + js.hasUnmeteredConstraint());
         }
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
new file mode 100644
index 0000000..d2ef6a2
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job.controllers;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.server.DeviceIdleController;
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * When device is dozing, set constraint for all jobs, except whitelisted apps, as not satisfied.
+ * When device is not dozing, set constraint for all jobs as satisfied.
+ */
+public class DeviceIdleJobsController extends StateController {
+
+    private static final String LOG_TAG = "DeviceIdleJobsController";
+    private static final boolean LOG_DEBUG = false;
+
+    // Singleton factory
+    private static Object sCreationLock = new Object();
+    final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
+    private static DeviceIdleJobsController sController;
+
+    private final PowerManager mPowerManager;
+    private final DeviceIdleController.LocalService mLocalDeviceIdleController;
+
+    /**
+     * True when in device idle mode, so we don't want to schedule any jobs.
+     */
+    private boolean mDeviceIdleMode;
+    private int[] mDeviceIdleWhitelistAppIds;
+
+    /**
+     * Returns a singleton for the DeviceIdleJobsController
+     */
+    public static DeviceIdleJobsController get(JobSchedulerService service) {
+        synchronized (sCreationLock) {
+            if (sController == null) {
+                sController = new DeviceIdleJobsController(service, service.getContext(),
+                        service.getLock());
+            }
+            return sController;
+        }
+    }
+
+    // onReceive
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)
+                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
+                updateIdleMode(mPowerManager != null
+                        ? (mPowerManager.isDeviceIdleMode()
+                                || mPowerManager.isLightDeviceIdleMode())
+                        : false);
+            } else if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(action)) {
+                updateWhitelist();
+            }
+        }
+    };
+
+    private DeviceIdleJobsController(StateChangedListener stateChangedListener, Context context,
+            Object lock) {
+        super(stateChangedListener, context, lock);
+
+        // Register for device idle mode changes
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mLocalDeviceIdleController =
+                LocalServices.getService(DeviceIdleController.LocalService.class);
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+        filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
+        filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        mContext.registerReceiverAsUser(
+                mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+    }
+
+    void updateIdleMode(boolean enabled) {
+        boolean changed = false;
+        // Need the whitelist to be ready when going into idle
+        if (mDeviceIdleWhitelistAppIds == null) {
+            updateWhitelist();
+        }
+        synchronized (mLock) {
+            if (mDeviceIdleMode != enabled) {
+                changed = true;
+            }
+            mDeviceIdleMode = enabled;
+            if (LOG_DEBUG) Slog.d(LOG_TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
+            for (JobStatus task : mTrackedTasks) {
+                updateTaskStateLocked(task);
+            }
+        }
+        // Inform the job scheduler service about idle mode changes
+        if (changed) {
+            mStateChangedListener.onDeviceIdleStateChanged(enabled);
+        }
+    }
+
+    /**
+     * Fetches the latest whitelist from the device idle controller.
+     */
+    void updateWhitelist() {
+        synchronized (mLock) {
+            if (mLocalDeviceIdleController != null) {
+                mDeviceIdleWhitelistAppIds =
+                        mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds();
+                if (LOG_DEBUG) {
+                    Slog.d(LOG_TAG, "Got whitelist " + Arrays.toString(mDeviceIdleWhitelistAppIds));
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks if the given job's scheduling app id exists in the device idle user whitelist.
+     */
+    boolean isWhitelistedLocked(JobStatus job) {
+        if (mDeviceIdleWhitelistAppIds != null
+                && ArrayUtils.contains(mDeviceIdleWhitelistAppIds,
+                        UserHandle.getAppId(job.getSourceUid()))) {
+            return true;
+        }
+        return false;
+    }
+
+    private void updateTaskStateLocked(JobStatus task) {
+        boolean enableTask = !mDeviceIdleMode || isWhitelistedLocked(task);
+        task.setDeviceNotDozingConstraintSatisfied(enableTask);
+    }
+
+    @Override
+    public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+        synchronized (mLock) {
+            mTrackedTasks.add(jobStatus);
+            updateTaskStateLocked(jobStatus);
+        }
+    }
+
+    @Override
+    public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
+        mTrackedTasks.remove(jobStatus);
+    }
+
+    @Override
+    public void dumpControllerStateLocked(PrintWriter pw) {
+        pw.println("DeviceIdleJobsController");
+        for (JobStatus task : mTrackedTasks) {
+            pw.print(task.getSourcePackageName());
+            pw.print(":runnable="
+                    + ((task.satisfiedConstraints & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0));
+            pw.print(", ");
+        }
+        pw.println();
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 7638494..d9eb45c 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -197,7 +197,7 @@
         for (int i = 0; i < mTrackedTasks.size(); i++) {
             final JobStatus js = mTrackedTasks.get(i);
             pw.print("  ");
-            pw.print(String.valueOf(js.hashCode()).substring(0, 3));
+            pw.print(String.valueOf(js.getJobId() + "," + js.getUid()));
             pw.println("..");
         }
     }
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index f835069..39905d8 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -54,16 +54,24 @@
     static final int CONSTRAINT_CONNECTIVITY = 1<<5;
     static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
     static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
+    static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<8;
+
+    // Soft override: ignore constraints like time that don't affect API availability
+    public static final int OVERRIDE_SOFT = 1;
+    // Full override: ignore all constraints including API-affecting like connectivity
+    public static final int OVERRIDE_FULL = 2;
 
     final JobInfo job;
     /** Uid of the package requesting this job. */
     final int callingUid;
-    final String name;
-    final String tag;
+    final String batteryName;
 
     final String sourcePackageName;
     final int sourceUserId;
     final int sourceUid;
+    final String sourceTag;
+
+    final String tag;
 
     /**
      * Earliest point in the future at which this job will be eligible to run. A value of 0
@@ -87,6 +95,11 @@
     public ArraySet<Uri> changedUris;
     public ArraySet<String> changedAuthorities;
 
+    public int lastEvaluatedPriority;
+
+    // Used by shell commands
+    public int overrideState = 0;
+
     /**
      * For use only by ContentObserverController: state it is maintaining about content URIs
      * being observed.
@@ -99,12 +112,10 @@
     }
 
     private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
-            int sourceUserId, int numFailures, long earliestRunTimeElapsedMillis,
+            int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
             long latestRunTimeElapsedMillis) {
         this.job = job;
         this.callingUid = callingUid;
-        this.name = job.getService().flattenToShortString();
-        this.tag = "*job*/" + this.name;
 
         int tempSourceUid = -1;
         if (sourceUserId != -1 && sourcePackageName != null) {
@@ -119,12 +130,29 @@
             this.sourceUid = callingUid;
             this.sourceUserId = UserHandle.getUserId(callingUid);
             this.sourcePackageName = job.getService().getPackageName();
+            this.sourceTag = null;
         } else {
             this.sourceUid = tempSourceUid;
             this.sourceUserId = sourceUserId;
             this.sourcePackageName = sourcePackageName;
+            this.sourceTag = tag;
         }
 
+        if (this.sourceTag != null) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(job.getService().getPackageName());
+            sb.append('/');
+            sb.append(this.sourceTag);
+            if (sourcePackageName != null) {
+                sb.append('/');
+                sb.append(this.sourcePackageName);
+            }
+            this.batteryName = sb.toString();
+        } else {
+            this.batteryName = job.getService().flattenToShortString();
+        }
+        this.tag = "*job*/" + this.batteryName;
+
         this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
         this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
         this.numFailures = numFailures;
@@ -158,8 +186,8 @@
     public JobStatus(JobStatus jobStatus) {
         this(jobStatus.getJob(), jobStatus.getUid(),
                 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
-                jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(),
-                jobStatus.getLatestRunTimeElapsed());
+                jobStatus.getSourceTag(), jobStatus.getNumFailures(),
+                jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
     }
 
     /**
@@ -169,18 +197,18 @@
      * wallclock runtime rather than resetting it on every boot.
      * We consider a freshly loaded job to no longer be in back-off.
      */
-    public JobStatus(JobInfo job, int callingUid, String sourcePackageName,
-            int sourceUserId, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
-        this(job, callingUid, sourcePackageName, sourceUserId, 0, earliestRunTimeElapsedMillis,
-                latestRunTimeElapsedMillis);
+    public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
+            String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+        this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
+                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
     }
 
     /** Create a new job to be rescheduled with the provided parameters. */
     public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
                       long newLatestRuntimeElapsedMillis, int backoffAttempt) {
         this(rescheduling.job, rescheduling.getUid(),
-                rescheduling.getSourcePackageName(),
-                rescheduling.getSourceUserId(), backoffAttempt, newEarliestRuntimeElapsedMillis,
+                rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
+                rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
                 newLatestRuntimeElapsedMillis);
     }
 
@@ -192,7 +220,7 @@
      * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
      */
     public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
-            int sourceUserId) {
+            int sourceUserId, String tag) {
         final long elapsedNow = SystemClock.elapsedRealtime();
         final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
         if (job.isPeriodic()) {
@@ -204,7 +232,7 @@
             latestRunTimeElapsedMillis = job.hasLateConstraint() ?
                     elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
         }
-        return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, 0,
+        return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
     }
 
@@ -240,12 +268,16 @@
         return UserHandle.getUserId(callingUid);
     }
 
+    public String getSourceTag() {
+        return sourceTag;
+    }
+
     public int getUid() {
         return callingUid;
     }
 
-    public String getName() {
-        return name;
+    public String getBatteryName() {
+        return batteryName;
     }
 
     public String getTag() {
@@ -332,6 +364,10 @@
         return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
     }
 
+    boolean setDeviceNotDozingConstraintSatisfied(boolean state) {
+        return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
+    }
+
     boolean setConstraintSatisfied(int constraint, boolean state) {
         boolean old = (satisfiedConstraints&constraint) != 0;
         if (old == state) {
@@ -347,13 +383,16 @@
      */
     public boolean isReady() {
         // Deadline constraint trumps other constraints (except for periodic jobs where deadline
-        // (is an implementation detail. A periodic job should only run if it's constraints are
+        // is an implementation detail. A periodic job should only run if its constraints are
         // satisfied).
-        // AppNotIdle implicit constraint trumps all!
+        // AppNotIdle implicit constraint must be satisfied
+        // DeviceNotDozing implicit constraint must be satisfied
         return (isConstraintsSatisfied()
                 || (!job.isPeriodic()
-                && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0))
-                && (satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0;
+                && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0)
+                )
+                && (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0
+                && (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0;
     }
 
     static final int CONSTRAINTS_OF_INTEREST =
@@ -361,12 +400,27 @@
             CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
             CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
 
+    // Soft override covers all non-"functional" constraints
+    static final int SOFT_OVERRIDE_CONSTRAINTS =
+            CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
+
     /**
      * @return Whether the constraints set on this job are satisfied.
      */
     public boolean isConstraintsSatisfied() {
+        if (overrideState == OVERRIDE_FULL) {
+            // force override: the job is always runnable
+            return true;
+        }
+
         final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
-        final int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+
+        int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+        if (overrideState == OVERRIDE_SOFT) {
+            // override: pretend all 'soft' requirements are satisfied
+            sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
+        }
+
         return (sat & req) == req;
     }
 
@@ -387,6 +441,7 @@
                 + ",U=" + (job.getTriggerContentUris() != null)
                 + ",F=" + numFailures + ",P=" + job.isPersisted()
                 + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
+                + ",DND=" + ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0)
                 + (isReady() ? "(READY)" : "")
                 + "]";
     }
@@ -414,10 +469,10 @@
         sb.append(Integer.toHexString(System.identityHashCode(this)));
         sb.append(" jId=");
         sb.append(job.getId());
-        sb.append(" uid=");
+        sb.append(' ');
         UserHandle.formatUid(sb, callingUid);
         sb.append(' ');
-        sb.append(job.getService().flattenToShortString());
+        sb.append(batteryName);
         return sb.toString();
     }
 
@@ -446,78 +501,77 @@
         if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
             pw.print(" CONTENT_TRIGGER");
         }
+        if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
+            pw.print(" DEVICE_NOT_DOZING");
+        }
     }
 
     // Dumpsys infrastructure
-    public void dump(PrintWriter pw, String prefix) {
+    public void dump(PrintWriter pw, String prefix, boolean full) {
         pw.print(prefix); UserHandle.formatUid(pw, callingUid);
         pw.print(" tag="); pw.println(tag);
         pw.print(prefix);
         pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
         pw.print(" user="); pw.print(getSourceUserId());
         pw.print(" pkg="); pw.println(getSourcePackageName());
-        pw.print(prefix); pw.println("JobInfo:");
-        pw.print(prefix); pw.print("  Service: ");
-        pw.println(job.getService().flattenToShortString());
-        if (job.isPeriodic()) {
-            pw.print(prefix); pw.print("  PERIODIC: interval=");
-            TimeUtils.formatDuration(job.getIntervalMillis(), pw);
-            pw.print(" flex=");
-            TimeUtils.formatDuration(job.getFlexMillis(), pw);
-            pw.println();
-        }
-        if (job.isPersisted()) {
-            pw.print(prefix); pw.println("  PERSISTED");
-        }
-        if (job.getPriority() != 0) {
-            pw.print(prefix); pw.print("  Priority: ");
-            pw.println(job.getPriority());
-        }
-        pw.print(prefix); pw.print("  Requires: charging=");
-        pw.print(job.isRequireCharging());
-        pw.print(" deviceIdle=");
-        pw.println(job.isRequireDeviceIdle());
-        if (job.getTriggerContentUris() != null) {
-            pw.print(prefix); pw.println("  Trigger content URIs:");
-            for (int i=0; i<job.getTriggerContentUris().length; i++) {
-                JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
-                pw.print(prefix); pw.print("    ");
-                pw.print(Integer.toHexString(trig.getFlags()));
-                pw.print(' ' );
-                pw.println(trig.getUri());
+        if (full) {
+            pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix);
+            pw.print("  Service: "); pw.println(job.getService().flattenToShortString());
+            if (job.isPeriodic()) {
+                pw.print(prefix); pw.print("  PERIODIC: interval=");
+                TimeUtils.formatDuration(job.getIntervalMillis(), pw);
+                pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
+                pw.println();
             }
-        }
-        if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
-            pw.print(prefix); pw.print("  Network type: ");
-            pw.println(job.getNetworkType());
-        }
-        if (job.getMinLatencyMillis() != 0) {
-            pw.print(prefix); pw.print("  Minimum latency: ");
-            TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
+            if (job.isPersisted()) {
+                pw.print(prefix); pw.println("  PERSISTED");
+            }
+            if (job.getPriority() != 0) {
+                pw.print(prefix); pw.print("  Priority: "); pw.println(job.getPriority());
+            }
+            pw.print(prefix); pw.print("  Requires: charging=");
+            pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
+            pw.println(job.isRequireDeviceIdle());
+            if (job.getTriggerContentUris() != null) {
+                pw.print(prefix); pw.println("  Trigger content URIs:");
+                for (int i = 0; i < job.getTriggerContentUris().length; i++) {
+                    JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
+                    pw.print(prefix); pw.print("    ");
+                    pw.print(Integer.toHexString(trig.getFlags()));
+                    pw.print(' '); pw.println(trig.getUri());
+                }
+            }
+            if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
+                pw.print(prefix); pw.print("  Network type: "); pw.println(job.getNetworkType());
+            }
+            if (job.getMinLatencyMillis() != 0) {
+                pw.print(prefix); pw.print("  Minimum latency: ");
+                TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
+                pw.println();
+            }
+            if (job.getMaxExecutionDelayMillis() != 0) {
+                pw.print(prefix); pw.print("  Max execution delay: ");
+                TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
+                pw.println();
+            }
+            pw.print(prefix); pw.print("  Backoff: policy="); pw.print(job.getBackoffPolicy());
+            pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
             pw.println();
-        }
-        if (job.getMaxExecutionDelayMillis() != 0) {
-            pw.print(prefix); pw.print("  Max execution delay: ");
-            TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
-            pw.println();
-        }
-        pw.print(prefix); pw.print("  Backoff: policy=");
-        pw.print(job.getBackoffPolicy());
-        pw.print(" initial=");
-        TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
-        pw.println();
-        if (job.hasEarlyConstraint()) {
-            pw.print(prefix); pw.println("  Has early constraint");
-        }
-        if (job.hasLateConstraint()) {
-            pw.print(prefix); pw.println("  Has late constraint");
+            if (job.hasEarlyConstraint()) {
+                pw.print(prefix); pw.println("  Has early constraint");
+            }
+            if (job.hasLateConstraint()) {
+                pw.print(prefix); pw.println("  Has late constraint");
+            }
         }
         pw.print(prefix); pw.print("Required constraints:");
         dumpConstraints(pw, requiredConstraints);
         pw.println();
-        pw.print(prefix); pw.print("Satisfied constraints:");
-        dumpConstraints(pw, satisfiedConstraints);
-        pw.println();
+        if (full) {
+            pw.print(prefix); pw.print("Satisfied constraints:");
+            dumpConstraints(pw, satisfiedConstraints);
+            pw.println();
+        }
         if (changedAuthorities != null) {
             pw.print(prefix); pw.println("Changed authorities:");
             for (int i=0; i<changedAuthorities.size(); i++) {
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 7882bc4d..ac7f4c3 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -33,7 +33,6 @@
     protected final Context mContext;
     protected final Object mLock;
     protected final StateChangedListener mStateChangedListener;
-    protected boolean mDeviceIdleMode;
 
     public StateController(StateChangedListener stateChangedListener, Context context,
             Object lock) {
@@ -42,10 +41,6 @@
         mLock = lock;
     }
 
-    public void deviceIdleModeChanged(boolean enabled) {
-        mDeviceIdleMode = enabled;
-    }
-
     /**
      * Implement the logic here to decide whether a job should be tracked by this controller.
      * This logic is put here so the JobManager can be completely agnostic of Controller logic.
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 620800c..3543249 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -39,9 +39,9 @@
     private static final String TAG = "JobScheduler.Time";
 
     /** Deadline alarm tag for logging purposes */
-    private final String DEADLINE_TAG = "deadline";
+    private final String DEADLINE_TAG = "JobScheduler.deadline";
     /** Delay alarm tag for logging purposes */
-    private final String DELAY_TAG = "delay";
+    private final String DELAY_TAG = "JobScheduler.delay";
 
     private long mNextJobExpiredElapsedMillis;
     private long mNextDelayExpiredElapsedMillis;
@@ -145,6 +145,9 @@
                 final long jobDeadline = job.getLatestRunTimeElapsed();
 
                 if (jobDeadline <= nowElapsedMillis) {
+                    if (job.hasTimingDelayConstraint()) {
+                        job.setTimingDelayConstraintSatisfied(true);
+                    }
                     job.setDeadlineConstraintSatisfied(true);
                     mStateChangedListener.onRunJobNow(job);
                     it.remove();
@@ -281,7 +284,7 @@
                 + "s");
         pw.println("Tracking:");
         for (JobStatus ts : mTrackedJobs) {
-            pw.println(String.valueOf(ts.hashCode()).substring(0, 3) + ".."
+            pw.println(String.valueOf(ts.getJobId() + "," + ts.getUid())
                     + ": (" + (ts.hasTimingDelayConstraint() ? ts.getEarliestRunTime() : "N/A")
                     + ", " + (ts.hasDeadlineConstraint() ?ts.getLatestRunTimeElapsed() : "N/A")
                     + ")");
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 7fb1783..e08fad4 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -508,18 +508,18 @@
     };
 
     private void subscriptionOrSimChanged(Context context) {
-        Log.d(TAG, "received SIM related action: ");
+        if (DEBUG) Log.d(TAG, "received SIM related action: ");
         TelephonyManager phone = (TelephonyManager)
                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
         String mccMnc = phone.getSimOperator();
         if (!TextUtils.isEmpty(mccMnc)) {
-            Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
+            if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
             synchronized (mLock) {
                 reloadGpsProperties(context, mProperties);
                 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
             }
         } else {
-            Log.d(TAG, "SIM MCC/MNC is still not available");
+            if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
         }
     }
 
@@ -569,7 +569,7 @@
     }
 
     private void reloadGpsProperties(Context context, Properties properties) {
-        Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
+        if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
         loadPropertiesFromResource(context, properties);
         boolean isPropertiesLoadedFromFile = false;
         final String gpsHardware = SystemProperties.get("ro.hardware.gps");
@@ -582,7 +582,7 @@
         if (!isPropertiesLoadedFromFile) {
             loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
         }
-        Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
+        if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
 
         // TODO: we should get rid of C2K specific setting.
         setSuplHostPort(properties.getProperty("SUPL_HOST"),
@@ -603,7 +603,7 @@
                 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
                 properties.store(baos, null);
                 native_configuration_update(baos.toString());
-                Log.d(TAG, "final config = " + baos.toString());
+                if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
             } catch (IOException ex) {
                 Log.e(TAG, "failed to dump properties contents");
             }
@@ -628,7 +628,7 @@
         String[] configValues = context.getResources().getStringArray(
                 com.android.internal.R.array.config_gpsParameters);
         for (String item : configValues) {
-            Log.d(TAG, "GpsParamsResource: " + item);
+            if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
             // We need to support "KEY =", but not "=VALUE".
             String[] split = item.split("=");
             if (split.length == 2) {
@@ -917,11 +917,13 @@
                     long certainty = mNtpTime.getCacheCertainty();
                     long now = System.currentTimeMillis();
 
-                    Log.d(TAG, "NTP server returned: "
-                            + time + " (" + new Date(time)
-                            + ") reference: " + timeReference
-                            + " certainty: " + certainty
-                            + " system time offset: " + (time - now));
+                    if (DEBUG) {
+                        Log.d(TAG, "NTP server returned: "
+                                + time + " (" + new Date(time)
+                                + ") reference: " + timeReference
+                                + " certainty: " + certainty
+                                + " system time offset: " + (time - now));
+                    }
 
                     native_inject_time(time, timeReference, (int) certainty);
                     delay = NTP_INTERVAL;
@@ -1557,11 +1559,11 @@
      * called from native code to update SV info
      */
     private void reportSvStatus() {
-        int svCount = native_read_sv_status(mSvidWithFlags, mSnrs, mSvElevations, mSvAzimuths);
+        int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
         mListenerHelper.onSvStatusChanged(
                 svCount,
                 mSvidWithFlags,
-                mSnrs,
+                mCn0s,
                 mSvElevations,
                 mSvAzimuths);
 
@@ -1576,7 +1578,7 @@
             }
             if (VERBOSE) {
                 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
-                        " snr: " + mSnrs[i]/10 +
+                        " cn0: " + mCn0s[i]/10 +
                         " elev: " + mSvElevations[i] +
                         " azimuth: " + mSvAzimuths[i] +
                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
@@ -1633,7 +1635,7 @@
                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
                 break;
             default:
-                Log.d(TAG, "Received Unknown AGPS status: " + status);
+                if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
         }
     }
 
@@ -2400,7 +2402,7 @@
 
     // preallocated arrays, to avoid memory allocation in reportStatus()
     private int mSvidWithFlags[] = new int[MAX_SVS];
-    private float mSnrs[] = new float[MAX_SVS];
+    private float mCn0s[] = new float[MAX_SVS];
     private float mSvElevations[] = new float[MAX_SVS];
     private float mSvAzimuths[] = new float[MAX_SVS];
     private int mSvCount;
@@ -2422,7 +2424,7 @@
     private native void native_delete_aiding_data(int flags);
     // returns number of SVs
     // mask[0] is ephemeris mask and mask[1] is almanac mask
-    private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
+    private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
             float[] azimuths);
     private native int native_read_nmea(byte[] buffer, int bufferSize);
     private native void native_inject_location(double latitude, double longitude, float accuracy);
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index d9e8e91..734a8d4 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -72,7 +72,7 @@
                 status = GnssMeasurementsEvent.STATUS_NOT_SUPPORTED;
                 break;
             case RESULT_GPS_LOCATION_DISABLED:
-                status = GnssMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
+                status = GnssMeasurementsEvent.STATUS_GNSS_LOCATION_DISABLED;
                 break;
             case RESULT_UNKNOWN:
                 return null;
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 57bce4b..fdef31f 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -73,7 +73,8 @@
                 status = GnssNavigationMessageEvent.STATUS_NOT_SUPPORTED;
                 break;
             case RESULT_GPS_LOCATION_DISABLED:
-                status = GnssNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
+                status = GnssNavigationMessageEvent
+                        .STATUS_GNSS_LOCATION_DISABLED;
                 break;
             case RESULT_UNKNOWN:
                 return null;
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 0b3111c..d471e45 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -75,7 +75,7 @@
     public void onSvStatusChanged(
             final int svCount,
             final int[] prnWithFlags,
-            final float[] snrs,
+            final float[] cn0s,
             final float[] elevations,
             final float[] azimuths) {
         Operation operation = new Operation() {
@@ -84,7 +84,7 @@
                 listener.onSvStatusChanged(
                         svCount,
                         prnWithFlags,
-                        snrs,
+                        cn0s,
                         elevations,
                         azimuths);
             }
diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
index 50dd607..e169d63 100644
--- a/services/core/java/com/android/server/media/MediaResourceMonitorService.java
+++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
@@ -37,13 +37,6 @@
 
     private static final String SERVICE_NAME = "media_resource_monitor";
 
-    /*
-     *  Resource types. Should be in sync with:
-     *  frameworks/av/media/libmedia/MediaResource.cpp
-     */
-    private static final String RESOURCE_AUDIO_CODEC = "audio-codec";
-    private static final String RESOURCE_VIDEO_CODEC = "video-codec";
-
     private final MediaResourceMonitorImpl mMediaResourceMonitorImpl;
 
     public MediaResourceMonitorService(Context context) {
@@ -58,25 +51,18 @@
 
     class MediaResourceMonitorImpl extends IMediaResourceMonitor.Stub {
         @Override
-        public void notifyResourceGranted(int pid, String type, String subType, long value)
+        public void notifyResourceGranted(int pid, int type)
                 throws RemoteException {
             if (DEBUG) {
-                Slog.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ", subType="
-                        + subType + ", value=" + value + ")");
+                Slog.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ")");
             }
             final long identity = Binder.clearCallingIdentity();
             try {
                 String pkgNames[] = getPackageNamesFromPid(pid);
-                Integer resourceType = null;
-                if (RESOURCE_AUDIO_CODEC.equals(subType)) {
-                    resourceType = Intent.EXTRA_MEDIA_RESOURCE_TYPE_AUDIO_CODEC;
-                } else if (RESOURCE_VIDEO_CODEC.equals(subType)) {
-                    resourceType = Intent.EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC;
-                }
-                if (pkgNames != null && resourceType != null) {
+                if (pkgNames != null) {
                     Intent intent = new Intent(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
                     intent.putExtra(Intent.EXTRA_PACKAGES, pkgNames);
-                    intent.putExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE, resourceType);
+                    intent.putExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE, type);
                     getContext().sendBroadcastAsUser(intent,
                             new UserHandle(ActivityManager.getCurrentUser()),
                             android.Manifest.permission.RECEIVE_MEDIA_RESOURCE_USAGE);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 862c061..29c54e9 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -77,6 +77,8 @@
      */
     private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000;
 
+    private static final int UID_NOT_SET = -1;
+
     private final MessageHandler mHandler;
 
     private final int mOwnerPid;
@@ -122,6 +124,9 @@
     private boolean mIsActive = false;
     private boolean mDestroyed = false;
 
+    private int mCallingUid = UID_NOT_SET;
+    private String mCallingPackage;
+
     public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
             ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
         mOwnerPid = ownerPid;
@@ -419,7 +424,9 @@
         return mSessionCb.mCb;
     }
 
-    public void sendMediaButton(KeyEvent ke, int sequenceId, ResultReceiver cb) {
+    public void sendMediaButton(KeyEvent ke, int sequenceId,
+            ResultReceiver cb, int uid, String packageName) {
+        updateCallingPackage(uid, packageName);
         mSessionCb.sendMediaButton(ke, sequenceId, cb);
     }
 
@@ -680,6 +687,33 @@
         return -1;
     }
 
+    private void updateCallingPackage() {
+        updateCallingPackage(UID_NOT_SET, null);
+    }
+
+    private void updateCallingPackage(int uid, String packageName) {
+        if (uid == UID_NOT_SET) {
+            uid = Binder.getCallingUid();
+        }
+        synchronized (mLock) {
+            if (mCallingUid == UID_NOT_SET || mCallingUid != uid) {
+                mCallingUid = uid;
+                mCallingPackage = packageName;
+                if (mCallingPackage != null) {
+                    return;
+                }
+                Context context = mService.getContext();
+                if (context == null) {
+                    return;
+                }
+                String[] packages = context.getPackageManager().getPackagesForUid(uid);
+                if (packages != null && packages.length > 0) {
+                    mCallingPackage = packages[0];
+                }
+            }
+        }
+    }
+
     private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
         @Override
         public void run() {
@@ -831,6 +865,11 @@
                 mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
+
+        @Override
+        public String getCallingPackage() {
+            return mCallingPackage;
+        }
     }
 
     class SessionCb {
@@ -1025,11 +1064,13 @@
         @Override
         public void sendCommand(String command, Bundle args, ResultReceiver cb)
                 throws RemoteException {
+            updateCallingPackage();
             mSessionCb.sendCommand(command, args, cb);
         }
 
         @Override
         public boolean sendMediaButton(KeyEvent mediaButtonIntent) {
+            updateCallingPackage();
             return mSessionCb.sendMediaButton(mediaButtonIntent, 0, null);
         }
 
@@ -1111,6 +1152,7 @@
 
         @Override
         public void adjustVolume(int direction, int flags, String packageName) {
+            updateCallingPackage();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
@@ -1122,6 +1164,7 @@
 
         @Override
         public void setVolumeTo(int value, int flags, String packageName) {
+            updateCallingPackage();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
@@ -1133,94 +1176,111 @@
 
         @Override
         public void prepare() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.prepare();
         }
 
         @Override
         public void prepareFromMediaId(String mediaId, Bundle extras)
                 throws RemoteException {
+            updateCallingPackage();
             mSessionCb.prepareFromMediaId(mediaId, extras);
         }
 
         @Override
         public void prepareFromSearch(String query, Bundle extras) throws RemoteException {
+            updateCallingPackage();
             mSessionCb.prepareFromSearch(query, extras);
         }
 
         @Override
         public void prepareFromUri(Uri uri, Bundle extras) throws RemoteException {
+            updateCallingPackage();
             mSessionCb.prepareFromUri(uri, extras);
         }
 
         @Override
         public void play() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.play();
         }
 
         @Override
         public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
+            updateCallingPackage();
             mSessionCb.playFromMediaId(mediaId, extras);
         }
 
         @Override
         public void playFromSearch(String query, Bundle extras) throws RemoteException {
+            updateCallingPackage();
             mSessionCb.playFromSearch(query, extras);
         }
 
         @Override
         public void playFromUri(Uri uri, Bundle extras) throws RemoteException {
+            updateCallingPackage();
             mSessionCb.playFromUri(uri, extras);
         }
 
         @Override
         public void skipToQueueItem(long id) {
+            updateCallingPackage();
             mSessionCb.skipToTrack(id);
         }
 
-
         @Override
         public void pause() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.pause();
         }
 
         @Override
         public void stop() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.stop();
         }
 
         @Override
         public void next() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.next();
         }
 
         @Override
         public void previous() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.previous();
         }
 
         @Override
         public void fastForward() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.fastForward();
         }
 
         @Override
         public void rewind() throws RemoteException {
+            updateCallingPackage();
             mSessionCb.rewind();
         }
 
         @Override
         public void seekTo(long pos) throws RemoteException {
+            updateCallingPackage();
             mSessionCb.seekTo(pos);
         }
 
         @Override
         public void rate(Rating rating) throws RemoteException {
+            updateCallingPackage();
             mSessionCb.rate(rating);
         }
 
         @Override
         public void sendCustomAction(String action, Bundle args)
                 throws RemoteException {
+            updateCallingPackage();
             mSessionCb.sendCustomAction(action, args);
         }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 745f476..e3c540a 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -946,7 +946,8 @@
                 // won't release it later
                 session.sendMediaButton(keyEvent,
                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                        mKeyEventReceiver);
+                        mKeyEventReceiver, getContext().getApplicationInfo().uid,
+                        getContext().getPackageName());
             } else {
                 // Launch the last PendingIntent we had with priority
                 UserRecord user = mUserRecords.get(mCurrentUserId);
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index 90e26d8..2807ec8 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -40,7 +40,7 @@
 
 public class IpConfigStore {
     private static final String TAG = "IpConfigStore";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     protected final DelayedDiskWrite mWriter;
 
@@ -59,8 +59,12 @@
 
     protected static final int IPCONFIG_FILE_VERSION = 2;
 
+    public IpConfigStore(DelayedDiskWrite writer) {
+        mWriter = writer;
+    }
+
     public IpConfigStore() {
-        mWriter = new DelayedDiskWrite();
+        this(new DelayedDiskWrite());
     }
 
     private boolean writeConfig(DataOutputStream out, int configKey,
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 5b1cedc..fc412e3 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -20,6 +20,7 @@
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
+import static android.provider.Settings.ACTION_VPN_SETTINGS;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -66,9 +67,6 @@
 
     private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
 
-    private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
-    private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN";
-
     private static final int ROOT_UID = 0;
 
     private final Context mContext;
@@ -101,7 +99,6 @@
         mProfile = Preconditions.checkNotNull(profile);
 
         final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
-        configIntent.putExtra(EXTRA_PICK_LOCKDOWN, true);
         mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0);
 
         final Intent resetIntent = new Intent(ACTION_LOCKDOWN_RESET);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 3421433..612bae2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -29,11 +29,11 @@
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkPolicy.CYCLE_NONE;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
@@ -41,16 +41,17 @@
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
-import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
@@ -67,6 +68,7 @@
 import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
+
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -77,6 +79,7 @@
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
+
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -127,12 +130,12 @@
 import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.Message;
-import android.os.ResultReceiver;
 import android.os.MessageQueue.IdleHandler;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -154,8 +157,6 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
-import libcore.io.IoUtils;
-
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
@@ -165,6 +166,10 @@
 import com.android.server.DeviceIdleController;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
+
+import libcore.io.IoUtils;
+
 import com.google.android.collect.Lists;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -221,6 +226,7 @@
     private static final String TAG_APP_POLICY = "app-policy";
     private static final String TAG_WHITELIST = "whitelist";
     private static final String TAG_RESTRICT_BACKGROUND = "restrict-background";
+    private static final String TAG_REVOKED_RESTRICT_BACKGROUND = "revoked-restrict-background";
 
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
@@ -240,8 +246,6 @@
     private static final String ATTR_APP_ID = "appId";
     private static final String ATTR_POLICY = "policy";
 
-    private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground";
-
     private static final String ACTION_ALLOW_BACKGROUND =
             "com.android.server.net.action.ALLOW_BACKGROUND";
     private static final String ACTION_SNOOZE_WARNING =
@@ -293,6 +297,7 @@
 
     final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
     final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+    final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
 
     /** Set of states for the child firewall chains. True if the chain is active. */
     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -318,6 +323,19 @@
      */
     private final SparseBooleanArray mRestrictBackgroundWhitelistUids = new SparseBooleanArray();
 
+    /**
+     * UIDs that have been initially white-listed by system to avoid restricted background.
+     */
+    private final SparseBooleanArray mDefaultRestrictBackgroundWhitelistUids =
+            new SparseBooleanArray();
+
+    /**
+     * UIDs that have been initially white-listed by system to avoid restricted background,
+     * but later revoked by user.
+     */
+    private final SparseBooleanArray mRestrictBackgroundWhitelistRevokedUids =
+            new SparseBooleanArray();
+
     /** Set of ifaces that are metered. */
     private ArraySet<String> mMeteredIfaces = new ArraySet<>();
     /** Set of over-limit templates that have been notified. */
@@ -414,6 +432,53 @@
         }
     }
 
+    /**
+     * Whitelists pre-defined apps for restrict background, but only if the user didn't already
+     * revoke the whitelist.
+     *
+     * @return whether any uid has been added to {@link #mRestrictBackgroundWhitelistUids}.
+     */
+    boolean addDefaultRestrictBackgroundWhitelistUids() {
+        final SystemConfig sysConfig = SystemConfig.getInstance();
+        final PackageManager pm = mContext.getPackageManager();
+        final List<UserInfo> users = mUserManager.getUsers();
+        final int numberUsers = users.size();
+
+        final ArraySet<String> allowDataUsage = sysConfig.getAllowInDataUsageSave();
+        boolean changed = false;
+        for (int i = 0; i < allowDataUsage.size(); i++) {
+            final String pkg = allowDataUsage.valueAt(i);
+            if (LOGD)
+                Slog.d(TAG, "checking restricted background whitelisting for package " + pkg);
+            final ApplicationInfo app;
+            try {
+                app = pm.getApplicationInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY);
+            } catch (PackageManager.NameNotFoundException e) {
+                // Should not happen
+                Slog.wtf(TAG, "No ApplicationInfo for package " + pkg);
+                continue;
+            }
+            if (!app.isPrivilegedApp()) {
+                Slog.w(TAG, "getAllowInDataUsageSave() returned non-privileged app: " + pkg);
+                continue;
+            }
+            for (int j = 0; j < numberUsers; j++) {
+                final UserInfo user = users.get(i);
+                final int uid = UserHandle.getUid(user.id, app.uid);
+                mDefaultRestrictBackgroundWhitelistUids.append(uid, true);
+                if (LOGD) Slog.d(TAG, "revoked whistelist status for uid " + uid + ": "
+                        + mRestrictBackgroundWhitelistRevokedUids.get(uid));
+                if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
+                    Slog.i(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
+                            + user.id + ") to restrict background whitelist");
+                    mRestrictBackgroundWhitelistUids.append(uid, true);
+                    changed = true;
+                }
+            }
+        }
+        return changed;
+    }
+
     void updatePowerSaveTempWhitelistLocked() {
         try {
             // Clear the states of the current whitelist
@@ -461,9 +526,11 @@
                     new PowerManagerInternal.LowPowerModeListener() {
                 @Override
                 public void onLowPowerModeChanged(boolean enabled) {
+                    if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
                     synchronized (mRulesLock) {
                         if (mRestrictPower != enabled) {
                             mRestrictPower = enabled;
+                            updateRulesForRestrictPowerLocked();
                             updateRulesForGlobalChangeLocked(true);
                         }
                     }
@@ -475,6 +542,10 @@
             // read policy from disk
             readPolicyLocked();
 
+            if (addDefaultRestrictBackgroundWhitelistUids()) {
+                writePolicyLocked();
+            }
+
             updateRulesForGlobalChangeLocked(false);
             updateNotificationsLocked();
         }
@@ -618,7 +689,7 @@
                 // global background data policy
                 if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
                 synchronized (mRulesLock) {
-                    updateRulesForUidLocked(uid);
+                    updateRestrictionRulesForUidLocked(uid);
                 }
             }
         }
@@ -636,7 +707,7 @@
             if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
             synchronized (mRulesLock) {
                 mUidPolicy.delete(uid);
-                updateRulesForUidLocked(uid);
+                updateRuleForRestrictBackgroundLocked(uid);
                 writePolicyLocked();
             }
         }
@@ -844,11 +915,6 @@
             }
         }
 
-        // ongoing notification when restricting background data
-        if (mRestrictBackground) {
-            enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
-        }
-
         // cancel stale notifications that we didn't renew above
         for (int i = beforeNotifs.size()-1; i >= 0; i--) {
             final String tag = beforeNotifs.valueAt(i);
@@ -1026,42 +1092,6 @@
         }
     }
 
-    /**
-     * Show ongoing notification to reflect that {@link #mRestrictBackground}
-     * has been enabled.
-     */
-    private void enqueueRestrictedNotification(String tag) {
-        final Resources res = mContext.getResources();
-        final Notification.Builder builder = new Notification.Builder(mContext);
-
-        final CharSequence title = res.getText(R.string.data_usage_restricted_title);
-        final CharSequence body = res.getString(R.string.data_usage_restricted_body);
-
-        builder.setOnlyAlertOnce(true);
-        builder.setOngoing(true);
-        builder.setSmallIcon(R.drawable.stat_notify_error);
-        builder.setTicker(title);
-        builder.setContentTitle(title);
-        builder.setContentText(body);
-        builder.setColor(mContext.getColor(
-                com.android.internal.R.color.system_notification_accent_color));
-
-        final Intent intent = buildAllowBackgroundDataIntent();
-        builder.setContentIntent(
-                PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
-
-        // TODO: move to NotificationManager once we can mock it
-        try {
-            final String packageName = mContext.getPackageName();
-            final int[] idReceived = new int[1];
-            mNotifManager.enqueueNotificationWithTag(packageName, packageName, tag,
-                    0x0, builder.getNotification(), idReceived, UserHandle.USER_ALL);
-            mActiveNotifs.add(tag);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
-        }
-    }
-
     private void cancelNotification(String tag) {
         // TODO: move to NotificationManager once we can mock it
         try {
@@ -1151,13 +1181,6 @@
             return;
         }
 
-        // If we are in restrict power mode, we want to treat all interfaces
-        // as metered, to restrict access to the network by uid.  However, we
-        // will not have a bandwidth limit.  Also only do this if restrict
-        // background data use is *not* enabled, since that takes precedence
-        // use over those networks can have a cost associated with it).
-        final boolean powerSave = mRestrictPower && !mRestrictBackground;
-
         // First, generate identities of all connected networks so we can
         // quickly compare them against all defined policies below.
         final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
@@ -1169,9 +1192,6 @@
                 final String baseIface = state.linkProperties.getInterfaceName();
                 if (baseIface != null) {
                     connIdents.add(Pair.create(baseIface, ident));
-                    if (powerSave) {
-                        connIfaces.add(baseIface);
-                    }
                 }
 
                 // Stacked interfaces are considered to have same identity as
@@ -1181,9 +1201,6 @@
                     final String stackedIface = stackedLink.getInterfaceName();
                     if (stackedIface != null) {
                         connIdents.add(Pair.create(stackedIface, ident));
-                        if (powerSave) {
-                            connIfaces.add(stackedIface);
-                        }
                     }
                 }
             }
@@ -1230,8 +1247,7 @@
             }
 
             if (LOGD) {
-                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
-                        + Arrays.toString(ifaces));
+                Slog.d(TAG, "applying policy " + policy + " to ifaces " + Arrays.toString(ifaces));
             }
 
             final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
@@ -1262,9 +1278,6 @@
                     removeInterfaceQuota(iface);
                     setInterfaceQuota(iface, quotaBytes);
                     newMeteredIfaces.add(iface);
-                    if (powerSave) {
-                        connIfaces.remove(iface);
-                    }
                 }
             }
 
@@ -1434,9 +1447,11 @@
 
                         final NetworkTemplate template = new NetworkTemplate(networkTemplate,
                                 subscriberId, networkId);
-                        mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
-                                cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
-                                lastLimitSnooze, metered, inferred));
+                        if (template.isPersistable()) {
+                            mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
+                                    cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
+                                    lastLimitSnooze, metered, inferred));
+                        }
 
                     } else if (TAG_UID_POLICY.equals(tag)) {
                         final int uid = readIntAttribute(in, ATTR_UID);
@@ -1464,6 +1479,9 @@
                     } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
                         final int uid = readIntAttribute(in, ATTR_UID);
                         mRestrictBackgroundWhitelistUids.put(uid, true);
+                    } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
+                        final int uid = readIntAttribute(in, ATTR_UID);
+                        mRestrictBackgroundWhitelistRevokedUids.put(uid, true);
                     }
                 } else if (type == END_TAG) {
                     if (TAG_WHITELIST.equals(tag)) {
@@ -1520,6 +1538,7 @@
             for (int i = 0; i < mNetworkPolicy.size(); i++) {
                 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
                 final NetworkTemplate template = policy.template;
+                if (!template.isPersistable()) continue;
 
                 out.startTag(null, TAG_NETWORK_POLICY);
                 writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
@@ -1562,7 +1581,7 @@
             out.startTag(null, TAG_WHITELIST);
 
             // restrict background whitelist
-            final int size = mRestrictBackgroundWhitelistUids.size();
+            int size = mRestrictBackgroundWhitelistUids.size();
             for (int i = 0; i < size; i++) {
                 final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
                 out.startTag(null, TAG_RESTRICT_BACKGROUND);
@@ -1570,6 +1589,15 @@
                 out.endTag(null, TAG_RESTRICT_BACKGROUND);
             }
 
+            // revoked restrict background whitelist
+            size = mRestrictBackgroundWhitelistRevokedUids.size();
+            for (int i = 0; i < size; i++) {
+                final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i);
+                out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
+                writeIntAttribute(out, ATTR_UID, uid);
+                out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
+            }
+
             out.endTag(null, TAG_WHITELIST);
 
             out.endDocument();
@@ -1595,7 +1623,7 @@
             try {
                 final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
                 if (oldPolicy != policy) {
-                    setUidPolicyUncheckedLocked(uid, policy, true);
+                    setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -1615,7 +1643,7 @@
             final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
             policy |= oldPolicy;
             if (oldPolicy != policy) {
-                setUidPolicyUncheckedLocked(uid, policy, true);
+                setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
             }
         }
     }
@@ -1632,16 +1660,27 @@
             final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
             policy = oldPolicy & ~policy;
             if (oldPolicy != policy) {
-                setUidPolicyUncheckedLocked(uid, policy, true);
+                setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
             }
         }
     }
 
+    private void setUidPolicyUncheckedLocked(int uid, int oldPolicy, int policy, boolean persist) {
+        setUidPolicyUncheckedLocked(uid, policy, persist);
+
+        // Checks if app was added or removed to the blacklist.
+        if ((oldPolicy == POLICY_NONE && policy == POLICY_REJECT_METERED_BACKGROUND)
+                || (oldPolicy == POLICY_REJECT_METERED_BACKGROUND && policy == POLICY_NONE)) {
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+                    .sendToTarget();
+        }
+    }
+
     private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
         mUidPolicy.put(uid, policy);
 
         // uid policy changed, recompute rules and persist policy.
-        updateRulesForUidLocked(uid);
+        updateRuleForRestrictBackgroundLocked(uid);
         if (persist) {
             writePolicyLocked();
         }
@@ -1692,12 +1731,10 @@
 
         if (wlUids.length > 0) {
             for (int uid : wlUids) {
-                removeRestrictBackgroundWhitelistedUidLocked(uid, false);
+                removeRestrictBackgroundWhitelistedUidLocked(uid, false, false);
             }
             writePolicy = true;
         }
-        updateRulesForGlobalChangeLocked(true);
-
         // Remove associated UID policies
         int[] uids = new int[0];
         for (int i = 0; i < mUidPolicy.size(); i++) {
@@ -1710,11 +1747,12 @@
         if (uids.length > 0) {
             for (int uid : uids) {
                 mUidPolicy.delete(uid);
-                updateRulesForUidLocked(uid);
             }
             writePolicy = true;
         }
 
+        updateRulesForGlobalChangeLocked(true);
+
         if (writePolicy) {
             writePolicyLocked();
         }
@@ -1860,10 +1898,12 @@
         try {
             maybeRefreshTrustedTime();
             synchronized (mRulesLock) {
-                mRestrictBackground = restrictBackground;
-                updateRulesForGlobalChangeLocked(true);
-                updateNotificationsLocked();
-                writePolicyLocked();
+                if (restrictBackground == mRestrictBackground) {
+                    // Ideally, UI should never allow this scenario...
+                    Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
+                    return;
+                }
+                setRestrictBackgroundLocked(restrictBackground);
             }
 
         } finally {
@@ -1874,26 +1914,56 @@
                 .sendToTarget();
     }
 
+    private void setRestrictBackgroundLocked(boolean restrictBackground) {
+        final boolean oldRestrictBackground = mRestrictBackground;
+        mRestrictBackground = restrictBackground;
+        // Must whitelist foreground apps before turning data saver mode on.
+        // TODO: there is no need to iterate through all apps here, just those in the foreground,
+        // so it could call AM to get the UIDs of such apps, and iterate through them instead.
+        updateRulesForRestrictBackgroundLocked();
+        try {
+            if (!mNetworkManager.setDataSaverModeEnabled(mRestrictBackground)) {
+                Slog.e(TAG, "Could not change Data Saver Mode on NMS to " + mRestrictBackground);
+                mRestrictBackground = oldRestrictBackground;
+                // TODO: if it knew the foreground apps (see TODO above), it could call
+                // updateRulesForRestrictBackgroundLocked() again to restore state.
+                return;
+            }
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+        updateNotificationsLocked();
+        writePolicyLocked();
+    }
+
     @Override
     public void addRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        if (!isUidValidForRules(uid)) return;
-        final boolean changed;
+        final boolean oldStatus;
+        final boolean needFirewallRules;
         synchronized (mRulesLock) {
-            final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+            oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
             if (oldStatus) {
                 if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
                 return;
             }
+            needFirewallRules = isUidValidForWhitelistRules(uid);
             Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
             mRestrictBackgroundWhitelistUids.append(uid, true);
-            changed = mRestrictBackground && !oldStatus;
-            if (changed && hasInternetPermissions(uid)) {
-                setUidNetworkRules(uid, false);
+            if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
+                    && mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
+                if (LOGD) Slog.d(TAG, "Removing uid " + uid
+                        + " from revoked restrict background whitelist");
+                mRestrictBackgroundWhitelistRevokedUids.delete(uid);
             }
+            if (needFirewallRules) {
+                // Only update firewall rules if necessary...
+                updateRuleForRestrictBackgroundLocked(uid);
+            }
+            // ...but always persists the whitelist request.
             writePolicyLocked();
         }
-        if (changed) {
+        if (mRestrictBackground && !oldStatus && needFirewallRules) {
             mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
                     .sendToTarget();
         }
@@ -1902,10 +1972,9 @@
     @Override
     public void removeRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        if (!isUidValidForRules(uid)) return;
         final boolean changed;
         synchronized (mRulesLock) {
-            changed = removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+            changed = removeRestrictBackgroundWhitelistedUidLocked(uid, false, true);
         }
         if (changed) {
             mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
@@ -1913,22 +1982,37 @@
         }
     }
 
-    private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+    /**
+     * Removes a uid from the restricted background whitelist, returning whether its current
+     * {@link ConnectivityManager.RestrictBackgroundStatus} changed.
+     */
+    private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean uidDeleted,
+            boolean updateNow) {
         final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
         if (!oldStatus) {
             if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
             return false;
         }
+        final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid);
         Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
-        final boolean changed = mRestrictBackground && oldStatus;
         mRestrictBackgroundWhitelistUids.delete(uid);
+        if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
+                && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
+            if (LOGD) Slog.d(TAG, "Adding uid " + uid
+                    + " to revoked restrict background whitelist");
+            mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
+        }
+        if (needFirewallRules) {
+            // Only update firewall rules if necessary...
+            updateRuleForRestrictBackgroundLocked(uid, uidDeleted);
+        }
         if (updateNow) {
-            if (changed && hasInternetPermissions(uid)) {
-                setUidNetworkRules(uid, true);
-            }
+            // ...but always persists the whitelist request.
             writePolicyLocked();
         }
-        return changed;
+        // Status only changes if Data Saver is turned on (otherwise it is DISABLED, even if the
+        // app was whitelisted before).
+        return mRestrictBackground && needFirewallRules;
     }
 
     @Override
@@ -1952,7 +2036,20 @@
     public int getRestrictBackgroundByCaller() {
         mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
         final int uid = Binder.getCallingUid();
+
         synchronized (mRulesLock) {
+            // Must clear identity because getUidPolicy() is restricted to system.
+            final long token = Binder.clearCallingIdentity();
+            final int policy;
+            try {
+                policy = getUidPolicy(uid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            if (policy == POLICY_REJECT_METERED_BACKGROUND) {
+                // App is blacklisted.
+                return RESTRICT_BACKGROUND_STATUS_ENABLED;
+            }
             if (!mRestrictBackground) {
                 return RESTRICT_BACKGROUND_STATUS_DISABLED;
             }
@@ -2168,6 +2265,30 @@
                 fout.decreaseIndent();
             }
 
+            size = mDefaultRestrictBackgroundWhitelistUids.size();
+            if (size > 0) {
+                fout.println("Default restrict background whitelist uids:");
+                fout.increaseIndent();
+                for (int i = 0; i < size; i++) {
+                    fout.print("UID=");
+                    fout.print(mDefaultRestrictBackgroundWhitelistUids.keyAt(i));
+                    fout.println();
+                }
+                fout.decreaseIndent();
+            }
+
+            size = mRestrictBackgroundWhitelistRevokedUids.size();
+            if (size > 0) {
+                fout.println("Default restrict background whitelist uids revoked by users:");
+                fout.increaseIndent();
+                for (int i = 0; i < size; i++) {
+                    fout.print("UID=");
+                    fout.print(mRestrictBackgroundWhitelistRevokedUids.keyAt(i));
+                    fout.println();
+                }
+                fout.decreaseIndent();
+            }
+
             final SparseBooleanArray knownUids = new SparseBooleanArray();
             collectKeys(mUidState, knownUids);
             collectKeys(mUidRules, knownUids);
@@ -2183,11 +2304,16 @@
                 final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 fout.print(" state=");
                 fout.print(state);
-                fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)");
+                if (state <= ActivityManager.PROCESS_STATE_TOP) {
+                    fout.print(" (fg)");
+                } else {
+                    fout.print(state <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+                            ? " (fg svc)" : " (bg)");
+                }
 
                 final int rule = mUidRules.get(uid, RULE_UNKNOWN);
                 fout.print(" rule=");
-                fout.print(DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule));
+                fout.print(ruleToString(rule));
 
                 fout.println();
             }
@@ -2195,6 +2321,10 @@
         }
     }
 
+    private String ruleToString(int rule) {
+        return DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule);
+    }
+
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ResultReceiver resultReceiver) throws RemoteException {
@@ -2211,49 +2341,80 @@
         }
     }
 
-    boolean isUidForegroundLocked(int uid) {
+    private boolean isUidForegroundLocked(int uid) {
+        return isUidStateForegroundLocked(
+                mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY));
+    }
+
+    private boolean isUidForegroundOnRestrictBackgroundLocked(int uid) {
+        final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        return isProcStateAllowedWhileOnRestrictBackgroundLocked(procState);
+    }
+
+    private boolean isUidStateForegroundLocked(int state) {
         // only really in foreground when screen is also on
-        return mScreenOn && mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY)
-                <= ActivityManager.PROCESS_STATE_TOP;
+        return mScreenOn && state <= ActivityManager.PROCESS_STATE_TOP;
     }
 
     /**
      * Process state of UID changed; if needed, will trigger
-     * {@link #updateRulesForUidLocked(int)}.
+     * {@link #updateRuleForRestrictBackgroundLocked(int)}.
      */
-    void updateUidStateLocked(int uid, int uidState) {
+    private void updateUidStateLocked(int uid, int uidState) {
         final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         if (oldUidState != uidState) {
             // state changed, push updated rules
             mUidState.put(uid, uidState);
-            updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
-            if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
-                    != isProcStateAllowedWhileIdle(uidState)) {
-                updateRuleForDeviceIdleLocked(uid);
+            updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState, uidState);
+            if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
+                    != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
+                if (mDeviceIdleMode) {
+                    updateRuleForDeviceIdleLocked(uid);
+                }
+                if (mRestrictPower) {
+                    updateRuleForRestrictPowerLocked(uid);
+                }
             }
+            updateNetworkStats(uid, isUidStateForegroundLocked(uidState));
         }
     }
 
-    void removeUidStateLocked(int uid) {
+    private void removeUidStateLocked(int uid) {
         final int index = mUidState.indexOfKey(uid);
         if (index >= 0) {
             final int oldUidState = mUidState.valueAt(index);
             mUidState.removeAt(index);
             if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
-                updateRulesForUidStateChangeLocked(uid, oldUidState,
+                updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState,
                         ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 if (mDeviceIdleMode) {
                     updateRuleForDeviceIdleLocked(uid);
                 }
+                if (mRestrictPower) {
+                    updateRuleForRestrictPowerLocked(uid);
+                }
+                updateNetworkStats(uid, false);
             }
         }
     }
 
-    void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) {
-        final boolean oldForeground = oldUidState <= ActivityManager.PROCESS_STATE_TOP;
-        final boolean newForeground = newUidState <= ActivityManager.PROCESS_STATE_TOP;
+    // adjust stats accounting based on foreground status
+    private void updateNetworkStats(int uid, boolean uidForeground) {
+        try {
+            mNetworkStats.setUidForeground(uid, uidForeground);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+    }
+
+    private void updateRestrictBackgroundRulesOnUidStatusChangedLocked(int uid, int oldUidState,
+            int newUidState) {
+        final boolean oldForeground =
+                isProcStateAllowedWhileOnRestrictBackgroundLocked(oldUidState);
+        final boolean newForeground =
+                isProcStateAllowedWhileOnRestrictBackgroundLocked(newUidState);
         if (oldForeground != newForeground) {
-            updateRulesForUidLocked(uid);
+            updateRuleForRestrictBackgroundLocked(uid);
         }
     }
 
@@ -2275,22 +2436,47 @@
         // only update rules for anyone with foreground activities
         final int size = mUidState.size();
         for (int i = 0; i < size; i++) {
-            if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_TOP) {
+            if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
                 final int uid = mUidState.keyAt(i);
-                updateRulesForUidLocked(uid);
+                updateRestrictionRulesForUidLocked(uid);
             }
         }
     }
 
-    static boolean isProcStateAllowedWhileIdle(int procState) {
+    static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
         return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
     }
 
+    static boolean isProcStateAllowedWhileOnRestrictBackgroundLocked(int procState) {
+        return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+    }
+
+    void updateRulesForRestrictPowerLocked() {
+        updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
+                mUidFirewallPowerSaveRules);
+    }
+
+    void updateRuleForRestrictPowerLocked(int uid) {
+        updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
+    }
+
     void updateRulesForDeviceIdleLocked() {
-        if (mDeviceIdleMode) {
-            // sync the whitelists before enable dozable chain.  We don't care about the rules if
+        updateRulesForWhitelistedPowerSaveLocked(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
+                mUidFirewallDozableRules);
+    }
+
+    void updateRuleForDeviceIdleLocked(int uid) {
+        updateRulesForWhitelistedPowerSaveLocked(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
+    }
+
+    // NOTE: since both fw_dozable and fw_powersave uses the same map
+    // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
+    private void updateRulesForWhitelistedPowerSaveLocked(boolean enabled, int chain,
+            SparseIntArray rules) {
+        if (enabled) {
+            // Sync the whitelists before enabling the chain.  We don't care about the rules if
             // we are disabling the chain.
-            final SparseIntArray uidRules = mUidFirewallDozableRules;
+            final SparseIntArray uidRules = rules;
             uidRules.clear();
             final List<UserInfo> users = mUserManager.getUsers();
             for (int ui = users.size() - 1; ui >= 0; ui--) {
@@ -2309,28 +2495,28 @@
                 }
             }
             for (int i = mUidState.size() - 1; i >= 0; i--) {
-                if (isProcStateAllowedWhileIdle(mUidState.valueAt(i))) {
+                if (isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.valueAt(i))) {
                     uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
                 }
             }
-            setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
+            setUidFirewallRules(chain, uidRules);
         }
 
-        enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
+        enableFirewallChainLocked(chain, enabled);
     }
 
-    void updateRuleForDeviceIdleLocked(int uid) {
-        if (mDeviceIdleMode) {
+    // NOTE: since both fw_dozable and fw_powersave uses the same map
+    // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
+    private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) {
+        if (enabled) {
             int appId = UserHandle.getAppId(uid);
             if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId)
-                    || isProcStateAllowedWhileIdle(mUidState.get(uid))) {
-                setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_ALLOW);
+                    || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
+                setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
             } else {
-                setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
+                setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
             }
         }
-
-        updateRulesForUidLocked(uid);
     }
 
     void updateRulesForAppIdleLocked() {
@@ -2338,7 +2524,6 @@
         uidRules.clear();
 
         // Fully update the app idle firewall chain.
-        final IPackageManager ipm = AppGlobals.getPackageManager();
         final List<UserInfo> users = mUserManager.getUsers();
         for (int ui = users.size() - 1; ui >= 0; ui--) {
             UserInfo user = users.get(ui);
@@ -2359,7 +2544,7 @@
     }
 
     void updateRuleForAppIdleLocked(int uid) {
-        if (!isUidValidForRules(uid)) return;
+        if (!isUidValidForBlacklistRules(uid)) return;
 
         int appId = UserHandle.getAppId(uid);
         if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)) {
@@ -2367,72 +2552,91 @@
         } else {
             setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
         }
-
-        updateRulesForUidLocked(uid);
     }
 
     void updateRulesForAppIdleParoleLocked() {
         boolean enableChain = !mUsageStats.isAppIdleParoleOn();
         enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
-        updateRulesForUidsLocked(mUidFirewallStandbyRules);
     }
 
     /**
      * Update rules that might be changed by {@link #mRestrictBackground},
      * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
      */
-    void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
-        final PackageManager pm = mContext.getPackageManager();
+    private void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
+        long start;
+        if (LOGD) start = System.currentTimeMillis();
 
         updateRulesForDeviceIdleLocked();
         updateRulesForAppIdleLocked();
-
-        // update rules for all installed applications
-        final List<UserInfo> users = mUserManager.getUsers();
-        final List<ApplicationInfo> apps = pm.getInstalledApplications(
-                PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS
-                        | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
-
-        for (UserInfo user : users) {
-            for (ApplicationInfo app : apps) {
-                final int uid = UserHandle.getUid(user.id, app.uid);
-                updateRulesForUidLocked(uid);
-            }
-        }
-
-        // limit data usage for some internal system services
-        updateRulesForUidLocked(android.os.Process.MEDIA_UID);
-        updateRulesForUidLocked(android.os.Process.DRM_UID);
+        updateRulesForRestrictPowerLocked();
+        updateRulesForRestrictBackgroundLocked();
+        setRestrictBackgroundLocked(mRestrictBackground);
 
         // If the set of restricted networks may have changed, re-evaluate those.
         if (restrictedNetworksChanged) {
             normalizePoliciesLocked();
             updateNetworkRulesLocked();
         }
+        if (LOGD) {
+            final long delta = System.currentTimeMillis() - start;
+            Slog.d(TAG, "updateRulesForGlobalChangeLocked(" + restrictedNetworksChanged + ") took "
+                    + delta + "ms");
+        }
     }
 
-    void updateRulesForTempWhitelistChangeLocked() {
+    private void updateRulesForRestrictBackgroundLocked() {
+        final PackageManager pm = mContext.getPackageManager();
+
+        // update rules for all installed applications
         final List<UserInfo> users = mUserManager.getUsers();
-        for (UserInfo user : users) {
-            for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
-                int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
-                int uid = UserHandle.getUid(user.id, appId);
-                updateRuleForAppIdleLocked(uid);
-                updateRuleForDeviceIdleLocked(uid);
+        final List<ApplicationInfo> apps = pm.getInstalledApplications(
+                PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
+                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+
+        final int usersSize = users.size();
+        final int appsSize = apps.size();
+        for (int i = 0; i < usersSize; i++) {
+            final UserInfo user = users.get(i);
+            for (int j = 0; j < appsSize; j++) {
+                final ApplicationInfo app = apps.get(j);
+                final int uid = UserHandle.getUid(user.id, app.uid);
+                updateRuleForRestrictBackgroundLocked(uid);
             }
         }
     }
 
-    private static boolean isUidValidForRules(int uid) {
+    private void updateRulesForTempWhitelistChangeLocked() {
+        final List<UserInfo> users = mUserManager.getUsers();
+        for (int i = 0; i < users.size(); i++) {
+            final UserInfo user = users.get(i);
+            for (int j = mPowerSaveTempWhitelistAppIds.size() - 1; j >= 0; j--) {
+                int appId = mPowerSaveTempWhitelistAppIds.keyAt(j);
+                int uid = UserHandle.getUid(user.id, appId);
+                updateRuleForAppIdleLocked(uid);
+                updateRuleForDeviceIdleLocked(uid);
+                updateRuleForRestrictPowerLocked(uid);
+            }
+        }
+    }
+
+    // TODO: the MEDIA / DRM restriction might not be needed anymore, in which case both
+    // methods below could be merged into a isUidValidForRules() method.
+    private boolean isUidValidForBlacklistRules(int uid) {
         // allow rules on specific system services, and any apps
         if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
-                || UserHandle.isApp(uid)) {
+            || (UserHandle.isApp(uid) && hasInternetPermissions(uid))) {
             return true;
         }
 
         return false;
     }
 
+    private boolean isUidValidForWhitelistRules(int uid) {
+        return UserHandle.isApp(uid) && hasInternetPermissions(uid);
+    }
+
     private boolean isUidIdle(int uid) {
         final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
         final int userId = UserHandle.getUserId(uid);
@@ -2447,12 +2651,6 @@
         return true;
     }
 
-    void updateRulesForUidsLocked(SparseIntArray uids) {
-        for (int i = 0; i < uids.size(); i++) {
-            updateRulesForUidLocked(uids.keyAt(i));
-        }
-    }
-
     /**
      * Checks if an uid has INTERNET permissions.
      * <p>
@@ -2471,72 +2669,153 @@
 
     /**
      * Applies network rules to bandwidth and firewall controllers based on uid policy.
-     * @param uid The uid for which to apply the latest policy
+     *
+     * <p>There are currently 2 types of restriction rules:
+     * <ul>
+     * <li>Battery Saver Mode (also referred as power save).
+     * <li>Data Saver Mode (formerly known as restrict background data).
+     * </ul>
      */
-    void updateRulesForUidLocked(int uid) {
-        if (!isUidValidForRules(uid) || !hasInternetPermissions(uid)) return;
+    private void updateRestrictionRulesForUidLocked(int uid) {
+        updateRuleForRestrictPowerLocked(uid);
+        updateRuleForRestrictBackgroundLocked(uid);
+    }
+
+    /**
+     * Applies network rules to bandwidth controllers based on process state and user-defined
+     * restrictions (blacklist / whitelist).
+     *
+     * <p>
+     * {@code netd} defines 3 firewall chains that govern whether an app has access to metered
+     * networks:
+     * <ul>
+     * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (blacklist).
+     * <li>@{code bw_happy_box}: UIDs added to this chain have access (whitelist), unless they're
+     *     also blacklisted.
+     * <li>@{code bw_data_saver}: when enabled (through {@link #setRestrictBackground(boolean)}),
+     *     no UIDs other those whitelisted will have access.
+     * <ul>
+     *
+     * <p>The @{code bw_penalty_box} and @{code bw_happy_box} are primarily managed through the
+     * {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundWhitelistedUid(int)} /
+     * {@link #removeRestrictBackgroundWhitelistedUid(int)} methods (for blacklist and whitelist
+     * respectively): these methods set the proper internal state (blacklist / whitelist), then call
+     * this ({@link #updateRuleForRestrictBackgroundLocked(int)}) to propagate the rules to
+     * {@link INetworkManagementService}, but this method should also be called in events (like
+     * Data Saver Mode flips or UID state changes) that might affect the foreground app, since the
+     * following rules should also be applied:
+     *
+     * <ul>
+     * <li>When Data Saver mode is on, the foreground app should be temporarily added to
+     *     {@code bw_happy_box} before the @{code bw_data_saver} chain is enabled.
+     * <li>If the foreground app is blacklisted by the user, it should be temporarily removed from
+     *     {@code bw_penalty_box}.
+     * <li>When the app leaves foreground state, the temporary changes above should be reverted.
+     * </ul>
+     *
+     * <p>For optimization, the rules are only applied on user apps that have internet access
+     * permission, since there is no need to change the {@code iptables} rule if the app does not
+     * have permission to use the internet.
+     *
+     * <p>The {@link #mUidRules} map is used to define the transtion of states of an UID.
+     */
+    private void updateRuleForRestrictBackgroundLocked(int uid) {
+        updateRuleForRestrictBackgroundLocked(uid, false);
+    }
+
+    /**
+     * Overloaded version of {@link #updateRuleForRestrictBackgroundLocked(int)} called when an
+     * app is removed - it ignores the UID validity check.
+     */
+    private void updateRuleForRestrictBackgroundLocked(int uid, boolean uidDeleted) {
+        if (!uidDeleted && !isUidValidForWhitelistRules(uid)) {
+            if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
+            return;
+        }
 
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
-        final boolean uidForeground = isUidForegroundLocked(uid);
+        final boolean isForeground = isUidForegroundOnRestrictBackgroundLocked(uid);
+        final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
+        final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);
 
-        // Derive active rules based on policy and active state
-        int appId = UserHandle.getAppId(uid);
-        int uidRules = RULE_ALLOW_ALL;
-        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
-            // uid in background, and policy says to block metered data
-            uidRules = RULE_REJECT_METERED;
-        } else if (mRestrictBackground) {
-            if (!uidForeground) {
-                // uid in background, global background disabled, and this uid is not on the white
-                // list of those allowed background access while global background is disabled
-                if (!mRestrictBackgroundWhitelistUids.get(uid)) {
-                    uidRules = RULE_REJECT_METERED;
-                }
+        int newRule = RULE_ALLOW_ALL;
+        final int oldRule = mUidRules.get(uid);
+
+        // First step: define the new rule based on user restrictions and foreground state.
+        if (isForeground) {
+            if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) {
+                newRule = RULE_TEMPORARY_ALLOW_METERED;
             }
-        } else if (mRestrictPower) {
-            final boolean whitelisted = mPowerSaveWhitelistExceptIdleAppIds.get(appId)
-                    || mPowerSaveTempWhitelistAppIds.get(appId);
-            if (!whitelisted && !uidForeground
-                    && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
-                // uid is in background, restrict power use mode is on (so we want to
-                // restrict all background network access), and this uid is not on the
-                // white list of those allowed background access.
-                uidRules = RULE_REJECT_METERED;
+        } else {
+            if (isBlacklisted) {
+                newRule = RULE_REJECT_METERED;
+            } else if (isWhitelisted) {
+                newRule = RULE_ALLOW_METERED;
             }
         }
 
-        // Check dozable state, which is whitelist
-        if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)
-                && mUidFirewallDozableRules.get(uid, FIREWALL_RULE_DEFAULT) != FIREWALL_RULE_ALLOW) {
-            uidRules = RULE_REJECT_ALL;
+        if (LOGV) {
+            Log.v(TAG, "updateRuleForRestrictBackgroundLocked(" + uid + "):"
+                    + " isForeground=" +isForeground + ", isBlacklisted: " + isBlacklisted
+                    + ", isWhitelisted: " + isWhitelisted + ", newRule: " + ruleToString(newRule)
+                    + ", oldRule: " + ruleToString(oldRule));
         }
 
-        // Check standby state, which is blacklist
-        if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)
-                && mUidFirewallStandbyRules.get(uid, FIREWALL_RULE_DEFAULT) == FIREWALL_RULE_DENY) {
-            uidRules = RULE_REJECT_ALL;
-        }
 
-        final int oldRules = mUidRules.get(uid);
-        if (uidRules == RULE_ALLOW_ALL) {
+        if (newRule == RULE_ALLOW_ALL) {
             mUidRules.delete(uid);
         } else {
-            mUidRules.put(uid, uidRules);
+            mUidRules.put(uid, newRule);
         }
 
-        final boolean rejectMetered = (uidRules == RULE_REJECT_METERED);
-        setUidNetworkRules(uid, rejectMetered);
+        // Second step: apply bw changes based on change of state.
+        if (newRule != oldRule) {
+            if (newRule == RULE_TEMPORARY_ALLOW_METERED) {
+                // Temporarily whitelist foreground app, removing from blacklist if necessary
+                // (since bw_penalty_box prevails over bw_happy_box).
 
-        // dispatch changed rule to existing listeners
-        if (oldRules != uidRules) {
-            mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
-        }
+                setMeteredNetworkWhitelist(uid, true);
+                // TODO: if statement below is used to avoid an unnecessary call to netd / iptables,
+                // but ideally it should be just:
+                //    setMeteredNetworkBlacklist(uid, isBlacklisted);
+                if (isBlacklisted) {
+                    setMeteredNetworkBlacklist(uid, false);
+                }
+            } else if (oldRule == RULE_TEMPORARY_ALLOW_METERED) {
+                // Remove temporary whitelist from app that is not on foreground anymore.
 
-        try {
-            // adjust stats accounting based on foreground status
-            mNetworkStats.setUidForeground(uid, uidForeground);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
+                // TODO: if statements below are used to avoid unnecessary calls to netd / iptables,
+                // but ideally they should be just:
+                //    setMeteredNetworkWhitelist(uid, isWhitelisted);
+                //    setMeteredNetworkBlacklist(uid, isBlacklisted);
+                if (!isWhitelisted) {
+                    setMeteredNetworkWhitelist(uid, false);
+                }
+                if (isBlacklisted) {
+                    setMeteredNetworkBlacklist(uid, true);
+                }
+            } else if (newRule == RULE_REJECT_METERED || oldRule == RULE_REJECT_METERED) {
+                // Flip state because app was explicitly added or removed to blacklist.
+                setMeteredNetworkBlacklist(uid, isBlacklisted);
+                if (oldRule == RULE_REJECT_METERED && isWhitelisted) {
+                    // Since blacklist prevails over whitelist, we need to handle the special case
+                    // where app is whitelisted and blacklisted at the same time (although such
+                    // scenario should be blocked by the UI), then blacklist is removed.
+                    setMeteredNetworkWhitelist(uid, isWhitelisted);
+                }
+            } else if (newRule == RULE_ALLOW_METERED || oldRule == RULE_ALLOW_METERED) {
+                // Flip state because app was explicitly added or removed to whitelist.
+                setMeteredNetworkWhitelist(uid, isWhitelisted);
+            } else {
+                // All scenarios should have been covered above
+                Log.wtf(TAG, "Unexpected change of state for " + uid
+                        + ": foreground=" + isForeground + ", whitelisted=" + isWhitelisted
+                        + ", blacklisted=" + isBlacklisted + ", newRule="
+                        + ruleToString(newRule) + ", oldRule=" + ruleToString(oldRule));
+            }
+
+            // dispatch changed rule to existing listeners
+            mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newRule).sendToTarget();
         }
     }
 
@@ -2698,11 +2977,23 @@
         }
     }
 
-    private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+    private void setMeteredNetworkBlacklist(int uid, boolean enable) {
+        if (LOGV) Slog.v(TAG, "setMeteredNetworkBlacklist " + uid + ": " + enable);
         try {
-            mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+            mNetworkManager.setUidMeteredNetworkBlacklist(uid, enable);
         } catch (IllegalStateException e) {
-            Log.wtf(TAG, "problem setting uid rules", e);
+            Log.wtf(TAG, "problem setting blacklist (" + enable + ") rules for " + uid, e);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+    }
+
+    private void setMeteredNetworkWhitelist(int uid, boolean enable) {
+        if (LOGV) Slog.v(TAG, "setMeteredNetworkWhitelist " + uid + ": " + enable);
+        try {
+            mNetworkManager.setUidMeteredNetworkWhitelist(uid, enable);
+        } catch (IllegalStateException e) {
+            Log.wtf(TAG, "problem setting whitelist (" + enable + ") rules for " + uid, e);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
         }
@@ -2738,6 +3029,8 @@
             mUidFirewallDozableRules.put(uid, rule);
         } else if (chain == FIREWALL_CHAIN_STANDBY) {
             mUidFirewallStandbyRules.put(uid, rule);
+        } else if (chain == FIREWALL_CHAIN_POWERSAVE) {
+            mUidFirewallPowerSaveRules.put(uid, rule);
         }
 
         try {
@@ -2882,7 +3175,7 @@
         public void onPackageRemoved(String packageName, int uid) {
             if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
             synchronized (mRulesLock) {
-                removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+                removeRestrictBackgroundWhitelistedUidLocked(uid, true, true);
             }
         }
     }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index a5dc008..d339f69 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -16,6 +16,8 @@
 
 package com.android.server.net;
 
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
 import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy;
 import static com.android.server.net.NetworkPolicyManagerService.TAG;
@@ -32,7 +34,6 @@
 import android.net.NetworkTemplate;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
-import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.util.Log;
@@ -83,20 +84,24 @@
         pw.println("");
         pw.println("  add restrict-background-whitelist UID");
         pw.println("    Adds a UID to the whitelist for restrict background usage.");
-        pw.println("  get metered-network ID");
-        pw.println("    Checks whether the given non-mobile network is metered or not.");
+        pw.println("  add restrict-background-blacklist UID");
+        pw.println("    Adds a UID to the blacklist for restrict background usage.");
         pw.println("  get restrict-background");
         pw.println("    Gets the global restrict background usage status.");
-        pw.println("  list metered-networks [BOOLEAN]");
-        pw.println("    Lists all non-mobile networks and whether they are metered or not.");
+        pw.println("  list wifi-networks [BOOLEAN]");
+        pw.println("    Lists all saved wifi networks and whether they are metered or not.");
         pw.println("    If a boolean argument is passed, filters just the metered (or unmetered)");
         pw.println("    networks.");
         pw.println("  list restrict-background-whitelist");
         pw.println("    Lists UIDs that are whitelisted for restrict background usage.");
+        pw.println("  list restrict-background-blacklist");
+        pw.println("    Lists UIDs that are blacklisted for restrict background usage.");
         pw.println("  remove restrict-background-whitelist UID");
         pw.println("    Removes a UID from the whitelist for restrict background usage.");
+        pw.println("  remove restrict-background-blacklist UID");
+        pw.println("    Removes a UID from the blacklist for restrict background usage.");
         pw.println("  set metered-network ID BOOLEAN");
-        pw.println("    Toggles whether the given non-mobile network is metered.");
+        pw.println("    Toggles whether the given wi-fi network is metered.");
         pw.println("  set restrict-background BOOLEAN");
         pw.println("    Sets the global restrict background usage status.");
     }
@@ -109,8 +114,6 @@
             return -1;
         }
         switch(type) {
-            case "metered-network":
-                return getMeteredWifiNetwork();
             case "restrict-background":
                 return getRestrictBackground();
         }
@@ -143,10 +146,12 @@
             return -1;
         }
         switch(type) {
-            case "metered-networks":
-                return listMeteredWifiNetworks();
+            case "wifi-networks":
+                return listWifiNetworks();
             case "restrict-background-whitelist":
                 return listRestrictBackgroundWhitelist();
+            case "restrict-background-blacklist":
+                return listRestrictBackgroundBlacklist();
         }
         pw.println("Error: unknown list type '" + type + "'");
         return -1;
@@ -162,6 +167,8 @@
         switch(type) {
             case "restrict-background-whitelist":
                 return addRestrictBackgroundWhitelist();
+            case "restrict-background-blacklist":
+                return addRestrictBackgroundBlacklist();
         }
         pw.println("Error: unknown add type '" + type + "'");
         return -1;
@@ -177,6 +184,8 @@
         switch(type) {
             case "restrict-background-whitelist":
                 return removeRestrictBackgroundWhitelist();
+            case "restrict-background-blacklist":
+                return removeRestrictBackgroundBlacklist();
         }
         pw.println("Error: unknown remove type '" + type + "'");
         return -1;
@@ -199,6 +208,24 @@
         return 0;
     }
 
+    private int listRestrictBackgroundBlacklist() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+
+        final int[] uids = mInterface.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
+        pw.print("Restrict background blacklisted UIDs: ");
+        if (uids.length == 0) {
+            pw.println("none");
+        } else {
+            for (int i = 0; i < uids.length; i++) {
+                int uid = uids[i];
+                pw.print(uid);
+                pw.print(' ');
+            }
+        }
+        pw.println();
+        return 0;
+    }
+
     private int getRestrictBackground() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         pw.print("Restrict background status: ");
@@ -233,7 +260,25 @@
         return 0;
     }
 
-    private int listMeteredWifiNetworks() throws RemoteException {
+    private int addRestrictBackgroundBlacklist() throws RemoteException {
+        final int uid = getUidFromNextArg();
+        if (uid < 0) {
+            return uid;
+        }
+        mInterface.setUidPolicy(uid, POLICY_REJECT_METERED_BACKGROUND);
+        return 0;
+    }
+
+    private int removeRestrictBackgroundBlacklist() throws RemoteException {
+        final int uid = getUidFromNextArg();
+        if (uid < 0) {
+            return uid;
+        }
+        mInterface.setUidPolicy(uid, POLICY_NONE);
+        return 0;
+    }
+
+    private int listWifiNetworks() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final String arg = getNextArg();
         final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
@@ -248,23 +293,6 @@
         return 0;
     }
 
-    private int getMeteredWifiNetwork() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        final String id = getNextArg();
-        if (id == null) {
-            pw.println("Error: didn't specify ID");
-            return -1;
-        }
-        final List<NetworkPolicy> policies = getWifiPolicies();
-        for (NetworkPolicy policy: policies) {
-            if (id.equals(getNetworkId(policy))) {
-                pw.println(policy.metered);
-                return 0;
-            }
-        }
-        return 0;
-    }
-
     private int setMeteredWifiNetwork() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final String id = getNextArg();
@@ -314,9 +342,12 @@
     private List<NetworkPolicy> getWifiPolicies() throws RemoteException {
         // First gets a list of saved wi-fi networks.
         final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
-        final Set<String> ssids = new HashSet<>(configs.size());
-        for (WifiConfiguration config : configs) {
-            ssids.add(removeDoubleQuotes(config.SSID));
+        final int size = configs != null ? configs.size() : 0;
+        final Set<String> ssids = new HashSet<>(size);
+        if (configs != null) {
+            for (WifiConfiguration config : configs) {
+                ssids.add(removeDoubleQuotes(config.SSID));
+            }
         }
 
         // Then gets the saved policies.
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index d986e94b..673dd8f 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -17,8 +17,8 @@
 package com.android.server.net;
 
 import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.ROAMING_DEFAULT;
-import static android.net.NetworkStats.ROAMING_ROAMING;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.ROAMING_YES;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.TAG_NONE;
@@ -242,7 +242,7 @@
                 entry.uid = key.uid;
                 entry.set = key.set;
                 entry.tag = key.tag;
-                entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_ROAMING : ROAMING_DEFAULT;
+                entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO;
                 entry.rxBytes = historyEntry.rxBytes;
                 entry.rxPackets = historyEntry.rxPackets;
                 entry.txBytes = historyEntry.txBytes;
diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java
index 2f55562..6f781b3 100644
--- a/services/core/java/com/android/server/net/NetworkStatsObservers.java
+++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java
@@ -52,7 +52,7 @@
  */
 class NetworkStatsObservers {
     private static final String TAG = "NetworkStatsObservers";
-    private static final boolean LOGV = true;
+    private static final boolean LOGV = false;
 
     private static final long MIN_THRESHOLD_BYTES = 2 * MB_IN_BYTES;
 
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 9820a12..c19b51f 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import android.app.AutomaticZenRule;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -44,7 +45,6 @@
 
 public class ConditionProviders extends ManagedServices {
     private final ArrayList<ConditionRecord> mRecords = new ArrayList<>();
-    private final ArrayMap<IBinder, IConditionListener> mListeners = new ArrayMap<>();
     private final ArraySet<String> mSystemConditionProviderNames;
     private final ArraySet<SystemConditionProviderService> mSystemConditionProviders
             = new ArraySet<>();
@@ -103,12 +103,6 @@
                 }
             }
         }
-        if (filter == null) {
-            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("    mSystemConditionProviders: "); pw.println(mSystemConditionProviderNames);
         for (int i = 0; i < mSystemConditionProviders.size(); i++) {
             mSystemConditionProviders.valueAt(i).dump(pw, filter);
@@ -173,16 +167,12 @@
         }
     }
 
-    private Condition[] validateConditions(String pkg, Condition[] conditions) {
+    private Condition[] removeDuplicateConditions(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;
@@ -219,16 +209,9 @@
         synchronized(mMutex) {
             if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
                     + (conditions == null ? null : Arrays.asList(conditions)));
-            conditions = validateConditions(pkg, conditions);
+            conditions = removeDuplicateConditions(pkg, conditions);
             if (conditions == null || conditions.length == 0) return;
             final int N = conditions.length;
-            for (IConditionListener listener : mListeners.values()) {
-                try {
-                    listener.onConditionsReceived(conditions);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Error sending conditions to listener " + listener, e);
-                }
-            }
             for (int i = 0; i < N; i++) {
                 final Condition c = conditions[i];
                 final ConditionRecord r = getRecordLocked(c.id, info.component, true /*create*/);
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index ab3cb83..5bc9b1c 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -26,7 +26,9 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.notification.Condition;
@@ -42,6 +44,8 @@
 import com.android.server.notification.NotificationManagerService.DumpFilter;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Built-in zen condition provider for calendar event-based conditions.
@@ -63,15 +67,18 @@
     private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
     private final SparseArray<CalendarTracker> mTrackers = new SparseArray<>();
     private final Handler mWorker;
+    private final HandlerThread mThread;
 
     private boolean mConnected;
     private boolean mRegistered;
     private boolean mBootComplete;  // don't hammer the calendar provider until boot completes.
     private long mNextAlarmTime;
 
-    public EventConditionProvider(Looper worker) {
+    public EventConditionProvider() {
         if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()");
-        mWorker = new Handler(worker);
+        mThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
+        mThread.start();
+        mWorker = new Handler(mThread.getLooper());
     }
 
     @Override
@@ -91,10 +98,12 @@
         pw.print("      mRegistered="); pw.println(mRegistered);
         pw.print("      mBootComplete="); pw.println(mBootComplete);
         dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, System.currentTimeMillis());
-        pw.println("      mSubscriptions=");
-        for (Uri conditionId : mSubscriptions) {
-            pw.print("        ");
-            pw.println(conditionId);
+        synchronized (mSubscriptions) {
+            pw.println("      mSubscriptions=");
+            for (Uri conditionId : mSubscriptions) {
+                pw.print("        ");
+                pw.println(conditionId);
+            }
         }
         pw.println("      mTrackers=");
         for (int i = 0; i < mTrackers.size(); i++) {
@@ -137,19 +146,23 @@
     public void onSubscribe(Uri conditionId) {
         if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
         if (!ZenModeConfig.isValidEventConditionId(conditionId)) {
-            notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition");
+            notifyCondition(createCondition(conditionId, Condition.STATE_FALSE));
             return;
         }
-        if (mSubscriptions.add(conditionId)) {
-            evaluateSubscriptions();
+        synchronized (mSubscriptions) {
+            if (mSubscriptions.add(conditionId)) {
+                evaluateSubscriptions();
+            }
         }
     }
 
     @Override
     public void onUnsubscribe(Uri conditionId) {
         if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
-        if (mSubscriptions.remove(conditionId)) {
-            evaluateSubscriptions();
+        synchronized (mSubscriptions) {
+            if (mSubscriptions.remove(conditionId)) {
+                evaluateSubscriptions();
+            }
         }
     }
 
@@ -193,51 +206,61 @@
             return;
         }
         final long now = System.currentTimeMillis();
-        for (int i = 0; i < mTrackers.size(); i++) {
-            mTrackers.valueAt(i).setCallback(mSubscriptions.isEmpty() ? null : mTrackerCallback);
-        }
-        setRegistered(!mSubscriptions.isEmpty());
-        long reevaluateAt = 0;
-        for (Uri conditionId : mSubscriptions) {
-            final EventInfo event = ZenModeConfig.tryParseEventConditionId(conditionId);
-            if (event == null) {
-                notifyCondition(conditionId, Condition.STATE_FALSE, "badConditionId");
-                continue;
+        List<Condition> conditionsToNotify = new ArrayList<>();
+        synchronized (mSubscriptions) {
+            for (int i = 0; i < mTrackers.size(); i++) {
+                mTrackers.valueAt(i).setCallback(
+                        mSubscriptions.isEmpty() ? null : mTrackerCallback);
             }
-            CheckEventResult result = null;
-            if (event.calendar == null) { // any calendar
-                // event could exist on any tracker
-                for (int i = 0; i < mTrackers.size(); i++) {
-                    final CalendarTracker tracker = mTrackers.valueAt(i);
-                    final CheckEventResult r = tracker.checkEvent(event, now);
-                    if (result == null) {
-                        result = r;
-                    } else {
-                        result.inEvent |= r.inEvent;
-                        result.recheckAt = Math.min(result.recheckAt, r.recheckAt);
-                    }
-                }
-            } else {
-                // event should exist on one tracker
-                final int userId = EventInfo.resolveUserId(event.userId);
-                final CalendarTracker tracker = mTrackers.get(userId);
-                if (tracker == null) {
-                    Slog.w(TAG, "No calendar tracker found for user " + userId);
-                    notifyCondition(conditionId, Condition.STATE_FALSE, "badUserId");
+            setRegistered(!mSubscriptions.isEmpty());
+            long reevaluateAt = 0;
+            for (Uri conditionId : mSubscriptions) {
+                final EventInfo event = ZenModeConfig.tryParseEventConditionId(conditionId);
+                if (event == null) {
+                    conditionsToNotify.add(createCondition(conditionId, Condition.STATE_FALSE));
                     continue;
                 }
-                result = tracker.checkEvent(event, now);
+                CheckEventResult result = null;
+                if (event.calendar == null) { // any calendar
+                    // event could exist on any tracker
+                    for (int i = 0; i < mTrackers.size(); i++) {
+                        final CalendarTracker tracker = mTrackers.valueAt(i);
+                        final CheckEventResult r = tracker.checkEvent(event, now);
+                        if (result == null) {
+                            result = r;
+                        } else {
+                            result.inEvent |= r.inEvent;
+                            result.recheckAt = Math.min(result.recheckAt, r.recheckAt);
+                        }
+                    }
+                } else {
+                    // event should exist on one tracker
+                    final int userId = EventInfo.resolveUserId(event.userId);
+                    final CalendarTracker tracker = mTrackers.get(userId);
+                    if (tracker == null) {
+                        Slog.w(TAG, "No calendar tracker found for user " + userId);
+                        conditionsToNotify.add(createCondition(conditionId, Condition.STATE_FALSE));
+                        continue;
+                    }
+                    result = tracker.checkEvent(event, now);
+                }
+                if (result.recheckAt != 0
+                        && (reevaluateAt == 0 || result.recheckAt < reevaluateAt)) {
+                    reevaluateAt = result.recheckAt;
+                }
+                if (!result.inEvent) {
+                    conditionsToNotify.add(createCondition(conditionId, Condition.STATE_FALSE));
+                    continue;
+                }
+                conditionsToNotify.add(createCondition(conditionId, Condition.STATE_TRUE));
             }
-            if (result.recheckAt != 0 && (reevaluateAt == 0 || result.recheckAt < reevaluateAt)) {
-                reevaluateAt = result.recheckAt;
-            }
-            if (!result.inEvent) {
-                notifyCondition(conditionId, Condition.STATE_FALSE, "!inEventNow");
-                continue;
-            }
-            notifyCondition(conditionId, Condition.STATE_TRUE, "inEventNow");
+            rescheduleAlarm(now, reevaluateAt);
         }
-        rescheduleAlarm(now, reevaluateAt);
+        for (Condition condition : conditionsToNotify) {
+            if (condition != null) {
+                notifyCondition(condition);
+            }
+        }
         if (DEBUG) Slog.d(TAG, "evaluateSubscriptions took " + (System.currentTimeMillis() - now));
     }
 
@@ -261,12 +284,6 @@
         alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
     }
 
-    private void notifyCondition(Uri conditionId, int state, String reason) {
-        if (DEBUG) Slog.d(TAG, "notifyCondition " + conditionId + " "
-                + Condition.stateToString(state) + " reason=" + reason);
-        notifyCondition(createCondition(conditionId, state));
-    }
-
     private Condition createCondition(Uri id, int state) {
         final String summary = NOT_SHOWN;
         final String line1 = NOT_SHOWN;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0d6e3e5..6d9fed4 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -237,7 +238,7 @@
                 rebuildRestoredPackages();
             }
             // make sure we're still bound to any of our services who may have just upgraded
-            rebindServices();
+            rebindServices(false);
         }
     }
 
@@ -248,13 +249,13 @@
             if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
             return;
         }
-        rebindServices();
+        rebindServices(true);
     }
 
     public void onUserUnlocked(int user) {
         if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
         rebuildRestoredPackages();
-        rebindServices();
+        rebindServices(false);
     }
 
     public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
@@ -301,7 +302,9 @@
      * */
     public void registerGuestService(ManagedServiceInfo guest) {
         checkNotNull(guest.service);
-        checkType(guest.service);
+        if (!checkType(guest.service)) {
+            throw new IllegalArgumentException();
+        }
         if (registerServiceImpl(guest) != null) {
             onServiceAdded(guest);
         }
@@ -325,12 +328,16 @@
                     component.flattenToShortString());
         }
 
-        final int[] userIds = mUserProfiles.getCurrentProfileIds();
-        for (int userId : userIds) {
-            if (enabled) {
-                registerServiceLocked(component, userId);
-            } else {
-                unregisterServiceLocked(component, userId);
+
+        synchronized (mMutex) {
+            final int[] userIds = mUserProfiles.getCurrentProfileIds();
+
+            for (int userId : userIds) {
+                if (enabled) {
+                    registerServiceLocked(component, userId);
+                } else {
+                    unregisterServiceLocked(component, userId);
+                }
             }
         }
     }
@@ -450,7 +457,7 @@
         return queryPackageForServices(packageName, userId, null);
     }
 
-    protected Set<ComponentName> queryPackageForServices(String packageName, int userId,
+    public Set<ComponentName> queryPackageForServices(String packageName, int userId,
             String category) {
         Set<ComponentName> installed = new ArraySet<>();
         final PackageManager pm = mContext.getPackageManager();
@@ -536,7 +543,7 @@
      * Called whenever packages change, the user switches, or the secure setting
      * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
      */
-    private void rebindServices() {
+    private void rebindServices(boolean forceRebind) {
         if (DEBUG) Slog.d(TAG, "rebindServices");
         final int[] userIds = mUserProfiles.getCurrentProfileIds();
         final int nUserIds = userIds.length;
@@ -552,15 +559,15 @@
         final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
 
         synchronized (mMutex) {
-            // Potentially unbind automatically bound services, retain system services.
+            // Rebind to non-system services if user switched
             for (ManagedServiceInfo service : mServices) {
                 if (!service.isSystem && !service.isGuest(this)) {
                     removableBoundServices.add(service);
                 }
             }
 
-            final ArraySet<ComponentName> newEnabled = new ArraySet<>();
-            final ArraySet<String> newPackages = new ArraySet<>();
+            mEnabledServicesForCurrentProfiles.clear();
+            mEnabledServicesPackageNames.clear();
 
             for (int i = 0; i < nUserIds; ++i) {
                 // decode the list of components
@@ -584,15 +591,13 @@
 
                 toAdd.put(userIds[i], add);
 
-                newEnabled.addAll(userComponents);
+                mEnabledServicesForCurrentProfiles.addAll(userComponents);
 
                 for (int j = 0; j < userComponents.size(); j++) {
                     final ComponentName component = userComponents.valueAt(j);
-                    newPackages.add(component.getPackageName());
+                    mEnabledServicesPackageNames.add(component.getPackageName());
                 }
             }
-            mEnabledServicesForCurrentProfiles = newEnabled;
-            mEnabledServicesPackageNames = newPackages;
         }
 
         for (ManagedServiceInfo info : removableBoundServices) {
@@ -600,11 +605,11 @@
             final int oldUser = info.userid;
             final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
             if (allowedComponents != null) {
-                if (allowedComponents.contains(component)) {
+                if (allowedComponents.contains(component) && !forceRebind) {
                     // Already bound, don't need to bind again.
                     allowedComponents.remove(component);
                 } else {
-                    // No longer allowed to be bound.
+                    // No longer allowed to be bound, or must rebind.
                     Slog.v(TAG, "disabling " + getCaption() + " for user "
                             + oldUser + ": " + component);
                     unregisterService(component, oldUser);
@@ -615,8 +620,7 @@
         for (int i = 0; i < nUserIds; ++i) {
             final Set<ComponentName> add = toAdd.get(userIds[i]);
             for (ComponentName component : add) {
-                Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
-                        + component);
+                Slog.v(TAG, "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
                 registerService(component, userIds[i]);
             }
         }
@@ -633,7 +637,21 @@
         }
     }
 
+    /**
+     * Inject a system service into the management list.
+     */
+    public void registerSystemService(final ComponentName name, final int userid) {
+        synchronized (mMutex) {
+            registerServiceLocked(name, userid, true /* isSystem */);
+        }
+    }
+
     private void registerServiceLocked(final ComponentName name, final int userid) {
+        registerServiceLocked(name, userid, false /* isSystem */);
+    }
+
+    private void registerServiceLocked(final ComponentName name, final int userid,
+            final boolean isSystem) {
         if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
 
         final String servicesBindingTag = name.toString() + "/" + userid;
@@ -691,7 +709,7 @@
                         try {
                             mService = asInterface(binder);
                             info = newServiceInfo(mService, name,
-                                userid, false /*isSystem*/, this, targetSdkVersion);
+                                userid, isSystem, this, targetSdkVersion);
                             binder.linkToDeath(info, 0);
                             added = mServices.add(info);
                         } catch (RemoteException e) {
@@ -838,7 +856,7 @@
             if (uri == null || mSecureSettingsUri.equals(uri)) {
                 if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri +
                         " / uri=" + uri);
-                rebindServices();
+                rebindServices(false);
                 rebuildRestoredPackages();
             }
         }
@@ -887,6 +905,7 @@
                 return false;
             }
             if (this.userid == UserHandle.USER_ALL) return true;
+            if (this.userid == UserHandle.USER_SYSTEM) return true;
             if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
             return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
         }
@@ -920,9 +939,9 @@
 
     public static class UserProfiles {
         // Profiles of the current user.
-        private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
+        private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
 
-        public void updateCache(Context context) {
+        public void updateCache(@NonNull Context context) {
             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
             if (userManager != null) {
                 int currentUserId = ActivityManager.getCurrentUser();
@@ -954,12 +973,12 @@
         }
     }
 
-    protected static class Config {
-        String caption;
-        String serviceInterface;
-        String secureSettingName;
-        String bindPermission;
-        String settingsAction;
-        int clientLabel;
+    public static class Config {
+        public String caption;
+        public String serviceInterface;
+        public String secureSettingName;
+        public String bindPermission;
+        public String settingsAction;
+        public int clientLabel;
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 5e4703d..7dff2c1 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -28,10 +28,11 @@
         final int leftImportance = left.getImportance();
         final int rightImportance = right.getImportance();
         if (leftImportance != rightImportance) {
-            // by priority, high to low
+            // by importance, high to low
             return -1 * Integer.compare(leftImportance, rightImportance);
         }
 
+        // Whether or not the notification can bypass DND.
         final int leftPackagePriority = left.getPackagePriority();
         final int rightPackagePriority = right.getPackagePriority();
         if (leftPackagePriority != rightPackagePriority) {
@@ -39,6 +40,13 @@
             return -1 * Integer.compare(leftPackagePriority, rightPackagePriority);
         }
 
+        final int leftPriority = left.sbn.getNotification().priority;
+        final int rightPriority = right.sbn.getNotification().priority;
+        if (leftPriority != rightPriority) {
+            // by priority, high to low
+            return -1 * Integer.compare(leftPriority, rightPriority);
+        }
+
         final float leftPeople = left.getContactAffinity();
         final float rightPeople = right.getContactAffinity();
         if (leftPeople != rightPeople) {
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
index b57cc75..bcdeb66 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -23,7 +23,7 @@
 import android.util.Slog;
 
 /**
- * This {@link com.android.server.notification.NotificationSignalExtractor} noticies noisy
+ * This {@link com.android.server.notification.NotificationSignalExtractor} notices noisy
  * notifications and marks them to get a temporary ranking bump.
  */
 public class NotificationIntrusivenessExtractor implements NotificationSignalExtractor {
@@ -44,9 +44,15 @@
             return null;
         }
 
-        final Notification notification = record.getNotification();
-        if (record.getImportance() > NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
-            record.setRecentlyIntrusive(true);
+        if (record.getImportance() >= NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
+            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.setRecentlyIntrusive(true);
+            }
         }
 
         return new RankingReconsideration(record.getKey(), HANG_TIME_MS) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 95198a3..99c41ea 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,33 +16,34 @@
 
 package com.android.server.notification;
 
-import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL;
-import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CLICK;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_ERROR;
-import static android.service.notification.NotificationAssistantService.REASON_GROUP_OPTIMIZATION;
-import static android.service.notification.NotificationAssistantService.REASON_GROUP_SUMMARY_CANCELED;
-import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL;
-import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_SUSPENDED;
-import static android.service.notification.NotificationAssistantService.REASON_PROFILE_TURNED_OFF;
-import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
+import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
+import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
+import static android.service.notification.NotificationRankerService.REASON_GROUP_OPTIMIZATION;
+import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
+import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
+import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
+import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
+import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
+import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
+import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
 import static android.service.notification.NotificationListenerService.TRIM_FULL;
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.Manifest;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -100,7 +101,7 @@
 import android.service.notification.IConditionProvider;
 import android.service.notification.INotificationListener;
 import android.service.notification.IStatusBarNotificationHolder;
-import android.service.notification.NotificationAssistantService;
+import android.service.notification.NotificationRankerService;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
@@ -119,6 +120,7 @@
 import android.widget.Toast;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
@@ -128,10 +130,9 @@
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
-import com.android.server.notification.ManagedServices.UserProfiles;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.vr.VrManagerInternal;
-import com.android.server.vr.VrStateListener;
+import com.android.server.notification.ManagedServices.UserProfiles;
 
 import libcore.io.IoUtils;
 
@@ -156,11 +157,14 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /** {@hide} */
@@ -213,21 +217,19 @@
 
     /** notification_enqueue status value for an ignored notification. */
     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
+    private String mRankerServicePackageName;
 
     private IActivityManager mAm;
     AudioManager mAudioManager;
     AudioManagerInternal mAudioManagerInternal;
-    StatusBarManagerInternal mStatusBar;
+    @Nullable StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
     private VrManagerInternal mVrManagerInternal;
-    private final NotificationVrListener mVrListener = new NotificationVrListener();
 
     final IBinder mForegroundToken = new Binder();
-    private WorkerHandler mHandler;
+    private Handler mHandler;
     private final HandlerThread mRankingThread = new HandlerThread("ranker",
             Process.THREAD_PRIORITY_BACKGROUND);
-    private final HandlerThread mAssistantThread = new HandlerThread("assistant",
-            Process.THREAD_PRIORITY_BACKGROUND);
 
     private Light mNotificationLight;
     Light mAttentionLight;
@@ -276,9 +278,6 @@
     // Persistent storage for notification policy
     private AtomicFile mPolicyFile;
 
-    // Temporary holder for <blocked-packages> config coming from old policy files.
-    private HashSet<String> mBlockedPackages = new HashSet<String>();
-
     private static final int DB_VERSION = 1;
 
     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
@@ -293,14 +292,13 @@
 
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
-    private NotificationAssistant mAssistant;
+    private NotificationRankers mRankerServices;
     private ConditionProviders mConditionProviders;
     private NotificationUsageStats mUsageStats;
 
     private static final int MY_UID = Process.myUid();
     private static final int MY_PID = Process.myPid();
     private RankingHandler mRankingHandler;
-    private Handler mAssistantHandler;
 
     private static class Archive {
         final int mBufferSize;
@@ -355,27 +353,7 @@
         final XmlPullParser parser = Xml.newPullParser();
         parser.setInput(stream, StandardCharsets.UTF_8.name());
 
-        int type;
-        String tag;
-        int version = DB_VERSION;
-        while ((type = parser.next()) != END_DOCUMENT) {
-            tag = parser.getName();
-            if (type == START_TAG) {
-                if (TAG_NOTIFICATION_POLICY.equals(tag)) {
-                    version = Integer.parseInt(
-                            parser.getAttributeValue(null, ATTR_VERSION));
-                } else if (TAG_BLOCKED_PKGS.equals(tag)) {
-                    while ((type = parser.next()) != END_DOCUMENT) {
-                        tag = parser.getName();
-                        if (TAG_PACKAGE.equals(tag)) {
-                            mBlockedPackages.add(
-                                    parser.getAttributeValue(null, ATTR_NAME));
-                        } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
-                            break;
-                        }
-                    }
-                }
-            }
+        while (parser.next() != END_DOCUMENT) {
             mZenModeHelper.readXml(parser, forRestore);
             mRankingHelper.readXml(parser, forRestore);
         }
@@ -384,7 +362,6 @@
     private void loadPolicyFile() {
         if (DBG) Slog.d(TAG, "loadPolicyFile");
         synchronized(mPolicyFile) {
-            mBlockedPackages.clear();
 
             FileInputStream infile = null;
             try {
@@ -596,33 +573,9 @@
         public void clearEffects() {
             synchronized (mNotificationList) {
                 if (DBG) Slog.d(TAG, "clearEffects");
-
-                // sound
-                mSoundNotificationKey = null;
-
-                long identity = Binder.clearCallingIdentity();
-                try {
-                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
-                    if (player != null) {
-                        player.stopAsync();
-                    }
-                } catch (RemoteException e) {
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-
-                // vibrate
-                mVibrateNotificationKey = null;
-                identity = Binder.clearCallingIdentity();
-                try {
-                    mVibrator.cancel();
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-
-                // light
-                mLights.clear();
-                updateLightsLocked();
+                clearSoundLocked();
+                clearVibrateLocked();
+                clearLightsLocked();
             }
         }
 
@@ -682,6 +635,36 @@
         }
     };
 
+    private void clearSoundLocked() {
+        mSoundNotificationKey = null;
+        long identity = Binder.clearCallingIdentity();
+        try {
+            final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+            if (player != null) {
+                player.stopAsync();
+            }
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void clearVibrateLocked() {
+        mVibrateNotificationKey = null;
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mVibrator.cancel();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void clearLightsLocked() {
+        // light
+        mLights.clear();
+        updateLightsLocked();
+    }
+
     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -758,7 +741,7 @@
                     }
                 }
                 mListeners.onPackagesChanged(queryReplace, pkgList);
-                mAssistant.onPackagesChanged(queryReplace, pkgList);
+                mRankerServices.onPackagesChanged(queryReplace, pkgList);
                 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
                 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
             }
@@ -788,17 +771,18 @@
                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
                             REASON_USER_STOPPED, null);
                 }
-            } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
-                boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
+            } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-                if (inQuietMode && userHandle >= 0) {
+                if (userHandle >= 0) {
                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
                             REASON_PROFILE_TURNED_OFF, null);
                 }
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                 // turn off LED when user passes through lock screen
                 mNotificationLight.turnOff();
-                mStatusBar.notificationLightOff();
+                if (mStatusBar != null) {
+                    mStatusBar.notificationLightOff();
+                }
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 // reload per-user settings
@@ -807,7 +791,7 @@
                 // Refresh managed services
                 mConditionProviders.onUserSwitched(user);
                 mListeners.onUserSwitched(user);
-                mAssistant.onUserSwitched(user);
+                mRankerServices.onUserSwitched(user);
                 mZenModeHelper.onUserSwitched(user);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 mUserProfiles.updateCache(context);
@@ -818,7 +802,7 @@
                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 mConditionProviders.onUserUnlocked(user);
                 mListeners.onUserUnlocked(user);
-                mAssistant.onUserUnlocked(user);
+                mRankerServices.onUserUnlocked(user);
                 mZenModeHelper.onUserUnlocked(user);
             }
         }
@@ -856,21 +840,15 @@
         }
     }
 
-    private final class NotificationVrListener extends VrStateListener {
-        @Override
-        public void onVrStateChanged(final boolean enabled) {
-            mListeners.setCategoryState(NotificationListenerService.CATEGORY_VR_NOTIFICATIONS,
-                enabled);
-        }
-    }
-
     private SettingsObserver mSettingsObserver;
     private ZenModeHelper mZenModeHelper;
 
     private final Runnable mBuzzBeepBlinked = new Runnable() {
         @Override
         public void run() {
-            mStatusBar.buzzBeepBlinked();
+            if (mStatusBar != null) {
+                mStatusBar.buzzBeepBlinked();
+            }
         }
     };
 
@@ -891,6 +869,26 @@
         super(context);
     }
 
+    @VisibleForTesting
+    void setAudioManager(AudioManager audioMananger) {
+        mAudioManager = audioMananger;
+    }
+
+    @VisibleForTesting
+    void setVibrator(Vibrator vibrator) {
+        mVibrator = vibrator;
+    }
+
+    @VisibleForTesting
+    void setSystemReady(boolean systemReady) {
+        mSystemReady = systemReady;
+    }
+
+    @VisibleForTesting
+    void setHandler(Handler handler) {
+        mHandler = handler;
+    }
+
     @Override
     public void onStart() {
         Resources resources = getContext().getResources();
@@ -900,9 +898,12 @@
         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
 
+        // This is the package that contains the AOSP framework update.
+        mRankerServicePackageName = getContext().getPackageManager()
+                .getServicesSystemSharedLibraryPackageName();
+
         mHandler = new WorkerHandler();
         mRankingThread.start();
-        mAssistantThread.start();
         String[] extractorNames;
         try {
             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
@@ -911,7 +912,6 @@
         }
         mUsageStats = new NotificationUsageStats(getContext());
         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
-        mAssistantHandler = new Handler(mAssistantThread.getLooper());
         mRankingHelper = new RankingHelper(getContext(),
                 mRankingHandler,
                 mUsageStats,
@@ -944,12 +944,20 @@
         final File systemDir = new File(Environment.getDataDirectory(), "system");
         mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
 
-        importOldBlockDb();
+        syncBlockDb();
 
+        // This is a MangedServices object that keeps track of the listeners.
         mListeners = new NotificationListeners();
-        mAssistant = new NotificationAssistant();
+
+        // This is a MangedServices object that keeps track of the ranker.
+        mRankerServices = new NotificationRankers();
+        // Find the updatable ranker and register it.
+        mRankerServices.registerRanker();
+
         mStatusBar = getLocalService(StatusBarManagerInternal.class);
-        mStatusBar.setNotificationDelegate(mNotificationDelegate);
+        if (mStatusBar != null) {
+            mStatusBar.setNotificationDelegate(mNotificationDelegate);
+        }
 
         final LightsManager lights = getLocalService(LightsManager.class);
         mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
@@ -999,7 +1007,7 @@
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
-        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         getContext().registerReceiver(mIntentReceiver, filter);
 
         IntentFilter pkgFilter = new IntentFilter();
@@ -1036,22 +1044,43 @@
     }
 
     /**
-     * Read the old XML-based app block database and import those blockages into the AppOps system.
+     * Make sure the XML config and the the AppOps system agree about blocks.
      */
-    private void importOldBlockDb() {
+    private void syncBlockDb() {
         loadPolicyFile();
 
-        PackageManager pm = getContext().getPackageManager();
-        for (String pkg : mBlockedPackages) {
-            PackageInfo info = null;
-            try {
-                info = pm.getPackageInfo(pkg, 0);
-                setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
-            } catch (NameNotFoundException e) {
-                // forget you
+        // sync bans from ranker into app opps
+        Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
+        for(Entry<Integer, String> ban : packageBans.entrySet()) {
+            final int uid = ban.getKey();
+            final String packageName = ban.getValue();
+            setNotificationsEnabledForPackageImpl(packageName, uid, false);
+        }
+
+        // sync bans from app opps into ranker
+        packageBans.clear();
+        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
+            final int userId = user.getUserHandle().getIdentifier();
+            final PackageManager packageManager = getContext().getPackageManager();
+            List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
+            final int packageCount = packages.size();
+            for (int p = 0; p < packageCount; p++) {
+                final String packageName = packages.get(p).packageName;
+                try {
+                    final int uid = packageManager.getPackageUidAsUser(packageName, userId);
+                    if (!checkNotificationOp(packageName, uid)) {
+                        packageBans.put(uid, packageName);
+                    }
+                } catch (NameNotFoundException e) {
+                    // forget you
+                }
             }
         }
-        mBlockedPackages.clear();
+        for (Entry<Integer, String> ban : packageBans.entrySet()) {
+            mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
+        }
+
+        savePolicyFile();
     }
 
     @Override
@@ -1064,14 +1093,13 @@
             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
             mVrManagerInternal = getLocalService(VrManagerInternal.class);
-            mVrManagerInternal.registerListener(mVrListener);
             mZenModeHelper.onSystemReady();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
             // bind to listener services.
             mSettingsObserver.observe();
             mListeners.onBootPhaseAppsCanStart();
-            mAssistant.onBootPhaseAppsCanStart();
+            mRankerServices.onBootPhaseAppsCanStart();
             mConditionProviders.onBootPhaseAppsCanStart();
         }
     }
@@ -1257,6 +1285,8 @@
             checkCallerIsSystem();
 
             setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
+            mRankingHelper.setEnabled(pkg, uid, enabled);
+            savePolicyFile();
         }
 
         /**
@@ -1304,7 +1334,7 @@
         }
 
         @Override
-        public void setImportance(String pkg, int uid,  int importance) {
+        public void setImportance(String pkg, int uid, int importance) {
             enforceSystemOrSystemUI("Caller not system or systemui");
             setNotificationsEnabledForPackageImpl(pkg, uid,
                     importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
@@ -1320,7 +1350,7 @@
 
         @Override
         public int getImportance(String pkg, int uid) {
-            checkCallerIsSystem();
+            enforceSystemOrSystemUI("Caller not system or systemui");
             return mRankingHelper.getImportance(pkg, uid);
         }
 
@@ -1435,8 +1465,8 @@
          * Remove a listener binder directly
          */
         @Override
-        public void unregisterListener(INotificationListener listener, int userid) {
-            mListeners.unregisterService(listener, userid);
+        public void unregisterListener(INotificationListener token, int userid) {
+            mListeners.unregisterService(token, userid);
         }
 
         /**
@@ -1489,8 +1519,8 @@
             checkCallerIsSystemOrSameApp(component.getPackageName());
             long identity = Binder.clearCallingIdentity();
             try {
-                ManagedServices manager = mAssistant.isComponentEnabledForCurrentProfiles(component)
-                        ? mAssistant
+                ManagedServices manager = mRankerServices.isComponentEnabledForCurrentProfiles(component)
+                        ? mRankerServices
                         : mListeners;
                 manager.setComponentState(component, true);
             } finally {
@@ -1698,9 +1728,9 @@
         }
 
         @Override
-        public List<AutomaticZenRule> getAutomaticZenRules() throws RemoteException {
+        public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
-            return mZenModeHelper.getAutomaticZenRules();
+            return mZenModeHelper.getZenRules();
         }
 
         @Override
@@ -1711,7 +1741,7 @@
         }
 
         @Override
-        public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule)
+        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
                 throws RemoteException {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
@@ -1724,7 +1754,7 @@
         }
 
         @Override
-        public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule)
+        public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
                 throws RemoteException {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
@@ -1732,7 +1762,7 @@
             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
 
-            return mZenModeHelper.updateAutomaticZenRule(automaticZenRule,
+            return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
                     "updateAutomaticZenRule");
         }
 
@@ -1803,6 +1833,16 @@
                     message);
         }
 
+        private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
+            try {
+                checkCallerIsSystemOrSameApp(pkg);
+            } catch (SecurityException e) {
+                getContext().enforceCallingPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        message);
+            }
+        }
+
         private void enforcePolicyAccess(int uid, String method) {
             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
@@ -1838,6 +1878,17 @@
         }
 
         private boolean checkPolicyAccess(String pkg) {
+            try {
+                int uid = getContext().getPackageManager().getPackageUidAsUser(
+                        pkg, UserHandle.getCallingUserId());
+                if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
+                        -1, true)) {
+                    return true;
+                }
+            } catch (NameNotFoundException e) {
+                return false;
+            }
             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
         }
 
@@ -1929,9 +1980,10 @@
         }
 
         @Override
-        public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
-            enforceSystemOrSystemUI("request policy access status for another package");
-            return checkPackagePolicyAccess(pkg);
+        public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
+            enforceSystemOrSystemUIOrSamePackage(pkg,
+                    "request policy access status for another package");
+            return checkPolicyAccess(pkg);
         }
 
         @Override
@@ -1983,7 +2035,7 @@
         }
 
         @Override
-        public void setImportanceFromAssistant(INotificationListener token, String key,
+        public void setImportanceFromRankerService(INotificationListener token, String key,
                 int importance, CharSequence explanation) throws RemoteException {
             if (importance == IMPORTANCE_NONE) {
                 throw new IllegalArgumentException("blocking not allowed: key=" + key);
@@ -1991,7 +2043,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mNotificationList) {
-                    mAssistant.checkServiceTokenLocked(token);
+                    mRankerServices.checkServiceTokenLocked(token);
                     NotificationRecord n = mNotificationsByKey.get(key);
                     n.setImportance(importance, explanation);
                     mRankingHandler.requestSort();
@@ -2019,21 +2071,8 @@
         JSONObject dump = new JSONObject();
         try {
             dump.put("service", "Notification Manager");
-            JSONArray bans = new JSONArray();
-            try {
-                ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
-                for (Integer userId : packageBans.keySet()) {
-                    for (String packageName : packageBans.get(userId)) {
-                        JSONObject ban = new JSONObject();
-                        ban.put("userId", userId);
-                        ban.put("packageName", packageName);
-                        bans.put(ban);
-                    }
-                }
-            } catch (NameNotFoundException e) {
-                // pass
-            }
-            dump.put("bans", bans);
+            dump.put("bans", mRankingHelper.dumpBansJson(filter));
+            dump.put("ranking", mRankingHelper.dumpJson(filter));
             dump.put("stats", mUsageStats.dumpJson(filter));
         } catch (JSONException e) {
             e.printStackTrace();
@@ -2141,8 +2180,9 @@
                     pw.print(listener.component);
                 }
                 pw.println(')');
-                pw.println("\n  Notification assistant:");
-                mAssistant.dump(pw, filter);
+                pw.println("\n  mRankerServicePackageName: " + mRankerServicePackageName);
+                pw.println("\n  Notification ranker services:");
+                mRankerServices.dump(pw, filter);
             }
             pw.println("\n  Policy access:");
             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2159,47 +2199,9 @@
                     r.dump(pw, "      ", getContext(), filter.redact);
                 }
             }
-
-            try {
-                pw.println("\n  Banned Packages:");
-                ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
-                for (Integer userId : packageBans.keySet()) {
-                    for (String packageName : packageBans.get(userId)) {
-                        pw.println("    " + userId + ": " + packageName);
-                    }
-                }
-            } catch (NameNotFoundException e) {
-                // pass
-            }
         }
     }
 
-    private ArrayMap<Integer, ArrayList<String>> getPackageBans(DumpFilter filter)
-            throws NameNotFoundException {
-        ArrayMap<Integer, ArrayList<String>> packageBans = new ArrayMap<>();
-        ArrayList<String> packageNames = new ArrayList<>();
-        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
-            final int userId = user.getUserHandle().getIdentifier();
-            final PackageManager packageManager = getContext().getPackageManager();
-            List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
-            final int packageCount = packages.size();
-            for (int p = 0; p < packageCount; p++) {
-                final String packageName = packages.get(p).packageName;
-                if (filter == null || filter.matches(packageName)) {
-                    final int uid = packageManager.getPackageUidAsUser(packageName, userId);
-                    if (!checkNotificationOp(packageName, uid)) {
-                        packageNames.add(packageName);
-                    }
-                }
-            }
-            if (!packageNames.isEmpty()) {
-                packageBans.put(userId, packageNames);
-                packageNames = new ArrayList<>();
-            }
-        }
-        return packageBans;
-    }
-
     /**
      * The private API only accessible to the system process.
      */
@@ -2307,7 +2309,7 @@
 
             synchronized (mNotificationList) {
                 final StatusBarNotification n = r.sbn;
-                Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
+                if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
                 if (old != null) {
                     // Retain ranking information from previous record
@@ -2328,7 +2330,7 @@
                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
                 boolean ignoreNotification =
                         removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
-                Slog.d(TAG, "ignoreNotification is " + ignoreNotification);
+                if (DBG) Slog.d(TAG, "ignoreNotification is " + ignoreNotification);
 
                 // This conditional is a dirty hack to limit the logging done on
                 //     behalf of the download manager without affecting other apps.
@@ -2369,9 +2371,9 @@
                     }
                 }
 
-                // tell the assistant about the notification
-                if (mAssistant.isEnabled()) {
-                    mAssistant.onNotificationEnqueued(r);
+                // tell the ranker service about the notification
+                if (mRankerServices.isEnabled()) {
+                    mRankerServices.onNotificationEnqueued(r);
                     // TODO delay the code below here for 100ms or until there is an answer
                 }
 
@@ -2516,15 +2518,17 @@
         return false;
     }
 
-    private void buzzBeepBlinkLocked(NotificationRecord record) {
+    @VisibleForTesting
+    void buzzBeepBlinkLocked(NotificationRecord record) {
         boolean buzz = false;
         boolean beep = false;
         boolean blink = false;
 
         final Notification notification = record.sbn.getNotification();
+        final String key = record.getKey();
 
         // Should this notification make noise, vibe, or use the LED?
-        final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_HIGH;
+        final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
         final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
         if (DBG || record.isIntercepted())
             Slog.v(TAG,
@@ -2545,9 +2549,15 @@
         if (disableEffects != null) {
             ZenLog.traceDisableEffects(record, disableEffects);
         }
+
+        // Remember if this notification already owns the notification channels.
+        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
+        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
+
+        // These are set inside the conditional if the notification is allowed to make noise.
+        boolean hasValidVibrate = false;
+        boolean hasValidSound = false;
         if (disableEffects == null
-                && (!(record.isUpdate
-                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
                 && (record.getUserId() == UserHandle.USER_ALL ||
                     record.getUserId() == currentUser ||
                     mUserProfiles.isCurrentProfile(record.getUserId()))
@@ -2556,10 +2566,6 @@
                 && mAudioManager != null) {
             if (DBG) Slog.v(TAG, "Interrupting!");
 
-            sendAccessibilityEvent(notification, record.sbn.getPackageName());
-
-            // sound
-
             // should we use the default notification sound? (indicated either by
             // DEFAULT_SOUND or because notification.sound is pointing at
             // Settings.System.NOTIFICATION_SOUND)
@@ -2569,8 +2575,6 @@
                                    .equals(notification.sound);
 
             Uri soundUri = null;
-            boolean hasValidSound = false;
-
             if (useDefaultSound) {
                 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
 
@@ -2583,88 +2587,105 @@
                 hasValidSound = (soundUri != null);
             }
 
-            if (hasValidSound) {
-                boolean looping =
-                        (notification.flags & Notification.FLAG_INSISTENT) != 0;
-                AudioAttributes audioAttributes = audioAttributesForNotification(notification);
-                mSoundNotificationKey = record.getKey();
-                // do not play notifications if stream volume is 0 (typically because
-                // ringer mode is silent) or if there is a user of exclusive audio focus
-                if ((mAudioManager.getStreamVolume(
-                        AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
-                            && !mAudioManager.isAudioFocusExclusive()) {
-                    final long identity = Binder.clearCallingIdentity();
-                    try {
-                        final IRingtonePlayer player =
-                                mAudioManager.getRingtonePlayer();
-                        if (player != null) {
-                            if (DBG) Slog.v(TAG, "Playing sound " + soundUri
-                                    + " with attributes " + audioAttributes);
-                            player.playAsync(soundUri, record.sbn.getUser(), looping,
-                                    audioAttributes);
-                            beep = true;
-                        }
-                    } catch (RemoteException e) {
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                }
-            }
-
-            // vibrate
             // Does the notification want to specify its own vibration?
             final boolean hasCustomVibrate = notification.vibrate != null;
 
             // new in 4.2: if there was supposed to be a sound and we're in vibrate
             // mode, and no other vibration is specified, we fall back to vibration
             final boolean convertSoundToVibration =
-                       !hasCustomVibrate
-                    && hasValidSound
-                    && (mAudioManager.getRingerModeInternal()
-                               == AudioManager.RINGER_MODE_VIBRATE);
+                    !hasCustomVibrate
+                            && hasValidSound
+                            && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
 
             // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
             final boolean useDefaultVibrate =
                     (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
 
-            if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
-                    && !(mAudioManager.getRingerModeInternal()
-                            == AudioManager.RINGER_MODE_SILENT)) {
-                mVibrateNotificationKey = record.getKey();
+            hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
+                    hasCustomVibrate;
 
-                if (useDefaultVibrate || convertSoundToVibration) {
-                    // Escalate privileges so we can use the vibrator even if the
-                    // notifying app does not have the VIBRATE permission.
-                    long identity = Binder.clearCallingIdentity();
-                    try {
-                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
-                            useDefaultVibrate ? mDefaultVibrationPattern
-                                : mFallbackVibrationPattern,
-                            ((notification.flags & Notification.FLAG_INSISTENT) != 0)
-                                ? 0: -1, audioAttributesForNotification(notification));
-                        buzz = true;
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
+            // We can alert, and we're allowed to alert, but if the developer asked us to only do
+            // it once, and we already have, then don't.
+            if (!(record.isUpdate
+                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
+
+                sendAccessibilityEvent(notification, record.sbn.getPackageName());
+
+                if (hasValidSound) {
+                    boolean looping =
+                            (notification.flags & Notification.FLAG_INSISTENT) != 0;
+                    AudioAttributes audioAttributes = audioAttributesForNotification(notification);
+                    mSoundNotificationKey = key;
+                    // do not play notifications if stream volume is 0 (typically because
+                    // ringer mode is silent) or if there is a user of exclusive audio focus
+                    if ((mAudioManager.getStreamVolume(
+                            AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
+                            && !mAudioManager.isAudioFocusExclusive()) {
+                        final long identity = Binder.clearCallingIdentity();
+                        try {
+                            final IRingtonePlayer player =
+                                    mAudioManager.getRingtonePlayer();
+                            if (player != null) {
+                                if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+                                        + " with attributes " + audioAttributes);
+                                player.playAsync(soundUri, record.sbn.getUser(), looping,
+                                        audioAttributes);
+                                beep = true;
+                            }
+                        } catch (RemoteException e) {
+                        } finally {
+                            Binder.restoreCallingIdentity(identity);
+                        }
                     }
-                } else if (notification.vibrate.length > 1) {
-                    // If you want your own vibration pattern, you need the VIBRATE
-                    // permission
-                    mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
-                            notification.vibrate,
-                        ((notification.flags & Notification.FLAG_INSISTENT) != 0)
-                                ? 0: -1, audioAttributesForNotification(notification));
-                    buzz = true;
+                }
+
+                if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
+                        == AudioManager.RINGER_MODE_SILENT)) {
+                    mVibrateNotificationKey = key;
+
+                    if (useDefaultVibrate || convertSoundToVibration) {
+                        // Escalate privileges so we can use the vibrator even if the
+                        // notifying app does not have the VIBRATE permission.
+                        long identity = Binder.clearCallingIdentity();
+                        try {
+                            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+                                    useDefaultVibrate ? mDefaultVibrationPattern
+                                            : mFallbackVibrationPattern,
+                                    ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+                                            ? 0: -1, audioAttributesForNotification(notification));
+                            buzz = true;
+                        } finally {
+                            Binder.restoreCallingIdentity(identity);
+                        }
+                    } else if (notification.vibrate.length > 1) {
+                        // If you want your own vibration pattern, you need the VIBRATE
+                        // permission
+                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+                                notification.vibrate,
+                                ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+                                        ? 0: -1, audioAttributesForNotification(notification));
+                        buzz = true;
+                    }
                 }
             }
+
+        }
+        // If a notification is updated to remove the actively playing sound or vibrate,
+        // cancel that feedback now
+        if (wasBeep && !hasValidSound) {
+            clearSoundLocked();
+        }
+        if (wasBuzz && !hasValidVibrate) {
+            clearVibrateLocked();
         }
 
         // light
         // release the light
-        boolean wasShowLights = mLights.remove(record.getKey());
+        boolean wasShowLights = mLights.remove(key);
         if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
                 && ((record.getSuppressedVisualEffects()
                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
-            mLights.add(record.getKey());
+            mLights.add(key);
             updateLightsLocked();
             if (mUseAttentionLight) {
                 mAttentionLight.pulse();
@@ -2678,7 +2699,7 @@
                     & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
                 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
             } else {
-                EventLogTags.writeNotificationAlert(record.getKey(),
+                EventLogTags.writeNotificationAlert(key,
                         buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
                 mHandler.post(mBuzzBeepBlinked);
             }
@@ -2876,9 +2897,10 @@
     }
 
     private void scheduleSendRankingUpdate() {
-        mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
-        Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
-        mHandler.sendMessage(m);
+        if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
+            Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
+            mHandler.sendMessage(m);
+        }
     }
 
     private void handleSendRankingUpdate() {
@@ -3292,7 +3314,9 @@
         // Don't flash while we are in a call or screen is on
         if (ledNotification == null || mInCall || mScreenOn) {
             mNotificationLight.turnOff();
-            mStatusBar.notificationLightOff();
+            if (mStatusBar != null) {
+                mStatusBar.notificationLightOff();
+            }
         } else {
             final Notification ledno = ledNotification.sbn.getNotification();
             int ledARGB = ledno.ledARGB;
@@ -3308,8 +3332,10 @@
                 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
                         ledOnMS, ledOffMS);
             }
-            // let SystemUI make an independent decision
-            mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
+            if (mStatusBar != null) {
+                // let SystemUI make an independent decision
+                mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
+            }
         }
     }
 
@@ -3461,6 +3487,9 @@
             return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
         } catch (RemoteException re) {
             throw new SecurityException("Could not talk to package manager service");
+        } catch (IllegalArgumentException ex) {
+            // Package not found.
+            return false;
         }
     }
 
@@ -3488,21 +3517,21 @@
         }
     }
 
-    public class NotificationAssistant extends ManagedServices {
+    public class NotificationRankers extends ManagedServices {
 
-        public NotificationAssistant() {
+        public NotificationRankers() {
             super(getContext(), mHandler, mNotificationList, mUserProfiles);
         }
 
         @Override
         protected Config getConfig() {
             Config c = new Config();
-            c.caption = "notification assistant";
-            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
-            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
-            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
+            c.caption = "notification ranker service";
+            c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
+            c.secureSettingName = null;
+            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
-            c.clientLabel = R.string.notification_assistant_binding_label;
+            c.clientLabel = R.string.notification_ranker_binding_label;
             return c;
         }
 
@@ -3530,10 +3559,10 @@
             final StatusBarNotification sbn = r.sbn;
             TrimCache trimCache = new TrimCache(sbn);
 
-            // mServices is the list inside ManagedServices of all the assistants,
+            // mServices is the list inside ManagedServices of all the rankers,
             // There should be only one, but it's a list, so while we enforce
             // singularity elsewhere, we keep it general here, to avoid surprises.
-            for (final ManagedServiceInfo info : NotificationAssistant.this.mServices) {
+            for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
                 boolean sbnVisible = isVisibleToListener(sbn, info);
                 if (!sbnVisible) {
                     continue;
@@ -3542,7 +3571,7 @@
                 final int importance = r.getImportance();
                 final boolean fromUser = r.isImportanceFromUser();
                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
-                mAssistantHandler.post(new Runnable() {
+                mHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         notifyEnqueued(info, sbnToPost, importance, fromUser);
@@ -3553,18 +3582,64 @@
 
         private void notifyEnqueued(final ManagedServiceInfo info,
                 final StatusBarNotification sbn, int importance, boolean fromUser) {
-            final INotificationListener assistant = (INotificationListener) info.service;
+            final INotificationListener ranker = (INotificationListener) info.service;
             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
-                assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
+                ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+                Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
             }
         }
 
         public boolean isEnabled() {
             return !mServices.isEmpty();
         }
+
+        @Override
+        public void onUserSwitched(int user) {
+            for (ManagedServiceInfo info : mServices) {
+                unregisterService(info.service, info.userid);
+            }
+            registerRanker();
+        }
+
+        @Override
+        public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
+            if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
+                    + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
+            if (mRankerServicePackageName == null) {
+                return;
+            }
+
+            if (pkgList != null && (pkgList.length > 0)) {
+                for (String pkgName : pkgList) {
+                    if (mRankerServicePackageName.equals(pkgName)) {
+                        registerRanker();
+                    }
+                }
+            }
+        }
+
+        protected void registerRanker() {
+            // Find the updatable ranker and register it.
+            if (mRankerServicePackageName == null) {
+                Slog.w(TAG, "could not start ranker service: no package specified!");
+                return;
+            }
+            Set<ComponentName> rankerComponents = queryPackageForServices(
+                    mRankerServicePackageName, UserHandle.USER_SYSTEM, null);
+            Iterator<ComponentName> iterator = rankerComponents.iterator();
+            if (iterator.hasNext()) {
+                ComponentName rankerComponent = iterator.next();
+                if (iterator.hasNext()) {
+                    Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
+                } else {
+                    registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
+                }
+            } else {
+                Slog.w(TAG, "could not start ranker service: none found");
+            }
+        }
     }
 
     public class NotificationListeners extends ManagedServices {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 25d17f6..fd893fa 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.notification;
 
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MIN;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
@@ -33,6 +34,8 @@
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.EventLogTags;
@@ -55,6 +58,8 @@
  * {@hide}
  */
 public final class NotificationRecord {
+    static final String TAG = "NotificationRecord";
+    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     final StatusBarNotification sbn;
     final int mOriginalFlags;
     private final Context mContext;
@@ -123,6 +128,8 @@
 
         switch (n.priority) {
             case Notification.PRIORITY_MIN:
+                importance = IMPORTANCE_MIN;
+                break;
             case Notification.PRIORITY_LOW:
                 importance = IMPORTANCE_LOW;
                 break;
@@ -143,25 +150,15 @@
                 || n.sound != null
                 || n.vibrate != null;
         stats.isNoisy = isNoisy;
-        if (!isNoisy && importance > IMPORTANCE_DEFAULT) {
-            importance = IMPORTANCE_DEFAULT;
+
+        if (!isNoisy && importance > IMPORTANCE_LOW) {
+            importance = IMPORTANCE_LOW;
         }
 
-        try {
-            final ApplicationInfo applicationInfo =
-                    mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
-                            0, sbn.getUser().getIdentifier());
-            if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.N) {
-                if (isNoisy) {
-                    if (importance >= IMPORTANCE_HIGH) {
-                        importance = IMPORTANCE_MAX;
-                    } else {
-                        importance = IMPORTANCE_HIGH;
-                    }
-                }
+        if (isNoisy) {
+            if (importance < IMPORTANCE_DEFAULT) {
+                importance = IMPORTANCE_DEFAULT;
             }
-        } catch (NameNotFoundException e) {
-            // oh well.
         }
 
         if (n.fullScreenIntent != null) {
@@ -227,12 +224,14 @@
             final int N = notification.actions.length;
             for (int i=0; i<N; i++) {
                 final Notification.Action action = notification.actions[i];
-                pw.println(String.format("%s    [%d] \"%s\" -> %s",
-                        prefix,
-                        i,
-                        action.title,
-                        action.actionIntent.toString()
-                        ));
+                if (action != null) {
+                    pw.println(String.format("%s    [%d] \"%s\" -> %s",
+                            prefix,
+                            i,
+                            action.title,
+                            action.actionIntent == null ? "null" : action.actionIntent.toString()
+                    ));
+                }
             }
             pw.println(prefix + "  }");
         }
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 0272850..b853417 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -336,6 +336,13 @@
             finalImportance = new ImportanceHistogram(context, "note_importance_");
         }
 
+        public AggregatedStats getPrevious() {
+            if (mPrevious == null) {
+                mPrevious = new AggregatedStats(mContext, key);
+            }
+            return mPrevious;
+        }
+
         public void countApiUse(NotificationRecord record) {
             final Notification n = record.getNotification();
             if (n.actions != null) {
@@ -411,67 +418,64 @@
         }
 
         public void emit() {
-            if (mPrevious == null) {
-                mPrevious = new AggregatedStats(null, key);
-            }
+            AggregatedStats previous = getPrevious();
+            maybeCount("note_post", (numPostedByApp - previous.numPostedByApp));
+            maybeCount("note_update", (numUpdatedByApp - previous.numUpdatedByApp));
+            maybeCount("note_remove", (numRemovedByApp - previous.numRemovedByApp));
+            maybeCount("note_with_people", (numWithValidPeople - previous.numWithValidPeople));
+            maybeCount("note_with_stars", (numWithStaredPeople - previous.numWithStaredPeople));
+            maybeCount("people_cache_hit", (numPeopleCacheHit - previous.numPeopleCacheHit));
+            maybeCount("people_cache_miss", (numPeopleCacheMiss - previous.numPeopleCacheMiss));
+            maybeCount("note_blocked", (numBlocked - previous.numBlocked));
+            maybeCount("note_suspended", (numSuspendedByAdmin - previous.numSuspendedByAdmin));
+            maybeCount("note_with_actions", (numWithActions - previous.numWithActions));
+            maybeCount("note_private", (numPrivate - previous.numPrivate));
+            maybeCount("note_secret", (numSecret - previous.numSecret));
+            maybeCount("note_interupt", (numInterrupt - previous.numInterrupt));
+            maybeCount("note_big_text", (numWithBigText - previous.numWithBigText));
+            maybeCount("note_big_pic", (numWithBigPicture - previous.numWithBigPicture));
+            maybeCount("note_fg", (numForegroundService - previous.numForegroundService));
+            maybeCount("note_ongoing", (numOngoing - previous.numOngoing));
+            maybeCount("note_auto", (numAutoCancel - previous.numAutoCancel));
+            maybeCount("note_large_icon", (numWithLargeIcon - previous.numWithLargeIcon));
+            maybeCount("note_inbox", (numWithInbox - previous.numWithInbox));
+            maybeCount("note_media", (numWithMediaSession - previous.numWithMediaSession));
+            maybeCount("note_title", (numWithTitle - previous.numWithTitle));
+            maybeCount("note_text", (numWithText - previous.numWithText));
+            maybeCount("note_sub_text", (numWithSubText - previous.numWithSubText));
+            maybeCount("note_info_text", (numWithInfoText - previous.numWithInfoText));
+            noisyImportance.maybeCount(previous.noisyImportance);
+            quietImportance.maybeCount(previous.quietImportance);
+            finalImportance.maybeCount(previous.finalImportance);
 
-            maybeCount("note_post", (numPostedByApp - mPrevious.numPostedByApp));
-            maybeCount("note_update", (numUpdatedByApp - mPrevious.numUpdatedByApp));
-            maybeCount("note_remove", (numRemovedByApp - mPrevious.numRemovedByApp));
-            maybeCount("note_with_people", (numWithValidPeople - mPrevious.numWithValidPeople));
-            maybeCount("note_with_stars", (numWithStaredPeople - mPrevious.numWithStaredPeople));
-            maybeCount("people_cache_hit", (numPeopleCacheHit - mPrevious.numPeopleCacheHit));
-            maybeCount("people_cache_miss", (numPeopleCacheMiss - mPrevious.numPeopleCacheMiss));
-            maybeCount("note_blocked", (numBlocked - mPrevious.numBlocked));
-            maybeCount("note_suspended", (numSuspendedByAdmin - mPrevious.numSuspendedByAdmin));
-            maybeCount("note_with_actions", (numWithActions - mPrevious.numWithActions));
-            maybeCount("note_private", (numPrivate - mPrevious.numPrivate));
-            maybeCount("note_secret", (numSecret - mPrevious.numSecret));
-            maybeCount("note_interupt", (numInterrupt - mPrevious.numInterrupt));
-            maybeCount("note_big_text", (numWithBigText - mPrevious.numWithBigText));
-            maybeCount("note_big_pic", (numWithBigPicture - mPrevious.numWithBigPicture));
-            maybeCount("note_fg", (numForegroundService - mPrevious.numForegroundService));
-            maybeCount("note_ongoing", (numOngoing - mPrevious.numOngoing));
-            maybeCount("note_auto", (numAutoCancel - mPrevious.numAutoCancel));
-            maybeCount("note_large_icon", (numWithLargeIcon - mPrevious.numWithLargeIcon));
-            maybeCount("note_inbox", (numWithInbox - mPrevious.numWithInbox));
-            maybeCount("note_media", (numWithMediaSession - mPrevious.numWithMediaSession));
-            maybeCount("note_title", (numWithTitle - mPrevious.numWithTitle));
-            maybeCount("note_text", (numWithText - mPrevious.numWithText));
-            maybeCount("note_sub_text", (numWithSubText - mPrevious.numWithSubText));
-            maybeCount("note_info_text", (numWithInfoText - mPrevious.numWithInfoText));
-            noisyImportance.maybeCount(mPrevious.noisyImportance);
-            quietImportance.maybeCount(mPrevious.quietImportance);
-            finalImportance.maybeCount(mPrevious.finalImportance);
-
-            mPrevious.numPostedByApp = numPostedByApp;
-            mPrevious.numUpdatedByApp = numUpdatedByApp;
-            mPrevious.numRemovedByApp = numRemovedByApp;
-            mPrevious.numPeopleCacheHit = numPeopleCacheHit;
-            mPrevious.numPeopleCacheMiss = numPeopleCacheMiss;
-            mPrevious.numWithStaredPeople = numWithStaredPeople;
-            mPrevious.numWithValidPeople = numWithValidPeople;
-            mPrevious.numBlocked = numBlocked;
-            mPrevious.numSuspendedByAdmin = numSuspendedByAdmin;
-            mPrevious.numWithActions = numWithActions;
-            mPrevious.numPrivate = numPrivate;
-            mPrevious.numSecret = numSecret;
-            mPrevious.numInterrupt = numInterrupt;
-            mPrevious.numWithBigText = numWithBigText;
-            mPrevious.numWithBigPicture = numWithBigPicture;
-            mPrevious.numForegroundService = numForegroundService;
-            mPrevious.numOngoing = numOngoing;
-            mPrevious.numAutoCancel = numAutoCancel;
-            mPrevious.numWithLargeIcon = numWithLargeIcon;
-            mPrevious.numWithInbox = numWithInbox;
-            mPrevious.numWithMediaSession = numWithMediaSession;
-            mPrevious.numWithTitle = numWithTitle;
-            mPrevious.numWithText = numWithText;
-            mPrevious.numWithSubText = numWithSubText;
-            mPrevious.numWithInfoText = numWithInfoText;
-            noisyImportance.update(mPrevious.noisyImportance);
-            quietImportance.update(mPrevious.quietImportance);
-            finalImportance.update(mPrevious.finalImportance);
+            previous.numPostedByApp = numPostedByApp;
+            previous.numUpdatedByApp = numUpdatedByApp;
+            previous.numRemovedByApp = numRemovedByApp;
+            previous.numPeopleCacheHit = numPeopleCacheHit;
+            previous.numPeopleCacheMiss = numPeopleCacheMiss;
+            previous.numWithStaredPeople = numWithStaredPeople;
+            previous.numWithValidPeople = numWithValidPeople;
+            previous.numBlocked = numBlocked;
+            previous.numSuspendedByAdmin = numSuspendedByAdmin;
+            previous.numWithActions = numWithActions;
+            previous.numPrivate = numPrivate;
+            previous.numSecret = numSecret;
+            previous.numInterrupt = numInterrupt;
+            previous.numWithBigText = numWithBigText;
+            previous.numWithBigPicture = numWithBigPicture;
+            previous.numForegroundService = numForegroundService;
+            previous.numOngoing = numOngoing;
+            previous.numAutoCancel = numAutoCancel;
+            previous.numWithLargeIcon = numWithLargeIcon;
+            previous.numWithInbox = numWithInbox;
+            previous.numWithMediaSession = numWithMediaSession;
+            previous.numWithTitle = numWithTitle;
+            previous.numWithText = numWithText;
+            previous.numWithSubText = numWithSubText;
+            previous.numWithInfoText = numWithInfoText;
+            noisyImportance.update(previous.noisyImportance);
+            quietImportance.update(previous.quietImportance);
+            finalImportance.update(previous.finalImportance);
         }
 
         void maybeCount(String name, int value) {
@@ -553,6 +557,7 @@
         }
 
         public JSONObject dumpJson() throws JSONException {
+            AggregatedStats previous = getPrevious();
             JSONObject dump = new JSONObject();
             dump.put("key", key);
             dump.put("duration", SystemClock.elapsedRealtime() - mCreated);
@@ -581,9 +586,9 @@
             maybePut(dump, "numWithText", numWithText);
             maybePut(dump, "numWithSubText", numWithSubText);
             maybePut(dump, "numWithInfoText", numWithInfoText);
-            noisyImportance.maybePut(dump, mPrevious.noisyImportance);
-            quietImportance.maybePut(dump, mPrevious.quietImportance);
-            finalImportance.maybePut(dump, mPrevious.finalImportance);
+            noisyImportance.maybePut(dump, previous.noisyImportance);
+            quietImportance.maybePut(dump, previous.quietImportance);
+            finalImportance.maybePut(dump, previous.finalImportance);
 
             return dump;
         }
@@ -597,8 +602,9 @@
 
     private static class ImportanceHistogram {
         // TODO define these somewhere else
-        private static final int NUM_IMPORTANCES = 5;
-        private static final String[] IMPORTANCE_NAMES = {"none", "low", "default", "high", "max"};
+        private static final int NUM_IMPORTANCES = 6;
+        private static final String[] IMPORTANCE_NAMES =
+                {"none", "min", "low", "default", "high", "max"};
         private final Context mContext;
         private final String[] mCounterNames;
         private final String mPrefix;
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index fd96a78..4a41705 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -25,6 +25,11 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -33,6 +38,8 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
 
 public class RankingHelper implements RankingConfig {
     private static final String TAG = "RankingHelper";
@@ -358,6 +365,14 @@
         updateConfig();
     }
 
+    public void setEnabled(String packageName, int uid, boolean enabled) {
+        boolean wasEnabled = getImportance(packageName, uid) != Ranking.IMPORTANCE_NONE;
+        if (wasEnabled == enabled) {
+            return;
+        }
+        setImportance(packageName, uid, enabled ? DEFAULT_IMPORTANCE : Ranking.IMPORTANCE_NONE);
+    }
+
     public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
         if (filter == null) {
             final int N = mSignalExtractors.length;
@@ -398,17 +413,97 @@
                 }
                 if (r.priority != DEFAULT_PRIORITY) {
                     pw.print(" priority=");
-                    pw.print(Ranking.importanceToString(r.priority));
+                    pw.print(Notification.priorityToString(r.priority));
                 }
                 if (r.visibility != DEFAULT_VISIBILITY) {
                     pw.print(" visibility=");
-                    pw.print(Ranking.importanceToString(r.visibility));
+                    pw.print(Notification.visibilityToString(r.visibility));
                 }
                 pw.println();
             }
         }
     }
 
+    public JSONObject dumpJson(NotificationManagerService.DumpFilter filter) {
+        JSONObject ranking = new JSONObject();
+        JSONArray records = new JSONArray();
+        try {
+            ranking.put("noUid", mRestoredWithoutUids.size());
+        } catch (JSONException e) {
+           // pass
+        }
+        final int N = mRecords.size();
+        for (int i = 0; i < N; i++) {
+            final Record r = mRecords.valueAt(i);
+            if (filter == null || filter.matches(r.pkg)) {
+                JSONObject record = new JSONObject();
+                try {
+                    record.put("userId", UserHandle.getUserId(r.uid));
+                    record.put("packageName", r.pkg);
+                    if (r.importance != DEFAULT_IMPORTANCE) {
+                        record.put("importance", Ranking.importanceToString(r.importance));
+                    }
+                    if (r.priority != DEFAULT_PRIORITY) {
+                        record.put("priority", Notification.priorityToString(r.priority));
+                    }
+                    if (r.visibility != DEFAULT_VISIBILITY) {
+                        record.put("visibility", Notification.visibilityToString(r.visibility));
+                    }
+                } catch (JSONException e) {
+                   // pass
+                }
+                records.put(record);
+            }
+        }
+        try {
+            ranking.put("records", records);
+        } catch (JSONException e) {
+            // pass
+        }
+        return ranking;
+    }
+
+    /**
+     * Dump only the ban information as structured JSON for the stats collector.
+     *
+     * This is intentionally redundant with {#link dumpJson} because the old
+     * scraper will expect this format.
+     *
+     * @param filter
+     * @return
+     */
+    public JSONArray dumpBansJson(NotificationManagerService.DumpFilter filter) {
+        JSONArray bans = new JSONArray();
+        Map<Integer, String> packageBans = getPackageBans();
+        for(Entry<Integer, String> ban : packageBans.entrySet()) {
+            final int userId = UserHandle.getUserId(ban.getKey());
+            final String packageName = ban.getValue();
+            if (filter == null || filter.matches(packageName)) {
+                JSONObject banJson = new JSONObject();
+                try {
+                    banJson.put("userId", userId);
+                    banJson.put("packageName", packageName);
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                bans.put(banJson);
+            }
+        }
+        return bans;
+    }
+
+    public Map<Integer, String> getPackageBans() {
+        final int N = mRecords.size();
+        ArrayMap<Integer, String> packageBans = new ArrayMap<>(N);
+        for (int i = 0; i < N; i++) {
+            final Record r = mRecords.valueAt(i);
+            if (r.importance == Ranking.IMPORTANCE_NONE) {
+                packageBans.put(r.uid, r.pkg);
+            }
+        }
+        return packageBans;
+    }
+
     public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
         if (queryReplace || pkgList == null || pkgList.length == 0
                 || mRestoredWithoutUids.isEmpty()) {
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 9cdece5..0945065 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -50,7 +50,7 @@
             mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
         }
         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
-            mConditionProviders.addSystemProvider(new EventConditionProvider(helper.getLooper()));
+            mConditionProviders.addSystemProvider(new EventConditionProvider());
         }
         mConditionProviders.setCallback(this);
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 383c1ab..5c5c8f8 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -238,13 +238,13 @@
         return mZenMode;
     }
 
-    public List<AutomaticZenRule> getAutomaticZenRules() {
-        List<AutomaticZenRule> rules = new ArrayList<>();
+    public List<ZenRule> getZenRules() {
+        List<ZenRule> rules = new ArrayList<>();
         synchronized (mConfig) {
             if (mConfig == null) return rules;
             for (ZenRule rule : mConfig.automaticRules.values()) {
                 if (canManageAutomaticZenRule(rule)) {
-                    rules.add(createAutomaticZenRule(rule));
+                    rules.add(rule);
                 }
             }
         }
@@ -264,18 +264,18 @@
         return null;
     }
 
-    public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
-        if (!TextUtils.isEmpty(automaticZenRule.getId())) {
-            throw new IllegalArgumentException("Rule already exists");
-        }
+    public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
         if (!isSystemRule(automaticZenRule)) {
             ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
             if (owner == null) {
                 throw new IllegalArgumentException("Owner is not a condition provider service");
             }
 
-            final int ruleInstanceLimit = owner.metaData.getInt(
-                    ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
+            int ruleInstanceLimit = -1;
+            if (owner.metaData != null) {
+                ruleInstanceLimit = owner.metaData.getInt(
+                        ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
+            }
             if (ruleInstanceLimit > 0 && ruleInstanceLimit
                     < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
                 throw new IllegalArgumentException("Rule instance limit exceeded");
@@ -293,14 +293,15 @@
             populateZenRule(automaticZenRule, rule, true);
             newConfig.automaticRules.put(rule.id, rule);
             if (setConfigLocked(newConfig, reason, true)) {
-                return createAutomaticZenRule(rule);
+                return rule.id;
             } else {
                 return null;
             }
         }
     }
 
-    public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
+    public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
+            String reason) {
         ZenModeConfig newConfig;
         synchronized (mConfig) {
             if (mConfig == null) return false;
@@ -309,7 +310,6 @@
                         + " reason=" + reason);
             }
             newConfig = mConfig.copy();
-            final String ruleId = automaticZenRule.getId();
             ZenModeConfig.ZenRule rule;
             if (ruleId == null) {
                 throw new IllegalArgumentException("Rule doesn't exist");
@@ -437,7 +437,7 @@
     private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
         return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
                 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
-                rule.id, rule.creationTime);
+                rule.creationTime);
     }
 
     public void setManualZenMode(int zenMode, Uri conditionId, String reason) {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 0eacd13..eae2eaa 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -24,7 +24,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -51,8 +50,6 @@
 
     final AtomicBoolean mIdleTime = new AtomicBoolean(false);
 
-    private boolean useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
-
     public static void schedule(Context context) {
         JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
         JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
@@ -93,8 +90,8 @@
                         // skip previously failing package
                         continue;
                     }
-                    if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles,
-                            /* extractOnly */ false, /* force */ false)) {
+                    if (!pm.performDexOpt(pkg, /* instruction set */ null, /* checkProfiles */ true,
+                            PackageManagerService.REASON_BACKGROUND_DEXOPT, /* force */ false)) {
                         // there was a problem running dexopt,
                         // remember this so we do not keep retrying.
                         sFailedPackageNames.add(pkg);
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index e7c2f6f..098b39e 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -31,10 +31,12 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.UserHandle;
+import android.print.PrintManager;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
 import android.provider.MediaStore;
 import android.provider.Telephony.Sms.Intents;
+import android.telephony.TelephonyManager;
 import android.security.Credentials;
 import android.util.ArraySet;
 import android.util.Log;
@@ -57,7 +59,8 @@
     private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
     private static final boolean DEBUG = false;
 
-    private static final int DEFAULT_FLAGS = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+    private static final int DEFAULT_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE
+            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 
     private static final String AUDIO_MIME_TYPE = "audio/mpeg";
 
@@ -244,10 +247,8 @@
             }
 
             // SetupWizard
-            Intent setupIntent = new Intent(Intent.ACTION_MAIN);
-            setupIntent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
-            PackageParser.Package setupPackage = getDefaultSystemHandlerActivityPackageLPr(
-                    setupIntent, userId);
+            PackageParser.Package setupPackage = getSystemPackageLPr(
+                    mService.mSetupWizardPackage);
             if (setupPackage != null
                     && doesPackageSupportRuntimePermissions(setupPackage)) {
                 grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
@@ -578,12 +579,32 @@
 
             // Print Spooler
             PackageParser.Package printSpoolerPackage = getSystemPackageLPr(
-                    "com.android.printspooler");
+                    PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
             if (printSpoolerPackage != null
                     && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
                 grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
             }
 
+            // EmergencyInfo
+            Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
+            PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackageLPr(
+                    emergencyInfoIntent, userId);
+            if (emergencyInfoPckg != null
+                    && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) {
+                grantRuntimePermissionsLPw(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId);
+                grantRuntimePermissionsLPw(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
+            }
+
+            // NFC Tag viewer
+            Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
+            nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
+            PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackageLPr(
+                    nfcTagIntent, userId);
+            if (nfcTagPkg != null
+                    && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
+                grantRuntimePermissionsLPw(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
+                grantRuntimePermissionsLPw(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
+            }
             mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
         }
     }
@@ -703,7 +724,8 @@
     private PackageParser.Package getDefaultSystemHandlerServicePackageLPr(
             Intent intent, int userId) {
         List<ResolveInfo> handlers = mService.queryIntentServices(intent,
-                intent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS, userId);
+                intent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS, userId)
+                .getList();
         if (handlers == null) {
             return null;
         }
@@ -777,7 +799,7 @@
     }
 
     private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions,
-            boolean systemFixed, boolean overrideUserChoice,  int userId) {
+            boolean systemFixed, boolean isDefaultPhoneOrSms, int userId) {
         if (pkg.requestedPermissions.isEmpty()) {
             return;
         }
@@ -785,7 +807,13 @@
         List<String> requestedPermissions = pkg.requestedPermissions;
         Set<String> grantablePermissions = null;
 
-        if (pkg.isUpdatedSystemApp()) {
+        // If this is the default Phone or SMS app we grant permissions regardless
+        // whether the version on the system image declares the permission as used since
+        // selecting the app as the default Phone or SMS the user makes a deliberate
+        // choice to grant this app the permissions needed to function. For all other
+        // apps, (default grants on first boot and user creation) we don't grant default
+        // permissions if the version on the system image does not declare them.
+        if (!isDefaultPhoneOrSms && pkg.isUpdatedSystemApp()) {
             PackageSetting sysPs = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
             if (sysPs != null) {
                 if (sysPs.pkg.requestedPermissions.isEmpty()) {
@@ -817,7 +845,7 @@
                 // Unless the caller wants to override user choices. The override is
                 // to make sure we can grant the needed permission to the default
                 // sms and phone apps after the user chooses this in the UI.
-                if (flags == 0 || overrideUserChoice) {
+                if (flags == 0 || isDefaultPhoneOrSms) {
                     // Never clobber policy or system.
                     final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                             | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
diff --git a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
index 8786350..389e0a1 100644
--- a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
+++ b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
@@ -210,6 +210,9 @@
     }
 
     public void onPackageUninstalledLPw(PackageParser.Package pkg) {
+        if (pkg == null) {
+            return;
+        }
         PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps == null) {
             return;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 1476e6e..7e25632 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.pm.PackageStats;
 import android.os.Build;
-import android.os.storage.StorageManager;
 import android.util.Slog;
 
 import com.android.internal.os.InstallerConnection;
@@ -37,17 +36,17 @@
      * frameworks/native/cmds/installd/installd.h
      * **************************************************************************/
     /** Application should be visible to everyone */
-    public static final int DEXOPT_PUBLIC       = 1 << 1;
+    public static final int DEXOPT_PUBLIC         = 1 << 1;
     /** Application wants to run in VM safe mode */
-    public static final int DEXOPT_SAFEMODE     = 1 << 2;
+    public static final int DEXOPT_SAFEMODE       = 1 << 2;
     /** Application wants to allow debugging of its code */
-    public static final int DEXOPT_DEBUGGABLE   = 1 << 3;
+    public static final int DEXOPT_DEBUGGABLE     = 1 << 3;
     /** The system boot has finished */
-    public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
-    /** Do not compile, only extract bytecode into an OAT file */
-    public static final int DEXOPT_EXTRACTONLY  = 1 << 5;
+    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 4;
+    /** Hint that the dexopt type is profile-guided. */
+    public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
     /** This is an OTA update dexopt */
-    public static final int DEXOPT_OTA          = 1 << 6;
+    public static final int DEXOPT_OTA            = 1 << 6;
 
     // NOTE: keep in sync with installd
     public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
@@ -137,19 +136,23 @@
     }
 
     public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
-            int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
+            int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
         assertValidInstructionSet(instructionSet);
         mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
-                volumeUuid, useProfiles);
+                compilerFilter, volumeUuid);
     }
 
     public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
-            String volumeUuid, boolean useProfiles)
+            String compilerFilter, String volumeUuid)
                     throws InstallerException {
         assertValidInstructionSet(instructionSet);
         mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
-                outputPath, dexFlags, volumeUuid, useProfiles);
+                outputPath, dexFlags, compilerFilter, volumeUuid);
+    }
+
+    public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
+        return mInstaller.mergeProfiles(uid, pkgName);
     }
 
     public void idmap(String targetApkPath, String overlayApkPath, int uid)
@@ -166,6 +169,14 @@
         mInstaller.execute("rmpackagedir", packageDir);
     }
 
+    public void clearAppProfiles(String pkgName) throws InstallerException {
+        mInstaller.execute("clear_app_profiles", pkgName);
+    }
+
+    public void destroyAppProfiles(String pkgName) throws InstallerException {
+        mInstaller.execute("destroy_app_profiles", pkgName);
+    }
+
     public void createUserConfig(int userid) throws InstallerException {
         mInstaller.execute("mkuserconfig", userid);
     }
@@ -203,6 +214,11 @@
         mInstaller.execute("linkfile", relativePath, fromBase, toBase);
     }
 
+    public void moveAb(String apkPath, String instructionSet, String outputPath)
+            throws InstallerException {
+        mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 8d75f60..4c18e15 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
@@ -25,16 +28,23 @@
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.IPackageManager;
+import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutServiceInternal;
+import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IInterface;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -43,16 +53,20 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Service that manages requests and callbacks for launchers that support
- * managed profiles. 
+ * managed profiles.
  */
-
 public class LauncherAppsService extends SystemService {
 
     private final LauncherAppsImpl mLauncherAppsImpl;
@@ -67,21 +81,63 @@
         publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl);
     }
 
-    class LauncherAppsImpl extends ILauncherApps.Stub {
+    static class BroadcastCookie {
+        public final UserHandle user;
+        public final String packageName;
+
+        BroadcastCookie(UserHandle userHandle, String packageName) {
+            this.user = userHandle;
+            this.packageName = packageName;
+        }
+    }
+
+    @VisibleForTesting
+    static class LauncherAppsImpl extends ILauncherApps.Stub {
         private static final boolean DEBUG = false;
         private static final String TAG = "LauncherAppsService";
         private final Context mContext;
         private final PackageManager mPm;
         private final UserManager mUm;
+        private final ShortcutServiceInternal mShortcutServiceInternal;
         private final PackageCallbackList<IOnAppsChangedListener> mListeners
                 = new PackageCallbackList<IOnAppsChangedListener>();
 
-        private MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+        private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+
+        private final Handler mCallbackHandler;
 
         public LauncherAppsImpl(Context context) {
             mContext = context;
             mPm = mContext.getPackageManager();
             mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            mShortcutServiceInternal = Preconditions.checkNotNull(
+                    LocalServices.getService(ShortcutServiceInternal.class));
+            mShortcutServiceInternal.addListener(mPackageMonitor);
+            mCallbackHandler = BackgroundThread.getHandler();
+        }
+
+        @VisibleForTesting
+        int injectBinderCallingUid() {
+            return getCallingUid();
+        }
+
+        final int injectCallingUserId() {
+            return UserHandle.getUserId(injectBinderCallingUid());
+        }
+
+        @VisibleForTesting
+        long injectClearCallingIdentity() {
+            return Binder.clearCallingIdentity();
+        }
+
+        // Injection point.
+        @VisibleForTesting
+        void injectRestoreCallingIdentity(long token) {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        private int getCallingUserId() {
+            return UserHandle.getUserId(injectBinderCallingUid());
         }
 
         /*
@@ -89,7 +145,8 @@
          *          android.content.pm.IOnAppsChangedListener)
          */
         @Override
-        public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException {
+        public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener)
+                throws RemoteException {
             synchronized (mListeners) {
                 if (DEBUG) {
                     Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle());
@@ -101,7 +158,8 @@
                     startWatchingPackageBroadcasts();
                 }
                 mListeners.unregister(listener);
-                mListeners.register(listener, Binder.getCallingUserHandle());
+                mListeners.register(listener, new BroadcastCookie(UserHandle.of(getCallingUserId()),
+                        callingPackage));
             }
         }
 
@@ -127,7 +185,7 @@
          * Register a receiver to watch for package broadcasts
          */
         private void startWatchingPackageBroadcasts() {
-            mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
+            mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
         }
 
         /**
@@ -155,12 +213,12 @@
          * Checks if the caller is in the same group as the userToCheck.
          */
         private void ensureInUserProfiles(UserHandle userToCheck, String message) {
-            final int callingUserId = UserHandle.getCallingUserId();
+            final int callingUserId = injectCallingUserId();
             final int targetUserId = userToCheck.getIdentifier();
 
             if (targetUserId == callingUserId) return;
 
-            long ident = Binder.clearCallingIdentity();
+            long ident = injectClearCallingIdentity();
             try {
                 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
                 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
@@ -170,7 +228,24 @@
                     throw new SecurityException(message);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                injectRestoreCallingIdentity(ident);
+            }
+        }
+
+        @VisibleForTesting // We override it in unit tests
+        void verifyCallingPackage(String callingPackage) {
+            int packageUid = -1;
+            try {
+                packageUid = mPm.getPackageUidAsUser(callingPackage,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                        UserHandle.getUserId(getCallingUid()));
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "Package not found: " + callingPackage);
+            }
+            if (packageUid != Binder.getCallingUid()) {
+                throw new SecurityException("Calling package name mismatch");
             }
         }
 
@@ -178,12 +253,12 @@
          * Checks if the user is enabled.
          */
         private boolean isUserEnabled(UserHandle user) {
-            long ident = Binder.clearCallingIdentity();
+            long ident = injectClearCallingIdentity();
             try {
                 UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier());
                 return targetUserInfo != null && targetUserInfo.isEnabled();
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                injectRestoreCallingIdentity(ident);
             }
         }
 
@@ -201,7 +276,9 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent,
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
                 return new ParceledListSlice<>(apps);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -219,7 +296,9 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 ResolveInfo app = mPm.resolveActivityAsUser(intent,
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
                 return app;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -238,7 +317,9 @@
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
                 PackageInfo info = pm.getPackageInfo(packageName,
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
                 return info != null && info.applicationInfo.enabled;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -264,6 +345,123 @@
             }
         }
 
+        private void ensureShortcutPermission(@NonNull String callingPackage, UserHandle user) {
+            verifyCallingPackage(callingPackage);
+            ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+
+            if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
+                    callingPackage)) {
+                throw new SecurityException("Caller can't access shortcut information");
+            }
+        }
+
+        @Override
+        public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
+                String packageName, ComponentName componentName, int flags, UserHandle user) {
+            ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return new ParceledListSlice<>(new ArrayList(0));
+            }
+
+            return new ParceledListSlice<>(
+                    mShortcutServiceInternal.getShortcuts(getCallingUserId(),
+                            callingPackage, changedSince, packageName,
+                            componentName, flags, user.getIdentifier()));
+        }
+
+        @Override
+        public ParceledListSlice getShortcutInfo(String callingPackage, String packageName,
+                List<String> ids, UserHandle user) {
+            ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return new ParceledListSlice<>(new ArrayList(0));
+            }
+
+            return new ParceledListSlice<>(
+                    mShortcutServiceInternal.getShortcutInfo(getCallingUserId(),
+                            callingPackage, packageName, ids, user.getIdentifier()));
+        }
+
+        @Override
+        public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
+                UserHandle user) {
+            ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                throw new IllegalStateException("Cannot pin shortcuts for disabled profile "
+                        + user);
+            }
+
+            mShortcutServiceInternal.pinShortcuts(getCallingUserId(),
+                    callingPackage, packageName, ids, user.getIdentifier());
+        }
+
+        @Override
+        public int getShortcutIconResId(String callingPackage, ShortcutInfo shortcut,
+                UserHandle user) {
+            ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return 0;
+            }
+
+            return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(),
+                    callingPackage, shortcut, user.getIdentifier());
+        }
+
+        @Override
+        public ParcelFileDescriptor getShortcutIconFd(String callingPackage, ShortcutInfo shortcut,
+                UserHandle user) {
+            ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return null;
+            }
+
+            return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
+                    callingPackage, shortcut, user.getIdentifier());
+        }
+
+        @Override
+        public boolean hasShortcutHostPermission(String callingPackage) {
+            verifyCallingPackage(callingPackage);
+            return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
+                    callingPackage);
+        }
+
+        @Override
+        public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
+                Rect sourceBounds, Bundle startActivityOptions, UserHandle user) {
+            verifyCallingPackage(callingPackage);
+            ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+
+            if (!isUserEnabled(user)) {
+                throw new IllegalStateException("Cannot start a shortcut for disabled profile "
+                        + user);
+            }
+
+            // Even without the permission, pinned shortcuts are always launchable.
+            if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(),
+                    callingPackage, packageName, shortcutId, user.getIdentifier())) {
+                ensureShortcutPermission(callingPackage, user);
+            }
+
+            final Intent intent = mShortcutServiceInternal.createShortcutIntent(getCallingUserId(),
+                    callingPackage, packageName, shortcutId, user.getIdentifier());
+            if (intent == null) {
+                return false;
+            }
+            // Note the target activity doesn't have to be exported.
+
+            intent.setSourceBounds(sourceBounds);
+            prepareIntentForLaunch(intent, sourceBounds);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mContext.startActivityAsUser(intent, startActivityOptions, user);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+            return true;
+        }
+
         @Override
         public boolean isActivityEnabled(ComponentName component, UserHandle user)
                 throws RemoteException {
@@ -276,7 +474,9 @@
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
                 ActivityInfo info = pm.getActivityInfo(component,
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
                 return info != null;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -293,16 +493,16 @@
 
             Intent launchIntent = new Intent(Intent.ACTION_MAIN);
             launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            launchIntent.setSourceBounds(sourceBounds);
-            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+            prepareIntentForLaunch(launchIntent, sourceBounds);
             launchIntent.setPackage(component.getPackageName());
 
             long ident = Binder.clearCallingIdentity();
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
                 ActivityInfo info = pm.getActivityInfo(component,
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
                 if (!info.exported) {
                     throw new SecurityException("Cannot launch non-exported components "
                             + component);
@@ -312,7 +512,9 @@
                 // as calling startActivityAsUser ignores the category and just
                 // resolves based on the component if present.
                 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent,
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
                 final int size = apps.size();
                 for (int i = 0; i < size; ++i) {
                     ActivityInfo activityInfo = apps.get(i).activityInfo;
@@ -332,6 +534,13 @@
             }
         }
 
+        private void prepareIntentForLaunch(@NonNull Intent launchIntent,
+                @Nullable Rect sourceBounds) {
+            launchIntent.setSourceBounds(sourceBounds);
+            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        }
+
         @Override
         public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
@@ -354,41 +563,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);
+        /** 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 = injectClearCallingIdentity();
+            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;
                 }
-                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);
-                }
+            } finally {
+                injectRestoreCallingIdentity(ident);
             }
+        }
+
+        @VisibleForTesting
+        void postToPackageMonitorHandler(Runnable r) {
+            mCallbackHandler.post(r);
+        }
+
+        private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
+
+            // TODO Simplify with lambdas.
 
             @Override
             public void onPackageAdded(String packageName, int uid) {
@@ -396,8 +611,8 @@
                 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;
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue;
                     try {
                         listener.onPackageAdded(user, packageName);
                     } catch (RemoteException re) {
@@ -415,8 +630,8 @@
                 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;
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue;
                     try {
                         listener.onPackageRemoved(user, packageName);
                     } catch (RemoteException re) {
@@ -434,8 +649,8 @@
                 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;
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue;
                     try {
                         listener.onPackageChanged(user, packageName);
                     } catch (RemoteException re) {
@@ -453,8 +668,8 @@
                 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;
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue;
                     try {
                         listener.onPackagesAvailable(user, packages, isReplacing());
                     } catch (RemoteException re) {
@@ -472,8 +687,8 @@
                 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;
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue;
                     try {
                         listener.onPackagesUnavailable(user, packages, isReplacing());
                     } catch (RemoteException re) {
@@ -491,8 +706,8 @@
                 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, "onPackagesSuspended")) continue;
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue;
                     try {
                         listener.onPackagesSuspended(user, packages);
                     } catch (RemoteException re) {
@@ -510,8 +725,8 @@
                 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, "onPackagesUnsuspended")) continue;
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue;
                     try {
                         listener.onPackagesUnsuspended(user, packages);
                     } catch (RemoteException re) {
@@ -523,6 +738,50 @@
                 super.onPackagesUnsuspended(packages);
             }
 
+            @Override
+            public void onShortcutChanged(@NonNull String packageName,
+                    @UserIdInt int userId) {
+                postToPackageMonitorHandler(() -> onShortcutChangedInner(packageName, userId));
+            }
+
+            private void onShortcutChangedInner(@NonNull String packageName,
+                    @UserIdInt int userId) {
+                final UserHandle user = UserHandle.of(userId);
+
+                final int n = mListeners.beginBroadcast();
+                for (int i = 0; i < n; i++) {
+                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                    if (!isEnabledProfileOf(user, cookie.user, "onShortcutChanged")) continue;
+
+                    final int launcherUserId = cookie.user.getIdentifier();
+
+                    // Make sure the caller has the permission.
+                    if (!mShortcutServiceInternal.hasShortcutHostPermission(
+                            launcherUserId, cookie.packageName)) {
+                        continue;
+                    }
+                    // Each launcher has a different set of pinned shortcuts, so we need to do a
+                    // query in here.
+                    // (As of now, only one launcher has the permission at a time, so it's bit
+                    // moot, but we may change the permission model eventually.)
+                    final List<ShortcutInfo> list =
+                            mShortcutServiceInternal.getShortcuts(launcherUserId,
+                                    cookie.packageName,
+                                    /* changedSince= */ 0, packageName, /* component= */ null,
+                                    ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
+                                    | ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC
+                                    , userId);
+                    try {
+                        listener.onShortcutChanged(user, packageName,
+                                new ParceledListSlice<>(list));
+                    } catch (RemoteException re) {
+                        Slog.d(TAG, "Callback failed ", re);
+                    }
+                }
+                mListeners.finishBroadcast();
+            }
         }
 
         class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 94b3b2d..c3a9226 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -16,36 +16,28 @@
 
 package com.android.server.pm;
 
-import android.app.AppGlobals;
+import static com.android.server.pm.Installer.DEXOPT_OTA;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
+
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.IOtaDexopt;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
-import android.content.pm.ResolveInfo;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.util.ArraySet;
 import android.util.Log;
+import android.util.Slog;
 
-import dalvik.system.DexFile;
+import com.android.internal.os.InstallerConnection.InstallerException;
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
-
-import static com.android.server.pm.Installer.DEXOPT_OTA;
 
 /**
  * A service for A/B OTA dexopting.
@@ -70,6 +62,9 @@
         // Use the package manager install and install lock here for the OTA dex optimizer.
         mPackageDexOptimizer = new OTADexoptPackageDexOptimizer(packageManagerService.mInstaller,
                 packageManagerService.mInstallLock, context);
+
+        // Now it's time to check whether we need to move any A/B artifacts.
+        moveAbArtifacts(packageManagerService.mInstaller);
     }
 
     public static OtaDexoptService main(Context context,
@@ -135,6 +130,7 @@
         // TODO: If apps are not installed in the internal /data partition, we should compare
         //       against that storage's free capacity.
         File dataDir = Environment.getDataDirectory();
+        @SuppressWarnings("deprecation")
         long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
         if (lowThreshold == 0) {
             throw new IllegalStateException("Invalid low memory threshold");
@@ -147,23 +143,53 @@
         }
 
         mPackageDexOptimizer.performDexOpt(nextPackage, null /* ISAs */, false /* useProfiles */,
-                false /* extractOnly */);
+                getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
     }
 
-    private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
-        List<ResolveInfo> ris = null;
-        try {
-            ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                    intent, null, 0, userId);
-        } catch (RemoteException e) {
+    private void moveAbArtifacts(Installer installer) {
+        if (mDexoptPackages != null) {
+            throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
         }
-        ArraySet<String> pkgNames = new ArraySet<String>(ris == null ? 0 : ris.size());
-        if (ris != null) {
-            for (ResolveInfo ri : ris) {
-                pkgNames.add(ri.activityInfo.packageName);
+
+        // Look into all packages.
+        Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
+        for (PackageParser.Package pkg : pkgs) {
+            if (pkg == null) {
+                continue;
+            }
+
+            // Does the package have code? If not, there won't be any artifacts.
+            if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
+                continue;
+            }
+            if (pkg.codePath == null) {
+                Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
+                continue;
+            }
+
+            // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into
+            // /data/ota and moved into the dalvik-cache already.
+            if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) {
+                continue;
+            }
+
+            final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+            final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+            final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                for (String path : paths) {
+                    String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
+                            getAbsolutePath();
+
+                    // TODO: Check first whether there is an artifact, to save the roundtrip time.
+
+                    try {
+                        installer.moveAb(path, dexCodeInstructionSet, oatDir);
+                    } catch (InstallerException e) {
+                    }
+                }
             }
         }
-        return pkgNames;
     }
 
     private static class OTADexoptPackageDexOptimizer extends
@@ -180,10 +206,5 @@
             return dexoptFlags | DEXOPT_OTA;
         }
 
-        @Override
-        protected void recordSuccessfulDexopt(Package pkg, String instructionSet) {
-            // Never record the dexopt, as it's in the B partition.
-        }
-
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index a3af561..d13f472 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -20,12 +20,10 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
+import android.os.Environment;
 import android.os.PowerManager;
 import android.os.UserHandle;
 import android.os.WorkSource;
-import android.os.storage.StorageManager;
-import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 
@@ -33,18 +31,18 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 
 import dalvik.system.DexFile;
 
 import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
 import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
+import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
 import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
 import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
-import static com.android.server.pm.Installer.DEXOPT_EXTRACTONLY;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
 
 /**
  * Helper class for running dexopt command on packages.
@@ -58,8 +56,6 @@
     static final int DEX_OPT_DEFERRED = 2;
     static final int DEX_OPT_FAILED = -1;
 
-    private static final boolean DEBUG_DEXOPT = PackageManagerService.DEBUG_DEXOPT;
-
     private final Installer mInstaller;
     private final Object mInstallLock;
 
@@ -93,8 +89,8 @@
      * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
      * synchronized on {@link #mInstallLock}.
      */
-    int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean useProfiles,
-            boolean extractOnly) {
+    int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean checkProfiles,
+            String targetCompilationFilter) {
         synchronized (mInstallLock) {
             final boolean useLock = mSystemReady;
             if (useLock) {
@@ -102,7 +98,8 @@
                 mDexoptWakeLock.acquire();
             }
             try {
-                return performDexOptLI(pkg, instructionSets, useProfiles, extractOnly);
+                return performDexOptLI(pkg, instructionSets, checkProfiles,
+                        targetCompilationFilter);
             } finally {
                 if (useLock) {
                     mDexoptWakeLock.release();
@@ -112,15 +109,6 @@
     }
 
     /**
-     * Determine whether the package should be skipped for the given instruction set. A return
-     * value of true means the package will be skipped. A return value of false means that the
-     * package will be further investigated, and potentially compiled.
-     */
-    protected boolean shouldSkipBasedOnISA(PackageParser.Package pkg, String instructionSet) {
-        return pkg.mDexOptPerformed.contains(instructionSet);
-    }
-
-    /**
      * Adjust the given dexopt-needed value. Can be overridden to influence the decision to
      * optimize or not (and in what way).
      */
@@ -135,15 +123,8 @@
         return dexoptFlags;
     }
 
-    /**
-     * Update the package status after a successful compilation.
-     */
-    protected void recordSuccessfulDexopt(PackageParser.Package pkg, String instructionSet) {
-        pkg.mDexOptPerformed.add(instructionSet);
-    }
-
     private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
-            boolean useProfiles, boolean extractOnly) {
+            boolean checkProfiles, String targetCompilerFilter) {
         final String[] instructionSets = targetInstructionSets != null ?
                 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
 
@@ -151,83 +132,102 @@
             return DEX_OPT_SKIPPED;
         }
 
+        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+
+        boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter);
+        // If any part of the app is used by other apps, we cannot use profile-guided
+        // compilation.
+        // Skip the check for forward locked packages since they don't share their code.
+        if (isProfileGuidedFilter && !pkg.isForwardLocked()) {
+            for (String path : paths) {
+                if (isUsedByOtherApps(path)) {
+                    checkProfiles = false;
+
+                    targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+                    if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {
+                        throw new IllegalStateException(targetCompilerFilter);
+                    }
+                    isProfileGuidedFilter = false;
+
+                    break;
+                }
+            }
+        }
+
+        // If we're asked to take profile updates into account, check now.
+        boolean newProfile = false;
+        if (checkProfiles && isProfileGuidedFilter) {
+            // Merge profiles, see if we need to do anything.
+            try {
+                newProfile = mInstaller.mergeProfiles(sharedGid, pkg.packageName);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to merge profiles", e);
+            }
+        }
+
         final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
         final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
 
-        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
         boolean performedDexOpt = false;
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-            if (!useProfiles && shouldSkipBasedOnISA(pkg, dexCodeInstructionSet)) {
-                // Skip only if we do not use profiles since they might trigger a recompilation.
-                continue;
-            }
-
             for (String path : paths) {
                 int dexoptNeeded;
-
                 try {
-                    dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName,
-                            dexCodeInstructionSet, /* defer */false);
+                    dexoptNeeded = DexFile.getDexOptNeeded(path,
+                            dexCodeInstructionSet, targetCompilerFilter, newProfile);
                 } catch (IOException ioe) {
                     Slog.w(TAG, "IOException reading apk: " + path, ioe);
                     return DEX_OPT_FAILED;
                 }
                 dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
-
-                if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
-                    if (useProfiles) {
-                        // Profiles may trigger re-compilation. The final decision is taken in
-                        // installd.
-                        dexoptNeeded = DexFile.DEX2OAT_NEEDED;
-                    } else {
-                        // No dexopt needed and we don't use profiles. Nothing to do.
-                        continue;
-                    }
+                if (PackageManagerService.DEBUG_DEXOPT) {
+                    Log.i(TAG, "DexoptNeeded for " + path + "@" + targetCompilerFilter + " is " +
+                            dexoptNeeded);
                 }
+
                 final String dexoptType;
                 String oatDir = null;
-                if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
-                    dexoptType = "dex2oat";
-                    oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
-                } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
-                    dexoptType = "patchoat";
-                } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
-                    dexoptType = "self patchoat";
-                } else {
-                    throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
+                switch (dexoptNeeded) {
+                    case DexFile.NO_DEXOPT_NEEDED:
+                        continue;
+                    case DexFile.DEX2OAT_NEEDED:
+                        dexoptType = "dex2oat";
+                        oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
+                        break;
+                    case DexFile.PATCHOAT_NEEDED:
+                        dexoptType = "patchoat";
+                        break;
+                    case DexFile.SELF_PATCHOAT_NEEDED:
+                        dexoptType = "self patchoat";
+                        break;
+                    default:
+                        throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
                 }
 
-
                 Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
                         + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
                         + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
-                        + " extractOnly=" + extractOnly + " oatDir = " + oatDir);
-                final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                        + " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir);
+                // Profile guide compiled oat files should not be public.
+                final boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
+                final int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
                 final int dexFlags = adjustDexoptFlags(
-                        (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
+                        ( isPublic ? DEXOPT_PUBLIC : 0)
                         | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
                         | (debuggable ? DEXOPT_DEBUGGABLE : 0)
-                        | (extractOnly ? DEXOPT_EXTRACTONLY : 0)
+                        | profileFlag
                         | DEXOPT_BOOTCOMPLETE);
 
                 try {
                     mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet,
-                            dexoptNeeded, oatDir, dexFlags, pkg.volumeUuid, useProfiles);
+                            dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid);
                     performedDexOpt = true;
                 } catch (InstallerException e) {
                     Slog.w(TAG, "Failed to dexopt", e);
                 }
             }
-
-            if (!extractOnly) {
-                // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
-                // either have either succeeded dexopt, or have had getDexOptNeeded tell us
-                // it isn't required. We therefore mark that this package doesn't need dexopt unless
-                // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
-                // it.
-                recordSuccessfulDexopt(pkg, dexCodeInstructionSet);
-            }
         }
 
         // If we've gotten here, we're sure that no error occurred and that we haven't
@@ -275,6 +275,25 @@
         mSystemReady = true;
     }
 
+    private boolean isUsedByOtherApps(String apkPath) {
+        try {
+            apkPath = new File(apkPath).getCanonicalPath();
+        } catch (IOException e) {
+            // Log an error but continue without it.
+            Slog.w(TAG, "Failed to get canonical path", e);
+        }
+        String useMarker = apkPath.replace('/', '@');
+        final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+        for (int i = 0; i < currentUserIds.length; i++) {
+            File profileDir = Environment.getDataProfilesDeForeignDexDirectory(currentUserIds[i]);
+            File foreignUseMark = new File(profileDir, useMarker);
+            if (foreignUseMark.exists()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * A specialized PackageDexOptimizer that overrides already-installed checks, forcing a
      * dexopt path.
@@ -291,12 +310,6 @@
         }
 
         @Override
-        protected boolean shouldSkipBasedOnISA(Package pkg, String instructionSet) {
-            // Forced compilation, never skip.
-            return false;
-        }
-
-        @Override
         protected int adjustDexoptNeeded(int dexoptNeeded) {
             // Ensure compilation, no matter the current state.
             // TODO: The return value is wrong when patchoat is needed.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b84ffa3..ef53905 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -34,6 +34,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionParams;
@@ -58,6 +59,7 @@
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructStat;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.ExceptionUtils;
 import android.util.MathUtils;
@@ -77,6 +79,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileFilter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -86,6 +89,7 @@
 public class PackageInstallerSession extends IPackageInstallerSession.Stub {
     private static final String TAG = "PackageInstaller";
     private static final boolean LOGD = true;
+    private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
 
     private static final int MSG_COMMIT = 0;
 
@@ -171,6 +175,25 @@
     @GuardedBy("mLock")
     private File mInheritedFilesBase;
 
+    private static final FileFilter sAddedFilter = new FileFilter() {
+        @Override
+        public boolean accept(File file) {
+            // Installers can't stage directories, so it's fine to ignore
+            // entries like "lost+found".
+            if (file.isDirectory()) return false;
+            if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
+            return true;
+        }
+    };
+    private static final FileFilter sRemovedFilter = new FileFilter() {
+        @Override
+        public boolean accept(File file) {
+            if (file.isDirectory()) return false;
+            if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
+            return true;
+        }
+    };
+
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
@@ -346,6 +369,32 @@
     }
 
     @Override
+    public void removeSplit(String splitName) {
+        if (TextUtils.isEmpty(params.appPackageName)) {
+            throw new IllegalStateException("Must specify package name to remove a split");
+        }
+        try {
+            createRemoveSplitMarker(splitName);
+        } catch (IOException e) {
+            throw ExceptionUtils.wrap(e);
+        }
+    }
+
+    private void createRemoveSplitMarker(String splitName) throws IOException {
+        try {
+            final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
+            if (!FileUtils.isValidExtFilename(markerName)) {
+                throw new IllegalArgumentException("Invalid marker: " + markerName);
+            }
+            final File target = new File(resolveStageDir(), markerName);
+            target.createNewFile();
+            Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
+
+    @Override
     public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
         try {
             return openWriteInternal(name, offsetBytes, lengthBytes);
@@ -608,22 +657,28 @@
         mResolvedStagedFiles.clear();
         mResolvedInheritedFiles.clear();
 
-        final File[] files = mResolvedStageDir.listFiles();
-        if (ArrayUtils.isEmpty(files)) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+        final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
+        final List<String> removeSplitList = new ArrayList<>();
+        if (!ArrayUtils.isEmpty(removedFiles)) {
+            for (File removedFile : removedFiles) {
+                final String fileName = removedFile.getName();
+                final String splitName = fileName.substring(
+                        0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
+                removeSplitList.add(splitName);
+            }
         }
 
+        final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+        if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+        }
         // Verify that all staged packages are internally consistent
         final ArraySet<String> stagedSplits = new ArraySet<>();
-        for (File file : files) {
-
-            // Installers can't stage directories, so it's fine to ignore
-            // entries like "lost+found".
-            if (file.isDirectory()) continue;
-
+        for (File addedFile : addedFiles) {
             final ApkLite apk;
             try {
-                apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
+                apk = PackageParser.parseApkLite(
+                        addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
             }
@@ -642,7 +697,7 @@
                 mSignatures = apk.signatures;
             }
 
-            assertApkConsistent(String.valueOf(file), apk);
+            assertApkConsistent(String.valueOf(addedFile), apk);
 
             // Take this opportunity to enforce uniform naming
             final String targetName;
@@ -657,8 +712,8 @@
             }
 
             final File targetFile = new File(mResolvedStageDir, targetName);
-            if (!file.equals(targetFile)) {
-                file.renameTo(targetFile);
+            if (!addedFile.equals(targetFile)) {
+                addedFile.renameTo(targetFile);
             }
 
             // Base is coming from session
@@ -669,6 +724,27 @@
             mResolvedStagedFiles.add(targetFile);
         }
 
+        if (removeSplitList.size() > 0) {
+            // validate split names marked for removal
+            final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0;
+            final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId);
+            for (String splitName : removeSplitList) {
+                if (!ArrayUtils.contains(pkg.splitNames, splitName)) {
+                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                            "Split not found: " + splitName);
+                }
+            }
+
+            // ensure we've got appropriate package name, version code and signatures
+            if (mPackageName == null) {
+                mPackageName = pkg.packageName;
+                mVersionCode = pkg.versionCode;
+            }
+            if (mSignatures == null) {
+                mSignatures = pkg.signatures;
+            }
+        }
+
         if (params.mode == SessionParams.MODE_FULL_INSTALL) {
             // Full installs must include a base package
             if (!stagedSplits.contains(null)) {
@@ -707,8 +783,8 @@
                 for (int i = 0; i < existing.splitNames.length; i++) {
                     final String splitName = existing.splitNames[i];
                     final File splitFile = new File(existing.splitCodePaths[i]);
-
-                    if (!stagedSplits.contains(splitName)) {
+                    final boolean splitRemoved = removeSplitList.contains(splitName);
+                    if (!stagedSplits.contains(splitName) && !splitRemoved) {
                         mResolvedInheritedFiles.add(splitFile);
                     }
                 }
@@ -748,6 +824,11 @@
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
                     + apk.packageName + " inconsistent with " + mPackageName);
         }
+        if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+                    + " specified package " + params.appPackageName
+                    + " inconsistent with " + apk.packageName);
+        }
         if (mVersionCode != apk.versionCode) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
                     + " version code " + apk.versionCode + " inconsistent with "
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index abbad21..fbf4c0c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -61,8 +61,10 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
@@ -74,6 +76,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED;
 import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
@@ -91,6 +94,8 @@
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
 import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
 import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
 import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
@@ -101,7 +106,9 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.IDevicePolicyManager;
+import android.app.admin.SecurityLog;
 import android.app.backup.IBackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -109,6 +116,7 @@
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentFilter.AuthorityEntry;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
@@ -141,6 +149,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ActivityIntentInfo;
+import android.content.pm.PackageParser.IntentInfo;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageStats;
@@ -153,7 +162,6 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.content.res.Resources;
@@ -315,6 +323,7 @@
     private static final boolean DEBUG_INTENT_MATCHING = false;
     private static final boolean DEBUG_PACKAGE_SCANNING = false;
     private static final boolean DEBUG_VERIFY = false;
+    private static final boolean DEBUG_FILTERS = false;
 
     // Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
     // and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -358,6 +367,7 @@
     static final int SCAN_MOVE = 1<<13;
     static final int SCAN_INITIAL = 1<<14;
     static final int SCAN_CHECK_ONLY = 1<<15;
+    static final int SCAN_DONT_KILL_APP = 1<<17;
 
     static final int REMOVE_CHATTY = 1<<16;
 
@@ -439,10 +449,36 @@
         sBrowserIntent.setData(Uri.parse("http:"));
     }
 
+    /**
+     * The set of all protected actions [i.e. those actions for which a high priority
+     * intent filter is disallowed].
+     */
+    private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>();
+    static {
+        PROTECTED_ACTIONS.add(Intent.ACTION_SEND);
+        PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO);
+        PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE);
+        PROTECTED_ACTIONS.add(Intent.ACTION_VIEW);
+    }
+
+    // Compilation reasons.
+    public static final int REASON_FIRST_BOOT = 0;
+    public static final int REASON_BOOT = 1;
+    public static final int REASON_INSTALL = 2;
+    public static final int REASON_BACKGROUND_DEXOPT = 3;
+    public static final int REASON_AB_OTA = 4;
+    public static final int REASON_NON_SYSTEM_LIBRARY = 5;
+    public static final int REASON_SHARED_APK = 6;
+    public static final int REASON_FORCED_DEXOPT = 7;
+
+    public static final int REASON_LAST = REASON_FORCED_DEXOPT;
+
     final ServiceThread mHandlerThread;
 
     final PackageHandler mHandler;
 
+    private final ProcessLoggingHandler mProcessLoggingHandler;
+
     /**
      * Messages for {@link #mHandler} that need to wait for system ready before
      * being dispatched.
@@ -458,6 +494,7 @@
     final int mDefParseFlags;
     final String[] mSeparateProcesses;
     final boolean mIsUpgrade;
+    final boolean mIsPreNUpgrade;
 
     /** The location for ASEC container files on internal storage. */
     final String mAsecInternalPath;
@@ -497,6 +534,9 @@
     final ArrayMap<String, PackageParser.Package> mPackages =
             new ArrayMap<String, PackageParser.Package>();
 
+    final ArrayMap<String, Set<String>> mKnownCodebase =
+            new ArrayMap<String, Set<String>>();
+
     // Tracks available target package names -> overlay package paths.
     final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays =
         new ArrayMap<String, ArrayMap<String, PackageParser.Package>>();
@@ -507,6 +547,20 @@
      * are package location.
      */
     final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+    /**
+     * Tracks high priority intent filters for protected actions. During boot, certain
+     * filter actions are protected and should never be allowed to have a high priority
+     * intent filter for them. However, there is one, and only one exception -- the
+     * setup wizard. It must be able to define a high priority intent filter for these
+     * actions to ensure there are no escapes from the wizard. We need to delay processing
+     * of these during boot as we need to look at all of the system packages in order
+     * to know which component is the setup wizard.
+     */
+    private final List<PackageParser.ActivityIntentInfo> mProtectedFilters = new ArrayList<>();
+    /**
+     * Whether or not processing protected filters should be deferred.
+     */
+    private boolean mDeferProtectedFilters = true;
 
     /**
      * Tracks existing system packages prior to receiving an OTA. Keys are package name.
@@ -637,9 +691,6 @@
     // List of packages names to keep cached, even if they are uninstalled for all users
     private List<String> mKeepUninstalledPackages;
 
-    private boolean mUseJitProfiles =
-            SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
-
     private static class IFVerificationParams {
         PackageParser.Package pkg;
         boolean replacing;
@@ -1014,6 +1065,7 @@
 
     final @Nullable String mRequiredVerifierPackage;
     final @Nullable String mRequiredInstallerPackage;
+    final @Nullable String mSetupWizardPackage;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
 
@@ -1426,19 +1478,21 @@
 
                         final boolean grantPermissions = (args.installFlags
                                 & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+                        final boolean killApp = (args.installFlags
+                                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                         final String[] grantedPermissions = args.installGrantPermissions;
 
                         // Handle the parent package
-                        handlePackagePostInstall(parentRes, grantPermissions, grantedPermissions,
-                                args.observer);
+                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
+                                grantedPermissions, args.observer);
 
                         // Handle the child packages
                         final int childCount = (parentRes.addedChildPackages != null)
                                 ? parentRes.addedChildPackages.size() : 0;
                         for (int i = 0; i < childCount; i++) {
                             PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
-                            handlePackagePostInstall(childRes, grantPermissions, grantedPermissions,
-                                    args.observer);
+                            handlePackagePostInstall(childRes, grantPermissions, killApp,
+                                    grantedPermissions, args.observer);
                         }
 
                         // Log tracing if needed
@@ -1633,11 +1687,12 @@
     }
 
     private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
-            String[] grantedPermissions, IPackageInstallObserver2 installObserver) {
+            boolean killApp, String[] grantedPermissions,
+            IPackageInstallObserver2 installObserver) {
         if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
             // Send the removed broadcasts
             if (res.removedInfo != null) {
-                res.removedInfo.sendPackageRemovedBroadcasts();
+                res.removedInfo.sendPackageRemovedBroadcasts(killApp);
             }
 
             // Now that we successfully installed the package, grant runtime
@@ -1692,6 +1747,8 @@
 
             // Send installed broadcasts if the install/update is not ephemeral
             if (!isEphemeral(res.pkg)) {
+                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
+
                 // Send added for users that see the package for the first time
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                         extras, 0 /*flags*/, null /*targetPackage*/,
@@ -1951,6 +2008,9 @@
 
     public static PackageManagerService main(Context context, Installer installer,
             boolean factoryTest, boolean onlyCore) {
+        // Self-check for initial settings.
+        PackageManagerServiceCompilerMapping.checkProperties();
+
         PackageManagerService m = new PackageManagerService(context, installer,
                 factoryTest, onlyCore);
         m.enableSystemUserPackages();
@@ -2073,6 +2133,7 @@
                     Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
             mHandlerThread.start();
             mHandler = new PackageHandler(mHandlerThread.getLooper());
+            mProcessLoggingHandler = new ProcessLoggingHandler();
             Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
 
             File dataDir = Environment.getDataDirectory();
@@ -2159,14 +2220,17 @@
                         }
 
                         try {
-                            int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
+                            // Shared libraries do not have profiles so we perform a full
+                            // AOT compilation (if needed).
+                            int dexoptNeeded = DexFile.getDexOptNeeded(
+                                    lib, dexCodeInstructionSet,
+                                    getCompilerFilterForReason(REASON_SHARED_APK),
+                                    false /* newProfile */);
                             if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                                // Shared libraries do not have profiles so we perform a full
-                                // AOT compilation.
                                 mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
                                         dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
-                                        StorageManager.UUID_PRIVATE_INTERNAL,
-                                        false /*useProfiles*/);
+                                        getCompilerFilterForReason(REASON_SHARED_APK),
+                                        StorageManager.UUID_PRIVATE_INTERNAL);
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
@@ -2182,6 +2246,7 @@
 
             final VersionInfo ver = mSettings.getInternalVersion();
             mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
+
             // when upgrading from pre-M, promote system app permissions from install to runtime
             mPromoteSystemApps =
                     mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
@@ -2198,6 +2263,11 @@
                 }
             }
 
+            // When upgrading from pre-N, we need to handle package extraction like first boot,
+            // as there is no profiling data available.
+            mIsPreNUpgrade = !mSettings.isNWorkDone();
+            mSettings.setNWorkDone();
+
             // Collect vendor overlay packages.
             // (Do this before scanning any apps.)
             // For security and version matching reason, only consider
@@ -2389,6 +2459,36 @@
             }
             mExpectingBetter.clear();
 
+            // Resolve protected action filters. Only the setup wizard is allowed to
+            // have a high priority filter for these actions.
+            mSetupWizardPackage = getSetupWizardPackageName();
+            if (mProtectedFilters.size() > 0) {
+                if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+                    Slog.i(TAG, "No setup wizard;"
+                        + " All protected intents capped to priority 0");
+                }
+                for (ActivityIntentInfo filter : mProtectedFilters) {
+                    if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
+                        if (DEBUG_FILTERS) {
+                            Slog.i(TAG, "Found setup wizard;"
+                                + " allow priority " + filter.getPriority() + ";"
+                                + " package: " + filter.activity.info.packageName
+                                + " activity: " + filter.activity.className
+                                + " priority: " + filter.getPriority());
+                        }
+                        // skip setup wizard; allow it to keep the high priority filter
+                        continue;
+                    }
+                    Slog.w(TAG, "Protected action; cap priority to 0;"
+                            + " package: " + filter.activity.info.packageName
+                            + " activity: " + filter.activity.className
+                            + " origPrio: " + filter.getPriority());
+                    filter.setPriority(0);
+                }
+            }
+            mDeferProtectedFilters = false;
+            mProtectedFilters.clear();
+
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
             updateAllSharedLibrariesLPw();
@@ -2441,7 +2541,7 @@
             // since core system apps like SettingsProvider and SystemUI
             // can't wait for user to start
             final int storageFlags;
-            if (StorageManager.isFileBasedEncryptionEnabled()) {
+            if (StorageManager.isFileEncryptedNativeOrEmulated()) {
                 storageFlags = StorageManager.FLAG_STORAGE_DE;
             } else {
                 storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -2449,33 +2549,6 @@
             reconcileAppsData(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,
                     storageFlags);
 
-            if (!StorageManager.isFileBasedEncryptionEnabled()
-                    && PackageManager.APPLY_FORCE_DEVICE_ENCRYPTED) {
-                // When upgrading a non-FBE device, we might need to shuffle
-                // around the default storage location of system apps
-                final List<UserInfo> users = sUserManager.getUsers(true);
-                for (PackageSetting ps : mSettings.mPackages.values()) {
-                    if (ps.pkg == null || !ps.isSystem()) continue;
-                    final int storageTarget = ps.pkg.applicationInfo.isForceDeviceEncrypted()
-                            ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
-                    for (UserInfo user : users) {
-                        if (ps.getInstalled(user.id)) {
-                            try {
-                                mInstaller.migrateAppData(StorageManager.UUID_PRIVATE_INTERNAL,
-                                        ps.name, user.id, storageTarget);
-                            } catch (InstallerException e) {
-                                logCriticalInfo(Log.WARN,
-                                        "Failed to migrate " + ps.name + ": " + e.getMessage());
-                            }
-                            // We may have just shuffled around app data
-                            // directories, so prepare it one more time
-                            prepareAppData(StorageManager.UUID_PRIVATE_INTERNAL, user.id,
-                                    storageFlags, ps.pkg, false);
-                        }
-                    }
-                }
-            }
-
             // If this is first boot after an OTA, and a normal boot, then
             // we need to clear code cache directories.
             if (mIsUpgrade && !onlyCore) {
@@ -2583,8 +2656,9 @@
     private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() {
         final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
 
-        final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
-                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        final List<ResolveInfo> matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM);
         if (matches.size() == 1) {
             return matches.get(0).getComponentInfo().packageName;
         } else {
@@ -2598,8 +2672,9 @@
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
 
-        final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
-                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM);
         if (matches.size() == 1) {
             return matches.get(0).getComponentInfo().packageName;
         } else {
@@ -2610,8 +2685,9 @@
     private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
         final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
 
-        final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
-                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        final List<ResolveInfo> matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM);
         ResolveInfo best = null;
         final int N = matches.size();
         for (int i = 0; i < N; i++) {
@@ -2645,8 +2721,9 @@
         }
 
         final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
-        final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent, null,
-                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        final List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM);
 
         final int N = resolvers.size();
         if (N == 0) {
@@ -2690,8 +2767,9 @@
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
 
-        final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
-                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM);
         if (matches.size() == 0) {
             return null;
         } else if (matches.size() == 1) {
@@ -2785,7 +2863,7 @@
 
     private List<String> resolveAllBrowserApps(int userId) {
         // Resolve the canonical browser intent and check that the handleAllWebDataURI boolean is set
-        List<ResolveInfo> list = queryIntentActivities(sBrowserIntent, null,
+        List<ResolveInfo> list = queryIntentActivitiesInternal(sBrowserIntent, null,
                 PackageManager.MATCH_ALL, userId);
 
         final int count = list.size();
@@ -2805,7 +2883,7 @@
     }
 
     private boolean packageIsBrowser(String packageName, int userId) {
-        List<ResolveInfo> list = queryIntentActivities(sBrowserIntent, null,
+        List<ResolveInfo> list = queryIntentActivitiesInternal(sBrowserIntent, null,
                 PackageManager.MATCH_ALL, userId);
         final int N = list.size();
         for (int i = 0; i < N; i++) {
@@ -2870,12 +2948,15 @@
         return cur;
     }
 
-    PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
+    private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        final PackageSetting ps = (PackageSetting) p.mExtras;
         if (ps == null) {
             return null;
         }
+        final PackageParser.Package p = ps.pkg;
+        if (p == null) {
+            return null;
+        }
 
         final PermissionsState permissionsState = ps.getPermissionsState();
 
@@ -2897,6 +2978,11 @@
                 throw new SecurityException("Package " + packageName + " was not found!");
             }
 
+            if (!ps.getInstalled(userId)) {
+                throw new SecurityException(
+                        "Package " + packageName + " was not installed for user " + userId + "!");
+            }
+
             if (mSafeMode && !ps.isSystem()) {
                 throw new SecurityException("Package " + packageName + " not a system app!");
             }
@@ -2905,8 +2991,8 @@
                 throw new SecurityException("Package " + packageName + " is currently frozen!");
             }
 
-            if (!userKeyUnlocked && !(ps.pkg.applicationInfo.isEncryptionAware()
-                    || ps.pkg.applicationInfo.isPartiallyEncryptionAware())) {
+            if (!userKeyUnlocked && !(ps.pkg.applicationInfo.isDirectBootAware()
+                    || ps.pkg.applicationInfo.isPartiallyDirectBootAware())) {
                 throw new SecurityException("Package " + packageName + " is not encryption aware!");
             }
         }
@@ -2915,7 +3001,8 @@
     @Override
     public boolean isPackageAvailable(String packageName, int userId) {
         if (!sUserManager.exists(userId)) return false;
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "is package available");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "is package available");
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
             if (p != null) {
@@ -2935,17 +3022,32 @@
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get package info");
         // reader
         synchronized (mPackages) {
-            PackageParser.Package p = mPackages.get(packageName);
+            final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
+            PackageParser.Package p = null;
+            if (matchFactoryOnly) {
+                final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
+                if (ps != null) {
+                    return generatePackageInfo(ps, flags, userId);
+                }
+            }
+            if (p == null) {
+                p = mPackages.get(packageName);
+                if (matchFactoryOnly && !isSystemApp(p)) {
+                    return null;
+                }
+            }
             if (DEBUG_PACKAGE_INFO)
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
-                return generatePackageInfo(p, flags, userId);
+                return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
             }
-            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
-                return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
+            if (!matchFactoryOnly && (flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                return generatePackageInfo(ps, flags, userId);
             }
         }
         return null;
@@ -2981,7 +3083,8 @@
     public int getPackageUid(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return -1;
         flags = updateFlagsForPackage(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get package uid");
 
         // reader
         synchronized (mPackages) {
@@ -3004,7 +3107,8 @@
     public int[] getPackageGids(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */,
                 "getPackageGids");
 
         // reader
@@ -3050,9 +3154,15 @@
     }
 
     @Override
-    public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
+    public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String group,
+            int flags) {
         // reader
         synchronized (mPackages) {
+            if (group != null && !mPermissionGroups.containsKey(group)) {
+                // This is thrown as NameNotFoundException
+                return null;
+            }
+
             ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
             for (BasePermission p : mSettings.mPermissions.values()) {
                 if (group == null) {
@@ -3065,11 +3175,7 @@
                     }
                 }
             }
-
-            if (out.size() > 0) {
-                return out;
-            }
-            return mPermissionGroups.containsKey(group) ? out : null;
+            return new ParceledListSlice<>(out);
         }
     }
 
@@ -3083,7 +3189,7 @@
     }
 
     @Override
-    public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+    public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
         // reader
         synchronized (mPackages) {
             final int N = mPermissionGroups.size();
@@ -3092,7 +3198,7 @@
             for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
                 out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
             }
-            return out;
+            return new ParceledListSlice<>(out);
         }
     }
 
@@ -3102,8 +3208,7 @@
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (ps.pkg == null) {
-                PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName,
-                        flags, userId);
+                final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
                 if (pInfo != null) {
                     return pInfo.applicationInfo;
                 }
@@ -3115,36 +3220,12 @@
         return null;
     }
 
-    private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags,
-            int userId) {
-        if (!sUserManager.exists(userId)) return null;
-        PackageSetting ps = mSettings.mPackages.get(packageName);
-        if (ps != null) {
-            PackageParser.Package pkg = ps.pkg;
-            if (pkg == null) {
-                if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
-                    return null;
-                }
-                // Only data remains, so we aren't worried about code paths
-                pkg = new PackageParser.Package(packageName);
-                pkg.applicationInfo.packageName = packageName;
-                pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
-                pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
-                pkg.applicationInfo.uid = ps.appId;
-                pkg.applicationInfo.initForUser(userId);
-                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
-            }
-            return generatePackageInfo(pkg, flags, userId);
-        }
-        return null;
-    }
-
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForApplication(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get application info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get application info");
         // writer
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -3243,7 +3324,7 @@
      * Return if the user key is currently unlocked.
      */
     private boolean isUserKeyUnlocked(int userId) {
-        if (StorageManager.isFileBasedEncryptionEnabled()) {
+        if (StorageManager.isFileEncryptedNativeOrEmulated()) {
             final IMountService mount = IMountService.Stub
                     .asInterface(ServiceManager.getService("mount"));
             if (mount == null) {
@@ -3267,17 +3348,17 @@
      * Update given flags based on encryption status of current user.
      */
     private int updateFlags(int flags, int userId) {
-        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
-                | PackageManager.MATCH_ENCRYPTION_AWARE)) != 0) {
+        if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                | PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
             // Caller expressed an explicit opinion about what encryption
             // aware/unaware components they want to see, so fall through and
             // give them what they want
         } else {
             // Caller expressed no opinion, so match based on user state
             if (isUserKeyUnlocked(userId)) {
-                flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+                flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
             } else {
-                flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
+                flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE;
             }
         }
         return flags;
@@ -3292,8 +3373,8 @@
                 | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS)) != 0) {
             // Caller is asking for component details, so they'd better be
             // asking for specific encryption matching behavior, or be triaged
-            if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
-                    | PackageManager.MATCH_ENCRYPTION_AWARE
+            if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
                     | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
                 triaged = false;
             }
@@ -3330,8 +3411,8 @@
         boolean triaged = true;
         // Caller is asking for component details, so they'd better be
         // asking for specific encryption matching behavior, or be triaged
-        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
-                | PackageManager.MATCH_ENCRYPTION_AWARE
+        if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                | PackageManager.MATCH_DIRECT_BOOT_AWARE
                 | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
             triaged = false;
         }
@@ -3359,7 +3440,8 @@
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get activity info");
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
@@ -3404,7 +3486,8 @@
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get receiver info");
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3423,7 +3506,8 @@
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get service info");
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3442,7 +3526,8 @@
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get provider info");
         synchronized (mPackages) {
             PackageParser.Provider p = mProviders.mProviders.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3485,22 +3570,17 @@
     }
 
     @Override
-    public FeatureInfo[] getSystemAvailableFeatures() {
-        Collection<FeatureInfo> featSet;
+    public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
         synchronized (mPackages) {
-            featSet = mAvailableFeatures.values();
-            int size = featSet.size();
-            if (size > 0) {
-                FeatureInfo[] features = new FeatureInfo[size+1];
-                featSet.toArray(features);
-                FeatureInfo fi = new FeatureInfo();
-                fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
-                        FeatureInfo.GL_ES_VERSION_UNDEFINED);
-                features[size] = fi;
-                return features;
-            }
+            final ArrayList<FeatureInfo> res = new ArrayList<>(mAvailableFeatures.values());
+
+            final FeatureInfo fi = new FeatureInfo();
+            fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
+                    FeatureInfo.GL_ES_VERSION_UNDEFINED);
+            res.add(fi);
+
+            return new ParceledListSlice<>(res);
         }
-        return null;
     }
 
     @Override
@@ -3834,7 +3914,8 @@
                 android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
                 "grantRuntimePermission");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "grantRuntimePermission");
 
         final int uid;
@@ -3945,7 +4026,8 @@
                 android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
                 "revokeRuntimePermission");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "revokeRuntimePermission");
 
         final int appId;
@@ -4049,7 +4131,8 @@
 
         enforceGrantRevokeRuntimePermissionPermissions("getPermissionFlags");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getPermissionFlags");
 
         synchronized (mPackages) {
@@ -4082,7 +4165,8 @@
 
         enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "updatePermissionFlags");
 
         // Only the system can change these flags and nothing else.
@@ -4139,7 +4223,8 @@
 
         enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlagsForAllApps");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "updatePermissionFlagsForAllApps");
 
         // Only the system can change system fixed flags.
@@ -4245,7 +4330,8 @@
                 // TODO: remove these terrible hacks
                 if (actionName.startsWith("android.net.netmon.lingerExpired")
                         || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
-                        || actionName.startsWith("com.android.internal.telephony.data-reconnect")) {
+                        || actionName.startsWith("com.android.internal.telephony.data-reconnect")
+                        || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
                     return true;
                 }
             }
@@ -4450,6 +4536,13 @@
     }
 
     @Override
+    public List<String> getAllPackages() {
+        synchronized (mPackages) {
+            return new ArrayList<String>(mPackages.keySet());
+        }
+    }
+
+    @Override
     public String[] getPackagesForUid(int uid) {
         uid = UserHandle.getAppId(uid);
         // reader
@@ -4572,8 +4665,10 @@
             int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(flags, userId, intent);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
-        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "resolve intent");
+        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
+                userId);
         final ResolveInfo bestChoice =
                 chooseBestActivity(intent, resolvedType, flags, query, userId);
 
@@ -4605,7 +4700,8 @@
             filter.dump(new PrintStreamPrinter(System.out), "    ");
         }
         intent.setComponent(null);
-        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
+                userId);
         // Find any earlier preferred or last chosen entries and nuke them
         findPreferredActivity(intent, resolvedType,
                 flags, query, 0, false, true, false, userId);
@@ -4618,7 +4714,8 @@
     public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
         final int userId = UserHandle.getCallingUserId();
         if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
-        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
+                userId);
         return findPreferredActivity(intent, resolvedType, flags, query, 0,
                 false, false, false, userId);
     }
@@ -4900,8 +4997,10 @@
                             if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
                             continue;
                         }
-                        final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent,
-                                flags | MATCH_DISABLED_COMPONENTS, userId);
+                        final ActivityInfo ai = getActivityInfo(
+                                pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
+                                        | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                                userId);
                         if (DEBUG_PREFERRED || debug) {
                             Slog.v(TAG, "Found preferred activity:");
                             if (ai != null) {
@@ -5001,8 +5100,9 @@
             // cross-profile app linking works only towards the parent.
             final UserInfo parent = getProfileParent(sourceUserId);
             synchronized(mPackages) {
+                int flags = updateFlagsForResolve(0, parent.id, intent);
                 CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
-                        intent, resolvedType, 0, sourceUserId, parent.id);
+                        intent, resolvedType, flags, sourceUserId, parent.id);
                 return xpDomainInfo != null;
             }
         }
@@ -5028,11 +5128,19 @@
     }
 
     @Override
-    public List<ResolveInfo> queryIntentActivities(Intent intent,
+    public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
+            String resolvedType, int flags, int userId) {
+        return new ParceledListSlice<>(
+                queryIntentActivitiesInternal(intent, resolvedType, flags, userId));
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForResolve(flags, userId, intent);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */,
+                "query intent activities");
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5517,16 +5625,24 @@
     }
 
     @Override
-    public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
+    public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
+            Intent[] specifics, String[] specificTypes, Intent intent,
+            String resolvedType, int flags, int userId) {
+        return new ParceledListSlice<>(queryIntentActivityOptionsInternal(caller, specifics,
+                specificTypes, intent, resolvedType, flags, userId));
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForResolve(flags, userId, intent);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
-                false, "query intent activity options");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */,
+                "query intent activity options");
         final String resultsAction = intent.getAction();
 
-        List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
+        final List<ResolveInfo> results = queryIntentActivitiesInternal(intent, resolvedType, flags
                 | PackageManager.GET_RESOLVED_FILTER, userId);
 
         if (DEBUG_INTENT_MATCHING) {
@@ -5691,8 +5807,14 @@
     }
 
     @Override
-    public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
-            int userId) {
+    public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
+            String resolvedType, int flags, int userId) {
+        return new ParceledListSlice<>(
+                queryIntentReceiversInternal(intent, resolvedType, flags, userId));
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
+            String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
@@ -5724,7 +5846,7 @@
                 return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
                         userId);
             }
-            return null;
+            return Collections.emptyList();
         }
     }
 
@@ -5732,7 +5854,7 @@
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(flags, userId, intent);
-        List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
+        List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
                 // If there is more than one service with the same priority,
@@ -5744,8 +5866,14 @@
     }
 
     @Override
-    public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
-            int userId) {
+    public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
+            String resolvedType, int flags, int userId) {
+        return new ParceledListSlice<>(
+                queryIntentServicesInternal(intent, resolvedType, flags, userId));
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
+            String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
@@ -5777,12 +5905,18 @@
                 return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services,
                         userId);
             }
-            return null;
+            return Collections.emptyList();
         }
     }
 
     @Override
-    public List<ResolveInfo> queryIntentContentProviders(
+    public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
+            String resolvedType, int flags, int userId) {
+        return new ParceledListSlice<>(
+                queryIntentContentProvidersInternal(intent, resolvedType, flags, userId));
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
             Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForResolve(flags, userId, intent);
@@ -5815,7 +5949,7 @@
                 return mProviders.queryIntentForPackage(
                         intent, resolvedType, flags, pkg.providers, userId);
             }
-            return null;
+            return Collections.emptyList();
         }
     }
 
@@ -5824,7 +5958,9 @@
         if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "get installed packages");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "get installed packages");
 
         // writer
         synchronized (mPackages) {
@@ -5832,11 +5968,11 @@
             if (listUninstalled) {
                 list = new ArrayList<PackageInfo>(mSettings.mPackages.size());
                 for (PackageSetting ps : mSettings.mPackages.values()) {
-                    PackageInfo pi;
+                    final PackageInfo pi;
                     if (ps.pkg != null) {
-                        pi = generatePackageInfo(ps.pkg, flags, userId);
+                        pi = generatePackageInfo(ps, flags, userId);
                     } else {
-                        pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+                        pi = generatePackageInfo(ps, flags, userId);
                     }
                     if (pi != null) {
                         list.add(pi);
@@ -5845,7 +5981,8 @@
             } else {
                 list = new ArrayList<PackageInfo>(mPackages.size());
                 for (PackageParser.Package p : mPackages.values()) {
-                    PackageInfo pi = generatePackageInfo(p, flags, userId);
+                    final PackageInfo pi =
+                            generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
                     if (pi != null) {
                         list.add(pi);
                     }
@@ -5872,11 +6009,11 @@
         if (numMatch == 0) {
             return;
         }
-        PackageInfo pi;
+        final PackageInfo pi;
         if (ps.pkg != null) {
-            pi = generatePackageInfo(ps.pkg, flags, userId);
+            pi = generatePackageInfo(ps, flags, userId);
         } else {
-            pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+            pi = generatePackageInfo(ps, flags, userId);
         }
         // The above might return null in cases of uninstalled apps or install-state
         // skew across users/profiles.
@@ -5976,7 +6113,8 @@
 
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
                 "getEphemeralApplications");
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getEphemeralApplications");
         synchronized (mPackages) {
             List<EphemeralApplicationInfo> ephemeralApps = mEphemeralApplicationRegistry
@@ -5990,7 +6128,8 @@
 
     @Override
     public boolean isEphemeralApplication(String packageName, int userId) {
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "isEphemeral");
         if (DISABLE_EPHEMERAL_APPS) {
             return false;
@@ -6014,7 +6153,8 @@
             return null;
         }
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getCookie");
         if (!isCallerSameApp(packageName)) {
             return null;
@@ -6031,7 +6171,8 @@
             return true;
         }
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "setCookie");
         if (!isCallerSameApp(packageName)) {
             return false;
@@ -6050,7 +6191,8 @@
 
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
                 "getEphemeralApplicationIcon");
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getEphemeralApplicationIcon");
         synchronized (mPackages) {
             return mEphemeralApplicationRegistry.getEphemeralApplicationIconLPw(
@@ -6064,7 +6206,12 @@
                 && UserHandle.getAppId(Binder.getCallingUid()) == pkg.applicationInfo.uid;
     }
 
-    public List<ApplicationInfo> getPersistentApplications(int flags) {
+    @Override
+    public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
+        return new ParceledListSlice<>(getPersistentApplicationsInternal(flags));
+    }
+
+    private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
         final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
 
         // reader
@@ -6073,9 +6220,16 @@
             final int userId = UserHandle.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Package p = i.next();
-                if (p.applicationInfo != null
-                        && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
-                        && (!mSafeMode || isSystemApp(p))) {
+                if (p.applicationInfo == null) continue;
+
+                final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
+                        && !p.applicationInfo.isDirectBootAware();
+                final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
+                        && p.applicationInfo.isDirectBootAware();
+
+                if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+                        && (!mSafeMode || isSystemApp(p))
+                        && (matchesUnaware || matchesAware)) {
                     PackageSetting ps = mSettings.mPackages.get(p.packageName);
                     if (ps != null) {
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
@@ -6139,11 +6293,11 @@
     }
 
     @Override
-    public ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
+    public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
             int uid, int flags) {
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForComponent(flags, userId, processName);
 
         ArrayList<ProviderInfo> finalList = null;
@@ -6175,7 +6329,7 @@
             return new ParceledListSlice<ProviderInfo>(finalList);
         }
 
-        return null;
+        return ParceledListSlice.emptyList();
     }
 
     @Override
@@ -6188,10 +6342,14 @@
     }
 
     @Override
-    public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+    public @NonNull ParceledListSlice<InstrumentationInfo> queryInstrumentation(
+            String targetPackage, int flags) {
+        return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
+    }
+
+    private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
             int flags) {
-        ArrayList<InstrumentationInfo> finalList =
-            new ArrayList<InstrumentationInfo>();
+        ArrayList<InstrumentationInfo> finalList = new ArrayList<InstrumentationInfo>();
 
         // reader
         synchronized (mPackages) {
@@ -6824,22 +6982,57 @@
     }
 
     @Override
-    public void extractPackagesIfNeeded() {
-        enforceSystemOrRoot("Only the system can request package extraction");
+    public void updatePackagesIfNeeded() {
+        enforceSystemOrRoot("Only the system can request package update");
 
-        // Extract pacakges only if profile-guided compilation is enabled because
-        // otherwise BackgroundDexOptService will not dexopt them later.
-        if (mUseJitProfiles) {
-            List<PackageParser.Package> pkgs;
-            synchronized (mPackages) {
-                pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
+        // We need to re-extract after an OTA.
+        boolean causeUpgrade = isUpgrade();
+
+        // First boot or factory reset.
+        // Note: we also handle devices that are upgrading to N right now as if it is their
+        //       first boot, as they do not have profile data.
+        boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;
+
+        // We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
+        boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
+
+        if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
+            return;
+        }
+
+        List<PackageParser.Package> pkgs;
+        synchronized (mPackages) {
+            pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
+        }
+
+        int curr = 0;
+        int total = pkgs.size();
+        for (PackageParser.Package pkg : pkgs) {
+            curr++;
+
+            if (DEBUG_DEXOPT) {
+                Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
             }
-            for (PackageParser.Package pkg : pkgs) {
-                if (PackageDexOptimizer.canOptimizePackage(pkg)) {
-                    performDexOpt(pkg.packageName, null /* instructionSet */,
-                             false /* useProfiles */, true /* extractOnly */, false /* force */);
+
+            if (!isFirstBoot()) {
+                try {
+                    ActivityManagerNative.getDefault().showBootMessage(
+                            mContext.getResources().getString(R.string.android_upgrading_apk,
+                                    curr, total), true);
+                } catch (RemoteException e) {
                 }
             }
+
+            if (PackageDexOptimizer.canOptimizePackage(pkg)) {
+                // If the cache was pruned, any compiled odex files will likely be out of date
+                // and would have to be patched (would be SELF_PATCHOAT, which is deprecated).
+                // Instead, force the extraction in this case.
+                performDexOpt(pkg.packageName,
+                        null /* instructionSet */,
+                        false /* checkProfiles */,
+                        causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
+                        false /* force */);
+            }
         }
     }
 
@@ -6857,29 +7050,37 @@
     // TODO: this is not used nor needed. Delete it.
     @Override
     public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
-        return performDexOptTraced(packageName, instructionSet, false /* useProfiles */,
-                false /* extractOnly */, false /* force */);
+        return performDexOptTraced(packageName, instructionSet, false /* checkProfiles */,
+                getFullCompilerFilter(), false /* force */);
     }
 
     @Override
-    public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
-            boolean extractOnly, boolean force) {
-        return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly, force);
+    public boolean performDexOpt(String packageName, String instructionSet,
+            boolean checkProfiles, int compileReason, boolean force) {
+        return performDexOptTraced(packageName, instructionSet, checkProfiles,
+                getCompilerFilterForReason(compileReason), force);
+    }
+
+    @Override
+    public boolean performDexOptMode(String packageName, String instructionSet,
+            boolean checkProfiles, String targetCompilerFilter, boolean force) {
+        return performDexOptTraced(packageName, instructionSet, checkProfiles,
+                targetCompilerFilter, force);
     }
 
     private boolean performDexOptTraced(String packageName, String instructionSet,
-                boolean useProfiles, boolean extractOnly, boolean force) {
+                boolean checkProfiles, String targetCompilerFilter, boolean force) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
         try {
-            return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly,
-                    force);
+            return performDexOptInternal(packageName, instructionSet, checkProfiles,
+                    targetCompilerFilter, force);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
     private boolean performDexOptInternal(String packageName, String instructionSet,
-                boolean useProfiles, boolean extractOnly, boolean force) {
+                boolean checkProfiles, String targetCompilerFilter, boolean force) {
         PackageParser.Package p;
         final String targetInstructionSet;
         synchronized (mPackages) {
@@ -6891,17 +7092,13 @@
 
             targetInstructionSet = instructionSet != null ? instructionSet :
                     getPrimaryInstructionSet(p.applicationInfo);
-            if (!force && !useProfiles && p.mDexOptPerformed.contains(targetInstructionSet)) {
-                // Skip only if we do not use profiles since they might trigger a recompilation.
-                return false;
-            }
         }
         long callingId = Binder.clearCallingIdentity();
         try {
             synchronized (mInstallLock) {
                 final String[] instructionSets = new String[] { targetInstructionSet };
                 int result = performDexOptInternalWithDependenciesLI(p, instructionSets,
-                        useProfiles, extractOnly, force);
+                        checkProfiles, targetCompilerFilter, force);
                 return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
             }
         } finally {
@@ -6922,7 +7119,8 @@
     }
 
     private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
-            String instructionSets[], boolean useProfiles, boolean extractOnly, boolean force) {
+            String instructionSets[], boolean checkProfiles, String targetCompilerFilter,
+            boolean force) {
         // Select the dex optimizer based on the force parameter.
         // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
         //       allocate an object here.
@@ -6936,13 +7134,13 @@
         if (!deps.isEmpty()) {
             for (PackageParser.Package depPackage : deps) {
                 // TODO: Analyze and investigate if we (should) profile libraries.
-                // Currently this will do a full compilation of the library.
-                pdo.performDexOpt(depPackage, instructionSets, false /* useProfiles */,
-                        false /* extractOnly */);
+                // Currently this will do a full compilation of the library by default.
+                pdo.performDexOpt(depPackage, instructionSets, false /* checkProfiles */,
+                        getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY));
             }
         }
 
-        return pdo.performDexOpt(p, instructionSets, useProfiles, extractOnly);
+        return pdo.performDexOpt(p, instructionSets, checkProfiles, targetCompilerFilter);
     }
 
     Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
@@ -7020,7 +7218,8 @@
             // Whoever is calling forceDexOpt wants a fully compiled package.
             // Don't use profiles since that may cause compilation to be skipped.
             final int res = performDexOptInternalWithDependenciesLI(pkg, instructionSets,
-                    false /* useProfiles */, false /* extractOnly */, true /* force */);
+                    false /* checkProfiles */, getCompilerFilterForReason(REASON_FORCED_DEXOPT),
+                    true /* force */);
 
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -7090,6 +7289,30 @@
         }
     }
 
+    private void deleteProfilesLI(String packageName, boolean destroy) {
+        final PackageParser.Package pkg;
+        synchronized (mPackages) {
+            pkg = mPackages.get(packageName);
+        }
+        if (pkg == null) {
+            Slog.w(TAG, "Failed to delete profiles. No package: " + packageName);
+            return;
+        }
+        deleteProfilesLI(pkg, destroy);
+    }
+
+    private void deleteProfilesLI(PackageParser.Package pkg, boolean destroy) {
+        try {
+            if (destroy) {
+                mInstaller.destroyAppProfiles(pkg.packageName);
+            } else {
+                mInstaller.clearAppProfiles(pkg.packageName);
+            }
+        } catch (InstallerException ex) {
+            Log.e(TAG, "Could not delete profiles for package " + pkg.packageName);
+        }
+    }
+
     private void deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
         final PackageParser.Package pkg;
         synchronized (mPackages) {
@@ -7875,13 +8098,17 @@
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
         // version of the application while the new one gets installed.
-        if ((scanFlags & SCAN_REPLACING) != 0) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
+        final boolean isReplacing = (scanFlags & SCAN_REPLACING) != 0;
+        final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
+        if (killApp) {
+            if (isReplacing) {
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
 
-            killApplication(pkg.applicationInfo.packageName,
-                        pkg.applicationInfo.uid, "replace pkg");
+                killApplication(pkg.applicationInfo.packageName,
+                            pkg.applicationInfo.uid, "replace pkg");
 
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
         }
 
         // Also need to kill any apps that are dependent on the library.
@@ -8203,8 +8430,8 @@
                 a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
                 a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
                 a.info.dataDir = pkg.applicationInfo.dataDir;
-                a.info.deviceEncryptedDataDir = pkg.applicationInfo.deviceEncryptedDataDir;
-                a.info.credentialEncryptedDataDir = pkg.applicationInfo.credentialEncryptedDataDir;
+                a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
+                a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
 
                 // TODO: Update instrumentation.nativeLibraryDir as well ? Does it
                 // need other information about the application, like the ABI and what not ?
@@ -9540,6 +9767,12 @@
                 // is granted only if it was already granted.
                 allowed = origPermissions.hasInstallPermission(perm);
             }
+            if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
+                    && pkg.packageName.equals(mSetupWizardPackage)) {
+                // If this permission is to be granted to the system setup wizard and
+                // this app is a setup wizard, then it gets the permission.
+                allowed = true;
+            }
         }
         return allowed;
     }
@@ -9597,8 +9830,314 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
+        /**
+         * Finds a privileged activity that matches the specified activity names.
+         */
+        private PackageParser.Activity findMatchingActivity(
+                List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
+            for (PackageParser.Activity sysActivity : activityList) {
+                if (sysActivity.info.name.equals(activityInfo.name)) {
+                    return sysActivity;
+                }
+                if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+                    return sysActivity;
+                }
+                if (sysActivity.info.targetActivity != null) {
+                    if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+                        return sysActivity;
+                    }
+                    if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+                        return sysActivity;
+                    }
+                }
+            }
+            return null;
+        }
+
+        public class IterGenerator<E> {
+            public Iterator<E> generate(ActivityIntentInfo info) {
+                return null;
+            }
+        }
+
+        public class ActionIterGenerator extends IterGenerator<String> {
+            @Override
+            public Iterator<String> generate(ActivityIntentInfo info) {
+                return info.actionsIterator();
+            }
+        }
+
+        public class CategoriesIterGenerator extends IterGenerator<String> {
+            @Override
+            public Iterator<String> generate(ActivityIntentInfo info) {
+                return info.categoriesIterator();
+            }
+        }
+
+        public class SchemesIterGenerator extends IterGenerator<String> {
+            @Override
+            public Iterator<String> generate(ActivityIntentInfo info) {
+                return info.schemesIterator();
+            }
+        }
+
+        public class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
+            @Override
+            public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
+                return info.authoritiesIterator();
+            }
+        }
+
+        /**
+         * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
+         * MODIFIED. Do not pass in a list that should not be changed.
+         */
+        private <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
+                IterGenerator<T> generator, Iterator<T> searchIterator) {
+            // loop through the set of actions; every one must be found in the intent filter
+            while (searchIterator.hasNext()) {
+                // we must have at least one filter in the list to consider a match
+                if (intentList.size() == 0) {
+                    break;
+                }
+
+                final T searchAction = searchIterator.next();
+
+                // loop through the set of intent filters
+                final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
+                while (intentIter.hasNext()) {
+                    final ActivityIntentInfo intentInfo = intentIter.next();
+                    boolean selectionFound = false;
+
+                    // loop through the intent filter's selection criteria; at least one
+                    // of them must match the searched criteria
+                    final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
+                    while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
+                        final T intentSelection = intentSelectionIter.next();
+                        if (intentSelection != null && intentSelection.equals(searchAction)) {
+                            selectionFound = true;
+                            break;
+                        }
+                    }
+
+                    // the selection criteria wasn't found in this filter's set; this filter
+                    // is not a potential match
+                    if (!selectionFound) {
+                        intentIter.remove();
+                    }
+                }
+            }
+        }
+
+        private boolean isProtectedAction(ActivityIntentInfo filter) {
+            final Iterator<String> actionsIter = filter.actionsIterator();
+            while (actionsIter != null && actionsIter.hasNext()) {
+                final String filterAction = actionsIter.next();
+                if (PROTECTED_ACTIONS.contains(filterAction)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Adjusts the priority of the given intent filter according to policy.
+         * <p>
+         * <ul>
+         * <li>The priority for non privileged applications is capped to '0'</li>
+         * <li>The priority for protected actions on privileged applications is capped to '0'</li>
+         * <li>The priority for unbundled updates to privileged applications is capped to the
+         *      priority defined on the system partition</li>
+         * </ul>
+         * <p>
+         * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
+         * allowed to obtain any priority on any action.
+         */
+        private void adjustPriority(
+                List<PackageParser.Activity> systemActivities, ActivityIntentInfo intent) {
+            // nothing to do; priority is fine as-is
+            if (intent.getPriority() <= 0) {
+                return;
+            }
+
+            final ActivityInfo activityInfo = intent.activity.info;
+            final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+
+            final boolean privilegedApp =
+                    ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+            if (!privilegedApp) {
+                // non-privileged applications can never define a priority >0
+                Slog.w(TAG, "Non-privileged app; cap priority to 0;"
+                        + " package: " + applicationInfo.packageName
+                        + " activity: " + intent.activity.className
+                        + " origPrio: " + intent.getPriority());
+                intent.setPriority(0);
+                return;
+            }
+
+            if (systemActivities == null) {
+                // the system package is not disabled; we're parsing the system partition
+                if (isProtectedAction(intent)) {
+                    if (mDeferProtectedFilters) {
+                        // We can't deal with these just yet. No component should ever obtain a
+                        // >0 priority for a protected actions, with ONE exception -- the setup
+                        // wizard. The setup wizard, however, cannot be known until we're able to
+                        // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
+                        // until all intent filters have been processed. Chicken, meet egg.
+                        // Let the filter temporarily have a high priority and rectify the
+                        // priorities after all system packages have been scanned.
+                        mProtectedFilters.add(intent);
+                        if (DEBUG_FILTERS) {
+                            Slog.i(TAG, "Protected action; save for later;"
+                                    + " package: " + applicationInfo.packageName
+                                    + " activity: " + intent.activity.className
+                                    + " origPrio: " + intent.getPriority());
+                        }
+                        return;
+                    } else {
+                        if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+                            Slog.i(TAG, "No setup wizard;"
+                                + " All protected intents capped to priority 0");
+                        }
+                        if (intent.activity.info.packageName.equals(mSetupWizardPackage)) {
+                            if (DEBUG_FILTERS) {
+                                Slog.i(TAG, "Found setup wizard;"
+                                    + " allow priority " + intent.getPriority() + ";"
+                                    + " package: " + intent.activity.info.packageName
+                                    + " activity: " + intent.activity.className
+                                    + " priority: " + intent.getPriority());
+                            }
+                            // setup wizard gets whatever it wants
+                            return;
+                        }
+                        Slog.w(TAG, "Protected action; cap priority to 0;"
+                                + " package: " + intent.activity.info.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                        intent.setPriority(0);
+                        return;
+                    }
+                }
+                // privileged apps on the system image get whatever priority they request
+                return;
+            }
+
+            // privileged app unbundled update ... try to find the same activity
+            final PackageParser.Activity foundActivity =
+                    findMatchingActivity(systemActivities, activityInfo);
+            if (foundActivity == null) {
+                // this is a new activity; it cannot obtain >0 priority
+                if (DEBUG_FILTERS) {
+                    Slog.i(TAG, "New activity; cap priority to 0;"
+                            + " package: " + applicationInfo.packageName
+                            + " activity: " + intent.activity.className
+                            + " origPrio: " + intent.getPriority());
+                }
+                intent.setPriority(0);
+                return;
+            }
+
+            // found activity, now check for filter equivalence
+
+            // a shallow copy is enough; we modify the list, not its contents
+            final List<ActivityIntentInfo> intentListCopy =
+                    new ArrayList<>(foundActivity.intents);
+            final List<ActivityIntentInfo> foundFilters = findFilters(intent);
+
+            // find matching action subsets
+            final Iterator<String> actionsIterator = intent.actionsIterator();
+            if (actionsIterator != null) {
+                getIntentListSubset(
+                        intentListCopy, new ActionIterGenerator(), actionsIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched action; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // find matching category subsets
+            final Iterator<String> categoriesIterator = intent.categoriesIterator();
+            if (categoriesIterator != null) {
+                getIntentListSubset(intentListCopy, new CategoriesIterGenerator(),
+                        categoriesIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched category; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // find matching schemes subsets
+            final Iterator<String> schemesIterator = intent.schemesIterator();
+            if (schemesIterator != null) {
+                getIntentListSubset(intentListCopy, new SchemesIterGenerator(),
+                        schemesIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // find matching authorities subsets
+            final Iterator<IntentFilter.AuthorityEntry>
+                    authoritiesIterator = intent.authoritiesIterator();
+            if (authoritiesIterator != null) {
+                getIntentListSubset(intentListCopy,
+                        new AuthoritiesIterGenerator(),
+                        authoritiesIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched authority; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // we found matching filter(s); app gets the max priority of all intents
+            int cappedPriority = 0;
+            for (int i = intentListCopy.size() - 1; i >= 0; --i) {
+                cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority());
+            }
+            if (intent.getPriority() > cappedPriority) {
+                if (DEBUG_FILTERS) {
+                    Slog.i(TAG, "Found matching filter(s);"
+                            + " cap priority to " + cappedPriority + ";"
+                            + " package: " + applicationInfo.packageName
+                            + " activity: " + intent.activity.className
+                            + " origPrio: " + intent.getPriority());
+                }
+                intent.setPriority(cappedPriority);
+                return;
+            }
+            // all this for nothing; the requested priority was <= what was on the system
+        }
+
         public final void addActivity(PackageParser.Activity a, String type) {
-            final boolean systemApp = a.info.applicationInfo.isSystemApp();
             mActivities.put(a.getComponentName(), a);
             if (DEBUG_SHOW_INFO)
                 Log.v(
@@ -9609,10 +10148,12 @@
             final int NI = a.intents.size();
             for (int j=0; j<NI; j++) {
                 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
-                if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
-                    intent.setPriority(0);
-                    Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
-                            + a.className + " with priority > 0, forcing to 0");
+                if ("activity".equals(type)) {
+                    final PackageSetting ps =
+                            mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName);
+                    final List<PackageParser.Activity> systemActivities =
+                            ps != null && ps.pkg != null ? ps.pkg.activities : null;
+                    adjustPriority(systemActivities, intent);
                 }
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
@@ -9762,18 +10303,6 @@
             out.println();
         }
 
-//        List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
-//            final Iterator<ResolveInfo> i = resolveInfoList.iterator();
-//            final List<ResolveInfo> retList = Lists.newArrayList();
-//            while (i.hasNext()) {
-//                final ResolveInfo resolveInfo = i.next();
-//                if (isEnabledLP(resolveInfo.activityInfo)) {
-//                    retList.add(resolveInfo);
-//                }
-//            }
-//            return retList;
-//        }
-
         // Keys are String (activity class name), values are Activity.
         private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
                 = new ArrayMap<ComponentName, PackageParser.Activity>();
@@ -10361,10 +10890,10 @@
 
     void startCleaningPackages() {
         // reader
+        if (!isExternalMediaAvailable()) {
+            return;
+        }
         synchronized (mPackages) {
-            if (!isExternalMediaAvailable()) {
-                return;
-            }
             if (mSettings.mPackagesToBeCleaned.isEmpty()) {
                 return;
             }
@@ -10382,21 +10911,13 @@
     }
 
     @Override
-    public void installPackage(String originPath, IPackageInstallObserver2 observer,
-            int installFlags, String installerPackageName, VerificationParams verificationParams,
-            String packageAbiOverride) {
-        installPackageAsUser(originPath, observer, installFlags, installerPackageName,
-                verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
-    }
-
-    @Override
     public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
-            int installFlags, String installerPackageName, VerificationParams verificationParams,
-            String packageAbiOverride, int userId) {
+            int installFlags, String installerPackageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
 
         final int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");
+        enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");
 
         if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             try {
@@ -10435,14 +10956,15 @@
                     + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
         }
 
-        verificationParams.setInstallerUid(callingUid);
-
         final File originFile = new File(originPath);
         final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        final InstallParams params = new InstallParams(origin, null, observer, installFlags,
-                installerPackageName, null, verificationParams, user, packageAbiOverride, null);
+        final VerificationInfo verificationInfo = new VerificationInfo(
+                null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
+        final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
+                installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
+                null /*packageAbiOverride*/, null /*grantedPermissions*/);
         params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -10462,10 +10984,9 @@
                 Slog.d(TAG, "Ephemeral install of " + packageName);
             }
         }
-        final VerificationParams verifParams = new VerificationParams(
-                null, sessionParams.originatingUri, sessionParams.referrerUri,
-                sessionParams.originatingUid);
-        verifParams.setInstallerUid(installerUid);
+        final VerificationInfo verificationInfo = new VerificationInfo(
+                sessionParams.originatingUri, sessionParams.referrerUri,
+                sessionParams.originatingUid, installerUid);
 
         final OriginInfo origin;
         if (stagedDir != null) {
@@ -10477,7 +10998,7 @@
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final InstallParams params = new InstallParams(origin, null, observer,
                 sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
-                verifParams, user, sessionParams.abiOverride,
+                verificationInfo, user, sessionParams.abiOverride,
                 sessionParams.grantedRuntimePermissions);
         params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
@@ -10527,7 +11048,8 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, true, true,
+        enforceCrossUserPermission(uid, userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "setApplicationHiddenSetting for user " + userId);
 
         if (hidden && isPackageDeviceAdmin(packageName, userId)) {
@@ -10577,7 +11099,7 @@
         info.removedPackage = packageName;
         info.removedUsers = new int[] {userId};
         info.uid = UserHandle.getUid(userId, pkgSetting.appId);
-        info.sendPackageRemovedBroadcasts();
+        info.sendPackageRemovedBroadcasts(true /*killApp*/);
     }
 
     private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended) {
@@ -10600,8 +11122,9 @@
     @Override
     public boolean getApplicationHiddenSettingAsUser(String packageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true,
-                false, "getApplicationHidden for user " + userId);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "getApplicationHidden for user " + userId);
         PackageSetting pkgSetting;
         long callingId = Binder.clearCallingIdentity();
         try {
@@ -10627,8 +11150,9 @@
                 null);
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, true, true, "installExistingPackage for user "
-                + userId);
+        enforceCrossUserPermission(uid, userId,
+                true /* requireFullPermission */, true /* checkShell */,
+                "installExistingPackage for user " + userId);
         if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
         }
@@ -10647,14 +11171,14 @@
                     pkgSetting.setInstalled(true, userId);
                     pkgSetting.setHidden(false, userId);
                     mSettings.writePackageRestrictionsLPr(userId);
-                    if (pkgSetting.pkg != null) {
-                        prepareAppDataAfterInstall(pkgSetting.pkg);
-                    }
                     installed = true;
                 }
             }
 
             if (installed) {
+                if (pkgSetting.pkg != null) {
+                    prepareAppDataAfterInstall(pkgSetting.pkg);
+                }
                 sendPackageAddedForUser(packageName, pkgSetting, userId);
             }
         } finally {
@@ -10677,7 +11201,8 @@
     public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
             int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "setPackagesSuspended for user " + userId);
 
         if (ArrayUtils.isEmpty(packageNames)) {
@@ -10705,7 +11230,7 @@
                     }
                     appId = pkgSetting.appId;
                     if (pkgSetting.getSuspended(userId) != suspended) {
-                        if (!canSuspendPackageForUser(packageName, userId)) {
+                        if (!canSuspendPackageForUserLocked(packageName, userId)) {
                             unactionedPackages.add(packageName);
                             continue;
                         }
@@ -10735,26 +11260,53 @@
 
     @Override
     public boolean isPackageSuspendedForUser(String packageName, int userId) {
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true,
-                false, "isPackageSuspendedForUser for user " + userId);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "isPackageSuspendedForUser for user " + userId);
         synchronized (mPackages) {
             final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
-            return pkgSetting != null && pkgSetting.getSuspended(userId);
+            if (pkgSetting == null) {
+                throw new IllegalArgumentException("Unknown target package: " + packageName);
+            }
+            return pkgSetting.getSuspended(userId);
         }
     }
 
-    // TODO: investigate and add more restrictions for suspending crucial packages.
-    private boolean canSuspendPackageForUser(String packageName, int userId) {
+    /**
+     * TODO: cache and disallow blocking the active dialer.
+     *
+     * @see also DefaultPermissionGrantPolicy#grantDefaultSystemHandlerPermissions
+     */
+    private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
         if (isPackageDeviceAdmin(packageName, userId)) {
-            Slog.w(TAG, "Not suspending/un-suspending package \"" + packageName
-                    + "\": has active device admin");
+            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+                    + "\": has an active device admin");
             return false;
         }
 
         String activeLauncherPackageName = getActiveLauncherPackageName(userId);
         if (packageName.equals(activeLauncherPackageName)) {
-            Slog.w(TAG, "Not suspending/un-suspending package \"" + packageName
-                    + "\" because it is set as the active launcher");
+            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+                    + "\": contains the active launcher");
+            return false;
+        }
+
+        if (packageName.equals(mRequiredInstallerPackage)) {
+            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+                    + "\": required for package installation");
+            return false;
+        }
+
+        if (packageName.equals(mRequiredVerifierPackage)) {
+            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+                    + "\": required for package verification");
+            return false;
+        }
+
+        final PackageParser.Package pkg = mPackages.get(packageName);
+        if (pkg != null && isPrivilegedApp(pkg)) {
+            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+                    + "\": is a privileged app");
             return false;
         }
 
@@ -11042,21 +11594,22 @@
     }
 
     @Override
-    public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
+    public @NonNull ParceledListSlice<IntentFilterVerificationInfo> getIntentFilterVerifications(
+            String packageName) {
         synchronized (mPackages) {
-            return mSettings.getIntentFilterVerificationsLPr(packageName);
+            return new ParceledListSlice<>(mSettings.getIntentFilterVerificationsLPr(packageName));
         }
     }
 
     @Override
-    public List<IntentFilter> getAllIntentFilters(String packageName) {
+    public @NonNull ParceledListSlice<IntentFilter> getAllIntentFilters(String packageName) {
         if (TextUtils.isEmpty(packageName)) {
-            return Collections.<IntentFilter>emptyList();
+            return ParceledListSlice.emptyList();
         }
         synchronized (mPackages) {
             PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null || pkg.activities == null) {
-                return Collections.<IntentFilter>emptyList();
+                return ParceledListSlice.emptyList();
             }
             final int count = pkg.activities.size();
             ArrayList<IntentFilter> result = new ArrayList<>();
@@ -11066,7 +11619,7 @@
                     result.addAll(activity.intents);
                 }
             }
-            return result;
+            return new ParceledListSlice<>(result);
         }
     }
 
@@ -11101,8 +11654,8 @@
      * @return the current "allow unknown sources" setting
      */
     private int getUnknownSourcesSettings() {
-        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
-                android.provider.Settings.Global.INSTALL_NON_MARKET_APPS,
+        return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
+                android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
                 -1);
     }
 
@@ -11505,6 +12058,30 @@
         }
     }
 
+    static class VerificationInfo {
+        /** A constant used to indicate that a uid value is not present. */
+        public static final int NO_UID = -1;
+
+        /** URI referencing where the package was downloaded from. */
+        final Uri originatingUri;
+
+        /** HTTP referrer URI associated with the originatingURI. */
+        final Uri referrer;
+
+        /** UID of the application that the install request originated from. */
+        final int originatingUid;
+
+        /** UID of application requesting the install */
+        final int installerUid;
+
+        VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
+            this.originatingUri = originatingUri;
+            this.referrer = referrer;
+            this.originatingUid = originatingUid;
+            this.installerUid = installerUid;
+        }
+    }
+
     class InstallParams extends HandlerParams {
         final OriginInfo origin;
         final MoveInfo move;
@@ -11512,15 +12089,15 @@
         int installFlags;
         final String installerPackageName;
         final String volumeUuid;
-        final VerificationParams verificationParams;
         private InstallArgs mArgs;
         private int mRet;
         final String packageAbiOverride;
         final String[] grantedRuntimePermissions;
+        final VerificationInfo verificationInfo;
 
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
-                VerificationParams verificationParams, UserHandle user, String packageAbiOverride,
+                VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
                 String[] grantedPermissions) {
             super(user);
             this.origin = origin;
@@ -11529,7 +12106,7 @@
             this.installFlags = installFlags;
             this.installerPackageName = installerPackageName;
             this.volumeUuid = volumeUuid;
-            this.verificationParams = verificationParams;
+            this.verificationInfo = verificationInfo;
             this.packageAbiOverride = packageAbiOverride;
             this.grantedRuntimePermissions = grantedPermissions;
         }
@@ -11546,20 +12123,56 @@
             boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
             // reader
             synchronized (mPackages) {
-                PackageParser.Package pkg = mPackages.get(packageName);
-                if (pkg != null) {
-                    if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
-                        // Check for downgrading.
-                        if ((installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) {
-                            try {
-                                checkDowngrade(pkg, pkgLite);
-                            } catch (PackageManagerException e) {
-                                Slog.w(TAG, "Downgrade detected: " + e.getMessage());
-                                return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
-                            }
+                // Currently installed package which the new package is attempting to replace or
+                // null if no such package is installed.
+                PackageParser.Package installedPkg = mPackages.get(packageName);
+                // Package which currently owns the data which the new package will own if installed.
+                // If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg
+                // will be null whereas dataOwnerPkg will contain information about the package
+                // which was uninstalled while keeping its data.
+                PackageParser.Package dataOwnerPkg = installedPkg;
+                if (dataOwnerPkg  == null) {
+                    PackageSetting ps = mSettings.mPackages.get(packageName);
+                    if (ps != null) {
+                        dataOwnerPkg = ps.pkg;
+                    }
+                }
+
+                if (dataOwnerPkg != null) {
+                    // If installed, the package will get access to data left on the device by its
+                    // predecessor. As a security measure, this is permited only if this is not a
+                    // version downgrade or if the predecessor package is marked as debuggable and
+                    // a downgrade is explicitly requested.
+                    //
+                    // On debuggable platform builds, downgrades are permitted even for
+                    // non-debuggable packages to make testing easier. Debuggable platform builds do
+                    // not offer security guarantees and thus it's OK to disable some security
+                    // mechanisms to make debugging/testing easier on those builds. However, even on
+                    // debuggable builds downgrades of packages are permitted only if requested via
+                    // installFlags. This is because we aim to keep the behavior of debuggable
+                    // platform builds as close as possible to the behavior of non-debuggable
+                    // platform builds.
+                    final boolean downgradeRequested =
+                            (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
+                    final boolean packageDebuggable =
+                                (dataOwnerPkg.applicationInfo.flags
+                                        & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                    final boolean downgradePermitted =
+                            (downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable));
+                    if (!downgradePermitted) {
+                        try {
+                            checkDowngrade(dataOwnerPkg, pkgLite);
+                        } catch (PackageManagerException e) {
+                            Slog.w(TAG, "Downgrade detected: " + e.getMessage());
+                            return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
                         }
+                    }
+                }
+
+                if (installedPkg != null) {
+                    if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                         // Check for updated system application.
-                        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                             if (onSd) {
                                 Slog.w(TAG, "Cannot install update to system app on sdcard");
                                 return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION;
@@ -11578,7 +12191,7 @@
                                 // App explictly prefers external. Let policy decide
                             } else {
                                 // Prefer previous location
-                                if (isExternal(pkg)) {
+                                if (isExternal(installedPkg)) {
                                     return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
                                 }
                                 return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
@@ -11747,7 +12360,7 @@
                     verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
                     // Query all live verifiers based on current user state
-                    final List<ResolveInfo> receivers = queryIntentReceivers(verification,
+                    final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
                             PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
 
                     if (DEBUG_VERIFY) {
@@ -11772,26 +12385,22 @@
                     verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
                             pkgLite.versionCode);
 
-                    if (verificationParams != null) {
-                        if (verificationParams.getVerificationURI() != null) {
-                           verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
-                                 verificationParams.getVerificationURI());
-                        }
-                        if (verificationParams.getOriginatingURI() != null) {
+                    if (verificationInfo != null) {
+                        if (verificationInfo.originatingUri != null) {
                             verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
-                                  verificationParams.getOriginatingURI());
+                                    verificationInfo.originatingUri);
                         }
-                        if (verificationParams.getReferrer() != null) {
+                        if (verificationInfo.referrer != null) {
                             verification.putExtra(Intent.EXTRA_REFERRER,
-                                  verificationParams.getReferrer());
+                                    verificationInfo.referrer);
                         }
-                        if (verificationParams.getOriginatingUid() >= 0) {
+                        if (verificationInfo.originatingUid >= 0) {
                             verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
-                                  verificationParams.getOriginatingUid());
+                                    verificationInfo.originatingUid);
                         }
-                        if (verificationParams.getInstallerUid() >= 0) {
+                        if (verificationInfo.installerUid >= 0) {
                             verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
-                                  verificationParams.getInstallerUid());
+                                    verificationInfo.installerUid);
                         }
                     }
 
@@ -12025,8 +12634,6 @@
          * Called after the source arguments are copied. This is used mostly for
          * MoveParams when it needs to read the source file to put it in the
          * destination.
-         *
-         * @return
          */
         int doPostCopy(int uid) {
             return PackageManager.INSTALL_SUCCEEDED;
@@ -12927,6 +13534,7 @@
         final PackageParser.Package oldPackage;
         final String pkgName = pkg.packageName;
         final int[] allUsers;
+        final boolean weFroze;
 
         // First find the old package info and check signatures
         synchronized(mPackages) {
@@ -12959,8 +13567,32 @@
 
             // In case of rollback, remember per-user/profile install state
             allUsers = sUserManager.getUserIds();
+
+            // Mark the app as frozen to prevent launching during the upgrade
+            // process, and then kill all running instances
+            if (!ps.frozen) {
+                ps.frozen = true;
+                weFroze = true;
+            } else {
+                weFroze = false;
+            }
         }
 
+        try {
+            replacePackageDirtyLI(pkg, oldPackage, parseFlags, scanFlags, user, allUsers,
+                    installerPackageName, res);
+        } finally {
+            // Regardless of success or failure of upgrade steps above, always
+            // unfreeze the package if we froze it
+            if (weFroze) {
+                unfreezePackage(pkgName);
+            }
+        }
+    }
+
+    private void replacePackageDirtyLI(PackageParser.Package pkg, PackageParser.Package oldPackage,
+            int parseFlags, int scanFlags, UserHandle user, int[] allUsers,
+            String installerPackageName, PackageInstalledInfo res) {
         // Update what is removed
         res.removedInfo = new PackageRemovedInfo();
         res.removedInfo.uid = oldPackage.applicationInfo.uid;
@@ -13008,6 +13640,15 @@
         }
     }
 
+    public List<String> getPreviousCodePaths(String packageName) {
+        final PackageSetting ps = mSettings.mPackages.get(packageName);
+        final List<String> result = new ArrayList<String>();
+        if (ps != null && ps.oldCodePaths != null) {
+            result.addAll(ps.oldCodePaths);
+        }
+        return result;
+    }
+
     private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
             PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
             int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
@@ -13017,12 +13658,16 @@
         String pkgName = deletedPackage.packageName;
         boolean deletedPkg = true;
         boolean addedPkg = false;
+        boolean updatedSettings = false;
+        final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
+        final int deleteFlags = PackageManager.DELETE_KEEP_DATA
+                | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
 
         final long origUpdateTime = (pkg.mExtras != null)
                 ? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
 
         // First delete the existing package while retaining the data directory
-        if (!deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+        if (!deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
                 res.removedInfo, true, pkg)) {
             // If the existing package wasn't successfully deleted
             res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
@@ -13043,11 +13688,33 @@
             }
 
             deleteCodeCacheDirsLI(pkg);
+            deleteProfilesLI(pkg, /*destroy*/ false);
 
             try {
                 final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
                         scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
                 updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
+
+                // Update the in-memory copy of the previous code paths.
+                PackageSetting ps = mSettings.mPackages.get(pkgName);
+                if (!killApp) {
+                    if (ps.oldCodePaths == null) {
+                        ps.oldCodePaths = new ArraySet<>();
+                    }
+                    Collections.addAll(ps.oldCodePaths, deletedPackage.baseCodePath);
+                    if (deletedPackage.splitCodePaths != null) {
+                        Collections.addAll(ps.oldCodePaths, deletedPackage.splitCodePaths);
+                    }
+                } else {
+                    ps.oldCodePaths = null;
+                }
+                if (ps.childPackageNames != null) {
+                    for (int i = ps.childPackageNames.size() - 1; i >= 0; --i) {
+                        final String childPkgName = ps.childPackageNames.get(i);
+                        final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
+                        childPs.oldCodePaths = ps.oldCodePaths;
+                    }
+                }
                 prepareAppDataAfterInstall(newPackage);
                 addedPkg = true;
             } catch (PackageManagerException e) {
@@ -13060,7 +13727,7 @@
 
             // Revert all internal state mutations and added folders for the failed install
             if (addedPkg) {
-                deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+                deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
                         res.removedInfo, true, null);
             }
 
@@ -13156,6 +13823,7 @@
 
         // Successfully disabled the old package. Now proceed with re-installation
         deleteCodeCacheDirsLI(pkg);
+        deleteProfilesLI(pkg, /*destroy*/ false);
 
         res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
         pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
@@ -13281,18 +13949,21 @@
         return null;
     }
 
-    private void removeNativeBinariesLI(PackageParser.Package pkg) {
+    private void removeNativeBinariesLI(PackageSetting ps) {
         // Remove the lib path for the parent package
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps != null) {
             NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
-        }
-        // Remove the lib path for the child packages
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            ps = (PackageSetting) pkg.childPackages.get(i).mExtras;
-            if (ps != null) {
-                NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
+            // Remove the lib path for the child packages
+            final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
+            for (int i = 0; i < childCount; i++) {
+                PackageSetting childPs = null;
+                synchronized (mPackages) {
+                    childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
+                }
+                if (childPs != null) {
+                    NativeLibraryHelper.removeNativeBinariesLI(childPs
+                            .legacyNativeLibraryPathString);
+                }
             }
         }
     }
@@ -13510,6 +14181,9 @@
             // moving a complete application; perform an initial scan on the new install location
             scanFlags |= SCAN_INITIAL;
         }
+        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+            scanFlags |= SCAN_DONT_KILL_APP;
+        }
 
         // Result object to be returned
         res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
@@ -13586,14 +14260,11 @@
             }
         }
 
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
         try {
             PackageParser.collectCertificates(pkg, parseFlags);
         } catch (PackageParserException e) {
             res.setError("Failed collect during installPackageLI", e);
             return;
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
         // Get rid of all references to package scan path via parser.
@@ -13776,21 +14447,17 @@
                 return;
             }
 
-            // Extract package to save the VM unzipping the APK in memory during
-            // launch. Only do this if profile-guided compilation is enabled because
-            // otherwise BackgroundDexOptService will not dexopt the package later.
-            if (mUseJitProfiles) {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-                // Do not run PackageDexOptimizer through the local performDexOpt
-                // method because `pkg` is not in `mPackages` yet.
-                int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
-                        false /* useProfiles */, true /* extractOnly */);
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
-                    String msg = "Extracking package failed for " + pkgName;
-                    res.setError(INSTALL_FAILED_DEXOPT, msg);
-                    return;
-                }
+
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+            // Do not run PackageDexOptimizer through the local performDexOpt
+            // method because `pkg` is not in `mPackages` yet.
+            int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
+                    false /* checkProfiles */, getCompilerFilterForReason(REASON_INSTALL));
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
+                String msg = "Extracking package failed for " + pkgName;
+                res.setError(INSTALL_FAILED_DEXOPT, msg);
+                return;
             }
         }
 
@@ -14077,25 +14744,48 @@
             return;
         }
 
-        for (int currentUserId : users) {
-            if (getBlockUninstallForUser(packageName, currentUserId)) {
-                try {
-                    observer.onPackageDeleted(packageName,
-                            PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
-                } catch (RemoteException re) {
-                }
-                return;
+        if (!deleteAllUsers && getBlockUninstallForUser(packageName, userId)) {
+            try {
+                observer.onPackageDeleted(packageName,
+                        PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
+            } catch (RemoteException re) {
             }
+            return;
         }
 
         if (DEBUG_REMOVE) {
-            Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
+            Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId
+                    + " deleteAllUsers: " + deleteAllUsers );
         }
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                final int returnCode = deletePackageX(packageName, userId, flags);
+                int returnCode;
+                if (!deleteAllUsers) {
+                    returnCode = deletePackageX(packageName, userId, flags);
+                } else {
+                    int[] blockUninstallUserIds = getBlockUninstallForUsers(packageName, users);
+                    // If nobody is blocking uninstall, proceed with delete for all users
+                    if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
+                        returnCode = deletePackageX(packageName, userId, flags);
+                    } else {
+                        // Otherwise uninstall individually for users with blockUninstalls=false
+                        final int userFlags = flags & ~PackageManager.DELETE_ALL_USERS;
+                        for (int userId : users) {
+                            if (!ArrayUtils.contains(blockUninstallUserIds, userId)) {
+                                returnCode = deletePackageX(packageName, userId, userFlags);
+                                if (returnCode != PackageManager.DELETE_SUCCEEDED) {
+                                    Slog.w(TAG, "Package delete failed for user " + userId
+                                            + ", returnCode " + returnCode);
+                                }
+                            }
+                        }
+                        // The app has only been marked uninstalled for certain users.
+                        // We still need to report that delete was blocked
+                        returnCode = PackageManager.DELETE_FAILED_OWNER_BLOCKED;
+                    }
+                }
                 try {
                     observer.onPackageDeleted(packageName, returnCode, null);
                 } catch (RemoteException e) {
@@ -14105,6 +14795,16 @@
         });
     }
 
+    private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
+        int[] result = EMPTY_INT_ARRAY;
+        for (int userId : userIds) {
+            if (getBlockUninstallForUser(packageName, userId)) {
+                result = ArrayUtils.appendInt(result, userId);
+            }
+        }
+        return result;
+    }
+
     @Override
     public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
         return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
@@ -14201,7 +14901,8 @@
         }
 
         if (res) {
-            info.sendPackageRemovedBroadcasts();
+            final boolean killApp = (flags & PackageManager.INSTALL_DONT_KILL_APP) == 0;
+            info.sendPackageRemovedBroadcasts(killApp);
             info.sendSystemPackageUpdatedBroadcasts();
             info.sendSystemPackageAppearedBroadcasts();
         }
@@ -14233,12 +14934,12 @@
         ArrayMap<String, PackageRemovedInfo> removedChildPackages;
         ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
 
-        void sendPackageRemovedBroadcasts() {
-            sendPackageRemovedBroadcastInternal();
+        void sendPackageRemovedBroadcasts(boolean killApp) {
+            sendPackageRemovedBroadcastInternal(killApp);
             final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
             for (int i = 0; i < childCount; i++) {
                 PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
-                childInfo.sendPackageRemovedBroadcastInternal();
+                childInfo.sendPackageRemovedBroadcastInternal(killApp);
             }
         }
 
@@ -14280,10 +14981,11 @@
                     null, 0, removedPackage, null, null);
         }
 
-        private void sendPackageRemovedBroadcastInternal() {
+        private void sendPackageRemovedBroadcastInternal(boolean killApp) {
             Bundle extras = new Bundle(2);
             extras.putInt(Intent.EXTRA_UID, removedAppId >= 0  ? removedAppId : uid);
             extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
+            extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
             if (isUpdate || isRemovedPackageSystemUpdate) {
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
             }
@@ -14415,7 +15117,7 @@
     private boolean deleteSystemPackageLI(PackageParser.Package deletedPkg,
             PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
             boolean writeSettings) {
-        if (deletedPkg.parentPackage != null) {
+        if (deletedPs.parentPackageName != null) {
             Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
             return false;
         }
@@ -14428,7 +15130,7 @@
         // the system pkg from system partition
         // reader
         synchronized (mPackages) {
-            disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPkg.packageName);
+            disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPs.name);
         }
 
         if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
@@ -14454,10 +15156,10 @@
         // Delete the updated package
         outInfo.isRemovedPackageSystemUpdate = true;
         if (outInfo.removedChildPackages != null) {
-            final int childCount = (deletedPkg.childPackages != null)
-                    ? deletedPkg.childPackages.size() : 0;
+            final int childCount = (deletedPs.childPackageNames != null)
+                    ? deletedPs.childPackageNames.size() : 0;
             for (int i = 0; i < childCount; i++) {
-                String childPackageName = deletedPkg.childPackages.get(i).packageName;
+                String childPackageName = deletedPs.childPackageNames.get(i);
                 if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
                         .contains(childPackageName)) {
                     PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
@@ -14477,7 +15179,7 @@
             flags |= PackageManager.DELETE_KEEP_DATA;
         }
 
-        boolean ret = deleteInstalledPackageLI(deletedPkg, true, flags, allUserHandles,
+        boolean ret = deleteInstalledPackageLI(deletedPs, true, flags, allUserHandles,
                 outInfo, writeSettings, disabledPs.pkg);
         if (!ret) {
             return false;
@@ -14488,7 +15190,7 @@
             // Reinstate the old system package
             enableSystemPackageLPw(disabledPs.pkg);
             // Remove any native libraries from the upgraded package.
-            removeNativeBinariesLI(deletedPkg);
+            removeNativeBinariesLI(deletedPs);
         }
 
         // Install the system package
@@ -14545,29 +15247,18 @@
         return true;
     }
 
-    private boolean deleteInstalledPackageLI(PackageParser.Package pkg,
+    private boolean deleteInstalledPackageLI(PackageSetting ps,
             boolean deleteCodeAndResources, int flags, int[] allUserHandles,
             PackageRemovedInfo outInfo, boolean writeSettings,
             PackageParser.Package replacingPackage) {
-        PackageSetting ps = null;
-
         synchronized (mPackages) {
-            pkg = mPackages.get(pkg.packageName);
-            if (pkg == null) {
-                return false;
-            }
-
-            ps = mSettings.mPackages.get(pkg.packageName);
-            if (ps == null) {
-                return false;
-            }
-
             if (outInfo != null) {
                 outInfo.uid = ps.appId;
             }
 
             if (outInfo != null && outInfo.removedChildPackages != null) {
-                final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+                final int childCount = (ps.childPackageNames != null)
+                        ? ps.childPackageNames.size() : 0;
                 for (int i = 0; i < childCount; i++) {
                     String childPackageName = ps.childPackageNames.get(i);
                     PackageSetting childPs = mSettings.mPackages.get(childPackageName);
@@ -14587,11 +15278,11 @@
         removePackageDataLI(ps, allUserHandles, outInfo, flags, writeSettings);
 
         // Delete the child packages data
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+        final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
         for (int i = 0; i < childCount; i++) {
             PackageSetting childPs;
             synchronized (mPackages) {
-                childPs = mSettings.peekPackageLPr(pkg.childPackages.get(i).packageName);
+                childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
             }
             if (childPs != null) {
                 PackageRemovedInfo childOutInfo = (outInfo != null
@@ -14607,7 +15298,7 @@
         }
 
         // Delete application code and resources only for parent packages
-        if (ps.pkg.parentPackage == null) {
+        if (ps.parentPackageName == null) {
             if (deleteCodeAndResources && (outInfo != null)) {
                 outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                         ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
@@ -14698,7 +15389,7 @@
                 return false;
             }
 
-            if (ps.pkg.parentPackage != null && (!isSystemApp(ps)
+            if (ps.parentPackageName != null && (!isSystemApp(ps)
                     || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
                 if (DEBUG_REMOVE) {
                     Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
@@ -14785,8 +15476,11 @@
         } else {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
             // Kill application pre-emptively especially for apps on sd.
-            killApplication(packageName, ps.appId, "uninstall pkg");
-            ret = deleteInstalledPackageLI(ps.pkg, deleteCodeAndResources, flags, allUserHandles,
+            final boolean killApp = (flags & PackageManager.DELETE_DONT_KILL_APP) == 0;
+            if (killApp) {
+                killApplication(packageName, ps.appId, "uninstall pkg");
+            }
+            ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, allUserHandles,
                     outInfo, writeSettings, replacingPackage);
         }
 
@@ -14963,11 +15657,29 @@
     }
 
     @Override
+    public void clearApplicationProfileData(String packageName) {
+        enforceSystemOrRoot("Only the system can clear all profile data");
+        try {
+            mInstaller.clearAppProfiles(packageName);
+        } catch (InstallerException ex) {
+            Log.e(TAG, "Could not clear profile data of package " + packageName);
+        }
+    }
+
+    @Override
     public void clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, final int userId) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_USER_DATA, null);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "clear application data");
+
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */, "clear application data");
+
+        final DevicePolicyManagerInternal dpmi = LocalServices
+                .getService(DevicePolicyManagerInternal.class);
+        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+            throw new SecurityException("Cannot clear data for a device owner or a profile owner");
+        }
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
@@ -14979,8 +15691,8 @@
                 clearExternalStorageDataSync(packageName, userId, true);
                 if (succeeded) {
                     // invoke DeviceStorageMonitor's update method to clear any notifications
-                    DeviceStorageMonitorInternal
-                            dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+                    DeviceStorageMonitorInternal dsm = LocalServices
+                            .getService(DeviceStorageMonitorInternal.class);
                     if (dsm != null) {
                         dsm.checkMemory();
                     }
@@ -15164,17 +15876,14 @@
                 // Otherwise, reset the permission.
                 final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
                 switch (revokeResult) {
-                    case PERMISSION_OPERATION_SUCCESS: {
-                        writeRuntimePermissions = true;
-                    } break;
-
+                    case PERMISSION_OPERATION_SUCCESS:
                     case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
                         writeRuntimePermissions = true;
                         final int appId = ps.appId;
                         mHandler.post(new Runnable() {
                             @Override
                             public void run() {
-                                killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
+                                killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
                             }
                         });
                     } break;
@@ -15379,22 +16088,6 @@
         return true;
     }
 
-
-    @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>();
-    }
-
     private int getUidTargetSdkVersionLockedLPr(int uid) {
         Object obj = mSettings.getUserIdLPr(uid);
         if (obj instanceof SharedUserSetting) {
@@ -15430,7 +16123,8 @@
             String opname) {
         // writer
         int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, true, false, "add preferred activity");
+        enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, false /* checkShell */, "add preferred activity");
         if (filter.countActions() == 0) {
             Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
             return;
@@ -15475,7 +16169,9 @@
         }
 
         final int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, true, false, "replace preferred activity");
+        enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "replace preferred activity");
         synchronized (mPackages) {
             if (mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -16240,14 +16936,29 @@
 
     @Override
     public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
+        return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
+    }
+
+    private Intent getHomeIntent() {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_HOME);
+        return intent;
+    }
 
-        final int callingUserId = UserHandle.getCallingUserId();
-        List<ResolveInfo> list = queryIntentActivities(intent, null,
-                PackageManager.GET_META_DATA, callingUserId);
+    private IntentFilter getHomeFilter() {
+        IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
+        filter.addCategory(Intent.CATEGORY_HOME);
+        filter.addCategory(Intent.CATEGORY_DEFAULT);
+        return filter;
+    }
+
+    ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+            int userId) {
+        Intent intent  = getHomeIntent();
+        List<ResolveInfo> list = queryIntentActivitiesInternal(intent, null,
+                PackageManager.GET_META_DATA, userId);
         ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
-                true, false, false, callingUserId);
+                true, false, false, userId);
 
         allHomeCandidates.clear();
         if (list != null) {
@@ -16262,6 +16973,49 @@
     }
 
     @Override
+    public void setHomeActivity(ComponentName comp, int userId) {
+        ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
+        getHomeActivitiesAsUser(homeActivities, userId);
+
+        boolean found = false;
+
+        final int size = homeActivities.size();
+        final ComponentName[] set = new ComponentName[size];
+        for (int i = 0; i < size; i++) {
+            final ResolveInfo candidate = homeActivities.get(i);
+            final ActivityInfo info = candidate.activityInfo;
+            final ComponentName activityName = new ComponentName(info.packageName, info.name);
+            set[i] = activityName;
+            if (!found && activityName.equals(comp)) {
+                found = true;
+            }
+        }
+        if (!found) {
+            throw new IllegalArgumentException("Component " + comp + " cannot be home on user "
+                    + userId);
+        }
+        replacePreferredActivity(getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
+                set, comp, userId);
+    }
+
+    private @Nullable String getSetupWizardPackageName() {
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
+
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
+                        | MATCH_DISABLED_COMPONENTS,
+                UserHandle.myUserId());
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().packageName;
+        } else {
+            Slog.e(TAG, "There should probably be exactly one setup wizard; found " + matches.size()
+                    + ": matches=" + matches);
+            return null;
+        }
+    }
+
+    @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
         if (!sUserManager.exists(userId)) return;
@@ -16293,7 +17047,8 @@
         final int uid = Binder.getCallingUid();
         final int permission = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
-        enforceCrossUserPermission(uid, userId, false, true, "set enabled");
+        enforceCrossUserPermission(uid, userId,
+                false /* requireFullPermission */, true /* checkShell */, "set enabled");
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
         boolean sendNow = false;
         boolean isApp = (className == null);
@@ -16404,6 +17159,22 @@
         }
     }
 
+    @Override
+    public void flushPackageRestrictionsAsUser(int userId) {
+        if (!sUserManager.exists(userId)) {
+            return;
+        }
+        enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
+                false /* checkShell */, "flushPackageRestrictions");
+        synchronized (mPackages) {
+            mSettings.writePackageRestrictionsLPr(userId);
+            mDirtyUsers.remove(userId);
+            if (mDirtyUsers.isEmpty()) {
+                mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+            }
+        }
+    }
+
     private void sendPackageChangedBroadcast(String packageName,
             boolean killFlag, ArrayList<String> componentNames, int packageUid) {
         if (DEBUG_INSTALL)
@@ -16432,7 +17203,8 @@
         final int permission = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
-        enforceCrossUserPermission(uid, userId, true, true, "stop package");
+        enforceCrossUserPermission(uid, userId,
+                true /* requireFullPermission */, true /* checkShell */, "stop package");
         // writer
         synchronized (mPackages) {
             if (mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
@@ -16454,7 +17226,8 @@
     public int getApplicationEnabledSetting(String packageName, int userId) {
         if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, false, false, "get enabled");
+        enforceCrossUserPermission(uid, userId,
+                false /* requireFullPermission */, false /* checkShell */, "get enabled");
         // reader
         synchronized (mPackages) {
             return mSettings.getApplicationEnabledSettingLPr(packageName, userId);
@@ -16465,7 +17238,8 @@
     public int getComponentEnabledSetting(ComponentName componentName, int userId) {
         if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, false, false, "get component enabled");
+        enforceCrossUserPermission(uid, userId,
+                false /* requireFullPermission */, false /* checkShell */, "get component enabled");
         // reader
         synchronized (mPackages) {
             return mSettings.getComponentEnabledSettingLPr(componentName, userId);
@@ -17236,8 +18010,9 @@
     }
 
     private String dumpDomainString(String packageName) {
-        List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName);
-        List<IntentFilter> filters = getAllIntentFilters(packageName);
+        List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName)
+                .getList();
+        List<IntentFilter> filters = getAllIntentFilters(packageName).getList();
 
         ArraySet<String> result = new ArraySet<>();
         if (iviList.size() > 0) {
@@ -17972,6 +18747,13 @@
 
             if (ps.getInstalled(userId)) {
                 prepareAppData(volumeUuid, userId, flags, ps.pkg, restoreconNeeded);
+
+                if (maybeMigrateAppData(volumeUuid, userId, ps.pkg)) {
+                    // We may have just shuffled around app data directories, so
+                    // prepare them one more time
+                    prepareAppData(volumeUuid, userId, flags, ps.pkg, restoreconNeeded);
+                }
+
                 preparedCount++;
             }
         }
@@ -17998,6 +18780,8 @@
      * correct for all installed apps. If there is an ownership mismatch, it
      * will try recovering system apps by wiping data; third-party app data is
      * left intact.
+     * <p>
+     * <em>Note: To avoid a deadlock, do not call this method with {@code mPackages} lock held</em>
      */
     private void prepareAppDataAfterInstall(PackageParser.Package pkg) {
         prepareAppDataAfterInstallInternal(pkg);
@@ -18097,6 +18881,30 @@
         }
     }
 
+    /**
+     * For system apps on non-FBE devices, this method migrates any existing
+     * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
+     * requested by the app.
+     */
+    private boolean maybeMigrateAppData(String volumeUuid, int userId, PackageParser.Package pkg) {
+        if (pkg.isSystemApp() && !StorageManager.isFileEncryptedNativeOrEmulated()
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage()
+                    ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
+            synchronized (mInstallLock) {
+                try {
+                    mInstaller.migrateAppData(volumeUuid, pkg.packageName, userId, storageTarget);
+                } catch (InstallerException e) {
+                    logCriticalInfo(Log.WARN,
+                            "Failed to migrate " + pkg.packageName + ": " + e.getMessage());
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     private void unfreezePackage(String packageName) {
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -18337,7 +19145,8 @@
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
         final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
-                installerPackageName, volumeUuid, null, user, packageAbiOverride, null);
+                installerPackageName, volumeUuid, null /*verificationInfo*/, user,
+                packageAbiOverride, null);
         params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -18992,6 +19801,17 @@
                 return permissionsState.isPermissionReviewRequired(userId);
             }
         }
+
+        @Override
+        public ApplicationInfo getApplicationInfo(String packageName, int userId) {
+            return PackageManagerService.this.getApplicationInfo(packageName, 0 /*flags*/, userId);
+        }
+
+        @Override
+        public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+                int userId) {
+            return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
+        }
     }
 
     @Override
@@ -19019,4 +19839,36 @@
     boolean isHistoricalPackageUsageAvailable() {
         return mPackageUsage.isHistoricalPackageUsageAvailable();
     }
+
+    /**
+     * Return a <b>copy</b> of the collection of packages known to the package manager.
+     * @return A copy of the values of mPackages.
+     */
+    Collection<PackageParser.Package> getPackages() {
+        synchronized (mPackages) {
+            return new ArrayList<>(mPackages.values());
+        }
+    }
+
+    /**
+     * Logs process start information (including base APK hash) to the security log.
+     * @hide
+     */
+    public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo,
+            String apkFile, int pid) {
+        if (!SecurityLog.isLoggingEnabled()) {
+            return;
+        }
+        Bundle data = new Bundle();
+        data.putLong("startTimestamp", System.currentTimeMillis());
+        data.putString("processName", processName);
+        data.putInt("uid", uid);
+        data.putString("seinfo", seinfo);
+        data.putString("apkFile", apkFile);
+        data.putInt("pid", pid);
+        Message msg = mProcessLoggingHandler.obtainMessage(
+                ProcessLoggingHandler.LOG_APP_PROCESS_START_MSG);
+        msg.setData(data);
+        mProcessLoggingHandler.sendMessage(msg);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
new file mode 100644
index 0000000..a7512db
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.os.SystemProperties;
+
+import dalvik.system.DexFile;
+
+/**
+ * Manage (retrieve) mappings from compilation reason to compilation filter.
+ */
+class PackageManagerServiceCompilerMapping {
+    // Names for compilation reasons.
+    static final String REASON_STRINGS[] = {
+            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk",
+            "forced-dexopt"
+    };
+
+    // Static block to ensure the strings array is of the right length.
+    static {
+        if (PackageManagerService.REASON_LAST + 1 != REASON_STRINGS.length) {
+            throw new IllegalStateException("REASON_STRINGS not correct");
+        }
+    }
+
+    private static String getSystemPropertyName(int reason) {
+        if (reason < 0 || reason >= REASON_STRINGS.length) {
+            throw new IllegalArgumentException("reason " + reason + " invalid");
+        }
+
+        return "pm.dexopt." + REASON_STRINGS[reason];
+    }
+
+    // Load the property for the given reason and check for validity. This will throw an
+    // exception in case the reason or value are invalid.
+    private static String getAndCheckValidity(int reason) {
+        String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
+        if (sysPropValue == null || sysPropValue.isEmpty() ||
+                !DexFile.isValidCompilerFilter(sysPropValue)) {
+            throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
+                    + "(reason " + REASON_STRINGS[reason] + ")");
+        }
+
+        // Ensure that some reasons are not mapped to profile-guided filters.
+        switch (reason) {
+            case PackageManagerService.REASON_SHARED_APK:
+            case PackageManagerService.REASON_FORCED_DEXOPT:
+                if (DexFile.isProfileGuidedCompilerFilter(sysPropValue)) {
+                    throw new IllegalStateException("\"" + sysPropValue + "\" is profile-guided, "
+                            + "but not allowed for " + REASON_STRINGS[reason]);
+                }
+                break;
+        }
+
+        return sysPropValue;
+    }
+
+    // Check that the properties are set and valid.
+    // Note: this is done in a separate method so this class can be statically initialized.
+    static void checkProperties() {
+        // We're gonna check all properties and collect the exceptions, so we can give a general
+        // overview. Store the exceptions here.
+        RuntimeException toThrow = null;
+
+        for (int reason = 0; reason <= PackageManagerService.REASON_LAST; reason++) {
+            try {
+                // Check that the system property name is legal.
+                String sysPropName = getSystemPropertyName(reason);
+                if (sysPropName == null ||
+                        sysPropName.isEmpty() ||
+                        sysPropName.length() > SystemProperties.PROP_NAME_MAX) {
+                    throw new IllegalStateException("Reason system property name \"" +
+                            sysPropName +"\" for reason " + REASON_STRINGS[reason]);
+                }
+
+                // Check validity, ignore result.
+                getAndCheckValidity(reason);
+            } catch (Exception exc) {
+                if (toThrow == null) {
+                    toThrow = new IllegalStateException("PMS compiler filter settings are bad.");
+                }
+                toThrow.addSuppressed(exc);
+            }
+        }
+
+        if (toThrow != null) {
+            throw toThrow;
+        }
+    }
+
+    public static String getCompilerFilterForReason(int reason) {
+        return getAndCheckValidity(reason);
+    }
+
+    /**
+     * Return the compiler filter for "full" compilation.
+     *
+     * We derive that from the traditional "dalvik.vm.dex2oat-filter" property and just make
+     * sure this isn't profile-guided. Returns "speed" in case of invalid (or missing) values.
+     */
+    public static String getFullCompilerFilter() {
+        String value = SystemProperties.get("dalvik.vm.dex2oat-filter");
+        if (value == null || value.isEmpty()) {
+            return "speed";
+        }
+
+        if (!DexFile.isValidCompilerFilter(value) ||
+                DexFile.isProfileGuidedCompilerFilter(value)) {
+            return "speed";
+        }
+
+        return value;
+    }
+
+    /**
+     * Return the non-profile-guided filter corresponding to the given filter.
+     */
+    public static String getNonProfileGuidedCompilerFilter(String filter) {
+        return DexFile.getNonProfileGuidedCompilerFilter(filter);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index a3ac514..f79d6ee 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -16,13 +16,15 @@
 
 package com.android.server.pm;
 
+import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.TAG;
+
 import android.app.AppGlobals;
 import android.content.Intent;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
 import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -35,9 +37,6 @@
 import java.util.List;
 import java.util.Set;
 
-import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
-import static com.android.server.pm.PackageManagerService.TAG;
-
 /**
  * Class containing helper methods for the PackageManagerService.
  *
@@ -49,7 +48,8 @@
     private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
         List<ResolveInfo> ris = null;
         try {
-            ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId);
+            ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId)
+                    .getList();
         } catch (RemoteException e) {
         }
         ArraySet<String> pkgNames = new ArraySet<String>();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index abee007..8527fd4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -50,6 +50,8 @@
 import android.util.PrintWriterPrinter;
 import com.android.internal.util.SizedInputStream;
 
+import dalvik.system.DexFile;
+
 import libcore.io.IoUtils;
 
 import java.io.File;
@@ -95,6 +97,8 @@
                     return runInstallCommit();
                 case "install-create":
                     return runInstallCreate();
+                case "install-remove":
+                    return runInstallRemove();
                 case "install-write":
                     return runInstallWrite();
                 case "compile":
@@ -115,6 +119,8 @@
                     return runSuspend(true);
                 case "unsuspend":
                     return runSuspend(false);
+                case "set-home-activity":
+                    return runSetHomeActivity();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -136,11 +142,12 @@
                 pw.println("Error: must either specify a package size or an APK file");
                 return 1;
             }
-            if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
                     false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                 return 1;
             }
-            if (doCommitSession(sessionId, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+            if (doCommitSession(sessionId, false /*logSuccess*/)
+                    != PackageInstaller.STATUS_SUCCESS) {
                 return 1;
             }
             abandonSession = false;
@@ -183,7 +190,7 @@
             pw.println("Package " + packageName + " new suspended state: "
                     + mInterface.isPackageSuspendedForUser(packageName, userId));
             return 0;
-        } catch (RemoteException e) {
+        } catch (RemoteException | IllegalArgumentException e) {
             pw.println(e.toString());
             return 1;
         }
@@ -225,66 +232,197 @@
         final int sessionId = Integer.parseInt(getNextArg());
         final String splitName = getNextArg();
         final String path = getNextArg();
-        return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
+        return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
+    }
+
+    private int runInstallRemove() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+
+        final int sessionId = Integer.parseInt(getNextArg());
+
+        final String splitName = getNextArg();
+        if (splitName == null) {
+            pw.println("Error: split name not specified");
+            return 1;
+        }
+        return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
     }
 
     private int runCompile() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        boolean useJitProfiles = false;
-        boolean extractOnly = false;
+        boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
         boolean forceCompilation = false;
-        String compilationMode = "default";
+        boolean allPackages = false;
+        boolean clearProfileData = false;
+        String compilerFilter = null;
+        String compilationReason = null;
+        String checkProfilesRaw = null;
+
+        if (peekNextArg() == null) {
+            // No arguments, show help.
+            pw.println("Usage: cmd package compile [-c] [-f] [--reset] [-m mode] " +
+                    "[-r reason] [-a|pkg]");
+            pw.println();
+            pw.println("  -c                Clear profile data");
+            pw.println("  -f                Force compilation");
+            pw.println("  --check-prof val  Look at profiles when doing dexopt.");
+            pw.println("                    Overrides dalvik.vm.usejitprofiles to true of false");
+            pw.println("  --reset           Reset package");
+            pw.println("  -m mode           Compilation mode, one of the dex2oat compiler filters");
+            pw.println("                      verify-none");
+            pw.println("                      verify-at-runtime");
+            pw.println("                      verify-profile");
+            pw.println("                      interpret-only");
+            pw.println("                      space-profile");
+            pw.println("                      space");
+            pw.println("                      speed-profile");
+            pw.println("                      speed");
+            pw.println("                      everything");
+            pw.println("  -r reason  Compiler reason, one of the package manager reasons");
+            for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
+                pw.println("               " +
+                        PackageManagerServiceCompilerMapping.REASON_STRINGS[i]);
+            }
+            pw.println("  -a         Apply to all packages");
+            return 1;
+        }
 
         String opt;
         while ((opt = getNextOption()) != null) {
             switch (opt) {
-                case "-m":
-                    compilationMode = getNextArgRequired();
+                case "-a":
+                    allPackages = true;
+                    break;
+                case "-c":
+                    clearProfileData = true;
                     break;
                 case "-f":
                     forceCompilation = true;
                     break;
+                case "-m":
+                    compilerFilter = getNextArgRequired();
+                    break;
+                case "-r":
+                    compilationReason = getNextArgRequired();
+                    break;
+                case "-check-prof":
+                    checkProfilesRaw = getNextArgRequired();
+                    break;
+                case "--reset":
+                    forceCompilation = true;
+                    clearProfileData = true;
+                    compilerFilter = "reset";
+                    break;
                 default:
                     pw.println("Error: Unknown option: " + opt);
                     return 1;
             }
         }
 
-        switch (compilationMode) {
-            case "default":
-                useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
-                extractOnly = false;
-                break;
-            case "all":
-                useJitProfiles = false;
-                extractOnly = false;
-                break;
-            case "profile":
-                useJitProfiles = true;
-                extractOnly = false;
-                break;
-            case "extract":
-                useJitProfiles = false;
-                extractOnly = true;
-                break;
-            default:
-                pw.println("Error: Unknown compilation mode: " + compilationMode);
+        if (checkProfilesRaw != null) {
+            if ("true".equals(checkProfilesRaw)) {
+                checkProfiles = true;
+            } else if ("false".equals(checkProfilesRaw)) {
+                checkProfiles = false;
+            } else {
+                pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
                 return 1;
+            }
         }
 
-        String packageName = getNextArg();
-        if (packageName == null) {
-            pw.println("Error: package name not specified");
+        if (compilerFilter != null && compilationReason != null) {
+            pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
+                    "at the same time");
+            return 1;
+        }
+        if (compilerFilter == null && compilationReason == null) {
+            pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
+                    "reason (\"-r\") at the same time");
             return 1;
         }
 
-        boolean success = mInterface.performDexOpt(packageName, null /* instructionSet */,
-                useJitProfiles, extractOnly, forceCompilation);
-        if (success) {
+        String targetCompilerFilter;
+        if (compilerFilter != null) {
+            // Specially recognize default and reset. Otherwise, only accept valid modes.
+            if ("default".equals(compilerFilter)) {
+                // Use the default mode for background dexopt.
+                targetCompilerFilter =
+                        PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                                PackageManagerService.REASON_BACKGROUND_DEXOPT);
+            } else if ("reset".equals(compilerFilter)) {
+                // Use the default mode for install.
+                targetCompilerFilter =
+                        PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                                PackageManagerService.REASON_INSTALL);
+            } else {
+                if (!DexFile.isValidCompilerFilter(compilerFilter)) {
+                    pw.println("Error: \"" + compilerFilter +
+                            "\" is not a valid compilation filter.");
+                    return 1;
+                }
+                targetCompilerFilter = compilerFilter;
+            }
+        } else {
+            int reason = -1;
+            for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
+                if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
+                        compilationReason)) {
+                    reason = i;
+                    break;
+                }
+            }
+            if (reason == -1) {
+                pw.println("Error: Unknown compilation reason: " + compilationReason);
+                return 1;
+            }
+            targetCompilerFilter =
+                    PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
+        }
+
+
+        List<String> packageNames = null;
+        if (allPackages) {
+            packageNames = mInterface.getAllPackages();
+        } else {
+            String packageName = getNextArg();
+            if (packageName == null) {
+                pw.println("Error: package name not specified");
+                return 1;
+            }
+            packageNames = Collections.singletonList(packageName);
+        }
+
+        List<String> failedPackages = new ArrayList<>();
+        for (String packageName : packageNames) {
+            if (clearProfileData) {
+                mInterface.clearApplicationProfileData(packageName);
+            }
+
+            boolean result = mInterface.performDexOptMode(packageName, null /* instructionSet */,
+                    checkProfiles, targetCompilerFilter, forceCompilation);
+            if (!result) {
+                failedPackages.add(packageName);
+            }
+        }
+
+        if (failedPackages.isEmpty()) {
             pw.println("Success");
             return 0;
+        } else if (failedPackages.size() == 1) {
+            pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
+            return 1;
         } else {
-            pw.println("Failure: package " + packageName + " could not be compiled");
+            pw.print("Failure: the following packages could not be compiled: ");
+            boolean is_first = true;
+            for (String packageName : failedPackages) {
+                if (is_first) {
+                    is_first = false;
+                } else {
+                    pw.print(", ");
+                }
+                pw.print(packageName);
+            }
+            pw.println();
             return 1;
         }
     }
@@ -317,11 +455,7 @@
 
     private int runListFeatures() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        final List<FeatureInfo> list = new ArrayList<FeatureInfo>();
-        final FeatureInfo[] rawList = mInterface.getSystemAvailableFeatures();
-        for (int i=0; i<rawList.length; i++) {
-            list.add(rawList[i]);
-        }
+        final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
 
         // sort by name
         Collections.sort(list, new Comparator<FeatureInfo>() {
@@ -380,7 +514,7 @@
         }
 
         final List<InstrumentationInfo> list =
-                mInterface.queryInstrumentation(targetPackage, 0 /*flags*/);
+                mInterface.queryInstrumentation(targetPackage, 0 /*flags*/).getList();
 
         // sort by target package
         Collections.sort(list, new Comparator<InstrumentationInfo>() {
@@ -521,7 +655,7 @@
 
     private int runListPermissionGroups() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0);
+        final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0).getList();
 
         final int count = pgs.size();
         for (int p = 0; p < count ; p++) {
@@ -568,7 +702,7 @@
         final ArrayList<String> groupList = new ArrayList<String>();
         if (groups) {
             final List<PermissionGroupInfo> infos =
-                    mInterface.getAllPermissionGroups(0 /*flags*/);
+                    mInterface.getAllPermissionGroups(0 /*flags*/).getList();
             final int count = infos.size();
             for (int i = 0; i < count; i++) {
                 groupList.add(infos.get(i).name);
@@ -627,12 +761,18 @@
             }
         }
 
-        String packageName = getNextArg();
+        final String packageName = getNextArg();
         if (packageName == null) {
             pw.println("Error: package name not specified");
             return 1;
         }
 
+        // if a split is specified, just remove it and not the whole package
+        final String splitName = getNextArg();
+        if (splitName != null) {
+            return runRemoveSplit(packageName, splitName);
+        }
+
         userId = translateUserId(userId, "runUninstall");
         if (userId == UserHandle.USER_ALL) {
             userId = UserHandle.USER_SYSTEM;
@@ -670,6 +810,36 @@
         }
     }
 
+    private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
+        sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+        sessionParams.appPackageName = packageName;
+        final int sessionId =
+                doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
+        boolean abandonSession = true;
+        try {
+            if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
+                    != PackageInstaller.STATUS_SUCCESS) {
+                return 1;
+            }
+            if (doCommitSession(sessionId, false /*logSuccess*/)
+                    != PackageInstaller.STATUS_SUCCESS) {
+                return 1;
+            }
+            abandonSession = false;
+            pw.println("Success");
+            return 0;
+        } finally {
+            if (abandonSession) {
+                try {
+                    doAbandonSession(sessionId, false /*logSuccess*/);
+                } catch (Exception ignore) {
+                }
+            }
+        }
+    }
+
     private Intent parseIntentAndUser() throws URISyntaxException {
         mTargetUser = UserHandle.USER_CURRENT;
         Intent intent = Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@@ -718,7 +888,7 @@
         }
         try {
             List<ResolveInfo> result = mInterface.queryIntentActivities(intent, null, 0,
-                    mTargetUser);
+                    mTargetUser).getList();
             PrintWriter pw = getOutPrintWriter();
             if (result == null || result.size() <= 0) {
                 pw.println("No activities found");
@@ -745,7 +915,7 @@
         }
         try {
             List<ResolveInfo> result = mInterface.queryIntentServices(intent, null, 0,
-                    mTargetUser);
+                    mTargetUser).getList();
             PrintWriter pw = getOutPrintWriter();
             if (result == null || result.size() <= 0) {
                 pw.println("No services found");
@@ -772,7 +942,7 @@
         }
         try {
             List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, null, 0,
-                    mTargetUser);
+                    mTargetUser).getList();
             PrintWriter pw = getOutPrintWriter();
             if (result == null || result.size() <= 0) {
                 pw.println("No receivers found");
@@ -872,6 +1042,39 @@
         return params;
     }
 
+    private int runSetHomeActivity() {
+        final PrintWriter pw = getOutPrintWriter();
+        int userId = UserHandle.USER_SYSTEM;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                default:
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+            }
+        }
+
+        String component = getNextArg();
+        ComponentName componentName =
+                component != null ? ComponentName.unflattenFromString(component) : null;
+
+        if (componentName == null) {
+            pw.println("Error: component name not specified or invalid");
+            return 1;
+        }
+
+        try {
+            mInterface.setHomeActivity(componentName, userId);
+            return 0;
+        } catch (RemoteException e) {
+            pw.println(e.toString());
+            return 1;
+        }
+    }
+
     private static String checkAbiArgument(String abi) {
         if (TextUtils.isEmpty(abi)) {
             throw new IllegalArgumentException("Missing ABI argument");
@@ -909,7 +1112,7 @@
         return sessionId;
     }
 
-    private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
+    private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
             boolean logSuccess) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         if ("-".equals(inPath)) {
@@ -965,6 +1168,27 @@
         }
     }
 
+    private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
+            throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        PackageInstaller.Session session = null;
+        try {
+            session = new PackageInstaller.Session(
+                    mInterface.getPackageInstaller().openSession(sessionId));
+            session.removeSplit(splitName);
+
+            if (logSuccess) {
+                pw.println("Success");
+            }
+            return 0;
+        } catch (IOException e) {
+            pw.println("Error: failed to remove split; " + e.getMessage());
+            return 1;
+        } finally {
+            IoUtils.closeQuietly(session);
+        }
+    }
+
     private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         PackageInstaller.Session session = null;
@@ -1051,7 +1275,7 @@
                 prefix = "  ";
             }
             List<PermissionInfo> ps =
-                    mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/);
+                    mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
             final int count = ps.size();
             boolean first = true;
             for (int p = 0 ; p < count ; p++) {
@@ -1139,12 +1363,17 @@
         pw.println("  help");
         pw.println("    Print this help text.");
         pw.println("");
-        pw.println("  compile [-m MODE] [-f] TARGET-PACKAGE");
-        pw.println("    Trigger compilation of TARGET-PACKAGE.");
+        pw.println("  compile [-m MODE] [-f] [-c] [--reset] (-a | TARGET-PACKAGE)");
+        pw.println("    Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".");
         pw.println("    Options:");
-        pw.println("      -m: select compilation mode");
-        pw.println("          MODE can be one of \"default\", \"all\", \"profile\", and \"extract\"");
+        pw.println("      -a: compile all packages");
+        pw.println("      -c: clear profile data before compiling");
         pw.println("      -f: force compilation even if not needed");
+        pw.println("      -m: select compilation mode");
+        pw.println("          MODE can be one of \"default\", \"full\", \"profile\"," +
+                   " and \"extract\"");
+        pw.println("      --reset: restore package to its post-install state");
+        pw.println("          shorthand for \"-c -f -m extract\"");
         pw.println("  list features");
         pw.println("    Prints all features of the system.");
         pw.println("  list instrumentation [-f] [TARGET-PACKAGE]");
@@ -1186,6 +1415,8 @@
         pw.println("    Suspends the specified package (as user).");
         pw.println("  unsuspend [--user USER_ID] TARGET-PACKAGE");
         pw.println("    Unsuspends the specified package (as user).");
+        pw.println("  set-home-activity [--user USER_ID] TARGET-COMPONENT");
+        pw.println("    set the default home activity (aka launcher).");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index e5eec7e..1434718 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -30,6 +30,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Settings base class for pending and resolved classes.
@@ -118,7 +119,14 @@
      * platform will refuse to launch packages in a frozen state.
      */
     boolean frozen = false;
-
+    /**
+     * Non-persisted value. During an "upgrade without restart", we need the set
+     * of all previous code paths so we can surgically add the new APKs to the
+     * active classloader. If at any point an application is upgraded with a
+     * restart, this field will be cleared since the classloader would be created
+     * using the full set of code paths when the package's process is started.
+     */
+    Set<String> oldCodePaths;
     PackageSettingBase origPackage;
 
     /** Package name of the app that installed this package */
diff --git a/services/core/java/com/android/server/pm/ProcessLoggingHandler.java b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
new file mode 100644
index 0000000..c47dda4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app.admin.SecurityLog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import android.util.Slog;
+
+public final class ProcessLoggingHandler extends Handler {
+
+    private static final String TAG = "ProcessLoggingHandler";
+    static final int LOG_APP_PROCESS_START_MSG = 1;
+    static final int INVALIDATE_BASE_APK_HASH_MSG = 2;
+
+    private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap();
+
+    ProcessLoggingHandler() {
+        super(BackgroundThread.getHandler().getLooper());
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case LOG_APP_PROCESS_START_MSG: {
+                Bundle bundle = msg.getData();
+                String processName = bundle.getString("processName");
+                int uid = bundle.getInt("uid");
+                String seinfo = bundle.getString("seinfo");
+                String apkFile = bundle.getString("apkFile");
+                int pid = bundle.getInt("pid");
+                long startTimestamp = bundle.getLong("startTimestamp");
+                String apkHash = computeStringHashOfApk(apkFile);
+                SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName,
+                        startTimestamp, uid, pid, seinfo, apkHash);
+                break;
+            }
+            case INVALIDATE_BASE_APK_HASH_MSG: {
+                Bundle bundle = msg.getData();
+                mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile"));
+                break;
+            }
+        }
+    }
+
+    void invalidateProcessLoggingBaseApkHash(String apkPath) {
+        Bundle data = new Bundle();
+        data.putString("apkFile", apkPath);
+        Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG);
+        msg.setData(data);
+        sendMessage(msg);
+    }
+
+    private String computeStringHashOfApk(String apkFile) {
+        if (apkFile == null) {
+            return "No APK";
+        }
+        String apkHash = mProcessLoggingBaseApkHashes.get(apkFile);
+        if (apkHash == null) {
+            try {
+                byte[] hash = computeHashOfApkFile(apkFile);
+                StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < hash.length; i++) {
+                    sb.append(String.format("%02x", hash[i]));
+                }
+                apkHash = sb.toString();
+                mProcessLoggingBaseApkHashes.put(apkFile, apkHash);
+            } catch (IOException | NoSuchAlgorithmException e) {
+                Slog.w(TAG, "computeStringHashOfApk() failed", e);
+            }
+        }
+        return apkHash != null ? apkHash : "Failed to count APK hash";
+    }
+
+    private byte[] computeHashOfApkFile(String packageArchiveLocation)
+            throws IOException, NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance("SHA-256");
+        FileInputStream input = new FileInputStream(new File(packageArchiveLocation));
+        byte[] buffer = new byte[65536];
+        int size;
+        while ((size = input.read(buffer)) > 0) {
+            md.update(buffer, 0, size);
+        }
+        input.close();
+        return md.digest();
+    }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 690cb98..3c3c576 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -190,6 +190,7 @@
             "all-intent-filter-verifications";
     private static final String TAG_DEFAULT_BROWSER = "default-browser";
     private static final String TAG_VERSION = "version";
+    private static final String TAG_N_WORK = "n-work";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_USER = "user";
@@ -214,6 +215,7 @@
     private static final String ATTR_VOLUME_UUID = "volumeUuid";
     private static final String ATTR_SDK_VERSION = "sdkVersion";
     private static final String ATTR_DATABASE_VERSION = "databaseVersion";
+    private static final String ATTR_DONE = "done";
 
     // Bookkeeping for restored permission grants
     private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
@@ -386,6 +388,17 @@
 
     public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
 
+    /**
+     * Used to track whether N+ work has been done. This is similar to the file-system level
+     * and denotes that first-boot or upgrade-to-N work has been done.
+     *
+     * Note: the flag has been added to a) allow tracking while an API level check is impossible
+     *       and b) to merge upgrade as well as first boot (because the flag is false, by default).
+     *
+     * STOPSHIP: b/27872764
+     */
+    private boolean mIsNWorkDone = false;
+
     Settings(Object lock) {
         this(Environment.getDataDirectory(), lock);
     }
@@ -2327,6 +2340,10 @@
 
             mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
 
+            serializer.startTag(null, TAG_N_WORK);
+            serializer.attribute(null, ATTR_DONE, Boolean.toString(mIsNWorkDone));
+            serializer.endTag(null, TAG_N_WORK);
+
             serializer.endTag(null, "packages");
 
             serializer.endDocument();
@@ -2387,10 +2404,7 @@
             if (DEBUG_KERNEL) Slog.d(TAG, "Dropping mapping " + name);
 
             mKernelMapping.remove(name);
-
-            final File dir = new File(mKernelMappingFilename, name);
-            FileUtils.deleteContents(dir);
-            dir.delete();
+            new File(mKernelMappingFilename, name).delete();
         }
     }
 
@@ -2607,7 +2621,6 @@
         if (pkg.volumeUuid != null) {
             serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
         }
-
         if (pkg.parentPackageName != null) {
             serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
         }
@@ -2864,7 +2877,8 @@
                     ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
                     ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
                     ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
-
+                } else if (TAG_N_WORK.equals(tagName)) {
+                    mIsNWorkDone = XmlUtils.readBooleanAttribute(parser, ATTR_DONE, false);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
                             + parser.getName());
@@ -3052,7 +3066,8 @@
             tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), "  ");
         }
         Intent intent = new Intent();
-        int flags = 0;
+        int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
         intent.setAction(tmpPa.getAction(0));
         for (int i=0; i<tmpPa.countCategories(); i++) {
             String cat = tmpPa.getCategory(i);
@@ -4143,6 +4158,14 @@
         return res;
     }
 
+    public boolean isNWorkDone() {
+        return mIsNWorkDone;
+    }
+
+    void setNWorkDone() {
+        mIsNWorkDone = true;
+    }
+
     static void printFlags(PrintWriter pw, int val, Object[] spec) {
         pw.print("[ ");
         for (int i=0; i<spec.length; i+=2) {
@@ -4174,9 +4197,19 @@
     };
 
     static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
-        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
-        ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+        ApplicationInfo.PRIVATE_FLAG_HIDDEN, "HIDDEN",
         ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+        ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+        ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS, "HAS_DOMAIN_URLS",
+        ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE",
+        ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE, "DIRECT_BOOT_AWARE",
+        ApplicationInfo.PRIVATE_FLAG_AUTOPLAY, "AUTOPLAY",
+        ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, "PARTIALLY_DIRECT_BOOT_AWARE",
+        ApplicationInfo.PRIVATE_FLAG_EPHEMERAL, "EPHEMERAL",
+        ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
+        ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES, "RESIZEABLE_ACTIVITIES",
+        ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
     };
 
     void dumpVersionLPr(IndentingPrintWriter pw) {
@@ -4285,6 +4318,7 @@
         }
         pw.print(prefix); pw.print("  versionCode="); pw.print(ps.versionCode);
         if (ps.pkg != null) {
+            pw.print(" minSdk="); pw.print(ps.pkg.applicationInfo.minSdkVersion);
             pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
         }
         pw.println();
@@ -4319,6 +4353,10 @@
             }
             pw.print(prefix); pw.print("  versionName="); pw.println(ps.pkg.mVersionName);
             pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, ps.pkg); pw.println();
+            final int apkSigningVersion = PackageParser.getApkSigningVersion(ps.pkg);
+            if (apkSigningVersion != PackageParser.APK_SIGNING_UNKNOWN) {
+                pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
+            }
             pw.print(prefix); pw.print("  applicationInfo=");
                 pw.println(ps.pkg.applicationInfo.toString());
             pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
@@ -4434,7 +4472,7 @@
                 if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
                     pw.print(", COSTS_MONEY");
                 }
-                if ((perm.info.flags&PermissionInfo.FLAG_HIDDEN) != 0) {
+                if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) {
                     pw.print(", HIDDEN");
                 }
                 if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
@@ -4444,7 +4482,8 @@
             }
         }
 
-        if ((permissionNames != null || dumpAll) && ps.pkg.requestedPermissions != null
+        if ((permissionNames != null || dumpAll) && ps.pkg != null
+                && ps.pkg.requestedPermissions != null
                 && ps.pkg.requestedPermissions.size() > 0) {
             final ArrayList<String> perms = ps.pkg.requestedPermissions;
             pw.print(prefix); pw.println("  requested permissions:");
@@ -4611,7 +4650,7 @@
             if (p.perm != null) {
                 pw.print("    perm="); pw.println(p.perm);
                 if ((p.perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
-                        || (p.perm.info.flags & PermissionInfo.FLAG_HIDDEN) != 0) {
+                        || (p.perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
                     pw.print("    flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags));
                 }
             }
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
new file mode 100644
index 0000000..c6d66fe
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.pm.ShortcutInfo;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Launcher information used by {@link ShortcutService}.
+ */
+class ShortcutLauncher extends ShortcutPackageItem {
+    private static final String TAG = ShortcutService.TAG;
+
+    static final String TAG_ROOT = "launcher-pins";
+
+    private static final String TAG_PACKAGE = "package";
+    private static final String TAG_PIN = "pin";
+
+    private static final String ATTR_LAUNCHER_USER_ID = "launcher-user";
+    private static final String ATTR_VALUE = "value";
+    private static final String ATTR_PACKAGE_NAME = "package-name";
+    private static final String ATTR_PACKAGE_USER_ID = "package-user";
+
+    private final int mOwnerUserId;
+
+    /**
+     * Package name -> IDs.
+     */
+    final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
+
+    private ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
+            @UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
+        super(launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
+        mOwnerUserId = ownerUserId;
+    }
+
+    public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
+            @UserIdInt int launcherUserId) {
+        this(ownerUserId, packageName, launcherUserId, null);
+    }
+
+    @Override
+    public int getOwnerUserId() {
+        return mOwnerUserId;
+    }
+
+    /**
+     * Called when the new package can't receive the backup, due to signature or version mismatch.
+     */
+    @Override
+    protected void onRestoreBlocked(ShortcutService s) {
+        final ArrayList<PackageWithUser> pinnedPackages =
+                new ArrayList<>(mPinnedShortcuts.keySet());
+        mPinnedShortcuts.clear();
+        for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
+            final PackageWithUser pu = pinnedPackages.get(i);
+            s.getPackageShortcutsLocked(pu.packageName, pu.userId)
+                    .refreshPinnedFlags(s);
+        }
+    }
+
+    @Override
+    protected void onRestored(ShortcutService s) {
+        // Nothing to do.
+    }
+
+    public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId,
+            @NonNull String packageName, @NonNull List<String> ids) {
+        final ShortcutPackage packageShortcuts =
+                s.getPackageShortcutsLocked(packageName, packageUserId);
+
+        final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
+
+        final int idSize = ids.size();
+        if (idSize == 0) {
+            mPinnedShortcuts.remove(pu);
+        } else {
+            final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
+
+            // Pin shortcuts.  Make sure only pin the ones that were visible to the caller.
+            // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
+
+            final ArraySet<String> newSet = new ArraySet<>();
+
+            for (int i = 0; i < idSize; i++) {
+                final String id = ids.get(i);
+                final ShortcutInfo si = packageShortcuts.findShortcutById(id);
+                if (si == null) {
+                    continue;
+                }
+                if (si.isDynamic() || (prevSet != null && prevSet.contains(id))) {
+                    newSet.add(id);
+                }
+            }
+            mPinnedShortcuts.put(pu, newSet);
+        }
+        packageShortcuts.refreshPinnedFlags(s);
+    }
+
+    /**
+     * Return the pinned shortcut IDs for the publisher package.
+     */
+    public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName,
+            @UserIdInt int packageUserId) {
+        return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
+    }
+
+    boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
+        return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
+    }
+
+    /**
+     * Persist.
+     */
+    @Override
+    public void saveToXml(XmlSerializer out, boolean forBackup)
+            throws IOException {
+        final int size = mPinnedShortcuts.size();
+        if (size == 0) {
+            return; // Nothing to write.
+        }
+
+        out.startTag(null, TAG_ROOT);
+        ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
+        ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
+        getPackageInfo().saveToXml(out);
+
+        for (int i = 0; i < size; i++) {
+            final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
+            if (forBackup && (pu.userId != getOwnerUserId())) {
+                continue; // Target package on a different user, skip. (i.e. work profile)
+            }
+
+            out.startTag(null, TAG_PACKAGE);
+            ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName);
+            ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId);
+
+            final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
+            final int idSize = ids.size();
+            for (int j = 0; j < idSize; j++) {
+                ShortcutService.writeTagValue(out, TAG_PIN, ids.valueAt(j));
+            }
+            out.endTag(null, TAG_PACKAGE);
+        }
+
+        out.endTag(null, TAG_ROOT);
+    }
+
+    /**
+     * Load.
+     */
+    public static ShortcutLauncher loadFromXml(XmlPullParser parser, int ownerUserId,
+            boolean fromBackup) throws IOException, XmlPullParserException {
+        final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
+                ATTR_PACKAGE_NAME);
+
+        // If restoring, just use the real user ID.
+        final int launcherUserId =
+                fromBackup ? ownerUserId
+                : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
+
+        final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName,
+                launcherUserId);
+
+        ArraySet<String> ids = null;
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            final int depth = parser.getDepth();
+            final String tag = parser.getName();
+            if (depth == outerDepth + 1) {
+                switch (tag) {
+                    case ShortcutPackageInfo.TAG_ROOT:
+                        ret.getPackageInfo().loadFromXml(parser, fromBackup);
+                        continue;
+                    case TAG_PACKAGE: {
+                        final String packageName = ShortcutService.parseStringAttribute(parser,
+                                ATTR_PACKAGE_NAME);
+                        final int packageUserId = fromBackup ? ownerUserId
+                                : ShortcutService.parseIntAttribute(parser,
+                                ATTR_PACKAGE_USER_ID, ownerUserId);
+                        ids = new ArraySet<>();
+                        ret.mPinnedShortcuts.put(
+                                PackageWithUser.of(packageUserId, packageName), ids);
+                        continue;
+                    }
+                }
+            }
+            if (depth == outerDepth + 2) {
+                switch (tag) {
+                    case TAG_PIN: {
+                        if (ids == null) {
+                            Slog.w(TAG, TAG_PIN + " in invalid place");
+                        } else {
+                            ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE));
+                        }
+                        continue;
+                    }
+                }
+            }
+            ShortcutService.warnForInvalidTag(depth, tag);
+        }
+        return ret;
+    }
+
+    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+        pw.println();
+
+        pw.print(prefix);
+        pw.print("Launcher: ");
+        pw.print(getPackageName());
+        pw.print("  Package user: ");
+        pw.print(getPackageUserId());
+        pw.print("  Owner user: ");
+        pw.print(getOwnerUserId());
+        pw.println();
+
+        getPackageInfo().dump(s, pw, prefix + "  ");
+        pw.println();
+
+        final int size = mPinnedShortcuts.size();
+        for (int i = 0; i < size; i++) {
+            pw.println();
+
+            final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
+            pw.print(prefix);
+            pw.print("  ");
+            pw.print("Package: ");
+            pw.print(pu.packageName);
+            pw.print("  User: ");
+            pw.println(pu.userId);
+
+            final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
+            final int idSize = ids.size();
+
+            for (int j = 0; j < idSize; j++) {
+                pw.print(prefix);
+                pw.print("    Pinned: ");
+                pw.print(ids.valueAt(j));
+                pw.println();
+            }
+        }
+    }
+
+    @VisibleForTesting
+    ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
+        return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
new file mode 100644
index 0000000..1076a7a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.os.PersistableBundle;
+import android.text.format.Formatter;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * Package information used by {@link ShortcutService}.
+ */
+class ShortcutPackage extends ShortcutPackageItem {
+    private static final String TAG = ShortcutService.TAG;
+
+    static final String TAG_ROOT = "package";
+    private static final String TAG_INTENT_EXTRAS = "intent-extras";
+    private static final String TAG_EXTRAS = "extras";
+    private static final String TAG_SHORTCUT = "shortcut";
+
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_DYNAMIC_COUNT = "dynamic-count";
+    private static final String ATTR_CALL_COUNT = "call-count";
+    private static final String ATTR_LAST_RESET = "last-reset";
+    private static final String ATTR_ID = "id";
+    private static final String ATTR_ACTIVITY = "activity";
+    private static final String ATTR_TITLE = "title";
+    private static final String ATTR_TEXT = "text";
+    private static final String ATTR_INTENT = "intent";
+    private static final String ATTR_WEIGHT = "weight";
+    private static final String ATTR_TIMESTAMP = "timestamp";
+    private static final String ATTR_FLAGS = "flags";
+    private static final String ATTR_ICON_RES = "icon-res";
+    private static final String ATTR_BITMAP_PATH = "bitmap-path";
+
+    /**
+     * All the shortcuts from the package, keyed on IDs.
+     */
+    final private ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();
+
+    /**
+     * # of dynamic shortcuts.
+     */
+    private int mDynamicShortcutCount = 0;
+
+    /**
+     * # of times the package has called rate-limited APIs.
+     */
+    private int mApiCallCount;
+
+    /**
+     * When {@link #mApiCallCount} was reset last time.
+     */
+    private long mLastResetTime;
+
+    private ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) {
+        super(packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
+    }
+
+    public ShortcutPackage(int packageUserId, String packageName) {
+        this(packageUserId, packageName, null);
+    }
+
+    @Override
+    public int getOwnerUserId() {
+        // For packages, always owner user == package user.
+        return getPackageUserId();
+    }
+
+    @Override
+    protected void onRestoreBlocked(ShortcutService s) {
+        // Can't restore due to version/signature mismatch.  Remove all shortcuts.
+        mShortcuts.clear();
+    }
+
+    @Override
+    protected void onRestored(ShortcutService s) {
+        // Because some launchers may not have been restored (e.g. allowBackup=false),
+        // we need to re-calculate the pinned shortcuts.
+        refreshPinnedFlags(s);
+    }
+
+    /**
+     * Note this does *not* provide a correct view to the calling launcher.
+     */
+    @Nullable
+    public ShortcutInfo findShortcutById(String id) {
+        return mShortcuts.get(id);
+    }
+
+    private ShortcutInfo deleteShortcut(@NonNull ShortcutService s,
+            @NonNull String id) {
+        final ShortcutInfo shortcut = mShortcuts.remove(id);
+        if (shortcut != null) {
+            s.removeIcon(getPackageUserId(), shortcut);
+            shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED);
+        }
+        return shortcut;
+    }
+
+    void addShortcut(@NonNull ShortcutService s, @NonNull ShortcutInfo newShortcut) {
+        deleteShortcut(s, newShortcut.getId());
+        s.saveIconAndFixUpShortcut(getPackageUserId(), newShortcut);
+        mShortcuts.put(newShortcut.getId(), newShortcut);
+    }
+
+    /**
+     * Add a shortcut, or update one with the same ID, with taking over existing flags.
+     *
+     * It checks the max number of dynamic shortcuts.
+     */
+    public void addDynamicShortcut(@NonNull ShortcutService s,
+            @NonNull ShortcutInfo newShortcut) {
+        newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+
+        final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
+
+        final boolean wasPinned;
+        final int newDynamicCount;
+
+        if (oldShortcut == null) {
+            wasPinned = false;
+            newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
+        } else {
+            wasPinned = oldShortcut.isPinned();
+            if (oldShortcut.isDynamic()) {
+                newDynamicCount = mDynamicShortcutCount; // not adding a dynamic shortcut.
+            } else {
+                newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
+            }
+        }
+
+        // Make sure there's still room.
+        s.enforceMaxDynamicShortcuts(newDynamicCount);
+
+        // Okay, make it dynamic and add.
+        if (wasPinned) {
+            newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
+        }
+
+        addShortcut(s, newShortcut);
+        mDynamicShortcutCount = newDynamicCount;
+    }
+
+    /**
+     * Remove all shortcuts that aren't pinned nor dynamic.
+     */
+    private void removeOrphans(@NonNull ShortcutService s) {
+        ArrayList<String> removeList = null; // Lazily initialize.
+
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+
+            if (si.isPinned() || si.isDynamic()) continue;
+
+            if (removeList == null) {
+                removeList = new ArrayList<>();
+            }
+            removeList.add(si.getId());
+        }
+        if (removeList != null) {
+            for (int i = removeList.size() - 1; i >= 0; i--) {
+                deleteShortcut(s, removeList.get(i));
+            }
+        }
+    }
+
+    /**
+     * Remove all dynamic shortcuts.
+     */
+    public void deleteAllDynamicShortcuts(@NonNull ShortcutService s) {
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+        }
+        removeOrphans(s);
+        mDynamicShortcutCount = 0;
+    }
+
+    /**
+     * Remove a dynamic shortcut by ID.
+     */
+    public void deleteDynamicWithId(@NonNull ShortcutService s, @NonNull String shortcutId) {
+        final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId);
+
+        if (oldShortcut == null) {
+            return;
+        }
+        if (oldShortcut.isDynamic()) {
+            mDynamicShortcutCount--;
+        }
+        if (oldShortcut.isPinned()) {
+            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+        } else {
+            deleteShortcut(s, shortcutId);
+        }
+    }
+
+    /**
+     * Called after a launcher updates the pinned set.  For each shortcut in this package,
+     * set FLAG_PINNED if any launcher has pinned it.  Otherwise, clear it.
+     *
+     * <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
+     */
+    public void refreshPinnedFlags(@NonNull ShortcutService s) {
+        // First, un-pin all shortcuts
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
+        }
+
+        // Then, for the pinned set for each launcher, set the pin flag one by one.
+        final ArrayMap<ShortcutUser.PackageWithUser, ShortcutLauncher> launchers =
+                s.getUserShortcutsLocked(getPackageUserId()).getAllLaunchers();
+
+        for (int l = launchers.size() - 1; l >= 0; l--) {
+            // Note even if a launcher that hasn't been installed can still pin shortcuts.
+
+            final ShortcutLauncher launcherShortcuts = launchers.valueAt(l);
+            final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
+                    getPackageName(), getPackageUserId());
+
+            if (pinned == null || pinned.size() == 0) {
+                continue;
+            }
+            for (int i = pinned.size() - 1; i >= 0; i--) {
+                final String id = pinned.valueAt(i);
+                final ShortcutInfo si = mShortcuts.get(id);
+                if (si == null) {
+                    // This happens if a launcher pinned shortcuts from this package, then backup&
+                    // restored, but this package doesn't allow backing up.
+                    // In that case the launcher ends up having a dangling pinned shortcuts.
+                    // That's fine, when the launcher is restored, we'll fix it.
+                    continue;
+                }
+                si.addFlags(ShortcutInfo.FLAG_PINNED);
+            }
+        }
+
+        // Lastly, remove the ones that are no longer pinned nor dynamic.
+        removeOrphans(s);
+    }
+
+    /**
+     * Number of calls that the caller has made, since the last reset.
+     */
+    public int getApiCallCount(@NonNull ShortcutService s) {
+        final long last = s.getLastResetTimeLocked();
+
+        final long now = s.injectCurrentTimeMillis();
+        if (ShortcutService.isClockValid(now) && mLastResetTime > now) {
+            Slog.w(TAG, "Clock rewound");
+            // Clock rewound.
+            mLastResetTime = now;
+            mApiCallCount = 0;
+            return mApiCallCount;
+        }
+
+        // If not reset yet, then reset.
+        if (mLastResetTime < last) {
+            if (ShortcutService.DEBUG) {
+                Slog.d(TAG, String.format("My last reset=%d, now=%d, last=%d: resetting",
+                        mLastResetTime, now, last));
+            }
+            mApiCallCount = 0;
+            mLastResetTime = last;
+        }
+        return mApiCallCount;
+    }
+
+    /**
+     * If the caller app hasn't been throttled yet, increment {@link #mApiCallCount}
+     * and return true.  Otherwise just return false.
+     */
+    public boolean tryApiCall(@NonNull ShortcutService s) {
+        if (getApiCallCount(s) >= s.mMaxDailyUpdates) {
+            return false;
+        }
+        mApiCallCount++;
+        return true;
+    }
+
+    public void resetRateLimitingForCommandLine() {
+        mApiCallCount = 0;
+        mLastResetTime = 0;
+    }
+
+    /**
+     * Find all shortcuts that match {@code query}.
+     */
+    public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
+            @Nullable Predicate<ShortcutInfo> query, int cloneFlag) {
+        findAll(s, result, query, cloneFlag, null, 0);
+    }
+
+    /**
+     * Find all shortcuts that match {@code query}.
+     *
+     * This will also provide a "view" for each launcher -- a non-dynamic shortcut that's not pinned
+     * by the calling launcher will not be included in the result, and also "isPinned" will be
+     * adjusted for the caller too.
+     */
+    public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
+            @Nullable Predicate<ShortcutInfo> query, int cloneFlag,
+            @Nullable String callingLauncher, int launcherUserId) {
+        if (getPackageInfo().isShadow()) {
+            // Restored and the app not installed yet, so don't return any.
+            return;
+        }
+
+        // Set of pinned shortcuts by the calling launcher.
+        final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
+                : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
+                    .getPinnedShortcutIds(getPackageName(), getPackageUserId());
+
+        for (int i = 0; i < mShortcuts.size(); i++) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+
+            // If it's called by non-launcher (i.e. publisher, always include -> true.
+            // Otherwise, only include non-dynamic pinned one, if the calling launcher has pinned
+            // it.
+            final boolean isPinnedByCaller = (callingLauncher == null)
+                    || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
+            if (!si.isDynamic()) {
+                if (!si.isPinned()) {
+                    s.wtf("Shortcut not pinned: package " + getPackageName()
+                            + ", user=" + getPackageUserId() + ", id=" + si.getId());
+                    continue;
+                }
+                if (!isPinnedByCaller) {
+                    continue;
+                }
+            }
+            final ShortcutInfo clone = si.clone(cloneFlag);
+            // Fix up isPinned for the caller.  Note we need to do it before the "test" callback,
+            // since it may check isPinned.
+            if (!isPinnedByCaller) {
+                clone.clearFlags(ShortcutInfo.FLAG_PINNED);
+            }
+            if (query == null || query.test(clone)) {
+                result.add(clone);
+            }
+        }
+    }
+
+    public void resetThrottling() {
+        mApiCallCount = 0;
+    }
+
+    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+        pw.println();
+
+        pw.print(prefix);
+        pw.print("Package: ");
+        pw.print(getPackageName());
+        pw.println();
+
+        pw.print(prefix);
+        pw.print("  ");
+        pw.print("Calls: ");
+        pw.print(getApiCallCount(s));
+        pw.println();
+
+        // This should be after getApiCallCount(), which may update it.
+        pw.print(prefix);
+        pw.print("  ");
+        pw.print("Last reset: [");
+        pw.print(mLastResetTime);
+        pw.print("] ");
+        pw.print(s.formatTime(mLastResetTime));
+        pw.println();
+
+        getPackageInfo().dump(s, pw, prefix + "  ");
+        pw.println();
+
+        pw.println("      Shortcuts:");
+        long totalBitmapSize = 0;
+        final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts;
+        final int size = shortcuts.size();
+        for (int i = 0; i < size; i++) {
+            final ShortcutInfo si = shortcuts.valueAt(i);
+            pw.print("        ");
+            pw.println(si.toInsecureString());
+            if (si.getBitmapPath() != null) {
+                final long len = new File(si.getBitmapPath()).length();
+                pw.print("          ");
+                pw.print("bitmap size=");
+                pw.println(len);
+
+                totalBitmapSize += len;
+            }
+        }
+        pw.print(prefix);
+        pw.print("  ");
+        pw.print("Total bitmap size: ");
+        pw.print(totalBitmapSize);
+        pw.print(" (");
+        pw.print(Formatter.formatFileSize(s.mContext, totalBitmapSize));
+        pw.println(")");
+    }
+
+    @Override
+    public void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+            throws IOException, XmlPullParserException {
+        final int size = mShortcuts.size();
+
+        if (size == 0 && mApiCallCount == 0) {
+            return; // nothing to write.
+        }
+
+        out.startTag(null, TAG_ROOT);
+
+        ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
+        ShortcutService.writeAttr(out, ATTR_DYNAMIC_COUNT, mDynamicShortcutCount);
+        ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
+        ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
+        getPackageInfo().saveToXml(out);
+
+        for (int j = 0; j < size; j++) {
+            saveShortcut(out, mShortcuts.valueAt(j), forBackup);
+        }
+
+        out.endTag(null, TAG_ROOT);
+    }
+
+    private static void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup)
+            throws IOException, XmlPullParserException {
+        if (forBackup) {
+            if (!si.isPinned()) {
+                return; // Backup only pinned icons.
+            }
+        }
+        out.startTag(null, TAG_SHORTCUT);
+        ShortcutService.writeAttr(out, ATTR_ID, si.getId());
+        // writeAttr(out, "package", si.getPackageName()); // not needed
+        ShortcutService.writeAttr(out, ATTR_ACTIVITY, si.getActivityComponent());
+        // writeAttr(out, "icon", si.getIcon());  // We don't save it.
+        ShortcutService.writeAttr(out, ATTR_TITLE, si.getTitle());
+        ShortcutService.writeAttr(out, ATTR_TEXT, si.getText());
+        ShortcutService.writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
+        ShortcutService.writeAttr(out, ATTR_WEIGHT, si.getWeight());
+        ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
+                si.getLastChangedTimestamp());
+        if (forBackup) {
+            // Don't write icon information.  Also drop the dynamic flag.
+            ShortcutService.writeAttr(out, ATTR_FLAGS,
+                    si.getFlags() &
+                            ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES
+                            | ShortcutInfo.FLAG_DYNAMIC));
+        } else {
+            ShortcutService.writeAttr(out, ATTR_FLAGS, si.getFlags());
+            ShortcutService.writeAttr(out, ATTR_ICON_RES, si.getIconResourceId());
+            ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath());
+        }
+
+        ShortcutService.writeTagExtra(out, TAG_INTENT_EXTRAS,
+                si.getIntentPersistableExtras());
+        ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
+
+        out.endTag(null, TAG_SHORTCUT);
+    }
+
+    public static ShortcutPackage loadFromXml(ShortcutService s, XmlPullParser parser,
+            int ownerUserId, boolean fromBackup)
+            throws IOException, XmlPullParserException {
+
+        final String packageName = ShortcutService.parseStringAttribute(parser,
+                ATTR_NAME);
+
+        final ShortcutPackage ret = new ShortcutPackage(ownerUserId, packageName);
+
+        ret.mDynamicShortcutCount =
+                ShortcutService.parseIntAttribute(parser, ATTR_DYNAMIC_COUNT);
+        ret.mApiCallCount =
+                ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
+        ret.mLastResetTime =
+                ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            final int depth = parser.getDepth();
+            final String tag = parser.getName();
+            if (depth == outerDepth + 1) {
+                switch (tag) {
+                    case ShortcutPackageInfo.TAG_ROOT:
+                        ret.getPackageInfo().loadFromXml(parser, fromBackup);
+                        continue;
+                    case TAG_SHORTCUT:
+                        final ShortcutInfo si = parseShortcut(parser, packageName);
+
+                        // Don't use addShortcut(), we don't need to save the icon.
+                        ret.mShortcuts.put(si.getId(), si);
+                        continue;
+                }
+            }
+            ShortcutService.warnForInvalidTag(depth, tag);
+        }
+        return ret;
+    }
+
+    private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName)
+            throws IOException, XmlPullParserException {
+        String id;
+        ComponentName activityComponent;
+        // Icon icon;
+        String title;
+        String text;
+        Intent intent;
+        PersistableBundle intentPersistableExtras = null;
+        int weight;
+        PersistableBundle extras = null;
+        long lastChangedTimestamp;
+        int flags;
+        int iconRes;
+        String bitmapPath;
+
+        id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
+        activityComponent = ShortcutService.parseComponentNameAttribute(parser,
+                ATTR_ACTIVITY);
+        title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE);
+        text = ShortcutService.parseStringAttribute(parser, ATTR_TEXT);
+        intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
+        weight = (int) ShortcutService.parseLongAttribute(parser, ATTR_WEIGHT);
+        lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
+        flags = (int) ShortcutService.parseLongAttribute(parser, ATTR_FLAGS);
+        iconRes = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES);
+        bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH);
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            final int depth = parser.getDepth();
+            final String tag = parser.getName();
+            if (ShortcutService.DEBUG_LOAD) {
+                Slog.d(TAG, String.format("  depth=%d type=%d name=%s",
+                        depth, type, tag));
+            }
+            switch (tag) {
+                case TAG_INTENT_EXTRAS:
+                    intentPersistableExtras = PersistableBundle.restoreFromXml(parser);
+                    continue;
+                case TAG_EXTRAS:
+                    extras = PersistableBundle.restoreFromXml(parser);
+                    continue;
+            }
+            throw ShortcutService.throwForInvalidTag(depth, tag);
+        }
+        return new ShortcutInfo(
+                id, packageName, activityComponent, /* icon =*/ null, title, text, intent,
+                intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
+                iconRes, bitmapPath);
+    }
+
+    @VisibleForTesting
+    List<ShortcutInfo> getAllShortcutsForTest() {
+        return new ArrayList<>(mShortcuts.values());
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
new file mode 100644
index 0000000..2c45890
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.UserIdInt;
+import android.content.pm.PackageInfo;
+import android.util.Slog;
+
+import com.android.server.backup.BackupUtils;
+
+import libcore.io.Base64;
+import libcore.util.HexEncoding;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
+ */
+class ShortcutPackageInfo {
+    private static final String TAG = ShortcutService.TAG;
+
+    static final String TAG_ROOT = "package-info";
+    private static final String ATTR_VERSION = "version";
+    private static final String ATTR_SHADOW = "shadow";
+
+    private static final String TAG_SIGNATURE = "signature";
+    private static final String ATTR_SIGNATURE_HASH = "hash";
+
+    /**
+     * When true, this package information was restored from the previous device, and the app hasn't
+     * been installed yet.
+     */
+    private boolean mIsShadow;
+    private int mVersionCode;
+    private ArrayList<byte[]> mSigHashes;
+
+    private ShortcutPackageInfo(int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) {
+        mVersionCode = versionCode;
+        mIsShadow = isShadow;
+        mSigHashes = sigHashes;
+    }
+
+    public static ShortcutPackageInfo newEmpty() {
+        return new ShortcutPackageInfo(0, new ArrayList<>(0), /* isShadow */ false);
+    }
+
+    public boolean isShadow() {
+        return mIsShadow;
+    }
+
+    public void setShadow(boolean shadow) {
+        mIsShadow = shadow;
+    }
+
+    public int getVersionCode() {
+        return mVersionCode;
+    }
+
+    public boolean hasSignatures() {
+        return mSigHashes.size() > 0;
+    }
+
+    public boolean canRestoreTo(ShortcutService s, PackageInfo target) {
+        if (!s.shouldBackupApp(target)) {
+            // "allowBackup" was true when backed up, but now false.
+            Slog.w(TAG, "Can't restore: package no longer allows backup");
+            return false;
+        }
+        if (target.versionCode < mVersionCode) {
+            Slog.w(TAG, String.format(
+                    "Can't restore: package current version %d < backed up version %d",
+                    target.versionCode, mVersionCode));
+            return false;
+        }
+        if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
+            Slog.w(TAG, "Can't restore: Package signature mismatch");
+            return false;
+        }
+        return true;
+    }
+
+    public static ShortcutPackageInfo generateForInstalledPackage(
+            ShortcutService s, String packageName, @UserIdInt int packageUserId) {
+        final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
+        if (pi.signatures == null || pi.signatures.length == 0) {
+            Slog.e(TAG, "Can't get signatures: package=" + packageName);
+            return null;
+        }
+        final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode,
+                BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
+
+        return ret;
+    }
+
+    public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
+        if (mIsShadow) {
+            s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
+                    + ", user=" + pkg.getOwnerUserId());
+            return;
+        }
+        // Note use mUserId here, rather than userId.
+        final PackageInfo pi = s.getPackageInfoWithSignatures(
+                pkg.getPackageName(), pkg.getPackageUserId());
+        if (pi == null) {
+            Slog.w(TAG, "Package not found: " + pkg.getPackageName());
+            return;
+        }
+        mVersionCode = pi.versionCode;
+        mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
+    }
+
+    public void saveToXml(XmlSerializer out) throws IOException {
+
+        out.startTag(null, TAG_ROOT);
+
+        ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
+        ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
+
+        for (int i = 0; i < mSigHashes.size(); i++) {
+            out.startTag(null, TAG_SIGNATURE);
+            ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, Base64.encode(mSigHashes.get(i)));
+            out.endTag(null, TAG_SIGNATURE);
+        }
+        out.endTag(null, TAG_ROOT);
+    }
+
+    public void loadFromXml(XmlPullParser parser, boolean fromBackup)
+            throws IOException, XmlPullParserException {
+
+        final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
+
+        // When restoring from backup, it's always shadow.
+        final boolean shadow =
+                fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
+
+        final ArrayList<byte[]> hashes = new ArrayList<>();
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            final int depth = parser.getDepth();
+            final String tag = parser.getName();
+
+            if (depth == outerDepth + 1) {
+                switch (tag) {
+                    case TAG_SIGNATURE: {
+                        final String hash = ShortcutService.parseStringAttribute(
+                                parser, ATTR_SIGNATURE_HASH);
+                        hashes.add(Base64.decode(hash.getBytes()));
+                        continue;
+                    }
+                }
+            }
+            ShortcutService.warnForInvalidTag(depth, tag);
+        }
+
+        // Successfully loaded; replace the feilds.
+        mVersionCode = versionCode;
+        mIsShadow = shadow;
+        mSigHashes = hashes;
+    }
+
+    public void dump(ShortcutService s, PrintWriter pw, String prefix) {
+        pw.println();
+
+        pw.print(prefix);
+        pw.println("PackageInfo:");
+
+        pw.print(prefix);
+        pw.print("  IsShadow: ");
+        pw.print(mIsShadow);
+        pw.println();
+
+        pw.print(prefix);
+        pw.print("  Version: ");
+        pw.print(mVersionCode);
+        pw.println();
+
+        for (int i = 0; i < mSigHashes.size(); i++) {
+            pw.print(prefix);
+            pw.print("    ");
+            pw.print("SigHash: ");
+            pw.println(HexEncoding.encode(mSigHashes.get(i)));
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
new file mode 100644
index 0000000..f31dd17
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
+abstract class ShortcutPackageItem {
+    private static final String TAG = ShortcutService.TAG;
+
+    private final int mPackageUserId;
+    private final String mPackageName;
+
+    private final ShortcutPackageInfo mPackageInfo;
+
+    protected ShortcutPackageItem(int packageUserId, @NonNull String packageName,
+            @NonNull ShortcutPackageInfo packageInfo) {
+        mPackageUserId = packageUserId;
+        mPackageName = Preconditions.checkStringNotEmpty(packageName);
+        mPackageInfo = Preconditions.checkNotNull(packageInfo);
+    }
+
+    /**
+     * ID of the user who actually has this package running on.  For {@link ShortcutPackage},
+     * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
+     * {@link #getOwnerUserId} is of a work profile, then this ID could be the user who owns the
+     * profile.
+     */
+    public int getPackageUserId() {
+        return mPackageUserId;
+    }
+
+    /**
+     * ID of the user who sees the shortcuts from this instance.
+     */
+    public abstract int getOwnerUserId();
+
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    public ShortcutPackageInfo getPackageInfo() {
+        return mPackageInfo;
+    }
+
+    public void refreshPackageInfoAndSave(ShortcutService s) {
+        if (mPackageInfo.isShadow()) {
+            return; // Don't refresh for shadow user.
+        }
+        mPackageInfo.refresh(s, this);
+        s.scheduleSaveUser(getOwnerUserId());
+    }
+
+    public void attemptToRestoreIfNeededAndSave(ShortcutService s) {
+        if (!mPackageInfo.isShadow()) {
+            return; // Already installed, nothing to do.
+        }
+        if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
+            if (ShortcutService.DEBUG) {
+                Slog.d(TAG, String.format("Package still not installed: %s user=%d",
+                        mPackageName, mPackageUserId));
+            }
+            return; // Not installed, no need to restore yet.
+        }
+        if (!mPackageInfo.hasSignatures()) {
+            s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
+                    + " but signatures not found in the restore data.");
+            onRestoreBlocked(s);
+            return;
+        }
+
+        final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
+        if (!mPackageInfo.canRestoreTo(s, pi)) {
+            // Package is now installed, but can't restore.  Let the subclass do the cleanup.
+            onRestoreBlocked(s);
+            return;
+        }
+        if (ShortcutService.DEBUG) {
+            Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
+                    mPackageUserId, getOwnerUserId()));
+        }
+
+        onRestored(s);
+
+        // Now the package is not shadow.
+        mPackageInfo.setShadow(false);
+
+        s.scheduleSaveUser(mPackageUserId);
+    }
+
+    /**
+     * Called when the new package can't be restored because it has a lower version number
+     * or different signatures.
+     */
+    protected abstract void onRestoreBlocked(ShortcutService s);
+
+    /**
+     * Called when the new package is successfully restored.
+     */
+    protected abstract void onRestored(ShortcutService s);
+
+    public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+            throws IOException, XmlPullParserException;
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
new file mode 100644
index 0000000..5c1e7a8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -0,0 +1,2396 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.IShortcutService;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutServiceInternal;
+import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.SELinux;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.text.format.Time;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+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.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * TODO:
+ *
+ * - Default launcher check does take a few ms.  Worth caching.
+ *
+ * - Clear data -> remove all dynamic?  but not the pinned?
+ *
+ * - Scan and remove orphan bitmaps (just in case).
+ *
+ * - Detect when already registered instances are passed to APIs again, which might break
+ *   internal bitmap handling.
+ *
+ * - Add more call stats.
+ */
+public class ShortcutService extends IShortcutService.Stub {
+    static final String TAG = "ShortcutService";
+
+    static final boolean DEBUG = false; // STOPSHIP if true
+    static final boolean DEBUG_LOAD = false; // STOPSHIP if true
+
+    @VisibleForTesting
+    static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
+
+    @VisibleForTesting
+    static final int DEFAULT_MAX_DAILY_UPDATES = 10;
+
+    @VisibleForTesting
+    static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5;
+
+    @VisibleForTesting
+    static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96;
+
+    @VisibleForTesting
+    static final int DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP = 48;
+
+    @VisibleForTesting
+    static final String DEFAULT_ICON_PERSIST_FORMAT = CompressFormat.PNG.name();
+
+    @VisibleForTesting
+    static final int DEFAULT_ICON_PERSIST_QUALITY = 100;
+
+    @VisibleForTesting
+    static final int DEFAULT_SAVE_DELAY_MS = 3000;
+
+    @VisibleForTesting
+    static final String FILENAME_BASE_STATE = "shortcut_service.xml";
+
+    @VisibleForTesting
+    static final String DIRECTORY_PER_USER = "shortcut_service";
+
+    @VisibleForTesting
+    static final String FILENAME_USER_PACKAGES = "shortcuts.xml";
+
+    static final String DIRECTORY_BITMAPS = "bitmaps";
+
+    private static final String TAG_ROOT = "root";
+    private static final String TAG_LAST_RESET_TIME = "last_reset_time";
+
+    private static final String ATTR_VALUE = "value";
+
+    @VisibleForTesting
+    interface ConfigConstants {
+        /**
+         * Key name for the save delay, in milliseconds. (int)
+         */
+        String KEY_SAVE_DELAY_MILLIS = "save_delay_ms";
+
+        /**
+         * Key name for the throttling reset interval, in seconds. (long)
+         */
+        String KEY_RESET_INTERVAL_SEC = "reset_interval_sec";
+
+        /**
+         * Key name for the max number of modifying API calls per app for every interval. (int)
+         */
+        String KEY_MAX_DAILY_UPDATES = "max_daily_updates";
+
+        /**
+         * Key name for the max icon dimensions in DP, for non-low-memory devices.
+         */
+        String KEY_MAX_ICON_DIMENSION_DP = "max_icon_dimension_dp";
+
+        /**
+         * Key name for the max icon dimensions in DP, for low-memory devices.
+         */
+        String KEY_MAX_ICON_DIMENSION_DP_LOWRAM = "max_icon_dimension_dp_lowram";
+
+        /**
+         * Key name for the max dynamic shortcuts per app. (int)
+         */
+        String KEY_MAX_SHORTCUTS = "max_shortcuts";
+
+        /**
+         * Key name for icon compression quality, 0-100.
+         */
+        String KEY_ICON_QUALITY = "icon_quality";
+
+        /**
+         * Key name for icon compression format: "PNG", "JPEG" or "WEBP"
+         */
+        String KEY_ICON_FORMAT = "icon_format";
+    }
+
+    final Context mContext;
+
+    private final Object mLock = new Object();
+
+    private final Handler mHandler;
+
+    @GuardedBy("mLock")
+    private final ArrayList<ShortcutChangeListener> mListeners = new ArrayList<>(1);
+
+    @GuardedBy("mLock")
+    private long mRawLastResetTime;
+
+    /**
+     * User ID -> UserShortcuts
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<ShortcutUser> mUsers = new SparseArray<>();
+
+    /**
+     * Max number of dynamic shortcuts that each application can have at a time.
+     */
+    private int mMaxDynamicShortcuts;
+
+    /**
+     * Max number of updating API calls that each application can make a day.
+     */
+    int mMaxDailyUpdates;
+
+    /**
+     * Actual throttling-reset interval.  By default it's a day.
+     */
+    private long mResetInterval;
+
+    /**
+     * Icon max width/height in pixels.
+     */
+    private int mMaxIconDimension;
+
+    private CompressFormat mIconPersistFormat;
+    private int mIconPersistQuality;
+
+    private int mSaveDelayMillis;
+
+    private final IPackageManager mIPackageManager;
+    private final PackageManagerInternal mPackageManagerInternal;
+    private final UserManager mUserManager;
+
+    @GuardedBy("mLock")
+    private List<Integer> mDirtyUserIds = new ArrayList<>();
+
+    private static final int PACKAGE_MATCH_FLAGS =
+            PackageManager.MATCH_DIRECT_BOOT_AWARE
+            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+            | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+
+    // Stats
+    @VisibleForTesting
+    interface Stats {
+        int GET_DEFAULT_HOME = 0;
+        int GET_PACKAGE_INFO = 1;
+        int GET_PACKAGE_INFO_WITH_SIG = 2;
+        int GET_APPLICATION_INFO = 3;
+        int LAUNCHER_PERMISSION_CHECK = 4;
+
+        int COUNT = LAUNCHER_PERMISSION_CHECK + 1;
+    }
+
+    final Object mStatLock = new Object();
+
+    @GuardedBy("mStatLock")
+    private final int[] mCountStats = new int[Stats.COUNT];
+
+    @GuardedBy("mStatLock")
+    private final long[] mDurationStats = new long[Stats.COUNT];
+
+    public ShortcutService(Context context) {
+        this(context, BackgroundThread.get().getLooper());
+    }
+
+    @VisibleForTesting
+    ShortcutService(Context context, Looper looper) {
+        mContext = Preconditions.checkNotNull(context);
+        LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
+        mHandler = new Handler(looper);
+        mIPackageManager = AppGlobals.getPackageManager();
+        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+        mUserManager = context.getSystemService(UserManager.class);
+
+        mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
+    }
+
+    void logDurationStat(int statId, long start) {
+        synchronized (mStatLock) {
+            mCountStats[statId]++;
+            mDurationStats[statId] += (System.currentTimeMillis() - start);
+        }
+    }
+
+    /**
+     * System service lifecycle.
+     */
+    public static final class Lifecycle extends SystemService {
+        final ShortcutService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new ShortcutService(context);
+        }
+
+        @Override
+        public void onStart() {
+            publishBinderService(Context.SHORTCUT_SERVICE, mService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            mService.onBootPhase(phase);
+        }
+
+        @Override
+        public void onCleanupUser(int userHandle) {
+            mService.handleCleanupUser(userHandle);
+        }
+
+        @Override
+        public void onUnlockUser(int userId) {
+            mService.handleUnlockUser(userId);
+        }
+    }
+
+    /** lifecycle event */
+    void onBootPhase(int phase) {
+        if (DEBUG) {
+            Slog.d(TAG, "onBootPhase: " + phase);
+        }
+        switch (phase) {
+            case SystemService.PHASE_LOCK_SETTINGS_READY:
+                initialize();
+                break;
+        }
+    }
+
+    /** lifecycle event */
+    void handleUnlockUser(int userId) {
+        synchronized (mLock) {
+            // Preload
+            getUserShortcutsLocked(userId);
+
+            cleanupGonePackages(userId);
+        }
+    }
+
+    /** lifecycle event */
+    void handleCleanupUser(int userId) {
+        synchronized (mLock) {
+            unloadUserLocked(userId);
+        }
+    }
+
+    private void unloadUserLocked(int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "unloadUserLocked: user=" + userId);
+        }
+        // Save all dirty information.
+        saveDirtyInfo();
+
+        // Unload
+        mUsers.delete(userId);
+    }
+
+    /** Return the base state file name */
+    private AtomicFile getBaseStateFile() {
+        final File path = new File(injectSystemDataPath(), FILENAME_BASE_STATE);
+        path.mkdirs();
+        return new AtomicFile(path);
+    }
+
+    /**
+     * Init the instance. (load the state file, etc)
+     */
+    private void initialize() {
+        synchronized (mLock) {
+            loadConfigurationLocked();
+            loadBaseStateLocked();
+        }
+    }
+
+    /**
+     * Load the configuration from Settings.
+     */
+    private void loadConfigurationLocked() {
+        updateConfigurationLocked(injectShortcutManagerConstants());
+    }
+
+    /**
+     * Load the configuration from Settings.
+     */
+    @VisibleForTesting
+    boolean updateConfigurationLocked(String config) {
+        boolean result = true;
+
+        final KeyValueListParser parser = new KeyValueListParser(',');
+        try {
+            parser.setString(config);
+        } catch (IllegalArgumentException e) {
+            // Failed to parse the settings string, log this and move on
+            // with defaults.
+            Slog.e(TAG, "Bad shortcut manager settings", e);
+            result = false;
+        }
+
+        mSaveDelayMillis = (int) parser.getLong(ConfigConstants.KEY_SAVE_DELAY_MILLIS,
+                DEFAULT_SAVE_DELAY_MS);
+
+        mResetInterval = parser.getLong(
+                ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC)
+                * 1000L;
+
+        mMaxDailyUpdates = (int) parser.getLong(
+                ConfigConstants.KEY_MAX_DAILY_UPDATES, DEFAULT_MAX_DAILY_UPDATES);
+
+        mMaxDynamicShortcuts = (int) parser.getLong(
+                ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP);
+
+        final int iconDimensionDp = injectIsLowRamDevice()
+                ? (int) parser.getLong(
+                    ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
+                    DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP)
+                : (int) parser.getLong(
+                    ConfigConstants.KEY_MAX_ICON_DIMENSION_DP,
+                    DEFAULT_MAX_ICON_DIMENSION_DP);
+
+        mMaxIconDimension = injectDipToPixel(iconDimensionDp);
+
+        mIconPersistFormat = CompressFormat.valueOf(
+                parser.getString(ConfigConstants.KEY_ICON_FORMAT, DEFAULT_ICON_PERSIST_FORMAT));
+
+        mIconPersistQuality = (int) parser.getLong(
+                ConfigConstants.KEY_ICON_QUALITY,
+                DEFAULT_ICON_PERSIST_QUALITY);
+
+        return result;
+    }
+
+    @VisibleForTesting
+    String injectShortcutManagerConstants() {
+        return android.provider.Settings.Global.getString(
+                mContext.getContentResolver(),
+                android.provider.Settings.Global.SHORTCUT_MANAGER_CONSTANTS);
+    }
+
+    @VisibleForTesting
+    int injectDipToPixel(int dip) {
+        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
+                mContext.getResources().getDisplayMetrics());
+    }
+
+    // === Persisting ===
+
+    @Nullable
+    static String parseStringAttribute(XmlPullParser parser, String attribute) {
+        return parser.getAttributeValue(null, attribute);
+    }
+
+    static boolean parseBooleanAttribute(XmlPullParser parser, String attribute) {
+        return parseLongAttribute(parser, attribute) == 1;
+    }
+
+    static int parseIntAttribute(XmlPullParser parser, String attribute) {
+        return (int) parseLongAttribute(parser, attribute);
+    }
+
+    static int parseIntAttribute(XmlPullParser parser, String attribute, int def) {
+        return (int) parseLongAttribute(parser, attribute, def);
+    }
+
+    static long parseLongAttribute(XmlPullParser parser, String attribute) {
+        return parseLongAttribute(parser, attribute, 0);
+    }
+
+    static long parseLongAttribute(XmlPullParser parser, String attribute, long def) {
+        final String value = parseStringAttribute(parser, attribute);
+        if (TextUtils.isEmpty(value)) {
+            return def;
+        }
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            Slog.e(TAG, "Error parsing long " + value);
+            return def;
+        }
+    }
+
+    @Nullable
+    static ComponentName parseComponentNameAttribute(XmlPullParser parser, String attribute) {
+        final String value = parseStringAttribute(parser, attribute);
+        if (TextUtils.isEmpty(value)) {
+            return null;
+        }
+        return ComponentName.unflattenFromString(value);
+    }
+
+    @Nullable
+    static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
+        final String value = parseStringAttribute(parser, attribute);
+        if (TextUtils.isEmpty(value)) {
+            return null;
+        }
+        try {
+            return Intent.parseUri(value, /* flags =*/ 0);
+        } catch (URISyntaxException e) {
+            Slog.e(TAG, "Error parsing intent", e);
+            return null;
+        }
+    }
+
+    static void writeTagValue(XmlSerializer out, String tag, String value) throws IOException {
+        if (TextUtils.isEmpty(value)) return;
+
+        out.startTag(null, tag);
+        out.attribute(null, ATTR_VALUE, value);
+        out.endTag(null, tag);
+    }
+
+    static void writeTagValue(XmlSerializer out, String tag, long value) throws IOException {
+        writeTagValue(out, tag, Long.toString(value));
+    }
+
+    static void writeTagValue(XmlSerializer out, String tag, ComponentName name) throws IOException {
+        if (name == null) return;
+        writeTagValue(out, tag, name.flattenToString());
+    }
+
+    static void writeTagExtra(XmlSerializer out, String tag, PersistableBundle bundle)
+            throws IOException, XmlPullParserException {
+        if (bundle == null) return;
+
+        out.startTag(null, tag);
+        bundle.saveToXml(out);
+        out.endTag(null, tag);
+    }
+
+    static void writeAttr(XmlSerializer out, String name, String value) throws IOException {
+        if (TextUtils.isEmpty(value)) return;
+
+        out.attribute(null, name, value);
+    }
+
+    static void writeAttr(XmlSerializer out, String name, long value) throws IOException {
+        writeAttr(out, name, String.valueOf(value));
+    }
+
+    static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException {
+        if (value) {
+            writeAttr(out, name, "1");
+        }
+    }
+
+    static void writeAttr(XmlSerializer out, String name, ComponentName comp) throws IOException {
+        if (comp == null) return;
+        writeAttr(out, name, comp.flattenToString());
+    }
+
+    static void writeAttr(XmlSerializer out, String name, Intent intent) throws IOException {
+        if (intent == null) return;
+
+        writeAttr(out, name, intent.toUri(/* flags =*/ 0));
+    }
+
+    @VisibleForTesting
+    void saveBaseStateLocked() {
+        final AtomicFile file = getBaseStateFile();
+        if (DEBUG) {
+            Slog.d(TAG, "Saving to " + file.getBaseFile());
+        }
+
+        FileOutputStream outs = null;
+        try {
+            outs = file.startWrite();
+
+            // Write to XML
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(outs, StandardCharsets.UTF_8.name());
+            out.startDocument(null, true);
+            out.startTag(null, TAG_ROOT);
+
+            // Body.
+            writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime);
+
+            // Epilogue.
+            out.endTag(null, TAG_ROOT);
+            out.endDocument();
+
+            // Close.
+            file.finishWrite(outs);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+            file.failWrite(outs);
+        }
+    }
+
+    private void loadBaseStateLocked() {
+        mRawLastResetTime = 0;
+
+        final AtomicFile file = getBaseStateFile();
+        if (DEBUG) {
+            Slog.d(TAG, "Loading from " + file.getBaseFile());
+        }
+        try (FileInputStream in = file.openRead()) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(in, StandardCharsets.UTF_8.name());
+
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (type != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                final int depth = parser.getDepth();
+                // Check the root tag
+                final String tag = parser.getName();
+                if (depth == 1) {
+                    if (!TAG_ROOT.equals(tag)) {
+                        Slog.e(TAG, "Invalid root tag: " + tag);
+                        return;
+                    }
+                    continue;
+                }
+                // Assume depth == 2
+                switch (tag) {
+                    case TAG_LAST_RESET_TIME:
+                        mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE);
+                        break;
+                    default:
+                        Slog.e(TAG, "Invalid tag: " + tag);
+                        break;
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // Use the default
+        } catch (IOException|XmlPullParserException e) {
+            Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+
+            mRawLastResetTime = 0;
+        }
+        // Adjust the last reset time.
+        getLastResetTimeLocked();
+    }
+
+    private void saveUserLocked(@UserIdInt int userId) {
+        final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
+        if (DEBUG) {
+            Slog.d(TAG, "Saving to " + path);
+        }
+        path.mkdirs();
+        final AtomicFile file = new AtomicFile(path);
+        FileOutputStream os = null;
+        try {
+            os = file.startWrite();
+
+            saveUserInternalLocked(userId, os, /* forBackup= */ false);
+
+            file.finishWrite(os);
+        } catch (XmlPullParserException|IOException e) {
+            Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+            file.failWrite(os);
+        }
+    }
+
+    private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
+            boolean forBackup) throws IOException, XmlPullParserException {
+
+        final BufferedOutputStream bos = new BufferedOutputStream(os);
+
+        // Write to XML
+        XmlSerializer out = new FastXmlSerializer();
+        out.setOutput(bos, StandardCharsets.UTF_8.name());
+        out.startDocument(null, true);
+
+        getUserShortcutsLocked(userId).saveToXml(this, out, forBackup);
+
+        out.endDocument();
+
+        bos.flush();
+        os.flush();
+    }
+
+    static IOException throwForInvalidTag(int depth, String tag) throws IOException {
+        throw new IOException(String.format("Invalid tag '%s' found at depth %d", tag, depth));
+    }
+
+    static void warnForInvalidTag(int depth, String tag) throws IOException {
+        Slog.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth));
+    }
+
+    @Nullable
+    private ShortcutUser loadUserLocked(@UserIdInt int userId) {
+        final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
+        if (DEBUG) {
+            Slog.d(TAG, "Loading from " + path);
+        }
+        final AtomicFile file = new AtomicFile(path);
+
+        final FileInputStream in;
+        try {
+            in = file.openRead();
+        } catch (FileNotFoundException e) {
+            if (DEBUG) {
+                Slog.d(TAG, "Not found " + path);
+            }
+            return null;
+        }
+        try {
+            return loadUserInternal(userId, in, /* forBackup= */ false);
+        } catch (IOException|XmlPullParserException e) {
+            Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+            return null;
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
+            boolean fromBackup) throws XmlPullParserException, IOException {
+
+        final BufferedInputStream bis = new BufferedInputStream(is);
+
+        ShortcutUser ret = null;
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(bis, StandardCharsets.UTF_8.name());
+
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            final int depth = parser.getDepth();
+
+            final String tag = parser.getName();
+            if (DEBUG_LOAD) {
+                Slog.d(TAG, String.format("depth=%d type=%d name=%s",
+                        depth, type, tag));
+            }
+            if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) {
+                ret = ShortcutUser.loadFromXml(this, parser, userId, fromBackup);
+                continue;
+            }
+            throwForInvalidTag(depth, tag);
+        }
+        return ret;
+    }
+
+    private void scheduleSaveBaseState() {
+        scheduleSaveInner(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state.
+    }
+
+    void scheduleSaveUser(@UserIdInt int userId) {
+        scheduleSaveInner(userId);
+    }
+
+    // In order to re-schedule, we need to reuse the same instance, so keep it in final.
+    private final Runnable mSaveDirtyInfoRunner = this::saveDirtyInfo;
+
+    private void scheduleSaveInner(@UserIdInt int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "Scheduling to save for " + userId);
+        }
+        synchronized (mLock) {
+            if (!mDirtyUserIds.contains(userId)) {
+                mDirtyUserIds.add(userId);
+            }
+        }
+        // If already scheduled, remove that and re-schedule in N seconds.
+        mHandler.removeCallbacks(mSaveDirtyInfoRunner);
+        mHandler.postDelayed(mSaveDirtyInfoRunner, mSaveDelayMillis);
+    }
+
+    @VisibleForTesting
+    void saveDirtyInfo() {
+        if (DEBUG) {
+            Slog.d(TAG, "saveDirtyInfo");
+        }
+        synchronized (mLock) {
+            for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
+                final int userId = mDirtyUserIds.get(i);
+                if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
+                    saveBaseStateLocked();
+                } else {
+                    saveUserLocked(userId);
+                }
+            }
+            mDirtyUserIds.clear();
+        }
+    }
+
+    /** Return the last reset time. */
+    long getLastResetTimeLocked() {
+        updateTimesLocked();
+        return mRawLastResetTime;
+    }
+
+    /** Return the next reset time. */
+    long getNextResetTimeLocked() {
+        updateTimesLocked();
+        return mRawLastResetTime + mResetInterval;
+    }
+
+    static boolean isClockValid(long time) {
+        return time >= 1420070400; // Thu, 01 Jan 2015 00:00:00 GMT
+    }
+
+    /**
+     * Update the last reset time.
+     */
+    private void updateTimesLocked() {
+
+        final long now = injectCurrentTimeMillis();
+
+        final long prevLastResetTime = mRawLastResetTime;
+
+        if (mRawLastResetTime == 0) { // first launch.
+            // TODO Randomize??
+            mRawLastResetTime = now;
+        } else if (now < mRawLastResetTime) {
+            // Clock rewound.
+            if (isClockValid(now)) {
+                Slog.w(TAG, "Clock rewound");
+                // TODO Randomize??
+                mRawLastResetTime = now;
+            }
+        } else {
+            if ((mRawLastResetTime + mResetInterval) <= now) {
+                final long offset = mRawLastResetTime % mResetInterval;
+                mRawLastResetTime = ((now / mResetInterval) * mResetInterval) + offset;
+            }
+        }
+        if (prevLastResetTime != mRawLastResetTime) {
+            scheduleSaveBaseState();
+        }
+    }
+
+    @GuardedBy("mLock")
+    @NonNull
+    private boolean isUserLoadedLocked(@UserIdInt int userId) {
+        return mUsers.get(userId) != null;
+    }
+
+    /** Return the per-user state. */
+    @GuardedBy("mLock")
+    @NonNull
+    ShortcutUser getUserShortcutsLocked(@UserIdInt int userId) {
+        ShortcutUser userPackages = mUsers.get(userId);
+        if (userPackages == null) {
+            userPackages = loadUserLocked(userId);
+            if (userPackages == null) {
+                userPackages = new ShortcutUser(userId);
+            }
+            mUsers.put(userId, userPackages);
+        }
+        return userPackages;
+    }
+
+    void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
+        for (int i = mUsers.size() - 1; i >= 0; i--) {
+            c.accept(mUsers.valueAt(i));
+        }
+    }
+
+    /** Return the per-user per-package state. */
+    @GuardedBy("mLock")
+    @NonNull
+    ShortcutPackage getPackageShortcutsLocked(
+            @NonNull String packageName, @UserIdInt int userId) {
+        return getUserShortcutsLocked(userId).getPackageShortcuts(this, packageName);
+    }
+
+    @GuardedBy("mLock")
+    @NonNull
+    ShortcutLauncher getLauncherShortcutsLocked(
+            @NonNull String packageName, @UserIdInt int ownerUserId,
+            @UserIdInt int launcherUserId) {
+        return getUserShortcutsLocked(ownerUserId)
+                .getLauncherShortcuts(this, packageName, launcherUserId);
+    }
+
+    // === Caller validation ===
+
+    void removeIcon(@UserIdInt int userId, ShortcutInfo shortcut) {
+        if (shortcut.getBitmapPath() != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Removing " + shortcut.getBitmapPath());
+            }
+            new File(shortcut.getBitmapPath()).delete();
+
+            shortcut.setBitmapPath(null);
+            shortcut.setIconResourceId(0);
+            shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES);
+        }
+    }
+
+    @VisibleForTesting
+    static class FileOutputStreamWithPath extends FileOutputStream {
+        private final File mFile;
+
+        public FileOutputStreamWithPath(File file) throws FileNotFoundException {
+            super(file);
+            mFile = file;
+        }
+
+        public File getFile() {
+            return mFile;
+        }
+    }
+
+    /**
+     * Build the cached bitmap filename for a shortcut icon.
+     *
+     * The filename will be based on the ID, except certain characters will be escaped.
+     */
+    @VisibleForTesting
+    FileOutputStreamWithPath openIconFileForWrite(@UserIdInt int userId, ShortcutInfo shortcut)
+            throws IOException {
+        final File packagePath = new File(getUserBitmapFilePath(userId),
+                shortcut.getPackageName());
+        if (!packagePath.isDirectory()) {
+            packagePath.mkdirs();
+            if (!packagePath.isDirectory()) {
+                throw new IOException("Unable to create directory " + packagePath);
+            }
+            SELinux.restorecon(packagePath);
+        }
+
+        final String baseName = String.valueOf(injectCurrentTimeMillis());
+        for (int suffix = 0;; suffix++) {
+            final String filename = (suffix == 0 ? baseName : baseName + "_" + suffix) + ".png";
+            final File file = new File(packagePath, filename);
+            if (!file.exists()) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Saving icon to " + file.getAbsolutePath());
+                }
+                return new FileOutputStreamWithPath(file);
+            }
+        }
+    }
+
+    void saveIconAndFixUpShortcut(@UserIdInt int userId, ShortcutInfo shortcut) {
+        if (shortcut.hasIconFile() || shortcut.hasIconResource()) {
+            return;
+        }
+
+        final long token = injectClearCallingIdentity();
+        try {
+            // Clear icon info on the shortcut.
+            shortcut.setIconResourceId(0);
+            shortcut.setBitmapPath(null);
+
+            final Icon icon = shortcut.getIcon();
+            if (icon == null) {
+                return; // has no icon
+            }
+
+            Bitmap bitmap = null;
+            try {
+                switch (icon.getType()) {
+                    case Icon.TYPE_RESOURCE: {
+                        injectValidateIconResPackage(shortcut, icon);
+
+                        shortcut.setIconResourceId(icon.getResId());
+                        shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES);
+                        return;
+                    }
+                    case Icon.TYPE_BITMAP: {
+                        bitmap = icon.getBitmap();
+                        break;
+                    }
+                    case Icon.TYPE_URI: {
+                        final Uri uri = ContentProvider.maybeAddUserId(icon.getUri(), userId);
+
+                        try (InputStream is = mContext.getContentResolver().openInputStream(uri)) {
+
+                            bitmap = BitmapFactory.decodeStream(is);
+
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Unable to load icon from " + uri);
+                            return;
+                        }
+                        break;
+                    }
+                    default:
+                        // This shouldn't happen because we've already validated the icon, but
+                        // just in case.
+                        throw ShortcutInfo.getInvalidIconException();
+                }
+                if (bitmap == null) {
+                    Slog.e(TAG, "Null bitmap detected");
+                    return;
+                }
+                // Shrink and write to the file.
+                File path = null;
+                try {
+                    final FileOutputStreamWithPath out = openIconFileForWrite(userId, shortcut);
+                    try {
+                        path = out.getFile();
+
+                        shrinkBitmap(bitmap, mMaxIconDimension)
+                                .compress(mIconPersistFormat, mIconPersistQuality, out);
+
+                        shortcut.setBitmapPath(out.getFile().getAbsolutePath());
+                        shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE);
+                    } finally {
+                        IoUtils.closeQuietly(out);
+                    }
+                } catch (IOException|RuntimeException e) {
+                    // STOPSHIP Change wtf to e
+                    Slog.wtf(ShortcutService.TAG, "Unable to write bitmap to file", e);
+                    if (path != null && path.exists()) {
+                        path.delete();
+                    }
+                }
+            } finally {
+                if (bitmap != null) {
+                    bitmap.recycle();
+                }
+                // Once saved, we won't use the original icon information, so null it out.
+                shortcut.clearIcon();
+            }
+        } finally {
+            injectRestoreCallingIdentity(token);
+        }
+    }
+
+    // Unfortunately we can't do this check in unit tests because we fake creator package names,
+    // so override in unit tests.
+    // TODO CTS this case.
+    void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
+        if (!shortcut.getPackageName().equals(icon.getResPackage())) {
+            throw new IllegalArgumentException(
+                    "Icon resource must reside in shortcut owner package");
+        }
+    }
+
+    @VisibleForTesting
+    static Bitmap shrinkBitmap(Bitmap in, int maxSize) {
+        // Original width/height.
+        final int ow = in.getWidth();
+        final int oh = in.getHeight();
+        if ((ow <= maxSize) && (oh <= maxSize)) {
+            if (DEBUG) {
+                Slog.d(TAG, String.format("Icon size %dx%d, no need to shrink", ow, oh));
+            }
+            return in;
+        }
+        final int longerDimension = Math.max(ow, oh);
+
+        // New width and height.
+        final int nw = ow * maxSize / longerDimension;
+        final int nh = oh * maxSize / longerDimension;
+        if (DEBUG) {
+            Slog.d(TAG, String.format("Icon size %dx%d, shrinking to %dx%d",
+                    ow, oh, nw, nh));
+        }
+
+        final Bitmap scaledBitmap = Bitmap.createBitmap(nw, nh, Bitmap.Config.ARGB_8888);
+        final Canvas c = new Canvas(scaledBitmap);
+
+        final RectF dst = new RectF(0, 0, nw, nh);
+
+        c.drawBitmap(in, /*src=*/ null, dst, /* paint =*/ null);
+
+        in.recycle();
+
+        return scaledBitmap;
+    }
+
+    // === Caller validation ===
+
+    private boolean isCallerSystem() {
+        final int callingUid = injectBinderCallingUid();
+         return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
+    }
+
+    private boolean isCallerShell() {
+        final int callingUid = injectBinderCallingUid();
+        return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
+    }
+
+    private void enforceSystemOrShell() {
+        Preconditions.checkState(isCallerSystem() || isCallerShell(),
+                "Caller must be system or shell");
+    }
+
+    private void enforceShell() {
+        Preconditions.checkState(isCallerShell(), "Caller must be shell");
+    }
+
+    private void enforceSystem() {
+        Preconditions.checkState(isCallerSystem(), "Caller must be system");
+    }
+
+    private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) {
+        Preconditions.checkStringNotEmpty(packageName, "packageName");
+
+        if (isCallerSystem()) {
+            return; // no check
+        }
+
+        final int callingUid = injectBinderCallingUid();
+
+        // Otherwise, make sure the arguments are valid.
+        if (UserHandle.getUserId(callingUid) != userId) {
+            throw new SecurityException("Invalid user-ID");
+        }
+        if (injectGetPackageUid(packageName, userId) == injectBinderCallingUid()) {
+            return; // Caller is valid.
+        }
+        throw new SecurityException("Caller UID= doesn't own " + packageName);
+    }
+
+    void postToHandler(Runnable r) {
+        mHandler.post(r);
+    }
+
+    /**
+     * Throw if {@code numShortcuts} is bigger than {@link #mMaxDynamicShortcuts}.
+     */
+    void enforceMaxDynamicShortcuts(int numShortcuts) {
+        if (numShortcuts > mMaxDynamicShortcuts) {
+            throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded");
+        }
+    }
+
+    /**
+     * - Sends a notification to LauncherApps
+     * - Write to file
+     */
+    private void userPackageChanged(@NonNull String packageName, @UserIdInt int userId) {
+        notifyListeners(packageName, userId);
+        scheduleSaveUser(userId);
+    }
+
+    private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) {
+        if (!mUserManager.isUserRunning(userId)) {
+            return;
+        }
+        postToHandler(() -> {
+            final ArrayList<ShortcutChangeListener> copy;
+            synchronized (mLock) {
+                copy = new ArrayList<>(mListeners);
+            }
+            // Note onShortcutChanged() needs to be called with the system service permissions.
+            for (int i = copy.size() - 1; i >= 0; i--) {
+                copy.get(i).onShortcutChanged(packageName, userId);
+            }
+        });
+    }
+
+    /**
+     * Clean up / validate an incoming shortcut.
+     * - Make sure all mandatory fields are set.
+     * - Make sure the intent's extras are persistable, and them to set
+     *  {@link ShortcutInfo#mIntentPersistableExtras}.  Also clear its extras.
+     * - Clear flags.
+     *
+     * TODO Detailed unit tests
+     */
+    private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
+        Preconditions.checkNotNull(shortcut, "Null shortcut detected");
+        if (shortcut.getActivityComponent() != null) {
+            Preconditions.checkState(
+                    shortcut.getPackageName().equals(
+                            shortcut.getActivityComponent().getPackageName()),
+                    "Activity package name mismatch");
+        }
+
+        if (!forUpdate) {
+            shortcut.enforceMandatoryFields();
+        }
+        if (shortcut.getIcon() != null) {
+            ShortcutInfo.validateIcon(shortcut.getIcon());
+        }
+
+        validateForXml(shortcut.getId());
+        validateForXml(shortcut.getTitle());
+        validatePersistableBundleForXml(shortcut.getIntentPersistableExtras());
+        validatePersistableBundleForXml(shortcut.getExtras());
+
+        shortcut.replaceFlags(0);
+    }
+
+    // KXmlSerializer is strict and doesn't allow certain characters, so we disallow those
+    // characters.
+
+    private static void validatePersistableBundleForXml(PersistableBundle b) {
+        if (b == null || b.size() == 0) {
+            return;
+        }
+        for (String key : b.keySet()) {
+            validateForXml(key);
+            final Object value = b.get(key);
+            if (value == null) {
+                continue;
+            } else if (value instanceof String) {
+                validateForXml((String) value);
+            } else if (value instanceof String[]) {
+                for (String v : (String[]) value) {
+                    validateForXml(v);
+                }
+            } else if (value instanceof PersistableBundle) {
+                validatePersistableBundleForXml((PersistableBundle) value);
+            }
+        }
+    }
+
+    private static void validateForXml(String s) {
+        if (TextUtils.isEmpty(s)) {
+            return;
+        }
+        for (int i = s.length() - 1; i >= 0; i--) {
+            if (!isAllowedInXml(s.charAt(i))) {
+                throw new IllegalArgumentException("Unsupported character detected in: " + s);
+            }
+        }
+    }
+
+    private static boolean isAllowedInXml(char c) {
+        return (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
+    }
+
+    // === APIs ===
+
+    @Override
+    public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        final int size = newShortcuts.size();
+
+        synchronized (mLock) {
+            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+
+            // Throttling.
+            if (!ps.tryApiCall(this)) {
+                return false;
+            }
+            enforceMaxDynamicShortcuts(size);
+
+            // Validate the shortcuts.
+            for (int i = 0; i < size; i++) {
+                fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false);
+            }
+
+            // First, remove all un-pinned; dynamic shortcuts
+            ps.deleteAllDynamicShortcuts(this);
+
+            // Then, add/update all.  We need to make sure to take over "pinned" flag.
+            for (int i = 0; i < size; i++) {
+                final ShortcutInfo newShortcut = newShortcuts.get(i);
+                ps.addDynamicShortcut(this, newShortcut);
+            }
+        }
+        userPackageChanged(packageName, userId);
+        return true;
+    }
+
+    @Override
+    public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        final int size = newShortcuts.size();
+
+        synchronized (mLock) {
+            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+
+            // Throttling.
+            if (!ps.tryApiCall(this)) {
+                return false;
+            }
+
+            for (int i = 0; i < size; i++) {
+                final ShortcutInfo source = newShortcuts.get(i);
+                fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
+
+                final ShortcutInfo target = ps.findShortcutById(source.getId());
+                if (target != null) {
+                    final boolean replacingIcon = (source.getIcon() != null);
+                    if (replacingIcon) {
+                        removeIcon(userId, target);
+                    }
+
+                    target.copyNonNullFieldsFrom(source);
+
+                    if (replacingIcon) {
+                        saveIconAndFixUpShortcut(userId, target);
+                    }
+                }
+            }
+        }
+        userPackageChanged(packageName, userId);
+
+        return true;
+    }
+
+    @Override
+    public boolean addDynamicShortcut(String packageName, ShortcutInfo newShortcut,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        synchronized (mLock) {
+            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+
+            // Throttling.
+            if (!ps.tryApiCall(this)) {
+                return false;
+            }
+
+            // Validate the shortcut.
+            fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
+
+            // Add it.
+            ps.addDynamicShortcut(this, newShortcut);
+        }
+        userPackageChanged(packageName, userId);
+
+        return true;
+    }
+
+    @Override
+    public void deleteDynamicShortcut(String packageName, String shortcutId,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        Preconditions.checkStringNotEmpty(shortcutId, "shortcutId must be provided");
+
+        synchronized (mLock) {
+            getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this, shortcutId);
+        }
+        userPackageChanged(packageName, userId);
+    }
+
+    @Override
+    public void deleteAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        synchronized (mLock) {
+            getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts(this);
+        }
+        userPackageChanged(packageName, userId);
+    }
+
+    @Override
+    public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        synchronized (mLock) {
+            return getShortcutsWithQueryLocked(
+                    packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
+                    ShortcutInfo::isDynamic);
+        }
+    }
+
+    @Override
+    public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        synchronized (mLock) {
+            return getShortcutsWithQueryLocked(
+                    packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
+                    ShortcutInfo::isPinned);
+        }
+    }
+
+    private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
+            @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
+
+        final ArrayList<ShortcutInfo> ret = new ArrayList<>();
+
+        getPackageShortcutsLocked(packageName, userId).findAll(this, ret, query, cloneFlags);
+
+        return new ParceledListSlice<>(ret);
+    }
+
+    @Override
+    public int getMaxDynamicShortcutCount(String packageName, @UserIdInt int userId)
+            throws RemoteException {
+        verifyCaller(packageName, userId);
+
+        return mMaxDynamicShortcuts;
+    }
+
+    @Override
+    public int getRemainingCallCount(String packageName, @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        synchronized (mLock) {
+            return mMaxDailyUpdates
+                    - getPackageShortcutsLocked(packageName, userId).getApiCallCount(this);
+        }
+    }
+
+    @Override
+    public long getRateLimitResetTime(String packageName, @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        synchronized (mLock) {
+            return getNextResetTimeLocked();
+        }
+    }
+
+    @Override
+    public int getIconMaxDimensions(String packageName, int userId) throws RemoteException {
+        synchronized (mLock) {
+            return mMaxIconDimension;
+        }
+    }
+
+    /**
+     * Reset all throttling, for developer options and command line.  Only system/shell can call it.
+     */
+    @Override
+    public void resetThrottling() {
+        enforceSystemOrShell();
+
+        resetThrottlingInner(getCallingUserId());
+    }
+
+    void resetThrottlingInner(@UserIdInt int userId) {
+        synchronized (mLock) {
+            getUserShortcutsLocked(userId).resetThrottling();
+        }
+        scheduleSaveUser(userId);
+        Slog.i(TAG, "ShortcutManager: throttling counter reset");
+    }
+
+    // We override this method in unit tests to do a simpler check.
+    boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
+        return hasShortcutHostPermissionInner(callingPackage, userId);
+    }
+
+    // This method is extracted so we can directly call this method from unit tests,
+    // even when hasShortcutPermission() is overridden.
+    @VisibleForTesting
+    boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
+        synchronized (mLock) {
+            final long start = System.currentTimeMillis();
+
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+
+            final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+
+            // Default launcher from package manager.
+            final long startGetHomeActivitiesAsUser = System.currentTimeMillis();
+            final ComponentName defaultLauncher = injectPackageManagerInternal()
+                    .getHomeActivitiesAsUser(allHomeCandidates, userId);
+            logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
+
+            ComponentName detected;
+            if (defaultLauncher != null) {
+                detected = defaultLauncher;
+                if (DEBUG) {
+                    Slog.v(TAG, "Default launcher from PM: " + detected);
+                }
+            } else {
+                detected = user.getLauncherComponent();
+
+                // TODO: Make sure it's still enabled.
+                if (DEBUG) {
+                    Slog.v(TAG, "Cached launcher: " + detected);
+                }
+            }
+
+            if (detected == null) {
+                // If we reach here, that means it's the first check since the user was created,
+                // and there's already multiple launchers and there's no default set.
+                // Find the system one with the highest priority.
+                // (We need to check the priority too because of FallbackHome in Settings.)
+                // If there's no system launcher yet, then no one can access shortcuts, until
+                // the user explicitly
+                final int size = allHomeCandidates.size();
+
+                int lastPriority = Integer.MIN_VALUE;
+                for (int i = 0; i < size; i++) {
+                    final ResolveInfo ri = allHomeCandidates.get(i);
+                    if (!ri.activityInfo.applicationInfo.isSystemApp()) {
+                        continue;
+                    }
+                    if (DEBUG) {
+                        Slog.d(TAG, String.format("hasShortcutPermissionInner: pkg=%s prio=%d",
+                                ri.activityInfo.getComponentName(), ri.priority));
+                    }
+                    if (ri.priority < lastPriority) {
+                        continue;
+                    }
+                    detected = ri.activityInfo.getComponentName();
+                    lastPriority = ri.priority;
+                }
+            }
+            logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
+
+            if (detected != null) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Detected launcher: " + detected);
+                }
+                user.setLauncherComponent(this, detected);
+                return detected.getPackageName().equals(callingPackage);
+            } else {
+                // Default launcher not found.
+                return false;
+            }
+        }
+    }
+
+    // === House keeping ===
+
+    /**
+     * Remove all the information associated with a package.  This will really remove all the
+     * information, including the restore information (i.e. it'll remove packages even if they're
+     * shadow).
+     */
+    @VisibleForTesting
+    void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
+        if (isPackageInstalled(packageName, packageUserId)) {
+            wtf("Package " + packageName + " is still installed for user " + packageUserId);
+            return;
+        }
+
+        final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
+
+        final ShortcutUser mUser = getUserShortcutsLocked(owningUserId);
+        boolean doNotify = false;
+
+        // First, remove the package from the package list (if the package is a publisher).
+        if (packageUserId == owningUserId) {
+            if (mUser.removePackage(packageName) != null) {
+                doNotify = true;
+            }
+        }
+
+        // Also remove from the launcher list (if the package is a launcher).
+        mUser.removeLauncher(packageUserId, packageName);
+
+        // Then remove pinned shortcuts from all launchers.
+        final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = mUser.getAllLaunchers();
+        for (int i = launchers.size() - 1; i >= 0; i--) {
+            launchers.valueAt(i).cleanUpPackage(packageName, packageUserId);
+        }
+        // Now there may be orphan shortcuts because we removed pinned shortucts at the previous
+        // step.  Remove them too.
+        for (int i = mUser.getAllPackages().size() - 1; i >= 0; i--) {
+            mUser.getAllPackages().valueAt(i).refreshPinnedFlags(this);
+        }
+
+        scheduleSaveUser(owningUserId);
+
+        if (doNotify) {
+            notifyListeners(packageName, owningUserId);
+        }
+
+        if (!wasUserLoaded) {
+            // Note this will execute the scheduled save.
+            unloadUserLocked(owningUserId);
+        }
+    }
+
+    /**
+     * Entry point from {@link LauncherApps}.
+     */
+    private class LocalService extends ShortcutServiceInternal {
+
+        @Override
+        public List<ShortcutInfo> getShortcuts(int launcherUserId,
+                @NonNull String callingPackage, long changedSince,
+                @Nullable String packageName, @Nullable ComponentName componentName,
+                int queryFlags, int userId) {
+            final ArrayList<ShortcutInfo> ret = new ArrayList<>();
+            final int cloneFlag =
+                    ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) == 0)
+                            ? ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER
+                            : ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
+
+            synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+                if (packageName != null) {
+                    getShortcutsInnerLocked(launcherUserId,
+                            callingPackage, packageName, changedSince,
+                            componentName, queryFlags, userId, ret, cloneFlag);
+                } else {
+                    final ArrayMap<String, ShortcutPackage> packages =
+                            getUserShortcutsLocked(userId).getAllPackages();
+                    for (int i = packages.size() - 1; i >= 0; i--) {
+                        getShortcutsInnerLocked(launcherUserId,
+                                callingPackage, packages.keyAt(i), changedSince,
+                                componentName, queryFlags, userId, ret, cloneFlag);
+                    }
+                }
+            }
+            return ret;
+        }
+
+        private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
+                @Nullable String packageName,long changedSince,
+                @Nullable ComponentName componentName, int queryFlags,
+                int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
+            getPackageShortcutsLocked(packageName, userId).findAll(ShortcutService.this, ret,
+                    (ShortcutInfo si) -> {
+                        if (si.getLastChangedTimestamp() < changedSince) {
+                            return false;
+                        }
+                        if (componentName != null
+                                && !componentName.equals(si.getActivityComponent())) {
+                            return false;
+                        }
+                        final boolean matchDynamic =
+                                ((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
+                                        && si.isDynamic();
+                        final boolean matchPinned =
+                                ((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0)
+                                        && si.isPinned();
+                        return matchDynamic || matchPinned;
+                    }, cloneFlag, callingPackage, launcherUserId);
+        }
+
+        @Override
+        public List<ShortcutInfo> getShortcutInfo(int launcherUserId,
+                @NonNull String callingPackage,
+                @NonNull String packageName, @Nullable List<String> ids, int userId) {
+            // Calling permission must be checked by LauncherAppsImpl.
+            Preconditions.checkStringNotEmpty(packageName, "packageName");
+
+            final ArrayList<ShortcutInfo> ret = new ArrayList<>(ids.size());
+            final ArraySet<String> idSet = new ArraySet<>(ids);
+            synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+                getPackageShortcutsLocked(packageName, userId).findAll(
+                        ShortcutService.this, ret,
+                        (ShortcutInfo si) -> idSet.contains(si.getId()),
+                        ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER, callingPackage, launcherUserId);
+            }
+            return ret;
+        }
+
+        @Override
+        public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
+                @NonNull String packageName, @NonNull String shortcutId, int userId) {
+            Preconditions.checkStringNotEmpty(packageName, "packageName");
+            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+
+            synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+                final ShortcutInfo si = getShortcutInfoLocked(
+                        launcherUserId, callingPackage, packageName, shortcutId, userId);
+                return si != null && si.isPinned();
+            }
+        }
+
+        private ShortcutInfo getShortcutInfoLocked(
+                int launcherUserId, @NonNull String callingPackage,
+                @NonNull String packageName, @NonNull String shortcutId, int userId) {
+            Preconditions.checkStringNotEmpty(packageName, "packageName");
+            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+
+            final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
+            getPackageShortcutsLocked(packageName, userId).findAll(
+                    ShortcutService.this, list,
+                    (ShortcutInfo si) -> shortcutId.equals(si.getId()),
+                    /* clone flags=*/ 0, callingPackage, launcherUserId);
+            return list.size() == 0 ? null : list.get(0);
+        }
+
+        @Override
+        public void pinShortcuts(int launcherUserId,
+                @NonNull String callingPackage, @NonNull String packageName,
+                @NonNull List<String> shortcutIds, int userId) {
+            // Calling permission must be checked by LauncherAppsImpl.
+            Preconditions.checkStringNotEmpty(packageName, "packageName");
+            Preconditions.checkNotNull(shortcutIds, "shortcutIds");
+
+            synchronized (mLock) {
+                final ShortcutLauncher launcher =
+                        getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
+                launcher.attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+                launcher.pinShortcuts(
+                        ShortcutService.this, userId, packageName, shortcutIds);
+            }
+            userPackageChanged(packageName, userId);
+        }
+
+        @Override
+        public Intent createShortcutIntent(int launcherUserId,
+                @NonNull String callingPackage,
+                @NonNull String packageName, @NonNull String shortcutId, int userId) {
+            // Calling permission must be checked by LauncherAppsImpl.
+            Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
+            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
+
+            synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+                // Make sure the shortcut is actually visible to the launcher.
+                final ShortcutInfo si = getShortcutInfoLocked(
+                        launcherUserId, callingPackage, packageName, shortcutId, userId);
+                // "si == null" should suffice here, but check the flags too just to make sure.
+                if (si == null || !(si.isDynamic() || si.isPinned())) {
+                    return null;
+                }
+                return si.getIntent();
+            }
+        }
+
+        @Override
+        public void addListener(@NonNull ShortcutChangeListener listener) {
+            synchronized (mLock) {
+                mListeners.add(Preconditions.checkNotNull(listener));
+            }
+        }
+
+        @Override
+        public int getShortcutIconResId(int launcherUserId,
+                @NonNull String callingPackage,
+                @NonNull ShortcutInfo shortcut, int userId) {
+            Preconditions.checkNotNull(shortcut, "shortcut");
+
+            synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+                final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
+                        shortcut.getPackageName(), userId).findShortcutById(shortcut.getId());
+                return (shortcutInfo != null && shortcutInfo.hasIconResource())
+                        ? shortcutInfo.getIconResourceId() : 0;
+            }
+        }
+
+        @Override
+        public ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
+                @NonNull String callingPackage,
+                @NonNull ShortcutInfo shortcutIn, int userId) {
+            Preconditions.checkNotNull(shortcutIn, "shortcut");
+
+            synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+                final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
+                        shortcutIn.getPackageName(), userId).findShortcutById(shortcutIn.getId());
+                if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
+                    return null;
+                }
+                try {
+                    if (shortcutInfo.getBitmapPath() == null) {
+                        Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
+                        return null;
+                    }
+                    return ParcelFileDescriptor.open(
+                            new File(shortcutInfo.getBitmapPath()),
+                            ParcelFileDescriptor.MODE_READ_ONLY);
+                } catch (FileNotFoundException e) {
+                    Slog.e(TAG, "Icon file not found: " + shortcutInfo.getBitmapPath());
+                    return null;
+                }
+            }
+        }
+
+        @Override
+        public boolean hasShortcutHostPermission(int launcherUserId,
+                @NonNull String callingPackage) {
+            return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
+        }
+    }
+
+    /**
+     * Package event callbacks.
+     */
+    @VisibleForTesting
+    final PackageMonitor mPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            handlePackageAdded(packageName, getChangingUserId());
+        }
+
+        @Override
+        public void onPackageUpdateFinished(String packageName, int uid) {
+            handlePackageUpdateFinished(packageName, getChangingUserId());
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            handlePackageRemoved(packageName, getChangingUserId());
+        }
+    };
+
+    /**
+     * Called when a user is unlocked.  Check all known packages still exist, and otherwise
+     * perform cleanup.
+     */
+    @VisibleForTesting
+    void cleanupGonePackages(@UserIdInt int ownerUserId) {
+        if (DEBUG) {
+            Slog.d(TAG, "cleanupGonePackages() ownerUserId=" + ownerUserId);
+        }
+        final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
+
+        synchronized (mLock) {
+            final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
+
+            user.forAllPackageItems(spi -> {
+                if (spi.getPackageInfo().isShadow()) {
+                    return; // Don't delete shadow information.
+                }
+                if (isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
+                    return; // Package not gone.
+                }
+                gonePackages.add(PackageWithUser.of(spi));
+            });
+            if (gonePackages.size() > 0) {
+                for (int i = gonePackages.size() - 1; i >= 0; i--) {
+                    final PackageWithUser pu = gonePackages.get(i);
+                    cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId);
+                }
+            }
+        }
+    }
+
+    private void handlePackageAdded(String packageName, @UserIdInt int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
+        }
+        synchronized (mLock) {
+            forEachLoadedUserLocked(user ->
+                    user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
+        }
+    }
+
+    private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d",
+                    packageName, userId));
+        }
+        synchronized (mLock) {
+            forEachLoadedUserLocked(user ->
+                    user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
+        }
+    }
+
+    private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) {
+        if (DEBUG) {
+            Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
+                    packageUserId));
+        }
+        synchronized (mLock) {
+            forEachLoadedUserLocked(user ->
+                cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
+        }
+    }
+
+    // === PackageManager interaction ===
+
+    PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
+        return injectPackageInfo(packageName, userId, true);
+    }
+
+    int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
+        final long token = injectClearCallingIdentity();
+        try {
+            return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS
+                    , userId);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+            Slog.wtf(TAG, "RemoteException", e);
+            return -1;
+        } finally {
+            injectRestoreCallingIdentity(token);
+        }
+    }
+
+    @VisibleForTesting
+    PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
+            boolean getSignatures) {
+        final long start = System.currentTimeMillis();
+        final long token = injectClearCallingIdentity();
+        try {
+            return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
+                    | (getSignatures ? PackageManager.GET_SIGNATURES : 0)
+                    , userId);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+            Slog.wtf(TAG, "RemoteException", e);
+            return null;
+        } finally {
+            injectRestoreCallingIdentity(token);
+
+            logDurationStat(
+                    (getSignatures ? Stats.GET_PACKAGE_INFO_WITH_SIG : Stats.GET_PACKAGE_INFO),
+                    start);
+        }
+    }
+
+    @VisibleForTesting
+    ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
+        final long start = System.currentTimeMillis();
+        final long token = injectClearCallingIdentity();
+        try {
+            return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+            Slog.wtf(TAG, "RemoteException", e);
+            return null;
+        } finally {
+            injectRestoreCallingIdentity(token);
+
+            logDurationStat(Stats.GET_APPLICATION_INFO, start);
+        }
+    }
+
+    private boolean isApplicationFlagSet(String packageName, int userId, int flags) {
+        final ApplicationInfo ai = injectApplicationInfo(packageName, userId);
+        return (ai != null) && ((ai.flags & flags) == flags);
+    }
+
+    boolean isPackageInstalled(String packageName, int userId) {
+        return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED);
+    }
+
+    // === Backup & restore ===
+
+    boolean shouldBackupApp(String packageName, int userId) {
+        return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
+    }
+
+    boolean shouldBackupApp(PackageInfo pi) {
+        return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+    }
+
+    @Override
+    public byte[] getBackupPayload(@UserIdInt int userId) {
+        enforceSystem();
+        if (DEBUG) {
+            Slog.d(TAG, "Backing up user " + userId);
+        }
+        synchronized (mLock) {
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+            if (user == null) {
+                Slog.w(TAG, "Can't backup: user not found: id=" + userId);
+                return null;
+            }
+
+            user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave(this));
+
+            // Then save.
+            final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
+            try {
+                saveUserInternalLocked(userId, os, /* forBackup */ true);
+            } catch (XmlPullParserException|IOException e) {
+                // Shouldn't happen.
+                Slog.w(TAG, "Backup failed.", e);
+                return null;
+            }
+            return os.toByteArray();
+        }
+    }
+
+    @Override
+    public void applyRestore(byte[] payload, @UserIdInt int userId) {
+        enforceSystem();
+        if (DEBUG) {
+            Slog.d(TAG, "Restoring user " + userId);
+        }
+        final ShortcutUser user;
+        final ByteArrayInputStream is = new ByteArrayInputStream(payload);
+        try {
+            user = loadUserInternal(userId, is, /* fromBackup */ true);
+        } catch (XmlPullParserException|IOException e) {
+            Slog.w(TAG, "Restoration failed.", e);
+            return;
+        }
+        synchronized (mLock) {
+            mUsers.put(userId, user);
+
+            // Then purge all the save images.
+            final File bitmapPath = getUserBitmapFilePath(userId);
+            final boolean success = FileUtils.deleteContents(bitmapPath);
+            if (!success) {
+                Slog.w(TAG, "Failed to delete " + bitmapPath);
+            }
+
+            saveUserLocked(userId);
+        }
+    }
+
+    // === Dump ===
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump UserManager from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " without permission "
+                    + android.Manifest.permission.DUMP);
+            return;
+        }
+        dumpInner(pw);
+    }
+
+    @VisibleForTesting
+    void dumpInner(PrintWriter pw) {
+        synchronized (mLock) {
+            final long now = injectCurrentTimeMillis();
+            pw.print("Now: [");
+            pw.print(now);
+            pw.print("] ");
+            pw.print(formatTime(now));
+
+            pw.print("  Raw last reset: [");
+            pw.print(mRawLastResetTime);
+            pw.print("] ");
+            pw.print(formatTime(mRawLastResetTime));
+
+            final long last = getLastResetTimeLocked();
+            pw.print("  Last reset: [");
+            pw.print(last);
+            pw.print("] ");
+            pw.print(formatTime(last));
+
+            final long next = getNextResetTimeLocked();
+            pw.print("  Next reset: [");
+            pw.print(next);
+            pw.print("] ");
+            pw.print(formatTime(next));
+            pw.println();
+
+            pw.print("  Max icon dim: ");
+            pw.print(mMaxIconDimension);
+            pw.print("  Icon format: ");
+            pw.print(mIconPersistFormat);
+            pw.print("  Icon quality: ");
+            pw.println(mIconPersistQuality);
+            pw.println();
+
+            pw.println("  Stats:");
+            synchronized (mStatLock) {
+                final String p = "     ";
+                dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
+                dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
+
+                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
+                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
+                dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
+            }
+
+            for (int i = 0; i < mUsers.size(); i++) {
+                pw.println();
+                mUsers.valueAt(i).dump(this, pw, "  ");
+            }
+        }
+    }
+
+    static String formatTime(long time) {
+        Time tobj = new Time();
+        tobj.set(time);
+        return tobj.format("%Y-%m-%d %H:%M:%S");
+    }
+
+    private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
+        pw.print(prefix);
+        final int count = mCountStats[statId];
+        final long dur = mDurationStats[statId];
+        pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
+                label, count, dur,
+                (count == 0 ? 0 : ((double) dur) / count)));
+    }
+
+    // === Shell support ===
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+
+        enforceShell();
+
+        (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
+    }
+
+    static class CommandException extends Exception {
+        public CommandException(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * Handle "adb shell cmd".
+     */
+    private class MyShellCommand extends ShellCommand {
+
+        private int mUserId = UserHandle.USER_SYSTEM;
+
+        private void parseOptions(boolean takeUser)
+                throws CommandException {
+            String opt;
+            while ((opt = getNextOption()) != null) {
+                switch (opt) {
+                    case "--user":
+                        if (takeUser) {
+                            mUserId = UserHandle.parseUserArg(getNextArgRequired());
+                            break;
+                        }
+                        // fallthrough
+                    default:
+                        throw new CommandException("Unknown option: " + opt);
+                }
+            }
+        }
+
+        @Override
+        public int onCommand(String cmd) {
+            if (cmd == null) {
+                return handleDefaultCommands(cmd);
+            }
+            final PrintWriter pw = getOutPrintWriter();
+            try {
+                switch (cmd) {
+                    case "reset-package-throttling":
+                        handleResetPackageThrottling();
+                        break;
+                    case "reset-throttling":
+                        handleResetThrottling();
+                        break;
+                    case "override-config":
+                        handleOverrideConfig();
+                        break;
+                    case "reset-config":
+                        handleResetConfig();
+                        break;
+                    case "clear-default-launcher":
+                        handleClearDefaultLauncher();
+                        break;
+                    case "get-default-launcher":
+                        handleGetDefaultLauncher();
+                        break;
+                    case "refresh-default-launcher":
+                        handleRefreshDefaultLauncher();
+                        break;
+                    case "unload-user":
+                        handleUnloadUser();
+                        break;
+                    default:
+                        return handleDefaultCommands(cmd);
+                }
+            } catch (CommandException e) {
+                pw.println("Error: " + e.getMessage());
+                return 1;
+            }
+            pw.println("Success");
+            return 0;
+        }
+
+        @Override
+        public void onHelp() {
+            final PrintWriter pw = getOutPrintWriter();
+            pw.println("Usage: cmd shortcut COMMAND [options ...]");
+            pw.println();
+            pw.println("cmd shortcut reset-package-throttling [--user USER_ID] PACKAGE");
+            pw.println("    Reset throttling for a package");
+            pw.println();
+            pw.println("cmd shortcut reset-throttling");
+            pw.println("    Reset throttling for all packages and users");
+            pw.println();
+            pw.println("cmd shortcut override-config CONFIG");
+            pw.println("    Override the configuration for testing (will last until reboot)");
+            pw.println();
+            pw.println("cmd shortcut reset-config");
+            pw.println("    Reset the configuration set with \"update-config\"");
+            pw.println();
+            pw.println("cmd shortcut clear-default-launcher [--user USER_ID]");
+            pw.println("    Clear the cached default launcher");
+            pw.println();
+            pw.println("cmd shortcut get-default-launcher [--user USER_ID]");
+            pw.println("    Show the cached default launcher");
+            pw.println();
+            pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]");
+            pw.println("    Refresh the cached default launcher");
+            pw.println();
+            pw.println("cmd shortcut unload-user [--user USER_ID]");
+            pw.println("    Unload a user from the memory");
+            pw.println("    (This should not affect any observable behavior)");
+            pw.println();
+        }
+
+        private int handleResetThrottling() throws CommandException {
+            parseOptions(/* takeUser =*/ true);
+
+            resetThrottlingInner(mUserId);
+            return 0;
+        }
+
+        private void handleResetPackageThrottling() throws CommandException {
+            parseOptions(/* takeUser =*/ true);
+
+            final String packageName = getNextArgRequired();
+
+            synchronized (mLock) {
+                getPackageShortcutsLocked(packageName, mUserId).resetRateLimitingForCommandLine();
+                saveUserLocked(mUserId);
+            }
+        }
+
+        private void handleOverrideConfig() throws CommandException {
+            final String config = getNextArgRequired();
+
+            synchronized (mLock) {
+                if (!updateConfigurationLocked(config)) {
+                    throw new CommandException("override-config failed.  See logcat for details.");
+                }
+            }
+        }
+
+        private void handleResetConfig() {
+            synchronized (mLock) {
+                loadConfigurationLocked();
+            }
+        }
+
+        private void clearLauncher() {
+            synchronized (mLock) {
+                getUserShortcutsLocked(mUserId).setLauncherComponent(
+                        ShortcutService.this, null);
+            }
+        }
+
+        private void showLauncher() {
+            synchronized (mLock) {
+                // This ensures to set the cached launcher.  Package name doesn't matter.
+                hasShortcutHostPermissionInner("-", mUserId);
+
+                getOutPrintWriter().println("Launcher: "
+                        + getUserShortcutsLocked(mUserId).getLauncherComponent());
+            }
+        }
+
+        private void handleClearDefaultLauncher() throws CommandException {
+            parseOptions(/* takeUser =*/ true);
+
+            clearLauncher();
+        }
+
+        private void handleGetDefaultLauncher() throws CommandException {
+            parseOptions(/* takeUser =*/ true);
+
+            showLauncher();
+        }
+
+        private void handleRefreshDefaultLauncher() throws CommandException {
+            parseOptions(/* takeUser =*/ true);
+
+            clearLauncher();
+            showLauncher();
+        }
+
+        private void handleUnloadUser() throws CommandException {
+            parseOptions(/* takeUser =*/ true);
+
+            ShortcutService.this.handleCleanupUser(mUserId);
+        }
+    }
+
+    // === Unit test support ===
+
+    // Injection point.
+    @VisibleForTesting
+    long injectCurrentTimeMillis() {
+        return System.currentTimeMillis();
+    }
+
+    // Injection point.
+    @VisibleForTesting
+    int injectBinderCallingUid() {
+        return getCallingUid();
+    }
+
+    private int getCallingUserId() {
+        return UserHandle.getUserId(injectBinderCallingUid());
+    }
+
+    // Injection point.
+    @VisibleForTesting
+    long injectClearCallingIdentity() {
+        return Binder.clearCallingIdentity();
+    }
+
+    // Injection point.
+    @VisibleForTesting
+    void injectRestoreCallingIdentity(long token) {
+        Binder.restoreCallingIdentity(token);
+    }
+
+    final void wtf(String message) {
+        wtf( message, /* exception= */ null);
+    }
+
+    // Injection point.
+    void wtf(String message, Exception e) {
+        Slog.wtf(TAG, message, e);
+    }
+
+    @VisibleForTesting
+    File injectSystemDataPath() {
+        return Environment.getDataSystemDirectory();
+    }
+
+    @VisibleForTesting
+    File injectUserDataPath(@UserIdInt int userId) {
+        return new File(Environment.getDataSystemCeDirectory(userId), DIRECTORY_PER_USER);
+    }
+
+    @VisibleForTesting
+    boolean injectIsLowRamDevice() {
+        return ActivityManager.isLowRamDeviceStatic();
+    }
+
+    @VisibleForTesting
+    PackageManagerInternal injectPackageManagerInternal() {
+        return mPackageManagerInternal;
+    }
+
+    @VisibleForTesting
+    File getUserBitmapFilePath(@UserIdInt int userId) {
+        return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS);
+    }
+
+    @VisibleForTesting
+    SparseArray<ShortcutUser> getShortcutsForTest() {
+        return mUsers;
+    }
+
+    @VisibleForTesting
+    int getMaxDynamicShortcutsForTest() {
+        return mMaxDynamicShortcuts;
+    }
+
+    @VisibleForTesting
+    int getMaxDailyUpdatesForTest() {
+        return mMaxDailyUpdates;
+    }
+
+    @VisibleForTesting
+    long getResetIntervalForTest() {
+        return mResetInterval;
+    }
+
+    @VisibleForTesting
+    int getMaxIconDimensionForTest() {
+        return mMaxIconDimension;
+    }
+
+    @VisibleForTesting
+    CompressFormat getIconPersistFormatForTest() {
+        return mIconPersistFormat;
+    }
+
+    @VisibleForTesting
+    int getIconPersistQualityForTest() {
+        return mIconPersistQuality;
+    }
+
+    @VisibleForTesting
+    ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
+        synchronized (mLock) {
+            final ShortcutUser user = mUsers.get(userId);
+            if (user == null) return null;
+
+            final ShortcutPackage pkg = user.getAllPackages().get(packageName);
+            if (pkg == null) return null;
+
+            return pkg.findShortcutById(shortcutId);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
new file mode 100644
index 0000000..593f607
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+
+import libcore.util.Objects;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.function.Consumer;
+
+/**
+ * User information used by {@link ShortcutService}.
+ */
+class ShortcutUser {
+    private static final String TAG = ShortcutService.TAG;
+
+    static final String TAG_ROOT = "user";
+    private static final String TAG_LAUNCHER = "launcher";
+
+    private static final String ATTR_VALUE = "value";
+
+    static final class PackageWithUser {
+        final int userId;
+        final String packageName;
+
+        private PackageWithUser(int userId, String packageName) {
+            this.userId = userId;
+            this.packageName = Preconditions.checkNotNull(packageName);
+        }
+
+        public static PackageWithUser of(int userId, String packageName) {
+            return new PackageWithUser(userId, packageName);
+        }
+
+        public static PackageWithUser of(ShortcutPackageItem spi) {
+            return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName());
+        }
+
+        @Override
+        public int hashCode() {
+            return packageName.hashCode() ^ userId;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof PackageWithUser)) {
+                return false;
+            }
+            final PackageWithUser that = (PackageWithUser) obj;
+
+            return userId == that.userId && packageName.equals(that.packageName);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("{Package: %d, %s}", userId, packageName);
+        }
+    }
+
+    @UserIdInt
+    private final int mUserId;
+
+    private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
+
+    private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
+
+    private ComponentName mLauncherComponent;
+
+    public ShortcutUser(int userId) {
+        mUserId = userId;
+    }
+
+    public int getUserId() {
+        return mUserId;
+    }
+
+    public ArrayMap<String, ShortcutPackage> getAllPackages() {
+        return mPackages;
+    }
+
+    public ShortcutPackage removePackage(@NonNull String packageName) {
+        return mPackages.remove(packageName);
+    }
+
+    public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
+        return mLaunchers;
+    }
+
+    public void addLauncher(ShortcutLauncher launcher) {
+        mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
+                launcher.getPackageName()), launcher);
+    }
+
+    public ShortcutLauncher removeLauncher(
+            @UserIdInt int packageUserId, @NonNull String packageName) {
+        return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
+    }
+
+    public ShortcutPackage getPackageShortcuts(ShortcutService s, @NonNull String packageName) {
+        ShortcutPackage ret = mPackages.get(packageName);
+        if (ret == null) {
+            ret = new ShortcutPackage(mUserId, packageName);
+            mPackages.put(packageName, ret);
+        } else {
+            ret.attemptToRestoreIfNeededAndSave(s);
+        }
+        return ret;
+    }
+
+    public ShortcutLauncher getLauncherShortcuts(ShortcutService s, @NonNull String packageName,
+            @UserIdInt int launcherUserId) {
+        final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
+        ShortcutLauncher ret = mLaunchers.get(key);
+        if (ret == null) {
+            ret = new ShortcutLauncher(mUserId, packageName, launcherUserId);
+            mLaunchers.put(key, ret);
+        } else {
+            ret.attemptToRestoreIfNeededAndSave(s);
+        }
+        return ret;
+    }
+
+    public void forAllPackageItems(Consumer<ShortcutPackageItem> callback) {
+        {
+            final int size = mLaunchers.size();
+            for (int i = 0; i < size; i++) {
+                callback.accept(mLaunchers.valueAt(i));
+            }
+        }
+        {
+            final int size = mPackages.size();
+            for (int i = 0; i < size; i++) {
+                callback.accept(mPackages.valueAt(i));
+            }
+        }
+    }
+
+    public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
+            Consumer<ShortcutPackageItem> callback) {
+        forAllPackageItems(spi -> {
+            if ((spi.getPackageUserId() == packageUserId)
+                    && spi.getPackageName().equals(packageName)) {
+                callback.accept(spi);
+            }
+        });
+    }
+
+    public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
+            @UserIdInt int packageUserId) {
+        forPackageItem(packageName, packageUserId, spi -> {
+            spi.attemptToRestoreIfNeededAndSave(s);
+        });
+    }
+
+    public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
+            throws IOException, XmlPullParserException {
+        out.startTag(null, TAG_ROOT);
+
+        ShortcutService.writeTagValue(out, TAG_LAUNCHER,
+                mLauncherComponent);
+
+        // Can't use forEachPackageItem due to the checked exceptions.
+        {
+            final int size = mLaunchers.size();
+            for (int i = 0; i < size; i++) {
+                saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup);
+            }
+        }
+        {
+            final int size = mPackages.size();
+            for (int i = 0; i < size; i++) {
+                saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup);
+            }
+        }
+
+        out.endTag(null, TAG_ROOT);
+    }
+
+    private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
+            ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
+        if (forBackup) {
+            if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
+                return; // Don't save.
+            }
+            if (spi.getPackageUserId() != spi.getOwnerUserId()) {
+                return; // Don't save cross-user information.
+            }
+        }
+        spi.saveToXml(out, forBackup);
+    }
+
+    public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
+            boolean fromBackup) throws IOException, XmlPullParserException {
+        final ShortcutUser ret = new ShortcutUser(userId);
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            final int depth = parser.getDepth();
+            final String tag = parser.getName();
+
+            if (depth == outerDepth + 1) {
+                switch (tag) {
+                    case TAG_LAUNCHER: {
+                        ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
+                                parser, ATTR_VALUE);
+                        continue;
+                    }
+                    case ShortcutPackage.TAG_ROOT: {
+                        final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
+                                s, parser, userId, fromBackup);
+
+                        // Don't use addShortcut(), we don't need to save the icon.
+                        ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
+                        continue;
+                    }
+
+                    case ShortcutLauncher.TAG_ROOT: {
+                        ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId, fromBackup));
+                        continue;
+                    }
+                }
+            }
+            ShortcutService.warnForInvalidTag(depth, tag);
+        }
+        return ret;
+    }
+
+    public ComponentName getLauncherComponent() {
+        return mLauncherComponent;
+    }
+
+    public void setLauncherComponent(ShortcutService s, ComponentName launcherComponent) {
+        if (Objects.equal(mLauncherComponent, launcherComponent)) {
+            return;
+        }
+        mLauncherComponent = launcherComponent;
+        s.scheduleSaveUser(mUserId);
+    }
+
+    public void resetThrottling() {
+        for (int i = mPackages.size() - 1; i >= 0; i--) {
+            mPackages.valueAt(i).resetThrottling();
+        }
+    }
+
+    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+        pw.print(prefix);
+        pw.print("User: ");
+        pw.print(mUserId);
+        pw.println();
+
+        pw.print(prefix);
+        pw.print("  ");
+        pw.print("Default launcher: ");
+        pw.print(mLauncherComponent);
+        pw.println();
+
+        for (int i = 0; i < mLaunchers.size(); i++) {
+            mLaunchers.valueAt(i).dump(s, pw, prefix + "  ");
+        }
+
+        for (int i = 0; i < mPackages.size(); i++) {
+            mPackages.valueAt(i).dump(s, pw, prefix + "  ");
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d5ed04a..06a91fb 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2011 The Android Open Source Project
  *
@@ -19,6 +20,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -29,13 +31,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Environment;
@@ -50,6 +52,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -120,6 +123,7 @@
     private static final String ATTR_ID = "id";
     private static final String ATTR_CREATION_TIME = "created";
     private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
+    private static final String ATTR_LAST_LOGGED_IN_FINGERPRINT = "lastLoggedInFingerprint";
     private static final String ATTR_SERIAL_NO = "serialNumber";
     private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String ATTR_PARTIAL = "partial";
@@ -378,14 +382,21 @@
             removeUserState(ui.id);
         }
 
-        onUserForeground(UserHandle.USER_SYSTEM);
-
         mAppOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
 
         synchronized (mRestrictionsLock) {
             applyUserRestrictionsLR(UserHandle.USER_SYSTEM);
         }
+
+        UserInfo currentGuestUser = findCurrentGuestUser();
+        if (currentGuestUser != null && !hasUserRestriction(
+                UserManager.DISALLOW_CONFIG_WIFI, currentGuestUser.id)) {
+            // If a guest user currently exists, apply the DISALLOW_CONFIG_WIFI option
+            // to it, in case this guest was created in a previous version where this
+            // user restriction was not a default guest restriction.
+            setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
+        }
     }
 
     @Override
@@ -447,7 +458,7 @@
                     continue;
                 }
                 if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
-                    users.add(ui);
+                    users.add(userWithName(ui));
                 }
             }
             return users;
@@ -489,7 +500,10 @@
             if (mRemovingUserIds.get(profile.id)) {
                 continue;
             }
-            users.add(profile);
+            if (profile.partial) {
+                continue;
+            }
+            users.add(userWithName(profile));
         }
         return users;
     }
@@ -562,12 +576,26 @@
 
     private void broadcastProfileAvailabilityChanges(UserHandle profileHandle,
             UserHandle parentHandle, boolean inQuietMode) {
-        Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+        Intent intent = new Intent();
+        if (inQuietMode) {
+            intent.setAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+        } else {
+            intent.setAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+        }
         intent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
         intent.putExtra(Intent.EXTRA_USER, profileHandle);
         intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         mContext.sendBroadcastAsUser(intent, parentHandle);
+
+        //TODO: remove once Launcher3 is updated.
+        Intent oldIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+        oldIntent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
+        oldIntent.putExtra(Intent.EXTRA_USER, profileHandle);
+        oldIntent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
+        oldIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mContext.sendBroadcastAsUser(oldIntent, parentHandle);
+
     }
 
     @Override
@@ -642,7 +670,39 @@
     public UserInfo getUserInfo(int userId) {
         checkManageUsersPermission("query user");
         synchronized (mUsersLock) {
-            return getUserInfoLU(userId);
+            return userWithName(getUserInfoLU(userId));
+        }
+    }
+
+    /**
+     * Returns a UserInfo object with the name filled in, for Owner, or the original
+     * if the name is already set.
+     */
+    private UserInfo userWithName(UserInfo orig) {
+        if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) {
+            UserInfo withName = new UserInfo(orig);
+            withName.name = getOwnerName();
+            return withName;
+        } else {
+            return orig;
+        }
+    }
+
+    @Override
+    public boolean isManagedProfile(int userId) {
+        int callingUserId = UserHandle.getCallingUserId();
+        if (callingUserId != userId && !hasManageUsersPermission()) {
+            synchronized (mPackagesLock) {
+                if (!isSameProfileGroupLP(callingUserId, userId)) {
+                    throw new SecurityException(
+                            "You need MANAGE_USERS permission to: check if specified user a " +
+                            "managed profile outside your profile group");
+                }
+            }
+        }
+        synchronized (mUsersLock) {
+            UserInfo userInfo =  getUserInfoLU(userId);
+            return userInfo != null && userInfo.isManagedProfile();
         }
     }
 
@@ -758,23 +818,28 @@
     }
 
     @Override
-    public ParcelFileDescriptor getUserIcon(int userId) {
+    public ParcelFileDescriptor getUserIcon(int targetUserId) {
         String iconPath;
         synchronized (mPackagesLock) {
-            UserInfo info = getUserInfoNoChecks(userId);
-            if (info == null || info.partial) {
-                Slog.w(LOG_TAG, "getUserIcon: unknown user #" + userId);
+            UserInfo targetUserInfo = getUserInfoNoChecks(targetUserId);
+            if (targetUserInfo == null || targetUserInfo.partial) {
+                Slog.w(LOG_TAG, "getUserIcon: unknown user #" + targetUserId);
                 return null;
             }
-            int callingGroupId = getUserInfoNoChecks(UserHandle.getCallingUserId()).profileGroupId;
-            if (callingGroupId == UserInfo.NO_PROFILE_GROUP_ID
-                    || callingGroupId != info.profileGroupId) {
+
+            final int callingUserId = UserHandle.getCallingUserId();
+            final int callingGroupId = getUserInfoNoChecks(callingUserId).profileGroupId;
+            final int targetGroupId = targetUserInfo.profileGroupId;
+            final boolean sameGroup = (callingGroupId != UserInfo.NO_PROFILE_GROUP_ID
+                    && callingGroupId == targetGroupId);
+            if ((callingUserId != targetUserId) && !sameGroup) {
                 checkManageUsersPermission("get the icon of a user who is not related");
             }
-            if (info.iconPath == null) {
+
+            if (targetUserInfo.iconPath == null) {
                 return null;
             }
-            iconPath = info.iconPath;
+            iconPath = targetUserInfo.iconPath;
         }
 
         try {
@@ -813,6 +878,7 @@
     private void initDefaultGuestRestrictions() {
         synchronized (mGuestRestrictions) {
             if (mGuestRestrictions.isEmpty()) {
+                mGuestRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true);
                 mGuestRestrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
                 mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);
                 mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
@@ -874,12 +940,12 @@
         }
         // Don't call them within the mRestrictionsLock.
         synchronized (mPackagesLock) {
-            if (globalChanged) {
-                writeUserListLP();
-            }
             if (localChanged) {
                 writeUserLP(getUserDataNoChecks(userId));
             }
+            if (globalChanged) {
+                writeUserListLP();
+            }
         }
 
         synchronized (mRestrictionsLock) {
@@ -1190,18 +1256,28 @@
      *
      * @param message used as message if SecurityException is thrown
      * @throws SecurityException if the caller is not system or root
+     * @see #hasManageUsersPermission()
      */
     private static final void checkManageUsersPermission(String message) {
-        final int uid = Binder.getCallingUid();
-        if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID
-                && ActivityManager.checkComponentPermission(
-                        android.Manifest.permission.MANAGE_USERS,
-                        uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+        if (!hasManageUsersPermission()) {
             throw new SecurityException("You need MANAGE_USERS permission to: " + message);
         }
     }
 
     /**
+     * @return whether the calling UID is system UID or root's UID or the calling app has the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}.
+     */
+    private static final boolean hasManageUsersPermission() {
+        final int callingUid = Binder.getCallingUid();
+        return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+                || callingUid == Process.ROOT_UID
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
      * Enforces that only the system UID or root's UID (on any user) can make certain calls to the
      * UserManager.
      *
@@ -1229,7 +1305,7 @@
             }
             FileOutputStream os;
             if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(tmp))
-                    && tmp.renameTo(file)) {
+                    && tmp.renameTo(file) && SELinux.restorecon(file)) {
                 info.iconPath = file.getAbsolutePath();
             }
             try {
@@ -1414,9 +1490,7 @@
             flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY;
         }
         // Create the system user
-        UserInfo system = new UserInfo(UserHandle.USER_SYSTEM,
-                mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
-                flags);
+        UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
         UserData userData = new UserData();
         userData.info = system;
         synchronized (mUsersLock) {
@@ -1433,8 +1507,12 @@
         updateUserIds();
         initDefaultGuestRestrictions();
 
-        writeUserListLP();
         writeUserLP(userData);
+        writeUserListLP();
+    }
+
+    private String getOwnerName() {
+        return mContext.getResources().getString(com.android.internal.R.string.owner_name);
     }
 
     private void scheduleWriteUser(UserData UserData) {
@@ -1480,6 +1558,10 @@
             serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
             serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
                     Long.toString(userInfo.lastLoggedInTime));
+            if (userInfo.lastLoggedInFingerprint != null) {
+                serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
+                        userInfo.lastLoggedInFingerprint);
+            }
             if (userInfo.iconPath != null) {
                 serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
             }
@@ -1506,9 +1588,11 @@
                     serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
                 }
             }
-            serializer.startTag(null, TAG_NAME);
-            serializer.text(userInfo.name);
-            serializer.endTag(null, TAG_NAME);
+            if (userInfo.name != null) {
+                serializer.startTag(null, TAG_NAME);
+                serializer.text(userInfo.name);
+                serializer.endTag(null, TAG_NAME);
+            }
             synchronized (mRestrictionsLock) {
                 UserRestrictionsUtils.writeRestrictions(serializer,
                         mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS);
@@ -1533,7 +1617,7 @@
             serializer.endDocument();
             userFile.finishWrite(fos);
         } catch (Exception ioe) {
-            Slog.e(LOG_TAG, "Error writing user info " + userData.info.id + "\n" + ioe);
+            Slog.e(LOG_TAG, "Error writing user info " + userData.info.id, ioe);
             userFile.failWrite(fos);
         }
     }
@@ -1608,6 +1692,7 @@
         String iconPath = null;
         long creationTime = 0L;
         long lastLoggedInTime = 0L;
+        String lastLoggedInFingerprint = null;
         int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
         int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
         boolean partial = false;
@@ -1648,6 +1733,8 @@
                 iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
                 creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
                 lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
+                lastLoggedInFingerprint = parser.getAttributeValue(null,
+                        ATTR_LAST_LOGGED_IN_FINGERPRINT);
                 profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
                         UserInfo.NO_PROFILE_GROUP_ID);
                 restrictedProfileParentId = readIntAttribute(parser,
@@ -1700,6 +1787,7 @@
             userInfo.serialNumber = serialNumber;
             userInfo.creationTime = creationTime;
             userInfo.lastLoggedInTime = lastLoggedInTime;
+            userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
             userInfo.partial = partial;
             userInfo.guestToRemove = guestToRemove;
             userInfo.profileGroupId = profileGroupId;
@@ -1870,10 +1958,12 @@
                     long now = System.currentTimeMillis();
                     userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
                     userInfo.partial = true;
+                    userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
                     userData = new UserData();
                     userData.info = userInfo;
                     mUsers.put(userId, userData);
                 }
+                writeUserLP(userData);
                 writeUserListLP();
                 if (parent != null) {
                     if (isManagedProfile) {
@@ -2126,7 +2216,13 @@
     }
 
     private void removeUserState(final int userHandle) {
-        mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
+        try {
+            mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
+        } catch (IllegalStateException e) {
+            // This may be simply because the user was partially created.
+            Slog.i(LOG_TAG,
+                "Destroying key for user " + userHandle + " failed, continuing anyway", e);
+        }
         // Cleanup package manager settings
         mPm.cleanUpUser(this, userHandle);
 
@@ -2141,13 +2237,13 @@
             mCachedEffectiveUserRestrictions.remove(userHandle);
             mDevicePolicyLocalUserRestrictions.remove(userHandle);
         }
-        // Remove user file
-        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
-        userFile.delete();
         // Update the user list
         synchronized (mPackagesLock) {
             writeUserListLP();
         }
+        // Remove user file
+        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
+        userFile.delete();
         updateUserIds();
         File userDir = Environment.getUserSystemDirectory(userHandle);
         File renamedUserDir = Environment.getUserSystemDirectory(UserHandle.USER_NULL - userHandle);
@@ -2203,6 +2299,7 @@
             if (restrictions == null || restrictions.isEmpty()) {
                 cleanAppRestrictionsForPackage(packageName, userId);
             } else {
+                restrictions.setDefusable(true);
                 // Write the restrictions to XML
                 writeApplicationRestrictionsLP(packageName, restrictions, userId);
             }
@@ -2490,7 +2587,7 @@
      * Called right before a user is unlocked. This gives us a chance to prepare
      * app storage.
      */
-    public void onBeforeUnlockUser(int userId) {
+    public void onBeforeUnlockUser(@UserIdInt int userId) {
         final int userSerial = getUserSerialNumber(userId);
         prepareUserStorage(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
         mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE);
@@ -2500,17 +2597,19 @@
      * Make a note of the last started time of a user and do some cleanup.
      * @param userId the user that was just foregrounded
      */
-    public void onUserForeground(int userId) {
+    public void onUserLoggedIn(@UserIdInt int userId) {
         UserData userData = getUserDataNoChecks(userId);
         if (userData == null || userData.info.partial) {
             Slog.w(LOG_TAG, "userForeground: unknown user #" + userId);
             return;
         }
-        long now = System.currentTimeMillis();
+
+        final long now = System.currentTimeMillis();
         if (now > EPOCH_PLUS_30_YEARS) {
             userData.info.lastLoggedInTime = now;
-            scheduleWriteUser(userData);
         }
+        userData.info.lastLoggedInFingerprint = Build.FINGERPRINT;
+        scheduleWriteUser(userData);
     }
 
     /**
@@ -2775,6 +2874,8 @@
                         sb.append(" ago");
                         pw.println(sb);
                     }
+                    pw.print("    Last logged in fingerprint: ");
+                    pw.println(userInfo.lastLoggedInFingerprint);
                     pw.print("    Has profile owner: ");
                     pw.println(mIsUserManaged.get(userId));
                     pw.println("    Restrictions:");
@@ -2982,6 +3083,22 @@
         }
 
         @Override
+        public void onEphemeralUserStop(int userId) {
+            synchronized (mUsersLock) {
+               UserInfo userInfo = getUserInfoLU(userId);
+               if (userInfo != null && userInfo.isEphemeral()) {
+                    // Do not allow switching back to the ephemeral user again as the user is going
+                    // to be deleted.
+                    userInfo.flags |= UserInfo.FLAG_DISABLED;
+                    if (userInfo.isGuest()) {
+                        // Indicate that the guest will be deleted after it stops.
+                        userInfo.guestToRemove = true;
+                    }
+               }
+            }
+        }
+
+        @Override
         public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
             UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL);
             // Keep this in sync with UserManager.createUser
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 4b355de62..364e9fa6 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -425,6 +425,18 @@
                             }
                         }
                     }
+                    break;
+                case UserManager.DISALLOW_SAFE_BOOT:
+                    // Unlike with the other restrictions, we want to propagate the new value to
+                    // the system settings even if it is false. The other restrictions modify
+                    // settings which could be manually changed by the user from the Settings app
+                    // after the policies enforcing these restrictions have been revoked, so we
+                    // leave re-setting of those settings to the user.
+                    android.provider.Settings.Global.putInt(
+                            context.getContentResolver(),
+                            android.provider.Settings.Global.SAFE_BOOT_DISALLOWED,
+                            newValue ? 1 : 0);
+                    break;
             }
         } finally {
             Binder.restoreCallingIdentity(id);
diff --git a/services/core/java/com/android/server/policy/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
index da9c001..6b203a9 100644
--- a/services/core/java/com/android/server/policy/EnableAccessibilityController.java
+++ b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
@@ -16,7 +16,9 @@
 
 package com.android.server.policy;
 
+import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -32,19 +34,25 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
+import android.util.Log;
 import android.util.MathUtils;
 import android.view.IWindowManager;
 import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 
 import com.android.internal.R;
+import com.android.server.LocalServices;
 
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
 public class EnableAccessibilityController {
+    private static final String TAG = "EnableAccessibilityController";
 
     private static final int SPEAK_WARNING_DELAY_MILLIS = 2000;
     private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 6000;
@@ -75,9 +83,6 @@
         }
     };
 
-    private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
-            ServiceManager.getService("window"));
-
     private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
             .Stub.asInterface(ServiceManager.getService("accessibility"));
 
@@ -132,7 +137,7 @@
                 && !getInstalledSpeakingAccessibilityServices(context).isEmpty();
     }
 
-    private static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
+    public static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
             Context context) {
         List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
         services.addAll(AccessibilityManager.getInstance(context)
@@ -213,71 +218,74 @@
     }
 
     private void enableAccessibility() {
-        List<AccessibilityServiceInfo> services = getInstalledSpeakingAccessibilityServices(
-                mContext);
-        if (services.isEmpty()) {
+        if (enableAccessibility(mContext)) {
+            mOnAccessibilityEnabledCallback.run();
+        }
+    }
+
+    public static boolean enableAccessibility(Context context) {
+        final IAccessibilityManager accessibilityManager = IAccessibilityManager
+                .Stub.asInterface(ServiceManager.getService("accessibility"));
+        final WindowManagerInternal windowManager = LocalServices.getService(
+                WindowManagerInternal.class);
+        final UserManager userManager = (UserManager) context.getSystemService(
+                Context.USER_SERVICE);
+        ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
+        if (componentName == null) {
+            return false;
+        }
+
+        boolean keyguardLocked = windowManager.isKeyguardLocked();
+        final boolean hasMoreThanOneUser = userManager.getUsers().size() > 1;
+        try {
+            if (!keyguardLocked || !hasMoreThanOneUser) {
+                final int userId = ActivityManager.getCurrentUser();
+                accessibilityManager.enableAccessibilityService(componentName, userId);
+            } else if (keyguardLocked) {
+                accessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
+                        componentName, true /* enableTouchExploration */);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "cannot enable accessibilty: " + e);
+        }
+
+        return true;
+    }
+
+    public static void disableAccessibility(Context context) {
+        final IAccessibilityManager accessibilityManager = IAccessibilityManager
+                .Stub.asInterface(ServiceManager.getService("accessibility"));
+        ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
+        if (componentName == null) {
             return;
         }
-        boolean keyguardLocked = false;
+
+        final int userId = ActivityManager.getCurrentUser();
         try {
-            keyguardLocked = mWindowManager.isKeyguardLocked();
-        } catch (RemoteException re) {
-            /* ignore */
+            accessibilityManager.disableAccessibilityService(componentName, userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "cannot disable accessibility " + e);
+        }
+    }
+
+    public static boolean isAccessibilityEnabled(Context context) {
+        final AccessibilityManager accessibilityManager =
+                context.getSystemService(AccessibilityManager.class);
+        List enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
+                AccessibilityServiceInfo.FEEDBACK_SPOKEN);
+        return enabledServices != null && !enabledServices.isEmpty();
+    }
+
+    @Nullable
+    public static ComponentName getInstalledSpeakingAccessibilityServiceComponent(
+            Context context) {
+        List<AccessibilityServiceInfo> services =
+                getInstalledSpeakingAccessibilityServices(context);
+        if (services.isEmpty()) {
+            return null;
         }
 
-        final boolean hasMoreThanOneUser = mUserManager.getUsers().size() > 1;
-
-        AccessibilityServiceInfo service = services.get(0);
-        boolean enableTouchExploration = (service.flags
-                & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
-        // Try to find a service supporting explore by touch.
-        if (!enableTouchExploration) {
-            final int serviceCount = services.size();
-            for (int i = 1; i < serviceCount; i++) {
-                AccessibilityServiceInfo candidate = services.get(i);
-                if ((candidate.flags & AccessibilityServiceInfo
-                        .FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0) {
-                    enableTouchExploration = true;
-                    service = candidate;
-                    break;
-                }
-            }
-        }
-
-        ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
-        ComponentName componentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
-        if (!keyguardLocked || !hasMoreThanOneUser) {
-            final int userId = ActivityManager.getCurrentUser();
-            String enabledServiceString = componentName.flattenToString();
-            ContentResolver resolver = mContext.getContentResolver();
-            // Enable one speaking accessibility service.
-            Settings.Secure.putStringForUser(resolver,
-                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                    enabledServiceString, userId);
-            // Allow the services we just enabled to toggle touch exploration.
-            Settings.Secure.putStringForUser(resolver,
-                    Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                    enabledServiceString, userId);
-            // Enable touch exploration.
-            if (enableTouchExploration) {
-                Settings.Secure.putIntForUser(resolver, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
-                        1, userId);
-            }
-            // Enable accessibility script injection (AndroidVox) for web content.
-            Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
-                    1, userId);
-            // Turn on accessibility mode last.
-            Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_ENABLED,
-                    1, userId);
-        } else if (keyguardLocked) {
-            try {
-                mAccessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
-                        componentName, enableTouchExploration);
-            } catch (RemoteException re) {
-                /* ignore */
-            }
-        }
-
-        mOnAccessibilityEnabledCallback.run();
+        ServiceInfo serviceInfo = services.get(0).getResolveInfo().serviceInfo;
+        return new ComponentName(serviceInfo.packageName, serviceInfo.name);
     }
 }
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index a0f20aa..5ef518e 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -18,6 +18,8 @@
 
 import com.android.internal.app.AlertController;
 import com.android.internal.app.AlertController.AlertParams;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.R;
@@ -388,6 +390,8 @@
                 public void run() {
                     try {
                         // Take an "interactive" bugreport.
+                        MetricsLogger.action(mContext,
+                                MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
                         ActivityManagerNative.getDefault().requestBugReport(
                                 ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
                     } catch (RemoteException e) {
@@ -405,6 +409,7 @@
             }
             try {
                 // Take a "full" bugreport.
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
                 ActivityManagerNative.getDefault().requestBugReport(
                         ActivityManager.BUGREPORT_OPTION_FULL);
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 716b96f..14d0457 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -18,13 +18,17 @@
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
 import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.view.WindowManager.DOCKED_TOP;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
 import static android.view.WindowManager.LayoutParams.*;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
@@ -33,7 +37,6 @@
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 
-import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerInternal;
@@ -54,6 +57,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.CompatibilityInfo;
@@ -73,6 +77,7 @@
 import android.media.RingtoneManager;
 import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.FactoryTest;
@@ -104,6 +109,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.LongSparseArray;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -132,6 +138,7 @@
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.policy.PhoneWindow;
+import com.android.internal.policy.IShortcutService;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.widget.PointerLocationView;
@@ -182,6 +189,9 @@
     static final int LONG_PRESS_POWER_SHUT_OFF = 2;
     static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
 
+    static final int LONG_PRESS_BACK_NOTHING = 0;
+    static final int LONG_PRESS_BACK_GO_TO_VOICE_ASSIST = 1;
+
     static final int MULTI_PRESS_POWER_NOTHING = 0;
     static final int MULTI_PRESS_POWER_THEATER_MODE = 1;
     static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2;
@@ -202,6 +212,13 @@
     static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0;
     static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1;
 
+    // Controls navigation bar opacity depending on which workspace stacks are currently
+    // visible.
+    // Nav bar is always opaque when either the freeform stack or docked stack is visible.
+    static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
+    // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
+    static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
+
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
     static final int APPLICATION_PANEL_SUBLAYER = 1;
@@ -235,6 +252,12 @@
     // app shows again. If that doesn't happen for 30s we drop the gesture.
     private static final long PANIC_GESTURE_EXPIRATION = 30000;
 
+    private static final String SYSUI_PACKAGE = "com.android.systemui";
+    private static final String SYSUI_SCREENSHOT_SERVICE =
+            "com.android.systemui.screenshot.TakeScreenshotService";
+    private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER =
+            "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver";
+
     /**
      * Keyguard stuff
      */
@@ -333,6 +356,8 @@
     int[] mNavigationBarHeightForRotationInCarMode = new int[4];
     int[] mNavigationBarWidthForRotationInCarMode = new int[4];
 
+    private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
+
     // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
     // This is for car dock and this is updated from resource.
     private boolean mEnableCarDockHomeCapture = true;
@@ -367,6 +392,7 @@
     // handler thread.  We'll need to resolve this someday by teaching the input dispatcher
     // to hold wakelocks during dispatch and eliminating the critical path.
     volatile boolean mPowerKeyHandled;
+    volatile boolean mBackKeyHandled;
     volatile boolean mBeganFromNonInteractive;
     volatile int mPowerKeyPressCounter;
     volatile boolean mEndCallKeyHandled;
@@ -419,6 +445,7 @@
     int mLongPressOnPowerBehavior;
     int mDoublePressOnPowerBehavior;
     int mTriplePressOnPowerBehavior;
+    int mLongPressOnBackBehavior;
     int mShortPressOnSleepBehavior;
     int mShortPressWindowBehavior;
     boolean mAwake;
@@ -528,6 +555,7 @@
     boolean mForceStatusBar;
     boolean mForceStatusBarFromKeyguard;
     private boolean mForceStatusBarTransparent;
+    int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
     boolean mHideLockScreen;
     boolean mForcingShowNavBar;
     int mForcingShowNavBarLayer;
@@ -573,6 +601,7 @@
     boolean mConsumeSearchKeyUp;
     boolean mAssistKeyLongPressed;
     boolean mPendingMetaAction;
+    boolean mForceShowSystemBars;
 
     // support for activating the lock screen while the screen is on
     boolean mAllowLockscreenWhenOn;
@@ -673,6 +702,7 @@
     private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 15;
     private static final int MSG_REQUEST_TRANSIENT_BARS = 16;
     private static final int MSG_REQUEST_TV_PICTURE_IN_PICTURE = 17;
+    private static final int MSG_BACK_LONG_PRESS = 18;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -737,6 +767,9 @@
                 case MSG_REQUEST_TV_PICTURE_IN_PICTURE:
                     requestTvPictureInPictureInternal();
                     break;
+                case MSG_BACK_LONG_PRESS:
+                    backLongPress();
+                    break;
             }
         }
     }
@@ -1083,6 +1116,13 @@
         }
     }
 
+    private void cancelPendingBackKeyAction() {
+        if (!mBackKeyHandled) {
+            mBackKeyHandled = true;
+            mHandler.removeMessages(MSG_BACK_LONG_PRESS);
+        }
+    }
+
     private void powerPress(long eventTime, boolean interactive, int count) {
         if (mScreenOnEarly && !mScreenOnFully) {
             Slog.i(TAG, "Suppressed redundant power key press while "
@@ -1190,6 +1230,19 @@
         }
     }
 
+    private void backLongPress() {
+        mBackKeyHandled = true;
+
+        switch (mLongPressOnBackBehavior) {
+            case LONG_PRESS_BACK_NOTHING:
+                break;
+            case LONG_PRESS_BACK_GO_TO_VOICE_ASSIST:
+                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+                startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+                break;
+        }
+    }
+
     private void sleepPress(long eventTime) {
         if (mShortPressOnSleepBehavior == SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME) {
             launchHomeFromHotKey(false /* awakenDreams */, true /*respectKeyguard*/);
@@ -1218,6 +1271,10 @@
         return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING;
     }
 
+    private boolean hasLongPressOnBackBehavior() {
+        return mLongPressOnBackBehavior != LONG_PRESS_BACK_NOTHING;
+    }
+
     private void interceptScreenshotChord() {
         if (mScreenshotChordEnabled
                 && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
@@ -1228,7 +1285,7 @@
                             + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
                 mScreenshotChordVolumeDownKeyConsumed = true;
                 cancelPendingPowerKeyAction();
-
+                mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
                 mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
             }
         }
@@ -1258,12 +1315,20 @@
         }
     };
 
-    private final Runnable mScreenshotRunnable = new Runnable() {
+    private class ScreenshotRunnable implements Runnable {
+        private int mScreenshotType = TAKE_SCREENSHOT_FULLSCREEN;
+
+        public void setScreenshotType(int screenshotType) {
+            mScreenshotType = screenshotType;
+        }
+
         @Override
         public void run() {
-            takeScreenshot();
+            takeScreenshot(mScreenshotType);
         }
-    };
+    }
+
+    private final ScreenshotRunnable mScreenshotRunnable = new ScreenshotRunnable();
 
     @Override
     public void showGlobalActions() {
@@ -1539,6 +1604,9 @@
         mSupportLongPressPowerWhenNonInteractive = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_supportLongPressPowerWhenNonInteractive);
 
+        mLongPressOnBackBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_longPressOnBackBehavior);
+
         mShortPressOnPowerBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shortPressOnPowerBehavior);
         mLongPressOnPowerBehavior = mContext.getResources().getInteger(
@@ -1707,6 +1775,9 @@
         if (mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
             mShortPressWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
         }
+
+        mNavBarOpacityMode = res.getInteger(
+                com.android.internal.R.integer.config_navBarOpacityMode);
     }
 
     @Override
@@ -2045,7 +2116,7 @@
 
                 // check if user has enabled this operation. SecurityException will be thrown if
                 // this app has not been allowed by the user
-                final int mode = mAppOpsManager.checkOp(outAppOp[0], callingUid,
+                final int mode = mAppOpsManager.checkOpNoThrow(outAppOp[0], callingUid,
                         attrs.packageName);
                 switch (mode) {
                     case AppOpsManager.MODE_ALLOWED:
@@ -2054,6 +2125,17 @@
                         // actually be hidden in WindowManagerService
                         return WindowManagerGlobal.ADD_OKAY;
                     case AppOpsManager.MODE_ERRORED:
+                        try {
+                            ApplicationInfo appInfo = mContext.getPackageManager()
+                                    .getApplicationInfo(attrs.packageName,
+                                            UserHandle.getUserId(callingUid));
+                            // Don't crash legacy apps
+                            if (appInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+                                return WindowManagerGlobal.ADD_OKAY;
+                            }
+                        } catch (PackageManager.NameNotFoundException e) {
+                            /* ignore */
+                        }
                         return WindowManagerGlobal.ADD_PERMISSION_DENIED;
                     default:
                         // in the default mode, we will make a decision here based on
@@ -2279,29 +2361,33 @@
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
             return 22;
+        case TYPE_SCREENSHOT:
+            // screenshot selection layer shouldn't go above system error, but it should cover
+            // navigation bars at the very least.
+            return 23;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
-            return 23;
+            return 24;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
-            return 24;
+            return 25;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
-            return 25;
+            return 26;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
-            return 26;
+            return 27;
         case TYPE_ACCESSIBILITY_OVERLAY:
             // overlay put by accessibility services to intercept user interaction
-            return 27;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 28;
-        case TYPE_BOOT_PROGRESS:
+        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 29;
+        case TYPE_BOOT_PROGRESS:
+            return 30;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 30;
+            return 31;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return 2;
@@ -2689,9 +2775,19 @@
         int insets = mWindowManagerFuncs.getDockedDividerInsetsLw();
 
         // If the divider is behind the navigation bar, don't animate.
-        if (mNavigationBar != null
-                && (win.getFrameLw().top + insets >= mNavigationBar.getFrameLw().top
-                        || win.getFrameLw().left + insets >= mNavigationBar.getFrameLw().left)) {
+        final Rect frame = win.getFrameLw();
+        final boolean behindNavBar = mNavigationBar != null
+                && ((mNavigationBarOnBottom
+                        && frame.top + insets >= mNavigationBar.getFrameLw().top)
+                || (!mNavigationBarOnBottom
+                        && frame.left + insets >= mNavigationBar.getFrameLw().left));
+        final boolean landscape = frame.height() > frame.width();
+        final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
+                || frame.left + insets >= win.getDisplayFrameLw().right);
+        final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
+                || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
+        final boolean offscreen = offscreenLandscape || offscreenPortrait;
+        if (behindNavBar || offscreen) {
             return 0;
         }
         if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
@@ -3001,11 +3097,18 @@
                     }
                 }
             }
+        } else if (keyCode == KeyEvent.KEYCODE_S && event.isMetaPressed()
+                && event.isCtrlPressed()) {
+            if (down && repeatCount == 0) {
+                int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
+                        : TAKE_SCREENSHOT_FULLSCREEN;
+                mScreenshotRunnable.setScreenshotType(type);
+                mHandler.post(mScreenshotRunnable);
+                return -1;
+            }
         } else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
-            if (down) {
-                if (repeatCount == 0) {
-                    toggleKeyboardShortcutsMenu();
-                }
+            if (down && repeatCount == 0 && !isKeyguardLocked()) {
+                toggleKeyboardShortcutsMenu(event.getDeviceId());
             }
         } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
             if (down) {
@@ -3048,6 +3151,7 @@
             }
         } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
             if (down && repeatCount == 0) {
+                mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
                 mHandler.post(mScreenshotRunnable);
             }
             return -1;
@@ -3096,7 +3200,9 @@
                 dispatchDirectAudioEvent(event);
                 return -1;
             }
-        } else if (KeyEvent.isMetaKey(keyCode)) {
+        }
+
+        if (KeyEvent.isMetaKey(keyCode)) {
             if (down) {
                 mPendingMetaAction = true;
             } else if (mPendingMetaAction) {
@@ -3211,6 +3317,35 @@
             return -1;
         }
 
+        if (down) {
+            long shortcutCode = (long) keyCode;
+            if (event.isCtrlPressed()) {
+                shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
+            }
+
+            if (event.isAltPressed()) {
+                shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
+            }
+
+            if (event.isShiftPressed()) {
+                shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
+            }
+
+            if (event.isMetaPressed()) {
+                shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE;
+            }
+
+            IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
+            if (shortcutService != null) {
+                try {
+                    shortcutService.notifyShortcutKeyPressed(shortcutCode);
+                } catch (RemoteException e) {
+                    mShortcutKeyServices.delete(shortcutCode);
+                }
+                return -1;
+            }
+        }
+
         // Reserve all the META modifier combos for system behavior
         if ((metaState & KeyEvent.META_META_ON) != 0) {
             return -1;
@@ -3300,6 +3435,18 @@
         return false;
     }
 
+    public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
+            throws RemoteException {
+        synchronized (mLock) {
+            IShortcutService service = mShortcutKeyServices.get(shortcutCode);
+            if (service != null && service.asBinder().pingBinder()) {
+                throw new RemoteException("Key already exists.");
+            }
+
+            mShortcutKeyServices.put(shortcutCode, shortcutService);
+        }
+    }
+
     private void launchAssistLongPressAction() {
         performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
         sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
@@ -3435,11 +3582,11 @@
         }
     }
 
-    private void toggleKeyboardShortcutsMenu() {
+    private void toggleKeyboardShortcutsMenu(int deviceId) {
         try {
             IStatusBarService statusbar = getStatusBarService();
             if (statusbar != null) {
-                statusbar.toggleKeyboardShortcutsMenu();
+                statusbar.toggleKeyboardShortcutsMenu(deviceId);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "RemoteException when showing keyboard shortcuts menu", e);
@@ -3605,7 +3752,7 @@
     }
 
     @Override
-    public void getInsetHintLw(WindowManager.LayoutParams attrs, int displayRotation,
+    public boolean getInsetHintLw(WindowManager.LayoutParams attrs, int displayRotation,
             Rect outContentInsets, Rect outStableInsets, Rect outOutsets) {
         final int fl = PolicyControl.getWindowFlags(null, attrs);
         final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
@@ -3660,10 +3807,11 @@
 
             outStableInsets.set(mStableLeft, mStableTop,
                     availRight - mStableRight, availBottom - mStableBottom);
-            return;
+            return mForceShowSystemBars;
         }
         outContentInsets.setEmpty();
         outStableInsets.setEmpty();
+        return mForceShowSystemBars;
     }
 
     private boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
@@ -4333,9 +4481,11 @@
                                     "Laying out navigation bar window: (%d,%d - %d,%d)",
                                     pf.left, pf.top, pf.right, pf.bottom));
                 } else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
-                                || attrs.type == TYPE_BOOT_PROGRESS)
+                                || attrs.type == TYPE_BOOT_PROGRESS
+                                || attrs.type == TYPE_SCREENSHOT)
                         && ((fl & FLAG_FULLSCREEN) != 0)) {
-                    // Fullscreen secure system overlays get what they ask for.
+                    // Fullscreen secure system overlays get what they ask for. Screenshot region
+                    // selection overlay should also expand to full screen.
                     pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
                     pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
                     pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
@@ -4491,7 +4641,9 @@
         }
 
         // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
-        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) {
+        // Also, we don't allow windows in multi-window mode to extend out of the screen.
+        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR
+                && !win.isInMultiWindowMode()) {
             df.left = df.top = -10000;
             df.right = df.bottom = 10000;
             if (attrs.type != TYPE_WALLPAPER) {
@@ -5084,21 +5236,22 @@
                 if (mScreenshotConnection != null) {
                     mContext.unbindService(mScreenshotConnection);
                     mScreenshotConnection = null;
+                    notifyScreenshotError();
                 }
             }
         }
     };
 
     // Assume this is called from the Handler thread.
-    private void takeScreenshot() {
+    private void takeScreenshot(final int screenshotType) {
         synchronized (mScreenshotLock) {
             if (mScreenshotConnection != null) {
                 return;
             }
-            ComponentName cn = new ComponentName("com.android.systemui",
-                    "com.android.systemui.screenshot.TakeScreenshotService");
-            Intent intent = new Intent();
-            intent.setComponent(cn);
+            final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE,
+                    SYSUI_SCREENSHOT_SERVICE);
+            final Intent serviceIntent = new Intent();
+            serviceIntent.setComponent(serviceComponent);
             ServiceConnection conn = new ServiceConnection() {
                 @Override
                 public void onServiceConnected(ComponentName name, IBinder service) {
@@ -5107,7 +5260,7 @@
                             return;
                         }
                         Messenger messenger = new Messenger(service);
-                        Message msg = Message.obtain(null, 1);
+                        Message msg = Message.obtain(null, screenshotType);
                         final ServiceConnection myConn = this;
                         Handler h = new Handler(mHandler.getLooper()) {
                             @Override
@@ -5133,17 +5286,35 @@
                         }
                     }
                 }
+
                 @Override
-                public void onServiceDisconnected(ComponentName name) {}
+                public void onServiceDisconnected(ComponentName name) {
+                    notifyScreenshotError();
+                }
             };
-            if (mContext.bindServiceAsUser(
-                    intent, conn, Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
+            if (mContext.bindServiceAsUser(serviceIntent, conn,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                    UserHandle.CURRENT)) {
                 mScreenshotConnection = conn;
                 mHandler.postDelayed(mScreenshotTimeout, 10000);
             }
         }
     }
 
+    /**
+     * Notifies the screenshot service to show an error.
+     */
+    private void notifyScreenshotError() {
+        // If the service process is killed, then ask it to clean up after itself
+        final ComponentName errorComponent = new ComponentName(SYSUI_PACKAGE,
+                SYSUI_SCREENSHOT_ERROR_RECEIVER);
+        Intent errorIntent = new Intent();
+        errorIntent.setComponent(errorComponent);
+        errorIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendBroadcastAsUser(errorIntent, UserHandle.ALL);
+    }
+
     /** {@inheritDoc} */
     @Override
     public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@@ -5214,6 +5385,29 @@
 
         // Handle special keys.
         switch (keyCode) {
+            case KeyEvent.KEYCODE_BACK: {
+                if (down) {
+                    mBackKeyHandled = false;
+                    if (hasLongPressOnBackBehavior()) {
+                        Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);
+                        msg.setAsynchronous(true);
+                        mHandler.sendMessageDelayed(msg,
+                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+                    }
+                } else {
+                    boolean handled = mBackKeyHandled;
+
+                    // Reset back key state
+                    cancelPendingBackKeyAction();
+
+                    // Don't pass back press to app if we've already handled it
+                    if (handled) {
+                        result &= ~ACTION_PASS_TO_USER;
+                    }
+                }
+                break;
+            }
+
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
@@ -6099,6 +6293,22 @@
         }
     }
 
+    @Override
+    public boolean isNavBarForcedShownLw(WindowState windowState) {
+        return mForceShowSystemBars;
+    }
+
+    @Override
+    public boolean isDockSideAllowed(int dockSide) {
+
+        // We do not allow all dock sides at which the navigation bar touches the docked stack.
+        if (!mNavigationBarCanMove) {
+            return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT;
+        } else {
+            return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT;
+        }
+    }
+
     void sendCloseSystemWindows() {
         PhoneWindow.sendCloseSystemWindows(mContext, null);
     }
@@ -6980,8 +7190,8 @@
         // We need to force system bars when the docked stack is visible, when the freeform stack
         // is visible but also when we are resizing for the transitions when docked stack
         // visibility changes.
-        final boolean forceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
-        final boolean forceOpaqueSystemBars = forceShowSystemBars && !mForceStatusBarFromKeyguard;
+        mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
+        final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
 
         // apply translucent bar vis flags
         WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen
@@ -7006,11 +7216,12 @@
         }
 
         if ((!areTranslucentBarsAllowed() && transWin != mStatusBar)
-                || forceOpaqueSystemBars) {
-            vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
-                    | View.SYSTEM_UI_TRANSPARENT);
+                || forceOpaqueStatusBar) {
+            vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
         }
 
+        vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);
+
         if (mForceWindowDrawsStatusBarBackground) {
             vis |= View.STATUS_BAR_TRANSPARENT;
             vis &= ~View.STATUS_BAR_TRANSLUCENT;
@@ -7029,11 +7240,11 @@
                 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
 
         final boolean transientStatusBarAllowed = mStatusBar != null
-                && (statusBarHasFocus || (!forceShowSystemBars
+                && (statusBarHasFocus || (!mForceShowSystemBars
                         && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
 
         final boolean transientNavBarAllowed = mNavigationBar != null
-                && !forceShowSystemBars && hideNavBarSysui && immersiveSticky;
+                && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
 
         final long now = SystemClock.uptimeMillis();
         final boolean pendingPanic = mPendingPanicGestureUptime != 0
@@ -7050,7 +7261,7 @@
                 && !transientStatusBarAllowed && hideStatusBarSysui;
         final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
                 && !transientNavBarAllowed;
-        if (denyTransientStatus || denyTransientNav || forceShowSystemBars) {
+        if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
             // clear the clearable flags instead
             clearClearableFlagsLw();
             vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
@@ -7083,6 +7294,41 @@
         return vis;
     }
 
+    /**
+     * @return the current visibility flags with the nav-bar opacity related flags toggled based
+     *         on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
+     */
+    private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
+            boolean freeformStackVisible, boolean isDockedDividerResizing) {
+        if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
+            if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
+                visibility = setNavBarOpaqueFlag(visibility);
+            }
+        } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
+            if (isDockedDividerResizing) {
+                visibility = setNavBarOpaqueFlag(visibility);
+            } else if (freeformStackVisible) {
+                visibility = setNavBarTranslucentFlag(visibility);
+            } else {
+                visibility = setNavBarOpaqueFlag(visibility);
+            }
+        }
+
+        if (!areTranslucentBarsAllowed()) {
+            visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
+        }
+        return visibility;
+    }
+
+    private int setNavBarOpaqueFlag(int visibility) {
+        return visibility &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
+    }
+
+    private int setNavBarTranslucentFlag(int visibility) {
+        visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
+        return visibility |= View.NAVIGATION_BAR_TRANSLUCENT;
+    }
+
     private void clearClearableFlagsLw() {
         int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
         if (newVal != mResettingSystemUiFlags) {
@@ -7210,6 +7456,8 @@
                 pw.print(" mLidControlsScreenLock="); pw.println(mLidControlsScreenLock);
                 pw.print(" mLidControlsSleep="); pw.println(mLidControlsSleep);
         pw.print(prefix);
+                pw.print(" mLongPressOnBackBehavior="); pw.println(mLongPressOnBackBehavior);
+        pw.print(prefix);
                 pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
                 pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
         pw.print(prefix);
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
index 9284442..a14c614 100644
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -78,7 +78,7 @@
     public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
         ShortcutInfo shortcut = null;
 
-        // If the Shift key is preesed, then search for the shift shortcuts.
+        // If the Shift key is pressed, then search for the shift shortcuts.
         boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
         SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts;
 
@@ -138,14 +138,18 @@
                     ComponentName componentName = new ComponentName(packageName, className);
                     try {
                         info = packageManager.getActivityInfo(componentName,
-                                PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                     } catch (PackageManager.NameNotFoundException e) {
                         String[] packages = packageManager.canonicalToCurrentPackageNames(
                                 new String[] { packageName });
                         componentName = new ComponentName(packages[0], className);
                         try {
                             info = packageManager.getActivityInfo(componentName,
-                                    PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+                                    PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                            | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                         } catch (PackageManager.NameNotFoundException e1) {
                             Log.w(TAG, "Unable to add bookmark: " + packageName
                                     + "/" + className, e);
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
index 9d353c6..86d0468 100644
--- a/services/core/java/com/android/server/policy/StatusBarController.java
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -29,6 +29,8 @@
 import android.view.animation.TranslateAnimation;
 
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
 
 import static android.view.WindowManagerInternal.*;
 
@@ -103,6 +105,20 @@
                 }
             });
         }
+
+        @Override
+        public void onAppTransitionFinishedLocked(IBinder token) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    StatusBarManagerInternal statusbar = LocalServices.getService(
+                            StatusBarManagerInternal.class);
+                    if (statusbar != null) {
+                        statusbar.appTransitionFinished();
+                    }
+                }
+            });
+        }
     };
 
     public StatusBarController() {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index dbaa598..7570960 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.power;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -50,6 +51,7 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
+import android.provider.Settings.SettingNotFoundException;
 import android.service.dreams.DreamManagerInternal;
 import android.util.EventLog;
 import android.util.Slog;
@@ -57,9 +59,11 @@
 import android.util.TimeUtils;
 import android.view.Display;
 import android.view.WindowManagerPolicy;
+
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.EventLogTags;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
@@ -67,10 +71,14 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
+import com.android.server.vr.VrManagerInternal;
+import com.android.server.vr.VrStateListener;
 import libcore.util.Objects;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -152,6 +160,7 @@
     // Power hints defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_HINT_LOW_POWER = 5;
     private static final int POWER_HINT_SUSTAINED_PERFORMANCE = 6;
+    private static final int POWER_HINT_VR_MODE = 7;
 
     // Power features defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1;
@@ -159,6 +168,14 @@
     // Default setting for double tap to wake.
     private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0;
 
+    /** Constants for {@link #shutdownOrRebootInternal} */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({HALT_MODE_SHUTDOWN, HALT_MODE_REBOOT, HALT_MODE_REBOOT_SAFE_MODE})
+    public @interface HaltMode {}
+    private static final int HALT_MODE_SHUTDOWN = 0;
+    private static final int HALT_MODE_REBOOT = 1;
+    private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
+
     private final Context mContext;
     private final ServiceThread mHandlerThread;
     private final PowerManagerHandler mHandler;
@@ -254,6 +271,9 @@
     // True if boot completed occurred.  We keep the screen on until this happens.
     private boolean mBootCompleted;
 
+    // Runnables that should be triggered on boot completed
+    private Runnable[] mBootCompletedRunnables;
+
     // True if auto-suspend mode is enabled.
     // Refer to autosuspend.h.
     private boolean mHalAutoSuspendModeEnabled;
@@ -518,13 +538,24 @@
     @Override
     public void onBootPhase(int phase) {
         synchronized (mLock) {
-            if (phase == PHASE_BOOT_COMPLETED) {
+            if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+                incrementBootCount();
+
+            } else if (phase == PHASE_BOOT_COMPLETED) {
                 final long now = SystemClock.uptimeMillis();
                 mBootCompleted = true;
                 mDirty |= DIRTY_BOOT_COMPLETED;
                 userActivityNoUpdateLocked(
                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
                 updatePowerStateLocked();
+
+                if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) {
+                    Slog.d(TAG, "Posting " + mBootCompletedRunnables.length + " delayed runnables");
+                    for (Runnable r : mBootCompletedRunnables) {
+                        BackgroundThread.getHandler().post(r);
+                    }
+                }
+                mBootCompletedRunnables = null;
             }
         }
     }
@@ -627,6 +658,7 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Secure.BRIGHTNESS_USE_TWILIGHT),
                     false, mSettingsObserver, UserHandle.USER_ALL);
+            getLocalService(VrManagerInternal.class).registerListener(mVrStateListener);
             // Go.
             readConfigurationLocked();
             updateSettingsLocked();
@@ -750,7 +782,17 @@
         mDirty |= DIRTY_SETTINGS;
     }
 
-    void updateLowPowerModeLocked() {
+    private void postAfterBootCompleted(Runnable r) {
+        if (mBootCompleted) {
+            BackgroundThread.getHandler().post(r);
+        } else {
+            Slog.d(TAG, "Delaying runnable until system is booted");
+            mBootCompletedRunnables = ArrayUtils.appendElement(Runnable.class,
+                    mBootCompletedRunnables, r);
+        }
+    }
+
+    private void updateLowPowerModeLocked() {
         if (mIsPowered && mLowPowerModeSetting) {
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateLowPowerModeLocked: powered, turning setting off");
@@ -767,7 +809,7 @@
         if (mLowPowerModeEnabled != lowPowerModeEnabled) {
             mLowPowerModeEnabled = lowPowerModeEnabled;
             powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
-            BackgroundThread.getHandler().post(new Runnable() {
+            postAfterBootCompleted(new Runnable() {
                 @Override
                 public void run() {
                     Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
@@ -2366,7 +2408,7 @@
         updatePowerStateLocked();
     }
 
-    private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
+    private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
             final String reason, boolean wait) {
         if (mHandler == null || !mSystemReady) {
             throw new IllegalStateException("Too early to call shutdown() or reboot()");
@@ -2376,10 +2418,12 @@
             @Override
             public void run() {
                 synchronized (this) {
-                    if (shutdown) {
-                        ShutdownThread.shutdown(mContext, reason, confirm);
-                    } else {
+                    if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
+                        ShutdownThread.rebootSafeMode(mContext, confirm);
+                    } else if (haltMode == HALT_MODE_REBOOT) {
                         ShutdownThread.reboot(mContext, reason, confirm);
+                    } else {
+                        ShutdownThread.shutdown(mContext, reason, confirm);
                     }
                 }
             }
@@ -2703,12 +2747,9 @@
         if (reason == null) {
             reason = "";
         }
-        if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
-            // If we are rebooting to go into recovery, instead of
-            // setting sys.powerctl directly we'll start the
-            // pre-recovery service which will do some preparation for
-            // recovery and then reboot for us.
-            SystemProperties.set("ctl.start", "pre-recovery");
+        if (reason.equals(PowerManager.REBOOT_RECOVERY)
+                || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+            SystemProperties.set("sys.powerctl", "reboot,recovery");
         } else {
             SystemProperties.set("sys.powerctl", "reboot," + reason);
         }
@@ -2893,6 +2934,20 @@
         return suspendBlocker;
     }
 
+    private void incrementBootCount() {
+        synchronized (mLock) {
+            int count;
+            try {
+                count = Settings.Global.getInt(
+                        getContext().getContentResolver(), Settings.Global.BOOT_COUNT);
+            } catch (SettingNotFoundException e) {
+                count = 0;
+            }
+            Settings.Global.putInt(
+                    getContext().getContentResolver(), Settings.Global.BOOT_COUNT, count + 1);
+        }
+    }
+
     private static WorkSource copyWorkSource(WorkSource workSource) {
         return workSource != null ? new WorkSource(workSource) : null;
     }
@@ -2952,6 +3007,13 @@
         }
     }
 
+    private final VrStateListener mVrStateListener = new VrStateListener() {
+        @Override
+        public void onVrStateChanged(boolean enabled) {
+            powerHintInternal(POWER_HINT_VR_MODE, enabled ? 1 : 0);
+        }
+    };
+
     /**
      * Handler for asynchronous operations performed by the power manager.
      */
@@ -3421,13 +3483,33 @@
         @Override // Binder call
         public void reboot(boolean confirm, String reason, boolean wait) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
-            if (PowerManager.REBOOT_RECOVERY.equals(reason)) {
+            if (PowerManager.REBOOT_RECOVERY.equals(reason)
+                    || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
                 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
             }
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                shutdownOrRebootInternal(false, confirm, reason, wait);
+                shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Reboots the device into safe mode
+         *
+         * @param confirm If true, shows a reboot confirmation dialog.
+         * @param wait If true, this call waits for the reboot to complete and does not return.
+         */
+        @Override // Binder call
+        public void rebootSafeMode(boolean confirm, boolean wait) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm,
+                        PowerManager.REBOOT_SAFE_MODE, wait);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -3445,7 +3527,7 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                shutdownOrRebootInternal(true, confirm, reason, wait);
+                shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index ac6a28e..bcafddc 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -32,8 +32,10 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.os.RecoverySystem;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -81,13 +83,9 @@
     private static Object sIsStartedGuard = new Object();
     private static boolean sIsStarted = false;
 
-    // uncrypt status files
-    private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
-    private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
-
     private static boolean mReboot;
     private static boolean mRebootSafeMode;
-    private static boolean mRebootUpdate;
+    private static boolean mRebootHasProgressBar;
     private static String mReason;
 
     // Provides shutdown assurance in case the system_server is killed
@@ -96,6 +94,9 @@
     // Indicates whether we are rebooting into safe mode
     public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode";
 
+    // Indicates whether we should stay in safe mode until ro.build.date.utc is newer than this
+    public static final String AUDIT_SAFEMODE_PROPERTY = "persist.sys.audit_safemode";
+
     // static instance of this thread
     private static final ShutdownThread sInstance = new ShutdownThread();
 
@@ -213,7 +214,7 @@
     public static void reboot(final Context context, String reason, boolean confirm) {
         mReboot = true;
         mRebootSafeMode = false;
-        mRebootUpdate = false;
+        mRebootHasProgressBar = false;
         mReason = reason;
         shutdownInner(context, confirm);
     }
@@ -233,7 +234,7 @@
 
         mReboot = true;
         mRebootSafeMode = true;
-        mRebootUpdate = false;
+        mRebootHasProgressBar = false;
         mReason = null;
         shutdownInner(context, confirm);
     }
@@ -250,10 +251,19 @@
         // Throw up a system dialog to indicate the device is rebooting / shutting down.
         ProgressDialog pd = new ProgressDialog(context);
 
-        // Path 1: Reboot to recovery and install the update
-        //   Condition: mReason == REBOOT_RECOVERY and mRebootUpdate == True
-        //   (mRebootUpdate is set by checking if /cache/recovery/uncrypt_file exists.)
-        //   UI: progress bar
+        // Path 1: Reboot to recovery for update
+        //   Condition: mReason == REBOOT_RECOVERY_UPDATE
+        //
+        //  Path 1a: uncrypt needed
+        //   Condition: if /cache/recovery/uncrypt_file exists but
+        //              /cache/recovery/block.map doesn't.
+        //   UI: determinate progress bar (mRebootHasProgressBar == True)
+        //
+        // * Path 1a is expected to be removed once the GmsCore shipped on
+        //   device always calls uncrypt prior to reboot.
+        //
+        //  Path 1b: uncrypt already done
+        //   UI: spinning circle only (no progress bar)
         //
         // Path 2: Reboot to recovery for factory reset
         //   Condition: mReason == REBOOT_RECOVERY
@@ -262,24 +272,31 @@
         // Path 3: Regular reboot / shutdown
         //   Condition: Otherwise
         //   UI: spinning circle only (no progress bar)
-        if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
-            mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
-            if (mRebootUpdate) {
-                pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
-                pd.setMessage(context.getText(
-                        com.android.internal.R.string.reboot_to_update_prepare));
+        if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
+            // We need the progress bar if uncrypt will be invoked during the
+            // reboot, which might be time-consuming.
+            mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
+                    && !(RecoverySystem.BLOCK_MAP_FILE.exists());
+            pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
+            if (mRebootHasProgressBar) {
                 pd.setMax(100);
-                pd.setProgressNumberFormat(null);
-                pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                 pd.setProgress(0);
                 pd.setIndeterminate(false);
-            } else {
-                // Factory reset path. Set the dialog message accordingly.
-                pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
+                pd.setProgressNumberFormat(null);
+                pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                 pd.setMessage(context.getText(
-                        com.android.internal.R.string.reboot_to_reset_message));
+                            com.android.internal.R.string.reboot_to_update_prepare));
+            } else {
                 pd.setIndeterminate(true);
+                pd.setMessage(context.getText(
+                            com.android.internal.R.string.reboot_to_update_reboot));
             }
+        } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
+            // Factory reset path. Set the dialog message accordingly.
+            pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
+            pd.setMessage(context.getText(
+                        com.android.internal.R.string.reboot_to_reset_message));
+            pd.setIndeterminate(true);
         } else {
             pd.setTitle(context.getText(com.android.internal.R.string.power_off));
             pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
@@ -379,7 +396,7 @@
                 if (delay <= 0) {
                     Log.w(TAG, "Shutdown broadcast timed out");
                     break;
-                } else if (mRebootUpdate) {
+                } else if (mRebootHasProgressBar) {
                     int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
                             BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
                     sInstance.setRebootProgress(status, null);
@@ -390,7 +407,7 @@
                 }
             }
         }
-        if (mRebootUpdate) {
+        if (mRebootHasProgressBar) {
             sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
         }
 
@@ -404,7 +421,7 @@
             } catch (RemoteException e) {
             }
         }
-        if (mRebootUpdate) {
+        if (mRebootHasProgressBar) {
             sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
         }
 
@@ -415,13 +432,13 @@
         if (pm != null) {
             pm.shutdown();
         }
-        if (mRebootUpdate) {
+        if (mRebootHasProgressBar) {
             sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
         }
 
         // Shutdown radios.
         shutdownRadios(MAX_RADIO_WAIT_TIME);
-        if (mRebootUpdate) {
+        if (mRebootHasProgressBar) {
             sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
         }
 
@@ -455,7 +472,7 @@
                 if (delay <= 0) {
                     Log.w(TAG, "Shutdown wait timed out");
                     break;
-                } else if (mRebootUpdate) {
+                } else if (mRebootHasProgressBar) {
                     int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
                             (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
                             MAX_SHUTDOWN_WAIT_TIME);
@@ -468,10 +485,11 @@
                 }
             }
         }
-        if (mRebootUpdate) {
+        if (mRebootHasProgressBar) {
             sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
 
-            // If it's to reboot to install update, invoke uncrypt via init service.
+            // If it's to reboot to install an update and uncrypt hasn't been
+            // done yet, trigger it now.
             uncrypt();
         }
 
@@ -549,7 +567,7 @@
 
                 long delay = endTime - SystemClock.elapsedRealtime();
                 while (delay > 0) {
-                    if (mRebootUpdate) {
+                    if (mRebootHasProgressBar) {
                         int status = (int)((timeout - delay) * 1.0 *
                                 (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
                         status += PACKAGE_MANAGER_STOP_PERCENT;
@@ -651,66 +669,40 @@
     private void uncrypt() {
         Log.i(TAG, "Calling uncrypt and monitoring the progress...");
 
+        final RecoverySystem.ProgressListener progressListener =
+                new RecoverySystem.ProgressListener() {
+            @Override
+            public void onProgress(int status) {
+                if (status >= 0 && status < 100) {
+                    // Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100).
+                    status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100);
+                    status += MOUNT_SERVICE_STOP_PERCENT;
+                    CharSequence msg = mContext.getText(
+                            com.android.internal.R.string.reboot_to_update_package);
+                    sInstance.setRebootProgress(status, msg);
+                } else if (status == 100) {
+                    CharSequence msg = mContext.getText(
+                            com.android.internal.R.string.reboot_to_update_reboot);
+                    sInstance.setRebootProgress(status, msg);
+                } else {
+                    // Ignored
+                }
+            }
+        };
+
         final boolean[] done = new boolean[1];
         done[0] = false;
         Thread t = new Thread() {
             @Override
             public void run() {
-                // Create the status pipe file to communicate with /system/bin/uncrypt.
-                new File(UNCRYPT_STATUS_FILE).delete();
+                RecoverySystem rs = (RecoverySystem) mContext.getSystemService(
+                        Context.RECOVERY_SERVICE);
+                String filename = null;
                 try {
-                    Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
-                } catch (ErrnoException e) {
-                    Log.w(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE +
-                            "\": " + e.getMessage());
-                }
-
-                SystemProperties.set("ctl.start", "uncrypt");
-
-                // Read the status from the pipe.
-                try (BufferedReader reader = new BufferedReader(
-                        new FileReader(UNCRYPT_STATUS_FILE))) {
-
-                    int lastStatus = Integer.MIN_VALUE;
-                    while (true) {
-                        String str = reader.readLine();
-                        try {
-                            int status = Integer.parseInt(str);
-
-                            // Avoid flooding the log with the same message.
-                            if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
-                                continue;
-                            }
-                            lastStatus = status;
-
-                            if (status >= 0 && status < 100) {
-                                // Update status
-                                Log.d(TAG, "uncrypt read status: " + status);
-                                // Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100).
-                                status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100);
-                                status += MOUNT_SERVICE_STOP_PERCENT;
-                                CharSequence msg = mContext.getText(
-                                        com.android.internal.R.string.reboot_to_update_package);
-                                sInstance.setRebootProgress(status, msg);
-                            } else if (status == 100) {
-                                Log.d(TAG, "uncrypt successfully finished.");
-                                CharSequence msg = mContext.getText(
-                                        com.android.internal.R.string.reboot_to_update_reboot);
-                                sInstance.setRebootProgress(status, msg);
-                                break;
-                            } else {
-                                // Error in /system/bin/uncrypt. Or it's rebooting to recovery
-                                // to perform other operations (e.g. factory reset).
-                                Log.d(TAG, "uncrypt failed with status: " + status);
-                                break;
-                            }
-                        } catch (NumberFormatException unused) {
-                            Log.d(TAG, "uncrypt invalid status received: " + str);
-                            break;
-                        }
-                    }
-                } catch (IOException unused) {
-                    Log.w(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+                    filename = FileUtils.readTextFile(RecoverySystem.UNCRYPT_PACKAGE_FILE, 0, null);
+                    rs.processPackage(mContext, new File(filename), progressListener);
+                } catch (IOException e) {
+                    Log.e(TAG, "Error uncrypting file", e);
                 }
                 done[0] = true;
             }
diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
index 0046fbb..6bacdfd 100644
--- a/services/core/java/com/android/server/search/Searchables.java
+++ b/services/core/java/com/android/server/search/Searchables.java
@@ -410,7 +410,7 @@
             activities =
                     mPm.queryIntentActivities(intent,
                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                    flags, mUserId);
+                    flags, mUserId).getList();
         } catch (RemoteException re) {
             // Local call
         }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index cbbcdae..9614417 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -33,4 +33,6 @@
     void topAppWindowChanged(boolean menuVisible);
     void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
             Rect fullscreenBounds, Rect dockedBounds, String cause);
+    void toggleSplitScreen();
+    void appTransitionFinished();
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 6eab8d4..dbbaa5e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -204,6 +204,25 @@
             StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
                     dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
         }
+
+        @Override
+        public void toggleSplitScreen() {
+            enforceStatusBarService();
+            if (mBar != null) {
+                try {
+                    mBar.toggleSplitScreen();
+                } catch (RemoteException ex) {}
+            }
+        }
+
+        public void appTransitionFinished() {
+            enforceStatusBarService();
+            if (mBar != null) {
+                try {
+                    mBar.appTransitionFinished();
+                } catch (RemoteException ex) {}
+            }
+        }
     };
 
     // ================================================================================
@@ -300,7 +319,7 @@
      */
     @Override
     public void disable2(int what, IBinder token, String pkg) {
-        disableForUser(what, token, pkg, mCurrentUserId);
+        disable2ForUser(what, token, pkg, mCurrentUserId);
     }
 
     /**
@@ -554,10 +573,10 @@
     }
 
     @Override
-    public void toggleKeyboardShortcutsMenu() {
+    public void toggleKeyboardShortcutsMenu(int deviceId) {
         if (mBar != null) {
             try {
-                mBar.toggleKeyboardShortcutsMenu();
+                mBar.toggleKeyboardShortcutsMenu(deviceId);
             } catch (RemoteException ex) {}
         }
     }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index e5c5b2bc..858f7c7 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -81,6 +81,7 @@
     private boolean mBound;
     private long mScheduledRestartUptimeMillis;
     private long mMaximumTimeToLock; // from DevicePolicyManager
+    private boolean mPendingSuccessfulUnlock = false;
 
     // Trust state
     private boolean mTrusted;
@@ -234,6 +235,11 @@
             setCallback(mCallback);
             updateDevicePolicyFeatures();
 
+            if (mPendingSuccessfulUnlock) {
+                onUnlockAttempt(true);
+                mPendingSuccessfulUnlock = false;
+            }
+
             if (mTrustManagerService.isDeviceLockedInner(mUserId)) {
                 onDeviceLocked();
             } else {
@@ -302,7 +308,11 @@
      */
     public void onUnlockAttempt(boolean successful) {
         try {
-            if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
+            if (mTrustAgentService != null) {
+                mTrustAgentService.onUnlockAttempt(successful);
+            } else {
+                mPendingSuccessfulUnlock = successful;
+            }
         } catch (RemoteException e) {
             onError(e);
         }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index b54e866..984fb76 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -19,7 +19,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
 import com.android.server.SystemService;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -104,7 +103,7 @@
     private static final int MSG_SET_DEVICE_LOCKED = 10;
     private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 11;
 
-    public static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
+    private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
 
     private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
@@ -136,13 +135,7 @@
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
         mLockPatternUtils = new LockPatternUtils(context);
-
-        mStrongAuthTracker = new StrongAuthTracker(context) {
-            @Override
-            public void onStrongAuthRequiredChanged(int userId) {
-                refreshAgentList(userId);
-            }
-        };
+        mStrongAuthTracker = new StrongAuthTracker(context);
     }
 
     @Override
@@ -231,24 +224,24 @@
                 TRUST_USUALLY_MANAGED_FLUSH_DELAY);
     }
 
-    void refreshAgentList(int userId) {
-        if (DEBUG) Slog.d(TAG, "refreshAgentList()");
+    void refreshAgentList(int userIdOrAll) {
+        if (DEBUG) Slog.d(TAG, "refreshAgentList(" + userIdOrAll + ")");
         if (!mTrustAgentsCanRun) {
             return;
         }
-        if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) {
-            Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle,"
+        if (userIdOrAll != UserHandle.USER_ALL && userIdOrAll < UserHandle.USER_SYSTEM) {
+            Log.e(TAG, "refreshAgentList(userId=" + userIdOrAll + "): Invalid user handle,"
                     + " must be USER_ALL or a specific user.", new Throwable("here"));
-            userId = UserHandle.USER_ALL;
+            userIdOrAll = UserHandle.USER_ALL;
         }
         PackageManager pm = mContext.getPackageManager();
 
         List<UserInfo> userInfos;
-        if (userId == UserHandle.USER_ALL) {
+        if (userIdOrAll == UserHandle.USER_ALL) {
             userInfos = mUserManager.getUsers(true /* excludeDying */);
         } else {
             userInfos = new ArrayList<>();
-            userInfos.add(mUserManager.getUserInfo(userId));
+            userInfos.add(mUserManager.getUserInfo(userIdOrAll));
         }
         LockPatternUtils lockPatternUtils = mLockPatternUtils;
 
@@ -261,7 +254,7 @@
             if (!userInfo.supportsSwitchToByUser()) continue;
             if (!mActivityManager.isUserRunning(userInfo.id)) continue;
             if (!lockPatternUtils.isSecure(userInfo.id)) continue;
-            if (!mStrongAuthTracker.isTrustAllowedForUser(userInfo.id)) continue;
+            if (!mStrongAuthTracker.canAgentsRunForUser(userInfo.id)) continue;
             DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
             int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
             final boolean disableTrustAgents =
@@ -302,7 +295,7 @@
         boolean trustMayHaveChanged = false;
         for (int i = 0; i < obsoleteAgents.size(); i++) {
             AgentInfo info = obsoleteAgents.valueAt(i);
-            if (userId == UserHandle.USER_ALL || userId == info.userId) {
+            if (userIdOrAll == UserHandle.USER_ALL || userIdOrAll == info.userId) {
                 if (info.agent.isManagingTrust()) {
                     trustMayHaveChanged = true;
                 }
@@ -312,10 +305,10 @@
         }
 
         if (trustMayHaveChanged) {
-            if (userId == UserHandle.USER_ALL) {
+            if (userIdOrAll == UserHandle.USER_ALL) {
                 updateTrustAll();
             } else {
-                updateTrust(userId, 0);
+                updateTrust(userIdOrAll, 0);
             }
         }
     }
@@ -578,6 +571,10 @@
     }
 
     private void dispatchUnlockAttempt(boolean successful, int userId) {
+        if (successful) {
+            mStrongAuthTracker.allowTrustFromUnlock(userId);
+        }
+
         for (int i = 0; i < mActiveAgents.size(); i++) {
             AgentInfo info = mActiveAgents.valueAt(i);
             if (info.userId == userId) {
@@ -608,6 +605,10 @@
     }
 
     private void dispatchOnTrustChanged(boolean enabled, int userId, int flags) {
+        if (DEBUG) {
+            Log.i(TAG, "onTrustChanged(" + enabled + ", " + userId + ", 0x"
+                    + Integer.toHexString(flags) + ")");
+        }
         if (!enabled) flags = 0;
         for (int i = 0; i < mTrustListeners.size(); i++) {
             try {
@@ -623,6 +624,9 @@
     }
 
     private void dispatchOnTrustManagedChanged(boolean managed, int userId) {
+        if (DEBUG) {
+            Log.i(TAG, "onTrustManagedChanged(" + managed + ", " + userId + ")");
+        }
         for (int i = 0; i < mTrustListeners.size(); i++) {
             try {
                 mTrustListeners.get(i).onTrustManagedChanged(managed, userId);
@@ -980,4 +984,61 @@
                     null /* scheduler */);
         }
     }
+
+    private class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+        SparseBooleanArray mStartFromSuccessfulUnlock = new SparseBooleanArray();
+
+        public StrongAuthTracker(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStrongAuthRequiredChanged(int userId) {
+            mStartFromSuccessfulUnlock.delete(userId);
+
+            if (DEBUG) {
+                Log.i(TAG, "onStrongAuthRequiredChanged(" + userId + ") ->"
+                        + " trustAllowed=" + isTrustAllowedForUser(userId)
+                        + " agentsCanRun=" + canAgentsRunForUser(userId));
+            }
+
+            refreshAgentList(userId);
+
+            // The list of active trust agents may not have changed, if there was a previous call
+            // to allowTrustFromUnlock, so we update the trust here too.
+            updateTrust(userId, 0 /* flags */);
+        }
+
+        boolean canAgentsRunForUser(int userId) {
+            return mStartFromSuccessfulUnlock.get(userId)
+                    || super.isTrustAllowedForUser(userId);
+        }
+
+        /**
+         * Temporarily suppress strong auth requirements for {@param userId} until strong auth
+         * changes again. Must only be called when we know about a successful unlock already
+         * before the underlying StrongAuthTracker.
+         *
+         * Note that this only changes whether trust agents can be started, not the actual trusted
+         * value.
+         */
+        void allowTrustFromUnlock(int userId) {
+            if (userId < UserHandle.USER_SYSTEM) {
+                throw new IllegalArgumentException("userId must be a valid user: " + userId);
+            }
+            boolean previous = canAgentsRunForUser(userId);
+            mStartFromSuccessfulUnlock.put(userId, true);
+
+            if (DEBUG) {
+                Log.i(TAG, "allowTrustFromUnlock(" + userId + ") ->"
+                        + " trustAllowed=" + isTrustAllowedForUser(userId)
+                        + " agentsCanRun=" + canAgentsRunForUser(userId));
+            }
+
+            if (canAgentsRunForUser(userId) != previous) {
+                refreshAgentList(userId);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 4e96d71..bf281d6 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiHotplugEvent;
@@ -45,6 +46,7 @@
 import android.media.tv.TvInputHardwareInfo;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvStreamConfig;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -57,9 +59,13 @@
 import android.view.KeyEvent;
 import android.view.Surface;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -549,6 +555,70 @@
         return (float) mCurrentIndex / (float) mCurrentMaxIndex;
     }
 
+    public void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump TvInputHardwareManager from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized (mLock) {
+            pw.println("TvInputHardwareManager Info:");
+            pw.increaseIndent();
+            pw.println("mConnections: deviceId -> Connection");
+            pw.increaseIndent();
+            for (int i = 0; i < mConnections.size(); i++) {
+                int deviceId = mConnections.keyAt(i);
+                Connection mConnection = mConnections.valueAt(i);
+                pw.println(deviceId + ": " + mConnection);
+
+            }
+            pw.decreaseIndent();
+
+            pw.println("mHardwareList:");
+            pw.increaseIndent();
+            for (TvInputHardwareInfo tvInputHardwareInfo : mHardwareList) {
+                pw.println(tvInputHardwareInfo);
+            }
+            pw.decreaseIndent();
+
+            pw.println("mHdmiDeviceList:");
+            pw.increaseIndent();
+            for (HdmiDeviceInfo hdmiDeviceInfo : mHdmiDeviceList) {
+                pw.println(hdmiDeviceInfo);
+            }
+            pw.decreaseIndent();
+
+            pw.println("mHardwareInputIdMap: deviceId -> inputId");
+            pw.increaseIndent();
+            for (int i = 0 ; i < mHardwareInputIdMap.size(); i++) {
+                int deviceId = mHardwareInputIdMap.keyAt(i);
+                String inputId = mHardwareInputIdMap.valueAt(i);
+                pw.println(deviceId + ": " + inputId);
+            }
+            pw.decreaseIndent();
+
+            pw.println("mHdmiInputIdMap: id -> inputId");
+            pw.increaseIndent();
+            for (int i = 0; i < mHdmiInputIdMap.size(); i++) {
+                int id = mHdmiInputIdMap.keyAt(i);
+                String inputId = mHdmiInputIdMap.valueAt(i);
+                pw.println(id + ": " + inputId);
+            }
+            pw.decreaseIndent();
+
+            pw.println("mInputMap: inputId -> inputInfo");
+            pw.increaseIndent();
+            for(Map.Entry<String, TvInputInfo> entry : mInputMap.entrySet()) {
+                pw.println(entry.getKey() + ": " + entry.getValue());
+            }
+            pw.decreaseIndent();
+            pw.decreaseIndent();
+        }
+    }
+
     private class Connection implements IBinder.DeathRecipient {
         private final TvInputHardwareInfo mHardwareInfo;
         private TvInputInfo mInfo;
@@ -641,6 +711,17 @@
                 resetLocked(null, null, null, null, null);
             }
         }
+
+        public String toString() {
+            return "Connection{"
+                    + " mHardwareInfo: " + mHardwareInfo
+                    + ", mInfo: " + mInfo
+                    + ", mCallback: " + mCallback
+                    + ", mConfigs: " + Arrays.toString(mConfigs)
+                    + ", mCallingUid: " + mCallingUid
+                    + ", mResolvedUserId: " + mResolvedUserId
+                    + " }";
+        }
     }
 
     private class TvInputHardwareImpl extends ITvInputHardware.Stub {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 628c627..30442bc 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1292,6 +1292,7 @@
         @Override
         public void unblockContent(
                 IBinder sessionToken, String unblockedRating, int userId) {
+            ensureParentalControlsPermission();
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
                     userId, "unblockContent");
@@ -1923,6 +1924,7 @@
                     pw.decreaseIndent();
                 }
             }
+            mTvInputHardwareManager.dump(fd, writer, args);
         }
     }
 
@@ -2511,7 +2513,7 @@
 
         // For the recording session only
         @Override
-        public void onTuned() {
+        public void onTuned(Uri channelUri) {
             synchronized (mLock) {
                 if (DEBUG) {
                     Slog.d(TAG, "onTuned()");
@@ -2520,7 +2522,7 @@
                     return;
                 }
                 try {
-                    mSessionState.client.onTuned(mSessionState.seq);
+                    mSessionState.client.onTuned(mSessionState.seq, channelUri);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "error in onTuned", e);
                 }
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index ac1ab64..6158c92 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -115,14 +115,14 @@
         getContext().registerReceiver(mReceiver, filter);
 
         publishLocalService(TwilightManager.class, mService);
-        getContext().getContentResolver().registerContentObserver(
-                Secure.getUriFor(Secure.TWILIGHT_MODE), false, mContentObserver, mCurrentUser);
-        mContentObserver.onChange(true);
     }
 
     @Override
     public void onBootPhase(int phase) {
         if (phase == PHASE_BOOT_COMPLETED) {
+            getContext().getContentResolver().registerContentObserver(
+                    Secure.getUriFor(Secure.TWILIGHT_MODE), false, mContentObserver, mCurrentUser);
+            mContentObserver.onChange(true);
             mBootCompleted = true;
             sendBroadcast();
         }
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
new file mode 100644
index 0000000..0f251fd
--- /dev/null
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -0,0 +1,266 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.utils;
+
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Manages the lifecycle of an application-provided service bound from system server.
+ *
+ * @hide
+ */
+public class ManagedApplicationService {
+    private final String TAG = getClass().getSimpleName();
+
+    private final Context mContext;
+    private final int mUserId;
+    private final ComponentName mComponent;
+    private final int mClientLabel;
+    private final String mSettingsAction;
+    private final BinderChecker mChecker;
+
+    private final DeathRecipient mDeathRecipient = new DeathRecipient() {
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mBoundInterface = null;
+            }
+        }
+    };
+
+    private final Object mLock = new Object();
+
+    // State protected by mLock
+    private ServiceConnection mPendingConnection;
+    private ServiceConnection mConnection;
+    private IInterface mBoundInterface;
+    private PendingEvent mPendingEvent;
+
+    private ManagedApplicationService(final Context context, final ComponentName component,
+            final int userId, int clientLabel, String settingsAction,
+            BinderChecker binderChecker) {
+        mContext = context;
+        mComponent = component;
+        mUserId = userId;
+        mClientLabel = clientLabel;
+        mSettingsAction = settingsAction;
+        mChecker = binderChecker;
+    }
+
+    /**
+     * Implement to validate returned IBinder instance.
+     */
+    public interface BinderChecker {
+        IInterface asInterface(IBinder binder);
+        boolean checkType(IInterface service);
+    }
+
+    /**
+     * Implement to call IInterface methods after service is connected.
+     */
+    public interface PendingEvent {
+         void runEvent(IInterface service) throws RemoteException;
+    }
+
+    /**
+     * Create a new ManagedApplicationService object but do not yet bind to the user service.
+     *
+     * @param context a Context to use for binding the application service.
+     * @param component the {@link ComponentName} of the application service to bind.
+     * @param userId the user ID of user to bind the application service as.
+     * @param clientLabel the resource ID of a label displayed to the user indicating the
+     *      binding service.
+     * @param settingsAction an action that can be used to open the Settings UI to enable/disable
+     *      binding to these services.
+     * @param binderChecker an interface used to validate the returned binder object.
+     * @return a ManagedApplicationService instance.
+     */
+    public static ManagedApplicationService build(@NonNull final Context context,
+        @NonNull final ComponentName component, final int userId, @NonNull int clientLabel,
+        @NonNull String settingsAction, @NonNull BinderChecker binderChecker) {
+        return new ManagedApplicationService(context, component, userId, clientLabel,
+            settingsAction, binderChecker);
+    }
+
+    /**
+     * @return the user ID of the user that owns the bound service.
+     */
+    public int getUserId() {
+        return mUserId;
+    }
+
+    /**
+     * @return the component of the bound service.
+     */
+    public ComponentName getComponent() {
+        return mComponent;
+    }
+
+    /**
+     * Asynchronously unbind from the application service if the bound service component and user
+     * does not match the given signature.
+     *
+     * @param componentName the component that must match.
+     * @param userId the user ID that must match.
+     * @return {@code true} if not matching.
+     */
+    public boolean disconnectIfNotMatching(final ComponentName componentName, final int userId) {
+        if (matches(componentName, userId)) {
+            return false;
+        }
+        disconnect();
+        return true;
+    }
+
+
+  /**
+   * Send an event to run as soon as the binder interface is available.
+   *
+   * @param event a {@link PendingEvent} to send.
+   */
+  public void sendEvent(@NonNull PendingEvent event) {
+        IInterface iface;
+        synchronized (mLock) {
+            iface = mBoundInterface;
+            if (iface == null) {
+                mPendingEvent = event;
+            }
+        }
+
+        if (iface != null) {
+            try {
+                event.runEvent(iface);
+            } catch (RuntimeException | RemoteException ex) {
+                Slog.e(TAG, "Received exception from user service: ", ex);
+            }
+        }
+    }
+
+    /**
+     * Asynchronously unbind from the application service if bound.
+     */
+    public void disconnect() {
+        synchronized (mLock) {
+            // Wipe out pending connections
+            mPendingConnection = null;
+
+            // Unbind existing connection, if it exists
+            if (mConnection != null) {
+                mContext.unbindService(mConnection);
+                mConnection = null;
+            }
+
+            mBoundInterface = null;
+        }
+    }
+
+    /**
+     * Asynchronously bind to the application service if not bound.
+     */
+    public void connect() {
+        synchronized (mLock) {
+            if (mConnection != null || mPendingConnection != null) {
+                // We're already connected or are trying to connect
+                return;
+            }
+
+            final PendingIntent pendingIntent = PendingIntent.getActivity(
+                    mContext, 0, new Intent(mSettingsAction), 0);
+            final Intent intent = new Intent().setComponent(mComponent).
+                    putExtra(Intent.EXTRA_CLIENT_LABEL, mClientLabel).
+                    putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
+
+            final ServiceConnection serviceConnection = new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+                    IInterface iface = null;
+                    PendingEvent pendingEvent = null;
+                    synchronized (mLock) {
+                        if (mPendingConnection == this) {
+                            // No longer pending, remove from pending connection
+                            mPendingConnection = null;
+                            mConnection = this;
+                        } else {
+                            // Service connection wasn't pending, must have been disconnected
+                            mContext.unbindService(this);
+                            return;
+                        }
+
+                        try {
+                            iBinder.linkToDeath(mDeathRecipient, 0);
+                            mBoundInterface = mChecker.asInterface(iBinder);
+                            if (!mChecker.checkType(mBoundInterface)) {
+                                // Received an invalid binder, disconnect
+                                mContext.unbindService(this);
+                                mBoundInterface = null;
+                            }
+                            iface = mBoundInterface;
+                            pendingEvent = mPendingEvent;
+                            mPendingEvent = null;
+                        } catch (RemoteException e) {
+                            // DOA
+                            Slog.w(TAG, "Unable to bind service: " + intent, e);
+                            mBoundInterface = null;
+                        }
+                    }
+                    if (iface != null && pendingEvent != null) {
+                        try {
+                            pendingEvent.runEvent(iface);
+                        } catch (RuntimeException | RemoteException ex) {
+                            Slog.e(TAG, "Received exception from user service: ", ex);
+                        }
+                    }
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName componentName) {
+                    Slog.w(TAG, "Service disconnected: " + intent);
+                    mConnection = null;
+                    mBoundInterface = null;
+                }
+            };
+
+            mPendingConnection = serviceConnection;
+
+            try {
+                if (!mContext.bindServiceAsUser(intent, serviceConnection,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                        new UserHandle(mUserId))) {
+                    Slog.w(TAG, "Unable to bind service: " + intent);
+                }
+            } catch (SecurityException e) {
+                Slog.w(TAG, "Unable to bind service: " + intent, e);
+            }
+        }
+    }
+
+    private boolean matches(final ComponentName component, final int userId) {
+        return Objects.equals(mComponent, component) && mUserId == userId;
+    }
+}
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
new file mode 100644
index 0000000..eb926c1
--- /dev/null
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -0,0 +1,288 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.vr;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.server.vr.SettingsObserver.SettingChangeListener;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Detects changes in packages, settings, and current users that may affect whether components
+ * implementing a given service can be run.
+ *
+ * @hide
+ */
+public class EnabledComponentsObserver implements SettingChangeListener {
+
+    private static final String TAG = EnabledComponentsObserver.class.getSimpleName();
+    private static final String ENABLED_SERVICES_SEPARATOR = ":";
+
+    public static final int NO_ERROR = 0;
+    public static final int DISABLED = -1;
+    public static final int NOT_INSTALLED = -2;
+
+    private final Object mLock;
+    private final Context mContext;
+    private final String mSettingName;
+    private final String mServiceName;
+    private final String mServicePermission;
+    private final SparseArray<ArraySet<ComponentName>> mInstalledSet = new SparseArray<>();
+    private final SparseArray<ArraySet<ComponentName>> mEnabledSet = new SparseArray<>();
+    private final Set<EnabledComponentChangeListener> mEnabledComponentListeners = new ArraySet<>();
+
+    /**
+     * Implement this to receive callbacks when relevant changes to the allowed components occur.
+     */
+    public interface EnabledComponentChangeListener {
+
+        /**
+         * Called when a change in the allowed components occurs.
+         */
+        void onEnabledComponentChanged();
+    }
+
+    private EnabledComponentsObserver(@NonNull Context context, @NonNull String settingName,
+            @NonNull String servicePermission, @NonNull String serviceName, @NonNull Object lock,
+            @NonNull Collection<EnabledComponentChangeListener> listeners) {
+        mLock = lock;
+        mContext = context;
+        mSettingName = settingName;
+        mServiceName = serviceName;
+        mServicePermission = servicePermission;
+        mEnabledComponentListeners.addAll(listeners);
+    }
+
+    /**
+     * Create a EnabledComponentObserver instance.
+     *
+     * @param context the context to query for changes.
+     * @param handler a handler to receive lifecycle events from system services on.
+     * @param settingName the name of a setting to monitor for a list of enabled components.
+     * @param looper a {@link Looper} to use for receiving package callbacks.
+     * @param servicePermission the permission required by the components to be bound.
+     * @param serviceName the intent action implemented by the tracked components.
+     * @param lock a lock object used to guard instance state in all callbacks and method calls.
+     * @return an EnableComponentObserver instance.
+     */
+    public static EnabledComponentsObserver build(@NonNull Context context,
+            @NonNull Handler handler, @NonNull String settingName, @NonNull Looper looper,
+            @NonNull String servicePermission, @NonNull String serviceName,
+            @NonNull final Object lock,
+            @NonNull Collection<EnabledComponentChangeListener> listeners) {
+
+        SettingsObserver s = SettingsObserver.build(context, handler, settingName);
+
+        final EnabledComponentsObserver o = new EnabledComponentsObserver(context, settingName,
+                servicePermission, serviceName, lock, listeners);
+
+        PackageMonitor packageMonitor = new PackageMonitor() {
+            @Override
+            public void onSomePackagesChanged() {
+                o.onPackagesChanged();
+
+            }
+
+            @Override
+            public void onPackageDisappeared(String packageName, int reason) {
+                o.onPackagesChanged();
+
+            }
+
+            @Override
+            public void onPackageModified(String packageName) {
+                o.onPackagesChanged();
+
+            }
+
+            @Override
+            public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
+                    boolean doit) {
+                o.onPackagesChanged();
+
+                return super.onHandleForceStop(intent, packages, uid, doit);
+            }
+        };
+
+        packageMonitor.register(context, looper, UserHandle.ALL, true);
+
+        s.addListener(o);
+
+        return o;
+
+    }
+
+    public void onPackagesChanged() {
+        rebuildAll();
+    }
+
+    @Override
+    public void onSettingChanged() {
+        rebuildAll();
+    }
+
+    @Override
+    public void onSettingRestored(String prevValue, String newValue, int userId) {
+        rebuildAll();
+    }
+
+    public void onUsersChanged() {
+        rebuildAll();
+    }
+
+    /**
+     * Rebuild the sets of allowed components for each current user profile.
+     */
+    public void rebuildAll() {
+        synchronized (mLock) {
+            mInstalledSet.clear();
+            mEnabledSet.clear();
+            final int[] userIds = getCurrentProfileIds();
+            for (int i : userIds) {
+                ArraySet<ComponentName> implementingPackages = loadComponentNamesForUser(i);
+                ArraySet<ComponentName> packagesFromSettings =
+                        loadComponentNamesFromSetting(mSettingName, i);
+                packagesFromSettings.retainAll(implementingPackages);
+
+                mInstalledSet.put(i, implementingPackages);
+                mEnabledSet.put(i, packagesFromSettings);
+
+            }
+        }
+        sendSettingChanged();
+    }
+
+    /**
+     * Check whether a given component is present and enabled for the given user.
+     *
+     * @param component the component to check.
+     * @param userId the user ID for the component to check.
+     * @return {@code true} if present and enabled.
+     */
+    public int isValid(ComponentName component, int userId) {
+        synchronized (mLock) {
+            ArraySet<ComponentName> installedComponents = mInstalledSet.get(userId);
+            if (installedComponents == null || !installedComponents.contains(component)) {
+                return NOT_INSTALLED;
+            }
+            ArraySet<ComponentName> validComponents = mEnabledSet.get(userId);
+            if (validComponents == null || !validComponents.contains(component)) {
+                return DISABLED;
+            }
+            return NO_ERROR;
+        }
+    }
+
+    private int[] getCurrentProfileIds() {
+        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (userManager == null) {
+            return null;
+        }
+        int currentUserId = ActivityManager.getCurrentUser();
+        List<UserInfo> profiles = userManager.getProfiles(currentUserId);
+        if (profiles == null) {
+            return null;
+        }
+        final int s = profiles.size();
+        int[] userIds = new int[s];
+        int ctr = 0;
+        for (UserInfo info : profiles) {
+            userIds[ctr++] = info.id;
+        }
+        return userIds;
+    }
+
+    public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
+            String serviceName, String permissionName) {
+
+        ArraySet<ComponentName> installed = new ArraySet<>();
+        Intent queryIntent = new Intent(serviceName);
+        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
+                queryIntent,
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+                userId);
+        if (installedServices != null) {
+            for (int i = 0, count = installedServices.size(); i < count; i++) {
+                ResolveInfo resolveInfo = installedServices.get(i);
+                ServiceInfo info = resolveInfo.serviceInfo;
+
+                ComponentName component = new ComponentName(info.packageName, info.name);
+                if (!permissionName.equals(info.permission)) {
+                    Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
+                            + ": it does not require the permission "
+                            + permissionName);
+                    continue;
+                }
+                installed.add(component);
+            }
+        }
+        return installed;
+    }
+
+    private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+        return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
+                mServicePermission);
+    }
+
+    private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+            int userId) {
+        final ContentResolver cr = mContext.getContentResolver();
+        String settingValue = Settings.Secure.getStringForUser(
+                cr,
+                settingName,
+                userId);
+        if (TextUtils.isEmpty(settingValue))
+            return new ArraySet<>();
+        String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
+        ArraySet<ComponentName> result = new ArraySet<>(restored.length);
+        for (int i = 0; i < restored.length; i++) {
+            ComponentName value = ComponentName.unflattenFromString(restored[i]);
+            if (null != value) {
+                result.add(value);
+            }
+        }
+        return result;
+    }
+
+    private void sendSettingChanged() {
+        for (EnabledComponentChangeListener l : mEnabledComponentListeners) {
+            l.onEnabledComponentChanged();
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/vr/SettingsObserver.java b/services/core/java/com/android/server/vr/SettingsObserver.java
new file mode 100644
index 0000000..ce76863
--- /dev/null
+++ b/services/core/java/com/android/server/vr/SettingsObserver.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.vr;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Detects changes in a given setting.
+ *
+ * @hide
+ */
+public class SettingsObserver {
+
+    private final String mSecureSettingName;
+    private final BroadcastReceiver mSettingRestorReceiver;
+    private final ContentObserver mContentObserver;
+    private final Set<SettingChangeListener> mSettingsListeners = new ArraySet<>();
+
+    /**
+     * Implement this to receive callbacks when the setting tracked by this observer changes.
+     */
+    public interface SettingChangeListener {
+
+        /**
+         * Called when the tracked setting has changed.
+         */
+        void onSettingChanged();
+
+
+        /**
+         * Called when the tracked setting has been restored for a particular user.
+         *
+         * @param prevValue the previous value of the setting.
+         * @param newValue the new value of the setting.
+         * @param userId the user ID for which this setting has been restored.
+         */
+        void onSettingRestored(String prevValue, String newValue, int userId);
+    }
+
+    private SettingsObserver(@NonNull final Context context, @NonNull final Handler handler,
+            @NonNull final Uri settingUri, @NonNull final String secureSettingName) {
+
+        mSecureSettingName = secureSettingName;
+        mSettingRestorReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
+                    String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
+                    if (Objects.equals(element, secureSettingName)) {
+                        String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
+                        String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
+                        sendSettingRestored(prevValue, newValue, getSendingUserId());
+                    }
+                }
+            }
+        };
+
+        mContentObserver = new ContentObserver(handler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                if (uri == null || settingUri.equals(uri)) {
+                    sendSettingChanged();
+                }
+            }
+        };
+
+        ContentResolver resolver = context.getContentResolver();
+        resolver.registerContentObserver(settingUri, false, mContentObserver,
+                UserHandle.USER_ALL);
+    }
+
+    /**
+     * Create a SettingsObserver instance.
+     *
+     * @param context the context to query for settings changes.
+     * @param handler the handler to use for a settings ContentObserver.
+     * @param settingName the setting to track.
+     * @return a SettingsObserver instance.
+     */
+    public static SettingsObserver build(@NonNull Context context, @NonNull Handler handler,
+            @NonNull String settingName) {
+        Uri settingUri = Settings.Secure.getUriFor(settingName);
+
+        return new SettingsObserver(context, handler, settingUri, settingName);
+    }
+
+    /**
+     * Add a listener for setting changes.
+     *
+     * @param listener a {@link SettingChangeListener} instance.
+     */
+    public void addListener(@NonNull SettingChangeListener listener) {
+        mSettingsListeners.add(listener);
+
+    }
+
+    /**
+     * Remove a listener for setting changes.
+     *
+     * @param listener a {@link SettingChangeListener} instance.
+     */
+    public void removeListener(@NonNull SettingChangeListener listener) {
+        mSettingsListeners.remove(listener);
+
+    }
+
+    private void sendSettingChanged() {
+        for (SettingChangeListener l : mSettingsListeners) {
+            l.onSettingChanged();
+        }
+    }
+
+    private void sendSettingRestored(final String prevValue, final String newValue, final int userId) {
+        for (SettingChangeListener l : mSettingsListeners) {
+            l.onSettingRestored(prevValue, newValue, userId);
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 42db364..93bb9d7 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,22 @@
  */
 package com.android.server.vr;
 
+import android.annotation.NonNull;
+import android.content.ComponentName;
+
 /**
- * VR mode local system service interface.
+ * Service for accessing the VR mode manager.
  *
  * @hide Only for use within system server.
  */
 public abstract class VrManagerInternal {
 
     /**
+     * The error code returned on success.
+     */
+    public static final int NO_ERROR = 0;
+
+    /**
      * Return current VR mode state.
      *
      * @return {@code true} if VR mode is enabled.
@@ -30,11 +38,26 @@
     public abstract boolean isInVrMode();
 
     /**
+     * Return {@code true} if the given package is the currently bound VrListenerService for the
+     * given user.
+     *
+     * @param packageName The package name to check.
+     * @param userId the user ID to check the package name for.
+     *
+     * @return {@code true} if the given package is the currently bound VrListenerService.
+     */
+    public abstract boolean isCurrentVrListener(String packageName, int userId);
+
+    /**
      * Set the current VR mode state.
      *
      * @param enabled {@code true} to enable VR mode.
+     * @param packageName The package name of the requested VrListenerService to bind.
+     * @param userId the user requesting the VrListenerService component.
+     * @param calling the component currently using VR mode, or null to leave unchanged.
      */
-    public abstract void setVrMode(boolean enabled);
+    public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName,
+            int userId, @NonNull ComponentName calling);
 
     /**
      * Add a listener for VR mode state changes.
@@ -43,13 +66,23 @@
      * </p>
      * @param listener the listener instance to add.
      */
-    public abstract void registerListener(VrStateListener listener);
+    public abstract void registerListener(@NonNull VrStateListener listener);
 
     /**
      * Remove the listener from the current set of listeners.
      *
      * @param listener the listener to remove.
      */
-    public abstract void unregisterListener(VrStateListener listener);
+    public abstract void unregisterListener(@NonNull VrStateListener listener);
+
+   /**
+    * Return NO_ERROR if the given package is installed on the device and enabled as a
+    * VrListenerService for the given current user, or a negative error code indicating a failure.
+    *
+    * @param packageName the name of the package to check, or null to select the default package.
+    * @return NO_ERROR if the given package is installed and is enabled, or a negative error code
+    *       given in {@link android.service.vr.VrModeException} on failure.
+    */
+    public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
 
 }
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 2f076d1..c572e76 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,24 +15,63 @@
  */
 package com.android.server.vr;
 
+import android.app.AppOpsManager;
+import android.app.NotificationManager;
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
+import android.service.vr.IVrListener;
+import android.service.vr.VrListenerService;
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.server.SystemService;
+import com.android.server.utils.ManagedApplicationService.PendingEvent;
+import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
+import com.android.server.utils.ManagedApplicationService;
+import com.android.server.utils.ManagedApplicationService.BinderChecker;
 
+import java.lang.StringBuilder;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Set;
 
 /**
- * Service tracking whether VR mode is active, and notifying listening system services of state
- * changes.
+ * Service tracking whether VR mode is active, and notifying listening services of state changes.
+ * <p/>
+ * Services running in system server may modify the state of VrManagerService via the interface in
+ * VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the
+ * interface given in VrStateListener.
+ * <p/>
+ * Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.:
+ *  hardware/libhardware/modules/vr
+ * <p/>
+ * In general applications may enable or disable VR mode by calling
+ * {@link android.app.Activity#setVrModeEnabled)}.  An application may also implement a service to
+ * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
  *
- * {@hide}
+ * @see {@link android.service.vr.VrListenerService}
+ * @see {@link com.android.server.vr.VrManagerInternal}
+ * @see {@link com.android.server.vr.VrStateListener}
+ *
+ * @hide
  */
-public class VrManagerService extends SystemService {
+public class VrManagerService extends SystemService implements EnabledComponentChangeListener{
 
     public static final String TAG = "VrManagerService";
 
@@ -40,9 +79,55 @@
     private static native void setVrModeNative(boolean enabled);
 
     private final Object mLock = new Object();
-    private boolean mVrModeEnabled = false;
-    private ArraySet<VrStateListener> mListeners = new ArraySet<>();
 
+    private final IBinder mOverlayToken = new Binder();
+
+    // State protected by mLock
+    private boolean mVrModeEnabled;
+    private final Set<VrStateListener> mListeners = new ArraySet<>();
+    private EnabledComponentsObserver mComponentObserver;
+    private ManagedApplicationService mCurrentVrService;
+    private Context mContext;
+    private ComponentName mCurrentVrModeComponent;
+    private int mCurrentVrModeUser;
+    private boolean mWasDefaultGranted;
+    private boolean mGuard;
+    private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
+    private String mPreviousNotificationPolicyAccessPackage;
+    private String mPreviousManageOverlayPackage;
+
+    private static final BinderChecker sBinderChecker = new BinderChecker() {
+        @Override
+        public IInterface asInterface(IBinder binder) {
+            return IVrListener.Stub.asInterface(binder);
+        }
+
+        @Override
+        public boolean checkType(IInterface service) {
+            return service instanceof IVrListener;
+        }
+    };
+
+    /**
+     * Called when a user, package, or setting changes that could affect whether or not the
+     * currently bound VrListenerService is changed.
+     */
+    @Override
+    public void onEnabledComponentChanged() {
+        synchronized (mLock) {
+            if (mCurrentVrService == null) {
+                return; // No active services
+            }
+
+            // There is an active service, update it if needed
+            updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(),
+                    mCurrentVrService.getUserId(), null);
+        }
+    }
+
+    /**
+     * Implementation of VrManagerInternal.  Callable only from system services.
+     */
     private final class LocalService extends VrManagerInternal {
         @Override
         public boolean isInVrMode() {
@@ -50,8 +135,14 @@
         }
 
         @Override
-        public void setVrMode(boolean enabled) {
-            VrManagerService.this.setVrMode(enabled);
+        public void setVrMode(boolean enabled, ComponentName packageName, int userId,
+                ComponentName callingPackage) {
+            VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
+        }
+
+        @Override
+        public boolean isCurrentVrListener(String packageName, int userId) {
+            return VrManagerService.this.isCurrentVrListener(packageName, userId);
         }
 
         @Override
@@ -63,6 +154,11 @@
         public void unregisterListener(VrStateListener listener) {
             VrManagerService.this.removeListener(listener);
         }
+
+        @Override
+        public int hasVrPackage(ComponentName packageName, int userId) {
+            return VrManagerService.this.hasVrPackage(packageName, userId);
+        }
     }
 
     public VrManagerService(Context context) {
@@ -73,11 +169,430 @@
     public void onStart() {
         synchronized(mLock) {
             initializeNative();
+            mContext = getContext();
         }
 
         publishLocalService(VrManagerInternal.class, new LocalService());
     }
 
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            synchronized (mLock) {
+                Looper looper = Looper.getMainLooper();
+                Handler handler = new Handler(looper);
+                ArrayList<EnabledComponentChangeListener> listeners = new ArrayList<>();
+                listeners.add(this);
+                mComponentObserver = EnabledComponentsObserver.build(mContext, handler,
+                        Settings.Secure.ENABLED_VR_LISTENERS, looper,
+                        android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
+                        VrListenerService.SERVICE_INTERFACE, mLock, listeners);
+
+                mComponentObserver.rebuildAll();
+            }
+        }
+    }
+
+    @Override
+    public void onStartUser(int userHandle) {
+        synchronized (mLock) {
+            mComponentObserver.onUsersChanged();
+        }
+    }
+
+    @Override
+    public void onSwitchUser(int userHandle) {
+        synchronized (mLock) {
+            mComponentObserver.onUsersChanged();
+        }
+
+    }
+
+    @Override
+    public void onStopUser(int userHandle) {
+        synchronized (mLock) {
+            mComponentObserver.onUsersChanged();
+        }
+
+    }
+
+    @Override
+    public void onCleanupUser(int userHandle) {
+        synchronized (mLock) {
+            mComponentObserver.onUsersChanged();
+        }
+    }
+
+    private void updateOverlayStateLocked(ComponentName exemptedComponent) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+            if (appOpsManager != null) {
+                String[] exemptions = (exemptedComponent == null) ? new String[0] :
+                        new String[] { exemptedComponent.getPackageName() };
+
+                appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+                        mVrModeEnabled, mOverlayToken, exemptions);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Send VR mode changes (if the mode state has changed), and update the bound/unbound state of
+     * the currently selected VR listener service.  If the component selected for the VR listener
+     * service has changed, unbind the previous listener and bind the new listener (if enabled).
+     * <p/>
+     * Note: Must be called while holding {@code mLock}.
+     *
+     * @param enabled new state for VR mode.
+     * @param component new component to be bound as a VR listener.
+     * @param userId user owning the component to be bound.
+     * @param calling the component currently using VR mode, or null to leave unchanged.
+     *
+     * @return {@code true} if the component/user combination specified is valid.
+     */
+    private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component,
+            int userId, ComponentName calling) {
+
+        boolean sendUpdatedCaller = false;
+        final long identity = Binder.clearCallingIdentity();
+        try {
+
+            boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
+                    EnabledComponentsObserver.NO_ERROR);
+
+            // Always send mode change events.
+            changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
+
+            if (!enabled || !validUserComponent) {
+                // Unbind whatever is running
+                if (mCurrentVrService != null) {
+                    Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
+                            mCurrentVrService.getUserId());
+                    mCurrentVrService.disconnect();
+                    disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                            new UserHandle(mCurrentVrService.getUserId()));
+                    mCurrentVrService = null;
+                }
+            } else {
+                if (mCurrentVrService != null) {
+                    // Unbind any running service that doesn't match the component/user selection
+                    if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+                        Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
+                                " for user " + mCurrentVrService.getUserId());
+                        disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                                new UserHandle(mCurrentVrService.getUserId()));
+                        createAndConnectService(component, userId);
+                        enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                                new UserHandle(mCurrentVrService.getUserId()));
+                        sendUpdatedCaller = true;
+                    }
+                    // The service with the correct component/user is bound
+                } else {
+                    // Nothing was previously running, bind a new service
+                    createAndConnectService(component, userId);
+                    enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                            new UserHandle(mCurrentVrService.getUserId()));
+                    sendUpdatedCaller = true;
+                }
+            }
+
+            if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent))  {
+                mCurrentVrModeComponent = calling;
+                mCurrentVrModeUser = userId;
+                sendUpdatedCaller = true;
+            }
+
+            if (mCurrentVrService != null && sendUpdatedCaller) {
+                final ComponentName c = mCurrentVrModeComponent;
+                mCurrentVrService.sendEvent(new PendingEvent() {
+                    @Override
+                    public void runEvent(IInterface service) throws RemoteException {
+                        IVrListener l = (IVrListener) service;
+                        l.focusedActivityChanged(c);
+                    }
+                });
+            }
+
+            return validUserComponent;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+     * component package and user.
+     *
+     * @param component the component whose package should be enabled.
+     * @param userId the user that owns the given component.
+     */
+    private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+        if (mGuard) {
+            // Impossible
+            throw new IllegalStateException("Enabling permissions without disabling.");
+        }
+        mGuard = true;
+
+        PackageManager pm = mContext.getPackageManager();
+
+        String pName = component.getPackageName();
+        if (pm == null) {
+            Slog.e(TAG, "Couldn't set implied permissions for " + pName +
+                ", PackageManager isn't running");
+            return;
+        }
+
+        ApplicationInfo info = null;
+        try {
+            info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA);
+        } catch (NameNotFoundException e) {
+        }
+
+        if (info == null) {
+            Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package.");
+            return;
+        }
+
+        if (!(info.isSystemApp() || info.isUpdatedSystemApp())) {
+            return; // Application is not pre-installed, avoid setting implied permissions
+        }
+
+        mWasDefaultGranted = true;
+
+        grantOverlayAccess(pName, userId);
+        grantNotificationPolicyAccess(pName);
+        grantNotificationListenerAccess(pName, userId);
+    }
+
+    /**
+     * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+     * component package and user.
+     *
+     * @param component the component whose package should be disabled.
+     * @param userId the user that owns the given component.
+     */
+    private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+        if (!mGuard) {
+            // Impossible
+            throw new IllegalStateException("Disabling permissions without enabling.");
+        }
+        mGuard = false;
+
+        PackageManager pm = mContext.getPackageManager();
+
+        if (pm == null) {
+            Slog.e(TAG, "Couldn't remove implied permissions for " + component +
+                ", PackageManager isn't running");
+            return;
+        }
+
+        String pName = component.getPackageName();
+        if (mWasDefaultGranted) {
+            revokeOverlayAccess(userId);
+            revokeNotificationPolicyAccess(pName);
+            revokeNotificiationListenerAccess();
+            mWasDefaultGranted = false;
+        }
+
+    }
+
+    private void grantOverlayAccess(String pkg, UserHandle userId) {
+        PackageManager pm = mContext.getPackageManager();
+        boolean prev = (PackageManager.PERMISSION_GRANTED ==
+                pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg));
+        mPreviousManageOverlayPackage = null;
+        if (!prev) {
+            pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW,
+                    userId);
+            mPreviousManageOverlayPackage = pkg;
+        }
+    }
+
+    private void revokeOverlayAccess(UserHandle userId) {
+        PackageManager pm = mContext.getPackageManager();
+        if (mPreviousManageOverlayPackage != null) {
+            pm.revokeRuntimePermission(mPreviousManageOverlayPackage,
+                    android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId);
+            mPreviousManageOverlayPackage = null;
+        }
+    }
+
+
+    private void grantNotificationPolicyAccess(String pkg) {
+        NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+        boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg);
+        mPreviousNotificationPolicyAccessPackage = null;
+        if (!prev) {
+            mPreviousNotificationPolicyAccessPackage = pkg;
+            nm.setNotificationPolicyAccessGranted(pkg, true);
+        }
+    }
+
+    private void revokeNotificationPolicyAccess(String pkg) {
+        NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+        if (mPreviousNotificationPolicyAccessPackage != null) {
+            nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false);
+            mPreviousNotificationPolicyAccessPackage = null;
+        }
+    }
+
+    private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
+        PackageManager pm = mContext.getPackageManager();
+        ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
+                userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
+                android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
+        ContentResolver resolver = mContext.getContentResolver();
+
+        ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+        mPreviousToggledListenerSettings.clear();
+
+        for (ComponentName c : possibleServices) {
+            String flatName = c.flattenToString();
+            if (Objects.equals(c.getPackageName(), pkg)
+                    && !current.contains(flatName)) {
+                mPreviousToggledListenerSettings.add(flatName);
+                current.add(flatName);
+            }
+        }
+
+        if (current.size() > 0) {
+            String flatSettings = formatSettings(current);
+            Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                    flatSettings);
+        }
+    }
+
+    private void revokeNotificiationListenerAccess() {
+        if (mPreviousToggledListenerSettings.isEmpty()) {
+            return;
+        }
+
+        ContentResolver resolver = mContext.getContentResolver();
+        ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+        current.removeAll(mPreviousToggledListenerSettings);
+        mPreviousToggledListenerSettings.clear();
+
+        String flatSettings = formatSettings(current);
+        Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                flatSettings);
+    }
+
+    private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
+        String flat = Settings.Secure.getString(resolver,
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+        ArraySet<String> current = new ArraySet<>();
+        if (flat != null) {
+            String[] allowed = flat.split(":");
+            for (String s : allowed) {
+                current.add(s);
+            }
+        }
+        return current;
+    }
+
+    private static String formatSettings(Collection<String> c) {
+        if (c == null || c.isEmpty()) {
+            return "";
+        }
+
+        StringBuilder b = new StringBuilder();
+        boolean start = true;
+        for (String s : c) {
+            if ("".equals(s)) {
+                continue;
+            }
+            if (!start) {
+                b.append(':');
+            }
+            b.append(s);
+            start = false;
+        }
+        return b.toString();
+    }
+
+
+
+    private void createAndConnectService(@NonNull ComponentName component, int userId) {
+        mCurrentVrService = VrManagerService.create(mContext, component, userId);
+        mCurrentVrService.connect();
+        Slog.i(TAG, "Connecting " + component + " for user " + userId);
+    }
+
+    /**
+     * Send VR mode change callbacks to HAL and system services if mode has actually changed.
+     * <p/>
+     * Note: Must be called while holding {@code mLock}.
+     *
+     * @param enabled new state of the VR mode.
+     * @param exemptedComponent a component to exempt from AppOps restrictions for overlays.
+     */
+    private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) {
+        if (mVrModeEnabled != enabled) {
+            mVrModeEnabled = enabled;
+
+            // Log mode change event.
+            Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
+            setVrModeNative(mVrModeEnabled);
+
+            updateOverlayStateLocked(exemptedComponent);
+            onVrModeChangedLocked();
+        }
+    }
+
+    /**
+     * Notify system services of VR mode change.
+     * <p/>
+     * Note: Must be called while holding {@code mLock}.
+     */
+    private void onVrModeChangedLocked() {
+        for (VrStateListener l : mListeners) {
+            l.onVrStateChanged(mVrModeEnabled);
+        }
+    }
+
+    /**
+     * Helper function for making ManagedApplicationService instances.
+     */
+    private static ManagedApplicationService create(@NonNull Context context,
+            @NonNull ComponentName component, int userId) {
+        return ManagedApplicationService.build(context, component, userId,
+                R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
+                sBinderChecker);
+    }
+
+    /*
+     * Implementation of VrManagerInternal calls.  These are callable from system services.
+     */
+
+    private boolean setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
+            int userId, @NonNull ComponentName callingPackage) {
+        synchronized (mLock) {
+            return updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
+        }
+    }
+
+    private boolean getVrMode() {
+        synchronized (mLock) {
+            return mVrModeEnabled;
+        }
+    }
+
+    private boolean isCurrentVrListener(String packageName, int userId) {
+        synchronized (mLock) {
+            if (mCurrentVrService == null) {
+                return false;
+            }
+            return mCurrentVrService.getComponent().getPackageName().equals(packageName) &&
+                    userId == mCurrentVrService.getUserId();
+        }
+    }
+
     private void addListener(VrStateListener listener) {
         synchronized (mLock) {
             mListeners.add(listener);
@@ -90,30 +605,9 @@
         }
     }
 
-    private void setVrMode(boolean enabled) {
+    private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
         synchronized (mLock) {
-            if (mVrModeEnabled != enabled) {
-                mVrModeEnabled = enabled;
-                // Log mode change event.
-                Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
-                setVrModeNative(mVrModeEnabled);
-                onVrModeChangedLocked();
-            }
-        }
-    }
-
-    private boolean getVrMode() {
-        synchronized (mLock) {
-            return mVrModeEnabled;
-        }
-    }
-
-    /**
-     * Notify system services of VR mode change.
-     */
-    private void onVrModeChangedLocked() {
-        for (VrStateListener l : mListeners) {
-            l.onVrStateChanged(mVrModeEnabled);
+            return mComponentObserver.isValid(targetPackageName, userId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/vr/VrStateListener.java b/services/core/java/com/android/server/vr/VrStateListener.java
index b8af4b2..b0603c8 100644
--- a/services/core/java/com/android/server/vr/VrStateListener.java
+++ b/services/core/java/com/android/server/vr/VrStateListener.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,9 @@
 package com.android.server.vr;
 
 /**
- * Listener for state changes in VrManagerService,
+ * Listener for state changes in VrManagerService.
+ *
+ * @hide Only for use within system server.
  */
 public abstract class VrStateListener {
 
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7378bde..fb3c6ec 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,10 +16,11 @@
 
 package com.android.server.wallpaper;
 
-import static android.app.WallpaperManager.FLAG_SET_SYSTEM;
-import static android.app.WallpaperManager.FLAG_SET_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static android.app.WallpaperManager.FLAG_LOCK;
 import static android.os.ParcelFileDescriptor.*;
 
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -104,7 +105,7 @@
 
 public class WallpaperManagerService extends IWallpaperManager.Stub {
     static final String TAG = "WallpaperManagerService";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     final Object mLock = new Object();
 
@@ -230,12 +231,17 @@
                                         false, wallpaper, null);
                             }
                             if (lockWallpaperChanged
-                                    || (wallpaper.whichPending & FLAG_SET_LOCK) != 0) {
-                                // either a lock-only wallpaper commit or a system+lock event,
-                                // so tell keyguard about it
+                                    || (wallpaper.whichPending & FLAG_LOCK) != 0) {
                                 if (DEBUG) {
-                                    Slog.i(TAG, "Lock-relevant wallpaper changed; telling listener");
+                                    Slog.i(TAG, "Lock-relevant wallpaper changed");
                                 }
+                                // either a lock-only wallpaper commit or a system+lock event.
+                                // if it's system-plus-lock we need to wipe the lock bookkeeping;
+                                // we're falling back to displaying the system wallpaper there.
+                                if (!lockWallpaperChanged) {
+                                    mLockWallpaperMap.remove(wallpaper.userId);
+                                }
+                                // and in any case, tell keyguard about it
                                 final IWallpaperManagerCallback cb = mKeyguardListener;
                                 if (cb != null) {
                                     try {
@@ -245,7 +251,7 @@
                                     }
                                 }
                             }
-                            saveSettingsLocked(wallpaper);
+                            saveSettingsLocked(wallpaper.userId);
                         }
                     }
                 }
@@ -436,12 +442,8 @@
         }
 
         // Called during initialization of a given user's wallpaper bookkeeping
-        boolean ensureCropExists() {
-            // if the crop file is not present, copy over the source image to use verbatim
-            if (!cropFile.exists()) {
-                return FileUtils.copyFile(wallpaperFile, cropFile);
-            }
-            return true;
+        boolean cropExists() {
+            return cropFile.exists();
         }
     }
 
@@ -479,7 +481,7 @@
                     // when we have an engine, but I'm not sure about
                     // locking there and anyway we always need to be able to
                     // recover if there is something wrong.
-                    saveSettingsLocked(mWallpaper);
+                    saveSettingsLocked(mWallpaper.userId);
                 }
             }
         }
@@ -503,7 +505,7 @@
                                 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
                                     > SystemClock.uptimeMillis()) {
                             Slog.w(TAG, "Reverting to built-in wallpaper!");
-                            clearWallpaperLocked(true, FLAG_SET_SYSTEM, mWallpaper.userId, null);
+                            clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
                         } else {
                             mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
                         }
@@ -582,7 +584,7 @@
                         if (!bindWallpaperComponentLocked(comp, false, false,
                                 wallpaper, null)) {
                             Slog.w(TAG, "Wallpaper no longer available; reverting to default");
-                            clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+                            clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
                         }
                     }
                 }
@@ -662,7 +664,7 @@
                     if (doit) {
                         Slog.w(TAG, "Wallpaper uninstalled, removing: "
                                 + wallpaper.wallpaperComponent);
-                        clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+                        clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
                     }
                 }
             }
@@ -682,7 +684,7 @@
                 } catch (NameNotFoundException e) {
                     Slog.w(TAG, "Wallpaper component gone, removing: "
                             + wallpaper.wallpaperComponent);
-                    clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+                    clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
                 }
             }
             if (wallpaper.nextWallpaperComponent != null
@@ -729,8 +731,27 @@
     public void systemRunning() {
         if (DEBUG) Slog.v(TAG, "systemReady");
         WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
-        if (!wallpaper.ensureCropExists()) {
-            clearWallpaperLocked(false, FLAG_SET_SYSTEM, UserHandle.USER_SYSTEM, null);
+        // If we think we're going to be using the system image wallpaper imagery, make
+        // sure we have something to render
+        if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
+            // No crop file? Make sure we've finished the processing sequence if necessary
+            if (!wallpaper.cropExists()) {
+                if (DEBUG) {
+                    Slog.i(TAG, "No crop; regenerating from source");
+                }
+                generateCrop(wallpaper);
+            }
+            // Still nothing?  Fall back to default.
+            if (!wallpaper.cropExists()) {
+                if (DEBUG) {
+                    Slog.i(TAG, "Unable to regenerate crop; resetting");
+                }
+                clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
+            }
+        } else {
+            if (DEBUG) {
+                Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
+            }
         }
         switchWallpaper(wallpaper, null);
         wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -821,7 +842,7 @@
     void switchUser(int userId, IRemoteCallback reply) {
         synchronized (mLock) {
             mCurrentUserId = userId;
-            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
             // Not started watching yet, in case wallpaper data was loaded for other reasons.
             if (wallpaper.wallpaperObserver == null) {
                 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -844,7 +865,7 @@
                 e = e1;
             }
             Slog.w(TAG, "Failure starting previous wallpaper", e);
-            clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, reply);
+            clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
         }
     }
 
@@ -855,12 +876,8 @@
         if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) {
             return;
         }
-        if (userId != UserHandle.getCallingUserId()) {
-            // cross-user call
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "WallpaperManagerService");
-        }
+        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, true, "clearWallpaper", null);
 
         synchronized (mLock) {
             clearWallpaperLocked(false, which, userId, null);
@@ -868,15 +885,18 @@
     }
 
     void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
-        if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
         }
 
         WallpaperData wallpaper = null;
-        if (which == FLAG_SET_LOCK) {
+        if (which == FLAG_LOCK) {
             wallpaper = mLockWallpaperMap.get(userId);
             if (wallpaper == null) {
                 // It's already gone; we're done.
+                if (DEBUG) {
+                    Slog.i(TAG, "Lock wallpaper already cleared");
+                }
                 return;
             }
         } else {
@@ -896,15 +916,20 @@
             if (wallpaper.wallpaperFile.exists()) {
                 wallpaper.wallpaperFile.delete();
                 wallpaper.cropFile.delete();
-                if (which == FLAG_SET_LOCK) {
+                if (which == FLAG_LOCK) {
+                    mLockWallpaperMap.remove(userId);
                     final IWallpaperManagerCallback cb = mKeyguardListener;
                     if (cb != null) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
+                        }
                         try {
                             cb.onWallpaperChanged();
                         } catch (RemoteException e) {
                             // Oh well it went away; no big deal
                         }
                     }
+                    saveSettingsLocked(userId);
                     return;
                 }
             }
@@ -983,7 +1008,7 @@
         }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
-            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
             if (width <= 0 || height <= 0) {
                 throw new IllegalArgumentException("width and height must be > 0");
             }
@@ -995,7 +1020,7 @@
             if (width != wallpaper.width || height != wallpaper.height) {
                 wallpaper.width = width;
                 wallpaper.height = height;
-                saveSettingsLocked(wallpaper);
+                saveSettingsLocked(userId);
                 if (mCurrentUserId != userId) return; // Don't change the properties now
                 if (wallpaper.connection != null) {
                     if (wallpaper.connection.mEngine != null) {
@@ -1045,14 +1070,14 @@
         }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
-            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
             if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
                 throw new IllegalArgumentException("padding must be positive: " + padding);
             }
 
             if (!padding.equals(wallpaper.padding)) {
                 wallpaper.padding.set(padding);
-                saveSettingsLocked(wallpaper);
+                saveSettingsLocked(userId);
                 if (mCurrentUserId != userId) return; // Don't change the properties now
                 if (wallpaper.connection != null) {
                     if (wallpaper.connection.mEngine != null) {
@@ -1075,20 +1100,16 @@
     @Override
     public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, final int which,
             Bundle outParams, int wallpaperUserId) {
-        if (wallpaperUserId != UserHandle.getCallingUserId()) {
-            // cross-user call
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "WallpaperManagerService");
-        }
+        wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
 
-        if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
         }
 
         synchronized (mLock) {
             final SparseArray<WallpaperData> whichSet =
-                    (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+                    (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
             WallpaperData wallpaper = whichSet.get(wallpaperUserId);
             if (wallpaper == null) {
                 // common case, this is the first lookup post-boot of the system or
@@ -1119,6 +1140,7 @@
         }
     }
 
+    @Override
     public WallpaperInfo getWallpaperInfo() {
         int userId = UserHandle.getCallingUserId();
         synchronized (mLock) {
@@ -1131,6 +1153,26 @@
     }
 
     @Override
+    public int getWallpaperIdForUser(int which, int userId) {
+        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
+
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
+            throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
+        }
+
+        final SparseArray<WallpaperData> map =
+                (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+        synchronized (mLock) {
+            WallpaperData wallpaper = map.get(userId);
+            if (wallpaper != null) {
+                return wallpaper.wallpaperId;
+            }
+        }
+        return -1;
+    }
+
+    @Override
     public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
         checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
         synchronized (mLock) {
@@ -1144,7 +1186,7 @@
             Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
 
-        if ((which & (FLAG_SET_LOCK|FLAG_SET_SYSTEM)) == 0) {
+        if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
             Slog.e(TAG, "Must specify a valid wallpaper category to set");
             return null;
         }
@@ -1220,6 +1262,7 @@
         return null;
     }
 
+    @Override
     public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
         if (isWallpaperSupported(callingPackage) && isWallpaperSettingAllowed(callingPackage)) {
             setWallpaperComponent(name);
@@ -1227,6 +1270,7 @@
     }
 
     // ToDo: Remove this version of the function
+    @Override
     public void setWallpaperComponent(ComponentName name) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
         synchronized (mLock) {
@@ -1239,7 +1283,10 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 wallpaper.imageWallpaperPending = false;
-                bindWallpaperComponentLocked(name, false, true, wallpaper, null);
+                if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
+                    wallpaper.wallpaperId = makeWallpaperIdLocked();
+                    notifyCallbacksLocked(wallpaper);
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -1304,7 +1351,7 @@
                 List<ResolveInfo> ris =
                         mIPackageManager.queryIntentServices(intent,
                                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                                PackageManager.GET_META_DATA, serviceUserId);
+                                PackageManager.GET_META_DATA, serviceUserId).getList();
                 for (int i=0; i<ris.size(); i++) {
                     ServiceInfo rsi = ris.get(i).serviceInfo;
                     if (rsi.name.equals(si.name) &&
@@ -1488,50 +1535,33 @@
         return new JournaledFile(new File(base), new File(base + ".tmp"));
     }
 
-    private void saveSettingsLocked(WallpaperData wallpaper) {
-        JournaledFile journal = makeJournaledFile(wallpaper.userId);
-        FileOutputStream stream = null;
+    private void saveSettingsLocked(int userId) {
+        JournaledFile journal = makeJournaledFile(userId);
+        FileOutputStream fstream = null;
+        BufferedOutputStream stream = null;
         try {
-            stream = new FileOutputStream(journal.chooseForWrite(), false);
             XmlSerializer out = new FastXmlSerializer();
+            fstream = new FileOutputStream(journal.chooseForWrite(), false);
+            stream = new BufferedOutputStream(fstream);
             out.setOutput(stream, StandardCharsets.UTF_8.name());
             out.startDocument(null, true);
 
-            out.startTag(null, "wp");
-            out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
-            out.attribute(null, "width", Integer.toString(wallpaper.width));
-            out.attribute(null, "height", Integer.toString(wallpaper.height));
+            WallpaperData wallpaper;
 
-            out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
-            out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
-            out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
-            out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
-
-            if (wallpaper.padding.left != 0) {
-                out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
+            wallpaper = mWallpaperMap.get(userId);
+            if (wallpaper != null) {
+                writeWallpaperAttributes(out, "wp", wallpaper);
             }
-            if (wallpaper.padding.top != 0) {
-                out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
+            wallpaper = mLockWallpaperMap.get(userId);
+            if (wallpaper != null) {
+                writeWallpaperAttributes(out, "kwp", wallpaper);
             }
-            if (wallpaper.padding.right != 0) {
-                out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
-            }
-            if (wallpaper.padding.bottom != 0) {
-                out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
-            }
-
-            out.attribute(null, "name", wallpaper.name);
-            if (wallpaper.wallpaperComponent != null
-                    && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
-                out.attribute(null, "component",
-                        wallpaper.wallpaperComponent.flattenToShortString());
-            }
-            out.endTag(null, "wp");
 
             out.endDocument();
-            stream.flush();
-            FileUtils.sync(stream);
-            stream.close();
+
+            stream.flush(); // also flushes fstream
+            FileUtils.sync(fstream);
+            stream.close(); // also closes fstream
             journal.commit();
         } catch (IOException e) {
             IoUtils.closeQuietly(stream);
@@ -1539,6 +1569,40 @@
         }
     }
 
+    private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        out.startTag(null, tag);
+        out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
+        out.attribute(null, "width", Integer.toString(wallpaper.width));
+        out.attribute(null, "height", Integer.toString(wallpaper.height));
+
+        out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
+        out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
+        out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
+        out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+
+        if (wallpaper.padding.left != 0) {
+            out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
+        }
+        if (wallpaper.padding.top != 0) {
+            out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
+        }
+        if (wallpaper.padding.right != 0) {
+            out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
+        }
+        if (wallpaper.padding.bottom != 0) {
+            out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
+        }
+
+        out.attribute(null, "name", wallpaper.name);
+        if (wallpaper.wallpaperComponent != null
+                && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
+            out.attribute(null, "component",
+                    wallpaper.wallpaperComponent.flattenToShortString());
+        }
+        out.endTag(null, tag);
+    }
+
     private void migrateFromOld() {
         File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
         File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
@@ -1574,7 +1638,7 @@
         // Combined or just-system operations use the 'system' WallpaperData
         // for this use; lock-only operations use the dedicated one.
         final SparseArray<WallpaperData> whichSet =
-                (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+                (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
         WallpaperData wallpaper = whichSet.get(userId);
         if (wallpaper == null) {
             // common case, this is the first lookup post-boot of the system or
@@ -1585,7 +1649,7 @@
             // yet a lock-only wallpaper set for this user, so we need to establish
             // it now.
             if (wallpaper == null) {
-                if (which == FLAG_SET_LOCK) {
+                if (which == FLAG_LOCK) {
                     wallpaper = new WallpaperData(userId,
                             WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
                     mLockWallpaperMap.put(userId, wallpaper);
@@ -1615,7 +1679,9 @@
         if (wallpaper == null) {
             wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
             mWallpaperMap.put(userId, wallpaper);
-            wallpaper.ensureCropExists();
+            if (!wallpaper.cropExists()) {
+                generateCrop(wallpaper);
+            }
         }
         boolean success = false;
         try {
@@ -1753,8 +1819,8 @@
         WallpaperData wallpaper = null;
         boolean success = false;
         synchronized (mLock) {
-            loadSettingsLocked(0);
-            wallpaper = mWallpaperMap.get(0);
+            loadSettingsLocked(UserHandle.USER_SYSTEM);
+            wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
             wallpaper.wallpaperId = makeWallpaperIdLocked();    // always bump id at restore
             if (wallpaper.nextWallpaperComponent != null
                     && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
@@ -1779,7 +1845,8 @@
                 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
                         + " id=" + wallpaper.wallpaperId);
                 if (success) {
-                    bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+                    generateCrop(wallpaper);    // based on the new image + metadata
+                    bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
                             wallpaper, null);
                 }
             }
@@ -1788,11 +1855,11 @@
         if (!success) {
             Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
             wallpaper.name = "";
-            getWallpaperDir(0).delete();
+            getWallpaperDir(UserHandle.USER_SYSTEM).delete();
         }
 
         synchronized (mLock) {
-            saveSettingsLocked(wallpaper);
+            saveSettingsLocked(UserHandle.USER_SYSTEM);
         }
     }
 
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
new file mode 100644
index 0000000..6052a6e
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.webkit;
+
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings.Global;
+import android.provider.Settings;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.webkit.WebViewFactory.MissingWebViewPackageException;
+import android.webkit.WebViewFactory;
+import android.webkit.WebViewProviderInfo;
+
+import com.android.internal.util.XmlUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Default implementation for the WebView preparation Utility interface.
+ * @hide
+ */
+public class SystemImpl implements SystemInterface {
+    private static final String TAG = SystemImpl.class.getSimpleName();
+    private static final String TAG_START = "webviewproviders";
+    private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider";
+    private static final String TAG_PACKAGE_NAME = "packageName";
+    private static final String TAG_DESCRIPTION = "description";
+    // Whether or not the provider must be explicitly chosen by the user to be used.
+    private static final String TAG_AVAILABILITY = "availableByDefault";
+    private static final String TAG_SIGNATURE = "signature";
+    private static final String TAG_FALLBACK = "isFallback";
+
+    /**
+     * Returns all packages declared in the framework resources as potential WebView providers.
+     * @hide
+     * */
+    @Override
+    public WebViewProviderInfo[] getWebViewPackages() {
+        int numFallbackPackages = 0;
+        XmlResourceParser parser = null;
+        List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
+        try {
+            parser = AppGlobals.getInitialApplication().getResources().getXml(
+                    com.android.internal.R.xml.config_webview_packages);
+            XmlUtils.beginDocument(parser, TAG_START);
+            while(true) {
+                XmlUtils.nextElement(parser);
+                String element = parser.getName();
+                if (element == null) {
+                    break;
+                }
+                if (element.equals(TAG_WEBVIEW_PROVIDER)) {
+                    String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
+                    if (packageName == null) {
+                        throw new MissingWebViewPackageException(
+                                "WebView provider in framework resources missing package name");
+                    }
+                    String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
+                    if (description == null) {
+                        throw new MissingWebViewPackageException(
+                                "WebView provider in framework resources missing description");
+                    }
+                    boolean availableByDefault = "true".equals(
+                            parser.getAttributeValue(null, TAG_AVAILABILITY));
+                    boolean isFallback = "true".equals(
+                            parser.getAttributeValue(null, TAG_FALLBACK));
+                    WebViewProviderInfo currentProvider = new WebViewProviderInfo(
+                            packageName, description, availableByDefault, isFallback,
+                            readSignatures(parser));
+                    if (currentProvider.isFallback) {
+                        numFallbackPackages++;
+                        if (numFallbackPackages > 1) {
+                            throw new AndroidRuntimeException(
+                                    "There can be at most one webview fallback package.");
+                        }
+                    }
+                    webViewProviders.add(currentProvider);
+                }
+                else {
+                    Log.e(TAG, "Found an element that is not a webview provider");
+                }
+            }
+        } catch(XmlPullParserException e) {
+            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+        } catch(IOException e) {
+            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+        return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+    }
+
+    /**
+     * Reads all signatures at the current depth (within the current provider) from the XML parser.
+     */
+    private static String[] readSignatures(XmlResourceParser parser) throws IOException,
+            XmlPullParserException {
+        List<String> signatures = new ArrayList<String>();
+        int outerDepth = parser.getDepth();
+        while(XmlUtils.nextElementWithin(parser, outerDepth)) {
+            if (parser.getName().equals(TAG_SIGNATURE)) {
+                // Parse the value within the signature tag
+                String signature = parser.nextText();
+                signatures.add(signature);
+            } else {
+                Log.e(TAG, "Found an element in a webview provider that is not a signature");
+            }
+        }
+        return signatures.toArray(new String[signatures.size()]);
+    }
+
+    @Override
+    public int onWebViewProviderChanged(PackageInfo packageInfo) {
+        return WebViewFactory.onWebViewProviderChanged(packageInfo);
+    }
+
+    @Override
+    public String getUserChosenWebViewProvider(Context context) {
+        return Settings.Global.getString(context.getContentResolver(),
+                Settings.Global.WEBVIEW_PROVIDER);
+    }
+
+    @Override
+    public void updateUserSetting(Context context, String newProviderName) {
+        Settings.Global.putString(context.getContentResolver(),
+                Settings.Global.WEBVIEW_PROVIDER,
+                newProviderName == null ? "" : newProviderName);
+    }
+
+    @Override
+    public void killPackageDependents(String packageName) {
+        try {
+            ActivityManagerNative.getDefault().killPackageDependents(packageName,
+                    UserHandle.USER_ALL);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    public boolean isFallbackLogicEnabled() {
+        // Note that this is enabled by default (i.e. if the setting hasn't been set).
+        return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
+                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
+    }
+
+    @Override
+    public void enableFallbackLogic(boolean enable) {
+        Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
+                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
+    }
+
+    @Override
+    public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
+        context.getPackageManager().deletePackage(packageName,
+                new IPackageDeleteObserver.Stub() {
+            public void packageDeleted(String packageName, int returnCode) {
+                // Ignore returnCode since the deletion could fail, e.g. we might be trying
+                // to delete a non-updated system-package (and we should still disable the
+                // package)
+                enablePackageForAllUsers(context, packageName, false);
+            }
+        }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+    }
+
+    @Override
+    public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
+        UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
+        for(UserInfo userInfo : userManager.getUsers()) {
+            enablePackageForUser(packageName, enable, userInfo.id);
+        }
+    }
+
+    @Override
+    public void enablePackageForUser(String packageName, boolean enable, int userId) {
+        try {
+            AppGlobals.getPackageManager().setApplicationEnabledSetting(
+                    packageName,
+                    enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
+                    userId, null);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
+        }
+    }
+
+    @Override
+    public boolean systemIsDebuggable() {
+        return Build.IS_DEBUGGABLE;
+    }
+
+    @Override
+    public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+            throws NameNotFoundException {
+        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+        return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
+    }
+
+    // flags declaring we want extra info from the package manager for webview providers
+    private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
+            | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+}
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
new file mode 100644
index 0000000..b5eb0a7
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.webkit;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.webkit.WebViewProviderInfo;
+
+/**
+ * System interface for the WebViewUpdateService.
+ * This interface provides a way to test the WebView preparation mechanism - during normal use this
+ * interface is implemented using calls to the Android framework, but by providing an alternative
+ * implementation we can test the WebView preparation logic without reaching other framework code.
+ *
+ * @hide
+ */
+public interface SystemInterface {
+    public WebViewProviderInfo[] getWebViewPackages();
+    public int onWebViewProviderChanged(PackageInfo packageInfo);
+
+    public String getUserChosenWebViewProvider(Context context);
+    public void updateUserSetting(Context context, String newProviderName);
+    public void killPackageDependents(String packageName);
+
+    public boolean isFallbackLogicEnabled();
+    public void enableFallbackLogic(boolean enable);
+
+    public void uninstallAndDisablePackageForAllUsers(Context context, String packageName);
+    public void enablePackageForAllUsers(Context context, String packageName, boolean enable);
+    public void enablePackageForUser(String packageName, boolean enable, int userId);
+
+    public boolean systemIsDebuggable();
+    public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+            throws NameNotFoundException;
+}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index f3b120f..4669676 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -16,34 +16,31 @@
 
 package com.android.server.webkit;
 
-import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
 import android.os.Binder;
+import android.os.PatternMatcher;
 import android.os.Process;
-import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.util.AndroidRuntimeException;
+import android.util.Base64;
 import android.util.Slog;
 import android.webkit.IWebViewUpdateService;
+import android.webkit.WebViewFactory;
 import android.webkit.WebViewProviderInfo;
 import android.webkit.WebViewProviderResponse;
-import android.webkit.WebViewFactory;
 
 import com.android.server.SystemService;
 
+import java.io.FileDescriptor;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -60,21 +57,19 @@
     private int mNumRelroCreationsFinished = 0;
     // Implies that we need to rerun relro creation because we are using an out-of-date package
     private boolean mWebViewPackageDirty = false;
-    // Set to true when the current provider is being replaced
-    private boolean mCurrentProviderBeingReplaced = false;
     private boolean mAnyWebViewInstalled = false;
 
     private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
 
     // The WebView package currently in use (or the one we are preparing).
     private PackageInfo mCurrentWebViewPackage = null;
-    // The WebView providers that are currently available.
-    private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
 
     private BroadcastReceiver mWebViewUpdatedReceiver;
+    private SystemInterface mSystemInterface;
 
     public WebViewUpdateService(Context context) {
         super(context);
+        mSystemInterface = new SystemImpl();
     }
 
     @Override
@@ -86,33 +81,40 @@
                     // the removal of the old package and one representing the addition of the
                     // new package.
                     // In the case where we receive an intent to remove the old version of the
-                    // package that is being replaced we set a flag here and early-out so that we
-                    // don't change provider while replacing the current package (we will instead
-                    // change provider when the new version of the package is being installed).
+                    // package that is being replaced we early-out here so that we don't run the
+                    // update-logic twice.
                     if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
                         && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
-                        synchronized(WebViewUpdateService.this) {
-                            if (mCurrentWebViewPackage == null) return;
-
-                            String webViewPackage = "package:" + mCurrentWebViewPackage.packageName;
-                            if (webViewPackage.equals(intent.getDataString()))
-                                mCurrentProviderBeingReplaced = true;
-                        }
-
                         return;
                     }
 
-                    for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
+                    // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
+                    // package, not just a component
+                    if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
+                        if (!entirePackageChanged(intent)) {
+                            return;
+                        }
+                    }
+
+                    if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
+                        int userId =
+                            intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                        handleNewUser(userId);
+                        return;
+                    }
+
+                    updateFallbackState(context, intent);
+
+                    for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
                         String webviewPackage = "package:" + provider.packageName;
 
                         if (webviewPackage.equals(intent.getDataString())) {
                             boolean updateWebView = false;
-                            boolean removedOldPackage = false;
+                            boolean removedOrChangedOldPackage = false;
                             String oldProviderName = null;
                             PackageInfo newPackage = null;
                             synchronized(WebViewUpdateService.this) {
                                 try {
-                                    updateValidWebViewPackages();
                                     newPackage = findPreferredWebViewPackage();
                                     if (mCurrentWebViewPackage != null)
                                         oldProviderName = mCurrentWebViewPackage.packageName;
@@ -125,7 +127,7 @@
                                         || mCurrentWebViewPackage == null;
                                     // We removed the old package if we received an intent to remove
                                     // or replace the old package.
-                                    removedOldPackage =
+                                    removedOrChangedOldPackage =
                                         provider.packageName.equals(oldProviderName);
                                     if (updateWebView) {
                                         onWebViewProviderChanged(newPackage);
@@ -135,16 +137,13 @@
                                             "relro with " + e);
                                 }
                             }
-                            if(updateWebView && !removedOldPackage && oldProviderName != null) {
+                            if(updateWebView && !removedOrChangedOldPackage
+                                    && oldProviderName != null) {
                                 // If the provider change is the result of adding or replacing a
                                 // package that was not the previous provider then we must kill
                                 // packages dependent on the old package ourselves. The framework
                                 // only kills dependents of packages that are being removed.
-                                try {
-                                    ActivityManagerNative.getDefault().killPackageDependents(
-                                        oldProviderName, UserHandle.USER_ALL);
-                                } catch (RemoteException e) {
-                                }
+                                mSystemInterface.killPackageDependents(oldProviderName);
                             }
                             return;
                         }
@@ -154,10 +153,125 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
+        // Make sure we only receive intents for WebView packages from our config file.
+        for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
+            filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
+        }
         getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
 
-        publishBinderService("webviewupdate", new BinderService());
+        IntentFilter userAddedFilter = new IntentFilter();
+        userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
+        getContext().registerReceiver(mWebViewUpdatedReceiver, userAddedFilter);
+
+        publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
+    }
+
+    private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
+        for (WebViewProviderInfo provider : providers) {
+            if (provider.availableByDefault && !provider.isFallback) {
+                try {
+                    PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
+                    if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) {
+                        return true;
+                    }
+                } catch (NameNotFoundException e) {
+                    // A non-existent provider is neither valid nor enabled
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called when a new user has been added to update the state of its fallback package.
+     */
+    void handleNewUser(int userId) {
+        if (!mSystemInterface.isFallbackLogicEnabled()) return;
+
+        WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
+        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
+        if (fallbackProvider == null) return;
+
+        mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
+                !existsValidNonFallbackProvider(webviewProviders), userId);
+    }
+
+    /**
+     * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
+     * package that is valid (and available by default) then disable the fallback package,
+     * otherwise, enable the fallback package.
+     */
+    void updateFallbackState(final Context context, final Intent intent) {
+        if (!mSystemInterface.isFallbackLogicEnabled()) return;
+
+        WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
+
+        if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
+                    || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
+            // A package was changed / updated / downgraded, early out if it is not one of the
+            // webview packages that are available by default.
+            String changedPackage = null;
+            for (WebViewProviderInfo provider : webviewProviders) {
+                String webviewPackage = "package:" + provider.packageName;
+                if (webviewPackage.equals(intent.getDataString())) {
+                    if (provider.availableByDefault) {
+                        changedPackage = provider.packageName;
+                    }
+                    break;
+                }
+            }
+            if (changedPackage == null) return;
+        }
+
+        // If there exists a valid and enabled non-fallback package - disable the fallback
+        // package, otherwise, enable it.
+        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
+        if (fallbackProvider == null) return;
+        boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
+
+        boolean isFallbackEnabled = false;
+        try {
+            isFallbackEnabled =
+                isEnabledPackage(mSystemInterface.getPackageInfoForProvider(fallbackProvider));
+        } catch (NameNotFoundException e) {
+        }
+
+        if (existsValidNonFallbackProvider
+                // During an OTA the primary user's WebView state might differ from other users', so
+                // ignore the state of that user during boot.
+                && (isFallbackEnabled || intent == null)) {
+            mSystemInterface.uninstallAndDisablePackageForAllUsers(context,
+                    fallbackProvider.packageName);
+        } else if (!existsValidNonFallbackProvider
+                // During an OTA the primary user's WebView state might differ from other users', so
+                // ignore the state of that user during boot.
+                && (!isFallbackEnabled || intent==null)) {
+            // Enable the fallback package for all users.
+            mSystemInterface.enablePackageForAllUsers(context, fallbackProvider.packageName, true);
+        }
+    }
+
+    /**
+     * Returns the only fallback provider, or null if there is none.
+     */
+    private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
+        for (WebViewProviderInfo provider : webviewPackages) {
+            if (provider.isFallback) {
+                return provider;
+            }
+        }
+        return null;
+    }
+
+    private boolean isFallbackPackage(String packageName) {
+        if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
+
+        WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
+        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
+        return (fallbackProvider != null
+                && packageName.equals(fallbackProvider.packageName));
     }
 
     /**
@@ -167,9 +281,9 @@
      * Currently, this means spawning the child processes which will create the relro files.
      */
     public void prepareWebViewInSystemServer() {
+        updateFallbackState(getContext(), null);
         try {
             synchronized(this) {
-                updateValidWebViewPackages();
                 mCurrentWebViewPackage = findPreferredWebViewPackage();
                 onWebViewProviderChanged(mCurrentWebViewPackage);
             }
@@ -182,39 +296,37 @@
 
     /**
      * Change WebView provider and provider setting and kill packages using the old provider.
+     * Return the new provider (in case we are in the middle of creating relro files this new
+     * provider will not be in use directly, but will when the relros are done).
      */
-    private void changeProviderAndSetting(String newProviderName) {
+    private String changeProviderAndSetting(String newProviderName) {
         PackageInfo oldPackage = null;
         PackageInfo newPackage = null;
         synchronized(this) {
             oldPackage = mCurrentWebViewPackage;
-            updateUserSetting(newProviderName);
+            mSystemInterface.updateUserSetting(getContext(), newProviderName);
 
             try {
                 newPackage = findPreferredWebViewPackage();
                 if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
                     // If we don't perform the user change, revert the settings change.
-                    updateUserSetting(newPackage.packageName);
-                    return;
+                    mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
+                    return newPackage.packageName;
                 }
             } catch (WebViewFactory.MissingWebViewPackageException e) {
                 Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView package "
                         + e);
                 // If we don't perform the user change but don't have an installed WebView package,
                 // we will have changed the setting and it will be used when a package is available.
-                return;
+                return newProviderName;
             }
             onWebViewProviderChanged(newPackage);
         }
         // Kill apps using the old provider
-        try {
-            if (oldPackage != null) {
-                ActivityManagerNative.getDefault().killPackageDependents(
-                        oldPackage.packageName, UserHandle.USER_ALL);
-            }
-        } catch (RemoteException e) {
+        if (oldPackage != null) {
+            mSystemInterface.killPackageDependents(oldPackage.packageName);
         }
-        return;
+        return newPackage.packageName;
     }
 
     /**
@@ -224,19 +336,16 @@
     private void onWebViewProviderChanged(PackageInfo newPackage) {
         synchronized(this) {
             mAnyWebViewInstalled = true;
-            // If we have changed provider then the replacement of the old provider is
-            // irrelevant - we can only have chosen a new provider if its package is available.
-            mCurrentProviderBeingReplaced = false;
             if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
                 mCurrentWebViewPackage = newPackage;
-                updateUserSetting(newPackage.packageName);
+                mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
 
                 // The relro creations might 'finish' (not start at all) before
                 // WebViewFactory.onWebViewProviderChanged which means we might not know the number
                 // of started creations before they finish.
                 mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
                 mNumRelroCreationsFinished = 0;
-                mNumRelroCreationsStarted = WebViewFactory.onWebViewProviderChanged(newPackage);
+                mNumRelroCreationsStarted = mSystemInterface.onWebViewProviderChanged(newPackage);
                 // If the relro creations finish before we know the number of started creations we
                 // will have to do any cleanup/notifying here.
                 checkIfRelrosDoneLocked();
@@ -246,36 +355,43 @@
         }
     }
 
+    private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
+        WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
+        List<ProviderAndPackageInfo> providers = new ArrayList<>();
+        for(int n = 0; n < allProviders.length; n++) {
+            try {
+                PackageInfo packageInfo =
+                    mSystemInterface.getPackageInfoForProvider(allProviders[n]);
+                if (isValidProvider(allProviders[n], packageInfo)) {
+                    providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
+                }
+            } catch (NameNotFoundException e) {
+                // Don't add non-existent packages
+            }
+        }
+        return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
+    }
+
     /**
-     * Updates the currently valid WebView provider packages.
-     * Should be used when a provider has been installed or removed.
-     * @hide
-     * */
-    private void updateValidWebViewPackages() {
-        List<WebViewProviderInfo> webViewProviders  =
-            new ArrayList<WebViewProviderInfo>(Arrays.asList(WebViewFactory.getWebViewPackages()));
-        Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
-        // remove non-valid packages
-        while(it.hasNext()) {
-            WebViewProviderInfo current = it.next();
-            if (!current.isValidProvider())
-                it.remove();
+     * Fetch only the currently valid WebView packages.
+     **/
+    private WebViewProviderInfo[] getValidWebViewPackages() {
+        ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
+        WebViewProviderInfo[] providers = new WebViewProviderInfo[providersAndPackageInfos.length];
+        for(int n = 0; n < providersAndPackageInfos.length; n++) {
+            providers[n] = providersAndPackageInfos[n].provider;
         }
-        synchronized(this) {
-            mCurrentValidWebViewPackages =
-                webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
-        }
+        return providers;
     }
 
-    private static String getUserChosenWebViewProvider() {
-        return Settings.Global.getString(AppGlobals.getInitialApplication().getContentResolver(),
-                Settings.Global.WEBVIEW_PROVIDER);
-    }
+    private class ProviderAndPackageInfo {
+        public final WebViewProviderInfo provider;
+        public final PackageInfo packageInfo;
 
-    private void updateUserSetting(String newProviderName) {
-        Settings.Global.putString(getContext().getContentResolver(),
-                Settings.Global.WEBVIEW_PROVIDER,
-                newProviderName == null ? "" : newProviderName);
+        public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
+            this.provider = provider;
+            this.packageInfo = packageInfo;
+        }
     }
 
     /**
@@ -286,28 +402,30 @@
      * @hide
      */
     private PackageInfo findPreferredWebViewPackage() {
-        WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
+        ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
 
-        String userChosenProvider = getUserChosenWebViewProvider();
+        String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(getContext());
 
         // If the user has chosen provider, use that
-        for (WebViewProviderInfo provider : providers) {
-            if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
-                return provider.getPackageInfo();
+        for (ProviderAndPackageInfo providerAndPackage : providers) {
+            if (providerAndPackage.provider.packageName.equals(userChosenProvider)
+                    && isEnabledPackage(providerAndPackage.packageInfo)) {
+                return providerAndPackage.packageInfo;
             }
         }
 
         // User did not choose, or the choice failed; use the most stable provider that is
         // enabled and available by default (not through user choice).
-        for (WebViewProviderInfo provider : providers) {
-            if (provider.isAvailableByDefault() && provider.isEnabled()) {
-                return provider.getPackageInfo();
+        for (ProviderAndPackageInfo providerAndPackage : providers) {
+            if (providerAndPackage.provider.availableByDefault
+                    && isEnabledPackage(providerAndPackage.packageInfo)) {
+                return providerAndPackage.packageInfo;
             }
         }
 
         // Could not find any enabled package either, use the most stable provider.
-        for (WebViewProviderInfo provider : providers) {
-            return provider.getPackageInfo();
+        for (ProviderAndPackageInfo providerAndPackage : providers) {
+            return providerAndPackage.packageInfo;
         }
 
         mAnyWebViewInstalled = false;
@@ -315,6 +433,64 @@
                 "Could not find a loadable WebView package");
     }
 
+
+    /**
+     * Returns whether this provider is valid for use as a WebView provider.
+     */
+    public boolean isValidProvider(WebViewProviderInfo configInfo,
+            PackageInfo packageInfo) {
+        if (providerHasValidSignature(configInfo, packageInfo) &&
+                WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean providerHasValidSignature(WebViewProviderInfo provider,
+            PackageInfo packageInfo) {
+        if (mSystemInterface.systemIsDebuggable()) {
+            return true;
+        }
+        Signature[] packageSignatures;
+        // If no signature is declared, instead check whether the package is included in the
+        // system.
+        if (provider.signatures == null || provider.signatures.length == 0) {
+            return packageInfo.applicationInfo.isSystemApp();
+        }
+        packageSignatures = packageInfo.signatures;
+        if (packageSignatures.length != 1)
+            return false;
+
+        final byte[] packageSignature = packageSignatures[0].toByteArray();
+        // Return whether the package signature matches any of the valid signatures
+        for (String signature : provider.signatures) {
+            final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
+            if (Arrays.equals(packageSignature, validSignature))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether the given package is enabled.
+     * This state can be changed by the user from Settings->Apps
+     */
+    public boolean isEnabledPackage(PackageInfo packageInfo) {
+        return packageInfo.applicationInfo.enabled;
+    }
+
+    /**
+     * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
+     * than just one of its components).
+     * @hide
+     */
+    public static boolean entirePackageChanged(Intent intent) {
+        String[] componentList =
+            intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+        return Arrays.asList(componentList).contains(
+                intent.getDataString().substring("package:".length()));
+    }
+
     /**
      * Returns whether WebView is ready and is not going to go through its preparation phase again
      * directly.
@@ -322,7 +498,6 @@
     private boolean webViewIsReadyLocked() {
         return !mWebViewPackageDirty
             && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
-            && !mCurrentProviderBeingReplaced
             // The current package might be replaced though we haven't received an intent declaring
             // this yet, the following flag makes anyone loading WebView to wait in this case.
             && mAnyWebViewInstalled;
@@ -334,13 +509,8 @@
                 mWebViewPackageDirty = false;
                 // If we have changed provider since we started the relro creation we need to
                 // redo the whole process using the new package instead.
-                // Though, if the current provider package is being replaced we don't want to change
-                // provider here since we will perform the change either when the package is added
-                // again or when we switch to another provider (whichever comes first).
-                if (!mCurrentProviderBeingReplaced) {
-                    PackageInfo newPackage = findPreferredWebViewPackage();
-                    onWebViewProviderChanged(newPackage);
-                }
+                PackageInfo newPackage = findPreferredWebViewPackage();
+                onWebViewProviderChanged(newPackage);
             } else {
                 this.notifyAll();
             }
@@ -349,6 +519,14 @@
 
     private class BinderService extends IWebViewUpdateService.Stub {
 
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out,
+                FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+            (new WebViewUpdateServiceShellCommand(this)).exec(
+                    this, in, out, err, args, resultReceiver);
+        }
+
+
         /**
          * The shared relro process calls this to notify us that it's done trying to create a relro
          * file. This method gets called even if the relro creation has failed or the process
@@ -364,9 +542,14 @@
                 return;
             }
 
-            synchronized (WebViewUpdateService.this) {
-                mNumRelroCreationsFinished++;
-                checkIfRelrosDoneLocked();
+            long callingId = Binder.clearCallingIdentity();
+            try {
+                synchronized (WebViewUpdateService.this) {
+                    mNumRelroCreationsFinished++;
+                    checkIfRelrosDoneLocked();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(callingId);
             }
         }
 
@@ -402,11 +585,6 @@
                 // Make sure we return the provider that was used to create the relro file
                 webViewPackage = WebViewUpdateService.this.mCurrentWebViewPackage;
                 if (webViewReady) {
-                } else if (mCurrentProviderBeingReplaced) {
-                    // It is important that we check this flag before the one representing WebView
-                    // being installed, otherwise we might think there is no WebView though the
-                    // current one is just being replaced.
-                    webViewStatus = WebViewFactory.LIBLOAD_WEBVIEW_BEING_REPLACED;
                 } else if (!mAnyWebViewInstalled) {
                     webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
                 } else {
@@ -423,7 +601,7 @@
          * This is called from DeveloperSettings when the user changes WebView provider.
          */
         @Override // Binder call
-        public void changeProviderAndSetting(String newProvider) {
+        public String changeProviderAndSetting(String newProvider) {
             if (getContext().checkCallingPermission(
                         android.Manifest.permission.WRITE_SECURE_SETTINGS)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -435,14 +613,22 @@
                 throw new SecurityException(msg);
             }
 
-            WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+            long callingId = Binder.clearCallingIdentity();
+            try {
+                return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+            } finally {
+                Binder.restoreCallingIdentity(callingId);
+            }
         }
 
         @Override // Binder call
         public WebViewProviderInfo[] getValidWebViewPackages() {
-            synchronized(WebViewUpdateService.this) {
-                return mCurrentValidWebViewPackages;
-            }
+            return WebViewUpdateService.this.getValidWebViewPackages();
+        }
+
+        @Override // Binder call
+        public WebViewProviderInfo[] getAllWebViewPackages() {
+            return WebViewUpdateService.this.mSystemInterface.getWebViewPackages();
         }
 
         @Override // Binder call
@@ -453,5 +639,26 @@
                 return WebViewUpdateService.this.mCurrentWebViewPackage.packageName;
             }
         }
+
+        @Override // Binder call
+        public boolean isFallbackPackage(String packageName) {
+            return WebViewUpdateService.this.isFallbackPackage(packageName);
+        }
+
+        @Override // Binder call
+        public void enableFallbackLogic(boolean enable) {
+            if (getContext().checkCallingPermission(
+                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                String msg = "Permission Denial: enableFallbackLogic() from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid()
+                        + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+
+            WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
new file mode 100644
index 0000000..68448f3
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.webkit;
+
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.webkit.IWebViewUpdateService;
+
+import java.io.PrintWriter;
+
+class WebViewUpdateServiceShellCommand extends ShellCommand {
+    final IWebViewUpdateService mInterface;
+
+    WebViewUpdateServiceShellCommand(IWebViewUpdateService service) {
+        mInterface = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            switch(cmd) {
+                case "enable-redundant-packages":
+                    return enableFallbackLogic(false);
+                case "disable-redundant-packages":
+                    return enableFallbackLogic(true);
+                case "set-webview-implementation":
+                    return setWebViewImplementation();
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        } catch (RemoteException e) {
+            pw.println("Remote exception: " + e);
+        }
+        return -1;
+    }
+
+    private int enableFallbackLogic(boolean enable) throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        mInterface.enableFallbackLogic(enable);
+        pw.println("Success");
+        return 0;
+    }
+
+    private int setWebViewImplementation() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        String shellChosenPackage = getNextArg();
+        String newPackage = mInterface.changeProviderAndSetting(shellChosenPackage);
+        if (shellChosenPackage.equals(newPackage)) {
+            pw.println("Success");
+            return 0;
+        } else {
+            pw.println(String.format(
+                        "Failed to switch to %s, the WebView implementation is now provided by %s.",
+                        shellChosenPackage, newPackage));
+            return 1;
+        }
+    }
+
+    @Override
+    public void onHelp() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("WebView updater commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println("");
+        pw.println("  enable-redundant-packages");
+        pw.println("    Allow a fallback package to be installed and enabled even when a");
+        pw.println("    more-preferred package is available. This command is useful when testing");
+        pw.println("    fallback packages.");
+        pw.println("  disable-redundant-packages");
+        pw.println("    Disallow installing and enabling fallback packages when a more-preferred");
+        pw.println("    package is available.");
+        pw.println("  set-webview-implementation PACKAGE");
+        pw.println("    Set the WebView implementation to the specified package.");
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 2c15818..bae628a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -21,6 +21,7 @@
 
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.annotation.NonNull;
 import android.app.Service;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -38,6 +39,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
@@ -122,6 +124,12 @@
         }
     }
 
+    public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
+        if (mDisplayMagnifier != null) {
+            mDisplayMagnifier.getMagnificationRegionsLocked(outMagnified, outAvailable);
+        }
+    }
+
     public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
         if (mDisplayMagnifier != null) {
             mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
@@ -392,6 +400,10 @@
             return spec;
         }
 
+        public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
+            mMagnifedViewport.getBoundsLocked(outMagnified, outAvailable);
+        }
+
         public void destroyLocked() {
             mMagnifedViewport.destroyWindow();
         }
@@ -413,6 +425,7 @@
             private final Matrix mTempMatrix = new Matrix();
 
             private final Region mMagnifiedBounds = new Region();
+            private final Region mAvailableBounds = new Region();
             private final Region mOldMagnifiedBounds = new Region();
             private final Region mOldAvailableBounds = new Region();
 
@@ -450,6 +463,12 @@
                 recomputeBoundsLocked();
             }
 
+            public void getBoundsLocked(@NonNull Region outMagnified,
+                    @NonNull Region outAvailable) {
+                outMagnified.set(mMagnifiedBounds);
+                outAvailable.set(mAvailableBounds);
+            }
+
             public void updateMagnificationSpecLocked(MagnificationSpec spec) {
                 if (spec != null) {
                     mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
@@ -469,14 +488,11 @@
                 final int screenWidth = mTempPoint.x;
                 final int screenHeight = mTempPoint.y;
 
-                Region magnifiedBounds = mMagnifiedBounds;
-                magnifiedBounds.set(0, 0, 0, 0);
-
-                Region availableBounds = mTempRegion1;
-                availableBounds.set(0, 0, screenWidth, screenHeight);
+                mMagnifiedBounds.set(0, 0, 0, 0);
+                mAvailableBounds.set(0, 0, screenWidth, screenHeight);
 
                 if (mCircularPath != null) {
-                    availableBounds.setPath(mCircularPath, availableBounds);
+                    mAvailableBounds.setPath(mCircularPath, mAvailableBounds);
                 }
 
                 Region nonMagnifiedBounds = mTempRegion4;
@@ -494,36 +510,37 @@
                         continue;
                     }
 
-                    Region windowBounds = mTempRegion2;
+                    // Consider the touchable portion of the window
                     Matrix matrix = mTempMatrix;
                     populateTransformationMatrixLocked(windowState, matrix);
+                    Region touchableRegion = mTempRegion3;
+                    windowState.getTouchableRegion(touchableRegion);
+                    Rect touchableFrame = mTempRect1;
+                    touchableRegion.getBounds(touchableFrame);
                     RectF windowFrame = mTempRectF;
+                    windowFrame.set(touchableFrame);
+                    windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
+                    matrix.mapRect(windowFrame);
+                    Region windowBounds = mTempRegion2;
+                    windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
+                            (int) windowFrame.right, (int) windowFrame.bottom);
+                    // Only update new regions
+                    Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
+                    portionOfWindowAlreadyAccountedFor.set(mMagnifiedBounds);
+                    portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
+                    windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
 
                     if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
-                        windowFrame.set(windowState.mFrame);
-                        windowFrame.offset(-windowFrame.left, -windowFrame.top);
-                        matrix.mapRect(windowFrame);
-                        windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
-                                (int) windowFrame.right, (int) windowFrame.bottom);
-                        magnifiedBounds.op(windowBounds, Region.Op.UNION);
-                        magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
+                        mMagnifiedBounds.op(windowBounds, Region.Op.UNION);
+                        mMagnifiedBounds.op(mAvailableBounds, Region.Op.INTERSECT);
                     } else {
-                        Region touchableRegion = mTempRegion3;
-                        windowState.getTouchableRegion(touchableRegion);
-                        Rect touchableFrame = mTempRect1;
-                        touchableRegion.getBounds(touchableFrame);
-                        windowFrame.set(touchableFrame);
-                        windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
-                        matrix.mapRect(windowFrame);
-                        windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
-                                (int) windowFrame.right, (int) windowFrame.bottom);
                         nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
-                        windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
-                        availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
+                        mAvailableBounds.op(windowBounds, Region.Op.DIFFERENCE);
                     }
 
+                    // Update accounted bounds
                     Region accountedBounds = mTempRegion2;
-                    accountedBounds.set(magnifiedBounds);
+                    accountedBounds.set(mMagnifiedBounds);
                     accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
                     accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
 
@@ -539,15 +556,15 @@
 
                 visibleWindows.clear();
 
-                magnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
+                mMagnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
                         screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
                         Region.Op.INTERSECT);
 
-                final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(magnifiedBounds);
-                final boolean availableChanged = !mOldAvailableBounds.equals(availableBounds);
+                final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(mMagnifiedBounds);
+                final boolean availableChanged = !mOldAvailableBounds.equals(mAvailableBounds);
                 if (magnifiedChanged || availableChanged) {
                     if (magnifiedChanged) {
-                        mWindow.setBounds(magnifiedBounds);
+                        mWindow.setBounds(mMagnifiedBounds);
                         Rect dirtyRect = mTempRect1;
                         if (mFullRedrawNeeded) {
                             mFullRedrawNeeded = false;
@@ -557,23 +574,23 @@
                             mWindow.invalidate(dirtyRect);
                         } else {
                             Region dirtyRegion = mTempRegion3;
-                            dirtyRegion.set(magnifiedBounds);
+                            dirtyRegion.set(mMagnifiedBounds);
                             dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
                             dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
                             dirtyRegion.getBounds(dirtyRect);
                             mWindow.invalidate(dirtyRect);
                         }
 
-                        mOldMagnifiedBounds.set(magnifiedBounds);
+                        mOldMagnifiedBounds.set(mMagnifiedBounds);
                     }
 
                     if (availableChanged) {
-                        mOldAvailableBounds.set(availableBounds);
+                        mOldAvailableBounds.set(mAvailableBounds);
                     }
 
                     final SomeArgs args = SomeArgs.obtain();
-                    args.arg1 = Region.obtain(magnifiedBounds);
-                    args.arg2 = Region.obtain(availableBounds);
+                    args.arg1 = Region.obtain(mMagnifiedBounds);
+                    args.arg2 = Region.obtain(mAvailableBounds);
                     mHandler.obtainMessage(
                             MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
                 }
@@ -1197,6 +1214,8 @@
             window.type = windowState.mAttrs.type;
             window.layer = windowState.mLayer;
             window.token = windowState.mClient.asBinder();
+            window.title = windowState.mAttrs.getTitle();
+            window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
 
             WindowState attachedWindow = windowState.mAttachedWindow;
             if (attachedWindow != null) {
@@ -1269,6 +1288,12 @@
                     && !oldWindow.childTokens.equals(newWindow.childTokens)) {
                 return true;
             }
+            if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
+                return true;
+            }
+            if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
+                return true;
+            }
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 5cb7099..d684278 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -43,10 +43,14 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Path;
 import android.graphics.Rect;
 import android.os.Debug;
 import android.os.IBinder;
@@ -73,6 +77,7 @@
 import com.android.server.wm.WindowManagerService.H;
 import com.android.server.wm.animation.ClipRectLRAnimation;
 import com.android.server.wm.animation.ClipRectTBAnimation;
+import com.android.server.wm.animation.CurvedTranslateAnimation;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -127,6 +132,8 @@
     public static final int TRANSIT_TASK_IN_PLACE = 17;
     /** An activity is being relaunched (e.g. due to configuration change). */
     public static final int TRANSIT_ACTIVITY_RELAUNCH = 18;
+    /** A task is being docked from recents. */
+    public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
 
     /** Fraction of animation at which the recents thumbnail stays completely transparent */
     private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
@@ -139,13 +146,15 @@
     static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
 
+    private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
+            new PathInterpolator(0.85f, 0f, 1f, 1f);
+
     /**
      * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
      * involved, to make it more understandable.
      */
     private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
     private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
-    private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
     private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
 
     private final Context mContext;
@@ -206,6 +215,7 @@
     private final Interpolator mThumbnailFadeOutInterpolator;
     private final Interpolator mLinearOutSlowInInterpolator;
     private final Interpolator mFastOutLinearInInterpolator;
+    private final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
 
     private final int mClipRevealTranslationY;
@@ -226,6 +236,8 @@
                 com.android.internal.R.interpolator.linear_out_slow_in);
         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_linear_in);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
         mConfigShortAnimTime = context.getResources().getInteger(
                 com.android.internal.R.integer.config_shortAnimTime);
         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -812,12 +824,14 @@
      * Prepares the specified animation with a standard duration, interpolator, etc.
      */
     Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
-            int duration, Interpolator interpolator) {
+            long duration, Interpolator interpolator) {
         if (duration > 0) {
             a.setDuration(duration);
         }
         a.setFillAfter(true);
-        a.setInterpolator(interpolator);
+        if (interpolator != null) {
+            a.setInterpolator(interpolator);
+        }
         a.initialize(appWidth, appHeight, appWidth, appHeight);
         return a;
     }
@@ -866,55 +880,95 @@
      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
      * when a thumbnail is specified with the pending animation override.
      */
-    Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, Bitmap thumbnailHeader,
-            final int taskId) {
+    Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
+            Bitmap thumbnailHeader, final int taskId, int orientation) {
         Animation a;
         final int thumbWidthI = thumbnailHeader.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
         final int thumbHeightI = thumbnailHeader.getHeight();
-        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
         final int appWidth = appRect.width();
 
         float scaleW = appWidth / thumbWidth;
-        float unscaledHeight = thumbHeight * scaleW;
         getNextAppTransitionStartRect(taskId, mTmpRect);
-        final float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
-        final float toY = appRect.top + -unscaledStartY;
+        final float fromX;
+        final float fromY;
+        final float toX;
+        final float toY;
+        final float pivotX;
+        final float pivotY;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+            fromX = mTmpRect.left;
+            fromY = mTmpRect.top;
+
+            // For the curved translate animation to work, the pivot points needs to be at the
+            // same absolute position as the one from the real surface.
+            toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
+            toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
+            pivotX = mTmpRect.width() / 2;
+            pivotY = appRect.height() / 2 / scaleW;
+        } else {
+            pivotX = 0;
+            pivotY = 0;
+            fromX = mTmpRect.left;
+            fromY = mTmpRect.top;
+            toX = appRect.left;
+            toY = appRect.top;
+        }
+        final long duration = getAspectScaleDuration();
+        final Interpolator interpolator = getAspectScaleInterpolator();
         if (mNextAppTransitionScaleUp) {
             // Animation up from the thumbnail to the full screen
-            Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
-                    mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
-            scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
-            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
+            scale.setInterpolator(interpolator);
+            scale.setDuration(duration);
             Animation alpha = new AlphaAnimation(1f, 0f);
-            alpha.setInterpolator(mThumbnailFadeOutInterpolator);
-            alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
-            final float toX = appRect.left + appRect.width() / 2 -
-                    (mTmpRect.left + thumbWidth / 2);
-            Animation translate = new TranslateAnimation(0, toX, 0, toY);
-            translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
-            translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
+                    ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
+            alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
+                    ? duration / 2
+                    : duration);
+            Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
+            translate.setInterpolator(interpolator);
+            translate.setDuration(duration);
+
+            mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
+            mTmpToClipRect.set(appRect);
+
+            // Containing frame is in screen space, but we need the clip rect in the
+            // app space.
+            mTmpToClipRect.offsetTo(0, 0);
+            mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
+            mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
+
+            if (contentInsets != null) {
+                mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
+                        (int) (-contentInsets.top * scaleW),
+                        (int) (-contentInsets.right * scaleW),
+                        (int) (-contentInsets.bottom * scaleW));
+            }
+
+            Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+            clipAnim.setInterpolator(interpolator);
+            clipAnim.setDuration(duration);
 
             // This AnimationSet uses the Interpolators assigned above.
             AnimationSet set = new AnimationSet(false);
             set.addAnimation(scale);
             set.addAnimation(alpha);
             set.addAnimation(translate);
+            set.addAnimation(clipAnim);
             a = set;
         } else {
             // Animation down from the full screen to the thumbnail
-            Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
-                    mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
-            scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
-            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
+            scale.setInterpolator(interpolator);
+            scale.setDuration(duration);
             Animation alpha = new AlphaAnimation(0f, 1f);
             alpha.setInterpolator(mThumbnailFadeInInterpolator);
-            alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
-            final float toX = appRect.left + appRect.width() / 2 -
-                    (mTmpRect.left + thumbWidth / 2);
-            Animation translate = new TranslateAnimation(toX, 0, toY, 0);
-            translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
-            translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            alpha.setDuration(duration);
+            Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
+            translate.setInterpolator(interpolator);
+            translate.setDuration(duration);
 
             // This AnimationSet uses the Interpolators assigned above.
             AnimationSet set = new AnimationSet(false);
@@ -925,7 +979,48 @@
 
         }
         return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
-                TOUCH_RESPONSE_INTERPOLATOR);
+                null);
+    }
+
+    private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
+
+        // Almost no x-change - use linear animation
+        if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
+            return new TranslateAnimation(fromX, toX, fromY, toY);
+        } else {
+            final Path path = createCurvedPath(fromX, toX, fromY, toY);
+            return new CurvedTranslateAnimation(path);
+        }
+    }
+
+    private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
+        final Path path = new Path();
+        path.moveTo(fromX, fromY);
+
+        if (fromY > toY) {
+            // If the object needs to go up, move it in horizontal direction first, then vertical.
+            path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
+        } else {
+            // If the object needs to go down, move it in vertical direction first, then horizontal.
+            path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
+        }
+        return path;
+    }
+
+    private long getAspectScaleDuration() {
+        if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+            return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
+        } else {
+            return THUMBNAIL_APP_TRANSITION_DURATION;
+        }
+    }
+
+    private Interpolator getAspectScaleInterpolator() {
+        if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+            return mFastOutSlowInInterpolator;
+        } else {
+            return TOUCH_RESPONSE_INTERPOLATOR;
+        }
     }
 
     /**
@@ -943,17 +1038,23 @@
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
         final int thumbHeightI = mTmpRect.height();
         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
-
-        // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
-        float scale = 1f;
-        int scaledTopDecor = 0;
+        final int thumbStartX = mTmpRect.left - containingFrame.left;
+        final int thumbStartY = mTmpRect.top - containingFrame.top;
 
         switch (thumbTransitState) {
-            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
-                if (freeform) {
+            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
+            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
+                final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
+                if (freeform && scaleUp) {
                     a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
                             containingFrame, surfaceInsets, taskId);
+                } else if (freeform) {
+                    a = createAspectScaledThumbnailExitFreeformAnimationLocked(
+                            containingFrame, surfaceInsets, taskId);
                 } else {
+                    AnimationSet set = new AnimationSet(true);
+
+                    // In portrait, we scale to fit the width
                     mTmpFromClipRect.set(containingFrame);
                     mTmpToClipRect.set(containingFrame);
 
@@ -964,26 +1065,61 @@
 
                     // Exclude insets region from the source clip.
                     mTmpFromClipRect.inset(contentInsets);
-
-                    // We scale the width and clip to the top/left square
-                    scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
-                    scaledTopDecor = (int) (scale * contentInsets.top);
-                    int unscaledThumbHeight = (int) (thumbHeight / scale);
-                    mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
-
                     mNextAppTransitionInsets.set(contentInsets);
 
-                    Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
-                            computePivot(mTmpRect.left - containingFrame.left, scale),
-                            computePivot(mTmpRect.top - containingFrame.top, scale));
-                    Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
-                    Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
+                    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+                        // We scale the width and clip to the top/left square
+                        // We scale the width and clip to the top/left square
+                        float scale = thumbWidth /
+                                (appWidth - contentInsets.left - contentInsets.right);
+                        int unscaledThumbHeight = (int) (thumbHeight / scale);
+                        mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
 
-                    AnimationSet set = new AnimationSet(true);
-                    set.addAnimation(clipAnim);
-                    set.addAnimation(scaleAnim);
-                    set.addAnimation(translateAnim);
+                        mNextAppTransitionInsets.set(contentInsets);
+
+                        Animation scaleAnim = new ScaleAnimation(
+                                scaleUp ? scale : 1, scaleUp ? 1 : scale,
+                                scaleUp ? scale : 1, scaleUp ? 1 : scale,
+                                containingFrame.width() / 2f,
+                                containingFrame.height() / 2f + contentInsets.top);
+                        final float targetX = (mTmpRect.left - containingFrame.left);
+                        final float x = containingFrame.width() / 2f
+                                - containingFrame.width() / 2f * scale;
+                        final float targetY = (mTmpRect.top - containingFrame.top);
+                        final float y = containingFrame.height() / 2f
+                                - containingFrame.height() / 2f * scale;
+                        final float startX = targetX - x;
+                        final float startY = targetY - y;
+                        Animation clipAnim = scaleUp
+                                ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
+                                : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
+                        Animation translateAnim = scaleUp
+                                ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
+                                : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
+
+                        set.addAnimation(clipAnim);
+                        set.addAnimation(scaleAnim);
+                        set.addAnimation(translateAnim);
+
+                    } else {
+                        // In landscape, we don't scale at all and only crop
+                        mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
+                        mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
+
+                        Animation clipAnim = scaleUp
+                                ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
+                                : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
+                        Animation translateAnim = scaleUp
+                                ? createCurvedMotion(thumbStartX, 0,
+                                thumbStartY - contentInsets.top, 0)
+                                : createCurvedMotion(0, thumbStartX, 0,
+                                        thumbStartY - contentInsets.top);
+
+                        set.addAnimation(clipAnim);
+                        set.addAnimation(translateAnim);
+                    }
                     a = set;
+                    a.setZAdjustment(Animation.ZORDER_TOP);
                 }
                 break;
             }
@@ -1009,55 +1145,12 @@
                 }
                 break;
             }
-            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
-                // App window scaling down from full screen
-                if (freeform) {
-                    a = createAspectScaledThumbnailExitFreeformAnimationLocked(
-                            containingFrame, surfaceInsets, taskId);
-                } else {
-                    mTmpFromClipRect.set(containingFrame);
-                    mTmpToClipRect.set(containingFrame);
-
-                    // Containing frame is in screen space, but we need the clip rect in the
-                    // app space.
-                    mTmpFromClipRect.offsetTo(0, 0);
-                    mTmpToClipRect.offsetTo(0, 0);
-
-                    // Exclude insets region from the target clip.
-                    mTmpToClipRect.inset(contentInsets);
-
-                    // We scale the width and clip to the top/left square
-                    scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
-                    scaledTopDecor = (int) (scale * contentInsets.top);
-                    int unscaledThumbHeight = (int) (thumbHeight / scale);
-                    mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
-
-                    mNextAppTransitionInsets.set(contentInsets);
-
-                    Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
-                            computePivot(mTmpRect.left - containingFrame.left, scale),
-                            computePivot(mTmpRect.top - containingFrame.top, scale));
-                    Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
-                    Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
-
-                    AnimationSet set = new AnimationSet(true);
-                    set.addAnimation(clipAnim);
-                    set.addAnimation(scaleAnim);
-                    set.addAnimation(translateAnim);
-
-                    a = set;
-                    a.setZAdjustment(Animation.ZORDER_TOP);
-                }
-                break;
-            }
             default:
                 throw new RuntimeException("Invalid thumbnail transition state");
         }
 
-        int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
-                THUMBNAIL_APP_TRANSITION_DURATION);
-        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
-                TOUCH_RESPONSE_INTERPOLATOR);
+        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
+                getAspectScaleDuration(), getAspectScaleInterpolator());
     }
 
     private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
@@ -1411,6 +1504,7 @@
                             ? WindowAnimation_activityCloseEnterAnimation
                             : WindowAnimation_activityCloseExitAnimation;
                     break;
+                case TRANSIT_DOCK_TASK_FROM_RECENTS:
                 case TRANSIT_TASK_OPEN:
                     animAttr = enter
                             ? WindowAnimation_taskOpenEnterAnimation
@@ -1467,6 +1561,14 @@
         return a;
     }
 
+    int getAppStackClipMode() {
+        return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
+                || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
+                || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
+                ? STACK_CLIP_NONE
+                : STACK_CLIP_AFTER_ANIM;
+    }
+
     void postAnimationCallback() {
         if (mNextAppTransitionCallback != null) {
             mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
@@ -1686,6 +1788,9 @@
             case TRANSIT_ACTIVITY_RELAUNCH: {
                 return "TRANSIT_ACTIVITY_RELAUNCH";
             }
+            case TRANSIT_DOCK_TASK_FROM_RECENTS: {
+                return "TRANSIT_DOCK_TASK_FROM_RECENTS";
+            }
             default: {
                 return "<UNKNOWN>";
             }
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index fa5ee72..aae52e8 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -23,6 +23,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 
 import android.graphics.Matrix;
 import android.util.Slog;
@@ -76,8 +77,6 @@
     // requires that the duration of the two animations are the same.
     SurfaceControl thumbnail;
     int thumbnailTransactionSeq;
-    int thumbnailX;
-    int thumbnailY;
     int thumbnailLayer;
     int thumbnailForceAboveLayer;
     Animation thumbnailAnimation;
@@ -106,6 +105,7 @@
     boolean usingTransferredAnimation = false;
 
     private boolean mSkipFirstFrame = false;
+    private int mStackClip = STACK_CLIP_BEFORE_ANIM;
 
     static final Animation sDummyAnimation = new DummyAnimation();
 
@@ -115,7 +115,8 @@
         mAnimator = mService.mAnimator;
     }
 
-    public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame) {
+    public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame,
+            int stackClip) {
         if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
                 + ": " + anim + " wxh=" + width + "x" + height
                 + " isVisible=" + mAppToken.isVisible());
@@ -142,6 +143,7 @@
         transformation.clear();
         transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
         hasTransformation = true;
+        mStackClip = stackClip;
 
         this.mSkipFirstFrame = skipFirstFrame;
 
@@ -153,6 +155,13 @@
         } else {
             mClearProlongedAnimation = true;
         }
+
+        // Since we are finally starting our animation, we don't need the logic anymore to prevent
+        // the app from showing again if we just moved between stacks. See
+        // {@link WindowState#notifyMovedInStack}.
+        for (int i = mAppToken.allAppWindows.size() - 1; i >= 0; i--) {
+            mAppToken.allAppWindows.get(i).resetJustMovedInStack();
+        }
     }
 
     public void setDummyAnimation() {
@@ -164,17 +173,22 @@
         transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
     }
 
+    void setNullAnimation() {
+        animation = null;
+        usingTransferredAnimation = false;
+    }
+
     public void clearAnimation() {
         if (animation != null) {
-            animation = null;
             animating = true;
         }
         clearThumbnail();
+        setNullAnimation();
         if (mAppToken.deferClearAllDrawn) {
             mAppToken.allDrawn = false;
             mAppToken.deferClearAllDrawn = false;
         }
-        usingTransferredAnimation = false;
+        mStackClip = STACK_CLIP_BEFORE_ANIM;
     }
 
     public boolean isAnimating() {
@@ -183,20 +197,25 @@
 
     public void clearThumbnail() {
         if (thumbnail != null) {
-            thumbnail.destroy();
+            thumbnail.hide();
+            mService.mWindowPlacerLocked.destroyAfterTransaction(thumbnail);
             thumbnail = null;
         }
         deferThumbnailDestruction = false;
     }
 
+    int getStackClip() {
+        return mStackClip;
+    }
+
     void transferCurrentAnimation(
             AppWindowAnimator toAppAnimator, WindowStateAnimator transferWinAnimator) {
 
         if (animation != null) {
             toAppAnimator.animation = animation;
-            animation = null;
             toAppAnimator.animating = animating;
             toAppAnimator.animLayerAdjustment = animLayerAdjustment;
+            setNullAnimation();
             animLayerAdjustment = 0;
             toAppAnimator.updateLayers();
             updateLayers();
@@ -233,7 +252,6 @@
         thumbnailTransformation.clear();
         final long animationFrameTime = getAnimationFrameTime(thumbnailAnimation, currentTime);
         thumbnailAnimation.getTransformation(animationFrameTime, thumbnailTransformation);
-        thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
 
         ScreenRotationAnimation screenRotationAnimation =
                 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
@@ -267,6 +285,7 @@
         }
         thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
                 tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
+        thumbnail.setWindowCrop(thumbnailTransformation.getClipRect());
     }
 
     /**
@@ -303,7 +322,7 @@
                 if (mProlongAnimation == PROLONG_ANIMATION_AT_END) {
                     hasMoreFrames = true;
                 } else {
-                    animation = null;
+                    setNullAnimation();
                     clearThumbnail();
                     if (DEBUG_ANIM) Slog.v(TAG, "Finished animation in " + mAppToken + " @ "
                             + currentTime);
@@ -440,8 +459,6 @@
         }
         if (thumbnail != null) {
             pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
-                    pw.print(" x="); pw.print(thumbnailX);
-                    pw.print(" y="); pw.print(thumbnailY);
                     pw.print(" layer="); pw.println(thumbnailLayer);
             pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
             pw.print(prefix); pw.print("thumbnailTransformation=");
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 12c62bd..4ec297e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -21,6 +21,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -128,6 +129,7 @@
     boolean mAlwaysFocusable;
 
     boolean mAppStopped;
+    int mPendingRelaunchCount;
 
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
 
@@ -159,6 +161,25 @@
         }
     }
 
+    void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
+        firstWindowDrawn = true;
+
+        // We now have a good window to show, remove dead placeholders
+        removeAllDeadWindows();
+
+        if (startingData != null) {
+            if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
+                    + win.mToken + ": first real window is shown, no animation");
+            // If this initial window is animating, stop it -- we will do an animation to reveal
+            // it from behind the starting window, so there is no need for it to also be doing its
+            // own stuff.
+            winAnimator.clearAnimation();
+            winAnimator.mService.mFinishedStarting.add(this);
+            winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
+        }
+        updateReportedVisibilityLocked();
+    }
+
     void updateReportedVisibilityLocked() {
         if (appToken == null) {
             return;
@@ -301,23 +322,6 @@
         }
     }
 
-    void setWindowsExiting(boolean exiting) {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            WindowState win = allAppWindows.get(i);
-            // If the app already requested to remove its window, we don't modify
-            // its exiting state. Otherwise the stale window won't get removed on
-            // exit and could cause focus to be given to the wrong window.
-            if (!(win.mRemoveOnExit && win.mAnimatingExit)) {
-                win.mAnimatingExit = exiting;
-            }
-            // If we're no longer exiting, remove the window from destroying list
-            if (!win.mAnimatingExit && win.mDestroying) {
-                win.mDestroying = false;
-                service.mDestroySurface.remove(win);
-            }
-        }
-    }
-
     // Here we destroy surfaces which have been marked as eligible by the animator, taking care
     // to ensure the client has finished with them. If the client could still be using them
     // we will skip destruction and try again when the client has stopped.
@@ -334,6 +338,11 @@
                 continue;
             }
 
+            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
+                    + " destroySurfaces: mAppStopped=" + mAppStopped
+                    + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
+                    + " win.mRemoveOnExit=" + win.mRemoveOnExit);
+
             win.destroyOrSaveSurface();
             if (win.mRemoveOnExit) {
                 win.mAnimatingExit = false;
@@ -352,11 +361,19 @@
         }
     }
 
-    // The application has stopped, so destroy any surfaces which were keeping alive
-    // in case they were still being used.
-    void notifyAppStopped() {
-        mAppStopped = true;
-        destroySurfaces();
+    /**
+     * If the application has stopped it is okay to destroy any surfaces which were keeping alive
+     * in case they were still being used.
+     */
+    void notifyAppStopped(boolean stopped) {
+        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this);
+        mAppStopped = stopped;
+
+        if (stopped) {
+            destroySurfaces();
+            // Remove any starting window that was added for this app if they are still around.
+            mTask.mService.scheduleRemoveStartingWindowLocked(this);
+        }
     }
 
     /**
@@ -449,7 +466,7 @@
                 winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
             WindowState win = allAppWindows.get(winNdx);
             if (win.mAppDied) {
-                if (DEBUG_WINDOW_MOVEMENT) {
+                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
                     Slog.w(TAG, "removeAllDeadWindows: " + win);
                 }
                 // Set mDestroying, we don't want any animation or delayed removal here.
@@ -498,6 +515,26 @@
         }
     }
 
+    boolean isRelaunching() {
+        return mPendingRelaunchCount > 0;
+    }
+
+    void startRelaunching() {
+        if (canFreezeBounds()) {
+            freezeBounds();
+        }
+        mPendingRelaunchCount++;
+    }
+
+    void finishRelaunching() {
+        if (canFreezeBounds()) {
+            unfreezeBounds();
+        }
+        if (mPendingRelaunchCount > 0) {
+            mPendingRelaunchCount--;
+        }
+    }
+
     void addWindow(WindowState w) {
         for (int i = allAppWindows.size() - 1; i >= 0; i--) {
             WindowState candidate = allAppWindows.get(i);
@@ -546,20 +583,26 @@
         }
     }
 
+    private boolean canFreezeBounds() {
+        // For freeform windows, we can't freeze the bounds at the moment because this would make
+        // the resizing unresponsive.
+        return mTask != null && !mTask.inFreeformWorkspace();
+    }
+
     /**
      * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
      * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
      * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
      * with a queue.
      */
-    void freezeBounds() {
+    private void freezeBounds() {
         mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
     }
 
     /**
      * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
      */
-    void unfreezeBounds() {
+    private void unfreezeBounds() {
         mFrozenBounds.remove();
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
@@ -594,6 +637,9 @@
         if (paused) {
             pw.print(prefix); pw.print("paused="); pw.println(paused);
         }
+        if (mAppStopped) {
+            pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
+        }
         if (numInterestingWindows != 0 || numDrawnWindows != 0
                 || allDrawn || mAppAnimator.allDrawn) {
             pw.print(prefix); pw.print("numInterestingWindows=");
@@ -619,10 +665,13 @@
             pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
                     pw.print(" startingView="); pw.print(startingView);
                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
-                    pw.print(" startingMoved"); pw.println(startingMoved);
+                    pw.print(" startingMoved="); pw.println(startingMoved);
         }
         if (!mFrozenBounds.isEmpty()) {
-            pw.print(prefix); pw.print("mFrozenBounds="); pw.print(mFrozenBounds);
+            pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
+        }
+        if (mPendingRelaunchCount != 0) {
+            pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index f0efebe..b7d6062 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -54,7 +54,8 @@
         private final AnimateBoundsUser mTarget;
         private final Rect mFrom;
         private final Rect mTo;
-        private final Rect mTmpRect;
+        private final Rect mTmpRect = new Rect();
+        private final Rect mTmpTaskBounds = new Rect();
         private final boolean mMoveToFullScreen;
         // True if this this animation was cancelled and will be replaced the another animation from
         // the same {@link #AnimateBoundsUser} target.
@@ -63,17 +64,40 @@
         // {@link #AnimateBoundsUser} target.
         private final boolean mReplacement;
 
+        // Depending on whether we are animating from
+        // a smaller to a larger size
+        private final int mFrozenTaskWidth;
+        private final int mFrozenTaskHeight;
+
         BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to,
                 boolean moveToFullScreen, boolean replacement) {
             super();
             mTarget = target;
             mFrom = from;
             mTo = to;
-            mTmpRect = new Rect();
             mMoveToFullScreen = moveToFullScreen;
             mReplacement = replacement;
             addUpdateListener(this);
             addListener(this);
+
+            // If we are animating from smaller to larger, we want to change the task bounds
+            // to their final size immediately so we can use scaling to make the window
+            // larger. Likewise if we are going from bigger to smaller, we want to wait until
+            // the end so we don't have to upscale from the smaller finished size.
+            if (animatingToLargerSize()) {
+                mFrozenTaskWidth = mTo.width();
+                mFrozenTaskHeight = mTo.height();
+            } else {
+                mFrozenTaskWidth = mFrom.width();
+                mFrozenTaskHeight = mFrom.height();
+            }
+        }
+
+        boolean animatingToLargerSize() {
+            if (mFrom.width() * mFrom.height() > mTo.width() * mTo.height()) {
+                return false;
+            }
+            return true;
         }
 
         @Override
@@ -87,7 +111,13 @@
             if (DEBUG) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + " mBounds="
                     + mTmpRect + " from=" + mFrom + " mTo=" + mTo + " value=" + value
                     + " remains=" + remains);
-            if (!mTarget.setSize(mTmpRect)) {
+
+            if (remains != 0) {
+                mTmpTaskBounds.set(mTmpRect.left, mTmpRect.top,
+                        mTmpRect.left + mFrozenTaskWidth, mTmpRect.top + mFrozenTaskHeight);
+            }
+
+            if (!mTarget.setPinnedStackSize(mTmpRect, remains != 0 ? mTmpTaskBounds : null)) {
                 // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
                 // any further animation.
                 animation.cancel();
@@ -99,6 +129,10 @@
         public void onAnimationStart(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
                     + " mReplacement=" + mReplacement);
+            if (animatingToLargerSize()) {
+                mTarget.setPinnedStackSize(mFrom, mTo);
+            }
+
             if (!mReplacement) {
                 mTarget.onAnimationStart();
             }
@@ -108,6 +142,7 @@
         public void onAnimationEnd(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
                     + " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace);
+
             finishAnimation();
             if (mMoveToFullScreen && !mWillReplace) {
                 mTarget.moveToFullscreen();
@@ -159,6 +194,12 @@
          * from the hierarchy and is not valid anymore.
          */
         boolean setSize(Rect bounds);
+        /**
+         * Behaves as setSize, but freezes the bounds of any tasks in the target at taskBounds,
+         * to allow for more flexibility during resizing. Only
+         * works for the pinned stack at the moment.
+         */
+        boolean setPinnedStackSize(Rect bounds, Rect taskBounds);
 
         void onAnimationStart();
 
@@ -173,7 +214,7 @@
         void getFullScreenBounds(Rect bounds);
     }
 
-    void animateBounds(final AnimateBoundsUser target, Rect from, Rect to) {
+    void animateBounds(final AnimateBoundsUser target, Rect from, Rect to, int animationDuration) {
         boolean moveToFullscreen = false;
         if (to == null) {
             to = new Rect();
@@ -201,7 +242,8 @@
                 new BoundsAnimator(target, from, to, moveToFullscreen, replacing);
         mRunningAnimations.put(target, animator);
         animator.setFloatValues(0f, 1f);
-        animator.setDuration(DEFAULT_APP_TRANSITION_DURATION * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
+        animator.setDuration((animationDuration != -1 ? animationDuration
+                : DEFAULT_APP_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
         animator.setInterpolator(new LinearInterpolator());
         animator.start();
     }
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index fc5d8ce..95be233 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -84,10 +84,13 @@
     /** The user of this dim layer. */
     private final DimLayerUser mUser;
 
-    DimLayer(WindowManagerService service, DimLayerUser user, int displayId) {
+    private final String mName;
+
+    DimLayer(WindowManagerService service, DimLayerUser user, int displayId, String name) {
         mUser = user;
         mDisplayId = displayId;
         mService = service;
+        mName = name;
         if (DEBUG_DIM_LAYER) Slog.v(TAG, "Ctor: displayId=" + displayId);
     }
 
@@ -100,7 +103,7 @@
                     16, 16, PixelFormat.OPAQUE,
                     SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
             } else {
-                mDimSurface = new SurfaceControl(service.mFxSession, TAG,
+                mDimSurface = new SurfaceControl(service.mFxSession, mName,
                     16, 16, PixelFormat.OPAQUE,
                     SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
             }
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 6d1cec4..3ec02b9 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -10,6 +10,8 @@
 import android.util.Slog;
 import android.util.TypedValue;
 
+import com.android.server.wm.DimLayer.DimLayerUser;
+
 import java.io.PrintWriter;
 
 /**
@@ -18,7 +20,8 @@
  * as well as other use cases (such as dimming above a dead window).
  */
 class DimLayerController {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "DimLayerController" : TAG_WM;
+    private static final String TAG_LOCAL = "DimLayerController";
+    private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
 
     /** Amount of time in milliseconds to animate the dim surface from one value to another,
      * when no window animation is driving it. */
@@ -63,7 +66,8 @@
                     newDimLayer = state.dimLayer;
                 } else {
                     // Create new full screen dim layer.
-                    newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId);
+                    newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId,
+                            getDimLayerTag(dimLayerUser));
                 }
                 dimLayerUser.getDimBounds(mTmpBounds);
                 newDimLayer.setBounds(mTmpBounds);
@@ -73,7 +77,8 @@
             }
         } else {
             newDimLayer = (state.dimLayer == null || previousFullscreen)
-                    ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId)
+                    ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId,
+                            getDimLayerTag(dimLayerUser))
                     : state.dimLayer;
             dimLayerUser.getDimBounds(mTmpBounds);
             newDimLayer.setBounds(mTmpBounds);
@@ -81,6 +86,10 @@
         state.dimLayer = newDimLayer;
     }
 
+    private static String getDimLayerTag(DimLayerUser dimLayerUser) {
+        return TAG_LOCAL + "/" + dimLayerUser.toShortString();
+    }
+
     private DimLayerState getOrCreateDimLayerState(DimLayer.DimLayerUser dimLayerUser) {
         if (DEBUG_DIM_LAYER) Slog.v(TAG, "getOrCreateDimLayerState, dimLayerUser="
                 + dimLayerUser.toShortString());
@@ -174,7 +183,12 @@
 
         for (int i = mState.size() - 1; i >= 0; i--) {
             DimLayer.DimLayerUser user = mState.keyAt(i);
-            if (user.isFullscreen()) {
+            DimLayerState state = mState.valueAt(i);
+            // We have to check that we are acutally the shared fullscreen layer
+            // for this path. If we began as non fullscreen and became fullscreen
+            // (e.g. Docked stack closing), then we may not be the shared layer
+            // and we have to make sure we always animate the layer.
+            if (user.isFullscreen() && state.dimLayer == mSharedFullScreenDimLayer) {
                 fullScreen = i;
                 if (mState.valueAt(i).continueDimming) {
                     fullScreenAndDimming = i;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 73cea52..28379f4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -29,6 +29,7 @@
 import android.app.ActivityManager.StackId;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.Region.Op;
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.view.Display;
@@ -426,6 +427,11 @@
             win.getTouchableRegion(mTmpRegion);
             mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
         }
+        if (getDockedStackVisibleForUserLocked() != null) {
+            mDividerControllerLocked.getTouchRegion(mTmpRect);
+            mTmpRegion.set(mTmpRect);
+            mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
+        }
         if (mTapDetector != null) {
             mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion, mNonResizeableRegion);
         }
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b6aa3f2..6f7e64f 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -16,6 +16,17 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.RemoteCallbackList;
@@ -32,17 +43,6 @@
 
 import java.util.ArrayList;
 
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
-import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
 /**
  * Keeps information about the docked stack divider.
  */
@@ -89,7 +89,7 @@
     private final DimLayer mDimLayer;
 
     private boolean mMinimizedDock;
-    private boolean mAnimating;
+    private boolean mAnimatingForMinimizedDockedStack;
     private boolean mAnimationStarted;
     private long mAnimationStartTime;
     private float mAnimationStart;
@@ -97,6 +97,9 @@
     private long mAnimationDuration;
     private final Interpolator mMinimizedDockInterpolator;
     private float mMaximizeMeetFraction;
+    private final Rect mTouchRegion = new Rect();
+    private boolean mAnimatingForIme;
+    private boolean mAdjustedForIme;
 
     DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -106,7 +109,8 @@
                 com.android.internal.R.dimen.docked_stack_divider_thickness);
         mDividerInsets = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_divider_insets);
-        mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId());
+        mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
+                "DockedStackDim");
         mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
                 context, android.R.interpolator.fast_out_slow_in);
     }
@@ -130,6 +134,15 @@
         }
     }
 
+    void setTouchRegion(Rect touchRegion) {
+        mTouchRegion.set(touchRegion);
+    }
+
+    void getTouchRegion(Rect outRegion) {
+        outRegion.set(mTouchRegion);
+        outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
+    }
+
     private void resetDragResizingChangeReported() {
         final WindowList windowList = mDisplayContent.getWindowList();
         for (int i = windowList.size() - 1; i >= 0; i--) {
@@ -164,6 +177,13 @@
         return mLastVisibility;
     }
 
+    void setAdjustedForIme(boolean adjusted, boolean animate) {
+        if (mAdjustedForIme != adjusted) {
+            mAnimatingForIme = animate;
+            mAdjustedForIme = adjusted;
+        }
+    }
+
     void positionDockedStackedDivider(Rect frame) {
         TaskStack stack = mDisplayContent.getDockedStackLocked();
         if (stack == null) {
@@ -223,6 +243,9 @@
             }
         }
         mDockedStackListeners.finishBroadcast();
+        if (!exists) {
+            setMinimizedDockedStack(false);
+        }
     }
 
     void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
@@ -243,12 +266,14 @@
         notifyDockedDividerVisibilityChanged(wasVisible());
         notifyDockedStackExistsChanged(
                 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
+        notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
     }
 
     void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
         SurfaceControl.openTransaction();
-        TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
-        boolean visibleAndValid = visible && stack != null;
+        final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
+        final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
+        boolean visibleAndValid = visible && stack != null && dockedStack != null;
         if (visibleAndValid) {
             stack.getDimBounds(mTmpRect);
             if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
@@ -317,12 +342,14 @@
      * @param animate Whether to animate the change.
      */
     private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
-        if (minimizedDock == mMinimizedDock
+        final boolean wasMinimized = mMinimizedDock;
+        mMinimizedDock = minimizedDock;
+        if (minimizedDock == wasMinimized
                 || mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
             return;
         }
 
-        mMinimizedDock = minimizedDock;
+        mAnimatingForIme = false;
         if (minimizedDock) {
             if (animate) {
                 startAdjustAnimation(0f, 1f);
@@ -339,7 +366,7 @@
     }
 
     private void startAdjustAnimation(float from, float to) {
-        mAnimating = true;
+        mAnimatingForMinimizedDockedStack = true;
         mAnimationStarted = false;
         mAnimationStart = from;
         mAnimationTarget = to;
@@ -347,13 +374,13 @@
 
     private void setMinimizedDockedStack(boolean minimized) {
         final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+        notifyDockedStackMinimizedChanged(minimized, 0);
         if (stack == null) {
             return;
         }
         if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
             mService.mWindowPlacerLocked.performSurfacePlacement();
         }
-        notifyDockedStackMinimizedChanged(minimized, 0);
     }
 
     private boolean isAnimationMaximizing() {
@@ -361,10 +388,45 @@
     }
 
     public boolean animate(long now) {
-        if (!mAnimating) {
+        if (mAnimatingForMinimizedDockedStack) {
+            return animateForMinimizedDockedStack(now);
+        } else if (mAnimatingForIme) {
+            return animateForIme();
+        } else {
             return false;
         }
+    }
 
+    private boolean animateForIme() {
+        boolean updated = false;
+        boolean animating = false;
+
+        final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            final TaskStack stack = stacks.get(i);
+            if (stack != null && stack.isAdjustedForIme()) {
+                updated |= stack.updateAdjustForIme();
+                animating |= stack.isAnimatingForIme();
+            }
+        }
+
+        if (updated) {
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+
+        if (!animating) {
+            mAnimatingForIme = false;
+            for (int i = stacks.size() - 1; i >= 0; --i) {
+                final TaskStack stack = stacks.get(i);
+                if (stack != null) {
+                    stack.clearImeGoingAway();
+                }
+            }
+        }
+        return animating;
+    }
+
+    private boolean animateForMinimizedDockedStack(long now) {
         final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
         if (!mAnimationStarted) {
             mAnimationStarted = true;
@@ -387,7 +449,7 @@
             }
         }
         if (t >= 1.0f) {
-            mAnimating = false;
+            mAnimatingForMinimizedDockedStack = false;
             return false;
         } else {
             return true;
diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java
new file mode 100644
index 0000000..08acf9d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DragResizeMode.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.wm;
+
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+
+/**
+ * Describes the mode in which a window is drag resizing.
+ */
+class DragResizeMode {
+
+    /**
+     * Freeform mode: Client surface is fullscreen, and client is responsible to draw window at
+     * the correct position.
+     */
+    static final int DRAG_RESIZE_MODE_FREEFORM = 0;
+
+    /**
+     * Mode for resizing the docked (and adjacent) stack: Client surface is fullscreen, but window
+     * is drawn at (0, 0), window manager is responsible for positioning the surface when draging.
+     */
+    static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
+
+    static boolean isModeAllowedForStack(int stackId, int mode) {
+        switch (mode) {
+            case DRAG_RESIZE_MODE_FREEFORM:
+                return stackId == FREEFORM_WORKSPACE_STACK_ID;
+            case DRAG_RESIZE_MODE_DOCKED_DIVIDER:
+                return stackId == DOCKED_STACK_ID
+                        || stackId == FULLSCREEN_WORKSPACE_STACK_ID
+                        || stackId == HOME_STACK_ID;
+            default:
+                return false;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index cf27b97..aace5e7 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -589,7 +589,7 @@
     void overridePointerIconLw(int touchSource) {
         mTouchSource = touchSource;
         if (isFromSource(InputDevice.SOURCE_MOUSE)) {
-            InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRAB);
+            InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRABBING);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 0581a16..24783bc 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,38 +16,33 @@
 
 package com.android.server.wm;
 
-import android.os.Looper;
 import android.os.Process;
 import android.view.Display;
 import android.view.InputChannel;
-import android.view.InputEventReceiver;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
 
-public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer {
+class InputConsumerImpl {
     final WindowManagerService mService;
     final InputChannel mServerChannel, mClientChannel;
     final InputApplicationHandle mApplicationHandle;
     final InputWindowHandle mWindowHandle;
-    final InputEventReceiver mInputEventReceiver;
-    final int mWindowLayer;
 
-    public InputConsumerImpl(WindowManagerService service, Looper looper,
-            InputEventReceiver.Factory inputEventReceiverFactory) {
-        String name = "input consumer";
+    InputConsumerImpl(WindowManagerService service, String name, InputChannel inputChannel) {
         mService = service;
 
         InputChannel[] channels = InputChannel.openInputChannelPair(name);
         mServerChannel = channels[0];
-        mClientChannel = channels[1];
+        if (inputChannel != null) {
+            channels[1].transferTo(inputChannel);
+            channels[1].dispose();
+            mClientChannel = inputChannel;
+        } else {
+            mClientChannel = channels[1];
+        }
         mService.mInputManager.registerInputChannel(mServerChannel, null);
 
-        mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
-                mClientChannel, looper);
-
         mApplicationHandle = new InputApplicationHandle(null);
         mApplicationHandle.name = name;
         mApplicationHandle.dispatchingTimeoutNanos =
@@ -57,8 +52,7 @@
         mWindowHandle.name = name;
         mWindowHandle.inputChannel = mServerChannel;
         mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
-        mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType);
-        mWindowHandle.layer = mWindowLayer;
+        mWindowHandle.layer = getLayerLw(mWindowHandle.layoutParamsType);
         mWindowHandle.layoutParamsFlags = 0;
         mWindowHandle.dispatchingTimeoutNanos =
                 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
@@ -81,21 +75,15 @@
         mWindowHandle.frameBottom = dh;
     }
 
-    @Override
-    public void dismiss() {
-        synchronized (mService.mWindowMap) {
-            if (mService.removeInputConsumer()) {
-                mInputEventReceiver.dispose();
-                mService.mInputManager.unregisterInputChannel(mServerChannel);
-                mClientChannel.dispose();
-                mServerChannel.dispose();
-            }
-        }
-    }
-
     private int getLayerLw(int windowType) {
         return mService.mPolicy.windowTypeToLayerLw(windowType)
                 * WindowManagerService.TYPE_LAYER_MULTIPLIER
                 + WindowManagerService.TYPE_LAYER_OFFSET;
     }
+
+    void disposeChannelsLw() {
+        mService.mInputManager.unregisterInputChannel(mServerChannel);
+        mClientChannel.dispose();
+        mServerChannel.dispose();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index e42658e..eea0e73 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -24,6 +24,7 @@
 
 import android.app.ActivityManagerNative;
 import android.graphics.Rect;
+import android.os.Debug;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Slog;
@@ -36,6 +37,7 @@
 import com.android.server.input.InputManagerService;
 import com.android.server.input.InputWindowHandle;
 
+import java.io.PrintWriter;
 import java.util.Arrays;
 
 final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
@@ -47,6 +49,9 @@
     // When true, prevents input dispatch from proceeding until set to false again.
     private boolean mInputDispatchFrozen;
 
+    // The reason the input is currently frozen or null if the input isn't frozen.
+    private String mInputFreezeReason = null;
+
     // When true, input dispatch proceeds normally.  Otherwise all events are dropped.
     // Initially false, so that input does not get dispatched until boot is finished at
     // which point the ActivityManager will enable dispatching.
@@ -277,6 +282,8 @@
 
         boolean addInputConsumerHandle = mService.mInputConsumer != null;
 
+        boolean addWallpaperInputConsumerHandle = mService.mWallpaperInputConsumer != null;
+
         // Add all windows on the default display.
         final int numDisplays = mService.mDisplayContents.size();
         final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
@@ -297,6 +304,14 @@
                     addInputConsumerHandle = false;
                 }
 
+                if (addWallpaperInputConsumerHandle) {
+                    if (child.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
+                        // Add the wallpaper input consumer above the first wallpaper window.
+                        addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+                        addWallpaperInputConsumerHandle = false;
+                    }
+                }
+
                 final int flags = child.mAttrs.flags;
                 final int privateFlags = child.mAttrs.privateFlags;
                 final int type = child.mAttrs.type;
@@ -324,6 +339,11 @@
             }
         }
 
+        if (addWallpaperInputConsumerHandle) {
+            // No wallpaper found, add the wallpaper input consumer at the end.
+            addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+        }
+
         // Send windows to native code.
         mService.mInputManager.setInputWindows(mInputWindowHandles);
 
@@ -474,12 +494,16 @@
     }
 
     public void freezeInputDispatchingLw() {
-        if (! mInputDispatchFrozen) {
+        if (!mInputDispatchFrozen) {
             if (DEBUG_INPUT) {
                 Slog.v(TAG_WM, "Freezing input dispatching");
             }
 
             mInputDispatchFrozen = true;
+
+            if (DEBUG_INPUT || true) {
+                mInputFreezeReason = Debug.getCallers(6);
+            }
             updateInputDispatchModeLw();
         }
     }
@@ -491,6 +515,7 @@
             }
 
             mInputDispatchFrozen = false;
+            mInputFreezeReason = null;
             updateInputDispatchModeLw();
         }
     }
@@ -509,4 +534,10 @@
     private void updateInputDispatchModeLw() {
         mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen);
     }
+
+    void dump(PrintWriter pw, String prefix) {
+        if (mInputFreezeReason != null) {
+            pw.println(prefix + "mInputFreezeReason=" + mInputFreezeReason);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 25de75a..daeb860 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -195,7 +195,7 @@
 
     @Override
     public void repositionChild(IWindow window, int left, int top, int right, int bottom,
-             long deferTransactionUntilFrame, Rect outFrame) {
+            long deferTransactionUntilFrame, Rect outFrame) {
         mService.repositionChild(this, window, left, top, right, bottom,
                 deferTransactionUntilFrame, outFrame);
     }
@@ -369,7 +369,12 @@
         if (DEBUG_TASK_POSITIONING) Slog.d(
                 TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
 
-        return mService.startMovingTask(window, startX, startY);
+        long ident = Binder.clearCallingIdentity();
+        try {
+            return mService.startMovingTask(window, startX, startY);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
     public void reportDropResult(IWindow window, boolean consumed) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 325005b..eea0ca0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -18,8 +18,8 @@
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
@@ -101,6 +101,7 @@
 
     // Whether the task is currently being drag-resized
     private boolean mDragResizing;
+    private int mDragResizeMode;
 
     private boolean mHomeTask;
 
@@ -134,51 +135,11 @@
 
         mShowNonResizeableDockToast = false;
 
-        if (isResizeable()) {
-            Slog.wtf(TAG,
-                    "Trying to show non-resizeable toast when task is resizeable task=" + this);
-            return;
-        }
-
         if (mResizeMode == RESIZE_MODE_UNRESIZEABLE) {
             final String text =
                     mService.mContext.getString(R.string.dock_non_resizeble_failed_to_dock_text);
             mService.mH.obtainMessage(SHOW_NON_RESIZEABLE_DOCK_TOAST, 0, 0, text).sendToTarget();
-            return;
         }
-
-        final int dockSide = mStack.getDockSide();
-        if (!inCropWindowsResizeMode() || dockSide == DOCKED_INVALID) {
-            return;
-        }
-
-        int xOffset = 0;
-        int yOffset = 0;
-        mStack.getBounds(mTmpRect);
-
-        if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
-            // The toast was originally placed at the bottom and centered. To place it at the
-            // bottom-center of the stack, we offset it horizontally by the diff between the center
-            // of the stack bounds vs. the center of the screen.
-            displayContent.getLogicalDisplayRect(mTmpRect2);
-            xOffset = mTmpRect.centerX() - mTmpRect2.centerX();
-        } else if (dockSide == DOCKED_TOP) {
-            // The toast was originally placed at the bottom and centered. To place it at the bottom
-            // center of the top stack, we offset it vertically by the diff between the bottom of
-            // the stack bounds vs. the bottom of the content rect.
-            //
-            // Note here we use the content rect instead of the display rect, as we want the toast's
-            // distance to the dock divider (when it's placed at the top half) to be the same as
-            // it's distance to the top of the navigation bar (when it's placed at the bottom).
-
-            // We don't adjust for DOCKED_BOTTOM case since it's already at the bottom.
-            displayContent.getContentRect(mTmpRect2);
-            yOffset = mTmpRect2.bottom - mTmpRect.bottom;
-        }
-        final String text =
-                mService.mContext.getString(R.string.dock_cropped_windows_text);
-        mService.mH.obtainMessage(SHOW_NON_RESIZEABLE_DOCK_TOAST,
-                xOffset, yOffset, text).sendToTarget();
     }
 
     void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
@@ -247,7 +208,15 @@
             mStack.removeTask(this);
         }
         stack.positionTask(this, position, showForAllUsers());
-        setBounds(bounds, config);
+        resizeLocked(bounds, config, false /* force */);
+
+        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                final WindowState win = windows.get(winNdx);
+                win.notifyMovedInStack();
+            }
+        }
     }
 
     boolean removeAppToken(AppWindowToken wtoken) {
@@ -272,7 +241,7 @@
     }
 
     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
-    int setBounds(Rect bounds, Configuration config) {
+    private int setBounds(Rect bounds, Configuration config) {
         if (config == null) {
             config = Configuration.EMPTY;
         }
@@ -456,7 +425,7 @@
         if (mFullscreen
                 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
                 || displayContent == null
-                || displayContent.getDockedStackLocked() != null) {
+                || displayContent.getDockedStackVisibleForUserLocked() != null) {
             return true;
         }
         return false;
@@ -529,7 +498,15 @@
                 return;
             }
 
-            out.set(mBounds);
+            if (!mFullscreen) {
+                // When minimizing the docked stack when going home, we don't adjust the task bounds
+                // so we need to intersect the task bounds with the stack bounds here.
+                mStack.getBounds(mTmpRect);
+                mTmpRect.intersect(mBounds);
+                out.set(mTmpRect);
+            } else {
+                out.set(mBounds);
+            }
             return;
         }
 
@@ -539,9 +516,14 @@
         mStack.getDisplayContent().getLogicalDisplayRect(out);
     }
 
-    void setDragResizing(boolean dragResizing) {
+    void setDragResizing(boolean dragResizing, int dragResizeMode) {
         if (mDragResizing != dragResizing) {
+            if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
+                throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
+                        + mStack.mStackId + " dragResizeMode=" + dragResizeMode);
+            }
             mDragResizing = dragResizing;
+            mDragResizeMode = dragResizeMode;
             resetDragResizingChangeReported();
         }
     }
@@ -560,6 +542,10 @@
         return mDragResizing || (mStack != null && mStack.isDragResizing());
     }
 
+    int getDragResizeMode() {
+        return mDragResizeMode;
+    }
+
     void updateDisplayInfo(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
@@ -598,13 +584,21 @@
     void resizeWindows() {
         final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
-            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+            final AppWindowToken atoken = mAppTokens.get(activityNdx);
+
+            // Some windows won't go through the resizing process, if they don't have a surface, so
+            // destroy all saved surfaces here.
+            atoken.destroySavedSurfaces();
+            final ArrayList<WindowState> windows = atoken.allAppWindows;
             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                 final WindowState win = windows.get(winNdx);
                 if (win.mHasSurface && !resizingWindows.contains(win)) {
                     if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
                     resizingWindows.add(win);
                 }
+                if (win.isGoneForLayoutLw()) {
+                    win.mResizedWhileGone = true;
+                }
             }
         }
     }
@@ -674,6 +668,10 @@
                 && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
     }
 
+    boolean isFloating() {
+        return StackId.tasksAreFloating(mStack.mStackId);
+    }
+
     /**
      * Whether the task should be treated as if it's docked. Returns true if the task
      * is currently in docked workspace, or it's side-by-side to a docked task.
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f7035c5..ae70aa8 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -29,6 +29,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
 
@@ -60,7 +61,8 @@
 import java.lang.annotation.RetentionPolicy;
 
 class TaskPositioner implements DimLayer.DimLayerUser {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskPositioner" : TAG_WM;
+    private static final String TAG_LOCAL = "TaskPositioner";
+    private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
 
     // The margin the pointer position has to be within the side of the screen to be
     // considered at the side of the screen.
@@ -287,7 +289,7 @@
         }
         mService.pauseRotationLocked();
 
-        mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId());
+        mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId(), TAG_LOCAL);
         mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
@@ -378,7 +380,7 @@
 
     private void endDragLocked() {
         mResizing = false;
-        mTask.setDragResizing(false);
+        mTask.setDragResizing(false, DRAG_RESIZE_MODE_FREEFORM);
     }
 
     /** Returns true if the move operation should be ended. */
@@ -408,7 +410,7 @@
                 bottom = Math.max(top + mMinVisibleHeight, bottom + deltaY);
             }
             mWindowDragBounds.set(left, top, right, bottom);
-            mTask.setDragResizing(true);
+            mTask.setDragResizing(true, DRAG_RESIZE_MODE_FREEFORM);
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 06e5ac5..0225c9b 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -55,6 +55,11 @@
     // If the stack should be resized to fullscreen.
     private static final boolean FULLSCREEN = true;
 
+    // When we have a top-bottom split screen, we shift the bottom stack up to accommodate
+    // the IME window. The static flag below controls whether to run animation when the
+    // IME window goes away.
+    private static final boolean ANIMATE_IME_GOING_AWAY = false;
+
     /** Unique identifier */
     final int mStackId;
 
@@ -107,10 +112,26 @@
     private final Rect mLastContentBounds = new Rect();
     private final Rect mTmpAdjustedBounds = new Rect();
     private boolean mAdjustedForIme;
+    private boolean mImeGoingAway;
     private WindowState mImeWin;
     private float mMinimizeAmount;
     private final int mDockedStackMinimizeThickness;
 
+    // If this is true, the task will be down or upscaled
+    // to perfectly fit the region it would have been cropped
+    // to.
+    private boolean mForceScaleToCrop = false;
+    // By default, movement animations are applied to all
+    // window movement. If this is true, animations will not
+    // be applied within this stack. This is useful for example
+    // if the windows are moving as the result of a stack animation,
+    // in which case a second window animation would cause jitter.
+    private boolean mFreezeMovementAnimations = false;
+
+    // Temporary storage for the new bounds that should be used after the configuration change.
+    // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
+    private final Rect mBoundsAfterRotation = new Rect();
+
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
@@ -137,9 +158,7 @@
     boolean setBounds(
             Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
             SparseArray<Rect> taskTempInsetBounds) {
-        if (!setBounds(stackBounds)) {
-            return false;
-        }
+        setBounds(stackBounds);
 
         // Update bounds of containing tasks.
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -191,10 +210,11 @@
      * @param bounds The adjusted bounds.
      * @param keepInsets Whether to keep the insets from the original bounds or to calculate new
      *                   ones depending on the adjusted bounds.
+     * @return true if the adjusted bounds has changed.
      */
-    private void setAdjustedBounds(Rect bounds, boolean keepInsets) {
+    private boolean setAdjustedBounds(Rect bounds, boolean keepInsets) {
         if (mAdjustedBounds.equals(bounds)) {
-            return;
+            return false;
         }
 
         mAdjustedBounds.set(bounds);
@@ -202,6 +222,7 @@
         alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds,
                 adjusted && keepInsets ? mBounds : null);
         mDisplayContent.layoutNeeded = true;
+        return true;
     }
 
     private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
@@ -326,40 +347,89 @@
             setBounds(mTmpRect2);
         } else {
             mLastUpdateDisplayInfoRotation = newRotation;
-            updateBoundsAfterRotation();
+            updateBoundsAfterRotation(true);
         }
     }
 
-    void onConfigurationChanged() {
+    boolean onConfigurationChanged() {
         mLastConfigChangedRotation = getDisplayInfo().rotation;
-        updateBoundsAfterRotation();
+        return updateBoundsAfterRotation(false);
     }
 
-    void updateBoundsAfterRotation() {
+    boolean updateBoundsAfterRotation(boolean scheduleResize) {
         if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) {
             // We wait for the rotation values after configuration change and display info. update
             // to be equal before updating the bounds due to rotation change otherwise things might
             // get out of alignment...
-            return;
+            return false;
         }
 
         final int newRotation = getDisplayInfo().rotation;
 
         if (mRotation == newRotation) {
             // Nothing to do here if the rotation didn't change
-            return;
+            return false;
         }
 
         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (mStackId == DOCKED_STACK_ID) {
+            repositionDockedStackAfterRotation(mTmpRect2);
             snapDockedStackAfterRotation(mTmpRect2);
         }
 
-        // Post message to inform activity manager of the bounds change simulating
-        // a one-way call. We do this to prevent a deadlock between window manager
-        // lock and activity manager lock been held.
-        mService.mH.obtainMessage(
-                RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+        if (scheduleResize) {
+            // Post message to inform activity manager of the bounds change simulating
+            // a one-way call. We do this to prevent a deadlock between window manager
+            // lock and activity manager lock been held.
+            mService.mH.obtainMessage(RESIZE_STACK, mStackId,
+                    0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+        } else {
+            mBoundsAfterRotation.set(mTmpRect2);
+        }
+
+        return true;
+    }
+
+    void getBoundsForNewConfiguration(Rect outBounds) {
+        outBounds.set(mBoundsAfterRotation);
+        mBoundsAfterRotation.setEmpty();
+    }
+
+    /**
+     * Some dock sides are not allowed by the policy. This method queries the policy and moves
+     * the docked stack around if needed.
+     *
+     * @param inOutBounds the bounds of the docked stack to adjust
+     */
+    private void repositionDockedStackAfterRotation(Rect inOutBounds) {
+        int dockSide = getDockSide(inOutBounds);
+        if (mService.mPolicy.isDockSideAllowed(dockSide)) {
+            return;
+        }
+        mDisplayContent.getLogicalDisplayRect(mTmpRect);
+        dockSide = DockedDividerUtils.invertDockSide(dockSide);
+        switch (dockSide) {
+            case DOCKED_LEFT:
+                int movement = inOutBounds.left;
+                inOutBounds.left -= movement;
+                inOutBounds.right -= movement;
+                break;
+            case DOCKED_RIGHT:
+                movement = mTmpRect.right - inOutBounds.right;
+                inOutBounds.left += movement;
+                inOutBounds.right += movement;
+                break;
+            case DOCKED_TOP:
+                movement = inOutBounds.top;
+                inOutBounds.top -= movement;
+                inOutBounds.bottom -= movement;
+                break;
+            case DOCKED_BOTTOM:
+                movement = mTmpRect.bottom - inOutBounds.bottom;
+                inOutBounds.top += movement;
+                inOutBounds.bottom += movement;
+                break;
+        }
     }
 
     /**
@@ -536,7 +606,8 @@
         }
 
         mDisplayContent = displayContent;
-        mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId());
+        mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
+                "animation background stackId=" + mStackId);
 
         Rect bounds = null;
         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
@@ -558,13 +629,6 @@
         }
 
         updateDisplayInfo(bounds);
-
-        if (mStackId == DOCKED_STACK_ID) {
-            // Attaching a docked stack to the display affects the size of all other static
-            // stacks since the docked stack occupies a dedicated region on screen.
-            // Resize existing static stacks so they are pushed to the side of the docked stack.
-            resizeNonDockedStacks(!FULLSCREEN, mBounds);
-        }
     }
 
     void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
@@ -673,36 +737,6 @@
         DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
     }
 
-    /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
-     * based on the presence of a docked stack.
-     * @param fullscreen If true the stacks will be resized to fullscreen, else they will be
-     *                   resized to the appropriate size based on the presence of a docked stack.
-     * @param dockedBounds Bounds of the docked stack.
-     */
-    private void resizeNonDockedStacks(boolean fullscreen, Rect dockedBounds) {
-        // Not using mTmpRect because we are posting the object in a message.
-        final Rect bounds = new Rect();
-        mDisplayContent.getLogicalDisplayRect(bounds);
-        if (!fullscreen) {
-            final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
-                    == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-            getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
-                    mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
-        }
-
-        final int count = mService.mStackIdToStack.size();
-        for (int i = 0; i < count; i++) {
-            final TaskStack otherStack = mService.mStackIdToStack.valueAt(i);
-            final int otherStackId = otherStack.mStackId;
-            if (StackId.isResizeableByDockedStack(otherStackId)
-                    && !otherStack.mBounds.equals(bounds)) {
-                mService.mH.sendMessage(
-                        mService.mH.obtainMessage(RESIZE_STACK, otherStackId,
-                                1 /*allowResizeInDockedMode*/, fullscreen ? null : bounds));
-            }
-        }
-    }
-
     void resetDockedStackToMiddle() {
         if (mStackId != DOCKED_STACK_ID) {
             throw new IllegalStateException("Not a docked stack=" + this);
@@ -736,12 +770,6 @@
             mService.mWindowPlacerLocked.requestTraversal();
         }
 
-        if (mStackId == DOCKED_STACK_ID) {
-            // Docked stack was detached from the display, so we no longer need to restrict the
-            // region of the screen other static stacks occupy. Go ahead and make them fullscreen.
-            resizeNonDockedStacks(FULLSCREEN, null);
-        }
-
         close();
     }
 
@@ -789,16 +817,55 @@
     void setAdjustedForIme(WindowState imeWin) {
         mAdjustedForIme = true;
         mImeWin = imeWin;
-        updateAdjustedBounds();
+        mImeGoingAway = false;
+    }
+
+    boolean isAdjustedForIme() {
+        return mAdjustedForIme || mImeGoingAway;
+    }
+    void clearImeGoingAway() {
+        mImeGoingAway = false;
+    }
+
+    boolean isAnimatingForIme() {
+        return mImeWin != null && mImeWin.isAnimatingLw();
+    }
+
+    /**
+     * Update the stack's bounds (crop or position) according to the IME window's
+     * current position. When IME window is animated, the bottom stack is animated
+     * together to track the IME window's current position, and the top stack is
+     * cropped as necessary.
+     *
+     * @return true if a traversal should be performed after the adjustment.
+     */
+    boolean updateAdjustForIme() {
+        boolean stopped = false;
+        if (mImeGoingAway && (!ANIMATE_IME_GOING_AWAY || !isAnimatingForIme())) {
+            mImeWin = null;
+            mAdjustedForIme = false;
+            stopped = true;
+        }
+        // Make sure to run a traversal when the animation stops so that the stack
+        // is moved to its final position.
+        return updateAdjustedBounds() || stopped;
     }
 
     /**
      * Resets the adjustment after it got adjusted for the IME.
+     * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
+     *                        animations; otherwise, set flag and animates the window away together
+     *                        with IME window.
      */
-    void resetAdjustedForIme() {
-        mAdjustedForIme = false;
-        mImeWin = null;
-        updateAdjustedBounds();
+    void resetAdjustedForIme(boolean adjustBoundsNow) {
+        if (adjustBoundsNow) {
+            mImeWin = null;
+            mAdjustedForIme = false;
+            mImeGoingAway = false;
+            updateAdjustedBounds();
+        } else {
+            mImeGoingAway |= mAdjustedForIme;
+        }
     }
 
     /**
@@ -817,6 +884,10 @@
         }
     }
 
+    boolean isAdjustedForMinimizedDock() {
+        return mMinimizeAmount != 0f;
+    }
+
     private boolean adjustForIME(final WindowState imeWin) {
         final int dockedSide = getDockSide();
         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
@@ -832,6 +903,12 @@
         getDisplayContent().getContentRect(displayContentRect);
         contentBounds.set(displayContentRect);
         int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+
+        // if IME window is animating, get its actual vertical shown position (but no smaller than
+        // the final target vertical position)
+        if (imeWin.isAnimatingLw()) {
+            imeTop = Math.max(imeTop, imeWin.getShownPositionLw().y);
+        }
         imeTop += imeWin.getGivenContentInsetsLw().top;
         if (contentBounds.bottom > imeTop) {
             contentBounds.bottom = imeTop;
@@ -880,9 +957,11 @@
                     (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
         } else if (dockSide == DOCKED_LEFT) {
             mTmpAdjustedBounds.set(mBounds);
+            final int width = mBounds.width();
             mTmpAdjustedBounds.right =
                     (int) (minimizeAmount * mDockedStackMinimizeThickness
                             + (1 - minimizeAmount) * mBounds.right);
+            mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
         } else if (dockSide == DOCKED_RIGHT) {
             mTmpAdjustedBounds.set(mBounds);
             mTmpAdjustedBounds.left =
@@ -915,7 +994,7 @@
     /**
      * Updates the adjustment depending on it's current state.
      */
-    void updateAdjustedBounds() {
+    boolean updateAdjustedBounds() {
         boolean adjust = false;
         if (mMinimizeAmount != 0f) {
             adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
@@ -926,7 +1005,7 @@
             mTmpAdjustedBounds.setEmpty();
             mLastContentBounds.setEmpty();
         }
-        setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
+        return setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
     }
 
     boolean isAdjustedForMinimizedDockedStack() {
@@ -1084,23 +1163,44 @@
             }
         }
         try {
-            mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false);
+            mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false, -1);
         } catch (RemoteException e) {
         }
         return true;
     }
 
+    public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
+        synchronized (mService.mWindowMap) {
+            if (mDisplayContent == null) {
+                return false;
+            }
+            if (mStackId != PINNED_STACK_ID) {
+                Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
+                        + "non pinned stack");
+                return false;
+            }
+        }
+        try {
+            mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
+        } catch (RemoteException e) {
+            // I don't believe you.
+        }
+        return true;
+    }
+
     @Override  // AnimatesBounds
     public void onAnimationStart() {
         synchronized (mService.mWindowMap) {
-            setDragResizingLocked(true);
+            mFreezeMovementAnimations = true;
+            mForceScaleToCrop = true;
         }
     }
 
     @Override  // AnimatesBounds
     public void onAnimationEnd() {
         synchronized (mService.mWindowMap) {
-            setDragResizingLocked(false);
+            mFreezeMovementAnimations = false;
+            mForceScaleToCrop = false;
             mService.requestTraversal();
         }
         if (mStackId == PINNED_STACK_ID) {
@@ -1125,4 +1225,12 @@
     public void getFullScreenBounds(Rect bounds) {
         getDisplayContent().getContentRect(bounds);
     }
+
+    public boolean getFreezeMovementAnimations() {
+        return mFreezeMovementAnimations;
+    }
+
+    public boolean getForceScaleToCrop() {
+        return mForceScaleToCrop;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 2e424d0..e44b0f3 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -508,10 +508,11 @@
 
             replacing = replacing || w.mWillReplaceWindow;
 
-            // If the app is executing an animation because the keyguard is going away,
-            // keep the wallpaper during the animation so it doesn't flicker out.
+            // If the app is executing an animation because the keyguard is going away (and the
+            // keyguard was showing the wallpaper) keep the wallpaper during the animation so it
+            // doesn't flicker out.
             final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
-                    || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayAnimation);
+                    || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayWithWallpaper);
             if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
                 if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
                 result.setWallpaperTarget(w, i);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 38d0711..eae7838 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -22,6 +22,9 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
+import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
@@ -33,6 +36,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
@@ -98,8 +103,7 @@
     boolean mInitialized = false;
 
     boolean mKeyguardGoingAway;
-    boolean mKeyguardGoingAwayToNotificationShade;
-    boolean mKeyguardGoingAwayDisableWindowAnimations;
+    int mKeyguardGoingAwayFlags;
 
     /** Use one animation for all entering activities after keyguard is dismissed. */
     Animation mPostKeyguardExitAnimation;
@@ -243,6 +247,13 @@
 
         final WindowList windows = mService.getWindowListLocked(displayId);
 
+        final boolean keyguardGoingAwayToShade =
+                (mKeyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0;
+        final boolean keyguardGoingAwayNoAnimation =
+                (mKeyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0;
+        final boolean keyguardGoingAwayWithWallpaper =
+                (mKeyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0;
+
         if (mKeyguardGoingAway) {
             for (int i = windows.size() - 1; i >= 0; i--) {
                 WindowState win = windows.get(i);
@@ -261,6 +272,8 @@
                         winAnimator.mAnimationIsEntrance = false;
                         winAnimator.mAnimationStartTime = -1;
                         winAnimator.mKeyguardGoingAwayAnimation = true;
+                        winAnimator.mKeyguardGoingAwayWithWallpaper
+                                = keyguardGoingAwayWithWallpaper;
                     }
                 } else {
                     if (DEBUG_KEYGUARD) Slog.d(TAG,
@@ -392,10 +405,14 @@
                             if (DEBUG_KEYGUARD) Slog.v(TAG,
                                     "Applying existing Keyguard exit animation to new window: win="
                                             + win);
-                            Animation a = mPolicy.createForceHideEnterAnimation(
-                                    false, mKeyguardGoingAwayToNotificationShade);
-                            winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime());
+
+                            Animation a = mPolicy.createForceHideEnterAnimation(false,
+                                    keyguardGoingAwayToShade);
+                            winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime(),
+                                    STACK_CLIP_BEFORE_ANIM);
                             winAnimator.mKeyguardGoingAwayAnimation = true;
+                            winAnimator.mKeyguardGoingAwayWithWallpaper
+                                    = keyguardGoingAwayWithWallpaper;
                         }
                         final WindowState currentFocus = mService.mCurrentFocus;
                         if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
@@ -431,7 +448,7 @@
             }
 
             final AppWindowToken atoken = win.mAppToken;
-            if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
+            if (winAnimator.mDrawState == READY_TO_SHOW) {
                 if (atoken == null || atoken.allDrawn) {
                     if (winAnimator.performShowLocked()) {
                         setPendingLayoutChanges(displayId,
@@ -463,18 +480,20 @@
         // being force-hidden, apply the appropriate animation to them if animations are not
         // disabled.
         if (unForceHiding != null) {
-            if (!mKeyguardGoingAwayDisableWindowAnimations) {
+            if (!keyguardGoingAwayNoAnimation) {
                 boolean first = true;
                 for (int i=unForceHiding.size()-1; i>=0; i--) {
                     final WindowStateAnimator winAnimator = unForceHiding.get(i);
                     Animation a = mPolicy.createForceHideEnterAnimation(
                             wallpaperInUnForceHiding && !startingInUnForceHiding,
-                            mKeyguardGoingAwayToNotificationShade);
+                            keyguardGoingAwayToShade);
                     if (a != null) {
                         if (DEBUG_KEYGUARD) Slog.v(TAG,
                                 "Starting keyguard exit animation on window " + winAnimator.mWin);
-                        winAnimator.setAnimation(a);
+                        winAnimator.setAnimation(a, STACK_CLIP_BEFORE_ANIM);
                         winAnimator.mKeyguardGoingAwayAnimation = true;
+                        winAnimator.mKeyguardGoingAwayWithWallpaper
+                                = keyguardGoingAwayWithWallpaper;
                         if (first) {
                             mPostKeyguardExitAnimation = a;
                             mPostKeyguardExitAnimation.setStartTime(mCurrentTime);
@@ -489,11 +508,10 @@
 
 
             // Wallpaper is going away in un-force-hide motion, animate it as well.
-            if (!wallpaperInUnForceHiding && wallpaper != null
-                    && !mKeyguardGoingAwayDisableWindowAnimations) {
+            if (!wallpaperInUnForceHiding && wallpaper != null && !keyguardGoingAwayNoAnimation) {
                 if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
                 Animation a = mPolicy.createForceHideWallpaperExitAnimation(
-                        mKeyguardGoingAwayToNotificationShade);
+                        keyguardGoingAwayToShade);
                 if (a != null) {
                     wallpaper.mWinAnimator.setAnimation(a);
                 }
@@ -530,7 +548,7 @@
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
             WindowStateAnimator winAnimator = win.mWinAnimator;
-            if (winAnimator.mSurfaceController == null) {
+            if (winAnimator.mSurfaceController == null || !winAnimator.hasSurface()) {
                 continue;
             }
 
@@ -771,6 +789,7 @@
         }
 
         mService.destroyPreservedSurfaceLocked();
+        mService.mWindowPlacerLocked.destroyPendingSurfaces();
 
         if (DEBUG_WINDOW_TRACE) {
             Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index d843a8c..6bdcd42 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -77,28 +77,22 @@
             int oldLayer = w.mLayer;
             if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
                 curLayer += WINDOW_LAYER_MULTIPLIER;
-                w.mLayer = curLayer;
             } else {
                 curBaseLayer = curLayer = w.mBaseLayer;
-                w.mLayer = curLayer;
             }
-            if (w.mLayer != oldLayer) {
-                layerChanged = true;
-                anyLayerChanged = true;
-            }
+            assignAnimLayer(w, curLayer);
 
-            final WindowStateAnimator winAnimator = w.mWinAnimator;
-            oldLayer = winAnimator.mAnimLayer;
-            winAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
-                    getSpecialWindowAnimLayerAdjustment(w);
-            if (winAnimator.mAnimLayer != oldLayer) {
+            // TODO: Preserved old behavior of code here but not sure comparing
+            // oldLayer to mAnimLayer and mLayer makes sense...though the
+            // worst case would be unintentionalp layer reassignment.
+            if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
                 layerChanged = true;
                 anyLayerChanged = true;
             }
 
             if (w.mAppToken != null) {
                 mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
-                        winAnimator.mAnimLayer);
+                        w.mWinAnimator.mAnimLayer);
             }
             collectSpecialWindows(w);
 
@@ -197,18 +191,20 @@
     }
 
     private void adjustSpecialWindows() {
-        int layer = mHighestApplicationLayer + 1;
+        int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
         // For pinned and docked stack window, we want to make them above other windows also when
         // these windows are animating.
         while (!mDockedWindows.isEmpty()) {
             layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
         }
 
-        // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space
-        // below the divider but above the app windows. It needs to be below the divider in because
-        // the divider sometimes overlaps the app windows.
-        layer++;
         layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+
+        if (mDockDivider != null && mDockDivider.isVisibleLw()
+                && mService.mInputMethodWindow != null) {
+            layer = assignAndIncreaseLayerIfNeeded(mService.mInputMethodWindow, layer);
+        }
+
         // We know that we will be animating a relaunching window in the near future, which will
         // receive a z-order increase. We want the replaced window to immediately receive the same
         // treatment, e.g. to be above the dock divider.
@@ -222,14 +218,24 @@
     }
 
     private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
-        if (win != null) {
-            win.mLayer = layer;
-            win.mWinAnimator.mAnimLayer = layer;
-            layer++;
+        if (win != null && layer > win.mLayer) {
+            assignAnimLayer(win, layer);
+            // Make sure we leave space inbetween normal windows for dims and such.
+            layer += WINDOW_LAYER_MULTIPLIER;
         }
         return layer;
     }
 
+    private void assignAnimLayer(WindowState w, int layer) {
+        w.mLayer = layer;
+        w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
+                    getSpecialWindowAnimLayerAdjustment(w);
+        if (w.mAppToken != null && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer > 0
+                && w.mWinAnimator.mAnimLayer > w.mAppToken.mAppAnimator.thumbnailForceAboveLayer) {
+            w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = w.mWinAnimator.mAnimLayer;
+        }
+    }
+
     void dump(PrintWriter pw, String s) {
         if (mInputMethodAnimLayerAdjustment != 0 ||
                 mService.mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 142715e..a632bdb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -20,9 +20,13 @@
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -117,8 +121,11 @@
 import android.view.inputmethod.InputMethodManagerInternal;
 import android.widget.Toast;
 
+import com.android.internal.R;
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IShortcutService;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -196,6 +203,8 @@
 import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
@@ -230,6 +239,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -320,6 +330,8 @@
 
     private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f;
 
+    private static final String PROPERTY_BUILD_DATE_UTC = "ro.build.date.utc";
+
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -360,6 +372,7 @@
     final WindowManagerPolicy mPolicy = new PhoneWindowManager();
 
     final IActivityManager mActivityManager;
+    final ActivityManagerInternal mAmInternal;
 
     final AppOpsManager mAppOps;
 
@@ -395,6 +408,11 @@
     InputConsumerImpl mInputConsumer;
 
     /**
+     * The input consumer added to the window manager before all wallpaper windows.
+     */
+    InputConsumerImpl mWallpaperInputConsumer;
+
+    /**
      * Windows that are being resized.  Used so we can tell the client about
      * the resize after closing the transaction in which we resized the
      * underlying surface.
@@ -498,6 +516,8 @@
 
     private final SparseIntArray mTmpTaskIds = new SparseIntArray();
 
+    private final ArrayList<Integer> mChangedStackList = new ArrayList();
+
     boolean mForceResizableTasks = false;
 
     int getDragLayerLocked() {
@@ -789,7 +809,13 @@
             = new WindowManagerInternal.AppTransitionListener() {
 
         @Override
+        public void onAppTransitionCancelledLocked() {
+            mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_CANCELLED);
+        }
+
+        @Override
         public void onAppTransitionFinishedLocked(IBinder token) {
+            mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_FINISHED);
             AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 return;
@@ -900,6 +926,7 @@
         mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
 
         mActivityManager = ActivityManagerNative.getDefault();
+        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
         AppOpsManager.OnOpChangedInternalListener opListener =
                 new AppOpsManager.OnOpChangedInternalListener() {
@@ -1342,11 +1369,8 @@
         final int fl = w.mAttrs.flags
                 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
         final int type = w.mAttrs.type;
-        // The dock divider has to sit above the application windows and so does the IME. IME also
-        // needs to sit above the dock divider, so it doesn't get cut in half. We make the dock
-        // divider be a target for IME, so this relationship can occur naturally.
         if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)
-                || type == TYPE_APPLICATION_STARTING || type == TYPE_DOCK_DIVIDER) {
+                || type == TYPE_APPLICATION_STARTING) {
             if (DEBUG_INPUT_METHOD) {
                 Slog.i(TAG_WM, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
                 if (!w.isVisibleOrAdding()) {
@@ -1993,11 +2017,19 @@
             final WindowStateAnimator winAnimator = win.mWinAnimator;
             winAnimator.mEnterAnimationPending = true;
             winAnimator.mEnteringAnimation = true;
-            prepareWindowReplacementTransition(atoken);
+            // Check if we need to prepare a transition for replacing window first.
+            if (atoken != null && !prepareWindowReplacementTransition(atoken)) {
+                // If not, check if need to set up a dummy transition during display freeze
+                // so that the unfreeze wait for the apps to draw. This might be needed if
+                // the app is relaunching.
+                prepareNoneTransitionForRelaunching(atoken);
+            }
 
             if (displayContent.isDefaultDisplay) {
-                mPolicy.getInsetHintLw(win.mAttrs, mRotation, outContentInsets, outStableInsets,
-                        outOutsets);
+                if (mPolicy.getInsetHintLw(win.mAttrs, mRotation, outContentInsets, outStableInsets,
+                        outOutsets)) {
+                    res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
+                }
             } else {
                 outContentInsets.setEmpty();
                 outStableInsets.setEmpty();
@@ -2051,10 +2083,10 @@
         return res;
     }
 
-    private void prepareWindowReplacementTransition(AppWindowToken atoken) {
-        if (atoken == null) {
-            return;
-        }
+    /**
+     * Returns true if we're done setting up any transitions.
+     */
+    private boolean prepareWindowReplacementTransition(AppWindowToken atoken) {
         atoken.allDrawn = false;
         WindowState replacedWindow = null;
         for (int i = atoken.windows.size() - 1; i >= 0 && replacedWindow == null; i--) {
@@ -2067,7 +2099,7 @@
         if (replacedWindow == null) {
             // We expect to already receive a request to remove the old window. If it did not
             // happen, let's just simply add a window.
-            return;
+            return false;
         }
         // We use the visible frame, because we want the animation to morph the window from what
         // was visible to the user to the final destination of the new window.
@@ -2079,6 +2111,19 @@
         mAppTransition.overridePendingAppTransitionClipReveal(frame.left, frame.top,
                 frame.width(), frame.height());
         executeAppTransition();
+        return true;
+    }
+
+    private void prepareNoneTransitionForRelaunching(AppWindowToken atoken) {
+        // Set up a none-transition and add the app to opening apps, so that the display
+        // unfreeze wait for the apps to be drawn.
+        // Note that if the display unfroze already because app unfreeze timed out,
+        // we don't set up the transition anymore and just let it go.
+        if (mDisplayFrozen && !mOpeningApps.contains(atoken) && atoken.isRelaunching()) {
+            mOpeningApps.add(atoken);
+            prepareAppTransition(AppTransition.TRANSIT_NONE, !ALWAYS_KEEP_CURRENT);
+            executeAppTransition();
+        }
     }
 
     /**
@@ -2139,12 +2184,15 @@
 
     void removeWindowLocked(WindowState win) {
         win.mWindowRemovalAllowed = true;
+        if (DEBUG_ADD_REMOVE) Slog.v(TAG,
+                "removeWindowLocked: " + win + " callers=" + Debug.getCallers(4));
+
         final boolean startingWindow = win.mAttrs.type == TYPE_APPLICATION_STARTING;
         if (startingWindow) {
             if (DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, "Starting window removed " + win);
         }
 
-        if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
+        if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win == mCurrentFocus) Slog.v(
                 TAG_WM, "Remove " + win + " client="
                 + Integer.toHexString(System.identityHashCode(win.mClient.asBinder()))
                 + ", surfaceController=" + win.mWinAnimator.mSurfaceController + " Callers="
@@ -2329,6 +2377,7 @@
                 mTokenMap.remove(token.token);
             } else if (atoken != null) {
                 atoken.firstWindowDrawn = false;
+                atoken.allDrawn = false;
             }
         }
 
@@ -2537,7 +2586,7 @@
 
                     try {
 
-                        win.applyGravityAndUpdateFrame();
+                        win.applyGravityAndUpdateFrame(win.mContainingFrame, win.mDisplayFrame);
                         win.mWinAnimator.computeShownFrameLocked();
 
                         win.mWinAnimator.setSurfaceBoundariesLocked(false);
@@ -2577,7 +2626,6 @@
                         == PackageManager.PERMISSION_GRANTED;
 
         long origId = Binder.clearCallingIdentity();
-
         synchronized(mWindowMap) {
             WindowState win = windowForClientLocked(session, client, false);
             if (win == null) {
@@ -2610,7 +2658,8 @@
                 }
 
                 // Odd choice but less odd than embedding in copyFrom()
-                if ((attrs.flags & WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY) != 0) {
+                if ((attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY)
+                        != 0) {
                     attrs.x = win.mAttrs.x;
                     attrs.y = win.mAttrs.y;
                     attrs.width = win.mAttrs.width;
@@ -2633,7 +2682,7 @@
             if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
                 winAnimator.mAlpha = attrs.alpha;
             }
-            win.setWindowScale(requestedWidth, requestedHeight);
+            win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
 
             boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0;
             final boolean isDefaultDisplay = win.isDefaultDisplay();
@@ -2758,6 +2807,12 @@
                 winAnimator.mReportSurfaceResized = false;
                 result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED;
             }
+            if (mPolicy.isNavBarForcedShownLw(win)) {
+                result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR;
+            }
+            if (!win.isGoneForLayoutLw()) {
+                win.mResizedWhileGone = false;
+            }
             outFrame.set(win.mCompatFrame);
             outOverscanInsets.set(win.mOverscanInsets);
             outContentInsets.set(win.mContentInsets);
@@ -2803,10 +2858,12 @@
         if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
             focusMayChange = isDefaultDisplay;
             win.mAnimatingExit = true;
+            win.mWinAnimator.mAnimating = true;
         } else if (win.mWinAnimator.isAnimating()) {
             // Currently in a hide animation... turn this into
             // an exit.
             win.mAnimatingExit = true;
+            win.mWinAnimator.mAnimating = true;
         } else if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
             // If the wallpaper is currently behind this
             // window, we need to change both of them inside
@@ -2890,9 +2947,9 @@
             }
         }
         final boolean freeformResizing = win.isDragResizing()
-                && win.getResizeMode() == WindowState.DRAG_RESIZE_MODE_FREEFORM;
+                && win.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
         final boolean dockedResizing = win.isDragResizing()
-                && win.getResizeMode() == WindowState.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+                && win.getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER;
         result |= freeformResizing ? WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM : 0;
         result |= dockedResizing ? WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED : 0;
         if (win.isAnimatingWithSavedSurface()) {
@@ -3009,7 +3066,7 @@
                 final int containingWidth = frame.width();
                 final int containingHeight = frame.height();
                 atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
-                        mAppTransition.canSkipFirstFrame());
+                        mAppTransition.canSkipFirstFrame(), mAppTransition.getAppStackClipMode());
             }
         } else {
             atoken.mAppAnimator.clearAnimation();
@@ -3360,7 +3417,8 @@
             }
         }
 
-        if (isStackVisibleLocked(DOCKED_STACK_ID)
+        if ((isStackVisibleLocked(DOCKED_STACK_ID)
+                && !mStackIdToStack.get(DOCKED_STACK_ID).isAdjustedForMinimizedDock())
                 || isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
             // We don't let app affect the system orientation when in freeform or docked mode since
             // they don't occupy the entire display and their request can conflict with other apps.
@@ -3542,7 +3600,7 @@
     }
 
     @Override
-    public void setNewConfiguration(Configuration config) {
+    public int[] setNewConfiguration(Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setNewConfiguration()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3554,16 +3612,30 @@
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
-            onConfigurationChanged();
-            mWindowPlacerLocked.performSurfacePlacement();
+            return onConfigurationChanged();
         }
     }
 
-    private void onConfigurationChanged() {
+    @Override
+    public Rect getBoundsForNewConfiguration(int stackId) {
+        synchronized(mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            final Rect outBounds = new Rect();
+            stack.getBoundsForNewConfiguration(outBounds);
+            return outBounds;
+        }
+    }
+
+    private int[] onConfigurationChanged() {
+        mChangedStackList.clear();
         for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
             final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
-            stack.onConfigurationChanged();
+            if (stack.onConfigurationChanged()) {
+                mChangedStackList.add(stack.mStackId);
+            }
         }
+        return mChangedStackList.isEmpty() ?
+                null : ArrayUtils.convertToIntArray(mChangedStackList);
     }
 
     @Override
@@ -3736,7 +3808,8 @@
         }
         for (final WindowState win : mWindowMap.values()) {
             final Task task = win.getTask();
-            if (task != null && mTmpTaskIds.get(task.mTaskId, -1) != -1) {
+            if (task != null && mTmpTaskIds.get(task.mTaskId, -1) != -1
+                    && task.inFreeformWorkspace()) {
                 final AppWindowToken appToken = win.mAppToken;
                 if (appToken != null && appToken.mAppAnimator != null) {
                     appToken.mAppAnimator.startProlongAnimation(scaleUp ?
@@ -3993,8 +4066,6 @@
                 wAppAnimator.thumbnail.destroy();
             }
             wAppAnimator.thumbnail = tAppAnimator.thumbnail;
-            wAppAnimator.thumbnailX = tAppAnimator.thumbnailX;
-            wAppAnimator.thumbnailY = tAppAnimator.thumbnailY;
             wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
             wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
             tAppAnimator.thumbnail = null;
@@ -4004,10 +4075,8 @@
 
     public void removeAppStartingWindow(IBinder token) {
         synchronized (mWindowMap) {
-            AppWindowToken wtoken = mTokenMap.get(token).appWindowToken;
-            if (wtoken.startingWindow != null) {
-                scheduleRemoveStartingWindowLocked(wtoken);
-            }
+            final AppWindowToken wtoken = mTokenMap.get(token).appWindowToken;
+            scheduleRemoveStartingWindowLocked(wtoken);
         }
     }
 
@@ -4064,7 +4133,7 @@
 
             if (transit != AppTransition.TRANSIT_UNSET) {
                 if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
-                    wtoken.mAppAnimator.animation = null;
+                    wtoken.mAppAnimator.setNullAnimation();
                 }
                 if (applyAnimationLocked(wtoken, lp, transit, visible, isVoiceInteraction)) {
                     delayed = runningAppAnimation = true;
@@ -4082,6 +4151,14 @@
             for (int i = 0; i < windowsCount; i++) {
                 WindowState win = wtoken.allAppWindows.get(i);
                 if (win == wtoken.startingWindow) {
+                    // Starting window that's exiting will be removed when the animation
+                    // finishes. Mark all relevant flags for that finishExit will proceed
+                    // all the way to actually remove it.
+                    if (!visible && win.isVisibleNow() && wtoken.mAppAnimator.isAnimating()) {
+                        win.mAnimatingExit = true;
+                        win.mRemoveOnExit = true;
+                        win.mWindowRemovalAllowed = true;
+                    }
                     continue;
                 }
 
@@ -4174,14 +4251,14 @@
     void updateTokenInPlaceLocked(AppWindowToken wtoken, int transit) {
         if (transit != AppTransition.TRANSIT_UNSET) {
             if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
-                wtoken.mAppAnimator.animation = null;
+                wtoken.mAppAnimator.setNullAnimation();
             }
             applyAnimationLocked(wtoken, null, transit, false, false);
         }
     }
 
     @Override
-    public void notifyAppStopped(IBinder token) {
+    public void notifyAppStopped(IBinder token, boolean stopped) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "notifyAppStopped()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -4194,7 +4271,7 @@
                 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
                 return;
             }
-            wtoken.notifyAppStopped();
+            wtoken.notifyAppStopped(stopped);
         }
     }
 
@@ -4231,8 +4308,34 @@
                 wtoken.appDied = false;
                 wtoken.removeAllWindows();
             } else if (visible) {
+                if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
+                    // Add the app mOpeningApps if transition is unset but ready. This means
+                    // we're doing a screen freeze, and the unfreeze will wait for all opening
+                    // apps to be ready.
+                    mOpeningApps.add(wtoken);
+                }
+                wtoken.startingMoved = false;
+                // If the token is currently hidden (should be the common case), or has been
+                // stopped, then we need to set up to wait for its windows to be ready.
+                if (wtoken.hidden || wtoken.mAppStopped) {
+                    wtoken.allDrawn = false;
+                    wtoken.deferClearAllDrawn = false;
+                    wtoken.waitingToShow = true;
+
+                    if (wtoken.clientHidden) {
+                        // In the case where we are making an app visible
+                        // but holding off for a transition, we still need
+                        // to tell the client to make its windows visible so
+                        // they get drawn.  Otherwise, we will wait on
+                        // performing the transition until all windows have
+                        // been drawn, they never will be, and we are sad.
+                        wtoken.clientHidden = false;
+                        wtoken.sendAppVisibilityToClients();
+                    }
+                }
+                if (DEBUG_ADD_REMOVE) Slog.v(
+                        TAG_WM, "No longer Stopped: " + wtoken);
                 wtoken.mAppStopped = false;
-                wtoken.setWindowsExiting(false);
             }
 
             // If we are preparing an app transition, then delay changing
@@ -4242,6 +4345,11 @@
                 // animation is going on (in this case an application transition). If the animation
                 // was transferred from another application/animator, no dummy animator should be
                 // created since an animation is already in progress.
+                if (wtoken.mAppAnimator.usingTransferredAnimation
+                        && wtoken.mAppAnimator.animation == null) {
+                    Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
+                            + ", using null transfered animation!");
+                }
                 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
                         (!wtoken.startingDisplayed || mSkipAppTransitionAnimation)) {
                     if (DEBUG_APP_TRANSITIONS) Slog.v(
@@ -4251,30 +4359,8 @@
                 wtoken.inPendingTransaction = true;
                 if (visible) {
                     mOpeningApps.add(wtoken);
-                    wtoken.startingMoved = false;
                     wtoken.mEnteringAnimation = true;
-
-                    // If the token is currently hidden (should be the
-                    // common case), then we need to set up to wait for
-                    // its windows to be ready.
-                    if (wtoken.hidden) {
-                        wtoken.allDrawn = false;
-                        wtoken.deferClearAllDrawn = false;
-                        wtoken.waitingToShow = true;
-
-                        if (wtoken.clientHidden) {
-                            // In the case where we are making an app visible
-                            // but holding off for a transition, we still need
-                            // to tell the client to make its windows visible so
-                            // they get drawn.  Otherwise, we will wait on
-                            // performing the transition until all windows have
-                            // been drawn, they never will be, and we are sad.
-                            wtoken.clientHidden = false;
-                            wtoken.sendAppVisibilityToClients();
-                        }
-                    }
                 } else {
-                    wtoken.setWindowsExiting(true);
                     mClosingApps.add(wtoken);
                     wtoken.mEnteringAnimation = false;
                 }
@@ -4486,17 +4572,30 @@
     }
 
     void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) {
+        if (wtoken == null) {
+            return;
+        }
         if (mH.hasMessages(H.REMOVE_STARTING, wtoken)) {
             // Already scheduled.
             return;
         }
-        if (wtoken != null && wtoken.startingWindow != null) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1) +
-                    ": Schedule remove starting " + wtoken + (wtoken != null ?
-                    " startingWindow=" + wtoken.startingWindow : ""));
-            Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
-            mH.sendMessage(m);
+
+        if (wtoken.startingWindow == null) {
+            if (wtoken.startingData != null) {
+                // Starting window has not been added yet, but it is scheduled to be added.
+                // Go ahead and cancel the request.
+                if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+                        "Clearing startingData for token=" + wtoken);
+                wtoken.startingData = null;
+            }
+            return;
         }
+
+        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1) +
+                ": Schedule remove starting " + wtoken + (wtoken != null ?
+                " startingWindow=" + wtoken.startingWindow : ""));
+        Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
+        mH.sendMessage(m);
     }
 
     void dumpAppTokensLocked() {
@@ -4943,6 +5042,23 @@
         }
     }
 
+    /**
+     * Puts a specific task into docked drag resizing mode. See {@link DragResizeMode}.
+     *
+     * @param taskId The id of the task to put into drag resize mode.
+     * @param resizing Whether to put the task into drag resize mode.
+     */
+    public void setTaskDockedResizing(int taskId, boolean resizing) {
+        synchronized (mWindowMap) {
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null) {
+                throw new IllegalArgumentException("setTaskDockedResizing: taskId " + taskId
+                        + " not found.");
+            }
+            task.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+        }
+    }
+
     public void scrollTask(int taskId, Rect bounds) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -5137,18 +5253,16 @@
     }
 
     @Override
-    public void keyguardGoingAway(boolean disableWindowAnimations,
-            boolean keyguardGoingToNotificationShade) {
+    public void keyguardGoingAway(int flags) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
-        if (DEBUG_KEYGUARD) Slog.d(TAG_WM, "keyguardGoingAway: disableWinAnim="
-                + disableWindowAnimations + " kgToNotifShade=" + keyguardGoingToNotificationShade);
+        if (DEBUG_KEYGUARD) Slog.d(TAG_WM,
+                "keyguardGoingAway: flags=0x" + Integer.toHexString(flags));
         synchronized (mWindowMap) {
             mAnimator.mKeyguardGoingAway = true;
-            mAnimator.mKeyguardGoingAwayToNotificationShade = keyguardGoingToNotificationShade;
-            mAnimator.mKeyguardGoingAwayDisableWindowAnimations = disableWindowAnimations;
+            mAnimator.mKeyguardGoingAwayFlags = flags;
             mWindowPlacerLocked.requestTraversal();
         }
     }
@@ -5691,7 +5805,7 @@
         if (mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_windowEnableCircularEmulatorDisplayOverlay)
                 && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false)
-                && Build.HARDWARE.contains("goldfish")) {
+                && Build.IS_EMULATOR) {
             mH.sendMessage(mH.obtainMessage(H.SHOW_EMULATOR_DISPLAY_OVERLAY));
         }
     }
@@ -6001,7 +6115,7 @@
                         int bottom = wf.bottom - cr.bottom;
                         frame.union(left, top, right, bottom);
                         ws.getVisibleBounds(stackBounds);
-                        if (!frame.intersect(stackBounds)) {
+                        if (!Rect.intersects(frame, stackBounds)) {
                             // Set frame empty if there's no intersection.
                             frame.setEmpty();
                         }
@@ -7308,6 +7422,33 @@
         }
     }
 
+    private void adjustForImeIfNeeded(final DisplayContent displayContent) {
+        final WindowState imeWin = mInputMethodWindow;
+        final TaskStack focusedStack =
+                mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+        final boolean dockVisible = isStackVisibleLocked(DOCKED_STACK_ID);
+        if (imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
+                && dockVisible
+                && focusedStack != null
+                && focusedStack.getDockSide() == DOCKED_BOTTOM){
+            final ArrayList<TaskStack> stacks = displayContent.getStacks();
+            for (int i = stacks.size() - 1; i >= 0; --i) {
+                final TaskStack stack = stacks.get(i);
+                if (stack.isVisibleLocked()) {
+                    stack.setAdjustedForIme(imeWin);
+                }
+            }
+            displayContent.mDividerControllerLocked.setAdjustedForIme(true, true);
+        } else {
+            final ArrayList<TaskStack> stacks = displayContent.getStacks();
+            for (int i = stacks.size() - 1; i >= 0; --i) {
+                final TaskStack stack = stacks.get(i);
+                stack.resetAdjustedForIme(!dockVisible);
+            }
+            displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible);
+        }
+    }
+
     // -------------------------------------------------------------
     // Drag and drop
     // -------------------------------------------------------------
@@ -7437,6 +7578,35 @@
         return mCurrentFocus;
     }
 
+    private void showAuditSafeModeNotification() {
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
+                new Intent(Intent.ACTION_VIEW,
+                           Uri.parse("https://support.google.com/nexus/answer/2852139")), 0);
+
+        String title = mContext.getString(R.string.audit_safemode_notification);
+
+        Notification notification = new Notification.Builder(mContext)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
+                .setWhen(0)
+                .setOngoing(true)
+                .setTicker(title)
+                .setLocalOnly(true)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(mContext.getString(R.string.audit_safemode_notification_details))
+                .setContentIntent(pendingIntent)
+                .build();
+
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+
+        notificationManager.notifyAsUser(null, R.string.audit_safemode_notification, notification,
+                UserHandle.ALL);
+    }
+
     public boolean detectSafeMode() {
         if (!mInputMonitor.waitForInputDevicesReady(
                 INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
@@ -7445,6 +7615,11 @@
                    + " milliseconds before attempting to detect safe mode.");
         }
 
+        if (Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.SAFE_BOOT_DISALLOWED, 0) != 0) {
+            return false;
+        }
+
         int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
                 KeyEvent.KEYCODE_MENU);
         int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
@@ -7458,8 +7633,23 @@
                 || volumeDownState > 0;
         try {
             if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
-                mSafeMode = true;
-                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
+                int auditSafeMode = SystemProperties.getInt(ShutdownThread.AUDIT_SAFEMODE_PROPERTY, 0);
+
+                if (auditSafeMode == 0) {
+                    mSafeMode = true;
+                    SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
+                } else {
+                    // stay in safe mode until we have updated to a newer build
+                    int buildDate = SystemProperties.getInt(PROPERTY_BUILD_DATE_UTC, 0);
+
+                    if (auditSafeMode >= buildDate) {
+                        mSafeMode = true;
+                        showAuditSafeModeNotification();
+                    } else {
+                        SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
+                        SystemProperties.set(ShutdownThread.AUDIT_SAFEMODE_PROPERTY, "");
+                    }
+                }
             }
         } catch (IllegalArgumentException e) {
         }
@@ -7581,6 +7771,11 @@
 
         public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
 
+        public static final int NOTIFY_APP_TRANSITION_STARTING = 47;
+        public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48;
+        public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
+        public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
+
         /**
          * Used to denote that an integer field in a message will not be used.
          */
@@ -8118,30 +8313,8 @@
                 case UPDATE_DOCKED_STACK_DIVIDER: {
                     synchronized (mWindowMap) {
                         final DisplayContent displayContent = getDefaultDisplayContentLocked();
-
                         displayContent.getDockedDividerController().reevaluateVisibility(false);
-
-                        final WindowState imeWin = mInputMethodWindow;
-                        final TaskStack focusedStack =
-                                mCurrentFocus != null ? mCurrentFocus.getStack() : null;
-                        if (imeWin != null && imeWin.isVisibleNow()
-                                && isStackVisibleLocked(DOCKED_STACK_ID)
-                                && focusedStack != null
-                                && focusedStack.getDockSide() == DOCKED_BOTTOM){
-                            final ArrayList<TaskStack> stacks = displayContent.getStacks();
-                            for (int i = stacks.size() - 1; i >= 0; --i) {
-                                final TaskStack stack = stacks.get(i);
-                                if (stack.isVisibleLocked()) {
-                                    stack.setAdjustedForIme(imeWin);
-                                }
-                            }
-                        } else {
-                            final ArrayList<TaskStack> stacks = displayContent.getStacks();
-                            for (int i = stacks.size() - 1; i >= 0; --i) {
-                                final TaskStack stack = stacks.get(i);
-                                stack.resetAdjustedForIme();
-                            }
-                        }
+                        adjustForImeIfNeeded(displayContent);
                     }
                 }
                 break;
@@ -8155,8 +8328,8 @@
                 break;
                 case RESIZE_STACK: {
                     try {
-                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false,
-                                false);
+                        mActivityManager.resizeStack(
+                                msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false, false, -1);
                     } catch (RemoteException e) {
                         // This will not happen since we are in the same process.
                     }
@@ -8164,7 +8337,7 @@
                 break;
                 case SHOW_NON_RESIZEABLE_DOCK_TOAST: {
                     final Toast toast = Toast.makeText(
-                            mContext, (String) msg.obj, Toast.LENGTH_LONG);
+                            mContext, (String) msg.obj, Toast.LENGTH_SHORT);
                     final int gravity = toast.getGravity();
                     final int xOffset = toast.getXOffset() + msg.arg1;
                     final int yOffset = toast.getYOffset() + msg.arg2;
@@ -8178,6 +8351,21 @@
                         token.clearTimedoutReplacesLocked();
                     }
                 }
+                case NOTIFY_APP_TRANSITION_STARTING: {
+                    mAmInternal.notifyAppTransitionStarting(msg.arg1);
+                }
+                break;
+                case NOTIFY_APP_TRANSITION_CANCELLED: {
+                    mAmInternal.notifyAppTransitionCancelled();
+                }
+                break;
+                case NOTIFY_APP_TRANSITION_FINISHED: {
+                    mAmInternal.notifyAppTransitionFinished();
+                }
+                break;
+                case NOTIFY_STARTING_WINDOW_DRAWN: {
+                    mAmInternal.notifyStartingWindowDrawn();
+                }
                 break;
             }
             if (DEBUG_WINDOW_TRACE) {
@@ -8727,10 +8915,10 @@
         i -= lastBelow;
         if (i != numRemoved) {
             displayContent.layoutNeeded = true;
-            Slog.w(TAG_WM, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
-                    numRemoved + " windows but added " + i,
-                    new RuntimeException("here").fillInStackTrace());
-            for (i=0; i<numRemoved; i++) {
+            Slog.w(TAG_WM, "On display=" + displayContent.getDisplayId() + " Rebuild removed "
+                    + numRemoved + " windows but added " + i + " rebuildAppWindowListLocked() "
+                    + " callers=" + Debug.getCallers(10));
+            for (i = 0; i < numRemoved; i++) {
                 WindowState ws = mRebuildTmp[i];
                 if (ws.mRebuilding) {
                     StringWriter sw = new StringWriter();
@@ -8873,7 +9061,7 @@
                                 + ", mDrawState=DRAW_PENDING in " + w
                                 + ", surfaceController " + winAnimator.mSurfaceController);
                     }
-                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
+                    winAnimator.mDrawState = DRAW_PENDING;
                     if (w.mAppToken != null) {
                         w.mAppToken.allDrawn = false;
                         w.mAppToken.deferClearAllDrawn = false;
@@ -9227,6 +9415,10 @@
             return;
         }
 
+        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
+                "startFreezingDisplayLocked: inTransaction=" + inTransaction
+                + " exitAnim=" + exitAnim + " enterAnim=" + enterAnim
+                + " called by " + Debug.getCallers(8));
         mScreenFrozenLock.acquire();
 
         mDisplayFrozen = true;
@@ -9297,6 +9489,9 @@
             return;
         }
 
+        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
+                "stopFreezingDisplayLocked: Unfreezing now");
+
         mDisplayFrozen = false;
         mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
         StringBuilder sb = new StringBuilder(128);
@@ -9493,13 +9688,37 @@
         }
     }
 
+    private static final class HideNavInputConsumer extends InputConsumerImpl
+            implements WindowManagerPolicy.InputConsumer {
+        private final InputEventReceiver mInputEventReceiver;
+
+        HideNavInputConsumer(WindowManagerService service, Looper looper,
+                             InputEventReceiver.Factory inputEventReceiverFactory) {
+            super(service, "input consumer", null);
+            mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
+                    mClientChannel, looper);
+        }
+
+        @Override
+        public void dismiss() {
+            if (mService.removeInputConsumer()) {
+                synchronized (mService.mWindowMap) {
+                    mInputEventReceiver.dispose();
+                    disposeChannelsLw();
+                }
+            }
+        }
+    }
+
     @Override
-    public InputConsumerImpl addInputConsumer(Looper looper,
+    public WindowManagerPolicy.InputConsumer addInputConsumer(Looper looper,
             InputEventReceiver.Factory inputEventReceiverFactory) {
         synchronized (mWindowMap) {
-            mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory);
+            HideNavInputConsumer inputConsumerImpl = new HideNavInputConsumer(
+                    this, looper, inputEventReceiverFactory);
+            mInputConsumer = inputConsumerImpl;
             mInputMonitor.updateInputWindowsLw(true);
-            return mInputConsumer;
+            return inputConsumerImpl;
         }
     }
 
@@ -9514,6 +9733,24 @@
         }
     }
 
+    public void createWallpaperInputConsumer(InputChannel inputChannel) {
+        synchronized (mWindowMap) {
+            mWallpaperInputConsumer = new InputConsumerImpl(this, "wallpaper input", inputChannel);
+            mWallpaperInputConsumer.mWindowHandle.hasWallpaper = true;
+            mInputMonitor.updateInputWindowsLw(true);
+        }
+    }
+
+    public void removeWallpaperInputConsumer() {
+        synchronized (mWindowMap) {
+            if (mWallpaperInputConsumer != null) {
+                mWallpaperInputConsumer.disposeChannelsLw();
+                mWallpaperInputConsumer = null;
+                mInputMonitor.updateInputWindowsLw(true);
+            }
+        }
+    }
+
     @Override
     public boolean hasNavigationBar() {
         return mPolicy.hasNavigationBar();
@@ -9581,8 +9818,8 @@
     public void notifyAppRelaunching(IBinder token) {
         synchronized (mWindowMap) {
             AppWindowToken appWindow = findAppWindowToken(token);
-            if (canFreezeBounds(appWindow)) {
-                appWindow.freezeBounds();
+            if (appWindow != null) {
+                appWindow.startRelaunching();
             }
         }
     }
@@ -9590,20 +9827,12 @@
     public void notifyAppRelaunchingFinished(IBinder token) {
         synchronized (mWindowMap) {
             AppWindowToken appWindow = findAppWindowToken(token);
-            if (canFreezeBounds(appWindow)) {
-                appWindow.unfreezeBounds();
+            if (appWindow != null) {
+                appWindow.finishRelaunching();
             }
         }
     }
 
-    private boolean canFreezeBounds(AppWindowToken appWindow) {
-
-        // For freeform windows, we can't freeze the bounds at the moment because this would make
-        // the resizing unresponsive.
-        return appWindow != null && appWindow.mTask != null
-                && !appWindow.mTask.inFreeformWorkspace();
-    }
-
     @Override
     public int getDockedDividerInsetsLw() {
         return getDefaultDisplayContentLocked().getDockedDividerController().getContentInsets();
@@ -9825,6 +10054,9 @@
                     pw.print(mLastFinishedFreezeSource);
                 }
                 pw.println();
+
+        mInputMonitor.dump(pw, "  ");
+
         if (dumpAll) {
             pw.print("  mSystemDecorLayer="); pw.print(mSystemDecorLayer);
                     pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
@@ -10356,6 +10588,15 @@
     }
 
     @Override
+    public void setDockedStackDividerTouchRegion(Rect touchRegion) {
+        synchronized (mWindowMap) {
+            getDefaultDisplayContentLocked().getDockedDividerController()
+                    .setTouchRegion(touchRegion);
+            setFocusTaskRegionLocked();
+        }
+    }
+
+    @Override
     public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
         synchronized (mWindowMap) {
             getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
@@ -10363,7 +10604,7 @@
         }
     }
 
-    public void animateResizePinnedStack(final Rect bounds) {
+    public void animateResizePinnedStack(final Rect bounds, final int animationDuration) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
             if (stack == null) {
@@ -10375,7 +10616,8 @@
             UiThread.getHandler().post(new Runnable() {
                 @Override
                 public void run() {
-                    mBoundsAnimationController.animateBounds(stack, originalBounds, bounds);
+                    mBoundsAnimationController.animateBounds(
+                            stack, originalBounds, bounds, animationDuration);
                 }
             });
         }
@@ -10412,9 +10654,12 @@
     }
 
     @Override
-    public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+    public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
         try {
-            getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver);
+            WindowState focusedWindow = getFocusedWindow();
+            if (focusedWindow != null && focusedWindow.mClient != null) {
+                getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver, deviceId);
+            }
         } catch (RemoteException e) {
         }
     }
@@ -10555,6 +10800,16 @@
         }
     }
 
+    public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
+            throws RemoteException {
+        if (!checkCallingPermission(Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
+                "registerShortcutKey")) {
+            throw new SecurityException(
+                    "Requires REGISTER_WINDOW_MANAGER_LISTENERS permission");
+        }
+        mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
+    }
+
     private final class LocalService extends WindowManagerInternal {
         @Override
         public void requestTraversalFromDisplayManager() {
@@ -10576,6 +10831,19 @@
         }
 
         @Override
+        public void getMagnificationRegions(@NonNull Region outMagnified,
+                @NonNull Region outAvailable) {
+            synchronized (mWindowMap) {
+                if (mAccessibilityController != null) {
+                    mAccessibilityController.getMagnificationRegionsLocked(
+                            outMagnified, outAvailable);
+                } else {
+                    throw new IllegalStateException("Magnification callbacks not set!");
+                }
+            }
+        }
+
+        @Override
         public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
             synchronized (mWindowMap) {
                 WindowState windowState = mWindowMap.get(windowToken);
@@ -10663,6 +10931,7 @@
 
         @Override
         public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
+            boolean allWindowsDrawn = false;
             synchronized (mWindowMap) {
                 mWaitingForDrawnCallback = callback;
                 final WindowList windows = getDefaultWindowListLocked();
@@ -10671,7 +10940,7 @@
                     final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
                     if (win.isVisibleLw()
                             && (win.mAppToken != null || isForceHiding)) {
-                        win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
+                        win.mWinAnimator.mDrawState = DRAW_PENDING;
                         // Force add to mResizingWindows.
                         win.mLastContentInsets.set(-1, -1, -1, -1);
                         mWaitingForDrawn.add(win);
@@ -10683,13 +10952,16 @@
                     }
                 }
                 mWindowPlacerLocked.requestTraversal();
+                mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
+                if (mWaitingForDrawn.isEmpty()) {
+                    allWindowsDrawn = true;
+                } else {
+                    mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
+                    checkDrawnWindowsLocked();
+                }
             }
-            mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
-            if (mWaitingForDrawn.isEmpty()) {
+            if (allWindowsDrawn) {
                 callback.run();
-            } else {
-                mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
-                checkDrawnWindowsLocked();
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f30c8d3..1eca4d4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -71,6 +71,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -87,6 +88,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -101,6 +104,10 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 class WindowList extends ArrayList<WindowState> {
+    WindowList() {}
+    WindowList(WindowList windowList) {
+        super(windowList);
+    }
 }
 
 /**
@@ -119,9 +126,6 @@
     // to capture touch events in that area.
     static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
 
-    static final int DRAG_RESIZE_MODE_FREEFORM = 0;
-    static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
-
     static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
 
     final WindowManagerService mService;
@@ -184,6 +188,10 @@
 
     private Configuration mConfiguration = Configuration.EMPTY;
     private Configuration mOverrideConfig = Configuration.EMPTY;
+    // Represents the changes from our override configuration applied
+    // to the global configuration. This is the only form of configuration
+    // which is suitable for delivery to the client.
+    private Configuration mMergedConfiguration = new Configuration();
     // Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
     // Used only on {@link #TYPE_KEYGUARD}.
     private boolean mConfigHasChanged;
@@ -320,6 +328,8 @@
      */
     final Rect mInsetFrame = new Rect();
 
+    private static final Rect sTmpRect = new Rect();
+
     boolean mContentChanged;
 
     // If a window showing a wallpaper: the requested offset for the
@@ -434,9 +444,9 @@
     // If not null, the window that will be used to replace the old one. This is being set when
     // the window is added and unset when this window reports its first draw.
     WindowState mReplacingWindow = null;
-
     // Whether this window is being moved via the resize API
     boolean mMovedByResize;
+
     /**
      * Wake lock for drawing.
      * Even though it's slightly more expensive to do so, we will use a separate wake lock
@@ -448,6 +458,16 @@
 
     final private Rect mTmpRect = new Rect();
 
+    /**
+     * See {@link #notifyMovedInStack}.
+     */
+    private boolean mJustMovedInStack;
+
+    /**
+     * Whether the window was resized by us while it was gone for layout.
+     */
+    boolean mResizedWhileGone = false;
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, final DisplayContent displayContent) {
@@ -611,6 +631,20 @@
         return mAttrs.packageName;
     }
 
+    /**
+     * Subtracts the insets calculated by intersecting {@param layoutFrame} with {@param insetFrame}
+     * from {@param frame}. In other words, it applies the insets that would result if
+     * {@param frame} would be shifted to {@param layoutFrame} and then applying the insets from
+     * {@param insetFrame}.
+     */
+    private void subtractInsets(Rect frame, Rect layoutFrame, Rect insetFrame) {
+        final int left = Math.max(0, insetFrame.left - layoutFrame.left);
+        final int top = Math.max(0, insetFrame.top - layoutFrame.top);
+        final int right = Math.max(0, layoutFrame.right - insetFrame.right);
+        final int bottom = Math.max(0, layoutFrame.bottom - insetFrame.bottom);
+        frame.inset(left, top, right, bottom);
+    }
+
     @Override
     public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf,
             Rect osf) {
@@ -624,18 +658,39 @@
         mHaveFrame = true;
 
         final Task task = getTask();
-        final boolean fullscreenTask = task == null || task.isFullscreen();
-        final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
+        final boolean fullscreenTask = !isInMultiWindowMode();
+        final boolean windowsAreFloating = task != null && task.isFloating();
 
-        if (fullscreenTask || (isChildWindow()
-                && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) {
+        // If the task has temp inset bounds set, we have to make sure all its windows uses
+        // the temp inset frame. Otherwise different display frames get applied to the main
+        // window and the child window, making them misaligned.
+        if (fullscreenTask) {
+            mInsetFrame.setEmpty();
+        } else {
+            task.getTempInsetBounds(mInsetFrame);
+        }
+
+        // Denotes the actual frame used to calculate the insets and to perform the layout. When
+        // resizing in docked mode, we'd like to freeze the layout, so we also need to freeze the
+        // insets temporarily. By the notion of a task having a different layout frame, we can
+        // achieve that while still moving the task around.
+        final Rect layoutContainingFrame;
+        final Rect layoutDisplayFrame;
+
+        // The offset from the layout containing frame to the actual containing frame.
+        final int layoutXDiff;
+        final int layoutYDiff;
+        if (mInsetFrame.isEmpty()  && (fullscreenTask
+                || layoutInParentFrame())) {
             // We use the parent frame as the containing frame for fullscreen and child windows
             mContainingFrame.set(pf);
             mDisplayFrame.set(df);
-            mInsetFrame.setEmpty();
+            layoutDisplayFrame = df;
+            layoutContainingFrame = pf;
+            layoutXDiff = 0;
+            layoutYDiff = 0;
         } else {
             task.getBounds(mContainingFrame);
-            task.getTempInsetBounds(mInsetFrame);
             if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) {
 
                 // If the bounds are frozen, we still want to translate the window freely and only
@@ -645,21 +700,37 @@
                 mContainingFrame.bottom = mContainingFrame.top + frozen.height();
             }
             final WindowState imeWin = mService.mInputMethodWindow;
-            if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
-                    && mContainingFrame.bottom > cf.bottom) {
-                // IME is up and obscuring this window. Adjust the window position so it is visible.
-                mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+            // IME is up and obscuring this window. Adjust the window position so it is visible.
+            if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this) {
+                    if (windowsAreFloating && mContainingFrame.bottom > cf.bottom) {
+                        // In freeform we want to move the top up directly.
+                        // TODO: Investigate why this is cf not pf.
+                        mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+                    } else if (mContainingFrame.bottom > pf.bottom) {
+                        // But in docked we want to behave like fullscreen
+                        // and behave as if the task were given smaller bounds
+                        // for the purposes of layout.
+                        mContainingFrame.bottom = pf.bottom;
+                    }
             }
 
-            if (freeformWorkspace) {
-                // In free form mode we have only to set the rectangle if it wasn't set already. No
-                // need to intersect it with the (visible) "content frame" since it is allowed to
-                // be outside the visible desktop.
+            if (windowsAreFloating) {
+                // In floating modes (e.g. freeform, pinned) we have only to set the rectangle
+                // if it wasn't set already. No need to intersect it with the (visible)
+                // "content frame" since it is allowed to be outside the visible desktop.
                 if (mContainingFrame.isEmpty()) {
                     mContainingFrame.set(cf);
                 }
             }
             mDisplayFrame.set(mContainingFrame);
+            layoutXDiff = !mInsetFrame.isEmpty() ? mInsetFrame.left - mContainingFrame.left : 0;
+            layoutYDiff = !mInsetFrame.isEmpty() ? mInsetFrame.top - mContainingFrame.top : 0;
+            layoutContainingFrame = !mInsetFrame.isEmpty() ? mInsetFrame : mContainingFrame;
+            subtractInsets(mDisplayFrame, layoutContainingFrame, df);
+            subtractInsets(mContainingFrame, layoutContainingFrame, pf);
+            subtractInsets(mInsetFrame, layoutContainingFrame, pf);
+            layoutDisplayFrame = df;
+            layoutDisplayFrame.intersect(layoutContainingFrame);
         }
 
         final int pw = mContainingFrame.width();
@@ -690,7 +761,11 @@
         final int fw = mFrame.width();
         final int fh = mFrame.height();
 
-        applyGravityAndUpdateFrame();
+        applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame);
+
+        // Offset the actual frame by the amount layout frame is off.
+        mFrame.offset(-layoutXDiff, -layoutYDiff);
+        mCompatFrame.offset(-layoutXDiff, -layoutYDiff);
 
         // Calculate the outsets before the content frame gets shrinked to the window frame.
         if (hasOutsets) {
@@ -702,15 +777,9 @@
             mOutsets.set(0, 0, 0, 0);
         }
 
-        // Denotes the actual frame used to calculate the insets. When resizing in docked mode,
-        // we'd like to freeze the layout, so we also need to freeze the insets temporarily. By the
-        // notion of a task having a different inset frame, we can achieve that while still moving
-        // the task around.
-        final Rect frame = !mInsetFrame.isEmpty() ? mInsetFrame : mFrame;
-
         // Make sure the content and visible frames are inside of the
         // final window frame.
-        if (freeformWorkspace && !mFrame.isEmpty()) {
+        if (windowsAreFloating && !mFrame.isEmpty()) {
             // Keep the frame out of the blocked system area, limit it in size to the content area
             // and make sure that there is always a minimum visible so that the user can drag it
             // into a usable area..
@@ -730,45 +799,35 @@
             mVisibleFrame.set(mContentFrame);
             mStableFrame.set(mContentFrame);
         } else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
-            if (isVisibleLw() || mWinAnimator.isAnimating()) {
-                // We don't adjust the dock divider frame for reasons other than performance. The
-                // real reason is that if it gets adjusted before it is shown for the first time,
-                // it would get size (0, 0). This causes a problem when we finally show the dock
-                // divider and try to draw to it. We do set the surface size at that moment to
-                // the correct size, but it's too late for the Surface Flinger to make it
-                // available for view rendering and as a result the renderer receives size 1, 1.
-                // This way we just keep the divider at the original size and Surface Flinger
-                // will return the correct value to the renderer.
-                mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
-                mContentFrame.set(mFrame);
-                if (!mFrame.equals(mLastFrame)) {
-                    mMovedByResize = true;
-                }
+            mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
+            mContentFrame.set(mFrame);
+            if (!mFrame.equals(mLastFrame)) {
+                mMovedByResize = true;
             }
         } else {
-            mContentFrame.set(Math.max(mContentFrame.left, frame.left),
-                    Math.max(mContentFrame.top, frame.top),
-                    Math.min(mContentFrame.right, frame.right),
-                    Math.min(mContentFrame.bottom, frame.bottom));
+            mContentFrame.set(Math.max(mContentFrame.left, layoutContainingFrame.left),
+                    Math.max(mContentFrame.top, layoutContainingFrame.top),
+                    Math.min(mContentFrame.right, layoutContainingFrame.right),
+                    Math.min(mContentFrame.bottom, layoutContainingFrame.bottom));
 
-            mVisibleFrame.set(Math.max(mVisibleFrame.left, frame.left),
-                    Math.max(mVisibleFrame.top, frame.top),
-                    Math.min(mVisibleFrame.right, frame.right),
-                    Math.min(mVisibleFrame.bottom, frame.bottom));
+            mVisibleFrame.set(Math.max(mVisibleFrame.left, layoutContainingFrame.left),
+                    Math.max(mVisibleFrame.top, layoutContainingFrame.top),
+                    Math.min(mVisibleFrame.right, layoutContainingFrame.right),
+                    Math.min(mVisibleFrame.bottom, layoutContainingFrame.bottom));
 
-            mStableFrame.set(Math.max(mStableFrame.left, frame.left),
-                    Math.max(mStableFrame.top, frame.top),
-                    Math.min(mStableFrame.right, frame.right),
-                    Math.min(mStableFrame.bottom, frame.bottom));
+            mStableFrame.set(Math.max(mStableFrame.left, layoutContainingFrame.left),
+                    Math.max(mStableFrame.top, layoutContainingFrame.top),
+                    Math.min(mStableFrame.right, layoutContainingFrame.right),
+                    Math.min(mStableFrame.bottom, layoutContainingFrame.bottom));
         }
 
-        if (!inFreeformWorkspace()) {
-            // Freeform windows can be positioned outside of the display frame, but that is not a
-            // reason to provide them with overscan insets.
-            mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
-                    Math.max(mOverscanFrame.top - frame.top, 0),
-                    Math.max(frame.right - mOverscanFrame.right, 0),
-                    Math.max(frame.bottom - mOverscanFrame.bottom, 0));
+        if (fullscreenTask && !windowsAreFloating) {
+            // Windows that are not fullscreen can be positioned outside of the display frame,
+            // but that is not a reason to provide them with overscan insets.
+            mOverscanInsets.set(Math.max(mOverscanFrame.left - layoutContainingFrame.left, 0),
+                    Math.max(mOverscanFrame.top - layoutContainingFrame.top, 0),
+                    Math.max(layoutContainingFrame.right - mOverscanFrame.right, 0),
+                    Math.max(layoutContainingFrame.bottom - mOverscanFrame.bottom, 0));
         }
 
         if (mAttrs.type == TYPE_DOCK_DIVIDER) {
@@ -784,39 +843,37 @@
             mContentInsets.setEmpty();
             mVisibleInsets.setEmpty();
         } else {
-            mContentInsets.set(mContentFrame.left - frame.left,
-                    mContentFrame.top - frame.top,
-                    frame.right - mContentFrame.right,
-                    frame.bottom - mContentFrame.bottom);
+            getDisplayContent().getLogicalDisplayRect(mTmpRect);
+            // Override right and/or bottom insets in case if the frame doesn't fit the screen in
+            // non-fullscreen mode.
+            boolean overrideRightInset = !fullscreenTask && mFrame.right > mTmpRect.right;
+            boolean overrideBottomInset = !fullscreenTask && mFrame.bottom > mTmpRect.bottom;
+            mContentInsets.set(mContentFrame.left - layoutContainingFrame.left,
+                    mContentFrame.top - layoutContainingFrame.top,
+                    overrideRightInset ? mTmpRect.right - mContentFrame.right
+                            : layoutContainingFrame.right - mContentFrame.right,
+                    overrideBottomInset ? mTmpRect.bottom - mContentFrame.bottom
+                            : layoutContainingFrame.bottom - mContentFrame.bottom);
 
-            mVisibleInsets.set(mVisibleFrame.left - frame.left,
-                    mVisibleFrame.top - frame.top,
-                    frame.right - mVisibleFrame.right,
-                    frame.bottom - mVisibleFrame.bottom);
+            mVisibleInsets.set(mVisibleFrame.left - layoutContainingFrame.left,
+                    mVisibleFrame.top - layoutContainingFrame.top,
+                    overrideRightInset ? mTmpRect.right - mVisibleFrame.right
+                            : layoutContainingFrame.right - mVisibleFrame.right,
+                    overrideBottomInset ? mTmpRect.bottom - mVisibleFrame.bottom
+                            : layoutContainingFrame.bottom - mVisibleFrame.bottom);
 
-            mStableInsets.set(Math.max(mStableFrame.left - frame.left, 0),
-                    Math.max(mStableFrame.top - frame.top, 0),
-                    Math.max(frame.right - mStableFrame.right, 0),
-                    Math.max(frame.bottom - mStableFrame.bottom, 0));
+            mStableInsets.set(Math.max(mStableFrame.left - layoutContainingFrame.left, 0),
+                    Math.max(mStableFrame.top - layoutContainingFrame.top, 0),
+                    overrideRightInset ? Math.max(mTmpRect.right - mStableFrame.right, 0)
+                            : Math.max(layoutContainingFrame.right - mStableFrame.right, 0),
+                    overrideBottomInset ? Math.max(mTmpRect.bottom - mStableFrame.bottom, 0)
+                            :  Math.max(layoutContainingFrame.bottom - mStableFrame.bottom, 0));
         }
 
-        if (!mInsetFrame.isEmpty()) {
-            mContentFrame.set(mFrame);
-            mContentFrame.top += mContentInsets.top;
-            mContentFrame.bottom += mContentInsets.bottom;
-            mContentFrame.left += mContentInsets.left;
-            mContentFrame.right += mContentInsets.right;
-            mVisibleFrame.set(mFrame);
-            mVisibleFrame.top += mVisibleInsets.top;
-            mVisibleFrame.bottom += mVisibleInsets.bottom;
-            mVisibleFrame.left += mVisibleInsets.left;
-            mVisibleFrame.right += mVisibleInsets.right;
-            mStableFrame.set(mFrame);
-            mStableFrame.top += mStableInsets.top;
-            mStableFrame.bottom += mStableInsets.bottom;
-            mStableFrame.left += mStableInsets.left;
-            mStableFrame.right += mStableInsets.right;
-        }
+        mContentFrame.offset(-layoutXDiff, -layoutYDiff);
+        mVisibleFrame.offset(-layoutXDiff, -layoutYDiff);
+        mStableFrame.offset(-layoutXDiff, -layoutYDiff);
+
         mCompatFrame.set(mFrame);
         if (mEnforceSizeCompat) {
             // If there is a size compatibility scale being applied to the
@@ -849,7 +906,7 @@
                 + "): frame=" + mFrame.toShortString()
                 + " ci=" + mContentInsets.toShortString()
                 + " vi=" + mVisibleInsets.toShortString()
-                + " vi=" + mStableInsets.toShortString()
+                + " si=" + mStableInsets.toShortString()
                 + " of=" + mOutsets.toShortString());
     }
 
@@ -1235,7 +1292,7 @@
         return mViewVisibility == View.GONE
                 || !mRelayoutCalled
                 || (atoken == null && mRootToken.hidden)
-                || (atoken != null && (atoken.hiddenRequested || atoken.hidden))
+                || (atoken != null && atoken.hiddenRequested)
                 || mAttachedHidden
                 || (mAnimatingExit && !isAnimatingLw())
                 || mDestroying;
@@ -1283,7 +1340,7 @@
      */
     boolean hasMoved() {
         return mHasSurface && (mContentChanged || mMovedByResize)
-                && !mAnimatingExit && !mWinAnimator.mLastHidden && mService.okToDisplay()
+                && !mAnimatingExit && mService.okToDisplay()
                 && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
                 && (mAttachedWindow == null || !mAttachedWindow.hasMoved());
     }
@@ -1345,6 +1402,11 @@
         mConfiguration = newConfig;
         mOverrideConfig = newOverrideConfig;
         mConfigHasChanged = false;
+
+        mMergedConfiguration.setTo(newConfig);
+        if (newOverrideConfig != null && newOverrideConfig != Configuration.EMPTY) {
+            mMergedConfiguration.updateFrom(newOverrideConfig);
+        }
     }
 
     void setHasSurface(boolean hasSurface) {
@@ -1374,6 +1436,39 @@
         }
     }
 
+    /**
+     * Notifies this window that the corresponding task has just moved in the stack.
+     * <p>
+     * This is used to fix the following: If we moved in the stack, and if the last clip rect was
+     * empty, meaning that our task was completely offscreen, we need to keep it invisible because
+     * the actual app transition that updates the visibility is delayed by a few transactions.
+     * Instead of messing around with the ordering and timing how transitions and transactions are
+     * executed, we introduce this little hack which prevents this window of getting visible again
+     * with the wrong bounds until the app transitions has started.
+     * <p>
+     * This method notifies the window about that we just moved in the stack so we can apply this
+     * logic in {@link WindowStateAnimator#updateSurfaceWindowCrop}
+     */
+    void notifyMovedInStack() {
+        mJustMovedInStack = true;
+    }
+
+    /**
+     * See {@link #notifyMovedInStack}.
+     *
+     * @return Whether we just got moved in the corresponding stack.
+     */
+    boolean hasJustMovedInStack() {
+        return mJustMovedInStack;
+    }
+
+    /**
+     * Resets that we just moved in the corresponding stack. See {@link #notifyMovedInStack}.
+     */
+    void resetJustMovedInStack() {
+        mJustMovedInStack = false;
+    }
+
     private final class DeadWindowEventReceiver extends InputEventReceiver {
         DeadWindowEventReceiver(InputChannel inputChannel) {
             super(inputChannel, mService.mH.getLooper());
@@ -1573,9 +1668,10 @@
             mTurnOnScreen = true;
         }
         if (isConfigChanged()) {
+            final Configuration newConfig = updateConfiguration();
             if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: "
-                    + mService.mCurConfiguration);
-            outConfig.setTo(mService.mCurConfiguration);
+                    + newConfig);
+            outConfig.setTo(newConfig);
         }
     }
 
@@ -1818,6 +1914,18 @@
     }
 
     private boolean shouldSaveSurface() {
+        if (mWinAnimator.mSurfaceController == null) {
+            // Don't bother if the surface controller is gone for any reason.
+            return false;
+        }
+
+        if ((mAttrs.flags & FLAG_SECURE) != 0) {
+            // We don't save secure surfaces since their content shouldn't be shown while the app
+            // isn't on screen and content might leak through during the transition animation with
+            // saved surface.
+            return false;
+        }
+
         if (ActivityManager.isLowRamDeviceStatic()) {
             // Don't save surfaces on Svelte devices.
             return false;
@@ -1836,6 +1944,12 @@
             return false;
         }
 
+        if (mResizedWhileGone) {
+            // Somebody resized our window while we were gone for layout, which means that the
+            // client got an old size, so we have an outdated surface here.
+            return false;
+        }
+
         if (DEBUG_DISABLE_SAVING_SURFACES) {
             return false;
         }
@@ -1853,6 +1967,12 @@
             mWinAnimator.hide("saved surface");
             mWinAnimator.mDrawState = WindowStateAnimator.NO_SURFACE;
             setHasSurface(false);
+            // The client should have disconnected at this point, but if it doesn't,
+            // we need to make sure it's disconnected. Otherwise when we reuse the surface
+            // the client can't reconnect to the buffer queue, and rendering will fail.
+            if (mWinAnimator.mSurfaceController != null) {
+                mWinAnimator.mSurfaceController.disconnectInTransaction();
+            }
         } else {
             mWinAnimator.destroySurfaceLocked();
         }
@@ -1872,10 +1992,18 @@
             return;
         }
         mSurfaceSaved = false;
-        setHasSurface(true);
-        mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
-        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-            Slog.v(TAG, "Restoring saved surface: " + this);
+        if (mWinAnimator.mSurfaceController != null) {
+            setHasSurface(true);
+            mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
+
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+                Slog.v(TAG, "Restoring saved surface: " + this);
+            }
+        } else {
+            // mSurfaceController shouldn't be null if mSurfaceSaved was still true at
+            // this point. Even if we destroyed the saved surface because of rotation
+            // or resize, mSurfaceSaved flag should have been cleared. So this is a wtf.
+            Slog.wtf(TAG, "Failed to restore saved surface: surface gone! " + this);
         }
     }
 
@@ -2006,21 +2134,30 @@
         }
     }
 
+    /**
+     * Update our current configurations, based on task configuration.
+     *
+     * @return A configuration suitable for sending to the client.
+     */
+    private Configuration updateConfiguration() {
+        final Task task = getTask();
+        final Configuration overrideConfig =
+            (task != null) ? task.mOverrideConfig : Configuration.EMPTY;
+        final boolean configChanged = isConfigChanged();
+        if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
+            Slog.i(TAG, "Sending new config to window " + this + ": " +
+                    " / config=" + mService.mCurConfiguration + " overrideConfig=" + overrideConfig);
+        }
+        setConfiguration(mService.mCurConfiguration, overrideConfig);
+        return mMergedConfiguration;
+    }
+
     void reportResized() {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
         try {
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mCompatFrame);
-            final boolean configChanged = isConfigChanged();
-            final Task task = getTask();
-            final Configuration overrideConfig =
-                    (task != null) ? task.mOverrideConfig : Configuration.EMPTY;
-            if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
-                Slog.i(TAG, "Sending new config to window " + this + ": "
-                        + " / config="
-                        + mService.mCurConfiguration + " overrideConfig=" + overrideConfig);
-            }
-            setConfiguration(mService.mCurConfiguration, overrideConfig);
+            final Configuration newConfig = isConfigChanged() ? updateConfiguration() : null;
             if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
                 Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
 
@@ -2031,7 +2168,6 @@
             final Rect stableInsets = mLastStableInsets;
             final Rect outsets = mLastOutsets;
             final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
-            final Configuration newConfig = configChanged ? mConfiguration : null;
             if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
                     && mClient instanceof IWindow.Stub) {
                 // To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -2106,7 +2242,7 @@
             Configuration newConfig) throws RemoteException {
         mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
                 reportDraw, newConfig, getBackdropFrame(frame),
-                isDragResizeChanged() /* forceRelayout */);
+                isDragResizeChanged() /* forceRelayout */, mPolicy.isNavBarForcedShownLw(this));
         mDragResizingChangeReported = true;
     }
 
@@ -2138,6 +2274,12 @@
         return task != null && task.inFreeformWorkspace();
     }
 
+    @Override
+    public boolean isInMultiWindowMode() {
+        final Task task = getTask();
+        return task != null && !task.isFullscreen();
+    }
+
     boolean isDragResizeChanged() {
         return mDragResizing != computeDragResizing();
     }
@@ -2160,7 +2302,7 @@
         return mResizeMode;
     }
 
-    private boolean computeDragResizing() {
+    boolean computeDragResizing() {
         final Task task = getTask();
         if (task == null) {
             return false;
@@ -2180,7 +2322,7 @@
         // background.
         return (mDisplayContent.mDividerControllerLocked.isResizing()
                         || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
-                !task.inFreeformWorkspace() && isVisibleLw();
+                !task.inFreeformWorkspace() && !isGoneForLayoutLw();
 
     }
 
@@ -2190,9 +2332,14 @@
             return;
         }
         mDragResizing = resizing;
-        mResizeMode = mDragResizing && mDisplayContent.mDividerControllerLocked.isResizing()
-                ? DRAG_RESIZE_MODE_DOCKED_DIVIDER
-                : DRAG_RESIZE_MODE_FREEFORM;
+        final Task task = getTask();
+        if (task != null && task.isDragResizing()) {
+            mResizeMode = task.getDragResizeMode();
+        } else {
+            mResizeMode = mDragResizing && mDisplayContent.mDividerControllerLocked.isResizing()
+                    ? DRAG_RESIZE_MODE_DOCKED_DIVIDER
+                    : DRAG_RESIZE_MODE_FREEFORM;
+        }
     }
 
     boolean isDragResizing() {
@@ -2298,7 +2445,8 @@
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
                 pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
                 pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
-                pw.print(" hasSavedSurface()="); pw.println(hasSavedSurface());
+                pw.print(" hasSavedSurface()="); pw.print(hasSavedSurface());
+                pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed);
         if (dumpAll) {
             pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
                     pw.print(" last="); mLastFrame.printShortString(pw);
@@ -2424,12 +2572,12 @@
         }
     }
 
-    void applyGravityAndUpdateFrame() {
-        final int pw = mContainingFrame.width();
-        final int ph = mContainingFrame.height();
+    void applyGravityAndUpdateFrame(Rect containingFrame, Rect displayFrame) {
+        final int pw = containingFrame.width();
+        final int ph = containingFrame.height();
         final Task task = getTask();
-        final boolean nonFullscreenTask = task != null && !task.isFullscreen();
-
+        final boolean nonFullscreenTask = isInMultiWindowMode();
+        final boolean fitToDisplay = task != null && !task.isFloating() && !layoutInParentFrame();
         float x, y;
         int w,h;
 
@@ -2473,7 +2621,7 @@
             y = mAttrs.y;
         }
 
-        if (nonFullscreenTask) {
+        if (nonFullscreenTask && !layoutInParentFrame()) {
             // Make sure window fits in containing frame since it is in a non-fullscreen task as
             // required by {@link Gravity#apply} call.
             w = Math.min(w, pw);
@@ -2481,18 +2629,32 @@
         }
 
         // Set mFrame
-        Gravity.apply(mAttrs.gravity, w, h, mContainingFrame,
+        Gravity.apply(mAttrs.gravity, w, h, containingFrame,
                 (int) (x + mAttrs.horizontalMargin * pw),
                 (int) (y + mAttrs.verticalMargin * ph), mFrame);
 
         // Now make sure the window fits in the overall display frame.
-        Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
+        if (fitToDisplay) {
+            Gravity.applyDisplay(mAttrs.gravity, displayFrame, mFrame);
+        }
+
+        // We need to make sure we update the CompatFrame as it is used for
+        // cropping decisions, etc, on systems where we lack a decor layer.
+        mCompatFrame.set(mFrame);
+        if (mEnforceSizeCompat) {
+            // See comparable block in computeFrameLw.
+            mCompatFrame.scale(mInvGlobalScale);
+        }
     }
 
     boolean isChildWindow() {
         return mAttachedWindow != null;
     }
 
+    boolean layoutInParentFrame() {
+        return isChildWindow() && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0;
+    }
+
     void setReplacing(boolean animate) {
         if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
                 || mAttrs.type == TYPE_APPLICATION_STARTING) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0828417..8fd8bc0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -20,6 +20,9 @@
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
@@ -37,8 +40,6 @@
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.localLOGV;
 import static com.android.server.wm.WindowManagerService.logWithStack;
-import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
 
@@ -74,6 +75,25 @@
     static final String TAG = TAG_WITH_CLASS_NAME ? "WindowStateAnimator" : TAG_WM;
     static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
 
+    /**
+     * Mode how the window gets clipped by the stack bounds during an animation: The clipping should
+     * be applied after applying the animation transformation, i.e. the stack bounds don't move
+     * during the animation.
+     */
+    static final int STACK_CLIP_AFTER_ANIM = 0;
+
+    /**
+     * Mode how the window gets clipped by the stack bounds: The clipping should be applied before
+     * applying the animation transformation, i.e. the stack bounds move with the window.
+     */
+    static final int STACK_CLIP_BEFORE_ANIM = 1;
+
+    /**
+     * Mode how window gets clipped by the stack bounds during an animation: Don't clip the window
+     * by the stack bounds.
+     */
+    static final int STACK_CLIP_NONE = 2;
+
     // Unchanging local convenience fields.
     final WindowManagerService mService;
     final WindowState mWin;
@@ -99,6 +119,7 @@
     int mLastLayer;
     long mAnimationStartTime;
     long mLastAnimationTime;
+    int mStackClip = STACK_CLIP_BEFORE_ANIM;
 
     /**
      * Set when we have changed the size of the surface, to know that
@@ -127,7 +148,9 @@
     boolean mHasClipRect;
     Rect mClipRect = new Rect();
     Rect mTmpClipRect = new Rect();
+    Rect mTmpFinalClipRect = new Rect();
     Rect mLastClipRect = new Rect();
+    Rect mLastFinalClipRect = new Rect();
     Rect mTmpStackBounds = new Rect();
 
     /**
@@ -159,6 +182,7 @@
     boolean mEnteringAnimation;
 
     boolean mKeyguardGoingAwayAnimation;
+    boolean mKeyguardGoingAwayWithWallpaper;
 
     /** The pixel format of the underlying SurfaceControl */
     int mSurfaceFormat;
@@ -224,7 +248,7 @@
         mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
     }
 
-    public void setAnimation(Animation anim, long startTime) {
+    public void setAnimation(Animation anim, long startTime, int stackClip) {
         if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
         mAnimating = false;
         mLocalAnimating = false;
@@ -236,10 +260,15 @@
         mTransformation.setAlpha(mLastHidden ? 0 : 1);
         mHasLocalTransformation = true;
         mAnimationStartTime = startTime;
+        mStackClip = stackClip;
+    }
+
+    public void setAnimation(Animation anim, int stackClip) {
+        setAnimation(anim, -1, stackClip);
     }
 
     public void setAnimation(Animation anim) {
-        setAnimation(anim, -1);
+        setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
     }
 
     public void clearAnimation() {
@@ -249,6 +278,8 @@
             mAnimation.cancel();
             mAnimation = null;
             mKeyguardGoingAwayAnimation = false;
+            mKeyguardGoingAwayWithWallpaper = false;
+            mStackClip = STACK_CLIP_BEFORE_ANIM;
         }
     }
 
@@ -380,6 +411,7 @@
 
         mAnimating = false;
         mKeyguardGoingAwayAnimation = false;
+        mKeyguardGoingAwayWithWallpaper = false;
         mLocalAnimating = false;
         if (mAnimation != null) {
             mAnimation.cancel();
@@ -393,6 +425,7 @@
         if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
         mHasTransformation = false;
         mHasLocalTransformation = false;
+        mStackClip = STACK_CLIP_BEFORE_ANIM;
         mWin.checkPolicyVisibilityChange();
         mTransformation.clear();
         if (mDrawState == HAS_DRAWN
@@ -433,9 +466,12 @@
                 + " remove=" + mWin.mRemoveOnExit
                 + " windowAnimating=" + isWindowAnimating());
 
-        final int N = mWin.mChildWindows.size();
-        for (int i=0; i<N; i++) {
-            mWin.mChildWindows.get(i).mWinAnimator.finishExit();
+        if (!mWin.mChildWindows.isEmpty()) {
+            // Copying to a different list as multiple children can be removed.
+            final WindowList childWindows = new WindowList(mWin.mChildWindows);
+            for (int i = childWindows.size() - 1; i >= 0; i--) {
+                childWindows.get(i).mWinAnimator.finishExit();
+            }
         }
 
         if (mEnteringAnimation) {
@@ -467,9 +503,8 @@
             return;
         }
 
-        if (WindowManagerService.localLOGV) Slog.v(
-                TAG, "Exit animation finished in " + this
-                + ": remove=" + mWin.mRemoveOnExit);
+        if (WindowManagerService.localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG,
+                "Exit animation finished in " + this + ": remove=" + mWin.mRemoveOnExit);
 
 
         mWin.mDestroying = true;
@@ -705,8 +740,6 @@
 
         // Start a new transaction and apply position & offset.
         final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
-        if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
-                "POS " + mTmpSize.left + ", " + mTmpSize.top, false);
         mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
         mLastHidden = true;
 
@@ -934,13 +967,15 @@
             if (appTransformation != null) {
                 tmpMatrix.postConcat(appTransformation.getMatrix());
             }
+
+            // The translation that applies the position of the window needs to be applied at the
+            // end in case that other translations include scaling. Otherwise the scaling will
+            // affect this translation. But it needs to be set before the screen rotation animation
+            // so the pivot point is at the center of the screen for all windows.
+            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
             if (screenAnimation) {
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
-            // The translation that applies the position of the window needs to be applied at the
-            // end in case that other translations include scaling. Otherwise the scaling will
-            // affect this translation.
-            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
 
             //TODO (multidisplay): Magnification is supported only for the default display.
             if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
@@ -990,6 +1025,17 @@
                     if (appTransformation.hasClipRect()) {
                         mClipRect.set(appTransformation.getClipRect());
                         mHasClipRect = true;
+                        // The app transformation clip will be in the coordinate space of the main
+                        // activity window, which the animation correctly assumes will be placed at
+                        // (0,0)+(insets) relative to the containing frame. This isn't necessarily
+                        // true for child windows though which can have an arbitrary frame position
+                        // relative to their containing frame. We need to offset the difference
+                        // between the containing frame as used to calculate the crop and our
+                        // bounds to compensate for this.
+                        if (mWin.isChildWindow() && mWin.layoutInParentFrame()) {
+                            mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
+                                    mWin.mContainingFrame.top - mWin.mFrame.top );
+                        }
                     }
                 }
                 if (screenAnimation) {
@@ -1115,10 +1161,12 @@
         }
     }
 
-    void updateSurfaceWindowCrop(final boolean recoveringMemory) {
+    void calculateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect) {
         final WindowState w = mWin;
         final DisplayContent displayContent = w.getDisplayContent();
         if (displayContent == null) {
+            clipRect.setEmpty();
+            finalClipRect.setEmpty();
             return;
         }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
@@ -1155,7 +1203,6 @@
         final boolean fullscreen = w.isFrameFullscreen(displayInfo);
         final boolean isFreeformResizing =
                 w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
-        final Rect clipRect = mTmpClipRect;
 
         // We use the clip rect as provided by the tranformation for non-fullscreen windows to
         // avoid premature clipping with the system decor rect.
@@ -1186,35 +1233,54 @@
         // so we need to translate to match the actual surface coordinates.
         clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
 
-        adjustCropToStackBounds(w, clipRect, isFreeformResizing);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + mClipRect);
+        finalClipRect.setEmpty();
+        adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
 
         w.transformFromScreenToSurfaceSpace(clipRect);
 
+        // See {@link WindowState#notifyMovedInStack} for why this is necessary.
+        if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
+            clipRect.setEmpty();
+        }
+    }
+
+    void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
         if (!clipRect.equals(mLastClipRect)) {
             mLastClipRect.set(clipRect);
             mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
         }
+        if (!finalClipRect.equals(mLastFinalClipRect)) {
+            mLastFinalClipRect.set(finalClipRect);
+            mSurfaceController.setFinalCropInTransaction(finalClipRect);
+        }
     }
 
-    private void adjustCropToStackBounds(WindowState w, Rect clipRect, boolean isFreeformResizing) {
+    private int resolveStackClip() {
+
+        // App animation overrides window animation stack clip mode.
+        if (mAppAnimator != null && mAppAnimator.animation != null) {
+            return mAppAnimator.getStackClip();
+        } else {
+            return mStackClip;
+        }
+    }
+    private void adjustCropToStackBounds(WindowState w, Rect clipRect, Rect finalClipRect,
+            boolean isFreeformResizing) {
         final Task task = w.getTask();
         if (task == null || !task.cropWindowsToStackBounds()) {
             return;
         }
 
-        // We don't apply the stack bounds crop if:
-        // 1. The window is currently animating docked mode or in freeform mode, otherwise the
-        // animating window will be suddenly (docked) or for whole animation (freeform) cut off.
-        // (Note that we still need to apply the crop if the task being docked is non-resizeable,
-        // in which case the task is running in fullscreen size but cropped to stack bounds.)
-        // 2. The window that is being replaced during animation, because it was living in a
-        // different stack. If we suddenly crop it to the new stack bounds, it might get cut off.
-        // We don't want it to happen, so we let it ignore the stack bounds until it gets removed.
-        // The window that will replace it will abide them.
-        if (isAnimating() && (w.mWillReplaceWindow
-                || (w.inDockedWorkspace() && task.isResizeable())
-                || w.inFreeformWorkspace())) {
+        final int stackClip = resolveStackClip();
+
+        // It's animating and we don't want to clip it to stack bounds during animation - abort.
+        if (isAnimating() && stackClip == STACK_CLIP_NONE) {
+            return;
+        }
+
+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        if (w == winShowWhenLocked) {
             return;
         }
 
@@ -1227,28 +1293,68 @@
                 w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
         final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
                 w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+
+        // If we are animating, we either apply the clip before applying all the animation
+        // transformation or after all the transformation.
+        final boolean useFinalClipRect = isAnimating() && stackClip == STACK_CLIP_AFTER_ANIM;
+
         // We need to do some acrobatics with surface position, because their clip region is
         // relative to the inside of the surface, but the stack bounds aren't.
-        clipRect.left = Math.max(0,
-                Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
-        clipRect.top = Math.max(0,
-                Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
-        clipRect.right = Math.max(0,
-                Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
-        clipRect.bottom = Math.max(0,
-                Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
+        if (useFinalClipRect) {
+            finalClipRect.set(mTmpStackBounds);
+        } else {
+            clipRect.left = Math.max(0,
+                    Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
+            clipRect.top = Math.max(0,
+                    Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
+            clipRect.right = Math.max(0,
+                    Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
+            clipRect.bottom = Math.max(0,
+                    Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
+        }
     }
 
     void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
+        final Task task = w.getTask();
 
         mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
         calculateSurfaceBounds(w, w.getAttrs());
 
-        mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, recoveringMemory);
+        float extraHScale = (float) 1.0;
+        float extraVScale = (float) 1.0;
 
-        mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale, mDtDx * w.mVScale,
-                mDsDy * w.mHScale, mDtDy * w.mVScale, recoveringMemory);
+        calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+        if (task != null && task.mStack.getForceScaleToCrop()) {
+            extraHScale = mTmpClipRect.width() / (float)mTmpSize.width();
+            extraVScale = mTmpClipRect.height() / (float)mTmpSize.height();
+
+            // In the case of ForceScaleToCrop we scale entire tasks together,
+            // and so we need to scale our offsets relative to the task bounds
+            // or parent and child windows would fall out of alignment.
+            int posX = (int) (mTmpSize.left - w.mAttrs.x * (1 - extraHScale));
+            int posY = (int) (mTmpSize.top - w.mAttrs.y * (1 - extraVScale));
+            posX += w.getAttrs().surfaceInsets.left * (1 - extraHScale);
+            posY += w.getAttrs().surfaceInsets.top * (1 - extraVScale);
+            mSurfaceController.setPositionInTransaction(posX, posY, recoveringMemory);
+
+            // Since we are scaled to fit in our previously desired crop, we can now
+            // expose the whole window in buffer space, and not risk extending
+            // past where the system would have cropped us
+            mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height());
+            mTmpFinalClipRect.setEmpty();
+            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
+        } else {
+            mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
+                    recoveringMemory);
+            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
+        }
+
+
+        mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * extraHScale,
+                mDtDx * w.mVScale * extraVScale,
+                mDsDy * w.mHScale * extraHScale,
+                mDtDy * w.mVScale * extraVScale, recoveringMemory);
         mSurfaceResized = mSurfaceController.setSizeInTransaction(
                 mTmpSize.width(), mTmpSize.height(),
                 recoveringMemory);
@@ -1260,7 +1366,6 @@
             w.applyDimLayerIfNeeded();
         }
 
-        updateSurfaceWindowCrop(recoveringMemory);
     }
 
     void prepareSurfaceLocked(final boolean recoveringMemory) {
@@ -1399,7 +1504,8 @@
             SurfaceControl.openTransaction();
             mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
                     mWin.mFrame.top + top, false);
-            updateSurfaceWindowCrop(false);
+            calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, false);
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error positioning surface of " + mWin
                     + " pos=(" + left + "," + top + ")", e);
@@ -1517,23 +1623,7 @@
             }
 
             if (mWin.mAttrs.type != TYPE_APPLICATION_STARTING && mWin.mAppToken != null) {
-                mWin.mAppToken.firstWindowDrawn = true;
-
-                // We now have a good window to show, remove dead placeholders
-                mWin.mAppToken.removeAllDeadWindows();
-
-                if (mWin.mAppToken.startingData != null) {
-                    if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
-                            + mWin.mToken + ": first real window is shown, no animation");
-                    // If this initial window is animating, stop it -- we
-                    // will do an animation to reveal it from behind the
-                    // starting window, so there is no need for it to also
-                    // be doing its own stuff.
-                    clearAnimation();
-                    mService.mFinishedStarting.add(mWin.mAppToken);
-                    mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
-                }
-                mWin.mAppToken.updateReportedVisibilityLocked();
+                mWin.mAppToken.onFirstWindowDrawn(mWin, this);
             }
 
             return true;
@@ -1678,6 +1768,7 @@
                     pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
                     pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
                     pw.print(" mAnimation="); pw.println(mAnimation);
+                    pw.print(" mStackClip="); pw.println(mStackClip);
         }
         if (mHasTransformation || mHasLocalTransformation) {
             pw.print(prefix); pw.print("XForm: has=");
@@ -1697,6 +1788,9 @@
             if (mHasClipRect) {
                 pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
             }
+            if (!mLastFinalClipRect.isEmpty()) {
+                pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
+            }
             pw.println();
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 93164de..8799c61 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -63,6 +63,8 @@
     // the window. We achieve this by explicitly hiding the surface and not letting it be shown.
     private boolean mHiddenForCrop = false;
 
+    // Initially a surface is hidden after just being created.
+    private boolean mHiddenForOtherReasons = true;
     private final String title;
 
     public WindowSurfaceController(SurfaceSession s,
@@ -95,6 +97,11 @@
 
     void hideInTransaction(String reason) {
         if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
+        mHiddenForOtherReasons = true;
+        updateVisibility();
+    }
+
+    private void hideSurface() {
         if (mSurfaceControl != null) {
             mSurfaceShown = false;
             try {
@@ -112,6 +119,8 @@
             mSurfaceY = top;
 
             try {
+                if (SHOW_TRANSACTIONS) logSurface(
+                        "POS (setPositionAndLayer) @ (" + left + "," + top + ")", null);
                 mSurfaceControl.setPosition(left, top);
                 mSurfaceControl.setLayerStack(layerStack);
 
@@ -131,7 +140,7 @@
 
     void destroyInTransaction() {
         //        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(4));
+        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
         //        }
         try {
             if (mSurfaceControl != null) {
@@ -145,6 +154,20 @@
         }
     }
 
+    void disconnectInTransaction() {
+        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+            Slog.i(TAG, "Disconnecting client: " + this);
+        }
+
+        try {
+            if (mSurfaceControl != null) {
+                mSurfaceControl.disconnect();
+            }
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Error disconnecting surface in: " + this, e);
+        }
+    }
+
     void setCropInTransaction(Rect clipRect, boolean recoveringMemory) {
         if (SHOW_TRANSACTIONS) logSurface(
                 "CROP " + clipRect.toShortString(), null);
@@ -152,9 +175,10 @@
             if (clipRect.width() > 0 && clipRect.height() > 0) {
                 mSurfaceControl.setWindowCrop(clipRect);
                 mHiddenForCrop = false;
+                updateVisibility();
             } else {
-                hideInTransaction("setCrop");
                 mHiddenForCrop = true;
+                updateVisibility();
             }
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error setting crop surface of " + this
@@ -165,6 +189,16 @@
         }
     }
 
+    void setFinalCropInTransaction(Rect clipRect) {
+        if (SHOW_TRANSACTIONS) logSurface(
+                "FINAL CROP " + clipRect.toShortString(), null);
+        try {
+            mSurfaceControl.setFinalCrop(clipRect);
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Error disconnecting surface in: " + this, e);
+        }
+    }
+
     void setLayer(int layer) {
         if (mSurfaceControl != null) {
             SurfaceControl.openTransaction();
@@ -183,6 +217,9 @@
             mSurfaceY = top;
 
             try {
+                if (SHOW_TRANSACTIONS) logSurface(
+                        "POS (setPositionInTransaction) @ (" + left + "," + top + ")", null);
+
                 mSurfaceControl.setPosition(left, top);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Error positioning surface of " + this
@@ -317,11 +354,26 @@
                 "SHOW (performLayout)", null);
         if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
                 + " during relayout");
+        mHiddenForOtherReasons = false;
+        return updateVisibility();
+    }
 
-        if (mHiddenForCrop) {
+    private boolean updateVisibility() {
+        if (mHiddenForCrop || mHiddenForOtherReasons) {
+            if (mSurfaceShown) {
+                hideSurface();
+            }
             return false;
+        } else {
+            if (!mSurfaceShown) {
+                return showSurface();
+            } else {
+                return true;
+            }
         }
+    }
 
+    private boolean showSurface() {
         try {
             mSurfaceShown = true;
             mSurfaceControl.show();
@@ -418,6 +470,7 @@
         private final PointF mPosition = new PointF();
         private final Point mSize = new Point();
         private final Rect mWindowCrop = new Rect();
+        private final Rect mFinalCrop = new Rect();
         private boolean mShown = false;
         private int mLayerStack;
         private boolean mIsOpaque;
@@ -503,6 +556,19 @@
         }
 
         @Override
+        public void setFinalCrop(Rect crop) {
+            if (crop != null) {
+                if (!crop.equals(mFinalCrop)) {
+                    if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setFinalCrop("
+                            + crop.toShortString() + "): OLD:" + this + ". Called by "
+                            + Debug.getCallers(3));
+                    mFinalCrop.set(crop);
+                }
+            }
+            super.setFinalCrop(crop);
+        }
+
+        @Override
         public void setLayerStack(int layerStack) {
             if (layerStack != mLayerStack) {
                 if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setLayerStack(" + layerStack + "): OLD:"
@@ -581,6 +647,13 @@
             }
         }
 
+        @Override
+        public void setTransparentRegionHint(Region region) {
+            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setTransparentRegionHint(" + region
+                    + "): OLD: " + this + " . Called by " + Debug.getCallers(3));
+            super.setTransparentRegionHint(region);
+        }
+
         static void dumpAllSurfaces(PrintWriter pw, String header) {
             synchronized (sSurfaces) {
                 final int N = sSurfaces.size();
@@ -606,6 +679,7 @@
                             pw.print(" mSize="); pw.print(s.mSize.x); pw.print("x");
                             pw.println(s.mSize.y);
                     pw.print("    mCrop="); s.mWindowCrop.printShortString(pw); pw.println();
+                    pw.print("    mFinalCrop="); s.mFinalCrop.printShortString(pw); pw.println();
                     pw.print("    Transform: ("); pw.print(s.mDsdx); pw.print(", ");
                             pw.print(s.mDtdx); pw.print(", "); pw.print(s.mDsdy);
                             pw.print(", "); pw.print(s.mDtdy); pw.println(")");
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index f705df8..eda2f39 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -1,10 +1,15 @@
 package com.android.server.wm;
 
+import static android.app.ActivityManagerInternal.APP_TRANSITION_SAVED_SURFACE;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_STARTING_WINDOW;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
@@ -14,6 +19,7 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -26,13 +32,21 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerService.H.*;
-import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
-import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.DO_TRAVERSAL;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_STARTING_WINDOW_DRAWN;
+import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
+import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
+import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
+import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
@@ -120,6 +134,8 @@
     }
     private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
 
+    private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
+
     public WindowSurfacePlacer(WindowManagerService service) {
         mService = service;
         mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
@@ -537,6 +553,7 @@
         mService.enableScreenIfNeededLocked();
 
         mService.scheduleAnimationLocked();
+        mService.mWindowPlacerLocked.destroyPendingSurfaces();
 
         if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
                 "performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
@@ -646,6 +663,7 @@
 
             for (int i = windows.size() - 1; i >= 0; i--) {
                 WindowState w = windows.get(i);
+                final Task task = w.getTask();
                 final boolean obscuredChanged = w.mObscured != mObscured;
 
                 // Update effect.
@@ -675,10 +693,13 @@
                     // currently animating... let's do something.
                     final int left = w.mFrame.left;
                     final int top = w.mFrame.top;
-                    final boolean adjustedForMinimizedDockedStack = w.getTask() != null &&
-                            w.getTask().mStack.isAdjustedForMinimizedDockedStack();
+                    final boolean adjustedForMinimizedDockOrIme = task != null
+                                && (task.mStack.isAdjustedForMinimizedDockedStack()
+                                    || task.mStack.isAdjustedForIme());
                     if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
-                            && !w.isDragResizing() && !adjustedForMinimizedDockedStack) {
+                            && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
+                            && (task == null || !w.getTask().mStack.getFreezeMovementAnimations())
+                            && !w.mWinAnimator.mLastHidden) {
                         winAnimator.setMoveAnimation(left, top);
                     }
 
@@ -692,11 +713,11 @@
                         w.mClient.moved(left, top);
                     } catch (RemoteException e) {
                     }
+                    w.mMovedByResize = false;
                 }
 
                 //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
                 w.mContentChanged = false;
-                w.mMovedByResize = false;
 
                 // Moved from updateWindowsAndWallpaperLocked().
                 if (w.mHasSurface) {
@@ -782,6 +803,7 @@
                                 }
                             }
                         } else if (w.isDrawnLw()) {
+                            mService.mH.sendEmptyMessage(NOTIFY_STARTING_WINDOW_DRAWN);
                             atoken.startingDisplayed = true;
                         }
                     }
@@ -838,6 +860,10 @@
             mService.mInputConsumer.layout(dw, dh);
         }
 
+        if (mService.mWallpaperInputConsumer != null) {
+            mService.mWallpaperInputConsumer.layout(dw, dh);
+        }
+
         final int N = windows.size();
         int i;
 
@@ -1148,7 +1174,7 @@
 
             if (!appAnimator.usingTransferredAnimation) {
                 appAnimator.clearThumbnail();
-                appAnimator.animation = null;
+                appAnimator.setNullAnimation();
             }
             wtoken.inPendingTransaction = false;
 
@@ -1208,6 +1234,10 @@
             if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
                 createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
             }
+            if (mService.mAppTransition.getAppTransition()
+                    == AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS) {
+                appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START);
+            }
         }
         return topOpeningApp;
     }
@@ -1221,7 +1251,7 @@
             final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
             appAnimator.clearThumbnail();
-            appAnimator.animation = null;
+            appAnimator.setNullAnimation();
             wtoken.inPendingTransaction = false;
             mService.setTokenVisibilityLocked(wtoken, animLp, false, transit, false,
                     voiceInteraction);
@@ -1262,6 +1292,7 @@
                 "Checking " + appsCount + " opening apps (frozen="
                         + mService.mDisplayFrozen + " timeout="
                         + mService.mAppTransition.isTimeout() + ")...");
+        int reason = APP_TRANSITION_TIMEOUT;
         if (!mService.mAppTransition.isTimeout()) {
             for (int i = 0; i < appsCount; i++) {
                 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
@@ -1269,13 +1300,25 @@
                         "Check opening app=" + wtoken + ": allDrawn="
                         + wtoken.allDrawn + " startingDisplayed="
                         + wtoken.startingDisplayed + " startingMoved="
-                        + wtoken.startingMoved);
+                        + wtoken.startingMoved + " isRelaunching()="
+                        + wtoken.isRelaunching());
 
+                if (wtoken.isRelaunching()) {
+                    return false;
+                }
+
+                final boolean drawnBeforeRestoring = wtoken.allDrawn;
                 wtoken.restoreSavedSurfaces();
 
                 if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
                     return false;
                 }
+                if (wtoken.allDrawn) {
+                    reason = drawnBeforeRestoring ? APP_TRANSITION_WINDOWS_DRAWN
+                            : APP_TRANSITION_SAVED_SURFACE;
+                } else {
+                    reason = APP_TRANSITION_STARTING_WINDOW;
+                }
             }
 
             // We also need to wait for the specs to be fetched, if needed.
@@ -1285,9 +1328,15 @@
             }
 
             // If the wallpaper is visible, we need to check it's ready too.
-            return !mWallpaperControllerLocked.isWallpaperVisible() ||
+            boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
                     mWallpaperControllerLocked.wallpaperTransitionReady();
+            if (wallpaperReady) {
+                mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reason, 0).sendToTarget();
+                return true;
+            }
+            return false;
         }
+        mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reason, 0).sendToTarget();
         return true;
     }
 
@@ -1465,7 +1514,7 @@
                 if (DEBUG_APP_TRANSITIONS)
                     Slog.v(TAG, "Now animating app in place " + wtoken);
                 appAnimator.clearThumbnail();
-                appAnimator.animation = null;
+                appAnimator.setNullAnimation();
                 mService.updateTokenInPlaceLocked(wtoken, transit);
                 wtoken.updateReportedVisibilityLocked();
 
@@ -1527,12 +1576,13 @@
                 WindowState win = appToken.findMainWindow();
                 Rect appRect = win != null ? win.getContentFrameLw() :
                         new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+                Rect insets = win != null ? win.mContentInsets : null;
                 // For the new aspect-scaled transition, we want it to always show
                 // above the animating opening/closing window, and we want to
                 // synchronize its thumbnail surface with the surface for the
                 // open/close animation (only on the way down)
                 anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
-                        thumbnailHeader, taskId);
+                        insets, thumbnailHeader, taskId, mService.mCurConfiguration.orientation);
                 openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
                 openingAppAnimator.deferThumbnailDestruction =
                         !mService.mAppTransition.isNextThumbnailTransitionScaleUp();
@@ -1547,8 +1597,6 @@
             openingAppAnimator.thumbnailLayer = openingLayer;
             openingAppAnimator.thumbnailAnimation = anim;
             mService.mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
-            openingAppAnimator.thumbnailX = mTmpStartRect.left;
-            openingAppAnimator.thumbnailY = mTmpStartRect.top;
         } catch (Surface.OutOfResourcesException e) {
             Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w="
                     + dirty.width() + " h=" + dirty.height(), e);
@@ -1598,6 +1646,25 @@
         }
     }
 
+    /**
+     * Puts the {@param surface} into a pending list to be destroyed after the current transaction
+     * has been committed.
+     */
+    void destroyAfterTransaction(SurfaceControl surface) {
+        mPendingDestroyingSurfaces.add(surface);
+    }
+
+    /**
+     * Destroys any surfaces that have been put into the pending list with
+     * {@link #destroyAfterTransaction}.
+     */
+    void destroyPendingSurfaces() {
+        for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
+            mPendingDestroyingSurfaces.get(i).destroy();
+        }
+        mPendingDestroyingSurfaces.clear();
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mTraversalScheduled="); pw.println(mTraversalScheduled);
     }
diff --git a/services/core/java/com/android/server/wm/animation/CurvedTranslateAnimation.java b/services/core/java/com/android/server/wm/animation/CurvedTranslateAnimation.java
new file mode 100644
index 0000000..33ac2ff
--- /dev/null
+++ b/services/core/java/com/android/server/wm/animation/CurvedTranslateAnimation.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.wm.animation;
+
+import android.animation.KeyframeSet;
+import android.animation.PathKeyframes;
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+/**
+ * Translate animation which follows a curved path.
+ */
+public class CurvedTranslateAnimation extends Animation {
+
+    private final PathKeyframes mKeyframes;
+
+    public CurvedTranslateAnimation(Path path) {
+        mKeyframes = KeyframeSet.ofPath(path);
+    }
+
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        PointF location = (PointF) mKeyframes.getValue(interpolatedTime);
+        t.getMatrix().setTranslate(location.x, location.y);
+    }
+}
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index 214d988..14d50ce 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -21,116 +21,158 @@
 
 #include <stdlib.h>
 
-#include <hardware/hardware_properties.h>
+#include <hardware/thermal.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 
-#include <hardware_properties/HardwarePropertiesManager.h>
-
 #include "core_jni_helpers.h"
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
+// These values must be kept in sync with the temperature source constants in
+// HardwarePropertiesManager.java
+enum {
+    TEMPERATURE_CURRENT = 0,
+    TEMPERATURE_THROTTLING = 1,
+    TEMPERATURE_SHUTDOWN = 2,
+    TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3
+};
+
 static struct {
     jclass clazz;
     jmethodID initMethod;
 } gCpuUsageInfoClassInfo;
 
-static struct hardware_properties_module* gHardwarePropertiesModule;
+jfloat gUndefinedTemperature;
+
+static struct thermal_module* gThermalModule;
 
 // ----------------------------------------------------------------------------
 
 static void nativeInit(JNIEnv* env, jobject obj) {
-    status_t err = hw_get_module(HARDWARE_PROPERTIES_HARDWARE_MODULE_ID,
-            (hw_module_t const**)&gHardwarePropertiesModule);
+    status_t err = hw_get_module(THERMAL_HARDWARE_MODULE_ID, (hw_module_t const**)&gThermalModule);
     if (err) {
-        ALOGE("Couldn't load %s module (%s)", HARDWARE_PROPERTIES_HARDWARE_MODULE_ID,
-              strerror(-err));
+        ALOGE("Couldn't load %s module (%s)", THERMAL_HARDWARE_MODULE_ID, strerror(-err));
     }
 }
 
 static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
-    if (gHardwarePropertiesModule && gHardwarePropertiesModule->getFanSpeeds) {
-        float *speeds = nullptr;
-        ssize_t size = gHardwarePropertiesModule->getFanSpeeds(gHardwarePropertiesModule, &speeds);
+    if (gThermalModule && gThermalModule->getCoolingDevices) {
+        ssize_t list_size = gThermalModule->getCoolingDevices(gThermalModule, nullptr, 0);
 
-        if (speeds && size > 0) {
-            jfloatArray fanSpeeds = env->NewFloatArray(size);
-            env->SetFloatArrayRegion(fanSpeeds, 0, size, speeds);
-            free(speeds);
-            return fanSpeeds;
+        if (list_size >= 0) {
+            cooling_device_t *list = (cooling_device_t *)
+                    malloc(list_size * sizeof(cooling_device_t));
+            ssize_t size = gThermalModule->getCoolingDevices(gThermalModule, list, list_size);
+            if (size >= 0) {
+                if (list_size > size) {
+                    list_size = size;
+                }
+                jfloat values[list_size];
+                for (ssize_t i = 0; i < list_size; ++i) {
+                    values[i] = list[i].current_value;
+                }
+
+                jfloatArray fanSpeeds = env->NewFloatArray(list_size);
+                env->SetFloatArrayRegion(fanSpeeds, 0, list_size, values);
+                free(list);
+                return fanSpeeds;
+            }
+
+            free(list);
         }
 
-        if (size < 0) {
-            ALOGE("Cloudn't get fan speeds because of HAL error");
-        }
+        ALOGE("Cloudn't get fan speeds because of HAL error");
     }
     return env->NewFloatArray(0);
 }
 
-static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type) {
-    if (gHardwarePropertiesModule) {
-        ssize_t size = 0;
-        float *temps = nullptr;
-        switch (type) {
-        case DEVICE_TEMPERATURE_CPU:
-            if (gHardwarePropertiesModule->getCpuTemperatures) {
-                size = gHardwarePropertiesModule->getCpuTemperatures(gHardwarePropertiesModule,
-                                                                     &temps);
+static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type,
+                                               int source) {
+    if (gThermalModule && gThermalModule->getTemperatures) {
+        ssize_t list_size = gThermalModule->getTemperatures(gThermalModule, nullptr, 0);
+        if (list_size >= 0) {
+            temperature_t *list = (temperature_t *) malloc(list_size * sizeof(temperature_t));
+            ssize_t size = gThermalModule->getTemperatures(gThermalModule, list, list_size);
+            if (size >= 0) {
+                if (list_size > size) {
+                    list_size = size;
+                }
+
+                jfloat values[list_size];
+                size_t length = 0;
+
+                for (ssize_t i = 0; i < list_size; ++i) {
+                    if (list[i].type == type) {
+                        switch (source) {
+                            case TEMPERATURE_CURRENT:
+                                if (list[i].current_value == UNKNOWN_TEMPERATURE) {
+                                    values[length++] = gUndefinedTemperature;
+                                } else {
+                                    values[length++] = list[i].current_value;
+                                }
+                                break;
+                            case TEMPERATURE_THROTTLING:
+                                if (list[i].throttling_threshold == UNKNOWN_TEMPERATURE) {
+                                    values[length++] = gUndefinedTemperature;
+                                } else {
+                                    values[length++] = list[i].throttling_threshold;
+                                }
+                                break;
+                            case TEMPERATURE_SHUTDOWN:
+                                if (list[i].shutdown_threshold == UNKNOWN_TEMPERATURE) {
+                                    values[length++] = gUndefinedTemperature;
+                                } else {
+                                    values[length++] = list[i].shutdown_threshold;
+                                }
+                                break;
+                            case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
+                                if (list[i].vr_throttling_threshold == UNKNOWN_TEMPERATURE) {
+                                    values[length++] = gUndefinedTemperature;
+                                } else {
+                                    values[length++] = list[i].vr_throttling_threshold;
+                                }
+                                break;
+                        }
+                    }
+                }
+                jfloatArray deviceTemps = env->NewFloatArray(length);
+                env->SetFloatArrayRegion(deviceTemps, 0, length, values);
+                free(list);
+                return deviceTemps;
             }
-            break;
-        case DEVICE_TEMPERATURE_GPU:
-            if (gHardwarePropertiesModule->getGpuTemperatures) {
-                size = gHardwarePropertiesModule->getGpuTemperatures(gHardwarePropertiesModule,
-                                                                    &temps);
-            }
-            break;
-        case DEVICE_TEMPERATURE_BATTERY:
-            if (gHardwarePropertiesModule->getBatteryTemperatures) {
-                size = gHardwarePropertiesModule->getBatteryTemperatures(gHardwarePropertiesModule,
-                                                                        &temps);
-            }
-            break;
+            free(list);
         }
-        if (temps && size > 0) {
-            jfloatArray deviceTemps = env->NewFloatArray(size);
-            env->SetFloatArrayRegion(deviceTemps, 0, size, temps);
-            free(temps);
-            return deviceTemps;
-        }
-        if (size < 0) {
-            ALOGE("Couldn't get device temperatures type=%d because of HAL error", type);
-        }
+        ALOGE("Couldn't get device temperatures because of HAL error");
     }
     return env->NewFloatArray(0);
 }
 
 static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
-    if (gHardwarePropertiesModule && gHardwarePropertiesModule->getCpuUsages
-        && gCpuUsageInfoClassInfo.initMethod) {
-        int64_t *active_times = nullptr;
-        int64_t *total_times = nullptr;
-        ssize_t size = gHardwarePropertiesModule->getCpuUsages(gHardwarePropertiesModule,
-                                                               &active_times, &total_times);
-        if (active_times && total_times && size > 0) {
-            jobjectArray cpuUsages = env->NewObjectArray(size, gCpuUsageInfoClassInfo.clazz,
-                                                         nullptr);
-            for (ssize_t i = 0; i < size; ++i) {
-                jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
-                                                  gCpuUsageInfoClassInfo.initMethod,
-                                                  active_times[i], total_times[i]);
-                env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
+    if (gThermalModule && gThermalModule->getCpuUsages
+            && gCpuUsageInfoClassInfo.initMethod) {
+        ssize_t size = gThermalModule->getCpuUsages(gThermalModule, nullptr);
+        if (size >= 0) {
+            cpu_usage_t *list = (cpu_usage_t *) malloc(size * sizeof(cpu_usage_t));
+            size = gThermalModule->getCpuUsages(gThermalModule, list);
+            if (size >= 0) {
+                jobjectArray cpuUsages = env->NewObjectArray(size, gCpuUsageInfoClassInfo.clazz,
+                        nullptr);
+                for (ssize_t i = 0; i < size; ++i) {
+                    if (list[i].is_online) {
+                        jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
+                                gCpuUsageInfoClassInfo.initMethod, list[i].active, list[i].total);
+                        env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
+                    }
+                }
+                free(list);
+                return cpuUsages;
             }
-            free(active_times);
-            free(total_times);
-            return cpuUsages;
+            free(list);
         }
-
-        if (size < 0) {
-            ALOGE("Couldn't get CPU usages because of HAL error");
-        }
+        ALOGE("Couldn't get CPU usages because of HAL error");
     }
     return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
 }
@@ -143,14 +185,14 @@
             (void*) nativeInit },
     { "nativeGetFanSpeeds", "()[F",
             (void*) nativeGetFanSpeeds },
-    { "nativeGetDeviceTemperatures", "(I)[F",
+    { "nativeGetDeviceTemperatures", "(II)[F",
             (void*) nativeGetDeviceTemperatures },
     { "nativeGetCpuUsages", "()[Landroid/os/CpuUsageInfo;",
             (void*) nativeGetCpuUsages }
 };
 
 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) {
-    gHardwarePropertiesModule = nullptr;
+    gThermalModule = nullptr;
     int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService",
                                        gHardwarePropertiesManagerServiceMethods,
                                        NELEM(gHardwarePropertiesManagerServiceMethods));
@@ -158,6 +200,12 @@
     gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
     gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
                                                          "<init>", "(JJ)V");
+
+    clazz = env->FindClass("android/os/HardwarePropertiesManager");
+    jfieldID undefined_temperature_field = GetStaticFieldIDOrDie(env, clazz,
+                                                                 "UNDEFINED_TEMPERATURE", "F");
+    gUndefinedTemperature = env->GetStaticFloatField(clazz, undefined_temperature_field);
+
     return res;
 }
 
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e39445a..ae05042 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -29,10 +29,11 @@
 #include "android_runtime/Log.h"
 
 #include <arpa/inet.h>
-#include <string.h>
-#include <pthread.h>
+#include <limits>
 #include <linux/in.h>
 #include <linux/in6.h>
+#include <pthread.h>
+#include <string.h>
 
 static jobject mCallbacksObj = NULL;
 
@@ -139,7 +140,7 @@
             ALOGD("Unknown constellation type with Svid = %d.", info.svid);
             info.constellation = GNSS_CONSTELLATION_UNKNOWN;
         }
-        info.snr = sv_status->sv_list[i].snr;
+        info.c_n0_dbhz = sv_status->sv_list[i].snr;
         info.elevation = sv_status->sv_list[i].elevation;
         info.azimuth = sv_status->sv_list[i].azimuth;
         info.flags = GNSS_SV_FLAGS_NONE;
@@ -697,12 +698,12 @@
 }
 
 static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
-        jintArray svidWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+        jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray,
         jfloatArray azumArray)
 {
     // this should only be called from within a call to reportSvStatus
     jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
-    jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
+    jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
 
@@ -712,13 +713,13 @@
         svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
             (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
             info.flags;
-        snrs[i] = info.snr;
+        cn0s[i] = info.c_n0_dbhz;
         elev[i] = info.elevation;
         azim[i] = info.azimuth;
     }
 
     env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
-    env->ReleaseFloatArrayElements(snrArray, snrs, 0);
+    env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
     env->ReleaseFloatArrayElements(elevArray, elev, 0);
     env->ReleaseFloatArrayElements(azumArray, azim, 0);
     return (jint) sGnssSvListSize;
@@ -1086,27 +1087,72 @@
 const char *const JavaMethodHelper<bool>::signature_ = "(Z)V";
 
 #define SET(setter, value) object.callSetter("set" # setter, (value))
-#define SET_IF(flag, setter, value) \
-        if (flags & (flag)) object.callSetter("set" # setter, (value))
+
+// If you want to check if a flag is not set, use SET_IF_NOT(FLAG, setter,
+// value) to do that. SET_IF(!FLAG, setter, value) won't compile.
+//
+// This macros generates compilation error if the provided 'flag' is not a
+// single token. For example, 'GNSS_CLOCK_HAS_BIAS' can be accepted, but
+// '!GNSS_CLOCK_HAS_DRIFT' will fail to compile.
+#define SET_IF(flag, setter, value) do { \
+        if (flags & flag) { \
+            JavaObject& name_check_##flag = object; \
+            name_check_##flag.callSetter("set" # setter, (value)); \
+        } \
+    } while (false)
+#define SET_IF_NOT(flag, setter, value) do { \
+        if (!(flags & flag)) { \
+            JavaObject& name_check_##flag = object; \
+            name_check_##flag.callSetter("set" # setter, (value)); \
+        } \
+    } while (false)
 
 static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+    static uint32_t discontinuity_count_to_handle_old_clock_type = 0;
     JavaObject object(env, "android/location/GnssClock");
     GpsClockFlags flags = clock->flags;
 
-    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
-    SET(Type, clock->type);
-    SET(TimeInNs, clock->time_ns);
+    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
+           LeapSecond,
+           static_cast<int32_t>(clock->leap_second));
+
+    // GnssClock only supports the more effective HW_CLOCK type, so type
+    // handling and documentation complexity has been removed.  To convert the
+    // old GPS_CLOCK types (active only in a limited number of older devices),
+    // the GPS time information is handled as an always discontinuous HW clock,
+    // with the GPS time information put into the full_bias_ns instead - so that
+    // time_ns + full_bias_ns = local estimate of GPS time (as remains true, in
+    // the new GnssClock struct.)
+    switch (clock->type) {
+      case GPS_CLOCK_TYPE_UNKNOWN:
+        // Clock type unsupported.
+        ALOGE("Unknown clock type provided.");
+        break;
+      case GPS_CLOCK_TYPE_LOCAL_HW_TIME:
+        // Already local hardware time. No need to do anything.
+        break;
+      case GPS_CLOCK_TYPE_GPS_TIME:
+        // GPS time, need to convert.
+        flags |= GNSS_CLOCK_HAS_FULL_BIAS;
+        clock->full_bias_ns = clock->time_ns;
+        clock->time_ns = 0;
+        SET(HardwareClockDiscontinuityCount,
+            discontinuity_count_to_handle_old_clock_type++);
+        break;
+    }
+
+    SET(TimeNanos, clock->time_ns);
     SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
-           TimeUncertaintyInNs,
+           TimeUncertaintyNanos,
            clock->time_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
-    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
     SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
-           BiasUncertaintyInNs,
+           BiasUncertaintyNanos,
            clock->bias_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
     SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
-           DriftUncertaintyInNsPerSec,
+           DriftUncertaintyNanosPerSecond,
            clock->drift_uncertainty_nsps);
 
     return object.get();
@@ -1116,20 +1162,21 @@
     JavaObject object(env, "android/location/GnssClock");
     GpsClockFlags flags = clock->flags;
 
-    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
-    SET(Type, static_cast<uint8_t>(GPS_CLOCK_TYPE_LOCAL_HW_TIME));
-    SET(TimeInNs, clock->time_ns);
+    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
+           LeapSecond,
+           static_cast<int32_t>(clock->leap_second));
+    SET(TimeNanos, clock->time_ns);
     SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
-           TimeUncertaintyInNs,
+           TimeUncertaintyNanos,
            clock->time_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
-    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
     SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
-           BiasUncertaintyInNs,
+           BiasUncertaintyNanos,
            clock->bias_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
     SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
-           DriftUncertaintyInNsPerSec,
+           DriftUncertaintyNanosPerSecond,
            clock->drift_uncertainty_nsps);
 
     SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count);
@@ -1141,41 +1188,30 @@
                                          GpsMeasurement* measurement) {
     JavaObject object(env, "android/location/GnssMeasurement");
     GpsMeasurementFlags flags = measurement->flags;
-    SET(Svid, static_cast<int16_t>(measurement->prn));
+    SET(Svid, static_cast<int32_t>(measurement->prn));
     if (measurement->prn >= 1 || measurement->prn <= 32) {
-        SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
     } else {
         ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
         SET(ConstellationType,
-            static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
+            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
     }
-    SET(TimeOffsetInNs, measurement->time_offset_ns);
-    SET(State, measurement->state);
-    SET(ReceivedSvTimeInNs, measurement->received_gps_tow_ns);
-    SET(ReceivedSvTimeUncertaintyInNs,
+    SET(TimeOffsetNanos, measurement->time_offset_ns);
+    SET(State, static_cast<int32_t>(measurement->state));
+    SET(ReceivedSvTimeNanos, measurement->received_gps_tow_ns);
+    SET(ReceivedSvTimeUncertaintyNanos,
         measurement->received_gps_tow_uncertainty_ns);
-    SET(Cn0InDbHz, measurement->c_n0_dbhz);
-    SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
-    SET(PseudorangeRateUncertaintyInMetersPerSec,
+    SET(Cn0DbHz, measurement->c_n0_dbhz);
+    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
+    SET(PseudorangeRateUncertaintyMetersPerSecond,
         measurement->pseudorange_rate_uncertainty_mps);
-    SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
-    SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
-    SET(AccumulatedDeltaRangeUncertaintyInMeters,
+    SET(AccumulatedDeltaRangeState,
+        static_cast<int32_t>(measurement->accumulated_delta_range_state));
+    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
+    SET(AccumulatedDeltaRangeUncertaintyMeters,
         measurement->accumulated_delta_range_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
-           PseudorangeInMeters,
-           measurement->pseudorange_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
-           PseudorangeUncertaintyInMeters,
-           measurement->pseudorange_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
-           CodePhaseInChips,
-           measurement->code_phase_chips);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
-           CodePhaseUncertaintyInChips,
-           measurement->code_phase_uncertainty_chips);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
-           CarrierFrequencyInHz,
+           CarrierFrequencyHz,
            measurement->carrier_frequency_hz);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
            CarrierCycles,
@@ -1186,33 +1222,9 @@
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
            CarrierPhaseUncertainty,
            measurement->carrier_phase_uncertainty);
-    SET(LossOfLock, measurement->loss_of_lock);
-    SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
-    SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
-           TimeFromLastBitInMs,
-           measurement->time_from_last_bit_ms);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
-           DopplerShiftInHz,
-           measurement->doppler_shift_hz);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
-           DopplerShiftUncertaintyInHz,
-           measurement->doppler_shift_uncertainty_hz);
-    SET(MultipathIndicator, measurement->multipath_indicator);
+    SET(MultipathIndicator,
+        static_cast<int32_t>(measurement->multipath_indicator));
     SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
-           ElevationInDeg,
-           measurement->elevation_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
-           ElevationUncertaintyInDeg,
-           measurement->elevation_uncertainty_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
-           AzimuthInDeg,
-           measurement->azimuth_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
-           AzimuthUncertaintyInDeg,
-           measurement->azimuth_uncertainty_deg);
-    SET(UsedInFix,
-        (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
 
     return object.get();
 }
@@ -1223,34 +1235,23 @@
     GpsMeasurementFlags flags = measurement->flags;
 
     SET(Svid, measurement->svid);
-    SET(ConstellationType, measurement->constellation);
-    SET(TimeOffsetInNs, measurement->time_offset_ns);
-    SET(State, measurement->state);
-    SET(ReceivedSvTimeInNs, measurement->received_sv_time_in_ns);
-    SET(ReceivedSvTimeUncertaintyInNs,
+    SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
+    SET(TimeOffsetNanos, measurement->time_offset_ns);
+    SET(State, static_cast<int32_t>(measurement->state));
+    SET(ReceivedSvTimeNanos, measurement->received_sv_time_in_ns);
+    SET(ReceivedSvTimeUncertaintyNanos,
         measurement->received_sv_time_uncertainty_in_ns);
-    SET(Cn0InDbHz, measurement->c_n0_dbhz);
-    SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
-    SET(PseudorangeRateUncertaintyInMetersPerSec,
+    SET(Cn0DbHz, measurement->c_n0_dbhz);
+    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
+    SET(PseudorangeRateUncertaintyMetersPerSecond,
         measurement->pseudorange_rate_uncertainty_mps);
-    SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
-    SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
-    SET(AccumulatedDeltaRangeUncertaintyInMeters,
+    SET(AccumulatedDeltaRangeState,
+        static_cast<int32_t>(measurement->accumulated_delta_range_state));
+    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
+    SET(AccumulatedDeltaRangeUncertaintyMeters,
         measurement->accumulated_delta_range_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
-           PseudorangeInMeters,
-           measurement->pseudorange_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
-           PseudorangeUncertaintyInMeters,
-           measurement->pseudorange_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
-           CodePhaseInChips,
-           measurement->code_phase_chips);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
-           CodePhaseUncertaintyInChips,
-           measurement->code_phase_uncertainty_chips);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
-           CarrierFrequencyInHz,
+           CarrierFrequencyHz,
            measurement->carrier_frequency_hz);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
            CarrierCycles,
@@ -1261,32 +1262,9 @@
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
            CarrierPhaseUncertainty,
            measurement->carrier_phase_uncertainty);
-    SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
-    SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
-           TimeFromLastBitInMs,
-           measurement->time_from_last_bit_ms);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
-           DopplerShiftInHz,
-           measurement->doppler_shift_hz);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
-           DopplerShiftUncertaintyInHz,
-           measurement->doppler_shift_uncertainty_hz);
-    SET(MultipathIndicator, measurement->multipath_indicator);
+    SET(MultipathIndicator,
+        static_cast<int32_t>(measurement->multipath_indicator));
     SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
-           ElevationInDeg,
-           measurement->elevation_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
-           ElevationUncertaintyInDeg,
-           measurement->elevation_uncertainty_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
-           AzimuthInDeg,
-           measurement->azimuth_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
-           AzimuthUncertaintyInDeg,
-           measurement->azimuth_uncertainty_deg);
-    SET(UsedInFix,
-        (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
 
     return object.get();
 }
@@ -1466,21 +1444,22 @@
         return NULL;
     }
     JavaObject object(env, "android/location/GnssNavigationMessage");
-    SET(Svid, static_cast<int16_t>(message->prn));
+    SET(Svid, static_cast<int32_t>(message->prn));
     if (message->prn >=1 && message->prn <= 32) {
-        SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
         // Legacy driver doesn't set the higher byte to constellation type
         // correctly. Set the higher byte to 'GPS'.
-        SET(Type, static_cast<int16_t>(message->type | 0x0100));
+        SET(Type, static_cast<int32_t>(message->type | 0x0100));
     } else {
         ALOGD("Unknown constellation type with Svid = %d.", message->prn);
         SET(ConstellationType,
-            static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
-        SET(Type, static_cast<int16_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
+            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
+        SET(Type, static_cast<int32_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
     }
-    SET(MessageId, message->message_id);
-    SET(SubmessageId, message->submessage_id);
+    SET(MessageId, static_cast<int32_t>(message->message_id));
+    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
     object.callSetter("setData", data, dataLength);
+    SET(Status, static_cast<int32_t>(message->status));
     return object.get();
 }
 
@@ -1493,11 +1472,12 @@
         return NULL;
     }
     JavaObject object(env, "android/location/GnssNavigationMessage");
-    SET(Type, message->type);
-    SET(Svid, message->svid);
-    SET(MessageId, message->message_id);
-    SET(SubmessageId, message->submessage_id);
+    SET(Type, static_cast<int32_t>(message->type));
+    SET(Svid, static_cast<int32_t>(message->svid));
+    SET(MessageId, static_cast<int32_t>(message->message_id));
+    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
     object.callSetter("setData", data, dataLength);
+    SET(Status, static_cast<int32_t>(message->status));
     return object.get();
 }
 
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 6c640ba..c4316f6 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -400,7 +400,7 @@
                 connection.mThread->shutdown();
             }
             connection.mThread = new BufferProducerThread(mDevice, deviceId, &stream);
-            connection.mThread->run();
+            connection.mThread->run("BufferProducerThread");
         }
     }
     connection.mSurface = surface;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 33225eb..42b5705 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,18 +21,21 @@
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.TEXT;
 
-import com.google.android.collect.Sets;
-
 import android.Manifest.permission;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accounts.AccountManager;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -48,10 +51,10 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.IDevicePolicyManager;
+import android.app.admin.SecurityLog;
+import android.app.admin.SecurityLog.SecurityEvent;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
-import android.auditing.SecurityLog;
-import android.auditing.SecurityLog.SecurityEvent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -82,6 +85,7 @@
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -112,6 +116,7 @@
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
 import android.service.persistentdata.PersistentDataBlockManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -131,6 +136,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.internal.util.ParcelableString;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
@@ -138,6 +144,7 @@
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
 import com.android.server.pm.UserRestrictionsUtils;
+import com.google.android.collect.Sets;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -151,6 +158,8 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
@@ -176,12 +185,16 @@
 
     private static final String DEVICE_POLICIES_XML = "device_policies.xml";
 
+    private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate";
+
     private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component";
 
     private static final String TAG_STATUS_BAR = "statusbar";
 
     private static final String ATTR_DISABLED = "disabled";
 
+    private static final String ATTR_NAME = "name";
+
     private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML =
             "do-not-ask-credentials-on-boot";
 
@@ -280,6 +293,20 @@
     private static final int PROFILE_KEYGUARD_FEATURES =
             PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
 
+    private static final int CODE_OK = 0;
+    private static final int CODE_HAS_DEVICE_OWNER = 1;
+    private static final int CODE_USER_HAS_PROFILE_OWNER = 2;
+    private static final int CODE_USER_NOT_RUNNING = 3;
+    private static final int CODE_USER_SETUP_COMPLETED = 4;
+    private static final int CODE_NONSYSTEM_USER_EXISTS = 5;
+    private static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
+    private static final int CODE_NOT_SYSTEM_USER = 7;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
+            CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER })
+    private @interface DeviceOwnerPreConditionCode {}
+
     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
 
     final Context mContext;
@@ -287,6 +314,7 @@
     final IPackageManager mIPackageManager;
     final UserManager mUserManager;
     final UserManagerInternal mUserManagerInternal;
+    final TelephonyManager mTelephonyManager;
     private final LockPatternUtils mLockPatternUtils;
 
     /**
@@ -308,7 +336,7 @@
      * Whether or not device admin feature is supported. If it isn't return defaults for all
      * public methods.
      */
-    private boolean mHasFeature;
+    boolean mHasFeature;
 
     private final SecurityLogMonitor mSecurityLogMonitor;
 
@@ -328,7 +356,7 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
+            if (DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
                     && mRemoteBugreportServiceIsActive.get()) {
                 onBugreportFinished(intent);
             }
@@ -342,10 +370,9 @@
             String action = intent.getAction();
             mInjector.getNotificationManager().cancel(LOG_TAG,
                     RemoteBugreportUtils.NOTIFICATION_ID);
-            if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
+            if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
                 onBugreportSharingAccepted();
-            } else if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED
-                    .equals(action)) {
+            } else if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
                 onBugreportSharingDeclined();
             }
             mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
@@ -398,6 +425,8 @@
         final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
         final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
 
+        final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();
+
         // This is the list of component allowed to start lock task mode.
         List<String> mLockTaskPackages = new ArrayList<>();
 
@@ -437,15 +466,14 @@
                     && userHandle == mOwners.getDeviceOwnerUserId()
                     && getDeviceOwnerRemoteBugreportUri() != null) {
                 IntentFilter filterConsent = new IntentFilter();
-                filterConsent.addAction(
-                        RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED);
-                filterConsent.addAction(
-                        RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED);
+                filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
+                filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
                 mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
-                mInjector.getNotificationManager().notify(LOG_TAG,
+                mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
                         RemoteBugreportUtils.NOTIFICATION_ID,
                         RemoteBugreportUtils.buildNotification(mContext,
-                                RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
+                                DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+                                UserHandle.ALL);
             }
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
@@ -462,12 +490,13 @@
             }
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
-                new MonitoringCertNotificationTask().execute(intent);
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+                new MonitoringCertNotificationTask().execute(userId);
             }
             if (Intent.ACTION_USER_ADDED.equals(action)) {
-                disableDeviceLoggingIfNotCompliant();
+                disableSecurityLoggingIfNotCompliant();
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                disableDeviceLoggingIfNotCompliant();
+                disableSecurityLoggingIfNotCompliant();
                 removeUserData(userHandle);
             } else if (Intent.ACTION_USER_STARTED.equals(action)) {
                 synchronized (DevicePolicyManagerService.this) {
@@ -633,8 +662,8 @@
         String shortSupportMessage = null;
         String longSupportMessage = null;
 
-        // Background color of confirm credentials screen. Default: gray.
-        static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
+        // Background color of confirm credentials screen. Default: teal.
+        static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B");
         int organizationColor = DEF_ORGANIZATION_COLOR;
 
         // Default title of confirm credentials screen
@@ -769,7 +798,7 @@
                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableContactsSearch));
                 out.endTag(null, TAG_DISABLE_CONTACTS_SEARCH);
             }
-            if (disableBluetoothContactSharing) {
+            if (!disableBluetoothContactSharing) {
                 out.startTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
                 out.attribute(null, ATTR_VALUE,
                         Boolean.toString(disableBluetoothContactSharing));
@@ -1102,9 +1131,7 @@
                 }
                 String tagDAM = parser.getName();
                 if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) {
-                    PersistableBundle bundle = new PersistableBundle();
-                    bundle.restoreFromXml(parser);
-                    result.options = bundle;
+                    result.options = PersistableBundle.restoreFromXml(parser);
                 } else {
                     Slog.w(LOG_TAG, "Unknown tag under " + tag +  ": " + tagDAM);
                 }
@@ -1254,10 +1281,10 @@
                     final String adminPackage = aa.info.getPackageName();
                     if (packageName == null || packageName.equals(adminPackage)) {
                         if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
-                                || mIPackageManager.getReceiverInfo(
-                                    aa.info.getComponent(),
-                                    PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
-                                    userHandle) == null) {
+                                || mIPackageManager.getReceiverInfo(aa.info.getComponent(),
+                                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                        userHandle) == null) {
                             removed = true;
                             policy.mAdminList.remove(i);
                             policy.mAdminMap.remove(aa.info.getComponent());
@@ -1337,6 +1364,10 @@
             return LocalServices.getService(PowerManagerInternal.class);
         }
 
+        TelephonyManager getTelephonyManager() {
+            return TelephonyManager.from(mContext);
+        }
+
         IWindowManager getIWindowManager() {
             return IWindowManager.Stub
                     .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -1363,6 +1394,22 @@
             return new LockPatternUtils(mContext);
         }
 
+        boolean storageManagerIsFileBasedEncryptionEnabled() {
+            return StorageManager.isFileEncryptedNativeOnly();
+        }
+
+        boolean storageManagerIsNonDefaultBlockEncrypted() {
+            return StorageManager.isNonDefaultBlockEncrypted();
+        }
+
+        boolean storageManagerIsEncrypted() {
+            return StorageManager.isEncrypted();
+        }
+
+        boolean storageManagerIsEncryptable() {
+            return StorageManager.isEncryptable();
+        }
+
         Looper getMyLooper() {
             return Looper.myLooper();
         }
@@ -1439,6 +1486,12 @@
             return "/data/system/";
         }
 
+        void registerContentObserver(Uri uri, boolean notifyForDescendents,
+                ContentObserver observer, int userHandle) {
+            mContext.getContentResolver().registerContentObserver(uri, notifyForDescendents,
+                    observer, userHandle);
+        }
+
         int settingsSecureGetIntForUser(String name, int def, int userHandle) {
             return Settings.Secure.getIntForUser(mContext.getContentResolver(),
                     name, def, userHandle);
@@ -1509,6 +1562,7 @@
         mUserManager = Preconditions.checkNotNull(injector.getUserManager());
         mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
         mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
+        mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager());
 
         mLocalService = new LocalService();
         mLockPatternUtils = injector.newLockPatternUtils();
@@ -1622,23 +1676,23 @@
         }
         // Still at the first stage of CryptKeeper double bounce, mOwners.hasDeviceOwner is
         // always false at this point.
-        if ("encrypted".equals(mInjector.systemPropertiesGet("ro.crypto.state"))
-                && "trigger_restart_min_framework".equals(
-                        mInjector.systemPropertiesGet("vold.decrypt"))){
+        if (StorageManager.inCryptKeeperBounce()) {
             return;
         }
 
         if (!TextUtils.isEmpty(mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT))) {
-            Slog.wtf(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?");
+            Slog.w(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?");
         } else {
             if (mOwners.hasDeviceOwner()) {
                 mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "true");
-                disableDeviceLoggingIfNotCompliant();
+                Slog.i(LOG_TAG, "Set ro.device_owner property to true");
+                disableSecurityLoggingIfNotCompliant();
                 if (mInjector.securityLogGetLoggingEnabledProperty()) {
                     mSecurityLogMonitor.start();
                 }
             } else {
                 mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "false");
+                Slog.i(LOG_TAG, "Set ro.device_owner property to false");
             }
         }
     }
@@ -2053,31 +2107,32 @@
             return null;
         }
         enforceFullCrossUsersPermission(userHandle);
-        Intent resolveIntent = new Intent();
-        resolveIntent.setComponent(adminName);
-        List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceiversAsUser(
-                resolveIntent,
-                PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
-                PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
-                userHandle);
-        if (infos == null || infos.size() <= 0) {
+        ActivityInfo ai = null;
+        try {
+            ai = mIPackageManager.getReceiverInfo(adminName,
+                    PackageManager.GET_META_DATA |
+                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS |
+                    PackageManager.MATCH_DIRECT_BOOT_AWARE |
+                    PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
+        } catch (RemoteException e) {
+            // shouldn't happen.
+        }
+        if (ai == null) {
             throw new IllegalArgumentException("Unknown admin: " + adminName);
         }
 
-        final ResolveInfo ri = infos.get(0);
-
-        if (!permission.BIND_DEVICE_ADMIN.equals(ri.activityInfo.permission)) {
+        if (!permission.BIND_DEVICE_ADMIN.equals(ai.permission)) {
             final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
                     + permission.BIND_DEVICE_ADMIN;
             Slog.w(LOG_TAG, message);
             if (throwForMissiongPermission &&
-                    ri.activityInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
+                    ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
                 throw new IllegalArgumentException(message);
             }
         }
 
         try {
-            return new DeviceAdminInfo(mContext, ri);
+            return new DeviceAdminInfo(mContext, ai);
         } catch (XmlPullParserException | IOException e) {
             Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
                     e);
@@ -2172,6 +2227,12 @@
                 out.endTag(null, "active-password");
             }
 
+            for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) {
+                out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+                out.attribute(null, ATTR_NAME, policy.mAcceptedCaCertificates.valueAt(i));
+                out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+            }
+
             for (int i=0; i<policy.mLockTaskPackages.size(); i++) {
                 String component = policy.mLockTaskPackages.get(i);
                 out.startTag(null, TAG_LOCK_TASK_COMPONENTS);
@@ -2338,6 +2399,8 @@
                             parser.getAttributeValue(null, "symbols"));
                     policy.mActivePasswordNonLetter = Integer.parseInt(
                             parser.getAttributeValue(null, "nonletter"));
+                } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) {
+                    policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME));
                 } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
                     policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
                 } else if (TAG_STATUS_BAR.equals(tag)) {
@@ -2493,7 +2556,7 @@
         onStartUser(UserHandle.USER_SYSTEM);
 
         // Register an observer for watching for user setup complete.
-        new SetupContentObserver(mHandler).register(mContext.getContentResolver());
+        new SetupContentObserver(mHandler).register();
         // Initialize the user setup state, to handle the upgrade case.
         updateUserSetupComplete();
 
@@ -2589,17 +2652,17 @@
         }
     }
 
-    private class MonitoringCertNotificationTask extends AsyncTask<Intent, Void, Void> {
+    private class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Void> {
         @Override
-        protected Void doInBackground(Intent... params) {
-            int userHandle = params[0].getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+        protected Void doInBackground(Integer... params) {
+            int userHandle = params[0];
 
             if (userHandle == UserHandle.USER_ALL) {
                 for (UserInfo userInfo : mUserManager.getUsers()) {
                     manageNotification(userInfo.getUserHandle());
                 }
             } else {
-                manageNotification(new UserHandle(userHandle));
+                manageNotification(UserHandle.of(userHandle));
             }
             return null;
         }
@@ -2609,25 +2672,27 @@
                 return;
             }
 
-            // Call out to KeyChain to check for user-added CAs
-            boolean hasCert = false;
+            // Call out to KeyChain to check for CAs which are waiting for approval.
+            final List<String> pendingCertificates;
             try {
-                KeyChainConnection kcs = KeyChain.bindAsUser(mContext, userHandle);
-                try {
-                    if (!kcs.getService().getUserCaAliases().getList().isEmpty()) {
-                        hasCert = true;
-                    }
-                } catch (RemoteException e) {
-                    Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
-                } finally {
-                    kcs.close();
-                }
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            } catch (RuntimeException e) {
-                Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
+                pendingCertificates = getInstalledCaCertificates(userHandle);
+            } catch (RemoteException | RuntimeException e) {
+                Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
+                return;
             }
-            if (!hasCert) {
+
+            synchronized (DevicePolicyManagerService.this) {
+                final DevicePolicyData policy = getUserData(userHandle.getIdentifier());
+
+                // Remove deleted certificates. Flush xml if necessary.
+                if (policy.mAcceptedCaCertificates.retainAll(pendingCertificates)) {
+                    saveSettingsLocked(userHandle.getIdentifier());
+                }
+                // Trim to approved certificates.
+                pendingCertificates.removeAll(policy.mAcceptedCaCertificates);
+            }
+
+            if (pendingCertificates.isEmpty()) {
                 mInjector.getNotificationManager().cancelAsUser(
                         null, MONITORING_CERT_NOTIFICATION_ID, userHandle);
                 return;
@@ -2658,7 +2723,8 @@
 
             final Context userContext;
             try {
-                userContext = mContext.createPackageContextAsUser("android", 0, userHandle);
+                final String packageName = mContext.getPackageName();
+                userContext = mContext.createPackageContextAsUser(packageName, 0, userHandle);
             } catch (PackageManager.NameNotFoundException e) {
                 Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
                 return;
@@ -2677,6 +2743,29 @@
             mInjector.getNotificationManager().notifyAsUser(
                     null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
         }
+
+        private List<String> getInstalledCaCertificates(UserHandle userHandle)
+                throws RemoteException, RuntimeException {
+            KeyChainConnection conn = null;
+            try {
+                conn = KeyChain.bindAsUser(mContext, userHandle);
+                List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
+                List<String> result = new ArrayList<>(aliases.size());
+                for (int i = 0; i < aliases.size(); i++) {
+                    result.add(aliases.get(i).string);
+                }
+                return result;
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                return null;
+            } catch (AssertionError e) {
+                throw new RuntimeException(e);
+            } finally {
+                if (conn != null) {
+                    conn.close();
+                }
+            }
+        }
     }
 
     /**
@@ -2714,6 +2803,10 @@
                         && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
                     throw new IllegalArgumentException("Admin is already added");
                 }
+                if (policy.mRemovingAdmins.contains(adminReceiver)) {
+                    throw new IllegalArgumentException(
+                            "Trying to set an admin which is being removed");
+                }
                 ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
                 policy.mAdminMap.put(adminReceiver, newAdmin);
                 int replaceIndex = -1;
@@ -2853,13 +2946,9 @@
     @Override
     public boolean isSeparateProfileChallengeAllowed(int userHandle) {
         ComponentName profileOwner = getProfileOwner(userHandle);
-        try {
-            // Profile challenge is supported on N or newer release.
-            return profileOwner != null &&
-                    getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
-        } catch (RemoteException e) {
-            return false;
-        }
+        // Profile challenge is supported on N or newer release.
+        return profileOwner != null &&
+                getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
     }
 
     @Override
@@ -2919,7 +3008,7 @@
             ArrayList<ActiveAdmin> admins = new ArrayList<ActiveAdmin>();
             for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
                 DevicePolicyData policy = getUserData(userInfo.id);
-                if (!isManagedProfile(userInfo.id)) {
+                if (!userInfo.isManagedProfile()) {
                     admins.addAll(policy.mAdminList);
                 } else {
                     // For managed profiles, we always include the policies set on the parent
@@ -3628,7 +3717,7 @@
             if (count == 0 ||
                     count > admin.maximumFailedPasswordsForWipe ||
                     (count == admin.maximumFailedPasswordsForWipe &&
-                            mUserManager.getUserInfo(userId).isPrimary())) {
+                            getUserInfo(userId).isPrimary())) {
                 count = admin.maximumFailedPasswordsForWipe;
                 strictestAdmin = admin;
             }
@@ -3636,6 +3725,15 @@
         return strictestAdmin;
     }
 
+    private UserInfo getUserInfo(@UserIdInt int userId) {
+        final long token = mInjector.binderClearCallingIdentity();
+        try {
+            return mUserManager.getUserInfo(userId);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
     @Override
     public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException {
         if (!mHasFeature) {
@@ -3644,32 +3742,26 @@
         final int callingUid = mInjector.binderGetCallingUid();
         final int userHandle = mInjector.userHandleGetCallingUserId();
 
-        if (getCredentialOwner(userHandle, /* parent */ false) != userHandle) {
-            throw new SecurityException("You can not change password for this profile because"
-                    + " it shares the password with the owner profile");
-        }
-
         String password = passwordOrNull != null ? passwordOrNull : "";
 
+        // Password resetting to empty/null is not allowed for managed profiles.
+        if (TextUtils.isEmpty(password)) {
+            enforceNotManagedProfile(userHandle, "clear the active password");
+        }
+
         int quality;
         synchronized (this) {
-            // If caller has PO (or DO), it can clear the password, so see if that's the case
-            // first.
+            // If caller has PO (or DO) it can change the password, so see if that's the case first.
             ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
                     null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid);
             if (admin == null) {
                 // Otherwise, make sure the caller has any active admin with the right policy.
                 admin = getActiveAdminForCallerLocked(null,
                         DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
-            }
 
-            final ComponentName adminComponent = admin.info.getComponent();
-
-            // As of N, only profile owners and device owners can reset the password.
-            if (!(isProfileOwner(adminComponent, userHandle)
-                    || isDeviceOwner(adminComponent, userHandle))) {
                 final boolean preN = getTargetSdk(admin.info.getPackageName(), userHandle)
                         <= android.os.Build.VERSION_CODES.M;
+
                 // As of N, password resetting to empty/null is not allowed anymore.
                 // TODO Should we allow DO/PO to set an empty password?
                 if (TextUtils.isEmpty(password)) {
@@ -3798,6 +3890,9 @@
         // back in to the service.
         final long ident = mInjector.binderClearCallingIdentity();
         try {
+            if (isManagedProfile(userHandle)) {
+                mLockPatternUtils.setSeparateProfileChallengeEnabled(userHandle, true);
+            }
             if (!TextUtils.isEmpty(password)) {
                 mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
             } else {
@@ -4022,6 +4117,29 @@
     }
 
     @Override
+    public boolean approveCaCert(String alias, int userId, boolean approval) {
+        enforceManageUsers();
+        synchronized (this) {
+            Set<String> certs = getUserData(userId).mAcceptedCaCertificates;
+            boolean changed = (approval ? certs.add(alias) : certs.remove(alias));
+            if (!changed) {
+                return false;
+            }
+            saveSettingsLocked(userId);
+        }
+        new MonitoringCertNotificationTask().execute(userId);
+        return true;
+    }
+
+    @Override
+    public boolean isCaCertApproved(String alias, int userId) {
+        enforceManageUsers();
+        synchronized (this) {
+            return getUserData(userId).mAcceptedCaCertificates.contains(alias);
+        }
+    }
+
+    @Override
     public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
         enforceCanManageCaCerts(admin);
 
@@ -4090,16 +4208,24 @@
     }
 
     @Override
-    public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) {
+    public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, byte[] chain,
+            String alias, boolean requestAccess) {
         enforceCanManageInstalledKeys(who);
 
-        final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+        final int callingUid = mInjector.binderGetCallingUid();
         final long id = mInjector.binderClearCallingIdentity();
         try {
-            final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
+            final KeyChainConnection keyChainConnection =
+                    KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
             try {
                 IKeyChainService keyChain = keyChainConnection.getService();
-                return keyChain.installKeyPair(privKey, cert, alias);
+                if (!keyChain.installKeyPair(privKey, cert, chain, alias)) {
+                    return false;
+                }
+                if (requestAccess) {
+                    keyChain.setGrant(callingUid, alias, true);
+                }
+                return true;
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, "Installing certificate", e);
             } finally {
@@ -4206,15 +4332,12 @@
         int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            try {
-                if (getTargetSdk(who.getPackageName(), userHandle) >= Build.VERSION_CODES.N) {
-                    if (installerPackage != null &&
-                            !isPackageInstalledForUser(installerPackage, userHandle)) {
-                        throw new IllegalArgumentException("Package " + installerPackage
-                                + " is not installed on the current user");
-                    }
+            if (getTargetSdk(who.getPackageName(), userHandle) >= Build.VERSION_CODES.N) {
+                if (installerPackage != null &&
+                        !isPackageInstalledForUser(installerPackage, userHandle)) {
+                    throw new IllegalArgumentException("Package " + installerPackage
+                            + " is not installed on the current user");
                 }
-            } catch (RemoteException e) {
             }
             DevicePolicyData policy = getUserData(userHandle);
             policy.mDelegatedCertInstallerPackage = installerPackage;
@@ -4232,6 +4355,13 @@
         }
     }
 
+    /**
+     * @return {@code true} if the package is installed and set as always-on, {@code false} if it is
+     * not installed and therefore not available.
+     *
+     * @throws SecurityException if the caller is not a profile or device owner.
+     * @throws UnsupportedException if the package does not support being set as always-on.
+     */
     @Override
     public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage)
             throws SecurityException {
@@ -4241,13 +4371,19 @@
 
         final int userId = mInjector.userHandleGetCallingUserId();
         final long token = mInjector.binderClearCallingIdentity();
-        try{
+        try {
+            if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
+                return false;
+            }
             ConnectivityManager connectivityManager = (ConnectivityManager)
                     mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-            return connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage);
+            if (!connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage)) {
+                throw new UnsupportedOperationException();
+            }
         } finally {
             mInjector.binderRestoreCallingIdentity(token);
         }
+        return true;
     }
 
     @Override
@@ -4805,12 +4941,37 @@
      * Get the current encryption status of the device.
      */
     @Override
-    public int getStorageEncryptionStatus(int userHandle) {
+    public int getStorageEncryptionStatus(@Nullable String callerPackage, int userHandle) {
         if (!mHasFeature) {
             // Ok to return current status.
         }
         enforceFullCrossUsersPermission(userHandle);
-        return getEncryptionStatus();
+
+        // It's not critical here, but let's make sure the package name is correct, in case
+        // we start using it for different purposes.
+        ensureCallerPackage(callerPackage);
+
+        final ApplicationInfo ai;
+        try {
+            ai = mIPackageManager.getApplicationInfo(callerPackage, 0, userHandle);
+        } catch (RemoteException e) {
+            throw new SecurityException(e);
+        }
+
+        boolean legacyApp = false;
+        if (ai.targetSdkVersion <= Build.VERSION_CODES.M) {
+            legacyApp = true;
+        } else if ("com.google.android.apps.enterprise.dmagent".equals(ai.packageName)
+                && ai.versionCode == 697) {
+            // TODO: STOPSHIP remove this (revert ag/895987) once a new prebuilt is dropped
+            legacyApp = true;
+        }
+
+        final int rawStatus = getEncryptionStatus();
+        if ((rawStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) {
+            return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
+        }
+        return rawStatus;
     }
 
     /**
@@ -4828,21 +4989,18 @@
      * Hook to low-levels:  Reporting the current status of encryption.
      * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED},
      * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE},
-     * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY}, or
+     * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY},
+     * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE_PER_USER}, or
      * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
      */
     private int getEncryptionStatus() {
-        String status = mInjector.systemPropertiesGet("ro.crypto.state", "unsupported");
-        if ("encrypted".equalsIgnoreCase(status)) {
-            final long token = mInjector.binderClearCallingIdentity();
-            try {
-                return LockPatternUtils.isDeviceEncrypted()
-                        ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
-                        : DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY;
-            } finally {
-                mInjector.binderRestoreCallingIdentity(token);
-            }
-        } else if ("unencrypted".equalsIgnoreCase(status)) {
+        if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
+            return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+        } else if (mInjector.storageManagerIsNonDefaultBlockEncrypted()) {
+            return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
+        } else if (mInjector.storageManagerIsEncrypted()) {
+            return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY;
+        } else if (mInjector.storageManagerIsEncryptable()) {
             return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
         } else {
             return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
@@ -4855,7 +5013,6 @@
     private void setEncryptionRequested(boolean encrypt) {
     }
 
-
     /**
      * Set whether the screen capture is disabled for the user managed by the specified admin.
      */
@@ -4970,7 +5127,7 @@
         Preconditions.checkNotNull(who, "ComponentName is null");
         // Allow setting this policy to true only if there is a split system user.
         if (forceEphemeralUsers && !mInjector.userManagerIsSplitSystemUser()) {
-            throw new IllegalArgumentException(
+            throw new UnsupportedOperationException(
                     "Cannot force ephemeral users on systems without split system user.");
         }
         boolean removeAllUsers = false;
@@ -5060,9 +5217,9 @@
             mRemoteBugreportServiceIsActive.set(true);
             mRemoteBugreportSharingAccepted.set(false);
             registerRemoteBugreportReceivers();
-            mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
                     RemoteBugreportUtils.buildNotification(mContext,
-                            RemoteBugreportUtils.NOTIFICATION_BUGREPORT_STARTED));
+                            DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
             mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
                     RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
             return true;
@@ -5096,7 +5253,7 @@
     private void registerRemoteBugreportReceivers() {
         try {
             IntentFilter filterFinished = new IntentFilter(
-                    RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH,
+                    DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH,
                     RemoteBugreportUtils.BUGREPORT_MIMETYPE);
             mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
         } catch (IntentFilter.MalformedMimeTypeException e) {
@@ -5104,8 +5261,8 @@
             Slog.w(LOG_TAG, "Failed to set type " + RemoteBugreportUtils.BUGREPORT_MIMETYPE, e);
         }
         IntentFilter filterConsent = new IntentFilter();
-        filterConsent.addAction(RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED);
-        filterConsent.addAction(RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED);
+        filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
+        filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
         mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
     }
 
@@ -5118,16 +5275,17 @@
             bugreportUriString = bugreportUri.toString();
         }
         String bugreportHash = intent.getStringExtra(
-                RemoteBugreportUtils.EXTRA_REMOTE_BUGREPORT_HASH);
+                DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
         if (mRemoteBugreportSharingAccepted.get()) {
             shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
             mInjector.getNotificationManager().cancel(LOG_TAG,
                     RemoteBugreportUtils.NOTIFICATION_ID);
         } else {
             setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
-            mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
                     RemoteBugreportUtils.buildNotification(mContext,
-                            RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
+                            DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+                            UserHandle.ALL);
         }
         mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
     }
@@ -5158,9 +5316,10 @@
         if (bugreportUriString != null) {
             shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
         } else if (mRemoteBugreportServiceIsActive.get()) {
-            mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
                     RemoteBugreportUtils.buildNotification(mContext,
-                            RemoteBugreportUtils.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED));
+                            DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
+                            UserHandle.ALL);
         }
     }
 
@@ -5522,7 +5681,8 @@
         Preconditions.checkNotNull(packageName, "packageName is null");
         final int callingUid = mInjector.binderGetCallingUid();
         try {
-            int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, 0);
+            int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
+                    UserHandle.getUserId(callingUid));
             if (uid != callingUid) {
                 throw new SecurityException("Invalid packageName");
             }
@@ -5552,7 +5712,7 @@
             mOwners.clearDeviceOwner();
             mOwners.writeDeviceOwner();
             updateDeviceOwnerLocked();
-            disableDeviceLoggingIfNotCompliant();
+            disableSecurityLoggingIfNotCompliant();
             // Reactivate backup service.
             long ident = mInjector.binderClearCallingIdentity();
             try {
@@ -5619,26 +5779,25 @@
     }
 
     @Override
-    public boolean setDeviceOwnerLockScreenInfo(ComponentName who, String info) {
+    public void setDeviceOwnerLockScreenInfo(ComponentName who, CharSequence info) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         if (!mHasFeature) {
-            return false;
+            return;
         }
 
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             long token = mInjector.binderClearCallingIdentity();
             try {
-                mLockPatternUtils.setDeviceOwnerInfo(info);
+                mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null);
             } finally {
                 mInjector.binderRestoreCallingIdentity(token);
             }
-            return true;
         }
     }
 
     @Override
-    public String getDeviceOwnerLockScreenInfo() {
+    public CharSequence getDeviceOwnerLockScreenInfo() {
         return mLockPatternUtils.getDeviceOwnerInfo();
     }
 
@@ -5720,8 +5879,7 @@
                 transitionCheckNeeded = false;
             } else {
                 // For all other cases, caller must have MANAGE_PROFILE_AND_DEVICE_OWNERS.
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+                enforceCanManageProfileAndDeviceOwners();
             }
 
             final DevicePolicyData policyData = getUserData(userHandle);
@@ -5888,7 +6046,7 @@
      * - adb if there are not accounts.
      */
     private void enforceCanSetProfileOwnerLocked(int userHandle) {
-        UserInfo info = mUserManager.getUserInfo(userHandle);
+        UserInfo info = getUserInfo(userHandle);
         if (info == null) {
             // User doesn't exist.
             throw new IllegalArgumentException(
@@ -5914,8 +6072,7 @@
             }
             return;
         }
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+        enforceCanManageProfileAndDeviceOwners();
         if (hasUserSetupCompleted(userHandle) && !isCallerWithSystemUid()) {
             throw new IllegalStateException("Cannot set the profile owner on a user which is "
                     + "already set-up");
@@ -5925,52 +6082,39 @@
     /**
      * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
      * permission.
-     * The device owner can only be set before the setup phase of the primary user has completed,
-     * except for adb if no accounts or additional users are present on the device.
      */
     private void enforceCanSetDeviceOwnerLocked(int userId) {
-        if (mOwners.hasDeviceOwner()) {
-            throw new IllegalStateException("Trying to set the device owner, but device owner "
-                    + "is already set.");
-        }
-        if (mOwners.hasProfileOwner(userId)) {
-            throw new IllegalStateException("Trying to set the device owner, but the user already "
-                    + "has a profile owner.");
-        }
-        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
-            throw new IllegalStateException("User not running: " + userId);
-        }
-
         int callingUid = mInjector.binderGetCallingUid();
-        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
-            if (!hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
-                return;
-            }
-            // STOPSHIP Do proper check in split user mode
-            if (!mInjector.userManagerIsSplitSystemUser()) {
-                if (mUserManager.getUserCount() > 1) {
-                    throw new IllegalStateException(
-                            "Not allowed to set the device owner because there "
-                                    + "are already several users on the device");
-                }
-                if (AccountManager.get(mContext).getAccounts().length > 0) {
-                    throw new IllegalStateException(
-                            "Not allowed to set the device owner because there "
-                                    + "are already some accounts on the device");
-                }
-            }
-            return;
+        boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
+        if (!isAdb) {
+            enforceCanManageProfileAndDeviceOwners();
         }
-        // STOPSHIP check the caller UID with userId
 
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
-        // STOPSHIP Do proper check in split user mode
-        if (!mInjector.userManagerIsSplitSystemUser()) {
-            if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
-                throw new IllegalStateException("Cannot set the device owner if the device is "
-                        + "already set-up");
-            }
+        final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
+        switch (code) {
+            case CODE_OK:
+                return;
+            case CODE_HAS_DEVICE_OWNER:
+                throw new IllegalStateException(
+                        "Trying to set the device owner, but device owner is already set.");
+            case CODE_USER_HAS_PROFILE_OWNER:
+                throw new IllegalStateException("Trying to set the device owner, but the user "
+                        + "already has a profile owner.");
+            case CODE_USER_NOT_RUNNING:
+                throw new IllegalStateException("User not running: " + userId);
+            case CODE_NOT_SYSTEM_USER:
+                throw new IllegalStateException("User is not system user");
+            case CODE_USER_SETUP_COMPLETED:
+                throw new IllegalStateException(
+                        "Cannot set the device owner if the device is already set-up");
+            case CODE_NONSYSTEM_USER_EXISTS:
+                throw new IllegalStateException("Not allowed to set the device owner because there "
+                        + "are already several users on the device");
+            case CODE_ACCOUNTS_NOT_EMPTY:
+                throw new IllegalStateException("Not allowed to set the device owner because there "
+                        + "are already some accounts on the device");
+            default:
+                throw new IllegalStateException("Unknown @DeviceOwnerPreConditionCode " + code);
         }
     }
 
@@ -6022,6 +6166,23 @@
         }
     }
 
+    private void ensureCallerPackage(@Nullable String packageName) {
+        if (packageName == null) {
+            Preconditions.checkState(isCallerWithSystemUid(),
+                    "Only caller can omit package name");
+        } else {
+            final int callingUid = mInjector.binderGetCallingUid();
+            final int userId = mInjector.userHandleGetCallingUserId();
+            try {
+                final ApplicationInfo ai = mIPackageManager.getApplicationInfo(
+                        packageName, 0, userId);
+                Preconditions.checkState(ai.uid == callingUid, "Unmatching package name");
+            } catch (RemoteException e) {
+                // Shouldn't happen
+            }
+        }
+    }
+
     private boolean isCallerWithSystemUid() {
         return UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID);
     }
@@ -6052,12 +6213,7 @@
     }
 
     private boolean isManagedProfile(int userHandle) {
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            return mUserManager.getUserInfo(userHandle).isManagedProfile();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        return getUserInfo(userHandle).isManagedProfile();
     }
 
     private void enableIfNecessary(String packageName, int userId) {
@@ -6112,6 +6268,27 @@
                 pw.println(" ");
                 pw.print("    mPasswordOwner="); pw.println(policy.mPasswordOwner);
             }
+            pw.println();
+            pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
+        }
+    }
+
+    private String getEncryptionStatusName(int encryptionStatus) {
+        switch (encryptionStatus) {
+            case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
+                return "inactive";
+            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY:
+                return "block default key";
+            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
+                return "block";
+            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER:
+                return "per-user";
+            case DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED:
+                return "unsupported";
+            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING:
+                return "activating";
+            default:
+                return "unknown";
         }
     }
 
@@ -6153,19 +6330,20 @@
     }
 
     @Override
-    public void setApplicationRestrictionsManagingPackage(ComponentName admin, String packageName) {
+    public boolean setApplicationRestrictionsManagingPackage(ComponentName admin,
+            String packageName) {
         Preconditions.checkNotNull(admin, "ComponentName is null");
 
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (packageName != null && !isPackageInstalledForUser(packageName, userHandle)) {
-                throw new IllegalArgumentException("Package " + packageName + " is not installed "
-                        + "on the current user");
+                return false;
             }
             DevicePolicyData policy = getUserData(userHandle);
             policy.mApplicationRestrictionsManagingPackage = packageName;
             saveSettingsLocked(userHandle);
+            return true;
         }
     }
 
@@ -6228,17 +6406,16 @@
 
     @Override
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName agent,
-            PersistableBundle args) {
+            PersistableBundle args, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(admin, "admin is null");
         Preconditions.checkNotNull(agent, "agent is null");
         final int userHandle = UserHandle.getCallingUserId();
-        enforceNotManagedProfile(userHandle, "set trust agent configuration");
         synchronized (this) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
-                    DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
+                    DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES, parent);
             ap.trustAgentInfos.put(agent.flattenToString(), new TrustAgentInfo(args));
             saveSettingsLocked(userHandle);
         }
@@ -6246,7 +6423,7 @@
 
     @Override
     public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
-            ComponentName agent, int userHandle) {
+            ComponentName agent, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return null;
         }
@@ -6256,46 +6433,44 @@
         synchronized (this) {
             final String componentName = agent.flattenToString();
             if (admin != null) {
-                final ActiveAdmin ap = getActiveAdminUncheckedLocked(admin, userHandle);
+                final ActiveAdmin ap = getActiveAdminUncheckedLocked(admin, userHandle, parent);
                 if (ap == null) return null;
                 TrustAgentInfo trustAgentInfo = ap.trustAgentInfos.get(componentName);
                 if (trustAgentInfo == null || trustAgentInfo.options == null) return null;
-                List<PersistableBundle> result = new ArrayList<PersistableBundle>();
+                List<PersistableBundle> result = new ArrayList<>();
                 result.add(trustAgentInfo.options);
                 return result;
             }
 
             // Return strictest policy for this user and profiles that are visible from this user.
-            final List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
             List<PersistableBundle> result = null;
-
             // Search through all admins that use KEYGUARD_DISABLE_TRUST_AGENTS and keep track
             // of the options. If any admin doesn't have options, discard options for the rest
             // and return null.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
             boolean allAdminsHaveOptions = true;
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i < N; i++) {
-                    final ActiveAdmin active = policy.mAdminList.get(i);
-                    final boolean disablesTrust = (active.disabledKeyguardFeatures
-                            & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
-                    final TrustAgentInfo info = active.trustAgentInfos.get(componentName);
-                    if (info != null && info.options != null && !info.options.isEmpty()) {
-                        if (disablesTrust) {
-                            if (result == null) {
-                                result = new ArrayList<PersistableBundle>();
-                            }
-                            result.add(info.options);
-                        } else {
-                            Log.w(LOG_TAG, "Ignoring admin " + active.info
-                                    + " because it has trust options but doesn't declare "
-                                    + "KEYGUARD_DISABLE_TRUST_AGENTS");
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                final ActiveAdmin active = admins.get(i);
+
+                final boolean disablesTrust = (active.disabledKeyguardFeatures
+                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+                final TrustAgentInfo info = active.trustAgentInfos.get(componentName);
+                if (info != null && info.options != null && !info.options.isEmpty()) {
+                    if (disablesTrust) {
+                        if (result == null) {
+                            result = new ArrayList<>();
                         }
-                    } else if (disablesTrust) {
-                        allAdminsHaveOptions = false;
-                        break;
+                        result.add(info.options);
+                    } else {
+                        Log.w(LOG_TAG, "Ignoring admin " + active.info
+                                + " because it has trust options but doesn't declare "
+                                + "KEYGUARD_DISABLE_TRUST_AGENTS");
                     }
+                } else if (disablesTrust) {
+                    allAdminsHaveOptions = false;
+                    break;
                 }
             }
             return allAdminsHaveOptions ? result : null;
@@ -6396,7 +6571,7 @@
         try {
             // If we have an enabled packages list for a managed profile the packages
             // we should check are installed for the parent user.
-            UserInfo user = mUserManager.getUserInfo(userIdToCheck);
+            UserInfo user = getUserInfo(userIdToCheck);
             if (user.isManagedProfile()) {
                 userIdToCheck = user.profileGroupId;
             }
@@ -6442,7 +6617,7 @@
             List<AccessibilityServiceInfo> enabledServices = null;
             long id = mInjector.binderClearCallingIdentity();
             try {
-                UserInfo user = mUserManager.getUserInfo(userId);
+                UserInfo user = getUserInfo(userId);
                 if (user.isManagedProfile()) {
                     userId = user.profileGroupId;
                 }
@@ -6524,7 +6699,7 @@
             if (result != null) {
                 long id = mInjector.binderClearCallingIdentity();
                 try {
-                    UserInfo user = mUserManager.getUserInfo(userId);
+                    UserInfo user = getUserInfo(userId);
                     if (user.isManagedProfile()) {
                         userId = user.profileGroupId;
                     }
@@ -6565,6 +6740,9 @@
         }
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin == null) {
+                return false;
+            }
             if (admin.permittedAccessiblityServices == null) {
                 return true;
             }
@@ -6578,7 +6756,7 @@
         long token = mInjector.binderClearCallingIdentity();
         try {
             UserInfo currentUser;
-            UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
+            UserInfo callingUser = getUserInfo(callingUserId);
             try {
                 currentUser = mInjector.getIActivityManager().getCurrentUser();
             } catch (RemoteException e) {
@@ -6735,6 +6913,9 @@
         }
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin == null) {
+                return false;
+            }
             if (admin.permittedInputMethods == null) {
                 return true;
             }
@@ -6743,57 +6924,6 @@
         }
     }
 
-    @Override
-    public UserHandle createUser(ComponentName who, String name) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        synchronized (this) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-
-            long id = mInjector.binderClearCallingIdentity();
-            try {
-                UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */);
-                if (userInfo != null) {
-                    return userInfo.getUserHandle();
-                }
-                return null;
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
-            }
-        }
-    }
-
-    @Override
-    public UserHandle createAndInitializeUser(ComponentName who, String name,
-            String ownerName, ComponentName profileOwnerComponent, Bundle adminExtras) {
-        UserHandle user = createUser(who, name);
-        if (user == null) {
-            return null;
-        }
-        long id = mInjector.binderClearCallingIdentity();
-        try {
-            String profileOwnerPkg = profileOwnerComponent.getPackageName();
-
-            final int userHandle = user.getIdentifier();
-            try {
-                // Install the profile owner if not present.
-                if (!mIPackageManager.isPackageAvailable(profileOwnerPkg, userHandle)) {
-                    mIPackageManager.installExistingPackageAsUser(profileOwnerPkg, userHandle);
-                }
-
-                // Start user in background.
-                mInjector.getIActivityManager().startUserInBackground(userHandle);
-            } catch (RemoteException e) {
-                Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
-            }
-
-            setActiveAdmin(profileOwnerComponent, true, userHandle, adminExtras);
-            setProfileOwner(profileOwnerComponent, ownerName, userHandle);
-            return user;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
-    }
-
     private void sendAdminEnabledBroadcastLocked(int userHandle) {
         DevicePolicyData policyData = getUserData(userHandle);
         if (policyData.mAdminBroadcastPending) {
@@ -6968,7 +7098,7 @@
     }
 
     @Override
-    public boolean getPackageSuspended(ComponentName who, String packageName) {
+    public boolean isPackageSuspended(ComponentName who, String packageName) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
@@ -7056,19 +7186,30 @@
     }
 
     @Override
-    public Bundle getUserRestrictions(ComponentName who, int userHandle) {
+    public Bundle getUserRestrictions(ComponentName who) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return activeAdmin.userRestrictions;
+        }
+    }
+
+    @Override
+    public Bundle getUserRestrictionsForUser(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
         Preconditions.checkNotNull(who, "ComponentName is null");
         enforceFullCrossUsersPermission(userHandle);
+        enforceCanManageProfileAndDeviceOwners();
         synchronized (this) {
             ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(who, userHandle);
             if (activeAdmin == null) {
-                throw new SecurityException("No active admin: " + activeAdmin);
-            }
-            if (activeAdmin.getUid() != mInjector.binderGetCallingUid()) {
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
-                        "Calling uid " + mInjector.binderGetCallingUid() + " neither owns the admin"
-                        + " " + who + " nor has MANAGE_PROFILE_AND_DEVICE_OWNERS permission");
+                return null;
             }
             return activeAdmin.userRestrictions;
         }
@@ -7164,11 +7305,13 @@
 
             try {
                 int parentUserId = getProfileParentId(userId);
-                List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
-                        intent,
-                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
-                        parentUserId);
+                List<ResolveInfo> activitiesToEnable = mIPackageManager
+                        .queryIntentActivities(intent,
+                                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                parentUserId)
+                        .getList();
 
                 if (VERBOSE_LOG) {
                     Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
@@ -7477,7 +7620,9 @@
     /**
      * Sets which packages may enter lock task mode.
      *
-     * This function can only be called by the device owner.
+     * <p>This function can only be called by the device owner or alternatively by the profile owner
+     * in case the user is affiliated.
+     *
      * @param packages The list of packages allowed to enter lock task mode.
      */
     @Override
@@ -7485,10 +7630,17 @@
             throws SecurityException {
         Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-
-            int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
-            setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
+            ActiveAdmin deviceOwner = getActiveAdminWithPolicyForUidLocked(
+                who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, mInjector.binderGetCallingUid());
+            ActiveAdmin profileOwner = getActiveAdminWithPolicyForUidLocked(
+                who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid());
+            if (deviceOwner != null || (profileOwner != null && isAffiliatedUser())) {
+                int userHandle = mInjector.userHandleGetCallingUserId();
+                setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
+            } else {
+                throw new SecurityException("Admin " + who +
+                    " is neither the device owner or affiliated user's profile owner.");
+            }
         }
     }
 
@@ -7775,9 +7927,9 @@
             super(handler);
         }
 
-        void register(ContentResolver resolver) {
-            resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
-            resolver.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
+        void register() {
+            mInjector.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
+            mInjector.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -7785,9 +7937,11 @@
             if (mUserSetupComplete.equals(uri)) {
                 updateUserSetupComplete();
             } else if (mDeviceProvisioned.equals(uri)) {
-                // Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
-                // is delayed until device is marked as provisioned.
-                setDeviceOwnerSystemPropertyLocked();
+                synchronized (DevicePolicyManagerService.this) {
+                    // Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
+                    // is delayed until device is marked as provisioned.
+                    setDeviceOwnerSystemPropertyLocked();
+                }
             }
         }
     }
@@ -7850,6 +8004,49 @@
                 listener.onCrossProfileWidgetProvidersChanged(userId, packages);
             }
         }
+
+        @Override
+        public boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId) {
+            if (!mHasFeature || packageName == null) {
+                return false;
+            }
+            if (userId < 0) {
+                throw new UnsupportedOperationException("userId should be >= 0");
+            }
+            synchronized (DevicePolicyManagerService.this) {
+                if (packageName.equals(mOwners.getProfileOwnerPackage(userId))) {
+                    return true;
+                }
+                if (userId == mOwners.getDeviceOwnerUserId()
+                        && packageName.equals(mOwners.getDeviceOwnerPackageName())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public Intent createPackageSuspendedDialogIntent(String packageName, int userId) {
+            Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+            intent.putExtra(Intent.EXTRA_USER_ID, userId);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            synchronized (DevicePolicyManagerService.this) {
+                ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
+                if (profileOwner != null) {
+                    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, profileOwner);
+                    return intent;
+                }
+
+                if (mOwners.getDeviceOwnerUserId() == userId) {
+                    ComponentName deviceOwner = mOwners.getDeviceOwnerComponent();
+                    if (deviceOwner != null) {
+                        intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceOwner);
+                        return intent;
+                    }
+                }
+            }
+            return null;
+        }
     }
 
     /**
@@ -8076,6 +8273,10 @@
 
     @Override
     public boolean isProvisioningAllowed(String action) {
+        if (!mHasFeature) {
+            return false;
+        }
+
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) {
             if (!hasFeatureManagedUsers()) {
@@ -8140,23 +8341,55 @@
         throw new IllegalArgumentException("Unknown provisioning action " + action);
     }
 
-    private boolean isDeviceOwnerProvisioningAllowed(int callingUserId) {
-        synchronized (this) {
-            if (mOwners.hasDeviceOwner()) {
-                return false;
+    /*
+     * The device owner can only be set before the setup phase of the primary user has completed,
+     * except for adb command if no accounts or additional users are present on the device.
+     */
+    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreCondition(
+            int deviceOwnerUserId, boolean isAdb) {
+        if (mOwners.hasDeviceOwner()) {
+            return CODE_HAS_DEVICE_OWNER;
+        }
+        if (mOwners.hasProfileOwner(deviceOwnerUserId)) {
+            return CODE_USER_HAS_PROFILE_OWNER;
+        }
+        if (!mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) {
+            return CODE_USER_NOT_RUNNING;
+        }
+        if (isAdb) {
+            // if shell command runs after user setup completed check device status. Otherwise, OK.
+            if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+                if (!mInjector.userManagerIsSplitSystemUser()) {
+                    if (mUserManager.getUserCount() > 1) {
+                        return CODE_NONSYSTEM_USER_EXISTS;
+                    }
+                    if (AccountManager.get(mContext).getAccounts().length > 0) {
+                        return CODE_ACCOUNTS_NOT_EMPTY;
+                    }
+                } else {
+                    // STOPSHIP Do proper check in split user mode
+                }
             }
+            return CODE_OK;
+        } else {
+            if (!mInjector.userManagerIsSplitSystemUser()) {
+                // In non-split user mode, DO has to be user 0
+                if (deviceOwnerUserId != UserHandle.USER_SYSTEM) {
+                    return CODE_NOT_SYSTEM_USER;
+                }
+                // In non-split user mode, only provision DO before setup wizard completes
+                if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+                    return CODE_USER_SETUP_COMPLETED;
+                }
+            } else {
+                // STOPSHIP Do proper check in split user mode
+            }
+            return CODE_OK;
         }
-        if (getProfileOwner(callingUserId) != null) {
-            return false;
-        }
-        if (mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
-            return false;
-        }
-        if (callingUserId != UserHandle.USER_SYSTEM) {
-            // Device owner provisioning can only be initiated from system user.
-            return false;
-        }
-        return true;
+    }
+
+    private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
+        return CODE_OK == checkSetDeviceOwnerPreCondition(deviceOwnerUserId, /* isAdb */ false);
     }
 
     private boolean hasFeatureManagedUsers() {
@@ -8168,10 +8401,10 @@
     }
 
     @Override
-    public String getWifiMacAddress() {
+    public String getWifiMacAddress(ComponentName admin) {
         // Make sure caller has DO.
         synchronized (this) {
-            getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
 
         final long ident = mInjector.binderClearCallingIdentity();
@@ -8190,11 +8423,16 @@
      * Returns the target sdk version number that the given packageName was built for
      * in the given user.
      */
-    private int getTargetSdk(String packageName, int userId) throws RemoteException {
-        final ApplicationInfo ai = mIPackageManager
-                .getApplicationInfo(packageName, 0, userId);
-        final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
-        return targetSdkVersion;
+    private int getTargetSdk(String packageName, int userId) {
+        final ApplicationInfo ai;
+        try {
+            ai = mIPackageManager.getApplicationInfo(packageName, 0, userId);
+            final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
+            return targetSdkVersion;
+        } catch (RemoteException e) {
+            // Shouldn't happen
+            return 0;
+        }
     }
 
     @Override
@@ -8203,13 +8441,7 @@
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         }
         final int callingUserId = mInjector.userHandleGetCallingUserId();
-        final UserInfo user;
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            user = mUserManager.getUserInfo(callingUserId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        final UserInfo user = getUserInfo(callingUserId);
         return user != null && user.isManagedProfile();
     }
 
@@ -8231,6 +8463,10 @@
         }
         long ident = mInjector.binderClearCallingIdentity();
         try {
+            // Make sure there are no ongoing calls on the device.
+            if (mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+                throw new IllegalStateException("Cannot be called with ongoing call on the device");
+            }
             mInjector.powerManagerReboot(PowerManager.REBOOT_REQUESTED_BY_DEVICE_OWNER);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -8484,19 +8720,22 @@
         return false;
     }
 
-    private void disableDeviceLoggingIfNotCompliant() {
+    private synchronized void disableSecurityLoggingIfNotCompliant() {
         if (!isDeviceOwnerManagedSingleUserDevice()) {
             mInjector.securityLogSetLoggingEnabledProperty(false);
-            Slog.w(LOG_TAG, "Device logging turned off as it's no longer a single user device.");
+            Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device.");
         }
     }
 
     @Override
-    public void setDeviceLoggingEnabled(ComponentName admin, boolean enabled) {
+    public void setSecurityLoggingEnabled(ComponentName admin, boolean enabled) {
         Preconditions.checkNotNull(admin);
         ensureDeviceOwnerManagingSingleUser(admin);
 
         synchronized (this) {
+            if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
+                return;
+            }
             mInjector.securityLogSetLoggingEnabledProperty(enabled);
             if (enabled) {
                 mSecurityLogMonitor.start();
@@ -8507,7 +8746,7 @@
     }
 
     @Override
-    public boolean getDeviceLoggingEnabled(ComponentName admin) {
+    public boolean isSecurityLoggingEnabled(ComponentName admin) {
         Preconditions.checkNotNull(admin);
         synchronized (this) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -8516,7 +8755,7 @@
     }
 
     @Override
-    public ParceledListSlice<SecurityEvent> retrievePreviousDeviceLogs(ComponentName admin) {
+    public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin) {
         Preconditions.checkNotNull(admin);
         ensureDeviceOwnerManagingSingleUser(admin);
 
@@ -8531,7 +8770,7 @@
     }
 
     @Override
-    public ParceledListSlice<SecurityEvent> retrieveDeviceLogs(ComponentName admin) {
+    public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin) {
         Preconditions.checkNotNull(admin);
         ensureDeviceOwnerManagingSingleUser(admin);
 
@@ -8544,6 +8783,11 @@
                 null);
     }
 
+    private void enforceCanManageProfileAndDeviceOwners() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+    }
+
     @Override
     public boolean isUninstallInQueue(final String packageName) {
         enforceCanManageDeviceAdmin();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 68fd0f6..b316cbd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -494,7 +494,6 @@
         abstract void writeInner(XmlSerializer out) throws IOException;
 
         abstract boolean readInner(XmlPullParser parser, int depth, String tag);
-
     }
 
     private class DeviceOwnerReadWriter extends FileReadWriter {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
index 117ba15..6d42dc9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
@@ -19,8 +19,12 @@
 import android.annotation.IntDef;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.text.format.DateUtils;
 
 import com.android.internal.R;
@@ -37,79 +41,62 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
-        NOTIFICATION_BUGREPORT_STARTED,
-        NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
-        NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
+        DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED,
+        DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
+        DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
     })
     @interface RemoteBugreportNotificationType {}
-    static final int NOTIFICATION_BUGREPORT_STARTED = 1;
-    static final int NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED = 2;
-    static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
 
     static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
 
     static final String CTL_STOP = "ctl.stop";
     static final String REMOTE_BUGREPORT_SERVICE = "bugreportremote";
 
-    static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
-            "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
-    static final String ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED =
-            "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED";
-    static final String ACTION_REMOTE_BUGREPORT_SHARING_DECLINED =
-            "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED";
-    static final String EXTRA_REMOTE_BUGREPORT_HASH = "android.intent.extra.REMOTE_BUGREPORT_HASH";
-
     static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
 
     static Notification buildNotification(Context context,
             @RemoteBugreportNotificationType int type) {
+        Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
+        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        dialogIntent.putExtra(DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
+        PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
+                dialogIntent, 0, null, UserHandle.CURRENT);
+
         Notification.Builder builder = new Notification.Builder(context)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
                 .setOngoing(true)
                 .setLocalOnly(true)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setContentIntent(pendingDialogIntent)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
 
-        if (type == NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
+        if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
             builder.setContentTitle(context.getString(
-                            R.string.sharing_remote_bugreport_notification_title))
-                    .setContentText(context.getString(
-                            R.string.sharing_remote_bugreport_notification_message))
-                    .setPriority(Notification.PRIORITY_HIGH)
-                    .setProgress(0, 0, true)
-                    .setStyle(new Notification.BigTextStyle().bigText(context.getString(
-                            R.string.sharing_remote_bugreport_notification_message)));
-        } else {
+                        R.string.sharing_remote_bugreport_notification_title))
+                    .setProgress(0, 0, true);
+        } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED) {
+            builder.setContentTitle(context.getString(
+                        R.string.taking_remote_bugreport_notification_title))
+                    .setProgress(0, 0, true);
+        } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
             PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(context, NOTIFICATION_ID,
-                    new Intent(ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED),
+                    new Intent(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(context,
-                    NOTIFICATION_ID, new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
+                    NOTIFICATION_ID, new Intent(
+                            DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             builder.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
-                            R.string.share_remote_bugreport_notification_decline),
-                            pendingIntentDecline).build())
+                        R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
                     .addAction(new Notification.Action.Builder(null /* icon */, context.getString(
-                            R.string.share_remote_bugreport_notification_accept),
-                            pendingIntentAccept).build())
+                        R.string.share_remote_bugreport_action), pendingIntentAccept).build())
                     .setContentTitle(context.getString(
-                            R.string.share_remote_bugreport_notification_title));
-
-            if (type == NOTIFICATION_BUGREPORT_STARTED) {
-                builder.setContentText(context.getString(
-                                R.string.share_remote_bugreport_notification_message))
-                        .setStyle(new Notification.BigTextStyle().bigText(context.getString(
-                                R.string.share_remote_bugreport_notification_message)))
-                        .setProgress(0, 0, true)
-                        .setPriority(Notification.PRIORITY_MAX)
-                        .setVibrate(new long[0]);
-            } else if (type == NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
-                builder.setContentText(context.getString(
-                                R.string.share_finished_remote_bugreport_notification_message))
-                        .setStyle(new Notification.BigTextStyle().bigText(context.getString(
-                                R.string.share_finished_remote_bugreport_notification_message)))
-                        .setPriority(Notification.PRIORITY_HIGH);
-            }
+                        R.string.share_remote_bugreport_notification_title))
+                    .setContentText(context.getString(
+                        R.string.share_remote_bugreport_notification_message_finished))
+                    .setStyle(new Notification.BigTextStyle().bigText(context.getString(
+                        R.string.share_remote_bugreport_notification_message_finished)));
         }
 
         return builder.build();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index f2d6180..79702a8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -17,8 +17,8 @@
 package com.android.server.devicepolicy;
 
 import android.app.admin.DeviceAdminReceiver;
-import android.auditing.SecurityLog;
-import android.auditing.SecurityLog.SecurityEvent;
+import android.app.admin.SecurityLog;
+import android.app.admin.SecurityLog.SecurityEvent;
 import android.util.Log;
 import android.util.Slog;
 
@@ -28,6 +28,8 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 import android.os.Process;
 
@@ -42,6 +44,8 @@
 class SecurityLogMonitor implements Runnable {
     private final DevicePolicyManagerService mService;
 
+    private final Lock mLock = new ReentrantLock();
+
     SecurityLogMonitor(DevicePolicyManagerService service) {
         mService = service;
     }
@@ -68,36 +72,50 @@
      */
     private static final long POLLING_INTERVAL_MILLISECONDS = TimeUnit.MINUTES.toMillis(1);
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private Thread mMonitorThread = null;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private ArrayList<SecurityEvent> mPendingLogs = new ArrayList<SecurityEvent>();
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private boolean mAllowedToRetrieve = false;
     // When DO will be allowed to retrieves the log, in milliseconds.
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private long mNextAllowedRetrivalTimeMillis = -1;
 
-    synchronized void start() {
-        if (mMonitorThread == null) {
-            mPendingLogs = new ArrayList<SecurityEvent>();
-            mAllowedToRetrieve = false;
-            mNextAllowedRetrivalTimeMillis = -1;
+    void start() {
+        mLock.lock();
+        try {
+            if (mMonitorThread == null) {
+                mPendingLogs = new ArrayList<SecurityEvent>();
+                mAllowedToRetrieve = false;
+                mNextAllowedRetrivalTimeMillis = -1;
 
-            mMonitorThread = new Thread(this);
-            mMonitorThread.start();
+                mMonitorThread = new Thread(this);
+                mMonitorThread.start();
+            }
+        } finally {
+            mLock.unlock();
         }
     }
 
-    synchronized void stop() {
-        if (mMonitorThread != null) {
-            mMonitorThread.interrupt();
-            try {
-                mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
-            } catch (InterruptedException e) {
-                Log.e(TAG, "Interrupted while waiting for thread to stop", e);
+    void stop() {
+        mLock.lock();
+        try {
+            if (mMonitorThread != null) {
+                mMonitorThread.interrupt();
+                try {
+                    mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Interrupted while waiting for thread to stop", e);
+                }
+                // Reset state and clear buffer
+                mPendingLogs = new ArrayList<SecurityEvent>();
+                mAllowedToRetrieve = false;
+                mNextAllowedRetrivalTimeMillis = -1;
+                mMonitorThread = null;
             }
-            mMonitorThread = null;
+        } finally {
+            mLock.unlock();
         }
     }
 
@@ -105,16 +123,21 @@
      * Returns the new batch of logs since the last call to this method. Returns null if
      * rate limit is exceeded.
      */
-    synchronized List<SecurityEvent> retrieveLogs() {
-        if (mAllowedToRetrieve) {
-            mAllowedToRetrieve = false;
-            mNextAllowedRetrivalTimeMillis = System.currentTimeMillis()
-                    + RATE_LIMIT_INTERVAL_MILLISECONDS;
-            List<SecurityEvent> result = mPendingLogs;
-            mPendingLogs = new ArrayList<SecurityEvent>();
-            return result;
-        } else {
-            return null;
+    List<SecurityEvent> retrieveLogs() {
+        mLock.lock();
+        try {
+            if (mAllowedToRetrieve) {
+                mAllowedToRetrieve = false;
+                mNextAllowedRetrivalTimeMillis = System.currentTimeMillis()
+                        + RATE_LIMIT_INTERVAL_MILLISECONDS;
+                List<SecurityEvent> result = mPendingLogs;
+                mPendingLogs = new ArrayList<SecurityEvent>();
+                return result;
+            } else {
+                return null;
+            }
+        } finally {
+            mLock.unlock();
         }
     }
 
@@ -141,7 +164,8 @@
                 }
                 if (!logs.isEmpty()) {
                     if (DEBUG) Slog.d(TAG, "processing new logs");
-                    synchronized (this) {
+                    mLock.lockInterruptibly();
+                    try {
                         mPendingLogs.addAll(logs);
                         if (mPendingLogs.size() > BUFFER_ENTRIES_MAXIMUM_LEVEL) {
                             // Truncate buffer down to half of BUFFER_ENTRIES_MAXIMUM_LEVEL
@@ -149,6 +173,8 @@
                                     mPendingLogs.size() - (BUFFER_ENTRIES_MAXIMUM_LEVEL / 2),
                                     mPendingLogs.size()));
                         }
+                    } finally {
+                        mLock.unlock();
                     }
                     lastLogTimestampNanos = logs.get(logs.size() - 1).getTimeNanos();
                     logs.clear();
@@ -163,18 +189,13 @@
             }
         }
         if (DEBUG) Slog.d(TAG, "MonitorThread exit.");
-        synchronized (this) {
-            // Reset state and clear buffer
-            mPendingLogs = new ArrayList<SecurityEvent>();
-            mAllowedToRetrieve = false;
-            mNextAllowedRetrivalTimeMillis = -1;
-        }
     }
 
-    private void notifyDeviceOwnerIfNeeded() {
+    private void notifyDeviceOwnerIfNeeded() throws InterruptedException {
         boolean shouldNotifyDO = false;
         boolean allowToRetrieveNow = false;
-        synchronized (this) {
+        mLock.lockInterruptibly();
+        try {
             int logSize = mPendingLogs.size();
             if (logSize >= BUFFER_ENTRIES_NOTIFICATION_LEVEL) {
                 // Allow DO to retrieve logs if too many pending logs
@@ -188,6 +209,8 @@
             }
             shouldNotifyDO = (!mAllowedToRetrieve) && allowToRetrieveNow;
             mAllowedToRetrieve = allowToRetrieveNow;
+        } finally {
+            mLock.unlock();
         }
         if (shouldNotifyDO) {
             if (DEBUG) Slog.d(TAG, "notify DO");
@@ -195,4 +218,4 @@
                     null);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c854573..e7ae2b0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources.Theme;
+import android.os.BaseBundle;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FactoryTest;
@@ -35,7 +36,6 @@
 import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.PowerManager;
-import android.os.RecoverySystem;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -53,12 +53,14 @@
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.internal.os.ZygoteInit;
+import com.android.internal.widget.ILockSettings;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.camera.CameraService;
 import com.android.server.clipboard.ClipboardService;
+import com.android.server.connectivity.MetricsLoggerService;
 import com.android.server.content.ContentService;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
 import com.android.server.display.DisplayManagerService;
@@ -68,10 +70,9 @@
 import com.android.server.input.InputManagerService;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.lights.LightsService;
-import com.android.internal.widget.ILockSettings;
+import com.android.server.media.MediaResourceMonitorService;
 import com.android.server.media.MediaRouterService;
 import com.android.server.media.MediaSessionService;
-import com.android.server.media.MediaResourceMonitorService;
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
@@ -82,6 +83,7 @@
 import com.android.server.pm.LauncherAppsService;
 import com.android.server.pm.OtaDexoptService;
 import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.ShortcutService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
@@ -151,6 +153,12 @@
             "com.android.server.MountService$Lifecycle";
     private static final String SEARCH_MANAGER_SERVICE_CLASS =
             "com.android.server.search.SearchManagerService$Lifecycle";
+    private static final String THERMAL_OBSERVER_CLASS =
+            "com.google.android.clockwork.ThermalObserver";
+    private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
+            "com.google.android.clockwork.bluetooth.WearBluetoothService";
+    private static final String CONTENT_SERVICE_CLASS =
+            "com.android.server.content.ContentService$Lifecycle";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -163,7 +171,7 @@
      * visual content.
      */
     private static final int DEFAULT_SYSTEM_THEME =
-            com.android.internal.R.style.Theme_Material_DayNight_DarkActionBar;
+            com.android.internal.R.style.Theme_Material_Light_DarkActionBar;
 
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
@@ -269,6 +277,10 @@
             // explicitly specifying a user.
             Environment.setUserRequired(true);
 
+            // Within the system server, any incoming Bundles should be defused
+            // to avoid throwing BadParcelableException.
+            BaseBundle.setShouldDefuse(true);
+
             // Ensure binder calls into the system always run at foreground priority.
             BinderInternal.disableBackgroundScheduling(true);
 
@@ -341,8 +353,8 @@
             // always make sure uncrypt gets executed properly when needed.
             // If '/cache/recovery/block.map' hasn't been created, stop the
             // reboot which will fail for sure, and get a chance to capture a
-            // bugreport when that's still feasible. (Bug; 26444951)
-            if (PowerManager.REBOOT_RECOVERY.equals(reason)) {
+            // bugreport when that's still feasible. (Bug: 26444951)
+            if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
                 File packageFile = new File(UNCRYPT_PACKAGE_FILE);
                 if (packageFile.exists()) {
                     String filename = null;
@@ -430,6 +442,24 @@
         mPackageManager = mSystemContext.getPackageManager();
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+        // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
+        // A/B artifacts after boot, before anything else might touch/need them.
+        // Note: this isn't needed during decryption (we don't have /data anyways).
+        if (!mOnlyCore) {
+            boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
+                    false);
+            if (!disableOtaDexopt) {
+                traceBeginAndSlog("StartOtaDexOptService");
+                try {
+                    OtaDexoptService.main(mSystemContext, mPackageManagerService);
+                } catch (Throwable e) {
+                    reportWtf("starting OtaDexOptService", e);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                }
+            }
+        }
+
         traceBeginAndSlog("StartUserManagerService");
         ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
@@ -498,6 +528,16 @@
         boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
         boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false);
         boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
+        boolean disableMediaProjection = SystemProperties.getBoolean("config.disable_mediaproj",
+                false);
+        boolean disableSerial = SystemProperties.getBoolean("config.disable_serial", false);
+        boolean disableSearchManager = SystemProperties.getBoolean("config.disable_searchmanager",
+                false);
+        boolean disableTrustManager = SystemProperties.getBoolean("config.disable_trustmanager",
+                false);
+        boolean disableTextServices = SystemProperties.getBoolean("config.disable_textservices", false);
+        boolean disableSamplingProfiler = SystemProperties.getBoolean("config.disable_samplingprof",
+                false);
         boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
 
         try {
@@ -536,8 +576,7 @@
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             traceBeginAndSlog("StartContentService");
-            contentService = ContentService.main(context,
-                    mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL);
+            mSystemServiceManager.startService(CONTENT_SERVICE_CLASS);
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             traceBeginAndSlog("InstallSystemProviders");
@@ -602,6 +641,10 @@
             } else {
                 mSystemServiceManager.startService(BluetoothService.class);
             }
+
+            traceBeginAndSlog("ConnectivityMetricsLoggerService");
+            mSystemServiceManager.startService(MetricsLoggerService.class);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         } catch (RuntimeException e) {
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting core service", e);
@@ -612,7 +655,6 @@
         WallpaperManagerService wallpaper = null;
         LocationManagerService location = null;
         CountryDetectorService countryDetector = null;
-        TextServicesManagerService tsms = null;
         ILockSettings lockSettings = null;
         AssetAtlasService atlas = null;
         MediaRouterService mediaRouter = null;
@@ -658,6 +700,14 @@
         // as appropriate.
         mSystemServiceManager.startService(UiModeManagerService.class);
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "UpdatePackagesIfNeeded");
+        try {
+            mPackageManagerService.updatePackagesIfNeeded();
+        } catch (Throwable e) {
+            reportWtf("update packages", e);
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PerformFstrimIfNeeded");
         try {
             mPackageManagerService.performFstrimIfNeeded();
@@ -666,14 +716,6 @@
         }
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "ExtractPackagesIfNeeded");
-        try {
-            mPackageManagerService.extractPackagesIfNeeded();
-        } catch (Throwable e) {
-            reportWtf("extract packages", e);
-        }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
         try {
             ActivityManagerNative.getDefault().showBootMessage(
                     context.getResources().getText(
@@ -738,15 +780,8 @@
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartTextServicesManagerService");
-                try {
-                    tsms = new TextServicesManagerService(context);
-                    ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
-                } catch (Throwable e) {
-                    reportWtf("starting Text Service Manager Service", e);
-                }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            if (!disableNonCoreServices && !disableTextServices) {
+                mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
             }
 
             if (!disableNetwork) {
@@ -833,6 +868,10 @@
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
+            if (!disableNonCoreServices) {
+                mSystemServiceManager.startService(RecoverySystemService.class);
+            }
+
             /*
              * MountService has a few dependencies: Notification Manager and
              * AppWidget Provider. Make sure MountService is completely started
@@ -892,7 +931,7 @@
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
-            if (!disableNonCoreServices) {
+            if (!disableNonCoreServices && !disableSearchManager) {
                 traceBeginAndSlog("StartSearchManagerService");
                 try {
                     mSystemServiceManager.startService(SEARCH_MANAGER_SERVICE_CLASS);
@@ -923,9 +962,8 @@
             if (!disableNonCoreServices) {
                 mSystemServiceManager.startService(DockObserver.class);
 
-                if (context.getPackageManager().hasSystemFeature
-                        (PackageManager.FEATURE_WATCH)) {
-                    mSystemServiceManager.startService(ThermalObserver.class);
+                if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+                    mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
                 }
             }
 
@@ -954,15 +992,17 @@
                     Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                 }
 
-                traceBeginAndSlog("StartSerialService");
-                try {
-                    // Serial port support
-                    serial = new SerialService(context);
-                    ServiceManager.addService(Context.SERIAL_SERVICE, serial);
-                } catch (Throwable e) {
-                    Slog.e(TAG, "Failure starting SerialService", e);
+                if (!disableSerial) {
+                    traceBeginAndSlog("StartSerialService");
+                    try {
+                        // Serial port support
+                        serial = new SerialService(context);
+                        ServiceManager.addService(Context.SERIAL_SERVICE, serial);
+                    } catch (Throwable e) {
+                        Slog.e(TAG, "Failure starting SerialService", e);
+                    }
+                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
                 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
                         "StartHardwarePropertiesManagerService");
@@ -987,7 +1027,8 @@
                     mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
                 }
 
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
+                    || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
                     mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
                 }
 
@@ -1000,6 +1041,7 @@
                     mSystemServiceManager.startService(GestureLauncherService.class);
                 }
                 mSystemServiceManager.startService(SensorNotificationService.class);
+                mSystemServiceManager.startService(ContextHubSystemService.class);
             }
 
             traceBeginAndSlog("StartDiskStatsService");
@@ -1010,23 +1052,26 @@
             }
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            traceBeginAndSlog("StartSamplingProfilerService");
-            try {
-                // need to add this service even if SamplingProfilerIntegration.isEnabled()
-                // is false, because it is this service that detects system property change and
-                // turns on SamplingProfilerIntegration. Plus, when sampling profiler doesn't work,
-                // there is little overhead for running this service.
-                ServiceManager.addService("samplingprofiler",
-                            new SamplingProfilerService(context));
-            } catch (Throwable e) {
-                reportWtf("starting SamplingProfiler Service", e);
+            if (!disableSamplingProfiler) {
+                traceBeginAndSlog("StartSamplingProfilerService");
+                try {
+                    // need to add this service even if SamplingProfilerIntegration.isEnabled()
+                    // is false, because it is this service that detects system property change and
+                    // turns on SamplingProfilerIntegration. Plus, when sampling profiler doesn't work,
+                    // there is little overhead for running this service.
+                    ServiceManager.addService("samplingprofiler",
+                                new SamplingProfilerService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting SamplingProfiler Service", e);
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             if (!disableNetwork && !disableNetworkTime) {
                 traceBeginAndSlog("StartNetworkTimeUpdateService");
                 try {
                     networkTimeUpdater = new NetworkTimeUpdateService(context);
+                    ServiceManager.addService("network_time_update_service", networkTimeUpdater);
                 } catch (Throwable e) {
                     reportWtf("starting NetworkTimeUpdate service", e);
                 }
@@ -1089,7 +1134,9 @@
                 mSystemServiceManager.startService(TvInputManagerService.class);
             }
 
-            mSystemServiceManager.startService(MediaResourceMonitorService.class);
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
+                mSystemServiceManager.startService(MediaResourceMonitorService.class);
+            }
 
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartMediaRouterService");
@@ -1101,7 +1148,9 @@
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-                mSystemServiceManager.startService(TrustManagerService.class);
+                if (!disableTrustManager) {
+                    mSystemServiceManager.startService(TrustManagerService.class);
+                }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
                     mSystemServiceManager.startService(FingerprintService.class);
@@ -1114,28 +1163,21 @@
                     reportWtf("starting BackgroundDexOptService", e);
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
-                // Manages A/B OTA dexopting.
-                boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
-                        false);
-                if (!disableOtaDexopt) {
-                    traceBeginAndSlog("StartOtaDexOptService");
-                    try {
-                        OtaDexoptService.main(mSystemContext, mPackageManagerService);
-                    } catch (Throwable e) {
-                        reportWtf("starting BackgroundDexOptService", e);
-                    }
-                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                }
             }
+            // LauncherAppsService uses ShortcutService.
+            mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
 
             mSystemServiceManager.startService(LauncherAppsService.class);
         }
 
-        if (!disableNonCoreServices) {
+        if (!disableNonCoreServices && !disableMediaProjection) {
             mSystemServiceManager.startService(MediaProjectionManagerService.class);
         }
 
+        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
+        }
+
         // Before things start rolling, be sure we have decided whether
         // we are in safe mode.
         final boolean safeMode = wm.detectSafeMode();
@@ -1241,7 +1283,6 @@
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
         final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
-        final TextServicesManagerService textServiceManagerServiceF = tsms;
         final StatusBarManagerService statusBarF = statusBar;
         final AssetAtlasService atlasF = atlas;
         final InputManagerService inputManagerF = inputManager;
@@ -1270,10 +1311,12 @@
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-                Slog.i(TAG, "WebViewFactory preparation");
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
-                mWebViewUpdateService.prepareWebViewInSystemServer();
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                if (!mOnlyCore) {
+                    Slog.i(TAG, "WebViewFactory preparation");
+                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
+                    mWebViewUpdateService.prepareWebViewInSystemServer();
+                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                }
 
                 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
                 try {
@@ -1282,7 +1325,7 @@
                     reportWtf("starting System UI", e);
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeMountServiceReady");
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkScoreReady");
                 try {
                     if (networkScoreF != null) networkScoreF.systemReady();
                 } catch (Throwable e) {
@@ -1355,12 +1398,6 @@
                     reportWtf("Notifying CommonTimeManagementService running", e);
                 }
                 try {
-                    if (textServiceManagerServiceF != null)
-                        textServiceManagerServiceF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying TextServicesManagerService running", e);
-                }
-                try {
                     if (atlasF != null) atlasF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying AssetAtlasService running", e);
@@ -1387,6 +1424,12 @@
                 } catch (Throwable e) {
                     reportWtf("Notifying MmsService running", e);
                 }
+
+                try {
+                    if (networkScoreF != null) networkScoreF.systemRunning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying NetworkScoreService running", e);
+                }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
         });
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
new file mode 100644
index 0000000..0ec50c4
--- /dev/null
+++ b/services/net/java/android/net/apf/ApfCapabilities.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.apf;
+
+/**
+ * APF program support capabilities.
+ *
+ * @hide
+ */
+public class ApfCapabilities {
+    /**
+     * Version of APF instruction set supported for packet filtering. 0 indicates no support for
+     * packet filtering using APF programs.
+     */
+    public final int apfVersionSupported;
+
+    /**
+     * Maximum size of APF program allowed.
+     */
+    public final int maximumApfProgramSize;
+
+    /**
+     * Format of packets passed to APF filter. Should be one of ARPHRD_*
+     */
+    public final int apfPacketFormat;
+
+    ApfCapabilities(int apfVersionSupported, int maximumApfProgramSize, int apfPacketFormat) {
+        this.apfVersionSupported = apfVersionSupported;
+        this.maximumApfProgramSize = maximumApfProgramSize;
+        this.apfPacketFormat = apfPacketFormat;
+    }
+
+    public String toString() {
+        return String.format("%s{version: %d, maxSize: %d format: %d}", getClass().getSimpleName(),
+                apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
+    }
+}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
new file mode 100644
index 0000000..f430a30
--- /dev/null
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -0,0 +1,909 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.apf;
+
+import static android.system.OsConstants.*;
+
+import android.net.LinkProperties;
+import android.net.NetworkUtils;
+import android.net.apf.ApfGenerator;
+import android.net.apf.ApfGenerator.IllegalInstructionException;
+import android.net.apf.ApfGenerator.Register;
+import android.net.ip.IpManager;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.PacketSocketAddress;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.Thread;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import libcore.io.IoBridge;
+
+/**
+ * For networks that support packet filtering via APF programs, {@code ApfFilter}
+ * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
+ * filter out redundant duplicate ones.
+ *
+ * Threading model:
+ * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
+ * know what RAs to filter for, thus generating APF programs is dependent on mRas.
+ * mRas can be accessed by multiple threads:
+ * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
+ * - callers of:
+ *    - setMulticastFilter(), which can cause an APF program to be generated.
+ *    - dump(), which dumps mRas among other things.
+ *    - shutdown(), which clears mRas.
+ * So access to mRas is synchronized.
+ *
+ * @hide
+ */
+public class ApfFilter {
+    // Thread to listen for RAs.
+    private class ReceiveThread extends Thread {
+        private final byte[] mPacket = new byte[1514];
+        private final FileDescriptor mSocket;
+        private volatile boolean mStopped;
+
+        public ReceiveThread(FileDescriptor socket) {
+            mSocket = socket;
+        }
+
+        public void halt() {
+            mStopped = true;
+            try {
+                // Interrupts the read() call the thread is blocked in.
+                IoBridge.closeAndSignalBlockedThreads(mSocket);
+            } catch (IOException ignored) {}
+        }
+
+        @Override
+        public void run() {
+            log("begin monitoring");
+            while (!mStopped) {
+                try {
+                    int length = Os.read(mSocket, mPacket, 0, mPacket.length);
+                    processRa(mPacket, length);
+                } catch (IOException|ErrnoException e) {
+                    if (!mStopped) {
+                        Log.e(TAG, "Read error", e);
+                    }
+                }
+            }
+        }
+    }
+
+    private static final String TAG = "ApfFilter";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    private static final int ETH_HEADER_LEN = 14;
+    private static final int ETH_ETHERTYPE_OFFSET = 12;
+    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
+    private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
+    // Endianness is not an issue for this constant because the APF interpreter always operates in
+    // network byte order.
+    private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
+    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
+    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+
+    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
+    private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
+    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
+    private static final int IPV6_HEADER_LEN = 40;
+    // The IPv6 all nodes address ff02::1
+    private static final byte[] IPV6_ALL_NODES_ADDRESS =
+            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+
+    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
+
+    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
+    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
+    private static final int UDP_HEADER_LEN = 8;
+
+    private static final int DHCP_CLIENT_PORT = 68;
+    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
+    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
+
+    private static int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
+    private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
+            0, 1, // Hardware type: Ethernet (1)
+            8, 0, // Protocol type: IP (0x0800)
+            6,    // Hardware size: 6
+            4,    // Protocol size: 4
+            0, 1  // Opcode: request (1)
+    };
+    private static int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
+
+    private final ApfCapabilities mApfCapabilities;
+    private final IpManager.Callback mIpManagerCallback;
+    private final NetworkInterface mNetworkInterface;
+    private byte[] mHardwareAddress;
+    private ReceiveThread mReceiveThread;
+    @GuardedBy("this")
+    private long mUniqueCounter;
+    @GuardedBy("this")
+    private boolean mMulticastFilter;
+    // Our IPv4 address, if we have just one, otherwise null.
+    @GuardedBy("this")
+    private byte[] mIPv4Address;
+
+    private ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
+            IpManager.Callback ipManagerCallback, boolean multicastFilter) {
+        mApfCapabilities = apfCapabilities;
+        mIpManagerCallback = ipManagerCallback;
+        mNetworkInterface = networkInterface;
+        mMulticastFilter = multicastFilter;
+
+        maybeStartFilter();
+    }
+
+    private void log(String s) {
+        Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s);
+    }
+
+    @GuardedBy("this")
+    private long getUniqueNumberLocked() {
+        return mUniqueCounter++;
+    }
+
+    /**
+     * Attempt to start listening for RAs and, if RAs are received, generating and installing
+     * filters to ignore useless RAs.
+     */
+    private void maybeStartFilter() {
+        FileDescriptor socket;
+        try {
+            mHardwareAddress = mNetworkInterface.getHardwareAddress();
+            synchronized(this) {
+                // Install basic filters
+                installNewProgramLocked();
+            }
+            socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
+            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6,
+                    mNetworkInterface.getIndex());
+            Os.bind(socket, addr);
+            NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
+        } catch(SocketException|ErrnoException e) {
+            Log.e(TAG, "Error starting filter", e);
+            return;
+        }
+        mReceiveThread = new ReceiveThread(socket);
+        mReceiveThread.start();
+    }
+
+    // Returns seconds since Unix Epoch.
+    private static long curTime() {
+        return System.currentTimeMillis() / 1000L;
+    }
+
+    // A class to hold information about an RA.
+    private class Ra {
+        // From RFC4861:
+        private static final int ICMP6_RA_HEADER_LEN = 16;
+        private static final int ICMP6_RA_CHECKSUM_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
+        private static final int ICMP6_RA_CHECKSUM_LEN = 2;
+        private static final int ICMP6_RA_OPTION_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
+        private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
+        private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
+        // Prefix information option.
+        private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
+        private static final int ICMP6_PREFIX_OPTION_LEN = 32;
+        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
+        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
+        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
+        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
+
+        // From RFC6106: Recursive DNS Server option
+        private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
+        // From RFC6106: DNS Search List option
+        private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
+
+        // From RFC4191: Route Information option
+        private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
+        // Above three options all have the same format:
+        private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
+        private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+
+        // Note: mPacket's position() cannot be assumed to be reset.
+        private final ByteBuffer mPacket;
+        // List of binary ranges that include the whole packet except the lifetimes.
+        // Pairs consist of offset and length.
+        private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
+                new ArrayList<Pair<Integer, Integer>>();
+        // Minimum lifetime in packet
+        long mMinLifetime;
+        // When the packet was last captured, in seconds since Unix Epoch
+        long mLastSeen;
+
+        // For debugging only. Offsets into the packet where PIOs are.
+        private final ArrayList<Integer> mPrefixOptionOffsets;
+        // For debugging only. How many times this RA was seen.
+        int seenCount = 0;
+
+        // For debugging only. Returns the hex representation of the last matching packet.
+        String getLastMatchingPacket() {
+            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), false /* lowercase */);
+        }
+
+        private String IPv6AddresstoString(int pos) {
+            try {
+                byte[] array = mPacket.array();
+                // Can't just call copyOfRange() and see if it throws, because if it reads past the
+                // end it pads with zeros instead of throwing.
+                if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
+                    return "???";
+                }
+                byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
+                InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
+                return address.getHostAddress();
+            } catch (UnsupportedOperationException e) {
+                // array() failed. Cannot happen, mPacket is array-backed and read-write.
+                return "???";
+            } catch (ClassCastException | UnknownHostException e) {
+                // Cannot happen.
+                return "???";
+            }
+        }
+
+        // Can't be static because it's in a non-static inner class.
+        // TODO: Make this final once RA is its own class.
+        private int uint8(byte b) {
+            return b & 0xff;
+        }
+
+        private int uint16(short s) {
+            return s & 0xffff;
+        }
+
+        private long uint32(int s) {
+            return s & 0xffffffff;
+        }
+
+        public String toString() {
+            try {
+                StringBuffer sb = new StringBuffer();
+                sb.append(String.format("RA %s -> %s %d ",
+                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
+                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
+                        uint16(mPacket.getShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET))));
+                for (int i: mPrefixOptionOffsets) {
+                    String prefix = IPv6AddresstoString(i + 16);
+                    int length = uint8(mPacket.get(i + 2));
+                    long valid = mPacket.getInt(i + 4);
+                    long preferred = mPacket.getInt(i + 8);
+                    sb.append(String.format("%s/%d %d/%d ", prefix, length, valid, preferred));
+                }
+                return sb.toString();
+            } catch (BufferUnderflowException | IndexOutOfBoundsException e) {
+                return "<Malformed RA>";
+            }
+        }
+
+        /**
+         * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
+         * Assumes mPacket.position() is as far as we've parsed the packet.
+         * @param lastNonLifetimeStart offset within packet of where the last binary range of
+         *                             data not including a lifetime.
+         * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
+         * @param lifetimeLength length of the next lifetime data.
+         * @return offset within packet of where the next binary range of data not including
+         *         a lifetime.  This can be passed into the next invocation of this function
+         *         via {@code lastNonLifetimeStart}.
+         */
+        private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
+                int lifetimeLength) {
+            lifetimeOffset += mPacket.position();
+            mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
+                    lifetimeOffset - lastNonLifetimeStart));
+            return lifetimeOffset + lifetimeLength;
+        }
+
+        // Note that this parses RA and may throw IllegalArgumentException (from
+        // Buffer.position(int) ) or IndexOutOfBoundsException (from ByteBuffer.get(int) ) if
+        // parsing encounters something non-compliant with specifications.
+        Ra(byte[] packet, int length) {
+            mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length));
+            mPacket.clear();
+            mLastSeen = curTime();
+
+            // Ignore the checksum.
+            int lastNonLifetimeStart = addNonLifetime(0,
+                    ICMP6_RA_CHECKSUM_OFFSET,
+                    ICMP6_RA_CHECKSUM_LEN);
+
+            // Parse router lifetime
+            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
+                    ICMP6_RA_ROUTER_LIFETIME_LEN);
+
+            // Parse ICMPv6 options
+            mPrefixOptionOffsets = new ArrayList<>();
+            mPacket.position(ICMP6_RA_OPTION_OFFSET);
+            while (mPacket.hasRemaining()) {
+                int optionType = ((int)mPacket.get(mPacket.position())) & 0xff;
+                int optionLength = (((int)mPacket.get(mPacket.position() + 1)) & 0xff) * 8;
+                switch (optionType) {
+                    case ICMP6_PREFIX_OPTION_TYPE:
+                        // Parse valid lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
+                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
+                        // Parse preferred lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
+                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
+                        mPrefixOptionOffsets.add(mPacket.position());
+                        break;
+                    // These three options have the same lifetime offset and size, so process
+                    // together:
+                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
+                    case ICMP6_RDNSS_OPTION_TYPE:
+                    case ICMP6_DNSSL_OPTION_TYPE:
+                        // Parse lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_4_BYTE_LIFETIME_OFFSET,
+                                ICMP6_4_BYTE_LIFETIME_LEN);
+                        break;
+                    default:
+                        // RFC4861 section 4.2 dictates we ignore unknown options for fowards
+                        // compatibility.
+                        break;
+                }
+                mPacket.position(mPacket.position() + optionLength);
+            }
+            // Mark non-lifetime bytes since last lifetime.
+            addNonLifetime(lastNonLifetimeStart, 0, 0);
+            mMinLifetime = minLifetime(packet, length);
+        }
+
+        // Ignoring lifetimes (which may change) does {@code packet} match this RA?
+        boolean matches(byte[] packet, int length) {
+            if (length != mPacket.capacity()) return false;
+            byte[] referencePacket = mPacket.array();
+            for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
+                for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
+                    if (packet[i] != referencePacket[i]) return false;
+                }
+            }
+            return true;
+        }
+
+        // What is the minimum of all lifetimes within {@code packet} in seconds?
+        // Precondition: matches(packet, length) already returned true.
+        long minLifetime(byte[] packet, int length) {
+            long minLifetime = Long.MAX_VALUE;
+            // Wrap packet in ByteBuffer so we can read big-endian values easily
+            ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
+            for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
+                int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
+
+                // The checksum is in mNonLifetimes, but it's not a lifetime.
+                if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
+                     continue;
+                }
+
+                int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
+                long val;
+                switch (lifetimeLength) {
+                    case 2: val = byteBuffer.getShort(offset); break;
+                    case 4: val = byteBuffer.getInt(offset); break;
+                    default: throw new IllegalStateException("bogus lifetime size " + length);
+                }
+                // Mask to size, converting signed to unsigned
+                val &= (1L << (lifetimeLength * 8)) - 1;
+                minLifetime = Math.min(minLifetime, val);
+            }
+            return minLifetime;
+        }
+
+        // How many seconds does this RA's have to live, taking into account the fact
+        // that we might have seen it a while ago.
+        long currentLifetime() {
+            return mMinLifetime - (curTime() - mLastSeen);
+        }
+
+        boolean isExpired() {
+            // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
+            // have to calculte the filter lifetime specially as a fraction of 0 is still 0.
+            return currentLifetime() <= 0;
+        }
+
+        // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
+        // Jump to the next filter if packet doesn't match this RA.
+        @GuardedBy("ApfFilter.this")
+        long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+            String nextFilterLabel = "Ra" + getUniqueNumberLocked();
+            // Skip if packet is not the right size
+            gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
+            gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
+            int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
+            // Skip filter if expired
+            gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
+            gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
+            for (int i = 0; i < mNonLifetimes.size(); i++) {
+                // Generate code to match the packet bytes
+                Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
+                // Don't generate JNEBS instruction for 0 bytes as it always fails the
+                // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
+                // the number of bytes to compare. nonLifetime is zero between the
+                // valid and preferred lifetimes in the prefix option.
+                if (nonLifetime.second != 0) {
+                    gen.addLoadImmediate(Register.R0, nonLifetime.first);
+                    gen.addJumpIfBytesNotEqual(Register.R0,
+                            Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
+                                               nonLifetime.first + nonLifetime.second),
+                            nextFilterLabel);
+                }
+                // Generate code to test the lifetimes haven't gone down too far
+                if ((i + 1) < mNonLifetimes.size()) {
+                    Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
+                    int offset = nonLifetime.first + nonLifetime.second;
+                    // Skip the checksum.
+                    if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
+                        continue;
+                    }
+                    int length = nextNonLifetime.first - offset;
+                    switch (length) {
+                        case 4: gen.addLoad32(Register.R0, offset); break;
+                        case 2: gen.addLoad16(Register.R0, offset); break;
+                        default: throw new IllegalStateException("bogus lifetime size " + length);
+                    }
+                    gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
+                }
+            }
+            gen.addJump(gen.DROP_LABEL);
+            gen.defineLabel(nextFilterLabel);
+            return filterLifetime;
+        }
+    }
+
+    // Maximum number of RAs to filter for.
+    private static final int MAX_RAS = 10;
+
+    @GuardedBy("this")
+    private ArrayList<Ra> mRas = new ArrayList<Ra>();
+
+    // There is always some marginal benefit to updating the installed APF program when an RA is
+    // seen because we can extend the program's lifetime slightly, but there is some cost to
+    // updating the program, so don't bother unless the program is going to expire soon. This
+    // constant defines "soon" in seconds.
+    private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
+    // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
+    // see a refresh.  Using half the lifetime might be a good idea except for the fact that
+    // packets may be dropped, so let's use 6.
+    private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
+
+    // When did we last install a filter program? In seconds since Unix Epoch.
+    @GuardedBy("this")
+    private long mLastTimeInstalledProgram;
+    // How long should the last installed filter program live for? In seconds.
+    @GuardedBy("this")
+    private long mLastInstalledProgramMinLifetime;
+
+    // For debugging only. The last program installed.
+    @GuardedBy("this")
+    private byte[] mLastInstalledProgram;
+
+    /**
+     * Generate filter code to process ARP packets. Execution of this code ends in either the
+     * DROP_LABEL or PASS_LABEL and does not fall off the end.
+     * Preconditions:
+     *  - Packet being filtered is ARP
+     */
+    @GuardedBy("this")
+    private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+        // Here's a basic summary of what the ARP filter program does:
+        //
+        // if it's not an ARP IPv4 request:
+        //   pass
+        // if it's not a request for our IPv4 address:
+        //   drop
+        // pass
+
+        // if it's not an ARP IPv4 request, pass
+        gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
+        gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_REQUEST_HEADER, gen.PASS_LABEL);
+        // if it's not a request for our IPv4 address, drop
+        gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
+        gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
+
+        // Otherwise, pass
+        gen.addJump(gen.PASS_LABEL);
+    }
+
+    /**
+     * Generate filter code to process IPv4 packets. Execution of this code ends in either the
+     * DROP_LABEL or PASS_LABEL and does not fall off the end.
+     * Preconditions:
+     *  - Packet being filtered is IPv4
+     *  - R1 is initialized to 0
+     */
+    @GuardedBy("this")
+    private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+        // Here's a basic summary of what the IPv4 filter program does:
+        //
+        // if it's multicast and we're dropping multicast:
+        //   drop
+        // if it's not broadcast:
+        //   pass
+        // if it's not DHCP destined to our MAC:
+        //   drop
+        // pass
+
+        if (mMulticastFilter) {
+            // Check for multicast destination address range
+            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
+            gen.addAnd(0xf0);
+            gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
+        }
+
+        // Drop all broadcasts besides DHCP addressed to us
+        // If not a broadcast packet, pass
+        // NOTE: Relies on R1 being initialized to 0 which is the offset of the ethernet
+        //       destination MAC address
+        gen.addJumpIfBytesNotEqual(Register.R1, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
+        // If not UDP, drop
+        gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
+        gen.addJumpIfR0NotEquals(IPPROTO_UDP, gen.DROP_LABEL);
+        // If fragment, drop. This matches the BPF filter installed by the DHCP client.
+        gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
+        gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, gen.DROP_LABEL);
+        // If not to DHCP client port, drop
+        gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+        gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
+        gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, gen.DROP_LABEL);
+        // If not DHCP to our MAC address, drop
+        gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
+        // NOTE: Relies on R1 containing IPv4 header offset.
+        gen.addAddR1();
+        gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, gen.DROP_LABEL);
+
+        // Otherwise, pass
+        gen.addJump(gen.PASS_LABEL);
+    }
+
+
+    /**
+     * Generate filter code to process IPv6 packets. Execution of this code ends in either the
+     * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
+     * Preconditions:
+     *  - Packet being filtered is IPv6
+     */
+    @GuardedBy("this")
+    private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+        // Here's a basic summary of what the IPv6 filter program does:
+        //
+        // if it's not ICMPv6:
+        //   pass
+        // if it's ICMPv6 NA to ff02::1:
+        //   drop
+
+        // If not ICMPv6, pass
+        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
+        // TODO: Drop multicast if the multicast filter is enabled.
+        gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
+        // Add unsolicited multicast neighbor announcements filter
+        String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
+        // If not neighbor announcements, skip unsolicited multicast NA filter
+        gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+        gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
+        // If to ff02::1, drop
+        // TODO: Drop only if they don't contain the address of on-link neighbours.
+        gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
+        gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
+                skipUnsolicitedMulticastNALabel);
+        gen.addJump(gen.DROP_LABEL);
+        gen.defineLabel(skipUnsolicitedMulticastNALabel);
+    }
+
+    /**
+     * Begin generating an APF program to:
+     * <ul>
+     * <li>Drop ARP requests not for us, if mIPv4Address is set,
+     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
+     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
+     * <li>Pass all other IPv4 packets,
+     * <li>Pass all non-ICMPv6 IPv6 packets,
+     * <li>Pass all non-IPv4 and non-IPv6 packets,
+     * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
+     * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
+     *     insertion of RA filters here, or if there aren't any, just passes the packets.
+     * </ul>
+     */
+    @GuardedBy("this")
+    private ApfGenerator beginProgramLocked() throws IllegalInstructionException {
+        ApfGenerator gen = new ApfGenerator();
+        // This is guaranteed to return true because of the check in maybeCreate.
+        gen.setApfVersion(mApfCapabilities.apfVersionSupported);
+
+        // Here's a basic summary of what the initial program does:
+        //
+        // if it's ARP:
+        //   inesrt ARP filter to drop or pass these appropriately
+        // if it's IPv4:
+        //   insert IPv4 filter to drop or pass these appropriately
+        // if it's not IPv6:
+        //   pass
+        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
+
+        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
+
+        if (mIPv4Address != null) {
+            // Add ARP filters:
+            String skipArpFiltersLabel = "skipArpFilters";
+            // If not ARP, skip ARP filters
+            // NOTE: Relies on R0 containing ethertype.
+            gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
+            generateArpFilterLocked(gen);
+            gen.defineLabel(skipArpFiltersLabel);
+        }
+
+        // Add IPv4 filters:
+        String skipIPv4FiltersLabel = "skipIPv4Filters";
+        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
+        // execute the ARP filter, since that filter does not fall through, but either drops or
+        // passes.
+        gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
+        // NOTE: Relies on R1 being initialized to 0.
+        generateIPv4FilterLocked(gen);
+        gen.defineLabel(skipIPv4FiltersLabel);
+
+        // Add IPv6 filters:
+        // If not IPv6, pass
+        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
+        // execute the ARP or IPv4 filters, since those filters do not fall through, but either
+        // drop or pass.
+        gen.addJumpIfR0NotEquals(ETH_P_IPV6, gen.PASS_LABEL);
+        generateIPv6FilterLocked(gen);
+        return gen;
+    }
+
+    @GuardedBy("this")
+    private void installNewProgramLocked() {
+        purgeExpiredRasLocked();
+        final byte[] program;
+        long programMinLifetime = Long.MAX_VALUE;
+        try {
+            // Step 1: Determine how many RA filters we can fit in the program.
+            ApfGenerator gen = beginProgramLocked();
+            ArrayList<Ra> rasToFilter = new ArrayList<Ra>();
+            for (Ra ra : mRas) {
+                ra.generateFilterLocked(gen);
+                // Stop if we get too big.
+                if (gen.programLengthOverEstimate() > mApfCapabilities.maximumApfProgramSize) break;
+                rasToFilter.add(ra);
+            }
+            // Step 2: Actually generate the program
+            gen = beginProgramLocked();
+            for (Ra ra : rasToFilter) {
+                programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
+            }
+            // Execution will reach the end of the program if no filters match, which will pass the
+            // packet to the AP.
+            program = gen.generate();
+        } catch (IllegalInstructionException e) {
+            Log.e(TAG, "Program failed to generate: ", e);
+            return;
+        }
+        mLastTimeInstalledProgram = curTime();
+        mLastInstalledProgramMinLifetime = programMinLifetime;
+        mLastInstalledProgram = program;
+        if (VDBG) {
+            hexDump("Installing filter: ", program, program.length);
+        }
+        mIpManagerCallback.installPacketFilter(program);
+    }
+
+    // Install a new filter program if the last installed one will die soon.
+    @GuardedBy("this")
+    private void maybeInstallNewProgramLocked() {
+        if (mRas.size() == 0) return;
+        // If the current program doesn't expire for a while, don't bother updating.
+        long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
+        if (expiry < curTime() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING) {
+            installNewProgramLocked();
+        }
+    }
+
+    private void hexDump(String msg, byte[] packet, int length) {
+        log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
+    }
+
+    @GuardedBy("this")
+    private void purgeExpiredRasLocked() {
+        for (int i = 0; i < mRas.size();) {
+            if (mRas.get(i).isExpired()) {
+                log("Expiring " + mRas.get(i));
+                mRas.remove(i);
+            } else {
+                i++;
+            }
+        }
+    }
+
+    private synchronized void processRa(byte[] packet, int length) {
+        if (VDBG) hexDump("Read packet = ", packet, length);
+
+        // Have we seen this RA before?
+        for (int i = 0; i < mRas.size(); i++) {
+            Ra ra = mRas.get(i);
+            if (ra.matches(packet, length)) {
+                if (VDBG) log("matched RA " + ra);
+                // Update lifetimes.
+                ra.mLastSeen = curTime();
+                ra.mMinLifetime = ra.minLifetime(packet, length);
+                ra.seenCount++;
+
+                // Keep mRas in LRU order so as to prioritize generating filters for recently seen
+                // RAs. LRU prioritizes this because RA filters are generated in order from mRas
+                // until the filter program exceeds the maximum filter program size allowed by the
+                // chipset, so RAs appearing earlier in mRas are more likely to make it into the
+                // filter program.
+                // TODO: consider sorting the RAs in order of increasing expiry time as well.
+                // Swap to front of array.
+                mRas.add(0, mRas.remove(i));
+
+                maybeInstallNewProgramLocked();
+                return;
+            }
+        }
+        purgeExpiredRasLocked();
+        // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
+        if (mRas.size() >= MAX_RAS) return;
+        final Ra ra;
+        try {
+            ra = new Ra(packet, length);
+        } catch (Exception e) {
+            Log.e(TAG, "Error parsing RA: " + e);
+            return;
+        }
+        // Ignore 0 lifetime RAs.
+        if (ra.isExpired()) return;
+        log("Adding " + ra);
+        mRas.add(ra);
+        installNewProgramLocked();
+    }
+
+    /**
+     * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
+     * filtering using APF programs.
+     */
+    public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
+            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
+            boolean multicastFilter) {
+        if (apfCapabilities == null || networkInterface == null) return null;
+        if (apfCapabilities.apfVersionSupported == 0) return null;
+        if (apfCapabilities.maximumApfProgramSize < 512) {
+            Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
+            return null;
+        }
+        // For now only support generating programs for Ethernet frames. If this restriction is
+        // lifted:
+        //   1. the program generator will need its offsets adjusted.
+        //   2. the packet filter attached to our packet socket will need its offset adjusted.
+        if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
+        if (!new ApfGenerator().setApfVersion(apfCapabilities.apfVersionSupported)) {
+            Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
+            return null;
+        }
+        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter);
+    }
+
+    public synchronized void shutdown() {
+        if (mReceiveThread != null) {
+            log("shutting down");
+            mReceiveThread.halt();  // Also closes socket.
+            mReceiveThread = null;
+        }
+        mRas.clear();
+    }
+
+    public synchronized void setMulticastFilter(boolean enabled) {
+        if (mMulticastFilter != enabled) {
+            mMulticastFilter = enabled;
+            installNewProgramLocked();
+        }
+    }
+
+    // Find the single IPv4 address if there is one, otherwise return null.
+    private static byte[] findIPv4Address(LinkProperties lp) {
+        byte[] ipv4Address = null;
+        for (InetAddress inetAddr : lp.getAddresses()) {
+            byte[] addr = inetAddr.getAddress();
+            if (addr.length != 4) continue;
+            // More than one IPv4 address, abort
+            if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null;
+            ipv4Address = addr;
+        }
+        return ipv4Address;
+    }
+
+    public synchronized void setLinkProperties(LinkProperties lp) {
+        // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
+        byte[] ipv4Address = findIPv4Address(lp);
+        // If ipv4Address is the same as mIPv4Address, then there's no change, just return.
+        if (Arrays.equals(ipv4Address, mIPv4Address)) return;
+        // Otherwise update mIPv4Address and install new program.
+        mIPv4Address = ipv4Address;
+        installNewProgramLocked();
+    }
+
+    public synchronized void dump(IndentingPrintWriter pw) {
+        pw.println("APF caps: " + mApfCapabilities);
+        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
+        pw.println("Multicast filtering: " + mMulticastFilter);
+        try {
+            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address));
+        } catch (UnknownHostException|NullPointerException e) {}
+        if (mLastTimeInstalledProgram == 0) {
+            pw.println("No program installed.");
+            return;
+        }
+
+        pw.println(String.format(
+                "Last program length %d, installed %ds ago, lifetime %d",
+                mLastInstalledProgram.length, curTime() - mLastTimeInstalledProgram,
+                mLastInstalledProgramMinLifetime));
+
+        pw.println("RA filters:");
+        pw.increaseIndent();
+        for (Ra ra: mRas) {
+            pw.println(ra);
+            pw.increaseIndent();
+            pw.println(String.format(
+                    "Seen: %d, last %ds ago", ra.seenCount, curTime() - ra.mLastSeen));
+            if (DBG) {
+                pw.println("Last match:");
+                pw.increaseIndent();
+                pw.println(ra.getLastMatchingPacket());
+                pw.decreaseIndent();
+            }
+            pw.decreaseIndent();
+        }
+
+        if (DBG) {
+            pw.println("Last program:");
+            pw.increaseIndent();
+            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
+            pw.decreaseIndent();
+        }
+
+        pw.decreaseIndent();
+    }
+}
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 4f99bff..406dd56 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -30,6 +30,8 @@
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
+import android.net.metrics.IpConnectivityEvent;
+import android.net.metrics.DhcpClientEvent;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Message;
@@ -84,10 +86,10 @@
 public class DhcpClient extends StateMachine {
 
     private static final String TAG = "DhcpClient";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean STATE_DBG = false;
     private static final boolean MSG_DBG = false;
-    private static final boolean PACKET_DBG = true;
+    private static final boolean PACKET_DBG = false;
 
     // Timers and timeouts.
     private static final int SECONDS = 1000;
@@ -136,7 +138,7 @@
             MessageUtils.findMessageNames(sMessageClasses);
 
     // DHCP parameters that we request.
-    private static final byte[] REQUESTED_PARAMS = new byte[] {
+    /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
         DHCP_SUBNET_MASK,
         DHCP_ROUTER,
         DHCP_DNS_SERVER,
@@ -146,6 +148,7 @@
         DHCP_LEASE_TIME,
         DHCP_RENEWAL_TIME,
         DHCP_REBINDING_TIME,
+        DHCP_VENDOR_INFO,
     };
 
     // DHCP flag that means "yes, we support unicast."
@@ -342,27 +345,31 @@
 
         @Override
         public void run() {
-            maybeLog("Receive thread started");
+            if (DBG) Log.d(TAG, "Receive thread started");
             while (!stopped) {
                 int length = 0;  // Or compiler can't tell it's initialized if a parse error occurs.
                 try {
                     length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
                     DhcpPacket packet = null;
                     packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
-                    maybeLog("Received packet: " + packet);
+                    if (DBG) Log.d(TAG, "Received packet: " + packet);
                     sendMessage(CMD_RECEIVED_PACKET, packet);
                 } catch (IOException|ErrnoException e) {
                     if (!stopped) {
                         Log.e(TAG, "Read error", e);
                     }
+                    DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_RECV_ERROR,
+                            mIfaceName, e.getMessage());
                 } catch (DhcpPacket.ParseException e) {
                     Log.e(TAG, "Can't parse packet: " + e.getMessage());
                     if (PACKET_DBG) {
                         Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
                     }
+                    DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_PARSE_ERROR, mIfaceName,
+                            e.getMessage());
                 }
             }
-            maybeLog("Receive thread stopped");
+            if (DBG) Log.d(TAG, "Receive thread stopped");
         }
     }
 
@@ -373,12 +380,12 @@
     private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) {
         try {
             if (to.equals(INADDR_BROADCAST)) {
-                maybeLog("Broadcasting " + description);
+                if (DBG) Log.d(TAG, "Broadcasting " + description);
                 Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
             } else {
                 // It's safe to call getpeername here, because we only send unicast packets if we
                 // have an IP address, and we connect the UDP socket in DhcpHaveAddressState#enter.
-                maybeLog("Unicasting " + description + " to " + Os.getpeername(mUdpSock));
+                if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock));
                 Os.write(mUdpSock, buf);
             }
         } catch(ErrnoException|IOException e) {
@@ -454,13 +461,11 @@
         mController.sendMessage(CMD_ON_QUIT);
     }
 
-    private void maybeLog(String msg) {
-        if (DBG) Log.d(TAG, msg);
-    }
-
     abstract class LoggingState extends State {
         public void enter() {
-            if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
+            String msg = "Entering state " + getName();
+            if (STATE_DBG) Log.d(TAG, msg);
+            DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_STATE_CHANGE, mIfaceName, msg);
         }
 
         private String messageName(int what) {
@@ -592,7 +597,7 @@
                     transitionTo(mStoppedState);
                     return HANDLED;
                 case CMD_ONESHOT_TIMEOUT:
-                    maybeLog("Timed out");
+                    if (DBG) Log.d(TAG, "Timed out");
                     notifyFailure();
                     return HANDLED;
                 default:
@@ -790,7 +795,7 @@
 
         @Override
         public void exit() {
-            maybeLog("Clearing IP address");
+            if (DBG) Log.d(TAG, "Clearing IP address");
             setIpAddress(new LinkAddress("0.0.0.0/0"));
         }
     }
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 6a255e5..a881408 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -57,6 +57,17 @@
 
     public static final int HWADDR_LEN = 16;
     public static final int MAX_OPTION_LEN = 255;
+
+    /**
+     * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
+     * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
+     * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
+     * because in general it is risky to assume that the hardware is able to send/receive packets
+     * larger than 1500 bytes even if the network supports it.
+     */
+    private static final int MIN_MTU = 1280;
+    private static final int MAX_MTU = 1500;
+
     /**
      * IP layer definitions.
      */
@@ -819,7 +830,11 @@
             // server-to-server packets, e.g. for relays.
             if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
                 !isPacketServerToServer(udpSrcPort, udpDstPort)) {
-                return null;
+                // This should almost never happen because we use SO_ATTACH_FILTER on the packet
+                // socket to drop packets that don't have the right source ports. However, it's
+                // possible that a packet arrives between when the socket is bound and when the
+                // filter is set. http://b/26696823 .
+                throw new ParseException("Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
             }
         }
 
@@ -913,7 +928,7 @@
                             break;
                         case DHCP_MTU:
                             expectedLen = 2;
-                            mtu = Short.valueOf(packet.getShort());
+                            mtu = packet.getShort();
                             break;
                         case DHCP_DOMAIN_NAME:
                             expectedLen = optionLen;
@@ -1102,6 +1117,8 @@
         results.serverAddress = mServerIdentifier;
         results.vendorInfo = mVendorInfo;
         results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
+        results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
+
         return results;
     }
 
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 2a90c60..54aeb3d 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -19,6 +19,8 @@
 import com.android.internal.util.MessageUtils;
 
 import android.content.Context;
+import android.net.apf.ApfCapabilities;
+import android.net.apf.ApfFilter;
 import android.net.DhcpResults;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
@@ -38,10 +40,13 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.server.net.NetlinkTracker;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
@@ -63,12 +68,9 @@
  * @hide
  */
 public class IpManager extends StateMachine {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
-    private static final boolean NO_CALLBACKS = false;
-    private static final boolean SEND_CALLBACKS = true;
-
     // For message logging.
     private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
     private static final SparseArray<String> sWhatToString =
@@ -107,6 +109,17 @@
 
         // Called when the IpManager state machine terminates.
         public void onQuit() {}
+
+        // Install an APF program to filter incoming packets.
+        public void installPacketFilter(byte[] filter) {}
+
+        // If multicast filtering cannot be accomplished with APF, this function will be called to
+        // actuate multicast filtering using another means.
+        public void setFallbackMulticastFilter(boolean enabled) {}
+
+        // Enabled/disable Neighbor Discover offload functionality. This is
+        // called, for example, whenever 464xlat is being started or stopped.
+        public void setNeighborDiscoveryOffload(boolean enable) {}
     }
 
     public static class WaitForProvisioningCallback extends Callback {
@@ -178,6 +191,11 @@
                 return this;
             }
 
+            public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
+                mConfig.mApfCapabilities = apfCapabilities;
+                return this;
+            }
+
             public ProvisioningConfiguration build() {
                 return new ProvisioningConfiguration(mConfig);
             }
@@ -186,6 +204,7 @@
         /* package */ boolean mUsingIpReachabilityMonitor = true;
         /* package */ boolean mRequestedPreDhcpAction;
         /* package */ StaticIpConfiguration mStaticIpConfig;
+        /* package */ ApfCapabilities mApfCapabilities;
 
         public ProvisioningConfiguration() {}
 
@@ -193,9 +212,12 @@
             mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
             mRequestedPreDhcpAction = other.mRequestedPreDhcpAction;
             mStaticIpConfig = other.mStaticIpConfig;
+            mApfCapabilities = other.mApfCapabilities;
         }
     }
 
+    public static final String DUMP_ARG = "ipmanager";
+
     private static final int CMD_STOP = 1;
     private static final int CMD_START = 2;
     private static final int CMD_CONFIRM = 3;
@@ -204,9 +226,17 @@
     private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
     private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
     private static final int CMD_UPDATE_HTTP_PROXY = 7;
+    private static final int CMD_SET_MULTICAST_FILTER = 8;
 
     private static final int MAX_LOG_RECORDS = 1000;
 
+    private static final boolean NO_CALLBACKS = false;
+    private static final boolean SEND_CALLBACKS = true;
+
+    // This must match the interface prefix in clatd.c.
+    // TODO: Revert this hack once IpManager and Nat464Xlat work in concert.
+    private static final String CLAT_PREFIX = "v4-";
+
     private final Object mLock = new Object();
     private final State mStoppedState = new StoppedState();
     private final State mStoppingState = new StoppingState();
@@ -215,12 +245,13 @@
     private final String mTag;
     private final Context mContext;
     private final String mInterfaceName;
+    private final String mClatInterfaceName;
     @VisibleForTesting
     protected final Callback mCallback;
     private final INetworkManagementService mNwService;
     private final NetlinkTracker mNetlinkTracker;
 
-    private int mInterfaceIndex;
+    private NetworkInterface mNetworkInterface;
 
     /**
      * Non-final member variables accessed only from within our StateMachine.
@@ -231,6 +262,8 @@
     private DhcpResults mDhcpResults;
     private String mTcpBufferSizes;
     private ProxyInfo mHttpProxy;
+    private ApfFilter mApfFilter;
+    private boolean mMulticastFiltering;
 
     /**
      * Member variables accessed both from within the StateMachine thread
@@ -241,15 +274,23 @@
 
     public IpManager(Context context, String ifName, Callback callback)
                 throws IllegalArgumentException {
+        this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)));
+    }
+
+    /**
+     * An expanded constructor, useful for dependency injection.
+     */
+    public IpManager(Context context, String ifName, Callback callback,
+            INetworkManagementService nwService) throws IllegalArgumentException {
         super(IpManager.class.getSimpleName() + "." + ifName);
         mTag = getName();
 
         mContext = context;
         mInterfaceName = ifName;
+        mClatInterfaceName = CLAT_PREFIX + ifName;
         mCallback = callback;
-
-        mNwService = INetworkManagementService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+        mNwService = nwService;
 
         mNetlinkTracker = new NetlinkTracker(
                 mInterfaceName,
@@ -258,7 +299,27 @@
                     public void update() {
                         sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
                     }
-                });
+                }) {
+            @Override
+            public void interfaceAdded(String iface) {
+                super.interfaceAdded(iface);
+                if (mClatInterfaceName.equals(iface)) {
+                    mCallback.setNeighborDiscoveryOffload(false);
+                }
+            }
+
+            @Override
+            public void interfaceRemoved(String iface) {
+                super.interfaceRemoved(iface);
+                if (mClatInterfaceName.equals(iface)) {
+                    // TODO: consider sending a message to the IpManager main
+                    // StateMachine thread, in case "NDO enabled" state becomes
+                    // tied to more things that 464xlat operation.
+                    mCallback.setNeighborDiscoveryOffload(true);
+                }
+            }
+        };
+
         try {
             mNwService.registerObserver(mNetlinkTracker);
         } catch (RemoteException e) {
@@ -277,25 +338,6 @@
         super.start();
     }
 
-    /**
-     * A special constructor for use in testing that bypasses some of the more
-     * complicated setup bits.
-     *
-     * TODO: Figure out how to delete this yet preserve testability.
-     */
-    @VisibleForTesting
-    protected IpManager(String ifName, Callback callback) {
-        super(IpManager.class.getSimpleName() + ".test-" + ifName);
-        mTag = getName();
-
-        mInterfaceName = ifName;
-        mCallback = callback;
-
-        mContext = null;
-        mNwService = null;
-        mNetlinkTracker = null;
-    }
-
     @Override
     protected void onQuitting() {
         mCallback.onQuit();
@@ -312,7 +354,7 @@
     }
 
     public void startProvisioning(ProvisioningConfiguration req) {
-        getInterfaceIndex();
+        getNetworkInterface();
         sendMessage(CMD_START, new ProvisioningConfiguration(req));
     }
 
@@ -359,12 +401,34 @@
         sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
     }
 
+    /**
+     * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
+     * if not, Callback.setFallbackMulticastFilter() is called.
+     */
+    public void setMulticastFilter(boolean enabled) {
+        sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
+    }
+
     public LinkProperties getLinkProperties() {
         synchronized (mLock) {
             return new LinkProperties(mLinkProperties);
         }
     }
 
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        pw.println("APF dump:");
+        pw.increaseIndent();
+        // Thread-unsafe access to mApfFilter but just used for debugging.
+        ApfFilter apfFilter = mApfFilter;
+        if (apfFilter != null) {
+            apfFilter.dump(pw);
+        } else {
+            pw.println("No apf support");
+        }
+        pw.decreaseIndent();
+    }
+
 
     /**
      * Internals.
@@ -379,7 +443,7 @@
     protected String getLogRecString(Message msg) {
         final String logLine = String.format(
                 "iface{%s/%d} arg1{%d} arg2{%d} obj{%s}",
-                mInterfaceName, mInterfaceIndex,
+                mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
                 msg.arg1, msg.arg2, Objects.toString(msg.obj));
         if (VDBG) {
             Log.d(mTag, getWhatToString(msg.what) + " " + logLine);
@@ -387,12 +451,12 @@
         return logLine;
     }
 
-    private void getInterfaceIndex() {
+    private void getNetworkInterface() {
         try {
-            mInterfaceIndex = NetworkInterface.getByName(mInterfaceName).getIndex();
+            mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
         } catch (SocketException | NullPointerException e) {
             // TODO: throw new IllegalStateException.
-            Log.e(mTag, "ALERT: Failed to get interface index: ", e);
+            Log.e(mTag, "ALERT: Failed to get interface object: ", e);
         }
     }
 
@@ -474,6 +538,7 @@
     }
 
     private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+        if (mApfFilter != null) mApfFilter.setLinkProperties(newLp);
         switch (delta) {
             case GAINED_PROVISIONING:
                 if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
@@ -560,6 +625,10 @@
                 }
             }
             newLp.setDomains(mDhcpResults.domains);
+
+            if (mDhcpResults.mtu != 0) {
+                newLp.setMtu(mDhcpResults.mtu);
+            }
         }
 
         // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
@@ -680,6 +749,10 @@
                     handleLinkPropertiesUpdate(NO_CALLBACKS);
                     break;
 
+                case CMD_SET_MULTICAST_FILTER:
+                    mMulticastFiltering = (boolean) msg.obj;
+                    break;
+
                 case DhcpClient.CMD_ON_QUIT:
                     // Everything is already stopped.
                     Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
@@ -719,6 +792,11 @@
     class StartedState extends State {
         @Override
         public void enter() {
+            mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
+                    mCallback, mMulticastFiltering);
+            // TODO: investigate the effects of any multicast filtering racing/interfering with the
+            // rest of this IP configuration startup.
+            if (mApfFilter == null) mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             // Set privacy extensions.
             try {
                 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
@@ -775,6 +853,11 @@
                 mDhcpClient.doQuit();
             }
 
+            if (mApfFilter != null) {
+                mApfFilter.shutdown();
+                mApfFilter = null;
+            }
+
             resetLinkProperties();
         }
 
@@ -826,6 +909,16 @@
                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
                     break;
 
+                case CMD_SET_MULTICAST_FILTER: {
+                    mMulticastFiltering = (boolean) msg.obj;
+                    if (mApfFilter != null) {
+                        mApfFilter.setMulticastFilter(mMulticastFiltering);
+                    } else {
+                        mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+                    }
+                    break;
+                }
+
                 case DhcpClient.CMD_PRE_DHCP_ACTION:
                     if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
                     if (mConfiguration.mRequestedPreDhcpAction) {
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 88155f7..af3175a 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -24,6 +24,8 @@
 import android.net.LinkProperties.ProvisioningChange;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
+import android.net.metrics.IpReachabilityMonitorMessageEvent;
+import android.net.metrics.IpReachabilityMonitorProbeEvent;
 import android.net.netlink.NetlinkConstants;
 import android.net.netlink.NetlinkErrorMessage;
 import android.net.netlink.NetlinkMessage;
@@ -132,7 +134,7 @@
  */
 public class IpReachabilityMonitor {
     private static final String TAG = "IpReachabilityMonitor";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
     public interface Callback {
@@ -162,7 +164,7 @@
     private boolean mRunning;
 
     /**
-     * Make the kernel to perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
+     * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
      * for the given IP address on the specified interface index.
      *
      * @return true, if the request was successfully passed to the kernel; false otherwise.
@@ -203,7 +205,8 @@
         } catch (ErrnoException | InterruptedIOException | SocketException e) {
             Log.d(TAG, "Error " + msgSnippet, e);
         }
-
+        IpReachabilityMonitorProbeEvent.logEvent("ifindex-" + ifIndex, ip.getHostAddress(),
+                returnValue);
         return returnValue;
     }
 
@@ -400,8 +403,7 @@
         return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
     }
 
-
-    // TODO: simply the number of objects by making this extend Thread.
+    // TODO: simplify the number of objects by making this extend Thread.
     private final class NetlinkSocketObserver implements Runnable {
         private NetlinkSocket mSocket;
 
@@ -519,6 +521,8 @@
 
             final short msgType = neighMsg.getHeader().nlmsg_type;
             final short nudState = ndMsg.ndm_state;
+            IpReachabilityMonitorMessageEvent.logEvent(maybeGetInterfaceName(mInterfaceIndex),
+                    destination.getHostAddress(), msgType, nudState);
             final String eventMsg = "NeighborEvent{"
                     + "elapsedMs=" + whenMs + ", "
                     + destination.getHostAddress() + ", "
@@ -549,4 +553,11 @@
             }
         }
     }
+
+    private String maybeGetInterfaceName(int index) {
+        if (index == mInterfaceIndex) {
+            return mInterfaceName;
+        }
+        return "ifindex-" + index;
+    }
 }
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index e6f4177..4d02928 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -41,13 +41,18 @@
 import android.print.IPrintDocumentAdapter;
 import android.print.IPrintJobStateChangeListener;
 import android.print.IPrintManager;
+import android.printservice.recommendation.IRecommendationsChangeListener;
+import android.print.IPrintServicesChangeListener;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.PrintAttributes;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
 import android.print.PrinterId;
 import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.content.PackageMonitor;
@@ -66,6 +71,8 @@
  * PrintManager implementation is contained within.
  */
 public final class PrintManagerService extends SystemService {
+    private static final String LOG_TAG = "PrintManagerService";
+
     private final PrintManagerImpl mPrintManagerImpl;
 
     public PrintManagerService(Context context) {
@@ -124,7 +131,7 @@
                 }
                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
                 resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -146,7 +153,7 @@
                     return null;
                 }
                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -171,7 +178,7 @@
                     return null;
                 }
                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -192,7 +199,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return null;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -217,7 +224,7 @@
                     return;
                 }
                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -242,7 +249,7 @@
                     return;
                 }
                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -253,43 +260,75 @@
         }
 
         @Override
-        public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
+        public List<PrintServiceInfo> getPrintServices(int selectionFlags, int userId) {
+            Preconditions.checkFlagsArgument(selectionFlags,
+                    PrintManager.DISABLED_SERVICES | PrintManager.ENABLED_SERVICES);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
-                // Only the current group members can get enabled services.
+                // Only the current group members can get print services.
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return null;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
-
-                // The user state might be updated via the same observer-set as the caller of this
-                // interface. If the caller is called back first the user state is not yet updated
-                // and the user gets and inconsistent view. Hence force an update.
-                userState.updateIfNeededLocked();
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
-                return userState.getEnabledPrintServices();
+                return userState.getPrintServices(selectionFlags);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
         }
 
         @Override
-        public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
+        public void setPrintServiceEnabled(ComponentName service, boolean isEnabled, int userId) {
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final int appId = UserHandle.getAppId(Binder.getCallingUid());
+
+            try {
+                if (appId != Process.SYSTEM_UID && appId != UserHandle.getAppId(
+                        mContext.getPackageManager().getPackageUidAsUser(
+                                PrintManager.PRINT_SPOOLER_PACKAGE_NAME, resolvedUserId))) {
+                    throw new SecurityException("Only system and print spooler can call this");
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(LOG_TAG, "Could not verify caller", e);
+                return;
+            }
+
+            service = Preconditions.checkNotNull(service);
+
             final UserState userState;
             synchronized (mLock) {
-                // Only the current group members can get installed services.
+                // Only the current group members can enable / disable services.
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
-                    return null;
+                    return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
-                return userState.getInstalledPrintServices();
+                userState.setPrintServiceEnabled(service, isEnabled);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<RecommendationInfo> getPrintServiceRecommendations(int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can get print service recommendations.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return null;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getPrintServiceRecommendations();
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -307,7 +346,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -329,7 +368,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -355,7 +394,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -376,7 +415,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -397,7 +436,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -418,7 +457,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -439,7 +478,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -463,7 +502,7 @@
                     return;
                 }
                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -485,7 +524,7 @@
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
-                userState = getOrCreateUserStateLocked(resolvedUserId);
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
             }
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -496,6 +535,96 @@
         }
 
         @Override
+        public void addPrintServicesChangeListener(IPrintServicesChangeListener listener,
+                int userId) throws RemoteException {
+            listener = Preconditions.checkNotNull(listener);
+
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can add a print services listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.addPrintServicesChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void removePrintServicesChangeListener(IPrintServicesChangeListener listener,
+                int userId) {
+            listener = Preconditions.checkNotNull(listener);
+
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can remove a print services change listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.removePrintServicesChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void addPrintServiceRecommendationsChangeListener(
+                IRecommendationsChangeListener listener, int userId)
+                throws RemoteException {
+            listener = Preconditions.checkNotNull(listener);
+
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can add a print service recommendations listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.addPrintServiceRecommendationsChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void removePrintServiceRecommendationsChangeListener(
+                IRecommendationsChangeListener listener, int userId) {
+            listener = Preconditions.checkNotNull(listener);
+
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can remove a print service recommendations
+                // listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.removePrintServiceRecommendationsChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             fd = Preconditions.checkNotNull(fd);
             pw = Preconditions.checkNotNull(pw);
@@ -550,43 +679,79 @@
 
         private void registerBroadcastReceivers() {
             PackageMonitor monitor = new PackageMonitor() {
-                private void updateServices(String packageName) {
-                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
-                    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());
+                /**
+                 * Checks if the package contains a print service.
+                 *
+                 * @param packageName The name of the package
+                 *
+                 * @return true iff the package contains a print service
+                 */
+                private boolean hasPrintService(String packageName) {
+                    Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+                    intent.setPackage(packageName);
 
-                        List<PrintServiceInfo> installedServices = userState
-                                .getInstalledPrintServices();
-                        final int numInstalledServices = installedServices.size();
-                        for (int i = 0; i < numInstalledServices; i++) {
-                            if (installedServices.get(i).getResolveInfo().serviceInfo.packageName
-                                    .equals(packageName)) {
-                                servicesChanged = true;
-                                break;
-                            }
-                        }
-                        if (servicesChanged) {
-                            userState.updateIfNeededLocked();
+                    List<ResolveInfo> installedServices = mContext.getPackageManager()
+                            .queryIntentServicesAsUser(intent,
+                                    GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING,
+                                    getChangingUserId());
+
+                    return installedServices != null && !installedServices.isEmpty();
+                }
+
+                /**
+                 * Checks if there is a print service currently registered for this package.
+                 *
+                 * @param userState The userstate for the current user
+                 * @param packageName The name of the package
+                 *
+                 * @return true iff the package contained (and might still contain) a print service
+                 */
+                private boolean hadPrintService(@NonNull UserState userState, String packageName) {
+                    List<PrintServiceInfo> installedServices = userState
+                            .getPrintServices(PrintManager.ALL_SERVICES);
+
+                    if (installedServices == null) {
+                        return false;
+                    }
+
+                    final int numInstalledServices = installedServices.size();
+                    for (int i = 0; i < numInstalledServices; i++) {
+                        if (installedServices.get(i).getResolveInfo().serviceInfo.packageName
+                                .equals(packageName)) {
+                            return true;
                         }
                     }
+
+                    return false;
                 }
 
                 @Override
                 public void onPackageModified(String packageName) {
                     if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
-                    updateServices(packageName);
-                    getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
+                    UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false);
+
+                    synchronized (mLock) {
+                        if (hadPrintService(userState, packageName)
+                                || hasPrintService(packageName)) {
+                            userState.updateIfNeededLocked();
+                        }
+                    }
+
+                    userState.prunePrintServices();
                 }
 
                 @Override
                 public void onPackageRemoved(String packageName, int uid) {
                     if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
-                    updateServices(packageName);
-                    getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
+                    UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false);
+
+                    synchronized (mLock) {
+                        if (hadPrintService(userState, packageName)) {
+                            userState.updateIfNeededLocked();
+                        }
+                    }
+
+                    userState.prunePrintServices();
                 }
 
                 @Override
@@ -597,11 +762,12 @@
                         // 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());
+                        UserState userState = getOrCreateUserStateLocked(getChangingUserId(),
+                                false);
                         boolean stoppedSomePackages = false;
 
                         List<PrintServiceInfo> enabledServices = userState
-                                .getEnabledPrintServices();
+                                .getPrintServices(PrintManager.ENABLED_SERVICES);
                         if (enabledServices == null) {
                             return false;
                         }
@@ -630,21 +796,12 @@
                 @Override
                 public void onPackageAdded(String packageName, int uid) {
                     if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
-
-                    // 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);
-
-                    List<ResolveInfo> installedServices = mContext.getPackageManager()
-                            .queryIntentServicesAsUser(intent,
-                                    GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING,
-                                    getChangingUserId());
-
-                    if (installedServices != null) {
-                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                        userState.updateIfNeededLocked();
+                    synchronized (mLock) {
+                        if (hasPrintService(packageName)) {
+                            UserState userState = getOrCreateUserStateLocked(getChangingUserId(),
+                                    false);
+                            userState.updateIfNeededLocked();
+                        }
                     }
                 }
             };
@@ -654,7 +811,7 @@
                     UserHandle.ALL, true);
         }
 
-        private UserState getOrCreateUserStateLocked(int userId) {
+        private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority) {
             if (!mUserManager.isUserUnlocked(userId)) {
                 throw new IllegalStateException(
                         "User " + userId + " must be unlocked for printing to be available");
@@ -662,9 +819,14 @@
 
             UserState userState = mUserStates.get(userId);
             if (userState == null) {
-                userState = new UserState(mContext, userId, mLock);
+                userState = new UserState(mContext, userId, mLock, lowPriority);
                 mUserStates.put(userId, userState);
             }
+
+            if (!lowPriority) {
+                userState.increasePriority();
+            }
+
             return userState;
         }
 
@@ -676,7 +838,7 @@
                 public void run() {
                     UserState userState;
                     synchronized (mLock) {
-                        userState = getOrCreateUserStateLocked(userId);
+                        userState = getOrCreateUserStateLocked(userId, true);
                         userState.updateIfNeededLocked();
                     }
                     // This is the first time we switch to this user after boot, so
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 9b99c67..9c3a852 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -19,6 +19,7 @@
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -813,6 +814,20 @@
         }
 
         @Override
+        public void setStatusRes(@NonNull PrintJobId printJobId, @StringRes int status,
+                @NonNull CharSequence appPackageName) {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    service.mSpooler.setStatus(printJobId, status, appPackageName);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @Override
         @SuppressWarnings({"rawtypes", "unchecked"})
         public void onPrintersAdded(ParceledListSlice printers) {
             RemotePrintService service = mWeakService.get();
diff --git a/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java b/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java
new file mode 100644
index 0000000..fa1f232
--- /dev/null
+++ b/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.print;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.printservice.recommendation.IRecommendationService;
+import android.printservice.recommendation.IRecommendationServiceCallbacks;
+import android.printservice.recommendation.RecommendationInfo;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+import static android.content.pm.PackageManager.GET_META_DATA;
+import static android.content.pm.PackageManager.GET_SERVICES;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+
+/**
+ * Connection to a remote print service recommendation service.
+ */
+class RemotePrintServiceRecommendationService {
+    private static final String LOG_TAG = "RemotePrintServiceRecS";
+
+    /** Lock for this object */
+    private final Object mLock = new Object();
+
+    /** Context used for the connection */
+    private @NonNull final Context mContext;
+
+    /**  The connection to the service (if {@link #mIsBound bound}) */
+    @GuardedBy("mLock")
+    private @NonNull final Connection mConnection;
+
+    /** If the service is currently bound. */
+    @GuardedBy("mLock")
+    private boolean mIsBound;
+
+    /** The service once bound */
+    @GuardedBy("mLock")
+    private IRecommendationService mService;
+
+    /**
+     * Callbacks to be called when there are updates to the print service recommendations.
+     */
+    public interface RemotePrintServiceRecommendationServiceCallbacks {
+        /**
+         * Called when there is an update list of print service recommendations.
+         *
+         * @param recommendations The new recommendations.
+         */
+        void onPrintServiceRecommendationsUpdated(
+                @Nullable List<RecommendationInfo> recommendations);
+    }
+
+    /**
+     * @return The intent that is used to connect to the print service recommendation service.
+     */
+    private Intent getServiceIntent(@NonNull UserHandle userHandle) throws Exception {
+        List<ResolveInfo> installedServices = mContext.getPackageManager()
+                .queryIntentServicesAsUser(new Intent(
+                        android.printservice.recommendation.RecommendationService.SERVICE_INTERFACE),
+                        GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING,
+                        userHandle.getIdentifier());
+
+        if (installedServices.size() != 1) {
+            throw new Exception(installedServices.size() + " instead of exactly one service found");
+        }
+
+        ResolveInfo installedService = installedServices.get(0);
+
+        ComponentName serviceName = new ComponentName(
+                installedService.serviceInfo.packageName,
+                installedService.serviceInfo.name);
+
+        ApplicationInfo appInfo = mContext.getPackageManager()
+                .getApplicationInfo(installedService.serviceInfo.packageName, 0);
+
+        if (appInfo == null) {
+            throw new Exception("Cannot read appInfo for service");
+        }
+
+        if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            throw new Exception("Service is not part of the system");
+        }
+
+        if (!android.Manifest.permission.BIND_PRINT_RECOMMENDATION_SERVICE.equals(
+                installedService.serviceInfo.permission)) {
+            throw new Exception("Service " + serviceName.flattenToShortString()
+                    + " does not require permission "
+                    + android.Manifest.permission.BIND_PRINT_RECOMMENDATION_SERVICE);
+        }
+
+        Intent serviceIntent = new Intent();
+        serviceIntent.setComponent(serviceName);
+
+        return serviceIntent;
+    }
+
+    /**
+     * Open a new connection to a {@link IRecommendationService remote print service
+     * recommendation service}.
+     *
+     * @param context    The context establishing the connection
+     * @param userHandle The user the connection is for
+     * @param callbacks  The callbacks to call by the service
+     */
+    RemotePrintServiceRecommendationService(@NonNull Context context,
+            @NonNull UserHandle userHandle,
+            @NonNull RemotePrintServiceRecommendationServiceCallbacks callbacks) {
+        mContext = context;
+        mConnection = new Connection(callbacks);
+
+        try {
+            Intent serviceIntent = getServiceIntent(userHandle);
+
+            synchronized (mLock) {
+                mIsBound = mContext.bindServiceAsUser(serviceIntent, mConnection,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, userHandle);
+
+                if (!mIsBound) {
+                    throw new Exception("Failed to bind to service " + serviceIntent);
+                }
+            }
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Could not connect to print service recommendation service", e);
+        }
+    }
+
+    /**
+     * Terminate the connection to the {@link IRecommendationService remote print
+     * service recommendation service}.
+     */
+    void close() {
+        synchronized (mLock) {
+            if (mService != null) {
+                try {
+                    mService.registerCallbacks(null);
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, "Could not unregister callbacks", e);
+                }
+
+                mService = null;
+            }
+
+            if (mIsBound) {
+                mContext.unbindService(mConnection);
+                mIsBound = false;
+            }
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        if (mIsBound || mService != null) {
+            Log.w(LOG_TAG, "Service still connected on finalize()");
+            close();
+        }
+
+        super.finalize();
+    }
+
+    /**
+     * Connection to the service.
+     */
+    private class Connection implements ServiceConnection {
+        private final RemotePrintServiceRecommendationServiceCallbacks mCallbacks;
+
+        public Connection(@NonNull RemotePrintServiceRecommendationServiceCallbacks callbacks) {
+            mCallbacks = callbacks;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (mLock) {
+                mService = (IRecommendationService)IRecommendationService.Stub.asInterface(service);
+
+                try {
+                    mService.registerCallbacks(new IRecommendationServiceCallbacks.Stub() {
+                        @Override
+                        public void onRecommendationsUpdated(
+                                List<RecommendationInfo> recommendations) {
+                            synchronized (mLock) {
+                                if (mIsBound && mService != null) {
+                                    if (recommendations != null) {
+                                        Preconditions.checkCollectionElementsNotNull(
+                                                recommendations, "recommendation");
+                                    }
+
+                                    mCallbacks.onPrintServiceRecommendationsUpdated(
+                                            recommendations);
+                                }
+                            }
+                        }
+                    });
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, "Could not register callbacks", e);
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.w(LOG_TAG, "Unexpected termination of connection");
+
+            synchronized (mLock) {
+                mService = null;
+            }
+        }
+    }
+}
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index d179b95..07cc9c0 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -19,6 +19,7 @@
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -36,6 +37,7 @@
 import android.print.IPrintSpoolerClient;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
+import android.print.PrintManager;
 import android.print.PrinterId;
 import android.printservice.PrintService;
 import android.util.Slog;
@@ -96,6 +98,8 @@
 
     private final PrintSpoolerCallbacks mCallbacks;
 
+    private boolean mIsLowPriority;
+
     private IPrintSpooler mRemoteInstance;
 
     private boolean mDestroyed;
@@ -108,15 +112,40 @@
         public void onPrintJobStateChanged(PrintJobInfo printJob);
     }
 
-    public RemotePrintSpooler(Context context, int userId,
+    public RemotePrintSpooler(Context context, int userId, boolean lowPriority,
             PrintSpoolerCallbacks callbacks) {
         mContext = context;
         mUserHandle = new UserHandle(userId);
         mCallbacks = callbacks;
+        mIsLowPriority = lowPriority;
         mClient = new PrintSpoolerClient(this);
         mIntent = new Intent();
-        mIntent.setComponent(new ComponentName("com.android.printspooler",
-                "com.android.printspooler.model.PrintSpoolerService"));
+        mIntent.setComponent(new ComponentName(PrintManager.PRINT_SPOOLER_PACKAGE_NAME,
+                PrintManager.PRINT_SPOOLER_PACKAGE_NAME + ".model.PrintSpoolerService"));
+    }
+
+    public void increasePriority() {
+        if (mIsLowPriority) {
+            mIsLowPriority = false;
+
+            synchronized (mLock) {
+                throwIfDestroyedLocked();
+
+                while (!mCanUnbind) {
+                    try {
+                        mLock.wait();
+                    } catch (InterruptedException e) {
+                        Slog.e(LOG_TAG, "Interrupted while waiting for operation to complete");
+                    }
+                }
+
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "Unbinding as previous binding was low priority");
+                }
+
+                unbindLocked();
+            }
+        }
     }
 
     public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state,
@@ -300,6 +329,35 @@
     }
 
     /**
+     * Set status of a print job.
+     *
+     * @param printJobId The print job to update
+     * @param status The new status as a string resource
+     * @param appPackageName The app package name the string res belongs to
+     */
+    public final void setStatus(@NonNull PrintJobId printJobId, @StringRes int status,
+            @NonNull CharSequence appPackageName) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            getRemoteInstanceLazy().setStatusRes(printJobId, status, appPackageName);
+        } catch (RemoteException|TimeoutException re) {
+            Slog.e(LOG_TAG, "Error setting status.", re);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setStatus()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
+    /**
      * Handle that a custom icon for a printer was loaded.
      *
      * @param printerId the id of the printer the icon belongs to
@@ -548,11 +606,18 @@
             return;
         }
         if (DEBUG) {
-            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
+            Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked() " +
+                    (mIsLowPriority ? "low priority" : ""));
         }
 
-        mContext.bindServiceAsUser(mIntent, mServiceConnection,
-                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, mUserHandle);
+        int flags;
+        if (mIsLowPriority) {
+            flags = Context.BIND_AUTO_CREATE;
+        } else {
+            flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+        }
+
+        mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, mUserHandle);
 
         final long startMillis = SystemClock.uptimeMillis();
         while (true) {
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index fcf2fc8..026942e 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -37,6 +37,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
+import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteCallbackList;
@@ -44,11 +45,14 @@
 import android.os.UserHandle;
 import android.print.IPrintDocumentAdapter;
 import android.print.IPrintJobStateChangeListener;
+import android.printservice.recommendation.IRecommendationsChangeListener;
+import android.print.IPrintServicesChangeListener;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.PrintAttributes;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
 import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
@@ -67,6 +71,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
 import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
+import com.android.server.print.RemotePrintServiceRecommendationService.RemotePrintServiceRecommendationServiceCallbacks;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -81,7 +86,8 @@
 /**
  * Represents the print state for a user.
  */
-final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
+final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
+        RemotePrintServiceRecommendationServiceCallbacks {
 
     private static final String LOG_TAG = "UserState";
 
@@ -121,13 +127,27 @@
 
     private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords;
 
+    private List<ListenerRecord<IPrintServicesChangeListener>> mPrintServicesChangeListenerRecords;
+
+    private List<ListenerRecord<IRecommendationsChangeListener>>
+            mPrintServiceRecommendationsChangeListenerRecords;
+
     private boolean mDestroyed;
 
-    public UserState(Context context, int userId, Object lock) {
+    /** Currently known list of print service recommendations */
+    private List<RecommendationInfo> mPrintServiceRecommendations;
+
+    /**
+     * Connection to the service updating the {@link #mPrintServiceRecommendations print service
+     * recommendations}.
+     */
+    private RemotePrintServiceRecommendationService mPrintServiceRecommendationsService;
+
+    public UserState(Context context, int userId, Object lock, boolean lowPriority) {
         mContext = context;
         mUserId = userId;
         mLock = lock;
-        mSpooler = new RemotePrintSpooler(context, userId, this);
+        mSpooler = new RemotePrintSpooler(context, userId, lowPriority, this);
         mHandler = new UserStateHandler(context.getMainLooper());
 
         synchronized (mLock) {
@@ -142,6 +162,10 @@
         }
     }
 
+    public void increasePriority() {
+        mSpooler.increasePriority();
+    }
+
     @Override
     public void onPrintJobQueued(PrintJobInfo printJob) {
         final RemotePrintService service;
@@ -342,32 +366,73 @@
         mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
     }
 
-    public @Nullable List<PrintServiceInfo> getEnabledPrintServices() {
+    public @Nullable List<PrintServiceInfo> getPrintServices(int selectionFlags) {
         synchronized (mLock) {
-            List<PrintServiceInfo> enabledServices = null;
+            List<PrintServiceInfo> selectedServices = null;
             final int installedServiceCount = mInstalledServices.size();
             for (int i = 0; i < installedServiceCount; i++) {
                 PrintServiceInfo installedService = mInstalledServices.get(i);
+
                 ComponentName componentName = new ComponentName(
                         installedService.getResolveInfo().serviceInfo.packageName,
                         installedService.getResolveInfo().serviceInfo.name);
-                if (mActiveServices.containsKey(componentName)) {
-                    if (enabledServices == null) {
-                        enabledServices = new ArrayList<PrintServiceInfo>();
+
+                // Update isEnabled under the same lock the final returned list is created
+                installedService.setIsEnabled(mActiveServices.containsKey(componentName));
+
+                if (installedService.isEnabled()) {
+                    if ((selectionFlags & PrintManager.ENABLED_SERVICES) == 0) {
+                        continue;
                     }
-                    enabledServices.add(installedService);
+                } else {
+                    if ((selectionFlags & PrintManager.DISABLED_SERVICES) == 0) {
+                        continue;
+                    }
                 }
+
+                if (selectedServices == null) {
+                    selectedServices = new ArrayList<>();
+                }
+                selectedServices.add(installedService);
             }
-            return enabledServices;
+            return selectedServices;
         }
     }
 
-    public List<PrintServiceInfo> getInstalledPrintServices() {
+    public void setPrintServiceEnabled(@NonNull ComponentName serviceName, boolean isEnabled) {
         synchronized (mLock) {
-            return mInstalledServices;
+            boolean isChanged = false;
+            if (isEnabled) {
+                isChanged = mDisabledServices.remove(serviceName);
+            } else {
+                // Make sure to only disable services that are currently installed
+                final int numServices = mInstalledServices.size();
+                for (int i = 0; i < numServices; i++) {
+                    PrintServiceInfo service = mInstalledServices.get(i);
+
+                    if (service.getComponentName().equals(serviceName)) {
+                        mDisabledServices.add(serviceName);
+                        isChanged = true;
+                        break;
+                    }
+                }
+            }
+
+            if (isChanged) {
+                writeDisabledPrintServicesLocked(mDisabledServices);
+
+                onConfigurationChangedLocked();
+            }
         }
     }
 
+    /**
+     * @return The currently known print service recommendations
+     */
+    public @Nullable List<RecommendationInfo> getPrintServiceRecommendations() {
+        return mPrintServiceRecommendations;
+    }
+
     public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
@@ -406,10 +471,7 @@
             @Nullable List<PrinterId> printerIds) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
-            // No services - nothing to do.
-            if (mActiveServices.isEmpty()) {
-                return;
-            }
+
             // No session - nothing to do.
             if (mPrinterDiscoverySession == null) {
                 return;
@@ -423,10 +485,7 @@
     public void stopPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
-            // No services - nothing to do.
-            if (mActiveServices.isEmpty()) {
-                return;
-            }
+
             // No session - nothing to do.
             if (mPrinterDiscoverySession == null) {
                 return;
@@ -523,6 +582,92 @@
         }
     }
 
+    public void addPrintServicesChangeListener(@NonNull IPrintServicesChangeListener listener)
+            throws RemoteException {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintServicesChangeListenerRecords == null) {
+                mPrintServicesChangeListenerRecords = new ArrayList<>();
+            }
+            mPrintServicesChangeListenerRecords.add(
+                    new ListenerRecord<IPrintServicesChangeListener>(listener) {
+                        @Override
+                        public void onBinderDied() {
+                            mPrintServicesChangeListenerRecords.remove(this);
+                        }
+                    });
+        }
+    }
+
+    public void removePrintServicesChangeListener(@NonNull IPrintServicesChangeListener listener) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintServicesChangeListenerRecords == null) {
+                return;
+            }
+            final int recordCount = mPrintServicesChangeListenerRecords.size();
+            for (int i = 0; i < recordCount; i++) {
+                ListenerRecord<IPrintServicesChangeListener> record =
+                        mPrintServicesChangeListenerRecords.get(i);
+                if (record.listener.asBinder().equals(listener.asBinder())) {
+                    mPrintServicesChangeListenerRecords.remove(i);
+                    break;
+                }
+            }
+            if (mPrintServicesChangeListenerRecords.isEmpty()) {
+                mPrintServicesChangeListenerRecords = null;
+            }
+        }
+    }
+
+    public void addPrintServiceRecommendationsChangeListener(
+            @NonNull IRecommendationsChangeListener listener) throws RemoteException {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+                mPrintServiceRecommendationsChangeListenerRecords = new ArrayList<>();
+
+                mPrintServiceRecommendationsService =
+                        new RemotePrintServiceRecommendationService(mContext,
+                                UserHandle.getUserHandleForUid(mUserId), this);
+            }
+            mPrintServiceRecommendationsChangeListenerRecords.add(
+                    new ListenerRecord<IRecommendationsChangeListener>(listener) {
+                        @Override
+                        public void onBinderDied() {
+                            mPrintServiceRecommendationsChangeListenerRecords.remove(this);
+                        }
+                    });
+        }
+    }
+
+    public void removePrintServiceRecommendationsChangeListener(
+            @NonNull IRecommendationsChangeListener listener) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+                return;
+            }
+            final int recordCount = mPrintServiceRecommendationsChangeListenerRecords.size();
+            for (int i = 0; i < recordCount; i++) {
+                ListenerRecord<IRecommendationsChangeListener> record =
+                        mPrintServiceRecommendationsChangeListenerRecords.get(i);
+                if (record.listener.asBinder().equals(listener.asBinder())) {
+                    mPrintServiceRecommendationsChangeListenerRecords.remove(i);
+                    break;
+                }
+            }
+            if (mPrintServiceRecommendationsChangeListenerRecords.isEmpty()) {
+                mPrintServiceRecommendationsChangeListenerRecords = null;
+
+                mPrintServiceRecommendations = null;
+
+                mPrintServiceRecommendationsService.close();
+                mPrintServiceRecommendationsService = null;
+            }
+        }
+    }
+
     @Override
     public void onPrintJobStateChanged(PrintJobInfo printJob) {
         mPrintJobForAppCache.onPrintJobStateChanged(printJob);
@@ -530,6 +675,16 @@
                 printJob.getAppId(), 0, printJob.getId()).sendToTarget();
     }
 
+    public void onPrintServicesChanged() {
+        mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_SERVICES_CHANGED).sendToTarget();
+    }
+
+    @Override
+    public void onPrintServiceRecommendationsUpdated(List<RecommendationInfo> recommendations) {
+        mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED,
+                0, 0, recommendations).sendToTarget();
+    }
+
     @Override
     public void onPrintersAdded(List<PrinterInfo> printers) {
         synchronized (mLock) {
@@ -894,6 +1049,8 @@
                 iterator.remove();
             }
         }
+
+        onPrintServicesChanged();
     }
 
     private void addServiceLocked(RemotePrintService service) {
@@ -978,8 +1135,53 @@
         }
     }
 
+    private void handleDispatchPrintServicesChanged() {
+        final List<ListenerRecord<IPrintServicesChangeListener>> records;
+        synchronized (mLock) {
+            if (mPrintServicesChangeListenerRecords == null) {
+                return;
+            }
+            records = new ArrayList<>(mPrintServicesChangeListenerRecords);
+        }
+        final int recordCount = records.size();
+        for (int i = 0; i < recordCount; i++) {
+            ListenerRecord<IPrintServicesChangeListener> record = records.get(i);
+
+            try {
+                record.listener.onPrintServicesChanged();;
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error notifying for print services change", re);
+            }
+        }
+    }
+
+    private void handleDispatchPrintServiceRecommendationsUpdated(
+            @Nullable List<RecommendationInfo> recommendations) {
+        final List<ListenerRecord<IRecommendationsChangeListener>> records;
+        synchronized (mLock) {
+            if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+                return;
+            }
+            records = new ArrayList<>(mPrintServiceRecommendationsChangeListenerRecords);
+
+            mPrintServiceRecommendations = recommendations;
+        }
+        final int recordCount = records.size();
+        for (int i = 0; i < recordCount; i++) {
+            ListenerRecord<IRecommendationsChangeListener> record = records.get(i);
+
+            try {
+                record.listener.onRecommendationsChanged();
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error notifying for print service recommendations change", re);
+            }
+        }
+    }
+
     private final class UserStateHandler extends Handler {
         public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1;
+        public static final int MSG_DISPATCH_PRINT_SERVICES_CHANGED = 2;
+        public static final int MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED = 3;
 
         public UserStateHandler(Looper looper) {
             super(looper, null, false);
@@ -987,10 +1189,21 @@
 
         @Override
         public void handleMessage(Message message) {
-            if (message.what == MSG_DISPATCH_PRINT_JOB_STATE_CHANGED) {
-                PrintJobId printJobId = (PrintJobId) message.obj;
-                final int appId = message.arg1;
-                handleDispatchPrintJobStateChanged(printJobId, appId);
+            switch (message.what) {
+                case MSG_DISPATCH_PRINT_JOB_STATE_CHANGED:
+                    PrintJobId printJobId = (PrintJobId) message.obj;
+                    final int appId = message.arg1;
+                    handleDispatchPrintJobStateChanged(printJobId, appId);
+                    break;
+                case MSG_DISPATCH_PRINT_SERVICES_CHANGED:
+                    handleDispatchPrintServicesChanged();
+                    break;
+                case MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED:
+                    handleDispatchPrintServiceRecommendationsUpdated(
+                            (List<RecommendationInfo>) message.obj);
+                    break;
+                default:
+                    // not reached
             }
         }
     }
@@ -1015,6 +1228,23 @@
         public abstract void onBinderDied();
     }
 
+    private abstract class ListenerRecord<T extends IInterface> implements DeathRecipient {
+        @NonNull final T listener;
+
+        public ListenerRecord(@NonNull T listener) throws RemoteException {
+            this.listener = listener;
+            listener.asBinder().linkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            listener.asBinder().unlinkToDeath(this, 0);
+            onBinderDied();
+        }
+
+        public abstract void onBinderDied();
+    }
+
     private class PrinterDiscoverySessionMediator {
         private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
                 new ArrayMap<PrinterId, PrinterInfo>();
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 3ae1072..23f186c 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -106,6 +106,10 @@
 
         <service android:name="com.android.server.job.MockPriorityJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE" />
+
+        <activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity" />
+        <activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity2" />
+        <activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity3" />
     </application>
 
     <instrumentation
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png
new file mode 100644
index 0000000..f700326
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_16x64.png b/services/tests/servicestests/res/drawable-nodpi/black_16x64.png
new file mode 100644
index 0000000..315763e
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_16x64.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_32x32.png b/services/tests/servicestests/res/drawable-nodpi/black_32x32.png
new file mode 100644
index 0000000..8958f6b
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_32x32.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png
new file mode 100644
index 0000000..f675030
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png
new file mode 100644
index 0000000..999d858
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_512x512.png b/services/tests/servicestests/res/drawable-nodpi/black_512x512.png
new file mode 100644
index 0000000..40d1c2c
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_512x512.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x16.png b/services/tests/servicestests/res/drawable-nodpi/black_64x16.png
new file mode 100644
index 0000000..5883015
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_64x16.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x64.png b/services/tests/servicestests/res/drawable-nodpi/black_64x64.png
new file mode 100644
index 0000000..71cfafc
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_64x64.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/icon1.png b/services/tests/servicestests/res/drawable-nodpi/icon1.png
new file mode 100644
index 0000000..64eb294
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/icon1.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/icon2.png b/services/tests/servicestests/res/drawable-nodpi/icon2.png
new file mode 100644
index 0000000..7502484
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/icon2.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable/icon1.png b/services/tests/servicestests/res/drawable/icon1.png
new file mode 100644
index 0000000..64eb294
--- /dev/null
+++ b/services/tests/servicestests/res/drawable/icon1.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable/icon2.png b/services/tests/servicestests/res/drawable/icon2.png
new file mode 100644
index 0000000..7502484
--- /dev/null
+++ b/services/tests/servicestests/res/drawable/icon2.png
Binary files differ
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index 2a967e6..f8eaf7d 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -261,7 +261,7 @@
 
     private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
             String domains, String serverAddress, String vendorInfo, int leaseDuration,
-            boolean hasMeteredHint, DhcpResults dhcpResults) throws Exception {
+            boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
         assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
         assertEquals(v4Address(gateway), dhcpResults.gateway);
 
@@ -277,6 +277,7 @@
         assertEquals(vendorInfo, dhcpResults.vendorInfo);
         assertEquals(leaseDuration, dhcpResults.leaseDuration);
         assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
+        assertEquals(mtu, dhcpResults.mtu);
     }
 
     @SmallTest
@@ -310,7 +311,7 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
-                null, "192.168.144.3", null, 7200, false, dhcpResults);
+                null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -342,10 +343,70 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
-                null, "192.168.43.1", "ANDROID_METERED", 3600, true, dhcpResults);
+                null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
         assertTrue(dhcpResults.hasMeteredHint());
     }
 
+    private byte[] mtuBytes(int mtu) {
+        // 0x1a02: option 26, length 2. 0xff: no more options.
+        if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
+            throw new IllegalArgumentException(
+                String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
+        }
+        String hexString = String.format("1a02%04xff", mtu);
+        return HexEncoding.decode(hexString.toCharArray(), false);
+    }
+
+    private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
+        if (mtuBytes != null) {
+            packet.position(packet.capacity() - mtuBytes.length);
+            packet.put(mtuBytes);
+            packet.clear();
+        }
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
+        DhcpResults dhcpResults = offerPacket.toDhcpResults();
+        assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
+                null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
+    }
+
+    @SmallTest
+    public void testMtu() throws Exception {
+        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+            // IP header.
+            "451001480000000080118849c0a89003c0a89ff7" +
+            // UDP header.
+            "004300440134dcfa" +
+            // BOOTP header.
+            "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
+            // MAC address.
+            "30766ff2a90c00000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Options
+            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
+            "3a0400000e103b040000189cff00000000"
+        ).toCharArray(), false));
+
+        checkMtu(packet, 0, null);
+        checkMtu(packet, 0, mtuBytes(1501));
+        checkMtu(packet, 1500, mtuBytes(1500));
+        checkMtu(packet, 1499, mtuBytes(1499));
+        checkMtu(packet, 1280, mtuBytes(1280));
+        checkMtu(packet, 0, mtuBytes(1279));
+        checkMtu(packet, 0, mtuBytes(576));
+        checkMtu(packet, 0, mtuBytes(68));
+        checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
+        checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
+        checkMtu(packet, 0, mtuBytes(-1));
+    }
+
     @SmallTest
     public void testBadHwaddrLength() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
@@ -453,7 +514,7 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
-                null, "1.1.1.1", null, 43200, false, dhcpResults);
+                null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -484,7 +545,7 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
-                "domain123.co.uk", "192.0.2.254", null, 49094, false, dhcpResults);
+                "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -518,7 +579,7 @@
         assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
-                "lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults);
+                "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -554,7 +615,40 @@
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("10.15.122.242/16", "10.15.200.23",
                 "209.129.128.3,209.129.148.3,209.129.128.6",
-                "wvm.edu", "10.1.105.252", null, 86400, false, dhcpResults);
+                "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
+    }
+
+    @SmallTest
+    public void testUdpInvalidDstPort() throws Exception {
+        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+            // Ethernet header.
+            "9cd917000000001c2e0000000800" +
+            // IP header.
+            "45a00148000040003d115087d18194fb0a0f7af2" +
+            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
+            // NOTE: The destination port is a non-DHCP port.
+            "0043aaaa01341268" +
+            // BOOTP header.
+            "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
+            // MAC address.
+            "9cd91700000000000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Options.
+            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
+            "d18180060f0777766d2e6564751c040a0fffffff000000"
+        ).toCharArray(), false));
+
+        try {
+            DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+            fail("Packet with invalid dst port did not throw ParseException");
+        } catch (ParseException expected) {}
     }
 
     @SmallTest
@@ -588,7 +682,7 @@
         assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
-                null, "192.171.189.2", null, 28800, false, dhcpResults);
+                null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -598,18 +692,10 @@
         byte[] hwaddr = {
                 (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a
         };
-        byte[] params = new byte[] {
-            DHCP_SUBNET_MASK,
-            DHCP_ROUTER,
-            DHCP_DNS_SERVER,
-            DHCP_DOMAIN_NAME,
-            DHCP_MTU,
-            DHCP_LEASE_TIME,
-        };
 
         ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
                 DhcpPacket.ENCAP_L2, transactionId, secs, hwaddr,
-                false /* do unicast */, params);
+                false /* do unicast */, DhcpClient.REQUESTED_PARAMS);
 
         byte[] headers = new byte[] {
             // Ethernet header.
@@ -617,14 +703,14 @@
             (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
             (byte) 0x08, (byte) 0x00,
             // IP header.
-            (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x52,
+            (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x56,
             (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x00,
-            (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x8c,
+            (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x88,
             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
             // UDP header.
             (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
-            (byte) 0x01, (byte) 0x3e, (byte) 0xd8, (byte) 0xa4,
+            (byte) 0x01, (byte) 0x42, (byte) 0x6a, (byte) 0x4a,
             // BOOTP.
             (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00,
             (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
@@ -655,13 +741,17 @@
                     'a', 'n', 'd', 'r', 'o', 'i', 'd', '-',
                     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e',
             // Requested parameter list.
-            (byte) 0x37, (byte) 0x06,
+            (byte) 0x37, (byte) 0x0a,
                 DHCP_SUBNET_MASK,
                 DHCP_ROUTER,
                 DHCP_DNS_SERVER,
                 DHCP_DOMAIN_NAME,
                 DHCP_MTU,
+                DHCP_BROADCAST_ADDRESS,
                 DHCP_LEASE_TIME,
+                DHCP_RENEWAL_TIME,
+                DHCP_REBINDING_TIME,
+                DHCP_VENDOR_INFO,
             // End options.
             (byte) 0xff,
             // Our packets are always of even length. TODO: find out why and possibly fix it.
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 5874429..8e11511 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -59,14 +59,17 @@
 import android.os.MessageQueue;
 import android.os.Messenger;
 import android.os.MessageQueue.IdleHandler;
+import android.os.SystemClock;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.LogPrinter;
 
+import com.android.internal.util.WakeupMessage;
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.net.NetworkPinner;
 
 import java.net.InetAddress;
 import java.util.concurrent.CountDownLatch;
@@ -87,10 +90,30 @@
 
     private BroadcastInterceptingContext mServiceContext;
     private WrappedConnectivityService mService;
-    private ConnectivityManager mCm;
+    private WrappedConnectivityManager mCm;
     private MockNetworkAgent mWiFiNetworkAgent;
     private MockNetworkAgent mCellNetworkAgent;
 
+    // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
+    // do not go through ConnectivityService but talk to netd directly, so they don't automatically
+    // reflect the state of our test ConnectivityService.
+    private class WrappedConnectivityManager extends ConnectivityManager {
+        private Network mFakeBoundNetwork;
+
+        public synchronized boolean bindProcessToNetwork(Network network) {
+            mFakeBoundNetwork = network;
+            return true;
+        }
+
+        public synchronized Network getBoundNetworkForProcess() {
+            return mFakeBoundNetwork;
+        }
+
+        public WrappedConnectivityManager(Context context, ConnectivityService service) {
+            super(context, service);
+        }
+    }
+
     private class MockContext extends BroadcastInterceptingContext {
         MockContext(Context base) {
             super(base);
@@ -138,9 +161,11 @@
                 assertNull("BUG: only one idle handler allowed", mIdleHandler);
                 mIdleHandler = new IdleHandler() {
                     public boolean queueIdle() {
-                        cv.open();
-                        mIdleHandler = null;
-                        return false;  // Remove the handler.
+                        synchronized (queue) {
+                            cv.open();
+                            mIdleHandler = null;
+                            return false;  // Remove the handler.
+                        }
                     }
                 };
                 queue.addIdleHandler(mIdleHandler);
@@ -484,6 +509,35 @@
         }
     }
 
+    private class FakeWakeupMessage extends WakeupMessage {
+        private static final int UNREASONABLY_LONG_WAIT = 1000;
+
+        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
+            super(context, handler, cmdName, cmd);
+        }
+
+        @Override
+        public void schedule(long when) {
+            long delayMs = when - SystemClock.elapsedRealtime();
+            if (delayMs < 0) delayMs = 0;
+            if (delayMs > UNREASONABLY_LONG_WAIT) {
+                fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
+                        "ms into the future: " + delayMs);
+            }
+            mHandler.sendEmptyMessageDelayed(mCmd, delayMs);
+        }
+
+        @Override
+        public void cancel() {
+            mHandler.removeMessages(mCmd);
+        }
+
+        @Override
+        public void onAlarm() {
+            throw new AssertionError("Should never happen. Update this fake.");
+        }
+    }
+
     // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
     private class WrappedNetworkMonitor extends NetworkMonitor {
         // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
@@ -498,6 +552,12 @@
         protected int isCaptivePortal() {
             return gen204ProbeResult;
         }
+
+        @Override
+        protected WakeupMessage makeWakeupMessage(
+                Context context, Handler handler, String cmdName, int cmd) {
+            return new FakeWakeupMessage(context, handler, cmdName, cmd);
+        }
     }
 
     private class WrappedConnectivityService extends ConnectivityService {
@@ -575,10 +635,10 @@
         int delays = 0;
         while (!criteria.get()) {
             try {
-                Thread.sleep(100);
+                Thread.sleep(50);
             } catch (InterruptedException e) {
             }
-            if (++delays == 5) fail();
+            if (++delays == 10) fail();
         }
     }
 
@@ -594,6 +654,8 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        NetworkMonitor.SetDefaultLingerTime(120);
+
         // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
         // http://b/25897652 .
         if (Looper.myLooper() == null) {
@@ -607,7 +669,8 @@
                 mock(INetworkPolicyManager.class));
 
         mService.systemReady();
-        mCm = new ConnectivityManager(getContext(), mService);
+        mCm = new WrappedConnectivityManager(getContext(), mService);
+        mCm.bindProcessToNetwork(null);
     }
 
     private int transportToLegacyType(int transport) {
@@ -674,8 +737,6 @@
 
     @LargeTest
     public void testLingering() throws Exception {
-        // Decrease linger timeout to the minimum allowed by AlarmManagerService.
-        NetworkMonitor.SetDefaultLingerTime(5000);
         verifyNoNetwork();
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -702,10 +763,8 @@
         assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
                 mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
         // Test cellular linger timeout.
-        try {
-            Thread.sleep(6000);
-        } catch (InterruptedException e) {
-        }
+        waitFor(new Criteria() {
+                public boolean get() { return mCm.getAllNetworks().length == 1; } });
         verifyActiveNetwork(TRANSPORT_WIFI);
         assertEquals(1, mCm.getAllNetworks().length);
         assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
@@ -949,29 +1008,41 @@
     private class TestNetworkCallback extends NetworkCallback {
         private final ConditionVariable mConditionVariable = new ConditionVariable();
         private CallbackState mLastCallback = CallbackState.NONE;
+        private Network mLastNetwork;
 
         public void onAvailable(Network network) {
             assertEquals(CallbackState.NONE, mLastCallback);
             mLastCallback = CallbackState.AVAILABLE;
+            mLastNetwork = network;
             mConditionVariable.open();
         }
 
         public void onLosing(Network network, int maxMsToLive) {
             assertEquals(CallbackState.NONE, mLastCallback);
             mLastCallback = CallbackState.LOSING;
+            mLastNetwork = network;
             mConditionVariable.open();
         }
 
         public void onLost(Network network) {
             assertEquals(CallbackState.NONE, mLastCallback);
             mLastCallback = CallbackState.LOST;
+            mLastNetwork = network;
             mConditionVariable.open();
         }
 
         void expectCallback(CallbackState state) {
+            expectCallback(state, null);
+        }
+
+        void expectCallback(CallbackState state, MockNetworkAgent mockAgent) {
             waitFor(mConditionVariable);
             assertEquals(state, mLastCallback);
+            if (mockAgent != null) {
+                assertEquals(mockAgent.getNetwork(), mLastNetwork);
+            }
             mLastCallback = CallbackState.NONE;
+            mLastNetwork = null;
             mConditionVariable.close();
         }
 
@@ -1330,6 +1401,55 @@
                 execptionCalled);
     }
 
+    @LargeTest
+    public void testRegisterDefaultNetworkCallback() throws Exception {
+        final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
+        // whenever Wi-Fi is up. Without this, the mobile network agent is
+        // reaped before any other activity can take place.
+        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        mCm.requestNetwork(cellRequest, cellNetworkCallback);
+        cellNetworkCallback.assertNoCallback();
+
+        // Bring up cell and expect CALLBACK_AVAILABLE.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+
+        // Bring up wifi and expect CALLBACK_AVAILABLE.
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        cellNetworkCallback.assertNoCallback();
+        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+
+        // Bring down cell. Expect no default network callback, since it wasn't the default.
+        mCellNetworkAgent.disconnect();
+        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Bring up cell. Expect no default network callback, since it won't be the default.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Bring down wifi. Expect the default network callback to notified of LOST wifi
+        // followed by AVAILABLE cell.
+        mWiFiNetworkAgent.disconnect();
+        cellNetworkCallback.assertNoCallback();
+        defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        mCellNetworkAgent.disconnect();
+        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+    }
+
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
@@ -1543,4 +1663,103 @@
         String url = mCm.getCaptivePortalServerUrl();
         assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
     }
+
+    private static class TestNetworkPinner extends NetworkPinner {
+        public static boolean awaitPin(int timeoutMs) {
+            synchronized(sLock) {
+                if (sNetwork == null) {
+                    try {
+                        sLock.wait(timeoutMs);
+                    } catch (InterruptedException e) {}
+                }
+                return sNetwork != null;
+            }
+        }
+
+        public static boolean awaitUnpin(int timeoutMs) {
+            synchronized(sLock) {
+                if (sNetwork != null) {
+                    try {
+                        sLock.wait(timeoutMs);
+                    } catch (InterruptedException e) {}
+                }
+                return sNetwork == null;
+            }
+        }
+    }
+
+    private void assertPinnedToWifiWithCellDefault() {
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+    }
+
+    private void assertPinnedToWifiWithWifiDefault() {
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+    }
+
+    private void assertNotPinnedToWifi() {
+        assertNull(mCm.getBoundNetworkForProcess());
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+    }
+
+    @SmallTest
+    public void testNetworkPinner() {
+        NetworkRequest wifiRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI)
+                .build();
+        assertNull(mCm.getBoundNetworkForProcess());
+
+        TestNetworkPinner.pin(mServiceContext, wifiRequest);
+        assertNull(mCm.getBoundNetworkForProcess());
+
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+
+        // When wi-fi connects, expect to be pinned.
+        assertTrue(TestNetworkPinner.awaitPin(100));
+        assertPinnedToWifiWithCellDefault();
+
+        // Disconnect and expect the pin to drop.
+        mWiFiNetworkAgent.disconnect();
+        assertTrue(TestNetworkPinner.awaitUnpin(100));
+        assertNotPinnedToWifi();
+
+        // Reconnecting does not cause the pin to come back.
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        assertFalse(TestNetworkPinner.awaitPin(100));
+        assertNotPinnedToWifi();
+
+        // Pinning while connected causes the pin to take effect immediately.
+        TestNetworkPinner.pin(mServiceContext, wifiRequest);
+        assertTrue(TestNetworkPinner.awaitPin(100));
+        assertPinnedToWifiWithCellDefault();
+
+        // Explicitly unpin and expect to use the default network again.
+        TestNetworkPinner.unpin();
+        assertNotPinnedToWifi();
+
+        // Disconnect cell and wifi.
+        ConditionVariable cv = waitForConnectivityBroadcasts(3);  // cell down, wifi up, wifi down.
+        mCellNetworkAgent.disconnect();
+        mWiFiNetworkAgent.disconnect();
+        waitFor(cv);
+
+        // Pinning takes effect even if the pinned network is the default when the pin is set...
+        TestNetworkPinner.pin(mServiceContext, wifiRequest);
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        assertTrue(TestNetworkPinner.awaitPin(100));
+        assertPinnedToWifiWithWifiDefault();
+
+        // ... and is maintained even when that network is no longer the default.
+        cv = waitForConnectivityBroadcasts(1);
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent.connect(true);
+        waitFor(cv);
+        assertPinnedToWifiWithCellDefault();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
index 055ce76..7f28d44 100644
--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -54,7 +54,7 @@
     public void testAddText() throws Exception {
         File dir = getEmptyDir("testAddText");
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
         Thread.sleep(5);
@@ -90,7 +90,7 @@
     public void testAddData() throws Exception {
         File dir = getEmptyDir("testAddData");
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
         dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
@@ -135,7 +135,7 @@
         gz3.close();
 
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
         dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
@@ -201,7 +201,7 @@
         new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
 
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         // Until a write, the timestamps are taken at face value
         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
@@ -252,7 +252,7 @@
     public void testIsTagEnabled() throws Exception {
         File dir = getEmptyDir("testIsTagEnabled");
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
         dropbox.addText("DropBoxTest", "TEST-ENABLED");
@@ -285,7 +285,7 @@
     public void testGetNextEntry() throws Exception {
         File dir = getEmptyDir("testGetNextEntry");
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
         dropbox.addText("DropBoxTest.A", "A0");
@@ -347,7 +347,7 @@
         final int overhead = 64;
         long before = System.currentTimeMillis();
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
@@ -441,7 +441,7 @@
         // Write one normal entry and another so big that it is instantly tombstoned
         long before = System.currentTimeMillis();
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         dropbox.addText("DropBoxTest", "TEST");
         addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
@@ -472,7 +472,7 @@
         File dir = getEmptyDir("testFileCountLimits");
 
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
         dropbox.addText("DropBoxTest", "TEST0");
         dropbox.addText("DropBoxTest", "TEST1");
         dropbox.addText("DropBoxTest", "TEST2");
@@ -525,7 +525,7 @@
         File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
         new FileOutputStream(dir).close();  // Create an empty file
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         dropbox.addText("DropBoxTest", "should be ignored");
         dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 72a458b..622e46e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -313,7 +313,7 @@
     public void testScreenChangesRules() throws Exception {
         Future<Void> future;
 
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -322,7 +322,7 @@
         verifyAndReset();
 
         // push strict policy for foreground uid, verify ALLOW rule
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -332,7 +332,7 @@
 
         // now turn screen off and verify REJECT rule
         expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
-        expectSetUidNetworkRules(UID_A, true);
+        expectSetUidMeteredNetworkBlacklist(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
@@ -342,7 +342,7 @@
 
         // and turn screen back on, verify ALLOW rule restored
         expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -354,7 +354,7 @@
     public void testPolicyNone() throws Exception {
         Future<Void> future;
 
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -363,7 +363,7 @@
         verifyAndReset();
 
         // POLICY_NONE should RULE_ALLOW in foreground
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -372,7 +372,7 @@
         verifyAndReset();
 
         // POLICY_NONE should RULE_ALLOW in background
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -385,7 +385,7 @@
         Future<Void> future;
 
         // POLICY_REJECT should RULE_ALLOW in background
-        expectSetUidNetworkRules(UID_A, true);
+        expectSetUidMeteredNetworkBlacklist(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
@@ -394,7 +394,7 @@
         verifyAndReset();
 
         // POLICY_REJECT should RULE_ALLOW in foreground
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -403,7 +403,7 @@
         verifyAndReset();
 
         // POLICY_REJECT should RULE_REJECT in background
-        expectSetUidNetworkRules(UID_A, true);
+        expectSetUidMeteredNetworkBlacklist(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
@@ -416,7 +416,7 @@
         Future<Void> future;
 
         // POLICY_NONE should have RULE_ALLOW in background
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -426,7 +426,7 @@
         verifyAndReset();
 
         // adding POLICY_REJECT should cause RULE_REJECT
-        expectSetUidNetworkRules(UID_A, true);
+        expectSetUidMeteredNetworkBlacklist(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
@@ -435,7 +435,7 @@
         verifyAndReset();
 
         // removing POLICY_REJECT should return us to RULE_ALLOW
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -632,7 +632,7 @@
         Future<Void> future;
 
         // POLICY_REJECT should RULE_REJECT in background
-        expectSetUidNetworkRules(UID_A, true);
+        expectSetUidMeteredNetworkBlacklist(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
@@ -641,7 +641,7 @@
         verifyAndReset();
 
         // uninstall should clear RULE_REJECT
-        expectSetUidNetworkRules(UID_A, false);
+        expectSetUidMeteredNetworkBlacklist(UID_A, false);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
@@ -890,9 +890,9 @@
         expectLastCall().atLeastOnce();
     }
 
-    private void expectSetUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
+    private void expectSetUidMeteredNetworkBlacklist(int uid, boolean rejectOnQuotaInterfaces)
             throws Exception {
-        mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+        mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces);
         expectLastCall().atLeastOnce();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
new file mode 100644
index 0000000..e440a0d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.pm.UserInfo;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+
+import com.android.server.am.TaskPersister;
+
+import java.io.File;
+import java.util.Random;
+
+public class TaskPersisterTest extends AndroidTestCase {
+    private static final String TEST_USER_NAME = "AM-Test-User";
+
+    private TaskPersister mTaskPersister;
+    private int testUserId;
+    private UserManager mUserManager;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mUserManager = UserManager.get(getContext());
+        mTaskPersister = new TaskPersister(getContext().getFilesDir());
+        testUserId = createUser(TEST_USER_NAME, 0);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        mTaskPersister.unloadUserDataFromMemory(testUserId);
+        removeUser(testUserId);
+    }
+
+    private int getRandomTaskIdForUser(int userId) {
+        int taskId = (int) (Math.random() * UserHandle.PER_USER_RANGE);
+        taskId += UserHandle.PER_USER_RANGE * userId;
+        return taskId;
+    }
+
+    public void testTaskIdsPersistence() {
+        SparseBooleanArray taskIdsOnFile = mTaskPersister.loadPersistedTaskIdsForUser(testUserId);
+        for (int i = 0; i < 100; i++) {
+            taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
+        }
+        mTaskPersister.maybeWritePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
+        SparseBooleanArray newTaskIdsOnFile = mTaskPersister
+                .loadPersistedTaskIdsForUser(testUserId);
+        assertTrue("TaskIds written differ from TaskIds read back from file",
+                taskIdsOnFile.equals(newTaskIdsOnFile));
+    }
+
+    private int createUser(String name, int flags) {
+        UserInfo user = mUserManager.createUser(name, flags);
+        if (user == null) {
+            fail("Error while creating the test user: " + TEST_USER_NAME);
+        }
+        return user.id;
+    }
+
+    private void removeUser(int userId) {
+        if (!mUserManager.removeUser(userId)) {
+            fail("Error while removing the test user: " + TEST_USER_NAME);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index db2a9ad..744443f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -15,25 +15,30 @@
  */
 package com.android.server.devicepolicy;
 
-import com.android.internal.widget.LockPatternUtils;
-
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.app.backup.IBackupManager;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.database.ContentObserver;
 import android.media.IAudioService;
+import android.net.Uri;
 import android.os.Looper;
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.os.storage.StorageManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
 import android.view.IWindowManager;
 
-import java.io.File;
+import com.android.internal.widget.LockPatternUtils;
 
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.when;
+import java.io.File;
+import java.util.Map;
 
 /**
  * Overrides {@link #DevicePolicyManagerService} for dependency injection.
@@ -75,6 +80,7 @@
     }
 
     public final DpmMockContext context;
+    private final MockInjector mMockInjector;
 
     public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
         this(new MockInjector(context, dataDir));
@@ -82,15 +88,36 @@
 
     private DevicePolicyManagerServiceTestable(MockInjector injector) {
         super(injector);
+        mMockInjector = injector;
         this.context = injector.context;
     }
 
+
+    public void notifyChangeToContentObserver(Uri uri, int userHandle) {
+        ContentObserver co = mMockInjector.mContentObservers
+                .get(new Pair<Uri, Integer>(uri, userHandle));
+        if (co != null) {
+            co.onChange(false, uri, userHandle); // notify synchronously
+        }
+
+        // Notify USER_ALL observer too.
+        co = mMockInjector.mContentObservers
+                .get(new Pair<Uri, Integer>(uri, UserHandle.USER_ALL));
+        if (co != null) {
+            co.onChange(false, uri, userHandle); // notify synchronously
+        }
+    }
+
+
     private static class MockInjector extends Injector {
 
         public final DpmMockContext context;
 
         public final File dataDir;
 
+        // Key is a pair of uri and userId
+        private final Map<Pair<Uri, Integer>, ContentObserver> mContentObservers = new ArrayMap<>();
+
         private MockInjector(DpmMockContext context, File dataDir) {
             super(context);
             this.context = context;
@@ -163,6 +190,26 @@
         }
 
         @Override
+        boolean storageManagerIsFileBasedEncryptionEnabled() {
+            return context.storageManager.isFileBasedEncryptionEnabled();
+        }
+
+        @Override
+        boolean storageManagerIsNonDefaultBlockEncrypted() {
+            return context.storageManager.isNonDefaultBlockEncrypted();
+        }
+
+        @Override
+        boolean storageManagerIsEncrypted() {
+            return context.storageManager.isEncrypted();
+        }
+
+        @Override
+        boolean storageManagerIsEncryptable() {
+            return context.storageManager.isEncryptable();
+        }
+
+        @Override
         String getDevicePolicyFilePathForSystemUser() {
             return context.systemUserDataDir.getAbsolutePath() + "/";
         }
@@ -243,6 +290,12 @@
         }
 
         @Override
+        void registerContentObserver(Uri uri, boolean notifyForDescendents,
+                ContentObserver observer, int userHandle) {
+            mContentObservers.put(new Pair<Uri, Integer>(uri, userHandle), observer);
+        }
+
+        @Override
         int settingsSecureGetIntForUser(String name, int def, int userHandle) {
             return context.settings.settingsSecureGetIntForUser(name, def, userHandle);
         }
@@ -301,5 +354,10 @@
         boolean securityLogIsLoggingEnabled() {
             return context.settings.securityLogIsLoggingEnabled();
         }
+
+        @Override
+        TelephonyManager getTelephonyManager() {
+            return context.telephonyManager;
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 212b37c..3a2e946 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -33,6 +33,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.TelephonyManager;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
@@ -542,10 +543,31 @@
     }
 
     /**
-     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
-     * successfully.
+     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
      */
     public void testSetDeviceOwner() throws Exception {
+        setDeviceOwner();
+
+        // Try to set a profile owner on the same user, which should fail.
+        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
+        try {
+            dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
+            fail("IllegalStateException not thrown");
+        } catch (IllegalStateException expected) {
+            assertTrue("Message was: " + expected.getMessage(),
+                    expected.getMessage().contains("already has a device owner"));
+        }
+
+        // DO admin can't be deactivated.
+        dpm.removeActiveAdmin(admin1);
+        assertTrue(dpm.isAdminActive(admin1));
+
+        // TODO Test getDeviceOwnerName() too. To do so, we need to change
+        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+    }
+
+    private void setDeviceOwner() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -593,24 +615,6 @@
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
         assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
-
-        // Try to set a profile owner on the same user, which should fail.
-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
-        dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
-        try {
-            dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
-            fail("IllegalStateException not thrown");
-        } catch (IllegalStateException expected) {
-            assertTrue("Message was: " + expected.getMessage(),
-                    expected.getMessage().contains("already has a device owner"));
-        }
-
-        // DO admin can't be deactivated.
-        dpm.removeActiveAdmin(admin1);
-        assertTrue(dpm.isAdminActive(admin1));
-
-        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
-        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
     }
 
     private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
@@ -969,6 +973,8 @@
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
 
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+
         // Make sure the admin packge is installed to each user.
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_SYSTEM_USER_UID);
@@ -1008,6 +1014,7 @@
      * finds the right component from a package name upon migration.
      */
     public void testDeviceOwnerMigration() throws Exception {
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
         checkDeviceOwnerWithMultipleDeviceAdmins();
 
         // Overwrite the device owner setting and clears the clas name.
@@ -1113,9 +1120,9 @@
             dpm.setApplicationRestrictionsManagingPackage(admin1,
                     nonExistAppRestrictionsManagerPackage);
             fail("Non-existent app set as app restriction manager.");
-        } catch (IllegalArgumentException expected) {
+        } catch (PackageManager.NameNotFoundException expected) {
             MoreAsserts.assertContainsRegex(
-                    "is not installed on the current user", expected.getMessage());
+                    nonExistAppRestrictionsManagerPackage, expected.getMessage());
         }
 
         // Let appRestrictionsManagerPackage manage app restrictions
@@ -1441,10 +1448,10 @@
 
         // Test 1. Caller doesn't have DO or DA.
         try {
-            dpm.getWifiMacAddress();
+            dpm.getWifiMacAddress(admin1);
             fail();
         } catch (SecurityException e) {
-            MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+            MoreAsserts.assertContainsRegex("No active admin", e.getMessage());
         }
 
         // DO needs to be an DA.
@@ -1453,19 +1460,19 @@
 
         // Test 2. Caller has DA, but not DO.
         try {
-            dpm.getWifiMacAddress();
+            dpm.getWifiMacAddress(admin1);
             fail();
         } catch (SecurityException e) {
-            MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+            MoreAsserts.assertContainsRegex("does not own the device", e.getMessage());
         }
 
         // Test 3. Caller has PO, but not DO.
         assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
         try {
-            dpm.getWifiMacAddress();
+            dpm.getWifiMacAddress(admin1);
             fail();
         } catch (SecurityException e) {
-            MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+            MoreAsserts.assertContainsRegex("does not own the device", e.getMessage());
         }
 
         // Remove PO.
@@ -1475,20 +1482,20 @@
         assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
 
         // 4-1.  But no WifiInfo.
-        assertNull(dpm.getWifiMacAddress());
+        assertNull(dpm.getWifiMacAddress(admin1));
 
         // 4-2.  Returns WifiInfo, but with the default MAC.
         when(mContext.wifiManager.getConnectionInfo()).thenReturn(new WifiInfo());
-        assertNull(dpm.getWifiMacAddress());
+        assertNull(dpm.getWifiMacAddress(admin1));
 
         // 4-3. With a real MAC address.
         final WifiInfo wi = new WifiInfo();
         wi.setMacAddress("11:22:33:44:55:66");
         when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
-        assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
+        assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
     }
 
-    public void testRebootCanOnlyBeCalledByDeviceOwner() throws Exception {
+    public void testReboot() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
@@ -1521,6 +1528,29 @@
         dpm.clearProfileOwner(admin1);
         assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
 
+        // admin1 is DO.
+        // Set current call state of device to ringing.
+        when(mContext.telephonyManager.getCallState())
+                .thenReturn(TelephonyManager.CALL_STATE_RINGING);
+        try {
+            dpm.reboot(admin1);
+            fail("DPM.reboot() called when receiveing a call, should thrown IllegalStateException");
+        } catch (IllegalStateException expected) {
+            MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage());
+        }
+
+        // Set current call state of device to dialing/active.
+        when(mContext.telephonyManager.getCallState())
+                .thenReturn(TelephonyManager.CALL_STATE_OFFHOOK);
+        try {
+            dpm.reboot(admin1);
+            fail("DPM.reboot() called when dialing, should thrown IllegalStateException");
+        } catch (IllegalStateException expected) {
+            MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage());
+        }
+
+        // Set current call state of device to idle.
+        when(mContext.telephonyManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_IDLE);
         dpm.reboot(admin1);
     }
 
@@ -1907,5 +1937,211 @@
         // TODO Verify calls to settingsGlobalPutInt.  Tried but somehow mockito threw
         // UnfinishedVerificationException.
     }
-}
 
+    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+        when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+                .thenReturn(false);
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(false);
+        initializeDpms();
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+    }
+
+    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(false);
+        initializeDpms();
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+
+        // Test again when split user is on
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+    }
+
+    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false /* because of non-split user */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false /* because of non-split user */);
+    }
+
+    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                false/* because of completed device setup */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false/* because of non-split user */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because of non-split user */);
+    }
+
+    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(false);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                false /* because canAddMoreManagedProfiles returns false */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because calling uid is system user */);
+
+    }
+
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(false);
+        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                false /* because canAddMoreManagedProfiles returns false */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because calling uid is system user */);
+    }
+
+    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+                true)).thenReturn(true);
+        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
+
+    }
+
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+                true)).thenReturn(true);
+        setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because user setup completed */);
+    }
+
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+            throws Exception {
+        setDeviceOwner();
+
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(false);
+        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                false /* can't provision managed profile on system user */);
+    }
+
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+            throws Exception {
+        setDeviceOwner();
+
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+                true)).thenReturn(true);
+        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+    }
+
+    private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
+        when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
+                userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
+        dpms.notifyChangeToContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), userhandle);
+    }
+
+    private void assertProvisioningAllowed(String action, boolean expected) {
+        assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
+                dpm.isProvisioningAllowed(action));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index ef8e420..60d7382 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -39,6 +39,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.os.storage.StorageManager;
+import android.telephony.TelephonyManager;
 import android.test.mock.MockContentResolver;
 import android.test.mock.MockContext;
 import android.view.IWindowManager;
@@ -51,6 +53,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -170,36 +173,36 @@
     }
 
     public static class SettingsForMock {
-        int settingsSecureGetIntForUser(String name, int def, int userHandle) {
+        public int settingsSecureGetIntForUser(String name, int def, int userHandle) {
             return 0;
         }
 
-        void settingsSecurePutIntForUser(String name, int value, int userHandle) {
+        public void settingsSecurePutIntForUser(String name, int value, int userHandle) {
         }
 
-        void settingsSecurePutStringForUser(String name, String value, int userHandle) {
+        public void settingsSecurePutStringForUser(String name, String value, int userHandle) {
         }
 
-        void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
+        public void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
         }
 
-        void settingsSecurePutInt(String name, int value) {
+        public void settingsSecurePutInt(String name, int value) {
         }
 
-        void settingsGlobalPutInt(String name, int value) {
+        public void settingsGlobalPutInt(String name, int value) {
         }
 
-        void settingsSecurePutString(String name, String value) {
+        public void settingsSecurePutString(String name, String value) {
         }
 
-        void settingsGlobalPutString(String name, String value) {
+        public void settingsGlobalPutString(String name, String value) {
         }
 
-        int settingsGlobalGetInt(String name, int def) {
+        public int settingsGlobalGetInt(String name, int value) {
             return 0;
         }
 
-        void securityLogSetLoggingEnabledProperty(boolean enabled) {
+        public void securityLogSetLoggingEnabledProperty(boolean enabled) {
         }
 
         public boolean securityLogGetLoggingEnabledProperty() {
@@ -211,6 +214,24 @@
         }
     }
 
+    public static class StorageManagerForMock {
+        public boolean isFileBasedEncryptionEnabled() {
+            return false;
+        }
+
+        public boolean isNonDefaultBlockEncrypted() {
+            return false;
+        }
+
+        public boolean isEncrypted() {
+            return false;
+        }
+
+        public boolean isEncryptable() {
+            return false;
+        }
+    }
+
     public final Context realTestContext;
 
     /**
@@ -239,9 +260,11 @@
     public final IBackupManager ibackupManager;
     public final IAudioService iaudioService;
     public final LockPatternUtils lockPatternUtils;
+    public final StorageManagerForMock storageManager;
     public final WifiManager wifiManager;
     public final SettingsForMock settings;
     public final MockContentResolver contentResolver;
+    public final TelephonyManager telephonyManager;
 
     /** Note this is a partial mock, not a real mock. */
     public final PackageManager packageManager;
@@ -272,8 +295,10 @@
         ibackupManager = mock(IBackupManager.class);
         iaudioService = mock(IAudioService.class);
         lockPatternUtils = mock(LockPatternUtils.class);
+        storageManager = mock(StorageManagerForMock.class);
         wifiManager = mock(WifiManager.class);
         settings = mock(SettingsForMock.class);
+        telephonyManager = mock(TelephonyManager.class);
 
         // Package manager is huge, so we use a partial mock instead.
         packageManager = spy(context.getPackageManager());
@@ -297,6 +322,8 @@
 
         mUserInfos.add(uh);
         when(userManager.getUsers()).thenReturn(mUserInfos);
+        when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
+        when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
         when(userManager.getUserInfo(anyInt())).thenAnswer(
                 new Answer<UserInfo>() {
                     @Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index ca43644..c80ca6c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -154,8 +154,10 @@
         aci.packageName = admin.getPackageName();
         aci.name = admin.getClassName();
 
-        doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
-                MockUtils.checkIntentComponent(admin),
+        // Note we don't set up queryBroadcastReceivers.  We don't use it in DPMS.
+
+        doReturn(aci).when(mMockContext.ipackageManager).getReceiverInfo(
+                eq(admin),
                 anyInt(),
                 eq(UserHandle.getUserId(packageUid)));
 
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index c786036..edbff83 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -12,6 +12,7 @@
 import android.util.Log;
 import android.util.ArraySet;
 
+import com.android.server.job.JobStore.JobSet;
 import com.android.server.job.controllers.JobStatus;
 
 import java.util.Iterator;
@@ -58,15 +59,15 @@
                 .setMinimumLatency(runFromMillis)
                 .setPersisted(true)
                 .build();
-        final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
+        final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(ts);
         Thread.sleep(IO_WAIT);
         // Manually load tasks from xml file.
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
 
         assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size());
-        final JobStatus loadedTaskStatus = jobStatusSet.iterator().next();
+        final JobStatus loadedTaskStatus = jobStatusSet.getAllJobs().get(0);
         assertTasksEqual(task, loadedTaskStatus.getJob());
         assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(ts));
         assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid());
@@ -91,16 +92,16 @@
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
                 .setPersisted(true)
                 .build();
-        final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1);
-        final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1);
+        final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1, null);
+        final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(taskStatus1);
         mTaskStoreUnderTest.add(taskStatus2);
         Thread.sleep(IO_WAIT);
 
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
         assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size());
-        Iterator<JobStatus> it = jobStatusSet.iterator();
+        Iterator<JobStatus> it = jobStatusSet.getAllJobs().iterator();
         JobStatus loaded1 = it.next();
         JobStatus loaded2 = it.next();
 
@@ -140,15 +141,15 @@
         extras.putInt("into", 3);
         b.setExtras(extras);
         final JobInfo task = b.build();
-        JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
+        JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
 
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
         assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
-        JobStatus loaded = jobStatusSet.iterator().next();
+        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
         assertTasksEqual(task, loaded.getJob());
     }
     public void testWritingTaskWithSourcePackage() throws Exception {
@@ -158,15 +159,15 @@
                 .setRequiresCharging(true)
                 .setPersisted(true);
         JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID,
-                "com.google.android.gms", 0);
+                "com.google.android.gms", 0, null);
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
 
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
         assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
-        JobStatus loaded = jobStatusSet.iterator().next();
+        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
         assertEquals("Source package not equal.", loaded.getSourcePackageName(),
                 taskStatus.getSourcePackageName());
         assertEquals("Source user not equal.", loaded.getSourceUserId(),
@@ -179,15 +180,15 @@
                 .setPeriodic(5*60*60*1000, 1*60*60*1000)
                 .setRequiresCharging(true)
                 .setPersisted(true);
-        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
 
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
         assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
-        JobStatus loaded = jobStatusSet.iterator().next();
+        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
         assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(),
                 taskStatus.getJob().getIntervalMillis());
         assertEquals("Flex not equal.", loaded.getJob().getFlexMillis(),
@@ -205,16 +206,16 @@
         final long invalidEarlyRuntimeElapsedMillis =
                 invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
         final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
-                0 /* sourceUserId */,
+                0 /* sourceUserId */, "someTag",
                 invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
 
         mTaskStoreUnderTest.add(js);
         Thread.sleep(IO_WAIT);
 
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
         assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
-        JobStatus loaded = jobStatusSet.iterator().next();
+        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
 
         // Assert early runtime was clamped to be under now + period. We can do <= here b/c we'll
         // call SystemClock.elapsedRealtime after doing the disk i/o.
@@ -231,12 +232,12 @@
                 .setOverrideDeadline(5000)
                 .setPriority(42)
                 .setPersisted(true);
-        final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(js);
         Thread.sleep(IO_WAIT);
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
-        JobStatus loaded = jobStatusSet.iterator().next();
+        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
         assertEquals("Priority not correctly persisted.", 42, loaded.getPriority());
     }
 
@@ -247,18 +248,18 @@
         JobInfo.Builder b = new Builder(42, mComponent)
                 .setOverrideDeadline(10000)
                 .setPersisted(false);
-        JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(jsNonPersisted);
         b = new Builder(43, mComponent)
                 .setOverrideDeadline(10000)
                 .setPersisted(true);
-        JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(jsPersisted);
         Thread.sleep(IO_WAIT);
-        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        final JobSet jobStatusSet = new JobSet();
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
         assertEquals("Job count is incorrect.", 1, jobStatusSet.size());
-        JobStatus jobStatus = jobStatusSet.iterator().next();
+        JobStatus jobStatus = jobStatusSet.getAllJobs().iterator().next();
         assertEquals("Wrong job persisted.", 43, jobStatus.getJobId());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
index b9e9aa9..82c6b6d 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
@@ -25,7 +25,7 @@
 import static org.mockito.Mockito.when;
 
 import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.ROAMING_DEFAULT;
+import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
@@ -447,7 +447,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -455,7 +455,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -487,7 +487,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -495,7 +495,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -527,7 +527,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -535,7 +535,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -567,7 +567,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -575,7 +575,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -607,7 +607,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -615,7 +615,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
index 4f6c7b9..74c1984 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
@@ -23,8 +23,8 @@
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_DEFAULT;
-import static android.net.NetworkStats.ROAMING_ROAMING;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.ROAMING_YES;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
@@ -321,8 +321,8 @@
         // verify service recorded history
         assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
         assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_DEFAULT, 512L, 4L, 256L, 2L, 4);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_DEFAULT, 512L, 4L, 256L, 2L,
+        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
+        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
                 6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
         verifyAndReset();
@@ -357,8 +357,8 @@
         // after systemReady(), we should have historical stats loaded again
         assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
         assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_DEFAULT, 512L, 4L, 256L, 2L, 4);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_DEFAULT, 512L, 4L, 256L, 2L,
+        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
+        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
                 6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
         verifyAndReset();
@@ -711,11 +711,11 @@
         NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(3, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 50L, 5L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 50L, 5L,
                 50L, 5L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 10L, 1L, 10L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 10L, 1L, 10L,
                 1L, 1);
-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 2048L, 16L,
+        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2048L, 16L,
                 1024L, 8L, 0);
 
         // now verify that recent history only contains one uid
@@ -723,7 +723,7 @@
         stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
         assertEquals(1, stats.size());
-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
                 512L, 4L, 0);
 
         verifyAndReset();
@@ -787,13 +787,13 @@
         final NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(4, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 2L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
                 128L, 2L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 1L, 64L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
                 1L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 32L, 2L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 2L,
                 32L, 2L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_DEFAULT, 1L, 1L, 1L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_NO, 1L, 1L, 1L,
                 1L, 1);
 
         verifyAndReset();
@@ -818,13 +818,13 @@
         expectCurrentTime();
         expectDefaultSettings();
         expectNetworkStatsSummary(buildEmptyStats());
-        // Note that all traffic from NetworkManagementService is tagged as ROAMING_DEFAULT, because
+        // Note that all traffic from NetworkManagementService is tagged as ROAMING_NO, because
         // roaming isn't tracked at that layer. We layer it on top by inspecting the iface
         // properties.
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 2L,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
                         128L, 2L, 0L)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 1L, 64L,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
                         1L, 0L));
         expectNetworkStatsPoll();
 
@@ -838,9 +838,9 @@
         final NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(2, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 2L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 2L,
                 128L, 2L, 0);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING, 64L, 1L, 64L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L,
                 1L, 0);
 
         verifyAndReset();
@@ -1073,9 +1073,9 @@
         expectDefaultSettings();
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 2L,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
                         128L, 2L, 0L)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 1L, 64L,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
                         1L, 0L));
         expectNetworkStatsPoll();
 
@@ -1089,9 +1089,9 @@
         NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(2, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 2L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 2L,
                 128L, 2L, 0);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING, 64L, 1L, 64L,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L,
                 1L, 0);
 
         verifyAndReset();
@@ -1106,9 +1106,9 @@
         expectDefaultSettings();
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         128000000L, 2L, 128000000L, 2L, 0L)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO,
                         64000000L, 1L, 64000000L, 1L, 0L));
         expectNetworkStatsPoll();
 
@@ -1122,9 +1122,9 @@
         stats = mSession.getSummaryForAllUid(
                 sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(2, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES,
                 128000000L, 2L, 128000000L, 2L, 0);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING,
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES,
                 64000000L, 1L, 64000000L, 1L, 0);
 
         verifyAndReset();
@@ -1180,7 +1180,7 @@
 
         // verify summary API
         final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
-        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, rxBytes,
+        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, rxBytes,
                 rxPackets, txBytes, txPackets, operations);
     }
 
@@ -1312,11 +1312,11 @@
         }
 
         List<Integer> roamings = new ArrayList<>();
-        if (roaming == ROAMING_DEFAULT || roaming == ROAMING_ALL) {
-            roamings.add(ROAMING_DEFAULT);
+        if (roaming == ROAMING_NO || roaming == ROAMING_ALL) {
+            roamings.add(ROAMING_NO);
         }
-        if (roaming == ROAMING_ROAMING || roaming == ROAMING_ALL) {
-            roamings.add(ROAMING_ROAMING);
+        if (roaming == ROAMING_YES || roaming == ROAMING_ALL) {
+            roamings.add(ROAMING_YES);
         }
 
         for (int s : sets) {
diff --git a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
new file mode 100644
index 0000000..83a59fd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.StatusBarNotification;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class BuzzBeepBlinkTest extends AndroidTestCase {
+
+    @Mock AudioManager mAudioManager;
+    @Mock Vibrator mVibrator;
+    @Mock android.media.IRingtonePlayer mRingtonePlayer;
+    @Mock Handler mHandler;
+
+    private NotificationManagerService mService;
+    private String mPkg = "com.android.server.notification";
+    private int mId = 1001;
+    private int mOtherId = 1002;
+    private String mTag = null;
+    private int mUid = 1000;
+    private int mPid = 2000;
+    private int mScore = 10;
+    private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+
+    @Override
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
+        when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+
+        mService = new NotificationManagerService(getContext());
+        mService.setAudioManager(mAudioManager);
+        mService.setVibrator(mVibrator);
+        mService.setSystemReady(true);
+        mService.setHandler(mHandler);
+    }
+
+    //
+    // Convenience functions for creating notification records
+    //
+
+    private NotificationRecord getNoisyOtherNotification() {
+        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+                true /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getBeepyNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                true /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getBeepyOnceNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                true /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getQuietNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                false /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getQuietOtherNotification() {
+        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+                false /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getQuietOnceNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                false /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getInsistentBeepyNotification() {
+        return getNotificationRecord(mId, true /* insistent */, false /* once */,
+                true /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getBuzzyNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                false /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getBuzzyOnceNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                false /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getInsistentBuzzyNotification() {
+        return getNotificationRecord(mId, true /* insistent */, false /* once */,
+                false /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
+            boolean noisy, boolean buzzy) {
+        final Builder builder = new Builder(getContext())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setOnlyAlertOnce(once);
+
+        int defaults = 0;
+        if (noisy) {
+            defaults |= Notification.DEFAULT_SOUND;
+        }
+        if (buzzy) {
+            defaults |= Notification.DEFAULT_VIBRATE;
+        }
+        builder.setDefaults(defaults);
+
+        Notification n = builder.build();
+        if (insistent) {
+            n.flags |= Notification.FLAG_INSISTENT;
+        }
+        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
+                mScore, n, mUser, System.currentTimeMillis());
+        return new NotificationRecord(getContext(), sbn);
+    }
+
+    //
+    // Convenience functions for interacting with mocks
+    //
+
+    private void verifyNeverBeep() throws RemoteException {
+        verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+                anyBoolean(), (AudioAttributes) anyObject());
+    }
+
+    private void verifyBeep() throws RemoteException {
+        verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+                eq(true), (AudioAttributes) anyObject());
+    }
+
+    private void verifyBeepLooped() throws RemoteException {
+        verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+                eq(false), (AudioAttributes) anyObject());
+    }
+
+    private void verifyNeverStopAudio() throws RemoteException {
+        verify(mRingtonePlayer, never()).stopAsync();
+    }
+
+    private void verifyStopAudio() throws RemoteException {
+        verify(mRingtonePlayer, times(1)).stopAsync();
+    }
+
+    private void verifyNeverVibrate() {
+        verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+                anyInt(), (AudioAttributes) anyObject());
+    }
+
+    private void verifyVibrate() {
+        verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+                eq(-1), (AudioAttributes) anyObject());
+    }
+
+    private void verifyVibrateLooped() {
+        verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+                eq(0), (AudioAttributes) anyObject());
+    }
+
+    private void verifyStopVibrate() {
+        verify(mVibrator, times(1)).cancel();
+    }
+
+    private void verifyNeverStopVibrate() throws RemoteException {
+        verify(mVibrator, never()).cancel();
+    }
+
+    @SmallTest
+    public void testBeep() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyBeepLooped();
+        verifyNeverVibrate();
+    }
+
+    //
+    // Tests
+    //
+
+    @SmallTest
+    public void testBeepInsistently() throws Exception {
+        NotificationRecord r = getInsistentBeepyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyBeep();
+    }
+
+    @SmallTest
+    public void testNoInterruptionForMin() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyNeverVibrate();
+    }
+
+    @SmallTest
+    public void testNoInterruptionForIntercepted() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        r.setIntercepted(true);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyNeverVibrate();
+    }
+
+    @SmallTest
+    public void testBeepTwice() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should beep
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+        verifyBeepLooped();
+    }
+
+    @SmallTest
+    public void testHonorAlertOnlyOnceForBeep() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getBeepyOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should not beep
+        mService.buzzBeepBlinkLocked(s);
+        verifyNeverBeep();
+    }
+
+    @SmallTest
+    public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getBeepyOnceNotification();
+        s.isUpdate = true;
+
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(s);
+
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+        NotificationRecord other = getNoisyOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(other); // this takes the audio stream
+        Mockito.reset(mRingtonePlayer);
+
+        // should not stop noise, since we no longer own it
+        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietInterloperDoesNotCancelAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord other = getQuietOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // should not stop noise, since it does not own it
+        mService.buzzBeepBlinkLocked(other);
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietUpdateCancelsAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // quiet update should stop making noise
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietOnceUpdateCancelsAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // stop making noise - this is a weird corner case, but quiet should override once
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopAudio();
+    }
+
+    @SmallTest
+    public void testDemoteSoundToVibrate() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        // the phone is quiet
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyVibrate();
+    }
+
+    @SmallTest
+    public void testDemotInsistenteSoundToVibrate() throws Exception {
+        NotificationRecord r = getInsistentBeepyNotification();
+
+        // the phone is quiet
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyVibrateLooped();
+    }
+
+    @SmallTest
+    public void testVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyVibrate();
+    }
+
+    @SmallTest
+    public void testInsistenteVibrate() throws Exception {
+        NotificationRecord r = getInsistentBuzzyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+        verifyVibrateLooped();
+    }
+
+    @SmallTest
+    public void testVibratTwice() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // update should vibrate
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+        verifyVibrate();
+    }
+
+    @SmallTest
+    public void testHonorAlertOnlyOnceForBuzz() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getBuzzyOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // update should not beep
+        mService.buzzBeepBlinkLocked(s);
+        verifyNeverVibrate();
+    }
+
+    @SmallTest
+    public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getBuzzyOnceNotification();
+        s.isUpdate = true;
+
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(s);
+
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+        NotificationRecord other = getNoisyOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
+        Mockito.reset(mVibrator);
+
+        // should not stop vibrate, since we no longer own it
+        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord other = getQuietOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // should not stop noise, since it does not own it
+        mService.buzzBeepBlinkLocked(other);
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietUpdateCancelsVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+
+        // quiet update should stop making noise
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietOnceUpdateCancelsvibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getQuietOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // stop making noise - this is a weird corner case, but quiet should override once
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietNotification();
+
+        // the phone is quiet
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        // quiet update should stop making noise
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopVibrate();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index f1fe346..32501ad 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -15,12 +15,6 @@
  */
 package com.android.server.notification;
 
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_LOW;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
-
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
new file mode 100644
index 0000000..baa5d36
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -0,0 +1,5375 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ILauncherApps;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.content.pm.ShortcutServiceInternal;
+import android.content.pm.Signature;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.BaseBundle;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.InstrumentationTestCase;
+import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.frameworks.servicestests.R;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
+import com.android.server.pm.ShortcutService.ConfigConstants;
+import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
+import com.android.server.testutis.TestUtils;
+
+import libcore.io.IoUtils;
+
+import org.junit.Assert;
+import org.mockito.ArgumentCaptor;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+
+/**
+ * Tests for ShortcutService and ShortcutManager.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+
+ * TODO: Add checks with assertAllNotHaveIcon()
+ * TODO: Detailed test for hasShortcutPermissionInner().
+ * TODO: Add tests for the command line functions too.
+ */
+@SmallTest
+public class ShortcutManagerTest extends InstrumentationTestCase {
+    private static final String TAG = "ShortcutManagerTest";
+
+    /**
+     * Whether to enable dump or not.  Should be only true when debugging to avoid bugs where
+     * dump affecting the behavior.
+     */
+    private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH true
+
+    private static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+
+    // public for mockito
+    public class BaseContext extends MockContext {
+        @Override
+        public Object getSystemService(String name) {
+            switch (name) {
+                case Context.USER_SERVICE:
+                    return mMockUserManager;
+            }
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getSystemServiceName(Class<?> serviceClass) {
+            return getTestContext().getSystemServiceName(serviceClass);
+        }
+
+        @Override
+        public PackageManager getPackageManager() {
+            return mMockPackageManager;
+        }
+
+        @Override
+        public Resources getResources() {
+            return getTestContext().getResources();
+        }
+
+        @Override
+        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+                IntentFilter filter, String broadcastPermission, Handler scheduler) {
+            // ignore.
+            return null;
+        }
+    }
+
+    /** Context used in the client side */
+    public class ClientContext extends BaseContext {
+        @Override
+        public String getPackageName() {
+            return mInjectedClientPackage;
+        }
+    }
+
+    /** Context used in the service side */
+    public class ServiceContext extends BaseContext {
+        long injectClearCallingIdentity() {
+            final int prevCallingUid = mInjectedCallingUid;
+            mInjectedCallingUid = Process.SYSTEM_UID;
+            return prevCallingUid;
+        }
+
+        void injectRestoreCallingIdentity(long token) {
+            mInjectedCallingUid = (int) token;
+        }
+
+        @Override
+        public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
+                UserHandle userId) {
+        }
+    }
+
+    /** ShortcutService with injection override methods. */
+    private final class ShortcutServiceTestable extends ShortcutService {
+        final ServiceContext mContext;
+
+        public ShortcutServiceTestable(ServiceContext context, Looper looper) {
+            super(context, looper);
+            mContext = context;
+        }
+
+        @Override
+        String injectShortcutManagerConstants() {
+            return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + ","
+                    + ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + ","
+                    + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=" + MAX_DAILY_UPDATES + ","
+                    + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + ","
+                    + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "="
+                    + MAX_ICON_DIMENSION_LOWRAM + ","
+                    + ConfigConstants.KEY_ICON_FORMAT + "=PNG,"
+                    + ConfigConstants.KEY_ICON_QUALITY + "=100";
+        }
+
+        @Override
+        long injectClearCallingIdentity() {
+            return mContext.injectClearCallingIdentity();
+        }
+
+        @Override
+        void injectRestoreCallingIdentity(long token) {
+            mContext.injectRestoreCallingIdentity(token);
+        }
+
+        @Override
+        int injectDipToPixel(int dip) {
+            return dip;
+        }
+
+        @Override
+        long injectCurrentTimeMillis() {
+            return mInjectedCurrentTimeLillis;
+        }
+
+        @Override
+        int injectBinderCallingUid() {
+            return mInjectedCallingUid;
+        }
+
+        @Override
+        int injectGetPackageUid(String packageName, int userId) {
+            return getInjectedPackageInfo(packageName, userId, false).applicationInfo.uid;
+        }
+
+        @Override
+        File injectSystemDataPath() {
+            return new File(mInjectedFilePathRoot, "system");
+        }
+
+        @Override
+        File injectUserDataPath(@UserIdInt int userId) {
+            return new File(mInjectedFilePathRoot, "user-" + userId);
+        }
+
+        @Override
+        void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
+            // Can't check
+        }
+
+        @Override
+        boolean injectIsLowRamDevice() {
+            return mInjectedIsLowRamDevice;
+        }
+
+        @Override
+        PackageManagerInternal injectPackageManagerInternal() {
+            return mMockPackageManagerInternal;
+        }
+
+        @Override
+        boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
+            return mDefaultLauncherChecker.test(callingPackage, userId);
+        }
+
+        @Override
+        PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
+                boolean getSignatures) {
+            return getInjectedPackageInfo(packageName, userId, getSignatures);
+        }
+
+        @Override
+        ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
+            PackageInfo pi = injectPackageInfo(packageName, userId, /* getSignatures= */ false);
+            return pi != null ? pi.applicationInfo : null;
+        }
+
+        @Override
+        void postToHandler(Runnable r) {
+            final long token = mContext.injectClearCallingIdentity();
+            r.run();
+            mContext.injectRestoreCallingIdentity(token);
+        }
+
+        @Override
+        void wtf(String message, Exception e) {
+            // During tests, WTF is fatal.
+            fail(message + "  exception: " + e);
+        }
+    }
+
+    /** ShortcutManager with injection override methods. */
+    private class ShortcutManagerTestable extends ShortcutManager {
+        public ShortcutManagerTestable(Context context, ShortcutServiceTestable service) {
+            super(context, service);
+        }
+
+        @Override
+        protected int injectMyUserId() {
+            return UserHandle.getUserId(mInjectedCallingUid);
+        }
+    }
+
+    private class LauncherAppImplTestable extends LauncherAppsImpl {
+        final ServiceContext mContext;
+
+        public LauncherAppImplTestable(ServiceContext context) {
+            super(context);
+            mContext = context;
+        }
+
+        @Override
+        public void verifyCallingPackage(String callingPackage) {
+            // SKIP
+        }
+
+        @Override
+        void postToPackageMonitorHandler(Runnable r) {
+            final long token = mContext.injectClearCallingIdentity();
+            r.run();
+            mContext.injectRestoreCallingIdentity(token);
+        }
+
+        @Override
+        int injectBinderCallingUid() {
+            return mInjectedCallingUid;
+        }
+
+        @Override
+        long injectClearCallingIdentity() {
+            final int prevCallingUid = mInjectedCallingUid;
+            mInjectedCallingUid = Process.SYSTEM_UID;
+            return prevCallingUid;
+        }
+
+        @Override
+        void injectRestoreCallingIdentity(long token) {
+            mInjectedCallingUid = (int) token;
+        }
+    }
+
+    private class LauncherAppsTestable extends LauncherApps {
+        public LauncherAppsTestable(Context context, ILauncherApps service) {
+            super(context, service);
+        }
+    }
+
+    public static class ShortcutActivity extends Activity {
+    }
+
+    public static class ShortcutActivity2 extends Activity {
+    }
+
+    public static class ShortcutActivity3 extends Activity {
+    }
+
+    private ServiceContext mServiceContext;
+    private ClientContext mClientContext;
+
+    private ShortcutServiceTestable mService;
+    private ShortcutManagerTestable mManager;
+    private ShortcutServiceInternal mInternal;
+
+    private LauncherAppImplTestable mLauncherAppImpl;
+
+    // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
+    private final Map<Pair<Integer, String>, LauncherAppsTestable>
+            mLauncherAppsMap = new HashMap<>();
+    private LauncherAppsTestable mLauncherApps; // Current one
+
+    private File mInjectedFilePathRoot;
+
+    private long mInjectedCurrentTimeLillis;
+
+    private boolean mInjectedIsLowRamDevice;
+
+    private int mInjectedCallingUid;
+    private String mInjectedClientPackage;
+
+    private Map<String, PackageInfo> mInjectedPackages;
+
+    private Set<PackageWithUser> mUninstalledPackages;
+
+    private PackageManager mMockPackageManager;
+    private PackageManagerInternal mMockPackageManagerInternal;
+    private UserManager mMockUserManager;
+
+    private static final String CALLING_PACKAGE_1 = "com.android.test.1";
+    private static final int CALLING_UID_1 = 10001;
+
+    private static final String CALLING_PACKAGE_2 = "com.android.test.2";
+    private static final int CALLING_UID_2 = 10002;
+
+    private static final String CALLING_PACKAGE_3 = "com.android.test.3";
+    private static final int CALLING_UID_3 = 10003;
+
+    private static final String CALLING_PACKAGE_4 = "com.android.test.4";
+    private static final int CALLING_UID_4 = 10004;
+
+    private static final String LAUNCHER_1 = "com.android.launcher.1";
+    private static final int LAUNCHER_UID_1 = 10011;
+
+    private static final String LAUNCHER_2 = "com.android.launcher.2";
+    private static final int LAUNCHER_UID_2 = 10012;
+
+    private static final String LAUNCHER_3 = "com.android.launcher.3";
+    private static final int LAUNCHER_UID_3 = 10013;
+
+    private static final String LAUNCHER_4 = "com.android.launcher.4";
+    private static final int LAUNCHER_UID_4 = 10014;
+
+    private static final int USER_0 = UserHandle.USER_SYSTEM;
+    private static final int USER_10 = 10;
+    private static final int USER_11 = 11;
+    private static final int USER_P0 = 20; // profile of user 0
+
+    private static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0);
+    private static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10);
+    private static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
+    private static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
+
+    private static final UserInfo USER_INFO_0 = withProfileGroupId(
+            new UserInfo(USER_0, "user0",
+                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
+
+    private static final UserInfo USER_INFO_10 =
+            new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
+
+    private static final UserInfo USER_INFO_11 =
+            new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
+
+    private static final UserInfo USER_INFO_P0 = withProfileGroupId(
+            new UserInfo(USER_P0, "userP0",
+                    UserInfo.FLAG_MANAGED_PROFILE), 10);
+
+    private BiPredicate<String, Integer> mDefaultLauncherChecker =
+            (callingPackage, userId) ->
+            LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
+            || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
+
+    private static final long START_TIME = 1440000000101L;
+
+    private static final long INTERVAL = 10000;
+
+    private static final int MAX_SHORTCUTS = 10;
+
+    private static final int MAX_DAILY_UPDATES = 3;
+
+    private static final int MAX_ICON_DIMENSION = 128;
+
+    private static final int MAX_ICON_DIMENSION_LOWRAM = 32;
+
+    private static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
+
+    static {
+        QUERY_ALL.setQueryFlags(
+                ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mServiceContext = spy(new ServiceContext());
+        mClientContext = new ClientContext();
+
+        mMockPackageManager = mock(PackageManager.class);
+        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+        mMockUserManager = mock(UserManager.class);
+
+        // Prepare injection values.
+
+        mInjectedCurrentTimeLillis = START_TIME;
+
+        mInjectedPackages = new HashMap<>();;
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
+        addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
+        addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
+        addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
+        addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
+        addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
+        addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
+
+        // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
+        updatePackageInfo(CALLING_PACKAGE_3,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+        updatePackageInfo(LAUNCHER_3,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        mUninstalledPackages = new HashSet<>();
+
+        mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
+
+        deleteAllSavedFiles();
+
+        // Set up users.
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_0;
+        }).when(mMockUserManager).getUserInfo(eq(USER_0));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_10;
+        }).when(mMockUserManager).getUserInfo(eq(USER_10));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_11;
+        }).when(mMockUserManager).getUserInfo(eq(USER_11));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_P0;
+        }).when(mMockUserManager).getUserInfo(eq(USER_P0));
+
+        // User 0 is always running.
+        when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
+
+        initService();
+        setCaller(CALLING_PACKAGE_1);
+    }
+
+    private static UserInfo withProfileGroupId(UserInfo in, int groupId) {
+        in.profileGroupId = groupId;
+        return in;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
+
+        shutdownServices();
+
+        super.tearDown();
+    }
+
+    private Context getTestContext() {
+        return getInstrumentation().getContext();
+    }
+
+    private void deleteAllSavedFiles() {
+        // Empty the data directory.
+        if (mInjectedFilePathRoot.exists()) {
+            Assert.assertTrue("failed to delete dir",
+                    FileUtils.deleteContents(mInjectedFilePathRoot));
+        }
+        mInjectedFilePathRoot.mkdirs();
+    }
+
+    /** (Re-) init the manager and the service. */
+    private void initService() {
+        shutdownServices();
+
+        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+
+        // Instantiate targets.
+        mService = new ShortcutServiceTestable(mServiceContext, Looper.getMainLooper());
+        mManager = new ShortcutManagerTestable(mClientContext, mService);
+
+        mInternal = LocalServices.getService(ShortcutServiceInternal.class);
+
+        mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
+        mLauncherApps = null;
+        mLauncherAppsMap.clear();
+
+        // Load the setting file.
+        mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
+    }
+
+    private void shutdownServices() {
+        if (mService != null) {
+            // Flush all the unsaved data from the previous instance.
+            mService.saveDirtyInfo();
+        }
+        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+
+        mService = null;
+        mManager = null;
+        mInternal = null;
+        mLauncherAppImpl = null;
+        mLauncherApps = null;
+        mLauncherAppsMap.clear();
+    }
+
+    private void addPackage(String packageName, int uid, int version) {
+        addPackage(packageName, uid, version, packageName);
+    }
+
+    private <T> List<T> list(T... array) {
+        return Arrays.asList(array);
+    }
+
+    private <T> Set<T> set(Set<T> in) {
+        return new ArraySet<T>(in);
+    }
+
+    private Signature[] genSignatures(String... signatures) {
+        final Signature[] sigs = new Signature[signatures.length];
+        for (int i = 0; i < signatures.length; i++){
+            sigs[i] = new Signature(signatures[i].getBytes());
+        }
+        return sigs;
+    }
+
+    private PackageInfo genPackage(String packageName, int uid, int version, String... signatures) {
+        final PackageInfo pi = new PackageInfo();
+        pi.packageName = packageName;
+        pi.applicationInfo = new ApplicationInfo();
+        pi.applicationInfo.uid = uid;
+        pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED
+                | ApplicationInfo.FLAG_ALLOW_BACKUP;
+        pi.versionCode = version;
+        pi.signatures = genSignatures(signatures);
+
+        return pi;
+    }
+
+    private void addPackage(String packageName, int uid, int version, String... signatures) {
+        mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
+    }
+
+    private void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
+        c.accept(mInjectedPackages.get(packageName));
+    }
+
+    private void uninstallPackage(int userId, String packageName) {
+        if (ENABLE_DUMP) {
+            Log.i(TAG, "Unnstall package " + packageName + " / " + userId);
+        }
+        mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
+    }
+
+    private void installPackage(int userId, String packageName) {
+        if (ENABLE_DUMP) {
+            Log.i(TAG, "Install package " + packageName + " / " + userId);
+        }
+        mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
+    }
+
+    PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
+            boolean getSignatures) {
+        final PackageInfo pi = mInjectedPackages.get(packageName);
+        if (pi == null) return null;
+
+        final PackageInfo ret = new PackageInfo();
+        ret.packageName = pi.packageName;
+        ret.versionCode = pi.versionCode;
+        ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
+        ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid);
+        if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
+            ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+        }
+
+        if (getSignatures) {
+            ret.signatures = pi.signatures;
+        }
+
+        return ret;
+    }
+
+    /** Replace the current calling package */
+    private void setCaller(String packageName, int userId) {
+        mInjectedClientPackage = packageName;
+        mInjectedCallingUid =
+                Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
+                        "Unknown package").applicationInfo.uid;
+
+        // Set up LauncherApps for this caller.
+        final Pair<Integer, String> key = Pair.create(userId, packageName);
+        if (!mLauncherAppsMap.containsKey(key)) {
+            mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
+        }
+        mLauncherApps = mLauncherAppsMap.get(key);
+    }
+
+    private void setCaller(String packageName) {
+        setCaller(packageName, UserHandle.USER_SYSTEM);
+    }
+
+    private String getCallingPackage() {
+        return mInjectedClientPackage;
+    }
+
+    private void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
+        mDefaultLauncherChecker = p;
+    }
+
+    private void runWithCaller(String packageName, int userId, Runnable r) {
+        final String previousPackage = mInjectedClientPackage;
+        final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
+
+        setCaller(packageName, userId);
+
+        r.run();
+
+        setCaller(previousPackage, previousUserId);
+    }
+
+    private int getCallingUserId() {
+        return UserHandle.getUserId(mInjectedCallingUid);
+    }
+
+    private UserHandle getCallingUser() {
+        return UserHandle.of(getCallingUserId());
+    }
+
+    /** For debugging */
+    private void dumpsysOnLogcat() {
+        dumpsysOnLogcat("");
+    }
+
+    private void dumpsysOnLogcat(String message) {
+        dumpsysOnLogcat(message, false);
+    }
+
+    private void dumpsysOnLogcat(String message, boolean force) {
+        if (force || !ENABLE_DUMP) return;
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        final PrintWriter pw = new PrintWriter(out);
+        mService.dumpInner(pw);
+        pw.close();
+
+        Log.e(TAG, "Dumping ShortcutService: " + message);
+        for (String line : out.toString().split("\n")) {
+            Log.e(TAG, line);
+        }
+    }
+
+    /**
+     * For debugging, dump arbitrary file on logcat.
+     */
+    private void dumpFileOnLogcat(String path) {
+        dumpFileOnLogcat(path, "");
+    }
+
+    private void dumpFileOnLogcat(String path, String message) {
+        if (!ENABLE_DUMP) return;
+
+        Log.i(TAG, "Dumping file: " + path + " " + message);
+        final StringBuilder sb = new StringBuilder();
+        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                Log.i(TAG, line);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Couldn't read file", e);
+            fail("Exception " + e);
+        }
+    }
+
+    /**
+     * For debugging, dump the main state file on logcat.
+     */
+    private void dumpBaseStateFile() {
+        mService.saveDirtyInfo();
+        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
+                + "/system/" + ShortcutService.FILENAME_BASE_STATE);
+    }
+
+    /**
+     * For debugging, dump per-user state file on logcat.
+     */
+    private void dumpUserFile(int userId) {
+        dumpUserFile(userId, "");
+    }
+
+    private void dumpUserFile(int userId, String message) {
+        mService.saveDirtyInfo();
+        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
+                + "/user-" + userId
+                + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
+    }
+
+    private void waitOnMainThread() throws Throwable {
+        runTestOnUiThread(() -> {});
+    }
+
+    public static Bundle makeBundle(Object... keysAndValues) {
+        Preconditions.checkState((keysAndValues.length % 2) == 0);
+
+        if (keysAndValues.length == 0) {
+            return null;
+        }
+        final Bundle ret = new Bundle();
+
+        for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
+            final String key = keysAndValues[i].toString();
+            final Object value = keysAndValues[i + 1];
+
+            if (value == null) {
+                ret.putString(key, null);
+            } else if (value instanceof Integer) {
+                ret.putInt(key, (Integer) value);
+            } else if (value instanceof String) {
+                ret.putString(key, (String) value);
+            } else if (value instanceof Bundle) {
+                ret.putBundle(key, (Bundle) value);
+            } else {
+                fail("Type not supported yet: " + value.getClass().getName());
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Make a shortcut with an ID.
+     */
+    private ShortcutInfo makeShortcut(String id) {
+        return makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* weight =*/ 0);
+    }
+
+    /**
+     * Make a shortcut with an ID and timestamp.
+     */
+    private ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
+        final ShortcutInfo s = makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* weight =*/ 0);
+        s.setTimestamp(timestamp);
+        return s;
+    }
+
+    /**
+     * Make a shortcut with an ID and icon.
+     */
+    private ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
+        return makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, icon,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* weight =*/ 0);
+    }
+
+    private ShortcutInfo makePackageShortcut(String packageName, String id) {
+        String origCaller = getCallingPackage();
+
+        setCaller(packageName);
+        ShortcutInfo s = makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* weight =*/ 0);
+        setCaller(origCaller); // restore the caller
+
+        return s;
+    }
+
+    /**
+     * Make multiple shortcuts with IDs.
+     */
+    private List<ShortcutInfo> makeShortcuts(String... ids) {
+        final ArrayList<ShortcutInfo> ret = new ArrayList();
+        for (String id : ids) {
+            ret.add(makeShortcut(id));
+        }
+        return ret;
+    }
+
+    private ShortcutInfo.Builder makeShortcutBuilder() {
+        return new ShortcutInfo.Builder(mClientContext);
+    }
+
+    /**
+     * Make a shortcut with details.
+     */
+    private ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
+            Icon icon, Intent intent, int weight) {
+        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext)
+                .setId(id)
+                .setTitle(title)
+                .setWeight(weight)
+                .setIntent(intent);
+        if (icon != null) {
+            b.setIcon(icon);
+        }
+        if (activity != null) {
+            b.setActivityComponent(activity);
+        }
+        final ShortcutInfo s = b.build();
+
+        s.setTimestamp(mInjectedCurrentTimeLillis); // HACK
+
+        return s;
+    }
+
+    /**
+     * Make an intent.
+     */
+    private Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
+        final Intent intent = new Intent(action);
+        intent.setComponent(makeComponent(clazz));
+        intent.replaceExtras(makeBundle(bundleKeysAndValues));
+        return intent;
+    }
+
+    /**
+     * Make an component name, with the client context.
+     */
+    @NonNull
+    private ComponentName makeComponent(Class<?> clazz) {
+        return new ComponentName(mClientContext, clazz);
+    }
+
+    private <T> Set<T> makeSet(T... values) {
+        final HashSet<T> ret = new HashSet<>();
+        for (T s : values) {
+            ret.add(s);
+        }
+        return ret;
+    }
+
+    private static void resetAll(Collection<?> mocks) {
+        for (Object o : mocks) {
+            reset(o);
+        }
+    }
+
+    @NonNull
+    private ShortcutInfo findById(List<ShortcutInfo> list, String id) {
+        for (ShortcutInfo s : list) {
+            if (s.getId().equals(id)) {
+                return s;
+            }
+        }
+        fail("Shortcut with id " + id + " not found");
+        return null;
+    }
+
+    private void assertSystem() {
+        assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
+    }
+
+    private void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
+        assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
+        assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertShortcutIds(@NonNull List<ShortcutInfo> actualShortcuts,
+            String... expectedIds) {
+        final HashSet<String> expected = new HashSet<>(list(expectedIds));
+        final HashSet<String> actual = new HashSet<>();
+        for (ShortcutInfo s : actualShortcuts) {
+            actual.add(s.getId());
+        }
+
+        // Compare the sets.
+        assertEquals(expected, actual);
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllHaveIntents(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNotNull("ID " + s.getId(), s.getIntent());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllNotHaveIntents(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNull("ID " + s.getId(), s.getIntent());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllHaveTitle(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNotNull("ID " + s.getId(), s.getTitle());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllNotHaveTitle(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNull("ID " + s.getId(), s.getTitle());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllNotHaveIcon(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNull("ID " + s.getId(), s.getIcon());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllHaveIconResId(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
+            assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllHaveIconFile(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
+            assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllHaveIcon(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
+            int shortcutFlags) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
+                    s.hasFlags(shortcutFlags));
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllKeyFieldsOnly(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.hasKeyFieldsOnly());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllNotKeyFieldsOnly(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertFalse("ID " + s.getId(), s.hasKeyFieldsOnly());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllDynamic(@NonNull List<ShortcutInfo> actualShortcuts) {
+        return assertAllHaveFlags(actualShortcuts, ShortcutInfo.FLAG_DYNAMIC);
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllPinned(@NonNull List<ShortcutInfo> actualShortcuts) {
+        return assertAllHaveFlags(actualShortcuts, ShortcutInfo.FLAG_PINNED);
+    }
+
+    @NonNull
+    private List<ShortcutInfo> assertAllDynamicOrPinned(
+            @NonNull List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isDynamic() || s.isPinned());
+        }
+        return actualShortcuts;
+    }
+
+    private void assertDynamicOnly(ShortcutInfo si) {
+        assertTrue(si.isDynamic());
+        assertFalse(si.isPinned());
+    }
+
+    private void assertPinnedOnly(ShortcutInfo si) {
+        assertFalse(si.isDynamic());
+        assertTrue(si.isPinned());
+    }
+
+    private void assertDynamicAndPinned(ShortcutInfo si) {
+        assertTrue(si.isDynamic());
+        assertTrue(si.isPinned());
+    }
+
+    private void assertBitmapSize(int expectedWidth, int expectedHeight, @NonNull Bitmap bitmap) {
+        assertEquals("width", expectedWidth, bitmap.getWidth());
+        assertEquals("height", expectedHeight, bitmap.getHeight());
+    }
+
+    private <T> void assertAllUnique(Collection<T> list) {
+        final Set<Object> set = new HashSet<>();
+        for (T item : list) {
+            if (set.contains(item)) {
+                fail("Duplicate item found: " + item + " (in the list: " + list + ")");
+            }
+            set.add(item);
+        }
+    }
+
+    @NonNull
+    private Bitmap pfdToBitmap(@NonNull ParcelFileDescriptor pfd) {
+        Preconditions.checkNotNull(pfd);
+        try {
+            return BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
+        } finally {
+            IoUtils.closeQuietly(pfd);
+        }
+    }
+
+    private void assertBundleEmpty(BaseBundle b) {
+        assertTrue(b == null || b.size() == 0);
+    }
+
+    private ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
+        return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
+    }
+
+    private void assertShortcutExists(String packageName, String shortcutId, int userId) {
+        assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
+    }
+
+    private void assertShortcutNotExists(String packageName, String shortcutId, int userId) {
+        assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
+    }
+
+    private Intent launchShortcutAndGetIntent(
+            @NonNull String packageName, @NonNull String shortcutId, int userId) {
+        reset(mServiceContext);
+        assertTrue(mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+                UserHandle.of(userId)));
+
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mServiceContext).startActivityAsUser(
+                intentCaptor.capture(),
+                any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        return intentCaptor.getValue();
+    }
+
+    private void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
+            int userId) {
+        assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
+    }
+
+    private void assertShortcutNotLaunchable(@NonNull String packageName,
+            @NonNull String shortcutId, int userId) {
+        try {
+            final boolean ok = mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+                    UserHandle.of(userId));
+            if (!ok) {
+                return; // didn't launch, okay.
+            }
+            fail();
+        } catch (SecurityException expected) {
+            // security exception is okay too.
+        }
+    }
+
+    private ShortcutInfo getPackageShortcut(String packageName, String shortcutId) {
+        return getPackageShortcut(packageName, shortcutId, getCallingUserId());
+    }
+
+    private ShortcutInfo getCallerShortcut(String shortcutId) {
+        return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
+    }
+
+    private List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
+        final List<ShortcutInfo>[] ret = new List[1];
+        runWithCaller(launcher, userId, () -> {
+            final ShortcutQuery q = new ShortcutQuery();
+            q.setQueryFlags(queryFlags);
+            ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId));
+        });
+        return ret[0];
+    }
+
+    private List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) {
+        return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
+    }
+
+
+    private Intent genPackageDeleteIntent(String pakcageName, int userId) {
+        Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+        i.setData(Uri.parse("package:" + pakcageName));
+        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        return i;
+    }
+
+    private Intent genPackageUpdateIntent(String pakcageName, int userId) {
+        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
+        i.setData(Uri.parse("package:" + pakcageName));
+        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        i.putExtra(Intent.EXTRA_REPLACING, true);
+        return i;
+    }
+
+    private ShortcutInfo parceled(ShortcutInfo si) {
+        Parcel p = Parcel.obtain();
+        p.writeParcelable(si, 0);
+        p.setDataPosition(0);
+        ShortcutInfo si2 = p.readParcelable(getClass().getClassLoader());
+        p.recycle();
+        return si2;
+    }
+
+    /**
+     * Test for the first launch path, no settings file available.
+     */
+    public void testFirstInitialize() {
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+    }
+
+    /**
+     * Test for {@link ShortcutService#getLastResetTimeLocked()} and
+     * {@link ShortcutService#getNextResetTimeLocked()}.
+     */
+    public void testUpdateAndGetNextResetTimeLocked() {
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+
+        // Advance clock.
+        mInjectedCurrentTimeLillis += 100;
+
+        // Shouldn't have changed.
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+
+        // Advance clock, almost the reset time.
+        mInjectedCurrentTimeLillis = START_TIME + INTERVAL - 1;
+
+        // Shouldn't have changed.
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+
+        // Advance clock.
+        mInjectedCurrentTimeLillis += 1;
+
+        assertResetTimes(START_TIME + INTERVAL, START_TIME + 2 * INTERVAL);
+
+        // Advance further; 4 days since start.
+        mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL + 50;
+
+        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
+    }
+
+    /**
+     * Test for the restoration from saved file.
+     */
+    public void testInitializeFromSavedFile() {
+
+        mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL + 50;
+        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
+
+        mService.saveBaseStateLocked();
+
+        dumpBaseStateFile();
+
+        mService.saveDirtyInfo();
+
+        // Restore.
+        initService();
+
+        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
+    }
+
+    /**
+     * Test for the restoration from restored file.
+     */
+    public void testLoadFromBrokenFile() {
+        // TODO Add various broken cases.
+    }
+
+    public void testLoadConfig() {
+        mService.updateConfigurationLocked(
+                ConfigConstants.KEY_RESET_INTERVAL_SEC + "=123,"
+                        + ConfigConstants.KEY_MAX_SHORTCUTS + "=4,"
+                        + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=5,"
+                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+                        + ConfigConstants.KEY_ICON_FORMAT + "=WEBP,"
+                        + ConfigConstants.KEY_ICON_QUALITY + "=75");
+        assertEquals(123000, mService.getResetIntervalForTest());
+        assertEquals(4, mService.getMaxDynamicShortcutsForTest());
+        assertEquals(5, mService.getMaxDailyUpdatesForTest());
+        assertEquals(100, mService.getMaxIconDimensionForTest());
+        assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
+        assertEquals(75, mService.getIconPersistQualityForTest());
+
+        mInjectedIsLowRamDevice = true;
+        mService.updateConfigurationLocked(
+                ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+                        + ConfigConstants.KEY_ICON_FORMAT + "=JPEG");
+        assertEquals(ShortcutService.DEFAULT_RESET_INTERVAL_SEC * 1000,
+                mService.getResetIntervalForTest());
+
+        assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP,
+                mService.getMaxDynamicShortcutsForTest());
+
+        assertEquals(ShortcutService.DEFAULT_MAX_DAILY_UPDATES,
+                mService.getMaxDailyUpdatesForTest());
+
+        assertEquals(50, mService.getMaxIconDimensionForTest());
+
+        assertEquals(CompressFormat.JPEG, mService.getIconPersistFormatForTest());
+
+        assertEquals(ShortcutService.DEFAULT_ICON_PERSIST_QUALITY,
+                mService.getIconPersistQualityForTest());
+    }
+
+    // === Test for app side APIs ===
+
+    /** Test for {@link android.content.pm.ShortcutManager#getMaxDynamicShortcutCount()} */
+    public void testGetMaxDynamicShortcutCount() {
+        assertEquals(MAX_SHORTCUTS, mManager.getMaxDynamicShortcutCount());
+    }
+
+    /** Test for {@link android.content.pm.ShortcutManager#getRemainingCallCount()} */
+    public void testGetRemainingCallCount() {
+        assertEquals(MAX_DAILY_UPDATES, mManager.getRemainingCallCount());
+    }
+
+    /** Test for {@link android.content.pm.ShortcutManager#getRateLimitResetTime()} */
+    public void testGetRateLimitResetTime() {
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL + 50;
+
+        assertEquals(START_TIME + 5 * INTERVAL, mManager.getRateLimitResetTime());
+    }
+
+    public void testSetDynamicShortcuts() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
+        final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.icon2));
+
+        final ShortcutInfo si1 = makeShortcut(
+                "shortcut1",
+                "Title 1",
+                makeComponent(ShortcutActivity.class),
+                icon1,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+
+        final ShortcutInfo si2 = makeShortcut(
+                "shortcut2",
+                "Title 2",
+                /* activity */ null,
+                icon2,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                /* weight */ 12);
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2");
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        // TODO: Check fields
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1");
+        assertEquals(1, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list()));
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(0, mManager.getRemainingCallCount());
+
+        dumpsysOnLogcat();
+
+        mInjectedCurrentTimeLillis++; // Need to advance the clock for reset to work.
+        mService.resetThrottlingInner(UserHandle.USER_SYSTEM);
+
+        dumpsysOnLogcat();
+
+        assertTrue(mManager.setDynamicShortcuts(list(si2, si3)));
+        assertEquals(2, mManager.getDynamicShortcuts().size());
+
+        // TODO Check max number
+
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+    }
+
+    public void testAddDynamicShortcuts() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+        final ShortcutInfo si2 = makeShortcut("shortcut2");
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1");
+
+        assertTrue(mManager.addDynamicShortcut(si2));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2");
+
+        // Add with the same ID
+        assertTrue(mManager.addDynamicShortcut(makeShortcut("shortcut1")));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2");
+
+        // TODO Check max number
+
+        // TODO Check fields.
+
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+        });
+    }
+
+    public void testDeleteDynamicShortcut() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+        final ShortcutInfo si2 = makeShortcut("shortcut2");
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2", "shortcut3");
+
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mManager.deleteDynamicShortcut("shortcut1");
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut2", "shortcut3");
+
+        mManager.deleteDynamicShortcut("shortcut1");
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut2", "shortcut3");
+
+        mManager.deleteDynamicShortcut("shortcutXXX");
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut2", "shortcut3");
+
+        mManager.deleteDynamicShortcut("shortcut2");
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut3");
+
+        mManager.deleteDynamicShortcut("shortcut3");
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()));
+
+        // Still 2 calls left.
+        assertEquals(2, mManager.getRemainingCallCount());
+    }
+
+    public void testDeleteAllDynamicShortcuts() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+        final ShortcutInfo si2 = makeShortcut("shortcut2");
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2", "shortcut3");
+
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mManager.deleteAllDynamicShortcuts();
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        // Note delete shouldn't affect throttling, so...
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+
+        // This should still work.
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
+        assertEquals(3, mManager.getDynamicShortcuts().size());
+
+        // Still 1 call left
+        assertEquals(1, mManager.getRemainingCallCount());
+    }
+
+    public void testThrottling() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Reached the max
+
+        mInjectedCurrentTimeLillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Still throttled
+        mInjectedCurrentTimeLillis = START_TIME + INTERVAL - 1;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Now it should work.
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1))); // fail
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        // 4 days later...
+        mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
+
+        // Make sure getRemainingCallCount() itself gets reset without calling setDynamicShortcuts().
+        mInjectedCurrentTimeLillis = START_TIME + 8 * INTERVAL;
+        assertEquals(3, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
+    }
+
+    public void testThrottling_rewind() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeLillis = 12345; // Clock reset!
+
+        // Since the clock looks invalid, the counter shouldn't have reset.
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Forward again.  Still haven't reset yet.
+        mInjectedCurrentTimeLillis = START_TIME + INTERVAL - 1;
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Now rewind -- this will reset the counters.
+        mInjectedCurrentTimeLillis = START_TIME - 100000;
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        // Forward again, should be reset now.
+        mInjectedCurrentTimeLillis += INTERVAL;
+        assertEquals(3, mManager.getRemainingCallCount());
+    }
+
+    public void testThrottling_perPackage() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+
+        // Reached the max
+
+        mInjectedCurrentTimeLillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+
+        // Try from a different caller.
+        mInjectedClientPackage = CALLING_PACKAGE_2;
+        mInjectedCallingUid = CALLING_UID_2;
+
+        // Need to create a new one wit the updated package name.
+        final ShortcutInfo si2 = makeShortcut("shortcut1");
+
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertEquals(1, mManager.getRemainingCallCount());
+
+        // Back to the original caller, still throttled.
+        mInjectedClientPackage = CALLING_PACKAGE_1;
+        mInjectedCallingUid = CALLING_UID_1;
+
+        mInjectedCurrentTimeLillis = START_TIME + INTERVAL - 1;
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+
+        // Now it should work.
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeLillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeLillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedClientPackage = CALLING_PACKAGE_2;
+        mInjectedCallingUid = CALLING_UID_2;
+
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertFalse(mManager.setDynamicShortcuts(list(si2)));
+    }
+
+    public void testIcons() {
+        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
+        final Icon res64x64 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
+        final Icon res512x512 = Icon.createWithResource(getTestContext(), R.drawable.black_512x512);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+        final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_64x64));
+        final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_512x512));
+
+        // Set from package 1
+        setCaller(CALLING_PACKAGE_1);
+        assertTrue(mManager.setDynamicShortcuts(list(
+                makeShortcutWithIcon("res32x32", res32x32),
+                makeShortcutWithIcon("res64x64", res64x64),
+                makeShortcutWithIcon("bmp32x32", bmp32x32),
+                makeShortcutWithIcon("bmp64x64", bmp64x64),
+                makeShortcutWithIcon("bmp512x512", bmp512x512),
+                makeShortcut("none")
+        )));
+
+        // getDynamicShortcuts() shouldn't return icons, thus assertAllNotHaveIcon().
+        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
+                "res32x32",
+                "res64x64",
+                "bmp32x32",
+                "bmp64x64",
+                "bmp512x512",
+                "none");
+
+        // Call from another caller with the same ID, just to make sure storage is per-package.
+        setCaller(CALLING_PACKAGE_2);
+        assertTrue(mManager.setDynamicShortcuts(list(
+                makeShortcutWithIcon("res32x32", res512x512),
+                makeShortcutWithIcon("res64x64", res512x512),
+                makeShortcutWithIcon("none", res512x512)
+        )));
+        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
+                "res32x32",
+                "res64x64",
+                "none");
+
+        // Re-initialize and load from the files.
+        mService.saveDirtyInfo();
+        initService();
+
+        // Load from launcher.
+        Bitmap bmp;
+
+        setCaller(LAUNCHER_1);
+        // Check hasIconResource()/hasIconFile().
+        assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
+                CALLING_PACKAGE_1, list("res32x32"),
+                getCallingUser())), "res32x32");
+
+        assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
+                CALLING_PACKAGE_1, list("res64x64"), getCallingUser())),
+                "res64x64");
+
+        assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
+                CALLING_PACKAGE_1, list("bmp32x32"), getCallingUser())),
+                "bmp32x32");
+
+        assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
+                CALLING_PACKAGE_1, list("bmp64x64"), getCallingUser())),
+                "bmp64x64");
+
+        assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
+                CALLING_PACKAGE_1, list("bmp512x512"), getCallingUser())),
+                "bmp512x512");
+
+        // Check
+        assertEquals(
+                R.drawable.black_32x32,
+                mLauncherApps.getShortcutIconResId(
+                        makePackageShortcut(CALLING_PACKAGE_1, "res32x32"), getCallingUser()));
+
+        assertEquals(
+                R.drawable.black_64x64,
+                mLauncherApps.getShortcutIconResId(
+
+                        makePackageShortcut(CALLING_PACKAGE_1, "res64x64"), getCallingUser()));
+
+        assertEquals(
+                0, // because it's not a resource
+                mLauncherApps.getShortcutIconResId(
+                        makePackageShortcut(CALLING_PACKAGE_1, "bmp32x32"), getCallingUser()));
+        assertEquals(
+                0, // because it's not a resource
+                mLauncherApps.getShortcutIconResId(
+                        makePackageShortcut(CALLING_PACKAGE_1, "bmp64x64"), getCallingUser()));
+        assertEquals(
+                0, // because it's not a resource
+                mLauncherApps.getShortcutIconResId(
+                        makePackageShortcut(CALLING_PACKAGE_1, "bmp512x512"), getCallingUser()));
+
+        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
+                makePackageShortcut(CALLING_PACKAGE_1, "bmp32x32"), getCallingUser()));
+        assertBitmapSize(32, 32, bmp);
+
+        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
+                makePackageShortcut(CALLING_PACKAGE_1, "bmp64x64"), getCallingUser()));
+        assertBitmapSize(64, 64, bmp);
+
+        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
+                makePackageShortcut(CALLING_PACKAGE_1, "bmp512x512"), getCallingUser()));
+        assertBitmapSize(128, 128, bmp);
+
+        // TODO Test the content URI case too.
+    }
+
+    private void checkShrinkBitmap(int expectedWidth, int expectedHeight, int resId, int maxSize) {
+        assertBitmapSize(expectedWidth, expectedHeight,
+                ShortcutService.shrinkBitmap(BitmapFactory.decodeResource(
+                        getTestContext().getResources(), resId),
+                        maxSize));
+    }
+
+    public void testShrinkBitmap() {
+        checkShrinkBitmap(32, 32, R.drawable.black_512x512, 32);
+        checkShrinkBitmap(511, 511, R.drawable.black_512x512, 511);
+        checkShrinkBitmap(512, 512, R.drawable.black_512x512, 512);
+
+        checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4096);
+        checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4100);
+        checkShrinkBitmap(512, 2048, R.drawable.black_1024x4096, 2048);
+
+        checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4096);
+        checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4100);
+        checkShrinkBitmap(2048, 512, R.drawable.black_4096x1024, 2048);
+    }
+
+    private File openIconFileForWriteAndGetPath(int userId, String packageName)
+            throws IOException {
+        // Shortcut IDs aren't used in the path, so just pass the same ID.
+        final FileOutputStreamWithPath out =
+                mService.openIconFileForWrite(userId, makePackageShortcut(packageName, "id"));
+        out.close();
+        return out.getFile();
+    }
+
+    public void testOpenIconFileForWrite() throws IOException {
+        mInjectedCurrentTimeLillis = 1000;
+
+        final File p10_1_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+        final File p10_1_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+
+        final File p10_2_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+        final File p10_2_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+
+        final File p11_1_1 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+        final File p11_1_2 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+
+        mInjectedCurrentTimeLillis++;
+
+        final File p10_1_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+        final File p10_1_4 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+        final File p10_1_5 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+
+        final File p10_2_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+        final File p11_1_3 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+
+        // Make sure their paths are all unique
+        assertAllUnique(list(
+                p10_1_1,
+                p10_1_2,
+                p10_1_3,
+                p10_1_4,
+                p10_1_5,
+
+                p10_2_1,
+                p10_2_2,
+                p10_2_3,
+
+                p11_1_1,
+                p11_1_2,
+                p11_1_3
+        ));
+
+        // Check each set has the same parent.
+        assertEquals(p10_1_1.getParent(), p10_1_2.getParent());
+        assertEquals(p10_1_1.getParent(), p10_1_3.getParent());
+        assertEquals(p10_1_1.getParent(), p10_1_4.getParent());
+        assertEquals(p10_1_1.getParent(), p10_1_5.getParent());
+
+        assertEquals(p10_2_1.getParent(), p10_2_2.getParent());
+        assertEquals(p10_2_1.getParent(), p10_2_3.getParent());
+
+        assertEquals(p11_1_1.getParent(), p11_1_2.getParent());
+        assertEquals(p11_1_1.getParent(), p11_1_3.getParent());
+
+        // Check the parents are still unique.
+        assertAllUnique(list(
+                p10_1_1.getParent(),
+                p10_2_1.getParent(),
+                p11_1_1.getParent()
+        ));
+
+        // All files created at the same time for the same package/user, expcet for the first ones,
+        // will have "_" in the path.
+        assertFalse(p10_1_1.getName().contains("_"));
+        assertTrue(p10_1_2.getName().contains("_"));
+        assertFalse(p10_1_3.getName().contains("_"));
+        assertTrue(p10_1_4.getName().contains("_"));
+        assertTrue(p10_1_5.getName().contains("_"));
+
+        assertFalse(p10_2_1.getName().contains("_"));
+        assertTrue(p10_2_2.getName().contains("_"));
+        assertFalse(p10_2_3.getName().contains("_"));
+
+        assertFalse(p11_1_1.getName().contains("_"));
+        assertTrue(p11_1_2.getName().contains("_"));
+        assertFalse(p11_1_3.getName().contains("_"));
+    }
+
+    public void testUpdateShortcuts() {
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"),
+                    makeShortcut("s2"),
+                    makeShortcut("s3"),
+                    makeShortcut("s4"),
+                    makeShortcut("s5")
+            )));
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"),
+                    makeShortcut("s2"),
+                    makeShortcut("s3"),
+                    makeShortcut("s4"),
+                    makeShortcut("s5")
+            )));
+        });
+        runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"),
+                    getCallingUser());
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"),
+                    getCallingUser());
+        });
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            mManager.deleteDynamicShortcut("s1");
+            mManager.deleteDynamicShortcut("s2");
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            mManager.deleteDynamicShortcut("s1");
+            mManager.deleteDynamicShortcut("s3");
+            mManager.deleteDynamicShortcut("s5");
+        });
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s3", "s4", "s5");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2", "s3");
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s2", "s4");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s4", "s5");
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            ShortcutInfo s2 = makeShortcutBuilder()
+                    .setId("s2")
+                    .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
+                    .build();
+
+            ShortcutInfo s4 = makeShortcutBuilder()
+                    .setId("s4")
+                    .setTitle("new title")
+                    .build();
+
+            mManager.updateShortcuts(list(s2, s4));
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            ShortcutInfo s2 = makeShortcutBuilder()
+                    .setId("s2")
+                    .setIntent(makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
+                            "key1", "val1"))
+                    .build();
+
+            ShortcutInfo s4 = makeShortcutBuilder()
+                    .setId("s4")
+                    .setIntent(new Intent(Intent.ACTION_ALL_APPS))
+                    .build();
+
+            mManager.updateShortcuts(list(s2, s4));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s3", "s4", "s5");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2", "s3");
+
+            ShortcutInfo s = getCallerShortcut("s2");
+            assertTrue(s.hasIconResource());
+            assertEquals(R.drawable.black_32x32, s.getIconResourceId());
+            assertEquals("Title-s2", s.getTitle());
+
+            s = getCallerShortcut("s4");
+            assertFalse(s.hasIconResource());
+            assertEquals(0, s.getIconResourceId());
+            assertEquals("new title", s.getTitle());
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s2", "s4");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s4", "s5");
+
+            ShortcutInfo s = getCallerShortcut("s2");
+            assertFalse(s.hasIconResource());
+            assertEquals(0, s.getIconResourceId());
+            assertEquals("Title-s2", s.getTitle());
+            assertEquals(Intent.ACTION_ANSWER, s.getIntent().getAction());
+            assertEquals(1, s.getIntent().getExtras().size());
+
+            s = getCallerShortcut("s4");
+            assertFalse(s.hasIconResource());
+            assertEquals(0, s.getIconResourceId());
+            assertEquals("Title-s4", s.getTitle());
+            assertEquals(Intent.ACTION_ALL_APPS, s.getIntent().getAction());
+            assertBundleEmpty(s.getIntent().getExtras());
+        });
+        // TODO Check with other fields too.
+
+        // TODO Check bitmap removal too.
+
+        runWithCaller(CALLING_PACKAGE_2, USER_11, () -> {
+            mManager.updateShortcuts(list());
+        });
+    }
+
+    // === Test for launcher side APIs ===
+
+    private static ShortcutQuery buildQuery(long changedSince,
+            String packageName, ComponentName componentName,
+            /* @ShortcutQuery.QueryFlags */ int flags) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setChangedSince(changedSince);
+        q.setPackage(packageName);
+        q.setActivity(componentName);
+        q.setQueryFlags(flags);
+        return q;
+    }
+
+    private static ShortcutQuery buildAllQuery(String packageName) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setPackage(packageName);
+        q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+        return q;
+    }
+
+    private static ShortcutQuery buildPinnedQuery(String packageName) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setPackage(packageName);
+        q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
+        return q;
+    }
+
+    public void testGetShortcuts() {
+
+        // Set up shortcuts.
+
+        setCaller(CALLING_PACKAGE_1);
+        final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 5000);
+        final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 1000);
+
+        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+
+        setCaller(CALLING_PACKAGE_2);
+        final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
+        final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
+        final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
+        assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
+
+        setCaller(CALLING_PACKAGE_3);
+        final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s3", START_TIME + 5000);
+        assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
+
+        setCaller(LAUNCHER_1);
+
+        // Get dynamic
+        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllNotKeyFieldsOnly(
+                mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                        /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                "s1", "s2"))));
+
+        // Get pinned
+        assertShortcutIds(
+                mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_PINNED), getCallingUser())
+                /* none */);
+
+        // Get both, with timestamp
+        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC),
+                        getCallingUser())),
+                "s2", "s3"))));
+
+        // FLAG_GET_KEY_FIELDS_ONLY
+        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+                        getCallingUser())),
+                "s2", "s3"))));
+
+        // Pin some shortcuts.
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                list("s3", "s4"), getCallingUser());
+
+        // Pinned ones only
+        assertAllPinned(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_PINNED),
+                        getCallingUser())),
+                "s3"))));
+
+        // All packages.
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 5000, /* package= */ null,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED),
+                        getCallingUser())),
+                "s1", "s3");
+
+        // TODO More tests: pinned but dynamic, filter by activity
+    }
+
+    public void testGetShortcutInfo() {
+        // Create shortcuts.
+        setCaller(CALLING_PACKAGE_1);
+        final ShortcutInfo s1_1 = makeShortcut(
+                "s1",
+                "Title 1",
+                makeComponent(ShortcutActivity.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+
+        final ShortcutInfo s1_2 = makeShortcut(
+                "s2",
+                "Title 2",
+                /* activity */ null,
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                /* weight */ 12);
+
+        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+        dumpsysOnLogcat();
+
+        setCaller(CALLING_PACKAGE_2);
+        final ShortcutInfo s2_1 = makeShortcut(
+                "s1",
+                "ABC",
+                makeComponent(ShortcutActivity2.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ANSWER, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+        assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
+        dumpsysOnLogcat();
+
+        // Pin some.
+        setCaller(LAUNCHER_1);
+
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                list("s2"), getCallingUser());
+
+        dumpsysOnLogcat();
+
+        // Delete some.
+        setCaller(CALLING_PACKAGE_1);
+        assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+        mManager.deleteDynamicShortcut("s2");
+        assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+
+        dumpsysOnLogcat();
+
+        setCaller(LAUNCHER_1);
+        List<ShortcutInfo> list;
+
+        // Note we don't guarantee the orders.
+        list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
+                assertAllNotKeyFieldsOnly(
+                mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
+                list("s2", "s1", "s3", null), getCallingUser())))),
+                "s1", "s2");
+        assertEquals("Title 1", findById(list, "s1").getTitle());
+        assertEquals("Title 2", findById(list, "s2").getTitle());
+
+        assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
+                mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
+                        list("s3"), getCallingUser())))
+                /* none */);
+
+        list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
+                mLauncherApps.getShortcutInfo(CALLING_PACKAGE_2,
+                        list("s1", "s2", "s3"), getCallingUser()))),
+                "s1");
+        assertEquals("ABC", findById(list, "s1").getTitle());
+    }
+
+    public void testPinShortcutAndGetPinnedShortcuts() {
+        // Create some shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
+            final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
+
+            assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
+            final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
+            final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
+            assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
+            assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
+        });
+
+        // Pin some.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2", "s3"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s3", "s4", "s5"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
+                    list("s3"), getCallingUser());  // Note ID doesn't exist
+        });
+
+        // Delete some.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+            mManager.deleteDynamicShortcut("s2");
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+            mManager.deleteDynamicShortcut("s3");
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+            mManager.deleteDynamicShortcut("s2");
+            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+        });
+
+        // Get pinned shortcuts from launcher
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s2");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3", "s4");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+                    /* none */);
+        });
+    }
+
+    public void testPinShortcutAndGetPinnedShortcuts_multi() {
+        // Create some shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        dumpsysOnLogcat();
+
+        // Pin some.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3", "s4"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1", "s2", "s4"), getCallingUser());
+        });
+
+        dumpsysOnLogcat();
+
+        // Delete some.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
+            mManager.deleteDynamicShortcut("s3");
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
+        });
+
+        dumpsysOnLogcat();
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
+            mManager.deleteDynamicShortcut("s1");
+            mManager.deleteDynamicShortcut("s3");
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
+        });
+
+        dumpsysOnLogcat();
+
+        // Get pinned shortcuts from launcher
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2");
+
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+        });
+
+        dumpsysOnLogcat();
+
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            // Launcher2 still has no pinned ones.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+                    /* none */);
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+                    /* none */);
+
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s2");
+
+            // Now pin some.
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1", "s2"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1", "s2"), getCallingUser());
+
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+
+            // S1 was not visible to it, so shouldn't be pinned.
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s2");
+        });
+
+        // Re-initialize and load from the files.
+        mService.saveDirtyInfo();
+        initService();
+
+        // Load from file.
+        mService.handleUnlockUser(USER_0);
+
+        // Make sure package info is restored too.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2");
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s2");
+        });
+
+        // Delete all dynamic.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.deleteAllDynamicShortcuts();
+
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            mManager.deleteAllDynamicShortcuts();
+
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1");
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2");
+
+            // from all packages.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, null,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2", "s3");
+
+            // Update pined.  Note s2 and s3 are actually available, but not visible to this
+            // launcher, so still can't be pinned.
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
+                    getCallingUser());
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+        });
+        // Re-publish s1.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+
+            // Now "s1" is visible, so can be pinned.
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
+                    getCallingUser());
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s3");
+        });
+
+        // Now clear pinned shortcuts.  First, from launcher 1.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
+
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2");
+        });
+
+        // Clear all pins from launcher 2.
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
+
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+    }
+
+    public void testPinShortcutAndGetPinnedShortcuts_crossProfile_plusLaunch() {
+        // Create some shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+
+        // Pin some shortcuts and see the result.
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1", "s2", "s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s2", "s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1", "s2", "s3"), HANDLE_USER_10);
+        });
+
+        // Cross profile pinning.
+        final int PIN_AND_DYNAMIC = ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC;
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+
+        // Remove some dynamic shortcuts.
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
+                    "s1", "s2", "s3");
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+
+        // Save & load and make sure we still have the same information.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+    }
+
+    public void testStartShortcut() {
+        // Create some shortcuts.
+        setCaller(CALLING_PACKAGE_1);
+        final ShortcutInfo s1_1 = makeShortcut(
+                "s1",
+                "Title 1",
+                makeComponent(ShortcutActivity.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+
+        final ShortcutInfo s1_2 = makeShortcut(
+                "s2",
+                "Title 2",
+                /* activity */ null,
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                /* weight */ 12);
+
+        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+
+        setCaller(CALLING_PACKAGE_2);
+        final ShortcutInfo s2_1 = makeShortcut(
+                "s1",
+                "ABC",
+                makeComponent(ShortcutActivity.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+        assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
+
+        // Pin all.
+        setCaller(LAUNCHER_1);
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                list("s1", "s2"), getCallingUser());
+
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                list("s1"), getCallingUser());
+
+        // Just to make it complicated, delete some.
+        setCaller(CALLING_PACKAGE_1);
+        mManager.deleteDynamicShortcut("s2");
+
+        // intent and check.
+        setCaller(LAUNCHER_1);
+
+        Intent intent;
+        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s1", USER_0);
+        assertEquals(ShortcutActivity2.class.getName(), intent.getComponent().getClassName());
+
+
+        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0);
+        assertEquals(ShortcutActivity3.class.getName(), intent.getComponent().getClassName());
+
+        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0);
+        assertEquals(ShortcutActivity.class.getName(), intent.getComponent().getClassName());
+
+        // TODO Check extra, etc
+    }
+
+    public void testLauncherCallback() throws Throwable {
+        LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
+
+        // Set listeners
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.registerCallback(c0, new Handler(Looper.getMainLooper()));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        waitOnMainThread();
+        ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s1", "s2", "s3");
+
+        // From different package.
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_2),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s1", "s2", "s3");
+
+        // Different user, callback shouldn't be called.
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        waitOnMainThread();
+        verify(c0, times(0)).onShortcutsChanged(
+                anyString(),
+                any(List.class),
+                any(UserHandle.class)
+        );
+
+        // Test for addDynamicShortcut.
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            dumpsysOnLogcat("before addDynamicShortcut");
+            assertTrue(mManager.addDynamicShortcut(makeShortcut("s4")));
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s1", "s2", "s3", "s4");
+
+        // Test for remove
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            mManager.deleteDynamicShortcut("s1");
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s2", "s3", "s4");
+
+        // Test for update
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.updateShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"))));
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s2", "s3", "s4");
+
+        // Test for deleteAll
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            mManager.deleteAllDynamicShortcuts();
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertEquals(0, shortcuts.getValue().size());
+
+        // Remove CALLING_PACKAGE_2
+        reset(c0);
+        uninstallPackage(USER_0, CALLING_PACKAGE_2);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0);
+
+        // Should get a callback with an empty list.
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_2),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertEquals(0, shortcuts.getValue().size());
+    }
+
+    private void assertCallbackNotReceived(LauncherApps.Callback mock) {
+        verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
+                any(UserHandle.class));
+    }
+
+    private void assertCallbackReceived(LauncherApps.Callback mock,
+            UserHandle user, String packageName, String... ids) {
+        ArgumentCaptor<List> shortcutsCaptor = ArgumentCaptor.forClass(List.class);
+
+        verify(mock, times(1)).onShortcutsChanged(eq(packageName), shortcutsCaptor.capture(),
+                eq(user));
+        assertShortcutIds(shortcutsCaptor.getValue(), ids);
+    }
+
+    public void testLauncherCallback_crossProfile() throws Throwable {
+        prepareCrossProfileDataSet();
+
+        final Handler h = new Handler(Looper.getMainLooper());
+
+        final LauncherApps.Callback c0_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_2 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_3 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_4 = mock(LauncherApps.Callback.class);
+
+        final LauncherApps.Callback cP0_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c10_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c10_2 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c11_1 = mock(LauncherApps.Callback.class);
+
+        final List<LauncherApps.Callback> all =
+                list(c0_1, c0_2, c0_3, c0_4, cP0_1, c10_1, c11_1);
+
+        setDefaultLauncherChecker((pkg, userId) -> {
+            switch (userId) {
+                case USER_0:
+                    return LAUNCHER_2.equals(pkg);
+                case USER_P0:
+                    return LAUNCHER_1.equals(pkg);
+                case USER_10:
+                    return LAUNCHER_1.equals(pkg);
+                case USER_11:
+                    return LAUNCHER_1.equals(pkg);
+                default:
+                    return false;
+            }
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> mLauncherApps.registerCallback(c0_1, h));
+        runWithCaller(LAUNCHER_2, USER_0, () -> mLauncherApps.registerCallback(c0_2, h));
+        runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h));
+        runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h));
+        runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h));
+        runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h));
+        runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h));
+        runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h));
+
+        // User 0.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3");
+        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+        // User 0, different package.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4");
+        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3,
+                "s1", "s2", "s3", "s4", "s5", "s6");
+
+        // Work profile, but not running, so don't send notifications.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_2);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(cP0_1);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+
+        // Work profile, now running.
+
+        when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+        when(mMockUserManager.isUserRunning(eq(USER_P0))).thenReturn(true);
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s5");
+        assertCallbackReceived(cP0_1, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+        // Normal secondary user.
+
+        when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+        when(mMockUserManager.isUserRunning(eq(USER_10))).thenReturn(true);
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_2);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(cP0_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1,
+                "x1", "x2", "x3", "x4", "x5");
+    }
+
+    // === Test for persisting ===
+
+    public void testSaveAndLoadUser_empty() {
+        assertTrue(mManager.setDynamicShortcuts(list()));
+
+        Log.i(TAG, "Saved state");
+        dumpsysOnLogcat();
+        dumpUserFile(0);
+
+        // Restore.
+        mService.saveDirtyInfo();
+        initService();
+
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+    }
+
+    /**
+     * Try save and load, also stop/start the user.
+     */
+    public void testSaveAndLoadUser() {
+        // First, create some shortcuts and save.
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x16);
+            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                    getTestContext().getResources(), R.drawable.icon2));
+
+            final ShortcutInfo si1 = makeShortcut(
+                    "s1",
+                    "title1-1",
+                    makeComponent(ShortcutActivity.class),
+                    icon1,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+                        /* weight */ 10);
+
+            final ShortcutInfo si2 = makeShortcut(
+                    "s2",
+                    "title1-2",
+                        /* activity */ null,
+                    icon2,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                        /* weight */ 12);
+
+            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+
+            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+            assertEquals(2, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_16x64);
+            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                    getTestContext().getResources(), R.drawable.icon2));
+
+            final ShortcutInfo si1 = makeShortcut(
+                    "s1",
+                    "title2-1",
+                    makeComponent(ShortcutActivity.class),
+                    icon1,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+                        /* weight */ 10);
+
+            final ShortcutInfo si2 = makeShortcut(
+                    "s2",
+                    "title2-2",
+                        /* activity */ null,
+                    icon2,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                        /* weight */ 12);
+
+            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+
+            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+            assertEquals(2, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
+            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                    getTestContext().getResources(), R.drawable.icon2));
+
+            final ShortcutInfo si1 = makeShortcut(
+                    "s1",
+                    "title10-1-1",
+                    makeComponent(ShortcutActivity.class),
+                    icon1,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+                        /* weight */ 10);
+
+            final ShortcutInfo si2 = makeShortcut(
+                    "s2",
+                    "title10-1-2",
+                        /* activity */ null,
+                    icon2,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                        /* weight */ 12);
+
+            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+
+            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+            assertEquals(2, mManager.getRemainingCallCount());
+        });
+
+        mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setLauncherComponent(
+                mService, new ComponentName("pkg1", "class"));
+
+        // Restore.
+        mService.saveDirtyInfo();
+        initService();
+
+        // Before the load, the map should be empty.
+        assertEquals(0, mService.getShortcutsForTest().size());
+
+        // this will pre-load the per-user info.
+        mService.handleUnlockUser(UserHandle.USER_SYSTEM);
+
+        // Now it's loaded.
+        assertEquals(1, mService.getShortcutsForTest().size());
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
+                    mManager.getDynamicShortcuts()))), "s1", "s2");
+            assertEquals(2, mManager.getRemainingCallCount());
+
+            assertEquals("title1-1", getCallerShortcut("s1").getTitle());
+            assertEquals("title1-2", getCallerShortcut("s2").getTitle());
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
+                    mManager.getDynamicShortcuts()))), "s1", "s2");
+            assertEquals(2, mManager.getRemainingCallCount());
+
+            assertEquals("title2-1", getCallerShortcut("s1").getTitle());
+            assertEquals("title2-2", getCallerShortcut("s2").getTitle());
+        });
+
+        assertEquals("pkg1", mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM)
+                .getLauncherComponent().getPackageName());
+
+        // Start another user
+        mService.handleUnlockUser(USER_10);
+
+        // Now the size is 2.
+        assertEquals(2, mService.getShortcutsForTest().size());
+
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
+                    mManager.getDynamicShortcuts()))), "s1", "s2");
+            assertEquals(2, mManager.getRemainingCallCount());
+
+            assertEquals("title10-1-1", getCallerShortcut("s1").getTitle());
+            assertEquals("title10-1-2", getCallerShortcut("s2").getTitle());
+        });
+        assertNull(mService.getShortcutsForTest().get(USER_10).getLauncherComponent());
+
+        // Try stopping the user
+        mService.handleCleanupUser(USER_10);
+
+        // Now it's unloaded.
+        assertEquals(1, mService.getShortcutsForTest().size());
+
+        // TODO Check all other fields
+    }
+
+    public void testCleanupPackage() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s0_1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s0_2"))));
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
+                    HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
+                    HANDLE_USER_0);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
+                    HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
+                    HANDLE_USER_0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s10_1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s10_2"))));
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
+                    HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
+                    HANDLE_USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
+                    HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
+                    HANDLE_USER_10);
+        });
+
+        // Remove all dynamic shortcuts; now all shortcuts are just pinned.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.deleteAllDynamicShortcuts();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            mManager.deleteAllDynamicShortcuts();
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            mManager.deleteAllDynamicShortcuts();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            mManager.deleteAllDynamicShortcuts();
+        });
+
+
+        final SparseArray<ShortcutUser> users =  mService.getShortcutsForTest();
+        assertEquals(2, users.size());
+        assertEquals(USER_0, users.keyAt(0));
+        assertEquals(USER_10, users.keyAt(1));
+
+        final ShortcutUser user0 =  users.get(USER_0);
+        final ShortcutUser user10 =  users.get(USER_10);
+
+
+        // Check the registered packages.
+        dumpsysOnLogcat();
+        assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                set(user0.getAllPackages().keySet()));
+        assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                set(user10.getAllPackages().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                set(user0.getAllLaunchers().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
+                        PackageWithUser.of(USER_10, LAUNCHER_2)),
+                set(user10.getAllLaunchers().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Nonexistent package.
+        uninstallPackage(USER_0, "abc");
+        mService.cleanUpPackageLocked("abc", USER_0, USER_0);
+
+        // No changes.
+        assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                set(user0.getAllPackages().keySet()));
+        assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                set(user10.getAllPackages().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                set(user0.getAllLaunchers().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
+                        PackageWithUser.of(USER_10, LAUNCHER_2)),
+                set(user10.getAllLaunchers().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove a package.
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0);
+
+        assertEquals(makeSet(CALLING_PACKAGE_2),
+                set(user0.getAllPackages().keySet()));
+        assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                set(user10.getAllPackages().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                set(user0.getAllLaunchers().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
+                        PackageWithUser.of(USER_10, LAUNCHER_2)),
+                set(user10.getAllLaunchers().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove a launcher.
+        uninstallPackage(USER_10, LAUNCHER_1);
+        mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10);
+
+        assertEquals(makeSet(CALLING_PACKAGE_2),
+                set(user0.getAllPackages().keySet()));
+        assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                set(user10.getAllPackages().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                set(user0.getAllLaunchers().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_10, LAUNCHER_2)),
+                set(user10.getAllLaunchers().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove a package.
+        uninstallPackage(USER_10, CALLING_PACKAGE_2);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10);
+
+        assertEquals(makeSet(CALLING_PACKAGE_2),
+                set(user0.getAllPackages().keySet()));
+        assertEquals(makeSet(CALLING_PACKAGE_1),
+                set(user10.getAllPackages().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                set(user0.getAllLaunchers().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_10, LAUNCHER_2)),
+                set(user10.getAllLaunchers().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1");
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove the other launcher from user 10 too.
+        uninstallPackage(USER_10, LAUNCHER_2);
+        mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10);
+
+        assertEquals(makeSet(CALLING_PACKAGE_2),
+                set(user0.getAllPackages().keySet()));
+        assertEquals(makeSet(CALLING_PACKAGE_1),
+                set(user10.getAllPackages().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                set(user0.getAllLaunchers().keySet()));
+        assertEquals(
+                makeSet(),
+                set(user10.getAllLaunchers().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+
+        // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // More remove.
+        uninstallPackage(USER_10, CALLING_PACKAGE_1);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10);
+
+        assertEquals(makeSet(CALLING_PACKAGE_2),
+                set(user0.getAllPackages().keySet()));
+        assertEquals(makeSet(),
+                set(user10.getAllPackages().keySet()));
+        assertEquals(
+                makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                set(user0.getAllLaunchers().keySet()));
+        assertEquals(makeSet(),
+                set(user10.getAllLaunchers().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+
+        // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+    }
+
+    public void testHandleGonePackage_crossProfile() {
+        // Create some shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Pin some.
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2"), UserHandle.of(USER_P0));
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3"), UserHandle.of(USER_P0));
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3"), HANDLE_USER_10);
+        });
+
+        // Check the state.
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Make sure all the information is persisted.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Start uninstalling.
+        uninstallPackage(USER_10, LAUNCHER_1);
+        mService.cleanupGonePackages(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Uninstall.
+        uninstallPackage(USER_10, CALLING_PACKAGE_1);
+        mService.cleanupGonePackages(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        uninstallPackage(USER_P0, LAUNCHER_1);
+        mService.cleanupGonePackages(USER_0);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        mService.cleanupGonePackages(USER_P0);
+        
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        uninstallPackage(USER_P0, CALLING_PACKAGE_1);
+
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Uninstall
+        uninstallPackage(USER_0, LAUNCHER_1);
+
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        uninstallPackage(USER_0, CALLING_PACKAGE_2);
+
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+    }
+
+    private void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi,
+            int version, String... signatures) {
+        assertEquals(expected, spi.canRestoreTo(mService, genPackage(
+                "dummy", /* uid */ 0, version, signatures)));
+    }
+
+    public void testCanRestoreTo() {
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
+        addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2");
+
+        final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackage(
+                mService, CALLING_PACKAGE_1, USER_0);
+        final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackage(
+                mService, CALLING_PACKAGE_2, USER_0);
+
+        checkCanRestoreTo(true, spi1, 10, "sig1");
+        checkCanRestoreTo(true, spi1, 10, "x", "sig1");
+        checkCanRestoreTo(true, spi1, 10, "sig1", "y");
+        checkCanRestoreTo(true, spi1, 10, "x", "sig1", "y");
+        checkCanRestoreTo(true, spi1, 11, "sig1");
+
+        checkCanRestoreTo(false, spi1, 10 /* empty */);
+        checkCanRestoreTo(false, spi1, 10, "x");
+        checkCanRestoreTo(false, spi1, 10, "x", "y");
+        checkCanRestoreTo(false, spi1, 10, "x");
+        checkCanRestoreTo(false, spi1, 9, "sig1");
+
+        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2");
+        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1");
+        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2", "y");
+        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1", "y");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2", "y");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1", "y");
+        checkCanRestoreTo(true, spi2, 11, "x", "sig2", "sig1", "y");
+
+        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x");
+        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1");
+        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x", "y");
+        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x", "y");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2", "y");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1", "y");
+        checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
+    }
+
+    public void testHandlePackageDelete() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+        assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+        setCaller(CALLING_PACKAGE_2, USER_0);
+        assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+        setCaller(CALLING_PACKAGE_3, USER_0);
+        assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+        setCaller(CALLING_PACKAGE_1, USER_10);
+        assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+        setCaller(CALLING_PACKAGE_2, USER_10);
+        assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+        setCaller(CALLING_PACKAGE_3, USER_10);
+        assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        uninstallPackage(USER_10, CALLING_PACKAGE_2);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        mInjectedPackages.remove(CALLING_PACKAGE_1);
+        mInjectedPackages.remove(CALLING_PACKAGE_3);
+
+        mService.handleUnlockUser(USER_0);
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        mService.handleUnlockUser(USER_10);
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+    }
+
+    private void backupAndRestore() {
+        int prevUid = mInjectedCallingUid;
+
+        mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
+
+        dumpsysOnLogcat("Before backup");
+
+        final byte[] payload =  mService.getBackupPayload(USER_0);
+        if (ENABLE_DUMP) {
+            final String xml = new String(payload);
+            Log.i(TAG, "Backup payload:");
+            for (String line : xml.split("\n")) {
+                Log.i(TAG, line);
+            }
+        }
+
+        // Before doing anything else, uninstall all packages.
+        for (int userId : list(USER_0, USER_P0)) {
+            for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
+                    LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
+                uninstallPackage(userId, pkg);
+            }
+        }
+
+        shutdownServices();
+
+        deleteAllSavedFiles();
+
+        initService();
+        mService.applyRestore(payload, USER_0);
+
+        // handleUnlockUser will perform the gone package check, but it shouldn't remove
+        // shadow information.
+        mService.handleUnlockUser(USER_0);
+
+        dumpsysOnLogcat("After restore");
+
+        mInjectedCallingUid = prevUid;
+    }
+
+    private void prepareCrossProfileDataSet() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list()));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
+                    makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_3, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_4, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
+        });
+
+        // Launcher on a managed profile is referring ot user 0!
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
+                    HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
+                    HANDLE_USER_10);
+        });
+
+        // Then remove some dynamic shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list()));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
+        });
+    }
+
+    private void prepareForBackupTest() {
+
+        prepareCrossProfileDataSet();
+
+        backupAndRestore();
+    }
+
+    private void assertExistsAndShadow(ShortcutPackageItem spi) {
+        assertNotNull(spi);
+        assertTrue(spi.getPackageInfo().isShadow());
+    }
+
+    /**
+     * Make sure the backup data doesn't have the following information:
+     * - Launchers on other users.
+     * - Non-backup app information.
+     *
+     * But restores all other infomation.
+     *
+     * It also omits the following pieces of information, but that's tested in
+     * {@link #testShortcutInfoSaveAndLoad_forBackup}.
+     * - Unpinned dynamic shortcuts
+     * - Bitmaps
+     */
+    public void testBackupAndRestore() {
+        prepareForBackupTest();
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_backupRestoreTwice() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        dumpsysOnLogcat("Before second backup");
+
+        backupAndRestore();
+
+        dumpsysOnLogcat("After second backup");
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_backupRestoreMultiple() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        // This also shouldn't affect the result.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+
+        backupAndRestore();
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_restoreToNewVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5);
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_restoreToSuperSetSignatures() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        // Change package signatures.
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy");
+
+        checkBackupAndRestore_success();
+    }
+
+    private void checkBackupAndRestore_success() {
+        // Make sure non-system user is not restored.
+        final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
+        assertEquals(0, userP0.getAllPackages().size());
+        assertEquals(0, userP0.getAllLaunchers().size());
+
+        // Make sure only "allowBackup" apps are restored, and are shadow.
+        final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
+        assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_1));
+        assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_2));
+        assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_1)));
+        assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_2)));
+
+        assertNull(user0.getAllPackages().get(CALLING_PACKAGE_3));
+        assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
+        assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty, not restored */ );
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty, not restored */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty, not restored */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        // 3 shouldn't be backed up, so no pinned shortcuts.
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        // Launcher on a different profile shouldn't be restored.
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+                    .size());
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+                            .size());
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+        });
+
+        // Package on a different profile, no restore.
+        installPackage(USER_P0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        // Restore launcher 2 on user 0.
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+
+        // Restoration of launcher2 shouldn't affect other packages; so do the same checks and
+        // make sure they still have the same result.
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+    }
+
+    public void testBackupAndRestore_publisherLowerVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    public void testBackupAndRestore_publisherWrongSignature() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    public void testBackupAndRestore_publisherNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(CALLING_PACKAGE_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    private void checkBackupAndRestore_publisherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testBackupAndRestore_launcherLowerVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    public void testBackupAndRestore_launcherWrongSignature() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    public void testBackupAndRestore_launcherNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(LAUNCHER_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    private void checkBackupAndRestore_launcherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+
+            // s1 was pinned by launcher 1, which is not restored, yet, so we still see "s1" here.
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        // Now we try to restore launcher 1.  Then we realize it's not restorable, so L1 has no pinned
+        // shortcuts.
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+
+            // Now CALLING_PACKAGE_1 realizes "s1" is no longer pinned.
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(CALLING_PACKAGE_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        updatePackageInfo(LAUNCHER_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_publisherAndLauncherNotRestored();
+    }
+
+    private void checkBackupAndRestore_publisherAndLauncherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        // Because launcher 1 wasn't restored, "s1" is no longer pinned.
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2", "s3");
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testSaveAndLoad_crossProfile() {
+        prepareCrossProfileDataSet();
+
+        dumpsysOnLogcat("Before save & load");
+
+        mService.saveDirtyInfo();
+        initService();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5");
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+                    /* empty */);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_P0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+                    /* empty */);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "x1", "x2", "x3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "x4", "x5");
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s1");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s1", "s2");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s1", "s2", "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s1", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+            TestUtils.assertExpectException(
+                    SecurityException.class, "", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+                    });
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s2");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s2", "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s2", "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s2", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_3, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s3", "s4", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s3", "s6");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_4, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s3", "s4", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s3", "s4", "s5", "s6");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s1", "s4");
+            TestUtils.assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+                    });
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10),
+                    "x4", "x5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10)
+                    /* empty */);
+            TestUtils.assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0);
+                    });
+            TestUtils.assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
+                    });
+        });
+    }
+
+    // ShortcutInfo tests
+
+    public void testShortcutInfoMissingMandatoryFields() {
+        TestUtils.assertExpectException(
+                IllegalArgumentException.class,
+                "ID must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).build());
+        TestUtils.assertExpectException(
+                IllegalArgumentException.class,
+                "title must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
+                        .enforceMandatoryFields());
+        TestUtils.assertExpectException(
+                NullPointerException.class,
+                "Intent must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).setId("id").setTitle("x").build()
+                        .enforceMandatoryFields());
+    }
+
+    public void testShortcutInfoParcel() {
+        ShortcutInfo si = parceled(new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setTitle("title")
+                .setIntent(makeIntent("action", ShortcutActivity.class))
+                .build());
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals("title", si.getTitle());
+        assertEquals("action", si.getIntent().getAction());
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+
+        si = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivityComponent(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+        si.addFlags(ShortcutInfo.FLAG_PINNED);
+        si.setBitmapPath("abc");
+        si.setIconResourceId(456);
+
+        si = parceled(si);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals("content://a.b.c/", si.getIcon().getUriString());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoClone() {
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivityComponent(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals("content://a.b.c/", si.getIcon().getUriString());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+        assertEquals(0, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals(null, si.getIntent());
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+        assertEquals(0, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(null, si.getActivityComponent());
+        assertEquals(null, si.getIcon());
+        assertEquals(null, si.getTitle());
+        assertEquals(null, si.getText());
+        assertEquals(null, si.getIntent());
+        assertEquals(0, si.getWeight());
+        assertEquals(null, si.getExtras());
+
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+        assertEquals(0, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivityComponent(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si;
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setActivityComponent(new ComponentName("x", "y")).build());
+        assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
+        assertEquals("content://x.y.z/", si.getIcon().getUriString());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+        assertEquals("xyz", si.getTitle());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setText("xxx").build());
+        assertEquals("xxx", si.getText());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+        assertEquals("action2", si.getIntent().getAction());
+        assertEquals(null, si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
+        assertEquals("action3", si.getIntent().getAction());
+        assertEquals("x", si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setWeight(999).build());
+        assertEquals(999, si.getWeight());
+
+
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("x", 99);
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setExtras(pb2).build());
+        assertEquals(99, si.getExtras().getInt("x"));
+
+        final long timestamp = si.getLastChangedTimestamp();
+        Thread.sleep(2);
+
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+
+        assertTrue(si.getLastChangedTimestamp() > timestamp);
+    }
+
+    public void testShortcutInfoSaveAndLoad() throws InterruptedException {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcut(sorig);
+
+        Thread.sleep(2);
+        final long now = System.currentTimeMillis();
+
+        // Save and load.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+        assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
+        assertNotNull(si.getBitmapPath()); // Something should be set.
+        assertEquals(0, si.getIconResourceId());
+        assertTrue(si.getLastChangedTimestamp() < now);
+    }
+
+    public void testShortcutInfoSaveAndLoad_forBackup() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcut(sorig);
+
+        // Dynamic shortcuts won't be backed up, so we need to pin it.
+        setCaller(LAUNCHER_1, USER_0);
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+
+        // Do backup & restore.
+        backupAndRestore();
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+        assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertNull(si.getBitmapPath()); // No icon.
+        assertEquals(0, si.getIconResourceId());
+    }
+
+    public void testDumpsys_crossProfile() {
+        prepareCrossProfileDataSet();
+        dumpsysOnLogcat("test1", /* force= */ true);
+    }
+
+    public void testDumpsys_withIcons() {
+        testIcons();
+        // Dump after having some icons.
+        dumpsysOnLogcat("test1", /* force= */ true);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
new file mode 100644
index 0000000..c016e61
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.backup;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser.Package;
+import android.content.pm.Signature;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.backup.BackupUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@SmallTest
+public class BackupUtilsTest extends AndroidTestCase {
+
+    private Signature[] genSignatures(String... signatures) {
+        final Signature[] sigs = new Signature[signatures.length];
+        for (int i = 0; i < signatures.length; i++){
+            sigs[i] = new Signature(signatures[i].getBytes());
+        }
+        return sigs;
+    }
+
+    private PackageInfo genPackage(String... signatures) {
+        final PackageInfo pi = new PackageInfo();
+        pi.packageName = "package";
+        pi.applicationInfo = new ApplicationInfo();
+        pi.signatures = genSignatures(signatures);
+
+        return pi;
+    }
+
+    public void testSignaturesMatch() {
+        final ArrayList<byte[]> stored1 = BackupUtils.hashSignatureArray(Arrays.asList(
+                "abc".getBytes()));
+        final ArrayList<byte[]> stored2 = BackupUtils.hashSignatureArray(Arrays.asList(
+                "abc".getBytes(), "def".getBytes()));
+
+        PackageInfo pi;
+
+        // False for null package.
+        assertFalse(BackupUtils.signaturesMatch(stored1, null));
+
+        // If it's a system app, signatures don't matter.
+        pi = genPackage("xyz");
+        pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        assertTrue(BackupUtils.signaturesMatch(stored1, pi));
+
+        // Non system apps.
+        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc")));
+
+        // Superset is okay.
+        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz")));
+        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc")));
+
+        assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz")));
+        assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def")));
+
+        assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc")));
+        assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y")));
+
+        // Subset is not okay.
+        assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc")));
+        assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def")));
+    }
+
+    public void testHashSignature() {
+        final byte[] sig1 = "abc".getBytes();
+        final byte[] sig2 = "def".getBytes();
+
+        final byte[] hash1a = BackupUtils.hashSignature(sig1);
+        final byte[] hash1b = BackupUtils.hashSignature(new Signature(sig1));
+
+        final byte[] hash2a = BackupUtils.hashSignature(sig2);
+        final byte[] hash2b = BackupUtils.hashSignature(new Signature(sig2));
+
+        assertEquals(32, hash1a.length);
+        MoreAsserts.assertEquals(hash1a, hash1b);
+
+        assertEquals(32, hash2a.length);
+        MoreAsserts.assertEquals(hash2a, hash2b);
+
+        assertFalse(Arrays.equals(hash1a, hash2a));
+
+        final ArrayList<byte[]> listA = BackupUtils.hashSignatureArray(Arrays.asList(
+                "abc".getBytes(), "def".getBytes()));
+
+        final ArrayList<byte[]> listB = BackupUtils.hashSignatureArray(new Signature[]{
+                new Signature("abc".getBytes()), new Signature("def".getBytes())});
+
+        assertEquals(2, listA.size());
+        assertEquals(2, listB.size());
+
+        MoreAsserts.assertEquals(hash1a, listA.get(0));
+        MoreAsserts.assertEquals(hash1a, listB.get(0));
+
+        MoreAsserts.assertEquals(hash2a, listA.get(1));
+        MoreAsserts.assertEquals(hash2a, listB.get(1));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
new file mode 100644
index 0000000..d2a4484
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.testutis;
+
+import android.test.MoreAsserts;
+
+import junit.framework.Assert;
+
+public class TestUtils {
+    private TestUtils() {
+    }
+
+    public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
+            String expectedExceptionMessageRegex, Runnable r) {
+        try {
+            r.run();
+            Assert.fail("Expected exception type " + expectedExceptionType.getName()
+                    + " was not thrown");
+        } catch (Throwable e) {
+            Assert.assertTrue(
+                    "Expected exception type was " + expectedExceptionType.getName()
+                    + " but caught " + e.getClass().getName(),
+                    expectedExceptionType.isAssignableFrom(e.getClass()));
+            if (expectedExceptionMessageRegex != null) {
+                MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
+            }
+        }
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 3e2b43d..a3313c9 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -274,6 +274,11 @@
                 - (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
     }
 
+    public void clearUsageLocked(String packageName, int userId) {
+        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+        userHistory.remove(packageName);
+    }
+
     private boolean hasPassedThresholdsLocked(PackageHistory packageHistory, long elapsedRealtime) {
         return (packageHistory.lastUsedScreenTime
                     <= getScreenOnTimeLocked(elapsedRealtime) - mScreenOnTimeThreshold)
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 8e891bf..beec40f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -151,6 +151,8 @@
     private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
             mPackageAccessListeners = new ArrayList<>();
 
+    private List<String> mCarrierPrivilegedApps;
+
     public UsageStatsService(Context context) {
         super(context);
     }
@@ -170,10 +172,19 @@
                     + mUsageStatsDir.getAbsolutePath());
         }
 
-        IntentFilter userActions = new IntentFilter(Intent.ACTION_USER_REMOVED);
-        userActions.addAction(Intent.ACTION_USER_STARTED);
-        getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, userActions,
-                null, null);
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        filter.addAction(Intent.ACTION_USER_STARTED);
+        getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, filter,
+                null, mHandler);
+
+        IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageFilter.addDataScheme("package");
+
+        getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
+                null, mHandler);
 
         mAppIdleEnabled = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_enableAutoPowerModes);
@@ -232,15 +243,15 @@
     }
 
     private class UserActionsReceiver extends BroadcastReceiver {
-
         @Override
         public void onReceive(Context context, Intent intent) {
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 if (userId >= 0) {
                     mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
                 }
-            } else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
+            } else if (Intent.ACTION_USER_STARTED.equals(action)) {
                 if (userId >=0) {
                     postCheckIdleStates(userId);
                 }
@@ -248,6 +259,23 @@
         }
     }
 
+    private class PackageReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_PACKAGE_ADDED.equals(action)
+                    || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+                clearCarrierPrivilegedApps();
+            }
+            if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
+                    Intent.ACTION_PACKAGE_ADDED.equals(action))
+                    && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(),
+                        getSendingUserId());
+            }
+        }
+    }
+
     private class DeviceStateReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -311,6 +339,12 @@
         }
     }
 
+    void clearAppIdleForPackage(String packageName, int userId) {
+        synchronized (mLock) {
+            mAppIdleHistory.clearUsageLocked(packageName, userId);
+        }
+    }
+
     private void cleanUpRemovedUsersLocked() {
         final List<UserInfo> users = mUserManager.getUsers(true);
         if (users == null || users.size() == 0) {
@@ -416,7 +450,7 @@
                 return false;
             }
         } catch (RemoteException re) {
-            return false;
+            throw re.rethrowFromSystemServer();
         }
 
         final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -784,6 +818,7 @@
                 return false;
             }
         } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
 
         if (isActiveDeviceAdmin(packageName, userId)) {
@@ -828,7 +863,7 @@
             }
             apps = slice.getList();
         } catch (RemoteException e) {
-            return new int[0];
+            throw e.rethrowFromSystemServer();
         }
 
         // State of each uid.  Key is the uid.  Value lower 16 bits is the number of apps
@@ -890,9 +925,30 @@
     }
 
     private boolean isCarrierApp(String packageName) {
-        TelephonyManager telephonyManager = getContext().getSystemService(TelephonyManager.class);
-        return telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
-                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+        synchronized (mLock) {
+            if (mCarrierPrivilegedApps == null) {
+                fetchCarrierPrivilegedAppsLocked();
+            }
+        }
+        return mCarrierPrivilegedApps.contains(packageName);
+    }
+
+    void clearCarrierPrivilegedApps() {
+        if (DEBUG) {
+            Slog.i(TAG, "Clearing carrier privileged apps list");
+        }
+        synchronized (mLock) {
+            mCarrierPrivilegedApps = null; // Need to be refetched.
+        }
+    }
+
+    private void fetchCarrierPrivilegedAppsLocked() {
+        TelephonyManager telephonyManager =
+                getContext().getSystemService(TelephonyManager.class);
+        mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
+        if (DEBUG) {
+            Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
+        }
     }
 
     private boolean isActiveNetworkScorer(String packageName) {
@@ -963,6 +1019,9 @@
             }
 
             pw.println();
+            pw.println("Carrier privileged apps: " + mCarrierPrivilegedApps);
+
+            pw.println();
             pw.println("Settings:");
 
             pw.print("  mAppIdleDurationMillis=");
@@ -1213,7 +1272,7 @@
                 userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
                         Binder.getCallingUid(), userId, false, true, "isAppInactive", null);
             } catch (RemoteException re) {
-                return false;
+                throw re.rethrowFromSystemServer();
             }
             final long token = Binder.clearCallingIdentity();
             try {
@@ -1232,7 +1291,7 @@
                         Binder.getCallingPid(), callingUid, userId, false, true,
                         "setAppIdle", null);
             } catch (RemoteException re) {
-                return;
+                throw re.rethrowFromSystemServer();
             }
             getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
                     "No permission to change app idle state");
@@ -1257,6 +1316,17 @@
         }
 
         @Override
+        public void onCarrierPrivilegedAppsChanged() {
+            if (DEBUG) {
+                Slog.i(TAG, "Carrier privileged apps changed");
+            }
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.BIND_CARRIER_SERVICES,
+                    "onCarrierPrivilegedAppsChanged can only be called by privileged apps.");
+            UsageStatsService.this.clearCarrierPrivilegedApps();
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 17039bb..101e200 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
@@ -101,8 +102,8 @@
                 TAG, device.getDeviceId(), notification);
     }
 
-    void hideNotification(UsbDevice device) {
-        mContext.getSystemService(NotificationManager.class).cancel(TAG, device.getDeviceId());
+    void hideNotification(int deviceId) {
+        mContext.getSystemService(NotificationManager.class).cancel(TAG, deviceId);
     }
 
     private class Receiver extends BroadcastReceiver {
@@ -121,7 +122,13 @@
         }
     }
 
-    static boolean isMtpDevice(UsbDevice device) {
+    static boolean shouldShowNotification(PackageManager packageManager, UsbDevice device) {
+        // We don't show MTP notification for devices that has FEATURE_AUTOMOTIVE.
+        return !packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) &&
+                isMtpDevice(device);
+    }
+
+    private static boolean isMtpDevice(UsbDevice device) {
         for (int i = 0; i < device.getInterfaceCount(); i++) {
             final UsbInterface usbInterface = device.getInterface(i);
             if ((usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE &&
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 129e537..058de05 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -385,6 +385,7 @@
             UsbAudioDevice audioDevice = selectAudioCard(addedCard);
             if (audioDevice != null) {
                 mAudioDevices.put(usbDevice, audioDevice);
+                Slog.i(TAG, "USB Audio Device Added: " + audioDevice);
             }
 
             // look for MIDI devices
@@ -441,6 +442,7 @@
         }
 
         UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
+        Slog.i(TAG, "USB Audio Device Removed: " + audioDevice);
         if (audioDevice != null) {
             if (audioDevice.mHasPlayback || audioDevice.mHasCapture) {
                 notifyDeviceState(audioDevice, false);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 35a0464..08cbcf7 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -608,6 +608,7 @@
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                     | Intent.FLAG_RECEIVER_FOREGROUND);
             intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
+            intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
             intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
             intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked);
 
@@ -717,6 +718,9 @@
                 case MSG_UPDATE_HOST_STATE:
                     mHostConnected = (msg.arg1 == 1);
                     updateUsbNotification();
+                    if (mBootCompleted) {
+                        updateUsbStateBroadcastIfNeeded();
+                    }
                     break;
                 case MSG_ENABLE_ADB:
                     setAdbEnabled(msg.arg1 == 1);
@@ -776,7 +780,7 @@
                     || ("0".equals(SystemProperties.get("persist.charging.notify")))) return;
             int id = 0;
             Resources r = mContext.getResources();
-            if (mConnected || mHostConnected) {
+            if (mConnected) {
                 if (!mUsbDataUnlocked) {
                     id = com.android.internal.R.string.usb_charging_notification_title;
                 } else if (UsbManager.containsFunction(mCurrentFunctions,
@@ -794,6 +798,8 @@
                 } else {
                     id = com.android.internal.R.string.usb_charging_notification_title;
                 }
+            } else if (mHostConnected) {
+                id = com.android.internal.R.string.usb_supplying_notification_title;
             }
             if (id != mUsbNotificationId) {
                 // clear notification if title needs changing
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 38ede87..46ce7a0 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -127,6 +127,14 @@
         public void setReceiver(MidiReceiver receiver) {
             mReceiver = receiver;
         }
+
+        @Override
+        public void onFlush() throws IOException {
+            MidiReceiver receiver = mReceiver;
+            if (receiver != null) {
+                receiver.flush();
+            }
+        }
     }
 
     public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index c4d7336..de9ede3 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -738,7 +738,7 @@
         // Send broadcast to running activity with registered intent
         mUserContext.sendBroadcast(intent);
 
-        if (MtpNotificationManager.isMtpDevice(device)) {
+        if (MtpNotificationManager.shouldShowNotification(mPackageManager, device)) {
             // Show notification if the device is MTP storage.
             mMtpNotificationManager.showNotification(device);
         } else {
@@ -769,9 +769,7 @@
         if (DEBUG) Slog.d(TAG, "usbDeviceRemoved, sending " + intent);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
 
-        if (MtpNotificationManager.isMtpDevice(device)) {
-            mMtpNotificationManager.hideNotification(device);
-        }
+        mMtpNotificationManager.hideNotification(device.getDeviceId());
     }
 
     public void accessoryAttached(UsbAccessory accessory) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index b4c4bf8..40687b0 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -171,7 +171,7 @@
 
             // Fetch a ModelData instance from the hash map. Creates a new one if none
             // exists.
-            ModelData modelData = getOrCreateGenericModelData(modelId);
+            ModelData modelData = getOrCreateGenericModelDataLocked(modelId);
 
             IRecognitionStatusCallback oldCallback = modelData.getCallback();
             if (oldCallback != null) {
@@ -199,6 +199,7 @@
                 }
                 modelData.setHandle(handle[0]);
                 modelData.setLoaded();
+                Slog.d(TAG, "Generic sound model loaded with handle:" + handle[0]);
             }
             modelData.setCallback(callback);
             modelData.setRecognitionConfig(recognitionConfig);
@@ -227,7 +228,7 @@
 
         synchronized (mLock) {
             if (DBG) {
-                Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId
+                Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId
                         + " soundModel=" + soundModel + ", listener=" + listener.asBinder()
                         + ", recognitionConfig=" + recognitionConfig);
                 Slog.d(TAG, "moduleProperties=" + mModuleProperties);
@@ -243,13 +244,13 @@
             }
 
             if (mModuleProperties == null) {
-                Slog.w(TAG, "Attempting startRecognition without the capability");
+                Slog.w(TAG, "Attempting startKeyphraseRecognition without the capability");
                 return STATUS_ERROR;
             }
             if (mModule == null) {
                 mModule = SoundTrigger.attachModule(mModuleProperties.id, this, null);
                 if (mModule == null) {
-                    Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
+                    Slog.w(TAG, "startKeyphraseRecognition cannot attach to sound trigger module");
                     return STATUS_ERROR;
                 }
             }
@@ -348,28 +349,31 @@
             }
 
             if (currentCallback == null || !modelData.isModelStarted()) {
-                // startRecognition hasn't been called or it failed.
-                Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
+                // startGenericRecognition hasn't been called or it failed.
+                Slog.w(TAG, "Attempting stopGenericRecognition without a successful" +
+                        " startGenericRecognition");
                 return STATUS_ERROR;
             }
             if (currentCallback.asBinder() != listener.asBinder()) {
                 // We don't allow a different listener to stop the recognition than the one
                 // that started it.
-                Slog.w(TAG, "Attempting stopRecognition for another recognition");
+                Slog.w(TAG, "Attempting stopGenericRecognition for another recognition");
                 return STATUS_ERROR;
             }
 
-            int status = stopGenericRecognitionLocked(modelData, false /* don't notify for synchronous calls */);
+            int status = stopGenericRecognitionLocked(modelData,
+                    false /* don't notify for synchronous calls */);
             if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "stopGenericRecognition failed: " + status);
                 return status;
             }
 
             // We leave the sound model loaded but not started, this helps us when we start
             // back.
             // Also clear the internal state once the recognition has been stopped.
-            modelData.clearState();
+            modelData.setLoaded();
             modelData.clearCallback();
-            if (!computeRecognitionRunning()) {
+            if (!computeRecognitionRunningLocked()) {
                 internalClearGlobalStateLocked();
             }
             return status;
@@ -471,6 +475,66 @@
         return mModuleProperties;
     }
 
+    int unloadKeyphraseSoundModel(int keyphraseId) {
+        if (mModule == null || mCurrentKeyphraseModelHandle == INVALID_VALUE) {
+            return STATUS_ERROR;
+        }
+        if (mKeyphraseId != keyphraseId) {
+            Slog.w(TAG, "Given sound model is not the one loaded.");
+            return STATUS_ERROR;
+        }
+
+        synchronized (mLock) {
+            // Stop recognition if it's the current one.
+            mRequested = false;
+            int status = updateRecognitionLocked(false /* don't notify */);
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status);
+            }
+
+            status = mModule.unloadSoundModel(mCurrentKeyphraseModelHandle);
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "unloadKeyphraseSoundModel call failed with " + status);
+            }
+            internalClearKeyphraseSoundModelLocked();
+            return status;
+        }
+    }
+
+    int unloadGenericSoundModel(UUID modelId) {
+        if (modelId == null || mModule == null) {
+            return STATUS_ERROR;
+        }
+        synchronized (mLock) {
+            ModelData modelData = mGenericModelDataMap.get(modelId);
+            if (modelData == null) {
+                Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" + modelId);
+                return STATUS_ERROR;
+            }
+            if (!modelData.isModelLoaded()) {
+                // Nothing to do here.
+                Slog.i(TAG, "Unload: Given generic model is not loaded:" + modelId);
+                return STATUS_OK;
+            }
+            if (modelData.isModelStarted()) {
+                int status = stopGenericRecognitionLocked(modelData,
+                        false /* don't notify for synchronous calls */);
+                if (status != SoundTrigger.STATUS_OK) {
+                    Slog.w(TAG, "stopGenericRecognition failed: " + status);
+                }
+            }
+
+            int status = mModule.unloadSoundModel(modelData.getHandle());
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status);
+                Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded.");
+            }
+            mGenericModelDataMap.remove(modelId);
+            if (DBG) dumpGenericModelStateLocked();
+            return status;
+        }
+    }
+
     //---- SoundTrigger.StatusListener methods
     @Override
     public void onRecognition(RecognitionEvent event) {
@@ -509,14 +573,14 @@
     }
 
     private boolean isKeyphraseRecognitionEvent(RecognitionEvent event) {
-        return mCurrentKeyphraseModelHandle == event.soundModelHandle;
+        return event instanceof KeyphraseRecognitionEvent;
     }
 
     private void onGenericRecognitionSuccessLocked(GenericRecognitionEvent event) {
         if (event.status != SoundTrigger.RECOGNITION_STATUS_SUCCESS) {
             return;
         }
-        ModelData model = getModelDataFor(event.soundModelHandle);
+        ModelData model = getModelDataForLocked(event.soundModelHandle);
         if (model == null) {
             Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
                     event.soundModelHandle);
@@ -531,9 +595,9 @@
         }
 
         try {
-            callback.onDetected((GenericRecognitionEvent) event);
+            callback.onGenericSoundTriggerDetected((GenericRecognitionEvent) event);
         } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in onDetected", e);
+            Slog.w(TAG, "RemoteException in onGenericSoundTriggerDetected", e);
         }
 
         model.setStopped();
@@ -651,10 +715,10 @@
 
         try {
             if (mKeyphraseListener != null) {
-                mKeyphraseListener.onDetected((KeyphraseRecognitionEvent) event);
+                mKeyphraseListener.onKeyphraseDetected((KeyphraseRecognitionEvent) event);
             }
         } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in onDetected", e);
+            Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
         }
 
         mKeyphraseStarted = false;
@@ -703,7 +767,7 @@
             int status = mModule.startRecognition(mCurrentKeyphraseModelHandle,
                     mRecognitionConfig);
             if (status != SoundTrigger.STATUS_OK) {
-                Slog.w(TAG, "startRecognition failed with " + status);
+                Slog.w(TAG, "startKeyphraseRecognition failed with " + status);
                 // Notify of error if needed.
                 if (notify) {
                     try {
@@ -855,7 +919,7 @@
         mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
     }
 
-    private ModelData getOrCreateGenericModelData(UUID modelId) {
+    private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
         ModelData modelData = mGenericModelDataMap.get(modelId);
         if (modelData == null) {
             modelData = new ModelData(modelId);
@@ -868,7 +932,7 @@
     // Instead of maintaining a second hashmap of modelHandle -> ModelData, we just
     // iterate through to find the right object (since we don't expect 100s of models
     // to be stored).
-    private ModelData getModelDataFor(int modelHandle) {
+    private ModelData getModelDataForLocked(int modelHandle) {
         // Fetch ModelData object corresponding to the model handle.
         for (ModelData model : mGenericModelDataMap.values()) {
             if (model.getHandle() == modelHandle) {
@@ -903,7 +967,7 @@
 
         int status = mModule.startRecognition(handle, config);
         if (status != SoundTrigger.STATUS_OK) {
-            Slog.w(TAG, "startRecognition failed with " + status);
+            Slog.w(TAG, "startGenericRecognition failed with " + status);
             // Notify of error if needed.
             if (notify) {
                 try {
@@ -913,6 +977,7 @@
                 }
             }
         } else {
+            Slog.i(TAG, "startRecognition successful.");
             modelData.setStarted();
             // Notify of resume if needed.
             if (notify) {
@@ -923,6 +988,7 @@
                 }
             }
         }
+        if (DBG) dumpGenericModelStateLocked();
         return status;
     }
 
@@ -951,33 +1017,37 @@
                 }
             }
         }
+        if (DBG) dumpGenericModelStateLocked();
         return status;
     }
 
+    private void dumpGenericModelStateLocked() {
+        for (UUID modelId : mGenericModelDataMap.keySet()) {
+            ModelData modelData = mGenericModelDataMap.get(modelId);
+            Slog.i(TAG, "Model :" + modelData.toString());
+        }
+    }
+
     // Computes whether we have any recognition running at all (voice or generic). Sets
     // the mRecognitionRunning variable with the result.
-    private boolean computeRecognitionRunning() {
-        synchronized (mLock) {
-            if (mModuleProperties == null || mModule == null) {
-                mRecognitionRunning = false;
-                return mRecognitionRunning;
-            }
-            if (mKeyphraseListener != null &&
-                    mKeyphraseStarted &&
-                    mCurrentKeyphraseModelHandle != INVALID_VALUE &&
-                    mCurrentSoundModel != null) {
+    private boolean computeRecognitionRunningLocked() {
+        if (mModuleProperties == null || mModule == null) {
+            mRecognitionRunning = false;
+            return mRecognitionRunning;
+        }
+        if (mKeyphraseListener != null && mKeyphraseStarted &&
+            mCurrentKeyphraseModelHandle != INVALID_VALUE && mCurrentSoundModel != null) {
+            mRecognitionRunning = true;
+            return mRecognitionRunning;
+        }
+        for (UUID modelId : mGenericModelDataMap.keySet()) {
+            ModelData modelData = mGenericModelDataMap.get(modelId);
+            if (modelData.isModelStarted()) {
                 mRecognitionRunning = true;
                 return mRecognitionRunning;
             }
-            for (UUID modelId : mGenericModelDataMap.keySet()) {
-                ModelData modelData = mGenericModelDataMap.get(modelId);
-                if (modelData.isModelStarted()) {
-                    mRecognitionRunning = true;
-                    return mRecognitionRunning;
-                }
-            }
-            mRecognitionRunning = false;
         }
+        mRecognitionRunning = false;
         return mRecognitionRunning;
     }
 
@@ -1069,5 +1139,18 @@
         synchronized RecognitionConfig getRecognitionConfig() {
             return mRecognitionConfig;
         }
+
+        String stateToString() {
+            switch(mModelState) {
+                case MODEL_NOTLOADED: return "NOT_LOADED";
+                case MODEL_LOADED: return "LOADED";
+                case MODEL_STARTED: return "STARTED";
+            }
+            return "Unknown state";
+        }
+
+        public String toString() {
+            return "Handle: " + mModelHandle + "ModelState: " + stateToString();
+        }
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
index 7722876..113431f 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -75,5 +75,7 @@
 
     public abstract ModuleProperties getModuleProperties();
 
+    public abstract int unloadKeyphraseModel(int keyphaseId);
+
     public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
 }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 251f314..a4c1210 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -122,10 +122,10 @@
         public int startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback,
                 RecognitionConfig config) {
             enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (!isInitialized()) return STATUS_ERROR;
             if (DEBUG) {
                 Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
             }
-            if (!isInitialized()) return STATUS_ERROR;
 
             GenericSoundModel model = getSoundModel(parcelUuid);
             if (model == null) {
@@ -173,6 +173,8 @@
             if (DEBUG) {
                 Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
             }
+            // Unload the model if it is loaded.
+            mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
             mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
         }
     }
@@ -216,6 +218,12 @@
         }
 
         @Override
+        public int unloadKeyphraseModel(int keyphraseId) {
+            if (!isInitialized()) return STATUS_ERROR;
+            return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!isInitialized()) return;
             mSoundTriggerHelper.dump(fd, pw, args);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 4a54643..837b4a4 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -75,7 +75,7 @@
  */
 public class VoiceInteractionManagerService extends SystemService {
     static final String TAG = "VoiceInteractionManagerService";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     final Context mContext;
     final ContentResolver mResolver;
@@ -760,6 +760,10 @@
             final long caller = Binder.clearCallingIdentity();
             boolean deleted = false;
             try {
+                int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
+                if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
+                    Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
+                }
                 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
                 return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
             } finally {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index de90202..b4c6e6a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -95,6 +95,19 @@
     public static final int STATE_DISCONNECTING = 10;
 
     /**
+     * The state of an external call which is in the process of being pulled from a remote device to
+     * the local device.
+     * <p>
+     * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property
+     * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call.
+     * <p>
+     * An {@link InCallService} will only see this state if it has the
+     * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
+     * manifest.
+     */
+    public static final int STATE_PULLING_CALL = 11;
+
+    /**
      * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
      * extras. Used to pass the phone accounts to display on the front end to the user in order to
      * select phone accounts to (for example) place a call.
@@ -226,8 +239,23 @@
          */
         public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
 
+        /**
+         * When set for an external call, indicates that this {@code Call} can be pulled from a
+         * remote device to the current device.
+         * <p>
+         * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set.
+         * <p>
+         * An {@link InCallService} will only see calls with this capability if it has the
+         * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
+         * in its manifest.
+         * <p>
+         * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
+         * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
+         */
+        public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
+
         //******************************************************************************************
-        // Next CAPABILITY value: 0x00800000
+        // Next CAPABILITY value: 0x01000000
         //******************************************************************************************
 
         /**
@@ -261,8 +289,25 @@
          */
         public static final int PROPERTY_WORK_CALL = 0x00000020;
 
+        /**
+         * When set, indicates that this {@code Call} does not actually exist locally for the
+         * {@link ConnectionService}.
+         * <p>
+         * Consider, for example, a scenario where a user has two phones with the same phone number.
+         * When a user places a call on one device, the telephony stack can represent that call on
+         * the other device by adding it to the {@link ConnectionService} with the
+         * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set.
+         * <p>
+         * An {@link InCallService} will only see calls with this property if it has the
+         * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
+         * in its manifest.
+         * <p>
+         * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
+         */
+        public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
+
         //******************************************************************************************
-        // Next PROPERTY value: 0x00000040
+        // Next PROPERTY value: 0x00000100
         //******************************************************************************************
 
         private final String mTelecomCallId;
@@ -362,6 +407,9 @@
             if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
                 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
             }
+            if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
+                builder.append(" CAPABILITY_CAN_PULL_CALL");
+            }
             builder.append("]");
             return builder.toString();
         }
@@ -411,6 +459,9 @@
             if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
                 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
             }
+            if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) {
+                builder.append(" PROPERTY_IS_EXTERNAL_CALL");
+            }
             builder.append("]");
             return builder.toString();
         }
@@ -624,6 +675,21 @@
                     parcelableCall.getExtras(),
                     parcelableCall.getIntentExtras());
         }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("[pa: ");
+            sb.append(mAccountHandle);
+            sb.append(", hdl: ");
+            sb.append(Log.pii(mHandle));
+            sb.append(", caps: ");
+            sb.append(capabilitiesToString(mCallCapabilities));
+            sb.append(", props: ");
+            sb.append(propertiesToString(mCallProperties));
+            sb.append("]");
+            return sb.toString();
+        }
     }
 
     public static abstract class Callback {
@@ -708,6 +774,17 @@
          *          conferenced.
          */
         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
+
+        /**
+         * Invoked when a call receives an event from its associated {@link Connection}.
+         * <p>
+         * See {@link Connection#sendConnectionEvent(String, Bundle)}.
+         *
+         * @param call The {@code Call} receiving the event.
+         * @param event The event.
+         * @param extras Extras associated with the connection event.
+         */
+        public void onConnectionEvent(Call call, String event, Bundle extras) {}
     }
 
     /**
@@ -736,6 +813,7 @@
     private String mRemainingPostDialSequence;
     private VideoCallImpl mVideoCallImpl;
     private Details mDetails;
+    private Bundle mExtras;
 
     /**
      * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
@@ -874,6 +952,126 @@
     }
 
     /**
+     * Initiates a request to the {@link ConnectionService} to pull an external call to the local
+     * device.
+     * <p>
+     * Calls to this method are ignored if the call does not have the
+     * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set.
+     * <p>
+     * An {@link InCallService} will only see calls which support this method if it has the
+     * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
+     * in its manifest.
+     */
+    public void pullExternalCall() {
+        // If this isn't an external call, ignore the request.
+        if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) {
+            return;
+        }
+
+        mInCallAdapter.pullExternalCall(mTelecomCallId);
+    }
+
+    /**
+     * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in
+     * the {@link ConnectionService}.
+     * <p>
+     * Events are exposed to {@link ConnectionService} implementations via
+     * {@link android.telecom.Connection#onCallEvent(String, Bundle)}.
+     * <p>
+     * No assumptions should be made as to how a {@link ConnectionService} will handle these events.
+     * Events should be fully qualified (e.g., com.example.event.MY_EVENT) to avoid conflicts.
+     *
+     * @param event The connection event.
+     * @param extras Bundle containing extra information associated with the event.
+     */
+    public void sendCallEvent(String event, Bundle extras) {
+        mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
+    }
+
+    /**
+     * Adds some extras to this {@link Call}.  Existing keys are replaced and new ones are
+     * added.
+     * <p>
+     * No assumptions should be made as to how an In-Call UI or service will handle these
+     * extras.  Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+     *
+     * @param extras The extras to add.
+     */
+    public final void putExtras(Bundle extras) {
+        if (extras == null) {
+            return;
+        }
+
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putAll(extras);
+        mInCallAdapter.putExtras(mTelecomCallId, extras);
+    }
+
+    /**
+     * Adds a boolean extra to this {@link Call}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, boolean value) {
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putBoolean(key, value);
+        mInCallAdapter.putExtra(mTelecomCallId, key, value);
+    }
+
+    /**
+     * Adds an integer extra to this {@code Connection}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, int value) {
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putInt(key, value);
+        mInCallAdapter.putExtra(mTelecomCallId, key, value);
+    }
+
+    /**
+     * Adds a string extra to this {@code Connection}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, String value) {
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putString(key, value);
+        mInCallAdapter.putExtra(mTelecomCallId, key, value);
+    }
+
+    /**
+     * Removes extras from this {@code Connection}.
+     *
+     * @param keys The keys of the extras to remove.
+     */
+    public final void removeExtras(List<String> keys) {
+        if (mExtras != null) {
+            for (String key : keys) {
+                mExtras.remove(key);
+            }
+            if (mExtras.size() == 0) {
+                mExtras = null;
+            }
+        }
+        mInCallAdapter.removeExtras(mTelecomCallId, keys);
+    }
+
+    /**
      * Obtains the parent of this {@code Call} in a conference, if any.
      *
      * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
@@ -1000,6 +1198,48 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return new StringBuilder().
+                append("Call [id: ").
+                append(mTelecomCallId).
+                append(", state: ").
+                append(stateToString(mState)).
+                append(", details: ").
+                append(mDetails).
+                append("]").toString();
+    }
+
+    /**
+     * @param state An integer value of a {@code STATE_*} constant.
+     * @return A string representation of the value.
+     */
+    private static String stateToString(int state) {
+        switch (state) {
+            case STATE_NEW:
+                return "NEW";
+            case STATE_RINGING:
+                return "RINGING";
+            case STATE_DIALING:
+                return "DIALING";
+            case STATE_ACTIVE:
+                return "ACTIVE";
+            case STATE_HOLDING:
+                return "HOLDING";
+            case STATE_DISCONNECTED:
+                return "DISCONNECTED";
+            case STATE_CONNECTING:
+                return "CONNECTING";
+            case STATE_DISCONNECTING:
+                return "DISCONNECTING";
+            case STATE_SELECT_PHONE_ACCOUNT:
+                return "SELECT_PHONE_ACCOUNT";
+            default:
+                Log.w(Call.class, "Unknown state %d", state);
+                return "UNKNOWN";
+        }
+    }
+
     /**
      * Adds a listener to this {@code Call}.
      *
@@ -1154,6 +1394,11 @@
         }
     }
 
+    /** {@hide} */
+    final void internalOnConnectionEvent(String event, Bundle extras) {
+        fireOnConnectionEvent(event, extras);
+    }
+
     private void fireStateChanged(final int newState) {
         for (CallbackRecord<Callback> record : mCallbackRecords) {
             final Call call = this;
@@ -1301,6 +1546,27 @@
     }
 
     /**
+     * Notifies listeners of an incoming connection event.
+     * <p>
+     * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}.
+     *
+     * @param event
+     * @param extras
+     */
+    private void fireOnConnectionEvent(final String event, final Bundle extras) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onConnectionEvent(call, event, extras);
+                }
+            });
+        }
+    }
+
+    /**
      * Determines if two bundles are equal.
      *
      * @param bundle The original bundle.
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 094b3a9..1ce4ade 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -16,10 +16,12 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Bundle;
 import android.telecom.Connection.VideoProvider;
+import android.util.ArraySet;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -51,10 +53,13 @@
         public void onDestroyed(Conference conference) {}
         public void onConnectionCapabilitiesChanged(
                 Conference conference, int connectionCapabilities) {}
+        public void onConnectionPropertiesChanged(
+                Conference conference, int connectionProperties) {}
         public void onVideoStateChanged(Conference c, int videoState) { }
         public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {}
         public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {}
-        public void onExtrasChanged(Conference conference, Bundle extras) {}
+        public void onExtrasChanged(Conference c, Bundle extras) {}
+        public void onExtrasRemoved(Conference c, List<String> keys) {}
     }
 
     private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
@@ -71,10 +76,12 @@
     private int mState = Connection.STATE_NEW;
     private DisconnectCause mDisconnectCause;
     private int mConnectionCapabilities;
+    private int mConnectionProperties;
     private String mDisconnectMessage;
     private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
     private StatusHints mStatusHints;
     private Bundle mExtras;
+    private Set<String> mPreviousExtraKeys;
 
     private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
         @Override
@@ -152,6 +159,16 @@
     }
 
     /**
+     * Returns the properties of the conference. See {@code PROPERTY_*} constants in class
+     * {@link Connection} for valid values.
+     *
+     * @return A bitmask of the properties of the conference call.
+     */
+    public final int getConnectionProperties() {
+        return mConnectionProperties;
+    }
+
+    /**
      * Whether the given capabilities support the specified capability.
      *
      * @param capabilities A capability bit field.
@@ -181,7 +198,10 @@
      * @hide
      */
     public void removeCapability(int capability) {
-        mConnectionCapabilities &= ~capability;
+        int newCapabilities = mConnectionCapabilities;
+        newCapabilities &= ~capability;
+
+        setConnectionCapabilities(newCapabilities);
     }
 
     /**
@@ -191,7 +211,10 @@
      * @hide
      */
     public void addCapability(int capability) {
-        mConnectionCapabilities |= capability;
+        int newCapabilities = mConnectionCapabilities;
+        newCapabilities |= capability;
+
+        setConnectionCapabilities(newCapabilities);
     }
 
     /**
@@ -354,7 +377,7 @@
      * Sets the capabilities of a conference. See {@code CAPABILITY_*} constants of class
      * {@link Connection} for valid values.
      *
-     * @param connectionCapabilities A bitmask of the {@code PhoneCapabilities} of the conference call.
+     * @param connectionCapabilities A bitmask of the {@code Capabilities} of the conference call.
      */
     public final void setConnectionCapabilities(int connectionCapabilities) {
         if (connectionCapabilities != mConnectionCapabilities) {
@@ -367,6 +390,22 @@
     }
 
     /**
+     * Sets the properties of a conference. See {@code PROPERTY_*} constants of class
+     * {@link Connection} for valid values.
+     *
+     * @param connectionProperties A bitmask of the {@code Properties} of the conference call.
+     */
+    public final void setConnectionProperties(int connectionProperties) {
+        if (connectionProperties != mConnectionProperties) {
+            mConnectionProperties = connectionProperties;
+
+            for (Listener l : mListeners) {
+                l.onConnectionPropertiesChanged(this, mConnectionProperties);
+            }
+        }
+    }
+
+    /**
      * Adds the specified connection as a child of this conference.
      *
      * @param connection The connection to add.
@@ -634,23 +673,173 @@
     }
 
     /**
-     * Set some extras that can be associated with this {@code Conference}. No assumptions should
-     * be made as to how an In-Call UI or service will handle these extras.
+     * Replaces all the extras associated with this {@code Conference}.
+     * <p>
+     * New or existing keys are replaced in the {@code Conference} extras.  Keys which are no longer
+     * in the new extras, but were present the last time {@code setExtras} was called are removed.
+     * <p>
+     * No assumptions should be made as to how an In-Call UI or service will handle these extras.
      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
      *
-     * @param extras The extras associated with this {@code Connection}.
+     * @param extras The extras associated with this {@code Conference}.
+     * @deprecated Use {@link #putExtras(Bundle)} to add extras.  Use {@link #removeExtras(List)}
+     * to remove extras.
      */
     public final void setExtras(@Nullable Bundle extras) {
-        mExtras = extras;
+        // Add/replace any new or changed extras values.
+        putExtras(extras);
+
+        // If we have used "setExtras" in the past, compare the key set from the last invocation to
+        // the current one and remove any keys that went away.
+        if (mPreviousExtraKeys != null) {
+            List<String> toRemove = new ArrayList<String>();
+            for (String oldKey : mPreviousExtraKeys) {
+                if (extras == null || !extras.containsKey(oldKey)) {
+                    toRemove.add(oldKey);
+                }
+            }
+
+            if (!toRemove.isEmpty()) {
+                removeExtras(toRemove);
+            }
+        }
+
+        // Track the keys the last time set called setExtras.  This way, the next time setExtras is
+        // called we can see if the caller has removed any extras values.
+        if (mPreviousExtraKeys == null) {
+            mPreviousExtraKeys = new ArraySet<String>();
+        }
+        mPreviousExtraKeys.clear();
+        if (extras != null) {
+            mPreviousExtraKeys.addAll(extras.keySet());
+        }
+    }
+
+    /**
+     * Adds some extras to this {@link Conference}.  Existing keys are replaced and new ones are
+     * added.
+     * <p>
+     * No assumptions should be made as to how an In-Call UI or service will handle these extras.
+     * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+     *
+     * @param extras The extras to add.
+     */
+    public final void putExtras(@NonNull Bundle extras) {
+        if (extras == null) {
+            return;
+        }
+
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putAll(extras);
+
         for (Listener l : mListeners) {
             l.onExtrasChanged(this, extras);
         }
     }
 
     /**
-     * @return The extras associated with this conference.
+     * Adds a boolean extra to this {@link Conference}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, boolean value) {
+        Bundle newExtras = new Bundle();
+        newExtras.putBoolean(key, value);
+        putExtras(newExtras);
+    }
+
+    /**
+     * Adds an integer extra to this {@link Conference}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, int value) {
+        Bundle newExtras = new Bundle();
+        newExtras.putInt(key, value);
+        putExtras(newExtras);
+    }
+
+    /**
+     * Adds a string extra to this {@link Conference}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, String value) {
+        Bundle newExtras = new Bundle();
+        newExtras.putString(key, value);
+        putExtras(newExtras);
+    }
+
+    /**
+     * Removes an extra from this {@link Conference}.
+     *
+     * @param keys The key of the extra key to remove.
+     */
+    public final void removeExtras(List<String> keys) {
+        if (keys == null || keys.isEmpty()) {
+            return;
+        }
+
+        if (mExtras != null) {
+            for (String key : keys) {
+                mExtras.remove(key);
+            }
+            if (mExtras.size() == 0) {
+                mExtras = null;
+            }
+        }
+
+        for (Listener l : mListeners) {
+            l.onExtrasRemoved(this, keys);
+        }
+    }
+
+    /**
+     * Returns the extras associated with this conference.
+     * <p>
+     * Extras should be updated using {@link #putExtras(Bundle)} and {@link #removeExtras(List)}.
+     * <p>
+     * Telecom or an {@link InCallService} can also update the extras via
+     * {@link android.telecom.Call#putExtras(Bundle)}, and
+     * {@link Call#removeExtras(List)}.
+     * <p>
+     * The conference is notified of changes to the extras made by Telecom or an
+     * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
+     *
+     * @return The extras associated with this connection.
      */
     public final Bundle getExtras() {
         return mExtras;
     }
+
+    /**
+     * Notifies this {@link Conference} of a change to the extras made outside the
+     * {@link ConnectionService}.
+     * <p>
+     * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
+     * {@link android.telecom.Call#putExtras(Bundle)}, and
+     * {@link Call#removeExtras(List)}.
+     *
+     * @param extras The new extras bundle.
+     */
+    public void onExtrasChanged(Bundle extras) {}
+
+    /**
+     * Handles a change to extras received from Telecom.
+     *
+     * @param extras The new extras.
+     * @hide
+     */
+    final void handleExtrasChanged(Bundle extras) {
+        mExtras = extras;
+        onExtrasChanged(mExtras);
+    }
 }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fa7a59d..d83cdb8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -20,6 +20,7 @@
 import com.android.internal.telecom.IVideoCallback;
 import com.android.internal.telecom.IVideoProvider;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.hardware.camera2.CameraManager;
@@ -30,6 +31,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.view.Surface;
 
 import java.util.ArrayList;
@@ -93,6 +95,15 @@
     public static final int STATE_DISCONNECTED = 6;
 
     /**
+     * The state of an external connection which is in the process of being pulled from a remote
+     * device to the local device.
+     * <p>
+     * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and
+     * {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection.
+     */
+    public static final int STATE_PULLING_CALL = 7;
+
+    /**
      * Connection can currently be put on hold or unheld. This is distinct from
      * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
      * it does not at the moment support the function. This can be true while the call is in the
@@ -183,31 +194,28 @@
     public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
 
     /**
-     * Whether the call is a generic conference, where we do not know the precise state of
-     * participants in the conference (eg. on CDMA).
-     *
+     * Un-used.
      * @hide
      */
-    public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
+    public static final int CAPABILITY_UNUSED_2 = 0x00004000;
 
     /**
-     * Connection is using high definition audio.
+     * Un-used.
      * @hide
      */
-    public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
+    public static final int CAPABILITY_UNUSED_3 = 0x00008000;
 
     /**
-     * Connection is using WIFI.
+     * Un-used.
      * @hide
      */
-    public static final int CAPABILITY_WIFI = 0x00010000;
+    public static final int CAPABILITY_UNUSED_4 = 0x00010000;
 
     /**
-     * Indicates that the current device callback number should be shown.
-     *
+     * Un-used.
      * @hide
      */
-    public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
+    public static final int CAPABILITY_UNUSED_5 = 0x00020000;
 
     /**
      * Speed up audio setup for MT call.
@@ -251,7 +259,6 @@
     /**
      * Indicates that the connection itself wants to handle any sort of reply response, rather than
      * relying on SMS.
-     * @hide
      */
     public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
 
@@ -270,8 +277,65 @@
      */
     public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
 
+    /**
+     * When set for an external connection, indicates that this {@code Connection} can be pulled
+     * from a remote device to the current device.
+     * <p>
+     * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL}
+     * is set.
+     */
+    public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x01000000
+    // Next CAPABILITY value: 0x02000000
+    //**********************************************************************************************
+
+    /**
+     * Indicates that the current device callback number should be shown.
+     *
+     * @hide
+     */
+    public static final int PROPERTY_SHOW_CALLBACK_NUMBER = 1<<0;
+
+    /**
+     * Whether the call is a generic conference, where we do not know the precise state of
+     * participants in the conference (eg. on CDMA).
+     *
+     * @hide
+     */
+    public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1;
+
+    /**
+     * Connection is using high definition audio.
+     * @hide
+     */
+    public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
+
+    /**
+     * Connection is using WIFI.
+     * @hide
+     */
+    public static final int PROPERTY_WIFI = 1<<3;
+
+    /**
+     * When set, indicates that the {@code Connection} does not actually exist locally for the
+     * {@link ConnectionService}.
+     * <p>
+     * Consider, for example, a scenario where a user has two devices with the same phone number.
+     * When a user places a call on one devices, the telephony stack can represent that call on the
+     * other device by adding is to the {@link ConnectionService} with the
+     * {@link #PROPERTY_IS_EXTERNAL_CALL} capability set.
+     * <p>
+     * An {@link ConnectionService} should not assume that all {@link InCallService}s will handle
+     * external connections.  Only those {@link InCallService}s which have the
+     * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
+     * manifest will see external connections.
+     */
+    public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4;
+
+
+    //**********************************************************************************************
+    // Next PROPERTY value: 1<<5
     //**********************************************************************************************
 
     /**
@@ -297,6 +361,36 @@
      */
     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
 
+    /**
+     * Connection event used to inform Telecom that it should play the on hold tone.  This is used
+     * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
+     * {@link #sendConnectionEvent(String)}.
+     * @hide
+     */
+    public static final String EVENT_ON_HOLD_TONE_START =
+            "android.telecom.event.ON_HOLD_TONE_START";
+
+    /**
+     * Connection event used to inform Telecom that it should stop the on hold tone.  This is used
+     * to stop a tone when the peer puts the current call on hold.  Sent to Telecom via
+     * {@link #sendConnectionEvent(String)}.
+     * @hide
+     */
+    public static final String EVENT_ON_HOLD_TONE_END =
+            "android.telecom.event.ON_HOLD_TONE_END";
+
+    /**
+     * Connection event used to inform {@link InCallService}s when pulling of an external call has
+     * failed.  The user interface should inform the user of the error.
+     * <p>
+     * Expected to be used by the {@link ConnectionService} when the {@link Call#pullExternalCall()}
+     * API is called on a {@link Call} with the properties
+     * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} and
+     * {@link Call.Details#CAPABILITY_CAN_PULL_CALL}, but the {@link ConnectionService} could not
+     * pull the external call due to an error condition.
+     */
+    public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
@@ -389,18 +483,6 @@
         if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
             builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
         }
-        if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
-            builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
-        }
-        if (can(capabilities, CAPABILITY_WIFI)) {
-            builder.append(" CAPABILITY_WIFI");
-        }
-        if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
-            builder.append(" CAPABILITY_GENERIC_CONFERENCE");
-        }
-        if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
-            builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
-        }
         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
             builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
         }
@@ -416,6 +498,37 @@
         if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
             builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
         }
+        if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
+            builder.append(" CAPABILITY_CAN_PULL_CALL");
+        }
+
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public static String propertiesToString(int properties) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[Properties:");
+
+        if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) {
+            builder.append(" PROPERTY_SHOW_CALLBACK_NUMBER");
+        }
+
+        if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
+            builder.append(" PROPERTY_HIGH_DEF_AUDIO");
+        }
+
+        if (can(properties, PROPERTY_WIFI)) {
+            builder.append(" PROPERTY_WIFI");
+        }
+
+        if (can(properties, PROPERTY_GENERIC_CONFERENCE)) {
+            builder.append(" PROPERTY_GENERIC_CONFERENCE");
+        }
+
+        if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) {
+            builder.append(" PROPERTY_IS_EXTERNAL_CALL");
+        }
 
         builder.append("]");
         return builder.toString();
@@ -434,6 +547,7 @@
         public void onRingbackRequested(Connection c, boolean ringback) {}
         public void onDestroyed(Connection c) {}
         public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
+        public void onConnectionPropertiesChanged(Connection c, int properties) {}
         public void onVideoProviderChanged(
                 Connection c, VideoProvider videoProvider) {}
         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
@@ -447,6 +561,8 @@
         public void onConferenceStarted() {}
         public void onConferenceMergeFailed(Connection c) {}
         public void onExtrasChanged(Connection c, Bundle extras) {}
+        public void onExtrasRemoved(Connection c, List<String> keys) {}
+        public void onConnectionEvent(Connection c, String event, Bundle extras) {}
     }
 
     /**
@@ -1102,6 +1218,7 @@
     private int mCallerDisplayNamePresentation;
     private boolean mRingbackRequested = false;
     private int mConnectionCapabilities;
+    private int mConnectionProperties;
     private VideoProvider mVideoProvider;
     private boolean mAudioModeIsVoip;
     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
@@ -1113,6 +1230,13 @@
     private Bundle mExtras;
 
     /**
+     * Tracks the key set for the extras bundle provided on the last invocation of
+     * {@link #setExtras(Bundle)}.  Used so that on subsequent invocations we can remove any extras
+     * keys which were set previously but are no longer present in the replacement Bundle.
+     */
+    private Set<String> mPreviousExtraKeys;
+
+    /**
      * Create a new Connection.
      */
     public Connection() {}
@@ -1248,6 +1372,17 @@
     }
 
     /**
+     * Returns the extras associated with this connection.
+     * <p>
+     * Extras should be updated using {@link #putExtras(Bundle)}.
+     * <p>
+     * Telecom or an {@link InCallService} can also update the extras via
+     * {@link android.telecom.Call#putExtras(Bundle)}, and
+     * {@link Call#removeExtras(List)}.
+     * <p>
+     * The connection is notified of changes to the extras made by Telecom or an
+     * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
+     *
      * @return The extras associated with this connection.
      */
     public final Bundle getExtras() {
@@ -1348,6 +1483,13 @@
     }
 
     /**
+     * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants.
+     */
+    public final int getConnectionProperties() {
+        return mConnectionProperties;
+    }
+
+    /**
      * Sets the value of the {@link #getAddress()} property.
      *
      * @param address The new address.
@@ -1544,6 +1686,21 @@
     }
 
     /**
+     * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants.
+     *
+     * @param connectionProperties The new connection properties.
+     */
+    public final void setConnectionProperties(int connectionProperties) {
+        checkImmutable();
+        if (mConnectionProperties != connectionProperties) {
+            mConnectionProperties = connectionProperties;
+            for (Listener l : mListeners) {
+                l.onConnectionPropertiesChanged(this, mConnectionProperties);
+            }
+        }
+    }
+
+    /**
      * Tears down the Connection object.
      */
     public final void destroy() {
@@ -1707,21 +1864,135 @@
     }
 
     /**
-     * Set some extras that can be associated with this {@code Connection}. No assumptions should
-     * be made as to how an In-Call UI or service will handle these extras.
+     * Set some extras that can be associated with this {@code Connection}.
+     * <p>
+     * New or existing keys are replaced in the {@code Connection} extras.  Keys which are no longer
+     * in the new extras, but were present the last time {@code setExtras} was called are removed.
+     * <p>
+     * No assumptions should be made as to how an In-Call UI or service will handle these extras.
      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
      *
      * @param extras The extras associated with this {@code Connection}.
+     * @deprecated Use {@link #putExtras(Bundle)} to add extras.  Use {@link #removeExtras(List)}
+     * to remove extras.
      */
     public final void setExtras(@Nullable Bundle extras) {
         checkImmutable();
-        mExtras = extras;
+
+        // Add/replace any new or changed extras values.
+        putExtras(extras);
+
+        // If we have used "setExtras" in the past, compare the key set from the last invocation to
+        // the current one and remove any keys that went away.
+        if (mPreviousExtraKeys != null) {
+            List<String> toRemove = new ArrayList<String>();
+            for (String oldKey : mPreviousExtraKeys) {
+                if (extras == null || !extras.containsKey(oldKey)) {
+                    toRemove.add(oldKey);
+                }
+            }
+            if (!toRemove.isEmpty()) {
+                removeExtras(toRemove);
+            }
+        }
+
+        // Track the keys the last time set called setExtras.  This way, the next time setExtras is
+        // called we can see if the caller has removed any extras values.
+        if (mPreviousExtraKeys == null) {
+            mPreviousExtraKeys = new ArraySet<String>();
+        }
+        mPreviousExtraKeys.clear();
+        if (extras != null) {
+            mPreviousExtraKeys.addAll(extras.keySet());
+        }
+    }
+
+    /**
+     * Adds some extras to this {@code Connection}.  Existing keys are replaced and new ones are
+     * added.
+     * <p>
+     * No assumptions should be made as to how an In-Call UI or service will handle these extras.
+     * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+     *
+     * @param extras The extras to add.
+     */
+    public final void putExtras(@NonNull Bundle extras) {
+        checkImmutable();
+        if (extras == null) {
+            return;
+        }
+
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putAll(extras);
+
         for (Listener l : mListeners) {
             l.onExtrasChanged(this, extras);
         }
     }
 
     /**
+     * Adds a boolean extra to this {@code Connection}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, boolean value) {
+        Bundle newExtras = new Bundle();
+        newExtras.putBoolean(key, value);
+        putExtras(newExtras);
+    }
+
+    /**
+     * Adds an integer extra to this {@code Connection}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, int value) {
+        Bundle newExtras = new Bundle();
+        newExtras.putInt(key, value);
+        putExtras(newExtras);
+    }
+
+    /**
+     * Adds a string extra to this {@code Connection}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(String key, String value) {
+        Bundle newExtras = new Bundle();
+        newExtras.putString(key, value);
+        putExtras(newExtras);
+    }
+
+    /**
+     * Removes an extra from this {@code Connection}.
+     *
+     * @param keys The key of the extra key to remove.
+     */
+    public final void removeExtras(List<String> keys) {
+        if (mExtras != null) {
+            for (String key : keys) {
+                mExtras.remove(key);
+            }
+
+            if (mExtras.size() == 0) {
+                mExtras = null;
+            }
+        }
+
+        for (Listener l : mListeners) {
+            l.onExtrasRemoved(this, keys);
+        }
+    }
+
+    /**
      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
      *
      * @param state The new connection audio state.
@@ -1816,9 +2087,8 @@
     public void onReject() {}
 
     /**
-     * Notifies ths Connection of a request reject with a message.
-     *
-     * @hide
+     * Notifies this Connection, which is in {@link #STATE_RINGING}, of
+     * a request to reject with a message.
      */
     public void onReject(String replyMessage) {}
 
@@ -1834,6 +2104,43 @@
      */
     public void onPostDialContinue(boolean proceed) {}
 
+    /**
+     * Notifies this Connection of a request to pull an external call to the local device.
+     * <p>
+     * The {@link InCallService} issues a request to pull an external call to the local device via
+     * {@link Call#pullExternalCall()}.
+     * <p>
+     * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL}
+     * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set.
+     * <p>
+     * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
+     */
+    public void onPullExternalCall() {}
+
+    /**
+     * Notifies this Connection of a {@link Call} event initiated from an {@link InCallService}.
+     * <p>
+     * The {@link InCallService} issues a Call event via {@link Call#sendCallEvent(String, Bundle)}.
+     * <p>
+     * See also {@link Call#sendCallEvent(String, Bundle)}.
+     *
+     * @param event The call event.
+     * @param extras Extras associated with the call event.
+     */
+    public void onCallEvent(String event, Bundle extras) {}
+
+    /**
+     * Notifies this {@link Connection} of a change to the extras made outside the
+     * {@link ConnectionService}.
+     * <p>
+     * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
+     * the {@link android.telecom.Call#putExtras(Bundle)} and
+     * {@link Call#removeExtras(List)}.
+     *
+     * @param extras The new extras bundle.
+     */
+    public void onExtrasChanged(Bundle extras) {}
+
     static String toLogSafePhoneNumber(String number) {
         // For unknown number, log empty string.
         if (number == null) {
@@ -1954,6 +2261,17 @@
     }
 
     /**
+     * Handles a change to extras received from Telecom.
+     *
+     * @param extras The new extras.
+     * @hide
+     */
+    final void handleExtrasChanged(Bundle extras) {
+        mExtras = extras;
+        onExtrasChanged(mExtras);
+    }
+
+    /**
      * Notifies listeners that the merge request failed.
      *
      * @hide
@@ -1986,4 +2304,22 @@
             l.onConferenceStarted();
         }
     }
+
+    /**
+     * Sends an event associated with this {@code Connection}, with associated event extras.
+     *
+     * Events are exposed to {@link InCallService} implementations via the
+     * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)} API.
+     *
+     * No assumptions should be made as to how an In-Call UI or service will handle these events.
+     * Events should be fully qualified (e.g., com.example.event.MY_EVENT) to avoid conflicts.
+     *
+     * @param event The connection event.
+     * @param extras Bundle containing extra information associated with the event.
+     */
+    public void sendConnectionEvent(String event, Bundle extras) {
+        for (Listener l : mListeners) {
+            l.onConnectionEvent(this, event, extras);
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index b4a7ce0..4cab7f0 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -103,6 +103,9 @@
     private static final int MSG_SWAP_CONFERENCE = 19;
     private static final int MSG_REJECT_WITH_MESSAGE = 20;
     private static final int MSG_SILENCE = 21;
+    private static final int MSG_PULL_EXTERNAL_CALL = 22;
+    private static final int MSG_SEND_CALL_EVENT = 23;
+    private static final int MSG_ON_EXTRAS_CHANGED = 24;
 
     private static Connection sNullConnection;
 
@@ -245,6 +248,28 @@
             args.argi1 = proceed ? 1 : 0;
             mHandler.obtainMessage(MSG_ON_POST_DIAL_CONTINUE, args).sendToTarget();
         }
+
+        @Override
+        public void pullExternalCall(String callId) {
+            mHandler.obtainMessage(MSG_PULL_EXTERNAL_CALL, callId).sendToTarget();
+        }
+
+        @Override
+        public void sendCallEvent(String callId, String event, Bundle extras) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = event;
+            args.arg3 = extras;
+            mHandler.obtainMessage(MSG_SEND_CALL_EVENT, args).sendToTarget();
+        }
+
+        @Override
+        public void onExtrasChanged(String callId, Bundle extras) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = extras;
+            mHandler.obtainMessage(MSG_ON_EXTRAS_CHANGED, args).sendToTarget();
+        }
     };
 
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -382,6 +407,33 @@
                     }
                     break;
                 }
+                case MSG_PULL_EXTERNAL_CALL: {
+                    pullExternalCall((String) msg.obj);
+                    break;
+                }
+                case MSG_SEND_CALL_EVENT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        String callId = (String) args.arg1;
+                        String event = (String) args.arg2;
+                        Bundle extras = (Bundle) args.arg3;
+                        sendCallEvent(callId, event, extras);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_ON_EXTRAS_CHANGED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        String callId = (String) args.arg1;
+                        Bundle extras = (Bundle) args.arg2;
+                        handleExtrasChanged(callId, extras);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
                 default:
                     break;
             }
@@ -443,6 +495,16 @@
         }
 
         @Override
+        public void onConnectionPropertiesChanged(
+                Conference conference,
+                int connectionProperties) {
+            String id = mIdByConference.get(conference);
+            Log.d(this, "call capabilities: conference: %s",
+                    Connection.propertiesToString(connectionProperties));
+            mAdapter.setConnectionProperties(id, connectionProperties);
+        }
+
+        @Override
         public void onVideoStateChanged(Conference c, int videoState) {
             String id = mIdByConference.get(c);
             Log.d(this, "onVideoStateChanged set video state %d", videoState);
@@ -460,13 +522,25 @@
         @Override
         public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {
             String id = mIdByConference.get(conference);
-            mAdapter.setStatusHints(id, statusHints);
+            if (id != null) {
+                mAdapter.setStatusHints(id, statusHints);
+            }
         }
 
         @Override
-        public void onExtrasChanged(Conference conference, Bundle extras) {
-            String id = mIdByConference.get(conference);
-            mAdapter.setExtras(id, extras);
+        public void onExtrasChanged(Conference c, Bundle extras) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.putExtras(id, extras);
+            }
+        }
+
+        @Override
+        public void onExtrasRemoved(Conference c, List<String> keys) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.removeExtras(id, keys);
+            }
         }
     };
 
@@ -559,6 +633,14 @@
         }
 
         @Override
+        public void onConnectionPropertiesChanged(Connection c, int properties) {
+            String id = mIdByConnection.get(c);
+            Log.d(this, "properties: parcelableconnection: %s",
+                    Connection.propertiesToString(properties));
+            mAdapter.setConnectionProperties(id, properties);
+        }
+
+        @Override
         public void onVideoProviderChanged(Connection c, Connection.VideoProvider videoProvider) {
             String id = mIdByConnection.get(c);
             Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
@@ -607,10 +689,26 @@
         }
 
         @Override
-        public void onExtrasChanged(Connection connection, Bundle extras) {
+        public void onExtrasChanged(Connection c, Bundle extras) {
+            String id = mIdByConnection.get(c);
+            if (id != null) {
+                mAdapter.putExtras(id, extras);
+            }
+        }
+        
+        public void onExtrasRemoved(Connection c, List<String> keys) {
+            String id = mIdByConnection.get(c);
+            if (id != null) {
+                mAdapter.removeExtras(id, keys);
+            }
+        }
+
+
+        @Override
+        public void onConnectionEvent(Connection connection, String event, Bundle extras) {
             String id = mIdByConnection.get(connection);
             if (id != null) {
-                mAdapter.setExtras(id, extras);
+                mAdapter.onConnectionEvent(id, event, extras);
             }
         }
     };
@@ -660,10 +758,11 @@
 
         Uri address = connection.getAddress();
         String number = address == null ? "null" : address.getSchemeSpecificPart();
-        Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s",
+        Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: %s",
                 Connection.toLogSafePhoneNumber(number),
                 Connection.stateToString(connection.getState()),
-                Connection.capabilitiesToString(connection.getConnectionCapabilities()));
+                Connection.capabilitiesToString(connection.getConnectionCapabilities()),
+                Connection.propertiesToString(connection.getConnectionProperties()));
 
         Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
         mAdapter.handleCreateConnectionComplete(
@@ -673,6 +772,7 @@
                         request.getAccountHandle(),
                         connection.getState(),
                         connection.getConnectionCapabilities(),
+                        connection.getConnectionProperties(),
                         connection.getAddress(),
                         connection.getAddressPresentation(),
                         connection.getCallerDisplayName(),
@@ -856,6 +956,60 @@
         }
     }
 
+    /**
+     * Notifies a {@link Connection} of a request to pull an external call.
+     *
+     * See {@link Call#pullExternalCall()}.
+     *
+     * @param callId The ID of the call to pull.
+     */
+    private void pullExternalCall(String callId) {
+        Log.d(this, "pullExternalCall(%s)", callId);
+        Connection connection = findConnectionForAction(callId, "pullExternalCall");
+        if (connection != null) {
+            connection.onPullExternalCall();
+        }
+    }
+
+    /**
+     * Notifies a {@link Connection} of a call event.
+     *
+     * See {@link Call#sendCallEvent(String, Bundle)}.
+     *
+     * @param callId The ID of the call receiving the event.
+     * @param event The event.
+     * @param extras Extras associated with the event.
+     */
+    private void sendCallEvent(String callId, String event, Bundle extras) {
+        Log.d(this, "sendCallEvent(%s, %s)", callId, event);
+        Connection connection = findConnectionForAction(callId, "sendCallEvent");
+        if (connection != null) {
+            connection.onCallEvent(event, extras);
+        }
+
+    }
+
+    /**
+     * Notifies a {@link Connection} or {@link Conference} of a change to the extras from Telecom.
+     * <p>
+     * These extra changes can originate from Telecom itself, or from an {@link InCallService} via
+     * the {@link android.telecom.Call#putExtra(String, boolean)},
+     * {@link android.telecom.Call#putExtra(String, int)},
+     * {@link android.telecom.Call#putExtra(String, String)},
+     * {@link Call#removeExtras(List)}.
+     *
+     * @param callId The ID of the call receiving the event.
+     * @param extras The new extras bundle.
+     */
+    private void handleExtrasChanged(String callId, Bundle extras) {
+        Log.d(this, "handleExtrasChanged(%s, %s)", callId, extras);
+        if (mConnectionById.containsKey(callId)) {
+            findConnectionForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
+        } else if (mConferenceById.containsKey(callId)) {
+            findConferenceForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
+        }
+    }
+
     private void onPostDialContinue(String callId, boolean proceed) {
         Log.d(this, "onPostDialContinue(%s)", callId);
         findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
@@ -976,6 +1130,7 @@
                     conference.getPhoneAccountHandle(),
                     conference.getState(),
                     conference.getConnectionCapabilities(),
+                    conference.getConnectionProperties(),
                     connectionIds,
                     conference.getVideoProvider() == null ?
                             null : conference.getVideoProvider().getInterface(),
@@ -1016,6 +1171,7 @@
                     phoneAccountHandle,
                     connection.getState(),
                     connection.getConnectionCapabilities(),
+                    connection.getConnectionProperties(),
                     connection.getAddress(),
                     connection.getAddressPresentation(),
                     connection.getCallerDisplayName(),
@@ -1045,6 +1201,16 @@
     }
 
     /**
+     * Returns all the active {@code Conference}s for which this {@code ConnectionService}
+     * has taken responsibility.
+     *
+     * @return A collection of {@code Conference}s created by this {@code ConnectionService}.
+     */
+    public final Collection<Conference> getAllConferences() {
+        return mConferenceById.values();
+    }
+
+    /**
      * Create a {@code Connection} given an incoming request. This is used to attach to existing
      * incoming calls.
      *
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 4562514..c8cd3c0 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -196,6 +196,15 @@
         }
     }
 
+    void setConnectionProperties(String callId, int properties) {
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                adapter.setConnectionProperties(callId, properties);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
     /**
      * Indicates whether or not the specified call is currently conferenced into the specified
      * conference call.
@@ -398,16 +407,105 @@
     }
 
     /**
-     * Sets extras associated with a connection.
+     * Adds some extras associated with a {@code Connection}.
      *
      * @param callId The unique ID of the call.
-     * @param extras The extras to associate with this call.
+     * @param extras The extras to add.
      */
-    void setExtras(String callId, Bundle extras) {
-        Log.v(this, "setExtras: %s", extras);
+    void putExtras(String callId, Bundle extras) {
+        Log.v(this, "putExtras: %s", callId);
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
-                adapter.setExtras(callId, extras);
+                adapter.putExtras(callId, extras);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /**
+     * Adds an extra associated with a {@code Connection}.
+     *
+     * @param callId The unique ID of the call.
+     * @param key The extra key.
+     * @param value The extra value.
+     */
+    void putExtra(String callId, String key, boolean value) {
+        Log.v(this, "putExtra: %s %s=%b", callId, key, value);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                Bundle bundle = new Bundle();
+                bundle.putBoolean(key, value);
+                adapter.putExtras(callId, bundle);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /**
+     * Adds an extra associated with a {@code Connection}.
+     *
+     * @param callId The unique ID of the call.
+     * @param key The extra key.
+     * @param value The extra value.
+     */
+    void putExtra(String callId, String key, int value) {
+        Log.v(this, "putExtra: %s %s=%d", callId, key, value);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                Bundle bundle = new Bundle();
+                bundle.putInt(key, value);
+                adapter.putExtras(callId, bundle);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /**
+     * Adds an extra associated with a {@code Connection}.
+     *
+     * @param callId The unique ID of the call.
+     * @param key The extra key.
+     * @param value The extra value.
+     */
+    void putExtra(String callId, String key, String value) {
+        Log.v(this, "putExtra: %s %s=%s", callId, key, value);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                Bundle bundle = new Bundle();
+                bundle.putString(key, value);
+                adapter.putExtras(callId, bundle);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /**
+     * Removes extras associated with a {@code Connection}.
+     *  @param callId The unique ID of the call.
+     * @param keys The extra keys to remove.
+     */
+    void removeExtras(String callId, List<String> keys) {
+        Log.v(this, "removeExtras: %s %s", callId, keys);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                adapter.removeExtras(callId, keys);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /**
+     * Informs Telecom of a connection level event.
+     *
+     * @param callId The unique ID of the call.
+     * @param event The event.
+     * @param extras Extras associated with the event.
+     */
+    void onConnectionEvent(String callId, String event, Bundle extras) {
+        Log.v(this, "onConnectionEvent: %s", event);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                adapter.onConnectionEvent(callId, event, extras);
             } catch (RemoteException ignored) {
             }
         }
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 293dc11..bf28feb 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -61,7 +61,10 @@
     private static final int MSG_ADD_EXISTING_CONNECTION = 21;
     private static final int MSG_ON_POST_DIAL_CHAR = 22;
     private static final int MSG_SET_CONFERENCE_MERGE_FAILED = 23;
-    private static final int MSG_SET_EXTRAS = 24;
+    private static final int MSG_PUT_EXTRAS = 24;
+    private static final int MSG_REMOVE_EXTRAS = 25;
+    private static final int MSG_ON_CONNECTION_EVENT = 26;
+    private static final int MSG_SET_CONNECTION_PROPERTIES = 27;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -116,6 +119,9 @@
                 case MSG_SET_CONNECTION_CAPABILITIES:
                     mDelegate.setConnectionCapabilities((String) msg.obj, msg.arg1);
                     break;
+                case MSG_SET_CONNECTION_PROPERTIES:
+                    mDelegate.setConnectionProperties((String) msg.obj, msg.arg1);
+                    break;
                 case MSG_SET_IS_CONFERENCED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -232,13 +238,33 @@
                     }
                     break;
                 }
-                case MSG_SET_EXTRAS: {
+                case MSG_PUT_EXTRAS: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
-                        mDelegate.setExtras((String) args.arg1, (Bundle) args.arg2);
+                        mDelegate.putExtras((String) args.arg1, (Bundle) args.arg2);
                     } finally {
                         args.recycle();
                     }
+                    break;
+                }
+                case MSG_REMOVE_EXTRAS: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.removeExtras((String) args.arg1, (List<String>) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_ON_CONNECTION_EVENT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.onConnectionEvent((String) args.arg1, (String) args.arg2,
+                                (Bundle) args.arg3);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
                 }
             }
         }
@@ -300,6 +326,13 @@
         }
 
         @Override
+        public void setConnectionProperties(String connectionId, int connectionProperties) {
+            mHandler.obtainMessage(
+                    MSG_SET_CONNECTION_PROPERTIES, connectionProperties, 0, connectionId)
+                    .sendToTarget();
+        }
+
+        @Override
         public void setConferenceMergeFailed(String callId) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = callId;
@@ -413,11 +446,28 @@
         }
 
         @Override
-        public final void setExtras(String connectionId, Bundle extras) {
+        public final void putExtras(String connectionId, Bundle extras) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = connectionId;
             args.arg2 = extras;
-            mHandler.obtainMessage(MSG_SET_EXTRAS, args).sendToTarget();
+            mHandler.obtainMessage(MSG_PUT_EXTRAS, args).sendToTarget();
+        }
+
+        @Override
+        public final void removeExtras(String connectionId, List<String> keys) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = connectionId;
+            args.arg2 = keys;
+            mHandler.obtainMessage(MSG_REMOVE_EXTRAS, args).sendToTarget();
+        }
+
+        @Override
+        public final void onConnectionEvent(String connectionId, String event, Bundle extras) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = connectionId;
+            args.arg2 = event;
+            args.arg3 = extras;
+            mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
         }
     };
 
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 3a7faf6..cf73d4f 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -64,6 +64,17 @@
      */
     public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10;
 
+    /**
+     * Disconnected because the user did not locally answer the incoming call, but it was answered
+     * on another device where the call was ringing.
+     */
+    public static final int ANSWERED_ELSEWHERE = 11;
+
+    /**
+     * Disconnected because the call was pulled from the current device to another device.
+     */
+    public static final int CALL_PULLED = 12;
+
     private int mDisconnectCode;
     private CharSequence mDisconnectLabel;
     private CharSequence mDisconnectDescription;
@@ -92,8 +103,8 @@
     /**
      * Creates a new DisconnectCause.
      *
-     * @param label The localized label to show to the user to explain the disconnect.
      * @param code The code for the disconnect cause.
+     * @param label The localized label to show to the user to explain the disconnect.
      * @param description The localized description to show to the user to explain the disconnect.
      * @param reason The reason for the disconnect.
      */
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 0cf7212b..3f270d9 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -16,10 +16,13 @@
 
 package android.telecom;
 
+import android.os.Bundle;
 import android.os.RemoteException;
 
 import com.android.internal.telecom.IInCallAdapter;
 
+import java.util.List;
+
 /**
  * Receives commands from {@link InCallService} implementations which should be executed by
  * Telecom. When Telecom binds to a {@link InCallService}, an instance of this class is given to
@@ -251,6 +254,105 @@
     }
 
     /**
+     * Instructs Telecom to pull an external call to the local device.
+     *
+     * @param callId The callId to pull.
+     */
+    public void pullExternalCall(String callId) {
+        try {
+            mAdapter.pullExternalCall(callId);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Intructs Telecom to send a call event.
+     *
+     * @param callId The callId to send the event for.
+     * @param event The event.
+     * @param extras Extras associated with the event.
+     */
+    public void sendCallEvent(String callId, String event, Bundle extras) {
+        try {
+            mAdapter.sendCallEvent(callId, event, extras);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Intructs Telecom to add extras to a call.
+     *
+     * @param callId The callId to add the extras to.
+     * @param extras The extras.
+     */
+    public void putExtras(String callId, Bundle extras) {
+        try {
+            mAdapter.putExtras(callId, extras);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Intructs Telecom to add an extra to a call.
+     *
+     * @param callId The callId to add the extras to.
+     * @param key The extra key.
+     * @param value The extra value.
+     */
+    public void putExtra(String callId, String key, boolean value) {
+        try {
+            Bundle bundle = new Bundle();
+            bundle.putBoolean(key, value);
+            mAdapter.putExtras(callId, bundle);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Intructs Telecom to add an extra to a call.
+     *
+     * @param callId The callId to add the extras to.
+     * @param key The extra key.
+     * @param value The extra value.
+     */
+    public void putExtra(String callId, String key, int value) {
+        try {
+            Bundle bundle = new Bundle();
+            bundle.putInt(key, value);
+            mAdapter.putExtras(callId, bundle);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Intructs Telecom to add an extra to a call.
+     *
+     * @param callId The callId to add the extras to.
+     * @param key The extra key.
+     * @param value The extra value.
+     */
+    public void putExtra(String callId, String key, String value) {
+        try {
+            Bundle bundle = new Bundle();
+            bundle.putString(key, value);
+            mAdapter.putExtras(callId, bundle);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Intructs Telecom to remove extras from a call.
+     * @param callId The callId to remove the extras from.
+     * @param keys The extra keys to remove.
+     */
+    public void removeExtras(String callId, List<String> keys) {
+        try {
+            mAdapter.removeExtras(callId, keys);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
      * Instructs Telecom to turn the proximity sensor on.
      */
     public void turnProximitySensorOn() {
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 671399b..df6715d 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -74,6 +75,7 @@
     private static final int MSG_BRING_TO_FOREGROUND = 6;
     private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7;
     private static final int MSG_SILENCE_RINGER = 8;
+    private static final int MSG_ON_CONNECTION_EVENT = 9;
 
     /** Default Handler used to consolidate binder method calls onto a single thread. */
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -118,6 +120,18 @@
                 case MSG_SILENCE_RINGER:
                     mPhone.internalSilenceRinger();
                     break;
+                case MSG_ON_CONNECTION_EVENT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        String callId = (String) args.arg1;
+                        String event = (String) args.arg2;
+                        Bundle extras = (Bundle) args.arg3;
+                        mPhone.internalOnConnectionEvent(callId, event, extras);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
                 default:
                     break;
             }
@@ -174,6 +188,15 @@
         public void silenceRinger() {
             mHandler.obtainMessage(MSG_SILENCE_RINGER).sendToTarget();
         }
+
+        @Override
+        public void onConnectionEvent(String callId, String event, Bundle extras) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = event;
+            args.arg3 = extras;
+            mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
+        }
     }
 
     private Phone.Listener mPhoneListener = new Phone.Listener() {
@@ -426,6 +449,19 @@
     }
 
     /**
+     * Called when a {@link Call} has received a connection event issued by the
+     * {@link ConnectionService}.
+     * <p>
+     * See {@link Connection#sendConnectionEvent(String, Bundle)}.
+     *
+     * @param call The call the event is associated with.
+     * @param event The event.
+     * @param extras Any associated extras.
+     */
+    public void onConnectionEvent(Call call, String event, Bundle extras) {
+    }
+
+    /**
      * Used to issue commands to the {@link Connection.VideoProvider} associated with a
      * {@link Call}.
      */
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 3f32dbe..a965342 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,7 +16,10 @@
 
 package android.telecom;
 
+import android.net.Uri;
 import android.os.AsyncTask;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -41,6 +44,7 @@
     public static final boolean ERROR = isLoggable(android.util.Log.ERROR);
 
     private static MessageDigest sMessageDigest;
+    private static final Object sMessageDigestLock = new Object();
 
     private Log() {}
 
@@ -54,7 +58,9 @@
                 } catch (NoSuchAlgorithmException e) {
                     md = null;
                 }
-                sMessageDigest = md;
+                synchronized (sMessageDigestLock) {
+                    sMessageDigest = md;
+                }
                 return null;
             }
         }.execute();
@@ -152,18 +158,47 @@
     public static String pii(Object pii) {
         if (pii == null || VERBOSE) {
             return String.valueOf(pii);
+        } if (pii instanceof Uri) {
+            return piiUri((Uri) pii);
         }
         return "[" + secureHash(String.valueOf(pii).getBytes()) + "]";
     }
 
+    private static String piiUri(Uri handle) {
+        StringBuilder sb = new StringBuilder();
+        String scheme = handle.getScheme();
+        if (!TextUtils.isEmpty(scheme)) {
+            sb.append(scheme).append(":");
+        }
+        String value = handle.getSchemeSpecificPart();
+        if (!TextUtils.isEmpty(value)) {
+            for (int i = 0; i < value.length(); i++) {
+                char c = value.charAt(i);
+                if (PhoneNumberUtils.isStartsPostDial(c)) {
+                    sb.append(c);
+                } else if (PhoneNumberUtils.isDialable(c)) {
+                    sb.append("*");
+                } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
+                    sb.append("*");
+                } else {
+                    sb.append(c);
+                }
+            }
+        }
+        return sb.toString();
+
+    }
+
     private static String secureHash(byte[] input) {
-        if (sMessageDigest != null) {
-            sMessageDigest.reset();
-            sMessageDigest.update(input);
-            byte[] result = sMessageDigest.digest();
-            return encodeHex(result);
-        } else {
-            return "Uninitialized SHA1";
+        synchronized (sMessageDigestLock) {
+            if (sMessageDigest != null) {
+                sMessageDigest.reset();
+                sMessageDigest.update(input);
+                byte[] result = sMessageDigest.digest();
+                return encodeHex(result);
+            } else {
+                return "Uninitialized SHA1";
+            }
         }
     }
 
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index 870f5ee..f5689d8 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -34,6 +34,7 @@
     private PhoneAccountHandle mPhoneAccount;
     private int mState;
     private int mConnectionCapabilities;
+    private int mConnectionProperties;
     private List<String> mConnectionIds;
     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
     private final IVideoProvider mVideoProvider;
@@ -45,6 +46,7 @@
             PhoneAccountHandle phoneAccount,
             int state,
             int connectionCapabilities,
+            int connectionProperties,
             List<String> connectionIds,
             IVideoProvider videoProvider,
             int videoState,
@@ -54,6 +56,7 @@
         mPhoneAccount = phoneAccount;
         mState = state;
         mConnectionCapabilities = connectionCapabilities;
+        mConnectionProperties = connectionProperties;
         mConnectionIds = connectionIds;
         mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
         mVideoProvider = videoProvider;
@@ -72,6 +75,8 @@
                 .append(Connection.stateToString(mState))
                 .append(", capabilities: ")
                 .append(Connection.capabilitiesToString(mConnectionCapabilities))
+                .append(", properties: ")
+                .append(Connection.propertiesToString(mConnectionProperties))
                 .append(", connectTime: ")
                 .append(mConnectTimeMillis)
                 .append(", children: ")
@@ -95,6 +100,10 @@
         return mConnectionCapabilities;
     }
 
+    public int getConnectionProperties() {
+        return mConnectionProperties;
+    }
+
     public List<String> getConnectionIds() {
         return mConnectionIds;
     }
@@ -134,9 +143,11 @@
             int videoState = source.readInt();
             StatusHints statusHints = source.readParcelable(classLoader);
             Bundle extras = source.readBundle(classLoader);
+            int properties = source.readInt();
 
-            return new ParcelableConference(phoneAccount, state, capabilities, connectionIds,
-                    videoCallProvider, videoState, connectTimeMillis, statusHints, extras);
+            return new ParcelableConference(phoneAccount, state, capabilities, properties,
+                    connectionIds, videoCallProvider, videoState, connectTimeMillis, statusHints,
+                    extras);
         }
 
         @Override
@@ -164,5 +175,6 @@
         destination.writeInt(mVideoState);
         destination.writeParcelable(mStatusHints, 0);
         destination.writeBundle(mExtras);
+        destination.writeInt(mConnectionProperties);
     }
 }
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index fe0a4d8..540f388 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -36,6 +36,7 @@
     private final PhoneAccountHandle mPhoneAccount;
     private final int mState;
     private final int mConnectionCapabilities;
+    private final int mConnectionProperties;
     private final Uri mAddress;
     private final int mAddressPresentation;
     private final String mCallerDisplayName;
@@ -55,6 +56,7 @@
             PhoneAccountHandle phoneAccount,
             int state,
             int capabilities,
+            int properties,
             Uri address,
             int addressPresentation,
             String callerDisplayName,
@@ -71,6 +73,7 @@
         mPhoneAccount = phoneAccount;
         mState = state;
         mConnectionCapabilities = capabilities;
+        mConnectionProperties = properties;
         mAddress = address;
         mAddressPresentation = addressPresentation;
         mCallerDisplayName = callerDisplayName;
@@ -94,11 +97,26 @@
         return mState;
     }
 
-    // Bit mask of actions a call supports, values are defined in {@link CallCapabilities}.
+    /**
+     * Returns the current connection capabilities bit-mask.  Connection capabilities are defined as
+     * {@code CAPABILITY_*} constants in {@link Connection}.
+     *
+     * @return Bit-mask containing capabilities of the connection.
+     */
     public int getConnectionCapabilities() {
         return mConnectionCapabilities;
     }
 
+    /**
+     * Returns the current connection properties bit-mask.  Connection properties are defined as
+     * {@code PROPERTY_*} constants in {@link Connection}.
+     *
+     * @return Bit-mask containing properties of the connection.
+     */
+    public int getConnectionProperties() {
+        return mConnectionProperties;
+    }
+
     public Uri getHandle() {
         return mAddress;
     }
@@ -160,6 +178,8 @@
                 .append(mState)
                 .append(", capabilities:")
                 .append(Connection.capabilitiesToString(mConnectionCapabilities))
+                .append(", properties:")
+                .append(Connection.propertiesToString(mConnectionProperties))
                 .append(", extras:")
                 .append(mExtras)
                 .toString();
@@ -188,12 +208,14 @@
             DisconnectCause disconnectCause = source.readParcelable(classLoader);
             List<String> conferenceableConnectionIds = new ArrayList<>();
             source.readStringList(conferenceableConnectionIds);
-            Bundle extras = source.readBundle(classLoader);
+            Bundle extras = Bundle.setDefusable(source.readBundle(classLoader), true);
+            int properties = source.readInt();
 
             return new ParcelableConnection(
                     phoneAccount,
                     state,
                     capabilities,
+                    properties,
                     address,
                     addressPresentation,
                     callerDisplayName,
@@ -241,5 +263,6 @@
         destination.writeParcelable(mDisconnectCause, 0);
         destination.writeStringList(mConferenceableConnectionIds);
         destination.writeBundle(mExtras);
+        destination.writeInt(mConnectionProperties);
     }
 }
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index d45938c..a4ef560 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -17,6 +17,7 @@
 package android.telecom;
 
 import android.annotation.SystemApi;
+import android.os.Bundle;
 import android.util.ArrayMap;
 
 import java.util.Collections;
@@ -190,6 +191,13 @@
         fireSilenceRinger();
     }
 
+    final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) {
+        Call call = mCallByTelecomCallId.get(telecomId);
+        if (call != null) {
+            call.internalOnConnectionEvent(event, extras);
+        }
+    }
+
     /**
      * Called to destroy the phone and cleanup any lingering calls.
      */
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index b56ce73..dbc2b0c 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -170,6 +170,15 @@
     public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
 
     /**
+     * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed.
+     * <p>
+     * When set, Telecom will allow emergency video calls to be placed.  When not set, Telecom will
+     * convert all outgoing video calls to emergency numbers to audio-only.
+     * @hide
+     */
+    public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
+
+    /**
      * URI scheme for telephone number URIs.
      */
     public static final String SCHEME_TEL = "tel";
@@ -731,6 +740,9 @@
         if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
             sb.append("PlaceEmerg ");
         }
+        if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
+            sb.append("EmergVideo ");
+        }
         if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
             sb.append("SimSub ");
         }
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 6dc6e9c..77b510d 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,6 +34,9 @@
  *      component name.</li>
  * </ul>
  *
+ * Note: This Class requires a non-null {@link ComponentName} and {@link UserHandle} to operate
+ * properly. Passing in invalid parameters will generate a log warning.
+ *
  * See {@link PhoneAccount}, {@link TelecomManager}.
  */
 public final class PhoneAccountHandle implements Parcelable {
@@ -41,15 +45,16 @@
     private final UserHandle mUserHandle;
 
     public PhoneAccountHandle(
-            ComponentName componentName,
-            String id) {
+            @NonNull ComponentName componentName,
+            @NonNull String id) {
         this(componentName, id, Process.myUserHandle());
     }
 
     public PhoneAccountHandle(
-            ComponentName componentName,
-            String id,
-            UserHandle userHandle) {
+            @NonNull ComponentName componentName,
+            @NonNull String id,
+            @NonNull UserHandle userHandle) {
+        checkParameters(componentName, userHandle);
         mComponentName = componentName;
         mId = id;
         mUserHandle = userHandle;
@@ -136,6 +141,17 @@
         mUserHandle.writeToParcel(out, flags);
     }
 
+    private void checkParameters(ComponentName componentName, UserHandle userHandle) {
+        if(componentName == null) {
+            android.util.Log.w("PhoneAccountHandle", new Exception("PhoneAccountHandle has " +
+                    "been created with null ComponentName!"));
+        }
+        if(userHandle == null) {
+            android.util.Log.w("PhoneAccountHandle", new Exception("PhoneAccountHandle has " +
+                    "been created with null UserHandle!"));
+        }
+    }
+
     public static final Creator<PhoneAccountHandle> CREATOR = new Creator<PhoneAccountHandle>() {
         @Override
         public PhoneAccountHandle createFromParcel(Parcel in) {
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index ae5cd46..943da6d 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -92,6 +92,18 @@
                 int connectionCapabilities) {}
 
         /**
+         * Indicates that the call properties of this {@code RemoteConference} have changed.
+         * See {@link #getConnectionProperties()}.
+         *
+         * @param conference The {@code RemoteConference} invoking this method.
+         * @param connectionProperties The new properties of the {@code RemoteConference}.
+         */
+        public void onConnectionPropertiesChanged(
+                RemoteConference conference,
+                int connectionProperties) {}
+
+
+        /**
          * Invoked when the set of {@link RemoteConnection}s which can be added to this conference
          * call have changed.
          *
@@ -133,6 +145,7 @@
     private int mState = Connection.STATE_NEW;
     private DisconnectCause mDisconnectCause;
     private int mConnectionCapabilities;
+    private int mConnectionProperties;
     private Bundle mExtras;
 
     /** @hide */
@@ -244,6 +257,24 @@
     }
 
     /** @hide */
+    void setConnectionProperties(final int connectionProperties) {
+        if (mConnectionProperties != connectionProperties) {
+            mConnectionProperties = connectionProperties;
+            for (CallbackRecord<Callback> record : mCallbackRecords) {
+                final RemoteConference conference = this;
+                final Callback callback = record.getCallback();
+                record.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onConnectionPropertiesChanged(
+                                conference, mConnectionProperties);
+                    }
+                });
+            }
+        }
+    }
+
+    /** @hide */
     void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
         mConferenceableConnections.clear();
         mConferenceableConnections.addAll(conferenceableConnections);
@@ -279,15 +310,35 @@
     }
 
     /** @hide */
-    void setExtras(final Bundle extras) {
-        mExtras = extras;
+    void putExtras(final Bundle extras) {
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putAll(extras);
+
+        notifyExtrasChanged();
+    }
+
+    /** @hide */
+    void removeExtras(List<String> keys) {
+        if (mExtras == null || keys == null || keys.isEmpty()) {
+            return;
+        }
+        for (String key : keys) {
+            mExtras.remove(key);
+        }
+
+        notifyExtrasChanged();
+    }
+
+    private void notifyExtrasChanged() {
         for (CallbackRecord<Callback> record : mCallbackRecords) {
             final RemoteConference conference = this;
             final Callback callback = record.getCallback();
             record.getHandler().post(new Runnable() {
                 @Override
                 public void run() {
-                    callback.onExtrasChanged(conference, extras);
+                    callback.onExtrasChanged(conference, mExtras);
                 }
             });
         }
@@ -322,6 +373,16 @@
     }
 
     /**
+     * Returns the properties of the conference. See {@code PROPERTY_*} constants in class
+     * {@link Connection} for valid values.
+     *
+     * @return A bitmask of the properties of the conference call.
+     */
+    public final int getConnectionProperties() {
+        return mConnectionProperties;
+    }
+
+    /**
      * Obtain the extras associated with this {@code RemoteConnection}.
      *
      * @return The extras for this connection.
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index f960959..dc8eaf6 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -90,6 +90,17 @@
                 int connectionCapabilities) {}
 
         /**
+         * Indicates that the call properties of this {@code RemoteConnection} have changed.
+         * See {@link #getConnectionProperties()}.
+         *
+         * @param connection The {@code RemoteConnection} invoking this method.
+         * @param connectionProperties The new properties of the {@code RemoteConnection}.
+         */
+        public void onConnectionPropertiesChanged(
+                RemoteConnection connection,
+                int connectionProperties) {}
+
+        /**
          * Invoked when the post-dial sequence in the outgoing {@code Connection} has reached a
          * pause character. This causes the post-dial signals to stop pending user confirmation. An
          * implementation should present this choice to the user and invoke
@@ -209,6 +220,17 @@
          * @param extras The extras containing other information associated with the connection.
          */
         public void onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras) {}
+
+        /**
+         * Handles a connection event propagated to this {@link RemoteConnection}.
+         * <p>
+         * Connection events originate from {@link Connection#sendConnectionEvent(String, Bundle)}.
+         *
+         * @param connection The {@code RemoteConnection} invoking this method.
+         * @param event The connection event.
+         * @param extras Extras associated with the event.
+         */
+        public void onConnectionEvent(RemoteConnection connection, String event, Bundle extras) {}
     }
 
     /**
@@ -577,6 +599,7 @@
     private boolean mRingbackRequested;
     private boolean mConnected;
     private int mConnectionCapabilities;
+    private int mConnectionProperties;
     private int mVideoState;
     private VideoProvider mVideoProvider;
     private boolean mIsVoipAudioMode;
@@ -613,6 +636,7 @@
         mDisconnectCause = connection.getDisconnectCause();
         mRingbackRequested = connection.isRingbackRequested();
         mConnectionCapabilities = connection.getConnectionCapabilities();
+        mConnectionProperties = connection.getConnectionProperties();
         mVideoState = connection.getVideoState();
         mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
         mIsVoipAudioMode = connection.getIsVoipAudioMode();
@@ -708,6 +732,16 @@
     }
 
     /**
+     * Obtains the properties of this {@code RemoteConnection}.
+     *
+     * @return A bitmask of the properties of the {@code RemoteConnection}, as defined in the
+     *         {@code PROPERTY_*} constants in class {@link Connection}.
+     */
+    public int getConnectionProperties() {
+        return mConnectionProperties;
+    }
+
+    /**
      * Determines if the audio mode of this {@code RemoteConnection} is VOIP.
      *
      * @return {@code true} if the {@code RemoteConnection}'s current audio mode is VOIP.
@@ -953,6 +987,20 @@
     }
 
     /**
+     * Instructs this {@link RemoteConnection} to pull itself to the local device.
+     * <p>
+     * See {@link Call#pullExternalCall()} for more information.
+     */
+    public void pullExternalCall() {
+        try {
+            if (mConnected) {
+                mConnectionService.pullExternalCall(mConnectionId);
+            }
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
      * Set the audio state of this {@code RemoteConnection}.
      *
      * @param state The audio state of this {@code RemoteConnection}.
@@ -1089,6 +1137,23 @@
     /**
      * @hide
      */
+    void setConnectionProperties(final int connectionProperties) {
+        mConnectionProperties = connectionProperties;
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onConnectionPropertiesChanged(connection, connectionProperties);
+                }
+            });
+        }
+    }
+
+    /**
+     * @hide
+     */
     void setDestroyed() {
         if (!mCallbackRecords.isEmpty()) {
             // Make sure that the callbacks are notified that the call is destroyed first.
@@ -1277,15 +1342,49 @@
     }
 
     /** @hide */
-    void setExtras(final Bundle extras) {
-        mExtras = extras;
+    void putExtras(final Bundle extras) {
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        mExtras.putAll(extras);
+
+        notifyExtrasChanged();
+    }
+
+    /** @hide */
+    void removeExtras(List<String> keys) {
+        if (mExtras == null || keys == null || keys.isEmpty()) {
+            return;
+        }
+        for (String key : keys) {
+            mExtras.remove(key);
+        }
+
+        notifyExtrasChanged();
+    }
+
+    private void notifyExtrasChanged() {
         for (CallbackRecord record : mCallbackRecords) {
             final RemoteConnection connection = this;
             final Callback callback = record.getCallback();
             record.getHandler().post(new Runnable() {
                 @Override
                 public void run() {
-                    callback.onExtrasChanged(connection, extras);
+                    callback.onExtrasChanged(connection, mExtras);
+                }
+            });
+        }
+    }
+
+    /** @hide */
+    void onConnectionEvent(final String event, final Bundle extras) {
+        for (CallbackRecord record : mCallbackRecords) {
+            final RemoteConnection connection = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onConnectionEvent(connection, event, extras);
                 }
             });
         }
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index dc0de0c..21a7706 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -61,6 +61,7 @@
                 mPendingConnections.remove(connection);
                 // Unconditionally initialize the connection ...
                 connection.setConnectionCapabilities(parcel.getConnectionCapabilities());
+                connection.setConnectionProperties(parcel.getConnectionProperties());
                 if (parcel.getHandle() != null
                     || parcel.getState() != Connection.STATE_DISCONNECTED) {
                     connection.setAddress(parcel.getHandle(), parcel.getHandlePresentation());
@@ -156,6 +157,17 @@
         }
 
         @Override
+        public void setConnectionProperties(String callId, int connectionProperties) {
+            if (mConnectionById.containsKey(callId)) {
+                findConnectionForAction(callId, "setConnectionProperties")
+                        .setConnectionProperties(connectionProperties);
+            } else {
+                findConferenceForAction(callId, "setConnectionProperties")
+                        .setConnectionProperties(connectionProperties);
+            }
+        }
+
+        @Override
         public void setIsConferenced(String callId, String conferenceCallId) {
             // Note: callId should not be null; conferenceCallId may be null
             RemoteConnection connection =
@@ -321,13 +333,28 @@
         }
 
         @Override
-        public void setExtras(String callId, Bundle extras) {
-            if (mConnectionById.containsKey(callId)) {
-                findConnectionForAction(callId, "setExtras")
-                        .setExtras(extras);
+        public void putExtras(String callId, Bundle extras) {
+            if (hasConnection(callId)) {
+                findConnectionForAction(callId, "putExtras").putExtras(extras);
             } else {
-                findConferenceForAction(callId, "setExtras")
-                        .setExtras(extras);
+                findConferenceForAction(callId, "putExtras").putExtras(extras);
+            }
+        }
+
+        @Override
+        public void removeExtras(String callId, List<String> keys) {
+            if (hasConnection(callId)) {
+                findConnectionForAction(callId, "removeExtra").removeExtras(keys);
+            } else {
+                findConferenceForAction(callId, "removeExtra").removeExtras(keys);
+            }
+        }
+
+        @Override
+        public void onConnectionEvent(String callId, String event, Bundle extras) {
+            if (mConnectionById.containsKey(callId)) {
+                findConnectionForAction(callId, "onConnectionEvent").onConnectionEvent(event,
+                        extras);
             }
         }
     };
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9f478df..6eafb90 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -317,6 +317,18 @@
             "android.telecom.IN_CALL_SERVICE_RINGING";
 
     /**
+     * A boolean meta-data value indicating whether an {@link InCallService} wants to be informed of
+     * calls which have the {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property.  An external
+     * call is one which a {@link ConnectionService} knows about, but is not connected to directly.
+     * Dialer implementations (see {@link #getDefaultDialerPackage()}) which would like to be
+     * informed of external calls should set this meta-data to {@code true} in the manifest
+     * registration of their {@link InCallService}.  By default, the {@link InCallService} will NOT
+     * be informed of external calls.
+     */
+    public static final String METADATA_INCLUDE_EXTERNAL_CALLS =
+            "android.telecom.INCLUDE_EXTERNAL_CALLS";
+
+    /**
      * The dual tone multi-frequency signaling character sent to indicate the dialing system should
      * pause for a predefined period.
      */
@@ -1421,20 +1433,23 @@
     }
 
     /**
-     * Launches the {@link android.app.Activity} to manage blocked numbers.
-     * <p> This method displays the UI to manage blocked numbers only if
+     * Creates the {@link Intent} which can be used with {@link Context#startActivity(Intent)} to
+     * launch the activity to manage blocked numbers.
+     * <p> The activity will display the UI to manage blocked numbers only if
      * {@link android.provider.BlockedNumberContract#canCurrentUserBlockNumbers(Context)} returns
      * {@code true} for the current user.
      */
-    public void launchManageBlockedNumbersActivity() {
+    public Intent createManageBlockedNumbersIntent() {
         ITelecomService service = getTelecomService();
+        Intent result = null;
         if (service != null) {
             try {
-                service.launchManageBlockedNumbersActivity(mContext.getPackageName());
+                result = service.createManageBlockedNumbersIntent();
             } catch (RemoteException e) {
-                Log.e(TAG, "Error calling ITelecomService#manageBlockedNumbers", e);
+                Log.e(TAG, "Error calling ITelecomService#createManageBlockedNumbersIntent", e);
             }
         }
+        return result;
     }
 
     private ITelecomService getTelecomService() {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 8a54add..a4c1798 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -75,4 +75,10 @@
     void swapConference(String conferenceCallId);
 
     void onPostDialContinue(String callId, boolean proceed);
+
+    void pullExternalCall(String callId);
+
+    void sendCallEvent(String callId, String event, in Bundle extras);
+
+    void onExtrasChanged(String callId, in Bundle extras);
 }
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 7647444..9bc8ffe 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -55,6 +55,8 @@
 
     void setConnectionCapabilities(String callId, int connectionCapabilities);
 
+    void setConnectionProperties(String callId, int connectionProperties);
+
     void setIsConferenced(String callId, String conferenceCallId);
 
     void setConferenceMergeFailed(String callId);
@@ -85,5 +87,9 @@
 
     void addExistingConnection(String callId, in ParcelableConnection connection);
 
-    void setExtras(String callId, in Bundle extras);
+    void putExtras(String callId, in Bundle extras);
+
+    void removeExtras(String callId, in List<String> keys);
+
+    void onConnectionEvent(String callId, String event, in Bundle extras);
 }
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 863fff2..49f9b3b 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.telecom;
 
+import android.os.Bundle;
 import android.telecom.PhoneAccountHandle;
 
 /**
@@ -60,4 +61,12 @@
     void turnOnProximitySensor();
 
     void turnOffProximitySensor(boolean screenOnImmediately);
+
+    void pullExternalCall(String callId);
+
+    void sendCallEvent(String callId, String event, in Bundle extras);
+
+    void putExtras(String callId, in Bundle extras);
+
+    void removeExtras(String callId, in List<String> keys);
 }
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index 0088e0c..3e43fe2 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telecom;
 
 import android.app.PendingIntent;
+import android.os.Bundle;
 import android.telecom.CallAudioState;
 import android.telecom.ParcelableCall;
 
@@ -47,4 +48,6 @@
     void onCanAddCallChanged(boolean canAddCall);
 
     void silenceRinger();
+
+    void onConnectionEvent(String callId, String event, in Bundle extras);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 95c8db5..871565d 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telecom;
 
 import android.content.ComponentName;
+import android.content.Intent;
 import android.telecom.ParcelableCallAnalytics;
 import android.telecom.PhoneAccountHandle;
 import android.net.Uri;
@@ -245,7 +246,7 @@
     boolean setDefaultDialer(in String packageName);
 
     /**
-    * @see TelecomServiceImpl#launchManageBlockedNumbersActivity
+    * @see TelecomServiceImpl#createManageBlockedNumbersIntent
     **/
-    void launchManageBlockedNumbersActivity(in String callingPackageName);
+    Intent createManageBlockedNumbersIntent();
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3ad7d34..461611d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -251,6 +251,40 @@
      */
     public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
 
+    /**
+     * Flag specifying whether WFC over IMS supports the "wifi only" option.  If false, the wifi
+     * calling settings will not include an option for "wifi only".  If true, the wifi calling
+     * settings will include an option for "wifi only"
+     * <p>
+     * By default, it is assumed that WFC supports "wifi only".
+     */
+    public static final String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL =
+            "carrier_wfc_supports_wifi_only_bool";
+
+    /**
+     * Default WFC_IMS_mode 0: WIFI_ONLY
+     *                      1: CELLULAR_PREFERRED
+     *                      2: WIFI_PREFERRED
+     * @hide
+     */
+    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT =
+            "carrier_default_wfc_ims_mode_int";
+    /**
+     * Default WFC_IMS_enabled: true VoWiFi by default is on
+     *                          false VoWiFi by default is off
+     * @hide
+     */
+    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL =
+            "carrier_default_wfc_ims_enabled_bool";
+
+    /**
+     * Default WFC_IMS_roaming_enabled: true VoWiFi roaming by default is on
+     *                                  false VoWiFi roaming by default is off
+     * @hide
+     */
+    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL =
+            "carrier_default_wfc_ims_roaming_enabled_bool";
+
     /** Flag specifying whether provisioning is required for VOLTE. */
     public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
             = "carrier_volte_provisioning_required_bool";
@@ -420,6 +454,11 @@
     public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
 
     /**
+     * Flag specifying whether ICCID is showed in SIM Status screen, default to false.
+     */
+    public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
+
+    /**
      * Flag specifying whether an additional (client initiated) intent needs to be sent on System
      * update
      */
@@ -561,21 +600,8 @@
      * When {@code true}, video calls to emergency numbers will be allowed.  When {@code false},
      * video calls to emergency numbers will be initiated as audio-only calls instead.
      */
-    @SystemApi
-    public static final String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS =
-            "bool_allow_emergency_video_calls";
-
-    /**
-     * Flag indicating whether the carrier supports video pause signaling.  When {@code true}, the
-     * carrier supports use of the {@link android.telecom.VideoProfile#STATE_PAUSED} video state
-     * to pause transmission of video when the In-Call app is sent to the background.
-     * When {@code false}, video pause signaling is not supported.  {@code True} by default unless
-     * a carrier configuration overrides the default.
-     */
-    @SystemApi
-    public static final String BOOL_ALLOW_VIDEO_PAUSE =
-            "bool_allow_video_pause";
-
+    public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL =
+            "allow_emergency_video_calls_bool";
 
     /**
      * Flag indicating whether the carrier supports RCS presence indication for video calls.  When
@@ -588,7 +614,6 @@
      * and can choose to hide or show the video calling icon based on whether a contact supports
      * video.
      */
-    @SystemApi
     public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
 
     /**
@@ -613,6 +638,10 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
+        sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
+        sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
         sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
@@ -637,7 +666,7 @@
         sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL, true);
         sDefaults.putBoolean(KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL, true);
-        sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, true);
+        sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL, true);
         sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
         sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
@@ -653,6 +682,7 @@
         sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN,false);
         sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOLEAN,true);
         sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
+        sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, "");
@@ -682,8 +712,7 @@
         sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
-        sDefaults.putBoolean(BOOL_ALLOW_EMERGENCY_VIDEO_CALLS, false);
-        sDefaults.putBoolean(BOOL_ALLOW_VIDEO_PAUSE, true);
+        sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
 
         // MMS defaults
@@ -733,9 +762,28 @@
      * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
      * @return A {@link PersistableBundle} containing the config for the given subId, or default
      *         values for an invalid subId.
+     *
+     * @deprecated use getConfig.
      */
     @Nullable
     public PersistableBundle getConfigForSubId(int subId) {
+        return getConfig(subId);
+    }
+
+    /**
+     * Gets the configuration values for a particular subscription, which is associated with a
+     * specific SIM card. If an invalid subId is used, the returned config will contain default
+     * values.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
+     * @return A {@link PersistableBundle} containing the config for the given subId, or default
+     *         values for an invalid subId.
+     */
+    @Nullable
+    public PersistableBundle getConfig(int subId) {
         try {
             ICarrierConfigLoader loader = getICarrierConfigLoader();
             if (loader == null) {
@@ -757,11 +805,32 @@
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
-     * @see #getConfigForSubId
+     * @return A {@link PersistableBundle} containing the config for the default subscription.
      */
     @Nullable
     public PersistableBundle getConfig() {
-        return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
+        return getConfig(SubscriptionManager.getDefaultSubscriptionId());
+    }
+
+    /**
+     * Calling this method triggers telephony services to fetch the current carrier configuration.
+     * <p>
+     * Normally this does not need to be called because the platform reloads config on its own.
+     * This should be called by a carrier service app if it wants to update config at an arbitrary
+     * moment.
+     * </p>
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
+     * <p>
+     * This method returns before the reload has completed, and
+     * {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an
+     * arbitrary thread.
+     * </p>
+     *
+     * @deprecated use notifyConfigChanged.
+     */
+    public void notifyConfigChangedForSubId(int subId) {
+        notifyConfigChanged(subId);
     }
 
     /**
@@ -779,7 +848,7 @@
      * arbitrary thread.
      * </p>
      */
-    public void notifyConfigChangedForSubId(int subId) {
+    public void notifyConfigChanged(int subId) {
         try {
             ICarrierConfigLoader loader = getICarrierConfigLoader();
             if (loader == null) {
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index ae130d4..bb2b447 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.telephony.IPhoneStateListener;
 import java.util.List;
+import java.lang.ref.WeakReference;
 
 /**
  * A listener class for monitoring changes in specific telephony states
@@ -533,84 +534,101 @@
     /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
+     *
+     * Using a static class and weak reference here to avoid memory leak caused by the
+     * IPhoneStateListener.Stub callback retaining references to the outside PhoneStateListeners:
+     * even caller has been destroyed and "un-registered" the PhoneStateListener, it is still not
+     * eligible for GC given the references coming from:
+     * Native Stack --> PhoneStateListener --> Context (Activity).
+     * memory of caller's context will be collected after GC from service side get triggered
      */
-    IPhoneStateListener callback = new IPhoneStateListener.Stub() {
+    private static class IPhoneStateListenerStub extends IPhoneStateListener.Stub {
+        private WeakReference<PhoneStateListener> mPhoneStateListenerWeakRef;
+
+        public IPhoneStateListenerStub(PhoneStateListener phoneStateListener) {
+            mPhoneStateListenerWeakRef = new WeakReference<PhoneStateListener>(phoneStateListener);
+        }
+
+        private void send(int what, int arg1, int arg2, Object obj) {
+            PhoneStateListener listener = mPhoneStateListenerWeakRef.get();
+            if (listener != null) {
+                Message.obtain(listener.mHandler, what, arg1, arg2, obj).sendToTarget();
+            }
+        }
+
         public void onServiceStateChanged(ServiceState serviceState) {
-            Message.obtain(mHandler, LISTEN_SERVICE_STATE, 0, 0, serviceState).sendToTarget();
+            send(LISTEN_SERVICE_STATE, 0, 0, serviceState);
         }
 
         public void onSignalStrengthChanged(int asu) {
-            Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTH, asu, 0, null).sendToTarget();
+            send(LISTEN_SIGNAL_STRENGTH, asu, 0, null);
         }
 
         public void onMessageWaitingIndicatorChanged(boolean mwi) {
-            Message.obtain(mHandler, LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null)
-                    .sendToTarget();
+            send(LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null);
         }
 
         public void onCallForwardingIndicatorChanged(boolean cfi) {
-            Message.obtain(mHandler, LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null)
-                    .sendToTarget();
+            send(LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null);
         }
 
         public void onCellLocationChanged(Bundle bundle) {
             CellLocation location = CellLocation.newFromBundle(bundle);
-            Message.obtain(mHandler, LISTEN_CELL_LOCATION, 0, 0, location).sendToTarget();
+            send(LISTEN_CELL_LOCATION, 0, 0, location);
         }
 
         public void onCallStateChanged(int state, String incomingNumber) {
-            Message.obtain(mHandler, LISTEN_CALL_STATE, state, 0, incomingNumber).sendToTarget();
+            send(LISTEN_CALL_STATE, state, 0, incomingNumber);
         }
 
         public void onDataConnectionStateChanged(int state, int networkType) {
-            Message.obtain(mHandler, LISTEN_DATA_CONNECTION_STATE, state, networkType).
-                    sendToTarget();
+            send(LISTEN_DATA_CONNECTION_STATE, state, networkType, null);
         }
 
         public void onDataActivity(int direction) {
-            Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget();
+            send(LISTEN_DATA_ACTIVITY, direction, 0, null);
         }
 
         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget();
+            send(LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength);
         }
 
         public void onOtaspChanged(int otaspMode) {
-            Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget();
+            send(LISTEN_OTASP_CHANGED, otaspMode, 0, null);
         }
 
         public void onCellInfoChanged(List<CellInfo> cellInfo) {
-            Message.obtain(mHandler, LISTEN_CELL_INFO, 0, 0, cellInfo).sendToTarget();
+            send(LISTEN_CELL_INFO, 0, 0, cellInfo);
         }
 
         public void onPreciseCallStateChanged(PreciseCallState callState) {
-            Message.obtain(mHandler, LISTEN_PRECISE_CALL_STATE, 0, 0, callState).sendToTarget();
+            send(LISTEN_PRECISE_CALL_STATE, 0, 0, callState);
         }
 
         public void onPreciseDataConnectionStateChanged(
                 PreciseDataConnectionState dataConnectionState) {
-            Message.obtain(mHandler, LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0,
-                    dataConnectionState).sendToTarget();
+            send(LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0, dataConnectionState);
         }
 
         public void onDataConnectionRealTimeInfoChanged(
                 DataConnectionRealTimeInfo dcRtInfo) {
-            Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0,
-                    dcRtInfo).sendToTarget();
+            send(LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0, dcRtInfo);
         }
 
         public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
-            Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
+            send(LISTEN_VOLTE_STATE, 0, 0, lteState);
         }
 
         public void onOemHookRawEvent(byte[] rawData) {
-            Message.obtain(mHandler, LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData).sendToTarget();
+            send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
         }
 
         public void onCarrierNetworkChange(boolean active) {
-            Message.obtain(mHandler, LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active).sendToTarget();
+            send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active);
         }
-    };
+    }
+
+    IPhoneStateListener callback = new IPhoneStateListenerStub(this);
 
     private void log(String s) {
         Rlog.d(LOG_TAG, s);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index ad007c6..39a9295 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -36,7 +36,7 @@
 public class ServiceState implements Parcelable {
 
     static final String LOG_TAG = "PHONE";
-    static final boolean DBG = true;
+    static final boolean DBG = false;
     static final boolean VDBG = false;  // STOPSHIP if true
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fcb42a4..865af78 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -47,6 +47,7 @@
 
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -2931,10 +2932,27 @@
      * @return an IccOpenLogicalChannelResponse object.
      */
     public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
+        return iccOpenLogicalChannel(getDefaultSubscription(), AID);
+    }
+
+    /**
+     * Opens a logical channel to the ICC card.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHO command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param AID Application id. See ETSI 102.221 and 101.220.
+     * @return an IccOpenLogicalChannelResponse object.
+     */
+    public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccOpenLogicalChannel(AID);
+                return telephony.iccOpenLogicalChannel(subId, AID);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -2955,10 +2973,28 @@
      * @return true if the channel was closed successfully.
      */
     public boolean iccCloseLogicalChannel(int channel) {
+        return iccCloseLogicalChannel(getDefaultSubscription(), channel);
+    }
+
+    /**
+     * Closes a previously opened logical channel to the ICC card.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHC command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param channel is the channel id to be closed as retruned by a successful
+     *            iccOpenLogicalChannel.
+     * @return true if the channel was closed successfully.
+     */
+    public boolean iccCloseLogicalChannel(int subId, int channel) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccCloseLogicalChannel(channel);
+                return telephony.iccCloseLogicalChannel(subId, channel);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -2988,10 +3024,38 @@
      */
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
+        return iccTransmitApduLogicalChannel(getDefaultSubscription(), channel, cla,
+                    instruction, p1, p2, p3, data);
+    }
+
+    /**
+     * Transmit an APDU to the ICC card over a logical channel.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CGLA command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param channel is the channel id to be closed as returned by a successful
+     *            iccOpenLogicalChannel.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
+            int instruction, int p1, int p2, int p3, String data) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccTransmitApduLogicalChannel(channel, cla,
+                return telephony.iccTransmitApduLogicalChannel(subId, channel, cla,
                     instruction, p1, p2, p3, data);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
@@ -3020,10 +3084,36 @@
      */
     public String iccTransmitApduBasicChannel(int cla,
             int instruction, int p1, int p2, int p3, String data) {
+        return iccTransmitApduBasicChannel(getDefaultSubscription(), cla,
+                    instruction, p1, p2, p3, data);
+    }
+
+    /**
+     * Transmit an APDU to the ICC card over the basic channel.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CSIM command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    public String iccTransmitApduBasicChannel(int subId, int cla,
+            int instruction, int p1, int p2, int p3, String data) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccTransmitApduBasicChannel(cla,
+                return telephony.iccTransmitApduBasicChannel(subId, cla,
                     instruction, p1, p2, p3, data);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
@@ -3048,10 +3138,31 @@
      */
     public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
             String filePath) {
+        return iccExchangeSimIO(getDefaultSubscription(), fileID, command, p1, p2, p3, filePath);
+    }
+
+    /**
+     * Returns the response APDU for a command APDU sent through SIM_IO.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param fileID
+     * @param command
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command.
+     * @param filePath
+     * @return The APDU response.
+     */
+    public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2,
+            int p3, String filePath) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccExchangeSimIO(fileID, command, p1, p2, p3, filePath);
+                return telephony.iccExchangeSimIO(subId, fileID, command, p1, p2, p3, filePath);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -3073,10 +3184,29 @@
      *         returns an empty string.
      */
     public String sendEnvelopeWithStatus(String content) {
+        return sendEnvelopeWithStatus(getDefaultSubscription(), content);
+    }
+
+    /**
+     * Send ENVELOPE to the SIM and return the response.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param content String containing SAT/USAT response in hexadecimal
+     *                format starting with command tag. See TS 102 223 for
+     *                details.
+     * @return The APDU response from the ICC card in hexadecimal format
+     *         with the last 4 bytes being the status word. If the command fails,
+     *         returns an empty string.
+     */
+    public String sendEnvelopeWithStatus(int subId, String content) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.sendEnvelopeWithStatus(content);
+                return telephony.sendEnvelopeWithStatus(subId, content);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -3420,7 +3550,7 @@
      * @return the response of ISIM Authetification, or null if not available
      * @hide
      * @deprecated
-     * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM
+     * @see getIccAuthentication with appType=PhoneConstants.APPTYPE_ISIM
      */
     public String getIsimChallengeResponse(String nonce){
         try {
@@ -3436,21 +3566,60 @@
         }
     }
 
+    // ICC SIM Application Types
+    public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
+    public static final int APPTYPE_USIM = PhoneConstants.APPTYPE_USIM;
+    public static final int APPTYPE_RUIM = PhoneConstants.APPTYPE_RUIM;
+    public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
+    public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
+    // authContext (parameter P2) when doing SIM challenge,
+    // per 3GPP TS 31.102 (Section 7.1.2)
+    public static final int AUTHTYPE_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
+    public static final int AUTHTYPE_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
+
     /**
-     * Returns the response of SIM Authentication through RIL.
-     * Returns null if the Authentication hasn't been successful
-     * @param subId subscription ID to be queried
-     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
-     * @param data authentication challenge data
-     * @return the response of SIM Authentication, or null if not available
-     * @hide
+     * Returns the response of authentication for the default subscription.
+     * Returns null if the authentication hasn't been successful
+     *
+     * <p>Requires that the calling app has carrier privileges or READ_PRIVILEGED_PHONE_STATE
+     * permission.
+     *
+     * @param appType the icc application type, like {@link #APPTYPE_USIM}
+     * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+     * {@link #AUTHTYPE_EAP_SIM}
+     * @param data authentication challenge data, base64 encoded.
+     * See 3GPP TS 31.102 7.1.2 for more details.
+     * @return the response of authentication, or null if not available
+     *
+     * @see #hasCarrierPrivileges
      */
-    public String getIccSimChallengeResponse(int subId, int appType, String data) {
+    public String getIccAuthentication(int appType, int authType, String data) {
+        return getIccAuthentication(getDefaultSubscription(), appType, authType, data);
+    }
+
+    /**
+     * Returns the response of USIM Authentication for specified subId.
+     * Returns null if the authentication hasn't been successful
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     *
+     * @param subId subscription ID used for authentication
+     * @param appType the icc application type, like {@link #APPTYPE_USIM}
+     * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+     * {@link #AUTHTYPE_EAP_SIM}
+     * @param data authentication challenge data, base64 encoded.
+     * See 3GPP TS 31.102 7.1.2 for more details.
+     * @return the response of authentication, or null if not available
+     *
+     * @see #hasCarrierPrivileges
+     */
+
+    public String getIccAuthentication(int subId, int appType, int authType, String data) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getIccSimChallengeResponse(subId, appType, data);
+            return info.getIccSimChallengeResponse(subId, appType, authType, data);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -3469,9 +3638,10 @@
      * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
      * @param data authentication challenge data
      * @return the response of SIM Authentication, or null if not available
+     * @hide
      */
     public String getIccSimChallengeResponse(int appType, String data) {
-        return getIccSimChallengeResponse(getDefaultSubscription(), appType, data);
+        return getIccAuthentication(getDefaultSubscription(), appType, AUTHTYPE_EAP_SIM, data);
     }
 
     /**
@@ -3637,8 +3807,20 @@
      * @return true on success; false on any failure.
      */
     public boolean setPreferredNetworkTypeToGlobal() {
-        return setPreferredNetworkType(getDefaultSubscription(),
-                RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
+        return setPreferredNetworkTypeToGlobal(getDefaultSubscription());
+    }
+
+    /**
+     * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
+     *
+     * <p>
+     * Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
+     *
+     * @return true on success; false on any failure.
+     */
+    public boolean setPreferredNetworkTypeToGlobal(int subId) {
+        return setPreferredNetworkType(subId, RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
     }
 
     /**
@@ -3685,10 +3867,26 @@
      * @return true if the app has carrier privileges.
      */
     public boolean hasCarrierPrivileges() {
+        return hasCarrierPrivileges(getDefaultSubscription());
+    }
+
+    /**
+     * Has the calling application been granted carrier privileges by the carrier.
+     *
+     * If any of the packages in the calling UID has carrier privileges, the
+     * call will return true. This access is granted by the owner of the UICC
+     * card and does not depend on the registered carrier.
+     *
+     * @param subId The subscription to use.
+     * @return true if the app has carrier privileges.
+     */
+    public boolean hasCarrierPrivileges(int subId) {
         try {
             ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.getCarrierPrivilegeStatus() == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+            if (telephony != null) {
+                return telephony.getCarrierPrivilegeStatus(subId) ==
+                    CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+            }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);
         } catch (NullPointerException ex) {
@@ -3712,10 +3910,29 @@
      * @return true if the operation was executed correctly.
      */
     public boolean setOperatorBrandOverride(String brand) {
+        return setOperatorBrandOverride(getDefaultSubscription(), brand);
+    }
+
+    /**
+     * Override the branding for the current ICCID.
+     *
+     * Once set, whenever the SIM is present in the device, the service
+     * provider name (SPN) and the operator name will both be replaced by the
+     * brand value input. To unset the value, the same function should be
+     * called with a null brand value.
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param brand The brand name to display/set.
+     * @return true if the operation was executed correctly.
+     */
+    public boolean setOperatorBrandOverride(int subId, String brand) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.setOperatorBrandOverride(brand);
+                return telephony.setOperatorBrandOverride(subId, brand);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setOperatorBrandOverride RemoteException", ex);
         } catch (NullPointerException ex) {
@@ -3746,10 +3963,37 @@
     public boolean setRoamingOverride(List<String> gsmRoamingList,
             List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
             List<String> cdmaNonRoamingList) {
+        return setRoamingOverride(getDefaultSubscription(), gsmRoamingList, gsmNonRoamingList,
+                cdmaRoamingList, cdmaNonRoamingList);
+    }
+
+    /**
+     * Override the roaming preference for the current ICCID.
+     *
+     * Using this call, the carrier app (see #hasCarrierPrivileges) can override
+     * the platform's notion of a network operator being considered roaming or not.
+     * The change only affects the ICCID that was active when this call was made.
+     *
+     * If null is passed as any of the input, the corresponding value is deleted.
+     *
+     * <p>Requires that the caller have carrier privilege. See #hasCarrierPrivileges.
+     *
+     * @param subId for which the roaming overrides apply.
+     * @param gsmRoamingList - List of MCCMNCs to be considered roaming for 3GPP RATs.
+     * @param gsmNonRoamingList - List of MCCMNCs to be considered not roaming for 3GPP RATs.
+     * @param cdmaRoamingList - List of SIDs to be considered roaming for 3GPP2 RATs.
+     * @param cdmaNonRoamingList - List of SIDs to be considered not roaming for 3GPP2 RATs.
+     * @return true if the operation was executed correctly.
+     *
+     * @hide
+     */
+    public boolean setRoamingOverride(int subId, List<String> gsmRoamingList,
+            List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
+            List<String> cdmaNonRoamingList) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.setRoamingOverride(gsmRoamingList, gsmNonRoamingList,
+                return telephony.setRoamingOverride(subId, gsmRoamingList, gsmNonRoamingList,
                         cdmaRoamingList, cdmaNonRoamingList);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setRoamingOverride RemoteException", ex);
@@ -3857,6 +4101,21 @@
     }
 
     /** @hide */
+    public List<String> getPackagesWithCarrierPrivileges() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getPackagesWithCarrierPrivileges();
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getPackagesWithCarrierPrivileges RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "getPackagesWithCarrierPrivileges NPE", ex);
+        }
+        return Collections.EMPTY_LIST;
+    }
+
+    /** @hide */
     @SystemApi
     public void dial(String number) {
         try {
@@ -4184,7 +4443,6 @@
             Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
         } catch (NullPointerException e) {
         }
-        Log.d(TAG, "getDataEnabled: retVal=" + retVal);
         return retVal;
     }
 
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 5f84e0c..303746c 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -178,7 +178,7 @@
      *  Codec: Codec info.
      *  DisplayText: Display text for the call.
      *  AdditionalCallInfo: Additional call info.
-     *  CallRadioTech: The radio tech on which the call is placed.
+     *  CallPull: Boolean value specifying if the call is a pulled call.
      */
     public static final String EXTRA_OI = "oi";
     public static final String EXTRA_CNA = "cna";
@@ -188,6 +188,7 @@
     public static final String EXTRA_CODEC = "Codec";
     public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
     public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
+    public static final String EXTRA_IS_CALL_PULL = "CallPull";
 
     /**
      * Extra key which the RIL can use to indicate the radio technology used for a call.
@@ -200,7 +201,7 @@
      * "14" vs (int) 14).
      * Note: This is used by {@link com.android.internal.telephony.imsphone.ImsPhoneConnection#
      *      updateWifiStateFromExtras(Bundle)} to determine whether to set the
-     * {@link android.telecom.Connection#CAPABILITY_WIFI} capability on a connection.
+     * {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection.
      */
     public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
 
diff --git a/telephony/java/com/android/ims/ImsExternalCallState.aidl b/telephony/java/com/android/ims/ImsExternalCallState.aidl
new file mode 100644
index 0000000..c208702
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsExternalCallState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+parcelable ImsExternalCallState;
diff --git a/telephony/java/com/android/ims/ImsExternalCallState.java b/telephony/java/com/android/ims/ImsExternalCallState.java
new file mode 100644
index 0000000..71c1837
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsExternalCallState.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/*
+ * This file contains all the api's through which
+ * information received in Dialog Event Package can be
+ * queried
+ */
+
+/**
+ * Parcelable object to handle MultiEndpoint Dialog Information
+ * @hide
+ */
+public class ImsExternalCallState implements Parcelable {
+
+    private static final String TAG = "ImsExternalCallState";
+
+    // Dialog States
+    public static final int CALL_STATE_CONFIRMED = 1;
+    public static final int CALL_STATE_TERMINATED = 2;
+    // Dialog Id
+    private int mCallId;
+    // Number
+    private Uri mAddress;
+    private boolean mIsPullable;
+    // CALL_STATE_CONFIRMED / CALL_STATE_TERMINATED
+    private int mCallState;
+    // ImsCallProfile#CALL_TYPE_*
+    private int mCallType;
+    private boolean mIsHeld;
+
+    public ImsExternalCallState() {
+    }
+
+    public ImsExternalCallState(int callId, Uri address, boolean isPullable, int callState,
+            int callType, boolean isCallheld) {
+        mCallId = callId;
+        mAddress = address;
+        mIsPullable = isPullable;
+        mCallState = callState;
+        mCallType = callType;
+        mIsHeld = isCallheld;
+        Rlog.d(TAG, "ImsExternalCallState = " + this);
+    }
+
+    public ImsExternalCallState(Parcel in) {
+        mCallId = in.readInt();
+        ClassLoader classLoader = ImsExternalCallState.class.getClassLoader();
+        mAddress = in.readParcelable(classLoader);
+        mIsPullable = (in.readInt() != 0);
+        mCallState = in.readInt();
+        mCallType = in.readInt();
+        mIsHeld = (in.readInt() != 0);
+        Rlog.d(TAG, "ImsExternalCallState const = " + this);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mCallId);
+        out.writeParcelable(mAddress, 0);
+        out.writeInt(mIsPullable ? 1 : 0);
+        out.writeInt(mCallState);
+        out.writeInt(mCallType);
+        out.writeInt(mIsHeld ? 1 : 0);
+        Rlog.d(TAG, "ImsExternalCallState writeToParcel = " + out.toString());
+    }
+
+    public static final Parcelable.Creator<ImsExternalCallState> CREATOR =
+            new Parcelable.Creator<ImsExternalCallState>() {
+        @Override
+        public ImsExternalCallState createFromParcel(Parcel in) {
+            return new ImsExternalCallState(in);
+        }
+
+        @Override
+        public ImsExternalCallState[] newArray(int size) {
+            return new ImsExternalCallState[size];
+        }
+    };
+
+    public int getCallId() {
+        return mCallId;
+    }
+
+    public Uri getAddress() {
+        return mAddress;
+    }
+
+    public boolean isCallPullable() {
+        return mIsPullable;
+    }
+
+    public int getCallState() {
+        return mCallState;
+    }
+
+    public int getCallType() {
+        return mCallType;
+    }
+
+    public boolean isCallHeld() {
+        return mIsHeld;
+    }
+
+    @Override
+    public String toString() {
+        return "ImsExternalCallState { mCallId = " + mCallId +
+                ", mAddress = " + mAddress +
+                ", mIsPullable = " + mIsPullable +
+                ", mCallState = " + mCallState +
+                ", mCallType = " + mCallType +
+                ", mIsHeld = " + mIsHeld + "}";
+    }
+}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index c909c6d..f06d154 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -241,6 +241,16 @@
     public static final int CODE_ANSWERED_ELSEWHERE = 1014;
 
     /**
+     * For MultiEndpoint - Call Pull request has failed
+     */
+    public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015;
+
+    /**
+     * For MultiEndpoint - Call has been pulled from primary to secondary
+     */
+    public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016;
+
+    /**
      * Supplementary services (HOLD/RESUME) failure error codes.
      * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
      */
@@ -249,12 +259,33 @@
     public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203;
 
     /**
+     * DPD Procedure received no response or send failed
+     */
+    public static final int CODE_IWLAN_DPD_FAILURE = 1300;
+
+    /**
+     * Establishment of the ePDG Tunnel Failed
+     */
+    public static final int CODE_EPDG_TUNNEL_ESTABLISH_FAILURE = 1400;
+
+    /**
+     * Re-keying of the ePDG Tunnel Failed; may not always result in teardown
+     */
+    public static final int CODE_EPDG_TUNNEL_REKEY_FAILURE = 1401;
+
+    /**
+     * Connection to the packet gateway is lost
+     */
+    public static final int CODE_EPDG_TUNNEL_LOST_CONNECTION = 1402;
+
+    /**
      * Network string error messages.
      * mExtraMessage may have these values.
      */
     public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED
             = "Forbidden. Not Authorized for Service";
 
+
     // For main reason code
     public int mCode;
     // For the extra code value; it depends on the code value.
diff --git a/telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl b/telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl
new file mode 100644
index 0000000..27b8fa1
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal;
+
+import com.android.ims.ImsExternalCallState;
+
+/**
+ * A listener type for receiving notifications about DEP through IMS
+ *
+ * {@hide}
+ */
+interface IImsExternalCallStateListener {
+
+    /**
+     * Notifies client when Dialog Event Package update is received
+     *
+     * @param List<ImsExternalCallState> - External Call Dialog
+     *
+     * @return void.
+     */
+    void onImsExternalCallStateUpdate(in List<ImsExternalCallState> externalCallDialogs);
+
+}
+
diff --git a/telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl b/telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl
new file mode 100644
index 0000000..1374caa
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal;
+
+import com.android.ims.internal.IImsExternalCallStateListener;
+
+/**
+ * Provides the ImsMultiEndpoint interface
+ *
+ * {@hide}
+ */
+interface IImsMultiEndpoint {
+    /**
+     * Sets the listener.
+     */
+    void setListener(in IImsExternalCallStateListener listener);
+
+
+    /**
+     * Query api to get the latest Dialog Event Package information
+     * Should be invoked only after setListener is done
+     */
+    void requestImsExternalCallStateInfo();
+}
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index 69259d0..04cb1f2 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -18,6 +18,8 @@
 
 import com.android.ims.ImsReasonInfo;
 
+import android.net.Uri;
+
 /**
  * A listener type for receiving notifications about the changes to
  * the IMS connection(registration).
@@ -100,4 +102,9 @@
      * @param count The number of waiting voice messages.
      */
     void voiceMessageCountUpdate(int count);
+
+    /**
+     * Notifies the application when the list of URIs associated with IMS client is updated.
+     */
+    void registrationAssociatedUriChanged(in Uri[] uris);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsService.aidl b/telephony/java/com/android/ims/internal/IImsService.aidl
index 30c48d7..a9614a6 100644
--- a/telephony/java/com/android/ims/internal/IImsService.aidl
+++ b/telephony/java/com/android/ims/internal/IImsService.aidl
@@ -19,12 +19,13 @@
 import android.app.PendingIntent;
 
 import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsRegistrationListener;
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsUt;
 import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
 
 import android.os.Message;
 
@@ -75,4 +76,9 @@
      * Used to set current TTY Mode.
      */
     void setUiTTYMode(int serviceId, int uiTtyMode, in Message onComplete);
+
+    /**
+     * MultiEndpoint interface for DEP.
+     */
+    IImsMultiEndpoint getMultiEndpointInterface(int serviceId);
 }
diff --git a/telephony/java/com/android/ims/internal/uce/common/CapInfo.aidl b/telephony/java/com/android/ims/internal/uce/common/CapInfo.aidl
new file mode 100644
index 0000000..5b0ac1f
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/common/CapInfo.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ims.internal.uce.common;
+
+parcelable CapInfo;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/common/CapInfo.java b/telephony/java/com/android/ims/internal/uce/common/CapInfo.java
new file mode 100644
index 0000000..56969a8
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/common/CapInfo.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.common;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/** Class for capability discovery information.
+ *  @hide */
+public class CapInfo implements Parcelable {
+
+    /** IM session support. */
+    private boolean mImSupported = false;
+    /** File transfer support. */
+    private boolean mFtSupported = false;
+    /** File transfer Thumbnail support. */
+    private boolean mFtThumbSupported = false;
+    /** File transfer Store and forward support. */
+    private boolean mFtSnFSupported = false;
+    /** File transfer HTTP support. */
+    private boolean mFtHttpSupported = false;
+    /** Image sharing support. */
+    private boolean mIsSupported = false;
+    /** Video sharing during a CS call support -- IR-74. */
+    private boolean mVsDuringCSSupported = false;
+    /** Video sharing outside of voice call support -- IR-84. */
+    private boolean mVsSupported = false;
+    /** Social presence support. */
+    private boolean mSpSupported = false;
+    /** Presence discovery support. */
+    private boolean mCdViaPresenceSupported = false;
+    /** IP voice call support (IR-92/IR-58). */
+    private boolean mIpVoiceSupported = false;
+    /** IP video call support (IR-92/IR-58). */
+    private boolean mIpVideoSupported = false;
+    /** IP Geo location Pull using File Transfer support. */
+    private boolean mGeoPullFtSupported = false;
+    /** IP Geo location Pull support. */
+    private boolean mGeoPullSupported = false;
+    /** IP Geo location Push support. */
+    private boolean mGeoPushSupported = false;
+    /** Standalone messaging support. */
+    private boolean mSmSupported = false;
+    /** Full Store and Forward Group Chat information. */
+    private boolean mFullSnFGroupChatSupported = false;
+    /** RCS IP Voice call support .  */
+    private boolean mRcsIpVoiceCallSupported = false;
+    /** RCS IP Video call support .  */
+    private boolean mRcsIpVideoCallSupported = false;
+    /** RCS IP Video call support .  */
+    private boolean mRcsIpVideoOnlyCallSupported = false;
+    /** List of supported extensions. */
+    private String[] mExts = new String[10];
+    /** Time used to compute when to query again. */
+    private long mCapTimestamp = 0;
+
+
+    /**
+     * Constructor for the CapInfo class.
+     */
+    public CapInfo() {
+    };
+
+
+    /**
+     * Checks whether IM is supported.
+     */
+    public boolean isImSupported() {
+        return mImSupported;
+    }
+
+    /**
+     * Sets IM as supported or not supported.
+     */
+    public void setImSupported(boolean imSupported) {
+        this.mImSupported = imSupported;
+    }
+
+    /**
+     * Checks whether FT Thumbnail is supported.
+     */
+    public boolean isFtThumbSupported() {
+        return mFtThumbSupported;
+    }
+
+    /**
+     * Sets FT thumbnail as supported or not supported.
+     */
+    public void setFtThumbSupported(boolean ftThumbSupported) {
+        this.mFtThumbSupported = ftThumbSupported;
+    }
+
+
+
+    /**
+     * Checks whether FT Store and Forward is supported
+     */
+    public boolean isFtSnFSupported() {
+        return  mFtSnFSupported;
+    }
+
+    /**
+     * Sets FT Store and Forward as supported or not supported.
+     */
+    public void setFtSnFSupported(boolean  ftSnFSupported) {
+        this.mFtSnFSupported =  ftSnFSupported;
+    }
+
+   /**
+    * Checks whether File transfer HTTP is supported.
+    */
+   public boolean isFtHttpSupported() {
+       return  mFtHttpSupported;
+   }
+
+   /**
+    * Sets File transfer HTTP as supported or not supported.
+    */
+   public void setFtHttpSupported(boolean  ftHttpSupported) {
+       this.mFtHttpSupported =  ftHttpSupported;
+   }
+
+    /**
+     * Checks whether FT is supported.
+     */
+    public boolean isFtSupported() {
+        return mFtSupported;
+    }
+
+    /**
+     * Sets FT as supported or not supported.
+     */
+    public void setFtSupported(boolean ftSupported) {
+        this.mFtSupported = ftSupported;
+    }
+
+    /**
+     * Checks whether IS is supported.
+     */
+    public boolean isIsSupported() {
+        return mIsSupported;
+    }
+
+    /**
+     * Sets IS as supported or not supported.
+     */
+    public void setIsSupported(boolean isSupported) {
+        this.mIsSupported = isSupported;
+    }
+
+    /**
+     * Checks whether video sharing is supported during a CS call.
+     */
+    public boolean isVsDuringCSSupported() {
+        return mVsDuringCSSupported;
+    }
+
+    /**
+     *  Sets video sharing as supported or not supported during a CS
+     *  call.
+     */
+    public void setVsDuringCSSupported(boolean vsDuringCSSupported) {
+        this.mVsDuringCSSupported = vsDuringCSSupported;
+    }
+
+    /**
+     *  Checks whether video sharing outside a voice call is
+     *   supported.
+     */
+    public boolean isVsSupported() {
+        return mVsSupported;
+    }
+
+    /**
+     * Sets video sharing as supported or not supported.
+     */
+    public void setVsSupported(boolean vsSupported) {
+        this.mVsSupported = vsSupported;
+    }
+
+    /**
+     * Checks whether social presence is supported.
+     */
+    public boolean isSpSupported() {
+        return mSpSupported;
+    }
+
+    /**
+     * Sets social presence as supported or not supported.
+     */
+    public void setSpSupported(boolean spSupported) {
+        this.mSpSupported = spSupported;
+    }
+
+    /**
+     * Checks whether capability discovery via presence is
+     * supported.
+     */
+    public boolean isCdViaPresenceSupported() {
+        return mCdViaPresenceSupported;
+    }
+
+    /**
+     * Sets capability discovery via presence as supported or not
+     * supported.
+     */
+    public void setCdViaPresenceSupported(boolean cdViaPresenceSupported) {
+        this.mCdViaPresenceSupported = cdViaPresenceSupported;
+    }
+
+    /**
+     * Checks whether IP voice call is supported.
+     */
+    public boolean isIpVoiceSupported() {
+        return mIpVoiceSupported;
+    }
+
+    /**
+     * Sets IP voice call as supported or not supported.
+     */
+    public void setIpVoiceSupported(boolean ipVoiceSupported) {
+        this.mIpVoiceSupported = ipVoiceSupported;
+    }
+
+    /**
+     * Checks whether IP video call is supported.
+     */
+    public boolean isIpVideoSupported() {
+        return mIpVideoSupported;
+    }
+
+    /**
+     * Sets IP video call as supported or not supported.
+     */
+    public void setIpVideoSupported(boolean ipVideoSupported) {
+        this.mIpVideoSupported = ipVideoSupported;
+    }
+
+   /**
+    * Checks whether Geo location Pull using File Transfer is
+    * supported.
+    */
+   public boolean isGeoPullFtSupported() {
+       return mGeoPullFtSupported;
+   }
+
+   /**
+    * Sets Geo location Pull using File Transfer as supported or
+    * not supported.
+    */
+   public void setGeoPullFtSupported(boolean geoPullFtSupported) {
+       this.mGeoPullFtSupported = geoPullFtSupported;
+   }
+
+    /**
+     * Checks whether Geo Pull is supported.
+     */
+    public boolean isGeoPullSupported() {
+        return mGeoPullSupported;
+    }
+
+    /**
+     * Sets Geo Pull as supported or not supported.
+     */
+    public void setGeoPullSupported(boolean geoPullSupported) {
+        this.mGeoPullSupported = geoPullSupported;
+    }
+
+    /**
+     * Checks whether Geo Push is supported.
+     */
+    public boolean isGeoPushSupported() {
+        return mGeoPushSupported;
+    }
+
+    /**
+     * Sets Geo Push as supported or not supported.
+     */
+    public void setGeoPushSupported(boolean geoPushSupported) {
+        this.mGeoPushSupported = geoPushSupported;
+    }
+
+    /**
+     * Checks whether short messaging is supported.
+     */
+    public boolean isSmSupported() {
+        return mSmSupported;
+    }
+
+    /**
+     * Sets short messaging as supported or not supported.
+     */
+    public void setSmSupported(boolean smSupported) {
+        this.mSmSupported = smSupported;
+    }
+
+    /**
+     * Checks whether store/forward and group chat are supported.
+     */
+    public boolean isFullSnFGroupChatSupported() {
+        return mFullSnFGroupChatSupported;
+    }
+
+    public boolean isRcsIpVoiceCallSupported() {
+        return mRcsIpVoiceCallSupported;
+    }
+
+    public boolean isRcsIpVideoCallSupported() {
+        return mRcsIpVideoCallSupported;
+    }
+
+    public boolean isRcsIpVideoOnlyCallSupported() {
+        return mRcsIpVideoOnlyCallSupported;
+    }
+
+    /**
+     * Sets store/forward and group chat supported or not supported.
+     */
+    public void setFullSnFGroupChatSupported(boolean fullSnFGroupChatSupported) {
+        this.mFullSnFGroupChatSupported = fullSnFGroupChatSupported;
+    }
+
+    public void setRcsIpVoiceCallSupported(boolean rcsIpVoiceCallSupported) {
+        this.mRcsIpVoiceCallSupported = rcsIpVoiceCallSupported;
+    }
+    public void setRcsIpVideoCallSupported(boolean rcsIpVideoCallSupported) {
+        this.mRcsIpVideoCallSupported = rcsIpVideoCallSupported;
+    }
+    public void setRcsIpVideoOnlyCallSupported(boolean rcsIpVideoOnlyCallSupported) {
+        this.mRcsIpVideoOnlyCallSupported = rcsIpVideoOnlyCallSupported;
+    }
+
+    /** Gets the list of supported extensions. */
+    public String[] getExts() {
+        return mExts;
+    }
+
+    /** Sets the list of supported extensions. */
+    public void setExts(String[] exts) {
+        this.mExts = exts;
+    }
+
+
+    /** Gets the time stamp for when to query again. */
+    public long getCapTimestamp() {
+        return mCapTimestamp;
+    }
+
+    /** Sets the time stamp for when to query again. */
+    public void setCapTimestamp(long capTimestamp) {
+        this.mCapTimestamp = capTimestamp;
+    }
+
+    public int describeContents() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+
+        dest.writeInt(mImSupported ? 1 : 0);
+        dest.writeInt(mFtSupported ? 1 : 0);
+        dest.writeInt(mFtThumbSupported ? 1 : 0);
+        dest.writeInt(mFtSnFSupported ? 1 : 0);
+        dest.writeInt(mFtHttpSupported ? 1 : 0);
+        dest.writeInt(mIsSupported ? 1 : 0);
+        dest.writeInt(mVsDuringCSSupported ? 1 : 0);
+        dest.writeInt(mVsSupported ? 1 : 0);
+        dest.writeInt(mSpSupported ? 1 : 0);
+        dest.writeInt(mCdViaPresenceSupported ? 1 : 0);
+        dest.writeInt(mIpVoiceSupported ? 1 : 0);
+        dest.writeInt(mIpVideoSupported ? 1 : 0);
+        dest.writeInt(mGeoPullFtSupported ? 1 : 0);
+        dest.writeInt(mGeoPullSupported ? 1 : 0);
+        dest.writeInt(mGeoPushSupported ? 1 : 0);
+        dest.writeInt(mSmSupported ? 1 : 0);
+        dest.writeInt(mFullSnFGroupChatSupported ? 1 : 0);
+
+        dest.writeInt(mRcsIpVoiceCallSupported ? 1 : 0);
+        dest.writeInt(mRcsIpVideoCallSupported ? 1 : 0);
+        dest.writeInt(mRcsIpVideoOnlyCallSupported ? 1 : 0);
+        dest.writeStringArray(mExts);
+        dest.writeLong(mCapTimestamp);
+    }
+
+    public static final Parcelable.Creator<CapInfo> CREATOR = new Parcelable.Creator<CapInfo>() {
+
+        public CapInfo createFromParcel(Parcel source) {
+            return new CapInfo(source);
+        }
+
+        public CapInfo[] newArray(int size) {
+            return new CapInfo[size];
+        }
+    };
+
+    private CapInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    public void readFromParcel(Parcel source) {
+
+        mImSupported = (source.readInt() == 0) ? false : true;
+        mFtSupported = (source.readInt() == 0) ? false : true;
+        mFtThumbSupported = (source.readInt() == 0) ? false : true;
+        mFtSnFSupported = (source.readInt() == 0) ? false : true;
+        mFtHttpSupported = (source.readInt() == 0) ? false : true;
+        mIsSupported = (source.readInt() == 0) ? false : true;
+        mVsDuringCSSupported = (source.readInt() == 0) ? false : true;
+        mVsSupported = (source.readInt() == 0) ? false : true;
+        mSpSupported = (source.readInt() == 0) ? false : true;
+        mCdViaPresenceSupported = (source.readInt() == 0) ? false : true;
+        mIpVoiceSupported = (source.readInt() == 0) ? false : true;
+        mIpVideoSupported = (source.readInt() == 0) ? false : true;
+        mGeoPullFtSupported = (source.readInt() == 0) ? false : true;
+        mGeoPullSupported = (source.readInt() == 0) ? false : true;
+        mGeoPushSupported = (source.readInt() == 0) ? false : true;
+        mSmSupported = (source.readInt() == 0) ? false : true;
+        mFullSnFGroupChatSupported = (source.readInt() == 0) ? false : true;
+
+        mRcsIpVoiceCallSupported = (source.readInt() == 0) ? false : true;
+        mRcsIpVideoCallSupported = (source.readInt() == 0) ? false : true;
+        mRcsIpVideoOnlyCallSupported = (source.readInt() == 0) ? false : true;
+
+        mExts = source.createStringArray();
+        mCapTimestamp = source.readLong();
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/uce/common/StatusCode.aidl b/telephony/java/com/android/ims/internal/uce/common/StatusCode.aidl
new file mode 100644
index 0000000..e1e5798
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/common/StatusCode.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ims.internal.uce.common;
+
+parcelable StatusCode;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
new file mode 100644
index 0000000..ad9b669
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.common;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+
+/** Class for UCE status codes.
+ *  @hide */
+public class StatusCode implements Parcelable {
+
+    /**
+     *  UCE status code definitions.
+     *  @hide
+     */
+
+    /**  Request was processed successfully. */
+    public static final int UCE_SUCCESS = 0;
+    /**  Request was processed unsuccessfully. */
+    public static final int UCE_FAILURE = 1;
+    /**  Asynchronous request was handled successfully; the final
+     *  result will be updated through
+     *  callback.
+     */
+    public static final int UCE_SUCCESS_ASYC_UPDATE = 2;
+    /**  Provided service handle is not valid. */
+    public static final int UCE_INVALID_SERVICE_HANDLE = 3;
+    /**  Provided listener handler is not valid. */
+    public static final int UCE_INVALID_LISTENER_HANDLE = 4;
+    /**  Invalid parameter(s). */
+    public static final int UCE_INVALID_PARAM = 5;
+    /**  Fetch error. */
+    public static final int UCE_FETCH_ERROR = 6;
+    /**  Request timed out. */
+    public static final int UCE_REQUEST_TIMEOUT = 7;
+    /**  Failure due to insufficient memory available. */
+    public static final int UCE_INSUFFICIENT_MEMORY = 8;
+    /**  Network connection is lost. */
+    public static final int UCE_LOST_NET = 9;
+    /**  Requested feature/resource is not supported. */
+    public static final int UCE_NOT_SUPPORTED = 10;
+    /**  Contact or resource is not found. */
+    public static final int UCE_NOT_FOUND = 11;
+    /**  Service is not available. */
+    public static final int UCE_SERVICE_UNAVAILABLE = 12;
+    /**  No Change in Capabilities */
+    public static final int UCE_NO_CHANGE_IN_CAP = 13;
+    /**  Service is unknown. */
+    public static final int UCE_SERVICE_UNKNOWN = 14;
+
+
+    private int mStatusCode = UCE_SUCCESS;
+
+    /**
+     * Constructor for the StatusCode class.
+     * @hide
+     */
+    public StatusCode() {}
+
+    /**
+     *  Gets the status code.
+     *  @hide
+     */
+    public int getStatusCode() {
+        return mStatusCode;
+    }
+
+    /**
+     *  Sets the status code.
+     *  @hide
+     */
+    public void setStatusCode(int nStatusCode) {
+        this.mStatusCode = nStatusCode;
+    }
+
+    /** @hide */
+    public int describeContents() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mStatusCode);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<StatusCode> CREATOR =
+                                      new Parcelable.Creator<StatusCode>() {
+
+        public StatusCode createFromParcel(Parcel source) {
+            // TODO Auto-generated method stub
+            return new StatusCode(source);
+        }
+
+        public StatusCode[] newArray(int size) {
+            // TODO Auto-generated method stub
+            return new StatusCode[size];
+        }
+    };
+
+    /** @hide */
+    private StatusCode(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mStatusCode = source.readInt();
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/uce/common/UceLong.aidl b/telephony/java/com/android/ims/internal/uce/common/UceLong.aidl
new file mode 100644
index 0000000..2a15f42
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/common/UceLong.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ims.internal.uce.common;
+
+parcelable UceLong;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/common/UceLong.java b/telephony/java/com/android/ims/internal/uce/common/UceLong.java
new file mode 100644
index 0000000..fd07fe8
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/common/UceLong.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.common;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+
+/** Simple object wrapper for a long type.
+ *  @hide */
+public class UceLong implements Parcelable {
+
+    private long mUceLong;
+    private int mClientId = 1001;
+
+    /**
+     * Constructor for the UceLong class.
+     * @hide
+     */
+    public UceLong() {
+    };
+
+    /**
+     * Gets the long value.
+     * @hide
+     */
+    public long getUceLong() {
+        return mUceLong;
+    }
+
+    /**
+     * Sets the long value.
+     * @hide
+     */
+    public void setUceLong(long uceLong) {
+        this.mUceLong = uceLong;
+    }
+
+    /** Get the client ID as integer value.
+     *  @hide
+     */
+    public int getClientId() {
+        return mClientId;
+    }
+
+    /**
+     * Set the client ID as integer value.
+     * @hide
+     */
+    public void setClientId(int nClientId) {
+        this.mClientId = nClientId;
+    }
+
+
+    /**
+     * Gets the instance of a UceLong class.
+     * @hide
+     */
+    public static UceLong getUceLongInstance() {
+        return new UceLong();
+    }
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        writeToParcel(dest);
+
+    }
+
+    /** @hide */
+    private void writeToParcel(Parcel out) {
+        out.writeLong(mUceLong);
+        out.writeInt(mClientId);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<UceLong> CREATOR =
+                                    new Parcelable.Creator<UceLong>() {
+
+        public UceLong createFromParcel(Parcel source) {
+            return new UceLong(source);
+        }
+
+        public UceLong[] newArray(int size) {
+            return new UceLong[size];
+        }
+    };
+
+    /** @hide */
+    private UceLong(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mUceLong = source.readLong();
+        mClientId = source.readInt();
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl b/telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl
new file mode 100644
index 0000000..8cb1153
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.options;
+
+import com.android.ims.internal.uce.options.OptionsSipResponse;
+import com.android.ims.internal.uce.options.OptionsCapInfo;
+import com.android.ims.internal.uce.options.OptionsCmdStatus;
+import com.android.ims.internal.uce.common.StatusCode;
+
+/** {@hide} */
+interface IOptionsListener
+{
+    /**
+     * Callback invoked with the version information of Options service implementation.
+     * @param version, version information of the service.
+     * @hide
+     */
+    void getVersionCb(in String version );
+
+    /**
+     * Callback function to be invoked by the Options service to notify the listener of service
+     * availability.
+     * @param statusCode, UCE_SUCCESS as service availability.
+     * @hide
+     */
+    void serviceAvailable(in StatusCode statusCode);
+
+    /**
+     * Callback function to be invoked by the Options service to notify the listener of service
+     * unavailability.
+     * @param statusCode, UCE_SUCCESS as service unavailability.
+     * @hide
+     */
+    void serviceUnavailable(in StatusCode statusCode);
+
+    /**
+     * Callback function to be invoked to inform the client when the response for a SIP OPTIONS
+     * has been received.
+     * @param uri, URI of the remote entity received in network response.
+     * @param sipResponse, data of the network response received.
+     * @param capInfo, capabilities of the remote entity received.
+     * @hide
+     */
+    void sipResponseReceived( String uri,
+                                in OptionsSipResponse sipResponse, in OptionsCapInfo capInfo);
+
+    /**
+     * Callback function to be invoked to inform the client of the status of an asynchronous call.
+     * @param cmdStatus, command status of the request placed.
+     * @hide
+     */
+    void cmdStatus(in OptionsCmdStatus cmdStatus);
+
+    /**
+     * Callback function to be invoked to inform the client of an incoming OPTIONS request
+     * from the network.
+     * @param uri, URI of the remote entity received.
+     * @param capInfo, capabilities of the remote entity.
+     * @param tID, transation of the request received from network.
+     * @hide
+     */
+    void incomingOptions( String uri, in OptionsCapInfo capInfo,
+                                            in int tID);
+}
diff --git a/telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl b/telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl
new file mode 100644
index 0000000..839bb55
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.options;
+
+import com.android.ims.internal.uce.options.IOptionsListener;
+import com.android.ims.internal.uce.options.OptionsCapInfo;
+import com.android.ims.internal.uce.common.CapInfo;
+import com.android.ims.internal.uce.common.StatusCode;
+import com.android.ims.internal.uce.common.UceLong;
+
+/** {@hide} */
+interface IOptionsService
+{
+
+    /**
+     * Gets the version of the Options service implementation.
+     * the result of this Call is received in getVersionCb
+     * @param optionsServiceHandle, received in serviceCreated() of IOptionsListener.
+     * @return StatusCode, status of the request placed.
+     * @hide
+     */
+    StatusCode getVersion(int optionsServiceHandle);
+
+    /**
+     * Adds a listener to the Options service.
+     * @param optionsServiceHandle, this returned in serviceCreated() of IOptionsListener.
+     * @param optionsListener, IOptionsListener object.
+     * @param optionsServiceListenerHdl wrapper for client's listener handle to be stored.
+     *
+     * The service will fill UceLong.mUceLong with optionsServiceListenerHdl
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode addListener(int optionsServiceHandle, IOptionsListener optionsListener,
+                           inout UceLong optionsServiceListenerHdl);
+
+    /**
+     * Removes a listener from the Options service.
+     * @param optionsServiceHandle, received in serviceCreated() of IOptionsListener.
+     * @param optionsListenerHandle, received in serviceCreated() of IOptionsListener.
+     * @param optionsServiceListenerHdl provided in createOptionsService() or Addlistener().
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode removeListener(int optionsServiceHandle, in UceLong optionsServiceListenerHdl);
+
+    /**
+     * Sets the capabilities information of the self device.
+     * The status of the call is received in cmdStatus callback
+     * @param optionsServiceHandle, this returned in serviceCreated() of IOptionsListener.
+     * @param capInfo, capability information to store.
+     * @param reqUserData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode setMyInfo(int optionsServiceHandle , in CapInfo capInfo, int reqUserData);
+
+
+    /**
+     * Gets the capabilities information of remote device.
+     * The Capability information is received in cmdStatus callback
+     * @param optionsServiceHandle, this returned in serviceCreated() of IOptionsListener.
+     * @param reqUserData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode getMyInfo(int optionsServiceHandle , int reqUserdata);
+
+    /**
+     * Requests the capabilities information of a remote URI.
+     * the remote party capability is received in sipResponseReceived() callback.
+     * @param optionsServiceHandle, this returned in serviceCreated() of IOptionsListener.
+     * @param remoteURI, URI of the remote contact.
+     * @param reqUserData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode getContactCap(int optionsServiceHandle , String remoteURI, int reqUserData);
+
+
+    /**
+     * Requests the capabilities information of specified contacts.
+     * For each remote party capability is received in sipResponseReceived() callback
+     * @param optionsServiceHandle, this returned in serviceCreated() of IOptionsListener.
+     * @param remoteURIList, list of remote contact URI's.
+     * @param reqUserData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode getContactListCap(int optionsServiceHandle, in String[] remoteURIList,
+                                 int reqUserData);
+
+
+    /**
+     * Requests the capabilities information of specified contacts.
+     * The incoming Options request is received in incomingOptions() callback.
+     *
+     * @param optionsServiceHandle, this returned in serviceCreated() of IOptionsListener.
+     * @param tId, transaction ID received in incomingOptions() call of IOptionsListener.
+     * @param sipResponseCode, SIP response code the UE needs to share to network.
+     * @param reasonPhrase, response phrase corresponding to the response code.
+     * @param capInfo, capabilities to share in the resonse to network.
+     * @param bContactInBL, true if the contact is blacklisted, else false.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode responseIncomingOptions(int optionsServiceHandle,  int tId, int sipResponseCode,
+                                       String reasonPhrase, in OptionsCapInfo capInfo,
+                                       in boolean bContactInBL);
+
+}
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.aidl b/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.aidl
new file mode 100644
index 0000000..711c516
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ims.internal.uce.options;
+
+parcelable OptionsCapInfo;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.java b/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
new file mode 100644
index 0000000..c570f49
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ims.internal.uce.options;
+
+import com.android.ims.internal.uce.common.CapInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/** @hide  */
+public class OptionsCapInfo implements Parcelable {
+
+    private String mSdp = "";  //  SDP message body. It is client responsibility.
+    private CapInfo mCapInfo;
+
+    public static OptionsCapInfo getOptionsCapInfoInstance() {
+        return new OptionsCapInfo();
+    }
+
+    public String getSdp() {
+        return mSdp;
+    }
+
+    public void setSdp(String sdp) {
+        this.mSdp = sdp;
+    }
+
+    /**
+     * Constructor for the OptionsCapInfo class.
+     */
+    public OptionsCapInfo() {
+        mCapInfo = new CapInfo();
+    };
+
+    public CapInfo getCapInfo() {
+        return mCapInfo;
+    }
+    /**
+     * Sets the CapInfo
+     */
+    public void setCapInfo(CapInfo capInfo) {
+        this.mCapInfo = capInfo;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mSdp);
+        dest.writeParcelable(mCapInfo, flags);
+    }
+
+    public static final Parcelable.Creator<OptionsCapInfo> CREATOR =
+                                new Parcelable.Creator<OptionsCapInfo>() {
+
+        public OptionsCapInfo createFromParcel(Parcel source) {
+            return new OptionsCapInfo(source);
+        }
+
+        public OptionsCapInfo[] newArray(int size) {
+            return new OptionsCapInfo[size];
+        }
+    };
+
+    private OptionsCapInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    public void readFromParcel(Parcel source) {
+        mSdp = source.readString();
+        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader());
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.aidl b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.aidl
new file mode 100644
index 0000000..e83e13e8
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.options;
+
+parcelable OptionsCmdId;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.java b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.java
new file mode 100644
index 0000000..35f769c
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.options;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class OptionsCmdId implements Parcelable {
+
+    /** UCE CD command ID types  */
+
+    /** Command ID corresponding to API GetMyInfo(). */
+    public static final int UCE_OPTIONS_CMD_GETMYCDINFO = 0;
+    /** Command ID corresponding to API SetMyInfo(). */
+    public static final int UCE_OPTIONS_CMD_SETMYCDINFO = 1;
+    /** Command ID corresponding to API GetContactCap(). */
+    public static final int UCE_OPTIONS_CMD_GETCONTACTCAP = 2;
+    /** Command ID corresponding to API GetContactListCap(). */
+    public static final int UCE_OPTIONS_CMD_GETCONTACTLISTCAP = 3;
+    /** Command ID corresponding to API ResponseIncomingOptions(). */
+    public static final int UCE_OPTIONS_CMD_RESPONSEINCOMINGOPTIONS = 4;
+    /** Command ID corresponding to API GetVersion(). */
+    public static final int UCE_OPTIONS_CMD_GET_VERSION = 5;
+    /** Default Command ID as Unknown. */
+    public static final int UCE_OPTIONS_CMD_UNKNOWN = 6;
+
+
+    private int mCmdId = UCE_OPTIONS_CMD_UNKNOWN;
+
+    /**
+     * Gets the command ID.
+     * @hide
+     */
+    public int getCmdId() {
+        return mCmdId;
+    }
+
+    /**
+     * Sets the command ID.
+     * @hide
+     */
+    public void setCmdId(int nCmdId) {
+        this.mCmdId = nCmdId;
+    }
+
+    /**
+     * Constructor for the OptionsCDCmdId class.
+     * @hide
+     */
+    public OptionsCmdId(){};
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mCmdId);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<OptionsCmdId> CREATOR =
+                                  new Parcelable.Creator<OptionsCmdId>() {
+        public OptionsCmdId createFromParcel(Parcel source) {
+            return new OptionsCmdId(source);
+        }
+
+        public OptionsCmdId[] newArray(int size) {
+            return new OptionsCmdId[size];
+        }
+    };
+
+    /** @hide */
+    private OptionsCmdId(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mCmdId = source.readInt();
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.aidl b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.aidl
new file mode 100644
index 0000000..1d30a9b
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ims.internal.uce.options;
+
+parcelable OptionsCmdStatus;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
new file mode 100644
index 0000000..dab191c
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.options;
+
+import com.android.ims.internal.uce.common.StatusCode;
+import com.android.ims.internal.uce.common.CapInfo;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class OptionsCmdStatus implements Parcelable {
+
+    private OptionsCmdId mCmdId;
+    private StatusCode mStatus;
+    private int mUserData;
+    private CapInfo mCapInfo;
+
+    /**
+     * Gets the UCE command ID.
+     * @hide
+     */
+    public OptionsCmdId getCmdId() {
+        return mCmdId;
+    }
+    /**
+     * Sets the command ID.
+     * @hide
+     */
+    public void setCmdId(OptionsCmdId cmdId) {
+        this.mCmdId = cmdId;
+    }
+
+    /**
+     * Gets the user data.
+     * @hide
+     */
+    public int getUserData() {
+        return mUserData;
+    }
+
+    /**
+       Sets the user data.
+       @hide  */
+    public void setUserData(int userData) {
+        this.mUserData = userData;
+    }
+
+    /**
+     * Gets the status code.
+     * @hide
+     */
+    public StatusCode getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Sets the status code.
+     * @hide
+     */
+    public void setStatus(StatusCode status) {
+        this.mStatus = status;
+    }
+
+    /**
+     * Constructor for the OptionsCmdStatus class.
+     * @hide
+     */
+    public OptionsCmdStatus() {
+        mStatus = new StatusCode();
+        mCapInfo = new CapInfo();
+        mCmdId = new OptionsCmdId();
+        mUserData = 0;
+    };
+
+    /** @hide */
+    public CapInfo getCapInfo() {
+        return mCapInfo;
+    }
+
+    /**
+     * Sets the CapInfo
+     * @hide
+     */
+    public void setCapInfo(CapInfo capInfo) {
+        this.mCapInfo = capInfo;
+    }
+
+    /**
+     * Gets the instance of the OptionsCmdStatus class.
+     * @hide
+     */
+    public static OptionsCmdStatus getOptionsCmdStatusInstance() {
+        return new OptionsCmdStatus();
+    }
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mUserData);
+        dest.writeParcelable(mCmdId, flags);
+        dest.writeParcelable(mStatus, flags);
+        dest.writeParcelable(mCapInfo, flags);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<OptionsCmdStatus> CREATOR =
+                   new Parcelable.Creator<OptionsCmdStatus>() {
+        public OptionsCmdStatus createFromParcel(Parcel source) {
+            return new OptionsCmdStatus(source);
+        }
+        public OptionsCmdStatus[] newArray(int size) {
+            return new OptionsCmdStatus[size];
+        }
+    };
+
+    /** @hide */
+    private OptionsCmdStatus(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mUserData = source.readInt();
+        mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader());
+        mStatus = source.readParcelable(StatusCode.class.getClassLoader());
+        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader());
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.aidl b/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.aidl
new file mode 100644
index 0000000..6e9583d
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ims.internal.uce.options;
+
+parcelable OptionsSipResponse;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.java b/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
new file mode 100644
index 0000000..0b9dd21
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.options;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+/** @hide  */
+public class OptionsSipResponse implements Parcelable {
+
+    private OptionsCmdId mCmdId;
+    private int mRequestId = 0;
+    private int mSipResponseCode = 0;
+    private int mRetryAfter = 0;
+    private String mReasonPhrase = "";
+
+    /**
+     * Gets the Options command ID.
+     * @hide
+     */
+    public OptionsCmdId getCmdId() {
+        return mCmdId;
+    }
+
+    /**
+     * Sets the Options command ID.
+     * @hide
+     */
+    public void setCmdId(OptionsCmdId cmdId) {
+        this.mCmdId = cmdId;
+    }
+
+    /**
+     * Gets the request ID
+     * @hide
+     */
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * Sets the request ID
+     * @hide
+     */
+    public void setRequestId(int requestId) {
+        this.mRequestId = requestId;
+    }
+
+    /**
+     * Gets the SIP response code.
+     * @hide
+     */
+    public int getSipResponseCode() {
+        return mSipResponseCode;
+    }
+
+    /**
+     * Sets the SIP response code.
+     * @hide
+     */
+    public void setSipResponseCode(int sipResponseCode) {
+        this.mSipResponseCode = sipResponseCode;
+    }
+
+    /**
+     * Gets the reason phrase associated with the SIP responce code.
+     * @hide
+     */
+    public String getReasonPhrase() {
+        return mReasonPhrase;
+    }
+
+    /**
+     * Sets the SIP response code reason phrase.
+     * @hide
+     */
+    public void setReasonPhrase(String reasonPhrase) {
+        this.mReasonPhrase = reasonPhrase;
+    }
+
+    /**
+     * Gets the SIP retryAfter sec value .
+     * @hide
+     */
+    public int getRetryAfter() {
+        return mRetryAfter;
+    }
+
+    /**
+     * Sets the SIP retryAfter sec value
+     * @hide
+     */
+    public void setRetryAfter(int retryAfter) {
+        this.mRetryAfter = retryAfter;
+    }
+
+    /**
+     * Constructor for the OptionsSipResponse class.
+     * @hide
+     */
+    public OptionsSipResponse() {
+        mCmdId = new OptionsCmdId();
+    };
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+
+        dest.writeInt(mRequestId);
+        dest.writeInt(mSipResponseCode);
+        dest.writeString(mReasonPhrase);
+        dest.writeParcelable(mCmdId, flags);
+        dest.writeInt(mRetryAfter);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<OptionsSipResponse> CREATOR =
+                                   new Parcelable.Creator<OptionsSipResponse>() {
+        public OptionsSipResponse createFromParcel(Parcel source) {
+            return new OptionsSipResponse(source);
+        }
+
+        public OptionsSipResponse[] newArray(int size) {
+            return new OptionsSipResponse[size];
+        }
+    };
+
+    /** @hide */
+    private OptionsSipResponse(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mRequestId = source.readInt();
+        mSipResponseCode = source.readInt();
+        mReasonPhrase = source.readString();
+        mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader());
+        mRetryAfter = source.readInt();
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
new file mode 100644
index 0000000..5b71149
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import com.android.ims.internal.uce.common.StatusCode;
+import com.android.ims.internal.uce.presence.PresPublishTriggerType;
+import com.android.ims.internal.uce.presence.PresCmdStatus;
+import com.android.ims.internal.uce.presence.PresCapInfo;
+import com.android.ims.internal.uce.presence.PresSipResponse;
+import com.android.ims.internal.uce.presence.PresTupleInfo;
+import com.android.ims.internal.uce.presence.PresResInstanceInfo;
+import com.android.ims.internal.uce.presence.PresResInfo;
+import com.android.ims.internal.uce.presence.PresRlmiInfo;
+
+
+/**
+ * IPresenceListener
+ * {@hide} */
+interface IPresenceListener
+{
+    /**
+     * Gets the version of the presence listener implementation.
+     * @param version, version information.
+     */
+    void getVersionCb(in String version );
+
+    /**
+     * Callback function to be invoked by the Presence service to notify the listener of service
+     * availability.
+     * @param statusCode, UCE_SUCCESS as service availability.
+     */
+    void serviceAvailable(in StatusCode statusCode);
+
+    /**
+     * Callback function to be invoked by the Presence service to notify the listener of service
+     * unavailability.
+     * @param statusCode, UCE_SUCCESS as service unAvailability.
+     */
+    void serviceUnAvailable(in StatusCode statusCode);
+
+    /**
+     * Callback function to be invoked by the Presence service to notify the listener to send a
+     * publish request.
+     * @param publishTrigger, Publish trigger for the network being supported.
+     */
+    void publishTriggering(in PresPublishTriggerType publishTrigger);
+
+    /**
+     * Callback function to be invoked to inform the client of the status of an asynchronous call.
+     * @param cmdStatus, command status of the request placed.
+     */
+    void cmdStatus( in PresCmdStatus cmdStatus);
+
+    /**
+     * Callback function to be invoked to inform the client when the response for a SIP message,
+     * such as PUBLISH or SUBSCRIBE, has been received.
+     * @param sipResponse, network response received for the request placed.
+     */
+    void sipResponseReceived(in PresSipResponse sipResponse);
+
+    /**
+     * Callback function to be invoked to inform the client when the NOTIFY message carrying a
+     * single contact's capabilities information is received.
+     * @param presentityURI, URI of the remote entity the request was placed.
+     * @param tupleInfo, array of capability information remote entity supports.
+     */
+    void capInfoReceived(in String presentityURI,
+                         in PresTupleInfo [] tupleInfo);
+
+    /**
+     * Callback function to be invoked to inform the client when the NOTIFY message carrying
+     * contact's capabilities information is received.
+     * @param rlmiInfo, resource infomation received from network.
+     * @param resInfo, array of capabilities received from network for the list of  remore URI.
+     */
+    void listCapInfoReceived(in PresRlmiInfo rlmiInfo,
+                             in PresResInfo [] resInfo);
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl b/telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl
new file mode 100644
index 0000000..fdea6d3
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import com.android.ims.internal.uce.presence.IPresenceListener;
+import com.android.ims.internal.uce.presence.PresCapInfo;
+import com.android.ims.internal.uce.presence.PresServiceInfo;
+import com.android.ims.internal.uce.common.UceLong;
+import com.android.ims.internal.uce.common.StatusCode;
+
+/** IPresenceService
+{@hide} */
+interface IPresenceService
+{
+
+    /**
+     * Gets the version of the Presence service implementation.
+     * The verion information is received in getVersionCb callback.
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode getVersion(int presenceServiceHdl);
+
+    /**
+     * Adds a listener to the Presence service.
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @param presenceServiceListener IPresenceListener Object.
+     * @param presenceServiceListenerHdl wrapper for client's listener handle to be stored.
+     *
+     * The service will fill UceLong.mUceLong with presenceListenerHandle.
+     *
+     * @return StatusCode, status of the request placed
+     */
+    StatusCode addListener(int presenceServiceHdl, IPresenceListener presenceServiceListener,
+                           inout UceLong presenceServiceListenerHdl);
+
+    /**
+     * Removes a listener from the Presence service.
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @param presenceServiceListenerHdl provided in createPresenceService() or Addlistener().
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode removeListener(int presenceServiceHdl, in UceLong presenceServiceListenerHdl);
+
+    /**
+     * Re-enables the Presence service if it is in the Blocked state due to receiving a SIP
+     * response 489 Bad event.
+     * The application must call this API before calling any presence API after receiving a SIP
+     * response 489 Bad event.
+     * The status of this request is notified in cmdStatus callback.
+     *
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @param userData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode reenableService(int presenceServiceHdl, int userData);
+
+    /**
+     * Sends a request to publish current device capabilities.
+     * The network response is notifed in sipResponseReceived() callback.
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @param myCapInfo PresCapInfo object.
+     * @param userData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode publishMyCap(int presenceServiceHdl, in PresCapInfo myCapInfo , int userData);
+
+    /**
+     * Retrieves the capability information for a single contact. Clients receive the requested
+     * information via the listener callback function capInfoReceived() callback.
+     *
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @param remoteUri remote contact URI
+     * @param userData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode getContactCap(int presenceServiceHdl , String remoteUri, int userData);
+
+    /**
+     * Retrieves the capability information for a list of contacts. Clients receive the requested
+     * information via the listener callback function listCapInfoReceived() callback.
+     *
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @param remoteUriList list of remote contact URI's.
+     * @param userData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode getContactListCap(int presenceServiceHdl, in String[] remoteUriList, int userData);
+
+    /**
+     * Sets the mapping between a new feature tag and the corresponding service tuple information
+     * to be included in the published document.
+     * The staus of this call is received in cmdStatus callback.
+     *
+     * @param presenceServiceHdl returned in createPresenceService().
+     * @param featureTag to be supported
+     * @param PresServiceInfo service information describing the featureTag.
+     * @param userData, userData provided by client to identify the request/API call, it
+     *                  is returned in the cmdStatus() callback for client to match response
+     *                  with original request.
+     * @return StatusCode, status of the request placed.
+     */
+    StatusCode  setNewFeatureTag(int presenceServiceHdl, String featureTag,
+                                 in PresServiceInfo serviceInfo, int userData);
+
+}
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.aidl
new file mode 100644
index 0000000..df9d75a
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresCapInfo;
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.java b/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.java
new file mode 100644
index 0000000..60fc226
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import com.android.ims.internal.uce.common.CapInfo;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+/** @hide */
+public class PresCapInfo implements Parcelable {
+
+    private CapInfo mCapInfo;
+    private String mContactUri = "";
+
+    /**
+     * Gets the UCE capability information.
+     * @hide
+     */
+    public CapInfo getCapInfo() {
+        return mCapInfo;
+    }
+
+    /** Sets the UCE Capability information.
+     *  @hide
+     */
+    public void setCapInfo(CapInfo capInfo) {
+        this.mCapInfo = capInfo;
+    }
+
+
+    /**
+     *  Gets the contact URI.
+     *  @hide
+     */
+    public String getContactUri() {
+        return mContactUri;
+    }
+
+    /**
+     *  Sets the contact URI.
+     *  @hide
+     */
+    public void setContactUri(String contactUri) {
+        this.mContactUri = contactUri;
+    }
+
+    /**
+     * Constructor for the PresCapInfo class.
+     * @hide
+     */
+    public PresCapInfo() {
+        mCapInfo = new CapInfo();
+    };
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mContactUri);
+        dest.writeParcelable(mCapInfo, flags);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresCapInfo> CREATOR =
+                                    new Parcelable.Creator<PresCapInfo>() {
+
+        public PresCapInfo createFromParcel(Parcel source) {
+            return new PresCapInfo(source);
+        }
+
+        public PresCapInfo[] newArray(int size) {
+            return new PresCapInfo[size];
+        }
+    };
+
+    /** @hide */
+    private PresCapInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mContactUri = source.readString();
+        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader());
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.aidl
new file mode 100644
index 0000000..6ece045
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresCmdID;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.java b/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.java
new file mode 100644
index 0000000..395f3e8
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresCmdId implements Parcelable {
+
+    /** Presence Command Status ID
+     *  @hide */
+
+
+    /** Command ID corresponding to function GetVersion(). */
+    public static final int UCE_PRES_CMD_GET_VERSION = 0;
+    /** Command ID corresponding to function Publish(). */
+    public static final int UCE_PRES_CMD_PUBLISHMYCAP = 1;
+    /** Command ID corresponding to function GetContactCap(). */
+    public static final int UCE_PRES_CMD_GETCONTACTCAP = 2;
+    /** Command ID corresponding to function GetContactListCap(). */
+    public static final int UCE_PRES_CMD_GETCONTACTLISTCAP = 3;
+    /** Command ID corresponding to function SetNewFeatureTag(). */
+    public static final int UCE_PRES_CMD_SETNEWFEATURETAG = 4;
+    /** Command ID corresponding to API ReenableService(). */
+    public static final int UCE_PRES_CMD_REENABLE_SERVICE = 5;
+    /** Command ID is unknown. */
+    public static final int UCE_PRES_CMD_UNKNOWN = 6;
+
+
+    private int mCmdId = UCE_PRES_CMD_UNKNOWN;
+
+
+    /**
+     * Gets the command ID.
+     * @hide
+     */
+    public int getCmdId() {
+        return mCmdId;
+    }
+
+    /**
+     * Sets the command ID.
+     * @hide
+     */
+    public void setCmdId(int nCmdId) {
+        this.mCmdId = nCmdId;
+    }
+
+
+   /**
+    * Constructor for the PresCmdId class.
+    * @hide
+    */
+    public PresCmdId(){};
+
+
+    /** @hide */
+    public int describeContents() {
+
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mCmdId);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresCmdId> CREATOR =
+                                  new Parcelable.Creator<PresCmdId>() {
+
+        public PresCmdId createFromParcel(Parcel source) {
+
+            return new PresCmdId(source);
+        }
+
+        public PresCmdId[] newArray(int size) {
+
+            return new PresCmdId[size];
+        }
+    };
+
+    /** @hide */
+    private PresCmdId(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mCmdId = source.readInt();
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.aidl
new file mode 100644
index 0000000..69bca2f
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresCmdStatus;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.java b/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
new file mode 100644
index 0000000..a5b498b
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import com.android.ims.internal.uce.common.StatusCode;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+/** @hide  */
+public class PresCmdStatus implements Parcelable{
+
+    private PresCmdId mCmdId = new PresCmdId();
+    private StatusCode mStatus = new StatusCode();
+    private int mUserData;
+    private int mRequestId;
+
+    /**
+     * Gets the Presence command ID.
+     * @hide
+     */
+    public PresCmdId getCmdId() {
+        return mCmdId;
+    }
+
+    /**
+     * Sets the command ID.
+     * @hide
+     */
+    public void setCmdId(PresCmdId cmdId) {
+        this.mCmdId = cmdId;
+    }
+
+    /**
+     * Gets the user data.
+     * @hide
+     */
+    public int getUserData() {
+        return mUserData;
+    }
+
+    /**
+     * Sets the user data.
+     * @hide
+     */
+    public void setUserData(int userData) {
+        this.mUserData = userData;
+    }
+
+    /**
+     * Gets the status code.
+     * @hide
+     */
+    public StatusCode getStatus() {
+        return mStatus;
+    }
+    /**
+     * Sets the status code.
+     * @hide
+     */
+    public void setStatus(StatusCode status) {
+        this.mStatus = status;
+    }
+
+    /**
+     * Gets the request ID.
+     * @hide
+     */
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * Sets the request ID.
+     * @hide
+     */
+    public void setRequestId(int requestId) {
+        this.mRequestId = requestId;
+    }
+
+    /**
+     * Constructor for the PresCmdStatus class.
+     * @hide
+     */
+    public PresCmdStatus() {
+        mStatus = new StatusCode();
+    };
+
+    /** @hide */
+    public int describeContents() {
+
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mUserData);
+        dest.writeInt(mRequestId);
+        dest.writeParcelable(mCmdId, flags);
+        dest.writeParcelable(mStatus, flags);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresCmdStatus> CREATOR =
+                                new Parcelable.Creator<PresCmdStatus>() {
+
+        public PresCmdStatus createFromParcel(Parcel source) {
+
+            return new PresCmdStatus(source);
+        }
+
+        public PresCmdStatus[] newArray(int size) {
+
+            return new PresCmdStatus[size];
+        }
+    };
+
+    /** @hide */
+    private PresCmdStatus(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mUserData = source.readInt();
+        mRequestId = source.readInt();
+        mCmdId = source.readParcelable(PresCmdId.class.getClassLoader());
+        mStatus = source.readParcelable(StatusCode.class.getClassLoader());
+    }
+
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.aidl
new file mode 100644
index 0000000..0fc0f1b
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresPublishTriggerType;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java b/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
new file mode 100644
index 0000000..3e8531a
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresPublishTriggerType implements Parcelable {
+
+    /** Publish Trigger Indication Definitions
+     *  @hide
+     */
+
+    /** ETag expired. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_ETAG_EXPIRED = 0;
+    /** Move to LTE with VoPS disabled. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1;
+    /** Move to LTE with VoPS enabled. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2;
+    /** Move to eHRPD. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_EHRPD = 3;
+    /** Move to HSPA+. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_HSPAPLUS = 4;
+    /** Move to 3G. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_3G = 5;
+    /** Move to 2G. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_2G = 6;
+    /** Move to WLAN */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_WLAN = 7;
+    /** Move to IWLAN */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN = 8;
+    /** Trigger is unknown. */
+    public static final int UCE_PRES_PUBLISH_TRIGGER_UNKNOWN = 9;
+
+
+
+
+    private int mPublishTriggerType = UCE_PRES_PUBLISH_TRIGGER_UNKNOWN;
+
+
+    /**
+     * Gets the publish trigger types.
+     * @hide
+     */
+    public int getPublishTrigeerType() {
+        return mPublishTriggerType;
+    }
+
+    /**
+     * Sets the publish trigger type.
+     * @hide
+     */
+    public void setPublishTrigeerType(int nPublishTriggerType) {
+        this.mPublishTriggerType = nPublishTriggerType;
+    }
+
+
+    /**
+     * Constructor for the PresPublishTriggerType class.
+     * @hide
+     */
+    public PresPublishTriggerType(){};
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mPublishTriggerType);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresPublishTriggerType> CREATOR =
+                               new Parcelable.Creator<PresPublishTriggerType>() {
+
+        public PresPublishTriggerType createFromParcel(Parcel source) {
+
+            return new PresPublishTriggerType(source);
+        }
+
+        public PresPublishTriggerType[] newArray(int size) {
+
+            return new PresPublishTriggerType[size];
+        }
+    };
+
+    /** @hide */
+    private PresPublishTriggerType(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mPublishTriggerType = source.readInt();
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.aidl
new file mode 100644
index 0000000..2b7b3bb
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresResInfo;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.java b/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.java
new file mode 100644
index 0000000..a073a23
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresResInfo implements Parcelable {
+
+    private String mResUri = "";
+    private String mDisplayName = "";
+    private PresResInstanceInfo mInstanceInfo;
+
+    /**
+     * Gets the Presence service resource instance information.
+     * @hide
+     */
+    public PresResInstanceInfo getInstanceInfo() {
+        return mInstanceInfo;
+    }
+
+    /**
+     * Sets the Presence service resource instance information.
+     * @hide
+     */
+    public void setInstanceInfo(PresResInstanceInfo instanceInfo) {
+        this.mInstanceInfo = instanceInfo;
+    }
+
+    /**
+     * Gets the resource URI.
+     * @hide
+     */
+    public String getResUri() {
+        return mResUri;
+    }
+
+    /**
+     * Sets the resource URI.
+     * @hide
+     */
+    public void setResUri(String resUri) {
+        this.mResUri = resUri;
+    }
+
+    /**
+     * Gets the display name.
+     * @hide
+     */
+    public String getDisplayName() {
+        return mDisplayName;
+    }
+
+    /**
+     * Sets the display name.
+     * @hide
+     */
+    public void setDisplayName(String displayName) {
+        this.mDisplayName = displayName;
+    }
+
+
+   /**
+    * Constructor for the PresResInstanceInfo class.
+    * @hide
+    */
+    public PresResInfo() {
+        mInstanceInfo = new PresResInstanceInfo();
+    };
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mResUri);
+        dest.writeString(mDisplayName);
+        dest.writeParcelable(mInstanceInfo, flags);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresResInfo> CREATOR =
+                                     new Parcelable.Creator<PresResInfo>() {
+        public PresResInfo createFromParcel(Parcel source) {
+            return new PresResInfo(source);
+        }
+
+        public PresResInfo[] newArray(int size) {
+            return new PresResInfo[size];
+        }
+    };
+
+    /** @hide */
+    private PresResInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mResUri = source.readString();
+        mDisplayName = source.readString();
+        mInstanceInfo = source.readParcelable(PresResInstanceInfo.class.getClassLoader());
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.aidl
new file mode 100644
index 0000000..3a0cfc4
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresResInstanceInfo;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java b/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java
new file mode 100644
index 0000000..430cff1
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.util.Arrays;
+
+/** @hide  */
+public class PresResInstanceInfo implements Parcelable{
+
+    /**
+     * UCE resource instance state definitions.
+     * @hide
+     */
+
+    /** Active state. */
+    public static final int UCE_PRES_RES_INSTANCE_STATE_ACTIVE = 0;
+    /** Pending state. */
+    public static final int UCE_PRES_RES_INSTANCE_STATE_PENDING = 1;
+    /** Terminated state. */
+    public static final int UCE_PRES_RES_INSTANCE_STATE_TERMINATED = 2;
+    /** Unknown state. */
+    public static final int UCE_PRES_RES_INSTANCE_STATE_UNKNOWN = 3;
+    /** Unknown instance. */
+    public static final int UCE_PRES_RES_INSTANCE_UNKNOWN = 4;
+
+
+    private int mResInstanceState;
+    private String mId = "";
+    private String mReason = "";
+    private String mPresentityUri = "";
+    private PresTupleInfo mTupleInfoArray[];
+
+
+    /**
+     * Gets the resource instance state.
+     * @hide
+     */
+    public int getResInstanceState() {
+        return mResInstanceState;
+    }
+
+    /**
+     * Sets the resource instance state.
+     * @hide
+     */
+    public void setResInstanceState(int nResInstanceState) {
+        this.mResInstanceState = nResInstanceState;
+    }
+
+    /**
+     * Gets the resource ID.
+     * @hide
+     */
+    public String getResId() {
+        return mId;
+    }
+
+    /**
+     * Sets the resource ID.
+     * @hide
+     */
+    public void setResId(String resourceId) {
+        this.mId = resourceId;
+    }
+
+    /**
+     * Gets the reason phrase associated with the SIP response
+     * code.
+     * @hide
+     */
+    public String getReason() {
+        return mReason;
+    }
+
+    /**
+     * Sets the reason phrase associated with the SIP response
+     * code.
+     * @hide
+     */
+    public void setReason(String reason) {
+        this.mReason = reason;
+    }
+
+    /**
+     * Gets the entity URI.
+     * @hide
+     */
+    public String getPresentityUri() {
+        return mPresentityUri;
+    }
+
+    /**
+     * Sets the entity URI.
+     * @hide
+     */
+    public void setPresentityUri(String presentityUri) {
+        this.mPresentityUri = presentityUri;
+    }
+
+    /**
+     * Gets the tuple information.
+     * @hide
+     */
+    public PresTupleInfo[] getTupleInfo() {
+        return mTupleInfoArray;
+    }
+
+    /**
+     * Sets the tuple information.
+     * @hide
+     */
+    public void setTupleInfo(PresTupleInfo[] tupleInfo) {
+        this.mTupleInfoArray = new PresTupleInfo[tupleInfo.length];
+        this.mTupleInfoArray = tupleInfo;
+    }
+
+
+   /**
+    * Constructor for the PresResInstanceInfo class.
+    * @hide
+    */
+    public PresResInstanceInfo(){
+
+    };
+
+    /** @hide */
+    public int describeContents() {
+
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+        dest.writeString(mReason);
+        dest.writeInt(mResInstanceState);
+        dest.writeString(mPresentityUri);
+        dest.writeParcelableArray(mTupleInfoArray, flags);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresResInstanceInfo> CREATOR =
+                      new Parcelable.Creator<PresResInstanceInfo>() {
+
+        public PresResInstanceInfo createFromParcel(Parcel source) {
+
+            return new PresResInstanceInfo(source);
+        }
+
+        public PresResInstanceInfo[] newArray(int size) {
+
+            return new PresResInstanceInfo[size];
+        }
+    };
+
+    /** @hide */
+    private PresResInstanceInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mId = source.readString();
+        mReason = source.readString();
+        mResInstanceState = source.readInt();
+        mPresentityUri = source.readString();
+        Parcelable[] tempParcelableArray = source.readParcelableArray(
+                                    PresTupleInfo.class.getClassLoader());
+        mTupleInfoArray = new PresTupleInfo[] {};
+        if(tempParcelableArray != null) {
+            mTupleInfoArray = Arrays.copyOf(tempParcelableArray, tempParcelableArray.length,
+                                            PresTupleInfo[].class);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.aidl
new file mode 100644
index 0000000..2689c2d
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresRlmiInfo;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java b/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
new file mode 100644
index 0000000..987dd77
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresRlmiInfo implements Parcelable {
+
+    /**
+     * uri corresponding to the list.  Typically, this is the URI to
+     * which the SUBSCRIBE request was sent.
+     */
+    private String mUri = "";
+    /** list version number from 0 to 2^32-1 */
+    private int mVersion;
+    /**
+     * Indicate whether the NOTIFY message contains information for
+     * every resource in the list
+     */
+    private boolean mFullState;
+    /** list name */
+    private String mListName = "";
+    /**
+     * unique request ID used to match NOTIFY with original list
+     * SUBSCRIBE
+     */
+    private int mRequestId;
+    /** subscription state*/
+    private PresSubscriptionState mPresSubscriptionState;
+    /** active subscription expires time in second */
+    private int mSubscriptionExpireTime;
+    /** list subscrption terminated reason */
+    private String mSubscriptionTerminatedReason;
+
+    /**
+     * Gets the URI.
+     * @hide
+     */
+    public String getUri() {
+        return mUri;
+    }
+
+    /**
+     * Sets the URI.
+     * @hide
+     */
+    public void setUri(String uri) {
+        this.mUri = uri;
+    }
+
+    /**
+     * Gets the version.
+     * @hide
+     */
+    public int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Sets the version.
+     * @hide
+     */
+    public void setVersion(int version) {
+        this.mVersion = version;
+    }
+
+    /**
+     * Gets the RLMI state.
+     * @hide
+     */
+    public boolean isFullState() {
+        return mFullState;
+    }
+
+    /**
+     * Sets the RLMI state.
+     * @hide
+     */
+    public void setFullState(boolean fullState) {
+        this.mFullState = fullState;
+    }
+
+    /**
+     * Gets the RLMI list name.
+     * @hide
+     */
+    public String getListName() {
+        return mListName;
+    }
+
+    /**
+     * Sets the RLMI list name.
+     * @hide
+     */
+    public void setListName(String listName) {
+        this.mListName = listName;
+    }
+
+    /**
+     *  Gets the subscription request ID.
+     *  @hide
+     */
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * Sets the subscription request ID.
+     * @hide
+     */
+    public void setRequestId(int requestId) {
+        this.mRequestId = requestId;
+    }
+
+    /**
+     * Gets the presence subscription state.
+     * @hide
+     */
+    public PresSubscriptionState getPresSubscriptionState() {
+        return mPresSubscriptionState;
+    }
+
+    /**
+     * Sets the presence subscription state.
+     * @hide
+     */
+    public void setPresSubscriptionState(PresSubscriptionState presSubscriptionState) {
+        this.mPresSubscriptionState = presSubscriptionState;
+    }
+
+    /**
+     * Gets the presence subscription expiration time.
+     * @hide
+     */
+    public int getSubscriptionExpireTime() {
+        return mSubscriptionExpireTime;
+    }
+
+    /**
+     * Sets the presence subscription expiration time.
+     * @hide
+     */
+    public void setSubscriptionExpireTime(int subscriptionExpireTime) {
+        this.mSubscriptionExpireTime = subscriptionExpireTime;
+    }
+
+    /**
+     * Gets the presence subscription terminated reason.
+     * @hide
+     */
+    public String getSubscriptionTerminatedReason() {
+        return mSubscriptionTerminatedReason;
+    }
+
+    /**
+     * Sets the presence subscription terminated reason.
+     * @hide
+     */
+    public void setSubscriptionTerminatedReason(String subscriptionTerminatedReason) {
+        this.mSubscriptionTerminatedReason = subscriptionTerminatedReason;
+    }
+
+    /**
+     * Constructor for the PresTupleInfo class.
+     * @hide
+     */
+    public PresRlmiInfo(){};
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mUri);
+        dest.writeInt(mVersion);
+        dest.writeInt(mFullState ? 1 : 0);
+        dest.writeString(mListName);
+        dest.writeInt(mRequestId);
+        dest.writeParcelable(mPresSubscriptionState, flags);
+        dest.writeInt(mSubscriptionExpireTime);
+        dest.writeString(mSubscriptionTerminatedReason);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresRlmiInfo> CREATOR =
+                                new Parcelable.Creator<PresRlmiInfo>() {
+
+        public PresRlmiInfo createFromParcel(Parcel source) {
+            return new PresRlmiInfo(source);
+        }
+
+        public PresRlmiInfo[] newArray(int size) {
+            return new PresRlmiInfo[size];
+        }
+    };
+
+    /** @hide */
+    private PresRlmiInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mUri = source.readString();
+        mVersion = source.readInt();
+        mFullState = (source.readInt() == 0) ? false : true;
+        mListName = source.readString();
+        mRequestId = source.readInt();
+        mPresSubscriptionState = source.readParcelable(
+                                  PresSubscriptionState.class.getClassLoader());
+        mSubscriptionExpireTime = source.readInt();
+        mSubscriptionTerminatedReason = source.readString();
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.aidl
new file mode 100644
index 0000000..91ddf86
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresServiceInfo;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.java b/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.java
new file mode 100644
index 0000000..f7b7264
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresServiceInfo implements Parcelable {
+
+    /** Presence Service Information
+     *  @hide
+     */
+
+    /** No media capability. */
+    public static final int UCE_PRES_MEDIA_CAP_NONE = 0;
+    /** Full duplex audio only. */
+    public static final int UCE_PRES_MEDIA_CAP_FULL_AUDIO_ONLY = 1;
+    /** Full duplex audio and video. */
+    public static final int UCE_PRES_MEDIA_CAP_FULL_AUDIO_AND_VIDEO = 2;
+    /** Media cap is unknown. */
+    public static final int UCE_PRES_MEDIA_CAP_UNKNOWN = 3;
+
+
+    private int mMediaCap = UCE_PRES_MEDIA_CAP_NONE;
+    private String mServiceID = "";
+    private String mServiceDesc = "";
+    private String mServiceVer = "";
+
+    /**
+     * Gets the media type.
+     * @hide
+     */
+    public int getMediaType() {
+        return mMediaCap;
+    }
+
+    /**
+     * Sets the media type.
+     * @hide
+     */
+    public void setMediaType(int nMediaCap) {
+        this.mMediaCap = nMediaCap;
+    }
+
+    /**
+     * Gets the service ID.
+     * @hide
+     */
+    public String getServiceId() {
+        return mServiceID;
+    }
+
+    /**
+     * Sets the service ID.
+     * @hide
+     */
+    public void setServiceId(String serviceID) {
+        this.mServiceID = serviceID;
+    }
+    /**
+     * Gets the service description.
+     * @hide
+     */
+    public String getServiceDesc() {
+        return mServiceDesc;
+    }
+
+    /**
+     * Sets the service description.
+     * @hide
+     */
+    public void setServiceDesc(String serviceDesc) {
+        this.mServiceDesc = serviceDesc;
+    }
+
+    /**
+     * Gets the service version.
+     * @hide
+     */
+    public String getServiceVer() {
+        return mServiceVer;
+    }
+
+    /**
+     * Sets the service version.
+     * @hide
+     */
+    public void setServiceVer(String serviceVer) {
+        this.mServiceVer = serviceVer;
+    }
+
+    /**
+     * Constructor for the PresServiceInfo class.
+     * @hide
+     */
+    public PresServiceInfo() {};
+
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mServiceID);
+        dest.writeString(mServiceDesc);
+        dest.writeString(mServiceVer);
+        dest.writeInt(mMediaCap);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresServiceInfo> CREATOR =
+                                new Parcelable.Creator<PresServiceInfo>() {
+
+        public PresServiceInfo createFromParcel(Parcel source) {
+            return new PresServiceInfo(source);
+        }
+
+        public PresServiceInfo[] newArray(int size) {
+            return new PresServiceInfo[size];
+        }
+    };
+
+    /** @hide */
+    private PresServiceInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mServiceID = source.readString();
+        mServiceDesc = source.readString();
+        mServiceVer = source.readString();
+        mMediaCap = source.readInt();
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.aidl
new file mode 100644
index 0000000..7dfff3d
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresSipResponse;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.java b/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.java
new file mode 100644
index 0000000..456b443
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresSipResponse implements Parcelable {
+
+    private PresCmdId mCmdId = new PresCmdId();
+    private int mRequestId = 0;
+    private int mSipResponseCode = 0;
+    private int mRetryAfter = 0;
+    private String mReasonPhrase = "";
+
+    /**
+     * Gets the Presence command ID.
+     * @hide
+     */
+    public PresCmdId getCmdId() {
+        return mCmdId;
+    }
+
+    /**
+     * Sets the Presence command ID.
+     * @hide
+     */
+    public void setCmdId(PresCmdId cmdId) {
+        this.mCmdId = cmdId;
+    }
+
+    /**
+     * Gets the request ID.
+     * @hide
+     */
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * Sets the request ID.
+     * @hide
+     */
+    public void setRequestId(int requestId) {
+        this.mRequestId = requestId;
+    }
+
+    /**
+     * Gets the SIP response code.
+     * @hide
+     */
+    public int getSipResponseCode() {
+        return mSipResponseCode;
+    }
+
+    /**
+     * Sets the SIP response code.
+     * @hide
+     */
+    public void setSipResponseCode(int sipResponseCode) {
+        this.mSipResponseCode = sipResponseCode;
+    }
+
+
+    /**
+     * Gets the reason phrase associated with the SIP responce
+     * code.
+     * @hide
+     */
+    public String getReasonPhrase() {
+        return mReasonPhrase;
+    }
+
+    /**
+     * Sets the SIP response code reason phrase.
+     * @hide
+     */
+    public void setReasonPhrase(String reasonPhrase) {
+        this.mReasonPhrase = reasonPhrase;
+    }
+
+    /**
+     * Gets the SIP retryAfter sec value.
+     * @hide
+     */
+    public int getRetryAfter() {
+        return mRetryAfter;
+    }
+
+    /**
+     * Sets the SIP retryAfter sec value
+     * @hide
+     */
+    public void setRetryAfter(int retryAfter) {
+        this.mRetryAfter = retryAfter;
+    }
+
+    /**
+     * Constructor for the PresSipResponse class.
+     * @hide
+     */
+    public PresSipResponse(){};
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRequestId);
+        dest.writeInt(mSipResponseCode);
+        dest.writeString(mReasonPhrase);
+        dest.writeParcelable(mCmdId, flags);
+        dest.writeInt(mRetryAfter);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresSipResponse> CREATOR =
+                            new Parcelable.Creator<PresSipResponse>() {
+
+        public PresSipResponse createFromParcel(Parcel source) {
+            return new PresSipResponse(source);
+        }
+
+        public PresSipResponse[] newArray(int size) {
+            return new PresSipResponse[size];
+        }
+    };
+
+    /** @hide */
+    private PresSipResponse(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mRequestId = source.readInt();
+        mSipResponseCode = source.readInt();
+        mReasonPhrase = source.readString();
+        mCmdId = source.readParcelable(PresCmdId.class.getClassLoader());
+        mRetryAfter = source.readInt();
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.aidl
new file mode 100644
index 0000000..7bff24a
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresSubscriptionState;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java b/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java
new file mode 100644
index 0000000..872bc23
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresSubscriptionState implements Parcelable {
+
+    /**
+     *  Subscription states.
+     *  @hide
+     */
+
+    /** Active state. */
+    public static final int UCE_PRES_SUBSCRIPTION_STATE_ACTIVE = 0;
+    /** Pending state. */
+    public static final int UCE_PRES_SUBSCRIPTION_STATE_PENDING = 1;
+    /** Terminated state. */
+    public static final int UCE_PRES_SUBSCRIPTION_STATE_TERMINATED = 2;
+    /** Unknown state. */
+    public static final int UCE_PRES_SUBSCRIPTION_STATE_UNKNOWN = 3;
+
+
+    private int mPresSubscriptionState = UCE_PRES_SUBSCRIPTION_STATE_UNKNOWN;
+
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mPresSubscriptionState);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresSubscriptionState> CREATOR =
+                                    new Parcelable.Creator<PresSubscriptionState>() {
+
+        public PresSubscriptionState createFromParcel(Parcel source) {
+            return new PresSubscriptionState(source);
+        }
+
+        public PresSubscriptionState[] newArray(int size) {
+            return new PresSubscriptionState[size];
+        }
+    };
+
+    /** @hide */
+    private PresSubscriptionState(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mPresSubscriptionState = source.readInt();
+    }
+
+    /**
+     * Constructor for the PresSubscriptionState class.
+     * @hide
+     */
+    public PresSubscriptionState() {    };
+
+    /**
+     * Gets the Presence subscription state.
+     * @hide
+     */
+    public int getPresSubscriptionStateValue() {
+        return mPresSubscriptionState;
+    }
+
+
+    /**
+     * Sets the Presence subscription state.
+     * @hide
+     */
+    public void setPresSubscriptionState(int nPresSubscriptionState) {
+        this.mPresSubscriptionState = nPresSubscriptionState;
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.aidl b/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.aidl
new file mode 100644
index 0000000..6571ebe
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+parcelable PresTupleInfo;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.java b/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
new file mode 100644
index 0000000..e1867c5
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.presence;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide  */
+public class PresTupleInfo implements Parcelable {
+
+    private String mFeatureTag = "";
+    private String mContactUri = "";
+    private String mTimestamp = "";
+
+
+    /**
+     * Gets the feature tag.
+     * @hide
+     */
+    public String getFeatureTag() {
+        return mFeatureTag;
+    }
+
+    /**
+     * Sets the feature tag.
+     * @hide
+     */
+    public void setFeatureTag(String featureTag) {
+        this.mFeatureTag = featureTag;
+    }
+
+    /**
+     * Gets the contact URI.
+     * @hide
+     */
+    public String getContactUri() {
+        return mContactUri;
+    }
+    /**
+     * Sets the contact URI.
+     * @hide
+     */
+    public void setContactUri(String contactUri) {
+        this.mContactUri = contactUri;
+    }
+
+    /**
+     * Gets the timestamp.
+     * @hide
+     */
+    public String getTimestamp() {
+        return mTimestamp;
+    }
+
+    /**
+     * Sets the timestamp.
+     * @hide
+     */
+    public void setTimestamp(String timestamp) {
+        this.mTimestamp = timestamp;
+    }
+
+    /**
+     * Constructor for the PresTupleInfo class.
+     * @hide
+     */
+    public PresTupleInfo(){};
+
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mFeatureTag);
+        dest.writeString(mContactUri);
+        dest.writeString(mTimestamp);
+    }
+
+    /** @hide */
+    public static final Parcelable.Creator<PresTupleInfo> CREATOR =
+                                      new Parcelable.Creator<PresTupleInfo>() {
+
+        public PresTupleInfo createFromParcel(Parcel source) {
+            return new PresTupleInfo(source);
+        }
+
+        public PresTupleInfo[] newArray(int size) {
+            return new PresTupleInfo[size];
+        }
+    };
+
+    /** @hide */
+    private PresTupleInfo(Parcel source) {
+        readFromParcel(source);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel source) {
+        mFeatureTag = source.readString();
+        mContactUri = source.readString();
+        mTimestamp = source.readString();
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl b/telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl
new file mode 100644
index 0000000..13707a1
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.uceservice;
+
+/** IUceListener
+ * {@hide}  */
+interface IUceListener
+{
+    /**
+     * Get UCE Status
+     * @param serviceStatusValue defined in ImsUceManager
+     * @hide
+     */
+    void setStatus(int serviceStatusValue);
+}
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
new file mode 100644
index 0000000..43f83cd
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.uceservice;
+
+import com.android.ims.internal.uce.uceservice.IUceListener;
+import com.android.ims.internal.uce.presence.IPresenceService;
+import com.android.ims.internal.uce.options.IOptionsListener;
+import com.android.ims.internal.uce.presence.IPresenceListener;
+import com.android.ims.internal.uce.options.IOptionsService;
+import com.android.ims.internal.uce.common.UceLong;
+import com.android.ims.internal.uce.common.StatusCode;
+
+/** IUceService
+ *  UCE service interface class.
+ * {@hide} */
+interface IUceService
+{
+
+    /**
+     * Starts the Uce service.
+     * @param uceListener IUceListener object
+     * @return boolean true if the service stop start is processed successfully, FALSE otherwise.
+     *
+     * Service status is returned in setStatus callback in IUceListener.
+     * @hide
+     */
+    boolean startService(IUceListener uceListener);
+
+    /**
+     * Stops the UCE service.
+     * @return boolean true if the service stop request is processed successfully, FALSE otherwise.
+     * @hide
+     */
+    boolean stopService();
+
+
+
+    /**
+     * Requests the UCE service start status.
+     * @return boolean true if service started else false.
+     * @hide
+     */
+    boolean isServiceStarted();
+
+    /**
+     * Creates a options service for Capability Discovery.
+     * @param optionsListener IOptionsListener object.
+     * @param optionsServiceListenerHdl wrapper for client's listener handle to be stored.
+     *
+     * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and
+     * used to validate callbacks received in IPresenceListener are indeed from the
+     * service the client created.
+     *
+     * @return  optionsServiceHandle
+     * @hide
+     */
+    int createOptionsService(IOptionsListener optionsListener,
+                             inout UceLong optionsServiceListenerHdl);
+
+    /**
+     * Destroys a Options service.
+     * @param optionsServiceHandle this is received in serviceCreated() callback
+     *        in IOptionsListener
+     * @hide
+     */
+    void destroyOptionsService(int optionsServiceHandle);
+
+    /**
+     * Creates a presence service.
+     * @param presenceServiceListener IPresenceListener object
+     * @param presenceServiceListenerHdl wrapper for client's listener handle to be stored.
+     *
+     * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and
+     * used to validate callbacks received in IPresenceListener are indeed from the
+     * service the client created.
+     *
+     * @return  presenceServiceHdl
+     * @hide
+     */
+    int createPresenceService(IPresenceListener presenceServiceListener,
+                              inout UceLong presenceServiceListenerHdl);
+
+    /**
+     * Destroys a presence service.
+     * @param presenceServiceHdl handle returned during createPresenceService()
+     * @hide
+     */
+    void destroyPresenceService(int presenceServiceHdl);
+
+
+
+    /**
+     * Query the UCE Service for information to know whether the is registered.
+     * @return boolean, true if Registered to for network events else false.
+     * @hide
+     */
+    boolean getServiceStatus();
+
+    /**
+     * Query the UCE Service for presence Service.
+     * @return IPresenceService object.
+     * @hide
+     */
+    IPresenceService getPresenceService();
+
+    /**
+     * Query the UCE Service for options service object.
+     * @return IOptionsService object.
+     * @hide
+     */
+    IOptionsService getOptionsService();
+
+}
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java b/telephony/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
new file mode 100644
index 0000000..4b0b098
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce.uceservice;
+
+import android.content.Context;
+import android.content.Intent;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+
+import java.util.HashMap;
+import android.util.Log;
+
+/**
+ * ImsUceManager Declaration
+ * @hide
+ */
+public class ImsUceManager {
+
+    private static final String LOG_TAG = "ImsUceManager";
+    /**
+     * Uce Service name Internal Uce only
+     * @hide
+     */
+    private static final String UCE_SERVICE = "uce";
+
+    /**
+     * IUceService object
+     * @hide
+     */
+    private IUceService mUceService = null;
+    private UceServiceDeathRecipient mDeathReceipient = new UceServiceDeathRecipient();
+    private Context mContext;
+    private int mPhoneId;
+    /**
+     * Stores the UceManager instaces of Clients identified by
+     * phoneId
+     * @hide
+     */
+    private static HashMap<Integer, ImsUceManager> sUceManagerInstances =
+                                                   new HashMap<Integer, ImsUceManager>();
+
+    public static final String ACTION_UCE_SERVICE_UP =
+                                       "com.android.ims.internal.uce.UCE_SERVICE_UP";
+    public static final String ACTION_UCE_SERVICE_DOWN =
+                                        "com.android.ims.internal.uce.UCE_SERVICE_DOWN";
+
+    /** Uce Service status received in IUceListener.setStatus()
+     *  callback
+     *  @hide
+     */
+    public static final int UCE_SERVICE_STATUS_FAILURE = 0;
+    /** indicate UI to call Presence/Options API.   */
+    public static final int UCE_SERVICE_STATUS_ON = 1;
+    /** Indicate UI destroy Presence/Options   */
+    public static final int UCE_SERVICE_STATUS_CLOSED = 2;
+    /** Service up and trying to register for network events  */
+    public static final int UCE_SERVICE_STATUS_READY = 3;
+
+    /**
+     * Part of the ACTION_UCE_SERVICE_UP or _DOWN intents. A long
+     * value; the phone ID corresponding to the IMS service coming up or down.
+     * Internal use only.
+     * @hide
+     */
+    public static final String EXTRA_PHONE_ID = "android:phone_id";
+
+
+    /**
+     * Gets the instance of UCE Manager
+     * @hide
+     */
+    public static ImsUceManager getInstance(Context context, int phoneId) {
+        //if (DBG) Log.d (LOG_TAG, "GetInstance Called");
+        synchronized (sUceManagerInstances) {
+            if (sUceManagerInstances.containsKey(phoneId)) {
+                return sUceManagerInstances.get(phoneId);
+            } else {
+                ImsUceManager uceMgr =  new ImsUceManager(context, phoneId);
+                sUceManagerInstances.put(phoneId, uceMgr);
+                return uceMgr;
+            }
+        }
+    }
+
+    /**
+     * Constructor
+     * @hide
+     */
+    private ImsUceManager(Context context, int phoneId) {
+        //if (DBG) Log.d (LOG_TAG, "Constructor");
+        mContext = context;
+        mPhoneId = phoneId;
+        createUceService(true);
+    }
+
+    /**
+     * Gets the Uce service Instance
+     *
+     * client should call this API only after  createUceService()
+     * this instance is deleted when ACTION_UCE_SERVICE_DOWN event
+     * is received.
+     * @hide
+     */
+    public IUceService getUceServiceInstance() {
+        //if (DBG) Log.d (LOG_TAG, "GetUceServiceInstance Called");
+        return mUceService;
+    }
+
+    /**
+     * Gets the UCE service name
+     * @hide
+     */
+    private String getUceServiceName(int phoneId) {
+        return UCE_SERVICE;
+    }
+
+    /**
+     * Gets the IBinder to UCE service
+     *
+     * Client should call this after receving ACTION_UCE_SERVICE_UP
+     * event.
+     * @hide
+     */
+    public void createUceService(boolean checkService) {
+        //if (DBG) Log.d (LOG_TAG, "CreateUceService Called");
+        if (checkService) {
+            IBinder binder = ServiceManager.checkService(getUceServiceName(mPhoneId));
+
+            if (binder == null) {
+                //if (DBG)Log.d (LOG_TAG, "Unable to find IBinder");
+                return;
+            }
+        }
+        IBinder b = ServiceManager.getService(getUceServiceName(mPhoneId));
+
+        if (b != null) {
+            try {
+                b.linkToDeath(mDeathReceipient, 0);
+            } catch (RemoteException e) {
+            }
+        }
+
+        this.mUceService = IUceService.Stub.asInterface(b);
+    }
+
+
+    /**
+     * Death recipient class for monitoring IMS service.
+     *
+     * After receiving ACTION_UCE_SERVICE_DOWN event, the client
+     * should wait to receive ACTION_UCE_SERVICE_UP and call
+     * createUceService inorder to create mUceService instance.
+     * @hide
+     */
+    private class UceServiceDeathRecipient implements IBinder.DeathRecipient {
+        @Override
+        public void binderDied() {
+            //if (DBG) Log.d (LOG_TAG, "found IBinder/IUceService Service Died");
+            mUceService = null;
+
+            if (mContext != null) {
+                Intent intent = new Intent(ACTION_UCE_SERVICE_DOWN);
+                intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
+                mContext.sendBroadcast(new Intent(intent));
+            }
+        }
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
new file mode 100644
index 0000000..3660e03
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal.uce;
+
+import com.android.ims.internal.uce.uceservice.IUceService;
+import com.android.ims.internal.uce.uceservice.IUceListener;
+import com.android.ims.internal.uce.common.StatusCode;
+import com.android.ims.internal.uce.common.UceLong;
+import com.android.ims.internal.uce.options.IOptionsListener;
+import com.android.ims.internal.uce.options.IOptionsService;
+import com.android.ims.internal.uce.presence.IPresenceService;
+import com.android.ims.internal.uce.presence.IPresenceListener;
+
+/**
+ * Sub IUceService interface. To enable forward compatability
+ * during developlemt
+ * @hide
+ */
+public abstract class UceServiceBase {
+    /**
+     * IUceService Stub Implementation
+     */
+    private final class UceServiceBinder extends IUceService.Stub {
+        @Override
+        public boolean startService(IUceListener uceListener) {
+            return onServiceStart(uceListener);
+        }
+
+        @Override
+        public boolean stopService() {
+            return onStopService();
+        }
+
+        @Override
+        public boolean isServiceStarted() {
+            return onIsServiceStarted();
+        }
+
+        @Override
+        public int createOptionsService(IOptionsListener optionsListener,
+                                        UceLong optionsServiceListenerHdl) {
+            return onCreateOptionsService(optionsListener, optionsServiceListenerHdl);
+        }
+
+
+        @Override
+        public void destroyOptionsService(int optionsServiceHandle) {
+            onDestroyOptionsService(optionsServiceHandle);
+        }
+
+        @Override
+        public int createPresenceService(
+            IPresenceListener presServiceListener,
+            UceLong presServiceListenerHdl) {
+            return onCreatePresService(presServiceListener, presServiceListenerHdl);
+        }
+
+        @Override
+        public void destroyPresenceService(int presServiceHdl) {
+            onDestroyPresService(presServiceHdl);
+        }
+
+        @Override
+        public boolean getServiceStatus() {
+            return onGetServiceStatus();
+        }
+
+        @Override
+        public IPresenceService getPresenceService() {
+            return onGetPresenceService();
+        }
+
+        @Override
+        public IOptionsService getOptionsService() {
+            return onGetOptionsService();
+        }
+    }
+
+    private UceServiceBinder mBinder;
+
+    public UceServiceBinder getBinder() {
+        if (mBinder == null) {
+            mBinder = new UceServiceBinder();
+        }
+        return mBinder;
+    }
+
+    protected boolean onServiceStart(IUceListener uceListener) {
+        //no-op
+        return false;
+    }
+
+    protected boolean onStopService() {
+        //no-op
+        return false;
+    }
+
+    protected boolean onIsServiceStarted() {
+        //no-op
+        return false;
+    }
+
+    protected int onCreateOptionsService(IOptionsListener optionsListener,
+                                                UceLong optionsServiceListenerHdl) {
+        //no-op
+        return 0;
+    }
+
+    protected void onDestroyOptionsService(int cdServiceHandle) {
+        //no-op
+        return;
+    }
+
+    protected int onCreatePresService(IPresenceListener presServiceListener,
+            UceLong presServiceListenerHdl) {
+        //no-op
+        return 0;
+    }
+
+    protected void onDestroyPresService(int presServiceHdl) {
+        //no-op
+        return;
+    }
+
+    protected boolean onGetServiceStatus() {
+        //no-op
+        return false;
+    }
+
+    protected IPresenceService onGetPresenceService() {
+        //no-op
+        return null;
+    }
+
+    protected IOptionsService onGetOptionsService () {
+        //no-op
+        return null;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index dc2b297..02baa34 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -196,8 +196,9 @@
      *
      * @param subId subscription ID to be queried
      * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+     * @param authType Authentication type, see PhoneConstants#AUTHTYPE_xxx
      * @param data authentication challenge data
      * @return challenge response
      */
-    String getIccSimChallengeResponse(int subId, int appType, String data);
+    String getIccSimChallengeResponse(int subId, int appType, int authType, String data);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62f294c..2727319 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -538,27 +538,30 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
+     * @param subId The subscription to use.
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return an IccOpenLogicalChannelResponse object.
      */
-    IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID);
+    IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID);
 
     /**
      * Closes a previously opened logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
+     * @param subId The subscription to use.
      * @param channel is the channel id to be closed as retruned by a
      *            successful iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
-    boolean iccCloseLogicalChannel(int channel);
+    boolean iccCloseLogicalChannel(int subId, int channel);
 
     /**
      * Transmit an APDU to the ICC card over a logical channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
+     * @param subId The subscription to use.
      * @param channel is the channel id to be closed as retruned by a
      *            successful iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
@@ -571,7 +574,7 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      */
-    String iccTransmitApduLogicalChannel(int channel, int cla, int instruction,
+    String iccTransmitApduLogicalChannel(int subId, int channel, int cla, int instruction,
             int p1, int p2, int p3, String data);
 
     /**
@@ -579,6 +582,7 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
      *
+     * @param subId The subscription to use.
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
      * @param p1 P1 value of the APDU command.
@@ -589,12 +593,13 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      */
-    String iccTransmitApduBasicChannel(int cla, int instruction,
+    String iccTransmitApduBasicChannel(int subId, int cla, int instruction,
             int p1, int p2, int p3, String data);
 
     /**
      * Returns the response APDU for a command APDU sent through SIM_IO.
      *
+     * @param subId The subscription to use.
      * @param fileID
      * @param command
      * @param p1 P1 value of the APDU command.
@@ -603,12 +608,13 @@
      * @param filePath
      * @return The APDU response.
      */
-    byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
+    byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2, int p3,
             String filePath);
 
     /**
      * Send ENVELOPE to the SIM and returns the response.
      *
+     * @param subId The subscription to use.
      * @param contents  String containing SAT/USAT response in hexadecimal
      *                  format starting with command tag. See TS 102 223 for
      *                  details.
@@ -616,7 +622,7 @@
      *         being the status word. If the command fails, returns an empty
      *         string.
      */
-    String sendEnvelopeWithStatus(String content);
+    String sendEnvelopeWithStatus(int subId, String content);
 
     /**
      * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
@@ -768,9 +774,10 @@
      *
      * TODO: Add a link to documentation.
      *
+     * @param subId The subscription to use.
      * @return carrier privilege status defined in TelephonyManager.
      */
-    int getCarrierPrivilegeStatus();
+    int getCarrierPrivilegeStatus(int subId);
 
     /**
      * Similar to above, but check for the package whose name is pkgName.
@@ -842,10 +849,11 @@
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *  or has to be carrier app - see #hasCarrierPrivileges.
      *
+     * @param subId The subscription to use.
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
      */
-    boolean setOperatorBrandOverride(String brand);
+    boolean setOperatorBrandOverride(int subId, String brand);
 
     /**
      * Override the roaming indicator for the current ICCID.
@@ -858,13 +866,14 @@
      *
      * <p>Requires that the caller have carrier privilege. See #hasCarrierPrivileges.
      *
+     * @param subId for which the roaming overrides apply.
      * @param gsmRoamingList - List of MCCMNCs to be considered roaming for 3GPP RATs.
      * @param gsmNonRoamingList - List of MCCMNCs to be considered not roaming for 3GPP RATs.
      * @param cdmaRoamingList - List of SIDs to be considered roaming for 3GPP2 RATs.
      * @param cdmaNonRoamingList - List of SIDs to be considered not roaming for 3GPP2 RATs.
      * @return true if the operation was executed correctly.
      */
-    boolean setRoamingOverride(in List<String> gsmRoamingList,
+    boolean setRoamingOverride(int subId, in List<String> gsmRoamingList,
             in List<String> gsmNonRoamingList, in List<String> cdmaRoamingList,
             in List<String> cdmaNonRoamingList);
 
@@ -1028,4 +1037,9 @@
      * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
      */
     boolean isVoicemailVibrationEnabled(in PhoneAccountHandle accountHandle);
+
+    /**
+     * Returns a list of packages that have carrier privileges.
+     */
+    List<String> getPackagesWithCarrierPrivileges();
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index ecd89ed..1680fe3 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -202,4 +202,10 @@
     public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0;
     public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1;
     public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER;
+
+    // authContext (parameter P2) when doing SIM challenge,
+    // per 3GPP TS 31.102 (Section 7.1.2)
+    public static final int AUTH_CONTEXT_EAP_SIM = 128;
+    public static final int AUTH_CONTEXT_EAP_AKA = 129;
+    public static final int AUTH_CONTEXT_UNDEFINED = -1;
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index bba357e..8aa0e34 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -81,8 +81,7 @@
     int INTERNAL_ERR = 38;                    /* Hit unexpected vendor internal error scenario */
     int SYSTEM_ERR = 39;                      /* Hit platform or system error */
     int MODEM_ERR = 40;                       /* Hit unexpected modem error */
-    int INVALID_STATE = 41;                   /* Can not process the request as vendor RIL is in
-                                                   invalid state. */
+    int INVALID_STATE = 41;                   /* Unexpected request for the current state */
     int NO_RESOURCES = 42;                    /* Not sufficient resource to process the request */
     int SIM_ERR = 43;                         /* Received error from SIM card */
     int INVALID_ARGUMENTS = 44;               /* Received invalid arguments in request */
@@ -92,6 +91,22 @@
     int NO_SMS_TO_ACK = 48;                   /* ACK received when there is no SMS to ack */
     int NETWORK_ERR = 49;                     /* Received error from network */
     int REQUEST_RATE_LIMITED = 50;            /* Operation denied due to overly-frequent requests */
+    int SIM_BUSY = 51;                        /* SIM is busy */
+    int SIM_FULL = 52;                        /* The target EF is full */
+    int NETWORK_REJECT = 53;                  /* Request is rejected by network */
+    int OPERATION_NOT_ALLOWED = 54;           /* Not allowed the request now */
+    int EMPTY_RECORD = 55;                    /* The request record is empty */
+    int INVALID_SMS_FORMAT = 56;              /* Invalid sms format */
+    int ENCODING_ERR = 57;                    /* Message not encoded properly */
+    int INVALID_SMSC_ADDRESS = 58;            /* SMSC address specified is invalid */
+    int NO_SUCH_ENTRY = 59;                   /* No such entry present to perform the request */
+    int NETWORK_NOT_READY = 60;               /* Network is not ready to perform the request */
+    int NOT_PROVISIONED = 61;                 /* Device doesnot have this value provisioned */
+    int NO_SUBSCRIPTION = 62;                 /* Device doesnot have subscription */
+    int NO_NETWORK_FOUND = 63;                /* Network cannot be found */
+    int DEVICE_IN_USE = 64;                   /* Operation cannot be performed because the device
+                                                 is currently in use */
+    int ABORTED = 65;                         /* Operation aborted */
     // Below is list of OEM specific error codes which can by used by OEMs in case they don't want to
     // reveal particular replacement for Generic failure
     int OEM_ERROR_1 = 501;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 645c3a1..6567ea7 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -217,4 +217,5 @@
      *     or Earpiece, based on the default audio routing strategy.
      */
     static final String PROPERTY_VIDEOCALL_AUDIO_OUTPUT = "persist.radio.call.audio.output";
+
 }
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 84cffe1..c7cbf97 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -145,13 +145,14 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @removed */
     @Override
     public SharedPreferences getSharedPreferences(File file, int mode) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public boolean migrateSharedPreferencesFrom(Context sourceContext, String name) {
+    public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
         throw new UnsupportedOperationException();
     }
 
@@ -180,6 +181,7 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @removed */
     @Override
     public File getSharedPreferencesPath(String name) {
         throw new UnsupportedOperationException();
@@ -258,7 +260,7 @@
     }
 
     @Override
-    public boolean migrateDatabaseFrom(Context sourceContext, String name) {
+    public boolean moveDatabaseFrom(Context sourceContext, String name) {
         throw new UnsupportedOperationException();
     }
 
@@ -726,26 +728,26 @@
     }
 
     @Override
-    public Context createDeviceEncryptedStorageContext() {
+    public Context createDeviceProtectedStorageContext() {
         throw new UnsupportedOperationException();
     }
 
     /** {@hide} */
     @SystemApi
     @Override
-    public Context createCredentialEncryptedStorageContext() {
+    public Context createCredentialProtectedStorageContext() {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public boolean isDeviceEncryptedStorage() {
+    public boolean isDeviceProtectedStorage() {
         throw new UnsupportedOperationException();
     }
 
     /** {@hide} */
     @SystemApi
     @Override
-    public boolean isCredentialEncryptedStorage() {
+    public boolean isCredentialProtectedStorage() {
         throw new UnsupportedOperationException();
     }
 }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index da43460..91e891f 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -25,7 +25,6 @@
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
@@ -44,7 +43,6 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -520,6 +518,14 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+            int badgeDensity) {
+        throw new UnsupportedOperationException();
+    }
+
+
     @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         throw new UnsupportedOperationException();
@@ -602,14 +608,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @hide */
-    @Override
-    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,
-            int flags, String installerPackageName, int userId) {
-        throw new UnsupportedOperationException();
-    }
-
-
     @Override
     public void setInstallerPackageName(String targetPackage,
             String installerPackageName) {
@@ -760,6 +758,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public void flushPackageRestrictionsAsUser(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void addPreferredActivity(IntentFilter filter,
             int match, ComponentName[] set, ComponentName activity) {
@@ -873,26 +877,6 @@
      * @hide
      */
     @Override
-    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
     public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
             UserHandle user) {
         return false;
@@ -1024,27 +1008,6 @@
      * @hide
      */
     @Override
-    public void installPackageWithVerification(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
     public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
             int flags) {
         throw new UnsupportedOperationException();
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 8b8d604..033312b 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -60,7 +60,9 @@
     // optional parameter: comma separated list of required account types before proceeding
     // with the app launch
     private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
-    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
+    private static final String WEARABLE_ACTION_GOOGLE =
+            "com.google.android.wearable.action.GOOGLE";
+    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 60000; //60s to allow app to idle
     private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
     private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
 
@@ -158,7 +160,7 @@
         for (String pair : appNames) {
             String[] parts = pair.split("\\^");
             if (parts.length != 2) {
-                Log.e(TAG, "The apps key is incorectly formatted");
+                Log.e(TAG, "The apps key is incorrectly formatted");
                 fail();
             }
 
@@ -174,6 +176,10 @@
         }
     }
 
+    private boolean hasLeanback(Context context) {
+        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+    }
+
     private void createMappings() {
         mNameToIntent = new LinkedHashMap<String, Intent>();
         mNameToProcess = new LinkedHashMap<String, String>();
@@ -181,8 +187,18 @@
         PackageManager pm = getInstrumentation().getContext()
                 .getPackageManager();
         Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
-        intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+        intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
+                Intent.CATEGORY_LEANBACK_LAUNCHER :
+                Intent.CATEGORY_LAUNCHER);
         List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+        resolveLoop(ris, intentToResolve, pm);
+        // For Wear
+        intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
+        ris = pm.queryIntentActivities(intentToResolve, 0);
+        resolveLoop(ris, intentToResolve, pm);
+    }
+
+    private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
         if (ris == null || ris.isEmpty()) {
             Log.i(TAG, "Could not find any apps");
         } else {
@@ -223,7 +239,7 @@
         // report error if any of the following is true:
         // * launch thread is alive
         // * result is not null, but:
-        //   * result is not START_SUCESS
+        //   * result is not START_SUCCESS
         //   * or in case of no force stop, result is not TASK_TO_FRONT either
         if (t.isAlive() || (result != null
                 && ((result.result != ActivityManager.START_SUCCESS)
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs
index caa947d..0a1742e 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs
@@ -14,10 +14,14 @@
 
     for (int x = 0; x < HEIGHT; x += REGION_SIZE) {
         bool interestingRegion = false;
-        int regionColor = (int) rsGetElementAt_uchar4(ideal, x, y);
+        uchar4 regionColor = rsGetElementAt_uchar4(ideal, x, y);
         for (int i = 0; i < REGION_SIZE && !interestingRegion; i++) {
             for (int j = 0; j < REGION_SIZE && !interestingRegion; j++) {
-                interestingRegion |= ((int) rsGetElementAt_uchar4(ideal, x + j, y + i)) != regionColor;
+                uchar4 testVal = rsGetElementAt_uchar4(ideal, x + j, y + i);
+                interestingRegion |= (testVal.r != regionColor.r);
+                interestingRegion |= (testVal.g != regionColor.g);
+                interestingRegion |= (testVal.b != regionColor.b);
+                interestingRegion |= (testVal.a != regionColor.a);
             }
         }
         if (interestingRegion) {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index de7b9c2..18fd985 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -347,6 +347,15 @@
         </activity>
 
         <activity
+                android:name="SingleFrameTextureViewTestActivity"
+                android:label="TextureView/SingleFrameTextureViewTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="HardwareCanvasSurfaceViewActivity"
                 android:label="SurfaceView/HardwareCanvas">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg b/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg
deleted file mode 100644
index 5acad94..0000000
--- a/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
new file mode 100644
index 0000000..187a6c0
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
index 1f2b939..1ea9f9c 100644
--- a/tests/HwAccelerationTest/res/layout/projection_clipping.xml
+++ b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
@@ -3,24 +3,32 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <FrameLayout
+    <ScrollView
+        android:orientation="vertical"
         android:translationX="50dp"
         android:translationY="50dp"
         android:elevation="30dp"
         android:layout_width="200dp"
         android:layout_height="200dp"
         android:background="@drawable/round_rect_background">
-        <View
-            android:id="@+id/clickable1"
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:background="?android:attr/selectableItemBackgroundBorderless"/>
-        <View
-            android:id="@+id/clickable2"
-            android:translationX="50dp"
-            android:translationY="10dp"
-            android:layout_width="150dp"
-            android:layout_height="100dp"
-            android:background="?android:attr/selectableItemBackgroundBorderless"/>
-    </FrameLayout>
+        <FrameLayout
+            android:layout_width="200dp"
+            android:layout_height="wrap_content">
+            <View
+                android:layout_width="200dp"
+                android:layout_height="2000dp"/>
+            <View
+                android:id="@+id/clickable1"
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:background="?android:attr/selectableItemBackgroundBorderless"/>
+            <View
+                android:id="@+id/clickable2"
+                android:translationX="50dp"
+                android:translationY="10dp"
+                android:layout_width="150dp"
+                android:layout_height="100dp"
+                android:background="?android:attr/selectableItemBackgroundBorderless"/>
+       </FrameLayout>
+    </ScrollView>
 </LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java
new file mode 100644
index 0000000..4d3826b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLUtils;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+public class SingleFrameTextureViewTestActivity extends Activity implements SurfaceTextureListener {
+    private static final String LOG_TAG = "SingleFrameTest";
+
+    private View mPreview;
+    private TextureView mTextureView;
+    private Thread mGLThread;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        TextView preview = new TextView(this);
+        preview.setText("This is a preview");
+        preview.setBackgroundColor(Color.WHITE);
+        mPreview = preview;
+        mTextureView = new TextureView(this);
+        mTextureView.setSurfaceTextureListener(this);
+
+        FrameLayout content = new FrameLayout(this);
+        content.addView(mTextureView,
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        content.addView(mPreview,
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+        setContentView(content);
+    }
+
+    private void stopGlThread() {
+        if (mGLThread != null) {
+            try {
+                mGLThread.join();
+                mGLThread = null;
+            } catch (InterruptedException e) { }
+        }
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        Log.d(LOG_TAG, "onSurfaceAvailable");
+        mGLThread = new Thread() {
+            static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+            static final int EGL_OPENGL_ES2_BIT = 4;
+
+            private EGL10 mEgl;
+            private EGLDisplay mEglDisplay;
+            private EGLConfig mEglConfig;
+            private EGLContext mEglContext;
+            private EGLSurface mEglSurface;
+
+            @Override
+            public void run() {
+                initGL();
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {}
+
+                for (int i = 0; i < 2; i++) {
+                    if (i == 0) {
+                        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+                    } else {
+                        glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+                    }
+                    glClear(GL_COLOR_BUFFER_BIT);
+                    Log.d(LOG_TAG, "eglSwapBuffers");
+                    if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                        throw new RuntimeException("Cannot swap buffers");
+                    }
+                    try {
+                        Thread.sleep(50);
+                    } catch (InterruptedException e) {}
+                }
+
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {}
+
+                finishGL();
+            }
+
+            private void finishGL() {
+                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+            }
+
+            private void initGL() {
+                mEgl = (EGL10) EGLContext.getEGL();
+
+                mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+                if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+                    throw new RuntimeException("eglGetDisplay failed "
+                            + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+                }
+
+                int[] version = new int[2];
+                if (!mEgl.eglInitialize(mEglDisplay, version)) {
+                    throw new RuntimeException("eglInitialize failed " +
+                            GLUtils.getEGLErrorString(mEgl.eglGetError()));
+                }
+
+                mEglConfig = chooseEglConfig();
+                if (mEglConfig == null) {
+                    throw new RuntimeException("eglConfig not initialized");
+                }
+
+                mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+                mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
+
+                if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+                    int error = mEgl.eglGetError();
+                    if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+                        Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                        return;
+                    }
+                    throw new RuntimeException("createWindowSurface failed "
+                            + GLUtils.getEGLErrorString(error));
+                }
+
+                if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                    throw new RuntimeException("eglMakeCurrent failed "
+                            + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+                }
+            }
+
+
+            EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+                int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+                return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+            }
+
+            private EGLConfig chooseEglConfig() {
+                int[] configsCount = new int[1];
+                EGLConfig[] configs = new EGLConfig[1];
+                int[] configSpec = getConfig();
+                if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+                    throw new IllegalArgumentException("eglChooseConfig failed " +
+                            GLUtils.getEGLErrorString(mEgl.eglGetError()));
+                } else if (configsCount[0] > 0) {
+                    return configs[0];
+                }
+                return null;
+            }
+
+            private int[] getConfig() {
+                return new int[] {
+                        EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                        EGL10.EGL_RED_SIZE, 8,
+                        EGL10.EGL_GREEN_SIZE, 8,
+                        EGL10.EGL_BLUE_SIZE, 8,
+                        EGL10.EGL_ALPHA_SIZE, 8,
+                        EGL10.EGL_DEPTH_SIZE, 0,
+                        EGL10.EGL_STENCIL_SIZE, 0,
+                        EGL10.EGL_NONE
+                };
+            }
+        };
+        mGLThread.start();
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        Log.d(LOG_TAG, "onSurfaceTextureSizeChanged");
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        Log.d(LOG_TAG, "onSurfaceTextureDestroyed");
+        stopGlThread();
+        return true;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+        Log.d(LOG_TAG, "onSurfaceTextureUpdated");
+        mPreview.setVisibility(View.GONE);
+    }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
index cb77118..a169b18 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
@@ -1,35 +1,35 @@
-/*

- * 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.locationtracker;

-

-import android.os.Bundle;

-import android.preference.PreferenceActivity;

-

-/**

- * Settings preference screen for location tracker

- */

-public class SettingsActivity extends PreferenceActivity {

-

-    @Override

-    protected void onCreate(Bundle savedInstanceState) {

-        super.onCreate(savedInstanceState);

-

-        // Load the preferences from an XML resource

-        addPreferencesFromResource(R.xml.preferences);

-    }

-

-}

+/*
+ * 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.locationtracker;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Settings preference screen for location tracker
+ */
+public class SettingsActivity extends PreferenceActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Load the preferences from an XML resource
+        addPreferencesFromResource(R.xml.preferences);
+    }
+
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
index 55d4d1e..adc39b3 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
@@ -1,75 +1,75 @@
-/*

- * 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.locationtracker.data;

-

-import android.app.ListActivity;

-import android.content.Context;

-import android.database.Cursor;

-import android.view.View;

-import android.widget.ResourceCursorAdapter;

-import android.widget.TextView;

-

-import com.android.locationtracker.R;

-

-/**

- * Used to bind Tracker data to a list view UI

- */

-public class TrackerListHelper extends TrackerDataHelper {

-

-    private ListActivity mActivity;

-

-    // sort entries by most recent first

-    private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";

-

-    public TrackerListHelper(ListActivity activity) {

-        super(activity, TrackerDataHelper.CSV_FORMATTER);

-        mActivity = activity;

-    }

-

-    /**

-     * Helper method for binding the list activities UI to the tracker data

-     * Tracker data will be sorted in most-recent first order

-     * Will enable automatic UI changes as tracker data changes

-     *

-     * @param layout - layout to populate data

-     */

-    public void bindListUI(int layout) {

-        Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,

-                TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);

-        // Used to map tracker entries from the database to views

-        TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);

-        mActivity.setListAdapter(adapter);

-        cursor.setNotificationUri(mActivity.getContentResolver(),

-                TrackerProvider.CONTENT_URI);

-

-    }

-

-    private class TrackerAdapter extends ResourceCursorAdapter {

-

-        public TrackerAdapter(Context context, int layout, Cursor c) {

-            super(context, layout, c);

-        }

-

-        @Override

-        public void bindView(View view, Context context, Cursor cursor) {

-            final TextView v = (TextView) view

-                    .findViewById(R.id.entrylist_item);

-            String rowText = mFormatter.getOutput(TrackerEntry

-                    .createEntry(cursor));

-            v.setText(rowText);

-        }

-    }

-}

+/*
+ * 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.locationtracker.data;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.database.Cursor;
+import android.view.View;
+import android.widget.ResourceCursorAdapter;
+import android.widget.TextView;
+
+import com.android.locationtracker.R;
+
+/**
+ * Used to bind Tracker data to a list view UI
+ */
+public class TrackerListHelper extends TrackerDataHelper {
+
+    private ListActivity mActivity;
+
+    // sort entries by most recent first
+    private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";
+
+    public TrackerListHelper(ListActivity activity) {
+        super(activity, TrackerDataHelper.CSV_FORMATTER);
+        mActivity = activity;
+    }
+
+    /**
+     * Helper method for binding the list activities UI to the tracker data
+     * Tracker data will be sorted in most-recent first order
+     * Will enable automatic UI changes as tracker data changes
+     *
+     * @param layout - layout to populate data
+     */
+    public void bindListUI(int layout) {
+        Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,
+                TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);
+        // Used to map tracker entries from the database to views
+        TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);
+        mActivity.setListAdapter(adapter);
+        cursor.setNotificationUri(mActivity.getContentResolver(),
+                TrackerProvider.CONTENT_URI);
+
+    }
+
+    private class TrackerAdapter extends ResourceCursorAdapter {
+
+        public TrackerAdapter(Context context, int layout, Cursor c) {
+            super(context, layout, c);
+        }
+
+        @Override
+        public void bindView(View view, Context context, Cursor cursor) {
+            final TextView v = (TextView) view
+                    .findViewById(R.id.entrylist_item);
+            String rowText = mFormatter.getOutput(TrackerEntry
+                    .createEntry(cursor));
+            v.setText(rowText);
+        }
+    }
+}
diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource.xml
new file mode 100644
index 0000000..8093b9d
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+  <base-config>
+    <trust-anchors>
+    </trust-anchors>
+  </base-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource_debug.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource_debug.xml
new file mode 100644
index 0000000..fc24df5
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource_debug.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- debug-overrides not inside network-security-config should cause a parsing error -->
+<debug-overrides>
+  <trust-anchors>
+    <certificates src="system" />
+  </trust-anchors>
+</debug-overrides>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
new file mode 100644
index 0000000..5d23d36e
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+  <domain-config>
+    <domain>android.com
+    </domain>
+    <domain>   developer.android.com    </domain>
+    <pin-set>
+      <pin digest="SHA-256">  7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=  </pin>
+    </pin-set>
+  </domain-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource.xml b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource.xml
new file mode 100644
index 0000000..8093b9d
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+  <base-config>
+    <trust-anchors>
+    </trust-anchors>
+  </base-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource_debug.xml b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource_debug.xml
new file mode 100644
index 0000000..6a2ad37
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource_debug.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+  <debug-overrides>
+    <trust-anchors>
+      <certificates src="system" />
+    </trust-anchors>
+  </debug-overrides>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index 9f48d56..eda3f5e 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -17,19 +17,28 @@
 package android.security.net.config;
 
 import android.app.Activity;
+import android.os.Build;
 import android.test.ActivityUnitTestCase;
 import android.util.ArraySet;
 import android.util.Pair;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.Socket;
 import java.net.URL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.TrustManager;
 
+import com.android.org.conscrypt.TrustedCertificateStore;
+
 public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
 
     public NetworkSecurityConfigTests() {
@@ -40,6 +49,51 @@
     private static final byte[] G2_SPKI_SHA256
             = hexToBytes("ec722969cb64200ab6638f68ac538e40abab5b19a6485661042a1061c4612776");
 
+    private static final byte[] TEST_CA_BYTES
+            = hexToBytes(
+                    "3082036130820249a003020102020900bd54597d6750ea62300d06092a86"
+                    + "4886f70d01010b05003047310b3009060355040613025553310b30090603"
+                    + "5504080c0243413110300e060355040a0c07416e64726f69643119301706"
+                    + "035504030c104e53436f6e6669672054657374204341301e170d31363032"
+                    + "32343030313130325a170d3136303332353030313130325a3047310b3009"
+                    + "060355040613025553310b300906035504080c0243413110300e06035504"
+                    + "0a0c07416e64726f69643119301706035504030c104e53436f6e66696720"
+                    + "5465737420434130820122300d06092a864886f70d01010105000382010f"
+                    + "003082010a0282010100e15ce8fd5794029841e760d68d6e0159c9c67630"
+                    + "089775bc728d83dae7e29e23fe5f6e113b789f4c5b22f052300ec6d5faa5"
+                    + "724432e7bac96682792ef6e9617c939c4329dce8788cbdf3a11b621fac9e"
+                    + "2edbec2d7e5e07296bbb544b89263137a6a31573a2362e05ca8ff9c886bf"
+                    + "52df4ff93c45475145a40a83f2670e23669220a5a4bf2c6860edb78d3022"
+                    + "192fb5dc5e8c118f70870f89da292dfe522751462f020ed556653c8b07f8"
+                    + "89712a6e8196c457a637439e3073d7d917ab55aa51a146826367f7b5922a"
+                    + "64fb2f95099de21eb98341fa76faa79ffbda123fe5b8adc614b16174e8b0"
+                    + "dfdac2bbc4d526d2487ad2b009d53996ec23ffbd732112efa66b02030100"
+                    + "01a350304e301d0603551d0e04160414f66e1a95486c879edd60a5756bc2"
+                    + "f1f4677e128e301f0603551d23041830168014f66e1a95486c879edd60a5"
+                    + "756bc2f1f4677e128e300c0603551d13040530030101ff300d06092a8648"
+                    + "86f70d01010b05000382010100d2856130dccae24e5f8901900d94bc642f"
+                    + "85466ab7cfa1066399077a168cd4b56603a9e2af9d2e58aec13101e338a4"
+                    + "8e95e9c7a84d7991f0d381d4965eaada1b80fbbd8277445f449babe64f53"
+                    + "ba625387460b592a1a97b14b8251115e6610350021a6e716ae22b905f8d4"
+                    + "eae24e668e71b12ab51fd2f2bb600e074487dec720c3db14dbca504844b6"
+                    + "933bb0248283ea95464747689c37d706d4839c7d0e9bd86abf98ddce5d36"
+                    + "8b38bfe5062353e28d5be378827fade1caa6bba3df9cd9ebf83d839eae52"
+                    + "780181f31973f15f982686ba6d899f7b644fd1f26c8ebb99f4c986faaf4c"
+                    + "1b9e3d9d391943ce3fb9fa2e631bd66b8ef3d47fd85acf09ea3a30f15f");
+
+    private static final X509Certificate TEST_CA_CERT;
+
+    static {
+        try {
+            CertificateFactory factory = CertificateFactory.getInstance("X.509");
+            Certificate cert = factory.generateCertificate(new ByteArrayInputStream(TEST_CA_BYTES));
+            TEST_CA_CERT = (X509Certificate) cert;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
     private static byte[] hexToBytes(String s) {
         int len = s.length();
         byte[] data = new byte[len / 2];
@@ -51,7 +105,6 @@
     }
 
 
-
     /**
      * Return a NetworkSecurityConfig that has an empty TrustAnchor set. This should always cause a
      * SSLHandshakeException when used for a connection.
@@ -174,7 +227,7 @@
     public void testConfigBuilderUsesParents() throws Exception {
         // Check that a builder with a parent uses the parent's values when non is set.
         NetworkSecurityConfig config = new NetworkSecurityConfig.Builder()
-                .setParent(NetworkSecurityConfig.getDefaultBuilder())
+                .setParent(NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N))
                 .build();
         assert(!config.getTrustAnchors().isEmpty());
     }
@@ -208,4 +261,38 @@
         TestUtils.assertUrlConnectionSucceeds(context, "developer.android.com", 443);
         TestUtils.assertUrlConnectionFails(context, "google.com", 443);
     }
+
+    public void testUserAddedCaOptIn() throws Exception {
+        TrustedCertificateStore store = new TrustedCertificateStore();
+        try {
+            // Install the test CA.
+            store.installCertificate(TEST_CA_CERT);
+            NetworkSecurityConfig preNConfig =
+                    NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.M).build();
+            NetworkSecurityConfig nConfig =
+                    NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N).build();
+            Set<TrustAnchor> preNAnchors = preNConfig.getTrustAnchors();
+            Set<TrustAnchor> nAnchors = nConfig.getTrustAnchors();
+            Set<X509Certificate> preNCerts = new HashSet<X509Certificate>();
+            for (TrustAnchor anchor : preNAnchors) {
+                preNCerts.add(anchor.certificate);
+            }
+            Set<X509Certificate> nCerts = new HashSet<X509Certificate>();
+            for (TrustAnchor anchor : nAnchors) {
+                nCerts.add(anchor.certificate);
+            }
+            assertTrue(preNCerts.contains(TEST_CA_CERT));
+            assertFalse(nCerts.contains(TEST_CA_CERT));
+        } finally {
+            // Delete the user added CA. We don't know the alias so just delete them all.
+            for (String alias : store.aliases()) {
+                if (store.isUser(alias)) {
+                    try {
+                        store.deleteCertificateEntry(alias);
+                    } catch (Exception ignored) {
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
index 4c12c2d..0412bc7 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
@@ -65,4 +65,9 @@
         }
         return certs;
     }
+
+    @Override
+    public void handleTrustStorageUpdate() {
+        // Nothing to do.
+    }
 }
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index 35e3ef4..f7066a6 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -431,4 +431,49 @@
         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
     }
+
+    public void testExtraDebugResource() throws Exception {
+        XmlConfigSource source =
+                new XmlConfigSource(getContext(), R.xml.extra_debug_resource, true);
+        ApplicationConfig appConfig = new ApplicationConfig(source);
+        assertFalse(appConfig.hasPerDomainConfigs());
+        NetworkSecurityConfig config = appConfig.getConfigForHostname("");
+        MoreAsserts.assertNotEmpty(config.getTrustAnchors());
+
+        // Check that the _debug file is ignored if debug is false.
+        source = new XmlConfigSource(getContext(), R.xml.extra_debug_resource, false);
+        appConfig = new ApplicationConfig(source);
+        assertFalse(appConfig.hasPerDomainConfigs());
+        config = appConfig.getConfigForHostname("");
+        MoreAsserts.assertEmpty(config.getTrustAnchors());
+    }
+
+    public void testExtraDebugResourceIgnored() throws Exception {
+        // Verify that parsing the extra debug config resource fails only when debugging is true.
+        XmlConfigSource source =
+                new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, false);
+        ApplicationConfig appConfig = new ApplicationConfig(source);
+        // Force parsing the config file.
+        appConfig.getConfigForHostname("");
+
+        source = new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, true);
+        appConfig = new ApplicationConfig(source);
+        try {
+            appConfig.getConfigForHostname("");
+            fail("Bad extra debug resource did not fail to parse");
+        } catch (RuntimeException expected) {
+        }
+    }
+
+    public void testDomainWhitespaceTrimming() throws Exception {
+        XmlConfigSource source =
+                new XmlConfigSource(getContext(), R.xml.domain_whitespace, false);
+        ApplicationConfig appConfig = new ApplicationConfig(source);
+        NetworkSecurityConfig defaultConfig = appConfig.getConfigForHostname("");
+        MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("developer.android.com"));
+        MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("android.com"));
+        SSLContext context = TestUtils.getSSLContext(source);
+        TestUtils.assertConnectionSucceeds(context, "android.com", 443);
+        TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
+    }
 }
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
index c8a8d6c..6463e1f 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
@@ -47,7 +47,7 @@
         OnBufferingUpdateListener, OnCompletionListener, OnErrorListener,
         OnAudioFocusChangeListener {
     private static final String TAG = "MediaPlayerManager";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
     private static long sDebugInstanceId = 0;
 
     private static final String[] SUPPORTED_FEATURES = {
diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml
index a72b3dd..71d6001 100644
--- a/tests/SoundTriggerTestApp/AndroidManifest.xml
+++ b/tests/SoundTriggerTestApp/AndroidManifest.xml
@@ -2,10 +2,12 @@
         package="com.android.test.soundtrigger">
 
     <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
     <application>
         <activity
             android:name="TestSoundTriggerActivity"
             android:label="SoundTrigger Test Application"
+            android:screenOrientation="portrait"
             android:theme="@android:style/Theme.Material">
             <!--
             <intent-filter>
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
index 3149783..3ca96d2 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
@@ -28,6 +28,8 @@
 import android.text.Editable;
 import android.text.method.ScrollingMovementMethod;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.PowerManager;
 import android.os.UserManager;
 import android.util.Log;
 import android.view.View;
@@ -38,7 +40,7 @@
 
 public class TestSoundTriggerActivity extends Activity {
     private static final String TAG = "TestSoundTriggerActivity";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     private SoundTriggerUtil mSoundTriggerUtil;
     private Random mRandom;
@@ -54,6 +56,8 @@
     private TextView mDebugView = null;
     private int mSelectedModelId = 1;
     private ScrollView mScrollView = null;
+    private PowerManager.WakeLock mScreenWakelock;
+    private Handler mHandler;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -66,6 +70,7 @@
         mDebugView.setMovementMethod(new ScrollingMovementMethod());
         mSoundTriggerUtil = new SoundTriggerUtil(this);
         mRandom = new Random();
+        mHandler = new Handler();
     }
 
     private void postMessage(String msg) {
@@ -85,24 +90,43 @@
         });
     }
 
-    private UUID getSelectedUuid() {
+    private synchronized UUID getSelectedUuid() {
         if (mSelectedModelId == 2) return mModelUuid2;
         if (mSelectedModelId == 3) return mModelUuid3;
         return mModelUuid1;  // Default.
     }
 
-    private void setDetector(SoundTriggerDetector detector) {
-        if (mSelectedModelId == 2) mDetector2 = detector;
-        if (mSelectedModelId == 3) mDetector3 = detector;
+    private synchronized void setDetector(SoundTriggerDetector detector) {
+        if (mSelectedModelId == 2) {
+            mDetector2 = detector;
+            return;
+        }
+        if (mSelectedModelId == 3) {
+            mDetector3 = detector;
+            return;
+        }
         mDetector1 = detector;
     }
 
-    private SoundTriggerDetector getDetector() {
+    private synchronized SoundTriggerDetector getDetector() {
         if (mSelectedModelId == 2) return mDetector2;
         if (mSelectedModelId == 3) return mDetector3;
         return mDetector1;
     }
 
+    private void screenWakeup() {
+        PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE));
+        if (mScreenWakelock == null) {
+            mScreenWakelock =  pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG");
+        }
+        mScreenWakelock.acquire();
+    }
+
+    private void screenRelease() {
+        PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE));
+        mScreenWakelock.release();
+    }
+
     /**
      * Called when the user clicks the enroll button.
      * Performs a fresh enrollment.
@@ -139,7 +163,7 @@
             Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
             return;
         }
-        boolean status = mSoundTriggerUtil.deleteSoundModel(mModelUuid1);
+        boolean status = mSoundTriggerUtil.deleteSoundModel(modelUuid);
         if (status) {
             Toast.makeText(this, "Successfully deleted model UUID=" + soundModel.uuid,
                     Toast.LENGTH_SHORT)
@@ -180,7 +204,10 @@
         UUID modelUuid = getSelectedUuid();
         SoundTriggerDetector detector = getDetector();
         if (detector == null) {
-            Log.i(TAG, "Created an instance of the SoundTriggerDetector.");
+            Log.i(TAG, "Created an instance of the SoundTriggerDetector for model #" +
+                    mSelectedModelId);
+            postMessage("Created an instance of the SoundTriggerDetector for model #" +
+                    mSelectedModelId);
             detector = mSoundTriggerUtil.createSoundTriggerDetector(modelUuid,
                     new DetectorCallback());
             setDetector(detector);
@@ -189,6 +216,7 @@
         if (!detector.startRecognition(
                 SoundTriggerDetector.RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS)) {
             Log.e(TAG, "Fast failure attempting to start recognition.");
+            postMessage("Fast failure attempting to start recognition:" + mSelectedModelId);
         }
     }
 
@@ -196,30 +224,38 @@
         SoundTriggerDetector detector = getDetector();
         if (detector == null) {
             Log.e(TAG, "Stop called on null detector.");
+            postMessage("Error: Stop called on null detector.");
             return;
         }
         postMessage("Triggering stop recognition for model: " + mSelectedModelId);
         if (!detector.stopRecognition()) {
             Log.e(TAG, "Fast failure attempting to stop recognition.");
+            postMessage("Fast failure attempting to stop recognition: " + mSelectedModelId);
         }
     }
 
-    public void onRadioButtonClicked(View view) {
+    public synchronized void onRadioButtonClicked(View view) {
         // Is the button now checked?
         boolean checked = ((RadioButton) view).isChecked();
         // Check which radio button was clicked
         switch(view.getId()) {
             case R.id.model_one:
-                if (checked) mSelectedModelId = 1;
-                postMessage("Selected model one.");
+                if (checked) {
+                    mSelectedModelId = 1;
+                    postMessage("Selected model one.");
+                }
                 break;
             case R.id.model_two:
-                if (checked) mSelectedModelId = 2;
-                postMessage("Selected model two.");
+                if (checked) {
+                    mSelectedModelId = 2;
+                    postMessage("Selected model two.");
+                }
                 break;
             case R.id.model_three:
-                if (checked) mSelectedModelId = 3;
-                postMessage("Selected model three.");
+                if (checked) {
+                    mSelectedModelId = 3;
+                    postMessage("Selected model three.");
+                }
                 break;
         }
     }
@@ -232,6 +268,13 @@
 
         public void onDetected(SoundTriggerDetector.EventPayload event) {
             postMessage("onDetected(): " + eventPayloadToString(event));
+            screenWakeup();
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                   screenRelease();
+                }
+            }, 1000L);
         }
 
         public void onError() {
diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
index 407a9d7..e67134d 100644
--- a/tests/SoundTriggerTests/Android.mk
+++ b/tests/SoundTriggerTests/Android.mk
@@ -18,8 +18,16 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+ifeq ($(SOUND_TRIGGER_USE_STUB_MODULE), 1)
+  LOCAL_SRC_FILES := $(call all-subdir-java-files)
+  LOCAL_PRIVILEGED_MODULE := true
+  LOCAL_CERTIFICATE := platform
+  TARGET_OUT_DATA_APPS_PRIVILEGED := $(TARGET_OUT_DATA)/priv-app
+else
+  LOCAL_SRC_FILES := src/android/hardware/soundtrigger/SoundTriggerTest.java
+endif
 
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := SoundTriggerTests
diff --git a/tests/SoundTriggerTests/AndroidManifest.xml b/tests/SoundTriggerTests/AndroidManifest.xml
index 5e5a108..f7454c7 100644
--- a/tests/SoundTriggerTests/AndroidManifest.xml
+++ b/tests/SoundTriggerTests/AndroidManifest.xml
@@ -14,7 +14,11 @@
      limitations under the License.
 -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.hardware.soundtrigger">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.hardware.soundtrigger">
+    <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
new file mode 100644
index 0000000..c0583ce
--- /dev/null
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.soundtrigger;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.ParcelUuid;
+import android.os.ServiceManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.io.DataOutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.UUID;
+
+import org.mockito.MockitoAnnotations;
+
+public class GenericSoundModelTest extends AndroidTestCase {
+    static final int MSG_DETECTION_ERROR = -1;
+    static final int MSG_DETECTION_RESUME = 0;
+    static final int MSG_DETECTION_PAUSE = 1;
+    static final int MSG_KEYPHRASE_TRIGGER = 2;
+    static final int MSG_GENERIC_TRIGGER = 4;
+
+    private Random random = new Random();
+    private HashSet<UUID> loadedModelUuids;
+    private ISoundTriggerService soundTriggerService;
+    private SoundTriggerManager soundTriggerManager;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+
+        Context context = getContext();
+        soundTriggerService = ISoundTriggerService.Stub.asInterface(
+                ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
+        soundTriggerManager = (SoundTriggerManager) context.getSystemService(
+                Context.SOUND_TRIGGER_SERVICE);
+
+        loadedModelUuids = new HashSet<UUID>();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        for (UUID modelUuid : loadedModelUuids) {
+            soundTriggerService.deleteSoundModel(new ParcelUuid(modelUuid));
+        }
+        super.tearDown();
+    }
+
+    GenericSoundModel new_sound_model() {
+        // Create sound model
+        byte[] data = new byte[1024];
+        random.nextBytes(data);
+        UUID modelUuid = UUID.randomUUID();
+        UUID mVendorUuid = UUID.randomUUID();
+        return new GenericSoundModel(modelUuid, mVendorUuid, data);
+    }
+
+    @SmallTest
+    public void testUpdateGenericSoundModel() throws Exception {
+        GenericSoundModel model = new_sound_model();
+
+        // Update sound model
+        soundTriggerService.updateSoundModel(model);
+        loadedModelUuids.add(model.uuid);
+
+        // Confirm it was updated
+        GenericSoundModel returnedModel =
+                soundTriggerService.getSoundModel(new ParcelUuid(model.uuid));
+        assertEquals(model, returnedModel);
+    }
+
+    @SmallTest
+    public void testDeleteGenericSoundModel() throws Exception {
+        GenericSoundModel model = new_sound_model();
+
+        // Update sound model
+        soundTriggerService.updateSoundModel(model);
+        loadedModelUuids.add(model.uuid);
+
+        // Delete sound model
+        soundTriggerService.deleteSoundModel(new ParcelUuid(model.uuid));
+        loadedModelUuids.remove(model.uuid);
+
+        // Confirm it was deleted
+        GenericSoundModel returnedModel =
+                soundTriggerService.getSoundModel(new ParcelUuid(model.uuid));
+        assertEquals(null, returnedModel);
+    }
+
+    @LargeTest
+    public void testStartStopGenericSoundModel() throws Exception {
+        GenericSoundModel model = new_sound_model();
+
+        boolean captureTriggerAudio = true;
+        boolean allowMultipleTriggers = true;
+        RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
+                null, null);
+        TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback());
+
+        // Update and start sound model recognition
+        soundTriggerService.updateSoundModel(model);
+        loadedModelUuids.add(model.uuid);
+        int r = soundTriggerService.startRecognition(new ParcelUuid(model.uuid), spyCallback,
+                config);
+        assertEquals("Could Not Start Recognition with code: " + r,
+                android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+
+        // Stop recognition
+        r = soundTriggerService.stopRecognition(new ParcelUuid(model.uuid), spyCallback);
+        assertEquals("Could Not Stop Recognition with code: " + r,
+                android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+    }
+
+    @LargeTest
+    public void testTriggerGenericSoundModel() throws Exception {
+        GenericSoundModel model = new_sound_model();
+
+        boolean captureTriggerAudio = true;
+        boolean allowMultipleTriggers = true;
+        RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
+                null, null);
+        TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback());
+
+        // Update and start sound model
+        soundTriggerService.updateSoundModel(model);
+        loadedModelUuids.add(model.uuid);
+        soundTriggerService.startRecognition(new ParcelUuid(model.uuid), spyCallback, config);
+
+        // Send trigger to stub HAL
+        Socket socket = new Socket(InetAddress.getLocalHost(), 14035);
+        DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+        out.writeBytes("trig " + model.uuid.toString() + "\r\n");
+        out.flush();
+        socket.close();
+
+        // Verify trigger was received
+        verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
+    }
+
+    /**
+     * Tests a more complicated pattern of loading, unloading, triggering, starting and stopping
+     * recognition. Intended to find unexpected errors that occur in unexpected states.
+     */
+    @LargeTest
+    public void testFuzzGenericSoundModel() throws Exception {
+        int numModels = 2;
+
+        final int STATUS_UNLOADED = 0;
+        final int STATUS_LOADED = 1;
+        final int STATUS_STARTED = 2;
+
+        class ModelInfo {
+            int status;
+            GenericSoundModel model;
+
+            public ModelInfo(GenericSoundModel model, int status) {
+                this.status = status;
+                this.model = model;
+            }
+        }
+
+        Random predictableRandom = new Random(100);
+
+        ArrayList modelInfos = new ArrayList<ModelInfo>();
+        for(int i=0; i<numModels; i++) {
+            // Create sound model
+            byte[] data = new byte[1024];
+            predictableRandom.nextBytes(data);
+            UUID modelUuid = UUID.randomUUID();
+            UUID mVendorUuid = UUID.randomUUID();
+            GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+            ModelInfo modelInfo = new ModelInfo(model, STATUS_UNLOADED);
+            modelInfos.add(modelInfo);
+        }
+
+        boolean captureTriggerAudio = true;
+        boolean allowMultipleTriggers = true;
+        RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
+                null, null);
+        TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback());
+
+
+        int numOperationsToRun = 100;
+        for(int i=0; i<numOperationsToRun; i++) {
+            // Select a random model
+            int modelInfoIndex = predictableRandom.nextInt(modelInfos.size());
+            ModelInfo modelInfo = (ModelInfo) modelInfos.get(modelInfoIndex);
+
+            // Perform a random operation
+            int operation = predictableRandom.nextInt(5);
+
+            if (operation == 0 && modelInfo.status == STATUS_UNLOADED) {
+                // Update and start sound model
+                soundTriggerService.updateSoundModel(modelInfo.model);
+                loadedModelUuids.add(modelInfo.model.uuid);
+                modelInfo.status = STATUS_LOADED;
+            } else if (operation == 1 && modelInfo.status == STATUS_LOADED) {
+                // Start the sound model
+                int r = soundTriggerService.startRecognition(new ParcelUuid(modelInfo.model.uuid),
+                        spyCallback, config);
+                assertEquals("Could Not Start Recognition with code: " + r,
+                        android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+                modelInfo.status = STATUS_STARTED;
+            } else if (operation == 2 && modelInfo.status == STATUS_STARTED) {
+                // Send trigger to stub HAL
+                Socket socket = new Socket(InetAddress.getLocalHost(), 14035);
+                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+                out.writeBytes("trig " + modelInfo.model.uuid + "\r\n");
+                out.flush();
+                socket.close();
+
+                // Verify trigger was received
+                verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
+                reset(spyCallback);
+            } else if (operation == 3 && modelInfo.status == STATUS_STARTED) {
+                // Stop recognition
+                int r = soundTriggerService.stopRecognition(new ParcelUuid(modelInfo.model.uuid),
+                        spyCallback);
+                assertEquals("Could Not Stop Recognition with code: " + r,
+                        android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+                modelInfo.status = STATUS_LOADED;
+            } else if (operation == 4 && modelInfo.status != STATUS_UNLOADED) {
+                // Delete sound model
+                soundTriggerService.deleteSoundModel(new ParcelUuid(modelInfo.model.uuid));
+                loadedModelUuids.remove(modelInfo.model.uuid);
+
+                // Confirm it was deleted
+                GenericSoundModel returnedModel =
+                        soundTriggerService.getSoundModel(new ParcelUuid(modelInfo.model.uuid));
+                assertEquals(null, returnedModel);
+                modelInfo.status = STATUS_UNLOADED;
+            }
+        }
+    }
+
+    public class TestRecognitionStatusCallback extends IRecognitionStatusCallback.Stub {
+        @Override
+        public void onGenericSoundTriggerDetected(GenericRecognitionEvent recognitionEvent) {
+        }
+
+        @Override
+        public void onKeyphraseDetected(KeyphraseRecognitionEvent recognitionEvent) {
+        }
+
+        @Override
+        public void onError(int status) {
+        }
+
+        @Override
+        public void onRecognitionPaused() {
+        }
+
+        @Override
+        public void onRecognitionResumed() {
+        }
+    }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 9ac4dbf..0da1bb1 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -86,6 +86,167 @@
     }
 
     private Test[] mTests = new Test[] {
+            new Test("Min priority") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("Min priority")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setPriority(Notification.PRIORITY_MIN)
+                            .build();
+                    mNM.notify(7000, n);
+                }
+            },
+            new Test("Min priority, high pri flag") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("Min priority, high pri flag")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                                    getPackageName() + "/raw/ringer"))
+                            .setPriority(Notification.PRIORITY_MIN)
+                            .setFullScreenIntent(makeIntent2(), true)
+                            .build();
+                    mNM.notify(7001, n);
+                }
+            },
+            new Test("Low priority") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("Low priority")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setPriority(Notification.PRIORITY_LOW)
+                            .build();
+                    mNM.notify(7002, n);
+                }
+            },
+            new Test("Default priority") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("Default priority")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .build();
+                    mNM.notify(7004, n);
+                }
+            },
+            new Test("High priority") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("High priority")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                                    getPackageName() + "/raw/ringer"))
+                            .setPriority(Notification.PRIORITY_HIGH)
+                            .build();
+                    mNM.notify(7006, n);
+                }
+            },
+            new Test("Max priority") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("Max priority")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                                    getPackageName() + "/raw/ringer"))
+                            .setPriority(Notification.PRIORITY_MAX)
+                            .setFullScreenIntent(makeIntent2(), false)
+                            .build();
+                    mNM.notify(7007, n);
+                }
+            },
+            new Test("Max priority with delay") {
+                public void run()
+                {
+                    try {
+                        Thread.sleep(5000);
+                    } catch (InterruptedException e) {
+                    }
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("Max priority")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                                    getPackageName() + "/raw/ringer"))
+                            .setPriority(Notification.PRIORITY_MAX)
+                            .setFullScreenIntent(makeIntent2(), false)
+                            .build();
+                    mNM.notify(7008, n);
+                }
+            },
+            new Test("public notification") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("public notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_PUBLIC)
+                            .build();
+                    mNM.notify(7009, n);
+                }
+            },
+            new Test("private notification, no public") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("private only notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_PRIVATE)
+                            .build();
+                    mNM.notify(7010, n);
+                }
+            },
+            new Test("private notification, has public") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("private version of notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_PRIVATE)
+                            .setPublicVersion(new Notification.Builder(NotificationTestList.this)
+                                    .setSmallIcon(R.drawable.icon2)
+                                    .setContentTitle("public notification of private notification")
+                                    .setPriority(Notification.PRIORITY_DEFAULT)
+                                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                                    .build())
+                            .build();
+                    mNM.notify(7011, n);
+                }
+            },
+            new Test("secret notification") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("secret notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_SECRET)
+                            .build();
+                    mNM.notify(7012, n);
+                }
+            },
         new Test("Off") {
             public void run() {
                 PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml
index d4c6610..4556b02 100644
--- a/tests/UiBench/res/layout/activity_transition.xml
+++ b/tests/UiBench/res/layout/activity_transition.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License
   -->
 <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/transition_grid_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="true"
@@ -25,8 +26,6 @@
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
-        android:layout_column="0"
-        android:layout_row="0"
         android:src="@drawable/ducky"
         android:onClick="clicked"
         android:transitionName="ducky"/>
@@ -36,8 +35,6 @@
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
         android:src="@drawable/woot"
-        android:layout_column="1"
-        android:layout_row="0"
         android:onClick="clicked"
         android:transitionName="woot"/>
     <ImageView
@@ -46,8 +43,6 @@
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
         android:src="@drawable/ball"
-        android:layout_column="0"
-        android:layout_row="1"
         android:onClick="clicked"
         android:transitionName="ball"/>
     <ImageView
@@ -56,8 +51,6 @@
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
         android:src="@drawable/block"
-        android:layout_column="1"
-        android:layout_row="1"
         android:onClick="clicked"
         android:transitionName="block"/>
     <ImageView
@@ -66,8 +59,6 @@
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
         android:src="@drawable/jellies"
-        android:layout_column="0"
-        android:layout_row="2"
         android:onClick="clicked"
         android:transitionName="jellies"/>
     <ImageView
@@ -76,8 +67,6 @@
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
         android:src="@drawable/mug"
-        android:layout_column="1"
-        android:layout_row="2"
         android:onClick="clicked"
         android:transitionName="mug"/>
     <ImageView
@@ -86,8 +75,6 @@
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
         android:src="@drawable/pencil"
-        android:layout_column="0"
-        android:layout_row="3"
         android:onClick="clicked"
         android:transitionName="pencil"/>
     <ImageView
@@ -96,8 +83,6 @@
         android:layout_width="wrap_content"
         android:scaleType="centerCrop"
         android:src="@drawable/scissors"
-        android:layout_column="1"
-        android:layout_row="3"
         android:onClick="clicked"
         android:transitionName="scissors"/>
 </GridLayout>
\ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
index 1106a13..0a069c2 100644
--- a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
@@ -18,11 +18,13 @@
 import android.app.ActivityOptions;
 import android.app.SharedElementCallback;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.support.v7.app.AppCompatActivity;
 import android.view.View;
+import android.widget.GridLayout;
 import android.widget.ImageView;
 
 import java.util.List;
@@ -90,6 +92,13 @@
         getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
         setContentView(R.layout.activity_transition);
         setupHero();
+
+        // Ensure that all images are visible regardless of orientation.
+        GridLayout gridLayout = (GridLayout) findViewById(R.id.transition_grid_layout);
+        boolean isPortrait =
+                getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+        gridLayout.setRowCount(isPortrait ? 4 : 2);
+        gridLayout.setColumnCount(isPortrait ? 2 : 4);
     }
 
     private void setupHero() {
diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk
index 3d44e33..dd8a4d4 100644
--- a/tests/VectorDrawableTest/Android.mk
+++ b/tests/VectorDrawableTest/Android.mk
@@ -23,6 +23,4 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SDK_VERSION := current
-
 include $(BUILD_PACKAGE)
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index e648897..7b3beb2 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -18,8 +18,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.dynamic" >
 
-    <uses-sdk android:minSdkVersion="21" />
-
     <application
         android:hardwareAccelerated="true"
         android:label="vector"
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_clamp.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_clamp.xml
new file mode 100644
index 0000000..6a24453
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_clamp.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:startColor="?android:attr/colorPrimary"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerColor="#00ff0000"
+          android:startX="0"
+          android:startY="0"
+          android:endX="50"
+          android:endY="50"
+          android:type="linear"
+          android:tileMode="clamp">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap_mirror.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap_mirror.xml
new file mode 100644
index 0000000..d342bca
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap_mirror.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:startColor="?android:attr/colorPrimary"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerColor="#f00"
+          android:startX="0"
+          android:startY="0"
+          android:endX="50"
+          android:endY="50"
+          android:type="linear"
+          android:tileMode="mirror">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#f00"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_repeat.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_repeat.xml
new file mode 100644
index 0000000..afb45aa
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_repeat.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:startColor="?android:attr/colorPrimary"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerColor="#f00"
+          android:startX="0"
+          android:startY="0"
+          android:endX="50"
+          android:endY="50"
+          android:type="linear"
+          android:tileMode="repeat">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_clamp.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_clamp.xml
new file mode 100644
index 0000000..64b32f6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_clamp.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="50"
+          android:startColor="?android:attr/colorPrimary"
+          android:type="radial"
+          android:tileMode="clamp">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
index 51b0e17..c6cea7c 100644
--- a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-    <!--
+<!--
 /*
  * Copyright (C) 2016 The Android Open Source Project
  *
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_repeat.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_repeat.xml
new file mode 100644
index 0000000..fb4346a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_repeat.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="50"
+          android:startColor="#ffffffff"
+          android:type="radial"
+          android:tileMode="repeat">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
index 8caa1b4..fefbe9f 100644
--- a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-    <!--
+<!--
 /*
  * Copyright (C) 2016 The Android Open Source Project
  *
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short_mirror.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short_mirror.xml
new file mode 100644
index 0000000..8b5ad7c
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short_mirror.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="50"
+          android:type="radial"
+          android:tileMode="mirror">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_clamp.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_clamp.xml
new file mode 100644
index 0000000..80f39f3e
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_clamp.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:startColor="#ffffffff"
+          android:type="sweep"
+          android:tileMode="clamp">
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long_mirror.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long_mirror.xml
new file mode 100644
index 0000000..0890bd6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long_mirror.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:type="sweep"
+          android:tileMode="mirror">
+    <item android:offset="-0.3" android:color="#f00"/>
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#0f0"/>
+    <item android:offset="0.6" android:color="#00f"/>
+    <item android:offset="0.7" android:color="?android:attr/colorControlActivated"/>
+    <item android:offset="1.5" android:color="#00f"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_repeat.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_repeat.xml
new file mode 100644
index 0000000..2ec5014
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_repeat.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:startColor="#ffffffff"
+          android:type="sweep"
+          android:tileMode="repeat">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_clamp.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_clamp.xml
new file mode 100644
index 0000000..3d746e7
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_clamp.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:centerColor="#7f7f7f"
+          android:endColor="#ffffff"
+          android:startColor="#000000"
+          android:startX="0"
+          android:endX="50"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear"
+          android:tileMode="clamp">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha_mirror.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha_mirror.xml
new file mode 100644
index 0000000..352a2fd
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha_mirror.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:startX="0"
+          android:endX="50"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear"
+          android:tileMode="mirror">
+    <item android:offset="0.1" android:color="#f00"/>
+    <item android:offset="0.2" android:color="#2f0f"/>
+    <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_repeat.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item_repeat.xml
new file mode 100644
index 0000000..42281d1
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item_repeat.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:centerColor="#7f7f7f"
+          android:endColor="#ffffff"
+          android:startColor="#000000"
+          android:startX="0"
+          android:endX="50"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear"
+          android:tileMode="repeat">
+    <item android:offset="0.1" android:color="#f00"/>
+    <item android:offset="0.2" android:color="#f0f"/>
+    <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml b/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
new file mode 100644
index 0000000..4f05090
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+                 xmlns:android="http://schemas.android.com/apk/res/android">
+    <aapt:attr name="android:drawable">
+        <vector
+                android:width="32dp"
+                android:viewportWidth="32"
+                android:height="32dp"
+                android:viewportHeight="32">
+            <group
+                    android:name="btn_radio_to_off_mtrl_0"
+                    android:translateX="16"
+                    android:translateY="16">
+                <group
+                        android:name="ring_outer">
+                    <path
+                            android:name="ring_outer_path"
+                            android:strokeColor="#FF000000"
+                            android:strokeWidth="2"
+                            android:pathData="M 0.0,-9.0 c 4.9705627482,0.0 9.0,4.0294372518 9.0,9.0 c 0.0,4.9705627482 -4.0294372518,9.0 -9.0,9.0 c -4.9705627482,0.0 -9.0,-4.0294372518 -9.0,-9.0 c 0.0,-4.9705627482 4.0294372518,-9.0 9.0,-9.0 Z"/>
+                </group>
+                <group
+                        android:name="dot_group">
+                    <path
+                            android:name="dot_path"
+                            android:pathData="M 0.0,-5.0 c -2.7619934082,0.0 -5.0,2.2380065918 -5.0,5.0 c 0.0,2.7619934082 2.2380065918,5.0 5.0,5.0 c 2.7619934082,0.0 5.0,-2.2380065918 5.0,-5.0 c 0.0,-2.7619934082 -2.2380065918,-5.0 -5.0,-5.0 Z"
+                            android:fillColor="#FF000000"/>
+                </group>
+            </group>
+        </vector>
+    </aapt:attr>
+    <target android:name="ring_outer">
+        <aapt:attr name="android:animation">
+            <set
+                    xmlns:android="http://schemas.android.com/apk/res/android" >
+                <set
+                        android:ordering="sequentially" >
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleX"
+                            android:valueFrom="1.0"
+                            android:valueTo="0.9"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in" />
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleX"
+                            android:valueFrom="0.9"
+                            android:valueTo="0.5"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleX"
+                            android:valueFrom="0.5"
+                            android:valueTo="1.0"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                </set>
+                <set
+                        android:ordering="sequentially" >
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleY"
+                            android:valueFrom="1.0"
+                            android:valueTo="0.9"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in" />
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleY"
+                            android:valueFrom="0.9"
+                            android:valueTo="0.5"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleY"
+                            android:valueFrom="0.5"
+                            android:valueTo="1.0"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                </set>
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="ring_outer_path">
+        <aapt:attr name="android:animation">
+            <set
+                    xmlns:android="http://schemas.android.com/apk/res/android">
+                <set
+                        android:ordering="sequentially">
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="strokeWidth"
+                            android:valueFrom="2.0"
+                            android:valueTo="2.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="strokeWidth"
+                            android:valueFrom="2.0"
+                            android:valueTo="18.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="strokeWidth"
+                            android:valueFrom="18.0"
+                            android:valueTo="2.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                </set>
+
+            </set>
+        </aapt:attr>
+    </target>
+    <target
+            android:name="dot_group">
+        <aapt:attr name="android:animation">
+            <set
+                    xmlns:android="http://schemas.android.com/apk/res/android">
+                <set
+                        android:ordering="sequentially">
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleX"
+                            android:valueFrom="1.0"
+                            android:valueTo="1.4"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleX"
+                            android:valueFrom="1.4"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleX"
+                            android:valueFrom="0.0"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                </set>
+                <set
+                        android:ordering="sequentially">
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleY"
+                            android:valueFrom="1.0"
+                            android:valueTo="1.4"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleY"
+                            android:valueFrom="1.4"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleY"
+                            android:valueFrom="0.0"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                </set>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
index 96fd70e..a6da114 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
@@ -17,7 +17,7 @@
     android:height="4dp"
     android:viewportHeight="4"
     android:viewportWidth="360"
-    android:width="360dp" >
+    android:width="36dp" >
 
     <group
         android:name="linear_indeterminate"
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml
new file mode 100644
index 0000000..d5d86d8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * 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 android:height="24dp" android:viewportHeight="400.0"
+        android:viewportWidth="1200.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillType="evenOdd"
+          android:fillColor="#f00"
+          android:pathData="M250,75L323,301 131,161 369,161 177,301z"
+          android:strokeColor="#000" android:strokeWidth="3"/>
+    <path android:fillType="evenOdd"
+          android:fillColor="#f00"
+          android:pathData="M600,81A107,107 0,0 1,600 295A107,107 0,0 1,600 81zM600,139A49,49 0,0 1,600 237A49,49 0,0 1,600 139z"
+          android:strokeColor="#000" android:strokeWidth="3"/>
+    <path android:fillType="evenOdd"
+          android:fillColor="#f00"
+          android:pathData="M950,81A107,107 0,0 1,950 295A107,107 0,0 1,950 81zM950,139A49,49 0,0 0,950 237A49,49 0,0 0,950 139z"
+          android:strokeColor="#000" android:strokeWidth="3"/>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml
new file mode 100644
index 0000000..9754e4b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * 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 android:height="24dp" android:viewportHeight="400.0"
+        android:viewportWidth="1200.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillType="nonZero"
+          android:fillColor="#f00"
+          android:pathData="M250,75L323,301 131,161 369,161 177,301z"
+          android:strokeColor="#000" android:strokeWidth="3"/>
+    <path android:fillType="nonZero"
+          android:fillColor="#f00"
+          android:pathData="M600,81A107,107 0,0 1,600 295A107,107 0,0 1,600 81zM600,139A49,49 0,0 1,600 237A49,49 0,0 1,600 139z"
+          android:strokeColor="#000" android:strokeWidth="3"/>
+    <path android:fillType="nonZero"
+          android:fillColor="#f00"
+          android:pathData="M950,81A107,107 0,0 1,950 295A107,107 0,0 1,950 81zM950,139A49,49 0,0 0,950 237A49,49 0,0 0,950 139z"
+          android:strokeColor="#000" android:strokeWidth="3"/>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1_clamp.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1_clamp.xml
new file mode 100644
index 0000000..2fa440a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1_clamp.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+       android:scaleX="0.5"
+       android:scaleY="0.5">
+    <path
+            android:name="background1"
+            android:fillColor="@color/fill_gradient_linear_clamp"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background2"
+            android:fillColor="@color/fill_gradient_radial_clamp"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background3"
+            android:fillColor="@color/fill_gradient_sweep_clamp"
+            android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+    <path
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="@color/stroke_gradient_clamp"
+            android:strokeWidth="20" />
+
+    <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0">
+        <path
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="@color/stroke_gradient_clamp"
+                android:strokeWidth="20" />
+
+        <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_clamp"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+
+        <group
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:fillColor="@color/fill_gradient_linear_clamp"
+                        android:strokeColor="@color/stroke_gradient_clamp"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+    </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2_repeat.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2_repeat.xml
new file mode 100644
index 0000000..5a43f80
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2_repeat.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+       android:scaleX="0.5"
+       android:scaleY="0.5">
+    <path
+            android:name="background1"
+            android:fillColor="@color/fill_gradient_linear_item_repeat"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background2"
+            android:fillColor="@color/fill_gradient_radial_item_repeat"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background3"
+            android:fillColor="@color/fill_gradient_sweep_item_repeat"
+            android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+    <path
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="@color/stroke_gradient_item_repeat"
+            android:strokeWidth="20" />
+
+    <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0">
+        <path
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="@color/stroke_gradient_item_repeat"
+                android:strokeWidth="20" />
+
+        <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item_repeat"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+
+        <group
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item_repeat"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+    </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3_mirror.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3_mirror.xml
new file mode 100644
index 0000000..e8de7c2
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3_mirror.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+       android:scaleX="0.5"
+       android:scaleY="0.5">
+    <path
+            android:name="background1"
+            android:fillColor="@color/fill_gradient_linear_item_overlap_mirror"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background2"
+            android:fillColor="@color/fill_gradient_radial_item_short_mirror"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background3"
+            android:fillColor="@color/fill_gradient_sweep_item_long_mirror"
+            android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+    <path
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="@color/stroke_gradient_item_alpha_mirror"
+            android:strokeWidth="20" />
+
+    <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0">
+        <path
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="@color/stroke_gradient_item_alpha_mirror"
+                android:strokeWidth="20" />
+
+        <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item_alpha_mirror"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+
+        <group
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item_alpha"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+    </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml b/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
new file mode 100644
index 0000000..d3728c4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.0 0.4,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index 087e68a..8f538ae 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -24,11 +24,13 @@
 import android.widget.Button;
 import android.widget.GridLayout;
 import android.widget.ScrollView;
+import android.widget.TextView;
 
 public class AnimatedVectorDrawableTest extends Activity implements View.OnClickListener {
     private static final String LOGCAT = "AnimatedVectorDrawableTest";
 
     protected int[] icon = {
+            R.drawable.btn_radio_on_to_off_bundle,
             R.drawable.ic_rotate_2_portrait_v2_animation,
             R.drawable.ic_signal_airplane_v2_animation,
             R.drawable.ic_hourglass_animation,
@@ -43,33 +45,53 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
+        final int[] layerTypes = {View.LAYER_TYPE_SOFTWARE, View.LAYER_TYPE_HARDWARE};
+        final boolean[] forceOnUi = {false, true};
         super.onCreate(savedInstanceState);
 
         ScrollView scrollView = new ScrollView(this);
         GridLayout container = new GridLayout(this);
         scrollView.addView(container);
-        container.setColumnCount(1);
+        container.setColumnCount(layerTypes.length * forceOnUi.length);
 
+        for (int j = 0; j < layerTypes.length; j++) {
+            for (int k = 0; k < forceOnUi.length; k++) {
+                TextView textView = new TextView(this);
+                String category = "Layer:"
+                        + (layerTypes[j] == View.LAYER_TYPE_SOFTWARE ? "SW" : "HW")
+                        + (forceOnUi[k] == true ? ",forceUI" : "");
+                textView.setText(category);
+                container.addView(textView);
+            }
+        }
         for (int i = 0; i < icon.length; i++) {
-            Button button = new Button(this);
-            button.setWidth(400);
-            button.setHeight(400);
-            button.setBackgroundResource(icon[i]);
-            AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
-            d.registerAnimationCallback(new Animatable2.AnimationCallback() {
-                @Override
-                public void onAnimationStart(Drawable drawable) {
-                    Log.v(LOGCAT, "Animator start");
-                }
+            for (int j = 0; j < layerTypes.length; j++) {
+                for (int k = 0; k < forceOnUi.length; k++) {
+                    Button button = new Button(this);
+                    button.setWidth(300);
+                    button.setHeight(300);
+                    button.setLayerType(layerTypes[j], null);
+                    button.setBackgroundResource(icon[i]);
+                    AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
+                    if (forceOnUi[k] == true) {
+                        d.forceAnimationOnUI();
+                    }
+                    d.registerAnimationCallback(new Animatable2.AnimationCallback() {
+                        @Override
+                        public void onAnimationStart(Drawable drawable) {
+                            Log.v(LOGCAT, "Animator start");
+                        }
 
-                @Override
-                public void onAnimationEnd(Drawable drawable) {
-                        Log.v(LOGCAT, "Animator end");
-                }
-            });
+                        @Override
+                        public void onAnimationEnd(Drawable drawable) {
+                            Log.v(LOGCAT, "Animator end");
+                        }
+                    });
 
-            container.addView(button);
-            button.setOnClickListener(this);
+                    container.addView(button);
+                    button.setOnClickListener(this);
+                }
+            }
         }
 
         setContentView(scrollView);
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index 7172147..5856f49 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -35,9 +35,14 @@
 public class VectorDrawablePerformance extends Activity {
     private static final String LOGCAT = "VectorDrawable1";
     protected int[] icon = {
+            R.drawable.vector_icon_filltype_nonzero,
+            R.drawable.vector_icon_filltype_evenodd,
             R.drawable.vector_icon_gradient_1,
             R.drawable.vector_icon_gradient_2,
             R.drawable.vector_icon_gradient_3,
+            R.drawable.vector_icon_gradient_1_clamp,
+            R.drawable.vector_icon_gradient_2_repeat,
+            R.drawable.vector_icon_gradient_3_mirror,
             R.drawable.vector_icon_state_list_simple,
             R.drawable.vector_icon_state_list_theme,
             R.drawable.vector_drawable01,
diff --git a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
index 2494db7..54c944f9 100644
--- a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -31,7 +31,7 @@
 
 public class TestEnrollmentActivity extends Activity {
     private static final String TAG = "TestEnrollmentActivity";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     /** Keyphrase related constants, must match those defined in enrollment_application.xml */
     private static final int KEYPHRASE_ID = 101;
diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
index 3791d02..d7f4a38 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
@@ -140,7 +140,7 @@
     @SmallTest
     public void testSET_ACTIVITY_WATCHER() {
         try {
-            mAm.setActivityController(null);
+            mAm.setActivityController(null, false);
             fail("IActivityManager.setActivityController did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 3b01827..c1cfd0b 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -373,7 +373,7 @@
 void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
     config.unpackLanguage(language);
     config.unpackRegion(region);
-    if (config.localeScriptWasProvided) {
+    if (config.localeScript[0] && !config.localeScriptWasComputed) {
         memcpy(script, config.localeScript, sizeof(config.localeScript));
     }
 
@@ -388,10 +388,6 @@
 
     if (script[0]) {
         memcpy(out->localeScript, script, sizeof(out->localeScript));
-        out->localeScriptWasProvided = true;
-    } else {
-        out->computeScript();
-        out->localeScriptWasProvided = false;
     }
 
     if (variant[0]) {
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index c449550..ca06ac4 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -249,7 +249,7 @@
      * above. SDK levels that have a non-numeric identifier are assumed
      * to be newer than any SDK level that has a number designated.
      */
-    bool isMinSdkAtLeast(int desired) {
+    bool isMinSdkAtLeast(int desired) const {
         /* If the application specifies a minSdkVersion in the manifest
          * then use that. Otherwise, check what the user specified on
          * the command line. If neither, it's not available since
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 40466bd..9939c18 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -1134,10 +1134,9 @@
     }
 }
 
-
 static void write_png(const char* imageName,
                       png_structp write_ptr, png_infop write_info,
-                      image_info& imageInfo, int grayscaleTolerance)
+                      image_info& imageInfo, const Bundle* bundle)
 {
     png_uint_32 width, height;
     int color_type;
@@ -1174,9 +1173,26 @@
     bool hasTransparency;
     int paletteEntries, alphaPaletteEntries;
 
+    int grayscaleTolerance = bundle->getGrayscaleTolerance();
     analyze_image(imageName, imageInfo, grayscaleTolerance, rgbPalette, alphaPalette,
                   &paletteEntries, &alphaPaletteEntries, &hasTransparency, &color_type, outRows);
 
+    // Legacy versions of aapt would always encode 9patch PNGs as RGBA.  This had the unintended
+    // benefit of working around a bug decoding paletted images in Android 4.1.
+    // https://code.google.com/p/android/issues/detail?id=34619
+    //
+    // If SDK_JELLY_BEAN is supported, we need to avoid a paletted encoding in order to not expose
+    // this bug.
+    if (!bundle->isMinSdkAtLeast(SDK_JELLY_BEAN_MR1)) {
+        if (imageInfo.is9Patch && PNG_COLOR_TYPE_PALETTE == color_type) {
+            if (hasTransparency) {
+                color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+            } else {
+                color_type = PNG_COLOR_TYPE_RGB;
+            }
+        }
+    }
+
     if (kIsDebug) {
         switch (color_type) {
         case PNG_COLOR_TYPE_PALETTE:
@@ -1332,8 +1348,7 @@
         return false;
     }
 
-    write_png(printableName.string(), write_ptr, write_info, *imageInfo,
-              bundle->getGrayscaleTolerance());
+    write_png(printableName.string(), write_ptr, write_info, *imageInfo, bundle);
 
     return true;
 }
@@ -1543,8 +1558,7 @@
     }
 
     // Actually write out to the new png
-    write_png(dest.string(), write_ptr, write_info, imageInfo,
-              bundle->getGrayscaleTolerance());
+    write_png(dest.string(), write_ptr, write_info, imageInfo, bundle);
 
     if (bundle->getVerbose()) {
         // Find the size of our new file
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 641c34b..d631f35 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -33,7 +33,7 @@
     ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
     ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
     ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
-    ".amr", ".awb", ".wma", ".wmv", ".webm"
+    ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"
 };
 
 /* fwd decls, so I can write this downward */
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index e87c7d40..6a4b637 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -308,29 +308,11 @@
         }
         added = true;
 
-        String16 attr16("attr");
-        
-        if (outTable->hasBagOrEntry(myPackage, attr16, ident)) {
-            sourcePos.error("Attribute \"%s\" has already been defined\n",
-                    String8(ident).string());
+        if (!outTable->makeAttribute(myPackage, ident, sourcePos, type, comment, appendComment)) {
             hasErrors = true;
             return UNKNOWN_ERROR;
         }
-        
-        char numberStr[16];
-        sprintf(numberStr, "%d", type);
-        status_t err = outTable->addBag(sourcePos, myPackage,
-                attr16, ident, String16(""),
-                String16("^type"),
-                String16(numberStr), NULL, NULL);
-        if (err != NO_ERROR) {
-            hasErrors = true;
-            return err;
-        }
-        outTable->appendComment(myPackage, attr16, ident, comment, appendComment);
-        //printf("Attribute %s comment: %s\n", String8(ident).string(),
-        //     String8(comment).string());
-        return err;
+        return NO_ERROR;
     }
 };
 
@@ -2115,6 +2097,61 @@
     return false;
 }
 
+bool ResourceTable::makeAttribute(const String16& package,
+                                  const String16& name,
+                                  const SourcePos& source,
+                                  int32_t format,
+                                  const String16& comment,
+                                  bool shouldAppendComment) {
+    const String16 attr16("attr");
+
+    // First look for this in the included resources...
+    uint32_t rid = mAssets->getIncludedResources()
+            .identifierForName(name.string(), name.size(),
+                               attr16.string(), attr16.size(),
+                               package.string(), package.size());
+    if (rid != 0) {
+        source.error("Attribute \"%s\" has already been defined", String8(name).string());
+        return false;
+    }
+
+    sp<ResourceTable::Entry> entry = getEntry(package, attr16, name, source, false);
+    if (entry == NULL) {
+        source.error("Failed to create entry attr/%s", String8(name).string());
+        return false;
+    }
+
+    if (entry->makeItABag(source) != NO_ERROR) {
+        return false;
+    }
+
+    const String16 formatKey16("^type");
+    const String16 formatValue16(String8::format("%d", format));
+
+    ssize_t idx = entry->getBag().indexOfKey(formatKey16);
+    if (idx >= 0) {
+        // We have already set a format for this attribute, check if they are different.
+        // We allow duplicate attribute definitions so long as they are identical.
+        // This is to ensure inter-operation with libraries that define the same generic attribute.
+        const Item& formatItem = entry->getBag().valueAt(idx);
+        if ((format & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) ||
+                formatItem.value != formatValue16) {
+            source.error("Attribute \"%s\" already defined with incompatible format.\n"
+                         "%s:%d: Original attribute defined here.",
+                         String8(name).string(), formatItem.sourcePos.file.string(),
+                         formatItem.sourcePos.line);
+            return false;
+        }
+    } else {
+        entry->addToBag(source, formatKey16, formatValue16);
+        // Increment the number of resources we have. This is used to determine if we should
+        // even generate a resource table.
+        mNumLocal++;
+    }
+    appendComment(package, attr16, name, comment, shouldAppendComment);
+    return true;
+}
+
 void ResourceTable::canAddEntry(const SourcePos& pos,
         const String16& package, const String16& type, const String16& name)
 {
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 4b7b3cd..cf1e992 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -571,6 +571,18 @@
 
     void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);
 
+    /**
+     * Make an attribute with the specified format. If another attribute with the same name but
+     * different format exists, this method returns false. If the name is not taken, or if the
+     * format is identical, this returns true.
+     */
+    bool makeAttribute(const String16& package,
+                       const String16& name,
+                       const SourcePos& source,
+                       int32_t format,
+                       const String16& comment,
+                       bool appendComment);
+
 private:
     void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
     sp<Package> getPackage(const String16& package);
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index f9d35ab..876a422 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -13,15 +13,12 @@
 # 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)),)
+LOCAL_PATH:= $(call my-dir)
 
 # ==========================================================
 # Setup some common variables for the different build
 # targets here.
 # ==========================================================
-LOCAL_PATH:= $(call my-dir)
 
 main := Main.cpp
 sources := \
@@ -57,6 +54,7 @@
 	Debug.cpp \
 	Flags.cpp \
 	java/AnnotationProcessor.cpp \
+	java/ClassDefinition.cpp \
 	java/JavaClassGenerator.cpp \
 	java/ManifestClassGenerator.cpp \
 	java/ProguardRules.cpp \
@@ -93,6 +91,7 @@
 	proto/TableProtoSerializer_test.cpp \
 	split/TableSplitter_test.cpp \
 	util/BigBuffer_test.cpp \
+	util/Files_test.cpp \
 	util/Maybe_test.cpp \
 	util/StringPiece_test.cpp \
 	util/Util_test.cpp \
@@ -127,10 +126,12 @@
 	libexpat \
 	libziparchive-host \
 	libpng \
-	libbase
+	libbase \
+	libprotobuf-cpp-lite_static
 
-hostSharedLibs := \
-	libprotobuf-cpp-lite
+# Do not add any shared libraries. AAPT2 is built to run on many
+# environments that may not have the required dependencies.
+hostSharedLibs :=
 
 ifneq ($(strip $(USE_MINGW)),)
 	hostStaticLibs += libz
@@ -192,4 +193,6 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
-endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
+ifeq ($(ONE_SHOT_MAKEFILE),)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
index 6acf3b0..be57661 100644
--- a/tools/aapt2/Locale.cpp
+++ b/tools/aapt2/Locale.cpp
@@ -253,7 +253,7 @@
 void LocaleValue::initFromResTable(const ResTable_config& config) {
     config.unpackLanguage(language);
     config.unpackRegion(region);
-    if (config.localeScriptWasProvided) {
+    if (config.localeScript[0] && !config.localeScriptWasComputed) {
         memcpy(script, config.localeScript, sizeof(config.localeScript));
     }
 
@@ -268,10 +268,6 @@
 
     if (script[0]) {
         memcpy(out->localeScript, script, sizeof(out->localeScript));
-        out->localeScriptWasProvided = true;
-    } else {
-        out->computeScript();
-        out->localeScriptWasProvided = false;
     }
 
     if (variant[0]) {
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index c71e249..03ca42b 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -77,13 +77,10 @@
     ResourceType type;
     std::u16string entry;
 
-    ResourceName() = default;
+    ResourceName() : type(ResourceType::kRaw) {}
     ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e);
 
     bool isValid() const;
-    bool operator<(const ResourceName& rhs) const;
-    bool operator==(const ResourceName& rhs) const;
-    bool operator!=(const ResourceName& rhs) const;
     std::u16string toString() const;
 };
 
@@ -109,10 +106,6 @@
 
     ResourceName toResourceName() const;
     bool isValid() const;
-
-    bool operator<(const ResourceNameRef& rhs) const;
-    bool operator==(const ResourceNameRef& rhs) const;
-    bool operator!=(const ResourceNameRef& rhs) const;
 };
 
 /**
@@ -138,17 +131,11 @@
     uint8_t packageId() const;
     uint8_t typeId() const;
     uint16_t entryId() const;
-    bool operator<(const ResourceId& rhs) const;
-    bool operator==(const ResourceId& rhs) const;
 };
 
 struct SourcedResourceName {
     ResourceName name;
     size_t line;
-
-    inline bool operator==(const SourcedResourceName& rhs) const {
-        return name == rhs.name && line == rhs.line;
-    }
 };
 
 struct ResourceFile {
@@ -227,16 +214,23 @@
     return static_cast<uint16_t>(id);
 }
 
-inline bool ResourceId::operator<(const ResourceId& rhs) const {
-    return id < rhs.id;
+inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
+    return lhs.id < rhs.id;
 }
 
-inline bool ResourceId::operator==(const ResourceId& rhs) const {
-    return id == rhs.id;
+inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
+    return lhs.id > rhs.id;
 }
 
-inline ::std::ostream& operator<<(::std::ostream& out,
-        const ResourceId& resId) {
+inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
+    return lhs.id == rhs.id;
+}
+
+inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
+    return lhs.id != rhs.id;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& resId) {
     std::ios_base::fmtflags oldFlags = out.flags();
     char oldFill = out.fill();
     out << "0x" << std::internal << std::setfill('0') << std::setw(8)
@@ -266,29 +260,21 @@
     return !package.empty() && !entry.empty();
 }
 
-inline bool ResourceName::operator<(const ResourceName& rhs) const {
-    return std::tie(package, type, entry)
+inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
+    return std::tie(lhs.package, lhs.type, lhs.entry)
             < std::tie(rhs.package, rhs.type, rhs.entry);
 }
 
-inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
-    return ResourceNameRef(lhs) < b;
-}
-
-inline bool ResourceName::operator==(const ResourceName& rhs) const {
-    return std::tie(package, type, entry)
+inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
+    return std::tie(lhs.package, lhs.type, lhs.entry)
             == std::tie(rhs.package, rhs.type, rhs.entry);
 }
 
-inline bool ResourceName::operator!=(const ResourceName& rhs) const {
-    return std::tie(package, type, entry)
+inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
+    return std::tie(lhs.package, lhs.type, lhs.entry)
             != std::tie(rhs.package, rhs.type, rhs.entry);
 }
 
-inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
-    return ResourceNameRef(lhs) != rhs;
-}
-
 inline std::u16string ResourceName::toString() const {
     std::u16string result;
     if (!package.empty()) {
@@ -333,18 +319,18 @@
     return !package.empty() && !entry.empty();
 }
 
-inline bool ResourceNameRef::operator<(const ResourceNameRef& rhs) const {
-    return std::tie(package, type, entry)
+inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
+    return std::tie(lhs.package, lhs.type, lhs.entry)
             < std::tie(rhs.package, rhs.type, rhs.entry);
 }
 
-inline bool ResourceNameRef::operator==(const ResourceNameRef& rhs) const {
-    return std::tie(package, type, entry)
+inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
+    return std::tie(lhs.package, lhs.type, lhs.entry)
             == std::tie(rhs.package, rhs.type, rhs.entry);
 }
 
-inline bool ResourceNameRef::operator!=(const ResourceNameRef& rhs) const {
-    return std::tie(package, type, entry)
+inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
+    return std::tie(lhs.package, lhs.type, lhs.entry)
             != std::tie(rhs.package, rhs.type, rhs.entry);
 }
 
@@ -355,6 +341,18 @@
     return out << name.type << "/" << name.entry;
 }
 
+inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
+    return ResourceNameRef(lhs) < b;
+}
+
+inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
+    return ResourceNameRef(lhs) != rhs;
+}
+
+inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
+    return lhs.name == rhs.name && lhs.line == rhs.line;
+}
+
 } // namespace aapt
 
 #endif // AAPT_RESOURCE_H
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index b100e84..9704d970 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -81,6 +81,12 @@
 
 // Recursively adds resources to the ResourceTable.
 static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
+    StringPiece16 trimmedComment = util::trimWhitespace(res->comment);
+    if (trimmedComment.size() != res->comment.size()) {
+        // Only if there was a change do we re-assign.
+        res->comment = trimmedComment.toString();
+    }
+
     if (res->symbolState) {
         Symbol symbol;
         symbol.state = res->symbolState.value();
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 5f9719e..2452a1d 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -422,10 +422,6 @@
 }
 
 class CompileContext : public IAaptContext {
-private:
-    StdErrDiagnostics mDiagnostics;
-    bool mVerbose = false;
-
 public:
     void setVerbose(bool val) {
         mVerbose = val;
@@ -444,18 +440,24 @@
        return nullptr;
     }
 
-    StringPiece16 getCompilationPackage() override {
-       return {};
+    const std::u16string& getCompilationPackage() override {
+        static std::u16string empty;
+        return empty;
     }
 
     uint8_t getPackageId() override {
        return 0x0;
     }
 
-    ISymbolTable* getExternalSymbols() override {
+    SymbolTable* getExternalSymbols() override {
        abort();
        return nullptr;
     }
+
+private:
+    StdErrDiagnostics mDiagnostics;
+    bool mVerbose = false;
+
 };
 
 /**
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index 9837c4e..bbf7f41 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -1175,7 +1175,7 @@
     if (errorMsg) {
         std::stringstream err;
         err << "9-patch malformed: " << errorMsg;
-        if (!errorEdge) {
+        if (errorEdge) {
             err << "." << std::endl;
             if (errorPixel >= 0) {
                 err << "Found at pixel #" << errorPixel << " along " << errorEdge << " edge";
diff --git a/tools/aapt2/data/AndroidManifest.xml b/tools/aapt2/data/AndroidManifest.xml
deleted file mode 100644
index d3b2fbe..0000000
--- a/tools/aapt2/data/AndroidManifest.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.app">
-    <application
-        android:name=".ActivityMain">
-    </application>
-</manifest>
diff --git a/tools/aapt2/data/Makefile b/tools/aapt2/data/Makefile
deleted file mode 100644
index 37012de..0000000
--- a/tools/aapt2/data/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
-##
-# Environment dependent variables
-##
-
-AAPT := aapt2
-ZIPALIGN := zipalign -f 4
-FRAMEWORK := ../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
-
-##
-# Project depenedent variables
-##
-
-LOCAL_PACKAGE := com.android.app
-LOCAL_RESOURCE_DIR := res
-LOCAL_LIBS := lib/out/package.apk
-LOCAL_OUT := out
-LOCAL_GEN := out/gen
-LOCAL_PROGUARD := out/proguard.rule
-
-##
-# AAPT2 custom rules.
-##
-
-PRIVATE_R_FILE := $(LOCAL_GEN)/$(subst .,/,$(LOCAL_PACKAGE))/R.java
-$(info PRIVATE_R_FILE = $(PRIVATE_R_FILE))
-
-# Eg: framework.apk, etc.
-PRIVATE_INCLUDES := $(FRAMEWORK)
-$(info PRIVATE_INCLUDES = $(PRIVATE_INCLUDES))
-
-# Eg: res/drawable/icon.png, res/values/styles.xml
-PRIVATE_RESOURCES := $(shell find $(LOCAL_RESOURCE_DIR) -mindepth 1 -maxdepth 2 -type f)
-$(info PRIVATE_RESOURCES = $(PRIVATE_RESOURCES))
-
-PRIVATE_RESOURCE_OBJECTS := $(subst /,_,$(patsubst $(LOCAL_RESOURCE_DIR)/%,%,$(filter $(LOCAL_RESOURCE_DIR)/values%,$(PRIVATE_RESOURCES))))
-PRIVATE_RESOURCE_OBJECTS := $(addprefix $(LOCAL_OUT)/,$(PRIVATE_RESOURCE_OBJECTS:.xml=.arsc.flat))
-$(info PRIVATE_RESOURCE_OBJECTS = $(PRIVATE_RESOURCE_OBJECTS))
-
-PRIVATE_FILE_OBJECTS := $(subst /,_,$(patsubst $(LOCAL_RESOURCE_DIR)/%,%,$(filter-out $(LOCAL_RESOURCE_DIR)/values%,$(PRIVATE_RESOURCES))))
-PRIVATE_FILE_OBJECTS := $(addprefix $(LOCAL_OUT)/,$(addsuffix .flat,$(PRIVATE_FILE_OBJECTS)))
-$(info PRIVATE_FILE_OBJECTS = $(PRIVATE_FILE_OBJECTS))
-
-.SECONDEXPANSION:
-
-$(LOCAL_OUT)/%.arsc.flat: $(LOCAL_RESOURCE_DIR)/$$(subst _,/,%).xml
-	$(AAPT) compile -o $(LOCAL_OUT) $<
-
-$(LOCAL_OUT)/%.flat: $(LOCAL_RESOURCE_DIR)/$$(subst _,/,%)
-	$(AAPT) compile -o $(LOCAL_OUT) $<
-
-$(LOCAL_PROGUARD) $(LOCAL_OUT)/package.apk: AndroidManifest.xml
-$(PRIVATE_R_FILE) $(LOCAL_PROGUARD) $(LOCAL_OUT)/package.apk: $(PRIVATE_FILE_OBJECTS) $(PRIVATE_RESOURCE_OBJECTS)
-	$(AAPT) link -o $(LOCAL_OUT)/package.apk --manifest AndroidManifest.xml --java $(LOCAL_GEN) --proguard $(LOCAL_PROGUARD) -I $(PRIVATE_INCLUDES) $(filter-out AndroidManifest.xml,$^) -v
-
-# Create the out directory if needed.
-dummy := $(shell test -d $(LOCAL_OUT) || mkdir -p $(LOCAL_OUT))
-
-.PHONY: all
-all: $(LOCAL_OUT)/package.apk $(LOCAL_PROGUARD) $(PRIVATE_R_FILE)
-
-.DEFAULT_GOAL := all
diff --git a/tools/aapt2/data/lib/AndroidManifest.xml b/tools/aapt2/data/lib/AndroidManifest.xml
deleted file mode 100644
index 08b468e..0000000
--- a/tools/aapt2/data/lib/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.appcompat">
-
-    <uses-feature android:name="bloooop" />
-</manifest>
diff --git a/tools/aapt2/data/lib/Makefile b/tools/aapt2/data/lib/Makefile
deleted file mode 100644
index 741be9a..0000000
--- a/tools/aapt2/data/lib/Makefile
+++ /dev/null
@@ -1,81 +0,0 @@
-##
-# Environment dependent variables
-##
-
-AAPT := aapt2
-ZIPALIGN := zipalign -f 4
-FRAMEWORK := ../../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
-
-##
-# Project depenedent variables
-##
-
-LOCAL_PACKAGE := android.appcompat
-LOCAL_RESOURCE_DIR := res
-LOCAL_OUT := out
-LOCAL_GEN := out/gen
-
-##
-# AAPT2 custom rules.
-##
-
-PRIVATE_APK_UNALIGNED := $(LOCAL_OUT)/package-unaligned.apk
-PRIVATE_APK_ALIGNED := $(LOCAL_OUT)/package.apk
-
-# Eg: framework.apk, etc.
-PRIVATE_LIBS := $(FRAMEWORK)
-$(info PRIVATE_LIBS = $(PRIVATE_LIBS))
-
-# Eg: gen/com/android/app/R.java
-PRIVATE_R_JAVA := $(LOCAL_GEN)/$(subst .,/,$(LOCAL_PACKAGE))/R.java
-$(info PRIVATE_R_JAVA = $(PRIVATE_R_JAVA))
-
-# Eg: res/drawable/icon.png, res/values/styles.xml
-PRIVATE_RESOURCES := $(shell find $(LOCAL_RESOURCE_DIR) -mindepth 1 -maxdepth 2 -type f)
-$(info PRIVATE_RESOURCES = $(PRIVATE_RESOURCES))
-
-# Eg: drawable, values, layouts
-PRIVATE_RESOURCE_TYPES := \
-	$(patsubst $(LOCAL_RESOURCE_DIR)/%/,%,$(sort $(dir $(PRIVATE_RESOURCES))))
-$(info PRIVATE_RESOURCE_TYPES = $(PRIVATE_RESOURCE_TYPES))
-
-# Eg: out/values-v4.apk, out/drawable-xhdpi.apk
-PRIVATE_INTERMEDIATE_TABLES := $(patsubst %,$(LOCAL_OUT)/%.apk,$(PRIVATE_RESOURCE_TYPES))
-$(info PRIVATE_INTERMEDIATE_TABLES = $(PRIVATE_INTERMEDIATE_TABLES))
-
-# Generates rules for collect phase.
-# $1: Resource type (values-v4)
-# returns: out/values-v4.apk: res/values-v4/styles.xml res/values-v4/colors.xml
-define make-collect-rule
-$(LOCAL_OUT)/$1.apk: $(filter $(LOCAL_RESOURCE_DIR)/$1/%,$(PRIVATE_RESOURCES))
-	$(AAPT) compile -o $$@ $$^
-endef
-
-# Collect: out/values-v4.apk <- res/values-v4/styles.xml res/values-v4/colors.xml
-$(foreach d,$(PRIVATE_RESOURCE_TYPES),$(eval $(call make-collect-rule,$d)))
-
-# Link: out/package-unaligned.apk <- out/values-v4.apk out/drawable-v4.apk
-$(PRIVATE_APK_UNALIGNED): $(PRIVATE_INTERMEDIATE_TABLES) $(PRIVATE_LIBS) AndroidManifest.xml
-	$(AAPT) link --manifest AndroidManifest.xml $(addprefix -I ,$(PRIVATE_LIBS)) --java $(LOCAL_GEN) -o $@ $(PRIVATE_INTERMEDIATE_TABLES) --static-lib
-
-# R.java: gen/com/android/app/R.java <- out/resources.arsc
-# No action since R.java is generated when out/resources.arsc is.
-$(PRIVATE_R_JAVA): $(PRIVATE_APK_UNALIGNED)
-
-# Assemble: zip out/resources.arsc AndroidManifest.xml and res/**/*
-$(PRIVATE_APK_ALIGNED): $(PRIVATE_APK_UNALIGNED)
-	$(ZIPALIGN) $< $@
-
-# Create the out directory if needed.
-dummy := $(shell test -d $(LOCAL_OUT) || mkdir -p $(LOCAL_OUT))
-
-.PHONY: java
-java: $(PRIVATE_R_JAVA)
-
-.PHONY: assemble
-assemble: $(PRIVATE_APK_ALIGNED)
-
-.PHONY: all
-all: assemble java
-
-.DEFAULT_GOAL := all
diff --git a/tools/aapt2/data/lib/res/layout/main.xml b/tools/aapt2/data/lib/res/layout/main.xml
deleted file mode 100644
index 187ed2d..0000000
--- a/tools/aapt2/data/lib/res/layout/main.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
diff --git a/tools/aapt2/data/lib/res/raw/hello.txt b/tools/aapt2/data/lib/res/raw/hello.txt
deleted file mode 100644
index 44fc22b..0000000
--- a/tools/aapt2/data/lib/res/raw/hello.txt
+++ /dev/null
@@ -1 +0,0 @@
-Oh howdy there
diff --git a/tools/aapt2/data/lib/res/values/styles.xml b/tools/aapt2/data/lib/res/values/styles.xml
deleted file mode 100644
index 4ce6333..0000000
--- a/tools/aapt2/data/lib/res/values/styles.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="Platform.AppCompat" parent="@android:style/Theme">
-        <item name="android:windowNoTitle">true</item>
-    </style>
-
-    <bool name="allow">true</bool>
-</resources>
diff --git a/tools/aapt2/data/res/drawable/image.xml b/tools/aapt2/data/res/drawable/image.xml
deleted file mode 100644
index 9b38739..0000000
--- a/tools/aapt2/data/res/drawable/image.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector />
diff --git a/tools/aapt2/data/res/layout-v21/main.xml b/tools/aapt2/data/res/layout-v21/main.xml
deleted file mode 100644
index 959b349..0000000
--- a/tools/aapt2/data/res/layout-v21/main.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
-    android:id="@+id/view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-</LinearLayout>
diff --git a/tools/aapt2/data/res/layout/main.xml b/tools/aapt2/data/res/layout/main.xml
deleted file mode 100644
index 8a5e9e8..0000000
--- a/tools/aapt2/data/res/layout/main.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
-    android:id="@+id/view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-
-    <fragment class="android.test.sample.App$Inner" />
-
-    <variable name="user" type="com.android.User" />
-
-    <View xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:id="@+id/me"
-        android:layout_width="1dp"
-        android:onClick="doClick"
-        android:text="@{user.name}"
-        android:background="#ffffff"
-        android:layout_height="match_parent"
-        app:flags="complex|weak"
-        android:colorAccent="#ffffff"/>
-</LinearLayout>
diff --git a/tools/aapt2/data/res/values-v4/styles.xml b/tools/aapt2/data/res/values-v4/styles.xml
deleted file mode 100644
index 979a82a..0000000
--- a/tools/aapt2/data/res/values-v4/styles.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="App" parent="android:Theme.Material">
-        <item name="android:colorAccent">@color/accent</item>
-        <item name="android:text">Hey</item>
-    </style>
-</resources>
diff --git a/tools/aapt2/data/res/values/colors.xml b/tools/aapt2/data/res/values/colors.xml
deleted file mode 100644
index 89db5fb..0000000
--- a/tools/aapt2/data/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <color name="primary">#f44336</color>
-    <color name="primary_dark">#b71c1c</color>
-    <color name="accent">#fdd835</color>
-</resources>
diff --git a/tools/aapt2/data/res/values/styles.xml b/tools/aapt2/data/res/values/styles.xml
deleted file mode 100644
index 2bbdad1..0000000
--- a/tools/aapt2/data/res/values/styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:lib="http://schemas.android.com/apk/res/android.appcompat">
-    <style name="App">
-        <item name="android:background">@color/primary</item>
-        <item name="android:colorPrimary">@color/primary</item>
-        <item name="android:colorPrimaryDark">@color/primary_dark</item>
-        <item name="android:colorAccent">@color/accent</item>
-    </style>
-    <attr name="custom" format="reference" />
-    <style name="Pop">
-        <item name="custom">@android:drawable/btn_default</item>
-        <item name="android:focusable">true</item>
-    </style>
-    <string name="yo">@string/wow</string>
-
-    <declare-styleable name="View">
-        <attr name="custom" />
-        <attr name="decor">
-            <enum name="no-border" value="0"/>
-            <enum name="border" value="1"/>
-            <enum name="shadow" value="2"/>
-        </attr>
-    </declare-styleable>
-
-</resources>
diff --git a/tools/aapt2/data/res/values/test.xml b/tools/aapt2/data/res/values/test.xml
deleted file mode 100644
index d7ab1c8..0000000
--- a/tools/aapt2/data/res/values/test.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="hooha"><font bgcolor="#ffffff">Hey guys!</font> <xliff:g>My</xliff:g> name is <b>Adam</b>. How <b><i>are</i></b> you?</string>
-    <public name="hooha" type="string" id="0x7f020001"/>
-    <string name="wow">@android:string/ok</string>
-    <public name="layout_width" type="attr" />
-    <attr name="layout_width" format="boolean" />
-    <attr name="flags">
-        <flag name="complex" value="1" />
-        <flag name="pub" value="2" />
-        <flag name="weak" value="4" />
-    </attr>
-</resources>
diff --git a/tools/aapt2/data/resources.arsc b/tools/aapt2/data/resources.arsc
deleted file mode 100644
index 6a416df..0000000
--- a/tools/aapt2/data/resources.arsc
+++ /dev/null
Binary files differ
diff --git a/tools/aapt2/data/resources_base.arsc b/tools/aapt2/data/resources_base.arsc
deleted file mode 100644
index f9d0610..0000000
--- a/tools/aapt2/data/resources_base.arsc
+++ /dev/null
Binary files differ
diff --git a/tools/aapt2/data/resources_hdpi.arsc b/tools/aapt2/data/resources_hdpi.arsc
deleted file mode 100644
index 97232a3..0000000
--- a/tools/aapt2/data/resources_hdpi.arsc
+++ /dev/null
Binary files differ
diff --git a/tools/aapt2/dump/Dump.cpp b/tools/aapt2/dump/Dump.cpp
index ad7de0a..56b9f9a 100644
--- a/tools/aapt2/dump/Dump.cpp
+++ b/tools/aapt2/dump/Dump.cpp
@@ -17,6 +17,7 @@
 #include "Debug.h"
 #include "Diagnostics.h"
 #include "Flags.h"
+#include "io/ZipArchive.h"
 #include "process/IResourceTableConsumer.h"
 #include "proto/ProtoSerialize.h"
 #include "util/Files.h"
@@ -56,6 +57,35 @@
 
 void tryDumpFile(IAaptContext* context, const std::string& filePath) {
     std::string err;
+    std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err);
+    if (zip) {
+        io::IFile* file = zip->findFile("resources.arsc.flat");
+        if (file) {
+            std::unique_ptr<io::IData> data = file->openAsData();
+            if (!data) {
+                context->getDiagnostics()->error(DiagMessage(filePath)
+                                                 << "failed to open resources.arsc.flat");
+                return;
+            }
+
+            pb::ResourceTable pbTable;
+            if (!pbTable.ParseFromArray(data->data(), data->size())) {
+                context->getDiagnostics()->error(DiagMessage(filePath)
+                                                 << "invalid resources.arsc.flat");
+                return;
+            }
+
+            std::unique_ptr<ResourceTable> table = deserializeTableFromPb(
+                    pbTable, Source(filePath), context->getDiagnostics());
+            if (table) {
+                DebugPrintTableOptions debugPrintTableOptions;
+                debugPrintTableOptions.showSources = true;
+                Debug::printTable(table.get(), debugPrintTableOptions);
+            }
+        }
+        return;
+    }
+
     Maybe<android::FileMap> file = file::mmapPath(filePath, &err);
     if (!file) {
         context->getDiagnostics()->error(DiagMessage(filePath) << err);
@@ -90,15 +120,16 @@
         return nullptr;
     }
 
-    StringPiece16 getCompilationPackage() override {
-        return {};
+    const std::u16string& getCompilationPackage() override {
+        static std::u16string empty;
+        return empty;
     }
 
     uint8_t getPackageId() override {
         return 0;
     }
 
-    ISymbolTable* getExternalSymbols() override {
+    SymbolTable* getExternalSymbols() override {
         abort();
         return nullptr;
     }
diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/flatten/XmlFlattener.cpp
index 8219462..3eac633 100644
--- a/tools/aapt2/flatten/XmlFlattener.cpp
+++ b/tools/aapt2/flatten/XmlFlattener.cpp
@@ -144,9 +144,9 @@
     }
 
     static bool cmpXmlAttributeById(const xml::Attribute* a, const xml::Attribute* b) {
-        if (a->compiledAttribute) {
-            if (b->compiledAttribute) {
-                return a->compiledAttribute.value().id < b->compiledAttribute.value().id;
+        if (a->compiledAttribute && a->compiledAttribute.value().id) {
+            if (b->compiledAttribute && b->compiledAttribute.value().id) {
+                return a->compiledAttribute.value().id.value() < b->compiledAttribute.value().id.value();
             }
             return true;
         } else if (!b->compiledAttribute) {
@@ -167,8 +167,8 @@
 
         // Filter the attributes.
         for (xml::Attribute& attr : node->attributes) {
-            if (mOptions.maxSdkLevel && attr.compiledAttribute) {
-                size_t sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id);
+            if (mOptions.maxSdkLevel && attr.compiledAttribute && attr.compiledAttribute.value().id) {
+                size_t sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id.value());
                 if (sdkLevel > mOptions.maxSdkLevel.value()) {
                     continue;
                 }
@@ -191,8 +191,8 @@
         uint16_t attributeIndex = 1;
         for (const xml::Attribute* xmlAttr : mFilteredAttrs) {
             // Assign the indices for specific attributes.
-            if (xmlAttr->compiledAttribute &&
-                    xmlAttr->compiledAttribute.value().id == kIdAttr) {
+            if (xmlAttr->compiledAttribute && xmlAttr->compiledAttribute.value().id &&
+                    xmlAttr->compiledAttribute.value().id.value() == kIdAttr) {
                 flatElem->idIndex = util::hostToDevice16(attributeIndex);
             } else if (xmlAttr->namespaceUri.empty()) {
                 if (xmlAttr->name == u"class") {
@@ -208,7 +208,7 @@
 
             flatAttr->rawValue.index = util::hostToDevice32(-1);
 
-            if (!xmlAttr->compiledAttribute) {
+            if (!xmlAttr->compiledAttribute || !xmlAttr->compiledAttribute.value().id) {
                 // The attribute has no associated ResourceID, so the string order doesn't matter.
                 addString(xmlAttr->name, kLowPriority, &flatAttr->name);
             } else {
@@ -221,17 +221,17 @@
                 // Lookup the StringPool for this package and make the reference there.
                 const xml::AaptAttribute& aaptAttr = xmlAttr->compiledAttribute.value();
 
-                StringPool::Ref nameRef = mPackagePools[aaptAttr.id.packageId()].makeRef(
-                        xmlAttr->name, StringPool::Context{ aaptAttr.id.id });
+                StringPool::Ref nameRef = mPackagePools[aaptAttr.id.value().packageId()].makeRef(
+                        xmlAttr->name, StringPool::Context{ aaptAttr.id.value().id });
 
                 // Add it to the list of strings to flatten.
                 addString(nameRef, &flatAttr->name);
+            }
 
-                if (mOptions.keepRawValues) {
-                    // Keep raw values (this is for static libraries).
-                    // TODO(with a smarter inflater for binary XML, we can do without this).
-                    addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
-                }
+            if (mOptions.keepRawValues || !xmlAttr->compiledValue) {
+                // Keep raw values if the value is not compiled or
+                // if we're building a static library (need symbols).
+                addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
             }
 
             if (xmlAttr->compiledValue) {
@@ -240,7 +240,6 @@
             } else {
                 // Flatten as a regular string type.
                 flatAttr->typedValue.dataType = android::Res_value::TYPE_STRING;
-                addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
                 addString(xmlAttr->value, kLowPriority,
                           (ResStringPool_ref*) &flatAttr->typedValue.data);
             }
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index 8648879..fef5ca3 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -32,7 +32,7 @@
         mContext = test::ContextBuilder()
                 .setCompilationPackage(u"com.app.test")
                 .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-                .setSymbolTable(test::StaticSymbolTableBuilder()
+                .addSymbolSource(test::StaticSymbolSourceBuilder()
                         .addSymbol(u"@android:attr/id", ResourceId(0x010100d0),
                                    test::AttributeBuilder().build())
                         .addSymbol(u"@com.app.test:id/id", ResourceId(0x7f020000))
diff --git a/tools/aapt2/integration-tests/Android.mk b/tools/aapt2/integration-tests/Android.mk
new file mode 100644
index 0000000..6361f9b
--- /dev/null
+++ b/tools/aapt2/integration-tests/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/integration-tests/AppOne/Android.mk b/tools/aapt2/integration-tests/AppOne/Android.mk
new file mode 100644
index 0000000..bc40a62
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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_USE_AAPT2 := true
+LOCAL_PACKAGE_NAME := AaptTestAppOne
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    AaptTestStaticLibOne \
+    AaptTestStaticLibTwo
+LOCAL_AAPT_FLAGS := --no-version-vectors
+include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
new file mode 100644
index 0000000..b6d8f2d
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 package="com.android.aapt.app.one" />
diff --git a/tools/aapt2/data/res/drawable/icon.png b/tools/aapt2/integration-tests/AppOne/res/drawable/icon.png
similarity index 100%
rename from tools/aapt2/data/res/drawable/icon.png
rename to tools/aapt2/integration-tests/AppOne/res/drawable/icon.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml b/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml
new file mode 100644
index 0000000..6132a75
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 />
diff --git a/tools/aapt2/data/res/drawable/test.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png
similarity index 100%
rename from tools/aapt2/data/res/drawable/test.9.png
rename to tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
new file mode 100644
index 0000000..9f5a4a8
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:support="http://schemas.android.com/apk/res/android.appcompat"
+    android:id="@+id/view"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout/main.xml b/tools/aapt2/integration-tests/AppOne/res/layout/main.xml
new file mode 100644
index 0000000..ab1a251
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/layout/main.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:support="http://schemas.android.com/apk/res/android.appcompat"
+    android:id="@+id/view"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <fragment class="android.test.sample.App$Inner" />
+
+    <variable name="user" type="com.android.User" />
+
+    <View xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/me"
+        android:layout_width="1dp"
+        android:onClick="doClick"
+        android:text="@{user.name}"
+        android:background="#ffffff"
+        android:layout_height="match_parent"
+        app:flags="complex|weak"
+        android:colorAccent="#ffffff"/>
+</LinearLayout>
diff --git a/tools/aapt2/data/res/raw/test.txt b/tools/aapt2/integration-tests/AppOne/res/raw/test.txt
similarity index 100%
rename from tools/aapt2/data/res/raw/test.txt
rename to tools/aapt2/integration-tests/AppOne/res/raw/test.txt
diff --git a/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml b/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml
new file mode 100644
index 0000000..d8c11e2
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="App" parent="android:Theme.Material">
+        <item name="android:colorAccent">@color/accent</item>
+        <item name="android:text">Hey</item>
+    </style>
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/colors.xml b/tools/aapt2/integration-tests/AppOne/res/values/colors.xml
new file mode 100644
index 0000000..4df5077
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <color name="primary">#f44336</color>
+    <color name="primary_dark">#b71c1c</color>
+    <color name="accent">#fdd835</color>
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/styles.xml b/tools/aapt2/integration-tests/AppOne/res/values/styles.xml
new file mode 100644
index 0000000..f05845c
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values/styles.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:lib="http://schemas.android.com/apk/res/android.appcompat">
+    <style name="App">
+        <item name="android:background">@color/primary</item>
+        <item name="android:colorPrimary">@color/primary</item>
+        <item name="android:colorPrimaryDark">@color/primary_dark</item>
+        <item name="android:colorAccent">@color/accent</item>
+    </style>
+    <attr name="custom" format="reference" />
+    <style name="Pop">
+        <item name="custom">@android:drawable/btn_default</item>
+        <item name="android:focusable">true</item>
+    </style>
+    <string name="yo">@string/wow</string>
+
+    <declare-styleable name="View">
+        <attr name="custom" />
+        <attr name="decor">
+            <enum name="no-border" value="0"/>
+            <enum name="border" value="1"/>
+            <enum name="shadow" value="2"/>
+        </attr>
+    </declare-styleable>
+
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/test.xml b/tools/aapt2/integration-tests/AppOne/res/values/test.xml
new file mode 100644
index 0000000..f4b7471
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values/test.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Reference the two static libraries -->
+    <string name="AppFooBar">@string/FooBar</string>
+    <string name="AppFoo">@string/Foo</string>
+
+    <string name="hooha"><font bgcolor="#ffffff">Hey guys!</font> <xliff:g>My</xliff:g> name is <b>Adam</b>. How <b><i>are</i></b> you?</string>
+    <public name="hooha" type="string" id="0x7f020001"/>
+    <string name="wow">@android:string/ok</string>
+    <public name="layout_width" type="attr" />
+    <attr name="layout_width" format="boolean" />
+    <attr name="flags">
+        <flag name="complex" value="1" />
+        <flag name="pub" value="2" />
+        <flag name="weak" value="4" />
+    </attr>
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java b/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java
new file mode 100644
index 0000000..472b35a
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.aapt.app.one;
+
+public class AppOne {
+    // IDs from StaticLibOne
+    public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+    public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+
+    // IDs from StaticLibTwo
+    public static int FooBarId = com.android.aapt.staticlib.two.R.string.FooBar;
+}
+
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
new file mode 100644
index 0000000..0b7129a
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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_USE_AAPT2 := true
+LOCAL_MODULE := AaptTestStaticLibOne
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+# We need this to compile the Java sources of AaptTestStaticLibTwo using javac.
+LOCAL_JAR_EXCLUDE_FILES := none
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml
new file mode 100644
index 0000000..705047e
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 package="com.android.aapt.staticlib.one" />
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml b/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml
new file mode 100644
index 0000000..683c91c
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+      android:text="@string/Foo" />
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
new file mode 100644
index 0000000..d09a485
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <!-- An attribute from StaticLibOne -->
+    <attr name="StaticLibOne_attr" format="string" />
+
+    <string name="Foo">Foo</string>
+    <string name="Foo" product="tablet">Bar</string>
+
+    <declare-styleable name="Widget">
+        <attr name="StaticLibOne_attr" />
+    </declare-styleable>
+</resources>
diff --git a/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java b/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java
new file mode 100644
index 0000000..cf48f67
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.aapt.staticlib.one;
+
+public class StaticLibOne {
+    // IDs from StaticLibOne
+    public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+    public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+}
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/Android.mk b/tools/aapt2/integration-tests/StaticLibTwo/Android.mk
new file mode 100644
index 0000000..8b6eb41
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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_USE_AAPT2 := true
+LOCAL_MODULE := AaptTestStaticLibTwo
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestStaticLibOne
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml
new file mode 100644
index 0000000..28f0699
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 package="com.android.aapt.staticlib.two" />
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml
new file mode 100644
index 0000000..dd5979f
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="1123"/>
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml
new file mode 100644
index 0000000..ba98307
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<View xmlns:custom="http://schemas.android.com/apk/res-auto"
+      custom:StaticLibOne_attr="@string/FooBar" />
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml
new file mode 100644
index 0000000..97bb2a5
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="FooBar">@string/Foo</string>
+</resources>
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java b/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
new file mode 100644
index 0000000..7110dcd
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.aapt.staticlib.two;
+
+public class StaticLibTwo {
+    // IDs from StaticLibOne
+    public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+    public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+
+    // IDs from StaticLibTwo
+    public static int FooBarId = com.android.aapt.staticlib.two.R.string.FooBar;
+}
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 329dac9..b3e7a02 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -92,9 +92,8 @@
         return {};
     }
 
-    ZipString suffix(".flat");
     void* cookie = nullptr;
-    result = StartIteration(collection->mHandle, &cookie, nullptr, &suffix);
+    result = StartIteration(collection->mHandle, &cookie, nullptr, nullptr);
     if (result != 0) {
         if (outError) *outError = ErrorCodeString(result);
         return {};
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 9c25d4e..ba74439 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -38,7 +38,7 @@
         mComment << "/**";
     }
 
-    mComment << "\n" << " * " << std::move(comment);
+    mComment << "\n * " << std::move(comment);
 }
 
 void AnnotationProcessor::appendComment(const StringPiece16& comment) {
@@ -60,7 +60,11 @@
     }
 }
 
-void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) {
+void AnnotationProcessor::appendNewLine() {
+    mComment << "\n *";
+}
+
+void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) const {
     if (mHasComments) {
         std::string result = mComment.str();
         for (StringPiece line : util::tokenize<char>(result, '\n')) {
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index e7f2be0..0fc5b08 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -61,10 +61,12 @@
     void appendComment(const StringPiece16& comment);
     void appendComment(const StringPiece& comment);
 
+    void appendNewLine();
+
     /**
      * Writes the comments and annotations to the stream, with the given prefix before each line.
      */
-    void writeToStream(std::ostream* out, const StringPiece& prefix);
+    void writeToStream(std::ostream* out, const StringPiece& prefix) const;
 
 private:
     enum : uint32_t {
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
new file mode 100644
index 0000000..08f2c8b
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "java/ClassDefinition.h"
+#include "util/StringPiece.h"
+
+#include <ostream>
+
+namespace aapt {
+
+bool ClassDefinition::empty() const {
+    for (const std::unique_ptr<ClassMember>& member : mMembers) {
+        if (!member->empty()) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void ClassDefinition::writeToStream(const StringPiece& prefix, bool final,
+                                    std::ostream* out) const {
+    if (mMembers.empty() && !mCreateIfEmpty) {
+        return;
+    }
+
+    ClassMember::writeToStream(prefix, final, out);
+
+    *out << prefix << "public ";
+    if (mQualifier == ClassQualifier::Static) {
+        *out << "static ";
+    }
+    *out << "final class " << mName << " {\n";
+
+    std::string newPrefix = prefix.toString();
+    newPrefix.append(kIndent);
+
+    for (const std::unique_ptr<ClassMember>& member : mMembers) {
+        member->writeToStream(newPrefix, final, out);
+        *out << "\n";
+    }
+
+    *out << prefix << "}";
+}
+
+constexpr static const char* sWarningHeader =
+        "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
+        " *\n"
+        " * This class was automatically generated by the\n"
+        " * aapt tool from the resource data it found. It\n"
+        " * should not be modified by hand.\n"
+        " */\n\n";
+
+bool ClassDefinition::writeJavaFile(const ClassDefinition* def,
+                                    const StringPiece& package,
+                                    bool final,
+                                    std::ostream* out) {
+    *out << sWarningHeader << "package " << package << ";\n\n";
+    def->writeToStream("", final, out);
+    return bool(*out);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
new file mode 100644
index 0000000..53e0f6f
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_JAVA_CLASSDEFINITION_H
+#define AAPT_JAVA_CLASSDEFINITION_H
+
+#include "Resource.h"
+#include "java/AnnotationProcessor.h"
+#include "util/StringPiece.h"
+#include "util/Util.h"
+
+#include <android-base/macros.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+// The number of attributes to emit per line in a Styleable array.
+constexpr static size_t kAttribsPerLine = 4;
+constexpr static const char* kIndent = "  ";
+
+class ClassMember {
+public:
+    virtual ~ClassMember() = default;
+
+    AnnotationProcessor* getCommentBuilder() {
+        return &mProcessor;
+    }
+
+    virtual bool empty() const = 0;
+
+    virtual void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const {
+        mProcessor.writeToStream(out, prefix);
+    }
+
+private:
+    AnnotationProcessor mProcessor;
+};
+
+template <typename T>
+class PrimitiveMember : public ClassMember {
+public:
+    PrimitiveMember(const StringPiece& name, const T& val) :
+            mName(name.toString()), mVal(val) {
+    }
+
+    bool empty() const override {
+        return false;
+    }
+
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+        ClassMember::writeToStream(prefix, final, out);
+
+        *out << prefix << "public static " << (final ? "final " : "")
+             << "int " << mName << "=" << mVal << ";";
+    }
+
+private:
+    std::string mName;
+    T mVal;
+
+    DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+/**
+ * Specialization for strings so they get the right type and are quoted with "".
+ */
+template <>
+class PrimitiveMember<std::string> : public ClassMember {
+public:
+    PrimitiveMember(const StringPiece& name, const std::string& val) :
+            mName(name.toString()), mVal(val) {
+    }
+
+    bool empty() const override {
+        return false;
+    }
+
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+        ClassMember::writeToStream(prefix, final, out);
+
+        *out << prefix << "public static " << (final ? "final " : "")
+             << "String " << mName << "=\"" << mVal << "\";";
+    }
+
+private:
+    std::string mName;
+    std::string mVal;
+
+    DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+using IntMember = PrimitiveMember<uint32_t>;
+using ResourceMember = PrimitiveMember<ResourceId>;
+using StringMember = PrimitiveMember<std::string>;
+
+template <typename T>
+class PrimitiveArrayMember : public ClassMember {
+public:
+    PrimitiveArrayMember(const StringPiece& name) :
+            mName(name.toString()) {
+    }
+
+    void addElement(const T& val) {
+        mElements.push_back(val);
+    }
+
+    bool empty() const override {
+        return false;
+    }
+
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+        ClassMember::writeToStream(prefix, final, out);
+
+        *out << "public static final int[] " << mName << "={";
+
+        const auto begin = mElements.begin();
+        const auto end = mElements.end();
+        for (auto current = begin; current != end; ++current) {
+            if (std::distance(begin, current) % kAttribsPerLine == 0) {
+                *out << "\n" << prefix << kIndent << kIndent;
+            }
+
+            *out << *current;
+            if (std::distance(current, end) > 1) {
+                *out << ", ";
+            }
+        }
+        *out << "\n" << prefix << kIndent <<"};";
+    }
+
+private:
+    std::string mName;
+    std::vector<T> mElements;
+
+    DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
+};
+
+using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
+
+enum class ClassQualifier {
+    None,
+    Static
+};
+
+class ClassDefinition : public ClassMember {
+public:
+    static bool writeJavaFile(const ClassDefinition* def,
+                              const StringPiece& package,
+                              bool final,
+                              std::ostream* out);
+
+    ClassDefinition(const StringPiece& name, ClassQualifier qualifier, bool createIfEmpty) :
+            mName(name.toString()), mQualifier(qualifier), mCreateIfEmpty(createIfEmpty) {
+    }
+
+    void addMember(std::unique_ptr<ClassMember> member) {
+        mMembers.push_back(std::move(member));
+    }
+
+    bool empty() const override;
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override;
+
+private:
+    std::string mName;
+    ClassQualifier mQualifier;
+    bool mCreateIfEmpty;
+    std::vector<std::unique_ptr<ClassMember>> mMembers;
+
+    DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
+};
+
+} // namespace aapt
+
+#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/ClassDefinitionWriter.h b/tools/aapt2/java/ClassDefinitionWriter.h
deleted file mode 100644
index 04e1274..0000000
--- a/tools/aapt2/java/ClassDefinitionWriter.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_JAVA_CLASSDEFINITION_H
-#define AAPT_JAVA_CLASSDEFINITION_H
-
-#include "Resource.h"
-#include "java/AnnotationProcessor.h"
-#include "util/StringPiece.h"
-#include "util/Util.h"
-
-#include <sstream>
-#include <string>
-
-namespace aapt {
-
-struct ClassDefinitionWriterOptions {
-    bool useFinalQualifier = false;
-    bool forceCreationIfEmpty = false;
-};
-
-/**
- * Writes a class for use in R.java or Manifest.java.
- */
-class ClassDefinitionWriter {
-public:
-    ClassDefinitionWriter(const StringPiece& name, const ClassDefinitionWriterOptions& options) :
-            mName(name.toString()), mOptions(options), mStarted(false) {
-    }
-
-    ClassDefinitionWriter(const StringPiece16& name, const ClassDefinitionWriterOptions& options) :
-            mName(util::utf16ToUtf8(name)), mOptions(options), mStarted(false) {
-    }
-
-    void addIntMember(const StringPiece& name, AnnotationProcessor* processor,
-                      const uint32_t val) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
-             << "int " << name << "=" << val << ";\n";
-    }
-
-    void addStringMember(const StringPiece16& name, AnnotationProcessor* processor,
-                         const StringPiece16& val) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
-             << "String " << name << "=\"" << val << "\";\n";
-    }
-
-    void addResourceMember(const StringPiece16& name, AnnotationProcessor* processor,
-                           const ResourceId id) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
-             << "int " << name << "=" << id <<";\n";
-    }
-
-    template <typename Iterator, typename FieldAccessorFunc>
-    void addArrayMember(const StringPiece16& name, AnnotationProcessor* processor,
-                        const Iterator begin, const Iterator end, FieldAccessorFunc f) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static final int[] " << name << "={";
-
-        for (Iterator current = begin; current != end; ++current) {
-            if (std::distance(begin, current) % kAttribsPerLine == 0) {
-                mOut << "\n" << kIndent << kIndent;
-            }
-
-            mOut << f(*current);
-            if (std::distance(current, end) > 1) {
-                mOut << ", ";
-            }
-        }
-        mOut << "\n" << kIndent <<"};\n";
-    }
-
-    void writeToStream(std::ostream* out, const StringPiece& prefix,
-                       AnnotationProcessor* processor=nullptr) {
-        if (mOptions.forceCreationIfEmpty) {
-            ensureClassDeclaration();
-        }
-
-        if (!mStarted) {
-            return;
-        }
-
-        if (processor) {
-            processor->writeToStream(out, prefix);
-        }
-
-        std::string result = mOut.str();
-        for (StringPiece line : util::tokenize<char>(result, '\n')) {
-            *out << prefix << line << "\n";
-        }
-        *out << prefix << "}\n";
-    }
-
-private:
-    constexpr static const char* kIndent = "  ";
-
-    // The number of attributes to emit per line in a Styleable array.
-    constexpr static size_t kAttribsPerLine = 4;
-
-    void ensureClassDeclaration() {
-        if (!mStarted) {
-            mStarted = true;
-            mOut << "public static final class " << mName << " {\n";
-        }
-    }
-
-    std::stringstream mOut;
-    std::string mName;
-    ClassDefinitionWriterOptions mOptions;
-    bool mStarted;
-};
-
-} // namespace aapt
-
-#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 6e340a2..092bab24 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -21,8 +21,9 @@
 #include "ValueVisitor.h"
 
 #include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
 #include "java/JavaClassGenerator.h"
+#include "process/SymbolTable.h"
 #include "util/StringPiece.h"
 
 #include <algorithm>
@@ -33,18 +34,9 @@
 
 namespace aapt {
 
-JavaClassGenerator::JavaClassGenerator(ResourceTable* table, JavaClassGeneratorOptions options) :
-        mTable(table), mOptions(options) {
-}
-
-static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) {
-    *out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
-            " *\n"
-            " * This class was automatically generated by the\n"
-            " * aapt tool from the resource data it found. It\n"
-            " * should not be modified by hand.\n"
-            " */\n\n"
-            "package " << packageNameToGenerate << ";\n\n";
+JavaClassGenerator::JavaClassGenerator(IAaptContext* context, ResourceTable* table,
+                                       const JavaClassGeneratorOptions& options) :
+        mContext(context), mTable(table), mOptions(options) {
 }
 
 static const std::set<StringPiece16> sJavaIdentifiers = {
@@ -68,71 +60,39 @@
  * Java symbols can not contain . or -, but those are valid in a resource name.
  * Replace those with '_'.
  */
-static std::u16string transform(const StringPiece16& symbol) {
-    std::u16string output = symbol.toString();
-    for (char16_t& c : output) {
-        if (c == u'.' || c == u'-') {
-            c = u'_';
+static std::string transform(const StringPiece16& symbol) {
+    std::string output = util::utf16ToUtf8(symbol);
+    for (char& c : output) {
+        if (c == '.' || c == '-') {
+            c = '_';
         }
     }
     return output;
 }
 
-bool JavaClassGenerator::skipSymbol(SymbolState state) {
-    switch (mOptions.types) {
-    case JavaClassGeneratorOptions::SymbolTypes::kAll:
-        return false;
-    case JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate:
-        return state == SymbolState::kUndefined;
-    case JavaClassGeneratorOptions::SymbolTypes::kPublic:
-        return state != SymbolState::kPublic;
+/**
+ * Transforms an attribute in a styleable to the Java field name:
+ *
+ * <declare-styleable name="Foo">
+ *   <attr name="android:bar" />
+ *   <attr name="bar" />
+ * </declare-styleable>
+ *
+ * Foo_android_bar
+ * Foo_bar
+ */
+static std::string transformNestedAttr(const ResourceNameRef& attrName,
+                                       const std::string& styleableClassName,
+                                       const StringPiece16& packageNameToGenerate) {
+    std::string output = styleableClassName;
+
+    // We may reference IDs from other packages, so prefix the entry name with
+    // the package.
+    if (!attrName.package.empty() && packageNameToGenerate != attrName.package) {
+        output += "_" + transform(attrName.package);
     }
-    return true;
-}
-
-void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
-                                                     AnnotationProcessor* processor,
-                                                     const StringPiece16& packageNameToGenerate,
-                                                     const std::u16string& entryName,
-                                                     const Styleable* styleable) {
-    // This must be sorted by resource ID.
-    std::vector<std::pair<ResourceId, ResourceNameRef>> sortedAttributes;
-    sortedAttributes.reserve(styleable->entries.size());
-    for (const auto& attr : styleable->entries) {
-        // If we are not encoding final attributes, the styleable entry may have no ID
-        // if we are building a static library.
-        assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
-        assert(attr.name && "no name set for Styleable entry");
-        sortedAttributes.emplace_back(attr.id ? attr.id.value() : ResourceId(0), attr.name.value());
-    }
-    std::sort(sortedAttributes.begin(), sortedAttributes.end());
-
-    auto accessorFunc = [](const std::pair<ResourceId, ResourceNameRef>& a) -> ResourceId {
-        return a.first;
-    };
-
-    // First we emit the array containing the IDs of each attribute.
-    outClassDef->addArrayMember(transform(entryName), processor,
-                                sortedAttributes.begin(),
-                                sortedAttributes.end(),
-                                accessorFunc);
-
-    // Now we emit the indices into the array.
-    size_t attrCount = sortedAttributes.size();
-    for (size_t i = 0; i < attrCount; i++) {
-        std::stringstream name;
-        name << transform(entryName);
-
-        // We may reference IDs from other packages, so prefix the entry name with
-        // the package.
-        const ResourceNameRef& itemName = sortedAttributes[i].second;
-        if (!itemName.package.empty() && packageNameToGenerate != itemName.package) {
-            name << "_" << transform(itemName.package);
-        }
-        name << "_" << transform(itemName.entry);
-
-        outClassDef->addIntMember(name.str(), nullptr, i);
-    }
+    output += "_" + transform(attrName.entry);
+    return output;
 }
 
 static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) {
@@ -206,25 +166,209 @@
         for (const Attribute::Symbol& symbol : attr->symbols) {
             std::stringstream line;
             line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>"
-                 << "<td>" << std::hex << symbol.value << std::dec << "</td>"
-                 << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>";
+            << "<td>" << std::hex << symbol.value << std::dec << "</td>"
+            << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>";
             processor->appendComment(line.str());
         }
         processor->appendComment("</table>");
     }
 }
 
-bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef,
-                                              const StringPiece16& packageNameToGenerate,
-                                              const ResourceTablePackage* package,
-                                              const ResourceTableType* type) {
+bool JavaClassGenerator::skipSymbol(SymbolState state) {
+    switch (mOptions.types) {
+    case JavaClassGeneratorOptions::SymbolTypes::kAll:
+        return false;
+    case JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate:
+        return state == SymbolState::kUndefined;
+    case JavaClassGeneratorOptions::SymbolTypes::kPublic:
+        return state != SymbolState::kPublic;
+    }
+    return true;
+}
+
+struct StyleableAttr {
+    const Reference* attrRef;
+    std::shared_ptr<Attribute> attribute;
+    std::string fieldName;
+};
+
+static bool lessStyleableAttr(const StyleableAttr& lhs, const StyleableAttr& rhs) {
+    const ResourceId lhsId = lhs.attrRef->id ? lhs.attrRef->id.value() : ResourceId(0);
+    const ResourceId rhsId = rhs.attrRef->id ? rhs.attrRef->id.value() : ResourceId(0);
+    if (lhsId < rhsId) {
+        return true;
+    } else if (lhsId > rhsId) {
+        return false;
+    } else {
+        return lhs.attrRef->name.value() < rhs.attrRef->name.value();
+    }
+}
+
+void JavaClassGenerator::addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+                                                    const std::u16string& entryName,
+                                                    const Styleable* styleable,
+                                                    ClassDefinition* outStyleableClassDef) {
+    const std::string className = transform(entryName);
+
+    std::unique_ptr<ResourceArrayMember> styleableArrayDef =
+            util::make_unique<ResourceArrayMember>(className);
+
+    // This must be sorted by resource ID.
+    std::vector<StyleableAttr> sortedAttributes;
+    sortedAttributes.reserve(styleable->entries.size());
+    for (const auto& attr : styleable->entries) {
+        // If we are not encoding final attributes, the styleable entry may have no ID
+        // if we are building a static library.
+        assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
+        assert(attr.name && "no name set for Styleable entry");
+
+        // We will need the unmangled, transformed name in the comments and the field,
+        // so create it once and cache it in this StyleableAttr data structure.
+        StyleableAttr styleableAttr = {};
+        styleableAttr.attrRef = &attr;
+        styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className,
+                                                      packageNameToGenerate);
+
+        Reference mangledReference;
+        mangledReference.id = attr.id;
+        mangledReference.name = attr.name;
+        if (mangledReference.name.value().package.empty()) {
+            mangledReference.name.value().package = mContext->getCompilationPackage();
+        }
+
+        if (Maybe<ResourceName> mangledName =
+                mContext->getNameMangler()->mangleName(mangledReference.name.value())) {
+            mangledReference.name = mangledName;
+        }
+
+        // Look up the symbol so that we can write out in the comments what are possible
+        // legal values for this attribute.
+        const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference(
+                mangledReference);
+        if (symbol) {
+            styleableAttr.attribute = symbol->attribute;
+        }
+        sortedAttributes.push_back(std::move(styleableAttr));
+    }
+
+    // Sort the attributes by ID.
+    std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr);
+
+    const size_t attrCount = sortedAttributes.size();
+    if (attrCount > 0) {
+        // Build the comment string for the Styleable. It includes details about the
+        // child attributes.
+        std::stringstream styleableComment;
+        if (!styleable->getComment().empty()) {
+            styleableComment << styleable->getComment() << "\n";
+        } else {
+            styleableComment << "Attributes that can be used with a " << className << ".\n";
+        }
+
+        styleableComment <<
+                "<p>Includes the following attributes:</p>\n"
+                "<table>\n"
+                "<colgroup align=\"left\" />\n"
+                "<colgroup align=\"left\" />\n"
+                "<tr><th>Attribute</th><th>Description</th></tr>\n";
+
+        for (const StyleableAttr& entry : sortedAttributes) {
+            const ResourceName& attrName = entry.attrRef->name.value();
+            styleableComment << "<tr><td>";
+            styleableComment << "<code>{@link #"
+                             << entry.fieldName << " "
+                             << (!attrName.package.empty()
+                                    ? attrName.package : mContext->getCompilationPackage())
+                             << ":" << attrName.entry
+                             << "}</code>";
+            styleableComment << "</td>";
+
+            styleableComment << "<td>";
+            if (entry.attribute) {
+                styleableComment << entry.attribute->getComment();
+            }
+            styleableComment << "</td></tr>\n";
+        }
+        styleableComment << "</table>\n";
+
+        for (const StyleableAttr& entry : sortedAttributes) {
+            styleableComment << "@see #" << entry.fieldName << "\n";
+        }
+
+        styleableArrayDef->getCommentBuilder()->appendComment(styleableComment.str());
+    }
+
+    // Add the ResourceIds to the array member.
+    for (const StyleableAttr& styleableAttr : sortedAttributes) {
+        styleableArrayDef->addElement(
+                styleableAttr.attrRef->id ? styleableAttr.attrRef->id.value() : ResourceId(0));
+    }
+
+    // Add the Styleable array to the Styleable class.
+    outStyleableClassDef->addMember(std::move(styleableArrayDef));
+
+    // Now we emit the indices into the array.
+    for (size_t i = 0; i < attrCount; i++) {
+        const StyleableAttr& styleableAttr = sortedAttributes[i];
+        const ResourceName& attrName = styleableAttr.attrRef->name.value();
+
+        StringPiece16 packageName = attrName.package;
+        if (packageName.empty()) {
+            packageName = mContext->getCompilationPackage();
+        }
+
+        std::unique_ptr<IntMember> indexMember = util::make_unique<IntMember>(
+                sortedAttributes[i].fieldName, i);
+
+        AnnotationProcessor* attrProcessor = indexMember->getCommentBuilder();
+
+        StringPiece16 comment = styleableAttr.attrRef->getComment();
+        if (styleableAttr.attribute && comment.empty()) {
+            comment = styleableAttr.attribute->getComment();
+        }
+
+        if (!comment.empty()) {
+            attrProcessor->appendComment("<p>\n@attr description");
+            attrProcessor->appendComment(comment);
+        } else {
+            std::stringstream defaultComment;
+            defaultComment
+                    << "<p>This symbol is the offset where the "
+                    << "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n"
+                    << "attribute's value can be found in the "
+                    << "{@link #" << className << "} array.";
+            attrProcessor->appendComment(defaultComment.str());
+        }
+
+        attrProcessor->appendNewLine();
+
+        if (styleableAttr.attribute) {
+            addAttributeFormatDoc(attrProcessor, styleableAttr.attribute.get());
+            attrProcessor->appendNewLine();
+        }
+
+        std::stringstream doclavaName;
+        doclavaName << "@attr name " << packageName << ":" << attrName.entry;;
+        attrProcessor->appendComment(doclavaName.str());
+
+        outStyleableClassDef->addMember(std::move(indexMember));
+    }
+}
+
+bool JavaClassGenerator::addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+                                               const ResourceTablePackage* package,
+                                               const ResourceTableType* type,
+                                               ClassDefinition* outTypeClassDef) {
+
     for (const auto& entry : type->entries) {
         if (skipSymbol(entry->symbolStatus.state)) {
             continue;
         }
 
-        ResourceId id(package->id.value(), type->id.value(), entry->id.value());
-        assert(id.isValid());
+        ResourceId id;
+        if (package->id && type->id && entry->id) {
+            id = ResourceId(package->id.value(), type->id.value(), entry->id.value());
+        }
 
         std::u16string unmangledPackage;
         std::u16string unmangledName = entry->name;
@@ -249,33 +393,41 @@
             return false;
         }
 
-        // Build the comments and annotations for this entry.
-
-        AnnotationProcessor processor;
-        if (entry->symbolStatus.state != SymbolState::kUndefined) {
-            processor.appendComment(entry->symbolStatus.comment);
-        }
-
-        for (const auto& configValue : entry->values) {
-            processor.appendComment(configValue->value->getComment());
-        }
-
-        // If this is an Attribute, append the format Javadoc.
-        if (!entry->values.empty()) {
-            if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
-                // We list out the available values for the given attribute.
-                addAttributeFormatDoc(&processor, attr);
-            }
-        }
-
         if (type->type == ResourceType::kStyleable) {
             assert(!entry->values.empty());
+
             const Styleable* styleable = static_cast<const Styleable*>(
                     entry->values.front()->value.get());
-            writeStyleableEntryForClass(outClassDef, &processor, packageNameToGenerate,
-                                        unmangledName, styleable);
+
+            // Comments are handled within this method.
+            addMembersToStyleableClass(packageNameToGenerate, unmangledName, styleable,
+                                       outTypeClassDef);
         } else {
-            outClassDef->addResourceMember(transform(unmangledName), &processor, id);
+            std::unique_ptr<ResourceMember> resourceMember =
+                    util::make_unique<ResourceMember>(transform(unmangledName), id);
+
+            // Build the comments and annotations for this entry.
+            AnnotationProcessor* processor = resourceMember->getCommentBuilder();
+
+            // Add the comments from any <public> tags.
+            if (entry->symbolStatus.state != SymbolState::kUndefined) {
+                processor->appendComment(entry->symbolStatus.comment);
+            }
+
+            // Add the comments from all configurations of this entry.
+            for (const auto& configValue : entry->values) {
+                processor->appendComment(configValue->value->getComment());
+            }
+
+            // If this is an Attribute, append the format Javadoc.
+            if (!entry->values.empty()) {
+                if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
+                    // We list out the available values for the given attribute.
+                    addAttributeFormatDoc(processor, attr);
+                }
+            }
+
+            outTypeClassDef->addMember(std::move(resourceMember));
         }
     }
     return true;
@@ -285,11 +437,19 @@
     return generate(packageNameToGenerate, packageNameToGenerate, out);
 }
 
+static void appendJavaDocAnnotations(const std::vector<std::string>& annotations,
+                                     AnnotationProcessor* processor) {
+    for (const std::string& annotation : annotations) {
+        std::string properAnnotation = "@";
+        properAnnotation += annotation;
+        processor->appendComment(properAnnotation);
+    }
+}
+
 bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate,
                                   const StringPiece16& outPackageName, std::ostream* out) {
-    generateHeader(outPackageName, out);
 
-    *out << "public final class R {\n";
+    ClassDefinition rClass("R", ClassQualifier::None, true);
 
     for (const auto& package : mTable->packages) {
         for (const auto& type : package->types) {
@@ -297,13 +457,15 @@
                 continue;
             }
 
-            ClassDefinitionWriterOptions classOptions;
-            classOptions.useFinalQualifier = mOptions.useFinal;
-            classOptions.forceCreationIfEmpty =
+            const bool forceCreationIfEmpty =
                     (mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
-            ClassDefinitionWriter classDef(toString(type->type), classOptions);
-            bool result = writeEntriesForClass(&classDef, packageNameToGenerate,
-                                               package.get(), type.get());
+
+            std::unique_ptr<ClassDefinition> classDef = util::make_unique<ClassDefinition>(
+                    util::utf16ToUtf8(toString(type->type)), ClassQualifier::Static,
+                    forceCreationIfEmpty);
+
+            bool result = addMembersToTypeClass(packageNameToGenerate, package.get(), type.get(),
+                                                classDef.get());
             if (!result) {
                 return false;
             }
@@ -312,30 +474,36 @@
                 // Also include private attributes in this same class.
                 ResourceTableType* privType = package->findType(ResourceType::kAttrPrivate);
                 if (privType) {
-                    result = writeEntriesForClass(&classDef, packageNameToGenerate,
-                                                  package.get(), privType);
+                    result = addMembersToTypeClass(packageNameToGenerate, package.get(), privType,
+                                                   classDef.get());
                     if (!result) {
                         return false;
                     }
                 }
             }
 
-            AnnotationProcessor processor;
             if (type->type == ResourceType::kStyleable &&
                     mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) {
                 // When generating a public R class, we don't want Styleable to be part of the API.
                 // It is only emitted for documentation purposes.
-                processor.appendComment("@doconly");
+                classDef->getCommentBuilder()->appendComment("@doconly");
             }
-            classDef.writeToStream(out, "  ", &processor);
+
+            appendJavaDocAnnotations(mOptions.javadocAnnotations, classDef->getCommentBuilder());
+
+            rClass.addMember(std::move(classDef));
         }
     }
 
-    *out << "}\n";
+    appendJavaDocAnnotations(mOptions.javadocAnnotations, rClass.getCommentBuilder());
+
+    if (!ClassDefinition::writeJavaFile(&rClass, util::utf16ToUtf8(outPackageName),
+                                        mOptions.useFinal, out)) {
+        return false;
+    }
+
     out->flush();
     return true;
 }
 
-
-
 } // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 023d6d6..77e0ed7 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -19,7 +19,7 @@
 
 #include "ResourceTable.h"
 #include "ResourceValues.h"
-
+#include "process/IResourceTableConsumer.h"
 #include "util/StringPiece.h"
 
 #include <ostream>
@@ -28,7 +28,7 @@
 namespace aapt {
 
 class AnnotationProcessor;
-class ClassDefinitionWriter;
+class ClassDefinition;
 
 struct JavaClassGeneratorOptions {
     /*
@@ -44,6 +44,11 @@
     };
 
     SymbolTypes types = SymbolTypes::kAll;
+
+    /**
+     * A list of JavaDoc annotations to add to the comments of all generated classes.
+     */
+    std::vector<std::string> javadocAnnotations;
 };
 
 /*
@@ -51,7 +56,8 @@
  */
 class JavaClassGenerator {
 public:
-    JavaClassGenerator(ResourceTable* table, JavaClassGeneratorOptions options);
+    JavaClassGenerator(IAaptContext* context, ResourceTable* table,
+                       const JavaClassGeneratorOptions& options);
 
     /*
      * Writes the R.java file to `out`. Only symbols belonging to `package` are written.
@@ -69,19 +75,19 @@
     const std::string& getError() const;
 
 private:
-    bool writeEntriesForClass(ClassDefinitionWriter* outClassDef,
-                              const StringPiece16& packageNameToGenerate,
-                              const ResourceTablePackage* package,
-                              const ResourceTableType* type);
+    bool addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+                               const ResourceTablePackage* package,
+                               const ResourceTableType* type,
+                               ClassDefinition* outTypeClassDef);
 
-    void writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
-                                     AnnotationProcessor* processor,
-                                     const StringPiece16& packageNameToGenerate,
-                                     const std::u16string& entryName,
-                                     const Styleable* styleable);
+    void addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+                                    const std::u16string& entryName,
+                                    const Styleable* styleable,
+                                    ClassDefinition* outStyleableClassDef);
 
     bool skipSymbol(SymbolState state);
 
+    IAaptContext* mContext;
     ResourceTable* mTable;
     JavaClassGeneratorOptions mOptions;
     std::string mError;
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index e9e7881..4f041b8 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -15,11 +15,9 @@
  */
 
 #include "java/JavaClassGenerator.h"
+#include "test/Test.h"
 #include "util/Util.h"
 
-#include "test/Builders.h"
-
-#include <gtest/gtest.h>
 #include <sstream>
 #include <string>
 
@@ -31,7 +29,11 @@
             .addSimple(u"@android:id/class", ResourceId(0x01020000))
             .build();
 
-    JavaClassGenerator generator(table.get(), {});
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+    JavaClassGenerator generator(context.get(), table.get(), {});
 
     std::stringstream out;
     EXPECT_FALSE(generator.generate(u"android", &out));
@@ -48,7 +50,11 @@
                               .build())
             .build();
 
-    JavaClassGenerator generator(table.get(), {});
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+    JavaClassGenerator generator(context.get(), table.get(), {});
 
     std::stringstream out;
     EXPECT_TRUE(generator.generate(u"android", &out));
@@ -72,7 +78,11 @@
             .addSimple(u"@android:id/com.foo$two", ResourceId(0x01020001))
             .build();
 
-    JavaClassGenerator generator(table.get(), {});
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+    JavaClassGenerator generator(context.get(), table.get(), {});
     std::stringstream out;
     ASSERT_TRUE(generator.generate(u"android", u"com.android.internal", &out));
 
@@ -90,7 +100,11 @@
             .addSimple(u"@android:^attr-private/one", ResourceId(0x01010000))
             .build();
 
-    JavaClassGenerator generator(table.get(), {});
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+    JavaClassGenerator generator(context.get(), table.get(), {});
     std::stringstream out;
     ASSERT_TRUE(generator.generate(u"android", &out));
 
@@ -110,10 +124,15 @@
             .setSymbolState(u"@android:id/two", ResourceId(0x01020001), SymbolState::kPrivate)
             .build();
 
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+
     JavaClassGeneratorOptions options;
     options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
     {
-        JavaClassGenerator generator(table.get(), options);
+        JavaClassGenerator generator(context.get(), table.get(), options);
         std::stringstream out;
         ASSERT_TRUE(generator.generate(u"android", &out));
         std::string output = out.str();
@@ -124,7 +143,7 @@
 
     options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
     {
-        JavaClassGenerator generator(table.get(), options);
+        JavaClassGenerator generator(context.get(), table.get(), options);
         std::stringstream out;
         ASSERT_TRUE(generator.generate(u"android", &out));
         std::string output = out.str();
@@ -135,7 +154,7 @@
 
     options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
     {
-        JavaClassGenerator generator(table.get(), options);
+        JavaClassGenerator generator(context.get(), table.get(), options);
         std::stringstream out;
         ASSERT_TRUE(generator.generate(u"android", &out));
         std::string output = out.str();
@@ -189,7 +208,11 @@
                                   .build())
                 .build();
 
-    JavaClassGenerator generator(table.get(), {});
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+    JavaClassGenerator generator(context.get(), table.get(), {});
 
     std::stringstream out;
     EXPECT_TRUE(generator.generate(u"android", &out));
@@ -207,8 +230,11 @@
     test::getValue<Id>(table.get(), u"@android:id/foo")
             ->setComment(std::u16string(u"This is a comment\n@deprecated"));
 
-    JavaClassGenerator generator(table.get(), {});
-
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+    JavaClassGenerator generator(context.get(), table.get(), {});
     std::stringstream out;
     ASSERT_TRUE(generator.generate(u"android", &out));
     std::string actual = out.str();
@@ -227,7 +253,35 @@
 }
 
 TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
+    Attribute attr(false);
+    attr.setComment(StringPiece16(u"This is an attribute"));
 
+    Styleable styleable;
+    styleable.entries.push_back(Reference(test::parseNameOrDie(u"@android:attr/one")));
+    styleable.setComment(StringPiece16(u"This is a styleable"));
+
+    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+            .setPackageId(u"android", 0x01)
+            .addValue(u"@android:attr/one", util::make_unique<Attribute>(attr))
+            .addValue(u"@android:styleable/Container",
+                      std::unique_ptr<Styleable>(styleable.clone(nullptr)))
+            .build();
+
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .setNameManglerPolicy(NameManglerPolicy{ u"android" })
+            .build();
+    JavaClassGeneratorOptions options;
+    options.useFinal = false;
+    JavaClassGenerator generator(context.get(), table.get(), options);
+    std::stringstream out;
+    ASSERT_TRUE(generator.generate(u"android", &out));
+    std::string actual = out.str();
+
+    EXPECT_NE(std::string::npos, actual.find("@attr name android:one"));
+    EXPECT_NE(std::string::npos, actual.find("@attr description"));
+    EXPECT_NE(std::string::npos, actual.find(util::utf16ToUtf8(attr.getComment())));
+    EXPECT_NE(std::string::npos, actual.find(util::utf16ToUtf8(styleable.getComment())));
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index a9b4c14..be8955e 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -16,7 +16,7 @@
 
 #include "Source.h"
 #include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
 #include "java/ManifestClassGenerator.h"
 #include "util/Maybe.h"
 #include "xml/XmlDom.h"
@@ -58,8 +58,8 @@
     return result;
 }
 
-static bool writeSymbol(IDiagnostics* diag, ClassDefinitionWriter* outClassDef, const Source& source,
-                        xml::Element* el) {
+static bool writeSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
+                        ClassDefinition* classDef) {
     xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name");
     if (!attr) {
         diag->error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
@@ -72,54 +72,53 @@
         return false;
     }
 
-    AnnotationProcessor processor;
-    processor.appendComment(el->comment);
-    outClassDef->addStringMember(result.value(), &processor, attr->value);
+    std::unique_ptr<StringMember> stringMember = util::make_unique<StringMember>(
+            util::utf16ToUtf8(result.value()), util::utf16ToUtf8(attr->value));
+    stringMember->getCommentBuilder()->appendComment(el->comment);
+
+    classDef->addMember(std::move(stringMember));
     return true;
 }
 
-bool ManifestClassGenerator::generate(IDiagnostics* diag, const StringPiece16& package,
-                                      xml::XmlResource* res, std::ostream* out) {
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
     xml::Element* el = xml::findRootElement(res->root.get());
     if (!el) {
-        return false;
+        diag->error(DiagMessage(res->file.source) << "no root tag defined");
+        return {};
     }
 
     if (el->name != u"manifest" && !el->namespaceUri.empty()) {
         diag->error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
-        return false;
+        return {};
     }
 
-    *out << "package " << package << ";\n\n"
-         << "public final class Manifest {\n";
+    std::unique_ptr<ClassDefinition> permissionClass =
+            util::make_unique<ClassDefinition>("permission", ClassQualifier::Static, false);
+    std::unique_ptr<ClassDefinition> permissionGroupClass =
+            util::make_unique<ClassDefinition>("permission_group", ClassQualifier::Static, false);
 
     bool error = false;
+
     std::vector<xml::Element*> children = el->getChildElements();
-
-    ClassDefinitionWriterOptions classOptions;
-    classOptions.useFinalQualifier = true;
-    classOptions.forceCreationIfEmpty = false;
-
-    // First write out permissions.
-    ClassDefinitionWriter classDef("permission", classOptions);
     for (xml::Element* childEl : children) {
-        if (childEl->namespaceUri.empty() && childEl->name == u"permission") {
-            error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
+        if (childEl->namespaceUri.empty()) {
+            if (childEl->name == u"permission") {
+                error |= !writeSymbol(res->file.source, diag, childEl, permissionClass.get());
+            } else if (childEl->name == u"permission-group") {
+                error |= !writeSymbol(res->file.source, diag, childEl, permissionGroupClass.get());
+            }
         }
     }
-    classDef.writeToStream(out, "  ");
 
-    // Next write out permission groups.
-    classDef = ClassDefinitionWriter("permission_group", classOptions);
-    for (xml::Element* childEl : children) {
-        if (childEl->namespaceUri.empty() && childEl->name == u"permission-group") {
-            error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
-        }
+    if (error) {
+        return {};
     }
-    classDef.writeToStream(out, "  ");
 
-    *out << "}\n";
-    return !error;
+    std::unique_ptr<ClassDefinition> manifestClass =
+            util::make_unique<ClassDefinition>("Manifest", ClassQualifier::None, false);
+    manifestClass->addMember(std::move(permissionClass));
+    manifestClass->addMember(std::move(permissionGroupClass));
+    return manifestClass;
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index 226ed23..f565289 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -18,6 +18,7 @@
 #define AAPT_JAVA_MANIFESTCLASSGENERATOR_H
 
 #include "Diagnostics.h"
+#include "java/ClassDefinition.h"
 #include "util/StringPiece.h"
 #include "xml/XmlDom.h"
 
@@ -25,10 +26,7 @@
 
 namespace aapt {
 
-struct ManifestClassGenerator {
-    bool generate(IDiagnostics* diag, const StringPiece16& package, xml::XmlResource* res,
-                  std::ostream* out);
-};
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
 
 } // namespace aapt
 
diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp
index fc57ae6f..a9ec318 100644
--- a/tools/aapt2/java/ManifestClassGenerator_test.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp
@@ -22,6 +22,23 @@
 
 namespace aapt {
 
+static ::testing::AssertionResult getManifestClassText(IAaptContext* context, xml::XmlResource* res,
+                                                       std::string* outStr) {
+    std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+            context->getDiagnostics(), res);
+    if (!manifestClass) {
+        return ::testing::AssertionFailure() << "manifestClass == nullptr";
+    }
+
+    std::stringstream out;
+    if (!manifestClass->writeJavaFile(manifestClass.get(), "android", true, &out)) {
+        return ::testing::AssertionFailure() << "failed to write java file";
+    }
+
+    *outStr = out.str();
+    return ::testing::AssertionSuccess();
+}
+
 TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) {
     std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
     std::unique_ptr<xml::XmlResource> manifest = test::buildXmlDom(R"EOF(
@@ -32,11 +49,8 @@
           <permission-group android:name="foo.bar.PERMISSION" />
         </manifest>)EOF");
 
-    std::stringstream out;
-    ManifestClassGenerator generator;
-    ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
-    std::string actual = out.str();
+    std::string actual;
+    ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
 
     const size_t permissionClassPos = actual.find("public static final class permission {");
     const size_t permissionGroupClassPos =
@@ -87,11 +101,8 @@
           <permission android:name="android.permission.SECRET" />
         </manifest>)EOF");
 
-    std::stringstream out;
-    ManifestClassGenerator generator;
-    ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
-    std::string actual = out.str();
+    std::string actual;
+    ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
 
     EXPECT_NE(std::string::npos, actual.find(
 R"EOF(    /**
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index d83f6def..8c8bffa 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -62,8 +62,11 @@
     std::set<std::u16string> extraJavaPackages;
     Maybe<std::string> generateProguardRulesPath;
     bool noAutoVersion = false;
+    bool noVersionVectors = false;
     bool staticLib = false;
+    bool noStaticLibPackages = false;
     bool generateNonFinalIds = false;
+    std::vector<std::string> javadocAnnotations;
     bool outputToDirectory = false;
     bool autoAddOverlay = false;
     bool doNotCompressAnything = false;
@@ -74,37 +77,58 @@
     TableSplitterOptions tableSplitterOptions;
 };
 
-struct LinkContext : public IAaptContext {
-    StdErrDiagnostics mDiagnostics;
-    std::unique_ptr<NameMangler> mNameMangler;
-    std::u16string mCompilationPackage;
-    uint8_t mPackageId;
-    std::unique_ptr<ISymbolTable> mSymbols;
-    bool mVerbose = false;
+class LinkContext : public IAaptContext {
+public:
+    LinkContext() : mNameMangler({}) {
+    }
 
     IDiagnostics* getDiagnostics() override {
         return &mDiagnostics;
     }
 
     NameMangler* getNameMangler() override {
-        return mNameMangler.get();
+        return &mNameMangler;
     }
 
-    StringPiece16 getCompilationPackage() override {
+    void setNameManglerPolicy(const NameManglerPolicy& policy) {
+        mNameMangler = NameMangler(policy);
+    }
+
+    const std::u16string& getCompilationPackage() override {
         return mCompilationPackage;
     }
 
+    void setCompilationPackage(const StringPiece16& packageName) {
+        mCompilationPackage = packageName.toString();
+    }
+
     uint8_t getPackageId() override {
         return mPackageId;
     }
 
-    ISymbolTable* getExternalSymbols() override {
-        return mSymbols.get();
+    void setPackageId(uint8_t id) {
+        mPackageId = id;
+    }
+
+    SymbolTable* getExternalSymbols() override {
+        return &mSymbols;
     }
 
     bool verbose() override {
         return mVerbose;
     }
+
+    void setVerbose(bool val) {
+        mVerbose = val;
+    }
+
+private:
+    StdErrDiagnostics mDiagnostics;
+    NameMangler mNameMangler;
+    std::u16string mCompilationPackage;
+    uint8_t mPackageId = 0x0;
+    SymbolTable mSymbols;
+    bool mVerbose = false;
 };
 
 static bool copyFileToArchive(io::IFile* file, const std::string& outPath,
@@ -117,11 +141,19 @@
         return false;
     }
 
-    CompiledFileInputStream inputStream(data->data(), data->size());
-    if (!inputStream.CompiledFile()) {
-        context->getDiagnostics()->error(DiagMessage(file->getSource())
-                                         << "invalid compiled file header");
-        return false;
+    const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data->data());
+    size_t bufferSize = data->size();
+
+    // If the file ends with .flat, we must strip off the CompiledFileHeader from it.
+    if (util::stringEndsWith<char>(file->getSource().path, ".flat")) {
+        CompiledFileInputStream inputStream(data->data(), data->size());
+        if (!inputStream.CompiledFile()) {
+            context->getDiagnostics()->error(DiagMessage(file->getSource())
+                                             << "invalid compiled file header");
+            return false;
+        }
+        buffer = reinterpret_cast<const uint8_t*>(inputStream.data());
+        bufferSize = inputStream.size();
     }
 
     if (context->verbose()) {
@@ -129,8 +161,7 @@
     }
 
     if (writer->startEntry(outPath, compressionFlags)) {
-        if (writer->writeEntry(reinterpret_cast<const uint8_t*>(inputStream.data()),
-                               inputStream.size())) {
+        if (writer->writeEntry(buffer, bufferSize)) {
             if (writer->finishEntry()) {
                 return true;
             }
@@ -156,7 +187,7 @@
         DiagMessage msg;
         msg << "writing " << path << " to archive";
         if (maxSdkLevel) {
-            msg << " maxSdkLevel=" << maxSdkLevel.value();
+            msg << " maxSdkLevel=" << maxSdkLevel.value() << " keepRawValues=" << keepRawValues;
         }
         context->getDiagnostics()->note(msg);
     }
@@ -248,6 +279,7 @@
 
 struct ResourceFileFlattenerOptions {
     bool noAutoVersion = false;
+    bool noVersionVectors = false;
     bool keepRawValues = false;
     bool doNotCompressAnything = false;
     std::vector<std::string> extensionsToNotCompress;
@@ -267,14 +299,13 @@
         io::IFile* fileToCopy;
         std::unique_ptr<xml::XmlResource> xmlToFlatten;
         std::string dstPath;
+        bool skipVersion = false;
     };
 
     uint32_t getCompressionFlags(const StringPiece& str);
 
-    std::unique_ptr<xml::XmlResource> linkAndVersionXmlFile(const ResourceEntry* entry,
-                                                            const ResourceFile& fileDesc,
-                                                            io::IFile* file,
-                                                            ResourceTable* table);
+    bool linkAndVersionXmlFile(const ResourceEntry* entry, const ResourceFile& fileDesc,
+                               io::IFile* file, ResourceTable* table, FileOperation* outFileOp);
 
     ResourceFileFlattenerOptions mOptions;
     IAaptContext* mContext;
@@ -294,11 +325,11 @@
     return ArchiveEntry::kCompress;
 }
 
-std::unique_ptr<xml::XmlResource> ResourceFileFlattener::linkAndVersionXmlFile(
-        const ResourceEntry* entry,
-        const ResourceFile& fileDesc,
-        io::IFile* file,
-        ResourceTable* table) {
+bool ResourceFileFlattener::linkAndVersionXmlFile(const ResourceEntry* entry,
+                                                  const ResourceFile& fileDesc,
+                                                  io::IFile* file,
+                                                  ResourceTable* table,
+                                                  FileOperation* outFileOp) {
     const StringPiece srcPath = file->getSource().path;
     if (mContext->verbose()) {
         mContext->getDiagnostics()->note(DiagMessage() << "linking " << srcPath);
@@ -307,51 +338,67 @@
     std::unique_ptr<io::IData> data = file->openAsData();
     if (!data) {
         mContext->getDiagnostics()->error(DiagMessage(file->getSource()) << "failed to open file");
-        return {};
+        return false;
     }
 
-    std::unique_ptr<xml::XmlResource> xmlRes;
     if (util::stringEndsWith<char>(srcPath, ".flat")) {
-        xmlRes = loadBinaryXmlSkipFileExport(file->getSource(), data->data(), data->size(),
-                                             mContext->getDiagnostics());
+        outFileOp->xmlToFlatten = loadBinaryXmlSkipFileExport(file->getSource(),
+                                                              data->data(), data->size(),
+                                                              mContext->getDiagnostics());
     } else {
-        xmlRes = xml::inflate(data->data(), data->size(), mContext->getDiagnostics(),
-                              file->getSource());
+        outFileOp->xmlToFlatten = xml::inflate(data->data(), data->size(),
+                                               mContext->getDiagnostics(),
+                                               file->getSource());
     }
 
-    if (!xmlRes) {
-        return {};
+    if (!outFileOp->xmlToFlatten) {
+        return false;
     }
 
     // Copy the the file description header.
-    xmlRes->file = fileDesc;
+    outFileOp->xmlToFlatten->file = fileDesc;
 
     XmlReferenceLinker xmlLinker;
-    if (!xmlLinker.consume(mContext, xmlRes.get())) {
-        return {};
+    if (!xmlLinker.consume(mContext, outFileOp->xmlToFlatten.get())) {
+        return false;
     }
 
-    if (!proguard::collectProguardRules(xmlRes->file.source, xmlRes.get(), mKeepSet)) {
-        return {};
+    if (!proguard::collectProguardRules(outFileOp->xmlToFlatten->file.source,
+                                        outFileOp->xmlToFlatten.get(), mKeepSet)) {
+        return false;
     }
 
     if (!mOptions.noAutoVersion) {
+        if (mOptions.noVersionVectors) {
+            // Skip this if it is a vector or animated-vector.
+            xml::Element* el = xml::findRootElement(outFileOp->xmlToFlatten.get());
+            if (el && el->namespaceUri.empty()) {
+                if (el->name == u"vector" || el->name == u"animated-vector") {
+                    // We are NOT going to version this file.
+                    outFileOp->skipVersion = true;
+                    return true;
+                }
+            }
+        }
+
         // Find the first SDK level used that is higher than this defined config and
         // not superseded by a lower or equal SDK level resource.
         for (int sdkLevel : xmlLinker.getSdkLevels()) {
-            if (sdkLevel > xmlRes->file.config.sdkVersion) {
-                if (!shouldGenerateVersionedResource(entry, xmlRes->file.config, sdkLevel)) {
+            if (sdkLevel > outFileOp->xmlToFlatten->file.config.sdkVersion) {
+                if (!shouldGenerateVersionedResource(entry, outFileOp->xmlToFlatten->file.config,
+                                                     sdkLevel)) {
                     // If we shouldn't generate a versioned resource, stop checking.
                     break;
                 }
 
-                ResourceFile versionedFileDesc = xmlRes->file;
-                versionedFileDesc.config.sdkVersion = sdkLevel;
+                ResourceFile versionedFileDesc = outFileOp->xmlToFlatten->file;
+                versionedFileDesc.config.sdkVersion = (uint16_t) sdkLevel;
 
                 if (mContext->verbose()) {
                     mContext->getDiagnostics()->note(DiagMessage(versionedFileDesc.source)
                                                      << "auto-versioning resource from config '"
-                                                     << xmlRes->file.config << "' -> '"
+                                                     << outFileOp->xmlToFlatten->file.config
+                                                     << "' -> '"
                                                      << versionedFileDesc.config << "'");
                 }
 
@@ -365,13 +412,13 @@
                                                                  file,
                                                                  mContext->getDiagnostics());
                 if (!added) {
-                    return {};
+                    return false;
                 }
                 break;
             }
         }
     }
-    return xmlRes;
+    return true;
 }
 
 /**
@@ -415,9 +462,7 @@
                         fileDesc.config = configValue->config;
                         fileDesc.name = ResourceName(pkg->name, type->type, entry->name);
                         fileDesc.source = fileRef->getSource();
-                        fileOp.xmlToFlatten = linkAndVersionXmlFile(entry.get(), fileDesc,
-                                                                    file, table);
-                        if (!fileOp.xmlToFlatten) {
+                        if (!linkAndVersionXmlFile(entry.get(), fileDesc, file, table, &fileOp)) {
                             error = true;
                             continue;
                         }
@@ -447,7 +492,7 @@
 
                 if (fileOp.xmlToFlatten) {
                     Maybe<size_t> maxSdkLevel;
-                    if (!mOptions.noAutoVersion) {
+                    if (!mOptions.noAutoVersion && !fileOp.skipVersion) {
                         maxSdkLevel = std::max<size_t>(config.sdkVersion, 1u);
                     }
 
@@ -474,39 +519,61 @@
 class LinkCommand {
 public:
     LinkCommand(LinkContext* context, const LinkOptions& options) :
-            mOptions(options), mContext(context), mFinalTable(), mFileCollection(nullptr) {
-        std::unique_ptr<io::FileCollection> fileCollection =
-                util::make_unique<io::FileCollection>();
-
-        // Get a pointer to the FileCollection for convenience, but it will be owned by the vector.
-        mFileCollection = fileCollection.get();
-
-        // Move it to the collection.
-        mCollections.push_back(std::move(fileCollection));
+            mOptions(options), mContext(context), mFinalTable(),
+            mFileCollection(util::make_unique<io::FileCollection>()) {
     }
 
     /**
      * Creates a SymbolTable that loads symbols from the various APKs and caches the
      * results for faster lookup.
      */
-    std::unique_ptr<ISymbolTable> createSymbolTableFromIncludePaths() {
-        AssetManagerSymbolTableBuilder builder;
+    bool loadSymbolsFromIncludePaths() {
+        std::unique_ptr<AssetManagerSymbolSource> assetSource =
+                util::make_unique<AssetManagerSymbolSource>();
         for (const std::string& path : mOptions.includePaths) {
             if (mContext->verbose()) {
                 mContext->getDiagnostics()->note(DiagMessage(path) << "loading include path");
             }
 
-            std::unique_ptr<android::AssetManager> assetManager =
-                    util::make_unique<android::AssetManager>();
-            int32_t cookie = 0;
-            if (!assetManager->addAssetPath(android::String8(path.data(), path.size()), &cookie)) {
+            // First try to load the file as a static lib.
+            std::string errorStr;
+            std::unique_ptr<ResourceTable> staticInclude = loadStaticLibrary(path, &errorStr);
+            if (staticInclude) {
+                if (!mOptions.staticLib) {
+                    // Can't include static libraries when not building a static library.
+                    mContext->getDiagnostics()->error(
+                            DiagMessage(path) << "can't include static library when building app");
+                    return false;
+                }
+
+                // If we are using --no-static-lib-packages, we need to rename the package of this
+                // table to our compilation package.
+                if (mOptions.noStaticLibPackages) {
+                    if (ResourceTablePackage* pkg = staticInclude->findPackageById(0x7f)) {
+                        pkg->name = mContext->getCompilationPackage();
+                    }
+                }
+
+                mContext->getExternalSymbols()->appendSource(
+                        util::make_unique<ResourceTableSymbolSource>(staticInclude.get()));
+
+                mStaticTableIncludes.push_back(std::move(staticInclude));
+
+            } else if (!errorStr.empty()) {
+                // We had an error with reading, so fail.
+                mContext->getDiagnostics()->error(DiagMessage(path) << errorStr);
+                return false;
+            }
+
+            if (!assetSource->addAssetPath(path)) {
                 mContext->getDiagnostics()->error(
                         DiagMessage(path) << "failed to load include path");
-                return {};
+                return false;
             }
-            builder.add(std::move(assetManager));
         }
-        return builder.build();
+
+        mContext->getExternalSymbols()->appendSource(std::move(assetSource));
+        return true;
     }
 
     Maybe<AppInfo> extractAppInfoFromManifest(xml::XmlResource* xmlRes) {
@@ -571,6 +638,35 @@
         return !error;
     }
 
+    /**
+     * Returns true if no IDs have been set, false otherwise.
+     */
+    bool verifyNoIdsSet() {
+        for (const auto& package : mFinalTable.packages) {
+            for (const auto& type : package->types) {
+                if (type->id) {
+                    mContext->getDiagnostics()->error(DiagMessage() << "type " << type->type
+                                                      << " has ID " << std::hex
+                                                      << (int) type->id.value()
+                                                      << std::dec << " assigned");
+                    return false;
+                }
+
+                for (const auto& entry : type->entries) {
+                    if (entry->id) {
+                        ResourceNameRef resName(package->name, type->type, entry->name);
+                        mContext->getDiagnostics()->error(DiagMessage() << "entry " << resName
+                                                          << " has ID " << std::hex
+                                                          << (int) entry->id.value()
+                                                          << std::dec << " assigned");
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
     std::unique_ptr<IArchiveWriter> makeArchiveWriter() {
         if (mOptions.outputToDirectory) {
             return createDirectoryArchiveWriter(mContext->getDiagnostics(), mOptions.outputPath);
@@ -599,6 +695,32 @@
         return false;
     }
 
+    bool flattenTableToPb(ResourceTable* table, IArchiveWriter* writer) {
+        // Create the file/zip entry.
+        if (!writer->startEntry("resources.arsc.flat", 0)) {
+            mContext->getDiagnostics()->error(DiagMessage() << "failed to open");
+            return false;
+        }
+
+        std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table);
+
+        // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+        // interface.
+        {
+            google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+
+            if (!pbTable->SerializeToZeroCopyStream(&adaptor)) {
+                mContext->getDiagnostics()->error(DiagMessage() << "failed to write");
+                return false;
+            }
+        }
+
+        if (!writer->finishEntry()) {
+            mContext->getDiagnostics()->error(DiagMessage() << "failed to finish entry");
+            return false;
+        }
+        return true;
+    }
 
     bool writeJavaFile(ResourceTable* table, const StringPiece16& packageNameToGenerate,
                        const StringPiece16& outPackage, JavaClassGeneratorOptions javaOptions) {
@@ -608,20 +730,31 @@
 
         std::string outPath = mOptions.generateJavaClassPath.value();
         file::appendPath(&outPath, file::packageToPath(util::utf16ToUtf8(outPackage)));
-        file::mkdirs(outPath);
+        if (!file::mkdirs(outPath)) {
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed to create directory '" << outPath << "'");
+            return false;
+        }
+
         file::appendPath(&outPath, "R.java");
 
         std::ofstream fout(outPath, std::ofstream::binary);
         if (!fout) {
-            mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
             return false;
         }
 
-        JavaClassGenerator generator(table, javaOptions);
+        JavaClassGenerator generator(mContext, table, javaOptions);
         if (!generator.generate(packageNameToGenerate, outPackage, &fout)) {
             mContext->getDiagnostics()->error(DiagMessage(outPath) << generator.getError());
             return false;
         }
+
+        if (!fout) {
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
+        }
         return true;
     }
 
@@ -630,26 +763,49 @@
             return true;
         }
 
+        std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+                mContext->getDiagnostics(), manifestXml);
+
+        if (!manifestClass) {
+            // Something bad happened, but we already logged it, so exit.
+            return false;
+        }
+
+        if (manifestClass->empty()) {
+            // Empty Manifest class, no need to generate it.
+            return true;
+        }
+
+        // Add any JavaDoc annotations to the generated class.
+        for (const std::string& annotation : mOptions.javadocAnnotations) {
+            std::string properAnnotation = "@";
+            properAnnotation += annotation;
+            manifestClass->getCommentBuilder()->appendComment(properAnnotation);
+        }
+
+        const std::string packageUtf8 = util::utf16ToUtf8(mContext->getCompilationPackage());
+
         std::string outPath = mOptions.generateJavaClassPath.value();
-        file::appendPath(&outPath,
-                         file::packageToPath(util::utf16ToUtf8(mContext->getCompilationPackage())));
-        file::mkdirs(outPath);
+        file::appendPath(&outPath, file::packageToPath(packageUtf8));
+
+        if (!file::mkdirs(outPath)) {
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed to create directory '" << outPath << "'");
+            return false;
+        }
+
         file::appendPath(&outPath, "Manifest.java");
 
         std::ofstream fout(outPath, std::ofstream::binary);
         if (!fout) {
-            mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
             return false;
         }
 
-        ManifestClassGenerator generator;
-        if (!generator.generate(mContext->getDiagnostics(), mContext->getCompilationPackage(),
-                                manifestXml, &fout)) {
-            return false;
-        }
-
-        if (!fout) {
-            mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+        if (!ClassDefinition::writeJavaFile(manifestClass.get(), packageUtf8, true, &fout)) {
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
             return false;
         }
         return true;
@@ -660,32 +816,108 @@
             return true;
         }
 
-        std::ofstream fout(mOptions.generateProguardRulesPath.value(), std::ofstream::binary);
+        const std::string& outPath = mOptions.generateProguardRulesPath.value();
+        std::ofstream fout(outPath, std::ofstream::binary);
         if (!fout) {
-            mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed to open '" << outPath << "': " << strerror(errno));
             return false;
         }
 
         proguard::writeKeepSet(&fout, keepSet);
         if (!fout) {
-            mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+            mContext->getDiagnostics()->error(
+                    DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
             return false;
         }
         return true;
     }
 
-    bool mergeStaticLibrary(const std::string& input) {
-        // TODO(adamlesinski): Load resources from a static library APK and merge the table into
-        // TableMerger.
-        mContext->getDiagnostics()->warn(DiagMessage()
-                                        << "linking static libraries not supported yet: "
-                                        << input);
+    std::unique_ptr<ResourceTable> loadStaticLibrary(const std::string& input,
+                                                     std::string* outError) {
+        std::unique_ptr<io::ZipFileCollection> collection = io::ZipFileCollection::create(
+                input, outError);
+        if (!collection) {
+            return {};
+        }
+        return loadTablePbFromCollection(collection.get());
+    }
+
+    std::unique_ptr<ResourceTable> loadTablePbFromCollection(io::IFileCollection* collection) {
+        io::IFile* file = collection->findFile("resources.arsc.flat");
+        if (!file) {
+            return {};
+        }
+
+        std::unique_ptr<io::IData> data = file->openAsData();
+        return loadTableFromPb(file->getSource(), data->data(), data->size(),
+                               mContext->getDiagnostics());
+    }
+
+    bool mergeStaticLibrary(const std::string& input, bool override) {
+        if (mContext->verbose()) {
+            mContext->getDiagnostics()->note(DiagMessage() << "merging static library " << input);
+        }
+
+        std::string errorStr;
+        std::unique_ptr<io::ZipFileCollection> collection =
+                io::ZipFileCollection::create(input, &errorStr);
+        if (!collection) {
+            mContext->getDiagnostics()->error(DiagMessage(input) << errorStr);
+            return false;
+        }
+
+        std::unique_ptr<ResourceTable> table = loadTablePbFromCollection(collection.get());
+        if (!table) {
+            mContext->getDiagnostics()->error(DiagMessage(input) << "invalid static library");
+            return false;
+        }
+
+        ResourceTablePackage* pkg = table->findPackageById(0x7f);
+        if (!pkg) {
+            mContext->getDiagnostics()->error(DiagMessage(input)
+                                              << "static library has no package");
+            return false;
+        }
+
+        bool result;
+        if (mOptions.noStaticLibPackages) {
+            // Merge all resources as if they were in the compilation package. This is the old
+            // behaviour of aapt.
+
+            // Add the package to the set of --extra-packages so we emit an R.java for each
+            // library package.
+            if (!pkg->name.empty()) {
+                mOptions.extraJavaPackages.insert(pkg->name);
+            }
+
+            pkg->name = u"";
+            if (override) {
+                result = mTableMerger->mergeOverlay(Source(input), table.get(), collection.get());
+            } else {
+                result = mTableMerger->merge(Source(input), table.get(), collection.get());
+            }
+
+        } else {
+            // This is the proper way to merge libraries, where the package name is preserved
+            // and resource names are mangled.
+            result = mTableMerger->mergeAndMangle(Source(input), pkg->name, table.get(),
+                                                  collection.get());
+        }
+
+        if (!result) {
+            return false;
+        }
+
+        // Make sure to move the collection into the set of IFileCollections.
+        mCollections.push_back(std::move(collection));
         return true;
     }
 
     bool mergeResourceTable(io::IFile* file, bool override) {
         if (mContext->verbose()) {
-            mContext->getDiagnostics()->note(DiagMessage() << "linking " << file->getSource());
+            mContext->getDiagnostics()->note(DiagMessage() << "merging resource table "
+                                             << file->getSource());
         }
 
         std::unique_ptr<io::IData> data = file->openAsData();
@@ -711,13 +943,14 @@
         return result;
     }
 
-    bool mergeCompiledFile(io::IFile* file, std::unique_ptr<ResourceFile> fileDesc, bool overlay) {
+    bool mergeCompiledFile(io::IFile* file, ResourceFile* fileDesc, bool override) {
         if (mContext->verbose()) {
-            mContext->getDiagnostics()->note(DiagMessage() << "adding " << file->getSource());
+            mContext->getDiagnostics()->note(DiagMessage() << "merging compiled file "
+                                             << file->getSource());
         }
 
         bool result = false;
-        if (overlay) {
+        if (override) {
             result = mTableMerger->mergeFileOverlay(*fileDesc, file);
         } else {
             result = mTableMerger->mergeFile(*fileDesc, file);
@@ -730,7 +963,7 @@
         // Add the exports of this file to the table.
         for (SourcedResourceName& exportedSymbol : fileDesc->exportedSymbols) {
             if (exportedSymbol.name.package.empty()) {
-                exportedSymbol.name.package = mContext->getCompilationPackage().toString();
+                exportedSymbol.name.package = mContext->getCompilationPackage();
             }
 
             ResourceNameRef resName = exportedSymbol.name;
@@ -743,11 +976,9 @@
 
             std::unique_ptr<Id> id = util::make_unique<Id>();
             id->setSource(fileDesc->source.withLine(exportedSymbol.line));
-            bool result = mFinalTable.addResourceAllowMangled(resName,
-                                                              ConfigDescription::defaultConfig(),
-                                                              std::string(),
-                                                              std::move(id),
-                                                              mContext->getDiagnostics());
+            bool result = mFinalTable.addResourceAllowMangled(
+                    resName, ConfigDescription::defaultConfig(), std::string(), std::move(id),
+                    mContext->getDiagnostics());
             if (!result) {
                 return false;
             }
@@ -756,12 +987,21 @@
     }
 
     /**
-     * Creates an io::IFileCollection from the ZIP archive and processes the files within.
+     * Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
+     * If override is true, conflicting resources are allowed to override each other, in order of
+     * last seen.
+     *
+     * An io::IFileCollection is created from the ZIP file and added to the set of
+     * io::IFileCollections that are open.
      */
     bool mergeArchive(const std::string& input, bool override) {
+        if (mContext->verbose()) {
+            mContext->getDiagnostics()->note(DiagMessage() << "merging archive " << input);
+        }
+
         std::string errorStr;
-        std::unique_ptr<io::ZipFileCollection> collection = io::ZipFileCollection::create(
-                input, &errorStr);
+        std::unique_ptr<io::ZipFileCollection> collection =
+                io::ZipFileCollection::create(input, &errorStr);
         if (!collection) {
             mContext->getDiagnostics()->error(DiagMessage(input) << errorStr);
             return false;
@@ -769,7 +1009,7 @@
 
         bool error = false;
         for (auto iter = collection->iterator(); iter->hasNext(); ) {
-            if (!processFile(iter->next(), override)) {
+            if (!mergeFile(iter->next(), override)) {
                 error = true;
             }
         }
@@ -779,22 +1019,45 @@
         return !error;
     }
 
-    bool processFile(const std::string& path, bool override) {
+    /**
+     * Takes a path to load and merge into the master ResourceTable. If override is true,
+     * conflicting resources are allowed to override each other, in order of last seen.
+     *
+     * If the file path ends with .flata, .jar, .jack, or .zip the file is treated as ZIP archive
+     * and the files within are merged individually.
+     *
+     * Otherwise the files is processed on its own.
+     */
+    bool mergePath(const std::string& path, bool override) {
         if (util::stringEndsWith<char>(path, ".flata") ||
                 util::stringEndsWith<char>(path, ".jar") ||
                 util::stringEndsWith<char>(path, ".jack") ||
                 util::stringEndsWith<char>(path, ".zip")) {
             return mergeArchive(path, override);
+        } else if (util::stringEndsWith<char>(path, ".apk")) {
+            return mergeStaticLibrary(path, override);
         }
 
         io::IFile* file = mFileCollection->insertFile(path);
-        return processFile(file, override);
+        return mergeFile(file, override);
     }
 
-    bool processFile(io::IFile* file, bool override) {
+    /**
+     * Takes a file to load and merge into the master ResourceTable. If override is true,
+     * conflicting resources are allowed to override each other, in order of last seen.
+     *
+     * If the file ends with .arsc.flat, then it is loaded as a ResourceTable and merged into the
+     * master ResourceTable. If the file ends with .flat, then it is treated like a compiled file
+     * and the header data is read and merged into the final ResourceTable.
+     *
+     * All other file types are ignored. This is because these files could be coming from a zip,
+     * where we could have other files like classes.dex.
+     */
+    bool mergeFile(io::IFile* file, bool override) {
         const Source& src = file->getSource();
         if (util::stringEndsWith<char>(src.path, ".arsc.flat")) {
             return mergeResourceTable(file, override);
+
         } else if (util::stringEndsWith<char>(src.path, ".flat")){
             // Try opening the file and looking for an Export header.
             std::unique_ptr<io::IData> data = file->openAsData();
@@ -806,9 +1069,8 @@
             std::unique_ptr<ResourceFile> resourceFile = loadFileExportHeader(
                     src, data->data(), data->size(), mContext->getDiagnostics());
             if (resourceFile) {
-                return mergeCompiledFile(file, std::move(resourceFile), override);
+                return mergeCompiledFile(file, resourceFile.get(), override);
             }
-
             return false;
         }
 
@@ -826,32 +1088,30 @@
         }
 
         if (Maybe<AppInfo> maybeAppInfo = extractAppInfoFromManifest(manifestXml.get())) {
-            mContext->mCompilationPackage = maybeAppInfo.value().package;
+            mContext->setCompilationPackage(maybeAppInfo.value().package);
         } else {
             mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
                                              << "no package specified in <manifest> tag");
             return 1;
         }
 
-        if (!util::isJavaPackageName(mContext->mCompilationPackage)) {
+        if (!util::isJavaPackageName(mContext->getCompilationPackage())) {
             mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
                                              << "invalid package name '"
-                                             << mContext->mCompilationPackage
+                                             << mContext->getCompilationPackage()
                                              << "'");
             return 1;
         }
 
-        mContext->mNameMangler = util::make_unique<NameMangler>(
-                NameManglerPolicy{ mContext->mCompilationPackage });
+        mContext->setNameManglerPolicy(NameManglerPolicy{ mContext->getCompilationPackage() });
 
-        if (mContext->mCompilationPackage == u"android") {
-            mContext->mPackageId = 0x01;
+        if (mContext->getCompilationPackage() == u"android") {
+            mContext->setPackageId(0x01);
         } else {
-            mContext->mPackageId = 0x7f;
+            mContext->setPackageId(0x7f);
         }
 
-        mContext->mSymbols = createSymbolTableFromIncludePaths();
-        if (!mContext->mSymbols) {
+        if (!loadSymbolsFromIncludePaths()) {
             return 1;
         }
 
@@ -861,20 +1121,21 @@
 
         if (mContext->verbose()) {
             mContext->getDiagnostics()->note(
-                    DiagMessage() << "linking package '" << mContext->mCompilationPackage << "' "
-                                  << "with package ID " << std::hex << (int) mContext->mPackageId);
+                    DiagMessage() << "linking package '" << mContext->getCompilationPackage()
+                                  << "' with package ID " << std::hex
+                                  << (int) mContext->getPackageId());
         }
 
 
         for (const std::string& input : inputFiles) {
-            if (!processFile(input, false)) {
+            if (!mergePath(input, false)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed parsing input");
                 return 1;
             }
         }
 
         for (const std::string& input : mOptions.overlayFiles) {
-            if (!processFile(input, true)) {
+            if (!mergePath(input, true)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed parsing overlays");
                 return 1;
             }
@@ -893,20 +1154,28 @@
             }
         }
 
-        {
+        if (!mOptions.staticLib) {
+            // Assign IDs if we are building a regular app.
             IdAssigner idAssigner;
             if (!idAssigner.consume(mContext, &mFinalTable)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed assigning IDs");
                 return 1;
             }
+        } else {
+            // Static libs are merged with other apps, and ID collisions are bad, so verify that
+            // no IDs have been set.
+            if (!verifyNoIdsSet()) {
+                return 1;
+            }
         }
 
-        mContext->mNameMangler = util::make_unique<NameMangler>(NameManglerPolicy{
-                mContext->mCompilationPackage, mTableMerger->getMergedPackages() });
-        mContext->mSymbols = JoinedSymbolTableBuilder()
-                .addSymbolTable(util::make_unique<SymbolTableWrapper>(&mFinalTable))
-                .addSymbolTable(std::move(mContext->mSymbols))
-                .build();
+        // Add the names to mangle based on our source merge earlier.
+        mContext->setNameManglerPolicy(NameManglerPolicy{
+                mContext->getCompilationPackage(), mTableMerger->getMergedPackages() });
+
+        // Add our table to the symbol table.
+        mContext->getExternalSymbols()->prependSource(
+                        util::make_unique<ResourceTableSymbolSource>(&mFinalTable));
 
         {
             ReferenceLinker linker;
@@ -915,20 +1184,32 @@
                 return 1;
             }
 
-            ProductFilter productFilter(mOptions.products);
-            if (!productFilter.consume(mContext, &mFinalTable)) {
-                mContext->getDiagnostics()->error(DiagMessage() << "failed stripping products");
-                return 1;
-            }
+            if (mOptions.staticLib) {
+                if (!mOptions.products.empty()) {
+                    mContext->getDiagnostics()->warn(
+                            DiagMessage() << "can't select products when building static library");
+                }
 
-            // TODO(adamlesinski): Actually pass in split constraints and handle splits at the file
-            // level.
-            TableSplitter tableSplitter({}, mOptions.tableSplitterOptions);
-            if (!tableSplitter.verifySplitConstraints(mContext)) {
-                return 1;
-            }
+                if (mOptions.tableSplitterOptions.configFilter != nullptr ||
+                        mOptions.tableSplitterOptions.preferredDensity) {
+                    mContext->getDiagnostics()->warn(
+                            DiagMessage() << "can't strip resources when building static library");
+                }
+            } else {
+                ProductFilter productFilter(mOptions.products);
+                if (!productFilter.consume(mContext, &mFinalTable)) {
+                    mContext->getDiagnostics()->error(DiagMessage() << "failed stripping products");
+                    return 1;
+                }
 
-            tableSplitter.splitTable(&mFinalTable);
+                // TODO(adamlesinski): Actually pass in split constraints and handle splits at the file
+                // level.
+                TableSplitter tableSplitter({}, mOptions.tableSplitterOptions);
+                if (!tableSplitter.verifySplitConstraints(mContext)) {
+                    return 1;
+                }
+                tableSplitter.splitTable(&mFinalTable);
+            }
         }
 
         proguard::KeepSet proguardKeepSet;
@@ -949,7 +1230,7 @@
             // AndroidManifest.xml has no resource name, but the CallSite is built from the name
             // (aka, which package the AndroidManifest.xml is coming from).
             // So we give it a package name so it can see local resources.
-            manifestXml->file.name.package = mContext->getCompilationPackage().toString();
+            manifestXml->file.name.package = mContext->getCompilationPackage();
 
             XmlReferenceLinker manifestLinker;
             if (manifestLinker.consume(mContext, manifestXml.get())) {
@@ -986,6 +1267,7 @@
         fileFlattenerOptions.doNotCompressAnything = mOptions.doNotCompressAnything;
         fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress;
         fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion;
+        fileFlattenerOptions.noVersionVectors = mOptions.noVersionVectors;
         ResourceFileFlattener fileFlattener(fileFlattenerOptions, mContext, &proguardKeepSet);
 
         if (!fileFlattener.flatten(&mFinalTable, archiveWriter.get())) {
@@ -1001,14 +1283,24 @@
             }
         }
 
-        if (!flattenTable(&mFinalTable, archiveWriter.get())) {
-            mContext->getDiagnostics()->error(DiagMessage() << "failed to write resources.arsc");
-            return 1;
+        if (mOptions.staticLib) {
+            if (!flattenTableToPb(&mFinalTable, archiveWriter.get())) {
+                mContext->getDiagnostics()->error(DiagMessage()
+                                                  << "failed to write resources.arsc.flat");
+                return 1;
+            }
+        } else {
+            if (!flattenTable(&mFinalTable, archiveWriter.get())) {
+                mContext->getDiagnostics()->error(DiagMessage()
+                                                  << "failed to write resources.arsc");
+                return 1;
+            }
         }
 
         if (mOptions.generateJavaClassPath) {
             JavaClassGeneratorOptions options;
             options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+            options.javadocAnnotations = mOptions.javadocAnnotations;
 
             if (mOptions.staticLib || mOptions.generateNonFinalIds) {
                 options.useFinal = false;
@@ -1065,14 +1357,17 @@
     LinkContext* mContext;
     ResourceTable mFinalTable;
 
-    ResourceTable mLocalFileTable;
     std::unique_ptr<TableMerger> mTableMerger;
 
     // A pointer to the FileCollection representing the filesystem (not archives).
-    io::FileCollection* mFileCollection;
+    std::unique_ptr<io::FileCollection> mFileCollection;
 
     // A vector of IFileCollections. This is mainly here to keep ownership of the collections.
     std::vector<std::unique_ptr<io::IFileCollection>> mCollections;
+
+    // A vector of ResourceTables. This is here to retain ownership, so that the SymbolTable
+    // can use these.
+    std::vector<std::unique_ptr<ResourceTable>> mStaticTableIncludes;
 };
 
 int link(const std::vector<StringPiece>& args) {
@@ -1089,6 +1384,7 @@
     Maybe<std::string> productList;
     bool legacyXFlag = false;
     bool requireLocalization = false;
+    bool verbose = false;
     Flags flags = Flags()
             .requiredFlag("-o", "Output path", &options.outputPath)
             .requiredFlag("--manifest", "Path to the Android manifest to build",
@@ -1104,6 +1400,10 @@
             .optionalSwitch("--no-auto-version",
                             "Disables automatic style and layout SDK versioning",
                             &options.noAutoVersion)
+            .optionalSwitch("--no-version-vectors",
+                            "Disables automatic versioning of vector drawables. Use this only\n"
+                            "when building with vector drawable support library",
+                            &options.noVersionVectors)
             .optionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01",
                             &legacyXFlag)
             .optionalSwitch("-z", "Require localization of strings marked 'suggested'",
@@ -1127,6 +1427,9 @@
             .optionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml "
                           "if none is present", &versionName)
             .optionalSwitch("--static-lib", "Generate a static Android library", &options.staticLib)
+            .optionalSwitch("--no-static-lib-packages",
+                            "Merge all library resources under the app's package",
+                            &options.noStaticLibPackages)
             .optionalSwitch("--non-final-ids", "Generates R.java without the final modifier.\n"
                             "This is implied when --static-lib is specified.",
                             &options.generateNonFinalIds)
@@ -1138,6 +1441,8 @@
                           &customJavaPackage)
             .optionalFlagList("--extra-packages", "Generate the same R.java but with different "
                               "package names", &extraJavaPackages)
+            .optionalFlagList("--add-javadoc-annotation", "Adds a JavaDoc annotation to all "
+                            "generated Java classes", &options.javadocAnnotations)
             .optionalSwitch("--auto-add-overlay", "Allows the addition of new resources in "
                             "overlays without <add-resource> tags", &options.autoAddOverlay)
             .optionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml",
@@ -1148,12 +1453,16 @@
                           &renameInstrumentationTargetPackage)
             .optionalFlagList("-0", "File extensions not to compress",
                               &options.extensionsToNotCompress)
-            .optionalSwitch("-v", "Enables verbose logging", &context.mVerbose);
+            .optionalSwitch("-v", "Enables verbose logging", &verbose);
 
     if (!flags.parse("aapt2 link", args, &std::cerr)) {
         return 1;
     }
 
+    if (verbose) {
+        context.setVerbose(verbose);
+    }
+
     if (privateSymbolsPackage) {
         options.privateSymbols = util::utf8ToUtf16(privateSymbolsPackage.value());
     }
@@ -1252,6 +1561,12 @@
         options.tableSplitterOptions.preferredDensity = preferredDensityConfig.density;
     }
 
+    // Turn off auto versioning for static-libs.
+    if (options.staticLib) {
+        options.noAutoVersion = true;
+        options.noVersionVectors = true;
+    }
+
     LinkCommand cmd(&context, options);
     return cmd.run(flags.getArgs());
 }
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index f40fbfb..18c47df 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -30,7 +30,7 @@
                 .setCompilationPackage(u"android")
                 .setPackageId(0x01)
                 .setNameManglerPolicy(NameManglerPolicy{ u"android" })
-                .setSymbolTable(test::StaticSymbolTableBuilder()
+                .addSymbolSource(test::StaticSymbolSourceBuilder()
                         .addSymbol(u"@android:attr/package", ResourceId(0x01010000),
                                    test::AttributeBuilder()
                                         .setTypeMask(android::ResTable_map::TYPE_STRING)
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index ef3fe4f..66eb0df 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-#include "ReferenceLinker.h"
-
 #include "Diagnostics.h"
+#include "ReferenceLinker.h"
 #include "ResourceTable.h"
 #include "ResourceUtils.h"
 #include "ResourceValues.h"
@@ -43,45 +42,10 @@
  * NOTE: All of the entries in the ResourceTable must be assigned IDs.
  */
 class ReferenceLinkerVisitor : public ValueVisitor {
-private:
-    IAaptContext* mContext;
-    ISymbolTable* mSymbols;
-    xml::IPackageDeclStack* mPackageDecls;
-    StringPool* mStringPool;
-    CallSite* mCallSite;
-    bool mError = false;
-
-    /**
-     * Transform a RawString value into a more specific, appropriate value, based on the
-     * Attribute. If a non RawString value is passed in, this is an identity transform.
-     */
-    std::unique_ptr<Item> parseValueWithAttribute(std::unique_ptr<Item> value,
-                                                  const Attribute* attr) {
-        if (RawString* rawString = valueCast<RawString>(value.get())) {
-            std::unique_ptr<Item> transformed =
-                    ResourceUtils::parseItemForAttribute(*rawString->value, attr);
-
-            // If we could not parse as any specific type, try a basic STRING.
-            if (!transformed && (attr->typeMask & android::ResTable_map::TYPE_STRING)) {
-                util::StringBuilder stringBuilder;
-                stringBuilder.append(*rawString->value);
-                if (stringBuilder) {
-                    transformed = util::make_unique<String>(
-                            mStringPool->makeRef(stringBuilder.str()));
-                }
-            }
-
-            if (transformed) {
-                return transformed;
-            }
-        };
-        return value;
-    }
-
 public:
     using ValueVisitor::visit;
 
-    ReferenceLinkerVisitor(IAaptContext* context, ISymbolTable* symbols, StringPool* stringPool,
+    ReferenceLinkerVisitor(IAaptContext* context, SymbolTable* symbols, StringPool* stringPool,
                            xml::IPackageDeclStack* decl,CallSite* callSite) :
             mContext(context), mSymbols(symbols), mPackageDecls(decl), mStringPool(stringPool),
             mCallSite(callSite) {
@@ -114,10 +78,11 @@
                                             &transformedReference);
 
             // Find the attribute in the symbol table and check if it is visible from this callsite.
-            const ISymbolTable::Symbol* symbol = ReferenceLinker::resolveAttributeCheckVisibility(
+            const SymbolTable::Symbol* symbol = ReferenceLinker::resolveAttributeCheckVisibility(
                     transformedReference, mContext->getNameMangler(), mSymbols, mCallSite, &errStr);
             if (symbol) {
                 // Assign our style key the correct ID.
+                // The ID may not exist.
                 entry.key.id = symbol->id;
 
                 // Try to convert the value to a more specific, typed value based on the
@@ -156,6 +121,41 @@
     bool hasError() {
         return mError;
     }
+
+private:
+    IAaptContext* mContext;
+    SymbolTable* mSymbols;
+    xml::IPackageDeclStack* mPackageDecls;
+    StringPool* mStringPool;
+    CallSite* mCallSite;
+    bool mError = false;
+
+    /**
+     * Transform a RawString value into a more specific, appropriate value, based on the
+     * Attribute. If a non RawString value is passed in, this is an identity transform.
+     */
+    std::unique_ptr<Item> parseValueWithAttribute(std::unique_ptr<Item> value,
+                                                  const Attribute* attr) {
+        if (RawString* rawString = valueCast<RawString>(value.get())) {
+            std::unique_ptr<Item> transformed =
+                    ResourceUtils::parseItemForAttribute(*rawString->value, attr);
+
+            // If we could not parse as any specific type, try a basic STRING.
+            if (!transformed && (attr->typeMask & android::ResTable_map::TYPE_STRING)) {
+                util::StringBuilder stringBuilder;
+                stringBuilder.append(*rawString->value);
+                if (stringBuilder) {
+                    transformed = util::make_unique<String>(
+                            mStringPool->makeRef(stringBuilder.str()));
+                }
+            }
+
+            if (transformed) {
+                return transformed;
+            }
+        };
+        return value;
+    }
 };
 
 } // namespace
@@ -164,13 +164,13 @@
  * The symbol is visible if it is public, or if the reference to it is requesting private access
  * or if the callsite comes from the same package.
  */
-bool ReferenceLinker::isSymbolVisible(const ISymbolTable::Symbol& symbol, const Reference& ref,
+bool ReferenceLinker::isSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
                                       const CallSite& callSite) {
     if (!symbol.isPublic && !ref.privateReference) {
         if (ref.name) {
             return callSite.resource.package == ref.name.value().package;
-        } else if (ref.id) {
-            return ref.id.value().packageId() == symbol.id.packageId();
+        } else if (ref.id && symbol.id) {
+            return ref.id.value().packageId() == symbol.id.value().packageId();
         } else {
             return false;
         }
@@ -178,9 +178,9 @@
     return true;
 }
 
-const ISymbolTable::Symbol* ReferenceLinker::resolveSymbol(const Reference& reference,
-                                                           NameMangler* mangler,
-                                                           ISymbolTable* symbols) {
+const SymbolTable::Symbol* ReferenceLinker::resolveSymbol(const Reference& reference,
+                                                          NameMangler* mangler,
+                                                          SymbolTable* symbols) {
     if (reference.name) {
         Maybe<ResourceName> mangled = mangler->mangleName(reference.name.value());
         return symbols->findByName(mangled ? mangled.value() : reference.name.value());
@@ -191,10 +191,10 @@
     }
 }
 
-const ISymbolTable::Symbol* ReferenceLinker::resolveSymbolCheckVisibility(
-        const Reference& reference, NameMangler* nameMangler, ISymbolTable* symbols,
+const SymbolTable::Symbol* ReferenceLinker::resolveSymbolCheckVisibility(
+        const Reference& reference, NameMangler* nameMangler, SymbolTable* symbols,
         CallSite* callSite, std::string* outError) {
-    const ISymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
+    const SymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
     if (!symbol) {
         if (outError) *outError = "not found";
         return nullptr;
@@ -207,12 +207,12 @@
     return symbol;
 }
 
-const ISymbolTable::Symbol* ReferenceLinker::resolveAttributeCheckVisibility(
-        const Reference& reference, NameMangler* nameMangler, ISymbolTable* symbols,
+const SymbolTable::Symbol* ReferenceLinker::resolveAttributeCheckVisibility(
+        const Reference& reference, NameMangler* nameMangler, SymbolTable* symbols,
         CallSite* callSite, std::string* outError) {
-    const ISymbolTable::Symbol* symbol = resolveSymbolCheckVisibility(reference, nameMangler,
-                                                                      symbols, callSite,
-                                                                      outError);
+    const SymbolTable::Symbol* symbol = resolveSymbolCheckVisibility(reference, nameMangler,
+                                                                     symbols, callSite,
+                                                                     outError);
     if (!symbol) {
         return nullptr;
     }
@@ -226,10 +226,10 @@
 
 Maybe<xml::AaptAttribute> ReferenceLinker::compileXmlAttribute(const Reference& reference,
                                                                NameMangler* nameMangler,
-                                                               ISymbolTable* symbols,
+                                                               SymbolTable* symbols,
                                                                CallSite* callSite,
                                                                std::string* outError) {
-    const ISymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
+    const SymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
     if (!symbol) {
         return {};
     }
@@ -256,7 +256,7 @@
 }
 
 bool ReferenceLinker::linkReference(Reference* reference, IAaptContext* context,
-                                    ISymbolTable* symbols, xml::IPackageDeclStack* decls,
+                                    SymbolTable* symbols, xml::IPackageDeclStack* decls,
                                     CallSite* callSite) {
     assert(reference);
     assert(reference->name || reference->id);
@@ -266,9 +266,12 @@
                                     &transformedReference);
 
     std::string errStr;
-    const ISymbolTable::Symbol* s = resolveSymbolCheckVisibility(
+    const SymbolTable::Symbol* s = resolveSymbolCheckVisibility(
             transformedReference, context->getNameMangler(), symbols, callSite, &errStr);
     if (s) {
+        // The ID may not exist. This is fine because of the possibility of building against
+        // libraries without assigned IDs.
+        // Ex: Linking against own resources when building a static library.
         reference->id = s->id;
         return true;
     }
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index a0eb00c..7993aaf 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -38,36 +38,36 @@
     /**
      * Returns true if the symbol is visible by the reference and from the callsite.
      */
-    static bool isSymbolVisible(const ISymbolTable::Symbol& symbol, const Reference& ref,
+    static bool isSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
                                 const CallSite& callSite);
 
     /**
      * Performs name mangling and looks up the resource in the symbol table. Returns nullptr
      * if the symbol was not found.
      */
-    static const ISymbolTable::Symbol* resolveSymbol(const Reference& reference,
-                                                     NameMangler* mangler, ISymbolTable* symbols);
+    static const SymbolTable::Symbol* resolveSymbol(const Reference& reference,
+                                                    NameMangler* mangler, SymbolTable* symbols);
 
     /**
      * Performs name mangling and looks up the resource in the symbol table. If the symbol is
      * not visible by the reference at the callsite, nullptr is returned. outError holds
      * the error message.
      */
-    static const ISymbolTable::Symbol* resolveSymbolCheckVisibility(const Reference& reference,
-                                                                    NameMangler* nameMangler,
-                                                                    ISymbolTable* symbols,
-                                                                    CallSite* callSite,
-                                                                    std::string* outError);
+    static const SymbolTable::Symbol* resolveSymbolCheckVisibility(const Reference& reference,
+                                                                   NameMangler* nameMangler,
+                                                                   SymbolTable* symbols,
+                                                                   CallSite* callSite,
+                                                                   std::string* outError);
 
     /**
      * Same as resolveSymbolCheckVisibility(), but also makes sure the symbol is an attribute.
      * That is, the return value will have a non-null value for ISymbolTable::Symbol::attribute.
      */
-    static const ISymbolTable::Symbol* resolveAttributeCheckVisibility(const Reference& reference,
-                                                                       NameMangler* nameMangler,
-                                                                       ISymbolTable* symbols,
-                                                                       CallSite* callSite,
-                                                                       std::string* outError);
+    static const SymbolTable::Symbol* resolveAttributeCheckVisibility(const Reference& reference,
+                                                                      NameMangler* nameMangler,
+                                                                      SymbolTable* symbols,
+                                                                      CallSite* callSite,
+                                                                      std::string* outError);
 
     /**
      * Resolves the attribute reference and returns an xml::AaptAttribute if successful.
@@ -75,7 +75,7 @@
      */
     static Maybe<xml::AaptAttribute> compileXmlAttribute(const Reference& reference,
                                                          NameMangler* nameMangler,
-                                                         ISymbolTable* symbols,
+                                                         SymbolTable* symbols,
                                                          CallSite* callSite,
                                                          std::string* outError);
 
@@ -92,7 +92,7 @@
      * to the reference at the callsite, the reference is updated with an ID.
      * Returns false on failure, and an error message is logged to the IDiagnostics in the context.
      */
-    static bool linkReference(Reference* reference, IAaptContext* context, ISymbolTable* symbols,
+    static bool linkReference(Reference* reference, IAaptContext* context, SymbolTable* symbols,
                               xml::IPackageDeclStack* decls, CallSite* callSite);
 
     /**
diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp
index 8d324fe..76b2309 100644
--- a/tools/aapt2/link/ReferenceLinker_test.cpp
+++ b/tools/aapt2/link/ReferenceLinker_test.cpp
@@ -15,12 +15,9 @@
  */
 
 #include "link/ReferenceLinker.h"
-#include "process/SymbolTable.h"
+#include "test/Test.h"
 
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+using android::ResTable_map;
 
 namespace aapt {
 
@@ -41,12 +38,10 @@
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
+                                     .build())
             .build();
 
     ReferenceLinker linker;
@@ -91,19 +86,20 @@
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(test::StaticSymbolTableBuilder()
-                    .addPublicSymbol(u"@android:style/Theme.Material", ResourceId(0x01060000))
-                    .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
-                               test::AttributeBuilder()
-                                    .setTypeMask(android::ResTable_map::TYPE_COLOR)
-                                    .build())
-                    .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
-                               test::AttributeBuilder()
-                                    .setTypeMask(android::ResTable_map::TYPE_FLAGS)
-                                    .addItem(u"one", 0x01)
-                                    .addItem(u"two", 0x02)
-                                    .build())
-                    .build())
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addPublicSymbol(u"@android:style/Theme.Material",
+                                                      ResourceId(0x01060000))
+                                     .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
+                                                      test::AttributeBuilder()
+                                                              .setTypeMask(ResTable_map::TYPE_COLOR)
+                                                              .build())
+                                     .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
+                                                      test::AttributeBuilder()
+                                                              .setTypeMask(ResTable_map::TYPE_FLAGS)
+                                                              .addItem(u"one", 0x01)
+                                                              .addItem(u"two", 0x02)
+                                                              .build())
+                                     .build())
             .build();
 
     ReferenceLinker linker;
@@ -131,11 +127,13 @@
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
-            .setSymbolTable(test::StaticSymbolTableBuilder()
-                    .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
-                               ResourceId(0x7f010000), test::AttributeBuilder()
-                                        .setTypeMask(android::ResTable_map::TYPE_COLOR).build())
-                    .build())
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
+                                                      ResourceId(0x7f010000),
+                                                      test::AttributeBuilder()
+                                                              .setTypeMask(ResTable_map::TYPE_COLOR)
+                                                              .build())
+                                     .build())
             .build();
 
     std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
@@ -167,12 +165,10 @@
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
+                                     .build())
             .build();
 
     ReferenceLinker linker;
@@ -190,13 +186,12 @@
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.app.lib" } })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
-                                               ResourceId(0x7f040034))
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
+                                                ResourceId(0x7f040034))
+                                     .build())
+
             .build();
 
     ReferenceLinker linker;
@@ -215,15 +210,14 @@
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
-                                               test::AttributeBuilder()
-                                                    .setTypeMask(android::ResTable_map::TYPE_COLOR)
-                                                    .build())
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
+                                                test::AttributeBuilder()
+                                                        .setTypeMask(
+                                                                android::ResTable_map::TYPE_COLOR)
+                                                        .build())
+                                     .build())
             .build();
 
     ReferenceLinker linker;
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 5f11745..7471e15 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -34,10 +34,21 @@
     assert(mMasterPackage && "package name or ID already taken");
 }
 
+bool TableMerger::merge(const Source& src, ResourceTable* table,
+                        io::IFileCollection* collection) {
+    return mergeImpl(src, table, collection, false /* overlay */, true /* allow new */);
+}
+
+bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table,
+                               io::IFileCollection* collection) {
+    return mergeImpl(src, table, collection, true /* overlay */, mOptions.autoAddOverlay);
+}
+
 /**
  * This will merge packages with the same package name (or no package name).
  */
 bool TableMerger::mergeImpl(const Source& src, ResourceTable* table,
+                            io::IFileCollection* collection,
                             bool overlay, bool allowNew) {
     const uint8_t desiredPackageId = mContext->getPackageId();
 
@@ -51,26 +62,36 @@
         }
 
         if (package->name.empty() || mContext->getCompilationPackage() == package->name) {
+            FileMergeCallback callback;
+            if (collection) {
+                callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
+                               FileReference* newFile, FileReference* oldFile) -> bool {
+                    // The old file's path points inside the APK, so we can use it as is.
+                    io::IFile* f = collection->findFile(util::utf16ToUtf8(*oldFile->path));
+                    if (!f) {
+                        mContext->getDiagnostics()->error(DiagMessage(src) << "file '"
+                                                          << *oldFile->path
+                                                          << "' not found");
+                        return false;
+                    }
+
+                    newFile->file = f;
+                    return true;
+                };
+            }
+
             // Merge here. Once the entries are merged and mangled, any references to
             // them are still valid. This is because un-mangled references are
             // mangled, then looked up at resolution time.
             // Also, when linking, we convert references with no package name to use
             // the compilation package name.
             error |= !doMerge(src, table, package.get(),
-                              false /* mangle */, overlay, allowNew, {});
+                              false /* mangle */, overlay, allowNew, callback);
         }
     }
     return !error;
 }
 
-bool TableMerger::merge(const Source& src, ResourceTable* table) {
-    return mergeImpl(src, table, false /* overlay */, true /* allow new */);
-}
-
-bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table) {
-    return mergeImpl(src, table, true /* overlay */, mOptions.autoAddOverlay);
-}
-
 /**
  * This will merge and mangle resources from a static library.
  */
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index b3c22dd..80c2a5e 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -65,13 +65,17 @@
 
     /**
      * Merges resources from the same or empty package. This is for local sources.
+     * An io::IFileCollection is optional and used to find the referenced Files and process them.
      */
-    bool merge(const Source& src, ResourceTable* table);
+    bool merge(const Source& src, ResourceTable* table,
+               io::IFileCollection* collection = nullptr);
 
     /**
      * Merges resources from an overlay ResourceTable.
+     * An io::IFileCollection is optional and used to find the referenced Files and process them.
      */
-    bool mergeOverlay(const Source& src, ResourceTable* table);
+    bool mergeOverlay(const Source& src, ResourceTable* table,
+                      io::IFileCollection* collection = nullptr);
 
     /**
      * Merges resources from the given package, mangling the name. This is for static libraries.
@@ -104,7 +108,7 @@
 
     bool mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay);
 
-    bool mergeImpl(const Source& src, ResourceTable* srcTable,
+    bool mergeImpl(const Source& src, ResourceTable* srcTable, io::IFileCollection* collection,
                    bool overlay, bool allowNew);
 
     bool doMerge(const Source& src, ResourceTable* srcTable, ResourceTablePackage* srcPackage,
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index a26d763..568bc74 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -34,17 +34,10 @@
  * as needed.
  */
 class ReferenceVisitor : public ValueVisitor {
-private:
-    IAaptContext* mContext;
-    ISymbolTable* mSymbols;
-    xml::IPackageDeclStack* mDecls;
-    CallSite* mCallSite;
-    bool mError;
-
 public:
     using ValueVisitor::visit;
 
-    ReferenceVisitor(IAaptContext* context, ISymbolTable* symbols, xml::IPackageDeclStack* decls,
+    ReferenceVisitor(IAaptContext* context, SymbolTable* symbols, xml::IPackageDeclStack* decls,
                      CallSite* callSite) :
              mContext(context), mSymbols(symbols), mDecls(decls), mCallSite(callSite),
              mError(false) {
@@ -59,25 +52,23 @@
     bool hasError() const {
         return mError;
     }
+
+private:
+    IAaptContext* mContext;
+    SymbolTable* mSymbols;
+    xml::IPackageDeclStack* mDecls;
+    CallSite* mCallSite;
+    bool mError;
 };
 
 /**
  * Visits each xml Element and compiles the attributes within.
  */
 class XmlVisitor : public xml::PackageAwareVisitor {
-private:
-    IAaptContext* mContext;
-    ISymbolTable* mSymbols;
-    Source mSource;
-    std::set<int>* mSdkLevelsFound;
-    CallSite* mCallSite;
-    ReferenceVisitor mReferenceVisitor;
-    bool mError = false;
-
 public:
     using xml::PackageAwareVisitor::visit;
 
-    XmlVisitor(IAaptContext* context, ISymbolTable* symbols, const Source& source,
+    XmlVisitor(IAaptContext* context, SymbolTable* symbols, const Source& source,
                std::set<int>* sdkLevelsFound, CallSite* callSite) :
             mContext(context), mSymbols(symbols), mSource(source), mSdkLevelsFound(sdkLevelsFound),
             mCallSite(callSite), mReferenceVisitor(context, symbols, this, callSite) {
@@ -105,10 +96,13 @@
 
                 // Convert the string value into a compiled Value if this is a valid attribute.
                 if (attr.compiledAttribute) {
-                    // Record all SDK levels from which the attributes were defined.
-                    const int sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id);
-                    if (sdkLevel > 1) {
-                        mSdkLevelsFound->insert(sdkLevel);
+                    if (attr.compiledAttribute.value().id) {
+                        // Record all SDK levels from which the attributes were defined.
+                        const size_t sdkLevel = findAttributeSdkLevel(
+                                attr.compiledAttribute.value().id.value());
+                        if (sdkLevel > 1) {
+                            mSdkLevelsFound->insert(sdkLevel);
+                        }
                     }
 
                     const Attribute* attribute = &attr.compiledAttribute.value().attribute;
@@ -124,6 +118,7 @@
                                                     << *attribute);
                         mError = true;
                     }
+
                 } else {
                     mContext->getDiagnostics()->error(DiagMessage(source)
                                                       << "attribute '" << package << ":"
@@ -150,6 +145,15 @@
     bool hasError() {
         return mError || mReferenceVisitor.hasError();
     }
+
+private:
+    IAaptContext* mContext;
+    SymbolTable* mSymbols;
+    Source mSource;
+    std::set<int>* mSdkLevelsFound;
+    CallSite* mCallSite;
+    ReferenceVisitor mReferenceVisitor;
+    bool mError = false;
 };
 
 } // namespace
diff --git a/tools/aapt2/link/XmlReferenceLinker_test.cpp b/tools/aapt2/link/XmlReferenceLinker_test.cpp
index 3bfaf91..af9098b 100644
--- a/tools/aapt2/link/XmlReferenceLinker_test.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker_test.cpp
@@ -14,12 +14,9 @@
  * limitations under the License.
  */
 
+#include <test/Context.h>
 #include "link/Linkers.h"
-
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
 
 namespace aapt {
 
@@ -30,7 +27,7 @@
                 .setCompilationPackage(u"com.app.test")
                 .setNameManglerPolicy(
                         NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
-                .setSymbolTable(test::StaticSymbolTableBuilder()
+                .addSymbolSource(test::StaticSymbolSourceBuilder()
                         .addPublicSymbol(u"@android:attr/layout_width", ResourceId(0x01010000),
                                    test::AttributeBuilder()
                                         .setTypeMask(android::ResTable_map::TYPE_ENUM |
@@ -92,14 +89,16 @@
                                                     u"layout_width");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010000));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010000));
     ASSERT_NE(xmlAttr->compiledValue, nullptr);
     ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr);
 
     xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", u"background");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010001));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010001));
     ASSERT_NE(xmlAttr->compiledValue, nullptr);
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
@@ -163,7 +162,8 @@
             u"http://schemas.android.com/apk/res/com.android.support", u"colorAccent");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010001));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010001));
     ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr);
 }
 
@@ -182,7 +182,8 @@
                                                     u"colorAccent");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010000));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010000));
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->name);
@@ -209,7 +210,8 @@
                                                     u"attr");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010002));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010002));
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->id);
@@ -223,7 +225,8 @@
     xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/com.app.test", u"attr");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010002));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002));
     ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->id);
@@ -246,7 +249,8 @@
             u"http://schemas.android.com/apk/res/com.app.test", u"attr");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010002));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002));
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->id);
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 3a88044..9affb83 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -30,14 +30,14 @@
 namespace aapt {
 
 class ResourceTable;
-struct ISymbolTable;
+class SymbolTable;
 
 struct IAaptContext {
     virtual ~IAaptContext() = default;
 
-    virtual ISymbolTable* getExternalSymbols() = 0;
+    virtual SymbolTable* getExternalSymbols() = 0;
     virtual IDiagnostics* getDiagnostics() = 0;
-    virtual StringPiece16 getCompilationPackage() = 0;
+    virtual const std::u16string& getCompilationPackage() = 0;
     virtual uint8_t getPackageId() = 0;
     virtual NameMangler* getNameMangler() = 0;
     virtual bool verbose() = 0;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index b6030a2..eaaf06f 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -25,11 +25,83 @@
 
 namespace aapt {
 
-const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& name) {
+void SymbolTable::appendSource(std::unique_ptr<ISymbolSource> source) {
+    mSources.push_back(std::move(source));
+
+    // We do not clear the cache, because sources earlier in the list take precedent.
+}
+
+void SymbolTable::prependSource(std::unique_ptr<ISymbolSource> source) {
+    mSources.insert(mSources.begin(), std::move(source));
+
+    // We must clear the cache in case we did a lookup before adding this resource.
+    mCache.clear();
+}
+
+const SymbolTable::Symbol* SymbolTable::findByName(const ResourceName& name) {
     if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
         return s.get();
     }
 
+    // We did not find it in the cache, so look through the sources.
+    for (auto& symbolSource : mSources) {
+        std::unique_ptr<Symbol> symbol = symbolSource->findByName(name);
+        if (symbol) {
+            // Take ownership of the symbol into a shared_ptr. We do this because LruCache
+            // doesn't support unique_ptr.
+            std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
+            mCache.put(name, sharedSymbol);
+
+            if (sharedSymbol->id) {
+                // The symbol has an ID, so we can also cache this!
+                mIdCache.put(sharedSymbol->id.value(), sharedSymbol);
+            }
+            return sharedSymbol.get();
+        }
+    }
+    return nullptr;
+}
+
+const SymbolTable::Symbol* SymbolTable::findById(ResourceId id) {
+    if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
+        return s.get();
+    }
+
+    // We did not find it in the cache, so look through the sources.
+    for (auto& symbolSource : mSources) {
+        std::unique_ptr<Symbol> symbol = symbolSource->findById(id);
+        if (symbol) {
+            // Take ownership of the symbol into a shared_ptr. We do this because LruCache
+            // doesn't support unique_ptr.
+            std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
+            mIdCache.put(id, sharedSymbol);
+            return sharedSymbol.get();
+        }
+    }
+    return nullptr;
+}
+
+const SymbolTable::Symbol* SymbolTable::findByReference(const Reference& ref) {
+    // First try the ID. This is because when we lookup by ID, we only fill in the ID cache.
+    // Looking up by name fills in the name and ID cache. So a cache miss will cause a failed
+    // ID lookup, then a successfull name lookup. Subsequent look ups will hit immediately
+    // because the ID is cached too.
+    //
+    // If we looked up by name first, a cache miss would mean we failed to lookup by name, then
+    // succeeded to lookup by ID. Subsequent lookups will miss then hit.
+    const SymbolTable::Symbol* symbol = nullptr;
+    if (ref.id) {
+        symbol = findById(ref.id.value());
+    }
+
+    if (ref.name && !symbol) {
+        symbol = findByName(ref.name.value());
+    }
+    return symbol;
+}
+
+std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::findByName(
+        const ResourceName& name) {
     Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
     if (!result) {
         if (name.type == ResourceType::kAttr) {
@@ -41,40 +113,35 @@
 
     ResourceTable::SearchResult sr = result.value();
 
-    // If no ID exists, we treat the symbol as missing. SymbolTables are used to
-    // find symbols to link.
-    if (!sr.package->id || !sr.type->id || !sr.entry->id) {
-        return {};
-    }
-
-    std::shared_ptr<Symbol> symbol = std::make_shared<Symbol>();
-    symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
+    std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>();
     symbol->isPublic = (sr.entry->symbolStatus.state == SymbolState::kPublic);
 
+    if (sr.package->id && sr.type->id && sr.entry->id) {
+        symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
+    }
+
     if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
         const ConfigDescription kDefaultConfig;
         ResourceConfigValue* configValue = sr.entry->findValue(kDefaultConfig);
         if (configValue) {
             // This resource has an Attribute.
             if (Attribute* attr = valueCast<Attribute>(configValue->value.get())) {
-                symbol->attribute = util::make_unique<Attribute>(*attr);
+                symbol->attribute = std::make_shared<Attribute>(*attr);
             } else {
                 return {};
             }
         }
     }
-
-    if (name.type == ResourceType::kAttrPrivate) {
-        // Masquerade this entry as kAttr.
-        mCache.put(ResourceName(name.package, ResourceType::kAttr, name.entry), symbol);
-    } else {
-        mCache.put(name, symbol);
-    }
-    return symbol.get();
+    return symbol;
 }
 
-static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
-                                                                    ResourceId id) {
+bool AssetManagerSymbolSource::addAssetPath(const StringPiece& path) {
+    int32_t cookie = 0;
+    return mAssets.addAssetPath(android::String8(path.data(), path.size()), &cookie);
+}
+
+static std::unique_ptr<SymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
+                                                                   ResourceId id) {
     // Try as a bag.
     const android::ResTable::bag_entry* entry;
     ssize_t count = table.lockBag(id.id, &entry);
@@ -84,13 +151,13 @@
     }
 
     // We found a resource.
-    std::shared_ptr<ISymbolTable::Symbol> s = std::make_shared<ISymbolTable::Symbol>();
+    std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>();
     s->id = id;
 
     // Check to see if it is an attribute.
     for (size_t i = 0; i < (size_t) count; i++) {
         if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
-            s->attribute = util::make_unique<Attribute>(false);
+            s->attribute = std::make_shared<Attribute>(false);
             s->attribute->typeMask = entry[i].map.value.data;
             break;
         }
@@ -138,43 +205,36 @@
     return s;
 }
 
-const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findByName(
+std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByName(
         const ResourceName& name) {
-    if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
-        return s.get();
+    const android::ResTable& table = mAssets.getResources(false);
+    StringPiece16 typeStr = toString(name.type);
+    uint32_t typeSpecFlags = 0;
+    ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
+                                               typeStr.data(), typeStr.size(),
+                                               name.package.data(), name.package.size(),
+                                               &typeSpecFlags);
+    if (!resId.isValid()) {
+        return {};
     }
 
-    for (const auto& asset : mAssets) {
-        const android::ResTable& table = asset->getResources(false);
-        StringPiece16 typeStr = toString(name.type);
-        uint32_t typeSpecFlags = 0;
-        ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
-                                                   typeStr.data(), typeStr.size(),
-                                                   name.package.data(), name.package.size(),
-                                                   &typeSpecFlags);
-        if (!resId.isValid()) {
-            continue;
-        }
-
-        std::shared_ptr<Symbol> s;
-        if (name.type == ResourceType::kAttr) {
-            s = lookupAttributeInTable(table, resId);
-        } else {
-            s = std::make_shared<Symbol>();
-            s->id = resId;
-        }
-
-        if (s) {
-            s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
-            mCache.put(name, s);
-            return s.get();
-        }
+    std::unique_ptr<SymbolTable::Symbol> s;
+    if (name.type == ResourceType::kAttr) {
+        s = lookupAttributeInTable(table, resId);
+    } else {
+        s = util::make_unique<SymbolTable::Symbol>();
+        s->id = resId;
     }
-    return nullptr;
+
+    if (s) {
+        s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+        return s;
+    }
+    return {};
 }
 
 static Maybe<ResourceName> getResourceName(const android::ResTable& table, ResourceId id) {
-    android::ResTable::resource_name resName;
+    android::ResTable::resource_name resName = {};
     if (!table.getResourceName(id.id, true, &resName)) {
         return {};
     }
@@ -211,55 +271,38 @@
     return name;
 }
 
-const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findById(
-        ResourceId id) {
-    if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
-        return s.get();
+std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findById(ResourceId id) {
+    const android::ResTable& table = mAssets.getResources(false);
+    Maybe<ResourceName> maybeName = getResourceName(table, id);
+    if (!maybeName) {
+        return {};
     }
 
-    for (const auto& asset : mAssets) {
-        const android::ResTable& table = asset->getResources(false);
+    uint32_t typeSpecFlags = 0;
+    table.getResourceFlags(id.id, &typeSpecFlags);
 
-        Maybe<ResourceName> maybeName = getResourceName(table, id);
-        if (!maybeName) {
-            continue;
-        }
-
-        uint32_t typeSpecFlags = 0;
-        table.getResourceFlags(id.id, &typeSpecFlags);
-
-        std::shared_ptr<Symbol> s;
-        if (maybeName.value().type == ResourceType::kAttr) {
-            s = lookupAttributeInTable(table, id);
-        } else {
-            s = std::make_shared<Symbol>();
-            s->id = id;
-        }
-
-        if (s) {
-            s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
-            mIdCache.put(id, s);
-            return s.get();
-        }
+    std::unique_ptr<SymbolTable::Symbol> s;
+    if (maybeName.value().type == ResourceType::kAttr) {
+        s = lookupAttributeInTable(table, id);
+    } else {
+        s = util::make_unique<SymbolTable::Symbol>();
+        s->id = id;
     }
-    return nullptr;
-}
 
-const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findByName(
-        const ResourceName& name) {
-    for (auto& symbolTable : mSymbolTables) {
-        if (const Symbol* s = symbolTable->findByName(name)) {
-            return s;
-        }
+    if (s) {
+        s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+        return s;
     }
     return {};
 }
 
-const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findById(ResourceId id) {
-    for (auto& symbolTable : mSymbolTables) {
-        if (const Symbol* s = symbolTable->findById(id)) {
-            return s;
-        }
+std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByReference(
+        const Reference& ref) {
+    // AssetManager always prefers IDs.
+    if (ref.id) {
+        return findById(ref.id.value());
+    } else if (ref.name) {
+        return findByName(ref.name.value());
     }
     return {};
 }
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 22096ed..0a6a4a5 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -25,37 +25,20 @@
 #include <utils/JenkinsHash.h>
 #include <utils/LruCache.h>
 
+#include <android-base/macros.h>
 #include <androidfw/AssetManager.h>
 #include <algorithm>
-#include <map>
 #include <memory>
 #include <vector>
 
 namespace aapt {
 
-struct ISymbolTable {
-    virtual ~ISymbolTable() = default;
-
-    struct Symbol {
-        ResourceId id;
-        std::unique_ptr<Attribute> attribute;
-        bool isPublic;
-    };
-
-    /**
-     * Never hold on to the result between calls to findByName or findById. The results
-     * are typically stored in a cache which may evict entries.
-     */
-    virtual const Symbol* findByName(const ResourceName& name) = 0;
-    virtual const Symbol* findById(ResourceId id) = 0;
-};
-
 inline android::hash_t hash_type(const ResourceName& name) {
     std::hash<std::u16string> strHash;
     android::hash_t hash = 0;
-    hash = android::JenkinsHashMix(hash, strHash(name.package));
+    hash = android::JenkinsHashMix(hash, (uint32_t) strHash(name.package));
     hash = android::JenkinsHashMix(hash, (uint32_t) name.type);
-    hash = android::JenkinsHashMix(hash, strHash(name.entry));
+    hash = android::JenkinsHashMix(hash, (uint32_t) strHash(name.entry));
     return hash;
 }
 
@@ -63,88 +46,106 @@
     return android::hash_type(id.id);
 }
 
-/**
- * Presents a ResourceTable as an ISymbolTable, caching results.
- * Instances of this class must outlive the encompassed ResourceTable.
- * Since symbols are cached, the ResourceTable should not change during the
- * lifetime of this SymbolTableWrapper.
- *
- * If a resource in the ResourceTable does not have a ResourceID assigned to it,
- * it is ignored.
- *
- * Lookups by ID are ignored.
- */
-class SymbolTableWrapper : public ISymbolTable {
+class ISymbolSource;
+
+class SymbolTable {
+public:
+    struct Symbol {
+        Maybe<ResourceId> id;
+        std::shared_ptr<Attribute> attribute;
+        bool isPublic;
+    };
+
+    SymbolTable() : mCache(200), mIdCache(200) {
+    }
+
+    void appendSource(std::unique_ptr<ISymbolSource> source);
+    void prependSource(std::unique_ptr<ISymbolSource> source);
+
+    /**
+     * Never hold on to the result between calls to findByName or findById. The results
+     * are typically stored in a cache which may evict entries.
+     */
+    const Symbol* findByName(const ResourceName& name);
+    const Symbol* findById(ResourceId id);
+
+    /**
+     * Let's the ISymbolSource decide whether looking up by name or ID is faster, if both
+     * are available.
+     */
+    const Symbol* findByReference(const Reference& ref);
+
 private:
-    ResourceTable* mTable;
+    std::vector<std::unique_ptr<ISymbolSource>> mSources;
 
     // We use shared_ptr because unique_ptr is not supported and
     // we need automatic deletion.
     android::LruCache<ResourceName, std::shared_ptr<Symbol>> mCache;
+    android::LruCache<ResourceId, std::shared_ptr<Symbol>> mIdCache;
 
+    DISALLOW_COPY_AND_ASSIGN(SymbolTable);
+};
+
+/**
+ * An interface that a symbol source implements in order to surface symbol information
+ * to the symbol table.
+ */
+class ISymbolSource {
 public:
-    SymbolTableWrapper(ResourceTable* table) : mTable(table), mCache(200) {
-    }
+    virtual ~ISymbolSource() = default;
 
-    const Symbol* findByName(const ResourceName& name) override;
+    virtual std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) = 0;
+    virtual std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) = 0;
 
-    // Unsupported, all queries to ResourceTable should be done by name.
-    const Symbol* findById(ResourceId id) override {
+    /**
+     * Default implementation tries the name if it exists, else the ID.
+     */
+    virtual std::unique_ptr<SymbolTable::Symbol> findByReference(const Reference& ref) {
+        if (ref.name) {
+            return findByName(ref.name.value());
+        } else if (ref.id) {
+            return findById(ref.id.value());
+        }
         return {};
     }
 };
 
-class AssetManagerSymbolTableBuilder {
-private:
-    struct AssetManagerSymbolTable : public ISymbolTable {
-        std::vector<std::unique_ptr<android::AssetManager>> mAssets;
-
-        // We use shared_ptr because unique_ptr is not supported and
-        // we need automatic deletion.
-        android::LruCache<ResourceName, std::shared_ptr<Symbol>> mCache;
-        android::LruCache<ResourceId, std::shared_ptr<Symbol>> mIdCache;
-
-        AssetManagerSymbolTable() : mCache(200), mIdCache(200) {
-        }
-
-        const Symbol* findByName(const ResourceName& name) override;
-        const Symbol* findById(ResourceId id) override;
-    };
-
-    std::unique_ptr<AssetManagerSymbolTable> mSymbolTable =
-            util::make_unique<AssetManagerSymbolTable>();
-
+/**
+ * Exposes the resources in a ResourceTable as symbols for SymbolTable.
+ * Instances of this class must outlive the encompassed ResourceTable.
+ * Lookups by ID are ignored.
+ */
+class ResourceTableSymbolSource : public ISymbolSource {
 public:
-    AssetManagerSymbolTableBuilder& add(std::unique_ptr<android::AssetManager> assetManager) {
-        mSymbolTable->mAssets.push_back(std::move(assetManager));
-        return *this;
+    explicit ResourceTableSymbolSource(ResourceTable* table) : mTable(table) {
     }
 
-    std::unique_ptr<ISymbolTable> build() {
-        return std::move(mSymbolTable);
+    std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override;
+
+    std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override {
+        return {};
     }
+
+private:
+    ResourceTable* mTable;
+
+    DISALLOW_COPY_AND_ASSIGN(ResourceTableSymbolSource);
 };
 
-class JoinedSymbolTableBuilder {
-private:
-    struct JoinedSymbolTable : public ISymbolTable {
-        std::vector<std::unique_ptr<ISymbolTable>> mSymbolTables;
-
-        const Symbol* findByName(const ResourceName& name) override;
-        const Symbol* findById(ResourceId id) override;
-    };
-
-    std::unique_ptr<JoinedSymbolTable> mSymbolTable = util::make_unique<JoinedSymbolTable>();
-
+class AssetManagerSymbolSource : public ISymbolSource {
 public:
-    JoinedSymbolTableBuilder& addSymbolTable(std::unique_ptr<ISymbolTable> table) {
-        mSymbolTable->mSymbolTables.push_back(std::move(table));
-        return *this;
-    }
+    AssetManagerSymbolSource() = default;
 
-    std::unique_ptr<ISymbolTable> build() {
-        return std::move(mSymbolTable);
-    }
+    bool addAssetPath(const StringPiece& path);
+
+    std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override;
+    std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override;
+    std::unique_ptr<SymbolTable::Symbol> findByReference(const Reference& ref) override;
+
+private:
+    android::AssetManager mAssets;
+
+    DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource);
 };
 
 } // namespace aapt
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index 1dc3b4f..34f31be 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -15,14 +15,11 @@
  */
 
 #include "process/SymbolTable.h"
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
 
 namespace aapt {
 
-TEST(SymbolTableWrapperTest, FindSymbolsWithIds) {
+TEST(ResourceTableSymbolSourceTest, FindSymbols) {
     std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
             .addSimple(u"@android:id/foo", ResourceId(0x01020000))
             .addSimple(u"@android:id/bar")
@@ -30,27 +27,27 @@
                       test::AttributeBuilder().build())
             .build();
 
-    SymbolTableWrapper symbolTable(table.get());
-    EXPECT_NE(symbolTable.findByName(test::parseNameOrDie(u"@android:id/foo")), nullptr);
-    EXPECT_EQ(symbolTable.findByName(test::parseNameOrDie(u"@android:id/bar")), nullptr);
+    ResourceTableSymbolSource symbolSource(table.get());
+    EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/foo")));
+    EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/bar")));
 
-    const ISymbolTable::Symbol* s = symbolTable.findByName(
+    std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
             test::parseNameOrDie(u"@android:attr/foo"));
-    ASSERT_NE(s, nullptr);
-    EXPECT_NE(s->attribute, nullptr);
+    ASSERT_NE(nullptr, s);
+    EXPECT_NE(nullptr, s->attribute);
 }
 
-TEST(SymbolTableWrapperTest, FindPrivateAttrSymbol) {
+TEST(ResourceTableSymbolSourceTest, FindPrivateAttrSymbol) {
     std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
             .addValue(u"@android:^attr-private/foo", ResourceId(0x01010000),
                       test::AttributeBuilder().build())
             .build();
 
-    SymbolTableWrapper symbolTable(table.get());
-    const ISymbolTable::Symbol* s = symbolTable.findByName(
+    ResourceTableSymbolSource symbolSource(table.get());
+    std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
                 test::parseNameOrDie(u"@android:attr/foo"));
-    ASSERT_NE(s, nullptr);
-    EXPECT_NE(s->attribute, nullptr);
+    ASSERT_NE(nullptr, s);
+    EXPECT_NE(nullptr, s->attribute);
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
index 9856a00..86883f8 100644
--- a/tools/aapt2/proto/TableProtoDeserializer.cpp
+++ b/tools/aapt2/proto/TableProtoDeserializer.cpp
@@ -483,8 +483,13 @@
         }
 
         const size_t padding = 4 - (pbSize & 0x03);
-        mData += sizeof(uint64_t) + pbSize + padding;
-        mSize -= sizeof(uint64_t) + pbSize + padding;
+        const size_t offset = sizeof(uint64_t) + pbSize + padding;
+        if (offset > mSize) {
+            return nullptr;
+        }
+
+        mData += offset;
+        mSize -= offset;
         mPbFile = std::move(pbFile);
     }
     return mPbFile.get();
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index b3d87d8..5d1b72b 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -178,10 +178,13 @@
     void serializeReferenceToPb(const Reference& ref, pb::Reference* pbRef) {
         if (ref.id) {
             pbRef->set_id(ref.id.value().id);
-        } else if (ref.name) {
+        }
+
+        if (ref.name) {
             StringPool::Ref symbolRef = mSymbolPool->makeRef(ref.name.value().toString());
             pbRef->set_symbol_idx(static_cast<uint32_t>(symbolRef.getIndex()));
         }
+
         pbRef->set_private_(ref.privateReference);
         pbRef->set_type(serializeReferenceTypeToPb(ref.referenceType));
     }
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
index 70a33f7..dd995d8 100644
--- a/tools/aapt2/proto/TableProtoSerializer_test.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer_test.cpp
@@ -62,6 +62,17 @@
                                        test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
                                        context->getDiagnostics()));
 
+    // Make a reference with both resource name and resource ID.
+    // The reference should point to a resource outside of this table to test that both
+    // name and id get serialized.
+    Reference expectedRef;
+    expectedRef.name = test::parseNameOrDie(u"@android:layout/main");
+    expectedRef.id = ResourceId(0x01020000);
+    ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:layout/abc"),
+                                   ConfigDescription::defaultConfig(), std::string(),
+                                   util::make_unique<Reference>(expectedRef),
+                                   context->getDiagnostics()));
+
     std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table.get());
     ASSERT_NE(nullptr, pbTable);
 
@@ -90,6 +101,13 @@
             newTable.get(), u"@com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
     ASSERT_NE(nullptr, prim);
     EXPECT_EQ(321u, prim->value.data);
+
+    Reference* actualRef = test::getValue<Reference>(newTable.get(), u"@com.app.a:layout/abc");
+    ASSERT_NE(nullptr, actualRef);
+    AAPT_ASSERT_TRUE(actualRef->name);
+    AAPT_ASSERT_TRUE(actualRef->id);
+    EXPECT_EQ(expectedRef.name.value(), actualRef->name.value());
+    EXPECT_EQ(expectedRef.id.value(), actualRef->id.value());
 }
 
 TEST(TableProtoSerializer, SerializeFileHeader) {
@@ -130,4 +148,27 @@
     EXPECT_EQ(test::parseNameOrDie(u"@+id/unchecked"), file->exportedSymbols[0].name);
 }
 
+TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
+    ResourceFile f;
+    std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
+
+    const std::string expectedData = "1234";
+
+    std::string outputStr;
+    {
+        google::protobuf::io::StringOutputStream outStream(&outputStr);
+        CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
+
+        ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
+        ASSERT_TRUE(outFileStream.Finish());
+    }
+
+    outputStr[0] = 0xff;
+
+    CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
+    EXPECT_EQ(nullptr, inFileStream.CompiledFile());
+    EXPECT_EQ(nullptr, inFileStream.data());
+    EXPECT_EQ(0u, inFileStream.size());
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 834caf8..8c56ebc 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -246,7 +246,7 @@
 inline std::unique_ptr<xml::XmlResource> buildXmlDomForPackageName(IAaptContext* context,
                                                                    const StringPiece& str) {
     std::unique_ptr<xml::XmlResource> doc = buildXmlDom(str);
-    doc->file.name.package = context->getCompilationPackage().toString();
+    doc->file.name.package = context->getCompilationPackage();
     return doc;
 }
 
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index e540cd7..96752d3 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -31,33 +31,16 @@
 namespace test {
 
 class Context : public IAaptContext {
-private:
-    friend class ContextBuilder;
-
-    Context() = default;
-
-    Maybe<std::u16string> mCompilationPackage;
-    Maybe<uint8_t> mPackageId;
-    std::unique_ptr<IDiagnostics> mDiagnostics = util::make_unique<StdErrDiagnostics>();
-    std::unique_ptr<ISymbolTable> mSymbols;
-    std::unique_ptr<NameMangler> mNameMangler;
-
 public:
-    ISymbolTable* getExternalSymbols() override {
-        assert(mSymbols && "test symbols not set");
-        return mSymbols.get();
-    }
-
-    void setSymbolTable(std::unique_ptr<ISymbolTable> symbols) {
-        mSymbols = std::move(symbols);
+    SymbolTable* getExternalSymbols() override {
+        return &mSymbols;
     }
 
     IDiagnostics* getDiagnostics() override {
-        assert(mDiagnostics && "test diagnostics not set");
-        return mDiagnostics.get();
+        return &mDiagnostics;
     }
 
-    StringPiece16 getCompilationPackage() override {
+    const std::u16string& getCompilationPackage() override {
         assert(mCompilationPackage && "package name not set");
         return mCompilationPackage.value();
     }
@@ -68,13 +51,24 @@
     }
 
     NameMangler* getNameMangler() override {
-        assert(mNameMangler && "test name mangler not set");
-        return mNameMangler.get();
+        return &mNameMangler;
     }
 
     bool verbose() override {
         return false;
     }
+
+private:
+    friend class ContextBuilder;
+
+    Context() : mNameMangler({}) {
+    }
+
+    Maybe<std::u16string> mCompilationPackage;
+    Maybe<uint8_t> mPackageId;
+    StdErrDiagnostics mDiagnostics;
+    SymbolTable mSymbols;
+    NameMangler mNameMangler;
 };
 
 class ContextBuilder {
@@ -92,18 +86,13 @@
         return *this;
     }
 
-    ContextBuilder& setSymbolTable(std::unique_ptr<ISymbolTable> symbols) {
-        mContext->mSymbols = std::move(symbols);
-        return *this;
-    }
-
-    ContextBuilder& setDiagnostics(std::unique_ptr<IDiagnostics> diag) {
-        mContext->mDiagnostics = std::move(diag);
-        return *this;
-    }
-
     ContextBuilder& setNameManglerPolicy(NameManglerPolicy policy) {
-        mContext->mNameMangler = util::make_unique<NameMangler>(policy);
+        mContext->mNameMangler = NameMangler(policy);
+        return *this;
+    }
+
+    ContextBuilder& addSymbolSource(std::unique_ptr<ISymbolSource> src) {
+        mContext->getExternalSymbols()->appendSource(std::move(src));
         return *this;
     }
 
@@ -112,57 +101,72 @@
     }
 };
 
-class StaticSymbolTableBuilder {
-private:
-    struct SymbolTable : public ISymbolTable {
-        std::list<std::unique_ptr<Symbol>> mSymbols;
-        std::map<ResourceName, Symbol*> mNameMap;
-        std::map<ResourceId, Symbol*> mIdMap;
+class StaticSymbolSourceBuilder {
+public:
+    StaticSymbolSourceBuilder& addPublicSymbol(const StringPiece16& name, ResourceId id,
+                                               std::unique_ptr<Attribute> attr = {}) {
+        std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
+                id, std::move(attr), true);
+        mSymbolSource->mNameMap[parseNameOrDie(name)] = symbol.get();
+        mSymbolSource->mIdMap[id] = symbol.get();
+        mSymbolSource->mSymbols.push_back(std::move(symbol));
+        return *this;
+    }
 
-        const Symbol* findByName(const ResourceName& name) override {
+    StaticSymbolSourceBuilder& addSymbol(const StringPiece16& name, ResourceId id,
+                                         std::unique_ptr<Attribute> attr = {}) {
+        std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
+                id, std::move(attr), false);
+        mSymbolSource->mNameMap[parseNameOrDie(name)] = symbol.get();
+        mSymbolSource->mIdMap[id] = symbol.get();
+        mSymbolSource->mSymbols.push_back(std::move(symbol));
+        return *this;
+    }
+
+    std::unique_ptr<ISymbolSource> build() {
+        return std::move(mSymbolSource);
+    }
+
+private:
+    class StaticSymbolSource : public ISymbolSource {
+    public:
+        StaticSymbolSource() = default;
+
+        std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override {
             auto iter = mNameMap.find(name);
             if (iter != mNameMap.end()) {
-                return iter->second;
+                return cloneSymbol(iter->second);
             }
             return nullptr;
         }
 
-        const Symbol* findById(ResourceId id) override {
+        std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override {
             auto iter = mIdMap.find(id);
             if (iter != mIdMap.end()) {
-                return iter->second;
+                return cloneSymbol(iter->second);
             }
             return nullptr;
         }
+
+        std::list<std::unique_ptr<SymbolTable::Symbol>> mSymbols;
+        std::map<ResourceName, SymbolTable::Symbol*> mNameMap;
+        std::map<ResourceId, SymbolTable::Symbol*> mIdMap;
+
+    private:
+        std::unique_ptr<SymbolTable::Symbol> cloneSymbol(SymbolTable::Symbol* sym) {
+            std::unique_ptr<SymbolTable::Symbol> clone = util::make_unique<SymbolTable::Symbol>();
+            clone->id = sym->id;
+            if (sym->attribute) {
+                clone->attribute = std::unique_ptr<Attribute>(sym->attribute->clone(nullptr));
+            }
+            clone->isPublic = sym->isPublic;
+            return clone;
+        }
+
+        DISALLOW_COPY_AND_ASSIGN(StaticSymbolSource);
     };
 
-    std::unique_ptr<SymbolTable> mSymbolTable = util::make_unique<SymbolTable>();
-
-public:
-    StaticSymbolTableBuilder& addPublicSymbol(const StringPiece16& name, ResourceId id,
-                                              std::unique_ptr<Attribute> attr = {}) {
-        std::unique_ptr<ISymbolTable::Symbol> symbol = util::make_unique<ISymbolTable::Symbol>(
-                id, std::move(attr));
-        symbol->isPublic = true;
-        mSymbolTable->mNameMap[parseNameOrDie(name)] = symbol.get();
-        mSymbolTable->mIdMap[id] = symbol.get();
-        mSymbolTable->mSymbols.push_back(std::move(symbol));
-        return *this;
-    }
-
-    StaticSymbolTableBuilder& addSymbol(const StringPiece16& name, ResourceId id,
-                                        std::unique_ptr<Attribute> attr = {}) {
-        std::unique_ptr<ISymbolTable::Symbol> symbol = util::make_unique<ISymbolTable::Symbol>(
-                id, std::move(attr));
-        mSymbolTable->mNameMap[parseNameOrDie(name)] = symbol.get();
-        mSymbolTable->mIdMap[id] = symbol.get();
-        mSymbolTable->mSymbols.push_back(std::move(symbol));
-        return *this;
-    }
-
-    std::unique_ptr<ISymbolTable> build() {
-        return std::move(mSymbolTable);
-    }
+    std::unique_ptr<StaticSymbolSource> mSymbolSource = util::make_unique<StaticSymbolSource>();
 };
 
 } // namespace test
diff --git a/tools/aapt2/test/Test.h b/tools/aapt2/test/Test.h
new file mode 100644
index 0000000..d4845cf
--- /dev/null
+++ b/tools/aapt2/test/Test.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_TEST_TEST_H
+#define AAPT_TEST_TEST_H
+
+#include "test/Builders.h"
+#include "test/Common.h"
+#include "test/Context.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+namespace test {
+
+} // namespace test
+} // namespace aapt
+
+#endif // AAPT_TEST_TEST_H
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 04e8199..6428e98 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -96,7 +96,7 @@
     const char* start = path.begin();
     const char* end = path.end();
     for (const char* current = start; current != end; ++current) {
-        if (*current == sDirSep) {
+        if (*current == sDirSep && current != start) {
             StringPiece parentPath(start, current - start);
             int result = mkdirImpl(parentPath);
             if (result < 0 && errno != EEXIST) {
@@ -139,6 +139,20 @@
     return {};
 }
 
+void appendPath(std::string* base, StringPiece part) {
+    assert(base);
+    const bool baseHasTrailingSep = (!base->empty() && *(base->end() - 1) == sDirSep);
+    const bool partHasLeadingSep = (!part.empty() && *(part.begin()) == sDirSep);
+    if (baseHasTrailingSep && partHasLeadingSep) {
+        // Remove the part's leading sep
+        part = part.substr(1, part.size() - 1);
+    } else if (!baseHasTrailingSep && !partHasLeadingSep) {
+        // None of the pieces has a separator.
+        *base += sDirSep;
+    }
+    base->append(part.data(), part.size());
+}
+
 std::string packageToPath(const StringPiece& package) {
     std::string outPath;
     for (StringPiece part : util::tokenize<char>(package, '.')) {
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index c58ba5d..c2e6115 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -61,14 +61,7 @@
 /*
  * Appends a path to `base`, separated by the directory separator.
  */
-void appendPath(std::string* base, const StringPiece& part);
-
-/*
- * Appends a series of paths to `base`, separated by the
- * system directory separator.
- */
-template <typename... Ts >
-void appendPath(std::string* base, const StringPiece& part, const Ts&... parts);
+void appendPath(std::string* base, StringPiece part);
 
 /*
  * Makes all the directories in `path`. The last element in the path
@@ -139,20 +132,6 @@
     std::vector<std::string> mPatternTokens;
 };
 
-inline void appendPath(std::string* base, const StringPiece& part) {
-    assert(base);
-    *base += sDirSep;
-    base->append(part.data(), part.size());
-}
-
-template <typename... Ts >
-void appendPath(std::string* base, const StringPiece& part, const Ts&... parts) {
-    assert(base);
-    *base += sDirSep;
-    base->append(part.data(), part.size());
-    appendPath(base, parts...);
-}
-
 } // namespace file
 } // namespace aapt
 
diff --git a/tools/aapt2/util/Files_test.cpp b/tools/aapt2/util/Files_test.cpp
new file mode 100644
index 0000000..efb0459
--- /dev/null
+++ b/tools/aapt2/util/Files_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/Test.h"
+#include "util/Files.h"
+
+#include <sstream>
+
+namespace aapt {
+namespace file {
+
+class FilesTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        std::stringstream builder;
+        builder << "hello" << sDirSep << "there";
+        mExpectedPath = builder.str();
+    }
+
+protected:
+    std::string mExpectedPath;
+};
+
+TEST_F(FilesTest, appendPath) {
+    std::string base = "hello";
+    appendPath(&base, "there");
+    EXPECT_EQ(mExpectedPath, base);
+}
+
+TEST_F(FilesTest, appendPathWithLeadingOrTrailingSeparators) {
+    std::string base = "hello/";
+    appendPath(&base, "there");
+    EXPECT_EQ(mExpectedPath, base);
+
+    base = "hello";
+    appendPath(&base, "/there");
+    EXPECT_EQ(mExpectedPath, base);
+
+    base = "hello/";
+    appendPath(&base, "/there");
+    EXPECT_EQ(mExpectedPath, base);
+}
+
+} // namespace files
+} // namespace aapt
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 033b0a4..b374d20 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -68,7 +68,7 @@
 };
 
 struct AaptAttribute {
-    ResourceId id;
+    Maybe<ResourceId> id;
     aapt::Attribute attribute;
 };
 
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index df76bc9..ca2d2e7 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -264,6 +264,9 @@
         if "static" in f.split and "final" in f.split:
             if re.match("[A-Z0-9_]+", f.name) is None:
                 error(clazz, f, "C2", "Constant field names must be FOO_NAME")
+            elif f.typ != "java.lang.String":
+                if f.name.startswith("MIN_") or f.name.startswith("MAX_"):
+                    warn(clazz, f, "C8", "If min/max could change in future, make them dynamic methods")
 
 
 def verify_enums(clazz):
@@ -417,6 +420,9 @@
         if len(creator) == 0 or len(write) == 0 or len(describe) == 0:
             error(clazz, None, "FW3", "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
 
+        if " final class " not in clazz.raw:
+            error(clazz, None, "FW8", "Parcelable classes must be final")
+
 
 def verify_protected(clazz):
     """Verify that no protected methods or fields are allowed."""
@@ -730,6 +736,13 @@
         if "throws java.lang.Exception" in m.raw or "throws java.lang.Throwable" in m.raw or "throws java.lang.Error" in m.raw:
             error(clazz, m, "S1", "Methods must not throw generic exceptions")
 
+        if "throws android.os.RemoteException" in m.raw:
+            if clazz.name == "android.content.ContentProviderClient": continue
+            if clazz.name == "android.os.Binder": continue
+            if clazz.name == "android.os.IBinder": continue
+
+            error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException")
+
 
 def verify_google(clazz):
     """Verifies that APIs never reference Google."""
@@ -946,6 +959,37 @@
             error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
 
 
+def verify_files(clazz):
+    """Verifies that methods accepting File also accept streams."""
+
+    has_file = set()
+    has_stream = set()
+
+    test = []
+    test.extend(clazz.ctors)
+    test.extend(clazz.methods)
+
+    for m in test:
+        if "java.io.File" in m.args:
+            has_file.add(m)
+        if "java.io.FileDescriptor" in m.args or "android.os.ParcelFileDescriptor" in m.args or "java.io.InputStream" in m.args or "java.io.OutputStream" in m.args:
+            has_stream.add(m.name)
+
+    for m in has_file:
+        if m.name not in has_stream:
+            warn(clazz, m, "M10", "Methods accepting File should also accept FileDescriptor or streams")
+
+
+def verify_manager_list(clazz):
+    """Verifies that managers return List<? extends Parcelable> instead of arrays."""
+
+    if not clazz.name.endswith("Manager"): return
+
+    for m in clazz.methods:
+        if m.typ.startswith("android.") and m.typ.endswith("[]"):
+            warn(clazz, m, None, "Methods should return List<? extends Parcelable> instead of Parcelable[] to support ParceledListSlice under the hood")
+
+
 def examine_clazz(clazz):
     """Find all style issues in the given class."""
     if clazz.pkg.name.startswith("java"): return
@@ -954,6 +998,7 @@
     if clazz.pkg.name.startswith("org.xml"): return
     if clazz.pkg.name.startswith("org.json"): return
     if clazz.pkg.name.startswith("org.w3c"): return
+    if clazz.pkg.name.startswith("android.icu."): return
 
     verify_constants(clazz)
     verify_enums(clazz)
@@ -989,6 +1034,8 @@
     verify_context_first(clazz)
     verify_listener_last(clazz)
     verify_resource_names(clazz)
+    verify_files(clazz)
+    verify_manager_list(clazz)
 
 
 def examine_stream(stream):
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
new file mode 100755
index 0000000..b5ed1b5
--- /dev/null
+++ b/tools/fonts/fontchain_lint.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python
+
+import collections
+import glob
+from os import path
+import sys
+from xml.etree import ElementTree
+
+from fontTools import ttLib
+
+LANG_TO_SCRIPT = {
+    'as': 'Beng',
+    'bn': 'Beng',
+    'cy': 'Latn',
+    'da': 'Latn',
+    'de': 'Latn',
+    'en': 'Latn',
+    'es': 'Latn',
+    'et': 'Latn',
+    'eu': 'Latn',
+    'fr': 'Latn',
+    'ga': 'Latn',
+    'gu': 'Gujr',
+    'hi': 'Deva',
+    'hr': 'Latn',
+    'hu': 'Latn',
+    'hy': 'Armn',
+    'ja': 'Jpan',
+    'kn': 'Knda',
+    'ko': 'Kore',
+    'ml': 'Mlym',
+    'mn': 'Cyrl',
+    'mr': 'Deva',
+    'nb': 'Latn',
+    'nn': 'Latn',
+    'or': 'Orya',
+    'pa': 'Guru',
+    'pt': 'Latn',
+    'sl': 'Latn',
+    'ta': 'Taml',
+    'te': 'Telu',
+    'tk': 'Latn',
+}
+
+def lang_to_script(lang_code):
+    lang = lang_code.lower()
+    while lang not in LANG_TO_SCRIPT:
+        hyphen_idx = lang.rfind('-')
+        assert hyphen_idx != -1, (
+            'We do not know what script the "%s" language is written in.'
+            % lang_code)
+        assumed_script = lang[hyphen_idx+1:]
+        if len(assumed_script) == 4 and assumed_script.isalpha():
+            # This is actually the script
+            return assumed_script.title()
+        lang = lang[:hyphen_idx]
+    return LANG_TO_SCRIPT[lang]
+
+
+def get_best_cmap(font):
+    font_file, index = font
+    font_path = path.join(_fonts_dir, font_file)
+    if index is not None:
+        ttfont = ttLib.TTFont(font_path, fontNumber=index)
+    else:
+        ttfont = ttLib.TTFont(font_path)
+    all_unicode_cmap = None
+    bmp_cmap = None
+    for cmap in ttfont['cmap'].tables:
+        specifier = (cmap.format, cmap.platformID, cmap.platEncID)
+        if specifier == (4, 3, 1):
+            assert bmp_cmap is None, 'More than one BMP cmap in %s' % (font, )
+            bmp_cmap = cmap
+        elif specifier == (12, 3, 10):
+            assert all_unicode_cmap is None, (
+                'More than one UCS-4 cmap in %s' % (font, ))
+            all_unicode_cmap = cmap
+
+    return all_unicode_cmap.cmap if all_unicode_cmap else bmp_cmap.cmap
+
+
+def assert_font_supports_any_of_chars(font, chars):
+    best_cmap = get_best_cmap(font)
+    for char in chars:
+        if char in best_cmap:
+            return
+    sys.exit('None of characters in %s were found in %s' % (chars, font))
+
+
+def assert_font_supports_all_of_chars(font, chars):
+    best_cmap = get_best_cmap(font)
+    for char in chars:
+        assert char in best_cmap, (
+            'U+%04X was not found in %s' % (char, font))
+
+
+def assert_font_supports_none_of_chars(font, chars):
+    best_cmap = get_best_cmap(font)
+    for char in chars:
+        assert char not in best_cmap, (
+            'U+%04X was found in %s' % (char, font))
+
+
+def check_hyphens(hyphens_dir):
+    # Find all the scripts that need automatic hyphenation
+    scripts = set()
+    for hyb_file in glob.iglob(path.join(hyphens_dir, '*.hyb')):
+        hyb_file = path.basename(hyb_file)
+        assert hyb_file.startswith('hyph-'), (
+            'Unknown hyphenation file %s' % hyb_file)
+        lang_code = hyb_file[hyb_file.index('-')+1:hyb_file.index('.')]
+        scripts.add(lang_to_script(lang_code))
+
+    HYPHENS = {0x002D, 0x2010}
+    for script in scripts:
+        fonts = _script_to_font_map[script]
+        assert fonts, 'No fonts found for the "%s" script' % script
+        for font in fonts:
+            assert_font_supports_any_of_chars(font, HYPHENS)
+
+
+def parse_fonts_xml(fonts_xml_path):
+    global _script_to_font_map, _fallback_chain
+    _script_to_font_map = collections.defaultdict(set)
+    _fallback_chain = []
+    tree = ElementTree.parse(fonts_xml_path)
+    for family in tree.findall('family'):
+        name = family.get('name')
+        variant = family.get('variant')
+        langs = family.get('lang')
+        if name:
+            assert variant is None, (
+                'No variant expected for LGC font %s.' % name)
+            assert langs is None, (
+                'No language expected for LGC fonts %s.' % name)
+        else:
+            assert variant in {None, 'elegant', 'compact'}, (
+                'Unexpected value for variant: %s' % variant)
+
+        if langs:
+            langs = langs.split()
+            scripts = {lang_to_script(lang) for lang in langs}
+        else:
+            scripts = set()
+
+        for child in family:
+            assert child.tag == 'font', (
+                'Unknown tag <%s>' % child.tag)
+            font_file = child.text
+            weight = int(child.get('weight'))
+            assert weight % 100 == 0, (
+                'Font weight "%d" is not a multiple of 100.' % weight)
+
+            style = child.get('style')
+            assert style in {'normal', 'italic'}, (
+                'Unknown style "%s"' % style)
+
+            index = child.get('index')
+            if index:
+                index = int(index)
+
+            _fallback_chain.append((
+                name,
+                frozenset(scripts),
+                variant,
+                weight,
+                style,
+                (font_file, index)))
+
+            if name: # non-empty names are used for default LGC fonts
+                map_scripts = {'Latn', 'Grek', 'Cyrl'}
+            else:
+                map_scripts = scripts
+            for script in map_scripts:
+                _script_to_font_map[script].add((font_file, index))
+
+
+def check_emoji_availability():
+    emoji_fonts = [font[5] for font in _fallback_chain if 'Zsye' in font[1]]
+    assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
+    emoji_font = emoji_fonts[0]
+    emoji_chars = _emoji_properties['Emoji']
+    assert_font_supports_all_of_chars(emoji_font, emoji_chars)
+
+
+def check_emoji_defaults():
+    default_emoji_chars = _emoji_properties['Emoji_Presentation']
+    missing_text_chars = _emoji_properties['Emoji'] - default_emoji_chars
+    emoji_font_seen = False
+    for name, scripts, variant, weight, style, font in _fallback_chain:
+        if 'Zsye' in scripts:
+            emoji_font_seen = True
+            # No need to check the emoji font
+            continue
+        # For later fonts, we only check them if they have a script
+        # defined, since the defined script may get them to a higher
+        # score even if they appear after the emoji font.
+        if emoji_font_seen and not scripts:
+            continue
+
+        # Check default emoji-style characters
+        assert_font_supports_none_of_chars(font, sorted(default_emoji_chars))
+
+        # Mark default text-style characters appearing in fonts above the emoji
+        # font as seen
+        if not emoji_font_seen:
+            missing_text_chars -= set(get_best_cmap(font))
+
+    # Noto does not have monochrome symbols for Unicode 7.0 wingdings and
+    # webdings
+    missing_text_chars -= _chars_by_age['7.0']
+    # TODO: Remove these after b/26113320 is fixed
+    missing_text_chars -= {
+        0x263A, # WHITE SMILING FACE
+        0x270C, # VICTORY HAND
+        0x2744, # SNOWFLAKE
+        0x2764, # HEAVY BLACK HEART
+    }
+    assert missing_text_chars == set(), (
+        'Text style version of some emoji characters are missing.')
+
+
+# Setting reverse to true returns a dictionary that maps the values to sets of
+# characters, useful for some binary properties. Otherwise, we get a
+# dictionary that maps characters to the property values, assuming there's only
+# one property in the file.
+def parse_unicode_datafile(file_path, reverse=False):
+    if reverse:
+        output_dict = collections.defaultdict(set)
+    else:
+        output_dict = {}
+    with open(file_path) as datafile:
+        for line in datafile:
+            if '#' in line:
+                line = line[:line.index('#')]
+            line = line.strip()
+            if not line:
+                continue
+            char_range, prop = line.split(';')
+            char_range = char_range.strip()
+            prop = prop.strip()
+            if '..' in char_range:
+                char_start, char_end = char_range.split('..')
+            else:
+                char_start = char_end = char_range
+            char_start = int(char_start, 16)
+            char_end = int(char_end, 16)
+            char_range = xrange(char_start, char_end+1)
+            if reverse:
+                output_dict[prop].update(char_range)
+            else:
+                for char in char_range:
+                    assert char not in output_dict
+                    output_dict[char] = prop
+    return output_dict
+
+
+def parse_ucd(ucd_path):
+    global _emoji_properties, _chars_by_age
+    _emoji_properties = parse_unicode_datafile(
+        path.join(ucd_path, 'emoji-data.txt'), reverse=True)
+    _chars_by_age = parse_unicode_datafile(
+        path.join(ucd_path, 'DerivedAge.txt'), reverse=True)
+
+
+def main():
+    target_out = sys.argv[1]
+    global _fonts_dir
+    _fonts_dir = path.join(target_out, 'fonts')
+
+    fonts_xml_path = path.join(target_out, 'etc', 'fonts.xml')
+    parse_fonts_xml(fonts_xml_path)
+
+    hyphens_dir = path.join(target_out, 'usr', 'hyphen-data')
+    check_hyphens(hyphens_dir)
+
+    check_emoji = sys.argv[2]
+    if check_emoji == 'true':
+        ucd_path = sys.argv[3]
+        parse_ucd(ucd_path)
+        check_emoji_availability()
+        check_emoji_defaults()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/layoutlib/.idea/codeStyleSettings.xml b/tools/layoutlib/.idea/codeStyleSettings.xml
index 89f7b34..ac90d1e 100644
--- a/tools/layoutlib/.idea/codeStyleSettings.xml
+++ b/tools/layoutlib/.idea/codeStyleSettings.xml
@@ -40,6 +40,7 @@
           <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
         </XML>
         <codeStyleSettings language="JAVA">
+          <option name="KEEP_LINE_BREAKS" value="false" />
           <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
           <option name="CALL_PARAMETERS_WRAP" value="1" />
           <option name="METHOD_PARAMETERS_WRAP" value="1" />
@@ -55,6 +56,7 @@
           <option name="DOWHILE_BRACE_FORCE" value="3" />
           <option name="WHILE_BRACE_FORCE" value="3" />
           <option name="FOR_BRACE_FORCE" value="3" />
+          <option name="WRAP_LONG_LINES" value="true" />
           <arrangement>
             <groups>
               <group>
diff --git a/tools/layoutlib/.idea/libraries/junit.xml b/tools/layoutlib/.idea/libraries/junit.xml
new file mode 100644
index 0000000..c889f5f
--- /dev/null
+++ b/tools/layoutlib/.idea/libraries/junit.xml
@@ -0,0 +1,11 @@
+<component name="libraryTable">
+  <library name="junit">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/junit_intermediates/javalib.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="file://$PROJECT_DIR$/../../../../external/junit/src" />
+    </SOURCES>
+  </library>
+</component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/runConfigurations/Create.xml b/tools/layoutlib/.idea/runConfigurations/Create.xml
index 58f057a..536a23f 100644
--- a/tools/layoutlib/.idea/runConfigurations/Create.xml
+++ b/tools/layoutlib/.idea/runConfigurations/Create.xml
@@ -2,8 +2,8 @@
   <configuration default="false" name="Create" type="Application" factoryName="Application" singleton="true">
     <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
     <option name="MAIN_CLASS_NAME" value="com.android.tools.layoutlib.create.Main" />
-    <option name="VM_PARAMETERS" value="" />
-    <option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icudata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
+    <option name="VM_PARAMETERS" value="-ea" />
+    <option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icudata-host-jarjar_intermediates/classes-jarjar.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-host-jarjar_intermediates/classes-jarjar.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
     <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../../../../" />
     <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
     <option name="ALTERNATIVE_JRE_PATH" value="" />
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index c2ad9ef..663e1e2 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -40,10 +40,8 @@
 built_ext_classes := $(call java-lib-files,ext)
 built_ext_data := $(call intermediates-dir-for, \
 			JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
-built_icudata_dep := $(call java-lib-deps,icu4j-icudata-jarjar)
-built_icudata_data := $(call java-lib-files,icu4j-icudata-jarjar)
-built_icutzdata_dep := $(call java-lib-deps,icu4j-icutzdata-jarjar)
-built_icutzdata_data := $(call java-lib-files,icu4j-icutzdata-jarjar)
+built_icudata_dep := $(call java-lib-deps,icu4j-icudata-host-jarjar,HOST)
+built_icutzdata_dep := $(call java-lib-deps,icu4j-icutzdata-host-jarjar,HOST)
 
 built_layoutlib_create_jar := $(call intermediates-dir-for, \
 			JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -77,8 +75,8 @@
 	             $(built_core_classes) \
 	             $(built_framework_classes) \
 	             $(built_ext_classes) \
-		     $(built_icudata_data) \
-		     $(built_icutzdata_data) \
+		     $(built_icudata_dep) \
+		     $(built_icutzdata_dep) \
 	             $(built_ext_data)
 	$(hide) ls -l $(built_framework_classes)
 
diff --git a/tools/layoutlib/bridge/bridge.iml b/tools/layoutlib/bridge/bridge.iml
index ccc10b3..57d08cb 100644
--- a/tools/layoutlib/bridge/bridge.iml
+++ b/tools/layoutlib/bridge/bridge.iml
@@ -84,6 +84,6 @@
         </SOURCES>
       </library>
     </orderEntry>
-    <orderEntry type="library" scope="TEST" name="JUnit4" level="application" />
+    <orderEntry type="library" scope="TEST" name="junit" level="project" />
   </component>
 </module>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
deleted file mode 100644
index fe46480..0000000
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ /dev/null
@@ -1,858 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.res;
-
-import com.android.SdkConstants;
-import com.android.ide.common.rendering.api.ArrayResourceValue;
-import com.android.ide.common.rendering.api.DensityBasedResourceValue;
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.LayoutlibCallback;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
-import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.impl.ParserFactory;
-import com.android.layoutlib.bridge.impl.ResourceHelper;
-import com.android.ninepatch.NinePatch;
-import com.android.resources.ResourceType;
-import com.android.util.Pair;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.ViewGroup.LayoutParams;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.util.Iterator;
-
-@SuppressWarnings("deprecation")
-public final class BridgeResources extends Resources {
-
-    private BridgeContext mContext;
-    private LayoutlibCallback mLayoutlibCallback;
-    private boolean[] mPlatformResourceFlag = new boolean[1];
-    private TypedValue mTmpValue = new TypedValue();
-
-    /**
-     * Simpler wrapper around FileInputStream. This is used when the input stream represent
-     * not a normal bitmap but a nine patch.
-     * This is useful when the InputStream is created in a method but used in another that needs
-     * to know whether this is 9-patch or not, such as BitmapFactory.
-     */
-    public class NinePatchInputStream extends FileInputStream {
-        private boolean mFakeMarkSupport = true;
-        public NinePatchInputStream(File file) throws FileNotFoundException {
-            super(file);
-        }
-
-        @Override
-        public boolean markSupported() {
-            //noinspection SimplifiableIfStatement
-            if (mFakeMarkSupport) {
-                // this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
-                return true;
-            }
-
-            return super.markSupported();
-        }
-
-        public void disableFakeMarkSupport() {
-            // disable fake mark support so that in case codec actually try to use them
-            // we don't lie to them.
-            mFakeMarkSupport = false;
-        }
-    }
-
-    /**
-     * This initializes the static field {@link Resources#mSystem} which is used
-     * by methods who get global resources using {@link Resources#getSystem()}.
-     * <p/>
-     * They will end up using our bridge resources.
-     * <p/>
-     * {@link Bridge} calls this method after setting up a new bridge.
-     */
-    public static Resources initSystem(BridgeContext context,
-            AssetManager assets,
-            DisplayMetrics metrics,
-            Configuration config,
-            LayoutlibCallback layoutlibCallback) {
-        return Resources.mSystem = new BridgeResources(context,
-                assets,
-                metrics,
-                config,
-                layoutlibCallback);
-    }
-
-    /**
-     * Disposes the static {@link Resources#mSystem} to make sure we don't leave objects
-     * around that would prevent us from unloading the library.
-     */
-    public static void disposeSystem() {
-        if (Resources.mSystem instanceof BridgeResources) {
-            ((BridgeResources)(Resources.mSystem)).mContext = null;
-            ((BridgeResources)(Resources.mSystem)).mLayoutlibCallback = null;
-        }
-        Resources.mSystem = null;
-    }
-
-    private BridgeResources(BridgeContext context, AssetManager assets, DisplayMetrics metrics,
-            Configuration config, LayoutlibCallback layoutlibCallback) {
-        super(assets, metrics, config);
-        mContext = context;
-        mLayoutlibCallback = layoutlibCallback;
-    }
-
-    public BridgeTypedArray newTypeArray(int numEntries, boolean platformFile) {
-        return new BridgeTypedArray(this, mContext, numEntries, platformFile);
-    }
-
-    private Pair<String, ResourceValue> getResourceValue(int id, boolean[] platformResFlag_out) {
-        // first get the String related to this id in the framework
-        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
-
-        if (resourceInfo != null) {
-            platformResFlag_out[0] = true;
-            String attributeName = resourceInfo.getSecond();
-
-            return Pair.of(attributeName, mContext.getRenderResources().getFrameworkResource(
-                    resourceInfo.getFirst(), attributeName));
-        }
-
-        // didn't find a match in the framework? look in the project.
-        if (mLayoutlibCallback != null) {
-            resourceInfo = mLayoutlibCallback.resolveResourceId(id);
-
-            if (resourceInfo != null) {
-                platformResFlag_out[0] = false;
-                String attributeName = resourceInfo.getSecond();
-
-                return Pair.of(attributeName, mContext.getRenderResources().getProjectResource(
-                        resourceInfo.getFirst(), attributeName));
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public Drawable getDrawable(int id, Theme theme) {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            return ResourceHelper.getDrawable(value.getSecond(), mContext, theme);
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public int getColor(int id, Theme theme) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resourceValue = value.getSecond();
-            try {
-                return ResourceHelper.getColor(resourceValue.getValue());
-            } catch (NumberFormatException e) {
-                // Check if the value passed is a file. If it is, mostly likely, user is referencing
-                // a color state list from a place where they should reference only a pure color.
-                String message;
-                if (new File(resourceValue.getValue()).isFile()) {
-                    String resource = (resourceValue.isFramework() ? "@android:" : "@") + "color/"
-                      + resourceValue.getName();
-                    message = "Hexadecimal color expected, found Color State List for " + resource;
-                } else {
-                    message = e.getMessage();
-                }
-                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, message, e, null);
-                return 0;
-            }
-        }
-
-        // Suppress possible NPE. getColorStateList will never return null, it will instead
-        // throw an exception, but intelliJ can't figure that out
-        //noinspection ConstantConditions
-        return getColorStateList(id, theme).getDefaultColor();
-    }
-
-    @Override
-    public ColorStateList getColorStateList(int id, Theme theme) throws NotFoundException {
-        Pair<String, ResourceValue> resValue = getResourceValue(id, mPlatformResourceFlag);
-
-        if (resValue != null) {
-            ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
-                    mContext);
-            if (stateList != null) {
-                return stateList.obtainForTheme(theme);
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public CharSequence getText(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resValue = value.getSecond();
-
-            assert resValue != null;
-            if (resValue != null) {
-                String v = resValue.getValue();
-                if (v != null) {
-                    return v;
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public CharSequence[] getTextArray(int id) throws NotFoundException {
-        ResourceValue resValue = getArrayResourceValue(id);
-        if (resValue == null) {
-            // Error already logged by getArrayResourceValue.
-            return new CharSequence[0];
-        } else if (!(resValue instanceof ArrayResourceValue)) {
-            return new CharSequence[]{
-                    resolveReference(resValue.getValue(), resValue.isFramework())};
-        }
-        ArrayResourceValue arv = ((ArrayResourceValue) resValue);
-        return fillValues(arv, new CharSequence[arv.getElementCount()]);
-    }
-
-    @Override
-    public String[] getStringArray(int id) throws NotFoundException {
-        ResourceValue resValue = getArrayResourceValue(id);
-        if (resValue == null) {
-            // Error already logged by getArrayResourceValue.
-            return new String[0];
-        } else if (!(resValue instanceof ArrayResourceValue)) {
-            return new String[]{
-                    resolveReference(resValue.getValue(), resValue.isFramework())};
-        }
-        ArrayResourceValue arv = ((ArrayResourceValue) resValue);
-        return fillValues(arv, new String[arv.getElementCount()]);
-    }
-
-    /**
-     * Resolve each element in resValue and copy them to {@code values}. The values copied are
-     * always Strings. The ideal signature for the method should be &lt;T super String&gt;, but java
-     * generics don't support it.
-     */
-    <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) {
-        int i = 0;
-        for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
-            @SuppressWarnings("unchecked")
-            T s = (T) resolveReference(iterator.next(), resValue.isFramework());
-            values[i] = s;
-        }
-        return values;
-    }
-
-    @Override
-    public int[] getIntArray(int id) throws NotFoundException {
-        ResourceValue rv = getArrayResourceValue(id);
-        if (rv == null) {
-            // Error already logged by getArrayResourceValue.
-            return new int[0];
-        } else if (!(rv instanceof ArrayResourceValue)) {
-            // This is an older IDE that can only give us the first element of the array.
-            String firstValue = resolveReference(rv.getValue(), rv.isFramework());
-            try {
-                return new int[]{getInt(firstValue)};
-            } catch (NumberFormatException e) {
-                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
-                        "Integer resource array contains non-integer value: " +
-                                firstValue, null);
-                return new int[1];
-            }
-        }
-        ArrayResourceValue resValue = ((ArrayResourceValue) rv);
-        int[] values = new int[resValue.getElementCount()];
-        int i = 0;
-        for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
-            String element = resolveReference(iterator.next(), resValue.isFramework());
-            try {
-                values[i] = getInt(element);
-            } catch (NumberFormatException e) {
-                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
-                        "Integer resource array contains non-integer value: " + element, null);
-            }
-        }
-        return values;
-    }
-
-    /**
-     * Try to find the ArrayResourceValue for the given id.
-     * <p/>
-     * If the ResourceValue found is not of type {@link ResourceType#ARRAY}, the method logs an
-     * error and return null. However, if the ResourceValue found has type {@code
-     * ResourceType.ARRAY}, but the value is not an instance of {@link ArrayResourceValue}, the
-     * method returns the ResourceValue. This happens on older versions of the IDE, which did not
-     * parse the array resources properly.
-     * <p/>
-     * @throws NotFoundException if no resource if found
-     */
-    @Nullable
-    private ResourceValue getArrayResourceValue(int id) throws NotFoundException {
-        Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
-
-        if (v != null) {
-            ResourceValue resValue = v.getSecond();
-
-            assert resValue != null;
-            if (resValue != null) {
-                final ResourceType type = resValue.getResourceType();
-                if (type != ResourceType.ARRAY) {
-                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
-                            String.format(
-                                    "Resource with id 0x%1$X is not an array resource, but %2$s",
-                                    id, type == null ? "null" : type.getDisplayName()),
-                            null);
-                    return null;
-                }
-                if (!(resValue instanceof ArrayResourceValue)) {
-                    Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED,
-                            "Obtaining resource arrays via getTextArray, getStringArray or getIntArray is not fully supported in this version of the IDE.",
-                            null);
-                }
-                return resValue;
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @NonNull
-    private String resolveReference(@NonNull String ref, boolean forceFrameworkOnly) {
-        if (ref.startsWith(SdkConstants.PREFIX_RESOURCE_REF) || ref.startsWith
-                (SdkConstants.PREFIX_THEME_REF)) {
-            ResourceValue rv =
-                    mContext.getRenderResources().findResValue(ref, forceFrameworkOnly);
-            rv = mContext.getRenderResources().resolveResValue(rv);
-            if (rv != null) {
-                return rv.getValue();
-            } else {
-                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
-                        "Unable to resolve resource " + ref, null);
-            }
-        }
-        // Not a reference.
-        return ref;
-    }
-
-    @Override
-    public XmlResourceParser getLayout(int id) throws NotFoundException {
-        Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
-
-        if (v != null) {
-            ResourceValue value = v.getSecond();
-            XmlPullParser parser = null;
-
-            try {
-                // check if the current parser can provide us with a custom parser.
-                if (mPlatformResourceFlag[0] == false) {
-                    parser = mLayoutlibCallback.getParser(value);
-                }
-
-                // create a new one manually if needed.
-                if (parser == null) {
-                    File xml = new File(value.getValue());
-                    if (xml.isFile()) {
-                        // we need to create a pull parser around the layout XML file, and then
-                        // give that to our XmlBlockParser
-                        parser = ParserFactory.create(xml, true);
-                    }
-                }
-
-                if (parser != null) {
-                    return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
-                }
-            } catch (XmlPullParserException e) {
-                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to configure parser for " + value.getValue(), e, null /*data*/);
-                // we'll return null below.
-            } catch (FileNotFoundException e) {
-                // this shouldn't happen since we check above.
-            }
-
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public XmlResourceParser getAnimation(int id) throws NotFoundException {
-        Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
-
-        if (v != null) {
-            ResourceValue value = v.getSecond();
-            XmlPullParser parser = null;
-
-            try {
-                File xml = new File(value.getValue());
-                if (xml.isFile()) {
-                    // we need to create a pull parser around the layout XML file, and then
-                    // give that to our XmlBlockParser
-                    parser = ParserFactory.create(xml);
-
-                    return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
-                }
-            } catch (XmlPullParserException e) {
-                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to configure parser for " + value.getValue(), e, null /*data*/);
-                // we'll return null below.
-            } catch (FileNotFoundException e) {
-                // this shouldn't happen since we check above.
-            }
-
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
-        return mContext.obtainStyledAttributes(set, attrs);
-    }
-
-    @Override
-    public TypedArray obtainTypedArray(int id) throws NotFoundException {
-        throw new UnsupportedOperationException();
-    }
-
-
-    @Override
-    public float getDimension(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resValue = value.getSecond();
-
-            assert resValue != null;
-            if (resValue != null) {
-                String v = resValue.getValue();
-                if (v != null) {
-                    if (v.equals(BridgeConstants.MATCH_PARENT) ||
-                            v.equals(BridgeConstants.FILL_PARENT)) {
-                        return LayoutParams.MATCH_PARENT;
-                    } else if (v.equals(BridgeConstants.WRAP_CONTENT)) {
-                        return LayoutParams.WRAP_CONTENT;
-                    }
-
-                    if (ResourceHelper.parseFloatAttribute(
-                            value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
-                            mTmpValue.type == TypedValue.TYPE_DIMENSION) {
-                        return mTmpValue.getDimension(getDisplayMetrics());
-                    }
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return 0;
-    }
-
-    @Override
-    public int getDimensionPixelOffset(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resValue = value.getSecond();
-
-            assert resValue != null;
-            if (resValue != null) {
-                String v = resValue.getValue();
-                if (v != null) {
-                    if (ResourceHelper.parseFloatAttribute(
-                            value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
-                            mTmpValue.type == TypedValue.TYPE_DIMENSION) {
-                        return TypedValue.complexToDimensionPixelOffset(mTmpValue.data,
-                                getDisplayMetrics());
-                    }
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return 0;
-    }
-
-    @Override
-    public int getDimensionPixelSize(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resValue = value.getSecond();
-
-            assert resValue != null;
-            if (resValue != null) {
-                String v = resValue.getValue();
-                if (v != null) {
-                    if (ResourceHelper.parseFloatAttribute(
-                            value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
-                            mTmpValue.type == TypedValue.TYPE_DIMENSION) {
-                        return TypedValue.complexToDimensionPixelSize(mTmpValue.data,
-                                getDisplayMetrics());
-                    }
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return 0;
-    }
-
-    @Override
-    public int getInteger(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resValue = value.getSecond();
-
-            assert resValue != null;
-            if (resValue != null) {
-                String v = resValue.getValue();
-                if (v != null) {
-                    try {
-                        return getInt(v);
-                    } catch (NumberFormatException e) {
-                        // return exception below
-                    }
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return 0;
-    }
-
-    @Override
-    public boolean getBoolean(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resValue = value.getSecond();
-
-            if (resValue != null) {
-                String v = resValue.getValue();
-                if (v != null) {
-                    return Boolean.parseBoolean(v);
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return false;
-    }
-
-    @Override
-    public String getResourceEntryName(int resid) throws NotFoundException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getResourceName(int resid) throws NotFoundException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getResourceTypeName(int resid) throws NotFoundException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getString(int id, Object... formatArgs) throws NotFoundException {
-        String s = getString(id);
-        if (s != null) {
-            return String.format(s, formatArgs);
-
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public String getString(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null && value.getSecond().getValue() != null) {
-            return value.getSecond().getValue();
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public void getValue(int id, TypedValue outValue, boolean resolveRefs)
-            throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            ResourceValue resVal = value.getSecond();
-            String v = resVal.getValue();
-
-            if (v != null) {
-                if (ResourceHelper.parseFloatAttribute(value.getFirst(), v, outValue,
-                        false /*requireUnit*/)) {
-                    return;
-                }
-                if (resVal instanceof DensityBasedResourceValue) {
-                    outValue.density =
-                      ((DensityBasedResourceValue) resVal).getResourceDensity().getDpiValue();
-                }
-
-                // else it's a string
-                outValue.type = TypedValue.TYPE_STRING;
-                outValue.string = v;
-                return;
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-    }
-
-    @Override
-    public void getValue(String name, TypedValue outValue, boolean resolveRefs)
-            throws NotFoundException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public XmlResourceParser getXml(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            String v = value.getSecond().getValue();
-
-            if (v != null) {
-                // check this is a file
-                File f = new File(v);
-                if (f.isFile()) {
-                    try {
-                        XmlPullParser parser = ParserFactory.create(f);
-
-                        return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
-                    } catch (XmlPullParserException e) {
-                        NotFoundException newE = new NotFoundException();
-                        newE.initCause(e);
-                        throw newE;
-                    } catch (FileNotFoundException e) {
-                        NotFoundException newE = new NotFoundException();
-                        newE.initCause(e);
-                        throw newE;
-                    }
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public XmlResourceParser loadXmlResourceParser(String file, int id,
-            int assetCookie, String type) throws NotFoundException {
-        // even though we know the XML file to load directly, we still need to resolve the
-        // id so that we can know if it's a platform or project resource.
-        // (mPlatformResouceFlag will get the result and will be used later).
-        getResourceValue(id, mPlatformResourceFlag);
-
-        File f = new File(file);
-        try {
-            XmlPullParser parser = ParserFactory.create(f);
-
-            return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
-        } catch (XmlPullParserException e) {
-            NotFoundException newE = new NotFoundException();
-            newE.initCause(e);
-            throw newE;
-        } catch (FileNotFoundException e) {
-            NotFoundException newE = new NotFoundException();
-            newE.initCause(e);
-            throw newE;
-        }
-    }
-
-    @Override
-    public InputStream openRawResource(int id) throws NotFoundException {
-        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
-
-        if (value != null) {
-            String path = value.getSecond().getValue();
-
-            if (path != null) {
-                // check this is a file
-                File f = new File(path);
-                if (f.isFile()) {
-                    try {
-                        // if it's a nine-patch return a custom input stream so that
-                        // other methods (mainly bitmap factory) can detect it's a 9-patch
-                        // and actually load it as a 9-patch instead of a normal bitmap
-                        if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
-                            return new NinePatchInputStream(f);
-                        }
-                        return new FileInputStream(f);
-                    } catch (FileNotFoundException e) {
-                        NotFoundException newE = new NotFoundException();
-                        newE.initCause(e);
-                        throw newE;
-                    }
-                }
-            }
-        }
-
-        // id was not found or not resolved. Throw a NotFoundException.
-        throwException(id);
-
-        // this is not used since the method above always throws
-        return null;
-    }
-
-    @Override
-    public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
-        getValue(id, value, true);
-
-        String path = value.string.toString();
-
-        File f = new File(path);
-        if (f.isFile()) {
-            try {
-                // if it's a nine-patch return a custom input stream so that
-                // other methods (mainly bitmap factory) can detect it's a 9-patch
-                // and actually load it as a 9-patch instead of a normal bitmap
-                if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
-                    return new NinePatchInputStream(f);
-                }
-                return new FileInputStream(f);
-            } catch (FileNotFoundException e) {
-                NotFoundException exception = new NotFoundException();
-                exception.initCause(e);
-                throw exception;
-            }
-        }
-
-        throw new NotFoundException();
-    }
-
-    @Override
-    public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Builds and throws a {@link Resources.NotFoundException} based on a resource id and a resource type.
-     * @param id the id of the resource
-     * @throws NotFoundException
-     */
-    private void throwException(int id) throws NotFoundException {
-        // first get the String related to this id in the framework
-        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
-
-        // if the name is unknown in the framework, get it from the custom view loader.
-        if (resourceInfo == null && mLayoutlibCallback != null) {
-            resourceInfo = mLayoutlibCallback.resolveResourceId(id);
-        }
-
-        String message;
-        if (resourceInfo != null) {
-            message = String.format(
-                    "Could not find %1$s resource matching value 0x%2$X (resolved name: %3$s) in current configuration.",
-                    resourceInfo.getFirst(), id, resourceInfo.getSecond());
-        } else {
-            message = String.format(
-                    "Could not resolve resource value: 0x%1$X.", id);
-        }
-
-        throw new NotFoundException(message);
-    }
-
-    private int getInt(String v) throws NumberFormatException {
-        int radix = 10;
-        if (v.startsWith("0x")) {
-            v = v.substring(2);
-            radix = 16;
-        } else if (v.startsWith("0")) {
-            radix = 8;
-        }
-        return Integer.parseInt(v, radix);
-    }
-}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index db4c6dc6..d0e431a 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -25,14 +25,9 @@
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.resources.ResourceType;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.Nullable;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
@@ -42,7 +37,6 @@
 import android.view.LayoutInflater_Delegate;
 import android.view.ViewGroup.LayoutParams;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Map;
@@ -71,7 +65,7 @@
  */
 public final class BridgeTypedArray extends TypedArray {
 
-    private final BridgeResources mBridgeResources;
+    private final Resources mBridgeResources;
     private final BridgeContext mContext;
     private final boolean mPlatformFile;
 
@@ -84,7 +78,7 @@
     @Nullable
     private int[] mEmptyIds;
 
-    public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
+    public BridgeTypedArray(Resources resources, BridgeContext context, int len,
             boolean platformFile) {
         super(resources, null, null, 0);
         mBridgeResources = resources;
@@ -305,71 +299,22 @@
         return defValue;
     }
 
-    /**
-     * Retrieve the ColorStateList for the attribute at <var>index</var>.
-     * The value may be either a single solid color or a reference to
-     * a color or complex {@link android.content.res.ColorStateList} description.
-     *
-     * @param index Index of attribute to retrieve.
-     *
-     * @return ColorStateList for the attribute, or null if not defined.
-     */
     @Override
     public ColorStateList getColorStateList(int index) {
         if (!hasValue(index)) {
             return null;
         }
 
-        ResourceValue resValue = mResourceData[index];
-        String value = resValue.getValue();
+        return ResourceHelper.getColorStateList(mResourceData[index], mContext);
+    }
 
-        if (value == null) {
+    @Override
+    public ComplexColor getComplexColor(int index) {
+        if (!hasValue(index)) {
             return null;
         }
 
-
-        try {
-            // Get the state list file content from callback to parse PSI file
-            XmlPullParser parser = mContext.getLayoutlibCallback().getXmlFileParser(value);
-            if (parser == null) {
-                // If used with a version of Android Studio that does not implement getXmlFileParser
-                // fall back to reading the file from disk
-                File f = new File(value);
-                if (f.isFile()) {
-                    parser = ParserFactory.create(f);
-                }
-            }
-            if (parser != null) {
-                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
-                        parser, mContext, resValue.isFramework());
-                try {
-                    return ColorStateList.createFromXml(mContext.getResources(), blockParser,
-                            mContext.getTheme());
-                } finally {
-                    blockParser.ensurePopped();
-                }
-            }
-        } catch (XmlPullParserException e) {
-            Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                    "Failed to configure parser for " + value, e, null);
-            return null;
-        } catch (Exception e) {
-            // this is an error and not warning since the file existence is checked before
-            // attempting to parse it.
-            Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
-                    "Failed to parse file " + value, e, null);
-
-            return null;
-        }
-
-        try {
-            int color = ResourceHelper.getColor(value);
-            return ColorStateList.valueOf(color);
-        } catch (NumberFormatException e) {
-            Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null);
-        }
-
-        return null;
+        return ResourceHelper.getComplexColor(mResourceData[index], mContext);
     }
 
     /**
@@ -756,7 +701,8 @@
         if (resVal instanceof ArrayResourceValue) {
             ArrayResourceValue array = (ArrayResourceValue) resVal;
             int count = array.getElementCount();
-            return count >= 0 ? mBridgeResources.fillValues(array, new CharSequence[count]) : null;
+            return count >= 0 ? Resources_Delegate.fillValues(mBridgeResources, array, new CharSequence[count]) :
+                    null;
         }
         int id = getResourceId(index, 0);
         String resIdMessage = id > 0 ? " (resource id 0x" + Integer.toHexString(id) + ')' : "";
@@ -1004,7 +950,6 @@
     }
 
     static TypedArray obtain(Resources res, int len) {
-        return res instanceof BridgeResources ?
-                new BridgeTypedArray(((BridgeResources) res), null, len, true) : null;
+        return new BridgeTypedArray(res, null, len, true);
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/content/res/ComplexColor_Accessor.java b/tools/layoutlib/bridge/src/android/content/res/ComplexColor_Accessor.java
new file mode 100644
index 0000000..09c0260
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/ComplexColor_Accessor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.res;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.Theme;
+import android.util.AttributeSet;
+
+import java.io.IOException;
+
+/**
+ * Class that provides access to the {@link GradientColor#createFromXmlInner(Resources,
+ * XmlPullParser, AttributeSet, Theme)} and {@link ColorStateList#createFromXmlInner(Resources,
+ * XmlPullParser, AttributeSet, Theme)} methods
+ */
+public class ComplexColor_Accessor {
+    public static GradientColor createGradientColorFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws IOException, XmlPullParserException {
+        return GradientColor.createFromXmlInner(r, parser, attrs, theme);
+    }
+
+    public static ColorStateList createColorStateListFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws IOException, XmlPullParserException {
+        return ColorStateList.createFromXmlInner(r, parser, attrs, theme);
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
new file mode 100644
index 0000000..ea320c7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -0,0 +1,926 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.res;
+
+import com.android.SdkConstants;
+import com.android.ide.common.rendering.api.ArrayResourceValue;
+import com.android.ide.common.rendering.api.DensityBasedResourceValue;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.LayoutlibCallback;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.layoutlib.bridge.util.NinePatchInputStream;
+import com.android.ninepatch.NinePatch;
+import com.android.resources.ResourceType;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.android.util.Pair;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewGroup.LayoutParams;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+@SuppressWarnings("deprecation")
+public class Resources_Delegate {
+
+    private static boolean[] mPlatformResourceFlag = new boolean[1];
+
+    public static Resources initSystem(BridgeContext context,
+            AssetManager assets,
+            DisplayMetrics metrics,
+            Configuration config,
+            LayoutlibCallback layoutlibCallback) {
+        Resources resources = new Resources(assets, metrics, config);
+        resources.mContext = context;
+        resources.mLayoutlibCallback = layoutlibCallback;
+        return Resources.mSystem = resources;
+    }
+
+    /**
+     * Disposes the static {@link Resources#mSystem} to make sure we don't leave objects around that
+     * would prevent us from unloading the library.
+     */
+    public static void disposeSystem() {
+        Resources.mSystem.mContext = null;
+        Resources.mSystem.mLayoutlibCallback = null;
+        Resources.mSystem = null;
+    }
+
+    public static BridgeTypedArray newTypeArray(Resources resources, int numEntries,
+            boolean platformFile) {
+        return new BridgeTypedArray(resources, resources.mContext, numEntries, platformFile);
+    }
+
+    private static Pair<ResourceType, String> getResourceInfo(Resources resources, int id,
+            boolean[] platformResFlag_out) {
+        // first get the String related to this id in the framework
+        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
+
+        // Set the layoutlib callback and context for resources
+        if (resources != Resources.mSystem && resources.mLayoutlibCallback == null) {
+            resources.mLayoutlibCallback = Resources.mSystem.mLayoutlibCallback;
+            resources.mContext = Resources.mSystem.mContext;
+        }
+
+        if (resourceInfo != null) {
+            platformResFlag_out[0] = true;
+            return resourceInfo;
+        }
+
+        // didn't find a match in the framework? look in the project.
+        if (resources.mLayoutlibCallback != null) {
+            resourceInfo = resources.mLayoutlibCallback.resolveResourceId(id);
+
+            if (resourceInfo != null) {
+                platformResFlag_out[0] = false;
+                return resourceInfo;
+            }
+        }
+        return null;
+    }
+
+    private static Pair<String, ResourceValue> getResourceValue(Resources resources, int id,
+            boolean[] platformResFlag_out) {
+        Pair<ResourceType, String> resourceInfo =
+                getResourceInfo(resources, id, platformResFlag_out);
+
+        if (resourceInfo != null) {
+            String attributeName = resourceInfo.getSecond();
+            RenderResources renderResources = resources.mContext.getRenderResources();
+            return Pair.of(attributeName, platformResFlag_out[0] ?
+                    renderResources.getFrameworkResource(resourceInfo.getFirst(), attributeName) :
+                    renderResources.getProjectResource(resourceInfo.getFirst(), attributeName));
+        }
+
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static Drawable getDrawable(Resources resources, int id) {
+        return getDrawable(resources, id, null);
+    }
+
+    @LayoutlibDelegate
+    static Drawable getDrawable(Resources resources, int id, Theme theme) {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            return ResourceHelper.getDrawable(value.getSecond(), resources.mContext, theme);
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static int getColor(Resources resources, int id) {
+        return getColor(resources, id, null);
+    }
+
+    @LayoutlibDelegate
+    static int getColor(Resources resources, int id, Theme theme) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resourceValue = value.getSecond();
+            try {
+                return ResourceHelper.getColor(resourceValue.getValue());
+            } catch (NumberFormatException e) {
+                // Check if the value passed is a file. If it is, mostly likely, user is referencing
+                // a color state list from a place where they should reference only a pure color.
+                String message;
+                if (new File(resourceValue.getValue()).isFile()) {
+                    String resource = (resourceValue.isFramework() ? "@android:" : "@") + "color/"
+                            + resourceValue.getName();
+                    message = "Hexadecimal color expected, found Color State List for " + resource;
+                } else {
+                    message = e.getMessage();
+                }
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, message, e, null);
+                return 0;
+            }
+        }
+
+        // Suppress possible NPE. getColorStateList will never return null, it will instead
+        // throw an exception, but intelliJ can't figure that out
+        //noinspection ConstantConditions
+        return getColorStateList(resources, id, theme).getDefaultColor();
+    }
+
+    @LayoutlibDelegate
+    static ColorStateList getColorStateList(Resources resources, int id) throws NotFoundException {
+        return getColorStateList(resources, id, null);
+    }
+
+    @LayoutlibDelegate
+    static ColorStateList getColorStateList(Resources resources, int id, Theme theme)
+            throws NotFoundException {
+        Pair<String, ResourceValue> resValue =
+                getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (resValue != null) {
+            ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
+                    resources.mContext);
+            if (stateList != null) {
+                return stateList.obtainForTheme(theme);
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static CharSequence getText(Resources resources, int id, CharSequence def) {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resValue = value.getSecond();
+
+            assert resValue != null;
+            if (resValue != null) {
+                String v = resValue.getValue();
+                if (v != null) {
+                    return v;
+                }
+            }
+        }
+
+        return def;
+    }
+
+    @LayoutlibDelegate
+    static CharSequence getText(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resValue = value.getSecond();
+
+            assert resValue != null;
+            if (resValue != null) {
+                String v = resValue.getValue();
+                if (v != null) {
+                    return v;
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static CharSequence[] getTextArray(Resources resources, int id) throws NotFoundException {
+        ResourceValue resValue = getArrayResourceValue(resources, id);
+        if (resValue == null) {
+            // Error already logged by getArrayResourceValue.
+            return new CharSequence[0];
+        } else if (!(resValue instanceof ArrayResourceValue)) {
+            return new CharSequence[]{
+                    resolveReference(resources, resValue.getValue(), resValue.isFramework())};
+        }
+        ArrayResourceValue arv = ((ArrayResourceValue) resValue);
+        return fillValues(resources, arv, new CharSequence[arv.getElementCount()]);
+    }
+
+    @LayoutlibDelegate
+    static String[] getStringArray(Resources resources, int id) throws NotFoundException {
+        ResourceValue resValue = getArrayResourceValue(resources, id);
+        if (resValue == null) {
+            // Error already logged by getArrayResourceValue.
+            return new String[0];
+        } else if (!(resValue instanceof ArrayResourceValue)) {
+            return new String[]{
+                    resolveReference(resources, resValue.getValue(), resValue.isFramework())};
+        }
+        ArrayResourceValue arv = ((ArrayResourceValue) resValue);
+        return fillValues(resources, arv, new String[arv.getElementCount()]);
+    }
+
+    /**
+     * Resolve each element in resValue and copy them to {@code values}. The values copied are
+     * always Strings. The ideal signature for the method should be &lt;T super String&gt;, but java
+     * generics don't support it.
+     */
+    static <T extends CharSequence> T[] fillValues(Resources resources, ArrayResourceValue resValue,
+            T[] values) {
+        int i = 0;
+        for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
+            @SuppressWarnings("unchecked")
+            T s = (T) resolveReference(resources, iterator.next(), resValue.isFramework());
+            values[i] = s;
+        }
+        return values;
+    }
+
+    @LayoutlibDelegate
+    static int[] getIntArray(Resources resources, int id) throws NotFoundException {
+        ResourceValue rv = getArrayResourceValue(resources, id);
+        if (rv == null) {
+            // Error already logged by getArrayResourceValue.
+            return new int[0];
+        } else if (!(rv instanceof ArrayResourceValue)) {
+            // This is an older IDE that can only give us the first element of the array.
+            String firstValue = resolveReference(resources, rv.getValue(), rv.isFramework());
+            try {
+                return new int[]{getInt(firstValue)};
+            } catch (NumberFormatException e) {
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+                        "Integer resource array contains non-integer value: " +
+                                firstValue, null);
+                return new int[1];
+            }
+        }
+        ArrayResourceValue resValue = ((ArrayResourceValue) rv);
+        int[] values = new int[resValue.getElementCount()];
+        int i = 0;
+        for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
+            String element = resolveReference(resources, iterator.next(), resValue.isFramework());
+            try {
+                values[i] = getInt(element);
+            } catch (NumberFormatException e) {
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+                        "Integer resource array contains non-integer value: " + element, null);
+            }
+        }
+        return values;
+    }
+
+    /**
+     * Try to find the ArrayResourceValue for the given id.
+     * <p/>
+     * If the ResourceValue found is not of type {@link ResourceType#ARRAY}, the method logs an
+     * error and return null. However, if the ResourceValue found has type {@code
+     * ResourceType.ARRAY}, but the value is not an instance of {@link ArrayResourceValue}, the
+     * method returns the ResourceValue. This happens on older versions of the IDE, which did not
+     * parse the array resources properly.
+     * <p/>
+     *
+     * @throws NotFoundException if no resource if found
+     */
+    @Nullable
+    private static ResourceValue getArrayResourceValue(Resources resources, int id)
+            throws NotFoundException {
+        Pair<String, ResourceValue> v = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (v != null) {
+            ResourceValue resValue = v.getSecond();
+
+            assert resValue != null;
+            if (resValue != null) {
+                final ResourceType type = resValue.getResourceType();
+                if (type != ResourceType.ARRAY) {
+                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
+                            String.format(
+                                    "Resource with id 0x%1$X is not an array resource, but %2$s",
+                                    id, type == null ? "null" : type.getDisplayName()),
+                            null);
+                    return null;
+                }
+                if (!(resValue instanceof ArrayResourceValue)) {
+                    Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED,
+                            "Obtaining resource arrays via getTextArray, getStringArray or getIntArray is not fully supported in this version of the IDE.",
+                            null);
+                }
+                return resValue;
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @NonNull
+    private static String resolveReference(Resources resources, @NonNull String ref,
+            boolean forceFrameworkOnly) {
+        if (ref.startsWith(SdkConstants.PREFIX_RESOURCE_REF) || ref.startsWith
+                (SdkConstants.PREFIX_THEME_REF)) {
+            ResourceValue rv =
+                    resources.mContext.getRenderResources().findResValue(ref, forceFrameworkOnly);
+            rv = resources.mContext.getRenderResources().resolveResValue(rv);
+            if (rv != null) {
+                return rv.getValue();
+            } else {
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
+                        "Unable to resolve resource " + ref, null);
+            }
+        }
+        // Not a reference.
+        return ref;
+    }
+
+    @LayoutlibDelegate
+    static XmlResourceParser getLayout(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> v = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (v != null) {
+            ResourceValue value = v.getSecond();
+            XmlPullParser parser = null;
+
+            try {
+                // check if the current parser can provide us with a custom parser.
+                if (!mPlatformResourceFlag[0]) {
+                    parser = resources.mLayoutlibCallback.getParser(value);
+                }
+
+                // create a new one manually if needed.
+                if (parser == null) {
+                    File xml = new File(value.getValue());
+                    if (xml.isFile()) {
+                        // we need to create a pull parser around the layout XML file, and then
+                        // give that to our XmlBlockParser
+                        parser = ParserFactory.create(xml, true);
+                    }
+                }
+
+                if (parser != null) {
+                    return new BridgeXmlBlockParser(parser, resources.mContext,
+                            mPlatformResourceFlag[0]);
+                }
+            } catch (XmlPullParserException e) {
+                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                        "Failed to configure parser for " + value.getValue(), e, null /*data*/);
+                // we'll return null below.
+            } catch (FileNotFoundException e) {
+                // this shouldn't happen since we check above.
+            }
+
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static XmlResourceParser getAnimation(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> v = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (v != null) {
+            ResourceValue value = v.getSecond();
+            XmlPullParser parser;
+
+            try {
+                File xml = new File(value.getValue());
+                if (xml.isFile()) {
+                    // we need to create a pull parser around the layout XML file, and then
+                    // give that to our XmlBlockParser
+                    parser = ParserFactory.create(xml);
+
+                    return new BridgeXmlBlockParser(parser, resources.mContext,
+                            mPlatformResourceFlag[0]);
+                }
+            } catch (XmlPullParserException e) {
+                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                        "Failed to configure parser for " + value.getValue(), e, null /*data*/);
+                // we'll return null below.
+            } catch (FileNotFoundException e) {
+                // this shouldn't happen since we check above.
+            }
+
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static TypedArray obtainAttributes(Resources resources, AttributeSet set, int[] attrs) {
+        return resources.mContext.obtainStyledAttributes(set, attrs);
+    }
+
+    @LayoutlibDelegate
+    static TypedArray obtainAttributes(Resources resources, Resources.Theme theme, AttributeSet
+            set, int[] attrs) {
+        return Resources.obtainAttributes_Original(resources, theme, set, attrs);
+    }
+
+    @LayoutlibDelegate
+    static TypedArray obtainTypedArray(Resources resources, int id) throws NotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @LayoutlibDelegate
+    static float getDimension(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resValue = value.getSecond();
+
+            assert resValue != null;
+            if (resValue != null) {
+                String v = resValue.getValue();
+                if (v != null) {
+                    if (v.equals(BridgeConstants.MATCH_PARENT) ||
+                            v.equals(BridgeConstants.FILL_PARENT)) {
+                        return LayoutParams.MATCH_PARENT;
+                    } else if (v.equals(BridgeConstants.WRAP_CONTENT)) {
+                        return LayoutParams.WRAP_CONTENT;
+                    }
+                    TypedValue tmpValue = new TypedValue();
+                    if (ResourceHelper.parseFloatAttribute(
+                            value.getFirst(), v, tmpValue, true /*requireUnit*/) &&
+                            tmpValue.type == TypedValue.TYPE_DIMENSION) {
+                        return tmpValue.getDimension(resources.getDisplayMetrics());
+                    }
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return 0;
+    }
+
+    @LayoutlibDelegate
+    static int getDimensionPixelOffset(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resValue = value.getSecond();
+
+            assert resValue != null;
+            if (resValue != null) {
+                String v = resValue.getValue();
+                if (v != null) {
+                    TypedValue tmpValue = new TypedValue();
+                    if (ResourceHelper.parseFloatAttribute(
+                            value.getFirst(), v, tmpValue, true /*requireUnit*/) &&
+                            tmpValue.type == TypedValue.TYPE_DIMENSION) {
+                        return TypedValue.complexToDimensionPixelOffset(tmpValue.data,
+                                resources.getDisplayMetrics());
+                    }
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return 0;
+    }
+
+    @LayoutlibDelegate
+    static int getDimensionPixelSize(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resValue = value.getSecond();
+
+            assert resValue != null;
+            if (resValue != null) {
+                String v = resValue.getValue();
+                if (v != null) {
+                    TypedValue tmpValue = new TypedValue();
+                    if (ResourceHelper.parseFloatAttribute(
+                            value.getFirst(), v, tmpValue, true /*requireUnit*/) &&
+                            tmpValue.type == TypedValue.TYPE_DIMENSION) {
+                        return TypedValue.complexToDimensionPixelSize(tmpValue.data,
+                                resources.getDisplayMetrics());
+                    }
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return 0;
+    }
+
+    @LayoutlibDelegate
+    static int getInteger(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resValue = value.getSecond();
+
+            assert resValue != null;
+            if (resValue != null) {
+                String v = resValue.getValue();
+                if (v != null) {
+                    try {
+                        return getInt(v);
+                    } catch (NumberFormatException e) {
+                        // return exception below
+                    }
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return 0;
+    }
+
+    @LayoutlibDelegate
+    static boolean getBoolean(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resValue = value.getSecond();
+
+            if (resValue != null) {
+                String v = resValue.getValue();
+                if (v != null) {
+                    return Boolean.parseBoolean(v);
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return false;
+    }
+
+    @LayoutlibDelegate
+    static String getResourceEntryName(Resources resources, int resid) throws NotFoundException {
+        Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, new boolean[1]);
+        if (resourceInfo != null) {
+            return resourceInfo.getSecond();
+        }
+        throwException(resid, null);
+        return null;
+
+    }
+
+    @LayoutlibDelegate
+    static String getResourceName(Resources resources, int resid) throws NotFoundException {
+        boolean[] platformOut = new boolean[1];
+        Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut);
+        String packageName;
+        if (resourceInfo != null) {
+            if (platformOut[0]) {
+                packageName = SdkConstants.ANDROID_NS_NAME;
+            } else {
+                packageName = resources.mContext.getPackageName();
+                packageName = packageName == null ? SdkConstants.APP_PREFIX : packageName;
+            }
+            return packageName + ':' + resourceInfo.getFirst().getName() + '/' +
+                    resourceInfo.getSecond();
+        }
+        throwException(resid, null);
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static String getResourcePackageName(Resources resources, int resid) throws NotFoundException {
+        boolean[] platformOut = new boolean[1];
+        Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut);
+        if (resourceInfo != null) {
+            if (platformOut[0]) {
+                return SdkConstants.ANDROID_NS_NAME;
+            }
+            String packageName = resources.mContext.getPackageName();
+            return packageName == null ? SdkConstants.APP_PREFIX : packageName;
+        }
+        throwException(resid, null);
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static String getResourceTypeName(Resources resources, int resid) throws NotFoundException {
+        Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, new boolean[1]);
+        if (resourceInfo != null) {
+            return resourceInfo.getFirst().getName();
+        }
+        throwException(resid, null);
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static String getString(Resources resources, int id, Object... formatArgs)
+            throws NotFoundException {
+        String s = getString(resources, id);
+        if (s != null) {
+            return String.format(s, formatArgs);
+
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static String getString(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null && value.getSecond().getValue() != null) {
+            return value.getSecond().getValue();
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static void getValue(Resources resources, int id, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            ResourceValue resVal = value.getSecond();
+            String v = resVal.getValue();
+
+            if (v != null) {
+                if (ResourceHelper.parseFloatAttribute(value.getFirst(), v, outValue,
+                        false /*requireUnit*/)) {
+                    return;
+                }
+                if (resVal instanceof DensityBasedResourceValue) {
+                    outValue.density =
+                            ((DensityBasedResourceValue) resVal).getResourceDensity().getDpiValue();
+                }
+
+                // else it's a string
+                outValue.type = TypedValue.TYPE_STRING;
+                outValue.string = v;
+                return;
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+    }
+
+    @LayoutlibDelegate
+    static void getValue(Resources resources, String name, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @LayoutlibDelegate
+    static XmlResourceParser getXml(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            String v = value.getSecond().getValue();
+
+            if (v != null) {
+                // check this is a file
+                File f = new File(v);
+                if (f.isFile()) {
+                    try {
+                        XmlPullParser parser = ParserFactory.create(f);
+
+                        return new BridgeXmlBlockParser(parser, resources.mContext,
+                                mPlatformResourceFlag[0]);
+                    } catch (XmlPullParserException e) {
+                        NotFoundException newE = new NotFoundException();
+                        newE.initCause(e);
+                        throw newE;
+                    } catch (FileNotFoundException e) {
+                        NotFoundException newE = new NotFoundException();
+                        newE.initCause(e);
+                        throw newE;
+                    }
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static XmlResourceParser loadXmlResourceParser(Resources resources, int id,
+            String type) throws NotFoundException {
+        return resources.loadXmlResourceParser_Original(id, type);
+    }
+
+    @LayoutlibDelegate
+    static XmlResourceParser loadXmlResourceParser(Resources resources, String file, int id,
+            int assetCookie, String type) throws NotFoundException {
+        // even though we know the XML file to load directly, we still need to resolve the
+        // id so that we can know if it's a platform or project resource.
+        // (mPlatformResouceFlag will get the result and will be used later).
+        getResourceValue(resources, id, mPlatformResourceFlag);
+
+        File f = new File(file);
+        try {
+            XmlPullParser parser = ParserFactory.create(f);
+
+            return new BridgeXmlBlockParser(parser, resources.mContext, mPlatformResourceFlag[0]);
+        } catch (XmlPullParserException e) {
+            NotFoundException newE = new NotFoundException();
+            newE.initCause(e);
+            throw newE;
+        } catch (FileNotFoundException e) {
+            NotFoundException newE = new NotFoundException();
+            newE.initCause(e);
+            throw newE;
+        }
+    }
+
+    @LayoutlibDelegate
+    static InputStream openRawResource(Resources resources, int id) throws NotFoundException {
+        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+        if (value != null) {
+            String path = value.getSecond().getValue();
+
+            if (path != null) {
+                // check this is a file
+                File f = new File(path);
+                if (f.isFile()) {
+                    try {
+                        // if it's a nine-patch return a custom input stream so that
+                        // other methods (mainly bitmap factory) can detect it's a 9-patch
+                        // and actually load it as a 9-patch instead of a normal bitmap
+                        if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
+                            return new NinePatchInputStream(f);
+                        }
+                        return new FileInputStream(f);
+                    } catch (FileNotFoundException e) {
+                        NotFoundException newE = new NotFoundException();
+                        newE.initCause(e);
+                        throw newE;
+                    }
+                }
+            }
+        }
+
+        // id was not found or not resolved. Throw a NotFoundException.
+        throwException(resources, id);
+
+        // this is not used since the method above always throws
+        return null;
+    }
+
+    @LayoutlibDelegate
+    static InputStream openRawResource(Resources resources, int id, TypedValue value) throws
+            NotFoundException {
+        getValue(resources, id, value, true);
+
+        String path = value.string.toString();
+
+        File f = new File(path);
+        if (f.isFile()) {
+            try {
+                // if it's a nine-patch return a custom input stream so that
+                // other methods (mainly bitmap factory) can detect it's a 9-patch
+                // and actually load it as a 9-patch instead of a normal bitmap
+                if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
+                    return new NinePatchInputStream(f);
+                }
+                return new FileInputStream(f);
+            } catch (FileNotFoundException e) {
+                NotFoundException exception = new NotFoundException();
+                exception.initCause(e);
+                throw exception;
+            }
+        }
+
+        throw new NotFoundException();
+    }
+
+    @LayoutlibDelegate
+    static AssetFileDescriptor openRawResourceFd(Resources resources, int id) throws
+            NotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Builds and throws a {@link Resources.NotFoundException} based on a resource id and a resource
+     * type.
+     *
+     * @param id the id of the resource
+     *
+     * @throws NotFoundException
+     */
+    private static void throwException(Resources resources, int id) throws NotFoundException {
+        throwException(id, getResourceInfo(resources, id, new boolean[1]));
+    }
+
+    private static void throwException(int id, @Nullable Pair<ResourceType, String> resourceInfo) {
+        String message;
+        if (resourceInfo != null) {
+            message = String.format(
+                    "Could not find %1$s resource matching value 0x%2$X (resolved name: %3$s) in current configuration.",
+                    resourceInfo.getFirst(), id, resourceInfo.getSecond());
+        } else {
+            message = String.format("Could not resolve resource value: 0x%1$X.", id);
+        }
+
+        throw new NotFoundException(message);
+    }
+
+    private static int getInt(String v) throws NumberFormatException {
+        int radix = 10;
+        if (v.startsWith("0x")) {
+            v = v.substring(2);
+            radix = 16;
+        } else if (v.startsWith("0")) {
+            radix = 8;
+        }
+        return Integer.parseInt(v, radix);
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
deleted file mode 100644
index 34ae825..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
+++ /dev/null
@@ -1,70 +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.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Composite;
-
-/**
- * Delegate implementing the native methods of android.graphics.AvoidXfermode
- *
- * Through the layoutlib_create tool, the original native methods of AvoidXfermode have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original AvoidXfermode class.
- *
- * Because this extends {@link Xfermode_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
- * {@link Xfermode_Delegate}.
- *
- */
-public class AvoidXfermode_Delegate extends Xfermode_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Composite getComposite(int alpha) {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Avoid Xfermodes are not supported in Layout Preview mode.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(int opColor, int tolerance, int nativeMode) {
-        AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 8d5863b..8bd2a7a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -23,7 +23,7 @@
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.annotation.Nullable;
-import android.content.res.BridgeResources.NinePatchInputStream;
+import com.android.layoutlib.bridge.util.NinePatchInputStream;
 import android.graphics.BitmapFactory.Options;
 import android.graphics.Bitmap_Delegate.BitmapCreateFlags;
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index e3bb3e3..6d8ecd7 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -67,7 +67,7 @@
 
     // ---- delegate manager ----
     private static final DelegateManager<Bitmap_Delegate> sManager =
-            new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
+            new DelegateManager<>(Bitmap_Delegate.class);
     private static long sFinalizer = -1;
 
     // ---- delegate helper data ----
@@ -314,7 +314,7 @@
 
     @LayoutlibDelegate
     /*package*/ static boolean nativeRecycle(long nativeBitmap) {
-        sManager.removeJavaReferenceFor(nativeBitmap);
+        // In our case reycle() is a no-op. We will let the finalizer to dispose the bitmap.
         return true;
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index c4fbd56..fa880f0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -142,7 +142,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setBitmap(long canvas, Bitmap bitmap) {
+    public static void native_setBitmap(long canvas, Bitmap bitmap) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
         if (canvasDelegate == null || bitmapDelegate==null) {
@@ -153,7 +153,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_isOpaque(long nativeCanvas) {
+    public static boolean native_isOpaque(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -164,10 +164,10 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
+    public static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
 
     @LayoutlibDelegate
-    /*package*/ static int native_getWidth(long nativeCanvas) {
+    public static int native_getWidth(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -178,7 +178,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_getHeight(long nativeCanvas) {
+    public static int native_getHeight(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -189,7 +189,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_save(long nativeCanvas, int saveFlags) {
+    public static int native_save(long nativeCanvas, int saveFlags) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -200,7 +200,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_saveLayer(long nativeCanvas, float l,
+    public static int native_saveLayer(long nativeCanvas, float l,
                                                float t, float r, float b,
                                                long paint, int layerFlags) {
         // get the delegate from the native int.
@@ -219,7 +219,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l,
+    public static int native_saveLayerAlpha(long nativeCanvas, float l,
                                                     float t, float r, float b,
                                                     int alpha, int layerFlags) {
         // get the delegate from the native int.
@@ -232,7 +232,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
+    public static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
         // FIXME: implement throwOnUnderflow.
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -244,7 +244,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount,
+    public static void native_restoreToCount(long nativeCanvas, int saveCount,
             boolean throwOnUnderflow) {
         // FIXME: implement throwOnUnderflow.
         // get the delegate from the native int.
@@ -257,7 +257,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_getSaveCount(long nativeCanvas) {
+    public static int native_getSaveCount(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -268,7 +268,7 @@
     }
 
     @LayoutlibDelegate
-   /*package*/ static void native_translate(long nativeCanvas, float dx, float dy) {
+   public static void native_translate(long nativeCanvas, float dx, float dy) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -279,7 +279,7 @@
     }
 
     @LayoutlibDelegate
-       /*package*/ static void native_scale(long nativeCanvas, float sx, float sy) {
+       public static void native_scale(long nativeCanvas, float sx, float sy) {
             // get the delegate from the native int.
             Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
             if (canvasDelegate == null) {
@@ -290,7 +290,7 @@
         }
 
     @LayoutlibDelegate
-    /*package*/ static void native_rotate(long nativeCanvas, float degrees) {
+    public static void native_rotate(long nativeCanvas, float degrees) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -301,7 +301,7 @@
     }
 
     @LayoutlibDelegate
-   /*package*/ static void native_skew(long nativeCanvas, float kx, float ky) {
+   public static void native_skew(long nativeCanvas, float kx, float ky) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -325,7 +325,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_concat(long nCanvas, long nMatrix) {
+    public static void native_concat(long nCanvas, long nMatrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
@@ -353,7 +353,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setMatrix(long nCanvas, long nMatrix) {
+    public static void native_setMatrix(long nCanvas, long nMatrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
@@ -383,7 +383,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_clipRect(long nCanvas,
+    public static boolean native_clipRect(long nCanvas,
                                                   float left, float top,
                                                   float right, float bottom,
                                                   int regionOp) {
@@ -397,7 +397,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_clipPath(long nativeCanvas,
+    public static boolean native_clipPath(long nativeCanvas,
                                                   long nativePath,
                                                   int regionOp) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -414,7 +414,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_clipRegion(long nativeCanvas,
+    public static boolean native_clipRegion(long nativeCanvas,
                                                     long nativeRegion,
                                                     int regionOp) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -431,7 +431,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
+    public static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
             return;
@@ -446,7 +446,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_getClipBounds(long nativeCanvas,
+    public static boolean native_getClipBounds(long nativeCanvas,
                                                        Rect bounds) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -467,7 +467,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_getCTM(long canvas, long matrix) {
+    public static void native_getCTM(long canvas, long matrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
         if (canvasDelegate == null) {
@@ -484,13 +484,13 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_quickReject(long nativeCanvas, long path) {
+    public static boolean native_quickReject(long nativeCanvas, long path) {
         // FIXME properly implement quickReject
         return false;
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_quickReject(long nativeCanvas,
+    public static boolean native_quickReject(long nativeCanvas,
                                                      float left, float top,
                                                      float right, float bottom) {
         // FIXME properly implement quickReject
@@ -498,7 +498,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawColor(long nativeCanvas, final int color, final int mode) {
+    public static void native_drawColor(long nativeCanvas, final int color, final int mode) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -529,14 +529,14 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPaint(long nativeCanvas, long paint) {
+    public static void native_drawPaint(long nativeCanvas, long paint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Canvas.drawPaint is not supported.", null, null /*data*/);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPoint(long nativeCanvas, float x, float y,
+    public static void native_drawPoint(long nativeCanvas, float x, float y,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -544,7 +544,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
+    public static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -552,7 +552,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawLine(long nativeCanvas,
+    public static void native_drawLine(long nativeCanvas,
             final float startX, final float startY, final float stopX, final float stopY,
             long paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -565,7 +565,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawLines(long nativeCanvas,
+    public static void native_drawLines(long nativeCanvas,
             final float[] pts, final int offset, final int count,
             long nativePaint) {
         draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
@@ -581,7 +581,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawRect(long nativeCanvas,
+    public static void native_drawRect(long nativeCanvas,
             final float left, final float top, final float right, final float bottom, long paint) {
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -607,7 +607,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawOval(long nativeCanvas, final float left,
+    public static void native_drawOval(long nativeCanvas, final float left,
             final float top, final float right, final float bottom, long paint) {
         if (right > left && bottom > top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -634,7 +634,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawCircle(long nativeCanvas,
+    public static void native_drawCircle(long nativeCanvas,
             float cx, float cy, float radius, long paint) {
         native_drawOval(nativeCanvas,
                 cx - radius, cy - radius, cx + radius, cy + radius,
@@ -642,7 +642,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawArc(long nativeCanvas,
+    public static void native_drawArc(long nativeCanvas,
             final float left, final float top, final float right, final float bottom,
             final float startAngle, final float sweep,
             final boolean useCenter, long paint) {
@@ -674,7 +674,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawRoundRect(long nativeCanvas,
+    public static void native_drawRoundRect(long nativeCanvas,
             final float left, final float top, final float right, final float bottom,
             final float rx, final float ry, long paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -704,7 +704,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPath(long nativeCanvas, long path, long paint) {
+    public static void native_drawPath(long nativeCanvas, long path, long paint) {
         final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
         if (pathDelegate == null) {
             return;
@@ -756,7 +756,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawRegion(long nativeCanvas, long nativeRegion,
+    public static void native_drawRegion(long nativeCanvas, long nativeRegion,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -764,7 +764,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
+    public static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
             long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop,
             final float dstRight, final float dstBottom, long nativePaintOrZero,
             final int screenDensity, final int bitmapDensity) {
@@ -811,7 +811,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+    public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
                                                  float left, float top,
                                                  long nativePaintOrZero,
                                                  int canvasDensity,
@@ -833,7 +833,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+    public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
                                  float srcLeft, float srcTop, float srcRight, float srcBottom,
                                  float dstLeft, float dstTop, float dstRight, float dstBottom,
                                  long nativePaintOrZero, int screenDensity, int bitmapDensity) {
@@ -849,7 +849,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawBitmap(long nativeCanvas, int[] colors,
+    public static void native_drawBitmap(long nativeCanvas, int[] colors,
                                                 int offset, int stride, final float x,
                                                  final float y, int width, int height,
                                                  boolean hasAlpha,
@@ -874,7 +874,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap,
+    public static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap,
                                                       long nMatrix, long nPaint) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
@@ -915,7 +915,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap,
+    public static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap,
             int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
             int colorOffset, long nPaint) {
         // FIXME
@@ -924,7 +924,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeDrawVertices(long nCanvas, int mode, int n,
+    public static void nativeDrawVertices(long nCanvas, int mode, int n,
             float[] verts, int vertOffset,
             float[] texs, int texOffset,
             int[] colors, int colorOffset,
@@ -936,14 +936,14 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count,
+    public static void native_drawText(long nativeCanvas, char[] text, int index, int count,
             float startX, float startY, int flags, long paint, long typeface) {
         drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0,
                 paint, typeface);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawText(long nativeCanvas, String text,
+    public static void native_drawText(long nativeCanvas, String text,
             int start, int end, float x, float y, final int flags, long paint,
             long typeface) {
         int count = end - start;
@@ -954,7 +954,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextRun(long nativeCanvas, String text,
+    public static void native_drawTextRun(long nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
             float x, float y, boolean isRtl, long paint, long typeface) {
         int count = end - start;
@@ -965,14 +965,14 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextRun(long nativeCanvas, char[] text,
+    public static void native_drawTextRun(long nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
             float x, float y, boolean isRtl, long paint, long typeface) {
         drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextOnPath(long nativeCanvas,
+    public static void native_drawTextOnPath(long nativeCanvas,
                                                      char[] text, int index,
                                                      int count, long path,
                                                      float hOffset,
@@ -984,7 +984,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextOnPath(long nativeCanvas,
+    public static void native_drawTextOnPath(long nativeCanvas,
                                                      String text, long path,
                                                      float hOffset,
                                                      float vOffset,
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 746ef36..7412bc2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -284,9 +284,9 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nAddFontWeightStyle(long nativeFamily,
-            ByteBuffer buffer, final List<FontListParser.Axis> axes,
-            final int weight, final boolean isItalic) {
+    /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+            int ttcIndex, List<FontListParser.Axis> listOfAxis,
+            int weight, boolean isItalic) {
         assert false : "The only client of this method has been overriden.";
         return false;
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 514d785..33296e1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -223,6 +223,14 @@
         return mColorFilter;
     }
 
+    public void setColorFilter(long colorFilterPtr) {
+        mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr);
+    }
+
+    public void setShader(long shaderPtr) {
+        mShader = Shader_Delegate.getDelegate(shaderPtr);
+    }
+
     /**
      * Returns the {@link Shader} delegate or null if none have been set
      *
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index e1da27b..265ebd1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -167,13 +167,13 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setFillType(long nPath, int ft) {
+    public static void native_setFillType(long nPath, int ft) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
         }
 
-        pathDelegate.mFillType = Path.sFillTypeArray[ft];
+        pathDelegate.setFillType(Path.sFillTypeArray[ft]);
     }
 
     @LayoutlibDelegate
@@ -423,21 +423,13 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_offset(long nPath, float dx, float dy, long dst_path) {
+    /*package*/ static void native_offset(long nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
         }
 
-        // could be null if the int is 0;
-        Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
-
-        pathDelegate.offset(dx, dy, dstDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_offset(long nPath, float dx, float dy) {
-        native_offset(nPath, dx, dy, 0);
+        pathDelegate.offset(dx, dy);
     }
 
     @LayoutlibDelegate
@@ -572,7 +564,7 @@
         return null;
     }
 
-    private static void addPath(long destPath, long srcPath, AffineTransform transform) {
+    public static void addPath(long destPath, long srcPath, AffineTransform transform) {
         Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
         if (destPathDelegate == null) {
             return;
@@ -630,7 +622,7 @@
      * Fills the given {@link RectF} with the path bounds.
      * @param bounds the RectF to be filled.
      */
-    private void fillBounds(RectF bounds) {
+    public void fillBounds(RectF bounds) {
         Rectangle2D rect = mPath.getBounds2D();
         bounds.left = (float)rect.getMinX();
         bounds.right = (float)rect.getMaxX();
@@ -644,7 +636,7 @@
      * @param x The x-coordinate of the start of a new contour
      * @param y The y-coordinate of the start of a new contour
      */
-    private void moveTo(float x, float y) {
+    public void moveTo(float x, float y) {
         mPath.moveTo(mLastX = x, mLastY = y);
     }
 
@@ -658,7 +650,7 @@
      * @param dy The amount to add to the y-coordinate of the end of the
      *           previous contour, to specify the start of a new contour
      */
-    private void rMoveTo(float dx, float dy) {
+    public void rMoveTo(float dx, float dy) {
         dx += mLastX;
         dy += mLastY;
         mPath.moveTo(mLastX = dx, mLastY = dy);
@@ -672,7 +664,7 @@
      * @param x The x-coordinate of the end of a line
      * @param y The y-coordinate of the end of a line
      */
-    private void lineTo(float x, float y) {
+    public void lineTo(float x, float y) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
@@ -689,7 +681,7 @@
      * @param dy The amount to add to the y-coordinate of the previous point on
      *           this contour, to specify a line
      */
-    private void rLineTo(float dx, float dy) {
+    public void rLineTo(float dx, float dy) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
@@ -714,7 +706,7 @@
      * @param x2 The x-coordinate of the end point on a quadratic curve
      * @param y2 The y-coordinate of the end point on a quadratic curve
      */
-    private void quadTo(float x1, float y1, float x2, float y2) {
+    public void quadTo(float x1, float y1, float x2, float y2) {
         mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
     }
 
@@ -732,7 +724,7 @@
      * @param dy2 The amount to add to the y-coordinate of the last point on
      *            this contour, for the end point of a quadratic curve
      */
-    private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
+    public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
@@ -755,7 +747,7 @@
      * @param x3 The x-coordinate of the end point on a cubic curve
      * @param y3 The y-coordinate of the end point on a cubic curve
      */
-    private void cubicTo(float x1, float y1, float x2, float y2,
+    public void cubicTo(float x1, float y1, float x2, float y2,
                         float x3, float y3) {
         if (!hasPoints()) {
             mPath.moveTo(0, 0);
@@ -768,7 +760,7 @@
      * current point on this contour. If there is no previous point, then a
      * moveTo(0,0) is inserted automatically.
      */
-    private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
+    public void rCubicTo(float dx1, float dy1, float dx2, float dy2,
                          float dx3, float dy3) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
@@ -798,7 +790,7 @@
      *                    mod 360.
      * @param forceMoveTo If true, always begin a new contour with the arc
      */
-    private void arcTo(float left, float top, float right, float bottom, float startAngle,
+    public void arcTo(float left, float top, float right, float bottom, float startAngle,
             float sweepAngle,
             boolean forceMoveTo) {
         Arc2D arc = new Arc2D.Float(left, top, right - left, bottom - top, -startAngle,
@@ -812,7 +804,7 @@
      * Close the current contour. If the current point is not equal to the
      * first point of the contour, a line segment is automatically added.
      */
-    private void close() {
+    public void close() {
         mPath.closePath();
     }
 
@@ -831,7 +823,7 @@
      * @param bottom The bottom of a rectangle to add to the path
      * @param dir    The direction to wind the rectangle's contour
      */
-    private void addRect(float left, float top, float right, float bottom,
+    public void addRect(float left, float top, float right, float bottom,
                         int dir) {
         moveTo(left, top);
 
@@ -860,21 +852,14 @@
      *
      * @param dx  The amount in the X direction to offset the entire path
      * @param dy  The amount in the Y direction to offset the entire path
-     * @param dst The translated path is written here. If this is null, then
-     *            the original path is modified.
      */
-    public void offset(float dx, float dy, Path_Delegate dst) {
+    public void offset(float dx, float dy) {
         GeneralPath newPath = new GeneralPath();
 
         PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
 
         newPath.append(iterator, false /*connect*/);
-
-        if (dst != null) {
-            dst.mPath = newPath;
-        } else {
-            mPath = newPath;
-        }
+        mPath = newPath;
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
deleted file mode 100644
index f27144f..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
+++ /dev/null
@@ -1,70 +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.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Composite;
-
-/**
- * Delegate implementing the native methods of android.graphics.PixelXorXfermode
- *
- * Through the layoutlib_create tool, the original native methods of PixelXorXfermode have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original PixelXorXfermode class.
- *
- * Because this extends {@link Xfermode_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
- * {@link Xfermode_Delegate}.
- *
- * @see Xfermode_Delegate
- */
-public class PixelXorXfermode_Delegate extends Xfermode_Delegate {
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Composite getComposite(int alpha) {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Pixel XOR Xfermodes are not supported in Layout Preview mode.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(int opColor) {
-        PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 1ca94dc..ff3f19f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -48,7 +48,7 @@
 
     // ---- delegate data ----
 
-    private final int mSrcColor;
+    private final java.awt.Color mSrcColor;
     private final Mode mMode;
 
 
@@ -66,9 +66,9 @@
 
     @Override
     public void applyFilter(Graphics2D g, int width, int height) {
-        BufferedImage image = createFilterImage(width, height);
         g.setComposite(getComposite(mMode, 0xFF));
-        g.drawImage(image, 0, 0, null);
+        g.setColor(mSrcColor);
+        g.fillRect(0, 0, width, height);
     }
 
     // ---- native methods ----
@@ -84,22 +84,10 @@
     // ---- Private delegate/helper methods ----
 
     private PorterDuffColorFilter_Delegate(int srcColor, int mode) {
-        mSrcColor = srcColor;
+        mSrcColor = new java.awt.Color(srcColor, true /* hasAlpha */);
         mMode = getCompatibleMode(getPorterDuffMode(mode));
     }
 
-    private BufferedImage createFilterImage(int width, int height) {
-        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        Graphics2D graphics = image.createGraphics();
-        try {
-            graphics.setColor(new java.awt.Color(mSrcColor, true /* hasAlpha */));
-            graphics.fillRect(0, 0, width, height);
-        } finally {
-            graphics.dispose();
-        }
-        return image;
-    }
-
     // For filtering the colors, the src image should contain the "color" only for pixel values
     // which are not transparent in the target image. But, we are using a simple rectangular image
     // completely filled with color. Hence some Composite rules do not apply as intended. However,
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
new file mode 100644
index 0000000..200fe3b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License") {}
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 com.android.ide.common.rendering.api.LayoutLog;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper_Delegate;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT;
+import android.graphics.drawable.VectorDrawable_Delegate.VFullPath_Delegate;
+import android.graphics.drawable.VectorDrawable_Delegate.VGroup_Delegate;
+import android.graphics.drawable.VectorDrawable_Delegate.VNativeObject;
+import android.graphics.drawable.VectorDrawable_Delegate.VPathRenderer_Delegate;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link
+ * AnimatedVectorDrawable}
+ * <p>
+ * Through the layoutlib_create tool, the original  methods of AnimatedVectorDrawable have been
+ * replaced by calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class AnimatedVectorDrawable_Delegate {
+    private static DelegateManager<AnimatorSetHolder> sAnimatorSets = new
+            DelegateManager<>(AnimatorSetHolder.class);
+    private static DelegateManager<PropertySetter> sHolders = new
+            DelegateManager<>(PropertySetter.class);
+
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreateAnimatorSet() {
+        return sAnimatorSets.addNewDelegate(new AnimatorSetHolder());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nAddAnimator(long setPtr, long propertyValuesHolder,
+            long nativeInterpolator, long startDelay, long duration, int repeatCount) {
+        PropertySetter holder = sHolders.getDelegate(propertyValuesHolder);
+        if (holder == null || holder.getValues() == null) {
+            return;
+        }
+
+        ObjectAnimator animator = new ObjectAnimator();
+        animator.setValues(holder.getValues());
+        animator.setInterpolator(
+                NativeInterpolatorFactoryHelper_Delegate.getDelegate(nativeInterpolator));
+        animator.setStartDelay(startDelay);
+        animator.setDuration(duration);
+        animator.setRepeatCount(repeatCount);
+        animator.setTarget(holder);
+        animator.setPropertyName(holder.getValues().getPropertyName());
+
+        AnimatorSetHolder set = sAnimatorSets.getDelegate(setPtr);
+        assert set != null;
+        set.addAnimator(animator);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
+            float startValue, float endValue) {
+        VGroup_Delegate group = VNativeObject.getDelegate(nativePtr);
+        Consumer<Float> setter = group.getPropertySetter(propertyId);
+
+        return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
+                endValue));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
+            long endValuePtr) {
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "AnimatedVectorDrawable path " +
+                "animations are not supported.", null, null);
+        return 0;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
+            int startValue, int endValue) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
+        Consumer<Integer> setter = path.getIntPropertySetter(propertyId);
+
+        return sHolders.addNewDelegate(IntPropertySetter.of(setter, startValue,
+                endValue));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreatePathPropertyHolder(long nativePtr, int propertyId,
+            float startValue, float endValue) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
+        Consumer<Float> setter = path.getFloatPropertySetter(propertyId);
+
+        return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
+                endValue));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
+            float endValue) {
+        VPathRenderer_Delegate renderer = VNativeObject.getDelegate(nativePtr);
+
+        return sHolders.addNewDelegate(FloatPropertySetter.of(renderer::setRootAlpha,
+                startValue,
+                endValue));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nSetPropertyHolderData(long nativePtr, float[] data, int length) {
+        PropertySetter setter = sHolders.getDelegate(nativePtr);
+        assert setter != null;
+
+        setter.setValues(data);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
+        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+        assert animatorSet != null;
+
+        animatorSet.start();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
+        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+        assert animatorSet != null;
+
+        animatorSet.reverse();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nEnd(long animatorSetPtr) {
+        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+        assert animatorSet != null;
+
+        animatorSet.end();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nReset(long animatorSetPtr) {
+        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+        assert animatorSet != null;
+
+        animatorSet.end();
+        animatorSet.start();
+    }
+
+    private static class AnimatorSetHolder {
+        private ArrayList<Animator> mAnimators = new ArrayList<>();
+        private AnimatorSet mAnimatorSet = null;
+
+        private void addAnimator(@NonNull Animator animator) {
+            mAnimators.add(animator);
+        }
+
+        private void ensureAnimatorSet() {
+            if (mAnimatorSet == null) {
+                mAnimatorSet = new AnimatorSet();
+                mAnimatorSet.playTogether(mAnimators);
+            }
+        }
+
+        private void start() {
+            ensureAnimatorSet();
+
+            mAnimatorSet.start();
+        }
+
+        private void end() {
+            mAnimatorSet.end();
+        }
+
+        private void reset() {
+            end();
+            start();
+        }
+
+        private void reverse() {
+            mAnimatorSet.reverse();
+        }
+    }
+
+    /**
+     * Class that allows setting a value and holds the range of values for the given property.
+     *
+     * @param <T> the type of the property
+     */
+    private static class PropertySetter<T> {
+        final Consumer<T> mValueSetter;
+        private PropertyValuesHolder mValues;
+
+        private PropertySetter(@NonNull Consumer<T> valueSetter) {
+            mValueSetter = valueSetter;
+        }
+
+        /**
+         * Method to set an {@link Integer} value for this property. The default implementation of
+         * this method doesn't do anything. This method is accessed via reflection by the
+         * PropertyValuesHolder.
+         */
+        public void setIntValue(Integer value) {
+        }
+
+        /**
+         * Method to set an {@link Integer} value for this property. The default implementation of
+         * this method doesn't do anything. This method is accessed via reflection by the
+         * PropertyValuesHolder.
+         */
+        public void setFloatValue(Float value) {
+        }
+
+        void setValues(float... values) {
+            mValues = PropertyValuesHolder.ofFloat("floatValue", values);
+        }
+
+        @Nullable
+        PropertyValuesHolder getValues() {
+            return mValues;
+        }
+
+        void setValues(int... values) {
+            mValues = PropertyValuesHolder.ofInt("intValue", values);
+        }
+    }
+
+    private static class IntPropertySetter extends PropertySetter<Integer> {
+        private IntPropertySetter(Consumer<Integer> valueSetter) {
+            super(valueSetter);
+        }
+
+        private static PropertySetter of(Consumer<Integer> valueSetter, int... values) {
+            PropertySetter setter = new IntPropertySetter(valueSetter);
+            setter.setValues(values);
+
+            return setter;
+        }
+
+        public void setIntValue(Integer value) {
+            mValueSetter.accept(value);
+        }
+    }
+
+    private static class FloatPropertySetter extends PropertySetter<Float> {
+        private FloatPropertySetter(Consumer<Float> valueSetter) {
+            super(valueSetter);
+        }
+
+        private static PropertySetter of(Consumer<Float> valueSetter, float... values) {
+            PropertySetter setter = new FloatPropertySetter(valueSetter);
+            setter.setValues(values);
+
+            return setter;
+        }
+
+        public void setFloatValue(Float value) {
+            mValueSetter.accept(value);
+        }
+
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java
new file mode 100644
index 0000000..3d78931
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT;
+
+public class AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate {
+    @LayoutlibDelegate
+    /*package*/ static boolean useLastSeenTarget(VectorDrawableAnimatorRT thisDrawableAnimator) {
+        return true;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
new file mode 100644
index 0000000..d8ff57b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -0,0 +1,1211 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.annotation.NonNull;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas_Delegate;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Cap;
+import android.graphics.Paint.Join;
+import android.graphics.Paint_Delegate;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.Path_Delegate;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.MathUtils;
+import android.util.PathParser_Delegate;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+import static android.graphics.Canvas.CLIP_SAVE_FLAG;
+import static android.graphics.Canvas.MATRIX_SAVE_FLAG;
+import static android.graphics.Paint.Cap.BUTT;
+import static android.graphics.Paint.Cap.ROUND;
+import static android.graphics.Paint.Cap.SQUARE;
+import static android.graphics.Paint.Join.BEVEL;
+import static android.graphics.Paint.Join.MITER;
+import static android.graphics.Paint.Style;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link VectorDrawable}
+ * <p>
+ * Through the layoutlib_create tool, the original  methods of VectorDrawable have been replaced by
+ * calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class VectorDrawable_Delegate {
+    private static final String LOGTAG = VectorDrawable_Delegate.class.getSimpleName();
+    private static final boolean DBG_VECTOR_DRAWABLE = false;
+
+    private static final DelegateManager<VNativeObject> sPathManager =
+            new DelegateManager<>(VNativeObject.class);
+
+    /**
+     * Obtains styled attributes from the theme, if available, or unstyled resources if the theme is
+     * null.
+     */
+    private static TypedArray obtainAttributes(
+            Resources res, Theme theme, AttributeSet set, int[] attrs) {
+        if (theme == null) {
+            return res.obtainAttributes(set, attrs);
+        }
+        return theme.obtainStyledAttributes(set, attrs, 0, 0);
+    }
+
+    private static int applyAlpha(int color, float alpha) {
+        int alphaBytes = Color.alpha(color);
+        color &= 0x00FFFFFF;
+        color |= ((int) (alphaBytes * alpha)) << 24;
+        return color;
+    }
+
+    @LayoutlibDelegate
+    static long nCreateRenderer(long rootGroupPtr) {
+        VGroup_Delegate rootGroup = VNativeObject.getDelegate(rootGroupPtr);
+        return sPathManager.addNewDelegate(new VPathRenderer_Delegate(rootGroup));
+    }
+
+    @LayoutlibDelegate
+    static void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+            float viewportHeight) {
+        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
+        nativePathRenderer.mViewportWidth = viewportWidth;
+        nativePathRenderer.mViewportHeight = viewportHeight;
+    }
+
+    @LayoutlibDelegate
+    static boolean nSetRootAlpha(long rendererPtr, float alpha) {
+        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
+        nativePathRenderer.setRootAlpha(alpha);
+
+        return true;
+    }
+
+    @LayoutlibDelegate
+    static float nGetRootAlpha(long rendererPtr) {
+        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
+
+        return nativePathRenderer.getRootAlpha();
+    }
+
+    @LayoutlibDelegate
+    static void nSetAllowCaching(long rendererPtr, boolean allowCaching) {
+        // ignored
+    }
+
+    @LayoutlibDelegate
+    static void nDraw(long rendererPtr, long canvasWrapperPtr,
+            long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache) {
+        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
+
+        Canvas_Delegate.native_save(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+        Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.left, bounds.top);
+
+        if (needsMirroring) {
+            Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.width(), 0);
+            Canvas_Delegate.native_scale(canvasWrapperPtr, -1.0f, 1.0f);
+        }
+
+        // At this point, canvas has been translated to the right position.
+        // And we use this bound for the destination rect for the drawBitmap, so
+        // we offset to (0, 0);
+        bounds.offsetTo(0, 0);
+        nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height());
+
+        Canvas_Delegate.native_restore(canvasWrapperPtr, true);
+    }
+
+    @LayoutlibDelegate
+    static long nCreateFullPath() {
+        return sPathManager.addNewDelegate(new VFullPath_Delegate());
+    }
+
+    @LayoutlibDelegate
+    static long nCreateFullPath(long nativeFullPathPtr) {
+        VFullPath_Delegate original = VNativeObject.getDelegate(nativeFullPathPtr);
+
+        return sPathManager.addNewDelegate(new VFullPath_Delegate(original));
+    }
+
+    @LayoutlibDelegate
+    static boolean nGetFullPathProperties(long pathPtr, byte[] propertiesData,
+            int length) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+
+        ByteBuffer properties = ByteBuffer.wrap(propertiesData);
+        properties.order(ByteOrder.nativeOrder());
+
+        properties.putFloat(VFullPath_Delegate.STROKE_WIDTH_INDEX * 4, path.getStrokeWidth());
+        properties.putInt(VFullPath_Delegate.STROKE_COLOR_INDEX * 4, path.getStrokeColor());
+        properties.putFloat(VFullPath_Delegate.STROKE_ALPHA_INDEX * 4, path.getStrokeAlpha());
+        properties.putInt(VFullPath_Delegate.FILL_COLOR_INDEX * 4, path.getFillColor());
+        properties.putFloat(VFullPath_Delegate.FILL_ALPHA_INDEX * 4, path.getStrokeAlpha());
+        properties.putFloat(VFullPath_Delegate.TRIM_PATH_START_INDEX * 4, path.getTrimPathStart());
+        properties.putFloat(VFullPath_Delegate.TRIM_PATH_END_INDEX * 4, path.getTrimPathEnd());
+        properties.putFloat(VFullPath_Delegate.TRIM_PATH_OFFSET_INDEX * 4,
+                path.getTrimPathOffset());
+        properties.putInt(VFullPath_Delegate.STROKE_LINE_CAP_INDEX * 4, path.getStrokeLineCap());
+        properties.putInt(VFullPath_Delegate.STROKE_LINE_JOIN_INDEX * 4, path.getStrokeLineJoin());
+        properties.putFloat(VFullPath_Delegate.STROKE_MITER_LIMIT_INDEX * 4,
+                path.getStrokeMiterlimit());
+        properties.putInt(VFullPath_Delegate.FILL_TYPE_INDEX * 4, path.getFillType());
+
+        return true;
+    }
+
+    @LayoutlibDelegate
+    static void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
+            int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
+            float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
+            int strokeLineJoin, int fillType) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+
+        path.setStrokeWidth(strokeWidth);
+        path.setStrokeColor(strokeColor);
+        path.setStrokeAlpha(strokeAlpha);
+        path.setFillColor(fillColor);
+        path.setFillAlpha(fillAlpha);
+        path.setTrimPathStart(trimPathStart);
+        path.setTrimPathEnd(trimPathEnd);
+        path.setTrimPathOffset(trimPathOffset);
+        path.setStrokeMiterlimit(strokeMiterLimit);
+        path.setStrokeLineCap(strokeLineCap);
+        path.setStrokeLineJoin(strokeLineJoin);
+        path.setFillType(fillType);
+    }
+
+    @LayoutlibDelegate
+    static void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+
+        path.setFillGradient(fillGradientPtr);
+    }
+
+    @LayoutlibDelegate
+    static void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+
+        path.setStrokeGradient(strokeGradientPtr);
+    }
+
+    @LayoutlibDelegate
+    static long nCreateClipPath() {
+        return sPathManager.addNewDelegate(new VClipPath_Delegate());
+    }
+
+    @LayoutlibDelegate
+    static long nCreateClipPath(long clipPathPtr) {
+        VClipPath_Delegate original = VNativeObject.getDelegate(clipPathPtr);
+        return sPathManager.addNewDelegate(new VClipPath_Delegate(original));
+    }
+
+    @LayoutlibDelegate
+    static long nCreateGroup() {
+        return sPathManager.addNewDelegate(new VGroup_Delegate());
+    }
+
+    @LayoutlibDelegate
+    static long nCreateGroup(long groupPtr) {
+        VGroup_Delegate original = VNativeObject.getDelegate(groupPtr);
+        return sPathManager.addNewDelegate(
+                new VGroup_Delegate(original, new ArrayMap<String, Object>()));
+    }
+
+    @LayoutlibDelegate
+    static void nSetName(long nodePtr, String name) {
+        VNativeObject group = VNativeObject.getDelegate(nodePtr);
+        group.setName(name);
+    }
+
+    @LayoutlibDelegate
+    static boolean nGetGroupProperties(long groupPtr, float[] propertiesData,
+            int length) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+
+        FloatBuffer properties = FloatBuffer.wrap(propertiesData);
+
+        properties.put(VGroup_Delegate.ROTATE_INDEX, group.getRotation());
+        properties.put(VGroup_Delegate.PIVOT_X_INDEX, group.getPivotX());
+        properties.put(VGroup_Delegate.PIVOT_Y_INDEX, group.getPivotY());
+        properties.put(VGroup_Delegate.SCALE_X_INDEX, group.getScaleX());
+        properties.put(VGroup_Delegate.SCALE_Y_INDEX, group.getScaleY());
+        properties.put(VGroup_Delegate.TRANSLATE_X_INDEX, group.getTranslateX());
+        properties.put(VGroup_Delegate.TRANSLATE_Y_INDEX, group.getTranslateY());
+
+        return true;
+    }
+    @LayoutlibDelegate
+    static void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
+            float pivotY, float scaleX, float scaleY, float translateX, float translateY) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+
+        group.setRotation(rotate);
+        group.setPivotX(pivotX);
+        group.setPivotY(pivotY);
+        group.setScaleX(scaleX);
+        group.setScaleY(scaleY);
+        group.setTranslateX(translateX);
+        group.setTranslateY(translateY);
+    }
+
+    @LayoutlibDelegate
+    static void nAddChild(long groupPtr, long nodePtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.mChildren.add(VNativeObject.getDelegate(nodePtr));
+    }
+
+    @LayoutlibDelegate
+    static void nSetPathString(long pathPtr, String pathString, int length) {
+        VPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setPathData(PathParser_Delegate.createNodesFromPathData(pathString));
+    }
+
+    /**
+     * The setters and getters below for paths and groups are here temporarily, and will be removed
+     * once the animation in AVD is replaced with RenderNodeAnimator, in which case the animation
+     * will modify these properties in native. By then no JNI hopping would be necessary for VD
+     * during animation, and these setters and getters will be obsolete.
+     */
+    // Setters and getters during animation.
+    @LayoutlibDelegate
+    static float nGetRotation(long groupPtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        return group.getRotation();
+    }
+
+    @LayoutlibDelegate
+    static void nSetRotation(long groupPtr, float rotation) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.setRotation(rotation);
+    }
+
+    @LayoutlibDelegate
+    static float nGetPivotX(long groupPtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        return group.getPivotX();
+    }
+
+    @LayoutlibDelegate
+    static void nSetPivotX(long groupPtr, float pivotX) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.setPivotX(pivotX);
+    }
+
+    @LayoutlibDelegate
+    static float nGetPivotY(long groupPtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        return group.getPivotY();
+    }
+
+    @LayoutlibDelegate
+    static void nSetPivotY(long groupPtr, float pivotY) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.setPivotY(pivotY);
+    }
+
+    @LayoutlibDelegate
+    static float nGetScaleX(long groupPtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        return group.getScaleX();
+    }
+
+    @LayoutlibDelegate
+    static void nSetScaleX(long groupPtr, float scaleX) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.setScaleX(scaleX);
+    }
+
+    @LayoutlibDelegate
+    static float nGetScaleY(long groupPtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        return group.getScaleY();
+    }
+
+    @LayoutlibDelegate
+    static void nSetScaleY(long groupPtr, float scaleY) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.setScaleY(scaleY);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTranslateX(long groupPtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        return group.getTranslateX();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTranslateX(long groupPtr, float translateX) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.setTranslateX(translateX);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTranslateY(long groupPtr) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        return group.getTranslateY();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTranslateY(long groupPtr, float translateY) {
+        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+        group.setTranslateY(translateY);
+    }
+
+    @LayoutlibDelegate
+    static void nSetPathData(long pathPtr, long pathDataPtr) {
+        VPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setPathData(PathParser_Delegate.getDelegate(pathDataPtr).getPathDataNodes());
+    }
+
+    @LayoutlibDelegate
+    static float nGetStrokeWidth(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getStrokeWidth();
+    }
+
+    @LayoutlibDelegate
+    static void nSetStrokeWidth(long pathPtr, float width) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setStrokeWidth(width);
+    }
+
+    @LayoutlibDelegate
+    static int nGetStrokeColor(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getStrokeColor();
+    }
+
+    @LayoutlibDelegate
+    static void nSetStrokeColor(long pathPtr, int strokeColor) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setStrokeColor(strokeColor);
+    }
+
+    @LayoutlibDelegate
+    static float nGetStrokeAlpha(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getStrokeAlpha();
+    }
+
+    @LayoutlibDelegate
+    static void nSetStrokeAlpha(long pathPtr, float alpha) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setStrokeAlpha(alpha);
+    }
+
+    @LayoutlibDelegate
+    static int nGetFillColor(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getFillColor();
+    }
+
+    @LayoutlibDelegate
+    static void nSetFillColor(long pathPtr, int fillColor) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setFillColor(fillColor);
+    }
+
+    @LayoutlibDelegate
+    static float nGetFillAlpha(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getFillAlpha();
+    }
+
+    @LayoutlibDelegate
+    static void nSetFillAlpha(long pathPtr, float fillAlpha) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setFillAlpha(fillAlpha);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTrimPathStart(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getTrimPathStart();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTrimPathStart(long pathPtr, float trimPathStart) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setTrimPathStart(trimPathStart);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTrimPathEnd(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getTrimPathEnd();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTrimPathEnd(long pathPtr, float trimPathEnd) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setTrimPathEnd(trimPathEnd);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTrimPathOffset(long pathPtr) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        return path.getTrimPathOffset();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTrimPathOffset(long pathPtr, float trimPathOffset) {
+        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+        path.setTrimPathOffset(trimPathOffset);
+    }
+
+    /**
+     * Base class for all the internal Delegates that does two functions:
+     * <ol>
+     *     <li>Serves as base class to store all the delegates in one {@link DelegateManager}
+     *     <li>Provides setName for all the classes. {@link VPathRenderer_Delegate} does actually
+     *     not need it
+     * </ol>
+     */
+    interface VNativeObject {
+        @NonNull
+        static <T> T getDelegate(long nativePtr) {
+            //noinspection unchecked
+            T vNativeObject = (T) sPathManager.getDelegate(nativePtr);
+
+            assert vNativeObject != null;
+            return vNativeObject;
+        }
+
+        void setName(String name);
+    }
+
+    private static class VClipPath_Delegate extends VPath_Delegate {
+        private VClipPath_Delegate() {
+            // Empty constructor.
+        }
+
+        private VClipPath_Delegate(VClipPath_Delegate copy) {
+            super(copy);
+        }
+
+        @Override
+        public boolean isClipPath() {
+            return true;
+        }
+    }
+
+    static class VFullPath_Delegate extends VPath_Delegate {
+        // These constants need to be kept in sync with their values in VectorDrawable.VFullPath
+        private static final int STROKE_WIDTH_INDEX = 0;
+        private static final int STROKE_COLOR_INDEX = 1;
+        private static final int STROKE_ALPHA_INDEX = 2;
+        private static final int FILL_COLOR_INDEX = 3;
+        private static final int FILL_ALPHA_INDEX = 4;
+        private static final int TRIM_PATH_START_INDEX = 5;
+        private static final int TRIM_PATH_END_INDEX = 6;
+        private static final int TRIM_PATH_OFFSET_INDEX = 7;
+        private static final int STROKE_LINE_CAP_INDEX = 8;
+        private static final int STROKE_LINE_JOIN_INDEX = 9;
+        private static final int STROKE_MITER_LIMIT_INDEX = 10;
+        private static final int FILL_TYPE_INDEX = 11;
+
+        private static final int LINECAP_BUTT = 0;
+        private static final int LINECAP_ROUND = 1;
+        private static final int LINECAP_SQUARE = 2;
+
+        private static final int LINEJOIN_MITER = 0;
+        private static final int LINEJOIN_ROUND = 1;
+        private static final int LINEJOIN_BEVEL = 2;
+
+        @NonNull
+        public Consumer<Float> getFloatPropertySetter(int propertyIdx) {
+            switch (propertyIdx) {
+                case STROKE_ALPHA_INDEX:
+                    return this::setStrokeAlpha;
+                case FILL_ALPHA_INDEX:
+                    return this::setFillAlpha;
+                case TRIM_PATH_START_INDEX:
+                    return this::setTrimPathStart;
+                case TRIM_PATH_END_INDEX:
+                    return this::setTrimPathEnd;
+                case TRIM_PATH_OFFSET_INDEX:
+                    return this::setTrimPathOffset;
+            }
+
+            throw new IllegalArgumentException("Invalid VFullPath_Delegate property index "
+                    + propertyIdx);
+        }
+
+        @NonNull
+        public Consumer<Integer> getIntPropertySetter(int propertyIdx) {
+            switch (propertyIdx) {
+                case STROKE_COLOR_INDEX:
+                    return this::setStrokeColor;
+                case FILL_COLOR_INDEX:
+                    return this::setFillColor;
+            }
+
+            throw new IllegalArgumentException("Invalid VFullPath_Delegate property index "
+                    + propertyIdx);
+        }
+
+        /////////////////////////////////////////////////////
+        // Variables below need to be copied (deep copy if applicable) for mutation.
+
+        int mStrokeColor = Color.TRANSPARENT;
+        float mStrokeWidth = 0;
+
+        int mFillColor = Color.TRANSPARENT;
+        long mStrokeGradient = 0;
+        long mFillGradient = 0;
+        float mStrokeAlpha = 1.0f;
+        float mFillAlpha = 1.0f;
+        float mTrimPathStart = 0;
+        float mTrimPathEnd = 1;
+        float mTrimPathOffset = 0;
+
+        Cap mStrokeLineCap = BUTT;
+        Join mStrokeLineJoin = MITER;
+        float mStrokeMiterlimit = 4;
+
+        int mFillType = 0; // WINDING(0) is the default value. See Path.FillType
+
+        private VFullPath_Delegate() {
+            // Empty constructor.
+        }
+
+        private VFullPath_Delegate(VFullPath_Delegate copy) {
+            super(copy);
+
+            mStrokeColor = copy.mStrokeColor;
+            mStrokeWidth = copy.mStrokeWidth;
+            mStrokeAlpha = copy.mStrokeAlpha;
+            mFillColor = copy.mFillColor;
+            mFillAlpha = copy.mFillAlpha;
+            mTrimPathStart = copy.mTrimPathStart;
+            mTrimPathEnd = copy.mTrimPathEnd;
+            mTrimPathOffset = copy.mTrimPathOffset;
+
+            mStrokeLineCap = copy.mStrokeLineCap;
+            mStrokeLineJoin = copy.mStrokeLineJoin;
+            mStrokeMiterlimit = copy.mStrokeMiterlimit;
+
+            mStrokeGradient = copy.mStrokeGradient;
+            mFillGradient = copy.mFillGradient;
+            mFillType = copy.mFillType;
+        }
+
+        private int getStrokeLineCap() {
+            switch (mStrokeLineCap) {
+                case BUTT:
+                    return LINECAP_BUTT;
+                case ROUND:
+                    return LINECAP_ROUND;
+                case SQUARE:
+                    return LINECAP_SQUARE;
+                default:
+                    assert false;
+            }
+
+            return -1;
+        }
+
+        private void setStrokeLineCap(int cap) {
+            switch (cap) {
+                case LINECAP_BUTT:
+                    mStrokeLineCap = BUTT;
+                    break;
+                case LINECAP_ROUND:
+                    mStrokeLineCap = ROUND;
+                    break;
+                case LINECAP_SQUARE:
+                    mStrokeLineCap = SQUARE;
+                    break;
+                default:
+                    assert false;
+            }
+        }
+
+        private int getStrokeLineJoin() {
+            switch (mStrokeLineJoin) {
+                case MITER:
+                    return LINEJOIN_MITER;
+                case ROUND:
+                    return LINEJOIN_ROUND;
+                case BEVEL:
+                    return LINEJOIN_BEVEL;
+                default:
+                    assert false;
+            }
+
+            return -1;
+        }
+
+        private void setStrokeLineJoin(int join) {
+            switch (join) {
+                case LINEJOIN_BEVEL:
+                    mStrokeLineJoin = BEVEL;
+                    break;
+                case LINEJOIN_MITER:
+                    mStrokeLineJoin = MITER;
+                    break;
+                case LINEJOIN_ROUND:
+                    mStrokeLineJoin = Join.ROUND;
+                    break;
+                default:
+                    assert false;
+            }
+        }
+
+        private int getStrokeColor() {
+            return mStrokeColor;
+        }
+
+        private void setStrokeColor(int strokeColor) {
+            mStrokeColor = strokeColor;
+        }
+
+        private float getStrokeWidth() {
+            return mStrokeWidth;
+        }
+
+        private void setStrokeWidth(float strokeWidth) {
+            mStrokeWidth = strokeWidth;
+        }
+
+        private float getStrokeAlpha() {
+            return mStrokeAlpha;
+        }
+
+        private void setStrokeAlpha(float strokeAlpha) {
+            mStrokeAlpha = strokeAlpha;
+        }
+
+        private int getFillColor() {
+            return mFillColor;
+        }
+
+        private void setFillColor(int fillColor) {
+            mFillColor = fillColor;
+        }
+
+        private float getFillAlpha() {
+            return mFillAlpha;
+        }
+
+        private void setFillAlpha(float fillAlpha) {
+            mFillAlpha = fillAlpha;
+        }
+
+        private float getTrimPathStart() {
+            return mTrimPathStart;
+        }
+
+        private void setTrimPathStart(float trimPathStart) {
+            mTrimPathStart = trimPathStart;
+        }
+
+        private float getTrimPathEnd() {
+            return mTrimPathEnd;
+        }
+
+        private void setTrimPathEnd(float trimPathEnd) {
+            mTrimPathEnd = trimPathEnd;
+        }
+
+        private float getTrimPathOffset() {
+            return mTrimPathOffset;
+        }
+
+        private void setTrimPathOffset(float trimPathOffset) {
+            mTrimPathOffset = trimPathOffset;
+        }
+
+        private void setStrokeMiterlimit(float limit) {
+            mStrokeMiterlimit = limit;
+        }
+
+        private float getStrokeMiterlimit() {
+            return mStrokeMiterlimit;
+        }
+
+        private void setStrokeGradient(long gradientPtr) {
+            mStrokeGradient = gradientPtr;
+        }
+
+        private void setFillGradient(long gradientPtr) {
+            mFillGradient = gradientPtr;
+        }
+
+        private void setFillType(int fillType) {
+            mFillType = fillType;
+        }
+
+        private int getFillType() {
+            return mFillType;
+        }
+    }
+
+    static class VGroup_Delegate implements VNativeObject {
+        // This constants need to be kept in sync with their definitions in VectorDrawable.Group
+        private static final int ROTATE_INDEX = 0;
+        private static final int PIVOT_X_INDEX = 1;
+        private static final int PIVOT_Y_INDEX = 2;
+        private static final int SCALE_X_INDEX = 3;
+        private static final int SCALE_Y_INDEX = 4;
+        private static final int TRANSLATE_X_INDEX = 5;
+        private static final int TRANSLATE_Y_INDEX = 6;
+
+        public Consumer<Float> getPropertySetter(int propertyIdx) {
+            switch (propertyIdx) {
+                case ROTATE_INDEX:
+                    return this::setRotation;
+                case PIVOT_X_INDEX:
+                    return this::setPivotX;
+                case PIVOT_Y_INDEX:
+                    return this::setPivotY;
+                case SCALE_X_INDEX:
+                    return this::setScaleX;
+                case SCALE_Y_INDEX:
+                    return this::setScaleY;
+                case TRANSLATE_X_INDEX:
+                    return this::setTranslateX;
+                case TRANSLATE_Y_INDEX:
+                    return this::setTranslateY;
+            }
+
+            throw new IllegalArgumentException("Invalid VGroup_Delegate property index "
+                    + propertyIdx);
+        }
+
+        /////////////////////////////////////////////////////
+        // Variables below need to be copied (deep copy if applicable) for mutation.
+        final ArrayList<Object> mChildren = new ArrayList<>();
+        // mStackedMatrix is only used temporarily when drawing, it combines all
+        // the parents' local matrices with the current one.
+        private final Matrix mStackedMatrix = new Matrix();
+        // mLocalMatrix is updated based on the update of transformation information,
+        // either parsed from the XML or by animation.
+        private final Matrix mLocalMatrix = new Matrix();
+        private float mRotate = 0;
+        private float mPivotX = 0;
+        private float mPivotY = 0;
+        private float mScaleX = 1;
+        private float mScaleY = 1;
+        private float mTranslateX = 0;
+        private float mTranslateY = 0;
+        private int mChangingConfigurations;
+        private String mGroupName = null;
+
+        private VGroup_Delegate(VGroup_Delegate copy, ArrayMap<String, Object> targetsMap) {
+            mRotate = copy.mRotate;
+            mPivotX = copy.mPivotX;
+            mPivotY = copy.mPivotY;
+            mScaleX = copy.mScaleX;
+            mScaleY = copy.mScaleY;
+            mTranslateX = copy.mTranslateX;
+            mTranslateY = copy.mTranslateY;
+            mGroupName = copy.mGroupName;
+            mChangingConfigurations = copy.mChangingConfigurations;
+            if (mGroupName != null) {
+                targetsMap.put(mGroupName, this);
+            }
+
+            mLocalMatrix.set(copy.mLocalMatrix);
+
+            final ArrayList<Object> children = copy.mChildren;
+            //noinspection ForLoopReplaceableByForEach
+            for (int i = 0; i < children.size(); i++) {
+                Object copyChild = children.get(i);
+                if (copyChild instanceof VGroup_Delegate) {
+                    VGroup_Delegate copyGroup = (VGroup_Delegate) copyChild;
+                    mChildren.add(new VGroup_Delegate(copyGroup, targetsMap));
+                } else {
+                    VPath_Delegate newPath;
+                    if (copyChild instanceof VFullPath_Delegate) {
+                        newPath = new VFullPath_Delegate((VFullPath_Delegate) copyChild);
+                    } else if (copyChild instanceof VClipPath_Delegate) {
+                        newPath = new VClipPath_Delegate((VClipPath_Delegate) copyChild);
+                    } else {
+                        throw new IllegalStateException("Unknown object in the tree!");
+                    }
+                    mChildren.add(newPath);
+                    if (newPath.mPathName != null) {
+                        targetsMap.put(newPath.mPathName, newPath);
+                    }
+                }
+            }
+        }
+
+        private VGroup_Delegate() {
+        }
+
+        private void updateLocalMatrix() {
+            // The order we apply is the same as the
+            // RenderNode.cpp::applyViewPropertyTransforms().
+            mLocalMatrix.reset();
+            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
+            mLocalMatrix.postScale(mScaleX, mScaleY);
+            mLocalMatrix.postRotate(mRotate, 0, 0);
+            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+        }
+
+        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+        private float getRotation() {
+            return mRotate;
+        }
+
+        private void setRotation(float rotation) {
+            if (rotation != mRotate) {
+                mRotate = rotation;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getPivotX() {
+            return mPivotX;
+        }
+
+        private void setPivotX(float pivotX) {
+            if (pivotX != mPivotX) {
+                mPivotX = pivotX;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getPivotY() {
+            return mPivotY;
+        }
+
+        private void setPivotY(float pivotY) {
+            if (pivotY != mPivotY) {
+                mPivotY = pivotY;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getScaleX() {
+            return mScaleX;
+        }
+
+        private void setScaleX(float scaleX) {
+            if (scaleX != mScaleX) {
+                mScaleX = scaleX;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getScaleY() {
+            return mScaleY;
+        }
+
+        private void setScaleY(float scaleY) {
+            if (scaleY != mScaleY) {
+                mScaleY = scaleY;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getTranslateX() {
+            return mTranslateX;
+        }
+
+        private void setTranslateX(float translateX) {
+            if (translateX != mTranslateX) {
+                mTranslateX = translateX;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getTranslateY() {
+            return mTranslateY;
+        }
+
+        private void setTranslateY(float translateY) {
+            if (translateY != mTranslateY) {
+                mTranslateY = translateY;
+                updateLocalMatrix();
+            }
+        }
+
+        @Override
+        public void setName(String name) {
+            mGroupName = name;
+        }
+    }
+
+    public static class VPath_Delegate implements VNativeObject {
+        protected PathParser_Delegate.PathDataNode[] mNodes = null;
+        String mPathName;
+        int mChangingConfigurations;
+
+        public VPath_Delegate() {
+            // Empty constructor.
+        }
+
+        public VPath_Delegate(VPath_Delegate copy) {
+            mPathName = copy.mPathName;
+            mChangingConfigurations = copy.mChangingConfigurations;
+            mNodes = PathParser_Delegate.deepCopyNodes(copy.mNodes);
+        }
+
+        public void toPath(Path path) {
+            path.reset();
+            if (mNodes != null) {
+                PathParser_Delegate.PathDataNode.nodesToPath(mNodes,
+                        Path_Delegate.getDelegate(path.mNativePath));
+            }
+        }
+
+        @Override
+        public void setName(String name) {
+            mPathName = name;
+        }
+
+        public boolean isClipPath() {
+            return false;
+        }
+
+        private void setPathData(PathParser_Delegate.PathDataNode[] nodes) {
+            if (!PathParser_Delegate.canMorph(mNodes, nodes)) {
+                // This should not happen in the middle of animation.
+                mNodes = PathParser_Delegate.deepCopyNodes(nodes);
+            } else {
+                PathParser_Delegate.updateNodes(mNodes, nodes);
+            }
+        }
+    }
+
+    static class VPathRenderer_Delegate implements VNativeObject {
+        /* Right now the internal data structure is organized as a tree.
+         * Each node can be a group node, or a path.
+         * A group node can have groups or paths as children, but a path node has
+         * no children.
+         * One example can be:
+         *                 Root Group
+         *                /    |     \
+         *           Group    Path    Group
+         *          /     \             |
+         *         Path   Path         Path
+         *
+         */
+        // Variables that only used temporarily inside the draw() call, so there
+        // is no need for deep copying.
+        private final Path mPath;
+        private final Path mRenderPath;
+        private final Matrix mFinalPathMatrix = new Matrix();
+        private final VGroup_Delegate mRootGroup;
+        private float mViewportWidth = 0;
+        private float mViewportHeight = 0;
+        private float mRootAlpha = 1.0f;
+        private Paint mStrokePaint;
+        private Paint mFillPaint;
+        private PathMeasure mPathMeasure;
+
+        private VPathRenderer_Delegate(VGroup_Delegate rootGroup) {
+            mRootGroup = rootGroup;
+            mPath = new Path();
+            mRenderPath = new Path();
+        }
+
+        private float getRootAlpha() {
+            return mRootAlpha;
+        }
+
+        void setRootAlpha(float alpha) {
+            mRootAlpha = alpha;
+        }
+
+        private void drawGroupTree(VGroup_Delegate currentGroup, Matrix currentMatrix,
+                long canvasPtr, int w, int h, long filterPtr) {
+            // Calculate current group's matrix by preConcat the parent's and
+            // and the current one on the top of the stack.
+            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+            // Mi the local matrix at level i of the group tree.
+            currentGroup.mStackedMatrix.set(currentMatrix);
+            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
+
+            // Save the current clip information, which is local to this group.
+            Canvas_Delegate.native_save(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+            // Draw the group tree in the same order as the XML file.
+            for (int i = 0; i < currentGroup.mChildren.size(); i++) {
+                Object child = currentGroup.mChildren.get(i);
+                if (child instanceof VGroup_Delegate) {
+                    VGroup_Delegate childGroup = (VGroup_Delegate) child;
+                    drawGroupTree(childGroup, currentGroup.mStackedMatrix,
+                            canvasPtr, w, h, filterPtr);
+                } else if (child instanceof VPath_Delegate) {
+                    VPath_Delegate childPath = (VPath_Delegate) child;
+                    drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr);
+                }
+            }
+            Canvas_Delegate.native_restore(canvasPtr, true);
+        }
+
+        public void draw(long canvasPtr, long filterPtr, int w, int h) {
+            // Traverse the tree in pre-order to draw.
+            drawGroupTree(mRootGroup, Matrix.IDENTITY_MATRIX, canvasPtr, w, h, filterPtr);
+        }
+
+        private void drawPath(VGroup_Delegate VGroup, VPath_Delegate VPath, long canvasPtr,
+                int w,
+                int h,
+                long filterPtr) {
+            final float scaleX = w / mViewportWidth;
+            final float scaleY = h / mViewportHeight;
+            final float minScale = Math.min(scaleX, scaleY);
+            final Matrix groupStackedMatrix = VGroup.mStackedMatrix;
+
+            mFinalPathMatrix.set(groupStackedMatrix);
+            mFinalPathMatrix.postScale(scaleX, scaleY);
+
+            final float matrixScale = getMatrixScale(groupStackedMatrix);
+            if (matrixScale == 0) {
+                // When either x or y is scaled to 0, we don't need to draw anything.
+                return;
+            }
+            VPath.toPath(mPath);
+            final Path path = mPath;
+
+            mRenderPath.reset();
+
+            if (VPath.isClipPath()) {
+                mRenderPath.addPath(path, mFinalPathMatrix);
+                Canvas_Delegate.native_clipPath(canvasPtr, mRenderPath.mNativePath, Op
+                        .INTERSECT.nativeInt);
+            } else {
+                VFullPath_Delegate fullPath = (VFullPath_Delegate) VPath;
+                if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
+                    float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
+                    float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
+
+                    if (mPathMeasure == null) {
+                        mPathMeasure = new PathMeasure();
+                    }
+                    mPathMeasure.setPath(mPath, false);
+
+                    float len = mPathMeasure.getLength();
+                    start = start * len;
+                    end = end * len;
+                    path.reset();
+                    if (start > end) {
+                        mPathMeasure.getSegment(start, len, path, true);
+                        mPathMeasure.getSegment(0f, end, path, true);
+                    } else {
+                        mPathMeasure.getSegment(start, end, path, true);
+                    }
+                    path.rLineTo(0, 0); // fix bug in measure
+                }
+                mRenderPath.addPath(path, mFinalPathMatrix);
+
+                if (fullPath.mFillColor != Color.TRANSPARENT) {
+                    if (mFillPaint == null) {
+                        mFillPaint = new Paint();
+                        mFillPaint.setStyle(Style.FILL);
+                        mFillPaint.setAntiAlias(true);
+                    }
+
+                    final Paint fillPaint = mFillPaint;
+                    fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
+                    Paint_Delegate fillPaintDelegate = Paint_Delegate.getDelegate(fillPaint
+                            .getNativeInstance());
+                    // mFillPaint can not be null at this point so we will have a delegate
+                    assert fillPaintDelegate != null;
+                    fillPaintDelegate.setColorFilter(filterPtr);
+                    fillPaintDelegate.setShader(fullPath.mFillGradient);
+                    Path_Delegate.native_setFillType(mRenderPath.mNativePath, fullPath.mFillType);
+                    Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
+                            .getNativeInstance());
+                }
+
+                if (fullPath.mStrokeColor != Color.TRANSPARENT) {
+                    if (mStrokePaint == null) {
+                        mStrokePaint = new Paint();
+                        mStrokePaint.setStyle(Style.STROKE);
+                        mStrokePaint.setAntiAlias(true);
+                    }
+
+                    final Paint strokePaint = mStrokePaint;
+                    if (fullPath.mStrokeLineJoin != null) {
+                        strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
+                    }
+
+                    if (fullPath.mStrokeLineCap != null) {
+                        strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
+                    }
+
+                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
+                    strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
+                    Paint_Delegate strokePaintDelegate = Paint_Delegate.getDelegate(strokePaint
+                            .getNativeInstance());
+                    // mStrokePaint can not be null at this point so we will have a delegate
+                    assert strokePaintDelegate != null;
+                    strokePaintDelegate.setColorFilter(filterPtr);
+                    final float finalStrokeScale = minScale * matrixScale;
+                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
+                    strokePaintDelegate.setShader(fullPath.mStrokeGradient);
+                    Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
+                            .getNativeInstance());
+                }
+            }
+        }
+
+        private float getMatrixScale(Matrix groupStackedMatrix) {
+            // Given unit vectors A = (0, 1) and B = (1, 0).
+            // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+            // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+            // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+            // If  max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+            //
+            // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+            // scale on x and y axis, and take the minimal of these two.
+            // For skew case, an unit square will mapped to a parallelogram. And this function will
+            // return the minimal height of the 2 bases.
+            float[] unitVectors = new float[]{0, 1, 1, 0};
+            groupStackedMatrix.mapVectors(unitVectors);
+            float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
+            float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
+            float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
+                    unitVectors[2], unitVectors[3]);
+            float maxScale = MathUtils.max(scaleX, scaleY);
+
+            float matrixScale = 0;
+            if (maxScale > 0) {
+                matrixScale = MathUtils.abs(crossProduct) / maxScale;
+            }
+            if (DBG_VECTOR_DRAWABLE) {
+                Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
+            }
+            return matrixScale;
+        }
+
+        @Override
+        public void setName(String name) {
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
index d3af837..6c34c70 100644
--- a/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
@@ -24,7 +24,6 @@
 import android.annotation.NonNull;
 import android.graphics.Path_Delegate;
 
-import java.awt.geom.Path2D;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.logging.Level;
@@ -52,10 +51,18 @@
     @NonNull
     private PathDataNode[] mPathDataNodes;
 
+    public static PathParser_Delegate getDelegate(long nativePtr) {
+        return sManager.getDelegate(nativePtr);
+    }
+
     private PathParser_Delegate(@NonNull PathDataNode[] nodes) {
         mPathDataNodes = nodes;
     }
 
+    public PathDataNode[] getPathDataNodes() {
+        return mPathDataNodes;
+    }
+
     @LayoutlibDelegate
     /*package*/ static boolean nParseStringForPath(long pathPtr, @NonNull String pathString, int
             stringLength) {
@@ -64,7 +71,7 @@
             return false;
         }
         assert pathString.length() == stringLength;
-        PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate.getJavaShape());
+        PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate);
         return true;
     }
 
@@ -75,7 +82,7 @@
         if (source == null || path_delegate == null) {
             return;
         }
-        PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate.getJavaShape());
+        PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate);
     }
 
     @LayoutlibDelegate
@@ -124,8 +131,11 @@
             out.mPathDataNodes = new PathDataNode[length];
         }
         for (int i = 0; i < length; i++) {
+            if (out.mPathDataNodes[i] == null) {
+                out.mPathDataNodes[i] = new PathDataNode(from.mPathDataNodes[i]);
+            }
             out.mPathDataNodes[i].interpolatePathDataNode(from.mPathDataNodes[i],
-                    to.mPathDataNodes[i], fraction);
+                        to.mPathDataNodes[i], fraction);
         }
         return true;
     }
@@ -137,9 +147,13 @@
 
     @LayoutlibDelegate
     /*package*/ static boolean nCanMorph(long fromDataPtr, long toDataPtr) {
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "morphing path data isn't " +
-                "supported", null, null);
-        return false;
+        PathParser_Delegate fromPath = PathParser_Delegate.getDelegate(fromDataPtr);
+        PathParser_Delegate toPath = PathParser_Delegate.getDelegate(toDataPtr);
+        if (fromPath == null || toPath == null || fromPath.getPathDataNodes() == null || toPath
+                .getPathDataNodes() == null) {
+            return true;
+        }
+        return PathParser_Delegate.canMorph(fromPath.getPathDataNodes(), toPath.getPathDataNodes());
     }
 
     @LayoutlibDelegate
@@ -158,7 +172,7 @@
      * @return an array of the PathDataNode.
      */
     @NonNull
-    private static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
+    public static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
         int start = 0;
         int end = 1;
 
@@ -186,7 +200,7 @@
      * @return a deep copy of the <code>source</code>.
      */
     @NonNull
-    private static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
+    public static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
         PathDataNode[] copy = new PathDataNode[source.length];
         for (int i = 0; i < source.length; i++) {
             copy[i] = new PathDataNode(source[i]);
@@ -194,6 +208,45 @@
         return copy;
     }
 
+    /**
+     * @param nodesFrom The source path represented in an array of PathDataNode
+     * @param nodesTo The target path represented in an array of PathDataNode
+     * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code>
+     */
+    public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) {
+        if (nodesFrom == null || nodesTo == null) {
+            return false;
+        }
+
+        if (nodesFrom.length != nodesTo.length) {
+            return false;
+        }
+
+        for (int i = 0; i < nodesFrom.length; i ++) {
+            if (nodesFrom[i].mType != nodesTo[i].mType
+                    || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Update the target's data to match the source.
+     * Before calling this, make sure canMorph(target, source) is true.
+     *
+     * @param target The target path represented in an array of PathDataNode
+     * @param source The source path represented in an array of PathDataNode
+     */
+    public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
+        for (int i = 0; i < source.length; i ++) {
+            target[i].mType = source[i].mType;
+            for (int j = 0; j < source[i].mParams.length; j ++) {
+                target[i].mParams[j] = source[i].mParams[j];
+            }
+        }
+    }
+
     private static int nextStart(@NonNull String s, int end) {
         char c;
 
@@ -330,7 +383,7 @@
      * Each PathDataNode represents one command in the "d" attribute of the svg file. An array of
      * PathDataNode can represent the whole "d" attribute.
      */
-    private static class PathDataNode {
+    public static class PathDataNode {
         private char mType;
         @NonNull
         private float[] mParams;
@@ -355,12 +408,13 @@
         }
 
         /**
-         * Convert an array of PathDataNode to Path.
+         * Convert an array of PathDataNode to Path. Reset the passed path as needed before
+         * calling this method.
          *
          * @param node The source array of PathDataNode.
          * @param path The target Path object.
          */
-        private static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path2D path) {
+        public static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path_Delegate path) {
             float[] current = new float[6];
             char previousCommand = 'm';
             //noinspection ForLoopReplaceableByForEach
@@ -387,24 +441,32 @@
         }
 
         @SuppressWarnings("PointlessArithmeticExpression")
-        private static void addCommand(@NonNull Path2D path, float[] current, char cmd,
-                char lastCmd, @NonNull float[] val) {
+        private static void addCommand(@NonNull Path_Delegate path, float[] current,
+                char previousCmd, char cmd, @NonNull float[] val) {
 
             int incr = 2;
-
-            float cx = current[0];
-            float cy = current[1];
-            float cpx = current[2];
-            float cpy = current[3];
-            float loopX = current[4];
-            float loopY = current[5];
+            float currentX = current[0];
+            float currentY = current[1];
+            float ctrlPointX = current[2];
+            float ctrlPointY = current[3];
+            float currentSegmentStartX = current[4];
+            float currentSegmentStartY = current[5];
+            float reflectiveCtrlPointX;
+            float reflectiveCtrlPointY;
 
             switch (cmd) {
                 case 'z':
                 case 'Z':
-                    path.closePath();
-                    cx = loopX;
-                    cy = loopY;
+                    path.close();
+                    // Path is closed here, but we need to move the pen to the
+                    // closed position. So we cache the segment's starting position,
+                    // and restore it here.
+                    currentX = currentSegmentStartX;
+                    currentY = currentSegmentStartY;
+                    ctrlPointX = currentSegmentStartX;
+                    ctrlPointY = currentSegmentStartY;
+                    path.moveTo(currentX, currentY);
+                    break;
                 case 'm':
                 case 'M':
                 case 'l':
@@ -432,185 +494,206 @@
                 case 'a':
                 case 'A':
                     incr = 7;
+                    break;
             }
 
             for (int k = 0; k < val.length; k += incr) {
-                boolean reflectCtrl;
-                float tempReflectedX, tempReflectedY;
-
                 switch (cmd) {
-                    case 'm':
-                        cx += val[k + 0];
-                        cy += val[k + 1];
+                    case 'm': // moveto - Start a new sub-path (relative)
+                        currentX += val[k + 0];
+                        currentY += val[k + 1];
+
                         if (k > 0) {
                             // According to the spec, if a moveto is followed by multiple
                             // pairs of coordinates, the subsequent pairs are treated as
                             // implicit lineto commands.
-                            path.lineTo(cx, cy);
+                            path.rLineTo(val[k + 0], val[k + 1]);
                         } else {
-                            path.moveTo(cx, cy);
-                            loopX = cx;
-                            loopY = cy;
+                            path.rMoveTo(val[k + 0], val[k + 1]);
+                            currentSegmentStartX = currentX;
+                            currentSegmentStartY = currentY;
                         }
                         break;
-                    case 'M':
-                        cx = val[k + 0];
-                        cy = val[k + 1];
+                    case 'M': // moveto - Start a new sub-path
+                        currentX = val[k + 0];
+                        currentY = val[k + 1];
+
                         if (k > 0) {
                             // According to the spec, if a moveto is followed by multiple
                             // pairs of coordinates, the subsequent pairs are treated as
                             // implicit lineto commands.
-                            path.lineTo(cx, cy);
+                            path.lineTo(val[k + 0], val[k + 1]);
                         } else {
-                            path.moveTo(cx, cy);
-                            loopX = cx;
-                            loopY = cy;
+                            path.moveTo(val[k + 0], val[k + 1]);
+                            currentSegmentStartX = currentX;
+                            currentSegmentStartY = currentY;
                         }
                         break;
-                    case 'l':
-                        cx += val[k + 0];
-                        cy += val[k + 1];
-                        path.lineTo(cx, cy);
+                    case 'l': // lineto - Draw a line from the current point (relative)
+                        path.rLineTo(val[k + 0], val[k + 1]);
+                        currentX += val[k + 0];
+                        currentY += val[k + 1];
                         break;
-                    case 'L':
-                        cx = val[k + 0];
-                        cy = val[k + 1];
-                        path.lineTo(cx, cy);
+                    case 'L': // lineto - Draw a line from the current point
+                        path.lineTo(val[k + 0], val[k + 1]);
+                        currentX = val[k + 0];
+                        currentY = val[k + 1];
                         break;
-                    case 'z':
-                    case 'Z':
-                        path.closePath();
-                        cx = loopX;
-                        cy = loopY;
+                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
+                        path.rLineTo(val[k + 0], 0);
+                        currentX += val[k + 0];
                         break;
-                    case 'h':
-                        cx += val[k + 0];
-                        path.lineTo(cx, cy);
+                    case 'H': // horizontal lineto - Draws a horizontal line
+                        path.lineTo(val[k + 0], currentY);
+                        currentX = val[k + 0];
                         break;
-                    case 'H':
-                        path.lineTo(val[k + 0], cy);
-                        cx = val[k + 0];
+                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
+                        path.rLineTo(0, val[k + 0]);
+                        currentY += val[k + 0];
                         break;
-                    case 'v':
-                        cy += val[k + 0];
-                        path.lineTo(cx, cy);
+                    case 'V': // vertical lineto - Draws a vertical line from the current point
+                        path.lineTo(currentX, val[k + 0]);
+                        currentY = val[k + 0];
                         break;
-                    case 'V':
-                        path.lineTo(cx, val[k + 0]);
-                        cy = val[k + 0];
-                        break;
-                    case 'c':
-                        path.curveTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
-                                cy + val[k + 3], cx + val[k + 4], cy + val[k + 5]);
-                        cpx = cx + val[k + 2];
-                        cpy = cy + val[k + 3];
-                        cx += val[k + 4];
-                        cy += val[k + 5];
-                        break;
-                    case 'C':
-                        path.curveTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
+                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
                                 val[k + 4], val[k + 5]);
-                        cx = val[k + 4];
-                        cy = val[k + 5];
-                        cpx = val[k + 2];
-                        cpy = val[k + 3];
-                        break;
-                    case 's':
-                        reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
-                                lastCmd == 'S');
-                        path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
-                                * cy - cpy : cy, cx + val[k + 0], cy + val[k + 1], cx
-                                + val[k + 2], cy + val[k + 3]);
 
-                        cpx = cx + val[k + 0];
-                        cpy = cy + val[k + 1];
-                        cx += val[k + 2];
-                        cy += val[k + 3];
+                        ctrlPointX = currentX + val[k + 2];
+                        ctrlPointY = currentY + val[k + 3];
+                        currentX += val[k + 4];
+                        currentY += val[k + 5];
+
                         break;
-                    case 'S':
-                        reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
-                                lastCmd == 'S');
-                        path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
-                                        * cy - cpy : cy, val[k + 0], val[k + 1], val[k + 2],
-                                val[k + 3]);
-                        cpx = (val[k + 0]);
-                        cpy = (val[k + 1]);
-                        cx = val[k + 2];
-                        cy = val[k + 3];
+                    case 'C': // curveto - Draws a cubic Bézier curve
+                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                                val[k + 4], val[k + 5]);
+                        currentX = val[k + 4];
+                        currentY = val[k + 5];
+                        ctrlPointX = val[k + 2];
+                        ctrlPointY = val[k + 3];
                         break;
-                    case 'q':
-                        path.quadTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
-                                cy + val[k + 3]);
-                        cpx = cx + val[k + 0];
-                        cpy = cy + val[k + 1];
-                        // Note that we have to update cpx first, since cx will be updated here.
-                        cx += val[k + 2];
-                        cy += val[k + 3];
+                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1],
+                                val[k + 2], val[k + 3]);
+
+                        ctrlPointX = currentX + val[k + 0];
+                        ctrlPointY = currentY + val[k + 1];
+                        currentX += val[k + 2];
+                        currentY += val[k + 3];
                         break;
-                    case 'Q':
+                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+                        ctrlPointX = val[k + 0];
+                        ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
+                        break;
+                    case 'q': // Draws a quadratic Bézier (relative)
+                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+                        ctrlPointX = currentX + val[k + 0];
+                        ctrlPointY = currentY + val[k + 1];
+                        currentX += val[k + 2];
+                        currentY += val[k + 3];
+                        break;
+                    case 'Q': // Draws a quadratic Bézier
                         path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
-                        cx = val[k + 2];
-                        cy = val[k + 3];
-                        cpx = val[k + 0];
-                        cpy = val[k + 1];
+                        ctrlPointX = val[k + 0];
+                        ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
                         break;
-                    case 't':
-                        reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
-                                lastCmd == 'T');
-                        tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
-                        tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
-                        path.quadTo(tempReflectedX, tempReflectedY, cx + val[k + 0],
-                                cy + val[k + 1]);
-                        cpx = tempReflectedX;
-                        cpy = tempReflectedY;
-                        cx += val[k + 0];
-                        cy += val[k + 1];
+                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1]);
+                        ctrlPointX = currentX + reflectiveCtrlPointX;
+                        ctrlPointY = currentY + reflectiveCtrlPointY;
+                        currentX += val[k + 0];
+                        currentY += val[k + 1];
                         break;
-                    case 'T':
-                        reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
-                                lastCmd == 'T');
-                        tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
-                        tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
-                        path.quadTo(tempReflectedX, tempReflectedY, val[k + 0], val[k + 1]);
-                        cx = val[k + 0];
-                        cy = val[k + 1];
-                        cpx = tempReflectedX;
-                        cpy = tempReflectedY;
+                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1]);
+                        ctrlPointX = reflectiveCtrlPointX;
+                        ctrlPointY = reflectiveCtrlPointY;
+                        currentX = val[k + 0];
+                        currentY = val[k + 1];
                         break;
-                    case 'a':
+                    case 'a': // Draws an elliptical arc
                         // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
-                        drawArc(path, cx, cy, val[k + 5] + cx, val[k + 6] + cy,
-                                val[k + 0], val[k + 1], val[k + 2], val[k + 3] != 0,
+                        drawArc(path,
+                                currentX,
+                                currentY,
+                                val[k + 5] + currentX,
+                                val[k + 6] + currentY,
+                                val[k + 0],
+                                val[k + 1],
+                                val[k + 2],
+                                val[k + 3] != 0,
                                 val[k + 4] != 0);
-                        cx += val[k + 5];
-                        cy += val[k + 6];
-                        cpx = cx;
-                        cpy = cy;
-
+                        currentX += val[k + 5];
+                        currentY += val[k + 6];
+                        ctrlPointX = currentX;
+                        ctrlPointY = currentY;
                         break;
-                    case 'A':
-                        drawArc(path, cx, cy, val[k + 5], val[k + 6], val[k + 0],
-                                val[k + 1], val[k + 2], val[k + 3] != 0,
+                    case 'A': // Draws an elliptical arc
+                        drawArc(path,
+                                currentX,
+                                currentY,
+                                val[k + 5],
+                                val[k + 6],
+                                val[k + 0],
+                                val[k + 1],
+                                val[k + 2],
+                                val[k + 3] != 0,
                                 val[k + 4] != 0);
-                        cx = val[k + 5];
-                        cy = val[k + 6];
-                        cpx = cx;
-                        cpy = cy;
+                        currentX = val[k + 5];
+                        currentY = val[k + 6];
+                        ctrlPointX = currentX;
+                        ctrlPointY = currentY;
                         break;
-
                 }
-                lastCmd = cmd;
+                previousCmd = cmd;
             }
-            current[0] = cx;
-            current[1] = cy;
-            current[2] = cpx;
-            current[3] = cpy;
-            current[4] = loopX;
-            current[5] = loopY;
-
+            current[0] = currentX;
+            current[1] = currentY;
+            current[2] = ctrlPointX;
+            current[3] = ctrlPointY;
+            current[4] = currentSegmentStartX;
+            current[5] = currentSegmentStartY;
         }
 
-        private static void drawArc(@NonNull Path2D p, float x0, float y0, float x1,
+        private static void drawArc(@NonNull Path_Delegate p, float x0, float y0, float x1,
                 float y1, float a, float b, float theta, boolean isMoreThanHalf,
                 boolean isPositiveArc) {
 
@@ -707,7 +790,7 @@
          * @param start The start angle of the arc on the ellipse
          * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
          */
-        private static void arcToBezier(@NonNull Path2D p, double cx, double cy, double a,
+        private static void arcToBezier(@NonNull Path_Delegate p, double cx, double cy, double a,
                 double b, double e1x, double e1y, double theta, double start,
                 double sweep) {
             // Taken from equations at:
@@ -744,8 +827,12 @@
                 double q2x = e2x - alpha * ep2x;
                 double q2y = e2y - alpha * ep2y;
 
-                p.curveTo((float) q1x, (float) q1y, (float) q2x, (float) q2y,
-                        (float) e2x, (float) e2y);
+                p.cubicTo((float) q1x,
+                        (float) q1y,
+                        (float) q2x,
+                        (float) q2y,
+                        (float) e2x,
+                        (float) e2y);
                 eta1 = eta2;
                 e1x = e2x;
                 e1y = e2y;
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 4901f72..94f3f54 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -45,4 +45,10 @@
     public static void dispatchOnPreDraw(View view) {
         view.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
     }
+
+    public static void detachFromWindow(View view) {
+        if (view != null) {
+            view.dispatchDetachedFromWindow();
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 723e827..bdddfd8 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -265,12 +265,15 @@
             if (viewKey != null) {
                 bc.addViewKey(view, viewKey);
             }
-            String scrollPos = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES, "scrollY");
-            if (scrollPos != null) {
-                if (scrollPos.endsWith("px")) {
-                    int value = Integer.parseInt(scrollPos.substring(0, scrollPos.length() - 2));
-                    bc.setScrollYPos(view, value);
-                }
+            String scrollPosX = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES, "scrollX");
+            if (scrollPosX != null && scrollPosX.endsWith("px")) {
+                int value = Integer.parseInt(scrollPosX.substring(0, scrollPosX.length() - 2));
+                bc.setScrollXPos(view, value);
+            }
+            String scrollPosY = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES, "scrollY");
+            if (scrollPosY != null && scrollPosY.endsWith("px")) {
+                int value = Integer.parseInt(scrollPosY.substring(0, scrollPosY.length() - 2));
+                bc.setScrollYPos(view, value);
             }
             if (ReflectionUtils.isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
                 Integer resourceId = null;
diff --git a/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java b/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java
index 01af669..6cd67c6 100644
--- a/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java
@@ -15,8 +15,11 @@
  */
 package android.view;
 
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import java.lang.reflect.Field;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -64,4 +67,17 @@
 
         thisChoreographer.doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
     }
+
+    public static void dispose() {
+        try {
+            Field threadInstanceField = Choreographer.class.getDeclaredField("sThreadInstance");
+            @SuppressWarnings("unchecked") ThreadLocal<Choreographer> threadInstance =
+                    (ThreadLocal<Choreographer>) threadInstanceField.get(null);
+            threadInstance.remove();
+        } catch (ReflectiveOperationException e) {
+            assert false;
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                    "Unable to clear Choreographer memory.", e, null);
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/HandlerActionQueue_Delegate.java b/tools/layoutlib/bridge/src/android/view/HandlerActionQueue_Delegate.java
new file mode 100644
index 0000000..e580ed0
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/HandlerActionQueue_Delegate.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of
+ * {@link HandlerActionQueue}
+ *
+ * Through the layoutlib_create tool, the original  methods of ViewRootImpl.RunQueue have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ */
+public class HandlerActionQueue_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static void postDelayed(HandlerActionQueue thisQueue, Runnable action, long
+            delayMillis) {
+        // The actual HandlerActionQueue is never run and therefore never cleared. This method
+        // avoids runnables to be added to the RunQueue so they do not leak resources.
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 8d1b124..f9e008e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -20,6 +20,7 @@
 import android.graphics.Rect;
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IShortcutService;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 
@@ -348,7 +349,7 @@
     }
 
     @Override
-    public void notifyAppStopped(IBinder token) throws RemoteException {
+    public void notifyAppStopped(IBinder token, boolean stopped) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -402,8 +403,15 @@
     }
 
     @Override
-    public void setNewConfiguration(Configuration arg0) throws RemoteException {
+    public int[] setNewConfiguration(Configuration arg0) throws RemoteException {
         // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Rect getBoundsForNewConfiguration(int stackId) throws RemoteException {
+        // TODO Auto-generated method stub
+        return null;
     }
 
     @Override
@@ -491,8 +499,7 @@
     }
 
     @Override
-    public void keyguardGoingAway(boolean disableWindowAnimations,
-            boolean keyguardGoingToNotificationShade) throws RemoteException {
+    public void keyguardGoingAway(int flags) throws RemoteException {
     }
 
     @Override
@@ -560,10 +567,25 @@
     }
 
     @Override
-    public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+    public void setDockedStackDividerTouchRegion(Rect touchableRegion) throws RemoteException {
+    }
+
+    @Override
+    public void requestAppKeyboardShortcuts(
+            IResultReceiver receiver, int deviceId) throws RemoteException {
     }
 
     @Override
     public void getStableInsets(Rect outInsets) throws RemoteException {
     }
+
+    @Override
+    public void registerShortcutKey(long shortcutCode, IShortcutService service)
+        throws RemoteException {}
+
+    @Override
+    public void createWallpaperInputConsumer(InputChannel inputChannel) throws RemoteException {}
+
+    @Override
+    public void removeWallpaperInputConsumer() throws RemoteException {}
 }
diff --git a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
index 1465f50..24f7887 100644
--- a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
@@ -55,7 +55,7 @@
     private String mName;
 
     @LayoutlibDelegate
-    /*package*/ static long nCreate(String name) {
+    /*package*/ static long nCreate(RenderNode thisRenderNode, String name) {
         RenderNode_Delegate renderNodeDelegate = new RenderNode_Delegate();
         renderNodeDelegate.mName = name;
         return sManager.addNewDelegate(renderNodeDelegate);
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index 411417c..1ea8a9f 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -141,9 +141,4 @@
     public void onActionModeFinished(ActionMode mode) {
 
     }
-
-    @Override
-    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, @Nullable Menu menu) {
-
-    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
new file mode 100644
index 0000000..01fe45d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.util.LongSparseLongArray;
+
+/**
+ * Delegate used to provide new implementation the native methods of {@link VirtualRefBasePtr}
+ *
+ * Through the layoutlib_create tool, the original native  methods of VirtualRefBasePtr have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ */
+@SuppressWarnings("unused")
+public class VirtualRefBasePtr_Delegate {
+    private static final DelegateManager<Object> sManager = new DelegateManager<>(Object.class);
+    private static final LongSparseLongArray sRefCount = new LongSparseLongArray();
+
+    @LayoutlibDelegate
+    /*package*/ static synchronized void nIncStrong(long ptr) {
+        long counter = sRefCount.get(ptr);
+        sRefCount.put(ptr, ++counter);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static synchronized void nDecStrong(long ptr) {
+        long counter = sRefCount.get(ptr);
+
+        if (counter > 1) {
+            sRefCount.put(ptr, --counter);
+        } else {
+            sRefCount.delete(ptr);
+            sManager.removeJavaReferenceFor(ptr);
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
new file mode 100644
index 0000000..0f39e80
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.util.MathUtils;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnticipateInterpolator;
+import android.view.animation.AnticipateOvershootInterpolator;
+import android.view.animation.BaseInterpolator;
+import android.view.animation.BounceInterpolator;
+import android.view.animation.CycleInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.OvershootInterpolator;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link
+ * NativeInterpolatorFactoryHelper}
+ * <p>
+ * Through the layoutlib_create tool, the original  methods of NativeInterpolatorFactoryHelper have
+ * been replaced by calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class NativeInterpolatorFactoryHelper_Delegate {
+    private static final DelegateManager<Interpolator> sManager = new DelegateManager<>
+            (Interpolator.class);
+
+    public static Interpolator getDelegate(long nativePtr) {
+        return sManager.getDelegate(nativePtr);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createAccelerateDecelerateInterpolator() {
+        return sManager.addNewDelegate(new AccelerateDecelerateInterpolator());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createAccelerateInterpolator(float factor) {
+        return sManager.addNewDelegate(new AccelerateInterpolator(factor));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createAnticipateInterpolator(float tension) {
+        return sManager.addNewDelegate(new AnticipateInterpolator(tension));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createAnticipateOvershootInterpolator(float tension) {
+        return sManager.addNewDelegate(new AnticipateOvershootInterpolator(tension));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createBounceInterpolator() {
+        return sManager.addNewDelegate(new BounceInterpolator());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createCycleInterpolator(float cycles) {
+        return sManager.addNewDelegate(new CycleInterpolator(cycles));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createDecelerateInterpolator(float factor) {
+        return sManager.addNewDelegate(new DecelerateInterpolator(factor));
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createLinearInterpolator() {
+        return sManager.addNewDelegate(new LinearInterpolator());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createOvershootInterpolator(float tension) {
+        return sManager.addNewDelegate(new OvershootInterpolator(tension));
+    }
+
+    private static class LutInterpolator extends BaseInterpolator {
+        private final float[] mValues;
+        private final int mSize;
+
+        private LutInterpolator(float[] values) {
+            mValues = values;
+            mSize = mValues.length;
+        }
+
+        @Override
+        public float getInterpolation(float input) {
+            float lutpos = input * mSize;
+            if (lutpos >= (mSize - 1)) {
+                return mValues[mSize - 1];
+            }
+
+            int ipart = (int) lutpos;
+            float weight = lutpos - ipart;
+
+            int i1 = ipart;
+            int i2 = Math.min(i1 + 1, mSize - 1);
+
+            assert i1 >= 0 && i2 >= 0 : "Negatives in the interpolation";
+
+            return MathUtils.lerp(mValues[i1], mValues[i2], weight);
+        }
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long createLutInterpolator(float[] values) {
+        return sManager.addNewDelegate(new LutInterpolator(values));
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index c8e3d03..9e50ee8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -24,6 +24,7 @@
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.Result.Status;
 import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 import com.android.layoutlib.bridge.impl.RenderDrawable;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 import com.android.layoutlib.bridge.util.DynamicIdMap;
@@ -408,7 +409,9 @@
     /**
      * Starts a layout session by inflating and rendering it. The method returns a
      * {@link RenderSession} on which further actions can be taken.
-     *
+     * <p/>
+     * If {@link SessionParams} includes the {@link RenderParamsFlags#FLAG_DO_NOT_RENDER_ON_CREATE},
+     * this method will only inflate the layout but will NOT render it.
      * @param params the {@link SessionParams} object with all the information necessary to create
      *           the scene.
      * @return a new {@link RenderSession} object that contains the result of the layout.
@@ -424,7 +427,10 @@
                 lastResult = scene.init(params.getTimeout());
                 if (lastResult.isSuccess()) {
                     lastResult = scene.inflate();
-                    if (lastResult.isSuccess()) {
+
+                    boolean doNotRenderOnCreate = Boolean.TRUE.equals(
+                            params.getFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE));
+                    if (lastResult.isSuccess() && !doNotRenderOnCreate) {
                         lastResult = scene.render(true /*freshRender*/);
                     }
                 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index 2ac212c..fea633e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -208,6 +208,9 @@
 
     @Override
     public void dispose() {
+        if (mSession != null) {
+            mSession.dispose();
+        }
     }
 
     /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 17ab2ff5..2399b3a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -52,11 +52,11 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.BridgeAssetManager;
-import android.content.res.BridgeResources;
 import android.content.res.BridgeTypedArray;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
+import android.content.res.Resources_Delegate;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
@@ -110,13 +110,13 @@
 public final class BridgeContext extends Context {
 
     /** The map adds cookies to each view so that IDE can link xml tags to views. */
-    private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
+    private final HashMap<View, Object> mViewKeyMap = new HashMap<>();
     /**
      * In some cases, when inflating an xml, some objects are created. Then later, the objects are
      * converted to views. This map stores the mapping from objects to cookies which can then be
      * used to populate the mViewKeyMap.
      */
-    private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<Object, Object>();
+    private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<>();
     private final BridgeAssetManager mAssets;
     private Resources mSystemResources;
     private final Object mProjectKey;
@@ -127,12 +127,12 @@
     private final LayoutlibCallback mLayoutlibCallback;
     private final WindowManager mWindowManager;
     private final DisplayManager mDisplayManager;
-    private final HashMap<View, Integer> mScrollYPos = new HashMap<View, Integer>();
+    private final HashMap<View, Integer> mScrollYPos = new HashMap<>();
+    private final HashMap<View, Integer> mScrollXPos = new HashMap<>();
 
     private Resources.Theme mTheme;
 
-    private final Map<Object, Map<String, String>> mDefaultPropMaps =
-        new IdentityHashMap<Object, Map<String,String>>();
+    private final Map<Object, PropertiesMap> mDefaultPropMaps = new IdentityHashMap<>();
 
     // maps for dynamically generated id representing style objects (StyleResourceValue)
     @Nullable
@@ -141,13 +141,12 @@
     private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
 
     // cache for TypedArray generated from StyleResourceValue object
-    private Map<int[], Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>
-            mTypedArrayCache;
+    private TypedArrayCache mTypedArrayCache;
     private BridgeInflater mBridgeInflater;
 
     private BridgeContentResolver mContentResolver;
 
-    private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
+    private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<>();
     private SharedPreferences mSharedPreferences;
     private ClassLoader mClassLoader;
     private IBinder mBinder;
@@ -161,15 +160,15 @@
      * This a map from value to attribute name. Warning for missing references shouldn't be logged
      * if value and attr name pair is the same as an entry in this map.
      */
-    private static Map<String, String> RTL_ATTRS = new HashMap<String, String>(10);
+    private static Map<String, String> RTL_ATTRS = new HashMap<>(10);
 
     static {
         RTL_ATTRS.put("?android:attr/paddingLeft", "paddingStart");
         RTL_ATTRS.put("?android:attr/paddingRight", "paddingEnd");
         RTL_ATTRS.put("?android:attr/layout_marginLeft", "layout_marginStart");
         RTL_ATTRS.put("?android:attr/layout_marginRight", "layout_marginEnd");
-        RTL_ATTRS.put("?android:attr/layout_toLeft", "layout_toStartOf");
-        RTL_ATTRS.put("?android:attr/layout_toRight", "layout_toEndOf");
+        RTL_ATTRS.put("?android:attr/layout_toLeftOf", "layout_toStartOf");
+        RTL_ATTRS.put("?android:attr/layout_toRightOf", "layout_toEndOf");
         RTL_ATTRS.put("?android:attr/layout_alignParentLeft", "layout_alignParentStart");
         RTL_ATTRS.put("?android:attr/layout_alignParentRight", "layout_alignParentEnd");
         RTL_ATTRS.put("?android:attr/drawableLeft", "drawableStart");
@@ -224,7 +223,7 @@
     public void initResources() {
         AssetManager assetManager = AssetManager.getSystem();
 
-        mSystemResources = BridgeResources.initSystem(
+        mSystemResources = Resources_Delegate.initSystem(
                 this,
                 assetManager,
                 mMetrics,
@@ -237,7 +236,7 @@
      * Disposes the {@link Resources} singleton.
      */
     public void disposeResources() {
-        BridgeResources.disposeSystem();
+        Resources_Delegate.disposeSystem();
     }
 
     public void setBridgeInflater(BridgeInflater inflater) {
@@ -324,11 +323,11 @@
         return mParserStack.get(mParserStack.size() - 2);
     }
 
-    public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
-        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid);
+    public boolean resolveThemeAttribute(int resId, TypedValue outValue, boolean resolveRefs) {
+        Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resId);
         boolean isFrameworkRes = true;
         if (resourceInfo == null) {
-            resourceInfo = mLayoutlibCallback.resolveResourceId(resid);
+            resourceInfo = mLayoutlibCallback.resolveResourceId(resId);
             isFrameworkRes = false;
         }
 
@@ -601,23 +600,20 @@
 
     @Override
     public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {
-        // No style is specified here, so create the typed array based on the default theme
-        // and the styles already applied to it. A null value of style indicates that the default
-        // theme should be used.
-        return createStyleBasedTypedArray(null, attrs);
+        return obtainStyledAttributes(0, attrs);
     }
 
     @Override
-    public final BridgeTypedArray obtainStyledAttributes(int resid, int[] attrs)
+    public final BridgeTypedArray obtainStyledAttributes(int resId, int[] attrs)
             throws Resources.NotFoundException {
         StyleResourceValue style = null;
         // get the StyleResourceValue based on the resId;
-        if (resid != 0) {
-            style = getStyleByDynamicId(resid);
+        if (resId != 0) {
+            style = getStyleByDynamicId(resId);
 
             if (style == null) {
                 // In some cases, style may not be a dynamic id, so we do a full search.
-                ResourceReference ref = resolveId(resid);
+                ResourceReference ref = resolveId(resId);
                 if (ref != null) {
                     style = mRenderResources.getStyle(ref.getName(), ref.isFramework());
                 }
@@ -628,41 +624,33 @@
             }
         }
 
-        // The map is from
-        // attrs (int[]) -> context's current themes (List<StyleRV>) -> resid (int) -> typed array.
         if (mTypedArrayCache == null) {
-            mTypedArrayCache = new IdentityHashMap<int[],
-                    Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>();
+            mTypedArrayCache = new TypedArrayCache();
         }
 
-        // get the 2nd map
-        Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>> map2 =
-                mTypedArrayCache.get(attrs);
-        if (map2 == null) {
-            map2 = new HashMap<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>();
-            mTypedArrayCache.put(attrs, map2);
-        }
-
-        // get the 3rd map
         List<StyleResourceValue> currentThemes = mRenderResources.getAllThemes();
-        Map<Integer, BridgeTypedArray> map3 = map2.get(currentThemes);
-        if (map3 == null) {
-            map3 = new HashMap<Integer, BridgeTypedArray>();
-            // Create a copy of the list before adding it to the map. This allows reusing the
-            // existing list.
-            currentThemes = new ArrayList<StyleResourceValue>(currentThemes);
-            map2.put(currentThemes, map3);
+
+        Pair<BridgeTypedArray, PropertiesMap> typeArrayAndPropertiesPair =
+                mTypedArrayCache.get(attrs, currentThemes, resId);
+
+        if (typeArrayAndPropertiesPair == null) {
+            typeArrayAndPropertiesPair = createStyleBasedTypedArray(style, attrs);
+            mTypedArrayCache.put(attrs, currentThemes, resId, typeArrayAndPropertiesPair);
         }
-
-        // get the array from the 3rd map
-        BridgeTypedArray ta = map3.get(resid);
-
-        if (ta == null) {
-            ta = createStyleBasedTypedArray(style, attrs);
-            map3.put(resid, ta);
+        // Add value to defaultPropsMap if needed
+        if (typeArrayAndPropertiesPair.getSecond() != null) {
+            Object key = getCurrentParser().getViewCookie();
+            if (key != null) {
+                PropertiesMap defaultPropMap = mDefaultPropMaps.get(key);
+                if (defaultPropMap == null) {
+                    defaultPropMap = typeArrayAndPropertiesPair.getSecond();
+                    mDefaultPropMaps.put(key, defaultPropMap);
+                } else {
+                    defaultPropMap.putAll(typeArrayAndPropertiesPair.getSecond());
+                }
+            }
         }
-
-        return ta;
+        return typeArrayAndPropertiesPair.getFirst();
     }
 
     @Override
@@ -674,7 +662,7 @@
     public BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
             int defStyleAttr, int defStyleRes) {
 
-        Map<String, String> defaultPropMap = null;
+        PropertiesMap defaultPropMap = null;
         boolean isPlatformFile = true;
 
         // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
@@ -688,7 +676,7 @@
             if (key != null) {
                 defaultPropMap = mDefaultPropMaps.get(key);
                 if (defaultPropMap == null) {
-                    defaultPropMap = new HashMap<String, String>();
+                    defaultPropMap = new PropertiesMap();
                     mDefaultPropMaps.put(key, defaultPropMap);
                 }
             }
@@ -706,8 +694,8 @@
 
         List<Pair<String, Boolean>> attributeList = searchAttrs(attrs);
 
-        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
-                isPlatformFile);
+        BridgeTypedArray ta =
+                Resources_Delegate.newTypeArray(mSystemResources, attrs.length, isPlatformFile);
 
         // look for a custom style.
         String customStyle = null;
@@ -936,32 +924,33 @@
      *
      * @see #obtainStyledAttributes(int, int[])
      */
-    private BridgeTypedArray createStyleBasedTypedArray(@Nullable StyleResourceValue style,
-            int[] attrs) throws Resources.NotFoundException {
-
+    private Pair<BridgeTypedArray, PropertiesMap> createStyleBasedTypedArray(
+            @Nullable StyleResourceValue style, int[] attrs) throws Resources.NotFoundException {
         List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
 
-        BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
-                false);
+        BridgeTypedArray ta = Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false);
 
+        PropertiesMap defaultPropMap = new PropertiesMap();
         // for each attribute, get its name so that we can search it in the style
-        for (int i = 0 ; i < attrs.length ; i++) {
+        for (int i = 0; i < attrs.length; i++) {
             Pair<String, Boolean> attribute = attributes.get(i);
 
             if (attribute != null) {
                 // look for the value in the given style
                 ResourceValue resValue;
+                String attrName = attribute.getFirst();
                 if (style != null) {
-                    resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(),
+                    resValue = mRenderResources.findItemInStyle(style, attrName,
                             attribute.getSecond());
                 } else {
-                    resValue = mRenderResources.findItemInTheme(attribute.getFirst(),
-                            attribute.getSecond());
+                    resValue = mRenderResources.findItemInTheme(attrName, attribute.getSecond());
                 }
 
                 if (resValue != null) {
+                    // Add it to defaultPropMap before resolving
+                    defaultPropMap.put(attrName, resValue.getValue());
                     // resolve it to make sure there are no references left.
-                    ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(),
+                    ta.bridgeSetValue(i, attrName, attribute.getSecond(),
                             mRenderResources.resolveResValue(resValue));
                 }
             }
@@ -969,7 +958,7 @@
 
         ta.sealArray();
 
-        return ta;
+        return Pair.of(ta, defaultPropMap);
     }
 
     /**
@@ -981,7 +970,7 @@
      * @return List of attribute information.
      */
     private List<Pair<String, Boolean>> searchAttrs(int[] attrs) {
-        List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length);
+        List<Pair<String, Boolean>> results = new ArrayList<>(attrs.length);
 
         // for each attribute, get its name so that we can search it in the style
         for (int attr : attrs) {
@@ -1010,7 +999,7 @@
      * @return A (name, isFramework) pair describing the attribute if found. Returns null
      *         if nothing is found.
      */
-    public Pair<String, Boolean> searchAttr(int attr) {
+    private Pair<String, Boolean> searchAttr(int attr) {
         Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
         if (info != null) {
             return Pair.of(info.getSecond(), Boolean.TRUE);
@@ -1027,8 +1016,8 @@
     public int getDynamicIdByStyle(StyleResourceValue resValue) {
         if (mDynamicIdToStyleMap == null) {
             // create the maps.
-            mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>();
-            mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>();
+            mDynamicIdToStyleMap = new HashMap<>();
+            mStyleToDynamicIdMap = new HashMap<>();
         }
 
         // look for an existing id
@@ -1258,7 +1247,7 @@
     }
 
     @Override
-    public boolean migrateDatabaseFrom(Context sourceContext, String name) {
+    public boolean moveDatabaseFrom(Context sourceContext, String name) {
         // pass
         return false;
     }
@@ -1451,7 +1440,7 @@
     }
 
     @Override
-    public boolean migrateSharedPreferencesFrom(Context sourceContext, String name) {
+    public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
         // pass
         return false;
     }
@@ -1837,25 +1826,99 @@
         return pos != null ? pos : 0;
     }
 
+    public void setScrollXPos(@NonNull View view, int scrollPos) {
+        mScrollXPos.put(view, scrollPos);
+    }
+
+    public int getScrollXPos(@NonNull View view) {
+        Integer pos = mScrollXPos.get(view);
+        return pos != null ? pos : 0;
+    }
+
     @Override
-    public Context createDeviceEncryptedStorageContext() {
+    public Context createDeviceProtectedStorageContext() {
         // pass
         return null;
     }
 
     @Override
-    public Context createCredentialEncryptedStorageContext() {
+    public Context createCredentialProtectedStorageContext() {
         // pass
         return null;
     }
 
     @Override
-    public boolean isDeviceEncryptedStorage() {
+    public boolean isDeviceProtectedStorage() {
         return false;
     }
 
     @Override
-    public boolean isCredentialEncryptedStorage() {
+    public boolean isCredentialProtectedStorage() {
         return false;
     }
+
+
+    /**
+     * The cached value depends on
+     * <ol>
+     * <li>{@code int[]}: the attributes for which TypedArray is created </li>
+     * <li>{@code List<StyleResourceValue>}: the themes set on the context at the time of
+     * creation of the TypedArray</li>
+     * <li>{@code Integer}: the default style used at the time of creation</li>
+     * </ol>
+     *
+     * The class is created by using nested maps resolving one dependency at a time.
+     * <p/>
+     * The final value of the nested maps is a pair of the typed array and a map of properties
+     * that should be added to {@link #mDefaultPropMaps}, if needed.
+     */
+    private static class TypedArrayCache {
+
+        private Map<int[],
+                Map<List<StyleResourceValue>,
+                        Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>> mCache;
+
+        public TypedArrayCache() {
+            mCache = new IdentityHashMap<>();
+        }
+
+        public Pair<BridgeTypedArray, PropertiesMap> get(int[] attrs,
+                List<StyleResourceValue> themes, int resId) {
+            Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>
+                    cacheFromThemes = mCache.get(attrs);
+            if (cacheFromThemes != null) {
+                Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId =
+                        cacheFromThemes.get(themes);
+                if (cacheFromResId != null) {
+                    return cacheFromResId.get(resId);
+                }
+            }
+            return null;
+        }
+
+        public void put(int[] attrs, List<StyleResourceValue> themes, int resId,
+                Pair<BridgeTypedArray, PropertiesMap> value) {
+            Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>
+                    cacheFromThemes = mCache.get(attrs);
+            if (cacheFromThemes == null) {
+                cacheFromThemes = new HashMap<>();
+                mCache.put(attrs, cacheFromThemes);
+            }
+            Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId =
+                    cacheFromThemes.get(themes);
+            if (cacheFromResId == null) {
+                cacheFromResId = new HashMap<>();
+                cacheFromThemes.put(themes, cacheFromResId);
+            }
+            cacheFromResId.put(resId, value);
+        }
+
+    }
+
+    /**
+     * An alias used for the value in {@code {@link #mDefaultPropMaps}}
+     */
+    private static class PropertiesMap extends HashMap<String, String> {
+    }
+
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 01c3c50..0cf51a4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -184,15 +184,6 @@
     }
 
     @Override
-    public InputBindResult startInput(
-            /* @InputMethodClient.StartInputReason */ int startInputReason,
-            IInputMethodClient client, IInputContext inputContext, EditorInfo attribute,
-            int controlFlags) throws RemoteException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
     public boolean switchToLastInputMethod(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
@@ -228,10 +219,11 @@
     }
 
     @Override
-    public InputBindResult windowGainedFocus(
+    public InputBindResult startInputOrWindowGainedFocus(
             /* @InputMethodClient.StartInputReason */ int startInputReason,
             IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
-            int windowFlags, EditorInfo attribute, IInputContext inputContext)
+            int windowFlags, EditorInfo attribute, IInputContext inputContext,
+            /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags)
             throws RemoteException {
         // TODO Auto-generated method stub
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index fcfbad2..42c0ae0 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -24,7 +24,6 @@
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
@@ -43,7 +42,6 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -486,6 +484,12 @@
     }
 
     @Override
+    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+        int badgeDensity) {
+        return null;
+    }
+
+    @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         return null;
     }
@@ -555,40 +559,11 @@
     }
 
     @Override
-    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
     public void installPackage(Uri packageURI, PackageInstallObserver observer, int flags,
             String installerPackageName) {
     }
 
     @Override
-    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,int flags,
-            String installerPackageName, int userId) {
-    }
-
-    @Override
-    public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
     public int installExistingPackage(String packageName) throws NameNotFoundException {
         return 0;
     }
@@ -740,6 +715,10 @@
     }
 
     @Override
+    public void flushPackageRestrictionsAsUser(int userId) {
+    }
+
+    @Override
     public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
             UserHandle userHandle) {
         return false;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index e9b7819..9f73d79 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -86,6 +86,11 @@
     }
 
     @Override
+    public void rebootSafeMode(boolean confirm, boolean wait) {
+        // pass for now.
+    }
+
+    @Override
     public void shutdown(boolean confirm, String reason, boolean wait) {
         // pass for now.
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 2000fbc..a83f100 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -50,7 +50,8 @@
 
     @Override
     public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6,
-            boolean b, Configuration configuration, Rect rect7, boolean b2) throws RemoteException {
+            boolean b, Configuration configuration, Rect rect7, boolean b2, boolean b3)
+            throws RemoteException {
         // pass for now.
     }
 
@@ -102,7 +103,8 @@
     }
 
     @Override
-    public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+    public void requestAppKeyboardShortcuts(
+            IResultReceiver receiver, int deviceId) throws RemoteException {
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index fe05b0e..5a6a00f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -96,7 +96,7 @@
     }
 
     @Override
-    public void repositionChild(IWindow childWindow, int x, int y, int width, int height,
+    public void repositionChild(IWindow window, int left, int top, int right, int bottom,
             long deferTransactionUntilFrame, Rect outFrame) {
         // pass for now.
         return;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
index b98f96f..051de90 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -16,6 +16,7 @@
 
 package com.android.layoutlib.bridge.android;
 
+import com.android.ide.common.rendering.api.LayoutlibCallback;
 import com.android.ide.common.rendering.api.RenderParams;
 import com.android.ide.common.rendering.api.SessionParams.Key;
 
@@ -42,11 +43,22 @@
     public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT =
             new Key<Boolean>("recyclerViewSupport", Boolean.class);
     /**
-     * The application package name. Used via
-     * {@link com.android.ide.common.rendering.api.LayoutlibCallback#getFlag(Key)}
+     * The application package name. Used via {@link LayoutlibCallback#getFlag(Key)}
      */
     public static final Key<String> FLAG_KEY_APPLICATION_PACKAGE =
             new Key<String>("applicationPackage", String.class);
+    /**
+     * To tell LayoutLib that IDE supports providing XML Parser for a file (useful for getting in
+     * memory contents of the file). Used via {@link LayoutlibCallback#getFlag(Key)}
+     */
+    public static final Key<Boolean> FLAG_KEY_XML_FILE_PARSER_SUPPORT =
+            new Key<Boolean>("xmlFileParser", Boolean.class);
+    /**
+     * To tell LayoutLib to not render when creating a new session. This allows controlling when the first
+     * layout rendering will happen.
+     */
+    public static final Key<Boolean> FLAG_DO_NOT_RENDER_ON_CREATE =
+            new Key<Boolean>("doNotRenderOnCreate", Boolean.class);
 
     // Disallow instances.
     private RenderParamsFlags() {}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
index d417eb7..3031701 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
@@ -66,6 +66,6 @@
 
     @Override
     public void requestAppKeyboardShortcuts(
-            KeyboardShortcutsReceiver receiver) {
+            KeyboardShortcutsReceiver receiver, int deviceId) {
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
index af6ba24..2cdc647 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
@@ -43,6 +43,7 @@
 import android.view.ViewGroup;
 import android.view.WindowCallback;
 import android.widget.ActionMenuPresenter;
+import android.widget.ActionMenuView;
 import android.widget.Toolbar;
 import android.widget.Toolbar_Accessor;
 
@@ -196,11 +197,16 @@
         @Override
         protected void inflateMenus() {
             super.inflateMenus();
-            // Inflating the menus doesn't initialize the ActionMenuPresenter. Setting a fake menu
-            // and then setting it back does the trick.
+            // Inflating the menus isn't enough. ActionMenuPresenter needs to be initialized too.
             MenuBuilder menu = getMenuBuilder();
             DecorToolbar decorToolbar = getDecorToolbar();
+            // Setting a menu different from the above initializes the presenter.
             decorToolbar.setMenu(new MenuBuilder(getActionMenuContext()), null);
+            // ActionMenuView needs to be recreated to be able to set the menu back.
+            ActionMenuPresenter presenter = getActionMenuPresenter();
+            if (presenter != null) {
+                presenter.setMenuView(new ActionMenuView(getPopupContext()));
+            }
             decorToolbar.setMenu(menu, null);
         }
 
@@ -255,7 +261,7 @@
                 @NonNull ActionBarView actionBarView) {
             super(context, callback, new WindowDecorActionBar(decorContentRoot));
             mActionBarView = actionBarView;
-            mActionBar = ((WindowDecorActionBar) super.mActionBar);
+            mActionBar = (WindowDecorActionBar) super.mActionBar;
             mDecorContentRoot = decorContentRoot;
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index baf2e2e..c59b1a6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -22,9 +22,11 @@
 import android.annotation.Nullable;
 import android.util.SparseArray;
 
+import java.io.PrintStream;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Manages native delegates.
@@ -73,14 +75,14 @@
 public final class DelegateManager<T> {
     @SuppressWarnings("FieldCanBeLocal")
     private final Class<T> mClass;
-    private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>();
+    private static final SparseWeakArray<Object> sDelegates = new SparseWeakArray<>();
     /** list used to store delegates when their main object holds a reference to them.
      * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
      * @see #addNewDelegate(Object)
      * @see #removeJavaReferenceFor(long)
      */
-    private final List<T> mJavaReferences = new ArrayList<T>();
-    private int mDelegateCounter = 0;
+    private static final List<Object> sJavaReferences = new ArrayList<>();
+    private static final AtomicLong sDelegateCounter = new AtomicLong(1);
 
     public DelegateManager(Class<T> theClass) {
         mClass = theClass;
@@ -97,9 +99,12 @@
      * @return the delegate or null if not found.
      */
     @Nullable
-    public synchronized T getDelegate(long native_object) {
+    public T getDelegate(long native_object) {
         if (native_object > 0) {
-            T delegate = mDelegates.get(native_object);
+            Object delegate;
+            synchronized (DelegateManager.class) {
+                delegate = sDelegates.get(native_object);
+            }
 
             if (Debug.DEBUG) {
                 if (delegate == null) {
@@ -109,7 +114,8 @@
             }
 
             assert delegate != null;
-            return delegate;
+            //noinspection unchecked
+            return (T)delegate;
         }
         return null;
     }
@@ -119,12 +125,13 @@
      * @param newDelegate the delegate to add
      * @return a unique native int to identify the delegate
      */
-    public synchronized long addNewDelegate(T newDelegate) {
-        long native_object = ++mDelegateCounter;
-
-        mDelegates.put(native_object, newDelegate);
-        assert !mJavaReferences.contains(newDelegate);
-        mJavaReferences.add(newDelegate);
+    public long addNewDelegate(T newDelegate) {
+        long native_object = sDelegateCounter.getAndIncrement();
+        synchronized (DelegateManager.class) {
+            sDelegates.put(native_object, newDelegate);
+            assert !sJavaReferences.contains(newDelegate);
+            sJavaReferences.add(newDelegate);
+        }
 
         if (Debug.DEBUG) {
             System.out.println(
@@ -140,14 +147,23 @@
      * Removes the main reference on the given delegate.
      * @param native_object the native integer representing the delegate.
      */
-    public synchronized void removeJavaReferenceFor(long native_object) {
-        T delegate = getDelegate(native_object);
+    public void removeJavaReferenceFor(long native_object) {
+        synchronized (DelegateManager.class) {
+            T delegate = getDelegate(native_object);
 
-        if (Debug.DEBUG) {
-            System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
-                    " with int " + native_object);
+            if (Debug.DEBUG) {
+                System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
+                        " with int " + native_object);
+            }
+
+            sJavaReferences.remove(delegate);
         }
+    }
 
-        mJavaReferences.remove(delegate);
+    public synchronized static void dump(PrintStream out) {
+        for (Object reference : sJavaReferences) {
+            int idx = sDelegates.indexOfValue(reference);
+            out.printf("[%d] %s\n", sDelegates.keyAt(idx), reference.getClass().getSimpleName());
+        }
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 4e4fcd0..0c53753 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -122,7 +122,7 @@
 
         // build the context
         mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
-                mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(),
+                mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(mParams),
                 mParams.getTargetSdkVersion(), mParams.isRtlSupported());
 
         setUp();
@@ -130,7 +130,6 @@
         return SUCCESS.createResult();
     }
 
-
     /**
      * Prepares the scene for action.
      * <p>
@@ -320,10 +319,11 @@
         }
     }
 
-    private Configuration getConfiguration() {
+    // VisibleForTesting
+    public static Configuration getConfiguration(RenderParams params) {
         Configuration config = new Configuration();
 
-        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
+        HardwareConfig hardwareConfig = params.getHardwareConfig();
 
         ScreenSize screenSize = hardwareConfig.getScreenSize();
         if (screenSize != null) {
@@ -392,7 +392,7 @@
         } else {
             config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_UNDEFINED;
         }
-        String locale = getParams().getLocale();
+        String locale = params.getLocale();
         if (locale != null && !locale.isEmpty()) config.locale = new Locale(locale);
 
         // TODO: fill in more config info.
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 ec50cfe..866b248 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
@@ -60,6 +60,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
 import android.graphics.Canvas;
+import android.os.Looper;
 import android.preference.Preference_Delegate;
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
@@ -266,6 +267,34 @@
     }
 
     /**
+     * Renders the given view hierarchy to the passed canvas and returns the result of the render
+     * operation.
+     * @param canvas an optional canvas to render the views to. If null, only the measure and
+     * layout steps will be executed.
+     */
+    private static Result render(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot,
+            @Nullable Canvas canvas, int width, int height) {
+        // measure again with the size we need
+        // This must always be done before the call to layout
+        measureView(viewRoot, null /*measuredView*/,
+                width, MeasureSpec.EXACTLY,
+                height, MeasureSpec.EXACTLY);
+
+        // now do the layout.
+        viewRoot.layout(0, 0, width, height);
+        handleScrolling(context, viewRoot);
+
+        if (canvas == null) {
+            return SUCCESS.createResult();
+        }
+
+        AttachInfo_Accessor.dispatchOnPreDraw(viewRoot);
+        viewRoot.draw(canvas);
+
+        return SUCCESS.createResult();
+    }
+
+    /**
      * Renders the scene.
      * <p>
      * {@link #acquire(long)} must have been called before this.
@@ -366,24 +395,12 @@
                 }
             }
 
-            // measure again with the size we need
-            // This must always be done before the call to layout
-            measureView(mViewRoot, null /*measuredView*/,
-                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
-                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
-
-            // now do the layout.
-            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
-
-            handleScrolling(mViewRoot);
-
+            Result renderResult = SUCCESS.createResult();
             if (params.isLayoutOnly()) {
                 // delete the canvas and image to reset them on the next full rendering
                 mImage = null;
                 mCanvas = null;
             } else {
-                AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot);
-
                 // draw the views
                 // create the BufferedImage into which the layout will be rendered.
                 boolean newImage = false;
@@ -445,6 +462,9 @@
                 if (mElapsedFrameTimeNanos >= 0) {
                     long initialTime = System_Delegate.nanoTime();
                     if (!mFirstFrameExecuted) {
+                        // We need to run an initial draw call to initialize the animations
+                        render(getContext(), mViewRoot, mCanvas, 0, 0);
+
                         // The first frame will initialize the animations
                         Choreographer_Delegate.doFrame(initialTime);
                         mFirstFrameExecuted = true;
@@ -452,14 +472,15 @@
                     // Second frame will move the animations
                     Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
                 }
-                mViewRoot.draw(mCanvas);
+                renderResult = render(getContext(), mViewRoot, mCanvas, mMeasuredScreenWidth,
+                        mMeasuredScreenHeight);
             }
 
             mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
                     false);
 
             // success!
-            return SUCCESS.createResult();
+            return renderResult;
         } catch (Throwable e) {
             // get the real cause of the exception.
             Throwable t = e;
@@ -487,7 +508,7 @@
      * @return the measured width/height if measuredView is non-null, null otherwise.
      */
     @SuppressWarnings("deprecation")  // For the use of Pair
-    private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
+    private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
             int width, int widthMode, int height, int heightMode) {
         int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
         int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
@@ -1056,25 +1077,29 @@
     }
 
     /**
-     * Set the vertical scroll position on all the components with the "scrollY" attribute. If the
-     * component supports nested scrolling attempt that first, then use the unconsumed scroll part
-     * to scroll the content in the component.
+     * Set the scroll position on all the components with the "scrollX" and "scrollY" attribute. If
+     * the component supports nested scrolling attempt that first, then use the unconsumed scroll
+     * part to scroll the content in the component.
      */
-    private void handleScrolling(View view) {
-        BridgeContext context = getContext();
-        int scrollPos = context.getScrollYPos(view);
-        if (scrollPos != 0) {
+    private static void handleScrolling(BridgeContext context, View view) {
+        int scrollPosX = context.getScrollXPos(view);
+        int scrollPosY = context.getScrollYPos(view);
+        if (scrollPosX != 0 || scrollPosY != 0) {
             if (view.isNestedScrollingEnabled()) {
                 int[] consumed = new int[2];
-                if (view.startNestedScroll(DesignLibUtil.SCROLL_AXIS_VERTICAL)) {
-                    view.dispatchNestedPreScroll(0, scrollPos, consumed, null);
-                    view.dispatchNestedScroll(consumed[0], consumed[1], 0, scrollPos, null);
+                int axis = scrollPosX != 0 ? View.SCROLL_AXIS_HORIZONTAL : 0;
+                axis |= scrollPosY != 0 ? View.SCROLL_AXIS_VERTICAL : 0;
+                if (view.startNestedScroll(axis)) {
+                    view.dispatchNestedPreScroll(scrollPosX, scrollPosY, consumed, null);
+                    view.dispatchNestedScroll(consumed[0], consumed[1], scrollPosX, scrollPosY,
+                            null);
                     view.stopNestedScroll();
-                    scrollPos -= consumed[1];
+                    scrollPosX -= consumed[0];
+                    scrollPosY -= consumed[1];
                 }
             }
-            if (scrollPos != 0) {
-                view.scrollBy(0, scrollPos);
+            if (scrollPosX != 0 || scrollPosY != 0) {
+                view.scrollTo(scrollPosX, scrollPosY);
             }
         }
 
@@ -1084,7 +1109,7 @@
         ViewGroup group = (ViewGroup) view;
         for (int i = 0; i < group.getChildCount(); i++) {
             View child = group.getChildAt(i);
-            handleScrolling(child);
+            handleScrolling(context, child);
         }
     }
 
@@ -1275,14 +1300,20 @@
             return null;
         }
 
+        ViewParent parent = view.getParent();
         ViewInfo result;
         if (isContentFrame) {
+            // Account for parent scroll values when calculating the bounding box
+            int scrollX = parent != null ? ((View)parent).getScrollX() : 0;
+            int scrollY = parent != null ? ((View)parent).getScrollY() : 0;
+
             // The view is part of the layout added by the user. Hence,
             // the ViewCookie may be obtained only through the Context.
             result = new ViewInfo(view.getClass().getName(),
                     getContext().getViewKey(view),
-                    view.getLeft(), view.getTop() + offset, view.getRight(),
-                    view.getBottom() + offset, view, view.getLayoutParams());
+                    -scrollX + view.getLeft(), -scrollY + view.getTop() + offset,
+                    -scrollX + view.getRight(), -scrollY + view.getBottom() + offset,
+                    view, view.getLayoutParams());
         } else {
             // We are part of the system decor.
             SystemViewInfo r = new SystemViewInfo(view.getClass().getName(),
@@ -1310,7 +1341,6 @@
                     // its parent is of type ActionMenuView. We can also check if the view is
                     // instanceof ActionMenuItemView but that will fail for menus using
                     // actionProviderClass.
-                    ViewParent parent = view.getParent();
                     while (parent != mViewRoot && parent instanceof ViewGroup) {
                         if (parent instanceof ActionMenuView) {
                             r.setViewType(ViewType.ACTION_BAR_MENU);
@@ -1396,4 +1426,34 @@
     public RenderSession getSession() {
         return mScene;
     }
+
+    public void dispose() {
+        boolean createdLooper = false;
+        if (Looper.myLooper() == null) {
+            // Detaching the root view from the window will try to stop any running animations.
+            // The stop method checks that it can run in the looper so, if there is no current
+            // looper, we create a temporary one to complete the shutdown.
+            Bridge.prepareThread();
+            createdLooper = true;
+        }
+        AttachInfo_Accessor.detachFromWindow(mViewRoot);
+        if (mCanvas != null) {
+            mCanvas.release();
+            mCanvas = null;
+        }
+        if (mViewInfoList != null) {
+            mViewInfoList.clear();
+        }
+        if (mSystemViewInfoList != null) {
+            mSystemViewInfoList.clear();
+        }
+        mImage = null;
+        mViewRoot = null;
+        mContentRoot = null;
+
+        if (createdLooper) {
+            Bridge.cleanupThread();
+            Choreographer_Delegate.dispose();
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index c72eeb1..a21de56 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -25,6 +25,7 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 import com.android.ninepatch.NinePatch;
 import com.android.ninepatch.NinePatchChunk;
 import com.android.resources.Density;
@@ -33,7 +34,11 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.ColorStateList;
+import android.content.res.ComplexColor;
+import android.content.res.ComplexColor_Accessor;
+import android.content.res.GradientColor;
 import android.content.res.Resources.Theme;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
@@ -47,6 +52,7 @@
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
@@ -119,54 +125,133 @@
         throw new NumberFormatException();
     }
 
-    public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) {
+    /**
+     * Returns a {@link ComplexColor} from the given {@link ResourceValue}
+     *
+     * @param resValue the value containing a color value or a file path to a complex color
+     * definition
+     * @param context the current context
+     * @param theme the theme to use when resolving the complex color
+     * @param allowGradients when false, only {@link ColorStateList} will be returned. If a {@link
+     * GradientColor} is found, null will be returned.
+     */
+    @Nullable
+    private static ComplexColor getInternalComplexColor(@NonNull ResourceValue resValue,
+            @NonNull BridgeContext context, @Nullable Theme theme, boolean allowGradients) {
         String value = resValue.getValue();
-        if (value != null && !RenderResources.REFERENCE_NULL.equals(value)) {
-            // first check if the value is a file (xml most likely)
+        if (value == null || RenderResources.REFERENCE_NULL.equals(value)) {
+            return null;
+        }
+
+        XmlPullParser parser = null;
+        // first check if the value is a file (xml most likely)
+        Boolean psiParserSupport = context.getLayoutlibCallback().getFlag(
+                RenderParamsFlags.FLAG_KEY_XML_FILE_PARSER_SUPPORT);
+        if (psiParserSupport != null && psiParserSupport) {
+            parser = context.getLayoutlibCallback().getXmlFileParser(value);
+        }
+        if (parser == null) {
             File f = new File(value);
             if (f.isFile()) {
+                // let the framework inflate the color from the XML file, by
+                // providing an XmlPullParser
                 try {
-                    // let the framework inflate the ColorStateList from the XML file, by
-                    // providing an XmlPullParser
-                    XmlPullParser parser = ParserFactory.create(f);
-
-                    BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
-                            parser, context, resValue.isFramework());
-                    try {
-                        return ColorStateList.createFromXml(context.getResources(), blockParser);
-                    } finally {
-                        blockParser.ensurePopped();
-                    }
-                } catch (XmlPullParserException e) {
-                    Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                            "Failed to configure parser for " + value, e, null /*data*/);
-                    // we'll return null below.
-                } catch (Exception e) {
-                    // this is an error and not warning since the file existence is
-                    // checked before attempting to parse it.
+                    parser = ParserFactory.create(f);
+                } catch (XmlPullParserException | FileNotFoundException e) {
                     Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
                             "Failed to parse file " + value, e, null /*data*/);
-
-                    return null;
-                }
-            } else {
-                // try to load the color state list from an int
-                try {
-                    int color = ResourceHelper.getColor(value);
-                    return ColorStateList.valueOf(color);
-                } catch (NumberFormatException e) {
-                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
-                            "Failed to convert " + value + " into a ColorStateList", e,
-                            null /*data*/);
-                    return null;
                 }
             }
         }
 
+        if (parser != null) {
+            try {
+                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
+                        parser, context, resValue.isFramework());
+                try {
+                    // Advance the parser to the first element so we can detect if it's a
+                    // color list or a gradient color
+                    int type;
+                    //noinspection StatementWithEmptyBody
+                    while ((type = blockParser.next()) != XmlPullParser.START_TAG
+                            && type != XmlPullParser.END_DOCUMENT) {
+                        // Seek parser to start tag.
+                    }
+
+                    if (type != XmlPullParser.START_TAG) {
+                        throw new XmlPullParserException("No start tag found");
+                    }
+
+                    final String name = blockParser.getName();
+                    if (allowGradients && "gradient".equals(name)) {
+                        return ComplexColor_Accessor.createGradientColorFromXmlInner(
+                                context.getResources(),
+                                blockParser, blockParser,
+                                theme);
+                    } else if ("selector".equals(name)) {
+                        return ComplexColor_Accessor.createColorStateListFromXmlInner(
+                                context.getResources(),
+                                blockParser, blockParser,
+                                theme);
+                    }
+                } finally {
+                    blockParser.ensurePopped();
+                }
+            } catch (XmlPullParserException e) {
+                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                        "Failed to configure parser for " + value, e, null /*data*/);
+                // we'll return null below.
+            } catch (Exception e) {
+                // this is an error and not warning since the file existence is
+                // checked before attempting to parse it.
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+                        "Failed to parse file " + value, e, null /*data*/);
+
+                return null;
+            }
+        } else {
+            // try to load the color state list from an int
+            try {
+                int color = getColor(value);
+                return ColorStateList.valueOf(color);
+            } catch (NumberFormatException e) {
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+                        "Failed to convert " + value + " into a ColorStateList", e,
+                        null /*data*/);
+            }
+        }
+
         return null;
     }
 
     /**
+     * Returns a {@link ColorStateList} from the given {@link ResourceValue}
+     *
+     * @param resValue the value containing a color value or a file path to a complex color
+     * definition
+     * @param context the current context
+     */
+    @Nullable
+    public static ColorStateList getColorStateList(@NonNull ResourceValue resValue,
+            @NonNull BridgeContext context) {
+        return (ColorStateList) getInternalComplexColor(resValue, context, context.getTheme(),
+                false);
+    }
+
+    /**
+     * Returns a {@link ComplexColor} from the given {@link ResourceValue}
+     *
+     * @param resValue the value containing a color value or a file path to a complex color
+     * definition
+     * @param context the current context
+     */
+    @Nullable
+    public static ComplexColor getComplexColor(@NonNull ResourceValue resValue,
+            @NonNull BridgeContext context) {
+        return getInternalComplexColor(resValue, context, context.getTheme(), true);
+    }
+
+    /**
      * Returns a drawable from the given value.
      * @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
      * or an hexadecimal color
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
index 08a8faf..161bf41 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
@@ -27,8 +27,8 @@
 
 public class DynamicIdMap {
 
-    private final Map<Pair<ResourceType, String>, Integer> mDynamicIds = new HashMap<Pair<ResourceType, String>, Integer>();
-    private final SparseArray<Pair<ResourceType, String>> mRevDynamicIds = new SparseArray<Pair<ResourceType, String>>();
+    private final Map<Pair<ResourceType, String>, Integer> mDynamicIds = new HashMap<>();
+    private final SparseArray<Pair<ResourceType, String>> mRevDynamicIds = new SparseArray<>();
     private int mDynamicSeed;
 
     public DynamicIdMap(int seed) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
new file mode 100644
index 0000000..96b795a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+/**
+ * Simpler wrapper around FileInputStream. This is used when the input stream represent
+ * not a normal bitmap but a nine patch.
+ * This is useful when the InputStream is created in a method but used in another that needs
+ * to know whether this is 9-patch or not, such as BitmapFactory.
+ */
+public class NinePatchInputStream extends FileInputStream {
+    private boolean mFakeMarkSupport = true;
+    public NinePatchInputStream(File file) throws FileNotFoundException {
+        super(file);
+    }
+
+    @Override
+    public boolean markSupported() {
+        if (mFakeMarkSupport) {
+            // this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
+            return true;
+        }
+
+        return super.markSupported();
+    }
+
+    public void disableFakeMarkSupport() {
+        // disable fake mark support so that in case codec actually try to use them
+        // we don't lie to them.
+        mFakeMarkSupport = false;
+    }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
new file mode 100644
index 0000000..87bd502
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
index 72b87ab..55d6a20 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/color/gradient.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/color/gradient.xml
new file mode 100644
index 0000000..fc0afa6
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/color/gradient.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:startX="10"
+          android:startY="10"
+          android:endX="50"
+          android:endY="50"
+          android:startColor="#ffff0000"
+          android:endColor="#ff00ff00" />
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
index ffc70dc..32e6e73 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
@@ -53,6 +53,35 @@
             android:trimPathStart="0.2"
             android:trimPathEnd="0.8"
         />
+
+        <!--
+            Draw a line with gradient stroke color
+        -->
+        <path
+            android:strokeWidth="1"
+            android:strokeColor="#FF00FF"
+            android:fillColor="@color/gradient"
+            android:pathData="M-20,-20 l0, 10 l10, 0 l0, -10 l-10,0 "
+        />
+
+        <!--
+            Draw squares with different fill types
+        -->
+        <path
+            android:fillType="evenOdd"
+            android:strokeWidth="1"
+            android:strokeColor="#AABBCC"
+            android:fillColor="#AAEFCC"
+            android:pathData="M-20,-40 l0, 10 l10, 0 l0, -10 l-10,0 m5,0 l0, 10 l10, 0 l0, -10 l-10,0"
+        />
+
+        <path
+            android:fillType="nonZero"
+            android:strokeWidth="1"
+            android:strokeColor="#AABBCC"
+            android:fillColor="#AAEFCC"
+            android:pathData="M0,-40 l0, 10 l10, 0 l0, -10 l-10,0 m5,0 l0, 10 l10, 0 l0, -10 l-10,0"
+        />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
new file mode 100644
index 0000000..a07498c
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
@@ -0,0 +1,57 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical"
+              android:scrollX="30px"
+              android:scrollY="90px">
+    <LinearLayout
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:background="#FF0000" />
+    <LinearLayout
+        android:layout_width="60dp"
+        android:layout_height="30dp"
+        android:background="#00FF00" />
+    <LinearLayout
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:background="#0000FF" />
+    <LinearLayout
+        android:layout_width="60dp"
+        android:layout_height="30dp"
+        android:background="#FF00FF" />
+    <LinearLayout
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:background="#00FFFF" />
+
+    <LinearLayout
+        android:layout_width="200dp"
+        android:layout_height="400dp"
+        android:orientation="vertical"
+        android:scrollX="-90px"
+        android:scrollY="450px">
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="60dp"
+            android:background="#FF0000" />
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="30dp"
+            android:background="#00FF00" />
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="60dp"
+            android:background="#0000FF" />
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="30dp"
+            android:background="#FF00FF" />
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="60dp"
+            android:background="#00FFFF" />
+    </LinearLayout>
+
+
+</LinearLayout>
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index fe16a3e..034c8b2 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -21,6 +21,7 @@
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.SessionParams;
 import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
+import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.ide.common.resources.FrameworkResources;
 import com.android.ide.common.resources.ResourceItem;
 import com.android.ide.common.resources.ResourceRepository;
@@ -28,11 +29,16 @@
 import com.android.ide.common.resources.configuration.FolderConfiguration;
 import com.android.io.FolderWrapper;
 import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
 import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
 import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
 import com.android.resources.Density;
 import com.android.resources.Navigation;
+import com.android.resources.ResourceType;
 import com.android.utils.ILogger;
 
 import org.junit.AfterClass;
@@ -41,16 +47,21 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.DisplayMetrics;
 
 import java.io.File;
-import java.io.FileFilter;
 import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.net.URL;
 import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 /**
@@ -157,13 +168,8 @@
         if (!host.isDirectory()) {
             return null;
         }
-        File[] hosts = host.listFiles(new FileFilter() {
-            @Override
-            public boolean accept(File path) {
-                return path.isDirectory() && (path.getName().startsWith("linux-") || path.getName()
-                        .startsWith("darwin-"));
-            }
-        });
+        File[] hosts = host.listFiles(path -> path.isDirectory() &&
+                (path.getName().startsWith("linux-") || path.getName().startsWith("darwin-")));
         for (File hostOut : hosts) {
             String platformDir = getPlatformDirFromHostOut(hostOut);
             if (platformDir != null) {
@@ -181,12 +187,9 @@
         if (!sdkDir.isDirectory()) {
             return null;
         }
-        File[] sdkDirs = sdkDir.listFiles(new FileFilter() {
-            @Override
-            public boolean accept(File path) {
-                // We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7)
-                return path.isDirectory() && path.getName().startsWith("sdk");
-            }
+        File[] sdkDirs = sdkDir.listFiles(path -> {
+            // We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7)
+            return path.isDirectory() && path.getName().startsWith("sdk");
         });
         for (File dir : sdkDirs) {
             String platformDir = getPlatformDirFromHostOutSdkSdk(dir);
@@ -198,46 +201,34 @@
     }
 
     private static String getPlatformDirFromHostOutSdkSdk(File sdkDir) {
-        File[] possibleSdks = sdkDir.listFiles(new FileFilter() {
-            @Override
-            public boolean accept(File path) {
-                return path.isDirectory() && path.getName().contains("android-sdk");
-            }
-        });
+        File[] possibleSdks = sdkDir.listFiles(
+                path -> path.isDirectory() && path.getName().contains("android-sdk"));
         for (File possibleSdk : possibleSdks) {
             File platformsDir = new File(possibleSdk, "platforms");
-            File[] platforms = platformsDir.listFiles(new FileFilter() {
-                @Override
-                public boolean accept(File path) {
-                    return path.isDirectory() && path.getName().startsWith("android-");
-                }
-            });
+            File[] platforms = platformsDir.listFiles(
+                    path -> path.isDirectory() && path.getName().startsWith("android-"));
             if (platforms == null || platforms.length == 0) {
                 continue;
             }
-            Arrays.sort(platforms, new Comparator<File>() {
-                // Codenames before ints. Higher APIs precede lower.
-                @Override
-                public int compare(File o1, File o2) {
-                    final int MAX_VALUE = 1000;
-                    String suffix1 = o1.getName().substring("android-".length());
-                    String suffix2 = o2.getName().substring("android-".length());
-                    int suff1, suff2;
-                    try {
-                        suff1 = Integer.parseInt(suffix1);
-                    } catch (NumberFormatException e) {
-                        suff1 = MAX_VALUE;
-                    }
-                    try {
-                        suff2 = Integer.parseInt(suffix2);
-                    } catch (NumberFormatException e) {
-                        suff2 = MAX_VALUE;
-                    }
-                    if (suff1 != MAX_VALUE || suff2 != MAX_VALUE) {
-                        return suff2 - suff1;
-                    }
-                    return suffix2.compareTo(suffix1);
+            Arrays.sort(platforms, (o1, o2) -> {
+                final int MAX_VALUE = 1000;
+                String suffix1 = o1.getName().substring("android-".length());
+                String suffix2 = o2.getName().substring("android-".length());
+                int suff1, suff2;
+                try {
+                    suff1 = Integer.parseInt(suffix1);
+                } catch (NumberFormatException e) {
+                    suff1 = MAX_VALUE;
                 }
+                try {
+                    suff2 = Integer.parseInt(suffix2);
+                } catch (NumberFormatException e) {
+                    suff2 = MAX_VALUE;
+                }
+                if (suff1 != MAX_VALUE || suff2 != MAX_VALUE) {
+                    return suff2 - suff1;
+                }
+                return suffix2.compareTo(suffix1);
             });
             return platforms[0].getAbsolutePath();
         }
@@ -258,6 +249,7 @@
             return null;
         }
     }
+
     /**
      * Initialize the bridge and the resource maps.
      */
@@ -291,7 +283,6 @@
     @Test
     public void testActivity() throws ClassNotFoundException {
         renderAndVerify("activity.xml", "activity.png");
-
     }
 
     /** Test allwidgets.xml */
@@ -310,6 +301,16 @@
         renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012);
     }
 
+    private static void gc() {
+        // See RuntimeUtil#gc in jlibs (http://jlibs.in/)
+        Object obj = new Object();
+        WeakReference ref = new WeakReference<Object>(obj);
+        obj = null;
+        while(ref.get() != null) {
+            System.gc();
+        }
+    }
+
     @AfterClass
     public static void tearDown() {
         sLayoutLibLog = null;
@@ -317,14 +318,18 @@
         sProjectResources = null;
         sLogger = null;
         sBridge = null;
+
+        gc();
+
+        System.out.println("Objects still linked from the DelegateManager:");
+        DelegateManager.dump(System.out);
     }
 
     /** Test expand_layout.xml */
     @Test
     public void testExpand() throws ClassNotFoundException {
         // Create the layout pull parser.
-        LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
-                "expand_vert_layout.xml");
+        LayoutPullParser parser = createLayoutPullParser("expand_vert_layout.xml");
         // Create LayoutLibCallback.
         LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
         layoutLibCallback.initResources();
@@ -336,7 +341,7 @@
                 .setNavigation(Navigation.NONAV);
 
         SessionParams params = getSessionParams(parser, customConfigGenerator,
-                layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+                layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false,
                 RenderingMode.V_SCROLL, 22);
 
         renderAndVerify(params, "expand_vert_layout.png");
@@ -346,10 +351,9 @@
                 .setScreenHeight(300)
                 .setDensity(Density.XHIGH)
                 .setNavigation(Navigation.NONAV);
-        parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
-                "expand_horz_layout.xml");
+        parser = createLayoutPullParser("expand_horz_layout.xml");
         params = getSessionParams(parser, customConfigGenerator,
-                layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+                layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false,
                 RenderingMode.H_SCROLL, 22);
 
         renderAndVerify(params, "expand_horz_layout.png");
@@ -359,8 +363,7 @@
     @Test
     public void testVectorAnimation() throws ClassNotFoundException {
         // Create the layout pull parser.
-        LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
-                "indeterminate_progressbar.xml");
+        LayoutPullParser parser = createLayoutPullParser("indeterminate_progressbar.xml");
         // Create LayoutLibCallback.
         LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
         layoutLibCallback.initResources();
@@ -371,8 +374,7 @@
 
         renderAndVerify(params, "animated_vector.png", TimeUnit.SECONDS.toNanos(2));
 
-        parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
-                "indeterminate_progressbar.xml");
+        parser = createLayoutPullParser("indeterminate_progressbar.xml");
         params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
                 layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
                 RenderingMode.V_SCROLL, 22);
@@ -386,8 +388,7 @@
     @Test
     public void testVectorDrawable() throws ClassNotFoundException {
         // Create the layout pull parser.
-        LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
-                "vector_drawable.xml");
+        LayoutPullParser parser = createLayoutPullParser("vector_drawable.xml");
         // Create LayoutLibCallback.
         LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
         layoutLibCallback.initResources();
@@ -399,6 +400,72 @@
         renderAndVerify(params, "vector_drawable.png", TimeUnit.SECONDS.toNanos(2));
     }
 
+    /** Test activity.xml */
+    @Test
+    public void testScrolling() throws ClassNotFoundException {
+        // Create the layout pull parser.
+        LayoutPullParser parser = createLayoutPullParser("scrolled.xml");
+        // Create LayoutLibCallback.
+        LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+        layoutLibCallback.initResources();
+
+        SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
+                layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+                RenderingMode.V_SCROLL, 22);
+        params.setForceNoDecor();
+        params.setExtendedViewInfoMode(true);
+
+        RenderResult result = renderAndVerify(params, "scrolled.png");
+        assertNotNull(result);
+        assertTrue(result.getResult().isSuccess());
+
+        ViewInfo rootLayout = result.getRootViews().get(0);
+        // Check the first box in the main LinearLayout
+        assertEquals(-90, rootLayout.getChildren().get(0).getTop());
+        assertEquals(-30, rootLayout.getChildren().get(0).getLeft());
+        assertEquals(90, rootLayout.getChildren().get(0).getBottom());
+        assertEquals(150, rootLayout.getChildren().get(0).getRight());
+
+        // Check the first box within the nested LinearLayout
+        assertEquals(-450, rootLayout.getChildren().get(5).getChildren().get(0).getTop());
+        assertEquals(90, rootLayout.getChildren().get(5).getChildren().get(0).getLeft());
+        assertEquals(-270, rootLayout.getChildren().get(5).getChildren().get(0).getBottom());
+        assertEquals(690, rootLayout.getChildren().get(5).getChildren().get(0).getRight());
+    }
+
+    @Test
+    public void testGetResourceNameVariants() throws Exception {
+        // Setup
+        SessionParams params = createSessionParams("", ConfigGenerator.NEXUS_4);
+        AssetManager assetManager = AssetManager.getSystem();
+        DisplayMetrics metrics = new DisplayMetrics();
+        Configuration configuration = RenderAction.getConfiguration(params);
+        Resources resources = new Resources(assetManager, metrics, configuration);
+        resources.mLayoutlibCallback = params.getLayoutlibCallback();
+        resources.mContext =
+                new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
+                        params.getAssets(), params.getLayoutlibCallback(), configuration,
+                        params.getTargetSdkVersion(), params.isRtlSupported());
+        // Test
+        assertEquals("android:style/ButtonBar",
+                resources.getResourceName(android.R.style.ButtonBar));
+        assertEquals("android", resources.getResourcePackageName(android.R.style.ButtonBar));
+        assertEquals("ButtonBar", resources.getResourceEntryName(android.R.style.ButtonBar));
+        assertEquals("style", resources.getResourceTypeName(android.R.style.ButtonBar));
+        int id = resources.mLayoutlibCallback.getResourceId(ResourceType.STRING, "app_name");
+        assertEquals("com.android.layoutlib.test.myapplication:string/app_name",
+                resources.getResourceName(id));
+        assertEquals("com.android.layoutlib.test.myapplication",
+                resources.getResourcePackageName(id));
+        assertEquals("string", resources.getResourceTypeName(id));
+        assertEquals("app_name", resources.getResourceEntryName(id));
+    }
+
+    @NonNull
+    private LayoutPullParser createLayoutPullParser(String layoutPath) {
+        return new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutPath);
+    }
+
     /**
      * Create a new rendering session and test that rendering the given layout doesn't throw any
      * exceptions and matches the provided image.
@@ -406,7 +473,8 @@
      * If frameTimeNanos is >= 0 a frame will be executed during the rendering. The time indicates
      * how far in the future is.
      */
-    private void renderAndVerify(SessionParams params, String goldenFileName, long frameTimeNanos)
+    @Nullable
+    private RenderResult renderAndVerify(SessionParams params, String goldenFileName, long frameTimeNanos)
             throws ClassNotFoundException {
         // TODO: Set up action bar handler properly to test menu rendering.
         // Create session params.
@@ -429,46 +497,60 @@
         try {
             String goldenImagePath = APP_TEST_DIR + "/golden/" + goldenFileName;
             ImageUtils.requireSimilar(goldenImagePath, session.getImage());
+
+            return RenderResult.getFromSession(session);
         } catch (IOException e) {
             getLogger().error(e, e.getMessage());
+        } finally {
+            session.dispose();
         }
+
+        return null;
     }
 
     /**
      * Create a new rendering session and test that rendering the given layout doesn't throw any
      * exceptions and matches the provided image.
      */
-    private void renderAndVerify(SessionParams params, String goldenFileName)
+    @Nullable
+    private RenderResult renderAndVerify(SessionParams params, String goldenFileName)
             throws ClassNotFoundException {
-        renderAndVerify(params, goldenFileName, -1);
+        return renderAndVerify(params, goldenFileName, -1);
     }
 
     /**
      * Create a new rendering session and test that rendering the given layout on nexus 5
      * doesn't throw any exceptions and matches the provided image.
      */
-    private void renderAndVerify(String layoutFileName, String goldenFileName)
+    @Nullable
+    private RenderResult renderAndVerify(String layoutFileName, String goldenFileName)
             throws ClassNotFoundException {
-        renderAndVerify(layoutFileName, goldenFileName, ConfigGenerator.NEXUS_5);
+        return renderAndVerify(layoutFileName, goldenFileName, ConfigGenerator.NEXUS_5);
     }
 
     /**
      * Create a new rendering session and test that rendering the given layout on given device
      * doesn't throw any exceptions and matches the provided image.
      */
-    private void renderAndVerify(String layoutFileName, String goldenFileName,
+    @Nullable
+    private RenderResult renderAndVerify(String layoutFileName, String goldenFileName,
             ConfigGenerator deviceConfig)
             throws ClassNotFoundException {
+        SessionParams params = createSessionParams(layoutFileName, deviceConfig);
+        return renderAndVerify(params, goldenFileName);
+    }
+
+    private SessionParams createSessionParams(String layoutFileName, ConfigGenerator deviceConfig)
+            throws ClassNotFoundException {
         // Create the layout pull parser.
-        LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName);
+        LayoutPullParser parser = createLayoutPullParser(layoutFileName);
         // Create LayoutLibCallback.
         LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
         layoutLibCallback.initResources();
         // TODO: Set up action bar handler properly to test menu rendering.
         // Create session params.
-        SessionParams params = getSessionParams(parser, deviceConfig,
+        return getSessionParams(parser, deviceConfig,
                 layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22);
-        renderAndVerify(params, goldenFileName);
     }
 
     /**
@@ -483,7 +565,7 @@
                         sFrameworkRepo.getConfiguredResources(config),
                         themeName, isProjectTheme);
 
-        return new SessionParams(
+        SessionParams sessionParams = new SessionParams(
                 layoutParser,
                 renderingMode,
                 null /*used for caching*/,
@@ -493,6 +575,8 @@
                 0,
                 targetSdk,
                 getLayoutLog());
+        sessionParams.setFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE, true);
+        return sessionParams;
     }
 
     private static LayoutLog getLayoutLog() {
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderResult.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderResult.java
new file mode 100644
index 0000000..17b20f7
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderResult.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.intensive;
+
+import com.android.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.ViewInfo;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+class RenderResult {
+    private final List<ViewInfo> mRootViews;
+    private final List<ViewInfo> mSystemViews;
+    private final Result mRenderResult;
+
+    private RenderResult(@Nullable Result result, @Nullable List<ViewInfo> systemViewInfoList,
+            @Nullable List<ViewInfo> rootViewInfoList) {
+        mSystemViews = systemViewInfoList == null ? Collections.emptyList() : systemViewInfoList;
+        mRootViews = rootViewInfoList == null ? Collections.emptyList() : rootViewInfoList;
+        mRenderResult = result;
+    }
+
+    @NonNull
+    static RenderResult getFromSession(@NonNull RenderSession session) {
+        return new RenderResult(session.getResult(),
+                new ArrayList<>(session.getSystemRootViews()),
+                new ArrayList<>(session.getRootViews()));
+    }
+
+    @Nullable
+    Result getResult() {
+        return mRenderResult;
+    }
+
+    @NonNull
+    public List<ViewInfo> getRootViews() {
+        return mRootViews;
+    }
+
+    @NonNull
+    public List<ViewInfo> getSystemViews() {
+        return mSystemViews;
+    }
+}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
index 6c16ed0..96ae523 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
@@ -24,7 +24,9 @@
 import com.android.ide.common.rendering.api.ParserFactory;
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams.Key;
 import com.android.ide.common.resources.IntArrayWrapper;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
 import com.android.utils.ILogger;
@@ -176,4 +178,12 @@
             }
         };
     }
+
+    @Override
+    public <T> T getFlag(Key<T> key) {
+        if (key.equals(RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE)) {
+            return (T) PACKAGE_NAME;
+        }
+        return null;
+    }
 }
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
index c79b662..1110494 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
@@ -56,9 +56,7 @@
     public LayoutPullParser(File layoutFile) {
         try {
             init(new FileInputStream(layoutFile));
-        } catch (XmlPullParserException e) {
-            throw new IOError(e);
-        } catch (FileNotFoundException e) {
+        } catch (XmlPullParserException | FileNotFoundException e) {
             throw new IOError(e);
         }
     }
diff --git a/tools/layoutlib/create/create.iml b/tools/layoutlib/create/create.iml
index b2b14b4..368b46b 100644
--- a/tools/layoutlib/create/create.iml
+++ b/tools/layoutlib/create/create.iml
@@ -22,6 +22,6 @@
         </SOURCES>
       </library>
     </orderEntry>
-    <orderEntry type="library" scope="TEST" name="JUnit4" level="application" />
+    <orderEntry type="library" scope="TEST" name="junit" level="project" />
   </component>
 </module>
\ No newline at end of file
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 48544ca..11d4c81 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -438,7 +438,8 @@
 
             try {
                 // exclude classes that are part of the default JRE (the one executing this program)
-                if (getClass().getClassLoader().loadClass(className) != null) {
+                if (className.startsWith("java.") ||
+                        getClass().getClassLoader().loadClass(className) != null) {
                     return;
                 }
             } catch (ClassNotFoundException e) {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index 5b99a6b..3b37612 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -367,6 +367,10 @@
 
         ClassVisitor cv = cw;
 
+        // FIXME Generify
+        if ("android/content/res/Resources".equals(className)) {
+            cv = new FieldInjectorAdapter(cv);
+        }
         if (mReplaceMethodCallsClasses.contains(className)) {
             cv = new ReplaceMethodCallsAdapter(cv, className);
         }
@@ -445,4 +449,5 @@
         }
         return buffer.toByteArray();
     }
+
 }
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 9e390f6..483bddc 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
@@ -155,6 +155,32 @@
      */
     public final static String[] DELEGATE_METHODS = new String[] {
         "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
+        "android.content.res.Resources#getAnimation",
+        "android.content.res.Resources#getBoolean",
+        "android.content.res.Resources#getColor",
+        "android.content.res.Resources#getColorStateList",
+        "android.content.res.Resources#getDimension",
+        "android.content.res.Resources#getDimensionPixelOffset",
+        "android.content.res.Resources#getDimensionPixelSize",
+        "android.content.res.Resources#getDrawable",
+        "android.content.res.Resources#getIntArray",
+        "android.content.res.Resources#getInteger",
+        "android.content.res.Resources#getLayout",
+        "android.content.res.Resources#getResourceEntryName",
+        "android.content.res.Resources#getResourceName",
+        "android.content.res.Resources#getResourcePackageName",
+        "android.content.res.Resources#getResourceTypeName",
+        "android.content.res.Resources#getString",
+        "android.content.res.Resources#getStringArray",
+        "android.content.res.Resources#getText",
+        "android.content.res.Resources#getTextArray",
+        "android.content.res.Resources#getValue",
+        "android.content.res.Resources#getXml",
+        "android.content.res.Resources#loadXmlResourceParser",
+        "android.content.res.Resources#obtainAttributes",
+        "android.content.res.Resources#obtainTypedArray",
+        "android.content.res.Resources#openRawResource",
+        "android.content.res.Resources#openRawResourceFd",
         "android.content.res.Resources$Theme#obtainStyledAttributes",
         "android.content.res.Resources$Theme#resolveAttribute",
         "android.content.res.Resources$Theme#resolveAttributes",
@@ -164,6 +190,7 @@
         "android.content.res.TypedArray#obtain",
         "android.graphics.BitmapFactory#finishDecode",
         "android.graphics.BitmapFactory#setDensityFromOptions",
+        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#useLastSeenTarget",
         "android.graphics.drawable.GradientDrawable#buildRing",
         "android.graphics.Typeface#getSystemFontConfigLocation",
         "android.graphics.Typeface#makeFamilyFromParsed",
@@ -178,6 +205,7 @@
         "android.view.Choreographer#scheduleVsyncLocked",
         "android.view.Display#updateDisplayInfoLocked",
         "android.view.Display#getWindowManager",
+        "android.view.HandlerActionQueue#postDelayed",
         "android.view.LayoutInflater#rInflate",
         "android.view.LayoutInflater#parseInclude",
         "android.view.View#getWindowToken",
@@ -229,7 +257,6 @@
      */
     public final static String[] DELEGATE_CLASS_NATIVES = new String[] {
         "android.animation.PropertyValuesHolder",
-        "android.graphics.AvoidXfermode",
         "android.graphics.Bitmap",
         "android.graphics.BitmapFactory",
         "android.graphics.BitmapShader",
@@ -257,7 +284,6 @@
         "android.graphics.PathDashPathEffect",
         "android.graphics.PathEffect",
         "android.graphics.PathMeasure",
-        "android.graphics.PixelXorXfermode",
         "android.graphics.PorterDuffColorFilter",
         "android.graphics.PorterDuffXfermode",
         "android.graphics.RadialGradient",
@@ -268,12 +294,16 @@
         "android.graphics.SweepGradient",
         "android.graphics.Typeface",
         "android.graphics.Xfermode",
+        "android.graphics.drawable.AnimatedVectorDrawable",
+        "android.graphics.drawable.VectorDrawable",
         "android.os.SystemClock",
         "android.os.SystemProperties",
         "android.text.AndroidBidi",
         "android.text.StaticLayout",
         "android.util.PathParser",
         "android.view.Display",
+        "com.android.internal.util.VirtualRefBasePtr",
+        "com.android.internal.view.animation.NativeInterpolatorFactoryHelper",
         "libcore.icu.ICU",
     };
 
@@ -311,7 +341,7 @@
             // Use android.icu.text versions of DateFormat and SimpleDateFormat since the
             // original ones do not match the Android implementation
             "java.text.DateFormat",                            "android.icu.text.DateFormat",
-            "java.text.SimpleDateFormat",                      "android.icu.text.SimpleDateFormat"
+            "java.text.SimpleDateFormat",                      "android.icu.text.SimpleDateFormat",
         };
 
     private final static String[] EXCLUDED_CLASSES =
@@ -320,7 +350,12 @@
             "org.kxml2.io.KXmlParser"
         };
 
+    /**
+     * List of fields for which we will update the visibility to be public. This is sometimes
+     * needed when access from the delegate classes is needed.
+     */
     private final static String[] PROMOTED_FIELDS = new String[] {
+        "android.graphics.drawable.VectorDrawable#mVectorState",
         "android.view.Choreographer#mLastFrameTimeNanos"
     };
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java
new file mode 100644
index 0000000..4608a84
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Injects fields in a class.
+ * <p>
+ * TODO: Generify
+ */
+public class FieldInjectorAdapter extends ClassVisitor {
+    public FieldInjectorAdapter(ClassVisitor cv) {
+        super(Opcodes.ASM4, cv);
+    }
+
+    @Override
+    public void visitEnd() {
+        super.visitField(Opcodes.ACC_PUBLIC, "mLayoutlibCallback",
+                "Lcom/android/ide/common/rendering/api/LayoutlibCallback;", null, null);
+        super.visitField(Opcodes.ACC_PUBLIC, "mContext",
+                "Lcom/android/layoutlib/bridge/android/BridgeContext;", null, null);
+        super.visitEnd();
+    }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
index 91161f5..024e32f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
@@ -16,9 +16,11 @@
 
 package com.android.tools.layoutlib.create;
 
+import java.util.Arrays;
 import java.util.HashMap;
 
 import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
 
 public class RefactorClassAdapter extends AbstractClassAdapter {
 
@@ -30,6 +32,14 @@
     }
 
     @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+            String[] exceptions) {
+        MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
+
+        return new RefactorStackMapAdapter(mw);
+    }
+
+    @Override
     protected String renameInternalType(String oldClassName) {
         if (oldClassName != null) {
             String newName = mRefactorClasses.get(oldClassName);
@@ -46,4 +56,49 @@
         }
         return oldClassName;
     }
+
+    /**
+     * A method visitor that renames all references from an old class name to a new class name in
+     * the stackmap of the method.
+     */
+    private class RefactorStackMapAdapter extends MethodVisitor {
+
+        private RefactorStackMapAdapter(MethodVisitor mv) {
+            super(Main.ASM_VERSION, mv);
+        }
+
+
+        private Object[] renameFrame(Object[] elements) {
+            if (elements == null) {
+                return null;
+            }
+
+            // The input array cannot be modified. We only copy the source array on write
+            boolean copied = false;
+            for (int i = 0; i < elements.length; i++) {
+                if (!(elements[i] instanceof String)) {
+                    continue;
+                }
+
+                if (!copied) {
+                    elements = Arrays.copyOf(elements, elements.length);
+                    copied = true;
+                }
+
+                String type = (String)elements[i];
+                if (type.indexOf(';') > 0) {
+                    elements[i] = renameTypeDesc(type);
+                } else {
+                    elements[i] = renameInternalType(type);
+                }
+            }
+
+            return elements;
+        }
+
+        @Override
+        public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+            super.visitFrame(type, nLocal, renameFrame(local), nStack, renameFrame(stack));
+        }
+    }
 }
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
index 0912fb1..afaa399 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
@@ -53,12 +53,10 @@
 
     private MockLog mLog;
 
-    private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getCanonicalName();
-    private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName();
-    private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" +
-                                                   InnerClass.class.getSimpleName();
-    private static final String STATIC_INNER_CLASS_NAME =
-            OuterClass.class.getCanonicalName() + "$" + StaticInnerClass.class.getSimpleName();
+    private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getName();
+    private static final String OUTER_CLASS_NAME = OuterClass.class.getName();
+    private static final String INNER_CLASS_NAME = InnerClass.class.getName();
+    private static final String STATIC_INNER_CLASS_NAME = StaticInnerClass.class.getName();
 
     @Before
     public void setUp() throws Exception {
@@ -69,12 +67,12 @@
     /**
      * Tests that a class not being modified still works.
      */
-    @SuppressWarnings("unchecked")
     @Test
     public void testNoOp() throws Throwable {
         // create an instance of the class that will be modified
         // (load the class in a distinct class loader so that we can trash its definition later)
         ClassLoader cl1 = new ClassLoader(this.getClass().getClassLoader()) { };
+        @SuppressWarnings("unchecked")
         Class<ClassWithNative> clazz1 = (Class<ClassWithNative>) cl1.loadClass(NATIVE_CLASS_NAME);
         ClassWithNative instance1 = clazz1.newInstance();
         assertEquals(42, instance1.add(20, 22));
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java
new file mode 100644
index 0000000..3db3e23
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.create.dataclass.StubClass;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Method;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+
+import static org.junit.Assert.*;
+
+public class StubMethodAdapterTest {
+
+    private static final String STUB_CLASS_NAME = StubClass.class.getName();
+
+    /**
+     * Load a dummy class, stub one of its method and ensure that the modified class works as
+     * intended.
+     */
+    @Test
+    public void testBoolean() throws Exception {
+        final String methodName = "returnTrue";
+        // First don't change the method and assert that it returns true
+        testBoolean((name, type) -> false, Assert::assertTrue, methodName);
+        // Change the method now and assert that it returns false.
+        testBoolean((name, type) -> methodName.equals(name) &&
+                Type.BOOLEAN_TYPE.equals(type.getReturnType()), Assert::assertFalse, methodName);
+    }
+
+    /**
+     * @param methodPredicate tests if the method should be replaced
+     */
+    private void testBoolean(BiPredicate<String, Type> methodPredicate, Consumer<Boolean> assertion,
+            String methodName) throws Exception {
+        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        // Always rename the class to avoid conflict with the original class.
+        String newClassName = STUB_CLASS_NAME + '_';
+        new ClassReader(STUB_CLASS_NAME).accept(
+                new ClassAdapter(newClassName, writer, methodPredicate), 0);
+        MyClassLoader myClassLoader = new MyClassLoader(newClassName, writer.toByteArray());
+        Class<?> aClass = myClassLoader.loadClass(newClassName);
+        assertTrue("StubClass not loaded by the classloader. Likely a bug in the test.",
+                myClassLoader.findClassCalled);
+        Method method = aClass.getMethod(methodName);
+        Object o = aClass.newInstance();
+        assertion.accept((Boolean) method.invoke(o));
+    }
+
+    private static class ClassAdapter extends ClassVisitor {
+
+        private final String mClassName;
+        private final BiPredicate<String, Type> mMethodPredicate;
+
+        private ClassAdapter(String className, ClassVisitor cv,
+                BiPredicate<String, Type> methodPredicate) {
+            super(Main.ASM_VERSION, cv);
+            mClassName = className.replace('.', '/');
+            mMethodPredicate = methodPredicate;
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName,
+                String[] interfaces) {
+            super.visit(version, access, mClassName, signature, superName,
+                    interfaces);
+        }
+
+        @Override
+        public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+                String[] exceptions) {
+            // Copied partly from
+            // com.android.tools.layoutlib.create.DelegateClassAdapter.visitMethod()
+            // but not generating the _Original method.
+            boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
+            boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
+            MethodVisitor originalMethod =
+                    super.visitMethod(access, name, desc, signature, exceptions);
+            Type descriptor = Type.getMethodType(desc);
+            if (mMethodPredicate.test(name, descriptor)) {
+                String methodSignature = mClassName + "#" + name;
+                String invokeSignature = methodSignature + desc;
+                return new StubMethodAdapter(originalMethod, name, descriptor.getReturnType(),
+                        invokeSignature, isStatic, isNative);
+            }
+            return originalMethod;
+        }
+    }
+
+    private static class MyClassLoader extends ClassLoader {
+        private final String mName;
+        private final byte[] mBytes;
+        private boolean findClassCalled;
+
+        private MyClassLoader(String name, byte[] bytes) {
+            mName = name;
+            mBytes = bytes;
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(mName)) {
+                findClassCalled = true;
+                return defineClass(name, mBytes, 0, mBytes.length);
+            }
+            return super.findClass(name);
+        }
+    }
+}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/StubClass.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/StubClass.java
new file mode 100644
index 0000000..3ae8e47
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/StubClass.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.StubMethodAdapterTest;
+
+/**
+ * Used by {@link StubMethodAdapterTest}
+ */
+@SuppressWarnings("unused")
+public class StubClass {
+
+    public boolean returnTrue() {
+        return true;
+    }
+}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 59416b8..87fc7fa 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -1,5 +1,6 @@
 package android.net.wifi;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Bundle;
@@ -14,6 +15,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
@@ -275,12 +277,13 @@
         /** Implement the Parcelable interface {@hide} */
         public static final Creator<RttCapabilities> CREATOR =
             new Creator<RttCapabilities>() {
-               public RttCapabilities createFromParcel(Parcel in) {
+            @Override
+            public RttCapabilities createFromParcel(Parcel in) {
                     RttCapabilities capabilities = new RttCapabilities();
-                    capabilities.oneSidedRttSupported = in.readInt() == 1 ? true : false;
-                        capabilities.twoSided11McRttSupported = in.readInt() == 1 ? true : false;
-                        capabilities.lciSupported = in.readInt() == 1 ? true : false;
-                        capabilities.lcrSupported = in.readInt() == 1 ? true : false;
+                    capabilities.oneSidedRttSupported = (in.readInt() == 1);
+                        capabilities.twoSided11McRttSupported = (in.readInt() == 1);
+                        capabilities.lciSupported = (in.readInt() == 1);
+                        capabilities.lcrSupported = (in.readInt() == 1);
                         capabilities.preambleSupported = in.readInt();
                         capabilities.bwSupported = in.readInt();
                         capabilities.responderSupported = (in.readInt() == 1);
@@ -300,7 +303,7 @@
                 try {
                     mRttCapabilities = mService.getRttCapabilities();
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Can not get RTT Capabilities");
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return mRttCapabilities;
@@ -464,58 +467,57 @@
     /** pseudo-private class used to parcel arguments */
     public static class ParcelableRttParams implements Parcelable {
 
+        @NonNull
         public RttParams mParams[];
 
-        ParcelableRttParams(RttParams[] params) {
-            mParams = params;
+        /**
+         * @hide
+         */
+        @VisibleForTesting
+        public ParcelableRttParams(RttParams[] params) {
+            mParams = (params == null ? new RttParams[0] : params);
         }
 
         /** Implement the Parcelable interface {@hide} */
+        @Override
         public int describeContents() {
             return 0;
         }
 
         /** Implement the Parcelable interface {@hide} */
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
-            if (mParams != null) {
-                dest.writeInt(mParams.length);
+            dest.writeInt(mParams.length);
 
-                for (RttParams params : mParams) {
-                    dest.writeInt(params.deviceType);
-                    dest.writeInt(params.requestType);
-                    dest.writeByte(params.secure ? (byte) 1 : 0);
-                    dest.writeString(params.bssid);
-                    dest.writeInt(params.channelWidth);
-                    dest.writeInt(params.frequency);
-                    dest.writeInt(params.centerFreq0);
-                    dest.writeInt(params.centerFreq1);
-                    dest.writeInt(params.numberBurst);
-                    dest.writeInt(params.interval);
-                    dest.writeInt(params.numSamplesPerBurst);
-                    dest.writeInt(params.numRetriesPerMeasurementFrame);
-                    dest.writeInt(params.numRetriesPerFTMR);
-                    dest.writeInt(params.LCIRequest ? 1 : 0);
-                    dest.writeInt(params.LCRRequest ? 1 : 0);
-                    dest.writeInt(params.burstTimeout);
-                    dest.writeInt(params.preamble);
-                    dest.writeInt(params.bandwidth);
-                }
-            } else {
-                dest.writeInt(0);
+            for (RttParams params : mParams) {
+                dest.writeInt(params.deviceType);
+                dest.writeInt(params.requestType);
+                dest.writeByte(params.secure ? (byte) 1 : 0);
+                dest.writeString(params.bssid);
+                dest.writeInt(params.channelWidth);
+                dest.writeInt(params.frequency);
+                dest.writeInt(params.centerFreq0);
+                dest.writeInt(params.centerFreq1);
+                dest.writeInt(params.numberBurst);
+                dest.writeInt(params.interval);
+                dest.writeInt(params.numSamplesPerBurst);
+                dest.writeInt(params.numRetriesPerMeasurementFrame);
+                dest.writeInt(params.numRetriesPerFTMR);
+                dest.writeInt(params.LCIRequest ? 1 : 0);
+                dest.writeInt(params.LCRRequest ? 1 : 0);
+                dest.writeInt(params.burstTimeout);
+                dest.writeInt(params.preamble);
+                dest.writeInt(params.bandwidth);
             }
         }
 
         /** Implement the Parcelable interface {@hide} */
         public static final Creator<ParcelableRttParams> CREATOR =
                 new Creator<ParcelableRttParams>() {
+                    @Override
                     public ParcelableRttParams createFromParcel(Parcel in) {
 
                         int num = in.readInt();
-
-                        if (num == 0) {
-                            return new ParcelableRttParams(null);
-                        }
-
                         RttParams params[] = new RttParams[num];
                         for (int i = 0; i < num; i++) {
                             params[i] = new RttParams();
@@ -532,8 +534,8 @@
                             params[i].numSamplesPerBurst = in.readInt();
                             params[i].numRetriesPerMeasurementFrame = in.readInt();
                             params[i].numRetriesPerFTMR = in.readInt();
-                            params[i].LCIRequest = in.readInt() == 1 ? true : false;
-                            params[i].LCRRequest = in.readInt() == 1 ? true : false;
+                            params[i].LCIRequest = (in.readInt() == 1);
+                            params[i].LCRRequest = (in.readInt() == 1);
                             params[i].burstTimeout = in.readInt();
                             params[i].preamble = in.readInt();
                             params[i].bandwidth = in.readInt();
@@ -543,6 +545,7 @@
                         return parcelableParams;
                     }
 
+                    @Override
                     public ParcelableRttParams[] newArray(int size) {
                         return new ParcelableRttParams[size];
                     }
@@ -715,11 +718,13 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
+        @Override
         public int describeContents() {
             return 0;
         }
 
         /** Implement the Parcelable interface {@hide} */
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             if (mResults != null) {
                 dest.writeInt(mResults.length);
@@ -764,6 +769,7 @@
         /** Implement the Parcelable interface {@hide} */
         public static final Creator<ParcelableRttResults> CREATOR =
                 new Creator<ParcelableRttResults>() {
+                    @Override
                     public ParcelableRttResults createFromParcel(Parcel in) {
 
                         int num = in.readInt();
@@ -816,6 +822,7 @@
                         return parcelableResults;
                     }
 
+                    @Override
                     public ParcelableRttResults[] newArray(int size) {
                         return new ParcelableRttResults[size];
                     }
@@ -1132,7 +1139,7 @@
                     Log.d(TAG, "Get the messenger from " + mService);
                     messenger = mService.getMessenger();
                 } catch (RemoteException e) {
-                    /* do nothing */
+                    throw e.rethrowFromSystemServer();
                 } catch (SecurityException e) {
                     /* do nothing */
                 }
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index ed12bdf..67cf107 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -56,6 +56,11 @@
      */
     public int anqpDomainId;
 
+    /*
+     * This field is equivalent to the |flags|, rather than the |capabilities| field
+     * of the per-BSS scan results returned by WPA supplicant. See the definition of
+     * |struct wpa_bss| in wpa_supplicant/bss.h for more details.
+     */
     /**
      * Describes the authentication, key management, and encryption schemes
      * supported by the access point.
@@ -160,21 +165,6 @@
         }
     }
 
-    /** @hide */
-    public static final int ENABLED                                          = 0;
-    /** @hide */
-    public static final int AUTO_ROAM_DISABLED                               = 16;
-    /** @hide */
-    public static final int AUTO_JOIN_DISABLED                               = 32;
-    /** @hide */
-    public static final int AUTHENTICATION_ERROR                              = 128;
-
-    /**
-     * Status: indicating join status
-     * @hide
-     */
-    public int autoJoinStatus;
-
     /**
      * num IP configuration failures
      * @hide
@@ -187,17 +177,6 @@
      */
     public long blackListTimestamp;
 
-    /** @hide **/
-    public void setAutoJoinStatus(int status) {
-        if (status < 0) status = 0;
-        if (status == 0) {
-            blackListTimestamp = 0;
-        }  else if (status > autoJoinStatus) {
-            blackListTimestamp = System.currentTimeMillis();
-        }
-        autoJoinStatus = status;
-    }
-
     /**
      * Status: indicating the scan result is not a result
      * that is part of user's saved configurations
@@ -237,6 +216,10 @@
     /** {@hide} */
     public static final long FLAG_80211mc_RESPONDER               = 0x0000000000000002;
 
+    /*
+     * These flags are specific to the ScanResult class, and are not related to the |flags|
+     * field of the per-BSS scan results from WPA supplicant.
+     */
     /**
      * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}.
      * {@hide}
@@ -331,9 +314,12 @@
      */
     public static class InformationElement {
         public static final int EID_SSID = 0;
+        public static final int EID_SUPPORTED_RATES = 1;
         public static final int EID_TIM = 5;
         public static final int EID_BSS_LOAD = 11;
+        public static final int EID_ERP = 42;
         public static final int EID_RSN = 48;
+        public static final int EID_EXTENDED_SUPPORTED_RATES = 50;
         public static final int EID_HT_OPERATION = 61;
         public static final int EID_INTERWORKING = 107;
         public static final int EID_ROAMING_CONSORTIUM = 111;
@@ -462,7 +448,6 @@
             distanceCm = source.distanceCm;
             distanceSdCm = source.distanceSdCm;
             seen = source.seen;
-            autoJoinStatus = source.autoJoinStatus;
             untrusted = source.untrusted;
             numConnection = source.numConnection;
             numUsage = source.numUsage;
@@ -506,9 +491,6 @@
 
         sb.append(", passpoint: ");
         sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
-        if (autoJoinStatus != 0) {
-            sb.append(", status: ").append(autoJoinStatus);
-        }
         sb.append(", ChannelBandwidth: ").append(channelWidth);
         sb.append(", centerFreq0: ").append(centerFreq0);
         sb.append(", centerFreq1: ").append(centerFreq1);
@@ -544,7 +526,6 @@
         dest.writeInt(centerFreq0);
         dest.writeInt(centerFreq1);
         dest.writeLong(seen);
-        dest.writeInt(autoJoinStatus);
         dest.writeInt(untrusted ? 1 : 0);
         dest.writeInt(numConnection);
         dest.writeInt(numUsage);
@@ -615,7 +596,6 @@
                 );
 
                 sr.seen = in.readLong();
-                sr.autoJoinStatus = in.readInt();
                 sr.untrusted = in.readInt() != 0;
                 sr.numConnection = in.readInt();
                 sr.numUsage = in.readInt();
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 035317e..4c38c9b 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Arrays;
+
 /**
  * Record of energy and activity information from controller and
  * underlying wifi stack state. Timestamp the record with elapsed
@@ -44,6 +46,11 @@
     /**
      * @hide
      */
+    public long[] mControllerTxTimePerLevelMs;
+
+    /**
+     * @hide
+     */
     public long mControllerRxTimeMs;
 
     /**
@@ -62,10 +69,12 @@
     public static final int STACK_STATE_STATE_IDLE = 3;
 
     public WifiActivityEnergyInfo(long timestamp, int stackState,
-                                  long txTime, long rxTime, long idleTime, long energyUsed) {
+                                  long txTime, long[] txTimePerLevel, long rxTime, long idleTime,
+                                  long energyUsed) {
         mTimestamp = timestamp;
         mStackState = stackState;
         mControllerTxTimeMs = txTime;
+        mControllerTxTimePerLevelMs = txTimePerLevel;
         mControllerRxTimeMs = rxTime;
         mControllerIdleTimeMs = idleTime;
         mControllerEnergyUsed = energyUsed;
@@ -77,6 +86,7 @@
             + " timestamp=" + mTimestamp
             + " mStackState=" + mStackState
             + " mControllerTxTimeMs=" + mControllerTxTimeMs
+            + " mControllerTxTimePerLevelMs=" + Arrays.toString(mControllerTxTimePerLevelMs)
             + " mControllerRxTimeMs=" + mControllerRxTimeMs
             + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
             + " mControllerEnergyUsed=" + mControllerEnergyUsed
@@ -89,11 +99,12 @@
             long timestamp = in.readLong();
             int stackState = in.readInt();
             long txTime = in.readLong();
+            long[] txTimePerLevel = in.createLongArray();
             long rxTime = in.readLong();
             long idleTime = in.readLong();
             long energyUsed = in.readLong();
             return new WifiActivityEnergyInfo(timestamp, stackState,
-                    txTime, rxTime, idleTime, energyUsed);
+                    txTime, txTimePerLevel, rxTime, idleTime, energyUsed);
         }
         public WifiActivityEnergyInfo[] newArray(int size) {
             return new WifiActivityEnergyInfo[size];
@@ -104,6 +115,7 @@
         out.writeLong(mTimestamp);
         out.writeInt(mStackState);
         out.writeLong(mControllerTxTimeMs);
+        out.writeLongArray(mControllerTxTimePerLevelMs);
         out.writeLong(mControllerRxTimeMs);
         out.writeLong(mControllerIdleTimeMs);
         out.writeLong(mControllerEnergyUsed);
@@ -128,6 +140,16 @@
     }
 
     /**
+     * @return tx time at power level provided in ms
+     */
+    public long getControllerTxTimeMillisAtLevel(int level) {
+        if (level < mControllerTxTimePerLevelMs.length) {
+            return mControllerTxTimePerLevelMs[level];
+        }
+        return 0;
+    }
+
+    /**
      * @return rx time in ms
      */
     public long getControllerRxTimeMillis() {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ddd8f43..fb2bdd4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -684,6 +684,13 @@
 
     /**
      * @hide
+     * A hint about whether or not the network represented by this WifiConfiguration
+     * is metered.
+     */
+    public boolean meteredHint;
+
+    /**
+     * @hide
      * Number of time the scorer overrode a the priority based choice, when comparing two
      * WifiConfigurations, note that since comparing WifiConfiguration happens very often
      * potentially at every scan, this number might become very large, even on an idle
@@ -931,6 +938,15 @@
         private boolean mSeenInLastQualifiedNetworkSelection;
 
         /**
+         * Boolean indicating if we have ever successfully connected to this network.
+         *
+         * This value will be set to true upon a successful connection.
+         * This value will be set to false if a previous value was not stored in the config or if
+         * the credentials are updated (ex. a password change).
+         */
+        private boolean mHasEverConnected;
+
+        /**
          * set whether this network is visible in latest Qualified Network Selection
          * @param seen value set to candidate
          */
@@ -1020,7 +1036,18 @@
             return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
         }
 
-        private NetworkSelectionStatus() {};
+        public void setHasEverConnected(boolean value) {
+            mHasEverConnected = value;
+        }
+
+        public boolean getHasEverConnected() {
+            return mHasEverConnected;
+        }
+
+        private NetworkSelectionStatus() {
+            // previously stored configs will not have this parameter, so we default to false.
+            mHasEverConnected = false;
+        };
 
         /**
          * @param reason specific error reason
@@ -1219,6 +1246,7 @@
             mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
             setConnectChoice(source.getConnectChoice());
             setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
+            setHasEverConnected(source.getHasEverConnected());
         }
 
         public void writeToParcel(Parcel dest) {
@@ -1237,6 +1265,7 @@
             } else {
                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
             }
+            dest.writeInt(getHasEverConnected() ? 1 : 0);
         }
 
         public void readFromParcel(Parcel in) {
@@ -1255,6 +1284,7 @@
                 setConnectChoice(null);
                 setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
             }
+            setHasEverConnected(in.readInt() != 0);
         }
     }
 
@@ -1302,6 +1332,7 @@
         selfAdded = false;
         didSelfAdd = false;
         ephemeral = false;
+        meteredHint = false;
         validatedInternetAccess = false;
         mIpConfiguration = new IpConfiguration();
         lastUpdateUid = -1;
@@ -1357,6 +1388,7 @@
                 append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
                 .append(" PRIO: ").append(this.priority)
+                .append(" HIDDEN: ").append(this.hiddenSSID)
                 .append('\n');
 
 
@@ -1380,6 +1412,8 @@
             sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
                     .getConnectChoiceTimestamp());
         }
+        sbuf.append(" hasEverConnected: ")
+                .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n");
 
         if (this.numAssociation > 0) {
             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
@@ -1398,7 +1432,9 @@
         if (this.selfAdded) sbuf.append(" selfAdded");
         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
         if (this.ephemeral) sbuf.append(" ephemeral");
-        if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess || this.ephemeral) {
+        if (this.meteredHint) sbuf.append(" meteredHint");
+        if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
+            || this.ephemeral || this.meteredHint) {
             sbuf.append("\n");
         }
         sbuf.append(" KeyMgmt:");
@@ -1545,18 +1581,6 @@
         return sbuf.toString();
     }
 
-    /**
-     * Construct a WifiConfiguration from a scanned network
-     * @param scannedAP the scan result used to construct the config entry
-     * TODO: figure out whether this is a useful way to construct a new entry.
-     *
-    public WifiConfiguration(ScanResult scannedAP) {
-        networkId = -1;
-        SSID = scannedAP.SSID;
-        BSSID = scannedAP.BSSID;
-    }
-    */
-
     /** {@hide} */
     public String getPrintableSsid() {
         if (SSID == null) return "";
@@ -1831,6 +1855,7 @@
             selfAdded = source.selfAdded;
             validatedInternetAccess = source.validatedInternetAccess;
             ephemeral = source.ephemeral;
+            meteredHint = source.meteredHint;
             if (source.visibility != null) {
                 visibility = new Visibility(source.visibility);
             }
@@ -1869,11 +1894,6 @@
         }
     }
 
-    /** {@hide} */
-    //public static final int NOTHING_TAG = 0;
-    /** {@hide} */
-    //public static final int SCAN_CACHE_TAG = 1;
-
     /** Implement the Parcelable interface {@hide} */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
@@ -1915,6 +1935,7 @@
         dest.writeInt(didSelfAdd ? 1 : 0);
         dest.writeInt(validatedInternetAccess ? 1 : 0);
         dest.writeInt(ephemeral ? 1 : 0);
+        dest.writeInt(meteredHint ? 1 : 0);
         dest.writeInt(creatorUid);
         dest.writeInt(lastConnectUid);
         dest.writeInt(lastUpdateUid);
@@ -1984,6 +2005,7 @@
                 config.didSelfAdd = in.readInt() != 0;
                 config.validatedInternetAccess = in.readInt() != 0;
                 config.ephemeral = in.readInt() != 0;
+                config.meteredHint = in.readInt() != 0;
                 config.creatorUid = in.readInt();
                 config.lastConnectUid = in.readInt();
                 config.lastUpdateUid = in.readInt();
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 58e8761..9e15d60 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -1047,7 +1047,7 @@
         StringBuffer sb = new StringBuffer();
         for (String key : mFields.keySet()) {
             // Don't display password in toString().
-            String value = (key == PASSWORD_KEY) ? "<removed>" : mFields.get(key);
+            String value = PASSWORD_KEY.equals(key) ? "<removed>" : mFields.get(key);
             sb.append(key).append(" ").append(value).append("\n");
         }
         return sb.toString();
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 9f8af6e..8d5efba 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -320,7 +320,8 @@
             if (!TextUtils.isEmpty(unicode)) {
                 return "\"" + unicode + "\"";
             } else {
-                return mWifiSsid.getHexString();
+                String hex = mWifiSsid.getHexString();
+                return (hex != null) ? hex : WifiSsid.NONE;
             }
         }
         return WifiSsid.NONE;
diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
index 1de4fd8..edd400b 100644
--- a/wifi/java/android/net/wifi/WifiLinkLayerStats.java
+++ b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
@@ -19,6 +19,8 @@
 import android.os.Parcelable;
 import android.os.Parcel;
 
+import java.util.Arrays;
+
 /**
  * A class representing link layer statistics collected over a Wifi Interface.
  */
@@ -101,6 +103,8 @@
     /** {@hide} */
     public int tx_time;
     /** {@hide} */
+    public int[] tx_time_per_level;
+    /** {@hide} */
     public int rx_time;
     /** {@hide} */
     public int on_time_scan;
@@ -141,9 +145,10 @@
                 .append(" lost=").append(Long.toString(this.lostmpdu_vo))
                 .append(" retries=").append(Long.toString(this.retries_vo)).append('\n');
         sbuf.append(" on_time : ").append(Integer.toString(this.on_time))
-                .append(" tx_time=").append(Integer.toString(this.tx_time))
                 .append(" rx_time=").append(Integer.toString(this.rx_time))
-                .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n');
+                .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n')
+                .append(" tx_time=").append(Integer.toString(this.tx_time))
+                .append(" tx_time_per_level=" + Arrays.toString(tx_time_per_level));
         return sbuf.toString();
     }
 
@@ -179,6 +184,7 @@
         dest.writeString(BSSID);
         dest.writeInt(on_time);
         dest.writeInt(tx_time);
+        dest.writeIntArray(tx_time_per_level);
         dest.writeInt(rx_time);
         dest.writeInt(on_time_scan);
     }
@@ -192,6 +198,7 @@
                 stats.BSSID = in.readString();
                 stats.on_time = in.readInt();
                 stats.tx_time = in.readInt();
+                stats.tx_time_per_level = in.createIntArray();
                 stats.rx_time = in.readInt();
                 stats.on_time_scan = in.readInt();
                 return stats;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4921073..8c1fbc3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -21,7 +21,6 @@
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
 import android.net.DhcpInfo;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -39,9 +38,9 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
+import com.android.server.net.NetworkPinner;
 
 import java.net.InetAddress;
 import java.util.ArrayList;
@@ -666,22 +665,13 @@
     private final int mTargetSdkVersion;
 
     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 int mListenerKey = 1;
+    private final SparseArray mListenerMap = new SparseArray();
+    private final Object mListenerMapLock = new Object();
 
-    private static AsyncChannel sAsyncChannel;
-    private static CountDownLatch sConnected;
-    private static ConnectivityManager sCM;
-
-    private static final Object sThreadRefLock = new Object();
-    private static int sThreadRefCount;
-    private static HandlerThread sHandlerThread;
-
-    @GuardedBy("sCM")
-    // TODO: Introduce refcounting and make this a per-process static callback, instead of a
-    // per-WifiManager callback.
-    private PinningNetworkCallback mNetworkCallback;
+    private AsyncChannel mAsyncChannel;
+    private CountDownLatch mConnected;
+    private Looper mLooper;
 
     /**
      * Create a new WifiManager instance.
@@ -693,11 +683,11 @@
      * @hide - hide this because it takes in a parameter of type IWifiManager, which
      * is a system private class.
      */
-    public WifiManager(Context context, IWifiManager service) {
+    public WifiManager(Context context, IWifiManager service, Looper looper) {
         mContext = context;
         mService = service;
+        mLooper = looper;
         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
-        init();
     }
 
     /**
@@ -723,8 +713,7 @@
         try {
             return mService.getConfiguredNetworks();
         } catch (RemoteException e) {
-            Log.w(TAG, "Caught RemoteException trying to get configured networks: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -734,7 +723,7 @@
         try {
             return mService.getPrivilegedConfiguredNetworks();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -744,7 +733,7 @@
         try {
             return mService.getConnectionStatistics();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -758,7 +747,7 @@
         try {
             return mService.getMatchingWifiConfig(scanResult);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -818,7 +807,7 @@
         try {
             return mService.addOrUpdateNetwork(config);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -832,7 +821,7 @@
         try {
             return mService.addPasspointManagementObject(mo);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -848,7 +837,7 @@
         try {
             return mService.modifyPasspointManagementObject(fqdn, mos);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -862,6 +851,7 @@
         try {
             mService.queryPasspointIcon(bssid, fileName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -875,7 +865,7 @@
         try {
             return mService.matchProviderWithCurrentNetwork(fqdn);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -889,28 +879,11 @@
         try {
             mService.deauthenticateNetwork(holdoff, ess);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Sets whether or not the given network is metered from a network policy
-     * point of view. A network should be classified as metered when the user is
-     * sensitive to heavy data usage on that connection due to monetary costs,
-     * data limitations or battery/performance issues. A typical example would
-     * be a wifi connection where the user was being charged for usage.
-     * @param netId the integer that identifies the network configuration
-     * to the supplicant.
-     * @param isMetered True to mark the network as metered.
-     * @return {@code true} if the operation succeeded.
-     * @hide
-     */
-    @SystemApi
-    public boolean setMetered(int netId, boolean isMetered) {
-        // TODO(jjoslin): Implement
-        return false;
-    }
-
-    /**
      * Remove the specified network from the list of configured networks.
      * This may result in the asynchronous delivery of state change
      * events.
@@ -922,7 +895,7 @@
         try {
             return mService.removeNetwork(netId);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -955,18 +928,22 @@
     public boolean enableNetwork(int netId, boolean disableOthers) {
         final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
         if (pin) {
-            registerPinningNetworkCallback();
+            NetworkRequest request = new NetworkRequest.Builder()
+                    .clearCapabilities()
+                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                    .build();
+            NetworkPinner.pin(mContext, request);
         }
 
         boolean success;
         try {
             success = mService.enableNetwork(netId, disableOthers);
         } catch (RemoteException e) {
-            success = false;
+            throw e.rethrowFromSystemServer();
         }
 
         if (pin && !success) {
-            unregisterPinningNetworkCallback();
+            NetworkPinner.unpin();
         }
 
         return success;
@@ -983,7 +960,7 @@
         try {
             return mService.disableNetwork(netId);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -997,7 +974,7 @@
             mService.disconnect();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1012,7 +989,7 @@
             mService.reconnect();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1027,7 +1004,7 @@
             mService.reassociate();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1042,7 +1019,7 @@
         try {
             return mService.pingSupplicant();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1090,7 +1067,7 @@
         try {
             return mService.getSupportedFeatures();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1216,9 +1193,8 @@
                 return mService.reportActivityInfo();
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "getControllerActivityEnergyInfo: " + e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -1232,7 +1208,7 @@
             mService.startScan(null, null);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1243,7 +1219,7 @@
             mService.startScan(null, workSource);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1299,7 +1275,7 @@
         try {
             return mService.getWpsNfcConfigurationToken(netId);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1311,7 +1287,7 @@
         try {
             return mService.getConnectionInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1328,7 +1304,7 @@
         try {
             return mService.getScanResults(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return new ArrayList<ScanResult>();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1344,7 +1320,7 @@
         try {
             return mService.isScanAlwaysAvailable();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1361,7 +1337,7 @@
         try {
             return mService.saveConfiguration();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1375,7 +1351,9 @@
     public void setCountryCode(String country, boolean persist) {
         try {
             mService.setCountryCode(country, persist);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -1387,9 +1365,9 @@
     public String getCountryCode() {
        try {
            String country = mService.getCountryCode();
-           return(country);
+           return country;
        } catch (RemoteException e) {
-           return null;
+           throw e.rethrowFromSystemServer();
        }
     }
 
@@ -1405,7 +1383,9 @@
     public void setFrequencyBand(int band, boolean persist) {
         try {
             mService.setFrequencyBand(band, persist);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -1421,7 +1401,7 @@
         try {
             return mService.getFrequencyBand();
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1434,7 +1414,7 @@
         try {
             return mService.isDualBandSupported();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1447,7 +1427,7 @@
         try {
             return mService.getDhcpInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1461,7 +1441,7 @@
         try {
             return mService.setWifiEnabled(enabled);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1476,7 +1456,7 @@
         try {
             return mService.getWifiEnabledState();
         } catch (RemoteException e) {
-            return WIFI_STATE_UNKNOWN;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1496,8 +1476,7 @@
      * @hide for CTS test only
      */
     public void getTxPacketCount(TxPacketCountListener listener) {
-        validateChannel();
-        sAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
+        getChannel().sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
     }
 
     /**
@@ -1553,7 +1532,7 @@
             mService.setWifiApEnabled(wifiConfig, enabled);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1571,7 +1550,7 @@
         try {
             return mService.getWifiApEnabledState();
         } catch (RemoteException e) {
-            return WIFI_AP_STATE_FAILED;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1598,7 +1577,7 @@
         try {
             return mService.getWifiApConfiguration();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1612,8 +1591,7 @@
         try {
             return mService.buildWifiConfig(uriString, mimeType, data);
         } catch (RemoteException e) {
-            Log.w(TAG, "Caught RemoteException trying to build wifi config: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1629,7 +1607,7 @@
             mService.setWifiApConfiguration(wifiConfig);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1646,7 +1624,7 @@
             mService.addToBlacklist(bssid);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1663,7 +1641,7 @@
             mService.clearBlacklist();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1692,7 +1670,7 @@
         try {
             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
         } catch (RemoteException e) {
-            // Just ignore the exception
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1706,7 +1684,7 @@
         try {
             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
         } catch (RemoteException e) {
-            // Just ignore the exception
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1862,25 +1840,34 @@
         public void onFailure(int reason);
     }
 
-    private static class ServiceHandler extends Handler {
+    // Ensure that multiple ServiceHandler threads do not interleave message dispatch.
+    private static final Object sServiceHandlerDispatchLock = new Object();
+
+    private class ServiceHandler extends Handler {
         ServiceHandler(Looper looper) {
             super(looper);
         }
 
         @Override
         public void handleMessage(Message message) {
+            synchronized (sServiceHandlerDispatchLock) {
+                dispatchMessageToListeners(message);
+            }
+        }
+
+        private void dispatchMessageToListeners(Message message) {
             Object listener = removeListener(message.arg2);
             switch (message.what) {
                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+                        mAsyncChannel.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;
+                        mAsyncChannel = null;
                     }
-                    sConnected.countDown();
+                    mConnected.countDown();
                     break;
                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
                     // Ignore
@@ -1889,7 +1876,7 @@
                     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;
+                    mAsyncChannel = null;
                     getLooper().quit();
                     break;
                     /* ActionListeners grouped together */
@@ -1915,8 +1902,8 @@
                         WpsResult result = (WpsResult) message.obj;
                         ((WpsCallback) listener).onStarted(result.pin);
                         //Listener needs to stay until completion or failure
-                        synchronized(sListenerMapLock) {
-                            sListenerMap.put(message.arg2, listener);
+                        synchronized (mListenerMapLock) {
+                            mListenerMap.put(message.arg2, listener);
                         }
                     }
                     break;
@@ -1961,149 +1948,47 @@
         }
     }
 
-    private static int putListener(Object listener) {
+    private int putListener(Object listener) {
         if (listener == null) return INVALID_KEY;
         int key;
-        synchronized (sListenerMapLock) {
+        synchronized (mListenerMapLock) {
             do {
-                key = sListenerKey++;
+                key = mListenerKey++;
             } while (key == INVALID_KEY);
-            sListenerMap.put(key, listener);
+            mListenerMap.put(key, listener);
         }
         return key;
     }
 
-    private static Object removeListener(int key) {
+    private Object removeListener(int key) {
         if (key == INVALID_KEY) return null;
-        synchronized (sListenerMapLock) {
-            Object listener = sListenerMap.get(key);
-            sListenerMap.remove(key);
+        synchronized (mListenerMapLock) {
+            Object listener = mListenerMap.get(key);
+            mListenerMap.remove(key);
             return listener;
         }
     }
 
-    private void init() {
-        synchronized (sThreadRefLock) {
-            if (++sThreadRefCount == 1) {
-                Messenger messenger = getWifiServiceMessenger();
-                if (messenger == null) {
-                    sAsyncChannel = null;
-                    return;
-                }
+    private synchronized AsyncChannel getChannel() {
+        if (mAsyncChannel == null) {
+            Messenger messenger = getWifiServiceMessenger();
+            if (messenger == null) {
+                throw new IllegalStateException(
+                        "getWifiServiceMessenger() returned null!  This is invalid.");
+            }
 
-                sHandlerThread = new HandlerThread("WifiManager");
-                sAsyncChannel = new AsyncChannel();
-                sConnected = new CountDownLatch(1);
+            mAsyncChannel = new AsyncChannel();
+            mConnected = 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");
-                }
+            Handler handler = new ServiceHandler(mLooper);
+            mAsyncChannel.connect(mContext, handler, messenger);
+            try {
+                mConnected.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 void initConnectivityManager() {
-        // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
-        // registered? Can we fix this by starting ConnectivityService before WifiService?
-        if (sCM == null) {
-            sCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-            if (sCM == null) {
-                throw new IllegalStateException("Bad luck, ConnectivityService not started.");
-            }
-        }
-    }
-
-    /**
-     * A NetworkCallback that pins the process to the first wifi network to connect.
-     *
-     * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
-     * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
-     * able to use that network because it's the system default.
-     *
-     * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
-     * we try not to set the default network unless they have already done so, and we try not to
-     * clear the default network unless we set it ourselves.
-     *
-     * This should maintain behaviour that's compatible with L, which would pin the whole system to
-     * any wifi network that was created via enableNetwork(..., true) until that network
-     * disconnected.
-     *
-     * Note that while this hack allows network traffic to flow, it is quite limited. For example:
-     *
-     * 1. setProcessDefaultNetwork only affects this process, so:
-     *    - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
-     *    - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
-     *      either, because other apps on the device will not be pinned.
-     * 2. The behaviour of other APIs is not modified. For example:
-     *    - getActiveNetworkInfo will return the system default network, not Wi-Fi.
-     *    - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
-     *    - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
-     *      will be surprised as well.
-     */
-    private class PinningNetworkCallback extends NetworkCallback {
-        private Network mPinnedNetwork;
-
-        @Override
-        public void onPreCheck(Network network) {
-            if (sCM.getProcessDefaultNetwork() == null && mPinnedNetwork == null) {
-                sCM.setProcessDefaultNetwork(network);
-                mPinnedNetwork = network;
-                Log.d(TAG, "Wifi alternate reality enabled on network " + network);
-            }
-        }
-
-        @Override
-        public void onLost(Network network) {
-            if (network.equals(mPinnedNetwork) && network.equals(sCM.getProcessDefaultNetwork())) {
-                sCM.setProcessDefaultNetwork(null);
-                Log.d(TAG, "Wifi alternate reality disabled on network " + network);
-                mPinnedNetwork = null;
-                unregisterPinningNetworkCallback();
-            }
-        }
-    }
-
-    private void registerPinningNetworkCallback() {
-        initConnectivityManager();
-        synchronized (sCM) {
-            if (mNetworkCallback == null) {
-                // TODO: clear all capabilities.
-                NetworkRequest request = new NetworkRequest.Builder()
-                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build();
-                mNetworkCallback = new PinningNetworkCallback();
-                try {
-                    sCM.registerNetworkCallback(request, mNetworkCallback);
-                } catch (SecurityException e) {
-                    Log.d(TAG, "Failed to register network callback", e);
-                }
-            }
-        }
-    }
-
-    private void unregisterPinningNetworkCallback() {
-        initConnectivityManager();
-        synchronized (sCM) {
-            if (mNetworkCallback != null) {
-                try {
-                    sCM.unregisterNetworkCallback(mNetworkCallback);
-                } catch (SecurityException e) {
-                    Log.d(TAG, "Failed to unregister network callback", e);
-                }
-                mNetworkCallback = null;
-            }
-        }
+        return mAsyncChannel;
     }
 
     /**
@@ -2124,10 +2009,9 @@
      */
     public void connect(WifiConfiguration config, ActionListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
-        validateChannel();
         // Use INVALID_NETWORK_ID for arg1 when passing a config object
         // arg1 is used to pass network id when the network already exists
-        sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
+        getChannel().sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
                 putListener(listener), config);
     }
 
@@ -2146,8 +2030,7 @@
      */
     public void connect(int networkId, ActionListener listener) {
         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
-        validateChannel();
-        sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
+        getChannel().sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
     }
 
     /**
@@ -2170,8 +2053,7 @@
      */
     public void save(WifiConfiguration config, ActionListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
-        validateChannel();
-        sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
+        getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
     }
 
     /**
@@ -2189,8 +2071,7 @@
      */
     public void forget(int netId, ActionListener listener) {
         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
-        validateChannel();
-        sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
+        getChannel().sendMessage(FORGET_NETWORK, netId, putListener(listener));
     }
 
     /**
@@ -2204,8 +2085,7 @@
      */
     public void disable(int netId, ActionListener listener) {
         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
-        validateChannel();
-        sAsyncChannel.sendMessage(DISABLE_NETWORK, netId, putListener(listener));
+        getChannel().sendMessage(DISABLE_NETWORK, netId, putListener(listener));
     }
 
     /**
@@ -2219,6 +2099,7 @@
         try {
             mService.disableEphemeralNetwork(SSID);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2232,8 +2113,7 @@
      */
     public void startWps(WpsInfo config, WpsCallback listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
-        validateChannel();
-        sAsyncChannel.sendMessage(START_WPS, 0, putListener(listener), config);
+        getChannel().sendMessage(START_WPS, 0, putListener(listener), config);
     }
 
     /**
@@ -2244,8 +2124,7 @@
      * initialized again
      */
     public void cancelWps(WpsCallback listener) {
-        validateChannel();
-        sAsyncChannel.sendMessage(CANCEL_WPS, 0, putListener(listener));
+        getChannel().sendMessage(CANCEL_WPS, 0, putListener(listener));
     }
 
     /**
@@ -2259,9 +2138,7 @@
         try {
             return mService.getWifiServiceMessenger();
         } catch (RemoteException e) {
-            return null;
-        } catch (SecurityException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2274,7 +2151,7 @@
         try {
             return mService.getConfigFile();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2340,7 +2217,8 @@
                             }
                             mActiveLockCount++;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = true;
                 }
@@ -2367,7 +2245,8 @@
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = false;
                 }
@@ -2427,6 +2306,7 @@
                     try {
                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
                     } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -2456,7 +2336,8 @@
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -2572,7 +2453,8 @@
                             }
                             mActiveLockCount++;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = true;
                 }
@@ -2611,7 +2493,8 @@
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = false;
                 }
@@ -2685,7 +2568,7 @@
         try {
             return mService.isMulticastEnabled();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2698,16 +2581,14 @@
             mService.initializeMulticastFiltering();
             return true;
         } catch (RemoteException e) {
-             return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
     protected void finalize() throws Throwable {
         try {
-            synchronized (sThreadRefLock) {
-                if (--sThreadRefCount == 0 && sAsyncChannel != null) {
-                    sAsyncChannel.disconnect();
-                }
+            if (mAsyncChannel != null) {
+                mAsyncChannel.disconnect();
             }
         } finally {
             super.finalize();
@@ -2736,7 +2617,7 @@
         try {
             return mService.getVerboseLoggingLevel();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2748,7 +2629,7 @@
         try {
             mService.enableAggressiveHandover(enabled);
         } catch (RemoteException e) {
-
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2761,7 +2642,7 @@
         try {
             return mService.getAggressiveHandover();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2773,7 +2654,7 @@
         try {
             mService.setAllowScansWithTraffic(enabled);
         } catch (RemoteException e) {
-
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2785,7 +2666,7 @@
         try {
             return mService.getAllowScansWithTraffic();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2798,6 +2679,7 @@
         try {
             mService.factoryReset();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2810,7 +2692,7 @@
         try {
             return mService.getCurrentNetwork();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2824,7 +2706,7 @@
         try {
             return mService.enableAutoJoinWhenAssociated(enabled);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2836,7 +2718,7 @@
         try {
             return mService.getEnableAutoJoinWhenAssociated();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
     /**
@@ -2847,7 +2729,7 @@
         try {
             mService.setHalBasedAutojoinOffload(enabled);
         } catch (RemoteException e) {
-
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2859,7 +2741,7 @@
         try {
             return mService.getHalBasedAutojoinOffload();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return 0;
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 2373754..73ddbbc 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -27,10 +27,13 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.WorkSource;
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
 import java.util.List;
@@ -78,6 +81,8 @@
     public static final int REASON_INVALID_REQUEST = -3;
     /** Invalid request */
     public static final int REASON_NOT_AUTHORIZED = -4;
+    /** An outstanding request with the same listener hasn't finished yet. */
+    public static final int REASON_DUPLICATE_REQEUST = -5;
 
     /** @hide */
     public static final String GET_AVAILABLE_CHANNELS_EXTRA = "Channels";
@@ -156,6 +161,11 @@
      */
     public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
 
+
+    /** {@hide} */
+    public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
+    /** {@hide} */
+    public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource";
     /**
      * scan configuration parameters to be sent to {@link #startBackgroundScan}
      */
@@ -165,6 +175,13 @@
         public int band;
         /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
         public ChannelSpec[] channels;
+        /**
+         * list of networkId's of hidden networks to scan for.
+         * These Id's should correspond to the wpa_supplicant's networkId's and will be used
+         * in connectivity scans using wpa_supplicant.
+         * {@hide}
+         * */
+        public int[] hiddenNetworkIds;
         /** period of background scan; in millisecond, 0 => single shot scan */
         public int periodInMs;
         /** must have a valid REPORT_EVENT value */
@@ -188,6 +205,11 @@
          * for a given period
          */
         public int stepCount;
+        /**
+         * Flag to indicate if the scan settings are targeted for PNO scan.
+         * {@hide}
+         */
+        public boolean isPnoScan;
 
         /** Implement the Parcelable interface {@hide} */
         public int describeContents() {
@@ -203,10 +225,9 @@
             dest.writeInt(maxScansToCache);
             dest.writeInt(maxPeriodInMs);
             dest.writeInt(stepCount);
-
+            dest.writeInt(isPnoScan ? 1 : 0);
             if (channels != null) {
                 dest.writeInt(channels.length);
-
                 for (int i = 0; i < channels.length; i++) {
                     dest.writeInt(channels[i].frequency);
                     dest.writeInt(channels[i].dwellTimeMS);
@@ -215,13 +236,13 @@
             } else {
                 dest.writeInt(0);
             }
+            dest.writeIntArray(hiddenNetworkIds);
         }
 
         /** 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();
@@ -230,17 +251,17 @@
                         settings.maxScansToCache = in.readInt();
                         settings.maxPeriodInMs = in.readInt();
                         settings.stepCount = in.readInt();
+                        settings.isPnoScan = in.readInt() == 1;
                         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;
                         }
-
+                        settings.hiddenNetworkIds = in.createIntArray();
                         return settings;
                     }
 
@@ -262,6 +283,12 @@
          * non-zero => scan was truncated, so results may not be complete
          */
         private int mFlags;
+        /**
+         * Indicates the buckets that were scanned to generate these results.
+         * This is not relevant to WifiScanner API users and is used internally.
+         * {@hide}
+         */
+        private int mBucketsScanned;
         /** all scan results discovered in this scan, sorted by timestamp in ascending order */
         private ScanResult mResults[];
 
@@ -273,9 +300,18 @@
             mResults = results;
         }
 
+        /** {@hide} */
+        public ScanData(int id, int flags, int bucketsScanned, ScanResult[] results) {
+            mId = id;
+            mFlags = flags;
+            mBucketsScanned = bucketsScanned;
+            mResults = results;
+        }
+
         public ScanData(ScanData s) {
             mId = s.mId;
             mFlags = s.mFlags;
+            mBucketsScanned = s.mBucketsScanned;
             mResults = new ScanResult[s.mResults.length];
             for (int i = 0; i < s.mResults.length; i++) {
                 ScanResult result = s.mResults[i];
@@ -292,6 +328,11 @@
             return mFlags;
         }
 
+        /** {@hide} */
+        public int getBucketsScanned() {
+            return mBucketsScanned;
+        }
+
         public ScanResult[] getResults() {
             return mResults;
         }
@@ -306,6 +347,7 @@
             if (mResults != null) {
                 dest.writeInt(mId);
                 dest.writeInt(mFlags);
+                dest.writeInt(mBucketsScanned);
                 dest.writeInt(mResults.length);
                 for (int i = 0; i < mResults.length; i++) {
                     ScanResult result = mResults[i];
@@ -322,12 +364,13 @@
                     public ScanData createFromParcel(Parcel in) {
                         int id = in.readInt();
                         int flags = in.readInt();
+                        int bucketsScanned = in.readInt();
                         int n = in.readInt();
                         ScanResult results[] = new ScanResult[n];
                         for (int i = 0; i < n; i++) {
                             results[i] = ScanResult.CREATOR.createFromParcel(in);
                         }
-                        return new ScanData(id, flags, results);
+                        return new ScanData(id, flags, bucketsScanned, results);
                     }
 
                     public ScanData[] newArray(int size) {
@@ -432,6 +475,158 @@
                 };
     }
 
+    /** {@hide} */
+    public static final String PNO_PARAMS_PNO_SETTINGS_KEY = "PnoSettings";
+    /** {@hide} */
+    public static final String PNO_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
+    /**
+     * PNO scan configuration parameters to be sent to {@link #startPnoScan}.
+     * Note: This structure needs to be in sync with |wifi_epno_params| struct in gscan HAL API.
+     * {@hide}
+     */
+    public static class PnoSettings implements Parcelable {
+        /**
+         * Pno network to be added to the PNO scan filtering.
+         * {@hide}
+         */
+        public static class PnoNetwork {
+            /*
+             * Pno flags bitmask to be set in {@link #PnoNetwork.flags}
+             */
+            /** Whether directed scan needs to be performed (for hidden SSIDs) */
+            public static final byte FLAG_DIRECTED_SCAN = (1 << 0);
+            /** Whether PNO event shall be triggered if the network is found on A band */
+            public static final byte FLAG_A_BAND = (1 << 1);
+            /** Whether PNO event shall be triggered if the network is found on G band */
+            public static final byte FLAG_G_BAND = (1 << 2);
+            /**
+             * Whether strict matching is required
+             * If required then the firmware must store the network's SSID and not just a hash
+             */
+            public static final byte FLAG_STRICT_MATCH = (1 << 3);
+            /**
+             * If this SSID should be considered the same network as the currently connected
+             * one for scoring.
+             */
+            public static final byte FLAG_SAME_NETWORK = (1 << 4);
+
+            /*
+             * Code for matching the beacon AUTH IE - additional codes. Bitmask to be set in
+             * {@link #PnoNetwork.authBitField}
+             */
+            /** Open Network */
+            public static final byte AUTH_CODE_OPEN = (1 << 0);
+            /** WPA_PSK or WPA2PSK */
+            public static final byte AUTH_CODE_PSK = (1 << 1);
+            /** any EAPOL */
+            public static final byte AUTH_CODE_EAPOL = (1 << 2);
+
+            /** SSID of the network */
+            public String ssid;
+            /** Network ID in wpa_supplicant */
+            public int networkId;
+            /** Assigned priority for the network */
+            public int priority;
+            /** Bitmask of the FLAG_XXX */
+            public byte flags;
+            /** Bitmask of the ATUH_XXX */
+            public byte authBitField;
+
+            /**
+             * default constructor for PnoNetwork
+             */
+            public PnoNetwork(String ssid) {
+                this.ssid = ssid;
+                flags = 0;
+                authBitField = 0;
+            }
+        }
+
+        /** Connected vs Disconnected PNO flag {@hide} */
+        public boolean isConnected;
+        /** Minimum 5GHz RSSI for a BSSID to be considered */
+        public int min5GHzRssi;
+        /** Minimum 2.4GHz RSSI for a BSSID to be considered */
+        public int min24GHzRssi;
+        /** Maximum score that a network can have before bonuses */
+        public int initialScoreMax;
+        /**
+         *  Only report when there is a network's score this much higher
+         *  than the current connection.
+         */
+        public int currentConnectionBonus;
+        /** score bonus for all networks with the same network flag */
+        public int sameNetworkBonus;
+        /** score bonus for networks that are not open */
+        public int secureBonus;
+        /** 5GHz RSSI score bonus (applied to all 5GHz networks) */
+        public int band5GHzBonus;
+        /** Pno Network filter list */
+        public PnoNetwork[] networkList;
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(isConnected ? 1 : 0);
+            dest.writeInt(min5GHzRssi);
+            dest.writeInt(min24GHzRssi);
+            dest.writeInt(initialScoreMax);
+            dest.writeInt(currentConnectionBonus);
+            dest.writeInt(sameNetworkBonus);
+            dest.writeInt(secureBonus);
+            dest.writeInt(band5GHzBonus);
+            if (networkList != null) {
+                dest.writeInt(networkList.length);
+                for (int i = 0; i < networkList.length; i++) {
+                    dest.writeString(networkList[i].ssid);
+                    dest.writeInt(networkList[i].networkId);
+                    dest.writeInt(networkList[i].priority);
+                    dest.writeByte(networkList[i].flags);
+                    dest.writeByte(networkList[i].authBitField);
+                }
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<PnoSettings> CREATOR =
+                new Creator<PnoSettings>() {
+                    public PnoSettings createFromParcel(Parcel in) {
+                        PnoSettings settings = new PnoSettings();
+                        settings.isConnected = in.readInt() == 1;
+                        settings.min5GHzRssi = in.readInt();
+                        settings.min24GHzRssi = in.readInt();
+                        settings.initialScoreMax = in.readInt();
+                        settings.currentConnectionBonus = in.readInt();
+                        settings.sameNetworkBonus = in.readInt();
+                        settings.secureBonus = in.readInt();
+                        settings.band5GHzBonus = in.readInt();
+                        int numNetworks = in.readInt();
+                        settings.networkList = new PnoNetwork[numNetworks];
+                        for (int i = 0; i < numNetworks; i++) {
+                            String ssid = in.readString();
+                            PnoNetwork network = new PnoNetwork(ssid);
+                            network.networkId = in.readInt();
+                            network.priority = in.readInt();
+                            network.flags = in.readByte();
+                            network.authBitField = in.readByte();
+                            settings.networkList[i] = network;
+                        }
+                        return settings;
+                    }
+
+                    public PnoSettings[] newArray(int size) {
+                        return new PnoSettings[size];
+                    }
+                };
+
+    }
+
     /**
      * interface to get scan events on; specify this on {@link #startBackgroundScan} or
      * {@link #startScan}
@@ -452,6 +647,18 @@
         public void onFullResult(ScanResult fullScanResult);
     }
 
+    /**
+     * interface to get PNO scan events on; specify this on {@link #startDisconnectedPnoScan} and
+     * {@link #startConnectedPnoScan}.
+     * {@hide}
+     */
+    public interface PnoScanListener extends ScanListener {
+        /**
+         * Invoked when one of the PNO networks are found in scan results.
+         */
+        void onPnoNetworkFound(ScanResult[] results);
+    }
+
     /** start wifi scan in background
      * @param settings specifies various parameters for the scan; for more information look at
      * {@link ScanSettings}
@@ -460,17 +667,40 @@
      *                 scans should also not share this object.
      */
     public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
-        validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
+        startBackgroundScan(settings, listener, null);
     }
+
+    /** start wifi scan in background
+     * @param settings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param workSource WorkSource to blame for power usage
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     */
+    public void startBackgroundScan(ScanSettings settings, ScanListener listener,
+            WorkSource workSource) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
+        validateChannel();
+        Bundle scanParams = new Bundle();
+        scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
+        scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
+        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
+    }
+
     /**
      * stop an ongoing wifi scan
      * @param listener specifies which scan to cancel; must be same object as passed in {@link
      *  #startBackgroundScan}
      */
     public void stopBackgroundScan(ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
     }
     /**
      * reports currently available scan results on appropriate listeners
@@ -491,8 +721,27 @@
      *                 scans should also not share this object.
      */
     public void startScan(ScanSettings settings, ScanListener listener) {
+        startScan(settings, listener, null);
+    }
+
+    /**
+     * starts a single scan and reports results asynchronously
+     * @param settings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param workSource WorkSource to blame for power usage
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     */
+    public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, putListener(listener), settings);
+        Bundle scanParams = new Bundle();
+        scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
+        scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
+        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
     }
 
     /**
@@ -501,8 +750,79 @@
      * @param listener
      */
     public void stopScan(ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
+    }
+
+    private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
+        // Bundle up both the settings and send it across.
+        Bundle pnoParams = new Bundle();
+        // Set the PNO scan flag.
+        scanSettings.isPnoScan = true;
+        pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
+        pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
+        sAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
+    }
+    /**
+     * Start wifi connected PNO scan
+     * @param scanSettings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param pnoSettings specifies various parameters for PNO; for more information look at
+     * {@link PnoSettings}
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     * {@hide}
+     */
+    public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
+            PnoScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
+        validateChannel();
+        pnoSettings.isConnected = true;
+        startPnoScan(scanSettings, pnoSettings, key);
+    }
+    /**
+     * Start wifi disconnected PNO scan
+     * @param scanSettings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param pnoSettings specifies various parameters for PNO; for more information look at
+     * {@link PnoSettings}
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     * {@hide}
+     */
+    public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
+            PnoScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
+        validateChannel();
+        pnoSettings.isConnected = false;
+        startPnoScan(scanSettings, pnoSettings, key);
+    }
+    /**
+     * Stop an ongoing wifi PNO scan
+     * @param pnoSettings specifies various parameters for PNO; for more information look at
+     * {@link PnoSettings}
+     * @param listener specifies which scan to cancel; must be same object as passed in {@link
+     *  #startPnoScan}
+     * TODO(rpius): Check if we can remove pnoSettings param in stop.
+     * {@hide}
+     */
+    public void stopPnoScan(PnoSettings pnoSettings, ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key, pnoSettings);
     }
 
     /** specifies information about an access point of interest */
@@ -634,8 +954,11 @@
      *                 provided on {@link #stopTrackingWifiChange}
      */
     public void startTrackingWifiChange(WifiChangeListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
+        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
     }
 
     /**
@@ -644,8 +967,10 @@
      * #stopTrackingWifiChange}
      */
     public void stopTrackingWifiChange(WifiChangeListener listener) {
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
     }
 
     /** @hide */
@@ -730,11 +1055,14 @@
      */
     public void startTrackingBssids(BssidInfo[] bssidInfos,
                                     int apLostThreshold, BssidListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
         HotlistSettings settings = new HotlistSettings();
         settings.bssidInfos = bssidInfos;
         settings.apLostThreshold = apLostThreshold;
-        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
+        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
     }
 
     /**
@@ -742,8 +1070,11 @@
      * @param listener same object provided in {@link #startTrackingBssids}
      */
     public void stopTrackingBssids(BssidListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
     }
 
 
@@ -797,6 +1128,12 @@
     public static final int CMD_STOP_SINGLE_SCAN            = BASE + 22;
     /** @hide */
     public static final int CMD_SINGLE_SCAN_COMPLETED       = BASE + 23;
+    /** @hide */
+    public static final int CMD_START_PNO_SCAN              = BASE + 24;
+    /** @hide */
+    public static final int CMD_STOP_PNO_SCAN               = BASE + 25;
+    /** @hide */
+    public static final int CMD_PNO_NETWORK_FOUND           = BASE + 26;
 
     private Context mContext;
     private IWifiScanner mService;
@@ -812,7 +1149,7 @@
 
     private static final Object sThreadRefLock = new Object();
     private static int sThreadRefCount;
-    private static HandlerThread sHandlerThread;
+    private static Handler sInternalHandler;
 
     /**
      * Create a new WifiScanner instance.
@@ -824,12 +1161,29 @@
      * @hide
      */
     public WifiScanner(Context context, IWifiScanner service) {
-        mContext = context;
-        mService = service;
-        init();
+        this(context, service, null, true);
     }
 
-    private void init() {
+    /**
+     * Create a new WifiScanner instance.
+     *
+     * @param context The application context.
+     * @param service The IWifiScanner Binder interface
+     * @param looper Looper for running WifiScanner operations. If null, a handler thread will be
+     *          created for running WifiScanner operations.
+     * @param waitForConnection If true, this will not return until a connection to Wifi Scanner
+     *          service is established.
+     * @hide
+     */
+    @VisibleForTesting
+    public WifiScanner(Context context, IWifiScanner service, Looper looper,
+            boolean waitForConnection) {
+        mContext = context;
+        mService = service;
+        init(looper, waitForConnection);
+    }
+
+    private void init(Looper looper, boolean waitForConnection) {
         synchronized (sThreadRefLock) {
             if (++sThreadRefCount == 1) {
                 Messenger messenger = null;
@@ -846,17 +1200,23 @@
                     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");
+                if (looper == null) {
+                    HandlerThread thread = new HandlerThread("WifiScanner");
+                    thread.start();
+                    sInternalHandler = new ServiceHandler(thread.getLooper());
+                } else {
+                    sInternalHandler = new ServiceHandler(looper);
+                }
+                sAsyncChannel.connect(mContext, sInternalHandler, messenger);
+                if (waitForConnection) {
+                    try {
+                        sConnected.await();
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "interrupted wait at init");
+                    }
                 }
             }
         }
@@ -867,6 +1227,30 @@
                 "No permission to access and change wifi or a bad initialization");
     }
 
+    // Add a listener into listener map. If the listener already exists, return INVALID_KEY and
+    // send an error message to internal handler; Otherwise add the listener to the listener map and
+    // return the key of the listener.
+    private int addListener(ActionListener listener) {
+        synchronized (sListenerMap) {
+            boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
+            // Note we need to put the listener into listener map even if it's a duplicate as the
+            // internal handler will need the key to find the listener. In case of duplicates,
+            // removing duplicate key logic will be handled in internal handler.
+            int key = putListener(listener);
+            if (keyExists) {
+                if (DBG) Log.d(TAG, "listener key already exists");
+                OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
+                        "Outstanding request with same key not stopped yet");
+                Message message = Message.obtain(sInternalHandler, CMD_OP_FAILED, 0, key,
+                        operationResult);
+                message.sendToTarget();
+                return INVALID_KEY;
+            } else {
+                return key;
+            }
+        }
+    }
+
     private static int putListener(Object listener) {
         if (listener == null) return INVALID_KEY;
         int key;
@@ -910,7 +1294,10 @@
 
     private static int removeListener(Object listener) {
         int key = getListenerKey(listener);
-        if (key == INVALID_KEY) return key;
+        if (key == INVALID_KEY) {
+            Log.e(TAG, "listener cannot be found");
+            return key;
+        }
         synchronized (sListenerMapLock) {
             sListenerMap.remove(key);
             return key;
@@ -1033,6 +1420,10 @@
                     if (DBG) Log.d(TAG, "removing listener for single scan");
                     removeListener(msg.arg2);
                     break;
+                case CMD_PNO_NETWORK_FOUND:
+                    ((PnoScanListener) listener).onPnoNetworkFound(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
                 default:
                     if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
                     return;
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index f8ba95d..c53cd3c 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -205,7 +205,7 @@
         for (int i = 0; i < octets.size(); i++) {
             out += String.format(Locale.US, "%02x", ssidbytes[i]);
         }
-        return out;
+        return (octets.size() > 0) ? out : null;
     }
 
     /** Implement the Parcelable interface {@hide} */
diff --git a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
index 17cc29f..f5cad13 100644
--- a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
+++ b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
@@ -16,8 +16,8 @@
 
 package android.net.wifi;
 
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
 /**
  * A class representing wifi wake reason accounting.
@@ -52,6 +52,8 @@
     public int ipv4RxMulticast;
     public int ipv6Multicast;
     public int otherRxMulticast;
+    public int[] cmdEventWakeCntArray;
+    public int[] driverFWLocalWakeCntArray;
 
     /* {@hide} */
     public WifiWakeReasonAndCounts () {
@@ -78,6 +80,13 @@
         sb.append(" ipv4RxMulticast ").append(ipv4RxMulticast);
         sb.append(" ipv6Multicast ").append(ipv6Multicast);
         sb.append(" otherRxMulticast ").append(otherRxMulticast);
+        for (int i = 0; i < cmdEventWakeCntArray.length; i++) {
+            sb.append(" cmdEventWakeCntArray[" + i + "] " + cmdEventWakeCntArray[i]);
+        }
+        for (int i = 0; i < driverFWLocalWakeCntArray.length; i++) {
+            sb.append(" driverFWLocalWakeCntArray[" + i + "] " + driverFWLocalWakeCntArray[i]);
+        }
+
         return sb.toString();
     }
 
@@ -111,6 +120,8 @@
         dest.writeInt(ipv4RxMulticast);
         dest.writeInt(ipv6Multicast);
         dest.writeInt(otherRxMulticast);
+        dest.writeIntArray(cmdEventWakeCntArray);
+        dest.writeIntArray(driverFWLocalWakeCntArray);
     }
 
     /* Implement the Parcelable interface
@@ -137,6 +148,8 @@
                 counts.ipv4RxMulticast = in.readInt();
                 counts.ipv6Multicast = in.readInt();
                 counts.otherRxMulticast = in.readInt();
+                in.readIntArray(counts.cmdEventWakeCntArray);
+                in.readIntArray(counts.driverFWLocalWakeCntArray);
                 return counts;
             }
             /* Implement the Parcelable interface
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 667c4b1..1b78beb 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -75,7 +75,7 @@
             }
             mService.connect(mBinder, listener.callback, events);
         } catch (RemoteException e) {
-            Log.w(TAG, "connect RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -94,7 +94,7 @@
             mService.disconnect(mBinder);
             mBinder = null;
         } catch (RemoteException e) {
-            Log.w(TAG, "disconnect RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -116,7 +116,7 @@
         try {
             mService.requestConfig(configRequest);
         } catch (RemoteException e) {
-            Log.w(TAG, "requestConfig RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -173,8 +173,7 @@
             if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId);
             mService.publish(sessionId, publishData, publishSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "createSession/publish RemoteException: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
 
         return new WifiNanPublishSession(this, sessionId);
@@ -200,7 +199,7 @@
         try {
             mService.publish(sessionId, publishData, publishSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "publish RemoteException: " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
     /**
@@ -256,8 +255,7 @@
             if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId);
             mService.subscribe(sessionId, subscribeData, subscribeSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "createSession/subscribe RemoteException: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
 
         return new WifiNanSubscribeSession(this, sessionId);
@@ -286,7 +284,7 @@
         try {
             mService.subscribe(sessionId, subscribeData, subscribeSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "subscribe RemoteException: " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -299,7 +297,7 @@
         try {
             mService.stopSession(sessionId);
         } catch (RemoteException e) {
-            Log.w(TAG, "stopSession RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -312,7 +310,7 @@
         try {
             mService.destroySession(sessionId);
         } catch (RemoteException e) {
-            Log.w(TAG, "destroySession RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -328,7 +326,7 @@
             }
             mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
         } catch (RemoteException e) {
-            Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 6409450..8d5cf63 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1362,8 +1362,8 @@
     public void setMiracastMode(int mode) {
         try {
             mService.setMiracastMode(mode);
-        } catch(RemoteException e) {
-           // ignore
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1378,7 +1378,7 @@
         try {
             return mService.getMessenger();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1393,7 +1393,7 @@
         try {
             return mService.getP2pStateMachineMessenger();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }